use VerticalRange arithmetics where possible

Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentTest.java
index b6720a7..6b8305c 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentTest.java
@@ -59,7 +59,7 @@
 		document.insertText(childElement.getStartOffset(), "Hello ");

 		document.insertText(childElement.getEndOffset(), "Child");

 		document.insertText(childElement.getEndOffset() + 1, " World");

-		final ContentRange range = childElement.getRange().resize(-2, 2);

+		final ContentRange range = childElement.getRange().resizeBy(-2, 2);

 		final DocumentFragment fragment = document.getFragment(range);

 		assertEquals(11, fragment.getLength());

 		assertNodesEqual(document.getNodes(range), fragment.getNodes());

diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NodeTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NodeTest.java
index 9e4c4bd..6c5b967 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NodeTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NodeTest.java
@@ -131,13 +131,13 @@
 		content.insertText(0, "prefix");

 		content.insertText(content.length(), "suffix");

 

-		assertTrue(node.isInRange(node.getRange().resize(-1, 0)));

+		assertTrue(node.isInRange(node.getRange().resizeBy(-1, 0)));

 		assertTrue(node.isInRange(node.getRange()));

-		assertFalse(node.isInRange(node.getRange().resize(1, 0)));

-		assertTrue(node.isInRange(node.getRange().resize(0, 1)));

-		assertFalse(node.isInRange(node.getRange().resize(0, -1)));

-		assertTrue(node.isInRange(node.getRange().resize(-1, 1)));

-		assertFalse(node.isInRange(node.getRange().resize(1, -1)));

+		assertFalse(node.isInRange(node.getRange().resizeBy(1, 0)));

+		assertTrue(node.isInRange(node.getRange().resizeBy(0, 1)));

+		assertFalse(node.isInRange(node.getRange().resizeBy(0, -1)));

+		assertTrue(node.isInRange(node.getRange().resizeBy(-1, 1)));

+		assertFalse(node.isInRange(node.getRange().resizeBy(1, -1)));

 	}

 

 	@Test

diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java
index cd24af6..57ad29d 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java
@@ -171,7 +171,7 @@
 		content.insertText(child1.getStartOffset(), "Hello");

 		content.insertText(child2.getStartOffset(), "World!");

 

-		final List<Node> childNodes = parent.getChildNodes(child1.getRange().resize(-2, 2));

+		final List<Node> childNodes = parent.getChildNodes(child1.getRange().resizeBy(-2, 2));

 		assertEquals(3, childNodes.size());

 		assertTrue(childNodes.get(0) instanceof Text);

 		assertSame(child1, childNodes.get(1));

@@ -358,7 +358,7 @@
 	public void shouldHandleSmallerStartOffset() throws Exception {

 		setUpChildNodes();

 		content.insertText(parent.getStartOffset(), "prefix");

-		final List<Node> childNodes = parent.getChildNodes(parent.getRange().resize(-2, 0));

+		final List<Node> childNodes = parent.getChildNodes(parent.getRange().resizeBy(-2, 0));

 		assertTextNodeEquals("Hello ", 7, 12, childNodes.get(0));

 		assertChildNodeEquals("Child1", 13, 20, childNodes.get(1));

 		assertChildNodeEquals("Child2", 21, 28, childNodes.get(2));

diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/RangeTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/RangeTest.java
index 4171924..b77910d 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/RangeTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/RangeTest.java
@@ -59,7 +59,7 @@
 

 	@Test

 	public void canMoveBounds() throws Exception {

-		assertEquals(new ContentRange(1, 8), new ContentRange(3, 5).resize(-2, 3));

+		assertEquals(new ContentRange(1, 8), new ContentRange(3, 5).resizeBy(-2, 3));

 	}

 

 	@Test

diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/L2SelectionTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/L2SelectionTest.java
index ebe2bdd..73aa374 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/L2SelectionTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/L2SelectionTest.java
@@ -41,7 +41,7 @@
 		final Element titleElement = widget.insertElement(TITLE);

 		widget.moveBy(-1, true);

 		assertTrue(widget.hasSelection());

-		assertEquals(titleElement.getRange().resize(0, -1), widget.getSelectedRange());

+		assertEquals(titleElement.getRange().resizeBy(0, -1), widget.getSelectedRange());

 	}

 

 	@Test

@@ -51,7 +51,7 @@
 		widget.moveBy(-5, false);

 		widget.moveTo(titleElement.getStartOffset(), true);

 		assertTrue(widget.hasSelection());

-		assertEquals(titleElement.getRange().resize(0, -1), widget.getSelectedRange());

+		assertEquals(titleElement.getRange().resizeBy(0, -1), widget.getSelectedRange());

 	}

 

 	@Test

@@ -68,6 +68,6 @@
 		final Element titleElement = widget.insertElement(TITLE);

 		widget.insertText("Hello World");

 		widget.moveTo(titleElement.getStartOffset() + 1, true);

-		assertEquals(titleElement.getRange().resize(1, -1), widget.getSelectedRange());

+		assertEquals(titleElement.getRange().resizeBy(1, -1), widget.getSelectedRange());

 	}

 }

diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/ContentRange.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/ContentRange.java
index d8cb81c..79bc33a 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/ContentRange.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/ContentRange.java
@@ -61,10 +61,10 @@
 	}

 

 	public ContentRange moveBy(final int delta) {

-		return resize(delta, delta);

+		return resizeBy(delta, delta);

 	}

 

-	public ContentRange resize(final int deltaStart, final int deltaEnd) {

+	public ContentRange resizeBy(final int deltaStart, final int deltaEnd) {

 		return new ContentRange(startOffset + deltaStart, endOffset + deltaEnd);

 	}

 

diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java
index 91149fb..21a8ac3 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java
@@ -187,7 +187,7 @@
 		if (range.getEndOffset() < gapStart) {
 			appendPlainText(result, range);
 		} else if (range.getStartOffset() >= gapStart) {
-			appendPlainText(result, range.resize(delta, delta));
+			appendPlainText(result, range.moveBy(delta));
 		} else {
 			appendPlainText(result, new ContentRange(range.getStartOffset(), gapStart - 1));
 			appendPlainText(result, new ContentRange(gapEnd, range.getEndOffset() + delta));
@@ -216,7 +216,7 @@
 		if (range.getEndOffset() < gapStart) {
 			appendRawText(result, range);
 		} else if (range.getStartOffset() >= gapStart) {
-			appendRawText(result, range.resize(delta, delta));
+			appendRawText(result, range.moveBy(delta));
 		} else {
 			appendRawText(result, new ContentRange(range.getStartOffset(), gapStart - 1));
 			appendRawText(result, new ContentRange(gapEnd, range.getEndOffset() + delta));
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 b2f62ea..d8c28f5 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
@@ -559,8 +559,7 @@
 
 	public VerticalRange layout(final LayoutContext context, final int top, final int bottom) {
 
-		int repaintStart = Integer.MAX_VALUE;
-		int repaintEnd = 0;
+		VerticalRange repaintRange = null;
 		boolean repaintToBottom = false;
 		final int originalHeight = getHeight();
 
@@ -583,7 +582,7 @@
 
 			// repaint everything
 			repaintToBottom = true;
-			repaintStart = 0;
+			repaintRange = new VerticalRange(0, 0);
 		}
 
 		final Box[] children = getChildren();
@@ -592,10 +591,13 @@
 				final BlockBox child = (BlockBox) element2;
 				if (top <= child.getY() + child.getHeight() && bottom >= child.getY()) {
 
-					final VerticalRange repaintRange = child.layout(context, top - child.getY(), bottom - child.getY());
-					if (repaintRange != null) {
-						repaintStart = Math.min(repaintStart, repaintRange.getStart() + child.getY());
-						repaintEnd = Math.max(repaintEnd, repaintRange.getEnd() + child.getY());
+					final VerticalRange layoutRange = child.layout(context, top - child.getY(), bottom - child.getY());
+					if (layoutRange != null) {
+						if (repaintRange == null) {
+							repaintRange = layoutRange.moveBy(child.getY());
+						} else {
+							repaintRange = repaintRange.union(layoutRange.moveBy(child.getY()));
+						}
 					}
 				}
 			}
@@ -604,20 +606,20 @@
 		final int childRepaintStart = positionChildren(context);
 		if (childRepaintStart != -1) {
 			repaintToBottom = true;
-			repaintStart = Math.min(repaintStart, childRepaintStart);
+			repaintRange = new VerticalRange(Math.min(repaintRange.getStart(), childRepaintStart), repaintRange.getEnd());
 		}
 
 		layoutState = LAYOUT_OK;
 
 		if (repaintToBottom) {
-			repaintEnd = Math.max(originalHeight, getHeight());
+			repaintRange = new VerticalRange(repaintRange.getStart(), Math.max(originalHeight, getHeight()));
 		}
 
-		if (repaintStart < repaintEnd) {
-			return new VerticalRange(repaintStart, repaintEnd);
-		} else {
+		if (repaintRange == null || repaintRange.isEmpty()) {
 			return null;
 		}
+
+		return repaintRange;
 	}
 
 	protected abstract List<Box> createChildren(LayoutContext context);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/RootBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/RootBox.java
index 7d57c90..7a58528 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/RootBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/RootBox.java
@@ -154,7 +154,7 @@
 		setHeight(childBox.getHeight() + insets.getTop() + insets.getBottom());
 
 		if (repaintRange != null) {
-			return new VerticalRange(repaintRange.getStart() + childBox.getY(), repaintRange.getEnd() + childBox.getY());
+			return repaintRange.moveBy(childBox.getY());
 		} else {
 			return null;
 		}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/VerticalRange.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/VerticalRange.java
index 8669f70..5058eb8 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/VerticalRange.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/VerticalRange.java
@@ -51,6 +51,25 @@
 		return end;
 	}
 
+	public int getHeight() {
+		return end - start;
+	}
+
+	/**
+	 * Returns true if start and end are equal.
+	 */
+	public boolean isEmpty() {
+		return getHeight() == 0;
+	}
+
+	public boolean contains(final VerticalRange other) {
+		return start <= other.start && end >= other.end;
+	}
+
+	public boolean contains(final int y) {
+		return start <= y && y <= end;
+	}
+
 	/**
 	 * Returns true if this range intersects the given range, even if the result would be an empty range.
 	 * 
@@ -88,11 +107,12 @@
 		return new VerticalRange(Math.min(start, range.start), Math.min(end, range.end));
 	}
 
-	/**
-	 * Returns true if start and end are equal.
-	 */
-	public boolean isEmpty() {
-		return start == end;
+	public VerticalRange moveBy(final int delta) {
+		return resizeBy(delta, delta);
+	}
+
+	public VerticalRange resizeBy(final int deltaStart, final int deltaEnd) {
+		return new VerticalRange(start + deltaStart, end + deltaEnd);
 	}
 
 	@Override
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/undo/InsertFragmentEdit.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/undo/InsertFragmentEdit.java
index 7d29813..f34a735 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/undo/InsertFragmentEdit.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/undo/InsertFragmentEdit.java
@@ -22,7 +22,7 @@
 

 	public void undo() throws CannotUndoException {

 		try {

-			document.delete(fragment.getContent().getRange().resize(offset, offset));

+			document.delete(fragment.getContent().getRange().moveBy(offset));

 		} catch (final DocumentValidationException ex) {

 			throw new CannotUndoException();

 		}

diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/VexWidgetImpl.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/VexWidgetImpl.java
index 3bcf8d0..a5c46a8 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/VexWidgetImpl.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/VexWidgetImpl.java
@@ -34,6 +34,7 @@
 import org.eclipse.vex.core.internal.css.StyleSheet;
 import org.eclipse.vex.core.internal.css.StyleSheetReader;
 import org.eclipse.vex.core.internal.css.Styles;
+import org.eclipse.vex.core.internal.dom.ContentRange;
 import org.eclipse.vex.core.internal.dom.Document;
 import org.eclipse.vex.core.internal.dom.DocumentEvent;
 import org.eclipse.vex.core.internal.dom.DocumentFragment;
@@ -42,15 +43,14 @@
 import org.eclipse.vex.core.internal.dom.Element;
 import org.eclipse.vex.core.internal.dom.Node;
 import org.eclipse.vex.core.internal.dom.Position;
-import org.eclipse.vex.core.internal.dom.ContentRange;
 import org.eclipse.vex.core.internal.dom.Validator;
 import org.eclipse.vex.core.internal.layout.BlockBox;
 import org.eclipse.vex.core.internal.layout.Box;
 import org.eclipse.vex.core.internal.layout.BoxFactory;
 import org.eclipse.vex.core.internal.layout.CssBoxFactory;
-import org.eclipse.vex.core.internal.layout.VerticalRange;
 import org.eclipse.vex.core.internal.layout.LayoutContext;
 import org.eclipse.vex.core.internal.layout.RootBox;
+import org.eclipse.vex.core.internal.layout.VerticalRange;
 import org.eclipse.vex.core.internal.undo.CannotRedoException;
 import org.eclipse.vex.core.internal.undo.CannotUndoException;
 import org.eclipse.vex.core.internal.undo.ChangeAttributeEdit;
@@ -1439,19 +1439,20 @@
 	 */
 	private void iterateLayout(final int offset) {
 
-		int repaintStart = Integer.MAX_VALUE;
-		int repaintEnd = 0;
+		VerticalRange repaintRange = null;
 		final Graphics g = hostComponent.createDefaultGraphics();
 		final LayoutContext context = createLayoutContext(g);
 		int layoutY = rootBox.getCaret(context, offset).getY();
 
 		while (true) {
-
 			final int oldLayoutY = layoutY;
-			final VerticalRange repaintRange = rootBox.layout(context, layoutY - LAYOUT_WINDOW / 2, layoutY + LAYOUT_WINDOW / 2);
-			if (repaintRange != null) {
-				repaintStart = Math.min(repaintStart, repaintRange.getStart());
-				repaintEnd = Math.max(repaintEnd, repaintRange.getEnd());
+			final VerticalRange layoutRange = rootBox.layout(context, layoutY - LAYOUT_WINDOW / 2, layoutY + LAYOUT_WINDOW / 2);
+			if (layoutRange != null) {
+				if (repaintRange == null) {
+					repaintRange = layoutRange;
+				} else {
+					repaintRange = repaintRange.union(layoutRange);
+				}
 			}
 
 			layoutY = rootBox.getCaret(context, offset).getY();
@@ -1461,13 +1462,15 @@
 		}
 		g.dispose();
 
-		if (repaintStart < repaintEnd) {
-			final Rectangle viewport = hostComponent.getViewport();
-			if (repaintStart < viewport.getY() + viewport.getHeight() && repaintEnd > viewport.getY()) {
-				final int start = Math.max(repaintStart, viewport.getY());
-				final int end = Math.min(repaintEnd, viewport.getY() + viewport.getHeight());
-				hostComponent.repaint(viewport.getX(), start, viewport.getWidth(), end - start);
-			}
+		if (repaintRange == null || repaintRange.isEmpty()) {
+			return;
+		}
+
+		final Rectangle viewport = hostComponent.getViewport();
+		final VerticalRange viewportRange = new VerticalRange(viewport.getY(), viewport.getY() + viewport.getHeight());
+		if (repaintRange.intersects(viewportRange)) {
+			final VerticalRange intersection = repaintRange.intersection(viewportRange);
+			hostComponent.repaint(viewport.getX(), intersection.getStart(), viewport.getWidth(), intersection.getHeight());
 		}
 	}