libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / gnu / java / awt / peer / gtk / GdkFontPeer.java
blob826cfbeceadbac51ccc99d71d1b05bd08e7eee3e
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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;
50 import java.awt.Font;
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;
61 import java.util.Map;
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);
70 /**
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);
88 if (tl == null)
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()
108 return (int) height;
111 public int getLeading ()
113 return (int) (height - (ascent + descent));
116 public int getAscent ()
118 return (int) ascent;
121 public int getMaxAscent ()
123 return (int) ascent;
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;
159 float ascent;
160 float descent;
161 float maxAscent;
162 float maxDescent;
163 float maxAdvance;
164 float height;
165 float underlineOffset;
166 float underlineThickness;
168 GdkFontMetrics metrics;
170 static
172 if (true) // GCJ LOCAL
174 System.loadLibrary("gtkpeer");
177 initStaticState ();
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();
204 dispose ();
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
211 * triplicate.
214 private String buildString(CharacterIterator iter)
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();
222 private String buildString(CharacterIterator iter, int begin, int limit)
224 CPStringBuilder sb = new CPStringBuilder();
225 int i = 0;
226 for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next(), i++)
228 if (begin <= i)
229 sb.append(c);
230 if (limit <= i)
231 break;
233 return sb.toString();
236 private String buildString(char[] chars, int begin, int limit)
238 return new String(chars, begin, limit - begin);
241 /* Public API */
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);
252 initState ();
253 setFont (this.familyName, this.style, (int)this.size);
254 metricsCache = new HashMap<Integer,GlyphMetrics>();
255 setupMetrics();
258 public GdkFontPeer (String name, Map attributes)
260 super(name, attributes);
261 initState ();
262 setFont (this.familyName, this.style, (int)this.size);
263 metricsCache = new HashMap<Integer,GlyphMetrics>();
264 setupMetrics();
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)
274 if (font == null)
275 return new Font("Dialog", Font.PLAIN, 12);
276 else if (font.getPeer() instanceof GdkFontPeer)
277 return font;
278 else
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)
305 String name;
307 if (locale == null)
308 locale = Locale.getDefault();
310 name = getName(NameDecoder.NAME_SUBFAMILY, locale);
311 if (name == null)
313 name = getName(NameDecoder.NAME_SUBFAMILY, Locale.ENGLISH);
314 if ("Regular".equals(name))
315 name = null;
318 return 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);
339 if( name == null )
340 return this.familyName;
342 return name;
346 * Extracts a String from the font&#x2019;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');
361 if( data == null )
362 return null;
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
373 return true;
376 public int canDisplayUpTo (Font font, CharacterIterator i, int start, int limit)
378 // FIXME: inquire with pango
379 return -1;
382 public GlyphVector createGlyphVector (Font font,
383 FontRenderContext ctx,
384 CharacterIterator i)
386 return new FreetypeGlyphVector(font, buildString (i), ctx);
389 public GlyphVector createGlyphVector (Font font,
390 FontRenderContext ctx,
391 int[] glyphCodes)
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
404 private int nchars;
405 public GdkFontLineMetrics (GdkFontPeer fp, int n)
407 nchars = n;
410 public float getAscent()
412 return ascent;
415 public int getBaselineIndex()
417 // FIXME
418 return Font.ROMAN_BASELINE;
421 public float[] getBaselineOffsets()
423 return new float[3];
426 public float getDescent()
428 return descent;
431 public float getHeight()
433 return height;
436 public float getLeading()
438 return height - (ascent + descent);
441 public int getNumChars()
443 return nchars;
446 public float getStrikethroughOffset()
448 // FreeType doesn't seem to provide a value here.
449 return ascent / 2;
452 public float getStrikethroughThickness()
454 // FreeType doesn't seem to provide a value here.
455 return 1.f;
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');
495 if( data == null )
496 return -1;
498 ByteBuffer buf = ByteBuffer.wrap( data );
499 return buf.getShort(4);
502 public boolean hasUniformLineMetrics (Font font)
504 return true;
507 public GlyphVector layoutGlyphVector (Font font, FontRenderContext frc,
508 char[] chars, int start, int limit,
509 int flags)
511 return new FreetypeGlyphVector(font, chars, start, limit - start,
512 frc, flags);
515 public LineMetrics getLineMetrics (Font font, String str,
516 FontRenderContext frc)
518 return new GdkFontLineMetrics (this, str.length ());
521 public FontMetrics getFontMetrics (Font font)
523 if (metrics == null)
524 metrics = new GdkFontMetrics(font);
525 return metrics;
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 );