1 /* GdkFontPeer.java -- Implements FontPeer with GTK+
2 Copyright (C) 1999, 2004, 2005, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu
.java
.awt
.peer
.gtk
;
41 import gnu
.java
.awt
.ClasspathToolkit
;
42 import gnu
.java
.awt
.peer
.ClasspathFontPeer
;
43 import gnu
.java
.awt
.font
.opentype
.NameDecoder
;
46 import java
.awt
.FontMetrics
;
47 import java
.awt
.Toolkit
;
48 import java
.awt
.font
.FontRenderContext
;
49 import java
.awt
.font
.GlyphVector
;
50 import java
.awt
.font
.GlyphMetrics
;
51 import java
.awt
.font
.LineMetrics
;
52 import java
.awt
.font
.TextLayout
;
53 import java
.awt
.geom
.Rectangle2D
;
54 import java
.text
.CharacterIterator
;
55 import java
.util
.Locale
;
57 import java
.nio
.ByteBuffer
;
58 import java
.util
.HashMap
;
60 public class GdkFontPeer
extends ClasspathFontPeer
62 static final FontRenderContext DEFAULT_CTX
=
63 new FontRenderContext(null, false, false);
66 * Caches TextLayout instances for use in charsWidth() and drawString().
67 * The size of the cache has been chosen so that relativly large GUIs with
68 * text documents are still efficient.
70 HashMap
<String
,TextLayout
> textLayoutCache
= new GtkToolkit
.LRUCache
<String
,TextLayout
>(500);
72 private class GdkFontMetrics
extends FontMetrics
75 public GdkFontMetrics (Font font
)
77 super(initFont(font
));
80 public int stringWidth (String str
)
82 TextLayout tl
= textLayoutCache
.get(str
);
85 tl
= new TextLayout(str
, font
, DEFAULT_CTX
);
86 textLayoutCache
.put(str
, tl
);
88 return (int) tl
.getAdvance();
91 public int charWidth (char ch
)
93 return stringWidth (new String (new char[] { ch
}));
96 public int charsWidth (char data
[], int off
, int len
)
98 return stringWidth (new String (data
, off
, len
));
101 public int getHeight()
106 public int getLeading ()
108 return (int) (height
- (ascent
+ descent
));
111 public int getAscent ()
116 public int getMaxAscent ()
121 public int getDescent ()
123 return (int) descent
;
126 public int getMaxDescent ()
128 return (int) maxDescent
;
131 public int getMaxAdvance ()
133 return (int) maxAdvance
;
137 static native void initStaticState();
138 private final int native_state
= GtkGenericPeer
.getUniqueInteger ();
141 * Cache GlyphMetrics objects.
143 private HashMap
<Integer
,GlyphMetrics
> metricsCache
;
145 private static final int FONT_METRICS_ASCENT
= 0;
146 private static final int FONT_METRICS_MAX_ASCENT
= 1;
147 private static final int FONT_METRICS_DESCENT
= 2;
148 private static final int FONT_METRICS_MAX_DESCENT
= 3;
149 private static final int FONT_METRICS_MAX_ADVANCE
= 4;
150 private static final int FONT_METRICS_HEIGHT
= 5;
151 private static final int FONT_METRICS_UNDERLINE_OFFSET
= 6;
152 private static final int FONT_METRICS_UNDERLINE_THICKNESS
= 7;
160 float underlineOffset
;
161 float underlineThickness
;
163 GdkFontMetrics metrics
;
167 System
.loadLibrary("gtkpeer");
173 private ByteBuffer nameTable
= null;
175 private native void initState ();
176 private native void dispose ();
177 private native void setFont (String family
, int style
, int size
);
179 native synchronized void getFontMetrics(double [] metrics
);
180 native synchronized void getTextMetrics(String str
, double [] metrics
);
182 native void releasePeerGraphicsResource();
185 protected void finalize ()
187 releasePeerGraphicsResource();
192 * Helpers for the 3-way overloading that this class seems to suffer
193 * from. Remove them if you feel like they're a performance bottleneck,
194 * for the time being I prefer my code not be written and debugged in
198 private String
buildString(CharacterIterator iter
)
200 StringBuffer sb
= new StringBuffer();
201 for(char c
= iter
.first(); c
!= CharacterIterator
.DONE
; c
= iter
.next())
203 return sb
.toString();
206 private String
buildString(CharacterIterator iter
, int begin
, int limit
)
208 StringBuffer sb
= new StringBuffer();
210 for(char c
= iter
.first(); c
!= CharacterIterator
.DONE
; c
= iter
.next(), i
++)
217 return sb
.toString();
220 private String
buildString(char[] chars
, int begin
, int limit
)
222 return new String(chars
, begin
, limit
- begin
);
227 public GdkFontPeer (String name
, int style
)
229 // All fonts get a default size of 12 if size is not specified.
230 this(name
, style
, 12);
233 public GdkFontPeer (String name
, int style
, int size
)
235 super(name
, style
, size
);
237 setFont (this.familyName
, this.style
, (int)this.size
);
238 metricsCache
= new HashMap
<Integer
,GlyphMetrics
>();
242 public GdkFontPeer (String name
, Map attributes
)
244 super(name
, attributes
);
246 setFont (this.familyName
, this.style
, (int)this.size
);
247 metricsCache
= new HashMap
<Integer
,GlyphMetrics
>();
253 * Makes sure to return a Font based on the given Font that has as
254 * peer a GdkFontPeer. Used in the initializer.
256 static Font
initFont(Font font
)
259 return new Font("Dialog", Font
.PLAIN
, 12);
260 else if (font
.getPeer() instanceof GdkFontPeer
)
264 ClasspathToolkit toolkit
;
265 toolkit
= (ClasspathToolkit
) Toolkit
.getDefaultToolkit();
266 return toolkit
.getFont(font
.getName(), font
.getAttributes());
270 private void setupMetrics()
272 double [] hires
= new double[8];
273 getFontMetrics(hires
);
274 ascent
= (float) hires
[FONT_METRICS_ASCENT
];
275 maxAscent
= (float) hires
[FONT_METRICS_MAX_ASCENT
];
276 descent
= (float) hires
[FONT_METRICS_DESCENT
];
277 maxDescent
= (float) hires
[FONT_METRICS_MAX_DESCENT
];
278 maxAdvance
= (float) hires
[FONT_METRICS_MAX_ADVANCE
];
279 height
= (float) hires
[FONT_METRICS_HEIGHT
];
280 underlineOffset
= (float) hires
[FONT_METRICS_UNDERLINE_OFFSET
];
281 underlineThickness
= (float) hires
[FONT_METRICS_UNDERLINE_THICKNESS
];
285 * Unneeded, but implemented anyway.
287 public String
getSubFamilyName(Font font
, Locale locale
)
292 locale
= Locale
.getDefault();
294 name
= getName(NameDecoder
.NAME_SUBFAMILY
, locale
);
297 name
= getName(NameDecoder
.NAME_SUBFAMILY
, Locale
.ENGLISH
);
298 if ("Regular".equals(name
))
306 * Returns the bytes belonging to a TrueType/OpenType table,
307 * Parameters n,a,m,e identify the 4-byte ASCII tag of the table.
309 * Returns null if the font is not TT, the table is nonexistant,
310 * or if some other unexpected error occured.
313 private native byte[] getTrueTypeTable(byte n
, byte a
, byte m
, byte e
);
316 * Returns the PostScript name of the font, defaults to the familyName if
317 * a PS name could not be retrieved.
319 public String
getPostScriptName(Font font
)
321 String name
= getName(NameDecoder
.NAME_POSTSCRIPT
,
322 /* any language */ null);
324 return this.familyName
;
330 * Extracts a String from the font’s name table.
332 * @param name the numeric TrueType or OpenType name ID.
334 * @param locale the locale for which names shall be localized, or
335 * <code>null</code> if the locale does mot matter because the name
336 * is known to be language-independent (for example, because it is
337 * the PostScript name).
339 private String
getName(int name
, Locale locale
)
341 if (nameTable
== null)
343 byte[] data
= getTrueTypeTable((byte)'n', (byte) 'a',
344 (byte) 'm', (byte) 'e');
348 nameTable
= ByteBuffer
.wrap( data
);
351 return NameDecoder
.getName(nameTable
, name
, locale
);
354 public boolean canDisplay (Font font
, char c
)
356 // FIXME: inquire with pango
360 public int canDisplayUpTo (Font font
, CharacterIterator i
, int start
, int limit
)
362 // FIXME: inquire with pango
366 public GlyphVector
createGlyphVector (Font font
,
367 FontRenderContext ctx
,
370 return new FreetypeGlyphVector(font
, buildString (i
), ctx
);
373 public GlyphVector
createGlyphVector (Font font
,
374 FontRenderContext ctx
,
377 return new FreetypeGlyphVector(font
, glyphCodes
, ctx
);
380 public byte getBaselineFor (Font font
, char c
)
382 // FIXME: Actually check.
383 return Font
.ROMAN_BASELINE
;
386 private class GdkFontLineMetrics
extends LineMetrics
389 public GdkFontLineMetrics (GdkFontPeer fp
, int n
)
394 public float getAscent()
399 public int getBaselineIndex()
402 return Font
.ROMAN_BASELINE
;
405 public float[] getBaselineOffsets()
410 public float getDescent()
415 public float getHeight()
420 public float getLeading()
422 return height
- (ascent
+ descent
);
425 public int getNumChars()
430 public float getStrikethroughOffset()
432 // FreeType doesn't seem to provide a value here.
436 public float getStrikethroughThickness()
438 // FreeType doesn't seem to provide a value here.
442 public float getUnderlineOffset()
444 return underlineOffset
;
447 public float getUnderlineThickness()
449 return underlineThickness
;
454 public LineMetrics
getLineMetrics (Font font
, CharacterIterator ci
,
455 int begin
, int limit
, FontRenderContext rc
)
457 return new GdkFontLineMetrics (this, limit
- begin
);
460 public Rectangle2D
getMaxCharBounds (Font font
, FontRenderContext rc
)
462 throw new UnsupportedOperationException ();
465 public int getMissingGlyphCode (Font font
)
467 throw new UnsupportedOperationException ();
470 public String
getGlyphName (Font font
, int glyphIndex
)
472 throw new UnsupportedOperationException ();
475 public int getNumGlyphs (Font font
)
477 byte[] data
= getTrueTypeTable((byte)'m', (byte) 'a',
478 (byte)'x', (byte) 'p');
482 ByteBuffer buf
= ByteBuffer
.wrap( data
);
483 return buf
.getShort(4);
486 public boolean hasUniformLineMetrics (Font font
)
491 public GlyphVector
layoutGlyphVector (Font font
, FontRenderContext frc
,
492 char[] chars
, int start
, int limit
,
495 return new FreetypeGlyphVector(font
, chars
, start
, limit
- start
,
499 public LineMetrics
getLineMetrics (Font font
, String str
,
500 FontRenderContext frc
)
502 return new GdkFontLineMetrics (this, str
.length ());
505 public FontMetrics
getFontMetrics (Font font
)
508 metrics
= new GdkFontMetrics(font
);
513 * Returns a cached GlyphMetrics object for a given glyphcode,
514 * or null if it doesn't exist in the cache.
516 GlyphMetrics
getGlyphMetrics( int glyphCode
)
518 return metricsCache
.get(new Integer(glyphCode
));
522 * Put a GlyphMetrics object in the cache.
524 void putGlyphMetrics( int glyphCode
, GlyphMetrics metrics
)
526 metricsCache
.put( new Integer( glyphCode
), metrics
);