< prev index next >
src/java.desktop/share/classes/sun/font/CMap.java
Print this page
@@ -138,19 +138,21 @@
* Unicode->other encoding translation array. A pre-computed look up
* which can be shared across all fonts using that encoding.
* Using this saves running character coverters repeatedly.
*/
char[] xlat;
+ UVS uvs = null;
static CMap initialize(TrueTypeFont font) {
CMap cmap = null;
int offset, platformID, encodingID=-1;
int three0=0, three1=0, three2=0, three3=0, three4=0, three5=0,
three6=0, three10=0;
+ int zero5 = 0; // for Unicode Variation Sequences
boolean threeStar = false;
ByteBuffer cmapBuffer = font.getTableBuffer(TrueTypeFont.cmapTag);
int cmapTableOffset = font.getTableSize(TrueTypeFont.cmapTag);
short numberSubTables = cmapBuffer.getShort(2);
@@ -171,10 +173,16 @@
case 4: three4 = offset; break; // Big 5 cmap
case 5: three5 = offset; break; // Wansung
case 6: three6 = offset; break; // Johab
case 10: three10 = offset; break; // MS Unicode surrogates
}
+ } else if (platformID == 0) {
+ encodingID = cmapBuffer.getShort();
+ offset = cmapBuffer.getInt();
+ if (encodingID == 5) {
+ zero5 = offset;
+ }
}
}
/* This defines the preference order for cmap subtables */
if (threeStar) {
@@ -260,10 +268,14 @@
* table listed. Not very useful but maybe better than
* rejecting the font entirely?
*/
cmap = createCMap(cmapBuffer, cmapBuffer.getInt(8), null);
}
+ // For Unicode Variation Sequences
+ if (cmap != null && zero5 != 0) {
+ cmap.createUVS(cmapBuffer, zero5);
+ }
return cmap;
}
/* speed up the converting by setting the range for double
* byte characters;
@@ -422,10 +434,25 @@
default: throw new RuntimeException("Cmap format unimplemented: " +
(int)buffer.getChar(offset));
}
}
+ private void createUVS(ByteBuffer buffer, int offset) {
+ int subtableFormat = buffer.getChar(offset);
+ if (subtableFormat == 14) {
+ long subtableLength = buffer.getInt(offset + 2) & INTMASK;
+ if (offset + subtableLength > buffer.capacity()) {
+ if (FontUtilities.isLogging()) {
+ FontUtilities.getLogger()
+ .warning("Cmap UVS subtable overflows buffer.");
+ }
+ }
+ this.uvs = new UVS(buffer, offset);
+ }
+ return;
+ }
+
/*
final char charVal(byte[] cmap, int index) {
return (char)(((0xff & cmap[index]) << 8)+(0xff & cmap[index+1]));
}
@@ -1057,6 +1084,178 @@
return 0;
}
}
return -1;
}
+
+ static class UVS {
+ int numSelectors;
+ int[] selector;
+
+ //for Default UVS Table
+ int[] numUnicodeValueRanges;
+ int[][] startUnicodeValue;
+ byte[][] additionalCount;
+ //for Non-Default UVS Table
+ int[] numUVSMapping;
+ int[][] unicodeValue;
+ char[][] glyphID;
+
+ UVS(ByteBuffer buffer, int offset) {
+ numSelectors = buffer.getInt(offset+6);
+ selector = new int[numSelectors];
+ numUnicodeValueRanges = new int[numSelectors];
+ startUnicodeValue = new int[numSelectors][];
+ additionalCount = new byte[numSelectors][];
+ numUVSMapping = new int[numSelectors];
+ unicodeValue = new int[numSelectors][];
+ glyphID = new char[numSelectors][];
+
+ for (int i = 0; i < numSelectors; i++) {
+ buffer.position(offset + 10 + i * 11);
+ selector[i] = (buffer.get() & 0xff) << 16; //UINT24
+ selector[i] += (buffer.get() & 0xff) << 8;
+ selector[i] += buffer.get() & 0xff;
+
+ //for Default UVS Table
+ int tableOffset = buffer.getInt(offset + 10 + i * 11 + 3);
+ if (tableOffset == 0) {
+ numUnicodeValueRanges[i] = 0;
+ } else {
+ buffer.position(offset+tableOffset);
+ numUnicodeValueRanges[i] = buffer.getInt() & INTMASK;
+
+ startUnicodeValue[i] = new int[numUnicodeValueRanges[i]];
+ additionalCount[i] = new byte[numUnicodeValueRanges[i]];
+
+ for (int j = 0; j < numUnicodeValueRanges[i]; j++) {
+ int temp = (buffer.get() & 0xff) << 16; //UINT24
+ temp += (buffer.get() & 0xff) << 8;
+ temp += buffer.get() & 0xff;
+ startUnicodeValue[i][j] = temp;
+ additionalCount[i][j] = buffer.get();
+ }
+ }
+
+ //for Non-Default UVS Table
+ tableOffset = buffer.getInt(offset + 10 + i * 11 + 7);
+ if (tableOffset == 0) {
+ numUVSMapping[i] = 0;
+ } else {
+ buffer.position(offset+tableOffset);
+ numUVSMapping[i] = buffer.getInt() & INTMASK;
+ unicodeValue[i] = new int[numUVSMapping[i]];
+ glyphID[i] = new char[numUVSMapping[i]];
+
+ for (int j = 0; j < numUVSMapping[i]; j++) {
+ int temp = (buffer.get() & 0xff) << 16; //UINT24
+ temp += (buffer.get() & 0xff) << 8;
+ temp += buffer.get() & 0xff;
+ unicodeValue[i][j] = temp;
+ glyphID[i][j] = buffer.getChar();
+ }
+ }
+ }
+ }
+
+ private int cachedCode;
+ private int targetCachedCode;
+ private int targetCachedSelector = -1;
+
+ /* getGlyph for Variation selector
+ return value:
+ 0: A special glyph for the variation selector is Not found
+ -1: Default glyph should be used
+ 0>: A special glyph is found
+ */
+ int getGlyph(int charCode, int variationSelector) {
+ synchronized(this) {
+ if (charCode == targetCachedCode &&
+ variationSelector == targetCachedSelector) {
+ return cachedCode;
+ }
+ }
+
+ int targetSelector = -1;
+ int result;
+ for (int i = 0; i < numSelectors; i++) {
+ if (selector[i] == variationSelector) {
+ targetSelector = i;
+ break;
+ }
+ }
+ if (targetSelector == -1) {
+ result = 0;
+ storeCache(charCode, variationSelector, result);
+ return result;
+ }
+ if (numUnicodeValueRanges[targetSelector] > 0) {
+ int index = java.util.Arrays.binarySearch(
+ startUnicodeValue[targetSelector], charCode);
+ if (index >= 0) {
+ result = -1; //pass through default table in actual CMAP
+ storeCache(charCode, variationSelector, result);
+ return result;
+ } else {
+ index = -index - 2;
+ if (index >=0 &&
+ charCode >= startUnicodeValue[targetSelector][index] &&
+ charCode <= startUnicodeValue[targetSelector][index]
+ +additionalCount[targetSelector][index]) {
+ result = -1; //pass through default table in actual CMAP
+ storeCache(charCode, variationSelector, result);
+ return result;
+ }
+ }
+ }
+ if (numUVSMapping[targetSelector] > 0) {
+ int index = java.util.Arrays.binarySearch(
+ unicodeValue[targetSelector], charCode);
+ if (index >= 0) {
+ result = glyphID[targetSelector][index];
+ storeCache(charCode, variationSelector, result);
+ return result;
+ }
+ }
+ result = 0;
+ storeCache(charCode, variationSelector, result);
+ return result;
+ }
+
+ private synchronized void storeCache(int charCode,
+ int variationSelector,
+ int glyph) {
+ cachedCode = glyph;
+ targetCachedCode = charCode;
+ targetCachedSelector = variationSelector;
+ }
+
+ boolean hasVariationSelectorGlyph(int charCode,
+ int variationSelector) {
+ int result = getGlyph(charCode, variationSelector);
+ if (result == 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ public char getGlyph(int charCode, int variationSelector) {
+ if (uvs == null) {
+ return 0;
+ }
+ int result = uvs.getGlyph(charCode, variationSelector);
+ if (result == -1) {
+ result = this.getGlyph(charCode);
+ }
+ return (char)(result & 0xFFFF);
+ }
+
+ public boolean hasVariationSelectorGlyph(int charCode,
+ int variationSelector) {
+ if (uvs == null) {
+ return false;
+ }
+ return uvs.hasVariationSelectorGlyph(charCode, variationSelector);
+ }
}
< prev index next >