</Or>
<Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED"/>
</Match>
+ <Match>
+ <Class name="org.apache.fop.render.pdf.extensions.PDFExtensionHandlerFactory"/>
+ <Method name="getSupportedNamespaces"/>
+ <Bug pattern="EI_EXPOSE_REP"/>
+ </Match>
+ <Match>
+ <Class name="org.apache.fop.render.pdf.extensions.PDFDictionaryEntryExtension"/>
+ <Method name="getValueAsNumber"/>
+ <Bug pattern="FE_FLOATING_POINT_EQUALITY"/>
+ </Match>
+ <Match>
+ <Class name="org.apache.fop.render.pdf.extensions.PDFDictionaryType"/>
+ <Method name="hasValueOfElementName"/>
+ <Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/>
+ </Match>
+ <Match>
+ <Class name="org.apache.fop.render.pdf.extensions.PDFDictionaryEntryType"/>
+ <Method name="hasValueOfElementName"/>
+ <Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/>
+ </Match>
</FindBugsFilter>
org.apache.fop.render.afp.extensions.AFPExtensionHandlerFactory
+org.apache.fop.render.pdf.extensions.PDFExtensionHandlerFactory
org.apache.fop.render.ps.extensions.PSExtensionHandlerFactory
org.apache.fop.fo.extensions.xmp.XMPContentHandlerFactory
+++ /dev/null
-/*
- * 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;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.Locator;
-
-import org.apache.fop.apps.FOPException;
-import org.apache.fop.fo.FOEventHandler;
-import org.apache.fop.fo.FONode;
-import org.apache.fop.fo.FObj;
-import org.apache.fop.fo.PropertyList;
-
-/**
- * Base class for pdf bookmark extension objects.
- */
-public abstract class ExtensionObj extends FObj {
-
- /**
- * Create a new extension object.
- *
- * @param parent the parent formatting object
- */
- public ExtensionObj(FONode parent) {
- super(parent);
- }
-
- /**
- * {@inheritDoc}
- */
- public void processNode(String elementName, Locator locator,
- Attributes attlist, PropertyList pList)
- throws FOPException {
- }
-
- /**
- * Create a default property list for this element.
- * @param parent the parent property list
- * @param foEventHandler an event handler
- * @return property list
- * @throws FOPException in case of exception
- */
- protected PropertyList createPropertyList(PropertyList parent,
- FOEventHandler foEventHandler) throws FOPException {
- return null;
- }
-}
-
private Number number;
+ public PDFNumber() {
+ this.number = Integer.valueOf(0);
+ }
+
+ public PDFNumber(Number number) {
+ this.number = number;
+ }
+
/**
* Returns the number.
* @return the number
if (result instanceof SAXResult) {
SAXResult saxResult = (SAXResult)result;
this.handler = new GenerationHelperContentHandler(
- saxResult.getHandler(), getMainNamespace());
+ saxResult.getHandler(), getMainNamespace(), getContext());
} else {
this.handler = new GenerationHelperContentHandler(
- createContentHandler(result), getMainNamespace());
+ createContentHandler(result), getMainNamespace(), getContext());
}
}
private boolean hyphenated;
+ private int pageIndex = -1;
+
/**
* Main constructor.
* @param ua the user agent
return hyphenated;
}
+ /**
+ * Record current page index.
+ * @param pageIndex a zero based page index or -1 (no page)
+ */
+ public void setPageIndex(int pageIndex) {
+ this.pageIndex = pageIndex;
+ }
+
+ /**
+ * Obtain current page index.
+ * @return a zero based page index or -1 (no page)
+ */
+ public int getPageIndex() {
+ return this.pageIndex;
+ }
+
}
Dimension dim = new Dimension(viewArea.width, viewArea.height);
establishForeignAttributes(page.getForeignAttributes());
+ documentHandler.getContext().setPageIndex(page.getPageIndex());
documentHandler.startPage(page.getPageIndex(), page.getPageNumberString(),
page.getSimplePageMasterName(), dim);
resetForeignAttributes();
establishForeignAttributes(page.getForeignAttributes());
documentHandler.endPage();
+ documentHandler.getContext().setPageIndex(-1);
resetForeignAttributes();
} catch (IFException e) {
handleIFException(e);
addAttribute(atts, "width", Integer.toString(size.width));
addAttribute(atts, "height", Integer.toString(size.height));
addForeignAttributes(atts);
+ getContext().setPageIndex(index);
handler.startElement(EL_PAGE, atts);
} catch (SAXException e) {
throw new IFException("SAX error in startPage()", e);
public void endPage() throws IFException {
try {
handler.endElement(EL_PAGE);
+ getContext().setPageIndex(-1);
} catch (SAXException e) {
throw new IFException("SAX error in endPage()", e);
}
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFPainter;
import org.apache.fop.render.pdf.PDFRendererConfig.PDFRendererConfigParser;
-import org.apache.fop.render.pdf.extensions.PDFEmbeddedFileExtensionAttachment;
+import org.apache.fop.render.pdf.extensions.PDFDictionaryAttachment;
+import org.apache.fop.render.pdf.extensions.PDFEmbeddedFileAttachment;
/**
* {@link org.apache.fop.render.intermediate.IFDocumentHandler} implementation that produces PDF.
} else if (extension instanceof Metadata) {
XMPMetadata wrapper = new XMPMetadata(((Metadata) extension));
pdfUtil.renderXMPMetadata(wrapper);
- } else if (extension instanceof PDFEmbeddedFileExtensionAttachment) {
- PDFEmbeddedFileExtensionAttachment embeddedFile
- = (PDFEmbeddedFileExtensionAttachment)extension;
+ } else if (extension instanceof PDFEmbeddedFileAttachment) {
+ PDFEmbeddedFileAttachment embeddedFile
+ = (PDFEmbeddedFileAttachment)extension;
try {
pdfUtil.addEmbeddedFile(embeddedFile);
} catch (IOException ioe) {
throw new IFException("Error adding embedded file: " + embeddedFile.getSrc(), ioe);
}
- } else {
+ } else if (extension instanceof PDFDictionaryAttachment) {
+ PDFDictionaryAttachment dictionaryExtension = (PDFDictionaryAttachment) extension;
+ pdfUtil.renderDictionaryExtension(dictionaryExtension, currentPage);
+ } else if (extension != null) {
log.debug("Don't know how to handle extension object. Ignoring: "
+ extension + " (" + extension.getClass().getName() + ")");
+ } else {
+ log.debug("Ignoring null extension object.");
}
}
import org.apache.fop.pdf.PDFICCStream;
import org.apache.fop.pdf.PDFInfo;
import org.apache.fop.pdf.PDFMetadata;
+import org.apache.fop.pdf.PDFName;
import org.apache.fop.pdf.PDFNames;
+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.PDFText;
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.PDFEmbeddedFileExtensionAttachment;
+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 static org.apache.fop.render.pdf.PDFEncryptionOption.ENCRYPTION_PARAMS;
import static org.apache.fop.render.pdf.PDFEncryptionOption.NO_ACCESSCONTENT;
}
}
+ public void renderDictionaryExtension(PDFDictionaryAttachment attachment, PDFPage currentPage) {
+ PDFDictionaryExtension extension = attachment.getExtension();
+ if (extension.getDictionaryType() == PDFDictionaryType.Catalog) {
+ augmentDictionary(pdfDoc.getRoot(), extension);
+ } else if (extension.getDictionaryType() == PDFDictionaryType.Page) {
+ if (extension.matchesPageNumber(currentPage.getPageIndex() + 1)) {
+ augmentDictionary(currentPage, extension);
+ }
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ private PDFDictionary augmentDictionary(PDFDictionary dictionary, PDFDictionaryExtension extension) {
+ for (PDFDictionaryEntryExtension entry : extension.getEntries()) {
+ if (entry instanceof PDFDictionaryExtension) {
+ dictionary.put(entry.getKey(), augmentDictionary(new PDFDictionary(dictionary), (PDFDictionaryExtension) entry));
+ } else {
+ augmentDictionary(dictionary, entry);
+ }
+ }
+ return dictionary;
+ }
+
+ private void augmentDictionary(PDFDictionary dictionary, PDFDictionaryEntryExtension entry) {
+ PDFDictionaryEntryType type = entry.getType();
+ String key = entry.getKey();
+ if (type == PDFDictionaryEntryType.Boolean) {
+ dictionary.put(key, entry.getValueAsBoolean());
+ } else if (type == PDFDictionaryEntryType.Name) {
+ dictionary.put(key, new PDFName(entry.getValueAsString()));
+ } else if (type == PDFDictionaryEntryType.Number) {
+ dictionary.put(key, new PDFNumber(entry.getValueAsNumber()));
+ } else if (type == PDFDictionaryEntryType.String) {
+ dictionary.put(key, entry.getValueAsString());
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
public PDFDocument setupPDFDocument(OutputStream out) throws IOException {
if (this.pdfDoc != null) {
throw new IllegalStateException("PDFDocument already set up");
* @param embeddedFile the object representing the embedded file to be added
* @throws IOException if an I/O error occurs
*/
- public void addEmbeddedFile(PDFEmbeddedFileExtensionAttachment embeddedFile)
+ public void addEmbeddedFile(PDFEmbeddedFileAttachment embeddedFile)
throws IOException {
this.pdfDoc.getProfile().verifyEmbeddedFilesAllowed();
PDFNames names = this.pdfDoc.getRoot().getNames();
--- /dev/null
+/*
+ * 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.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);
+ }
+}
+
package org.apache.fop.render.pdf.extensions;
-// FOP
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.extensions.ExtensionAttachment;
+// CSOFF: LineLengthCheck
+
/**
* Base class for the PDF-specific extension elements.
*/
* Instantiates extension attachment object.
* @return extension attachment
*/
- protected abstract ExtensionAttachment instantiateExtensionAttachment();
+ protected ExtensionAttachment instantiateExtensionAttachment() {
+ return null;
+ }
}
--- /dev/null
+/*
+ * 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.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import org.apache.fop.render.intermediate.IFContext;
+import org.apache.fop.util.GenerationHelperContentHandler;
+
+// CSOFF: LineLengthCheck
+
+public class PDFDictionaryAttachment extends PDFExtensionAttachment {
+
+ private static final long serialVersionUID = -5576832955238384505L;
+
+ private PDFDictionaryExtension extension;
+
+ public PDFDictionaryAttachment(PDFDictionaryExtension extension) {
+ this.extension = extension;
+ }
+
+ public PDFDictionaryExtension getExtension() {
+ return extension;
+ }
+
+ @Override
+ public void toSAX(ContentHandler handler) throws SAXException {
+ PDFDictionaryType dictionaryType = extension.getDictionaryType();
+ int pageNumber = 0;
+ if (dictionaryType == PDFDictionaryType.Page) {
+ 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)) {
+ pageNumber = pageIndex + 1;
+ } else {
+ pageNumber = -1;
+ }
+ }
+ }
+ }
+ if (pageNumber >= 0) {
+ toSAX(handler, extension);
+ }
+ }
+
+ private void toSAX(ContentHandler handler, PDFDictionaryExtension dictionary) throws SAXException {
+ AttributesImpl attributes = new AttributesImpl();
+ String ln = dictionary.getElementName();
+ String qn = PREFIX + ":" + ln;
+ attributes = extractIFAttributes(attributes, dictionary);
+ handler.startElement(CATEGORY, ln, qn, attributes);
+ for (PDFDictionaryEntryExtension entry : dictionary.getEntries()) {
+ toSAX(handler, entry);
+ }
+ handler.endElement(CATEGORY, ln, qn);
+ }
+
+ private void toSAX(ContentHandler handler, PDFDictionaryEntryExtension entry) throws SAXException {
+ if (entry instanceof PDFDictionaryExtension) {
+ toSAX(handler, (PDFDictionaryExtension) 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);
+ }
+ handler.endElement(CATEGORY, ln, qn);
+ }
+ }
+
+ private static AttributesImpl extractIFAttributes(AttributesImpl attributes, PDFDictionaryExtension dictionary) {
+ PDFDictionaryType type = dictionary.getDictionaryType();
+ if (type == PDFDictionaryType.Catalog) {
+ // no specific attriburtes
+ } else if (type == PDFDictionaryType.Page) {
+ String pageNumbersName = PDFDictionaryExtension.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 key = dictionary.getKey();
+ if (key != null) {
+ attributes.addAttribute(null, keyName, keyName, "CDATA", key);
+ }
+ }
+ return attributes;
+ }
+
+ private static AttributesImpl extractIFAttributes(AttributesImpl attributes, PDFDictionaryEntryExtension entry) {
+ String keyName = PDFDictionaryEntryExtension.PROPERTY_KEY;
+ String key = entry.getKey();
+ if (key != null) {
+ attributes.addAttribute(null, keyName, keyName, "CDATA", key);
+ }
+ return attributes;
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+import org.apache.fop.fo.extensions.ExtensionAttachment;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Extension element for dictionaries: pdf:{catalog,page,dictionary}. The specific type
+ * of dictionary is established at construction type.
+ */
+public class PDFDictionaryElement extends AbstractPDFDictionaryElement {
+
+ public static final String ATT_PAGE_NUMBERS = PDFDictionaryExtension.PROPERTY_PAGE_NUMBERS;
+
+ private PDFDictionaryExtension extension;
+
+ /**
+ * Main constructor
+ * @param parent parent FO node
+ */
+ PDFDictionaryElement(FONode parent, PDFDictionaryType type) {
+ super(parent);
+ this.extension = new PDFDictionaryExtension(type);
+ }
+
+ public PDFDictionaryExtension getExtension() {
+ return extension;
+ }
+
+ @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);
+ }
+ } else if (extension.getDictionaryType() == PDFDictionaryType.Dictionary) {
+ String key = attlist.getValue(ATT_KEY);
+ if (key == null) {
+ missingPropertyError(ATT_KEY);
+ } else if (key.isEmpty()) {
+ invalidPropertyValueError(ATT_KEY, key, null);
+ } else {
+ extension.setKey(key);
+ }
+ }
+ }
+
+ @Override
+ 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");
+ }
+ } else if (localName.equals("page")) {
+ if (parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER) {
+ invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), "rule.childOfSPM");
+ }
+ } else if (localName.equals("dictionary")) {
+ if (!PDFDictionaryType.hasValueOfElementName(parent.getLocalName())) {
+ invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), null);
+ }
+ } else {
+ throw new IllegalStateException("unknown name: " + localName);
+ }
+ }
+
+ @Override
+ protected void addChildNode(FONode child) throws FOPException {
+ if (child instanceof PDFDictionaryElement) {
+ PDFDictionaryExtension extension = ((PDFDictionaryElement) child).getExtension();
+ if (extension.getDictionaryType() == PDFDictionaryType.Dictionary) {
+ this.extension.addEntry(extension);
+ }
+ } else if (child instanceof PDFDictionaryEntryElement) {
+ PDFDictionaryEntryExtension extension = ((PDFDictionaryEntryElement) child).getExtension();
+ this.extension.addEntry(extension);
+ }
+ }
+
+ @Override
+ public void endOfNode() throws FOPException {
+ super.endOfNode();
+ }
+
+ @Override
+ public String getLocalName() {
+ return extension.getDictionaryType().elementName();
+ }
+
+ @Override
+ protected ExtensionAttachment instantiateExtensionAttachment() {
+ return new PDFDictionaryAttachment(extension);
+ }
+
+}
--- /dev/null
+/*
+ * 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.isEmpty()) {
+ 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.isEmpty()) {
+ 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();
+ }
+}
--- /dev/null
+/*
+ * 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.util.XMLUtil;
+
+// CSOFF: LineLengthCheck
+
+public class PDFDictionaryEntryExtension {
+
+ public static final String PROPERTY_KEY = "key";
+
+ private PDFDictionaryEntryType type;
+ private String key = "";
+ private Object value;
+
+ PDFDictionaryEntryExtension() {
+ }
+
+ PDFDictionaryEntryExtension(PDFDictionaryEntryType type) {
+ this.type = type;
+ }
+
+ public PDFDictionaryEntryType getType() {
+ return type;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ /**
+ * Obtain entry value as Boolean.
+ * @return entry value
+ */
+ public Boolean getValueAsBoolean() {
+ if (value instanceof String) {
+ return Boolean.valueOf((String)value);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Obtain entry value as Number.
+ * @return entry value
+ */
+ public Number getValueAsNumber() {
+ if (value instanceof String) {
+ double d = Double.parseDouble((String) value);
+ if (Math.floor(d) == d) {
+ return Long.valueOf((long) d);
+ } else {
+ return Double.valueOf(d);
+ }
+ } else {
+ return Integer.valueOf(0);
+ }
+ }
+
+ public String getValueAsString() {
+ if (value instanceof String) {
+ return (String) value;
+ } else {
+ return "";
+ }
+ }
+
+ public String getValueAsXMLEscapedString() {
+ return XMLUtil.escape(getValueAsString());
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+ public String getElementName() {
+ return type.elementName();
+ }
+
+}
--- /dev/null
+/*
+ * 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
+
+/**
+ * Enumeration type for leaf PDF dictionary entry extension elements.
+ */
+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
+
+ private String elementName;
+ PDFDictionaryEntryType(String elementName) {
+ this.elementName = elementName;
+ }
+ public String elementName() {
+ return elementName;
+ }
+ static PDFDictionaryEntryType valueOfElementName(String elementName) {
+ for (PDFDictionaryEntryType type : values()) {
+ if (type.elementName.equals(elementName)) {
+ return type;
+ }
+ }
+ throw new IllegalArgumentException();
+ }
+ static boolean hasValueOfElementName(String elementName) {
+ try {
+ return valueOfElementName(elementName) != null;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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 PDFDictionaryExtension extends PDFDictionaryEntryExtension {
+
+ 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;
+
+ PDFDictionaryExtension() {
+ }
+
+ PDFDictionaryExtension(PDFDictionaryType dictionaryType) {
+ super(PDFDictionaryEntryType.Dictionary);
+ this.dictionaryType = dictionaryType;
+ this.properties = new java.util.HashMap<String, String>();
+ this.entries = new java.util.ArrayList<PDFDictionaryEntryExtension>();
+ }
+
+ public PDFDictionaryType getDictionaryType() {
+ return dictionaryType;
+ }
+
+ public void setProperty(String name, String value) {
+ properties.put(name, value);
+ }
+
+ public String getProperty(String name) {
+ return properties.get(name);
+ }
+
+ public void addEntry(PDFDictionaryEntryExtension entry) {
+ entries.add(entry);
+ }
+
+ public List<PDFDictionaryEntryExtension> getEntries() {
+ return entries;
+ }
+
+ public PDFDictionaryEntryExtension getLastEntry() {
+ if (entries.size() > 0) {
+ return entries.get(entries.size() - 1);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * 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.isEmpty()) {
+ 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;
+ }
+
+ @Override
+ public String getElementName() {
+ return dictionaryType.elementName();
+ }
+
+}
--- /dev/null
+/*
+ * 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
+
+/**
+ * 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
+
+ private String elementName;
+ PDFDictionaryType(String elementName) {
+ this.elementName = elementName;
+ }
+ public String elementName() {
+ return elementName;
+ }
+ static PDFDictionaryType valueOfElementName(String elementName) {
+ for (PDFDictionaryType type : values()) {
+ if (type.elementName.equals(elementName)) {
+ return type;
+ }
+ }
+ throw new IllegalArgumentException();
+ }
+ static boolean hasValueOfElementName(String elementName) {
+ try {
+ return valueOfElementName(elementName) != null;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+}
import org.apache.fop.fo.ElementMapping;
import org.apache.fop.fo.FONode;
+// CSOFF: LineLengthCheck
+
/**
* This class provides the element mapping for the PDF-specific extensions.
*/
protected void initialize() {
if (foObjs == null) {
foObjs = new java.util.HashMap<String, Maker>();
- foObjs.put(PDFEmbeddedFileElement.ELEMENT, new PDFEmbeddedFileMaker());
+ // 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));
+ }
+ }
}
}
- static class PDFEmbeddedFileMaker extends ElementMapping.Maker {
+ static class PDFEmbeddedFileElementMaker extends ElementMapping.Maker {
public FONode make(FONode parent) {
return new PDFEmbeddedFileElement(parent);
}
}
+
+ static class PDFDictionaryElementMaker extends ElementMapping.Maker {
+ private PDFDictionaryType dictionaryType;
+ PDFDictionaryElementMaker(PDFDictionaryType dictionaryType) {
+ this.dictionaryType = dictionaryType;
+ }
+ public FONode make(FONode parent) {
+ return new PDFDictionaryElement(parent, dictionaryType);
+ }
+ }
+
+ static class PDFDictionaryEntryElementMaker extends ElementMapping.Maker {
+ private PDFDictionaryEntryType entryType;
+ PDFDictionaryEntryElementMaker(PDFDictionaryEntryType entryType) {
+ this.entryType = entryType;
+ }
+ public FONode make(FONode parent) {
+ return new PDFDictionaryEntryElement(parent, entryType);
+ }
+ }
}
--- /dev/null
+/*
+ * 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.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * This is the pass-through value object for the PDF extension.
+ */
+public class PDFEmbeddedFileAttachment extends PDFExtensionAttachment {
+
+ private static final long serialVersionUID = -1L;
+
+ /** element name */
+ protected static final String ELEMENT = "embedded-file";
+
+ /** name of file to be embedded */
+ private static final String ATT_NAME = "filename";
+
+ /** source of file to be embedded (URI) */
+ private static final String ATT_SRC = "src";
+
+ /** a description of the file to be embedded */
+ private static final String ATT_DESC = "desc";
+
+ /** filename attribute */
+ private String filename = null;
+
+ /** description attribute (optional) */
+ private String desc = null;
+
+ /** source name attribute */
+ private String src = null;
+
+ /**
+ * No-argument contructor.
+ */
+ public PDFEmbeddedFileAttachment() {
+ super();
+ }
+
+ /**
+ * Default constructor.
+ * @param filename the name of the file
+ * @param src the location of the file
+ * @param desc the description of the file
+ */
+ public PDFEmbeddedFileAttachment(String filename, String src, String desc) {
+ super();
+ this.filename = filename;
+ this.src = src;
+ this.desc = desc;
+ }
+
+ /**
+ * Returns the file name.
+ * @return the file name
+ */
+ public String getFilename() {
+ return filename;
+ }
+
+ /**
+ * Sets the file name.
+ * @param name The file name to set.
+ */
+ public void setFilename(String name) {
+ this.filename = name;
+ }
+
+ /**
+ * Returns the file description.
+ * @return the description
+ */
+ public String getDesc() {
+ return desc;
+ }
+
+ /**
+ * Sets the description of the file.
+ * @param desc the description to set
+ */
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ /**
+ * Returns the source URI of the file.
+ * @return the source URI
+ */
+ public String getSrc() {
+ return src;
+ }
+
+ /**
+ * Sets the source URI of the file.
+ * @param src the source URI
+ */
+ public void setSrc(String src) {
+ this.src = src;
+ }
+
+ /** {@inheritDoc} */
+ public String getCategory() {
+ return CATEGORY;
+ }
+
+ /** {@inheritDoc} */
+ public String toString() {
+ return "PDFEmbeddedFile(name=" + getFilename() + ", " + getSrc() + ")";
+ }
+
+ /**
+ * @return the element name
+ */
+ protected String getElement() {
+ return ELEMENT;
+ }
+
+ /** {@inheritDoc} */
+ public void toSAX(ContentHandler handler) throws SAXException {
+ AttributesImpl atts = new AttributesImpl();
+ if (filename != null && filename.length() > 0) {
+ atts.addAttribute(null, ATT_NAME, ATT_NAME, "CDATA", filename);
+ }
+ if (src != null && src.length() > 0) {
+ atts.addAttribute(null, ATT_SRC, ATT_SRC, "CDATA", src);
+ }
+ if (desc != null && desc.length() > 0) {
+ atts.addAttribute(null, ATT_DESC, ATT_DESC, "CDATA", desc);
+ }
+ String element = getElement();
+ handler.startElement(CATEGORY, element, element, atts);
+ handler.endElement(CATEGORY, element, element);
+ }
+
+}
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;
/**
* Extension element for pdf:embedded-file.
* Main constructor
* @param parent parent FO node
*/
- protected PDFEmbeddedFileElement(FONode parent) {
+ PDFEmbeddedFileElement(FONode parent) {
super(parent);
}
- /** {@inheritDoc} */
+ @Override
public void startOfNode() throws FOPException {
super.startOfNode();
if (parent.getNameId() != Constants.FO_DECLARATIONS) {
}
}
- /** {@inheritDoc} */
+ @Override
public void processNode(String elementName, Locator locator,
Attributes attlist, PropertyList propertyList)
throws FOPException {
- PDFEmbeddedFileExtensionAttachment embeddedFile
- = (PDFEmbeddedFileExtensionAttachment)getExtensionAttachment();
+ PDFEmbeddedFileAttachment embeddedFile
+ = (PDFEmbeddedFileAttachment)getExtensionAttachment();
String desc = attlist.getValue("description");
if (desc != null && desc.length() > 0) {
embeddedFile.setDesc(desc);
embeddedFile.setFilename(filename);
}
- /** {@inheritDoc} */
+ @Override
public String getLocalName() {
return ELEMENT;
}
-
- /** {@inheritDoc} */
- protected ExtensionAttachment instantiateExtensionAttachment() {
- return new PDFEmbeddedFileExtensionAttachment();
- }
}
+++ /dev/null
-/*
- * 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.ContentHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.AttributesImpl;
-
-/**
- * This is the pass-through value object for the PDF extension.
- */
-public class PDFEmbeddedFileExtensionAttachment extends PDFExtensionAttachment {
-
- /** element name */
- protected static final String ELEMENT = "embedded-file";
-
- /** name of file to be embedded */
- private static final String ATT_NAME = "filename";
-
- /** source of file to be embedded (URI) */
- private static final String ATT_SRC = "src";
-
- /** a description of the file to be embedded */
- private static final String ATT_DESC = "desc";
-
- /** filename attribute */
- private String filename = null;
-
- /** description attribute (optional) */
- private String desc = null;
-
- /** source name attribute */
- private String src = null;
-
- /**
- * No-argument contructor.
- */
- public PDFEmbeddedFileExtensionAttachment() {
- super();
- }
-
- /**
- * Default constructor.
- * @param filename the name of the file
- * @param src the location of the file
- * @param desc the description of the file
- */
- public PDFEmbeddedFileExtensionAttachment(String filename, String src, String desc) {
- super();
- this.filename = filename;
- this.src = src;
- this.desc = desc;
- }
-
- /**
- * Returns the file name.
- * @return the file name
- */
- public String getFilename() {
- return filename;
- }
-
- /**
- * Sets the file name.
- * @param name The file name to set.
- */
- public void setFilename(String name) {
- this.filename = name;
- }
-
- /**
- * Returns the file description.
- * @return the description
- */
- public String getDesc() {
- return desc;
- }
-
- /**
- * Sets the description of the file.
- * @param desc the description to set
- */
- public void setDesc(String desc) {
- this.desc = desc;
- }
-
- /**
- * Returns the source URI of the file.
- * @return the source URI
- */
- public String getSrc() {
- return src;
- }
-
- /**
- * Sets the source URI of the file.
- * @param src the source URI
- */
- public void setSrc(String src) {
- this.src = src;
- }
-
- /** {@inheritDoc} */
- public String getCategory() {
- return CATEGORY;
- }
-
- /** {@inheritDoc} */
- public String toString() {
- return "PDFEmbeddedFile(name=" + getFilename() + ", " + getSrc() + ")";
- }
-
- /**
- * @return the element name
- */
- protected String getElement() {
- return ELEMENT;
- }
-
- /** {@inheritDoc} */
- public void toSAX(ContentHandler handler) throws SAXException {
- AttributesImpl atts = new AttributesImpl();
- if (filename != null && filename.length() > 0) {
- atts.addAttribute(null, ATT_NAME, ATT_NAME, "CDATA", filename);
- }
- if (src != null && src.length() > 0) {
- atts.addAttribute(null, ATT_SRC, ATT_SRC, "CDATA", src);
- }
- if (desc != null && desc.length() > 0) {
- atts.addAttribute(null, ATT_DESC, ATT_DESC, "CDATA", desc);
- }
- String element = getElement();
- handler.startElement(CATEGORY, element, element, atts);
- handler.endElement(CATEGORY, element, element);
- }
-
-}
import org.apache.fop.fo.extensions.ExtensionAttachment;
-/**
- * This is the pass-through value object for the PDF extension.
- */
+// CSOFF: LineLengthCheck
+
public abstract class PDFExtensionAttachment implements ExtensionAttachment, XMLizable {
/** The category URI for this extension attachment. */
public static final String CATEGORY = "apache:fop:extensions:pdf";
+ /** The prefix to use with qualified names for this extension attachment. */
+ public static final String PREFIX = "pdf";
+
/**
* Default constructor.
*/
public PDFExtensionAttachment() {
- //nop
- }
-
- /**
- * @return the category URI
- * @see org.apache.fop.fo.extensions.ExtensionAttachment#getCategory()
- */
- public String getCategory() {
- return CATEGORY;
}
- /** @return type name */
- public String getType() {
- String className = getClass().getName();
- return className.substring(className.lastIndexOf('.') + 3);
+ public String getPrefix() {
+ return PREFIX;
}
- /**
- * @return a string representation of this object
- * @see java.lang.Object#toString()
- */
- public String toString() {
- return getType();
+ @Override
+ public String getCategory() {
+ return CATEGORY;
}
-
- /** @return element */
- protected abstract String getElement();
}
package org.apache.fop.render.pdf.extensions;
+import java.util.Stack;
+
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener;
+// CSOFF: LineLengthCheck
+
/**
* ContentHandler (parser) for restoring PDF extension objects from XML.
*/
-public class PDFExtensionHandler extends DefaultHandler
- implements ContentHandlerFactory.ObjectSource {
+public class PDFExtensionHandler extends DefaultHandler implements ContentHandlerFactory.ObjectSource {
/** Logger instance */
protected static final Log log = LogFactory.getLog(PDFExtensionHandler.class);
- private Attributes lastAttributes;
-
private PDFExtensionAttachment returnedObject;
private ObjectBuiltListener listener;
- /** {@inheritDoc} */
- public void startElement(String uri, String localName, String qName, Attributes attributes)
- throws SAXException {
- boolean handled = false;
+ // PDFEmbeddedFileAttachment related state
+ private Attributes lastAttributes;
+
+ // PDFDictionaryAttachment related
+ private Stack<PDFDictionaryExtension> dictionaries = new Stack<PDFDictionaryExtension>();
+ private boolean captureContent;
+ private StringBuffer characters;
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (PDFExtensionAttachment.CATEGORY.equals(uri)) {
- lastAttributes = new AttributesImpl(attributes);
- handled = false;
- if (localName.equals(PDFEmbeddedFileExtensionAttachment.ELEMENT)) {
- //handled in endElement
- handled = true;
+ 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);
+ 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);
+ }
+ }
+ dictionaries.push(dictionary);
+ } else if (PDFDictionaryEntryType.hasValueOfElementName(localName)) {
+ PDFDictionaryEntryExtension entry = new PDFDictionaryEntryExtension(PDFDictionaryEntryType.valueOfElementName(localName));
+ String key = attributes.getValue(PDFDictionaryEntryElement.ATT_KEY);
+ if (key != null) {
+ entry.setKey(key);
+ }
+ if (!dictionaries.empty()) {
+ PDFDictionaryExtension dictionary = dictionaries.peek();
+ dictionary.addEntry(entry);
+ captureContent = true;
+ }
+ } else {
+ throw new SAXException("Unhandled element " + localName + " in namespace: " + uri);
}
+ } else {
+ log.warn("Unhandled element " + localName + " in namespace: " + uri);
}
- if (!handled) {
- if (PDFExtensionAttachment.CATEGORY.equals(uri)) {
- throw new SAXException("Unhandled element " + localName
- + " in namespace: " + uri);
- } else {
- log.warn("Unhandled element " + localName
- + " in namespace: " + uri);
+ }
+
+ @Override
+ public void characters(char[] data, int start, int length) throws SAXException {
+ if (captureContent) {
+ if (characters == null) {
+ characters = new StringBuffer((length < 16) ? 16 : length);
}
+ characters.append(data, start, length);
}
}
- /** {@inheritDoc} */
+ @Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (PDFExtensionAttachment.CATEGORY.equals(uri)) {
- if (PDFEmbeddedFileExtensionAttachment.ELEMENT.equals(localName)) {
+ if (PDFEmbeddedFileAttachment.ELEMENT.equals(localName)) {
String name = lastAttributes.getValue("name");
String src = lastAttributes.getValue("src");
String desc = lastAttributes.getValue("description");
- this.returnedObject = new PDFEmbeddedFileExtensionAttachment(name, src, desc);
+ 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)) {
+ this.returnedObject = new PDFDictionaryAttachment(dictionary);
+ } else if (!dictionaries.empty()) {
+ PDFDictionaryExtension dictionaryOuter = dictionaries.peek();
+ dictionaryOuter.addEntry(dictionary);
+ }
+ } else {
+ throw new SAXException(new IllegalStateException("no active dictionary"));
+ }
+ } else if (PDFDictionaryEntryType.hasValueOfElementName(localName)) {
+ if (!dictionaries.empty()) {
+ PDFDictionaryExtension dictionary = dictionaries.peek();
+ PDFDictionaryEntryExtension entry = dictionary.getLastEntry();
+ if (entry != null) {
+ if (characters != null) {
+ entry.setValue(characters.toString());
+ characters = null;
+ }
+ } else {
+ throw new SAXException(new IllegalStateException("no active entry"));
+ }
+ } else {
+ throw new SAXException(new IllegalStateException("no active dictionary"));
+ }
}
}
+ captureContent = false;
}
- /** {@inheritDoc} */
+ @Override
public void endDocument() throws SAXException {
if (listener != null) {
listener.notifyObjectBuilt(getObject());
}
}
- /** {@inheritDoc} */
+ @Override
public Object getObject() {
return returnedObject;
}
- /** {@inheritDoc} */
+ @Override
public void setObjectBuiltListener(ObjectBuiltListener listener) {
this.listener = listener;
}
--- /dev/null
+/*
+ * 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.ContentHandler;
+
+import org.apache.fop.util.ContentHandlerFactory;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Factory for the ContentHandler that handles serialized PDFExtensionAttachment instances.
+ */
+public class PDFExtensionHandlerFactory implements ContentHandlerFactory {
+
+ private static final String[] NAMESPACES = new String[] {PDFExtensionAttachment.CATEGORY};
+
+ /** {@inheritDoc} */
+ public String[] getSupportedNamespaces() {
+ return NAMESPACES;
+ }
+
+ /** {@inheritDoc} */
+ public ContentHandler createContentHandler() {
+ return new PDFExtensionHandler();
+ }
+}
}
try {
GenerationHelperContentHandler helper = new GenerationHelperContentHandler(
- handler, null);
+ handler, null, null);
FontListSerializer serializer = new FontListSerializer();
serializer.generateSAX(fontFamilies, singleFamily, helper);
} finally {
private static final Attributes EMPTY_ATTS = new AttributesImpl();
private String mainNamespace;
+ private Object contentHandlerContext;
/**
* Main constructor. If the given handler also implements any of the EntityResolver,
* @param handler the SAX content handler to delegate all calls to
* @param mainNamespace the main namespace used for generated XML content when abbreviated
* ContentHandler calls are used.
+ * @param contentHandlerContext additional content handler context state
*/
- public GenerationHelperContentHandler(ContentHandler handler, String mainNamespace) {
+ public GenerationHelperContentHandler(ContentHandler handler, String mainNamespace, Object contentHandlerContext) {
super(handler);
this.mainNamespace = mainNamespace;
+ this.contentHandlerContext = contentHandlerContext;
}
/**
this.mainNamespace = namespaceURI;
}
+ /**
+ * Returns the context object (may be null).
+ * @return the context object
+ */
+ public Object getContentHandlerContext() {
+ return this.contentHandlerContext;
+ }
+
/**
* Convenience method to generate a startElement SAX event.
* @param localName the local name of the element
}
}
+ /**
+ * Escape '<', '>' and '&' using NCRs.
+ * @param unescaped string
+ * @return escaped string
+ */
+ public static String escape(String unescaped) {
+ int needsEscape = 0;
+ for (int i = 0, n = unescaped.length(); i < n; ++i) {
+ char c = unescaped.charAt(i);
+ if ((c == '<') || (c == '>') || (c == '&')) {
+ ++needsEscape;
+ }
+ }
+ if (needsEscape > 0) {
+ StringBuffer sb = new StringBuffer(unescaped.length() + 6 * needsEscape);
+ for (int i = 0, n = unescaped.length(); i < n; ++i) {
+ char c = unescaped.charAt(i);
+ if ((c == '<') || (c == '>') || (c == '&')) {
+ sb.append("&#x");
+ sb.append(Integer.toString(c, 16));
+ sb.append(';');
+ } else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ } else {
+ return unescaped;
+ }
+ }
+
}
}
private GenerationHelperContentHandler decorate(ContentHandler contentHandler) {
- return new GenerationHelperContentHandler(contentHandler, getMainNamespace());
+ return new GenerationHelperContentHandler(contentHandler, getMainNamespace(), getContext());
}
private void closeCurrentStream() {
documents. Example: the fix of marks layering will be such a case when it's done.
-->
<release version="FOP Trunk" date="TBD">
+ <action context="Renderers" dev="GA" type="add" fixes-bug="FOP-2298">
+ Enable support for PDF page transitions.
+ </action>
<action context="Code" dev="PH" type="fix" fixes-bug="FOP-2211" due-to="Alexios Giotis, PH">
Fix and improve the handling of temporary files using the new URI resource resolvers
</action>
--- /dev/null
+<?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.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:pdf="http://xmlgraphics.apache.org/fop/extensions/pdf">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="simple">
+ <fo:region-body/>
+ <fo:region-before/>
+ <fo:region-after/>
+ <pdf:page page-numbers="*">
+ <pdf:number key="Dur">5</pdf:number>
+ </pdf:page>
+ <pdf:page page-numbers="1">
+ <pdf:dictionary key="Trans">
+ <pdf:name key="Type">Trans</pdf:name>
+ <pdf:number key="D">1</pdf:number>
+ <pdf:name key="S">Glitter</pdf:name>
+ <pdf:number key="Di">0</pdf:number>
+ </pdf:dictionary>
+ </pdf:page>
+ <pdf:page page-numbers="2">
+ <pdf:dictionary key="Trans">
+ <pdf:name key="Type">Trans</pdf:name>
+ <pdf:number key="D">1</pdf:number>
+ <pdf:name key="S">Push</pdf:name>
+ <pdf:number key="Di">180</pdf:number>
+ </pdf:dictionary>
+ </pdf:page>
+ <pdf:page page-numbers="3">
+ <pdf:dictionary key="Trans">
+ <pdf:name key="Type">Trans</pdf:name>
+ <pdf:number key="D">1</pdf:number>
+ <pdf:name key="S">Cover</pdf:name>
+ <pdf:number key="Di">270</pdf:number>
+ </pdf:dictionary>
+ </pdf:page>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <fo:declarations>
+ <pdf:catalog>
+ <pdf:name key="Foo">Bar</pdf:name>
+ </pdf:catalog>
+ </fo:declarations>
+ <fo:page-sequence master-reference="simple">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block page-break-before="always">SLIDE 1</fo:block>
+ <fo:block page-break-before="always">SLIDE 2</fo:block>
+ <fo:block page-break-before="always">SLIDE 3</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks xmlns:pdf="apache:fop:extensions:pdf">
+ <eval expected="Foo" xpath="/areaTree/extension-attachments/pdf:catalog/pdf:name/@key"/>
+ <eval expected="Bar" xpath="/areaTree/extension-attachments/pdf:catalog/pdf:name"/>
+ <eval expected="Dur" xpath="/areaTree/pageSequence/pageViewport[@nr=1]/page/extension-attachments/pdf:page/pdf:number/@key"/>
+ <eval expected="5" xpath="/areaTree/pageSequence/pageViewport[@nr=1]/page/extension-attachments/pdf:page/pdf:number"/>
+ </checks>
+ <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate" xmlns:pdf="apache:fop:extensions:pdf">
+ <eval expected="Foo" xpath="/if:document/if:header/pdf:catalog/pdf:name/@key"/>
+ <eval expected="Bar" xpath="/if:document/if:header/pdf:catalog/pdf:name"/>
+ <eval expected="Dur" xpath="//if:page[@name=1]/if:page-header/pdf:page/pdf:number/@key"/>
+ <eval expected="5" xpath="//if:page[@name=1]/if:page-header/pdf:page/pdf:number"/>
+ <eval expected="2" xpath="count(//if:page[@name=1]/if:page-header/pdf:page)"/>
+ <eval expected="2" xpath="count(//if:page[@name=2]/if:page-header/pdf:page)"/>
+ <eval expected="2" xpath="count(//if:page[@name=3]/if:page-header/pdf:page)"/>
+ </if-checks>
+</testcase>