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 }