< prev index next >

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

Print this page

        

@@ -131,10 +131,30 @@
             }
         }
         return missingGlyph;
     }
 
+    private int convertToGlyph(int unicode, int variationSelector) {
+        if (variationSelector == 0) {
+            return convertToGlyph(unicode);
+        }
+        for (int slot = 0; slot < font.numSlots; slot++) {
+            if (!hasExcludes || !font.isExcludedChar(slot, unicode)) {
+                CharToGlyphMapper mapper = getSlotMapper(slot);
+                if (mapper instanceof TrueTypeGlyphMapper) {
+                    int glyphCode = ((TrueTypeGlyphMapper)mapper).
+                            getGlyphOfVS(unicode, variationSelector);
+                    if (glyphCode != mapper.getMissingGlyphCode()) {
+                        glyphCode = compositeGlyphCode(slot, glyphCode);
+                        return glyphCode;
+                    }
+                }
+            }
+        }
+        return convertToGlyph(unicode); //retry without Variation Selector
+    }
+
     public int getNumGlyphs() {
         int numGlyphs = 0;
         /* The number of glyphs in a composite is affected by
          * exclusion ranges and duplicates (ie the same code point is
          * mapped by two different fonts) and also whether or not to

@@ -203,15 +223,81 @@
                     code = (code - HI_SURROGATE_START) *
                         0x400 + low - LO_SURROGATE_START + 0x10000;
                     glyphs[i + 1] = INVISIBLE_GLYPH_ID;
                 }
             }
+            if (isVariationSelector(code)) {
+                return charsToGlyphsNSVS(count, unicodes, glyphs);
+            }
+
+            int gc = glyphs[i] = getCachedGlyphCode(code);
+            if (gc == UNINITIALIZED_GLYPH) {
+                glyphs[i] = convertToGlyph(code);
+            }
+
+            if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
+                continue;
+            }
+            else if (FontUtilities.isComplexCharCode(code)) {
+                return true;
+            }
+            else if (code >= 0x10000) {
+                i += 1; // Empty glyph slot after surrogate
+                continue;
+            }
+        }
+
+        return false;
+    }
+
+    private boolean charsToGlyphsNSVS(int count, char[] unicodes,
+                                     int[] glyphs) {
+
+        for (int i = 0; i < count; i++) {
+            int code = unicodes[i]; // char is unsigned.
+            int step = 1;
+            int variationSelector = 0;
+
+            if (code >= HI_SURROGATE_START &&
+                code <= HI_SURROGATE_END && i < count - 1) {
+                char low = unicodes[i + 1];
+
+                if (low >= LO_SURROGATE_START &&
+                    low <= LO_SURROGATE_END) {
+                    code = (code - HI_SURROGATE_START) *
+                        0x400 + low - LO_SURROGATE_START + 0x10000;
+                    glyphs[i + 1] = INVISIBLE_GLYPH_ID;
+                    step = 2;
+                }
+            }
 
+            if (i < count - step &&
+                isVariationSelectorBMP(unicodes[i+step]) &&
+                isVSBaseChar(code)) {
+                variationSelector = unicodes[i+step];
+                glyphs[i] = convertToGlyph(code, variationSelector);
+                glyphs[i+step] = INVISIBLE_GLYPH_ID;
+                i += 1;
+            } else if (i < count - step -1 &&
+                       isVariationSelectorExt(unicodes[i+step],
+                                              unicodes[i+step+1]) &&
+                       isVSBaseChar(code)) {
+                variationSelector = (unicodes[i+step] 
+                                     - HI_SURROGATE_START) * 0x400 
+                                    + unicodes[i+step+1] - LO_SURROGATE_START
+                                    + 0x10000;
+                glyphs[i] = convertToGlyph(code, variationSelector);
+                glyphs[i+step] = INVISIBLE_GLYPH_ID;
+                glyphs[i+step+1] = INVISIBLE_GLYPH_ID;
+                i += 2;
+            }
+            if (variationSelector == 0) {
             int gc = glyphs[i] = getCachedGlyphCode(code);
             if (gc == UNINITIALIZED_GLYPH) {
                 glyphs[i] = convertToGlyph(code);
             }
+            }
 
             if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
                 continue;
             }
             else if (FontUtilities.isComplexCharCode(code)) {

@@ -239,35 +325,117 @@
 
                 if (low >= LO_SURROGATE_START &&
                     low <= LO_SURROGATE_END) {
                     code = (code - HI_SURROGATE_START) *
                         0x400 + low - LO_SURROGATE_START + 0x10000;
+                    if (isVariationSelector(code)) {
+                        charsToGlyphsVS(count, unicodes, glyphs);
+                        return;
+                    }
 
                     int gc = glyphs[i] = getCachedGlyphCode(code);
                     if (gc == UNINITIALIZED_GLYPH) {
                         glyphs[i] = convertToGlyph(code);
                     }
                     i += 1; // Empty glyph slot after surrogate
                     glyphs[i] = INVISIBLE_GLYPH_ID;
                     continue;
                 }
+            } else if (isVariationSelectorBMP(unicodes[i])) {
+                charsToGlyphsVS(count, unicodes, glyphs);
+                return;
             }
 
             int gc = glyphs[i] = getCachedGlyphCode(code);
             if (gc == UNINITIALIZED_GLYPH) {
                 glyphs[i] = convertToGlyph(code);
             }
         }
     }
 
+    private void charsToGlyphsVS(int count, char[] unicodes, int[] glyphs) {
+        for (int i = 0; i < count; i++) {
+            int code = unicodes[i]; // char is unsigned.
+            int variationSelector = 0;
+            int step = 1;
+
+            if (code >= HI_SURROGATE_START &&
+                code <= HI_SURROGATE_END && i < count - 1) {
+                char low = unicodes[i + 1];
+
+                if (low >= LO_SURROGATE_START &&
+                    low <= LO_SURROGATE_END) {
+                    code = (code - HI_SURROGATE_START) *
+                        0x400 + low - LO_SURROGATE_START + 0x10000;
+
+                    glyphs[i+1] = INVISIBLE_GLYPH_ID;
+                    step = 2;
+                }
+            }
+
+            if (i < count - step &&
+                isVariationSelectorBMP(unicodes[i+step]) &&
+                isVSBaseChar(code)) {
+                    variationSelector = unicodes[i+step];
+                    glyphs[i] = convertToGlyph(code, variationSelector);
+                    glyphs[i+step] = INVISIBLE_GLYPH_ID;
+                    i += 1;
+            } else if (i < count - step -1 &&
+                       isVariationSelectorExt(unicodes[i+step], 
+                                              unicodes[i+step+1]) &&
+                       isVSBaseChar(code)) {
+                variationSelector = (unicodes[i+step] 
+                                     - HI_SURROGATE_START) * 0x400 
+                                    + unicodes[i+step+1] - LO_SURROGATE_START
+                                    + 0x10000;
+                glyphs[i] = convertToGlyph(code, variationSelector);
+                glyphs[i+step] = INVISIBLE_GLYPH_ID;
+                glyphs[i+step+1] = INVISIBLE_GLYPH_ID;
+                i += 2;
+            }
+            if (variationSelector == 0) {
+                int gc = glyphs[i] = getCachedGlyphCode(code);
+                if (gc == UNINITIALIZED_GLYPH) {
+                    glyphs[i] = convertToGlyph(code);
+                }
+            }
+            if (code >= 0x10000) {
+                i++;
+            }
+        }
+    }
+
     public void charsToGlyphs(int count, int[] unicodes, int[] glyphs) {
         for (int i=0; i<count; i++) {
             int code = unicodes[i];
+            if (isVariationSelector(code)) {
+                charsToGlyphsVS(count, unicodes, glyphs);
+                return;
+            }
+
+            glyphs[i] = getCachedGlyphCode(code);
+            if (glyphs[i] == UNINITIALIZED_GLYPH) {
+                glyphs[i] = convertToGlyph(code);
+            }
+        }
+    }
+
+    private void charsToGlyphsVS(int count, int[] unicodes, int[] glyphs) {
+        for (int i = 0; i < count; i++) {
+            int code = unicodes[i];
 
+            if (i < count-1 &&
+                isVariationSelector(unicodes[i+1]) &&
+                isVSBaseChar(code) ) {
+                glyphs[i] = convertToGlyph(code, unicodes[i+1]);
+                glyphs[i+1] = INVISIBLE_GLYPH_ID;
+                i++;
+            } else {
             glyphs[i] = getCachedGlyphCode(code);
             if (glyphs[i] == UNINITIALIZED_GLYPH) {
                 glyphs[i] = convertToGlyph(code);
             }
         }
     }
+    }
 
 }
< prev index next >