1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17/**
18 * @author Oleg V. Khaschansky
19 * @version $Revision$
20 *
21 * @date: Jul 12, 2005
22 */
23
24package org.apache.harmony.awt.gl.font;
25
26import java.awt.Font;
27import java.awt.GraphicsEnvironment;
28import java.util.List;
29import java.util.Map;
30
31/**
32 * This class chooses the default font for the given text.
33 * If it finds the character which current font is unable to display
34 * it starts the next font run and looks for the font which is able to
35 * display the current character. It also caches the font mappings
36 * (index in the array containing all fonts) for the characters,
37 * using that fact that scripts are mainly contiguous in the UTF-16 encoding
38 * and there's a high probability that the upper byte will be the same for the
39 * next character as for the previous. This allows to save the space used for the cache.
40 */
41public class FontFinder {
42    private static final float DEFAULT_FONT_SIZE = 12;
43
44    private static final Font fonts[] =
45            GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
46
47    private static final int NUM_BLOCKS = 256;
48    private static final int BLOCK_SIZE = 256;
49    private static final int INDEX_MASK = 0xFF;
50    private static final int BLOCK_SHIFT = 8;
51
52    // Maps characters into the fonts array
53    private static final int blocks[][] = new int[NUM_BLOCKS][];
54
55    /**
56     * Finds the font which is able to display the given character
57     * and saves the font mapping for this character
58     * @param c - character
59     * @return font
60     */
61    static Font findFontForChar(char c) {
62        int blockNum = c >> BLOCK_SHIFT;
63        int index = c & INDEX_MASK;
64
65        if (blocks[blockNum] == null) {
66            blocks[blockNum] = new int[BLOCK_SIZE];
67        }
68
69        if (blocks[blockNum][index] == 0) {
70            blocks[blockNum][index] = 1;
71
72            for (int i=0; i<fonts.length; i++) {
73                if (fonts[i].canDisplay(c)) {
74                    blocks[blockNum][index] = i+1;
75                    break;
76                }
77            }
78        }
79
80        return getDefaultSizeFont(blocks[blockNum][index]-1);
81    }
82
83    /**
84     * Derives the default size font
85     * @param i - index in the array of all fonts
86     * @return derived font
87     */
88    static Font getDefaultSizeFont(int i) {
89        if (fonts[i].getSize() != DEFAULT_FONT_SIZE) {
90            fonts[i] = fonts[i].deriveFont(DEFAULT_FONT_SIZE);
91        }
92
93        return fonts[i];
94    }
95
96    /**
97     * Assigns default fonts for the given text run.
98     * First three parameters are input, last three are output.
99     * @param text - given text
100     * @param runStart - start of the text run
101     * @param runLimit - end of the text run
102     * @param runStarts - starts of the resulting font runs
103     * @param fonts - mapping of the font run starts to the fonts
104     */
105    static void findFonts(char text[], int runStart, int runLimit, List<Integer> runStarts,
106            Map<Integer, Font> fonts) {
107        Font prevFont = null;
108        Font currFont;
109        for (int i = runStart; i < runLimit; i++) {
110            currFont = findFontForChar(text[i]);
111            if (currFont != prevFont) {
112                prevFont = currFont;
113                Integer idx = new Integer(i);
114                fonts.put(idx, currFont);
115                if (i != runStart) {
116                    runStarts.add(idx);
117                }
118            }
119        }
120    }
121}
122