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