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
.classpath
.Configuration
;
42 import gnu
.classpath
.Pointer
;
44 import gnu
.java
.awt
.ClasspathToolkit
;
45 import gnu
.java
.awt
.peer
.ClasspathFontPeer
;
46 import gnu
.java
.awt
.font
.opentype
.NameDecoder
;
48 import gnu
.java
.lang
.CPStringBuilder
;
51 import java
.awt
.FontMetrics
;
52 import java
.awt
.Toolkit
;
53 import java
.awt
.font
.FontRenderContext
;
54 import java
.awt
.font
.GlyphVector
;
55 import java
.awt
.font
.GlyphMetrics
;
56 import java
.awt
.font
.LineMetrics
;
57 import java
.awt
.font
.TextLayout
;
58 import java
.awt
.geom
.Rectangle2D
;
59 import java
.text
.CharacterIterator
;
60 import java
.util
.Locale
;
62 import java
.nio
.ByteBuffer
;
63 import java
.util
.HashMap
;
65 public class GdkFontPeer
extends ClasspathFontPeer
67 static final FontRenderContext DEFAULT_CTX
=
68 new FontRenderContext(null, false, false);
71 * Caches TextLayout instances for use in charsWidth() and drawString().
72 * The size of the cache has been chosen so that relativly large GUIs with
73 * text documents are still efficient.
75 HashMap
<String
,TextLayout
> textLayoutCache
= new GtkToolkit
.LRUCache
<String
,TextLayout
>(500);
77 private class GdkFontMetrics
extends FontMetrics
80 public GdkFontMetrics (Font font
)
82 super(initFont(font
));
85 public int stringWidth (String str
)
87 TextLayout tl
= textLayoutCache
.get(str
);
90 tl
= new TextLayout(str
, font
, DEFAULT_CTX
);
91 textLayoutCache
.put(str
, tl
);
93 return (int) tl
.getAdvance();
96 public int charWidth (char ch
)
98 return stringWidth (new String (new char[] { ch
}));
101 public int charsWidth (char data
[], int off
, int len
)
103 return stringWidth (new String (data
, off
, len
));
106 public int getHeight()
111 public int getLeading ()
113 return (int) (height
- (ascent
+ descent
));
116 public int getAscent ()
121 public int getMaxAscent ()
126 public int getDescent ()
128 return (int) descent
;
131 public int getMaxDescent ()
133 return (int) maxDescent
;
136 public int getMaxAdvance ()
138 return (int) maxAdvance
;
142 static native void initStaticState();
143 private final int native_state
= GtkGenericPeer
.getUniqueInteger ();
146 * Cache GlyphMetrics objects.
148 private HashMap
<Integer
,GlyphMetrics
> metricsCache
;
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;
165 float underlineOffset
;
166 float underlineThickness
;
168 GdkFontMetrics metrics
;
172 if (true) // GCJ LOCAL
174 System
.loadLibrary("gtkpeer");
181 private ByteBuffer nameTable
= null;
184 * The pointer to the native font data.
186 * This field is manipulated by native code. Don't change or remove
187 * without adjusting the native code.
189 private Pointer nativeFont
;
191 private native void initState ();
192 private native void dispose ();
193 private native void setFont (String family
, int style
, int size
);
195 native synchronized void getFontMetrics(double [] metrics
);
196 native synchronized void getTextMetrics(String str
, double [] metrics
);
198 native void releasePeerGraphicsResource();
201 protected void finalize ()
203 releasePeerGraphicsResource();
208 * Helpers for the 3-way overloading that this class seems to suffer
209 * from. Remove them if you feel like they're a performance bottleneck,
210 * for the time being I prefer my code not be written and debugged in
214 private String
buildString(CharacterIterator iter
)
216 CPStringBuilder sb
= new CPStringBuilder();
217 for(char c
= iter
.first(); c
!= CharacterIterator
.DONE
; c
= iter
.next())
219 return sb
.toString();
222 private String
buildString(CharacterIterator iter
, int begin
, int limit
)
224 CPStringBuilder sb
= new CPStringBuilder();
226 for(char c
= iter
.first(); c
!= CharacterIterator
.DONE
; c
= iter
.next(), i
++)
233 return sb
.toString();
236 private String
buildString(char[] chars
, int begin
, int limit
)
238 return new String(chars
, begin
, limit
- begin
);
243 public GdkFontPeer (String name
, int style
)
245 // All fonts get a default size of 12 if size is not specified.
246 this(name
, style
, 12);
249 public GdkFontPeer (String name
, int style
, int size
)
251 super(name
, style
, size
);
253 setFont (this.familyName
, this.style
, (int)this.size
);
254 metricsCache
= new HashMap
<Integer
,GlyphMetrics
>();
258 public GdkFontPeer (String name
, Map attributes
)
260 super(name
, attributes
);
262 setFont (this.familyName
, this.style
, (int)this.size
);
263 metricsCache
= new HashMap
<Integer
,GlyphMetrics
>();
269 * Makes sure to return a Font based on the given Font that has as
270 * peer a GdkFontPeer. Used in the initializer.
272 static Font
initFont(Font font
)
275 return new Font("Dialog", Font
.PLAIN
, 12);
276 else if (font
.getPeer() instanceof GdkFontPeer
)
280 ClasspathToolkit toolkit
;
281 toolkit
= (ClasspathToolkit
) Toolkit
.getDefaultToolkit();
282 return toolkit
.getFont(font
.getName(), font
.getAttributes());
286 private void setupMetrics()
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
];
301 * Unneeded, but implemented anyway.
303 public String
getSubFamilyName(Font font
, Locale locale
)
308 locale
= Locale
.getDefault();
310 name
= getName(NameDecoder
.NAME_SUBFAMILY
, locale
);
313 name
= getName(NameDecoder
.NAME_SUBFAMILY
, Locale
.ENGLISH
);
314 if ("Regular".equals(name
))
322 * Returns the bytes belonging to a TrueType/OpenType table,
323 * Parameters n,a,m,e identify the 4-byte ASCII tag of the table.
325 * Returns null if the font is not TT, the table is nonexistant,
326 * or if some other unexpected error occured.
329 private native byte[] getTrueTypeTable(byte n
, byte a
, byte m
, byte e
);
332 * Returns the PostScript name of the font, defaults to the familyName if
333 * a PS name could not be retrieved.
335 public String
getPostScriptName(Font font
)
337 String name
= getName(NameDecoder
.NAME_POSTSCRIPT
,
338 /* any language */ null);
340 return this.familyName
;
346 * Extracts a String from the font’s name table.
348 * @param name the numeric TrueType or OpenType name ID.
350 * @param locale the locale for which names shall be localized, or
351 * <code>null</code> if the locale does mot matter because the name
352 * is known to be language-independent (for example, because it is
353 * the PostScript name).
355 private String
getName(int name
, Locale locale
)
357 if (nameTable
== null)
359 byte[] data
= getTrueTypeTable((byte)'n', (byte) 'a',
360 (byte) 'm', (byte) 'e');
364 nameTable
= ByteBuffer
.wrap( data
);
367 return NameDecoder
.getName(nameTable
, name
, locale
);
370 public boolean canDisplay (Font font
, int c
)
372 // FIXME: inquire with pango
376 public int canDisplayUpTo (Font font
, CharacterIterator i
, int start
, int limit
)
378 // FIXME: inquire with pango
382 public GlyphVector
createGlyphVector (Font font
,
383 FontRenderContext ctx
,
386 return new FreetypeGlyphVector(font
, buildString (i
), ctx
);
389 public GlyphVector
createGlyphVector (Font font
,
390 FontRenderContext ctx
,
393 return new FreetypeGlyphVector(font
, glyphCodes
, ctx
);
396 public byte getBaselineFor (Font font
, char c
)
398 // FIXME: Actually check.
399 return Font
.ROMAN_BASELINE
;
402 private class GdkFontLineMetrics
extends LineMetrics
405 public GdkFontLineMetrics (GdkFontPeer fp
, int n
)
410 public float getAscent()
415 public int getBaselineIndex()
418 return Font
.ROMAN_BASELINE
;
421 public float[] getBaselineOffsets()
426 public float getDescent()
431 public float getHeight()
436 public float getLeading()
438 return height
- (ascent
+ descent
);
441 public int getNumChars()
446 public float getStrikethroughOffset()
448 // FreeType doesn't seem to provide a value here.
452 public float getStrikethroughThickness()
454 // FreeType doesn't seem to provide a value here.
458 public float getUnderlineOffset()
460 return underlineOffset
;
463 public float getUnderlineThickness()
465 return underlineThickness
;
470 public LineMetrics
getLineMetrics (Font font
, CharacterIterator ci
,
471 int begin
, int limit
, FontRenderContext rc
)
473 return new GdkFontLineMetrics (this, limit
- begin
);
476 public Rectangle2D
getMaxCharBounds (Font font
, FontRenderContext rc
)
478 throw new UnsupportedOperationException ();
481 public int getMissingGlyphCode (Font font
)
483 throw new UnsupportedOperationException ();
486 public String
getGlyphName (Font font
, int glyphIndex
)
488 throw new UnsupportedOperationException ();
491 public int getNumGlyphs (Font font
)
493 byte[] data
= getTrueTypeTable((byte)'m', (byte) 'a',
494 (byte)'x', (byte) 'p');
498 ByteBuffer buf
= ByteBuffer
.wrap( data
);
499 return buf
.getShort(4);
502 public boolean hasUniformLineMetrics (Font font
)
507 public GlyphVector
layoutGlyphVector (Font font
, FontRenderContext frc
,
508 char[] chars
, int start
, int limit
,
511 return new FreetypeGlyphVector(font
, chars
, start
, limit
- start
,
515 public LineMetrics
getLineMetrics (Font font
, String str
,
516 FontRenderContext frc
)
518 return new GdkFontLineMetrics (this, str
.length ());
521 public FontMetrics
getFontMetrics (Font font
)
524 metrics
= new GdkFontMetrics(font
);
529 * Returns a cached GlyphMetrics object for a given glyphcode,
530 * or null if it doesn't exist in the cache.
532 GlyphMetrics
getGlyphMetrics( int glyphCode
)
534 return metricsCache
.get(new Integer(glyphCode
));
538 * Put a GlyphMetrics object in the cache.
540 void putGlyphMetrics( int glyphCode
, GlyphMetrics metrics
)
542 metricsCache
.put( new Integer( glyphCode
), metrics
);