allow url(...) to be used in the content CSS property

Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/BatikBehaviorTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/BatikBehaviorTest.java
index e3542da..8760d40 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/BatikBehaviorTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/BatikBehaviorTest.java
@@ -50,7 +50,7 @@
 		final Element element = new Element("plan");
 		final IElement before = styleSheet.getPseudoElementBefore(element);
 		final Styles beforeStyles = styleSheet.getStyles(before);
-		assertEquals("test", beforeStyles.getContent(element).get(0));
+		assertEquals("test", beforeStyles.getTextualContent(element).get(0));
 		assertEquals(123.0f, beforeStyles.getFontSize(), 0.0f);
 	}
 
@@ -63,7 +63,7 @@
 		assertEquals(123.0f, styles.getFontSize(), 0.0f);
 		final IElement before = styleSheet.getPseudoElementBefore(element);
 		final Styles beforeStyles = styleSheet.getStyles(before);
-		assertEquals("test", beforeStyles.getContent(element).get(0));
+		assertEquals("test", beforeStyles.getTextualContent(element).get(0));
 		assertEquals(123.0f, beforeStyles.getFontSize(), 0.0f);
 	}
 
@@ -76,9 +76,9 @@
 		final Element nochild = new Element("child");
 		child.setParent(element);
 		final Styles styles = styleSheet.getStyles(child);
-		assertEquals(1, styles.getContent(element).size());
-		assertEquals("child", styles.getContent(element).get(0));
+		assertEquals(1, styles.getTextualContent(element).size());
+		assertEquals("child", styles.getTextualContent(element).get(0));
 		final Styles nochildStyles = styleSheet.getStyles(nochild);
-		assertEquals("nochild", nochildStyles.getContent(element).get(0));
+		assertEquals("nochild", nochildStyles.getTextualContent(element).get(0));
 	}
 }
\ No newline at end of file
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/CssTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/CssTest.java
index 3389232..a770e76 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/CssTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/CssTest.java
@@ -579,9 +579,9 @@
 
 		final Styles styles = ss.getStyles(element);
 
-		assertEquals("Before", styles.getContent(element).get(0));
+		assertEquals("Before", styles.getTextualContent(element).get(0));
 		element.setAttribute("attribute", "After");
-		assertEquals("After", styles.getContent(element).get(0));
+		assertEquals("After", styles.getTextualContent(element).get(0));
 	}
 
 	@Test
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/IPropertyContent.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/IPropertyContent.java
new file mode 100644
index 0000000..2eb6441
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/IPropertyContent.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * 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.css;
+
+public interface IPropertyContent {
+
+	<T> T accept(IPropertyContentVisitor<T> visitor);
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/IPropertyContentVisitor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/IPropertyContentVisitor.java
new file mode 100644
index 0000000..0beaee1
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/IPropertyContentVisitor.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * 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.css;
+
+public interface IPropertyContentVisitor<T> {
+
+	T visit(TextualContent content);
+
+	T visit(URIContent content);
+
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheet.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheet.java
index 5e388d7..40fdbf3 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheet.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheet.java
@@ -263,6 +263,10 @@
 				// content: attr(attributeName)
 				content.add(lexicalUnit);
 				break;
+			case LexicalUnit.SAC_URI:
+				// content: url("<some URI of an image>")
+				content.add(lexicalUnit);
+				break;
 			}
 			lexicalUnit = lexicalUnit.getNextLexicalUnit();
 		}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Styles.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Styles.java
index 4b2af16..4213ed8 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Styles.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Styles.java
@@ -13,6 +13,8 @@
  *******************************************************************************/
 package org.eclipse.vex.core.internal.css;
 
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -22,6 +24,7 @@
 import org.eclipse.vex.core.internal.core.FontSpec;
 import org.eclipse.vex.core.internal.core.Length;
 import org.eclipse.vex.core.provisional.dom.BaseNodeVisitor;
+import org.eclipse.vex.core.provisional.dom.BaseNodeVisitorWithResult;
 import org.eclipse.vex.core.provisional.dom.IElement;
 import org.eclipse.vex.core.provisional.dom.INode;
 import org.eclipse.vex.core.provisional.dom.IProcessingInstruction;
@@ -168,7 +171,7 @@
 	 * @param node
 	 *            The INode to get attr(...) values from
 	 */
-	public List<String> getContent(final INode node) {
+	public List<String> getTextualContent(final INode node) {
 		final List<String> content = new ArrayList<String>();
 		for (LexicalUnit lexicalUnit : contentLexicalUnits) {
 			switch (lexicalUnit.getLexicalUnitType()) {
@@ -202,6 +205,57 @@
 		return content;
 	}
 
+	public List<IPropertyContent> getAllContent(final INode node) {
+		final List<IPropertyContent> allContent = new ArrayList<IPropertyContent>();
+		for (LexicalUnit lexicalUnit : contentLexicalUnits) {
+			final IPropertyContent content = getContent(lexicalUnit, node);
+			if (content != null) {
+				allContent.add(content);
+			}
+			lexicalUnit = lexicalUnit.getNextLexicalUnit();
+		}
+		return allContent;
+	}
+
+	private IPropertyContent getContent(final LexicalUnit lexicalUnit, final INode node) {
+		switch (lexicalUnit.getLexicalUnitType()) {
+		case LexicalUnit.SAC_STRING_VALUE:
+			// content: "A String"
+			return new TextualContent(lexicalUnit.getStringValue());
+		case LexicalUnit.SAC_ATTR:
+			// content: attr(attributeName)
+			final LexicalUnit currentLexicalUnit = lexicalUnit;
+			return node.accept(new BaseNodeVisitorWithResult<IPropertyContent>() {
+				@Override
+				public IPropertyContent visit(final IElement element) {
+					final String attributeValue = element.getAttributeValue(currentLexicalUnit.getStringValue());
+					if (attributeValue != null) {
+						return new TextualContent(attributeValue);
+					}
+					return null;
+				}
+
+				@Override
+				public IPropertyContent visit(final IProcessingInstruction pi) {
+					if (currentLexicalUnit.getStringValue().equalsIgnoreCase(CSS.PSEUDO_TARGET)) {
+						return new TextualContent(pi.getTarget());
+					}
+					return null;
+				}
+			});
+		case LexicalUnit.SAC_URI:
+			// content: url("<some URI of an image>")
+			try {
+				return new URIContent(new URI(lexicalUnit.getStringValue()));
+			} catch (final URISyntaxException e) {
+				e.printStackTrace();
+				return null;
+			}
+		default:
+			return null;
+		}
+	}
+
 	/**
 	 * Returns the value of the <code>display</code> property.
 	 */
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextualContent.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextualContent.java
new file mode 100644
index 0000000..f2764eb
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextualContent.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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.css;
+
+public class TextualContent implements IPropertyContent {
+
+	public final String text;
+
+	public TextualContent(final String text) {
+		this.text = text;
+	}
+
+	@Override
+	public <T> T accept(final IPropertyContentVisitor<T> visitor) {
+		return visitor.visit(this);
+	}
+
+	@Override
+	public String toString() {
+		return text;
+	}
+
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/URIContent.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/URIContent.java
new file mode 100644
index 0000000..4c06f2b
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/URIContent.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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.css;
+
+import java.net.URI;
+
+public class URIContent implements IPropertyContent {
+
+	public final URI uri;
+
+	public URIContent(final URI uri) {
+		this.uri = uri;
+	}
+
+	@Override
+	public <T> T accept(final IPropertyContentVisitor<T> visitor) {
+		return visitor.visit(this);
+	}
+
+	@Override
+	public String toString() {
+		return uri.toString();
+	}
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java
index 49a24db..dbe570d 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java
@@ -77,7 +77,7 @@
 	 *            The node passed to Styles#getContent (to get attr values from)
 	 */
 	public static String getGeneratedContent(final LayoutContext context, final Styles styles, final INode node) {
-		final List<String> content = styles.getContent(node);
+		final List<String> content = styles.getTextualContent(node);
 		final StringBuffer sb = new StringBuffer();
 		for (final String string : content) {
 			sb.append(string); // TODO: change to ContentPart
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/visualization/CssBasedBoxModelBuilder.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/visualization/CssBasedBoxModelBuilder.java
index f23ec37..0a0d1ea 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/visualization/CssBasedBoxModelBuilder.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/visualization/CssBasedBoxModelBuilder.java
@@ -41,6 +41,7 @@
 import org.eclipse.vex.core.internal.boxes.RootBox;
 import org.eclipse.vex.core.internal.boxes.TextContent;
 import org.eclipse.vex.core.internal.css.CSS;
+import org.eclipse.vex.core.internal.css.IPropertyContent;
 import org.eclipse.vex.core.internal.css.StyleSheet;
 import org.eclipse.vex.core.internal.css.Styles;
 import org.eclipse.vex.core.internal.css.Styles.PseudoElement;
@@ -287,7 +288,7 @@
 		}
 
 		final StringBuilder content = new StringBuilder();
-		for (final String part : pseudoElementStyles.getContent(node)) {
+		for (final IPropertyContent part : pseudoElementStyles.getAllContent(node)) {
 			content.append(part);
 		}
 		return frame(paragraph(pseudoElementStyles, staticText(content.toString(), pseudoElementStyles)), pseudoElementStyles);
@@ -440,7 +441,7 @@
 		}
 
 		final StringBuilder content = new StringBuilder();
-		for (final String part : pseudoElementStyles.getContent(node)) {
+		for (final IPropertyContent part : pseudoElementStyles.getAllContent(node)) {
 			content.append(part);
 		}
 		return frame(inlineContainer(staticText(content.toString(), pseudoElementStyles)), pseudoElementStyles);