diff options
Diffstat (limited to 'src/java/org/apache/fop/afp/fonts')
14 files changed, 471 insertions, 216 deletions
diff --git a/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java b/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java index 417250df1..244e6122c 100644 --- a/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java +++ b/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java @@ -19,6 +19,7 @@ package org.apache.fop.afp.fonts; +import org.apache.fop.afp.AFPEventProducer; import org.apache.fop.fonts.Base14Font; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontCollection; @@ -40,6 +41,15 @@ import org.apache.fop.fonts.base14.TimesRoman; */ public class AFPBase12FontCollection implements FontCollection { + private final AFPEventProducer eventProducer; + + /** + * @param eventProducer the AFP-specific event producer + */ + public AFPBase12FontCollection(AFPEventProducer eventProducer) { + this.eventProducer = eventProducer; + } + /** standard raster font sizes */ private static final int[] RASTER_SIZES = {6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 30, 36}; @@ -52,7 +62,7 @@ public class AFPBase12FontCollection implements FontCollection { int size = RASTER_SIZES[i] * 1000; FopCharacterSet characterSet = new FopCharacterSet( CharacterSet.DEFAULT_CODEPAGE, CharacterSet.DEFAULT_ENCODING, - charsetName + CHARSET_REF[i], base14); + charsetName + CHARSET_REF[i], base14, eventProducer); font.addCharacterSet(size, characterSet); } } @@ -108,22 +118,22 @@ public class AFPBase12FontCollection implements FontCollection { "Times New Roman", "TimesNewRoman", "serif", "any"}; font = createReferencedRasterFont("Times Roman"); - addCharacterSet(font, "CON200", new TimesRoman()); + addCharacterSet(font, "C0N200", new TimesRoman()); num = addFontProperties(fontInfo, font, timesNames, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL, num); font = createReferencedRasterFont("Times Roman Italic"); - addCharacterSet(font, "CON300", new TimesItalic()); + addCharacterSet(font, "C0N300", new TimesItalic()); num = addFontProperties(fontInfo, font, timesNames, Font.STYLE_ITALIC, Font.WEIGHT_NORMAL, num); font = createReferencedRasterFont("Times Roman Bold"); - addCharacterSet(font, "CON400", new TimesBold()); + addCharacterSet(font, "C0N400", new TimesBold()); num = addFontProperties(fontInfo, font, timesNames, Font.STYLE_NORMAL, Font.WEIGHT_BOLD, num); font = createReferencedRasterFont("Times Roman Italic Bold"); - addCharacterSet(font, "CON500", new TimesBoldItalic()); + addCharacterSet(font, "C0N500", new TimesBoldItalic()); num = addFontProperties(fontInfo, font, timesNames, Font.STYLE_ITALIC, Font.WEIGHT_BOLD, num); diff --git a/src/java/org/apache/fop/afp/fonts/AFPFont.java b/src/java/org/apache/fop/afp/fonts/AFPFont.java index 944c98f8e..8a4ae3dc1 100644 --- a/src/java/org/apache/fop/afp/fonts/AFPFont.java +++ b/src/java/org/apache/fop/afp/fonts/AFPFont.java @@ -19,6 +19,7 @@ package org.apache.fop.afp.fonts; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -62,8 +63,8 @@ public abstract class AFPFont extends Typeface { } /** {@inheritDoc} */ - public Set getFamilyNames() { - Set s = new java.util.HashSet(); + public Set<String> getFamilyNames() { + Set<String> s = new HashSet<String>(); s.add(this.name); return s; } @@ -129,4 +130,4 @@ public abstract class AFPFont extends Typeface { public String toString() { return "name=" + name; } -}
\ No newline at end of file +} diff --git a/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java b/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java index b7db6a74e..0854d04a1 100644 --- a/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java +++ b/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java @@ -19,7 +19,6 @@ package org.apache.fop.afp.fonts; -import java.util.Iterator; import java.util.List; import org.apache.fop.afp.AFPEventProducer; @@ -34,9 +33,9 @@ import org.apache.fop.fonts.FontTriplet; */ public class AFPFontCollection implements FontCollection { - private final EventBroadcaster eventBroadcaster; + private final AFPEventProducer eventProducer; - private final List/*<AFPFontInfo>*/ fontInfoList; + private final List<AFPFontInfo> fontInfoList; /** * Main constructor @@ -44,49 +43,40 @@ public class AFPFontCollection implements FontCollection { * @param eventBroadcaster the event broadcaster * @param fontInfoList the font info list */ - public AFPFontCollection(EventBroadcaster eventBroadcaster, - List/*<AFPFontInfo>*/ fontInfoList) { - this.eventBroadcaster = eventBroadcaster; + public AFPFontCollection(EventBroadcaster eventBroadcaster, List<AFPFontInfo> fontInfoList) { + this.eventProducer = AFPEventProducer.Provider.get(eventBroadcaster); this.fontInfoList = fontInfoList; } /** {@inheritDoc} */ public int setup(int start, FontInfo fontInfo) { int num = 1; - AFPEventProducer eventProducer = AFPEventProducer.Provider.get(eventBroadcaster); if (fontInfoList != null && fontInfoList.size() > 0) { - for (Iterator it = fontInfoList.iterator(); it.hasNext();) { - AFPFontInfo afpFontInfo = (AFPFontInfo)it.next(); + for (AFPFontInfo afpFontInfo : fontInfoList) { AFPFont afpFont = afpFontInfo.getAFPFont(); - List/*<FontTriplet>*/ tripletList = afpFontInfo.getFontTriplets(); - for (Iterator it2 = tripletList.iterator(); it2.hasNext();) { - FontTriplet triplet = (FontTriplet)it2.next(); + List<FontTriplet> tripletList = afpFontInfo.getFontTriplets(); + for (FontTriplet triplet : tripletList) { fontInfo.addMetrics("F" + num, afpFont); fontInfo.addFontProperties("F" + num, triplet.getName(), triplet.getStyle(), triplet.getWeight()); num++; } } - checkDefaultFontAvailable(fontInfo, eventProducer, - Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - checkDefaultFontAvailable(fontInfo, eventProducer, - Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - checkDefaultFontAvailable(fontInfo, eventProducer, - Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - checkDefaultFontAvailable(fontInfo, eventProducer, - Font.STYLE_ITALIC, Font.WEIGHT_BOLD); + checkDefaultFontAvailable(fontInfo, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); + checkDefaultFontAvailable(fontInfo, Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); + checkDefaultFontAvailable(fontInfo, Font.STYLE_NORMAL, Font.WEIGHT_BOLD); + checkDefaultFontAvailable(fontInfo, Font.STYLE_ITALIC, Font.WEIGHT_BOLD); } else { eventProducer.warnDefaultFontSetup(this); // Go with a default base 12 configuration for AFP environments - FontCollection base12FontCollection = new AFPBase12FontCollection(); + FontCollection base12FontCollection = new AFPBase12FontCollection(eventProducer); num = base12FontCollection.setup(num, fontInfo); } return num; } - private void checkDefaultFontAvailable(FontInfo fontInfo, AFPEventProducer eventProducer, - String style, int weight) { + private void checkDefaultFontAvailable(FontInfo fontInfo, String style, int weight) { if (!fontInfo.hasFont("any", style, weight)) { eventProducer.warnMissingDefaultFont(this, style, weight); } diff --git a/src/java/org/apache/fop/afp/fonts/AFPFontInfo.java b/src/java/org/apache/fop/afp/fonts/AFPFontInfo.java index 0259435c6..8e865d4e5 100644 --- a/src/java/org/apache/fop/afp/fonts/AFPFontInfo.java +++ b/src/java/org/apache/fop/afp/fonts/AFPFontInfo.java @@ -21,6 +21,8 @@ package org.apache.fop.afp.fonts; import java.util.List; +import org.apache.fop.fonts.FontTriplet; + /** * FontInfo contains meta information on fonts @@ -28,22 +30,22 @@ import java.util.List; public class AFPFontInfo { private AFPFont font; - private List/*<FontTriplet>*/ tripletList; + private List<FontTriplet> tripletList; /** * Main constructor - * + * * @param afpFont The AFP Font * @param tripletList List of font triplets to associate with this font */ - public AFPFontInfo(AFPFont afpFont, List/*<FontTriplet>*/ tripletList) { + public AFPFontInfo(AFPFont afpFont, List<FontTriplet> tripletList) { this.font = afpFont; this.tripletList = tripletList; } /** * Returns the afp font - * + * * @return the afp font */ public AFPFont getAFPFont() { @@ -52,10 +54,10 @@ public class AFPFontInfo { /** * Returns the list of font triplets associated with this font. - * + * * @return List of font triplets */ - public List/*<FontTriplet>*/ getFontTriplets() { + public List<FontTriplet> getFontTriplets() { return tripletList; } diff --git a/src/java/org/apache/fop/afp/fonts/AFPPageFonts.java b/src/java/org/apache/fop/afp/fonts/AFPPageFonts.java index ee7a3c0eb..2d1fec1ab 100644 --- a/src/java/org/apache/fop/afp/fonts/AFPPageFonts.java +++ b/src/java/org/apache/fop/afp/fonts/AFPPageFonts.java @@ -61,4 +61,4 @@ public class AFPPageFonts extends java.util.HashMap { } return afpFontAttributes; } -}
\ No newline at end of file +} diff --git a/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java b/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java index c1ab6a5fc..fdd238242 100644 --- a/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java +++ b/src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java @@ -174,4 +174,4 @@ public abstract class AbstractOutlineFont extends AFPFont { return charSet.getEncoding(); } -}
\ No newline at end of file +} diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSet.java b/src/java/org/apache/fop/afp/fonts/CharacterSet.java index 7123d4138..fad5e95e6 100644 --- a/src/java/org/apache/fop/afp/fonts/CharacterSet.java +++ b/src/java/org/apache/fop/afp/fonts/CharacterSet.java @@ -19,23 +19,18 @@ package org.apache.fop.afp.fonts; -import java.io.File; import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CodingErrorAction; -import java.nio.charset.UnsupportedCharsetException; +import java.util.HashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.afp.AFPConstants; +import org.apache.fop.afp.AFPEventProducer; +import org.apache.fop.afp.fonts.CharactersetEncoder.EncodedChars; import org.apache.fop.afp.util.ResourceAccessor; -import org.apache.fop.afp.util.SimpleResourceAccessor; import org.apache.fop.afp.util.StringUtils; /** @@ -70,59 +65,46 @@ public class CharacterSet { /** The code page to which the character set relates */ - protected String codePage; + protected final String codePage; /** The encoding used for the code page */ - protected String encoding; + protected final String encoding; - /** The charset encoder corresponding to this encoding */ - private CharsetEncoder encoder; + /** The characterset encoder corresponding to this encoding */ + private final CharactersetEncoder encoder; /** The character set relating to the font */ - protected String name; + protected final String name; /** The path to the installed fonts */ - private ResourceAccessor accessor; + private final ResourceAccessor accessor; /** The current orientation (currently only 0 is supported by FOP) */ private final String currentOrientation = "0"; /** The collection of objects for each orientation */ - private Map characterSetOrientations = null; + private final Map<String, CharacterSetOrientation> characterSetOrientations; /** The nominal vertical size (in millipoints) for bitmap fonts. 0 for outline fonts. */ - private int nominalVerticalSize = 0; + private int nominalVerticalSize; /** - * Constructor for the CharacterSetMetric object, the character set is used - * to load the font information from the actual AFP font. - * - * @param codePage the code page identifier - * @param encoding the encoding of the font - * @param name the character set name - * @param path the path to the installed afp fonts - * @deprecated Please use - * {@link #CharacterSet(String, String, String, ResourceAccessor)} instead. - */ - public CharacterSet(String codePage, String encoding, String name, String path) { - this(codePage, encoding, name, - new SimpleResourceAccessor(path != null ? new File(path) : null)); - } - - /** - * Constructor for the CharacterSetMetric object, the character set is used - * to load the font information from the actual AFP font. + * Constructor for the CharacterSetMetric object, the character set is used to load the font + * information from the actual AFP font. * * @param codePage the code page identifier * @param encoding the encoding of the font + * @param charsetType the type of the characterset * @param name the character set name * @param accessor the resource accessor to load resource with + * @param eventProducer for handling AFP related events */ - CharacterSet(String codePage, String encoding, String name, ResourceAccessor accessor) { + CharacterSet(String codePage, String encoding, CharacterSetType charsetType, String name, + ResourceAccessor accessor, AFPEventProducer eventProducer) { if (name.length() > MAX_NAME_LEN) { String msg = "Character set name '" + name + "' must be a maximum of " + MAX_NAME_LEN + " characters"; - LOG.error("Constructor:: " + msg); + eventProducer.characterSetNameInvalid(this, msg); throw new IllegalArgumentException(msg); } @@ -133,17 +115,10 @@ public class CharacterSet { } this.codePage = codePage; this.encoding = encoding; - try { - this.encoder = Charset.forName(encoding).newEncoder(); - this.encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); - } catch (UnsupportedCharsetException uce) { - //No nio-capable encoder available - //This may happen with "Cp500" on Sun Java 1.4.2 - this.encoder = null; - } + this.encoder = CharactersetEncoder.newInstance(encoding, charsetType); this.accessor = accessor; - this.characterSetOrientations = new java.util.HashMap(4); + this.characterSetOrientations = new HashMap<String, CharacterSetOrientation>(4); } /** @@ -152,9 +127,7 @@ public class CharacterSet { * @param cso the metrics for the orientation */ public void addCharacterSetOrientation(CharacterSetOrientation cso) { - characterSetOrientations.put( - String.valueOf(cso.getOrientation()), - cso); + characterSetOrientations.put(String.valueOf(cso.getOrientation()), cso); } /** @@ -333,7 +306,7 @@ public class CharacterSet { */ private CharacterSetOrientation getCharacterSetOrientation() { CharacterSetOrientation c - = (CharacterSetOrientation) characterSetOrientations.get(currentOrientation); + = characterSetOrientations.get(currentOrientation); return c; } @@ -357,32 +330,8 @@ public class CharacterSet { * @return the encoded characters * @throws CharacterCodingException if the encoding operation fails */ - public byte[] encodeChars(CharSequence chars) throws CharacterCodingException { - if (encoder != null) { - ByteBuffer bb; - // encode method is not thread safe - synchronized (encoder) { - bb = encoder.encode(CharBuffer.wrap(chars)); - } - if (bb.hasArray()) { - return bb.array(); - } else { - bb.rewind(); - byte[] bytes = new byte[bb.remaining()]; - bb.get(bytes); - return bytes; - } - } else { - //Sun Java 1.4.2 compatibility - byte[] bytes; - try { - bytes = chars.toString().getBytes(this.encoding); - return bytes; - } catch (UnsupportedEncodingException uee) { - throw new UnsupportedOperationException( - "Unsupported encoding: " + uee.getMessage()); - } - } + public EncodedChars encodeChars(CharSequence chars) throws CharacterCodingException { + return encoder.encode(chars); } /** diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java b/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java index d575e2ae1..7da2d71ca 100644 --- a/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java +++ b/src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java @@ -24,6 +24,9 @@ import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.WeakHashMap; @@ -34,6 +37,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.image.loader.util.SoftMapCache; import org.apache.fop.afp.AFPConstants; +import org.apache.fop.afp.AFPEventProducer; import org.apache.fop.afp.util.ResourceAccessor; import org.apache.fop.afp.util.StructuredFieldReader; import org.apache.fop.fonts.Typeface; @@ -58,7 +62,7 @@ import org.apache.fop.fonts.Typeface; * formatted object. <p/> * */ -public class CharacterSetBuilder { +public abstract class CharacterSetBuilder { /** * Static logging instance @@ -66,11 +70,6 @@ public class CharacterSetBuilder { protected static final Log LOG = LogFactory.getLog(CharacterSetBuilder.class); /** - * Singleton reference - */ - private static CharacterSetBuilder instance; - - /** * Template used to convert lists to arrays. */ private static final CharacterSetOrientation[] EMPTY_CSO_ARRAY = new CharacterSetOrientation[0]; @@ -106,8 +105,8 @@ public class CharacterSetBuilder { /** * The collection of code pages */ - private final Map/*<String, Map<String, String>>*/ codePagesCache - = new WeakHashMap/*<String, Map<String, String>>*/(); + private final Map<String, Map<String, String>> codePagesCache + = Collections.synchronizedMap(new WeakHashMap<String, Map<String, String>>()); /** * Cache of charactersets @@ -115,18 +114,15 @@ public class CharacterSetBuilder { private final SoftMapCache characterSetsCache = new SoftMapCache(true); /** Default constructor. */ - protected CharacterSetBuilder() { + private CharacterSetBuilder() { } /** * Factory method for the single-byte implementation of AFPFontReader. * @return AFPFontReader */ - public static CharacterSetBuilder getInstance() { - if (instance == null) { - instance = new CharacterSetBuilder(); - } - return instance; + public static CharacterSetBuilder getSingleByteInstance() { + return SingleByteLoader.getInstance(); } /** @@ -134,7 +130,7 @@ public class CharacterSetBuilder { * @return AFPFontReader */ public static CharacterSetBuilder getDoubleByteInstance() { - return new DoubleByteLoader(); + return DoubleByteLoader.getInstance(); } @@ -143,11 +139,13 @@ public class CharacterSetBuilder { * * * @param accessor the resource accessor * @param filename the file name + * @param eventProducer for handling AFP related events * @return an inputStream * * @throws IOException in the event that an I/O exception of some sort has occurred */ - protected InputStream openInputStream(ResourceAccessor accessor, String filename) + protected InputStream openInputStream(ResourceAccessor accessor, String filename, + AFPEventProducer eventProducer) throws IOException { URI uri; try { @@ -181,30 +179,76 @@ public class CharacterSetBuilder { } /** - * Load the font details and metrics into the CharacterSetMetric object, - * this will use the actual afp code page and character set files to load - * the object with the necessary metrics. + * Load the font details and metrics into the CharacterSetMetric object, this will use the + * actual afp code page and character set files to load the object with the necessary metrics. + * * @param characterSetName name of the characterset * @param codePageName name of the code page file * @param encoding encoding name * @param accessor used to load codepage and characterset + * @param eventProducer for handling AFP related events * @return CharacterSet object * @throws IOException if an I/O error occurs */ - public CharacterSet build(String characterSetName, String codePageName, - String encoding, ResourceAccessor accessor) throws IOException { + public CharacterSet buildSBCS(String characterSetName, String codePageName, String encoding, + ResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { + return processFont(characterSetName, codePageName, encoding, CharacterSetType.SINGLE_BYTE, + accessor, eventProducer); + } + + /** + * Load the font details and metrics into the CharacterSetMetric object, this will use the + * actual afp code page and character set files to load the object with the necessary metrics. + * This method is to be used for double byte character sets (DBCS). + * + * @param characterSetName name of the characterset + * @param codePageName name of the code page file + * @param encoding encoding name + * @param charsetType the characterset type + * @param accessor used to load codepage and characterset + * @param eventProducer for handling AFP related events + * @return CharacterSet object + * @throws IOException if an I/O error occurs + */ + public CharacterSet buildDBCS(String characterSetName, String codePageName, String encoding, + CharacterSetType charsetType, ResourceAccessor accessor, AFPEventProducer eventProducer) + throws IOException { + return processFont(characterSetName, codePageName, encoding, charsetType, accessor, + eventProducer); + } + + /** + * Load the font details and metrics into the CharacterSetMetric object, this will use the + * actual afp code page and character set files to load the object with the necessary metrics. + * + * @param characterSetName the CharacterSetMetric object to populate + * @param codePageName the name of the code page to use + * @param encoding name of the encoding in use + * @param typeface base14 font name + * @param eventProducer for handling AFP related events + * @return CharacterSet object + * @throws IOException if an I/O error occurs + */ + public CharacterSet build(String characterSetName, String codePageName, String encoding, + Typeface typeface, AFPEventProducer eventProducer) throws IOException { + return new FopCharacterSet(codePageName, encoding, characterSetName, typeface, + eventProducer); + } + private CharacterSet processFont(String characterSetName, String codePageName, String encoding, + CharacterSetType charsetType, ResourceAccessor accessor, AFPEventProducer eventProducer) + throws IOException { // check for cached version of the characterset String descriptor = characterSetName + "_" + encoding + "_" + codePageName; - CharacterSet characterSet = (CharacterSet)characterSetsCache.get(descriptor); + CharacterSet characterSet = (CharacterSet) characterSetsCache.get(descriptor); if (characterSet != null) { return characterSet; } // characterset not in the cache, so recreating - characterSet = new CharacterSet( - codePageName, encoding, characterSetName, accessor); + characterSet = new CharacterSet(codePageName, encoding, charsetType, characterSetName, + accessor, eventProducer); InputStream inputStream = null; @@ -215,16 +259,17 @@ public class CharacterSetBuilder { * information to map the unicode character id to the graphic * chracter global identifier. */ + Map<String, String> codePage; + synchronized (codePagesCache) { + codePage = codePagesCache.get(codePageName); - Map/*<String,String>*/ codePage - = (Map/*<String,String>*/)codePagesCache.get(codePageName); - - if (codePage == null) { - codePage = loadCodePage(codePageName, encoding, accessor); - codePagesCache.put(codePageName, codePage); + if (codePage == null) { + codePage = loadCodePage(codePageName, encoding, accessor, eventProducer); + codePagesCache.put(codePageName, codePage); + } } - inputStream = openInputStream(accessor, characterSetName); + inputStream = openInputStream(accessor, characterSetName, eventProducer); StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream); @@ -240,12 +285,12 @@ public class CharacterSetBuilder { CharacterSetOrientation[] characterSetOrientations = processFontOrientation(structuredFieldReader); - int metricNormalizationFactor; + double metricNormalizationFactor; if (fontControl.isRelative()) { metricNormalizationFactor = 1; } else { int dpi = fontControl.getDpi(); - metricNormalizationFactor = 1000 * 72000 + metricNormalizationFactor = 1000.0d * 72000.0d / fontDescriptor.getNominalFontSizeInMillipoints() / dpi; } @@ -268,23 +313,6 @@ public class CharacterSetBuilder { } characterSetsCache.put(descriptor, characterSet); return characterSet; - - } - - /** - * Load the font details and metrics into the CharacterSetMetric object, - * this will use the actual afp code page and character set files to load - * the object with the necessary metrics. - * - * @param characterSetName the CharacterSetMetric object to populate - * @param codePageName the name of the code page to use - * @param encoding name of the encoding in use - * @param typeface base14 font name - * @return CharacterSet object - */ - public CharacterSet build(String characterSetName, String codePageName, - String encoding, Typeface typeface) { - return new FopCharacterSet(codePageName, encoding, characterSetName, typeface); } /** @@ -296,18 +324,19 @@ public class CharacterSetBuilder { * @param encoding * the encoding to use for the character decoding * @param accessor the resource accessor + * @param eventProducer for handling AFP related events * @return a code page mapping (key: GCGID, value: Unicode character) * @throws IOException if an I/O exception of some sort has occurred. */ - protected Map/*<String,String>*/ loadCodePage(String codePage, String encoding, - ResourceAccessor accessor) throws IOException { + protected Map<String, String> loadCodePage(String codePage, String encoding, + ResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { // Create the HashMap to store code page information - Map/*<String,String>*/ codePages = new java.util.HashMap/*<String,String>*/(); + Map<String, String> codePages = new HashMap<String, String>(); InputStream inputStream = null; try { - inputStream = openInputStream(accessor, codePage.trim()); + inputStream = openInputStream(accessor, codePage.trim(), eventProducer); StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream); byte[] data = structuredFieldReader.getNext(CHARACTER_TABLE_SF); @@ -338,6 +367,8 @@ public class CharacterSetBuilder { position++; } } + } catch (FileNotFoundException e) { + eventProducer.codePageNotFound(this, e); } finally { closeInputStream(inputStream); } @@ -408,7 +439,7 @@ public class CharacterSetBuilder { int position = 0; byte[] fnoData = new byte[26]; - List orientations = new java.util.ArrayList(); + List<CharacterSetOrientation> orientations = new ArrayList<CharacterSetOrientation>(); // Read data, ignoring bytes 0 - 2 for (int index = 3; index < data.length; index++) { @@ -434,8 +465,7 @@ public class CharacterSetBuilder { } } - return (CharacterSetOrientation[]) orientations - .toArray(EMPTY_CSO_ARRAY); + return orientations.toArray(EMPTY_CSO_ARRAY); } /** @@ -508,8 +538,8 @@ public class CharacterSetBuilder { * @throws IOException if an I/O exception of some sort has occurred. */ protected void processFontIndex(StructuredFieldReader structuredFieldReader, - CharacterSetOrientation cso, Map/*<String,String>*/ codepage, - double metricNormalizationFactor) + CharacterSetOrientation cso, Map<String, String> codepage, + double metricNormalizationFactor) throws IOException { byte[] data = structuredFieldReader.getNext(FONT_INDEX_SF); @@ -539,7 +569,7 @@ public class CharacterSetBuilder { String gcgiString = new String(gcgid, AFPConstants.EBCIDIC_ENCODING); - String idx = (String) codepage.get(gcgiString); + String idx = codepage.get(gcgiString); if (idx != null) { @@ -652,20 +682,42 @@ public class CharacterSetBuilder { } } + private static final class SingleByteLoader extends CharacterSetBuilder { + + private static final SingleByteLoader INSTANCE = new SingleByteLoader(); + + private SingleByteLoader() { + super(); + } + + private static SingleByteLoader getInstance() { + return INSTANCE; + } + } + /** * Double-byte (CID Keyed font (Type 0)) implementation of AFPFontReader. */ - private static class DoubleByteLoader extends CharacterSetBuilder { + private static final class DoubleByteLoader extends CharacterSetBuilder { - protected Map/*<String,String>*/ loadCodePage(String codePage, String encoding, - ResourceAccessor accessor) throws IOException { + private static final DoubleByteLoader INSTANCE = new DoubleByteLoader(); + + private DoubleByteLoader() { + } + + static DoubleByteLoader getInstance() { + return INSTANCE; + } + + protected Map<String, String> loadCodePage(String codePage, String encoding, + ResourceAccessor accessor, AFPEventProducer eventProducer) throws IOException { // Create the HashMap to store code page information - Map/*<String,String>*/ codePages = new java.util.HashMap/*<String,String>*/(); + Map<String, String> codePages = new HashMap<String, String>(); InputStream inputStream = null; try { - inputStream = openInputStream(accessor, codePage.trim()); + inputStream = openInputStream(accessor, codePage.trim(), eventProducer); StructuredFieldReader structuredFieldReader = new StructuredFieldReader(inputStream); @@ -695,13 +747,13 @@ public class CharacterSetBuilder { AFPConstants.EBCIDIC_ENCODING); String charString = new String(charBytes, encoding); codePages.put(gcgiString, charString); - - } - else { + } else { position++; } } } + } catch (FileNotFoundException e) { + eventProducer.codePageNotFound(this, e); } finally { closeInputStream(inputStream); } diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java b/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java index b7246f35b..7ac8ae96b 100644 --- a/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java +++ b/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java @@ -107,7 +107,7 @@ public class CharacterSetOrientation { * a character rotation other than 0, ascender height loses its * meaning when the character is lying on its side or is upside down * with respect to normal viewing orientation. For the general case, - * Ascender Height is the character�s most positive y-axis value. + * Ascender Height is the character's most positive y-axis value. * For bounded character boxes, for a given character having an * ascender, ascender height and baseline offset are equal. * @return the ascender value in millipoints diff --git a/src/java/org/apache/fop/afp/fonts/CharacterSetType.java b/src/java/org/apache/fop/afp/fonts/CharacterSetType.java new file mode 100644 index 000000000..8eaaa089b --- /dev/null +++ b/src/java/org/apache/fop/afp/fonts/CharacterSetType.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.fonts; + +/** + * An enumeration of AFP characterset types. + */ +public enum CharacterSetType { + /** Double byte character sets; these do NOT have the shift-in;shift-out operators */ + DOUBLE_BYTE, + /** Double byte character sets; these can have the shift-in;shift-out operators */ + DOUBLE_BYTE_LINE_DATA, + SINGLE_BYTE; +} diff --git a/src/java/org/apache/fop/afp/fonts/CharactersetEncoder.java b/src/java/org/apache/fop/afp/fonts/CharactersetEncoder.java new file mode 100644 index 000000000..f101bdab4 --- /dev/null +++ b/src/java/org/apache/fop/afp/fonts/CharactersetEncoder.java @@ -0,0 +1,220 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.fonts; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CodingErrorAction; + +/** + * An abstraction that wraps the encoding mechanism for encoding a Unicode character sequence into a + * specified format. + */ +public abstract class CharactersetEncoder { + + private final CharsetEncoder encoder; + + private CharactersetEncoder(String encoding) { + this.encoder = Charset.forName(encoding).newEncoder(); + this.encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); + } + + /** + * Tells whether or not this encoder can encode the given character. + * + * @param c the character + * @return true if, and only if, this encoder can encode the given character + * @throws IllegalStateException - If an encoding operation is already in progress + */ + final boolean canEncode(char c) { + return encoder.canEncode(c); + } + + /** + * Encodes a character sequence to a byte array. + * + * @param chars the character sequence + * @return the encoded character sequence + * @throws CharacterCodingException if the encoding operation fails + */ + final EncodedChars encode(CharSequence chars) throws CharacterCodingException { + ByteBuffer bb; + // encode method is not thread safe + synchronized (encoder) { + bb = encoder.encode(CharBuffer.wrap(chars)); + } + if (bb.hasArray()) { + return getEncodedChars(bb.array(), bb.limit()); + } else { + bb.rewind(); + byte[] bytes = new byte[bb.remaining()]; + bb.get(bytes); + return getEncodedChars(bytes, bytes.length); + } + } + + abstract EncodedChars getEncodedChars(byte[] byteArray, int length); + + /** + * Encodes <code>chars</code> into a format specified by <code>encoding</code>. + * + * @param chars the character sequence + * @param encoding the encoding type + * @return encoded data + * @throws CharacterCodingException if encoding fails + */ + public static EncodedChars encodeSBCS(CharSequence chars, String encoding) + throws CharacterCodingException { + CharactersetEncoder encoder = newInstance(encoding, CharacterSetType.SINGLE_BYTE); + return encoder.encode(chars); + } + + /** + * The EBCDIC double byte encoder is used for encoding IBM format DBCS (double byte character + * sets) with an EBCDIC code-page. Given a double byte EBCDIC code page and a Unicode character + * sequence it will return its EBCDIC code-point, however, the "Shift In - Shift Out" operators + * are removed from the sequence of bytes. These are only used in Line Data. + */ + private static final class EbcdicDoubleByteLineDataEncoder extends CharactersetEncoder { + private EbcdicDoubleByteLineDataEncoder(String encoding) { + super(encoding); + } + @Override + EncodedChars getEncodedChars(byte[] byteArray, int length) { + if (byteArray[0] == 0x0E && byteArray[length - 1] == 0x0F) { + return new EncodedChars(byteArray, 1, length - 2, true); + } + return new EncodedChars(byteArray, true); + } + } + + /** + * The default encoder is used for encoding IBM format SBCS (single byte character sets), this + * the primary format for most Latin character sets. This can also be used for Unicode double- + * byte character sets (DBCS). + */ + private static final class DefaultEncoder extends CharactersetEncoder { + private final boolean isDBCS; + + private DefaultEncoder(String encoding, boolean isDBCS) { + super(encoding); + this.isDBCS = isDBCS; + } + + @Override + EncodedChars getEncodedChars(byte[] byteArray, int length) { + return new EncodedChars(byteArray, isDBCS); + } + } + + /** + * Returns an new instance of a {@link CharactersetEncoder}. + * + * @param encoding the encoding for the underlying character encoder + * @param isEbcdicDBCS whether or not this wraps a double-byte EBCDIC code page. + * @return the CharactersetEncoder + */ + static CharactersetEncoder newInstance(String encoding, CharacterSetType charsetType) { + switch (charsetType) { + case DOUBLE_BYTE_LINE_DATA: + return new EbcdicDoubleByteLineDataEncoder(encoding); + case DOUBLE_BYTE: + return new DefaultEncoder(encoding, true); + default: + return new DefaultEncoder(encoding, false); + } + } + + /** + * A container for encoded character bytes + */ + // CSOFF: FinalClass - disabling "final" modifier so that this class can be mocked + public static class EncodedChars { + + private final byte[] bytes; + private final int offset; + private final int length; + private final boolean isDBCS; + + private EncodedChars(byte[] bytes, int offset, int length, boolean isDBCS) { + if (offset < 0 || length < 0 || offset + length > bytes.length) { + throw new IllegalArgumentException(); + } + this.bytes = bytes; + this.offset = offset; + this.length = length; + this.isDBCS = isDBCS; + } + + private EncodedChars(byte[] bytes, boolean isDBCS) { + this(bytes, 0, bytes.length, isDBCS); + } + + /** + * write <code>length</code> bytes from <code>offset</code> to the output stream + * + * @param out output to write the bytes to + * @param offset the offset where to write + * @param length the length to write + * @throws IOException if an I/O error occurs + */ + public void writeTo(OutputStream out, int offset, int length) throws IOException { + if (offset < 0 || length < 0 || offset + length > bytes.length) { + throw new IllegalArgumentException(); + } + out.write(bytes, this.offset + offset, length); + } + + /** + * The number of containing bytes. + * + * @return the length + */ + public int getLength() { + return length; + } + + /** + * Indicates whether or not the EncodedChars object wraps double byte characters. + * + * @return true if the wrapped characters are double byte (DBCSs) + */ + public boolean isDBCS() { + return isDBCS; + } + + /** + * The bytes + * + * @return the bytes + */ + public byte[] getBytes() { + // return copy just in case + byte[] copy = new byte[bytes.length]; + System.arraycopy(bytes, 0, copy, 0, bytes.length); + return copy; + } + } +} diff --git a/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java b/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java index 716ca538f..f83c38621 100644 --- a/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java +++ b/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java @@ -19,6 +19,7 @@ package org.apache.fop.afp.fonts; +import org.apache.fop.afp.AFPEventProducer; import org.apache.fop.afp.util.ResourceAccessor; import org.apache.fop.fonts.Typeface; @@ -37,14 +38,12 @@ public class FopCharacterSet extends CharacterSet { * @param encoding the encoding of the font * @param name the character set name * @param charSet the fop character set + * @param eventProducer for handling AFP related events */ - public FopCharacterSet( - String codePage, - String encoding, - String name, - Typeface charSet) { - - super(codePage, encoding, name, (ResourceAccessor)null); + public FopCharacterSet(String codePage, String encoding, String name, Typeface charSet, + AFPEventProducer eventProducer) { + super(codePage, encoding, CharacterSetType.SINGLE_BYTE, name, (ResourceAccessor) null, + eventProducer); this.charSet = charSet; } @@ -55,7 +54,7 @@ public class FopCharacterSet extends CharacterSet { * a character rotation other than 0, ascender height loses its * meaning when the character is lying on its side or is upside down * with respect to normal viewing orientation. For the general case, - * Ascender Height is the character�s most positive y-axis value. + * Ascender Height is the character's most positive y-axis value. * For bounded character boxes, for a given character having an * ascender, ascender height and baseline offset are equal. * @return the ascender value in millipoints @@ -134,5 +133,4 @@ public class FopCharacterSet extends CharacterSet { public char mapChar(char c) { return charSet.mapChar(c); } - -}
\ No newline at end of file +} diff --git a/src/java/org/apache/fop/afp/fonts/OutlineFont.java b/src/java/org/apache/fop/afp/fonts/OutlineFont.java index d4fd0624d..01c605146 100644 --- a/src/java/org/apache/fop/afp/fonts/OutlineFont.java +++ b/src/java/org/apache/fop/afp/fonts/OutlineFont.java @@ -33,4 +33,4 @@ public class OutlineFont extends AbstractOutlineFont { super(name, charSet); } -}
\ No newline at end of file +} diff --git a/src/java/org/apache/fop/afp/fonts/RasterFont.java b/src/java/org/apache/fop/afp/fonts/RasterFont.java index 2a4d5d270..30704b2b0 100644 --- a/src/java/org/apache/fop/afp/fonts/RasterFont.java +++ b/src/java/org/apache/fop/afp/fonts/RasterFont.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; +import java.util.TreeMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -39,9 +40,8 @@ public class RasterFont extends AFPFont { /** Static logging instance */ protected static final Log LOG = LogFactory.getLog("org.apache.fop.afp.fonts"); - private final SortedMap/*<Integer,CharacterSet>*/ charSets - = new java.util.TreeMap/*<Integer,CharacterSet>*/(); - private Map/*<Integer,CharacterSet>*/ substitutionCharSets; + private final SortedMap<Integer, CharacterSet> charSets = new TreeMap<Integer, CharacterSet>(); + private Map<Integer, CharacterSet> substitutionCharSets; private CharacterSet charSet = null; @@ -70,14 +70,14 @@ public class RasterFont extends AFPFont { /** * Get the character set metrics for the specified point size. * - * @param size the point size (in mpt) + * @param sizeInMpt the point size (in mpt) * @return the character set metrics */ - public CharacterSet getCharacterSet(int size) { + public CharacterSet getCharacterSet(int sizeInMpt) { - //TODO: replace with Integer.valueOf() once we switch to Java 5 - Integer requestedSize = new Integer(size); + Integer requestedSize = Integer.valueOf(sizeInMpt); CharacterSet csm = (CharacterSet) charSets.get(requestedSize); + double sizeInPt = sizeInMpt / 1000.0; if (csm != null) { return csm; @@ -92,8 +92,8 @@ public class RasterFont extends AFPFont { // No match or substitution found, but there exist entries // for other sizes // Get char set with nearest, smallest font size - SortedMap smallerSizes = charSets.headMap(requestedSize); - SortedMap largerSizes = charSets.tailMap(requestedSize); + SortedMap<Integer, CharacterSet> smallerSizes = charSets.headMap(requestedSize); + SortedMap<Integer, CharacterSet> largerSizes = charSets.tailMap(requestedSize); int smallerSize = smallerSizes.isEmpty() ? 0 : ((Integer)smallerSizes.lastKey()).intValue(); int largerSize = largerSizes.isEmpty() ? Integer.MAX_VALUE @@ -101,10 +101,10 @@ public class RasterFont extends AFPFont { Integer fontSize; if (!smallerSizes.isEmpty() - && (size - smallerSize) <= (largerSize - size)) { - fontSize = new Integer(smallerSize); + && (sizeInMpt - smallerSize) <= (largerSize - sizeInMpt)) { + fontSize = Integer.valueOf(smallerSize); } else { - fontSize = new Integer(largerSize); + fontSize = Integer.valueOf(largerSize); } csm = (CharacterSet) charSets.get(fontSize); @@ -112,19 +112,21 @@ public class RasterFont extends AFPFont { // Add the substitute mapping, so subsequent calls will // find it immediately if (substitutionCharSets == null) { - substitutionCharSets = new HashMap(); + substitutionCharSets = new HashMap<Integer, CharacterSet>(); } substitutionCharSets.put(requestedSize, csm); - String msg = "No " + (size / 1000f) + "pt font " + getFontName() - + " found, substituted with " + fontSize.intValue() / 1000f + "pt font"; - LOG.warn(msg); + // do not output the warning if the font size is closer to an integer less than 0.1 + if (!(Math.abs(fontSize.intValue() / 1000.0 - sizeInPt) < 0.1)) { + String msg = "No " + sizeInPt + "pt font " + getFontName() + + " found, substituted with " + fontSize.intValue() / 1000f + "pt font"; + LOG.warn(msg); + } } } if (csm == null) { // Still no match -> error - String msg = "No font found for font " + getFontName() - + " with point size " + size / 1000f; + String msg = "No font found for font " + getFontName() + " with point size " + sizeInPt; LOG.error(msg); throw new FontRuntimeException(msg); } @@ -138,9 +140,9 @@ public class RasterFont extends AFPFont { * @return the first character in this font. */ public int getFirstChar() { - Iterator it = charSets.values().iterator(); + Iterator<CharacterSet> it = charSets.values().iterator(); if (it.hasNext()) { - CharacterSet csm = (CharacterSet) it.next(); + CharacterSet csm = it.next(); return csm.getFirstChar(); } else { String msg = "getFirstChar() - No character set found for font:" + getFontName(); @@ -155,9 +157,9 @@ public class RasterFont extends AFPFont { */ public int getLastChar() { - Iterator it = charSets.values().iterator(); + Iterator<CharacterSet> it = charSets.values().iterator(); if (it.hasNext()) { - CharacterSet csm = (CharacterSet) it.next(); + CharacterSet csm = it.next(); return csm.getLastChar(); } else { String msg = "getLastChar() - No character set found for font:" + getFontName(); |