001: /*
002: * @(#)QtFontPeer.java 1.24 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027: /**
028: * QtFontPeer.java
029: *
030: */package sun.awt.qt;
031:
032: import sun.awt.peer.FontPeer;
033: import java.awt.Font;
034: import java.awt.FontMetrics;
035: import sun.io.CharacterEncoding;
036: import java.io.InputStream;
037: import java.io.BufferedInputStream;
038: import sun.io.FileIO;
039: import sun.io.FileIOFactory;
040: import java.util.*;
041: import java.awt.Color;
042: import java.awt.font.TextAttribute;
043:
044: /** The peer used for fonts in Qt. This class extends the FontMetrics
045: class so that it is very quick to get the font metrics for a font
046: and we don't need to create a new object each time. We also maintain a cache
047: which allows multiple font objects to share the same peer if they are of the
048: same name, style and size. This reduces further the number of objects created. */
049:
050: class QtFontPeer extends FontMetrics implements FontPeer {
051: private static int generatedFontCount = 0;
052:
053: /*
054: * Added for 1.1 attribute support
055: */
056: private boolean strikethrough;
057: private boolean underline;
058:
059: private QtFontPeer(Font font, boolean strikethrough,
060: boolean underline) {
061: super (font);
062: this .strikethrough = strikethrough;
063: this .underline = underline;
064: init(font.getFamily(), font.isItalic(), font.isBold(), font
065: .getSize());
066: }
067:
068: private QtFontPeer(int qtfont) {
069: super (null);
070: data = qtfont;
071: }
072:
073: /** Gets the FontPeer for the specified Font. This will look in a
074: cache first to prevent loading of the font for a second time. */
075:
076: synchronized static QtFontPeer getFontPeer(Font font) {
077: QtFontPeer peer = null;
078: String fontKey = font.getName() + font.getSize()
079: + font.getStyle();
080: Map attributes = font.getAttributes();
081: Object obj;
082: boolean strikeThrough = false, underline = false;
083: if ((obj = attributes.get(TextAttribute.STRIKETHROUGH)) != null) {
084: if (obj.equals(TextAttribute.STRIKETHROUGH_ON)) {
085: fontKey += "strike";
086: strikeThrough = true;
087: }
088: }
089:
090: if ((obj = attributes.get(TextAttribute.UNDERLINE)) != null) {
091: if (obj.equals(TextAttribute.UNDERLINE_ON)) {
092: fontKey += "under";
093: underline = true;
094: }
095: }
096:
097: peer = (QtFontPeer) fontToPeerMap.get(fontKey);
098:
099: if (peer == null) {
100: peer = new QtFontPeer(font, strikeThrough, underline);
101: fontToPeerMap.put(fontKey, peer);
102: }
103:
104: return peer;
105: }
106:
107: /** Gets the font for the specified QtFont. This is used when installing fonts on
108: the Java components when a widget is created. We check what font the native widget uses and,
109: if one has not been explicitly set for the Java component, we set the font on the component.
110: This will examine all loaded fonts in the cache and see if there is one for qtfont.
111: If not it will create a new font object with a unique name. */
112:
113: private synchronized static Font getFont(int qtfont) {
114: Iterator i = fontToPeerMap.entrySet().iterator();
115:
116: while (i.hasNext()) {
117: Map.Entry entry = (Map.Entry) i.next();
118: QtFontPeer peer = (QtFontPeer) entry.getValue();
119:
120: if (areFontsTheSame(qtfont, peer.data)) {
121: // fontToPeerMap has multi-type keys which is either a String
122: // (See getFontPeer(Font) or a Font (See getFont(int)), so
123: // instead of performing a dynamic cast on "entry.getKey()",
124: // we simply return the Font contained in the peer
125: return peer.getFont();
126: }
127: }
128:
129: // We need to generate a new font for the QtFont.
130:
131: QtFontPeer peer = new QtFontPeer(qtfont);
132: Font font = createFont(
133: "GeneratedFont" + (++generatedFontCount), peer);
134: // use a string as a key here to be consistent with getFontPeer
135: // but, here we don't need to worry about strikethrough and underline
136: // because we won't create a native widget with a font that has those
137: // attributes
138: String fontKey = font.getName() + font.getSize()
139: + font.getStyle();
140:
141: fontToPeerMap.put(fontKey, peer);
142:
143: return font;
144: }
145:
146: /** Tests whether two qtfonts are the same. */
147:
148: private static native boolean areFontsTheSame(int font1, int font2);
149:
150: /** Creates a font with the specified name and qtfont. */
151: private static native Font createFont(String name, QtFontPeer peer);
152:
153: /**
154: * 6228133
155: * Deletes the native font.
156: */
157: private static native void deleteFonts(int len, int[] qtfonts);
158:
159: /** Loads the font and sets the ascent and descent fields. */
160:
161: private native void init(String family, boolean italic,
162: boolean bold, int size);
163:
164: /**
165: * Determines the <em>font ascent</em> of the font described by this
166: * font metric. The font ascent is the distance from the font's
167: * baseline to the top of most alphanumeric characters. Some
168: * characters in the font may extend above the font ascent line.
169: * @return the font ascent of the font.
170: * @see java.awt.FontMetrics#getMaxAscent
171: * @since JDK1.0
172: */
173: public int getAscent() {
174: return ascent;
175: }
176:
177: /**
178: * Determines the <em>font descent</em> of the font described by this
179: * font metric. The font descent is the distance from the font's
180: * baseline to the bottom of most alphanumeric characters with
181: * descenders. Some characters in the font may extend below the font
182: * descent line.
183: * @return the font descent of the font.
184: * @see java.awt.FontMetrics#getMaxDescent
185: * @since JDK1.0
186: */
187: public int getDescent() {
188: return descent;
189: }
190:
191: /**
192: * Determines the <em>standard leading</em> of the font described by
193: * this font metric. The standard leading (interline spacing) is the
194: * logical amount of space to be reserved between the descent of one
195: * line of text and the ascent of the next line. The height metric is
196: * calculated to include this extra space.
197: * @return the standard leading of the font.
198: * @see java.awt.FontMetrics#getHeight
199: * @see java.awt.FontMetrics#getAscent
200: * @see java.awt.FontMetrics#getDescent
201: * @since JDK1.0
202: */
203: public int getLeading() {
204: return leading;
205: }
206:
207: /**
208: * Gets the maximum advance width of any character in this Font.
209: * The advance width is the amount by which the current point is
210: * moved from one character to the next in a line of text.
211: * @return the maximum advance width of any character
212: * in the font, or <code>-1</code> if the
213: * maximum advance width is not known.
214: * @since JDK1.0
215: */
216: public int getMaxAdvance() {
217: return -1;
218: }
219:
220: /**
221: * Returns the advance width of the specified character in this Font.
222: * The advance width is the amount by which the current point is
223: * moved from one character to the next in a line of text.
224: * @param ch the character to be measured
225: * @return the advance width of the specified <code>char</code>
226: * in the font described by this font metric.
227: * @see java.awt.FontMetrics#charsWidth
228: * @see java.awt.FontMetrics#stringWidth
229: * @since JDK1.0
230: */
231: public int charWidth(char ch) {
232: // Optimization for ASCII characters. Prevents creating a string and using all the
233: // char to byte converters to get the bytes.
234:
235: if (ch < 128)
236: return asciiCharWidth(ch);
237:
238: String string = new String(new char[] { ch });
239:
240: return stringWidthNative(string);
241: }
242:
243: private native int asciiCharWidth(char c);
244:
245: /**
246: * Returns the total advance width for showing the specified String
247: * in this Font.
248: * The advance width is the amount by which the current point is
249: * moved from one character to the next in a line of text.
250: * @param str the String to be measured
251: * @return the advance width of the specified string
252: * in the font described by this font metric.
253: * @see java.awt.FontMetrics#bytesWidth
254: * @see java.awt.FontMetrics#charsWidth
255: * @since JDK1.0
256: */
257: public int stringWidth(String str) {
258: // 6261520
259: // throwing NPE to be complaint with J2SE impl, eventhough the spec
260: // does not enforce it.
261: if (str == null) {
262: throw new NullPointerException("str is null");
263: }
264: // 6261520
265: return stringWidthNative(str);
266: }
267:
268: protected native int stringWidthNative(String str);
269:
270: private static native void initIDs();
271:
272: /* The font propertiues used to map from font names to fonset names. */
273:
274: private static Properties defaultProperties;
275:
276: /*
277: * Try to load font properties from default locations.
278: * If font properties cannot be loaded (possibly because there is no file
279: * system present), use a set of en_US properties by default.
280: */
281: static {
282: initIDs();
283: defaultProperties = new Properties();
284:
285: java.security.AccessController
286: .doPrivileged(new java.security.PrivilegedAction() {
287: public Object run() {
288: String jhome = System.getProperty("java.home");
289: String uhome = System.getProperty("user.home");
290:
291: if (jhome == null) {
292: throw new Error(
293: "java.home property not set");
294: }
295:
296: String language = System.getProperty(
297: "user.language", "en");
298: String region = System
299: .getProperty("user.region");
300:
301: // Translate the raw encoding name returned by the VM to the canonical
302: // name from the alias table in CharacterEncoding. Map unlisted raw
303: // encoding names to themselves. - bug 4163038
304:
305: String rawEncoding = System
306: .getProperty("file.encoding");
307: String encoding = CharacterEncoding
308: .aliasName(rawEncoding);
309:
310: if (encoding == null)
311: encoding = rawEncoding;
312:
313: try {
314: FileIO f = null;
315:
316: if (region != null) {
317: f = tryOpeningFontProp(f, uhome,
318: language, region + "_"
319: + encoding);
320: f = tryOpeningFontProp(f, jhome,
321: language, region + "_"
322: + encoding);
323: f = tryOpeningFontProp(f, uhome,
324: language, region);
325: f = tryOpeningFontProp(f, jhome,
326: language, region);
327: }
328:
329: f = tryOpeningFontProp(f, uhome, language,
330: encoding);
331: f = tryOpeningFontProp(f, jhome, language,
332: encoding);
333: f = tryOpeningFontProp(f, uhome, language,
334: null);
335: f = tryOpeningFontProp(f, jhome, language,
336: null);
337: f = tryOpeningFontProp(f, uhome, encoding,
338: null);
339: f = tryOpeningFontProp(f, jhome, encoding,
340: null);
341: f = tryOpeningFontProp(f, uhome, null, null);
342: f = tryOpeningFontProp(f, jhome, null, null);
343:
344: // Load property file
345: InputStream in = new BufferedInputStream(f
346: .getInputStream());
347: defaultProperties.load(in);
348: in.close();
349: }
350:
351: // If anything goes wrong then resort to default properties.
352:
353: catch (Exception e) {
354: setDefaultProperty("serif.0",
355: "adobe-times-normal-r---*-%d-*");
356: setDefaultProperty("serif.1",
357: "-urw-itc zapfdingbats-medium-r-normal--*-%d-*");
358: setDefaultProperty("serif.2",
359: "*-symbol-medium-r-normal--*-%d-*");
360: setDefaultProperty("serif.italic.0",
361: "-adobe-times-normal-i---*-%d-*");
362: setDefaultProperty("serif.bold.0",
363: "-adobe-times-bold-r---*-%d-*");
364: setDefaultProperty("serif.bolditalic.0",
365: "-adobe-times-bold-i---*-%d-*");
366: setDefaultProperty("sansserif.0",
367: "-adobe-helvetica-normal-r-normal--*-%d-*");
368: setDefaultProperty("sansserif.1",
369: "-urw-itc zapfdingbats-medium-r-normal--*-%d-*");
370: setDefaultProperty("sansserif.2",
371: "-*-symbol-medium-r-normal--*-%d-*");
372: setDefaultProperty("sansserif.italic.0",
373: "-adobe-helvetica-normal-i-normal--*-%d-*");
374: setDefaultProperty("sansserif.bold.0",
375: "-adobe-helvetica-bold-r-normal--*-%d-*");
376: setDefaultProperty(
377: "sansserif.bolditalic.0",
378: "-adobe-helvetica-bold-i-normal--*-%d-*");
379: setDefaultProperty("monospaced.0",
380: "-adobe-courier-normal-r---*-%d-*");
381: setDefaultProperty("monospaced.1",
382: "-urw-itc zapfdingbats-medium-r-normal--*-%d-*");
383: setDefaultProperty("monospaced.2",
384: "-*-symbol-medium-r-normal--*-%d-*");
385: setDefaultProperty("monospaced.italic.0",
386: "-adobe-courier-normal-i---*-%d-*");
387: setDefaultProperty("monospaced.bold.0",
388: "-adobe-courier-bold-r---*-%d-*");
389: setDefaultProperty(
390: "monospaced.bolditalic.0",
391: "-adobe-courier-bold-i---*-%d-*");
392: setDefaultProperty("dialog.0",
393: "-adobe-helvetica-normal-r-normal--*-%d-*");
394: setDefaultProperty("dialog.1",
395: "-urw-itc zapfdingbats-medium-r-normal--*-%d-*");
396: setDefaultProperty("dialog.2",
397: "-*-symbol-medium-r-normal--*-%d-*");
398: setDefaultProperty("dialog.italic.0",
399: "-adobe-helvetica-normal-i-normal--*-%d-*");
400: setDefaultProperty("dialog.bold.0",
401: "-adobe-helvetica-bold-r-normal--*-%d-*");
402: setDefaultProperty("dialog.bolditalic.0",
403: "-adobe-helvetica-bold-i-normal--*-%d-*");
404: setDefaultProperty("dialoginput.0",
405: "-adobe-courier-normal-r---*-%d-*");
406: setDefaultProperty("dialoginput.1",
407: "-urw-itc zapfdingbats-medium-r-normal--*-%d-*");
408: setDefaultProperty("dialoginput.2",
409: "-*-symbol-medium-r-normal--*-%d-*");
410: setDefaultProperty("dialoginput.italic.0",
411: "-adobe-courier-normal-i---*-%d-*");
412: setDefaultProperty("dialoginput.bold.0",
413: "-adobe-courier-bold-r---*-%d-*");
414: setDefaultProperty(
415: "dialoginput.bolditalic.0",
416: "-adobe-courier-bold-i---*-%d-*");
417: setDefaultProperty("default.char", "274f");
418: setDefaultProperty("timesroman.0",
419: "-adobe-times-normal-r---*-%d-*");
420: setDefaultProperty("timesroman.italic.0",
421: "-adobe-times-normal-i---*-%d-*");
422: setDefaultProperty("timesroman.bold.0",
423: "-adobe-times-bold-r---*-%d-*");
424: setDefaultProperty(
425: "timesroman.bolditalic.0",
426: "-adobe-times-bold-i---*-%d-*");
427: setDefaultProperty("helvetica.0",
428: "-adobe-helvetica-normal-r-normal--*-%d-*");
429: setDefaultProperty("helvetica.italic.0",
430: "-adobe-helvetica-normal-i-normal--*-%d-*");
431: setDefaultProperty("helvetica.bold.0",
432: "-adobe-helvetica-bold-r-normal--*-%d-*");
433: setDefaultProperty(
434: "helvetica.bolditalic.0",
435: "-adobe-helvetica-bold-i-normal--*-%d-*");
436: setDefaultProperty("courier.0",
437: "-adobe-courier-normal-r---*-%d-*");
438: setDefaultProperty("courier.italic.0",
439: "-adobe-courier-normal-i---*-%d-*");
440: setDefaultProperty("courier.bold.0",
441: "-adobe-courier-bold-r---*-%d-*");
442: setDefaultProperty("courier.bolditalic.0",
443: "-adobe-courier-bold-i---*-%d-*");
444: setDefaultProperty("zapfdingbats.0",
445: "-urw-itc zapfdingbats-medium-r-normal--*-%d-*");
446:
447: setDefaultProperty("fontset.serif.plain",
448: "-adobe-times-normal-r-*--*-%d-*");
449: setDefaultProperty("fontset.serif.italic",
450: "-adobe-times-normal-i-*--*-%d-*");
451: setDefaultProperty("fontset.serif.bold",
452: "-adobe-times-bold-r-*--*-%d-*");
453: setDefaultProperty(
454: "fontset.serif.bolditalic",
455: "-adobe-times-bold-i-*--*-%d-*");
456: setDefaultProperty(
457: "fontset.sansserif.plain",
458: "-adobe-helvetica-medium-r-normal--*-%d-*");
459: setDefaultProperty(
460: "fontset.sansserif.italic",
461: "-adobe-helvetica-medium-i-normal--*-%d-*");
462: setDefaultProperty(
463: "fontset.sansserif.bold",
464: "-adobe-helvetica-bold-r-normal--*-%d-*");
465: setDefaultProperty(
466: "fontset.sansserif.bolditalic",
467: "-adobe-helvetica-bold-i-normal--*-%d-*");
468: setDefaultProperty(
469: "fontset.monospaced.plain",
470: "-adobe-courier-medium-r-*--*-%d-*");
471: setDefaultProperty(
472: "fontset.monospaced.italic",
473: "-adobe-courier-medium-i-*--*-%d-*");
474: setDefaultProperty(
475: "fontset.monospaced.bold",
476: "-adobe-courier-bold-r-*--*-%d-*");
477: setDefaultProperty(
478: "fontset.monospaced.bolditalic",
479: "-adobe-courier-bold-i-*--*-%d-*");
480: setDefaultProperty("fontset.dialog.plain",
481: "-adobe-helvetica-medium-r-normal--*-%d-*");
482: setDefaultProperty("fontset.dialog.italic",
483: "-adobe-helvetica-medium-i-normal--*-%d-*");
484: setDefaultProperty("fontset.dialog.bold",
485: "-adobe-helvetica-bold-r-normal--*-%d-*");
486: setDefaultProperty(
487: "fontset.dialog.bolditalic",
488: "-adobe-helvetica-bold-i-normal--*-%d-*");
489: setDefaultProperty(
490: "fontset.dialoginput.plain",
491: "-adobe-courier-medium-r-*--*-%d-*");
492: setDefaultProperty(
493: "fontset.dialoginput.italic",
494: "-adobe-courier-medium-i-*--*-%d-*");
495: setDefaultProperty(
496: "fontset.dialoginput.bold",
497: "-adobe-courier-bold-r-*--*-%d-*");
498: setDefaultProperty(
499: "fontset.dialoginput.bolditalic",
500: "-adobe-courier-bold-i-*--*-%d-*");
501: setDefaultProperty("fontset.zapfdingbats",
502: "-urw-itc zapfdingbats-medium-r-normal--*-%d-*");
503: setDefaultProperty(
504: "fontset.timesroman.plain",
505: "-adobe-times-medium-r-*--*-%d-*");
506: setDefaultProperty(
507: "fontset.timesroman.italic",
508: "-adobe-times-medium-i-*--*-%d-*");
509: setDefaultProperty(
510: "fontset.timesroman.bold",
511: "-adobe-times-bold-r-*--*-%d-*");
512: setDefaultProperty(
513: "fontset.timesroman.bolditalic",
514: "-adobe-times-bold-i-*--*-%d-*");
515: setDefaultProperty(
516: "fontset.helvetica.plain",
517: "-adobe-helvetica-medium-r-normal--*-%d-*");
518: setDefaultProperty(
519: "fontset.helvetica.italic",
520: "-adobe-helvetica-medium-i-normal--*-%d-*");
521: setDefaultProperty(
522: "fontset.helvetica.bold",
523: "-adobe-helvetica-bold-r-medium--*-%d-*");
524: setDefaultProperty(
525: "fontset.helvetica.bolditalic",
526: "-adobe-helvetica-bold-i-normal--*-%d-*");
527: setDefaultProperty("fontset.courier.plain",
528: "-adobe-courier-medium-r-*--*-%d-*");
529: setDefaultProperty(
530: "fontset.courier.italic",
531: "-adobe-courier-medium-i-*--*-%d-*");
532: setDefaultProperty("fontset.courier.bold",
533: "-adobe-courier-bold-r-*--*-%d-*");
534: setDefaultProperty(
535: "fontset.courier.bolditalic",
536: "-adobe-courier-bold-i-*--*-%d-*");
537: setDefaultProperty("fontset.zapfdingbats",
538: "-urw-itc zapfdingbats-medium-r-normal--*-%d-*");
539: setDefaultProperty("fontset.default",
540: "-adobe-helvetica-medium-r-normal--*-%d-*");
541: }
542:
543: return null;
544: }
545: });
546: }
547:
548: /*
549: * 6228133
550: *
551: * Called when the VM is shutting down by QtToolkit's shutdown hook.
552: */
553: static void cleanup() {
554: if (fontToPeerMap.size() == 0) {
555: return;
556: }
557:
558: int i = 0, len = 0;
559: ;
560:
561: // Free the native qt font memory. This pointers are being held
562: // in the static cache (Map).
563: len = fontToPeerMap.size();
564: int[] fontArray = new int[len];
565: Iterator itr = fontToPeerMap.entrySet().iterator();
566:
567: while (itr.hasNext()) {
568: Map.Entry entry = (Map.Entry) itr.next();
569: QtFontPeer peer = (QtFontPeer) entry.getValue();
570: fontArray[i] = peer.data;
571: i++;
572: }
573: deleteFonts(len, fontArray);
574: }
575:
576: private static void setDefaultProperty(String name, String value) {
577: if (defaultProperties.getProperty(name) == null)
578: defaultProperties.setProperty(name, value);
579: }
580:
581: private static FileIO tryOpeningFontProp(FileIO f, String homedir,
582: String language, String ext) {
583: if (f != null)
584: return f; // already validated
585:
586: String filename = homedir + FileIO.separator + "lib"
587: + FileIO.separator + "font.properties";
588:
589: if (language != null) {
590: filename += "." + language;
591:
592: if (ext != null)
593: filename += "_" + ext;
594: }
595:
596: FileIO propsFile = FileIOFactory.newInstance(filename);
597: if ((propsFile != null) && propsFile.canRead()) {
598: return propsFile;
599: }
600:
601: return null;
602: }
603:
604: /* The map which maps fonts to their peers. */
605:
606: private static Map fontToPeerMap = new HashMap(10);
607:
608: /* Private data used by native code to store the QtFont. */
609:
610: int data;
611:
612: /* The ascent of this font. */
613:
614: private int ascent;
615:
616: /* The descent of this font. */
617:
618: private int descent;
619:
620: /* The leading, i.e., the natural inter-line spacing, of this font. */
621:
622: private int leading;
623: }
|