b.dirty();
} });
+ specialBoxProperties.put("transform", new SpecialBoxProperty() {
+ 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;
+ MARK_FOR_REFLOW_b;
+ b.flags |= FONT_CHANGED_FLAG;
+ b.dirty();
+ } });
+
specialBoxProperties.put("fontsize", new SpecialBoxProperty() {
public Object get(Box b) { return b.font; }
public void put(Box b, Object value) {
b.dirty();
} });
+ specialBoxProperties.put("strokewidth", new SpecialBoxProperty() {
+ public Object get(Box b) { return b.strokewidth; }
+ public void put(Box b, Object value) {
+ if (b.strokewidth == stoi(value)) return;
+ b.strokewidth = stoi(value);
+ b.dirty();
+ } });
+
specialBoxProperties.put("thisbox", new SpecialBoxProperty() {
public Object get(Box b) { return b; }
public void put(Box b, Object value) {
public static Res stringToRes(String url) { return stringToRes(url, false); }
public static Res stringToRes(String url, boolean permitLocalFilesystem) {
if (url.indexOf('!') != -1)
- return (Res)(new Zip(stringToRes(url.substring(0, url.lastIndexOf('!')))).get(url.substring(url.lastIndexOf('!') + 1)));
+ return (Res)(new Zip(stringToRes(url.substring(0, url.lastIndexOf('!')))).
+ get(url.substring(url.lastIndexOf('!') + 1)));
if (url.startsWith("http://")) return new HTTP(url);
if (url.startsWith("https://")) return new HTTP(url);
if (url.startsWith("file:") && permitLocalFilesystem) return new File(url.substring(5));
throw new JS.Exn("invalid resource specifier " + url);
}
+ /** subclass from this if you want a CachedInputStream for each path */
+ public static abstract class CachedRes extends Res {
+ private Hash cachedInputStreams = new Hash();
+ abstract InputStream _getInputStream(String path) throws IOException;
+ public final InputStream getInputStream(String path) throws IOException {
+ CachedInputStream cis = (CachedInputStream)cachedInputStreams.get(path);
+ if (cis == null) {
+ cis = new CachedInputStream(_getInputStream(path));
+ cachedInputStreams.put(path, cis);
+ }
+ return cis.getInputStream();
+ }
+ }
+
/** HTTP or HTTPS resource */
- public static class HTTP extends Res {
+ public static class HTTP extends CachedRes {
private String url;
HTTP(String url) { this.url = url; }
- public InputStream getInputStream(String path) throws IOException { return new org.xwt.HTTP(url + path).GET(); }
+ public InputStream _getInputStream(String path) throws IOException {
+ return new org.xwt.HTTP(url + path).GET(); }
}
/** byte arrays */
--- /dev/null
+package org.xwt.util;
+import java.io.*;
+
+/**
+ * Wraps around an InputStream, caching the stream in a byte[] as it
+ * is read and permitting multiple simultaneous readers
+ */
+public class CachedInputStream {
+
+ boolean filling = false; ///< true iff some thread is blocked on us waiting for input
+ boolean eof = false; ///< true iff end of stream has been reached
+ byte[] cache = new byte[1024 * 128];
+ int size = 0;
+ final InputStream is;
+
+ public CachedInputStream(InputStream is) { this.is = is; }
+ public InputStream getInputStream() { return new SubStream(); }
+
+ public void grow(int newLength) {
+ if (newLength < cache.length) return;
+ byte[] newCache = new byte[cache.length + 2 * (newLength - cache.length)];
+ System.arraycopy(cache, 0, newCache, 0, size);
+ cache = newCache;
+ }
+
+ synchronized void fillCache(int howMuch) throws IOException {
+ if (filling) { try { wait(); } catch (InterruptedException e) { }; return; }
+ filling = true;
+ grow(size + howMuch);
+ int ret = is.read(cache, size, howMuch);
+ if (ret == -1) eof = true;
+ else size += ret;
+ filling = false;
+ notifyAll();
+ }
+
+ private class SubStream extends InputStream {
+ int pos = 0;
+ public int available() { return Math.max(0, size - pos); }
+ public long skip(long n) throws IOException { pos += (int)n; return n; } // FEATURE: don't skip past EOF
+ public int read() throws IOException { // FEATURE: be smarter here
+ byte[] b = new byte[1];
+ int ret = read(b, 0, 1);
+ return ret == -1 ? -1 : b[0];
+ }
+ public int read(byte[] b, int off, int len) throws IOException {
+ synchronized(CachedInputStream.this) {
+ while (pos >= size && !eof) fillCache(pos + len - size);
+ if (eof && pos == size) return -1;
+ int count = Math.min(size - pos, len);
+ System.arraycopy(cache, pos, b, off, count);
+ return count;
+ }
+ }
+ }
+}