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