aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2010-01-21 17:37:07 +0000
committerJeremias Maerki <jeremias@apache.org>2010-01-21 17:37:07 +0000
commitbb2844e0645707a666fcf43e7fbcb32c8daca49c (patch)
treef4f06a9011c874cac381d97942cac868e0ff15f8 /src
parentab6e2cc40a0c0dde6b98eec000ab94d1c7e35cb1 (diff)
downloadxmlgraphics-fop-bb2844e0645707a666fcf43e7fbcb32c8daca49c.tar.gz
xmlgraphics-fop-bb2844e0645707a666fcf43e7fbcb32c8daca49c.zip
Bugzilla #48567:
Initial support for CID-keyed double-byte fonts (Type 0) in AFP output. Submitted by: Peter Hancock <peter.hancock.at.gmail.com> Patch modified by jeremias: - as discussed: removed fallback character code - as discussed: changed "double-byte" to "CIDKeyed" for the font type. - some cosmetic changes - removed some dead code and commented code. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@901793 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r--src/documentation/content/xdocs/trunk/output.xml15
-rw-r--r--src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java177
-rw-r--r--src/java/org/apache/fop/afp/fonts/CharacterSet.java62
-rw-r--r--src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java (renamed from src/java/org/apache/fop/afp/fonts/AFPFontReader.java)240
-rw-r--r--src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java47
-rw-r--r--src/java/org/apache/fop/afp/fonts/DoubleByteFont.java90
-rw-r--r--src/java/org/apache/fop/afp/fonts/OutlineFont.java159
-rw-r--r--src/java/org/apache/fop/afp/modca/MapCodedFont.java27
-rw-r--r--src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java97
9 files changed, 635 insertions, 279 deletions
diff --git a/src/documentation/content/xdocs/trunk/output.xml b/src/documentation/content/xdocs/trunk/output.xml
index 01af40a56..54ed357a0 100644
--- a/src/documentation/content/xdocs/trunk/output.xml
+++ b/src/documentation/content/xdocs/trunk/output.xml
@@ -548,10 +548,11 @@ out = proc.getOutputStream();]]></source>
<!-- AFP Renderer -->
...
</renderer>]]></source>
- <p>There are 3 font configuration variants supported:</p>
+ <p>There are 4 font configuration variants supported:</p>
<ol>
<li>IBM Raster fonts</li>
<li>IBM Outline fonts</li>
+ <li>IBM CID-keyed (Type 0) fonts</li>
<li>FOP built-in Base14 fonts</li>
</ol>
<p>A typical raster font configuration looks like:</p>
@@ -600,6 +601,18 @@ out = proc.getOutputStream();]]></source>
supported for the time being, but you should move to using the more flexible "base-uri"
attribute so you can profit from the power of URI resolvers.
</note>
+ <p>A CID-keyed font (Type 0, double-byte outline font) configuration is much the same as an outline font.
+ However, the characterset definition is now required within the afp-font element.</p>
+<source><![CDATA[ <font>
+ <afp-font type="CIDKeyed" characterset="CZJHMNU"
+ codepage="T1120000" encoding="UnicodeBigUnmarked"
+ base-uri="file:/fonts/ibm" />
+ <font-triplet name="J-Heisei Mincho" style="normal" weight="normal" />
+ </font>
+]]></source>
+ <p>
+Note that the value of the encoding attribute in the example is the double-byte encoding 'UnicodeBigUnmarked' (UTF-16BE).
+ </p>
<p>Experimentation has shown that the font metrics for the FOP built-in Base14 fonts are actually
very similar to some of the IBM outline and raster fonts. In cases were the IBM font files are not
available the base-uri attribute in the afp-font element can be replaced by a base14-font attribute
diff --git a/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java b/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java
new file mode 100644
index 000000000..2061e9d82
--- /dev/null
+++ b/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java
@@ -0,0 +1,177 @@
+/*
+ * 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.fonts;
+
+/**
+ * A font defined as a set of lines and curves as opposed to a bitmap font. An
+ * outline font can be scaled to any size and otherwise transformed more easily
+ * than a bitmap font, and with more attractive results.
+ */
+public abstract class AbstractOutlineFont extends AFPFont {
+
+ /** The character set for this font */
+ protected CharacterSet charSet = null;
+
+ /**
+ * Constructor for an outline font.
+ *
+ * @param name
+ * the name of the font
+ * @param charSet
+ * the chracter set
+ */
+ public AbstractOutlineFont(String name, CharacterSet charSet) {
+ super(name);
+ this.charSet = charSet;
+ }
+
+ /**
+ * Get the character set metrics.
+ *
+ * @return the character set
+ */
+ public CharacterSet getCharacterSet() {
+ return charSet;
+ }
+
+ /**
+ * Get the character set metrics.
+ * @param size ignored
+ * @return the character set
+ */
+ public CharacterSet getCharacterSet(int size) {
+ return charSet;
+ }
+
+ /**
+ * Get the first character in this font.
+ * @return the first character in this font
+ */
+ public int getFirstChar() {
+ return charSet.getFirstChar();
+ }
+
+ /**
+ * Get the last character in this font.
+ * @return the last character in this font
+ */
+ public int getLastChar() {
+ return charSet.getLastChar();
+ }
+
+ /**
+ * The ascender is the part of a lowercase letter that extends above the
+ * "x-height" (the height of the letter "x"), such as "d", "t", or "h". Also
+ * used to denote the part of the letter extending above the x-height.
+ *
+ * @param size the font size (in mpt)
+ * @return the ascender for the given size
+ */
+ public int getAscender(int size) {
+ return charSet.getAscender() * size;
+ }
+
+ /**
+ * Obtains the height of capital letters for the specified point size.
+ *
+ * @param size the font size (in mpt)
+ * @return the cap height for the given size
+ */
+ public int getCapHeight(int size) {
+ return charSet.getCapHeight() * size;
+ }
+
+ /**
+ * The descender is the part of a lowercase letter that extends below the
+ * base line, such as "g", "j", or "p". Also used to denote the part of the
+ * letter extending below the base line.
+ *
+ * @param size the font size (in mpt)
+ * @return the descender for the given size
+ */
+ public int getDescender(int size) {
+ return charSet.getDescender() * size;
+ }
+
+ /**
+ * The "x-height" (the height of the letter "x").
+ *
+ * @param size the font size (in mpt)
+ * @return the x height for the given size
+ */
+ public int getXHeight(int size) {
+ return charSet.getXHeight() * size;
+ }
+
+ /**
+ * Obtain the width of the character for the specified point size.
+ * @param character the character
+ * @param size the font size (in mpt)
+ * @return the width of the character for the specified point size
+ */
+ public int getWidth(int character, int size) {
+ return charSet.getWidth(character) * size;
+ }
+
+ /**
+ * Get the getWidth (in 1/1000ths of a point size) of all characters in this
+ * character set.
+ *
+ * @param size the font size (in mpt)
+ * @return the widths of all characters
+ */
+ public int[] getWidths(int size) {
+ int[] widths = charSet.getWidths();
+ for (int i = 0; i < widths.length; i++) {
+ widths[i] = widths[i] * size;
+ }
+ return widths;
+ }
+
+ /**
+ * Get the getWidth (in 1/1000ths of a point size) of all characters in this
+ * character set.
+ *
+ * @return the widths of all characters
+ */
+ public int[] getWidths() {
+ return getWidths(1000);
+ }
+
+ /** {@inheritDoc} */
+ public boolean hasChar(char c) {
+ return charSet.hasChar(c);
+ }
+
+ /**
+ * Map a Unicode character to a code point in the font.
+ * @param c character to map
+ * @return the mapped character
+ */
+ public char mapChar(char c) {
+ return charSet.mapChar(c);
+ }
+
+ /** {@inheritDoc} */
+ public String getEncodingName() {
+ return charSet.getEncoding();
+ }
+
+} \ No newline at end of file
diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSet.java b/src/java/org/apache/fop/afp/fonts/CharacterSet.java
index 48d5f4f30..555d70158 100644
--- a/src/java/org/apache/fop/afp/fonts/CharacterSet.java
+++ b/src/java/org/apache/fop/afp/fonts/CharacterSet.java
@@ -20,7 +20,6 @@
package org.apache.fop.afp.fonts;
import java.io.File;
-import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.nio.ByteBuffer;
@@ -60,7 +59,7 @@ import org.apache.fop.afp.util.StringUtils;
public class CharacterSet {
/** Static logging instance */
- protected static final Log log = LogFactory.getLog(CharacterSet.class.getName());
+ protected static final Log LOG = LogFactory.getLog(CharacterSet.class.getName());
/** default codepage */
public static final String DEFAULT_CODEPAGE = "T1V10500";
@@ -86,9 +85,6 @@ public class CharacterSet {
/** The path to the installed fonts */
private ResourceAccessor accessor;
- /** Indicator as to whether to metrics have been loaded */
- private boolean isMetricsLoaded = false;
-
/** The current orientation (currently only 0 is supported by FOP) */
private final String currentOrientation = "0";
@@ -122,11 +118,11 @@ public class CharacterSet {
* @param name the character set name
* @param accessor the resource accessor to load resource with
*/
- public CharacterSet(String codePage, String encoding, String name, ResourceAccessor accessor) {
+ CharacterSet(String codePage, String encoding, String name, ResourceAccessor accessor) {
if (name.length() > MAX_NAME_LEN) {
String msg = "Character set name '" + name + "' must be a maximum of "
+ MAX_NAME_LEN + " characters";
- log.error("Constructor:: " + msg);
+ LOG.error("Constructor:: " + msg);
throw new IllegalArgumentException(msg);
}
@@ -192,7 +188,7 @@ public class CharacterSet {
* @return the ascender value in millipoints
*/
public int getAscender() {
- load();
+
return getCharacterSetOrientation().getAscender();
}
@@ -204,7 +200,7 @@ public class CharacterSet {
* @return the cap height value in millipoints
*/
public int getCapHeight() {
- load();
+
return getCharacterSetOrientation().getCapHeight();
}
@@ -216,7 +212,7 @@ public class CharacterSet {
* @return the descender value in millipoints
*/
public int getDescender() {
- load();
+
return getCharacterSetOrientation().getDescender();
}
@@ -226,7 +222,7 @@ public class CharacterSet {
* @return the first character in the character set
*/
public int getFirstChar() {
- load();
+
return getCharacterSetOrientation().getFirstChar();
}
@@ -236,7 +232,7 @@ public class CharacterSet {
* @return the last character in the character set
*/
public int getLastChar() {
- load();
+
return getCharacterSetOrientation().getLastChar();
}
@@ -254,7 +250,7 @@ public class CharacterSet {
* @return the widths of all characters
*/
public int[] getWidths() {
- load();
+
return getCharacterSetOrientation().getWidths();
}
@@ -264,7 +260,7 @@ public class CharacterSet {
* @return the typical height of characters
*/
public int getXHeight() {
- load();
+
return getCharacterSetOrientation().getXHeight();
}
@@ -276,27 +272,11 @@ public class CharacterSet {
* @return the width of the character
*/
public int getWidth(int character) {
- load();
+
return getCharacterSetOrientation().getWidth(character);
}
- /**
- * Lazy creation of the character metrics, the afp font file will only
- * be processed on a method call requiring the metric information.
- */
- private void load() {
- if (!isMetricsLoaded) {
- AFPFontReader afpFontReader = new AFPFontReader();
- try {
- afpFontReader.loadCharacterSetMetric(this);
- isMetricsLoaded = true;
- } catch (IOException e) {
- String msg = "Failed to load the character set metrics for code page " + codePage;
- log.error(msg);
- throw new RuntimeException(e.getMessage());
- }
- }
- }
+
/**
* Returns the AFP character set identifier
@@ -318,7 +298,7 @@ public class CharacterSet {
nameBytes = name.getBytes(AFPConstants.EBCIDIC_ENCODING);
} catch (UnsupportedEncodingException usee) {
nameBytes = name.getBytes();
- log.warn(
+ LOG.warn(
"UnsupportedEncodingException translating the name " + name);
}
return nameBytes;
@@ -417,4 +397,20 @@ public class CharacterSet {
return c;
}
+ /**
+ * Returns the increment for an space.
+ * @return the space increment
+ */
+ public int getSpaceIncrement() {
+ return getCharacterSetOrientation().getSpaceIncrement();
+ }
+
+ /**
+ * Returns the increment for an em space.
+ * @return the em space increment
+ */
+ public int getEmSpaceIncrement() {
+ return getCharacterSetOrientation().getEmSpaceIncrement();
+ }
+
}
diff --git a/src/java/org/apache/fop/afp/fonts/AFPFontReader.java b/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
index 25ea15278..ea9703a08 100644
--- a/src/java/org/apache/fop/afp/fonts/AFPFontReader.java
+++ b/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
@@ -33,10 +33,15 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.afp.AFPConstants;
import org.apache.fop.afp.util.ResourceAccessor;
import org.apache.fop.afp.util.StructuredFieldReader;
+import org.apache.fop.fonts.Typeface;
/**
- * The AFPFontReader is responsible for reading the font attributes from binary
- * code page files and the character set metric files. In IBM font structure, a
+ * The CharacterSetBuilder is responsible building the a CharacterSet instance that holds
+ * the font metric data. The data is either read from disk and passed to a CharacterSet (*)
+ * or a FopCharacterSet is instantiated that is composed of a Typeface instance configured
+ * with this data.<p/>
+ * -*- For referenced fonts CharacterSetBuilder is responsible for reading the font attributes
+ * from binary code page files and the character set metric files. In IBM font structure, a
* code page maps each character of text to the characters in a character set.
* Each character is translated into a code point. When the character is
* printed, each code point is matched to a character ID on the code page
@@ -49,14 +54,13 @@ import org.apache.fop.afp.util.StructuredFieldReader;
* files in order to determine the correct metrics to use when rendering the
* formatted object. <p/>
*
- * @author <a href="mailto:pete@townsend.uk.com">Pete Townsend </a>
*/
-public final class AFPFontReader {
+public class CharacterSetBuilder {
/**
* Static logging instance
*/
- protected static final Log log = LogFactory.getLog(AFPFontReader.class);
+ protected static final Log LOG = LogFactory.getLog(CharacterSetBuilder.class);
/**
* Template used to convert lists to arrays.
@@ -97,16 +101,36 @@ public final class AFPFontReader {
private final Map/*<String, Map<String, String>>*/ codePagesCache
= new java.util.HashMap/*<String, Map<String, String>>*/();
+
+ private CharacterSetBuilder() { }
+
+ /**
+ * Factory method for the single-byte implementation of AFPFontReader.
+ * @return AFPFontReader
+ */
+ public static CharacterSetBuilder getInstance() {
+ return new CharacterSetBuilder();
+ }
+
+ /**
+ * Factory method for the double-byte (CID Keyed font (Type 0)) implementation of AFPFontReader.
+ * @return AFPFontReader
+ */
+ public static CharacterSetBuilder getDoubleByteInstance() {
+ return new DoubleByteLoader();
+ }
+
+
/**
* Returns an InputStream to a given file path and filename
*
- * @param path the file path
+ * * @param accessor the resource accessor
* @param filename the file name
* @return an inputStream
*
* @throws IOException in the event that an I/O exception of some sort has occurred
*/
- private InputStream openInputStream(ResourceAccessor accessor, String filename)
+ protected InputStream openInputStream(ResourceAccessor accessor, String filename)
throws IOException {
URI uri;
try {
@@ -124,14 +148,14 @@ public final class AFPFontReader {
*
* @param inputStream the inputstream to close
*/
- private void closeInputStream(InputStream inputStream) {
+ protected void closeInputStream(InputStream inputStream) {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (Exception ex) {
// Lets log at least!
- log.error(ex.getMessage());
+ LOG.error(ex.getMessage());
}
}
@@ -139,11 +163,15 @@ public final class AFPFontReader {
* Load the font details and metrics into the CharacterSetMetric object,
* this will use the actual afp code page and character set files to load
* the object with the necessary metrics.
- *
- * @param characterSet the CharacterSetMetric object to populate
- * @throws IOException if an I/O exception of some sort has occurred.
+ * @param codePageName name of the code page file
+ * @param encoding
+ * @throws RuntimeException if an I/O exception of some sort has occurred.
*/
- public void loadCharacterSetMetric(CharacterSet characterSet) throws IOException {
+ public CharacterSet build(String characterSetName, String codePageName,
+ String encoding, ResourceAccessor accessor) {
+
+ CharacterSet characterSet = new CharacterSet(
+ codePageName, encoding, characterSetName, accessor);
InputStream inputStream = null;
@@ -154,24 +182,15 @@ public final class AFPFontReader {
* information to map the unicode character id to the graphic
* chracter global identifier.
*/
- String codePageId = new String(characterSet.getCodePage());
- ResourceAccessor accessor = characterSet.getResourceAccessor();
Map/*<String,String>*/ codePage
- = (Map/*<String,String>*/)codePagesCache.get(codePageId);
+ = (Map/*<String,String>*/)codePagesCache.get(codePageName);
if (codePage == null) {
- codePage = loadCodePage(codePageId, characterSet.getEncoding(), accessor);
- codePagesCache.put(codePageId, codePage);
+ codePage = loadCodePage(codePageName, encoding, accessor);
+ codePagesCache.put(codePageName, codePage);
}
- /**
- * Load the character set metric information, no need to cache this
- * information as it should be cached by the objects that wish to
- * load character set metric information.
- */
- final String characterSetName = characterSet.getName();
-
inputStream = openInputStream(accessor, characterSetName);
StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream);
@@ -208,15 +227,40 @@ public final class AFPFontReader {
characterSet.addCharacterSetOrientation(characterSetOrientations[i]);
}
} else {
- throw new IOException(
- "Failed to read font control structured field in character set "
- + characterSetName);
+
+ String msg = "Failed to load the character set metrics for code page "
+ + codePageName;
+ LOG.error(msg);
+ throw new RuntimeException("Failed to read font control structured field"
+ + "in character set " + characterSetName);
+
}
- } finally {
+ } catch(IOException e){
+ String msg = "Failed to load the character set metrics for code page " + codePageName;
+ LOG.error(msg);
+ throw new RuntimeException("Failed to read font control structured field"
+ + "in character set " + characterSetName);
+ }
+ finally {
+
closeInputStream(inputStream);
}
+ return characterSet;
+
+ }
+
+ /**
+ * Load the font details and metrics into the CharacterSetMetric object,
+ * this will use the actual afp code page and character set files to load
+ * the object with the necessary metrics.
+ *
+ * @param characterSet the CharacterSetMetric object to populate
+ */
+ public CharacterSet build(String characterSetName, String codePageName,
+ String encoding, Typeface typeface) {
+ return new FopCharacterSet(codePageName, encoding, characterSetName, typeface);
}
/**
@@ -229,8 +273,9 @@ public final class AFPFontReader {
* the encoding to use for the character decoding
* @param accessor the resource accessor
* @returns a code page mapping
+ * @throws IOException if an I/O exception of some sort has occurred.
*/
- private Map/*<String,String>*/ loadCodePage(String codePage, String encoding,
+ protected Map/*<String,String>*/ loadCodePage(String codePage, String encoding,
ResourceAccessor accessor) throws IOException {
// Create the HashMap to store code page information
@@ -277,8 +322,10 @@ public final class AFPFontReader {
*
* @param structuredFieldReader the structured field reader
* @return a class representing the font descriptor
+ * @throws IOException if an I/O exception of some sort has occurred.
*/
- private static FontDescriptor processFontDescriptor(StructuredFieldReader structuredFieldReader)
+ protected static FontDescriptor processFontDescriptor(
+ StructuredFieldReader structuredFieldReader)
throws IOException {
byte[] fndData = structuredFieldReader.getNext(FONT_DESCRIPTOR_SF);
@@ -290,8 +337,10 @@ public final class AFPFontReader {
*
* @param structuredFieldReader
* the structured field reader
+ * @return the FontControl
+ * @throws IOException if an I/O exception of some sort has occurred.
*/
- private FontControl processFontControl(StructuredFieldReader structuredFieldReader)
+ protected FontControl processFontControl(StructuredFieldReader structuredFieldReader)
throws IOException {
byte[] fncData = structuredFieldReader.getNext(FONT_CONTROL_SF);
@@ -320,8 +369,10 @@ public final class AFPFontReader {
*
* @param structuredFieldReader
* the structured field reader
+ * @return CharacterSetOrientation array
+ * @throws IOException if an I/O exception of some sort has occurred.
*/
- private CharacterSetOrientation[] processFontOrientation(
+ protected CharacterSetOrientation[] processFontOrientation(
StructuredFieldReader structuredFieldReader) throws IOException {
byte[] data = structuredFieldReader.getNext(FONT_ORIENTATION_SF);
@@ -341,27 +392,15 @@ public final class AFPFontReader {
position = 0;
- int orientation = 0;
-
- switch (fnoData[2]) {
- case 0x00:
- orientation = 0;
- break;
- case 0x2D:
- orientation = 90;
- break;
- case 0x5A:
- orientation = 180;
- break;
- case (byte) 0x87:
- orientation = 270;
- break;
- default:
- System.out.println("ERROR: Oriantation");
- }
+ int orientation = determineOrientation(fnoData[2]);
+ // Space Increment
+ int space = ((fnoData[8] & 0xFF ) << 8) + (fnoData[9] & 0xFF);
+ // Em-Space Increment
+ int em = ((fnoData[14] & 0xFF ) << 8) + (fnoData[15] & 0xFF);
- CharacterSetOrientation cso = new CharacterSetOrientation(
- orientation);
+ CharacterSetOrientation cso = new CharacterSetOrientation(orientation);
+ cso.setSpaceIncrement(space);
+ cso.setEmSpaceIncrement(em);
orientations.add(cso);
}
@@ -381,8 +420,9 @@ public final class AFPFontReader {
* the array of CharacterSetOrientation objects
* @param metricNormalizationFactor factor to apply to the metrics to get normalized
* font metric values
+ * @throws IOException if an I/O exception of some sort has occurred.
*/
- private void processFontPosition(StructuredFieldReader structuredFieldReader,
+ protected void processFontPosition(StructuredFieldReader structuredFieldReader,
CharacterSetOrientation[] characterSetOrientations, double metricNormalizationFactor)
throws IOException {
@@ -437,8 +477,9 @@ public final class AFPFontReader {
* @param codepage the map of code pages
* @param metricNormalizationFactor factor to apply to the metrics to get normalized
* font metric values
+ * @throws IOException if an I/O exception of some sort has occurred.
*/
- private void processFontIndex(StructuredFieldReader structuredFieldReader,
+ protected void processFontIndex(StructuredFieldReader structuredFieldReader,
CharacterSetOrientation cso, Map/*<String,String>*/ codepage,
double metricNormalizationFactor)
throws IOException {
@@ -483,10 +524,9 @@ public final class AFPFontReader {
int diff = Math.abs(abc - width);
if (diff != 0 && width != 0) {
double diffPercent = 100 * diff / (double)width;
- //if difference > 2%
if (diffPercent > 2) {
- if (log.isTraceEnabled()) {
- log.trace(gcgiString + ": "
+ if (LOG.isTraceEnabled()) {
+ LOG.trace(gcgiString + ": "
+ a + " + " + b + " + " + c + " = " + (a + b + c)
+ " but found: " + width);
}
@@ -516,9 +556,9 @@ public final class AFPFontReader {
cso.setFirstChar(lowest);
cso.setLastChar(highest);
- if (log.isDebugEnabled() && firstABCMismatch != null) {
+ if (LOG.isDebugEnabled() && firstABCMismatch != null) {
//Debug level because it usually is no problem.
- log.debug("Font has metrics inconsitencies where A+B+C doesn't equal the"
+ LOG.debug("Font has metrics inconsitencies where A+B+C doesn't equal the"
+ " character increment. The first such character found: "
+ firstABCMismatch);
}
@@ -584,4 +624,84 @@ public final class AFPFontReader {
}
}
+ /**
+ * Double-byte (CID Keyed font (Type 0)) implementation of AFPFontReader.
+ */
+ private static class DoubleByteLoader extends CharacterSetBuilder {
+
+ protected Map/*<String,String>*/ loadCodePage(String codePage, String encoding,
+ ResourceAccessor accessor) throws IOException {
+
+ // Create the HashMap to store code page information
+ Map/*<String,String>*/ codePages = new java.util.HashMap/*<String,String>*/();
+
+ InputStream inputStream = null;
+ try {
+ inputStream = openInputStream(accessor, codePage.trim());
+
+ StructuredFieldReader structuredFieldReader
+ = new StructuredFieldReader(inputStream);
+ byte[] data;
+ while ((data = structuredFieldReader.getNext(CHARACTER_TABLE_SF)) != null) {
+ int position = 0;
+
+ byte[] gcgiBytes = new byte[8];
+ byte[] charBytes = new byte[2];
+ // Read data, ignoring bytes 0 - 2
+ for (int index = 3; index < data.length; index++) {
+
+ if (position < 8) {
+ // Build the graphic character global identifier key
+ gcgiBytes[position] = data[index];
+ position++;
+ } else if (position == 9) {
+ // Set the character
+ charBytes[0] = data[index];
+ position++;
+ } else if (position == 10) {
+ position = 0;
+ // Set the character
+ charBytes[1] = data[index];
+
+ String gcgiString = new String(gcgiBytes,
+ AFPConstants.EBCIDIC_ENCODING);
+ String charString = new String(charBytes, encoding);
+ codePages.put(gcgiString, charString);
+
+ }
+ else {
+ position++;
+ }
+ }
+ }
+ } finally {
+ closeInputStream(inputStream);
+ }
+
+ return codePages;
+ }
+
+ }
+
+ private static int determineOrientation(byte orientation) {
+ int degrees = 0;
+
+ switch (orientation) {
+ case 0x00:
+ degrees = 0;
+ break;
+ case 0x2D:
+ degrees = 90;
+ break;
+ case 0x5A:
+ degrees = 180;
+ break;
+ case (byte) 0x87:
+ degrees = 270;
+ break;
+ default:
+ throw new IllegalStateException("Invalid orientation: " + orientation);
+ }
+ return degrees;
+ }
}
diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java b/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java
index 1946fd4a4..db0908acb 100644
--- a/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java
+++ b/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java
@@ -19,6 +19,8 @@
package org.apache.fop.afp.fonts;
+import java.util.Arrays;
+
/**
* The IBM Font Object Content Architecture (FOCA) supports presentation
* of character shapes by defining their characteristics, which include
@@ -58,7 +60,7 @@ public class CharacterSetOrientation {
/**
* The character widths in the character set
*/
- private int[] charsWidths = new int[256];
+ private int[] charsWidths = null;
/**
* The height of lowercase letters
@@ -81,6 +83,12 @@ public class CharacterSetOrientation {
*/
private int orientation = 0;
+ /** space increment */
+ private int spaceIncrement;
+ /** em space increment */
+ private int emSpaceIncrement = -1;
+
+
/**
* Constructor for the CharacterSetOrientation, the orientation is
* expressed as the degrees rotation (i.e 0, 90, 180, 270)
@@ -88,6 +96,8 @@ public class CharacterSetOrientation {
*/
public CharacterSetOrientation(int orientation) {
this.orientation = orientation;
+ charsWidths = new int[256];
+ Arrays.fill(charsWidths, -1);
}
/**
@@ -245,8 +255,10 @@ public class CharacterSetOrientation {
public void setWidth(int character, int width) {
if (character >= charsWidths.length) {
// Increase the size of the array if necessary
+ // TODO Can we remove firstChar? surely firstChar==0 at this stage?
int[] arr = new int[(character - firstChar) + 1];
System.arraycopy(charsWidths, 0, arr, 0, charsWidths.length);
+ Arrays.fill(arr, charsWidths.length, character - firstChar, -1);
charsWidths = arr;
}
charsWidths[character] = width;
@@ -261,4 +273,37 @@ public class CharacterSetOrientation {
public void setXHeight(int xHeight) {
this.xHeight = xHeight;
}
+
+ /**
+ * Returns the space increment.
+ * @return the space increment
+ */
+ public int getSpaceIncrement(){
+ return this.spaceIncrement;
+ }
+
+ /**
+ * Sets the space increment.
+ * @param value the space increment
+ */
+ public void setSpaceIncrement(int value) {
+ this.spaceIncrement = value;
+ }
+
+ /**
+ * Returns the em space increment.
+ * @return the em space increment
+ */
+ public int getEmSpaceIncrement(){
+ return this.emSpaceIncrement;
+ }
+
+ /**
+ * Sets the em space increment.
+ * @param value the em space increment
+ */
+ public void setEmSpaceIncrement(int value) {
+ this.emSpaceIncrement = value;
+ }
+
}
diff --git a/src/java/org/apache/fop/afp/fonts/DoubleByteFont.java b/src/java/org/apache/fop/afp/fonts/DoubleByteFont.java
new file mode 100644
index 000000000..1d3b03f1f
--- /dev/null
+++ b/src/java/org/apache/fop/afp/fonts/DoubleByteFont.java
@@ -0,0 +1,90 @@
+/*
+ * 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.fonts;
+
+import java.util.Set;
+
+/**
+ * Implementation of AbstractOutlineFont that supports double-byte fonts (CID Keyed font (Type 0)).
+ * The width of characters that are not prescribed a width metrics in the font resource use
+ * a fallback width. The default width is 1 em. A character can be supplied and queried for the
+ * fallback width of all non-ideograph characters.<p />
+ */
+public class DoubleByteFont extends AbstractOutlineFont {
+
+ //private static final Log LOG = LogFactory.getLog(DoubleByteFont.class);
+
+ //See also http://unicode.org/reports/tr11/ which we've not closely looked at, yet
+ //TODO the Unicode block listed here is probably not complete (ex. Hiragana, Katakana etc.)
+ private static final Set IDEOGRAPHIC = new java.util.HashSet();
+ static {
+ IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS);
+ //IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT); //Java 1.5
+ IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS);
+ IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A);
+ //IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B); //Java 1.1
+ }
+
+ /**
+ * Constructor for an double-byte outline font.
+ * @param name the name of the font
+ * @param charSet the character set
+ */
+ public DoubleByteFont(String name, CharacterSet charSet) {
+ super(name, charSet);
+ }
+
+ /** {@inheritDoc} */
+ public int getWidth(int character, int size) {
+ int charWidth;
+ try {
+ charWidth = charSet.getWidth(character);
+ } catch (IllegalArgumentException e) {
+ // We shall try and handle characters that have no mapped width metric in font resource
+ charWidth = -1;
+ }
+
+ if (charWidth == -1) {
+ charWidth = inferCharWidth(character);
+ }
+ return charWidth * size;
+ }
+
+ private int inferCharWidth(int character) {
+
+ //Is this character an ideograph?
+ boolean isIdeographic = false;
+ Character.UnicodeBlock charBlock = Character.UnicodeBlock.of((char)character);
+ if (charBlock == null) {
+ isIdeographic = false;
+ } else if (IDEOGRAPHIC.contains(charBlock)) {
+ isIdeographic = true;
+ } else { //default
+ isIdeographic = false;
+ }
+
+ if (isIdeographic) {
+ return charSet.getEmSpaceIncrement();
+ } else {
+ return charSet.getSpaceIncrement();
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/afp/fonts/OutlineFont.java b/src/java/org/apache/fop/afp/fonts/OutlineFont.java
index 8dca69f9c..26488e54d 100644
--- a/src/java/org/apache/fop/afp/fonts/OutlineFont.java
+++ b/src/java/org/apache/fop/afp/fonts/OutlineFont.java
@@ -19,165 +19,14 @@
package org.apache.fop.afp.fonts;
-
/**
- * A font defined as a set of lines and curves as opposed to a bitmap font. An
- * outline font can be scaled to any size and otherwise transformed more easily
- * than a bitmap font, and with more attractive results. <p/>
- *
+ * Default implementation of AbstractOutlineFont.
*/
-public class OutlineFont extends AFPFont {
-
- /** The character set for this font */
- private CharacterSet charSet = null;
-
- /**
- * Constructor for an outline font.
- *
- * @param name
- * the name of the font
- * @param charSet
- * the chracter set
- */
- public OutlineFont(String name, CharacterSet charSet) {
- super(name);
- this.charSet = charSet;
- }
-
- /**
- * Get the character set metrics.
- *
- * @return the character set
- */
- public CharacterSet getCharacterSet() {
-
- return charSet;
-
- }
-
- /**
- * Get the character set metrics.
- * @param size ignored
- * @return the character set
- */
- public CharacterSet getCharacterSet(int size) {
-
- return charSet;
-
- }
-
- /**
- * Get the first character in this font.
- * @return the first character in this font
- */
- public int getFirstChar() {
- return charSet.getFirstChar();
- }
-
- /**
- * Get the last character in this font.
- * @return the last character in this font
- */
- public int getLastChar() {
- return charSet.getLastChar();
- }
-
- /**
- * The ascender is the part of a lowercase letter that extends above the
- * "x-height" (the height of the letter "x"), such as "d", "t", or "h". Also
- * used to denote the part of the letter extending above the x-height.
- *
- * @param size the font size (in mpt)
- * @return the ascender for the given size
- */
- public int getAscender(int size) {
- return charSet.getAscender() * size;
- }
-
- /**
- * Obtains the height of capital letters for the specified point size.
- *
- * @param size the font size (in mpt)
- * @return the cap height for the given size
- */
- public int getCapHeight(int size) {
- return charSet.getCapHeight() * size;
- }
-
- /**
- * The descender is the part of a lowercase letter that extends below the
- * base line, such as "g", "j", or "p". Also used to denote the part of the
- * letter extending below the base line.
- *
- * @param size the font size (in mpt)
- * @return the descender for the given size
- */
- public int getDescender(int size) {
- return charSet.getDescender() * size;
- }
-
- /**
- * The "x-height" (the height of the letter "x").
- *
- * @param size the font size (in mpt)
- * @return the x height for the given size
- */
- public int getXHeight(int size) {
- return charSet.getXHeight() * size;
- }
-
- /**
- * Obtain the width of the character for the specified point size.
- * @param character the character
- * @param size the font size (in mpt)
- * @return the width of the character for the specified point size
- */
- public int getWidth(int character, int size) {
- return charSet.getWidth(character) * size;
- }
-
- /**
- * Get the getWidth (in 1/1000ths of a point size) of all characters in this
- * character set.
- *
- * @param size the font size (in mpt)
- * @return the widths of all characters
- */
- public int[] getWidths(int size) {
- int[] widths = charSet.getWidths();
- for (int i = 0; i < widths.length; i++) {
- widths[i] = widths[i] * size;
- }
- return widths;
- }
-
- /**
- * Get the getWidth (in 1/1000ths of a point size) of all characters in this
- * character set.
- *
- * @return the widths of all characters
- */
- public int[] getWidths() {
- return getWidths(1000);
- }
+public class OutlineFont extends AbstractOutlineFont {
/** {@inheritDoc} */
- public boolean hasChar(char c) {
- return charSet.hasChar(c);
- }
-
- /**
- * Map a Unicode character to a code point in the font.
- * @param c character to map
- * @return the mapped character
- */
- public char mapChar(char c) {
- return charSet.mapChar(c);
- }
-
- /** {@inheritDoc} */
- public String getEncodingName() {
- return charSet.getEncoding();
+ public OutlineFont(String name, CharacterSet charSet) {
+ super(name, charSet);
}
} \ No newline at end of file
diff --git a/src/java/org/apache/fop/afp/modca/MapCodedFont.java b/src/java/org/apache/fop/afp/modca/MapCodedFont.java
index e732a8bb7..084ae4b4c 100644
--- a/src/java/org/apache/fop/afp/modca/MapCodedFont.java
+++ b/src/java/org/apache/fop/afp/modca/MapCodedFont.java
@@ -29,6 +29,7 @@ import java.util.List;
import org.apache.fop.afp.AFPConstants;
import org.apache.fop.afp.fonts.AFPFont;
import org.apache.fop.afp.fonts.CharacterSet;
+import org.apache.fop.afp.fonts.DoubleByteFont;
import org.apache.fop.afp.fonts.FontRuntimeException;
import org.apache.fop.afp.fonts.OutlineFont;
import org.apache.fop.afp.fonts.RasterFont;
@@ -77,19 +78,22 @@ public class MapCodedFont extends AbstractStructuredObject {
}
// Font Character Set Name Reference
- baos.write(0x0C);
+ baos.write(0x0C); //TODO Relax requirement for 8 chars in the name
baos.write(0x02);
baos.write((byte) 0x86);
baos.write(0x00);
baos.write(fd.characterSet);
// Font Code Page Name Reference
- baos.write(0x0C);
+ baos.write(0x0C); //TODO Relax requirement for 8 chars in the name
baos.write(0x02);
baos.write((byte) 0x85);
baos.write(0x00);
baos.write(fd.codePage);
+ //TODO idea: for CIDKeyed fonts, maybe hint at Unicode encoding with X'50' triplet
+ //to allow font substitution.
+
// Character Rotation
baos.write(0x04);
baos.write(0x26);
@@ -217,6 +221,25 @@ public class MapCodedFont extends AbstractStructuredObject {
AFPConstants.EBCIDIC_ENCODING)
+ " must have a fixed length of 8 characters.");
}
+ } else if (font instanceof DoubleByteFont) {
+ DoubleByteFont outline = (DoubleByteFont) font;
+ CharacterSet cs = outline.getCharacterSet();
+ fontDefinition.characterSet = cs.getNameBytes();
+
+ // There are approximately 72 points to 1 inch or 20 1440ths per point.
+
+ fontDefinition.scale = 20 * size / 1000;
+
+ fontDefinition.codePage = cs.getCodePage().getBytes(
+ AFPConstants.EBCIDIC_ENCODING);
+
+ //TODO Relax requirement for 8 characters
+ if (fontDefinition.codePage.length != 8) {
+ throw new IllegalArgumentException("The code page "
+ + new String(fontDefinition.codePage,
+ AFPConstants.EBCIDIC_ENCODING)
+ + " must have a fixed length of 8 characters.");
+ }
} else {
String msg = "Font of type " + font.getClass().getName()
+ " not recognized.";
diff --git a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java
index 1e15d4c72..27ffeae62 100644
--- a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java
+++ b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java
@@ -30,10 +30,12 @@ import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.fop.afp.AFPResourceLevel;
import org.apache.fop.afp.AFPResourceLevelDefaults;
+import org.apache.fop.afp.fonts.AFPFont;
import org.apache.fop.afp.fonts.AFPFontCollection;
import org.apache.fop.afp.fonts.AFPFontInfo;
import org.apache.fop.afp.fonts.CharacterSet;
-import org.apache.fop.afp.fonts.FopCharacterSet;
+import org.apache.fop.afp.fonts.CharacterSetBuilder;
+import org.apache.fop.afp.fonts.DoubleByteFont;
import org.apache.fop.afp.fonts.OutlineFont;
import org.apache.fop.afp.fonts.RasterFont;
import org.apache.fop.afp.util.DefaultFOPResourceAccessor;
@@ -57,7 +59,7 @@ import org.apache.fop.util.LogUtil;
* AFP Renderer configurator
*/
public class AFPRendererConfigurator extends PrintRendererConfigurator
- implements IFDocumentHandlerConfigurator {
+ implements IFDocumentHandlerConfigurator {
/**
* Default constructor
@@ -69,7 +71,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator
}
private AFPFontInfo buildFont(Configuration fontCfg, String fontPath)
- throws ConfigurationException {
+ throws ConfigurationException {
FontManager fontManager = this.userAgent.getFactory().getFontManager();
@@ -127,11 +129,33 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator
return null;
}
String encoding = afpFontCfg.getAttribute("encoding");
+
if (encoding == null) {
log.error("Mandatory afp-font configuration attribute 'encoding=' is missing");
return null;
}
+ AFPFont font = fontFromType(type, codepage, encoding, accessor, afpFontCfg);
+
+ return font != null ? new AFPFontInfo(font, tripletList) : null;
+ }
+
+
+ /**
+ * Create the AFPFont based on type and type-dependent configuration.
+ *
+ * @param type font type e.g. 'raster', 'outline'
+ * @param codepage codepage file
+ * @param encoding character encoding e.g. 'Cp500', 'UnicodeBigUnmarked'
+ * @param accessor
+ * @param afpFontCfg
+ * @return
+ * @throws ConfigurationException
+ */
+ private AFPFont fontFromType(String type, String codepage, String encoding,
+ ResourceAccessor accessor, Configuration afpFontCfg)
+ throws ConfigurationException {
+
if ("raster".equalsIgnoreCase(type)) {
String name = afpFontCfg.getAttribute("name", "Unknown");
@@ -161,27 +185,28 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator
if (base14 != null) {
try {
Class clazz = Class.forName("org.apache.fop.fonts.base14."
- + base14);
+ + base14);
try {
Typeface tf = (Typeface)clazz.newInstance();
- font.addCharacterSet(sizeMpt, new FopCharacterSet(
- codepage, encoding, characterset, tf));
+ font.addCharacterSet(sizeMpt,
+ CharacterSetBuilder.getInstance()
+ .build(characterset, codepage, encoding, tf));
} catch (Exception ie) {
String msg = "The base 14 font class " + clazz.getName()
- + " could not be instantiated";
+ + " could not be instantiated";
log.error(msg);
}
} catch (ClassNotFoundException cnfe) {
String msg = "The base 14 font class for " + characterset
- + " could not be found";
+ + " could not be found";
log.error(msg);
}
} else {
- font.addCharacterSet(sizeMpt, new CharacterSet(
- codepage, encoding, characterset, accessor));
+ font.addCharacterSet(sizeMpt, CharacterSetBuilder.getInstance()
+ .build(characterset, codepage, encoding, accessor));
}
}
- return new AFPFontInfo(font, tripletList);
+ return font;
} else if ("outline".equalsIgnoreCase(type)) {
String characterset = afpFontCfg.getAttribute("characterset");
@@ -195,30 +220,47 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator
if (base14 != null) {
try {
Class clazz = Class.forName("org.apache.fop.fonts.base14."
- + base14);
+ + base14);
try {
Typeface tf = (Typeface)clazz.newInstance();
- characterSet = new FopCharacterSet(
- codepage, encoding, characterset, tf);
+ characterSet = CharacterSetBuilder.getInstance()
+ .build(characterset, codepage, encoding, tf);
} catch (Exception ie) {
String msg = "The base 14 font class " + clazz.getName()
- + " could not be instantiated";
+ + " could not be instantiated";
log.error(msg);
}
} catch (ClassNotFoundException cnfe) {
String msg = "The base 14 font class for " + characterset
- + " could not be found";
+ + " could not be found";
log.error(msg);
}
} else {
- characterSet = new CharacterSet(codepage, encoding, characterset, accessor);
+ characterSet = CharacterSetBuilder.getInstance().build(
+ characterset, codepage, encoding, accessor);
}
+ // Return new font object
+ return new OutlineFont(name, characterSet);
+
+ } else if ("CIDKeyed".equalsIgnoreCase(type)) {
+ String characterset = afpFontCfg.getAttribute("characterset");
+ if (characterset == null) {
+ log.error("Mandatory afp-font configuration attribute 'characterset=' is missing");
+ return null;
+ }
+ String name = afpFontCfg.getAttribute("name", characterset);
+ CharacterSet characterSet = null;
+ characterSet = CharacterSetBuilder.getDoubleByteInstance()
+ .build(characterset, codepage, encoding, accessor);
+
// Create a new font object
- OutlineFont font = new OutlineFont(name, characterSet);
- return new AFPFontInfo(font, tripletList);
+ DoubleByteFont font = new DoubleByteFont(name, characterSet);
+ return font;
+
} else {
- log.error("No or incorrect type attribute");
+ log.error("No or incorrect type attribute: " + type);
}
+
return null;
}
@@ -230,7 +272,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator
* @throws ConfigurationException if something's wrong with the config data
*/
private List/*<AFPFontInfo>*/ buildFontListFromConfiguration(Configuration cfg)
- throws FOPException, ConfigurationException {
+ throws FOPException, ConfigurationException {
Configuration fonts = cfg.getChild("fonts");
FontManager fontManager = this.userAgent.getFactory().getFontManager();
@@ -261,9 +303,9 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator
FontTriplet triplet = (FontTriplet) fontTriplets.get(j);
if (log.isDebugEnabled()) {
log.debug(" Font triplet "
- + triplet.getName() + ", "
- + triplet.getStyle() + ", "
- + triplet.getWeight());
+ + triplet.getName() + ", "
+ + triplet.getStyle() + ", "
+ + triplet.getWeight());
}
if ((referencedFontsMatcher != null && referencedFontsMatcher.matches(triplet))
@@ -346,7 +388,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator
// a default external resource group file setting
Configuration resourceGroupFileCfg
- = cfg.getChild("resource-group-file", false);
+ = cfg.getChild("resource-group-file", false);
if (resourceGroupFileCfg != null) {
String resourceGroupDest = null;
try {
@@ -358,14 +400,15 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator
customizable.setDefaultResourceGroupFilePath(resourceGroupDest);
} else {
log.warn("Unable to write to default external resource group file '"
- + resourceGroupDest + "'");
+ + resourceGroupDest + "'");
}
}
} catch (ConfigurationException e) {
LogUtil.handleException(log, e,
userAgent.getFactory().validateUserConfigStrictly());
} catch (IOException ioe) {
- throw new FOPException("Could not create default external resource group file", ioe);
+ throw new FOPException("Could not create default external resource group file"
+ , ioe);
}
}