< 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,24 @@
         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 +1083,174 @@
                 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 >