001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Ilya S. Okomin
019: * @version $Revision$
020: */package org.apache.harmony.awt.gl.font;
021:
022: import java.awt.Font;
023: import java.awt.GraphicsEnvironment;
024: import java.awt.peer.FontPeer;
025: import java.io.File;
026: import java.io.FileInputStream;
027: import java.io.IOException;
028: import java.lang.ref.ReferenceQueue;
029: import java.lang.ref.SoftReference;
030: import java.util.Enumeration;
031: import java.util.Hashtable;
032: import java.util.Locale;
033: import java.util.Properties;
034: import java.util.Vector;
035:
036: import org.apache.harmony.awt.gl.CommonGraphics2DFactory;
037: import org.apache.harmony.awt.gl.font.fontlib.FLFontManager;
038:
039: public abstract class FontManager {
040:
041: static {
042: java.awt.Toolkit.getDefaultToolkit();
043: }
044:
045: public static final boolean IS_FONTLIB = "true".equals(System
046: .getProperty("java.awt.fontlib"))
047: || GraphicsEnvironment.isHeadless();
048:
049: /**
050: * array of font families names
051: */
052: public String[] allFamilies;
053:
054: public static final String DEFAULT_NAME = IS_FONTLIB ? "DejaVu Sans" : "Default"; /* Default font name *///$NON-NLS-1$
055: public static final String DIALOG_NAME = "Dialog"; /* Dialog font name *///$NON-NLS-1$
056:
057: /**
058: * Set of constants applicable to the TrueType 'name' table.
059: */
060: public static final byte FAMILY_NAME_ID = 1; /* Family name identifier */
061: public static final byte FONT_NAME_ID = 4; /* Full font name identifier */
062: public static final byte POSTSCRIPT_NAME_ID = 6; /* PostScript name identifier */
063: public static final short ENGLISH_LANGID = 0x0409; /* English (United States)language identifier */
064:
065: /**
066: * Set of constants describing font type.
067: */
068: public static final byte FONT_TYPE_TT = 4; /* TrueType type (TRUETYPE_FONTTYPE) */
069: public static final byte FONT_TYPE_T1 = 2; /* Type1 type (DEVICE_FONTTYPE) */
070: public static final byte FONT_TYPE_UNDEF = 0; /* Undefined type */
071:
072: // logical family types (indices in FontManager.LOGICAL_FONT_NAMES)
073: static final int DIALOG = 3; // FF_SWISS
074: static final int SANSSERIF = 1; // FF_SWISS
075: static final int DIALOGINPUT = 4; // FF_MODERN
076: static final int MONOSPACED = 2; // FF_MODERN
077: static final int SERIF = 0; // FF_ROMAN
078:
079: /**
080: * FontProperty related constants.
081: */
082:
083: public static final String PLATFORM_FONT_NAME = "PlatformFontName"; //$NON-NLS-1$
084: public static final String LOGICAL_FONT_NAME = "LogicalFontName"; //$NON-NLS-1$
085: public static final String COMPONENT_INDEX = "ComponentIndex"; //$NON-NLS-1$
086: public static final String STYLE_INDEX = "StyleIndex"; //$NON-NLS-1$
087:
088: public static final String[] FONT_MAPPING_KEYS = {
089: "LogicalFontName.StyleName.ComponentIndex", "LogicalFontName.ComponentIndex" //$NON-NLS-1$ //$NON-NLS-2$
090: };
091:
092: public static final String FONT_CHARACTER_ENCODING = "fontcharset.LogicalFontName.ComponentIndex"; //$NON-NLS-1$
093:
094: public static final String EXCLUSION_RANGES = "exclusion.LogicalFontName.ComponentIndex"; //$NON-NLS-1$
095:
096: public static final String FONT_FILE_NAME = "filename.PlatformFontName"; //$NON-NLS-1$
097:
098: /**
099: * Available logical font families names.
100: */
101: public static final String[] LOGICAL_FONT_FAMILIES = {
102: "Serif", "SansSerif", "Monospaced", "Dialog", "DialogInput" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
103: };
104:
105: /**
106: * Available logical font names.
107: */
108: public static final String[] LOGICAL_FONT_NAMES = {
109: "serif", "serif.plain", "serif.bold", "serif.italic", "serif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
110: "sansserif", "sansserif.plain", "sansserif.bold", "sansserif.italic", "sansserif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
111: "monospaced", "monospaced.plain", "monospaced.bold", "monospaced.italic", "monospaced.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
112: "dialog", "dialog.plain", "dialog.bold", "dialog.italic", "dialog.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
113: "dialoginput", "dialoginput.plain", "dialoginput.bold", "dialoginput.italic", "dialoginput.bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
114: };
115:
116: /**
117: * Available logical font face names.
118: */
119: public static final String[] LOGICAL_FONT_FACES = {
120: "Serif", "Serif.plain", "Serif.bold", "Serif.italic", "Serif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
121: "Sansserif", "Sansserif.plain", "Sansserif.bold", "Sansserif.italic", "Sansserif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
122: "Monospaced", "Monospaced.plain", "Monospaced.bold", "Monospaced.italic", "Monospaced.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
123: "Dialog", "Dialog.plain", "Dialog.bold", "Dialog.italic", "Dialog.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
124: "Dialoginput", "Dialoginput.plain", "Dialoginput.bold", "Dialoginput.italic", "Dialoginput.bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
125: };
126:
127: /**
128: * Set of font style names.
129: * Font.getStyle() corresponds to indexes in STYLE_NAMES array.
130: */
131: public static final String[] STYLE_NAMES = {
132: "plain", "bold", "italic", "bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
133: };
134:
135: /**
136: * Logical font styles names table where font styles names used
137: * as the key and the value is the index of this style name.
138: */
139: private static final Hashtable<String, Integer> style_keys = new Hashtable<String, Integer>(
140: 4);
141:
142: /**
143: * Initialize font styles keys table.
144: */
145: static {
146: for (int i = 0; i < STYLE_NAMES.length; i++) {
147: style_keys.put(STYLE_NAMES[i], Integer.valueOf(i));
148: }
149: }
150:
151: /**
152: * Return font style from the logical style name.
153: *
154: * @param lName style name of the logical face
155: */
156: public static int getLogicalStyle(String lName) {
157: Integer value = style_keys.get(lName);
158: return value != null ? value.intValue() : -1;
159: }
160:
161: /**
162: * Set of possible "os" property values.
163: */
164: public static final String[] OS_VALUES = {
165: "NT", "98", "2000", "Me", "XP", // For Windows //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
166: "Redhat", "Turbo", "SuSE" // For Linux //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
167: };
168:
169: /**
170: * Set of possible font.property file names.
171: * Language, Country, Encoding, OS, Version should be replaced with
172: * the values from current configuration.
173: */
174: public static final String[] FP_FILE_NAMES = {
175: "/lib/font.properties.Language_Country_Encoding.OSVersion", //$NON-NLS-1$
176: "/lib/font.properties.Language_Country_Encoding.OS", //$NON-NLS-1$
177: "/lib/font.properties.Language_Country_Encoding.Version", //$NON-NLS-1$
178: "/lib/font.properties.Language_Country_Encoding", //$NON-NLS-1$
179: "/lib/font.properties.Language_Country.OSVersion", //$NON-NLS-1$
180: "/lib/font.properties.Language_Country.OS", //$NON-NLS-1$
181: "/lib/font.properties.Language_Country.Version", //$NON-NLS-1$
182: "/lib/font.properties.Language_Country", //$NON-NLS-1$
183: "/lib/font.properties.Language_Encoding.OSVersion", //$NON-NLS-1$
184: "/lib/font.properties.Language_Encoding.OS", //$NON-NLS-1$
185: "/lib/font.properties.Language_Encoding.Version", //$NON-NLS-1$
186: "/lib/font.properties.Language_Encoding", //$NON-NLS-1$
187: "/lib/font.properties.Language.OSVersion", //$NON-NLS-1$
188: "/lib/font.properties.Language.OS", //$NON-NLS-1$
189: "/lib/font.properties.Language.Version", //$NON-NLS-1$
190: "/lib/font.properties.Language", //$NON-NLS-1$
191: "/lib/font.properties.Encoding.OSVersion", //$NON-NLS-1$
192: "/lib/font.properties.Encoding.OS", //$NON-NLS-1$
193: "/lib/font.properties.Encoding.Version", //$NON-NLS-1$
194: "/lib/font.properties.Encoding", //$NON-NLS-1$
195: "/lib/font.properties.OSVersion", //$NON-NLS-1$
196: "/lib/font.properties.OS", //$NON-NLS-1$
197: "/lib/font.properties.Version", //$NON-NLS-1$
198: "/lib/font.properties" //$NON-NLS-1$
199: };
200:
201: /**
202: * Table with all available font properties corresponding
203: * to the current system configuration.
204: */
205: public Hashtable<String, Vector<FontProperty>> fProperties = new Hashtable<String, Vector<FontProperty>>();
206:
207: public FontManager() {
208:
209: if (!IS_FONTLIB) {
210: allFamilies = getAllFamilies();
211: /*
212: * Creating and registering shutdown hook to free resources
213: * before object is destroyed.
214: */
215: DisposeNativeHook shutdownHook = new DisposeNativeHook();
216: Runtime.getRuntime().addShutdownHook(shutdownHook);
217: }
218: }
219:
220: /**
221: * Maximum number of unreferenced font peers to keep.
222: */
223: public static final int EMPTY_FONTS_CAPACITY = 10;
224:
225: /**
226: * Locale - Language ID hash table.
227: */
228: protected Hashtable<String, Short> tableLCID = new Hashtable<String, Short>();
229:
230: /**
231: * Hash table that contains FontPeers instances.
232: */
233:
234: public Hashtable<String, HashMapReference> fontsTable = new Hashtable<String, HashMapReference>();
235:
236: /**
237: * ReferenceQueue for HashMapReference objects to check
238: * if they were collected by garbage collector.
239: */
240: public ReferenceQueue<FontPeer> queue = new ReferenceQueue<FontPeer>();
241:
242: /**
243: * Singleton instance
244: */
245: private static FontManager inst = IS_FONTLIB ? new FLFontManager()
246: : CommonGraphics2DFactory.inst.getFontManager();
247:
248: /**
249: * Gets singleton instance of FontManager
250: *
251: * @return instance of FontManager implementation
252: */
253: public static FontManager getInstance() {
254: return inst;
255: }
256:
257: /**
258: * Returns platform-dependent Font peer created from the specified
259: * Font object from the table with cached FontPeers instances.
260: *
261: * Note, this method checks whether FontPeer with specified parameters
262: * exists in the table with cached FontPeers' instances. If there is no needed
263: * instance - it is created and cached.
264: *
265: * @param fontName name of the font
266: * @param _fontStyle style of the font
267: * @param size font size
268: *
269: * @return platform dependent FontPeer implementation created from
270: * the specified parameters
271: */
272: public FontPeer getFontPeer(String fontName, int _fontStyle,
273: int size) {
274:
275: updateFontsTable();
276:
277: FontPeer peer = null;
278: String key;
279: String name;
280: int fontStyle = _fontStyle;
281:
282: int logicalIndex = getLogicalFaceIndex(fontName);
283:
284: if (logicalIndex != -1) {
285: name = getLogicalFaceFromFont(fontStyle, logicalIndex);
286: fontStyle = getStyleFromLogicalFace(name);
287: key = name.concat(String.valueOf(size));
288: } else {
289: name = fontName;
290: key = name.concat(String.valueOf(fontStyle)).concat(
291: String.valueOf(size));
292: }
293:
294: HashMapReference hmr = fontsTable.get(key);
295: if (hmr != null) {
296: peer = hmr.get();
297: }
298:
299: if (peer == null) {
300: peer = createFontPeer(name, fontStyle, size, logicalIndex);
301: if (peer == null) {
302: peer = getFontPeer(DIALOG_NAME, fontStyle, size);
303: }
304: fontsTable.put(key, new HashMapReference(key, peer, queue));
305: }
306:
307: return peer;
308: }
309:
310: /**
311: * Returns instance of font peer (logical or physical) according to the
312: * specified parameters.
313: *
314: * @param name font face name
315: * @param style style of the font
316: * @param size size of the font
317: * @param logicalIndex index of the logical face name in LOGICAL_FONT_FACES
318: * array or -1 if desired font peer is not logical.
319: */
320: protected FontPeer createFontPeer(String name, int style, int size,
321: int logicalIndex) {
322: FontPeer peer;
323: if (logicalIndex != -1) {
324: peer = createLogicalFontPeer(name, style, size);
325: } else {
326: peer = createPhysicalFontPeer(name, style, size);
327: }
328:
329: return peer;
330: }
331:
332: /**
333: * Returns family name for logical face names as a parameter.
334: *
335: * @param faceName logical font face name
336: */
337: public String getFamilyFromLogicalFace(String faceName) {
338: int pos = faceName.indexOf("."); //$NON-NLS-1$
339: if (pos == -1) {
340: return faceName;
341: }
342:
343: return faceName.substring(0, pos);
344: }
345:
346: /**
347: * Returns new logical font peer for the parameters specified using font
348: * properties.
349: *
350: * @param faceName face name of the logical font
351: * @param style style of the font
352: * @param size font size
353: *
354: */
355: private FontPeer createLogicalFontPeer(String faceName, int style,
356: int size) {
357: String family = getFamilyFromLogicalFace(faceName);
358: FontProperty[] fps = getFontProperties(family.toLowerCase()
359: + "." + style); //$NON-NLS-1$
360: if (fps != null) {
361: int numFonts = fps.length;
362: FontPeerImpl[] physicalFonts = new FontPeerImpl[numFonts];
363: for (int i = 0; i < numFonts; i++) {
364: FontProperty fp = fps[i];
365:
366: String name = fp.getName();
367: int fpStyle = fp.getStyle();
368: String key = name.concat(String.valueOf(fpStyle))
369: .concat(String.valueOf(size));
370:
371: HashMapReference hmr = fontsTable.get(key);
372: if (hmr != null) {
373: physicalFonts[i] = (FontPeerImpl) hmr.get();
374: }
375:
376: if (physicalFonts[i] == null) {
377: physicalFonts[i] = (FontPeerImpl) createPhysicalFontPeer(
378: name, fpStyle, size);
379: fontsTable.put(key, new HashMapReference(key,
380: physicalFonts[i], queue));
381: }
382:
383: if (physicalFonts[i] == null) {
384: physicalFonts[i] = (FontPeerImpl) getDefaultFont(
385: style, size);
386: }
387: }
388: return new CompositeFont(family, faceName, style, size,
389: fps, physicalFonts);
390: }
391:
392: // if there is no property for this logical font - default font is to be
393: // created
394: FontPeerImpl peer = (FontPeerImpl) getDefaultFont(style, size);
395:
396: return peer;
397: }
398:
399: /**
400: * Returns new physical font peer for the parameters specified using font properties
401: * This method must be overridden by subclasses implementations.
402: *
403: * @param faceName face name or family name of the font
404: * @param style style of the font
405: * @param size font size
406: *
407: */
408: public abstract FontPeer createPhysicalFontPeer(String name,
409: int style, int size);
410:
411: /**
412: * Returns default font peer class with "Default" name that is usually
413: * used when font with specified font names and style doesn't exsist
414: * on a system.
415: *
416: * @param style style of the font
417: * @param size size of the font
418: */
419: public FontPeer getDefaultFont(int style, int size) {
420: updateFontsTable();
421:
422: FontPeer peer = null;
423: String key = DEFAULT_NAME.concat(String.valueOf(style)).concat(
424: String.valueOf(size));
425:
426: HashMapReference hmr = fontsTable.get(key);
427: if (hmr != null) {
428: peer = hmr.get();
429: }
430:
431: if (peer == null) {
432: peer = createDefaultFont(style, size);
433:
434: ((FontPeerImpl) peer).setFamily(DEFAULT_NAME);
435: ((FontPeerImpl) peer).setPSName(DEFAULT_NAME);
436: ((FontPeerImpl) peer).setFontName(DEFAULT_NAME);
437:
438: fontsTable.put(key, new HashMapReference(key, peer, queue));
439: }
440:
441: return peer;
442: }
443:
444: /**
445: *
446: * Returns new default font peer with "Default" name for the parameters
447: * specified. This method must be overridden by subclasses implementations.
448: *
449: * @param style style of the font
450: * @param size size of the font
451: */
452: public abstract FontPeer createDefaultFont(int style, int size);
453:
454: /**
455: * Returns face name of the logical font, which is the result
456: * of specified font style and face style union.
457: *
458: * @param fontStyle specified style of the font
459: * @param logicalIndex index of the specified face from the
460: * LOGICAL_FONT_FACES array
461: * @return resulting face name
462: */
463: public String getLogicalFaceFromFont(int fontStyle, int logicalIndex) {
464: int style = 0;
465: String name = LOGICAL_FONT_FACES[logicalIndex];
466: int pos = name.indexOf("."); //$NON-NLS-1$
467:
468: if (pos == -1) {
469: return createLogicalFace(name, fontStyle);
470: }
471:
472: String styleName = name.substring(pos + 1);
473: name = name.substring(0, pos);
474:
475: // appending font style to the face style
476: style = fontStyle | getLogicalStyle(styleName);
477:
478: return createLogicalFace(name, style);
479: }
480:
481: /**
482: * Function returns style value from logical face name.
483: *
484: * @param name face name
485: * @return font style
486: */
487: public int getStyleFromLogicalFace(String name) {
488: int style;
489: int pos = name.indexOf("."); //$NON-NLS-1$
490:
491: if (pos == -1) {
492: return Font.PLAIN;
493: }
494:
495: String styleName = name.substring(pos + 1);
496:
497: style = getLogicalStyle(styleName);
498:
499: return style;
500: }
501:
502: /**
503: * Returns logical face name corresponding to the logical
504: * family name and style of the font.
505: *
506: * @param family font family
507: * @param styleIndex index of the style name from the STYLE_NAMES array
508: */
509: public String createLogicalFace(String family, int styleIndex) {
510: return family + "." + STYLE_NAMES[styleIndex]; //$NON-NLS-1$
511: }
512:
513: /**
514: * Return language Id from LCID hash corresponding to the specified locale
515: *
516: * @param l specified locale
517: */
518: public Short getLCID(Locale l) {
519: if (this .tableLCID.size() == 0) {
520: initLCIDTable();
521: }
522:
523: return tableLCID.get(l.toString());
524: }
525:
526: /**
527: * Platform-dependent LCID table init.
528: */
529: public abstract void initLCIDTable();
530:
531: /**
532: * Freeing native resources. This hook is used to avoid
533: * sudden application exit and to free resources created in native code.
534: */
535: private class DisposeNativeHook extends Thread {
536:
537: @Override
538: public void run() {
539: try {
540: /* Disposing native font peer's resources */
541: Enumeration<String> kEnum = fontsTable.keys();
542:
543: while (kEnum.hasMoreElements()) {
544: Object key = kEnum.nextElement();
545: HashMapReference hmr = fontsTable.remove(key);
546: FontPeerImpl delPeer = (FontPeerImpl) hmr.get();
547:
548: if ((delPeer != null)
549: && (delPeer.getClass() != CompositeFont.class)) {
550: // there's nothing to dispose in CompositeFont objects
551: delPeer.dispose();
552: }
553: }
554: } catch (Throwable t) {
555: throw new RuntimeException(t);
556: }
557: }
558: }
559:
560: /**
561: * Returns File object, created in a directory
562: * according to the System, where JVM is being ran.
563: *
564: * In Linux case we use ".fonts" directory (for fontconfig purpose),
565: * where font file from the stream will be stored, hence in LinuxFontManager this
566: * method is overridden.
567: * In Windows case we use Windows temp directory (default implementation)
568: *
569: */
570: public File getTempFontFile() throws IOException {
571:
572: File fontFile = File.createTempFile("jFont", ".ttf"); //$NON-NLS-1$ //$NON-NLS-2$
573: fontFile.deleteOnExit();
574:
575: return fontFile;
576: }
577:
578: /**
579: * Returns File object with font properties. It's name obtained using current
580: * system configuration properties and locale settings. If no appropriate
581: * file is found method returns null.
582: */
583: public static File getFontPropertyFile() {
584: File file = null;
585:
586: String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
587: Locale l = Locale.getDefault();
588: String language = l.getLanguage();
589: String country = l.getCountry();
590: String fileEncoding = System.getProperty("file.encoding"); //$NON-NLS-1$
591:
592: String os = System.getProperty("os.name"); //$NON-NLS-1$
593:
594: int i = 0;
595:
596: // OS names from system properties don't match
597: // OS identifiers used in font.property files
598: for (; i < OS_VALUES.length; i++) {
599: if (os.endsWith(OS_VALUES[i])) {
600: os = OS_VALUES[i];
601: break;
602: }
603: }
604:
605: if (i == OS_VALUES.length) {
606: os = null;
607: }
608:
609: String version = System.getProperty("os.version"); //$NON-NLS-1$
610: String pathname;
611:
612: for (i = 0; i < FP_FILE_NAMES.length; i++) {
613: pathname = FP_FILE_NAMES[i];
614: if (os != null) {
615: pathname = pathname.replaceFirst("OS", os); //$NON-NLS-1$
616: }
617:
618: pathname = javaHome + pathname;
619:
620: // pathname = pathname.replaceAll("Language", language). //$NON-NLS-1$
621: // replaceAll("Country", country). //$NON-NLS-1$
622: // replaceAll("Encoding", fileEncoding). //$NON-NLS-1$
623: // replaceAll("Version", version); //$NON-NLS-1$
624: int curPos;
625: StringBuilder result = new StringBuilder(pathname);
626:
627: curPos = result.indexOf("Language"); //$NON-NLS-1$
628: if (curPos >= 0) {
629: result.replace(curPos, curPos + 8, language);
630: }
631: curPos = result.indexOf("Country"); //$NON-NLS-1$
632: if (curPos >= 0) {
633: result.replace(curPos, curPos + 7, country);
634: }
635: curPos = result.indexOf("Encoding"); //$NON-NLS-1$
636: if (curPos >= 0) {
637: result.replace(curPos, curPos + 8, fileEncoding);
638: }
639: curPos = result.indexOf("Version"); //$NON-NLS-1$
640: if (curPos >= 0) {
641: result.replace(curPos, curPos + 7, version);
642: }
643: pathname = result.toString();
644:
645: file = new File(pathname);
646:
647: if (file.exists()) {
648: break;
649: }
650: }
651:
652: return file.exists() ? file : null;
653: }
654:
655: /**
656: * Returns an array of integer range values
657: * if the parameter exclusionString has format:
658: * Range
659: * Range [, exclusionString]
660: *
661: * Range:
662: * Char-Char
663: *
664: * Char:
665: * HexDigit HexDigit HexDigit HexDigit
666: *
667: * Method returns null if the specified string is null.
668: *
669: * @param exclusionString string parameter in specified format
670: */
671: public static int[] parseIntervals(String exclusionString) {
672: int[] results = null;
673:
674: if (exclusionString == null) {
675: return null;
676: }
677:
678: String[] intervals = exclusionString.split(","); //$NON-NLS-1$
679:
680: if (intervals != null) {
681: int num = intervals.length;
682: if (num > 0) {
683: results = new int[intervals.length << 1];
684: for (int i = 0; i < intervals.length; i++) {
685: String ranges[] = intervals[i].split("-"); //$NON-NLS-1$
686: results[i * 2] = Integer.parseInt(ranges[0], 16);
687: results[i * 2 + 1] = Integer
688: .parseInt(ranges[1], 16);
689:
690: }
691: }
692: }
693: return results;
694: }
695:
696: /**
697: * Returns Properties from the properties file or null if
698: * there is an error with FileInputStream processing.
699: *
700: * @param file File object containing properties
701: */
702: public static Properties getProperties(File file) {
703: Properties props = null;
704: FileInputStream fis = null;
705: try {
706: fis = new FileInputStream(file);
707: props = new Properties();
708: props.load(fis);
709: } catch (Exception e) {
710: System.out.println(e);
711: }
712: return props;
713: }
714:
715: /**
716: * Returns an array of FontProperties from the properties file
717: * with the specified property name "logical face.style". E.g.
718: * "dialog.2" corresponds to the font family Dialog with bold style.
719: *
720: * @param fpName key of the font properties in the properties set
721: */
722: public FontProperty[] getFontProperties(String fpName) {
723: Vector<FontProperty> props = fProperties.get(fpName);
724:
725: if (props == null) {
726: return null;
727: }
728:
729: int size = props.size();
730:
731: if (size == 0) {
732: return null;
733: }
734:
735: FontProperty[] fps = new FontProperty[size];
736: for (int i = 0; i < fps.length; i++) {
737: fps[i] = props.elementAt(i);
738: }
739: return fps;
740: }
741:
742: /**
743: * Returns index of the font name in array of font names or -1 if
744: * this font is not logical.
745: *
746: * @param fontName specified font name
747: */
748: public static int getLogicalFaceIndex(String fontName) {
749: for (int i = 0; i < LOGICAL_FONT_NAMES.length; i++) {
750: if (LOGICAL_FONT_NAMES[i].equalsIgnoreCase(fontName)) {
751: return i;
752: }
753: }
754: return -1;
755: }
756:
757: /**
758: * Returns true if specified family name is available in this
759: * GraphicsEnvironment.
760: *
761: * @param familyName the specified font family name
762: */
763: public boolean isFamilyExist(String familyName) {
764: return (getFamilyIndex(familyName) != -1);
765: }
766:
767: /**
768: * Returns index of family name from the array of family names available in
769: * this GraphicsEnvironment or -1 if no family name was found.
770: *
771: * @param familyName specified font family name
772: */
773: public int getFamilyIndex(String familyName) {
774: for (int i = 0; i < allFamilies.length; i++) {
775: if (familyName.equalsIgnoreCase(allFamilies[i])) {
776: return i;
777: }
778: }
779: return -1;
780: }
781:
782: /**
783: * Returns family with index specified from the array of family names available in
784: * this GraphicsEnvironment.
785: *
786: * @param index index of the family in families names array
787: */
788: public String getFamily(int index) {
789: return allFamilies[index];
790: }
791:
792: /**
793: * Returns index of face name from the array of face names available in
794: * this GraphicsEnvironment or -1 if no face name was found. Default return
795: * value is -1, method must be overridden by FontManager implementation.
796: *
797: * @param faceName font face name which index is to be searched
798: */
799: public int getFaceIndex(String faceName) {
800: return -1;
801: }
802:
803: public abstract String[] getAllFamilies();
804:
805: public abstract Font[] getAllFonts();
806:
807: /**
808: * Class contains SoftReference instance that can be stored in the
809: * Hashtable by means of key field corresponding to it.
810: */
811: protected class HashMapReference extends SoftReference<FontPeer> {
812:
813: /**
814: * The key for Hashtable.
815: */
816: private final String key;
817:
818: /**
819: * Creates a new soft reference with the key specified and
820: * adding this reference in the reference queue specified.
821: *
822: * @param key the key in Hashtable
823: * @param value object that corresponds to the key
824: * @param queue reference queue where reference is to be added
825: */
826: public HashMapReference(final String key, final FontPeer value,
827: final ReferenceQueue<FontPeer> queue) {
828: super (value, queue);
829: this .key = key;
830: }
831:
832: /**
833: * Returns the key that corresponds to the SoftReference instance
834: *
835: * @return the key in Hashtable with cached references
836: */
837: public Object getKey() {
838: return key;
839: }
840: }
841:
842: /**
843: * Removes keys from the Hashtable with font peers which corresponding
844: * HashMapReference objects were garbage collected.
845: */
846: private void updateFontsTable() {
847: HashMapReference r;
848: while ((r = (HashMapReference) queue.poll()) != null) {
849: fontsTable.remove(r.getKey());
850: }
851: }
852:
853: }
|