add box classes that represent a tables, row groups, rows, and cells

Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/BaseBoxVisitor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/BaseBoxVisitor.java
index 9575355..deb1b83 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/BaseBoxVisitor.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/BaseBoxVisitor.java
@@ -51,6 +51,26 @@
 	}
 
 	@Override
+	public void visit(final Table box) {
+		// ignore
+	}
+
+	@Override
+	public void visit(final TableRowGroup box) {
+		// ignore
+	}
+
+	@Override
+	public void visit(final TableRow box) {
+		// ignore
+	}
+
+	@Override
+	public void visit(final TableCell box) {
+		// ignore
+	}
+
+	@Override
 	public void visit(final Paragraph box) {
 		// ignore
 	}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/BaseBoxVisitorWithResult.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/BaseBoxVisitorWithResult.java
index 6364940..09758c9 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/BaseBoxVisitorWithResult.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/BaseBoxVisitorWithResult.java
@@ -61,6 +61,26 @@
 	}
 
 	@Override
+	public T visit(final Table box) {
+		return defaultValue;
+	}
+
+	@Override
+	public T visit(final TableRowGroup box) {
+		return defaultValue;
+	}
+
+	@Override
+	public T visit(final TableRow box) {
+		return defaultValue;
+	}
+
+	@Override
+	public T visit(final TableCell box) {
+		return defaultValue;
+	}
+
+	@Override
 	public T visit(final Paragraph box) {
 		return defaultValue;
 	}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/BoxFactory.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/BoxFactory.java
index e47f8e1..6d7da5c 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/BoxFactory.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/BoxFactory.java
@@ -142,6 +142,38 @@
 		return listItem;
 	}
 
+	public static Table table(final IStructuralBox... children) {
+		final Table table = new Table();
+		for (final IStructuralBox child : children) {
+			table.appendChild(child);
+		}
+		return table;
+	}
+
+	public static TableRowGroup tableRowGroup(final IStructuralBox... children) {
+		final TableRowGroup tableRowGroup = new TableRowGroup();
+		for (final IStructuralBox child : children) {
+			tableRowGroup.appendChild(child);
+		}
+		return tableRowGroup;
+	}
+
+	public static TableRow tableRow(final IStructuralBox... children) {
+		final TableRow tableRow = new TableRow();
+		for (final IStructuralBox child : children) {
+			tableRow.appendChild(child);
+		}
+		return tableRow;
+	}
+
+	public static TableCell tableCell(final IStructuralBox... children) {
+		final TableCell tableCell = new TableCell();
+		for (final IStructuralBox child : children) {
+			tableCell.appendChild(child);
+		}
+		return tableCell;
+	}
+
 	public static Paragraph paragraph(final IInlineBox... children) {
 		final Paragraph paragraph = new Paragraph();
 		for (final IInlineBox child : children) {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/DepthFirstBoxTraversal.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/DepthFirstBoxTraversal.java
index 6fcea6b..b4b2d70 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/DepthFirstBoxTraversal.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/DepthFirstBoxTraversal.java
@@ -50,6 +50,26 @@
 	}
 
 	@Override
+	public T visit(final Table box) {
+		return traverseChildren(box);
+	}
+
+	@Override
+	public T visit(final TableRowGroup box) {
+		return traverseChildren(box);
+	}
+
+	@Override
+	public T visit(final TableRow box) {
+		return traverseChildren(box);
+	}
+
+	@Override
+	public T visit(final TableCell box) {
+		return traverseChildren(box);
+	}
+
+	@Override
 	public T visit(final Paragraph box) {
 		return traverseChildren(box);
 	}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/IBoxVisitor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/IBoxVisitor.java
index be3bc01..7209f9e 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/IBoxVisitor.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/IBoxVisitor.java
@@ -29,6 +29,14 @@
 
 	void visit(ListItem box);
 
+	void visit(Table box);
+
+	void visit(TableRowGroup box);
+
+	void visit(TableRow box);
+
+	void visit(TableCell box);
+
 	void visit(Paragraph box);
 
 	void visit(InlineNodeReference box);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/IBoxVisitorWithResult.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/IBoxVisitorWithResult.java
index 1a01ea0..583a140 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/IBoxVisitorWithResult.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/IBoxVisitorWithResult.java
@@ -29,6 +29,14 @@
 
 	T visit(ListItem box);
 
+	T visit(Table box);
+
+	T visit(TableRowGroup box);
+
+	T visit(TableRow box);
+
+	T visit(TableCell box);
+
 	T visit(Paragraph box);
 
 	T visit(InlineNodeReference box);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/ParentTraversal.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/ParentTraversal.java
index 9e5ae4a..f5d41a2 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/ParentTraversal.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/ParentTraversal.java
@@ -61,6 +61,26 @@
 	}
 
 	@Override
+	public T visit(final Table box) {
+		return box.getParent().accept(this);
+	}
+
+	@Override
+	public T visit(final TableRowGroup box) {
+		return box.getParent().accept(this);
+	}
+
+	@Override
+	public T visit(final TableRow box) {
+		return box.getParent().accept(this);
+	}
+
+	@Override
+	public T visit(final TableCell box) {
+		return box.getParent().accept(this);
+	}
+
+	@Override
 	public T visit(final Paragraph box) {
 		return box.getParent().accept(this);
 	}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/Table.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/Table.java
new file mode 100644
index 0000000..d09c7b7
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/Table.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Florian Thienel and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * 		Florian Thienel - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.boxes;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.ListIterator;
+
+import org.eclipse.vex.core.internal.core.Graphics;
+import org.eclipse.vex.core.internal.core.Rectangle;
+
+/**
+ * @author Florian Thienel
+ */
+public class Table extends BaseBox implements IStructuralBox, IParentBox<IStructuralBox> {
+
+	private IBox parent;
+	private int top;
+	private int left;
+	private int width;
+	private int height;
+	private final ArrayList<IStructuralBox> children = new ArrayList<IStructuralBox>();
+
+	@Override
+	public void setParent(final IBox parent) {
+		this.parent = parent;
+	}
+
+	@Override
+	public IBox getParent() {
+		return parent;
+	}
+
+	@Override
+	public int getAbsoluteTop() {
+		if (parent == null) {
+			return top;
+		}
+		return parent.getAbsoluteTop() + top;
+	}
+
+	@Override
+	public int getAbsoluteLeft() {
+		if (parent == null) {
+			return left;
+		}
+		return parent.getAbsoluteLeft() + left;
+	}
+
+	public int getTop() {
+		return top;
+	}
+
+	public int getLeft() {
+		return left;
+	}
+
+	public void setPosition(final int top, final int left) {
+		this.top = top;
+		this.left = left;
+	}
+
+	@Override
+	public int getWidth() {
+		return width;
+	}
+
+	public void setWidth(final int width) {
+		this.width = Math.max(0, width);
+	}
+
+	@Override
+	public int getHeight() {
+		return height;
+	}
+
+	@Override
+	public Rectangle getBounds() {
+		return new Rectangle(left, top, width, height);
+	}
+
+	@Override
+	public void accept(final IBoxVisitor visitor) {
+		visitor.visit(this);
+	}
+
+	@Override
+	public <T> T accept(final IBoxVisitorWithResult<T> visitor) {
+		return visitor.visit(this);
+	}
+
+	public boolean hasChildren() {
+		return !children.isEmpty();
+	}
+
+	public void prependChild(final IStructuralBox child) {
+		if (child == null) {
+			return;
+		}
+		child.setParent(this);
+		children.add(0, child);
+	}
+
+	public void appendChild(final IStructuralBox child) {
+		if (child == null) {
+			return;
+		}
+		child.setParent(this);
+		children.add(child);
+	}
+
+	@Override
+	public void replaceChildren(final Collection<? extends IBox> oldChildren, final IStructuralBox newChild) {
+		boolean newChildInserted = false;
+
+		for (final ListIterator<IStructuralBox> iter = children.listIterator(); iter.hasNext();) {
+			final IStructuralBox child = iter.next();
+			if (oldChildren.contains(child)) {
+				iter.remove();
+				if (!newChildInserted) {
+					iter.add(newChild);
+					newChild.setParent(this);
+					newChildInserted = true;
+				}
+			}
+		}
+	}
+
+	public Iterable<IStructuralBox> getChildren() {
+		return children;
+	}
+
+	public void layout(final Graphics graphics) {
+		height = 0;
+		for (int i = 0; i < children.size(); i += 1) {
+			final IStructuralBox child = children.get(i);
+			child.setPosition(height, 0);
+			child.setWidth(width);
+			child.layout(graphics);
+			height += child.getHeight();
+		}
+	}
+
+	@Override
+	public boolean reconcileLayout(final Graphics graphics) {
+		final int oldHeight = height;
+		height = 0;
+		for (int i = 0; i < children.size(); i += 1) {
+			final IStructuralBox child = children.get(i);
+			child.setPosition(height, 0);
+			height += child.getHeight();
+		}
+		return oldHeight != height;
+	}
+
+	@Override
+	public void paint(final Graphics graphics) {
+		ChildBoxPainter.paint(children, graphics);
+	}
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TableCell.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TableCell.java
new file mode 100644
index 0000000..8f68528
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TableCell.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Florian Thienel and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * 		Florian Thienel - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.boxes;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.ListIterator;
+
+import org.eclipse.vex.core.internal.core.Graphics;
+import org.eclipse.vex.core.internal.core.Rectangle;
+
+/**
+ * @author Florian Thienel
+ */
+public class TableCell extends BaseBox implements IStructuralBox, IParentBox<IStructuralBox> {
+
+	private IBox parent;
+	private int top;
+	private int left;
+	private int width;
+	private int height;
+	private final ArrayList<IStructuralBox> children = new ArrayList<IStructuralBox>();
+
+	@Override
+	public void setParent(final IBox parent) {
+		this.parent = parent;
+	}
+
+	@Override
+	public IBox getParent() {
+		return parent;
+	}
+
+	@Override
+	public int getAbsoluteTop() {
+		if (parent == null) {
+			return top;
+		}
+		return parent.getAbsoluteTop() + top;
+	}
+
+	@Override
+	public int getAbsoluteLeft() {
+		if (parent == null) {
+			return left;
+		}
+		return parent.getAbsoluteLeft() + left;
+	}
+
+	public int getTop() {
+		return top;
+	}
+
+	public int getLeft() {
+		return left;
+	}
+
+	public void setPosition(final int top, final int left) {
+		this.top = top;
+		this.left = left;
+	}
+
+	@Override
+	public int getWidth() {
+		return width;
+	}
+
+	public void setWidth(final int width) {
+		this.width = Math.max(0, width);
+	}
+
+	@Override
+	public int getHeight() {
+		return height;
+	}
+
+	@Override
+	public Rectangle getBounds() {
+		return new Rectangle(left, top, width, height);
+	}
+
+	@Override
+	public void accept(final IBoxVisitor visitor) {
+		visitor.visit(this);
+	}
+
+	@Override
+	public <T> T accept(final IBoxVisitorWithResult<T> visitor) {
+		return visitor.visit(this);
+	}
+
+	public boolean hasChildren() {
+		return !children.isEmpty();
+	}
+
+	public void prependChild(final IStructuralBox child) {
+		if (child == null) {
+			return;
+		}
+		child.setParent(this);
+		children.add(0, child);
+	}
+
+	public void appendChild(final IStructuralBox child) {
+		if (child == null) {
+			return;
+		}
+		child.setParent(this);
+		children.add(child);
+	}
+
+	@Override
+	public void replaceChildren(final Collection<? extends IBox> oldChildren, final IStructuralBox newChild) {
+		boolean newChildInserted = false;
+
+		for (final ListIterator<IStructuralBox> iter = children.listIterator(); iter.hasNext();) {
+			final IStructuralBox child = iter.next();
+			if (oldChildren.contains(child)) {
+				iter.remove();
+				if (!newChildInserted) {
+					iter.add(newChild);
+					newChild.setParent(this);
+					newChildInserted = true;
+				}
+			}
+		}
+	}
+
+	public Iterable<IStructuralBox> getChildren() {
+		return children;
+	}
+
+	public void layout(final Graphics graphics) {
+		height = 0;
+		for (int i = 0; i < children.size(); i += 1) {
+			final IStructuralBox child = children.get(i);
+			child.setPosition(height, 0);
+			child.setWidth(width);
+			child.layout(graphics);
+			height += child.getHeight();
+		}
+	}
+
+	@Override
+	public boolean reconcileLayout(final Graphics graphics) {
+		final int oldHeight = height;
+		height = 0;
+		for (int i = 0; i < children.size(); i += 1) {
+			final IStructuralBox child = children.get(i);
+			child.setPosition(height, 0);
+			height += child.getHeight();
+		}
+		return oldHeight != height;
+	}
+
+	@Override
+	public void paint(final Graphics graphics) {
+		ChildBoxPainter.paint(children, graphics);
+	}
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TableRow.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TableRow.java
new file mode 100644
index 0000000..fe4d588
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TableRow.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Florian Thienel and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * 		Florian Thienel - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.boxes;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.ListIterator;
+
+import org.eclipse.vex.core.internal.core.Graphics;
+import org.eclipse.vex.core.internal.core.Rectangle;
+
+/**
+ * @author Florian Thienel
+ */
+public class TableRow extends BaseBox implements IStructuralBox, IParentBox<IStructuralBox> {
+
+	private IBox parent;
+	private int top;
+	private int left;
+	private int width;
+	private int height;
+	private final ArrayList<IStructuralBox> children = new ArrayList<IStructuralBox>();
+
+	@Override
+	public void setParent(final IBox parent) {
+		this.parent = parent;
+	}
+
+	@Override
+	public IBox getParent() {
+		return parent;
+	}
+
+	@Override
+	public int getAbsoluteTop() {
+		if (parent == null) {
+			return top;
+		}
+		return parent.getAbsoluteTop() + top;
+	}
+
+	@Override
+	public int getAbsoluteLeft() {
+		if (parent == null) {
+			return left;
+		}
+		return parent.getAbsoluteLeft() + left;
+	}
+
+	public int getTop() {
+		return top;
+	}
+
+	public int getLeft() {
+		return left;
+	}
+
+	public void setPosition(final int top, final int left) {
+		this.top = top;
+		this.left = left;
+	}
+
+	@Override
+	public int getWidth() {
+		return width;
+	}
+
+	public void setWidth(final int width) {
+		this.width = Math.max(0, width);
+	}
+
+	@Override
+	public int getHeight() {
+		return height;
+	}
+
+	@Override
+	public Rectangle getBounds() {
+		return new Rectangle(left, top, width, height);
+	}
+
+	@Override
+	public void accept(final IBoxVisitor visitor) {
+		visitor.visit(this);
+	}
+
+	@Override
+	public <T> T accept(final IBoxVisitorWithResult<T> visitor) {
+		return visitor.visit(this);
+	}
+
+	public boolean hasChildren() {
+		return !children.isEmpty();
+	}
+
+	public void prependChild(final IStructuralBox child) {
+		if (child == null) {
+			return;
+		}
+		child.setParent(this);
+		children.add(0, child);
+	}
+
+	public void appendChild(final IStructuralBox child) {
+		if (child == null) {
+			return;
+		}
+		child.setParent(this);
+		children.add(child);
+	}
+
+	@Override
+	public void replaceChildren(final Collection<? extends IBox> oldChildren, final IStructuralBox newChild) {
+		boolean newChildInserted = false;
+
+		for (final ListIterator<IStructuralBox> iter = children.listIterator(); iter.hasNext();) {
+			final IStructuralBox child = iter.next();
+			if (oldChildren.contains(child)) {
+				iter.remove();
+				if (!newChildInserted) {
+					iter.add(newChild);
+					newChild.setParent(this);
+					newChildInserted = true;
+				}
+			}
+		}
+	}
+
+	public Iterable<IStructuralBox> getChildren() {
+		return children;
+	}
+
+	public void layout(final Graphics graphics) {
+		height = 0;
+		for (int i = 0; i < children.size(); i += 1) {
+			final IStructuralBox child = children.get(i);
+			child.setPosition(height, 0);
+			child.setWidth(width);
+			child.layout(graphics);
+			height += child.getHeight();
+		}
+	}
+
+	@Override
+	public boolean reconcileLayout(final Graphics graphics) {
+		final int oldHeight = height;
+		height = 0;
+		for (int i = 0; i < children.size(); i += 1) {
+			final IStructuralBox child = children.get(i);
+			child.setPosition(height, 0);
+			height += child.getHeight();
+		}
+		return oldHeight != height;
+	}
+
+	@Override
+	public void paint(final Graphics graphics) {
+		ChildBoxPainter.paint(children, graphics);
+	}
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TableRowGroup.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TableRowGroup.java
new file mode 100644
index 0000000..71f7f40
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/boxes/TableRowGroup.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Florian Thienel and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * 		Florian Thienel - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.boxes;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.ListIterator;
+
+import org.eclipse.vex.core.internal.core.Graphics;
+import org.eclipse.vex.core.internal.core.Rectangle;
+
+/**
+ * @author Florian Thienel
+ */
+public class TableRowGroup extends BaseBox implements IStructuralBox, IParentBox<IStructuralBox> {
+
+	private IBox parent;
+	private int top;
+	private int left;
+	private int width;
+	private int height;
+	private final ArrayList<IStructuralBox> children = new ArrayList<IStructuralBox>();
+
+	@Override
+	public void setParent(final IBox parent) {
+		this.parent = parent;
+	}
+
+	@Override
+	public IBox getParent() {
+		return parent;
+	}
+
+	@Override
+	public int getAbsoluteTop() {
+		if (parent == null) {
+			return top;
+		}
+		return parent.getAbsoluteTop() + top;
+	}
+
+	@Override
+	public int getAbsoluteLeft() {
+		if (parent == null) {
+			return left;
+		}
+		return parent.getAbsoluteLeft() + left;
+	}
+
+	public int getTop() {
+		return top;
+	}
+
+	public int getLeft() {
+		return left;
+	}
+
+	public void setPosition(final int top, final int left) {
+		this.top = top;
+		this.left = left;
+	}
+
+	@Override
+	public int getWidth() {
+		return width;
+	}
+
+	public void setWidth(final int width) {
+		this.width = Math.max(0, width);
+	}
+
+	@Override
+	public int getHeight() {
+		return height;
+	}
+
+	@Override
+	public Rectangle getBounds() {
+		return new Rectangle(left, top, width, height);
+	}
+
+	@Override
+	public void accept(final IBoxVisitor visitor) {
+		visitor.visit(this);
+	}
+
+	@Override
+	public <T> T accept(final IBoxVisitorWithResult<T> visitor) {
+		return visitor.visit(this);
+	}
+
+	public boolean hasChildren() {
+		return !children.isEmpty();
+	}
+
+	public void prependChild(final IStructuralBox child) {
+		if (child == null) {
+			return;
+		}
+		child.setParent(this);
+		children.add(0, child);
+	}
+
+	public void appendChild(final IStructuralBox child) {
+		if (child == null) {
+			return;
+		}
+		child.setParent(this);
+		children.add(child);
+	}
+
+	@Override
+	public void replaceChildren(final Collection<? extends IBox> oldChildren, final IStructuralBox newChild) {
+		boolean newChildInserted = false;
+
+		for (final ListIterator<IStructuralBox> iter = children.listIterator(); iter.hasNext();) {
+			final IStructuralBox child = iter.next();
+			if (oldChildren.contains(child)) {
+				iter.remove();
+				if (!newChildInserted) {
+					iter.add(newChild);
+					newChild.setParent(this);
+					newChildInserted = true;
+				}
+			}
+		}
+	}
+
+	public Iterable<IStructuralBox> getChildren() {
+		return children;
+	}
+
+	public void layout(final Graphics graphics) {
+		height = 0;
+		for (int i = 0; i < children.size(); i += 1) {
+			final IStructuralBox child = children.get(i);
+			child.setPosition(height, 0);
+			child.setWidth(width);
+			child.layout(graphics);
+			height += child.getHeight();
+		}
+	}
+
+	@Override
+	public boolean reconcileLayout(final Graphics graphics) {
+		final int oldHeight = height;
+		height = 0;
+		for (int i = 0; i < children.size(); i += 1) {
+			final IStructuralBox child = children.get(i);
+			child.setPosition(height, 0);
+			height += child.getHeight();
+		}
+		return oldHeight != height;
+	}
+
+	@Override
+	public void paint(final Graphics graphics) {
+		ChildBoxPainter.paint(children, graphics);
+	}
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/DOMVisualization.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/DOMVisualization.java
index eedf7a1..bbfa746 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/DOMVisualization.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/DOMVisualization.java
@@ -28,6 +28,10 @@
 import org.eclipse.vex.core.internal.boxes.RootBox;
 import org.eclipse.vex.core.internal.boxes.StructuralFrame;
 import org.eclipse.vex.core.internal.boxes.StructuralNodeReference;
+import org.eclipse.vex.core.internal.boxes.Table;
+import org.eclipse.vex.core.internal.boxes.TableCell;
+import org.eclipse.vex.core.internal.boxes.TableRow;
+import org.eclipse.vex.core.internal.boxes.TableRowGroup;
 import org.eclipse.vex.core.internal.boxes.TextContent;
 import org.eclipse.vex.core.internal.boxes.VerticalBlock;
 import org.eclipse.vex.core.internal.cursor.ContentTopology;
@@ -137,6 +141,26 @@
 			}
 
 			@Override
+			public void visit(final Table box) {
+				box.replaceChildren(modifiedBoxes, boxModelBuilder.visualizeStructure(node));
+			}
+
+			@Override
+			public void visit(final TableRowGroup box) {
+				box.replaceChildren(modifiedBoxes, boxModelBuilder.visualizeStructure(node));
+			}
+
+			@Override
+			public void visit(final TableRow box) {
+				box.replaceChildren(modifiedBoxes, boxModelBuilder.visualizeStructure(node));
+			}
+
+			@Override
+			public void visit(final TableCell box) {
+				box.replaceChildren(modifiedBoxes, boxModelBuilder.visualizeStructure(node));
+			}
+
+			@Override
 			public void visit(final Paragraph box) {
 				box.replaceChildren(modifiedBoxes, boxModelBuilder.visualizeInline(node));
 			}