[425507]use GapContentPosition to track position in layout boxes

Bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=425507
Change-Id: I371513ba433c4a6cc90ee79b94038078eb7ee0b0
Signed-off-by: Carsten Hiesserich <carsten.hie@gmail.com>
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestDocumentTextBox.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestDocumentTextBox.java
index 9efbe3d..1cf55ad 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestDocumentTextBox.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestDocumentTextBox.java
@@ -109,6 +109,19 @@
 		assertEquals("Last right box should have a width", 36, pair2.getRight().getWidth());
 	}
 
+	@Test
+	public void testPositionUpdate() throws Exception {
+		final IDocument doc = new Document(new QualifiedName(null, "root"));
+		doc.insertText(2, "before 12345 67890 ");
+		final IElement root = doc.getRootElement();
+		final DocumentTextBox box = new DocumentTextBox(context, root, root.getStartOffset() + 8, root.getEndOffset() - 1);
+		final InlineBox.Pair pair = box.split(context, 150, false);
+		doc.insertText(2, "before");
+		assertEquals(root.getStartOffset() + 8 + 6, pair.getLeft().getStartOffset());
+		assertEquals("12345 ", ((DocumentTextBox) pair.getLeft()).getText());
+		assertEquals("67890 ", ((DocumentTextBox) pair.getRight()).getText());
+	}
+
 	private void assertSplit(final INode node, final int splitPos, final boolean force, final String left, final String right) {
 
 		final DocumentTextBox box = new DocumentTextBox(context, node, node.getStartOffset() + 1, node.getEndOffset() - 1);
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/simple-edit.xml b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/simple-edit.xml
index dc05bf2..536b9c1 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/simple-edit.xml
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/simple-edit.xml
@@ -7,7 +7,7 @@
 			<box class="RootBox">

 				<box class="BlockElementBox">

 					<box class="BlockElementBox" element="root" layoutState="LAYOUT_PROPAGATE">

-						<box class="BlockElementBox" element="p" layoutState="LAYOUT_REDO">

+						<box class="BlockElementBox" element="p" layoutState="LAYOUT_PROPAGATE">

 							<box class="ParagraphBox">

 								<box class="LineBox">

 									<box class="DocumentTextBox" text="before" />

@@ -71,7 +71,7 @@
 				<box class="BlockElementBox">

 					<box class="BlockElementBox" element="root">

 					

-						<box class="BlockElementBox" element="p" layoutState="LAYOUT_REDO">

+						<box class="BlockElementBox" element="p">

 							<box class="ParagraphBox">

 								<box class="LineBox">

 									<box class="DocumentTextBox" text="before" />

diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBlockBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBlockBox.java
index b896ddb..afbbdd9 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBlockBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBlockBox.java
@@ -24,7 +24,6 @@
 import org.eclipse.vex.core.internal.core.Insets;
 import org.eclipse.vex.core.internal.css.StyleSheet;
 import org.eclipse.vex.core.internal.css.Styles;
-import org.eclipse.vex.core.internal.widget.IBoxFilter;
 import org.eclipse.vex.core.provisional.dom.BaseNodeVisitorWithResult;
 import org.eclipse.vex.core.provisional.dom.ContentRange;
 import org.eclipse.vex.core.provisional.dom.IComment;
@@ -412,11 +411,7 @@
 
 		if (direct) {
 			layoutState = LAYOUT_REDO;
-			if (getParent() instanceof AbstractBlockBox) {
-				// The parent box may contain text elements after the edited offset, that has to be updated
-				((AbstractBlockBox) getParent()).invalidateChildrenAfterOffset(getStartOffset());
-			}
-		} else if (layoutState != LAYOUT_REDO) {
+		} else {
 			layoutState = LAYOUT_PROPAGATE;
 		}
 
@@ -425,28 +420,6 @@
 		}
 	}
 
-	/**
-	 * Checks if there are any children with content after an invalidated element. If so, the box has to update those
-	 * children.
-	 * 
-	 * @param offset
-	 *            The offset of the edited element
-	 */
-	protected void invalidateChildrenAfterOffset(final int offset) {
-		final IBoxFilter filter = new IBoxFilter() {
-			public boolean matches(final Box box) {
-				return box.hasContent() && box.getStartOffset() > offset;
-			}
-		};
-
-		for (final Box child : getChildren()) {
-			if (filter.matches(child)) {
-				layoutState = LAYOUT_REDO;
-				break;
-			}
-		}
-	}
-
 	@Override
 	public boolean isAnonymous() {
 		return getNode() == null;
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DocumentTextBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DocumentTextBox.java
index 93890ca..b0a1672 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DocumentTextBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DocumentTextBox.java
@@ -20,6 +20,7 @@
 import org.eclipse.vex.core.internal.css.Styles;
 import org.eclipse.vex.core.provisional.dom.ContentRange;
 import org.eclipse.vex.core.provisional.dom.INode;
+import org.eclipse.vex.core.provisional.dom.IPosition;
 
 /**
  * A TextBox that gets its text from the document. Represents text which is editable within the VexWidget.
@@ -27,6 +28,7 @@
 public class DocumentTextBox extends TextBox {
 
 	private int startRelative;
+	private final IPosition startPosition;
 	private final int endRelative;
 
 	/**
@@ -48,15 +50,15 @@
 			throw new AssertionFailedException(MessageFormat.format("assertion failed: DocumentTextBox for {2}: startOffset {0} > endOffset {1}", startOffset, endOffset, node)); //$NON-NLS-1$
 		}
 
-		final int nodeStart = node.getStartOffset();
-		startRelative = startOffset - nodeStart;
-		endRelative = endOffset - nodeStart;
+		startRelative = 0;
+		startPosition = node.getContent().createPosition(startOffset);
+		endRelative = endOffset - startOffset;
 
 		// The box constructed here will be splitted, so there's no need to calculate the width here.
 		calculateHeight(context);
 		setWidth(-1);
 
-		if (startOffset <= nodeStart || endOffset >= node.getEndOffset()) {
+		if (startOffset <= node.getStartOffset() || endOffset >= node.getEndOffset()) {
 			// Do not use Assert.isTrue. This Contructor is called very often and the use of Assert.isTrue would evaluate the Message.format every time.
 			throw new AssertionFailedException(MessageFormat.format("assertion failed: Range of DocumentTextBox for {0} exceeds content of parent node", node)); //$NON-NLS-1$
 		}
@@ -74,8 +76,9 @@
 	 */
 	private DocumentTextBox(final DocumentTextBox other, final int endOffset, final int width) {
 		super(other.getNode());
+		startPosition = other.startPosition;
 		startRelative = other.startRelative;
-		endRelative = endOffset - getNode().getStartOffset();
+		endRelative = endOffset - startPosition.getOffset();
 		setWidth(width);
 		setHeight(other.getHeight());
 		setBaseline(other.getBaseline());
@@ -89,7 +92,7 @@
 		if (endRelative == -1) {
 			return -1;
 		} else {
-			return getNode().getStartOffset() + endRelative;
+			return startPosition.getOffset() + endRelative;
 		}
 	}
 
@@ -101,7 +104,7 @@
 		if (startRelative == -1) {
 			return -1;
 		} else {
-			return getNode().getStartOffset() + startRelative;
+			return startPosition.getOffset() + startRelative;
 		}
 	}
 
@@ -222,7 +225,7 @@
 			right = null;
 		} else {
 			// Instead of creating a new box, we reuse this one
-			startRelative = split - getNode().getStartOffset();
+			startRelative = split - startPosition.getOffset();
 			if (left == null) {
 				calculateSize(context);
 				remaining -= getWidth();