CMapFormat0(Buffer buffer, int offset) { /* skip 6 bytes of format, length, and version */ int len = buffer.getChar(offset + 2); cmap = new byte[len - 6]; buffer.get(offset + 6, cmap, 0, len - 6); }
static CMap createCMap(Buffer buffer, int offset) { /* First do a sanity check that this cmap subtable is contained * within the cmap table. */ int subtableFormat = buffer.getChar(offset); switch (subtableFormat) { case 0: return new CMapFormat0(buffer, offset); case 2: return new CMapFormat2(buffer, offset); case 4: return new CMapFormat4(buffer, offset); case 6: return new CMapFormat6(buffer, offset); case 8: return new CMapFormat8(buffer, offset); case 10: return new CMapFormat10(buffer, offset); case 12: return new CMapFormat12(buffer, offset); default: throw new RuntimeException("Cmap format unimplemented: " + (int) buffer.getChar(offset)); } }
CMapFormat10(Buffer buffer, int offset) { buffer.position(offset + 12); startCharCode = buffer.getInt() & INTMASK; numChars = buffer.getInt() & INTMASK; glyphIdArray = new char[numChars]; for (int i = 0; i < numChars; i++) { glyphIdArray[i] = buffer.getChar(); } }
CMapFormat6(Buffer buffer, int offset) { buffer.position(offset + 6); firstCode = buffer.getChar(); entryCount = buffer.getChar(); glyphIdArray = new char[entryCount]; for (int i = 0; i < entryCount; i++) { glyphIdArray[i] = buffer.getChar(); } }
CMapFormat2(Buffer buffer, int offset) { int tableLen = buffer.getChar(offset + 2); buffer.position(offset + 6); char maxSubHeader = 0; for (int i = 0; i < 256; i++) { subHeaderKey[i] = buffer.getChar(); if (subHeaderKey[i] > maxSubHeader) { maxSubHeader = subHeaderKey[i]; } } /* The value of the subHeaderKey is 8 * the subHeader index, * so the number of subHeaders can be obtained by dividing * this value bv 8 and adding 1. */ int numSubHeaders = (maxSubHeader >> 3) + 1; firstCodeArray = new char[numSubHeaders]; entryCountArray = new char[numSubHeaders]; idDeltaArray = new short[numSubHeaders]; idRangeOffSetArray = new char[numSubHeaders]; for (int i = 0; i < numSubHeaders; i++) { firstCodeArray[i] = buffer.getChar(); entryCountArray[i] = buffer.getChar(); idDeltaArray[i] = (short) buffer.getChar(); idRangeOffSetArray[i] = buffer.getChar(); } int glyphIndexArrSize = (tableLen - 518 - numSubHeaders * 8) / 2; glyphIndexArray = new char[glyphIndexArrSize]; for (int i = 0; i < glyphIndexArrSize; i++) { glyphIndexArray[i] = buffer.getChar(); } }
CMapFormat12(Buffer buffer, int offset) { numGroups = buffer.getInt(offset + 12); startCharCode = new long[numGroups]; endCharCode = new long[numGroups]; startGlyphID = new int[numGroups]; buffer.position(offset + 16); // REMIND: why slice ? // buffer = buffer.slice(); for (int i = 0; i < numGroups; i++) { startCharCode[i] = buffer.getInt() & INTMASK; endCharCode[i] = buffer.getInt() & INTMASK; startGlyphID[i] = buffer.getInt() & INTMASK; } /* Finds the high bit by binary searching through the bits */ int value = numGroups; if (value >= 1 << 16) { value >>= 16; highBit += 16; } if (value >= 1 << 8) { value >>= 8; highBit += 8; } if (value >= 1 << 4) { value >>= 4; highBit += 4; } if (value >= 1 << 2) { value >>= 2; highBit += 2; } if (value >= 1 << 1) { value >>= 1; highBit += 1; } power = 1 << highBit; extra = numGroups - power; }
static CMap initialize(PrismFontFile font) { CMap cmap = null; int offset, platformID, encodingID = -1; int three0 = 0, three1 = 0, three10 = 0, zeroStarOffset = 0; boolean zeroStar = false, threeStar = false; Buffer cmapBuffer = font.readTable(FontConstants.cmapTag); short numberSubTables = cmapBuffer.getShort(2); /* Locate the offsets of supported 3,* Microsoft platform encodings, * and any 0,* Unicode platform encoding. The latter is used by * all current OS X fonts that don't have a Microsoft cmap. * We will always prefer the Microsoft cmap, for the fonts that * provide both. They ought to perform the same mappings. Although * I can imagine that a vendor might provide a different looking * glyph for some special characters for OS X vs Windows, I'm not * actually aware of any such case. */ for (int i = 0; i < numberSubTables; i++) { cmapBuffer.position(i * 8 + 4); platformID = cmapBuffer.getShort(); if (platformID == 0) { zeroStar = true; encodingID = cmapBuffer.getShort(); zeroStarOffset = cmapBuffer.getInt(); } else if (platformID == 3) { threeStar = true; encodingID = cmapBuffer.getShort(); offset = cmapBuffer.getInt(); switch (encodingID) { case 0: three0 = offset; break; // MS Symbol encoding case 1: three1 = offset; break; // MS Unicode cmap case 10: three10 = offset; break; // MS Unicode surrogates } } } /* This defines the preference order for cmap subtables */ if (threeStar) { if (three10 != 0) { cmap = createCMap(cmapBuffer, three10); } else if (three0 != 0) { cmap = createCMap(cmapBuffer, three0); } else if (three1 != 0) { cmap = createCMap(cmapBuffer, three1); } } else if (zeroStar && zeroStarOffset != 0) { cmap = createCMap(cmapBuffer, zeroStarOffset); } else { /* No 0,* or supported 3,* subtable was found. * Use whatever is the first table listed. * Since these are supposed to be sorted, there's a good chance * it will be Mac Roman (1,0). If its not that then its * likely a really old font but not one that's found on either * Windows or OS X * In fact I didn't even find any OS X font that supported * only (1,*). * So this seems likely to be an untravelled path which is * just as well given that its not likely to work properly. */ cmap = createCMap(cmapBuffer, cmapBuffer.getInt(8)); } return cmap; }
CMapFormat4(Buffer buffer, int offset) { buffer.position(offset); buffer.getChar(); // skip, we already know format=4 int subtableLength = buffer.getChar(); /* Try to recover from some bad fonts which specify a subtable * length that would overflow the byte buffer holding the whole * cmap table. If this isn't a recoverable situation an exception * may be thrown which is caught higher up the call stack. * Whilst this may seem lenient, in practice, unless the "bad" * subtable we are using is the last one in the cmap table we * would have no way of knowing about this problem anyway. */ if (offset + subtableLength > buffer.capacity()) { subtableLength = buffer.capacity() - offset; } buffer.getChar(); // skip language segCount = buffer.getChar() / 2; buffer.getChar(); // skip searchRange entrySelector = buffer.getChar(); rangeShift = buffer.getChar() / 2; startCount = new char[segCount]; endCount = new char[segCount]; idDelta = new short[segCount]; idRangeOffset = new char[segCount]; for (int i = 0; i < segCount; i++) { endCount[i] = buffer.getChar(); } buffer.getChar(); // 2 bytes for reserved pad for (int i = 0; i < segCount; i++) { startCount[i] = buffer.getChar(); } for (int i = 0; i < segCount; i++) { idDelta[i] = (short) buffer.getChar(); } for (int i = 0; i < segCount; i++) { char ctmp = buffer.getChar(); idRangeOffset[i] = (char) ((ctmp >> 1) & 0xffff); } /* Can calculate the number of glyph IDs by subtracting * "pos" from the length of the cmap */ int pos = (segCount * 8 + 16) / 2; buffer.position(pos * 2 + offset); // * 2 for chars int numGlyphIds = (subtableLength / 2 - pos); glyphIds = new char[numGlyphIds]; for (int i = 0; i < numGlyphIds; i++) { glyphIds[i] = buffer.getChar(); } }