2003/11/13 05:04:21
[org.ibex.core.git] / src / org / xwt / Font.java
index 75bd9c8..2eef1f1 100644 (file)
@@ -8,25 +8,40 @@ import java.io.*;
 
 public class Font {
 
+    private Font(Res res, int pointsize) { this.res = res; this.pointsize = pointsize; }
+
     public final int pointsize;
     public final Res res;
     public int max_ascent;
     public int max_descent;
-    public Glyph[] glyphs = new Glyph[65535];
-    boolean used = false;
+    boolean latinCharsPreloaded = false;        ///< true if a request to preload ASCII 32-127 has begun
+    Glyph[] glyphs = new Glyph[65535];
 
-    private Font(Res res, int pointsize) {
-        this.res = res;
-        this.pointsize = pointsize;
+    public static class Glyph {
+        public Glyph(char c, Font f) { this.c = c; font = f; }
+        public char c;
+        public int baseline;       // within the picture, this is the y-coordinate of the baseline
+        public int advance;        // amount to increment the x-coordinate
+        public Picture p;
+        public final Font font;
     }
 
-    private static Cache fontCache = new Cache();
+
+    // Statics //////////////////////////////////////////////////////////////////////
+
+    private static final Freetype freetype = new Freetype();
+    private static Cache sizeCache = new Cache(100);
+    static final Queue glyphsToBeRendered = new Queue(255);
+    private static Cache fontCache = new Cache(100);
     public static Font getFont(Res res, int pointsize) {
         Font ret = (Font)fontCache.get(res, new Integer(pointsize));
         if (ret == null) fontCache.put(res, new Integer(pointsize), ret = new Font(res, pointsize));
         return ret;
     }
 
+
+    // Methods //////////////////////////////////////////////////////////////////////
+
     /**
      *  If the glyphs of <code>text</code> are not yet loaded, spawn a
      *  Task to load them and invoke callback.
@@ -44,21 +59,19 @@ public class Font {
         for(int i=0; i<text.length(); i++) {
             final char c = text.charAt(i);
             Glyph g = glyphs[c];
-            if (g == null) glyphsToBeRendered.prepend(g = new Glyph(c));
+            if (g == null) glyphsToBeRendered.prepend(g = new Glyph(c, this));    // prepend so they are high priority
             if (g.p == null) {
                 glyphsToBeRendered.prepend(g);
                 encounteredUnrenderedGlyph = true;
             } else if (!encounteredUnrenderedGlyph) {
                 if (pb != null && g.p != null)
-                    pb.drawPictureAlphaOnly(g.p, x + width, y + g.font.max_ascent - g.baseline,
-                                            cx1, cy1, cx2, cy2, textcolor);
+                    pb.drawPictureAlphaOnly(g.p, x + width, y + g.font.max_ascent - g.baseline, cx1, cy1, cx2, cy2, textcolor);
                 width += g.advance;
                 height = java.lang.Math.max(height, max_ascent + max_descent);
             }
         }
         
-        // FIXME: be cleaner here
-        if (encounteredUnrenderedGlyph) Scheduler.add(new Scheduler.Task() { public void perform() {
+        if (encounteredUnrenderedGlyph && callback != null) Scheduler.add(new Scheduler.Task() { public void perform() {
             for(int i=0; i<text.length(); i++) {
                 Glyph g = glyphs[text.charAt(i)];
                 if (g == null || g.p == null) { Scheduler.add(this); return; }
@@ -66,34 +79,28 @@ public class Font {
             callback.perform();
         }});
     
-        if (!used) for(int i=32; i<128; i++) glyphsToBeRendered.append(glyphs[i] = new Glyph((char)i));
-        if (!used || encounteredUnrenderedGlyph) { System.out.println("foo!"); Scheduler.add(glyphRenderingTask); }
-        used = true;
-        return ((long)width << 16) | (long)height;
+        if (!latinCharsPreloaded) for(int i=32; i<128; i++) glyphsToBeRendered.append(glyphs[i] = new Glyph((char)i, this));
+        if (!latinCharsPreloaded || encounteredUnrenderedGlyph) Scheduler.add(glyphRenderingTask);
+        latinCharsPreloaded = true;
+        return encounteredUnrenderedGlyph ? -1 : (((long)width << 16) | (long)height);
     }
 
-
-    public class Glyph {
-        public char c;
-        public int baseline;       // within the picture, this is the y-coordinate of the baseline
-        public int advance;        // amount to increment the x-coordinate
-        public Picture p;
-        public final Font font;
-        public Glyph(char c) { this.c = c; font = Font.this; }
+    public int textwidth(String s) { return (int)(textsize(s) >>> 16L); }
+    public int textheight(String s) { return (int)(textsize(s) & 0xffffffffL); }
+    public long textsize(String s) {
+        Long l = (Long)sizeCache.get(s);
+        if (l != null) return ((Long)l).longValue();
+        long ret = rasterizeGlyphs(s, null, 0, 0, 0, 0, 0, 0, 0, null);
+        if (ret != -1) sizeCache.put(s, new Long(ret));
+        return ret == -1 ? 0 : ret;
     }
 
-    private static final Freetype freetype = new Freetype();
-    static final Queue glyphsToBeRendered = new Queue(255);
     static final Scheduler.Task glyphRenderingTask = new Scheduler.Task() { public void perform() {
         Glyph g = (Glyph)glyphsToBeRendered.remove(false);
         if (g == null) return;
         if (g.p != null) { perform(); return; }
         Log.log(Glyph.class, "rendering glyph " + g.c);
-        try {
-            freetype.renderGlyph(g);
-        } catch (IOException e) {
-            Log.log(Freetype.class, e);
-        }
+        try { freetype.renderGlyph(g); } catch (IOException e) { Log.log(Freetype.class, e); }
         Scheduler.add(this);
     } };
 }