1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
3 import org.xwt.translators.*;
11 private Font(Res res, int pointsize) { this.res = res; this.pointsize = pointsize; }
13 public final int pointsize;
15 public int max_ascent;
16 public int max_descent;
17 boolean latinCharsPreloaded = false; ///< true if a request to preload ASCII 32-127 has begun
18 Glyph[] glyphs = new Glyph[65535];
20 public static class Glyph {
21 public Glyph(char c, Font f) { this.c = c; font = f; }
23 public int baseline; // within the picture, this is the y-coordinate of the baseline
24 public int advance; // amount to increment the x-coordinate
26 public final Font font;
30 // Statics //////////////////////////////////////////////////////////////////////
32 private static final Freetype freetype = new Freetype();
33 private static Cache sizeCache = new Cache(100);
34 static final Queue glyphsToBeRendered = new Queue(255);
35 private static Cache fontCache = new Cache(100);
36 public static Font getFont(Res res, int pointsize) {
37 Font ret = (Font)fontCache.get(res, new Integer(pointsize));
38 if (ret == null) fontCache.put(res, new Integer(pointsize), ret = new Font(res, pointsize));
43 // Methods //////////////////////////////////////////////////////////////////////
46 * If the glyphs of <code>text</code> are not yet loaded, spawn a
47 * Task to load them and invoke callback.
49 * returns the width (in the high-order int) and height (in the
50 * low-order int) of the string's rasterization, or -1 if some
51 * glyphs are not loaded.
53 public long rasterizeGlyphs(final String text, PixelBuffer pb, int textcolor,
54 int x, int y, int cx1, int cy1, int cx2, int cy2,
55 final Scheduler.Task callback) {
56 boolean encounteredUnrenderedGlyph = false;
59 for(int i=0; i<text.length(); i++) {
60 final char c = text.charAt(i);
62 if (g == null) glyphsToBeRendered.prepend(g = new Glyph(c, this)); // prepend so they are high priority
64 glyphsToBeRendered.prepend(g);
65 encounteredUnrenderedGlyph = true;
66 } else if (!encounteredUnrenderedGlyph) {
67 if (pb != null && g.p != null)
68 pb.drawPictureAlphaOnly(g.p, x + width, y + g.font.max_ascent - g.baseline, cx1, cy1, cx2, cy2, textcolor);
70 height = java.lang.Math.max(height, max_ascent + max_descent);
74 if (encounteredUnrenderedGlyph && callback != null) Scheduler.add(new Scheduler.Task() { public void perform() {
75 for(int i=0; i<text.length(); i++) {
76 Glyph g = glyphs[text.charAt(i)];
77 if (g == null || g.p == null) { Scheduler.add(this); return; }
82 if (!latinCharsPreloaded) for(int i=32; i<128; i++) glyphsToBeRendered.append(glyphs[i] = new Glyph((char)i, this));
83 if (!latinCharsPreloaded || encounteredUnrenderedGlyph) Scheduler.add(glyphRenderingTask);
84 latinCharsPreloaded = true;
85 return encounteredUnrenderedGlyph ? -1 : (((long)width << 16) | (long)height);
88 public int textwidth(String s) { return (int)(textsize(s) >>> 16L); }
89 public int textheight(String s) { return (int)(textsize(s) & 0xffffffffL); }
90 public long textsize(String s) {
91 Long l = (Long)sizeCache.get(s);
92 if (l != null) return ((Long)l).longValue();
93 long ret = rasterizeGlyphs(s, null, 0, 0, 0, 0, 0, 0, 0, null);
94 if (ret != -1) sizeCache.put(s, new Long(ret));
95 return ret == -1 ? 0 : ret;
98 static final Scheduler.Task glyphRenderingTask = new Scheduler.Task() { public void perform() {
99 Glyph g = (Glyph)glyphsToBeRendered.remove(false);
100 if (g == null) return;
101 if (g.p != null) { perform(); return; }
102 Log.log(Glyph.class, "rendering glyph " + g.c);
103 try { freetype.renderGlyph(g); } catch (IOException e) { Log.log(Freetype.class, e); }