< 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             try {
 450                 this.uvs = new UVS(buffer, offset);
 451             } catch (Throwable t) {
 452                 t.printStackTrace();
 453             }
 454         }
 455         return;
 456     }
 457 
 458 /*
 459     final char charVal(byte[] cmap, int index) {
 460         return (char)(((0xff & cmap[index]) << 8)+(0xff & cmap[index+1]));
 461     }
 462 
 463     final short shortVal(byte[] cmap, int index) {
 464         return (short)(((0xff & cmap[index]) << 8)+(0xff & cmap[index+1]));
 465     }
 466 */
 467     abstract char getGlyph(int charCode);
 468 
 469     /* Format 4 Header is
 470      * ushort format (off=0)
 471      * ushort length (off=2)
 472      * ushort language (off=4)
 473      * ushort segCountX2 (off=6)
 474      * ushort searchRange (off=8)
 475      * ushort entrySelector (off=10)
 476      * ushort rangeShift (off=12)
 477      * ushort endCount[segCount] (off=14)


1073     public static final NullCMapClass theNullCmap = new NullCMapClass();
1074 
1075     final int getControlCodeGlyph(int charCode, boolean noSurrogates) {
1076         if (charCode < 0x0010) {
1077             switch (charCode) {
1078             case 0x0009:
1079             case 0x000a:
1080             case 0x000d: return CharToGlyphMapper.INVISIBLE_GLYPH_ID;
1081             }
1082         } else if (charCode >= 0x200c) {
1083             if ((charCode <= 0x200f) ||
1084                 (charCode >= 0x2028 && charCode <= 0x202e) ||
1085                 (charCode >= 0x206a && charCode <= 0x206f)) {
1086                 return CharToGlyphMapper.INVISIBLE_GLYPH_ID;
1087             } else if (noSurrogates && charCode >= 0xFFFF) {
1088                 return 0;
1089             }
1090         }
1091         return -1;
1092     }
1093 
1094     static class UVS {
1095         int numSelectors;
1096         int[] selector;
1097 
1098         //for Default UVS Table
1099         int[] numUnicodeValueRanges;
1100         int[][] startUnicodeValue;
1101         short[][] additionalCount;
1102         //for Non-Default UVS Table
1103         int[] numUVSMapping;
1104         int[][] unicodeValue;
1105         char[][] glyphID;
1106 
1107         UVS(ByteBuffer buffer, int offset) {
1108             numSelectors = buffer.getInt(offset+6);
1109             selector = new int[numSelectors];
1110             numUnicodeValueRanges = new int[numSelectors];
1111             startUnicodeValue = new int[numSelectors][];
1112             additionalCount = new short[numSelectors][];
1113             numUVSMapping = new int[numSelectors];
1114             unicodeValue = new int[numSelectors][];
1115             glyphID = new char[numSelectors][];
1116 
1117             for (int i = 0; i < numSelectors; i++) {
1118                 buffer.position(offset + 10 + i * 11);
1119                 selector[i] = (buffer.get() & 0xff) << 16; //UINT24
1120                 selector[i] += (buffer.get() & 0xff) << 8;
1121                 selector[i] += buffer.get() & 0xff;
1122 
1123                 //for Default UVS Table
1124                 int tableOffset = buffer.getInt(offset + 10 + i * 11 + 3);
1125                 if (tableOffset == 0) {
1126                     numUnicodeValueRanges[i] = 0;
1127                 } else if (tableOffset > 0) {
1128                     buffer.position(offset+tableOffset);
1129                     numUnicodeValueRanges[i] = buffer.getInt() & INTMASK;
1130 
1131                     startUnicodeValue[i] = new int[numUnicodeValueRanges[i]];
1132                     additionalCount[i] = new short[numUnicodeValueRanges[i]];
1133 
1134                     for (int j = 0; j < numUnicodeValueRanges[i]; j++) {
1135                         int temp = (buffer.get() & 0xff) << 16; //UINT24
1136                         temp += (buffer.get() & 0xff) << 8;
1137                         temp += buffer.get() & 0xff;
1138                         startUnicodeValue[i][j] = temp;
1139                         additionalCount[i][j] = (short)(buffer.get() & 0xff);
1140                     }
1141                 }
1142 
1143                 //for Non-Default UVS Table
1144                 tableOffset = buffer.getInt(offset + 10 + i * 11 + 7);
1145                 if (tableOffset == 0) {
1146                     numUVSMapping[i] = 0;
1147                 } else if (tableOffset > 0) {
1148                     buffer.position(offset+tableOffset);
1149                     numUVSMapping[i] = buffer.getInt() & INTMASK;
1150                     unicodeValue[i] = new int[numUVSMapping[i]];
1151                     glyphID[i] = new char[numUVSMapping[i]];
1152 
1153                     for (int j = 0; j < numUVSMapping[i]; j++) {
1154                         int temp = (buffer.get() & 0xff) << 16; //UINT24
1155                         temp += (buffer.get() & 0xff) << 8;
1156                         temp += buffer.get() & 0xff;
1157                         unicodeValue[i][j] = temp;
1158                         glyphID[i][j] = buffer.getChar();
1159                     }
1160                 }
1161             }
1162         }
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         static final int VS_NOGLYPH = 0;
1171         static final int VS_DEFAULT_GLYPH = -1;
1172         private int getGlyph(int charCode, int variationSelector) {
1173             int targetSelector = -1;
1174             for (int i = 0; i < numSelectors; i++) {
1175                 if (selector[i] == variationSelector) {
1176                     targetSelector = i;
1177                     break;
1178                 }
1179             }
1180             if (targetSelector == -1) {
1181                 return VS_NOGLYPH;
1182             }
1183             if (numUnicodeValueRanges[targetSelector] > 0) {
1184                 int index = java.util.Arrays.binarySearch(
1185                                 startUnicodeValue[targetSelector], charCode);
1186                 if (index >= 0) {
1187                     return VS_DEFAULT_GLYPH;
1188                 } else {
1189                     index = -index - 2;
1190                     if (index >= 0 &&
1191                         charCode >= startUnicodeValue[targetSelector][index] &&
1192                         charCode <= startUnicodeValue[targetSelector][index]
1193                                     +additionalCount[targetSelector][index]) {
1194                         return VS_DEFAULT_GLYPH;
1195                     }
1196                 }
1197             }
1198             if (numUVSMapping[targetSelector] > 0) {
1199                 int index = java.util.Arrays.binarySearch(
1200                                 unicodeValue[targetSelector], charCode);
1201                 if (index >= 0) {
1202                     return glyphID[targetSelector][index];
1203                 }
1204             }
1205             return VS_NOGLYPH;
1206         }
1207     }
1208 
1209     char getGlyph(int charCode, int variationSelector, boolean allowFallback) {
1210         char glyph = 0;
1211         if (uvs == null) {
1212             if (allowFallback) {
1213                 glyph = getGlyph(charCode);
1214             }
1215         } else {
1216             int result = uvs.getGlyph(charCode, variationSelector);
1217             if (result > 0) {
1218                 glyph = (char)(result & 0xFFFF);
1219             } else if (result == UVS.VS_DEFAULT_GLYPH ||
1220                        allowFallback) {
1221                 glyph = getGlyph(charCode);
1222             }
1223         }
1224         return glyph;
1225     }
1226 }
< prev index next >