-- cgit v1.2.3 From 0c11c0d32561d68c97d9bafcd8e5d823558419d8 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 2 Jun 2010 10:55:56 +0000 Subject: Added support for full embedding of TrueType font in PostScript, with encoding forced to WinAnsi. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@950488 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/SingleByteFont.java | 11 +++ .../apache/fop/fonts/truetype/TTFFontLoader.java | 1 + src/java/org/apache/fop/render/ps/PSFontUtils.java | 102 ++++++++++++++++++++- 3 files changed, 112 insertions(+), 2 deletions(-) diff --git a/src/java/org/apache/fop/fonts/SingleByteFont.java b/src/java/org/apache/fop/fonts/SingleByteFont.java index fb4725bd4..14cba4815 100644 --- a/src/java/org/apache/fop/fonts/SingleByteFont.java +++ b/src/java/org/apache/fop/fonts/SingleByteFont.java @@ -44,6 +44,7 @@ public class SingleByteFont extends CustomFont { //Map private List additionalEncodings; + private List cmaps; /** * Main constructor. @@ -334,5 +335,15 @@ public class SingleByteFont extends CustomFont { } } + /** TODO remove */ + public void setCMaps(List cmaps) { + this.cmaps = cmaps; + } + + /** TODO remove */ + public List getCMaps() { + return cmaps; + } + } diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index 405a25f9e..df8cce1b2 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -163,6 +163,7 @@ public class TTFFontLoader extends FontLoader { singleFont.setEncoding(ttf.getCharSetName()); returnFont.setFirstChar(ttf.getFirstChar()); returnFont.setLastChar(ttf.getLastChar()); + singleFont.setCMaps(ttf.getCMaps()); copyWidthsSingleByte(ttf); } diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index a29210b41..7b359b176 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -23,8 +23,11 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; +import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; +import java.util.Set; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; @@ -37,6 +40,7 @@ import org.apache.xmlgraphics.ps.DSCConstants; import org.apache.xmlgraphics.ps.PSGenerator; import org.apache.xmlgraphics.ps.PSResource; 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.CustomFont; @@ -47,6 +51,7 @@ import org.apache.fop.fonts.LazyFont; import org.apache.fop.fonts.SingleByteEncoding; import org.apache.fop.fonts.SingleByteFont; import org.apache.fop.fonts.Typeface; +import org.apache.fop.fonts.truetype.TTFCmapEntry; /** * Utility code for font handling in PostScript. @@ -196,7 +201,8 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { public static void embedFont(PSGenerator gen, Typeface tf, PSResource fontRes) throws IOException { boolean embeddedFont = false; - if (FontType.TYPE1 == tf.getFontType()) { + FontType fontType = tf.getFontType(); + if (fontType == FontType.TYPE1 || fontType == FontType.TRUETYPE) { if (tf instanceof CustomFont) { CustomFont cf = (CustomFont)tf; if (isEmbeddable(cf)) { @@ -204,7 +210,11 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { if (in != null) { gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, fontRes); - embedType1Font(gen, in); + if (fontType == FontType.TYPE1) { + embedType1Font(gen, in); + } else { + embedTrueTypeFont(gen, (SingleByteFont) tf, in); + } gen.writeDSCComment(DSCConstants.END_RESOURCE); gen.getResourceTracker().registerSuppliedResource(fontRes); embeddedFont = true; @@ -221,6 +231,94 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } } + private static void embedTrueTypeFont(PSGenerator gen, + SingleByteFont font, InputStream fontStream) throws IOException { + /* 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"); + gen.write("/FontName /"); + gen.write(font.getFontName()); + gen.writeln(" 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(" /"); + String glyphName = Glyphs.charToGlyphName(Glyphs.WINANSI_ENCODING[i]); + if (glyphName.equals("")) { + gen.write(Glyphs.NOTDEF); + } else { + glyphs.add(glyphName); + gen.write(glyphName); + } + 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 + * 65535 characters, string will start with a newline, 2 characters are needed to + * hex-encode each byte, one newline character will be added every 40 bytes, each + * string should start at a 4-byte boundary + * => buffer size = floor((65535 - 1) * 40 / 81 / 4) * 4 + * TODO this is not robust: depends on how often ASCIIHexOutputStream adds a newline + */ + // TODO does not follow Technical Note #5012's requirements: + // "strings must begin at TrueType table boundaries, or at individual glyph + // boundaries within the glyf table." + // There may be compatibility issues with older PostScript interpreters + byte[] buffer = new byte[32360]; + int readCount; + while ((readCount = fontStream.read(buffer)) > 0) { + ASCIIHexOutputStream hexOut = new ASCIIHexOutputStream(gen.getOutputStream()); + gen.writeln("<"); + hexOut.write(buffer, 0, readCount); + gen.write("> "); + } + gen.writeln("]def"); + gen.write("/CharStrings "); + gen.write(Integer.toString(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.writeln(" def"); + } + gen.writeln("end readonly def"); + gen.writeln("FontName currentdict end definefont pop"); + } + + private static int getGlyphIndex(String glyphName, List cmaps) { + char c = Glyphs.getUnicodeSequenceForGlyphName(glyphName).charAt(0); + for (Iterator iter = cmaps.iterator(); iter.hasNext();) { + TTFCmapEntry cmap = (TTFCmapEntry) iter.next(); + if (cmap.getUnicodeStart() <= c && c <= cmap.getUnicodeEnd()) { + return cmap.getGlyphStartIndex() + c - cmap.getUnicodeStart(); + } + } + return 0; + } + private static boolean isEmbeddable(CustomFont font) { return font.isEmbeddable(); } -- cgit v1.2.3 From ebbdc63b2618a96bcc0a7b6ce29fe75b973e6e9f Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Tue, 29 Jun 2010 15:46:41 +0000 Subject: Added support for CID-keyed TrueType fonts in PostScript output git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@959012 13f79535-47bb-0310-9956-ffa450edef68 --- lib/xmlgraphics-commons-1.4svn.jar | Bin 572607 -> 569246 bytes src/java/org/apache/fop/fonts/CIDFontType.java | 2 +- .../apache/fop/render/ps/FontResourceCache.java | 13 +- src/java/org/apache/fop/render/ps/HexEncoder.java | 57 +++++++ .../apache/fop/render/ps/PSDocumentHandler.java | 7 +- .../org/apache/fop/render/ps/PSEventProducer.java | 7 + .../org/apache/fop/render/ps/PSEventProducer.xml | 1 + .../org/apache/fop/render/ps/PSFontResource.java | 77 +++++++++ src/java/org/apache/fop/render/ps/PSFontUtils.java | 175 +++++++++++++++++---- src/java/org/apache/fop/render/ps/PSPainter.java | 43 +++-- .../org/apache/fop/render/ps/PSTextPainter.java | 10 +- test/java/org/apache/fop/UtilityCodeTestSuite.java | 2 + .../apache/fop/render/ps/HexEncoderTestCase.java | 58 +++++++ 13 files changed, 392 insertions(+), 60 deletions(-) create mode 100644 src/java/org/apache/fop/render/ps/HexEncoder.java create mode 100644 src/java/org/apache/fop/render/ps/PSFontResource.java create mode 100644 test/java/org/apache/fop/render/ps/HexEncoderTestCase.java diff --git a/lib/xmlgraphics-commons-1.4svn.jar b/lib/xmlgraphics-commons-1.4svn.jar index c99758f16..d8e8ff18f 100644 Binary files a/lib/xmlgraphics-commons-1.4svn.jar and b/lib/xmlgraphics-commons-1.4svn.jar 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 @@ Failed to parse dictionary string. Reason: {e}, content = "{content}" + PostScript Level 3 features are needed to handle this document. Please make sure that your printer supports PostScript Level 3. 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); + } + } + +} -- cgit v1.2.3 From ef97b9f09ca70310511f6670c259fe73585b64ad Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Tue, 29 Jun 2010 16:16:11 +0000 Subject: XML Graphics Commons jar committed in rev. 959012 was wrong git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@959018 13f79535-47bb-0310-9956-ffa450edef68 --- lib/xmlgraphics-commons-1.4svn.jar | Bin 569246 -> 576615 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/lib/xmlgraphics-commons-1.4svn.jar b/lib/xmlgraphics-commons-1.4svn.jar index d8e8ff18f..444fa5f4d 100644 Binary files a/lib/xmlgraphics-commons-1.4svn.jar and b/lib/xmlgraphics-commons-1.4svn.jar differ -- cgit v1.2.3 From da43afb9f8478dc523c6bda34510022a3fd1cc19 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Fri, 2 Jul 2010 15:25:08 +0000 Subject: Added toString method to ease debugging git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@960025 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/FontType.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/java/org/apache/fop/fonts/FontType.java b/src/java/org/apache/fop/fonts/FontType.java index 95b594ca4..e19901d1e 100644 --- a/src/java/org/apache/fop/fonts/FontType.java +++ b/src/java/org/apache/fop/fonts/FontType.java @@ -127,4 +127,9 @@ public class FontType { return value; } + /** {@inheritDoc} */ + public String toString() { + return name; + } + } -- cgit v1.2.3 From 28e4838961e59c4d016a27a6a6f1efa158fa6bf9 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Fri, 2 Jul 2010 15:57:08 +0000 Subject: Create PSFontResource for non-embedded fonts and fonts with additional encodings git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@960040 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/render/ps/PSFontUtils.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index 7f0d40824..d27954c23 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -134,7 +134,8 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { String postFix = "_" + (i + 1); PSResource derivedFontRes = defineDerivedFont(gen, tf.getFontName(), tf.getFontName() + postFix, encoding.getName()); - fontResources.put(key + postFix, derivedFontRes); + fontResources.put(key + postFix, + PSFontResource.createFontResource(derivedFontRes)); } } } @@ -252,6 +253,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } if (!embeddedFont) { gen.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, fontRes); + fontResource = PSFontResource.createFontResource(fontRes); } return fontResource; } -- cgit v1.2.3 From 589c8ab356833617014977ab1a7a8ee6c181359a Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Fri, 2 Jul 2010 17:23:36 +0000 Subject: Trying to get a glyph name out of a Unicode code point is already done by the call to mapChar, so doing it again in TTFFontLoader is useless. Instead, make use of the post table if it exists, that may contain a list of glyph names and allow more glyphs to be supported. That allows to reference instead of embed a TrueType font that is already installed on the printer. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@960065 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/truetype/TTFFile.java | 4 ++++ src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java | 12 +++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java index 9fd6adbce..a1b6319ed 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java @@ -1691,6 +1691,10 @@ public class TTFFile { return result; } + String getGlyphName(int glyphIndex) { + return mtxTab[glyphIndex].getName(); + } + /** * Static main method to get info about a TrueType font. * @param args The command line arguments diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index df8cce1b2..10e618adf 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -27,8 +27,6 @@ import java.util.Map; import org.apache.commons.io.IOUtils; -import org.apache.xmlgraphics.fonts.Glyphs; - import org.apache.fop.fonts.BFEntry; import org.apache.fop.fonts.CIDFontType; import org.apache.fop.fonts.EncodingMode; @@ -187,11 +185,11 @@ public class TTFFontLoader extends FontLoader { for (char u = (char)ce.getUnicodeStart(); u <= ce.getUnicodeEnd(); u++) { int codePoint = singleFont.getEncoding().mapChar(u); if (codePoint <= 0) { - String unicode = Character.toString(u); - String charName = Glyphs.stringToGlyph(unicode); - if (charName.length() > 0) { - NamedCharacter nc = new NamedCharacter(charName, unicode); - int glyphIndex = ce.getGlyphStartIndex() + u - ce.getUnicodeStart(); + int glyphIndex = ce.getGlyphStartIndex() + u - ce.getUnicodeStart(); + String glyphName = ttf.getGlyphName(glyphIndex); + if (glyphName != "") { + String unicode = Character.toString(u); + NamedCharacter nc = new NamedCharacter(glyphName, unicode); singleFont.addUnencodedCharacter(nc, wx[glyphIndex]); } } -- cgit v1.2.3 From bb6dd55147567b97aac0061e713321825bc32ef9 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Fri, 27 Aug 2010 18:07:13 +0000 Subject: Added support for multi-byte fonts git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@990219 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/render/ps/PSTextPainter.java | 33 ++++++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/java/org/apache/fop/render/ps/PSTextPainter.java b/src/java/org/apache/fop/render/ps/PSTextPainter.java index e3dace703..c5237fd80 100644 --- a/src/java/org/apache/fop/render/ps/PSTextPainter.java +++ b/src/java/org/apache/fop/render/ps/PSTextPainter.java @@ -45,6 +45,9 @@ import org.apache.xmlgraphics.ps.PSGenerator; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontMetrics; +import org.apache.fop.fonts.LazyFont; +import org.apache.fop.fonts.MultiByteFont; import org.apache.fop.svg.NativeTextPainter; import org.apache.fop.util.CharUtilities; @@ -427,14 +430,22 @@ public class PSTextPainter extends NativeTextPainter { textUtil.setCurrentFont(f, mapped); applyColor(paint, gen); + FontMetrics metrics = f.getFontMetrics(); + boolean multiByte = metrics instanceof MultiByteFont + || metrics instanceof LazyFont + && ((LazyFont) metrics).getRealFont() instanceof MultiByteFont; StringBuffer sb = new StringBuffer(); - sb.append('('); + sb.append(multiByte ? '<' : '('); for (int i = 0, c = this.currentChars.length(); i < c; i++) { char ch = this.currentChars.charAt(i); mapped = f.mapChar(ch); - PSGenerator.escapeChar(mapped, sb); + if (multiByte) { + sb.append(HexEncoder.encode(mapped)); + } else { + PSGenerator.escapeChar(mapped, sb); + } } - sb.append(')'); + sb.append(multiByte ? '>' : ')'); if (x || y) { sb.append("\n["); int idx = 0; @@ -512,10 +523,20 @@ public class PSTextPainter extends NativeTextPainter { textUtil.selectFont(f, mapped); textUtil.setCurrentFont(f, mapped); } - mapped = f.mapChar(this.currentChars.charAt(i)); //add glyph outlines to current path - char codepoint = (char)(mapped % 256); - gen.write("(" + codepoint + ")"); + mapped = f.mapChar(this.currentChars.charAt(i)); + FontMetrics metrics = f.getFontMetrics(); + boolean multiByte = metrics instanceof MultiByteFont + || metrics instanceof LazyFont + && ((LazyFont) metrics).getRealFont() instanceof MultiByteFont; + if (multiByte) { + gen.write('<'); + gen.write(HexEncoder.encode(mapped)); + gen.write('>'); + } else { + char codepoint = (char)(mapped % 256); + gen.write("(" + codepoint + ")"); + } gen.writeln(" false charpath"); if (iter.hasNext()) { -- cgit v1.2.3 From 001ddbb84ad0805b8112a861df08f9ca7d56fc3e Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Fri, 27 Aug 2010 18:27:03 +0000 Subject: Fixed list of supplied resources for DSC when option set to true git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@990220 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/render/ps/PSFontUtils.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index 7adb9f756..e1a477b4e 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -492,10 +492,18 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { Typeface tf = getTypeFace(fontInfo, fonts, key); PSResource fontRes = new PSResource("font", tf.getFontName()); fontResources.put(key, fontRes); - if (FontType.TYPE1 == tf.getFontType()) { + FontType fontType = tf.getFontType(); + if (fontType == FontType.TYPE1 || fontType == FontType.TRUETYPE + || fontType == FontType.TYPE0) { if (tf instanceof CustomFont) { CustomFont cf = (CustomFont)tf; if (isEmbeddable(cf)) { + if (fontType == FontType.TYPE0) { + resTracker.registerSuppliedResource( + new PSResource(PSResource.TYPE_CIDFONT, tf.getFontName())); + resTracker.registerSuppliedResource( + new PSResource(PSResource.TYPE_CMAP, "Identity-H")); + } resTracker.registerSuppliedResource(fontRes); } if (tf instanceof SingleByteFont) { -- cgit v1.2.3 From 519ac01c92c11a0305f13b7124fe2242cfb5b922 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Fri, 27 Aug 2010 18:40:49 +0000 Subject: Added possibility to use glyphs outside WinAnsiEncoding for TrueType fonts that are not embedded in the PostScript file, and that don't have a list of glyph names ('post' table version 3). This is done by creating glyph names using Adobe's convention (/u1234) and adding a CharStrings table that maps those glyph names to the actual glyph index. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@990225 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/SingleByteFont.java | 25 ++++ .../org/apache/fop/fonts/truetype/TTFFile.java | 129 +++++++++++++++++++-- .../apache/fop/fonts/truetype/TTFFontLoader.java | 6 + src/java/org/apache/fop/render/ps/HexEncoder.java | 57 --------- src/java/org/apache/fop/render/ps/PSFontUtils.java | 57 ++++++++- src/java/org/apache/fop/render/ps/PSPainter.java | 1 + .../org/apache/fop/render/ps/PSTextPainter.java | 1 + src/java/org/apache/fop/util/HexEncoder.java | 57 +++++++++ test/java/org/apache/fop/UtilityCodeTestSuite.java | 2 +- .../apache/fop/render/ps/HexEncoderTestCase.java | 58 --------- .../org/apache/fop/util/HexEncoderTestCase.java | 58 +++++++++ 11 files changed, 324 insertions(+), 127 deletions(-) delete mode 100644 src/java/org/apache/fop/render/ps/HexEncoder.java create mode 100644 src/java/org/apache/fop/util/HexEncoder.java delete mode 100644 test/java/org/apache/fop/render/ps/HexEncoderTestCase.java create mode 100644 test/java/org/apache/fop/util/HexEncoderTestCase.java diff --git a/src/java/org/apache/fop/fonts/SingleByteFont.java b/src/java/org/apache/fop/fonts/SingleByteFont.java index 14cba4815..a09c81670 100644 --- a/src/java/org/apache/fop/fonts/SingleByteFont.java +++ b/src/java/org/apache/fop/fonts/SingleByteFont.java @@ -27,6 +27,8 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; + /** * Generic SingleByte font */ @@ -46,6 +48,8 @@ public class SingleByteFont extends CustomFont { private List cmaps; + private PostScriptVersion ttPostScriptVersion; + /** * Main constructor. */ @@ -335,6 +339,27 @@ public class SingleByteFont extends CustomFont { } } + /** + * Sets the version of the PostScript table stored in the TrueType font represented by + * this instance. + * + * @param version version of the post table + */ + public void setTrueTypePostScriptVersion(PostScriptVersion version) { + ttPostScriptVersion = version; + } + + /** + * Returns the version of the PostScript table stored in the TrueType font represented by + * this instance. + * + * @return the version of the post table + */ + public PostScriptVersion getTrueTypePostScriptVersion() { + assert getFontType() == FontType.TRUETYPE; + return ttPostScriptVersion; + } + /** TODO remove */ public void setCMaps(List cmaps) { this.cmaps = cmaps; diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java index 7ad51c676..6f3bb9f49 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java @@ -41,10 +41,94 @@ import org.apache.fop.fonts.FontUtil; public class TTFFile { static final byte NTABS = 24; - static final int NMACGLYPHS = 258; static final int MAX_CHAR_CODE = 255; static final int ENC_BUF_SIZE = 1024; + private static final String[] MAC_GLYPH_ORDERING = { + /* 0x000 */ + ".notdef", ".null", "nonmarkingreturn", "space", + "exclam", "quotedbl", "numbersign", "dollar", + "percent", "ampersand", "quotesingle", "parenleft", + "parenright", "asterisk", "plus", "comma", + /* 0x010 */ + "hyphen", "period", "slash", "zero", + "one", "two", "three", "four", + "five", "six", "seven", "eight", + "nine", "colon", "semicolon", "less", + /* 0x020 */ + "equal", "greater", "question", "at", + "A", "B", "C", "D", + "E", "F", "G", "H", + "I", "J", "K", "L", + /* 0x030 */ + "M", "N", "O", "P", + "Q", "R", "S", "T", + "U", "V", "W", "X", + "Y", "Z", "bracketleft", "backslash", + /* 0x040 */ + "bracketright", "asciicircum", "underscore", "grave", + "a", "b", "c", "d", + "e", "f", "g", "h", + "i", "j", "k", "l", + /* 0x050 */ + "m", "n", "o", "p", + "q", "r", "s", "t", + "u", "v", "w", "x", + "y", "z", "braceleft", "bar", + /* 0x060 */ + "braceright", "asciitilde", "Adieresis", "Aring", + "Ccedilla", "Eacute", "Ntilde", "Odieresis", + "Udieresis", "aacute", "agrave", "acircumflex", + "adieresis", "atilde", "aring", "ccedilla", + /* 0x070 */ + "eacute", "egrave", "ecircumflex", "edieresis", + "iacute", "igrave", "icircumflex", "idieresis", + "ntilde", "oacute", "ograve", "ocircumflex", + "odieresis", "otilde", "uacute", "ugrave", + /* 0x080 */ + "ucircumflex", "udieresis", "dagger", "degree", + "cent", "sterling", "section", "bullet", + "paragraph", "germandbls", "registered", "copyright", + "trademark", "acute", "dieresis", "notequal", + /* 0x090 */ + "AE", "Oslash", "infinity", "plusminus", + "lessequal", "greaterequal", "yen", "mu", + "partialdiff", "summation", "product", "pi", + "integral", "ordfeminine", "ordmasculine", "Omega", + /* 0x0A0 */ + "ae", "oslash", "questiondown", "exclamdown", + "logicalnot", "radical", "florin", "approxequal", + "Delta", "guillemotleft", "guillemotright", "ellipsis", + "nonbreakingspace", "Agrave", "Atilde", "Otilde", + /* 0x0B0 */ + "OE", "oe", "endash", "emdash", + "quotedblleft", "quotedblright", "quoteleft", "quoteright", + "divide", "lozenge", "ydieresis", "Ydieresis", + "fraction", "currency", "guilsinglleft", "guilsinglright", + /* 0x0C0 */ + "fi", "fl", "daggerdbl", "periodcentered", + "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", + "Ecircumflex", "Aacute", "Edieresis", "Egrave", + "Iacute", "Icircumflex", "Idieresis", "Igrave", + /* 0x0D0 */ + "Oacute", "Ocircumflex", "apple", "Ograve", + "Uacute", "Ucircumflex", "Ugrave", "dotlessi", + "circumflex", "tilde", "macron", "breve", + "dotaccent", "ring", "cedilla", "hungarumlaut", + /* 0x0E0 */ + "ogonek", "caron", "Lslash", "lslash", + "Scaron", "scaron", "Zcaron", "zcaron", + "brokenbar", "Eth", "eth", "Yacute", + "yacute", "Thorn", "thorn", "minus", + /* 0x0F0 */ + "multiply", "onesuperior", "twosuperior", "threesuperior", + "onehalf", "onequarter", "threequarters", "franc", + "Gbreve", "gbreve", "Idotaccent", "Scedilla", + "scedilla", "Cacute", "cacute", "Ccaron", + /* 0x100 */ + "ccaron", "dcroat" + }; + /** Set to true to get even more debug output than with level DEBUG */ public static final boolean TRACE_ENABLED = false; @@ -64,7 +148,7 @@ public class TTFFile { private int upem; // unitsPerEm from "head" table private int nhmtx; // Number of horizontal metrics - private int postFormat; + private PostScriptVersion postScriptVersion; private int locaFormat; /** * Offset to last loca @@ -159,6 +243,27 @@ public class TTFFile { } } + /** + * Version of the PostScript table (post) contained in this font. + */ + public static final class PostScriptVersion { + + /** PostScript table version 1.0. */ + public static final PostScriptVersion V1 = new PostScriptVersion(); + + /** PostScript table version 2.0. */ + public static final PostScriptVersion V2 = new PostScriptVersion(); + + /** PostScript table version 3.0. */ + public static final PostScriptVersion V3 = new PostScriptVersion(); + + /** Unknown version of the PostScript table. */ + public static final PostScriptVersion UNKNOWN = new PostScriptVersion(); + + private PostScriptVersion() { } + + } + /** * Position inputstream to position indicated * in the dirtab offset + offset @@ -604,6 +709,10 @@ public class TTFFile { } } + PostScriptVersion getPostScriptVersion() { + return postScriptVersion; + } + /** * Returns the font family names of the font. * @return Set The family names (a Set of Strings) @@ -964,7 +1073,7 @@ public class TTFFile { */ private void readPostScript(FontFileReader in) throws IOException { seekTab(in, "post", 0); - postFormat = in.readTTFLong(); + int postFormat = in.readTTFLong(); italicAngle = in.readTTFULong(); underlinePosition = in.readTTFShort(); underlineThickness = in.readTTFShort(); @@ -977,12 +1086,14 @@ public class TTFFile { switch (postFormat) { case 0x00010000: log.debug("PostScript format 1"); - for (int i = 0; i < Glyphs.MAC_GLYPH_NAMES.length; i++) { - mtxTab[i].setName(Glyphs.MAC_GLYPH_NAMES[i]); + postScriptVersion = PostScriptVersion.V1; + for (int i = 0; i < MAC_GLYPH_ORDERING.length; i++) { + mtxTab[i].setName(MAC_GLYPH_ORDERING[i]); } break; case 0x00020000: log.debug("PostScript format 2"); + postScriptVersion = PostScriptVersion.V2; int numGlyphStrings = 0; // Read Number of Glyphs @@ -1015,11 +1126,11 @@ public class TTFFile { //Set glyph names for (int i = 0; i < l; i++) { - if (mtxTab[i].getIndex() < NMACGLYPHS) { - mtxTab[i].setName(Glyphs.MAC_GLYPH_NAMES[mtxTab[i].getIndex()]); + if (mtxTab[i].getIndex() < MAC_GLYPH_ORDERING.length) { + mtxTab[i].setName(MAC_GLYPH_ORDERING[mtxTab[i].getIndex()]); } else { if (!mtxTab[i].isIndexReserved()) { - int k = mtxTab[i].getIndex() - NMACGLYPHS; + int k = mtxTab[i].getIndex() - MAC_GLYPH_ORDERING.length; if (log.isTraceEnabled()) { log.trace(k + " i=" + i + " mtx=" + mtxTab.length @@ -1035,9 +1146,11 @@ public class TTFFile { case 0x00030000: // PostScript format 3 contains no glyph names log.debug("PostScript format 3"); + postScriptVersion = PostScriptVersion.V3; break; default: log.error("Unknown PostScript format: " + postFormat); + postScriptVersion = PostScriptVersion.UNKNOWN; } } diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index 10e618adf..cf24ea352 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -36,6 +36,8 @@ import org.apache.fop.fonts.FontType; import org.apache.fop.fonts.MultiByteFont; import org.apache.fop.fonts.NamedCharacter; import org.apache.fop.fonts.SingleByteFont; +import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; +import org.apache.fop.util.HexEncoder; /** * Loads a TrueType font into memory directly from the original font file. @@ -162,6 +164,7 @@ public class TTFFontLoader extends FontLoader { returnFont.setFirstChar(ttf.getFirstChar()); returnFont.setLastChar(ttf.getLastChar()); singleFont.setCMaps(ttf.getCMaps()); + singleFont.setTrueTypePostScriptVersion(ttf.getPostScriptVersion()); copyWidthsSingleByte(ttf); } @@ -187,6 +190,9 @@ public class TTFFontLoader extends FontLoader { if (codePoint <= 0) { int glyphIndex = ce.getGlyphStartIndex() + u - ce.getUnicodeStart(); String glyphName = ttf.getGlyphName(glyphIndex); + if (glyphName == "" && ttf.getPostScriptVersion() != PostScriptVersion.V2) { + glyphName = "u" + HexEncoder.encode(u); + } if (glyphName != "") { String unicode = Character.toString(u); NamedCharacter nc = new NamedCharacter(glyphName, unicode); diff --git a/src/java/org/apache/fop/render/ps/HexEncoder.java b/src/java/org/apache/fop/render/ps/HexEncoder.java deleted file mode 100644 index e78563102..000000000 --- a/src/java/org/apache/fop/render/ps/HexEncoder.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index e1a477b4e..07ca0e4b5 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -55,6 +55,8 @@ import org.apache.fop.fonts.SingleByteEncoding; import org.apache.fop.fonts.SingleByteFont; import org.apache.fop.fonts.Typeface; import org.apache.fop.fonts.truetype.TTFCmapEntry; +import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; +import org.apache.fop.util.HexEncoder; /** * Utility code for font handling in PostScript. @@ -132,8 +134,16 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { SingleByteEncoding encoding = sbf.getAdditionalEncoding(i); defineEncoding(gen, encoding); String postFix = "_" + (i + 1); - PSResource derivedFontRes = defineDerivedFont(gen, tf.getFontName(), - tf.getFontName() + postFix, encoding.getName()); + PSResource derivedFontRes; + if (tf.getFontType() == FontType.TRUETYPE + && sbf.getTrueTypePostScriptVersion() != PostScriptVersion.V2) { + derivedFontRes = defineDerivedTrueTypeFont(gen, eventProducer, + tf.getFontName(), tf.getFontName() + postFix, encoding, + sbf.getCMaps()); + } else { + derivedFontRes = defineDerivedFont(gen, tf.getFontName(), + tf.getFontName() + postFix, encoding.getName()); + } fontResources.put(key + postFix, PSFontResource.createFontResource(derivedFontRes)); } @@ -334,7 +344,10 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } private static int getGlyphIndex(String glyphName, List cmaps) { - char c = Glyphs.getUnicodeSequenceForGlyphName(glyphName).charAt(0); + return getGlyphIndex(Glyphs.getUnicodeSequenceForGlyphName(glyphName).charAt(0), cmaps); + } + + private static int getGlyphIndex(char c, List cmaps) { for (Iterator iter = cmaps.iterator(); iter.hasNext();) { TTFCmapEntry cmap = (TTFCmapEntry) iter.next(); if (cmap.getUnicodeStart() <= c && c <= cmap.getUnicodeEnd()) { @@ -591,4 +604,42 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { return res; } + private static PSResource defineDerivedTrueTypeFont(PSGenerator gen, + PSEventProducer eventProducer, String baseFontName, String fontName, + SingleByteEncoding encoding, List cmaps) throws IOException { + PSResource res = new PSResource(PSResource.TYPE_FONT, fontName); + gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, res); + gen.commentln("%XGCDependencies: font " + baseFontName); + gen.commentln("%XGC+ encoding " + encoding.getName()); + gen.writeln("/" + baseFontName + " findfont"); + gen.writeln("dup length dict begin"); + gen.writeln(" {1 index /FID ne {def} {pop pop} ifelse} forall"); + gen.writeln(" /Encoding " + encoding.getName() + " def"); + + gen.writeln(" /CharStrings 256 dict dup begin"); + String[] charNameMap = encoding.getCharNameMap(); + char[] unicodeCharMap = encoding.getUnicodeCharMap(); + assert charNameMap.length == unicodeCharMap.length; + for (int i = 0; i < charNameMap.length; i++) { + String glyphName = charNameMap[i]; + gen.write(" /"); + gen.write(glyphName); + gen.write(" "); + if (glyphName.equals(".notdef")) { + gen.write(0); + } else { + gen.write(getGlyphIndex(unicodeCharMap[i], cmaps)); + } + gen.writeln(" def"); + } + gen.writeln(" end readonly def"); + + gen.writeln(" currentdict"); + gen.writeln("end"); + gen.writeln("/" + fontName + " exch definefont pop"); + gen.writeDSCComment(DSCConstants.END_RESOURCE); + gen.getResourceTracker().registerSuppliedResource(res); + return res; + } + } diff --git a/src/java/org/apache/fop/render/ps/PSPainter.java b/src/java/org/apache/fop/render/ps/PSPainter.java index b31775177..5ed217db1 100644 --- a/src/java/org/apache/fop/render/ps/PSPainter.java +++ b/src/java/org/apache/fop/render/ps/PSPainter.java @@ -55,6 +55,7 @@ import org.apache.fop.render.intermediate.IFState; import org.apache.fop.traits.BorderProps; import org.apache.fop.traits.RuleStyle; import org.apache.fop.util.CharUtilities; +import org.apache.fop.util.HexEncoder; /** * IFPainter implementation that produces PostScript. diff --git a/src/java/org/apache/fop/render/ps/PSTextPainter.java b/src/java/org/apache/fop/render/ps/PSTextPainter.java index c5237fd80..caa778ae2 100644 --- a/src/java/org/apache/fop/render/ps/PSTextPainter.java +++ b/src/java/org/apache/fop/render/ps/PSTextPainter.java @@ -50,6 +50,7 @@ import org.apache.fop.fonts.LazyFont; import org.apache.fop.fonts.MultiByteFont; import org.apache.fop.svg.NativeTextPainter; import org.apache.fop.util.CharUtilities; +import org.apache.fop.util.HexEncoder; /** * Renders the attributed character iterator of a text node. diff --git a/src/java/org/apache/fop/util/HexEncoder.java b/src/java/org/apache/fop/util/HexEncoder.java new file mode 100644 index 000000000..38f312784 --- /dev/null +++ b/src/java/org/apache/fop/util/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.util; + +/** + * A helper class create to hex-encoded representations of numbers. + */ +public 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 + */ + public 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 + */ + public static String encode(char c) { + return encode(c, 4); + } + +} diff --git a/test/java/org/apache/fop/UtilityCodeTestSuite.java b/test/java/org/apache/fop/UtilityCodeTestSuite.java index 153b2649e..3a01f7bf8 100644 --- a/test/java/org/apache/fop/UtilityCodeTestSuite.java +++ b/test/java/org/apache/fop/UtilityCodeTestSuite.java @@ -24,10 +24,10 @@ 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; +import org.apache.fop.util.HexEncoderTestCase; import org.apache.fop.util.PDFNumberTestCase; import org.apache.fop.util.XMLResourceBundleTestCase; diff --git a/test/java/org/apache/fop/render/ps/HexEncoderTestCase.java b/test/java/org/apache/fop/render/ps/HexEncoderTestCase.java deleted file mode 100644 index 75aee060f..000000000 --- a/test/java/org/apache/fop/render/ps/HexEncoderTestCase.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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); - } - } - -} diff --git a/test/java/org/apache/fop/util/HexEncoderTestCase.java b/test/java/org/apache/fop/util/HexEncoderTestCase.java new file mode 100644 index 000000000..e6198e0ad --- /dev/null +++ b/test/java/org/apache/fop/util/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.util; + +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); + } + } + +} -- cgit v1.2.3 From 1080c61fb2f07d5995bd1671751f2f4bd11b1f3e Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Tue, 31 Aug 2010 14:20:22 +0000 Subject: Do not issue a warning if renderer configured to output PostScript level 3. Throw an error instead when it is not the case. Pass the event producer around. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@991203 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/render/ps/PSDocumentHandler.java | 16 ++++++---- .../org/apache/fop/render/ps/PSEventProducer.java | 8 ++--- .../org/apache/fop/render/ps/PSEventProducer.xml | 2 +- src/java/org/apache/fop/render/ps/PSFontUtils.java | 37 ++++++++++++++++++---- .../org/apache/fop/render/ps/ResourceHandler.java | 10 ++++-- 5 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/java/org/apache/fop/render/ps/PSDocumentHandler.java b/src/java/org/apache/fop/render/ps/PSDocumentHandler.java index 1e0411aa5..f5f0fbd24 100644 --- a/src/java/org/apache/fop/render/ps/PSDocumentHandler.java +++ b/src/java/org/apache/fop/render/ps/PSDocumentHandler.java @@ -49,6 +49,7 @@ import org.apache.xmlgraphics.ps.dsc.ResourceTracker; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentBoundingBox; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentHiResBoundingBox; +import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; import org.apache.fop.render.intermediate.IFContext; @@ -104,6 +105,8 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { private static final int COMMENT_DOCUMENT_TRAILER = 1; private static final int COMMENT_PAGE_TRAILER = 2; + private PSEventProducer eventProducer; + /** * Default constructor. */ @@ -123,7 +126,9 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** {@inheritDoc} */ public void setContext(IFContext context) { super.setContext(context); - this.psUtil = new PSRenderingUtil(context.getUserAgent()); + FOUserAgent userAgent = context.getUserAgent(); + this.psUtil = new PSRenderingUtil(userAgent); + eventProducer = PSEventProducer.Provider.get(userAgent.getEventBroadcaster()); } /** {@inheritDoc} */ @@ -142,7 +147,7 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { try { OutputStream out; if (psUtil.isOptimizeResources()) { - this.tempFile = File.createTempFile("fop", null); + this.tempFile = File.createTempFile("fop", ".ps"); out = new java.io.FileOutputStream(this.tempFile); out = new java.io.BufferedOutputStream(out); } else { @@ -200,8 +205,7 @@ 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, - PSEventProducer.Provider.get(getUserAgent().getEventBroadcaster()))); + this.fontResources.addAll(PSFontUtils.writeFontDict(gen, fontInfo, eventProducer)); } else { gen.commentln("%FOPFontSetup"); //Place-holder, will be replaced in the second pass } @@ -256,8 +260,8 @@ public class PSDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { in = new java.io.BufferedInputStream(in); try { try { - ResourceHandler handler = new ResourceHandler(getUserAgent(), this.fontInfo, - resTracker, this.formResources); + ResourceHandler handler = new ResourceHandler(getUserAgent(), eventProducer, + this.fontInfo, resTracker, this.formResources); handler.process(in, this.outputStream, this.currentPageNumber, this.documentBoundingBox); this.outputStream.flush(); diff --git a/src/java/org/apache/fop/render/ps/PSEventProducer.java b/src/java/org/apache/fop/render/ps/PSEventProducer.java index d702a5701..bffdf2236 100644 --- a/src/java/org/apache/fop/render/ps/PSEventProducer.java +++ b/src/java/org/apache/fop/render/ps/PSEventProducer.java @@ -29,7 +29,7 @@ public interface PSEventProducer extends EventProducer { /** Provider class for the event producer. */ final class Provider { - + private Provider() { } @@ -54,10 +54,10 @@ public interface PSEventProducer extends EventProducer { void postscriptDictionaryParseError(Object source, String content, Exception e); /** - * PostScript Level 3 features are being used. + * PostScript Level 3 features are necessary. * * @param source the event source - * @event.severity WARN + * @event.severity FATAL */ - void postscriptLevel3Used(Object source); + void postscriptLevel3Needed(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 213e74e27..64b22d1a4 100644 --- a/src/java/org/apache/fop/render/ps/PSEventProducer.xml +++ b/src/java/org/apache/fop/render/ps/PSEventProducer.xml @@ -1,5 +1,5 @@ Failed to parse dictionary string. Reason: {e}, content = "{content}" - PostScript Level 3 features are needed to handle this document. Please make sure that your printer supports PostScript Level 3. + PostScript Level 3 features are needed to handle this document. diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index 07ca0e4b5..5272dccac 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -77,9 +77,19 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { */ public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo) throws IOException { - return writeFontDict(gen, fontInfo, (PSEventProducer) null); + return writeFontDict(gen, fontInfo, null); } + /** + * Generates the PostScript code for the font dictionary. This method should only be + * used if no "resource optimization" is performed, i.e. when the fonts are not embedded + * in a second pass. + * @param gen PostScript generator to use for output + * @param fontInfo available fonts + * @param eventProducer to report events + * @return a Map of PSResource instances representing all defined fonts (key: font key) + * @throws IOException in case of an I/O problem + */ public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo, PSEventProducer eventProducer) throws IOException { return writeFontDict(gen, fontInfo, fontInfo.getFonts(), true, eventProducer); @@ -92,12 +102,13 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { * @param gen PostScript generator to use for output * @param fontInfo available fonts * @param fonts the set of fonts to work with + * @param eventProducer the event producer * @return a Map of PSResource instances representing all defined fonts (key: font key) * @throws IOException in case of an I/O problem */ - public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo, Map fonts) - throws IOException { - return writeFontDict(gen, fontInfo, fonts, false, null); + public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo, Map fonts, + PSEventProducer eventProducer) throws IOException { + return writeFontDict(gen, fontInfo, fonts, false, eventProducer); } /** @@ -224,14 +235,12 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { if (in != null) { if (fontType == FontType.TYPE0) { if (gen.embedIdentityH()) { + checkPostScriptVersion(gen, eventProducer); /* * 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, @@ -268,6 +277,19 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { return fontResource; } + private static void checkPostScriptVersion(PSGenerator gen, PSEventProducer eventProducer) { + if (gen.getPSLevel() < 3) { + if (eventProducer != null) { + eventProducer.postscriptLevel3Needed(gen); + } else { + throw new IllegalStateException("PostScript Level 3 is" + + " required to use TrueType fonts," + + " configured level is " + + gen.getPSLevel()); + } + } + } + private static void embedTrueTypeFont(PSGenerator gen, SingleByteFont font, InputStream fontStream) throws IOException { /* See Adobe Technical Note #5012, "The Type 42 Font Format Specification" */ @@ -607,6 +629,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { private static PSResource defineDerivedTrueTypeFont(PSGenerator gen, PSEventProducer eventProducer, String baseFontName, String fontName, SingleByteEncoding encoding, List cmaps) throws IOException { + checkPostScriptVersion(gen, eventProducer); PSResource res = new PSResource(PSResource.TYPE_FONT, fontName); gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, res); gen.commentln("%XGCDependencies: font " + baseFontName); diff --git a/src/java/org/apache/fop/render/ps/ResourceHandler.java b/src/java/org/apache/fop/render/ps/ResourceHandler.java index 502242c17..5594897ba 100644 --- a/src/java/org/apache/fop/render/ps/ResourceHandler.java +++ b/src/java/org/apache/fop/render/ps/ResourceHandler.java @@ -83,6 +83,8 @@ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors { private FOUserAgent userAgent; private FontInfo fontInfo; + private PSEventProducer eventProducer; + private ResourceTracker resTracker; //key: URI, values PSImageFormResource @@ -93,13 +95,15 @@ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors { /** * Main constructor. * @param userAgent the FO user agent + * @param eventProducer the event producer * @param fontInfo the font information * @param resTracker the resource tracker to use * @param formResources Contains all forms used by this document (maintained by PSRenderer) */ - public ResourceHandler(FOUserAgent userAgent, FontInfo fontInfo, - ResourceTracker resTracker, Map formResources) { + public ResourceHandler(FOUserAgent userAgent, PSEventProducer eventProducer, + FontInfo fontInfo, ResourceTracker resTracker, Map formResources) { this.userAgent = userAgent; + this.eventProducer = eventProducer; this.fontInfo = fontInfo; this.resTracker = resTracker; determineInlineForms(formResources); @@ -222,7 +226,7 @@ public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors { if (fontSetupPlaceholder == null) { throw new DSCException("Didn't find %FOPFontSetup comment in stream"); } - PSFontUtils.writeFontDict(gen, fontInfo, fontInfo.getUsedFonts()); + PSFontUtils.writeFontDict(gen, fontInfo, fontInfo.getUsedFonts(), eventProducer); generateForms(globalFormResources, gen); //Skip the prolog and to the first page -- cgit v1.2.3 From e725976e0051e90b91664cf96dc22d79a4425c16 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Wed, 3 Nov 2010 16:22:50 +0000 Subject: TrueType subsetting for CID TTF fonts is now working. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1030518 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/render/ps/FontResourceCache.java | 4 +- src/java/org/apache/fop/render/ps/PSFontUtils.java | 101 ++++++++++++--------- 2 files changed, 61 insertions(+), 44 deletions(-) diff --git a/src/java/org/apache/fop/render/ps/FontResourceCache.java b/src/java/org/apache/fop/render/ps/FontResourceCache.java index 24a34e3db..dc88711b3 100644 --- a/src/java/org/apache/fop/render/ps/FontResourceCache.java +++ b/src/java/org/apache/fop/render/ps/FontResourceCache.java @@ -77,9 +77,9 @@ class FontResourceCache { throw new IllegalStateException("Font not available: " + key); } if (postFix == null) { - return tf.getFontName(); + return tf.getEmbedFontName(); } else { - return tf.getFontName() + postFix; + return tf.getEmbedFontName() + postFix; } } diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index 5272dccac..8ff2a5567 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -24,7 +24,6 @@ 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; import java.util.Map; @@ -54,7 +53,9 @@ import org.apache.fop.fonts.MultiByteFont; import org.apache.fop.fonts.SingleByteEncoding; import org.apache.fop.fonts.SingleByteFont; import org.apache.fop.fonts.Typeface; +import org.apache.fop.fonts.truetype.FontFileReader; import org.apache.fop.fonts.truetype.TTFCmapEntry; +import org.apache.fop.fonts.truetype.TTFSubSetFile; import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; import org.apache.fop.util.HexEncoder; @@ -130,7 +131,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { while (iter.hasNext()) { String key = (String)iter.next(); Typeface tf = getTypeFace(fontInfo, fonts, key); - PSResource fontRes = new PSResource(PSResource.TYPE_FONT, tf.getFontName()); + PSResource fontRes = new PSResource(PSResource.TYPE_FONT, tf.getEmbedFontName()); PSFontResource fontResource = embedFont(gen, tf, fontRes, eventProducer); fontResources.put(key, fontResource); @@ -149,11 +150,11 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { if (tf.getFontType() == FontType.TRUETYPE && sbf.getTrueTypePostScriptVersion() != PostScriptVersion.V2) { derivedFontRes = defineDerivedTrueTypeFont(gen, eventProducer, - tf.getFontName(), tf.getFontName() + postFix, encoding, + tf.getEmbedFontName(), tf.getEmbedFontName() + postFix, encoding, sbf.getCMaps()); } else { - derivedFontRes = defineDerivedFont(gen, tf.getFontName(), - tf.getFontName() + postFix, encoding.getName()); + derivedFontRes = defineDerivedFont(gen, tf.getEmbedFontName(), + tf.getEmbedFontName() + postFix, encoding.getName()); } fontResources.put(key + postFix, PSFontResource.createFontResource(derivedFontRes)); @@ -194,12 +195,12 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } else { if (tf instanceof Base14Font) { //Our Base 14 fonts don't use the default encoding - redefineFontEncoding(gen, tf.getFontName(), tf.getEncodingName()); + redefineFontEncoding(gen, tf.getEmbedFontName(), tf.getEncodingName()); } else if (tf instanceof SingleByteFont) { SingleByteFont sbf = (SingleByteFont)tf; if (!sbf.isUsingNativeEncoding()) { //Font has been configured to use an encoding other than the default one - redefineFontEncoding(gen, tf.getFontName(), tf.getEncodingName()); + redefineFontEncoding(gen, tf.getEmbedFontName(), tf.getEncodingName()); } } } @@ -235,7 +236,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { if (in != null) { if (fontType == FontType.TYPE0) { if (gen.embedIdentityH()) { - checkPostScriptVersion(gen, eventProducer); + checkPostScriptLevel3(gen, eventProducer); /* * First CID-keyed font to be embedded; add * %%IncludeResource: comment for ProcSet CIDInit. @@ -257,14 +258,14 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { embedTrueTypeFont(gen, (SingleByteFont) tf, in); fontResource = PSFontResource.createFontResource(fontRes); } else { - embedType0Font(gen, (MultiByteFont) tf, in); + composeType0Font(gen, (MultiByteFont) tf, in); } gen.writeDSCComment(DSCConstants.END_RESOURCE); gen.getResourceTracker().registerSuppliedResource(fontRes); embeddedFont = true; } else { - gen.commentln("%WARNING: Could not embed font: " + cf.getFontName()); - log.warn("Font " + cf.getFontName() + " is marked as supplied in the" + gen.commentln("%WARNING: Could not embed font: " + cf.getEmbedFontName()); + log.warn("Font " + cf.getEmbedFontName() + " is marked as supplied in the" + " PostScript file but could not be embedded!"); } } @@ -277,7 +278,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { return fontResource; } - private static void checkPostScriptVersion(PSGenerator gen, PSEventProducer eventProducer) { + private static void checkPostScriptLevel3(PSGenerator gen, PSEventProducer eventProducer) { if (gen.getPSLevel() < 3) { if (eventProducer != null) { eventProducer.postscriptLevel3Needed(gen); @@ -302,7 +303,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { private static void createType42DictionaryEntries(PSGenerator gen, CustomFont font, InputStream fontStream, List cmaps) throws IOException { gen.write("/FontName /"); - gen.write(font.getFontName()); + gen.write(font.getEmbedFontName()); gen.writeln(" def"); gen.writeln("/PaintType 0 def"); gen.writeln("/FontMatrix [1 0 0 1 0 0] def"); @@ -310,19 +311,25 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { 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(i); - gen.write(" /"); - String glyphName = Glyphs.charToGlyphName(Glyphs.WINANSI_ENCODING[i]); - if (glyphName.equals("")) { - gen.write(Glyphs.NOTDEF); - } else { - glyphs.add(glyphName); - gen.write(glyphName); + Set glyphs = null; + if (font.getFontType() == FontType.TYPE0) { + //"/Encoding" is required but ignored for CID fonts + //so we keep it minimal to save space + } else { + glyphs = new java.util.HashSet(); + for (int i = 0; i < Glyphs.WINANSI_ENCODING.length; i++) { + gen.write("dup "); + gen.write(i); + gen.write(" /"); + String glyphName = Glyphs.charToGlyphName(Glyphs.WINANSI_ENCODING[i]); + if (glyphName.equals("")) { + gen.write(Glyphs.NOTDEF); + } else { + glyphs.add(glyphName); //TODO don't just register the WinAnsi subset! + gen.write(glyphName); + } + gen.writeln(" put"); } - gen.writeln(" put"); } gen.writeln("readonly def"); gen.write("/sfnts["); @@ -348,19 +355,22 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } gen.writeln("]def"); gen.write("/CharStrings "); - gen.write(glyphs.size() + 1); + gen.write(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 - for (Iterator iter = glyphs.iterator(); iter.hasNext();) { - String glyphName = (String) iter.next(); - gen.write("/"); - gen.write(glyphName); - gen.write(" "); - gen.write(getGlyphIndex(glyphName, cmaps)); - gen.writeln(" def"); + if (glyphs != null) { + for (Iterator iter = glyphs.iterator(); iter.hasNext();) { + String glyphName = (String) iter.next(); + gen.write("/"); + gen.write(glyphName); + gen.write(" "); + gen.write(getGlyphIndex(glyphName, cmaps)); + gen.writeln(" def"); + } } gen.writeln("end readonly def"); } @@ -379,9 +389,9 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { return 0; } - private static void embedType0Font(PSGenerator gen, MultiByteFont font, InputStream fontStream) + private static void composeType0Font(PSGenerator gen, MultiByteFont font, InputStream fontStream) throws IOException { - String psName = font.getFontName(); + String psName = font.getEmbedFontName(); gen.write("/"); gen.write(psName); gen.write(" /Identity-H [/"); @@ -391,7 +401,14 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { private static PSResource embedCIDFont(PSGenerator gen, MultiByteFont font, InputStream fontStream) throws IOException { - String psName = font.getFontName(); + FontFileReader reader = new FontFileReader(fontStream); + + TTFSubSetFile subset = new TTFSubSetFile(); + byte[] subsetFont = subset.readFont(reader, + font.getTTCName(), font.getUsedGlyphs()); + InputStream subsetInput = new java.io.ByteArrayInputStream(subsetFont); + + String psName = font.getEmbedFontName(); gen.write("%%BeginResource: CIDFont "); gen.writeln(psName); @@ -446,11 +463,11 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { lineCount = 1; } } - String gid = HexEncoder.encode(cidSubset.getGlyphIndexForSubsetIndex(cid), 4); + String gid = HexEncoder.encode(cid, 4); gen.write(gid); } gen.writeln(">] def"); - createType42DictionaryEntries(gen, font, fontStream, Collections.EMPTY_LIST); + createType42DictionaryEntries(gen, font, subsetInput, Collections.EMPTY_LIST); gen.writeln("CIDFontName currentdict end /CIDFont defineresource pop"); gen.writeln("end"); gen.writeln("%%EndResource"); @@ -525,7 +542,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { while (iter.hasNext()) { String key = (String)iter.next(); Typeface tf = getTypeFace(fontInfo, fonts, key); - PSResource fontRes = new PSResource("font", tf.getFontName()); + PSResource fontRes = new PSResource("font", tf.getEmbedFontName()); fontResources.put(key, fontRes); FontType fontType = tf.getFontType(); if (fontType == FontType.TYPE1 || fontType == FontType.TRUETYPE @@ -535,7 +552,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { if (isEmbeddable(cf)) { if (fontType == FontType.TYPE0) { resTracker.registerSuppliedResource( - new PSResource(PSResource.TYPE_CIDFONT, tf.getFontName())); + new PSResource(PSResource.TYPE_CIDFONT, tf.getEmbedFontName())); resTracker.registerSuppliedResource( new PSResource(PSResource.TYPE_CMAP, "Identity-H")); } @@ -549,7 +566,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { PSResource.TYPE_ENCODING, encoding.getName()); resTracker.registerSuppliedResource(encodingRes); PSResource derivedFontRes = new PSResource( - PSResource.TYPE_FONT, tf.getFontName() + "_" + (i + 1)); + PSResource.TYPE_FONT, tf.getEmbedFontName() + "_" + (i + 1)); resTracker.registerSuppliedResource(derivedFontRes); } } @@ -629,7 +646,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { private static PSResource defineDerivedTrueTypeFont(PSGenerator gen, PSEventProducer eventProducer, String baseFontName, String fontName, SingleByteEncoding encoding, List cmaps) throws IOException { - checkPostScriptVersion(gen, eventProducer); + checkPostScriptLevel3(gen, eventProducer); PSResource res = new PSResource(PSResource.TYPE_FONT, fontName); gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, res); gen.commentln("%XGCDependencies: font " + baseFontName); -- cgit v1.2.3 From 327caf5863606991d03fc1e3e5c9880bec75b4ca Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Thu, 11 Nov 2010 20:03:43 +0000 Subject: PostScript Output: Bugfix for the occasional badly rendered glyph on HP Laserjets. Reason: the /sfnts entry should split strings at glyph boundaries which currently doesn't happen. Solution: Switch to the /GlyphDirectory approach described in the section "Incremental Definition of Type 42 Fonts" in the PS language reference. This way all glyphs are separated into single strings which seems to solve the problem. It is also much closer to the approach taken by the various PostScript printer drivers on Windows. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1034094 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/fonts/truetype/TTFSubSetFile.java | 410 ++++++++++++--------- src/java/org/apache/fop/render/ps/PSFontUtils.java | 50 ++- 2 files changed, 274 insertions(+), 186 deletions(-) diff --git a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java index 37e24836e..7614a267b 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java @@ -20,7 +20,6 @@ package org.apache.fop.fonts.truetype; import java.io.IOException; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -35,6 +34,10 @@ import java.util.Map; */ public class TTFSubSetFile extends TTFFile { + private static enum OperatingMode { + PDF, POSTSCRIPT_GLYPH_DIRECTORY + } + private byte[] output = null; private int realSize = 0; private int currentPos = 0; @@ -43,37 +46,27 @@ public class TTFSubSetFile extends TTFFile { * Offsets in name table to be filled out by table. * The offsets are to the checkSum field */ - private int cvtDirOffset = 0; - private int fpgmDirOffset = 0; + private Map offsets = new java.util.HashMap(); private int glyfDirOffset = 0; private int headDirOffset = 0; - private int hheaDirOffset = 0; private int hmtxDirOffset = 0; private int locaDirOffset = 0; private int maxpDirOffset = 0; - private int prepDirOffset = 0; private int checkSumAdjustmentOffset = 0; private int locaOffset = 0; - /** - * Initalize the output array - */ - private void init(int size) { - output = new byte[size]; - realSize = 0; - currentPos = 0; - - // createDirectory() - } - - private int determineTableCount() { + private int determineTableCount(OperatingMode operatingMode) { int numTables = 4; //4 req'd tables: head,hhea,hmtx,maxp if (isCFF()) { throw new UnsupportedOperationException( "OpenType fonts with CFF glyphs are not supported"); } else { - numTables += 2; //1 req'd table: glyf,loca + if (operatingMode == OperatingMode.POSTSCRIPT_GLYPH_DIRECTORY) { + numTables++; //1 table: gdir + } else { + numTables += 2; //2 req'd tables: glyf,loca + } if (hasCvt()) { numTables++; } @@ -90,8 +83,8 @@ public class TTFSubSetFile extends TTFFile { /** * Create the directory table */ - private void createDirectory() { - int numTables = determineTableCount(); + private void createDirectory(OperatingMode operatingMode) { + int numTables = determineTableCount(operatingMode); // Create the TrueType header writeByte((byte)0); writeByte((byte)1); @@ -117,22 +110,24 @@ public class TTFSubSetFile extends TTFFile { // Create space for the table entries if (hasCvt()) { writeString("cvt "); - cvtDirOffset = currentPos; + offsets.put("cvt ", currentPos); currentPos += 12; realSize += 16; } if (hasFpgm()) { writeString("fpgm"); - fpgmDirOffset = currentPos; + offsets.put("fpgm", currentPos); currentPos += 12; realSize += 16; } - writeString("glyf"); - glyfDirOffset = currentPos; - currentPos += 12; - realSize += 16; + if (operatingMode != OperatingMode.POSTSCRIPT_GLYPH_DIRECTORY) { + writeString("glyf"); + glyfDirOffset = currentPos; + currentPos += 12; + realSize += 16; + } writeString("head"); headDirOffset = currentPos; @@ -140,7 +135,7 @@ public class TTFSubSetFile extends TTFFile { realSize += 16; writeString("hhea"); - hheaDirOffset = currentPos; + offsets.put("hhea", currentPos); currentPos += 12; realSize += 16; @@ -149,10 +144,12 @@ public class TTFSubSetFile extends TTFFile { currentPos += 12; realSize += 16; - writeString("loca"); - locaDirOffset = currentPos; - currentPos += 12; - realSize += 16; + if (operatingMode != OperatingMode.POSTSCRIPT_GLYPH_DIRECTORY) { + writeString("loca"); + locaDirOffset = currentPos; + currentPos += 12; + realSize += 16; + } writeString("maxp"); maxpDirOffset = currentPos; @@ -161,37 +158,21 @@ public class TTFSubSetFile extends TTFFile { if (hasPrep()) { writeString("prep"); - prepDirOffset = currentPos; + offsets.put("prep", currentPos); currentPos += 12; realSize += 16; } - } - - - /** - * Copy the cvt table as is from original font to subset font - */ - private boolean createCvt(FontFileReader in) throws IOException { - TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("cvt "); - if (entry != null) { - pad4(); - seekTab(in, "cvt ", 0); - System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()), - 0, output, currentPos, (int)entry.getLength()); - int checksum = getCheckSum(currentPos, (int)entry.getLength()); - writeULong(cvtDirOffset, checksum); - writeULong(cvtDirOffset + 4, currentPos); - writeULong(cvtDirOffset + 8, (int)entry.getLength()); - currentPos += (int)entry.getLength(); - realSize += (int)entry.getLength(); - return true; - } else { - return false; - //throw new IOException("Can't find cvt table"); + if (operatingMode == OperatingMode.POSTSCRIPT_GLYPH_DIRECTORY) { + //"gdir" indicates to the PostScript interpreter that the GlyphDirectory approach + //is in use. + writeString("gdir"); + currentPos += 12; + realSize += 16; } } + private boolean hasCvt() { return dirTabs.containsKey("cvt "); } @@ -205,19 +186,29 @@ public class TTFSubSetFile extends TTFFile { } /** - * Copy the fpgm table as is from original font to subset font + * Create an empty loca table without updating checksum */ - private boolean createFpgm(FontFileReader in) throws IOException { - TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("fpgm"); + private void createLoca(int size) throws IOException { + pad4(); + locaOffset = currentPos; + writeULong(locaDirOffset + 4, currentPos); + writeULong(locaDirOffset + 8, size * 4 + 4); + currentPos += size * 4 + 4; + realSize += size * 4 + 4; + } + + private boolean copyTable(FontFileReader in, String tableName) throws IOException { + TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get(tableName); if (entry != null) { pad4(); - seekTab(in, "fpgm", 0); + seekTab(in, tableName, 0); System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()), 0, output, currentPos, (int)entry.getLength()); int checksum = getCheckSum(currentPos, (int)entry.getLength()); - writeULong(fpgmDirOffset, checksum); - writeULong(fpgmDirOffset + 4, currentPos); - writeULong(fpgmDirOffset + 8, (int)entry.getLength()); + int offset = offsets.get(tableName); + writeULong(offset, checksum); + writeULong(offset + 4, currentPos); + writeULong(offset + 8, (int)entry.getLength()); currentPos += (int)entry.getLength(); realSize += (int)entry.getLength(); return true; @@ -226,20 +217,19 @@ public class TTFSubSetFile extends TTFFile { } } - - /** - * Create an empty loca table without updating checksum + * Copy the cvt table as is from original font to subset font */ - private void createLoca(int size) throws IOException { - pad4(); - locaOffset = currentPos; - writeULong(locaDirOffset + 4, currentPos); - writeULong(locaDirOffset + 8, size * 4 + 4); - currentPos += size * 4 + 4; - realSize += size * 4 + 4; + private boolean createCvt(FontFileReader in) throws IOException { + return copyTable(in, "cvt "); } + /** + * Copy the fpgm table as is from original font to subset font + */ + private boolean createFpgm(FontFileReader in) throws IOException { + return copyTable(in, "fpgm"); + } /** * Copy the maxp table as is from original font to subset font @@ -270,23 +260,7 @@ public class TTFSubSetFile extends TTFFile { * Copy the prep table as is from original font to subset font */ private boolean createPrep(FontFileReader in) throws IOException { - TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("prep"); - if (entry != null) { - pad4(); - seekTab(in, "prep", 0); - System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()), - 0, output, currentPos, (int)entry.getLength()); - - int checksum = getCheckSum(currentPos, (int)entry.getLength()); - writeULong(prepDirOffset, checksum); - writeULong(prepDirOffset + 4, currentPos); - writeULong(prepDirOffset + 8, (int)entry.getLength()); - currentPos += (int)entry.getLength(); - realSize += (int)entry.getLength(); - return true; - } else { - return false; - } + return copyTable(in, "prep"); } @@ -295,21 +269,8 @@ public class TTFSubSetFile extends TTFFile { * and fill in size of hmtx table */ private void createHhea(FontFileReader in, int size) throws IOException { - TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hhea"); - if (entry != null) { - pad4(); - seekTab(in, "hhea", 0); - System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()), - 0, output, currentPos, (int)entry.getLength()); - writeUShort((int)entry.getLength() + currentPos - 2, size); - - int checksum = getCheckSum(currentPos, (int)entry.getLength()); - writeULong(hheaDirOffset, checksum); - writeULong(hheaDirOffset + 4, currentPos); - writeULong(hheaDirOffset + 8, (int)entry.getLength()); - currentPos += (int)entry.getLength(); - realSize += (int)entry.getLength(); - } else { + boolean copied = copyTable(in, "hhea"); + if (!copied) { throw new IOException("Can't find hhea table"); } } @@ -354,30 +315,22 @@ public class TTFSubSetFile extends TTFFile { * Create the glyf table and fill in loca table */ private void createGlyf(FontFileReader in, - Map glyphs) throws IOException { + Map glyphs) throws IOException { TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf"); int size = 0; - int start = 0; + int startPos = 0; int endOffset = 0; // Store this as the last loca if (entry != null) { pad4(); - start = currentPos; + startPos = currentPos; /* Loca table must be in order by glyph index, so build * an array first and then write the glyph info and * location offset. */ - int[] origIndexes = new int[glyphs.size()]; - - Iterator e = glyphs.keySet().iterator(); - while (e.hasNext()) { - Integer origIndex = (Integer)e.next(); - Integer subsetIndex = (Integer)glyphs.get(origIndex); - origIndexes[subsetIndex.intValue()] = origIndex.intValue(); - } + int[] origIndexes = buildSubsetIndexToOrigIndexMap(glyphs); for (int i = 0; i < origIndexes.length; i++) { - int glyphLength = 0; int nextOffset = 0; int origGlyphIndex = origIndexes[i]; if (origGlyphIndex >= (mtxTab.length - 1)) { @@ -385,32 +338,38 @@ public class TTFSubSetFile extends TTFFile { } else { nextOffset = (int)mtxTab[origGlyphIndex + 1].getOffset(); } - glyphLength = nextOffset - (int)mtxTab[origGlyphIndex].getOffset(); + int glyphOffset = (int)mtxTab[origGlyphIndex].getOffset(); + int glyphLength = nextOffset - glyphOffset; + byte[] glyphData = in.getBytes( + (int)entry.getOffset() + glyphOffset, + glyphLength); + int endOffset1 = endOffset; // Copy glyph System.arraycopy( - in.getBytes((int)entry.getOffset() + (int)mtxTab[origGlyphIndex].getOffset(), - glyphLength), 0, + glyphData, 0, output, currentPos, glyphLength); // Update loca table - writeULong(locaOffset + i * 4, currentPos - start); - if ((currentPos - start + glyphLength) > endOffset) { - endOffset = (currentPos - start + glyphLength); + writeULong(locaOffset + i * 4, currentPos - startPos); + if ((currentPos - startPos + glyphLength) > endOffset1) { + endOffset1 = (currentPos - startPos + glyphLength); } currentPos += glyphLength; realSize += glyphLength; + endOffset = endOffset1; + } - size = currentPos - start; + size = currentPos - startPos; - int checksum = getCheckSum(start, size); + int checksum = getCheckSum(startPos, size); writeULong(glyfDirOffset, checksum); - writeULong(glyfDirOffset + 4, start); + writeULong(glyfDirOffset + 4, startPos); writeULong(glyfDirOffset + 8, size); currentPos += 12; realSize += 12; @@ -425,6 +384,15 @@ public class TTFSubSetFile extends TTFFile { } } + private int[] buildSubsetIndexToOrigIndexMap(Map glyphs) { + int[] origIndexes = new int[glyphs.size()]; + for (Map.Entry glyph : glyphs.entrySet()) { + int origIndex = glyph.getKey(); + int subsetIndex = glyph.getValue(); + origIndexes[subsetIndex] = origIndex; + } + return origIndexes; + } /** * Create the hmtx table by copying metrics from original @@ -433,7 +401,7 @@ public class TTFSubSetFile extends TTFFile { * metric (key) to the subset metric (value) */ private void createHmtx(FontFileReader in, - Map glyphs) throws IOException { + Map glyphs) throws IOException { TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hmtx"); int longHorMetricSize = glyphs.size() * 2; @@ -443,10 +411,9 @@ public class TTFSubSetFile extends TTFFile { if (entry != null) { pad4(); //int offset = (int)entry.offset; - Iterator e = glyphs.keySet().iterator(); - while (e.hasNext()) { - Integer origIndex = (Integer)e.next(); - Integer subsetIndex = (Integer)glyphs.get(origIndex); + for (Map.Entry glyph : glyphs.entrySet()) { + Integer origIndex = glyph.getKey(); + Integer subsetIndex = glyph.getValue(); writeUShort(currentPos + subsetIndex.intValue() * 4, mtxTab[origIndex.intValue()].getWx()); @@ -469,9 +436,9 @@ public class TTFSubSetFile extends TTFFile { * Returns a List containing the glyph itself plus all glyphs * that this composite glyph uses */ - private List getIncludedGlyphs(FontFileReader in, int glyphOffset, + private List getIncludedGlyphs(FontFileReader in, int glyphOffset, Integer glyphIdx) throws IOException { - List ret = new java.util.ArrayList(); + List ret = new java.util.ArrayList(); ret.add(glyphIdx); int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset() + 10; Integer compositeIdx = null; @@ -479,7 +446,7 @@ public class TTFSubSetFile extends TTFFile { boolean moreComposites = true; while (moreComposites) { flags = in.readTTFUShort(offset); - compositeIdx = new Integer(in.readTTFUShort(offset + 2)); + compositeIdx = Integer.valueOf(in.readTTFUShort(offset + 2)); ret.add(compositeIdx); offset += 4; @@ -513,7 +480,7 @@ public class TTFSubSetFile extends TTFFile { * Rewrite all compositepointers in glyphindex glyphIdx * */ - private void remapComposite(FontFileReader in, Map glyphs, + private void remapComposite(FontFileReader in, Map glyphs, int glyphOffset, Integer glyphIdx) throws IOException { int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset() @@ -525,8 +492,8 @@ public class TTFSubSetFile extends TTFFile { while (moreComposites) { flags = in.readTTFUShort(offset); - compositeIdx = new Integer(in.readTTFUShort(offset + 2)); - Integer newIdx = (Integer)glyphs.get(compositeIdx); + compositeIdx = Integer.valueOf(in.readTTFUShort(offset + 2)); + Integer newIdx = glyphs.get(compositeIdx); if (newIdx == null) { // This errormessage would look much better // if the fontname was printed to @@ -572,40 +539,35 @@ public class TTFSubSetFile extends TTFFile { * mapping */ private void scanGlyphs(FontFileReader in, - Map glyphs) throws IOException { + Map glyphs) throws IOException { TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf"); - Map newComposites = null; - Map allComposites = new java.util.HashMap(); + Map newComposites = null; + Map allComposites = new java.util.HashMap(); int newIndex = glyphs.size(); if (entry != null) { while (newComposites == null || newComposites.size() > 0) { // Inefficient to iterate through all glyphs - newComposites = new java.util.HashMap(); - - Iterator e = glyphs.keySet().iterator(); - while (e.hasNext()) { - Integer origIndex = (Integer)e.next(); + newComposites = new java.util.HashMap(); + for (Map.Entry glyph : glyphs.entrySet()) { + int origIndex = glyph.getKey(); if (in.readTTFShort(entry.getOffset() - + mtxTab[origIndex.intValue()].getOffset()) < 0) { + + mtxTab[origIndex].getOffset()) < 0) { // origIndex is a composite glyph - allComposites.put(origIndex, glyphs.get(origIndex)); - List composites + allComposites.put(origIndex, glyph.getValue()); + List composites = getIncludedGlyphs(in, (int)entry.getOffset(), origIndex); // Iterate through all composites pointed to // by this composite and check if they exists // in the glyphs map, add them if not. - Iterator cps = composites.iterator(); - while (cps.hasNext()) { - Integer cIdx = (Integer)cps.next(); + for (Integer cIdx : composites) { if (glyphs.get(cIdx) == null && newComposites.get(cIdx) == null) { - newComposites.put(cIdx, - new Integer(newIndex)); + newComposites.put(cIdx, newIndex); newIndex++; } } @@ -613,18 +575,15 @@ public class TTFSubSetFile extends TTFFile { } // Add composites to glyphs - Iterator m = newComposites.keySet().iterator(); - while (m.hasNext()) { - Integer im = (Integer)m.next(); - glyphs.put(im, newComposites.get(im)); + for (Map.Entry im : newComposites.entrySet()) { + glyphs.put(im.getKey(), im.getValue()); } } // Iterate through all composites to remap their composite index - Iterator ce = allComposites.keySet().iterator(); - while (ce.hasNext()) { + for (Integer idx : allComposites.keySet()) { remapComposite(in, glyphs, (int)entry.getOffset(), - (Integer)ce.next()); + idx); } } else { @@ -653,7 +612,7 @@ public class TTFSubSetFile extends TTFFile { } //Copy the Map as we're going to modify it - Map subsetGlyphs = new java.util.HashMap(glyphs); + Map subsetGlyphs = new java.util.HashMap(glyphs); output = new byte[in.getFileSize()]; @@ -666,7 +625,7 @@ public class TTFSubSetFile extends TTFFile { scanGlyphs(in, subsetGlyphs); - createDirectory(); // Create the TrueType header and directory + createDirectory(OperatingMode.PDF); // Create the TrueType header and directory createHead(in); createHhea(in, subsetGlyphs.size()); // Create the hhea table @@ -704,6 +663,121 @@ public class TTFSubSetFile extends TTFFile { return ret; } + /** + * Returns a subset of the original font suitable for use in PostScript programs. + * + * @param in FontFileReader to read from + * @param name Name to be checked for in the font file + * @param glyphs Map of glyphs (glyphs has old index as (Integer) key and + * new index as (Integer) value) + * @param glyphHandler the handler to receive all glyphs of the subset + * @return A subset of the original font + * @throws IOException in case of an I/O problem + */ + public byte[] toPostScriptSubset(FontFileReader in, String name, + Map glyphs, GlyphHandler glyphHandler) throws IOException { + + //Check if TrueType collection, and that the name exists in the collection + if (!checkTTC(in, name)) { + throw new IOException("Failed to read font"); + } + + //Copy the Map as we're going to modify it + Map subsetGlyphs = new java.util.HashMap(glyphs); + + output = new byte[in.getFileSize()]; + + readDirTabs(in); + readFontHeader(in); + getNumGlyphs(in); + readHorizontalHeader(in); + readHorizontalMetrics(in); + readIndexToLocation(in); + + scanGlyphs(in, subsetGlyphs); + + // Create the TrueType header and directory + createDirectory(OperatingMode.POSTSCRIPT_GLYPH_DIRECTORY); + + createHead(in); + createHhea(in, subsetGlyphs.size()); // Create the hhea table + createHmtx(in, subsetGlyphs); // Create hmtx table + createMaxp(in, subsetGlyphs.size()); // copy the maxp table + + boolean optionalTableFound; + optionalTableFound = createCvt(in); // copy the cvt table + if (!optionalTableFound) { + // cvt is optional (used in TrueType fonts only) + log.debug("TrueType: ctv table not present. Skipped."); + } + + optionalTableFound = createFpgm(in); // copy fpgm table + if (!optionalTableFound) { + // fpgm is optional (used in TrueType fonts only) + log.debug("TrueType: fpgm table not present. Skipped."); + } + + optionalTableFound = createPrep(in); // copy prep table + if (!optionalTableFound) { + // prep is optional (used in TrueType fonts only) + log.debug("TrueType: prep table not present. Skipped."); + } + + //Send all the glyphs from the subset + handleGlyphSubset(in, subsetGlyphs, glyphHandler); + + pad4(); + createCheckSumAdjustment(); + + byte[] ret = new byte[realSize]; + System.arraycopy(output, 0, ret, 0, realSize); + + return ret; + } + + private void handleGlyphSubset(FontFileReader in, Map glyphs, + GlyphHandler glyphHandler) throws IOException { + TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf"); + if (entry != null) { + + int[] origIndexes = buildSubsetIndexToOrigIndexMap(glyphs); + + for (int i = 0; i < origIndexes.length; i++) { + int nextOffset = 0; + int origGlyphIndex = origIndexes[i]; + if (origGlyphIndex >= (mtxTab.length - 1)) { + nextOffset = (int)lastLoca; + } else { + nextOffset = (int)mtxTab[origGlyphIndex + 1].getOffset(); + } + int glyphOffset = (int)mtxTab[origGlyphIndex].getOffset(); + int glyphLength = nextOffset - glyphOffset; + + byte[] glyphData = in.getBytes( + (int)entry.getOffset() + glyphOffset, + glyphLength); + + glyphHandler.addGlyph(glyphData); + } + } else { + throw new IOException("Can't find glyf table"); + } + } + + /** + * Used as callback to handle a number of glyphs. + */ + public static interface GlyphHandler { + + /** + * Adds a glyph. + * @param glyphData the glyph data + * @throws IOException if an I/O error occurs + */ + void addGlyph(byte[] glyphData) throws IOException; + + } + /** * writes a ISO-8859-1 string at the currentPosition * updates currentPosition but not realSize @@ -839,10 +913,10 @@ public class TTFSubSetFile extends TTFFile { private int getCheckSum(int start, int size) { - return (int)getLongCheckSum(start, size); + return (int)getLongCheckSum(output, start, size); } - private long getLongCheckSum(int start, int size) { + private static long getLongCheckSum(byte[] data, int start, int size) { // All the tables here are aligned on four byte boundaries // Add remainder to size if it's not a multiple of 4 int remainder = size % 4; @@ -853,10 +927,10 @@ public class TTFSubSetFile extends TTFFile { long sum = 0; for (int i = 0; i < size; i += 4) { - int l = (int)(output[start + i] << 24); - l += (int)(output[start + i + 1] << 16); - l += (int)(output[start + i + 2] << 16); - l += (int)(output[start + i + 3] << 16); + int l = (int)(data[start + i] << 24); + l += (int)(data[start + i + 1] << 16); + l += (int)(data[start + i + 2] << 16); + l += (int)(data[start + i + 3] << 16); sum += l; if (sum > 0xffffffff) { sum = sum - 0xffffffff; @@ -867,7 +941,7 @@ public class TTFSubSetFile extends TTFFile { } private void createCheckSumAdjustment() { - long sum = getLongCheckSum(0, realSize); + long sum = getLongCheckSum(output, 0, realSize); int checksum = (int)(0xb1b0afba - sum); writeULong(checkSumAdjustmentOffset, checksum); } diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index 8ff2a5567..1f6129dc0 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -43,6 +43,7 @@ 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.CIDFontType; import org.apache.fop.fonts.CIDSubset; import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.Font; @@ -243,7 +244,8 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { */ gen.includeProcsetCIDInitResource(); } - PSResource cidFontResource = embedCIDFont(gen, (MultiByteFont) tf, in); + PSResource cidFontResource = embedType2CIDFont(gen, + (MultiByteFont) tf, in); fontResource = PSFontResource.createFontResource(fontRes, gen.getProcsetCIDInitResource(), gen.getIdentityHCMapResource(), @@ -311,12 +313,12 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { gen.writeln("/FontType 42 def"); gen.writeln("/Encoding 256 array"); gen.writeln("0 1 255{1 index exch/.notdef put}for"); - Set glyphs = null; + Set glyphs = null; if (font.getFontType() == FontType.TYPE0) { //"/Encoding" is required but ignored for CID fonts //so we keep it minimal to save space } else { - glyphs = new java.util.HashSet(); + glyphs = new java.util.HashSet(); for (int i = 0; i < Glyphs.WINANSI_ENCODING.length; i++) { gen.write("dup "); gen.write(i); @@ -355,16 +357,14 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } gen.writeln("]def"); gen.write("/CharStrings "); - gen.write(1); - //gen.write(glyphs.size() + 1); + gen.write(glyphs != null ? glyphs.size() + 1 : 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 + gen.writeln(" 0 def"); // .notdef always has to be at index 0 if (glyphs != null) { - for (Iterator iter = glyphs.iterator(); iter.hasNext();) { - String glyphName = (String) iter.next(); + //Only performed in singly-byte mode + for (String glyphName : glyphs) { gen.write("/"); gen.write(glyphName); gen.write(" "); @@ -389,8 +389,8 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { return 0; } - private static void composeType0Font(PSGenerator gen, MultiByteFont font, InputStream fontStream) - throws IOException { + private static void composeType0Font(PSGenerator gen, MultiByteFont font, + InputStream fontStream) throws IOException { String psName = font.getEmbedFontName(); gen.write("/"); gen.write(psName); @@ -399,14 +399,9 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { gen.writeln("] composefont pop"); } - private static PSResource embedCIDFont(PSGenerator gen, + private static PSResource embedType2CIDFont(final PSGenerator gen, MultiByteFont font, InputStream fontStream) throws IOException { - FontFileReader reader = new FontFileReader(fontStream); - - TTFSubSetFile subset = new TTFSubSetFile(); - byte[] subsetFont = subset.readFont(reader, - font.getTTCName(), font.getUsedGlyphs()); - InputStream subsetInput = new java.io.ByteArrayInputStream(subsetFont); + assert font.getCIDType() == CIDFontType.CIDTYPE2; String psName = font.getEmbedFontName(); gen.write("%%BeginResource: CIDFont "); @@ -467,6 +462,25 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { gen.write(gid); } gen.writeln(">] def"); + + //Create tables for subset + TTFSubSetFile subset = new TTFSubSetFile(); + TTFSubSetFile.GlyphHandler glyphHandler = new TTFSubSetFile.GlyphHandler() { + + public void addGlyph(byte[] glyphData) throws IOException { + ASCIIHexOutputStream hexOut = new ASCIIHexOutputStream(gen.getOutputStream()); + gen.writeln("<"); + hexOut.write(glyphData); + gen.writeln(">"); + } + }; + gen.writeln("/GlyphDirectory ["); + FontFileReader reader = new FontFileReader(fontStream); + byte[] subsetFont = subset.toPostScriptSubset(reader, + font.getTTCName(), font.getUsedGlyphs(), glyphHandler); + gen.writeln("] def"); + + InputStream subsetInput = new java.io.ByteArrayInputStream(subsetFont); createType42DictionaryEntries(gen, font, subsetInput, Collections.EMPTY_LIST); gen.writeln("CIDFontName currentdict end /CIDFont defineresource pop"); gen.writeln("end"); -- cgit v1.2.3 From f133bab5a846c87a88eb697fee4b659122c46bdb Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Mon, 15 Nov 2010 15:31:38 +0000 Subject: Added full support for single-byte encodings when TTF fonts are embedded in PostScript. Deprecated MultiByteFont.setBFEntries() in favor of CustomFont.setCMap(). Added some TODO related to BFEntry and TTFCmapEntry essentially being the same class. Maybe we should rename BFEntry. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1035307 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/BFEntry.java | 3 + src/java/org/apache/fop/fonts/CustomFont.java | 24 +++++++ src/java/org/apache/fop/fonts/FontReader.java | 7 +- src/java/org/apache/fop/fonts/MultiByteFont.java | 29 ++++++--- src/java/org/apache/fop/fonts/SingleByteFont.java | 16 ++--- .../apache/fop/fonts/truetype/TTFCmapEntry.java | 4 ++ .../org/apache/fop/fonts/truetype/TTFFile.java | 42 ++++++------ .../apache/fop/fonts/truetype/TTFFontLoader.java | 26 ++++---- src/java/org/apache/fop/render/ps/PSFontUtils.java | 74 +++++++++++++--------- 9 files changed, 138 insertions(+), 87 deletions(-) diff --git a/src/java/org/apache/fop/fonts/BFEntry.java b/src/java/org/apache/fop/fonts/BFEntry.java index 4e0b169fd..c8311a9d2 100644 --- a/src/java/org/apache/fop/fonts/BFEntry.java +++ b/src/java/org/apache/fop/fonts/BFEntry.java @@ -24,6 +24,9 @@ package org.apache.fop.fonts; */ public class BFEntry { + //TODO Think about renaming this class to CMapRange or something. + //TODO Copy equals() and hashCode() from TTFCmapEntry + private int unicodeStart; private int unicodeEnd; private int glyphStartIndex; diff --git a/src/java/org/apache/fop/fonts/CustomFont.java b/src/java/org/apache/fop/fonts/CustomFont.java index 4cf24ae16..c3687a94e 100644 --- a/src/java/org/apache/fop/fonts/CustomFont.java +++ b/src/java/org/apache/fop/fonts/CustomFont.java @@ -59,6 +59,9 @@ public abstract class CustomFont extends Typeface private boolean useKerning = true; + /** the character map, mapping Unicode ranges to glyph indices. */ + protected BFEntry[] cmap; + /** {@inheritDoc} */ public String getFontName() { return fontName; @@ -454,4 +457,25 @@ public abstract class CustomFont extends Typeface } } + /** + * Sets the identity character map for this font. It maps all available Unicode characters + * to their glyph indices inside the font. + * @param cmap the identity character map + */ + public void setCMap(BFEntry[] cmap) { + this.cmap = new BFEntry[cmap.length]; + System.arraycopy(cmap, 0, this.cmap, 0, cmap.length); + } + + /** + * Returns the identity character map for this font. It maps all available Unicode characters + * to their glyph indices inside the font. + * @return the identity character map + */ + public BFEntry[] getCMap() { + BFEntry[] copy = new BFEntry[cmap.length]; + System.arraycopy(this.cmap, 0, copy, 0, this.cmap.length); + return copy; + } + } diff --git a/src/java/org/apache/fop/fonts/FontReader.java b/src/java/org/apache/fop/fonts/FontReader.java index 16da99baa..34da35f85 100644 --- a/src/java/org/apache/fop/fonts/FontReader.java +++ b/src/java/org/apache/fop/fonts/FontReader.java @@ -143,12 +143,14 @@ public class FontReader extends DefaultHandler { /** * {@inheritDoc} */ + @Override public void startDocument() { } /** * {@inheritDoc} */ + @Override public void setDocumentLocator(Locator locator) { this.locator = locator; } @@ -156,6 +158,7 @@ public class FontReader extends DefaultHandler { /** * {@inheritDoc} */ + @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (localName.equals("font-metrics")) { @@ -224,6 +227,7 @@ public class FontReader extends DefaultHandler { /** * {@inheritDoc} */ + @Override public void endElement(String uri, String localName, String qName) throws SAXException { String content = text.toString().trim(); if ("font-name".equals(localName)) { @@ -292,7 +296,7 @@ public class FontReader extends DefaultHandler { multiFont.setWidthArray(wds); } else if ("bfranges".equals(localName)) { - multiFont.setBFEntries((BFEntry[])bfranges.toArray(new BFEntry[0])); + multiFont.setCMap((BFEntry[])bfranges.toArray(new BFEntry[0])); } text.setLength(0); //Reset text buffer (see characters()) } @@ -300,6 +304,7 @@ public class FontReader extends DefaultHandler { /** * {@inheritDoc} */ + @Override public void characters(char[] ch, int start, int length) { text.append(ch, start, length); } diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java index b3b5d8639..e285fa068 100644 --- a/src/java/org/apache/fop/fonts/MultiByteFont.java +++ b/src/java/org/apache/fop/fonts/MultiByteFont.java @@ -41,9 +41,6 @@ public class MultiByteFont extends CIDFont { private CIDSubset subset = new CIDSubset(); - /** A map from Unicode indices to glyph indices */ - private BFEntry[] bfentries = null; - /** * Default constructor */ @@ -74,26 +71,31 @@ public class MultiByteFont extends CIDFont { } /** {@inheritDoc} */ + @Override public int getDefaultWidth() { return defaultWidth; } /** {@inheritDoc} */ + @Override public String getRegistry() { return "Adobe"; } /** {@inheritDoc} */ + @Override public String getOrdering() { return "UCS"; } /** {@inheritDoc} */ + @Override public int getSupplement() { return 0; } /** {@inheritDoc} */ + @Override public CIDFontType getCIDType() { return cidType; } @@ -111,6 +113,7 @@ public class MultiByteFont extends CIDFont { } /** {@inheritDoc} */ + @Override public String getEmbedFontName() { if (isEmbeddable()) { return getPrefixedFontName(); @@ -125,11 +128,13 @@ public class MultiByteFont extends CIDFont { } /** {@inheritDoc} */ + @Override public CIDSubset getCIDSubset() { return this.subset; } /** {@inheritDoc} */ + @Override public String getEncodingName() { return encoding; } @@ -158,22 +163,23 @@ public class MultiByteFont extends CIDFont { * @return the glyph index (or 0 if the glyph is not available) */ private int findGlyphIndex(char c) { - int idx = (int)c; + int idx = c; int retIdx = SingleByteEncoding.NOT_FOUND_CODE_POINT; - for (int i = 0; (i < bfentries.length) && retIdx == 0; i++) { - if (bfentries[i].getUnicodeStart() <= idx - && bfentries[i].getUnicodeEnd() >= idx) { + for (int i = 0; (i < cmap.length) && retIdx == 0; i++) { + if (cmap[i].getUnicodeStart() <= idx + && cmap[i].getUnicodeEnd() >= idx) { - retIdx = bfentries[i].getGlyphStartIndex() + retIdx = cmap[i].getGlyphStartIndex() + idx - - bfentries[i].getUnicodeStart(); + - cmap[i].getUnicodeStart(); } } return retIdx; } /** {@inheritDoc} */ + @Override public char mapChar(char c) { notifyMapOperation(); int glyphIndex = findGlyphIndex(c); @@ -188,6 +194,7 @@ public class MultiByteFont extends CIDFont { } /** {@inheritDoc} */ + @Override public boolean hasChar(char c) { return (findGlyphIndex(c) != SingleByteEncoding.NOT_FOUND_CODE_POINT); } @@ -196,9 +203,11 @@ public class MultiByteFont extends CIDFont { * Sets the array of BFEntry instances which constitutes the Unicode to glyph index map for * a font. ("BF" means "base font") * @param entries the Unicode to glyph index map + * @deprecated use {@link #setCMap(BFEntry[])} instead */ + @Deprecated public void setBFEntries(BFEntry[] entries) { - this.bfentries = entries; + setCMap(entries); } /** diff --git a/src/java/org/apache/fop/fonts/SingleByteFont.java b/src/java/org/apache/fop/fonts/SingleByteFont.java index a09c81670..7f103b134 100644 --- a/src/java/org/apache/fop/fonts/SingleByteFont.java +++ b/src/java/org/apache/fop/fonts/SingleByteFont.java @@ -46,8 +46,6 @@ public class SingleByteFont extends CustomFont { //Map private List additionalEncodings; - private List cmaps; - private PostScriptVersion ttPostScriptVersion; /** @@ -64,6 +62,7 @@ public class SingleByteFont extends CustomFont { } /** {@inheritDoc} */ + @Override public String getEncodingName() { return this.mapping.getName(); } @@ -104,6 +103,7 @@ public class SingleByteFont extends CustomFont { } /** {@inheritDoc} */ + @Override public char mapChar(char c) { notifyMapOperation(); char d = mapping.mapChar(c); @@ -155,6 +155,7 @@ public class SingleByteFont extends CustomFont { } /** {@inheritDoc} */ + @Override public boolean hasChar(char c) { char d = mapping.mapChar(c); if (d != SingleByteEncoding.NOT_FOUND_CODE_POINT) { @@ -334,6 +335,7 @@ public class SingleByteFont extends CustomFont { } /** {@inheritDoc} */ + @Override public String toString() { return getCharacter().toString(); } @@ -360,15 +362,5 @@ public class SingleByteFont extends CustomFont { return ttPostScriptVersion; } - /** TODO remove */ - public void setCMaps(List cmaps) { - this.cmaps = cmaps; - } - - /** TODO remove */ - public List getCMaps() { - return cmaps; - } - } diff --git a/src/java/org/apache/fop/fonts/truetype/TTFCmapEntry.java b/src/java/org/apache/fop/fonts/truetype/TTFCmapEntry.java index 897d5e2de..a63f76def 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFCmapEntry.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFCmapEntry.java @@ -25,6 +25,8 @@ package org.apache.fop.fonts.truetype; */ public class TTFCmapEntry { + //TODO this class is redundant: BFEntry does the same but doesn't have an intuitive name + private int unicodeStart; private int unicodeEnd; private int glyphStartIndex; @@ -44,6 +46,7 @@ public class TTFCmapEntry { /** * {@inheritDoc} */ + @Override public int hashCode() { int hc = super.hashCode(); hc ^= ( hc * 11 ) + unicodeStart; @@ -55,6 +58,7 @@ public class TTFCmapEntry { /** * {@inheritDoc} */ + @Override public boolean equals(Object o) { if (o instanceof TTFCmapEntry) { TTFCmapEntry ce = (TTFCmapEntry)o; diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java index 6f3bb9f49..c288b2586 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java @@ -143,7 +143,7 @@ public class TTFFile { protected Map dirTabs; private Map kerningTab; // for CIDs private Map ansiKerningTab; // For winAnsiEncoding - private List cmaps; + private List cmaps; private List unicodeMapping; private int upem; // unitsPerEm from "head" table @@ -597,7 +597,7 @@ public class TTFFile { ansiIndex = new java.util.HashMap(); for (int i = 32; i < Glyphs.WINANSI_ENCODING.length; i++) { Integer ansi = new Integer(i); - Integer uni = new Integer((int)Glyphs.WINANSI_ENCODING[i]); + Integer uni = new Integer(Glyphs.WINANSI_ENCODING[i]); List v = (List)ansiIndex.get(uni); if (v == null) { @@ -669,7 +669,7 @@ public class TTFFile { } private void createCMaps() { - cmaps = new java.util.ArrayList(); + this.cmaps = new java.util.ArrayList(); TTFCmapEntry tce = new TTFCmapEntry(); Iterator e = unicodeMapping.listIterator(); @@ -750,7 +750,7 @@ public class TTFFile { * @return int The CapHeight */ public int getCapHeight() { - return (int)convertTTFUnit2PDFUnit(capHeight); + return convertTTFUnit2PDFUnit(capHeight); } /** @@ -758,7 +758,7 @@ public class TTFFile { * @return int The XHeight */ public int getXHeight() { - return (int)convertTTFUnit2PDFUnit(xHeight); + return convertTTFUnit2PDFUnit(xHeight); } /** @@ -817,10 +817,10 @@ public class TTFFile { */ public int[] getFontBBox() { final int[] fbb = new int[4]; - fbb[0] = (int)convertTTFUnit2PDFUnit(fontBBox1); - fbb[1] = (int)convertTTFUnit2PDFUnit(fontBBox2); - fbb[2] = (int)convertTTFUnit2PDFUnit(fontBBox3); - fbb[3] = (int)convertTTFUnit2PDFUnit(fontBBox4); + fbb[0] = convertTTFUnit2PDFUnit(fontBBox1); + fbb[1] = convertTTFUnit2PDFUnit(fontBBox2); + fbb[2] = convertTTFUnit2PDFUnit(fontBBox3); + fbb[3] = convertTTFUnit2PDFUnit(fontBBox4); return fbb; } @@ -830,7 +830,7 @@ public class TTFFile { * @return int The LowerCaseAscent */ public int getLowerCaseAscent() { - return (int)convertTTFUnit2PDFUnit(ascender); + return convertTTFUnit2PDFUnit(ascender); } /** @@ -838,7 +838,7 @@ public class TTFFile { * @return int The LowerCaseDescent */ public int getLowerCaseDescent() { - return (int)convertTTFUnit2PDFUnit(descender); + return convertTTFUnit2PDFUnit(descender); } /** @@ -865,7 +865,7 @@ public class TTFFile { public int[] getWidths() { int[] wx = new int[mtxTab.length]; for (int i = 0; i < wx.length; i++) { - wx[i] = (int)convertTTFUnit2PDFUnit(mtxTab[i].getWx()); + wx[i] = convertTTFUnit2PDFUnit(mtxTab[i].getWx()); } return wx; @@ -877,7 +877,7 @@ public class TTFFile { * @return int Standard width */ public int getCharWidth(int idx) { - return (int)convertTTFUnit2PDFUnit(ansiWidth[idx]); + return convertTTFUnit2PDFUnit(ansiWidth[idx]); } /** @@ -1557,7 +1557,7 @@ public class TTFFile { if (adjTab == null) { adjTab = new java.util.HashMap(); } - adjTab.put(u2, new Integer((int)convertTTFUnit2PDFUnit(kpx))); + adjTab.put(u2, new Integer(convertTTFUnit2PDFUnit(kpx))); kerningTab.put(iObj, adjTab); } } @@ -1608,7 +1608,7 @@ public class TTFFile { * Return a List with TTFCmapEntry. * @return A list of TTFCmapEntry objects */ - public List getCMaps() { + public List getCMaps() { return cmaps; } @@ -1753,8 +1753,8 @@ public class TTFFile { System.out.println("Family name: " + familyNames); System.out.println("Subfamily name: " + subFamilyName); System.out.println("Notice: " + notice); - System.out.println("xHeight: " + (int)convertTTFUnit2PDFUnit(xHeight)); - System.out.println("capheight: " + (int)convertTTFUnit2PDFUnit(capHeight)); + System.out.println("xHeight: " + convertTTFUnit2PDFUnit(xHeight)); + System.out.println("capheight: " + convertTTFUnit2PDFUnit(capHeight)); int italic = (int)(italicAngle >> 16); System.out.println("Italic: " + italic); @@ -1767,10 +1767,10 @@ public class TTFFile { System.out.println(); System.out.println("Ascender: " + convertTTFUnit2PDFUnit(ascender)); System.out.println("Descender: " + convertTTFUnit2PDFUnit(descender)); - System.out.println("FontBBox: [" + (int)convertTTFUnit2PDFUnit(fontBBox1) - + " " + (int)convertTTFUnit2PDFUnit(fontBBox2) + " " - + (int)convertTTFUnit2PDFUnit(fontBBox3) + " " - + (int)convertTTFUnit2PDFUnit(fontBBox4) + "]"); + System.out.println("FontBBox: [" + convertTTFUnit2PDFUnit(fontBBox1) + + " " + convertTTFUnit2PDFUnit(fontBBox2) + " " + + convertTTFUnit2PDFUnit(fontBBox3) + " " + + convertTTFUnit2PDFUnit(fontBBox4) + "]"); } private String formatUnitsForDebug(int units) { diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index cf24ea352..011f444cd 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -80,6 +80,7 @@ public class TTFFontLoader extends FontLoader { } /** {@inheritDoc} */ + @Override protected void read() throws IOException { read(this.subFontName); } @@ -147,26 +148,15 @@ public class TTFFontLoader extends FontLoader { multiFont.setCIDType(CIDFontType.CIDTYPE2); int[] wx = ttf.getWidths(); multiFont.setWidthArray(wx); - List entries = ttf.getCMaps(); - BFEntry[] bfentries = new BFEntry[entries.size()]; - int pos = 0; - Iterator iter = ttf.getCMaps().listIterator(); - while (iter.hasNext()) { - TTFCmapEntry ce = (TTFCmapEntry)iter.next(); - bfentries[pos] = new BFEntry(ce.getUnicodeStart(), ce.getUnicodeEnd(), - ce.getGlyphStartIndex()); - pos++; - } - multiFont.setBFEntries(bfentries); } else { singleFont.setFontType(FontType.TRUETYPE); singleFont.setEncoding(ttf.getCharSetName()); returnFont.setFirstChar(ttf.getFirstChar()); returnFont.setLastChar(ttf.getLastChar()); - singleFont.setCMaps(ttf.getCMaps()); singleFont.setTrueTypePostScriptVersion(ttf.getPostScriptVersion()); copyWidthsSingleByte(ttf); } + returnFont.setCMap(getCMap(ttf)); if (useKerning) { copyKerning(ttf, isCid); @@ -176,6 +166,18 @@ public class TTFFontLoader extends FontLoader { } } + private BFEntry[] getCMap(TTFFile ttf) { + List entries = ttf.getCMaps(); + BFEntry[] bfentries = new BFEntry[entries.size()]; + int pos = 0; + for (TTFCmapEntry ce : ttf.getCMaps()) { + bfentries[pos] = new BFEntry(ce.getUnicodeStart(), ce.getUnicodeEnd(), + ce.getGlyphStartIndex()); + pos++; + } + return bfentries; + } + private void copyWidthsSingleByte(TTFFile ttf) { int[] wx = ttf.getWidths(); for (int i = singleFont.getFirstChar(); i <= singleFont.getLastChar(); i++) { diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index 1f6129dc0..3cdfdfd4d 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -23,11 +23,8 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; -import java.util.Collections; import java.util.Iterator; -import java.util.List; import java.util.Map; -import java.util.Set; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; @@ -42,6 +39,7 @@ import org.apache.xmlgraphics.ps.PSResource; import org.apache.xmlgraphics.ps.dsc.ResourceTracker; import org.apache.xmlgraphics.util.io.ASCIIHexOutputStream; +import org.apache.fop.fonts.BFEntry; import org.apache.fop.fonts.Base14Font; import org.apache.fop.fonts.CIDFontType; import org.apache.fop.fonts.CIDSubset; @@ -55,7 +53,6 @@ import org.apache.fop.fonts.SingleByteEncoding; import org.apache.fop.fonts.SingleByteFont; import org.apache.fop.fonts.Typeface; import org.apache.fop.fonts.truetype.FontFileReader; -import org.apache.fop.fonts.truetype.TTFCmapEntry; import org.apache.fop.fonts.truetype.TTFSubSetFile; import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; import org.apache.fop.util.HexEncoder; @@ -152,7 +149,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { && sbf.getTrueTypePostScriptVersion() != PostScriptVersion.V2) { derivedFontRes = defineDerivedTrueTypeFont(gen, eventProducer, tf.getEmbedFontName(), tf.getEmbedFontName() + postFix, encoding, - sbf.getCMaps()); + sbf.getCMap()); } else { derivedFontRes = defineDerivedFont(gen, tf.getEmbedFontName(), tf.getEmbedFontName() + postFix, encoding.getName()); @@ -298,12 +295,12 @@ 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()); + createType42DictionaryEntries(gen, font, fontStream, font.getCMap()); gen.writeln("FontName currentdict end definefont pop"); } private static void createType42DictionaryEntries(PSGenerator gen, CustomFont font, - InputStream fontStream, List cmaps) throws IOException { + InputStream fontStream, BFEntry[] cmap) throws IOException { gen.write("/FontName /"); gen.write(font.getEmbedFontName()); gen.writeln(" def"); @@ -313,12 +310,13 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { gen.writeln("/FontType 42 def"); gen.writeln("/Encoding 256 array"); gen.writeln("0 1 255{1 index exch/.notdef put}for"); - Set glyphs = null; + boolean buildCharStrings; if (font.getFontType() == FontType.TYPE0) { //"/Encoding" is required but ignored for CID fonts //so we keep it minimal to save space + buildCharStrings = false; } else { - glyphs = new java.util.HashSet(); + buildCharStrings = true; for (int i = 0; i < Glyphs.WINANSI_ENCODING.length; i++) { gen.write("dup "); gen.write(i); @@ -327,7 +325,6 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { if (glyphName.equals("")) { gen.write(Glyphs.NOTDEF); } else { - glyphs.add(glyphName); //TODO don't just register the WinAnsi subset! gen.write(glyphName); } gen.writeln(" put"); @@ -357,33 +354,48 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } gen.writeln("]def"); gen.write("/CharStrings "); - gen.write(glyphs != null ? glyphs.size() + 1 : 1); + if (buildCharStrings) { + int charCount = 1; //1 for .notdef + for (BFEntry entry : cmap) { + charCount += entry.getUnicodeEnd() - entry.getUnicodeStart() + 1; + } + gen.write(charCount); + } else { + gen.write(1); + } gen.writeln(" dict dup begin"); gen.write("/"); gen.write(Glyphs.NOTDEF); gen.writeln(" 0 def"); // .notdef always has to be at index 0 - if (glyphs != null) { - //Only performed in singly-byte mode - for (String glyphName : glyphs) { - gen.write("/"); - gen.write(glyphName); - gen.write(" "); - gen.write(getGlyphIndex(glyphName, cmaps)); - gen.writeln(" def"); + if (buildCharStrings) { + //Only performed in singly-byte mode, ignored for CID fonts + + for (BFEntry entry : cmap) { + int glyphIndex = entry.getGlyphStartIndex(); + for (int ch = entry.getUnicodeStart(); ch <= entry.getUnicodeEnd(); ch++) { + char ch16 = (char)ch; //TODO Handle Unicode characters beyond 16bit + String glyphName = Glyphs.charToGlyphName(ch16); + + if ("".equals(glyphName)) { + glyphName = "u" + Integer.toHexString(ch).toUpperCase(); + } + gen.write("/"); + gen.write(glyphName); + gen.write(" "); + gen.write(glyphIndex); + gen.writeln(" def"); + + glyphIndex++; + } } } gen.writeln("end readonly def"); } - private static int getGlyphIndex(String glyphName, List cmaps) { - return getGlyphIndex(Glyphs.getUnicodeSequenceForGlyphName(glyphName).charAt(0), cmaps); - } - - private static int getGlyphIndex(char c, List cmaps) { - for (Iterator iter = cmaps.iterator(); iter.hasNext();) { - TTFCmapEntry cmap = (TTFCmapEntry) iter.next(); - if (cmap.getUnicodeStart() <= c && c <= cmap.getUnicodeEnd()) { - return cmap.getGlyphStartIndex() + c - cmap.getUnicodeStart(); + private static int getGlyphIndex(char c, BFEntry[] cmap) { + for (BFEntry entry : cmap) { + if (entry.getUnicodeStart() <= c && c <= entry.getUnicodeEnd()) { + return entry.getGlyphStartIndex() + c - entry.getUnicodeStart(); } } return 0; @@ -481,7 +493,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { gen.writeln("] def"); InputStream subsetInput = new java.io.ByteArrayInputStream(subsetFont); - createType42DictionaryEntries(gen, font, subsetInput, Collections.EMPTY_LIST); + createType42DictionaryEntries(gen, font, subsetInput, new BFEntry[0]); gen.writeln("CIDFontName currentdict end /CIDFont defineresource pop"); gen.writeln("end"); gen.writeln("%%EndResource"); @@ -659,7 +671,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { private static PSResource defineDerivedTrueTypeFont(PSGenerator gen, PSEventProducer eventProducer, String baseFontName, String fontName, - SingleByteEncoding encoding, List cmaps) throws IOException { + SingleByteEncoding encoding, BFEntry[] cmap) throws IOException { checkPostScriptLevel3(gen, eventProducer); PSResource res = new PSResource(PSResource.TYPE_FONT, fontName); gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, res); @@ -682,7 +694,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { if (glyphName.equals(".notdef")) { gen.write(0); } else { - gen.write(getGlyphIndex(unicodeCharMap[i], cmaps)); + gen.write(getGlyphIndex(unicodeCharMap[i], cmap)); } gen.writeln(" def"); } -- cgit v1.2.3 From a42084359926741824e490653c1e5957af5ead74 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Mon, 15 Nov 2010 15:35:12 +0000 Subject: Added semicolon for enum to avoid problems with qdox and Maven. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1035313 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/fonts/truetype/TTFSubSetFile.java | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java index 7614a267b..ec9a51256 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java @@ -35,7 +35,7 @@ import java.util.Map; public class TTFSubSetFile extends TTFFile { private static enum OperatingMode { - PDF, POSTSCRIPT_GLYPH_DIRECTORY + PDF, POSTSCRIPT_GLYPH_DIRECTORY; } private byte[] output = null; @@ -869,15 +869,15 @@ public class TTFSubSetFile extends TTFFile { * Read a unsigned short value at given position */ private int readUShort(int pos) { - int ret = (int)output[pos]; + int ret = output[pos]; if (ret < 0) { ret += 256; } ret = ret << 8; - if ((int)output[pos + 1] < 0) { - ret |= (int)output[pos + 1] + 256; + if (output[pos + 1] < 0) { + ret |= output[pos + 1] + 256; } else { - ret |= (int)output[pos + 1]; + ret |= output[pos + 1]; } return ret; @@ -900,7 +900,7 @@ public class TTFSubSetFile extends TTFFile { */ private int maxPow2(int max) { int i = 0; - while (Math.pow(2, (double)i) < max) { + while (Math.pow(2, i) < max) { i++; } @@ -908,7 +908,7 @@ public class TTFSubSetFile extends TTFFile { } private int log2(int num) { - return (int)(Math.log((double)num) / Math.log(2)); + return (int)(Math.log(num) / Math.log(2)); } @@ -927,10 +927,10 @@ public class TTFSubSetFile extends TTFFile { long sum = 0; for (int i = 0; i < size; i += 4) { - int l = (int)(data[start + i] << 24); - l += (int)(data[start + i + 1] << 16); - l += (int)(data[start + i + 2] << 16); - l += (int)(data[start + i + 3] << 16); + int l = (data[start + i] << 24); + l += (data[start + i + 1] << 16); + l += (data[start + i + 2] << 16); + l += (data[start + i + 3] << 16); sum += l; if (sum > 0xffffffff) { sum = sum - 0xffffffff; -- cgit v1.2.3 From 7c8f02c57302d672fe4d0a8fc5332af6d9f0e610 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Fri, 30 Mar 2012 19:09:29 +0000 Subject: Bugzilla #50483: Improved support for TrueType fonts in PostScript Refactored code and added unit tests Patch by Mehdi Houshmand git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1307574 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 15 +- .../fop/tools/EventProducerCollectorTask.java | 8 +- src/java/org/apache/fop/fonts/BFEntry.java | 35 +- src/java/org/apache/fop/fonts/CustomFont.java | 18 +- .../org/apache/fop/fonts/CustomFontCollection.java | 2 +- src/java/org/apache/fop/fonts/EmbedFontInfo.java | 23 + src/java/org/apache/fop/fonts/EmbeddingMode.java | 56 ++ src/java/org/apache/fop/fonts/EncodingMode.java | 2 +- .../org/apache/fop/fonts/FontInfoConfigurator.java | 6 +- src/java/org/apache/fop/fonts/FontLoader.java | 23 +- src/java/org/apache/fop/fonts/LazyFont.java | 11 +- src/java/org/apache/fop/fonts/MutableFont.java | 6 + src/java/org/apache/fop/fonts/apps/TTFReader.java | 30 +- .../fop/fonts/autodetect/FontInfoFinder.java | 7 +- .../apache/fop/fonts/truetype/FontFileReader.java | 29 +- .../apache/fop/fonts/truetype/TTFCmapEntry.java | 122 ----- .../apache/fop/fonts/truetype/TTFDirTabEntry.java | 8 + .../org/apache/fop/fonts/truetype/TTFFile.java | 587 ++++++++++++--------- .../apache/fop/fonts/truetype/TTFFontLoader.java | 36 +- .../fop/fonts/truetype/TTFGlyphOutputStream.java | 48 ++ .../apache/fop/fonts/truetype/TTFOutputStream.java | 51 ++ .../apache/fop/fonts/truetype/TTFSubSetFile.java | 532 ++++++++----------- .../apache/fop/fonts/truetype/TTFTableName.java | 158 ++++++ .../fop/fonts/truetype/TTFTableOutputStream.java | 37 ++ src/java/org/apache/fop/pdf/PDFFactory.java | 8 +- .../render/java2d/ConfiguredFontCollection.java | 5 +- src/java/org/apache/fop/render/ps/PSFontUtils.java | 234 ++++---- src/java/org/apache/fop/render/ps/PSPainter.java | 53 +- .../apache/fop/render/ps/fonts/PSTTFGenerator.java | 104 ++++ .../render/ps/fonts/PSTTFGlyphOutputStream.java | 72 +++ .../fop/render/ps/fonts/PSTTFOutputStream.java | 64 +++ .../render/ps/fonts/PSTTFTableOutputStream.java | 58 ++ .../org/apache/fop/fonts/DejaVuLGCSerifTest.java | 4 +- .../org/apache/fop/fonts/EncodingModeTest.java | 23 +- .../org/apache/fop/fonts/FOPFontsTestSuite.java | 54 ++ .../fop/fonts/truetype/FontFileReaderTest.java | 283 ++++++++++ .../org/apache/fop/fonts/truetype/TTFFileTest.java | 399 ++++++++++++++ .../fop/fonts/truetype/TTFSubSetFileTest.java | 69 +++ .../fop/fonts/truetype/TTFTableNameTest.java | 145 +++++ .../apache/fop/render/ps/RenderPSTestSuite.java | 55 ++ .../fop/render/ps/fonts/PSTTFGeneratorTest.java | 111 ++++ .../ps/fonts/PSTTFGlyphOutputStreamTest.java | 105 ++++ .../fop/render/ps/fonts/PSTTFOutputStreamTest.java | 82 +++ .../ps/fonts/PSTTFTableOutputStreamTest.java | 86 +++ test/resources/fonts/DroidSansMono.LICENSE | 18 + 45 files changed, 2952 insertions(+), 930 deletions(-) create mode 100644 src/java/org/apache/fop/fonts/EmbeddingMode.java delete mode 100644 src/java/org/apache/fop/fonts/truetype/TTFCmapEntry.java create mode 100644 src/java/org/apache/fop/fonts/truetype/TTFGlyphOutputStream.java create mode 100644 src/java/org/apache/fop/fonts/truetype/TTFOutputStream.java create mode 100644 src/java/org/apache/fop/fonts/truetype/TTFTableName.java create mode 100644 src/java/org/apache/fop/fonts/truetype/TTFTableOutputStream.java create mode 100644 src/java/org/apache/fop/render/ps/fonts/PSTTFGenerator.java create mode 100644 src/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStream.java create mode 100644 src/java/org/apache/fop/render/ps/fonts/PSTTFOutputStream.java create mode 100644 src/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStream.java create mode 100644 test/java/org/apache/fop/fonts/FOPFontsTestSuite.java create mode 100644 test/java/org/apache/fop/fonts/truetype/FontFileReaderTest.java create mode 100644 test/java/org/apache/fop/fonts/truetype/TTFFileTest.java create mode 100644 test/java/org/apache/fop/fonts/truetype/TTFSubSetFileTest.java create mode 100644 test/java/org/apache/fop/fonts/truetype/TTFTableNameTest.java create mode 100644 test/java/org/apache/fop/render/ps/RenderPSTestSuite.java create mode 100644 test/java/org/apache/fop/render/ps/fonts/PSTTFGeneratorTest.java create mode 100644 test/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStreamTest.java create mode 100644 test/java/org/apache/fop/render/ps/fonts/PSTTFOutputStreamTest.java create mode 100644 test/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStreamTest.java create mode 100644 test/resources/fonts/DroidSansMono.LICENSE diff --git a/build.xml b/build.xml index bc515dff0..41823745d 100644 --- a/build.xml +++ b/build.xml @@ -90,7 +90,10 @@ list of possible build targets. - + + + + @@ -944,7 +947,15 @@ list of possible build targets. - + + + + + + + + + diff --git a/src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java b/src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java index 6786e43f0..0945c52bb 100644 --- a/src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java +++ b/src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java @@ -37,18 +37,16 @@ import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; -import org.w3c.dom.Node; - import org.apache.commons.io.IOUtils; +import org.apache.fop.events.model.EventModel; +import org.apache.fop.events.model.EventProducerModel; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.selectors.FilenameSelector; - -import org.apache.fop.events.model.EventModel; -import org.apache.fop.events.model.EventProducerModel; +import org.w3c.dom.Node; /** * Ant task which inspects a file set for Java interfaces which extend the diff --git a/src/java/org/apache/fop/fonts/BFEntry.java b/src/java/org/apache/fop/fonts/BFEntry.java index c8311a9d2..654c1952b 100644 --- a/src/java/org/apache/fop/fonts/BFEntry.java +++ b/src/java/org/apache/fop/fonts/BFEntry.java @@ -22,14 +22,13 @@ package org.apache.fop.fonts; /** * This is just a holder class for bfentries, groups of characters of a base font (bf). */ -public class BFEntry { +public final class BFEntry { //TODO Think about renaming this class to CMapRange or something. - //TODO Copy equals() and hashCode() from TTFCmapEntry - private int unicodeStart; - private int unicodeEnd; - private int glyphStartIndex; + private final int unicodeStart; + private final int unicodeEnd; + private final int glyphStartIndex; /** * Main constructor. @@ -43,6 +42,32 @@ public class BFEntry { this.glyphStartIndex = glyphStartIndex; } + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int hc = 17; + hc = 31 * hc + unicodeStart; + hc = 31 * hc + unicodeEnd; + hc = 31 * hc + glyphStartIndex; + return hc; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object o) { + if (o instanceof BFEntry) { + BFEntry ce = (BFEntry) o; + return ce.unicodeStart == this.unicodeStart + && ce.unicodeEnd == this.unicodeEnd + && ce.glyphStartIndex == this.glyphStartIndex; + } + return false; + } + /** * Returns the unicodeStart. * @return the Unicode start index diff --git a/src/java/org/apache/fop/fonts/CustomFont.java b/src/java/org/apache/fop/fonts/CustomFont.java index bc64e0f33..a7b630578 100644 --- a/src/java/org/apache/fop/fonts/CustomFont.java +++ b/src/java/org/apache/fop/fonts/CustomFont.java @@ -42,6 +42,7 @@ public abstract class CustomFont extends Typeface private String embedFileName = null; private String embedResourceName = null; private FontResolver resolver = null; + private EmbeddingMode embeddingMode = EmbeddingMode.AUTO; private int capHeight = 0; private int xHeight = 0; @@ -113,6 +114,14 @@ public abstract class CustomFont extends Typeface return embedFileName; } + /** + * Returns the embedding mode for this font. + * @return embedding mode + */ + public EmbeddingMode getEmbeddingMode() { + return embeddingMode; + } + /** * Returns a Source representing an embeddable font file. * @return Source for an embeddable font file @@ -262,7 +271,7 @@ public abstract class CustomFont extends Typeface return lastChar; } - /** + /**MutableFont * Used to determine if kerning is enabled. * @return True if kerning is enabled. */ @@ -327,6 +336,13 @@ public abstract class CustomFont extends Typeface this.embedResourceName = name; } + /** + * {@inheritDoc} + */ + public void setEmbeddingMode(EmbeddingMode embeddingMode) { + this.embeddingMode = embeddingMode; + } + /** * {@inheritDoc} */ diff --git a/src/java/org/apache/fop/fonts/CustomFontCollection.java b/src/java/org/apache/fop/fonts/CustomFontCollection.java index 9f98814a3..3bd1fa7c7 100644 --- a/src/java/org/apache/fop/fonts/CustomFontCollection.java +++ b/src/java/org/apache/fop/fonts/CustomFontCollection.java @@ -71,7 +71,7 @@ public class CustomFontCollection implements FontCollection { List triplets = embedFontInfo.getFontTriplets(); for (int tripletIndex = 0; tripletIndex < triplets.size(); tripletIndex++) { - FontTriplet triplet = (FontTriplet) triplets.get(tripletIndex); + FontTriplet triplet = triplets.get(tripletIndex); fontInfo.addFontProperties(internalName, triplet); } } diff --git a/src/java/org/apache/fop/fonts/EmbedFontInfo.java b/src/java/org/apache/fop/fonts/EmbedFontInfo.java index b53cdfdd6..2bc8bb452 100644 --- a/src/java/org/apache/fop/fonts/EmbedFontInfo.java +++ b/src/java/org/apache/fop/fonts/EmbedFontInfo.java @@ -25,6 +25,8 @@ import java.util.List; /** * FontInfo contains meta information on fonts (where is the metrics file etc.) + * TODO: We need to remove this class and think about more intelligent design patterns + * (Data classes => Procedural code) */ public class EmbedFontInfo implements Serializable { @@ -39,6 +41,8 @@ public class EmbedFontInfo implements Serializable { protected boolean kerning; /** the requested encoding mode for the font */ protected EncodingMode encodingMode = EncodingMode.AUTO; + /** the requested embedding mode for this font */ + protected EmbeddingMode embeddingMode = EmbeddingMode.AUTO; /** the PostScript name of the font */ protected String postScriptName = null; @@ -136,6 +140,14 @@ public class EmbedFontInfo implements Serializable { } } + /** + * Returns the embedding mode for this font. + * @return the embedding mode. + */ + public EmbeddingMode getEmbeddingMode() { + return embeddingMode; + } + /** * Defines whether the font is embedded or not. * @param value true to embed the font, false to reference it @@ -163,6 +175,17 @@ public class EmbedFontInfo implements Serializable { this.encodingMode = mode; } + /** + * Sets the embedding mode for this font, currently not supported for type1 fonts. + * @param embeddingMode the new embedding mode. + */ + public void setEmbeddingMode(EmbeddingMode embeddingMode) { + if (embeddingMode == null) { + throw new NullPointerException("embeddingMode must not be null"); + } + this.embeddingMode = embeddingMode; + } + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); diff --git a/src/java/org/apache/fop/fonts/EmbeddingMode.java b/src/java/org/apache/fop/fonts/EmbeddingMode.java new file mode 100644 index 000000000..89f56cfd7 --- /dev/null +++ b/src/java/org/apache/fop/fonts/EmbeddingMode.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts; + +/** + * This enumerates the embedding mode of fonts; full; subset; auto (auto defaults to full for + * type1 fonts and subset for truetype fonts. + */ +public enum EmbeddingMode { + /** Default option: assumes FULL for type1 fonts and SUBSET for truetype fonts. */ + AUTO, + /** Full font embedding: This means the whole of the font is written to file. */ + FULL, + /** Subset font embedding: Only the mandatory tables and a subset of glyphs are written + * to file.*/ + SUBSET; + + /** + * Returns the name of this embedding mode. + * @return String - lower case. + */ + public String getName() { + return this.toString().toLowerCase(); + } + + /** + * Returns {@link EmbeddingMode} by name. + * @param value String - the name of the embedding mode (not case sensitive). + * @return embedding mode constant. + */ + public static EmbeddingMode getValue(String value) { + for (EmbeddingMode mode : EmbeddingMode.values()) { + if (mode.toString().equalsIgnoreCase(value)) { + return mode; + } + } + throw new IllegalArgumentException("Invalid embedding-mode: " + value); + } +} diff --git a/src/java/org/apache/fop/fonts/EncodingMode.java b/src/java/org/apache/fop/fonts/EncodingMode.java index 8a40d6593..78ffb7ac6 100644 --- a/src/java/org/apache/fop/fonts/EncodingMode.java +++ b/src/java/org/apache/fop/fonts/EncodingMode.java @@ -52,7 +52,7 @@ public enum EncodingMode { * @param name the name of the encoding mode to look up * @return the encoding mode constant */ - public static EncodingMode getEncodingMode(String name) { + public static EncodingMode getValue(String name) { for (EncodingMode em : EncodingMode.values()) { if (name.equalsIgnoreCase(em.getName())) { return em; diff --git a/src/java/org/apache/fop/fonts/FontInfoConfigurator.java b/src/java/org/apache/fop/fonts/FontInfoConfigurator.java index 67bb2e295..bf4c01453 100644 --- a/src/java/org/apache/fop/fonts/FontInfoConfigurator.java +++ b/src/java/org/apache/fop/fonts/FontInfoConfigurator.java @@ -251,11 +251,15 @@ public class FontInfoConfigurator { } boolean useKerning = fontCfg.getAttributeAsBoolean("kerning", true); - EncodingMode encodingMode = EncodingMode.getEncodingMode( + EncodingMode encodingMode = EncodingMode.getValue( fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName())); + EmbeddingMode embeddingMode = EmbeddingMode.getValue( + fontCfg.getAttribute("embedding-mode", EmbeddingMode.AUTO.toString())); EmbedFontInfo embedFontInfo = new EmbedFontInfo(metricsUrl, useKerning, tripletList, embedUrl, subFont); embedFontInfo.setEncodingMode(encodingMode); + embedFontInfo.setEmbeddingMode(embeddingMode); + if (fontCache != null) { if (!fontCache.containsFont(embedFontInfo)) { fontCache.addFont(embedFontInfo); diff --git a/src/java/org/apache/fop/fonts/FontLoader.java b/src/java/org/apache/fop/fonts/FontLoader.java index 02c09a1a1..b033e517e 100644 --- a/src/java/org/apache/fop/fonts/FontLoader.java +++ b/src/java/org/apache/fop/fonts/FontLoader.java @@ -30,7 +30,6 @@ import javax.xml.transform.stream.StreamSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.apache.fop.fonts.truetype.TTFFontLoader; import org.apache.fop.fonts.type1.Type1FontLoader; @@ -80,15 +79,17 @@ public abstract class FontLoader { * @param fontFile the File representation of the font * @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise) * @param embedded indicates whether the font is embedded or referenced + * @param embeddingMode the embedding mode * @param encodingMode the requested encoding mode * @param resolver the font resolver to use when resolving URIs * @return the newly loaded font * @throws IOException In case of an I/O error */ public static CustomFont loadFont(File fontFile, String subFontName, - boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException { + boolean embedded, EmbeddingMode embeddingMode, EncodingMode encodingMode, + FontResolver resolver) throws IOException { return loadFont(fontFile.toURI().toURL(), subFontName, - embedded, encodingMode, resolver); + embedded, embeddingMode, encodingMode, resolver); } /** @@ -96,16 +97,17 @@ public abstract class FontLoader { * @param fontUrl the URL representation of the font * @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise) * @param embedded indicates whether the font is embedded or referenced + * @param embeddingMode the embedding mode of the font * @param encodingMode the requested encoding mode * @param resolver the font resolver to use when resolving URIs * @return the newly loaded font * @throws IOException In case of an I/O error */ public static CustomFont loadFont(URL fontUrl, String subFontName, - boolean embedded, EncodingMode encodingMode, + boolean embedded, EmbeddingMode embeddingMode, EncodingMode encodingMode, FontResolver resolver) throws IOException { return loadFont(fontUrl.toExternalForm(), subFontName, - embedded, encodingMode, true, + embedded, embeddingMode, encodingMode, true, resolver); } @@ -114,6 +116,7 @@ public abstract class FontLoader { * @param fontFileURI the URI to the font * @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise) * @param embedded indicates whether the font is embedded or referenced + * @param embeddingMode the embedding mode of the font * @param encodingMode the requested encoding mode * @param useKerning indicates whether kerning information should be loaded if available * @param resolver the font resolver to use when resolving URIs @@ -121,8 +124,8 @@ public abstract class FontLoader { * @throws IOException In case of an I/O error */ public static CustomFont loadFont(String fontFileURI, String subFontName, - boolean embedded, EncodingMode encodingMode, boolean useKerning, - FontResolver resolver) throws IOException { + boolean embedded, EmbeddingMode embeddingMode, EncodingMode encodingMode, + boolean useKerning, FontResolver resolver) throws IOException { fontFileURI = fontFileURI.trim(); boolean type1 = isType1(fontFileURI); FontLoader loader; @@ -131,10 +134,14 @@ public abstract class FontLoader { throw new IllegalArgumentException( "CID encoding mode not supported for Type 1 fonts"); } + if (embeddingMode == EmbeddingMode.SUBSET) { + throw new IllegalArgumentException( + "Subset embedding for Type 1 fonts is not supported"); + } loader = new Type1FontLoader(fontFileURI, embedded, useKerning, resolver); } else { loader = new TTFFontLoader(fontFileURI, subFontName, - embedded, encodingMode, useKerning, resolver); + embedded, embeddingMode, encodingMode, useKerning, resolver); } return loader.getFont(); } diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java index a8fd447c4..4d63dafea 100644 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ b/src/java/org/apache/fop/fonts/LazyFont.java @@ -27,12 +27,10 @@ import java.util.Set; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; -import org.xml.sax.InputSource; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.apache.fop.apps.FOPException; +import org.xml.sax.InputSource; /** * This class is used to defer the loading of a font until it is really used. @@ -45,6 +43,7 @@ public class LazyFont extends Typeface implements FontDescriptor { private String fontEmbedPath = null; private boolean useKerning = false; private EncodingMode encodingMode = EncodingMode.AUTO; + private EmbeddingMode embeddingMode = EmbeddingMode.AUTO; private boolean embedded = true; private String subFontName = null; @@ -65,6 +64,7 @@ public class LazyFont extends Typeface implements FontDescriptor { this.fontEmbedPath = fontInfo.getEmbedFile(); this.useKerning = fontInfo.getKerning(); this.encodingMode = fontInfo.getEncodingMode(); + this.embeddingMode = fontInfo.getEmbeddingMode(); this.subFontName = fontInfo.getSubFontName(); this.embedded = fontInfo.isEmbedded(); this.resolver = resolver; @@ -131,8 +131,9 @@ public class LazyFont extends Typeface implements FontDescriptor { if (fontEmbedPath == null) { throw new RuntimeException("Cannot load font. No font URIs available."); } - realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName, - this.embedded, this.encodingMode, useKerning, resolver); + realFont = FontLoader.loadFont(fontEmbedPath, subFontName, + embedded, embeddingMode, encodingMode, + useKerning, resolver); } if (realFont instanceof FontDescriptor) { realFontDescriptor = (FontDescriptor) realFont; diff --git a/src/java/org/apache/fop/fonts/MutableFont.java b/src/java/org/apache/fop/fonts/MutableFont.java index bcbcadbdc..c19dca6b5 100644 --- a/src/java/org/apache/fop/fonts/MutableFont.java +++ b/src/java/org/apache/fop/fonts/MutableFont.java @@ -60,6 +60,12 @@ public interface MutableFont { */ void setEmbedResourceName(String name); + /** + * Set the embedding mode for this font. + * @param embeddingMode the embedding mode. + */ + void setEmbeddingMode(EmbeddingMode embeddingMode); + /** * Sets the capital height value. * @param capHeight capital height diff --git a/src/java/org/apache/fop/fonts/apps/TTFReader.java b/src/java/org/apache/fop/fonts/apps/TTFReader.java index 6e64f9144..bd2fe1257 100644 --- a/src/java/org/apache/fop/fonts/apps/TTFReader.java +++ b/src/java/org/apache/fop/fonts/apps/TTFReader.java @@ -20,7 +20,6 @@ package org.apache.fop.fonts.apps; import java.io.IOException; -import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -28,9 +27,9 @@ import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.logging.LogFactory; import org.apache.fop.Version; +import org.apache.fop.fonts.BFEntry; import org.apache.fop.fonts.FontUtil; import org.apache.fop.fonts.truetype.FontFileReader; -import org.apache.fop.fonts.truetype.TTFCmapEntry; import org.apache.fop.fonts.truetype.TTFFile; import org.apache.fop.util.CommandLineLogger; import org.w3c.dom.Document; @@ -272,9 +271,9 @@ public class TTFReader extends AbstractFontReader { root.appendChild(el); el.appendChild(doc.createTextNode(ttf.getFullName())); } - Set familyNames = ttf.getFamilyNames(); + Set familyNames = ttf.getFamilyNames(); if (familyNames.size() > 0) { - String familyName = (String)familyNames.iterator().next(); + String familyName = familyNames.iterator().next(); el = doc.createElement("family-name"); root.appendChild(el); el.appendChild(doc.createTextNode(familyName)); @@ -370,9 +369,7 @@ public class TTFReader extends AbstractFontReader { el = doc.createElement("bfranges"); mel.appendChild(el); - Iterator iter = ttf.getCMaps().listIterator(); - while (iter.hasNext()) { - TTFCmapEntry ce = (TTFCmapEntry)iter.next(); + for (BFEntry ce : ttf.getCMaps()) { Element el2 = doc.createElement("bf"); el.appendChild(el2); el2.setAttribute("us", String.valueOf(ce.getUnicodeStart())); @@ -427,31 +424,28 @@ public class TTFReader extends AbstractFontReader { Document doc = parent.getOwnerDocument(); // Get kerning - Iterator iter; + Set kerningKeys; if (isCid) { - iter = ttf.getKerning().keySet().iterator(); + kerningKeys = ttf.getKerning().keySet(); } else { - iter = ttf.getAnsiKerning().keySet().iterator(); + kerningKeys = ttf.getAnsiKerning().keySet(); } - while (iter.hasNext()) { - Integer kpx1 = (Integer)iter.next(); + for (Integer kpx1 : kerningKeys) { el = doc.createElement("kerning"); el.setAttribute("kpx1", kpx1.toString()); parent.appendChild(el); Element el2 = null; - Map h2; + Map h2; if (isCid) { - h2 = (Map)ttf.getKerning().get(kpx1); + h2 = ttf.getKerning().get(kpx1); } else { - h2 = (Map)ttf.getAnsiKerning().get(kpx1); + h2 = ttf.getAnsiKerning().get(kpx1); } - Iterator iter2 = h2.keySet().iterator(); - while (iter2.hasNext()) { - Integer kpx2 = (Integer)iter2.next(); + for (Integer kpx2 : h2.keySet()) { if (isCid || kpx2.intValue() < 256) { el2 = doc.createElement("pair"); el2.setAttribute("kpx2", kpx2.toString()); diff --git a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java index 714af0e57..a3e74ada7 100644 --- a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java +++ b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java @@ -31,6 +31,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.EmbedFontInfo; +import org.apache.fop.fonts.EmbeddingMode; import org.apache.fop.fonts.EncodingMode; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontCache; @@ -218,7 +219,8 @@ public class FontInfoFinder { } try { TTFFontLoader ttfLoader = new TTFFontLoader( - fontFileURL, fontName, true, EncodingMode.AUTO, true, resolver); + fontFileURL, fontName, true, EmbeddingMode.AUTO, EncodingMode.AUTO, + true, resolver); customFont = ttfLoader.getFont(); if (this.eventListener != null) { customFont.setEventListener(this.eventListener); @@ -242,7 +244,8 @@ public class FontInfoFinder { } else { // The normal case try { - customFont = FontLoader.loadFont(fontURL, null, true, EncodingMode.AUTO, resolver); + customFont = FontLoader.loadFont(fontURL, null, true, EmbeddingMode.AUTO, + EncodingMode.AUTO, resolver); if (this.eventListener != null) { customFont.setEventListener(this.eventListener); } diff --git a/src/java/org/apache/fop/fonts/truetype/FontFileReader.java b/src/java/org/apache/fop/fonts/truetype/FontFileReader.java index a6db7b6d0..e394b98ed 100644 --- a/src/java/org/apache/fop/fonts/truetype/FontFileReader.java +++ b/src/java/org/apache/fop/fonts/truetype/FontFileReader.java @@ -89,16 +89,6 @@ public class FontFileReader { current = (int)offset; } - /** - * Set current file position to offset - * - * @param add The number of bytes to advance - * @throws IOException In case of an I/O problem - */ - public void seekAdd(long add) throws IOException { - seekSet(current + add); - } - /** * Skip a given number of bytes. * @@ -106,7 +96,7 @@ public class FontFileReader { * @throws IOException In case of an I/O problem */ public void skip(long add) throws IOException { - seekAdd(add); + seekSet(current + add); } /** @@ -133,7 +123,7 @@ public class FontFileReader { * @return One byte * @throws IOException If EOF is reached */ - public byte read() throws IOException { + private byte read() throws IOException { if (current >= fsize) { throw new java.io.EOFException("Reached EOF, file size=" + fsize); } @@ -277,14 +267,14 @@ public class FontFileReader { public final String readTTFString() throws IOException { int i = current; while (file[i++] != 0) { - if (i > fsize) { + if (i >= fsize) { throw new java.io.EOFException("Reached EOF, file size=" + fsize); } } - byte[] tmp = new byte[i - current]; - System.arraycopy(file, current, tmp, 0, i - current); + byte[] tmp = new byte[i - current - 1]; + System.arraycopy(file, current, tmp, 0, i - current - 1); return new String(tmp, "ISO-8859-1"); } @@ -352,6 +342,11 @@ public class FontFileReader { System.arraycopy(file, offset, ret, 0, length); return ret; } - - + /** + * Returns the full byte array representation of the file. + * @return byte array. + */ + public byte[] getAllBytes() { + return file; + } } \ No newline at end of file diff --git a/src/java/org/apache/fop/fonts/truetype/TTFCmapEntry.java b/src/java/org/apache/fop/fonts/truetype/TTFCmapEntry.java deleted file mode 100644 index a63f76def..000000000 --- a/src/java/org/apache/fop/fonts/truetype/TTFCmapEntry.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -/** - * The CMap entry contains information of a Unicode range and the - * the glyph indexes related to the range - */ -public class TTFCmapEntry { - - //TODO this class is redundant: BFEntry does the same but doesn't have an intuitive name - - private int unicodeStart; - private int unicodeEnd; - private int glyphStartIndex; - - TTFCmapEntry() { - unicodeStart = 0; - unicodeEnd = 0; - glyphStartIndex = 0; - } - - TTFCmapEntry(int unicodeStart, int unicodeEnd, int glyphStartIndex) { - this.unicodeStart = unicodeStart; - this.unicodeEnd = unicodeEnd; - this.glyphStartIndex = glyphStartIndex; - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - int hc = super.hashCode(); - hc ^= ( hc * 11 ) + unicodeStart; - hc ^= ( hc * 19 ) + unicodeEnd; - hc ^= ( hc * 23 ) + glyphStartIndex; - return hc; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object o) { - if (o instanceof TTFCmapEntry) { - TTFCmapEntry ce = (TTFCmapEntry)o; - if (ce.unicodeStart == this.unicodeStart - && ce.unicodeEnd == this.unicodeEnd - && ce.glyphStartIndex == this.glyphStartIndex) { - return true; - } - } - return false; - } - - /** - * Returns the glyphStartIndex. - * @return int - */ - public int getGlyphStartIndex() { - return glyphStartIndex; - } - - /** - * Returns the unicodeEnd. - * @return int - */ - public int getUnicodeEnd() { - return unicodeEnd; - } - - /** - * Returns the unicodeStart. - * @return int - */ - public int getUnicodeStart() { - return unicodeStart; - } - - /** - * Sets the glyphStartIndex. - * @param glyphStartIndex The glyphStartIndex to set - */ - public void setGlyphStartIndex(int glyphStartIndex) { - this.glyphStartIndex = glyphStartIndex; - } - - /** - * Sets the unicodeEnd. - * @param unicodeEnd The unicodeEnd to set - */ - public void setUnicodeEnd(int unicodeEnd) { - this.unicodeEnd = unicodeEnd; - } - - /** - * Sets the unicodeStart. - * @param unicodeStart The unicodeStart to set - */ - public void setUnicodeStart(int unicodeStart) { - this.unicodeStart = unicodeStart; - } - -} diff --git a/src/java/org/apache/fop/fonts/truetype/TTFDirTabEntry.java b/src/java/org/apache/fop/fonts/truetype/TTFDirTabEntry.java index 405a71395..ca121a609 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFDirTabEntry.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFDirTabEntry.java @@ -33,6 +33,14 @@ class TTFDirTabEntry { private long offset; private long length; + public TTFDirTabEntry() { + } + + public TTFDirTabEntry(long offset, long length) { + this.offset = offset; + this.length = length; + } + /** * Read Dir Tab, return tag name */ diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java index 5aea4a66b..74d32a769 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java @@ -20,14 +20,22 @@ package org.apache.fop.fonts.truetype; import java.io.IOException; +import java.util.ArrayList; import java.util.BitSet; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.fonts.BFEntry; import org.apache.fop.fonts.FontUtil; import org.apache.xmlgraphics.fonts.Glyphs; @@ -127,6 +135,8 @@ public class TTFFile { "ccaron", "dcroat" }; + /** The FontFileReader used to read this truetype font */ + protected FontFileReader fontFile; /** Set to true to get even more debug output than with level DEBUG */ public static final boolean TRACE_ENABLED = false; @@ -138,11 +148,11 @@ public class TTFFile { /** * Table directory */ - protected Map dirTabs; - private Map> kerningTab; // for CIDs + protected Map dirTabs; + private Map> kerningTab; // for CIDs private Map> ansiKerningTab; // For winAnsiEncoding - private List cmaps; - private List unicodeMapping; + private List cmaps; + private List unicodeMapping; private int upem; // unitsPerEm from "head" table private int nhmtx; // Number of horizontal metrics @@ -153,18 +163,16 @@ public class TTFFile { */ protected long lastLoca = 0; private int numberOfGlyphs; // Number of glyphs in font (read from "maxp" table) - private int nmGlyphs; // Used in fixWidths - remove? /** * Contains glyph data */ protected TTFMtxEntry[] mtxTab; // Contains glyph data - private final int[] mtxEncoded = null; private String postScriptName = ""; private String fullName = ""; private String notice = ""; - private final Set familyNames = new java.util.HashSet(); //Set + private Set familyNames = new HashSet(); private String subFamilyName = ""; private long italicAngle = 0; @@ -193,12 +201,12 @@ public class TTFFile { private short lastChar = 0; private int[] ansiWidth; - private Map ansiIndex; + private Map> ansiIndex; // internal mapping of glyph indexes to unicode indexes // used for quick mappings in this class - private final Map glyphToUnicodeMap = new java.util.HashMap(); - private final Map unicodeToGlyphMap = new java.util.HashMap(); + private Map glyphToUnicodeMap = new HashMap (); + private Map unicodeToGlyphMap = new HashMap (); private TTFDirTabEntry currentDirTab; @@ -210,9 +218,9 @@ public class TTFFile { protected Log log = LogFactory.getLog(TTFFile.class); /** - * Key-value helper class + * Key-value helper class (immutable) */ - class UnicodeMapping { + final class UnicodeMapping { private final int unicodeIndex; private final int glyphIndex; @@ -244,33 +252,26 @@ public class TTFFile { /** * Version of the PostScript table (post) contained in this font. */ - public static final class PostScriptVersion { - + public static enum PostScriptVersion { /** PostScript table version 1.0. */ - public static final PostScriptVersion V1 = new PostScriptVersion(); - + V1, /** PostScript table version 2.0. */ - public static final PostScriptVersion V2 = new PostScriptVersion(); - + V2, /** PostScript table version 3.0. */ - public static final PostScriptVersion V3 = new PostScriptVersion(); - + V3, /** Unknown version of the PostScript table. */ - public static final PostScriptVersion UNKNOWN = new PostScriptVersion(); - - private PostScriptVersion() { } - + UNKNOWN; } /** * Position inputstream to position indicated * in the dirtab offset + offset */ - boolean seekTab(FontFileReader in, String name, + boolean seekTab(FontFileReader in, TTFTableName tableName, long offset) throws IOException { - TTFDirTabEntry dt = (TTFDirTabEntry)dirTabs.get(name); + TTFDirTabEntry dt = dirTabs.get(tableName); if (dt == null) { - log.error("Dirtab " + name + " not found."); + log.error("Dirtab " + tableName.getName() + " not found."); return false; } else { in.seekSet(dt.getOffset() + offset); @@ -306,12 +307,12 @@ public class TTFFile { * Set the unicodeIndex in the TTFMtxEntries and fills in the * cmaps vector. */ - private boolean readCMAP(FontFileReader in) throws IOException { + private boolean readCMAP() throws IOException { - unicodeMapping = new java.util.ArrayList(); + unicodeMapping = new ArrayList(); - seekTab(in, "cmap", 2); - int numCMap = in.readTTFUShort(); // Number of cmap subtables + seekTab(fontFile, TTFTableName.CMAP, 2); + int numCMap = fontFile.readTTFUShort(); // Number of cmap subtables long cmapUniOffset = 0; long symbolMapOffset = 0; @@ -321,9 +322,9 @@ public class TTFFile { //Read offset for all tables. We are only interested in the unicode table for (int i = 0; i < numCMap; i++) { - int cmapPID = in.readTTFUShort(); - int cmapEID = in.readTTFUShort(); - long cmapOffset = in.readTTFULong(); + int cmapPID = fontFile.readTTFUShort(); + int cmapEID = fontFile.readTTFUShort(); + long cmapOffset = fontFile.readTTFLong(); if (log.isDebugEnabled()) { log.debug("Platform ID: " + cmapPID + " Encoding: " + cmapEID); @@ -338,9 +339,9 @@ public class TTFFile { } if (cmapUniOffset > 0) { - return readUnicodeCmap(in, cmapUniOffset, 1); + return readUnicodeCmap(cmapUniOffset, 1); } else if (symbolMapOffset > 0) { - return readUnicodeCmap(in, symbolMapOffset, 0); + return readUnicodeCmap(symbolMapOffset, 0); } else { log.fatal("Unsupported TrueType font: No Unicode or Symbol cmap table" + " not present. Aborting"); @@ -349,26 +350,26 @@ public class TTFFile { } private boolean readUnicodeCmap // CSOK: MethodLength - (FontFileReader in, long cmapUniOffset, int encodingID) + (long cmapUniOffset, int encodingID) throws IOException { //Read CMAP table and correct mtxTab.index int mtxPtr = 0; // Read unicode cmap - seekTab(in, "cmap", cmapUniOffset); - int cmapFormat = in.readTTFUShort(); - /*int cmap_length =*/ in.readTTFUShort(); //skip cmap length + seekTab(fontFile, TTFTableName.CMAP, cmapUniOffset); + int cmapFormat = fontFile.readTTFUShort(); + /*int cmap_length =*/ fontFile.readTTFUShort(); //skip cmap length if (log.isDebugEnabled()) { log.debug("CMAP format: " + cmapFormat); } if (cmapFormat == 4) { - in.skip(2); // Skip version number - int cmapSegCountX2 = in.readTTFUShort(); - int cmapSearchRange = in.readTTFUShort(); - int cmapEntrySelector = in.readTTFUShort(); - int cmapRangeShift = in.readTTFUShort(); + fontFile.skip(2); // Skip version number + int cmapSegCountX2 = fontFile.readTTFUShort(); + int cmapSearchRange = fontFile.readTTFUShort(); + int cmapEntrySelector = fontFile.readTTFUShort(); + int cmapRangeShift = fontFile.readTTFUShort(); if (log.isDebugEnabled()) { log.debug("segCountX2 : " + cmapSegCountX2); @@ -384,26 +385,26 @@ public class TTFFile { int[] cmapRangeOffsets = new int[cmapSegCountX2 / 2]; for (int i = 0; i < (cmapSegCountX2 / 2); i++) { - cmapEndCounts[i] = in.readTTFUShort(); + cmapEndCounts[i] = fontFile.readTTFUShort(); } - in.skip(2); // Skip reservedPad + fontFile.skip(2); // Skip reservedPad for (int i = 0; i < (cmapSegCountX2 / 2); i++) { - cmapStartCounts[i] = in.readTTFUShort(); + cmapStartCounts[i] = fontFile.readTTFUShort(); } for (int i = 0; i < (cmapSegCountX2 / 2); i++) { - cmapDeltas[i] = in.readTTFShort(); + cmapDeltas[i] = fontFile.readTTFShort(); } //int startRangeOffset = in.getCurrentPos(); for (int i = 0; i < (cmapSegCountX2 / 2); i++) { - cmapRangeOffsets[i] = in.readTTFUShort(); + cmapRangeOffsets[i] = fontFile.readTTFUShort(); } - int glyphIdArrayOffset = in.getCurrentPos(); + int glyphIdArrayOffset = fontFile.getCurrentPos(); BitSet eightBitGlyphs = new BitSet(256); @@ -445,8 +446,8 @@ public class TTFFile { + (j - cmapStartCounts[i]) + (i) - cmapSegCountX2 / 2) * 2; - in.seekSet(glyphOffset); - glyphIdx = (in.readTTFUShort() + cmapDeltas[i]) + fontFile.seekSet(glyphOffset); + glyphIdx = (fontFile.readTTFUShort() + cmapDeltas[i]) & 0xffff; unicodeMapping.add(new UnicodeMapping(glyphIdx, j)); @@ -465,11 +466,9 @@ public class TTFFile { } // Also add winAnsiWidth - List v = (List)ansiIndex.get(new Integer(j)); + List v = ansiIndex.get(new Integer(j)); if (v != null) { - Iterator e = v.listIterator(); - while (e.hasNext()) { - Integer aIdx = (Integer)e.next(); + for (Integer aIdx : v) { ansiWidth[aIdx.intValue()] = mtxTab[glyphIdx].getWx(); @@ -510,11 +509,9 @@ public class TTFFile { } // Also add winAnsiWidth - List v = (List)ansiIndex.get(new Integer(j)); + List v = ansiIndex.get(new Integer(j)); if (v != null) { - Iterator e = v.listIterator(); - while (e.hasNext()) { - Integer aIdx = (Integer)e.next(); + for (Integer aIdx : v) { ansiWidth[aIdx.intValue()] = mtxTab[glyphIdx].getWx(); } } @@ -592,14 +589,14 @@ public class TTFFile { // Create an index hash to the ansiWidth // Can't just index the winAnsiEncoding when inserting widths // same char (eg bullet) is repeated more than one place - ansiIndex = new java.util.HashMap(); + ansiIndex = new HashMap>(); for (int i = 32; i < Glyphs.WINANSI_ENCODING.length; i++) { Integer ansi = new Integer(i); Integer uni = new Integer(Glyphs.WINANSI_ENCODING[i]); - List v = (List)ansiIndex.get(uni); + List v = ansiIndex.get(uni); if (v == null) { - v = new java.util.ArrayList(); + v = new ArrayList(); ansiIndex.put(uni, v); } v.add(ansi); @@ -618,12 +615,12 @@ public class TTFFile { * @throws IOException In case of an I/O problem */ public boolean readFont(FontFileReader in, String name) throws IOException { - + fontFile = in; /* * Check if TrueType collection, and that the name * exists in the collection */ - if (!checkTTC(in, name)) { + if (!checkTTC(name)) { if (name == null) { throw new IllegalArgumentException( "For TrueType collection you must specify which font " @@ -634,26 +631,26 @@ public class TTFFile { } } - readDirTabs(in); - readFontHeader(in); - getNumGlyphs(in); + readDirTabs(); + readFontHeader(); + getNumGlyphs(); if (log.isDebugEnabled()) { log.debug("Number of glyphs in font: " + numberOfGlyphs); } - readHorizontalHeader(in); - readHorizontalMetrics(in); + readHorizontalHeader(); + readHorizontalMetrics(); initAnsiWidths(); - readPostScript(in); - readOS2(in); + readPostScript(); + readOS2(); determineAscDesc(); if (!isCFF) { - readIndexToLocation(in); - readGlyf(in); + readIndexToLocation(); + readGlyf(); } - readName(in); - boolean pcltFound = readPCLT(in); + readName(); + boolean pcltFound = readPCLT(); // Read cmap table and fill in ansiwidths - boolean valid = readCMAP(in); + boolean valid = readCMAP(); if (!valid) { return false; } @@ -661,38 +658,52 @@ public class TTFFile { createCMaps(); // print_max_min(); - readKerning(in); + readKerning(); guessVerticalMetricsFromGlyphBBox(); return true; } + /** + * Reads a font. + * + * @param in FontFileReader to read from + * @param name Name to be checked for in the font file + * @param glyphs Map of glyphs (glyphs has old index as (Integer) key and + * new index as (Integer) value) + * @throws IOException in case of an I/O problem + */ + public void readFont(FontFileReader in, String name, + Map glyphs) throws IOException { + readFont(in, name); + } + private void createCMaps() { - this.cmaps = new java.util.ArrayList(); - TTFCmapEntry tce = new TTFCmapEntry(); + cmaps = new ArrayList(); + int unicodeStart; + int glyphStart; + int unicodeEnd; - Iterator e = unicodeMapping.listIterator(); - UnicodeMapping um = (UnicodeMapping)e.next(); + Iterator e = unicodeMapping.listIterator(); + UnicodeMapping um = e.next(); UnicodeMapping lastMapping = um; - tce.setUnicodeStart(um.getUnicodeIndex()); - tce.setGlyphStartIndex(um.getGlyphIndex()); + unicodeStart = um.getUnicodeIndex(); + glyphStart = um.getGlyphIndex(); while (e.hasNext()) { - um = (UnicodeMapping)e.next(); + um = e.next(); if (((lastMapping.getUnicodeIndex() + 1) != um.getUnicodeIndex()) || ((lastMapping.getGlyphIndex() + 1) != um.getGlyphIndex())) { - tce.setUnicodeEnd(lastMapping.getUnicodeIndex()); - cmaps.add(tce); - - tce = new TTFCmapEntry(); - tce.setUnicodeStart(um.getUnicodeIndex()); - tce.setGlyphStartIndex(um.getGlyphIndex()); + unicodeEnd = lastMapping.getUnicodeIndex(); + cmaps.add(new BFEntry(unicodeStart, unicodeEnd, glyphStart)); + unicodeStart = um.getUnicodeIndex(); + glyphStart = um.getGlyphIndex(); } lastMapping = um; } - tce.setUnicodeEnd(um.getUnicodeIndex()); - cmaps.add(tce); + unicodeEnd = lastMapping.getUnicodeIndex(); + cmaps.add(new BFEntry(unicodeStart, unicodeEnd, glyphStart)); } /** @@ -715,7 +726,7 @@ public class TTFFile { * Returns the font family names of the font. * @return Set The family names (a Set of Strings) */ - public Set getFamilyNames() { + public Set getFamilyNames() { return familyNames; } @@ -759,6 +770,17 @@ public class TTFFile { return convertTTFUnit2PDFUnit(xHeight); } + /** + * Returns the number of bytes necessary to pad the currentPosition so that a table begins + * on a 4-byte boundary. + * @param currentPosition the position to pad. + * @return int the number of bytes to pad. + */ + protected int getPadSize(int currentPosition) { + int padSize = 4 - (currentPosition % 4); + return padSize < 4 ? padSize : 0; + } + /** * Returns the Flags attribute of the font. * @return int The Flags @@ -766,13 +788,13 @@ public class TTFFile { public int getFlags() { int flags = 32; // Use Adobe Standard charset if (italicAngle != 0) { - flags = flags | 64; + flags |= 64; } if (isFixedPitch != 0) { - flags = flags | 2; + flags |= 2; } if (hasSerifs) { - flags = flags | 1; + flags |= 1; } return flags; } @@ -810,7 +832,6 @@ public class TTFFile { } /** - * Returns the font bounding box. * @return int[] The font bbox */ public int[] getFontBBox() { @@ -916,11 +937,10 @@ public class TTFFile { * FontFileReader and fill the global HashMap dirTabs * with the table name (String) as key and a TTFDirTabEntry * as value. - * @param in FontFileReader to read the table directory from * @throws IOException in case of an I/O problem */ - protected void readDirTabs(FontFileReader in) throws IOException { - int sfntVersion = in.readTTFLong(); // TTF_FIXED_SIZE (4 bytes) + protected void readDirTabs() throws IOException { + int sfntVersion = fontFile.readTTFLong(); // TTF_FIXED_SIZE (4 bytes) switch (sfntVersion) { case 0x10000: log.debug("sfnt version: OpenType 1.0"); @@ -939,42 +959,45 @@ public class TTFFile { log.debug("Unknown sfnt version: " + Integer.toHexString(sfntVersion)); break; } - int ntabs = in.readTTFUShort(); - in.skip(6); // 3xTTF_USHORT_SIZE + int ntabs = fontFile.readTTFUShort(); + fontFile.skip(6); // 3xTTF_USHORT_SIZE - dirTabs = new java.util.HashMap(); + dirTabs = new HashMap(); TTFDirTabEntry[] pd = new TTFDirTabEntry[ntabs]; log.debug("Reading " + ntabs + " dir tables"); + for (int i = 0; i < ntabs; i++) { pd[i] = new TTFDirTabEntry(); - dirTabs.put(pd[i].read(in), pd[i]); + String tableName = pd[i].read(fontFile); + dirTabs.put(TTFTableName.getValue(tableName), pd[i]); } + dirTabs.put(TTFTableName.DIRECTORY_TABLE, + new TTFDirTabEntry(0L, fontFile.getCurrentPos())); log.debug("dir tables: " + dirTabs.keySet()); } /** * Read the "head" table, this reads the bounding box and * sets the upem (unitsPerEM) variable - * @param in FontFileReader to read the header from * @throws IOException in case of an I/O problem */ - protected void readFontHeader(FontFileReader in) throws IOException { - seekTab(in, "head", 2 * 4 + 2 * 4); - int flags = in.readTTFUShort(); + protected void readFontHeader() throws IOException { + seekTab(fontFile, TTFTableName.HEAD, 2 * 4 + 2 * 4); + int flags = fontFile.readTTFUShort(); if (log.isDebugEnabled()) { log.debug("flags: " + flags + " - " + Integer.toString(flags, 2)); } - upem = in.readTTFUShort(); + upem = fontFile.readTTFUShort(); if (log.isDebugEnabled()) { log.debug("unit per em: " + upem); } - in.skip(16); + fontFile.skip(16); - fontBBox1 = in.readTTFShort(); - fontBBox2 = in.readTTFShort(); - fontBBox3 = in.readTTFShort(); - fontBBox4 = in.readTTFShort(); + fontBBox1 = fontFile.readTTFShort(); + fontBBox2 = fontFile.readTTFShort(); + fontBBox3 = fontFile.readTTFShort(); + fontBBox4 = fontFile.readTTFShort(); if (log.isDebugEnabled()) { log.debug("font bbox: xMin=" + fontBBox1 + " yMin=" + fontBBox2 @@ -982,19 +1005,18 @@ public class TTFFile { + " yMax=" + fontBBox4); } - in.skip(2 + 2 + 2); + fontFile.skip(2 + 2 + 2); - locaFormat = in.readTTFShort(); + locaFormat = fontFile.readTTFShort(); } /** * Read the number of glyphs from the "maxp" table - * @param in FontFileReader to read the number of glyphs from * @throws IOException in case of an I/O problem */ - protected void getNumGlyphs(FontFileReader in) throws IOException { - seekTab(in, "maxp", 4); - numberOfGlyphs = in.readTTFUShort(); + protected void getNumGlyphs() throws IOException { + seekTab(fontFile, TTFTableName.MAXP, 4); + numberOfGlyphs = fontFile.readTTFUShort(); } @@ -1002,17 +1024,16 @@ public class TTFFile { * Read the "hhea" table to find the ascender and descender and * size of "hmtx" table, as a fixed size font might have only * one width. - * @param in FontFileReader to read the hhea table from * @throws IOException in case of an I/O problem */ - protected void readHorizontalHeader(FontFileReader in) + protected void readHorizontalHeader() throws IOException { - seekTab(in, "hhea", 4); - hheaAscender = in.readTTFShort(); - hheaDescender = in.readTTFShort(); + seekTab(fontFile, TTFTableName.HHEA, 4); + hheaAscender = fontFile.readTTFShort(); + hheaDescender = fontFile.readTTFShort(); - in.skip(2 + 2 + 3 * 2 + 8 * 2); - nhmtx = in.readTTFUShort(); + fontFile.skip(2 + 2 + 3 * 2 + 8 * 2); + nhmtx = fontFile.readTTFUShort(); if (log.isDebugEnabled()) { log.debug("hhea.Ascender: " + formatUnitsForDebug(hheaAscender)); @@ -1026,12 +1047,11 @@ public class TTFFile { * in the mtxTab array. If the number of metrics is less * than the number of glyphs (eg fixed size fonts), extend * the mtxTab array and fill in the missing widths - * @param in FontFileReader to read the hmtx table from * @throws IOException in case of an I/O problem */ - protected void readHorizontalMetrics(FontFileReader in) + protected void readHorizontalMetrics() throws IOException { - seekTab(in, "hmtx", 0); + seekTab(fontFile, TTFTableName.HMTX, 0); int mtxSize = Math.max(numberOfGlyphs, nhmtx); mtxTab = new TTFMtxEntry[mtxSize]; @@ -1043,8 +1063,8 @@ public class TTFFile { mtxTab[i] = new TTFMtxEntry(); } for (int i = 0; i < nhmtx; i++) { - mtxTab[i].setWx(in.readTTFUShort()); - mtxTab[i].setLsb(in.readTTFUShort()); + mtxTab[i].setWx(fontFile.readTTFUShort()); + mtxTab[i].setLsb(fontFile.readTTFUShort()); if (TRACE_ENABLED) { if (log.isDebugEnabled()) { @@ -1059,7 +1079,7 @@ public class TTFFile { int lastWidth = mtxTab[nhmtx - 1].getWx(); for (int i = nhmtx; i < mtxSize; i++) { mtxTab[i].setWx(lastWidth); - mtxTab[i].setLsb(in.readTTFUShort()); + mtxTab[i].setLsb(fontFile.readTTFUShort()); } } } @@ -1069,16 +1089,16 @@ public class TTFFile { * Read the "post" table * containing the PostScript names of the glyphs. */ - private void readPostScript(FontFileReader in) throws IOException { - seekTab(in, "post", 0); - int postFormat = in.readTTFLong(); - italicAngle = in.readTTFULong(); - underlinePosition = in.readTTFShort(); - underlineThickness = in.readTTFShort(); - isFixedPitch = in.readTTFULong(); + private void readPostScript() throws IOException { + seekTab(fontFile, TTFTableName.POST, 0); + int postFormat = fontFile.readTTFLong(); + italicAngle = fontFile.readTTFULong(); + underlinePosition = fontFile.readTTFShort(); + underlineThickness = fontFile.readTTFShort(); + isFixedPitch = fontFile.readTTFULong(); //Skip memory usage values - in.skip(4 * 4); + fontFile.skip(4 * 4); log.debug("PostScript format: 0x" + Integer.toHexString(postFormat)); switch (postFormat) { @@ -1095,11 +1115,11 @@ public class TTFFile { int numGlyphStrings = 0; // Read Number of Glyphs - int l = in.readTTFUShort(); + int l = fontFile.readTTFUShort(); // Read indexes for (int i = 0; i < l; i++) { - mtxTab[i].setIndex(in.readTTFUShort()); + mtxTab[i].setIndex(fontFile.readTTFUShort()); if (mtxTab[i].getIndex() > 257) { //Index is not in the Macintosh standard set @@ -1119,7 +1139,7 @@ public class TTFFile { + " set. Total number of glyphs=" + l); } for (int i = 0; i < psGlyphsBuffer.length; i++) { - psGlyphsBuffer[i] = in.readTTFString(in.readTTFUByte()); + psGlyphsBuffer[i] = fontFile.readTTFString(fontFile.readTTFUByte()); } //Set glyph names @@ -1156,60 +1176,60 @@ public class TTFFile { /** * Read the "OS/2" table */ - private void readOS2(FontFileReader in) throws IOException { + private void readOS2() throws IOException { // Check if font is embeddable - TTFDirTabEntry os2Entry = (TTFDirTabEntry)dirTabs.get("OS/2"); + TTFDirTabEntry os2Entry = dirTabs.get(TTFTableName.OS2); if (os2Entry != null) { - seekTab(in, "OS/2", 0); - int version = in.readTTFUShort(); + seekTab(fontFile, TTFTableName.OS2, 0); + int version = fontFile.readTTFUShort(); if (log.isDebugEnabled()) { log.debug("OS/2 table: version=" + version + ", offset=" + os2Entry.getOffset() + ", len=" + os2Entry.getLength()); } - in.skip(2); //xAvgCharWidth - this.usWeightClass = in.readTTFUShort(); + fontFile.skip(2); //xAvgCharWidth + this.usWeightClass = fontFile.readTTFUShort(); // usWidthClass - in.skip(2); + fontFile.skip(2); - int fsType = in.readTTFUShort(); + int fsType = fontFile.readTTFUShort(); if (fsType == 2) { isEmbeddable = false; } else { isEmbeddable = true; } - in.skip(11 * 2); - in.skip(10); //panose array - in.skip(4 * 4); //unicode ranges - in.skip(4); - in.skip(3 * 2); + fontFile.skip(11 * 2); + fontFile.skip(10); //panose array + fontFile.skip(4 * 4); //unicode ranges + fontFile.skip(4); + fontFile.skip(3 * 2); int v; - os2Ascender = in.readTTFShort(); //sTypoAscender - os2Descender = in.readTTFShort(); //sTypoDescender + os2Ascender = fontFile.readTTFShort(); //sTypoAscender + os2Descender = fontFile.readTTFShort(); //sTypoDescender if (log.isDebugEnabled()) { log.debug("sTypoAscender: " + os2Ascender + " -> internal " + convertTTFUnit2PDFUnit(os2Ascender)); log.debug("sTypoDescender: " + os2Descender + " -> internal " + convertTTFUnit2PDFUnit(os2Descender)); } - v = in.readTTFShort(); //sTypoLineGap + v = fontFile.readTTFShort(); //sTypoLineGap if (log.isDebugEnabled()) { log.debug("sTypoLineGap: " + v); } - v = in.readTTFUShort(); //usWinAscent + v = fontFile.readTTFUShort(); //usWinAscent if (log.isDebugEnabled()) { log.debug("usWinAscent: " + formatUnitsForDebug(v)); } - v = in.readTTFUShort(); //usWinDescent + v = fontFile.readTTFUShort(); //usWinDescent if (log.isDebugEnabled()) { log.debug("usWinDescent: " + formatUnitsForDebug(v)); } //version 1 OS/2 table might end here if (os2Entry.getLength() >= 78 + (2 * 4) + (2 * 2)) { - in.skip(2 * 4); - this.os2xHeight = in.readTTFShort(); //sxHeight - this.os2CapHeight = in.readTTFShort(); //sCapHeight + fontFile.skip(2 * 4); + this.os2xHeight = fontFile.readTTFShort(); //sxHeight + this.os2CapHeight = fontFile.readTTFShort(); //sCapHeight if (log.isDebugEnabled()) { log.debug("sxHeight: " + this.os2xHeight); log.debug("sCapHeight: " + this.os2CapHeight); @@ -1223,42 +1243,40 @@ public class TTFFile { /** * Read the "loca" table. - * @param in FontFileReader to read from * @throws IOException In case of a I/O problem */ - protected final void readIndexToLocation(FontFileReader in) + protected final void readIndexToLocation() throws IOException { - if (!seekTab(in, "loca", 0)) { + if (!seekTab(fontFile, TTFTableName.LOCA, 0)) { throw new IOException("'loca' table not found, happens when the font file doesn't" + " contain TrueType outlines (trying to read an OpenType CFF font maybe?)"); } for (int i = 0; i < numberOfGlyphs; i++) { - mtxTab[i].setOffset(locaFormat == 1 ? in.readTTFULong() - : (in.readTTFUShort() << 1)); + mtxTab[i].setOffset(locaFormat == 1 ? fontFile.readTTFULong() + : (fontFile.readTTFUShort() << 1)); } - lastLoca = (locaFormat == 1 ? in.readTTFULong() - : (in.readTTFUShort() << 1)); + lastLoca = (locaFormat == 1 ? fontFile.readTTFULong() + : (fontFile.readTTFUShort() << 1)); } /** * Read the "glyf" table to find the bounding boxes. - * @param in FontFileReader to read from * @throws IOException In case of a I/O problem */ - private void readGlyf(FontFileReader in) throws IOException { - TTFDirTabEntry dirTab = (TTFDirTabEntry)dirTabs.get("glyf"); + private void readGlyf() throws IOException { + TTFDirTabEntry dirTab = dirTabs.get(TTFTableName.GLYF); if (dirTab == null) { throw new IOException("glyf table not found, cannot continue"); } for (int i = 0; i < (numberOfGlyphs - 1); i++) { if (mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) { - in.seekSet(dirTab.getOffset() + mtxTab[i].getOffset()); - in.skip(2); + fontFile.seekSet(dirTab.getOffset() + mtxTab[i].getOffset()); + fontFile.skip(2); final int[] bbox = { - in.readTTFShort(), - in.readTTFShort(), - in.readTTFShort(), - in.readTTFShort()}; + fontFile.readTTFShort(), + fontFile.readTTFShort(), + fontFile.readTTFShort(), + fontFile.readTTFShort()}; mtxTab[i].setBoundingBox(bbox); } else { mtxTab[i].setBoundingBox(mtxTab[0].getBoundingBox()); @@ -1266,17 +1284,17 @@ public class TTFFile { } - long n = ((TTFDirTabEntry)dirTabs.get("glyf")).getOffset(); + long n = (dirTabs.get(TTFTableName.GLYF)).getOffset(); for (int i = 0; i < numberOfGlyphs; i++) { if ((i + 1) >= mtxTab.length || mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) { - in.seekSet(n + mtxTab[i].getOffset()); - in.skip(2); + fontFile.seekSet(n + mtxTab[i].getOffset()); + fontFile.skip(2); final int[] bbox = { - in.readTTFShort(), - in.readTTFShort(), - in.readTTFShort(), - in.readTTFShort()}; + fontFile.readTTFShort(), + fontFile.readTTFShort(), + fontFile.readTTFShort(), + fontFile.readTTFShort()}; mtxTab[i].setBoundingBox(bbox); } else { /**@todo Verify that this is correct, looks like a copy/paste bug (jm)*/ @@ -1297,34 +1315,33 @@ public class TTFFile { /** * Read the "name" table. - * @param in FontFileReader to read from * @throws IOException In case of a I/O problem */ - private void readName(FontFileReader in) throws IOException { - seekTab(in, "name", 2); - int i = in.getCurrentPos(); - int n = in.readTTFUShort(); - int j = in.readTTFUShort() + i - 2; + private void readName() throws IOException { + seekTab(fontFile, TTFTableName.NAME, 2); + int i = fontFile.getCurrentPos(); + int n = fontFile.readTTFUShort(); + int j = fontFile.readTTFUShort() + i - 2; i += 2 * 2; while (n-- > 0) { // getLogger().debug("Iteration: " + n); - in.seekSet(i); - final int platformID = in.readTTFUShort(); - final int encodingID = in.readTTFUShort(); - final int languageID = in.readTTFUShort(); + fontFile.seekSet(i); + final int platformID = fontFile.readTTFUShort(); + final int encodingID = fontFile.readTTFUShort(); + final int languageID = fontFile.readTTFUShort(); - int k = in.readTTFUShort(); - int l = in.readTTFUShort(); + int k = fontFile.readTTFUShort(); + int l = fontFile.readTTFUShort(); if (((platformID == 1 || platformID == 3) && (encodingID == 0 || encodingID == 1))) { - in.seekSet(j + in.readTTFUShort()); + fontFile.seekSet(j + fontFile.readTTFUShort()); String txt; if (platformID == 3) { - txt = in.readTTFString(l, encodingID); + txt = fontFile.readTTFString(l, encodingID); } else { - txt = in.readTTFString(l); + txt = fontFile.readTTFString(l); } if (log.isDebugEnabled()) { @@ -1368,21 +1385,20 @@ public class TTFFile { /** * Read the "PCLT" table to find xHeight and capHeight. - * @param in FontFileReader to read from * @throws IOException In case of a I/O problem */ - private boolean readPCLT(FontFileReader in) throws IOException { - TTFDirTabEntry dirTab = (TTFDirTabEntry)dirTabs.get("PCLT"); + private boolean readPCLT() throws IOException { + TTFDirTabEntry dirTab = dirTabs.get(TTFTableName.PCLT); if (dirTab != null) { - in.seekSet(dirTab.getOffset() + 4 + 4 + 2); - xHeight = in.readTTFUShort(); + fontFile.seekSet(dirTab.getOffset() + 4 + 4 + 2); + xHeight = fontFile.readTTFUShort(); log.debug("xHeight from PCLT: " + formatUnitsForDebug(xHeight)); - in.skip(2 * 2); - capHeight = in.readTTFUShort(); + fontFile.skip(2 * 2); + capHeight = fontFile.readTTFUShort(); log.debug("capHeight from PCLT: " + formatUnitsForDebug(capHeight)); - in.skip(2 + 16 + 8 + 6 + 1 + 1); + fontFile.skip(2 + 16 + 8 + 6 + 1 + 1); - int serifStyle = in.readTTFUByte(); + int serifStyle = fontFile.readTTFUByte(); serifStyle = serifStyle >> 6; serifStyle = serifStyle & 3; if (serifStyle == 1) { @@ -1512,19 +1528,18 @@ public class TTFFile { /** * Read the kerning table, create a table for both CIDs and * winAnsiEncoding. - * @param in FontFileReader to read from * @throws IOException In case of a I/O problem */ - private void readKerning(FontFileReader in) throws IOException { + private void readKerning() throws IOException { // Read kerning - kerningTab = new java.util.HashMap(); - ansiKerningTab = new java.util.HashMap(); - TTFDirTabEntry dirTab = (TTFDirTabEntry)dirTabs.get("kern"); + kerningTab = new HashMap>(); + ansiKerningTab = new HashMap>(); + TTFDirTabEntry dirTab = dirTabs.get(TTFTableName.KERN); if (dirTab != null) { - seekTab(in, "kern", 2); - for (int n = in.readTTFUShort(); n > 0; n--) { - in.skip(2 * 2); - int k = in.readTTFUShort(); + seekTab(fontFile, TTFTableName.KERN, 2); + for (int n = fontFile.readTTFUShort(); n > 0; n--) { + fontFile.skip(2 * 2); + int k = fontFile.readTTFUShort(); if (!((k & 1) != 0) || (k & 2) != 0 || (k & 4) != 0) { return; } @@ -1532,12 +1547,12 @@ public class TTFFile { continue; } - k = in.readTTFUShort(); - in.skip(3 * 2); + k = fontFile.readTTFUShort(); + fontFile.skip(3 * 2); while (k-- > 0) { - int i = in.readTTFUShort(); - int j = in.readTTFUShort(); - int kpx = in.readTTFShort(); + int i = fontFile.readTTFUShort(); + int j = fontFile.readTTFUShort(); + int kpx = fontFile.readTTFShort(); if (kpx != 0) { // CID kerning table entry, using unicode indexes final Integer iObj = glyphToUnicode(i); @@ -1551,9 +1566,9 @@ public class TTFFile { log.debug("Ignoring kerning pair because Unicode index was" + " found for the second glyph " + i); } else { - Map adjTab = kerningTab.get(iObj); + Map adjTab = kerningTab.get(iObj); if (adjTab == null) { - adjTab = new java.util.HashMap(); + adjTab = new HashMap(); } adjTab.put(u2, new Integer(convertTTFUnit2PDFUnit(kpx))); kerningTab.put(iObj, adjTab); @@ -1565,16 +1580,12 @@ public class TTFFile { // Create winAnsiEncoded kerning table from kerningTab // (could probably be simplified, for now we remap back to CID indexes and // then to winAnsi) - Iterator ae = kerningTab.keySet().iterator(); - while (ae.hasNext()) { - Integer unicodeKey1 = (Integer)ae.next(); + for (Integer unicodeKey1 : kerningTab.keySet()) { Integer cidKey1 = unicodeToGlyph(unicodeKey1.intValue()); - Map akpx = new java.util.HashMap(); - Map ckpx = kerningTab.get(unicodeKey1); + Map akpx = new HashMap(); + Map ckpx = kerningTab.get(unicodeKey1); - Iterator aee = ckpx.keySet().iterator(); - while (aee.hasNext()) { - Integer unicodeKey2 = (Integer)aee.next(); + for (Integer unicodeKey2 : ckpx.keySet()) { Integer cidKey2 = unicodeToGlyph(unicodeKey2.intValue()); Integer kern = (Integer)ckpx.get(unicodeKey2); @@ -1602,11 +1613,71 @@ public class TTFFile { } } + /** + * Streams a font. + * @param ttfOut The interface for streaming True Type tables. + * @exception IOException file write error + */ + public void stream(TTFOutputStream ttfOut) throws IOException { + SortedSet> sortedDirTabs = sortDirTabMap(dirTabs); + byte[] file = fontFile.getAllBytes(); + TTFTableOutputStream tableOut = ttfOut.getTableOutputStream(); + TTFGlyphOutputStream glyphOut = ttfOut.getGlyphOutputStream(); + ttfOut.startFontStream(); + for (Map.Entry entry : sortedDirTabs) { + int offset = (int) entry.getValue().getOffset(); + int paddedLength = (int) entry.getValue().getLength(); + paddedLength += getPadSize(offset + paddedLength); + if (entry.getKey().equals(TTFTableName.GLYF)) { + streamGlyf(glyphOut, file, offset, paddedLength); + } else { + tableOut.streamTable(file, offset, paddedLength); + } + } + ttfOut.endFontStream(); + } + + private void streamGlyf(TTFGlyphOutputStream glyphOut, byte[] fontFile, int tableOffset, + int tableLength) throws IOException { + //Stream all but the last glyph + int glyphStart = 0; + int glyphEnd = 0; + glyphOut.startGlyphStream(); + for (int i = 0; i < mtxTab.length - 1; i++) { + glyphStart = (int) mtxTab[i].getOffset() + tableOffset; + glyphEnd = (int) mtxTab[i + 1].getOffset() + tableOffset; + glyphOut.streamGlyph(fontFile, glyphStart, glyphEnd - glyphStart); + } + glyphOut.streamGlyph(fontFile, glyphEnd, (tableOffset + tableLength) - glyphEnd); + glyphOut.endGlyphStream(); + } + + /** + * This returns the order in which the tables in a truetype font should be written to file. + * @param directoryTabs the map that is to be sorted. + * @return TTFTablesNames[] an array of table names sorted in the order they should appear in + * the TTF file. + */ + SortedSet> + sortDirTabMap(Map directoryTabs) { + SortedSet> sortedSet + = new TreeSet>( + new Comparator>() { + + public int compare(Entry o1, + Entry o2) { + return (int) (o1.getValue().getOffset() - o2.getValue().getOffset()); + } + }); + sortedSet.addAll(directoryTabs.entrySet()); + return sortedSet; + } + /** * Return a List with TTFCmapEntry. * @return A list of TTFCmapEntry objects */ - public List getCMaps() { + public List getCMaps() { return cmaps; } @@ -1615,24 +1686,23 @@ public class TTFFile { * name exists in the collection. * If it does, set offset in fontfile to the beginning of * the Table Directory for that font. - * @param in FontFileReader to read from * @param name The name to check * @return True if not collection or font name present, false otherwise * @throws IOException In case of an I/O problem */ - protected final boolean checkTTC(FontFileReader in, String name) throws IOException { - String tag = in.readTTFString(4); + protected final boolean checkTTC(String name) throws IOException { + String tag = fontFile.readTTFString(4); if ("ttcf".equals(tag)) { // This is a TrueType Collection - in.skip(4); + fontFile.skip(4); // Read directory offsets - int numDirectories = (int)in.readTTFULong(); + int numDirectories = (int)fontFile.readTTFULong(); // int numDirectories=in.readTTFUShort(); long[] dirOffsets = new long[numDirectories]; for (int i = 0; i < numDirectories; i++) { - dirOffsets[i] = in.readTTFULong(); + dirOffsets[i] = fontFile.readTTFULong(); } log.info("This is a TrueType collection file with " @@ -1646,10 +1716,10 @@ public class TTFFile { // Is found, just to show all the names long dirTabOffset = 0; for (int i = 0; (i < numDirectories); i++) { - in.seekSet(dirOffsets[i]); - readDirTabs(in); + fontFile.seekSet(dirOffsets[i]); + readDirTabs(); - readName(in); + readName(); if (fullName.equals(name)) { found = true; @@ -1667,10 +1737,10 @@ public class TTFFile { subFamilyName = ""; } - in.seekSet(dirTabOffset); + fontFile.seekSet(dirTabOffset); return found; } else { - in.seekSet(0); + fontFile.seekSet(0); return true; } } @@ -1682,8 +1752,7 @@ public class TTFFile { * @throws IOException In case of an I/O problem */ public final List getTTCnames(FontFileReader in) throws IOException { - List fontNames = new java.util.ArrayList(); - + List fontNames = new ArrayList(); String tag = in.readTTFString(4); if ("ttcf".equals(tag)) { @@ -1705,9 +1774,9 @@ public class TTFFile { for (int i = 0; (i < numDirectories); i++) { in.seekSet(dirOffsets[i]); - readDirTabs(in); + readDirTabs(); - readName(in); + readName(); log.debug(fullName); fontNames.add(fullName); @@ -1733,13 +1802,13 @@ public class TTFFile { * doesn't matter... */ private Integer[] unicodeToWinAnsi(int unicode) { - List ret = new java.util.ArrayList(); + List ret = new ArrayList(); for (int i = 32; i < Glyphs.WINANSI_ENCODING.length; i++) { if (unicode == Glyphs.WINANSI_ENCODING[i]) { ret.add(new Integer(i)); } } - return (Integer[])ret.toArray(new Integer[0]); + return ret.toArray(new Integer[0]); } /** @@ -1783,7 +1852,7 @@ public class TTFFile { * @throws IOException if glyphIndex not found */ private Integer glyphToUnicode(int glyphIndex) throws IOException { - return (Integer) glyphToUnicodeMap.get(new Integer(glyphIndex)); + return glyphToUnicodeMap.get(new Integer(glyphIndex)); } /** @@ -1795,7 +1864,7 @@ public class TTFFile { */ private Integer unicodeToGlyph(int unicodeIndex) throws IOException { final Integer result - = (Integer) unicodeToGlyphMap.get(new Integer(unicodeIndex)); + = unicodeToGlyphMap.get(new Integer(unicodeIndex)); if (result == null) { throw new IOException( "Glyph index not found for unicode value " + unicodeIndex); @@ -1830,4 +1899,4 @@ public class TTFFile { ioe.printStackTrace(System.err); } } -} \ No newline at end of file +} diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index dd8cb27a4..7a1a7e5c8 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -21,15 +21,13 @@ package org.apache.fop.fonts.truetype; import java.io.IOException; import java.io.InputStream; -import java.util.Iterator; -import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.io.IOUtils; - import org.apache.fop.fonts.BFEntry; import org.apache.fop.fonts.CIDFontType; +import org.apache.fop.fonts.EmbeddingMode; import org.apache.fop.fonts.EncodingMode; import org.apache.fop.fonts.FontLoader; import org.apache.fop.fonts.FontResolver; @@ -49,6 +47,7 @@ public class TTFFontLoader extends FontLoader { private SingleByteFont singleFont; private final String subFontName; private EncodingMode encodingMode; + private EmbeddingMode embeddingMode; /** * Default constructor @@ -56,7 +55,7 @@ public class TTFFontLoader extends FontLoader { * @param resolver the FontResolver for font URI resolution */ public TTFFontLoader(String fontFileURI, FontResolver resolver) { - this(fontFileURI, null, true, EncodingMode.AUTO, true, resolver); + this(fontFileURI, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, resolver); } /** @@ -65,23 +64,27 @@ public class TTFFontLoader extends FontLoader { * @param subFontName the sub-fontname of a font in a TrueType Collection (or null for normal * TrueType fonts) * @param embedded indicates whether the font is embedded or referenced + * @param embeddingMode the embedding mode of the font * @param encodingMode the requested encoding mode * @param useKerning true to enable loading kerning info if available, false to disable * @param resolver the FontResolver for font URI resolution */ public TTFFontLoader(String fontFileURI, String subFontName, - boolean embedded, EncodingMode encodingMode, boolean useKerning, - FontResolver resolver) { + boolean embedded, EmbeddingMode embeddingMode, EncodingMode encodingMode, + boolean useKerning, FontResolver resolver) { super(fontFileURI, embedded, true, resolver); this.subFontName = subFontName; this.encodingMode = encodingMode; + this.embeddingMode = embeddingMode; if (this.encodingMode == EncodingMode.AUTO) { this.encodingMode = EncodingMode.CID; //Default to CID mode for TrueType } + if (this.embeddingMode == EmbeddingMode.AUTO) { + this.embeddingMode = EmbeddingMode.SUBSET; + } } /** {@inheritDoc} */ - @Override protected void read() throws IOException { read(this.subFontName); } @@ -144,7 +147,7 @@ public class TTFFontLoader extends FontLoader { returnFont.setItalicAngle(Integer.parseInt(ttf.getItalicAngle())); returnFont.setMissingWidth(0); returnFont.setWeight(ttf.getWeightClass()); - + returnFont.setEmbeddingMode(this.embeddingMode); if (isCid) { multiFont.setCIDType(CIDFontType.CIDTYPE2); int[] wx = ttf.getWidths(); @@ -168,15 +171,8 @@ public class TTFFontLoader extends FontLoader { } private BFEntry[] getCMap(TTFFile ttf) { - List entries = ttf.getCMaps(); - BFEntry[] bfentries = new BFEntry[entries.size()]; - int pos = 0; - for (TTFCmapEntry ce : ttf.getCMaps()) { - bfentries[pos] = new BFEntry(ce.getUnicodeStart(), ce.getUnicodeEnd(), - ce.getGlyphStartIndex()); - pos++; - } - return bfentries; + BFEntry[] array = new BFEntry[ttf.getCMaps().size()]; + return ttf.getCMaps().toArray(array); } private void copyWidthsSingleByte(TTFFile ttf) { @@ -184,9 +180,8 @@ public class TTFFontLoader extends FontLoader { for (int i = singleFont.getFirstChar(); i <= singleFont.getLastChar(); i++) { singleFont.setWidth(i, ttf.getCharWidth(i)); } - Iterator iter = ttf.getCMaps().listIterator(); - while (iter.hasNext()) { - TTFCmapEntry ce = (TTFCmapEntry)iter.next(); + + for (BFEntry ce : ttf.getCMaps()) { if (ce.getUnicodeStart() < 0xFFFE) { for (char u = (char)ce.getUnicodeStart(); u <= ce.getUnicodeEnd(); u++) { int codePoint = singleFont.getEncoding().mapChar(u); @@ -221,7 +216,6 @@ public class TTFFontLoader extends FontLoader { } for (Integer kpx1 : kerningSet) { - Map h2; if (isCid) { h2 = ttf.getKerning().get(kpx1); diff --git a/src/java/org/apache/fop/fonts/truetype/TTFGlyphOutputStream.java b/src/java/org/apache/fop/fonts/truetype/TTFGlyphOutputStream.java new file mode 100644 index 000000000..ee3101f9b --- /dev/null +++ b/src/java/org/apache/fop/fonts/truetype/TTFGlyphOutputStream.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts.truetype; + +import java.io.IOException; + +/** + * This is an interface for streaming individual glyphs from the glyf table in a True Type font. + */ +public interface TTFGlyphOutputStream { + /** + * Begins the streaming of glyphs. + * @throws IOException file write exception + */ + void startGlyphStream() throws IOException; + + /** + * Streams an individual glyph at offset from a byte array. + * @param byteArray byte[] the font byte array. + * @param offset int the starting position to stream from. + * @param length int the number of bytes to stream. + * @throws IOException file write exception. + */ + void streamGlyph(byte[] byteArray, int offset, int length) throws IOException; + + /** + * Ends the streaming of glyphs. + * @throws IOException file write exception. + */ + void endGlyphStream() throws IOException; +} diff --git a/src/java/org/apache/fop/fonts/truetype/TTFOutputStream.java b/src/java/org/apache/fop/fonts/truetype/TTFOutputStream.java new file mode 100644 index 000000000..8fb8a5cc7 --- /dev/null +++ b/src/java/org/apache/fop/fonts/truetype/TTFOutputStream.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts.truetype; + +import java.io.IOException; + +/** + * This is an interface for streaming True Type font. + */ +public interface TTFOutputStream { + /** + * Starts writing the font to file. + * @throws IOException file write exception. + */ + void startFontStream() throws IOException; + + /** + * Returns an object for streaming True Type tables. + * @return {@link TTFTableOutputStream} + */ + TTFTableOutputStream getTableOutputStream(); + + /** + * Returns an object for streaming True Type glyphs in the glyf table. + * @return {@link TTFGlyphOutputStream} + */ + TTFGlyphOutputStream getGlyphOutputStream(); + + /** + * Ends writing the font to file. + * @throws IOException file write exception. + */ + void endFontStream() throws IOException; +} diff --git a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java index cf3f55b7d..5bd93ce81 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java @@ -20,8 +20,10 @@ package org.apache.fop.fonts.truetype; import java.io.IOException; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.SortedSet; /** @@ -34,10 +36,6 @@ import java.util.Map; */ public class TTFSubSetFile extends TTFFile { - private static enum OperatingMode { - PDF, POSTSCRIPT_GLYPH_DIRECTORY; - } - private byte[] output = null; private int realSize = 0; private int currentPos = 0; @@ -46,27 +44,25 @@ public class TTFSubSetFile extends TTFFile { * Offsets in name table to be filled out by table. * The offsets are to the checkSum field */ - private Map offsets = new java.util.HashMap(); - private int glyfDirOffset = 0; - private int headDirOffset = 0; - private int hmtxDirOffset = 0; - private int locaDirOffset = 0; - private int maxpDirOffset = 0; + private Map offsets = new HashMap(); private int checkSumAdjustmentOffset = 0; private int locaOffset = 0; - private int determineTableCount(OperatingMode operatingMode) { - int numTables = 4; //4 req'd tables: head,hhea,hmtx,maxp + /** Stores the glyph offsets so that we can end strings at glyph boundaries */ + private int[] glyphOffsets; + + /** The dir tab entries in the new subset font. */ + private Map newDirTabs + = new HashMap(); + + private int determineTableCount() { + int numTables = 4; //4 req'd tables: head,hhea,hmtx,maxp, if (isCFF()) { throw new UnsupportedOperationException( "OpenType fonts with CFF glyphs are not supported"); } else { - if (operatingMode == OperatingMode.POSTSCRIPT_GLYPH_DIRECTORY) { - numTables++; //1 table: gdir - } else { - numTables += 2; //2 req'd tables: glyf,loca - } + numTables += 5; //5 req'd tables: glyf,loca,post,name,OS/2 if (hasCvt()) { numTables++; } @@ -83,8 +79,8 @@ public class TTFSubSetFile extends TTFFile { /** * Create the directory table */ - private void createDirectory(OperatingMode operatingMode) { - int numTables = determineTableCount(operatingMode); + private void createDirectory() { + int numTables = determineTableCount(); // Create the TrueType header writeByte((byte)0); writeByte((byte)1); @@ -97,7 +93,7 @@ public class TTFSubSetFile extends TTFFile { // Create searchRange, entrySelector and rangeShift int maxPow = maxPow2(numTables); - int searchRange = maxPow * 16; + int searchRange = (int) Math.pow(2, maxPow) * 16; writeUShort(searchRange); realSize += 2; @@ -106,83 +102,47 @@ public class TTFSubSetFile extends TTFFile { writeUShort((numTables * 16) - searchRange); realSize += 2; + // Create space for the table entries (these must be in ASCII alphabetical order[A-Z]then[a-z]) + writeTableName(TTFTableName.OS2); - // Create space for the table entries if (hasCvt()) { - writeString("cvt "); - offsets.put("cvt ", currentPos); - currentPos += 12; - realSize += 16; + writeTableName(TTFTableName.CVT); } - if (hasFpgm()) { - writeString("fpgm"); - offsets.put("fpgm", currentPos); - currentPos += 12; - realSize += 16; - } - - if (operatingMode != OperatingMode.POSTSCRIPT_GLYPH_DIRECTORY) { - writeString("glyf"); - glyfDirOffset = currentPos; - currentPos += 12; - realSize += 16; - } - - writeString("head"); - headDirOffset = currentPos; - currentPos += 12; - realSize += 16; - - writeString("hhea"); - offsets.put("hhea", currentPos); - currentPos += 12; - realSize += 16; - - writeString("hmtx"); - hmtxDirOffset = currentPos; - currentPos += 12; - realSize += 16; - - if (operatingMode != OperatingMode.POSTSCRIPT_GLYPH_DIRECTORY) { - writeString("loca"); - locaDirOffset = currentPos; - currentPos += 12; - realSize += 16; + writeTableName(TTFTableName.FPGM); + } + writeTableName(TTFTableName.GLYF); + writeTableName(TTFTableName.HEAD); + writeTableName(TTFTableName.HHEA); + writeTableName(TTFTableName.HMTX); + writeTableName(TTFTableName.LOCA); + writeTableName(TTFTableName.MAXP); + writeTableName(TTFTableName.NAME); + writeTableName(TTFTableName.POST); + if (hasPrep()) { + writeTableName(TTFTableName.PREP); } + newDirTabs.put(TTFTableName.DIRECTORY_TABLE, new TTFDirTabEntry(0, currentPos)); + } - writeString("maxp"); - maxpDirOffset = currentPos; + private void writeTableName(TTFTableName tableName) { + writeString(tableName.getName()); + offsets.put(tableName, currentPos); currentPos += 12; realSize += 16; - - if (hasPrep()) { - writeString("prep"); - offsets.put("prep", currentPos); - currentPos += 12; - realSize += 16; - } - - if (operatingMode == OperatingMode.POSTSCRIPT_GLYPH_DIRECTORY) { - //"gdir" indicates to the PostScript interpreter that the GlyphDirectory approach - //is in use. - writeString("gdir"); - currentPos += 12; - realSize += 16; - } } private boolean hasCvt() { - return dirTabs.containsKey("cvt "); + return dirTabs.containsKey(TTFTableName.CVT); } private boolean hasFpgm() { - return dirTabs.containsKey("fpgm"); + return dirTabs.containsKey(TTFTableName.FPGM); } private boolean hasPrep() { - return dirTabs.containsKey("prep"); + return dirTabs.containsKey(TTFTableName.PREP); } /** @@ -191,26 +151,24 @@ public class TTFSubSetFile extends TTFFile { private void createLoca(int size) throws IOException { pad4(); locaOffset = currentPos; - writeULong(locaDirOffset + 4, currentPos); - writeULong(locaDirOffset + 8, size * 4 + 4); + int dirTableOffset = offsets.get(TTFTableName.LOCA); + writeULong(dirTableOffset + 4, currentPos); + writeULong(dirTableOffset + 8, size * 4 + 4); currentPos += size * 4 + 4; realSize += size * 4 + 4; } - private boolean copyTable(FontFileReader in, String tableName) throws IOException { - TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get(tableName); + private boolean copyTable(FontFileReader in, TTFTableName tableName) throws IOException { + TTFDirTabEntry entry = dirTabs.get(tableName); if (entry != null) { pad4(); seekTab(in, tableName, 0); System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()), 0, output, currentPos, (int)entry.getLength()); - int checksum = getCheckSum(currentPos, (int)entry.getLength()); - int offset = offsets.get(tableName); - writeULong(offset, checksum); - writeULong(offset + 4, currentPos); - writeULong(offset + 8, (int)entry.getLength()); - currentPos += (int)entry.getLength(); - realSize += (int)entry.getLength(); + + updateCheckSum(currentPos, (int) entry.getLength(), tableName); + currentPos += (int) entry.getLength(); + realSize += (int) entry.getLength(); return true; } else { return false; @@ -221,14 +179,34 @@ public class TTFSubSetFile extends TTFFile { * Copy the cvt table as is from original font to subset font */ private boolean createCvt(FontFileReader in) throws IOException { - return copyTable(in, "cvt "); + return copyTable(in, TTFTableName.CVT); } /** * Copy the fpgm table as is from original font to subset font */ private boolean createFpgm(FontFileReader in) throws IOException { - return copyTable(in, "fpgm"); + return copyTable(in, TTFTableName.FPGM); + } + + /** + * Copy the name table as is from the original. + * @param in FontFileReader + * @return boolean + * @throws IOException exception + */ + private boolean createName(FontFileReader in) throws IOException { + return copyTable(in, TTFTableName.NAME); + } + + /** + * Copy the OS/2 table as is from the original. + * @param in + * @return + * @throws IOException + */ + private boolean createOS2(FontFileReader in) throws IOException { + return copyTable(in, TTFTableName.OS2); } /** @@ -236,18 +214,16 @@ public class TTFSubSetFile extends TTFFile { * and set num glyphs to size */ private void createMaxp(FontFileReader in, int size) throws IOException { - TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("maxp"); + TTFTableName maxp = TTFTableName.MAXP; + TTFDirTabEntry entry = dirTabs.get(maxp); if (entry != null) { pad4(); - seekTab(in, "maxp", 0); + seekTab(in, maxp, 0); System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()), 0, output, currentPos, (int)entry.getLength()); writeUShort(currentPos + 4, size); - int checksum = getCheckSum(currentPos, (int)entry.getLength()); - writeULong(maxpDirOffset, checksum); - writeULong(maxpDirOffset + 4, currentPos); - writeULong(maxpDirOffset + 8, (int)entry.getLength()); + updateCheckSum(currentPos, (int)entry.getLength(), maxp); currentPos += (int)entry.getLength(); realSize += (int)entry.getLength(); } else { @@ -255,12 +231,34 @@ public class TTFSubSetFile extends TTFFile { } } + private void createPost(FontFileReader in) throws IOException { + TTFTableName post = TTFTableName.POST; + TTFDirTabEntry entry = dirTabs.get(post); + if (entry != null) { + pad4(); + seekTab(in, post, 0); + int newTableSize = 32; // This is the post table size with glyphs truncated + byte[] newPostTable = new byte[newTableSize]; + // We only want the first 28 bytes (truncate the glyph names); + System.arraycopy(in.getBytes((int) entry.getOffset(), newTableSize), + 0, newPostTable, 0, newTableSize); + // set the post table to Format 3.0 + newPostTable[1] = 0x03; + System.arraycopy(newPostTable, 0, output, currentPos, newTableSize); + updateCheckSum(currentPos, newTableSize, post); + currentPos += newTableSize; + realSize += newTableSize; + } else { + throw new IOException("Can't find post table"); + } + } + /** * Copy the prep table as is from original font to subset font */ private boolean createPrep(FontFileReader in) throws IOException { - return copyTable(in, "prep"); + return copyTable(in, TTFTableName.PREP); } @@ -269,8 +267,18 @@ public class TTFSubSetFile extends TTFFile { * and fill in size of hmtx table */ private void createHhea(FontFileReader in, int size) throws IOException { - boolean copied = copyTable(in, "hhea"); - if (!copied) { + TTFDirTabEntry entry = dirTabs.get(TTFTableName.HHEA); + if (entry != null) { + pad4(); + seekTab(in, TTFTableName.HHEA, 0); + System.arraycopy(in.getBytes((int) entry.getOffset(), (int) entry.getLength()), 0, + output, currentPos, (int) entry.getLength()); + writeUShort((int) entry.getLength() + currentPos - 2, size); + + updateCheckSum(currentPos, (int) entry.getLength(), TTFTableName.HHEA); + currentPos += (int) entry.getLength(); + realSize += (int) entry.getLength(); + } else { throw new IOException("Can't find hhea table"); } } @@ -283,10 +291,11 @@ public class TTFSubSetFile extends TTFFile { * in checkSumAdjustmentOffset */ private void createHead(FontFileReader in) throws IOException { - TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("head"); + TTFTableName head = TTFTableName.HEAD; + TTFDirTabEntry entry = dirTabs.get(head); if (entry != null) { pad4(); - seekTab(in, "head", 0); + seekTab(in, head, 0); System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()), 0, output, currentPos, (int)entry.getLength()); @@ -298,11 +307,7 @@ public class TTFSubSetFile extends TTFFile { output[currentPos + 50] = 0; // long locaformat output[currentPos + 51] = 1; // long locaformat - int checksum = getCheckSum(currentPos, (int)entry.getLength()); - writeULong(headDirOffset, checksum); - writeULong(headDirOffset + 4, currentPos); - writeULong(headDirOffset + 8, (int)entry.getLength()); - + updateCheckSum(currentPos, (int)entry.getLength(), head); currentPos += (int)entry.getLength(); realSize += (int)entry.getLength(); } else { @@ -315,8 +320,9 @@ public class TTFSubSetFile extends TTFFile { * Create the glyf table and fill in loca table */ private void createGlyf(FontFileReader in, - Map glyphs) throws IOException { - TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf"); + Map glyphs) throws IOException { + TTFTableName glyf = TTFTableName.GLYF; + TTFDirTabEntry entry = dirTabs.get(glyf); int size = 0; int startPos = 0; int endOffset = 0; // Store this as the last loca @@ -329,6 +335,7 @@ public class TTFSubSetFile extends TTFFile { * location offset. */ int[] origIndexes = buildSubsetIndexToOrigIndexMap(glyphs); + glyphOffsets = new int[origIndexes.length]; for (int i = 0; i < origIndexes.length; i++) { int nextOffset = 0; @@ -358,27 +365,30 @@ public class TTFSubSetFile extends TTFFile { endOffset1 = (currentPos - startPos + glyphLength); } + // Store the glyph boundary positions relative to the start the font + glyphOffsets[i] = currentPos; currentPos += glyphLength; realSize += glyphLength; - endOffset = endOffset1; + endOffset = endOffset1; } + size = currentPos - startPos; - int checksum = getCheckSum(startPos, size); - writeULong(glyfDirOffset, checksum); - writeULong(glyfDirOffset + 4, startPos); - writeULong(glyfDirOffset + 8, size); currentPos += 12; realSize += 12; + updateCheckSum(startPos, size + 12, glyf); // Update loca checksum and last loca index writeULong(locaOffset + glyphs.size() * 4, endOffset); - - checksum = getCheckSum(locaOffset, glyphs.size() * 4 + 4); - writeULong(locaDirOffset, checksum); + int locaSize = glyphs.size() * 4 + 4; + int checksum = getCheckSum(output, locaOffset, locaSize); + writeULong(offsets.get(TTFTableName.LOCA), checksum); + int padSize = (locaOffset + locaSize) % 4; + newDirTabs.put(TTFTableName.LOCA, + new TTFDirTabEntry(locaOffset, locaSize + padSize)); } else { throw new IOException("Can't find glyf table"); } @@ -402,7 +412,8 @@ public class TTFSubSetFile extends TTFFile { */ private void createHmtx(FontFileReader in, Map glyphs) throws IOException { - TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hmtx"); + TTFTableName hmtx = TTFTableName.HMTX; + TTFDirTabEntry entry = dirTabs.get(hmtx); int longHorMetricSize = glyphs.size() * 2; int leftSideBearingSize = glyphs.size() * 2; @@ -421,10 +432,7 @@ public class TTFSubSetFile extends TTFFile { mtxTab[origIndex.intValue()].getLsb()); } - int checksum = getCheckSum(currentPos, hmtxSize); - writeULong(hmtxDirOffset, checksum); - writeULong(hmtxDirOffset + 4, currentPos); - writeULong(hmtxDirOffset + 8, hmtxSize); + updateCheckSum(currentPos, hmtxSize, hmtx); currentPos += hmtxSize; realSize += hmtxSize; } else { @@ -540,16 +548,16 @@ public class TTFSubSetFile extends TTFFile { */ private void scanGlyphs(FontFileReader in, Map glyphs) throws IOException { - TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf"); + TTFDirTabEntry entry = dirTabs.get(TTFTableName.GLYF); Map newComposites = null; - Map allComposites = new java.util.HashMap(); + Map allComposites = new HashMap(); int newIndex = glyphs.size(); if (entry != null) { while (newComposites == null || newComposites.size() > 0) { // Inefficient to iterate through all glyphs - newComposites = new java.util.HashMap(); + newComposites = new HashMap(); for (Map.Entry glyph : glyphs.entrySet()) { int origIndex = glyph.getKey(); @@ -591,46 +599,38 @@ public class TTFSubSetFile extends TTFFile { } } - - /** - * Returns a subset of the original font. + * Reads a font and creates a subset of the font. * * @param in FontFileReader to read from * @param name Name to be checked for in the font file * @param glyphs Map of glyphs (glyphs has old index as (Integer) key and * new index as (Integer) value) - * @return A subset of the original font * @throws IOException in case of an I/O problem */ - public byte[] readFont(FontFileReader in, String name, + public void readFont(FontFileReader in, String name, Map glyphs) throws IOException { - + fontFile = in; //Check if TrueType collection, and that the name exists in the collection - if (!checkTTC(in, name)) { + if (!checkTTC(name)) { throw new IOException("Failed to read font"); } //Copy the Map as we're going to modify it - Map subsetGlyphs = new java.util.HashMap(glyphs); + Map subsetGlyphs = new HashMap(glyphs); output = new byte[in.getFileSize()]; - readDirTabs(in); - readFontHeader(in); - getNumGlyphs(in); - readHorizontalHeader(in); - readHorizontalMetrics(in); - readIndexToLocation(in); + readDirTabs(); + readFontHeader(); + getNumGlyphs(); + readHorizontalHeader(); + readHorizontalMetrics(); + readIndexToLocation(); scanGlyphs(in, subsetGlyphs); - createDirectory(OperatingMode.PDF); // Create the TrueType header and directory - - createHead(in); - createHhea(in, subsetGlyphs.size()); // Create the hhea table - createHmtx(in, subsetGlyphs); // Create hmtx table - createMaxp(in, subsetGlyphs.size()); // copy the maxp table + createDirectory(); // Create the TrueType header and directory boolean optionalTableFound; optionalTableFound = createCvt(in); // copy the cvt table @@ -644,78 +644,16 @@ public class TTFSubSetFile extends TTFFile { // fpgm is optional (used in TrueType fonts only) log.debug("TrueType: fpgm table not present. Skipped."); } - - optionalTableFound = createPrep(in); // copy prep table - if (!optionalTableFound) { - // prep is optional (used in TrueType fonts only) - log.debug("TrueType: prep table not present. Skipped."); - } - createLoca(subsetGlyphs.size()); // create empty loca table - createGlyf(in, subsetGlyphs); //create glyf table and update loca table - - pad4(); - createCheckSumAdjustment(); - - byte[] ret = new byte[realSize]; - System.arraycopy(output, 0, ret, 0, realSize); - - return ret; - } - - /** - * Returns a subset of the original font suitable for use in PostScript programs. - * - * @param in FontFileReader to read from - * @param name Name to be checked for in the font file - * @param glyphs Map of glyphs (glyphs has old index as (Integer) key and - * new index as (Integer) value) - * @param glyphHandler the handler to receive all glyphs of the subset - * @return A subset of the original font - * @throws IOException in case of an I/O problem - */ - public byte[] toPostScriptSubset(FontFileReader in, String name, - Map glyphs, GlyphHandler glyphHandler) throws IOException { - - //Check if TrueType collection, and that the name exists in the collection - if (!checkTTC(in, name)) { - throw new IOException("Failed to read font"); - } - - //Copy the Map as we're going to modify it - Map subsetGlyphs = new java.util.HashMap(glyphs); - - output = new byte[in.getFileSize()]; - - readDirTabs(in); - readFontHeader(in); - getNumGlyphs(in); - readHorizontalHeader(in); - readHorizontalMetrics(in); - readIndexToLocation(in); - - scanGlyphs(in, subsetGlyphs); - - // Create the TrueType header and directory - createDirectory(OperatingMode.POSTSCRIPT_GLYPH_DIRECTORY); + createGlyf(in, subsetGlyphs); //create glyf table and update loca table + createOS2(in); // copy the OS/2 table createHead(in); createHhea(in, subsetGlyphs.size()); // Create the hhea table createHmtx(in, subsetGlyphs); // Create hmtx table createMaxp(in, subsetGlyphs.size()); // copy the maxp table - - boolean optionalTableFound; - optionalTableFound = createCvt(in); // copy the cvt table - if (!optionalTableFound) { - // cvt is optional (used in TrueType fonts only) - log.debug("TrueType: ctv table not present. Skipped."); - } - - optionalTableFound = createFpgm(in); // copy fpgm table - if (!optionalTableFound) { - // fpgm is optional (used in TrueType fonts only) - log.debug("TrueType: fpgm table not present. Skipped."); - } + createName(in); // copy the name table + createPost(in); // copy the post table optionalTableFound = createPrep(in); // copy prep table if (!optionalTableFound) { @@ -723,59 +661,54 @@ public class TTFSubSetFile extends TTFFile { log.debug("TrueType: prep table not present. Skipped."); } - //Send all the glyphs from the subset - handleGlyphSubset(in, subsetGlyphs, glyphHandler); - pad4(); createCheckSumAdjustment(); + } + /** + * Returns a subset of the fonts (readFont() MUST be called first in order to create the + * subset). + * @return byte array + */ + public byte[] getFontSubset() { byte[] ret = new byte[realSize]; System.arraycopy(output, 0, ret, 0, realSize); - return ret; } - private void handleGlyphSubset(FontFileReader in, Map glyphs, - GlyphHandler glyphHandler) throws IOException { - TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf"); - if (entry != null) { - - int[] origIndexes = buildSubsetIndexToOrigIndexMap(glyphs); - - for (int i = 0; i < origIndexes.length; i++) { - int nextOffset = 0; - int origGlyphIndex = origIndexes[i]; - if (origGlyphIndex >= (mtxTab.length - 1)) { - nextOffset = (int)lastLoca; - } else { - nextOffset = (int)mtxTab[origGlyphIndex + 1].getOffset(); - } - int glyphOffset = (int)mtxTab[origGlyphIndex].getOffset(); - int glyphLength = nextOffset - glyphOffset; - - byte[] glyphData = in.getBytes( - (int)entry.getOffset() + glyphOffset, - glyphLength); - - glyphHandler.addGlyph(glyphData); + private void handleGlyphSubset(TTFGlyphOutputStream glyphOut) throws IOException { + glyphOut.startGlyphStream(); + // Stream all but the last glyph + for (int i = 0; i < glyphOffsets.length - 1; i++) { + glyphOut.streamGlyph(output, glyphOffsets[i], + glyphOffsets[i + 1] - glyphOffsets[i]); + } + // Stream the last glyph + TTFDirTabEntry glyf = newDirTabs.get(TTFTableName.GLYF); + long lastGlyphLength = glyf.getLength() + - (glyphOffsets[glyphOffsets.length - 1] - glyf.getOffset()); + glyphOut.streamGlyph(output, glyphOffsets[glyphOffsets.length - 1], + (int) lastGlyphLength); + glyphOut.endGlyphStream(); + } + + @Override + public void stream(TTFOutputStream ttfOut) throws IOException { + SortedSet> sortedDirTabs + = sortDirTabMap(newDirTabs); + TTFTableOutputStream tableOut = ttfOut.getTableOutputStream(); + TTFGlyphOutputStream glyphOut = ttfOut.getGlyphOutputStream(); + + ttfOut.startFontStream(); + for (Map.Entry entry : sortedDirTabs) { + if (entry.getKey().equals(TTFTableName.GLYF)) { + handleGlyphSubset(glyphOut); + } else { + tableOut.streamTable(output, (int) entry.getValue().getOffset(), + (int) entry.getValue().getLength()); } - } else { - throw new IOException("Can't find glyf table"); } - } - - /** - * Used as callback to handle a number of glyphs. - */ - public static interface GlyphHandler { - - /** - * Adds a glyph. - * @param glyphData the glyph data - * @throws IOException if an I/O error occurs - */ - void addGlyph(byte[] glyphData) throws IOException; - + ttfOut.endFontStream(); } /** @@ -827,20 +760,6 @@ public class TTFSubSetFile extends TTFFile { output[pos + 1] = b2; } - /** - * Appends a ULONG to the output array, - * updates currentPos but not realSize - */ - private void writeULong(int s) { - byte b1 = (byte)((s >> 24) & 0xff); - byte b2 = (byte)((s >> 16) & 0xff); - byte b3 = (byte)((s >> 8) & 0xff); - byte b4 = (byte)(s & 0xff); - writeByte(b1); - writeByte(b2); - writeByte(b3); - writeByte(b4); - } /** * Appends a ULONG to the output array, @@ -857,41 +776,17 @@ public class TTFSubSetFile extends TTFFile { output[pos + 3] = b4; } - /** - * Read a signed short value at given position - */ - private short readShort(int pos) { - int ret = readUShort(pos); - return (short)ret; - } - - /** - * Read a unsigned short value at given position - */ - private int readUShort(int pos) { - int ret = output[pos]; - if (ret < 0) { - ret += 256; - } - ret = ret << 8; - if (output[pos + 1] < 0) { - ret |= output[pos + 1] + 256; - } else { - ret |= output[pos + 1]; - } - - return ret; - } - /** * Create a padding in the fontfile to align * on a 4-byte boundary */ private void pad4() { - int padSize = currentPos % 4; - for (int i = 0; i < padSize; i++) { - output[currentPos++] = 0; - realSize++; + int padSize = getPadSize(currentPos); + if (padSize < 4) { + for (int i = 0; i < padSize; i++) { + output[currentPos++] = 0; + realSize++; + } } } @@ -900,23 +795,25 @@ public class TTFSubSetFile extends TTFFile { */ private int maxPow2(int max) { int i = 0; - while (Math.pow(2, i) < max) { + while (Math.pow(2, i) <= max) { i++; } return (i - 1); } - private int log2(int num) { - return (int)(Math.log(num) / Math.log(2)); - } - - private int getCheckSum(int start, int size) { - return (int)getLongCheckSum(output, start, size); + private void updateCheckSum(int tableStart, int tableSize, TTFTableName tableName) { + int checksum = getCheckSum(output, tableStart, tableSize); + int offset = offsets.get(tableName); + int padSize = getPadSize(tableStart + tableSize); + newDirTabs.put(tableName, new TTFDirTabEntry(tableStart, tableSize + padSize)); + writeULong(offset, checksum); + writeULong(offset + 4, tableStart); + writeULong(offset + 8, tableSize); } - private static long getLongCheckSum(byte[] data, int start, int size) { + private static int getCheckSum(byte[] data, int start, int size) { // All the tables here are aligned on four byte boundaries // Add remainder to size if it's not a multiple of 4 int remainder = size % 4; @@ -927,26 +824,19 @@ public class TTFSubSetFile extends TTFFile { long sum = 0; for (int i = 0; i < size; i += 4) { - int l = (data[start + i] << 24); - l += (data[start + i + 1] << 16); - l += (data[start + i + 2] << 16); - l += (data[start + i + 3] << 16); - sum += l; - if (sum > 0xffffffff) { - sum = sum - 0xffffffff; + long l = 0; + for (int j = 0; j < 4; j++) { + l <<= 8; + l |= data[start + i + j] & 0xff; } + sum += l; } - - return sum; + return (int) sum; } private void createCheckSumAdjustment() { - long sum = getLongCheckSum(output, 0, realSize); + long sum = getCheckSum(output, 0, realSize); int checksum = (int)(0xb1b0afba - sum); writeULong(checkSumAdjustmentOffset, checksum); } - } - - - diff --git a/src/java/org/apache/fop/fonts/truetype/TTFTableName.java b/src/java/org/apache/fop/fonts/truetype/TTFTableName.java new file mode 100644 index 000000000..e8e66a8ba --- /dev/null +++ b/src/java/org/apache/fop/fonts/truetype/TTFTableName.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts.truetype; + + +/** + * This class holds the True Type Format table names as in the Directory Table of a TTF font file. + * This class must also support custom tables found in fonts (thus an enum wasn't used). + */ +public final class TTFTableName { + /** The first table in a True Type font file containing metadata about other tables. */ + public static final TTFTableName DIRECTORY_TABLE = new TTFTableName("dirTable"); + + /** Embedded bitmap data */ + public static final TTFTableName EBDT = new TTFTableName("EBDT"); + + /** Embedded bitmap location data */ + public static final TTFTableName EBLC = new TTFTableName("EBLC"); + + /** Embedded bitmap scaling data */ + public static final TTFTableName EBSC = new TTFTableName("EBSC"); + + /** A font forge specific table */ + public static final TTFTableName FFTM = new TTFTableName("FFTM"); + + /** Divides glyphs into various classes that make using the GPOS/GSUB tables easier. */ + public static final TTFTableName GDEF = new TTFTableName("GDEF"); + + /** Provides kerning information, mark-to-base, etc. for opentype fonts */ + public static final TTFTableName GPOS = new TTFTableName("GPOS"); + + /** Provides ligature information, swash, etc. for opentype fonts */ + public static final TTFTableName GSUB = new TTFTableName("GSUB"); + + /** Linear threshold table */ + public static final TTFTableName LTSH = new TTFTableName("LTSH"); + + /** OS/2 and Windows specific metrics */ + public static final TTFTableName OS2 = new TTFTableName("OS/2"); + + /** PCL 5 data*/ + public static final TTFTableName PCLT = new TTFTableName("PCLT"); + + /** Vertical Device Metrics table */ + public static final TTFTableName VDMX = new TTFTableName("VDMX"); + + /** character to glyph mapping */ + public static final TTFTableName CMAP = new TTFTableName("cmap"); + + /** Control Value Table */ + public static final TTFTableName CVT = new TTFTableName("cvt "); + + /** font program */ + public static final TTFTableName FPGM = new TTFTableName("fpgm"); + + /** grid-fitting and scan conversion procedure (grayscale) */ + public static final TTFTableName GASP = new TTFTableName("gasp"); + + /** glyph data */ + public static final TTFTableName GLYF = new TTFTableName("glyf"); + + /** horizontal device metrics */ + public static final TTFTableName HDMX = new TTFTableName("hdmx"); + + /** font header */ + public static final TTFTableName HEAD = new TTFTableName("head"); + + /** horizontal header */ + public static final TTFTableName HHEA = new TTFTableName("hhea"); + + /** horizontal metrics */ + public static final TTFTableName HMTX = new TTFTableName("hmtx"); + + /** kerning */ + public static final TTFTableName KERN = new TTFTableName("kern"); + + /** index to location */ + public static final TTFTableName LOCA = new TTFTableName("loca"); + + /** maximum profile */ + public static final TTFTableName MAXP = new TTFTableName("maxp"); + + /** naming table */ + public static final TTFTableName NAME = new TTFTableName("name"); + + /** PostScript information */ + public static final TTFTableName POST = new TTFTableName("post"); + + /** CVT Program */ + public static final TTFTableName PREP = new TTFTableName("prep"); + + /** Vertical Metrics header */ + public static final TTFTableName VHEA = new TTFTableName("vhea"); + + /** Vertical Metrics */ + public static final TTFTableName VMTX = new TTFTableName("vmtx"); + + private final String name; + + private TTFTableName(String name) { + this.name = name; + } + + /** + * Returns the name of the table as it should be in the Table Directory. + * @return String + */ + public String getName() { + return name; + } + + /** + * Returns the appropriate TTFTableName object when given the string representation. + * @param tableName table name as in the Directory Table. + * @return TTFTableName + */ + public static TTFTableName getValue(String tableName) { + if (tableName != null) { + return new TTFTableName(tableName); + } + throw new IllegalArgumentException("A TrueType font table name must not be null"); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof TTFTableName)) { + return false; + } + TTFTableName to = (TTFTableName) o; + return this.name.equals(to.getName()); + } + +} diff --git a/src/java/org/apache/fop/fonts/truetype/TTFTableOutputStream.java b/src/java/org/apache/fop/fonts/truetype/TTFTableOutputStream.java new file mode 100644 index 000000000..75f0ef63d --- /dev/null +++ b/src/java/org/apache/fop/fonts/truetype/TTFTableOutputStream.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts.truetype; + +import java.io.IOException; + +/** + * An interface for streaming full True Type tables from a TTF file. + */ +public interface TTFTableOutputStream { + + /** + * Streams a table defined in byteArray at offset of length bytes. + * @param byteArray The source of the table to stream from. + * @param offset The position in byteArray to begin streaming from. + * @param length The number of bytes to stream. + * @throws IOException write error. + */ + void streamTable(byte[] byteArray, int offset, int length) throws IOException; +} diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java index 752d14207..2f83f76d1 100644 --- a/src/java/org/apache/fop/pdf/PDFFactory.java +++ b/src/java/org/apache/fop/pdf/PDFFactory.java @@ -39,9 +39,6 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - -import org.apache.xmlgraphics.xmp.Metadata; - import org.apache.fop.fonts.CIDFont; import org.apache.fop.fonts.CIDSubset; import org.apache.fop.fonts.CodePointMapping; @@ -59,6 +56,7 @@ import org.apache.fop.fonts.truetype.FontFileReader; import org.apache.fop.fonts.truetype.TTFSubSetFile; import org.apache.fop.fonts.type1.PFBData; import org.apache.fop.fonts.type1.PFBParser; +import org.apache.xmlgraphics.xmp.Metadata; /** * This class provides method to create and register PDF objects. @@ -1663,8 +1661,8 @@ public class PDFFactory { FontFileReader reader = new FontFileReader(in); TTFSubSetFile subset = new TTFSubSetFile(); - byte[] subsetFont = subset.readFont(reader, - mbfont.getTTCName(), mbfont.getUsedGlyphs()); + subset.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs()); + byte[] subsetFont = subset.getFontSubset(); // Only TrueType CID fonts are supported now embeddedFont = new PDFTTFStream(subsetFont.length); diff --git a/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java b/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java index fb88b8bce..08cfd3fc4 100644 --- a/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java +++ b/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java @@ -25,7 +25,6 @@ import javax.xml.transform.Source; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.EmbedFontInfo; import org.apache.fop.fonts.EncodingMode; @@ -88,8 +87,8 @@ public class ConfiguredFontCollection implements FontCollection { font = new CustomFontMetricsMapper(fontMetrics, fontSource); } else { CustomFont fontMetrics = FontLoader.loadFont( - fontFile, null, true, EncodingMode.AUTO, - configFontInfo.getKerning(), fontResolver); + fontFile, null, true, configFontInfo.getEmbeddingMode(), + EncodingMode.AUTO, configFontInfo.getKerning(), fontResolver); font = new CustomFontMetricsMapper(fontMetrics); } diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index 9df0aa030..157f4f419 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -23,7 +23,10 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; @@ -36,13 +39,13 @@ import org.apache.xmlgraphics.ps.DSCConstants; import org.apache.xmlgraphics.ps.PSGenerator; import org.apache.xmlgraphics.ps.PSResource; import org.apache.xmlgraphics.ps.dsc.ResourceTracker; -import org.apache.xmlgraphics.util.io.ASCIIHexOutputStream; import org.apache.fop.fonts.BFEntry; import org.apache.fop.fonts.Base14Font; import org.apache.fop.fonts.CIDFontType; import org.apache.fop.fonts.CIDSubset; import org.apache.fop.fonts.CustomFont; +import org.apache.fop.fonts.EmbeddingMode; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontType; @@ -52,8 +55,11 @@ import org.apache.fop.fonts.SingleByteEncoding; import org.apache.fop.fonts.SingleByteFont; import org.apache.fop.fonts.Typeface; import org.apache.fop.fonts.truetype.FontFileReader; +import org.apache.fop.fonts.truetype.TTFFile; +import org.apache.fop.fonts.truetype.TTFOutputStream; import org.apache.fop.fonts.truetype.TTFSubSetFile; import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; +import org.apache.fop.render.ps.fonts.PSTTFOutputStream; import org.apache.fop.util.HexEncoder; /** @@ -63,7 +69,6 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { /** logging instance */ protected static final Log log = LogFactory.getLog(PSFontUtils.class); - /** * Generates the PostScript code for the font dictionary. This method should only be * used if no "resource optimization" is performed, i.e. when the fonts are not embedded @@ -119,11 +124,12 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { * @return a Map of PSResource instances representing all defined fonts (key: font key) * @throws IOException in case of an I/O problem */ - private static Map writeFontDict(PSGenerator gen, FontInfo fontInfo, Map fonts, - boolean encodeAllCharacters, PSEventProducer eventProducer) throws IOException { + private static Map writeFontDict(PSGenerator gen, FontInfo fontInfo, + Map fonts, boolean encodeAllCharacters, PSEventProducer eventProducer) + throws IOException { gen.commentln("%FOPBeginFontDict"); - Map fontResources = new java.util.HashMap(); + Map fontResources = new HashMap(); for (String key : fonts.keySet()) { Typeface tf = getTypeFace(fontInfo, fonts, key); PSResource fontRes = new PSResource(PSResource.TYPE_FONT, tf.getEmbedFontName()); @@ -219,57 +225,52 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { private static PSFontResource embedFont(PSGenerator gen, Typeface tf, PSResource fontRes, PSEventProducer eventProducer) throws IOException { - boolean embeddedFont = false; FontType fontType = tf.getFontType(); 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()) { - checkPostScriptLevel3(gen, eventProducer); - /* - * First CID-keyed font to be embedded; add - * %%IncludeResource: comment for ProcSet CIDInit. - */ - gen.includeProcsetCIDInitResource(); - } - PSResource cidFontResource = embedType2CIDFont(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); - fontResource = PSFontResource.createFontResource(fontRes); - } else if (fontType == FontType.TRUETYPE) { - embedTrueTypeFont(gen, (SingleByteFont) tf, in); - fontResource = PSFontResource.createFontResource(fontRes); - } else { - composeType0Font(gen, (MultiByteFont) tf, in); - } - gen.writeDSCComment(DSCConstants.END_RESOURCE); - gen.getResourceTracker().registerSuppliedResource(fontRes); - embeddedFont = true; - } else { - gen.commentln("%WARNING: Could not embed font: " + cf.getEmbedFontName()); - log.warn("Font " + cf.getEmbedFontName() + " is marked as supplied in the" - + " PostScript file but could not be embedded!"); - } - } - } - } - if (!embeddedFont) { + if (!(fontType == FontType.TYPE1 || fontType == FontType.TRUETYPE + || fontType == FontType.TYPE0) || !(tf instanceof CustomFont)) { gen.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, fontRes); fontResource = PSFontResource.createFontResource(fontRes); + return fontResource; + } + CustomFont cf = (CustomFont)tf; + if (isEmbeddable(cf)) { + InputStream in = getInputStreamOnFont(gen, cf); + if (in == null) { + gen.commentln("%WARNING: Could not embed font: " + cf.getEmbedFontName()); + log.warn("Font " + cf.getEmbedFontName() + " is marked as supplied in the" + + " PostScript file but could not be embedded!"); + gen.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, fontRes); + fontResource = PSFontResource.createFontResource(fontRes); + return fontResource; + } + if (fontType == FontType.TYPE0) { + if (gen.embedIdentityH()) { + checkPostScriptLevel3(gen, eventProducer); + /* + * First CID-keyed font to be embedded; add + * %%IncludeResource: comment for ProcSet CIDInit. + */ + gen.includeProcsetCIDInitResource(); + } + PSResource cidFontResource = embedType2CIDFont(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); + fontResource = PSFontResource.createFontResource(fontRes); + } else if (fontType == FontType.TRUETYPE) { + embedTrueTypeFont(gen, (SingleByteFont) tf, in); + fontResource = PSFontResource.createFontResource(fontRes); + } else { + composeType0Font(gen, (MultiByteFont) tf, in); + } + gen.writeDSCComment(DSCConstants.END_RESOURCE); + gen.getResourceTracker().registerSuppliedResource(fontRes); } return fontResource; } @@ -292,12 +293,28 @@ 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.getCMap()); + if (font.getEmbeddingMode() == EmbeddingMode.AUTO) { + font.setEmbeddingMode(EmbeddingMode.SUBSET); + } + FontFileReader reader = new FontFileReader(fontStream); + // TODO is subset-embedding working? In which case the following can be factorized + // with what is in composeType0Font +// TTFFile ttfFile; +// if (font.getEmbeddingMode() != EmbeddingMode.FULL) { +// ttfFile = new TTFSubSetFile(); +// ttfFile.readFont(reader, font.getFullName()(), font.getUsedGlyphs()); +// } else { +// ttfFile = new TTFFile(); +// ttfFile.readFont(reader, font.getFullName()); +// } + TTFFile ttfFile = new TTFFile(); + ttfFile.readFont(reader, font.getFullName()); + createType42DictionaryEntries(gen, font, font.getCMap(), ttfFile); gen.writeln("FontName currentdict end definefont pop"); } private static void createType42DictionaryEntries(PSGenerator gen, CustomFont font, - InputStream fontStream, BFEntry[] cmap) throws IOException { + BFEntry[] cmap, TTFFile ttfFile) throws IOException { gen.write("/FontName /"); gen.write(font.getEmbedFontName()); gen.writeln(" def"); @@ -308,7 +325,8 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { gen.writeln("/Encoding 256 array"); gen.writeln("0 1 255{1 index exch/.notdef put}for"); boolean buildCharStrings; - if (font.getFontType() == FontType.TYPE0) { + Set glyphNames = new HashSet(); + if (font.getFontType() == FontType.TYPE0 && font.getEmbeddingMode() != EmbeddingMode.FULL) { //"/Encoding" is required but ignored for CID fonts //so we keep it minimal to save space buildCharStrings = false; @@ -323,72 +341,75 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { gen.write(Glyphs.NOTDEF); } else { gen.write(glyphName); + glyphNames.add(glyphName); } gen.writeln(" put"); } } gen.writeln("readonly def"); - gen.write("/sfnts["); - /* - * Store the font file in an array of hex-encoded strings. Strings are limited to - * 65535 characters, string will start with a newline, 2 characters are needed to - * hex-encode each byte, one newline character will be added every 40 bytes, each - * string should start at a 4-byte boundary - * => buffer size = floor((65535 - 1) * 40 / 81 / 4) * 4 - * TODO this is not robust: depends on how often ASCIIHexOutputStream adds a newline - */ - // TODO does not follow Technical Note #5012's requirements: - // "strings must begin at TrueType table boundaries, or at individual glyph - // boundaries within the glyf table." - // There may be compatibility issues with older PostScript interpreters - byte[] buffer = new byte[32360]; - int readCount; - while ((readCount = fontStream.read(buffer)) > 0) { - ASCIIHexOutputStream hexOut = new ASCIIHexOutputStream(gen.getOutputStream()); - gen.writeln("<"); - hexOut.write(buffer, 0, readCount); - gen.write("> "); - } - gen.writeln("]def"); + TTFOutputStream ttfOut = new PSTTFOutputStream(gen); + ttfFile.stream(ttfOut); + + buildCharStrings(gen, buildCharStrings, cmap, glyphNames, font); + } + + private static void buildCharStrings(PSGenerator gen, boolean buildCharStrings, + BFEntry[] cmap, Set glyphNames, CustomFont font) throws IOException { gen.write("/CharStrings "); - if (buildCharStrings) { + if (!buildCharStrings) { + gen.write(1); + } else if (font.getEmbeddingMode() != EmbeddingMode.FULL) { int charCount = 1; //1 for .notdef for (BFEntry entry : cmap) { charCount += entry.getUnicodeEnd() - entry.getUnicodeStart() + 1; } gen.write(charCount); } else { - gen.write(1); + gen.write(font.getCMap().length); } gen.writeln(" dict dup begin"); gen.write("/"); gen.write(Glyphs.NOTDEF); gen.writeln(" 0 def"); // .notdef always has to be at index 0 - if (buildCharStrings) { - //Only performed in singly-byte mode, ignored for CID fonts - + if (!buildCharStrings) { + // If we're not building the full CharStrings we can end here + gen.writeln("end readonly def"); + return; + } + if (font.getEmbeddingMode() != EmbeddingMode.FULL) { + //Only performed in singly-byte mode, ignored for CID fonts for (BFEntry entry : cmap) { int glyphIndex = entry.getGlyphStartIndex(); for (int ch = entry.getUnicodeStart(); ch <= entry.getUnicodeEnd(); ch++) { char ch16 = (char)ch; //TODO Handle Unicode characters beyond 16bit String glyphName = Glyphs.charToGlyphName(ch16); - if ("".equals(glyphName)) { glyphName = "u" + Integer.toHexString(ch).toUpperCase(); } - gen.write("/"); - gen.write(glyphName); - gen.write(" "); - gen.write(glyphIndex); - gen.writeln(" def"); + writeGlyphDefs(gen, glyphName, glyphIndex); glyphIndex++; } } + } else { + for (String name : glyphNames) { + writeGlyphDefs(gen, name, + getGlyphIndex(Glyphs.getUnicodeSequenceForGlyphName(name).charAt(0), + font.getCMap())); + } } gen.writeln("end readonly def"); } + private static void writeGlyphDefs(PSGenerator gen, String glyphName, int glyphIndex) + throws IOException { + gen.write("/"); + gen.write(glyphName); + gen.write(" "); + gen.write(glyphIndex); + gen.writeln(" def"); + } + private static int getGlyphIndex(char c, BFEntry[] cmap) { for (BFEntry entry : cmap) { if (entry.getUnicodeStart() <= c && c <= entry.getUnicodeEnd()) { @@ -408,7 +429,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { gen.writeln("] composefont pop"); } - private static PSResource embedType2CIDFont(final PSGenerator gen, + private static PSResource embedType2CIDFont(PSGenerator gen, MultiByteFont font, InputStream fontStream) throws IOException { assert font.getCIDType() == CIDFontType.CIDTYPE2; @@ -467,30 +488,28 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { lineCount = 1; } } - String gid = HexEncoder.encode(cid, 4); + String gid; + if (font.getEmbeddingMode() != EmbeddingMode.FULL) { + gid = HexEncoder.encode(cid, 4); + } else { + gid = HexEncoder.encode(cidSubset.getGlyphIndexForSubsetIndex(cid), 4); + } gen.write(gid); } gen.writeln(">] def"); + FontFileReader reader = new FontFileReader(fontStream); - //Create tables for subset - TTFSubSetFile subset = new TTFSubSetFile(); - TTFSubSetFile.GlyphHandler glyphHandler = new TTFSubSetFile.GlyphHandler() { + TTFFile ttfFile; + if (font.getEmbeddingMode() != EmbeddingMode.FULL) { + ttfFile = new TTFSubSetFile(); + ttfFile.readFont(reader, font.getTTCName(), font.getUsedGlyphs()); + } else { + ttfFile = new TTFFile(); + ttfFile.readFont(reader, font.getTTCName()); + } - public void addGlyph(byte[] glyphData) throws IOException { - ASCIIHexOutputStream hexOut = new ASCIIHexOutputStream(gen.getOutputStream()); - gen.writeln("<"); - hexOut.write(glyphData); - gen.writeln(">"); - } - }; - gen.writeln("/GlyphDirectory ["); - FontFileReader reader = new FontFileReader(fontStream); - byte[] subsetFont = subset.toPostScriptSubset(reader, - font.getTTCName(), font.getUsedGlyphs(), glyphHandler); - gen.writeln("] def"); - InputStream subsetInput = new java.io.ByteArrayInputStream(subsetFont); - createType42DictionaryEntries(gen, font, subsetInput, new BFEntry[0]); + createType42DictionaryEntries(gen, font, new BFEntry[0], ttfFile); gen.writeln("CIDFontName currentdict end /CIDFont defineresource pop"); gen.writeln("end"); gen.writeln("%%EndResource"); @@ -702,5 +721,4 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { gen.getResourceTracker().registerSuppliedResource(res); return res; } - } diff --git a/src/java/org/apache/fop/render/ps/PSPainter.java b/src/java/org/apache/fop/render/ps/PSPainter.java index 5ed217db1..2821f6c67 100644 --- a/src/java/org/apache/fop/render/ps/PSPainter.java +++ b/src/java/org/apache/fop/render/ps/PSPainter.java @@ -404,8 +404,7 @@ public class PSPainter extends AbstractIFPainter { } } - private void writeText( // CSOK: ParameterNumber - String text, int start, int len, + private void writeText(String text, int start, int len, int letterSpacing, int wordSpacing, int[] dx, Font font, Typeface tf, boolean multiByte) throws IOException { PSGenerator generator = getGenerator(); @@ -416,16 +415,6 @@ 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); @@ -467,9 +456,7 @@ public class PSPainter extends AbstractIFPainter { sb.append(PSGenerator.LF); lineStart = sb.length(); } - sb.append(strOpen); - sb.append(accText); - sb.append(strClose); + lineStart = writePostScriptString(sb, accText, multiByte, lineStart); sb.append(' '); accText.setLength(0); //reset accumulated text } @@ -478,9 +465,10 @@ public class PSPainter extends AbstractIFPainter { } if (needTJ) { if (accText.length() > 0) { - sb.append(strOpen); - sb.append(accText); - sb.append(strClose); + if ((sb.length() - lineStart + accText.length()) > 200) { + sb.append(PSGenerator.LF); + } + writePostScriptString(sb, accText, multiByte); } if (hasLetterSpacing) { sb.append("] " + formatMptAsPt(generator, letterSpacing) + " ATJ"); @@ -488,7 +476,7 @@ public class PSPainter extends AbstractIFPainter { sb.append("] TJ"); } } else { - sb.append(strOpen).append(accText).append(strClose); + writePostScriptString(sb, accText, multiByte); if (hasLetterSpacing) { StringBuffer spb = new StringBuffer(); spb.append(formatMptAsPt(generator, letterSpacing)) @@ -502,6 +490,32 @@ public class PSPainter extends AbstractIFPainter { generator.writeln(sb.toString()); } + private void writePostScriptString(StringBuffer buffer, StringBuffer string, + boolean multiByte) { + writePostScriptString(buffer, string, multiByte, 0); + } + + private int writePostScriptString(StringBuffer buffer, StringBuffer string, boolean multiByte, + int lineStart) { + buffer.append(multiByte ? '<' : '('); + int l = string.length(); + int index = 0; + int maxCol = 200; + buffer.append(string.substring(index, Math.min(index + maxCol, l))); + index += maxCol; + while (index < l) { + if (!multiByte) { + buffer.append('\\'); + } + buffer.append(PSGenerator.LF); + lineStart = buffer.length(); + buffer.append(string.substring(index, Math.min(index + maxCol, l))); + index += maxCol; + } + buffer.append(multiByte ? '>' : ')'); + return lineStart; + } + private void useFont(String key, int size) throws IOException { PSFontResource res = this.documentHandler.getPSResourceForFontKey(key); PSGenerator generator = getGenerator(); @@ -509,5 +523,4 @@ public class PSPainter extends AbstractIFPainter { res.notifyResourceUsageOnPage(generator.getResourceTracker()); } - } diff --git a/src/java/org/apache/fop/render/ps/fonts/PSTTFGenerator.java b/src/java/org/apache/fop/render/ps/fonts/PSTTFGenerator.java new file mode 100644 index 000000000..f8ce37505 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/fonts/PSTTFGenerator.java @@ -0,0 +1,104 @@ +/* + * 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.fonts; + +import java.io.IOException; + +import org.apache.xmlgraphics.ps.PSGenerator; +import org.apache.xmlgraphics.util.io.ASCIIHexOutputStream; + +/** + * This is a wrapper for {@link PSGenerator} that contains some members specific for streaming + * True Type fonts to a PostScript document. + */ +public class PSTTFGenerator { + private PSGenerator gen; + private ASCIIHexOutputStream hexOut; + + /** + * The buffer is used to store the font file in an array of hex-encoded strings. Strings are + * limited to 65535 characters, string will start with a newline, 2 characters are needed to + * hex-encode each byte. + */ + public static final int MAX_BUFFER_SIZE = 32764; + + /** + * Constructor - initialises the PSGenerator in this wrapper class. + * @param gen PSGenerator + */ + public PSTTFGenerator(PSGenerator gen) { + this.gen = gen; + hexOut = new ASCIIHexOutputStream(gen.getOutputStream()); + } + + /** + * Begins writing a string by writing '<' to the begin. + * @throws IOException file write exception. + */ + public void startString() throws IOException { + // We need to reset the streamer so that it starts a new line in the PS document + hexOut = new ASCIIHexOutputStream(gen.getOutputStream()); + gen.writeln("<"); + } + + /** + * Streams a string to a PostScript document (wraps PSGenerator.write(String)). + * @param cmd String + * @throws IOException file write exception + */ + public void write(String cmd) throws IOException { + gen.write(cmd); + } + + /** + * Streams a string followed by a new line char to a PostScript document (wraps + * PSGenerator.writeln(String)). + * @param cmd String + * @throws IOException file write exception + */ + public void writeln(String cmd) throws IOException { + gen.writeln(cmd); + } + + /** + * Streams the bytes. + * @param byteArray byte[] the byte array to stream to file. + * @param offset int the starting position in the byte array to stream to file. + * @param length the number of bytes to stream to file. This MUST be less than + * MAX_BUFFER_SIZE - 1 since strings are suffixed by '00' (as in spec). + * @throws IOException file write exception + */ + public void streamBytes(byte[] byteArray, int offset, int length) throws IOException { + if (length > MAX_BUFFER_SIZE) { + throw new UnsupportedOperationException("Attempting to write a string to a PostScript" + + " file that is greater than the buffer size."); + } + hexOut.write(byteArray, offset, length); + } + + /** + * Finishes writing a string by appending '00' and '>' to the end. + * @throws IOException file write exception + */ + public void endString() throws IOException { + /* Appends a '00' to the end of the string as specified in the spec */ + gen.write("00\n> "); + } +} diff --git a/src/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStream.java b/src/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStream.java new file mode 100644 index 000000000..9727af764 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStream.java @@ -0,0 +1,72 @@ +/* + * 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.fonts; + +import java.io.IOException; + +import org.apache.fop.fonts.truetype.TTFGlyphOutputStream; + +/** + * This class streams glyphs from the "glyf" table in a True Type font. + */ +public class PSTTFGlyphOutputStream implements TTFGlyphOutputStream { + /** This counts the total number of bytes written that have been streamed. */ + private int byteCounter = 0; + + /** This is a place-holder for the offset of the last string boundary. */ + private int lastStringBoundary = 0; + private PSTTFGenerator ttfGen; + + /** + * Constructor + * @param ttfGen PSTTFGenerator + */ + public PSTTFGlyphOutputStream(PSTTFGenerator ttfGen) { + this.ttfGen = ttfGen; + } + + /** {@inheritDoc} */ + public void startGlyphStream() throws IOException { + ttfGen.startString(); + } + + /** {@inheritDoc} */ + public void streamGlyph(byte[] byteArray, int offset, int length) throws IOException { + if (length > PSTTFGenerator.MAX_BUFFER_SIZE) { + throw new UnsupportedOperationException("The glyph is " + length + " there may be an " + + "error in the font file."); + } + + if (length + (byteCounter - lastStringBoundary) < PSTTFGenerator.MAX_BUFFER_SIZE) { + ttfGen.streamBytes(byteArray, offset, length); + } else { + ttfGen.endString(); + lastStringBoundary = byteCounter; + ttfGen.startString(); + ttfGen.streamBytes(byteArray, offset, length); + } + byteCounter += length; + } + + /** {@inheritDoc} */ + public void endGlyphStream() throws IOException { + ttfGen.endString(); + } +} diff --git a/src/java/org/apache/fop/render/ps/fonts/PSTTFOutputStream.java b/src/java/org/apache/fop/render/ps/fonts/PSTTFOutputStream.java new file mode 100644 index 000000000..bf3803eb4 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/fonts/PSTTFOutputStream.java @@ -0,0 +1,64 @@ +/* + * 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.fonts; + +import java.io.IOException; + +import org.apache.fop.fonts.truetype.TTFGlyphOutputStream; +import org.apache.fop.fonts.truetype.TTFOutputStream; +import org.apache.fop.fonts.truetype.TTFTableOutputStream; +import org.apache.xmlgraphics.ps.PSGenerator; + +/** + * Implements TTFOutputStream and streams font tables to a PostScript file. + */ +public class PSTTFOutputStream implements TTFOutputStream { + /** The wrapper class for PSGenerator */ + private final PSTTFGenerator ttfGen; + + /** + * Constructor - assigns a PSGenerator to stream the font. + * @param gen PSGenerator. + */ + public PSTTFOutputStream(PSGenerator gen) { + this.ttfGen = new PSTTFGenerator(gen); + } + + /** {@inheritDoc} */ + public void startFontStream() throws IOException { + ttfGen.write("/sfnts["); + } + + /** {@inheritDoc} */ + public TTFTableOutputStream getTableOutputStream() { + return new PSTTFTableOutputStream(ttfGen); + } + + /** {@inheritDoc} */ + public TTFGlyphOutputStream getGlyphOutputStream() { + return new PSTTFGlyphOutputStream(ttfGen); + } + + /** {@inheritDoc} */ + public void endFontStream() throws IOException { + ttfGen.writeln("] def"); + } + +} diff --git a/src/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStream.java b/src/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStream.java new file mode 100644 index 000000000..24d96878e --- /dev/null +++ b/src/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStream.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.fonts; + +import java.io.IOException; + +import org.apache.fop.fonts.truetype.TTFTableOutputStream; + +/** + * This class streams a truetype table to a PostScript file. + * + */ +public class PSTTFTableOutputStream implements TTFTableOutputStream { + private PSTTFGenerator ttfGen; + /** + * Constructor. + * @param ttfGen PSGenerator the streamer class used for streaming bytes. + */ + public PSTTFTableOutputStream(PSTTFGenerator ttfGen) { + this.ttfGen = ttfGen; + } + + /** {@inheritDoc} */ + public void streamTable(byte[] byteArray, int offset, int length) throws IOException { + int offsetPosition = offset; + // Need to split the table into MAX_BUFFER_SIZE chunks + for (int i = 0; i < length / PSTTFGenerator.MAX_BUFFER_SIZE; i++) { + streamString(byteArray, offsetPosition, PSTTFGenerator.MAX_BUFFER_SIZE); + offsetPosition += PSTTFGenerator.MAX_BUFFER_SIZE; + } + if (length % PSTTFGenerator.MAX_BUFFER_SIZE > 0) { + streamString(byteArray, offsetPosition, length % PSTTFGenerator.MAX_BUFFER_SIZE); + } + } + + private void streamString(byte[] byteArray, int offset, int length) throws IOException { + ttfGen.startString(); + ttfGen.streamBytes(byteArray, offset, length); + ttfGen.endString(); + } +} diff --git a/test/java/org/apache/fop/fonts/DejaVuLGCSerifTest.java b/test/java/org/apache/fop/fonts/DejaVuLGCSerifTest.java index fb0c3a795..17d614829 100644 --- a/test/java/org/apache/fop/fonts/DejaVuLGCSerifTest.java +++ b/test/java/org/apache/fop/fonts/DejaVuLGCSerifTest.java @@ -33,13 +33,13 @@ public class DejaVuLGCSerifTest extends TestCase { /** * sets up the testcase by loading the DejaVu Font. - * + * * @throws Exception * if the test fails. */ public void setUp() throws Exception { File file = new File("test/resources/fonts/DejaVuLGCSerif.ttf"); - font = FontLoader.loadFont(file, "", true, EncodingMode.AUTO, + font = FontLoader.loadFont(file, "", true, EmbeddingMode.AUTO, EncodingMode.AUTO, fontResolver); } diff --git a/test/java/org/apache/fop/fonts/EncodingModeTest.java b/test/java/org/apache/fop/fonts/EncodingModeTest.java index 4e81c46d6..e240aea30 100644 --- a/test/java/org/apache/fop/fonts/EncodingModeTest.java +++ b/test/java/org/apache/fop/fonts/EncodingModeTest.java @@ -21,16 +21,33 @@ package org.apache.fop.fonts; import junit.framework.TestCase; +/** + * Tests the enum org.apache.fop.fonts.EncodingMode. + */ public class EncodingModeTest extends TestCase { + /** + * Test getName() - tests the getName() method returns the expected String. + */ public void testGetName() { assertEquals("auto", EncodingMode.AUTO.getName()); assertEquals("single-byte", EncodingMode.SINGLE_BYTE.getName()); assertEquals("cid", EncodingMode.CID.getName()); } + /** + * Test getValue() - test that getValue() method returns the expected enum value when given + * an appropriate String. + */ public void testGetValue() { - assertEquals(EncodingMode.AUTO, EncodingMode.getEncodingMode("auto")); - assertEquals(EncodingMode.SINGLE_BYTE, EncodingMode.getEncodingMode("single-byte")); - assertEquals(EncodingMode.CID, EncodingMode.getEncodingMode("cid")); + assertEquals(EncodingMode.AUTO, EncodingMode.getValue("auto")); + assertEquals(EncodingMode.SINGLE_BYTE, EncodingMode.getValue("single-byte")); + assertEquals(EncodingMode.CID, EncodingMode.getValue("cid")); + try { + // We expect this to fail + assertEquals(EncodingMode.AUTO, EncodingMode.getValue("fail")); + fail("Encoding mode fails to throw an appropriate exception"); + } catch (IllegalArgumentException e) { + // PASS + } } } diff --git a/test/java/org/apache/fop/fonts/FOPFontsTestSuite.java b/test/java/org/apache/fop/fonts/FOPFontsTestSuite.java new file mode 100644 index 000000000..618bdde22 --- /dev/null +++ b/test/java/org/apache/fop/fonts/FOPFontsTestSuite.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.fop.fonts.truetype.FontFileReaderTest; +import org.apache.fop.fonts.truetype.TTFFileTest; +import org.apache.fop.fonts.truetype.TTFSubSetFileTest; +import org.apache.fop.fonts.truetype.TTFTableNameTest; + +/** + * A test suite designed for org.apache.fop.fonts.* + */ +public final class FOPFontsTestSuite { + /** + * Constructor + */ + private FOPFontsTestSuite() { + } + /** + * Testing org.apache.fop.fonts.* + * @return test + */ + public static Test suite() { + TestSuite testSuite = new TestSuite("Test suite for FOPs fonts classes"); + //$JUnit-BEGIN$ + testSuite.addTest(new TestSuite(EncodingModeTest.class)); + testSuite.addTest(new TestSuite(FontFileReaderTest.class)); + testSuite.addTest(new TestSuite(TTFFileTest.class)); + testSuite.addTest(new TestSuite(TTFSubSetFileTest.class)); + testSuite.addTest(new TestSuite(TTFTableNameTest.class)); + //$JUnit-END$ + return testSuite; + } +} diff --git a/test/java/org/apache/fop/fonts/truetype/FontFileReaderTest.java b/test/java/org/apache/fop/fonts/truetype/FontFileReaderTest.java new file mode 100644 index 000000000..25d5be735 --- /dev/null +++ b/test/java/org/apache/fop/fonts/truetype/FontFileReaderTest.java @@ -0,0 +1,283 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts.truetype; + +import java.io.ByteArrayInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + +import junit.framework.TestCase; + +/** + * A test class for org.apache.fop.truetype.FontFileReader + */ +public class FontFileReaderTest extends TestCase { + private FontFileReader fontReader; + private final InputStream in; + private final byte[] byteArray; + + /** + * Constructor - initialises an array that only needs to be created once. It creates a byte[] + * of form { 0x00, 0x01, 0x02, 0x03..., 0xff}; + */ + public FontFileReaderTest() { + byteArray = new byte[256]; + for (int i = 0; i < 256; i++) { + byteArray[i] = (byte) i; + } + in = new ByteArrayInputStream(byteArray); + } + + /** + * sets up the test subject object for testing. + */ + public void setUp() { + try { + fontReader = new FontFileReader(in); + } catch (Exception e) { + fail("Error: " + e.getMessage()); + } + } + + /** + * the "destructor" method. + * + */ + public void tearDown() { + fontReader = null; + } + + /** + * Test readTTFByte() + * @throws IOException exception + */ + public void testReadTTFByte() throws IOException { + for (int i = 0; i < 256; i++) { + assertEquals((byte) i, fontReader.readTTFByte()); + } + } + + /** + * Test seekSet() - check that it moves to the correct position and enforce a failure case. + * @throws IOException exception + */ + public void testSeekSet() throws IOException { + fontReader.seekSet(10); + assertEquals(10, fontReader.readTTFByte()); + try { + fontReader.seekSet(257); + fail("FileFontReaderTest Failed testSeekSet"); + } catch (IOException e) { + // Passed + } + } + + /** + * Test skip() - check that it moves to the correct position and enforce a failure case. + * @throws IOException exception + */ + public void testSkip() throws IOException { + fontReader.skip(100); + assertEquals(100, fontReader.readTTFByte()); + try { + // 100 (seekAdd) + 1 (read() = 1 byte) + 156 = 257 + fontReader.skip(156); + fail("FileFontReaderTest Failed testSkip"); + } catch (IOException e) { + // Passed + } + } + + /** + * Test getCurrentPos() - 3 checks: + * 1) test with seekSet(int) + * 2) test with skip(int) + * 3) test with a readTTFByte() (this moves the position by the size of the data being read) + * @throws IOException exception + */ + public void testGetCurrentPos() throws IOException { + fontReader.seekSet(10); + fontReader.skip(100); + assertEquals(110, fontReader.getCurrentPos()); + fontReader.readTTFByte(); + assertEquals(111, fontReader.getCurrentPos()); + } + + /** + * Test getFileSize() + */ + public void testGetFileSize() { + assertEquals(256, fontReader.getFileSize()); + } + + /** + * Test readTTFUByte() + * @throws IOException exception + */ + public void testReadTTFUByte() throws IOException { + for (int i = 0; i < 256; i++) { + assertEquals(i, fontReader.readTTFUByte()); + } + } + + /** + * Test readTTFShort() - Test positive and negative numbers (two's compliment). + * @throws IOException exception + */ + public void testReadTTFShort() throws IOException { + // 0x0001 = 1 + assertEquals("Should have been 1 (0x0001)", 1, fontReader.readTTFShort()); + // 0x0203 = 515 + assertEquals(515, fontReader.readTTFShort()); + // now test negative numbers + fontReader.seekSet(250); + // 0xfafb + assertEquals(-1285, fontReader.readTTFShort()); + } + + /** + * Test readTTFUShort() - Test positive and potentially negative numbers (two's compliment). + * @throws IOException exception + */ + public void testReadTTFUShort() throws IOException { + // 0x0001 + assertEquals(1, fontReader.readTTFUShort()); + // 0x0203 + assertEquals(515, fontReader.readTTFUShort()); + // test potential negatives + fontReader.seekSet(250); + // 0xfafb + assertEquals((250 << 8) + 251, fontReader.readTTFUShort()); + } + + /** + * Test readTTFShort(int) - test reading ahead of current position and behind current position + * and in both cases ensure that our current position isn't changed. + * @throws IOException exception + */ + public void testReadTTFShortWithArg() throws IOException { + // 0x6465 + assertEquals(25701, fontReader.readTTFShort(100)); + assertEquals(0, fontReader.getCurrentPos()); + // read behind current position (and negative) + fontReader.seekSet(255); + // 0xfafb + assertEquals(-1285, fontReader.readTTFShort(250)); + assertEquals(255, fontReader.getCurrentPos()); + } + + /** + * Test readTTFUShort(int arg) - test reading ahead of current position and behind current + * position and in both cases ensure that our current position isn't changed. + * @throws IOException exception + */ + public void testReadTTFUShortWithArg() throws IOException { + // 0x6465 + assertEquals(25701, fontReader.readTTFUShort(100)); + assertEquals(0, fontReader.getCurrentPos()); + // read behind current position (and potential negative) + fontReader.seekSet(255); + // 0xfafb + assertEquals(64251, fontReader.readTTFUShort(250)); + assertEquals(255, fontReader.getCurrentPos()); + } + + /** + * Test readTTFLong() + * @throws IOException exception + */ + public void testReadTTFLong() throws IOException { + // 0x00010203 + assertEquals(66051, fontReader.readTTFLong()); + // test negative numbers + fontReader.seekSet(250); + // 0xf0f1f2f3 + assertEquals(-84148995, fontReader.readTTFLong()); + } + + /** + * Test readTTFULong() + * @throws IOException exception + */ + public void testReadTTFULong() throws IOException { + // 0x00010203 + assertEquals(66051, fontReader.readTTFULong()); + // test negative numbers + fontReader.seekSet(250); + // 0xfafbfcfd + assertEquals(4210818301L, fontReader.readTTFULong()); + } + + /** + * Test readTTFString() - there are two paths to test here: + * 1) A null terminated string + * 2) A string not terminated with a null (we expect this to throw an EOFException) + * @throws IOException exception + */ + public void testReadTTFString() throws IOException { + byte[] strByte = {(byte)'t', (byte)'e', (byte)'s', (byte)'t', 0x00}; + fontReader = new FontFileReader(new ByteArrayInputStream(strByte)); + assertEquals("test", fontReader.readTTFString()); + try { + // not NUL terminated + byte[] strByteNoNull = {(byte)'t', (byte)'e', (byte)'s', (byte)'t'}; + fontReader = new FontFileReader(new ByteArrayInputStream(strByteNoNull)); + assertEquals("test", fontReader.readTTFString()); + fail("FontFileReaderTest testReadTTFString Fails."); + } catch (EOFException e) { + // Pass + } + } + + /** + * Test readTTFString(int arg) + * @throws IOException exception + */ + public void testReadTTFStringIntArg() throws IOException { + byte[] strByte = {(byte)'t', (byte)'e', (byte)'s', (byte)'t'}; + fontReader = new FontFileReader(new ByteArrayInputStream(strByte)); + assertEquals("test", fontReader.readTTFString(4)); + try { + fontReader = new FontFileReader(new ByteArrayInputStream(strByte)); + assertEquals("test", fontReader.readTTFString(5)); + fail("FontFileReaderTest testReadTTFStringIntArg Fails."); + } catch (EOFException e) { + // Pass + } + } + + /** + * Test readTTFString(int arg1, int arg2) + */ + public void testReadTTFString2IntArgs() { + // currently the same as above + } + + /** + * Test getBytes() + * @throws IOException exception + */ + public void testGetBytes() throws IOException { + byte[] retrievedBytes = fontReader.getBytes(0, 256); + assertTrue(Arrays.equals(byteArray, retrievedBytes)); + } +} diff --git a/test/java/org/apache/fop/fonts/truetype/TTFFileTest.java b/test/java/org/apache/fop/fonts/truetype/TTFFileTest.java new file mode 100644 index 000000000..ccc12d991 --- /dev/null +++ b/test/java/org/apache/fop/fonts/truetype/TTFFileTest.java @@ -0,0 +1,399 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts.truetype; + +import java.io.IOException; +import java.util.Map; + +import junit.framework.TestCase; + +import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; + +/** + * Class for testing org.apache.fop.fonts.truetype.TTFFile + */ +public class TTFFileTest extends TestCase { + // We only want to initialize the FontFileReader once (for performance reasons) + /** The truetype font file (DejaVuLGCSerif) */ + protected final TTFFile dejavuTTFFile; + /** The FontFileReader for ttfFile (DejaVuLGCSerif) */ + protected final FontFileReader dejavuReader; + /** The truetype font file (DroidSansMono) */ + protected final TTFFile droidmonoTTFFile; + /** The FontFileReader for ttfFile (DroidSansMono) */ + protected final FontFileReader droidmonoReader; + + + /** + * Constructor initialises FileFontReader to + * @throws IOException exception + */ + public TTFFileTest() throws IOException { + dejavuTTFFile = new TTFFile(); + dejavuReader = new FontFileReader("test/resources/fonts/DejaVuLGCSerif.ttf"); + dejavuTTFFile.readFont(dejavuReader); + droidmonoTTFFile = new TTFFile(); + droidmonoReader = new FontFileReader("test/resources/fonts/DroidSansMono.ttf"); + droidmonoTTFFile.readFont(droidmonoReader); + } + + /** + * Test convertTTFUnit2PDFUnit() - The units per em retrieved reading the HEAD table from + * the font file. (DroidSansMono has the same units per em as DejaVu so no point testing it) + */ + public void testConvertTTFUnit2PDFUnit() { + // DejaVu has 2048 units per em (PDF works in millipts, thus the 1000) + // test rational number + assertEquals(1000, dejavuTTFFile.convertTTFUnit2PDFUnit(2048)); + // test smallest case, this should = 0.488 (round down to 0) + assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(1)); + // this should round up, but since it's millipts... + assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(2)); + // ensure behaviour is the same for negative numbers + assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(-0)); + assertEquals(-1000, dejavuTTFFile.convertTTFUnit2PDFUnit(-2048)); + assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(-1)); + assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(-2)); + } + + /** + * Test checkTTC() + * @throws IOException exception + */ + public void testCheckTTC() throws IOException { + // DejaVu is not a TTC, thus this returns true + assertTrue(dejavuTTFFile.checkTTC("")); + assertTrue(droidmonoTTFFile.checkTTC("")); + /* + * Cannot reasonably test the rest of this method without an actual truetype collection + * because all methods in FontFileReader are "final" and thus mocking isn't possible. + */ + } + + /** + * Test getAnsiKerning() - Tests values retrieved from the kern table in the font file. + */ + public void testGetAnsiKerning() { + Map> ansiKerning = dejavuTTFFile.getKerning(); + if (ansiKerning.isEmpty()) { + fail(); + } + Integer k1 = ansiKerning.get(Integer.valueOf('A')).get( + Integer.valueOf('T')); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-112), k1.intValue()); + Integer k2 = ansiKerning.get(Integer.valueOf('Y')).get(Integer.valueOf('u')); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-178), k2.intValue()); + + // DroidSansMono doens't have kerning (it's mono-spaced) + ansiKerning = droidmonoTTFFile.getAnsiKerning(); + if (!ansiKerning.isEmpty()) { + fail("DroidSansMono shouldn't have any kerning data."); + } + } + + /** + * Test getCapHeight - there are several paths to test: + * 1) The PCLT table (if present) + * 2) The yMax (3rd) value, for the bounding box, for 'H' in the glyf table. + * if not the above: + * 3) The caps height in the OS/2 table + * Tests values retrieved from analysing the font file. + */ + public void testGetCapHeight() { + // DejaVu doesn't have the PCLT table and so these have to be guessed + // The height is approximated to be the height of the "H" which for + // Deja = 1493 TTFunits + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1493), dejavuTTFFile.getCapHeight()); + // DroidSansMono doesn't have a PCLT table either + // height of "H" = 1462 + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1462), + droidmonoTTFFile.getCapHeight()); + } + + /** + * Test getCharSetName() - check that it returns "WinAnsiEncoding". + */ + public void testGetCharSetName() { + assertTrue("WinAnsiEncoding".equals(dejavuTTFFile.getCharSetName())); + assertTrue("WinAnsiEncoding".equals(droidmonoTTFFile.getCharSetName())); + } + + /** + * Test getCharWidth() - Test values retrieved from the metrics in the glyf table in + * the font file. + */ + public void testGetCharWidth() { + // Arbitrarily test a few values: + // The width of "H" (Unicode index 0x0048) is 1786 + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1786), dejavuTTFFile.getCharWidth(0x48)); + // The width of "i" (unicode index 0x0069) is 655 TTFunits + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(655), dejavuTTFFile.getCharWidth(0x69)); + // final check, "!" (unicode index 0x0021) is 823 TTFunits + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(823), dejavuTTFFile.getCharWidth(0x21)); + + // All the glyphs should be the same width in DroidSansMono (mono-spaced) + int charWidth = droidmonoTTFFile.convertTTFUnit2PDFUnit(1229); + for (int i = 0; i < 255; i++) { + assertEquals(charWidth, droidmonoTTFFile.getCharWidth(i)); + } + } + + /** + * TODO: add implementation to this test + */ + public void testGetCMaps() { + } + + /** + * Test getFamilyNames() - Test value retrieved from the name table in the font file. + */ + public void testGetFamilyNames() { + assertEquals(1, dejavuTTFFile.getFamilyNames().size()); + for (String name : dejavuTTFFile.getFamilyNames()) { + assertEquals("DejaVu LGC Serif", name); + } + assertEquals(1, droidmonoTTFFile.getFamilyNames().size()); + for (String name : droidmonoTTFFile.getFamilyNames()) { + assertEquals("Droid Sans Mono", name); + } + } + + /** + * Test getFirstChar() - TODO: implement a more intelligent test here. + */ + public void testGetFirstChar() { + // Not really sure how to test this intelligently + assertEquals(0, dejavuTTFFile.getFirstChar()); + assertEquals(0, droidmonoTTFFile.getFirstChar()); + } + + /** + * Test getFlags() - Test values retrieved from the POST table in the font file. + */ + public void testGetFlags() { + /* DejaVu flags are: + * italic angle = 0 + * fixed pitch = 0 + * has serifs = true (default value; this font doesn't have a PCLT table) + */ + int flags = dejavuTTFFile.getFlags(); + assertEquals(0, flags & 64); // Italics angle = 0 + assertEquals(32, flags & 32); // Adobe standard charset + assertEquals(0, flags & 2); // fixed pitch = 0 + assertEquals(1, flags & 1); // has serifs = 1 (true) + /* + * Droid flags are: + * italic angle = 0 + * fixed pitch = 1 + * has serifs = true (default value; this font doesn't have a PCLT table) + */ + flags = droidmonoTTFFile.getFlags(); + assertEquals(0, flags & 64); + assertEquals(32, flags & 32); + assertEquals(2, flags & 2); + assertEquals(1, flags & 1); + } + + /** + * Test getFontBBox() - Test values retrieved from values in the HEAD table in the font file. + */ + public void testGetFontBBox() { + int[] bBox = dejavuTTFFile.getFontBBox(); + /* + * The head table has the following values(DejaVu): + * xmin = -1576, ymin = -710, xmax = 3439, ymax = 2544 + */ + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-1576), bBox[0]); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-710), bBox[1]); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(3439), bBox[2]); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(2544), bBox[3]); + /* + * The head table has the following values (DroidSansMono): + * xmin = -312, ymin= -555, xmax = 1315, ymax = 2163 + */ + bBox = droidmonoTTFFile.getFontBBox(); + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(-312), bBox[0]); + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(-555), bBox[1]); + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1315), bBox[2]); + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(2163), bBox[3]); + } + + /** + * Test getFullName() - Test value retrieved from the name table in the font file. + */ + public void testGetFullName() { + assertEquals("DejaVu LGC Serif", dejavuTTFFile.getFullName()); + assertEquals("Droid Sans Mono", droidmonoTTFFile.getFullName()); + } + + /** + * Test getGlyphName - Test value retrieved from the POST table in the font file. + */ + public void testGetGlyphName() { + assertEquals("H", dejavuTTFFile.getGlyphName(43)); + assertEquals("H", droidmonoTTFFile.getGlyphName(43)); + } + + /** + * Test getItalicAngle() - Test value retrieved from the POST table in the font file. + */ + public void testGetItalicAngle() { + assertEquals("0", dejavuTTFFile.getItalicAngle()); + assertEquals("0", droidmonoTTFFile.getItalicAngle()); + } + + /** + * Test getKerning() - Test values retrieved from the kern table in the font file. + */ + public void testGetKerning() { + Map> kerning = dejavuTTFFile.getKerning(); + if (kerning.isEmpty()) { + fail(); + } + Integer k1 = kerning.get(Integer.valueOf('A')).get(Integer.valueOf('T')); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-112), k1.intValue()); + Integer k2 = kerning.get(Integer.valueOf('K')).get(Integer.valueOf('u')); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-45), k2.intValue()); + + // DroidSansMono has no kerning data (mono-spaced) + kerning = droidmonoTTFFile.getKerning(); + if (!kerning.isEmpty()) { + fail("DroidSansMono shouldn't have any kerning data"); + } + } + + /** + * Test lastChar() - TODO: implement a more intelligent test + */ + public void testLastChar() { + assertEquals(0xff, dejavuTTFFile.getLastChar()); + assertEquals(0xff, droidmonoTTFFile.getLastChar()); + } + + /** + * Test getLowerCaseAscent() - There are several paths to test: + * 1) The values in the HHEA table (see code) + * 2) Fall back to values from the OS/2 table + * Test values retrieved from the font file. + */ + public void testGetLowerCaseAscent() { + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1556), + dejavuTTFFile.getLowerCaseAscent()); + // Curiously the same value + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1556), + droidmonoTTFFile.getLowerCaseAscent()); + } + + /** + * Test getPostScriptName() - Test values retrieved from the post table in the font file. + */ + public void testGetPostScriptName() { + assertEquals(PostScriptVersion.V2, dejavuTTFFile.getPostScriptVersion()); + assertEquals(PostScriptVersion.V2, droidmonoTTFFile.getPostScriptVersion()); + } + + /** + * Test getStemV() - Undefined. + */ + public void testGetStemV() { + // Undefined + assertEquals("0", dejavuTTFFile.getStemV()); + assertEquals("0", droidmonoTTFFile.getStemV()); + } + + /** + * Test getSubFamilyName() - Test values retrieved from the name table in the font file. + */ + public void testGetSubFamilyName() { + assertEquals("Book", dejavuTTFFile.getSubFamilyName()); + assertEquals("Regular", droidmonoTTFFile.getSubFamilyName()); + } + + /** + * Test getTTCnames() - TODO: add implementation with TTC font. + */ + public void testGetTTCnames() { + // Can't test with with DejaVu since it's not a TrueType Collection + } + + /** + * Test getWeightClass() - Test value retrieved from the OS/2 table in the font file. + */ + public void testGetWeightClass() { + // Retrieved from OS/2 table + assertEquals(400, dejavuTTFFile.getWeightClass()); + assertEquals(400, droidmonoTTFFile.getWeightClass()); + } + + /** + * Test getWidths() - Test values retrieved from the hmtx table in the font file. + */ + public void testGetWidths() { + int[] widths = dejavuTTFFile.getWidths(); + // using the width of 'A' index = 36 + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1479), widths[36]); + // using the width of '|' index = 95 + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(690), widths[95]); + widths = droidmonoTTFFile.getWidths(); + // DroidSansMono should have all widths the same size (mono-spaced) + int width = droidmonoTTFFile.convertTTFUnit2PDFUnit(1229); + for (int i = 0; i < 255; i++) { + assertEquals(width, widths[i]); + } + } + + /** + * Test getXHeight() - There are several paths to test: + * 1) The PCLT table (if available) + * 2) The yMax for the bounding box for 'x' in the glyf table. + * Fall back: + * 3) The xheight in the OS/2 table. + */ + public void testGetXHeight() { + // Since there's no PCLT table, the height of 'x' is used for both DejaVu and DroidSansMono + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1064), dejavuTTFFile.getXHeight()); + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1098), droidmonoTTFFile.getXHeight()); + } + + /** + * Test isCFF() - TODO: add test for a CFF font. + */ + public void testIsCFF() { + // Neither DejaVu nor DroidSansMono are a compact format font + assertEquals(false, dejavuTTFFile.isCFF()); + assertEquals(false, droidmonoTTFFile.isCFF()); + } + + /** + * Test isEmbeddable() - Test value retrieved from the OS/2 table in the font file. + */ + public void testIsEmbeddable() { + // Dejavu and DroidSansMono are both embeddable + assertEquals(true, dejavuTTFFile.isEmbeddable()); + assertEquals(true, droidmonoTTFFile.isEmbeddable()); + } + + /** + * Test readFont() - Add implementation if necessary. + */ + public void testReadFont() { + // I'm pretty sure we've tested this with all the other tests + } +} diff --git a/test/java/org/apache/fop/fonts/truetype/TTFSubSetFileTest.java b/test/java/org/apache/fop/fonts/truetype/TTFSubSetFileTest.java new file mode 100644 index 000000000..b0ced70e8 --- /dev/null +++ b/test/java/org/apache/fop/fonts/truetype/TTFSubSetFileTest.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts.truetype; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * This class tests TTFSubSetFile + * TODO: Test with more than just a single font + */ +public class TTFSubSetFileTest extends TTFFileTest { + private TTFSubSetFile ttfSubset; + private byte[] subset; + /** + * Constructor + * @throws IOException exception + */ + public TTFSubSetFileTest() throws IOException { + super(); + } + + /** + * setUp() + * @exception IOException file read error + */ + public void setUp() throws IOException { + ttfSubset = new TTFSubSetFile(); + Map glyphs = new HashMap(); + for (int i = 0; i < 255; i++) { + glyphs.put(i, i); + } + ttfSubset.readFont(dejavuReader, "DejaVu", glyphs); + subset = ttfSubset.getFontSubset(); + } + /** + * Test readFont(FontFileReader, String, Map) - Reads the font and tests the output by injecting + * it into a TTFFile object to check the validity of the file as a font. This currently doesn't + * create a cmap table, and so the font doesn't contain ALL of the mandatory tables. + * @throws IOException exception + */ + public void testReadFont3Args() throws IOException { + + ByteArrayInputStream byteArray = new ByteArrayInputStream(subset); + dejavuTTFFile.readFont(new FontFileReader(byteArray)); + // Test a couple arbitrary values + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-1576), dejavuTTFFile.getFontBBox()[0]); + assertEquals(dejavuTTFFile.getFullName(), "DejaVu LGC Serif"); + } +} diff --git a/test/java/org/apache/fop/fonts/truetype/TTFTableNameTest.java b/test/java/org/apache/fop/fonts/truetype/TTFTableNameTest.java new file mode 100644 index 000000000..224dad8a3 --- /dev/null +++ b/test/java/org/apache/fop/fonts/truetype/TTFTableNameTest.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts.truetype; + +import junit.framework.TestCase; + +/** + * This class tests the enum org.apache.fop.fonts.truetype.TTFTableName + * + */ +public class TTFTableNameTest extends TestCase { + /** + * Test getName() - tests that the getName() method returns the expected String as expected in + * the Directory Table. + * @exception IllegalAccessException error + */ + public void testGetName() throws IllegalAccessException { + assertEquals("dirTable", TTFTableName.DIRECTORY_TABLE.getName()); + assertEquals("EBDT", TTFTableName.EBDT.getName()); + assertEquals("EBLC", TTFTableName.EBLC.getName()); + assertEquals("EBSC", TTFTableName.EBSC.getName()); + assertEquals("FFTM", TTFTableName.FFTM.getName()); + assertEquals("GDEF", TTFTableName.GDEF.getName()); + assertEquals("GPOS", TTFTableName.GPOS.getName()); + assertEquals("GSUB", TTFTableName.GSUB.getName()); + assertEquals("LTSH", TTFTableName.LTSH.getName()); + assertEquals("OS/2", TTFTableName.OS2.getName()); + assertEquals("PCLT", TTFTableName.PCLT.getName()); + assertEquals("VDMX", TTFTableName.VDMX.getName()); + assertEquals("cmap", TTFTableName.CMAP.getName()); + assertEquals("cvt ", TTFTableName.CVT.getName()); + assertEquals("fpgm", TTFTableName.FPGM.getName()); + assertEquals("gasp", TTFTableName.GASP.getName()); + assertEquals("glyf", TTFTableName.GLYF.getName()); + assertEquals("hdmx", TTFTableName.HDMX.getName()); + assertEquals("head", TTFTableName.HEAD.getName()); + assertEquals("hhea", TTFTableName.HHEA.getName()); + assertEquals("hmtx", TTFTableName.HMTX.getName()); + assertEquals("kern", TTFTableName.KERN.getName()); + assertEquals("loca", TTFTableName.LOCA.getName()); + assertEquals("maxp", TTFTableName.MAXP.getName()); + assertEquals("name", TTFTableName.NAME.getName()); + assertEquals("post", TTFTableName.POST.getName()); + assertEquals("prep", TTFTableName.PREP.getName()); + assertEquals("vhea", TTFTableName.VHEA.getName()); + assertEquals("vmtx", TTFTableName.VMTX.getName()); + // make sure it works with other table names + TTFTableName test = TTFTableName.getValue("test"); + assertEquals("test", test.getName()); + } + + /** + * Test getValue(String) - tests that the getValue(String) method returns the expected + * TTFTableNames value when it is given a String (name of a table). + * @exception IllegalAccessException error + */ + public void testGetValue() throws IllegalAccessException { + assertEquals(TTFTableName.EBDT, TTFTableName.getValue("EBDT")); + assertEquals(TTFTableName.EBLC, TTFTableName.getValue("EBLC")); + assertEquals(TTFTableName.EBSC, TTFTableName.getValue("EBSC")); + assertEquals(TTFTableName.FFTM, TTFTableName.getValue("FFTM")); + assertEquals(TTFTableName.LTSH, TTFTableName.getValue("LTSH")); + assertEquals(TTFTableName.OS2, TTFTableName.getValue("OS/2")); + assertEquals(TTFTableName.PCLT, TTFTableName.getValue("PCLT")); + assertEquals(TTFTableName.VDMX, TTFTableName.getValue("VDMX")); + assertEquals(TTFTableName.CMAP, TTFTableName.getValue("cmap")); + assertEquals(TTFTableName.CVT, TTFTableName.getValue("cvt ")); + assertEquals(TTFTableName.FPGM, TTFTableName.getValue("fpgm")); + assertEquals(TTFTableName.GASP, TTFTableName.getValue("gasp")); + assertEquals(TTFTableName.GLYF, TTFTableName.getValue("glyf")); + assertEquals(TTFTableName.HDMX, TTFTableName.getValue("hdmx")); + assertEquals(TTFTableName.HEAD, TTFTableName.getValue("head")); + assertEquals(TTFTableName.HHEA, TTFTableName.getValue("hhea")); + assertEquals(TTFTableName.HMTX, TTFTableName.getValue("hmtx")); + assertEquals(TTFTableName.KERN, TTFTableName.getValue("kern")); + assertEquals(TTFTableName.LOCA, TTFTableName.getValue("loca")); + assertEquals(TTFTableName.MAXP, TTFTableName.getValue("maxp")); + assertEquals(TTFTableName.NAME, TTFTableName.getValue("name")); + assertEquals(TTFTableName.POST, TTFTableName.getValue("post")); + assertEquals(TTFTableName.PREP, TTFTableName.getValue("prep")); + assertEquals(TTFTableName.VHEA, TTFTableName.getValue("vhea")); + assertEquals(TTFTableName.VMTX, TTFTableName.getValue("vmtx")); + // Test that we can store a random table name and it will not fail or throw an error. + TTFTableName test = TTFTableName.getValue("random"); + assertTrue(test instanceof TTFTableName); + } + + /** + * This class overrides hashCode() - we need to ensure it works properly by instantiating two + * objects and comparing their hash-codes. + * @exception IllegalAccessException error + */ + public void testHashCode() throws IllegalAccessException { + TTFTableName a = TTFTableName.getValue("testObject"); + TTFTableName b = TTFTableName.getValue("testObject"); + assertTrue(a.hashCode() == b.hashCode()); + TTFTableName c = TTFTableName.getValue("fail"); + assertFalse(a.hashCode() == c.hashCode()); + } + + /** + * This class overrides equals(object) - we need to test: + * 1) Reflexivity + * 2) Symmetry + * 3) Transitivity + * 4) Consistency + * 5) check it fails if you put in a null value + * @throws IllegalAccessException error + */ + public void testEquals() throws IllegalAccessException { + // Reflexivity + TTFTableName a = TTFTableName.getValue("test"); + assertTrue(a.equals(a)); + // Symmetry + TTFTableName b = TTFTableName.getValue("test"); + assertTrue(a.equals(b)); + assertTrue(b.equals(a)); + // Transitivity (tested with symmetry) + // Consistency (test that a == b is true and that a == c fails) + TTFTableName c = TTFTableName.getValue("fail"); + for (int i = 0; i < 100; i++) { + assertTrue(a.equals(b)); + assertFalse(a.equals(c)); + } + // check with null value + assertFalse(a.equals(null)); + } +} diff --git a/test/java/org/apache/fop/render/ps/RenderPSTestSuite.java b/test/java/org/apache/fop/render/ps/RenderPSTestSuite.java new file mode 100644 index 000000000..6052faeb5 --- /dev/null +++ b/test/java/org/apache/fop/render/ps/RenderPSTestSuite.java @@ -0,0 +1,55 @@ +/* + * 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.Test; +import junit.framework.TestSuite; + +import org.apache.fop.render.ps.fonts.PSTTFGeneratorTest; +import org.apache.fop.render.ps.fonts.PSTTFGlyphOutputStreamTest; +import org.apache.fop.render.ps.fonts.PSTTFOutputStreamTest; +import org.apache.fop.render.ps.fonts.PSTTFTableOutputStreamTest; + + +/** + * A test Suite for org.apache.fop.render.ps.* + */ +public final class RenderPSTestSuite { + /** + * Constructor. + */ + private RenderPSTestSuite() { + } + + /** + * Testing org.apache.fop.render.ps.* + * @return test + */ + public static Test suite() { + TestSuite suite = new TestSuite(); + //$JUnit-BEGIN$ + suite.addTest(new TestSuite(PSTTFGeneratorTest.class)); + suite.addTest(new TestSuite(PSTTFOutputStreamTest.class)); + suite.addTest(new TestSuite(PSTTFGlyphOutputStreamTest.class)); + suite.addTest(new TestSuite(PSTTFTableOutputStreamTest.class)); + //$JUnit-END$ + return suite; + } +} diff --git a/test/java/org/apache/fop/render/ps/fonts/PSTTFGeneratorTest.java b/test/java/org/apache/fop/render/ps/fonts/PSTTFGeneratorTest.java new file mode 100644 index 000000000..fd3d98c98 --- /dev/null +++ b/test/java/org/apache/fop/render/ps/fonts/PSTTFGeneratorTest.java @@ -0,0 +1,111 @@ +/* + * 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.fonts; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import junit.framework.TestCase; + +import org.apache.xmlgraphics.ps.PSGenerator; + +/** + * The test class for org.apache.fop.render.ps.fonts.PSGenerator + */ +public class PSTTFGeneratorTest extends TestCase { + private PSTTFGenerator ttfGen; + private ByteArrayOutputStream out = new ByteArrayOutputStream(); + private PSGenerator gen = new PSGenerator(out); + private byte[] byteArray; + + /** + * Constructor + */ + public PSTTFGeneratorTest() { + byteArray = new byte[65536]; + for (int i = 0; i < 65536; i++) { + byteArray[i] = (byte) i; + } + } + + @Override + public void setUp() { + ttfGen = new PSTTFGenerator(gen); + } + + /** + * Tests startString() - starts the string in an appropriate way for a PostScript file. + * @exception IOException write error + */ + public void testStartString() throws IOException { + ttfGen.startString(); + assertEquals("<\n", out.toString()); + } + + /** + * Test streamBytes() - tests that strings are written to file in the proper format. + * @throws IOException write error. + */ + public void testStreamBytes() throws IOException { + ttfGen.streamBytes(byteArray, 0, 16); + assertEquals("000102030405060708090A0B0C0D0E0F", out.toString()); + /* + * 65520 is the closes multiple of 80 to 65535 (max string size in PS document) and since + * one byte takes up two characters, 65520 / 2 - 16 (16 bytes already written)= 32744. + */ + ttfGen.streamBytes(byteArray, 0, 32744); + // Using a regex to ensure that the format is correct + assertTrue(out.toString().matches("([0-9A-F]{80}\n){819}")); + try { + ttfGen.streamBytes(byteArray, 0, PSTTFGenerator.MAX_BUFFER_SIZE + 1); + fail("Shouldn't be able to write more than MAX_BUFFER_SIZE to a PS document"); + } catch (UnsupportedOperationException e) { + // PASS + } + } + + /** + * Test reset() - reset should reset the line counter such that when reset() is invoked the + * following string streamed to the PS document should be 80 chars long. + * @throws IOException file write error. + */ + public void testReset() throws IOException { + ttfGen.streamBytes(byteArray, 0, 40); + assertTrue(out.toString().matches("([0-9A-F]{80}\n)")); + ttfGen.streamBytes(byteArray, 0, 40); + assertTrue(out.toString().matches("([0-9A-F]{80}\n){2}")); + + } + + /** + * Test endString() - ensures strings are ended in the PostScript document in the correct + * format, a "00" needs to be appended to the end of a string. + * @throws IOException file write error + */ + public void testEndString() throws IOException { + ttfGen.endString(); + assertEquals("00\n> ", out.toString()); + out.reset(); + // we need to check that this doesn't write more than 80 chars per line + ttfGen.streamBytes(byteArray, 0, 40); + ttfGen.endString(); + assertTrue(out.toString().matches("([0-9A-F]{80}\n)00\n> ")); + } +} diff --git a/test/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStreamTest.java b/test/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStreamTest.java new file mode 100644 index 000000000..3bd93b1ba --- /dev/null +++ b/test/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStreamTest.java @@ -0,0 +1,105 @@ +/* + * 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.fonts; + +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.io.IOException; + +import junit.framework.TestCase; + +import org.mockito.InOrder; + +/** + * Test class for PSTTFGlyphOutputStream + */ +public class PSTTFGlyphOutputStreamTest extends TestCase { + private PSTTFGenerator mockGen; + private PSTTFGlyphOutputStream glyphOut; + + @Override + public void setUp() { + mockGen = mock(PSTTFGenerator.class); + glyphOut = new PSTTFGlyphOutputStream(mockGen); + } + + /** + * Test startGlyphStream() - test that startGlyphStream() invokes reset() and startString() in + * PSTTFGenerator. + * @exception IOException file write error + */ + public void testStartGlyphStream() throws IOException { + glyphOut.startGlyphStream(); + verify(mockGen).startString(); + } + + /** + * Test streamGlyph(byte[],int,int) - tests several paths: + * 1) strings are properly appended + * 2) when total strings size > PSTTFGenerator.MAX_BUFFER_SIZE, the strings is closed and a new + * strings is started. + * 3) if a glyph of size > PSTTFGenerator.MAX_BUFFER_SIZE is attempted, an exception is thrown. + * @throws IOException file write error. + */ + public void testStreamGlyph() throws IOException { + int byteArraySize = 10; + byte[] byteArray = new byte[byteArraySize]; + int runs = 100; + for (int i = 0; i < runs; i++) { + glyphOut.streamGlyph(byteArray, 0, byteArraySize); + } + verify(mockGen, times(runs)).streamBytes(byteArray, 0, byteArraySize); + + /* + * We want to run this for MAX_BUFFER_SIZE / byteArraySize so that go over the string + * boundary and enforce the ending and starting of a new string. Using mockito to ensure + * that this behaviour is performed in order (since this is an integral behavioural aspect) + */ + int stringLimit = PSTTFGenerator.MAX_BUFFER_SIZE / byteArraySize; + for (int i = 0; i < stringLimit; i++) { + glyphOut.streamGlyph(byteArray, 0, byteArraySize); + } + InOrder inOrder = inOrder(mockGen); + inOrder.verify(mockGen, times(stringLimit)).streamBytes(byteArray, 0, byteArraySize); + inOrder.verify(mockGen).endString(); + inOrder.verify(mockGen).startString(); + inOrder.verify(mockGen, times(runs)).streamBytes(byteArray, 0, byteArraySize); + + try { + glyphOut.streamGlyph(byteArray, 0, PSTTFGenerator.MAX_BUFFER_SIZE + 1); + fail("Shouldn't allow a length > PSTTFGenerator.MAX_BUFFER_SIZE"); + } catch (UnsupportedOperationException e) { + // PASS + } + } + + /** + * Test endGlyphStream() - tests that PSTTFGenerator.endString() is invoked when this method + * is called. + * @throws IOException file write exception + */ + public void testEndGlyphStream() throws IOException { + glyphOut.endGlyphStream(); + verify(mockGen).endString(); + } +} diff --git a/test/java/org/apache/fop/render/ps/fonts/PSTTFOutputStreamTest.java b/test/java/org/apache/fop/render/ps/fonts/PSTTFOutputStreamTest.java new file mode 100644 index 000000000..f9b623f69 --- /dev/null +++ b/test/java/org/apache/fop/render/ps/fonts/PSTTFOutputStreamTest.java @@ -0,0 +1,82 @@ +/* + * 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.fonts; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.io.IOException; + +import junit.framework.TestCase; + +import org.apache.fop.fonts.truetype.TTFGlyphOutputStream; +import org.apache.fop.fonts.truetype.TTFTableOutputStream; +import org.apache.xmlgraphics.ps.PSGenerator; + +/** + * Tests PSTTFOuputStream + */ +public class PSTTFOutputStreamTest extends TestCase { + private PSGenerator gen; + private PSTTFOutputStream out; + + /** + * Assigns an OutputStream to the PSGenerator. + */ + public void setUp() { + gen = mock(PSGenerator.class); + out = new PSTTFOutputStream(gen); + } + + /** + * Test startFontStream() - Just tests that the font is properly initiated in the PostScript + * document (in this case with "/sfnts[") + * @throws IOException write exception. + */ + public void testStartFontStream() throws IOException { + out.startFontStream(); + verify(gen).write("/sfnts["); + } + + /** + * Test getTableOutputStream() - we need to test that the inheritance model is properly obeyed. + */ + public void testGetTableOutputStream() { + TTFTableOutputStream tableOut = out.getTableOutputStream(); + assertTrue(tableOut instanceof PSTTFTableOutputStream); + } + + /** + * Test getGlyphOutputStream() - we need to test that the inheritance model is properly obeyed. + */ + public void testGetGlyphOutputStream() { + TTFGlyphOutputStream glyphOut = out.getGlyphOutputStream(); + assertTrue(glyphOut instanceof PSTTFGlyphOutputStream); + } + + /** + * Test endFontStream() + * @exception IOException write error. + */ + public void testEndFontStream() throws IOException { + out.endFontStream(); + verify(gen).writeln("] def"); + } +} diff --git a/test/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStreamTest.java b/test/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStreamTest.java new file mode 100644 index 000000000..41605ceb0 --- /dev/null +++ b/test/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStreamTest.java @@ -0,0 +1,86 @@ +/* + * 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.fonts; + +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; + +import java.io.IOException; + +import junit.framework.TestCase; + +import org.mockito.InOrder; + +/** + * Test class for unit testing PSTTFTableOutputStream + */ +public class PSTTFTableOutputStreamTest extends TestCase { + private PSTTFGenerator mockGen; + private PSTTFTableOutputStream tableOut; + + @Override + public void setUp() { + mockGen = mock(PSTTFGenerator.class); + tableOut = new PSTTFTableOutputStream(mockGen); + } + + /** + * Test streamTable() - several paths to test (2. and 3. test corner cases): + * 1) that a table of length < PSTTFGenerator.MAX_BUFFER_SIZE invokes the correct methods in + * PSTTFGenerator. + * 2) that a table of length > PSTTFGenerator.MAX_BUFFER_SIZE and + * length == n * PSTTFGenerator.MAX_BUFFER_SIZE is split up and the methods in PSTTFGenerator + * are invoked. + * 3) that a table of length > PSTTFGenerator.MAX_BUFFER_SIZE but + * length != n * PSTTFGenerator.MAX_BUFFER_SIZE is split up and the methods in PSTTFGenerator + * are invoked. + * @throws IOException file write error. + */ + public void testStreamTable() throws IOException { + byte[] byteArray = new byte[PSTTFGenerator.MAX_BUFFER_SIZE * 3]; + tableOut.streamTable(byteArray, 0, 10); + InOrder inOrder = inOrder(mockGen); + inOrder.verify(mockGen).startString(); + inOrder.verify(mockGen).streamBytes(byteArray, 0, 10); + inOrder.verify(mockGen).endString(); + + setUp(); // reset all all the method calls + /* We're going to run this 3 times to ensure the proper method calls are invoked and all + * the bytes are streamed */ + tableOut.streamTable(byteArray, 0, byteArray.length); + inOrder = inOrder(mockGen); + for (int i = 0; i < 3; i++) { + int offset = PSTTFGenerator.MAX_BUFFER_SIZE * i; + inOrder.verify(mockGen).startString(); + inOrder.verify(mockGen).streamBytes(byteArray, offset, PSTTFGenerator.MAX_BUFFER_SIZE); + inOrder.verify(mockGen).endString(); + } + + setUp(); // reset all the method calls + tableOut.streamTable(byteArray, 0, PSTTFGenerator.MAX_BUFFER_SIZE + 1); + inOrder = inOrder(mockGen); + inOrder.verify(mockGen).startString(); + inOrder.verify(mockGen).streamBytes(byteArray, 0, PSTTFGenerator.MAX_BUFFER_SIZE); + inOrder.verify(mockGen).endString(); + inOrder.verify(mockGen).startString(); + inOrder.verify(mockGen).streamBytes(byteArray, PSTTFGenerator.MAX_BUFFER_SIZE, 1); + inOrder.verify(mockGen).endString(); + } +} diff --git a/test/resources/fonts/DroidSansMono.LICENSE b/test/resources/fonts/DroidSansMono.LICENSE new file mode 100644 index 000000000..1a96dfde6 --- /dev/null +++ b/test/resources/fonts/DroidSansMono.LICENSE @@ -0,0 +1,18 @@ +Copyright (C) 2008 The Android Open Source Project + +Licensed 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. + +########## + +This directory contains the fonts for the platform. They are licensed +under the Apache 2 license. -- cgit v1.2.3 From 55c1f8be3cf6da96f690f34743d47ecee95243bb Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 11 Apr 2012 13:38:03 +0000 Subject: Removed dependency on no longer existing setup-xml-schema target git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1324757 13f79535-47bb-0310-9956-ffa450edef68 --- jacoco.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jacoco.xml b/jacoco.xml index 679b78c8a..43e5f394b 100644 --- a/jacoco.xml +++ b/jacoco.xml @@ -5,7 +5,7 @@ - + -- cgit v1.2.3 From 340025483a07776d56b655bbee3b402ba589a5b4 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 28 May 2012 15:50:35 +0000 Subject: Bugzilla #53296: Updated TTFinPS specific test cases to JUnit 4 Patch by Robert Meyer, applied with minor modifications git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1343299 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/fonts/EncodingModeTest.java | 53 --- .../org/apache/fop/fonts/EncodingModeTestCase.java | 8 + .../org/apache/fop/fonts/FOPFontsTestSuite.java | 40 +- .../fop/fonts/truetype/FontFileReaderTest.java | 283 -------------- .../fop/fonts/truetype/FontFileReaderTestCase.java | 304 +++++++++++++++ .../org/apache/fop/fonts/truetype/TTFFileTest.java | 399 ------------------- .../apache/fop/fonts/truetype/TTFFileTestCase.java | 427 +++++++++++++++++++++ .../fop/fonts/truetype/TTFSubSetFileTest.java | 69 ---- .../fop/fonts/truetype/TTFSubSetFileTestCase.java | 76 ++++ .../fop/fonts/truetype/TTFTableNameTest.java | 145 ------- .../fop/fonts/truetype/TTFTableNameTestCase.java | 153 ++++++++ .../apache/fop/render/ps/RenderPSTestSuite.java | 40 +- .../fop/render/ps/fonts/PSTTFGeneratorTest.java | 111 ------ .../render/ps/fonts/PSTTFGeneratorTestCase.java | 120 ++++++ .../ps/fonts/PSTTFGlyphOutputStreamTest.java | 105 ----- .../ps/fonts/PSTTFGlyphOutputStreamTestCase.java | 109 ++++++ .../fop/render/ps/fonts/PSTTFOutputStreamTest.java | 82 ---- .../render/ps/fonts/PSTTFOutputStreamTestCase.java | 90 +++++ .../ps/fonts/PSTTFTableOutputStreamTest.java | 86 ----- .../ps/fonts/PSTTFTableOutputStreamTestCase.java | 87 +++++ .../org/apache/fop/util/HexEncoderTestCase.java | 37 +- test/resources/fonts/DroidSansMono.LICENSE | 18 - test/resources/fonts/ttf/DroidSansMono.LICENSE | 18 + test/resources/fonts/ttf/DroidSansMono.ttf | Bin 0 -> 78296 bytes 24 files changed, 1440 insertions(+), 1420 deletions(-) delete mode 100644 test/java/org/apache/fop/fonts/EncodingModeTest.java delete mode 100644 test/java/org/apache/fop/fonts/truetype/FontFileReaderTest.java create mode 100644 test/java/org/apache/fop/fonts/truetype/FontFileReaderTestCase.java delete mode 100644 test/java/org/apache/fop/fonts/truetype/TTFFileTest.java create mode 100644 test/java/org/apache/fop/fonts/truetype/TTFFileTestCase.java delete mode 100644 test/java/org/apache/fop/fonts/truetype/TTFSubSetFileTest.java create mode 100644 test/java/org/apache/fop/fonts/truetype/TTFSubSetFileTestCase.java delete mode 100644 test/java/org/apache/fop/fonts/truetype/TTFTableNameTest.java create mode 100644 test/java/org/apache/fop/fonts/truetype/TTFTableNameTestCase.java delete mode 100644 test/java/org/apache/fop/render/ps/fonts/PSTTFGeneratorTest.java create mode 100644 test/java/org/apache/fop/render/ps/fonts/PSTTFGeneratorTestCase.java delete mode 100644 test/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStreamTest.java create mode 100644 test/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStreamTestCase.java delete mode 100644 test/java/org/apache/fop/render/ps/fonts/PSTTFOutputStreamTest.java create mode 100644 test/java/org/apache/fop/render/ps/fonts/PSTTFOutputStreamTestCase.java delete mode 100644 test/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStreamTest.java create mode 100644 test/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStreamTestCase.java delete mode 100644 test/resources/fonts/DroidSansMono.LICENSE create mode 100644 test/resources/fonts/ttf/DroidSansMono.LICENSE create mode 100644 test/resources/fonts/ttf/DroidSansMono.ttf diff --git a/test/java/org/apache/fop/fonts/EncodingModeTest.java b/test/java/org/apache/fop/fonts/EncodingModeTest.java deleted file mode 100644 index e240aea30..000000000 --- a/test/java/org/apache/fop/fonts/EncodingModeTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import junit.framework.TestCase; - -/** - * Tests the enum org.apache.fop.fonts.EncodingMode. - */ -public class EncodingModeTest extends TestCase { - /** - * Test getName() - tests the getName() method returns the expected String. - */ - public void testGetName() { - assertEquals("auto", EncodingMode.AUTO.getName()); - assertEquals("single-byte", EncodingMode.SINGLE_BYTE.getName()); - assertEquals("cid", EncodingMode.CID.getName()); - } - - /** - * Test getValue() - test that getValue() method returns the expected enum value when given - * an appropriate String. - */ - public void testGetValue() { - assertEquals(EncodingMode.AUTO, EncodingMode.getValue("auto")); - assertEquals(EncodingMode.SINGLE_BYTE, EncodingMode.getValue("single-byte")); - assertEquals(EncodingMode.CID, EncodingMode.getValue("cid")); - try { - // We expect this to fail - assertEquals(EncodingMode.AUTO, EncodingMode.getValue("fail")); - fail("Encoding mode fails to throw an appropriate exception"); - } catch (IllegalArgumentException e) { - // PASS - } - } -} diff --git a/test/java/org/apache/fop/fonts/EncodingModeTestCase.java b/test/java/org/apache/fop/fonts/EncodingModeTestCase.java index 5fd9b4f37..8cab9eb8b 100644 --- a/test/java/org/apache/fop/fonts/EncodingModeTestCase.java +++ b/test/java/org/apache/fop/fonts/EncodingModeTestCase.java @@ -23,6 +23,9 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; +/** + * Tests {@link EncodingMode}. + */ public class EncodingModeTestCase { @Test @@ -38,4 +41,9 @@ public class EncodingModeTestCase { assertEquals(EncodingMode.SINGLE_BYTE, EncodingMode.getValue("single-byte")); assertEquals(EncodingMode.CID, EncodingMode.getValue("cid")); } + + @Test(expected = IllegalArgumentException.class) + public void getValueMustCheckForIllegalArguments() { + EncodingMode.getValue("fail"); + } } diff --git a/test/java/org/apache/fop/fonts/FOPFontsTestSuite.java b/test/java/org/apache/fop/fonts/FOPFontsTestSuite.java index 618bdde22..8e1a0040d 100644 --- a/test/java/org/apache/fop/fonts/FOPFontsTestSuite.java +++ b/test/java/org/apache/fop/fonts/FOPFontsTestSuite.java @@ -19,36 +19,24 @@ package org.apache.fop.fonts; -import junit.framework.Test; -import junit.framework.TestSuite; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; -import org.apache.fop.fonts.truetype.FontFileReaderTest; -import org.apache.fop.fonts.truetype.TTFFileTest; -import org.apache.fop.fonts.truetype.TTFSubSetFileTest; -import org.apache.fop.fonts.truetype.TTFTableNameTest; +import org.apache.fop.fonts.truetype.FontFileReaderTestCase; +import org.apache.fop.fonts.truetype.TTFFileTestCase; +import org.apache.fop.fonts.truetype.TTFSubSetFileTestCase; +import org.apache.fop.fonts.truetype.TTFTableNameTestCase; /** * A test suite designed for org.apache.fop.fonts.* */ +@RunWith(Suite.class) +@SuiteClasses({ + EncodingModeTestCase.class, + FontFileReaderTestCase.class, + TTFFileTestCase.class, + TTFSubSetFileTestCase.class, + TTFTableNameTestCase.class }) public final class FOPFontsTestSuite { - /** - * Constructor - */ - private FOPFontsTestSuite() { - } - /** - * Testing org.apache.fop.fonts.* - * @return test - */ - public static Test suite() { - TestSuite testSuite = new TestSuite("Test suite for FOPs fonts classes"); - //$JUnit-BEGIN$ - testSuite.addTest(new TestSuite(EncodingModeTest.class)); - testSuite.addTest(new TestSuite(FontFileReaderTest.class)); - testSuite.addTest(new TestSuite(TTFFileTest.class)); - testSuite.addTest(new TestSuite(TTFSubSetFileTest.class)); - testSuite.addTest(new TestSuite(TTFTableNameTest.class)); - //$JUnit-END$ - return testSuite; - } } diff --git a/test/java/org/apache/fop/fonts/truetype/FontFileReaderTest.java b/test/java/org/apache/fop/fonts/truetype/FontFileReaderTest.java deleted file mode 100644 index 25d5be735..000000000 --- a/test/java/org/apache/fop/fonts/truetype/FontFileReaderTest.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.ByteArrayInputStream; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; - -import junit.framework.TestCase; - -/** - * A test class for org.apache.fop.truetype.FontFileReader - */ -public class FontFileReaderTest extends TestCase { - private FontFileReader fontReader; - private final InputStream in; - private final byte[] byteArray; - - /** - * Constructor - initialises an array that only needs to be created once. It creates a byte[] - * of form { 0x00, 0x01, 0x02, 0x03..., 0xff}; - */ - public FontFileReaderTest() { - byteArray = new byte[256]; - for (int i = 0; i < 256; i++) { - byteArray[i] = (byte) i; - } - in = new ByteArrayInputStream(byteArray); - } - - /** - * sets up the test subject object for testing. - */ - public void setUp() { - try { - fontReader = new FontFileReader(in); - } catch (Exception e) { - fail("Error: " + e.getMessage()); - } - } - - /** - * the "destructor" method. - * - */ - public void tearDown() { - fontReader = null; - } - - /** - * Test readTTFByte() - * @throws IOException exception - */ - public void testReadTTFByte() throws IOException { - for (int i = 0; i < 256; i++) { - assertEquals((byte) i, fontReader.readTTFByte()); - } - } - - /** - * Test seekSet() - check that it moves to the correct position and enforce a failure case. - * @throws IOException exception - */ - public void testSeekSet() throws IOException { - fontReader.seekSet(10); - assertEquals(10, fontReader.readTTFByte()); - try { - fontReader.seekSet(257); - fail("FileFontReaderTest Failed testSeekSet"); - } catch (IOException e) { - // Passed - } - } - - /** - * Test skip() - check that it moves to the correct position and enforce a failure case. - * @throws IOException exception - */ - public void testSkip() throws IOException { - fontReader.skip(100); - assertEquals(100, fontReader.readTTFByte()); - try { - // 100 (seekAdd) + 1 (read() = 1 byte) + 156 = 257 - fontReader.skip(156); - fail("FileFontReaderTest Failed testSkip"); - } catch (IOException e) { - // Passed - } - } - - /** - * Test getCurrentPos() - 3 checks: - * 1) test with seekSet(int) - * 2) test with skip(int) - * 3) test with a readTTFByte() (this moves the position by the size of the data being read) - * @throws IOException exception - */ - public void testGetCurrentPos() throws IOException { - fontReader.seekSet(10); - fontReader.skip(100); - assertEquals(110, fontReader.getCurrentPos()); - fontReader.readTTFByte(); - assertEquals(111, fontReader.getCurrentPos()); - } - - /** - * Test getFileSize() - */ - public void testGetFileSize() { - assertEquals(256, fontReader.getFileSize()); - } - - /** - * Test readTTFUByte() - * @throws IOException exception - */ - public void testReadTTFUByte() throws IOException { - for (int i = 0; i < 256; i++) { - assertEquals(i, fontReader.readTTFUByte()); - } - } - - /** - * Test readTTFShort() - Test positive and negative numbers (two's compliment). - * @throws IOException exception - */ - public void testReadTTFShort() throws IOException { - // 0x0001 = 1 - assertEquals("Should have been 1 (0x0001)", 1, fontReader.readTTFShort()); - // 0x0203 = 515 - assertEquals(515, fontReader.readTTFShort()); - // now test negative numbers - fontReader.seekSet(250); - // 0xfafb - assertEquals(-1285, fontReader.readTTFShort()); - } - - /** - * Test readTTFUShort() - Test positive and potentially negative numbers (two's compliment). - * @throws IOException exception - */ - public void testReadTTFUShort() throws IOException { - // 0x0001 - assertEquals(1, fontReader.readTTFUShort()); - // 0x0203 - assertEquals(515, fontReader.readTTFUShort()); - // test potential negatives - fontReader.seekSet(250); - // 0xfafb - assertEquals((250 << 8) + 251, fontReader.readTTFUShort()); - } - - /** - * Test readTTFShort(int) - test reading ahead of current position and behind current position - * and in both cases ensure that our current position isn't changed. - * @throws IOException exception - */ - public void testReadTTFShortWithArg() throws IOException { - // 0x6465 - assertEquals(25701, fontReader.readTTFShort(100)); - assertEquals(0, fontReader.getCurrentPos()); - // read behind current position (and negative) - fontReader.seekSet(255); - // 0xfafb - assertEquals(-1285, fontReader.readTTFShort(250)); - assertEquals(255, fontReader.getCurrentPos()); - } - - /** - * Test readTTFUShort(int arg) - test reading ahead of current position and behind current - * position and in both cases ensure that our current position isn't changed. - * @throws IOException exception - */ - public void testReadTTFUShortWithArg() throws IOException { - // 0x6465 - assertEquals(25701, fontReader.readTTFUShort(100)); - assertEquals(0, fontReader.getCurrentPos()); - // read behind current position (and potential negative) - fontReader.seekSet(255); - // 0xfafb - assertEquals(64251, fontReader.readTTFUShort(250)); - assertEquals(255, fontReader.getCurrentPos()); - } - - /** - * Test readTTFLong() - * @throws IOException exception - */ - public void testReadTTFLong() throws IOException { - // 0x00010203 - assertEquals(66051, fontReader.readTTFLong()); - // test negative numbers - fontReader.seekSet(250); - // 0xf0f1f2f3 - assertEquals(-84148995, fontReader.readTTFLong()); - } - - /** - * Test readTTFULong() - * @throws IOException exception - */ - public void testReadTTFULong() throws IOException { - // 0x00010203 - assertEquals(66051, fontReader.readTTFULong()); - // test negative numbers - fontReader.seekSet(250); - // 0xfafbfcfd - assertEquals(4210818301L, fontReader.readTTFULong()); - } - - /** - * Test readTTFString() - there are two paths to test here: - * 1) A null terminated string - * 2) A string not terminated with a null (we expect this to throw an EOFException) - * @throws IOException exception - */ - public void testReadTTFString() throws IOException { - byte[] strByte = {(byte)'t', (byte)'e', (byte)'s', (byte)'t', 0x00}; - fontReader = new FontFileReader(new ByteArrayInputStream(strByte)); - assertEquals("test", fontReader.readTTFString()); - try { - // not NUL terminated - byte[] strByteNoNull = {(byte)'t', (byte)'e', (byte)'s', (byte)'t'}; - fontReader = new FontFileReader(new ByteArrayInputStream(strByteNoNull)); - assertEquals("test", fontReader.readTTFString()); - fail("FontFileReaderTest testReadTTFString Fails."); - } catch (EOFException e) { - // Pass - } - } - - /** - * Test readTTFString(int arg) - * @throws IOException exception - */ - public void testReadTTFStringIntArg() throws IOException { - byte[] strByte = {(byte)'t', (byte)'e', (byte)'s', (byte)'t'}; - fontReader = new FontFileReader(new ByteArrayInputStream(strByte)); - assertEquals("test", fontReader.readTTFString(4)); - try { - fontReader = new FontFileReader(new ByteArrayInputStream(strByte)); - assertEquals("test", fontReader.readTTFString(5)); - fail("FontFileReaderTest testReadTTFStringIntArg Fails."); - } catch (EOFException e) { - // Pass - } - } - - /** - * Test readTTFString(int arg1, int arg2) - */ - public void testReadTTFString2IntArgs() { - // currently the same as above - } - - /** - * Test getBytes() - * @throws IOException exception - */ - public void testGetBytes() throws IOException { - byte[] retrievedBytes = fontReader.getBytes(0, 256); - assertTrue(Arrays.equals(byteArray, retrievedBytes)); - } -} diff --git a/test/java/org/apache/fop/fonts/truetype/FontFileReaderTestCase.java b/test/java/org/apache/fop/fonts/truetype/FontFileReaderTestCase.java new file mode 100644 index 000000000..5c1fec175 --- /dev/null +++ b/test/java/org/apache/fop/fonts/truetype/FontFileReaderTestCase.java @@ -0,0 +1,304 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts.truetype; + +import java.io.ByteArrayInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * A test class for org.apache.fop.truetype.FontFileReader + */ +public class FontFileReaderTestCase { + private FontFileReader fontReader; + private final InputStream in; + private final byte[] byteArray; + + /** + * Constructor - initialises an array that only needs to be created once. It creates a byte[] + * of form { 0x00, 0x01, 0x02, 0x03..., 0xff}; + */ + public FontFileReaderTestCase() { + byteArray = new byte[256]; + for (int i = 0; i < 256; i++) { + byteArray[i] = (byte) i; + } + in = new ByteArrayInputStream(byteArray); + } + + /** + * sets up the test subject object for testing. + */ + @Before + public void setUp() { + try { + fontReader = new FontFileReader(in); + } catch (Exception e) { + fail("Error: " + e.getMessage()); + } + } + + /** + * the "destructor" method. + * + */ + public void tearDown() { + fontReader = null; + } + + /** + * Test readTTFByte() + * @throws IOException exception + */ + @Test + public void testReadTTFByte() throws IOException { + for (int i = 0; i < 256; i++) { + assertEquals((byte) i, fontReader.readTTFByte()); + } + } + + /** + * Test seekSet() - check that it moves to the correct position and enforce a failure case. + * @throws IOException exception + */ + @Test + public void testSeekSet() throws IOException { + fontReader.seekSet(10); + assertEquals(10, fontReader.readTTFByte()); + try { + fontReader.seekSet(257); + fail("FileFontReaderTest Failed testSeekSet"); + } catch (IOException e) { + // Passed + } + } + + /** + * Test skip() - check that it moves to the correct position and enforce a failure case. + * @throws IOException exception + */ + @Test + public void testSkip() throws IOException { + fontReader.skip(100); + assertEquals(100, fontReader.readTTFByte()); + try { + // 100 (seekAdd) + 1 (read() = 1 byte) + 156 = 257 + fontReader.skip(156); + fail("FileFontReaderTest Failed testSkip"); + } catch (IOException e) { + // Passed + } + } + + /** + * Test getCurrentPos() - 3 checks: + * 1) test with seekSet(int) + * 2) test with skip(int) + * 3) test with a readTTFByte() (this moves the position by the size of the data being read) + * @throws IOException exception + */ + @Test + public void testGetCurrentPos() throws IOException { + fontReader.seekSet(10); + fontReader.skip(100); + assertEquals(110, fontReader.getCurrentPos()); + fontReader.readTTFByte(); + assertEquals(111, fontReader.getCurrentPos()); + } + + /** + * Test getFileSize() + */ + @Test + public void testGetFileSize() { + assertEquals(256, fontReader.getFileSize()); + } + + /** + * Test readTTFUByte() + * @throws IOException exception + */ + @Test + public void testReadTTFUByte() throws IOException { + for (int i = 0; i < 256; i++) { + assertEquals(i, fontReader.readTTFUByte()); + } + } + + /** + * Test readTTFShort() - Test positive and negative numbers (two's compliment). + * @throws IOException exception + */ + @Test + public void testReadTTFShort() throws IOException { + // 0x0001 = 1 + assertEquals("Should have been 1 (0x0001)", 1, fontReader.readTTFShort()); + // 0x0203 = 515 + assertEquals(515, fontReader.readTTFShort()); + // now test negative numbers + fontReader.seekSet(250); + // 0xfafb + assertEquals(-1285, fontReader.readTTFShort()); + } + + /** + * Test readTTFUShort() - Test positive and potentially negative numbers (two's compliment). + * @throws IOException exception + */ + @Test + public void testReadTTFUShort() throws IOException { + // 0x0001 + assertEquals(1, fontReader.readTTFUShort()); + // 0x0203 + assertEquals(515, fontReader.readTTFUShort()); + // test potential negatives + fontReader.seekSet(250); + // 0xfafb + assertEquals((250 << 8) + 251, fontReader.readTTFUShort()); + } + + /** + * Test readTTFShort(int) - test reading ahead of current position and behind current position + * and in both cases ensure that our current position isn't changed. + * @throws IOException exception + */ + @Test + public void testReadTTFShortWithArg() throws IOException { + // 0x6465 + assertEquals(25701, fontReader.readTTFShort(100)); + assertEquals(0, fontReader.getCurrentPos()); + // read behind current position (and negative) + fontReader.seekSet(255); + // 0xfafb + assertEquals(-1285, fontReader.readTTFShort(250)); + assertEquals(255, fontReader.getCurrentPos()); + } + + /** + * Test readTTFUShort(int arg) - test reading ahead of current position and behind current + * position and in both cases ensure that our current position isn't changed. + * @throws IOException exception + */ + @Test + public void testReadTTFUShortWithArg() throws IOException { + // 0x6465 + assertEquals(25701, fontReader.readTTFUShort(100)); + assertEquals(0, fontReader.getCurrentPos()); + // read behind current position (and potential negative) + fontReader.seekSet(255); + // 0xfafb + assertEquals(64251, fontReader.readTTFUShort(250)); + assertEquals(255, fontReader.getCurrentPos()); + } + + /** + * Test readTTFLong() + * @throws IOException exception + */ + @Test + public void testReadTTFLong() throws IOException { + // 0x00010203 + assertEquals(66051, fontReader.readTTFLong()); + // test negative numbers + fontReader.seekSet(250); + // 0xf0f1f2f3 + assertEquals(-84148995, fontReader.readTTFLong()); + } + + /** + * Test readTTFULong() + * @throws IOException exception + */ + @Test + public void testReadTTFULong() throws IOException { + // 0x00010203 + assertEquals(66051, fontReader.readTTFULong()); + // test negative numbers + fontReader.seekSet(250); + // 0xfafbfcfd + assertEquals(4210818301L, fontReader.readTTFULong()); + } + + /** + * Test readTTFString() - there are two paths to test here: + * 1) A null terminated string + * 2) A string not terminated with a null (we expect this to throw an EOFException) + * @throws IOException exception + */ + @Test + public void testReadTTFString() throws IOException { + byte[] strByte = {(byte)'t', (byte)'e', (byte)'s', (byte)'t', 0x00}; + fontReader = new FontFileReader(new ByteArrayInputStream(strByte)); + assertEquals("test", fontReader.readTTFString()); + try { + // not NUL terminated + byte[] strByteNoNull = {(byte)'t', (byte)'e', (byte)'s', (byte)'t'}; + fontReader = new FontFileReader(new ByteArrayInputStream(strByteNoNull)); + assertEquals("test", fontReader.readTTFString()); + fail("FontFileReaderTest testReadTTFString Fails."); + } catch (EOFException e) { + // Pass + } + } + + /** + * Test readTTFString(int arg) + * @throws IOException exception + */ + @Test + public void testReadTTFStringIntArg() throws IOException { + byte[] strByte = {(byte)'t', (byte)'e', (byte)'s', (byte)'t'}; + fontReader = new FontFileReader(new ByteArrayInputStream(strByte)); + assertEquals("test", fontReader.readTTFString(4)); + try { + fontReader = new FontFileReader(new ByteArrayInputStream(strByte)); + assertEquals("test", fontReader.readTTFString(5)); + fail("FontFileReaderTest testReadTTFStringIntArg Fails."); + } catch (EOFException e) { + // Pass + } + } + + /** + * Test readTTFString(int arg1, int arg2) + */ + public void testReadTTFString2IntArgs() { + // currently the same as above + } + + /** + * Test getBytes() + * @throws IOException exception + */ + @Test + public void testGetBytes() throws IOException { + byte[] retrievedBytes = fontReader.getBytes(0, 256); + assertTrue(Arrays.equals(byteArray, retrievedBytes)); + } +} diff --git a/test/java/org/apache/fop/fonts/truetype/TTFFileTest.java b/test/java/org/apache/fop/fonts/truetype/TTFFileTest.java deleted file mode 100644 index ccc12d991..000000000 --- a/test/java/org/apache/fop/fonts/truetype/TTFFileTest.java +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.IOException; -import java.util.Map; - -import junit.framework.TestCase; - -import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; - -/** - * Class for testing org.apache.fop.fonts.truetype.TTFFile - */ -public class TTFFileTest extends TestCase { - // We only want to initialize the FontFileReader once (for performance reasons) - /** The truetype font file (DejaVuLGCSerif) */ - protected final TTFFile dejavuTTFFile; - /** The FontFileReader for ttfFile (DejaVuLGCSerif) */ - protected final FontFileReader dejavuReader; - /** The truetype font file (DroidSansMono) */ - protected final TTFFile droidmonoTTFFile; - /** The FontFileReader for ttfFile (DroidSansMono) */ - protected final FontFileReader droidmonoReader; - - - /** - * Constructor initialises FileFontReader to - * @throws IOException exception - */ - public TTFFileTest() throws IOException { - dejavuTTFFile = new TTFFile(); - dejavuReader = new FontFileReader("test/resources/fonts/DejaVuLGCSerif.ttf"); - dejavuTTFFile.readFont(dejavuReader); - droidmonoTTFFile = new TTFFile(); - droidmonoReader = new FontFileReader("test/resources/fonts/DroidSansMono.ttf"); - droidmonoTTFFile.readFont(droidmonoReader); - } - - /** - * Test convertTTFUnit2PDFUnit() - The units per em retrieved reading the HEAD table from - * the font file. (DroidSansMono has the same units per em as DejaVu so no point testing it) - */ - public void testConvertTTFUnit2PDFUnit() { - // DejaVu has 2048 units per em (PDF works in millipts, thus the 1000) - // test rational number - assertEquals(1000, dejavuTTFFile.convertTTFUnit2PDFUnit(2048)); - // test smallest case, this should = 0.488 (round down to 0) - assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(1)); - // this should round up, but since it's millipts... - assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(2)); - // ensure behaviour is the same for negative numbers - assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(-0)); - assertEquals(-1000, dejavuTTFFile.convertTTFUnit2PDFUnit(-2048)); - assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(-1)); - assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(-2)); - } - - /** - * Test checkTTC() - * @throws IOException exception - */ - public void testCheckTTC() throws IOException { - // DejaVu is not a TTC, thus this returns true - assertTrue(dejavuTTFFile.checkTTC("")); - assertTrue(droidmonoTTFFile.checkTTC("")); - /* - * Cannot reasonably test the rest of this method without an actual truetype collection - * because all methods in FontFileReader are "final" and thus mocking isn't possible. - */ - } - - /** - * Test getAnsiKerning() - Tests values retrieved from the kern table in the font file. - */ - public void testGetAnsiKerning() { - Map> ansiKerning = dejavuTTFFile.getKerning(); - if (ansiKerning.isEmpty()) { - fail(); - } - Integer k1 = ansiKerning.get(Integer.valueOf('A')).get( - Integer.valueOf('T')); - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-112), k1.intValue()); - Integer k2 = ansiKerning.get(Integer.valueOf('Y')).get(Integer.valueOf('u')); - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-178), k2.intValue()); - - // DroidSansMono doens't have kerning (it's mono-spaced) - ansiKerning = droidmonoTTFFile.getAnsiKerning(); - if (!ansiKerning.isEmpty()) { - fail("DroidSansMono shouldn't have any kerning data."); - } - } - - /** - * Test getCapHeight - there are several paths to test: - * 1) The PCLT table (if present) - * 2) The yMax (3rd) value, for the bounding box, for 'H' in the glyf table. - * if not the above: - * 3) The caps height in the OS/2 table - * Tests values retrieved from analysing the font file. - */ - public void testGetCapHeight() { - // DejaVu doesn't have the PCLT table and so these have to be guessed - // The height is approximated to be the height of the "H" which for - // Deja = 1493 TTFunits - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1493), dejavuTTFFile.getCapHeight()); - // DroidSansMono doesn't have a PCLT table either - // height of "H" = 1462 - assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1462), - droidmonoTTFFile.getCapHeight()); - } - - /** - * Test getCharSetName() - check that it returns "WinAnsiEncoding". - */ - public void testGetCharSetName() { - assertTrue("WinAnsiEncoding".equals(dejavuTTFFile.getCharSetName())); - assertTrue("WinAnsiEncoding".equals(droidmonoTTFFile.getCharSetName())); - } - - /** - * Test getCharWidth() - Test values retrieved from the metrics in the glyf table in - * the font file. - */ - public void testGetCharWidth() { - // Arbitrarily test a few values: - // The width of "H" (Unicode index 0x0048) is 1786 - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1786), dejavuTTFFile.getCharWidth(0x48)); - // The width of "i" (unicode index 0x0069) is 655 TTFunits - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(655), dejavuTTFFile.getCharWidth(0x69)); - // final check, "!" (unicode index 0x0021) is 823 TTFunits - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(823), dejavuTTFFile.getCharWidth(0x21)); - - // All the glyphs should be the same width in DroidSansMono (mono-spaced) - int charWidth = droidmonoTTFFile.convertTTFUnit2PDFUnit(1229); - for (int i = 0; i < 255; i++) { - assertEquals(charWidth, droidmonoTTFFile.getCharWidth(i)); - } - } - - /** - * TODO: add implementation to this test - */ - public void testGetCMaps() { - } - - /** - * Test getFamilyNames() - Test value retrieved from the name table in the font file. - */ - public void testGetFamilyNames() { - assertEquals(1, dejavuTTFFile.getFamilyNames().size()); - for (String name : dejavuTTFFile.getFamilyNames()) { - assertEquals("DejaVu LGC Serif", name); - } - assertEquals(1, droidmonoTTFFile.getFamilyNames().size()); - for (String name : droidmonoTTFFile.getFamilyNames()) { - assertEquals("Droid Sans Mono", name); - } - } - - /** - * Test getFirstChar() - TODO: implement a more intelligent test here. - */ - public void testGetFirstChar() { - // Not really sure how to test this intelligently - assertEquals(0, dejavuTTFFile.getFirstChar()); - assertEquals(0, droidmonoTTFFile.getFirstChar()); - } - - /** - * Test getFlags() - Test values retrieved from the POST table in the font file. - */ - public void testGetFlags() { - /* DejaVu flags are: - * italic angle = 0 - * fixed pitch = 0 - * has serifs = true (default value; this font doesn't have a PCLT table) - */ - int flags = dejavuTTFFile.getFlags(); - assertEquals(0, flags & 64); // Italics angle = 0 - assertEquals(32, flags & 32); // Adobe standard charset - assertEquals(0, flags & 2); // fixed pitch = 0 - assertEquals(1, flags & 1); // has serifs = 1 (true) - /* - * Droid flags are: - * italic angle = 0 - * fixed pitch = 1 - * has serifs = true (default value; this font doesn't have a PCLT table) - */ - flags = droidmonoTTFFile.getFlags(); - assertEquals(0, flags & 64); - assertEquals(32, flags & 32); - assertEquals(2, flags & 2); - assertEquals(1, flags & 1); - } - - /** - * Test getFontBBox() - Test values retrieved from values in the HEAD table in the font file. - */ - public void testGetFontBBox() { - int[] bBox = dejavuTTFFile.getFontBBox(); - /* - * The head table has the following values(DejaVu): - * xmin = -1576, ymin = -710, xmax = 3439, ymax = 2544 - */ - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-1576), bBox[0]); - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-710), bBox[1]); - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(3439), bBox[2]); - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(2544), bBox[3]); - /* - * The head table has the following values (DroidSansMono): - * xmin = -312, ymin= -555, xmax = 1315, ymax = 2163 - */ - bBox = droidmonoTTFFile.getFontBBox(); - assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(-312), bBox[0]); - assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(-555), bBox[1]); - assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1315), bBox[2]); - assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(2163), bBox[3]); - } - - /** - * Test getFullName() - Test value retrieved from the name table in the font file. - */ - public void testGetFullName() { - assertEquals("DejaVu LGC Serif", dejavuTTFFile.getFullName()); - assertEquals("Droid Sans Mono", droidmonoTTFFile.getFullName()); - } - - /** - * Test getGlyphName - Test value retrieved from the POST table in the font file. - */ - public void testGetGlyphName() { - assertEquals("H", dejavuTTFFile.getGlyphName(43)); - assertEquals("H", droidmonoTTFFile.getGlyphName(43)); - } - - /** - * Test getItalicAngle() - Test value retrieved from the POST table in the font file. - */ - public void testGetItalicAngle() { - assertEquals("0", dejavuTTFFile.getItalicAngle()); - assertEquals("0", droidmonoTTFFile.getItalicAngle()); - } - - /** - * Test getKerning() - Test values retrieved from the kern table in the font file. - */ - public void testGetKerning() { - Map> kerning = dejavuTTFFile.getKerning(); - if (kerning.isEmpty()) { - fail(); - } - Integer k1 = kerning.get(Integer.valueOf('A')).get(Integer.valueOf('T')); - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-112), k1.intValue()); - Integer k2 = kerning.get(Integer.valueOf('K')).get(Integer.valueOf('u')); - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-45), k2.intValue()); - - // DroidSansMono has no kerning data (mono-spaced) - kerning = droidmonoTTFFile.getKerning(); - if (!kerning.isEmpty()) { - fail("DroidSansMono shouldn't have any kerning data"); - } - } - - /** - * Test lastChar() - TODO: implement a more intelligent test - */ - public void testLastChar() { - assertEquals(0xff, dejavuTTFFile.getLastChar()); - assertEquals(0xff, droidmonoTTFFile.getLastChar()); - } - - /** - * Test getLowerCaseAscent() - There are several paths to test: - * 1) The values in the HHEA table (see code) - * 2) Fall back to values from the OS/2 table - * Test values retrieved from the font file. - */ - public void testGetLowerCaseAscent() { - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1556), - dejavuTTFFile.getLowerCaseAscent()); - // Curiously the same value - assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1556), - droidmonoTTFFile.getLowerCaseAscent()); - } - - /** - * Test getPostScriptName() - Test values retrieved from the post table in the font file. - */ - public void testGetPostScriptName() { - assertEquals(PostScriptVersion.V2, dejavuTTFFile.getPostScriptVersion()); - assertEquals(PostScriptVersion.V2, droidmonoTTFFile.getPostScriptVersion()); - } - - /** - * Test getStemV() - Undefined. - */ - public void testGetStemV() { - // Undefined - assertEquals("0", dejavuTTFFile.getStemV()); - assertEquals("0", droidmonoTTFFile.getStemV()); - } - - /** - * Test getSubFamilyName() - Test values retrieved from the name table in the font file. - */ - public void testGetSubFamilyName() { - assertEquals("Book", dejavuTTFFile.getSubFamilyName()); - assertEquals("Regular", droidmonoTTFFile.getSubFamilyName()); - } - - /** - * Test getTTCnames() - TODO: add implementation with TTC font. - */ - public void testGetTTCnames() { - // Can't test with with DejaVu since it's not a TrueType Collection - } - - /** - * Test getWeightClass() - Test value retrieved from the OS/2 table in the font file. - */ - public void testGetWeightClass() { - // Retrieved from OS/2 table - assertEquals(400, dejavuTTFFile.getWeightClass()); - assertEquals(400, droidmonoTTFFile.getWeightClass()); - } - - /** - * Test getWidths() - Test values retrieved from the hmtx table in the font file. - */ - public void testGetWidths() { - int[] widths = dejavuTTFFile.getWidths(); - // using the width of 'A' index = 36 - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1479), widths[36]); - // using the width of '|' index = 95 - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(690), widths[95]); - widths = droidmonoTTFFile.getWidths(); - // DroidSansMono should have all widths the same size (mono-spaced) - int width = droidmonoTTFFile.convertTTFUnit2PDFUnit(1229); - for (int i = 0; i < 255; i++) { - assertEquals(width, widths[i]); - } - } - - /** - * Test getXHeight() - There are several paths to test: - * 1) The PCLT table (if available) - * 2) The yMax for the bounding box for 'x' in the glyf table. - * Fall back: - * 3) The xheight in the OS/2 table. - */ - public void testGetXHeight() { - // Since there's no PCLT table, the height of 'x' is used for both DejaVu and DroidSansMono - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1064), dejavuTTFFile.getXHeight()); - assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1098), droidmonoTTFFile.getXHeight()); - } - - /** - * Test isCFF() - TODO: add test for a CFF font. - */ - public void testIsCFF() { - // Neither DejaVu nor DroidSansMono are a compact format font - assertEquals(false, dejavuTTFFile.isCFF()); - assertEquals(false, droidmonoTTFFile.isCFF()); - } - - /** - * Test isEmbeddable() - Test value retrieved from the OS/2 table in the font file. - */ - public void testIsEmbeddable() { - // Dejavu and DroidSansMono are both embeddable - assertEquals(true, dejavuTTFFile.isEmbeddable()); - assertEquals(true, droidmonoTTFFile.isEmbeddable()); - } - - /** - * Test readFont() - Add implementation if necessary. - */ - public void testReadFont() { - // I'm pretty sure we've tested this with all the other tests - } -} diff --git a/test/java/org/apache/fop/fonts/truetype/TTFFileTestCase.java b/test/java/org/apache/fop/fonts/truetype/TTFFileTestCase.java new file mode 100644 index 000000000..d490a3d5d --- /dev/null +++ b/test/java/org/apache/fop/fonts/truetype/TTFFileTestCase.java @@ -0,0 +1,427 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts.truetype; + +import java.io.IOException; +import java.util.Map; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; + +/** + * Class for testing org.apache.fop.fonts.truetype.TTFFile + */ +public class TTFFileTestCase { + // We only want to initialize the FontFileReader once (for performance reasons) + /** The truetype font file (DejaVuLGCSerif) */ + protected final TTFFile dejavuTTFFile; + /** The FontFileReader for ttfFile (DejaVuLGCSerif) */ + protected final FontFileReader dejavuReader; + /** The truetype font file (DroidSansMono) */ + protected final TTFFile droidmonoTTFFile; + /** The FontFileReader for ttfFile (DroidSansMono) */ + protected final FontFileReader droidmonoReader; + + + /** + * Constructor initialises FileFontReader to + * @throws IOException exception + */ + public TTFFileTestCase() throws IOException { + dejavuTTFFile = new TTFFile(); + dejavuReader = new FontFileReader("test/resources/fonts/ttf/DejaVuLGCSerif.ttf"); + dejavuTTFFile.readFont(dejavuReader); + droidmonoTTFFile = new TTFFile(); + droidmonoReader = new FontFileReader("test/resources/fonts/ttf/DroidSansMono.ttf"); + droidmonoTTFFile.readFont(droidmonoReader); + } + + /** + * Test convertTTFUnit2PDFUnit() - The units per em retrieved reading the HEAD table from + * the font file. (DroidSansMono has the same units per em as DejaVu so no point testing it) + */ + @Test + public void testConvertTTFUnit2PDFUnit() { + // DejaVu has 2048 units per em (PDF works in millipts, thus the 1000) + // test rational number + assertEquals(1000, dejavuTTFFile.convertTTFUnit2PDFUnit(2048)); + // test smallest case, this should = 0.488 (round down to 0) + assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(1)); + // this should round up, but since it's millipts... + assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(2)); + // ensure behaviour is the same for negative numbers + assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(-0)); + assertEquals(-1000, dejavuTTFFile.convertTTFUnit2PDFUnit(-2048)); + assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(-1)); + assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(-2)); + } + + /** + * Test checkTTC() + * @throws IOException exception + */ + @Test + public void testCheckTTC() throws IOException { + // DejaVu is not a TTC, thus this returns true + assertTrue(dejavuTTFFile.checkTTC("")); + assertTrue(droidmonoTTFFile.checkTTC("")); + /* + * Cannot reasonably test the rest of this method without an actual truetype collection + * because all methods in FontFileReader are "final" and thus mocking isn't possible. + */ + } + + /** + * Test getAnsiKerning() - Tests values retrieved from the kern table in the font file. + */ + @Test + public void testGetAnsiKerning() { + Map> ansiKerning = dejavuTTFFile.getKerning(); + if (ansiKerning.isEmpty()) { + fail(); + } + Integer k1 = ansiKerning.get(Integer.valueOf('A')).get( + Integer.valueOf('T')); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-112), k1.intValue()); + Integer k2 = ansiKerning.get(Integer.valueOf('Y')).get(Integer.valueOf('u')); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-178), k2.intValue()); + + // DroidSansMono doens't have kerning (it's mono-spaced) + ansiKerning = droidmonoTTFFile.getAnsiKerning(); + if (!ansiKerning.isEmpty()) { + fail("DroidSansMono shouldn't have any kerning data."); + } + } + + /** + * Test getCapHeight - there are several paths to test: + * 1) The PCLT table (if present) + * 2) The yMax (3rd) value, for the bounding box, for 'H' in the glyf table. + * if not the above: + * 3) The caps height in the OS/2 table + * Tests values retrieved from analysing the font file. + */ + @Test + public void testGetCapHeight() { + // DejaVu doesn't have the PCLT table and so these have to be guessed + // The height is approximated to be the height of the "H" which for + // Deja = 1493 TTFunits + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1493), dejavuTTFFile.getCapHeight()); + // DroidSansMono doesn't have a PCLT table either + // height of "H" = 1462 + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1462), + droidmonoTTFFile.getCapHeight()); + } + + /** + * Test getCharSetName() - check that it returns "WinAnsiEncoding". + */ + @Test + public void testGetCharSetName() { + assertTrue("WinAnsiEncoding".equals(dejavuTTFFile.getCharSetName())); + assertTrue("WinAnsiEncoding".equals(droidmonoTTFFile.getCharSetName())); + } + + /** + * Test getCharWidth() - Test values retrieved from the metrics in the glyf table in + * the font file. + */ + @Test + public void testGetCharWidth() { + // Arbitrarily test a few values: + // The width of "H" (Unicode index 0x0048) is 1786 + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1786), dejavuTTFFile.getCharWidth(0x48)); + // The width of "i" (unicode index 0x0069) is 655 TTFunits + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(655), dejavuTTFFile.getCharWidth(0x69)); + // final check, "!" (unicode index 0x0021) is 823 TTFunits + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(823), dejavuTTFFile.getCharWidth(0x21)); + + // All the glyphs should be the same width in DroidSansMono (mono-spaced) + int charWidth = droidmonoTTFFile.convertTTFUnit2PDFUnit(1229); + for (int i = 0; i < 255; i++) { + assertEquals(charWidth, droidmonoTTFFile.getCharWidth(i)); + } + } + + /** + * TODO: add implementation to this test + */ + public void testGetCMaps() { + } + + /** + * Test getFamilyNames() - Test value retrieved from the name table in the font file. + */ + @Test + public void testGetFamilyNames() { + assertEquals(1, dejavuTTFFile.getFamilyNames().size()); + for (String name : dejavuTTFFile.getFamilyNames()) { + assertEquals("DejaVu LGC Serif", name); + } + assertEquals(1, droidmonoTTFFile.getFamilyNames().size()); + for (String name : droidmonoTTFFile.getFamilyNames()) { + assertEquals("Droid Sans Mono", name); + } + } + + /** + * Test getFirstChar() - TODO: implement a more intelligent test here. + */ + @Test + public void testGetFirstChar() { + // Not really sure how to test this intelligently + assertEquals(0, dejavuTTFFile.getFirstChar()); + assertEquals(0, droidmonoTTFFile.getFirstChar()); + } + + /** + * Test getFlags() - Test values retrieved from the POST table in the font file. + */ + @Test + public void testGetFlags() { + /* DejaVu flags are: + * italic angle = 0 + * fixed pitch = 0 + * has serifs = true (default value; this font doesn't have a PCLT table) + */ + int flags = dejavuTTFFile.getFlags(); + assertEquals(0, flags & 64); // Italics angle = 0 + assertEquals(32, flags & 32); // Adobe standard charset + assertEquals(0, flags & 2); // fixed pitch = 0 + assertEquals(1, flags & 1); // has serifs = 1 (true) + /* + * Droid flags are: + * italic angle = 0 + * fixed pitch = 1 + * has serifs = true (default value; this font doesn't have a PCLT table) + */ + flags = droidmonoTTFFile.getFlags(); + assertEquals(0, flags & 64); + assertEquals(32, flags & 32); + assertEquals(2, flags & 2); + assertEquals(1, flags & 1); + } + + /** + * Test getFontBBox() - Test values retrieved from values in the HEAD table in the font file. + */ + @Test + public void testGetFontBBox() { + int[] bBox = dejavuTTFFile.getFontBBox(); + /* + * The head table has the following values(DejaVu): + * xmin = -1576, ymin = -710, xmax = 3439, ymax = 2544 + */ + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-1576), bBox[0]); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-710), bBox[1]); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(3439), bBox[2]); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(2544), bBox[3]); + /* + * The head table has the following values (DroidSansMono): + * xmin = -312, ymin= -555, xmax = 1315, ymax = 2163 + */ + bBox = droidmonoTTFFile.getFontBBox(); + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(-312), bBox[0]); + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(-555), bBox[1]); + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1315), bBox[2]); + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(2163), bBox[3]); + } + + /** + * Test getFullName() - Test value retrieved from the name table in the font file. + */ + @Test + public void testGetFullName() { + assertEquals("DejaVu LGC Serif", dejavuTTFFile.getFullName()); + assertEquals("Droid Sans Mono", droidmonoTTFFile.getFullName()); + } + + /** + * Test getGlyphName - Test value retrieved from the POST table in the font file. + */ + @Test + public void testGetGlyphName() { + assertEquals("H", dejavuTTFFile.getGlyphName(43)); + assertEquals("H", droidmonoTTFFile.getGlyphName(43)); + } + + /** + * Test getItalicAngle() - Test value retrieved from the POST table in the font file. + */ + @Test + public void testGetItalicAngle() { + assertEquals("0", dejavuTTFFile.getItalicAngle()); + assertEquals("0", droidmonoTTFFile.getItalicAngle()); + } + + /** + * Test getKerning() - Test values retrieved from the kern table in the font file. + */ + @Test + public void testGetKerning() { + Map> kerning = dejavuTTFFile.getKerning(); + if (kerning.isEmpty()) { + fail(); + } + Integer k1 = kerning.get(Integer.valueOf('A')).get(Integer.valueOf('T')); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-112), k1.intValue()); + Integer k2 = kerning.get(Integer.valueOf('K')).get(Integer.valueOf('u')); + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-45), k2.intValue()); + + // DroidSansMono has no kerning data (mono-spaced) + kerning = droidmonoTTFFile.getKerning(); + if (!kerning.isEmpty()) { + fail("DroidSansMono shouldn't have any kerning data"); + } + } + + /** + * Test lastChar() - TODO: implement a more intelligent test + */ + @Test + public void testLastChar() { + assertEquals(0xff, dejavuTTFFile.getLastChar()); + assertEquals(0xff, droidmonoTTFFile.getLastChar()); + } + + /** + * Test getLowerCaseAscent() - There are several paths to test: + * 1) The values in the HHEA table (see code) + * 2) Fall back to values from the OS/2 table + * Test values retrieved from the font file. + */ + @Test + public void testGetLowerCaseAscent() { + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1556), + dejavuTTFFile.getLowerCaseAscent()); + // Curiously the same value + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1556), + droidmonoTTFFile.getLowerCaseAscent()); + } + + /** + * Test getPostScriptName() - Test values retrieved from the post table in the font file. + */ + @Test + public void testGetPostScriptName() { + assertEquals(PostScriptVersion.V2, dejavuTTFFile.getPostScriptVersion()); + assertEquals(PostScriptVersion.V2, droidmonoTTFFile.getPostScriptVersion()); + } + + /** + * Test getStemV() - Undefined. + */ + @Test + public void testGetStemV() { + // Undefined + assertEquals("0", dejavuTTFFile.getStemV()); + assertEquals("0", droidmonoTTFFile.getStemV()); + } + + /** + * Test getSubFamilyName() - Test values retrieved from the name table in the font file. + */ + @Test + public void testGetSubFamilyName() { + assertEquals("Book", dejavuTTFFile.getSubFamilyName()); + assertEquals("Regular", droidmonoTTFFile.getSubFamilyName()); + } + + /** + * Test getTTCnames() - TODO: add implementation with TTC font. + */ + public void testGetTTCnames() { + // Can't test with with DejaVu since it's not a TrueType Collection + } + + /** + * Test getWeightClass() - Test value retrieved from the OS/2 table in the font file. + */ + @Test + public void testGetWeightClass() { + // Retrieved from OS/2 table + assertEquals(400, dejavuTTFFile.getWeightClass()); + assertEquals(400, droidmonoTTFFile.getWeightClass()); + } + + /** + * Test getWidths() - Test values retrieved from the hmtx table in the font file. + */ + @Test + public void testGetWidths() { + int[] widths = dejavuTTFFile.getWidths(); + // using the width of 'A' index = 36 + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1479), widths[36]); + // using the width of '|' index = 95 + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(690), widths[95]); + widths = droidmonoTTFFile.getWidths(); + // DroidSansMono should have all widths the same size (mono-spaced) + int width = droidmonoTTFFile.convertTTFUnit2PDFUnit(1229); + for (int i = 0; i < 255; i++) { + assertEquals(width, widths[i]); + } + } + + /** + * Test getXHeight() - There are several paths to test: + * 1) The PCLT table (if available) + * 2) The yMax for the bounding box for 'x' in the glyf table. + * Fall back: + * 3) The xheight in the OS/2 table. + */ + @Test + public void testGetXHeight() { + // Since there's no PCLT table, the height of 'x' is used for both DejaVu and DroidSansMono + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1064), dejavuTTFFile.getXHeight()); + assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1098), droidmonoTTFFile.getXHeight()); + } + + /** + * Test isCFF() - TODO: add test for a CFF font. + */ + @Test + public void testIsCFF() { + // Neither DejaVu nor DroidSansMono are a compact format font + assertEquals(false, dejavuTTFFile.isCFF()); + assertEquals(false, droidmonoTTFFile.isCFF()); + } + + /** + * Test isEmbeddable() - Test value retrieved from the OS/2 table in the font file. + */ + @Test + public void testIsEmbeddable() { + // Dejavu and DroidSansMono are both embeddable + assertEquals(true, dejavuTTFFile.isEmbeddable()); + assertEquals(true, droidmonoTTFFile.isEmbeddable()); + } + + /** + * Test readFont() - Add implementation if necessary. + */ + public void testReadFont() { + // I'm pretty sure we've tested this with all the other tests + } +} diff --git a/test/java/org/apache/fop/fonts/truetype/TTFSubSetFileTest.java b/test/java/org/apache/fop/fonts/truetype/TTFSubSetFileTest.java deleted file mode 100644 index b0ced70e8..000000000 --- a/test/java/org/apache/fop/fonts/truetype/TTFSubSetFileTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -/** - * This class tests TTFSubSetFile - * TODO: Test with more than just a single font - */ -public class TTFSubSetFileTest extends TTFFileTest { - private TTFSubSetFile ttfSubset; - private byte[] subset; - /** - * Constructor - * @throws IOException exception - */ - public TTFSubSetFileTest() throws IOException { - super(); - } - - /** - * setUp() - * @exception IOException file read error - */ - public void setUp() throws IOException { - ttfSubset = new TTFSubSetFile(); - Map glyphs = new HashMap(); - for (int i = 0; i < 255; i++) { - glyphs.put(i, i); - } - ttfSubset.readFont(dejavuReader, "DejaVu", glyphs); - subset = ttfSubset.getFontSubset(); - } - /** - * Test readFont(FontFileReader, String, Map) - Reads the font and tests the output by injecting - * it into a TTFFile object to check the validity of the file as a font. This currently doesn't - * create a cmap table, and so the font doesn't contain ALL of the mandatory tables. - * @throws IOException exception - */ - public void testReadFont3Args() throws IOException { - - ByteArrayInputStream byteArray = new ByteArrayInputStream(subset); - dejavuTTFFile.readFont(new FontFileReader(byteArray)); - // Test a couple arbitrary values - assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-1576), dejavuTTFFile.getFontBBox()[0]); - assertEquals(dejavuTTFFile.getFullName(), "DejaVu LGC Serif"); - } -} diff --git a/test/java/org/apache/fop/fonts/truetype/TTFSubSetFileTestCase.java b/test/java/org/apache/fop/fonts/truetype/TTFSubSetFileTestCase.java new file mode 100644 index 000000000..16bedad8d --- /dev/null +++ b/test/java/org/apache/fop/fonts/truetype/TTFSubSetFileTestCase.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts.truetype; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * This class tests TTFSubSetFile + * TODO: Test with more than just a single font + */ +public class TTFSubSetFileTestCase extends TTFFileTestCase { + private TTFSubSetFile ttfSubset; + private byte[] subset; + /** + * Constructor + * @throws IOException exception + */ + public TTFSubSetFileTestCase() throws IOException { + super(); + } + + /** + * setUp() + * @exception IOException file read error + */ + @Before + public void setUp() throws IOException { + ttfSubset = new TTFSubSetFile(); + Map glyphs = new HashMap(); + for (int i = 0; i < 255; i++) { + glyphs.put(i, i); + } + ttfSubset.readFont(dejavuReader, "DejaVu", glyphs); + subset = ttfSubset.getFontSubset(); + } + /** + * Test readFont(FontFileReader, String, Map) - Reads the font and tests the output by injecting + * it into a TTFFile object to check the validity of the file as a font. This currently doesn't + * create a cmap table, and so the font doesn't contain ALL of the mandatory tables. + * @throws IOException exception + */ + @Test + public void testReadFont3Args() throws IOException { + + ByteArrayInputStream byteArray = new ByteArrayInputStream(subset); + dejavuTTFFile.readFont(new FontFileReader(byteArray)); + // Test a couple arbitrary values + assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-1576), dejavuTTFFile.getFontBBox()[0]); + assertEquals(dejavuTTFFile.getFullName(), "DejaVu LGC Serif"); + } +} diff --git a/test/java/org/apache/fop/fonts/truetype/TTFTableNameTest.java b/test/java/org/apache/fop/fonts/truetype/TTFTableNameTest.java deleted file mode 100644 index 224dad8a3..000000000 --- a/test/java/org/apache/fop/fonts/truetype/TTFTableNameTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import junit.framework.TestCase; - -/** - * This class tests the enum org.apache.fop.fonts.truetype.TTFTableName - * - */ -public class TTFTableNameTest extends TestCase { - /** - * Test getName() - tests that the getName() method returns the expected String as expected in - * the Directory Table. - * @exception IllegalAccessException error - */ - public void testGetName() throws IllegalAccessException { - assertEquals("dirTable", TTFTableName.DIRECTORY_TABLE.getName()); - assertEquals("EBDT", TTFTableName.EBDT.getName()); - assertEquals("EBLC", TTFTableName.EBLC.getName()); - assertEquals("EBSC", TTFTableName.EBSC.getName()); - assertEquals("FFTM", TTFTableName.FFTM.getName()); - assertEquals("GDEF", TTFTableName.GDEF.getName()); - assertEquals("GPOS", TTFTableName.GPOS.getName()); - assertEquals("GSUB", TTFTableName.GSUB.getName()); - assertEquals("LTSH", TTFTableName.LTSH.getName()); - assertEquals("OS/2", TTFTableName.OS2.getName()); - assertEquals("PCLT", TTFTableName.PCLT.getName()); - assertEquals("VDMX", TTFTableName.VDMX.getName()); - assertEquals("cmap", TTFTableName.CMAP.getName()); - assertEquals("cvt ", TTFTableName.CVT.getName()); - assertEquals("fpgm", TTFTableName.FPGM.getName()); - assertEquals("gasp", TTFTableName.GASP.getName()); - assertEquals("glyf", TTFTableName.GLYF.getName()); - assertEquals("hdmx", TTFTableName.HDMX.getName()); - assertEquals("head", TTFTableName.HEAD.getName()); - assertEquals("hhea", TTFTableName.HHEA.getName()); - assertEquals("hmtx", TTFTableName.HMTX.getName()); - assertEquals("kern", TTFTableName.KERN.getName()); - assertEquals("loca", TTFTableName.LOCA.getName()); - assertEquals("maxp", TTFTableName.MAXP.getName()); - assertEquals("name", TTFTableName.NAME.getName()); - assertEquals("post", TTFTableName.POST.getName()); - assertEquals("prep", TTFTableName.PREP.getName()); - assertEquals("vhea", TTFTableName.VHEA.getName()); - assertEquals("vmtx", TTFTableName.VMTX.getName()); - // make sure it works with other table names - TTFTableName test = TTFTableName.getValue("test"); - assertEquals("test", test.getName()); - } - - /** - * Test getValue(String) - tests that the getValue(String) method returns the expected - * TTFTableNames value when it is given a String (name of a table). - * @exception IllegalAccessException error - */ - public void testGetValue() throws IllegalAccessException { - assertEquals(TTFTableName.EBDT, TTFTableName.getValue("EBDT")); - assertEquals(TTFTableName.EBLC, TTFTableName.getValue("EBLC")); - assertEquals(TTFTableName.EBSC, TTFTableName.getValue("EBSC")); - assertEquals(TTFTableName.FFTM, TTFTableName.getValue("FFTM")); - assertEquals(TTFTableName.LTSH, TTFTableName.getValue("LTSH")); - assertEquals(TTFTableName.OS2, TTFTableName.getValue("OS/2")); - assertEquals(TTFTableName.PCLT, TTFTableName.getValue("PCLT")); - assertEquals(TTFTableName.VDMX, TTFTableName.getValue("VDMX")); - assertEquals(TTFTableName.CMAP, TTFTableName.getValue("cmap")); - assertEquals(TTFTableName.CVT, TTFTableName.getValue("cvt ")); - assertEquals(TTFTableName.FPGM, TTFTableName.getValue("fpgm")); - assertEquals(TTFTableName.GASP, TTFTableName.getValue("gasp")); - assertEquals(TTFTableName.GLYF, TTFTableName.getValue("glyf")); - assertEquals(TTFTableName.HDMX, TTFTableName.getValue("hdmx")); - assertEquals(TTFTableName.HEAD, TTFTableName.getValue("head")); - assertEquals(TTFTableName.HHEA, TTFTableName.getValue("hhea")); - assertEquals(TTFTableName.HMTX, TTFTableName.getValue("hmtx")); - assertEquals(TTFTableName.KERN, TTFTableName.getValue("kern")); - assertEquals(TTFTableName.LOCA, TTFTableName.getValue("loca")); - assertEquals(TTFTableName.MAXP, TTFTableName.getValue("maxp")); - assertEquals(TTFTableName.NAME, TTFTableName.getValue("name")); - assertEquals(TTFTableName.POST, TTFTableName.getValue("post")); - assertEquals(TTFTableName.PREP, TTFTableName.getValue("prep")); - assertEquals(TTFTableName.VHEA, TTFTableName.getValue("vhea")); - assertEquals(TTFTableName.VMTX, TTFTableName.getValue("vmtx")); - // Test that we can store a random table name and it will not fail or throw an error. - TTFTableName test = TTFTableName.getValue("random"); - assertTrue(test instanceof TTFTableName); - } - - /** - * This class overrides hashCode() - we need to ensure it works properly by instantiating two - * objects and comparing their hash-codes. - * @exception IllegalAccessException error - */ - public void testHashCode() throws IllegalAccessException { - TTFTableName a = TTFTableName.getValue("testObject"); - TTFTableName b = TTFTableName.getValue("testObject"); - assertTrue(a.hashCode() == b.hashCode()); - TTFTableName c = TTFTableName.getValue("fail"); - assertFalse(a.hashCode() == c.hashCode()); - } - - /** - * This class overrides equals(object) - we need to test: - * 1) Reflexivity - * 2) Symmetry - * 3) Transitivity - * 4) Consistency - * 5) check it fails if you put in a null value - * @throws IllegalAccessException error - */ - public void testEquals() throws IllegalAccessException { - // Reflexivity - TTFTableName a = TTFTableName.getValue("test"); - assertTrue(a.equals(a)); - // Symmetry - TTFTableName b = TTFTableName.getValue("test"); - assertTrue(a.equals(b)); - assertTrue(b.equals(a)); - // Transitivity (tested with symmetry) - // Consistency (test that a == b is true and that a == c fails) - TTFTableName c = TTFTableName.getValue("fail"); - for (int i = 0; i < 100; i++) { - assertTrue(a.equals(b)); - assertFalse(a.equals(c)); - } - // check with null value - assertFalse(a.equals(null)); - } -} diff --git a/test/java/org/apache/fop/fonts/truetype/TTFTableNameTestCase.java b/test/java/org/apache/fop/fonts/truetype/TTFTableNameTestCase.java new file mode 100644 index 000000000..0a2eec544 --- /dev/null +++ b/test/java/org/apache/fop/fonts/truetype/TTFTableNameTestCase.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts.truetype; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * This class tests the enum org.apache.fop.fonts.truetype.TTFTableName + * + */ +public class TTFTableNameTestCase { + /** + * Test getName() - tests that the getName() method returns the expected String as expected in + * the Directory Table. + * @exception IllegalAccessException error + */ + @Test + public void testGetName() throws IllegalAccessException { + assertEquals("dirTable", TTFTableName.DIRECTORY_TABLE.getName()); + assertEquals("EBDT", TTFTableName.EBDT.getName()); + assertEquals("EBLC", TTFTableName.EBLC.getName()); + assertEquals("EBSC", TTFTableName.EBSC.getName()); + assertEquals("FFTM", TTFTableName.FFTM.getName()); + assertEquals("GDEF", TTFTableName.GDEF.getName()); + assertEquals("GPOS", TTFTableName.GPOS.getName()); + assertEquals("GSUB", TTFTableName.GSUB.getName()); + assertEquals("LTSH", TTFTableName.LTSH.getName()); + assertEquals("OS/2", TTFTableName.OS2.getName()); + assertEquals("PCLT", TTFTableName.PCLT.getName()); + assertEquals("VDMX", TTFTableName.VDMX.getName()); + assertEquals("cmap", TTFTableName.CMAP.getName()); + assertEquals("cvt ", TTFTableName.CVT.getName()); + assertEquals("fpgm", TTFTableName.FPGM.getName()); + assertEquals("gasp", TTFTableName.GASP.getName()); + assertEquals("glyf", TTFTableName.GLYF.getName()); + assertEquals("hdmx", TTFTableName.HDMX.getName()); + assertEquals("head", TTFTableName.HEAD.getName()); + assertEquals("hhea", TTFTableName.HHEA.getName()); + assertEquals("hmtx", TTFTableName.HMTX.getName()); + assertEquals("kern", TTFTableName.KERN.getName()); + assertEquals("loca", TTFTableName.LOCA.getName()); + assertEquals("maxp", TTFTableName.MAXP.getName()); + assertEquals("name", TTFTableName.NAME.getName()); + assertEquals("post", TTFTableName.POST.getName()); + assertEquals("prep", TTFTableName.PREP.getName()); + assertEquals("vhea", TTFTableName.VHEA.getName()); + assertEquals("vmtx", TTFTableName.VMTX.getName()); + // make sure it works with other table names + TTFTableName test = TTFTableName.getValue("test"); + assertEquals("test", test.getName()); + } + + /** + * Test getValue(String) - tests that the getValue(String) method returns the expected + * TTFTableNames value when it is given a String (name of a table). + * @exception IllegalAccessException error + */ + @Test + public void testGetValue() throws IllegalAccessException { + assertEquals(TTFTableName.EBDT, TTFTableName.getValue("EBDT")); + assertEquals(TTFTableName.EBLC, TTFTableName.getValue("EBLC")); + assertEquals(TTFTableName.EBSC, TTFTableName.getValue("EBSC")); + assertEquals(TTFTableName.FFTM, TTFTableName.getValue("FFTM")); + assertEquals(TTFTableName.LTSH, TTFTableName.getValue("LTSH")); + assertEquals(TTFTableName.OS2, TTFTableName.getValue("OS/2")); + assertEquals(TTFTableName.PCLT, TTFTableName.getValue("PCLT")); + assertEquals(TTFTableName.VDMX, TTFTableName.getValue("VDMX")); + assertEquals(TTFTableName.CMAP, TTFTableName.getValue("cmap")); + assertEquals(TTFTableName.CVT, TTFTableName.getValue("cvt ")); + assertEquals(TTFTableName.FPGM, TTFTableName.getValue("fpgm")); + assertEquals(TTFTableName.GASP, TTFTableName.getValue("gasp")); + assertEquals(TTFTableName.GLYF, TTFTableName.getValue("glyf")); + assertEquals(TTFTableName.HDMX, TTFTableName.getValue("hdmx")); + assertEquals(TTFTableName.HEAD, TTFTableName.getValue("head")); + assertEquals(TTFTableName.HHEA, TTFTableName.getValue("hhea")); + assertEquals(TTFTableName.HMTX, TTFTableName.getValue("hmtx")); + assertEquals(TTFTableName.KERN, TTFTableName.getValue("kern")); + assertEquals(TTFTableName.LOCA, TTFTableName.getValue("loca")); + assertEquals(TTFTableName.MAXP, TTFTableName.getValue("maxp")); + assertEquals(TTFTableName.NAME, TTFTableName.getValue("name")); + assertEquals(TTFTableName.POST, TTFTableName.getValue("post")); + assertEquals(TTFTableName.PREP, TTFTableName.getValue("prep")); + assertEquals(TTFTableName.VHEA, TTFTableName.getValue("vhea")); + assertEquals(TTFTableName.VMTX, TTFTableName.getValue("vmtx")); + // Test that we can store a random table name and it will not fail or throw an error. + TTFTableName test = TTFTableName.getValue("random"); + assertTrue(test instanceof TTFTableName); + } + + /** + * This class overrides hashCode() - we need to ensure it works properly by instantiating two + * objects and comparing their hash-codes. + * @exception IllegalAccessException error + */ + @Test + public void testHashCode() throws IllegalAccessException { + TTFTableName a = TTFTableName.getValue("testObject"); + TTFTableName b = TTFTableName.getValue("testObject"); + assertTrue(a.hashCode() == b.hashCode()); + TTFTableName c = TTFTableName.getValue("fail"); + assertFalse(a.hashCode() == c.hashCode()); + } + + /** + * This class overrides equals(object) - we need to test: + * 1) Reflexivity + * 2) Symmetry + * 3) Transitivity + * 4) Consistency + * 5) check it fails if you put in a null value + * @throws IllegalAccessException error + */ + @Test + public void testEquals() throws IllegalAccessException { + // Reflexivity + TTFTableName a = TTFTableName.getValue("test"); + assertTrue(a.equals(a)); + // Symmetry + TTFTableName b = TTFTableName.getValue("test"); + assertTrue(a.equals(b)); + assertTrue(b.equals(a)); + // Transitivity (tested with symmetry) + // Consistency (test that a == b is true and that a == c fails) + TTFTableName c = TTFTableName.getValue("fail"); + for (int i = 0; i < 100; i++) { + assertTrue(a.equals(b)); + assertFalse(a.equals(c)); + } + // check with null value + assertFalse(a.equals(null)); + } +} diff --git a/test/java/org/apache/fop/render/ps/RenderPSTestSuite.java b/test/java/org/apache/fop/render/ps/RenderPSTestSuite.java index 6052faeb5..2e15bf91f 100644 --- a/test/java/org/apache/fop/render/ps/RenderPSTestSuite.java +++ b/test/java/org/apache/fop/render/ps/RenderPSTestSuite.java @@ -19,37 +19,25 @@ package org.apache.fop.render.ps; -import junit.framework.Test; -import junit.framework.TestSuite; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; -import org.apache.fop.render.ps.fonts.PSTTFGeneratorTest; -import org.apache.fop.render.ps.fonts.PSTTFGlyphOutputStreamTest; -import org.apache.fop.render.ps.fonts.PSTTFOutputStreamTest; -import org.apache.fop.render.ps.fonts.PSTTFTableOutputStreamTest; +import org.apache.fop.render.ps.fonts.PSTTFGeneratorTestCase; +import org.apache.fop.render.ps.fonts.PSTTFGlyphOutputStreamTestCase; +import org.apache.fop.render.ps.fonts.PSTTFOutputStreamTestCase; +import org.apache.fop.render.ps.fonts.PSTTFTableOutputStreamTestCase; /** * A test Suite for org.apache.fop.render.ps.* */ +@RunWith(Suite.class) +@SuiteClasses({ + PSTTFGeneratorTestCase.class, + PSTTFOutputStreamTestCase.class, + PSTTFGlyphOutputStreamTestCase.class, + PSTTFTableOutputStreamTestCase.class +}) public final class RenderPSTestSuite { - /** - * Constructor. - */ - private RenderPSTestSuite() { - } - - /** - * Testing org.apache.fop.render.ps.* - * @return test - */ - public static Test suite() { - TestSuite suite = new TestSuite(); - //$JUnit-BEGIN$ - suite.addTest(new TestSuite(PSTTFGeneratorTest.class)); - suite.addTest(new TestSuite(PSTTFOutputStreamTest.class)); - suite.addTest(new TestSuite(PSTTFGlyphOutputStreamTest.class)); - suite.addTest(new TestSuite(PSTTFTableOutputStreamTest.class)); - //$JUnit-END$ - return suite; - } } diff --git a/test/java/org/apache/fop/render/ps/fonts/PSTTFGeneratorTest.java b/test/java/org/apache/fop/render/ps/fonts/PSTTFGeneratorTest.java deleted file mode 100644 index fd3d98c98..000000000 --- a/test/java/org/apache/fop/render/ps/fonts/PSTTFGeneratorTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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.fonts; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import junit.framework.TestCase; - -import org.apache.xmlgraphics.ps.PSGenerator; - -/** - * The test class for org.apache.fop.render.ps.fonts.PSGenerator - */ -public class PSTTFGeneratorTest extends TestCase { - private PSTTFGenerator ttfGen; - private ByteArrayOutputStream out = new ByteArrayOutputStream(); - private PSGenerator gen = new PSGenerator(out); - private byte[] byteArray; - - /** - * Constructor - */ - public PSTTFGeneratorTest() { - byteArray = new byte[65536]; - for (int i = 0; i < 65536; i++) { - byteArray[i] = (byte) i; - } - } - - @Override - public void setUp() { - ttfGen = new PSTTFGenerator(gen); - } - - /** - * Tests startString() - starts the string in an appropriate way for a PostScript file. - * @exception IOException write error - */ - public void testStartString() throws IOException { - ttfGen.startString(); - assertEquals("<\n", out.toString()); - } - - /** - * Test streamBytes() - tests that strings are written to file in the proper format. - * @throws IOException write error. - */ - public void testStreamBytes() throws IOException { - ttfGen.streamBytes(byteArray, 0, 16); - assertEquals("000102030405060708090A0B0C0D0E0F", out.toString()); - /* - * 65520 is the closes multiple of 80 to 65535 (max string size in PS document) and since - * one byte takes up two characters, 65520 / 2 - 16 (16 bytes already written)= 32744. - */ - ttfGen.streamBytes(byteArray, 0, 32744); - // Using a regex to ensure that the format is correct - assertTrue(out.toString().matches("([0-9A-F]{80}\n){819}")); - try { - ttfGen.streamBytes(byteArray, 0, PSTTFGenerator.MAX_BUFFER_SIZE + 1); - fail("Shouldn't be able to write more than MAX_BUFFER_SIZE to a PS document"); - } catch (UnsupportedOperationException e) { - // PASS - } - } - - /** - * Test reset() - reset should reset the line counter such that when reset() is invoked the - * following string streamed to the PS document should be 80 chars long. - * @throws IOException file write error. - */ - public void testReset() throws IOException { - ttfGen.streamBytes(byteArray, 0, 40); - assertTrue(out.toString().matches("([0-9A-F]{80}\n)")); - ttfGen.streamBytes(byteArray, 0, 40); - assertTrue(out.toString().matches("([0-9A-F]{80}\n){2}")); - - } - - /** - * Test endString() - ensures strings are ended in the PostScript document in the correct - * format, a "00" needs to be appended to the end of a string. - * @throws IOException file write error - */ - public void testEndString() throws IOException { - ttfGen.endString(); - assertEquals("00\n> ", out.toString()); - out.reset(); - // we need to check that this doesn't write more than 80 chars per line - ttfGen.streamBytes(byteArray, 0, 40); - ttfGen.endString(); - assertTrue(out.toString().matches("([0-9A-F]{80}\n)00\n> ")); - } -} diff --git a/test/java/org/apache/fop/render/ps/fonts/PSTTFGeneratorTestCase.java b/test/java/org/apache/fop/render/ps/fonts/PSTTFGeneratorTestCase.java new file mode 100644 index 000000000..f7f311ff8 --- /dev/null +++ b/test/java/org/apache/fop/render/ps/fonts/PSTTFGeneratorTestCase.java @@ -0,0 +1,120 @@ +/* + * 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.fonts; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.apache.xmlgraphics.ps.PSGenerator; + +/** + * The test class for org.apache.fop.render.ps.fonts.PSGenerator + */ +public class PSTTFGeneratorTestCase { + private PSTTFGenerator ttfGen; + private ByteArrayOutputStream out = new ByteArrayOutputStream(); + private PSGenerator gen = new PSGenerator(out); + private byte[] byteArray; + + /** + * Constructor + */ + public PSTTFGeneratorTestCase() { + byteArray = new byte[65536]; + for (int i = 0; i < 65536; i++) { + byteArray[i] = (byte) i; + } + } + + @Before + public void setUp() { + ttfGen = new PSTTFGenerator(gen); + } + + /** + * Tests startString() - starts the string in an appropriate way for a PostScript file. + * @exception IOException write error + */ + @Test + public void testStartString() throws IOException { + ttfGen.startString(); + assertEquals("<\n", out.toString()); + } + + /** + * Test streamBytes() - tests that strings are written to file in the proper format. + * @throws IOException write error. + */ + @Test + public void testStreamBytes() throws IOException { + ttfGen.streamBytes(byteArray, 0, 16); + assertEquals("000102030405060708090A0B0C0D0E0F", out.toString()); + /* + * 65520 is the closes multiple of 80 to 65535 (max string size in PS document) and since + * one byte takes up two characters, 65520 / 2 - 16 (16 bytes already written)= 32744. + */ + ttfGen.streamBytes(byteArray, 0, 32744); + // Using a regex to ensure that the format is correct + assertTrue(out.toString().matches("([0-9A-F]{80}\n){819}")); + try { + ttfGen.streamBytes(byteArray, 0, PSTTFGenerator.MAX_BUFFER_SIZE + 1); + fail("Shouldn't be able to write more than MAX_BUFFER_SIZE to a PS document"); + } catch (UnsupportedOperationException e) { + // PASS + } + } + + /** + * Test reset() - reset should reset the line counter such that when reset() is invoked the + * following string streamed to the PS document should be 80 chars long. + * @throws IOException file write error. + */ + @Test + public void testReset() throws IOException { + ttfGen.streamBytes(byteArray, 0, 40); + assertTrue(out.toString().matches("([0-9A-F]{80}\n)")); + ttfGen.streamBytes(byteArray, 0, 40); + assertTrue(out.toString().matches("([0-9A-F]{80}\n){2}")); + + } + + /** + * Test endString() - ensures strings are ended in the PostScript document in the correct + * format, a "00" needs to be appended to the end of a string. + * @throws IOException file write error + */ + @Test + public void testEndString() throws IOException { + ttfGen.endString(); + assertEquals("00\n> ", out.toString()); + out.reset(); + // we need to check that this doesn't write more than 80 chars per line + ttfGen.streamBytes(byteArray, 0, 40); + ttfGen.endString(); + assertTrue(out.toString().matches("([0-9A-F]{80}\n)00\n> ")); + } +} diff --git a/test/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStreamTest.java b/test/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStreamTest.java deleted file mode 100644 index 3bd93b1ba..000000000 --- a/test/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStreamTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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.fonts; - -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.io.IOException; - -import junit.framework.TestCase; - -import org.mockito.InOrder; - -/** - * Test class for PSTTFGlyphOutputStream - */ -public class PSTTFGlyphOutputStreamTest extends TestCase { - private PSTTFGenerator mockGen; - private PSTTFGlyphOutputStream glyphOut; - - @Override - public void setUp() { - mockGen = mock(PSTTFGenerator.class); - glyphOut = new PSTTFGlyphOutputStream(mockGen); - } - - /** - * Test startGlyphStream() - test that startGlyphStream() invokes reset() and startString() in - * PSTTFGenerator. - * @exception IOException file write error - */ - public void testStartGlyphStream() throws IOException { - glyphOut.startGlyphStream(); - verify(mockGen).startString(); - } - - /** - * Test streamGlyph(byte[],int,int) - tests several paths: - * 1) strings are properly appended - * 2) when total strings size > PSTTFGenerator.MAX_BUFFER_SIZE, the strings is closed and a new - * strings is started. - * 3) if a glyph of size > PSTTFGenerator.MAX_BUFFER_SIZE is attempted, an exception is thrown. - * @throws IOException file write error. - */ - public void testStreamGlyph() throws IOException { - int byteArraySize = 10; - byte[] byteArray = new byte[byteArraySize]; - int runs = 100; - for (int i = 0; i < runs; i++) { - glyphOut.streamGlyph(byteArray, 0, byteArraySize); - } - verify(mockGen, times(runs)).streamBytes(byteArray, 0, byteArraySize); - - /* - * We want to run this for MAX_BUFFER_SIZE / byteArraySize so that go over the string - * boundary and enforce the ending and starting of a new string. Using mockito to ensure - * that this behaviour is performed in order (since this is an integral behavioural aspect) - */ - int stringLimit = PSTTFGenerator.MAX_BUFFER_SIZE / byteArraySize; - for (int i = 0; i < stringLimit; i++) { - glyphOut.streamGlyph(byteArray, 0, byteArraySize); - } - InOrder inOrder = inOrder(mockGen); - inOrder.verify(mockGen, times(stringLimit)).streamBytes(byteArray, 0, byteArraySize); - inOrder.verify(mockGen).endString(); - inOrder.verify(mockGen).startString(); - inOrder.verify(mockGen, times(runs)).streamBytes(byteArray, 0, byteArraySize); - - try { - glyphOut.streamGlyph(byteArray, 0, PSTTFGenerator.MAX_BUFFER_SIZE + 1); - fail("Shouldn't allow a length > PSTTFGenerator.MAX_BUFFER_SIZE"); - } catch (UnsupportedOperationException e) { - // PASS - } - } - - /** - * Test endGlyphStream() - tests that PSTTFGenerator.endString() is invoked when this method - * is called. - * @throws IOException file write exception - */ - public void testEndGlyphStream() throws IOException { - glyphOut.endGlyphStream(); - verify(mockGen).endString(); - } -} diff --git a/test/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStreamTestCase.java b/test/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStreamTestCase.java new file mode 100644 index 000000000..82b4364c3 --- /dev/null +++ b/test/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStreamTestCase.java @@ -0,0 +1,109 @@ +/* + * 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.fonts; + +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; + +import static org.junit.Assert.fail; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +/** + * Test class for PSTTFGlyphOutputStream + */ +public class PSTTFGlyphOutputStreamTestCase { + private PSTTFGenerator mockGen; + private PSTTFGlyphOutputStream glyphOut; + + @Before + public void setUp() { + mockGen = mock(PSTTFGenerator.class); + glyphOut = new PSTTFGlyphOutputStream(mockGen); + } + + /** + * Test startGlyphStream() - test that startGlyphStream() invokes reset() and startString() in + * PSTTFGenerator. + * @exception IOException file write error + */ + @Test + public void testStartGlyphStream() throws IOException { + glyphOut.startGlyphStream(); + verify(mockGen).startString(); + } + + /** + * Test streamGlyph(byte[],int,int) - tests several paths: + * 1) strings are properly appended + * 2) when total strings size > PSTTFGenerator.MAX_BUFFER_SIZE, the strings is closed and a new + * strings is started. + * 3) if a glyph of size > PSTTFGenerator.MAX_BUFFER_SIZE is attempted, an exception is thrown. + * @throws IOException file write error. + */ + @Test + public void testStreamGlyph() throws IOException { + int byteArraySize = 10; + byte[] byteArray = new byte[byteArraySize]; + int runs = 100; + for (int i = 0; i < runs; i++) { + glyphOut.streamGlyph(byteArray, 0, byteArraySize); + } + verify(mockGen, times(runs)).streamBytes(byteArray, 0, byteArraySize); + + /* + * We want to run this for MAX_BUFFER_SIZE / byteArraySize so that go over the string + * boundary and enforce the ending and starting of a new string. Using mockito to ensure + * that this behaviour is performed in order (since this is an integral behavioural aspect) + */ + int stringLimit = PSTTFGenerator.MAX_BUFFER_SIZE / byteArraySize; + for (int i = 0; i < stringLimit; i++) { + glyphOut.streamGlyph(byteArray, 0, byteArraySize); + } + InOrder inOrder = inOrder(mockGen); + inOrder.verify(mockGen, times(stringLimit)).streamBytes(byteArray, 0, byteArraySize); + inOrder.verify(mockGen).endString(); + inOrder.verify(mockGen).startString(); + inOrder.verify(mockGen, times(runs)).streamBytes(byteArray, 0, byteArraySize); + + try { + glyphOut.streamGlyph(byteArray, 0, PSTTFGenerator.MAX_BUFFER_SIZE + 1); + fail("Shouldn't allow a length > PSTTFGenerator.MAX_BUFFER_SIZE"); + } catch (UnsupportedOperationException e) { + // PASS + } + } + + /** + * Test endGlyphStream() - tests that PSTTFGenerator.endString() is invoked when this method + * is called. + * @throws IOException file write exception + */ + @Test + public void testEndGlyphStream() throws IOException { + glyphOut.endGlyphStream(); + verify(mockGen).endString(); + } +} diff --git a/test/java/org/apache/fop/render/ps/fonts/PSTTFOutputStreamTest.java b/test/java/org/apache/fop/render/ps/fonts/PSTTFOutputStreamTest.java deleted file mode 100644 index f9b623f69..000000000 --- a/test/java/org/apache/fop/render/ps/fonts/PSTTFOutputStreamTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.fonts; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import java.io.IOException; - -import junit.framework.TestCase; - -import org.apache.fop.fonts.truetype.TTFGlyphOutputStream; -import org.apache.fop.fonts.truetype.TTFTableOutputStream; -import org.apache.xmlgraphics.ps.PSGenerator; - -/** - * Tests PSTTFOuputStream - */ -public class PSTTFOutputStreamTest extends TestCase { - private PSGenerator gen; - private PSTTFOutputStream out; - - /** - * Assigns an OutputStream to the PSGenerator. - */ - public void setUp() { - gen = mock(PSGenerator.class); - out = new PSTTFOutputStream(gen); - } - - /** - * Test startFontStream() - Just tests that the font is properly initiated in the PostScript - * document (in this case with "/sfnts[") - * @throws IOException write exception. - */ - public void testStartFontStream() throws IOException { - out.startFontStream(); - verify(gen).write("/sfnts["); - } - - /** - * Test getTableOutputStream() - we need to test that the inheritance model is properly obeyed. - */ - public void testGetTableOutputStream() { - TTFTableOutputStream tableOut = out.getTableOutputStream(); - assertTrue(tableOut instanceof PSTTFTableOutputStream); - } - - /** - * Test getGlyphOutputStream() - we need to test that the inheritance model is properly obeyed. - */ - public void testGetGlyphOutputStream() { - TTFGlyphOutputStream glyphOut = out.getGlyphOutputStream(); - assertTrue(glyphOut instanceof PSTTFGlyphOutputStream); - } - - /** - * Test endFontStream() - * @exception IOException write error. - */ - public void testEndFontStream() throws IOException { - out.endFontStream(); - verify(gen).writeln("] def"); - } -} diff --git a/test/java/org/apache/fop/render/ps/fonts/PSTTFOutputStreamTestCase.java b/test/java/org/apache/fop/render/ps/fonts/PSTTFOutputStreamTestCase.java new file mode 100644 index 000000000..744f17f64 --- /dev/null +++ b/test/java/org/apache/fop/render/ps/fonts/PSTTFOutputStreamTestCase.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.render.ps.fonts; + +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import org.apache.xmlgraphics.ps.PSGenerator; + +import org.apache.fop.fonts.truetype.TTFGlyphOutputStream; +import org.apache.fop.fonts.truetype.TTFTableOutputStream; + +/** + * Tests PSTTFOuputStream + */ +public class PSTTFOutputStreamTestCase { + private PSGenerator gen; + private PSTTFOutputStream out; + + /** + * Assigns an OutputStream to the PSGenerator. + */ + @Before + public void setUp() { + gen = mock(PSGenerator.class); + out = new PSTTFOutputStream(gen); + } + + /** + * Test startFontStream() - Just tests that the font is properly initiated in the PostScript + * document (in this case with "/sfnts[") + * @throws IOException write exception. + */ + @Test + public void testStartFontStream() throws IOException { + out.startFontStream(); + verify(gen).write("/sfnts["); + } + + /** + * Test getTableOutputStream() - we need to test that the inheritance model is properly obeyed. + */ + @Test + public void testGetTableOutputStream() { + TTFTableOutputStream tableOut = out.getTableOutputStream(); + assertTrue(tableOut instanceof PSTTFTableOutputStream); + } + + /** + * Test getGlyphOutputStream() - we need to test that the inheritance model is properly obeyed. + */ + @Test + public void testGetGlyphOutputStream() { + TTFGlyphOutputStream glyphOut = out.getGlyphOutputStream(); + assertTrue(glyphOut instanceof PSTTFGlyphOutputStream); + } + + /** + * Test endFontStream() + * @exception IOException write error. + */ + @Test + public void testEndFontStream() throws IOException { + out.endFontStream(); + verify(gen).writeln("] def"); + } +} diff --git a/test/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStreamTest.java b/test/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStreamTest.java deleted file mode 100644 index 41605ceb0..000000000 --- a/test/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStreamTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.fonts; - -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; - -import java.io.IOException; - -import junit.framework.TestCase; - -import org.mockito.InOrder; - -/** - * Test class for unit testing PSTTFTableOutputStream - */ -public class PSTTFTableOutputStreamTest extends TestCase { - private PSTTFGenerator mockGen; - private PSTTFTableOutputStream tableOut; - - @Override - public void setUp() { - mockGen = mock(PSTTFGenerator.class); - tableOut = new PSTTFTableOutputStream(mockGen); - } - - /** - * Test streamTable() - several paths to test (2. and 3. test corner cases): - * 1) that a table of length < PSTTFGenerator.MAX_BUFFER_SIZE invokes the correct methods in - * PSTTFGenerator. - * 2) that a table of length > PSTTFGenerator.MAX_BUFFER_SIZE and - * length == n * PSTTFGenerator.MAX_BUFFER_SIZE is split up and the methods in PSTTFGenerator - * are invoked. - * 3) that a table of length > PSTTFGenerator.MAX_BUFFER_SIZE but - * length != n * PSTTFGenerator.MAX_BUFFER_SIZE is split up and the methods in PSTTFGenerator - * are invoked. - * @throws IOException file write error. - */ - public void testStreamTable() throws IOException { - byte[] byteArray = new byte[PSTTFGenerator.MAX_BUFFER_SIZE * 3]; - tableOut.streamTable(byteArray, 0, 10); - InOrder inOrder = inOrder(mockGen); - inOrder.verify(mockGen).startString(); - inOrder.verify(mockGen).streamBytes(byteArray, 0, 10); - inOrder.verify(mockGen).endString(); - - setUp(); // reset all all the method calls - /* We're going to run this 3 times to ensure the proper method calls are invoked and all - * the bytes are streamed */ - tableOut.streamTable(byteArray, 0, byteArray.length); - inOrder = inOrder(mockGen); - for (int i = 0; i < 3; i++) { - int offset = PSTTFGenerator.MAX_BUFFER_SIZE * i; - inOrder.verify(mockGen).startString(); - inOrder.verify(mockGen).streamBytes(byteArray, offset, PSTTFGenerator.MAX_BUFFER_SIZE); - inOrder.verify(mockGen).endString(); - } - - setUp(); // reset all the method calls - tableOut.streamTable(byteArray, 0, PSTTFGenerator.MAX_BUFFER_SIZE + 1); - inOrder = inOrder(mockGen); - inOrder.verify(mockGen).startString(); - inOrder.verify(mockGen).streamBytes(byteArray, 0, PSTTFGenerator.MAX_BUFFER_SIZE); - inOrder.verify(mockGen).endString(); - inOrder.verify(mockGen).startString(); - inOrder.verify(mockGen).streamBytes(byteArray, PSTTFGenerator.MAX_BUFFER_SIZE, 1); - inOrder.verify(mockGen).endString(); - } -} diff --git a/test/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStreamTestCase.java b/test/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStreamTestCase.java new file mode 100644 index 000000000..c20c3d8b1 --- /dev/null +++ b/test/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStreamTestCase.java @@ -0,0 +1,87 @@ +/* + * 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.fonts; + +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; + +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; + +/** + * Test class for unit testing PSTTFTableOutputStream + */ +public class PSTTFTableOutputStreamTestCase { + private PSTTFGenerator mockGen; + private PSTTFTableOutputStream tableOut; + + @Before + public void setUp() { + mockGen = mock(PSTTFGenerator.class); + tableOut = new PSTTFTableOutputStream(mockGen); + } + + /** + * Test streamTable() - several paths to test (2. and 3. test corner cases): + * 1) that a table of length < PSTTFGenerator.MAX_BUFFER_SIZE invokes the correct methods in + * PSTTFGenerator. + * 2) that a table of length > PSTTFGenerator.MAX_BUFFER_SIZE and + * length == n * PSTTFGenerator.MAX_BUFFER_SIZE is split up and the methods in PSTTFGenerator + * are invoked. + * 3) that a table of length > PSTTFGenerator.MAX_BUFFER_SIZE but + * length != n * PSTTFGenerator.MAX_BUFFER_SIZE is split up and the methods in PSTTFGenerator + * are invoked. + * @throws IOException file write error. + */ + @Test + public void testStreamTable() throws IOException { + byte[] byteArray = new byte[PSTTFGenerator.MAX_BUFFER_SIZE * 3]; + tableOut.streamTable(byteArray, 0, 10); + InOrder inOrder = inOrder(mockGen); + inOrder.verify(mockGen).startString(); + inOrder.verify(mockGen).streamBytes(byteArray, 0, 10); + inOrder.verify(mockGen).endString(); + + setUp(); // reset all all the method calls + /* We're going to run this 3 times to ensure the proper method calls are invoked and all + * the bytes are streamed */ + tableOut.streamTable(byteArray, 0, byteArray.length); + inOrder = inOrder(mockGen); + for (int i = 0; i < 3; i++) { + int offset = PSTTFGenerator.MAX_BUFFER_SIZE * i; + inOrder.verify(mockGen).startString(); + inOrder.verify(mockGen).streamBytes(byteArray, offset, PSTTFGenerator.MAX_BUFFER_SIZE); + inOrder.verify(mockGen).endString(); + } + + setUp(); // reset all the method calls + tableOut.streamTable(byteArray, 0, PSTTFGenerator.MAX_BUFFER_SIZE + 1); + inOrder = inOrder(mockGen); + inOrder.verify(mockGen).startString(); + inOrder.verify(mockGen).streamBytes(byteArray, 0, PSTTFGenerator.MAX_BUFFER_SIZE); + inOrder.verify(mockGen).endString(); + inOrder.verify(mockGen).startString(); + inOrder.verify(mockGen).streamBytes(byteArray, PSTTFGenerator.MAX_BUFFER_SIZE, 1); + inOrder.verify(mockGen).endString(); + } +} diff --git a/test/java/org/apache/fop/util/HexEncoderTestCase.java b/test/java/org/apache/fop/util/HexEncoderTestCase.java index e6198e0ad..cb366abdf 100644 --- a/test/java/org/apache/fop/util/HexEncoderTestCase.java +++ b/test/java/org/apache/fop/util/HexEncoderTestCase.java @@ -19,20 +19,24 @@ package org.apache.fop.util; -import junit.framework.TestCase; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; /** * Test case for the conversion of characters into hex-encoded strings. */ -public class HexEncoderTestCase extends TestCase { +public class HexEncoderTestCase { - private static char successor(char d) { - if (d == '9') { - return 'A'; - } else if (d == 'F') { - return '0'; - } else { - return (char) (d + 1); + /** + * Tests that characters are properly encoded into hex strings. + */ + @Test + 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); } } @@ -44,14 +48,13 @@ public class HexEncoderTestCase extends TestCase { } 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); + private static char successor(char d) { + if (d == '9') { + return 'A'; + } else if (d == 'F') { + return '0'; + } else { + return (char) (d + 1); } } diff --git a/test/resources/fonts/DroidSansMono.LICENSE b/test/resources/fonts/DroidSansMono.LICENSE deleted file mode 100644 index 1a96dfde6..000000000 --- a/test/resources/fonts/DroidSansMono.LICENSE +++ /dev/null @@ -1,18 +0,0 @@ -Copyright (C) 2008 The Android Open Source Project - -Licensed 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. - -########## - -This directory contains the fonts for the platform. They are licensed -under the Apache 2 license. diff --git a/test/resources/fonts/ttf/DroidSansMono.LICENSE b/test/resources/fonts/ttf/DroidSansMono.LICENSE new file mode 100644 index 000000000..1a96dfde6 --- /dev/null +++ b/test/resources/fonts/ttf/DroidSansMono.LICENSE @@ -0,0 +1,18 @@ +Copyright (C) 2008 The Android Open Source Project + +Licensed 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. + +########## + +This directory contains the fonts for the platform. They are licensed +under the Apache 2 license. diff --git a/test/resources/fonts/ttf/DroidSansMono.ttf b/test/resources/fonts/ttf/DroidSansMono.ttf new file mode 100644 index 000000000..4546611d4 Binary files /dev/null and b/test/resources/fonts/ttf/DroidSansMono.ttf differ -- cgit v1.2.3 From 2717d9ecafe3e69071f5a90478bb8924d0dbc468 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Tue, 29 May 2012 15:32:11 +0000 Subject: Removed unused methods git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1343776 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/fonts/truetype/TTFSubSetFile.java | 29 ---------------------- 1 file changed, 29 deletions(-) diff --git a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java index e217ec1b6..094716a66 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java @@ -753,32 +753,6 @@ public class TTFSubSetFile extends TTFFile { output[pos + 3] = b4; } - /** - * Read a signed short value at given position - */ - private short readShort(int pos) { - int ret = readUShort(pos); - return (short)ret; - } - - /** - * Read a unsigned short value at given position - */ - private int readUShort(int pos) { - int ret = output[pos]; - if (ret < 0) { - ret += 256; - } - ret = ret << 8; - if (output[pos + 1] < 0) { - ret |= output[pos + 1] + 256; - } else { - ret |= output[pos + 1]; - } - - return ret; - } - /** * Create a padding in the fontfile to align * on a 4-byte boundary @@ -805,9 +779,6 @@ public class TTFSubSetFile extends TTFFile { return (i - 1); } - private int log2(int num) { - return (int)(Math.log(num) / Math.log(2)); - } private void updateCheckSum(int tableStart, int tableSize, TTFTableName tableName) { int checksum = getCheckSum(output, tableStart, tableSize); -- cgit v1.2.3 From 1f82c47f3ce060d638211c1fbde79438f10304b1 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Tue, 29 May 2012 15:33:09 +0000 Subject: Made glyphToUnicodeMap and unicodeToGlyphMap final git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1343777 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/truetype/TTFFile.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java index f80226e26..168b49482 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java @@ -215,8 +215,8 @@ public class TTFFile { // internal mapping of glyph indexes to unicode indexes // used for quick mappings in this class - private Map glyphToUnicodeMap = new HashMap (); - private Map unicodeToGlyphMap = new HashMap (); + private final Map glyphToUnicodeMap = new HashMap (); + private final Map unicodeToGlyphMap = new HashMap (); private TTFDirTabEntry currentDirTab; -- cgit v1.2.3 From 9107ba1eee67d9ec10dad051d43beaff77b13a77 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Tue, 29 May 2012 15:33:54 +0000 Subject: setBFEntries is deprecated, replaced with setCMap git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1343780 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/FontReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/org/apache/fop/fonts/FontReader.java b/src/java/org/apache/fop/fonts/FontReader.java index a1766e46f..381eec7f4 100644 --- a/src/java/org/apache/fop/fonts/FontReader.java +++ b/src/java/org/apache/fop/fonts/FontReader.java @@ -307,7 +307,7 @@ public class FontReader extends DefaultHandler { multiFont.setWidthArray(wds); } else if ("bfranges".equals(localName)) { - multiFont.setBFEntries(bfranges.toArray(new BFEntry[0])); + multiFont.setCMap(bfranges.toArray(new BFEntry[0])); } text.setLength(0); //Reset text buffer (see characters()) } -- cgit v1.2.3 From 28397e02f096c91109b9d5f71a69e01becef5a60 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 30 May 2012 10:23:32 +0000 Subject: Organized imports git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1344184 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/fop/tools/EventProducerCollectorTask.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java b/src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java index 6505d4f09..38867d87a 100644 --- a/src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java +++ b/src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java @@ -37,16 +37,18 @@ import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import org.w3c.dom.Node; + import org.apache.commons.io.IOUtils; -import org.apache.fop.events.model.EventModel; -import org.apache.fop.events.model.EventProducerModel; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.selectors.FilenameSelector; -import org.w3c.dom.Node; + +import org.apache.fop.events.model.EventModel; +import org.apache.fop.events.model.EventProducerModel; /** * Ant task which inspects a file set for Java interfaces which extend the -- cgit v1.2.3 From a5c4a9c5d50b8766015e74046be3baeb34916205 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 30 May 2012 13:32:35 +0000 Subject: Renamed BFEntry into CMapSegment git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1344251 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/BFEntry.java | 111 --------------------- src/java/org/apache/fop/fonts/CMapSegment.java | 106 ++++++++++++++++++++ src/java/org/apache/fop/fonts/CustomFont.java | 10 +- src/java/org/apache/fop/fonts/FontReader.java | 8 +- src/java/org/apache/fop/fonts/MultiByteFont.java | 26 ++--- src/java/org/apache/fop/fonts/apps/TTFReader.java | 4 +- .../org/apache/fop/fonts/truetype/TTFFile.java | 17 ++-- .../apache/fop/fonts/truetype/TTFFontLoader.java | 14 +-- src/java/org/apache/fop/render/ps/PSFontUtils.java | 28 +++--- 9 files changed, 160 insertions(+), 164 deletions(-) delete mode 100644 src/java/org/apache/fop/fonts/BFEntry.java create mode 100644 src/java/org/apache/fop/fonts/CMapSegment.java diff --git a/src/java/org/apache/fop/fonts/BFEntry.java b/src/java/org/apache/fop/fonts/BFEntry.java deleted file mode 100644 index 0841f36c8..000000000 --- a/src/java/org/apache/fop/fonts/BFEntry.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -/** - * This is just a holder class for bfentries, groups of characters of a base font (bf). - */ -public final class BFEntry { - - //TODO Think about renaming this class to CMapRange or something. - - private final int unicodeStart; - private final int unicodeEnd; - private final int glyphStartIndex; - - /** - * Main constructor. - * @param unicodeStart Unicode start index - * @param unicodeEnd Unicode end index - * @param glyphStartIndex glyph start index - */ - public BFEntry(int unicodeStart, int unicodeEnd, int glyphStartIndex) { - this.unicodeStart = unicodeStart; - this.unicodeEnd = unicodeEnd; - this.glyphStartIndex = glyphStartIndex; - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - int hc = 17; - hc = 31 * hc + unicodeStart; - hc = 31 * hc + unicodeEnd; - hc = 31 * hc + glyphStartIndex; - return hc; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object o) { - if (o instanceof BFEntry) { - BFEntry ce = (BFEntry) o; - return ce.unicodeStart == this.unicodeStart - && ce.unicodeEnd == this.unicodeEnd - && ce.glyphStartIndex == this.glyphStartIndex; - } - return false; - } - - /** - * Returns the unicodeStart. - * @return the Unicode start index - */ - public int getUnicodeStart() { - return unicodeStart; - } - - /** - * Returns the unicodeEnd. - * @return the Unicode end index - */ - public int getUnicodeEnd() { - return unicodeEnd; - } - - /** - * Returns the glyphStartIndex. - * @return the glyph start index - */ - public int getGlyphStartIndex() { - return glyphStartIndex; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuilder sb = new StringBuilder("BFEntry: "); - sb.append ( "{ UC[" ); - sb.append ( unicodeStart ); - sb.append ( ',' ); - sb.append ( unicodeEnd ); - sb.append ( "]: GC[" ); - sb.append ( glyphStartIndex ); - sb.append ( ',' ); - sb.append ( glyphStartIndex + ( unicodeEnd - unicodeStart ) ); - sb.append ( "] }" ); - return sb.toString(); - } - -} diff --git a/src/java/org/apache/fop/fonts/CMapSegment.java b/src/java/org/apache/fop/fonts/CMapSegment.java new file mode 100644 index 000000000..816df2ca0 --- /dev/null +++ b/src/java/org/apache/fop/fonts/CMapSegment.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fonts; + +/** + * A segment in a cmap table of format 4. Unicode code points between + * {@link #getUnicodeStart()} and {@link #getUnicodeEnd()} map to contiguous glyph indices + * starting from {@link #getGlyphStartIndex()}. + */ +public final class CMapSegment { + + private final int unicodeStart; + private final int unicodeEnd; + private final int glyphStartIndex; + + /** + * Creates a new segment. + * + * @param unicodeStart Unicode start index + * @param unicodeEnd Unicode end index + * @param glyphStartIndex glyph start index + */ + public CMapSegment(int unicodeStart, int unicodeEnd, int glyphStartIndex) { + this.unicodeStart = unicodeStart; + this.unicodeEnd = unicodeEnd; + this.glyphStartIndex = glyphStartIndex; + } + + @Override + public int hashCode() { + int hc = 17; + hc = 31 * hc + unicodeStart; + hc = 31 * hc + unicodeEnd; + hc = 31 * hc + glyphStartIndex; + return hc; + } + + @Override + public boolean equals(Object o) { + if (o instanceof CMapSegment) { + CMapSegment ce = (CMapSegment) o; + return ce.unicodeStart == this.unicodeStart + && ce.unicodeEnd == this.unicodeEnd + && ce.glyphStartIndex == this.glyphStartIndex; + } + return false; + } + + /** + * Returns the unicodeStart. + * @return the Unicode start index + */ + public int getUnicodeStart() { + return unicodeStart; + } + + /** + * Returns the unicodeEnd. + * @return the Unicode end index + */ + public int getUnicodeEnd() { + return unicodeEnd; + } + + /** + * Returns the glyphStartIndex. + * @return the glyph start index + */ + public int getGlyphStartIndex() { + return glyphStartIndex; + } + + /** {@inheritDoc} */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder("CMapSegment: "); + sb.append ( "{ UC[" ); + sb.append ( unicodeStart ); + sb.append ( ',' ); + sb.append ( unicodeEnd ); + sb.append ( "]: GC[" ); + sb.append ( glyphStartIndex ); + sb.append ( ',' ); + sb.append ( glyphStartIndex + ( unicodeEnd - unicodeStart ) ); + sb.append ( "] }" ); + return sb.toString(); + } + +} diff --git a/src/java/org/apache/fop/fonts/CustomFont.java b/src/java/org/apache/fop/fonts/CustomFont.java index 7386b7341..b506393a6 100644 --- a/src/java/org/apache/fop/fonts/CustomFont.java +++ b/src/java/org/apache/fop/fonts/CustomFont.java @@ -64,7 +64,7 @@ public abstract class CustomFont extends Typeface private boolean useAdvanced = true; /** the character map, mapping Unicode ranges to glyph indices. */ - protected BFEntry[] cmap; + protected CMapSegment[] cmap; /** {@inheritDoc} */ public String getFontName() { @@ -497,8 +497,8 @@ public abstract class CustomFont extends Typeface * to their glyph indices inside the font. * @param cmap the identity character map */ - public void setCMap(BFEntry[] cmap) { - this.cmap = new BFEntry[cmap.length]; + public void setCMap(CMapSegment[] cmap) { + this.cmap = new CMapSegment[cmap.length]; System.arraycopy(cmap, 0, this.cmap, 0, cmap.length); } @@ -507,8 +507,8 @@ public abstract class CustomFont extends Typeface * to their glyph indices inside the font. * @return the identity character map */ - public BFEntry[] getCMap() { - BFEntry[] copy = new BFEntry[cmap.length]; + public CMapSegment[] getCMap() { + CMapSegment[] copy = new CMapSegment[cmap.length]; System.arraycopy(this.cmap, 0, copy, 0, this.cmap.length); return copy; } diff --git a/src/java/org/apache/fop/fonts/FontReader.java b/src/java/org/apache/fop/fonts/FontReader.java index 381eec7f4..46ea9123d 100644 --- a/src/java/org/apache/fop/fonts/FontReader.java +++ b/src/java/org/apache/fop/fonts/FontReader.java @@ -64,7 +64,7 @@ public class FontReader extends DefaultHandler { private Map currentKerning = null; - private List bfranges = null; + private List bfranges = null; private void createFont(InputSource source) throws FOPException { XMLReader parser = null; @@ -201,9 +201,9 @@ public class FontReader extends DefaultHandler { returnFont.putKerningEntry(new Integer(attributes.getValue("kpx1")), currentKerning); } else if ("bfranges".equals(localName)) { - bfranges = new ArrayList(); + bfranges = new ArrayList(); } else if ("bf".equals(localName)) { - BFEntry entry = new BFEntry(getInt(attributes.getValue("us")), + CMapSegment entry = new CMapSegment(getInt(attributes.getValue("us")), getInt(attributes.getValue("ue")), getInt(attributes.getValue("gi"))); bfranges.add(entry); @@ -307,7 +307,7 @@ public class FontReader extends DefaultHandler { multiFont.setWidthArray(wds); } else if ("bfranges".equals(localName)) { - multiFont.setCMap(bfranges.toArray(new BFEntry[0])); + multiFont.setCMap(bfranges.toArray(new CMapSegment[0])); } text.setLength(0); //Reset text buffer (see characters()) } diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java index c249c4d19..4db5ece84 100644 --- a/src/java/org/apache/fop/fonts/MultiByteFont.java +++ b/src/java/org/apache/fop/fonts/MultiByteFont.java @@ -183,17 +183,17 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl } /** - * Add a private use mapping {PU,GI} to the existing BFENTRIES map. + * Add a private use mapping {PU,GI} to the existing character map. * N.B. Does not insert in order, merely appends to end of existing map. */ private synchronized void addPrivateUseMapping ( int pu, int gi ) { assert findGlyphIndex ( pu ) == SingleByteEncoding.NOT_FOUND_CODE_POINT; - BFEntry[] bfeOld = cmap; - int bfeCnt = bfeOld.length; - BFEntry[] bfeNew = new BFEntry [ bfeCnt + 1 ]; - System.arraycopy ( bfeOld, 0, bfeNew, 0, bfeCnt ); - bfeNew [ bfeCnt ] = new BFEntry ( pu, pu, gi ); - cmap = bfeNew; + CMapSegment[] oldCmap = cmap; + int cmapLength = oldCmap.length; + CMapSegment[] newCmap = new CMapSegment [ cmapLength + 1 ]; + System.arraycopy ( oldCmap, 0, newCmap, 0, cmapLength ); + newCmap [ cmapLength ] = new CMapSegment ( pu, pu, gi ); + cmap = newCmap; } /** @@ -252,11 +252,11 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl private int findCharacterFromGlyphIndex ( int gi, boolean augment ) { int cc = 0; for ( int i = 0, n = cmap.length; i < n; i++ ) { - BFEntry be = cmap [ i ]; - int s = be.getGlyphStartIndex(); - int e = s + ( be.getUnicodeEnd() - be.getUnicodeStart() ); + CMapSegment segment = cmap [ i ]; + int s = segment.getGlyphStartIndex(); + int e = s + ( segment.getUnicodeEnd() - segment.getUnicodeStart() ); if ( ( gi >= s ) && ( gi <= e ) ) { - cc = be.getUnicodeStart() + ( gi - s ); + cc = segment.getUnicodeStart() + ( gi - s ); break; } } @@ -296,10 +296,10 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl * Sets the array of BFEntry instances which constitutes the Unicode to glyph index map for * a font. ("BF" means "base font") * @param entries the Unicode to glyph index map - * @deprecated use {@link #setCMap(BFEntry[])} instead + * @deprecated use {@link #setCMap(CMapSegment[])} instead */ @Deprecated - public void setBFEntries(BFEntry[] entries) { + public void setBFEntries(CMapSegment[] entries) { setCMap(entries); } diff --git a/src/java/org/apache/fop/fonts/apps/TTFReader.java b/src/java/org/apache/fop/fonts/apps/TTFReader.java index 59a5c47bb..224c8de2f 100644 --- a/src/java/org/apache/fop/fonts/apps/TTFReader.java +++ b/src/java/org/apache/fop/fonts/apps/TTFReader.java @@ -33,7 +33,7 @@ import org.xml.sax.SAXException; import org.apache.commons.logging.LogFactory; import org.apache.fop.Version; -import org.apache.fop.fonts.BFEntry; +import org.apache.fop.fonts.CMapSegment; import org.apache.fop.fonts.FontUtil; import org.apache.fop.fonts.truetype.FontFileReader; import org.apache.fop.fonts.truetype.TTFFile; @@ -385,7 +385,7 @@ public class TTFReader extends AbstractFontReader { el = doc.createElement("bfranges"); mel.appendChild(el); - for (BFEntry ce : ttf.getCMaps()) { + for (CMapSegment ce : ttf.getCMaps()) { Element el2 = doc.createElement("bf"); el.appendChild(el2); el2.setAttribute("us", String.valueOf(ce.getUnicodeStart())); diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java index 168b49482..77cdddcdd 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java @@ -43,7 +43,7 @@ import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable; import org.apache.fop.complexscripts.fonts.GlyphPositioningTable; import org.apache.fop.complexscripts.fonts.GlyphSubstitutionTable; import org.apache.fop.complexscripts.fonts.OTFAdvancedTypographicTableReader; -import org.apache.fop.fonts.BFEntry; +import org.apache.fop.fonts.CMapSegment; import org.apache.fop.fonts.FontUtil; /** @@ -161,7 +161,7 @@ public class TTFFile { protected Map dirTabs; private Map> kerningTab; // for CIDs private Map> ansiKerningTab; // For winAnsiEncoding - private List cmaps; + private List cmaps; private Set unicodeMappings; private int upem; // unitsPerEm from "head" table @@ -764,7 +764,7 @@ public class TTFFile { } private void createCMaps() { - cmaps = new ArrayList(); + cmaps = new ArrayList(); int unicodeStart; int glyphStart; int unicodeEnd; @@ -781,7 +781,7 @@ public class TTFFile { if (((lastMapping.getUnicodeIndex() + 1) != um.getUnicodeIndex()) || ((lastMapping.getGlyphIndex() + 1) != um.getGlyphIndex())) { unicodeEnd = lastMapping.getUnicodeIndex(); - cmaps.add(new BFEntry(unicodeStart, unicodeEnd, glyphStart)); + cmaps.add(new CMapSegment(unicodeStart, unicodeEnd, glyphStart)); unicodeStart = um.getUnicodeIndex(); glyphStart = um.getGlyphIndex(); } @@ -789,7 +789,7 @@ public class TTFFile { } unicodeEnd = lastMapping.getUnicodeIndex(); - cmaps.add(new BFEntry(unicodeStart, unicodeEnd, glyphStart)); + cmaps.add(new CMapSegment(unicodeStart, unicodeEnd, glyphStart)); } /** @@ -1758,10 +1758,11 @@ public class TTFFile { } /** - * Return a List with TTFCmapEntry. - * @return A list of TTFCmapEntry objects + * Returns this font's character to glyph mapping. + * + * @return the font's cmap */ - public List getCMaps() { + public List getCMaps() { return cmaps; } diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index 9a19f287b..9c6098de2 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -26,7 +26,7 @@ import java.util.Set; import org.apache.commons.io.IOUtils; -import org.apache.fop.fonts.BFEntry; +import org.apache.fop.fonts.CMapSegment; import org.apache.fop.fonts.CIDFontType; import org.apache.fop.fonts.EmbeddingMode; import org.apache.fop.fonts.EncodingMode; @@ -181,8 +181,8 @@ public class TTFFontLoader extends FontLoader { } } - private BFEntry[] getCMap(TTFFile ttf) { - BFEntry[] array = new BFEntry[ttf.getCMaps().size()]; + private CMapSegment[] getCMap(TTFFile ttf) { + CMapSegment[] array = new CMapSegment[ttf.getCMaps().size()]; return ttf.getCMaps().toArray(array); } @@ -192,12 +192,12 @@ public class TTFFontLoader extends FontLoader { singleFont.setWidth(i, ttf.getCharWidth(i)); } - for (BFEntry ce : ttf.getCMaps()) { - if (ce.getUnicodeStart() < 0xFFFE) { - for (char u = (char)ce.getUnicodeStart(); u <= ce.getUnicodeEnd(); u++) { + for (CMapSegment segment : ttf.getCMaps()) { + if (segment.getUnicodeStart() < 0xFFFE) { + for (char u = (char)segment.getUnicodeStart(); u <= segment.getUnicodeEnd(); u++) { int codePoint = singleFont.getEncoding().mapChar(u); if (codePoint <= 0) { - int glyphIndex = ce.getGlyphStartIndex() + u - ce.getUnicodeStart(); + int glyphIndex = segment.getGlyphStartIndex() + u - segment.getUnicodeStart(); String glyphName = ttf.getGlyphName(glyphIndex); if (glyphName == "" && ttf.getPostScriptVersion() != PostScriptVersion.V2) { glyphName = "u" + HexEncoder.encode(u); diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index 157f4f419..53ceff53e 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -40,7 +40,7 @@ import org.apache.xmlgraphics.ps.PSGenerator; import org.apache.xmlgraphics.ps.PSResource; import org.apache.xmlgraphics.ps.dsc.ResourceTracker; -import org.apache.fop.fonts.BFEntry; +import org.apache.fop.fonts.CMapSegment; import org.apache.fop.fonts.Base14Font; import org.apache.fop.fonts.CIDFontType; import org.apache.fop.fonts.CIDSubset; @@ -314,7 +314,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } private static void createType42DictionaryEntries(PSGenerator gen, CustomFont font, - BFEntry[] cmap, TTFFile ttfFile) throws IOException { + CMapSegment[] cmap, TTFFile ttfFile) throws IOException { gen.write("/FontName /"); gen.write(font.getEmbedFontName()); gen.writeln(" def"); @@ -354,14 +354,14 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } private static void buildCharStrings(PSGenerator gen, boolean buildCharStrings, - BFEntry[] cmap, Set glyphNames, CustomFont font) throws IOException { + CMapSegment[] cmap, Set glyphNames, CustomFont font) throws IOException { gen.write("/CharStrings "); if (!buildCharStrings) { gen.write(1); } else if (font.getEmbeddingMode() != EmbeddingMode.FULL) { int charCount = 1; //1 for .notdef - for (BFEntry entry : cmap) { - charCount += entry.getUnicodeEnd() - entry.getUnicodeStart() + 1; + for (CMapSegment segment : cmap) { + charCount += segment.getUnicodeEnd() - segment.getUnicodeStart() + 1; } gen.write(charCount); } else { @@ -378,9 +378,9 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } if (font.getEmbeddingMode() != EmbeddingMode.FULL) { //Only performed in singly-byte mode, ignored for CID fonts - for (BFEntry entry : cmap) { - int glyphIndex = entry.getGlyphStartIndex(); - for (int ch = entry.getUnicodeStart(); ch <= entry.getUnicodeEnd(); ch++) { + for (CMapSegment segment : cmap) { + int glyphIndex = segment.getGlyphStartIndex(); + for (int ch = segment.getUnicodeStart(); ch <= segment.getUnicodeEnd(); ch++) { char ch16 = (char)ch; //TODO Handle Unicode characters beyond 16bit String glyphName = Glyphs.charToGlyphName(ch16); if ("".equals(glyphName)) { @@ -410,10 +410,10 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { gen.writeln(" def"); } - private static int getGlyphIndex(char c, BFEntry[] cmap) { - for (BFEntry entry : cmap) { - if (entry.getUnicodeStart() <= c && c <= entry.getUnicodeEnd()) { - return entry.getGlyphStartIndex() + c - entry.getUnicodeStart(); + private static int getGlyphIndex(char c, CMapSegment[] cmap) { + for (CMapSegment segment : cmap) { + if (segment.getUnicodeStart() <= c && c <= segment.getUnicodeEnd()) { + return segment.getGlyphStartIndex() + c - segment.getUnicodeStart(); } } return 0; @@ -509,7 +509,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } - createType42DictionaryEntries(gen, font, new BFEntry[0], ttfFile); + createType42DictionaryEntries(gen, font, new CMapSegment[0], ttfFile); gen.writeln("CIDFontName currentdict end /CIDFont defineresource pop"); gen.writeln("end"); gen.writeln("%%EndResource"); @@ -685,7 +685,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { private static PSResource defineDerivedTrueTypeFont(PSGenerator gen, PSEventProducer eventProducer, String baseFontName, String fontName, - SingleByteEncoding encoding, BFEntry[] cmap) throws IOException { + SingleByteEncoding encoding, CMapSegment[] cmap) throws IOException { checkPostScriptLevel3(gen, eventProducer); PSResource res = new PSResource(PSResource.TYPE_FONT, fontName); gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, res); -- cgit v1.2.3 From f9544fb7a61934ef65ef623c71550be13a199c95 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 30 May 2012 13:35:59 +0000 Subject: Removed deprecated method git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1344254 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/MultiByteFont.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java index 4db5ece84..54b772b2e 100644 --- a/src/java/org/apache/fop/fonts/MultiByteFont.java +++ b/src/java/org/apache/fop/fonts/MultiByteFont.java @@ -292,17 +292,6 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl return (findGlyphIndex(c) != SingleByteEncoding.NOT_FOUND_CODE_POINT); } - /** - * Sets the array of BFEntry instances which constitutes the Unicode to glyph index map for - * a font. ("BF" means "base font") - * @param entries the Unicode to glyph index map - * @deprecated use {@link #setCMap(CMapSegment[])} instead - */ - @Deprecated - public void setBFEntries(CMapSegment[] entries) { - setCMap(entries); - } - /** * Sets the defaultWidth. * @param defaultWidth The defaultWidth to set -- cgit v1.2.3 From 992889d0a8c427bf6ff2fa313699f13bd9f31094 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 30 May 2012 15:28:14 +0000 Subject: Javadoc improvements git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1344309 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/CustomFont.java | 8 +-- src/java/org/apache/fop/fonts/EmbedFontInfo.java | 2 +- src/java/org/apache/fop/fonts/EmbeddingMode.java | 12 ++-- src/java/org/apache/fop/fonts/FontType.java | 2 +- src/java/org/apache/fop/fonts/MutableFont.java | 4 +- .../org/apache/fop/fonts/truetype/TTFFile.java | 9 +-- .../fop/fonts/truetype/TTFGlyphOutputStream.java | 18 +++--- .../apache/fop/fonts/truetype/TTFOutputStream.java | 16 +++-- .../apache/fop/fonts/truetype/TTFSubSetFile.java | 12 +--- .../apache/fop/fonts/truetype/TTFTableName.java | 68 +++++++++++----------- .../fop/fonts/truetype/TTFTableOutputStream.java | 14 ++--- .../render/ps/fonts/PSTTFGlyphOutputStream.java | 27 +++++---- .../render/ps/fonts/PSTTFTableOutputStream.java | 13 +++-- 13 files changed, 99 insertions(+), 106 deletions(-) diff --git a/src/java/org/apache/fop/fonts/CustomFont.java b/src/java/org/apache/fop/fonts/CustomFont.java index b506393a6..89f515205 100644 --- a/src/java/org/apache/fop/fonts/CustomFont.java +++ b/src/java/org/apache/fop/fonts/CustomFont.java @@ -493,9 +493,9 @@ public abstract class CustomFont extends Typeface } /** - * Sets the identity character map for this font. It maps all available Unicode characters + * Sets the character map for this font. It maps all available Unicode characters * to their glyph indices inside the font. - * @param cmap the identity character map + * @param cmap the character map */ public void setCMap(CMapSegment[] cmap) { this.cmap = new CMapSegment[cmap.length]; @@ -503,9 +503,9 @@ public abstract class CustomFont extends Typeface } /** - * Returns the identity character map for this font. It maps all available Unicode characters + * Returns the character map for this font. It maps all available Unicode characters * to their glyph indices inside the font. - * @return the identity character map + * @return the character map */ public CMapSegment[] getCMap() { CMapSegment[] copy = new CMapSegment[cmap.length]; diff --git a/src/java/org/apache/fop/fonts/EmbedFontInfo.java b/src/java/org/apache/fop/fonts/EmbedFontInfo.java index 4287e6938..64bd200be 100644 --- a/src/java/org/apache/fop/fonts/EmbedFontInfo.java +++ b/src/java/org/apache/fop/fonts/EmbedFontInfo.java @@ -188,7 +188,7 @@ public class EmbedFontInfo implements Serializable { } /** - * Sets the embedding mode for this font, currently not supported for type1 fonts. + * Sets the embedding mode for this font, currently not supported for Type 1 fonts. * @param embeddingMode the new embedding mode. */ public void setEmbeddingMode(EmbeddingMode embeddingMode) { diff --git a/src/java/org/apache/fop/fonts/EmbeddingMode.java b/src/java/org/apache/fop/fonts/EmbeddingMode.java index 89f56cfd7..d75c7a3d4 100644 --- a/src/java/org/apache/fop/fonts/EmbeddingMode.java +++ b/src/java/org/apache/fop/fonts/EmbeddingMode.java @@ -21,10 +21,10 @@ package org.apache.fop.fonts; /** * This enumerates the embedding mode of fonts; full; subset; auto (auto defaults to full for - * type1 fonts and subset for truetype fonts. + * Type 1 fonts and subset for TrueType fonts. */ public enum EmbeddingMode { - /** Default option: assumes FULL for type1 fonts and SUBSET for truetype fonts. */ + /** Default option: assumes FULL for Type 1 fonts and SUBSET for TrueType fonts. */ AUTO, /** Full font embedding: This means the whole of the font is written to file. */ FULL, @@ -34,16 +34,16 @@ public enum EmbeddingMode { /** * Returns the name of this embedding mode. - * @return String - lower case. + * @return the name of this embedding mode in lower case. */ public String getName() { return this.toString().toLowerCase(); } /** - * Returns {@link EmbeddingMode} by name. - * @param value String - the name of the embedding mode (not case sensitive). - * @return embedding mode constant. + * Returns the embedding mode corresponding to the given name. + * @param value the name of an embedding mode (not case sensitive) + * @return the corresponding embedding mode */ public static EmbeddingMode getValue(String value) { for (EmbeddingMode mode : EmbeddingMode.values()) { diff --git a/src/java/org/apache/fop/fonts/FontType.java b/src/java/org/apache/fop/fonts/FontType.java index 06bbf1bc1..edd8d0c37 100644 --- a/src/java/org/apache/fop/fonts/FontType.java +++ b/src/java/org/apache/fop/fonts/FontType.java @@ -130,7 +130,7 @@ public class FontType { return value; } - /** {@inheritDoc} */ + @Override public String toString() { return name; } diff --git a/src/java/org/apache/fop/fonts/MutableFont.java b/src/java/org/apache/fop/fonts/MutableFont.java index adbf3b250..3ebc3c465 100644 --- a/src/java/org/apache/fop/fonts/MutableFont.java +++ b/src/java/org/apache/fop/fonts/MutableFont.java @@ -61,8 +61,8 @@ public interface MutableFont { void setEmbedResourceName(String name); /** - * Set the embedding mode for this font. - * @param embeddingMode the embedding mode. + * Sets the embedding mode. + * @param embeddingMode the embedding mode */ void setEmbeddingMode(EmbeddingMode embeddingMode); diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java index 77cdddcdd..1ec4120a6 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java @@ -142,8 +142,9 @@ public class TTFFile { "ccaron", "dcroat" }; - /** The FontFileReader used to read this truetype font */ + /** The FontFileReader used to read this TrueType font. */ protected FontFileReader fontFile; + /** Set to true to get even more debug output than with level DEBUG */ public static final boolean TRACE_ENABLED = false; @@ -246,7 +247,7 @@ public class TTFFile { } /** - * Key-value helper class (immutable) + * Key-value helper class. */ final class UnicodeMapping implements Comparable { @@ -1699,7 +1700,7 @@ public class TTFFile { /** * Streams a font. - * @param ttfOut The interface for streaming True Type tables. + * @param ttfOut The interface for streaming TrueType tables. * @exception IOException file write error */ public void stream(TTFOutputStream ttfOut) throws IOException { @@ -1737,7 +1738,7 @@ public class TTFFile { } /** - * This returns the order in which the tables in a truetype font should be written to file. + * Returns the order in which the tables in a TrueType font should be written to file. * @param directoryTabs the map that is to be sorted. * @return TTFTablesNames[] an array of table names sorted in the order they should appear in * the TTF file. diff --git a/src/java/org/apache/fop/fonts/truetype/TTFGlyphOutputStream.java b/src/java/org/apache/fop/fonts/truetype/TTFGlyphOutputStream.java index ee3101f9b..313d5836d 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFGlyphOutputStream.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFGlyphOutputStream.java @@ -22,27 +22,27 @@ package org.apache.fop.fonts.truetype; import java.io.IOException; /** - * This is an interface for streaming individual glyphs from the glyf table in a True Type font. + * An interface for writing individual glyphs from the glyf table of a TrueType font to an output stream. */ public interface TTFGlyphOutputStream { + /** * Begins the streaming of glyphs. - * @throws IOException file write exception */ void startGlyphStream() throws IOException; /** - * Streams an individual glyph at offset from a byte array. - * @param byteArray byte[] the font byte array. - * @param offset int the starting position to stream from. - * @param length int the number of bytes to stream. - * @throws IOException file write exception. + * Streams an individual glyph from the given byte array. + * + * @param glyphData the source of the glyph data to stream from + * @param offset the position in the glyph data where the glyph starts + * @param size the size of the glyph data in bytes */ - void streamGlyph(byte[] byteArray, int offset, int length) throws IOException; + void streamGlyph(byte[] glyphData, int offset, int size) throws IOException; /** * Ends the streaming of glyphs. - * @throws IOException file write exception. */ void endGlyphStream() throws IOException; + } diff --git a/src/java/org/apache/fop/fonts/truetype/TTFOutputStream.java b/src/java/org/apache/fop/fonts/truetype/TTFOutputStream.java index 8fb8a5cc7..09b5b6f50 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFOutputStream.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFOutputStream.java @@ -22,30 +22,28 @@ package org.apache.fop.fonts.truetype; import java.io.IOException; /** - * This is an interface for streaming True Type font. + * An interface for writing a TrueType font to an output stream. */ public interface TTFOutputStream { + /** - * Starts writing the font to file. - * @throws IOException file write exception. + * Starts writing the font. */ void startFontStream() throws IOException; /** - * Returns an object for streaming True Type tables. - * @return {@link TTFTableOutputStream} + * Returns an object for streaming TrueType tables. */ TTFTableOutputStream getTableOutputStream(); /** - * Returns an object for streaming True Type glyphs in the glyf table. - * @return {@link TTFGlyphOutputStream} + * Returns an object for streaming TrueType glyphs in the glyf table. */ TTFGlyphOutputStream getGlyphOutputStream(); /** - * Ends writing the font to file. - * @throws IOException file write exception. + * Ends writing the font. */ void endFontStream() throws IOException; + } diff --git a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java index 094716a66..5e8fbb379 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java @@ -81,7 +81,7 @@ public class TTFSubSetFile extends TTFFile { = new HashMap(); private int determineTableCount() { - int numTables = 4; //4 req'd tables: head,hhea,hmtx,maxp, + int numTables = 4; //4 req'd tables: head,hhea,hmtx,maxp if (isCFF()) { throw new UnsupportedOperationException( "OpenType fonts with CFF glyphs are not supported"); @@ -126,7 +126,7 @@ public class TTFSubSetFile extends TTFFile { writeUShort((numTables * 16) - searchRange); realSize += 2; - // Create space for the table entries (these must be in ASCII alphabetical order[A-Z]then[a-z]) + // Create space for the table entries (these must be in ASCII alphabetical order[A-Z] then[a-z]) writeTableName(TTFTableName.OS2); if (hasCvt()) { @@ -215,9 +215,6 @@ public class TTFSubSetFile extends TTFFile { /** * Copy the name table as is from the original. - * @param in FontFileReader - * @return boolean - * @throws IOException exception */ private boolean createName(FontFileReader in) throws IOException { return copyTable(in, TTFTableName.NAME); @@ -225,9 +222,6 @@ public class TTFSubSetFile extends TTFFile { /** * Copy the OS/2 table as is from the original. - * @param in - * @return - * @throws IOException */ private boolean createOS2(FontFileReader in) throws IOException { return copyTable(in, TTFTableName.OS2); @@ -389,7 +383,7 @@ public class TTFSubSetFile extends TTFFile { endOffset1 = (currentPos - startPos + glyphLength); } - // Store the glyph boundary positions relative to the start the font + // Store the glyph boundary positions relative to the start of the font glyphOffsets[i] = currentPos; currentPos += glyphLength; realSize += glyphLength; diff --git a/src/java/org/apache/fop/fonts/truetype/TTFTableName.java b/src/java/org/apache/fop/fonts/truetype/TTFTableName.java index 0d071712b..cf66954b6 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFTableName.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFTableName.java @@ -21,95 +21,96 @@ package org.apache.fop.fonts.truetype; /** - * This class holds the True Type Format table names as in the Directory Table of a TTF font file. - * This class must also support custom tables found in fonts (thus an enum wasn't used). + * Represents table names as found in a TrueType font's Table Directory. + * TrueType fonts may have custom tables so we cannot use an enum. */ public final class TTFTableName { - /** The first table in a True Type font file containing metadata about other tables. */ + + /** The first table in a TrueType font file containing metadata about other tables. */ public static final TTFTableName DIRECTORY_TABLE = new TTFTableName("dirTable"); - /** Embedded bitmap data */ + /** Embedded bitmap data. */ public static final TTFTableName EBDT = new TTFTableName("EBDT"); - /** Embedded bitmap location data */ + /** Embedded bitmap location data. */ public static final TTFTableName EBLC = new TTFTableName("EBLC"); - /** Embedded bitmap scaling data */ + /** Embedded bitmap scaling data. */ public static final TTFTableName EBSC = new TTFTableName("EBSC"); - /** A font forge specific table */ + /** A FontForge specific table. */ public static final TTFTableName FFTM = new TTFTableName("FFTM"); /** Divides glyphs into various classes that make using the GPOS/GSUB tables easier. */ public static final TTFTableName GDEF = new TTFTableName("GDEF"); - /** Provides kerning information, mark-to-base, etc. for opentype fonts */ + /** Provides kerning information, mark-to-base, etc. for opentype fonts. */ public static final TTFTableName GPOS = new TTFTableName("GPOS"); - /** Provides ligature information, swash, etc. for opentype fonts */ + /** Provides ligature information, swash, etc. for opentype fonts. */ public static final TTFTableName GSUB = new TTFTableName("GSUB"); - /** Linear threshold table */ + /** Linear threshold table. */ public static final TTFTableName LTSH = new TTFTableName("LTSH"); - /** OS/2 and Windows specific metrics */ + /** OS/2 and Windows specific metrics. */ public static final TTFTableName OS2 = new TTFTableName("OS/2"); - /** PCL 5 data*/ + /** PCL 5 data. */ public static final TTFTableName PCLT = new TTFTableName("PCLT"); - /** Vertical Device Metrics table */ + /** Vertical Device Metrics table. */ public static final TTFTableName VDMX = new TTFTableName("VDMX"); - /** character to glyph mapping */ + /** Character to glyph mapping. */ public static final TTFTableName CMAP = new TTFTableName("cmap"); - /** Control Value Table */ + /** Control Value Table. */ public static final TTFTableName CVT = new TTFTableName("cvt "); - /** font program */ + /** Font program. */ public static final TTFTableName FPGM = new TTFTableName("fpgm"); - /** grid-fitting and scan conversion procedure (grayscale) */ + /** Grid-fitting and scan conversion procedure (grayscale). */ public static final TTFTableName GASP = new TTFTableName("gasp"); - /** glyph data */ + /** Glyph data. */ public static final TTFTableName GLYF = new TTFTableName("glyf"); - /** horizontal device metrics */ + /** Horizontal device metrics. */ public static final TTFTableName HDMX = new TTFTableName("hdmx"); - /** font header */ + /** Font header. */ public static final TTFTableName HEAD = new TTFTableName("head"); - /** horizontal header */ + /** Horizontal header. */ public static final TTFTableName HHEA = new TTFTableName("hhea"); - /** horizontal metrics */ + /** Horizontal metrics. */ public static final TTFTableName HMTX = new TTFTableName("hmtx"); - /** kerning */ + /** Kerning. */ public static final TTFTableName KERN = new TTFTableName("kern"); - /** index to location */ + /** Index to location. */ public static final TTFTableName LOCA = new TTFTableName("loca"); - /** maximum profile */ + /** Maximum profile. */ public static final TTFTableName MAXP = new TTFTableName("maxp"); - /** naming table */ + /** Naming table. */ public static final TTFTableName NAME = new TTFTableName("name"); - /** PostScript information */ + /** PostScript information. */ public static final TTFTableName POST = new TTFTableName("post"); - /** CVT Program */ + /** CVT Program. */ public static final TTFTableName PREP = new TTFTableName("prep"); - /** Vertical Metrics header */ + /** Vertical Metrics header. */ public static final TTFTableName VHEA = new TTFTableName("vhea"); - /** Vertical Metrics */ + /** Vertical Metrics. */ public static final TTFTableName VMTX = new TTFTableName("vmtx"); private final String name; @@ -119,16 +120,15 @@ public final class TTFTableName { } /** - * Returns the name of the table as it should be in the Table Directory. - * @return String + * Returns the name of the table as it should be in the Directory Table. */ public String getName() { return name; } /** - * Returns the appropriate TTFTableName object when given the string representation. - * @param tableName table name as in the Directory Table. + * Returns an instance of this class corresponding to the given string representation. + * @param tableName table name as in the Table Directory * @return TTFTableName */ public static TTFTableName getValue(String tableName) { diff --git a/src/java/org/apache/fop/fonts/truetype/TTFTableOutputStream.java b/src/java/org/apache/fop/fonts/truetype/TTFTableOutputStream.java index 75f0ef63d..d0d2007f5 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFTableOutputStream.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFTableOutputStream.java @@ -22,16 +22,16 @@ package org.apache.fop.fonts.truetype; import java.io.IOException; /** - * An interface for streaming full True Type tables from a TTF file. + * An interface for writing a TrueType table to an output stream. */ public interface TTFTableOutputStream { /** - * Streams a table defined in byteArray at offset of length bytes. - * @param byteArray The source of the table to stream from. - * @param offset The position in byteArray to begin streaming from. - * @param length The number of bytes to stream. - * @throws IOException write error. + * Streams a table from the given byte array. + * + * @param ttfData the source of the table to stream from + * @param offset the position in the byte array where the table starts + * @param size the size of the table in bytes */ - void streamTable(byte[] byteArray, int offset, int length) throws IOException; + void streamTable(byte[] ttfData, int offset, int size) throws IOException; } diff --git a/src/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStream.java b/src/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStream.java index 9727af764..1335a66b5 100644 --- a/src/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStream.java +++ b/src/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStream.java @@ -27,11 +27,12 @@ import org.apache.fop.fonts.truetype.TTFGlyphOutputStream; * This class streams glyphs from the "glyf" table in a True Type font. */ public class PSTTFGlyphOutputStream implements TTFGlyphOutputStream { + /** This counts the total number of bytes written that have been streamed. */ - private int byteCounter = 0; + private int byteCounter; /** This is a place-holder for the offset of the last string boundary. */ - private int lastStringBoundary = 0; + private int lastStringBoundary; private PSTTFGenerator ttfGen; /** @@ -42,31 +43,29 @@ public class PSTTFGlyphOutputStream implements TTFGlyphOutputStream { this.ttfGen = ttfGen; } - /** {@inheritDoc} */ - public void startGlyphStream() throws IOException { + public void startGlyphStream() throws IOException { ttfGen.startString(); } - /** {@inheritDoc} */ - public void streamGlyph(byte[] byteArray, int offset, int length) throws IOException { - if (length > PSTTFGenerator.MAX_BUFFER_SIZE) { - throw new UnsupportedOperationException("The glyph is " + length + " there may be an " - + "error in the font file."); + public void streamGlyph(byte[] glyphData, int offset, int size) throws IOException { + if (size > PSTTFGenerator.MAX_BUFFER_SIZE) { + throw new UnsupportedOperationException("The glyph is " + size + + " bytes. There may be an error in the font file."); } - if (length + (byteCounter - lastStringBoundary) < PSTTFGenerator.MAX_BUFFER_SIZE) { - ttfGen.streamBytes(byteArray, offset, length); + if (size + (byteCounter - lastStringBoundary) < PSTTFGenerator.MAX_BUFFER_SIZE) { + ttfGen.streamBytes(glyphData, offset, size); } else { ttfGen.endString(); lastStringBoundary = byteCounter; ttfGen.startString(); - ttfGen.streamBytes(byteArray, offset, length); + ttfGen.streamBytes(glyphData, offset, size); } - byteCounter += length; + byteCounter += size; } - /** {@inheritDoc} */ public void endGlyphStream() throws IOException { ttfGen.endString(); } + } diff --git a/src/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStream.java b/src/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStream.java index 24d96878e..431374709 100644 --- a/src/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStream.java +++ b/src/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStream.java @@ -28,7 +28,9 @@ import org.apache.fop.fonts.truetype.TTFTableOutputStream; * */ public class PSTTFTableOutputStream implements TTFTableOutputStream { + private PSTTFGenerator ttfGen; + /** * Constructor. * @param ttfGen PSGenerator the streamer class used for streaming bytes. @@ -37,16 +39,15 @@ public class PSTTFTableOutputStream implements TTFTableOutputStream { this.ttfGen = ttfGen; } - /** {@inheritDoc} */ - public void streamTable(byte[] byteArray, int offset, int length) throws IOException { + public void streamTable(byte[] ttfData, int offset, int size) throws IOException { int offsetPosition = offset; // Need to split the table into MAX_BUFFER_SIZE chunks - for (int i = 0; i < length / PSTTFGenerator.MAX_BUFFER_SIZE; i++) { - streamString(byteArray, offsetPosition, PSTTFGenerator.MAX_BUFFER_SIZE); + for (int i = 0; i < size / PSTTFGenerator.MAX_BUFFER_SIZE; i++) { + streamString(ttfData, offsetPosition, PSTTFGenerator.MAX_BUFFER_SIZE); offsetPosition += PSTTFGenerator.MAX_BUFFER_SIZE; } - if (length % PSTTFGenerator.MAX_BUFFER_SIZE > 0) { - streamString(byteArray, offsetPosition, length % PSTTFGenerator.MAX_BUFFER_SIZE); + if (size % PSTTFGenerator.MAX_BUFFER_SIZE > 0) { + streamString(ttfData, offsetPosition, size % PSTTFGenerator.MAX_BUFFER_SIZE); } } -- cgit v1.2.3 From 86004ef152f37a9046c3a9be34190e8852b1e736 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Thu, 31 May 2012 15:24:51 +0000 Subject: Javadoc improvements git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1344773 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/render/ps/fonts/PSTTFGenerator.java | 35 ++++++++++------------ .../render/ps/fonts/PSTTFGlyphOutputStream.java | 10 +++++-- .../fop/render/ps/fonts/PSTTFOutputStream.java | 16 +++++----- .../render/ps/fonts/PSTTFTableOutputStream.java | 6 ++-- src/java/org/apache/fop/util/HexEncoder.java | 2 +- 5 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/java/org/apache/fop/render/ps/fonts/PSTTFGenerator.java b/src/java/org/apache/fop/render/ps/fonts/PSTTFGenerator.java index f8ce37505..31035dc31 100644 --- a/src/java/org/apache/fop/render/ps/fonts/PSTTFGenerator.java +++ b/src/java/org/apache/fop/render/ps/fonts/PSTTFGenerator.java @@ -26,7 +26,7 @@ import org.apache.xmlgraphics.util.io.ASCIIHexOutputStream; /** * This is a wrapper for {@link PSGenerator} that contains some members specific for streaming - * True Type fonts to a PostScript document. + * TrueType fonts to a PostScript document. */ public class PSTTFGenerator { private PSGenerator gen; @@ -40,8 +40,8 @@ public class PSTTFGenerator { public static final int MAX_BUFFER_SIZE = 32764; /** - * Constructor - initialises the PSGenerator in this wrapper class. - * @param gen PSGenerator + * Creates a new instance wrapping the given generator. + * @param gen the PSGenerator to wrap */ public PSTTFGenerator(PSGenerator gen) { this.gen = gen; @@ -49,8 +49,7 @@ public class PSTTFGenerator { } /** - * Begins writing a string by writing '<' to the begin. - * @throws IOException file write exception. + * Writes the '<' character that starts a string. */ public void startString() throws IOException { // We need to reset the streamer so that it starts a new line in the PS document @@ -59,31 +58,29 @@ public class PSTTFGenerator { } /** - * Streams a string to a PostScript document (wraps PSGenerator.write(String)). - * @param cmd String - * @throws IOException file write exception + * Writes the given string to the output. + * @param cmd a string */ public void write(String cmd) throws IOException { gen.write(cmd); } /** - * Streams a string followed by a new line char to a PostScript document (wraps - * PSGenerator.writeln(String)). - * @param cmd String - * @throws IOException file write exception + * Writes the given string to the output, followed by a newline. + * @param cmd a string */ public void writeln(String cmd) throws IOException { gen.writeln(cmd); } /** - * Streams the bytes. - * @param byteArray byte[] the byte array to stream to file. - * @param offset int the starting position in the byte array to stream to file. - * @param length the number of bytes to stream to file. This MUST be less than - * MAX_BUFFER_SIZE - 1 since strings are suffixed by '00' (as in spec). - * @throws IOException file write exception + * Writes bytes from the given byte array to the output. + * + * @param byteArray byte[] a byte array + * @param offset the position in the byte array where the streaming must start + * @param length the number of bytes to stream. This MUST be less than + * {@link MAX_BUFFER_SIZE} - 1 since strings are suffixed by '00' (see Section 4.2 of + * Adobe Technical Note #5012, The Type 42 Font Format Specification.). */ public void streamBytes(byte[] byteArray, int offset, int length) throws IOException { if (length > MAX_BUFFER_SIZE) { @@ -95,10 +92,10 @@ public class PSTTFGenerator { /** * Finishes writing a string by appending '00' and '>' to the end. - * @throws IOException file write exception */ public void endString() throws IOException { /* Appends a '00' to the end of the string as specified in the spec */ gen.write("00\n> "); } + } diff --git a/src/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStream.java b/src/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStream.java index 1335a66b5..cc2ae3e82 100644 --- a/src/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStream.java +++ b/src/java/org/apache/fop/render/ps/fonts/PSTTFGlyphOutputStream.java @@ -24,15 +24,19 @@ import java.io.IOException; import org.apache.fop.fonts.truetype.TTFGlyphOutputStream; /** - * This class streams glyphs from the "glyf" table in a True Type font. + * Streams glyphs in accordance with the constraints of the PostScript file format. + * Mainly, PostScript strings have a limited capacity and the font data may have to be + * broken down into several strings; however, this must occur at well-defined places like + * table or glyph boundaries. See also Adobe Technical Note #5012, The Type 42 Font + * Format Specification. */ public class PSTTFGlyphOutputStream implements TTFGlyphOutputStream { - /** This counts the total number of bytes written that have been streamed. */ + /** Total number of bytes written so far. */ private int byteCounter; - /** This is a place-holder for the offset of the last string boundary. */ private int lastStringBoundary; + private PSTTFGenerator ttfGen; /** diff --git a/src/java/org/apache/fop/render/ps/fonts/PSTTFOutputStream.java b/src/java/org/apache/fop/render/ps/fonts/PSTTFOutputStream.java index bf3803eb4..271d87d1b 100644 --- a/src/java/org/apache/fop/render/ps/fonts/PSTTFOutputStream.java +++ b/src/java/org/apache/fop/render/ps/fonts/PSTTFOutputStream.java @@ -21,42 +21,40 @@ package org.apache.fop.render.ps.fonts; import java.io.IOException; +import org.apache.xmlgraphics.ps.PSGenerator; + import org.apache.fop.fonts.truetype.TTFGlyphOutputStream; import org.apache.fop.fonts.truetype.TTFOutputStream; import org.apache.fop.fonts.truetype.TTFTableOutputStream; -import org.apache.xmlgraphics.ps.PSGenerator; /** - * Implements TTFOutputStream and streams font tables to a PostScript file. + * Streams a TrueType font according to the PostScript format. */ public class PSTTFOutputStream implements TTFOutputStream { - /** The wrapper class for PSGenerator */ + private final PSTTFGenerator ttfGen; /** - * Constructor - assigns a PSGenerator to stream the font. - * @param gen PSGenerator. + * Creates a new instance wrapping the given generator. + * + * @param gen the generator to wrap */ public PSTTFOutputStream(PSGenerator gen) { this.ttfGen = new PSTTFGenerator(gen); } - /** {@inheritDoc} */ public void startFontStream() throws IOException { ttfGen.write("/sfnts["); } - /** {@inheritDoc} */ public TTFTableOutputStream getTableOutputStream() { return new PSTTFTableOutputStream(ttfGen); } - /** {@inheritDoc} */ public TTFGlyphOutputStream getGlyphOutputStream() { return new PSTTFGlyphOutputStream(ttfGen); } - /** {@inheritDoc} */ public void endFontStream() throws IOException { ttfGen.writeln("] def"); } diff --git a/src/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStream.java b/src/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStream.java index 431374709..2226e11e8 100644 --- a/src/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStream.java +++ b/src/java/org/apache/fop/render/ps/fonts/PSTTFTableOutputStream.java @@ -24,8 +24,7 @@ import java.io.IOException; import org.apache.fop.fonts.truetype.TTFTableOutputStream; /** - * This class streams a truetype table to a PostScript file. - * + * Streams a TrueType table according to the PostScript format. */ public class PSTTFTableOutputStream implements TTFTableOutputStream { @@ -33,7 +32,7 @@ public class PSTTFTableOutputStream implements TTFTableOutputStream { /** * Constructor. - * @param ttfGen PSGenerator the streamer class used for streaming bytes. + * @param ttfGen the helper object to stream TrueType data */ public PSTTFTableOutputStream(PSTTFGenerator ttfGen) { this.ttfGen = ttfGen; @@ -56,4 +55,5 @@ public class PSTTFTableOutputStream implements TTFTableOutputStream { ttfGen.streamBytes(byteArray, offset, length); ttfGen.endString(); } + } diff --git a/src/java/org/apache/fop/util/HexEncoder.java b/src/java/org/apache/fop/util/HexEncoder.java index 38f312784..9ca91f2d2 100644 --- a/src/java/org/apache/fop/util/HexEncoder.java +++ b/src/java/org/apache/fop/util/HexEncoder.java @@ -20,7 +20,7 @@ package org.apache.fop.util; /** - * A helper class create to hex-encoded representations of numbers. + * A helper class to create hex-encoded representations of numbers. */ public final class HexEncoder { -- cgit v1.2.3 From fae8882d2261a48ae2b158ff631fe696d511b98b Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Thu, 31 May 2012 15:55:34 +0000 Subject: Renamed DIRECTORY_TABLE into TABLE_DIRECTORY git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1344787 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/truetype/TTFFile.java | 2 +- src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java | 2 +- src/java/org/apache/fop/fonts/truetype/TTFTableName.java | 2 +- test/java/org/apache/fop/fonts/truetype/TTFTableNameTestCase.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java index 1ec4120a6..a1d012aa3 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java @@ -1058,7 +1058,7 @@ public class TTFFile { String tableName = pd[i].read(fontFile); dirTabs.put(TTFTableName.getValue(tableName), pd[i]); } - dirTabs.put(TTFTableName.DIRECTORY_TABLE, + dirTabs.put(TTFTableName.TABLE_DIRECTORY, new TTFDirTabEntry(0L, fontFile.getCurrentPos())); log.debug("dir tables: " + dirTabs.keySet()); } diff --git a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java index 5e8fbb379..00cb45f5a 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java @@ -146,7 +146,7 @@ public class TTFSubSetFile extends TTFFile { if (hasPrep()) { writeTableName(TTFTableName.PREP); } - newDirTabs.put(TTFTableName.DIRECTORY_TABLE, new TTFDirTabEntry(0, currentPos)); + newDirTabs.put(TTFTableName.TABLE_DIRECTORY, new TTFDirTabEntry(0, currentPos)); } private void writeTableName(TTFTableName tableName) { diff --git a/src/java/org/apache/fop/fonts/truetype/TTFTableName.java b/src/java/org/apache/fop/fonts/truetype/TTFTableName.java index cf66954b6..e5ad63128 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFTableName.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFTableName.java @@ -27,7 +27,7 @@ package org.apache.fop.fonts.truetype; public final class TTFTableName { /** The first table in a TrueType font file containing metadata about other tables. */ - public static final TTFTableName DIRECTORY_TABLE = new TTFTableName("dirTable"); + public static final TTFTableName TABLE_DIRECTORY = new TTFTableName("tableDirectory"); /** Embedded bitmap data. */ public static final TTFTableName EBDT = new TTFTableName("EBDT"); diff --git a/test/java/org/apache/fop/fonts/truetype/TTFTableNameTestCase.java b/test/java/org/apache/fop/fonts/truetype/TTFTableNameTestCase.java index 0a2eec544..b9066dc2d 100644 --- a/test/java/org/apache/fop/fonts/truetype/TTFTableNameTestCase.java +++ b/test/java/org/apache/fop/fonts/truetype/TTFTableNameTestCase.java @@ -37,7 +37,7 @@ public class TTFTableNameTestCase { */ @Test public void testGetName() throws IllegalAccessException { - assertEquals("dirTable", TTFTableName.DIRECTORY_TABLE.getName()); + assertEquals("tableDirectory", TTFTableName.TABLE_DIRECTORY.getName()); assertEquals("EBDT", TTFTableName.EBDT.getName()); assertEquals("EBLC", TTFTableName.EBLC.getName()); assertEquals("EBSC", TTFTableName.EBSC.getName()); -- cgit v1.2.3 From 37378b836a3c55ac323010e39e4986c14337eb60 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 13 Jun 2012 15:40:23 +0000 Subject: Removed commented code: subset-embedding for single-byte fonts is not working yet git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1349919 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/render/ps/PSFontUtils.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index 53ceff53e..c70181cf7 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -40,10 +40,10 @@ import org.apache.xmlgraphics.ps.PSGenerator; import org.apache.xmlgraphics.ps.PSResource; import org.apache.xmlgraphics.ps.dsc.ResourceTracker; -import org.apache.fop.fonts.CMapSegment; import org.apache.fop.fonts.Base14Font; import org.apache.fop.fonts.CIDFontType; import org.apache.fop.fonts.CIDSubset; +import org.apache.fop.fonts.CMapSegment; import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.EmbeddingMode; import org.apache.fop.fonts.Font; @@ -56,9 +56,9 @@ import org.apache.fop.fonts.SingleByteFont; import org.apache.fop.fonts.Typeface; import org.apache.fop.fonts.truetype.FontFileReader; import org.apache.fop.fonts.truetype.TTFFile; +import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; import org.apache.fop.fonts.truetype.TTFOutputStream; import org.apache.fop.fonts.truetype.TTFSubSetFile; -import org.apache.fop.fonts.truetype.TTFFile.PostScriptVersion; import org.apache.fop.render.ps.fonts.PSTTFOutputStream; import org.apache.fop.util.HexEncoder; @@ -297,16 +297,6 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { font.setEmbeddingMode(EmbeddingMode.SUBSET); } FontFileReader reader = new FontFileReader(fontStream); - // TODO is subset-embedding working? In which case the following can be factorized - // with what is in composeType0Font -// TTFFile ttfFile; -// if (font.getEmbeddingMode() != EmbeddingMode.FULL) { -// ttfFile = new TTFSubSetFile(); -// ttfFile.readFont(reader, font.getFullName()(), font.getUsedGlyphs()); -// } else { -// ttfFile = new TTFFile(); -// ttfFile.readFont(reader, font.getFullName()); -// } TTFFile ttfFile = new TTFFile(); ttfFile.readFont(reader, font.getFullName()); createType42DictionaryEntries(gen, font, font.getCMap(), ttfFile); -- cgit v1.2.3 From eaa8350771d955e817b65258461f581a640deb31 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 18 Jun 2012 14:04:02 +0000 Subject: Cosmetics only: organised imports git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1351348 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/FontLoader.java | 1 + src/java/org/apache/fop/fonts/LazyFont.java | 5 +++-- src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java | 2 +- src/java/org/apache/fop/pdf/PDFFactory.java | 2 +- src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java | 1 + src/java/org/apache/fop/render/ps/PSTextPainter.java | 1 - 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/java/org/apache/fop/fonts/FontLoader.java b/src/java/org/apache/fop/fonts/FontLoader.java index 46c35ccaa..9bdbcd350 100644 --- a/src/java/org/apache/fop/fonts/FontLoader.java +++ b/src/java/org/apache/fop/fonts/FontLoader.java @@ -30,6 +30,7 @@ import javax.xml.transform.stream.StreamSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.fop.fonts.truetype.TTFFontLoader; import org.apache.fop.fonts.type1.Type1FontLoader; diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java index 67e7de7c0..dfad4ffce 100644 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ b/src/java/org/apache/fop/fonts/LazyFont.java @@ -27,14 +27,15 @@ import java.util.Set; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; +import org.xml.sax.InputSource; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.fop.apps.FOPException; -import org.xml.sax.InputSource; import org.apache.fop.complexscripts.fonts.Positionable; import org.apache.fop.complexscripts.fonts.Substitutable; - /** * This class is used to defer the loading of a font until it is really used. */ diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index 9c6098de2..8f0744d50 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -26,8 +26,8 @@ import java.util.Set; import org.apache.commons.io.IOUtils; -import org.apache.fop.fonts.CMapSegment; import org.apache.fop.fonts.CIDFontType; +import org.apache.fop.fonts.CMapSegment; import org.apache.fop.fonts.EmbeddingMode; import org.apache.fop.fonts.EncodingMode; import org.apache.fop.fonts.FontLoader; diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java index 9b2968c33..beb384dcf 100644 --- a/src/java/org/apache/fop/pdf/PDFFactory.java +++ b/src/java/org/apache/fop/pdf/PDFFactory.java @@ -45,6 +45,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.java2d.color.ColorUtil; import org.apache.xmlgraphics.java2d.color.NamedColorSpace; + import org.apache.xmlgraphics.xmp.Metadata; import org.apache.fop.fonts.CIDFont; @@ -64,7 +65,6 @@ import org.apache.fop.fonts.truetype.FontFileReader; import org.apache.fop.fonts.truetype.TTFSubSetFile; import org.apache.fop.fonts.type1.PFBData; import org.apache.fop.fonts.type1.PFBParser; -import org.apache.xmlgraphics.xmp.Metadata; /** * This class provides method to create and register PDF objects. diff --git a/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java b/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java index 2520d6347..9c404be3e 100644 --- a/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java +++ b/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java @@ -25,6 +25,7 @@ import javax.xml.transform.Source; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.EmbedFontInfo; import org.apache.fop.fonts.EncodingMode; diff --git a/src/java/org/apache/fop/render/ps/PSTextPainter.java b/src/java/org/apache/fop/render/ps/PSTextPainter.java index 822a9a66d..2b3afaec7 100644 --- a/src/java/org/apache/fop/render/ps/PSTextPainter.java +++ b/src/java/org/apache/fop/render/ps/PSTextPainter.java @@ -35,7 +35,6 @@ 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; -- cgit v1.2.3 From 4cd3db9c8ef05e5e5c31c847cf9de24e0a9cc452 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 18 Jun 2012 14:05:46 +0000 Subject: Fixed FindBugs issue: use String.to(Lower|Upper)Case with Locale.ENGLISH git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1351349 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/EmbeddingMode.java | 4 +++- src/java/org/apache/fop/render/ps/PSFontUtils.java | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/java/org/apache/fop/fonts/EmbeddingMode.java b/src/java/org/apache/fop/fonts/EmbeddingMode.java index d75c7a3d4..5a3e905c9 100644 --- a/src/java/org/apache/fop/fonts/EmbeddingMode.java +++ b/src/java/org/apache/fop/fonts/EmbeddingMode.java @@ -19,6 +19,8 @@ package org.apache.fop.fonts; +import java.util.Locale; + /** * This enumerates the embedding mode of fonts; full; subset; auto (auto defaults to full for * Type 1 fonts and subset for TrueType fonts. @@ -37,7 +39,7 @@ public enum EmbeddingMode { * @return the name of this embedding mode in lower case. */ public String getName() { - return this.toString().toLowerCase(); + return this.toString().toLowerCase(Locale.ENGLISH); } /** diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index c70181cf7..d0d75744f 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -25,6 +25,7 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.util.HashMap; import java.util.HashSet; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -374,7 +375,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { char ch16 = (char)ch; //TODO Handle Unicode characters beyond 16bit String glyphName = Glyphs.charToGlyphName(ch16); if ("".equals(glyphName)) { - glyphName = "u" + Integer.toHexString(ch).toUpperCase(); + glyphName = "u" + Integer.toHexString(ch).toUpperCase(Locale.ENGLISH); } writeGlyphDefs(gen, glyphName, glyphIndex); -- cgit v1.2.3 From cc0a25b5405e3fe7aed441d86fb40b25852b1560 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 18 Jun 2012 14:06:12 +0000 Subject: Fixed FindBugs issue: do not compare strings with == or != git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1351350 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index 8f0744d50..1410239ee 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -199,10 +199,10 @@ public class TTFFontLoader extends FontLoader { if (codePoint <= 0) { int glyphIndex = segment.getGlyphStartIndex() + u - segment.getUnicodeStart(); String glyphName = ttf.getGlyphName(glyphIndex); - if (glyphName == "" && ttf.getPostScriptVersion() != PostScriptVersion.V2) { + if (glyphName.length() == 0 && ttf.getPostScriptVersion() != PostScriptVersion.V2) { glyphName = "u" + HexEncoder.encode(u); } - if (glyphName != "") { + if (glyphName.length() > 0) { String unicode = Character.toString(u); NamedCharacter nc = new NamedCharacter(glyphName, unicode); singleFont.addUnencodedCharacter(nc, wx[glyphIndex]); -- cgit v1.2.3 From 58efb3c3ac4c0e54ee5157aef60cbcc9ff163542 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 18 Jun 2012 14:07:00 +0000 Subject: Removed unused private methods git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1351351 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/fonts/truetype/TTFSubSetFile.java | 101 --------------------- 1 file changed, 101 deletions(-) diff --git a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java index 00cb45f5a..c83aaabd8 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java @@ -458,107 +458,6 @@ public class TTFSubSetFile extends TTFFile { } } - /** - * Returns a List containing the glyph itself plus all glyphs - * that this composite glyph uses - */ - private List getIncludedGlyphs(FontFileReader in, int glyphOffset, - Integer glyphIdx) throws IOException { - List ret = new java.util.ArrayList(); - ret.add(glyphIdx); - int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset() + 10; - Integer compositeIdx = null; - int flags = 0; - boolean moreComposites = true; - while (moreComposites) { - flags = in.readTTFUShort(offset); - compositeIdx = Integer.valueOf(in.readTTFUShort(offset + 2)); - ret.add(compositeIdx); - - offset += 4; - if ((flags & 1) > 0) { - // ARG_1_AND_ARG_2_ARE_WORDS - offset += 4; - } else { - offset += 2; - } - - if ((flags & 8) > 0) { - offset += 2; // WE_HAVE_A_SCALE - } else if ((flags & 64) > 0) { - offset += 4; // WE_HAVE_AN_X_AND_Y_SCALE - } else if ((flags & 128) > 0) { - offset += 8; // WE_HAVE_A_TWO_BY_TWO - } - - if ((flags & 32) > 0) { - moreComposites = true; - } else { - moreComposites = false; - } - } - - return ret; - } - - - /** - * Rewrite all compositepointers in glyphindex glyphIdx - * - */ - private void remapComposite(FontFileReader in, Map glyphs, - int glyphOffset, - Integer glyphIdx) throws IOException { - int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset() - + 10; - - Integer compositeIdx = null; - int flags = 0; - boolean moreComposites = true; - - while (moreComposites) { - flags = in.readTTFUShort(offset); - compositeIdx = Integer.valueOf(in.readTTFUShort(offset + 2)); - Integer newIdx = glyphs.get(compositeIdx); - if (newIdx == null) { - // This errormessage would look much better - // if the fontname was printed to - //log.error("An embedded font " - // + "contains bad glyph data. " - // + "Characters might not display " - // + "correctly."); - moreComposites = false; - continue; - } - - in.writeTTFUShort(offset + 2, newIdx.intValue()); - - offset += 4; - - if ((flags & 1) > 0) { - // ARG_1_AND_ARG_2_ARE_WORDS - offset += 4; - } else { - offset += 2; - } - - if ((flags & 8) > 0) { - offset += 2; // WE_HAVE_A_SCALE - } else if ((flags & 64) > 0) { - offset += 4; // WE_HAVE_AN_X_AND_Y_SCALE - } else if ((flags & 128) > 0) { - offset += 8; // WE_HAVE_A_TWO_BY_TWO - } - - if ((flags & 32) > 0) { - moreComposites = true; - } else { - moreComposites = false; - } - } - } - - /** * Reads a font and creates a subset of the font. * -- cgit v1.2.3 From 4582b41af17d7f7ba85a399d6ff0d44a85f4fee9 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 18 Jun 2012 14:07:54 +0000 Subject: Ignore new FindBugs issues git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1351352 13f79535-47bb-0310-9956-ffa450edef68 --- findbugs-exclude.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/findbugs-exclude.xml b/findbugs-exclude.xml index 46879d1f6..f1289c560 100644 --- a/findbugs-exclude.xml +++ b/findbugs-exclude.xml @@ -1,5 +1,14 @@ + + + + + + + + + -- cgit v1.2.3 From 4e554123dc134fa7a8180f3398e0f2277456159d Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 18 Jun 2012 14:38:56 +0000 Subject: Updated the documentation git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_TrueTypeInPostScript@1351362 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/trunk/fonts.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/documentation/content/xdocs/trunk/fonts.xml b/src/documentation/content/xdocs/trunk/fonts.xml index f3481607d..ba607e40b 100644 --- a/src/documentation/content/xdocs/trunk/fonts.xml +++ b/src/documentation/content/xdocs/trunk/fonts.xml @@ -493,10 +493,10 @@ Various notes related to embedded fonts:

    -
  • The PostScript renderer does not yet support TrueType fonts, but can embed Type 1 fonts.
  • -
  • The font is simply embedded into the PDF file, it is not converted.
  • -
  • When FOP embeds a font, it adds a prefix to the fontname to ensure that the name will not match the fontname of an installed font. - This is helpful with older versions of Acrobat Reader that preferred installed fonts over embedded fonts.
  • +
  • The font is simply embedded into the output file, it is not converted.
  • +
  • When FOP embeds a font in a PDF file, it adds a prefix to the fontname to ensure that + the name will not match the fontname of an installed font. This is helpful with older + versions of Acrobat Reader that preferred installed fonts over embedded fonts.
  • When embedding PostScript fonts, the entire font is always embedded.
  • When embedding TrueType fonts (ttf) or TrueType Collections (ttc), a subset of the original font, containing only the glyphs used, is embedded in the output document. @@ -576,4 +576,4 @@

    - \ No newline at end of file + -- cgit v1.2.3