Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Thienel2014-03-18 19:43:46 +0000
committerFlorian Thienel2014-03-18 19:43:46 +0000
commit32f17c8068b095d6d05c0fb043b7569753d1b622 (patch)
treead57f2bf75abb7594fe0cf1ac382787a00921926
parent55548d4b77b56ab230e9de6083bea4cad2228966 (diff)
downloadorg.eclipse.mylyn.docs.vex-32f17c8068b095d6d05c0fb043b7569753d1b622.tar.gz
org.eclipse.mylyn.docs.vex-32f17c8068b095d6d05c0fb043b7569753d1b622.tar.xz
org.eclipse.mylyn.docs.vex-32f17c8068b095d6d05c0fb043b7569753d1b622.zip
extract distinct BlockBox implementation for list items
The handling of list items was contained in BlockElementBox. This change moves the list item handling into its own BlockBox derivative. Change-Id: Ia899ed4a75b371cd2dc0064d15fd88806587ae0f Signed-off-by: Florian Thienel <florian@thienel.org>
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/BlockElementBoxTest.java (renamed from org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/BlockElementBoxTest.java)3
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTest.java1
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/lists.css33
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/lists.xml142
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/tables.xml4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockElementBox.java214
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/Bullet.java41
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CircleBullet.java35
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CssBoxFactory.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DiscBullet.java33
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ListItemBox.java176
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/SquareBullet.java35
12 files changed, 504 insertions, 217 deletions
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/BlockElementBoxTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/BlockElementBoxTest.java
index 26a09ff1..97e67998 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/BlockElementBoxTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/BlockElementBoxTest.java
@@ -8,7 +8,7 @@
* Contributors:
* John Krasnay - initial API and implementation
*******************************************************************************/
-package org.eclipse.vex.core.internal.dom;
+package org.eclipse.vex.core.internal.layout;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -25,7 +25,6 @@ import org.eclipse.vex.core.internal.io.DocumentReader;
import org.eclipse.vex.core.internal.layout.BlockElementBox;
import org.eclipse.vex.core.internal.layout.Box;
import org.eclipse.vex.core.internal.layout.CssBoxFactory;
-import org.eclipse.vex.core.internal.layout.FakeGraphics;
import org.eclipse.vex.core.internal.layout.LayoutContext;
import org.eclipse.vex.core.internal.layout.RootBox;
import org.eclipse.vex.core.provisional.dom.IDocument;
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTest.java
index e3b3181d..8f89e27f 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTest.java
@@ -79,6 +79,7 @@ public class LayoutTest extends TestCase {
suite.addTest(loadSuite("before-after.xml"));
suite.addTest(loadSuite("linebreaks.xml"));
suite.addTest(loadSuite("tables.xml"));
+ suite.addTest(loadSuite("lists.xml"));
suite.addTest(loadSuite("simple-edit.xml"));
suite.addTest(loadSuite("comment-processing-instr.xml"));
suite.addTest(loadSuite("include.xml"));
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/lists.css b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/lists.css
new file mode 100644
index 00000000..d8cb7ba4
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/lists.css
@@ -0,0 +1,33 @@
+root {
+ display: block;
+}
+
+ul {
+ display: block;
+ list-style-type: disc;
+}
+
+ul ul {
+ list-style-type: square;
+}
+
+ul ul ul {
+ list-style-type: circle;
+}
+
+ol {
+ display: block;
+ list-item-style: decimal;
+}
+
+ol ol {
+ list-style-type: lower-alpha;
+}
+
+ol ol ol {
+ list-style-type: lower-roman;
+}
+
+li {
+ display: list-item;
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/lists.xml b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/lists.xml
new file mode 100644
index 00000000..6db2071e
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/lists.xml
@@ -0,0 +1,142 @@
+<?xml version='1.0'?>
+<testcases css="lists.css">
+
+ <test id="UL one level (empty)" layoutWidth="100">
+ <doc><![CDATA[ <root><ul><li></li></ul></root> ]]></doc>
+ <result>
+ <box class="RootBox">
+ <box class="BlockElementBox">
+ <box class="BlockElementBox" element="root">
+ <box class="BlockElementBox" element="ul">
+ <box class="ListItemBox" element="li">
+ <box class="ParagraphBox">
+ <box class="LineBox">
+ <box class="PlaceholderBox" />
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </result>
+ </test>
+
+ <test id="UL two levels (empty)" layoutWidth="100">
+ <doc><![CDATA[ <root><ul><ul><li></li></ul></ul></root> ]]></doc>
+ <result>
+ <box class="RootBox">
+ <box class="BlockElementBox">
+ <box class="BlockElementBox" element="root">
+ <box class="BlockElementBox" element="ul">
+ <box class="BlockElementBox" element="ul">
+ <box class="ListItemBox" element="li">
+ <box class="ParagraphBox">
+ <box class="LineBox">
+ <box class="PlaceholderBox" />
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </result>
+ </test>
+
+ <test id="UL three levels (empty)" layoutWidth="100">
+ <doc><![CDATA[ <root><ul><ul><ul><li></li></ul></ul></ul></root> ]]></doc>
+ <result>
+ <box class="RootBox">
+ <box class="BlockElementBox">
+ <box class="BlockElementBox" element="root">
+ <box class="BlockElementBox" element="ul">
+ <box class="BlockElementBox" element="ul">
+ <box class="BlockElementBox" element="ul">
+ <box class="ListItemBox" element="li">
+ <box class="ParagraphBox">
+ <box class="LineBox">
+ <box class="PlaceholderBox" />
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </result>
+ </test>
+
+ <test id="OL one level (empty)" layoutWidth="100">
+ <doc><![CDATA[ <root><ol><li></li></ol></root> ]]></doc>
+ <result>
+ <box class="RootBox">
+ <box class="BlockElementBox">
+ <box class="BlockElementBox" element="root">
+ <box class="BlockElementBox" element="ol">
+ <box class="ListItemBox" element="li">
+ <box class="ParagraphBox">
+ <box class="LineBox">
+ <box class="PlaceholderBox" />
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </result>
+ </test>
+
+ <test id="OL two levels (empty)" layoutWidth="100">
+ <doc><![CDATA[ <root><ol><ol><li></li></ol></ol></root> ]]></doc>
+ <result>
+ <box class="RootBox">
+ <box class="BlockElementBox">
+ <box class="BlockElementBox" element="root">
+ <box class="BlockElementBox" element="ol">
+ <box class="BlockElementBox" element="ol">
+ <box class="ListItemBox" element="li">
+ <box class="ParagraphBox">
+ <box class="LineBox">
+ <box class="PlaceholderBox" />
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </result>
+ </test>
+
+ <test id="OL three levels (empty)" layoutWidth="100">
+ <doc><![CDATA[ <root><ol><ol><ol><li></li></ol></ol></ol></root> ]]></doc>
+ <result>
+ <box class="RootBox">
+ <box class="BlockElementBox">
+ <box class="BlockElementBox" element="root">
+ <box class="BlockElementBox" element="ol">
+ <box class="BlockElementBox" element="ol">
+ <box class="BlockElementBox" element="ol">
+ <box class="ListItemBox" element="li">
+ <box class="ParagraphBox">
+ <box class="LineBox">
+ <box class="PlaceholderBox" />
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </result>
+ </test>
+
+</testcases> \ No newline at end of file
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/tables.xml b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/tables.xml
index e9a25b99..ab4a3dc8 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/tables.xml
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/tables.xml
@@ -305,7 +305,7 @@
</test>
-<!--
+<!--
<test id="Anonymous Table and Row - Empty" layoutWidth="100">
<doc><![CDATA[ <root><td></td></root> ]]></doc>
<result>
@@ -588,7 +588,7 @@
</box>
<box class="TableRowGroupBox" element="tbody">
<box class="TableRowBox">
-
+
</box>
</box>
</box>
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockElementBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockElementBox.java
index 979dbe51..881090ae 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockElementBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockElementBox.java
@@ -17,15 +17,11 @@ import java.util.ArrayList;
import java.util.List;
import org.eclipse.vex.core.internal.VEXCorePlugin;
-import org.eclipse.vex.core.internal.core.Drawable;
-import org.eclipse.vex.core.internal.core.Graphics;
-import org.eclipse.vex.core.internal.core.Rectangle;
import org.eclipse.vex.core.internal.css.CSS;
import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.css.Styles;
import org.eclipse.vex.core.provisional.dom.IElement;
import org.eclipse.vex.core.provisional.dom.INode;
-import org.eclipse.vex.core.provisional.dom.IParent;
/**
* A block box corresponding to a DOM Element. Block boxes lay their children out stacked top to bottom. Block boxes
@@ -33,16 +29,9 @@ import org.eclipse.vex.core.provisional.dom.IParent;
*/
public class BlockElementBox extends AbstractBlockBox {
- /** hspace btn. list-item bullet and block, as fraction of font-size */
- static final float BULLET_SPACE = 0.5f;
-
- /** vspace btn. list-item bullet and baseine, as fraction of font-size */
- // private static final float BULLET_LIFT = 0.1f;
/** number of boxes created since VM startup, for profiling */
private static int boxCount;
- BlockBox beforeMarker;
-
/**
* Class constructor. This box's children are not created here but in the first call to layout. Instead, we estimate
* the box's height here based on the given width.
@@ -59,7 +48,7 @@ public class BlockElementBox extends AbstractBlockBox {
}
/**
- * Returns the number of boxes created since VM startup. Used for profiling.
+ * @return the number of boxes created since VM startup. Used for profiling.
*/
public static int getBoxCount() {
return boxCount;
@@ -76,47 +65,10 @@ public class BlockElementBox extends AbstractBlockBox {
}
@Override
- public void paint(final LayoutContext context, final int x, final int y) {
-
- super.paint(context, x, y);
-
- if (beforeMarker != null) {
- beforeMarker.paint(context, x + beforeMarker.getX(), y + beforeMarker.getY());
- }
- }
-
- @Override
- protected int positionChildren(final LayoutContext context) {
-
- final int repaintStart = super.positionChildren(context);
-
- final Styles styles = context.getStyleSheet().getStyles(getNode());
- if (beforeMarker != null) {
- final int x = -beforeMarker.getWidth() - Math.round(BULLET_SPACE * styles.getFontSize());
- int y = getFirstLineTop(context);
- final LineBox firstLine = getFirstLine();
- if (firstLine != null) {
- y += firstLine.getBaseline() - beforeMarker.getFirstLine().getBaseline();
- }
-
- beforeMarker.setX(x);
- beforeMarker.setY(y);
- }
-
- return repaintStart;
- }
-
- @Override
public String toString() {
return "BlockElementBox: <" + getNode() + ">" + "[x=" + getX() + ",y=" + getY() + ",width=" + getWidth() + ",height=" + getHeight() + "]";
}
- // ===================================================== PRIVATE
-
- /**
- * Lays out the children as vertically stacked blocks. Runs of text and inline elements are wrapped in
- * DummyBlockBox's.
- */
@Override
public List<Box> createChildren(final LayoutContext context) {
long start = 0;
@@ -180,10 +132,6 @@ public class BlockElementBox extends AbstractBlockBox {
childList.add(afterBlock);
}
- if (styles.getDisplay().equals(CSS.LIST_ITEM) && !styles.getListStyleType().equals(CSS.NONE)) {
- createListMarker(context);
- }
-
if (VEXCorePlugin.getInstance().isDebugging()) {
final long end = System.currentTimeMillis();
if (end - start > 10) {
@@ -194,94 +142,7 @@ public class BlockElementBox extends AbstractBlockBox {
return childList;
}
- /**
- * Creates a marker box for this primary box and puts it in the beforeMarker field.
- */
- private void createListMarker(final LayoutContext context) {
-
- final Styles styles = context.getStyleSheet().getStyles(getNode());
-
- InlineBox markerInline;
- final String type = styles.getListStyleType();
- if (type.equals(CSS.NONE)) {
- return;
- } else if (type.equals(CSS.CIRCLE)) {
- markerInline = createCircleBullet(getNode(), styles);
- } else if (type.equals(CSS.SQUARE)) {
- markerInline = createSquareBullet(getNode(), styles);
- } else if (isEnumeratedListStyleType(type)) {
- final String item = getItemNumberString(type);
- markerInline = new StaticTextBox(context, getNode(), item + ".");
- } else {
- markerInline = createDiscBullet(getNode(), styles);
- }
-
- beforeMarker = ParagraphBox.create(context, getNode(), new InlineBox[] { markerInline }, Integer.MAX_VALUE);
-
- }
-
- /**
- * Returns a Drawable that draws a circle-style list item bullet.
- */
- private static InlineBox createCircleBullet(final INode node, final Styles styles) {
- final int size = Math.round(0.5f * styles.getFontSize());
- final int lift = Math.round(0.1f * styles.getFontSize());
- final Drawable drawable = new Drawable() {
- public void draw(final Graphics g, final int x, final int y) {
- g.setLineStyle(Graphics.LINE_SOLID);
- g.setLineWidth(1);
- g.drawOval(x, y - size - lift, size, size);
- }
-
- public Rectangle getBounds() {
- return new Rectangle(0, -size - lift, size, size);
- }
- };
- return new DrawableBox(drawable, node);
- }
-
- /**
- * Returns a Drawable that draws a disc-style list item bullet.
- */
- private static InlineBox createDiscBullet(final INode node, final Styles styles) {
- final int size = Math.round(0.5f * styles.getFontSize());
- final int lift = Math.round(0.1f * styles.getFontSize());
- final Drawable drawable = new Drawable() {
- public void draw(final Graphics g, final int x, final int y) {
- g.fillOval(x, y - size - lift, size, size);
- }
-
- public Rectangle getBounds() {
- return new Rectangle(0, -size - lift, size, size);
- }
- };
- return new DrawableBox(drawable, node);
- }
-
- /**
- * Returns a Drawable that draws a square-style list item bullet.
- */
- private static InlineBox createSquareBullet(final INode node, final Styles styles) {
- final int size = Math.round(0.5f * styles.getFontSize());
- final int lift = Math.round(0.1f * styles.getFontSize());
- final Drawable drawable = new Drawable() {
- public void draw(final Graphics g, final int x, final int y) {
- g.setLineStyle(Graphics.LINE_SOLID);
- g.setLineWidth(1);
- g.drawRect(x, y - size - lift, size, size);
- }
-
- public Rectangle getBounds() {
- return new Rectangle(0, -size - lift, size, size);
- }
- };
- return new DrawableBox(drawable, node);
- }
-
- /**
- * Returns the vertical distance from the top of this box to the top of its first line.
- */
- int getFirstLineTop(final LayoutContext context) {
+ protected int getFirstLineTop(final LayoutContext context) {
final Styles styles = context.getStyleSheet().getStyles(getNode());
final int top = styles.getBorderTopWidth() + styles.getPaddingTop().get(0);
final Box[] children = getChildren();
@@ -292,75 +153,4 @@ public class BlockElementBox extends AbstractBlockBox {
}
}
- /**
- * Returns the item number of this box. The item number indicates the ordinal number of the corresponding element
- * amongst its siblings starting with 1.
- */
- private int getItemNumber() {
- final INode node = getNode();
- final IParent parent = node.getParent();
-
- if (parent == null) {
- return 1;
- }
-
- int item = 1;
- for (final INode child : parent.children()) {
- if (child == node) {
- return item;
- }
- if (child.isKindOf(node)) {
- item++;
- }
- }
-
- throw new IllegalStateException();
- }
-
- private String getItemNumberString(final String style) {
- final int item = getItemNumber();
- if (style.equals(CSS.DECIMAL_LEADING_ZERO)) {
- if (item < 10) {
- return "0" + Integer.toString(item);
- } else {
- return Integer.toString(item);
- }
- } else if (style.equals(CSS.LOWER_ALPHA) || style.equals(CSS.LOWER_LATIN)) {
- return getAlpha(item);
- } else if (style.equals(CSS.LOWER_ROMAN)) {
- return getRoman(item);
- } else if (style.equals(CSS.UPPER_ALPHA) || style.equals(CSS.UPPER_LATIN)) {
- return getAlpha(item).toUpperCase();
- } else if (style.equals(CSS.UPPER_ROMAN)) {
- return getRoman(item).toUpperCase();
- } else {
- return Integer.toString(item);
- }
- }
-
- private String getAlpha(final int n) {
- final String alpha = "abcdefghijklmnopqrstuvwxyz";
- return String.valueOf(alpha.charAt((n - 1) % 26));
- }
-
- private String getRoman(final int n) {
- final String[] ones = { "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix" };
- final String[] tens = { "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc" };
- final String[] hundreds = { "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm" };
- final StringBuffer sb = new StringBuffer();
- for (int i = 0; i < n / 1000; i++) {
- sb.append("m");
- }
- sb.append(hundreds[n / 100 % 10]);
- sb.append(tens[n / 10 % 10]);
- sb.append(ones[n % 10]);
- return sb.toString();
- }
-
- private static boolean isEnumeratedListStyleType(final String s) {
- return s.equals(CSS.ARMENIAN) || s.equals(CSS.CJK_IDEOGRAPHIC) || s.equals(CSS.DECIMAL) || s.equals(CSS.DECIMAL_LEADING_ZERO) || s.equals(CSS.GEORGIAN) || s.equals(CSS.HEBREW)
- || s.equals(CSS.HIRAGANA) || s.equals(CSS.HIRAGANA_IROHA) || s.equals(CSS.KATAKANA) || s.equals(CSS.KATAKANA_IROHA) || s.equals(CSS.LOWER_ALPHA) || s.equals(CSS.LOWER_GREEK)
- || s.equals(CSS.LOWER_LATIN) || s.equals(CSS.LOWER_ROMAN) || s.equals(CSS.UPPER_ALPHA) || s.equals(CSS.UPPER_LATIN) || s.equals(CSS.UPPER_ROMAN);
- }
-
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/Bullet.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/Bullet.java
new file mode 100644
index 00000000..07367550
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/Bullet.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.layout;
+
+import org.eclipse.vex.core.internal.core.Drawable;
+
+/**
+ * @author Florian Thienel
+ */
+public abstract class Bullet implements Drawable {
+
+ // size of the bullet as fraction of font-size
+ private static final float BULLET_SIZE = 0.5f;
+ // vspace between list-item bullet and baseine, as fraction of font-size
+ private static final float BULLET_LIFT = 0.1f;
+
+ final int size;
+ final int lift;
+
+ public Bullet(final float fontSize) {
+ size = Math.round(BULLET_SIZE * fontSize);
+ lift = Math.round(BULLET_LIFT * fontSize);
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public int getLift() {
+ return lift;
+ }
+
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CircleBullet.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CircleBullet.java
new file mode 100644
index 00000000..a7842e25
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CircleBullet.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.layout;
+
+import org.eclipse.vex.core.internal.core.Graphics;
+import org.eclipse.vex.core.internal.core.Rectangle;
+
+/**
+ * @author Florian Thienel
+ */
+public class CircleBullet extends Bullet {
+
+ public CircleBullet(final float fontSize) {
+ super(fontSize);
+ }
+
+ public void draw(final Graphics g, final int x, final int y) {
+ g.setLineStyle(Graphics.LINE_SOLID);
+ g.setLineWidth(1);
+ g.drawOval(x, y - size - lift, size, size);
+ }
+
+ public Rectangle getBounds() {
+ return new Rectangle(0, -size - lift, size, size);
+ }
+
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CssBoxFactory.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CssBoxFactory.java
index 5afde078..07f2cf58 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CssBoxFactory.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CssBoxFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2008 John Krasnay and others.
+ * Copyright (c) 2004, 2014 John Krasnay 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
@@ -48,6 +48,8 @@ public class CssBoxFactory implements BoxFactory {
return new TableBox(context, parentBox, element);
} else if (displayStyle.equals(CSS.INCLUDE)) {
return new IncludeBlockBox(context, parentBox, element);
+ } else if (displayStyle.equals(CSS.LIST_ITEM)) {
+ return new ListItemBox(context, parentBox, node);
} else if (context.getWhitespacePolicy().isBlock(element)) {
return new BlockElementBox(context, parentBox, node);
} else {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DiscBullet.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DiscBullet.java
new file mode 100644
index 00000000..8be0176e
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DiscBullet.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.layout;
+
+import org.eclipse.vex.core.internal.core.Graphics;
+import org.eclipse.vex.core.internal.core.Rectangle;
+
+/**
+ * @author Florian Thienel
+ */
+public class DiscBullet extends Bullet {
+
+ public DiscBullet(final float fontSize) {
+ super(fontSize);
+ }
+
+ public void draw(final Graphics g, final int x, final int y) {
+ g.fillOval(x, y - size - lift, size, size);
+ }
+
+ public Rectangle getBounds() {
+ return new Rectangle(0, -size - lift, size, size);
+ }
+
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ListItemBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ListItemBox.java
new file mode 100644
index 00000000..0698fae8
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ListItemBox.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.layout;
+
+import java.util.List;
+
+import org.eclipse.vex.core.internal.css.CSS;
+import org.eclipse.vex.core.internal.css.Styles;
+import org.eclipse.vex.core.provisional.dom.INode;
+import org.eclipse.vex.core.provisional.dom.IParent;
+
+/**
+ * @author Florian Thienel
+ */
+public class ListItemBox extends BlockElementBox {
+
+ // hspace between list-item bullet and block as fraction of font-size
+ private static final float BULLET_SPACE = 0.5f;
+
+ private BlockBox itemMarker;
+
+ public ListItemBox(final LayoutContext context, final BlockBox parent, final INode node) {
+ super(context, parent, node);
+ }
+
+ @Override
+ public void paint(final LayoutContext context, final int x, final int y) {
+ super.paint(context, x, y);
+
+ if (itemMarker != null) {
+ itemMarker.paint(context, x + itemMarker.getX(), y + itemMarker.getY());
+ }
+ }
+
+ @Override
+ protected int positionChildren(final LayoutContext context) {
+ final int repaintStart = super.positionChildren(context);
+
+ final Styles styles = context.getStyleSheet().getStyles(getNode());
+ if (itemMarker != null) {
+ final int x = -itemMarker.getWidth() - Math.round(BULLET_SPACE * styles.getFontSize());
+ int y = getFirstLineTop(context);
+ final LineBox firstLine = getFirstLine();
+ if (firstLine != null) {
+ y += firstLine.getBaseline() - itemMarker.getFirstLine().getBaseline();
+ }
+
+ itemMarker.setX(x);
+ itemMarker.setY(y);
+ }
+
+ return repaintStart;
+ }
+
+ @Override
+ public List<Box> createChildren(final LayoutContext context) {
+ final Styles styles = context.getStyleSheet().getStyles(getNode());
+ if (!styles.getListStyleType().equals(CSS.NONE)) {
+ itemMarker = createItemMarker(context, getNode());
+ }
+ return super.createChildren(context);
+ }
+
+ private static BlockBox createItemMarker(final LayoutContext context, final INode item) {
+ final Styles styles = context.getStyleSheet().getStyles(item);
+ final String listStyleType = styles.getListStyleType();
+ final float fontSize = styles.getFontSize();
+ if (listStyleType.equals(CSS.NONE)) {
+ return null;
+ }
+
+ final InlineBox markerInline;
+ if (isEnumeratedListStyleType(listStyleType)) {
+ markerInline = createEnumeratedMarker(context, item, listStyleType);
+ } else if (listStyleType.equals(CSS.CIRCLE)) {
+ markerInline = createCircleBullet(item, fontSize);
+ } else if (listStyleType.equals(CSS.SQUARE)) {
+ markerInline = createSquareBullet(item, fontSize);
+ } else {
+ markerInline = createDiscBullet(item, fontSize);
+ }
+
+ return ParagraphBox.create(context, item, new InlineBox[] { markerInline }, Integer.MAX_VALUE);
+ }
+
+ private static InlineBox createEnumeratedMarker(final LayoutContext context, final INode item, final String listStyleType) {
+ final String numberString = numberToString(getItemNumber(item), listStyleType);
+ return new StaticTextBox(context, item, numberString + ".");
+ }
+
+ private static InlineBox createCircleBullet(final INode node, final float fontSize) {
+ return new DrawableBox(new CircleBullet(fontSize), node);
+ }
+
+ private static InlineBox createDiscBullet(final INode node, final float fontSize) {
+ return new DrawableBox(new DiscBullet(fontSize), node);
+ }
+
+ private static InlineBox createSquareBullet(final INode node, final float fontSize) {
+ return new DrawableBox(new SquareBullet(fontSize), node);
+ }
+
+ private static int getItemNumber(final INode item) {
+ final IParent parent = item.getParent();
+
+ if (parent == null) {
+ return 1;
+ }
+
+ int number = 1;
+ for (final INode child : parent.children()) {
+ if (child == item) {
+ return number;
+ }
+ if (child.isKindOf(item)) {
+ number++;
+ }
+ }
+
+ throw new IllegalStateException();
+ }
+
+ private static String numberToString(final int number, final String listStyleType) {
+ if (listStyleType.equals(CSS.DECIMAL_LEADING_ZERO)) {
+ if (number < 10) {
+ return "0" + Integer.toString(number);
+ } else {
+ return Integer.toString(number);
+ }
+ } else if (listStyleType.equals(CSS.LOWER_ALPHA) || listStyleType.equals(CSS.LOWER_LATIN)) {
+ return numberAsAlpha(number);
+ } else if (listStyleType.equals(CSS.LOWER_ROMAN)) {
+ return numberAsRoman(number);
+ } else if (listStyleType.equals(CSS.UPPER_ALPHA) || listStyleType.equals(CSS.UPPER_LATIN)) {
+ return numberAsAlpha(number).toUpperCase();
+ } else if (listStyleType.equals(CSS.UPPER_ROMAN)) {
+ return numberAsRoman(number).toUpperCase();
+ } else {
+ return Integer.toString(number);
+ }
+ }
+
+ private static String numberAsAlpha(final int number) {
+ final String alphabet = "abcdefghijklmnopqrstuvwxyz";
+ return String.valueOf(alphabet.charAt((number - 1) % 26));
+ }
+
+ private static String numberAsRoman(final int number) {
+ final String[] ones = { "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix" };
+ final String[] tens = { "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc" };
+ final String[] hundreds = { "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm" };
+ final StringBuilder romanNumber = new StringBuilder();
+ for (int i = 0; i < number / 1000; i++) {
+ romanNumber.append("m");
+ }
+ romanNumber.append(hundreds[number / 100 % 10]);
+ romanNumber.append(tens[number / 10 % 10]);
+ romanNumber.append(ones[number % 10]);
+ return romanNumber.toString();
+ }
+
+ private static boolean isEnumeratedListStyleType(final String s) {
+ return s.equals(CSS.ARMENIAN) || s.equals(CSS.CJK_IDEOGRAPHIC) || s.equals(CSS.DECIMAL) || s.equals(CSS.DECIMAL_LEADING_ZERO) || s.equals(CSS.GEORGIAN) || s.equals(CSS.HEBREW)
+ || s.equals(CSS.HIRAGANA) || s.equals(CSS.HIRAGANA_IROHA) || s.equals(CSS.KATAKANA) || s.equals(CSS.KATAKANA_IROHA) || s.equals(CSS.LOWER_ALPHA) || s.equals(CSS.LOWER_GREEK)
+ || s.equals(CSS.LOWER_LATIN) || s.equals(CSS.LOWER_ROMAN) || s.equals(CSS.UPPER_ALPHA) || s.equals(CSS.UPPER_LATIN) || s.equals(CSS.UPPER_ROMAN);
+ }
+
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/SquareBullet.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/SquareBullet.java
new file mode 100644
index 00000000..7b4068b0
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/SquareBullet.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.layout;
+
+import org.eclipse.vex.core.internal.core.Graphics;
+import org.eclipse.vex.core.internal.core.Rectangle;
+
+/**
+ * @author Florian Thienel
+ */
+public class SquareBullet extends Bullet {
+
+ public SquareBullet(final float fontSize) {
+ super(fontSize);
+ }
+
+ public void draw(final Graphics g, final int x, final int y) {
+ g.setLineStyle(Graphics.LINE_SOLID);
+ g.setLineWidth(1);
+ g.drawRect(x, y - size - lift, size, size);
+ }
+
+ public Rectangle getBounds() {
+ return new Rectangle(0, -size - lift, size, size);
+ }
+
+}

Back to the top