summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2010-11-15 13:58:40 +0000
committerJeremias Maerki <jeremias@apache.org>2010-11-15 13:58:40 +0000
commita46140eafd2005fac84de4a359ee484aadb3f968 (patch)
tree9fccf940d8c91ac917d1f3ca66658be54f6224d5
parent327caf5863606991d03fc1e3e5c9880bec75b4ca (diff)
parent3dc848243b02e9a7b1c24b4dfd252dc545bfa0f7 (diff)
downloadxmlgraphics-fop-a46140eafd2005fac84de4a359ee484aadb3f968.tar.gz
xmlgraphics-fop-a46140eafd2005fac84de4a359ee484aadb3f968.zip
Merged from Trunk revisions 990171 to 1035276.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1035278 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--build.xml52
-rw-r--r--src/documentation/content/xdocs/dev/release.xml1
-rw-r--r--src/documentation/content/xdocs/download.xml17
-rw-r--r--src/documentation/content/xdocs/trunk/compiling.xml15
-rw-r--r--src/documentation/content/xdocs/trunk/configuration.xml9
-rw-r--r--src/documentation/content/xdocs/trunk/output.xml7
-rw-r--r--src/java/org/apache/fop/afp/AFPResourceManager.java55
-rw-r--r--src/java/org/apache/fop/afp/AFPStreamer.java2
-rw-r--r--src/java/org/apache/fop/afp/DataStream.java6
-rw-r--r--src/java/org/apache/fop/afp/apps/FontPatternExtractor.java157
-rw-r--r--src/java/org/apache/fop/afp/fonts/AFPFontCollection.java2
-rw-r--r--src/java/org/apache/fop/afp/modca/IncludedResourceObject.java3
-rw-r--r--src/java/org/apache/fop/afp/modca/ObjectContainer.java2
-rw-r--r--src/java/org/apache/fop/afp/parser/MODCAParser.java80
-rw-r--r--src/java/org/apache/fop/afp/parser/UnparsedStructuredField.java355
-rw-r--r--src/java/org/apache/fop/afp/util/AFPResourceUtil.java214
-rw-r--r--src/java/org/apache/fop/afp/util/StructuredFieldReader.java79
-rw-r--r--src/java/org/apache/fop/apps/FopFactory.java24
-rw-r--r--src/java/org/apache/fop/apps/FopFactoryConfigurator.java96
-rw-r--r--src/java/org/apache/fop/area/PageViewport.java17
-rw-r--r--src/java/org/apache/fop/cli/CommandLineOptions.java2
-rw-r--r--src/java/org/apache/fop/datatypes/Numeric.java12
-rw-r--r--src/java/org/apache/fop/fo/expr/NumericOp.java44
-rw-r--r--src/java/org/apache/fop/fo/flow/table/TableFObj.java14
-rw-r--r--src/java/org/apache/fop/fo/pagination/Root.java2
-rw-r--r--src/java/org/apache/fop/fo/properties/BackgroundPositionShorthand.java2
-rw-r--r--src/java/org/apache/fop/fo/properties/BorderWidthPropertyMaker.java5
-rw-r--r--src/java/org/apache/fop/fo/properties/ColorProperty.java2
-rw-r--r--src/java/org/apache/fop/fo/properties/CommonHyphenation.java2
-rw-r--r--src/java/org/apache/fop/fo/properties/CompoundPropertyMaker.java7
-rw-r--r--src/java/org/apache/fop/fo/properties/FontFamilyProperty.java2
-rw-r--r--src/java/org/apache/fop/fo/properties/FontSizePropertyMaker.java2
-rw-r--r--src/java/org/apache/fop/fo/properties/KeepProperty.java2
-rw-r--r--src/java/org/apache/fop/fo/properties/PageDimensionMaker.java2
-rw-r--r--src/java/org/apache/fop/fo/properties/ToBeImplementedProperty.java2
-rw-r--r--src/java/org/apache/fop/fonts/EncodingMode.java35
-rw-r--r--src/java/org/apache/fop/fonts/FontInfoConfigurator.java2
-rw-r--r--src/java/org/apache/fop/hyphenation/HyphenationTreeCache.java23
-rw-r--r--src/java/org/apache/fop/hyphenation/Hyphenator.java237
-rw-r--r--src/java/org/apache/fop/layoutmgr/Page.java6
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageBreaker.java16
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageProvider.java20
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java1
-rw-r--r--src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java7
-rw-r--r--src/java/org/apache/fop/pdf/PDFMetadata.java3
-rw-r--r--src/java/org/apache/fop/pdf/PDFName.java4
-rw-r--r--src/java/org/apache/fop/render/afp/AFPDocumentHandler.java23
-rw-r--r--src/java/org/apache/fop/render/afp/AFPPainter.java30
-rw-r--r--src/java/org/apache/fop/render/afp/PageSegmentDescriptor.java57
-rw-r--r--src/java/org/apache/fop/render/afp/extensions/AFPElementMapping.java2
-rw-r--r--src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java29
-rw-r--r--src/java/org/apache/fop/render/afp/extensions/AFPPageSegmentElement.java149
-rw-r--r--src/java/org/apache/fop/render/intermediate/util/IFConcatenator.java11
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java8
-rw-r--r--src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java3
-rw-r--r--src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java9
-rw-r--r--src/java/org/apache/fop/render/ps/extensions/PSExtensionHandler.java3
-rw-r--r--src/java/org/apache/fop/render/rtf/RTFHandler.java25
-rw-r--r--src/java/org/apache/fop/render/rtf/TextAttributesConverter.java39
-rw-r--r--src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java133
-rw-r--r--src/java/org/apache/fop/svg/AbstractFOPTranscoder.java3
-rw-r--r--src/java/org/apache/fop/svg/NativeTextPainter.java28
-rw-r--r--src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java2
-rw-r--r--src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java34
-rw-r--r--src/java/org/apache/fop/svg/PDFTranscoder.java4
-rw-r--r--src/java/org/apache/fop/tools/anttasks/Fop.java34
-rw-r--r--src/java/org/apache/fop/traits/MinOptMax.java53
-rw-r--r--status.xml15
-rw-r--r--test/java/org/apache/fop/fonts/EncodingModeTest.java36
-rw-r--r--test/layoutengine/hyphenation-testcases/hyphenation-pattern_fallback.xml137
-rw-r--r--test/layoutengine/standard-testcases/flow_changing-ipd_table-after-break.xml23
-rw-r--r--test/layoutengine/standard-testcases/region-body_column-count_span_4.xml84
-rw-r--r--xmlgraphics-fop-pom-template.pom11
73 files changed, 2126 insertions, 508 deletions
diff --git a/build.xml b/build.xml
index 1d9aad8ed..ae4f5c886 100644
--- a/build.xml
+++ b/build.xml
@@ -149,8 +149,8 @@ list of possible build targets.
<property name="javac.debug" value="on"/>
<property name="javac.optimize" value="off"/>
<property name="javac.deprecation" value="on"/>
- <property name="javac.source" value="1.4"/>
- <property name="javac.target" value="1.4"/>
+ <property name="javac.source" value="1.5"/>
+ <property name="javac.target" value="1.5"/>
<property name="javac.fork" value="no"/>
<property name="junit.fork" value="on"/>
<property name="junit.haltonfailure" value="off"/>
@@ -193,8 +193,11 @@ list of possible build targets.
<property name="fotree.disabled" value="test/fotree/disabled-testcases.xml"/>
<property name="dist.bin.dir" value="${basedir}/dist-bin"/>
<property name="dist.src.dir" value="${basedir}/dist-src"/>
+ <property name="nightly.dir" value="${basedir}/nightly"/>
<property name="dist.bin.result.dir" value="${dist.bin.dir}/${name}-${version}"/>
<property name="dist.src.result.dir" value="${dist.src.dir}/${name}-${version}"/>
+ <tstamp/>
+ <property name="nightly.result.dir" value="${nightly.dir}/${name}-${DSTAMP}"/>
<property name="samedir" value="${basedir}"/>
<property name="junit.reports.dir" value="${build.dir}/test-reports"/>
<property name="junit.html.reports.dir" value="${build.dir}/test-reports/html"/>
@@ -1045,7 +1048,6 @@ NOTE:
<pathelement path="${src.sandbox.dir}"/>
<pathelement path="${build.gensrc.dir}"/>
</sourcepath>
- <tag name="asf.todo" scope="all" description="To do:"/>
<tag name="event.severity" scope="all" description="Event severity level:"/>
<group title="Control and Startup">
<package name="org.apache.fop"/>
@@ -1356,6 +1358,50 @@ NOTE:
<move file="${build.dir}/${name}-${version}-bundle.jar" todir="${basedir}"/>
</target>
<!-- =================================================================== -->
+<!-- Nightly builds -->
+<!-- =================================================================== -->
+ <target name="junit-nightly-build" depends="junit-userconfig,junit-text-linebreak,junit-fotree">
+ <fail>
+ <condition>
+ <or>
+ <isset property="fop.junit.error"/>
+ <isset property="fop.junit.failure"/>
+ </or>
+ </condition>
+NOTE:
+**************************************************************************
+* One or more of the Junit tests had Failures or Errors or were skipped! *
+* Please check the output above for relevant messages. *
+* Or use the "junit-reports" target to generate HTML test reports. *
+**************************************************************************
+ </fail>
+ <echo>All Junit tests passed!</echo>
+ </target>
+ <target name="nightly-build" depends="clean,jar-main,junit-nightly-build">
+ <echo message="Building the binary distribution files (zip,tar)"/>
+ <delete dir="${nightly.dir}"/>
+ <mkdir dir="${nightly.result.dir}"/>
+ <copy todir="${nightly.result.dir}">
+ <fileset refid="dist.bin"/>
+ <fileset refid="dist.bin.lib"/>
+ </copy>
+ <mkdir dir="${nightly.result.dir}/build"/>
+ <copy todir="${nightly.result.dir}/build" file="build/fop.jar"/>
+ <chmod file="${nightly.result.dir}/fop" perm="ugo+rx"/>
+ <zip zipfile="${name}-${DSTAMP}-bin.zip" basedir="${nightly.dir}" includes="**"/>
+ <tar longfile="gnu" destfile="${name}-${DSTAMP}-bin.tar">
+ <tarfileset dir="${nightly.dir}" mode="755">
+ <include name="${name}-${DSTAMP}/fop"/>
+ </tarfileset>
+ <tarfileset dir="${nightly.dir}">
+ <include name="**"/>
+ <exclude name="${name}-${DSTAMP}/fop"/>
+ </tarfileset>
+ </tar>
+ <gzip zipfile="${name}-${DSTAMP}-bin.tar.gz" src="${name}-${DSTAMP}-bin.tar"/>
+ <delete file="${name}-${DSTAMP}-bin.tar"/>
+ </target>
+<!-- =================================================================== -->
<!-- Generate examples -->
<!-- =================================================================== -->
<target name="examples" depends="package" description="Generates the example files">
diff --git a/src/documentation/content/xdocs/dev/release.xml b/src/documentation/content/xdocs/dev/release.xml
index 4e54df872..da614bee0 100644
--- a/src/documentation/content/xdocs/dev/release.xml
+++ b/src/documentation/content/xdocs/dev/release.xml
@@ -69,6 +69,7 @@ The purpose of documenting it here is to facilitate consistency, ensure that the
<li>Update the tab names and directories in tabs.xml</li>
<li>Delete the previous version directory.</li>
<li>Update index.xml in the new version directory.</li>
+ <li>Update compiling.xml in the new version directory: change the intro for trunk to that for a release.</li>
<li>Build the dist files (<code>build[.sh] dist</code>)
and upload them to your web directory on
<code>people.apache.org</code></li>
diff --git a/src/documentation/content/xdocs/download.xml b/src/documentation/content/xdocs/download.xml
index d8fbe9978..9d7988e61 100644
--- a/src/documentation/content/xdocs/download.xml
+++ b/src/documentation/content/xdocs/download.xml
@@ -51,8 +51,8 @@
<p>
Binary distributions include "-bin" in their names, and can be downloaded from a
<link href="http://www.apache.org/dyn/closer.cgi/xmlgraphics/fop">FOP Distribution mirror</link>.
- Nightly builds of trunk source code can be downloaded here:
- <link href="http://vc.apache.org/snapshots/fop/">Snapshot Trunk Builds</link>
+ Nightly builds of trunk code can be downloaded here:
+ <link href="http://ci.apache.org/projects/xmlgraphics/fop/snapshots/">Nightly Snapshots</link>.
</p>
</section>
<section id="source">
@@ -67,13 +67,12 @@
<link href="http://www.apache.org/dyn/closer.cgi/xmlgraphics/fop">FOP Distribution mirror</link>.
Source distributions include "-src" in their names.
</li>
- <!--li>
- Download a CVS snapshot from the cvs files
- <link href="http://xml.apache.org/from-cvs/xml-fop/">here</link>.
- These snapshots are built approximately every six hours, and have the GMT of
- their creation time embedded in their names. Please note that CVS snapshots
- are made only for the "redesign" branch.
- </li-->
+ <li>
+ Download a Subversion snapshot
+ <link href="http://vc.apache.org/snapshots/fop/">here</link>.
+ These snapshots are checked out from Subversion approximately every six hours, and have the GMT of
+ their creation time embedded in their names.
+ </li>
<li>
Download directly from the SVN repository.
Anyone can do this using the
diff --git a/src/documentation/content/xdocs/trunk/compiling.xml b/src/documentation/content/xdocs/trunk/compiling.xml
index 98a6dfb6d..0a8bf3486 100644
--- a/src/documentation/content/xdocs/trunk/compiling.xml
+++ b/src/documentation/content/xdocs/trunk/compiling.xml
@@ -25,16 +25,23 @@
<body>
<section id="build-needed">
<title>Do You Need To Build?</title>
- <p>
+<!-- text for released versions -->
+<!-- <p>
FOP distributions are either pre-compiled binary or source.
If you are using a binary distribution, it is already built and there is no need to build it again.
See the <a href="../download.html">Download Instructions</a> for information about whether a
binary or source distribution is best for your needs.
- </p>
+ </p>-->
+<!-- /text for released versions -->
+<!-- text for trunk -->
<p>
- If you got the source code from a repository snapshot or via Subversion you will need to build FOP
- in any case.
+ FOP snapshots are either pre-compiled binary or source.
+ If you are using a binary snapshot, it is already built and there is no need to build it again.
+ If you got the source code from a repository snapshot or via Subversion you will need to build FOP.
+ See the <a href="../download.html">Download Instructions</a> for information about where to obtain binary or repository snapshots, and whether a
+ binary or source snapshot is best for your needs.
</p>
+<!-- /text for trunk -->
</section>
<section id="env">
<title>Set Up Your Environment</title>
diff --git a/src/documentation/content/xdocs/trunk/configuration.xml b/src/documentation/content/xdocs/trunk/configuration.xml
index aae7de7f0..3ef8795b7 100644
--- a/src/documentation/content/xdocs/trunk/configuration.xml
+++ b/src/documentation/content/xdocs/trunk/configuration.xml
@@ -89,6 +89,12 @@
</td>
<td>disabled</td>
</tr>
+ <tr>
+ <td>hyphenation-pattern</td>
+ <td>String, attribute lang, attribute country (optional)</td>
+ <td>Register a file name for the hyphenation pattern for the mentioned language and country. Language ll and country CC must both consist of two letters.</td>
+ <td>ll_CC</td>
+ </tr>
<tr>
<td>source-resolution</td>
<td>Integer, dpi</td>
@@ -215,6 +221,9 @@
<!-- default page-height and page-width, in case
value is specified as auto -->
<default-page-settings height="11in" width="8.26in"/>
+
+ <!-- Use file name nl_Bel instead of the default nl_BE -->
+ <hyphenation-pattern lang="nl" country="BE">nl_Bel</hyphenation-pattern>
<!-- etc. etc..... -->
</fop>]]></source>
diff --git a/src/documentation/content/xdocs/trunk/output.xml b/src/documentation/content/xdocs/trunk/output.xml
index 1766cd493..226a2d96c 100644
--- a/src/documentation/content/xdocs/trunk/output.xml
+++ b/src/documentation/content/xdocs/trunk/output.xml
@@ -885,6 +885,13 @@ Note that the value of the encoding attribute in the example is the double-byte
segment in the generated file. Please also note that page segments cannot be scaled.
They are always rendered in their intrinsic size.
</p>
+ <p>
+ The include-page-segment extension element has the optional attribute
+ <i>resource-file</i>. The value of this is a URI to a resource containing a page
+ segment with the declared name. In this case FOP embeds the page segment into the
+ generated document so that the external resource does not have to be supplied in the
+ print job.
+ </p>
</section>
<section id="afp-tag-logical-element">
<title>Tag Logical Element (TLE) Extension</title>
diff --git a/src/java/org/apache/fop/afp/AFPResourceManager.java b/src/java/org/apache/fop/afp/AFPResourceManager.java
index b7e1abc01..ae759e14a 100644
--- a/src/java/org/apache/fop/afp/AFPResourceManager.java
+++ b/src/java/org/apache/fop/afp/AFPResourceManager.java
@@ -19,12 +19,15 @@
package org.apache.fop.afp;
+import java.io.BufferedInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -38,6 +41,7 @@ import org.apache.fop.afp.modca.PageSegment;
import org.apache.fop.afp.modca.Registry;
import org.apache.fop.afp.modca.ResourceGroup;
import org.apache.fop.afp.modca.ResourceObject;
+import org.apache.fop.afp.util.AFPResourceUtil;
import org.apache.fop.afp.util.ResourceAccessor;
/**
@@ -314,6 +318,57 @@ public class AFPResourceManager {
}
/**
+ * Creates an included resource extracting the named resource from an external source.
+ * @param resourceName the name of the resource
+ * @param uri the URI for the resource
+ * @param accessor resource accessor to access the resource with
+ * @throws IOException if an I/O error occurs while loading the resource
+ */
+ public void createIncludedResourceFromExternal(final String resourceName,
+ final URI uri, final ResourceAccessor accessor) throws IOException {
+
+ AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE);
+
+ AFPResourceInfo resourceInfo = new AFPResourceInfo();
+ resourceInfo.setLevel(resourceLevel);
+ resourceInfo.setName(resourceName);
+ resourceInfo.setUri(uri.toASCIIString());
+
+ String resource = (String)includeNameMap.get(resourceInfo);
+ if (resource == null) {
+
+ ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel);
+
+ //resourceObject delegates write commands to copyNamedResource()
+ //The included resource may already be wrapped in a resource object
+ AbstractNamedAFPObject resourceObject = new AbstractNamedAFPObject(null) {
+
+ protected void writeContent(OutputStream os) throws IOException {
+ InputStream inputStream = null;
+ try {
+ inputStream = accessor.createInputStream(uri);
+ BufferedInputStream bin = new BufferedInputStream(inputStream);
+ AFPResourceUtil.copyNamedResource(resourceName, bin, os);
+ } finally {
+ IOUtils.closeQuietly(inputStream);
+ }
+ }
+
+ //bypass super.writeStart
+ protected void writeStart(OutputStream os) throws IOException { }
+ //bypass super.writeEnd
+ protected void writeEnd(OutputStream os) throws IOException { }
+ };
+
+ resourceGroup.addObject(resourceObject);
+
+ includeNameMap.put(resourceInfo, resourceName);
+
+ }
+ }
+
+
+ /**
* Sets resource level defaults. The existing defaults over merged with the ones passed in
* as parameter.
* @param defaults the new defaults
diff --git a/src/java/org/apache/fop/afp/AFPStreamer.java b/src/java/org/apache/fop/afp/AFPStreamer.java
index 33d1dbf90..154ca4cc9 100644
--- a/src/java/org/apache/fop/afp/AFPStreamer.java
+++ b/src/java/org/apache/fop/afp/AFPStreamer.java
@@ -158,7 +158,7 @@ public class AFPStreamer implements Streamable {
*/
// write out any external resource groups
public void close() throws IOException {
- Iterator it = pathResourceGroupMap.entrySet().iterator();
+ Iterator it = pathResourceGroupMap.values().iterator();
while (it.hasNext()) {
StreamedResourceGroup resourceGroup = (StreamedResourceGroup)it.next();
resourceGroup.close();
diff --git a/src/java/org/apache/fop/afp/DataStream.java b/src/java/org/apache/fop/afp/DataStream.java
index 843e3fa65..a437c3004 100644
--- a/src/java/org/apache/fop/afp/DataStream.java
+++ b/src/java/org/apache/fop/afp/DataStream.java
@@ -359,9 +359,9 @@ public class DataStream {
* @param charSet is the AFP Character Set to use with the text
* @throws UnsupportedEncodingException thrown if character encoding is not supported
*/
- public void createText
- ( final AFPTextDataInfo textDataInfo, final int letterSpacing, final int wordSpacing,
- final Font font, final CharacterSet charSet) throws UnsupportedEncodingException {
+ public void createText(final AFPTextDataInfo textDataInfo, final int letterSpacing,
+ final int wordSpacing, final Font font, final CharacterSet charSet)
+ throws UnsupportedEncodingException {
int rotation = paintingState.getRotation();
if (rotation != 0) {
textDataInfo.setRotation(rotation);
diff --git a/src/java/org/apache/fop/afp/apps/FontPatternExtractor.java b/src/java/org/apache/fop/afp/apps/FontPatternExtractor.java
new file mode 100644
index 000000000..0adffcd8b
--- /dev/null
+++ b/src/java/org/apache/fop/afp/apps/FontPatternExtractor.java
@@ -0,0 +1,157 @@
+/*
+ * 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.afp.apps;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import org.apache.commons.io.HexDump;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+
+import org.apache.fop.afp.parser.MODCAParser;
+import org.apache.fop.afp.parser.UnparsedStructuredField;
+
+/**
+ * This class represents a tool for extracting the Type 1 PFB file from an AFP outline font.
+ */
+public class FontPatternExtractor {
+
+ private PrintStream printStream = System.out;
+
+ /**
+ * Extracts the Type1 PFB file from the given AFP outline font.
+ * @param file the AFP file to read from
+ * @param targetDir the target directory where the PFB file is to be placed.
+ * @throws IOException if an I/O error occurs
+ */
+ public void extract(File file, File targetDir) throws IOException {
+ InputStream in = new java.io.FileInputStream(file);
+ try {
+ MODCAParser parser = new MODCAParser(in);
+ ByteArrayOutputStream baout = new ByteArrayOutputStream();
+ UnparsedStructuredField strucField;
+ while ((strucField = parser.readNextStructuredField()) != null) {
+ if (strucField.getSfTypeID() == 0xD3EE89) {
+ println(strucField.toString());
+ HexDump.dump(strucField.getData(), 0, printStream, 0);
+ baout.write(strucField.getData());
+ }
+ }
+
+ ByteArrayInputStream bin = new ByteArrayInputStream(baout.toByteArray());
+ DataInputStream din = new DataInputStream(bin);
+ long len = din.readInt() & 0xFFFFFFFFL;
+ println("Length: " + len);
+ din.skip(4); //checksum
+ int tidLen = din.readUnsignedShort() - 2;
+ byte[] tid = new byte[tidLen];
+ din.readFully(tid);
+ String filename = new String(tid, "ISO-8859-1");
+ int asciiCount1 = countUSAsciiCharacters(filename);
+ String filenameEBCDIC = new String(tid, "Cp1146");
+ int asciiCount2 = countUSAsciiCharacters(filenameEBCDIC);
+ println("TID: " + filename + " " + filenameEBCDIC);
+
+ if (asciiCount2 > asciiCount1) {
+ //Haven't found an indicator if the name is encoded in EBCDIC or not
+ //so we use a trick.
+ filename = filenameEBCDIC;
+ }
+ if (!filename.toLowerCase().endsWith(".pfb")) {
+ filename = filename + ".pfb";
+ }
+ println("Output filename: " + filename);
+ File out = new File(targetDir, filename);
+
+ OutputStream fout = new java.io.FileOutputStream(out);
+ try {
+ IOUtils.copyLarge(din, fout);
+ } finally {
+ IOUtils.closeQuietly(fout);
+ }
+
+
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ }
+
+ private void println(String s) {
+ printStream.println(s);
+ }
+
+ private void println() {
+ printStream.println();
+ }
+
+ private int countUSAsciiCharacters(String filename) {
+ int count = 0;
+ for (int i = 0, c = filename.length(); i < c; i++) {
+ if (filename.charAt(i) < 128) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Main method
+ * @param args the command-line arguments
+ */
+ public static void main(String[] args) {
+ try {
+ FontPatternExtractor app = new FontPatternExtractor();
+
+ app.println("Font Pattern Extractor");
+ app.println();
+
+ if (args.length > 0) {
+ String filename = args[0];
+ File file = new File(filename);
+
+ File targetDir = file.getParentFile();
+ if (args.length > 1) {
+ targetDir = new File(args[1]);
+ targetDir.mkdirs();
+ }
+
+ app.extract(file, targetDir);
+ } else {
+ app.println("This tool tries to extract the PFB file from an AFP outline font.");
+ app.println();
+ app.println("Usage: Java -cp ... " + FontPatternExtractor.class.getName()
+ + " <afp-font-file> [<target-dir>]");
+ System.exit(-1);
+ }
+
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(-1);
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java b/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java
index 66b3f5564..b7db6a74e 100644
--- a/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java
+++ b/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java
@@ -61,9 +61,9 @@ public class AFPFontCollection implements FontCollection {
List/*<FontTriplet>*/ tripletList = afpFontInfo.getFontTriplets();
for (Iterator it2 = tripletList.iterator(); it2.hasNext();) {
FontTriplet triplet = (FontTriplet)it2.next();
+ fontInfo.addMetrics("F" + num, afpFont);
fontInfo.addFontProperties("F" + num,
triplet.getName(), triplet.getStyle(), triplet.getWeight());
- fontInfo.addMetrics("F" + num, afpFont);
num++;
}
}
diff --git a/src/java/org/apache/fop/afp/modca/IncludedResourceObject.java b/src/java/org/apache/fop/afp/modca/IncludedResourceObject.java
index 296ab2d9d..dc841bd40 100644
--- a/src/java/org/apache/fop/afp/modca/IncludedResourceObject.java
+++ b/src/java/org/apache/fop/afp/modca/IncludedResourceObject.java
@@ -26,6 +26,7 @@ import java.net.URI;
import org.apache.commons.io.IOUtils;
+import org.apache.fop.afp.util.AFPResourceUtil;
import org.apache.fop.afp.util.ResourceAccessor;
@@ -54,7 +55,7 @@ public class IncludedResourceObject extends AbstractNamedAFPObject {
public void writeToStream(OutputStream os) throws IOException {
InputStream in = resourceAccessor.createInputStream(this.uri);
try {
- IOUtils.copy(in, os);
+ AFPResourceUtil.copyResourceFile(in, os);
} finally {
IOUtils.closeQuietly(in);
}
diff --git a/src/java/org/apache/fop/afp/modca/ObjectContainer.java b/src/java/org/apache/fop/afp/modca/ObjectContainer.java
index 515425906..9bc8dc594 100644
--- a/src/java/org/apache/fop/afp/modca/ObjectContainer.java
+++ b/src/java/org/apache/fop/afp/modca/ObjectContainer.java
@@ -113,7 +113,7 @@ public class ObjectContainer extends AbstractDataObject {
}
/**
- * Sets the data for the the object container
+ * Sets the data for the object container
*
* @param data a byte array
*/
diff --git a/src/java/org/apache/fop/afp/parser/MODCAParser.java b/src/java/org/apache/fop/afp/parser/MODCAParser.java
new file mode 100644
index 000000000..356d4f169
--- /dev/null
+++ b/src/java/org/apache/fop/afp/parser/MODCAParser.java
@@ -0,0 +1,80 @@
+/*
+ * 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.afp.parser;
+
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An simple MO:DCA/AFP parser.
+ */
+public class MODCAParser {
+
+ /** The carriage control character (0x5A) used to indicate the start of a structured field. */
+ public static final byte CARRIAGE_CONTROL_CHAR = (byte)(0x5A & 0xFF);
+
+ private DataInputStream din;
+
+ /**
+ * Main constructor
+ * @param in the {@link InputStream} to read the AFP file from.
+ */
+ public MODCAParser(InputStream in) {
+ if (!in.markSupported()) {
+ in = new java.io.BufferedInputStream(in);
+ }
+ this.din = new DataInputStream(in);
+ }
+
+ /**
+ * Returns the {@link DataInputStream} used for parsing structured fields.
+ * @return the data input stream
+ */
+ public DataInputStream getDataInputStream() {
+ return this.din;
+ }
+
+ /**
+ * Reads the next structured field from the input stream.
+ * <p>
+ * No structure validation of the MO:DCA file is performed.
+ * @return a new unparsed structured field (or null when parsing is finished).
+ * @throws IOException if an I/O error occurs
+ */
+ public UnparsedStructuredField readNextStructuredField() throws IOException {
+ try {
+ while (true) {
+ byte b = din.readByte(); //Skip 0x5A character if necessary (ex. AFP)
+ if (b == 0x0D || b == 0x0A) {
+ //CR and LF may be used as field delimiters
+ continue;
+ } else if (b == CARRIAGE_CONTROL_CHAR) {
+ break; //Signals the start of a new structured field
+ }
+ }
+ } catch (EOFException eof) {
+ return null;
+ }
+ return UnparsedStructuredField.readStructuredField(getDataInputStream());
+ }
+
+}
diff --git a/src/java/org/apache/fop/afp/parser/UnparsedStructuredField.java b/src/java/org/apache/fop/afp/parser/UnparsedStructuredField.java
new file mode 100644
index 000000000..f775c05ee
--- /dev/null
+++ b/src/java/org/apache/fop/afp/parser/UnparsedStructuredField.java
@@ -0,0 +1,355 @@
+/*
+ * 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.afp.parser;
+
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.text.DecimalFormat;
+
+import org.apache.commons.io.HexDump;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Represents an unparsed (generic) AFP structured field.
+ */
+public class UnparsedStructuredField {
+
+ private static final Log LOG = LogFactory.getLog(UnparsedStructuredField.class);
+
+ private static final int INTRODUCER_LENGTH = 8;
+
+ private short sfLength;
+ private byte sfClassCode;
+ private byte sfTypeCode;
+ private byte sfCategoryCode;
+ private boolean sfiExtensionPresent;
+ private boolean sfiSegmentedData;
+ private boolean sfiPaddingPresent;
+ private short extLength;
+ private byte[] introducerData;
+ private byte[] extData;
+ private byte[] data;
+
+ /**
+ * Default constructor.
+ */
+ public UnparsedStructuredField() {
+ //nop
+ }
+
+ /**
+ * Reads a structured field from a {@link DataInputStream}. The resulting object can be
+ * further interpreted be follow-up code.
+ * @param din the stream to read from
+ * @return the generic structured field
+ * @throws IOException if an I/O error occurs
+ */
+ public static UnparsedStructuredField readStructuredField(DataInputStream din)
+ throws IOException {
+ UnparsedStructuredField sf = new UnparsedStructuredField();
+
+ //Read introducer as byte array to preserve any data not parsed below
+ din.mark(INTRODUCER_LENGTH);
+ sf.introducerData = new byte[INTRODUCER_LENGTH]; //Length of introducer
+ din.readFully(sf.introducerData);
+ din.reset();
+
+ //Parse the introducer
+ short len;
+ try {
+ len = din.readShort();
+ } catch (EOFException eof) {
+ return null;
+ }
+ sf.sfLength = len;
+ sf.sfClassCode = din.readByte();
+ sf.sfTypeCode = din.readByte();
+ sf.sfCategoryCode = din.readByte();
+
+ //Flags
+ byte f = din.readByte();
+ sf.sfiExtensionPresent = (f & 0x01) != 0;
+ sf.sfiSegmentedData = (f & 0x04) != 0;
+ sf.sfiPaddingPresent = (f & 0x10) != 0;
+ din.skip(2); //Reserved
+
+ int dataLength = sf.sfLength - INTRODUCER_LENGTH;
+
+ //Handle optional extension
+ if (sf.sfiExtensionPresent) {
+ sf.extLength = (short)(((short)din.readByte()) & 0xFF);
+ if (sf.extLength > 0) {
+ sf.extData = new byte[sf.extLength - 1];
+ din.readFully(sf.extData);
+ dataLength -= sf.extLength;
+ }
+ }
+
+ //Read payload
+ sf.data = new byte[dataLength];
+ din.readFully(sf.data);
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace(sf);
+ }
+
+ return sf;
+ }
+
+ /** {@inheritDoc} */
+ public String toString() {
+ StringBuffer sb = new StringBuffer("Structured Field: ");
+ sb.append(Integer.toHexString(getSfTypeID()).toUpperCase());
+ sb.append(", len=");
+ sb.append(new DecimalFormat("00000").format(getSfLength()));
+ sb.append(" ").append(getTypeCodeAsString());
+ sb.append(" ").append(getCategoryCodeAsString());
+ if (isSfiExtensionPresent()) {
+ sb.append(", SFI extension present");
+ }
+ if (isSfiSegmentedData()) {
+ sb.append(", segmented data");
+ }
+ if (isSfiPaddingPresent()) {
+ sb.append(", with padding");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Dump the structured field as hex data to the given {@link PrintStream}.
+ * @param out the {@link PrintStream} to dump to
+ * @throws IOException if an I/O error occurs
+ */
+ public void dump(PrintStream out) throws IOException {
+ out.println(toString());
+ HexDump.dump(getData(), 0, out, 0);
+ }
+
+ /**
+ * Dump the structured field as hex data to <code>System.out</code>.
+ * @throws IOException if an I/O error occurs
+ */
+ public void dump() throws IOException {
+ dump(System.out);
+ }
+
+ /**
+ * Returns type code function name for this field.
+ * @return the type code function name
+ */
+ public String getTypeCodeAsString() {
+ switch ((int)getSfTypeCode() & 0xFF) {
+ case 0xA0: return "Attribute";
+ case 0xA2: return "CopyCount";
+ case 0xA6: return "Descriptor";
+ case 0xA7: return "Control";
+ case 0xA8: return "Begin";
+ case 0xA9: return "End";
+ case 0xAB: return "Map";
+ case 0xAC: return "Position";
+ case 0xAD: return "Process";
+ case 0xAF: return "Include";
+ case 0xB0: return "Table";
+ case 0xB1: return "Migration";
+ case 0xB2: return "Variable";
+ case 0xB4: return "Link";
+ case 0xEE: return "Data";
+ default: return "Unknown:" + Integer.toHexString((int)getSfTypeCode()).toUpperCase();
+ }
+ }
+
+ /**
+ * Returns category code function name for this field.
+ * @return the category code function name
+ */
+ public String getCategoryCodeAsString() {
+ switch ((int)getSfCategoryCode() & 0xFF) {
+ case 0x5F: return "Page Segment";
+ case 0x6B: return "Object Area";
+ case 0x77: return "Color Attribute Table";
+ case 0x7B: return "IM Image";
+ case 0x88: return "Medium";
+ case 0x89: return "Font";
+ case 0x8A: return "Coded Font";
+ case 0x90: return "Process Element";
+ case 0x92: return "Object Container";
+ case 0x9B: return "Presentation Text";
+ case 0xA7: return "Index";
+ case 0xA8: return "Document";
+ case 0xAD: return "Page Group";
+ case 0xAF: return "Page";
+ case 0xBB: return "Graphics";
+ case 0xC3: return "Data Resource";
+ case 0xC4: return "Document Environment Group (DEG)";
+ case 0xC6: return "Resource Group";
+ case 0xC7: return "Object Environment Group (OEG)";
+ case 0xC9: return "Active Environment Group (AEG)";
+ case 0xCC: return "Medium Map";
+ case 0xCD: return "Form Map";
+ case 0xCE: return "Name Resource";
+ case 0xD8: return "Page Overlay";
+ case 0xD9: return "Resource Environment Group (REG)";
+ case 0xDF: return "Overlay";
+ case 0xEA: return "Data Supression";
+ case 0xEB: return "Bar Code";
+ case 0xEE: return "No Operation";
+ case 0xFB: return "Image";
+ default: return "Unknown:" + Integer.toHexString((int)getSfTypeCode()).toUpperCase();
+ }
+ }
+
+ /**
+ * Returns the structured field's length.
+ * @return the field length
+ */
+ public short getSfLength() {
+ return this.sfLength;
+ }
+
+ /**
+ * Returns the structured field's identifier.
+ * @return the field identifier
+ */
+ public int getSfTypeID() {
+ return ((getSfClassCode() & 0xFF) << 16)
+ | ((getSfTypeCode() & 0xFF) << 8)
+ | (getSfCategoryCode() & 0xFF);
+ }
+
+ /**
+ * Returns the structured field's class code.
+ * @return the field class code
+ */
+ public byte getSfClassCode() {
+ return this.sfClassCode;
+ }
+
+ /**
+ * Returns the structured field's type code.
+ * @return the type code
+ */
+ public byte getSfTypeCode() {
+ return this.sfTypeCode;
+ }
+
+ /**
+ * Returns the structured field's category code.
+ * @return the sfCategoryCode
+ */
+ public byte getSfCategoryCode() {
+ return this.sfCategoryCode;
+ }
+
+ /**
+ * Indicates whether an field introducer extension is present.
+ * @return true if an field introducer extension is present
+ */
+ public boolean isSfiExtensionPresent() {
+ return this.sfiExtensionPresent && (this.extData != null);
+ }
+
+ /**
+ * Indicates whether segmented data is present.
+ * @return true if the data is segmented
+ */
+ public boolean isSfiSegmentedData() {
+ return this.sfiSegmentedData;
+ }
+
+ /**
+ * Indicates whether the data is padded.
+ * @return true if the data is padded
+ */
+ public boolean isSfiPaddingPresent() {
+ return this.sfiPaddingPresent;
+ }
+
+ /**
+ * Returns the length of the extension if present.
+ * @return the length of the extension (or 0 if no extension is present)
+ */
+ public short getExtLength() {
+ return this.extLength;
+ }
+
+ /**
+ * Returns the extension data if present.
+ * @return the extension data (or null if no extension is present)
+ */
+ public byte[] getExtData() {
+ return this.extData;
+ }
+
+ /**
+ * Returns the structured field's payload.
+ * @return the field's data
+ */
+ public byte[] getData() {
+ return this.data;
+ }
+
+ /**
+ * Returns the structured field's introducer data.
+ * @return the introducer data
+ */
+ public byte[] getIntroducerData() {
+ return this.introducerData;
+ }
+
+ /**
+ * Returns the complete structured field as a byte array.
+ * @return the complete field data
+ */
+ public byte[] getCompleteFieldAsBytes() {
+ int len = INTRODUCER_LENGTH;
+ if (isSfiExtensionPresent()) {
+ len += getExtLength();
+ }
+ len += getData().length;
+ byte[] bytes = new byte[len];
+ int pos = 0;
+ System.arraycopy(getIntroducerData(), 0, bytes, pos, INTRODUCER_LENGTH);
+ pos += INTRODUCER_LENGTH;
+ if (isSfiExtensionPresent()) {
+ System.arraycopy(getExtData(), 0, bytes, pos, getExtLength());
+ pos += getExtLength();
+ }
+ System.arraycopy(getData(), 0, bytes, pos, getData().length);
+ return bytes;
+ }
+
+ /**
+ * Writes this structured field to the given {@link OutputStream}.
+ * @param out the output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public void writeTo(OutputStream out) throws IOException {
+ out.write(this.introducerData);
+ if (isSfiExtensionPresent()) {
+ out.write(this.extData);
+ }
+ out.write(this.data);
+ }
+}
diff --git a/src/java/org/apache/fop/afp/util/AFPResourceUtil.java b/src/java/org/apache/fop/afp/util/AFPResourceUtil.java
new file mode 100644
index 000000000..ebb318046
--- /dev/null
+++ b/src/java/org/apache/fop/afp/util/AFPResourceUtil.java
@@ -0,0 +1,214 @@
+/*
+ * 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.afp.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Collection;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.fop.afp.AFPConstants;
+import org.apache.fop.afp.modca.ResourceObject;
+import org.apache.fop.afp.modca.AbstractAFPObject.Category;
+import org.apache.fop.afp.parser.MODCAParser;
+import org.apache.fop.afp.parser.UnparsedStructuredField;
+
+/**
+ * TODO better docs
+ * Utility for AFP resource handling
+ *
+ *
+ * A utility class to read structured fields from a MO:DCA document. Each
+ * component of a mixed object document is explicitly defined and delimited
+ * in the data. This is accomplished through the use of MO:DCA data structures,
+ * called structured fields. Structured fields are used to envelop document
+ * components and to provide commands and information to applications using
+ * the data. Structured fields may contain one or more parameters. Each
+ * parameter provides one value from a set of values defined by the architecture.
+ * <p/>
+ * MO:DCA structured fields consist of two parts: an introducer that identifies
+ * the length and type of the structured field, and data that provides the
+ * structured field's effect. The data is contained in a set of parameters,
+ * which can consist of other data structures and data elements. The maximum
+ * length of a structured field is 32767 bytes.
+ * <p/>
+ */
+public final class AFPResourceUtil {
+
+ private static final byte TYPE_CODE_BEGIN = (byte)(0xA8 & 0xFF);
+ private static final byte TYPE_CODE_END = (byte)(0xA9 & 0xFF);
+
+ private static final Log LOG = LogFactory.getLog(AFPResourceUtil.class);
+
+ private AFPResourceUtil() {
+ //nop
+ }
+
+ /**
+ * Get the next structured field as identified by the identifier
+ * parameter (this must be a valid MO:DCA structured field).
+ * @param identifier the three byte identifier
+ * @param inputStream the inputStream
+ * @throws IOException if an I/O exception occurred
+ * @return the next structured field or null when there are no more
+ */
+ public static byte[] getNext(byte[] identifier, InputStream inputStream) throws IOException {
+ MODCAParser parser = new MODCAParser(inputStream);
+ while (true) {
+ UnparsedStructuredField field = parser.readNextStructuredField();
+ if (field == null) {
+ return null;
+ }
+ if (field.getSfClassCode() == identifier[0]
+ && field.getSfTypeCode() == identifier[1]
+ && field.getSfCategoryCode() == identifier[2]) {
+ return field.getCompleteFieldAsBytes();
+ }
+ }
+ }
+
+ private static String getResourceName(UnparsedStructuredField field)
+ throws UnsupportedEncodingException {
+ //The first 8 bytes of the field data represent the resource name
+ byte[] nameBytes = new byte[8];
+ System.arraycopy(field.getData(), 0, nameBytes, 0, 8);
+ String asciiName;
+ asciiName = new String(nameBytes, AFPConstants.EBCIDIC_ENCODING);
+ return asciiName;
+ }
+
+ /**
+ * Copy a complete resource file to a given {@link OutputStream}.
+ * @param in external resource input
+ * @param out output destination
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copyResourceFile(final InputStream in, OutputStream out)
+ throws IOException {
+ MODCAParser parser = new MODCAParser(in);
+ while (true) {
+ UnparsedStructuredField field = parser.readNextStructuredField();
+ if (field == null) {
+ break;
+ }
+ out.write(MODCAParser.CARRIAGE_CONTROL_CHAR);
+ field.writeTo(out);
+ }
+ }
+
+ /**
+ * Copy a named resource to a given {@link OutputStream}. The MO:DCA fields read from the
+ * {@link InputStream} are scanned for the resource with the given name.
+ * @param name name of structured field
+ * @param in external resource input
+ * @param out output destination
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copyNamedResource(String name,
+ final InputStream in, final OutputStream out) throws IOException {
+ final MODCAParser parser = new MODCAParser(in);
+ Collection resourceNames = new java.util.HashSet();
+
+ //Find matching "Begin" field
+ final UnparsedStructuredField fieldBegin;
+ while (true) {
+ UnparsedStructuredField field = parser.readNextStructuredField();
+ if (field == null) {
+ throw new IOException("Requested resource '" + name
+ + "' not found. Encountered resource names: " + resourceNames);
+ }
+
+ if (field.getSfTypeCode() != TYPE_CODE_BEGIN) { //0xA8=Begin
+ continue; //Not a "Begin" field
+ }
+ String resourceName = getResourceName(field);
+ resourceNames.add(resourceName);
+ if (resourceName.equals(name)) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Start of requested structured field found:\n"
+ + field);
+ }
+ fieldBegin = field;
+ break; //Name doesn't match
+ }
+ }
+
+ //Decide whether the resource file has to be wrapped in a resource object
+ boolean wrapInResource;
+ if (fieldBegin.getSfCategoryCode() == Category.PAGE_SEGMENT) {
+ //A naked page segment must be wrapped in a resource object
+ wrapInResource = true;
+ } else if (fieldBegin.getSfCategoryCode() == Category.NAME_RESOURCE) {
+ //A resource object can be copied directly
+ wrapInResource = false;
+ } else {
+ throw new IOException("Cannot handle resource: " + fieldBegin);
+ }
+
+ //Copy structured fields (wrapped or as is)
+ if (wrapInResource) {
+ ResourceObject resourceObject = new ResourceObject(name) {
+ protected void writeContent(OutputStream os) throws IOException {
+ copyStructuredFields(name, fieldBegin, parser, out);
+ }
+ };
+ resourceObject.setType(ResourceObject.TYPE_PAGE_SEGMENT);
+ resourceObject.writeToStream(out);
+ } else {
+ copyStructuredFields(name, fieldBegin, parser, out);
+ }
+ }
+
+ private static void copyStructuredFields(String name, UnparsedStructuredField fieldBegin,
+ MODCAParser parser, OutputStream out) throws IOException {
+ boolean inRequestedResource;
+
+ //The "Begin" field first
+ out.write(MODCAParser.CARRIAGE_CONTROL_CHAR);
+ fieldBegin.writeTo(out);
+ UnparsedStructuredField field;
+
+ //Then the rest of the fields until the corresponding "End" field
+ inRequestedResource = true;
+ do {
+ field = parser.readNextStructuredField();
+ if (field == null) {
+ break; //Unexpected EOF
+ }
+
+ if (field.getSfTypeCode() == TYPE_CODE_END) {
+ String resourceName = getResourceName(field);
+ if (resourceName.equals(name)) {
+ inRequestedResource = false; //Signal end of loop
+ }
+ }
+ out.write(MODCAParser.CARRIAGE_CONTROL_CHAR);
+ field.writeTo(out);
+ } while (inRequestedResource);
+ if (inRequestedResource) {
+ throw new IOException("Ending structured field not found for resource " + name);
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/afp/util/StructuredFieldReader.java b/src/java/org/apache/fop/afp/util/StructuredFieldReader.java
index 34add3bbe..1fc6d8369 100644
--- a/src/java/org/apache/fop/afp/util/StructuredFieldReader.java
+++ b/src/java/org/apache/fop/afp/util/StructuredFieldReader.java
@@ -54,80 +54,27 @@ public class StructuredFieldReader {
}
/**
- * Get the next structured field as identified by the identifer
- * parameter (this must be a valid MO:DCA structured field.
+ * Get the next structured field as identified by the identifier
+ * parameter (this must be a valid MO:DCA structured field).
+ * Note: The returned data does not include the field length and identifier!
* @param identifier the three byte identifier
* @throws IOException if an I/O exception occurred
* @return the next structured field or null when there are no more
*/
public byte[] getNext(byte[] identifier) throws IOException {
- int bufferPointer = 0;
- byte[] bufferData = new byte[identifier.length + 2];
- for (int x = 0; x < identifier.length; x++) {
- bufferData[x] = 0x00;
- }
-
- int c;
- while ((c = inputStream.read()) > -1) {
-
- bufferData[bufferPointer] = (byte) c;
-
- // Check the last characters in the buffer
- int index = 0;
- boolean found = true;
-
- for (int i = identifier.length - 1; i > -1; i--) {
-
- int p = bufferPointer - index;
- if (p < 0) {
- p = bufferData.length + p;
- }
-
- index++;
-
- if (identifier[i] != bufferData[p]) {
- found = false;
- break;
- }
-
- }
-
- if (found) {
-
- byte[] length = new byte[2];
-
- int a = bufferPointer - identifier.length;
- if (a < 0) {
- a = bufferData.length + a;
- }
-
- int b = bufferPointer - identifier.length - 1;
- if (b < 0) {
- b = bufferData.length + b;
- }
-
- length[0] = bufferData[b];
- length[1] = bufferData[a];
-
- int reclength = ((length[0] & 0xFF) << 8)
- + (length[1] & 0xFF) - identifier.length - 2;
-
- byte[] retval = new byte[reclength];
-
- inputStream.read(retval, 0, reclength);
-
- return retval;
-
- }
-
- bufferPointer++;
- if (bufferPointer >= bufferData.length) {
- bufferPointer = 0;
- }
+ byte[] bytes = AFPResourceUtil.getNext(identifier, this.inputStream);
+ if (bytes != null) {
+ //Users of this class expect the field data without length and identifier
+ int srcPos = 2 + identifier.length;
+ byte[] tmp = new byte[bytes.length - srcPos];
+ System.arraycopy(bytes, srcPos, tmp, 0, tmp.length);
+ bytes = tmp;
}
- return null;
+ return bytes;
+
}
+
}
diff --git a/src/java/org/apache/fop/apps/FopFactory.java b/src/java/org/apache/fop/apps/FopFactory.java
index 907895c99..7bcdd2703 100644
--- a/src/java/org/apache/fop/apps/FopFactory.java
+++ b/src/java/org/apache/fop/apps/FopFactory.java
@@ -26,6 +26,8 @@ import java.io.OutputStream;
import java.net.MalformedURLException;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
import javax.xml.transform.Source;
@@ -109,6 +111,11 @@ public class FopFactory implements ImageContext {
private String hyphenBase = null;
/**
+ * Map of configured names of hyphenation pattern file names: ll_CC => name
+ */
+ private Map/*<String,String>*/ hyphPatNames = null;
+
+ /**
* FOP has the ability, for some FO's, to continue processing even if the
* input XSL violates that FO's content model. This is the default
* behavior for FOP. However, this flag, if set, provides the user the
@@ -407,6 +414,23 @@ public class FopFactory implements ImageContext {
}
/**
+ * @return the hyphPatNames
+ */
+ public Map getHyphPatNames() {
+ return hyphPatNames;
+ }
+
+ /**
+ * @param hyphPatNames the hyphPatNames to set
+ */
+ public void setHyphPatNames(Map hyphPatNames) {
+ if (hyphPatNames == null) {
+ hyphPatNames = new HashMap();
+ }
+ this.hyphPatNames = hyphPatNames;
+ }
+
+ /**
* Sets the URI Resolver. It is used for resolving factory-level URIs like hyphenation
* patterns and as backup for URI resolution performed during a rendering run.
* @param uriResolver the new URI resolver
diff --git a/src/java/org/apache/fop/apps/FopFactoryConfigurator.java b/src/java/org/apache/fop/apps/FopFactoryConfigurator.java
index e46530177..ad0869ea1 100644
--- a/src/java/org/apache/fop/apps/FopFactoryConfigurator.java
+++ b/src/java/org/apache/fop/apps/FopFactoryConfigurator.java
@@ -22,6 +22,8 @@ package org.apache.fop.apps;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
+import java.util.HashMap;
+import java.util.Map;
import org.xml.sax.SAXException;
@@ -35,6 +37,7 @@ import org.apache.xmlgraphics.image.loader.spi.ImageImplRegistry;
import org.apache.xmlgraphics.image.loader.util.Penalty;
import org.apache.fop.fonts.FontManagerConfigurator;
+import org.apache.fop.hyphenation.HyphenationTreeCache;
import org.apache.fop.util.LogUtil;
/**
@@ -89,20 +92,7 @@ public class FopFactoryConfigurator {
* @param factory fop factory
* @throws FOPException fop exception
*/
- public void configure(FopFactory factory) throws FOPException {
- if (log.isDebugEnabled()) {
- log.debug("Initializing FopFactory Configuration");
- }
-
- if (cfg.getChild("accessibility", false) != null) {
- try {
- this.factory.setAccessibility(
- cfg.getChild("accessibility").getValueAsBoolean());
- } catch (ConfigurationException e) {
- throw new FOPException(e);
- }
- }
-
+ public void configure(FopFactory factory) throws FOPException { // CSOK: MethodLength
// strict configuration
if (cfg.getChild("strict-configuration", false) != null) {
try {
@@ -113,6 +103,19 @@ public class FopFactoryConfigurator {
}
}
boolean strict = factory.validateUserConfigStrictly();
+ if (log.isDebugEnabled()) {
+ log.debug("Initializing FopFactory Configuration"
+ + "with " + (strict ? "strict" : "permissive") + " validation");
+ }
+
+ if (cfg.getChild("accessibility", false) != null) {
+ try {
+ this.factory.setAccessibility(
+ cfg.getChild("accessibility").getValueAsBoolean());
+ } catch (ConfigurationException e) {
+ LogUtil.handleException(log, e, strict);
+ }
+ }
// strict fo validation
if (cfg.getChild("strict-validation", false) != null) {
@@ -142,6 +145,64 @@ public class FopFactoryConfigurator {
}
}
+ /**
+ * Read configuration elements hyphenation-pattern,
+ * construct a map ll_CC => filename, and set it on the factory
+ */
+ Configuration[] hyphPatConfig = cfg.getChildren("hyphenation-pattern");
+ if (hyphPatConfig.length != 0) {
+ Map/*<String,String>*/ hyphPatNames = new HashMap/*<String,String>*/();
+ for (int i = 0; i < hyphPatConfig.length; ++i) {
+ String lang, country, filename;
+ StringBuffer error = new StringBuffer();
+ String location = hyphPatConfig[i].getLocation();
+
+ lang = hyphPatConfig[i].getAttribute("lang", null);
+ if (lang == null) {
+ addError("The lang attribute of a hyphenation-pattern configuration"
+ + " element must exist (" + location + ")", error);
+ } else if (!lang.matches("[a-zA-Z]{2}")) {
+ addError("The lang attribute of a hyphenation-pattern configuration"
+ + " element must consist of exactly two letters ("
+ + location + ")", error);
+ }
+ lang = lang.toLowerCase();
+
+ country = hyphPatConfig[i].getAttribute("country", null);
+ if ("".equals(country)) {
+ country = null;
+ }
+ if (country != null) {
+ if (!country.matches("[a-zA-Z]{2}")) {
+ addError("The country attribute of a hyphenation-pattern configuration"
+ + " element must consist of exactly two letters ("
+ + location + ")", error);
+ }
+ country = country.toUpperCase();
+ }
+
+ filename = hyphPatConfig[i].getValue(null);
+ if (filename == null) {
+ addError("The value of a hyphenation-pattern configuration"
+ + " element may not be empty (" + location + ")", error);
+ }
+
+ if (error.length() != 0) {
+ LogUtil.handleError(log, error.toString(), strict);
+ continue;
+ }
+
+ String llccKey = HyphenationTreeCache.constructLlccKey(lang, country);
+ hyphPatNames.put(llccKey, filename);
+ if (log.isDebugEnabled()) {
+ log.debug("Using hyphenation pattern filename " + filename
+ + " for lang=\"" + lang + "\""
+ + (country != null ? ", country=\"" + country + "\"" : ""));
+ }
+ }
+ factory.setHyphPatNames(hyphPatNames);
+ }
+
// renderer options
if (cfg.getChild("source-resolution", false) != null) {
factory.setSourceResolution(
@@ -203,6 +264,13 @@ public class FopFactoryConfigurator {
configureImageLoading(cfg.getChild("image-loading", false), strict);
}
+ private static void addError(String message, StringBuffer error) {
+ if (error.length() != 0) {
+ error.append(". ");
+ }
+ error.append(message);
+ }
+
private void configureImageLoading(Configuration parent, boolean strict) throws FOPException {
if (parent == null) {
return;
diff --git a/src/java/org/apache/fop/area/PageViewport.java b/src/java/org/apache/fop/area/PageViewport.java
index 63740386e..bccae8754 100644
--- a/src/java/org/apache/fop/area/PageViewport.java
+++ b/src/java/org/apache/fop/area/PageViewport.java
@@ -95,8 +95,10 @@ public class PageViewport extends AreaTreeObject implements Resolvable, Cloneabl
* @param pageNumber the page number
* @param pageStr String representation of the page number
* @param blank true if this is a blank page
+ * @param spanAll true if the first span area spans all columns
*/
- public PageViewport(SimplePageMaster spm, int pageNumber, String pageStr, boolean blank) {
+ public PageViewport(SimplePageMaster spm, int pageNumber, String pageStr,
+ boolean blank, boolean spanAll) {
this.simplePageMasterName = spm.getMasterName();
setExtensionAttachments(spm.getExtensionAttachments());
setForeignAttributes(spm.getForeignAttributes());
@@ -107,7 +109,18 @@ public class PageViewport extends AreaTreeObject implements Resolvable, Cloneabl
this.pageNumberString = pageStr;
this.viewArea = new Rectangle(0, 0, pageWidth, pageHeight);
this.page = new Page(spm);
- createSpan(false);
+ createSpan(spanAll);
+ }
+
+ /**
+ * Create a page viewport.
+ * @param spm SimplePageMaster indicating the page and region dimensions
+ * @param pageNumber the page number
+ * @param pageStr String representation of the page number
+ * @param blank true if this is a blank page
+ */
+ public PageViewport(SimplePageMaster spm, int pageNumber, String pageStr, boolean blank) {
+ this(spm, pageNumber, pageStr, blank, false);
}
/**
diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java
index 6b4ec1a1d..2a5c0d272 100644
--- a/src/java/org/apache/fop/cli/CommandLineOptions.java
+++ b/src/java/org/apache/fop/cli/CommandLineOptions.java
@@ -1231,7 +1231,7 @@ public class CommandLineOptions {
+ " -out mime outfile input will be rendered using the given MIME type\n"
+ " (outfile req'd) Example: \"-out application/pdf D:\\out.pdf\"\n"
+ " (Tip: \"-out list\" prints the list of supported MIME types"
- + " and exits)\n"
+ + " and exits)\n"
//+ " -mif outfile input will be rendered as MIF (FrameMaker) (outfile req'd)\n"
//+ " Experimental feature - requires additional fop-sandbox.jar.\n"
+ " -svg outfile input will be rendered as an SVG slides file (outfile req'd) \n"
diff --git a/src/java/org/apache/fop/datatypes/Numeric.java b/src/java/org/apache/fop/datatypes/Numeric.java
index c26cacd7c..2004c6721 100644
--- a/src/java/org/apache/fop/datatypes/Numeric.java
+++ b/src/java/org/apache/fop/datatypes/Numeric.java
@@ -29,15 +29,15 @@ import org.apache.fop.fo.expr.PropertyException;
* Numerics can be either absolute or relative. Relative numerics
* must be resolved against base value before the value can be used.
* <p>
- * To support relative numerics internally in the expresion parser and
- * during evaulation one additional methods exists: isAbsolute() which
+ * To support relative numerics internally in the expression parser and
+ * during evaluation one additional methods exists: isAbsolute() which
* return true for absolute numerics and false for relative numerics.
*/
public interface Numeric {
/**
* Return the value of this Numeric
* @return the computed value.
- * @throws PropertyException if a propert exception occurs
+ * @throws PropertyException if a property exception occurs
*/
double getNumericValue() throws PropertyException;
@@ -45,7 +45,7 @@ public interface Numeric {
* Return the value of this Numeric
* @param context The context for the length calculation (for percentage based lengths)
* @return the computed value.
- * @throws PropertyException if a propert exception occurs
+ * @throws PropertyException if a property exception occurs
*/
double getNumericValue(PercentBaseContext context) throws PropertyException;
@@ -78,9 +78,9 @@ public interface Numeric {
int getValue(PercentBaseContext context);
/**
- * Return the resolved value. This method will becalled during evaluation
+ * Return the resolved value. This method will be called during evaluation
* of the expression tree and relative numerics can then return a
- * resolved absolute Numeric. Absolute numerics can just return themself.
+ * resolved absolute Numeric. Absolute numerics can just return themselves.
*
* @return A resolved value.
* @throws PropertyException
diff --git a/src/java/org/apache/fop/fo/expr/NumericOp.java b/src/java/org/apache/fop/fo/expr/NumericOp.java
index d1f91d509..a2b203330 100644
--- a/src/java/org/apache/fop/fo/expr/NumericOp.java
+++ b/src/java/org/apache/fop/fo/expr/NumericOp.java
@@ -19,8 +19,8 @@
package org.apache.fop.fo.expr;
-import org.apache.fop.datatypes.PercentBaseContext;
import org.apache.fop.datatypes.Numeric;
+import org.apache.fop.datatypes.PercentBaseContext;
/**
* This class contains static methods to evaluate operations on Numeric
@@ -43,8 +43,7 @@ public final class NumericOp {
* @throws PropertyException If the dimension of the operand is different
* from the dimension of this Numeric.
*/
- public static Numeric addition(Numeric op1, Numeric op2)
- throws PropertyException {
+ public static Numeric addition(Numeric op1, Numeric op2) throws PropertyException {
if (op1.isAbsolute() && op2.isAbsolute()) {
return addition2(op1, op2, null);
} else {
@@ -80,8 +79,7 @@ public final class NumericOp {
* @throws PropertyException If the dimension of the operand is different
* from the dimension of this Numeric.
*/
- public static Numeric subtraction(Numeric op1, Numeric op2)
- throws PropertyException {
+ public static Numeric subtraction(Numeric op1, Numeric op2) throws PropertyException {
if (op1.isAbsolute() && op2.isAbsolute()) {
return subtraction2(op1, op2, null);
} else {
@@ -100,7 +98,7 @@ public final class NumericOp {
* from the dimension of this Numeric.
*/
public static Numeric subtraction2(Numeric op1, Numeric op2, PercentBaseContext context)
- throws PropertyException {
+ throws PropertyException {
if (op1.getDimension() != op2.getDimension()) {
throw new PropertyException("Can't subtract Numerics of different dimensions");
}
@@ -117,8 +115,7 @@ public final class NumericOp {
* @throws PropertyException If the dimension of the operand is different
* from the dimension of this Numeric.
*/
- public static Numeric multiply(Numeric op1, Numeric op2)
- throws PropertyException {
+ public static Numeric multiply(Numeric op1, Numeric op2) throws PropertyException {
if (op1.isAbsolute() && op2.isAbsolute()) {
return multiply2(op1, op2, null);
} else {
@@ -137,7 +134,7 @@ public final class NumericOp {
* from the dimension of this Numeric.
*/
public static Numeric multiply2(Numeric op1, Numeric op2, PercentBaseContext context)
- throws PropertyException {
+ throws PropertyException {
return numeric(op1.getNumericValue(context) * op2.getNumericValue(context),
op1.getDimension() + op2.getDimension());
}
@@ -171,7 +168,7 @@ public final class NumericOp {
* from the dimension of this Numeric.
*/
public static Numeric divide2(Numeric op1, Numeric op2, PercentBaseContext context)
- throws PropertyException {
+ throws PropertyException {
return numeric(op1.getNumericValue(context) / op2.getNumericValue(context),
op1.getDimension() - op2.getDimension());
}
@@ -183,8 +180,7 @@ public final class NumericOp {
* @return A new Numeric object representing the absolute value.
* @throws PropertyException if a property exception occurs
*/
- public static Numeric modulo(Numeric op1, Numeric op2)
- throws PropertyException {
+ public static Numeric modulo(Numeric op1, Numeric op2) throws PropertyException {
if (op1.isAbsolute() && op2.isAbsolute()) {
return modulo2(op1, op2, null);
} else {
@@ -202,7 +198,7 @@ public final class NumericOp {
* from the dimension of this Numeric.
*/
public static Numeric modulo2(Numeric op1, Numeric op2, PercentBaseContext context)
- throws PropertyException {
+ throws PropertyException {
return numeric(op1.getNumericValue(context)
% op2.getNumericValue(context), op1.getDimension());
}
@@ -213,8 +209,7 @@ public final class NumericOp {
* @return a new Numeric object representing the absolute value of the operand.
* @throws PropertyException if a property exception occurs
*/
- public static Numeric abs(Numeric op)
- throws PropertyException {
+ public static Numeric abs(Numeric op) throws PropertyException {
if (op.isAbsolute()) {
return abs2(op, null);
} else {
@@ -230,8 +225,7 @@ public final class NumericOp {
* @throws PropertyException If the dimension of the operand is different
* from the dimension of this Numeric.
*/
- public static Numeric abs2(Numeric op, PercentBaseContext context)
- throws PropertyException {
+ public static Numeric abs2(Numeric op, PercentBaseContext context) throws PropertyException {
return numeric(Math.abs(op.getNumericValue(context)), op.getDimension());
}
@@ -241,8 +235,7 @@ public final class NumericOp {
* @return a new Numeric object representing the negation of the operand.
* @throws PropertyException if a property exception occurs
*/
- public static Numeric negate(Numeric op)
- throws PropertyException {
+ public static Numeric negate(Numeric op) throws PropertyException {
if (op.isAbsolute()) {
return negate2(op, null);
} else {
@@ -259,8 +252,7 @@ public final class NumericOp {
* @throws PropertyException If the dimension of the operand is different
* from the dimension of this Numeric.
*/
- public static Numeric negate2(Numeric op, PercentBaseContext context)
- throws PropertyException {
+ public static Numeric negate2(Numeric op, PercentBaseContext context) throws PropertyException {
return numeric(-op.getNumericValue(context), op.getDimension());
}
@@ -271,8 +263,7 @@ public final class NumericOp {
* @return a Numeric which is the maximum of the two operands.
* @throws PropertyException if the dimensions or value types of the operands are different.
*/
- public static Numeric max(Numeric op1, Numeric op2)
- throws PropertyException {
+ public static Numeric max(Numeric op1, Numeric op2) throws PropertyException {
if (op1.isAbsolute() && op2.isAbsolute()) {
return max2(op1, op2, null);
} else {
@@ -290,7 +281,7 @@ public final class NumericOp {
* from the dimension of this Numeric.
*/
public static Numeric max2(Numeric op1, Numeric op2, PercentBaseContext context)
- throws PropertyException {
+ throws PropertyException {
if (op1.getDimension() != op2.getDimension()) {
throw new PropertyException("Arguments to max() must have same dimensions");
}
@@ -304,8 +295,7 @@ public final class NumericOp {
* @return a Numeric which is the minimum of the two operands.
* @throws PropertyException if the dimensions or value types of the operands are different.
*/
- public static Numeric min(Numeric op1, Numeric op2)
- throws PropertyException {
+ public static Numeric min(Numeric op1, Numeric op2) throws PropertyException {
if (op1.isAbsolute() && op2.isAbsolute()) {
return min2(op1, op2, null);
} else {
@@ -323,7 +313,7 @@ public final class NumericOp {
* from the dimension of this Numeric.
*/
public static Numeric min2(Numeric op1, Numeric op2, PercentBaseContext context)
- throws PropertyException {
+ throws PropertyException {
if (op1.getDimension() != op2.getDimension()) {
throw new PropertyException("Arguments to min() must have same dimensions");
}
diff --git a/src/java/org/apache/fop/fo/flow/table/TableFObj.java b/src/java/org/apache/fop/fo/flow/table/TableFObj.java
index 6ba763933..fce82dcff 100644
--- a/src/java/org/apache/fop/fo/flow/table/TableFObj.java
+++ b/src/java/org/apache/fop/fo/flow/table/TableFObj.java
@@ -217,11 +217,10 @@ public abstract class TableFObj extends FObj implements StructurePointerProperty
*/
i = 1;
}
- TableEventProducer eventProducer
- = TableEventProducer.Provider.get(fo.getUserAgent().getEventBroadcaster());
- eventProducer.forceNextColumnNumber
- (this, propertyList.getFObj().getName(),
- val, i, propertyList.getFObj().getLocator());
+ TableEventProducer eventProducer = TableEventProducer.Provider.get(
+ fo.getUserAgent().getEventBroadcaster());
+ eventProducer.forceNextColumnNumber(this, propertyList.getFObj().getName(),
+ val, i, propertyList.getFObj().getLocator());
}
return NumberProperty.getInstance(i);
}
@@ -231,9 +230,8 @@ public abstract class TableFObj extends FObj implements StructurePointerProperty
}
/** {@inheritDoc} */
- public void processNode
- (String elementName, Locator locator, Attributes attlist, PropertyList pList)
- throws FOPException {
+ public void processNode(String elementName, Locator locator, Attributes attlist,
+ PropertyList pList) throws FOPException {
super.processNode(elementName, locator, attlist, pList);
Table table = getTable();
if (!inMarker() && !table.isSeparateBorderModel()) {
diff --git a/src/java/org/apache/fop/fo/pagination/Root.java b/src/java/org/apache/fop/fo/pagination/Root.java
index 2a634c24a..8f8e0a509 100644
--- a/src/java/org/apache/fop/fo/pagination/Root.java
+++ b/src/java/org/apache/fop/fo/pagination/Root.java
@@ -212,7 +212,7 @@ public class Root extends FObj {
* @throws IllegalArgumentException for negative additional page counts
*/
public void notifyPageSequenceFinished(int lastPageNumber, int additionalPages)
- throws IllegalArgumentException {
+ throws IllegalArgumentException {
if (additionalPages >= 0) {
totalPagesGenerated += additionalPages;
diff --git a/src/java/org/apache/fop/fo/properties/BackgroundPositionShorthand.java b/src/java/org/apache/fop/fo/properties/BackgroundPositionShorthand.java
index 58f1ac210..3c0118181 100644
--- a/src/java/org/apache/fop/fo/properties/BackgroundPositionShorthand.java
+++ b/src/java/org/apache/fop/fo/properties/BackgroundPositionShorthand.java
@@ -58,7 +58,7 @@ public class BackgroundPositionShorthand extends ListProperty {
* to "50%".
*/
public Property make(PropertyList propertyList, String value, FObj fo)
- throws PropertyException {
+ throws PropertyException {
Property p = super.make(propertyList, value, fo);
if (p.getList().size() == 1) {
/* only background-position-horizontal specified
diff --git a/src/java/org/apache/fop/fo/properties/BorderWidthPropertyMaker.java b/src/java/org/apache/fop/fo/properties/BorderWidthPropertyMaker.java
index 467682878..d2bab22ab 100644
--- a/src/java/org/apache/fop/fo/properties/BorderWidthPropertyMaker.java
+++ b/src/java/org/apache/fop/fo/properties/BorderWidthPropertyMaker.java
@@ -54,9 +54,8 @@ public class BorderWidthPropertyMaker extends LengthProperty.Maker {
* {@inheritDoc}
*/
- public Property get(int subpropId, PropertyList propertyList,
- boolean bTryInherit, boolean bTryDefault)
- throws PropertyException {
+ public Property get(int subpropId, PropertyList propertyList, boolean bTryInherit,
+ boolean bTryDefault) throws PropertyException {
Property p = super.get(subpropId, propertyList,
bTryInherit, bTryDefault);
diff --git a/src/java/org/apache/fop/fo/properties/ColorProperty.java b/src/java/org/apache/fop/fo/properties/ColorProperty.java
index e7b8d5931..293f31577 100644
--- a/src/java/org/apache/fop/fo/properties/ColorProperty.java
+++ b/src/java/org/apache/fop/fo/properties/ColorProperty.java
@@ -99,7 +99,7 @@ public final class ColorProperty extends Property {
* @see ColorUtil#parseColorString(FOUserAgent, String)
*/
public static ColorProperty getInstance(FOUserAgent foUserAgent, String value)
- throws PropertyException {
+ throws PropertyException {
ColorProperty instance = new ColorProperty(
ColorUtil.parseColorString(
foUserAgent, value));
diff --git a/src/java/org/apache/fop/fo/properties/CommonHyphenation.java b/src/java/org/apache/fop/fo/properties/CommonHyphenation.java
index 65b2cebbd..7b9b5bc82 100644
--- a/src/java/org/apache/fop/fo/properties/CommonHyphenation.java
+++ b/src/java/org/apache/fop/fo/properties/CommonHyphenation.java
@@ -92,7 +92,7 @@ public final class CommonHyphenation {
* @throws PropertyException if a a property exception occurs
*/
public static CommonHyphenation getInstance(PropertyList propertyList)
- throws PropertyException {
+ throws PropertyException {
StringProperty language
= (StringProperty) propertyList.get(Constants.PR_LANGUAGE);
StringProperty country
diff --git a/src/java/org/apache/fop/fo/properties/CompoundPropertyMaker.java b/src/java/org/apache/fop/fo/properties/CompoundPropertyMaker.java
index 3edb84009..cbd34c9b3 100644
--- a/src/java/org/apache/fop/fo/properties/CompoundPropertyMaker.java
+++ b/src/java/org/apache/fop/fo/properties/CompoundPropertyMaker.java
@@ -139,9 +139,8 @@ public class CompoundPropertyMaker extends PropertyMaker {
* @return the property
* @throws PropertyException if a property exception occurs
*/
- public Property get(int subpropertyId, PropertyList propertyList,
- boolean tryInherit, boolean tryDefault)
- throws PropertyException {
+ public Property get(int subpropertyId, PropertyList propertyList, boolean tryInherit,
+ boolean tryDefault) throws PropertyException {
Property p = super.get(subpropertyId, propertyList, tryInherit, tryDefault);
if (subpropertyId != 0 && p != null) {
p = getSubprop(p, subpropertyId);
@@ -254,7 +253,7 @@ public class CompoundPropertyMaker extends PropertyMaker {
* @throws PropertyException ...
*/
protected Property makeCompound(PropertyList propertyList, FObj parentFO)
- throws PropertyException {
+ throws PropertyException {
Property p = makeNewProperty();
CompoundDatatype data = (CompoundDatatype) p.getObject();
for (int i = 0; i < Constants.COMPOUND_COUNT; i++) {
diff --git a/src/java/org/apache/fop/fo/properties/FontFamilyProperty.java b/src/java/org/apache/fop/fo/properties/FontFamilyProperty.java
index 330101ee7..f6fa806c9 100644
--- a/src/java/org/apache/fop/fo/properties/FontFamilyProperty.java
+++ b/src/java/org/apache/fop/fo/properties/FontFamilyProperty.java
@@ -52,7 +52,7 @@ public final class FontFamilyProperty extends ListProperty {
* {@inheritDoc}
*/
public Property make(PropertyList propertyList, String value, FObj fo)
- throws PropertyException {
+ throws PropertyException {
if ("inherit".equals(value)) {
return super.make(propertyList, value, fo);
} else {
diff --git a/src/java/org/apache/fop/fo/properties/FontSizePropertyMaker.java b/src/java/org/apache/fop/fo/properties/FontSizePropertyMaker.java
index 60ef955ba..72884a177 100644
--- a/src/java/org/apache/fop/fo/properties/FontSizePropertyMaker.java
+++ b/src/java/org/apache/fop/fo/properties/FontSizePropertyMaker.java
@@ -51,7 +51,7 @@ public class FontSizePropertyMaker
* it is immediately replaced by the resolved {@link FixedLength}.
*/
public Property make(PropertyList propertyList, String value, FObj fo)
- throws PropertyException {
+ throws PropertyException {
Property p = super.make(propertyList, value, fo);
if (p instanceof PercentLength) {
Property pp = propertyList.getFromParent(this.propId);
diff --git a/src/java/org/apache/fop/fo/properties/KeepProperty.java b/src/java/org/apache/fop/fo/properties/KeepProperty.java
index 0bc44e459..9d04ce780 100644
--- a/src/java/org/apache/fop/fo/properties/KeepProperty.java
+++ b/src/java/org/apache/fop/fo/properties/KeepProperty.java
@@ -62,7 +62,7 @@ public final class KeepProperty extends Property implements CompoundDatatype {
* {@inheritDoc}
*/
public Property convertProperty(Property p, PropertyList propertyList, FObj fo)
- throws PropertyException {
+ throws PropertyException {
if (p instanceof KeepProperty) {
return p;
}
diff --git a/src/java/org/apache/fop/fo/properties/PageDimensionMaker.java b/src/java/org/apache/fop/fo/properties/PageDimensionMaker.java
index 919dd84d0..c0c6a2ed7 100644
--- a/src/java/org/apache/fop/fo/properties/PageDimensionMaker.java
+++ b/src/java/org/apache/fop/fo/properties/PageDimensionMaker.java
@@ -44,7 +44,7 @@ public class PageDimensionMaker extends LengthProperty.Maker {
* Return the default or user-defined fallback in case the value
* was specified as "auto"
* @param subpropId The subproperty id of the property being retrieved.
- * Is 0 when retriving a base property.
+ * Is 0 when retrieving a base property.
* @param propertyList The PropertyList object being built for this FO.
* @param tryInherit true if inherited properties should be examined.
* @param tryDefault true if the default value should be returned.
diff --git a/src/java/org/apache/fop/fo/properties/ToBeImplementedProperty.java b/src/java/org/apache/fop/fo/properties/ToBeImplementedProperty.java
index 387355623..59a6cafef 100644
--- a/src/java/org/apache/fop/fo/properties/ToBeImplementedProperty.java
+++ b/src/java/org/apache/fop/fo/properties/ToBeImplementedProperty.java
@@ -23,7 +23,7 @@ import org.apache.fop.fo.FObj;
import org.apache.fop.fo.PropertyList;
/**
- * A special property for representing an as yet implemented implemented property.
+ * A special property for representing an as yet unimplemented property.
*/
public class ToBeImplementedProperty extends Property {
diff --git a/src/java/org/apache/fop/fonts/EncodingMode.java b/src/java/org/apache/fop/fonts/EncodingMode.java
index 734292c54..8a40d6593 100644
--- a/src/java/org/apache/fop/fonts/EncodingMode.java
+++ b/src/java/org/apache/fop/fonts/EncodingMode.java
@@ -19,25 +19,19 @@
package org.apache.fop.fonts;
-import java.io.ObjectStreamException;
-import java.io.Serializable;
-
-
/**
* This class enumerates all supported encoding modes for fonts: auto, single-byte and CID.
*/
-public final class EncodingMode implements Serializable {
-
- private static final long serialVersionUID = 8311486102457779529L;
+public enum EncodingMode {
/** Automatic selection of encoding mode. */
- public static final EncodingMode AUTO = new EncodingMode("auto");
+ AUTO("auto"),
/** Single-byte encoding */
- public static final EncodingMode SINGLE_BYTE = new EncodingMode("single-byte");
+ SINGLE_BYTE("single-byte"),
/** CID encoding */
- public static final EncodingMode CID = new EncodingMode("cid");
+ CID("cid");
private String name;
@@ -58,25 +52,18 @@ public final class EncodingMode implements Serializable {
* @param name the name of the encoding mode to look up
* @return the encoding mode constant
*/
- public static EncodingMode valueOf(String name) {
- if (name.equalsIgnoreCase(EncodingMode.AUTO.getName())) {
- return EncodingMode.AUTO;
- } else if (name.equalsIgnoreCase(EncodingMode.SINGLE_BYTE.getName())) {
- return EncodingMode.SINGLE_BYTE;
- } else if (name.equalsIgnoreCase(EncodingMode.CID.getName())) {
- return EncodingMode.CID;
- } else {
- throw new IllegalArgumentException("Invalid encoding mode: " + name);
+ public static EncodingMode getEncodingMode(String name) {
+ for (EncodingMode em : EncodingMode.values()) {
+ if (name.equalsIgnoreCase(em.getName())) {
+ return em;
+ }
}
- }
-
- private Object readResolve() throws ObjectStreamException {
- return valueOf(getName());
+ throw new IllegalArgumentException("Invalid encoding mode: " + name);
}
/** {@inheritDoc} */
public String toString() {
- return "EncodingMode:" + getName();
+ return "EncodingMode: " + getName();
}
}
diff --git a/src/java/org/apache/fop/fonts/FontInfoConfigurator.java b/src/java/org/apache/fop/fonts/FontInfoConfigurator.java
index f8399b110..9a11f84bc 100644
--- a/src/java/org/apache/fop/fonts/FontInfoConfigurator.java
+++ b/src/java/org/apache/fop/fonts/FontInfoConfigurator.java
@@ -254,7 +254,7 @@ public class FontInfoConfigurator {
}
boolean useKerning = fontCfg.getAttributeAsBoolean("kerning", true);
- EncodingMode encodingMode = EncodingMode.valueOf(
+ EncodingMode encodingMode = EncodingMode.getEncodingMode(
fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName()));
EmbedFontInfo embedFontInfo
= new EmbedFontInfo(metricsUrl, useKerning, tripletList, embedUrl, subFont);
diff --git a/src/java/org/apache/fop/hyphenation/HyphenationTreeCache.java b/src/java/org/apache/fop/hyphenation/HyphenationTreeCache.java
index 5831e2b98..40a44a942 100644
--- a/src/java/org/apache/fop/hyphenation/HyphenationTreeCache.java
+++ b/src/java/org/apache/fop/hyphenation/HyphenationTreeCache.java
@@ -20,6 +20,7 @@
package org.apache.fop.hyphenation;
import java.util.Hashtable;
+import java.util.Map;
import java.util.Set;
/**
@@ -39,7 +40,7 @@ public class HyphenationTreeCache {
* @return the HyhenationTree instance or null if it's not in the cache
*/
public HyphenationTree getHyphenationTree(String lang, String country) {
- String key = constructKey(lang, country);
+ String key = constructLlccKey(lang, country);
// first try to find it in the cache
if (hyphenTrees.containsKey(key)) {
@@ -57,7 +58,7 @@ public class HyphenationTreeCache {
* @param country the country (may be null or "none")
* @return the resulting key
*/
- public static String constructKey(String lang, String country) {
+ public static String constructLlccKey(String lang, String country) {
String key = lang;
// check whether the country code has been used
if (country != null && !country.equals("none")) {
@@ -67,6 +68,24 @@ public class HyphenationTreeCache {
}
/**
+ * If the user configured a hyphenation pattern file name
+ * for this (lang,country) value, return it. If not, return null.
+ * @param lang the language
+ * @param country the country (may be null or "none")
+ * @param hyphPatNames the map of user-configured hyphenation pattern file names
+ * @return the hyphenation pattern file name or null
+ */
+ public static String constructUserKey(String lang, String country, Map hyphPatNames) {
+ String userKey = null;
+ if (hyphPatNames != null) {
+ String key = constructLlccKey(lang, country);
+ key.replace('_', '-');
+ userKey = (String) hyphPatNames.get(key);
+ }
+ return userKey;
+ }
+
+ /**
* Cache a hyphenation tree under its key.
* @param key the key (ex. "de_CH" or "en")
* @param hTree the hyphenation tree
diff --git a/src/java/org/apache/fop/hyphenation/Hyphenator.java b/src/java/org/apache/fop/hyphenation/Hyphenator.java
index 230f2ae20..76e8b6327 100644
--- a/src/java/org/apache/fop/hyphenation/Hyphenator.java
+++ b/src/java/org/apache/fop/hyphenation/Hyphenator.java
@@ -24,6 +24,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
+import java.util.Map;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
@@ -39,32 +40,20 @@ import org.xml.sax.InputSource;
*
* @author Carlos Villegas <cav@uniscope.co.jp>
*/
-public class Hyphenator {
+public final class Hyphenator {
/** logging instance */
protected static Log log = LogFactory.getLog(Hyphenator.class);
private static HyphenationTreeCache hTreeCache = null;
- private HyphenationTree hyphenTree = null;
- private int remainCharCount = 2;
- private int pushCharCount = 2;
/** Enables a dump of statistics. Note: If activated content is sent to System.out! */
private static boolean statisticsDump = false;
/**
* Creates a new hyphenator.
- * @param lang the language
- * @param country the country (may be null or "none")
- * @param leftMin the minimum number of characters before the hyphenation point
- * @param rightMin the minimum number of characters after the hyphenation point
*/
- public Hyphenator(String lang, String country, int leftMin,
- int rightMin) {
- hyphenTree = getHyphenationTree(lang, country);
- remainCharCount = leftMin;
- pushCharCount = rightMin;
- }
+ private Hyphenator() { }
/** @return the default (static) hyphenation tree cache */
public static synchronized HyphenationTreeCache getHyphenationTreeCache() {
@@ -75,35 +64,76 @@ public class Hyphenator {
}
/**
- * Returns a hyphenation tree for a given language and country. The hyphenation trees are
- * cached.
+ * Returns a hyphenation tree for a given language and country,
+ * with fallback from (lang,country) to (lang).
+ * The hyphenation trees are cached.
* @param lang the language
* @param country the country (may be null or "none")
+ * @param resolver resolver to find the hyphenation files
+ * @param hyphPatNames the map with user-configured hyphenation pattern file names
* @return the hyphenation tree
*/
public static HyphenationTree getHyphenationTree(String lang,
- String country) {
- return getHyphenationTree(lang, country, null);
+ String country, HyphenationTreeResolver resolver, Map hyphPatNames) {
+ String llccKey = HyphenationTreeCache.constructLlccKey(lang, country);
+ HyphenationTreeCache cache = getHyphenationTreeCache();
+
+ // If this hyphenation tree has been registered as missing, return immediately
+ if (cache.isMissing(llccKey)) {
+ return null;
+ }
+
+ HyphenationTree hTree = getHyphenationTree2(lang, country, resolver, hyphPatNames);
+
+ // fallback to lang only
+ if (hTree == null && country != null && !country.equals("none")) {
+ String llKey = HyphenationTreeCache.constructLlccKey(lang, null);
+ if (!cache.isMissing(llKey)) {
+ hTree = getHyphenationTree2(lang, null, resolver, hyphPatNames);
+ if (hTree != null && log.isDebugEnabled()) {
+ log.debug("Couldn't find hyphenation pattern "
+ + "for lang=\"" + lang + "\",country=\"" + country + "\"."
+ + " Using general language pattern "
+ + "for lang=\"" + lang + "\" instead.");
+ }
+ if (hTree == null) {
+ // no fallback; register as missing
+ cache.noteMissing(llKey);
+ } else {
+ // also register for (lang,country)
+ cache.cache(llccKey, hTree);
+ }
+ }
+ }
+
+ if (hTree == null) {
+ // (lang,country) and (lang) tried; register as missing
+ cache.noteMissing(llccKey);
+ log.error("Couldn't find hyphenation pattern "
+ + "for lang=\"" + lang + "\""
+ + (country != null && !country.equals("none")
+ ? ",country=\"" + country + "\""
+ : "")
+ + ".");
+ }
+
+ return hTree;
}
/**
- * Returns a hyphenation tree for a given language and country. The hyphenation trees are
- * cached.
+ * Returns a hyphenation tree for a given language and country
+ * The hyphenation trees are cached.
* @param lang the language
* @param country the country (may be null or "none")
* @param resolver resolver to find the hyphenation files
+ * @param hyphPatNames the map with user-configured hyphenation pattern file names
* @return the hyphenation tree
*/
- public static HyphenationTree getHyphenationTree(String lang,
- String country, HyphenationTreeResolver resolver) {
- String key = HyphenationTreeCache.constructKey(lang, country);
+ private static HyphenationTree getHyphenationTree2(String lang,
+ String country, HyphenationTreeResolver resolver, Map hyphPatNames) {
+ String llccKey = HyphenationTreeCache.constructLlccKey(lang, country);
HyphenationTreeCache cache = getHyphenationTreeCache();
- // See if there was an error finding this hyphenation tree before
- if (cache.isMissing(key)) {
- return null;
- }
-
HyphenationTree hTree;
// first try to find it in the cache
hTree = getHyphenationTreeCache().getHyphenationTree(lang, country);
@@ -111,6 +141,11 @@ public class Hyphenator {
return hTree;
}
+ String key = HyphenationTreeCache.constructUserKey(lang, country, hyphPatNames);
+ if (key == null) {
+ key = llccKey;
+ }
+
if (resolver != null) {
hTree = getUserHyphenationTree(key, resolver);
}
@@ -120,11 +155,9 @@ public class Hyphenator {
// put it into the pattern cache
if (hTree != null) {
- cache.cache(key, hTree);
- } else {
- log.error("Couldn't find hyphenation pattern " + key);
- cache.noteMissing(key);
+ cache.cache(llccKey, hTree);
}
+
return hTree;
}
@@ -179,31 +212,11 @@ public class Hyphenator {
try {
is = getResourceStream(key);
if (is == null) {
- if (key.length() == 5) {
- String lang = key.substring(0, 2);
- is = getResourceStream(lang);
- if (is != null) {
- if (log.isDebugEnabled()) {
- log.debug("Couldn't find hyphenation pattern '"
- + key
- + "'. Using general language pattern '"
- + lang
- + "' instead.");
- }
- } else {
- if (log.isDebugEnabled()) {
- log.debug("Couldn't find precompiled hyphenation pattern "
- + lang + " in resources.");
- }
- return null;
- }
- } else {
- if (log.isDebugEnabled()) {
- log.debug("Couldn't find precompiled hyphenation pattern "
- + key + " in resources");
- }
- return null;
+ if (log.isDebugEnabled()) {
+ log.debug("Couldn't find precompiled hyphenation pattern "
+ + key + " in resources");
}
+ return null;
}
hTree = readHyphenationTree(is);
} finally {
@@ -335,6 +348,7 @@ public class Hyphenator {
* @param lang the language
* @param country the optional country code (may be null or "none")
* @param resolver resolver to find the hyphenation files
+ * @param hyphPatNames the map with user-configured hyphenation pattern file names
* @param word the word to hyphenate
* @param leftMin the minimum number of characters before the hyphenation point
* @param rightMin the minimum number of characters after the hyphenation point
@@ -342,121 +356,14 @@ public class Hyphenator {
*/
public static Hyphenation hyphenate(String lang, String country,
HyphenationTreeResolver resolver,
+ Map hyphPatNames,
String word,
int leftMin, int rightMin) {
- HyphenationTree hTree = getHyphenationTree(lang, country, resolver);
+ HyphenationTree hTree = getHyphenationTree(lang, country, resolver, hyphPatNames);
if (hTree == null) {
return null;
}
return hTree.hyphenate(word, leftMin, rightMin);
}
- /**
- * Hyphenates a word.
- * @param lang the language
- * @param country the optional country code (may be null or "none")
- * @param word the word to hyphenate
- * @param leftMin the minimum number of characters before the hyphenation point
- * @param rightMin the minimum number of characters after the hyphenation point
- * @return the hyphenation result
- */
- public static Hyphenation hyphenate(String lang, String country,
- String word,
- int leftMin, int rightMin) {
- return hyphenate(lang, country, null, word, leftMin, rightMin);
- }
-
- /**
- * Hyphenates a word.
- * @param lang the language
- * @param country the optional country code (may be null or "none")
- * @param resolver resolver to find the hyphenation files
- * @param word the word to hyphenate
- * @param offset the offset of the first character in the "word" character array
- * @param len the length of the word
- * @param leftMin the minimum number of characters before the hyphenation point
- * @param rightMin the minimum number of characters after the hyphenation point
- * @return the hyphenation result
- */
- public static Hyphenation hyphenate(String lang, // CSOK: ParameterNumber
- String country,
- HyphenationTreeResolver resolver,
- char[] word, int offset, int len,
- int leftMin, int rightMin) {
- HyphenationTree hTree = getHyphenationTree(lang, country, resolver);
- if (hTree == null) {
- return null;
- }
- return hTree.hyphenate(word, offset, len, leftMin, rightMin);
- }
-
- /**
- * Hyphenates a word.
- * @param lang the language
- * @param country the optional country code (may be null or "none")
- * @param word the word to hyphenate
- * @param offset the offset of the first character in the "word" character array
- * @param len the length of the word
- * @param leftMin the minimum number of characters before the hyphenation point
- * @param rightMin the minimum number of characters after the hyphenation point
- * @return the hyphenation result
- */
- public static Hyphenation hyphenate(String lang, String country,
- char[] word, int offset, int len,
- int leftMin, int rightMin) {
- return hyphenate(lang, country, null, word, offset, len, leftMin, rightMin);
- }
-
- /**
- * Sets the minimum number of characters before the hyphenation point
- * @param min the number of characters
- */
- public void setMinRemainCharCount(int min) {
- remainCharCount = min;
- }
-
- /**
- * Sets the minimum number of characters after the hyphenation point
- * @param min the number of characters
- */
- public void setMinPushCharCount(int min) {
- pushCharCount = min;
- }
-
- /**
- * Sets the language and country for the hyphenation process.
- * @param lang the language
- * @param country the country (may be null or "none")
- */
- public void setLanguage(String lang, String country) {
- hyphenTree = getHyphenationTree(lang, country);
- }
-
- /**
- * Hyphenates a word.
- * @param word the word to hyphenate
- * @param offset the offset of the first character in the "word" character array
- * @param len the length of the word
- * @return the hyphenation result
- */
- public Hyphenation hyphenate(char[] word, int offset, int len) {
- if (hyphenTree == null) {
- return null;
- }
- return hyphenTree.hyphenate(word, offset, len, remainCharCount,
- pushCharCount);
- }
-
- /**
- * Hyphenates a word.
- * @param word the word to hyphenate
- * @return the hyphenation result
- */
- public Hyphenation hyphenate(String word) {
- if (hyphenTree == null) {
- return null;
- }
- return hyphenTree.hyphenate(word, remainCharCount, pushCharCount);
- }
-
}
diff --git a/src/java/org/apache/fop/layoutmgr/Page.java b/src/java/org/apache/fop/layoutmgr/Page.java
index b183efa01..d8ec66e82 100644
--- a/src/java/org/apache/fop/layoutmgr/Page.java
+++ b/src/java/org/apache/fop/layoutmgr/Page.java
@@ -41,10 +41,12 @@ public class Page {
* @param pageNumber the page number (as an int)
* @param pageNumberStr the page number (as a String)
* @param blank true if this is a blank page
+ * @param spanAll true if the first span area spans all columns
*/
- public Page(SimplePageMaster spm, int pageNumber, String pageNumberStr, boolean blank) {
+ public Page(SimplePageMaster spm, int pageNumber, String pageNumberStr,
+ boolean blank, boolean spanAll) {
this.spm = spm;
- this.pageViewport = new PageViewport(spm, pageNumber, pageNumberStr, blank);
+ this.pageViewport = new PageViewport(spm, pageNumber, pageNumberStr, blank, spanAll);
}
/**
diff --git a/src/java/org/apache/fop/layoutmgr/PageBreaker.java b/src/java/org/apache/fop/layoutmgr/PageBreaker.java
index 171b3fd4f..3a41eb191 100644
--- a/src/java/org/apache/fop/layoutmgr/PageBreaker.java
+++ b/src/java/org/apache/fop/layoutmgr/PageBreaker.java
@@ -45,6 +45,7 @@ public class PageBreaker extends AbstractBreaker {
private boolean needColumnBalancing;
private PageProvider pageProvider;
private Block separatorArea;
+ private boolean spanAllActive;
/**
* The FlowLayoutManager object, which processes
@@ -148,8 +149,9 @@ public class PageBreaker extends AbstractBreaker {
}
firstPart = false;
pageBreakHandled = true;
+
pageProvider.setStartOfNextElementList(pslm.getCurrentPageNum(),
- pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex());
+ pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex(), this.spanAllActive);
return super.getNextBlockList(childLC, nextSequenceStartsOn, positionAtIPDChange,
restartLM, firstElements);
}
@@ -342,8 +344,9 @@ public class PageBreaker extends AbstractBreaker {
pageBreakHandled = true;
//Update so the available BPD is reported correctly
int currentPageNum = pslm.getCurrentPageNum();
+
pageProvider.setStartOfNextElementList(currentPageNum,
- pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex());
+ pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex(), this.spanAllActive);
//Make sure we only add the areas we haven't added already
effectiveList.ignoreAtStart = newStartPos;
@@ -387,7 +390,7 @@ public class PageBreaker extends AbstractBreaker {
boolean fitsOnePage
= optimalPageCount <= pslm.getCurrentPV()
- .getBodyRegion().getMainReference().getCurrentSpan().getColumnCount();
+ .getBodyRegion().getMainReference().getCurrentSpan().getColumnCount();
if (needColumnBalancing) {
if (!fitsOnePage) {
@@ -435,7 +438,8 @@ public class PageBreaker extends AbstractBreaker {
handleBreakTrait(breakClass);
}
pageProvider.setStartOfNextElementList(pslm.getCurrentPageNum(),
- pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex());
+ pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex(),
+ this.spanAllActive);
}
pageBreakHandled = false;
// add static areas and resolve any new id areas
@@ -503,9 +507,11 @@ public class PageBreaker extends AbstractBreaker {
case Constants.EN_ALL:
//break due to span change in multi-column layout
curPage.getPageViewport().createSpan(true);
+ this.spanAllActive = true;
return;
case Constants.EN_NONE:
curPage.getPageViewport().createSpan(false);
+ this.spanAllActive = false;
return;
case Constants.EN_COLUMN:
case Constants.EN_AUTO:
@@ -554,7 +560,7 @@ public class PageBreaker extends AbstractBreaker {
*/
private boolean needBlankPageBeforeNew(int breakVal) {
if (breakVal == Constants.EN_PAGE
- || (pslm.getCurrentPage().getPageViewport().getPage().isEmpty())) {
+ || (pslm.getCurrentPage().getPageViewport().getPage().isEmpty())) {
// any page is OK or we already have an empty page
return false;
} else {
diff --git a/src/java/org/apache/fop/layoutmgr/PageProvider.java b/src/java/org/apache/fop/layoutmgr/PageProvider.java
index 2e531a8d8..8caafa72b 100644
--- a/src/java/org/apache/fop/layoutmgr/PageProvider.java
+++ b/src/java/org/apache/fop/layoutmgr/PageProvider.java
@@ -51,6 +51,7 @@ public class PageProvider implements Constants {
private int startPageOfPageSequence;
private int startPageOfCurrentElementList;
private int startColumnOfCurrentElementList;
+ private boolean spanAllForCurrentElementList;
private List cachedPages = new java.util.ArrayList();
private int lastPageIndex = -1;
@@ -88,12 +89,17 @@ public class PageProvider implements Constants {
* on so it can later retrieve PageViewports relative to this first page.
* @param startPage the number of the first page for the element list.
* @param startColumn the starting column number for the element list.
+ * @param spanAll true if the current element list is for a column-spanning section
*/
- public void setStartOfNextElementList(int startPage, int startColumn) {
- log.debug("start of the next element list is:"
- + " page=" + startPage + " col=" + startColumn);
+ public void setStartOfNextElementList(int startPage, int startColumn, boolean spanAll) {
+ if (log.isDebugEnabled()) {
+ log.debug("start of the next element list is:"
+ + " page=" + startPage + " col=" + startColumn
+ + (spanAll ? ", column-spanning" : ""));
+ }
this.startPageOfCurrentElementList = startPage - startPageOfPageSequence + 1;
this.startColumnOfCurrentElementList = startColumn;
+ this.spanAllForCurrentElementList = spanAll;
//Reset Cache
this.lastRequestedIndex = -1;
this.lastReportedBPD = -1;
@@ -290,7 +296,7 @@ public class PageProvider implements Constants {
if (log.isTraceEnabled()) {
log.trace("Caching " + index);
}
- cacheNextPage(index, isBlank, isLastPage);
+ cacheNextPage(index, isBlank, isLastPage, this.spanAllForCurrentElementList);
}
Page page = (Page)cachedPages.get(intIndex);
boolean replace = false;
@@ -306,7 +312,7 @@ public class PageProvider implements Constants {
}
if (replace) {
discardCacheStartingWith(intIndex);
- page = cacheNextPage(index, isBlank, isLastPage);
+ page = cacheNextPage(index, isBlank, isLastPage, this.spanAllForCurrentElementList);
}
return page;
}
@@ -320,7 +326,7 @@ public class PageProvider implements Constants {
}
}
- private Page cacheNextPage(int index, boolean isBlank, boolean isLastPage) {
+ private Page cacheNextPage(int index, boolean isBlank, boolean isLastPage, boolean spanAll) {
String pageNumberString = pageSeq.makeFormattedPageNumber(index);
boolean isFirstPage = (startPageOfPageSequence == index);
SimplePageMaster spm = pageSeq.getNextSimplePageMaster(
@@ -335,7 +341,7 @@ public class PageProvider implements Constants {
eventProducer.flowNotMappingToRegionBody(this,
pageSeq.getMainFlow().getFlowName(), spm.getMasterName(), spm.getLocator());
}
- Page page = new Page(spm, index, pageNumberString, isBlank);
+ Page page = new Page(spm, index, pageNumberString, isBlank, spanAll);
//Set unique key obtained from the AreaTreeHandler
page.getPageViewport().setKey(areaTreeHandler.generatePageViewportKey());
page.getPageViewport().setForeignAttributes(spm.getForeignAttributes());
diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
index 83d286c15..cbae691b1 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
@@ -1415,6 +1415,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
= Hyphenator.hyphenate(hyphenationProperties.language.getString(),
hyphenationProperties.country.getString(),
getFObj().getUserAgent().getFactory().getHyphenationTreeResolver(),
+ getFObj().getUserAgent().getFactory().getHyphPatNames(),
sbChars.toString(),
hyphenationProperties.hyphenationRemainCharacterCount.getValue(),
hyphenationProperties.hyphenationPushCharacterCount.getValue());
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
index 2b432d0d4..7e343697a 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
@@ -552,4 +552,11 @@ public class TableLayoutManager extends BlockStackingLayoutManager
}
}
+ /** {@inheritDoc} */
+ public void reset() {
+ super.reset();
+ curBlockArea = null;
+ tableUnit = 0.0;
+ }
+
}
diff --git a/src/java/org/apache/fop/pdf/PDFMetadata.java b/src/java/org/apache/fop/pdf/PDFMetadata.java
index 49f762708..b9612d11b 100644
--- a/src/java/org/apache/fop/pdf/PDFMetadata.java
+++ b/src/java/org/apache/fop/pdf/PDFMetadata.java
@@ -151,6 +151,9 @@ public class PDFMetadata extends PDFStream {
}
dc.addDate(info.getCreationDate());
+ //Somewhat redundant but some PDF/A checkers issue a warning without this.
+ dc.setFormat("application/pdf");
+
//PDF/A identification
PDFAMode pdfaMode = pdfDoc.getProfile().getPDFAMode();
if (pdfaMode.isPDFA1LevelB()) {
diff --git a/src/java/org/apache/fop/pdf/PDFName.java b/src/java/org/apache/fop/pdf/PDFName.java
index 8214cda76..3f9af7669 100644
--- a/src/java/org/apache/fop/pdf/PDFName.java
+++ b/src/java/org/apache/fop/pdf/PDFName.java
@@ -41,6 +41,7 @@ public class PDFName extends PDFObject {
this.name = escapeName(name);
}
+ private static final String ESCAPED_NAME_CHARS = "/()<>[]%#";
/**
* Escapes a PDF name. It adds the leading slash and escapes characters as necessary.
@@ -56,7 +57,8 @@ public class PDFName extends PDFObject {
}
for (int i = (skipFirst ? 1 : 0), c = name.length(); i < c; i++) {
char ch = name.charAt(i);
- if (ch < 33 || ch > 126 || ch == 0x2F) {
+
+ if (ch < 33 || ch > 126 || ESCAPED_NAME_CHARS.indexOf(ch) >= 0) {
sb.append('#');
toHex(ch, sb);
} else {
diff --git a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
index 21d4faf56..c37e0c37c 100644
--- a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
+++ b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
@@ -47,6 +47,7 @@ import org.apache.fop.render.afp.extensions.AFPElementMapping;
import org.apache.fop.render.afp.extensions.AFPIncludeFormMap;
import org.apache.fop.render.afp.extensions.AFPInvokeMediumMap;
import org.apache.fop.render.afp.extensions.AFPPageOverlay;
+import org.apache.fop.render.afp.extensions.AFPPageSegmentElement;
import org.apache.fop.render.afp.extensions.AFPPageSetup;
import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler;
import org.apache.fop.render.intermediate.IFDocumentHandler;
@@ -76,8 +77,8 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
private DataStream dataStream;
/** the map of page segments */
- private Map/*<String,String>*/pageSegmentMap
- = new java.util.HashMap/*<String,String>*/();
+ private Map/*<String,PageSegmentDescriptor>*/pageSegmentMap
+ = new java.util.HashMap/*<String,PageSegmentDescriptor>*/();
/** Medium Map referenced on previous page **/
private String lastMediumMap;
@@ -213,7 +214,6 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
throws IFException {
this.location = LOC_ELSEWHERE;
paintingState.clear();
- pageSegmentMap.clear();
AffineTransform baseTransform = getBaseTransform();
paintingState.concatenate(baseTransform);
@@ -288,9 +288,12 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
null);
}
if (AFPElementMapping.INCLUDE_PAGE_SEGMENT.equals(element)) {
- String name = aps.getName();
- String source = aps.getValue();
- pageSegmentMap.put(source, name);
+ AFPPageSegmentElement.AFPPageSegmentSetup apse
+ = (AFPPageSegmentElement.AFPPageSegmentSetup)aps;
+ String name = apse.getName();
+ String source = apse.getValue();
+ String uri = apse.getResourceSrc();
+ pageSegmentMap.put(source, new PageSegmentDescriptor(name, uri));
} else if (AFPElementMapping.NO_OPERATION.equals(element)) {
String content = aps.getContent();
if (content != null) {
@@ -392,13 +395,13 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
}
/**
- * Returns the page segment name for a given URI if it actually represents a page segment.
+ * Returns the page segment descriptor for a given URI if it actually represents a page segment.
* Otherwise, it just returns null.
* @param uri the URI that identifies the page segment
- * @return the page segment name or null if there's no page segment for the given URI
+ * @return the page segment descriptor or null if there's no page segment for the given URI
*/
- String getPageSegmentNameFor(String uri) {
- return (String)pageSegmentMap.get(uri);
+ PageSegmentDescriptor getPageSegmentNameFor(String uri) {
+ return (PageSegmentDescriptor)pageSegmentMap.get(uri);
}
}
diff --git a/src/java/org/apache/fop/render/afp/AFPPainter.java b/src/java/org/apache/fop/render/afp/AFPPainter.java
index 0bbfef3e8..ed16a923b 100644
--- a/src/java/org/apache/fop/render/afp/AFPPainter.java
+++ b/src/java/org/apache/fop/render/afp/AFPPainter.java
@@ -26,6 +26,8 @@ import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.Map;
import org.w3c.dom.Document;
@@ -48,6 +50,8 @@ import org.apache.fop.afp.modca.AbstractPageObject;
import org.apache.fop.afp.modca.PresentationTextObject;
import org.apache.fop.afp.ptoca.PtocaBuilder;
import org.apache.fop.afp.ptoca.PtocaProducer;
+import org.apache.fop.afp.util.DefaultFOPResourceAccessor;
+import org.apache.fop.afp.util.ResourceAccessor;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
@@ -183,14 +187,34 @@ public class AFPPainter extends AbstractIFPainter {
/** {@inheritDoc} */
public void drawImage(String uri, Rectangle rect) throws IFException {
- String name = documentHandler.getPageSegmentNameFor(uri);
- if (name != null) {
+ PageSegmentDescriptor pageSegment = documentHandler.getPageSegmentNameFor(uri);
+
+ if (pageSegment != null) {
float[] srcPts = {rect.x, rect.y};
int[] coords = unitConv.mpts2units(srcPts);
int width = Math.round(unitConv.mpt2units(rect.width));
int height = Math.round(unitConv.mpt2units(rect.height));
- getDataStream().createIncludePageSegment(name, coords[X], coords[Y], width, height);
+ getDataStream().createIncludePageSegment(pageSegment.getName(),
+ coords[X], coords[Y], width, height);
+
+ //Do we need to embed an external page segment?
+ if (pageSegment.getURI() != null) {
+ ResourceAccessor accessor = new DefaultFOPResourceAccessor (
+ documentHandler.getUserAgent(), null, null);
+ try {
+ URI resourceUri = new URI(pageSegment.getURI());
+ documentHandler.getResourceManager().createIncludedResourceFromExternal(
+ pageSegment.getName(), resourceUri, accessor);
+
+ } catch (URISyntaxException urie) {
+ throw new IFException("Could not handle resource url"
+ + pageSegment.getURI(), urie);
+ } catch (IOException ioe) {
+ throw new IFException("Could not handle resource" + pageSegment.getURI(), ioe);
+ }
+ }
+
} else {
drawImageUsingURI(uri, rect);
}
diff --git a/src/java/org/apache/fop/render/afp/PageSegmentDescriptor.java b/src/java/org/apache/fop/render/afp/PageSegmentDescriptor.java
new file mode 100644
index 000000000..8915a7a59
--- /dev/null
+++ b/src/java/org/apache/fop/render/afp/PageSegmentDescriptor.java
@@ -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.render.afp;
+
+/**
+ * Class holding information on a page segment.
+ */
+class PageSegmentDescriptor {
+
+ private String name;
+ private String uri;
+
+ /**
+ * Creates a new page segment descriptor.
+ * @param name the page segment name
+ * @param uri the URI identifying the external resource file (may be null if the page segment
+ * shall be referenced rather than embedded)
+ */
+ public PageSegmentDescriptor(String name, String uri) {
+ this.name = name;
+ this.uri = uri;
+ }
+
+ /**
+ * Returns the name of the page segment (usually 8 upper case letters).
+ * @return the name of the page segment
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns the URI of the external resource containing the page segment.
+ * @return the URI of the external resource (or null if the resource is not to be embedded)
+ */
+ public String getURI() {
+ return this.uri;
+ }
+
+} \ No newline at end of file
diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPElementMapping.java b/src/java/org/apache/fop/render/afp/extensions/AFPElementMapping.java
index d77e21db2..580e9f800 100644
--- a/src/java/org/apache/fop/render/afp/extensions/AFPElementMapping.java
+++ b/src/java/org/apache/fop/render/afp/extensions/AFPElementMapping.java
@@ -103,7 +103,7 @@ public class AFPElementMapping extends ElementMapping {
static class AFPIncludePageSegmentMaker extends ElementMapping.Maker {
public FONode make(FONode parent) {
- return new AFPPageSetupElement(parent, INCLUDE_PAGE_SEGMENT);
+ return new AFPPageSegmentElement(parent, INCLUDE_PAGE_SEGMENT);
}
}
diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java b/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java
index 254b68f1f..f2e77ec33 100644
--- a/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java
+++ b/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java
@@ -24,11 +24,13 @@ import java.net.URISyntaxException;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.fop.render.afp.extensions.AFPPageSegmentElement.AFPPageSegmentSetup;
import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener;
@@ -52,7 +54,7 @@ public class AFPExtensionHandler extends DefaultHandler
throws SAXException {
boolean handled = false;
if (AFPExtensionAttachment.CATEGORY.equals(uri)) {
- lastAttributes = attributes;
+ lastAttributes = new AttributesImpl(attributes);
handled = true;
if (localName.equals(AFPElementMapping.NO_OPERATION)
|| localName.equals(AFPElementMapping.TAG_LOGICAL_ELEMENT)
@@ -96,6 +98,30 @@ public class AFPExtensionHandler extends DefaultHandler
if (name != null) {
returnedObject.setName(name);
}
+ } else if (AFPElementMapping.INCLUDE_PAGE_SEGMENT.equals(localName)) {
+ AFPPageSegmentSetup pageSetupExtn = null;
+
+ pageSetupExtn = new AFPPageSegmentSetup(localName);
+ this.returnedObject = pageSetupExtn;
+
+ String name = lastAttributes.getValue("name");
+ if (name != null) {
+ returnedObject.setName(name);
+ }
+ String value = lastAttributes.getValue("value");
+ if (value != null && pageSetupExtn != null) {
+ pageSetupExtn.setValue(value);
+ }
+
+ String resourceSrc = lastAttributes.getValue("resource-file");
+ if (resourceSrc != null && pageSetupExtn != null) {
+ pageSetupExtn.setResourceSrc(resourceSrc);
+ }
+
+ if (content.length() > 0 && pageSetupExtn != null) {
+ pageSetupExtn.setContent(content.toString());
+ content.setLength(0); //Reset text buffer (see characters())
+ }
} else {
AFPPageSetup pageSetupExtn = null;
if (AFPElementMapping.INVOKE_MEDIUM_MAP.equals(localName)) {
@@ -117,6 +143,7 @@ public class AFPExtensionHandler extends DefaultHandler
content.setLength(0); //Reset text buffer (see characters())
}
}
+
}
}
diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPPageSegmentElement.java b/src/java/org/apache/fop/render/afp/extensions/AFPPageSegmentElement.java
new file mode 100644
index 000000000..f7379e02c
--- /dev/null
+++ b/src/java/org/apache/fop/render/afp/extensions/AFPPageSegmentElement.java
@@ -0,0 +1,149 @@
+/*
+ * 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.afp.extensions;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.extensions.ExtensionAttachment;
+
+/**
+ * This class extends the org.apache.fop.extensions.ExtensionObj class. The
+ * object faciliates extraction of elements from formatted objects based on
+ * the static list as defined in the AFPElementMapping implementation.
+ * <p/>
+ */
+public class AFPPageSegmentElement extends AFPPageSetupElement {
+
+ private static final String ATT_RESOURCE_SRC = "resource-file";
+
+ /**
+ * Constructs an AFP object (called by Maker).
+ *
+ * @param parent the parent formatting object
+ * @param name the name of the afp element
+ */
+ public AFPPageSegmentElement(FONode parent, String name) {
+ super(parent, name);
+ }
+
+
+ private AFPPageSegmentSetup getPageSetupAttachment() {
+ return (AFPPageSegmentSetup)getExtensionAttachment();
+ }
+
+
+ /** {@inheritDoc} */
+ public void processNode(String elementName, Locator locator,
+ Attributes attlist, PropertyList propertyList)
+ throws FOPException {
+
+ AFPPageSegmentSetup pageSetup = getPageSetupAttachment();
+ super.processNode(elementName, locator, attlist, propertyList);
+
+
+ String attr = attlist.getValue(ATT_RESOURCE_SRC);
+
+ if (attr != null && attr.length() > 0) {
+ pageSetup.setResourceSrc(attr);
+ }
+
+ }
+
+ /** {@inheritDoc} */
+ protected ExtensionAttachment instantiateExtensionAttachment() {
+ return new AFPPageSegmentSetup(getLocalName());
+ }
+
+ /**
+ * This is the pass-through value object for the AFP extension.
+ */
+ public static class AFPPageSegmentSetup extends AFPPageSetup {
+
+ private static final long serialVersionUID = 1L;
+
+ private String resourceSrc;
+
+ /**
+ * Default constructor.
+ *
+ * @param elementName the name of the setup code object, may be null
+ */
+ public AFPPageSegmentSetup(String elementName) {
+ super(elementName);
+ }
+
+ /**
+ * Returns the source URI for the page segment.
+ * @return the source URI
+ */
+ public String getResourceSrc() {
+ return resourceSrc;
+ }
+
+ /**
+ * Sets the source URI for the page segment.
+ * @param resourceSrc the source URI
+ */
+ public void setResourceSrc(String resourceSrc) {
+ this.resourceSrc = resourceSrc.trim();
+ }
+
+
+ /** {@inheritDoc} */
+ public void toSAX(ContentHandler handler) throws SAXException {
+ AttributesImpl atts = new AttributesImpl();
+ if (name != null && name.length() > 0) {
+ atts.addAttribute(null, ATT_NAME, ATT_NAME, "CDATA", name);
+ }
+ if (value != null && value.length() > 0) {
+ atts.addAttribute(null, ATT_VALUE, ATT_VALUE, "CDATA", value);
+ }
+
+ if (resourceSrc != null && resourceSrc.length() > 0) {
+ atts.addAttribute(null, ATT_RESOURCE_SRC, ATT_RESOURCE_SRC, "CDATA", resourceSrc);
+ }
+
+ handler.startElement(CATEGORY, elementName, elementName, atts);
+ if (content != null && content.length() > 0) {
+ char[] chars = content.toCharArray();
+ handler.characters(chars, 0, chars.length);
+ }
+ handler.endElement(CATEGORY, elementName, elementName);
+ }
+
+ /** {@inheritDoc} */
+ public String toString() {
+ return "AFPPageSegmentSetup(element-name=" + getElementName()
+ + " name=" + getName()
+ + " value=" + getValue()
+ + " resource=" + getResourceSrc() + ")";
+ }
+
+ }
+
+
+}
diff --git a/src/java/org/apache/fop/render/intermediate/util/IFConcatenator.java b/src/java/org/apache/fop/render/intermediate/util/IFConcatenator.java
index 4b0a3fe68..71ee7a0b0 100644
--- a/src/java/org/apache/fop/render/intermediate/util/IFConcatenator.java
+++ b/src/java/org/apache/fop/render/intermediate/util/IFConcatenator.java
@@ -19,7 +19,6 @@
package org.apache.fop.render.intermediate.util;
-
import java.awt.Dimension;
import javax.xml.transform.Source;
@@ -39,12 +38,17 @@ import org.apache.fop.render.intermediate.IFParser;
* <p>
* Note: This class will filter/ignore any document navigation events. Support for this may be
* added later.
+ * <p>
+ * Note: document-level extensions will only be transferred from the first document passed in.
+ * If you need to merge extensions from all the concatenated documents, you may have to merge
+ * these manually on the XML level, for example using XSLT.
*/
public class IFConcatenator {
private IFDocumentHandler targetHandler;
private int nextPageIndex = 0;
+ private boolean inFirstDocument = true;
/**
* Creates a new IF concatenator.
@@ -163,14 +167,17 @@ public class IFConcatenator {
/** {@inheritDoc} */
public void endDocument() throws IFException {
//ignore
+ inFirstDocument = false;
}
/** {@inheritDoc} */
public void handleExtensionObject(Object extension) throws IFException {
- if (inPageSequence) {
+ if (inPageSequence || inFirstDocument) {
//Only pass through when inside page-sequence
+ //or for the first document (for document-level extensions).
super.handleExtensionObject(extension);
}
+ //Note:Extensions from non-first documents are ignored!
}
/** {@inheritDoc} */
diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java
index 99233abb6..05726be22 100644
--- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java
+++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java
@@ -38,6 +38,7 @@ import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.image.loader.batik.BatikImageFlavors;
+import org.apache.fop.image.loader.batik.BatikUtil;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;
@@ -46,6 +47,7 @@ import org.apache.fop.svg.PDFBridgeContext;
import org.apache.fop.svg.PDFGraphics2D;
import org.apache.fop.svg.SVGEventProducer;
import org.apache.fop.svg.SVGUserAgent;
+import org.w3c.dom.Document;
/**
* Image Handler implementation which handles SVG images.
@@ -82,10 +84,14 @@ public class PDFImageHandlerSVG implements ImageHandler {
userAgent.getFactory().getImageManager(),
userAgent.getImageSessionContext(),
new AffineTransform());
+
+ //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine)
+ //to it.
+ Document clonedDoc = BatikUtil.cloneSVGDocument(imageSVG.getDocument());
GraphicsNode root;
try {
- root = builder.build(ctx, imageSVG.getDocument());
+ root = builder.build(ctx, clonedDoc);
builder = null;
} catch (Exception e) {
SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
diff --git a/src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java b/src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java
index d285904a8..04c95545c 100644
--- a/src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java
+++ b/src/java/org/apache/fop/render/pdf/extensions/PDFExtensionHandler.java
@@ -21,6 +21,7 @@ package org.apache.fop.render.pdf.extensions;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.commons.logging.Log;
@@ -48,7 +49,7 @@ public class PDFExtensionHandler extends DefaultHandler
throws SAXException {
boolean handled = false;
if (PDFExtensionAttachment.CATEGORY.equals(uri)) {
- lastAttributes = attributes;
+ lastAttributes = new AttributesImpl(attributes);
handled = false;
if (localName.equals(PDFEmbeddedFileExtensionAttachment.ELEMENT)) {
//handled in endElement
diff --git a/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java b/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
index 41cba7563..839a0cab6 100644
--- a/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
+++ b/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
@@ -23,6 +23,8 @@ import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.io.IOException;
+import org.w3c.dom.Document;
+
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.gvt.GraphicsNode;
@@ -34,6 +36,7 @@ import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
import org.apache.xmlgraphics.ps.PSGenerator;
import org.apache.fop.image.loader.batik.BatikImageFlavors;
+import org.apache.fop.image.loader.batik.BatikUtil;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.svg.SVGEventProducer;
@@ -70,10 +73,14 @@ public class PSImageHandlerSVG implements ImageHandler {
context.getUserAgent().getFactory().getImageManager(),
context.getUserAgent().getImageSessionContext());
+ //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine)
+ //to it.
+ Document clonedDoc = BatikUtil.cloneSVGDocument(imageSVG.getDocument());
+
GraphicsNode root;
try {
GVTBuilder builder = new GVTBuilder();
- root = builder.build(ctx, imageSVG.getDocument());
+ root = builder.build(ctx, clonedDoc);
} catch (Exception e) {
SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
context.getUserAgent().getEventBroadcaster());
diff --git a/src/java/org/apache/fop/render/ps/extensions/PSExtensionHandler.java b/src/java/org/apache/fop/render/ps/extensions/PSExtensionHandler.java
index dee918f19..bf970d0a6 100644
--- a/src/java/org/apache/fop/render/ps/extensions/PSExtensionHandler.java
+++ b/src/java/org/apache/fop/render/ps/extensions/PSExtensionHandler.java
@@ -21,6 +21,7 @@ package org.apache.fop.render.ps.extensions;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.commons.logging.Log;
@@ -49,7 +50,7 @@ public class PSExtensionHandler extends DefaultHandler
throws SAXException {
boolean handled = false;
if (PSExtensionAttachment.CATEGORY.equals(uri)) {
- lastAttributes = attributes;
+ lastAttributes = new AttributesImpl(attributes);
handled = false;
if (localName.equals(PSSetupCode.ELEMENT)
|| localName.equals(PSSetPageDevice.ELEMENT)
diff --git a/src/java/org/apache/fop/render/rtf/RTFHandler.java b/src/java/org/apache/fop/render/rtf/RTFHandler.java
index 5698329c8..35f58e170 100644
--- a/src/java/org/apache/fop/render/rtf/RTFHandler.java
+++ b/src/java/org/apache/fop/render/rtf/RTFHandler.java
@@ -80,11 +80,11 @@ import org.apache.fop.fo.flow.PageNumber;
import org.apache.fop.fo.flow.PageNumberCitation;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableBody;
-import org.apache.fop.fo.flow.table.TableFooter;
-import org.apache.fop.fo.flow.table.TablePart;
import org.apache.fop.fo.flow.table.TableCell;
import org.apache.fop.fo.flow.table.TableColumn;
+import org.apache.fop.fo.flow.table.TableFooter;
import org.apache.fop.fo.flow.table.TableHeader;
+import org.apache.fop.fo.flow.table.TablePart;
import org.apache.fop.fo.flow.table.TableRow;
import org.apache.fop.fo.pagination.Flow;
import org.apache.fop.fo.pagination.PageSequence;
@@ -436,7 +436,8 @@ public class RTFHandler extends FOEventHandler {
RtfTextrun textrun = container.getTextrun();
textrun.addParagraphBreak();
- textrun.popBlockAttributes();
+ int breakValue = toRtfBreakValue(bl.getBreakAfter());
+ textrun.popBlockAttributes(breakValue);
} catch (IOException ioe) {
handleIOTrouble(ioe);
@@ -488,7 +489,8 @@ public class RTFHandler extends FOEventHandler {
RtfTextrun textrun = container.getTextrun();
textrun.addParagraphBreak();
- textrun.popBlockAttributes();
+ int breakValue = toRtfBreakValue(bl.getBreakAfter());
+ textrun.popBlockAttributes(breakValue);
} catch (IOException ioe) {
handleIOTrouble(ioe);
@@ -498,6 +500,21 @@ public class RTFHandler extends FOEventHandler {
}
}
+ private int toRtfBreakValue(int foBreakValue) {
+ switch (foBreakValue) {
+ case Constants.EN_PAGE:
+ return RtfTextrun.BREAK_PAGE;
+ case Constants.EN_EVEN_PAGE:
+ return RtfTextrun.BREAK_EVEN_PAGE;
+ case Constants.EN_ODD_PAGE:
+ return RtfTextrun.BREAK_ODD_PAGE;
+ case Constants.EN_COLUMN:
+ return RtfTextrun.BREAK_COLUMN;
+ default:
+ return RtfTextrun.BREAK_NONE;
+ }
+ }
+
/** {@inheritDoc} */
public void startTable(Table tbl) {
if (bDefer) {
diff --git a/src/java/org/apache/fop/render/rtf/TextAttributesConverter.java b/src/java/org/apache/fop/render/rtf/TextAttributesConverter.java
index 1b7e21bd3..d377f740d 100644
--- a/src/java/org/apache/fop/render/rtf/TextAttributesConverter.java
+++ b/src/java/org/apache/fop/render/rtf/TextAttributesConverter.java
@@ -35,6 +35,7 @@ import org.apache.fop.fo.flow.BlockContainer;
import org.apache.fop.fo.flow.Inline;
import org.apache.fop.fo.flow.Leader;
import org.apache.fop.fo.flow.PageNumber;
+import org.apache.fop.fo.flow.table.TableCell;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonFont;
import org.apache.fop.fo.properties.CommonMarginBlock;
@@ -80,10 +81,48 @@ final class TextAttributesConverter {
attrBlockMargin(fobj.getCommonMarginBlock(), attrib);
attrBlockTextAlign(fobj.getTextAlign(), attrib);
attrBorder(fobj.getCommonBorderPaddingBackground(), attrib, fobj);
+ attrBreak(fobj, attrib);
return attrib;
}
+ private static void attrBreak(Block fobj, FOPRtfAttributes attrib) {
+ int breakValue = fobj.getBreakBefore();
+ if (breakValue != Constants.EN_AUTO) {
+ //"sect" Creates a new section and a page break,
+ //a simple page break with control word "page" caused
+ //some problems
+ boolean bHasTableCellParent = false;
+ FONode f = fobj;
+ while (f.getParent() != null) {
+ f = f.getParent();
+ if (f instanceof TableCell) {
+ bHasTableCellParent = true;
+ break;
+ }
+ }
+ if (!bHasTableCellParent) {
+ attrib.set("sect");
+ switch (breakValue) {
+ case Constants.EN_EVEN_PAGE:
+ attrib.set("sbkeven");
+ break;
+ case Constants.EN_ODD_PAGE:
+ attrib.set("sbkodd");
+ break;
+ case Constants.EN_COLUMN:
+ attrib.set("sbkcol");
+ break;
+ default:
+ attrib.set("sbkpage");
+ }
+ } else {
+ log.warn("Cannot create break-before for a block inside a table.");
+ }
+ }
+ //Break after is handled in RtfCloseGroupMark
+ }
+
/**
* Converts all known text FO properties to RtfAttributes
* @param fobj FObj whose properties are to be converted
diff --git a/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java b/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
index 4831ffd86..128c9a3df 100644
--- a/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
+++ b/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfTextrun.java
@@ -25,9 +25,10 @@ import java.io.Writer;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
+import java.util.Stack;
-// FOP
-import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfExternalGraphic;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
/**
* Class which contains a linear text run. It has methods to add attributes,
@@ -35,9 +36,26 @@ import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfExternalGraphic;
* @author Peter Herweg, pherweg@web.de
*/
public class RtfTextrun extends RtfContainer {
+
+ /** Constant for no page break */
+ public static final int BREAK_NONE = 0;
+ /** Constant for a normal page break */
+ public static final int BREAK_PAGE = 1;
+ /** Constant for a column break */
+ public static final int BREAK_COLUMN = 2;
+ /** Constant for a even page break */
+ public static final int BREAK_EVEN_PAGE = 3;
+ /** Constant for a odd page break */
+ public static final int BREAK_ODD_PAGE = 4;
+
private boolean bSuppressLastPar = false;
private RtfListItem rtfListItem;
+ /**
+ * logging instance
+ */
+ protected static Log log = LogFactory.getLog(RtfTextrun.class);
+
/** Manager for handling space-* property. */
private RtfSpaceManager rtfSpaceManager = new RtfSpaceManager();
@@ -68,10 +86,12 @@ public class RtfTextrun extends RtfContainer {
/** Class which represents the closing of a RTF group mark.*/
private class RtfCloseGroupMark extends RtfElement {
+ private int breakType = BREAK_NONE;
- RtfCloseGroupMark(RtfContainer parent, Writer w)
- throws IOException {
+ RtfCloseGroupMark(RtfContainer parent, Writer w, int breakType)
+ throws IOException {
super(parent, w);
+ this.breakType = breakType;
}
/**
@@ -82,11 +102,44 @@ public class RtfTextrun extends RtfContainer {
}
/**
- * write RTF code of all our children
+ * Returns the break type.
+ * @return the break type (BREAK_* constants)
+ */
+ public int getBreakType() {
+ return breakType;
+ }
+
+ /**
+ * Write RTF code of all our children.
* @throws IOException for I/O problems
*/
protected void writeRtfContent() throws IOException {
writeGroupMark(false);
+ boolean bHasTableCellParent = this.getParentOfClass(RtfTableCell.class) != null;
+
+ //Unknown behavior when a table starts a new section,
+ //Word may crash
+ if (breakType != BREAK_NONE) {
+ if (!bHasTableCellParent) {
+ writeControlWord("sect");
+ /* The following modifiers don't seem to appear in the right place */
+ switch (breakType) {
+ case BREAK_EVEN_PAGE:
+ writeControlWord("sbkeven");
+ break;
+ case BREAK_ODD_PAGE:
+ writeControlWord("sbkodd");
+ break;
+ case BREAK_COLUMN:
+ writeControlWord("sbkcol");
+ break;
+ default:
+ writeControlWord("sbkpage");
+ }
+ } else {
+ log.warn("Cannot create break-after for a paragraph inside a table.");
+ }
+ }
}
}
@@ -135,8 +188,18 @@ public class RtfTextrun extends RtfContainer {
*
* @throws IOException for I/O problems
*/
+ private void addCloseGroupMark(int breakType) throws IOException {
+ RtfCloseGroupMark r = new RtfCloseGroupMark(this, writer, breakType);
+ }
+
+ /**
+ * Adds instance of <code>CloseGroupMark</code> as a child, but without a break option.
+ * Inline attributes do not need that for example
+ *
+ * @throws IOException for I/O problems
+ */
private void addCloseGroupMark() throws IOException {
- RtfCloseGroupMark r = new RtfCloseGroupMark(this, writer);
+ RtfCloseGroupMark r = new RtfCloseGroupMark(this, writer, BREAK_NONE);
}
/**
@@ -155,14 +218,14 @@ public class RtfTextrun extends RtfContainer {
/**
* Pops block attributes, notifies all opened blocks about pushing block
* attributes, adds <code>CloseGroupMark</code> as a child.
- *
+ * @param breakType the break type
* @throws IOException for I/O problems
*/
- public void popBlockAttributes() throws IOException {
- rtfSpaceManager.popRtfSpaceSplitter();
- rtfSpaceManager.stopUpdatingSpaceBefore();
- addCloseGroupMark();
- }
+ public void popBlockAttributes(int breakType) throws IOException {
+ rtfSpaceManager.popRtfSpaceSplitter();
+ rtfSpaceManager.stopUpdatingSpaceBefore();
+ addCloseGroupMark(breakType);
+ }
/**
* Pushes inline attributes.
@@ -228,28 +291,30 @@ public class RtfTextrun extends RtfContainer {
* @throws IOException for I/O problems
*/
public void addParagraphBreak() throws IOException {
- // get copy of children list
- List children = getChildren();
-
- // delete all previous CloseGroupMark
- int deletedCloseGroupCount = 0;
-
- ListIterator lit = children.listIterator(children.size());
- while (lit.hasPrevious()
- && (lit.previous() instanceof RtfCloseGroupMark)) {
- lit.remove();
- deletedCloseGroupCount++;
- }
-
- if (children.size() != 0) {
- // add paragraph break and restore all deleted close group marks
- setChildren(children);
- new RtfParagraphBreak(this, writer);
- for (int i = 0; i < deletedCloseGroupCount; i++) {
- addCloseGroupMark();
- }
- }
- }
+ // get copy of children list
+ List children = getChildren();
+ Stack tmp = new Stack();
+
+ // delete all previous CloseGroupMark
+ int deletedCloseGroupCount = 0;
+
+ ListIterator lit = children.listIterator(children.size());
+ while (lit.hasPrevious()
+ && (lit.previous() instanceof RtfCloseGroupMark)) {
+ tmp.push(new Integer(((RtfCloseGroupMark)lit.next()).getBreakType()));
+ lit.remove();
+ deletedCloseGroupCount++;
+ }
+
+ if (children.size() != 0) {
+ // add paragraph break and restore all deleted close group marks
+ setChildren(children);
+ new RtfParagraphBreak(this, writer);
+ for (int i = 0; i < deletedCloseGroupCount; i++) {
+ addCloseGroupMark(((Integer)tmp.pop()).intValue());
+ }
+ }
+ }
/**
* Inserts a leader.
diff --git a/src/java/org/apache/fop/svg/AbstractFOPTranscoder.java b/src/java/org/apache/fop/svg/AbstractFOPTranscoder.java
index fc007b90a..aa8c5238c 100644
--- a/src/java/org/apache/fop/svg/AbstractFOPTranscoder.java
+++ b/src/java/org/apache/fop/svg/AbstractFOPTranscoder.java
@@ -29,6 +29,7 @@ import org.w3c.dom.DOMImplementation;
import org.xml.sax.EntityResolver;
+import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.DefaultConfiguration;
@@ -55,7 +56,7 @@ import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext;
/**
* This is the common base class of all of FOP's transcoders.
*/
-public abstract class AbstractFOPTranscoder extends SVGAbstractTranscoder {
+public abstract class AbstractFOPTranscoder extends SVGAbstractTranscoder implements Configurable {
/**
* The key is used to specify the resolution for on-the-fly images generated
diff --git a/src/java/org/apache/fop/svg/NativeTextPainter.java b/src/java/org/apache/fop/svg/NativeTextPainter.java
index 14fa6460d..94d426396 100644
--- a/src/java/org/apache/fop/svg/NativeTextPainter.java
+++ b/src/java/org/apache/fop/svg/NativeTextPainter.java
@@ -111,9 +111,9 @@ public abstract class NativeTextPainter extends StrokingTextPainter {
String style = ((posture != null) && (posture.floatValue() > 0.0))
? Font.STYLE_ITALIC : Font.STYLE_NORMAL;
- int weight = ((taWeight != null)
- && (taWeight.floatValue() > 1.0)) ? Font.WEIGHT_BOLD
- : Font.WEIGHT_NORMAL;
+ int weight = toCSSWeight(taWeight != null
+ ? taWeight.floatValue()
+ : TextAttribute.WEIGHT_REGULAR.floatValue());
String firstFontFamily = null;
@@ -176,6 +176,28 @@ public abstract class NativeTextPainter extends StrokingTextPainter {
return (Font[])fonts.toArray(new Font[fonts.size()]);
}
+ private int toCSSWeight(float weight) {
+ if (weight <= TextAttribute.WEIGHT_EXTRA_LIGHT.floatValue()) {
+ return 100;
+ } else if (weight <= TextAttribute.WEIGHT_LIGHT.floatValue()) {
+ return 200;
+ } else if (weight <= TextAttribute.WEIGHT_DEMILIGHT.floatValue()) {
+ return 300;
+ } else if (weight <= TextAttribute.WEIGHT_REGULAR.floatValue()) {
+ return 400;
+ } else if (weight <= TextAttribute.WEIGHT_SEMIBOLD.floatValue()) {
+ return 500;
+ } else if (weight <= TextAttribute.WEIGHT_BOLD.floatValue()) {
+ return 600;
+ } else if (weight <= TextAttribute.WEIGHT_HEAVY.floatValue()) {
+ return 700;
+ } else if (weight <= TextAttribute.WEIGHT_EXTRABOLD.floatValue()) {
+ return 800;
+ } else {
+ return 900;
+ }
+ }
+
/**
* Collects all characters from an {@link AttributedCharacterIterator}.
* @param runaci the character iterator
diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java
index cf3053e19..409b8dd9f 100644
--- a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java
+++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java
@@ -256,6 +256,7 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D {
if (!pdfContext.isPagePending()) {
return; //ignore
}
+ currentStream.write("Q\n");
//Finish page
PDFStream pdfStream = this.pdfDoc.getFactory().makeStream(
PDFFilterList.CONTENT_FILTER, false);
@@ -321,6 +322,7 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D {
pdfContext.setCurrentPage(page);
pageRef = page.referencePDF();
+ currentStream.write("q\n");
AffineTransform at = new AffineTransform(1.0, 0.0, 0.0, -1.0,
0.0, height);
currentStream.write("1 0 0 -1 0 " + height + " cm\n");
diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java
index b77518ab0..24974b01a 100644
--- a/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java
+++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2DConfigurator.java
@@ -25,12 +25,15 @@ import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.fop.apps.FOPException;
+import org.apache.fop.fonts.CustomFontCollection;
+import org.apache.fop.fonts.FontCollection;
import org.apache.fop.fonts.FontEventListener;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontInfoConfigurator;
import org.apache.fop.fonts.FontManager;
+import org.apache.fop.fonts.FontManagerConfigurator;
import org.apache.fop.fonts.FontResolver;
-import org.apache.fop.fonts.FontSetup;
+import org.apache.fop.fonts.base14.Base14FontCollection;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.render.pdf.PDFRendererConfigurator;
@@ -70,29 +73,30 @@ public class PDFDocumentGraphics2DConfigurator {
*/
public static FontInfo createFontInfo(Configuration cfg) throws FOPException {
FontInfo fontInfo = new FontInfo();
+ final boolean strict = false;
+ FontResolver fontResolver = FontManager.createMinimalFontResolver();
+ //TODO The following could be optimized by retaining the FontManager somewhere
+ FontManager fontManager = new FontManager();
if (cfg != null) {
- FontResolver fontResolver = FontManager.createMinimalFontResolver();
- //TODO The following could be optimized by retaining the FontManager somewhere
- FontManager fontManager = new FontManager();
+ FontManagerConfigurator fmConfigurator = new FontManagerConfigurator(cfg);
+ fmConfigurator.configure(fontManager, strict);
+ }
- //TODO Make use of fontBaseURL, font substitution and referencing configuration
- //Requires a change to the expected configuration layout
+ List fontCollections = new java.util.ArrayList();
+ fontCollections.add(new Base14FontCollection(fontManager.isBase14KerningEnabled()));
+ if (cfg != null) {
//TODO Wire in the FontEventListener
- final FontEventListener listener = null;
- final boolean strict = false;
+ FontEventListener listener = null; //new FontEventAdapter(eventBroadcaster);
FontInfoConfigurator fontInfoConfigurator
= new FontInfoConfigurator(cfg, fontManager, fontResolver, listener, strict);
List/*<EmbedFontInfo>*/ fontInfoList = new java.util.ArrayList/*<EmbedFontInfo>*/();
fontInfoConfigurator.configure(fontInfoList);
-
- if (fontManager.useCache()) {
- fontManager.getFontCache().save();
- }
- FontSetup.setup(fontInfo, fontInfoList, fontResolver);
- } else {
- FontSetup.setup(fontInfo);
+ fontCollections.add(new CustomFontCollection(fontResolver, fontInfoList));
}
+ fontManager.setup(fontInfo,
+ (FontCollection[])fontCollections.toArray(
+ new FontCollection[fontCollections.size()]));
return fontInfo;
}
diff --git a/src/java/org/apache/fop/svg/PDFTranscoder.java b/src/java/org/apache/fop/svg/PDFTranscoder.java
index fc27cb48a..bf08b2fcf 100644
--- a/src/java/org/apache/fop/svg/PDFTranscoder.java
+++ b/src/java/org/apache/fop/svg/PDFTranscoder.java
@@ -27,7 +27,6 @@ import java.io.OutputStream;
import org.w3c.dom.Document;
import org.w3c.dom.svg.SVGLength;
-import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.UnitProcessor;
@@ -73,8 +72,7 @@ import org.apache.fop.fonts.FontInfo;
* @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
* @version $Id$
*/
-public class PDFTranscoder extends AbstractFOPTranscoder
- implements Configurable {
+public class PDFTranscoder extends AbstractFOPTranscoder {
/** Graphics2D instance that is used to paint to */
protected PDFDocumentGraphics2D graphics = null;
diff --git a/src/java/org/apache/fop/tools/anttasks/Fop.java b/src/java/org/apache/fop/tools/anttasks/Fop.java
index c0a1ba9f7..58dd1fb5b 100644
--- a/src/java/org/apache/fop/tools/anttasks/Fop.java
+++ b/src/java/org/apache/fop/tools/anttasks/Fop.java
@@ -20,14 +20,6 @@
package org.apache.fop.tools.anttasks;
// Ant
-import org.apache.tools.ant.BuildException;
-import org.apache.tools.ant.DirectoryScanner;
-import org.apache.tools.ant.Project;
-import org.apache.tools.ant.Task;
-import org.apache.tools.ant.types.FileSet;
-import org.apache.tools.ant.util.GlobPatternMapper;
-
-// Java
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
@@ -36,17 +28,23 @@ import java.net.MalformedURLException;
import java.util.List;
import java.util.Vector;
-// FOP
+import org.xml.sax.SAXException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.impl.SimpleLog;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.GlobPatternMapper;
+
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.cli.InputHandler;
-import org.apache.commons.logging.impl.SimpleLog;
-import org.apache.commons.logging.Log;
-import org.xml.sax.SAXException;
-
/**
* Wrapper for FOP which allows it to be accessed from within an Ant task.
* Accepts the inputs:
@@ -156,7 +154,7 @@ public class Fop extends Task {
}
/**
- * Sets the XSLT parameters
+ * Sets the XSLT parameters
* @param xsltParams the XSLT parameters
*/
public void setXsltParams(String xsltParams) {
@@ -267,7 +265,7 @@ public class Fop extends Task {
/**
* Set whether exceptions are thrown.
* default is false.
- * @param throwExceptions true if should be thrown
+ * @param throwExceptions true if exceptions should be thrown
*/
public void setThrowexceptions(boolean throwExceptions) {
this.throwExceptions = throwExceptions;
@@ -553,7 +551,7 @@ class FOPTaskStarter {
// OR output file doesn't exist OR
// output file is older than input file
if (task.getForce() || !outf.exists()
- || (task.getXmlFile().lastModified() > outf.lastModified()
+ || (task.getXmlFile().lastModified() > outf.lastModified()
|| task.getXsltFile().lastModified() > outf.lastModified())) {
render(task.getXmlFile(), task.getXsltFile(), outf, outputFormat);
actioncount++;
@@ -639,8 +637,8 @@ class FOPTaskStarter {
}
}
- private void renderInputHandler
- (InputHandler inputHandler, File outFile, String outputFormat) throws Exception {
+ private void renderInputHandler(InputHandler inputHandler, File outFile, String outputFormat)
+ throws Exception {
OutputStream out = null;
try {
out = new java.io.FileOutputStream(outFile);
diff --git a/src/java/org/apache/fop/traits/MinOptMax.java b/src/java/org/apache/fop/traits/MinOptMax.java
index 99fab1adf..45b55695f 100644
--- a/src/java/org/apache/fop/traits/MinOptMax.java
+++ b/src/java/org/apache/fop/traits/MinOptMax.java
@@ -56,8 +56,7 @@ public final class MinOptMax implements Serializable {
* @return the corresponding instance
* @throws IllegalArgumentException if <code>min > opt || max < opt</code>.
*/
- public static MinOptMax getInstance(int min, int opt, int max)
- throws IllegalArgumentException {
+ public static MinOptMax getInstance(int min, int opt, int max) throws IllegalArgumentException {
if (min > opt) {
throw new IllegalArgumentException("min (" + min + ") > opt (" + opt + ")");
}
@@ -168,8 +167,7 @@ public final class MinOptMax implements Serializable {
* @throws ArithmeticException if this instance has strictly less shrink or stretch
* than the operand
*/
- public MinOptMax minus(MinOptMax operand)
- throws ArithmeticException {
+ public MinOptMax minus(MinOptMax operand) throws ArithmeticException {
checkCompatibility(getShrink(), operand.getShrink(), "shrink");
checkCompatibility(getStretch(), operand.getStretch(), "stretch");
return new MinOptMax(min - operand.min, opt - operand.opt, max - operand.max);
@@ -194,58 +192,54 @@ public final class MinOptMax implements Serializable {
}
/**
- * Returns an instance with the given value added to the minimal value.
+ * Do not use, backwards compatibility only. Returns an instance with the
+ * given value added to the minimal value.
*
* @param minOperand the minimal value to be added.
* @return an instance with the given value added to the minimal value.
- * @throws IllegalArgumentException if <code>min + minOperand > opt || max < opt</code>.
+ * @throws IllegalArgumentException if
+ * <code>min + minOperand > opt || max < opt</code>.
*/
- // [GA] remove deprecation - no alternative specified
- // @deprecated Do not use! It's only for backwards compatibility.
- public MinOptMax plusMin(int minOperand)
- throws IllegalArgumentException {
+ public MinOptMax plusMin(int minOperand) throws IllegalArgumentException {
return getInstance(min + minOperand, opt, max);
}
/**
- * Returns an instance with the given value subtracted to the minimal value.
+ * Do not use, backwards compatibility only. Returns an instance with the
+ * given value subtracted to the minimal value.
*
* @param minOperand the minimal value to be subtracted.
* @return an instance with the given value subtracted to the minimal value.
- * @throws IllegalArgumentException if <code>min - minOperand > opt || max < opt</code>.
+ * @throws IllegalArgumentException if
+ * <code>min - minOperand > opt || max < opt</code>.
*/
- // [GA] remove deprecation - no alternative specified
- // @deprecated Do not use! It's only for backwards compatibility.
- public MinOptMax minusMin(int minOperand)
- throws IllegalArgumentException {
+ public MinOptMax minusMin(int minOperand) throws IllegalArgumentException {
return getInstance(min - minOperand, opt, max);
}
/**
- * Returns an instance with the given value added to the maximal value.
+ * Do not use, backwards compatibility only. Returns an instance with the
+ * given value added to the maximal value.
*
* @param maxOperand the maximal value to be added.
* @return an instance with the given value added to the maximal value.
- * @throws IllegalArgumentException if <code>min > opt || max < opt + maxOperand</code>.
+ * @throws IllegalArgumentException if
+ * <code>min > opt || max < opt + maxOperand</code>.
*/
- // [GA] remove deprecation - no alternative specified
- // @deprecated Do not use! It's only for backwards compatibility.
- public MinOptMax plusMax(int maxOperand)
- throws IllegalArgumentException {
+ public MinOptMax plusMax(int maxOperand) throws IllegalArgumentException {
return getInstance(min, opt, max + maxOperand);
}
/**
- * Returns an instance with the given value subtracted to the maximal value.
+ * Do not use, backwards compatibility only. Returns an instance with the
+ * given value subtracted to the maximal value.
*
* @param maxOperand the maximal value to be subtracted.
* @return an instance with the given value subtracted to the maximal value.
- * @throws IllegalArgumentException if <code>min > opt || max < opt - maxOperand</code>.
+ * @throws IllegalArgumentException if
+ * <code>min > opt || max < opt - maxOperand</code>.
*/
- // [GA] remove deprecation - no alternative specified
- // @deprecated Do not use! It's only for backwards compatibility.
- public MinOptMax minusMax(int maxOperand)
- throws IllegalArgumentException {
+ public MinOptMax minusMax(int maxOperand) throws IllegalArgumentException {
return getInstance(min, opt, max - maxOperand);
}
@@ -256,8 +250,7 @@ public final class MinOptMax implements Serializable {
* @return the product of this <code>MinOptMax</code> and the given factor
* @throws IllegalArgumentException if the factor is negative
*/
- public MinOptMax mult(int factor)
- throws IllegalArgumentException {
+ public MinOptMax mult(int factor) throws IllegalArgumentException {
if (factor < 0) {
throw new IllegalArgumentException("factor < 0; was: " + factor);
} else if (factor == 1) {
diff --git a/status.xml b/status.xml
index 1f0916753..b651ddf89 100644
--- a/status.xml
+++ b/status.xml
@@ -58,6 +58,18 @@
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="JM" type="add" fixes-bug="42600" due-to="Maximilian Aster">
+ Added some support for break-before/-after for RTF output.
+ </action>
+ <action context="Renderers" dev="JM" type="add" fixes-bug="49379" due-to="Peter Hancock">
+ Added ability to embed an external AFP page segment resource file (AFP output only).
+ </action>
+ <action context="Renderers" dev="JM" type="fix" fixes-bug="46360" due-to="Alexis Giotis">
+ Fixed a multi-threading issue when rendering SVG.
+ </action>
+ <action context="Layout" dev="JM" type="fix" fixes-bug="49885">
+ Fixed retrieval of available BPD for cases spanning columns and multiple pages with differing page masters.
+ </action>
<action context="Renderers" dev="VH" type="remove">
Removed old Renderer implementations for those output formats that have a version based on
the new DocumentHandler architecture available (AFP, PCL, PDF, PS).
@@ -395,6 +407,9 @@
Fixed a problem where the BPD or a block area could be wrong if there is a nested,
absolutely positioned area (for example a block-container).
</action>
+ <action context="Code" dev="VH" type="fix" fixes-bug="45971" due-to="Tow Browder">
+ Improved the behaviour of the command line interface.
+ </action>
<action context="Layout" dev="AD" type="fix" fixes-bug="40798">
Bugzilla 40798: A conditional-page-master-reference with page-position="last" qualifies
for a first page, if it is also the last. Additionally: also added support for
diff --git a/test/java/org/apache/fop/fonts/EncodingModeTest.java b/test/java/org/apache/fop/fonts/EncodingModeTest.java
new file mode 100644
index 000000000..4e81c46d6
--- /dev/null
+++ b/test/java/org/apache/fop/fonts/EncodingModeTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.fonts;
+
+import junit.framework.TestCase;
+
+public class EncodingModeTest extends TestCase {
+ public void testGetName() {
+ assertEquals("auto", EncodingMode.AUTO.getName());
+ assertEquals("single-byte", EncodingMode.SINGLE_BYTE.getName());
+ assertEquals("cid", EncodingMode.CID.getName());
+ }
+
+ public void testGetValue() {
+ assertEquals(EncodingMode.AUTO, EncodingMode.getEncodingMode("auto"));
+ assertEquals(EncodingMode.SINGLE_BYTE, EncodingMode.getEncodingMode("single-byte"));
+ assertEquals(EncodingMode.CID, EncodingMode.getEncodingMode("cid"));
+ }
+}
diff --git a/test/layoutengine/hyphenation-testcases/hyphenation-pattern_fallback.xml b/test/layoutengine/hyphenation-testcases/hyphenation-pattern_fallback.xml
new file mode 100644
index 000000000..3af71a3ea
--- /dev/null
+++ b/test/layoutengine/hyphenation-testcases/hyphenation-pattern_fallback.xml
@@ -0,0 +1,137 @@
+<?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>
+ Checks fallback from hyphenation pattern for (lang,country) to hyphenation pattern for (lang)
+ </p>
+ </info>
+ <fo>
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="simple"
+ page-height="29.7cm"
+ page-width="21cm"
+ margin-top="1cm"
+ margin-bottom="2cm"
+ margin-left="7cm"
+ margin-right="3cm">
+ <fo:region-body margin-top="1.5cm"/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <!-- end: defines page layout -->
+
+
+ <fo:page-sequence master-reference="simple">
+
+ <fo:flow flow-name="xsl-region-body"
+ text-align="justify">
+
+ <fo:block font-size="12pt"
+ font-family="sans-serif"
+ background-color="blue"
+ color="white"
+ text-align="start">
+ language="en",country="IN"
+ </fo:block>
+ <fo:block font-size="12pt"
+ font-family="sans-serif"
+ space-after="3pt"
+ language="en"
+ country="IN"
+ hyphenate="true"
+ hyphenation-ladder-count="no-limit"
+ >
+ This document has been reviewed by W3C Members and other interested parties and has been endorsed by the Director as a
+ W3C Recommendation. It is a stable document and may be used as reference material or cited as a normative reference from
+ another document. W3C's role in making the Recommendation is to draw attention to the specification and to promote its
+ widespread deployment. This enhances the functionality and interoperability of the Web.
+ </fo:block>
+
+ <fo:block font-size="12pt"
+ font-family="sans-serif"
+ background-color="blue"
+ color="white"
+ text-align="start">
+ language="em"
+ </fo:block>
+ <fo:block font-size="12pt"
+ font-family="sans-serif"
+ space-after="3pt"
+ language="em"
+ hyphenate="true"
+ hyphenation-ladder-count="no-limit"
+ >
+ This document has been reviewed by W3C Members and other interested parties and has been endorsed by the Director as a
+ W3C Recommendation. It is a stable document and may be used as reference material or cited as a normative reference from
+ another document. W3C's role in making the Recommendation is to draw attention to the specification and to promote its
+ widespread deployment. This enhances the functionality and interoperability of the Web.
+ </fo:block>
+
+ <fo:block font-size="12pt"
+ font-family="sans-serif"
+ background-color="blue"
+ color="white"
+ text-align="start">
+ language="em",country="IN"
+ </fo:block>
+ <fo:block font-size="12pt"
+ font-family="sans-serif"
+ space-after="3pt"
+ language="em"
+ country="IN"
+ hyphenate="true"
+ hyphenation-ladder-count="no-limit"
+ >
+ This document has been reviewed by W3C Members and other interested parties and has been endorsed by the Director as a
+ W3C Recommendation. It is a stable document and may be used as reference material or cited as a normative reference from
+ another document. W3C's role in making the Recommendation is to draw attention to the specification and to promote its
+ widespread deployment. This enhances the functionality and interoperability of the Web.
+ </fo:block>
+
+ </fo:flow>
+ </fo:page-sequence>
+</fo:root>
+
+ </fo>
+
+ <checks>
+ <eval expected="8" xpath="count(//pageViewport[1]//flow/block[2]/lineArea)"/>
+ <eval expected="Di-" xpath="//pageViewport[1]//flow/block[2]/lineArea[2]/text/word[10]"/>
+ <eval expected="norma-" xpath="//pageViewport[1]//flow/block[2]/lineArea[4]/text/word[12]"/>
+ <eval expected="mak-" xpath="//pageViewport[1]//flow/block[2]/lineArea[5]/text/word[9]"/>
+ <eval expected="specifi-" xpath="//pageViewport[1]//flow/block[2]/lineArea[6]/text/word[10]"/>
+ <eval expected="en-" xpath="//pageViewport[1]//flow/block[2]/lineArea[7]/text/word[9]"/>
+
+ <eval expected="9" xpath="count(//pageViewport[1]//flow/block[4]/lineArea)"/>
+ <eval expected="by" xpath="//pageViewport[1]//flow/block[4]/lineArea[2]/text/word[9]"/>
+ <eval expected="cited" xpath="//pageViewport[1]//flow/block[4]/lineArea[4]/text/word[10]"/>
+ <eval expected="document." xpath="//pageViewport[1]//flow/block[4]/lineArea[5]/text/word[7]"/>
+ <eval expected="to" xpath="//pageViewport[1]//flow/block[4]/lineArea[6]/text/word[10]"/>
+ <eval expected="deployment." xpath="//pageViewport[1]//flow/block[4]/lineArea[7]/text/word[8]"/>
+
+ <eval expected="9" xpath="count(//pageViewport[1]//flow/block[6]/lineArea)"/>
+ <eval expected="by" xpath="//pageViewport[1]//flow/block[6]/lineArea[2]/text/word[9]"/>
+ <eval expected="cited" xpath="//pageViewport[1]//flow/block[6]/lineArea[4]/text/word[10]"/>
+ <eval expected="document." xpath="//pageViewport[1]//flow/block[6]/lineArea[5]/text/word[7]"/>
+ <eval expected="to" xpath="//pageViewport[1]//flow/block[6]/lineArea[6]/text/word[10]"/>
+ <eval expected="deployment." xpath="//pageViewport[1]//flow/block[6]/lineArea[7]/text/word[8]"/>
+ </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/flow_changing-ipd_table-after-break.xml b/test/layoutengine/standard-testcases/flow_changing-ipd_table-after-break.xml
index 956563e20..1b10d722c 100644
--- a/test/layoutengine/standard-testcases/flow_changing-ipd_table-after-break.xml
+++ b/test/layoutengine/standard-testcases/flow_changing-ipd_table-after-break.xml
@@ -56,13 +56,19 @@
<fo:table table-layout="fixed" width="100%">
<fo:table-body>
<fo:table-row>
- <fo:table-cell>
- <fo:block>After the table 1</fo:block>
+ <fo:table-cell border="1pt solid black">
+ <fo:block>Cell 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell border="1pt solid black">
+ <fo:block>Cell 1.2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
- <fo:table-cell>
- <fo:block>After the table 2</fo:block>
+ <fo:table-cell border="1pt solid black">
+ <fo:block>Cell 2.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell border="1pt solid black">
+ <fo:block>Cell 2.2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
@@ -74,7 +80,12 @@
<checks>
<eval expected="Block before the page break." xpath="//pageViewport[1]//flow/block[2]//text"/>
<eval expected="Block after the page break." xpath="//pageViewport[2]//flow/block[1]//text"/>
- <eval expected="After the table 1" xpath="//pageViewport[2]//flow/block[2]/block[1]//text"/>
- <eval expected="After the table 2" xpath="//pageViewport[2]//flow/block[2]/block[2]//text"/>
+ <eval expected="400000" xpath="//pageViewport[2]//flow/block[2]/@ipd"/>
+ <eval expected="199000" xpath="//pageViewport[2]//flow/block[2]/block[1]/@ipd"/>
+ <eval expected="Cell 1.1" xpath="//pageViewport[2]//flow/block[2]/block[1]//text"/>
+ <eval expected="199000" xpath="//pageViewport[2]//flow/block[2]/block[2]/@ipd"/>
+ <eval expected="Cell 1.2" xpath="//pageViewport[2]//flow/block[2]/block[2]//text"/>
+ <eval expected="Cell 2.1" xpath="//pageViewport[2]//flow/block[2]/block[3]//text"/>
+ <eval expected="Cell 2.2" xpath="//pageViewport[2]//flow/block[2]/block[4]//text"/>
</checks>
</testcase>
diff --git a/test/layoutengine/standard-testcases/region-body_column-count_span_4.xml b/test/layoutengine/standard-testcases/region-body_column-count_span_4.xml
new file mode 100644
index 000000000..8bc4652ce
--- /dev/null
+++ b/test/layoutengine/standard-testcases/region-body_column-count_span_4.xml
@@ -0,0 +1,84 @@
+<?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 multi-column documents. Check that spanned section that are broken over
+ to multiple pages still respect the span setting. This particular test makes sure that pages with different region-body
+ height are handled properly.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="odd-page" page-height="3.5cm" page-width="4cm" margin="0.45cm">
+ <fo:region-body margin-top="12pt * 1.2 * 2" column-count="2" background-color="yellow"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="even-page" page-height="3.5cm" page-width="4cm" margin="0.45cm">
+ <fo:region-body column-count="2" background-color="orange"/>
+ </fo:simple-page-master>
+ <fo:page-sequence-master master-name="master">
+ <fo:repeatable-page-master-alternatives>
+ <fo:conditional-page-master-reference master-reference="odd-page" odd-or-even="odd" blank-or-not-blank="not-blank"/>
+ <fo:conditional-page-master-reference master-reference="even-page" odd-or-even="even" blank-or-not-blank="not-blank"/>
+ </fo:repeatable-page-master-alternatives>
+ </fo:page-sequence-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="master">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block span="all">
+ <fo:block>Line 1</fo:block>
+ <fo:block>Line 2</fo:block>
+ <fo:block>Line 3</fo:block>
+ <fo:block>Line 4</fo:block>
+ <fo:block>Line 5</fo:block>
+ <fo:block>Line 6</fo:block>
+ <fo:block>Line 7</fo:block>
+ <fo:block>Line 8</fo:block>
+ <fo:block>Line 9</fo:block>
+ <fo:block>Line 10</fo:block>
+ <fo:block>Line 11</fo:block>
+ <fo:block>Line 12</fo:block>
+ <fo:block>Line 13</fo:block>
+ <fo:block>Line 14</fo:block>
+ <fo:block>Line 15</fo:block>
+ <fo:block>Line 16</fo:block>
+ <fo:block>Line 17</fo:block>
+ <fo:block>Line 18</fo:block>
+ <fo:block>Line 19</fo:block>
+ <fo:block>Line 20</fo:block>
+ <fo:block>Line 21</fo:block>
+ <fo:block>Line 22</fo:block>
+ </fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks>
+ <eval expected="6" xpath="count(//pageViewport)"/>
+
+ <eval expected="3" xpath="count(//pageViewport[@nr=1]//lineArea)"/>
+ <eval expected="5" xpath="count(//pageViewport[@nr=2]//lineArea)"/>
+ <eval expected="3" xpath="count(//pageViewport[@nr=3]//lineArea)"/>
+ <eval expected="5" xpath="count(//pageViewport[@nr=4]//lineArea)"/>
+ <eval expected="3" xpath="count(//pageViewport[@nr=5]//lineArea)"/>
+ <eval expected="3" xpath="count(//pageViewport[@nr=6]//lineArea)"/>
+
+ </checks>
+</testcase>
diff --git a/xmlgraphics-fop-pom-template.pom b/xmlgraphics-fop-pom-template.pom
index f4389cb96..efa30f67f 100644
--- a/xmlgraphics-fop-pom-template.pom
+++ b/xmlgraphics-fop-pom-template.pom
@@ -19,7 +19,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
-http://maven.apache.org/maven-v4_0_0.xsd">
+http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>fop</artifactId>
@@ -59,18 +59,23 @@ http://maven.apache.org/maven-v4_0_0.xsd">
<scm>
<connection>scm:svn:http://svn.apache.org/repos/asf/xmlgraphics/fop/trunk</connection>
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk</developerConnection>
- <url>http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/trunk/?root=Apache-SVN</url>
+ <url>http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/?root=Apache-SVN</url>
</scm>
<organization>
<name>Apache Software Foundation</name>
<url>http://www.apache.org/</url>
</organization>
+ <parent>
+ <groupId>org.apache</groupId>
+ <artifactId>apache</artifactId>
+ <version>7</version>
+ </parent>
<dependencies>
<!-- XML Graphics -->
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>xmlgraphics-commons</artifactId>
- <version>1.3</version>
+ <version>1.4</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>