void renderText(int x, int y, int clipx, int clipy, int clipw, int cliph, PixelBuffer buf) {
for(int i=0; i<text.length(); i++) {
- // FIXME: clipping
- char c = text.charAt(i);
- Glyph g = Glyph.getGlyph(font, fontsize, c);
- if (g.p != null)
- buf.drawPictureAlphaOnly(g.p,
- x,
- y + g.max_ascent - g.baseline + g.max_descent,
- x,
- y + g.max_ascent - g.baseline + g.max_descent,
- x + g.p.getWidth(),
- y + g.max_ascent - g.baseline + g.max_descent + g.p.getHeight(),
- textcolor);
- x += g.advance;
+ final char c = text.charAt(i);
+ Glyph g = Glyph.getCachedGlyph(font, fontsize, c);
+ if (g != null) {
+ int top = y + g.max_ascent - g.baseline + g.max_descent;
+ if (g.p != null)
+ buf.drawPictureAlphaOnly(g.p, x, top,
+ clipx, clipy, clipx + clipw, clipy + cliph, textcolor);
+ x += g.advance;
+ } else {
+ final int fontsize_final = fontsize;
+ final Res font_final = font;
+ ThreadMessage.newthread(new JS.Callable() {
+ public Object call(JS.Array args) {
+ Glyph.renderGlyph(font_final, fontsize_final, c);
+ recompute_font();
+ Box b = Box.this; MARK_FOR_REFLOW_b;
+ dirty();
+ return null;
+ } });
+ return;
+ }
}
}
textheight = 0;
if (text == null) return;
for(int i=0; i<text.length(); i++) {
- Glyph g = Glyph.getGlyph(font, fontsize, text.charAt(i));
- textwidth += g.advance;
- textheight = g.max_ascent;
+ Glyph g = Glyph.getCachedGlyph(font, fontsize, text.charAt(i));
+ if (g == null) {
+ final int fontsize_final = fontsize;
+ final Res font_final = font;
+ final char c = text.charAt(i);
+ ThreadMessage.newthread(new JS.Callable() {
+ public Object call(JS.Array args) {
+ Glyph.renderGlyph(font_final, fontsize_final, c);
+ recompute_font();
+ Box b = Box.this; MARK_FOR_REFLOW_b;
+ dirty();
+ return null;
+ } });
+ } else {
+ textwidth += g.advance;
+ textheight = g.max_ascent;
+ }
}
} catch (Exception e) {
Log.log(this, e);
// k1=font.res k2=(c << 16 | pointsize)
private static Cache glyphCache = new Cache();
- public static Glyph getGlyph(Res res, int pointsize, char c) {
- Glyph ret = (Glyph)glyphCache.get(res, new Integer((((int)c) << 16) | pointsize));
- if (ret != null) return ret;
-
- ThreadMessage.fakeBackground = true;
- // FEATURE: be smarter here
- if (c >= 32 && c < 127) Freetype.renderGlyphs(res, pointsize, 32, 126, glyphCache);
- else Freetype.renderGlyphs(res, pointsize, (int)c, (int)c, glyphCache);
- ThreadMessage.fakeBackground = false;
-
- ret = (Glyph)glyphCache.get(res, new Integer((((int)c) << 16) | pointsize));
- if (ret != null) return ret;
- throw new JS.Exn("error rendering glyph " + c + "; glyph is null");
+ public static Glyph getCachedGlyph(Res res, int pointsize, char c) {
+ return (Glyph)glyphCache.get(res, new Integer((((int)c) << 16) | pointsize));
+ }
+ public static void renderGlyph(Res res, int pointsize, char c) {
+ if (!ThreadMessage.suspendThread())
+ throw new RuntimeException("attempt to perform background-only operation in a foreground thread");
+ synchronized(res) {
+ // FEATURE: be smarter here
+ if ((Glyph)glyphCache.get(res, new Integer((((int)c) << 16) | pointsize)) != null) return;
+ Log.log(Freetype.class, "rendering glyphs for font " + res.getDescriptiveName());
+ if (c >= 32 && c < 127) Freetype.renderGlyphs(res, pointsize, 32, 126, glyphCache);
+ else Freetype.renderGlyphs(res, pointsize, (int)c, (int)c, glyphCache);
+ if ((Glyph)glyphCache.get(res, new Integer((((int)c) << 16) | pointsize)) == null)
+ throw new JS.Exn("error rendering glyph " + c + "; glyph is null");
+ }
+ ThreadMessage.resumeThread();
}
}
public static String originHost = null;
public static String origin = null;
- public static final Res builtin = new Res.Zip(new Res() {
- public InputStream getInputStream(String path) { return Platform.getBuiltinInputStream(); } });
+ public static final Res builtin = new Res.Builtin();
public static Picture scarImage = null;
public static void printUsage() {
static boolean alreadyDetectedProxy = false;
/** the result of proxy autodetection */
- static HTTP.Proxy cachedProxyInfo = null;
+ static org.xwt.HTTP.Proxy cachedProxyInfo = null;
/** the current build */
public static String build = "unknown";
}
/** detects proxy settings */
- protected synchronized HTTP.Proxy _detectProxy() { return null; }
- public static synchronized HTTP.Proxy detectProxy() {
+ protected synchronized org.xwt.HTTP.Proxy _detectProxy() { return null; }
+ public static synchronized org.xwt.HTTP.Proxy detectProxy() {
if (cachedProxyInfo != null) return cachedProxyInfo;
if (alreadyDetectedProxy) return null;
alreadyDetectedProxy = true;
if (Log.on) Log.log(Platform.class, "attempting environment-variable DNS proxy detection");
- cachedProxyInfo = HTTP.Proxy.detectProxyViaManual();
+ cachedProxyInfo = org.xwt.HTTP.Proxy.detectProxyViaManual();
if (cachedProxyInfo != null) return cachedProxyInfo;
if (Log.on) Log.log(Platform.class, "attempting " + platform.getClass().getName() + " proxy detection");
}
}
+ /** the Builtin resource */
+ public static class Builtin extends Res {
+ public Builtin() { };
+ public String getDescriptiveName() { return "[builtin]"; }
+ public InputStream getInputStream(String path) throws IOException {
+ if (!path.equals("")) throw new IOException("the builtin resource has no subresources");
+ return Platform.getBuiltinInputStream();
+ }
+ }
+
/** what you get when you reference a subresource */
public static class Ref extends Res {
Res parent;
Ref(Res parent, Object key) { this.parent = parent; this.key = key; }
public String getDescriptiveName() {
String pdn = parent.getDescriptiveName();
- return pdn.equals("") ? key.toString() : (pdn + "." + key.toString());
+ if (pdn.equals("")) return key.toString();
+ if (!pdn.endsWith("!")) pdn += ".";
+ return pdn + key.toString();
}
public Res addExtension(String extension) {
return (key instanceof String && ((String)key).endsWith(extension)) ? this : new Ref(parent, key + extension);
*/
public class ThreadMessage extends Thread implements Message {
- public static boolean fakeBackground = false;
-
private volatile static int threadcount = 0;
/** the JavaScript function that we are executing */
/** attempts to put this thread into the background to perform a blocking operation; returns false if unable to do so */
public static boolean suspendThread() {
- if (fakeBackground) return true;
// put ourselves in the background
Thread thread = Thread.currentThread();
if (!(thread instanceof ThreadMessage)) {
/** re-enqueues this thread */
public static void resumeThread() {
- if (fakeBackground) return;
ThreadMessage mythread = (ThreadMessage)Thread.currentThread();
Message.Q.add(mythread);
mythread.setPriority(Thread.NORM_PRIORITY);