1 /*
   2  * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package sun.font;
  27 
  28 /*
  29  * This isn't a critical performance case, so don't do any
  30  * char->glyph map caching for Type1 fonts. The ones that are used
  31  * in composites will be cached there.
  32  */
  33 
  34 public final class Type1GlyphMapper extends CharToGlyphMapper {
  35 
  36     Type1Font font;
  37     FontScaler scaler;
  38 
  39     public Type1GlyphMapper(Type1Font font) {
  40         this.font = font;
  41         initMapper();
  42     }
  43 
  44     private void initMapper() {
  45         scaler = font.getScaler();
  46         try {
  47           missingGlyph = scaler.getMissingGlyphCode();
  48         } catch (FontScalerException fe) {
  49             scaler = FontScaler.getNullScaler();
  50             try {
  51                 missingGlyph = scaler.getMissingGlyphCode();
  52             } catch (FontScalerException e) { //should not happen
  53                 missingGlyph = 0;
  54             }
  55         }
  56     }
  57 
  58     public int getNumGlyphs() {
  59         try {
  60             return scaler.getNumGlyphs();
  61         } catch (FontScalerException e) {
  62             scaler = FontScaler.getNullScaler();
  63             return getNumGlyphs();
  64         }
  65     }
  66 
  67     public int getMissingGlyphCode() {
  68         return missingGlyph;
  69     }
  70 
  71     public boolean canDisplay(char ch) {
  72         try {
  73             return scaler.getGlyphCode(ch) != missingGlyph;
  74         } catch(FontScalerException e) {
  75             scaler = FontScaler.getNullScaler();
  76             return canDisplay(ch);
  77         }
  78     }
  79 
  80     public int charToGlyph(char ch) {
  81         try {
  82             return scaler.getGlyphCode(ch);
  83         } catch (FontScalerException e) {
  84             scaler = FontScaler.getNullScaler();
  85             return charToGlyph(ch);
  86         }
  87     }
  88 
  89     public int charToGlyph(int ch) {
  90         if (ch < 0 || ch > 0xffff) {
  91             return missingGlyph;
  92         } else {
  93             try {
  94                 return scaler.getGlyphCode((char)ch);
  95             } catch (FontScalerException e) {
  96                 scaler = FontScaler.getNullScaler();
  97                 return charToGlyph(ch);
  98             }
  99         }
 100     }
 101 
 102     public void charsToGlyphs(int count, char[] unicodes, int[] glyphs) {
 103         /* The conversion into surrogates is misleading.
 104          * The Type1 glyph mapper only accepts 16 bit unsigned shorts.
 105          * If its > not in the range it can use assign the missing glyph.
 106          */
 107         for (int i=0; i<count; i++) {
 108             int code = unicodes[i]; // char is unsigned.
 109 
 110             if (code >= HI_SURROGATE_START &&
 111                 code <= HI_SURROGATE_END && i < count - 1) {
 112                 char low = unicodes[i + 1];
 113 
 114                 if (low >= LO_SURROGATE_START &&
 115                     low <= LO_SURROGATE_END) {
 116                     code = (code - HI_SURROGATE_START) *
 117                         0x400 + low - LO_SURROGATE_START + 0x10000;
 118                     glyphs[i + 1] = 0xFFFF; // invisible glyph
 119                 }
 120             }
 121             glyphs[i] = charToGlyph(code);
 122             if (code >= 0x10000) {
 123                 i += 1; // Empty glyph slot after surrogate
 124             }
 125         }
 126     }
 127 
 128     public void charsToGlyphs(int count, int[] unicodes, int[] glyphs) {
 129         /* I believe this code path is never exercised. Its there mainly
 130          * for surrogates and/or the opentype engine which aren't likely
 131          * to be an issue for Type1 fonts. So no need to optimise it.
 132          */
 133         for (int i=0; i<count; i++) {
 134             glyphs[i] = charToGlyph(unicodes[i]);
 135         }
 136     }
 137 
 138 
 139     /* This variant checks if shaping is needed and immediately
 140      * returns true if it does. A caller of this method should be expecting
 141      * to check the return type because it needs to know how to handle
 142      * the character data for display.
 143      */
 144     public boolean charsToGlyphsNS(int count, char[] unicodes, int[] glyphs) {
 145 
 146         for (int i=0; i<count; i++) {
 147             int code = unicodes[i]; // char is unsigned.
 148 
 149             if (code >= HI_SURROGATE_START &&
 150                 code <= HI_SURROGATE_END && i < count - 1) {
 151                 char low = unicodes[i + 1];
 152 
 153                 if (low >= LO_SURROGATE_START &&
 154                     low <= LO_SURROGATE_END) {
 155                     code = (code - HI_SURROGATE_START) *
 156                         0x400 + low - LO_SURROGATE_START + 0x10000;
 157                     glyphs[i + 1] = INVISIBLE_GLYPH_ID;
 158                 }
 159             }
 160 
 161             glyphs[i] = charToGlyph(code);
 162 
 163             if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
 164                 continue;
 165             }
 166             else if (FontUtilities.isComplexCharCode(code)) {
 167                 return true;
 168             }
 169             else if (code >= 0x10000) {
 170                 i += 1; // Empty glyph slot after surrogate
 171                 continue;
 172             }
 173         }
 174 
 175         return false;
 176     }
 177 }