0N/A/*
2362N/A * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A *
0N/A */
0N/A
0N/A/*
0N/A * (C) Copyright IBM Corp. 1999, All rights reserved.
0N/A */
0N/A
0N/Apackage sun.font;
0N/A
0N/Aimport java.awt.Font;
0N/Aimport java.awt.GraphicsEnvironment;
0N/Aimport java.awt.font.TextAttribute;
0N/Aimport java.util.ArrayList;
0N/Aimport java.util.Map;
0N/Aimport sun.text.CodePointIterator;
0N/A
0N/A/**
0N/A * This class maps an individual character to a Font family which can
0N/A * display it. The character-to-Font mapping does not depend on the
0N/A * character's context, so a particular character will be mapped to the
0N/A * same font family each time.
0N/A * <p>
0N/A * Typically, clients will call getIndexFor(char) for each character
0N/A * in a style run. When getIndexFor() returns a different value from
0N/A * ones seen previously, the characters up to that point will be assigned
0N/A * a font obtained from getFont().
0N/A */
0N/Apublic final class FontResolver {
0N/A
0N/A // An array of all fonts available to the runtime. The fonts
0N/A // will be searched in order.
0N/A private Font[] allFonts;
0N/A private Font[] supplementaryFonts;
0N/A private int[] supplementaryIndices;
0N/A
0N/A // Default size of Fonts (if created from an empty Map, for instance).
0N/A private static final int DEFAULT_SIZE = 12; // from Font
0N/A
0N/A private Font defaultFont = new Font(Font.DIALOG, Font.PLAIN, DEFAULT_SIZE);
0N/A
0N/A // The results of previous lookups are cached in a two-level
0N/A // table. The value for a character c is found in:
0N/A // blocks[c>>SHIFT][c&MASK]
0N/A // although the second array is only allocated when needed.
0N/A // A 0 value means the character's font has not been looked up.
0N/A // A positive value means the character's font is in the allFonts
0N/A // array at index (value-1).
0N/A private static final int SHIFT = 9;
0N/A private static final int BLOCKSIZE = 1<<(16-SHIFT);
0N/A private static final int MASK = BLOCKSIZE-1;
0N/A private int[][] blocks = new int[1<<SHIFT][];
0N/A
0N/A private FontResolver() {
0N/A }
0N/A
0N/A private Font[] getAllFonts() {
0N/A if (allFonts == null) {
0N/A allFonts =
0N/A GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
0N/A for (int i=0; i < allFonts.length; i++) {
0N/A allFonts[i] = allFonts[i].deriveFont((float)DEFAULT_SIZE);
0N/A }
0N/A }
0N/A return allFonts;
0N/A }
0N/A
0N/A /**
0N/A * Search fonts in order, and return "1" to indicate its in the default
0N/A * font, (or not found at all), or the index of the first font
0N/A * which can display the given character, plus 2, if it is not
0N/A * in the default font.
0N/A */
0N/A private int getIndexFor(char c) {
0N/A
0N/A if (defaultFont.canDisplay(c)) {
0N/A return 1;
0N/A }
0N/A for (int i=0; i < getAllFonts().length; i++) {
0N/A if (allFonts[i].canDisplay(c)) {
0N/A return i+2;
0N/A }
0N/A }
0N/A return 1;
0N/A }
0N/A
0N/A private Font [] getAllSCFonts() {
0N/A
0N/A if (supplementaryFonts == null) {
0N/A ArrayList<Font> fonts = new ArrayList<Font>();
0N/A ArrayList<Integer> indices = new ArrayList<Integer>();
0N/A
0N/A for (int i=0; i<getAllFonts().length; i++) {
0N/A Font font = allFonts[i];
1686N/A Font2D font2D = FontUtilities.getFont2D(font);
0N/A if (font2D.hasSupplementaryChars()) {
0N/A fonts.add(font);
215N/A indices.add(Integer.valueOf(i));
0N/A }
0N/A }
0N/A
0N/A int len = fonts.size();
0N/A supplementaryIndices = new int[len];
0N/A for (int i=0; i<len; i++) {
0N/A supplementaryIndices[i] = indices.get(i);
0N/A }
0N/A supplementaryFonts = fonts.toArray(new Font[len]);
0N/A }
0N/A return supplementaryFonts;
0N/A }
0N/A
0N/A /* This method is called only for character codes >= 0x10000 - which
0N/A * are assumed to be legal supplementary characters.
0N/A * It looks first at the default font (to avoid calling getAllFonts if at
0N/A * all possible) and if that doesn't map the code point, it scans
0N/A * just the fonts that may contain supplementary characters.
0N/A * The index that is returned is into the "allFonts" array so that
0N/A * callers see the same value for both supplementary and base chars.
0N/A */
0N/A private int getIndexFor(int cp) {
0N/A
0N/A if (defaultFont.canDisplay(cp)) {
0N/A return 1;
0N/A }
0N/A
0N/A for (int i = 0; i < getAllSCFonts().length; i++) {
0N/A if (supplementaryFonts[i].canDisplay(cp)) {
0N/A return supplementaryIndices[i]+2;
0N/A }
0N/A }
0N/A return 1;
0N/A }
0N/A
0N/A /**
0N/A * Return an index for the given character. The index identifies a
0N/A * font family to getFont(), and has no other inherent meaning.
0N/A * @param c the character to map
0N/A * @return a value for consumption by getFont()
0N/A * @see #getFont
0N/A */
0N/A public int getFontIndex(char c) {
0N/A
0N/A int blockIndex = c>>SHIFT;
0N/A int[] block = blocks[blockIndex];
0N/A if (block == null) {
0N/A block = new int[BLOCKSIZE];
0N/A blocks[blockIndex] = block;
0N/A }
0N/A
0N/A int index = c & MASK;
0N/A if (block[index] == 0) {
0N/A block[index] = getIndexFor(c);
0N/A }
0N/A return block[index];
0N/A }
0N/A
0N/A public int getFontIndex(int cp) {
0N/A if (cp < 0x10000) {
0N/A return getFontIndex((char)cp);
0N/A }
0N/A return getIndexFor(cp);
0N/A }
0N/A
0N/A /**
0N/A * Determines the font index for the code point at the current position in the
0N/A * iterator, then advances the iterator to the first code point that has
0N/A * a different index or until the iterator is DONE, and returns the font index.
0N/A * @param iter a code point iterator, this will be advanced past any code
0N/A * points that have the same font index
0N/A * @return the font index for the initial code point found, or 1 if the iterator
0N/A * was empty.
0N/A */
0N/A public int nextFontRunIndex(CodePointIterator iter) {
0N/A int cp = iter.next();
0N/A int fontIndex = 1;
0N/A if (cp != CodePointIterator.DONE) {
0N/A fontIndex = getFontIndex(cp);
0N/A
0N/A while ((cp = iter.next()) != CodePointIterator.DONE) {
0N/A if (getFontIndex(cp) != fontIndex) {
0N/A iter.prev();
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A return fontIndex;
0N/A }
0N/A
0N/A /**
0N/A * Return a Font from a given font index with properties
0N/A * from attributes. The font index, which should have been produced
0N/A * by getFontIndex(), determines a font family. The size and style
0N/A * of the Font reflect the properties in attributes. Any Font or
0N/A * font family specifications in attributes are ignored, on the
0N/A * assumption that clients have already handled them.
0N/A * @param index an index from getFontIndex() which determines the
0N/A * font family
0N/A * @param attributes a Map from which the size and style of the Font
0N/A * are determined. The default size is 12 and the default style
0N/A * is Font.PLAIN
0N/A * @see #getFontIndex
0N/A */
0N/A public Font getFont(int index, Map attributes) {
0N/A Font font = defaultFont;
0N/A
0N/A if (index >= 2) {
0N/A font = allFonts[index-2];
0N/A }
0N/A
0N/A return font.deriveFont(attributes);
0N/A }
0N/A
0N/A private static FontResolver INSTANCE;
0N/A
0N/A /**
0N/A * Return a shared instance of FontResolver.
0N/A */
0N/A public static FontResolver getInstance() {
0N/A if (INSTANCE == null) {
0N/A INSTANCE = new FontResolver();
0N/A }
0N/A return INSTANCE;
0N/A }
0N/A}