1065 lines · 40.8 KB · Java
RawDownload
                idDelta[i] = (short)buffer.get();            }             for (int i=0; i<segCount; i++) {                char ctmp = buffer.get();                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);            int numGlyphIds = (subtableLength/2 - pos);            glyphIds = new char[numGlyphIds];            for (int i=0;i<numGlyphIds;i++) {                glyphIds[i] = buffer.get();            }/*            System.err.println("segcount="+segCount);            System.err.println("entrySelector="+entrySelector);            System.err.println("rangeShift="+rangeShift);            for (int j=0;j<segCount;j++) {              System.err.println("j="+j+ " sc="+(int)(startCount[j]&0xffff)+                                 " ec="+(int)(endCount[j]&0xffff)+                                 " delta="+idDelta[j] +                                 " ro="+(int)idRangeOffset[j]);            }             //System.err.println("numglyphs="+glyphIds.length);            for (int i=0;i<numGlyphIds;i++) {                  System.err.println("gid["+i+"]="+(int)glyphIds[i]);            }*/        }         char getGlyph(int charCode) {             int index = 0;            char glyphCode = 0;             int controlGlyph = getControlCodeGlyph(charCode, true);            if (controlGlyph >= 0) {                return (char)controlGlyph;            }             /* presence of translation array indicates that this             * cmap is in some other (non-unicode encoding).             * In order to look-up a char->glyph mapping we need to             * translate the unicode code point to the encoding of             * the cmap.             * REMIND: VALID CHARCODES??             */            if (xlat != null) {                charCode = xlat[charCode];            }             /*             * Citation from the TrueType (and OpenType) spec:             *   The segments are sorted in order of increasing endCode             *   values, and the segment values are specified in four parallel             *   arrays. You search for the first endCode that is greater than             *   or equal to the character code you want to map. If the             *   corresponding startCode is less than or equal to the             *   character code, then you use the corresponding idDelta and             *   idRangeOffset to map the character code to a glyph index             *   (otherwise, the missingGlyph is returned).             */             /*             * CMAP format4 defines several fields for optimized search of             * the segment list (entrySelector, searchRange, rangeShift).             * However, benefits are neglible and some fonts have incorrect             * data - so we use straightforward binary search (see bug 6247425)             */            int left = 0, right = startCount.length;            index = startCount.length >> 1;            while (left < right) {                if (endCount[index] < charCode) {                    left = index + 1;                } else {                    right = index;                }                index = (left + right) >> 1;            }             if (charCode >= startCount[index] && charCode <= endCount[index]) {                int rangeOffset = idRangeOffset[index];                 if (rangeOffset == 0) {                    glyphCode = (char)(charCode + idDelta[index]);                } else {                    /* Calculate an index into the glyphIds array */ /*                    System.err.println("rangeoffset="+rangeOffset+                                       " charCode=" + charCode +                                       " scnt["+index+"]="+(int)startCount[index] +                                       " segCnt="+segCount);*/                     int glyphIDIndex = rangeOffset - segCount + index                                         + (charCode - startCount[index]);                    glyphCode = glyphIds[glyphIDIndex];                    if (glyphCode != 0) {                        glyphCode = (char)(glyphCode + idDelta[index]);                    }                }            }            if (glyphCode != 0) {            //System.err.println("cc="+Integer.toHexString((int)charCode) + " gc="+(int)glyphCode);            }            return glyphCode;        }    }     // Format 0: Byte Encoding table    static class CMapFormat0 extends CMap {        byte [] cmap;         CMapFormat0(ByteBuffer buffer, int offset) {             /* skip 6 bytes of format, length, and version */            int len = buffer.getChar(offset+2);            cmap = new byte[len-6];            buffer.position(offset+6);            buffer.get(cmap);        }         char getGlyph(int charCode) {            if (charCode < 256) {                if (charCode < 0x0010) {                    switch (charCode) {                    case 0x0009:                    case 0x000a:                    case 0x000d: return CharToGlyphMapper.INVISIBLE_GLYPH_ID;                    }                }                return (char)(0xff & cmap[charCode]);            } else {                return 0;            }        }    } //     static CMap createSymbolCMap(ByteBuffer buffer, int offset, char[] syms) { //      CMap cmap = createCMap(buffer, offset, null);//      if (cmap == null) {//          return null;//      } else {//          return new CMapFormatSymbol(cmap, syms);//      }//     } //     static class CMapFormatSymbol extends CMap { //      CMap cmap;//      static final int NUM_BUCKETS = 128;//      Bucket[] buckets = new Bucket[NUM_BUCKETS]; //      class Bucket {//          char unicode;//          char glyph;//          Bucket next; //          Bucket(char u, char g) {//              unicode = u;//              glyph = g;//          }//      } //      CMapFormatSymbol(CMap cmap, char[] syms) { //          this.cmap = cmap; //          for (int i=0;i<syms.length;i++) {//              char unicode = syms[i];//              if (unicode != noSuchChar) {//                  char glyph = cmap.getGlyph(i + 0xf000);//                  int hash = unicode % NUM_BUCKETS;//                  Bucket bucket = new Bucket(unicode, glyph);//                  if (buckets[hash] == null) {//                      buckets[hash] = bucket;//                  } else {//                      Bucket b = buckets[hash];//                      while (b.next != null) {//                          b = b.next;//                      }//                      b.next = bucket;//                  }//              }//          }//      } //      char getGlyph(int unicode) {//          if (unicode >= 0x1000) {//              return 0;//          }//          else if (unicode >=0xf000 && unicode < 0xf100) {//              return cmap.getGlyph(unicode);//          } else {//              Bucket b = buckets[unicode % NUM_BUCKETS];//              while (b != null) {//                  if (b.unicode == unicode) {//                      return b.glyph;//                  } else {//                      b = b.next;//                  }//              }//              return 0;//          }//      }//     }     // Format 2: High-byte mapping through table    static class CMapFormat2 extends CMap {         char[] subHeaderKey = new char[256];         /* Store subheaders in individual arrays          * A SubHeader entry theortically looks like {          *   char firstCode;          *   char entryCount;          *   short idDelta;          *   char idRangeOffset;          * }          */        char[] firstCodeArray;        char[] entryCountArray;        short[] idDeltaArray;        char[] idRangeOffSetArray;         char[] glyphIndexArray;         CMapFormat2(ByteBuffer buffer, int offset, char[] xlat) {             this.xlat = xlat;             int tableLen = buffer.getChar(offset+2);            buffer.position(offset+6);            CharBuffer cBuffer = buffer.asCharBuffer();            char maxSubHeader = 0;            for (int i=0;i<256;i++) {                subHeaderKey[i] = cBuffer.get();                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] = cBuffer.get();                entryCountArray[i] = cBuffer.get();                idDeltaArray[i] = (short)cBuffer.get();                idRangeOffSetArray[i] = cBuffer.get();//              System.out.println("sh["+i+"]:fc="+(int)firstCodeArray[i]+//                                 " ec="+(int)entryCountArray[i]+//                                 " delta="+(int)idDeltaArray[i]+//                                 " offset="+(int)idRangeOffSetArray[i]);            }             int glyphIndexArrSize = (tableLen-518-numSubHeaders*8)/2;            glyphIndexArray = new char[glyphIndexArrSize];            for (int i=0; i<glyphIndexArrSize;i++) {                glyphIndexArray[i] = cBuffer.get();            }        }         char getGlyph(int charCode) {            int controlGlyph = getControlCodeGlyph(charCode, true);            if (controlGlyph >= 0) {                return (char)controlGlyph;            }             if (xlat != null) {                charCode = xlat[charCode];            }             char highByte = (char)(charCode >> 8);            char lowByte = (char)(charCode & 0xff);            int key = subHeaderKey[highByte]>>3; // index into subHeaders            char mapMe;             if (key != 0) {                mapMe = lowByte;            } else {                mapMe = highByte;                if (mapMe == 0) {                    mapMe = lowByte;                }            } //          System.err.println("charCode="+Integer.toHexString(charCode)+//                             " key="+key+ " mapMe="+Integer.toHexString(mapMe));            char firstCode = firstCodeArray[key];            if (mapMe < firstCode) {                return 0;            } else {                mapMe -= firstCode;            }             if (mapMe < entryCountArray[key]) {                /* "address" arithmetic is needed to calculate the offset                 * into glyphIndexArray. "idRangeOffSetArray[key]" specifies                 * the number of bytes from that location in the table where                 * the subarray of glyphIndexes starting at "firstCode" begins.                 * Each entry in the subHeader table is 8 bytes, and the                 * idRangeOffSetArray field is at offset 6 in the entry.                 * The glyphIndexArray immediately follows the subHeaders.                 * So if there are "N" entries then the number of bytes to the                 * start of glyphIndexArray is (N-key)*8-6.                 * Subtract this from the idRangeOffSetArray value to get                 * the number of bytes into glyphIndexArray and divide by 2 to                 * get the (char) array index.                 */                int glyphArrayOffset = ((idRangeOffSetArray.length-key)*8)-6;                int glyphSubArrayStart =                        (idRangeOffSetArray[key] - glyphArrayOffset)/2;                char glyphCode = glyphIndexArray[glyphSubArrayStart+mapMe];                if (glyphCode != 0) {                    glyphCode += idDeltaArray[key]; //idDelta                    return glyphCode;                }            }            return 0;        }    }     // Format 6: Trimmed table mapping    static class CMapFormat6 extends CMap {         char firstCode;        char entryCount;        char[] glyphIdArray;         CMapFormat6(ByteBuffer bbuffer, int offset, char[] xlat) {              System.err.println("WARNING: CMapFormat8 is untested.");             bbuffer.position(offset+6);             CharBuffer buffer = bbuffer.asCharBuffer();             firstCode = buffer.get();             entryCount = buffer.get();             glyphIdArray = new char[entryCount];             for (int i=0; i< entryCount; i++) {                 glyphIdArray[i] = buffer.get();             }         }          char getGlyph(int charCode) {            int controlGlyph = getControlCodeGlyph(charCode, true);            if (controlGlyph >= 0) {                return (char)controlGlyph;            }              if (xlat != null) {                 charCode = xlat[charCode];             }              charCode -= firstCode;             if (charCode < 0 || charCode >= entryCount) {                  return 0;             } else {                  return glyphIdArray[charCode];             }         }    }     // Format 8: mixed 16-bit and 32-bit coverage    // Seems unlikely this code will ever get tested as we look for    // MS platform Cmaps and MS states (in the Opentype spec on their website)    // that MS doesn't support this format    static class CMapFormat8 extends CMap {         byte[] is32 = new byte[8192];         int nGroups;         int[] startCharCode;         int[] endCharCode;         int[] startGlyphID;          CMapFormat8(ByteBuffer bbuffer, int offset, char[] xlat) {              System.err.println("WARNING: CMapFormat8 is untested.");             bbuffer.position(12);             bbuffer.get(is32);             nGroups = bbuffer.getInt();             startCharCode = new int[nGroups];             endCharCode   = new int[nGroups];             startGlyphID  = new int[nGroups];         }         char getGlyph(int charCode) {            if (xlat != null) {                throw new RuntimeException("xlat array for cmap fmt=8");            }            return 0;        }     }      // Format 4-byte 10: Trimmed table mapping    // Seems unlikely this code will ever get tested as we look for    // MS platform Cmaps and MS states (in the Opentype spec on their website)    // that MS doesn't support this format    static class CMapFormat10 extends CMap {          long firstCode;         int entryCount;         char[] glyphIdArray;          CMapFormat10(ByteBuffer bbuffer, int offset, char[] xlat) {              System.err.println("WARNING: CMapFormat10 is untested.");             firstCode = bbuffer.getInt() & INTMASK;             entryCount = bbuffer.getInt() & INTMASK;             bbuffer.position(offset+20);             CharBuffer buffer = bbuffer.asCharBuffer();             glyphIdArray = new char[entryCount];             for (int i=0; i< entryCount; i++) {                 glyphIdArray[i] = buffer.get();             }         }          char getGlyph(int charCode) {              if (xlat != null) {                 throw new RuntimeException("xlat array for cmap fmt=10");             }              int code = (int)(charCode - firstCode);             if (code < 0 || code >= entryCount) {                 return 0;             } else {                 return glyphIdArray[code];             }         }    }     // Format 12: Segmented coverage for UCS-4 (fonts supporting    // surrogate pairs)    static class CMapFormat12 extends CMap {         int numGroups;        int highBit =0;        int power;        int extra;        long[] startCharCode;        long[] endCharCode;        int[] startGlyphID;         CMapFormat12(ByteBuffer buffer, int offset, char[] xlat) {            if (xlat != null) {                throw new RuntimeException("xlat array for cmap fmt=12");            }             numGroups = buffer.getInt(offset+12);            startCharCode = new long[numGroups];            endCharCode = new long[numGroups];            startGlyphID = new int[numGroups];            buffer.position(offset+16);            buffer = buffer.slice();            IntBuffer ibuffer = buffer.asIntBuffer();            for (int i=0; i<numGroups; i++) {                startCharCode[i] = ibuffer.get() & INTMASK;                endCharCode[i] = ibuffer.get() & INTMASK;                startGlyphID[i] = ibuffer.get() & 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;            }

Lines 501–1000 of 1065. Previous lines