in fop-core/src/main/java/org/apache/fop/fonts/truetype/OpenFont.java [451:720]
private boolean readUnicodeCmap(long cmapUniOffset, int encodingID)
throws IOException {
//Read CMAP table and correct mtxTab.index
int mtxPtr = 0;
// Read unicode cmap
seekTab(fontFile, OFTableName.CMAP, cmapUniOffset);
int cmapFormat = fontFile.readTTFUShort();
if (cmapFormat < 8) {
fontFile.readTTFUShort(); //skip cmap length
fontFile.readTTFUShort(); //skip cmap version
} else {
fontFile.readTTFUShort(); //skip 2 bytes to read a Fixed32
fontFile.readTTFULong(); //skip cmap length
fontFile.readTTFULong(); //skip cmap version
}
if (log.isDebugEnabled()) {
log.debug("CMAP format: " + cmapFormat);
}
if (cmapFormat == 4) {
int cmapSegCountX2 = fontFile.readTTFUShort();
int cmapSearchRange = fontFile.readTTFUShort();
int cmapEntrySelector = fontFile.readTTFUShort();
int cmapRangeShift = fontFile.readTTFUShort();
if (log.isDebugEnabled()) {
log.debug("segCountX2 : " + cmapSegCountX2);
log.debug("searchRange : " + cmapSearchRange);
log.debug("entrySelector: " + cmapEntrySelector);
log.debug("rangeShift : " + cmapRangeShift);
}
int[] cmapEndCounts = new int[cmapSegCountX2 / 2];
int[] cmapStartCounts = new int[cmapSegCountX2 / 2];
int[] cmapDeltas = new int[cmapSegCountX2 / 2];
int[] cmapRangeOffsets = new int[cmapSegCountX2 / 2];
for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
cmapEndCounts[i] = fontFile.readTTFUShort();
}
fontFile.skip(2); // Skip reservedPad
for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
cmapStartCounts[i] = fontFile.readTTFUShort();
}
for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
cmapDeltas[i] = fontFile.readTTFShort();
}
//int startRangeOffset = in.getCurrentPos();
for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
cmapRangeOffsets[i] = fontFile.readTTFUShort();
}
int glyphIdArrayOffset = fontFile.getCurrentPos();
BitSet eightBitGlyphs = new BitSet(256);
// Insert the unicode id for the glyphs in mtxTab
// and fill in the cmaps ArrayList
for (int i = 0; i < cmapStartCounts.length; i++) {
if (log.isTraceEnabled()) {
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++) {
// Update lastChar
if (j < 256 && j > lastChar) {
lastChar = (short)j;
}
if (j < 256) {
eightBitGlyphs.set(j);
}
if (mtxPtr < mtxTab.length) {
int glyphIdx;
// the last character 65535 = .notdef
// may have a range offset
if (cmapRangeOffsets[i] != 0 && j != 65535) {
int glyphOffset = glyphIdArrayOffset
+ ((cmapRangeOffsets[i] / 2)
+ (j - cmapStartCounts[i])
+ (i)
- cmapSegCountX2 / 2) * 2;
fontFile.seekSet(glyphOffset);
glyphIdx = (fontFile.readTTFUShort() + cmapDeltas[i])
& 0xffff;
//mtxTab[glyphIdx].setName(mtxTab[glyphIdx].getName() + " - "+(char)j);
unicodeMappings.add(new UnicodeMapping(this, glyphIdx, j));
mtxTab[glyphIdx].getUnicodeIndex().add(j);
mapSymbol(encodingID, j, eightBitGlyphs, glyphIdx);
// Also add winAnsiWidth
List<Integer> v = ansiIndex.get(j);
if (v != null) {
for (Integer aIdx : v) {
ansiWidth[aIdx]
= mtxTab[glyphIdx].getWx();
if (log.isTraceEnabled()) {
log.trace("Added width "
+ mtxTab[glyphIdx].getWx()
+ " uni: " + j
+ " ansi: " + aIdx);
}
}
}
if (log.isTraceEnabled()) {
log.trace("Idx: "
+ glyphIdx
+ " Delta: " + cmapDeltas[i]
+ " Unicode: " + j
+ " name: " + mtxTab[glyphIdx].getName());
}
} else {
glyphIdx = (j + cmapDeltas[i]) & 0xffff;
if (glyphIdx < mtxTab.length) {
mtxTab[glyphIdx].getUnicodeIndex().add(j);
} else {
log.debug("Glyph " + glyphIdx
+ " out of range: "
+ mtxTab.length);
}
unicodeMappings.add(new UnicodeMapping(this, glyphIdx, j));
if (glyphIdx < mtxTab.length) {
mtxTab[glyphIdx].getUnicodeIndex().add(j);
} else {
log.debug("Glyph " + glyphIdx
+ " out of range: "
+ mtxTab.length);
}
mapSymbol(encodingID, j, eightBitGlyphs, glyphIdx);
// Also add winAnsiWidth
List<Integer> v = ansiIndex.get(j);
if (v != null) {
for (Integer aIdx : v) {
ansiWidth[aIdx] = mtxTab[glyphIdx].getWx();
}
}
//getLogger().debug("IIdx: " +
// mtxPtr +
// " Delta: " + cmap_deltas[i] +
// " Unicode: " + j +
// " name: " +
// mtxTab[(j+cmap_deltas[i]) & 0xffff].name);
}
if (glyphIdx < mtxTab.length) {
if (mtxTab[glyphIdx].getUnicodeIndex().size() < 2) {
mtxPtr++;
}
}
}
}
}
} else if (cmapFormat == 12) {
long nGroups = fontFile.readTTFULong();
for (long i = 0; i < nGroups; ++i) {
long startCharCode = fontFile.readTTFULong();
long endCharCode = fontFile.readTTFULong();
long startGlyphCode = fontFile.readTTFULong();
if (startCharCode < 0 || startCharCode > 0x10FFFFL) {
log.warn("startCharCode outside Unicode range");
continue;
}
if (startCharCode >= 0xD800 && startCharCode <= 0xDFFF) {
log.warn("startCharCode is a surrogate pair: " + startCharCode);
}
//endCharCode outside unicode range or is surrogate pair.
if (endCharCode > 0 && endCharCode < startCharCode || endCharCode > 0x10FFFFL) {
log.warn("startCharCode outside Unicode range");
continue;
}
if (endCharCode >= 0xD800 && endCharCode <= 0xDFFF) {
log.warn("endCharCode is a surrogate pair: " + startCharCode);
}
for (long offset = 0; offset <= endCharCode - startCharCode; ++offset) {
long glyphIndexL = startGlyphCode + offset;
long charCodeL = startCharCode + offset;
if (glyphIndexL >= numberOfGlyphs) {
log.warn("Format 12 cmap contains an invalid glyph index");
break;
}
if (charCodeL > 0x10FFFFL) {
log.warn("Format 12 cmap contains character beyond UCS-4");
}
if (glyphIndexL > Integer.MAX_VALUE) {
log.error("glyphIndex > Integer.MAX_VALUE");
continue;
}
if (charCodeL > Integer.MAX_VALUE) {
log.error("startCharCode + j > Integer.MAX_VALUE");
continue;
}
// Update lastChar
if (charCodeL < 0xFF && charCodeL > lastChar) {
lastChar = (short) charCodeL;
}
int charCode = (int) charCodeL;
int glyphIndex = (int) glyphIndexL;
// Also add winAnsiWidth.
List<Integer> ansiIndexes = null;
if (charCodeL <= Character.MAX_VALUE) {
ansiIndexes = ansiIndex.get((int) charCodeL);
}
unicodeMappings.add(new UnicodeMapping(this, glyphIndex, charCode));
mtxTab[glyphIndex].getUnicodeIndex().add(charCode);
if (ansiIndexes == null) {
continue;
}
for (Integer aIdx : ansiIndexes) {
ansiWidth[aIdx] = mtxTab[glyphIndex].getWx();
if (log.isTraceEnabled()) {
log.trace("Added width "
+ mtxTab[glyphIndex].getWx()
+ " uni: " + offset
+ " ansi: " + aIdx);
}
}
}
}
} else {
log.error("Cmap format not supported: " + cmapFormat);
return false;
}
return true;
}