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 Ilya S. Okomin
19 * @version $Revision$
20 */
21package org.apache.harmony.awt.gl.font;
22
23import java.awt.Font;
24import java.awt.peer.FontPeer;
25import java.io.File;
26import java.io.IOException;
27import java.util.Properties;
28import java.util.Vector;
29
30import org.apache.harmony.awt.gl.font.FontManager;
31import org.apache.harmony.awt.gl.font.FontProperty;
32import org.apache.harmony.awt.internal.nls.Messages;
33
34import android.util.Log;
35
36public class AndroidFontManager extends FontManager {
37
38    // set of all available faces supported by a system
39    String faces[];
40
41    // weight names according to xlfd structure
42    public static final String[] LINUX_WEIGHT_NAMES = {
43            "black", "bold", "demibold", "medium", "light" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
44    };
45
46    // slant names according to xlfd structure
47    public static final String[] LINUX_SLANT_NAMES = {
48            "i", "o", "r" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
49    };
50
51    /** Singleton AndroidFontManager instance */
52    public static final AndroidFontManager inst = new AndroidFontManager();
53
54    private AndroidFontManager() {
55        super();
56        faces = new String[] {/*"PLAIN",*/ "NORMAL", "BOLD", "ITALIC", "BOLDITALIC"};
57        initFontProperties();
58    }
59
60    public void initLCIDTable(){
61    	throw new RuntimeException("Not implemented!");
62    }
63
64    /**
65     * Returns temporary File object to store data from InputStream.
66     * This File object saved to `~/.fonts/' folder that is included in the
67     * list of folders searched for font files, and this is where user-specific
68     * font files should be installed.
69     */
70    public File getTempFontFile()throws IOException{
71        File fontFile = File.createTempFile("jFont", ".ttf", new File(System.getProperty("user.home") +"/.fonts")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
72        fontFile.deleteOnExit();
73
74        return fontFile;
75    }
76
77    /**
78     * Initializes fProperties array field for the current system configuration font
79     * property file.
80     *
81     * RuntimeException is thrown if font property contains incorrect format of
82     * xlfd string.
83     *
84     * @return true is success, false if font property doesn't exist or doesn't
85     * contain roperties.
86     */
87    public boolean initFontProperties(){
88        File fpFile = getFontPropertyFile();
89        if (fpFile == null){
90            return false;
91        }
92
93        Properties props = getProperties(fpFile);
94        if (props == null){
95            return false;
96        }
97
98        for (int i=0; i < LOGICAL_FONT_NAMES.length; i++){
99            String lName = LOGICAL_FONT_NAMES[i];
100            for (int j=0; j < STYLE_NAMES.length; j++){
101                String styleName = STYLE_NAMES[j];
102                Vector propsVector = new Vector();
103
104                // Number of entries for a logical font
105                int numComp = 0;
106                // Is more entries for this style and logical font name left
107                boolean moreEntries = true;
108                String value = null;
109
110                while(moreEntries){
111                    // Component Font Mappings property name
112                    String property = FONT_MAPPING_KEYS[0].replaceAll("LogicalFontName", lName).replaceAll("StyleName", styleName).replaceAll("ComponentIndex", String.valueOf(numComp)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
113                    value = props.getProperty(property);
114
115                    // If the StyleName is omitted, it's assumed to be plain
116                    if ((j == 0) && (value == null)){
117                        property = FONT_MAPPING_KEYS[1].replaceAll("LogicalFontName", lName).replaceAll("ComponentIndex", String.valueOf(numComp)); //$NON-NLS-1$ //$NON-NLS-2$
118                        value = props.getProperty(property);
119                    }
120
121                    if (value != null){
122                        String[] fields = parseXLFD(value);
123
124                        if (fields == null){
125                            // awt.08=xfld parse string error: {0}
126                            throw new RuntimeException(Messages.getString("awt.08", value)); //$NON-NLS-1$
127                        }
128
129                        String fontName = fields[1];
130                        String weight = fields[2];
131                        String italic = fields[3];
132
133                        int style = getBoldStyle(weight) | getItalicStyle(italic);
134                        // Component Font Character Encodings property value
135                        String encoding = props.getProperty(FONT_CHARACTER_ENCODING.replaceAll("LogicalFontName", lName).replaceAll("ComponentIndex", String.valueOf(numComp))); //$NON-NLS-1$ //$NON-NLS-2$
136
137                        // Exclusion Ranges property value
138                        String exclString = props.getProperty(EXCLUSION_RANGES.replaceAll("LogicalFontName", lName).replaceAll("ComponentIndex", String.valueOf(numComp))); //$NON-NLS-1$ //$NON-NLS-2$
139                        int[] exclRange = parseIntervals(exclString);
140
141                        FontProperty fp = new AndroidFontProperty(lName, styleName, null, fontName, value, style, exclRange, encoding);
142
143                        propsVector.add(fp);
144                        numComp++;
145                    } else {
146                        moreEntries = false;
147                    }
148                }
149                fProperties.put(LOGICAL_FONT_NAMES[i] + "." + j, propsVector); //$NON-NLS-1$
150            }
151        }
152
153        return true;
154
155    }
156
157    /**
158     * Returns style according to the xlfd weight string.
159     * If weight string is incorrect returned value is Font.PLAIN
160     *
161     * @param str weight name String
162     */
163    private int getBoldStyle(String str){
164        for (int i = 0; i < LINUX_WEIGHT_NAMES.length;i++){
165            if (str.equalsIgnoreCase(LINUX_WEIGHT_NAMES[i])){
166                return (i < 3) ? Font.BOLD : Font.PLAIN;
167            }
168        }
169        return Font.PLAIN;
170    }
171
172    /**
173     * Returns style according to the xlfd slant string.
174     * If slant string is incorrect returned value is Font.PLAIN
175     *
176     * @param str slant name String
177     */
178    private int getItalicStyle(String str){
179        for (int i = 0; i < LINUX_SLANT_NAMES.length;i++){
180            if (str.equalsIgnoreCase(LINUX_SLANT_NAMES[i])){
181                return (i < 2) ? Font.ITALIC : Font.PLAIN;
182            }
183        }
184        return Font.PLAIN;
185    }
186
187    /**
188     * Parse xlfd string and returns array of Strings with separate xlfd
189     * elements.<p>
190     *
191     * xlfd format:
192     *      -Foundry-Family-Weight-Slant-Width-Style-PixelSize-PointSize-ResX-ResY-Spacing-AvgWidth-Registry-Encoding
193     * @param xlfd String parameter in xlfd format
194     */
195    public static String[] parseXLFD(String xlfd){
196        int fieldsCount = 14;
197        String fieldsDelim = "-"; //$NON-NLS-1$
198        String[] res = new String[fieldsCount];
199        if (!xlfd.startsWith(fieldsDelim)){
200            return null;
201        }
202
203        xlfd = xlfd.substring(1);
204        int i=0;
205        int pos;
206        for (i=0; i < fieldsCount-1; i++){
207            pos = xlfd.indexOf(fieldsDelim);
208            if (pos != -1){
209                res[i] = xlfd.substring(0, pos);
210                xlfd = xlfd.substring(pos + 1);
211            } else {
212                return null;
213            }
214        }
215        pos = xlfd.indexOf(fieldsDelim);
216
217        // check if no fields left
218        if(pos != -1){
219            return null;
220        }
221        res[fieldsCount-1] = xlfd;
222
223        return res;
224    }
225
226    public int getFaceIndex(String faceName){
227
228        for (int i = 0; i < faces.length; i++) {
229            if(faces[i].equals(faceName)){
230                return i;
231            }
232        }
233        return -1;
234    }
235
236    public String[] getAllFamilies(){
237        if (allFamilies == null){
238        	allFamilies = new String[]{"sans-serif", "serif", "monospace"};
239        }
240        return allFamilies;
241    }
242
243    public Font[] getAllFonts(){
244        Font[] fonts = new Font[faces.length];
245        for (int i =0; i < fonts.length;i++){
246            fonts[i] = new Font(faces[i], Font.PLAIN, 1);
247        }
248        return fonts;
249    }
250
251    public FontPeer createPhysicalFontPeer(String name, int style, int size) {
252        AndroidFont peer;
253        int familyIndex = getFamilyIndex(name);
254        if (familyIndex != -1){
255            // !! we use family names from the list with cached families because
256            // they are differ from the family names in xlfd structure, in xlfd
257            // family names mostly in lower case.
258            peer = new AndroidFont(getFamily(familyIndex), style, size);
259            peer.setFamily(getFamily(familyIndex));
260            return peer;
261        }
262        int faceIndex = getFaceIndex(name);
263        if (faceIndex != -1){
264
265            peer = new AndroidFont(name, style, size);
266            return peer;
267        }
268
269        return null;
270    }
271
272    public FontPeer createDefaultFont(int style, int size) {
273    	Log.i("DEFAULT FONT", Integer.toString(style));
274        return new AndroidFont(DEFAULT_NAME, style, size);
275    }
276
277}
278