1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43:
44: import ;
45: import ;
46: import ;
47:
48: import ;
49:
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64:
65: public class GdkFontPeer extends ClasspathFontPeer
66: {
67: static final FontRenderContext DEFAULT_CTX =
68: new FontRenderContext(null, false, false);
69:
70:
75: HashMap<String,TextLayout> textLayoutCache = new GtkToolkit.LRUCache<String,TextLayout>(500);
76:
77: private class GdkFontMetrics extends FontMetrics
78: {
79:
80: public GdkFontMetrics (Font font)
81: {
82: super(initFont(font));
83: }
84:
85: public int stringWidth (String str)
86: {
87: TextLayout tl = textLayoutCache.get(str);
88: if (tl == null)
89: {
90: tl = new TextLayout(str, font, DEFAULT_CTX);
91: textLayoutCache.put(str, tl);
92: }
93: return (int) tl.getAdvance();
94: }
95:
96: public int charWidth (char ch)
97: {
98: return stringWidth (new String (new char[] { ch }));
99: }
100:
101: public int charsWidth (char data[], int off, int len)
102: {
103: return stringWidth (new String (data, off, len));
104: }
105:
106: public int getHeight()
107: {
108: return (int) height;
109: }
110:
111: public int getLeading ()
112: {
113: return (int) (height - (ascent + descent));
114: }
115:
116: public int getAscent ()
117: {
118: return (int) ascent;
119: }
120:
121: public int getMaxAscent ()
122: {
123: return (int) ascent;
124: }
125:
126: public int getDescent ()
127: {
128: return (int) descent;
129: }
130:
131: public int getMaxDescent ()
132: {
133: return (int) maxDescent;
134: }
135:
136: public int getMaxAdvance ()
137: {
138: return (int) maxAdvance;
139: }
140: }
141:
142: static native void initStaticState();
143: private final int native_state = GtkGenericPeer.getUniqueInteger ();
144:
145:
148: private HashMap<Integer,GlyphMetrics> metricsCache;
149:
150: private static final int FONT_METRICS_ASCENT = 0;
151: private static final int FONT_METRICS_MAX_ASCENT = 1;
152: private static final int FONT_METRICS_DESCENT = 2;
153: private static final int FONT_METRICS_MAX_DESCENT = 3;
154: private static final int FONT_METRICS_MAX_ADVANCE = 4;
155: private static final int FONT_METRICS_HEIGHT = 5;
156: private static final int FONT_METRICS_UNDERLINE_OFFSET = 6;
157: private static final int FONT_METRICS_UNDERLINE_THICKNESS = 7;
158:
159: float ascent;
160: float descent;
161: float maxAscent;
162: float maxDescent;
163: float maxAdvance;
164: float height;
165: float underlineOffset;
166: float underlineThickness;
167:
168: GdkFontMetrics metrics;
169:
170: static
171: {
172: if (true)
173: {
174: System.loadLibrary("gtkpeer");
175: }
176:
177: initStaticState ();
178:
179: }
180:
181: private ByteBuffer nameTable = null;
182:
183:
189: private Pointer nativeFont;
190:
191: private native void initState ();
192: private native void dispose ();
193: private native void setFont (String family, int style, int size);
194:
195: native synchronized void getFontMetrics(double [] metrics);
196: native synchronized void getTextMetrics(String str, double [] metrics);
197:
198: native void releasePeerGraphicsResource();
199:
200:
201: protected void finalize ()
202: {
203: releasePeerGraphicsResource();
204: dispose ();
205: }
206:
207:
213:
214: private String buildString(CharacterIterator iter)
215: {
216: CPStringBuilder sb = new CPStringBuilder();
217: for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next())
218: sb.append(c);
219: return sb.toString();
220: }
221:
222: private String buildString(CharacterIterator iter, int begin, int limit)
223: {
224: CPStringBuilder sb = new CPStringBuilder();
225: int i = 0;
226: for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next(), i++)
227: {
228: if (begin <= i)
229: sb.append(c);
230: if (limit <= i)
231: break;
232: }
233: return sb.toString();
234: }
235:
236: private String buildString(char[] chars, int begin, int limit)
237: {
238: return new String(chars, begin, limit - begin);
239: }
240:
241:
242:
243: public GdkFontPeer (String name, int style)
244: {
245:
246: this(name, style, 12);
247: }
248:
249: public GdkFontPeer (String name, int style, int size)
250: {
251: super(name, style, size);
252: initState ();
253: setFont (this.familyName, this.style, (int)this.size);
254: metricsCache = new HashMap<Integer,GlyphMetrics>();
255: setupMetrics();
256: }
257:
258: public GdkFontPeer (String name, Map attributes)
259: {
260: super(name, attributes);
261: initState ();
262: setFont (this.familyName, this.style, (int)this.size);
263: metricsCache = new HashMap<Integer,GlyphMetrics>();
264: setupMetrics();
265: }
266:
267:
268:
272: static Font initFont(Font font)
273: {
274: if (font == null)
275: return new Font("Dialog", Font.PLAIN, 12);
276: else if (font.getPeer() instanceof GdkFontPeer)
277: return font;
278: else
279: {
280: ClasspathToolkit toolkit;
281: toolkit = (ClasspathToolkit) Toolkit.getDefaultToolkit();
282: return toolkit.getFont(font.getName(), font.getAttributes());
283: }
284: }
285:
286: private void setupMetrics()
287: {
288: double [] hires = new double[8];
289: getFontMetrics(hires);
290: ascent = (float) hires[FONT_METRICS_ASCENT];
291: maxAscent = (float) hires[FONT_METRICS_MAX_ASCENT];
292: descent = (float) hires[FONT_METRICS_DESCENT];
293: maxDescent = (float) hires[FONT_METRICS_MAX_DESCENT];
294: maxAdvance = (float) hires[FONT_METRICS_MAX_ADVANCE];
295: height = (float) hires[FONT_METRICS_HEIGHT];
296: underlineOffset = (float) hires[FONT_METRICS_UNDERLINE_OFFSET];
297: underlineThickness = (float) hires[FONT_METRICS_UNDERLINE_THICKNESS];
298: }
299:
300:
303: public String getSubFamilyName(Font font, Locale locale)
304: {
305: String name;
306:
307: if (locale == null)
308: locale = Locale.getDefault();
309:
310: name = getName(NameDecoder.NAME_SUBFAMILY, locale);
311: if (name == null)
312: {
313: name = getName(NameDecoder.NAME_SUBFAMILY, Locale.ENGLISH);
314: if ("Regular".equals(name))
315: name = null;
316: }
317:
318: return name;
319: }
320:
321:
329: private native byte[] getTrueTypeTable(byte n, byte a, byte m, byte e);
330:
331:
335: public String getPostScriptName(Font font)
336: {
337: String name = getName(NameDecoder.NAME_POSTSCRIPT,
338: null);
339: if( name == null )
340: return this.familyName;
341:
342: return name;
343: }
344:
345:
355: private String getName(int name, Locale locale)
356: {
357: if (nameTable == null)
358: {
359: byte[] data = getTrueTypeTable((byte)'n', (byte) 'a',
360: (byte) 'm', (byte) 'e');
361: if( data == null )
362: return null;
363:
364: nameTable = ByteBuffer.wrap( data );
365: }
366:
367: return NameDecoder.getName(nameTable, name, locale);
368: }
369:
370: public boolean canDisplay (Font font, int c)
371: {
372:
373: return true;
374: }
375:
376: public int canDisplayUpTo (Font font, CharacterIterator i, int start, int limit)
377: {
378:
379: return -1;
380: }
381:
382: public GlyphVector createGlyphVector (Font font,
383: FontRenderContext ctx,
384: CharacterIterator i)
385: {
386: return new FreetypeGlyphVector(font, buildString (i), ctx);
387: }
388:
389: public GlyphVector createGlyphVector (Font font,
390: FontRenderContext ctx,
391: int[] glyphCodes)
392: {
393: return new FreetypeGlyphVector(font, glyphCodes, ctx);
394: }
395:
396: public byte getBaselineFor (Font font, char c)
397: {
398:
399: return Font.ROMAN_BASELINE;
400: }
401:
402: private class GdkFontLineMetrics extends LineMetrics
403: {
404: private int nchars;
405: public GdkFontLineMetrics (GdkFontPeer fp, int n)
406: {
407: nchars = n;
408: }
409:
410: public float getAscent()
411: {
412: return ascent;
413: }
414:
415: public int getBaselineIndex()
416: {
417:
418: return Font.ROMAN_BASELINE;
419: }
420:
421: public float[] getBaselineOffsets()
422: {
423: return new float[3];
424: }
425:
426: public float getDescent()
427: {
428: return descent;
429: }
430:
431: public float getHeight()
432: {
433: return height;
434: }
435:
436: public float getLeading()
437: {
438: return height - (ascent + descent);
439: }
440:
441: public int getNumChars()
442: {
443: return nchars;
444: }
445:
446: public float getStrikethroughOffset()
447: {
448:
449: return ascent / 2;
450: }
451:
452: public float getStrikethroughThickness()
453: {
454:
455: return 1.f;
456: }
457:
458: public float getUnderlineOffset()
459: {
460: return underlineOffset;
461: }
462:
463: public float getUnderlineThickness()
464: {
465: return underlineThickness;
466: }
467:
468: }
469:
470: public LineMetrics getLineMetrics (Font font, CharacterIterator ci,
471: int begin, int limit, FontRenderContext rc)
472: {
473: return new GdkFontLineMetrics (this, limit - begin);
474: }
475:
476: public Rectangle2D getMaxCharBounds (Font font, FontRenderContext rc)
477: {
478: throw new UnsupportedOperationException ();
479: }
480:
481: public int getMissingGlyphCode (Font font)
482: {
483: throw new UnsupportedOperationException ();
484: }
485:
486: public String getGlyphName (Font font, int glyphIndex)
487: {
488: throw new UnsupportedOperationException ();
489: }
490:
491: public int getNumGlyphs (Font font)
492: {
493: byte[] data = getTrueTypeTable((byte)'m', (byte) 'a',
494: (byte)'x', (byte) 'p');
495: if( data == null )
496: return -1;
497:
498: ByteBuffer buf = ByteBuffer.wrap( data );
499: return buf.getShort(4);
500: }
501:
502: public boolean hasUniformLineMetrics (Font font)
503: {
504: return true;
505: }
506:
507: public GlyphVector layoutGlyphVector (Font font, FontRenderContext frc,
508: char[] chars, int start, int limit,
509: int flags)
510: {
511: return new FreetypeGlyphVector(font, chars, start, limit - start,
512: frc, flags);
513: }
514:
515: public LineMetrics getLineMetrics (Font font, String str,
516: FontRenderContext frc)
517: {
518: return new GdkFontLineMetrics (this, str.length ());
519: }
520:
521: public FontMetrics getFontMetrics (Font font)
522: {
523: if (metrics == null)
524: metrics = new GdkFontMetrics(font);
525: return metrics;
526: }
527:
528:
532: GlyphMetrics getGlyphMetrics( int glyphCode )
533: {
534: return metricsCache.get(new Integer(glyphCode));
535: }
536:
537:
540: void putGlyphMetrics( int glyphCode, GlyphMetrics metrics )
541: {
542: metricsCache.put( new Integer( glyphCode ), metrics );
543: }
544:
545: }