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 */ 21 package org.apache.harmony.awt.gl.font; 22 23 import java.awt.Font; 24 import java.awt.peer.FontPeer; 25 import java.io.File; 26 import java.io.IOException; 27 import java.util.Properties; 28 import java.util.Vector; 29 30 import org.apache.harmony.awt.gl.font.FontManager; 31 import org.apache.harmony.awt.gl.font.FontProperty; 32 import org.apache.harmony.awt.internal.nls.Messages; 33 34 import android.util.Log; 35 36 public 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