1 /* 2 * Copyright 2000-2007 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 package sun.awt.motif; 27 28 import java.awt.Font; 29 import java.io.BufferedReader; 30 import java.io.File; 31 import java.io.FileInputStream; 32 import java.io.InputStreamReader; 33 import java.util.HashMap; 34 import java.util.HashSet; 35 import java.util.Locale; 36 import java.util.logging.Logger; 37 import java.util.Properties; 38 import java.util.Scanner; 39 import sun.awt.FontConfiguration; 40 import sun.awt.X11GraphicsEnvironment; 41 import sun.java2d.SunGraphicsEnvironment; 42 import java.nio.charset.Charset; 43 44 public class MFontConfiguration extends FontConfiguration { 45 46 private static FontConfiguration fontConfig = null; 47 private static Logger logger; 48 49 public MFontConfiguration(SunGraphicsEnvironment environment) { 50 super(environment); 51 if (SunGraphicsEnvironment.debugFonts) { 52 logger = Logger.getLogger("sun.awt.FontConfiguration"); 53 } 54 initTables(); 55 } 56 57 58 public MFontConfiguration(SunGraphicsEnvironment environment, 59 boolean preferLocaleFonts, 60 boolean preferPropFonts) { 61 super(environment, preferLocaleFonts, preferPropFonts); 62 if (SunGraphicsEnvironment.debugFonts) { 63 logger = Logger.getLogger("sun.awt.FontConfiguration"); 64 } 65 initTables(); 66 } 67 68 /* Needs to be kept in sync with updates in the languages used in 69 * the fontconfig files. 70 */ 71 protected void initReorderMap() { 72 reorderMap = new HashMap(); 73 if (osName == null) { /* null means SunOS */ 74 initReorderMapForSolaris(); 75 } else { 76 initReorderMapForLinux(); 77 } 78 } 79 80 private void initReorderMapForSolaris() { 81 /* Don't create a no-op entry, so we can optimize this case 82 * i.e. we don't need to do anything so can avoid slower paths in 83 * the code. 84 */ 85 // reorderMap.put("UTF-8", "latin-1"); 86 reorderMap.put("UTF-8.hi", "devanagari"); // NB is in Lucida. 87 reorderMap.put("UTF-8.ja", 88 split("japanese-x0201,japanese-x0208,japanese-x0212")); 89 reorderMap.put("UTF-8.ko", "korean-johab"); 90 reorderMap.put("UTF-8.th", "thai"); 91 reorderMap.put("UTF-8.zh.TW", "chinese-big5"); 92 reorderMap.put("UTF-8.zh.HK", split("chinese-big5,chinese-hkscs")); 93 if (sun.font.FontManager.isSolaris8) { 94 reorderMap.put("UTF-8.zh.CN", split("chinese-gb2312,chinese-big5")); 95 } else { 96 reorderMap.put("UTF-8.zh.CN", 97 split("chinese-gb18030-0,chinese-gb18030-1")); 98 } 99 reorderMap.put("UTF-8.zh", 100 split("chinese-big5,chinese-hkscs,chinese-gb18030-0,chinese-gb18030-1")); 101 reorderMap.put("Big5", "chinese-big5"); 102 reorderMap.put("Big5-HKSCS", split("chinese-big5,chinese-hkscs")); 103 if (! sun.font.FontManager.isSolaris8 && ! sun.font.FontManager.isSolaris9) { 104 reorderMap.put("GB2312", split("chinese-gbk,chinese-gb2312")); 105 } else { 106 reorderMap.put("GB2312","chinese-gb2312"); 107 } 108 reorderMap.put("x-EUC-TW", 109 split("chinese-cns11643-1,chinese-cns11643-2,chinese-cns11643-3")); 110 reorderMap.put("GBK", "chinese-gbk"); 111 reorderMap.put("GB18030",split("chinese-gb18030-0,chinese-gb18030-1")); 112 113 reorderMap.put("TIS-620", "thai"); 114 reorderMap.put("x-PCK", 115 split("japanese-x0201,japanese-x0208,japanese-x0212")); 116 reorderMap.put("x-eucJP-Open", 117 split("japanese-x0201,japanese-x0208,japanese-x0212")); 118 reorderMap.put("EUC-KR", "korean"); 119 /* Don't create a no-op entry, so we can optimize this case */ 120 // reorderMap.put("ISO-8859-1", "latin-1"); 121 reorderMap.put("ISO-8859-2", "latin-2"); 122 reorderMap.put("ISO-8859-5", "cyrillic-iso8859-5"); 123 reorderMap.put("windows-1251", "cyrillic-cp1251"); 124 reorderMap.put("KOI8-R", "cyrillic-koi8-r"); 125 reorderMap.put("ISO-8859-6", "arabic"); 126 reorderMap.put("ISO-8859-7", "greek"); 127 reorderMap.put("ISO-8859-8", "hebrew"); 128 reorderMap.put("ISO-8859-9", "latin-5"); 129 reorderMap.put("ISO-8859-13", "latin-7"); 130 reorderMap.put("ISO-8859-15", "latin-9"); 131 } 132 133 private void initReorderMapForLinux() { 134 reorderMap.put("UTF-8.ja.JP", "japanese-iso10646"); 135 reorderMap.put("UTF-8.ko.KR", "korean-iso10646"); 136 reorderMap.put("UTF-8.zh.TW", "chinese-tw-iso10646"); 137 reorderMap.put("UTF-8.zh.HK", "chinese-tw-iso10646"); 138 reorderMap.put("UTF-8.zh.CN", "chinese-cn-iso10646"); 139 reorderMap.put("x-euc-jp-linux", 140 split("japanese-x0201,japanese-x0208")); 141 reorderMap.put("GB2312", "chinese-gb18030"); 142 reorderMap.put("Big5", "chinese-big5"); 143 reorderMap.put("EUC-KR", "korean"); 144 if (osName.equals("Sun")){ 145 reorderMap.put("GB18030", "chinese-cn-iso10646"); 146 } 147 else { 148 reorderMap.put("GB18030", "chinese-gb18030"); 149 } 150 } 151 152 /** 153 * Sets the OS name and version from environment information. 154 */ 155 protected void setOsNameAndVersion(){ 156 super.setOsNameAndVersion(); 157 158 if (osName.equals("SunOS")) { 159 //don't care os name on Solaris 160 osName = null; 161 } else if (osName.equals("Linux")) { 162 try { 163 File f; 164 if ((f = new File("/etc/sun-release")).canRead()) { 165 osName = "Sun"; 166 osVersion = getVersionString(f); 167 } else if ((f = new File("/etc/fedora-release")).canRead()) { 168 osName = "Fedora"; 169 osVersion = getVersionString(f); 170 } else if ((f = new File("/etc/redhat-release")).canRead()) { 171 osName = "RedHat"; 172 osVersion = getVersionString(f); 173 } else if ((f = new File("/etc/turbolinux-release")).canRead()) { 174 osName = "Turbo"; 175 osVersion = getVersionString(f); 176 } else if ((f = new File("/etc/SuSE-release")).canRead()) { 177 osName = "SuSE"; 178 osVersion = getVersionString(f); 179 } else if ((f = new File("/etc/lsb-release")).canRead()) { 180 /* Ubuntu and (perhaps others) use only lsb-release. 181 * Syntax and encoding is compatible with java properties. 182 * For Ubuntu the ID is "Ubuntu". 183 */ 184 Properties props = new Properties(); 185 props.load(new FileInputStream(f)); 186 osName = props.getProperty("DISTRIB_ID"); 187 osVersion = props.getProperty("DISTRIB_RELEASE"); 188 } 189 } catch (Exception e) { 190 } 191 } 192 return; 193 } 194 195 /** 196 * Gets the OS version string from a Linux release-specific file. 197 */ 198 private String getVersionString(File f){ 199 try { 200 Scanner sc = new Scanner(f); 201 return sc.findInLine("(\\d)+((\\.)(\\d)+)*"); 202 } 203 catch (Exception e){ 204 } 205 return null; 206 } 207 208 private static final String fontsDirPrefix = "$JRE_LIB_FONTS"; 209 210 protected String mapFileName(String fileName) { 211 if (fileName != null && fileName.startsWith(fontsDirPrefix)) { 212 return SunGraphicsEnvironment.jreFontDirName 213 + fileName.substring(fontsDirPrefix.length()); 214 } 215 return fileName; 216 } 217 218 // overrides FontConfiguration.getFallbackFamilyName 219 public String getFallbackFamilyName(String fontName, String defaultFallback) { 220 // maintain compatibility with old font.properties files, which 221 // either had aliases for TimesRoman & Co. or defined mappings for them. 222 String compatibilityName = getCompatibilityFamilyName(fontName); 223 if (compatibilityName != null) { 224 return compatibilityName; 225 } 226 return defaultFallback; 227 } 228 229 protected String getEncoding(String awtFontName, 230 String characterSubsetName) { 231 // extract encoding field from XLFD 232 int beginIndex = 0; 233 int fieldNum = 13; // charset registry field 234 while (fieldNum-- > 0 && beginIndex >= 0) { 235 beginIndex = awtFontName.indexOf("-", beginIndex) + 1; 236 } 237 if (beginIndex == -1) { 238 return "default"; 239 } 240 String xlfdEncoding = awtFontName.substring(beginIndex); 241 if (xlfdEncoding.indexOf("fontspecific") > 0) { 242 if (awtFontName.indexOf("dingbats") > 0) { 243 return "sun.awt.motif.X11Dingbats"; 244 } else if (awtFontName.indexOf("symbol") > 0) { 245 return "sun.awt.Symbol"; 246 } 247 } 248 String encoding = (String) encodingMap.get(xlfdEncoding); 249 if (encoding == null) { 250 encoding = "default"; 251 } 252 return encoding; 253 } 254 255 protected Charset getDefaultFontCharset(String fontName) { 256 return Charset.forName("ISO8859_1"); 257 } 258 259 /* methods for Motif support *********************************************/ 260 261 private String[][] motifFontSets = new String[NUM_FONTS][NUM_STYLES]; 262 263 public String getMotifFontSet(String fontName, int style) { 264 assert isLogicalFontFamilyName(fontName); 265 fontName = fontName.toLowerCase(Locale.ENGLISH); 266 int fontIndex = getFontIndex(fontName); 267 int styleIndex = getStyleIndex(style); 268 return getMotifFontSet(fontIndex, styleIndex); 269 } 270 271 private String getMotifFontSet(int fontIndex, int styleIndex) { 272 String fontSet = motifFontSets[fontIndex][styleIndex]; 273 if (fontSet == null) { 274 fontSet = buildMotifFontSet(fontIndex, styleIndex); 275 motifFontSets[fontIndex][styleIndex] = fontSet; 276 } 277 return fontSet; 278 } 279 280 private String buildMotifFontSet(int fontIndex, int styleIndex) { 281 StringBuilder buffer = new StringBuilder(); 282 short[] scripts = getCoreScripts(fontIndex); 283 for (int i = 0; i < scripts.length; i++) { 284 short nameID = getComponentFontIDMotif(scripts[i], fontIndex, styleIndex); 285 if (nameID == 0) { 286 nameID = getComponentFontID(scripts[i], fontIndex, styleIndex); 287 } 288 String name = getComponentFontName(nameID); 289 if (name == null || name.endsWith("fontspecific")) { 290 continue; 291 } 292 if (buffer.length() > 0) { 293 buffer.append(','); 294 } 295 buffer.append(name); 296 } 297 return buffer.toString(); 298 } 299 300 protected String getFaceNameFromComponentFontName(String componentFontName) { 301 return null; 302 } 303 304 protected String getFileNameFromComponentFontName(String componentFontName) { 305 // for X11, component font name is XLFD 306 // if we have a file name already, just use it; otherwise let's see 307 // what the graphics environment can provide 308 String fileName = getFileNameFromPlatformName(componentFontName); 309 if (fileName != null && fileName.charAt(0) == '/' && 310 !needToSearchForFile(fileName)) { 311 return fileName; 312 } 313 return ((X11GraphicsEnvironment) environment).getFileNameFromXLFD(componentFontName); 314 } 315 316 /** 317 * Get default font for Motif widgets to use, preventing them from 318 * wasting time accessing inappropriate X resources. This is called 319 * only from native code. 320 * 321 * This is part of a Motif specific performance enhancement. By 322 * default, when Motif widgets are created and initialized, Motif will 323 * set up default fonts for the widgets, which we ALWAYS override. 324 * This set up includes finding the default font in the widget's X 325 * resources and fairly expensive requests of the X server to identify 326 * the specific font or fontset. We avoid all of this overhead by 327 * providing a well known font to use at the creation of widgets, where 328 * possible. 329 * 330 * The X11 fonts are specified by XLFD strings which have %d as a 331 * marker to indicate where the fontsize should be substituted. [The 332 * libc function sprintf() is used to replace it.] The value 140 333 * specifies a font size of 14 points. 334 */ 335 private static String getDefaultMotifFontSet() { 336 String font = ((MFontConfiguration) getFontConfiguration()).getMotifFontSet("sansserif", Font.PLAIN); 337 if (font != null) { 338 int i; 339 while ((i = font.indexOf("%d")) >= 0) { 340 font = font.substring(0, i) + "140" + font.substring(i+2); 341 } 342 } 343 return font; 344 } 345 346 public HashSet<String> getAWTFontPathSet() { 347 HashSet<String> fontDirs = new HashSet<String>(); 348 short[] scripts = getCoreScripts(0); 349 for (int i = 0; i< scripts.length; i++) { 350 String path = getString(table_awtfontpaths[scripts[i]]); 351 if (path != null) { 352 int start = 0; 353 int colon = path.indexOf(':'); 354 while (colon >= 0) { 355 fontDirs.add(path.substring(start, colon)); 356 start = colon + 1; 357 colon = path.indexOf(':', start); 358 } 359 fontDirs.add((start == 0) ? path : path.substring(start)); 360 } 361 } 362 return fontDirs; 363 } 364 365 /* methods for table setup ***********************************************/ 366 367 private static HashMap encodingMap = new HashMap(); 368 369 private void initTables() { 370 // encodingMap maps XLFD encoding component to 371 // name of corresponding java.nio charset 372 encodingMap.put("iso8859-1", "ISO-8859-1"); 373 encodingMap.put("iso8859-2", "ISO-8859-2"); 374 encodingMap.put("iso8859-4", "ISO-8859-4"); 375 encodingMap.put("iso8859-5", "ISO-8859-5"); 376 encodingMap.put("iso8859-6", "ISO-8859-6"); 377 encodingMap.put("iso8859-7", "ISO-8859-7"); 378 encodingMap.put("iso8859-8", "ISO-8859-8"); 379 encodingMap.put("iso8859-9", "ISO-8859-9"); 380 encodingMap.put("iso8859-13", "ISO-8859-13"); 381 encodingMap.put("iso8859-15", "ISO-8859-15"); 382 encodingMap.put("gb2312.1980-0", "sun.awt.motif.X11GB2312"); 383 if (osName == null) { 384 // use standard converter on Solaris 385 encodingMap.put("gbk-0", "GBK"); 386 } else { 387 encodingMap.put("gbk-0", "sun.awt.motif.X11GBK"); 388 } 389 encodingMap.put("gb18030.2000-0", "sun.awt.motif.X11GB18030_0"); 390 encodingMap.put("gb18030.2000-1", "sun.awt.motif.X11GB18030_1"); 391 encodingMap.put("cns11643-1", "sun.awt.motif.X11CNS11643P1"); 392 encodingMap.put("cns11643-2", "sun.awt.motif.X11CNS11643P2"); 393 encodingMap.put("cns11643-3", "sun.awt.motif.X11CNS11643P3"); 394 encodingMap.put("big5-1", "Big5"); 395 encodingMap.put("big5-0", "Big5"); 396 encodingMap.put("hkscs-1", "Big5-HKSCS"); 397 encodingMap.put("ansi-1251", "windows-1251"); 398 encodingMap.put("koi8-r", "KOI8-R"); 399 encodingMap.put("jisx0201.1976-0", "sun.awt.motif.X11JIS0201"); 400 encodingMap.put("jisx0208.1983-0", "sun.awt.motif.X11JIS0208"); 401 encodingMap.put("jisx0212.1990-0", "sun.awt.motif.X11JIS0212"); 402 encodingMap.put("ksc5601.1987-0", "sun.awt.motif.X11KSC5601"); 403 encodingMap.put("ksc5601.1992-3", "sun.awt.motif.X11Johab"); 404 encodingMap.put("tis620.2533-0", "TIS-620"); 405 encodingMap.put("iso10646-1", "UTF-16BE"); 406 } 407 408 }