From: megacz Date: Fri, 30 Jan 2004 07:40:45 +0000 (+0000) Subject: 2003/11/03 00:08:26 X-Git-Tag: RC3~387 X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=214fe5c02d3f0fb9c3c61128a100e6a3cb01668e;p=org.ibex.core.git 2003/11/03 00:08:26 darcs-hash:20040130074045-2ba56-e68dd1eb1c63ce9e3f6cecfe5addb9f4d15c9b9e.gz --- diff --git a/src/org/xwt/Box.java.pp b/src/org/xwt/Box.java.pp index c58eebc..7f8f46e 100644 --- a/src/org/xwt/Box.java.pp +++ b/src/org/xwt/Box.java.pp @@ -112,8 +112,7 @@ public final class Box extends JS.Scope { public LENGTH maxwidth = MAX_LENGTH; public LENGTH maxheight = MAX_LENGTH; private String text = null; - private Res font = null; - private int fontsize = 10; + private Font font = null; private LENGTH textwidth = 0; private LENGTH textheight = 0; @@ -454,15 +453,15 @@ public final class Box extends JS.Scope { for(int y = globaly; y < clipy + cliph; y += image.getHeight()) buf.drawPicture(image, x, y, clipx, clipy, clipx + clipw, clipy + cliph); - if (text != null && !text.equals("")) - Glyph.rasterizeGlyphs(font, fontsize, text, buf, textcolor, globalx, globaly, clipx, clipy, clipw + clipx, clipy + cliph, - new Callback() { public Object call(Object arg) { - Box.this.dirty(); - Box b = Box.this; - MARK_FOR_REFLOW_b; - b.dirty(); - return null; - }}); + if (text != null && !text.equals("") && font != null) // FIXME + font.rasterizeGlyphs(text, buf, textcolor, + globalx, globaly, clipx, clipy, clipw + clipx, clipy + cliph, + new Scheduler.Task() { public void perform() { + Box.this.dirty(); + Box b = Box.this; + MARK_FOR_REFLOW_b; + b.dirty(); + }}); if (path != null) { if (rtransform == null) rpath = null; @@ -518,7 +517,7 @@ 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) { + public void put(int i, Object value, TailCall tail) { if (i < 0) return; Trap t = value == null ? (Trap)get("childremoved", Trap.class) : (Trap)get("childadded", Trap.class); @@ -528,17 +527,18 @@ public final class Box extends JS.Scope { } if (redirect == null) { - if (t != null) t.perform(value); + if (t != null) t.perform(value, tail); 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; - redirect.put(i, value); - if (t != null) t.perform(value); + // FIXME: what if both of them want a tailcall? + redirect.put(i, value, tail); + if (t != null) t.perform(value, tail); } else if (value == null) { if (i >= 0 && i < numChildren()) { Box b = getChild(i); b.remove(); - if (t != null) t.perform(b); + if (t != null) t.perform(b, tail); } } else { Box newnode = (Box)value; @@ -600,12 +600,12 @@ public final class Box extends JS.Scope { MARK_FOR_REFLOW_this; newnode.dirty(); - if (t != null) t.perform(b); + if (t != null) t.perform(b, tail); } } public Object get(Object key, Object key2) { return super.get(key, key2); } - public void put(Object key, Object key2, Object val) { super.put(key, key2, val); } + public void put2(Object key, Object key2, Object val) { super.put2(key, key2, val); } public Object get_(Object name) { return super.get(name); } public Object get(Object name) { return get(name, false); } @@ -618,7 +618,7 @@ public final class Box extends JS.Scope { // See if we're triggering a trap Trap t = ignoretraps ? (Trap)null : (Trap)get(name, Trap.class); - if (t != null) return t.perform(); + if (t != null) { t.perform(); return null; } // Check for a special handler SpecialBoxProperty gph = (SpecialBoxProperty)SpecialBoxProperty.specialBoxProperties.get(name); @@ -647,17 +647,15 @@ 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, false); } - public void put(Object name_, Object value, boolean ignoretraps) { - if (name_ instanceof Number) { put(((Number)name_).intValue(), value); return; } + 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; } String name = name_.toString(); if (!ignoretraps) { Trap t = (Trap)get(name, Trap.class); - if (t != null) { - t.perform(value); - return; - } + if (t != null) { t.perform(value, tail); return; } } SpecialBoxProperty gph = (SpecialBoxProperty)SpecialBoxProperty.specialBoxProperties.get(name); @@ -729,7 +727,9 @@ public final class Box extends JS.Scope { // note that JavaScript box[0] will invoke put(int i), not put(String s) if (oldparent != null) { Trap t = (Trap)oldparent.get("childremoved", Trap.class); - if (t != null) t.perform(this); + + // FIXME!! + //if (t != null) t.perform(this, tail); } } @@ -808,16 +808,14 @@ public final class Box extends JS.Scope { public void recompute_font() { if (text == null) { textwidth = textheight = 0; return; } - if (font == null) { /* FIXME */ } - long widthheight = Glyph.rasterizeGlyphs(font, fontsize, text, null, textcolor, 0, 0, 0, 0, 0, 0, - new Callback() { public Object call(Object arg) { - Box b = Box.this; - recompute_font(); - MARK_FOR_REFLOW_b; - b.dirty(); - return null; - } }); - if (widthheight == -1) return; + if (font == null) { /* FIXME */ return; } + long widthheight = font.rasterizeGlyphs(text, null, textcolor, 0, 0, 0, 0, 0, 0, + new Scheduler.Task() { public void perform() { + Box b = Box.this; + recompute_font(); + MARK_FOR_REFLOW_b; + b.dirty(); + } }); textwidth = (int)((widthheight & 0xffff0000) >> 16); textheight = (int)(widthheight & 0x0000ffff); MARK_FOR_REFLOW_this; @@ -897,15 +895,18 @@ public final class Box extends JS.Scope { specialBoxProperties.put("fill", new ColorBoxProperty() { public void put(final Box b, final Object value) { if (value == null || !(value instanceof Res)) super.put(b, value); - else Picture.fromRes((Res)value, new Callback() { public Object call(Object pic) { - if (pic == b.image) return null; - b.image = (Picture)pic; - b.minwidth = b.image.getWidth(); - b.minheight = b.image.getHeight(); - MARK_FOR_REFLOW_b; - b.dirty(); - return null; - } }); + else { + Callback callback = new Callback() { public Object call(Object pic) { + b.image = (Picture)pic; + b.minwidth = b.image.getWidth(); + b.minheight = b.image.getHeight(); + MARK_FOR_REFLOW_b; + b.dirty(); + return null; + } }; + Picture pic = Picture.fromRes((Res)value, callback); + if (pic != null) callback.call(pic); + } } public int getColor(Box b) { return b.fillcolor; } public void putColor(Box b, int argb) { b.fillcolor = argb; } @@ -1011,7 +1012,8 @@ public final class Box extends JS.Scope { public Object get(Box b) { return b.font; } public void put(Box b, Object value) { // FIXME: translate value into a resource if it is a string - b.font = value == null ? null : (Res)value; + b.font = value == null ? null : + Font.getFont((Res)value, b.font == null ? 10 : b.font.pointsize); // FIXME MARK_FOR_REFLOW_b; b.flags |= FONT_CHANGED_FLAG; b.dirty(); @@ -1021,8 +1023,9 @@ public final class Box extends JS.Scope { specialBoxProperties.put("fontsize", new SpecialBoxProperty() { public Object get(Box b) { return b.font; } public void put(Box b, Object value) { - if (b.fontsize == stoi(value)) return; - b.fontsize = stoi(value); + if (b.font != null && b.font.pointsize == stoi(value)) return; + b.font = value == null ? null : + Font.getFont(b.font == null ? null : b.font.res, stoi(value)); // FIXME MARK_FOR_REFLOW_b; b.flags |= FONT_CHANGED_FLAG; b.dirty(); diff --git a/src/org/xwt/Main.java b/src/org/xwt/Main.java index 3c79fd8..bc26f96 100644 --- a/src/org/xwt/Main.java +++ b/src/org/xwt/Main.java @@ -91,16 +91,13 @@ public class Main { Picture.fromRes((Res)Main.builtin.get("org/xwt/builtin/scar.png"), new Callback() { public Object call(Object arg) { scarImage = (Picture)arg; - Scheduler.add(new Scheduler.Task() { - public Object call(Object args) { - Template.getTemplate(((Res)final_rr.get(initialTemplate))).apply(new Box(), null, xwt); - return null; - } - }); + Scheduler.add(new Scheduler.Task() { public void perform() { + Template.getTemplate(((Res)final_rr.get(initialTemplate))).apply(new Box(), null, xwt); + } }); return null; } }); - new Thread() { public void run() { Scheduler.run(); } }.start(); + new Thread() { public void run() { Scheduler.singleton.run(); } }.start(); Platform.running(); } diff --git a/src/org/xwt/Picture.java b/src/org/xwt/Picture.java index a4cc602..38f9c0a 100644 --- a/src/org/xwt/Picture.java +++ b/src/org/xwt/Picture.java @@ -33,28 +33,32 @@ public abstract class Picture { private static Cache cache = new Cache(); private static GIF gif = new GIF(); + // FIXME: return a Picture that gets filled in later /** turns a resource into a Picture.Source and passes it to the callback */ - public static void fromRes(final Res r, final Callback callback) { + public static Picture fromRes(final Res r, final Callback callback) { Picture ret = (Picture)cache.get(r); - if (ret != null) { - callback.call(ret); - return; - } - + if (ret != null) return ret; try { - // FIXME: put self in background - PushbackInputStream pbis = new PushbackInputStream(r.getInputStream()); - int c = pbis.read(); - pbis.unread(c); - if (c == 'G') ret = gif.fromInputStream(pbis, r.getDescriptiveName()); - else if (c == 137) ret = new PNG().fromInputStream(pbis, r.getDescriptiveName()); - else if (c == 0xff) ret = Platform.decodeJPEG(pbis, r.getDescriptiveName()); - else throw new JS.Exn("couldn't figure out image type from first byte"); - cache.put(r, ret); - ret.res = r; - callback.call(ret); + Platform.inputStreamToByteArray(r.getInputStream(), new Callback() { public Object call(Object o) { + try { + Picture ret = null; + byte[] b = (byte[])o; + InputStream pbis = new ByteArrayInputStream(b); + if ((b[0] & 0xff) == 'G') ret = gif.fromInputStream(pbis, r.getDescriptiveName()); + else if ((b[0] & 0xff) == 137) ret = new PNG().fromInputStream(pbis, r.getDescriptiveName()); + else if ((b[0] & 0xff) == 0xff) ret = Platform.decodeJPEG(pbis, r.getDescriptiveName()); + else throw new JS.Exn("couldn't figure out image type from first byte"); + ret.res = r; + cache.put(r, ret); + callback.call(ret); + } catch (Exception e) { + Log.log(Picture.class, e); + } + return null; + }}); } catch (Exception e) { Log.log(Picture.class, e); } + return null; } } diff --git a/src/org/xwt/Platform.java b/src/org/xwt/Platform.java index 5b1f0ac..f8937ca 100644 --- a/src/org/xwt/Platform.java +++ b/src/org/xwt/Platform.java @@ -317,6 +317,25 @@ public class Platform { return cachedProxyInfo; } + + /** returns a Scheduler instance; used to implement platform-specific schedulers */ + protected Scheduler _getScheduler() { return new Scheduler(); } + public static Scheduler getScheduler() { return platform._getScheduler(); } + + /** read an input stream into a byte array and invoke callback when ready */ + protected void _inputStreamToByteArray(final InputStream is, final Callback c) { + new java.lang.Thread() { + public void run() { + try { + final byte[] b = InputStreamToByteArray.convert(is); + Scheduler.add(new Scheduler.Task() { public void perform() { c.call(b); }}); + } catch (IOException e) { + Log.log(Platform.class, e); + } + } + }.start(); + } + public static void inputStreamToByteArray(InputStream is, Callback c) { platform._inputStreamToByteArray(is, c); } public static void running() { platform._running(); } public void _running() { new Semaphore().block(); } diff --git a/src/org/xwt/Res.java b/src/org/xwt/Res.java index 196bb2c..ea503b5 100644 --- a/src/org/xwt/Res.java +++ b/src/org/xwt/Res.java @@ -219,13 +219,11 @@ public abstract class Res extends JS { public int read(byte[] b, int off, int len) throws IOException { int ret = super.read(b, off, len); if (ret != 1) bytesDownloaded += ret; - Scheduler.add(new Scheduler.Task() { public Object call(Object arg) { + Scheduler.add(new Scheduler.Task() { public void perform() { JS.Array args = new JS.Array(); args.addElement(new Integer(bytesDownloaded)); args.addElement(new Integer(is instanceof KnownLength ? ((KnownLength)is).getLength() : 0)); - // FIXME - // new JS.Thread(callback, callbackScope).resume(); - return null; + new JS.Thread(callback, null, args).resume(); } }); return ret; } diff --git a/src/org/xwt/Scheduler.java b/src/org/xwt/Scheduler.java index 95fd6bf..2cb7892 100644 --- a/src/org/xwt/Scheduler.java +++ b/src/org/xwt/Scheduler.java @@ -5,24 +5,22 @@ import java.util.*; import org.xwt.js.*; import org.xwt.util.*; -// FEATURE: reimplement Watcher /** Implements cooperative multitasking */ public class Scheduler { - private static Scheduler singleton = new Scheduler(); - public static void run() { singleton.do_run(); } + public static final Scheduler singleton = Platform.getScheduler(); protected Scheduler() { } - public static abstract class Task implements Callback { public abstract Object call(Object o); } - - private static Queue runnable = new Queue(50); + public static abstract class Task { public abstract void perform(); } + protected static Queue runnable = new Queue(50); public static void add(Task t) { singleton.runnable.append(t); } - public void do_run() { + public void run() { while(true) { Task t = (Task)runnable.remove(true); try { - t.call(null); + t.perform(); + // FIXME: be smarter about this for(int i=0; i 0) return cascade(); - JS.Thread.current().setTailCall(f, new TrapArgs(this)); - return null; - } catch (Exception e) { - Log.log(this, "Exception thrown from within trap: " + e); - return null; - } + if (f.getNumFormalArgs() > 0) return cascade(); + else return new JS.TailCall().set(f, new TrapArgs(this)); } - private static JS.CompiledFunction cascadeHelper = null; - private static String cascadeHelperText = - "return function(q) { var ret = arguments.doTrap;" + - "if (ret != false && !arguments.didCascade) arguments.cascade = q; };"; - static { - try { - cascadeHelper = JS.parse("cascadeHelper", 1, new StringReader(cascadeHelperText)); - cascadeHelper = (JS.CompiledFunction)new JS.Thread(cascadeHelper).resume(); - } catch (Exception e) { - Log.log(Trap.class, e); - } + public Object cascade() { + if (next != null) return next.perform(); + else return trapee.get(name, true); } - public void perform(Object val) { - try { - if (f.getNumFormalArgs() == 0) cascade(val); - else JS.Thread.current().setTailCall(cascadeHelper, new TrapArgs(this, val)); - } catch (Exception e) { - Log.log(this, "Exception thrown from within trap: " + e); - e.printStackTrace(); - } + // Write Traps ////////////////////////////////////////////////////////////////////// + + public void perform(Object val, JS.TailCall tail) { + if (f.getNumFormalArgs() == 0) cascade(val, tail); + else tail.set(cascadeHelper, new TrapArgs(this, val)); } - public Object cascade() { - if (next != null) { next.perform(); return null; } - return trapee.get(name, true); + public void cascade(Object val, JS.TailCall tail) { + if (next != null) next.perform(val, tail); + else trapee.put(name, val, tail, true); } - public void cascade(Object val) { - if (next != null) next.perform(val); - trapee.put(name, val, true); - } + // Args /////////////////////////////////////////////////////////////////////////// private static class TrapArgs extends JS.Array { private Trap t; @@ -147,16 +132,16 @@ public class Trap { public TrapArgs(Trap t) { this.t = t; } public TrapArgs(Trap t, Object value) { this.t = t; addElement(value); } - public void put(Object key, Object val) { - if (key.equals("cascade")) { cascadeHappened = true; t.cascade(val); } - else super.put(key, val); + public void put(Object key, Object val, JS.TailCall tail) { + if (key.equals("cascade")) { cascadeHappened = true; t.cascade(val, tail); } + else super.put(key, val, (JS.TailCall)tail); } public Object get(Object key) { // common case if(!(key instanceof String)) return super.get(key); if (key.equals("trapee")) return t.trapee; - if (key.equals("doTrap")) { JS.Thread.current().setTailCall(t.f, this); return null; } + if (key.equals("doTrap")) return new JS.TailCall().set(t.f, this); if (key.equals("didCascade")) return cascadeHappened ? Boolean.TRUE : Boolean.FALSE; if (key.equals("trapname")) return t.name; if (key.equals("cascade")) return t.cascade(); diff --git a/src/org/xwt/XWT.java b/src/org/xwt/XWT.java index c5f7a13..99b158f 100644 --- a/src/org/xwt/XWT.java +++ b/src/org/xwt/XWT.java @@ -52,9 +52,8 @@ public final class XWT extends JS.Obj { public void put(Object name, final Object value) { if (name.equals("thread") && value != null && (value instanceof JS.Callable || value instanceof JS.CompiledFunction)) { - Scheduler.add(new Scheduler.Task() { public Object call(Object arg) { + Scheduler.add(new Scheduler.Task() { public void perform() { new JS.Thread((CompiledFunction)value).resume(); - return null; } }); } else if (name.equals("clipboard")) Platform.setClipBoard(value.toString()); else if (name.equals("frame")) Platform.createSurface((Box)value, true, true); @@ -238,13 +237,9 @@ public final class XWT extends JS.Obj { public static void sleep(final int i) { final JS.Thread jsthread = JS.Thread.current(); final long currentTime = System.currentTimeMillis(); - final Scheduler.Task task = new Scheduler.Task() { public Object call(Object arg) { - if (System.currentTimeMillis() - currentTime < i) { - Scheduler.add(this); - } else { - jsthread.resume(); - } - return null; + final Scheduler.Task task = new Scheduler.Task() { public void perform() { + if (System.currentTimeMillis() - currentTime < i) Scheduler.add(this); + else jsthread.resume(); } }; jsthread.pause(); Scheduler.add(task); diff --git a/src/org/xwt/js/CompiledFunctionImpl.java b/src/org/xwt/js/CompiledFunctionImpl.java index 2c69e1d..90f0322 100644 --- a/src/org/xwt/js/CompiledFunctionImpl.java +++ b/src/org/xwt/js/CompiledFunctionImpl.java @@ -102,17 +102,6 @@ class CompiledFunctionImpl extends JS.Obj implements ByteCodes, Tokens { try { if (cx.paused) return null; cx.bind(); - if (cx.tailCallFunction != null) { - cx.stack.pop(); // discard actual return value - cx.pc -= 2; - cx.stack.push(new CallMarker(cx)); - cx.stack.push(cx.tailCallArgs); - cx.currentCompiledFunction = cx.tailCallFunction; - cx.tailCallFunction = null; - cx.tailCallArgs = null; - cx.scope = new FunctionScope("unknown", cx.currentCompiledFunction.parentScope); - cx.pc = 0; - } if (cx.currentCompiledFunction == null) return cx.stack.pop(); if (cx.pc >= ((CompiledFunctionImpl)cx.currentCompiledFunction).size) return cx.stack.pop(); String label = null; @@ -245,8 +234,18 @@ class CompiledFunctionImpl extends JS.Obj implements ByteCodes, Tokens { throw je("tried to put a value to the " + key + " property on a " + target.getClass().getName()); if (key == null) throw je("tried to assign \"" + (val==null?"(null)":val.toString()) + "\" to the null key"); - ((JS)target).put(key, val); + // FIXME too many allocations here + TailCall tail = new TailCall(); + ((JS)target).put(key, val, tail); cx.stack.push(val); + if (tail.func != null) { + cx.stack.push(new CallMarker(cx)); + cx.stack.push(tail.args); + cx.currentCompiledFunction = tail.func; + cx.scope = new CompiledFunctionImpl.FunctionScope("unknown", tail.func.parentScope); + cx.pc = -1; + break; + } break; } @@ -268,6 +267,14 @@ class CompiledFunctionImpl extends JS.Obj implements ByteCodes, Tokens { ret = Internal.getFromPrimitive(o,v); else if (o instanceof JS) { ret = ((JS)o).get(v); + if (ret instanceof JS.TailCall) { + cx.stack.push(new CallMarker(cx)); + cx.stack.push(((JS.TailCall)ret).args); + cx.currentCompiledFunction = ((JS.TailCall)ret).func; + cx.scope = new CompiledFunctionImpl.FunctionScope("unknown", ((JS.TailCall)ret).func.parentScope); + cx.pc = -1; + break; + } } else throw je("tried to get property " + v + " from a " + o.getClass().getName()); cx.stack.push(ret); @@ -298,6 +305,14 @@ class CompiledFunctionImpl extends JS.Obj implements ByteCodes, Tokens { break; } else { o = ((JS)o).get(method); + if (o instanceof JS.TailCall) { + cx.stack.push(new CallMarker(cx)); + cx.stack.push(((JS.TailCall)o).args); + cx.currentCompiledFunction = ((JS.TailCall)o).func; + cx.scope = new CompiledFunctionImpl.FunctionScope("unknown", ((JS.TailCall)o).func.parentScope); + cx.pc = -1; + break; + } } } else { throw new JS.Exn("Tried to call a method on an object that isn't a JS object: " + o); @@ -314,6 +329,14 @@ class CompiledFunctionImpl extends JS.Obj implements ByteCodes, Tokens { } else { ret = ((JS.Callable)o).call(arguments); + if (ret instanceof JS.TailCall) { + cx.stack.push(new CallMarker(cx)); + cx.stack.push(((JS.TailCall)ret).args); + cx.currentCompiledFunction = ((JS.TailCall)ret).func; + cx.scope = new CompiledFunctionImpl.FunctionScope("unknown", ((JS.TailCall)ret).func.parentScope); + cx.pc = -1; + break; + } } cx.stack.push(ret); break;