From: adam Date: Mon, 12 Apr 2004 07:48:10 +0000 (+0000) Subject: reorganized file layout (part 2: edits) X-Git-Tag: RC4^0 X-Git-Url: http://git.megacz.com/?p=org.ibex.core.git;a=commitdiff_plain;h=8e190fb0ff508ccf4962bbfbf8295a431805c12b reorganized file layout (part 2: edits) darcs-hash:20040412074810-5007d-4ba54bb6fa3b33da53ad47735219dc3051d1d260.gz --- diff --git a/Makefile b/Makefile index 8a452d6..a67c9e5 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ all: Java2 Linux Win32 Darwin Solaris clean: ; rm -rf build; rm .preprocessor dist-clean: - rm -rf .jikes .configure* .install* build .compile .build* + rm -rf .configure* .install* build .compile .build* find upstream -name config.cache -exec rm {} \; test -e upstream/nestedvm && make -C upstream/nestedvm clean rm .install_nestedvm @@ -57,7 +57,7 @@ target_bin_extension_Java2 := jar target_bin_extension := $(target_bin_extension_$(platform)) target_bin := ibex.$(target_bin_extension) -jikes_flags := -nowarn +javac := javac -classpath upstream/bcel-5.1/src/bcel-5.1.jar:build/class -d build/class/ -sourcepath build/java/:upstream/mips:upstream/mips/build:src gcc_optimizations := -Os #gcc_optimizations := -O9 -ffast-math -fomit-frame-pointer -foptimize-sibling-calls #gcc_optimizations += -finline-functions -funroll-loops -ffunction-sections -fdata-sections @@ -114,38 +114,42 @@ java_sources += build/java/org/xwt/mips/UsermodeConstants.java java_classes := $(java_sources:build/java/%.java=build/class/%.class) java_classes += build/class/gnu/regexp/CharUnit.class build/class/gnu/regexp/IntPair.class -build/java/org/xwt/mips/%: .install_nestedvm - mkdir -p build/java/org/xwt/mips - cd build/java/org/xwt/mips; ln -sf ../../../../../upstream/nestedvm/src/org/xwt/mips/* . - cd build/java/org/xwt/mips; ln -sf ../../../../../upstream/nestedvm/build/org/xwt/mips/*.java . - - ### Java Source Files ############################################################################## +build/java/gnu/regexp: .download_gnu.regexp-1.1.4 + mkdir -p $(@D); cd $(@D); ln -sf ../../../upstream/gnu.regexp-1.1.4/src/src/gnu/regexp +build/java/org/xwt/mips: .download_nestedvm + mkdir -p $(@D); cd $(@D); ln -sf ../../../../upstream/nestedvm/src/org/xwt/mips +build/java/org/ibex/crypto: .download_org.ibex.crypto + mkdir -p $(@D); cd $(@D); ln -sf ../../../../upstream/org.ibex.crypto/src/org/ibex/crypto + mkdir -p build/java/org/ibex/net; + cd build/java/org/ibex/net; ln -sf ../../../../../upstream/org.ibex.crypto/src/org/ibex/net/SSL.java + cd build/java/org/ibex/net; ln -sf ../../../../../upstream/org.ibex.crypto/src/org/ibex/net/ssl + ifeq ($(platform),Java2) -.preprocessor: src/org/ibex/util/Preprocessor.java src/org/ibex/util/Vec.java src/gnu/regexp/*.java - @make .jikes +.preprocessor: build/java/gnu/regexp src/org/ibex/util/Preprocessor.java src/org/ibex/util/Vec.java build/java/org/xwt/mips build/java/org/ibex/crypto + @mkdir -p build/class/org/ibex/util build/class/gnu/regexp - ./.jikes $^ -d build/class + $(javac) src/org/ibex/util/Preprocessor.java src/org/ibex/util/Vec.java build/java/gnu/regexp/*.java -d build/class @touch $@ else -.preprocessor: src/org/ibex/util/Preprocessor.java src/org/ibex/util/Vec.java src/gnu/regexp/*.java +.preprocessor: build/java/gnu/regexp src/org/ibex/util/Preprocessor.java src/org/ibex/util/Vec.java build/java/org/xwt/mips build/java/org/ibex/crypto @mkdir -p build/class/org/ibex/util build/class/gnu/regexp - $(gcj) -Isrc -C $^ -d build/class + $(gcj) -Isrc -C src/org/ibex/util/Preprocessor.java src/org/ibex/util/Vec.java build/java/gnu/regexp/*.java -d build/class @touch $@ endif build/cc/%.cc: src/%.c ; @echo linking $@; mkdir -p $(@D); ln -fs `echo $(@D)/ | sed 's_[^/]*//*_../_g'`/$< $@ build/res/%: src/% ; @echo linking $@; mkdir -p $(@D); ln -fs `echo $(@D)/ | sed 's_[^/]*//*_../_g'`/$< $@ build/java/org/ibex/%.java: src/org/ibex/%.java .preprocessor @echo -e "\n\033[1mpreprocessing .java -> .java: $<\033[0m" - mkdir -p `dirname $@`; java -cp build/class org.ibex.util.Preprocessor < $^ > $@ + mkdir -p `dirname $@`; java -cp build/class:build/java org.ibex.util.Preprocessor < $^ > $@ build/java/%.java: src/%.java ; @echo linking $@; mkdir -p $(@D); ln -fs `echo $(@D)/ | sed 's_[^/]*//*_../_g'`/$< $@ ### Java Class Files ############################################################################## -build/class/org/ibex/translators/MIPSApps.class: build/mips/mipsapps.mips .install_nestedvm .jikes - mkdir -p build/java/org/ibex/translators +build/class/org/ibex/util/MIPSApps.class: build/mips/mipsapps.mips .install_nestedvm + mkdir -p build/java/org/ibex/util @echo -e "\n\033[1mtranslating .mips -> .class: $<\033[0m" java -cp upstream/nestedvm/build:upstream/nestedvm/upstream/build/bcel-5.1/bcel-5.1.jar \ org.xwt.mips.Compiler org.ibex.translators.MIPSApps $< -outfile $@ @@ -155,10 +159,10 @@ compile: .compile .compile: .download_nestedvm .download_bcel-5.1 $(java_sources) $(java_classes); touch $@ ifeq ($(platform),Java2) -build/class/%.class: build/java/%.java .preprocessor .jikes +build/class/%.class: build/java/%.java .preprocessor @echo -e "\n\033[1mcompiling .java -> .class: $<\033[0m" mkdir -p build/class - @./.jikes $< -d build/class + @$(javac) $< -d build/class else build/class/%.class: build/java/%.java @echo -e "\n\033[1mcompiling .java -> .class: $<\033[0m" @@ -166,7 +170,7 @@ build/class/%.class: build/java/%.java $(gcj) -I$(bcel_jar) -C -O0 $< -d build/class endif -build/Java2/ibex.jar: .compile build/res/builtin.jar build/class/org/ibex/translators/MIPSApps.class +build/Java2/ibex.jar: .compile build/res/builtin.jar build/class/org/ibex/util/MIPSApps.class @echo -e "\n\033[1marchiving .class -> .jar: build/Java2/ibex.jar\033[0m" mkdir -p build/Java2 echo -e "Manifest-Version: 1.0\nMain-Class: org.ibex.Main\n" > build/Java2/.manifest @@ -286,7 +290,7 @@ endif ### Builtin Resources ############################################################################## -builtin_src := $(shell find src/org/ibex/builtin -name '*.*' \! -name '*.xcf') +builtin_src := $(shell find src/org/ibex/core/builtin -name '*.*' \! -name '*.xcf') build/res/fonts/vera: .download_vera-1.10 mkdir -p build/res/fonts/vera cd build/res/fonts/vera; ln -fs ../../../../upstream/vera-1.10/ttf-bitstream-vera-1.10/Vera.ttf @@ -294,7 +298,7 @@ build/res/fonts/vera: .download_vera-1.10 cd build/res/fonts/vera; ln -fs ../../../../upstream/vera-1.10/ttf-bitstream-vera-1.10/VeraSe.ttf build/res/builtin.jar: $(builtin_src:src/%=build/res/%) build/res/fonts/vera @echo -e "\n\033[1mzipping res/* -> .jar: builtin.jar\033[0m" - cd build/res; $(jar) cf builtin.jar org/ibex/builtin/scar.png fonts + cd build/res; $(jar) cf builtin.jar org/ibex/core/builtin/scar.png fonts build/$(platform)/builtin.o: build/res/builtin.jar @echo -e "\n\033[1mwrapping .jar -> .o: resources.o\033[0m" @mkdir -p $(@D) @@ -316,7 +320,7 @@ build/mips/%.c.o: src/%.c .download_libmspack-20030726 .install_nestedvm -Iupstream/libmspack-20030726/src/mspack \ -c -o $@ $< -build/mips/mipsapps.mips: build/mips/org/ibex/translators/Freetype.c.o build/mips/org/ibex/translators/MSPack.c.o build/mips/org/ibex/translators/main.c.o +build/mips/mipsapps.mips: build/mips/org/ibex/graphics/Freetype.c.o build/mips/org/ibex/util/MSPack.c.o make .install_freetype-2.1.4_mips-unknown-elf target=mips-unknown-elf make .install_libmspack-20030726_mips-unknown-elf target=mips-unknown-elf @echo -e "\n\033[1mlinking .o -> .mips: $@\033[0m" diff --git a/Makefile.upstream b/Makefile.upstream index 17722ac..fb677cb 100644 --- a/Makefile.upstream +++ b/Makefile.upstream @@ -13,11 +13,11 @@ url_mingw-runtime-3.0 := http://unc.dl.sourceforge.net/sourceforge/mingw/mingw- url_freetype-2.1.4 := http://unc.dl.sourceforge.net/sourceforge/freetype/freetype-2.1.4.tar.gz url_gcc-3.3 := http://mirrors.rcn.net/pub/sourceware/gcc/releases/gcc-3.3/gcc-3.3.tar.gz url_jpeg-6b := http://www.ijg.org/files/jpegsrc.v6b.tar.gz -url_jikes-1.18 := http://dist.xwt.org/jikes-1.18.tgz url_libmspack-20030726 := http://www.kyz.uklinux.net/downloads/libmspack-20030726.tar.gz url_vera-1.10 := http://fgo-temp.acc.umu.se/pub/GNOME/sources/ttf-bitstream-vera/1.10/ttf-bitstream-vera-1.10.tar.gz url_WindowMaker-0.80.2 := http://windowmaker.org/pub/source/release/WindowMaker-0.80.2.tar.gz url_bcel-5.1 := http://www.apache.org/dist/jakarta/bcel/binaries/bcel-5.1.tar.gz +url_gnu.regexp-1.1.4 := ftp://ftp.tralfamadore.com/pub/java/gnu.regexp-1.1.4.tar.gz .install_binutils-2.13.2.1_powerpc-apple-darwin: .vendor rm -rf upstream/darwin-linker/src @@ -121,6 +121,11 @@ environment_gcc_3.3_$(target) += PATH=$(shell pwd)/upstream/install/bi touch .install_gcc-3.3_mips-unknown-elf touch .install_binutils-2.13.2.1_mips-unknown-elf +.download_org.ibex.crypto: + mkdir -p upstream/org.ibex.crypto + cd upstream/org.ibex.crypto; wget -l 99 -nH -r http://crypto.ibex.org/ + touch $@ + # vendor-supplied binaries and headers; this is stuff that comes with various OSes vendor: .vendor; @true .vendor: @@ -226,24 +231,5 @@ endif make $(make_install_$*_$(target)) install $(setcc) $(environment_$*_$(target)) touch $@ -# jikes has a special target to autodetect a pre-installed jikes, and to autodetect the JVM's $CLASSPATH -.jikes: - @echo -e "\n\033[1mdetecting your jikes installation...\033[0m" - echo "#!/bin/sh" > .jikes -ifeq ($(shell javac -version 2>&1 | head -n 1),javac 1.5.0-beta) - echo -n 'PATH=upstream/install/bin:$$PATH javac -classpath upstream/bcel-5.1/src/bcel-5.1.jar:build/class $$@ -d build/class/ -sourcepath build/java/:upstream/mips:upstream/mips/build:src' >> .jikes -else - echo -n 'PATH=upstream/install/bin:$$PATH jikes -classpath upstream/bcel-5.1/src/bcel-5.1.jar:build/class $$@ -d build/class/ -sourcepath build/java/:upstream/mips:upstream/mips/build:src ' >> .jikes - (type jikes && (jikes --version | grep "Version 1.18")) || make .install_jikes-1.18_ target= - echo -n "$(jikes_flags) -bootclasspath " >> .jikes - echo "public class GetBootClassPath { public static void main(String[] s) { " > GetBootClassPath.java - echo "System.out.println(System.getProperty(\"sun.boot.class.path\")); } }" >> GetBootClassPath.java - javac GetBootClassPath.java - java -cp . GetBootClassPath >> .jikes - rm GetBootClassPath.* -endif - echo 'EXIT=$$?' >> .jikes - echo 'exit $$EXIT' >> .jikes - mv .jikes .jikes+ - cp .jikes+ .jikes - chmod +x .jikes + + diff --git a/src/org/ibex/core/Box.java b/src/org/ibex/core/Box.java index c898d8e..f333abb 100644 --- a/src/org/ibex/core/Box.java +++ b/src/org/ibex/core/Box.java @@ -1,6 +1,6 @@ // FIXME // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.core; // FIXME: are traps on x/y meaningful? // FIXME: if we trap on cols, then set rows to 0 (forcing cols to 1), does the cols trap get triggered? @@ -17,7 +17,7 @@ package org.ibex; import java.util.*; import org.ibex.js.*; import org.ibex.util.*; -import org.ibex.translators.*; +import org.ibex.graphics.*; /** *

@@ -38,7 +38,7 @@ import org.ibex.translators.*; * trigger a Surface.abort; if rendering were done in the same pass, * rendering work done prior to the Surface.abort would be wasted. */ -public final class Box extends JSScope implements Scheduler.Task { +public final class Box extends JSScope implements Task { // Macros ////////////////////////////////////////////////////////////////////// @@ -52,7 +52,7 @@ public final class Box extends JSScope implements Scheduler.Task { //#define CHECKSET_BOOLEAN(prop) boolean nu = toBoolean(value); if (nu == prop) break; prop = nu; //#define CHECKSET_STRING(prop) if ((value==null&&prop==null)||(value!=null&&JS.toString(value).equals(prop))) break; prop=JS.toString(value); - protected Box() { super(null); } + public Box() { super(null); } // FIXME memory leak static Hash boxToCursor = new Hash(500, 3); @@ -128,9 +128,9 @@ public final class Box extends JSScope implements Scheduler.Task { /* private VectorGraphics.VectorPath path = null; - private VectorGraphics.Affine transform = null; + private Affine transform = null; private VectorGraphics.RasterPath rpath = null; - private VectorGraphics.Affine rtransform = null; + private Affine rtransform = null; */ //#define DIRTY dirty() @@ -172,11 +172,11 @@ public final class Box extends JSScope implements Scheduler.Task { // Reflow //////////////////////////////////////////////////////////////////////////////////////// /** should only be invoked on the root box */ - void reflow() { pack(); resize(x, y, maxwidth, maxheight); place(); } + public void reflow() { pack(); resize(x, y, maxwidth, maxheight); place(); } private static Box[] frontier = new Box[65535]; /** pack the boxes into rows and columns, compute contentwidth */ - void pack() { + public void pack() { if (!test(REPACK)) { constrain(); return; } boolean haskid = false; for(Box child = getChild(0); child != null; child = child.nextSibling()) { haskid = true; child.pack(); } @@ -390,7 +390,7 @@ public final class Box extends JSScope implements Scheduler.Task { // Rendering Pipeline ///////////////////////////////////////////////////////////////////// /** Renders self and children within the specified region. All rendering operations are clipped to xIn,yIn,wIn,hIn */ - void render(int parentx, int parenty, int cx1, int cy1, int cx2, int cy2, PixelBuffer buf, VectorGraphics.Affine a) { + public void render(int parentx, int parenty, int cx1, int cy1, int cx2, int cy2, PixelBuffer buf, Affine a) { if (!test(VISIBLE)) return; int globalx = parentx + (parent == null ? 0 : x); int globaly = parenty + (parent == null ? 0 : y); @@ -463,9 +463,9 @@ public final class Box extends JSScope implements Scheduler.Task { case "distanceto": return METHOD; case "text": return text; case "path": throw new JSExn("cannot read from the path property"); - case "fill": return colorToString(fillcolor); - case "strokecolor": return colorToString(strokecolor); - case "textcolor": return colorToString(strokecolor); + case "fill": return Color.colorToString(fillcolor); + case "strokecolor": return Color.colorToString(strokecolor); + case "textcolor": return Color.colorToString(strokecolor); case "font": return font == null ? null : font.stream; case "fontsize": return font == null ? N(10) : N(font.pointsize); case "strokewidth": return N(strokewidth); @@ -539,8 +539,8 @@ public final class Box extends JSScope implements Scheduler.Task { //#switch(name) case "thisbox": if (value == null) removeSelf(); case "text": if (value == null) value = ""; CHECKSET_STRING(text); RECONSTRAIN(); DIRTY; - case "strokecolor": value = N(stringToColor((String)value)); CHECKSET_INT(strokecolor); DIRTY; - case "textcolor": value = N(stringToColor((String)value)); CHECKSET_INT(strokecolor); DIRTY; + case "strokecolor": value = N(Color.stringToColor((String)value)); CHECKSET_INT(strokecolor); DIRTY; + case "textcolor": value = N(Color.stringToColor((String)value)); CHECKSET_INT(strokecolor); DIRTY; case "strokewidth": CHECKSET_SHORT(strokewidth); DIRTY; case "shrink": CHECKSET_FLAG(HSHRINK | VSHRINK); RECONSTRAIN(); case "hshrink": CHECKSET_FLAG(HSHRINK); RECONSTRAIN(); @@ -695,7 +695,7 @@ public final class Box extends JSScope implements Scheduler.Task { texture = null; fillcolor = 0; } else if (value instanceof String) { - int newfillcolor = stringToColor((String)value); + int newfillcolor = Color.stringToColor((String)value); if (newfillcolor == fillcolor) return; fillcolor = newfillcolor; texture = null; @@ -761,34 +761,6 @@ public final class Box extends JSScope implements Scheduler.Task { putAndTriggerTrapsAndCatchExceptions(name.substring(1), value); } - private static int stringToColor(String s) { - // FIXME support three-char strings by doubling digits - if (s == null) return 0x00000000; - else if (SVG.colors.get(s) != null) return 0xFF000000 | toInt(SVG.colors.get(s)); - else if (s.length() == 7 && s.charAt(0) == '#') try { - // FEATURE alpha - return 0xFF000000 | - (Integer.parseInt(s.substring(1, 3), 16) << 16) | - (Integer.parseInt(s.substring(3, 5), 16) << 8) | - Integer.parseInt(s.substring(5, 7), 16); - } catch (NumberFormatException e) { - Log.info(Box.class, "invalid color " + s); - return 0; - } - else return 0; // FEATURE: error? - } - - private static String colorToString(int argb) { - if ((argb & 0xFF000000) == 0) return null; - String red = Integer.toHexString((argb & 0x00FF0000) >> 16); - String green = Integer.toHexString((argb & 0x0000FF00) >> 8); - String blue = Integer.toHexString(argb & 0x000000FF); - if (red.length() < 2) red = "0" + red; - if (blue.length() < 2) blue = "0" + blue; - if (green.length() < 2) green = "0" + green; - return "#" + red + green + blue; - } - /** figures out what box in this subtree of the Box owns the pixel at x,y relitave to the Surface */ public static Box whoIs(Box cur, int x, int y) { @@ -862,7 +834,7 @@ public final class Box extends JSScope implements Scheduler.Task { // Tree Manipulation ///////////////////////////////////////////////////////////////////// - void removeSelf() { + public void removeSelf() { if (parent != null) { parent.removeChild(parent.indexNode(this)); return; } Surface surface = Surface.fromBox(this); if (surface != null) surface.dispose(true); @@ -936,8 +908,8 @@ public final class Box extends JSScope implements Scheduler.Task { putAndTriggerTrapsAndCatchExceptions("ChildChange", b); } } - - void putAndTriggerTrapsAndCatchExceptions(Object name, Object val) { + + public void putAndTriggerTrapsAndCatchExceptions(Object name, Object val) { try { putAndTriggerTraps(name, val); } catch (JSExn e) { diff --git a/src/org/ibex/core/Ibex.java b/src/org/ibex/core/Ibex.java index d97a9d5..011b9bb 100644 --- a/src/org/ibex/core/Ibex.java +++ b/src/org/ibex/core/Ibex.java @@ -1,10 +1,13 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.core; import java.io.*; import org.ibex.js.*; import org.ibex.util.*; -import org.bouncycastle.util.encoders.Base64; +import org.ibex.graphics.*; +import org.ibex.plat.*; +import org.ibex.net.*; +import org.ibex.crypto.*; /** Singleton class that provides all functionality in the ibex.* namespace */ public final class Ibex extends JS.Cloneable { @@ -125,7 +128,7 @@ public final class Ibex extends JS.Cloneable { public void put(Object name, final Object value) throws JSExn { //#switch(name) - case "thread": Scheduler.add((Scheduler.Task)value); return; + case "thread": Scheduler.add((Task)value); return; case "ui.clipboard": Platform.setClipBoard((String)value); return; case "ui.frame": Platform.createSurface((Box)value, true, true); return; case "ui.window": Platform.createSurface((Box)value, false, true); return; diff --git a/src/org/ibex/core/LocalStorage.java b/src/org/ibex/core/LocalStorage.java index 7c1d747..b523d24 100644 --- a/src/org/ibex/core/LocalStorage.java +++ b/src/org/ibex/core/LocalStorage.java @@ -1,9 +1,9 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.core; import java.io.*; import org.ibex.util.*; -import org.bouncycastle.util.encoders.Base64; +import org.ibex.crypto.*; /** Manages access to ~/.ibex */ public class LocalStorage { diff --git a/src/org/ibex/core/Main.java b/src/org/ibex/core/Main.java index 8003ada..72fd55a 100644 --- a/src/org/ibex/core/Main.java +++ b/src/org/ibex/core/Main.java @@ -1,11 +1,13 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.core; import java.net.*; import java.io.*; import java.util.*; import org.ibex.js.*; import org.ibex.util.*; +import org.ibex.plat.*; +import org.ibex.graphics.*; /** Entry point for the Ibex Engine; handles splash screen, initial xwar loading, and argument processing */ public class Main { @@ -24,7 +26,6 @@ public class Main { public static String initialTemplate = null; public static final Stream builtin = new Stream.Zip(new Stream.Builtin()); - public static Picture scarImage = null; public static void printUsage() { System.err.println("Usage: ibex [-lawp] [ url | file | directory ]"); @@ -91,9 +92,9 @@ public class Main { if (Log.on) Log.info(Main.class, "loading xwar"); final Ibex ibex = new Ibex(rr); - scarImage = + org.ibex.graphics.Surface.scarImage = Picture.load((Stream)Main.builtin.get("org/ibex/builtin/scar.png"), - new Scheduler.Task() { public void perform() throws JSExn, UnknownHostException { + new Task() { public void perform() throws JSExn, UnknownHostException { if (Log.on) Log.info(Main.class, "invoking initial template"); ibex.resolveString(startupTemplate, false).call(new Box(), null, null, null, 1); } }); diff --git a/src/org/ibex/core/Template.java b/src/org/ibex/core/Template.java index 2f3e2ac..6e29c4a 100644 --- a/src/org/ibex/core/Template.java +++ b/src/org/ibex/core/Template.java @@ -1,5 +1,5 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.core; import java.io.*; import java.util.*; @@ -59,7 +59,7 @@ public class Template { * @param pboxes a vector of all box parents on which to put $-references * @param ptemplates a vector of the fileNames to recieve private references on the pboxes */ - void apply(Box b) throws JSExn { + public void apply(Box b) throws JSExn { try { apply(b, null); } catch (IOException e) { diff --git a/src/org/ibex/graphics/Affine.java b/src/org/ibex/graphics/Affine.java new file mode 100644 index 0000000..31e2e2b --- /dev/null +++ b/src/org/ibex/graphics/Affine.java @@ -0,0 +1,128 @@ +// FIXME +// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] +package org.ibex.graphics; +import java.util.*; + +/** an affine transform; all operations are destructive */ +public final class Affine { + + // [ a b e ] + // [ c d f ] + // [ 0 0 1 ] + public float a, b, c, d, e, f; + + Affine(float _a, float _b, float _c, float _d, float _e, float _f) { a = _a; b = _b; c = _c; d = _d; e = _e; f = _f; } + public String toString() { return "[ " + a + ", " + b + ", " + c + ", " + d + ", " + e + ", " + f + " ]"; } + public Affine copy() { return new Affine(a, b, c, d, e, f); } + public static Affine identity() { return new Affine(1, 0, 0, 1, 0, 0); } + public static Affine scale(float sx, float sy) { return new Affine(sx, 0, 0, sy, 0, 0); } + public static Affine shear(float degrees) { + return new Affine(1, 0, (float)Math.tan(degrees * (float)(Math.PI / 180.0)), 1, 0, 0); } + public static Affine translate(float tx, float ty) { return new Affine(1, 0, 0, 1, tx, ty); } + public static Affine flip(boolean horiz, boolean vert) { return new Affine(horiz ? -1 : 1, 0, 0, vert ? -1 : 1, 0, 0); } + public float multiply_px(float x, float y) { return x * a + y * c + e; } + public float multiply_py(float x, float y) { return x * b + y * d + f; } + public boolean equalsIgnoringTranslation(Affine x) { return a == x.a && b == x.b && c == x.c && d == x.d; } + + public boolean equals(Object o) { + if (!(o instanceof Affine)) return false; + Affine x = (Affine)o; + return a == x.a && b == x.b && c == x.c && d == x.d && e == x.e && f == x.f; + } + + public static Affine rotate(float degrees) { + float s = (float)Math.sin(degrees * (float)(Math.PI / 180.0)); + float c = (float)Math.cos(degrees * (float)(Math.PI / 180.0)); + return new Affine(c, s, -s, c, 0, 0); + } + + /** this = this * a */ + public Affine multiply(Affine A) { + float _a = this.a * A.a + this.b * A.c; + float _b = this.a * A.b + this.b * A.d; + float _c = this.c * A.a + this.d * A.c; + float _d = this.c * A.b + this.d * A.d; + float _e = this.e * A.a + this.f * A.c + A.e; + float _f = this.e * A.b + this.f * A.d + A.f; + a = _a; b = _b; c = _c; d = _d; e = _e; f = _f; + return this; + } + + public void invert() { + float det = 1 / (a * d - b * c); + float _a = d * det; + float _b = -1 * b * det; + float _c = -1 * c * det; + float _d = a * det; + float _e = -1 * e * a - f * c; + float _f = -1 * e * b - f * d; + a = _a; b = _b; c = _c; d = _d; e = _e; f = _f; + } + + public static Affine parse(String t) { + if (t == null) return null; + t = t.trim(); + Affine ret = Affine.identity(); + while (t.length() > 0) { + if (t.startsWith("skewX(")) { + // FIXME + + } else if (t.startsWith("shear(")) { + // FIXME: nonstandard; remove this + ret.multiply(Affine.shear(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(')'))))); + + } else if (t.startsWith("skewY(")) { + // FIXME + + } else if (t.startsWith("rotate(")) { + String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')')); + if (sub.indexOf(',') != -1) { + float angle = Float.parseFloat(sub.substring(0, sub.indexOf(','))); + sub = sub.substring(sub.indexOf(',') + 1); + float cx = Float.parseFloat(sub.substring(0, sub.indexOf(','))); + sub = sub.substring(sub.indexOf(',') + 1); + float cy = Float.parseFloat(sub); + ret.multiply(Affine.translate(cx, cy)); + ret.multiply(Affine.rotate(angle)); + ret.multiply(Affine.translate(-1 * cx, -1 * cy)); + } else { + ret.multiply(Affine.rotate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(')'))))); + } + + } else if (t.startsWith("translate(")) { + String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')')); + if (sub.indexOf(',') > -1) { + ret.multiply(Affine.translate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))), + Float.parseFloat(t.substring(t.indexOf(',') + 1, t.indexOf(')'))))); + } else { + ret.multiply(Affine.translate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))), 0)); + } + + } else if (t.startsWith("flip(")) { + String which = t.substring(t.indexOf('(') + 1, t.indexOf(')')); + ret.multiply(Affine.flip(which.equals("horizontal"), which.equals("vertical"))); + + } else if (t.startsWith("scale(")) { + String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')')); + if (sub.indexOf(',') > -1) { + ret.multiply(Affine.scale(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))), + Float.parseFloat(t.substring(t.indexOf(',') + 1, t.indexOf(')'))))); + } else { + ret.multiply(Affine.scale(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))), + Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))))); + } + + } else if (t.startsWith("matrix(")) { + // FIXME: is this mapped right? + float d[] = new float[6]; + StringTokenizer st = new StringTokenizer(t, ",", false); + for(int i=0; i<6; i++) + d[i] = Float.parseFloat(st.nextToken()); + ret.multiply(new Affine(d[0], d[1], d[2], d[3], d[4], d[5])); + } + t = t.substring(t.indexOf(')') + 1).trim(); + } + return ret; + } + +} diff --git a/src/org/ibex/graphics/Color.java b/src/org/ibex/graphics/Color.java new file mode 100644 index 0000000..210aade --- /dev/null +++ b/src/org/ibex/graphics/Color.java @@ -0,0 +1,187 @@ +// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +package org.ibex.graphics; +import java.util.*; +import org.ibex.util.*; + +public class Color { + + public static int stringToColor(String s) { + // FIXME support three-char strings by doubling digits + if (s == null) return 0x00000000; + else if (standard.get(s) != null) return 0xFF000000 | org.ibex.js.JS.toInt(standard.get(s)); + else if (s.length() == 7 && s.charAt(0) == '#') try { + // FEATURE alpha + return 0xFF000000 | + (Integer.parseInt(s.substring(1, 3), 16) << 16) | + (Integer.parseInt(s.substring(3, 5), 16) << 8) | + Integer.parseInt(s.substring(5, 7), 16); + } catch (NumberFormatException e) { + Log.info(Color.class, "invalid color " + s); + return 0; + } + else return 0; // FEATURE: error? + } + + public static String colorToString(int argb) { + if ((argb & 0xFF000000) == 0) return null; + String red = Integer.toHexString((argb & 0x00FF0000) >> 16); + String green = Integer.toHexString((argb & 0x0000FF00) >> 8); + String blue = Integer.toHexString(argb & 0x000000FF); + if (red.length() < 2) red = "0" + red; + if (blue.length() < 2) blue = "0" + blue; + if (green.length() < 2) green = "0" + green; + return "#" + red + green + blue; + } + + /** Copied verbatim from the SVG specification */ + private static Hashtable standard = new Hashtable(400); + static { + standard.put("aliceblue", new Integer((240 << 16) | (248 << 8) | 255)); + standard.put("antiquewhite", new Integer((250 << 16) | (235 << 8) | 215)); + standard.put("aqua", new Integer((0 << 16) | (255 << 8) | 255)); + standard.put("aquamarine", new Integer((127 << 16) | (255 << 8) | 212)); + standard.put("azure", new Integer((240 << 16) | (255 << 8) | 255)); + standard.put("beige", new Integer((245 << 16) | (245 << 8) | 220)); + standard.put("bisque", new Integer((255 << 16) | (228 << 8) | 196)); + standard.put("black", new Integer((0 << 16) | (0 << 8) | 0)); + standard.put("blanchedalmond", new Integer((255 << 16) | (235 << 8) | 205)); + standard.put("blue", new Integer((0 << 16) | (0 << 8) | 255)); + standard.put("blueviolet", new Integer((138 << 16) | (43 << 8) | 226)); + standard.put("brown", new Integer((165 << 16) | (42 << 8) | 42)); + standard.put("burlywood", new Integer((222 << 16) | (184 << 8) | 135)); + standard.put("cadetblue", new Integer((95 << 16) | (158 << 8) | 160)); + standard.put("chartreuse", new Integer((127 << 16) | (255 << 8) | 0)); + standard.put("chocolate", new Integer((210 << 16) | (105 << 8) | 30)); + standard.put("coral", new Integer((255 << 16) | (127 << 8) | 80)); + standard.put("cornflowerblue", new Integer((100 << 16) | (149 << 8) | 237)); + standard.put("cornsilk", new Integer((255 << 16) | (248 << 8) | 220)); + standard.put("crimson", new Integer((220 << 16) | (20 << 8) | 60)); + standard.put("cyan", new Integer((0 << 16) | (255 << 8) | 255)); + standard.put("darkblue", new Integer((0 << 16) | (0 << 8) | 139)); + standard.put("darkcyan", new Integer((0 << 16) | (139 << 8) | 139)); + standard.put("darkgoldenrod", new Integer((184 << 16) | (134 << 8) | 11)); + standard.put("darkgray", new Integer((169 << 16) | (169 << 8) | 169)); + standard.put("darkgreen", new Integer((0 << 16) | (100 << 8) | 0)); + standard.put("darkgrey", new Integer((169 << 16) | (169 << 8) | 169)); + standard.put("darkkhaki", new Integer((189 << 16) | (183 << 8) | 107)); + standard.put("darkmagenta", new Integer((139 << 16) | (0 << 8) | 139)); + standard.put("darkolivegreen", new Integer((85 << 16) | (107 << 8) | 47)); + standard.put("darkorange", new Integer((255 << 16) | (140 << 8) | 0)); + standard.put("darkorchid", new Integer((153 << 16) | (50 << 8) | 204)); + standard.put("darkred", new Integer((139 << 16) | (0 << 8) | 0)); + standard.put("darksalmon", new Integer((233 << 16) | (150 << 8) | 122)); + standard.put("darkseagreen", new Integer((143 << 16) | (188 << 8) | 143)); + standard.put("darkslateblue", new Integer((72 << 16) | (61 << 8) | 139)); + standard.put("darkslategray", new Integer((47 << 16) | (79 << 8) | 79)); + standard.put("darkslategrey", new Integer((47 << 16) | (79 << 8) | 79)); + standard.put("darkturquoise", new Integer((0 << 16) | (206 << 8) | 209)); + standard.put("darkviolet", new Integer((148 << 16) | (0 << 8) | 211)); + standard.put("deeppink", new Integer((255 << 16) | (20 << 8) | 147)); + standard.put("deepskyblue", new Integer((0 << 16) | (191 << 8) | 255)); + standard.put("dimgray", new Integer((105 << 16) | (105 << 8) | 105)); + standard.put("dimgrey", new Integer((105 << 16) | (105 << 8) | 105)); + standard.put("dodgerblue", new Integer((30 << 16) | (144 << 8) | 255)); + standard.put("firebrick", new Integer((178 << 16) | (34 << 8) | 34)); + standard.put("floralwhite", new Integer((255 << 16) | (250 << 8) | 240)); + standard.put("forestgreen", new Integer((34 << 16) | (139 << 8) | 34)); + standard.put("fuchsia", new Integer((255 << 16) | (0 << 8) | 255)); + standard.put("gainsboro", new Integer((220 << 16) | (220 << 8) | 220)); + standard.put("ghostwhite", new Integer((248 << 16) | (248 << 8) | 255)); + standard.put("gold", new Integer((255 << 16) | (215 << 8) | 0)); + standard.put("goldenrod", new Integer((218 << 16) | (165 << 8) | 32)); + standard.put("gray", new Integer((128 << 16) | (128 << 8) | 128)); + standard.put("grey", new Integer((128 << 16) | (128 << 8) | 128)); + standard.put("green", new Integer((0 << 16) | (128 << 8) | 0)); + standard.put("greenyellow", new Integer((173 << 16) | (255 << 8) | 47)); + standard.put("honeydew", new Integer((240 << 16) | (255 << 8) | 240)); + standard.put("hotpink", new Integer((255 << 16) | (105 << 8) | 180)); + standard.put("indianred", new Integer((205 << 16) | (92 << 8) | 92)); + standard.put("indigo", new Integer((75 << 16) | (0 << 8) | 130)); + standard.put("ivory", new Integer((255 << 16) | (255 << 8) | 240)); + standard.put("khaki", new Integer((240 << 16) | (230 << 8) | 140)); + standard.put("lavender", new Integer((230 << 16) | (230 << 8) | 250)); + standard.put("lavenderblush", new Integer((255 << 16) | (240 << 8) | 245)); + standard.put("lawngreen", new Integer((124 << 16) | (252 << 8) | 0)); + standard.put("lemonchiffon", new Integer((255 << 16) | (250 << 8) | 205)); + standard.put("lightblue", new Integer((173 << 16) | (216 << 8) | 230)); + standard.put("lightcoral", new Integer((240 << 16) | (128 << 8) | 128)); + standard.put("lightcyan", new Integer((224 << 16) | (255 << 8) | 255)); + standard.put("lightgoldenrodyellow", new Integer((250 << 16) | (250 << 8) | 210)); + standard.put("lightgray", new Integer((211 << 16) | (211 << 8) | 211)); + standard.put("lightgreen", new Integer((144 << 16) | (238 << 8) | 144)); + standard.put("lightgrey", new Integer((211 << 16) | (211 << 8) | 211)); + standard.put("lightpink", new Integer((255 << 16) | (182 << 8) | 193)); + standard.put("lightsalmon", new Integer((255 << 16) | (160 << 8) | 122)); + standard.put("lightseagreen", new Integer((32 << 16) | (178 << 8) | 170)); + standard.put("lightskyblue", new Integer((135 << 16) | (206 << 8) | 250)); + standard.put("lightslategray", new Integer((119 << 16) | (136 << 8) | 153)); + standard.put("lightslategrey", new Integer((119 << 16) | (136 << 8) | 153)); + standard.put("lightsteelblue", new Integer((176 << 16) | (196 << 8) | 222)); + standard.put("lightyellow", new Integer((255 << 16) | (255 << 8) | 224)); + standard.put("lime", new Integer((0 << 16) | (255 << 8) | 0)); + standard.put("limegreen", new Integer((50 << 16) | (205 << 8) | 50)); + standard.put("linen", new Integer((250 << 16) | (240 << 8) | 230)); + standard.put("magenta", new Integer((255 << 16) | (0 << 8) | 255)); + standard.put("maroon", new Integer((128 << 16) | (0 << 8) | 0)); + standard.put("mediumaquamarine", new Integer((102 << 16) | (205 << 8) | 170)); + standard.put("mediumblue", new Integer((0 << 16) | (0 << 8) | 205)); + standard.put("mediumorchid", new Integer((186 << 16) | (85 << 8) | 211)); + standard.put("mediumpurple", new Integer((147 << 16) | (112 << 8) | 219)); + standard.put("mediumseagreen", new Integer((60 << 16) | (179 << 8) | 113)); + standard.put("mediumslateblue", new Integer((123 << 16) | (104 << 8) | 238)); + standard.put("mediumspringgreen", new Integer((0 << 16) | (250 << 8) | 154)); + standard.put("mediumturquoise", new Integer((72 << 16) | (209 << 8) | 204)); + standard.put("mediumvioletred", new Integer((199 << 16) | (21 << 8) | 133)); + standard.put("midnightblue", new Integer((25 << 16) | (25 << 8) | 112)); + standard.put("mintcream", new Integer((245 << 16) | (255 << 8) | 250)); + standard.put("mistyrose", new Integer((255 << 16) | (228 << 8) | 225)); + standard.put("moccasin", new Integer((255 << 16) | (228 << 8) | 181)); + standard.put("navajowhite", new Integer((255 << 16) | (222 << 8) | 173)); + standard.put("navy", new Integer((0 << 16) | (0 << 8) | 128)); + standard.put("oldlace", new Integer((253 << 16) | (245 << 8) | 230)); + standard.put("olive", new Integer((128 << 16) | (128 << 8) | 0)); + standard.put("olivedrab", new Integer((107 << 16) | (142 << 8) | 35)); + standard.put("orange", new Integer((255 << 16) | (165 << 8) | 0)); + standard.put("orangered", new Integer((255 << 16) | (69 << 8) | 0)); + standard.put("orchid", new Integer((218 << 16) | (112 << 8) | 214)); + standard.put("palegoldenrod", new Integer((238 << 16) | (232 << 8) | 170)); + standard.put("palegreen", new Integer((152 << 16) | (251 << 8) | 152)); + standard.put("paleturquoise", new Integer((175 << 16) | (238 << 8) | 238)); + standard.put("palevioletred", new Integer((219 << 16) | (112 << 8) | 147)); + standard.put("papayawhip", new Integer((255 << 16) | (239 << 8) | 213)); + standard.put("peachpuff", new Integer((255 << 16) | (218 << 8) | 185)); + standard.put("peru", new Integer((205 << 16) | (133 << 8) | 63)); + standard.put("pink", new Integer((255 << 16) | (192 << 8) | 203)); + standard.put("plum", new Integer((221 << 16) | (160 << 8) | 221)); + standard.put("powderblue", new Integer((176 << 16) | (224 << 8) | 230)); + standard.put("purple", new Integer((128 << 16) | (0 << 8) | 128)); + standard.put("red", new Integer((255 << 16) | (0 << 8) | 0)); + standard.put("rosybrown", new Integer((188 << 16) | (143 << 8) | 143)); + standard.put("royalblue", new Integer((65 << 16) | (105 << 8) | 225)); + standard.put("saddlebrown", new Integer((139 << 16) | (69 << 8) | 19)); + standard.put("salmon", new Integer((250 << 16) | (128 << 8) | 114)); + standard.put("sandybrown", new Integer((244 << 16) | (164 << 8) | 96)); + standard.put("seagreen", new Integer((46 << 16) | (139 << 8) | 87)); + standard.put("seashell", new Integer((255 << 16) | (245 << 8) | 238)); + standard.put("sienna", new Integer((160 << 16) | (82 << 8) | 45)); + standard.put("silver", new Integer((192 << 16) | (192 << 8) | 192)); + standard.put("skyblue", new Integer((135 << 16) | (206 << 8) | 235)); + standard.put("slateblue", new Integer((106 << 16) | (90 << 8) | 205)); + standard.put("slategray", new Integer((112 << 16) | (128 << 8) | 144)); + standard.put("slategrey", new Integer((112 << 16) | (128 << 8) | 144)); + standard.put("snow", new Integer((255 << 16) | (250 << 8) | 250)); + standard.put("springgreen", new Integer((0 << 16) | (255 << 8) | 127)); + standard.put("steelblue", new Integer((70 << 16) | (130 << 8) | 180)); + standard.put("tan", new Integer((210 << 16) | (180 << 8) | 140)); + standard.put("teal", new Integer((0 << 16) | (128 << 8) | 128)); + standard.put("thistle", new Integer((216 << 16) | (191 << 8) | 216)); + standard.put("tomato", new Integer((255 << 16) | (99 << 8) | 71)); + standard.put("turquoise", new Integer((64 << 16) | (224 << 8) | 208)); + standard.put("violet", new Integer((238 << 16) | (130 << 8) | 238)); + standard.put("wheat", new Integer((245 << 16) | (222 << 8) | 179)); + standard.put("white", new Integer((255 << 16) | (255 << 8) | 255)); + standard.put("whitesmoke", new Integer((245 << 16) | (245 << 8) | 245)); + standard.put("yellow", new Integer((255 << 16) | (255 << 8) | 0)); + standard.put("yellowgreen", new Integer((154 << 16) | (205 << 8) | 50)); + } +} diff --git a/src/org/ibex/graphics/Font.java b/src/org/ibex/graphics/Font.java index 451672e..47ba25b 100644 --- a/src/org/ibex/graphics/Font.java +++ b/src/org/ibex/graphics/Font.java @@ -1,11 +1,11 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; -import org.ibex.translators.*; +package org.ibex.graphics; import org.ibex.util.*; import java.io.*; import java.util.Hashtable; - -import org.ibex.js.JSExn; +import org.ibex.js.*; +import org.xwt.mips.*; +import org.ibex.plat.*; // FEATURE: this could be cleaner /** encapsulates a single font (a set of Glyphs) */ @@ -33,7 +33,7 @@ public class Font { public int height = -1; ///< the height of the glyph public byte[] data = null; ///< the alpha channel samples for this font void render() { - if (!isLoaded) try { freetype.renderGlyph(this); } catch (IOException e) { Log.info(Freetype.class, e); } + if (!isLoaded) try { renderGlyph(this); } catch (IOException e) { Log.info(Font.class, e); } isLoaded = true; } } @@ -41,7 +41,6 @@ public class Font { // Statics ////////////////////////////////////////////////////////////////////// - static final Freetype freetype = new Freetype(); static final Hashtable glyphsToBeCached = new Hashtable(); static final Hashtable glyphsToBeDisplayed = new Hashtable(); private static Cache fontCache = new Cache(100); @@ -94,7 +93,7 @@ public class Font { return ret; } - static final Scheduler.Task glyphRenderingTask = new Scheduler.Task() { public void perform() { + static final Task glyphRenderingTask = new Task() { public void perform() { // FIXME: this should be a low-priority task glyphRenderingTaskIsScheduled = false; if (glyphsToBeCached.isEmpty()) return; @@ -107,4 +106,59 @@ public class Font { glyphRenderingTaskIsScheduled = true; Scheduler.add(this); } }; + + + // FreeType Interface ////////////////////////////////////////////////////////////////////////////// + + // FEATURE: use streams, not memoryfont's + // FEATURE: kerning pairs + private static int mem_allocated = 0; + private static org.xwt.mips.Runtime vm = null; + private static Stream loadedStream = null; + + public static void loadFontByteStream(Stream res) { + try { + Log.info(Font.class, "loading font " + res); + loadedStream = res; + InputStream is = Stream.getInputStream(res); + byte[] fontstream = InputStreamToByteArray.convert(is); + vm = (org.xwt.mips.Runtime)Class.forName("org.ibex.util.MIPSApps").newInstance(); + int baseAddr = vm.sbrk(fontstream.length); + vm.copyout(fontstream, baseAddr, fontstream.length); + vm.setUserInfo(0, baseAddr); + vm.setUserInfo(1, fontstream.length); + vm.start(new String[]{ "freetype" }); + vm.execute(); + if(vm.getState() == org.xwt.mips.Runtime.DONE) throw new Error("Freetype VM exited: " + vm.exitStatus()); + } catch (Exception e) { + Log.info(Font.class, e); + } + } + + public static synchronized void renderGlyph(Font.Glyph glyph) throws IOException { + try { + Log.debug(Font.class, "rasterizing glyph " + glyph.c + " of font " + glyph.font); + if (loadedStream != glyph.font.stream) loadFontByteStream(glyph.font.stream); + vm.setUserInfo(2, (int)glyph.c); + vm.setUserInfo(3, (int)glyph.c); + vm.setUserInfo(4, glyph.font.pointsize); + long start = System.currentTimeMillis(); + vm.execute(); + glyph.font.max_ascent = vm.getUserInfo(8); + glyph.font.max_descent = vm.getUserInfo(9); + glyph.baseline = vm.getUserInfo(10); + glyph.advance = vm.getUserInfo(11); + + glyph.width = vm.getUserInfo(6); + glyph.height = vm.getUserInfo(7); + + glyph.data = new byte[glyph.width * glyph.height]; + int addr = vm.getUserInfo(5); + vm.copyin(addr, glyph.data, glyph.width * glyph.height); + glyph.isLoaded = true; + + } catch (Exception e) { + Log.info(Font.class, e); + } + } } diff --git a/src/org/ibex/graphics/Freetype.c b/src/org/ibex/graphics/Freetype.c index 2a1c798..f65f5c8 100644 --- a/src/org/ibex/graphics/Freetype.c +++ b/src/org/ibex/graphics/Freetype.c @@ -3,6 +3,8 @@ #include #include +char *user_info[1024]; + /* NOTE: _user_info is defined in crt0.c. It points to a 4096 byte block of memory that contains 1024 32-bit values that can be set with the setUserInfo() method of MIPSEmu. @@ -34,8 +36,6 @@ */ -extern char *user_info[1024]; - #define FT_Check(expr) do { \ if((expr) != 0) { \ errprint(#expr " failed\n"); \ @@ -105,3 +105,12 @@ if (old_glyph_index != -1) { } old_glyph_index = glyph_index; */ + + +extern int mspack_main(); +int main(int argc, char **argv) { + if(argc < 1) return 1; + if(strcmp(argv[0],"mspack")==0) return mspack_main(); + if(strcmp(argv[0],"freetype")==0) return freetype_main(); + return 1; +} diff --git a/src/org/ibex/graphics/GIF.java b/src/org/ibex/graphics/GIF.java index 26b1a40..254430e 100644 --- a/src/org/ibex/graphics/GIF.java +++ b/src/org/ibex/graphics/GIF.java @@ -41,7 +41,7 @@ * terms specified in this license. * */ -package org.ibex.translators; +package org.ibex.graphics; import org.ibex.*; import org.ibex.util.*; diff --git a/src/org/ibex/util/HTML.java b/src/org/ibex/graphics/HTML.java similarity index 99% rename from src/org/ibex/util/HTML.java rename to src/org/ibex/graphics/HTML.java index 5b0811f..47de2e0 100644 --- a/src/org/ibex/util/HTML.java +++ b/src/org/ibex/graphics/HTML.java @@ -1,5 +1,5 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex.translators; +package org.ibex.graphics; import java.util.*; import java.net.*; diff --git a/src/org/ibex/graphics/PNG.java b/src/org/ibex/graphics/PNG.java index ee6537e..b5d47f2 100644 --- a/src/org/ibex/graphics/PNG.java +++ b/src/org/ibex/graphics/PNG.java @@ -11,7 +11,7 @@ * hereby granted. */ -package org.ibex.translators; +package org.ibex.graphics; import org.ibex.*; import org.ibex.util.*; diff --git a/src/org/ibex/graphics/Paint.java b/src/org/ibex/graphics/Paint.java new file mode 100644 index 0000000..46c43ee --- /dev/null +++ b/src/org/ibex/graphics/Paint.java @@ -0,0 +1,102 @@ +// FIXME +// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] +package org.ibex.graphics; +import java.util.*; + +public abstract class Paint { + public abstract void fillTrapezoid(int tx1, int tx2, int ty1, int tx3, int tx4, int ty2, PixelBuffer buf); + + public static class SingleColorPaint extends Paint { + int color; + public SingleColorPaint(int color) { this.color = color; } + public void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, PixelBuffer buf) { + buf.fillTrapezoid(x1, x2, y1, x3, x4, y2, color); + } + } + + + /* + public static abstract class GradientPaint extends Paint { + public GradientPaint(boolean reflect, boolean repeat, Affine gradientTransform, + int[] stop_colors, float[] stop_offsets) { + this.reflect = reflect; this.repeat = repeat; + this.gradientTransform = gradientTransform; + this.stop_colors = stop_colors; + this.stop_offsets = stop_offsets; + } + Affine gradientTransform = Affine.identity(); + boolean useBoundingBox = false; // FIXME not supported + boolean patternUseBoundingBox = false; // FIXME not supported + + // it's invalid for both of these to be true + boolean reflect = false; // FIXME not supported + boolean repeat = false; // FIXME not supported + int[] stop_colors; + float[] stop_offsets; + + public void fillTrapezoid(float tx1, float tx2, float ty1, float tx3, float tx4, float ty2, PixelBuffer buf) { + Affine a = buf.a; + Affine inverse = a.copy().invert(); + float slope1 = (tx3 - tx1) / (ty2 - ty1); + float slope2 = (tx4 - tx2) / (ty2 - ty1); + for(float y=ty1; y _x2) { float _x0 = _x1; _x1 = _x2; _x2 = _x0; } + + for(float x=_x1; x<_x2; x++) { + + float distance = isLinear ? + // length of projection of onto the gradient vector == { \dot {grad \over |grad|}} + (x * (x2 - x1) + y * (y2 - y1)) / (float)Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) : + + // radial form is simple! FIXME, not quite right + (float)Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)); + + // FIXME: offsets are 0..1, not 0..length(gradient) + int i = 0; for(; i= stop_offsets.length) continue; + + // gradate from offsets[i - 1] to offsets[i] + float percentage = ((distance - stop_offsets[i - 1]) / (stop_offsets[i] - stop_offsets[i - 1])); + + int a = (int)((((stop_colors[i] >> 24) & 0xff) - ((stop_colors[i - 1] >> 24) & 0xff)) * percentage) + + ((stop_colors[i - 1] >> 24) & 0xff); + int r = (int)((((stop_colors[i] >> 16) & 0xff) - ((stop_colors[i - 1] >> 16) & 0xff)) * percentage) + + ((stop_colors[i - 1] >> 16) & 0xff); + int g = (int)((((stop_colors[i] >> 8) & 0xff) - ((stop_colors[i - 1] >> 8) & 0xff)) * percentage) + + ((stop_colors[i - 1] >> 8) & 0xff); + int b = (int)((((stop_colors[i] >> 0) & 0xff) - ((stop_colors[i - 1] >> 0) & 0xff)) * percentage) + + ((stop_colors[i - 1] >> 0) & 0xff); + int argb = (a << 24) | (r << 16) | (g << 8) | b; + buf.drawPoint((int)x, (int)Math.floor(y), argb); + } + } + } + } + + public static class LinearGradientPaint extends GradientPaint { + public LinearGradientPaint(float x1, float y1, float x2, float y2, boolean reflect, boolean repeat, + Affine gradientTransform, int[] stop_colors, float[] stop_offsets) { + super(reflect, repeat, gradientTransform, stop_colors, stop_offsets); + this.x1 = x1; this.x2 = x2; this.y1 = y1; this.y2 = y2; + } + float x1 = 0, y1 = 0, x2 = 300, y2 = 300; + } + + public static class RadialGradientPaint extends GradientPaint { + public RadialGradientPaint(float cx, float cy, float fx, float fy, float r, boolean reflect, boolean repeat, + Affine gradientTransform, int[] stop_colors, float[] stop_offsets) { + super(reflect, repeat, gradientTransform, stop_colors, stop_offsets); + this.cx = cx; this.cy = cy; this.fx = fx; this.fy = fy; this.r = r; + } + + float cx, cy, r, fx, fy; + + } + */ + + +} diff --git a/src/org/ibex/graphics/Path.java b/src/org/ibex/graphics/Path.java index 79fecba..71063a2 100644 --- a/src/org/ibex/graphics/Path.java +++ b/src/org/ibex/graphics/Path.java @@ -1,201 +1,66 @@ // FIXME -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] +package org.ibex.graphics; import java.util.*; -// FIXME: offer a "subpixel" mode where we pass floats to the Platform and don't do any snapping -// FIXME: fracture when realizing instead of when parsing? - -/* - v1.0 - - textpath - - gradients - - patterns - - clipping/masking - - filters (filtering of a group must be performed AFTER the group is assembled; sep. canvas) - - v1.1 - - bump caps [requires Paint that can fill circles...] [remember to distinguish between closed/unclosed] - - line joins - - mitre (hard) - - bevel (easy) - - bump (easy, but requires 'round' Paint) - - subtree sharing? otherwise the memory consumption might be outrageous... clone="" attribute? - - better clipping - - intersect clip regions (linearity) - - clip on trapezoids, not pixels - - faster gradients and patterns: - - transform each corner of the trapezoid and then interpolate -*/ - -/** Ibex's fully conformant Static SVG Viewer; see SVG spec, section G.7 */ -public final class VectorGraphics { - - // Private Constants /////////////////////////////////////////////////////////////////// +/** an abstract path; may contain splines and arcs */ +public class Path { + public static final float PX_PER_INCH = 72; + public static final float INCHES_PER_CM = (float)0.3937; + public static final float INCHES_PER_MM = INCHES_PER_CM / 10; private static final int DEFAULT_PATHLEN = 1000; private static final float PI = (float)Math.PI; + // the number of vertices on this path + int numvertices = 0; - // Public entry points ///////////////////////////////////////////////////////////////// - - public static VectorPath parseVectorPath(String s) { - if (s == null) return null; - PathTokenizer t = new PathTokenizer(s); - VectorPath ret = new VectorPath(); - char last_command = 'M'; - boolean first = true; - while(t.hasMoreTokens()) { - char command = t.parseCommand(); - if (first && command != 'M') throw new RuntimeException("the first command of a path must be 'M'"); - first = false; - boolean relative = Character.toLowerCase(command) == command; - command = Character.toLowerCase(command); - ret.parseSingleCommandAndArguments(t, command, relative); - last_command = command; - } - return ret; - } - - - // Affine ////////////////////////////////////////////////////////////////////////////// - - /** an affine transform; all operations are destructive */ - public static final class Affine { - - // [ a b e ] - // [ c d f ] - // [ 0 0 1 ] - public float a, b, c, d, e, f; - - Affine(float _a, float _b, float _c, float _d, float _e, float _f) { a = _a; b = _b; c = _c; d = _d; e = _e; f = _f; } - public String toString() { return "[ " + a + ", " + b + ", " + c + ", " + d + ", " + e + ", " + f + " ]"; } - public Affine copy() { return new Affine(a, b, c, d, e, f); } - public static Affine identity() { return new Affine(1, 0, 0, 1, 0, 0); } - public static Affine scale(float sx, float sy) { return new Affine(sx, 0, 0, sy, 0, 0); } - public static Affine shear(float degrees) { - return new Affine(1, 0, (float)Math.tan(degrees * (float)(Math.PI / 180.0)), 1, 0, 0); } - public static Affine translate(float tx, float ty) { return new Affine(1, 0, 0, 1, tx, ty); } - public static Affine flip(boolean horiz, boolean vert) { return new Affine(horiz ? -1 : 1, 0, 0, vert ? -1 : 1, 0, 0); } - public float multiply_px(float x, float y) { return x * a + y * c + e; } - public float multiply_py(float x, float y) { return x * b + y * d + f; } - public boolean equalsIgnoringTranslation(Affine x) { return a == x.a && b == x.b && c == x.c && d == x.d; } - - public boolean equals(Object o) { - if (!(o instanceof Affine)) return false; - Affine x = (Affine)o; - return a == x.a && b == x.b && c == x.c && d == x.d && e == x.e && f == x.f; - } + // the vertices of the path + float[] x = new float[DEFAULT_PATHLEN]; + float[] y = new float[DEFAULT_PATHLEN]; - public static Affine rotate(float degrees) { - float s = (float)Math.sin(degrees * (float)(Math.PI / 180.0)); - float c = (float)Math.cos(degrees * (float)(Math.PI / 180.0)); - return new Affine(c, s, -s, c, 0, 0); - } + // the type of each edge; type[i] is the type of the edge from x[i],y[i] to x[i+1],y[i+1] + byte[] type = new byte[DEFAULT_PATHLEN]; - /** this = this * a */ - public Affine multiply(Affine A) { - float _a = this.a * A.a + this.b * A.c; - float _b = this.a * A.b + this.b * A.d; - float _c = this.c * A.a + this.d * A.c; - float _d = this.c * A.b + this.d * A.d; - float _e = this.e * A.a + this.f * A.c + A.e; - float _f = this.e * A.b + this.f * A.d + A.f; - a = _a; b = _b; c = _c; d = _d; e = _e; f = _f; - return this; - } - - public void invert() { - float det = 1 / (a * d - b * c); - float _a = d * det; - float _b = -1 * b * det; - float _c = -1 * c * det; - float _d = a * det; - float _e = -1 * e * a - f * c; - float _f = -1 * e * b - f * d; - a = _a; b = _b; c = _c; d = _d; e = _e; f = _f; - } - } + // bezier control points + float[] c1x = new float[DEFAULT_PATHLEN]; // or rx (arcto) + float[] c1y = new float[DEFAULT_PATHLEN]; // or ry (arcto) + float[] c2x = new float[DEFAULT_PATHLEN]; // or x-axis-rotation (arcto) + float[] c2y = new float[DEFAULT_PATHLEN]; // or large-arc << 1 | sweep (arcto) + boolean closed = false; - // PathTokenizer ////////////////////////////////////////////////////////////////////////////// + static final byte TYPE_MOVETO = 0; + static final byte TYPE_LINETO = 1; + static final byte TYPE_ARCTO = 2; + static final byte TYPE_CUBIC = 3; + static final byte TYPE_QUADRADIC = 4; - public static Affine parseTransform(String t) { - if (t == null) return null; - t = t.trim(); - Affine ret = VectorGraphics.Affine.identity(); - while (t.length() > 0) { - if (t.startsWith("skewX(")) { - // FIXME - - } else if (t.startsWith("shear(")) { - // FIXME: nonstandard; remove this - ret.multiply(VectorGraphics.Affine.shear(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(')'))))); - - } else if (t.startsWith("skewY(")) { - // FIXME - - } else if (t.startsWith("rotate(")) { - String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')')); - if (sub.indexOf(',') != -1) { - float angle = Float.parseFloat(sub.substring(0, sub.indexOf(','))); - sub = sub.substring(sub.indexOf(',') + 1); - float cx = Float.parseFloat(sub.substring(0, sub.indexOf(','))); - sub = sub.substring(sub.indexOf(',') + 1); - float cy = Float.parseFloat(sub); - ret.multiply(VectorGraphics.Affine.translate(cx, cy)); - ret.multiply(VectorGraphics.Affine.rotate(angle)); - ret.multiply(VectorGraphics.Affine.translate(-1 * cx, -1 * cy)); - } else { - ret.multiply(VectorGraphics.Affine.rotate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(')'))))); - } - - } else if (t.startsWith("translate(")) { - String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')')); - if (sub.indexOf(',') > -1) { - ret.multiply(VectorGraphics.Affine.translate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))), - Float.parseFloat(t.substring(t.indexOf(',') + 1, t.indexOf(')'))))); - } else { - ret.multiply(VectorGraphics.Affine.translate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))), 0)); - } - - } else if (t.startsWith("flip(")) { - String which = t.substring(t.indexOf('(') + 1, t.indexOf(')')); - ret.multiply(VectorGraphics.Affine.flip(which.equals("horizontal"), which.equals("vertical"))); - - } else if (t.startsWith("scale(")) { - String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')')); - if (sub.indexOf(',') > -1) { - ret.multiply(VectorGraphics.Affine.scale(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))), - Float.parseFloat(t.substring(t.indexOf(',') + 1, t.indexOf(')'))))); - } else { - ret.multiply(VectorGraphics.Affine.scale(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))), - Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))))); - } - - } else if (t.startsWith("matrix(")) { - // FIXME: is this mapped right? - float d[] = new float[6]; - StringTokenizer st = new StringTokenizer(t, ",", false); - for(int i=0; i<6; i++) - d[i] = Float.parseFloat(st.nextToken()); - ret.multiply(new VectorGraphics.Affine(d[0], d[1], d[2], d[3], d[4], d[5])); - } - t = t.substring(t.indexOf(')') + 1).trim(); - } - return ret; - } - - public static final float PX_PER_INCH = 72; - public static final float INCHES_PER_CM = (float)0.3937; - public static final float INCHES_PER_MM = INCHES_PER_CM / 10; - - public static class PathTokenizer { + public static class Tokenizer { // FIXME: check array bounds exception for improperly terminated string String s; int i = 0; char lastCommand = 'M'; - public PathTokenizer(String s) { this.s = s; } + public Tokenizer(String s) { this.s = s; } + + public static Path parse(String s) { + if (s == null) return null; + Tokenizer t = new Tokenizer(s); + Path ret = new Path(); + char last_command = 'M'; + boolean first = true; + while(t.hasMoreTokens()) { + char command = t.parseCommand(); + if (first && command != 'M') throw new RuntimeException("the first command of a path must be 'M'"); + first = false; + boolean relative = Character.toLowerCase(command) == command; + command = Character.toLowerCase(command); + ret.parseSingleCommandAndArguments(t, command, relative); + last_command = command; + } + return ret; + } + private void consumeWhitespace() { while(i < s.length() && (Character.isWhitespace(s.charAt(i)))) i++; if (i < s.length() && s.charAt(i) == ',') i++; @@ -235,169 +100,139 @@ public final class VectorGraphics { } } + /** Creates a concrete vector path transformed through the given matrix. */ + public Raster realize(Affine a) { + + Raster ret = new Raster(); + int NUMSTEPS = 5; // FIXME + ret.numvertices = 1; + ret.x[0] = (int)Math.round(a.multiply_px(x[0], y[0])); + ret.y[0] = (int)Math.round(a.multiply_py(x[0], y[0])); + + for(int i=1; i> 1; + float fs = ((int)c2y[i]) & 1; + float x1 = x[i]; + float y1 = y[i]; + float x2 = x[i+1]; + float y2 = y[i+1]; + + // F.6.5: given x1,y1,x2,y2,fa,fs, compute cx,cy,theta1,dtheta + float x1_ = (float)Math.cos(phi) * (x1 - x2) / 2 + (float)Math.sin(phi) * (y1 - y2) / 2; + float y1_ = -1 * (float)Math.sin(phi) * (x1 - x2) / 2 + (float)Math.cos(phi) * (y1 - y2) / 2; + float tmp = (float)Math.sqrt((rx * rx * ry * ry - rx * rx * y1_ * y1_ - ry * ry * x1_ * x1_) / + (rx * rx * y1_ * y1_ + ry * ry * x1_ * x1_)); + float cx_ = (fa == fs ? -1 : 1) * tmp * (rx * y1_ / ry); + float cy_ = (fa == fs ? -1 : 1) * -1 * tmp * (ry * x1_ / rx); + float cx = (float)Math.cos(phi) * cx_ - (float)Math.sin(phi) * cy_ + (x1 + x2) / 2; + float cy = (float)Math.sin(phi) * cx_ + (float)Math.cos(phi) * cy_ + (y1 + y2) / 2; + + // F.6.4 Conversion from center to endpoint parameterization + float ux = 1, uy = 0, vx = (x1_ - cx_) / rx, vy = (y1_ - cy_) / ry; + float det = ux * vy - uy * vx; + float theta1 = (det < 0 ? -1 : 1) * + (float)Math.acos((ux * vx + uy * vy) / + ((float)Math.sqrt(ux * ux + uy * uy) * (float)Math.sqrt(vx * vx + vy * vy))); + ux = (x1_ - cx_) / rx; uy = (y1_ - cy_) / ry; + vx = (-1 * x1_ - cx_) / rx; vy = (-1 * y1_ - cy_) / ry; + det = ux * vy - uy * vx; + float dtheta = (det < 0 ? -1 : 1) * + (float)Math.acos((ux * vx + uy * vy) / + ((float)Math.sqrt(ux * ux + uy * uy) * (float)Math.sqrt(vx * vx + vy * vy))); + dtheta = dtheta % (float)(2 * Math.PI); + + if (fs == 0 && dtheta > 0) theta1 -= 2 * PI; + if (fs == 1 && dtheta < 0) theta1 += 2 * PI; + + if (fa == 1 && dtheta < 0) dtheta = 2 * PI + dtheta; + else if (fa == 1 && dtheta > 0) dtheta = -1 * (2 * PI - dtheta); + + // FIXME: integrate F.6.6 + // FIXME: isn't quite ending where it should... + + // F.6.3: Parameterization alternatives + float theta = theta1; + for(int j=0; j> 1; - float fs = ((int)c2y[i]) & 1; - float x1 = x[i]; - float y1 = y[i]; - float x2 = x[i+1]; - float y2 = y[i+1]; - - // F.6.5: given x1,y1,x2,y2,fa,fs, compute cx,cy,theta1,dtheta - float x1_ = (float)Math.cos(phi) * (x1 - x2) / 2 + (float)Math.sin(phi) * (y1 - y2) / 2; - float y1_ = -1 * (float)Math.sin(phi) * (x1 - x2) / 2 + (float)Math.cos(phi) * (y1 - y2) / 2; - float tmp = (float)Math.sqrt((rx * rx * ry * ry - rx * rx * y1_ * y1_ - ry * ry * x1_ * x1_) / - (rx * rx * y1_ * y1_ + ry * ry * x1_ * x1_)); - float cx_ = (fa == fs ? -1 : 1) * tmp * (rx * y1_ / ry); - float cy_ = (fa == fs ? -1 : 1) * -1 * tmp * (ry * x1_ / rx); - float cx = (float)Math.cos(phi) * cx_ - (float)Math.sin(phi) * cy_ + (x1 + x2) / 2; - float cy = (float)Math.sin(phi) * cx_ + (float)Math.cos(phi) * cy_ + (y1 + y2) / 2; - - // F.6.4 Conversion from center to endpoint parameterization - float ux = 1, uy = 0, vx = (x1_ - cx_) / rx, vy = (y1_ - cy_) / ry; - float det = ux * vy - uy * vx; - float theta1 = (det < 0 ? -1 : 1) * - (float)Math.acos((ux * vx + uy * vy) / - ((float)Math.sqrt(ux * ux + uy * uy) * (float)Math.sqrt(vx * vx + vy * vy))); - ux = (x1_ - cx_) / rx; uy = (y1_ - cy_) / ry; - vx = (-1 * x1_ - cx_) / rx; vy = (-1 * y1_ - cy_) / ry; - det = ux * vy - uy * vx; - float dtheta = (det < 0 ? -1 : 1) * - (float)Math.acos((ux * vx + uy * vy) / - ((float)Math.sqrt(ux * ux + uy * uy) * (float)Math.sqrt(vx * vx + vy * vy))); - dtheta = dtheta % (float)(2 * Math.PI); - - if (fs == 0 && dtheta > 0) theta1 -= 2 * PI; - if (fs == 1 && dtheta < 0) theta1 += 2 * PI; - - if (fa == 1 && dtheta < 0) dtheta = 2 * PI + dtheta; - else if (fa == 1 && dtheta > 0) dtheta = -1 * (2 * PI - dtheta); - - // FIXME: integrate F.6.6 - // FIXME: isn't quite ending where it should... - - // F.6.3: Parameterization alternatives - float theta = theta1; - for(int j=0; j 0) ret.sort(0, ret.numedges - 1, false); - return ret; - } + if (ret.numedges > 0) ret.sort(0, ret.numedges - 1, false); + return ret; + } - protected void parseSingleCommandAndArguments(PathTokenizer t, char command, boolean relative) { - if (numvertices == 0 && command != 'm') throw new RuntimeException("first command MUST be an 'm'"); - if (numvertices > x.length - 2) { - float[] new_x = new float[x.length * 2]; System.arraycopy(x, 0, new_x, 0, x.length); x = new_x; - float[] new_y = new float[y.length * 2]; System.arraycopy(y, 0, new_y, 0, y.length); y = new_y; - } - switch(command) { + protected void parseSingleCommandAndArguments(Tokenizer t, char command, boolean relative) { + if (numvertices == 0 && command != 'm') throw new RuntimeException("first command MUST be an 'm'"); + if (numvertices > x.length - 2) { + float[] new_x = new float[x.length * 2]; System.arraycopy(x, 0, new_x, 0, x.length); x = new_x; + float[] new_y = new float[y.length * 2]; System.arraycopy(y, 0, new_y, 0, y.length); y = new_y; + } + switch(command) { case 'z': { int where; type[numvertices-1] = TYPE_LINETO; @@ -486,51 +321,48 @@ public final class VectorGraphics { default: // FIXME - } + } - /* - // invariant: after this loop, no two lines intersect other than at a vertex - // FIXME: cleanup - int index = numvertices - 2; - for(int i=0; i Math.min(x[i+1], x[i]) && _x < Math.max(x[i+1], x[i]) && - _x > Math.min(x[j+1], x[j]) && _x < Math.max(x[j+1], x[j])) { - // FIXME: something's not right in here. See if we can do without fracturing line 'i'. - for(int k = ++numvertices; k>i; k--) { x[k] = x[k - 1]; y[k] = y[k - 1]; } - x[i+1] = _x; - y[i+1] = _y; - x[numvertices] = x[numvertices - 1]; x[numvertices - 1] = _x; - y[numvertices] = y[numvertices - 1]; y[numvertices - 1] = _y; - edges[numedges++] = numvertices - 1; numvertices++; - index++; - break; // actually 'continue' the outermost loop - } - } - } - */ + if (_x > Math.min(x[i+1], x[i]) && _x < Math.max(x[i+1], x[i]) && + _x > Math.min(x[j+1], x[j]) && _x < Math.max(x[j+1], x[j])) { + // FIXME: something's not right in here. See if we can do without fracturing line 'i'. + for(int k = ++numvertices; k>i; k--) { x[k] = x[k - 1]; y[k] = y[k - 1]; } + x[i+1] = _x; + y[i+1] = _y; + x[numvertices] = x[numvertices - 1]; x[numvertices - 1] = _x; + y[numvertices] = y[numvertices - 1]; y[numvertices - 1] = _y; + edges[numedges++] = numvertices - 1; numvertices++; + index++; + break; // actually 'continue' the outermost loop + } + } + } + */ - } } - - // Rasterized Vector Path ////////////////////////////////////////////////////////////////////////////// /** a vector path */ - public static class RasterPath { + public static class Raster { // the vertices of this path int[] x = new int[DEFAULT_PATHLEN]; @@ -658,7 +490,7 @@ public final class VectorGraphics { } ratio = actualLength / segLength; } - PathTokenizer pt = new PathTokenizer(dashArray); + Tokenizer pt = new Tokenizer(dashArray); Vector v = new Vector(); while (pt.hasMoreTokens()) v.addElement(new Float(pt.parseFloat())); float[] dashes = new float[v.size() % 2 == 0 ? v.size() : 2 * v.size()]; @@ -702,113 +534,6 @@ public final class VectorGraphics { return ret; } } - - - // Paint ////////////////////////////////////////////////////////////////////////////// - public static interface Paint { - public abstract void - fillTrapezoid(int tx1, int tx2, int ty1, int tx3, int tx4, int ty2, PixelBuffer buf); - } - - public static class SingleColorPaint implements Paint { - int color; - public SingleColorPaint(int color) { this.color = color; } - public void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, PixelBuffer buf) { - buf.fillTrapezoid(x1, x2, y1, x3, x4, y2, color); - } - } } - - - - - - - - - - /* - public static abstract class GradientPaint extends Paint { - public GradientPaint(boolean reflect, boolean repeat, Affine gradientTransform, - int[] stop_colors, float[] stop_offsets) { - this.reflect = reflect; this.repeat = repeat; - this.gradientTransform = gradientTransform; - this.stop_colors = stop_colors; - this.stop_offsets = stop_offsets; - } - Affine gradientTransform = Affine.identity(); - boolean useBoundingBox = false; // FIXME not supported - boolean patternUseBoundingBox = false; // FIXME not supported - - // it's invalid for both of these to be true - boolean reflect = false; // FIXME not supported - boolean repeat = false; // FIXME not supported - int[] stop_colors; - float[] stop_offsets; - - public void fillTrapezoid(float tx1, float tx2, float ty1, float tx3, float tx4, float ty2, PixelBuffer buf) { - Affine a = buf.a; - Affine inverse = a.copy().invert(); - float slope1 = (tx3 - tx1) / (ty2 - ty1); - float slope2 = (tx4 - tx2) / (ty2 - ty1); - for(float y=ty1; y _x2) { float _x0 = _x1; _x1 = _x2; _x2 = _x0; } - - for(float x=_x1; x<_x2; x++) { - - float distance = isLinear ? - // length of projection of onto the gradient vector == { \dot {grad \over |grad|}} - (x * (x2 - x1) + y * (y2 - y1)) / (float)Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) : - - // radial form is simple! FIXME, not quite right - (float)Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)); - - // FIXME: offsets are 0..1, not 0..length(gradient) - int i = 0; for(; i= stop_offsets.length) continue; - - // gradate from offsets[i - 1] to offsets[i] - float percentage = ((distance - stop_offsets[i - 1]) / (stop_offsets[i] - stop_offsets[i - 1])); - - int a = (int)((((stop_colors[i] >> 24) & 0xff) - ((stop_colors[i - 1] >> 24) & 0xff)) * percentage) + - ((stop_colors[i - 1] >> 24) & 0xff); - int r = (int)((((stop_colors[i] >> 16) & 0xff) - ((stop_colors[i - 1] >> 16) & 0xff)) * percentage) + - ((stop_colors[i - 1] >> 16) & 0xff); - int g = (int)((((stop_colors[i] >> 8) & 0xff) - ((stop_colors[i - 1] >> 8) & 0xff)) * percentage) + - ((stop_colors[i - 1] >> 8) & 0xff); - int b = (int)((((stop_colors[i] >> 0) & 0xff) - ((stop_colors[i - 1] >> 0) & 0xff)) * percentage) + - ((stop_colors[i - 1] >> 0) & 0xff); - int argb = (a << 24) | (r << 16) | (g << 8) | b; - buf.drawPoint((int)x, (int)Math.floor(y), argb); - } - } - } - } - - public static class LinearGradientPaint extends GradientPaint { - public LinearGradientPaint(float x1, float y1, float x2, float y2, boolean reflect, boolean repeat, - Affine gradientTransform, int[] stop_colors, float[] stop_offsets) { - super(reflect, repeat, gradientTransform, stop_colors, stop_offsets); - this.x1 = x1; this.x2 = x2; this.y1 = y1; this.y2 = y2; - } - float x1 = 0, y1 = 0, x2 = 300, y2 = 300; - } - - public static class RadialGradientPaint extends GradientPaint { - public RadialGradientPaint(float cx, float cy, float fx, float fy, float r, boolean reflect, boolean repeat, - Affine gradientTransform, int[] stop_colors, float[] stop_offsets) { - super(reflect, repeat, gradientTransform, stop_colors, stop_offsets); - this.cx = cx; this.cy = cy; this.fx = fx; this.fy = fy; this.r = r; - } - - float cx, cy, r, fx, fy; - - } - */ - diff --git a/src/org/ibex/graphics/Picture.java b/src/org/ibex/graphics/Picture.java index d1abf61..528b0d7 100644 --- a/src/org/ibex/graphics/Picture.java +++ b/src/org/ibex/graphics/Picture.java @@ -1,9 +1,10 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.graphics; import java.io.*; import org.ibex.js.*; +import org.ibex.plat.*; import org.ibex.util.*; -import org.ibex.translators.*; +import org.ibex.core.*; /** * The in-memory representation of a PNG or GIF image. It is @@ -30,7 +31,7 @@ public class Picture { protected void loaded() { isLoaded = true; } /** turns a stream into a Picture.Source and passes it to the callback */ - public static Picture load(final JS stream, final Scheduler.Task callback) { + public static Picture load(final JS stream, final Task callback) { Picture ret = (Picture)cache.get(stream); if (ret == null) cache.put(stream, ret = Platform.createPicture(stream)); final Picture p = ret; diff --git a/src/org/ibex/graphics/PixelBuffer.java b/src/org/ibex/graphics/PixelBuffer.java index 1434301..6107f71 100644 --- a/src/org/ibex/graphics/PixelBuffer.java +++ b/src/org/ibex/graphics/PixelBuffer.java @@ -1,5 +1,5 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.graphics; /** *

@@ -22,7 +22,7 @@ package org.ibex; public abstract class PixelBuffer { /** draw the picture at (dx1, dy1), cropping to (cx1, cy1, cx2, cy2) */ - protected abstract void drawPicture(Picture source, int dx1, int dy1, int cx1, int cy1, int cx2, int cy2); + public abstract void drawPicture(Picture source, int dx1, int dy1, int cx1, int cy1, int cx2, int cy2); /** fill a trapezoid whose top and bottom edges are horizontal */ public abstract void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int color); diff --git a/src/org/ibex/graphics/SVG.java b/src/org/ibex/graphics/SVG.java index b8f73f9..90311a6 100644 --- a/src/org/ibex/graphics/SVG.java +++ b/src/org/ibex/graphics/SVG.java @@ -1,7 +1,33 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex.translators; +package org.ibex.graphics; import java.util.*; + +// FIXME: offer a "subpixel" mode where we pass floats to the Platform and don't do any snapping +// FIXME: fracture when realizing instead of when parsing? + +/* + v1.0 + - textpath + - gradients + - patterns + - clipping/masking + - filters (filtering of a group must be performed AFTER the group is assembled; sep. canvas) + + v1.1 + - bump caps [requires Paint that can fill circles...] [remember to distinguish between closed/unclosed] + - line joins + - mitre (hard) + - bevel (easy) + - bump (easy, but requires 'round' Paint) + - subtree sharing? otherwise the memory consumption might be outrageous... clone="" attribute? + - better clipping + - intersect clip regions (linearity) + - clip on trapezoids, not pixels + - faster gradients and patterns: + - transform each corner of the trapezoid and then interpolate +*/ + // FIXME: need to support style sheets and the 'style=' attribute // FIXME: need to convert markers into subboxes public class SVG { @@ -272,157 +298,4 @@ public class SVG { } */ - - /** Copied verbatim from the SVG specification */ - public static Hashtable colors = new Hashtable(400); - static { - colors.put("aliceblue", new Integer((240 << 16) | (248 << 8) | 255)); - colors.put("antiquewhite", new Integer((250 << 16) | (235 << 8) | 215)); - colors.put("aqua", new Integer((0 << 16) | (255 << 8) | 255)); - colors.put("aquamarine", new Integer((127 << 16) | (255 << 8) | 212)); - colors.put("azure", new Integer((240 << 16) | (255 << 8) | 255)); - colors.put("beige", new Integer((245 << 16) | (245 << 8) | 220)); - colors.put("bisque", new Integer((255 << 16) | (228 << 8) | 196)); - colors.put("black", new Integer((0 << 16) | (0 << 8) | 0)); - colors.put("blanchedalmond", new Integer((255 << 16) | (235 << 8) | 205)); - colors.put("blue", new Integer((0 << 16) | (0 << 8) | 255)); - colors.put("blueviolet", new Integer((138 << 16) | (43 << 8) | 226)); - colors.put("brown", new Integer((165 << 16) | (42 << 8) | 42)); - colors.put("burlywood", new Integer((222 << 16) | (184 << 8) | 135)); - colors.put("cadetblue", new Integer((95 << 16) | (158 << 8) | 160)); - colors.put("chartreuse", new Integer((127 << 16) | (255 << 8) | 0)); - colors.put("chocolate", new Integer((210 << 16) | (105 << 8) | 30)); - colors.put("coral", new Integer((255 << 16) | (127 << 8) | 80)); - colors.put("cornflowerblue", new Integer((100 << 16) | (149 << 8) | 237)); - colors.put("cornsilk", new Integer((255 << 16) | (248 << 8) | 220)); - colors.put("crimson", new Integer((220 << 16) | (20 << 8) | 60)); - colors.put("cyan", new Integer((0 << 16) | (255 << 8) | 255)); - colors.put("darkblue", new Integer((0 << 16) | (0 << 8) | 139)); - colors.put("darkcyan", new Integer((0 << 16) | (139 << 8) | 139)); - colors.put("darkgoldenrod", new Integer((184 << 16) | (134 << 8) | 11)); - colors.put("darkgray", new Integer((169 << 16) | (169 << 8) | 169)); - colors.put("darkgreen", new Integer((0 << 16) | (100 << 8) | 0)); - colors.put("darkgrey", new Integer((169 << 16) | (169 << 8) | 169)); - colors.put("darkkhaki", new Integer((189 << 16) | (183 << 8) | 107)); - colors.put("darkmagenta", new Integer((139 << 16) | (0 << 8) | 139)); - colors.put("darkolivegreen", new Integer((85 << 16) | (107 << 8) | 47)); - colors.put("darkorange", new Integer((255 << 16) | (140 << 8) | 0)); - colors.put("darkorchid", new Integer((153 << 16) | (50 << 8) | 204)); - colors.put("darkred", new Integer((139 << 16) | (0 << 8) | 0)); - colors.put("darksalmon", new Integer((233 << 16) | (150 << 8) | 122)); - colors.put("darkseagreen", new Integer((143 << 16) | (188 << 8) | 143)); - colors.put("darkslateblue", new Integer((72 << 16) | (61 << 8) | 139)); - colors.put("darkslategray", new Integer((47 << 16) | (79 << 8) | 79)); - colors.put("darkslategrey", new Integer((47 << 16) | (79 << 8) | 79)); - colors.put("darkturquoise", new Integer((0 << 16) | (206 << 8) | 209)); - colors.put("darkviolet", new Integer((148 << 16) | (0 << 8) | 211)); - colors.put("deeppink", new Integer((255 << 16) | (20 << 8) | 147)); - colors.put("deepskyblue", new Integer((0 << 16) | (191 << 8) | 255)); - colors.put("dimgray", new Integer((105 << 16) | (105 << 8) | 105)); - colors.put("dimgrey", new Integer((105 << 16) | (105 << 8) | 105)); - colors.put("dodgerblue", new Integer((30 << 16) | (144 << 8) | 255)); - colors.put("firebrick", new Integer((178 << 16) | (34 << 8) | 34)); - colors.put("floralwhite", new Integer((255 << 16) | (250 << 8) | 240)); - colors.put("forestgreen", new Integer((34 << 16) | (139 << 8) | 34)); - colors.put("fuchsia", new Integer((255 << 16) | (0 << 8) | 255)); - colors.put("gainsboro", new Integer((220 << 16) | (220 << 8) | 220)); - colors.put("ghostwhite", new Integer((248 << 16) | (248 << 8) | 255)); - colors.put("gold", new Integer((255 << 16) | (215 << 8) | 0)); - colors.put("goldenrod", new Integer((218 << 16) | (165 << 8) | 32)); - colors.put("gray", new Integer((128 << 16) | (128 << 8) | 128)); - colors.put("grey", new Integer((128 << 16) | (128 << 8) | 128)); - colors.put("green", new Integer((0 << 16) | (128 << 8) | 0)); - colors.put("greenyellow", new Integer((173 << 16) | (255 << 8) | 47)); - colors.put("honeydew", new Integer((240 << 16) | (255 << 8) | 240)); - colors.put("hotpink", new Integer((255 << 16) | (105 << 8) | 180)); - colors.put("indianred", new Integer((205 << 16) | (92 << 8) | 92)); - colors.put("indigo", new Integer((75 << 16) | (0 << 8) | 130)); - colors.put("ivory", new Integer((255 << 16) | (255 << 8) | 240)); - colors.put("khaki", new Integer((240 << 16) | (230 << 8) | 140)); - colors.put("lavender", new Integer((230 << 16) | (230 << 8) | 250)); - colors.put("lavenderblush", new Integer((255 << 16) | (240 << 8) | 245)); - colors.put("lawngreen", new Integer((124 << 16) | (252 << 8) | 0)); - colors.put("lemonchiffon", new Integer((255 << 16) | (250 << 8) | 205)); - colors.put("lightblue", new Integer((173 << 16) | (216 << 8) | 230)); - colors.put("lightcoral", new Integer((240 << 16) | (128 << 8) | 128)); - colors.put("lightcyan", new Integer((224 << 16) | (255 << 8) | 255)); - colors.put("lightgoldenrodyellow", new Integer((250 << 16) | (250 << 8) | 210)); - colors.put("lightgray", new Integer((211 << 16) | (211 << 8) | 211)); - colors.put("lightgreen", new Integer((144 << 16) | (238 << 8) | 144)); - colors.put("lightgrey", new Integer((211 << 16) | (211 << 8) | 211)); - colors.put("lightpink", new Integer((255 << 16) | (182 << 8) | 193)); - colors.put("lightsalmon", new Integer((255 << 16) | (160 << 8) | 122)); - colors.put("lightseagreen", new Integer((32 << 16) | (178 << 8) | 170)); - colors.put("lightskyblue", new Integer((135 << 16) | (206 << 8) | 250)); - colors.put("lightslategray", new Integer((119 << 16) | (136 << 8) | 153)); - colors.put("lightslategrey", new Integer((119 << 16) | (136 << 8) | 153)); - colors.put("lightsteelblue", new Integer((176 << 16) | (196 << 8) | 222)); - colors.put("lightyellow", new Integer((255 << 16) | (255 << 8) | 224)); - colors.put("lime", new Integer((0 << 16) | (255 << 8) | 0)); - colors.put("limegreen", new Integer((50 << 16) | (205 << 8) | 50)); - colors.put("linen", new Integer((250 << 16) | (240 << 8) | 230)); - colors.put("magenta", new Integer((255 << 16) | (0 << 8) | 255)); - colors.put("maroon", new Integer((128 << 16) | (0 << 8) | 0)); - colors.put("mediumaquamarine", new Integer((102 << 16) | (205 << 8) | 170)); - colors.put("mediumblue", new Integer((0 << 16) | (0 << 8) | 205)); - colors.put("mediumorchid", new Integer((186 << 16) | (85 << 8) | 211)); - colors.put("mediumpurple", new Integer((147 << 16) | (112 << 8) | 219)); - colors.put("mediumseagreen", new Integer((60 << 16) | (179 << 8) | 113)); - colors.put("mediumslateblue", new Integer((123 << 16) | (104 << 8) | 238)); - colors.put("mediumspringgreen", new Integer((0 << 16) | (250 << 8) | 154)); - colors.put("mediumturquoise", new Integer((72 << 16) | (209 << 8) | 204)); - colors.put("mediumvioletred", new Integer((199 << 16) | (21 << 8) | 133)); - colors.put("midnightblue", new Integer((25 << 16) | (25 << 8) | 112)); - colors.put("mintcream", new Integer((245 << 16) | (255 << 8) | 250)); - colors.put("mistyrose", new Integer((255 << 16) | (228 << 8) | 225)); - colors.put("moccasin", new Integer((255 << 16) | (228 << 8) | 181)); - colors.put("navajowhite", new Integer((255 << 16) | (222 << 8) | 173)); - colors.put("navy", new Integer((0 << 16) | (0 << 8) | 128)); - colors.put("oldlace", new Integer((253 << 16) | (245 << 8) | 230)); - colors.put("olive", new Integer((128 << 16) | (128 << 8) | 0)); - colors.put("olivedrab", new Integer((107 << 16) | (142 << 8) | 35)); - colors.put("orange", new Integer((255 << 16) | (165 << 8) | 0)); - colors.put("orangered", new Integer((255 << 16) | (69 << 8) | 0)); - colors.put("orchid", new Integer((218 << 16) | (112 << 8) | 214)); - colors.put("palegoldenrod", new Integer((238 << 16) | (232 << 8) | 170)); - colors.put("palegreen", new Integer((152 << 16) | (251 << 8) | 152)); - colors.put("paleturquoise", new Integer((175 << 16) | (238 << 8) | 238)); - colors.put("palevioletred", new Integer((219 << 16) | (112 << 8) | 147)); - colors.put("papayawhip", new Integer((255 << 16) | (239 << 8) | 213)); - colors.put("peachpuff", new Integer((255 << 16) | (218 << 8) | 185)); - colors.put("peru", new Integer((205 << 16) | (133 << 8) | 63)); - colors.put("pink", new Integer((255 << 16) | (192 << 8) | 203)); - colors.put("plum", new Integer((221 << 16) | (160 << 8) | 221)); - colors.put("powderblue", new Integer((176 << 16) | (224 << 8) | 230)); - colors.put("purple", new Integer((128 << 16) | (0 << 8) | 128)); - colors.put("red", new Integer((255 << 16) | (0 << 8) | 0)); - colors.put("rosybrown", new Integer((188 << 16) | (143 << 8) | 143)); - colors.put("royalblue", new Integer((65 << 16) | (105 << 8) | 225)); - colors.put("saddlebrown", new Integer((139 << 16) | (69 << 8) | 19)); - colors.put("salmon", new Integer((250 << 16) | (128 << 8) | 114)); - colors.put("sandybrown", new Integer((244 << 16) | (164 << 8) | 96)); - colors.put("seagreen", new Integer((46 << 16) | (139 << 8) | 87)); - colors.put("seashell", new Integer((255 << 16) | (245 << 8) | 238)); - colors.put("sienna", new Integer((160 << 16) | (82 << 8) | 45)); - colors.put("silver", new Integer((192 << 16) | (192 << 8) | 192)); - colors.put("skyblue", new Integer((135 << 16) | (206 << 8) | 235)); - colors.put("slateblue", new Integer((106 << 16) | (90 << 8) | 205)); - colors.put("slategray", new Integer((112 << 16) | (128 << 8) | 144)); - colors.put("slategrey", new Integer((112 << 16) | (128 << 8) | 144)); - colors.put("snow", new Integer((255 << 16) | (250 << 8) | 250)); - colors.put("springgreen", new Integer((0 << 16) | (255 << 8) | 127)); - colors.put("steelblue", new Integer((70 << 16) | (130 << 8) | 180)); - colors.put("tan", new Integer((210 << 16) | (180 << 8) | 140)); - colors.put("teal", new Integer((0 << 16) | (128 << 8) | 128)); - colors.put("thistle", new Integer((216 << 16) | (191 << 8) | 216)); - colors.put("tomato", new Integer((255 << 16) | (99 << 8) | 71)); - colors.put("turquoise", new Integer((64 << 16) | (224 << 8) | 208)); - colors.put("violet", new Integer((238 << 16) | (130 << 8) | 238)); - colors.put("wheat", new Integer((245 << 16) | (222 << 8) | 179)); - colors.put("white", new Integer((255 << 16) | (255 << 8) | 255)); - colors.put("whitesmoke", new Integer((245 << 16) | (245 << 8) | 245)); - colors.put("yellow", new Integer((255 << 16) | (255 << 8) | 0)); - colors.put("yellowgreen", new Integer((154 << 16) | (205 << 8) | 50)); - } - } diff --git a/src/org/ibex/graphics/Surface.java b/src/org/ibex/graphics/Surface.java index 7e23169..b9207bb 100644 --- a/src/org/ibex/graphics/Surface.java +++ b/src/org/ibex/graphics/Surface.java @@ -1,8 +1,11 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.graphics; import org.ibex.js.*; import org.ibex.util.*; +import org.ibex.plat.*; + +import org.ibex.core.*; // FIXME /** * A Surface, as described in the Ibex Reference. @@ -10,7 +13,7 @@ import org.ibex.util.*; * Platform subclasses should include an inner class subclass of * Surface to return from the Platform._createSurface() method */ -public abstract class Surface extends PixelBuffer implements Scheduler.Task { +public abstract class Surface extends PixelBuffer implements Task { // Static Data //////////////////////////////////////////////////////////////////////////////// @@ -21,12 +24,12 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { public static Vec allSurfaces = new Vec(); /** When set to true, render() should abort as soon as possible and restart the rendering process */ - volatile boolean abort = false; + public volatile boolean abort = false; // these three variables are used to ensure that user resizes trump programmatic resizes - volatile boolean syncRootBoxToSurface = false; - volatile int pendingWidth = 0; - volatile int pendingHeight = 0; + public volatile boolean syncRootBoxToSurface = false; + public volatile int pendingWidth = 0; + public volatile int pendingHeight = 0; public static boolean alt = false; ///< true iff the alt button is pressed down public static boolean control = false; ///< true iff the control button is pressed down @@ -74,6 +77,7 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { public void setMinimumSize(int minx, int miny, boolean resizable) { } protected void setSize(int w, int h) { _setSize(w, h); } + public static Picture scarImage = null; // Helper methods for subclasses //////////////////////////////////////////////////////////// @@ -88,7 +92,7 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { if (button == 1) new Message("_Press1", T, root); else if (button == 2) new Message("_Press2", T, root); else if (button == 3) { - Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn { + Scheduler.add(new Task() { public void perform() throws JSExn { Platform.clipboardReadEnabled = true; try { root.putAndTriggerTraps("_Press3", T); @@ -126,7 +130,7 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { } /** we enqueue ourselves in the Scheduler when we have a Move message to deal with */ - private Scheduler.Task mover = new Scheduler.Task() { + private Task mover = new Task() { public void perform() { if (mousex == newmousex && mousey == newmousey) return; int oldmousex = mousex; mousex = newmousex; @@ -167,7 +171,7 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { // FEATURE: can we avoid creating objects here? protected final void PosChange(final int x, final int y) { - Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn { + Scheduler.add(new Task() { public void perform() throws JSExn { root.x = x; root.y = y; root.putAndTriggerTrapsAndCatchExceptions("PosChange", T); @@ -220,15 +224,15 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { public Surface(Box root) { this.root = root; - root.setMaxWidth(JS.N(Math.min(Platform.getScreenWidth(), root.maxwidth))); - root.setMaxHeight(JS.N(Math.min(Platform.getScreenHeight(), root.maxheight))); + root.setWidth(root.minwidth, Math.min(Platform.getScreenWidth(), root.maxwidth)); + root.setHeight(root.minheight, Math.min(Platform.getScreenHeight(), root.maxheight)); Surface old = fromBox(root); if (old != null) old.dispose(false); else root.removeSelf(); Refresh(); } - private static VectorGraphics.Affine identity = VectorGraphics.Affine.identity(); + private static Affine identity = Affine.identity(); /** runs the prerender() and render() pipelines in the root Box to regenerate the backbuffer, then blits it to the screen */ public synchronized void render() { @@ -238,14 +242,14 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { abort = false; root.pack(); if (syncRootBoxToSurface) { - root.setMaxWidth(JS.N(pendingWidth)); - root.setMaxHeight(JS.N(pendingHeight)); + root.setWidth(root.minwidth, pendingWidth); + root.setHeight(root.minheight, pendingHeight); syncRootBoxToSurface = false; } if (root.maxwidth != root.width || root.maxheight != root.height) { // dirty the place where the scar used to be and where it is now - dirty(0, root.height - Main.scarImage.height, Main.scarImage.width, Main.scarImage.height); - dirty(0, root.maxheight - Main.scarImage.height, Main.scarImage.width, Main.scarImage.height); + dirty(0, root.height - scarImage.height, scarImage.width, scarImage.height); + dirty(0, root.maxheight - scarImage.height, scarImage.width, scarImage.height); } root.reflow(); setSize(root.width, root.height); @@ -266,7 +270,7 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { if (w <= 0 || h <= 0) continue; root.render(0, 0, x, y, x + w, y + h, this, identity); - drawPicture(Main.scarImage, 0, root.height - Main.scarImage.height, x, y, x+w, y+h); + drawPicture(scarImage, 0, root.height - scarImage.height, x, y, x+w, y+h); if (abort) { // x,y,w,h is only partially reconstructed, so we must be careful not to re-blit it @@ -281,7 +285,7 @@ public abstract class Surface extends PixelBuffer implements Scheduler.Task { } // FEATURE: reinstate recycler - public class Message implements Scheduler.Task { + public class Message implements Task { private Box boxContainingMouse; private Object value; diff --git a/src/org/ibex/js/JS.java b/src/org/ibex/js/JS.java index de60d0c..9a54710 100644 --- a/src/org/ibex/js/JS.java +++ b/src/org/ibex/js/JS.java @@ -69,7 +69,7 @@ public class JS extends org.ibex.util.BalancedTree { return new JS.UnpauseCallback(i); } - public static class UnpauseCallback implements Scheduler.Task { + public static class UnpauseCallback implements Task { Interpreter i; UnpauseCallback(Interpreter i) { this.i = i; } public void perform() throws JSExn { unpause(null); } diff --git a/src/org/ibex/js/JSFunction.java b/src/org/ibex/js/JSFunction.java index 1455d38..4bf41e4 100644 --- a/src/org/ibex/js/JSFunction.java +++ b/src/org/ibex/js/JSFunction.java @@ -2,9 +2,10 @@ package org.ibex.js; import java.io.*; +import org.ibex.util.*; /** A JavaScript function, compiled into bytecode */ -class JSFunction extends JS implements ByteCodes, Tokens, org.ibex.Scheduler.Task { +class JSFunction extends JS implements ByteCodes, Tokens, Task { // Fields and Accessors /////////////////////////////////////////////// diff --git a/src/org/ibex/js/Stream.java b/src/org/ibex/js/Stream.java index 878afa3..05045e9 100644 --- a/src/org/ibex/js/Stream.java +++ b/src/org/ibex/js/Stream.java @@ -1,11 +1,11 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.js; import java.io.*; import java.util.zip.*; -import org.ibex.js.*; import org.ibex.util.*; -import org.ibex.translators.MSPack; +import org.ibex.plat.*; +import org.ibex.net.*; /** * Essentiall an InputStream "factory". You can repeatedly ask a @@ -32,24 +32,24 @@ public abstract class Stream extends JS.Cloneable { // Private Interface ////////////////////////////////////////////////////////////////////////////// - protected abstract InputStream getInputStream() throws IOException; + public abstract InputStream getInputStream() throws IOException; protected String getCacheKey() throws NotCacheableException { throw new NotCacheableException(); } /** HTTP or HTTPS resource */ public static class HTTP extends Stream { private String url; public String toString() { return "Stream.HTTP:" + url; } - HTTP(String url) { while (url.endsWith("/")) url = url.substring(0, url.length() - 1); this.url = url; } + public HTTP(String url) { while (url.endsWith("/")) url = url.substring(0, url.length() - 1); this.url = url; } public Object _get(Object key) { return new HTTP(url + "/" + (String)key); } public String getCacheKey(Vec path) throws NotCacheableException { return url; } - public InputStream getInputStream() throws IOException { return new org.ibex.HTTP(url).GET(); } + public InputStream getInputStream() throws IOException { return new org.ibex.net.HTTP(url).GET(); } } /** byte arrays */ public static class ByteArray extends Stream { private byte[] bytes; private String cacheKey; - ByteArray(byte[] bytes, String cacheKey) { this.bytes = bytes; this.cacheKey = cacheKey; } + public ByteArray(byte[] bytes, String cacheKey) { this.bytes = bytes; this.cacheKey = cacheKey; } public String getCacheKey() throws NotCacheableException { if (cacheKey == null) throw new NotCacheableException(); return cacheKey; } public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(bytes); } @@ -58,7 +58,7 @@ public abstract class Stream extends JS.Cloneable { /** a file */ public static class File extends Stream { private String path; - File(String path) { this.path = path; } + public File(String path) { this.path = path; } public String toString() { return "file:" + path; } public String getCacheKey() throws NotCacheableException { throw new NotCacheableException(); /* already on disk */ } public InputStream getInputStream() throws IOException { return new FileInputStream(path); } @@ -69,8 +69,8 @@ public abstract class Stream extends JS.Cloneable { public static class Zip extends Stream { private Stream parent; private String path; - Zip(Stream parent) { this(parent, null); } - Zip(Stream parent, String path) { + public Zip(Stream parent) { this(parent, null); } + public Zip(Stream parent, String path) { while(path != null && path.startsWith("/")) path = path.substring(1); this.parent = parent; this.path = path; @@ -91,8 +91,8 @@ public abstract class Stream extends JS.Cloneable { public static class Cab extends Stream { private Stream parent; private String path; - Cab(Stream parent) { this(parent, null); } - Cab(Stream parent, String path) { this.parent = parent; this.path = path; } + public Cab(Stream parent) { this(parent, null); } + public Cab(Stream parent, String path) { this.parent = parent; this.path = path; } public String getCacheKey() throws NotCacheableException { return parent.getCacheKey() + "!cab:"; } public Object _get(Object key) { return new Cab(parent, path==null?(String)key:path+'/'+(String)key); } public InputStream getInputStream() throws IOException { return new MSPack(parent.getInputStream()).getInputStream(path); } @@ -108,7 +108,7 @@ public abstract class Stream extends JS.Cloneable { public static class ProgressWatcher extends Stream { final Stream watchee; JS callback; - ProgressWatcher(Stream watchee, JS callback) { this.watchee = watchee; this.callback = callback; } + public ProgressWatcher(Stream watchee, JS callback) { this.watchee = watchee; this.callback = callback; } public String getCacheKey() throws NotCacheableException { return watchee.getCacheKey(); } public InputStream getInputStream() throws IOException { final InputStream is = watchee.getInputStream(); @@ -122,7 +122,7 @@ public abstract class Stream extends JS.Cloneable { 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 void perform() throws IOException, JSExn { + Scheduler.add(new Task() { public void perform() throws IOException, JSExn { callback.call(N(bytesDownloaded), N(is instanceof KnownLength ? ((KnownLength)is).getLength() : 0), null, null, 2); } }); @@ -147,7 +147,7 @@ public abstract class Stream extends JS.Cloneable { if (!disk) { cis = new CachedInputStream(parent.getInputStream()); } else { - java.io.File f = LocalStorage.Cache.getCacheFileForKey(key); + java.io.File f = org.ibex.core.LocalStorage.Cache.getCacheFileForKey(key); if (f.exists()) return new FileInputStream(f); cis = new CachedInputStream(parent.getInputStream(), f); } diff --git a/src/org/ibex/net/HTTP.java b/src/org/ibex/net/HTTP.java index 10da62b..0142a9e 100644 --- a/src/org/ibex/net/HTTP.java +++ b/src/org/ibex/net/HTTP.java @@ -1,13 +1,14 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.net; import java.net.*; import java.io.*; import java.util.*; import org.ibex.js.*; import org.ibex.util.*; -import org.bouncycastle.util.encoders.Base64; -import org.bouncycastle.crypto.digests.*; +import org.ibex.plat.*; +import org.ibex.core.*; +import org.ibex.crypto.*; /** * This object encapsulates a *single* HTTP connection. Multiple requests may be pipelined over a connection (thread-safe), @@ -638,7 +639,7 @@ public class HTTP { private String H(String s) throws IOException { byte[] b = s.getBytes("UTF8"); - MD5Digest md5 = new MD5Digest(); + MD5 md5 = new MD5(); md5.update(b, 0, b.length); byte[] out = new byte[md5.getDigestSize()]; md5.doFinal(out, 0); @@ -783,7 +784,7 @@ public class HTTP { if (authorization != oldAuth) return; if (Log.on) Log.info(Authorization.class, "displaying proxy authorization dialog"); - Scheduler.add(new Scheduler.Task() { + Scheduler.add(new Task() { public void perform() throws IOException, JSExn { Box b = new Box(); Template t = null; @@ -1021,7 +1022,7 @@ public class HTTP { public static byte[] getNTLM2SessionResponse(String password, byte[] challenge, byte[] clientChallenge) throws UnsupportedEncodingException { byte[] ntlmHash = ntlmHash(password); - MD5Digest md5 = new MD5Digest(); + MD5 md5 = new MD5(); md5.update(challenge, 0, challenge.length); md5.update(clientChallenge, 0, clientChallenge.length); byte[] sessionHash = new byte[8]; @@ -1070,11 +1071,15 @@ public class HTTP { * of the NTLM Response and the NTLMv2 and LMv2 Hashes. */ private static byte[] ntlmHash(String password) throws UnsupportedEncodingException { + // FIXME + /* byte[] unicodePassword = password.getBytes("UnicodeLittleUnmarked"); - MD4Digest md4 = new MD4Digest(); + MD4 md4 = new MD4(); md4.update(unicodePassword, 0, unicodePassword.length); byte[] ret = new byte[md4.getDigestSize()]; return ret; + */ + return null; } /** @@ -1231,14 +1236,14 @@ public class HTTP { byte[] content = new byte[data.length + 64]; System.arraycopy(ipad, 0, content, 0, 64); System.arraycopy(data, 0, content, 64, data.length); - MD5Digest md5 = new MD5Digest(); + MD5 md5 = new MD5(); md5.update(content, 0, content.length); data = new byte[md5.getDigestSize()]; md5.doFinal(data, 0); content = new byte[data.length + 64]; System.arraycopy(opad, 0, content, 0, 64); System.arraycopy(data, 0, content, 64, data.length); - md5 = new MD5Digest(); + md5 = new MD5(); md5.update(content, 0, content.length); byte[] ret = new byte[md5.getDigestSize()]; md5.doFinal(ret, 0); diff --git a/src/org/ibex/net/SOAP.java b/src/org/ibex/net/SOAP.java index 946ccb7..85670a3 100644 --- a/src/org/ibex/net/SOAP.java +++ b/src/org/ibex/net/SOAP.java @@ -1,11 +1,11 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.net; import java.io.*; import java.util.*; import org.ibex.js.*; import org.ibex.util.*; -import org.bouncycastle.util.encoders.Base64; +import org.ibex.crypto.*; /** * A partial RPC-style SOAP 1.1 client. Implemented from the SOAP 1.1 @@ -18,7 +18,7 @@ import org.bouncycastle.util.encoders.Base64; *

  • WSDL support * */ -class SOAP extends XMLRPC { +public class SOAP extends XMLRPC { /** the desired content of the SOAPAction header */ String action = null; @@ -268,12 +268,12 @@ class SOAP extends XMLRPC { return content.toString(); } - SOAP(String url, String methodname, String action, String nameSpace) { + public SOAP(String url, String methodname, String action, String nameSpace) { super(url, methodname); this.action = action; this.nameSpace = nameSpace; } - SOAP(String url, String methodname, SOAP httpSource, String action, String nameSpace) { + public SOAP(String url, String methodname, SOAP httpSource, String action, String nameSpace) { super(url, methodname, httpSource); this.action = action; this.nameSpace = nameSpace; diff --git a/src/org/ibex/net/XMLRPC.java b/src/org/ibex/net/XMLRPC.java index 607d34e..14aacb5 100644 --- a/src/org/ibex/net/XMLRPC.java +++ b/src/org/ibex/net/XMLRPC.java @@ -1,11 +1,11 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.net; import java.io.*; import java.util.*; import org.ibex.js.*; import org.ibex.util.*; -import org.bouncycastle.util.encoders.Base64; +import org.ibex.crypto.*; /** * An XML-RPC client implemented as a JavaScript Host Object. See the @@ -29,7 +29,7 @@ import org.bouncycastle.util.encoders.Base64; * convert. * */ -class XMLRPC extends JS { +public class XMLRPC extends JS { public XMLRPC(String url, String method) { this.http = url.startsWith("stdio:") ? HTTP.stdio : new HTTP(url); @@ -329,20 +329,20 @@ class XMLRPC extends JS { try { new Helper().parse(br); final Object result = fault ? new JSExn(objects.elementAt(0)) : objects.size() == 0 ? null : objects.elementAt(0); - Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn { callback.unpause(result); }}); + Scheduler.add(new Task() { public void perform() throws JSExn { callback.unpause(result); }}); } finally { tracker.clear(); objects.setSize(0); } } catch (final JSExn e) { final Exception e2 = e; - Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn { callback.unpause(e2); }}); + Scheduler.add(new Task() { public void perform() throws JSExn { callback.unpause(e2); }}); } catch (final IOException e) { final Exception e2 = e; - Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn { callback.unpause(new JSExn(e2)); }}); + Scheduler.add(new Task() { public void perform() throws JSExn { callback.unpause(new JSExn(e2)); }}); } catch (final XML.Exn e) { final Exception e2 = e; - Scheduler.add(new Scheduler.Task() { public void perform() throws JSExn { callback.unpause(new JSExn(e2)); }}); + Scheduler.add(new Task() { public void perform() throws JSExn { callback.unpause(new JSExn(e2)); }}); } } } diff --git a/src/org/ibex/plat/AWT.java b/src/org/ibex/plat/AWT.java index c7a1dce..8c8956d 100644 --- a/src/org/ibex/plat/AWT.java +++ b/src/org/ibex/plat/AWT.java @@ -9,6 +9,9 @@ import java.awt.*; import java.awt.datatransfer.*; import java.awt.image.*; import java.awt.event.*; +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.net.*; /** Platform subclass for all VM's providing AWT 1.1 functionality */ public class AWT extends JVM { @@ -113,8 +116,8 @@ public class AWT extends JVM { // Inner Classes ///////////////////////////////////////////////////////////////////////////////////// - protected org.ibex.Font.Glyph _createGlyph(org.ibex.Font f, char c) { return new AWTGlyph(f, c); } - protected static class AWTGlyph extends org.ibex.Font.Glyph { + protected org.ibex.graphics.Font.Glyph _createGlyph(org.ibex.graphics.Font f, char c) { return new AWTGlyph(f, c); } + protected static class AWTGlyph extends org.ibex.graphics.Font.Glyph { private Image i = null; private static ColorModel cmodel = new DirectColorModel(32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); @@ -128,7 +131,7 @@ public class AWT extends JVM { }; */ - public AWTGlyph(org.ibex.Font f, char c) { super(f, c); } + public AWTGlyph(org.ibex.graphics.Font f, char c) { super(f, c); } Image getImage() { if (i == null && isLoaded) { @@ -213,11 +216,11 @@ public class AWT extends JVM { } /** implemented with java.awt 1.1's setXORMode() */ - public void drawGlyph(org.ibex.Font.Glyph source, int dx, int dy, int cx1, int cy1, int cx2, int cy2, int rgb) { + public void drawGlyph(org.ibex.graphics.Font.Glyph source, int dx, int dy, int cx1, int cy1, int cx2, int cy2, int rgb) { // XOR the target region - g.setXORMode(new Color((rgb & 0x00ff0000) >> 16, (rgb & 0x0000ff00) >> 8, rgb & 0x000000ff)); - g.setColor(new Color(0x0, 0x0, 0x0)); + g.setXORMode(new java.awt.Color((rgb & 0x00ff0000) >> 16, (rgb & 0x0000ff00) >> 8, rgb & 0x000000ff)); + g.setColor(new java.awt.Color(0x0, 0x0, 0x0)); g.fillRect(cx1, cy1, cx2 - cx1, cy2 - cy1); // blacken the area we want the glyph to cover @@ -227,8 +230,8 @@ public class AWT extends JVM { g.setClip(0, 0, i.getWidth(null), i.getHeight(null)); // XOR back, turning black into the chosen rgb color - g.setXORMode(new Color((rgb & 0x00ff0000) >> 16, (rgb & 0x0000ff00) >> 8, rgb & 0x000000ff)); - g.setColor(new Color(0x0, 0x0, 0x0)); + g.setXORMode(new java.awt.Color((rgb & 0x00ff0000) >> 16, (rgb & 0x0000ff00) >> 8, rgb & 0x000000ff)); + g.setColor(new java.awt.Color(0x0, 0x0, 0x0)); g.fillRect(cx1, cy1, cx2 - cx1, cy2 - cy1); // restore the graphics context @@ -237,7 +240,7 @@ public class AWT extends JVM { // FIXME: try to use os acceleration public void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int argb) { - g.setColor(new Color((argb & 0x00FF0000) >> 16, (argb & 0x0000FF00) >> 8, (argb & 0x000000FF))); + g.setColor(new java.awt.Color((argb & 0x00FF0000) >> 16, (argb & 0x0000FF00) >> 8, (argb & 0x000000FF))); if (x1 == x3 && x2 == x4) { g.fillRect(x1, y1, x4 - x1, y2 - y1); } else for(int y=y1; y> 16) & 0xff, + java.awt.Color.white : + new java.awt.Color((root.fillcolor >> 16) & 0xff, (root.fillcolor >> 8) & 0xff, (root.fillcolor) & 0xff)); } diff --git a/src/org/ibex/plat/Darwin.java b/src/org/ibex/plat/Darwin.java index 34cad44..09c8a65 100644 --- a/src/org/ibex/plat/Darwin.java +++ b/src/org/ibex/plat/Darwin.java @@ -7,6 +7,9 @@ import gnu.gcj.RawData; import org.ibex.util.*; import org.ibex.js.*; import org.ibex.*; +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.net.*; public class Darwin extends POSIX { private static final Class openGLClass = OpenGL.class; diff --git a/src/org/ibex/plat/GCJ.java b/src/org/ibex/plat/GCJ.java index 8954660..2391434 100644 --- a/src/org/ibex/plat/GCJ.java +++ b/src/org/ibex/plat/GCJ.java @@ -6,6 +6,9 @@ import org.ibex.util.*; import java.io.*; import java.security.*; import java.security.cert.*; +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.net.*; /** common superclass for all platforms that use GCJ to compile a native binary */ public abstract class GCJ extends Platform { diff --git a/src/org/ibex/plat/JVM.java b/src/org/ibex/plat/JVM.java index 54f6e21..7f7bdfd 100644 --- a/src/org/ibex/plat/JVM.java +++ b/src/org/ibex/plat/JVM.java @@ -2,6 +2,9 @@ package org.ibex.plat; import org.ibex.*; +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.net.*; /** common superclass for all platforms that run in a "real" JVM */ public abstract class JVM extends Platform { diff --git a/src/org/ibex/plat/Java2.java b/src/org/ibex/plat/Java2.java index 7a1909b..32c6d0c 100644 --- a/src/org/ibex/plat/Java2.java +++ b/src/org/ibex/plat/Java2.java @@ -9,7 +9,9 @@ import java.util.*; import org.ibex.util.*; import org.ibex.*; import java.lang.reflect.*; - +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.net.*; /** Platform class for most reasonable Java1.2+ Java2s */ public class Java2 extends AWT { @@ -41,11 +43,11 @@ public class Java2 extends AWT { } /** this is done with reflection in case a new version of the plugin comes out that doesn't let us pull the sun.plugin.* trick */ - protected synchronized org.ibex.HTTP.Proxy _detectProxy() { - return (org.ibex.HTTP.Proxy)java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() { + protected synchronized org.ibex.net.HTTP.Proxy _detectProxy() { + return (org.ibex.net.HTTP.Proxy)java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() { public Object run() { try { - org.ibex.HTTP.Proxy pi = new org.ibex.HTTP.Proxy(); + org.ibex.net.HTTP.Proxy pi = new org.ibex.net.HTTP.Proxy(); Class PluginProxyHandler = Class.forName("sun.plugin.protocol.PluginProxyHandler"); Method getDefaultProxyHandler = PluginProxyHandler.getMethod("getDefaultProxyHandler", new Class[] { }); @@ -176,14 +178,14 @@ public class Java2 extends AWT { private DataBuffer buf = null; // this doens't seem to work on Windows - public void drawGlyph(org.ibex.Font.Glyph source, int dx, int dy, int cx1, int cy1, int cx2, int cy2, int rgb) { + public void drawGlyph(org.ibex.graphics.Font.Glyph source, int dx, int dy, int cx1, int cy1, int cx2, int cy2, int rgb) { Image i2 = ((AWTGlyph)source).getImage(); Graphics2D g2 = (Graphics2D)i.getGraphics(); g2.setComposite(AlphaComposite.DstOut); g2.setClip(cx1, cy1, cx2 - cx1, cy2 - cy1); g2.drawImage(i2, dx, dy, null); g2.setComposite(AlphaComposite.DstOver); - g2.setColor(new Color((rgb & 0x00FF0000) >> 16, (rgb & 0x0000FF00) >> 8, (rgb & 0x000000FF))); + g2.setColor(new java.awt.Color((rgb & 0x00FF0000) >> 16, (rgb & 0x0000FF00) >> 8, (rgb & 0x000000FF))); g2.fillRect(dx, dy, cx2 - dx, cy2 - dy); g2.drawImage(i2, 0, 0, null); g2.setClip(0, 0, i.getWidth(null), i.getHeight(null)); diff --git a/src/org/ibex/plat/Linux.java b/src/org/ibex/plat/Linux.java index 9ece3af..959ba5d 100644 --- a/src/org/ibex/plat/Linux.java +++ b/src/org/ibex/plat/Linux.java @@ -1,6 +1,10 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] package org.ibex.plat; +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.net.*; + /** Linux with an X11 display */ public class Linux extends X11 { diff --git a/src/org/ibex/plat/OpenGL.java b/src/org/ibex/plat/OpenGL.java index 0d5bf18..040556e 100644 --- a/src/org/ibex/plat/OpenGL.java +++ b/src/org/ibex/plat/OpenGL.java @@ -5,6 +5,9 @@ package org.ibex.plat; import org.ibex.*; import org.ibex.js.*; import org.ibex.util.*; +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.net.*; abstract class OpenGL { static final boolean pretendToBeACrappyVideoCard = false; @@ -133,7 +136,7 @@ abstract class OpenGL { public void deleteTexture(final int tex) { // CHECKME: Is this safe to do from finalize()? // natDeleteTexture MUST be run from the message queue thread - Scheduler.add(new Scheduler.Task() { public void perform() { natDeleteTexture(tex); }}); + Scheduler.add(new Task() { public void perform() { natDeleteTexture(tex); }}); } private static abstract class GLPicture { diff --git a/src/org/ibex/plat/POSIX.java b/src/org/ibex/plat/POSIX.java index 7b721a7..314596b 100644 --- a/src/org/ibex/plat/POSIX.java +++ b/src/org/ibex/plat/POSIX.java @@ -2,6 +2,9 @@ package org.ibex.plat; import java.util.*; +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.net.*; /** Platform implementation for POSIX compliant operating systems */ public class POSIX extends GCJ { diff --git a/src/org/ibex/plat/PalmOS.java b/src/org/ibex/plat/PalmOS.java index 85e67da..430e9ca 100644 --- a/src/org/ibex/plat/PalmOS.java +++ b/src/org/ibex/plat/PalmOS.java @@ -2,6 +2,9 @@ package org.ibex.plat; import org.ibex.*; import java.io.*; +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.net.*; /** Platform class for PalmOS devices */ public class PalmOS extends Platform { diff --git a/src/org/ibex/plat/Platform.java b/src/org/ibex/plat/Platform.java index 4b110a6..5ad71c2 100644 --- a/src/org/ibex/plat/Platform.java +++ b/src/org/ibex/plat/Platform.java @@ -1,11 +1,16 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.plat; import java.lang.reflect.*; import java.net.*; import java.io.*; import org.ibex.js.*; import org.ibex.util.*; +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.net.*; /** * Abstracts away the small irregularities in JVM implementations. @@ -23,10 +28,10 @@ public abstract class Platform { // Static Data ///////////////////////////////////////////////////////////////////////////////////// - static boolean clipboardReadEnabled = false; ///< true iff inside a C-v/A-v/Press3 trap handler - static Platform platform = null; ///< The appropriate Platform object for this JVM - static boolean alreadyDetectedProxy = false; ///< true if proxy autodetection has already been run - static org.ibex.HTTP.Proxy cachedProxyInfo = null; ///< the result of proxy autodetection + public static boolean clipboardReadEnabled = false; ///< true iff inside a C-v/A-v/Press3 trap handler + public static Platform platform = null; ///< The appropriate Platform object for this JVM + public static boolean alreadyDetectedProxy = false; ///< true if proxy autodetection has already been run + public static org.ibex.net.HTTP.Proxy cachedProxyInfo = null; ///< the result of proxy autodetection public static String build = "unknown"; ///< the current build // VM Detection Logic ///////////////////////////////////////////////////////////////////// @@ -100,11 +105,11 @@ public abstract class Platform { protected Surface _createSurface(Box b, boolean framed) { return null; } protected Picture _createPicture(JS r) { return null; } protected PixelBuffer _createPixelBuffer(int w, int h, Surface owner) { return null; } - protected Font.Glyph _createGlyph(org.ibex.Font f, char c) { return new DefaultGlyph(f, c); } + protected Font.Glyph _createGlyph(org.ibex.graphics.Font f, char c) { return new DefaultGlyph(f, c); } public static PixelBuffer createPixelBuffer(int w, int h, Surface s) { return platform._createPixelBuffer(w, h, s); } public static Picture createPicture(JS r) { return platform._createPicture(r); } - public static Font.Glyph createGlyph(org.ibex.Font f, char c) { return platform._createGlyph(f, c); } + public static Font.Glyph createGlyph(org.ibex.graphics.Font f, char c) { return platform._createGlyph(f, c); } public static Surface createSurface(Box b, boolean framed, boolean refreshable) { Surface ret = platform._createSurface(b, framed); ret.setInvisible(false); @@ -245,15 +250,15 @@ public abstract class Platform { } /** detects proxy settings */ - protected synchronized org.ibex.HTTP.Proxy _detectProxy() { return null; } - public static synchronized org.ibex.HTTP.Proxy detectProxy() { + protected synchronized org.ibex.net.HTTP.Proxy _detectProxy() { return null; } + public static synchronized org.ibex.net.HTTP.Proxy detectProxy() { if (cachedProxyInfo != null) return cachedProxyInfo; if (alreadyDetectedProxy) return null; alreadyDetectedProxy = true; Log.info(Platform.class, "attempting environment-variable DNS proxy detection"); - cachedProxyInfo = org.ibex.HTTP.Proxy.detectProxyViaManual(); + cachedProxyInfo = org.ibex.net.HTTP.Proxy.detectProxyViaManual(); if (cachedProxyInfo != null) return cachedProxyInfo; Log.info(Platform.class, "attempting " + platform.getClass().getName() + " proxy detection"); @@ -270,7 +275,7 @@ public abstract class Platform { // FEATURE: be more efficient for many of the subclasses public static class DefaultGlyph extends Font.Glyph { private Picture p = null; - public DefaultGlyph(org.ibex.Font f, char c) { super(f, c); } + public DefaultGlyph(org.ibex.graphics.Font f, char c) { super(f, c); } public Picture getPicture() { if (p == null && isLoaded) { Picture p = createPicture(null); diff --git a/src/org/ibex/plat/Win32.java b/src/org/ibex/plat/Win32.java index 592baf9..e034258 100644 --- a/src/org/ibex/plat/Win32.java +++ b/src/org/ibex/plat/Win32.java @@ -5,6 +5,9 @@ import org.ibex.*; import org.ibex.util.*; import java.util.*; import org.ibex.js.*; +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.net.*; /** Platform specific code for GCJ-compiled Win32 binaries */ public class Win32 extends GCJ { diff --git a/src/org/ibex/plat/X11.java b/src/org/ibex/plat/X11.java index 80db668..46a549e 100644 --- a/src/org/ibex/plat/X11.java +++ b/src/org/ibex/plat/X11.java @@ -5,6 +5,9 @@ import gnu.gcj.RawData; import java.util.*; import org.ibex.js.*; import org.ibex.util.*; +import org.ibex.graphics.*; +import org.ibex.core.*; +import org.ibex.net.*; import org.ibex.*; /** Platform implementation for POSIX compliant operating systems with an X11 Server */ diff --git a/src/org/ibex/util/BalancedTree.java b/src/org/ibex/util/BalancedTree.java index 36d8542..615db24 100644 --- a/src/org/ibex/util/BalancedTree.java +++ b/src/org/ibex/util/BalancedTree.java @@ -27,7 +27,7 @@ public class BalancedTree { /** the number of elements in the tree */ public final int treeSize() { return root == 0 ? 0 : size[root]; } - + /** clamps index to [0..treeSize()] and inserts object o *before* the specified index */ public final synchronized void insertNode(int index, Object o) { if(o == null) throw new Error("can't insert nulls in the balanced tree"); @@ -169,14 +169,13 @@ public class BalancedTree { // collisions when a single Object is inserted into multiple // trees int dest = Math.abs(o.hashCode() ^ this.hashCode()) % objects.length; - if (dest == 0) dest = 1; Object search = alloc ? null : o; int odest = dest; boolean plus = true; int tries = 1; while (objects[dest] != search || !(alloc || root(dest) == root)) { + if (dest == 0) dest++; dest = Math.abs((odest + (plus ? 1 : -1) * tries * tries) % objects.length); - if (dest == 0) dest=1; if (plus) tries++; plus = !plus; // FEATURE: GROW - if(tries > MAX_SLOT_DISTANCE) return -1; @@ -224,11 +223,13 @@ public class BalancedTree { int c = left[d]; if (d <= 0) throw new Error("rotation error"); left[d] = b; - right[b] = c <= 0 ? -d : c; + if(size[b] <= 3) // b is now a leaf + right[b] = -d; + else + right[b] = c; parent[b] = d; parent[d] = p; if(c > 0) parent[c] = b; - if (p == 0) root = d; else if (left[p] == b) left[p] = d; else if (right[p] == b) right[p] = d; @@ -332,6 +333,7 @@ public class BalancedTree { // we found the node to delete } else { + // fast path: it has no children if (left[slot] <= 0 && right[slot] <= 0) { if (p == 0) root = 0; @@ -339,6 +341,7 @@ public class BalancedTree { int[] side = left[p] == slot ? left : right; side[p] = side[slot]; // fix parent's pointer } + // fast path: it has no left child, so we replace it with its right child } else if (left[slot] <= 0) { if (p == 0) root = right[slot]; diff --git a/src/org/ibex/util/EjAlbertBrowserLauncher.java b/src/org/ibex/util/EjAlbertBrowserLauncher.java new file mode 100644 index 0000000..a2bb059 --- /dev/null +++ b/src/org/ibex/util/EjAlbertBrowserLauncher.java @@ -0,0 +1,589 @@ +package org.ibex.util; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * BrowserLauncher is a class that provides one static method, openURL, which opens the default + * web browser for the current user of the system to the given URL. It may support other + * protocols depending on the system -- mailto, ftp, etc. -- but that has not been rigorously + * tested and is not guaranteed to work. + *

    + * Yes, this is platform-specific code, and yes, it may rely on classes on certain platforms + * that are not part of the standard JDK. What we're trying to do, though, is to take something + * that's frequently desirable but inherently platform-specific -- opening a default browser -- + * and allow programmers (you, for example) to do so without worrying about dropping into native + * code or doing anything else similarly evil. + *

    + * Anyway, this code is completely in Java and will run on all JDK 1.1-compliant systems without + * modification or a need for additional libraries. All classes that are required on certain + * platforms to allow this to run are dynamically loaded at runtime via reflection and, if not + * found, will not cause this to do anything other than returning an error when opening the + * browser. + *

    + * There are certain system requirements for this class, as it's running through Runtime.exec(), + * which is Java's way of making a native system call. Currently, this requires that a Macintosh + * have a Finder which supports the GURL event, which is true for Mac OS 8.0 and 8.1 systems that + * have the Internet Scripting AppleScript dictionary installed in the Scripting Additions folder + * in the Extensions folder (which is installed by default as far as I know under Mac OS 8.0 and + * 8.1), and for all Mac OS 8.5 and later systems. On Windows, it only runs under Win32 systems + * (Windows 95, 98, and NT 4.0, as well as later versions of all). On other systems, this drops + * back from the inherently platform-sensitive concept of a default browser and simply attempts + * to launch Netscape via a shell command. + *

    + * This code is Copyright 1999-2001 by Eric Albert (ejalbert@cs.stanford.edu) and may be + * redistributed or modified in any form without restrictions as long as the portion of this + * comment from this paragraph through the end of the comment is not removed. The author + * requests that he be notified of any application, applet, or other binary that makes use of + * this code, but that's more out of curiosity than anything and is not required. This software + * includes no warranty. The author is not repsonsible for any loss of data or functionality + * or any adverse or unexpected effects of using this software. + *

    + * Credits: + *
    Steven Spencer, JavaWorld magazine (Java Tip 66) + *
    Thanks also to Ron B. Yeh, Eric Shapiro, Ben Engber, Paul Teitlebaum, Andrea Cantatore, + * Larry Barowski, Trevor Bedzek, Frank Miedrich, and Ron Rabakukk + * + * @author Eric Albert (ejalbert@cs.stanford.edu) + * @version 1.4b1 (Released June 20, 2001) + */ +public class EjAlbertBrowserLauncher { + + /** + * The Java virtual machine that we are running on. Actually, in most cases we only care + * about the operating system, but some operating systems require us to switch on the VM. */ + private static int jvm; + + /** The browser for the system */ + private static Object browser; + + /** + * Caches whether any classes, methods, and fields that are not part of the JDK and need to + * be dynamically loaded at runtime loaded successfully. + *

    + * Note that if this is false, openURL() will always return an + * IOException. + */ + private static boolean loadedWithoutErrors; + + /** The com.apple.mrj.MRJFileUtils class */ + private static Class mrjFileUtilsClass; + + /** The com.apple.mrj.MRJOSType class */ + private static Class mrjOSTypeClass; + + /** The com.apple.MacOS.AEDesc class */ + private static Class aeDescClass; + + /** The (int) method of com.apple.MacOS.AETarget */ + private static Constructor aeTargetConstructor; + + /** The (int, int, int) method of com.apple.MacOS.AppleEvent */ + private static Constructor appleEventConstructor; + + /** The (String) method of com.apple.MacOS.AEDesc */ + private static Constructor aeDescConstructor; + + /** The findFolder method of com.apple.mrj.MRJFileUtils */ + private static Method findFolder; + + /** The getFileCreator method of com.apple.mrj.MRJFileUtils */ + private static Method getFileCreator; + + /** The getFileType method of com.apple.mrj.MRJFileUtils */ + private static Method getFileType; + + /** The openURL method of com.apple.mrj.MRJFileUtils */ + private static Method openURL; + + /** The makeOSType method of com.apple.MacOS.OSUtils */ + private static Method makeOSType; + + /** The putParameter method of com.apple.MacOS.AppleEvent */ + private static Method putParameter; + + /** The sendNoReply method of com.apple.MacOS.AppleEvent */ + private static Method sendNoReply; + + /** Actually an MRJOSType pointing to the System Folder on a Macintosh */ + private static Object kSystemFolderType; + + /** The keyDirectObject AppleEvent parameter type */ + private static Integer keyDirectObject; + + /** The kAutoGenerateReturnID AppleEvent code */ + private static Integer kAutoGenerateReturnID; + + /** The kAnyTransactionID AppleEvent code */ + private static Integer kAnyTransactionID; + + /** The linkage object required for JDirect 3 on Mac OS X. */ + private static Object linkage; + + /** The framework to reference on Mac OS X */ + private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox"; + + /** JVM constant for MRJ 2.0 */ + private static final int MRJ_2_0 = 0; + + /** JVM constant for MRJ 2.1 or later */ + private static final int MRJ_2_1 = 1; + + /** JVM constant for Java on Mac OS X 10.0 (MRJ 3.0) */ + private static final int MRJ_3_0 = 3; + + /** JVM constant for MRJ 3.1 */ + private static final int MRJ_3_1 = 4; + + /** JVM constant for any Windows NT JVM */ + private static final int WINDOWS_NT = 5; + + /** JVM constant for any Windows 9x JVM */ + private static final int WINDOWS_9x = 6; + + /** JVM constant for any other platform */ + private static final int OTHER = -1; + + /** + * The file type of the Finder on a Macintosh. Hardcoding "Finder" would keep non-U.S. English + * systems from working properly. + */ + private static final String FINDER_TYPE = "FNDR"; + + /** + * The creator code of the Finder on a Macintosh, which is needed to send AppleEvents to the + * application. + */ + private static final String FINDER_CREATOR = "MACS"; + + /** The name for the AppleEvent type corresponding to a GetURL event. */ + private static final String GURL_EVENT = "GURL"; + + /** + * The first parameter that needs to be passed into Runtime.exec() to open the default web + * browser on Windows. + */ + private static final String FIRST_WINDOWS_PARAMETER = "/c"; + + /** The second parameter for Runtime.exec() on Windows. */ + private static final String SECOND_WINDOWS_PARAMETER = "start"; + + /** + * The third parameter for Runtime.exec() on Windows. This is a "title" + * parameter that the command line expects. Setting this parameter allows + * URLs containing spaces to work. + */ + private static final String THIRD_WINDOWS_PARAMETER = "\"\""; + + /** + * The shell parameters for Netscape that opens a given URL in an already-open copy of Netscape + * on many command-line systems. + */ + private static final String NETSCAPE_REMOTE_PARAMETER = "-remote"; + private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL("; + private static final String NETSCAPE_OPEN_PARAMETER_END = ")'"; + + /** + * The message from any exception thrown throughout the initialization process. + */ + private static String errorMessage; + + /** + * An initialization block that determines the operating system and loads the necessary + * runtime data. + */ + static { + loadedWithoutErrors = true; + String osName = System.getProperty("os.name"); + if (osName.startsWith("Mac OS")) { + String mrjVersion = System.getProperty("mrj.version"); + String majorMRJVersion = mrjVersion.substring(0, 3); + try { + double version = Double.valueOf(majorMRJVersion).doubleValue(); + if (version == 2) { + jvm = MRJ_2_0; + } else if (version >= 2.1 && version < 3) { + // Assume that all 2.x versions of MRJ work the same. MRJ 2.1 actually + // works via Runtime.exec() and 2.2 supports that but has an openURL() method + // as well that we currently ignore. + jvm = MRJ_2_1; + } else if (version == 3.0) { + jvm = MRJ_3_0; + } else if (version >= 3.1) { + // Assume that all 3.1 and later versions of MRJ work the same. + jvm = MRJ_3_1; + } else { + loadedWithoutErrors = false; + errorMessage = "Unsupported MRJ version: " + version; + } + } catch (NumberFormatException nfe) { + loadedWithoutErrors = false; + errorMessage = "Invalid MRJ version: " + mrjVersion; + } + } else if (osName.startsWith("Windows")) { + if (osName.indexOf("9") != -1) { + jvm = WINDOWS_9x; + } else { + jvm = WINDOWS_NT; + } + } else { + jvm = OTHER; + } + + if (loadedWithoutErrors) { // if we haven't hit any errors yet + loadedWithoutErrors = loadClasses(); + } + } + + /** + * This class should be never be instantiated; this just ensures so. + */ + private EjAlbertBrowserLauncher() { } + + /** + * Called by a static initializer to load any classes, fields, and methods required at runtime + * to locate the user's web browser. + * @return true if all intialization succeeded + * false if any portion of the initialization failed + */ + private static boolean loadClasses() { + switch (jvm) { + case MRJ_2_0: + try { + Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget"); + Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils"); + Class appleEventClass = Class.forName("com.apple.MacOS.AppleEvent"); + Class aeClass = Class.forName("com.apple.MacOS.ae"); + aeDescClass = Class.forName("com.apple.MacOS.AEDesc"); + + aeTargetConstructor = aeTargetClass.getDeclaredConstructor(new Class [] { int.class }); + appleEventConstructor = appleEventClass.getDeclaredConstructor(new Class[] { int.class, int.class, aeTargetClass, int.class, int.class }); + aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class[] { String.class }); + + makeOSType = osUtilsClass.getDeclaredMethod("makeOSType", new Class [] { String.class }); + putParameter = appleEventClass.getDeclaredMethod("putParameter", new Class[] { int.class, aeDescClass }); + sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply", new Class[] { }); + + Field keyDirectObjectField = aeClass.getDeclaredField("keyDirectObject"); + keyDirectObject = (Integer) keyDirectObjectField.get(null); + Field autoGenerateReturnIDField = appleEventClass.getDeclaredField("kAutoGenerateReturnID"); + kAutoGenerateReturnID = (Integer) autoGenerateReturnIDField.get(null); + Field anyTransactionIDField = appleEventClass.getDeclaredField("kAnyTransactionID"); + kAnyTransactionID = (Integer) anyTransactionIDField.get(null); + } catch (ClassNotFoundException cnfe) { + errorMessage = cnfe.getMessage(); + return false; + } catch (NoSuchMethodException nsme) { + errorMessage = nsme.getMessage(); + return false; + } catch (NoSuchFieldException nsfe) { + errorMessage = nsfe.getMessage(); + return false; + } catch (IllegalAccessException iae) { + errorMessage = iae.getMessage(); + return false; + } + break; + case MRJ_2_1: + try { + mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils"); + mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType"); + Field systemFolderField = mrjFileUtilsClass.getDeclaredField("kSystemFolderType"); + kSystemFolderType = systemFolderField.get(null); + findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder", new Class[] { mrjOSTypeClass }); + getFileCreator = mrjFileUtilsClass.getDeclaredMethod("getFileCreator", new Class[] { File.class }); + getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType", new Class[] { File.class }); + } catch (ClassNotFoundException cnfe) { + errorMessage = cnfe.getMessage(); + return false; + } catch (NoSuchFieldException nsfe) { + errorMessage = nsfe.getMessage(); + return false; + } catch (NoSuchMethodException nsme) { + errorMessage = nsme.getMessage(); + return false; + } catch (SecurityException se) { + errorMessage = se.getMessage(); + return false; + } catch (IllegalAccessException iae) { + errorMessage = iae.getMessage(); + return false; + } + break; + case MRJ_3_0: + try { + Class linker = Class.forName("com.apple.mrj.jdirect.Linker"); + Constructor constructor = linker.getConstructor(new Class[]{ Class.class }); + linkage = constructor.newInstance(new Object[] { EjAlbertBrowserLauncher.class }); + } catch (ClassNotFoundException cnfe) { + errorMessage = cnfe.getMessage(); + return false; + } catch (NoSuchMethodException nsme) { + errorMessage = nsme.getMessage(); + return false; + } catch (InvocationTargetException ite) { + errorMessage = ite.getMessage(); + return false; + } catch (InstantiationException ie) { + errorMessage = ie.getMessage(); + return false; + } catch (IllegalAccessException iae) { + errorMessage = iae.getMessage(); + return false; + } + break; + case MRJ_3_1: + try { + mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils"); + openURL = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class[] { String.class }); + } catch (ClassNotFoundException cnfe) { + errorMessage = cnfe.getMessage(); + return false; + } catch (NoSuchMethodException nsme) { + errorMessage = nsme.getMessage(); + return false; + } + break; + default: + break; + } + return true; + } + + /** + * Attempts to locate the default web browser on the local system. Caches results so it + * only locates the browser once for each use of this class per JVM instance. + * @return The browser for the system. Note that this may not be what you would consider + * to be a standard web browser; instead, it's the application that gets called to + * open the default web browser. In some cases, this will be a non-String object + * that provides the means of calling the default browser. + */ + private static Object locateBrowser() { + if (browser != null) { + return browser; + } + switch (jvm) { + case MRJ_2_0: + try { + Integer finderCreatorCode = (Integer) makeOSType.invoke(null, new Object[] { FINDER_CREATOR }); + Object aeTarget = aeTargetConstructor.newInstance(new Object[] { finderCreatorCode }); + Integer gurlType = (Integer) makeOSType.invoke(null, new Object[] { GURL_EVENT }); + Object appleEvent = appleEventConstructor.newInstance(new Object[] { gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID }); + // Don't set browser = appleEvent because then the next time we call + // locateBrowser(), we'll get the same AppleEvent, to which we'll already have + // added the relevant parameter. Instead, regenerate the AppleEvent every time. + // There's probably a way to do this better; if any has any ideas, please let + // me know. + return appleEvent; + } catch (IllegalAccessException iae) { + browser = null; + errorMessage = iae.getMessage(); + return browser; + } catch (InstantiationException ie) { + browser = null; + errorMessage = ie.getMessage(); + return browser; + } catch (InvocationTargetException ite) { + browser = null; + errorMessage = ite.getMessage(); + return browser; + } + case MRJ_2_1: + File systemFolder; + try { + systemFolder = (File) findFolder.invoke(null, new Object[] { kSystemFolderType }); + } catch (IllegalArgumentException iare) { + browser = null; + errorMessage = iare.getMessage(); + return browser; + } catch (IllegalAccessException iae) { + browser = null; + errorMessage = iae.getMessage(); + return browser; + } catch (InvocationTargetException ite) { + browser = null; + errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage(); + return browser; + } + String[] systemFolderFiles = systemFolder.list(); + // Avoid a FilenameFilter because that can't be stopped mid-list + for(int i = 0; i < systemFolderFiles.length; i++) { + try { + File file = new File(systemFolder, systemFolderFiles[i]); + if (!file.isFile()) { + continue; + } + // We're looking for a file with a creator code of 'MACS' and + // a type of 'FNDR'. Only requiring the type results in non-Finder + // applications being picked up on certain Mac OS 9 systems, + // especially German ones, and sending a GURL event to those + // applications results in a logout under Multiple Users. + Object fileType = getFileType.invoke(null, new Object[] { file }); + if (FINDER_TYPE.equals(fileType.toString())) { + Object fileCreator = getFileCreator.invoke(null, new Object[] { file }); + if (FINDER_CREATOR.equals(fileCreator.toString())) { + browser = file.toString(); // Actually the Finder, but that's OK + return browser; + } + } + } catch (IllegalArgumentException iare) { + browser = browser; + errorMessage = iare.getMessage(); + return null; + } catch (IllegalAccessException iae) { + browser = null; + errorMessage = iae.getMessage(); + return browser; + } catch (InvocationTargetException ite) { + browser = null; + errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage(); + return browser; + } + } + browser = null; + break; + case MRJ_3_0: + case MRJ_3_1: + browser = ""; // Return something non-null + break; + case WINDOWS_NT: + browser = "cmd.exe"; + break; + case WINDOWS_9x: + browser = "command.com"; + break; + case OTHER: + default: + browser = "netscape"; + break; + } + return browser; + } + + /** + * Attempts to open the default web browser to the given URL. + * @param url The URL to open + * @throws IOException If the web browser could not be located or does not run + */ + public static void openURL(String url) throws IOException { + if (!loadedWithoutErrors) { + throw new IOException("Exception in finding browser: " + errorMessage); + } + Object browser = locateBrowser(); + if (browser == null) { + throw new IOException("Unable to locate browser: " + errorMessage); + } + + switch (jvm) { + case MRJ_2_0: + Object aeDesc = null; + try { + aeDesc = aeDescConstructor.newInstance(new Object[] { url }); + putParameter.invoke(browser, new Object[] { keyDirectObject, aeDesc }); + sendNoReply.invoke(browser, new Object[] { }); + } catch (InvocationTargetException ite) { + throw new IOException("InvocationTargetException while creating AEDesc: " + ite.getMessage()); + } catch (IllegalAccessException iae) { + throw new IOException("IllegalAccessException while building AppleEvent: " + iae.getMessage()); + } catch (InstantiationException ie) { + throw new IOException("InstantiationException while creating AEDesc: " + ie.getMessage()); + } finally { + aeDesc = null; // Encourage it to get disposed if it was created + browser = null; // Ditto + } + break; + case MRJ_2_1: + Runtime.getRuntime().exec(new String[] { (String) browser, url } ); + break; + case MRJ_3_0: + int[] instance = new int[1]; + int result = ICStart(instance, 0); + if (result == 0) { + int[] selectionStart = new int[] { 0 }; + byte[] urlBytes = url.getBytes(); + int[] selectionEnd = new int[] { urlBytes.length }; + result = ICLaunchURL(instance[0], new byte[] { 0 }, urlBytes, + urlBytes.length, selectionStart, + selectionEnd); + if (result == 0) { + // Ignore the return value; the URL was launched successfully + // regardless of what happens here. + ICStop(instance); + } else { + throw new IOException("Unable to launch URL: " + result); + } + } else { + throw new IOException("Unable to create an Internet Config instance: " + result); + } + break; + case MRJ_3_1: + try { + openURL.invoke(null, new Object[] { url }); + } catch (InvocationTargetException ite) { + throw new IOException("InvocationTargetException while calling openURL: " + ite.getMessage()); + } catch (IllegalAccessException iae) { + throw new IOException("IllegalAccessException while calling openURL: " + iae.getMessage()); + } + break; + case WINDOWS_NT: + case WINDOWS_9x: + // Add quotes around the URL to allow ampersands and other special + // characters to work. + Process process = Runtime.getRuntime().exec(new String[] { (String) browser, + FIRST_WINDOWS_PARAMETER, + SECOND_WINDOWS_PARAMETER, + THIRD_WINDOWS_PARAMETER, + '"' + url + '"' }); + // This avoids a memory leak on some versions of Java on Windows. + // That's hinted at in . + try { + process.waitFor(); + process.exitValue(); + } catch (InterruptedException ie) { + throw new IOException("InterruptedException while launching browser: " + ie.getMessage()); + } + break; + case OTHER: + // Assume that we're on Unix and that Netscape is installed + + // First, attempt to open the URL in a currently running session of Netscape + process = Runtime.getRuntime().exec(new String[] { (String) browser, + NETSCAPE_REMOTE_PARAMETER, + NETSCAPE_OPEN_PARAMETER_START + + url + + NETSCAPE_OPEN_PARAMETER_END }); + try { + int exitCode = process.waitFor(); + if (exitCode != 0) { // if Netscape was not open + Runtime.getRuntime().exec(new String[] { (String) browser, url }); + } + } catch (InterruptedException ie) { + throw new IOException("InterruptedException while launching browser: " + ie.getMessage()); + } + break; + default: + // This should never occur, but if it does, we'll try the simplest thing possible + Runtime.getRuntime().exec(new String[] { (String) browser, url }); + break; + } + } + + /** + * Methods required for Mac OS X. The presence of native methods does not cause + * any problems on other platforms. + */ + /* + private native static int ICStart(int[] instance, int signature); + private native static int ICStop(int[] instance); + private native static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len, + int[] selectionStart, int[] selectionEnd); + */ + private static int ICStart(int[] instance, int signature) { return 0; } + private static int ICStop(int[] instance) { return 0; } + private static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len, + int[] selectionStart, int[] selectionEnd) { return 0; } +} diff --git a/src/org/ibex/util/MSPack.java b/src/org/ibex/util/MSPack.java index c6c988d..625ffec 100644 --- a/src/org/ibex/util/MSPack.java +++ b/src/org/ibex/util/MSPack.java @@ -1,6 +1,6 @@ -package org.ibex.translators; +package org.ibex.util; -import org.ibex.Main; +import org.ibex.core.Main; import org.ibex.util.*; import org.xwt.mips.*; import java.io.*; @@ -18,7 +18,7 @@ public class MSPack { public MSPack(InputStream cabIS) throws IOException { try { - Runtime vm = (Runtime)Class.forName("org.ibex.translators.MIPSApps").newInstance(); + Runtime vm = (Runtime)Class.forName("org.ibex.util.MIPSApps").newInstance(); byte[] cab = InputStreamToByteArray.convert(cabIS); int cabAddr = vm.sbrk(cab.length); if(cabAddr < 0) throw new MSPackException("sbrk failed"); diff --git a/src/org/ibex/util/SSL.java b/src/org/ibex/util/SSL.java deleted file mode 100644 index 25c76ac..0000000 --- a/src/org/ibex/util/SSL.java +++ /dev/null @@ -1,1659 +0,0 @@ -// Copyright (C) 2003 Adam Megacz all rights reserved. -// -// You may modify, copy, and redistribute this code under the terms of -// the GNU Library Public License version 2.1, with the exception of -// the portion of clause 6a after the semicolon (aka the "obnoxious -// relink clause") - -package org.ibex.util; - -import org.bouncycastle.crypto.AsymmetricBlockCipher; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.params.RSAKeyParameters; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.MD5Digest; -import org.bouncycastle.crypto.digests.MD2Digest; -import org.bouncycastle.crypto.engines.RSAEngine; -import org.bouncycastle.crypto.engines.RC4Engine; -import org.bouncycastle.util.encoders.Base64; -import org.bouncycastle.asn1.DERInputStream; -import org.bouncycastle.asn1.DEROutputStream; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERObject; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.BERInputStream; -import org.bouncycastle.asn1.x509.X509CertificateStructure; -import org.bouncycastle.asn1.x509.RSAPublicKeyStructure; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x509.TBSCertificateStructure; -import org.bouncycastle.asn1.x509.X509Name; -import org.bouncycastle.asn1.x509.X509Extensions; -import org.bouncycastle.asn1.x509.X509Extension; -import org.bouncycastle.asn1.x509.BasicConstraints; -import org.ibex.util.Log; -import java.net.*; -import java.io.*; -import java.util.*; -import java.math.*; -import java.text.*; - -/** - - TinySSL: a tiny SSL implementation in Java, built on the - bouncycastle.org lightweight crypto library. - - This class implements an SSLv3 client-side socket, with the - SSL_RSA_EXPORT_WITH_RC4_40_MD5 and SSL_RSA_WITH_RC4_128_MD5 cipher - suites, as well as certificate chain verification against a - collection of 93 built-in Trusted Root CA public keys (the same 93 - included with Microsoft Internet Explorer 5.5 SP2). - - As of 07-Dec-01, the zipped bytecode for this class is 43k, and the - subset of bouncycastle it requires is 82k. - - This class should work correctly on any Java 1.1 compliant - platform. The java.security.* classes are not used. - - The main design goal for this class was the smallest possible body - of code capable of connecting to 99% of all active HTTPS - servers. Although this class is useful in many other situations - (IMAPS, Secure SMTP, etc), the author will refuse all feature - requests and submitted patches which go beyond this scope. - - Because of the limited goals of this class, certain abstractions - have been avoided, and certain parameters have been - hard-coded. "Magic numbers" are often used instead of "static final - int"'s, although they are usually accompanied by a descriptive - comment. Numeric offsets into byte arrays are also favored over - DataInputStream(ByteArrayInputStream(foo))'s. - - Much thanks and credit go to the BouncyCastle team for producing - such a first-class library, and for helping me out on the - dev-crypto mailing list while I was writing this. - - Revision History: - - 1.0 07-Dec-01 Initial Release - - 1.01 15-Mar-02 Added PKCS1 class to avoid dependancy on java.security.SecureRandom - - 1.02 27-Mar-02 Fixed a bug which would hang the connection when more than one - Handshake message appeared in the same TLS Record - - 1.03 10-Aug-02 Fixed a vulnerability outlined at - http://online.securityfocus.com/archive/1/286290 - - 1.04 12-Dec-03 Renamed to org.ibex.SSL, fixed race condition - -*/ - -public class SSL extends Socket { - - // Simple Test ////////////////////////////////////////////// - - public static void main(String[] args) { - Log.on = true; - try { - Socket s = new SSL("www.paypal.com", 443); - PrintWriter pw = new PrintWriter(s.getOutputStream()); - BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); - pw.println("GET / HTTP/1.0"); - pw.println(""); - pw.flush(); - - while(true) { - String s2 = br.readLine(); - if (s2 == null) return; - Log.info(SSL.class, s2); - } - - } catch (Exception e) { - e.printStackTrace(); - } - } - - // Static Data ////////////////////////////////////////////// - - public static class SSLException extends IOException { public SSLException(String s) { super(s); } } - static SubjectPublicKeyInfo[] trusted_CA_public_keys; - static String[] trusted_CA_public_key_identifiers; - public static byte[] pad1 = new byte[48]; - public static byte[] pad2 = new byte[48]; - public static byte[] pad1_sha = new byte[40]; - public static byte[] pad2_sha = new byte[40]; - static byte[] randpool; - static long randcnt = 0; - - // Cipher State ////////////////////////////////////////////// - - public byte[] server_random = new byte[32]; - public byte[] client_random = new byte[32]; - public byte[] client_write_MAC_secret = new byte[16]; - public byte[] server_write_MAC_secret = new byte[16]; - public byte[] client_write_key = null; - public byte[] server_write_key = null; - public byte[] master_secret = null; - - /** the bytes of the ServerKeyExchangeMessage, null if none recieved */ - public byte[] serverKeyExchange = null; - - /** true iff the server asked for a certificate */ - public boolean cert_requested = false; - - public X509CertificateStructure server_cert = null; - - public SSLOutputStream os = null; - public SSLInputStream is = null; - - String hostname; - - /** if true, we don't mind if the server's cert isn't signed by a CA. USE WITH CAUTION! */ - boolean ignoreUntrustedCert = false; - - /** the concatenation of all the bytes of all handshake messages sent or recieved */ - public byte[] handshakes = new byte[] { }; - - /** true iff we're using SSL_RSA_EXPORT_WITH_RC4_40_MD5 */ - boolean export = false; - - public InputStream getInputStream() throws IOException { return is != null ? is : super.getInputStream(); } - public OutputStream getOutputStream() throws IOException { return os != null ? os : super.getOutputStream(); } - - public SSL(String host, int port) throws IOException { this(host, port, true, false); } - public SSL(String host, int port, boolean negotiateImmediately) throws IOException { this(host, port, negotiateImmediately, false); } - public SSL(String host, int port, boolean negotiateImmediately, boolean ignoreUntrustedCert) throws IOException { - super(host, port); - if (!initializationFinished) { - synchronized(SSL.class) { - while (!initializationFinished) - try { SSL.class.wait(); } catch (Exception e) { } - } - } - hostname = host; - this.ignoreUntrustedCert = ignoreUntrustedCert; - if (negotiateImmediately) negotiate(); - } - - /** negotiates the SSL connection */ - public void negotiate() throws IOException { - os = new SSLOutputStream(super.getOutputStream()); - is = new SSLInputStream(super.getInputStream()); - os.writeClientHello(); - is.readServerHandshakes(); - os.sendClientHandshakes(); - is.readServerFinished(); - } - - class SSLInputStream extends InputStream { - - /** the underlying inputstream */ - DataInputStream raw; - - /** the server's sequence number */ - public int seq_num = 0; - - /** the decryption engine */ - public RC4Engine rc4 = null; - - /** pending bytes -- decrypted, but not yet fed to consumer */ - byte[] pend = null; - int pendstart = 0; - int pendlen = 0; - - public void mark() { } - public void reset() { } - public boolean markSupported() { return false; } - public long skip(long l) throws IOException { for(long i=0; i 1) { - throw new SSLException("got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]); - } else if (decrypted_payload[1] == 0) { - if (Log.on) Log.info(this, "server requested connection closure; returning null"); - return null; - } else { - if (Log.on) Log.info(this, "got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]); - return readRecord(); - } - - } else if (type == 22) { - if (Log.on) Log.info(this, "read a handshake"); - - } else if (type != 23) { - if (Log.on) Log.info(this, "unexpected record type: " + type + "; skipping"); - return readRecord(); - - } - - if (Log.on) Log.info(this, " returning " + decrypted_payload.length + " byte record payload"); - return decrypted_payload; - } - - private byte[] readHandshake() throws IOException { - // acquire a handshake message - byte type = (byte)read(); - int len = ((read() & 0xff) << 16) | ((read() & 0xff) << 8) | (read() & 0xff); - byte[] rec = new byte[len + 4]; - rec[0] = type; - rec[1] = (byte)(((len & 0x00ff0000) >> 16) & 0xff); - rec[2] = (byte)(((len & 0x0000ff00) >> 8) & 0xff); - rec[3] = (byte)((len & 0x000000ff) & 0xff); - if (len > 0) read(rec, 4, len); - return rec; - } - - /** This reads the ServerHello, Certificate, and ServerHelloDone handshake messages */ - public void readServerHandshakes() throws IOException { - for(;;) { - - byte[] rec = readHandshake(); - handshakes = concat(new byte[][] { handshakes, rec }); - - switch(rec[0]) { - case 2: // ServerHello - if (Log.on) Log.info(this, "got ServerHello"); - byte ver_major = rec[4]; - byte ver_minor = rec[5]; - System.arraycopy(rec, 6, server_random, 0, server_random.length); - short cipher_high = rec[6 + server_random.length + rec[6 + server_random.length] + 1]; - short cipher_low = rec[6 + server_random.length + rec[6 + server_random.length] + 2]; - - if (cipher_low == 0x04 || cipher_high != 0x00) { - export = false; - if (Log.on) Log.info(this, "using SSL_RSA_WITH_RC4_128_MD5"); - - } else if (cipher_low == 0x03 || cipher_high != 0x00) { - export = true; - if (Log.on) Log.info(this, "using SSL_RSA_EXPORT_WITH_RC4_40_MD5"); - - } else throw new SSLException("server asked for cipher " + ((cipher_high << 8) | cipher_low) + - " but we only do SSL_RSA_WITH_RC4_128_MD5 (0x0004) and " + - "SSL_RSA_EXPORT_WITH_RC4_40_MD5 (0x0003)"); - - byte compressionMethod = rec[6 + server_random.length + rec[6 + server_random.length] + 3]; - if (compressionMethod != 0x0) throw new SSLException("server asked for compression method " + compressionMethod + - " but we don't support compression"); - break; - - case 11: // Server's certificate(s) - if (Log.on) Log.info(this, "got Server Certificate(s)"); - int numcertbytes = ((rec[4] & 0xff) << 16) | ((rec[5] & 0xff) << 8) | (rec[6] & 0xff); - int numcerts = 0; - X509CertificateStructure last_cert = null; - X509CertificateStructure this_cert = null; - - for(int i=0; i 1 << 14) { - write(payload, off, 1 << 14, type); - write(payload, off + 1 << 14, len - 1 << 14, type); - return; - } - - raw.writeByte(type); - raw.writeShort(0x0300); - - if (rc4 == null) { - raw.writeShort(len); - raw.write(payload, off, len); - - } else { - byte[] MAC = computeMAC(type, payload, off, len, client_write_MAC_secret, seq_num); - byte[] encryptedPayload = new byte[MAC.length + len]; - rc4.processBytes(payload, off, len, encryptedPayload, 0); - rc4.processBytes(MAC, 0, MAC.length, encryptedPayload, len); - raw.writeShort(encryptedPayload.length); - raw.write(encryptedPayload); - - } - - seq_num++; - } - - /** tacks a handshake header onto payload before sending it */ - public void writeHandshake(int type, byte[] payload) throws IOException { - byte[] real_payload = new byte[payload.length + 4]; - System.arraycopy(payload, 0, real_payload, 4, payload.length); - real_payload[0] = (byte)(type & 0xFF); - intToBytes(payload.length, real_payload, 1, 3); - handshakes = concat(new byte[][] { handshakes, real_payload }); - write(real_payload, 0, real_payload.length, (byte)22); - } - - public void sendClientHandshakes() throws IOException { - - if (Log.on) Log.info(this, "shaking hands"); - if (cert_requested) { - if (Log.on) Log.info(this, "telling the server we have no certificates"); - writeHandshake(11, new byte[] { 0x0, 0x0, 0x0 }); - } - - // generate the premaster secret - byte[] pre_master_secret = new byte[48]; - pre_master_secret[0] = 0x03; // first two bytes of premaster secret are our version number - pre_master_secret[1] = 0x00; - getRandomBytes(pre_master_secret, 2, pre_master_secret.length - 2); - - // encrypt and send the pre_master_secret - try { - byte[] encrypted_pre_master_secret; - - SubjectPublicKeyInfo pki = server_cert.getSubjectPublicKeyInfo(); - RSAPublicKeyStructure rsa_pks = new RSAPublicKeyStructure((DERSequence)pki.getPublicKey()); - BigInteger modulus = rsa_pks.getModulus(); - BigInteger exponent = rsa_pks.getPublicExponent(); - - if (serverKeyExchange != null) { - - AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine()); - rsa.init(false, new RSAKeyParameters(false, modulus, exponent)); - - int modulus_size = ((serverKeyExchange[4] & 0xff) << 8) | (serverKeyExchange[5] & 0xff); - byte[] b_modulus = new byte[modulus_size]; - System.arraycopy(serverKeyExchange, 6, b_modulus, 0, modulus_size); - modulus = new BigInteger(1, b_modulus); - - int exponent_size = ((serverKeyExchange[6 + modulus_size] & 0xff) << 8) | (serverKeyExchange[7 + modulus_size] & 0xff); - byte[] b_exponent = new byte[exponent_size]; - System.arraycopy(serverKeyExchange, 8 + modulus_size, b_exponent, 0, exponent_size); - exponent = new BigInteger(1, b_exponent); - - byte[] server_params = new byte[modulus_size + exponent_size + 4]; - System.arraycopy(serverKeyExchange, 4, server_params, 0, server_params.length); - - byte[] expectedSignature = concat(new byte[][] { md5(new byte[][] { client_random, server_random, server_params } ), - sha(new byte[][] { client_random, server_random, server_params } ) } ); - - byte[] recievedSignature = rsa.processBlock(serverKeyExchange, 6 + server_params.length, - serverKeyExchange.length - 6 - server_params.length); - - for(int i=0; i> (i * 8)); - } - - /** fills b with random bytes */ - public static synchronized void getRandomBytes(byte[] b, int offset, int len) { - MD5Digest md5 = new MD5Digest(); - byte[] b2 = new byte[16]; - while(len > 0) { - md5.reset(); - md5.update(randpool, 0, randpool.length); - intToBytes(randcnt++, b2, 0, 8); - md5.update(b2, 0, 8); - md5.doFinal(b2, 0); - int n = len < 16 ? len : 16; - System.arraycopy(b2, 0, b, offset, n); - len -= n; - offset += n; - } - } - - public static byte[] computeMAC(byte type, byte[] payload, int off, int len, byte[] MAC_secret, long seq_num) { - byte[] MAC = new byte[16]; - MD5Digest md5 = new MD5Digest(); - md5.update(MAC_secret, 0, MAC_secret.length); - md5.update(pad1, 0, pad1.length); - - byte[] b = new byte[11]; - intToBytes(seq_num, b, 0, 8); - b[8] = type; - intToBytes(len, b, 9, 2); - md5.update(b, 0, b.length); - - md5.update(payload, off, len); - md5.doFinal(MAC, 0); - md5.reset(); - md5.update(MAC_secret, 0, MAC_secret.length); - md5.update(pad2, 0, pad2.length); - md5.update(MAC, 0, MAC.length); - md5.doFinal(MAC, 0); - - return MAC; - } - - public static byte[] concat(byte[][] inputs) { - int total = 0; - for(int i=0; i= block.length || start < HEADER_LENGTH) - throw new InvalidCipherTextException("no data in block"); - - byte[] result = new byte[block.length - start]; - System.arraycopy(block, start, result, 0, result.length); - return result; - } - } - -} - diff --git a/src/org/ibex/util/Scheduler.java b/src/org/ibex/util/Scheduler.java index 09487bd..e4c85fa 100644 --- a/src/org/ibex/util/Scheduler.java +++ b/src/org/ibex/util/Scheduler.java @@ -1,10 +1,12 @@ // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.util; import java.io.IOException; import org.ibex.js.*; import org.ibex.util.*; +import org.ibex.graphics.*; +import org.ibex.plat.*; /** Implements cooperative multitasking */ public class Scheduler { @@ -12,7 +14,6 @@ public class Scheduler { // Public API Exposed to org.ibex ///////////////////////////////////////////////// private static Scheduler singleton; - public static interface Task { public abstract void perform() throws IOException, JSExn; } public static void add(Task t) { Log.debug(Scheduler.class, "scheduling " + t); Scheduler.runnable.append(t); } public static void init() { if (singleton == null) (singleton = Platform.getScheduler()).run(); } @@ -52,7 +53,7 @@ public class Scheduler { * Surface.renderAll() more often than that if it so chooses. */ public void run() { defaultRun(); } - protected Scheduler() { } + public Scheduler() { } // Default Implementation ////////////////////////////////////////////////////// diff --git a/src/org/ibex/util/Task.java b/src/org/ibex/util/Task.java new file mode 100644 index 0000000..e710724 --- /dev/null +++ b/src/org/ibex/util/Task.java @@ -0,0 +1,8 @@ +// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] +package org.ibex.util; +import java.io.IOException; +import org.ibex.js.*; + +public interface Task { + public abstract void perform() throws IOException, JSExn; +}