jdk/src/share/classes/sun/font/FontResolver.java
changeset 2 90ce3da70b43
child 438 2ae294e4518c
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Portions Copyright 1999-2005 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 
       
    27 /*
       
    28  * (C) Copyright IBM Corp. 1999,  All rights reserved.
       
    29  */
       
    30 
       
    31 package sun.font;
       
    32 
       
    33 import java.awt.Font;
       
    34 import java.awt.GraphicsEnvironment;
       
    35 import java.awt.font.TextAttribute;
       
    36 import java.util.ArrayList;
       
    37 import java.util.Map;
       
    38 import sun.text.CodePointIterator;
       
    39 
       
    40 /**
       
    41  * This class maps an individual character to a Font family which can
       
    42  * display it.  The character-to-Font mapping does not depend on the
       
    43  * character's context, so a particular character will be mapped to the
       
    44  * same font family each time.
       
    45  * <p>
       
    46  * Typically, clients will call getIndexFor(char) for each character
       
    47  * in a style run.  When getIndexFor() returns a different value from
       
    48  * ones seen previously, the characters up to that point will be assigned
       
    49  * a font obtained from getFont().
       
    50  */
       
    51 public final class FontResolver {
       
    52 
       
    53     // An array of all fonts available to the runtime.  The fonts
       
    54     // will be searched in order.
       
    55     private Font[] allFonts;
       
    56     private Font[] supplementaryFonts;
       
    57     private int[]  supplementaryIndices;
       
    58 
       
    59     // Default size of Fonts (if created from an empty Map, for instance).
       
    60     private static final int DEFAULT_SIZE = 12; // from Font
       
    61 
       
    62     private Font defaultFont = new Font(Font.DIALOG, Font.PLAIN, DEFAULT_SIZE);
       
    63 
       
    64     // The results of previous lookups are cached in a two-level
       
    65     // table.  The value for a character c is found in:
       
    66     //     blocks[c>>SHIFT][c&MASK]
       
    67     // although the second array is only allocated when needed.
       
    68     // A 0 value means the character's font has not been looked up.
       
    69     // A positive value means the character's font is in the allFonts
       
    70     // array at index (value-1).
       
    71     private static final int SHIFT = 9;
       
    72     private static final int BLOCKSIZE = 1<<(16-SHIFT);
       
    73     private static final int MASK = BLOCKSIZE-1;
       
    74     private int[][] blocks = new int[1<<SHIFT][];
       
    75 
       
    76     private FontResolver() {
       
    77     }
       
    78 
       
    79     private Font[] getAllFonts() {
       
    80         if (allFonts == null) {
       
    81             allFonts =
       
    82             GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
       
    83             for (int i=0; i < allFonts.length; i++) {
       
    84                 allFonts[i] = allFonts[i].deriveFont((float)DEFAULT_SIZE);
       
    85             }
       
    86         }
       
    87         return allFonts;
       
    88     }
       
    89 
       
    90     /**
       
    91      * Search fonts in order, and return "1" to indicate its in the default
       
    92      * font, (or not found at all),  or the index of the first font
       
    93      * which can display the given character, plus 2, if it is not
       
    94      * in the default font.
       
    95      */
       
    96     private int getIndexFor(char c) {
       
    97 
       
    98         if (defaultFont.canDisplay(c)) {
       
    99             return 1;
       
   100         }
       
   101         for (int i=0; i < getAllFonts().length; i++) {
       
   102             if (allFonts[i].canDisplay(c)) {
       
   103                 return i+2;
       
   104             }
       
   105         }
       
   106         return 1;
       
   107     }
       
   108 
       
   109     private Font [] getAllSCFonts() {
       
   110 
       
   111         if (supplementaryFonts == null) {
       
   112             ArrayList<Font> fonts = new ArrayList<Font>();
       
   113             ArrayList<Integer> indices = new ArrayList<Integer>();
       
   114 
       
   115             for (int i=0; i<getAllFonts().length; i++) {
       
   116                 Font font = allFonts[i];
       
   117                 Font2D font2D = FontManager.getFont2D(font);
       
   118                 if (font2D.hasSupplementaryChars()) {
       
   119                     fonts.add(font);
       
   120                     indices.add(new Integer(i));
       
   121                 }
       
   122             }
       
   123 
       
   124             int len = fonts.size();
       
   125             supplementaryIndices = new int[len];
       
   126             for (int i=0; i<len; i++) {
       
   127                 supplementaryIndices[i] = indices.get(i);
       
   128             }
       
   129             supplementaryFonts = fonts.toArray(new Font[len]);
       
   130         }
       
   131         return supplementaryFonts;
       
   132     }
       
   133 
       
   134     /* This method is called only for character codes >= 0x10000 - which
       
   135      * are assumed to be legal supplementary characters.
       
   136      * It looks first at the default font (to avoid calling getAllFonts if at
       
   137      * all possible) and if that doesn't map the code point, it scans
       
   138      * just the fonts that may contain supplementary characters.
       
   139      * The index that is returned is into the "allFonts" array so that
       
   140      * callers see the same value for both supplementary and base chars.
       
   141      */
       
   142     private int getIndexFor(int cp) {
       
   143 
       
   144         if (defaultFont.canDisplay(cp)) {
       
   145             return 1;
       
   146         }
       
   147 
       
   148         for (int i = 0; i < getAllSCFonts().length; i++) {
       
   149             if (supplementaryFonts[i].canDisplay(cp)) {
       
   150                 return supplementaryIndices[i]+2;
       
   151             }
       
   152         }
       
   153         return 1;
       
   154     }
       
   155 
       
   156     /**
       
   157      * Return an index for the given character.  The index identifies a
       
   158      * font family to getFont(), and has no other inherent meaning.
       
   159      * @param c the character to map
       
   160      * @return a value for consumption by getFont()
       
   161      * @see #getFont
       
   162      */
       
   163     public int getFontIndex(char c) {
       
   164 
       
   165         int blockIndex = c>>SHIFT;
       
   166         int[] block = blocks[blockIndex];
       
   167         if (block == null) {
       
   168             block = new int[BLOCKSIZE];
       
   169             blocks[blockIndex] = block;
       
   170         }
       
   171 
       
   172         int index = c & MASK;
       
   173         if (block[index] == 0) {
       
   174             block[index] = getIndexFor(c);
       
   175         }
       
   176         return block[index];
       
   177     }
       
   178 
       
   179     public int getFontIndex(int cp) {
       
   180         if (cp < 0x10000) {
       
   181             return getFontIndex((char)cp);
       
   182         }
       
   183         return getIndexFor(cp);
       
   184     }
       
   185 
       
   186     /**
       
   187      * Determines the font index for the code point at the current position in the
       
   188      * iterator, then advances the iterator to the first code point that has
       
   189      * a different index or until the iterator is DONE, and returns the font index.
       
   190      * @param iter a code point iterator, this will be advanced past any code
       
   191      *             points that have the same font index
       
   192      * @return the font index for the initial code point found, or 1 if the iterator
       
   193      * was empty.
       
   194      */
       
   195     public int nextFontRunIndex(CodePointIterator iter) {
       
   196         int cp = iter.next();
       
   197         int fontIndex = 1;
       
   198         if (cp != CodePointIterator.DONE) {
       
   199             fontIndex = getFontIndex(cp);
       
   200 
       
   201             while ((cp = iter.next()) != CodePointIterator.DONE) {
       
   202                 if (getFontIndex(cp) != fontIndex) {
       
   203                     iter.prev();
       
   204                     break;
       
   205                 }
       
   206             }
       
   207         }
       
   208         return fontIndex;
       
   209     }
       
   210 
       
   211     /**
       
   212      * Return a Font from a given font index with properties
       
   213      * from attributes.  The font index, which should have been produced
       
   214      * by getFontIndex(), determines a font family.  The size and style
       
   215      * of the Font reflect the properties in attributes.  Any Font or
       
   216      * font family specifications in attributes are ignored, on the
       
   217      * assumption that clients have already handled them.
       
   218      * @param index an index from getFontIndex() which determines the
       
   219      *        font family
       
   220      * @param attributes a Map from which the size and style of the Font
       
   221      *        are determined.  The default size is 12 and the default style
       
   222      *        is Font.PLAIN
       
   223      * @see #getFontIndex
       
   224      */
       
   225     public Font getFont(int index, Map attributes) {
       
   226         Font font = defaultFont;
       
   227 
       
   228         if (index >= 2) {
       
   229             font = allFonts[index-2];
       
   230         }
       
   231 
       
   232         return font.deriveFont(attributes);
       
   233     }
       
   234 
       
   235     private static FontResolver INSTANCE;
       
   236 
       
   237     /**
       
   238      * Return a shared instance of FontResolver.
       
   239      */
       
   240     public static FontResolver getInstance() {
       
   241         if (INSTANCE == null) {
       
   242             INSTANCE = new FontResolver();
       
   243         }
       
   244         return INSTANCE;
       
   245     }
       
   246 }