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