aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/java/org/apache/fop/fonts/CIDFull.java13
-rw-r--r--src/java/org/apache/fop/fonts/CIDSet.java14
-rw-r--r--src/java/org/apache/fop/fonts/CIDSubset.java18
-rw-r--r--src/java/org/apache/fop/fonts/CustomFont.java12
-rw-r--r--src/java/org/apache/fop/fonts/MultiByteFont.java18
-rw-r--r--src/java/org/apache/fop/fonts/SingleByteFont.java12
-rw-r--r--src/java/org/apache/fop/fonts/truetype/GlyfTable.java6
-rw-r--r--src/java/org/apache/fop/fonts/truetype/OFDirTabEntry.java4
-rw-r--r--src/java/org/apache/fop/fonts/truetype/OpenFont.java27
-rw-r--r--src/java/org/apache/fop/fonts/truetype/TTFFile.java8
-rw-r--r--src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java3
-rw-r--r--src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java4
-rw-r--r--src/java/org/apache/fop/render/pcl/HardcodedFonts.java2
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLEventProducer.java9
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLEventProducer.xml1
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLGenerator.java9
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLPainter.java193
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java1
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLRenderingUtil.java15
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtil.java125
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/PCLCharacterDefinition.java147
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/PCLCharacterWriter.java42
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/PCLFontReader.java113
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactory.java65
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/PCLFontSegment.java62
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/PCLSoftFont.java160
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java278
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/PCLSymbolSet.java200
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriter.java154
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java731
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFOS2FontTable.java77
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFPCLTFontTable.java115
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFPOSTFontTable.java51
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFTable.java47
-rw-r--r--src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFTableFactory.java49
35 files changed, 2738 insertions, 47 deletions
diff --git a/src/java/org/apache/fop/fonts/CIDFull.java b/src/java/org/apache/fop/fonts/CIDFull.java
index ee062a2bb..1130459b7 100644
--- a/src/java/org/apache/fop/fonts/CIDFull.java
+++ b/src/java/org/apache/fop/fonts/CIDFull.java
@@ -57,6 +57,18 @@ public class CIDFull implements CIDSet {
}
/** {@inheritDoc} */
+ @Override
+ public char getUnicodeFromGID(int glyphIndex) {
+ return ' ';
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getGIDFromChar(char ch) {
+ return ch;
+ }
+
+ /** {@inheritDoc} */
public char getUnicode(int index) {
initGlyphIndices();
if (glyphIndices.get(index)) {
@@ -109,5 +121,4 @@ public class CIDFull implements CIDSet {
public int[] getWidths() {
return font.getWidths();
}
-
}
diff --git a/src/java/org/apache/fop/fonts/CIDSet.java b/src/java/org/apache/fop/fonts/CIDSet.java
index 7530ea6e7..acfc705c8 100644
--- a/src/java/org/apache/fop/fonts/CIDSet.java
+++ b/src/java/org/apache/fop/fonts/CIDSet.java
@@ -44,6 +44,20 @@ public interface CIDSet {
char getUnicode(int index);
/**
+ * Gets the unicode character from the original font glyph index
+ * @param glyphIndex The original glyph index of the character in the font
+ * @return The character represented by the passed GID
+ */
+ char getUnicodeFromGID(int glyphIndex);
+
+ /**
+ * Returns the glyph index from the original font from a character
+ * @param ch The character
+ * @return The glyph index in the original font.
+ */
+ int getGIDFromChar(char ch);
+
+ /**
* Maps a character to a character selector for a font subset. If the character isn't in the
* subset, yet, it is added and a new character selector returned. Otherwise, the already
* allocated character selector is returned from the existing map/subset.
diff --git a/src/java/org/apache/fop/fonts/CIDSubset.java b/src/java/org/apache/fop/fonts/CIDSubset.java
index f442c13ed..01b8495f8 100644
--- a/src/java/org/apache/fop/fonts/CIDSubset.java
+++ b/src/java/org/apache/fop/fonts/CIDSubset.java
@@ -53,6 +53,12 @@ public class CIDSubset implements CIDSet {
*/
private Map<Integer, Character> usedCharsIndex = new HashMap<Integer, Character>();
+ /**
+ * A map between the original character and it's GID in the original font.
+ */
+ private Map<Character, Integer> charToGIDs = new HashMap<Character, Integer>();
+
+
private final MultiByteFont font;
public CIDSubset(MultiByteFont mbf) {
@@ -93,6 +99,7 @@ public class CIDSubset implements CIDSet {
usedGlyphs.put(glyphIndex, selector);
usedGlyphsIndex.put(selector, glyphIndex);
usedCharsIndex.put(selector, unicode);
+ charToGIDs.put(unicode, glyphIndex);
usedGlyphsCount++;
return selector;
} else {
@@ -106,6 +113,17 @@ public class CIDSubset implements CIDSet {
}
/** {@inheritDoc} */
+ public char getUnicodeFromGID(int glyphIndex) {
+ int selector = usedGlyphs.get(glyphIndex);
+ return usedCharsIndex.get(selector);
+ }
+
+ /** {@inheritDoc} */
+ public int getGIDFromChar(char ch) {
+ return charToGIDs.get(ch);
+ }
+
+ /** {@inheritDoc} */
public char[] getChars() {
char[] charArray = new char[usedGlyphsCount];
for (int i = 0; i < usedGlyphsCount; i++) {
diff --git a/src/java/org/apache/fop/fonts/CustomFont.java b/src/java/org/apache/fop/fonts/CustomFont.java
index fffb429ed..6f325d96d 100644
--- a/src/java/org/apache/fop/fonts/CustomFont.java
+++ b/src/java/org/apache/fop/fonts/CustomFont.java
@@ -568,4 +568,16 @@ public abstract class CustomFont extends Typeface
this.strikeoutThickness = strikeoutThickness;
}
+ /**
+ * Returns a Map of used Glyphs.
+ * @return Map Map of used Glyphs
+ */
+ public abstract Map<Integer, Integer> getUsedGlyphs();
+
+ /**
+ * Returns the character from it's original glyph index in the font
+ * @param glyphIndex The original index of the character
+ * @return The character
+ */
+ public abstract char getUnicodeFromGID(int glyphIndex);
}
diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java
index 296c86de2..22b5116bb 100644
--- a/src/java/org/apache/fop/fonts/MultiByteFont.java
+++ b/src/java/org/apache/fop/fonts/MultiByteFont.java
@@ -426,6 +426,24 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl
}
/**
+ * Returns the character from it's original glyph index in the font
+ * @param glyphIndex The original index of the character
+ * @return The character
+ */
+ public char getUnicodeFromGID(int glyphIndex) {
+ return cidSet.getUnicodeFromGID(glyphIndex);
+ }
+
+ /**
+ * Gets the original glyph index in the font from a character.
+ * @param ch The character
+ * @return The glyph index in the font
+ */
+ public int getGIDFromChar(char ch) {
+ return cidSet.getGIDFromChar(ch);
+ }
+
+ /**
* Establishes the glyph definition table.
* @param gdef the glyph definition table to be used by this font
*/
diff --git a/src/java/org/apache/fop/fonts/SingleByteFont.java b/src/java/org/apache/fop/fonts/SingleByteFont.java
index e12da81cc..e3037a524 100644
--- a/src/java/org/apache/fop/fonts/SingleByteFont.java
+++ b/src/java/org/apache/fop/fonts/SingleByteFont.java
@@ -63,6 +63,7 @@ public class SingleByteFont extends CustomFont {
private LinkedHashMap<Integer, String> usedGlyphNames;
private Map<Integer, Integer> usedGlyphs;
private Map<Integer, Character> usedCharsIndex;
+ private Map<Character, Integer> charGIDMappings;
public SingleByteFont(InternalResourceResolver resourceResolver) {
super(resourceResolver);
@@ -76,6 +77,7 @@ public class SingleByteFont extends CustomFont {
usedGlyphNames = new LinkedHashMap<Integer, String>();
usedGlyphs = new HashMap<Integer, Integer>();
usedCharsIndex = new HashMap<Integer, Character>();
+ charGIDMappings = new HashMap<Character, Integer>();
// The zeroth value is reserved for .notdef
usedGlyphs.put(0, 0);
@@ -234,6 +236,7 @@ public class SingleByteFont extends CustomFont {
int selector = usedGlyphsCount;
usedGlyphs.put(glyphIndex, selector);
usedCharsIndex.put(selector, unicode);
+ charGIDMappings.put(unicode, glyphIndex);
usedGlyphsCount++;
return selector;
} else {
@@ -519,6 +522,15 @@ public class SingleByteFont extends CustomFont {
return getUnicode(selector);
}
+ public int getGIDFromChar(char ch) {
+ return charGIDMappings.get(ch);
+ }
+
+ public char getUnicodeFromGID(int glyphIndex) {
+ int selector = usedGlyphs.get(glyphIndex);
+ return usedCharsIndex.get(selector);
+ }
+
public void mapUsedGlyphName(int gid, String value) {
usedGlyphNames.put(gid, value);
}
diff --git a/src/java/org/apache/fop/fonts/truetype/GlyfTable.java b/src/java/org/apache/fop/fonts/truetype/GlyfTable.java
index 1233a586e..6ad479a0e 100644
--- a/src/java/org/apache/fop/fonts/truetype/GlyfTable.java
+++ b/src/java/org/apache/fop/fonts/truetype/GlyfTable.java
@@ -47,7 +47,7 @@ public class GlyfTable {
/** All the glyphs that are composed, but do not appear in the subset. */
protected Set<Integer> composedGlyphs = new TreeSet<Integer>();
- protected GlyfTable(FontFileReader in, OFMtxEntry[] metrics, OFDirTabEntry dirTableEntry,
+ public GlyfTable(FontFileReader in, OFMtxEntry[] metrics, OFDirTabEntry dirTableEntry,
Map<Integer, Integer> glyphs) throws IOException {
mtxTab = metrics;
tableOffset = dirTableEntry.getOffset();
@@ -202,7 +202,7 @@ public class GlyfTable {
} while (GlyfFlags.hasMoreComposites(flags));
}
- private boolean isComposite(int indexInOriginal) throws IOException {
+ public boolean isComposite(int indexInOriginal) throws IOException {
int numberOfContours = in.readTTFShort(tableOffset + mtxTab[indexInOriginal].getOffset());
return numberOfContours < 0;
}
@@ -215,7 +215,7 @@ public class GlyfTable {
* @return the set of glyph indices this glyph composes
* @throws IOException an I/O error
*/
- private Set<Integer> retrieveComposedGlyphs(int indexInOriginal)
+ public Set<Integer> retrieveComposedGlyphs(int indexInOriginal)
throws IOException {
Set<Integer> composedGlyphs = new HashSet<Integer>();
long offset = tableOffset + mtxTab[indexInOriginal].getOffset() + 10;
diff --git a/src/java/org/apache/fop/fonts/truetype/OFDirTabEntry.java b/src/java/org/apache/fop/fonts/truetype/OFDirTabEntry.java
index 0e468eb7b..34e7fba14 100644
--- a/src/java/org/apache/fop/fonts/truetype/OFDirTabEntry.java
+++ b/src/java/org/apache/fop/fonts/truetype/OFDirTabEntry.java
@@ -30,7 +30,7 @@ import java.util.Arrays;
public class OFDirTabEntry {
private byte[] tag = new byte[4];
- private int checksum;
+ private long checksum;
private long offset;
private long length;
@@ -74,7 +74,7 @@ public class OFDirTabEntry {
* Returns the checksum.
* @return int
*/
- public int getChecksum() {
+ public long getChecksum() {
return checksum;
}
diff --git a/src/java/org/apache/fop/fonts/truetype/OpenFont.java b/src/java/org/apache/fop/fonts/truetype/OpenFont.java
index b9dcfb936..e94f31bb1 100644
--- a/src/java/org/apache/fop/fonts/truetype/OpenFont.java
+++ b/src/java/org/apache/fop/fonts/truetype/OpenFont.java
@@ -355,7 +355,7 @@ public abstract class OpenFont {
long offset) throws IOException {
OFDirTabEntry dt = dirTabs.get(tableName);
if (dt == null) {
- log.error("Dirtab " + tableName.getName() + " not found.");
+ log.info("Dirtab " + tableName.getName() + " not found.");
return false;
} else {
in.seekSet(dt.getOffset() + offset);
@@ -966,6 +966,15 @@ public abstract class OpenFont {
}
/**
+ * Returns the original bounding box values from the HEAD table
+ * @return An array of bounding box values
+ */
+ public int[] getBBoxRaw() {
+ int[] bbox = {fontBBox1, fontBBox2, fontBBox3, fontBBox4};
+ return bbox;
+ }
+
+ /**
* Returns the LowerCaseAscent attribute of the font.
* @return int The LowerCaseAscent
*/
@@ -1048,6 +1057,18 @@ public abstract class OpenFont {
}
/**
+ * Returns the width of a given character in raw units
+ * @param idx Index of the character
+ * @return int Width in it's raw form stored in the font
+ */
+ public int getCharWidthRaw(int idx) {
+ if (ansiWidth != null) {
+ return ansiWidth[idx];
+ }
+ return -1;
+ }
+
+ /**
* Returns the kerning table.
* @return Map The kerning table
*/
@@ -1978,4 +1999,8 @@ public abstract class OpenFont {
IOUtils.closeQuietly(stream);
}
}
+
+ public String getCopyrightNotice() {
+ return notice;
+ }
}
diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java
index 52df45ffb..4b0e3d628 100644
--- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java
+++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java
@@ -188,6 +188,14 @@ public class TTFFile extends OpenFont {
: (fontFile.readTTFUShort() << 1));
}
+ /**
+ * Gets the last location of the glyf table
+ * @return The last location as a long
+ */
+ public long getLastGlyfLocation() {
+ return lastLoca;
+ }
+
@Override
protected void initializeFont(FontFileReader in) throws IOException {
fontFile = in;
diff --git a/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java b/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java
index b9b7539fc..c6f02506e 100644
--- a/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java
+++ b/src/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java
@@ -83,7 +83,8 @@ public class ConfiguredFontCollection implements FontCollection {
font = new CustomFontMetricsMapper(fontMetrics, fontSource);
} else {
FontUris fontUris = new FontUris(fontURI, null);
- CustomFont fontMetrics = FontLoader.loadFont(fontUris, null, true,
+ CustomFont fontMetrics = FontLoader.loadFont(fontUris,
+ configFontInfo.getSubFontName(), true,
configFontInfo.getEmbeddingMode(), configFontInfo.getEncodingMode(),
configFontInfo.getKerning(), configFontInfo.getAdvanced(), resourceResolver);
font = new CustomFontMetricsMapper(fontMetrics);
diff --git a/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java b/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java
index 62283915f..c7f5da116 100644
--- a/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java
+++ b/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java
@@ -289,4 +289,8 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp
}
}
+ public Typeface getRealFont() {
+ return typeface;
+ }
+
}
diff --git a/src/java/org/apache/fop/render/pcl/HardcodedFonts.java b/src/java/org/apache/fop/render/pcl/HardcodedFonts.java
index 185e1ece5..82e622098 100644
--- a/src/java/org/apache/fop/render/pcl/HardcodedFonts.java
+++ b/src/java/org/apache/fop/render/pcl/HardcodedFonts.java
@@ -55,7 +55,7 @@ final class HardcodedFonts {
return selectFont(gen, name, size);
}
- private static boolean selectFont(PCLGenerator gen, String name, int size) throws IOException {
+ protected static boolean selectFont(PCLGenerator gen, String name, int size) throws IOException {
int fontcode = 0;
if (name.length() > 1 && name.charAt(0) == 'F') {
try {
diff --git a/src/java/org/apache/fop/render/pcl/PCLEventProducer.java b/src/java/org/apache/fop/render/pcl/PCLEventProducer.java
index 7d2ed252e..3a8a1de55 100644
--- a/src/java/org/apache/fop/render/pcl/PCLEventProducer.java
+++ b/src/java/org/apache/fop/render/pcl/PCLEventProducer.java
@@ -53,4 +53,13 @@ public interface PCLEventProducer extends EventProducer {
*/
void paperTypeUnavailable(Object source, long pageWidth, long pageHeight, String fallbackPaper);
+ /**
+ * The font type is not supported for PCL output.
+ * @param source The event source
+ * @param fontName The name of the font not supported
+ * @param supportedTypes The types of fonts currently supported
+ * @event.severity ERROR
+ */
+ void fontTypeNotSupported(Object source, String fontName, String supportedTypes);
+
}
diff --git a/src/java/org/apache/fop/render/pcl/PCLEventProducer.xml b/src/java/org/apache/fop/render/pcl/PCLEventProducer.xml
index 5d5785a4c..463fcb16a 100644
--- a/src/java/org/apache/fop/render/pcl/PCLEventProducer.xml
+++ b/src/java/org/apache/fop/render/pcl/PCLEventProducer.xml
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<catalogue xml:lang="en">
<message key="paperTypeUnavailable">Paper type ({pageWidth} x {pageHeight} mpt) could not be determined. Falling back to: {fallbackPaper}</message>
+ <message key="fontTypeNotSupported">The font '{fontName}' is not supported. PCL output currently only supports {supportedTypes}</message>
</catalogue>
diff --git a/src/java/org/apache/fop/render/pcl/PCLGenerator.java b/src/java/org/apache/fop/render/pcl/PCLGenerator.java
index 05a0fc666..67d37fbb5 100644
--- a/src/java/org/apache/fop/render/pcl/PCLGenerator.java
+++ b/src/java/org/apache/fop/render/pcl/PCLGenerator.java
@@ -141,6 +141,15 @@ public class PCLGenerator {
}
/**
+ * Writes raw bytes to the output stream
+ * @param bytes The bytes
+ * @throws IOException In case of an I/O error
+ */
+ public void writeBytes(byte[] bytes) throws IOException {
+ out.write(bytes);
+ }
+
+ /**
* Formats a double value with two decimal positions for PCL output.
*
* @param value value to format
diff --git a/src/java/org/apache/fop/render/pcl/PCLPainter.java b/src/java/org/apache/fop/render/pcl/PCLPainter.java
index 9f7de4930..69465a7fd 100644
--- a/src/java/org/apache/fop/render/pcl/PCLPainter.java
+++ b/src/java/org/apache/fop/render/pcl/PCLPainter.java
@@ -28,7 +28,9 @@ import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.util.List;
import java.util.Map;
import java.util.Stack;
@@ -42,16 +44,27 @@ import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
import org.apache.xmlgraphics.java2d.GraphicContext;
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
+import org.apache.fop.fonts.CIDFontType;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontTriplet;
+import org.apache.fop.fonts.FontType;
+import org.apache.fop.fonts.LazyFont;
+import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.Typeface;
import org.apache.fop.render.ImageHandlerUtil;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.intermediate.AbstractIFPainter;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFState;
import org.apache.fop.render.intermediate.IFUtil;
+import org.apache.fop.render.java2d.CustomFontMetricsMapper;
import org.apache.fop.render.java2d.FontMetricsMapper;
import org.apache.fop.render.java2d.Java2DPainter;
+import org.apache.fop.render.pcl.fonts.PCLCharacterWriter;
+import org.apache.fop.render.pcl.fonts.PCLSoftFont;
+import org.apache.fop.render.pcl.fonts.PCLSoftFontManager;
+import org.apache.fop.render.pcl.fonts.PCLSoftFontManager.PCLTextSegment;
+import org.apache.fop.render.pcl.fonts.truetype.PCLTTFCharacterWriter;
import org.apache.fop.traits.BorderProps;
import org.apache.fop.traits.RuleStyle;
import org.apache.fop.util.CharUtilities;
@@ -73,6 +86,8 @@ public class PCLPainter extends AbstractIFPainter<PCLDocumentHandler> implements
private Stack<GraphicContext> graphicContextStack = new Stack<GraphicContext>();
private GraphicContext graphicContext = new GraphicContext();
+ private PCLSoftFontManager sfManager = new PCLSoftFontManager();
+
/**
* Main constructor.
* @param parent the parent document handler
@@ -315,16 +330,51 @@ public class PCLPainter extends AbstractIFPainter<PCLDocumentHandler> implements
//TODO Ignored: state.getFontVariant()
//TODO Opportunity for font caching if font state is more heavily used
String fontKey = getFontKey(triplet);
- boolean pclFont = getPCLUtil().isAllTextAsBitmaps() ? false
- : HardcodedFonts.setFont(gen, fontKey, state.getFontSize(), text);
+ Typeface tf = getTypeface(fontKey);
+ boolean drawAsBitmaps = getPCLUtil().isAllTextAsBitmaps();
+ boolean pclFont = HardcodedFonts.setFont(gen, fontKey, state.getFontSize(), text);
if (pclFont) {
drawTextNative(x, y, letterSpacing, wordSpacing, dp, text, triplet);
} else {
- drawTextAsBitmap(x, y, letterSpacing, wordSpacing, dp, text, triplet);
- if (DEBUG) {
- state.setTextColor(Color.GRAY);
- HardcodedFonts.setFont(gen, "F1", state.getFontSize(), text);
- drawTextNative(x, y, letterSpacing, wordSpacing, dp, text, triplet);
+ // TrueType conversion to a soft font (PCL 5 Technical Reference - Chapter 11)
+ if (!drawAsBitmaps && isTrueType(tf)) {
+ boolean madeSF = false;
+ if (sfManager.getSoftFont(tf, text) == null) {
+ madeSF = true;
+ ByteArrayOutputStream baos = sfManager.makeSoftFont(tf);
+ if (baos != null) {
+ gen.writeBytes(baos.toByteArray());
+ }
+ }
+ String formattedSize = gen.formatDouble2(state.getFontSize() / 1000.0);
+ gen.writeCommand(String.format("(s%sV", formattedSize));
+ List<PCLTextSegment> textSegments = sfManager.getTextSegments(text, tf);
+ if (textSegments.isEmpty()) {
+ textSegments.add(new PCLTextSegment(sfManager.getSoftFontID(tf), text));
+ }
+ boolean first = true;
+ for (PCLTextSegment textSegment : textSegments) {
+ gen.writeCommand(String.format("(%dX", textSegment.getFontID()));
+ PCLSoftFont softFont = sfManager.getSoftFontFromID(textSegment.getFontID());
+ PCLCharacterWriter charWriter = new PCLTTFCharacterWriter(softFont);
+ gen.writeBytes(sfManager.assignFontID(textSegment.getFontID()));
+ gen.writeBytes(charWriter.writeCharacterDefinitions(textSegment.getText()));
+ if (first) {
+ drawTextUsingSoftFont(x, y, letterSpacing, wordSpacing, dp,
+ textSegment.getText(), triplet, softFont);
+ first = false;
+ } else {
+ drawTextUsingSoftFont(-1, -1, letterSpacing, wordSpacing, dp,
+ textSegment.getText(), triplet, softFont);
+ }
+ }
+ } else {
+ drawTextAsBitmap(x, y, letterSpacing, wordSpacing, dp, text, triplet);
+ if (DEBUG) {
+ state.setTextColor(Color.GRAY);
+ HardcodedFonts.setFont(gen, "F1", state.getFontSize(), text);
+ drawTextNative(x, y, letterSpacing, wordSpacing, dp, text, triplet);
+ }
}
}
} catch (IOException ioe) {
@@ -332,6 +382,29 @@ public class PCLPainter extends AbstractIFPainter<PCLDocumentHandler> implements
}
}
+ private boolean isTrueType(Typeface tf) {
+ if (tf.getFontType().equals(FontType.TRUETYPE)) {
+ return true;
+ } else if (tf instanceof CustomFontMetricsMapper) {
+ Typeface realFont = ((CustomFontMetricsMapper) tf).getRealFont();
+ if (realFont instanceof MultiByteFont) {
+ return ((MultiByteFont) realFont).getCIDType().equals(CIDFontType.CIDTYPE2);
+ }
+ }
+ return false;
+ }
+
+ private Typeface getTypeface(String fontName) {
+ if (fontName == null) {
+ throw new NullPointerException("fontName must not be null");
+ }
+ Typeface tf = getFontInfo().getFonts().get(fontName);
+ if (tf instanceof LazyFont) {
+ tf = ((LazyFont)tf).getRealFont();
+ }
+ return tf;
+ }
+
private void drawTextNative(int x, int y, int letterSpacing, int wordSpacing, int[][] dp,
String text, FontTriplet triplet) throws IOException {
Color textColor = state.getTextColor();
@@ -414,25 +487,87 @@ public class PCLPainter extends AbstractIFPainter<PCLDocumentHandler> implements
}
+ private void drawTextUsingSoftFont(int x, int y, int letterSpacing, int wordSpacing, int[][] dp,
+ String text, FontTriplet triplet, PCLSoftFont softFont) throws IOException {
+ Color textColor = state.getTextColor();
+ if (textColor != null) {
+ gen.setTransparencyMode(true, false);
+ gen.selectGrayscale(textColor);
+ }
+
+ if (x != -1 && y != -1) {
+ setCursorPos(x, y);
+ }
+
+ float fontSize = state.getFontSize() / 1000f;
+ Font font = getFontInfo().getFontInstance(triplet, state.getFontSize());
+ int l = text.length();
+ int[] dx = IFUtil.convertDPToDX(dp);
+ int dxl = (dx != null ? dx.length : 0);
+
+ StringBuffer sb = new StringBuffer(Math.max(16, l));
+ if (dx != null && dxl > 0 && dx[0] != 0) {
+ sb.append("\u001B&a+").append(gen.formatDouble2(dx[0] / 100.0)).append('H');
+ }
+ String current = "";
+ for (int i = 0; i < l; i++) {
+ char orgChar = text.charAt(i);
+ float glyphAdjust = 0;
+ if (!font.hasChar(orgChar)) {
+ if (CharUtilities.isFixedWidthSpace(orgChar)) {
+ //Fixed width space are rendered as spaces so copy/paste works in a reader
+ char ch = font.mapChar(CharUtilities.SPACE);
+ int spaceDiff = font.getCharWidth(ch) - font.getCharWidth(orgChar);
+ glyphAdjust = -(10 * spaceDiff / fontSize);
+ }
+ }
+
+ if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) {
+ glyphAdjust += wordSpacing;
+ }
+ current += orgChar;
+ glyphAdjust += letterSpacing;
+ if (dx != null && i < dxl - 1) {
+ glyphAdjust += dx[i + 1];
+ }
+
+ if (glyphAdjust != 0) {
+ gen.getOutputStream().write(sb.toString().getBytes(gen.getTextEncoding()));
+ for (int j = 0; j < current.length(); j++) {
+ gen.getOutputStream().write(softFont.getCharCode(current.charAt(j)));
+ }
+ sb = new StringBuffer();
+
+ String command = (glyphAdjust > 0) ? "\u001B&a+" : "\u001B&a";
+ sb.append(command).append(gen.formatDouble2(glyphAdjust / 100.0)).append('H');
+
+ current = "";
+ }
+ }
+ if (!current.equals("")) {
+ gen.getOutputStream().write(sb.toString().getBytes(gen.getTextEncoding()));
+ for (int i = 0; i < current.length(); i++) {
+ gen.getOutputStream().write(softFont.getCharCode(current.charAt(i)));
+ }
+ }
+ }
+
private static final double SAFETY_MARGIN_FACTOR = 0.05;
- private Rectangle getTextBoundingBox(int x, int y,
- int letterSpacing, int wordSpacing, int[][] dp,
- String text,
- Font font, FontMetricsMapper metrics) {
+ private Rectangle getTextBoundingBox(int x, int y, int letterSpacing, int wordSpacing,
+ int[][] dp, String text, Font font, FontMetricsMapper metrics) {
int maxAscent = metrics.getMaxAscent(font.getFontSize()) / 1000;
- int descent = metrics.getDescender(font.getFontSize()) / 1000; //is negative
- int safetyMargin = (int)(SAFETY_MARGIN_FACTOR * font.getFontSize());
- Rectangle boundingRect = new Rectangle(
- x, y - maxAscent - safetyMargin,
- 0, maxAscent - descent + 2 * safetyMargin);
+ int descent = metrics.getDescender(font.getFontSize()) / 1000; // is negative
+ int safetyMargin = (int) (SAFETY_MARGIN_FACTOR * font.getFontSize());
+ Rectangle boundingRect = new Rectangle(x, y - maxAscent - safetyMargin, 0, maxAscent
+ - descent + 2 * safetyMargin);
int l = text.length();
int[] dx = IFUtil.convertDPToDX(dp);
int dxl = (dx != null ? dx.length : 0);
if (dx != null && dxl > 0 && dx[0] != 0) {
- boundingRect.setLocation(boundingRect.x - (int)Math.ceil(dx[0] / 10f), boundingRect.y);
+ boundingRect.setLocation(boundingRect.x - (int) Math.ceil(dx[0] / 10f), boundingRect.y);
}
float width = 0.0f;
for (int i = 0; i < l; i++) {
@@ -451,19 +586,17 @@ public class PCLPainter extends AbstractIFPainter<PCLDocumentHandler> implements
width += cw + glyphAdjust;
}
int extraWidth = font.getFontSize() / 3;
- boundingRect.setSize(
- (int)Math.ceil(width) + extraWidth,
- boundingRect.height);
+ boundingRect.setSize((int) Math.ceil(width) + extraWidth, boundingRect.height);
return boundingRect;
}
- private void drawTextAsBitmap(final int x, final int y,
- final int letterSpacing, final int wordSpacing, final int[][] dp,
- final String text, FontTriplet triplet) throws IFException {
- //Use Java2D to paint different fonts via bitmap
+ private void drawTextAsBitmap(final int x, final int y, final int letterSpacing,
+ final int wordSpacing, final int[][] dp, final String text, FontTriplet triplet)
+ throws IFException {
+ // Use Java2D to paint different fonts via bitmap
final Font font = getFontInfo().getFontInstance(triplet, state.getFontSize());
- //for cursive fonts, so the text isn't clipped
+ // for cursive fonts, so the text isn't clipped
FontMetricsMapper mapper;
try {
mapper = (FontMetricsMapper) getFontInfo().getMetricsFor(font.getFontName());
@@ -473,11 +606,11 @@ public class PCLPainter extends AbstractIFPainter<PCLDocumentHandler> implements
final int maxAscent = mapper.getMaxAscent(font.getFontSize()) / 1000;
final int ascent = mapper.getAscender(font.getFontSize()) / 1000;
final int descent = mapper.getDescender(font.getFontSize()) / 1000;
- int safetyMargin = (int)(SAFETY_MARGIN_FACTOR * font.getFontSize());
+ int safetyMargin = (int) (SAFETY_MARGIN_FACTOR * font.getFontSize());
final int baselineOffset = maxAscent + safetyMargin;
- final Rectangle boundingBox = getTextBoundingBox(x, y,
- letterSpacing, wordSpacing, dp, text, font, mapper);
+ final Rectangle boundingBox = getTextBoundingBox(x, y, letterSpacing, wordSpacing, dp,
+ text, font, mapper);
final Dimension dim = boundingBox.getSize();
Graphics2DImagePainter painter = new Graphics2DImagePainter() {
@@ -485,7 +618,7 @@ public class PCLPainter extends AbstractIFPainter<PCLDocumentHandler> implements
public void paint(Graphics2D g2d, Rectangle2D area) {
if (DEBUG) {
g2d.setBackground(Color.LIGHT_GRAY);
- g2d.clearRect(0, 0, (int)area.getWidth(), (int)area.getHeight());
+ g2d.clearRect(0, 0, (int) area.getWidth(), (int) area.getHeight());
}
g2d.translate(-x, -y + baselineOffset);
@@ -501,7 +634,7 @@ public class PCLPainter extends AbstractIFPainter<PCLDocumentHandler> implements
try {
painter.drawText(x, y, letterSpacing, wordSpacing, dp, text);
} catch (IFException e) {
- //This should never happen with the Java2DPainter
+ // This should never happen with the Java2DPainter
throw new RuntimeException("Unexpected error while painting text", e);
}
}
diff --git a/src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java b/src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java
index dcda49059..33376655f 100644
--- a/src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java
+++ b/src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java
@@ -67,6 +67,7 @@ public class PCLRendererConfigurator extends PrintRendererConfigurator {
if (config.isTextRendering() != null) {
pclUtil.setAllTextAsBitmaps(config.isTextRendering());
}
+
}
@Override
diff --git a/src/java/org/apache/fop/render/pcl/PCLRenderingUtil.java b/src/java/org/apache/fop/render/pcl/PCLRenderingUtil.java
index 3fc8b5258..32693764f 100644
--- a/src/java/org/apache/fop/render/pcl/PCLRenderingUtil.java
+++ b/src/java/org/apache/fop/render/pcl/PCLRenderingUtil.java
@@ -51,12 +51,6 @@ public class PCLRenderingUtil {
private float ditheringQuality = 0.5f;
/**
- * Controls whether all text should be painted as text. This is a fallback setting in case
- * the mixture of native and bitmapped text does not provide the necessary quality.
- */
- private boolean allTextAsBitmaps;
-
- /**
* Controls whether an RGB canvas is used when converting Java2D graphics to bitmaps.
* This can be used to work around problems with Apache Batik, for example, but setting
* this to true will increase memory consumption.
@@ -68,6 +62,12 @@ public class PCLRenderingUtil {
*/
private boolean disabledPJL;
+ /**
+ * Controls whether all text should be painted as text. This is a fallback setting in case the mixture of native and
+ * bitmapped text does not provide the necessary quality.
+ */
+ private boolean allTextAsBitmaps;
+
PCLRenderingUtil(FOUserAgent userAgent) {
this.userAgent = userAgent;
initialize();
@@ -127,8 +127,7 @@ public class PCLRenderingUtil {
}
/**
- * Controls whether all text should be generated as bitmaps or only text for which there's
- * no native font.
+ * Controls whether all text should be generated as bitmaps or only text for which there's no native font.
* @param allTextAsBitmaps true if all text should be painted as bitmaps
*/
public void setAllTextAsBitmaps(boolean allTextAsBitmaps) {
diff --git a/src/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtil.java b/src/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtil.java
new file mode 100644
index 000000000..1b9382f7b
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/PCLByteWriterUtil.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+public class PCLByteWriterUtil {
+
+ public byte[] padBytes(byte[] in, int length) {
+ return padBytes(in, length, 0);
+ }
+
+ public byte[] padBytes(byte[] in, int length, int value) {
+ byte[] out = new byte[length];
+ for (int i = 0; i < length; i++) {
+ if (i < in.length) {
+ out[i] = in[i];
+ } else {
+ out[i] = (byte) value;
+ }
+ }
+ return out;
+ }
+
+ public byte[] signedInt(int s) {
+ byte b1 = (byte) (s >> 8);
+ byte b2 = (byte) s;
+ return new byte[]{b1, b2};
+ }
+
+ public byte signedByte(int s) {
+ return (byte) s;
+ }
+
+ public byte[] unsignedLongInt(int s) {
+ return unsignedLongInt((long) s);
+ }
+
+ public byte[] unsignedLongInt(long s) {
+ byte b1 = (byte) ((s >> 24) & 0xff);
+ byte b2 = (byte) ((s >> 16) & 0xff);
+ byte b3 = (byte) ((s >> 8) & 0xff);
+ byte b4 = (byte) (s & 0xff);
+ return new byte[]{b1, b2, b3, b4};
+ }
+
+ public byte[] unsignedInt(int s) {
+ byte b1 = (byte) ((s >> 8) & 0xff);
+ byte b2 = (byte) (s & 0xff);
+ return new byte[]{b1, b2};
+ }
+
+ public int unsignedByte(int b) {
+ return (byte) b & 0xFF;
+ }
+
+ public int maxPower2(int value) {
+ int test = 2;
+ while (test < value) {
+ test *= 2;
+ }
+ return test;
+ }
+
+ public int log(int x, int base) {
+ return (int) (Math.log(x) / Math.log(base));
+ }
+
+ public byte[] toByteArray(int[] s) {
+ byte[] values = new byte[s.length];
+ for (int i = 0; i < s.length; i++) {
+ values[i] = (byte) s[i];
+ }
+ return values;
+ }
+
+ public byte[] insertIntoArray(int index, byte[] insertTo, byte[] data) throws IOException {
+ byte[] preBytes = Arrays.copyOf(insertTo, index);
+ byte[] postBytes = Arrays.copyOfRange(insertTo, index, insertTo.length);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(preBytes);
+ baos.write(data);
+ baos.write(postBytes);
+ return baos.toByteArray();
+ }
+
+ public byte[] updateDataAtLocation(byte[] data, byte[] update, int offset) {
+ int count = 0;
+ for (int i = offset; i < offset + update.length; i++) {
+ data[i] = update[count++];
+ }
+ return data;
+ }
+
+ /**
+ * Writes a PCL escape command to the output stream.
+ * @param cmd the command (without the ESCAPE character)
+ * @throws IOException In case of an I/O error
+ */
+ public byte[] writeCommand(String cmd) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(27); // ESC
+ baos.write(cmd.getBytes("US-ASCII"));
+ return baos.toByteArray();
+ }
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/PCLCharacterDefinition.java b/src/java/org/apache/fop/render/pcl/fonts/PCLCharacterDefinition.java
new file mode 100644
index 000000000..c275084dc
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/PCLCharacterDefinition.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PCLCharacterDefinition {
+ private int charCode;
+ private int charDefinitionSize;
+ private byte[] glyfData;
+ private boolean hasContinuation;
+ private PCLCharacterFormat charFormat;
+ private PCLCharacterClass charClass;
+ private PCLByteWriterUtil pclByteWriter;
+ private List<PCLCharacterDefinition> composites;
+ private boolean isComposite;
+
+ public PCLCharacterDefinition(int charCode, PCLCharacterFormat charFormat,
+ PCLCharacterClass charClass, byte[] glyfData, PCLByteWriterUtil pclByteWriter,
+ boolean isComposite) {
+ this.charCode = charCode;
+ this.charFormat = charFormat;
+ this.charClass = charClass;
+ this.glyfData = glyfData;
+ this.pclByteWriter = pclByteWriter;
+ this.isComposite = isComposite;
+ // Glyph Data + (Descriptor Size) + (Character Data Size) + (Glyph ID) must
+ // be less than 32767 otherwise it will result in a continuation structure.
+ charDefinitionSize = glyfData.length + 4 + 2 + 2;
+ hasContinuation = charDefinitionSize > 32767;
+ composites = new ArrayList<PCLCharacterDefinition>();
+ }
+
+ public byte[] getCharacterCommand() throws IOException {
+ return pclByteWriter.writeCommand(String.format("*c%dE", (isComposite) ? 65535 : charCode));
+ }
+
+ public byte[] getCharacterDefinitionCommand() throws IOException {
+ return pclByteWriter.writeCommand(String.format("(s%dW", 10 + glyfData.length));
+ }
+
+ public byte[] getData() throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ // Write Character Descriptor
+ if (!hasContinuation) {
+ writeCharacterDescriptorHeader(0, baos);
+ baos.write(glyfData);
+ } else {
+ int continuations = glyfData.length / 32767;
+ for (int i = 0; i < continuations; i++) {
+ writeCharacterDescriptorHeader(i == 0 ? 0 : 1, baos);
+ int continuationStart = i * 32767;
+ int continuationLength = continuationStart - glyfData.length < 32767
+ ? continuationStart - glyfData.length : 32767;
+ baos.write(glyfData, continuationStart, continuationLength);
+ }
+ }
+ baos.write(0); // Reserved
+ byte[] charBytes = baos.toByteArray();
+ long sum = 0;
+ for (int i = 4; i < charBytes.length; i++) {
+ sum += charBytes[i];
+ }
+ int remainder = (int) (sum % 256);
+ baos.write(256 - remainder); // Checksum
+
+ return baos.toByteArray();
+ }
+
+ private void writeCharacterDescriptorHeader(int continuation, ByteArrayOutputStream baos) throws IOException {
+ baos.write(pclByteWriter.unsignedByte(charFormat.getValue()));
+ baos.write(continuation);
+ baos.write(pclByteWriter.unsignedByte(2)); // Descriptor size (from this byte to character data)
+ baos.write(pclByteWriter.unsignedByte(charClass.getValue()));
+ baos.write(pclByteWriter.unsignedInt(glyfData.length + 4));
+ baos.write(pclByteWriter.unsignedInt(charCode));
+ }
+
+ public void addCompositeGlyph(PCLCharacterDefinition composite) {
+ composites.add(composite);
+ }
+
+ public List<PCLCharacterDefinition> getCompositeGlyphs() {
+ return composites;
+ }
+
+ /**
+ * Character Format used in PCL Character Descriptor See Table 11-50 from PCL 5 Specification
+ */
+ public enum PCLCharacterFormat {
+ LaserJet_Raster(4),
+ Intellifont(10),
+ TrueType(15);
+
+ private int value;
+
+ PCLCharacterFormat(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+ }
+
+ /**
+ * Character Class used in PCL Character Descriptor See Table 11-51 from PCL 5 Specification
+ */
+ public enum PCLCharacterClass {
+ Bitmap(1),
+ CompressedBitmap(2),
+ Contour_Intellifont(3),
+ Compound_Contour_Intellifont(4),
+ TrueType(15);
+
+ private int value;
+
+ PCLCharacterClass(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/PCLCharacterWriter.java b/src/java/org/apache/fop/render/pcl/fonts/PCLCharacterWriter.java
new file mode 100644
index 000000000..df04371e0
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/PCLCharacterWriter.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts;
+
+import java.io.IOException;
+
+import org.apache.fop.fonts.truetype.FontFileReader;
+import org.apache.fop.fonts.truetype.OpenFont;
+
+public abstract class PCLCharacterWriter {
+
+ protected PCLSoftFont font;
+ protected PCLByteWriterUtil pclByteWriter;
+ protected OpenFont openFont;
+ protected FontFileReader fontReader;
+
+ public PCLCharacterWriter(PCLSoftFont font) throws IOException {
+ this.font = font;
+ openFont = font.getOpenFont();
+ fontReader = font.getReader();
+ pclByteWriter = new PCLByteWriterUtil();
+ }
+
+ public abstract byte[] writeCharacterDefinitions(String text) throws IOException;
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/PCLFontReader.java b/src/java/org/apache/fop/render/pcl/fonts/PCLFontReader.java
new file mode 100644
index 000000000..6bd5192ac
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/PCLFontReader.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.fop.fonts.CustomFont;
+import org.apache.fop.fonts.Typeface;
+import org.apache.fop.fonts.truetype.FontFileReader;
+import org.apache.fop.fonts.truetype.OpenFont;
+
+public abstract class PCLFontReader {
+
+ protected Typeface typeface;
+ protected PCLByteWriterUtil pclByteWriter;
+ protected CustomFont font;
+
+ public PCLFontReader(Typeface font, PCLByteWriterUtil pclByteWriter) {
+ this.typeface = font;
+ this.pclByteWriter = pclByteWriter;
+ }
+
+ public void setFont(CustomFont mbFont) {
+ this.font = mbFont;
+ }
+
+ /** Header Data **/
+ public abstract int getDescriptorSize();
+ public abstract int getHeaderFormat();
+ public abstract int getFontType();
+ public abstract int getStyleMSB();
+ public abstract int getBaselinePosition();
+ public abstract int getCellWidth();
+ public abstract int getCellHeight();
+ public abstract int getOrientation();
+ public abstract int getSpacing();
+ public abstract int getSymbolSet();
+ public abstract int getPitch();
+ public abstract int getHeight();
+ public abstract int getXHeight();
+ public abstract int getWidthType();
+ public abstract int getStyleLSB();
+ public abstract int getStrokeWeight();
+ public abstract int getTypefaceLSB();
+ public abstract int getTypefaceMSB();
+ public abstract int getSerifStyle();
+ public abstract int getQuality();
+ public abstract int getPlacement();
+ public abstract int getUnderlinePosition();
+ public abstract int getUnderlineThickness();
+ public abstract int getTextHeight();
+ public abstract int getTextWidth();
+ public abstract int getFirstCode();
+ public abstract int getLastCode();
+ public abstract int getPitchExtended();
+ public abstract int getHeightExtended();
+ public abstract int getCapHeight();
+ public abstract int getFontNumber();
+ public abstract String getFontName();
+ public abstract int getScaleFactor() throws IOException;
+ public abstract int getMasterUnderlinePosition() throws IOException;
+ public abstract int getMasterUnderlineThickness() throws IOException;
+ public abstract int getFontScalingTechnology();
+ public abstract int getVariety();
+
+ /** Segmented Font Data **/
+ public abstract List<PCLFontSegment> getFontSegments(Map<Character, Integer> mappedGlyphs)
+ throws IOException;
+
+ /** Character Definitions **/
+ public abstract Map<Integer, int[]> getCharacterOffsets() throws IOException;
+
+ public abstract OpenFont getFontFile();
+ public abstract FontFileReader getFontFileReader();
+
+ /**
+ * Gets the most significant byte from a 16-bit integer
+ * @param s The number
+ * @return The resulting byte value as an integer
+ */
+ protected int getMSB(int s) {
+ return s >> 8;
+ }
+
+ /**
+ * Gets the least significant byte from a 16-bit integer
+ * @param s The number
+ * @return The resulting byte value as an integer
+ */
+ protected int getLSB(int s) {
+ byte b1 = (byte) (s >> 8);
+ return s;
+ }
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactory.java b/src/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactory.java
new file mode 100644
index 000000000..15c4e8d54
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/PCLFontReaderFactory.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts;
+
+import java.io.IOException;
+
+import org.apache.fop.fonts.CIDFontType;
+import org.apache.fop.fonts.CustomFont;
+import org.apache.fop.fonts.FontType;
+import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.Typeface;
+import org.apache.fop.render.java2d.CustomFontMetricsMapper;
+import org.apache.fop.render.pcl.fonts.truetype.PCLTTFFontReader;
+
+public final class PCLFontReaderFactory {
+
+ private PCLByteWriterUtil pclByteWriter;
+
+ private PCLFontReaderFactory(PCLByteWriterUtil pclByteWriter) {
+ this.pclByteWriter = pclByteWriter;
+ }
+
+ public static PCLFontReaderFactory getInstance(PCLByteWriterUtil pclByteWriter) {
+ return new PCLFontReaderFactory(pclByteWriter);
+ }
+
+ public PCLFontReader createInstance(Typeface font) throws IOException {
+ if (font.getFontType() == FontType.TRUETYPE || isCIDType2(font)) {
+ return new PCLTTFFontReader(font, pclByteWriter);
+ }
+ // else if (font instanceof MultiByteFont && ((MultiByteFont) font).isOTFFile()) {
+ // Placeholder for future Type 1 / OTF Soft font implementations e.g.
+ // return new PCLOTFFontReader(font, pclByteWriter);
+ // }
+ return null;
+ }
+
+ private boolean isCIDType2(Typeface font) {
+ CustomFontMetricsMapper fontMetrics = (CustomFontMetricsMapper) font;
+ CustomFont customFont = (CustomFont) fontMetrics.getRealFont();
+
+ if (customFont instanceof MultiByteFont) {
+ return ((MultiByteFont) customFont).getCIDType() == CIDFontType.CIDTYPE2;
+ }
+ return false;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/PCLFontSegment.java b/src/java/org/apache/fop/render/pcl/fonts/PCLFontSegment.java
new file mode 100644
index 000000000..111dbf932
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/PCLFontSegment.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts;
+
+public class PCLFontSegment {
+ private SegmentID identifier;
+ private byte[] data;
+
+ public PCLFontSegment(SegmentID identifier, byte[] data) {
+ this.identifier = identifier;
+ this.data = data;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public SegmentID getIdentifier() {
+ return identifier;
+ }
+
+ public int getSize() {
+ return (identifier == SegmentID.NULL) ? 0 : data.length;
+ }
+
+ public enum SegmentID {
+ CC(17219), // Character Complement
+ CP(17232), // Copyright
+ GT(18260), // Global TrueType Data
+ IF(18758), // Intellifont Face Data
+ PA(20545), // PANOSE Description
+ XW(22619), // XWindows Font Name
+ NULL(65535); // Null Segment
+
+ private int complementID;
+
+ SegmentID(int complementID) {
+ this.complementID = complementID;
+ }
+
+ public int getValue() {
+ return complementID;
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/PCLSoftFont.java b/src/java/org/apache/fop/render/pcl/fonts/PCLSoftFont.java
new file mode 100644
index 000000000..8412534eb
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/PCLSoftFont.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.Typeface;
+import org.apache.fop.fonts.truetype.FontFileReader;
+import org.apache.fop.fonts.truetype.OpenFont;
+import org.apache.fop.render.java2d.CustomFontMetricsMapper;
+
+public class PCLSoftFont {
+ private int fontID;
+ private Typeface font;
+ private Map<Integer, int[]> charOffsets;
+ private OpenFont openFont;
+ private InputStream fontStream;
+ private FontFileReader reader;
+ /** Map containing unicode character and it's soft font codepoint **/
+ private Map<Integer, Integer> charsWritten;
+ private Map<Character, Integer> mappedChars;
+ private Map<Integer, Integer> charMtxPositions;
+ private boolean multiByteFont;
+ private int charCount = 32;
+
+ public PCLSoftFont(int fontID, Typeface font, boolean multiByteFont) {
+ this.fontID = fontID;
+ this.font = font;
+ charsWritten = new HashMap<Integer, Integer>();
+ mappedChars = new HashMap<Character, Integer>();
+ this.multiByteFont = multiByteFont;
+ }
+
+ public Typeface getTypeface() {
+ return font;
+ }
+
+ public int getFontID() {
+ return fontID;
+ }
+
+ public void setCharacterOffsets(Map<Integer, int[]> charOffsets) {
+ this.charOffsets = charOffsets;
+ }
+
+ public Map<Integer, int[]> getCharacterOffsets() {
+ return charOffsets;
+ }
+
+ public OpenFont getOpenFont() {
+ return openFont;
+ }
+
+ public void setOpenFont(OpenFont openFont) {
+ this.openFont = openFont;
+ }
+
+ public InputStream getFontStream() {
+ return fontStream;
+ }
+
+ public void setFontStream(InputStream fontStream) {
+ this.fontStream = fontStream;
+ }
+
+ public FontFileReader getReader() {
+ return reader;
+ }
+
+ public void setReader(FontFileReader reader) {
+ this.reader = reader;
+ }
+
+ public void writeCharacter(int unicode) {
+ charsWritten.put(unicode, charCount++);
+ }
+
+ public int getUnicodeCodePoint(int unicode) {
+ if (charsWritten.containsKey(unicode)) {
+ return charsWritten.get(unicode);
+ } else {
+ return -1;
+ }
+ }
+
+ public boolean hasPreviouslyWritten(int unicode) {
+ return charsWritten.containsKey(unicode);
+ }
+
+ public int getMtxCharIndex(int unicode) {
+ if (charMtxPositions.get(unicode) != null) {
+ return charMtxPositions.get(unicode);
+ }
+ return 0;
+ }
+
+ public int getCmapGlyphIndex(int unicode) {
+ if (font instanceof CustomFontMetricsMapper) {
+ CustomFontMetricsMapper customFont = (CustomFontMetricsMapper) font;
+ Typeface realFont = customFont.getRealFont();
+ if (realFont instanceof MultiByteFont) {
+ MultiByteFont mbFont = (MultiByteFont) realFont;
+ return mbFont.findGlyphIndex(unicode);
+ }
+ }
+ return 0;
+ }
+
+ public void setMtxCharIndexes(Map<Integer, Integer> charMtxPositions) {
+ this.charMtxPositions = charMtxPositions;
+ }
+
+ public int getCharCount() {
+ return charCount;
+ }
+
+ public void setMappedChars(Map<Character, Integer> mappedChars) {
+ this.mappedChars = mappedChars;
+ }
+
+ public Map<Character, Integer> getMappedChars() {
+ return mappedChars;
+ }
+
+ public int getCharIndex(char ch) {
+ if (mappedChars.containsKey(ch)) {
+ return mappedChars.get(ch);
+ } else {
+ return -1;
+ }
+ }
+
+ public int getCharCode(char ch) {
+ if (multiByteFont) {
+ return getCharIndex(ch);
+ } else {
+ return getUnicodeCodePoint(ch);
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java b/src/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java
new file mode 100644
index 000000000..621ea4f18
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.fop.fonts.CustomFont;
+import org.apache.fop.fonts.Typeface;
+import org.apache.fop.render.java2d.CustomFontMetricsMapper;
+
+public class PCLSoftFontManager {
+ private ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ private PCLFontReader fontReader;
+ private PCLByteWriterUtil pclByteWriter = new PCLByteWriterUtil();
+ private List<PCLSoftFont> fonts = new ArrayList<PCLSoftFont>();
+ private PCLFontReaderFactory fontReaderFactory;
+
+ private static final int SOFT_FONT_SIZE = 255;
+
+ public ByteArrayOutputStream makeSoftFont(Typeface font) throws IOException {
+ List<Map<Character, Integer>> mappedGlyphs = mapFontGlyphs(font);
+ if (fontReaderFactory == null) {
+ fontReaderFactory = PCLFontReaderFactory.getInstance(pclByteWriter);
+ }
+ fontReader = fontReaderFactory.createInstance(font);
+ initialize();
+ if (mappedGlyphs.isEmpty()) {
+ mappedGlyphs.add(new HashMap<Character, Integer>());
+ }
+ if (fontReader != null) {
+ for (Map<Character, Integer> glyphSet : mappedGlyphs) {
+ PCLSoftFont softFont = new PCLSoftFont(fonts.size() + 1, font,
+ mappedGlyphs.get(0).size() != 0);
+ softFont.setMappedChars(glyphSet);
+ assignFontID();
+ writeFontHeader(softFont.getMappedChars());
+ softFont.setCharacterOffsets(fontReader.getCharacterOffsets());
+ softFont.setOpenFont(fontReader.getFontFile());
+ softFont.setReader(fontReader.getFontFileReader());
+ fonts.add(softFont);
+ }
+ return baos;
+ } else {
+ return null;
+ }
+ }
+
+ private List<Map<Character, Integer>> mapFontGlyphs(Typeface tf) {
+ List<Map<Character, Integer>> mappedGlyphs = new ArrayList<Map<Character, Integer>>();
+ if (tf instanceof CustomFontMetricsMapper) {
+ CustomFontMetricsMapper fontMetrics = (CustomFontMetricsMapper) tf;
+ CustomFont customFont = (CustomFont) fontMetrics.getRealFont();
+ mappedGlyphs = mapGlyphs(customFont.getUsedGlyphs(), customFont);
+ }
+ return mappedGlyphs;
+ }
+
+ private List<Map<Character, Integer>> mapGlyphs(Map<Integer, Integer> usedGlyphs, CustomFont font) {
+ int charCount = 32;
+ List<Map<Character, Integer>> mappedGlyphs = new ArrayList<Map<Character, Integer>>();
+ Map<Character, Integer> fontGlyphs = new HashMap<Character, Integer>();
+ for (Entry<Integer, Integer> entry : usedGlyphs.entrySet()) {
+ int glyphID = entry.getKey();
+ if (glyphID == 0) {
+ continue;
+ }
+ char unicode = font.getUnicodeFromGID(glyphID);
+ if (charCount > SOFT_FONT_SIZE) {
+ mappedGlyphs.add(fontGlyphs);
+ charCount = 32;
+ fontGlyphs = new HashMap<Character, Integer>();
+ }
+ fontGlyphs.put(unicode, charCount++);
+ }
+ if (fontGlyphs.size() > 0) {
+ mappedGlyphs.add(fontGlyphs);
+ }
+ return mappedGlyphs;
+ }
+
+ private void initialize() {
+ baos.reset();
+ }
+
+ private void assignFontID() throws IOException {
+ baos.write(assignFontID(fonts.size() + 1));
+ }
+
+ public byte[] assignFontID(int fontID) throws IOException {
+ return pclByteWriter.writeCommand(String.format("*c%dD", fontID));
+ }
+
+ private void writeFontHeader(Map<Character, Integer> mappedGlyphs) throws IOException {
+ ByteArrayOutputStream header = new ByteArrayOutputStream();
+ header.write(pclByteWriter.unsignedInt(fontReader.getDescriptorSize()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getHeaderFormat()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getFontType()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getStyleMSB()));
+ header.write(0); // Reserved
+ header.write(pclByteWriter.unsignedInt(fontReader.getBaselinePosition()));
+ header.write(pclByteWriter.unsignedInt(fontReader.getCellWidth()));
+ header.write(pclByteWriter.unsignedInt(fontReader.getCellHeight()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getOrientation()));
+ header.write(fontReader.getSpacing());
+ header.write(pclByteWriter.unsignedInt(fontReader.getSymbolSet()));
+ header.write(pclByteWriter.unsignedInt(fontReader.getPitch()));
+ header.write(pclByteWriter.unsignedInt(fontReader.getHeight()));
+ header.write(pclByteWriter.unsignedInt(fontReader.getXHeight()));
+ header.write(pclByteWriter.signedByte(fontReader.getWidthType()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getStyleLSB()));
+ header.write(pclByteWriter.signedByte(fontReader.getStrokeWeight()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getTypefaceLSB()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getTypefaceMSB()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getSerifStyle()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getQuality()));
+ header.write(pclByteWriter.signedByte(fontReader.getPlacement()));
+ header.write(pclByteWriter.signedByte(fontReader.getUnderlinePosition()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getUnderlineThickness()));
+ header.write(pclByteWriter.unsignedInt(fontReader.getTextHeight()));
+ header.write(pclByteWriter.unsignedInt(fontReader.getTextWidth()));
+ header.write(pclByteWriter.unsignedInt(fontReader.getFirstCode()));
+ header.write(pclByteWriter.unsignedInt(fontReader.getLastCode()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getPitchExtended()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getHeightExtended()));
+ header.write(pclByteWriter.unsignedInt(fontReader.getCapHeight()));
+ header.write(pclByteWriter.unsignedLongInt(fontReader.getFontNumber()));
+ header.write(pclByteWriter.padBytes(fontReader.getFontName().getBytes("US-ASCII"), 16, 32));
+ header.write(pclByteWriter.unsignedInt(fontReader.getScaleFactor()));
+ header.write(pclByteWriter.signedInt(fontReader.getMasterUnderlinePosition()));
+ header.write(pclByteWriter.unsignedInt(fontReader.getMasterUnderlineThickness()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getFontScalingTechnology()));
+ header.write(pclByteWriter.unsignedByte(fontReader.getVariety()));
+
+ writeSegmentedFontData(header, mappedGlyphs);
+
+ baos.write(getFontHeaderCommand(header.size()));
+ baos.write(header.toByteArray());
+ }
+
+ private void writeSegmentedFontData(ByteArrayOutputStream header,
+ Map<Character, Integer> mappedGlyphs) throws IOException {
+ List<PCLFontSegment> fontSegments = fontReader.getFontSegments(mappedGlyphs);
+ for (PCLFontSegment segment : fontSegments) {
+ writeFontSegment(header, segment);
+ }
+ header.write(0); // Reserved
+ // Checksum must equal 0 when added to byte 64 offset (modulo 256)
+ long sum = 0;
+ byte[] headerBytes = header.toByteArray();
+ for (int i = 64; i < headerBytes.length; i++) {
+ sum += headerBytes[i];
+ }
+ int remainder = (int) (sum % 256);
+ header.write(256 - remainder);
+ }
+
+ private byte[] getFontHeaderCommand(int headerSize) throws IOException {
+ return pclByteWriter.writeCommand(String.format(")s%dW", headerSize));
+ }
+
+ private void writeFontSegment(ByteArrayOutputStream header, PCLFontSegment segment) throws IOException {
+ header.write(pclByteWriter.unsignedInt(segment.getIdentifier().getValue()));
+ header.write(pclByteWriter.unsignedInt(segment.getData().length));
+ header.write(segment.getData());
+ }
+
+ /**
+ * Finds a soft font associated with the given typeface. If more than one instance of the font exists (as each font
+ * is bound and restricted to 255 characters) it will find the last font with available capacity.
+ * @param font The typeface associated with the soft font
+ * @return Returns the PCLSoftFont with available capacity
+ */
+ public PCLSoftFont getSoftFont(Typeface font, String text) {
+ for (PCLSoftFont sftFont : fonts) {
+ if (sftFont.getTypeface().equals(font)
+ && sftFont.getCharCount() + countNonMatches(sftFont, text) < SOFT_FONT_SIZE) {
+ return sftFont;
+ }
+ }
+ return null;
+ }
+
+ public PCLSoftFont getSoftFontFromID(int index) {
+ return fonts.get(index - 1);
+ }
+
+ private int countNonMatches(PCLSoftFont font, String text) {
+ int result = 0;
+ for (char ch : text.toCharArray()) {
+ int value = font.getUnicodeCodePoint(ch);
+ if (value == -1) {
+ result++;
+ }
+ }
+ return result;
+ }
+
+ public int getSoftFontID(Typeface tf) throws IOException {
+ PCLSoftFont font = getSoftFont(tf, "");
+ for (int i = 0; i < fonts.size(); i++) {
+ if (fonts.get(i).equals(font)) {
+ return i + 1;
+ }
+ }
+ return -1;
+ }
+
+ public List<PCLTextSegment> getTextSegments(String text, Typeface font) {
+ List<PCLTextSegment> textSegments = new ArrayList<PCLTextSegment>();
+ int curFontID = -1;
+ String current = "";
+ for (char ch : text.toCharArray()) {
+ for (PCLSoftFont softFont : fonts) {
+ if (curFontID == -1) {
+ curFontID = softFont.getFontID();
+ }
+ if (softFont.getCharIndex(ch) == -1 || !softFont.getTypeface().equals(font)) {
+ continue;
+ }
+ if (current.length() > 0 && curFontID != softFont.getFontID()) {
+ textSegments.add(new PCLTextSegment(curFontID, current));
+ current = "";
+ curFontID = softFont.getFontID();
+ }
+ if (curFontID != softFont.getFontID()) {
+ curFontID = softFont.getFontID();
+ }
+ current += ch;
+ break;
+ }
+ }
+ if (current.length() > 0) {
+ textSegments.add(new PCLTextSegment(curFontID, current));
+ }
+ return textSegments;
+ }
+
+ public static class PCLTextSegment {
+ private String text;
+ private int fontID;
+
+ public PCLTextSegment(int fontID, String text) {
+ this.text = text;
+ this.fontID = fontID;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public int getFontID() {
+ return fontID;
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/PCLSymbolSet.java b/src/java/org/apache/fop/render/pcl/fonts/PCLSymbolSet.java
new file mode 100644
index 000000000..a2c50df23
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/PCLSymbolSet.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts;
+
+/**
+ * Table C-1 from http://www.lprng.com/DISTRIB/RESOURCES/DOCS/pcl5comp.pdf
+ */
+public enum PCLSymbolSet {
+ // Unbound font containing > 256 characters
+ Unbound("1X", 56),
+
+ // Other symbol sets to use in bound fonts
+ Bound_Generic("0Q", 17),
+ GW_3212("18C", 597),
+ ISO_60_Danish_Norwegian("0D", 4),
+ Devanagari("2D", 68),
+ ISO_4_United_Kingdom("1E", 37),
+ Windows_3_1_Latin2("9E", 293),
+ ISO_69_French("1F", 38),
+ ISO_21_German("1G", 39),
+ Greek_8("8G", 283),
+ Windows_3_1_Latin_Greek("9G", 295),
+ PC_851_Latin_Greek("10G", 327),
+ PC_8_Latin_Greek("12G", 391),
+ Hebrew_7("0H", 8),
+ ISO_8859_8_Latin_Hebrew("7H", 232),
+ Hebrew_8("8H", 264),
+ PC_862_Latin_Hebrew("15H", 488),
+ ISO_15_Italian("0I", 9),
+ Microsoft_Publishing("6J", 202),
+ DeskTop("7J", 234),
+ Document("8J", 266),
+ PC_1004("9J", 298),
+ PS_Text("10J", 330),
+ PS_ISO_Latin1("11J", 362),
+ MC_Text("12J", 394),
+ Ventura_International3("13J", 426),
+ Ventura_US3("14J", 458),
+ Swash_Characters("16J", 522),
+ Small_Caps_Old_Style_Figures("17J", 554),
+ Old_Style_Figures("18J", 586),
+ Fractions("19J", 618),
+ Lining_Figures("21J", 682),
+ Small_Caps_and_Lining_Figures("22J", 714),
+ Alternate_Caps("23J", 746),
+ Kana_8_JIS_210("8K", 267),
+ Korean_8("9K", 299),
+
+ Line_Draw_7("0L", 12),
+ HP_Block_Characters("1L", 44),
+ Tax_Line_Draw("2L", 76),
+ Line_Draw_8("8L", 268),
+ Ventura_ITC_Zapf_Dingbats3("9L", 300),
+ PS_ITC_Zapf_Dingbats("10L", 332),
+ ITC_Zapf_Dingbats_Series_100("11L", 364),
+ ITC_Zapf_Dingbats_Series_200("12L", 396),
+ ITC_Zapf_Dingbats_Series_300("13L", 428),
+ Windows_Baltic("19L", 620),
+ Carta("20L", 652),
+ Ornaments("21L", 684),
+ Universal_News_Commercial_Pi("22L", 716),
+ Chess("23L", 748),
+ Astrology_1("24L", 780),
+ Pi_Set_1("31L", 1004),
+ Pi_Set_2("32L", 1036),
+ Pi_Set_3("33L", 1068),
+ Pi_Set_4("34L", 1100),
+ Pi_Set_5("35L", 1132),
+ Pi_Set_6("36L", 1164),
+ Wingdings("579L", 18540),
+ Math_7("0M", 13),
+ Tech_7("1M", 45),
+ PS_Math("5M", 173),
+ Ventura_Math3("6M", 205),
+ Math_8("8M", 269),
+ Universal_Greek_Math_Pi("10M", 333),
+ TeX_Math_Extension("11M", 365),
+ TeX_Math_Symbol("12M", 397),
+ TeX_Math_Italic("13M", 429),
+ Symbol("19M", 621),
+ ISO_8859_1_Latin_1("0N", 14),
+ ISO_8859_2_Latin_2("2N", 78),
+
+ ISO_8859_3_Latin_3("3N", 110),
+ ISO_8859_4_Latin_4("4N", 142),
+ ISO_8859_9_Latin_5("5N", 174),
+ ISO_8859_10_Latin_6("6N", 206),
+ ISO_8859_5_Latin_Cyrillic("10N", 334),
+ ISO_8859_6_Latin_Arabic("11N", 366),
+ ISO_8859_7_Latin_Greek("12N", 398),
+ OCR_A("0O", 15),
+ OCR_B("1O", 47),
+ OCR_M("2O", 79),
+ MICR_E13B("10O", 335),
+ Typewriter_Paired_APL("0P", 16),
+ Bit_Paired_APL("1P", 48),
+ Expert("10P", 336),
+ Alternate("11P", 368),
+ Fraktur("12P", 400),
+ Cyrillic_ASCII_8859_5_1986("0R", 18),
+ Cyrillic("1R", 50),
+ PC_Cyrillic("3R", 114),
+ Windows_3_1_Latin_Cyrillic("9R", 306),
+ ISO_11_Swedish("0S", 19),
+ ISO_17_Spanish3("2S", 83),
+ HP_European_Spanish("7S", 243),
+ HP_Latin_Spanish("8S", 275),
+ HP_GL_Download("16S", 531),
+ HP_GL_Drafting("17S", 563),
+ HP_GL_Special_Symbols("18S", 595),
+ Sonata("20S", 659),
+ Thai_8("0T", 20),
+ TISI_620_2533_Thai("1T", 52),
+ Windows_3_1_Latin_5("5T", 180),
+ Turkish_8("8T", 276),
+
+ PC_8_Turkish("9T", 308),
+ Teletex("10T", 340),
+ ISO_6_ASCII("0U", 21),
+ Legal("1U", 53),
+ HPL("5U", 181),
+ OEM_1("7U", 245),
+ Roman_8("8U", 277),
+ Windows_3_0_Latin_1("9U", 309),
+ PC_8_Code_Page_437("10U", 341),
+ PC_8_D_N_Danish_Norwegian("11U", 373),
+ PC_850_Multilingual("12U", 405),
+ Pi_Font("15U", 501),
+ PC_857("16U", 533),
+ PC_852_Latin_2("17U", 565),
+ Windows_3_1_Latin_1("19U", 629),
+ PC_860_Portugal("20U", 661),
+ PC_861_Iceland("21U", 693),
+ PC_863_Canada_French("23U", 757),
+ PC_865_Norway("25U", 821),
+ PC_775("26U", 853),
+ Arabic_8("8V", 278),
+ Windows_3_1_Latin_Arabic("9V", 310),
+ Code_Page_864_Latin_Arabic("10V", 342),
+ Barcode_3of9("0Y", 25),
+ Industrial_2_of_5_Barcode("1Y", 57),
+ Matrix_2_of_5_Barcode("2Y", 89),
+ Interleaved_2_of_5_Barcode("4Y", 153),
+ CODABAR_Barcode("5Y", 185),
+ MSI_Plessey_Barcode("6Y", 217),
+ Code_11_Barcode("7Y", 249),
+ UPC_EAN_Barcode("8Y", 281),
+ MICR_CMC_7("14Y", 473),
+ USPS_ZIP("5Y", 505),
+
+ Math_7_2("0A", 1),
+ Line_Draw_7_2("0B", 2),
+ HP_Large_Characters("0C", 3),
+ ISO_61_Norwegian_Version_2("1D", 36),
+ Roman_Extension("0E", 5),
+ ISO_25_French("0F", 6),
+ HP_German("0G", 7),
+ ISO_14_JIS_ASCII("0K", 11),
+ ISO_13_Katakana("1K", 43),
+ ISO_57_Chinese("2K", 75),
+ HP_Spanish("1S", 51),
+ ISO_10_Swedish("3S", 115),
+ ISO_16_Portuguese("4S", 147),
+ ISO_84_Portuguese("5S", 179),
+ ISO_85_Spanish("6S", 211),
+ ISO_2_International_Reference("2U", 85),
+ Arabic("0V", 22);
+
+ private String symbolSetID;
+ private int kind1;
+
+ PCLSymbolSet(String symbolSetID, int kind1) {
+ this.kind1 = kind1;
+ }
+
+ public String getSymbolSetID() {
+ return symbolSetID;
+ }
+
+ public int getKind1() {
+ return kind1;
+ }
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriter.java b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriter.java
new file mode 100644
index 000000000..41fefaaf0
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFCharacterWriter.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts.truetype;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.fop.fonts.truetype.GlyfTable;
+import org.apache.fop.fonts.truetype.OFDirTabEntry;
+import org.apache.fop.fonts.truetype.OFMtxEntry;
+import org.apache.fop.fonts.truetype.OFTableName;
+import org.apache.fop.fonts.truetype.TTFFile;
+import org.apache.fop.render.pcl.fonts.PCLCharacterDefinition;
+import org.apache.fop.render.pcl.fonts.PCLCharacterDefinition.PCLCharacterClass;
+import org.apache.fop.render.pcl.fonts.PCLCharacterDefinition.PCLCharacterFormat;
+import org.apache.fop.render.pcl.fonts.PCLCharacterWriter;
+import org.apache.fop.render.pcl.fonts.PCLSoftFont;
+
+public class PCLTTFCharacterWriter extends PCLCharacterWriter {
+
+ private List<OFMtxEntry> mtx;
+ private OFDirTabEntry tabEntry;
+
+ public PCLTTFCharacterWriter(PCLSoftFont softFont) throws IOException {
+ super(softFont);
+ softFont.setMtxCharIndexes(scanMtxCharacters());
+ }
+
+ @Override
+ public byte[] writeCharacterDefinitions(String text) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ for (char ch : text.toCharArray()) {
+ int character = (int) ch;
+ if (!font.hasPreviouslyWritten(character)) {
+ PCLCharacterDefinition pclChar = getCharacterDefinition(ch);
+ writePCLCharacter(baos, pclChar);
+ List<PCLCharacterDefinition> compositeGlyphs = pclChar.getCompositeGlyphs();
+ for (PCLCharacterDefinition composite : compositeGlyphs) {
+ writePCLCharacter(baos, composite);
+ }
+ }
+ }
+ return baos.toByteArray();
+ }
+
+ private void writePCLCharacter(ByteArrayOutputStream baos, PCLCharacterDefinition pclChar) throws IOException {
+ baos.write(pclChar.getCharacterCommand());
+ baos.write(pclChar.getCharacterDefinitionCommand());
+ baos.write(pclChar.getData());
+ }
+
+ private Map<Integer, Integer> scanMtxCharacters() throws IOException {
+ Map<Integer, Integer> charMtxOffsets = new HashMap<Integer, Integer>();
+ List<OFMtxEntry> mtx = openFont.getMtx();
+ OFTableName glyfTag = OFTableName.GLYF;
+ if (openFont.seekTab(fontReader, glyfTag, 0)) {
+ for (int i = 1; i < mtx.size(); i++) {
+ OFMtxEntry entry = mtx.get(i);
+ int charCode = 0;
+ if (entry.getUnicodeIndex().size() > 0) {
+ charCode = (Integer) entry.getUnicodeIndex().get(0);
+ } else {
+ charCode = entry.getIndex();
+ }
+ charMtxOffsets.put(charCode, i);
+ }
+ }
+ return charMtxOffsets;
+ }
+
+ private PCLCharacterDefinition getCharacterDefinition(int unicode) throws IOException {
+ if (mtx == null) {
+ mtx = openFont.getMtx();
+ tabEntry = openFont.getDirectoryEntry(OFTableName.GLYF);
+ }
+ if (openFont.seekTab(fontReader, OFTableName.GLYF, 0)) {
+ int charIndex = font.getMtxCharIndex(unicode);
+
+ // Fallback - only works for MultiByte fonts
+ if (charIndex == 0) {
+ charIndex = font.getCmapGlyphIndex(unicode);
+ }
+
+ Map<Integer, Integer> subsetGlyphs = new HashMap<Integer, Integer>();
+ subsetGlyphs.put(charIndex, 1);
+
+ byte[] glyphData = getGlyphData(charIndex);
+
+ font.writeCharacter(unicode);
+
+ PCLCharacterDefinition newChar = new PCLCharacterDefinition(
+ font.getCharCode((char) unicode),
+ PCLCharacterFormat.TrueType,
+ PCLCharacterClass.TrueType, glyphData, pclByteWriter, false);
+
+ // Handle composite character definitions
+ GlyfTable glyfTable = new GlyfTable(fontReader, mtx.toArray(new OFMtxEntry[mtx.size()]),
+ tabEntry, subsetGlyphs);
+ if (glyfTable.isComposite(charIndex)) {
+ Set<Integer> composites = glyfTable.retrieveComposedGlyphs(charIndex);
+ for (Integer compositeIndex : composites) {
+ byte[] compositeData = getGlyphData(compositeIndex);
+ newChar.addCompositeGlyph(new PCLCharacterDefinition(compositeIndex,
+ PCLCharacterFormat.TrueType,
+ PCLCharacterClass.TrueType, compositeData, pclByteWriter, true));
+ }
+ }
+
+ return newChar;
+ }
+ return null;
+ }
+
+ private byte[] getGlyphData(int charIndex) throws IOException {
+ OFMtxEntry entry = mtx.get(charIndex);
+ OFMtxEntry nextEntry;
+ int nextOffset = 0;
+ if (charIndex < mtx.size() - 1) {
+ nextEntry = mtx.get(charIndex + 1);
+ nextOffset = (int) nextEntry.getOffset();
+ } else {
+ nextOffset = (int) ((TTFFile) openFont).getLastGlyfLocation();
+ }
+ int glyphOffset = (int) entry.getOffset();
+ int glyphLength = nextOffset - glyphOffset;
+
+ byte[] glyphData = new byte[0];
+ if (glyphLength > 0) {
+ glyphData = fontReader.getBytes((int) tabEntry.getOffset() + glyphOffset, glyphLength);
+ }
+ return glyphData;
+ }
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java
new file mode 100644
index 000000000..1a054953c
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java
@@ -0,0 +1,731 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts.truetype;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.fop.fonts.CustomFont;
+import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.SingleByteFont;
+import org.apache.fop.fonts.Typeface;
+import org.apache.fop.fonts.truetype.FontFileReader;
+import org.apache.fop.fonts.truetype.OFDirTabEntry;
+import org.apache.fop.fonts.truetype.OFFontLoader;
+import org.apache.fop.fonts.truetype.OFMtxEntry;
+import org.apache.fop.fonts.truetype.OFTableName;
+import org.apache.fop.fonts.truetype.OpenFont;
+import org.apache.fop.fonts.truetype.TTFFile;
+import org.apache.fop.render.java2d.CustomFontMetricsMapper;
+import org.apache.fop.render.pcl.fonts.PCLByteWriterUtil;
+import org.apache.fop.render.pcl.fonts.PCLFontReader;
+import org.apache.fop.render.pcl.fonts.PCLFontSegment;
+import org.apache.fop.render.pcl.fonts.PCLFontSegment.SegmentID;
+import org.apache.fop.render.pcl.fonts.PCLSymbolSet;
+
+public class PCLTTFFontReader extends PCLFontReader {
+ protected TTFFile ttfFont;
+ protected InputStream fontStream;
+ protected FontFileReader reader;
+ private PCLTTFPCLTFontTable pcltTable;
+ private PCLTTFOS2FontTable os2Table;
+ private PCLTTFPOSTFontTable postTable;
+ private PCLTTFTableFactory ttfTableFactory;
+
+ private static final int HMTX_RESTRICT_SIZE = 50000;
+
+ private static final Map<Integer, Integer> FONT_WEIGHT = new HashMap<Integer, Integer>() {
+ private static final long serialVersionUID = 1L;
+ {
+ put(100, -6); // 100 Thin
+ put(200, -4); // 200 Extra-Light
+ put(300, -3); // 300 Light
+ put(400, 0); // 400 Normal (Regular)
+ put(500, 0); // 500 Medium
+ put(600, 2); // 600 Semi-bold
+ put(700, 3); // 700 Bold
+ put(800, 4); // 800 Extra-bold
+ put(900, 5); // 900 Black (Heavy)
+ }
+ };
+
+ private static final Map<Integer, Integer> FONT_SERIF = new HashMap<Integer, Integer>() {
+ private static final long serialVersionUID = 1L;
+ {
+ /** The following are the best guess conversion between serif styles. Unfortunately
+ * there appears to be no standard and so each specification has it's own set of values.
+ * Please change if better fit found. **/
+ put(0, 0); // Any = Normal Sans
+ put(1, 64); // No Fit = Sans Serif
+ put(2, 9); // Cove = Script Nonconnecting
+ put(3, 12); // Obtuse Cove = Script Broken Letter
+ put(4, 10); // Square Cove = Script Joining
+ put(5, 0); // Obtuse Square Cove = Sans Serif Square
+ put(6, 128); // Square = Serif
+ put(7, 2); // Thin = Serif Line
+ put(8, 7); // Bone = Rounded Bracket
+ put(9, 11); // Exeraggerated = Script Calligraphic
+ put(10, 3); // Triangle = Serif Triangle
+ put(11, 0); // Normal Sans = Sans Serif Square
+ put(12, 4); // Obtuse Sans = Serif Swath
+ put(13, 6); // Perp Sans = Serif Bracket
+ put(14, 8); // Flared = Flair Serif
+ put(15, 1); // Rounded = Sans Serif Round
+ }
+ };
+
+ private static final Map<Integer, Integer> FONT_WIDTH = new HashMap<Integer, Integer>() {
+ private static final long serialVersionUID = 1L;
+ {
+ /** The conversions between TTF and PCL are not 1 to 1 **/
+ put(1, -5); // 1 = Ultra Compressed
+ put(2, -4); // 2 = Extra Compressed
+ put(3, -3); // 3 = Compresses
+ put(4, -2); // 4 = Condensed
+ put(5, 0); // 5 = Normal
+ put(6, 2); // 6 = Expanded
+ put(7, 3); // 5 = Extra Expanded
+ }
+ };
+
+ private int scaleFactor = -1;
+ private PCLSymbolSet symbolSet = PCLSymbolSet.Bound_Generic;
+
+ public PCLTTFFontReader(Typeface font, PCLByteWriterUtil pclByteWriter) throws IOException {
+ super(font, pclByteWriter);
+ loadFont();
+ }
+
+ protected void loadFont() throws IOException {
+ if (typeface instanceof CustomFontMetricsMapper) {
+ CustomFontMetricsMapper fontMetrics = (CustomFontMetricsMapper) typeface;
+ CustomFont font = (CustomFont) fontMetrics.getRealFont();
+ setFont((CustomFont) fontMetrics.getRealFont());
+ String fontName = font.getFullName();
+ fontStream = font.getInputStream();
+ reader = new FontFileReader(fontStream);
+
+ ttfFont = new TTFFile();
+ String header = OFFontLoader.readHeader(reader);
+ ttfFont.readFont(reader, header, fontName);
+ readFontTables();
+ } else {
+ // TODO - Handle when typeface is not in the expected format for a PCL TrueType object
+ }
+ }
+
+ protected void readFontTables() throws IOException {
+ PCLTTFTable fontTable;
+ fontTable = readFontTable(OFTableName.PCLT);
+ if (fontTable instanceof PCLTTFPCLTFontTable) {
+ pcltTable = (PCLTTFPCLTFontTable) fontTable;
+ }
+ fontTable = readFontTable(OFTableName.OS2);
+ if (fontTable instanceof PCLTTFOS2FontTable) {
+ os2Table = (PCLTTFOS2FontTable) fontTable;
+ }
+ fontTable = readFontTable(OFTableName.POST);
+ if (fontTable instanceof PCLTTFPOSTFontTable) {
+ postTable = (PCLTTFPOSTFontTable) fontTable;
+ }
+ }
+
+ private PCLTTFTable readFontTable(OFTableName tableName) throws IOException {
+ if (ttfFont.seekTab(reader, tableName, 0)) {
+ return getTTFTableFactory().newInstance(tableName);
+ }
+ return null;
+ }
+
+ private PCLTTFTableFactory getTTFTableFactory() {
+ if (ttfTableFactory == null) {
+ ttfTableFactory = PCLTTFTableFactory.getInstance(reader);
+ }
+ return ttfTableFactory;
+ }
+
+ @Override
+ public int getDescriptorSize() {
+ return 72; // Descriptor size (leave at 72 for our purposes)
+ }
+
+ @Override
+ public int getHeaderFormat() {
+ return 15; // TrueType Scalable Font
+ }
+
+ @Override
+ public int getFontType() {
+ if (symbolSet == PCLSymbolSet.Unbound) {
+ return 11; // Font Type - Unbound TrueType Scalable font
+ } else {
+ return 2; // 0-255 (except 0, 7 and 27)
+ }
+ }
+
+ @Override
+ public int getStyleMSB() {
+ if (pcltTable != null) {
+ return getMSB(pcltTable.getStyle());
+ }
+ return 3;
+ }
+
+ @Override
+ public int getBaselinePosition() {
+ return 0; // Baseline position must be set to 0 for TTF fonts
+ }
+
+ @Override
+ public int getCellWidth() {
+ int[] bbox = ttfFont.getBBoxRaw();
+ return bbox[2] - bbox[0];
+ }
+
+ @Override
+ public int getCellHeight() {
+ int[] bbox = ttfFont.getBBoxRaw();
+ return bbox[3] - bbox[1];
+ }
+
+ @Override
+ public int getOrientation() {
+ return 0; // Scalable fonts (TrueType) must be 0
+ }
+
+ @Override
+ public int getSpacing() {
+ if (os2Table != null) {
+ return (os2Table.getPanose()[4] == 9) ? 0 : 1;
+ } else if (postTable != null) {
+ return postTable.getIsFixedPitch();
+ }
+ return 1;
+ }
+
+ @Override
+ public int getSymbolSet() {
+ if (pcltTable != null) {
+ return pcltTable.getSymbolSet();
+ } else {
+ return symbolSet.getKind1();
+ }
+ }
+
+ @Override
+ public int getPitch() {
+ int pitch = ttfFont.getCharWidthRaw(0x20);
+ if (pitch < 0) {
+ // No advance width found for the space character
+ return 0;
+ }
+ return pitch;
+ }
+
+ @Override
+ public int getHeight() {
+ return 0; // Fixed zero value for TrueType fonts
+ }
+
+ @Override
+ public int getXHeight() {
+ if (pcltTable != null) {
+ return pcltTable.getXHeight();
+ } else if (os2Table != null) {
+ return os2Table.getXHeight();
+ }
+ return 0;
+ }
+
+ @Override
+ public int getWidthType() {
+ if (pcltTable != null) {
+ return pcltTable.getWidthType();
+ } else if (os2Table != null) {
+ return convertTTFWidthClass(os2Table.getWidthClass());
+ }
+ return 0;
+ }
+
+ private int convertTTFWidthClass(int widthClass) {
+ if (FONT_WIDTH.containsKey(widthClass)) {
+ return FONT_WIDTH.get(widthClass);
+ } else {
+ return 0; // No match - return normal
+ }
+ }
+
+ @Override
+ public int getStyleLSB() {
+ if (pcltTable != null) {
+ return getLSB(pcltTable.getStyle());
+ }
+ return 224;
+ }
+
+ @Override
+ public int getStrokeWeight() {
+ if (pcltTable != null) {
+ return pcltTable.getStrokeWeight();
+ } else if (os2Table != null) {
+ return convertTTFWeightClass(os2Table.getWeightClass());
+ }
+ return 0;
+ }
+
+ private int convertTTFWeightClass(int weightClass) {
+ if (FONT_WEIGHT.containsKey(weightClass)) {
+ return FONT_WEIGHT.get(weightClass);
+ } else {
+ return 0; // No match - return normal
+ }
+ }
+
+ @Override
+ public int getTypefaceLSB() {
+ if (pcltTable != null) {
+ return getLSB(pcltTable.getTypeFamily());
+ }
+ return 254;
+ }
+
+ @Override
+ public int getTypefaceMSB() {
+ if (pcltTable != null) {
+ return getMSB(pcltTable.getTypeFamily());
+ }
+ return 0;
+ }
+
+ @Override
+ public int getSerifStyle() {
+ if (pcltTable != null) {
+ return pcltTable.getSerifStyle();
+ } else {
+ return convertFromTTFSerifStyle();
+ }
+ }
+
+ private int convertFromTTFSerifStyle() {
+ if (os2Table != null) {
+ int serifStyle = os2Table.getPanose()[1];
+ return FONT_SERIF.get(serifStyle);
+ }
+ return 0;
+ }
+
+ @Override
+ public int getQuality() {
+ return 2; // Letter quality
+ }
+
+ @Override
+ public int getPlacement() {
+ return 0; // Fixed value of 0 for TrueType (scalable fonts)
+ }
+
+ @Override
+ public int getUnderlinePosition() {
+ return 0; // Scalable fonts has a fixed value of 0 - See Master Underline Position
+ }
+
+ @Override
+ public int getUnderlineThickness() {
+ return 0; // Scalable fonts has a fixed value of 0 - See Master Underline Thickness
+ }
+
+ @Override
+ public int getTextHeight() {
+ return 2048;
+ }
+
+ @Override
+ public int getTextWidth() {
+ if (os2Table != null) {
+ return os2Table.getAvgCharWidth();
+ }
+ return 0;
+ }
+
+ @Override
+ public int getFirstCode() {
+ return 32;
+ }
+
+ @Override
+ public int getLastCode() {
+ return 255; // Bound font with a maximum of 255 characters
+ }
+
+ @Override
+ public int getPitchExtended() {
+ return 0; // Zero for Scalable fonts
+ }
+
+ @Override
+ public int getHeightExtended() {
+ return 0; // Zero for Scalable fonts
+ }
+
+ @Override
+ public int getCapHeight() {
+ if (pcltTable != null) {
+ return pcltTable.getStrokeWeight();
+ } else if (os2Table != null) {
+ return os2Table.getCapHeight();
+ }
+ return 0;
+ }
+
+ @Override
+ public int getFontNumber() {
+ if (pcltTable != null) {
+ return (int) pcltTable.getFontNumber();
+ }
+ return 0;
+ }
+
+ @Override
+ public String getFontName() {
+ if (pcltTable != null) {
+ return pcltTable.getTypeface();
+ } else {
+ return ttfFont.getFullName();
+ }
+ }
+
+ @Override
+ public int getScaleFactor() throws IOException {
+ if (scaleFactor == -1) {
+ OFTableName headTag = OFTableName.HEAD;
+ if (ttfFont.seekTab(reader, headTag, 0)) {
+ reader.readTTFLong(); // Version
+ reader.readTTFLong(); // Font revision
+ reader.readTTFLong(); // Check sum adjustment
+ reader.readTTFLong(); // Magic number
+ reader.readTTFShort(); // Flags
+ scaleFactor = reader.readTTFUShort(); // Units per em
+ return scaleFactor;
+ }
+ } else {
+ return scaleFactor;
+ }
+ return 0;
+ }
+
+ @Override
+ public int getMasterUnderlinePosition() throws IOException {
+ return (int) Math.round(getScaleFactor() * 0.2);
+ }
+
+ @Override
+ public int getMasterUnderlineThickness() throws IOException {
+ return (int) Math.round(getScaleFactor() * 0.05);
+ }
+
+ @Override
+ public int getFontScalingTechnology() {
+ return 1; // TrueType scalable font
+ }
+
+ @Override
+ public int getVariety() {
+ return 0; // TrueType fonts must be set to zero
+ }
+
+ public List<PCLFontSegment> getFontSegments(Map<Character, Integer> mappedGlyphs)
+ throws IOException {
+ List<PCLFontSegment> fontSegments = new ArrayList<PCLFontSegment>();
+ fontSegments.add(new PCLFontSegment(SegmentID.CC, getCharacterComplement()));
+ fontSegments.add(new PCLFontSegment(SegmentID.PA, pclByteWriter.toByteArray(os2Table.getPanose())));
+ fontSegments.add(new PCLFontSegment(SegmentID.GT, getGlobalTrueTypeData(mappedGlyphs)));
+ fontSegments.add(new PCLFontSegment(SegmentID.CP, ttfFont.getCopyrightNotice().getBytes("US-ASCII")));
+ fontSegments.add(new PCLFontSegment(SegmentID.NULL, new byte[0]));
+ return fontSegments;
+ }
+
+ /**
+ * See Font Header Format 11-35 (Character Complement Array) in the PCL 5 Specification. Defined as an array of 8
+ * bytes specific to certain character sets. In this case specifying 0 for all values (default complement) means the
+ * font is compatible with any character sets. '110' on least significant bits signifies unicode. See specification
+ * for further customization.
+ */
+ private byte[] getCharacterComplement() {
+ byte[] ccUnicode = new byte[8];
+ ccUnicode[7] = 6;
+ return ccUnicode;
+ }
+
+ private byte[] getGlobalTrueTypeData(Map<Character, Integer> mappedGlyphs) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ List<TableOffset> tableOffsets = new ArrayList<TableOffset>();
+ // Version
+ baos.write(pclByteWriter.unsignedInt(1)); // Major
+ baos.write(pclByteWriter.unsignedInt(0)); // Minor
+ int numTables = 5; // head, hhea, hmtx, maxp and gdir
+ // Optional Hint Tables
+ OFDirTabEntry headTable = ttfFont.getDirectoryEntry(OFTableName.CVT);
+ if (headTable != null) {
+ numTables++;
+ }
+ OFDirTabEntry fpgmTable = ttfFont.getDirectoryEntry(OFTableName.FPGM);
+ if (fpgmTable != null) {
+ numTables++;
+ }
+ OFDirTabEntry prepTable = ttfFont.getDirectoryEntry(OFTableName.PREP);
+ if (prepTable != null) {
+ numTables++;
+ }
+ baos.write(pclByteWriter.unsignedInt(numTables)); // numTables
+ int maxPowerNumTables = pclByteWriter.maxPower2(numTables);
+ int searchRange = maxPowerNumTables * 16;
+ baos.write(pclByteWriter.unsignedInt(searchRange));
+ baos.write(pclByteWriter.unsignedInt(pclByteWriter.log(maxPowerNumTables, 2))); // Entry Selector
+ baos.write(pclByteWriter.unsignedInt(numTables * 16 - searchRange)); // Range shift
+
+ // Add default data tables
+ writeTrueTypeTable(baos, OFTableName.HEAD, tableOffsets);
+ writeTrueTypeTable(baos, OFTableName.HHEA, tableOffsets);
+ byte[] hmtxTable = createHmtx(mappedGlyphs);
+ writeSubsetHMTX(baos, OFTableName.HMTX, tableOffsets, hmtxTable);
+ writeTrueTypeTable(baos, OFTableName.MAXP, tableOffsets);
+ // Write the blank GDIR directory which is built in memory on the printer
+ writeGDIR(baos);
+
+ // Add optional data tables (for hints)
+ writeTrueTypeTable(baos, OFTableName.CVT, tableOffsets);
+ writeTrueTypeTable(baos, OFTableName.FPGM, tableOffsets);
+ writeTrueTypeTable(baos, OFTableName.PREP, tableOffsets);
+
+ baos = copyTables(tableOffsets, baos, hmtxTable, mappedGlyphs.size());
+
+ return baos.toByteArray();
+ }
+
+ private static class TableOffset {
+ private long originOffset;
+ private long originLength;
+ private int newOffset;
+
+ public TableOffset(long originOffset, long originLength, int newOffset) {
+ this.originOffset = originOffset;
+ this.originLength = originLength;
+ this.newOffset = newOffset;
+ }
+
+ public long getOriginOffset() {
+ return originOffset;
+ }
+
+ public long getOriginLength() {
+ return originLength;
+ }
+
+ public int getNewOffset() {
+ return newOffset;
+ }
+ }
+
+ private void writeTrueTypeTable(ByteArrayOutputStream baos, OFTableName table,
+ List<TableOffset> tableOffsets) throws IOException, UnsupportedEncodingException {
+ OFDirTabEntry tabEntry = ttfFont.getDirectoryEntry(table);
+ if (tabEntry != null) {
+ baos.write(tabEntry.getTag());
+ baos.write(pclByteWriter.unsignedLongInt(tabEntry.getChecksum()));
+ TableOffset newTableOffset = new TableOffset(tabEntry.getOffset(),
+ tabEntry.getLength(), baos.size());
+ tableOffsets.add(newTableOffset);
+ baos.write(pclByteWriter.unsignedLongInt(0)); // Offset to be set later
+ baos.write(pclByteWriter.unsignedLongInt(tabEntry.getLength()));
+ }
+ }
+
+ private void writeGDIR(ByteArrayOutputStream baos) throws UnsupportedEncodingException, IOException {
+ baos.write("gdir".getBytes("ISO-8859-1"));
+ baos.write(pclByteWriter.unsignedLongInt(0)); // Checksum
+ baos.write(pclByteWriter.unsignedLongInt(0)); // Offset
+ baos.write(pclByteWriter.unsignedLongInt(0)); // Length
+ }
+
+ private ByteArrayOutputStream copyTables(List<TableOffset> tableOffsets,
+ ByteArrayOutputStream baos, byte[] hmtxTable, int hmtxSize)
+ throws IOException {
+ Map<Integer, byte[]> offsetValues = new HashMap<Integer, byte[]>();
+ for (TableOffset tableOffset : tableOffsets) {
+ offsetValues.put(tableOffset.getNewOffset(), pclByteWriter.unsignedLongInt(baos.size()));
+ if (tableOffset.getOriginOffset() == -1) { // Update the offset in the table directory
+ baos.write(hmtxTable);
+ } else {
+ byte[] tableData = reader.getBytes((int) tableOffset.getOriginOffset(),
+ (int) tableOffset.getOriginLength());
+ int index = tableOffsets.indexOf(tableOffset);
+ if (index == 1) {
+ tableData = updateHHEA(tableData, hmtxSize + 33);
+ }
+
+ // Write the table data to the end of the TrueType segment output
+ baos.write(tableData);
+ }
+ }
+ baos = updateOffsets(baos, offsetValues);
+ return baos;
+ }
+
+ private byte[] updateHHEA(byte[] tableData, int hmtxSize) {
+ writeUShort(tableData, tableData.length - 2, hmtxSize);
+ return tableData;
+ }
+
+ private ByteArrayOutputStream updateOffsets(ByteArrayOutputStream baos, Map<Integer, byte[]> offsets)
+ throws IOException {
+ byte[] softFont = baos.toByteArray();
+ for (int offset : offsets.keySet()) {
+ pclByteWriter.updateDataAtLocation(softFont, offsets.get(offset), offset);
+ }
+ baos = new ByteArrayOutputStream();
+ baos.write(softFont);
+ return baos;
+ }
+
+ @Override
+ public Map<Integer, int[]> getCharacterOffsets() throws IOException {
+ List<OFMtxEntry> mtx = ttfFont.getMtx();
+ OFTableName glyfTag = OFTableName.GLYF;
+ Map<Integer, int[]> charOffsets = new HashMap<Integer, int[]>();
+ OFDirTabEntry tabEntry = ttfFont.getDirectoryEntry(glyfTag);
+ if (ttfFont.seekTab(reader, glyfTag, 0)) {
+ for (int i = 1; i < mtx.size(); i++) {
+ OFMtxEntry entry = mtx.get(i);
+ OFMtxEntry nextEntry;
+ int nextOffset = 0;
+ int charCode = 0;
+ if (entry.getUnicodeIndex().size() > 0) {
+ charCode = (Integer) entry.getUnicodeIndex().get(0);
+ } else {
+ charCode = entry.getIndex();
+ }
+
+ if (i < mtx.size() - 1) {
+ nextEntry = mtx.get(i + 1);
+ nextOffset = (int) nextEntry.getOffset();
+ } else {
+ nextOffset = (int) ttfFont.getLastGlyfLocation();
+ }
+ int glyphOffset = (int) entry.getOffset();
+ int glyphLength = nextOffset - glyphOffset;
+
+ charOffsets.put(charCode, new int[]{(int) tabEntry.getOffset() + glyphOffset, glyphLength});
+ }
+ }
+ return charOffsets;
+ }
+
+ @Override
+ public OpenFont getFontFile() {
+ return ttfFont;
+ }
+
+ @Override
+ public FontFileReader getFontFileReader() {
+ return reader;
+ }
+
+ private void writeSubsetHMTX(ByteArrayOutputStream baos, OFTableName table,
+ List<TableOffset> tableOffsets, byte[] hmtxTable) throws IOException {
+ OFDirTabEntry tabEntry = ttfFont.getDirectoryEntry(table);
+ if (tabEntry != null) {
+ baos.write(tabEntry.getTag());
+ // Override the original checksum for the subset version
+ baos.write(pclByteWriter.unsignedLongInt(getCheckSum(hmtxTable, 0, hmtxTable.length)));
+ TableOffset newTableOffset = new TableOffset(-1, hmtxTable.length, baos.size());
+ tableOffsets.add(newTableOffset);
+ baos.write(pclByteWriter.unsignedLongInt(0)); // Offset to be set later
+ baos.write(pclByteWriter.unsignedLongInt(hmtxTable.length));
+ }
+ }
+
+ protected static int getCheckSum(byte[] data, int start, int size) {
+ // All the tables here are aligned on four byte boundaries
+ // Add remainder to size if it's not a multiple of 4
+ int remainder = size % 4;
+ if (remainder != 0) {
+ size += remainder;
+ }
+
+ long sum = 0;
+
+ for (int i = 0; i < size; i += 4) {
+ long l = 0;
+ for (int j = 0; j < 4; j++) {
+ l <<= 8;
+ if (data.length > (start + i + j)) {
+ l |= data[start + i + j] & 0xff;
+ }
+ }
+ sum += l;
+ }
+ return (int) sum;
+ }
+
+ protected byte[] createHmtx(Map<Character, Integer> mappedGlyphs) throws IOException {
+ byte[] hmtxTable = new byte[((mappedGlyphs.size() + 32) * 4)];
+ OFDirTabEntry entry = ttfFont.getDirectoryEntry(OFTableName.HMTX);
+
+ if (entry != null) {
+ for (Entry<Character, Integer> glyphSubset : mappedGlyphs.entrySet()) {
+ char unicode = glyphSubset.getKey();
+ int originalIndex = 0;
+ int softFontGlyphIndex = glyphSubset.getValue();
+ if (font instanceof MultiByteFont) {
+ originalIndex = ((MultiByteFont) font).getGIDFromChar(unicode);
+
+ writeUShort(hmtxTable, (softFontGlyphIndex) * 4,
+ ttfFont.getMtx().get(originalIndex).getWx());
+ writeUShort(hmtxTable, (softFontGlyphIndex) * 4 + 2,
+ ttfFont.getMtx().get(originalIndex).getLsb());
+ } else {
+ originalIndex = ((SingleByteFont) font).getGIDFromChar(unicode);
+
+ writeUShort(hmtxTable, (softFontGlyphIndex) * 4,
+ ((SingleByteFont) font).getWidth(originalIndex, 1));
+ writeUShort(hmtxTable, (softFontGlyphIndex) * 4 + 2, 0);
+ }
+ }
+ }
+ return hmtxTable;
+ }
+
+ /**
+ * Appends a USHORT to the output array, updates currentPost but not realSize
+ */
+ private void writeUShort(byte[] out, int offset, int s) {
+ byte b1 = (byte) ((s >> 8) & 0xff);
+ byte b2 = (byte) (s & 0xff);
+ out[offset] = b1;
+ out[offset + 1] = b2;
+ }
+} \ No newline at end of file
diff --git a/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFOS2FontTable.java b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFOS2FontTable.java
new file mode 100644
index 000000000..4c5f98d8b
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFOS2FontTable.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts.truetype;
+
+import java.io.IOException;
+
+import org.apache.fop.fonts.truetype.FontFileReader;
+
+public class PCLTTFOS2FontTable extends PCLTTFTable {
+ private int avgCharWidth;
+ private int xHeight;
+ private int widthClass;
+ private int weightClass;
+ private int capHeight;
+ private int[] panose = new int[10];
+
+ public PCLTTFOS2FontTable(FontFileReader in) throws IOException {
+ super(in);
+ int version = reader.readTTFUShort(); // Version
+ avgCharWidth = reader.readTTFShort();
+ weightClass = reader.readTTFShort();
+ widthClass = reader.readTTFShort();
+ skipShort(reader, 12);
+ for (int i = 0; i < 10; i++) {
+ panose[i] = reader.readTTFByte();
+ }
+ skipLong(reader, 4);
+ skipByte(reader, 4);
+ skipShort(reader, 8);
+ if (version >= 2) {
+ skipLong(reader, 2);
+ xHeight = reader.readTTFShort();
+ capHeight = reader.readTTFShort();
+ }
+ }
+
+ public int getAvgCharWidth() {
+ return avgCharWidth;
+ }
+
+ public int getXHeight() {
+ return xHeight;
+ }
+
+ public int getWidthClass() {
+ return widthClass;
+ }
+
+ public int getWeightClass() {
+ return weightClass;
+ }
+
+ public int getCapHeight() {
+ return capHeight;
+ }
+
+ public int[] getPanose() {
+ return panose;
+ }
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFPCLTFontTable.java b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFPCLTFontTable.java
new file mode 100644
index 000000000..5be46a4ec
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFPCLTFontTable.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts.truetype;
+
+import java.io.IOException;
+
+import org.apache.fop.fonts.truetype.FontFileReader;
+
+public class PCLTTFPCLTFontTable extends PCLTTFTable {
+ private long version;
+ private long fontNumber;
+ private int pitch;
+ private int xHeight;
+ private int style;
+ private int typeFamily;
+ private int capHeight;
+ private int symbolSet;
+ private String typeface;
+ private String characterComplement;
+ private String filename;
+ private int strokeWeight;
+ private int widthType;
+ private int serifStyle;
+
+ public PCLTTFPCLTFontTable(FontFileReader in) throws IOException {
+ super(in);
+ version = reader.readTTFULong();
+ fontNumber = reader.readTTFULong();
+ pitch = reader.readTTFUShort();
+ xHeight = reader.readTTFUShort();
+ style = reader.readTTFUShort();
+ typeFamily = reader.readTTFUShort();
+ capHeight = reader.readTTFUShort();
+ symbolSet = reader.readTTFUShort();
+ typeface = reader.readTTFString(16);
+ characterComplement = reader.readTTFString(8);
+ filename = reader.readTTFString(6);
+ strokeWeight = reader.readTTFUShort();
+ widthType = reader.readTTFUShort();
+ serifStyle = reader.readTTFUByte();
+ }
+
+ public long getVersion() {
+ return version;
+ }
+
+ public long getFontNumber() {
+ return fontNumber;
+ }
+
+ public int getPitch() {
+ return pitch;
+ }
+
+ public int getXHeight() {
+ return xHeight;
+ }
+
+ public int getStyle() {
+ return style;
+ }
+
+ public int getTypeFamily() {
+ return typeFamily;
+ }
+
+ public int getCapHeight() {
+ return capHeight;
+ }
+
+ public int getSymbolSet() {
+ return symbolSet;
+ }
+
+ public String getTypeface() {
+ return typeface;
+ }
+
+ public String getCharacterComplement() {
+ return characterComplement;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public int getStrokeWeight() {
+ return strokeWeight;
+ }
+
+ public int getWidthType() {
+ return widthType;
+ }
+
+ public int getSerifStyle() {
+ return serifStyle;
+ }
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFPOSTFontTable.java b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFPOSTFontTable.java
new file mode 100644
index 000000000..9995f7f55
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFPOSTFontTable.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts.truetype;
+
+import java.io.IOException;
+
+import org.apache.fop.fonts.truetype.FontFileReader;
+
+public class PCLTTFPOSTFontTable extends PCLTTFTable {
+ private int underlinePosition;
+ private int underlineThickness;
+ private int isFixedPitch;
+
+ public PCLTTFPOSTFontTable(FontFileReader in) throws IOException {
+ super(in);
+ reader.readTTFLong(); // Version
+ reader.readTTFLong(); // Italic Angle
+ underlinePosition = reader.readTTFShort();
+ underlineThickness = reader.readTTFShort();
+ isFixedPitch = (int) reader.readTTFULong();
+ }
+
+ public int getUnderlinePosition() {
+ return underlinePosition;
+ }
+
+ public int getUnderlineThickness() {
+ return underlineThickness;
+ }
+
+ public int getIsFixedPitch() {
+ return isFixedPitch;
+ }
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFTable.java b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFTable.java
new file mode 100644
index 000000000..cfe866474
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFTable.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts.truetype;
+
+import java.io.IOException;
+
+import org.apache.fop.fonts.truetype.FontFileReader;
+
+public class PCLTTFTable {
+ protected FontFileReader reader;
+
+ public PCLTTFTable(FontFileReader reader) {
+ this.reader = reader;
+ }
+
+ protected void skipShort(FontFileReader reader, int skips)
+ throws IOException {
+ reader.skip(skips * 2);
+ }
+
+ protected void skipLong(FontFileReader reader, int skips)
+ throws IOException {
+ reader.skip(skips * 4);
+ }
+
+ protected void skipByte(FontFileReader reader, int skips)
+ throws IOException {
+ reader.skip(skips);
+ }
+}
diff --git a/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFTableFactory.java b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFTableFactory.java
new file mode 100644
index 000000000..e72563e96
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFTableFactory.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl.fonts.truetype;
+
+import java.io.IOException;
+
+import org.apache.fop.fonts.truetype.FontFileReader;
+import org.apache.fop.fonts.truetype.OFTableName;
+
+public final class PCLTTFTableFactory {
+ private FontFileReader reader;
+
+ private PCLTTFTableFactory(FontFileReader reader) {
+ this.reader = reader;
+ }
+
+ public static PCLTTFTableFactory getInstance(FontFileReader reader) {
+ return new PCLTTFTableFactory(reader);
+ }
+
+ public PCLTTFTable newInstance(OFTableName tableName)
+ throws IOException {
+ if (tableName == OFTableName.PCLT) {
+ return new PCLTTFPCLTFontTable(reader);
+ } else if (tableName == OFTableName.OS2) {
+ return new PCLTTFOS2FontTable(reader);
+ } else if (tableName == OFTableName.POST) {
+ return new PCLTTFPOSTFontTable(reader);
+ }
+ return null;
+ }
+}