< prev index next >

src/java.desktop/share/classes/sun/font/CMap.java

Print this page




 123 
 124     static final short ShiftJISEncoding = 2;
 125     static final short GBKEncoding      = 3;
 126     static final short Big5Encoding     = 4;
 127     static final short WansungEncoding  = 5;
 128     static final short JohabEncoding    = 6;
 129     static final short MSUnicodeSurrogateEncoding = 10;
 130 
 131     static final char noSuchChar = (char)0xfffd;
 132     static final int SHORTMASK = 0x0000ffff;
 133     static final int INTMASK   = 0xffffffff;
 134 
 135     static final char[][] converterMaps = new char[7][];
 136 
 137     /*
 138      * Unicode->other encoding translation array. A pre-computed look up
 139      * which can be shared across all fonts using that encoding.
 140      * Using this saves running character coverters repeatedly.
 141      */
 142     char[] xlat;

 143 
 144     static CMap initialize(TrueTypeFont font) {
 145 
 146         CMap cmap = null;
 147 
 148         int offset, platformID, encodingID=-1;
 149 
 150         int three0=0, three1=0, three2=0, three3=0, three4=0, three5=0,
 151             three6=0, three10=0;

 152         boolean threeStar = false;
 153 
 154         ByteBuffer cmapBuffer = font.getTableBuffer(TrueTypeFont.cmapTag);
 155         int cmapTableOffset = font.getTableSize(TrueTypeFont.cmapTag);
 156         short numberSubTables = cmapBuffer.getShort(2);
 157 
 158         /* locate the offsets of all 3,*  (ie Microsoft platform) encodings */
 159         for (int i=0; i<numberSubTables; i++) {
 160             cmapBuffer.position(i * 8 + 4);
 161             platformID = cmapBuffer.getShort();
 162             if (platformID == 3) {
 163                 threeStar = true;
 164                 encodingID = cmapBuffer.getShort();
 165                 offset     = cmapBuffer.getInt();
 166                 switch (encodingID) {
 167                 case 0:  three0  = offset; break; // MS Symbol encoding
 168                 case 1:  three1  = offset; break; // MS Unicode cmap
 169                 case 2:  three2  = offset; break; // ShiftJIS cmap.
 170                 case 3:  three3  = offset; break; // GBK cmap
 171                 case 4:  three4  = offset; break; // Big 5 cmap
 172                 case 5:  three5  = offset; break; // Wansung
 173                 case 6:  three6  = offset; break; // Johab
 174                 case 10: three10 = offset; break; // MS Unicode surrogates
 175                 }






 176             }
 177         }
 178 
 179         /* This defines the preference order for cmap subtables */
 180         if (threeStar) {
 181             if (three10 != 0) {
 182                 cmap = createCMap(cmapBuffer, three10, null);
 183             }
 184             else if  (three0 != 0) {
 185                 /* The special case treatment of these fonts leads to
 186                  * anomalies where a user can view "wingdings" and "wingdings2"
 187                  * and the latter shows all its code points in the unicode
 188                  * private use area at 0xF000->0XF0FF and the former shows
 189                  * a scattered subset of its glyphs that are known mappings to
 190                  * unicode code points.
 191                  * The primary purpose of these mappings was to facilitate
 192                  * display of symbol chars etc in composite fonts, however
 193                  * this is not needed as all these code points are covered
 194                  * by Lucida Sans Regular.
 195                  * Commenting this out reduces the role of these two files


 245                 else {
 246                     cmap = createCMap(cmapBuffer, three4,
 247                                       getConverterMap(Big5Encoding));
 248                 }
 249             }
 250             else if (three5 != 0) {
 251                 cmap = createCMap(cmapBuffer, three5,
 252                                   getConverterMap(WansungEncoding));
 253             }
 254             else if (three6 != 0) {
 255                 cmap = createCMap(cmapBuffer, three6,
 256                                   getConverterMap(JohabEncoding));
 257             }
 258         } else {
 259             /* No 3,* subtable was found. Just use whatever is the first
 260              * table listed. Not very useful but maybe better than
 261              * rejecting the font entirely?
 262              */
 263             cmap = createCMap(cmapBuffer, cmapBuffer.getInt(8), null);
 264         }




 265         return cmap;
 266     }
 267 
 268     /* speed up the converting by setting the range for double
 269      * byte characters;
 270      */
 271     static char[] getConverter(short encodingID) {
 272         int dBegin = 0x8000;
 273         int dEnd   = 0xffff;
 274         String encoding;
 275 
 276         switch (encodingID) {
 277         case ShiftJISEncoding:
 278             dBegin = 0x8140;
 279             dEnd   = 0xfcfc;
 280             encoding = "SJIS";
 281             break;
 282         case GBKEncoding:
 283             dBegin = 0x8140;
 284             dEnd   = 0xfea0;


 407             subtableLength = buffer.getInt(offset+4) & INTMASK;
 408         }
 409         if (offset+subtableLength > buffer.capacity()) {
 410             if (FontUtilities.isLogging()) {
 411                 FontUtilities.getLogger().warning("Cmap subtable overflows buffer.");
 412             }
 413         }
 414         switch (subtableFormat) {
 415         case 0:  return new CMapFormat0(buffer, offset);
 416         case 2:  return new CMapFormat2(buffer, offset, xlat);
 417         case 4:  return new CMapFormat4(buffer, offset, xlat);
 418         case 6:  return new CMapFormat6(buffer, offset, xlat);
 419         case 8:  return new CMapFormat8(buffer, offset, xlat);
 420         case 10: return new CMapFormat10(buffer, offset, xlat);
 421         case 12: return new CMapFormat12(buffer, offset, xlat);
 422         default: throw new RuntimeException("Cmap format unimplemented: " +
 423                                             (int)buffer.getChar(offset));
 424         }
 425     }
 426 















 427 /*
 428     final char charVal(byte[] cmap, int index) {
 429         return (char)(((0xff & cmap[index]) << 8)+(0xff & cmap[index+1]));
 430     }
 431 
 432     final short shortVal(byte[] cmap, int index) {
 433         return (short)(((0xff & cmap[index]) << 8)+(0xff & cmap[index+1]));
 434     }
 435 */
 436     abstract char getGlyph(int charCode);
 437 
 438     /* Format 4 Header is
 439      * ushort format (off=0)
 440      * ushort length (off=2)
 441      * ushort language (off=4)
 442      * ushort segCountX2 (off=6)
 443      * ushort searchRange (off=8)
 444      * ushort entrySelector (off=10)
 445      * ushort rangeShift (off=12)
 446      * ushort endCount[segCount] (off=14)


1042     public static final NullCMapClass theNullCmap = new NullCMapClass();
1043 
1044     final int getControlCodeGlyph(int charCode, boolean noSurrogates) {
1045         if (charCode < 0x0010) {
1046             switch (charCode) {
1047             case 0x0009:
1048             case 0x000a:
1049             case 0x000d: return CharToGlyphMapper.INVISIBLE_GLYPH_ID;
1050             }
1051         } else if (charCode >= 0x200c) {
1052             if ((charCode <= 0x200f) ||
1053                 (charCode >= 0x2028 && charCode <= 0x202e) ||
1054                 (charCode >= 0x206a && charCode <= 0x206f)) {
1055                 return CharToGlyphMapper.INVISIBLE_GLYPH_ID;
1056             } else if (noSurrogates && charCode >= 0xFFFF) {
1057                 return 0;
1058             }
1059         }
1060         return -1;
1061     }












































































































































































1062 }


 123 
 124     static final short ShiftJISEncoding = 2;
 125     static final short GBKEncoding      = 3;
 126     static final short Big5Encoding     = 4;
 127     static final short WansungEncoding  = 5;
 128     static final short JohabEncoding    = 6;
 129     static final short MSUnicodeSurrogateEncoding = 10;
 130 
 131     static final char noSuchChar = (char)0xfffd;
 132     static final int SHORTMASK = 0x0000ffff;
 133     static final int INTMASK   = 0xffffffff;
 134 
 135     static final char[][] converterMaps = new char[7][];
 136 
 137     /*
 138      * Unicode->other encoding translation array. A pre-computed look up
 139      * which can be shared across all fonts using that encoding.
 140      * Using this saves running character coverters repeatedly.
 141      */
 142     char[] xlat;
 143     UVS uvs = null;
 144 
 145     static CMap initialize(TrueTypeFont font) {
 146 
 147         CMap cmap = null;
 148 
 149         int offset, platformID, encodingID=-1;
 150 
 151         int three0=0, three1=0, three2=0, three3=0, three4=0, three5=0,
 152             three6=0, three10=0;
 153         int zero5 = 0; // for Unicode Variation Sequences
 154         boolean threeStar = false;
 155 
 156         ByteBuffer cmapBuffer = font.getTableBuffer(TrueTypeFont.cmapTag);
 157         int cmapTableOffset = font.getTableSize(TrueTypeFont.cmapTag);
 158         short numberSubTables = cmapBuffer.getShort(2);
 159 
 160         /* locate the offsets of all 3,*  (ie Microsoft platform) encodings */
 161         for (int i=0; i<numberSubTables; i++) {
 162             cmapBuffer.position(i * 8 + 4);
 163             platformID = cmapBuffer.getShort();
 164             if (platformID == 3) {
 165                 threeStar = true;
 166                 encodingID = cmapBuffer.getShort();
 167                 offset     = cmapBuffer.getInt();
 168                 switch (encodingID) {
 169                 case 0:  three0  = offset; break; // MS Symbol encoding
 170                 case 1:  three1  = offset; break; // MS Unicode cmap
 171                 case 2:  three2  = offset; break; // ShiftJIS cmap.
 172                 case 3:  three3  = offset; break; // GBK cmap
 173                 case 4:  three4  = offset; break; // Big 5 cmap
 174                 case 5:  three5  = offset; break; // Wansung
 175                 case 6:  three6  = offset; break; // Johab
 176                 case 10: three10 = offset; break; // MS Unicode surrogates
 177                 }
 178             } else if (platformID == 0) {
 179                 encodingID = cmapBuffer.getShort();
 180                 offset     = cmapBuffer.getInt();
 181                 if (encodingID == 5) {
 182                     zero5 = offset;
 183                 } 
 184             }
 185         }
 186 
 187         /* This defines the preference order for cmap subtables */
 188         if (threeStar) {
 189             if (three10 != 0) {
 190                 cmap = createCMap(cmapBuffer, three10, null);
 191             }
 192             else if  (three0 != 0) {
 193                 /* The special case treatment of these fonts leads to
 194                  * anomalies where a user can view "wingdings" and "wingdings2"
 195                  * and the latter shows all its code points in the unicode
 196                  * private use area at 0xF000->0XF0FF and the former shows
 197                  * a scattered subset of its glyphs that are known mappings to
 198                  * unicode code points.
 199                  * The primary purpose of these mappings was to facilitate
 200                  * display of symbol chars etc in composite fonts, however
 201                  * this is not needed as all these code points are covered
 202                  * by Lucida Sans Regular.
 203                  * Commenting this out reduces the role of these two files


 253                 else {
 254                     cmap = createCMap(cmapBuffer, three4,
 255                                       getConverterMap(Big5Encoding));
 256                 }
 257             }
 258             else if (three5 != 0) {
 259                 cmap = createCMap(cmapBuffer, three5,
 260                                   getConverterMap(WansungEncoding));
 261             }
 262             else if (three6 != 0) {
 263                 cmap = createCMap(cmapBuffer, three6,
 264                                   getConverterMap(JohabEncoding));
 265             }
 266         } else {
 267             /* No 3,* subtable was found. Just use whatever is the first
 268              * table listed. Not very useful but maybe better than
 269              * rejecting the font entirely?
 270              */
 271             cmap = createCMap(cmapBuffer, cmapBuffer.getInt(8), null);
 272         }
 273         // For Unicode Variation Sequences
 274         if (cmap != null && zero5 != 0) {
 275             cmap.createUVS(cmapBuffer, zero5);
 276         }
 277         return cmap;
 278     }
 279 
 280     /* speed up the converting by setting the range for double
 281      * byte characters;
 282      */
 283     static char[] getConverter(short encodingID) {
 284         int dBegin = 0x8000;
 285         int dEnd   = 0xffff;
 286         String encoding;
 287 
 288         switch (encodingID) {
 289         case ShiftJISEncoding:
 290             dBegin = 0x8140;
 291             dEnd   = 0xfcfc;
 292             encoding = "SJIS";
 293             break;
 294         case GBKEncoding:
 295             dBegin = 0x8140;
 296             dEnd   = 0xfea0;


 419             subtableLength = buffer.getInt(offset+4) & INTMASK;
 420         }
 421         if (offset+subtableLength > buffer.capacity()) {
 422             if (FontUtilities.isLogging()) {
 423                 FontUtilities.getLogger().warning("Cmap subtable overflows buffer.");
 424             }
 425         }
 426         switch (subtableFormat) {
 427         case 0:  return new CMapFormat0(buffer, offset);
 428         case 2:  return new CMapFormat2(buffer, offset, xlat);
 429         case 4:  return new CMapFormat4(buffer, offset, xlat);
 430         case 6:  return new CMapFormat6(buffer, offset, xlat);
 431         case 8:  return new CMapFormat8(buffer, offset, xlat);
 432         case 10: return new CMapFormat10(buffer, offset, xlat);
 433         case 12: return new CMapFormat12(buffer, offset, xlat);
 434         default: throw new RuntimeException("Cmap format unimplemented: " +
 435                                             (int)buffer.getChar(offset));
 436         }
 437     }
 438 
 439     private void createUVS(ByteBuffer buffer, int offset) {
 440         int subtableFormat = buffer.getChar(offset);
 441         if (subtableFormat == 14) {
 442             long subtableLength = buffer.getInt(offset + 2) & INTMASK;
 443             if (offset + subtableLength > buffer.capacity()) {
 444                 if (FontUtilities.isLogging()) {
 445                     FontUtilities.getLogger()
 446                             .warning("Cmap UVS subtable overflows buffer.");
 447                 }
 448             }
 449             this.uvs = new UVS(buffer, offset);
 450         }
 451         return;
 452     }
 453 
 454 /*
 455     final char charVal(byte[] cmap, int index) {
 456         return (char)(((0xff & cmap[index]) << 8)+(0xff & cmap[index+1]));
 457     }
 458 
 459     final short shortVal(byte[] cmap, int index) {
 460         return (short)(((0xff & cmap[index]) << 8)+(0xff & cmap[index+1]));
 461     }
 462 */
 463     abstract char getGlyph(int charCode);
 464 
 465     /* Format 4 Header is
 466      * ushort format (off=0)
 467      * ushort length (off=2)
 468      * ushort language (off=4)
 469      * ushort segCountX2 (off=6)
 470      * ushort searchRange (off=8)
 471      * ushort entrySelector (off=10)
 472      * ushort rangeShift (off=12)
 473      * ushort endCount[segCount] (off=14)


1069     public static final NullCMapClass theNullCmap = new NullCMapClass();
1070 
1071     final int getControlCodeGlyph(int charCode, boolean noSurrogates) {
1072         if (charCode < 0x0010) {
1073             switch (charCode) {
1074             case 0x0009:
1075             case 0x000a:
1076             case 0x000d: return CharToGlyphMapper.INVISIBLE_GLYPH_ID;
1077             }
1078         } else if (charCode >= 0x200c) {
1079             if ((charCode <= 0x200f) ||
1080                 (charCode >= 0x2028 && charCode <= 0x202e) ||
1081                 (charCode >= 0x206a && charCode <= 0x206f)) {
1082                 return CharToGlyphMapper.INVISIBLE_GLYPH_ID;
1083             } else if (noSurrogates && charCode >= 0xFFFF) {
1084                 return 0;
1085             }
1086         }
1087         return -1;
1088     }
1089 
1090     static class UVS {
1091         int numSelectors;
1092         int[] selector;
1093 
1094         //for Default UVS Table
1095         int[] numUnicodeValueRanges;
1096         int[][] startUnicodeValue;
1097         byte[][] additionalCount;
1098         //for Non-Default UVS Table
1099         int[] numUVSMapping;
1100         int[][] unicodeValue;
1101         char[][] glyphID;
1102 
1103         UVS(ByteBuffer buffer, int offset) {
1104             numSelectors = buffer.getInt(offset+6);
1105             selector = new int[numSelectors];
1106             numUnicodeValueRanges = new int[numSelectors];
1107             startUnicodeValue = new int[numSelectors][];
1108             additionalCount = new byte[numSelectors][];
1109             numUVSMapping = new int[numSelectors];
1110             unicodeValue = new int[numSelectors][];
1111             glyphID = new char[numSelectors][];
1112 
1113             for (int i = 0; i < numSelectors; i++) {
1114                 buffer.position(offset + 10 + i * 11);
1115                 selector[i] = (buffer.get() & 0xff) << 16; //UINT24
1116                 selector[i] += (buffer.get() & 0xff) << 8;
1117                 selector[i] += buffer.get() & 0xff;
1118 
1119                 //for Default UVS Table
1120                 int tableOffset = buffer.getInt(offset + 10 + i * 11 + 3);
1121                 if (tableOffset == 0) {
1122                     numUnicodeValueRanges[i] = 0;
1123                 } else {
1124                     buffer.position(offset+tableOffset);
1125                     numUnicodeValueRanges[i] = buffer.getInt() & INTMASK;
1126 
1127                     startUnicodeValue[i] = new int[numUnicodeValueRanges[i]];
1128                     additionalCount[i] = new byte[numUnicodeValueRanges[i]];
1129 
1130                     for (int j = 0; j < numUnicodeValueRanges[i]; j++) {
1131                         int temp = (buffer.get() & 0xff) << 16; //UINT24
1132                         temp += (buffer.get() & 0xff) << 8;
1133                         temp += buffer.get() & 0xff;
1134                         startUnicodeValue[i][j] = temp;
1135                         additionalCount[i][j] =  buffer.get();
1136                     }
1137                 }
1138 
1139                 //for Non-Default UVS Table
1140                 tableOffset = buffer.getInt(offset + 10 + i * 11 + 7);
1141                 if (tableOffset == 0) {
1142                     numUVSMapping[i] = 0;
1143                 } else {
1144                     buffer.position(offset+tableOffset);
1145                     numUVSMapping[i] = buffer.getInt() & INTMASK;
1146                     unicodeValue[i] = new int[numUVSMapping[i]];
1147                     glyphID[i] = new char[numUVSMapping[i]];
1148 
1149                     for (int j = 0; j < numUVSMapping[i]; j++) {
1150                         int temp = (buffer.get() & 0xff) << 16; //UINT24
1151                         temp += (buffer.get() & 0xff) << 8;
1152                         temp += buffer.get() & 0xff;
1153                         unicodeValue[i][j] = temp;
1154                         glyphID[i][j] = buffer.getChar();
1155                     }
1156                 }
1157             }
1158         }
1159 
1160         private int cachedCode;
1161         private int targetCachedCode;
1162         private int targetCachedSelector = -1;
1163 
1164         /* getGlyph for Variation selector
1165            return value:
1166             0: A special glyph for the variation selector is Not found
1167            -1: Default glyph should be used
1168            0>: A special glyph is found
1169         */
1170         int getGlyph(int charCode, int variationSelector) {
1171             synchronized(this) {
1172                 if (charCode == targetCachedCode && 
1173                     variationSelector == targetCachedSelector) {
1174                     return cachedCode;
1175                 }
1176             }
1177 
1178             int targetSelector = -1;
1179             int result;
1180             for (int i = 0; i < numSelectors; i++) {
1181                 if (selector[i] == variationSelector) {
1182                     targetSelector = i;
1183                     break;
1184                 }
1185             }
1186             if (targetSelector == -1) {
1187                 result = 0;
1188                 storeCache(charCode, variationSelector, result);
1189                 return result;
1190             }
1191             if (numUnicodeValueRanges[targetSelector] > 0) {
1192                 int index = java.util.Arrays.binarySearch(
1193                                 startUnicodeValue[targetSelector], charCode);
1194                 if (index >= 0) {
1195                     result = -1; //pass through default table in actual CMAP
1196                     storeCache(charCode, variationSelector, result);
1197                     return result;
1198                 } else {
1199                     index = -index - 2;
1200                     if (index >=0 &&
1201                         charCode >= startUnicodeValue[targetSelector][index] &&
1202                         charCode <= startUnicodeValue[targetSelector][index]
1203                                     +additionalCount[targetSelector][index]) {
1204                         result = -1; //pass through default table in actual CMAP
1205                         storeCache(charCode, variationSelector, result);
1206                         return result;
1207                     }
1208                 }
1209             }
1210             if (numUVSMapping[targetSelector] > 0) {
1211                 int index = java.util.Arrays.binarySearch(
1212                                 unicodeValue[targetSelector], charCode);
1213                 if (index >= 0) {
1214                     result = glyphID[targetSelector][index];
1215                     storeCache(charCode, variationSelector, result);
1216                     return result;
1217                 }
1218             }
1219             result = 0;
1220             storeCache(charCode, variationSelector, result);
1221             return result;
1222         }
1223 
1224         private synchronized void storeCache(int charCode, 
1225                                              int variationSelector, 
1226                                              int glyph) {
1227             cachedCode = glyph;
1228             targetCachedCode = charCode;
1229             targetCachedSelector = variationSelector;
1230         }
1231 
1232         boolean hasVariationSelectorGlyph(int charCode,
1233                                           int variationSelector) {
1234             int result = getGlyph(charCode, variationSelector);
1235             if (result == 0) {
1236                 return false;
1237             } else {
1238                 return true;
1239             }
1240         }
1241     }
1242 
1243     public char getGlyph(int charCode, int variationSelector) {
1244         if (uvs == null) {
1245             return 0;
1246         }
1247         int result = uvs.getGlyph(charCode, variationSelector);
1248         if (result == -1) {
1249             result = this.getGlyph(charCode);
1250         }
1251         return (char)(result & 0xFFFF);
1252     }
1253 
1254     public boolean hasVariationSelectorGlyph(int charCode, 
1255                                              int variationSelector) {
1256         if (uvs == null) {
1257             return false;
1258         }
1259         return uvs.hasVariationSelectorGlyph(charCode, variationSelector);
1260     }
1261 }
< prev index next >