Author: jeremias
Date: Wed Dec 16 10:47:04 2009
New Revision: 891181
URL: http://svn.apache.org/viewvc?rev=891181&view=rev
Log:
Added support for TrueType fonts with symbol character maps (like "Wingdings"
and "Symbol"). Characters for these fonts are usually found in the 0xF020 to
0xF0FF range (a Unicode private use area).
There's also experimental support to additionally map these characters into the
0x0020 to 0x00FF range if no characters are mapped in this area. That means
that that, for example, Wingdings' pen symbol can be accessed using 0xF021 and
0x0021.
Modified:
xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFile.java
xmlgraphics/fop/trunk/status.xml
Modified:
xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFile.java
URL:
http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFile.java?rev=891181&r1=891180&r2=891181&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFile.java
(original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fonts/truetype/TTFFile.java
Wed Dec 16 10:47:04 2009
@@ -20,6 +20,7 @@
package org.apache.fop.fonts.truetype;
import java.io.IOException;
+import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -206,12 +207,10 @@
unicodeMapping = new java.util.ArrayList();
- //Read CMAP table and correct mtxTab.index
- int mtxPtr = 0;
-
seekTab(in, "cmap", 2);
int numCMap = in.readTTFUShort(); // Number of cmap subtables
long cmapUniOffset = 0;
+ long symbolMapOffset = 0;
if (log.isDebugEnabled()) {
log.debug(numCMap + " cmap tables");
@@ -230,12 +229,26 @@
if (cmapPID == 3 && cmapEID == 1) {
cmapUniOffset = cmapOffset;
}
+ if (cmapPID == 3 && cmapEID == 0) {
+ symbolMapOffset = cmapOffset;
+ }
}
- if (cmapUniOffset <= 0) {
- log.fatal("Unsupported TrueType font: Unicode cmap table not
present. Aborting");
+ if (cmapUniOffset > 0) {
+ return readUnicodeCmap(in, cmapUniOffset, 1);
+ } else if (symbolMapOffset > 0) {
+ return readUnicodeCmap(in, symbolMapOffset, 0);
+ } else {
+ log.fatal("Unsupported TrueType font: No Unicode or Symbol cmap
table"
+ + " not present. Aborting");
return false;
}
+ }
+
+ private boolean readUnicodeCmap(FontFileReader in, long cmapUniOffset, int
encodingID)
+ throws IOException {
+ //Read CMAP table and correct mtxTab.index
+ int mtxPtr = 0;
// Read unicode cmap
seekTab(in, "cmap", cmapUniOffset);
@@ -288,6 +301,8 @@
int glyphIdArrayOffset = in.getCurrentPos();
+ BitSet eightBitGlyphs = new BitSet(256);
+
// Insert the unicode id for the glyphs in mtxTab
// and fill in the cmaps ArrayList
@@ -297,6 +312,13 @@
log.trace(i + ": " + cmapStartCounts[i]
+ " - " +
cmapEndCounts[i]);
}
+ if (log.isDebugEnabled()) {
+ if (isInPrivateUseArea(cmapStartCounts[i],
cmapEndCounts[i])) {
+ log.debug("Font contains glyphs in the Unicode private
use area: "
+ + Integer.toHexString(cmapStartCounts[i]) + "
- "
+ + Integer.toHexString(cmapEndCounts[i]));
+ }
+ }
for (int j = cmapStartCounts[i]; j <= cmapEndCounts[i]; j++) {
@@ -305,6 +327,10 @@
lastChar = (short)j;
}
+ if (j < 256) {
+ eightBitGlyphs.set(j);
+ }
+
if (mtxPtr < mtxTab.length) {
int glyphIdx;
// the last character 65535 = .notdef
@@ -322,6 +348,17 @@
unicodeMapping.add(new UnicodeMapping(glyphIdx,
j));
mtxTab[glyphIdx].getUnicodeIndex().add(new
Integer(j));
+ if (encodingID == 0 && j >= 0xF020 && j <= 0xF0FF)
{
+ //Experimental: Mapping 0xF020-0xF0FF to
0x0020-0x00FF
+ //Tested with Wingdings and Symbol TTF fonts
which map their
+ //glyphs in the region 0xF020-0xF0FF.
+ int mapped = j - 0xF000;
+ if (!eightBitGlyphs.get(mapped)) {
+ //Only map if Unicode code point hasn't
been mapped before
+ unicodeMapping.add(new
UnicodeMapping(glyphIdx, mapped));
+ mtxTab[glyphIdx].getUnicodeIndex().add(new
Integer(mapped));
+ }
+ }
// Also add winAnsiWidth
List v = (List)ansiIndex.get(new Integer(j));
@@ -394,10 +431,21 @@
}
}
}
+ } else {
+ log.error("Cmap format not supported: " + cmapFormat);
+ return false;
}
return true;
}
+ private boolean isInPrivateUseArea(int start, int end) {
+ return (isInPrivateUseArea(start) || isInPrivateUseArea(end));
+ }
+
+ private boolean isInPrivateUseArea(int unicode) {
+ return (unicode >= 0xE000 && unicode <= 0xF8FF);
+ }
+
/**
* Print first char/last char
*/
@@ -803,9 +851,15 @@
* @throws IOException in case of an I/O problem
*/
protected void readFontHeader(FontFileReader in) throws IOException {
- seekTab(in, "head", 2 * 4 + 2 * 4 + 2);
+ seekTab(in, "head", 2 * 4 + 2 * 4);
+ int flags = in.readTTFUShort();
+ if (log.isDebugEnabled()) {
+ log.debug("flags: " + flags + " - " + Integer.toString(flags, 2));
+ }
upem = in.readTTFUShort();
- log.debug("unit per em: " + upem);
+ if (log.isDebugEnabled()) {
+ log.debug("unit per em: " + upem);
+ }
in.skip(16);
@@ -813,6 +867,12 @@
fontBBox2 = in.readTTFShort();
fontBBox3 = in.readTTFShort();
fontBBox4 = in.readTTFShort();
+ if (log.isDebugEnabled()) {
+ log.debug("font bbox: xMin=" + fontBBox1
+ + " yMin=" + fontBBox2
+ + " xMax=" + fontBBox3
+ + " yMax=" + fontBBox4);
+ }
in.skip(2 + 2 + 2);
@@ -841,15 +901,16 @@
throws IOException {
seekTab(in, "hhea", 4);
hheaAscender = in.readTTFShort();
- log.debug("hhea.Ascender: " + hheaAscender + " " +
convertTTFUnit2PDFUnit(hheaAscender));
hheaDescender = in.readTTFShort();
- log.debug("hhea.Descender: " + hheaDescender + " " +
convertTTFUnit2PDFUnit(hheaDescender));
in.skip(2 + 2 + 3 * 2 + 8 * 2);
nhmtx = in.readTTFUShort();
- log.debug("Number of horizontal metrics: " + nhmtx);
-
+ if (log.isDebugEnabled()) {
+ log.debug("hhea.Ascender: " + formatUnitsForDebug(hheaAscender));
+ log.debug("hhea.Descender: " + formatUnitsForDebug(hheaDescender));
+ log.debug("Number of horizontal metrics: " + nhmtx);
+ }
}
/**
@@ -1013,17 +1074,23 @@
int v;
os2Ascender = in.readTTFShort(); //sTypoAscender
os2Descender = in.readTTFShort(); //sTypoDescender
- v = in.readTTFShort(); //sTypoLineGap
- v = in.readTTFUShort(); //usWinAscent
- v = in.readTTFUShort(); //usWinDescent
if (log.isDebugEnabled()) {
log.debug("sTypoAscender: " + os2Ascender
- + " " + convertTTFUnit2PDFUnit(os2Ascender));
+ + " -> internal " +
convertTTFUnit2PDFUnit(os2Ascender));
log.debug("sTypoDescender: " + os2Descender
- + " " + convertTTFUnit2PDFUnit(os2Descender));
+ + " -> internal " +
convertTTFUnit2PDFUnit(os2Descender));
+ }
+ v = in.readTTFShort(); //sTypoLineGap
+ if (log.isDebugEnabled()) {
log.debug("sTypoLineGap: " + v);
- log.debug("usWinAscent: " + v + " " +
convertTTFUnit2PDFUnit(v));
- log.debug("usWinDescent: " + v + " " +
convertTTFUnit2PDFUnit(v));
+ }
+ v = in.readTTFUShort(); //usWinAscent
+ if (log.isDebugEnabled()) {
+ log.debug("usWinAscent: " + formatUnitsForDebug(v));
+ }
+ v = in.readTTFUShort(); //usWinDescent
+ if (log.isDebugEnabled()) {
+ log.debug("usWinDescent: " + formatUnitsForDebug(v));
}
//version 1 OS/2 table might end here
@@ -1197,12 +1264,10 @@
if (dirTab != null) {
in.seekSet(dirTab.getOffset() + 4 + 4 + 2);
xHeight = in.readTTFUShort();
- log.debug("xHeight from PCLT: " + xHeight
- + " " + convertTTFUnit2PDFUnit(xHeight));
+ log.debug("xHeight from PCLT: " + formatUnitsForDebug(xHeight));
in.skip(2 * 2);
capHeight = in.readTTFUShort();
- log.debug("capHeight from PCLT: " + capHeight
- + " " + convertTTFUnit2PDFUnit(capHeight));
+ log.debug("capHeight from PCLT: " +
formatUnitsForDebug(capHeight));
in.skip(2 + 16 + 8 + 6 + 1 + 1);
int serifStyle = in.readTTFUByte();
@@ -1296,10 +1361,8 @@
}
}
if (log.isDebugEnabled()) {
- log.debug("Ascender from glyph 'd': " + localAscender
- + " " + convertTTFUnit2PDFUnit(localAscender));
- log.debug("Descender from glyph 'p': " + localDescender
- + " " + convertTTFUnit2PDFUnit(localDescender));
+ log.debug("Ascender from glyph 'd': " +
formatUnitsForDebug(localAscender));
+ log.debug("Descender from glyph 'p': " +
formatUnitsForDebug(localDescender));
}
if (ascender - descender > upem) {
log.debug("Replacing specified ascender/descender with derived
values to get values"
@@ -1309,10 +1372,8 @@
}
if (log.isDebugEnabled()) {
- log.debug("xHeight from glyph 'x': " + localXHeight
- + " " + convertTTFUnit2PDFUnit(localXHeight));
- log.debug("CapHeight from glyph 'H': " + localCapHeight
- + " " + convertTTFUnit2PDFUnit(localCapHeight));
+ log.debug("xHeight from glyph 'x': " +
formatUnitsForDebug(localXHeight));
+ log.debug("CapHeight from glyph 'H': " +
formatUnitsForDebug(localCapHeight));
}
if (capHeight == 0) {
capHeight = localCapHeight;
@@ -1598,6 +1659,10 @@
+ (int)convertTTFUnit2PDFUnit(fontBBox4) + "]");
}
+ private String formatUnitsForDebug(int units) {
+ return units + " -> " + convertTTFUnit2PDFUnit(units) + " internal
units";
+ }
+
/**
* Map a glyph index to the corresponding unicode code point
*
Modified: xmlgraphics/fop/trunk/status.xml
URL:
http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/status.xml?rev=891181&r1=891180&r2=891181&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/status.xml (original)
+++ xmlgraphics/fop/trunk/status.xml Wed Dec 16 10:47:04 2009
@@ -58,6 +58,14 @@
documents. Example: the fix of marks layering will be such a case when
it's done.
-->
<release version="FOP Trunk" date="TBD">
+ <action context="Fonts" dev="JM" type="add">
+ Added support for TrueType fonts with symbol character maps (like
"Wingdings" and "Symbol").
+ Character for these fonts are usually found in the 0xF020 to 0xF0FF
range
+ (a Unicode private use area).
+ </action>
+ <action context="Fonts" dev="JM" type="fix">
+ Bugfix: Font selection fallbacks did not work in some cases (ex.
bold+italic to normal)
+ </action>
<action context="Renderers" dev="CB" type="fix" fixes-bug="48290">
Bugfix: AFP Renderer: AttributeQualifier Triplet occurs before TLE
Value.
</action>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]