aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd1
-rw-r--r--src/java/org/apache/fop/area/AreaTreeParser.java2
-rw-r--r--src/java/org/apache/fop/area/Trait.java5
-rw-r--r--src/java/org/apache/fop/fo/Constants.java5
-rw-r--r--src/java/org/apache/fop/fo/FOPropertyMapping.java7
-rw-r--r--src/java/org/apache/fop/fo/FObj.java14
-rw-r--r--src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java2
-rw-r--r--src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java1
-rw-r--r--src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java1
-rw-r--r--src/java/org/apache/fop/layoutmgr/TraitSetter.java11
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java1
-rw-r--r--src/java/org/apache/fop/pdf/AbstractPDFStream.java4
-rw-r--r--src/java/org/apache/fop/pdf/PDFDictionary.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFDocument.java54
-rw-r--r--src/java/org/apache/fop/pdf/PDFFactory.java24
-rw-r--r--src/java/org/apache/fop/pdf/PDFIdentifiedDictionary.java42
-rw-r--r--src/java/org/apache/fop/pdf/PDFLayer.java86
-rw-r--r--src/java/org/apache/fop/pdf/PDFNavigator.java93
-rw-r--r--src/java/org/apache/fop/pdf/PDFNavigatorAction.java28
-rw-r--r--src/java/org/apache/fop/pdf/PDFPaintingState.java34
-rw-r--r--src/java/org/apache/fop/pdf/PDFResources.java34
-rw-r--r--src/java/org/apache/fop/pdf/PDFSetOCGStateAction.java82
-rw-r--r--src/java/org/apache/fop/pdf/PDFTransitionAction.java79
-rw-r--r--src/java/org/apache/fop/render/AbstractRenderer.java58
-rw-r--r--src/java/org/apache/fop/render/afp/AFPPainter.java2
-rw-r--r--src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java4
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFGraphicContext.java23
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFPainter.java8
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFParser.java5
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFRenderer.java32
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFSerializer.java13
-rw-r--r--src/java/org/apache/fop/render/java2d/Java2DPainter.java2
-rw-r--r--src/java/org/apache/fop/render/java2d/Java2DRenderer.java8
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLPainter.java2
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFContentGenerator.java81
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java3
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFPainter.java4
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java261
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFActionElement.java64
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFActionExtension.java32
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFArrayElement.java82
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFArrayExtension.java84
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFCatalogElement.java45
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFCatalogExtension.java29
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFCollectionEntryElement.java146
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFCollectionEntryExtension.java (renamed from src/java/org/apache/fop/render/pdf/extensions/AbstractPDFDictionaryElement.java)36
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFCollectionExtension.java34
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryAttachment.java70
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryElement.java83
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryEntryElement.java109
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryExtension.java97
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryType.java19
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFElementMapping.java90
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java124
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFLayerElement.java45
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFLayerExtension.java29
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFNavigatorElement.java45
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFNavigatorExtension.java30
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFObjectExtension.java (renamed from src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryEntryExtension.java)47
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFObjectType.java (renamed from src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryEntryType.java)26
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFPageElement.java64
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFPageExtension.java73
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFReferenceElement.java58
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFReferenceExtension.java61
-rw-r--r--src/java/org/apache/fop/render/ps/PSPainter.java2
-rw-r--r--src/java/org/apache/fop/render/txt/TXTRenderer.java8
-rw-r--r--src/java/org/apache/fop/render/xml/XMLRenderer.java10
-rw-r--r--src/java/org/apache/fop/util/AbstractPaintingState.java67
-rw-r--r--src/sandbox/org/apache/fop/render/svg/SVGPainter.java10
-rw-r--r--status.xml5
-rw-r--r--test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java2
-rw-r--r--test/java/org/apache/fop/fonts/FontsTestSuite.java2
-rw-r--r--test/java/org/apache/fop/pdf/PDFDestsTestCase.java2
-rw-r--r--test/java/org/apache/fop/pdf/PDFDictionaryTestCase.java2
-rw-r--r--test/java/org/apache/fop/pdf/PDFPageLabelsTestCase.java28
-rw-r--r--test/java/org/apache/fop/pdf/PDFStreamTestCase.java2
-rw-r--r--test/java/org/apache/fop/pdf/xref/CrossReferenceTableTestCase.java2
-rw-r--r--test/java/org/apache/fop/render/intermediate/AbstractIFPainterTestCase.java2
-rw-r--r--test/layoutengine/standard-testcases/pdf-dictionary-extension_2.xml74
-rw-r--r--test/layoutengine/standard-testcases/pdf-dictionary-extension_3.xml122
80 files changed, 2644 insertions, 436 deletions
diff --git a/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd b/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd
index d6f0c694c..2e58a7f45 100644
--- a/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd
+++ b/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd
@@ -38,6 +38,7 @@
<xs:complexContent>
<xs:extension base="mf:contentType">
<xs:attribute name="transform" type="xs:string"/>
+ <xs:attribute name="layer" type="xs:string"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
diff --git a/src/java/org/apache/fop/area/AreaTreeParser.java b/src/java/org/apache/fop/area/AreaTreeParser.java
index c79f975c1..f6de99dd0 100644
--- a/src/java/org/apache/fop/area/AreaTreeParser.java
+++ b/src/java/org/apache/fop/area/AreaTreeParser.java
@@ -1040,7 +1040,7 @@ public class AreaTreeParser {
}
private static final Object[] SUBSET_COMMON = new Object[] {
- Trait.PROD_ID};
+ Trait.PROD_ID, Trait.LAYER};
private static final Object[] SUBSET_LINK = new Object[] {
Trait.INTERNAL_LINK, Trait.EXTERNAL_LINK};
private static final Object[] SUBSET_COLOR = new Object[] {
diff --git a/src/java/org/apache/fop/area/Trait.java b/src/java/org/apache/fop/area/Trait.java
index cd0d4becf..eac9d440d 100644
--- a/src/java/org/apache/fop/area/Trait.java
+++ b/src/java/org/apache/fop/area/Trait.java
@@ -169,9 +169,11 @@ public final class Trait implements Serializable {
/** shift direction trait */
public static final Integer SHIFT_DIRECTION = 42;
+ /** For optional content groups. */
+ public static final Integer LAYER = 43;
/** Maximum value used by trait keys */
- public static final int MAX_TRAIT_KEY = 42;
+ public static final int MAX_TRAIT_KEY = 43;
private static final TraitInfo[] TRAIT_INFO = new TraitInfo[MAX_TRAIT_KEY + 1];
@@ -243,6 +245,7 @@ public final class Trait implements Serializable {
new TraitInfo("block-progression-direction", Direction.class));
put(SHIFT_DIRECTION,
new TraitInfo("shift-direction", Direction.class));
+ put(LAYER, new TraitInfo("layer", String.class));
}
diff --git a/src/java/org/apache/fop/fo/Constants.java b/src/java/org/apache/fop/fo/Constants.java
index 28f02a762..086cbca40 100644
--- a/src/java/org/apache/fop/fo/Constants.java
+++ b/src/java/org/apache/fop/fo/Constants.java
@@ -816,8 +816,11 @@ public interface Constants {
/** Scope for table header */
int PR_X_HEADER_COLUMN = 290;
+ /** For specifying PDF optional content group (layer) binding. */
+ int PR_X_LAYER = 291;
+
/** Number of property constants defined */
- int PROPERTY_COUNT = 290;
+ int PROPERTY_COUNT = 291;
// compound property constants
diff --git a/src/java/org/apache/fop/fo/FOPropertyMapping.java b/src/java/org/apache/fop/fo/FOPropertyMapping.java
index 36e3f21c4..cc4fe9e2c 100644
--- a/src/java/org/apache/fop/fo/FOPropertyMapping.java
+++ b/src/java/org/apache/fop/fo/FOPropertyMapping.java
@@ -2721,6 +2721,13 @@ public final class FOPropertyMapping implements Constants {
m.addEnum("auto", getEnumProperty(EN_AUTO, "AUTO"));
m.setDefault("auto");
addPropertyMaker("z-index", m);
+
+ // fox:layer
+ m = new StringProperty.Maker(PR_X_LAYER);
+ m.setInherited(false);
+ m.setDefault("");
+ addPropertyMaker("fox:layer", m);
+
}
private void createShorthandProperties() {
diff --git a/src/java/org/apache/fop/fo/FObj.java b/src/java/org/apache/fop/fo/FObj.java
index b6f2ec83e..0d1a2a84b 100644
--- a/src/java/org/apache/fop/fo/FObj.java
+++ b/src/java/org/apache/fop/fo/FObj.java
@@ -74,7 +74,8 @@ public abstract class FObj extends FONode implements Constants {
private int bidiLevel = -1;
// The value of properties relevant for all fo objects
- private String id = null;
+ private String id;
+ private String layer;
// End of property values
/**
@@ -173,6 +174,7 @@ public abstract class FObj extends FONode implements Constants {
*/
public void bind(PropertyList pList) throws FOPException {
id = pList.get(PR_ID).getString();
+ layer = pList.get(PR_X_LAYER).getString();
}
/**
@@ -583,6 +585,16 @@ public abstract class FObj extends FONode implements Constants {
return (id != null && id.length() > 0);
}
+ /** @return the "layer" property. */
+ public String getLayer() {
+ return layer;
+ }
+
+ /** @return whether this object has an layer set */
+ public boolean hasLayer() {
+ return (layer != null && layer.length() > 0);
+ }
+
/** {@inheritDoc} */
public String getNamespaceURI() {
return FOElementMapping.URI;
diff --git a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
index 09b47f02a..82db43e59 100644
--- a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
+++ b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
@@ -66,6 +66,8 @@ public class ExtensionElementMapping extends ElementMapping {
PROPERTY_ATTRIBUTES.add("border-before-end-radius");
PROPERTY_ATTRIBUTES.add("border-after-start-radius");
PROPERTY_ATTRIBUTES.add("border-after-end-radius");
+ //Optional content groups (layers)
+ PROPERTY_ATTRIBUTES.add("layer");
}
/**
diff --git a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
index a23cd28f1..eced48939 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
@@ -867,6 +867,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager impl
transferForeignAttributes(viewportBlockArea);
TraitSetter.setProducerID(viewportBlockArea, getBlockContainerFO().getId());
+ TraitSetter.setLayer(viewportBlockArea, getBlockContainerFO().getLayer());
TraitSetter.addBorders(viewportBlockArea,
getBlockContainerFO().getCommonBorderPaddingBackground(),
discardBorderBefore, discardBorderAfter, false, false, this);
diff --git a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
index 55b17e953..b29b95cb1 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
@@ -381,6 +381,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager implements Co
getBlockFO().getCommonBorderPaddingBackground(),
startIndent, endIndent,
this);
+ TraitSetter.setLayer(curBlockArea, getBlockFO().getLayer());
curBlockArea.setLocale(getBlockFO().getCommonHyphenation().getLocale());
curBlockArea.setLocation(FONode.getLocatorString(getBlockFO().getLocator()));
diff --git a/src/java/org/apache/fop/layoutmgr/TraitSetter.java b/src/java/org/apache/fop/layoutmgr/TraitSetter.java
index 739d535ca..af40f0681 100644
--- a/src/java/org/apache/fop/layoutmgr/TraitSetter.java
+++ b/src/java/org/apache/fop/layoutmgr/TraitSetter.java
@@ -617,4 +617,15 @@ public final class TraitSetter {
area.addTrait(Trait.PROD_ID, id);
}
}
+
+ /**
+ * Sets the optional content group layer as a trait on the area.
+ * @param area the area to set the traits on
+ * @param layer the layer ID to set
+ */
+ public static void setLayer(Area area, String layer) {
+ if (layer != null && layer.length() > 0) {
+ area.addTrait(Trait.LAYER, layer);
+ }
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
index dd80db1d1..61dcf45c9 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
@@ -213,6 +213,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
}
if (fobj instanceof Inline || fobj instanceof BasicLink) {
TraitSetter.setProducerID(area, fobj.getId());
+ TraitSetter.setLayer(area, fobj.getLayer());
}
return area;
}
diff --git a/src/java/org/apache/fop/pdf/AbstractPDFStream.java b/src/java/org/apache/fop/pdf/AbstractPDFStream.java
index 41eed4885..13bd1bda1 100644
--- a/src/java/org/apache/fop/pdf/AbstractPDFStream.java
+++ b/src/java/org/apache/fop/pdf/AbstractPDFStream.java
@@ -143,7 +143,7 @@ public abstract class AbstractPDFStream extends PDFObject {
*/
protected int outputStreamData(StreamCache encodedStream, OutputStream out) throws IOException {
int length = 0;
- byte[] p = encode("stream\n");
+ byte[] p = encode("\nstream\n");
out.write(p);
length += p.length;
@@ -186,7 +186,7 @@ public abstract class AbstractPDFStream extends PDFObject {
throws IOException {
int bytesWritten = 0;
//Stream header
- byte[] buf = encode("stream\n");
+ byte[] buf = encode("\nstream\n");
out.write(buf);
bytesWritten += buf.length;
diff --git a/src/java/org/apache/fop/pdf/PDFDictionary.java b/src/java/org/apache/fop/pdf/PDFDictionary.java
index 6bacd31a3..ae0b950fd 100644
--- a/src/java/org/apache/fop/pdf/PDFDictionary.java
+++ b/src/java/org/apache/fop/pdf/PDFDictionary.java
@@ -131,7 +131,7 @@ public class PDFDictionary extends PDFObject {
} else {
textBuffer.append('\n');
}
- textBuffer.append(">>\n");
+ textBuffer.append(">>");
}
}
diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java
index ff9f61201..bcd54fcb9 100644
--- a/src/java/org/apache/fop/pdf/PDFDocument.java
+++ b/src/java/org/apache/fop/pdf/PDFDocument.java
@@ -155,6 +155,12 @@ public class PDFDocument {
private List<PDFLaunch> launches = new ArrayList<PDFLaunch>();
+ private List<PDFLayer> layers;
+
+ private List<PDFNavigator> navigators;
+
+ private List<PDFNavigatorAction> navigatorActions;
+
private PDFFactory factory;
private FileIDGenerator fileIDGenerator;
@@ -477,6 +483,24 @@ public class PDFDocument {
if (obj instanceof PDFGoToRemote) {
this.gotoremotes.add((PDFGoToRemote) obj);
}
+ if (obj instanceof PDFLayer) {
+ if (this.layers == null) {
+ this.layers = new ArrayList<PDFLayer>();
+ }
+ this.layers.add((PDFLayer) obj);
+ }
+ if (obj instanceof PDFNavigator) {
+ if (this.navigators == null) {
+ this.navigators = new ArrayList<PDFNavigator>();
+ }
+ this.navigators.add((PDFNavigator) obj);
+ }
+ if (obj instanceof PDFNavigatorAction) {
+ if (this.navigatorActions == null) {
+ this.navigatorActions = new ArrayList<PDFNavigatorAction>();
+ }
+ this.navigatorActions.add((PDFNavigatorAction) obj);
+ }
}
/**
@@ -890,6 +914,34 @@ public class PDFDocument {
}
/**
+ *
+ */
+ public PDFReference resolveExtensionReference(String id) {
+ if (layers != null) {
+ for (PDFLayer layer : layers) {
+ if (layer.hasId(id)) {
+ return layer.makeReference();
+ }
+ }
+ }
+ if (navigators != null) {
+ for (PDFNavigator navigator : navigators) {
+ if (navigator.hasId(id)) {
+ return navigator.makeReference();
+ }
+ }
+ }
+ if (navigatorActions != null) {
+ for (PDFNavigatorAction action : navigatorActions) {
+ if (action.hasId(id)) {
+ return action.makeReference();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Writes out the entire document
*
* @param stream the OutputStream to output the document to
@@ -1009,7 +1061,7 @@ public class PDFDocument {
streamIndirectObjects(trailerObjects, stream);
TrailerDictionary trailerDictionary = createTrailerDictionary();
long startxref = trailerOutputHelper.outputCrossReferenceObject(stream, trailerDictionary);
- String trailer = "startxref\n" + startxref + "\n%%EOF\n";
+ String trailer = "\nstartxref\n" + startxref + "\n%%EOF\n";
stream.write(encode(trailer));
}
diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java
index 631499af1..5af33866e 100644
--- a/src/java/org/apache/fop/pdf/PDFFactory.java
+++ b/src/java/org/apache/fop/pdf/PDFFactory.java
@@ -1821,4 +1821,28 @@ public class PDFFactory {
return obj;
}
+ public PDFLayer makeLayer(String id) {
+ PDFLayer layer = new PDFLayer(id);
+ getDocument().registerObject(layer);
+ return layer;
+ }
+
+ public PDFSetOCGStateAction makeSetOCGStateAction(String id) {
+ PDFSetOCGStateAction action = new PDFSetOCGStateAction(id);
+ getDocument().registerObject(action);
+ return action;
+ }
+
+ public PDFTransitionAction makeTransitionAction(String id) {
+ PDFTransitionAction action = new PDFTransitionAction(id);
+ getDocument().registerObject(action);
+ return action;
+ }
+
+ public PDFNavigator makeNavigator(String id) {
+ PDFNavigator navigator = new PDFNavigator(id);
+ getDocument().registerObject(navigator);
+ return navigator;
+ }
+
}
diff --git a/src/java/org/apache/fop/pdf/PDFIdentifiedDictionary.java b/src/java/org/apache/fop/pdf/PDFIdentifiedDictionary.java
new file mode 100644
index 000000000..c2d033aec
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFIdentifiedDictionary.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.pdf;
+
+/**
+ * Identified Dictionary.
+ */
+public class PDFIdentifiedDictionary extends PDFDictionary {
+
+ private final String id;
+
+ public PDFIdentifiedDictionary(String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return this.id;
+ }
+
+ public boolean hasId(String id) {
+ return (this.id != null) && (id != null) && this.id.equals(id);
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/pdf/PDFLayer.java b/src/java/org/apache/fop/pdf/PDFLayer.java
new file mode 100644
index 000000000..f8f434e87
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFLayer.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.pdf;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Optional Content Group Dictionary, which we will call a 'layer'.
+ */
+public class PDFLayer extends PDFIdentifiedDictionary {
+
+ public abstract static class Resolver {
+ private boolean resolved;
+ private PDFLayer layer;
+ private Object extension;
+ public Resolver(PDFLayer layer, Object extension) {
+ this.layer = layer;
+ this.extension = extension;
+ }
+ public PDFLayer getLayer() {
+ return layer;
+ }
+ public Object getExtension() {
+ return extension;
+ }
+ public void resolve() {
+ if (!resolved) {
+ performResolution();
+ resolved = true;
+ }
+ }
+ protected void performResolution() {
+ }
+ }
+
+ private Resolver resolver;
+
+ public PDFLayer(String id) {
+ super(id);
+ put("Type", new PDFName("OCG"));
+ }
+
+ @Override
+ public int output(OutputStream stream) throws IOException {
+ if (resolver != null) {
+ resolver.resolve();
+ }
+ return super.output(stream);
+ }
+
+ public void setResolver(Resolver resolver) {
+ this.resolver = resolver;
+ }
+
+ public void populate(Object name, Object intent, Object usage) {
+ if (name != null) {
+ put("Name", name);
+ }
+ if (intent != null) {
+ put("Intent", intent);
+ }
+ if (usage != null) {
+ put("Usage", usage);
+ }
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/pdf/PDFNavigator.java b/src/java/org/apache/fop/pdf/PDFNavigator.java
new file mode 100644
index 000000000..fdb97469b
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFNavigator.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.pdf;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Navigation Node Dictionary, which we call a 'navigator'.
+ * This class is used to for sub-page navigation.
+ */
+public class PDFNavigator extends PDFIdentifiedDictionary {
+
+ public abstract static class Resolver {
+ private boolean resolved;
+ private PDFNavigator navigator;
+ private Object extension;
+ public Resolver(PDFNavigator navigator, Object extension) {
+ this.navigator = navigator;
+ this.extension = extension;
+ }
+ public PDFNavigator getNavigator() {
+ return navigator;
+ }
+ public Object getExtension() {
+ return extension;
+ }
+ public void resolve() {
+ if (!resolved) {
+ performResolution();
+ resolved = true;
+ }
+ }
+ protected void performResolution() {
+ }
+ }
+
+ private Resolver resolver;
+
+ public PDFNavigator(String id) {
+ super(id);
+ put("Type", new PDFName("NavNode"));
+ }
+
+ @Override
+ public int output(OutputStream stream) throws IOException {
+ if (resolver != null) {
+ resolver.resolve();
+ }
+ return super.output(stream);
+ }
+
+ public void setResolver(Resolver resolver) {
+ this.resolver = resolver;
+ }
+
+ public void populate(Object nextAction, Object nextNode, Object prevAction, Object prevNode, Object duration) {
+ if (nextAction != null) {
+ put("NA", nextAction);
+ }
+ if (nextNode != null) {
+ put("Next", nextNode);
+ }
+ if (prevAction != null) {
+ put("PA", prevAction);
+ }
+ if (prevNode != null) {
+ put("Prev", prevNode);
+ }
+ if (duration != null) {
+ put("Dur", duration);
+ }
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/pdf/PDFNavigatorAction.java b/src/java/org/apache/fop/pdf/PDFNavigatorAction.java
new file mode 100644
index 000000000..ba32269b5
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFNavigatorAction.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.pdf;
+
+public abstract class PDFNavigatorAction extends PDFIdentifiedDictionary {
+
+ protected PDFNavigatorAction(String id) {
+ super(id);
+ }
+
+}
diff --git a/src/java/org/apache/fop/pdf/PDFPaintingState.java b/src/java/org/apache/fop/pdf/PDFPaintingState.java
index 29d022f61..f6528a30c 100644
--- a/src/java/org/apache/fop/pdf/PDFPaintingState.java
+++ b/src/java/org/apache/fop/pdf/PDFPaintingState.java
@@ -44,8 +44,6 @@ import org.apache.fop.util.AbstractPaintingState;
* previous state then the necessary values can be overridden.
* The current transform behaves differently to other values as the
* matrix is combined with the current resolved value.
- * It is impossible to optimise the result without analysing the all
- * the possible combinations after completing.
*/
public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState {
@@ -187,6 +185,36 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState
return newState;
}
+ public void setLayer(String layer) {
+ getPDFData().setLayer(layer);
+ }
+
+ public String getLayer() {
+ return getPDFData().getLayer();
+ }
+
+ public boolean getLayerChanged() {
+ String layerCurrent = getLayer();
+ if (layerCurrent == null) {
+ return false;
+ } else if (getStateStack().isEmpty()) {
+ return true;
+ } else {
+ for (int i = getStackLevel(); i > 0; --i) {
+ String layerPrev = ((PDFData) getStateStack().get(i - 1)).getLayer();
+ if (layerPrev == null) {
+ continue;
+ } else {
+ // Both current and prior are set, so, if same, then we know layer
+ // didn't change (and can stop search), otherwise it did change.
+ return !layerCurrent.equals(layerPrev);
+ }
+ }
+ // Current layer set, but no prior saved layer set, so must have changed.
+ return true;
+ }
+ }
+
/** {@inheritDoc} */
@Override
protected AbstractData instantiateData() {
@@ -209,7 +237,7 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState
AbstractData data = getData();
AbstractData copy = (AbstractData)data.clone();
data.clearTransform();
- getStateStack().add(copy);
+ getStateStack().push(copy);
}
private PDFData getPDFData() {
diff --git a/src/java/org/apache/fop/pdf/PDFResources.java b/src/java/org/apache/fop/pdf/PDFResources.java
index cded7c00a..6d09d5738 100644
--- a/src/java/org/apache/fop/pdf/PDFResources.java
+++ b/src/java/org/apache/fop/pdf/PDFResources.java
@@ -37,8 +37,8 @@ import org.apache.fop.fonts.base14.ZapfDingbats;
/**
* Class representing a /Resources object.
*
- * /Resources object contain a list of references to the fonts for the
- * document
+ * /Resources object contain a list of references to the fonts, patterns,
+ * shadings, etc., for the document.
*/
public class PDFResources extends PDFDictionary {
@@ -73,6 +73,9 @@ public class PDFResources extends PDFDictionary {
/** Map of ICC color spaces (key: ICC profile description) */
protected Map<String, PDFICCBasedColorSpace> iccColorSpaces = new LinkedHashMap<String, PDFICCBasedColorSpace>();
+ /** Named properties */
+ protected Map<String, PDFReference> properties = new LinkedHashMap<String, PDFReference>();
+
/**
* create a /Resources object.
*
@@ -191,6 +194,25 @@ public class PDFResources extends PDFDictionary {
return cs;
}
+ /**
+ * Add a named property.
+ *
+ * @param name name of property
+ * @param property reference to property value
+ */
+ public void addProperty(String name, PDFReference property) {
+ this.properties.put(name, property);
+ }
+
+ /**
+ * Get a named property.
+ *
+ * @param name name of property
+ */
+ public PDFReference getProperty(String name) {
+ return this.properties.get(name);
+ }
+
@Override
public int output(OutputStream stream) throws IOException {
populateDictionary();
@@ -253,6 +275,14 @@ public class PDFResources extends PDFDictionary {
}
put("ColorSpace", dict);
}
+
+ if (!properties.isEmpty()) {
+ PDFDictionary dict = new PDFDictionary(this);
+ for (String name : properties.keySet()) {
+ dict.put(name, properties.get(name));
+ }
+ put("Properties", dict);
+ }
}
}
diff --git a/src/java/org/apache/fop/pdf/PDFSetOCGStateAction.java b/src/java/org/apache/fop/pdf/PDFSetOCGStateAction.java
new file mode 100644
index 000000000..a47c5cd59
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFSetOCGStateAction.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.pdf;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class PDFSetOCGStateAction extends PDFNavigatorAction {
+
+ public abstract static class Resolver {
+ private boolean resolved;
+ private PDFSetOCGStateAction action;
+ private Object extension;
+ public Resolver(PDFSetOCGStateAction action, Object extension) {
+ this.action = action;
+ this.extension = extension;
+ }
+ public PDFSetOCGStateAction getAction() {
+ return action;
+ }
+ public Object getExtension() {
+ return extension;
+ }
+ public void resolve() {
+ if (!resolved) {
+ performResolution();
+ resolved = true;
+ }
+ }
+ protected void performResolution() {
+ }
+ }
+
+ private Resolver resolver;
+
+ public PDFSetOCGStateAction(String id) {
+ super(id);
+ put("Type", new PDFName("Action"));
+ put("S", new PDFName("SetOCGState"));
+ }
+
+ @Override
+ public int output(OutputStream stream) throws IOException {
+ if (resolver != null) {
+ resolver.resolve();
+ }
+ return super.output(stream);
+ }
+
+ public void setResolver(Resolver resolver) {
+ this.resolver = resolver;
+ }
+
+ public void populate(Object state, Object preserveRB, Object nextAction) {
+ if (state != null) {
+ put("State", state);
+ }
+ if (preserveRB != null) {
+ put("PreserveRB", preserveRB);
+ }
+ if (nextAction != null) {
+ put("Next", nextAction);
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/pdf/PDFTransitionAction.java b/src/java/org/apache/fop/pdf/PDFTransitionAction.java
new file mode 100644
index 000000000..01f8fcf21
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFTransitionAction.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.pdf;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class PDFTransitionAction extends PDFNavigatorAction {
+
+ public abstract static class Resolver {
+ private boolean resolved;
+ private PDFTransitionAction action;
+ private Object extension;
+ public Resolver(PDFTransitionAction action, Object extension) {
+ this.action = action;
+ this.extension = extension;
+ }
+ public PDFTransitionAction getAction() {
+ return action;
+ }
+ public Object getExtension() {
+ return extension;
+ }
+ public void resolve() {
+ if (!resolved) {
+ performResolution();
+ resolved = true;
+ }
+ }
+ protected void performResolution() {
+ }
+ }
+
+ private Resolver resolver;
+
+ public PDFTransitionAction(String id) {
+ super(id);
+ put("Type", new PDFName("Action"));
+ put("S", new PDFName("Trans"));
+ }
+
+ @Override
+ public int output(OutputStream stream) throws IOException {
+ if (resolver != null) {
+ resolver.resolve();
+ }
+ return super.output(stream);
+ }
+
+ public void setResolver(Resolver resolver) {
+ this.resolver = resolver;
+ }
+
+ public void populate(Object transition, Object nextAction) {
+ if (transition != null) {
+ put("Trans", transition);
+ }
+ if (nextAction != null) {
+ put("Next", nextAction);
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/render/AbstractRenderer.java b/src/java/org/apache/fop/render/AbstractRenderer.java
index e274e5c4b..9a94e0cc6 100644
--- a/src/java/org/apache/fop/render/AbstractRenderer.java
+++ b/src/java/org/apache/fop/render/AbstractRenderer.java
@@ -28,6 +28,7 @@ import java.io.OutputStream;
import java.util.List;
import java.util.Locale;
import java.util.Set;
+import java.util.Stack;
import org.w3c.dom.Document;
@@ -112,8 +113,12 @@ public abstract class AbstractRenderer
/** the currently active PageViewport */
protected PageViewport currentPageViewport;
+ /* warned XML handlers */
private Set warnedXMLHandlers;
+ /* layers stack */
+ private Stack<String> layers;
+
/** {@inheritDoc} */
public abstract void setupFontInfo(FontInfo fontInfo) throws FOPException;
@@ -471,6 +476,10 @@ public abstract class AbstractRenderer
* @param children The children to render within the block viewport
*/
protected void renderBlockViewport(BlockViewport bv, List children) {
+ boolean inNewLayer = false;
+ if (maybeStartLayer(bv)) {
+ inNewLayer = true;
+ }
// clip and position viewport if necessary
if (bv.getPositioning() == Block.ABSOLUTE) {
// save positions
@@ -506,6 +515,7 @@ public abstract class AbstractRenderer
currentIPPosition = saveIP;
currentBPPosition = saveBP + bv.getAllocBPD();
}
+ maybeEndLayer(bv, inNewLayer);
}
/**
@@ -573,6 +583,10 @@ public abstract class AbstractRenderer
protected void renderBlock(Block block) {
assert block != null;
List children = block.getChildAreas();
+ boolean inNewLayer = false;
+ if (maybeStartLayer(block)) {
+ inNewLayer = true;
+ }
if (block instanceof BlockViewport) {
if (children != null) {
renderBlockViewport((BlockViewport) block, children);
@@ -607,6 +621,45 @@ public abstract class AbstractRenderer
currentBPPosition = saveBP + block.getAllocBPD();
}
}
+ maybeEndLayer(block, inNewLayer);
+ }
+
+ /**
+ * Establish new optional content group layer.
+ * @param layer name of layer
+ */
+ protected abstract void startLayer(String layer);
+
+ /**
+ * Finish current optional content group layer.
+ */
+ protected abstract void endLayer();
+
+ protected boolean maybeStartLayer(Area area) {
+ String layer = (String) area.getTrait(Trait.LAYER);
+ if (layer != null) {
+ if (layers == null) {
+ layers = new Stack<String>();
+ }
+ if (layers.empty() || !layers.peek().equals(layer)) {
+ layers.push(layer);
+ startLayer(layer);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected void maybeEndLayer(Area area, boolean inNewLayer) {
+ if (inNewLayer) {
+ assert layers != null;
+ assert !layers.empty();
+ String layer = (String) area.getTrait(Trait.LAYER);
+ assert layer != null;
+ assert layers.peek().equals(layer);
+ endLayer();
+ layers.pop();
+ }
}
/**
@@ -746,6 +799,10 @@ public abstract class AbstractRenderer
* @param ip the inline parent to render
*/
protected void renderInlineParent(InlineParent ip) {
+ boolean inNewLayer = false;
+ if (maybeStartLayer(ip)) {
+ inNewLayer = true;
+ }
int level = ip.getBidiLevel();
List children = ip.getChildAreas();
renderInlineAreaBackAndBorders(ip);
@@ -782,6 +839,7 @@ public abstract class AbstractRenderer
}
currentIPPosition = saveIP + ip.getAllocIPD();
currentBPPosition = saveBP;
+ maybeEndLayer(ip, inNewLayer);
}
/**
diff --git a/src/java/org/apache/fop/render/afp/AFPPainter.java b/src/java/org/apache/fop/render/afp/AFPPainter.java
index 12713bb24..aaa702afa 100644
--- a/src/java/org/apache/fop/render/afp/AFPPainter.java
+++ b/src/java/org/apache/fop/render/afp/AFPPainter.java
@@ -164,7 +164,7 @@ public class AFPPainter extends AbstractIFPainter<AFPDocumentHandler> {
}
/** {@inheritDoc} */
- public void startGroup(AffineTransform transform) throws IFException {
+ public void startGroup(AffineTransform transform, String layer) throws IFException {
try {
saveGraphicsState();
concatenateTransformationMatrix(transform);
diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
index 2dd046fa9..f69fe2091 100644
--- a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
+++ b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
@@ -126,8 +126,8 @@ public abstract class AbstractIFPainter<T extends IFDocumentHandler> implements
}
/** {@inheritDoc} */
- public void startGroup(AffineTransform[] transforms) throws IFException {
- startGroup(combine(transforms));
+ public void startGroup(AffineTransform[] transforms, String layer) throws IFException {
+ startGroup(combine(transforms), layer);
}
/**
diff --git a/src/java/org/apache/fop/render/intermediate/IFGraphicContext.java b/src/java/org/apache/fop/render/intermediate/IFGraphicContext.java
index 868615360..c1742be1f 100644
--- a/src/java/org/apache/fop/render/intermediate/IFGraphicContext.java
+++ b/src/java/org/apache/fop/render/intermediate/IFGraphicContext.java
@@ -89,6 +89,7 @@ public class IFGraphicContext extends GraphicContext {
public static class Group {
private AffineTransform[] transforms;
+ private String layer;
/**
* Construct a Group.
@@ -106,6 +107,16 @@ public class IFGraphicContext extends GraphicContext {
this(new AffineTransform[] {transform});
}
+ /**
+ * Construct a layer Group, i.e., a Group with no transforms
+ * but with a optional content group layer label.
+ * @param layer a layer label
+ */
+ public Group(String layer) {
+ this();
+ this.layer = layer;
+ }
+
/** Default constructor. */
public Group() {
this(EMPTY_TRANSFORM_ARRAY);
@@ -116,12 +127,17 @@ public class IFGraphicContext extends GraphicContext {
return this.transforms;
}
+ /** @return layer */
+ public String getLayer() {
+ return this.layer;
+ }
+
/**
* @param painter a painter
* @throws IFException in not caught
*/
public void start(IFPainter painter) throws IFException {
- painter.startGroup(transforms);
+ painter.startGroup(transforms, layer);
}
/**
@@ -136,6 +152,11 @@ public class IFGraphicContext extends GraphicContext {
public String toString() {
StringBuffer sb = new StringBuffer("group: ");
IFUtil.toString(getTransforms(), sb);
+ if ((layer != null) && (layer.length() > 0)) {
+ sb.append(" layer(");
+ sb.append(layer);
+ sb.append(')');
+ }
return sb.toString();
}
diff --git a/src/java/org/apache/fop/render/intermediate/IFPainter.java b/src/java/org/apache/fop/render/intermediate/IFPainter.java
index 599292287..d43b5cb85 100644
--- a/src/java/org/apache/fop/render/intermediate/IFPainter.java
+++ b/src/java/org/apache/fop/render/intermediate/IFPainter.java
@@ -113,19 +113,21 @@ public interface IFPainter {
/**
* Starts a new group of graphical elements. Corresponds to SVG's g element.
* @param transforms a series of transformation matrices establishing the new coordinate system
+ * @param layer an optional layer label (or null if none)
* @throws IFException if an error occurs while handling this element
*/
- void startGroup(AffineTransform[] transforms) throws IFException;
+ void startGroup(AffineTransform[] transforms, String layer) throws IFException;
/**
* Starts a new group of graphical elements. Corresponds to SVG's g element.
* @param transform the transformation matrix establishing the new coordinate system
+ * @param layer an optional layer label (or null if none)
* @throws IFException if an error occurs while handling this element
*/
- void startGroup(AffineTransform transform) throws IFException;
+ void startGroup(AffineTransform transform, String layer) throws IFException;
/**
- * Ends the current group and restores the previous coordinate system.
+ * Ends the current group and restores the previous coordinate system (and layer).
* @throws IFException if an error occurs while handling this element
*/
void endGroup() throws IFException;
diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java
index 1af1d4a06..519726291 100644
--- a/src/java/org/apache/fop/render/intermediate/IFParser.java
+++ b/src/java/org/apache/fop/render/intermediate/IFParser.java
@@ -592,7 +592,8 @@ public class IFParser implements IFConstants {
String transform = attributes.getValue("transform");
AffineTransform[] transforms
= AffineTransformArrayParser.createAffineTransform(transform);
- painter.startGroup(transforms);
+ String layer = attributes.getValue("layer");
+ painter.startGroup(transforms, layer);
}
public void endElement() throws IFException {
@@ -800,8 +801,8 @@ public class IFParser implements IFConstants {
}
painter.drawImage(uri, new Rectangle(x, y, width, height));
}
- resetForeignAttributes();
resetStructureTreeElement();
+ resetForeignAttributes();
inForeignObject = false;
}
diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java
index 30ceda108..e40a8f6b3 100644
--- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java
+++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java
@@ -742,6 +742,12 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
protected void renderBlockViewport(BlockViewport bv, List children) {
//Essentially the same code as in the super class but optimized for the IF
+ // Handle new layer.
+ boolean inNewLayer = false;
+ if (maybeStartLayer(bv)) {
+ inNewLayer = true;
+ }
+
//This is the content-rect
Dimension dim = new Dimension(bv.getIPD(), bv.getBPD());
viewportDimensionStack.push(dim);
@@ -842,6 +848,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
currentBPPosition += bv.getAllocBPD();
}
viewportDimensionStack.pop();
+ maybeEndLayer(bv, inNewLayer);
}
/** {@inheritDoc} */
@@ -849,7 +856,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
StructureTreeElement structElem
= (StructureTreeElement) viewport.getTrait(Trait.STRUCTURE_TREE_ELEMENT);
establishStructureTreeElement(structElem);
- pushdID(viewport);
+ pushID(viewport);
Dimension dim = new Dimension(viewport.getIPD(), viewport.getBPD());
viewportDimensionStack.push(dim);
super.renderInlineViewport(viewport);
@@ -896,9 +903,26 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
}
/** {@inheritDoc} */
+ protected void startLayer(String layer) {
+ if (log.isTraceEnabled()) {
+ log.trace("startLayer() layer=" + layer);
+ }
+ saveGraphicsState();
+ pushGroup(new IFGraphicContext.Group(layer));
+ }
+
+ /** {@inheritDoc} */
+ protected void endLayer() {
+ if (log.isTraceEnabled()) {
+ log.trace("endLayer()");
+ }
+ restoreGraphicsState();
+ }
+
+ /** {@inheritDoc} */
protected void renderInlineArea(InlineArea inlineArea) {
saveInlinePosIfTargetable(inlineArea);
- pushdID(inlineArea);
+ pushID(inlineArea);
super.renderInlineArea(inlineArea);
popID(inlineArea);
}
@@ -965,7 +989,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
log.trace("renderBlock() " + block);
}
saveBlockPosIfTargetable(block);
- pushdID(block);
+ pushID(block);
IFContext context = documentHandler.getContext();
Locale oldLocale = context.getLanguage();
context.setLanguage(block.getLocale());
@@ -977,7 +1001,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
popID(block);
}
- private void pushdID(Area area) {
+ private void pushID(Area area) {
String prodID = (String) area.getTrait(Trait.PROD_ID);
if (prodID != null) {
ids.push(prodID);
diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java
index 1ffd42863..395e79719 100644
--- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java
+++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java
@@ -428,21 +428,24 @@ implements IFConstants, IFPainter, IFDocumentNavigationHandler {
}
/** {@inheritDoc} */
- public void startGroup(AffineTransform[] transforms) throws IFException {
- startGroup(IFUtil.toString(transforms));
+ public void startGroup(AffineTransform[] transforms, String layer) throws IFException {
+ startGroup(IFUtil.toString(transforms), layer);
}
/** {@inheritDoc} */
- public void startGroup(AffineTransform transform) throws IFException {
- startGroup(IFUtil.toString(transform));
+ public void startGroup(AffineTransform transform, String layer) throws IFException {
+ startGroup(IFUtil.toString(transform), layer);
}
- private void startGroup(String transform) throws IFException {
+ private void startGroup(String transform, String layer) throws IFException {
try {
AttributesImpl atts = new AttributesImpl();
if (transform != null && transform.length() > 0) {
addAttribute(atts, "transform", transform);
}
+ if (layer != null && layer.length() > 0) {
+ addAttribute(atts, "layer", layer);
+ }
handler.startElement(EL_GROUP, atts);
} catch (SAXException e) {
throw new IFException("SAX error in startGroup()", e);
diff --git a/src/java/org/apache/fop/render/java2d/Java2DPainter.java b/src/java/org/apache/fop/render/java2d/Java2DPainter.java
index 07440ff0b..328d1a4f8 100644
--- a/src/java/org/apache/fop/render/java2d/Java2DPainter.java
+++ b/src/java/org/apache/fop/render/java2d/Java2DPainter.java
@@ -143,7 +143,7 @@ public class Java2DPainter extends AbstractIFPainter<Java2DDocumentHandler> {
}
/** {@inheritDoc} */
- public void startGroup(AffineTransform transform) throws IFException {
+ public void startGroup(AffineTransform transform, String layer) throws IFException {
saveGraphicsState();
try {
concatenateTransformationMatrix(transform);
diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java
index a98aff353..d343c55d8 100644
--- a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java
+++ b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java
@@ -476,6 +476,14 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem
}
/** {@inheritDoc} */
+ protected void startLayer(String layer) {
+ }
+
+ /** {@inheritDoc} */
+ protected void endLayer() {
+ }
+
+ /** {@inheritDoc} */
protected List breakOutOfStateStack() {
log.debug("Block.FIXED --> break out");
List breakOutList;
diff --git a/src/java/org/apache/fop/render/pcl/PCLPainter.java b/src/java/org/apache/fop/render/pcl/PCLPainter.java
index c51ee834f..f934eed8c 100644
--- a/src/java/org/apache/fop/render/pcl/PCLPainter.java
+++ b/src/java/org/apache/fop/render/pcl/PCLPainter.java
@@ -126,7 +126,7 @@ public class PCLPainter extends AbstractIFPainter<PCLDocumentHandler> implements
}
/** {@inheritDoc} */
- public void startGroup(AffineTransform transform) throws IFException {
+ public void startGroup(AffineTransform transform, String layer) throws IFException {
saveGraphicsState();
try {
concatenateTransformationMatrix(transform);
diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
index dde6b0ef3..ac7b1d905 100644
--- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
+++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
@@ -30,6 +30,7 @@ import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFFilterList;
import org.apache.fop.pdf.PDFNumber;
import org.apache.fop.pdf.PDFPaintingState;
+import org.apache.fop.pdf.PDFReference;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFStream;
import org.apache.fop.pdf.PDFText;
@@ -55,7 +56,7 @@ public class PDFContentGenerator {
private PDFColorHandler colorHandler;
/** drawing state */
- protected PDFPaintingState currentState = null;
+ protected PDFPaintingState currentState;
/** Text generation utility holding the current font status */
protected PDFTextUtil textutil;
@@ -156,15 +157,23 @@ public class PDFContentGenerator {
*/
protected void comment(String text) {
if (WRITE_COMMENTS) {
- currentStream.add("% " + text + "\n");
+ getStream().add("% " + text + "\n");
}
}
/** Save graphics state. */
protected void saveGraphicsState() {
endTextObject();
- currentState.save();
- currentStream.add("q\n");
+ getState().save();
+ getStream().add("q\n");
+ }
+
+ /** Save graphics state with optional layer. */
+ protected void saveGraphicsState(String layer) {
+ endTextObject();
+ getState().save();
+ maybeBeginLayer(layer);
+ getStream().add("q\n");
}
/**
@@ -174,9 +183,9 @@ public class PDFContentGenerator {
*/
protected void saveGraphicsState(String structElemType, int sequenceNum) {
endTextObject();
- currentState.save();
+ getState().save();
beginMarkedContentSequence(structElemType, sequenceNum);
- currentStream.add("q\n");
+ getStream().add("q\n");
}
/**
@@ -208,18 +217,18 @@ public class PDFContentGenerator {
if (structElemType != null) {
String actualTextProperty = actualText == null ? ""
: " /ActualText " + PDFText.escapeText(actualText);
- currentStream.add(structElemType + " <</MCID " + String.valueOf(mcid)
+ getStream().add(structElemType + " <</MCID " + String.valueOf(mcid)
+ actualTextProperty + ">>\n"
+ "BDC\n");
} else {
- currentStream.add("/Artifact\nBMC\n");
+ getStream().add("/Artifact\nBMC\n");
this.inArtifactMode = true;
}
this.inMarkedContentSequence = true;
}
void endMarkedContentSequence() {
- currentStream.add("EMC\n");
+ getStream().add("EMC\n");
this.inMarkedContentSequence = false;
this.inArtifactMode = false;
}
@@ -231,9 +240,10 @@ public class PDFContentGenerator {
*/
protected void restoreGraphicsState(boolean popState) {
endTextObject();
- currentStream.add("Q\n");
+ getStream().add("Q\n");
+ maybeEndLayer();
if (popState) {
- currentState.restore();
+ getState().restore();
}
}
@@ -251,11 +261,42 @@ public class PDFContentGenerator {
*/
protected void restoreGraphicsStateAccess() {
endTextObject();
- currentStream.add("Q\n");
+ getStream().add("Q\n");
if (this.inMarkedContentSequence) {
endMarkedContentSequence();
}
- currentState.restore();
+ getState().restore();
+ }
+
+ private void maybeBeginLayer(String layer) {
+ if ((layer != null) && (layer.length() > 0)) {
+ getState().setLayer(layer);
+ beginOptionalContent(layer);
+ }
+ }
+
+ private void maybeEndLayer() {
+ if (getState().getLayerChanged()) {
+ endOptionalContent();
+ }
+ }
+
+ private int ocNameIndex = 0;
+
+ private void beginOptionalContent(String layerId) {
+ String name;
+ PDFReference layer = document.resolveExtensionReference(layerId);
+ if (layer != null) {
+ name = "oc" + ++ocNameIndex;
+ document.getResources().addProperty(name, layer);
+ } else {
+ name = "unknown";
+ }
+ getStream().add("/OC /" + name + " BDC\n");
+ }
+
+ private void endOptionalContent() {
+ getStream().add("EMC\n");
}
/** Indicates the beginning of a text object. */
@@ -310,8 +351,8 @@ public class PDFContentGenerator {
public void concatenate(AffineTransform transform) {
this.transform = transform;
if (!transform.isIdentity()) {
- currentState.concatenate(transform);
- currentStream.add(CTMHelper.toPDFString(transform, false) + " cm\n");
+ getState().concatenate(transform);
+ getStream().add(CTMHelper.toPDFString(transform, false) + " cm\n");
}
}
@@ -333,7 +374,7 @@ public class PDFContentGenerator {
* @param content the PDF content
*/
public void add(String content) {
- currentStream.add(content);
+ getStream().add(content);
}
/**
@@ -350,9 +391,9 @@ public class PDFContentGenerator {
* @param width line width in points
*/
public void updateLineWidth(float width) {
- if (currentState.setLineWidth(width)) {
+ if (getState().setLineWidth(width)) {
//Only write if value has changed WRT the current line width
- currentStream.add(format(width) + " w\n");
+ getStream().add(format(width) + " w\n");
}
}
@@ -362,7 +403,7 @@ public class PDFContentGenerator {
*/
public void updateCharacterSpacing(float value) {
if (getState().setCharacterSpacing(value)) {
- currentStream.add(format(value) + " Tc\n");
+ getStream().add(format(value) + " Tc\n");
}
}
@@ -400,7 +441,7 @@ public class PDFContentGenerator {
if (pdf != null) {
colorHandler.establishColor(pdf, col, fill);
} else {
- setColor(col, fill, this.currentStream);
+ setColor(col, fill, getStream());
}
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
index 0a3d34ef4..648cdce7a 100644
--- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
+++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
@@ -306,8 +306,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
throw new IFException("Error adding embedded file: " + embeddedFile.getSrc(), ioe);
}
} else if (extension instanceof PDFDictionaryAttachment) {
- PDFDictionaryAttachment dictionaryExtension = (PDFDictionaryAttachment) extension;
- pdfUtil.renderDictionaryExtension(dictionaryExtension, currentPage);
+ pdfUtil.renderDictionaryExtension((PDFDictionaryAttachment) extension, currentPage);
} else if (extension != null) {
log.debug("Don't know how to handle extension object. Ignoring: "
+ extension + " (" + extension.getClass().getName() + ")");
diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java
index d9fdd399c..f85328b8b 100644
--- a/src/java/org/apache/fop/render/pdf/PDFPainter.java
+++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java
@@ -143,8 +143,8 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
}
/** {@inheritDoc} */
- public void startGroup(AffineTransform transform) throws IFException {
- generator.saveGraphicsState();
+ public void startGroup(AffineTransform transform, String layer) throws IFException {
+ generator.saveGraphicsState(layer);
generator.concatenate(toPoints(transform));
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
index 962cd7847..d27fead12 100644
--- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
+++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
@@ -27,6 +27,7 @@ import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.EnumMap;
+import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
@@ -55,24 +56,33 @@ import org.apache.fop.pdf.PDFFileSpec;
import org.apache.fop.pdf.PDFICCBasedColorSpace;
import org.apache.fop.pdf.PDFICCStream;
import org.apache.fop.pdf.PDFInfo;
+import org.apache.fop.pdf.PDFLayer;
import org.apache.fop.pdf.PDFMetadata;
import org.apache.fop.pdf.PDFName;
import org.apache.fop.pdf.PDFNames;
+import org.apache.fop.pdf.PDFNavigator;
+import org.apache.fop.pdf.PDFNull;
import org.apache.fop.pdf.PDFNumber;
import org.apache.fop.pdf.PDFOutputIntent;
import org.apache.fop.pdf.PDFPage;
import org.apache.fop.pdf.PDFPageLabels;
import org.apache.fop.pdf.PDFReference;
+import org.apache.fop.pdf.PDFSetOCGStateAction;
import org.apache.fop.pdf.PDFText;
+import org.apache.fop.pdf.PDFTransitionAction;
import org.apache.fop.pdf.PDFXMode;
import org.apache.fop.pdf.Version;
import org.apache.fop.pdf.VersionController;
+import org.apache.fop.render.pdf.extensions.PDFActionExtension;
+import org.apache.fop.render.pdf.extensions.PDFArrayExtension;
+import org.apache.fop.render.pdf.extensions.PDFCollectionEntryExtension;
import org.apache.fop.render.pdf.extensions.PDFDictionaryAttachment;
-import org.apache.fop.render.pdf.extensions.PDFDictionaryEntryExtension;
-import org.apache.fop.render.pdf.extensions.PDFDictionaryEntryType;
import org.apache.fop.render.pdf.extensions.PDFDictionaryExtension;
import org.apache.fop.render.pdf.extensions.PDFDictionaryType;
import org.apache.fop.render.pdf.extensions.PDFEmbeddedFileAttachment;
+import org.apache.fop.render.pdf.extensions.PDFObjectType;
+import org.apache.fop.render.pdf.extensions.PDFPageExtension;
+import org.apache.fop.render.pdf.extensions.PDFReferenceExtension;
import static org.apache.fop.render.pdf.PDFEncryptionOption.ENCRYPTION_PARAMS;
import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_ACCESSCONTENT;
@@ -260,10 +270,189 @@ class PDFRenderingUtil {
public void renderDictionaryExtension(PDFDictionaryAttachment attachment, PDFPage currentPage) {
PDFDictionaryExtension extension = attachment.getExtension();
- if (extension.getDictionaryType() == PDFDictionaryType.Catalog) {
+ PDFDictionaryType type = extension.getDictionaryType();
+ if (type == PDFDictionaryType.Action) {
+ addNavigatorAction(extension);
+ } else if (type == PDFDictionaryType.Layer) {
+ addLayer(extension);
+ } else if (type == PDFDictionaryType.Navigator) {
+ addNavigator(extension);
+ } else {
+ renderDictionaryExtension(extension, currentPage);
+ }
+ }
+
+ public void addLayer(PDFDictionaryExtension extension) {
+ assert extension.getDictionaryType() == PDFDictionaryType.Layer;
+ String id = extension.getProperty(PDFDictionaryExtension.PROPERTY_ID);
+ if ((id != null) && (id.length() > 0)) {
+ PDFLayer layer = pdfDoc.getFactory().makeLayer(id);
+ layer.setResolver(new PDFLayer.Resolver(layer, extension) {
+ public void performResolution() {
+ PDFDictionaryExtension extension = (PDFDictionaryExtension) getExtension();
+ Object name = extension.findEntryValue("Name");
+ Object intent = extension.findEntryValue("Intent");
+ Object usage = makeDictionary(extension.findEntryValue("Usage"));
+ getLayer().populate(name, intent, usage);
+ }
+ });
+ }
+ }
+
+ public void addNavigatorAction(PDFDictionaryExtension extension) {
+ assert extension.getDictionaryType() == PDFDictionaryType.Action;
+ String id = extension.getProperty(PDFDictionaryExtension.PROPERTY_ID);
+ if ((id != null) && (id.length() > 0)) {
+ String type = extension.getProperty(PDFActionExtension.PROPERTY_TYPE);
+ if (type != null) {
+ if (type.equals("SetOCGState")) {
+ PDFSetOCGStateAction action = pdfDoc.getFactory().makeSetOCGStateAction(id);
+ action.setResolver(new PDFSetOCGStateAction.Resolver(action, extension) {
+ public void performResolution() {
+ PDFDictionaryExtension extension = (PDFDictionaryExtension) getExtension();
+ Object state = makeArray(extension.findEntryValue("State"));
+ Object preserveRB = extension.findEntryValue("PreserveRB");
+ Object nextAction = makeDictionaryOrArray(extension.findEntryValue("Next"));
+ getAction().populate(state, preserveRB, nextAction);
+ }
+ });
+ } else if (type.equals("Trans")) {
+ PDFTransitionAction action = pdfDoc.getFactory().makeTransitionAction(id);
+ action.setResolver(new PDFTransitionAction.Resolver(action, extension) {
+ public void performResolution() {
+ PDFDictionaryExtension extension = (PDFDictionaryExtension) getExtension();
+ Object transition = makeDictionary(extension.findEntryValue("Trans"));
+ Object nextAction = makeDictionaryOrArray(extension.findEntryValue("Next"));
+ getAction().populate(transition, nextAction);
+ }
+ });
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+ }
+
+ public void addNavigator(PDFDictionaryExtension extension) {
+ assert extension.getDictionaryType() == PDFDictionaryType.Navigator;
+ String id = extension.getProperty(PDFDictionaryExtension.PROPERTY_ID);
+ if ((id != null) && (id.length() > 0)) {
+ PDFNavigator navigator = pdfDoc.getFactory().makeNavigator(id);
+ navigator.setResolver(new PDFNavigator.Resolver(navigator, extension) {
+ public void performResolution() {
+ PDFDictionaryExtension extension = (PDFDictionaryExtension) getExtension();
+ Object nextAction = makeDictionary(extension.findEntryValue("NA"));
+ Object next = makeDictionary(extension.findEntryValue("Next"));
+ Object prevAction = makeDictionary(extension.findEntryValue("PA"));
+ Object prev = makeDictionary(extension.findEntryValue("Prev"));
+ Object duration = extension.findEntryValue("Dur");
+ getNavigator().populate(nextAction, next, prevAction, prev, duration);
+ }
+ });
+ }
+ }
+
+ private Object makeArray(Object value) {
+ if (value == null) {
+ return null;
+ } else if (value instanceof PDFReferenceExtension) {
+ return resolveReference((PDFReferenceExtension) value);
+ } else if (value instanceof List<?>) {
+ return populateArray(new PDFArray(), (List<?>) value);
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private Object populateArray(PDFArray array, List<?> entries) {
+ for (PDFCollectionEntryExtension entry : (List<PDFCollectionEntryExtension>) entries) {
+ PDFObjectType type = entry.getType();
+ if (type == PDFObjectType.Array) {
+ array.add(makeArray(entry.getValue()));
+ } else if (type == PDFObjectType.Boolean) {
+ array.add(entry.getValueAsBoolean());
+ } else if (type == PDFObjectType.Dictionary) {
+ array.add(makeDictionary(entry.getValue()));
+ } else if (type == PDFObjectType.Name) {
+ array.add(new PDFName(entry.getValueAsString()));
+ } else if (type == PDFObjectType.Number) {
+ array.add(new PDFNumber(entry.getValueAsNumber()));
+ } else if (type == PDFObjectType.Reference) {
+ array.add(resolveReference((PDFReferenceExtension) entry));
+ } else if (type == PDFObjectType.String) {
+ array.add(entry.getValue());
+ }
+ }
+ return array;
+ }
+
+ private Object makeDictionary(Object value) {
+ if (value == null) {
+ return null;
+ } else if (value instanceof PDFReferenceExtension) {
+ return resolveReference((PDFReferenceExtension) value);
+ } else if (value instanceof List<?>) {
+ return populateDictionary(new PDFDictionary(), (List<?>) value);
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private Object populateDictionary(PDFDictionary dictionary, List<?> entries) {
+ for (PDFCollectionEntryExtension entry : (List<PDFCollectionEntryExtension>) entries) {
+ PDFObjectType type = entry.getType();
+ String key = entry.getKey();
+ if (type == PDFObjectType.Array) {
+ dictionary.put(key, makeArray(entry.getValue()));
+ } else if (type == PDFObjectType.Boolean) {
+ dictionary.put(key, entry.getValueAsBoolean());
+ } else if (type == PDFObjectType.Dictionary) {
+ dictionary.put(key, makeDictionary(entry.getValue()));
+ } else if (type == PDFObjectType.Name) {
+ dictionary.put(key, new PDFName(entry.getValueAsString()));
+ } else if (type == PDFObjectType.Number) {
+ dictionary.put(key, new PDFNumber(entry.getValueAsNumber()));
+ } else if (type == PDFObjectType.Reference) {
+ dictionary.put(key, resolveReference((PDFReferenceExtension) entry));
+ } else if (type == PDFObjectType.String) {
+ dictionary.put(key, entry.getValue());
+ }
+ }
+ return dictionary;
+ }
+
+ private Object makeDictionaryOrArray(Object value) {
+ if (value == null) {
+ return null;
+ } else if (value instanceof PDFReferenceExtension) {
+ return resolveReference((PDFReferenceExtension) value);
+ } else if (value instanceof List<?>) {
+ if (hasKeyedEntry((List<?>) value)) {
+ return populateDictionary(new PDFDictionary(), (List<?>) value);
+ } else {
+ return populateArray(new PDFArray(), (List<?>) value);
+ }
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private boolean hasKeyedEntry(List<?> entries) {
+ for (PDFCollectionEntryExtension entry : (List<PDFCollectionEntryExtension>) entries) {
+ if (entry.getKey() != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void renderDictionaryExtension(PDFDictionaryExtension extension, PDFPage currentPage) {
+ PDFDictionaryType type = extension.getDictionaryType();
+ if (type == PDFDictionaryType.Catalog) {
augmentDictionary(pdfDoc.getRoot(), extension);
- } else if (extension.getDictionaryType() == PDFDictionaryType.Page) {
- if (extension.matchesPageNumber(currentPage.getPageIndex() + 1)) {
+ } else if (type == PDFDictionaryType.Page) {
+ assert extension instanceof PDFPageExtension;
+ if (((PDFPageExtension) extension).matchesPageNumber(currentPage.getPageIndex() + 1)) {
augmentDictionary(currentPage, extension);
}
} else {
@@ -272,9 +461,11 @@ class PDFRenderingUtil {
}
private PDFDictionary augmentDictionary(PDFDictionary dictionary, PDFDictionaryExtension extension) {
- for (PDFDictionaryEntryExtension entry : extension.getEntries()) {
+ for (PDFCollectionEntryExtension entry : extension.getEntries()) {
if (entry instanceof PDFDictionaryExtension) {
dictionary.put(entry.getKey(), augmentDictionary(new PDFDictionary(dictionary), (PDFDictionaryExtension) entry));
+ } else if (entry instanceof PDFArrayExtension) {
+ dictionary.put(entry.getKey(), augmentArray(new PDFArray(dictionary), (PDFArrayExtension) entry));
} else {
augmentDictionary(dictionary, entry);
}
@@ -282,22 +473,68 @@ class PDFRenderingUtil {
return dictionary;
}
- private void augmentDictionary(PDFDictionary dictionary, PDFDictionaryEntryExtension entry) {
- PDFDictionaryEntryType type = entry.getType();
+ private void augmentDictionary(PDFDictionary dictionary, PDFCollectionEntryExtension entry) {
+ PDFObjectType type = entry.getType();
String key = entry.getKey();
- if (type == PDFDictionaryEntryType.Boolean) {
+ if (type == PDFObjectType.Boolean) {
dictionary.put(key, entry.getValueAsBoolean());
- } else if (type == PDFDictionaryEntryType.Name) {
+ } else if (type == PDFObjectType.Name) {
dictionary.put(key, new PDFName(entry.getValueAsString()));
- } else if (type == PDFDictionaryEntryType.Number) {
+ } else if (type == PDFObjectType.Number) {
dictionary.put(key, new PDFNumber(entry.getValueAsNumber()));
- } else if (type == PDFDictionaryEntryType.String) {
+ } else if (type == PDFObjectType.Reference) {
+ assert entry instanceof PDFReferenceExtension;
+ dictionary.put(key, resolveReference((PDFReferenceExtension) entry));
+ } else if (type == PDFObjectType.String) {
dictionary.put(key, entry.getValueAsString());
} else {
throw new IllegalStateException();
}
}
+ private Object resolveReference(PDFReferenceExtension entry) {
+ PDFReference reference = (PDFReference) entry.getResolvedReference();
+ if (reference == null) {
+ reference = pdfDoc.resolveExtensionReference(entry.getReferenceId());
+ if (reference != null) {
+ entry.setResolvedReference(reference);
+ }
+ return reference;
+ }
+ return PDFNull.INSTANCE;
+ }
+
+ private PDFArray augmentArray(PDFArray array, PDFArrayExtension extension) {
+ for (PDFCollectionEntryExtension entry : extension.getEntries()) {
+ if (entry instanceof PDFDictionaryExtension) {
+ array.add(augmentDictionary(new PDFDictionary(array), (PDFDictionaryExtension) entry));
+ } else if (entry instanceof PDFArrayExtension) {
+ array.add(augmentArray(new PDFArray(array), (PDFArrayExtension) entry));
+ } else {
+ augmentArray(array, entry);
+ }
+ }
+ return array;
+ }
+
+ private void augmentArray(PDFArray array, PDFCollectionEntryExtension entry) {
+ PDFObjectType type = entry.getType();
+ if (type == PDFObjectType.Boolean) {
+ array.add(entry.getValueAsBoolean());
+ } else if (type == PDFObjectType.Name) {
+ array.add(new PDFName(entry.getValueAsString()));
+ } else if (type == PDFObjectType.Number) {
+ array.add(new PDFNumber(entry.getValueAsNumber()));
+ } else if (type == PDFObjectType.Reference) {
+ assert entry instanceof PDFReferenceExtension;
+ array.add(resolveReference((PDFReferenceExtension) entry));
+ } else if (type == PDFObjectType.String) {
+ array.add(entry.getValueAsString());
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
public PDFDocument setupPDFDocument(OutputStream out) throws IOException {
if (this.pdfDoc != null) {
throw new IllegalStateException("PDFDocument already set up");
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFActionElement.java b/src/java/org/apache/fop/render/pdf/extensions/PDFActionElement.java
new file mode 100644
index 000000000..e4a5747e6
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFActionElement.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.PropertyList;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Extension element for pdf:action.
+ */
+public class PDFActionElement extends PDFDictionaryElement {
+
+ public static final String ATT_TYPE = PDFActionExtension.PROPERTY_TYPE;
+
+ /**
+ * Main constructor
+ * @param parent parent FO node
+ */
+ PDFActionElement(FONode parent) {
+ super(parent, PDFDictionaryType.Action);
+ }
+
+ @Override
+ public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList propertyList) throws FOPException {
+ super.processNode(elementName, locator, attlist, propertyList);
+ String type = attlist.getValue(ATT_TYPE);
+ if (type != null) {
+ getDictionaryExtension().setProperty(PDFActionExtension.PROPERTY_TYPE, type);
+ }
+ }
+
+ @Override
+ public void startOfNode() throws FOPException {
+ super.startOfNode();
+ if (parent.getNameId() != Constants.FO_DECLARATIONS) {
+ invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), "rule.childOfDeclarations");
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFActionExtension.java b/src/java/org/apache/fop/render/pdf/extensions/PDFActionExtension.java
new file mode 100644
index 000000000..778b8a203
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFActionExtension.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+// CSOFF: LineLengthCheck
+
+public class PDFActionExtension extends PDFDictionaryExtension {
+
+ public static final String PROPERTY_TYPE = "type";
+
+ PDFActionExtension() {
+ super(PDFDictionaryType.Action);
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFArrayElement.java b/src/java/org/apache/fop/render/pdf/extensions/PDFArrayElement.java
new file mode 100644
index 000000000..1f3ba22b2
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFArrayElement.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.PropertyList;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Extension element for pdf:array.
+ */
+public class PDFArrayElement extends PDFCollectionEntryElement {
+
+ private PDFArrayExtension extension;
+
+ /**
+ * Main constructor
+ * @param parent parent FO node
+ */
+ PDFArrayElement(FONode parent) {
+ super(parent, PDFObjectType.Array, new PDFArrayExtension());
+ }
+
+ public PDFArrayExtension getArrayExtension() {
+ assert getExtension() instanceof PDFArrayExtension;
+ return (PDFArrayExtension) getExtension();
+ }
+
+ @Override
+ public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList propertyList) throws FOPException {
+ super.processNode(elementName, locator, attlist, propertyList);
+ }
+
+ @Override
+ public void startOfNode() throws FOPException {
+ super.startOfNode();
+ }
+
+ @Override
+ protected void addChildNode(FONode child) throws FOPException {
+ PDFArrayExtension extension = getArrayExtension();
+ if (child instanceof PDFCollectionEntryElement) {
+ PDFCollectionEntryExtension entry = ((PDFCollectionEntryElement) child).getExtension();
+ if (entry.getKey() == null) {
+ extension.addEntry(entry);
+ }
+ }
+ }
+
+ @Override
+ public void endOfNode() throws FOPException {
+ super.endOfNode();
+ }
+
+ @Override
+ public String getLocalName() {
+ return PDFObjectType.Array.elementName();
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFArrayExtension.java b/src/java/org/apache/fop/render/pdf/extensions/PDFArrayExtension.java
new file mode 100644
index 000000000..80c6c94e4
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFArrayExtension.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+import java.util.List;
+import java.util.Map;
+
+// CSOFF: LineLengthCheck
+
+public class PDFArrayExtension extends PDFCollectionExtension {
+
+ private static final long serialVersionUID = -1L;
+
+ private Map<String, String> properties;
+ private List<PDFCollectionEntryExtension> entries;
+
+ PDFArrayExtension() {
+ super(PDFObjectType.Array);
+ this.properties = new java.util.HashMap<String, String>();
+ this.entries = new java.util.ArrayList<PDFCollectionEntryExtension>();
+ }
+
+ @Override
+ public void setValue(Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue() {
+ return getEntries();
+ }
+
+ public void setProperty(String name, String value) {
+ properties.put(name, value);
+ }
+
+ public String getProperty(String name) {
+ return properties.get(name);
+ }
+
+ @Override
+ public void addEntry(PDFCollectionEntryExtension entry) {
+ if (entry.getKey() != null) {
+ throw new IllegalArgumentException();
+ } else {
+ entries.add(entry);
+ }
+ }
+
+ public List<PDFCollectionEntryExtension> getEntries() {
+ return entries;
+ }
+
+ public PDFCollectionEntryExtension getLastEntry() {
+ if (entries.size() > 0) {
+ return entries.get(entries.size() - 1);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public String getElementName() {
+ return PDFObjectType.Array.elementName();
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFCatalogElement.java b/src/java/org/apache/fop/render/pdf/extensions/PDFCatalogElement.java
new file mode 100644
index 000000000..029357d22
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFCatalogElement.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.FONode;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Extension element for pdf:catalog.
+ */
+public class PDFCatalogElement extends PDFDictionaryElement {
+
+ PDFCatalogElement(FONode parent) {
+ super(parent, PDFDictionaryType.Catalog);
+ }
+
+ @Override
+ public void startOfNode() throws FOPException {
+ super.startOfNode();
+ if (parent.getNameId() != Constants.FO_DECLARATIONS) {
+ invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), "rule.childOfDeclarations");
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFCatalogExtension.java b/src/java/org/apache/fop/render/pdf/extensions/PDFCatalogExtension.java
new file mode 100644
index 000000000..381f6fbe8
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFCatalogExtension.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+// CSOFF: LineLengthCheck
+
+public class PDFCatalogExtension extends PDFDictionaryExtension {
+
+ PDFCatalogExtension() {
+ super(PDFDictionaryType.Catalog);
+ }
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFCollectionEntryElement.java b/src/java/org/apache/fop/render/pdf/extensions/PDFCollectionEntryElement.java
new file mode 100644
index 000000000..4185ceef0
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFCollectionEntryElement.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.PropertyList;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Extension element for collection entries: pdf:{array,boolean,dictionary,name,number,reference,string}. The specific type
+ * of entry is established at construction type.
+ */
+public class PDFCollectionEntryElement extends AbstractPDFExtensionElement {
+
+ public static final String ATT_KEY = PDFCollectionEntryExtension.PROPERTY_KEY;
+
+ private PDFCollectionEntryExtension extension;
+ private StringBuffer characters;
+
+ PDFCollectionEntryElement(FONode parent, PDFObjectType type, PDFCollectionEntryExtension extension) {
+ super(parent);
+ this.extension = extension;
+ }
+
+ PDFCollectionEntryElement(FONode parent, PDFObjectType type) {
+ this(parent, type, createExtension(type));
+ }
+
+ private static PDFCollectionEntryExtension createExtension(PDFObjectType type) {
+ if (type == PDFObjectType.Reference) {
+ return new PDFReferenceExtension();
+ } else {
+ return new PDFCollectionEntryExtension(type);
+ }
+ }
+
+ public PDFCollectionEntryExtension getExtension() {
+ return extension;
+ }
+
+ @Override
+ public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList propertyList) throws FOPException {
+ if (parent instanceof PDFDictionaryElement) {
+ String key = attlist.getValue(ATT_KEY);
+ if (key == null) {
+ missingPropertyError(ATT_KEY);
+ } else if (key.length() == 0) {
+ invalidPropertyValueError(ATT_KEY, key, null);
+ } else {
+ extension.setKey(key);
+ }
+ }
+ }
+
+ @Override
+ public void startOfNode() throws FOPException {
+ super.startOfNode();
+ if (parent instanceof PDFDictionaryElement) {
+ if (!PDFDictionaryType.hasValueOfElementName(parent.getLocalName())) {
+ invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), null);
+ }
+ }
+ }
+
+ @Override
+ protected void characters(char[] data, int start, int length, PropertyList pList, Locator locator) throws FOPException {
+ if (capturePCData(extension.getType())) {
+ if (characters == null) {
+ characters = new StringBuffer((length < 16) ? 16 : length);
+ }
+ characters.append(data, start, length);
+ }
+ }
+
+ private boolean capturePCData(PDFObjectType type) {
+ if (type == PDFObjectType.Array) {
+ return false;
+ } else if (type == PDFObjectType.Dictionary) {
+ return false;
+ } else {
+ return (type != PDFObjectType.Reference);
+ }
+ }
+
+ @Override
+ public void endOfNode() throws FOPException {
+ if (capturePCData(extension.getType())) {
+ if (extension.getType() == PDFObjectType.Boolean) {
+ String value = (characters != null) ? characters.toString() : "";
+ if (!value.equals("true") && !value.equals("false")) {
+ invalidPropertyValueError("<value>", value, null);
+ }
+ extension.setValue(Boolean.valueOf(value));
+ } else if (extension.getType() == PDFObjectType.Name) {
+ String value = (characters != null) ? characters.toString() : "";
+ if (value.length() == 0) {
+ invalidPropertyValueError("<value>", value, null);
+ }
+ extension.setValue(value);
+ } else if (extension.getType() == PDFObjectType.Number) {
+ String value = (characters != null) ? characters.toString() : "";
+ try {
+ double d = Double.parseDouble(value);
+ if (Math.abs(Math.floor(d) - d) < 1E-10) {
+ extension.setValue(Long.valueOf((long) d));
+ } else {
+ extension.setValue(Double.valueOf(d));
+ }
+ } catch (NumberFormatException e) {
+ invalidPropertyValueError("<value>", value, null);
+ }
+ } else if (extension.getType() == PDFObjectType.String) {
+ String value = (characters != null) ? characters.toString() : "";
+ extension.setValue(value);
+ }
+ }
+ super.endOfNode();
+ }
+
+ @Override
+ public String getLocalName() {
+ return extension.getType().elementName();
+ }
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/AbstractPDFDictionaryElement.java b/src/java/org/apache/fop/render/pdf/extensions/PDFCollectionEntryExtension.java
index 9de7e95da..d28f1602f 100644
--- a/src/java/org/apache/fop/render/pdf/extensions/AbstractPDFDictionaryElement.java
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFCollectionEntryExtension.java
@@ -19,25 +19,25 @@
package org.apache.fop.render.pdf.extensions;
-import org.apache.fop.fo.FONode;
-
// CSOFF: LineLengthCheck
-/**
- * Base class for the PDF dictionary related extension elements.
- */
-public abstract class AbstractPDFDictionaryElement extends AbstractPDFExtensionElement {
-
- public static final String ATT_KEY = PDFDictionaryEntryExtension.PROPERTY_KEY;
-
- /**
- * Default constructor
- *
- * @param parent parent of this node
- * @see org.apache.fop.fo.FONode#FONode(FONode)
- */
- public AbstractPDFDictionaryElement(FONode parent) {
- super(parent);
+public class PDFCollectionEntryExtension extends PDFObjectExtension {
+
+ public static final String PROPERTY_KEY = "key";
+
+ /* Non-empty key if used as dictionary entry, otherwise must be null. */
+ private String key;
+
+ PDFCollectionEntryExtension(PDFObjectType type) {
+ super(type);
}
-}
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFCollectionExtension.java b/src/java/org/apache/fop/render/pdf/extensions/PDFCollectionExtension.java
new file mode 100644
index 000000000..228d69c79
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFCollectionExtension.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+// CSOFF: LineLengthCheck
+
+public abstract class PDFCollectionExtension extends PDFCollectionEntryExtension {
+
+ protected PDFCollectionExtension(PDFObjectType type) {
+ super(type);
+ }
+
+ public abstract void addEntry(PDFCollectionEntryExtension entry);
+
+ public abstract PDFCollectionEntryExtension getLastEntry();
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryAttachment.java b/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryAttachment.java
index 19e5ce07a..3832619ba 100644
--- a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryAttachment.java
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryAttachment.java
@@ -43,14 +43,13 @@ public class PDFDictionaryAttachment extends PDFExtensionAttachment {
}
public void toSAX(ContentHandler handler) throws SAXException {
- PDFDictionaryType dictionaryType = extension.getDictionaryType();
int pageNumber = 0;
- if (dictionaryType == PDFDictionaryType.Page) {
+ if (extension instanceof PDFPageExtension) {
if (handler instanceof GenerationHelperContentHandler) {
Object context = ((GenerationHelperContentHandler) handler).getContentHandlerContext();
if (context instanceof IFContext) {
int pageIndex = ((IFContext) context).getPageIndex();
- if ((pageIndex >= 0) && extension.matchesPageNumber(pageIndex + 1)) {
+ if ((pageIndex >= 0) && ((PDFPageExtension) extension).matchesPageNumber(pageIndex + 1)) {
pageNumber = pageIndex + 1;
} else {
pageNumber = -1;
@@ -69,24 +68,40 @@ public class PDFDictionaryAttachment extends PDFExtensionAttachment {
String qn = PREFIX + ":" + ln;
attributes = extractIFAttributes(attributes, dictionary);
handler.startElement(CATEGORY, ln, qn, attributes);
- for (PDFDictionaryEntryExtension entry : dictionary.getEntries()) {
+ for (PDFCollectionEntryExtension entry : dictionary.getEntries()) {
toSAX(handler, entry);
}
handler.endElement(CATEGORY, ln, qn);
}
- private void toSAX(ContentHandler handler, PDFDictionaryEntryExtension entry) throws SAXException {
+ private void toSAX(ContentHandler handler, PDFArrayExtension array) throws SAXException {
+ AttributesImpl attributes = new AttributesImpl();
+ String ln = array.getElementName();
+ String qn = PREFIX + ":" + ln;
+ attributes = extractIFAttributes(attributes, array);
+ handler.startElement(CATEGORY, ln, qn, attributes);
+ for (PDFCollectionEntryExtension entry : array.getEntries()) {
+ toSAX(handler, entry);
+ }
+ handler.endElement(CATEGORY, ln, qn);
+ }
+
+ private void toSAX(ContentHandler handler, PDFCollectionEntryExtension entry) throws SAXException {
if (entry instanceof PDFDictionaryExtension) {
toSAX(handler, (PDFDictionaryExtension) entry);
+ } else if (entry instanceof PDFArrayExtension) {
+ toSAX(handler, (PDFArrayExtension) entry);
} else {
AttributesImpl attributes = new AttributesImpl();
String ln = entry.getElementName();
String qn = PREFIX + ":" + ln;
attributes = extractIFAttributes(attributes, entry);
handler.startElement(CATEGORY, ln, qn, attributes);
- char[] characters = entry.getValueAsXMLEscapedString().toCharArray();
- if (characters.length > 0) {
- handler.characters(characters, 0, characters.length);
+ if (!(entry instanceof PDFReferenceExtension)) {
+ char[] characters = entry.getValueAsXMLEscapedString().toCharArray();
+ if (characters.length > 0) {
+ handler.characters(characters, 0, characters.length);
+ }
}
handler.endElement(CATEGORY, ln, qn);
}
@@ -94,16 +109,27 @@ public class PDFDictionaryAttachment extends PDFExtensionAttachment {
private static AttributesImpl extractIFAttributes(AttributesImpl attributes, PDFDictionaryExtension dictionary) {
PDFDictionaryType type = dictionary.getDictionaryType();
- if (type == PDFDictionaryType.Catalog) {
- // no specific attriburtes
+ if (dictionary.usesIDAttribute()) {
+ String idName = PDFDictionaryElement.ATT_ID;
+ String id = dictionary.getProperty(PDFDictionaryExtension.PROPERTY_ID);
+ if (id != null) {
+ attributes.addAttribute(null, idName, idName, "ID", id);
+ }
+ }
+ if (type == PDFDictionaryType.Action) {
+ String actionTypeName = PDFActionElement.ATT_TYPE;
+ String actionType = dictionary.getProperty(PDFActionExtension.PROPERTY_TYPE);
+ if (actionType != null) {
+ attributes.addAttribute(null, actionTypeName, actionTypeName, "CDATA", actionType);
+ }
} else if (type == PDFDictionaryType.Page) {
- String pageNumbersName = PDFDictionaryExtension.PROPERTY_PAGE_NUMBERS;
+ String pageNumbersName = PDFPageExtension.PROPERTY_PAGE_NUMBERS;
String pageNumbers = dictionary.getProperty(pageNumbersName);
if (pageNumbers != null) {
attributes.addAttribute(null, pageNumbersName, pageNumbersName, "CDATA", pageNumbers);
}
} else if (type == PDFDictionaryType.Dictionary) {
- String keyName = PDFDictionaryEntryExtension.PROPERTY_KEY;
+ String keyName = PDFCollectionEntryElement.ATT_KEY;
String key = dictionary.getKey();
if (key != null) {
attributes.addAttribute(null, keyName, keyName, "CDATA", key);
@@ -112,12 +138,28 @@ public class PDFDictionaryAttachment extends PDFExtensionAttachment {
return attributes;
}
- private static AttributesImpl extractIFAttributes(AttributesImpl attributes, PDFDictionaryEntryExtension entry) {
- String keyName = PDFDictionaryEntryExtension.PROPERTY_KEY;
+ private static AttributesImpl extractIFAttributes(AttributesImpl attributes, PDFArrayExtension array) {
+ String keyName = PDFCollectionEntryExtension.PROPERTY_KEY;
+ String key = array.getKey();
+ if (key != null) {
+ attributes.addAttribute(null, keyName, keyName, "CDATA", key);
+ }
+ return attributes;
+ }
+
+ private static AttributesImpl extractIFAttributes(AttributesImpl attributes, PDFCollectionEntryExtension entry) {
+ String keyName = PDFCollectionEntryElement.ATT_KEY;
String key = entry.getKey();
if (key != null) {
attributes.addAttribute(null, keyName, keyName, "CDATA", key);
}
+ if (entry instanceof PDFReferenceExtension) {
+ String refid = ((PDFReferenceExtension) entry).getReferenceId();
+ if (refid != null) {
+ String refidName = PDFReferenceElement.ATT_REFID;
+ attributes.addAttribute(null, refidName, refidName, "IDREF", refid);
+ }
+ }
return attributes;
}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryElement.java b/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryElement.java
index 0920f3a78..9dc127da6 100644
--- a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryElement.java
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryElement.java
@@ -23,7 +23,6 @@ import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.apache.fop.apps.FOPException;
-import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.extensions.ExtensionAttachment;
@@ -34,38 +33,54 @@ import org.apache.fop.fo.extensions.ExtensionAttachment;
* Extension element for dictionaries: pdf:{catalog,page,dictionary}. The specific type
* of dictionary is established at construction type.
*/
-public class PDFDictionaryElement extends AbstractPDFDictionaryElement {
+public class PDFDictionaryElement extends PDFCollectionEntryElement {
- public static final String ATT_PAGE_NUMBERS = PDFDictionaryExtension.PROPERTY_PAGE_NUMBERS;
-
- private PDFDictionaryExtension extension;
+ public static final String ATT_ID = PDFDictionaryExtension.PROPERTY_ID;
/**
* Main constructor
* @param parent parent FO node
*/
PDFDictionaryElement(FONode parent, PDFDictionaryType type) {
- super(parent);
- this.extension = new PDFDictionaryExtension(type);
+ super(parent, PDFObjectType.Dictionary, createExtension(type));
+ }
+
+ private static PDFDictionaryExtension createExtension(PDFDictionaryType type) {
+ if (type == PDFDictionaryType.Action) {
+ return new PDFActionExtension();
+ } else if (type == PDFDictionaryType.Catalog) {
+ return new PDFCatalogExtension();
+ } else if (type == PDFDictionaryType.Layer) {
+ return new PDFLayerExtension();
+ } else if (type == PDFDictionaryType.Navigator) {
+ return new PDFNavigatorExtension();
+ } else if (type == PDFDictionaryType.Page) {
+ return new PDFPageExtension();
+ } else {
+ return new PDFDictionaryExtension(type);
+ }
}
- public PDFDictionaryExtension getExtension() {
- return extension;
+ public PDFDictionaryExtension getDictionaryExtension() {
+ assert getExtension() instanceof PDFDictionaryExtension;
+ return (PDFDictionaryExtension) getExtension();
}
@Override
public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList propertyList) throws FOPException {
- if (extension.getDictionaryType() == PDFDictionaryType.Catalog) {
- // no specific properties
- } else if (extension.getDictionaryType() == PDFDictionaryType.Page) {
- String pageNumbers = attlist.getValue(ATT_PAGE_NUMBERS);
- if (pageNumbers != null) {
- extension.setProperty(ATT_PAGE_NUMBERS, pageNumbers);
+ PDFDictionaryExtension extension = getDictionaryExtension();
+ if (extension.usesIDAttribute()) {
+ String id = attlist.getValue(ATT_ID);
+ if (id != null) {
+ extension.setProperty(PDFDictionaryExtension.PROPERTY_ID, id);
}
- } else if (extension.getDictionaryType() == PDFDictionaryType.Dictionary) {
+ }
+ if (extension.getDictionaryType() == PDFDictionaryType.Dictionary) {
String key = attlist.getValue(ATT_KEY);
if (key == null) {
- missingPropertyError(ATT_KEY);
+ if (parent instanceof PDFDictionaryElement) {
+ missingPropertyError(ATT_KEY);
+ }
} else if (key.length() == 0) {
invalidPropertyValueError(ATT_KEY, key, null);
} else {
@@ -78,16 +93,18 @@ public class PDFDictionaryElement extends AbstractPDFDictionaryElement {
public void startOfNode() throws FOPException {
super.startOfNode();
String localName = getLocalName();
- if (localName.equals("catalog")) {
- if (parent.getNameId() != Constants.FO_DECLARATIONS) {
- invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), "rule.childOfDeclarations");
- }
+ if (localName.equals("action")) {
+ // handled in PDFActionElement subclass
+ } else if (localName.equals("catalog")) {
+ // handled in PDFCatalogElement subclass
+ } else if (localName.equals("layer")) {
+ // handled in PDFLayerElement subclass
+ } else if (localName.equals("navigator")) {
+ // handled in PDFNavigattorElement subclass
} else if (localName.equals("page")) {
- if (parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER) {
- invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), "rule.childOfSPM");
- }
+ // handled in PDFPageElement subclass
} else if (localName.equals("dictionary")) {
- if (!PDFDictionaryType.hasValueOfElementName(parent.getLocalName())) {
+ if (!PDFDictionaryType.hasValueOfElementName(parent.getLocalName()) && !PDFObjectType.Array.elementName().equals(parent.getLocalName())) {
invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), null);
}
} else {
@@ -97,14 +114,15 @@ public class PDFDictionaryElement extends AbstractPDFDictionaryElement {
@Override
protected void addChildNode(FONode child) throws FOPException {
+ PDFDictionaryExtension extension = getDictionaryExtension();
if (child instanceof PDFDictionaryElement) {
- PDFDictionaryExtension extension = ((PDFDictionaryElement) child).getExtension();
- if (extension.getDictionaryType() == PDFDictionaryType.Dictionary) {
- this.extension.addEntry(extension);
+ PDFDictionaryExtension entry = ((PDFDictionaryElement) child).getDictionaryExtension();
+ if (entry.getDictionaryType() == PDFDictionaryType.Dictionary) {
+ extension.addEntry(entry);
}
- } else if (child instanceof PDFDictionaryEntryElement) {
- PDFDictionaryEntryExtension extension = ((PDFDictionaryEntryElement) child).getExtension();
- this.extension.addEntry(extension);
+ } else if (child instanceof PDFCollectionEntryElement) {
+ PDFCollectionEntryExtension entry = ((PDFCollectionEntryElement) child).getExtension();
+ extension.addEntry(entry);
}
}
@@ -115,12 +133,13 @@ public class PDFDictionaryElement extends AbstractPDFDictionaryElement {
@Override
public String getLocalName() {
+ PDFDictionaryExtension extension = getDictionaryExtension();
return extension.getDictionaryType().elementName();
}
@Override
protected ExtensionAttachment instantiateExtensionAttachment() {
- return new PDFDictionaryAttachment(extension);
+ return new PDFDictionaryAttachment(getDictionaryExtension());
}
}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryEntryElement.java b/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryEntryElement.java
deleted file mode 100644
index bcdb90c2c..000000000
--- a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryEntryElement.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.pdf.extensions;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.Locator;
-
-import org.apache.fop.apps.FOPException;
-import org.apache.fop.fo.FONode;
-import org.apache.fop.fo.PropertyList;
-
-// CSOFF: LineLengthCheck
-
-/**
- * Extension element for dictionary entries: pdf:{boolean,name,number,string}. The specific type
- * of entry is established at construction type.
- */
-public class PDFDictionaryEntryElement extends AbstractPDFDictionaryElement {
-
- private PDFDictionaryEntryExtension extension;
- private StringBuffer characters;
-
- /**
- * Main constructor
- * @param parent parent FO node
- */
- PDFDictionaryEntryElement(FONode parent, PDFDictionaryEntryType type) {
- super(parent);
- this.extension = new PDFDictionaryEntryExtension(type);
- }
-
- public PDFDictionaryEntryExtension getExtension() {
- return extension;
- }
-
- @Override
- public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList propertyList) throws FOPException {
- String key = attlist.getValue("key");
- if (key == null) {
- missingPropertyError("key");
- } else if (key.length() == 0) {
- invalidPropertyValueError("key", key, null);
- } else {
- extension.setKey(key);
- }
- }
-
- @Override
- public void startOfNode() throws FOPException {
- super.startOfNode();
- if (!PDFDictionaryType.hasValueOfElementName(parent.getLocalName())) {
- invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), null);
- }
- }
-
- @Override
- protected void characters(char[] data, int start, int length, PropertyList pList, Locator locator) throws FOPException {
- if (characters == null) {
- characters = new StringBuffer((length < 16) ? 16 : length);
- }
- characters.append(data, start, length);
- }
-
- @Override
- public void endOfNode() throws FOPException {
- String value = (characters != null) ? characters.toString() : "";
- if (extension.getType() == PDFDictionaryEntryType.Boolean) {
- if (!value.equals("true") && !value.equals("false")) {
- invalidPropertyValueError("<value>", value, null);
- }
- } else if (extension.getType() == PDFDictionaryEntryType.Name) {
- if (value.length() == 0) {
- invalidPropertyValueError("<value>", value, null);
- }
- } else if (extension.getType() == PDFDictionaryEntryType.Number) {
- try {
- Double.valueOf(value);
- } catch (NumberFormatException e) {
- invalidPropertyValueError("<value>", value, null);
- }
- } else if (extension.getType() != PDFDictionaryEntryType.String) {
- throw new IllegalStateException();
- }
- extension.setValue(value);
- super.endOfNode();
- }
-
- @Override
- public String getLocalName() {
- return extension.getType().elementName();
- }
-}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryExtension.java b/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryExtension.java
index d4b11cdb4..50b6f3a83 100644
--- a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryExtension.java
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryExtension.java
@@ -24,24 +24,36 @@ import java.util.Map;
// CSOFF: LineLengthCheck
-public class PDFDictionaryExtension extends PDFDictionaryEntryExtension {
+public class PDFDictionaryExtension extends PDFCollectionExtension {
+ public static final String PROPERTY_ID = "id";
public static final String PROPERTY_PAGE_NUMBERS = "page-numbers";
private static final long serialVersionUID = -1L;
private PDFDictionaryType dictionaryType;
private Map<String, String> properties;
- private List<PDFDictionaryEntryExtension> entries;
+ private List<PDFCollectionEntryExtension> entries;
PDFDictionaryExtension() {
+ this(PDFDictionaryType.Dictionary);
}
PDFDictionaryExtension(PDFDictionaryType dictionaryType) {
- super(PDFDictionaryEntryType.Dictionary);
+ super(PDFObjectType.Dictionary);
this.dictionaryType = dictionaryType;
this.properties = new java.util.HashMap<String, String>();
- this.entries = new java.util.ArrayList<PDFDictionaryEntryExtension>();
+ this.entries = new java.util.ArrayList<PDFCollectionEntryExtension>();
+ }
+
+ @Override
+ public void setValue(Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue() {
+ return getEntries();
}
public PDFDictionaryType getDictionaryType() {
@@ -56,15 +68,40 @@ public class PDFDictionaryExtension extends PDFDictionaryEntryExtension {
return properties.get(name);
}
- public void addEntry(PDFDictionaryEntryExtension entry) {
- entries.add(entry);
+ @Override
+ public void addEntry(PDFCollectionEntryExtension entry) {
+ if ((entry.getKey() == null) || (entry.getKey().length() == 0)) {
+ throw new IllegalArgumentException();
+ } else {
+ entries.add(entry);
+ }
}
- public List<PDFDictionaryEntryExtension> getEntries() {
+ public List<PDFCollectionEntryExtension> getEntries() {
return entries;
}
- public PDFDictionaryEntryExtension getLastEntry() {
+ public PDFCollectionEntryExtension findEntry(String key) {
+ for (PDFCollectionEntryExtension entry : entries) {
+ String entryKey = entry.getKey();
+ if ((entryKey != null) && entryKey.equals(key)) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
+ public Object findEntryValue(String key) {
+ for (PDFCollectionEntryExtension entry : entries) {
+ String entryKey = entry.getKey();
+ if ((entryKey != null) && entryKey.equals(key)) {
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+
+ public PDFCollectionEntryExtension getLastEntry() {
if (entries.size() > 0) {
return entries.get(entries.size() - 1);
} else {
@@ -72,48 +109,8 @@ public class PDFDictionaryExtension extends PDFDictionaryEntryExtension {
}
}
- /**
- * Determine if page dictionary and page number matches.
- * @param pageNumber page number, where first page number is 1
- * @return true if this dictionary is a page dictionary and specified page number matches specified page-number property
- */
- public boolean matchesPageNumber(int pageNumber) {
- if (dictionaryType != PDFDictionaryType.Page) {
- return false;
- }
- String pageNumbers = getProperty(PROPERTY_PAGE_NUMBERS);
- if ((pageNumbers == null) || (pageNumbers.length() == 0)) {
- return false;
- } else if (pageNumbers.equals("*")) {
- return true;
- } else {
- for (String interval : pageNumbers.split("\\s*,\\s*")) {
- String[] components = interval.split("\\s*-\\s*");
- if (components.length < 1) {
- continue;
- } else {
- try {
- int start = Integer.parseInt(components[0]);
- int end = 0;
- if (components.length > 1) {
- if (!components[1].equals("LAST")) {
- end = Integer.parseInt(components[1]);
- }
- }
- if ((end == 0) && (pageNumber == start)) {
- return true;
- } else if ((end > start) && (pageNumber >= start) && (pageNumber < end)) {
- return true;
- } else {
- continue;
- }
- } catch (NumberFormatException e) {
- continue;
- }
- }
- }
- }
- return false;
+ public boolean usesIDAttribute() {
+ return dictionaryType.usesIDAttribute();
}
@Override
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryType.java b/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryType.java
index edd95160a..a49a5fc8c 100644
--- a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryType.java
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryType.java
@@ -25,17 +25,28 @@ package org.apache.fop.render.pdf.extensions;
* Enumeration type for PDF dictionary extension elements.
*/
public enum PDFDictionaryType {
- Dictionary("dictionary"), // generic (nested) dictionary element
- Catalog("catalog"), // catalog dictionary element
- Page("page"); // page dictionary element
+ Action("action", true), // action dictionary element
+ Catalog("catalog"), // catalog dictionary element
+ Dictionary("dictionary"), // generic (nested) dictionary element
+ Layer("layer", true), // optional content group dictionary element
+ Navigator("navigator", true), // navigation node dictionary element
+ Page("page"); // page dictionary element
private String elementName;
- PDFDictionaryType(String elementName) {
+ private boolean usesIDAttribute;
+ PDFDictionaryType(String elementName, boolean usesIDAttribute) {
this.elementName = elementName;
+ this.usesIDAttribute = usesIDAttribute;
+ }
+ PDFDictionaryType(String elementName) {
+ this(elementName, false);
}
public String elementName() {
return elementName;
}
+ public boolean usesIDAttribute() {
+ return usesIDAttribute;
+ }
static PDFDictionaryType valueOfElementName(String elementName) {
for (PDFDictionaryType type : values()) {
if (type.elementName.equals(elementName)) {
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFElementMapping.java b/src/java/org/apache/fop/render/pdf/extensions/PDFElementMapping.java
index 3e063e24b..1fba80796 100644
--- a/src/java/org/apache/fop/render/pdf/extensions/PDFElementMapping.java
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFElementMapping.java
@@ -41,17 +41,56 @@ public class PDFElementMapping extends ElementMapping {
protected void initialize() {
if (foObjs == null) {
foObjs = new java.util.HashMap<String, Maker>();
+ // pdf:action
+ foObjs.put(PDFDictionaryType.Action.elementName(), new PDFActionElementMaker());
+ // pdf:array
+ foObjs.put(PDFObjectType.Array.elementName(), new PDFArrayElementMaker());
+ // pdf:boolean
+ foObjs.put(PDFObjectType.Boolean.elementName(), new PDFCollectionEntryElementMaker(PDFObjectType.Boolean));
+ // pdf:catalog
+ foObjs.put(PDFDictionaryType.Catalog.elementName(), new PDFCatalogElementMaker());
+ // pdf:dictionary
+ foObjs.put(PDFDictionaryType.Dictionary.elementName(), new PDFDictionaryElementMaker());
// pdf:embedded-file
foObjs.put(PDFEmbeddedFileElement.ELEMENT, new PDFEmbeddedFileElementMaker());
- // pdf:{catalog,page} et al.
- for (PDFDictionaryType type : PDFDictionaryType.values()) {
- foObjs.put(type.elementName(), new PDFDictionaryElementMaker(type));
- }
- for (PDFDictionaryEntryType type : PDFDictionaryEntryType.values()) {
- if (type != PDFDictionaryEntryType.Dictionary) {
- foObjs.put(type.elementName(), new PDFDictionaryEntryElementMaker(type));
- }
- }
+ // pdf:name
+ foObjs.put(PDFObjectType.Name.elementName(), new PDFCollectionEntryElementMaker(PDFObjectType.Name));
+ // pdf:number
+ foObjs.put(PDFObjectType.Number.elementName(), new PDFCollectionEntryElementMaker(PDFObjectType.Number));
+ // pdf:navigator
+ foObjs.put(PDFDictionaryType.Navigator.elementName(), new PDFNavigatorElementMaker());
+ // pdf:layer
+ foObjs.put(PDFDictionaryType.Layer.elementName(), new PDFLayerElementMaker());
+ // pdf:page
+ foObjs.put(PDFDictionaryType.Page.elementName(), new PDFPageElementMaker());
+ // pdf:reference
+ foObjs.put(PDFObjectType.Reference.elementName(), new PDFReferenceElementMaker());
+ // pdf:string
+ foObjs.put(PDFObjectType.String.elementName(), new PDFCollectionEntryElementMaker(PDFObjectType.String));
+ }
+ }
+
+ static class PDFActionElementMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new PDFActionElement(parent);
+ }
+ }
+
+ static class PDFArrayElementMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new PDFArrayElement(parent);
+ }
+ }
+
+ static class PDFCatalogElementMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new PDFCatalogElement(parent);
+ }
+ }
+
+ static class PDFDictionaryElementMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new PDFDictionaryElement(parent, PDFDictionaryType.Dictionary);
}
}
@@ -61,23 +100,38 @@ public class PDFElementMapping extends ElementMapping {
}
}
- static class PDFDictionaryElementMaker extends ElementMapping.Maker {
- private PDFDictionaryType dictionaryType;
- PDFDictionaryElementMaker(PDFDictionaryType dictionaryType) {
- this.dictionaryType = dictionaryType;
+ static class PDFLayerElementMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new PDFLayerElement(parent);
}
+ }
+
+ static class PDFNavigatorElementMaker extends ElementMapping.Maker {
public FONode make(FONode parent) {
- return new PDFDictionaryElement(parent, dictionaryType);
+ return new PDFNavigatorElement(parent);
}
}
- static class PDFDictionaryEntryElementMaker extends ElementMapping.Maker {
- private PDFDictionaryEntryType entryType;
- PDFDictionaryEntryElementMaker(PDFDictionaryEntryType entryType) {
+ static class PDFPageElementMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new PDFPageElement(parent);
+ }
+ }
+
+ static class PDFCollectionEntryElementMaker extends ElementMapping.Maker {
+ private PDFObjectType entryType;
+ PDFCollectionEntryElementMaker(PDFObjectType entryType) {
this.entryType = entryType;
}
public FONode make(FONode parent) {
- return new PDFDictionaryEntryElement(parent, entryType);
+ return new PDFCollectionEntryElement(parent, entryType);
}
}
+
+ static class PDFReferenceElementMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new PDFReferenceElement(parent);
+ }
+ }
+
}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java b/src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java
index f14f1e7d6..2fd14058e 100644
--- a/src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java
@@ -49,7 +49,7 @@ public class PDFExtensionHandler extends DefaultHandler implements ContentHandle
private Attributes lastAttributes;
// PDFDictionaryAttachment related
- private Stack<PDFDictionaryExtension> dictionaries = new Stack<PDFDictionaryExtension>();
+ private Stack<PDFCollectionExtension> collections = new Stack<PDFCollectionExtension>();
private boolean captureContent;
private StringBuffer characters;
@@ -58,29 +58,78 @@ public class PDFExtensionHandler extends DefaultHandler implements ContentHandle
if (PDFExtensionAttachment.CATEGORY.equals(uri)) {
if (localName.equals(PDFEmbeddedFileAttachment.ELEMENT)) {
lastAttributes = new AttributesImpl(attributes);
- } else if (PDFDictionaryType.hasValueOfElementName(localName)) {
- PDFDictionaryExtension dictionary = new PDFDictionaryExtension(PDFDictionaryType.valueOfElementName(localName));
- String key = attributes.getValue(PDFDictionaryEntryExtension.PROPERTY_KEY);
+ } else if (PDFDictionaryType.Action.elementName().equals(localName)) {
+ PDFActionExtension action = new PDFActionExtension();
+ String id = attributes.getValue(PDFDictionaryElement.ATT_ID);
+ if (id != null) {
+ action.setProperty(PDFDictionaryExtension.PROPERTY_ID, id);
+ }
+ String type = attributes.getValue(PDFActionElement.ATT_TYPE);
+ if (type != null) {
+ action.setProperty(PDFActionExtension.PROPERTY_TYPE, type);
+ }
+ collections.push(action);
+ } else if (PDFObjectType.Array.elementName().equals(localName)) {
+ PDFArrayExtension array = new PDFArrayExtension();
+ String key = attributes.getValue(PDFCollectionEntryElement.ATT_KEY);
+ if (key != null) {
+ array.setKey(key);
+ }
+ collections.push(array);
+ } else if (PDFDictionaryType.Catalog.elementName().equals(localName)) {
+ PDFCatalogExtension catalog = new PDFCatalogExtension();
+ collections.push(catalog);
+ } else if (PDFDictionaryType.Dictionary.elementName().equals(localName)) {
+ PDFDictionaryExtension dictionary = new PDFDictionaryExtension();
+ String key = attributes.getValue(PDFCollectionEntryElement.ATT_KEY);
if (key != null) {
dictionary.setKey(key);
}
- if (dictionary.getDictionaryType() == PDFDictionaryType.Page) {
- String pageNumbers = attributes.getValue(PDFDictionaryElement.ATT_PAGE_NUMBERS);
- if (pageNumbers != null) {
- dictionary.setProperty(PDFDictionaryElement.ATT_PAGE_NUMBERS, pageNumbers);
- }
+ collections.push(dictionary);
+ } else if (PDFDictionaryType.Layer.elementName().equals(localName)) {
+ PDFLayerExtension layer = new PDFLayerExtension();
+ String id = attributes.getValue(PDFDictionaryElement.ATT_ID);
+ if (id != null) {
+ layer.setProperty(PDFDictionaryExtension.PROPERTY_ID, id);
+ }
+ collections.push(layer);
+ } else if (PDFDictionaryType.Navigator.elementName().equals(localName)) {
+ PDFNavigatorExtension navigator = new PDFNavigatorExtension();
+ String id = attributes.getValue(PDFDictionaryElement.ATT_ID);
+ if (id != null) {
+ navigator.setProperty(PDFDictionaryExtension.PROPERTY_ID, id);
+ }
+ collections.push(navigator);
+ } else if (PDFDictionaryType.Page.elementName().equals(localName)) {
+ PDFPageExtension page = new PDFPageExtension();
+ String pageNumbers = attributes.getValue(PDFPageElement.ATT_PAGE_NUMBERS);
+ if (pageNumbers != null) {
+ page.setProperty(PDFPageExtension.PROPERTY_PAGE_NUMBERS, pageNumbers);
+ }
+ collections.push(page);
+ } else if (PDFObjectType.hasValueOfElementName(localName)) {
+ PDFCollectionEntryExtension entry;
+ if (PDFObjectType.Reference.elementName().equals(localName)) {
+ entry = new PDFReferenceExtension();
+ } else {
+ entry = new PDFCollectionEntryExtension(PDFObjectType.valueOfElementName(localName));
}
- dictionaries.push(dictionary);
- } else if (PDFDictionaryEntryType.hasValueOfElementName(localName)) {
- PDFDictionaryEntryExtension entry = new PDFDictionaryEntryExtension(PDFDictionaryEntryType.valueOfElementName(localName));
- String key = attributes.getValue(PDFDictionaryEntryElement.ATT_KEY);
+ String key = attributes.getValue(PDFCollectionEntryElement.ATT_KEY);
if (key != null) {
entry.setKey(key);
}
- if (!dictionaries.empty()) {
- PDFDictionaryExtension dictionary = dictionaries.peek();
- dictionary.addEntry(entry);
- captureContent = true;
+ if (entry instanceof PDFReferenceExtension) {
+ String refid = attributes.getValue(PDFReferenceElement.ATT_REFID);
+ if (refid != null) {
+ ((PDFReferenceExtension) entry).setReferenceId(refid);
+ }
+ }
+ if (!collections.empty()) {
+ PDFCollectionExtension collection = collections.peek();
+ collection.addEntry(entry);
+ if (!(entry instanceof PDFReferenceExtension)) {
+ captureContent = true;
+ }
}
} else {
throw new SAXException("Unhandled element " + localName + " in namespace: " + uri);
@@ -107,33 +156,48 @@ public class PDFExtensionHandler extends DefaultHandler implements ContentHandle
String name = lastAttributes.getValue("name");
String src = lastAttributes.getValue("src");
String desc = lastAttributes.getValue("description");
+ this.lastAttributes = null;
this.returnedObject = new PDFEmbeddedFileAttachment(name, src, desc);
} else if (PDFDictionaryType.hasValueOfElementName(localName)) {
- if (!dictionaries.empty()) {
- PDFDictionaryExtension dictionary = dictionaries.pop();
- if ((dictionary.getDictionaryType() == PDFDictionaryType.Catalog) || (dictionary.getDictionaryType() == PDFDictionaryType.Page)) {
+ if (!collections.empty() && (collections.peek() instanceof PDFDictionaryExtension)) {
+ PDFDictionaryExtension dictionary = (PDFDictionaryExtension) collections.pop();
+ if (!collections.empty()) {
+ PDFCollectionExtension collectionOuter = collections.peek();
+ collectionOuter.addEntry(dictionary);
+ } else if (dictionary.getDictionaryType() != PDFDictionaryType.Dictionary) {
this.returnedObject = new PDFDictionaryAttachment(dictionary);
- } else if (!dictionaries.empty()) {
- PDFDictionaryExtension dictionaryOuter = dictionaries.peek();
- dictionaryOuter.addEntry(dictionary);
+ } else {
+ throw new SAXException(new IllegalStateException("generic dictionary not permitted at outer level"));
+ }
+ } else {
+ throw new SAXException(new IllegalStateException("collections stack is empty or not a dictionary"));
+ }
+ } else if (PDFObjectType.Array.elementName().equals(localName)) {
+ if (!collections.empty() && (collections.peek() instanceof PDFArrayExtension)) {
+ PDFArrayExtension array = (PDFArrayExtension) collections.pop();
+ if (!collections.empty()) {
+ PDFCollectionExtension collectionOuter = collections.peek();
+ collectionOuter.addEntry(array);
+ } else {
+ throw new SAXException(new IllegalStateException("array not permitted at outer level"));
}
} else {
- throw new SAXException(new IllegalStateException("no active dictionary"));
+ throw new SAXException(new IllegalStateException("collections stack is empty or not an array"));
}
- } else if (PDFDictionaryEntryType.hasValueOfElementName(localName)) {
- if (!dictionaries.empty()) {
- PDFDictionaryExtension dictionary = dictionaries.peek();
- PDFDictionaryEntryExtension entry = dictionary.getLastEntry();
+ } else if (PDFObjectType.hasValueOfElementName(localName)) {
+ if (!collections.empty()) {
+ PDFCollectionExtension collection = collections.peek();
+ PDFCollectionEntryExtension entry = collection.getLastEntry();
if (entry != null) {
if (characters != null) {
entry.setValue(characters.toString());
characters = null;
}
} else {
- throw new SAXException(new IllegalStateException("no active entry"));
+ throw new SAXException(new IllegalStateException("no current entry"));
}
} else {
- throw new SAXException(new IllegalStateException("no active dictionary"));
+ throw new SAXException(new IllegalStateException("entry not permitted at outer level"));
}
}
}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFLayerElement.java b/src/java/org/apache/fop/render/pdf/extensions/PDFLayerElement.java
new file mode 100644
index 000000000..dab0ecf78
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFLayerElement.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.FONode;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Extension element for pdf:layer.
+ */
+public class PDFLayerElement extends PDFDictionaryElement {
+
+ PDFLayerElement(FONode parent) {
+ super(parent, PDFDictionaryType.Layer);
+ }
+
+ @Override
+ public void startOfNode() throws FOPException {
+ super.startOfNode();
+ if (parent.getNameId() != Constants.FO_DECLARATIONS) {
+ invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), "rule.childOfDeclarations");
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFLayerExtension.java b/src/java/org/apache/fop/render/pdf/extensions/PDFLayerExtension.java
new file mode 100644
index 000000000..d6cc27ab8
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFLayerExtension.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+// CSOFF: LineLengthCheck
+
+public class PDFLayerExtension extends PDFDictionaryExtension {
+
+ PDFLayerExtension() {
+ super(PDFDictionaryType.Layer);
+ }
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFNavigatorElement.java b/src/java/org/apache/fop/render/pdf/extensions/PDFNavigatorElement.java
new file mode 100644
index 000000000..5c5b779b5
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFNavigatorElement.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.FONode;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Extension element for pdf:navigator.
+ */
+public class PDFNavigatorElement extends PDFDictionaryElement {
+
+ PDFNavigatorElement(FONode parent) {
+ super(parent, PDFDictionaryType.Navigator);
+ }
+
+ @Override
+ public void startOfNode() throws FOPException {
+ super.startOfNode();
+ if (parent.getNameId() != Constants.FO_DECLARATIONS) {
+ invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), "rule.childOfDeclarations");
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFNavigatorExtension.java b/src/java/org/apache/fop/render/pdf/extensions/PDFNavigatorExtension.java
new file mode 100644
index 000000000..ee9dfa7c8
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFNavigatorExtension.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+// CSOFF: LineLengthCheck
+
+public class PDFNavigatorExtension extends PDFDictionaryExtension {
+
+ PDFNavigatorExtension() {
+ super(PDFDictionaryType.Navigator);
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryEntryExtension.java b/src/java/org/apache/fop/render/pdf/extensions/PDFObjectExtension.java
index 94d6b5dbf..5447d87f2 100644
--- a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryEntryExtension.java
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFObjectExtension.java
@@ -23,34 +23,20 @@ import org.apache.fop.util.XMLUtil;
// CSOFF: LineLengthCheck
-public class PDFDictionaryEntryExtension {
+public class PDFObjectExtension {
- public static final String PROPERTY_KEY = "key";
-
- private PDFDictionaryEntryType type;
- private String key = "";
+ private PDFObjectType type;
private Object value;
- PDFDictionaryEntryExtension() {
- }
-
- PDFDictionaryEntryExtension(PDFDictionaryEntryType type) {
+ PDFObjectExtension(PDFObjectType type) {
this.type = type;
}
- public PDFDictionaryEntryType getType() {
+ public PDFObjectType getType() {
return type;
}
- public String getKey() {
- return key;
- }
-
- public void setKey(String key) {
- this.key = key;
- }
-
- public void setValue(String value) {
+ public void setValue(Object value) {
this.value = value;
}
@@ -63,7 +49,10 @@ public class PDFDictionaryEntryExtension {
* @return entry value
*/
public Boolean getValueAsBoolean() {
- if (value instanceof String) {
+ Object value = getValue();
+ if (value instanceof Boolean) {
+ return (Boolean) value;
+ } else if (value instanceof String) {
return Boolean.valueOf((String)value);
} else {
return false;
@@ -75,9 +64,12 @@ public class PDFDictionaryEntryExtension {
* @return entry value
*/
public Number getValueAsNumber() {
- if (value instanceof String) {
+ Object value = getValue();
+ if (value instanceof Number) {
+ return (Number) value;
+ } else if (value instanceof String) {
double d = Double.parseDouble((String) value);
- if (Math.floor(d) == d) {
+ if (Math.abs(Math.floor(d) - d) < 1E-10) {
return Long.valueOf((long) d);
} else {
return Double.valueOf(d);
@@ -88,10 +80,13 @@ public class PDFDictionaryEntryExtension {
}
public String getValueAsString() {
- if (value instanceof String) {
+ Object value = getValue();
+ if (value == null) {
+ return null;
+ } else if (value instanceof String) {
return (String) value;
} else {
- return "";
+ return value.toString();
}
}
@@ -99,10 +94,6 @@ public class PDFDictionaryEntryExtension {
return XMLUtil.escape(getValueAsString());
}
- public void setValue(Object value) {
- this.value = value;
- }
-
public String getElementName() {
return type.elementName();
}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryEntryType.java b/src/java/org/apache/fop/render/pdf/extensions/PDFObjectType.java
index e4b25819a..c193a3b7b 100644
--- a/src/java/org/apache/fop/render/pdf/extensions/PDFDictionaryEntryType.java
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFObjectType.java
@@ -22,24 +22,27 @@ package org.apache.fop.render.pdf.extensions;
// CSOFF: LineLengthCheck
/**
- * Enumeration type for leaf PDF dictionary entry extension elements.
+ * Enumeration type for leaf PDF object extension types used as singletons,
+ * dictionary entries, or array entries.
*/
-public enum PDFDictionaryEntryType {
- Boolean("boolean"), // boolean valued entry
- Dictionary("dictionary"), // dictionary valued entry
- Name("name"), // name valued entry
- Number("number"), // number valued entry
- String("string"); // string valued entry
+public enum PDFObjectType {
+ Array("array"), // array valued entry
+ Boolean("boolean"), // boolean valued entry
+ Dictionary("dictionary"), // dictionary valued entry
+ Name("name"), // name valued entry
+ Number("number"), // number valued entry
+ Reference("reference"), // indirect object reference entry
+ String("string"); // string valued entry
private String elementName;
- PDFDictionaryEntryType(String elementName) {
+ PDFObjectType(String elementName) {
this.elementName = elementName;
}
public String elementName() {
return elementName;
}
- static PDFDictionaryEntryType valueOfElementName(String elementName) {
- for (PDFDictionaryEntryType type : values()) {
+ static PDFObjectType valueOfElementName(String elementName) {
+ for (PDFObjectType type : values()) {
if (type.elementName.equals(elementName)) {
return type;
}
@@ -48,7 +51,8 @@ public enum PDFDictionaryEntryType {
}
static boolean hasValueOfElementName(String elementName) {
try {
- return valueOfElementName(elementName) != null;
+ valueOfElementName(elementName);
+ return true;
} catch (Exception e) {
return false;
}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFPageElement.java b/src/java/org/apache/fop/render/pdf/extensions/PDFPageElement.java
new file mode 100644
index 000000000..28a966ead
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFPageElement.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.PropertyList;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Extension element for pdf:page.
+ */
+public class PDFPageElement extends PDFDictionaryElement {
+
+ public static final String ATT_PAGE_NUMBERS = PDFDictionaryExtension.PROPERTY_PAGE_NUMBERS;
+
+ /**
+ * Main constructor
+ * @param parent parent FO node
+ */
+ PDFPageElement(FONode parent) {
+ super(parent, PDFDictionaryType.Page);
+ }
+
+ @Override
+ public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList propertyList) throws FOPException {
+ super.processNode(elementName, locator, attlist, propertyList);
+ String pageNumbers = attlist.getValue(ATT_PAGE_NUMBERS);
+ if (pageNumbers != null) {
+ getDictionaryExtension().setProperty(PDFDictionaryExtension.PROPERTY_PAGE_NUMBERS, pageNumbers);
+ }
+ }
+
+ @Override
+ public void startOfNode() throws FOPException {
+ super.startOfNode();
+ if (parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER) {
+ invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), "rule.childOfSPM");
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFPageExtension.java b/src/java/org/apache/fop/render/pdf/extensions/PDFPageExtension.java
new file mode 100644
index 000000000..0726a4e55
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFPageExtension.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+// CSOFF: LineLengthCheck
+
+public class PDFPageExtension extends PDFDictionaryExtension {
+
+ public static final String PROPERTY_PAGE_NUMBERS = "page-numbers";
+
+ PDFPageExtension() {
+ super(PDFDictionaryType.Page);
+ }
+
+ /**
+ * Determine if page dictionary and page number matches.
+ * @param pageNumber page number, where first page number is 1
+ * @return true if this dictionary is a page dictionary and specified page number matches specified page-number property
+ */
+ public boolean matchesPageNumber(int pageNumber) {
+ String pageNumbers = getProperty(PROPERTY_PAGE_NUMBERS);
+ if ((pageNumbers == null) || (pageNumbers.length() == 0)) {
+ return false;
+ } else if (pageNumbers.equals("*")) {
+ return true;
+ } else {
+ for (String interval : pageNumbers.split("\\s*,\\s*")) {
+ String[] components = interval.split("\\s*-\\s*");
+ if (components.length < 1) {
+ continue;
+ } else {
+ try {
+ int start = Integer.parseInt(components[0]);
+ int end = 0;
+ if (components.length > 1) {
+ if (!components[1].equals("LAST")) {
+ end = Integer.parseInt(components[1]);
+ }
+ }
+ if ((end == 0) && (pageNumber == start)) {
+ return true;
+ } else if ((end > start) && (pageNumber >= start) && (pageNumber < end)) {
+ return true;
+ } else {
+ continue;
+ }
+ } catch (NumberFormatException e) {
+ continue;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFReferenceElement.java b/src/java/org/apache/fop/render/pdf/extensions/PDFReferenceElement.java
new file mode 100644
index 000000000..37aeeb890
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFReferenceElement.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.PropertyList;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Extension element for pdf:reference.
+ */
+public class PDFReferenceElement extends PDFCollectionEntryElement {
+
+ public static final String ATT_REFID = PDFReferenceExtension.PROPERTY_REFID;
+
+ /**
+ * Main constructor
+ * @param parent parent FO node
+ */
+ PDFReferenceElement(FONode parent) {
+ super(parent, PDFObjectType.Reference);
+ }
+
+ @Override
+ public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList propertyList) throws FOPException {
+ super.processNode(elementName, locator, attlist, propertyList);
+ String refid = attlist.getValue(ATT_REFID);
+ if (refid == null) {
+ missingPropertyError(ATT_REFID);
+ } else if (refid.length() == 0) {
+ invalidPropertyValueError(ATT_REFID, refid, null);
+ } else {
+ ((PDFReferenceExtension) getExtension()).setReferenceId(refid);
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFReferenceExtension.java b/src/java/org/apache/fop/render/pdf/extensions/PDFReferenceExtension.java
new file mode 100644
index 000000000..09621c01c
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFReferenceExtension.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf.extensions;
+
+// CSOFF: LineLengthCheck
+
+public class PDFReferenceExtension extends PDFCollectionEntryExtension {
+
+ public static final String PROPERTY_REFID = "refid";
+
+ private String refid;
+ private Object resolvedReference;
+
+ PDFReferenceExtension() {
+ super(PDFObjectType.Reference);
+ }
+
+ @Override
+ public void setValue(Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue() {
+ return this;
+ }
+
+ public String getReferenceId() {
+ return refid;
+ }
+
+ public void setReferenceId(String refid) {
+ this.refid = refid;
+ }
+
+ public Object getResolvedReference() {
+ return resolvedReference;
+ }
+
+ public void setResolvedReference(Object resolvedReference) {
+ this.resolvedReference = resolvedReference;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSPainter.java b/src/java/org/apache/fop/render/ps/PSPainter.java
index 3d1887f2d..547662c47 100644
--- a/src/java/org/apache/fop/render/ps/PSPainter.java
+++ b/src/java/org/apache/fop/render/ps/PSPainter.java
@@ -116,7 +116,7 @@ public class PSPainter extends AbstractIFPainter<PSDocumentHandler> {
}
/** {@inheritDoc} */
- public void startGroup(AffineTransform transform) throws IFException {
+ public void startGroup(AffineTransform transform, String layer) throws IFException {
try {
PSGenerator generator = getGenerator();
saveGraphicsState();
diff --git a/src/java/org/apache/fop/render/txt/TXTRenderer.java b/src/java/org/apache/fop/render/txt/TXTRenderer.java
index bf4a46e19..5b398711f 100644
--- a/src/java/org/apache/fop/render/txt/TXTRenderer.java
+++ b/src/java/org/apache/fop/render/txt/TXTRenderer.java
@@ -583,6 +583,14 @@ public class TXTRenderer extends AbstractPathOrientedRenderer {
}
/** {@inheritDoc} */
+ protected void startLayer(String layer) {
+ }
+
+ /** {@inheritDoc} */
+ protected void endLayer() {
+ }
+
+ /** {@inheritDoc} */
protected void concatenateTransformationMatrix(AffineTransform at) {
currentState.push(new CTM(UnitConv.ptToMpt(at)));
}
diff --git a/src/java/org/apache/fop/render/xml/XMLRenderer.java b/src/java/org/apache/fop/render/xml/XMLRenderer.java
index 2212da434..68e2e3c62 100644
--- a/src/java/org/apache/fop/render/xml/XMLRenderer.java
+++ b/src/java/org/apache/fop/render/xml/XMLRenderer.java
@@ -545,6 +545,16 @@ public class XMLRenderer extends AbstractXMLRenderer {
//only necessary for graphical output
}
+ /** {@inheritDoc} */
+ protected void startLayer(String layer) {
+ //only necessary for graphical output
+ }
+
+ /** {@inheritDoc} */
+ protected void endLayer() {
+ //only necessary for graphical output
+ }
+
/**
* {@inheritDoc}
* org.apache.fop.area.inline.InlineArea)
diff --git a/src/java/org/apache/fop/util/AbstractPaintingState.java b/src/java/org/apache/fop/util/AbstractPaintingState.java
index 96c3633e6..3e966d202 100644
--- a/src/java/org/apache/fop/util/AbstractPaintingState.java
+++ b/src/java/org/apache/fop/util/AbstractPaintingState.java
@@ -24,7 +24,6 @@ import java.awt.geom.AffineTransform;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Iterator;
import java.util.List;
import java.util.Stack;
@@ -36,10 +35,10 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
private static final long serialVersionUID = 5998356138437094188L;
/** current state data */
- private AbstractData data = null;
+ private AbstractData data;
/** the state stack */
- private StateStack/*<AbstractData>*/ stateStack = new StateStack/*<AbstractData>*/();
+ private StateStack<AbstractData> stateStack = new StateStack<AbstractData>();
/**
* Instantiates a new state data object
@@ -216,8 +215,7 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
*/
public AffineTransform getTransform() {
AffineTransform at = new AffineTransform();
- for (Iterator iter = stateStack.iterator(); iter.hasNext();) {
- AbstractData data = (AbstractData)iter.next();
+ for (AbstractData data : stateStack) {
AffineTransform stackTrans = data.getTransform();
at.concatenate(stackTrans);
}
@@ -249,7 +247,7 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
if (stateStack.isEmpty()) {
return null;
} else {
- AbstractData baseData = (AbstractData)stateStack.get(0);
+ AbstractData baseData = stateStack.get(0);
return (AffineTransform) baseData.getTransform().clone();
}
}
@@ -297,7 +295,7 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
*/
public AbstractData restore() {
if (!stateStack.isEmpty()) {
- setData((AbstractData)stateStack.pop());
+ setData(stateStack.pop());
return this.data;
} else {
return null;
@@ -310,12 +308,11 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
*
* @param dataList a state data list
*/
- public void saveAll(List/*<AbstractData>*/ dataList) {
- Iterator it = dataList.iterator();
- while (it.hasNext()) {
+ public void saveAll(List<AbstractData> dataList) {
+ for (AbstractData data : dataList) {
// save current data on stack
save();
- setData((AbstractData)it.next());
+ setData(data);
}
}
@@ -325,8 +322,8 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
*
* @return a list of state data popped from the stack
*/
- public List/*<AbstractData>*/ restoreAll() {
- List/*<AbstractData>*/ dataList = new java.util.ArrayList/*<AbstractData>*/();
+ public List<AbstractData> restoreAll() {
+ List<AbstractData> dataList = new java.util.ArrayList<AbstractData>();
AbstractData data;
while (true) {
data = getData();
@@ -361,7 +358,7 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
*
* @return the state stack
*/
- protected Stack/*<AbstractData>*/ getStateStack() {
+ protected Stack<AbstractData> getStateStack() {
return this.stateStack;
}
@@ -369,8 +366,10 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
@Override
public Object clone() {
AbstractPaintingState state = instantiate();
- state.stateStack = new StateStack(this.stateStack);
- state.data = (AbstractData)this.data.clone();
+ state.stateStack = new StateStack<AbstractData>(this.stateStack);
+ if (this.data != null) {
+ state.data = (AbstractData)this.data.clone();
+ }
return state;
}
@@ -385,7 +384,7 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
/**
* A stack implementation which holds state objects
*/
- public class StateStack extends java.util.Stack {
+ public class StateStack<E> extends java.util.Stack<E> {
private static final long serialVersionUID = 4897178211223823041L;
@@ -393,7 +392,6 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
* Default constructor
*/
public StateStack() {
- super();
}
/**
@@ -419,25 +417,28 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
private static final long serialVersionUID = 5208418041189828624L;
/** The current color */
- protected Color color = null;
+ protected Color color;
/** The current background color */
- protected Color backColor = null;
+ protected Color backColor;
/** The current font name */
- protected String fontName = null;
+ protected String fontName;
/** The current font size */
- protected int fontSize = 0;
+ protected int fontSize;
/** The current line width */
- protected float lineWidth = 0;
+ protected float lineWidth;
/** The dash array for the current basic stroke (line type) */
- protected float[] dashArray = null;
+ protected float[] dashArray;
/** The current transform */
- protected AffineTransform transform = null;
+ protected AffineTransform transform;
+
+ /** The current (optional content group) layer. */
+ protected String layer;
/**
* Returns a newly create data object
@@ -485,6 +486,18 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
transform = new AffineTransform();
}
+ public void setLayer(String layer) {
+ if (layer != null) {
+ this.layer = layer;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public String getLayer() {
+ return this.layer;
+ }
+
/**
* Returns the derived rotation from the current transform
*
@@ -523,6 +536,7 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
this.transform = new AffineTransform();
}
data.transform = new AffineTransform(this.transform);
+ data.layer = this.layer;
return data;
}
@@ -535,7 +549,8 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable {
+ ", fontSize=" + fontSize
+ ", lineWidth=" + lineWidth
+ ", dashArray=" + dashArray
- + ", transform=" + transform;
+ + ", transform=" + transform
+ + ", layer=" + layer;
}
}
}
diff --git a/src/sandbox/org/apache/fop/render/svg/SVGPainter.java b/src/sandbox/org/apache/fop/render/svg/SVGPainter.java
index ebd143a69..fb7ce2677 100644
--- a/src/sandbox/org/apache/fop/render/svg/SVGPainter.java
+++ b/src/sandbox/org/apache/fop/render/svg/SVGPainter.java
@@ -146,16 +146,16 @@ public class SVGPainter extends AbstractIFPainter<AbstractSVGDocumentHandler>
}
/** {@inheritDoc} */
- public void startGroup(AffineTransform[] transforms) throws IFException {
- startGroup(SVGUtil.formatAffineTransformsMptToPt(transforms));
+ public void startGroup(AffineTransform[] transforms, String layer) throws IFException {
+ startGroup(SVGUtil.formatAffineTransformsMptToPt(transforms), layer);
}
/** {@inheritDoc} */
- public void startGroup(AffineTransform transform) throws IFException {
- startGroup(SVGUtil.formatAffineTransformMptToPt(transform));
+ public void startGroup(AffineTransform transform, String layer) throws IFException {
+ startGroup(SVGUtil.formatAffineTransformMptToPt(transform), layer);
}
- private void startGroup(String transform) throws IFException {
+ private void startGroup(String transform, String layer) throws IFException {
try {
AttributesImpl atts = new AttributesImpl();
if (transform != null && transform.length() > 0) {
diff --git a/status.xml b/status.xml
index 352f487c3..91b9c78d3 100644
--- a/status.xml
+++ b/status.xml
@@ -58,7 +58,10 @@
users, i.e. when the behaviour changes and could affect the layout of existing
documents. Example: the fix of marks layering will be such a case when it's done.
-->
- <release version="FOP Trunk" date="TBD">
+ <release version="FOP Trunk" date="01 November 2013">
+ <action context="Renderers" dev="GA" type="add" fixes-bug="FOP-2301">
+ Enable support for PDF sub-page transitions.
+ </action>
<action context="Layout" dev="GA" type="fix" fixes-bug="FOP-2310">
Fix misplaced table cell border in WM RTL context.
</action>
diff --git a/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java b/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java
index d156b908c..ee3498a03 100644
--- a/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java
+++ b/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java
@@ -35,6 +35,8 @@ import static org.junit.Assert.assertTrue;
*/
public class EmbedFontInfoTestCase {
+ public EmbedFontInfoTestCase() {}
+
private EmbedFontInfo sut;
private final URI metricsURI = URI.create("test/resources/fonts/ttf/glb12.ttf.xml");
diff --git a/test/java/org/apache/fop/fonts/FontsTestSuite.java b/test/java/org/apache/fop/fonts/FontsTestSuite.java
index ad48c46c4..1baba49df 100644
--- a/test/java/org/apache/fop/fonts/FontsTestSuite.java
+++ b/test/java/org/apache/fop/fonts/FontsTestSuite.java
@@ -29,7 +29,7 @@ import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({
FontManagerConfiguratorTestCase.class,
- EmbedFontInfo.class,
+ EmbedFontInfoTestCase.class,
FontEventProcessingTestCase.class,
FontManagerConfiguratorTestCase.class
})
diff --git a/test/java/org/apache/fop/pdf/PDFDestsTestCase.java b/test/java/org/apache/fop/pdf/PDFDestsTestCase.java
index 08d841ede..49c1e6dab 100644
--- a/test/java/org/apache/fop/pdf/PDFDestsTestCase.java
+++ b/test/java/org/apache/fop/pdf/PDFDestsTestCase.java
@@ -32,7 +32,7 @@ import java.util.List;
public class PDFDestsTestCase extends PDFObjectTestCase {
private PDFDests dests = new PDFDests();
- private String expectedString = "<< /Names [(number) 10 (name) /Test#20name] >>\n";
+ private String expectedString = "<< /Names [(number) 10 (name) /Test#20name] >>";
@Before
public void setUp() {
diff --git a/test/java/org/apache/fop/pdf/PDFDictionaryTestCase.java b/test/java/org/apache/fop/pdf/PDFDictionaryTestCase.java
index 3f84fac2e..00224e93e 100644
--- a/test/java/org/apache/fop/pdf/PDFDictionaryTestCase.java
+++ b/test/java/org/apache/fop/pdf/PDFDictionaryTestCase.java
@@ -47,7 +47,7 @@ public class PDFDictionaryTestCase extends PDFObjectTestCase {
+ " /array [1 (two) 20]\n"
+ " /number 20\n"
+ " /null null\n"
- + ">>\n";
+ + ">>";
@Before
public void setUp() {
diff --git a/test/java/org/apache/fop/pdf/PDFPageLabelsTestCase.java b/test/java/org/apache/fop/pdf/PDFPageLabelsTestCase.java
index e982bf246..a8be7ee74 100644
--- a/test/java/org/apache/fop/pdf/PDFPageLabelsTestCase.java
+++ b/test/java/org/apache/fop/pdf/PDFPageLabelsTestCase.java
@@ -37,11 +37,11 @@ public class PDFPageLabelsTestCase {
int index = 0;
StringBuilder expected = new StringBuilder();
expected.append("[");
- expected.append(index + " << /S /r >>\n");
+ expected.append(index + " << /S /r >>");
pageLabels.addPageLabel(index++, "i");
pageLabels.addPageLabel(index++, "ii");
pageLabels.addPageLabel(index++, "iii");
- expected.append(" " + index + " << /S /D >>\n");
+ expected.append(" " + index + " << /S /D >>");
pageLabels.addPageLabel(index++, "1");
pageLabels.addPageLabel(index++, "2");
pageLabels.addPageLabel(index++, "3");
@@ -52,33 +52,33 @@ public class PDFPageLabelsTestCase {
pageLabels.addPageLabel(index++, "8");
pageLabels.addPageLabel(index++, "9");
pageLabels.addPageLabel(index++, "10");
- expected.append(" " + index + " << /S /A >>\n");
+ expected.append(" " + index + " << /S /A >>");
pageLabels.addPageLabel(index++, "A");
pageLabels.addPageLabel(index++, "B");
- expected.append(" " + index + " << /S /R /St 100 >>\n");
+ expected.append(" " + index + " << /S /R /St 100 >>");
pageLabels.addPageLabel(index++, "C");
- expected.append(" " + index + " << /S /R /St 500 >>\n");
+ expected.append(" " + index + " << /S /R /St 500 >>");
pageLabels.addPageLabel(index++, "D");
- expected.append(" " + index + " << /S /A /St 5 >>\n");
+ expected.append(" " + index + " << /S /A /St 5 >>");
pageLabels.addPageLabel(index++, "E");
pageLabels.addPageLabel(index++, "F");
pageLabels.addPageLabel(index++, "G");
- expected.append(" " + index + " << /P (aa) >>\n");
+ expected.append(" " + index + " << /P (aa) >>");
pageLabels.addPageLabel(index++, "aa");
- expected.append(" " + index + " << /P (ab) >>\n");
+ expected.append(" " + index + " << /P (ab) >>");
pageLabels.addPageLabel(index++, "ab");
- expected.append(" " + index + " << /P (ac) >>\n");
+ expected.append(" " + index + " << /P (ac) >>");
pageLabels.addPageLabel(index++, "ac");
- expected.append(" " + index + " << /S /a >>\n");
+ expected.append(" " + index + " << /S /a >>");
pageLabels.addPageLabel(index++, "a");
pageLabels.addPageLabel(index++, "b");
- expected.append(" " + index + " << /S /R /St 2 >>\n");
+ expected.append(" " + index + " << /S /R /St 2 >>");
pageLabels.addPageLabel(index++, "II");
- expected.append(" " + index + " << /S /R /St 12 >>\n");
+ expected.append(" " + index + " << /S /R /St 12 >>");
pageLabels.addPageLabel(index++, "XII");
- expected.append(" " + index + " <<\n /P (00)\n /S /D\n /St 9\n>>\n");
+ expected.append(" " + index + " <<\n /P (00)\n /S /D\n /St 9\n>>");
pageLabels.addPageLabel(index++, "009");
- expected.append(" " + index + " <<\n /P (0)\n /S /D\n /St 10\n>>\n");
+ expected.append(" " + index + " <<\n /P (0)\n /S /D\n /St 10\n>>");
pageLabels.addPageLabel(index++, "010");
pageLabels.addPageLabel(index++, "011");
expected.append("]");
diff --git a/test/java/org/apache/fop/pdf/PDFStreamTestCase.java b/test/java/org/apache/fop/pdf/PDFStreamTestCase.java
index 93dcea511..20e38a600 100644
--- a/test/java/org/apache/fop/pdf/PDFStreamTestCase.java
+++ b/test/java/org/apache/fop/pdf/PDFStreamTestCase.java
@@ -118,7 +118,7 @@ public class PDFStreamTestCase {
private byte[] createSampleStreamData() throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
- stream.write("stream\n".getBytes("US-ASCII"));
+ stream.write("\nstream\n".getBytes("US-ASCII"));
stream.write(createSampleData());
stream.write("\nendstream".getBytes("US-ASCII"));
return stream.toByteArray();
diff --git a/test/java/org/apache/fop/pdf/xref/CrossReferenceTableTestCase.java b/test/java/org/apache/fop/pdf/xref/CrossReferenceTableTestCase.java
index ceff96a91..12f6e3c1b 100644
--- a/test/java/org/apache/fop/pdf/xref/CrossReferenceTableTestCase.java
+++ b/test/java/org/apache/fop/pdf/xref/CrossReferenceTableTestCase.java
@@ -73,7 +73,7 @@ public class CrossReferenceTableTestCase extends CrossReferenceObjectTest {
.append(" /Info 2 0 R\n")
.append(" /ID [<0123456789ABCDEF> <0123456789ABCDEF>]\n")
.append(" /Size ").append(Integer.toString(offsets.size() + 1)).append('\n')
- .append(">>\n");
+ .append(">>");
return getBytes(expected);
}
diff --git a/test/java/org/apache/fop/render/intermediate/AbstractIFPainterTestCase.java b/test/java/org/apache/fop/render/intermediate/AbstractIFPainterTestCase.java
index 592335648..be8b5d718 100644
--- a/test/java/org/apache/fop/render/intermediate/AbstractIFPainterTestCase.java
+++ b/test/java/org/apache/fop/render/intermediate/AbstractIFPainterTestCase.java
@@ -51,7 +51,7 @@ public class AbstractIFPainterTestCase {
public void endViewport() throws IFException {
}
- public void startGroup(AffineTransform transform) throws IFException {
+ public void startGroup(AffineTransform transform, String layer) throws IFException {
}
public void endGroup() throws IFException {
diff --git a/test/layoutengine/standard-testcases/pdf-dictionary-extension_2.xml b/test/layoutengine/standard-testcases/pdf-dictionary-extension_2.xml
new file mode 100644
index 000000000..486b8601c
--- /dev/null
+++ b/test/layoutengine/standard-testcases/pdf-dictionary-extension_2.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- $Id$ -->
+<testcase>
+ <info>
+ <p>
+ This test checks the PDF dictionary extensions related to optional content groups (layers).
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:pdf="http://xmlgraphics.apache.org/fop/extensions/pdf"
+ xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="simple">
+ <fo:region-body/>
+ <fo:region-before/>
+ <fo:region-after/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <fo:declarations>
+ <!-- Optional Content Group Layers -->
+ <pdf:layer id="layer1">
+ <pdf:string key="Name">Bullet 1</pdf:string>
+ </pdf:layer>
+ <pdf:layer id="layer2">
+ <pdf:string key="Name">Bullet 2</pdf:string>
+ </pdf:layer>
+ <!-- Document Catalog's Optional Content (Layers) Directory and Default State -->
+ <pdf:catalog>
+ <pdf:dictionary key="OCProperties">
+ <!-- Directory of OCGs (layers) in Document -->
+ <pdf:array key="OCGs">
+ <pdf:reference refid="layer1"/>
+ <pdf:reference refid="layer2"/>
+ </pdf:array>
+ <!-- Default State for OCGs -->
+ <pdf:dictionary key="D">
+ <pdf:string key="Name">Default</pdf:string>
+ <pdf:name key="BaseState">OFF</pdf:name>
+ </pdf:dictionary>
+ </pdf:dictionary>
+ </pdf:catalog>
+ </fo:declarations>
+ <fo:page-sequence master-reference="simple">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block fox:layer="layer1">
+ <fo:block>BULLET 1A</fo:block>
+ <fo:block>BULLET 1B</fo:block>
+ </fo:block>
+ <fo:block fox:layer="layer2">BULLET 2</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks xmlns:pdf="apache:fop:extensions:pdf">
+ <eval expected="layer1" xpath="//flow/block[1]/@layer"/>
+ <eval expected="layer2" xpath="//flow/block[2]/@layer"/>
+ </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/pdf-dictionary-extension_3.xml b/test/layoutengine/standard-testcases/pdf-dictionary-extension_3.xml
new file mode 100644
index 000000000..ee5061497
--- /dev/null
+++ b/test/layoutengine/standard-testcases/pdf-dictionary-extension_3.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- $Id$ -->
+<testcase>
+ <info>
+ <p>
+ This test checks the PDF dictionary extensions related to optional content groups (layers),
+ including navigator and action dictionaries.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:pdf="http://xmlgraphics.apache.org/fop/extensions/pdf"
+ xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="simple">
+ <fo:region-body/>
+ <fo:region-before/>
+ <fo:region-after/>
+ <!-- Initial Layers Navigation Node for Page 1 -->
+ <pdf:page page-numbers="1">
+ <pdf:reference key="PresSteps" refid="navInitial"/>
+ </pdf:page>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <fo:declarations>
+ <!-- Optional Content Group Layers -->
+ <pdf:layer id="layer1">
+ <pdf:string key="Name">Bullet 1</pdf:string>
+ </pdf:layer>
+ <pdf:layer id="layer2">
+ <pdf:string key="Name">Bullet 2</pdf:string>
+ </pdf:layer>
+ <!-- Navigator Actions -->
+ <pdf:action type="SetOCGState" id="setStateInitial">
+ <pdf:array key="State">
+ <pdf:name>OFF</pdf:name>
+ <pdf:reference refid="layer1"/>
+ <pdf:reference refid="layer2"/>
+ </pdf:array>
+ </pdf:action>
+ <pdf:action type="SetOCGState" id="setStateBullet1">
+ <pdf:array key="State">
+ <pdf:name>OFF</pdf:name>
+ <pdf:reference refid="layer2"/>
+ <pdf:name>ON</pdf:name>
+ <pdf:reference refid="layer1"/>
+ </pdf:array>
+ </pdf:action>
+ <pdf:action type="SetOCGState" id="setStateBullet2">
+ <pdf:array key="State">
+ <pdf:name>OFF</pdf:name>
+ <pdf:reference refid="layer1"/>
+ <pdf:name>ON</pdf:name>
+ <pdf:reference refid="layer2"/>
+ </pdf:array>
+ </pdf:action>
+ <!-- Navigators -->
+ <pdf:navigator id="navInitial">
+ <pdf:reference key="NA" refid="setStateBullet1"/>
+ <pdf:reference key="Next" refid="navBullet1"/>
+ <pdf:reference key="PA" refid="setStateInitial"/>
+ <pdf:reference key="Prev" refid="navInitial"/>
+ </pdf:navigator>
+ <pdf:navigator id="navBullet1">
+ <pdf:reference key="NA" refid="setStateBullet2"/>
+ <pdf:reference key="Next" refid="navBullet2"/>
+ <pdf:reference key="PA" refid="setStateInitial"/>
+ <pdf:reference key="Prev" refid="navInitial"/>
+ </pdf:navigator>
+ <pdf:navigator id="navBullet2">
+ <pdf:reference key="NA" refid="setStateBullet2"/>
+ <pdf:reference key="Next" refid="navBullet2"/>
+ <pdf:reference key="PA" refid="setStateBullet1"/>
+ <pdf:reference key="Prev" refid="navBullet1"/>
+ </pdf:navigator>
+ <!-- Document Catalog's Optional Content (Layers) Directory and Default State -->
+ <pdf:catalog>
+ <pdf:dictionary key="OCProperties">
+ <!-- Directory of OCGs (layers) in Document -->
+ <pdf:array key="OCGs">
+ <pdf:reference refid="layer1"/>
+ <pdf:reference refid="layer2"/>
+ </pdf:array>
+ <!-- Default State for OCGs -->
+ <pdf:dictionary key="D">
+ <pdf:string key="Name">Default</pdf:string>
+ <pdf:name key="BaseState">OFF</pdf:name>
+ </pdf:dictionary>
+ </pdf:dictionary>
+ </pdf:catalog>
+ </fo:declarations>
+ <fo:page-sequence master-reference="simple">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block fox:layer="layer1">
+ <fo:block>BULLET 1A</fo:block>
+ <fo:block>BULLET 1B</fo:block>
+ </fo:block>
+ <fo:block fox:layer="layer2">BULLET 2</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks xmlns:pdf="apache:fop:extensions:pdf">
+ <eval expected="layer1" xpath="//flow/block[1]/@layer"/>
+ <eval expected="layer2" xpath="//flow/block[2]/@layer"/>
+ </checks>
+</testcase>