From c1653ad47548cff23a614559544fe0b0aec3522d Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 19 Mar 2012 15:56:19 +0000 Subject: [PATCH] Bugzilla #51385: Added configuration option to set the version of the output PDF document. Patch by Mehdi Houshmand, applied with minor modifications git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1302518 13f79535-47bb-0310-9956-ffa450edef68 --- .../content/xdocs/trunk/configuration.xml | 14 +- src/java/org/apache/fop/pdf/PDFDocument.java | 60 +++++--- .../org/apache/fop/pdf/PDFEmbeddedFile.java | 2 +- src/java/org/apache/fop/pdf/PDFInfo.java | 66 ++++++++ src/java/org/apache/fop/pdf/PDFObject.java | 70 --------- src/java/org/apache/fop/pdf/PDFProfile.java | 4 +- src/java/org/apache/fop/pdf/PDFRoot.java | 15 +- src/java/org/apache/fop/pdf/Version.java | 71 +++++++++ .../org/apache/fop/pdf/VersionController.java | 121 +++++++++++++++ .../render/pdf/PDFConfigurationConstants.java | 2 + .../render/pdf/PDFRendererConfigurator.java | 18 +++ .../fop/render/pdf/PDFRenderingUtil.java | 26 +++- status.xml | 3 + .../fop/pdf/VersionControllerTestCase.java | 143 ++++++++++++++++++ .../org/apache/fop/pdf/VersionTestCase.java | 89 +++++++++++ 15 files changed, 605 insertions(+), 99 deletions(-) create mode 100644 src/java/org/apache/fop/pdf/Version.java create mode 100644 src/java/org/apache/fop/pdf/VersionController.java create mode 100644 test/java/org/apache/fop/pdf/VersionControllerTestCase.java create mode 100644 test/java/org/apache/fop/pdf/VersionTestCase.java diff --git a/src/documentation/content/xdocs/trunk/configuration.xml b/src/documentation/content/xdocs/trunk/configuration.xml index cd1e1dfc3..10769c5ff 100644 --- a/src/documentation/content/xdocs/trunk/configuration.xml +++ b/src/documentation/content/xdocs/trunk/configuration.xml @@ -395,6 +395,18 @@ ]]> +

+ By default FOP produces PDF files of version 1.4, but this can be changed in order to benefit + from features that appeared in newer versions of PDF. At the moment, only a few features from + PDF 1.5 have been implemented, but the configuration element will accept any value between + 1.4 and 1.7. This is the value that will appear in the PDF header, although only features up + to 1.5 will actually be used. + + 1.5 + + ]]> +

@@ -522,4 +534,4 @@ information it finds. Check if FOP finds what you expect.
- \ No newline at end of file + diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java index e9206a1bb..e9886fc37 100644 --- a/src/java/org/apache/fop/pdf/PDFDocument.java +++ b/src/java/org/apache/fop/pdf/PDFDocument.java @@ -65,12 +65,6 @@ public class PDFDocument { private static final Long LOCATION_PLACEHOLDER = new Long(0); - /** Integer constant to represent PDF 1.3 */ - public static final int PDF_VERSION_1_3 = 3; - - /** Integer constant to represent PDF 1.4 */ - public static final int PDF_VERSION_1_4 = 4; - /** the encoding to use when converting strings to PDF commands */ public static final String ENCODING = "ISO-8859-1"; @@ -95,8 +89,8 @@ public class PDFDocument { /** the objects themselves */ private List objects = new LinkedList(); - /** Indicates what PDF version is active */ - private int pdfVersion = PDF_VERSION_1_4; + /** Controls the PDF version of this document */ + private VersionController versionController; /** Indicates which PDF profiles are active (PDF/A, PDF/X etc.) */ private PDFProfile pdfProfile = new PDFProfile(this); @@ -197,6 +191,24 @@ public class PDFDocument { * @param prod the name of the producer of this pdf document */ public PDFDocument(String prod) { + this(prod, null); + versionController = VersionController.getDynamicVersionController(Version.V1_4, this); + } + + /** + * Creates an empty PDF document. + * + * The constructor creates a /Root and /Pages object to + * track the document but does not write these objects until + * the trailer is written. Note that the object ID of the + * pages object is determined now, and the xref table is + * updated later. This allows Pages to refer to their + * Parent before we write it out. + * + * @param prod the name of the producer of this pdf document + * @param versionController the version controller of this PDF document + */ + public PDFDocument(String prod, VersionController versionController) { this.factory = new PDFFactory(this); @@ -211,26 +223,32 @@ public class PDFDocument { // Make the /Info record this.info = getFactory().makeInfo(prod); + + this.versionController = versionController; + } + + /** + * Returns the current PDF version. + * + * @return returns the PDF version + */ + public Version getPDFVersion() { + return versionController.getPDFVersion(); } /** - * @return the integer representing the active PDF version - * (one of PDFDocument.PDF_VERSION_*) + * Sets the PDF version of this document. + * + * @param version the PDF version + * @throws IllegalStateException if the version of this PDF is not allowed to change. */ - public int getPDFVersion() { - return this.pdfVersion; + public void setPDFVersion(Version version) { + versionController.setPDFVersion(version); } - /** @return the String representing the active PDF version */ + /** @return the String representing the current PDF version */ public String getPDFVersionString() { - switch (getPDFVersion()) { - case PDF_VERSION_1_3: - return "1.3"; - case PDF_VERSION_1_4: - return "1.4"; - default: - throw new IllegalStateException("Unsupported PDF version selected"); - } + return versionController.getPDFVersion().toString(); } /** @return the PDF profile currently active. */ diff --git a/src/java/org/apache/fop/pdf/PDFEmbeddedFile.java b/src/java/org/apache/fop/pdf/PDFEmbeddedFile.java index a5b44710a..dc0681405 100644 --- a/src/java/org/apache/fop/pdf/PDFEmbeddedFile.java +++ b/src/java/org/apache/fop/pdf/PDFEmbeddedFile.java @@ -34,7 +34,7 @@ public class PDFEmbeddedFile extends PDFStream { super(); put("Type", new PDFName("EmbeddedFile")); PDFDictionary params = new PDFDictionary(); - params.put("CreationDate", params.formatDateTime(new Date())); + params.put("CreationDate", PDFInfo.formatDateTime(new Date())); put("Params", params); } diff --git a/src/java/org/apache/fop/pdf/PDFInfo.java b/src/java/org/apache/fop/pdf/PDFInfo.java index dabd88685..3f3fb3b46 100644 --- a/src/java/org/apache/fop/pdf/PDFInfo.java +++ b/src/java/org/apache/fop/pdf/PDFInfo.java @@ -21,7 +21,11 @@ package org.apache.fop.pdf; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Calendar; import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; /** * class representing an /Info object @@ -232,5 +236,67 @@ public class PDFInfo extends PDFObject { return bout.toByteArray(); } + /** + * Returns a SimpleDateFormat instance for formatting PDF date-times. + * @return a new SimpleDateFormat instance + */ + protected static SimpleDateFormat getPDFDateFormat() { + SimpleDateFormat df = new SimpleDateFormat("'D:'yyyyMMddHHmmss", Locale.ENGLISH); + df.setTimeZone(TimeZone.getTimeZone("GMT")); + return df; + } + + /** + * Formats a date/time according to the PDF specification (D:YYYYMMDDHHmmSSOHH'mm'). + * @param time date/time value to format + * @param tz the time zone + * @return the requested String representation + */ + protected static String formatDateTime(Date time, TimeZone tz) { + Calendar cal = Calendar.getInstance(tz, Locale.ENGLISH); + cal.setTime(time); + + int offset = cal.get(Calendar.ZONE_OFFSET); + offset += cal.get(Calendar.DST_OFFSET); + + // DateFormat is operating on GMT so adjust for time zone offset + Date dt1 = new Date(time.getTime() + offset); + StringBuffer sb = new StringBuffer(); + sb.append(getPDFDateFormat().format(dt1)); + + offset /= (1000 * 60); // Convert to minutes + + if (offset == 0) { + sb.append('Z'); + } else { + if (offset > 0) { + sb.append('+'); + } else { + sb.append('-'); + } + int offsetHour = Math.abs(offset / 60); + int offsetMinutes = Math.abs(offset % 60); + if (offsetHour < 10) { + sb.append('0'); + } + sb.append(Integer.toString(offsetHour)); + sb.append('\''); + if (offsetMinutes < 10) { + sb.append('0'); + } + sb.append(Integer.toString(offsetMinutes)); + sb.append('\''); + } + return sb.toString(); + } + + /** + * Formats a date/time according to the PDF specification. (D:YYYYMMDDHHmmSSOHH'mm'). + * @param time date/time value to format + * @return the requested String representation + */ + protected static String formatDateTime(Date time) { + return formatDateTime(time, TimeZone.getDefault()); + } } diff --git a/src/java/org/apache/fop/pdf/PDFObject.java b/src/java/org/apache/fop/pdf/PDFObject.java index d74133222..5abb5a142 100644 --- a/src/java/org/apache/fop/pdf/PDFObject.java +++ b/src/java/org/apache/fop/pdf/PDFObject.java @@ -23,11 +23,6 @@ package org.apache.fop.pdf; import java.io.IOException; import java.io.OutputStream; import java.io.Writer; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -339,71 +334,6 @@ public abstract class PDFObject implements PDFWritable { } } - /** - * Returns a SimpleDateFormat instance for formatting PDF date-times. - * @return a new SimpleDateFormat instance - */ - protected SimpleDateFormat getPDFDateFormat() { - SimpleDateFormat df = new SimpleDateFormat("'D:'yyyyMMddHHmmss", Locale.ENGLISH); - df.setTimeZone(TimeZone.getTimeZone("GMT")); - return df; - } - - /** - * Formats a date/time according to the PDF specification - * (D:YYYYMMDDHHmmSSOHH'mm'). - * @param time date/time value to format - * @param tz the time zone - * @return the requested String representation - */ - protected String formatDateTime(Date time, TimeZone tz) { - Calendar cal = Calendar.getInstance(tz, Locale.ENGLISH); - cal.setTime(time); - - int offset = cal.get(Calendar.ZONE_OFFSET); - offset += cal.get(Calendar.DST_OFFSET); - - //DateFormat is operating on GMT so adjust for time zone offset - Date dt1 = new Date(time.getTime() + offset); - StringBuffer sb = new StringBuffer(); - sb.append(getPDFDateFormat().format(dt1)); - - offset /= (1000 * 60); //Convert to minutes - - if (offset == 0) { - sb.append('Z'); - } else { - if (offset > 0) { - sb.append('+'); - } else { - sb.append('-'); - } - int offsetHour = Math.abs(offset / 60); - int offsetMinutes = Math.abs(offset % 60); - if (offsetHour < 10) { - sb.append('0'); - } - sb.append(Integer.toString(offsetHour)); - sb.append('\''); - if (offsetMinutes < 10) { - sb.append('0'); - } - sb.append(Integer.toString(offsetMinutes)); - sb.append('\''); - } - return sb.toString(); - } - - /** - * Formats a date/time according to the PDF specification. - * (D:YYYYMMDDHHmmSSOHH'mm'). - * @param time date/time value to format - * @return the requested String representation - */ - protected String formatDateTime(Date time) { - return formatDateTime(time, TimeZone.getDefault()); - } - /** * Check if the other PDFObject has the same content as the current object. *

diff --git a/src/java/org/apache/fop/pdf/PDFProfile.java b/src/java/org/apache/fop/pdf/PDFProfile.java index b4b43c422..580a9a791 100644 --- a/src/java/org/apache/fop/pdf/PDFProfile.java +++ b/src/java/org/apache/fop/pdf/PDFProfile.java @@ -184,11 +184,11 @@ public class PDFProfile { public void verifyPDFVersion() { final String err = "PDF version must be 1.4 for {0}"; if (getPDFAMode().isPDFA1LevelB() - && getDocument().getPDFVersion() != PDFDocument.PDF_VERSION_1_4) { + && !Version.V1_4.equals(getDocument().getPDFVersion())) { throw new PDFConformanceException(format(err, getPDFAMode())); } if (getPDFXMode() == PDFXMode.PDFX_3_2003 - && getDocument().getPDFVersion() != PDFDocument.PDF_VERSION_1_4) { + && !Version.V1_4.equals(getDocument().getPDFVersion())) { throw new PDFConformanceException(format(err, getPDFXMode())); } } diff --git a/src/java/org/apache/fop/pdf/PDFRoot.java b/src/java/org/apache/fop/pdf/PDFRoot.java index 76f2587de..81b93b159 100644 --- a/src/java/org/apache/fop/pdf/PDFRoot.java +++ b/src/java/org/apache/fop/pdf/PDFRoot.java @@ -205,7 +205,7 @@ public class PDFRoot extends PDFDictionary { * @since PDF 1.4 */ public void setMetadata(PDFMetadata meta) { - if (getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) { + if (getDocumentSafely().getPDFVersion().compareTo(Version.V1_4) >= 0) { put("Metadata", meta.makeReference()); } } @@ -235,7 +235,7 @@ public class PDFRoot extends PDFDictionary { * @since PDF 1.4 */ public void addOutputIntent(PDFOutputIntent outputIntent) { - if (getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) { + if (getDocumentSafely().getPDFVersion().compareTo(Version.V1_4) >= 0) { PDFArray outputIntents = getOutputIntents(); if (outputIntents == null) { outputIntents = new PDFArray(this); @@ -245,6 +245,17 @@ public class PDFRoot extends PDFDictionary { } } + /** + * Sets the "Version" entry. If this version is greater than that specified in the header, this + * version takes precedence. + * + * @param version the PDF document version + * @since PDF 1.4 + */ + void setVersion(Version version) { + put("Version", new PDFName(version.toString())); + } + /** * Returns the language identifier of the document. * @return the language identifier of the document (or null if not set or undefined) diff --git a/src/java/org/apache/fop/pdf/Version.java b/src/java/org/apache/fop/pdf/Version.java new file mode 100644 index 000000000..0df63d312 --- /dev/null +++ b/src/java/org/apache/fop/pdf/Version.java @@ -0,0 +1,71 @@ +/* + * 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; + +/** + * A version of PDF. Values are ordered such that compareTo() gives sensible + * results (e.g., {@code V1_4.compareTo(V1_5) < 0}). + */ +public enum Version { + /** PDF v1 */ + V1_0("1.0"), + /** PDF v1.1 */ + V1_1("1.1"), + /** PDF v1.2 */ + V1_2("1.2"), + /** PDF v1.3 */ + V1_3("1.3"), + /** PDF v1.4 */ + V1_4("1.4"), + /** PDF v1.5 */ + V1_5("1.5"), + /** PDF v1.6 */ + V1_6("1.6"), + /** PDF v1.7 */ + V1_7("1.7"); + + private String version; + + private Version(String version) { + this.version = version; + } + + /** + * Given the PDF version as a String, returns the corresponding enumerated type. The String + * should be in the format "1.x" for PDF v1.x. + * + * @param version a version number + * @return the corresponding Version instance + * @throws IllegalArgumentException if the argument does not correspond to any existing PDF version + */ + public static Version getValueOf(String version) { + for (Version pdfVersion : Version.values()) { + if (pdfVersion.toString().equals(version)) { + return pdfVersion; + } + } + throw new IllegalArgumentException("Invalid PDF version given: " + version); + } + + @Override + public String toString() { + return version; + } +} diff --git a/src/java/org/apache/fop/pdf/VersionController.java b/src/java/org/apache/fop/pdf/VersionController.java new file mode 100644 index 000000000..4a92f4994 --- /dev/null +++ b/src/java/org/apache/fop/pdf/VersionController.java @@ -0,0 +1,121 @@ +/* + * 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; + +/** + * An abstraction that controls the mutability of the PDF version for a document. + */ +public abstract class VersionController { + + private Version version; + + private VersionController(Version version) { + this.version = version; + } + + /** + * Returns the PDF version of the document. + * + * @return the PDF version + */ + public Version getPDFVersion() { + return version; + } + + /** + * Sets the PDF version of the document. + * + * @param version the PDF version + * @throws IllegalStateException if the PDF version is not allowed to change. + */ + public abstract void setPDFVersion(Version version); + + @Override + public String toString() { + return version.toString(); + } + + /** + * A class representing the version of a PDF document. This class doesn't allow the version to + * change once it has been set, it is immutable. Any attempt to set the version will result in + * an exception being thrown. + */ + private static final class FixedVersion extends VersionController { + + private FixedVersion(Version version) { + super(version); + } + + @Override + public void setPDFVersion(Version version) { + throw new IllegalStateException("Cannot change the version of this PDF document."); + } + } + + /** + * A class representing the version of a PDF document. This class allows the version to be + * changed once it has been set (it is mutable) ONLY if the new version is greater. If the PDF + * version is changed after it has been instantiated, the version will be set in the document + * catalog. + */ + private static final class DynamicVersion extends VersionController { + + private PDFDocument doc; + + private DynamicVersion(Version version, PDFDocument doc) { + super(version); + this.doc = doc; + } + + @Override + public void setPDFVersion(Version version) { + if (super.version.compareTo(version) < 0) { + super.version = version; + doc.getRoot().setVersion(version); + } + } + } + + /** + * Returns a controller that disallows subsequent change to the document's version. The minimum + * allowed version is v1.4. + * + * @param version the PDF version (must be >= v1.4) + * @return the fixed PDF version controller + */ + public static VersionController getFixedVersionController(Version version) { + if (version.compareTo(Version.V1_4) < 0) { + throw new IllegalArgumentException("The PDF version cannot be set below version 1.4"); + } + return new FixedVersion(version); + } + + /** + * Returns a controller that allows subsequent changes to the document's version. + * + * @param initialVersion the initial PDF version + * @param doc the document whose version is being set + * @return the dynamic PDF version controller + */ + public static VersionController getDynamicVersionController(Version initialVersion, + PDFDocument doc) { + return new DynamicVersion(initialVersion, doc); + } +} diff --git a/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java b/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java index 994cbc0de..4a8a03b27 100644 --- a/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java +++ b/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java @@ -74,6 +74,8 @@ public interface PDFConfigurationConstants { String PDF_X_MODE = "pdf-x-mode"; /** Rendering Options key for the ICC profile for the output intent. */ String KEY_OUTPUT_PROFILE = "output-profile"; + /** PDF version entry: specify the version of the PDF document created, datatype: String */ + String PDF_VERSION = "version"; /** * Rendering Options key for disabling the sRGB color space (only possible if no PDF/A or * PDF/X profile is active). diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java index dcc7dd32e..df5224c04 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java @@ -157,6 +157,8 @@ public class PDFRendererConfigurator extends PrintRendererConfigurator { pdfUtil.setDisableSRGBColorSpace( disableColorSpaceConfig.getValueAsBoolean(false)); } + + setPDFDocVersion(cfg, pdfUtil); } private int checkEncryptionLength(int encryptionLength) { @@ -175,6 +177,22 @@ public class PDFRendererConfigurator extends PrintRendererConfigurator { return correctEncryptionLength; } + private void setPDFDocVersion(Configuration cfg, PDFRenderingUtil pdfUtil) throws FOPException { + Configuration pdfVersion = cfg.getChild(PDFConfigurationConstants.PDF_VERSION, false); + if (pdfVersion != null) { + String version = pdfVersion.getValue(null); + if (version != null && version.length() != 0) { + try { + pdfUtil.setPDFVersion(version); + } catch (IllegalArgumentException e) { + throw new FOPException(e.getMessage()); + } + } else { + throw new FOPException("The PDF version has not been set."); + } + } + } + /** * Builds a filter map from an Avalon Configuration object. * diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java index c662b0345..83f6ccab6 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java @@ -64,6 +64,8 @@ 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; /** @@ -102,6 +104,8 @@ class PDFRenderingUtil implements PDFConfigurationConstants { /** Optional URI to an output profile to be used. */ protected String outputProfileURI; + protected Version maxPDFVersion; + PDFRenderingUtil(FOUserAgent userAgent) { this.userAgent = userAgent; @@ -375,8 +379,16 @@ class PDFRenderingUtil implements PDFConfigurationConstants { if (this.pdfDoc != null) { throw new IllegalStateException("PDFDocument already set up"); } - this.pdfDoc = new PDFDocument( - userAgent.getProducer() != null ? userAgent.getProducer() : ""); + + String producer = userAgent.getProducer() != null ? userAgent.getProducer() : ""; + + if (maxPDFVersion == null) { + this.pdfDoc = new PDFDocument(producer); + } else { + VersionController controller = + VersionController.getFixedVersionController(maxPDFVersion); + this.pdfDoc = new PDFDocument(producer, controller); + } updateInfo(); updatePDFProfiles(); pdfDoc.setFilterMap(filterMap); @@ -482,4 +494,14 @@ class PDFRenderingUtil implements PDFConfigurationConstants { nameArray.add(new PDFReference(fileSpec)); } + /** + * Sets the PDF version of the output document. See {@link Version} for the format of + * version. + * @param version the PDF version + * @throws IllegalArgumentException if the format of version doesn't conform to that specified + * by {@link Version} + */ + public void setPDFVersion(String version) { + maxPDFVersion = Version.getValueOf(version); + } } diff --git a/status.xml b/status.xml index 52bf109c4..e34ecdb48 100644 --- a/status.xml +++ b/status.xml @@ -62,6 +62,9 @@ documents. Example: the fix of marks layering will be such a case when it's done. --> + + Added configuration option to set the version of the output PDF document. + Fixed bug that caused a configured and installed SVG font to stroked, also added an event indicating when fonts are stroked. diff --git a/test/java/org/apache/fop/pdf/VersionControllerTestCase.java b/test/java/org/apache/fop/pdf/VersionControllerTestCase.java new file mode 100644 index 000000000..74637c91f --- /dev/null +++ b/test/java/org/apache/fop/pdf/VersionControllerTestCase.java @@ -0,0 +1,143 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import org.junit.Before; +import org.junit.Test; + + +/** + * A test class for {@link VersionController}. + */ +public class VersionControllerTestCase { + + private PDFDocument doc; + + @Before + public void setUp() { + doc = new PDFDocument("test"); + } + + @Test + public void testGetVersion() { + // These do the same thing + for (Version version : Version.values()) { + if (version.compareTo(Version.V1_4) >= 0) { + VersionController fixedVC = VersionController.getFixedVersionController(version); + assertEquals(version, fixedVC.getPDFVersion()); + } + + VersionController dynamicVC = VersionController.getDynamicVersionController(version, + doc); + assertEquals(version, dynamicVC.getPDFVersion()); + } + } + + /** + * Tests that the setter methods work at setting the underlying version. + * Here there is a disparity between the two objects, the fixed version will + * throw an exception if the setter is invoked. The dynamic version will + * allow the version to be changed, if the new version is greater than the + * version already set. + */ + @Test + public void testSetVersion() { + // Create every type of expected PDFVersion + for (Version originalVersion : Version.values()) { + // Compare against every type of Version + for (Version setVersion : Version.values()) { + testDynamicController(originalVersion, setVersion); + testFixedController(originalVersion, setVersion); + } + + } + } + + /** + * The fixed implementation will throw an exception if an attempt is made to change its + * version. + * + * @param originalVersion the version given to the constructor when PDFVersion instantiated + * @param setVersion the version being set + */ + private void testFixedController(Version originalVersion, Version setVersion) { + if (originalVersion.compareTo(Version.V1_4) >= 0) { + VersionController fixedVC = VersionController + .getFixedVersionController(originalVersion); + try { + fixedVC.setPDFVersion(setVersion); + fail("The FixedVersionController should throw an exception if an attempt to change " + + "the version is made"); + } catch (IllegalStateException e) { + // PASS + } + // Changes are NOT allowed, the original version is immutable + assertEquals(originalVersion, fixedVC.getPDFVersion()); + // The document version is NEVER changed + assertEquals(Version.V1_4, doc.getPDFVersion()); + // the /Version parameter shouldn't be present in the document catalog + assertNull(doc.getRoot().get("Version")); + } else { + try { + VersionController.getFixedVersionController(originalVersion); + fail("Versions < 1.4 aren't allowed."); + } catch (IllegalArgumentException e) { + // PASS + } + } + } + + /** + * The dynamic implementation allows the version to be changed. However, the version given in + * the constructor will be the version set in the header of the PDF document. Any change to the + * version will then be made in the document catalog. + * + * @param originalVersion the version given to the constructor when PDFVersion instantiated + * @param setVersion the version being set + */ + private void testDynamicController(Version originalVersion, Version setVersion) { + VersionController testSubj = VersionController.getDynamicVersionController(originalVersion, + doc); + testSubj.setPDFVersion(setVersion); + PDFName nameVersion = new PDFName(setVersion.toString()); + + if (originalVersion.compareTo(setVersion) < 0) { + versionShouldChange(setVersion, testSubj, nameVersion); + } else { + versionShouldNotChange(originalVersion, testSubj); + } + doc.getRoot().put("Version", null); + } + + private void versionShouldNotChange(Version originalVersion, VersionController testSubj) { + assertEquals(originalVersion, testSubj.getPDFVersion()); + assertNull(doc.getRoot().get("Version")); + } + + private void versionShouldChange(Version setVersion, VersionController testSubj, + PDFName nameVersion) { + assertEquals(setVersion, testSubj.getPDFVersion()); + assertEquals(nameVersion.toString(), doc.getRoot().get("Version").toString()); + } +} diff --git a/test/java/org/apache/fop/pdf/VersionTestCase.java b/test/java/org/apache/fop/pdf/VersionTestCase.java new file mode 100644 index 000000000..9c90f0966 --- /dev/null +++ b/test/java/org/apache/fop/pdf/VersionTestCase.java @@ -0,0 +1,89 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * This is a test case for ({@link Version}. + */ +public class VersionTestCase { + + /** + * Test the getValue() method. This should return {@link Version} given a + * {@link String}. + */ + @Test + public void testGetValue() { + int index = 0; + for (Version version : Version.values()) { + assertEquals(version, Version.getValueOf("1." + index++)); + } + } + + @Test(expected = IllegalArgumentException.class) + public void testGetValueIllegalArgument() { + Version.getValueOf("blah"); + } + + /** + * Tests that the toString() method returns the PDF version string of the proper + * format. + */ + @Test + public void testToString() { + // Test all the normal values + int index = 0; + for (Version version : Version.values()) { + assertTrue(version.toString().equals("1." + index++)); + } + } + + /** + * Tests that the compareTo() contract is obeyed. + */ + @Test + public void testCompareTo() { + // Ensure that the implicit comparison contract is satisfied + Version[] expected = { + Version.V1_0, + Version.V1_1, + Version.V1_2, + Version.V1_3, + Version.V1_4, + Version.V1_5, + Version.V1_6, + Version.V1_7 + }; + + Version[] actual = Version.values(); + + for (int i = 0; i < actual.length - 1; i++) { + assertEquals(-1, actual[i].compareTo(expected[i + 1])); + + assertEquals(0, actual[i].compareTo(expected[i])); + + assertEquals(1, actual[i + 1].compareTo(expected[i])); + } + } +} -- 2.39.5