diff options
-rw-r--r-- | lib/xmlgraphics-commons-1.4svn.jar | bin | 572607 -> 569246 bytes | |||
-rw-r--r-- | src/java/org/apache/fop/fonts/CIDFontType.java | 2 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/FontResourceCache.java | 13 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/HexEncoder.java | 57 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSDocumentHandler.java | 7 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSEventProducer.java | 7 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSEventProducer.xml | 1 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSFontResource.java | 77 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSFontUtils.java | 175 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSPainter.java | 43 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSTextPainter.java | 10 | ||||
-rw-r--r-- | test/java/org/apache/fop/UtilityCodeTestSuite.java | 2 | ||||
-rw-r--r-- | test/java/org/apache/fop/render/ps/HexEncoderTestCase.java | 58 |
13 files changed, 392 insertions, 60 deletions
diff --git a/lib/xmlgraphics-commons-1.4svn.jar b/lib/xmlgraphics-commons-1.4svn.jar Binary files differindex c99758f16..d8e8ff18f 100644 --- a/lib/xmlgraphics-commons-1.4svn.jar +++ b/lib/xmlgraphics-commons-1.4svn.jar 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); + } + } + +} |