2003/11/03 05:28:30
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:40:49 +0000 (07:40 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:40:49 +0000 (07:40 +0000)
darcs-hash:20040130074049-2ba56-fa4930ffbfd61f94af88f20c9b3d59d76d015ff1.gz

Makefile
src/org/xwt/Box.java.pp
src/org/xwt/Font.java [new file with mode: 0644]

index d89b329..12dcc02 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -323,3 +323,4 @@ dist-private:
 test: JVM; /System/Library/Frameworks/JavaVM.framework/Versions/1.3.1/Commands/java -jar build/JVM/xwt.jar http://localhost/demo.xwar
 #test: JVM; java -jar build/JVM/xwt.jar http://localhost/demo.xwar
 
+oldcompile: ; CLASSPATH=$$CLASSPATH:lib/libgcj-minimal.jar javac -d build/class `find build/java/ -name \*.java`
index 7f8f46e..473d049 100644 (file)
@@ -517,28 +517,28 @@ public final class Box extends JS.Scope {
      *  INVARIANT: after completion, getChild(min(i, numChildren())) == newnode
      *  WARNING: O(n) runtime, unless i == numChildren()
      */
-    public void put(int i, Object value, TailCall tail) {
-        if (i < 0) return;
+    public Object put(int i, Object value) {
+        if (i < 0) return null;
         Trap t = value == null ? (Trap)get("childremoved", Trap.class) : (Trap)get("childadded", Trap.class);
             
         if (value != null && !(value instanceof Box)) {
             if (Log.on) Log.logJS(this, "attempt to set a numerical property on a box to a non-box");
-            return;
+            return null;
         }
 
         if (redirect == null) {
-            if (t != null) t.perform(value, tail);
+            if (t != null) return t.perform(value);
             else if (Log.on) Log.logJS(this, "attempt to add/remove children to/from a node with a null redirect");
         } else if (redirect != this) {
             Box b = value == null ? (Box)redirect.get(i) : (Box)value;
             // FIXME: what if both of them want a tailcall?
-            redirect.put(i, value, tail);
-            if (t != null) t.perform(value, tail);
+            redirect.put(i, value);
+            if (t != null) return t.perform(value);
         } else if (value == null) {
             if (i >= 0 && i < numChildren()) {
                 Box b = getChild(i);
                 b.remove();
-                if (t != null) t.perform(b, tail);
+                if (t != null) return t.perform(b);
             }
         } else {
             Box newnode = (Box)value;
@@ -547,7 +547,7 @@ public final class Box extends JS.Scope {
             for(Box cur = newnode.parent; cur != null; cur = cur.parent)
                 if (cur.redirect == newnode) {
                     if (Log.on) Log.logJS(this, "attempt to move a box that is the target of a redirect");
-                    return;
+                    return null;
                 }
 
             // check for recursive ancestor violation
@@ -555,7 +555,7 @@ public final class Box extends JS.Scope {
                 if (cur == newnode) {
                     if (Log.on) Log.logJS(this, "attempt to make a node a parent of its own ancestor");
                     if (Log.on) Log.log(this, "box == " + this + "  ancestor == " + newnode);
-                    return;
+                    return null;
                 }
 
             if (numKids > 15 && children == null) convert_to_array();
@@ -600,8 +600,9 @@ public final class Box extends JS.Scope {
             MARK_FOR_REFLOW_this;
             
             newnode.dirty();
-            if (t != null) t.perform(b, tail);
+            if (t != null) return t.perform(b);
         }
+        return null;
     }
     
     public Object get(Object key, Object key2) { return super.get(key, key2); }
@@ -647,21 +648,20 @@ public final class Box extends JS.Scope {
      *  @param rp if this put is being performed via a root proxy, rp is the root proxy.
      */
     public void put_(Object name, Object value) { super.put(name, value); }
-    public void put(Object name, Object value) { put(name, value, null, false); }  // FIXME: correct?
-    public void put(Object name, Object value, TailCall tail) { put(name, value, tail, false); }
-    public void put(Object name_, Object value, TailCall tail, boolean ignoretraps) {
-        if (name_ instanceof Number) { put(((Number)name_).intValue(), value, tail); }
-        if (!(name_ instanceof String)) { super.put(name_,value); return; }
+    public Object put(Object name, Object value) { return put(name, value, false); }
+    public Object put(Object name_, Object value,  boolean ignoretraps) {
+        if (name_ instanceof Number) { return put(((Number)name_).intValue(), value); }
+        if (!(name_ instanceof String)) { return super.put(name_,value); }
         String name = name_.toString();
         if (!ignoretraps) {
             Trap t = (Trap)get(name, Trap.class);
-            if (t != null) { t.perform(value, tail); return; }
+            if (t != null) return t.perform(value);
         }
 
         SpecialBoxProperty gph = (SpecialBoxProperty)SpecialBoxProperty.specialBoxProperties.get(name);
-        if (gph != null) { gph.put(name, this, value); return; }
+        if (gph != null) { gph.put(name, this, value); return null; }
 
-        super.put(name, value);
+        return super.put(name, value);
     }
 
 
diff --git a/src/org/xwt/Font.java b/src/org/xwt/Font.java
new file mode 100644 (file)
index 0000000..b1d9230
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
+package org.xwt;
+import org.xwt.translators.*;
+import org.xwt.util.*;
+import org.xwt.js.*;
+import java.util.*;
+
+public class Font {
+
+    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;
+
+    private Font(Res res, int pointsize) {
+        this.res = res;
+        this.pointsize = pointsize;
+    }
+
+    private static Cache fontCache = new Cache();
+    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;
+    }
+
+    /**
+     *  If the glyphs of <code>text</code> are not yet loaded, spawn a
+     *  Task to load them and invoke callback.
+     *
+     *  returns the width (in the high-order int) and height (in the
+     *  low-order int) of the string's rasterization, or -1 if some
+     *  glyphs are not loaded.
+     */
+    public long rasterizeGlyphs(final String text, PixelBuffer pb, int textcolor,
+                                int x, int y, int cx1, int cy1, int cx2, int cy2,
+                                final Scheduler.Task callback) {
+        boolean encounteredUnrenderedGlyph = false;
+        int width = 0;
+        int height = 0;
+        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.p == null) {
+                glyphsToBeRendered.prepend(g);
+                Scheduler.add(glyphRenderingTask);
+                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);
+                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() {
+            for(int i=0; i<text.length(); i++) {
+                Glyph g = glyphs[text.charAt(i)];
+                if (g == null || g.p == null) { Scheduler.add(this); return; }
+            }
+            callback.perform();
+        }});
+    
+        if (!used) for(int i=32; i<128; i++) glyphsToBeRendered.append(glyphs[i] = new Glyph((char)i));
+        used = true;
+        return ((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; }
+    }
+
+    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 || g.p != null) return;
+        Log.log(Glyph.class, "rendering glyph " + g.c);
+        freetype.renderGlyph(g);
+        Scheduler.add(this);
+    } };
+}