001: /*
002: * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.awt.motif;
027:
028: import java.awt.Font;
029: import java.io.BufferedReader;
030: import java.io.File;
031: import java.io.FileInputStream;
032: import java.io.InputStreamReader;
033: import java.util.HashMap;
034: import java.util.HashSet;
035: import java.util.Locale;
036: import java.util.logging.Logger;
037: import java.util.Properties;
038: import java.util.Scanner;
039: import sun.awt.FontConfiguration;
040: import sun.awt.X11GraphicsEnvironment;
041: import sun.java2d.SunGraphicsEnvironment;
042: import java.nio.charset.Charset;
043:
044: public class MFontConfiguration extends FontConfiguration {
045:
046: private static FontConfiguration fontConfig = null;
047: private static Logger logger;
048:
049: public MFontConfiguration(SunGraphicsEnvironment environment) {
050: super (environment);
051: if (SunGraphicsEnvironment.debugFonts) {
052: logger = Logger.getLogger("sun.awt.FontConfiguration");
053: }
054: initTables();
055: }
056:
057: public MFontConfiguration(SunGraphicsEnvironment environment,
058: boolean preferLocaleFonts, boolean preferPropFonts) {
059: super (environment, preferLocaleFonts, preferPropFonts);
060: if (SunGraphicsEnvironment.debugFonts) {
061: logger = Logger.getLogger("sun.awt.FontConfiguration");
062: }
063: initTables();
064: }
065:
066: /* Needs to be kept in sync with updates in the languages used in
067: * the fontconfig files.
068: */
069: protected void initReorderMap() {
070: reorderMap = new HashMap();
071: if (osName == null) { /* null means SunOS */
072: initReorderMapForSolaris();
073: } else {
074: initReorderMapForLinux();
075: }
076: }
077:
078: private void initReorderMapForSolaris() {
079: /* Don't create a no-op entry, so we can optimize this case
080: * i.e. we don't need to do anything so can avoid slower paths in
081: * the code.
082: */
083: // reorderMap.put("UTF-8", "latin-1");
084: reorderMap.put("UTF-8.hi", "devanagari"); // NB is in Lucida.
085: reorderMap.put("UTF-8.ja",
086: split("japanese-x0201,japanese-x0208,japanese-x0212"));
087: reorderMap.put("UTF-8.ko", "korean-johab");
088: reorderMap.put("UTF-8.th", "thai");
089: reorderMap.put("UTF-8.zh.TW", "chinese-big5");
090: reorderMap.put("UTF-8.zh.HK",
091: split("chinese-big5,chinese-hkscs"));
092: if (sun.font.FontManager.isSolaris8) {
093: reorderMap.put("UTF-8.zh.CN",
094: split("chinese-gb2312,chinese-big5"));
095: } else {
096: reorderMap.put("UTF-8.zh.CN",
097: split("chinese-gb18030-0,chinese-gb18030-1"));
098: }
099: reorderMap
100: .put(
101: "UTF-8.zh",
102: split("chinese-big5,chinese-hkscs,chinese-gb18030-0,chinese-gb18030-1"));
103: reorderMap.put("Big5", "chinese-big5");
104: reorderMap.put("Big5-HKSCS",
105: split("chinese-big5,chinese-hkscs"));
106: if (!sun.font.FontManager.isSolaris8
107: && !sun.font.FontManager.isSolaris9) {
108: reorderMap.put("GB2312",
109: split("chinese-gbk,chinese-gb2312"));
110: } else {
111: reorderMap.put("GB2312", "chinese-gb2312");
112: }
113: reorderMap
114: .put(
115: "x-EUC-TW",
116: split("chinese-cns11643-1,chinese-cns11643-2,chinese-cns11643-3"));
117: reorderMap.put("GBK", "chinese-gbk");
118: reorderMap.put("GB18030",
119: split("chinese-gb18030-0,chinese-gb18030-1"));
120:
121: reorderMap.put("TIS-620", "thai");
122: reorderMap.put("x-PCK",
123: split("japanese-x0201,japanese-x0208,japanese-x0212"));
124: reorderMap.put("x-eucJP-Open",
125: split("japanese-x0201,japanese-x0208,japanese-x0212"));
126: reorderMap.put("EUC-KR", "korean");
127: /* Don't create a no-op entry, so we can optimize this case */
128: // reorderMap.put("ISO-8859-1", "latin-1");
129: reorderMap.put("ISO-8859-2", "latin-2");
130: reorderMap.put("ISO-8859-5", "cyrillic-iso8859-5");
131: reorderMap.put("windows-1251", "cyrillic-cp1251");
132: reorderMap.put("KOI8-R", "cyrillic-koi8-r");
133: reorderMap.put("ISO-8859-6", "arabic");
134: reorderMap.put("ISO-8859-7", "greek");
135: reorderMap.put("ISO-8859-8", "hebrew");
136: reorderMap.put("ISO-8859-9", "latin-5");
137: reorderMap.put("ISO-8859-13", "latin-7");
138: reorderMap.put("ISO-8859-15", "latin-9");
139: }
140:
141: private void initReorderMapForLinux() {
142: reorderMap.put("UTF-8.ja.JP", "japanese-iso10646");
143: reorderMap.put("UTF-8.ko.KR", "korean-iso10646");
144: reorderMap.put("UTF-8.zh.TW", "chinese-tw-iso10646");
145: reorderMap.put("UTF-8.zh.HK", "chinese-tw-iso10646");
146: reorderMap.put("UTF-8.zh.CN", "chinese-cn-iso10646");
147: reorderMap.put("x-euc-jp-linux",
148: split("japanese-x0201,japanese-x0208"));
149: reorderMap.put("GB2312", "chinese-gb18030");
150: reorderMap.put("Big5", "chinese-big5");
151: reorderMap.put("EUC-KR", "korean");
152: if (osName.equals("Sun")) {
153: reorderMap.put("GB18030", "chinese-cn-iso10646");
154: } else {
155: reorderMap.put("GB18030", "chinese-gb18030");
156: }
157: }
158:
159: /**
160: * Sets the OS name and version from environment information.
161: */
162: protected void setOsNameAndVersion() {
163: super .setOsNameAndVersion();
164:
165: if (osName.equals("SunOS")) {
166: //don't care os name on Solaris
167: osName = null;
168: } else if (osName.equals("Linux")) {
169: try {
170: File f;
171: if ((f = new File("/etc/sun-release")).canRead()) {
172: osName = "Sun";
173: osVersion = getVersionString(f);
174: } else if ((f = new File("/etc/fedora-release"))
175: .canRead()) {
176: osName = "Fedora";
177: osVersion = getVersionString(f);
178: } else if ((f = new File("/etc/redhat-release"))
179: .canRead()) {
180: osName = "RedHat";
181: osVersion = getVersionString(f);
182: } else if ((f = new File("/etc/turbolinux-release"))
183: .canRead()) {
184: osName = "Turbo";
185: osVersion = getVersionString(f);
186: } else if ((f = new File("/etc/SuSE-release"))
187: .canRead()) {
188: osName = "SuSE";
189: osVersion = getVersionString(f);
190: } else if ((f = new File("/etc/lsb-release")).canRead()) {
191: /* Ubuntu and (perhaps others) use only lsb-release.
192: * Syntax and encoding is compatible with java properties.
193: * For Ubuntu the ID is "Ubuntu".
194: */
195: Properties props = new Properties();
196: props.load(new FileInputStream(f));
197: osName = props.getProperty("DISTRIB_ID");
198: osVersion = props.getProperty("DISTRIB_RELEASE");
199: }
200: } catch (Exception e) {
201: }
202: }
203: return;
204: }
205:
206: /**
207: * Gets the OS version string from a Linux release-specific file.
208: */
209: private String getVersionString(File f) {
210: try {
211: Scanner sc = new Scanner(f);
212: return sc.findInLine("(\\d)+((\\.)(\\d)+)*");
213: } catch (Exception e) {
214: }
215: return null;
216: }
217:
218: private static final String fontsDirPrefix = "$JRE_LIB_FONTS";
219:
220: protected String mapFileName(String fileName) {
221: if (fileName != null && fileName.startsWith(fontsDirPrefix)) {
222: return SunGraphicsEnvironment.jreFontDirName
223: + fileName.substring(fontsDirPrefix.length());
224: }
225: return fileName;
226: }
227:
228: // overrides FontConfiguration.getFallbackFamilyName
229: public String getFallbackFamilyName(String fontName,
230: String defaultFallback) {
231: // maintain compatibility with old font.properties files, which
232: // either had aliases for TimesRoman & Co. or defined mappings for them.
233: String compatibilityName = getCompatibilityFamilyName(fontName);
234: if (compatibilityName != null) {
235: return compatibilityName;
236: }
237: return defaultFallback;
238: }
239:
240: protected String getEncoding(String awtFontName,
241: String characterSubsetName) {
242: // extract encoding field from XLFD
243: int beginIndex = 0;
244: int fieldNum = 13; // charset registry field
245: while (fieldNum-- > 0 && beginIndex >= 0) {
246: beginIndex = awtFontName.indexOf("-", beginIndex) + 1;
247: }
248: if (beginIndex == -1) {
249: return "default";
250: }
251: String xlfdEncoding = awtFontName.substring(beginIndex);
252: if (xlfdEncoding.indexOf("fontspecific") > 0) {
253: if (awtFontName.indexOf("dingbats") > 0) {
254: return "sun.awt.motif.X11Dingbats";
255: } else if (awtFontName.indexOf("symbol") > 0) {
256: return "sun.awt.Symbol";
257: }
258: }
259: String encoding = (String) encodingMap.get(xlfdEncoding);
260: if (encoding == null) {
261: encoding = "default";
262: }
263: return encoding;
264: }
265:
266: protected Charset getDefaultFontCharset(String fontName) {
267: return Charset.forName("ISO8859_1");
268: }
269:
270: /* methods for Motif support *********************************************/
271:
272: private String[][] motifFontSets = new String[NUM_FONTS][NUM_STYLES];
273:
274: public String getMotifFontSet(String fontName, int style) {
275: assert isLogicalFontFamilyName(fontName);
276: fontName = fontName.toLowerCase(Locale.ENGLISH);
277: int fontIndex = getFontIndex(fontName);
278: int styleIndex = getStyleIndex(style);
279: return getMotifFontSet(fontIndex, styleIndex);
280: }
281:
282: private String getMotifFontSet(int fontIndex, int styleIndex) {
283: String fontSet = motifFontSets[fontIndex][styleIndex];
284: if (fontSet == null) {
285: fontSet = buildMotifFontSet(fontIndex, styleIndex);
286: motifFontSets[fontIndex][styleIndex] = fontSet;
287: }
288: return fontSet;
289: }
290:
291: private String buildMotifFontSet(int fontIndex, int styleIndex) {
292: StringBuilder buffer = new StringBuilder();
293: short[] scripts = getCoreScripts(fontIndex);
294: for (int i = 0; i < scripts.length; i++) {
295: short nameID = getComponentFontIDMotif(scripts[i],
296: fontIndex, styleIndex);
297: if (nameID == 0) {
298: nameID = getComponentFontID(scripts[i], fontIndex,
299: styleIndex);
300: }
301: String name = getComponentFontName(nameID);
302: if (name == null || name.endsWith("fontspecific")) {
303: continue;
304: }
305: if (buffer.length() > 0) {
306: buffer.append(',');
307: }
308: buffer.append(name);
309: }
310: return buffer.toString();
311: }
312:
313: protected String getFaceNameFromComponentFontName(
314: String componentFontName) {
315: return null;
316: }
317:
318: protected String getFileNameFromComponentFontName(
319: String componentFontName) {
320: // for X11, component font name is XLFD
321: // if we have a file name already, just use it; otherwise let's see
322: // what the graphics environment can provide
323: String fileName = getFileNameFromPlatformName(componentFontName);
324: if (fileName != null && fileName.charAt(0) == '/'
325: && !needToSearchForFile(fileName)) {
326: return fileName;
327: }
328: return ((X11GraphicsEnvironment) environment)
329: .getFileNameFromXLFD(componentFontName);
330: }
331:
332: /**
333: * Get default font for Motif widgets to use, preventing them from
334: * wasting time accessing inappropriate X resources. This is called
335: * only from native code.
336: *
337: * This is part of a Motif specific performance enhancement. By
338: * default, when Motif widgets are created and initialized, Motif will
339: * set up default fonts for the widgets, which we ALWAYS override.
340: * This set up includes finding the default font in the widget's X
341: * resources and fairly expensive requests of the X server to identify
342: * the specific font or fontset. We avoid all of this overhead by
343: * providing a well known font to use at the creation of widgets, where
344: * possible.
345: *
346: * The X11 fonts are specified by XLFD strings which have %d as a
347: * marker to indicate where the fontsize should be substituted. [The
348: * libc function sprintf() is used to replace it.] The value 140
349: * specifies a font size of 14 points.
350: */
351: private static String getDefaultMotifFontSet() {
352: String font = ((MFontConfiguration) getFontConfiguration())
353: .getMotifFontSet("sansserif", Font.PLAIN);
354: if (font != null) {
355: int i;
356: while ((i = font.indexOf("%d")) >= 0) {
357: font = font.substring(0, i) + "140"
358: + font.substring(i + 2);
359: }
360: }
361: return font;
362: }
363:
364: public HashSet<String> getAWTFontPathSet() {
365: HashSet<String> fontDirs = new HashSet<String>();
366: short[] scripts = getCoreScripts(0);
367: for (int i = 0; i < scripts.length; i++) {
368: String path = getString(table_awtfontpaths[scripts[i]]);
369: if (path != null) {
370: int start = 0;
371: int colon = path.indexOf(':');
372: while (colon >= 0) {
373: fontDirs.add(path.substring(start, colon));
374: start = colon + 1;
375: colon = path.indexOf(':', start);
376: }
377: fontDirs.add((start == 0) ? path : path
378: .substring(start));
379: }
380: }
381: return fontDirs;
382: }
383:
384: /* methods for table setup ***********************************************/
385:
386: private static HashMap encodingMap = new HashMap();
387:
388: private void initTables() {
389: // encodingMap maps XLFD encoding component to
390: // name of corresponding java.nio charset
391: encodingMap.put("iso8859-1", "ISO-8859-1");
392: encodingMap.put("iso8859-2", "ISO-8859-2");
393: encodingMap.put("iso8859-4", "ISO-8859-4");
394: encodingMap.put("iso8859-5", "ISO-8859-5");
395: encodingMap.put("iso8859-6", "ISO-8859-6");
396: encodingMap.put("iso8859-7", "ISO-8859-7");
397: encodingMap.put("iso8859-8", "ISO-8859-8");
398: encodingMap.put("iso8859-9", "ISO-8859-9");
399: encodingMap.put("iso8859-13", "ISO-8859-13");
400: encodingMap.put("iso8859-15", "ISO-8859-15");
401: encodingMap.put("gb2312.1980-0", "sun.awt.motif.X11GB2312");
402: if (osName == null) {
403: // use standard converter on Solaris
404: encodingMap.put("gbk-0", "GBK");
405: } else {
406: encodingMap.put("gbk-0", "sun.awt.motif.X11GBK");
407: }
408: encodingMap.put("gb18030.2000-0", "sun.awt.motif.X11GB18030_0");
409: encodingMap.put("gb18030.2000-1", "sun.awt.motif.X11GB18030_1");
410: encodingMap.put("cns11643-1", "sun.awt.motif.X11CNS11643P1");
411: encodingMap.put("cns11643-2", "sun.awt.motif.X11CNS11643P2");
412: encodingMap.put("cns11643-3", "sun.awt.motif.X11CNS11643P3");
413: encodingMap.put("big5-1", "Big5");
414: encodingMap.put("big5-0", "Big5");
415: encodingMap.put("hkscs-1", "Big5-HKSCS");
416: encodingMap.put("ansi-1251", "windows-1251");
417: encodingMap.put("koi8-r", "KOI8-R");
418: encodingMap.put("jisx0201.1976-0", "sun.awt.motif.X11JIS0201");
419: encodingMap.put("jisx0208.1983-0", "sun.awt.motif.X11JIS0208");
420: encodingMap.put("jisx0212.1990-0", "sun.awt.motif.X11JIS0212");
421: encodingMap.put("ksc5601.1987-0", "sun.awt.motif.X11KSC5601");
422: encodingMap.put("ksc5601.1992-3", "sun.awt.motif.X11Johab");
423: encodingMap.put("tis620.2533-0", "TIS-620");
424: encodingMap.put("iso10646-1", "UTF-16BE");
425: }
426:
427: }
|