aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/xmlgraphics-commons-1.4svn.jarbin572607 -> 569246 bytes
-rw-r--r--src/java/org/apache/fop/fonts/CIDFontType.java2
-rw-r--r--src/java/org/apache/fop/render/ps/FontResourceCache.java13
-rw-r--r--src/java/org/apache/fop/render/ps/HexEncoder.java57
-rw-r--r--src/java/org/apache/fop/render/ps/PSDocumentHandler.java7
-rw-r--r--src/java/org/apache/fop/render/ps/PSEventProducer.java7
-rw-r--r--src/java/org/apache/fop/render/ps/PSEventProducer.xml1
-rw-r--r--src/java/org/apache/fop/render/ps/PSFontResource.java77
-rw-r--r--src/java/org/apache/fop/render/ps/PSFontUtils.java175
-rw-r--r--src/java/org/apache/fop/render/ps/PSPainter.java43
-rw-r--r--src/java/org/apache/fop/render/ps/PSTextPainter.java10
-rw-r--r--test/java/org/apache/fop/UtilityCodeTestSuite.java2
-rw-r--r--test/java/org/apache/fop/render/ps/HexEncoderTestCase.java58
13 files changed, 392 insertions, 60 deletions
diff --git a/lib/xmlgraphics-commons-1.4svn.jar b/lib/xmlgraphics-commons-1.4svn.jar
index c99758f16..d8e8ff18f 100644
--- a/lib/xmlgraphics-commons-1.4svn.jar
+++ b/lib/xmlgraphics-commons-1.4svn.jar
Binary files differ
diff --git a/src/java/org/apache/fop/fonts/CIDFontType.java b/src/java/org/apache/fop/fonts/CIDFontType.java
index 24132ffc2..f553377b3 100644
--- a/src/java/org/apache/fop/fonts/CIDFontType.java
+++ b/src/java/org/apache/fop/fonts/CIDFontType.java
@@ -34,7 +34,7 @@ public class CIDFontType extends ValuedEnum {
/**
* CID Font Type 2 (based on TrueType format)
*/
- public static final CIDFontType CIDTYPE2 = new CIDFontType("CIDFontType2", 1);
+ public static final CIDFontType CIDTYPE2 = new CIDFontType("CIDFontType2", 2);
/**
diff --git a/src/java/org/apache/fop/render/ps/FontResourceCache.java b/src/java/org/apache/fop/render/ps/FontResourceCache.java
index 7d6f076a7..24a34e3db 100644
--- a/src/java/org/apache/fop/render/ps/FontResourceCache.java
+++ b/src/java/org/apache/fop/render/ps/FontResourceCache.java
@@ -42,19 +42,20 @@ class FontResourceCache {
}
/**
- * Returns the PSResource for the given font key.
+ * Returns the PSFontResource for the given font key.
* @param key the font key ("F*")
- * @return the matching PSResource
+ * @return the matching PSFontResource instance
*/
- public PSResource getPSResourceForFontKey(String key) {
- PSResource res = null;
+ public PSFontResource getFontResourceForFontKey(String key) {
+ PSFontResource res = null;
if (this.fontResources != null) {
- res = (PSResource)this.fontResources.get(key);
+ res = (PSFontResource)this.fontResources.get(key);
} else {
this.fontResources = new java.util.HashMap();
}
if (res == null) {
- res = new PSResource(PSResource.TYPE_FONT, getPostScriptNameForFontKey(key));
+ res = PSFontResource.createFontResource(
+ new PSResource(PSResource.TYPE_FONT, getPostScriptNameForFontKey(key)));
this.fontResources.put(key, res);
}
return res;
diff --git a/src/java/org/apache/fop/render/ps/HexEncoder.java b/src/java/org/apache/fop/render/ps/HexEncoder.java
new file mode 100644
index 000000000..e78563102
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/HexEncoder.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.ps;
+
+/**
+ * A helper class to hex-encoded representations of numbers.
+ */
+final class HexEncoder {
+
+ private HexEncoder() { }
+
+ /**
+ * Returns an hex encoding of the given number as a string of the given length,
+ * left-padded with zeros if necessary.
+ *
+ * @param n a number
+ * @param width required length of the string
+ * @return an hex-encoded representation of the number
+ */
+ static String encode(int n, int width) {
+ char[] digits = new char[width];
+ for (int i = width - 1; i >= 0; i--) {
+ int digit = n & 0xF;
+ digits[i] = (char) (digit < 10 ? '0' + digit : 'A' + digit - 10);
+ n >>= 4;
+ }
+ return new String(digits);
+ }
+
+ /**
+ * Returns an hex encoding of the given character as a four-character string.
+ *
+ * @param c a character
+ * @return an hex-encoded representation of the character
+ */
+ static String encode(char c) {
+ return encode(c, 4);
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSDocumentHandler.java b/src/java/org/apache/fop/render/ps/PSDocumentHandler.java
index d55e0724b..1e0411aa5 100644
--- a/src/java/org/apache/fop/render/ps/PSDocumentHandler.java
+++ b/src/java/org/apache/fop/render/ps/PSDocumentHandler.java
@@ -200,7 +200,8 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
gen.writeDSCComment(DSCConstants.BEGIN_SETUP);
PSRenderingUtil.writeSetupCodeList(gen, setupCodeList, "SetupCode");
if (!psUtil.isOptimizeResources()) {
- this.fontResources.addAll(PSFontUtils.writeFontDict(gen, fontInfo));
+ this.fontResources.addAll(PSFontUtils.writeFontDict(gen, fontInfo,
+ PSEventProducer.Provider.get(getUserAgent().getEventBroadcaster())));
} else {
gen.commentln("%FOPFontSetup"); //Place-holder, will be replaced in the second pass
}
@@ -538,8 +539,8 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
* @param key the font key ("F*")
* @return the matching PSResource
*/
- protected PSResource getPSResourceForFontKey(String key) {
- return this.fontResources.getPSResourceForFontKey(key);
+ protected PSFontResource getPSResourceForFontKey(String key) {
+ return this.fontResources.getFontResourceForFontKey(key);
}
/**
diff --git a/src/java/org/apache/fop/render/ps/PSEventProducer.java b/src/java/org/apache/fop/render/ps/PSEventProducer.java
index f04205e1c..3da5b1edb 100644
--- a/src/java/org/apache/fop/render/ps/PSEventProducer.java
+++ b/src/java/org/apache/fop/render/ps/PSEventProducer.java
@@ -50,4 +50,11 @@ public interface PSEventProducer extends EventProducer {
*/
void postscriptDictionaryParseError(Object source, String content, Exception e);
+ /**
+ * PostScript Level 3 features are being used.
+ *
+ * @param source the event source
+ * @event.severity WARN
+ */
+ void postscriptLevel3Used(Object source);
}
diff --git a/src/java/org/apache/fop/render/ps/PSEventProducer.xml b/src/java/org/apache/fop/render/ps/PSEventProducer.xml
index bcd89ed07..213e74e27 100644
--- a/src/java/org/apache/fop/render/ps/PSEventProducer.xml
+++ b/src/java/org/apache/fop/render/ps/PSEventProducer.xml
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<catalogue xml:lang="en">
<message key="postscriptDictionaryParseError">Failed to parse dictionary string. Reason: {e}, content = "{content}"</message>
+ <message key="postscriptLevel3Used">PostScript Level 3 features are needed to handle this document. Please make sure that your printer supports PostScript Level 3.</message>
</catalogue>
diff --git a/src/java/org/apache/fop/render/ps/PSFontResource.java b/src/java/org/apache/fop/render/ps/PSFontResource.java
new file mode 100644
index 000000000..8b7b835ed
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSFontResource.java
@@ -0,0 +1,77 @@
+/*
+ * 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.ps;
+
+import org.apache.xmlgraphics.ps.PSResource;
+import org.apache.xmlgraphics.ps.dsc.ResourceTracker;
+
+/**
+ * A DSC resource corresponding to a font. This class handles the possible other resources
+ * that a font may depend on. For example, a CID-keyed font depends on a CIDFont resource, a
+ * CMap resource, and the ProcSet CIDInit resource.
+ */
+abstract class PSFontResource {
+
+ static PSFontResource createFontResource(final PSResource fontResource) {
+ return new PSFontResource() {
+
+ String getName() {
+ return fontResource.getName();
+ }
+
+ void notifyResourceUsageOnPage(ResourceTracker resourceTracker) {
+ resourceTracker.notifyResourceUsageOnPage(fontResource);
+ }
+ };
+ }
+
+ static PSFontResource createFontResource(final PSResource fontResource,
+ final PSResource procsetCIDInitResource, final PSResource cmapResource,
+ final PSResource cidFontResource) {
+ return new PSFontResource() {
+
+ String getName() {
+ return fontResource.getName();
+ }
+
+ void notifyResourceUsageOnPage(ResourceTracker resourceTracker) {
+ resourceTracker.notifyResourceUsageOnPage(fontResource);
+ resourceTracker.notifyResourceUsageOnPage(procsetCIDInitResource);
+ resourceTracker.notifyResourceUsageOnPage(cmapResource);
+ resourceTracker.notifyResourceUsageOnPage(cidFontResource);
+ }
+ };
+ }
+
+ /**
+ * Returns the name of the font resource.
+ *
+ * @return the name of the font
+ */
+ abstract String getName();
+
+ /**
+ * Notifies the given resource tracker of all the resources needed by this font.
+ *
+ * @param resourceTracker
+ */
+ abstract void notifyResourceUsageOnPage(ResourceTracker resourceTracker);
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java
index 7b359b176..7f0d40824 100644
--- a/src/java/org/apache/fop/render/ps/PSFontUtils.java
+++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java
@@ -23,6 +23,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -43,11 +44,13 @@ import org.apache.xmlgraphics.ps.dsc.ResourceTracker;
import org.apache.xmlgraphics.util.io.ASCIIHexOutputStream;
import org.apache.fop.fonts.Base14Font;
+import org.apache.fop.fonts.CIDSubset;
import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.LazyFont;
+import org.apache.fop.fonts.MultiByteFont;
import org.apache.fop.fonts.SingleByteEncoding;
import org.apache.fop.fonts.SingleByteFont;
import org.apache.fop.fonts.Typeface;
@@ -72,7 +75,12 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
*/
public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo)
throws IOException {
- return writeFontDict(gen, fontInfo, fontInfo.getFonts(), true);
+ return writeFontDict(gen, fontInfo, (PSEventProducer) null);
+ }
+
+ public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo,
+ PSEventProducer eventProducer) throws IOException {
+ return writeFontDict(gen, fontInfo, fontInfo.getFonts(), true, eventProducer);
}
/**
@@ -87,7 +95,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
*/
public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo, Map fonts)
throws IOException {
- return writeFontDict(gen, fontInfo, fonts, false);
+ return writeFontDict(gen, fontInfo, fonts, false, null);
}
/**
@@ -101,7 +109,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
* @throws IOException in case of an I/O problem
*/
private static Map writeFontDict(PSGenerator gen, FontInfo fontInfo, Map fonts,
- boolean encodeAllCharacters) throws IOException {
+ boolean encodeAllCharacters, PSEventProducer eventProducer) throws IOException {
gen.commentln("%FOPBeginFontDict");
Map fontResources = new java.util.HashMap();
@@ -110,8 +118,8 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
String key = (String)iter.next();
Typeface tf = getTypeFace(fontInfo, fonts, key);
PSResource fontRes = new PSResource(PSResource.TYPE_FONT, tf.getFontName());
- fontResources.put(key, fontRes);
- embedFont(gen, tf, fontRes);
+ PSFontResource fontResource = embedFont(gen, tf, fontRes, eventProducer);
+ fontResources.put(key, fontResource);
if (tf instanceof SingleByteFont) {
SingleByteFont sbf = (SingleByteFont)tf;
@@ -191,29 +199,45 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
return tf;
}
- /**
- * Embeds a font in the PostScript file.
- * @param gen the PostScript generator
- * @param tf the font
- * @param fontRes the PSResource associated with the font
- * @throws IOException In case of an I/O error
- */
- public static void embedFont(PSGenerator gen, Typeface tf, PSResource fontRes)
- throws IOException {
+ private static PSFontResource embedFont(PSGenerator gen, Typeface tf, PSResource fontRes,
+ PSEventProducer eventProducer) throws IOException {
boolean embeddedFont = false;
FontType fontType = tf.getFontType();
- if (fontType == FontType.TYPE1 || fontType == FontType.TRUETYPE) {
+ PSFontResource fontResource = null;
+ if (fontType == FontType.TYPE1 || fontType == FontType.TRUETYPE
+ || fontType == FontType.TYPE0) {
if (tf instanceof CustomFont) {
CustomFont cf = (CustomFont)tf;
if (isEmbeddable(cf)) {
InputStream in = getInputStreamOnFont(gen, cf);
if (in != null) {
+ if (fontType == FontType.TYPE0) {
+ if (gen.embedIdentityH()) {
+ /*
+ * First CID-keyed font to be embedded; add
+ * %%IncludeResource: comment for ProcSet CIDInit.
+ */
+ gen.includeProcsetCIDInitResource();
+ if (eventProducer != null) {
+ eventProducer.postscriptLevel3Used(gen);
+ }
+ }
+ PSResource cidFontResource = embedCIDFont(gen, (MultiByteFont) tf, in);
+ fontResource = PSFontResource.createFontResource(fontRes,
+ gen.getProcsetCIDInitResource(),
+ gen.getIdentityHCMapResource(),
+ cidFontResource);
+ }
gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE,
fontRes);
if (fontType == FontType.TYPE1) {
embedType1Font(gen, in);
- } else {
+ fontResource = PSFontResource.createFontResource(fontRes);
+ } else if (fontType == FontType.TRUETYPE) {
embedTrueTypeFont(gen, (SingleByteFont) tf, in);
+ fontResource = PSFontResource.createFontResource(fontRes);
+ } else {
+ embedType0Font(gen, (MultiByteFont) tf, in);
}
gen.writeDSCComment(DSCConstants.END_RESOURCE);
gen.getResourceTracker().registerSuppliedResource(fontRes);
@@ -229,6 +253,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
if (!embeddedFont) {
gen.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, fontRes);
}
+ return fontResource;
}
private static void embedTrueTypeFont(PSGenerator gen,
@@ -236,15 +261,25 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
/* See Adobe Technical Note #5012, "The Type 42 Font Format Specification" */
gen.commentln("%!PS-TrueTypeFont-65536-65536-1"); // TODO TrueType & font versions
gen.writeln("11 dict begin");
+ createType42DictionaryEntries(gen, font, fontStream, font.getCMaps());
+ gen.writeln("FontName currentdict end definefont pop");
+ }
+
+ private static void createType42DictionaryEntries(PSGenerator gen, CustomFont font,
+ InputStream fontStream, List cmaps) throws IOException {
gen.write("/FontName /");
gen.write(font.getFontName());
gen.writeln(" def");
+ gen.writeln("/PaintType 0 def");
+ gen.writeln("/FontMatrix [1 0 0 1 0 0] def");
+ writeFontBBox(gen, font);
+ gen.writeln("/FontType 42 def");
gen.writeln("/Encoding 256 array");
gen.writeln("0 1 255{1 index exch/.notdef put}for");
Set glyphs = new HashSet();
for (int i = 0; i < Glyphs.WINANSI_ENCODING.length; i++) {
gen.write("dup ");
- gen.write(Integer.toString(i));
+ gen.write(i);
gen.write(" /");
String glyphName = Glyphs.charToGlyphName(Glyphs.WINANSI_ENCODING[i]);
if (glyphName.equals("")) {
@@ -256,16 +291,6 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
gen.writeln(" put");
}
gen.writeln("readonly def");
- gen.writeln("/PaintType 0 def");
- gen.writeln("/FontMatrix [1 0 0 1 0 0] def");
- int[] bbox = font.getFontBBox();
- gen.write("/FontBBox[");
- for (int i = 0; i < 4; i++) {
- gen.write(" ");
- gen.write(Integer.toString(bbox[i]));
- }
- gen.writeln(" ] def");
- gen.writeln("/FontType 42 def");
gen.write("/sfnts[");
/*
* Store the font file in an array of hex-encoded strings. Strings are limited to
@@ -289,23 +314,21 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
}
gen.writeln("]def");
gen.write("/CharStrings ");
- gen.write(Integer.toString(glyphs.size() + 1));
+ gen.write(glyphs.size() + 1);
gen.writeln(" dict dup begin");
gen.write("/");
gen.write(Glyphs.NOTDEF);
gen.writeln(" 0 def"); // TODO always glyph index 0?
// TODO ugly and temporary, until CID is implemented
- List cmaps = font.getCMaps();
for (Iterator iter = glyphs.iterator(); iter.hasNext();) {
String glyphName = (String) iter.next();
gen.write("/");
gen.write(glyphName);
gen.write(" ");
- gen.write(Integer.toString(getGlyphIndex(glyphName, cmaps)));
+ gen.write(getGlyphIndex(glyphName, cmaps));
gen.writeln(" def");
}
gen.writeln("end readonly def");
- gen.writeln("FontName currentdict end definefont pop");
}
private static int getGlyphIndex(String glyphName, List cmaps) {
@@ -319,6 +342,96 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
return 0;
}
+ private static void embedType0Font(PSGenerator gen, MultiByteFont font, InputStream fontStream)
+ throws IOException {
+ String psName = font.getFontName();
+ gen.write("/");
+ gen.write(psName);
+ gen.write(" /Identity-H [/");
+ gen.write(psName);
+ gen.writeln("] composefont pop");
+ }
+
+ private static PSResource embedCIDFont(PSGenerator gen,
+ MultiByteFont font, InputStream fontStream) throws IOException {
+ String psName = font.getFontName();
+ gen.write("%%BeginResource: CIDFont ");
+ gen.writeln(psName);
+
+ gen.write("%%Title: (");
+ gen.write(psName);
+ gen.writeln(" Adobe Identity 0)");
+
+ gen.writeln("%%Version: 1"); // TODO use font revision?
+ gen.writeln("/CIDInit /ProcSet findresource begin");
+ gen.writeln("20 dict begin");
+
+ gen.write("/CIDFontName /");
+ gen.write(psName);
+ gen.writeln(" def");
+
+ gen.writeln("/CIDFontVersion 1 def"); // TODO same as %%Version above
+
+ gen.write("/CIDFontType ");
+ gen.write(font.getCIDType().getValue());
+ gen.writeln(" def");
+
+ gen.writeln("/CIDSystemInfo 3 dict dup begin");
+ gen.writeln(" /Registry (Adobe) def");
+ gen.writeln(" /Ordering (Identity) def");
+ gen.writeln(" /Supplement 0 def");
+ gen.writeln("end def");
+
+ // TODO UIDBase (and UIDOffset in CMap) necessary if PostScript Level 1 & 2
+ // interpreters are to be supported
+ // (Level 1: with composite font extensions; Level 2: those that do not offer
+ // native mode support for CID-keyed fonts)
+
+ // TODO XUID (optional but strongly recommended)
+
+ // TODO /FontInfo
+
+ gen.write("/CIDCount ");
+ CIDSubset cidSubset = font.getCIDSubset();
+ int subsetSize = cidSubset.getSubsetSize();
+ gen.write(subsetSize);
+ gen.writeln(" def");
+ gen.writeln("/GDBytes 2 def"); // TODO always 2?
+ gen.writeln("/CIDMap [<");
+ int colCount = 0;
+ int lineCount = 1;
+ for (int cid = 0; cid < subsetSize; cid++) {
+ if (colCount++ == 20) {
+ gen.newLine();
+ colCount = 1;
+ if (lineCount++ == 800) {
+ gen.writeln("> <");
+ lineCount = 1;
+ }
+ }
+ String gid = HexEncoder.encode(cidSubset.getGlyphIndexForSubsetIndex(cid), 4);
+ gen.write(gid);
+ }
+ gen.writeln(">] def");
+ createType42DictionaryEntries(gen, font, fontStream, Collections.EMPTY_LIST);
+ gen.writeln("CIDFontName currentdict end /CIDFont defineresource pop");
+ gen.writeln("end");
+ gen.writeln("%%EndResource");
+ PSResource cidFontResource = new PSResource(PSResource.TYPE_CIDFONT, psName);
+ gen.getResourceTracker().registerSuppliedResource(cidFontResource);
+ return cidFontResource;
+ }
+
+ private static void writeFontBBox(PSGenerator gen, CustomFont font) throws IOException {
+ int[] bbox = font.getFontBBox();
+ gen.write("/FontBBox[");
+ for (int i = 0; i < 4; i++) {
+ gen.write(" ");
+ gen.write(bbox[i]);
+ }
+ gen.writeln(" ] def");
+ }
+
private static boolean isEmbeddable(CustomFont font) {
return font.isEmbeddable();
}
diff --git a/src/java/org/apache/fop/render/ps/PSPainter.java b/src/java/org/apache/fop/render/ps/PSPainter.java
index 38b76fd8a..894b4fb9d 100644
--- a/src/java/org/apache/fop/render/ps/PSPainter.java
+++ b/src/java/org/apache/fop/render/ps/PSPainter.java
@@ -44,6 +44,7 @@ import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.LazyFont;
+import org.apache.fop.fonts.MultiByteFont;
import org.apache.fop.fonts.SingleByteFont;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.render.RenderingContext;
@@ -379,7 +380,7 @@ public class PSPainter extends AbstractIFPainter {
if (currentEncoding != encoding) {
if (i > 0) {
writeText(text, start, i - start,
- letterSpacing, wordSpacing, dx, font, tf);
+ letterSpacing, wordSpacing, dx, font, tf, false);
}
if (encoding == 0) {
useFont(fontKey, sizeMillipoints);
@@ -391,12 +392,11 @@ public class PSPainter extends AbstractIFPainter {
}
}
writeText(text, start, textLen - start,
- letterSpacing, wordSpacing, dx, font, tf);
+ letterSpacing, wordSpacing, dx, font, tf, false);
} else {
- //Simple single-font painting
useFont(fontKey, sizeMillipoints);
writeText(text, 0, textLen,
- letterSpacing, wordSpacing, dx, font, tf);
+ letterSpacing, wordSpacing, dx, font, tf, tf instanceof MultiByteFont);
}
} catch (IOException ioe) {
throw new IFException("I/O error in drawText()", ioe);
@@ -405,7 +405,7 @@ public class PSPainter extends AbstractIFPainter {
private void writeText(String text, int start, int len,
int letterSpacing, int wordSpacing, int[] dx,
- Font font, Typeface tf) throws IOException {
+ Font font, Typeface tf, boolean multiByte) throws IOException {
PSGenerator generator = getGenerator();
int end = start + len;
int initialSize = len;
@@ -414,6 +414,16 @@ public class PSPainter extends AbstractIFPainter {
boolean hasLetterSpacing = (letterSpacing != 0);
boolean needTJ = false;
+ char strOpen;
+ char strClose;
+ if (multiByte) {
+ strOpen = '<';
+ strClose = '>';
+ } else {
+ strOpen = '(';
+ strClose = ')';
+ }
+
int lineStart = 0;
StringBuffer accText = new StringBuffer(initialSize);
StringBuffer sb = new StringBuffer(initialSize);
@@ -439,8 +449,12 @@ public class PSPainter extends AbstractIFPainter {
if (dx != null && i < dxl - 1) {
glyphAdjust -= dx[i + 1];
}
- char codepoint = (char)(ch % 256);
- PSGenerator.escapeChar(codepoint, accText); //add character to accumulated text
+ if (multiByte) {
+ accText.append(HexEncoder.encode(ch));
+ } else {
+ char codepoint = (char)(ch % 256);
+ PSGenerator.escapeChar(codepoint, accText); //add character to accumulated text
+ }
if (glyphAdjust != 0) {
needTJ = true;
if (sb.length() == 0) {
@@ -451,9 +465,10 @@ public class PSPainter extends AbstractIFPainter {
sb.append(PSGenerator.LF);
lineStart = sb.length();
}
- sb.append('(');
+ sb.append(strOpen);
sb.append(accText);
- sb.append(") ");
+ sb.append(strClose);
+ sb.append(' ');
accText.setLength(0); //reset accumulated text
}
sb.append(Integer.toString(glyphAdjust)).append(' ');
@@ -461,9 +476,9 @@ public class PSPainter extends AbstractIFPainter {
}
if (needTJ) {
if (accText.length() > 0) {
- sb.append('(');
+ sb.append(strOpen);
sb.append(accText);
- sb.append(')');
+ sb.append(strClose);
}
if (hasLetterSpacing) {
sb.append("] " + formatMptAsPt(generator, letterSpacing) + " ATJ");
@@ -471,7 +486,7 @@ public class PSPainter extends AbstractIFPainter {
sb.append("] TJ");
}
} else {
- sb.append('(').append(accText).append(")");
+ sb.append(strOpen).append(accText).append(strClose);
if (hasLetterSpacing) {
StringBuffer spb = new StringBuffer();
spb.append(formatMptAsPt(generator, letterSpacing))
@@ -486,10 +501,10 @@ public class PSPainter extends AbstractIFPainter {
}
private void useFont(String key, int size) throws IOException {
- PSResource res = this.documentHandler.getPSResourceForFontKey(key);
+ PSFontResource res = this.documentHandler.getPSResourceForFontKey(key);
PSGenerator generator = getGenerator();
generator.useFont("/" + res.getName(), size / 1000f);
- generator.getResourceTracker().notifyResourceUsageOnPage(res);
+ res.notifyResourceUsageOnPage(generator.getResourceTracker());
}
diff --git a/src/java/org/apache/fop/render/ps/PSTextPainter.java b/src/java/org/apache/fop/render/ps/PSTextPainter.java
index 23418f4e3..4625ff299 100644
--- a/src/java/org/apache/fop/render/ps/PSTextPainter.java
+++ b/src/java/org/apache/fop/render/ps/PSTextPainter.java
@@ -35,13 +35,13 @@ import java.text.AttributedCharacterIterator;
import java.util.Iterator;
import java.util.List;
+import org.apache.batik.gvt.TextNode;
import org.apache.batik.gvt.font.GVTGlyphVector;
import org.apache.batik.gvt.text.TextPaintInfo;
import org.apache.batik.gvt.text.TextSpanLayout;
import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
import org.apache.xmlgraphics.ps.PSGenerator;
-import org.apache.xmlgraphics.ps.PSResource;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
@@ -240,9 +240,9 @@ public class PSTextPainter extends NativeTextPainter {
}
}
- private PSResource getResourceForFont(Font f, String postfix) {
+ private PSFontResource getResourceForFont(Font f, String postfix) {
String key = (postfix != null ? f.getFontName() + '_' + postfix : f.getFontName());
- return this.fontResources.getPSResourceForFontKey(key);
+ return this.fontResources.getFontResourceForFontKey(key);
}
private void clip(PSGraphics2D ps, Shape shape) throws IOException {
@@ -299,9 +299,9 @@ public class PSTextPainter extends NativeTextPainter {
public void selectFont(Font f, char mapped) throws IOException {
int encoding = mapped / 256;
String postfix = (encoding == 0 ? null : Integer.toString(encoding));
- PSResource res = getResourceForFont(f, postfix);
+ PSFontResource res = getResourceForFont(f, postfix);
gen.useFont("/" + res.getName(), f.getFontSize() / 1000f);
- gen.getResourceTracker().notifyResourceUsageOnPage(res);
+ res.notifyResourceUsageOnPage(gen.getResourceTracker());
}
public Font getCurrentFont() {
diff --git a/test/java/org/apache/fop/UtilityCodeTestSuite.java b/test/java/org/apache/fop/UtilityCodeTestSuite.java
index fed9f0f71..153b2649e 100644
--- a/test/java/org/apache/fop/UtilityCodeTestSuite.java
+++ b/test/java/org/apache/fop/UtilityCodeTestSuite.java
@@ -24,6 +24,7 @@ import junit.framework.TestSuite;
import org.apache.fop.events.BasicEventTestCase;
import org.apache.fop.pdf.PDFObjectTestCase;
+import org.apache.fop.render.ps.HexEncoderTestCase;
import org.apache.fop.traits.BorderPropsTestCase;
import org.apache.fop.util.ColorUtilTestCase;
import org.apache.fop.util.ElementListUtilsTestCase;
@@ -51,6 +52,7 @@ public class UtilityCodeTestSuite {
suite.addTest(new TestSuite(BasicEventTestCase.class));
suite.addTest(new TestSuite(XMLResourceBundleTestCase.class));
suite.addTest(new TestSuite(URIResolutionTestCase.class));
+ suite.addTest(new TestSuite(HexEncoderTestCase.class));
//$JUnit-END$
return suite;
}
diff --git a/test/java/org/apache/fop/render/ps/HexEncoderTestCase.java b/test/java/org/apache/fop/render/ps/HexEncoderTestCase.java
new file mode 100644
index 000000000..75aee060f
--- /dev/null
+++ b/test/java/org/apache/fop/render/ps/HexEncoderTestCase.java
@@ -0,0 +1,58 @@
+/*
+ * 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.ps;
+
+import junit.framework.TestCase;
+
+/**
+ * Test case for the conversion of characters into hex-encoded strings.
+ */
+public class HexEncoderTestCase extends TestCase {
+
+ private static char successor(char d) {
+ if (d == '9') {
+ return 'A';
+ } else if (d == 'F') {
+ return '0';
+ } else {
+ return (char) (d + 1);
+ }
+ }
+
+ private static void increment(char[] digits) {
+ int d = 4;
+ do {
+ d--;
+ digits[d] = successor(digits[d]);
+ } while (digits[d] == '0' && d > 0);
+ }
+
+ /**
+ * Tests that characters are properly encoded into hex strings.
+ */
+ public void testEncodeChar() {
+ char[] digits = new char[] {'0', '0', '0', '0'};
+ for (int c = 0; c <= 0xFFFF; c++) {
+ assertEquals(new String(digits), HexEncoder.encode((char) c));
+ increment(digits);
+ }
+ }
+
+}