--- src/java/META-INF/services/org.apache.fop.fo.ElementMapping (revision 676141)
+++ src/java/META-INF/services/org.apache.fop.fo.ElementMapping (working copy)
@@ -1,4 +1,5 @@
org.apache.fop.fo.FOElementMapping
+org.apache.fop.fo.extensions.pdf.PDFExtensionElementMapping
org.apache.fop.fo.extensions.svg.SVGElementMapping
org.apache.fop.fo.extensions.svg.BatikExtensionElementMapping
org.apache.fop.fo.extensions.ExtensionElementMapping
--- src/java/org/apache/fop/fo/extensions/pdf/AbstractPDFExtension.java (revision 0)
+++ src/java/org/apache/fop/fo/extensions/pdf/AbstractPDFExtension.java (revision 0)
@@ -0,0 +1,57 @@
+/*
+ * 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.fo.extensions.pdf;
+
+import org.apache.fop.fo.extensions.ExtensionObj;
+import org.apache.fop.fo.extensions.ExtensionAttachment;
+import org.apache.fop.fo.FONode;
+
+public abstract class AbstractPDFExtension extends ExtensionObj {
+
+ /**
+ * Create a new AbstractPDFExtension that is a child of the given
+ * {@link FONode}
+ *
+ * @param parent the parent {@link FONode}
+ */
+ public AbstractPDFExtension(FONode parent) {
+ super(parent);
+ }
+
+ /** {@inheritDoc} */
+ public ExtensionAttachment getExtensionAttachment() {
+ return new PDFExtensionAttachment(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return {@link PDFExtensionElementMapping#URI}
+ */
+ public String getNamespaceURI() {
+ return PDFExtensionElementMapping.URI;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return {@link PDFExtensionElementMapping#PREFIX}
+ */
+ public String getNormalNamespacePrefix() {
+ return PDFExtensionElementMapping.PREFIX;
+ }
+
+}
+ Id
+ native
--- src/java/org/apache/fop/fo/extensions/pdf/PDFDictionaryExtension.java (revision 0)
+++ src/java/org/apache/fop/fo/extensions/pdf/PDFDictionaryExtension.java (revision 0)
@@ -0,0 +1,127 @@
+/*
+ * 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.fo.extensions.pdf;
+
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.ValidationException;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.extensions.ExtensionObj;
+import org.apache.fop.apps.FOPException;
+import org.apache.xmlgraphics.util.QName;
+import org.xml.sax.Locator;
+import org.xml.sax.Attributes;
+
+import java.nio.CharBuffer;
+import java.util.ListIterator;
+
+/**
+ * Class modelling the pdf:dictionary extension object.
+ *
+ * This extension, in co-operation with {@link PDFEntryExtension} allows
+ * the user to build dictionaries that will be injected into the
+ * PDF document.
+ * If the type is specified as "catalog", the entries/subdictionaries will be added to
+ * the document catalog.
+ */
+public class PDFDictionaryExtension extends AbstractPDFExtension {
+
+ public static final int TYPE_CATALOG = 0;
+ public static final int TYPE_NORMAL = 1;
+
+ static final String[] TYPES = { "catalog", "normal" };
+
+ private int type;
+ private String name;
+
+ /**
+ * Create a new PDFDictionaryExtension instance that is
+ * a child of the given {@link FONode}.
+ *
+ * @param parent the parent {@link FONode}
+ */
+ public PDFDictionaryExtension(FONode parent) {
+ super(parent);
+ }
+
+ private static int getType(String typeString) {
+ for (int i = TYPES.length; --i >= 0;) {
+ if (TYPES[i].equals(typeString)) {
+ return i;
+ }
+ }
+ assert false;
+ return -1;
+ }
+
+ /** {@inheritDoc} */
+ public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList pList) throws FOPException {
+ String dictType = attlist.getValue("type");
+ if (dictType == null || "".equals(dictType)) {
+ //assume "normal" if absent
+ dictType = TYPES[TYPE_NORMAL];
+ }
+ this.type = getType(dictType);
+ this.name = attlist.getValue("name");
+ }
+
+ /** {@inheritDoc} */
+ protected void validateChildNode(Locator loc, String namespaceURI, String localName) throws ValidationException {
+ if (PDFExtensionElementMapping.URI.equals(namespaceURI)) {
+ if ("entry".equals(localName) || "dictionary".equals(localName)) {
+ return; //no problem
+ }
+ }
+ //TODO: Replace by extension-specific event (?)
+ this.invalidChildError(loc, namespaceURI, localName);
+ }
+
+ /**
+ * Return an int
identifying the type of PDF dictionary.
+ *
+ * @return one of {@link #TYPE_CATALOG}, or {@link #TYPE_NORMAL}
+ */
+ public int getType() {
+ return this.type;
+ }
+
+ /**
+ * Return a java.lang.String
naming the type of PDF dictionary.
+ *
+ * @return one of "catalog" or "normal"
+ */
+ public String getTypeName() {
+ return TYPES[this.type];
+ }
+
+ /**
+ * Return the name of this dictionary
+ *
+ * @return the name of the dictionary
+ */
+ public String getDictionaryName() {
+ return this.name;
+ }
+
+ /** {@inheritDoc} */
+ public String getLocalName() {
+ return "dictionary";
+ }
+
+}
--- src/java/org/apache/fop/fo/extensions/pdf/PDFEntryExtension.java (revision 0)
+++ src/java/org/apache/fop/fo/extensions/pdf/PDFEntryExtension.java (revision 0)
@@ -0,0 +1,150 @@
+/*
+ * 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.fo.extensions.pdf;
+
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.ValidationException;
+import org.apache.fop.apps.FOPException;
+import org.xml.sax.Locator;
+import org.xml.sax.Attributes;
+
+import java.nio.CharBuffer;
+
+/**
+ * Class modelling the pdf:entry
extension object.
+ * This extension can be used to create PDF entries in a
+ * pdf:dictionary
object.
+ * The object is mapped virtually one-on-one to PDF.
+ *
+ * <pdf:entry name="PageMode">FullScreen</pdf:entry>
+ *
+ * will result in "/PageMode FullScreen" being added as an entry
+ * to the dictionary.
+ */
+public class PDFEntryExtension extends AbstractPDFExtension {
+
+ public static final int TYPE_NUMBER = 0;
+ public static final int TYPE_BOOLEAN = 1;
+ public static final int TYPE_NAME = 2;
+ public static final int TYPE_ARRAY = 3;
+
+ static final String[] TYPES = {
+ "number", "boolean", "name", "array" };
+
+ private String entryName;
+ private int entryType;
+ private CharBuffer entryValue;
+
+ /**
+ * Construct a new PDFEntryExtension instance that is a child
+ * of the given {@link org.apache.fop.fo.FONode}
+ *
+ * @param parent the parent {@link org.apache.fop.fo.FONode}
+ */
+ public PDFEntryExtension(FONode parent) {
+ super(parent);
+ }
+
+ private static int getType(String typeName) {
+ for (int i = TYPES.length; --i >= 0;) {
+ if (TYPES[i].equals(typeName)) {
+ return i;
+ }
+ }
+ assert false;
+ return -1;
+ }
+
+ /** {@inheritDoc} */
+ protected void validateChildNode(Locator loc, String namespaceURI, String localName) throws ValidationException {
+ //TODO: Replace by extension-specific event (?)
+ this.invalidChildError(loc, namespaceURI, localName);
+ }
+
+ /** {@inheritDoc} */
+ public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList pList) throws FOPException {
+ this.entryName = attlist.getValue("name");
+ if (this.entryName == null || "".equals(this.entryName)) {
+ this.missingPropertyError("name");
+ }
+
+ this.entryType = getType(attlist.getValue("type"));
+
+ super.processNode(elementName, locator, attlist, pList);
+ }
+
+ /** {@inheritDoc} */
+ protected void addCharacters(char[] data, int start, int length, PropertyList pList, Locator locator) throws FOPException {
+ if (this.entryValue == null) {
+ this.entryValue = CharBuffer.allocate(length);
+ } else {
+ CharBuffer newExpr = CharBuffer.allocate(
+ this.entryValue.length() + length);
+ this.entryValue.position(0);
+ newExpr.put(this.entryValue);
+ this.entryValue = newExpr;
+ }
+ this.entryValue.put(data, start, length);
+ }
+
+ /**
+ * Return the name of the PDF entry.
+ *
+ * @return the name of the entry
+ */
+ public String getEntryName() {
+ return this.entryName;
+ }
+
+ /**
+ * Return the value of the PDF entry (= the #PCDATA
+ * content of the node in the source document)
+ *
+ * @return the value of the entry
+ */
+ public String getEntryValue() {
+ this.entryValue.rewind();
+ return this.entryValue.toString();
+ }
+
+ /**
+ * Return the type of this entry.
+ *
+ * @return one of {@link #TYPE_NUMBER}, {@link #TYPE_BOOLEAN},
+ * {@link #TYPE_NAME}, or {@link#TYPE_ARRAY}
+ */
+ public int getEntryType() {
+ return this.entryType;
+ }
+
+ /**
+ * Return the type of this entry as a String.
+ *
+ * @return the type name of this entry
+ */
+ public String getEntryTypeName() {
+ return TYPES[this.entryType];
+ }
+
+ /** {@inheritDoc} */
+ public String getLocalName() {
+ return "entry";
+ }
+
+}
+ Id
+ native
--- src/java/org/apache/fop/fo/extensions/pdf/PDFExtensionAttachment.java (revision 0)
+++ src/java/org/apache/fop/fo/extensions/pdf/PDFExtensionAttachment.java (revision 0)
@@ -0,0 +1,47 @@
+/*
+ * 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.fo.extensions.pdf;
+
+import org.apache.fop.fo.extensions.ExtensionAttachment;
+
+import java.io.Serializable;
+
+public class PDFExtensionAttachment implements ExtensionAttachment, Serializable {
+
+ private AbstractPDFExtension ext;
+
+ public PDFExtensionAttachment() {
+ //nop
+ }
+
+ public PDFExtensionAttachment(AbstractPDFExtension ext) {
+ this.ext = ext;
+ }
+
+ public AbstractPDFExtension getExtensionObject() {
+ return this.ext;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return {@link PDFExtensionElementMapping#URI}
+ */
+ public String getCategory() {
+ return PDFExtensionElementMapping.URI;
+ }
+}
+ Id
+ native
--- src/java/org/apache/fop/fo/extensions/pdf/PDFExtensionElementMapping.java (revision 0)
+++ src/java/org/apache/fop/fo/extensions/pdf/PDFExtensionElementMapping.java (revision 0)
@@ -0,0 +1,70 @@
+/*
+ * 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.fo.extensions.pdf;
+
+import org.apache.fop.fo.extensions.ExtensionElementMapping;
+import org.apache.fop.fo.ElementMapping;
+import org.apache.fop.fo.FONode;
+
+import java.util.HashMap;
+
+public class PDFExtensionElementMapping extends ExtensionElementMapping {
+
+ /** The FOP PDF extension namespace URI */
+ public static final String URI = "http://xmlgraphics.apache.org/fop/extensions/pdf";
+
+ /** The standard namespace prefix */
+ public static final String PREFIX = "pdf";
+ /**
+ * Constructor.
+ */
+ public PDFExtensionElementMapping() {
+ namespaceURI = URI;
+ }
+
+ /**
+ * Initialize the data structures.
+ */
+ protected void initialize() {
+ if (foObjs == null) {
+ foObjs = new HashMap();
+ foObjs.put("dictionary", new PDFDictionaryExtensionMaker());
+ foObjs.put("entry", new PDFEntryExtensionMaker());
+ }
+ }
+
+ /** Inner class for making instances of {@link PDFDictionaryExtension} */
+ static class PDFDictionaryExtensionMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new PDFDictionaryExtension(parent);
+ }
+ }
+
+ /** Inner class for making instances of {@link PDFEntryExtension} */
+ static class PDFEntryExtensionMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new PDFEntryExtension(parent);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public String getStandardPrefix() {
+ return PREFIX;
+ }
+
+}
+ Id
+ native
--- src/java/org/apache/fop/render/pdf/PDFRenderer.java (revision 676141)
+++ src/java/org/apache/fop/render/pdf/PDFRenderer.java (working copy)
@@ -76,6 +76,11 @@
import org.apache.fop.events.ResourceEventProducer;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.extensions.ExtensionAttachment;
+import org.apache.fop.fo.extensions.pdf.AbstractPDFExtension;
+import org.apache.fop.fo.extensions.pdf.PDFDictionaryExtension;
+import org.apache.fop.fo.extensions.pdf.PDFEntryExtension;
+import org.apache.fop.fo.extensions.pdf.PDFExtensionAttachment;
+import org.apache.fop.fo.extensions.pdf.PDFExtensionElementMapping;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.LazyFont;
@@ -98,6 +103,7 @@
import org.apache.fop.pdf.PDFInfo;
import org.apache.fop.pdf.PDFLink;
import org.apache.fop.pdf.PDFMetadata;
+import org.apache.fop.pdf.PDFName;
import org.apache.fop.pdf.PDFNumber;
import org.apache.fop.pdf.PDFNumsArray;
import org.apache.fop.pdf.PDFOutline;
@@ -548,6 +554,9 @@
if (XMPMetadata.CATEGORY.equals(attachment.getCategory())) {
renderXMPMetadata((XMPMetadata)attachment);
}
+ if (PDFExtensionElementMapping.URI.equals(attachment.getCategory())) {
+ renderPDFExtension((PDFExtensionAttachment)attachment);
+ }
}
}
@@ -621,6 +630,70 @@
pdfDoc.getRoot().setMetadata(pdfMetadata);
}
+ private void renderPDFEntryExtension(PDFEntryExtension entry, PDFDictionary dict) {
+
+ switch (entry.getEntryType()) {
+ case PDFEntryExtension.TYPE_BOOLEAN:
+ dict.put(
+ entry.getEntryName(),
+ ("true".equals(entry.getEntryValue())));
+ break;
+ case PDFEntryExtension.TYPE_NAME:
+ dict.put(
+ entry.getEntryName(),
+ new PDFName(entry.getEntryValue()));
+ break;
+ case PDFEntryExtension.TYPE_NUMBER:
+ case PDFEntryExtension.TYPE_ARRAY:
+ //TODO: Implement
+ default:
+ assert false;
+ }
+
+ }
+
+ private void renderPDFDictionaryExtension(PDFDictionaryExtension dict, PDFDictionary parent) {
+ AbstractPDFExtension entry;
+ PDFExtensionAttachment att;
+ PDFDictionary pdfDict = null;
+
+ if (parent == null) {
+ //add entries to document catalog
+ pdfDict = pdfDoc.getRoot();
+ } else {
+ pdfDict = new PDFDictionary(parent);
+ }
+
+ for (Iterator entryIter = dict.getExtensionAttachments().iterator(); entryIter.hasNext();) {
+ att = (PDFExtensionAttachment)entryIter.next();
+ entry = att.getExtensionObject();
+ if (entry instanceof PDFEntryExtension) {
+ //atomic entry
+ renderPDFEntryExtension((PDFEntryExtension)entry, pdfDict);
+ } else if (entry instanceof PDFDictionaryExtension) {
+ //subdictionary
+ renderPDFDictionaryExtension((PDFDictionaryExtension)entry, pdfDict);
+ }
+ }
+
+ if (parent != null) {
+ parent.put(dict.getDictionaryName(), pdfDict);
+ }
+ }
+
+ private void renderPDFExtension(PDFExtensionAttachment ext) {
+ AbstractPDFExtension extNode = ext.getExtensionObject();
+ if (extNode instanceof PDFDictionaryExtension) {
+ PDFDictionaryExtension dict = (PDFDictionaryExtension)extNode;
+ if (dict.getType() == PDFDictionaryExtension.TYPE_CATALOG) {
+ //add the entries/subdictionaries to pdfDoc.getRoot()
+ renderPDFDictionaryExtension(dict, null);
+ } else {
+ //TODO??
+ }
+ }
+ }
+
/** {@inheritDoc} */
public Graphics2DAdapter getGraphics2DAdapter() {
return new PDFGraphics2DAdapter(this);
--- src/java/org/apache/fop/pdf/PDFDictionary.java (revision 676141)
+++ src/java/org/apache/fop/pdf/PDFDictionary.java (working copy)
@@ -88,6 +88,18 @@
}
this.entries.put(name, new Integer(value));
}
+
+ /**
+ * Puts a new name/value pair.
+ * @param name the name
+ * @param value the value
+ */
+ public void put(String name, boolean value) {
+ if (!entries.containsKey(name)) {
+ this.order.add(name);
+ }
+ this.entries.put(name, value ? Boolean.TRUE : Boolean.FALSE);
+ }
/**
* Returns the value given a name.