зеркало из https://github.com/mozilla/pluotsorbet.git
Merge branch 'master' into clarify-licenses-hardest
Conflicts: jsshell.js
This commit is contained in:
Коммит
c393611362
|
@ -23,4 +23,10 @@ cache:
|
|||
- node_modules
|
||||
- /tmp/j2me.js
|
||||
notifications:
|
||||
irc: "irc.mozilla.org#j2mejs"
|
||||
irc:
|
||||
channels:
|
||||
- "irc.mozilla.org#j2me.js"
|
||||
template:
|
||||
- "%{repository_slug} - %{commit_message} - %{result} - %{build_url}"
|
||||
use_notice: true
|
||||
skip_join: true
|
||||
|
|
10
Makefile
10
Makefile
|
@ -1,10 +1,11 @@
|
|||
.PHONY: all test tests j2me java certs app clean jasmin aot shumway config-build
|
||||
.PHONY: all test tests j2me java certs app clean jasmin aot shumway config-build benchmarks
|
||||
BASIC_SRCS=$(shell find . -maxdepth 2 -name "*.ts" -not -path "./build/*") config.ts
|
||||
JIT_SRCS=$(shell find jit -name "*.ts" -not -path "./build/*")
|
||||
SHUMWAY_SRCS=$(shell find shumway -name "*.ts")
|
||||
RELEASE ?= 0
|
||||
VERSION ?=$(shell date +%s)
|
||||
PROFILE ?= 0
|
||||
BENCHMARK ?= 0
|
||||
|
||||
# Sensor support
|
||||
JSR_256 ?= 1
|
||||
|
@ -30,13 +31,14 @@ toBool = $(if $(findstring 1,$(1)),true,false)
|
|||
PREPROCESS = python tools/preprocess-1.1.0/lib/preprocess.py -s \
|
||||
-D RELEASE=$(call toBool,$(RELEASE)) \
|
||||
-D PROFILE=$(call toBool,$(PROFILE)) \
|
||||
-D BENCHMARK=$(call toBool,$(BENCHMARK)) \
|
||||
-D JSR_256=$(JSR_256) \
|
||||
-D JSR_179=$(JSR_179) \
|
||||
-D VERSION=$(VERSION)
|
||||
PREPROCESS_SRCS = $(shell find . -name "*.in" -not -path config/build.js.in)
|
||||
PREPROCESS_DESTS = $(PREPROCESS_SRCS:.in=)
|
||||
|
||||
all: config-build java jasmin tests j2me shumway aot
|
||||
all: config-build java jasmin tests j2me shumway aot benchmarks
|
||||
|
||||
test: all
|
||||
tests/runtests.py
|
||||
|
@ -108,6 +110,9 @@ certs:
|
|||
app: config-build java certs
|
||||
tools/package.sh
|
||||
|
||||
benchmarks:
|
||||
make -C bench
|
||||
|
||||
clean:
|
||||
rm -f j2me.js `find . -name "*~"`
|
||||
rm -rf build
|
||||
|
@ -115,3 +120,4 @@ clean:
|
|||
make -C tools/jasmin-2.4 clean
|
||||
make -C tests clean
|
||||
make -C java clean
|
||||
make -C bench clean
|
||||
|
|
20
README.md
20
README.md
|
@ -142,6 +142,26 @@ Modelines for JS files:
|
|||
|
||||
One way to profile j2me.js is to use the JS profiler available in Firefox Dev Tools. This will tell us how well the JVM is working and how well natives work. This type of profiling will not measure time that is taken waiting for async callbacks to be called (for example, when using the native JS filesystem API).
|
||||
|
||||
## Benchmarks
|
||||
|
||||
### Startup Benchmark
|
||||
|
||||
The startup benchmark measures from when the benchmark.js file loads to the call of `DisplayDevice.gainedForeground0`. Included in a benchmark build are helpers to build baseline scores so that subsequent runs of the benchmark can be compared. A t-test is used in the comparison to see if the changes were significant.
|
||||
|
||||
To use:
|
||||
|
||||
*It is recommended that a dedicated Firefox profile is used with the about:config preference of `security.turn_off_all_security_so_that_viruses_can_take_over_this_computer` set to true so garbage collection and cycle collection can be run in between test rounds*
|
||||
|
||||
1. Checkout the version you want to be the baseline(usually mozilla/master).
|
||||
1. Build a benchmark build `RELEASE=1 BENCHMARK=1 make` *"RELEASE=1" is not required, but is recommended to avoid debug code from changing execution behavior.*
|
||||
1. Open the midlet you want to test with `&logLevel=log` appended to the url and click `Build Benchmark Baseline`
|
||||
1. When finished, the message `FINISHED BUILDING BASELINE` will show up in the log.
|
||||
1. Apply/checkout your changes to the code
|
||||
1. Rebuild `RELEASE=1 BENCHMARK=1 make`
|
||||
1. Refresh the midlet
|
||||
1. Click `Run Startup Benchmark`
|
||||
1. Once done, the benchmark will dump results to the log. If it says "FASTER" or "SLOWER" the t-test has determined the results were significant. If it says "INSIGNIFICANT RESULT" the changes were likely not enough to be differentiated from the noise of the test.
|
||||
|
||||
## Filesystem
|
||||
|
||||
midp/fs.js contains native implementations of various midp filesystem APIs.
|
||||
|
|
|
@ -1,3 +1,25 @@
|
|||
com/sun/cldc/i18n/j2me/UTF_8_Reader.prepareForNextChar.(I)V
|
||||
com/sun/cldc/i18n/j2me/UTF_8_Reader.getByteOfCurrentChar.(IZ)I
|
||||
com/sun/cldc/io/ResourceInputStream.read.()I
|
||||
java/lang/StringBuffer.append.(C)Ljava/lang/StringBuffer;
|
||||
com/sun/cldc/io/ResourceInputStream.available.()I
|
||||
java/io/ByteArrayInputStream.read.()I
|
||||
java/lang/String.charAt.(I)C
|
||||
java/lang/String.length.()I
|
||||
java/lang/String.indexOf.(II)I
|
||||
java/lang/String.substring.(II)Ljava/lang/String;
|
||||
java/lang/String.<init>.(II[C)V
|
||||
java/lang/String.trim.()Ljava/lang/String;
|
||||
com/sun/cldc/i18n/uclc/DefaultCaseConverter.toUpperCase.(C)C
|
||||
java/io/ByteArrayOutputStream.write.([BII)V
|
||||
java/lang/String.equals.(Ljava/lang/Object;)Z
|
||||
java/lang/String.getChars.(II[CI)V
|
||||
java/lang/StringBuffer.append.(Ljava/lang/String;)Ljava/lang/StringBuffer;
|
||||
java/lang/StringBuffer.expandCapacity.(I)V
|
||||
java/lang/String.substring.(I)Ljava/lang/String;
|
||||
java/lang/String.indexOf.(Ljava/lang/String;I)I
|
||||
java/lang/StringBuffer.length.()I
|
||||
java/lang/String.indexOf.(Ljava/lang/String;)I
|
||||
java/util/Vector.indexOf.(Ljava/lang/Object;I)I
|
||||
java/util/PropertyPermission.getActions.(I)Ljava/lang/String;
|
||||
java/util/Vector.addElement.(Ljava/lang/Object;)V
|
||||
|
@ -297,4 +319,13 @@ java/util/Hashtable$HashtableEnumerator.nextElement.()Ljava/lang/Object;
|
|||
com/sun/midp/lcdui/DisplayDevice.isPrimaryDisplay.()Z
|
||||
com/sun/midp/main/MIDletProxy.getClassName.()Ljava/lang/String;
|
||||
com/sun/midp/rms/RmsEnvironment.getSecureFilenameBase.(I)Ljava/lang/String;
|
||||
com/sun/midp/midletsuite/SuiteContainerAdapter.getSecureFilenameBase.(I)Ljava/lang/String;
|
||||
com/sun/midp/midletsuite/SuiteContainerAdapter.getSecureFilenameBase.(I)Ljava/lang/String;
|
||||
com/nokia/mid/ui/gestures/GestureEventImpl.getType.()I
|
||||
com/nokia/mid/ui/gestures/GestureEventImpl.getDragDistanceX.()I
|
||||
com/nokia/mid/ui/gestures/GestureEventImpl.getDragDistanceY.()I
|
||||
com/nokia/mid/ui/gestures/GestureEventImpl.getStartX.()I
|
||||
com/nokia/mid/ui/gestures/GestureEventImpl.getStartY.()I
|
||||
com/nokia/mid/ui/gestures/GestureEventImpl.getFlickDirection.()F
|
||||
com/nokia/mid/ui/gestures/GestureEventImpl.getFlickSpeed.()I
|
||||
com/nokia/mid/ui/gestures/GestureEventImpl.getFlickSpeedX.()I
|
||||
com/nokia/mid/ui/gestures/GestureEventImpl.getFlickSpeedY.()I
|
|
@ -1,9 +1,6 @@
|
|||
interface TestInterface {
|
||||
public void asd();
|
||||
}
|
||||
|
||||
class SimpleClass {
|
||||
import com.sun.cldchi.jvm.JVM;
|
||||
|
||||
class BubbleSort {
|
||||
private static void bubbleSort(int [] a, int left, int right) {
|
||||
for (int i = right; i > 1; i--) {
|
||||
for (int j = left; j < i; j++) {
|
||||
|
@ -17,19 +14,21 @@ class SimpleClass {
|
|||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("I'm hungry");
|
||||
|
||||
int [] array = new int [1024];
|
||||
int[] array = new int[1024];
|
||||
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] = array.length - i;
|
||||
}
|
||||
|
||||
long total = 0L;
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
for (int j = 0; j < array.length; j++) {
|
||||
array[j] = array.length - j;
|
||||
}
|
||||
SimpleClass.bubbleSort(array, 0, array.length - 1);
|
||||
long start = JVM.monotonicTimeMillis();
|
||||
BubbleSort.bubbleSort(array, 0, array.length - 1);
|
||||
total += JVM.monotonicTimeMillis() - start;
|
||||
}
|
||||
|
||||
String s = "";
|
||||
|
@ -37,5 +36,7 @@ class SimpleClass {
|
|||
s += array[i] + " ";
|
||||
}
|
||||
System.out.println(s);
|
||||
|
||||
System.out.println("BubbleSort: " + total);
|
||||
}
|
||||
}
|
|
@ -18,25 +18,77 @@ public class ByteArrayInputOutputStreamBench {
|
|||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
void writeAndReadSingle(byte[] array) throws IOException {
|
||||
void writeSingle(byte[] array) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
baos.write(array[i]);
|
||||
}
|
||||
baos.close();
|
||||
}
|
||||
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
void readSingle(byte[] array) throws IOException {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(array);
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
int val = bais.read();
|
||||
int val = bais.read();
|
||||
}
|
||||
}
|
||||
|
||||
void writeAndReadArray(byte[] array) throws IOException {
|
||||
void writeArray64(byte[] array) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < 64; i++) {
|
||||
baos.write(array, i << 6, 64);
|
||||
baos.close();
|
||||
}
|
||||
}
|
||||
|
||||
void readArray64(byte[] array) throws IOException {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(array);
|
||||
byte[] output = new byte[4096];
|
||||
for (int i = 0; i < 64; i++) {
|
||||
bais.read(output, i << 6, 64);
|
||||
}
|
||||
}
|
||||
|
||||
void writeArray128(byte[] array) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < 32; i++) {
|
||||
baos.write(array, i << 7, 128);
|
||||
}
|
||||
baos.close();
|
||||
}
|
||||
|
||||
void readArray128(byte[] array) throws IOException {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(array);
|
||||
byte[] output = new byte[4096];
|
||||
for (int i = 0; i < 32; i++) {
|
||||
bais.read(output, i << 7, 128);
|
||||
}
|
||||
}
|
||||
|
||||
void writeArray256(byte[] array) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < 16; i++) {
|
||||
baos.write(array, i << 8, 256);
|
||||
}
|
||||
baos.close();
|
||||
}
|
||||
|
||||
void readArray256(byte[] array) throws IOException {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(array);
|
||||
byte[] output = new byte[4096];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
bais.read(output, i << 8, 256);
|
||||
}
|
||||
}
|
||||
|
||||
void writeArray(byte[] array) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write(array, 0, 4096);
|
||||
baos.close();
|
||||
}
|
||||
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
void readArray(byte[] array) throws IOException {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(array);
|
||||
byte[] output = new byte[4096];
|
||||
bais.read(output, 0, 4096);
|
||||
}
|
||||
|
@ -45,21 +97,77 @@ public class ByteArrayInputOutputStreamBench {
|
|||
try {
|
||||
long start, time;
|
||||
|
||||
byte[] array = generateArray();
|
||||
byte[] array = generateArray();
|
||||
|
||||
start = JVM.monotonicTimeMillis();
|
||||
for (int i = 0; i < 250; i++) {
|
||||
writeAndReadSingle(array);
|
||||
writeSingle(array);
|
||||
}
|
||||
time = JVM.monotonicTimeMillis() - start;
|
||||
System.out.println("writeAndReadSingle: " + time);
|
||||
System.out.println("writeSingle: " + time);
|
||||
|
||||
start = JVM.monotonicTimeMillis();
|
||||
for (int i = 0; i < 20000; i++) {
|
||||
writeAndReadArray(array);
|
||||
for (int i = 0; i < 250; i++) {
|
||||
readSingle(array);
|
||||
}
|
||||
time = JVM.monotonicTimeMillis() - start;
|
||||
System.out.println("writeAndReadArray: " + time);
|
||||
System.out.println("readSingle: " + time);
|
||||
|
||||
start = JVM.monotonicTimeMillis();
|
||||
for (int i = 0; i < 5000; i++) {
|
||||
writeArray64(array);
|
||||
}
|
||||
time = JVM.monotonicTimeMillis() - start;
|
||||
System.out.println("writeArray64: " + time);
|
||||
|
||||
start = JVM.monotonicTimeMillis();
|
||||
for (int i = 0; i < 5000; i++) {
|
||||
readArray64(array);
|
||||
}
|
||||
time = JVM.monotonicTimeMillis() - start;
|
||||
System.out.println("readArray64: " + time);
|
||||
|
||||
start = JVM.monotonicTimeMillis();
|
||||
for (int i = 0; i < 5000; i++) {
|
||||
writeArray128(array);
|
||||
}
|
||||
time = JVM.monotonicTimeMillis() - start;
|
||||
System.out.println("writeArray128: " + time);
|
||||
|
||||
start = JVM.monotonicTimeMillis();
|
||||
for (int i = 0; i < 5000; i++) {
|
||||
readArray128(array);
|
||||
}
|
||||
time = JVM.monotonicTimeMillis() - start;
|
||||
System.out.println("readArray128: " + time);
|
||||
|
||||
start = JVM.monotonicTimeMillis();
|
||||
for (int i = 0; i < 5000; i++) {
|
||||
writeArray256(array);
|
||||
}
|
||||
time = JVM.monotonicTimeMillis() - start;
|
||||
System.out.println("writeArray256: " + time);
|
||||
|
||||
start = JVM.monotonicTimeMillis();
|
||||
for (int i = 0; i < 5000; i++) {
|
||||
readArray256(array);
|
||||
}
|
||||
time = JVM.monotonicTimeMillis() - start;
|
||||
System.out.println("readArray256: " + time);
|
||||
|
||||
start = JVM.monotonicTimeMillis();
|
||||
for (int i = 0; i < 25000; i++) {
|
||||
writeArray(array);
|
||||
}
|
||||
time = JVM.monotonicTimeMillis() - start;
|
||||
System.out.println("writeArray: " + time);
|
||||
|
||||
start = JVM.monotonicTimeMillis();
|
||||
for (int i = 0; i < 25000; i++) {
|
||||
readArray(array);
|
||||
}
|
||||
time = JVM.monotonicTimeMillis() - start;
|
||||
System.out.println("readArray: " + time);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
import java.lang.Object;
|
||||
import java.lang.System;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import org.mozilla.internal.Sys;
|
||||
import com.sun.cldchi.jvm.JVM;
|
||||
|
||||
class JITBenchmark {
|
||||
|
||||
static class A {}
|
||||
static class B extends A {}
|
||||
|
||||
public static int size = 0;
|
||||
public static long start = 0;
|
||||
|
||||
public static void createObjectArrays() {
|
||||
Object array = null;
|
||||
int count = size / 8;
|
||||
for (int i = 0; i < count; i++) {
|
||||
array = new Object[64];
|
||||
array = new Object[128];
|
||||
array = new Object[256];
|
||||
array = new Object[512];
|
||||
}
|
||||
}
|
||||
|
||||
public static void createPrimitiveArrays() {
|
||||
Object array = null;
|
||||
int count = size / 8;
|
||||
for (int i = 0; i < count; i++) {
|
||||
array = new int[64];
|
||||
array = new int[128];
|
||||
array = new int[256];
|
||||
array = new int[512];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void writeByteArrayOutputStream() {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
int count = size * 16;
|
||||
for (int i = 0; i < count; i++) {
|
||||
stream.write(i);
|
||||
stream.write(i);
|
||||
stream.write(i);
|
||||
stream.write(i);
|
||||
}
|
||||
}
|
||||
|
||||
public static void concatStrings() {
|
||||
String s = "";
|
||||
int count = size / 16;
|
||||
for (int i = 0; i < count; i++) {
|
||||
s += "X";
|
||||
}
|
||||
}
|
||||
|
||||
public static void getBytes() {
|
||||
String s = "getBytesgetBytesgetBytesgetBytesgetBytesgetBytesgetBytesgetBytesgetBytesgetBytesgetBytesgetBytesgetBytesgetBytesgetBytesgetBytes";
|
||||
int count = size / 4;
|
||||
byte [] bytes = null;
|
||||
for (int i = 0; i < count; i++) {
|
||||
bytes = s.getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
public static void synch() {
|
||||
int count = size * 32;
|
||||
byte [] bytes = null;
|
||||
Object o = new Object();
|
||||
int sum = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
synchronized (o) {
|
||||
sum++;
|
||||
}
|
||||
synchronized (o) {
|
||||
sum++;
|
||||
}
|
||||
synchronized (o) {
|
||||
sum++;
|
||||
}
|
||||
synchronized (o) {
|
||||
sum++;
|
||||
}
|
||||
synchronized (o) {
|
||||
sum++;
|
||||
}
|
||||
synchronized (o) {
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void hashtable() {
|
||||
int count = size * 2;
|
||||
Hashtable hash = new Hashtable();
|
||||
Object o = new Object();
|
||||
String [] names = {
|
||||
"hello", "world", "hello1", "world2", "hello3", "world4", "hello5", "world6"
|
||||
};
|
||||
for (int i = 0; i < count; i++) {
|
||||
String name = names[i % names.length];
|
||||
hash.put(name, o);
|
||||
hash.get(name);
|
||||
hash.put(name, o);
|
||||
hash.get(name);
|
||||
hash.put(name, o);
|
||||
hash.get(name);
|
||||
hash.put(name, o);
|
||||
hash.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
public static void arrayTypeCheck() {
|
||||
A [] array = new A [1024];
|
||||
A a = new A();
|
||||
B b = new B();
|
||||
int count = size * 3;
|
||||
for (int i = 0; i < count - 1; i++) {
|
||||
array[i % 1024] = a;
|
||||
array[i % 1024] = b;
|
||||
}
|
||||
}
|
||||
|
||||
public static void begin() {
|
||||
System.gc();
|
||||
start = JVM.monotonicTimeMillis();
|
||||
}
|
||||
|
||||
public static void finish(String name) {
|
||||
System.out.println(name + ": " + (JVM.monotonicTimeMillis() - start));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
// Sys.eval("J2ME.emitCheckArrayStore = false;");
|
||||
// Sys.eval("J2ME.emitCheckArrayBounds = false;");
|
||||
|
||||
size = 1024;
|
||||
|
||||
begin();
|
||||
start = JVM.monotonicTimeMillis();
|
||||
createObjectArrays();
|
||||
createPrimitiveArrays();
|
||||
writeByteArrayOutputStream();
|
||||
concatStrings();
|
||||
getBytes();
|
||||
synch();
|
||||
hashtable();
|
||||
arrayTypeCheck();
|
||||
finish("startup");
|
||||
|
||||
size = 1024 * 256;
|
||||
|
||||
long start = JVM.monotonicTimeMillis();
|
||||
begin();
|
||||
createObjectArrays();
|
||||
finish("createObjectArrays");
|
||||
|
||||
begin();
|
||||
createPrimitiveArrays();
|
||||
finish("createPrimitiveArrays");
|
||||
|
||||
begin();
|
||||
writeByteArrayOutputStream();
|
||||
finish("writeByteArrayOutputStream");
|
||||
|
||||
begin();
|
||||
concatStrings();
|
||||
finish("concatStrings");
|
||||
|
||||
begin();
|
||||
getBytes();
|
||||
finish("getBytes");
|
||||
|
||||
begin();
|
||||
synch();
|
||||
finish("synchronize");
|
||||
|
||||
begin();
|
||||
hashtable();
|
||||
finish("hashtable");
|
||||
|
||||
begin();
|
||||
arrayTypeCheck();
|
||||
finish("arrayTypeCheck");
|
||||
|
||||
System.out.println();
|
||||
System.out.println("Total: " + (JVM.monotonicTimeMillis() - start));
|
||||
}
|
||||
}
|
|
@ -59,6 +59,7 @@ public class UTF8Bench {
|
|||
InputStream is = file.openInputStream();
|
||||
start = JVM.monotonicTimeMillis();
|
||||
readUtf8Data(is);
|
||||
time = JVM.monotonicTimeMillis() - start;
|
||||
System.out.println("readUtf8Data: " + time);
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
var Benchmark = (function() {
|
||||
|
||||
function mean(array) {
|
||||
function add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
return array.reduce(add, 0) / array.length;
|
||||
}
|
||||
|
||||
var defaultStorage = {
|
||||
numRounds: 10,
|
||||
roundDelay: 5000, // ms to delay starting next round of tests
|
||||
baseline: [],
|
||||
running: false,
|
||||
round: 0,
|
||||
times: [],
|
||||
deleteFs: true,
|
||||
deleteJitCache: true,
|
||||
buildBaseline: false
|
||||
};
|
||||
|
||||
function Storage(key, defaults) {
|
||||
this.key = key;
|
||||
if (!(key in localStorage)) {
|
||||
this.storage = defaults;
|
||||
this.save();
|
||||
}
|
||||
this.storage = JSON.parse(localStorage[key]);
|
||||
Object.keys(defaultStorage).forEach(function(key) {
|
||||
Object.defineProperty(this, key, {
|
||||
get: function() { return this.storage[key]; },
|
||||
set: function(newValue) { this.storage[key] = newValue; this.save() },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
}, this);
|
||||
}
|
||||
|
||||
Storage.prototype = {
|
||||
save: function() {
|
||||
localStorage[this.key] = JSON.stringify(this.storage);
|
||||
}
|
||||
};
|
||||
|
||||
var storage = new Storage("benchmark", defaultStorage);
|
||||
|
||||
var startup = {
|
||||
run: function(settings) {
|
||||
storage.round = 0;
|
||||
storage.times = [];
|
||||
storage.running = true;
|
||||
storage.numRounds = "numRounds" in settings ? settings.numRounds : defaultStorage.numRounds;
|
||||
storage.roundDelay = "roundDelay" in settings ? settings.roundDelay : defaultStorage.roundDelay;
|
||||
storage.deleteFs = "deleteFs" in settings ? settings.deleteFs : defaultStorage.deleteFs;
|
||||
storage.deleteJitCache = "deleteJitCache" in settings ? settings.deleteJitCache : defaultStorage.deleteJitCache;
|
||||
storage.buildBaseline = "buildBaseline" in settings ? settings.buildBaseline : defaultStorage.buildBaseline;
|
||||
if (storage.buildBaseline) {
|
||||
storage.baseline = [];
|
||||
}
|
||||
this.runNextRound();
|
||||
},
|
||||
startTimer: function() {
|
||||
if (!storage.running) {
|
||||
console.log("startTimer called while benchmark not running");
|
||||
return;
|
||||
}
|
||||
this.startTime = performance.now();
|
||||
},
|
||||
stopTimer: function() {
|
||||
if (!storage.running) {
|
||||
console.log("stopTimer called while benchmark not running");
|
||||
return;
|
||||
}
|
||||
if (this.startTime === null) {
|
||||
console.log("stopTimer called without previous call to startTimer");
|
||||
return;
|
||||
}
|
||||
var took = performance.now() - this.startTime;
|
||||
this.startTime = null;
|
||||
var times = storage.times;
|
||||
times.push(took);
|
||||
storage.times = times;
|
||||
storage.round++;
|
||||
if (storage.round >= storage.numRounds) {
|
||||
this.finish();
|
||||
return;
|
||||
}
|
||||
this.runNextRound();
|
||||
},
|
||||
runNextRound: function() {
|
||||
function run() {
|
||||
DumbPipe.close(DumbPipe.open("reload", {}));
|
||||
}
|
||||
if (typeof netscape !== "undefined" && netscape.security.PrivilegeManager) {
|
||||
// To enable GC use a seperate profile and enable the pref:
|
||||
// security.turn_off_all_security_so_that_viruses_can_take_over_this_computer
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
console.log("Forcing CC/GC.");
|
||||
for (var i = 0; i < 3; i++) {
|
||||
Components.utils.forceCC();
|
||||
Components.utils.forceGC();
|
||||
}
|
||||
}
|
||||
if (storage.deleteFs) {
|
||||
console.log("Deleting fs.");
|
||||
indexedDB.deleteDatabase("asyncStorage");
|
||||
}
|
||||
if (storage.deleteJitCache) {
|
||||
console.log("Deleting jit cache.");
|
||||
indexedDB.deleteDatabase("CompiledMethodCache");
|
||||
}
|
||||
console.log("Scheduling round " + (storage.round + 1) + " of " + storage.numRounds + " to run in " + storage.roundDelay + "ms");
|
||||
setTimeout(run, storage.roundDelay);
|
||||
},
|
||||
finish: function() {
|
||||
storage.running = false;
|
||||
var times = storage.times;
|
||||
var message = "Current times: " + JSON.stringify(times) + "\n";
|
||||
var baselineMean = mean(storage.baseline);
|
||||
var currentMean = mean(times);
|
||||
message += "Current mean : " + Math.round(currentMean) + "ms\n";
|
||||
if (storage.baseline.length) {
|
||||
message +=
|
||||
"Baseline mean: " + Math.round(baselineMean) + "ms\n" +
|
||||
"+/- : " + Math.round(currentMean - baselineMean) + "ms\n" +
|
||||
"% : " + (100 * (currentMean - baselineMean) / baselineMean).toFixed(2) + "\n";
|
||||
}
|
||||
if (storage.baseline.length) {
|
||||
var p = (storage.baseline.length < 2) ? 1 : ttest(storage.baseline, times).pValue();
|
||||
if (p < 0.05) {
|
||||
message += currentMean < baselineMean ? "FASTER" : "SLOWER";
|
||||
} else {
|
||||
message += "INSIGNIFICANT RESULT";
|
||||
}
|
||||
}
|
||||
if (storage.buildBaseline) {
|
||||
storage.baseline = times;
|
||||
storage.buildBaseline = false;
|
||||
message = "FINISHED BUILDING BASELINE\n" + message;
|
||||
}
|
||||
message = "-------------------------------------------------------------\n" +
|
||||
message + "\n" +
|
||||
"-------------------------------------------------------------\n";
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Start right away instead of in init() so we can see any speedups in script loading.
|
||||
if (storage.running) {
|
||||
startup.startTimer();
|
||||
}
|
||||
|
||||
return {
|
||||
initUI: function() {
|
||||
var numRoundsEl = document.getElementById("benchmark-num-rounds");
|
||||
var roundDelayEl = document.getElementById("benchmark-round-delay");
|
||||
var deleteFsEl = document.getElementById("benchmark-delete-fs");
|
||||
var deleteJitCacheEl = document.getElementById("benchmark-delete-jit-cache");
|
||||
var startButton = document.getElementById("benchmark-startup-run");
|
||||
var baselineButton = document.getElementById("benchmark-startup-baseline");
|
||||
|
||||
numRoundsEl.value = storage.numRounds;
|
||||
roundDelayEl.value = storage.roundDelay;
|
||||
deleteFsEl.checked = storage.deleteFs;
|
||||
deleteJitCacheEl.checked = storage.deleteJitCache;
|
||||
|
||||
if (storage.baseline.length === 0) {
|
||||
startButton.disabled = true;
|
||||
}
|
||||
|
||||
function getSettings() {
|
||||
return {
|
||||
numRounds: numRoundsEl.value | 0,
|
||||
roundDelay: roundDelayEl.value | 0,
|
||||
deleteFs: !!deleteFsEl.checked,
|
||||
deleteJitCache: !!deleteJitCacheEl.checked,
|
||||
};
|
||||
}
|
||||
|
||||
startButton.onclick = function() {
|
||||
startup.run(getSettings());
|
||||
};
|
||||
|
||||
baselineButton.onclick = function() {
|
||||
var settings = getSettings();
|
||||
settings["buildBaseline"] = true;
|
||||
startup.run(settings);
|
||||
};
|
||||
},
|
||||
startup: {
|
||||
init: function() {
|
||||
if (!storage.running) {
|
||||
return;
|
||||
}
|
||||
var implKey = "com/sun/midp/lcdui/DisplayDevice.gainedForeground0.(II)V";
|
||||
var originalFn = Native[implKey];
|
||||
Native[implKey] = function() {
|
||||
startup.stopTimer();
|
||||
originalFn.apply(null, arguments);
|
||||
};
|
||||
},
|
||||
run: startup.run.bind(startup),
|
||||
}
|
||||
};
|
||||
})();
|
24
bindings.ts
24
bindings.ts
|
@ -11,6 +11,15 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
},
|
||||
"java/lang/String": {
|
||||
fields: {
|
||||
instanceSymbols: {
|
||||
"value.[C": "value",
|
||||
"offset.I": "offset",
|
||||
"count.I": "count"
|
||||
}
|
||||
}
|
||||
},
|
||||
"java/lang/Thread": {
|
||||
fields: {
|
||||
instanceSymbols: {
|
||||
|
@ -18,14 +27,6 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
},
|
||||
"java/io/ByteArrayOutputStream": {
|
||||
fields: {
|
||||
instanceSymbols: {
|
||||
"count.I": "count",
|
||||
"buf.[B": "buf"
|
||||
}
|
||||
}
|
||||
},
|
||||
"com/sun/cldc/i18n/j2me/UTF_8_Writer": {
|
||||
fields: {
|
||||
instanceSymbols: {
|
||||
|
@ -197,7 +198,12 @@ module J2ME {
|
|||
}
|
||||
|
||||
export interface String extends java.lang.Object {
|
||||
str: string;
|
||||
value: Uint16Array;
|
||||
offset: number;
|
||||
count: number;
|
||||
_offset: number;
|
||||
_count: number
|
||||
_value: string;
|
||||
}
|
||||
|
||||
export interface Thread extends java.lang.Object {
|
||||
|
|
|
@ -1,27 +1,71 @@
|
|||
package com.nokia.mid.ui.gestures;
|
||||
|
||||
import com.sun.midp.events.NativeEvent;
|
||||
|
||||
public class GestureEventImpl implements GestureEvent {
|
||||
public GestureEventImpl(int type, int dragDistanceX, int dragDistanceY, int startX, int startY,
|
||||
float flickDirection, int flickSpeed, int flickSpeedX, int flickSpeedY,
|
||||
int pinchDistanceStarting, int pinchDistanceCurrent, int pinchDistanceChange,
|
||||
int pinchCenterX, int pinchCenterY, int pinchCenterChangeX, int pinchCenterChangeY) {
|
||||
// Overridden in midp/gestures.js
|
||||
protected NativeEvent nativeEvent;
|
||||
|
||||
public int getType() {
|
||||
return nativeEvent.intParam1;
|
||||
}
|
||||
|
||||
native public int getType();
|
||||
native public int getDragDistanceX();
|
||||
native public int getDragDistanceY();
|
||||
native public int getStartX();
|
||||
native public int getStartY();
|
||||
native public float getFlickDirection();
|
||||
native public int getFlickSpeed();
|
||||
native public int getFlickSpeedX();
|
||||
native public int getFlickSpeedY();
|
||||
native public int getPinchDistanceStarting();
|
||||
native public int getPinchDistanceCurrent();
|
||||
native public int getPinchDistanceChange();
|
||||
native public int getPinchCenterX();
|
||||
native public int getPinchCenterY();
|
||||
native public int getPinchCenterChangeX();
|
||||
native public int getPinchCenterChangeY();
|
||||
public int getDragDistanceX() {
|
||||
return nativeEvent.intParam2;
|
||||
}
|
||||
|
||||
public int getDragDistanceY() {
|
||||
return nativeEvent.intParam3;
|
||||
}
|
||||
|
||||
public int getStartX() {
|
||||
return nativeEvent.intParam5;
|
||||
}
|
||||
|
||||
public int getStartY() {
|
||||
return nativeEvent.intParam6;
|
||||
}
|
||||
|
||||
public float getFlickDirection() {
|
||||
return nativeEvent.floatParam1;
|
||||
}
|
||||
|
||||
public int getFlickSpeed() {
|
||||
return nativeEvent.intParam7;
|
||||
}
|
||||
|
||||
public int getFlickSpeedX() {
|
||||
return nativeEvent.intParam8;
|
||||
}
|
||||
|
||||
public int getFlickSpeedY() {
|
||||
return nativeEvent.intParam9;
|
||||
}
|
||||
|
||||
public int getPinchDistanceStarting() {
|
||||
return nativeEvent.intParam10;
|
||||
}
|
||||
|
||||
public int getPinchDistanceCurrent() {
|
||||
return nativeEvent.intParam11;
|
||||
}
|
||||
|
||||
public int getPinchDistanceChange() {
|
||||
return nativeEvent.intParam12;
|
||||
}
|
||||
|
||||
public int getPinchCenterX() {
|
||||
return nativeEvent.intParam13;
|
||||
}
|
||||
|
||||
public int getPinchCenterY() {
|
||||
return nativeEvent.intParam14;
|
||||
}
|
||||
|
||||
public int getPinchCenterChangeX() {
|
||||
return nativeEvent.intParam15;
|
||||
}
|
||||
|
||||
public int getPinchCenterChangeY() {
|
||||
return nativeEvent.intParam16;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,11 @@ public class GestureRegistrationManager implements EventListener {
|
|||
private static Vector zoneRegistrations = new Vector();
|
||||
private static Hashtable listenerRegistrations = new Hashtable();
|
||||
|
||||
// http://developer.nokia.com/resources/library/Java/_zip/GUID-237420DE-CCBE-4A74-A129-572E0708D428/com/nokia/mid/ui/gestures/GestureEvent.html
|
||||
// The API imposes the restriction that the gesture event data is only valid during the call to
|
||||
// GestureListener.gestureAction(Object, GestureInteractiveZone, GestureEvent).
|
||||
private static GestureEventImpl gestureEvent = new GestureEventImpl();
|
||||
|
||||
static {
|
||||
EventQueue eventQueue = EventQueue.getEventQueue();
|
||||
eventQueue.registerEventListener(EventTypes.GESTURE_EVENT, GestureRegistrationManager.getRegistrationManagerInstance());
|
||||
|
@ -40,23 +45,7 @@ public class GestureRegistrationManager implements EventListener {
|
|||
}
|
||||
|
||||
public void process(Event event) {
|
||||
NativeEvent nativeEvent = (NativeEvent)event;
|
||||
GestureEvent gestureEvent = new GestureEventImpl(nativeEvent.intParam1,
|
||||
nativeEvent.intParam2,
|
||||
nativeEvent.intParam3,
|
||||
nativeEvent.intParam5,
|
||||
nativeEvent.intParam6,
|
||||
nativeEvent.floatParam1,
|
||||
nativeEvent.intParam7,
|
||||
nativeEvent.intParam8,
|
||||
nativeEvent.intParam9,
|
||||
nativeEvent.intParam10,
|
||||
nativeEvent.intParam11,
|
||||
nativeEvent.intParam12,
|
||||
nativeEvent.intParam13,
|
||||
nativeEvent.intParam14,
|
||||
nativeEvent.intParam15,
|
||||
nativeEvent.intParam16);
|
||||
gestureEvent.nativeEvent = (NativeEvent)event;
|
||||
|
||||
for (int i = 0; i < zoneRegistrations.size(); i++) {
|
||||
ZoneRegistration zoneReg = (ZoneRegistration)zoneRegistrations.elementAt(i);
|
||||
|
|
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License version 2 for more details (a copy is
|
||||
* included at /legal/license.txt).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this work; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.cldc.i18n.j2me;
|
||||
|
||||
import com.sun.cldc.i18n.StreamReader;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/** Reader for UTF-8 encoded input streams. */
|
||||
public class UTF_8_Reader extends StreamReader {
|
||||
boolean initialized = false;
|
||||
|
||||
/** Constructs a UTF-8 reader. */
|
||||
public UTF_8_Reader() {
|
||||
}
|
||||
|
||||
public Reader open(InputStream in, String enc)
|
||||
throws UnsupportedEncodingException {
|
||||
super.open(in, enc);
|
||||
return this;
|
||||
}
|
||||
|
||||
private native void init(byte[] bytes);
|
||||
|
||||
/**
|
||||
* Read a block of UTF8 characters.
|
||||
*
|
||||
* @param cbuf output buffer for converted characters read
|
||||
* @param off initial offset into the provided buffer
|
||||
* @param len length of characters in the buffer
|
||||
* @return the number of converted characters
|
||||
* @exception IOException is thrown if the input stream
|
||||
* could not be read for the raw unconverted character
|
||||
*/
|
||||
public native int readNative(char cbuf[], int off, int len);
|
||||
public int read(char cbuf[], int off, int len) throws IOException {
|
||||
if (!initialized) {
|
||||
// Read the whole stream in memory
|
||||
byte[] buffer = new byte[1024];
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
try {
|
||||
int numRead = 0;
|
||||
while ((numRead = in.read(buffer)) > -1) {
|
||||
output.write(buffer, 0, numRead);
|
||||
}
|
||||
output.flush();
|
||||
} catch (Exception e) {
|
||||
throw new UnsupportedEncodingException("Failed to read from the stream");
|
||||
}
|
||||
|
||||
init(output.toByteArray());
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
return readNative(cbuf, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the present position in the stream.
|
||||
*
|
||||
* @param readAheadLimit number of characters to buffer ahead
|
||||
* @exception IOException If an I/O error occurs or
|
||||
* marking is not supported by the underlying input stream.
|
||||
*/
|
||||
public void mark(int readAheadLimit) throws IOException {
|
||||
throw new RuntimeException("WARNING: mark() not supported in the overriden UTF_8_Reader");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the read ahead marks is not supported for UTF8 readers.
|
||||
* @exception IOException is thrown, for all calls to this method
|
||||
* because marking is not supported for UTF8 readers
|
||||
*/
|
||||
public void reset() throws IOException {
|
||||
throw new RuntimeException("WARNING: reset() not supported in the overriden UTF_8_Reader");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size in chars of an array of bytes.
|
||||
*
|
||||
* @param array Source buffer
|
||||
* @param offset Offset at which to start counting characters
|
||||
* @param length number of bytes to use for counting
|
||||
*
|
||||
* @return number of characters that would be converted
|
||||
*/
|
||||
/*
|
||||
* This method is only used by our internal Helper class in the method
|
||||
* byteToCharArray to know how much to allocate before using a
|
||||
* reader. If we encounter bad encoding we should return a count
|
||||
* that includes that character so the reader will throw an IOException
|
||||
*/
|
||||
public int sizeOf(byte[] array, int offset, int length) {
|
||||
int count = 0;
|
||||
int endOfArray;
|
||||
int extraBytes;
|
||||
|
||||
for (endOfArray = offset + length; offset < endOfArray; ) {
|
||||
int oldCount = count;
|
||||
count++;
|
||||
/* Reduce amount of case-mode comparisons */
|
||||
if ((array[offset]&0x80) == 0) {
|
||||
extraBytes = 0;
|
||||
} else {
|
||||
switch (((int)array[offset] & 0xff) >> 4) {
|
||||
case 12: case 13:
|
||||
/* 11 bits: 110x xxxx 10xx xxxx */
|
||||
extraBytes = 1;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
/* 16 bits: 1110 xxxx 10xx xxxx 10xx xxxx */
|
||||
extraBytes = 2;
|
||||
break;
|
||||
|
||||
case 15:
|
||||
if (((int)array[offset] & 0x08)==0) {
|
||||
/* 21 bits: 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */
|
||||
// we imply that the 5 high bits are not all zeroes
|
||||
extraBytes = 3;
|
||||
count++;
|
||||
break;
|
||||
} // else as default
|
||||
|
||||
default:
|
||||
/*
|
||||
* this byte will be replaced with 'RC'
|
||||
*/
|
||||
extraBytes = 0;
|
||||
}
|
||||
}
|
||||
offset++;
|
||||
// test if extra bytes are in form 10xx xxxx
|
||||
while (extraBytes-- > 0){
|
||||
if (offset < endOfArray) {
|
||||
if ((((int)array[offset]) & 0xC0) != 0x80) {
|
||||
break; // test fails: char will be replaced with 'RC'
|
||||
} else {
|
||||
offset++;
|
||||
}
|
||||
} else {
|
||||
// broken sequence of bytes detected at the array tail
|
||||
// the broken char still must be counted
|
||||
count = oldCount+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License version 2 for more details (a copy is
|
||||
* included at /legal/license.txt).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this work; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.cldc.i18n.j2me;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Writer for UTF-8 encoded output streams. NOTE: The UTF-8 writer only
|
||||
* supports UCS-2, or Unicode, to UTF-8 conversion. There is no support
|
||||
* for UTF-16 encoded characters outside of the Basic Multilingual Plane
|
||||
* (BMP). These are encoded in UTF-16 using previously reserved values
|
||||
* between U+D800 and U+DFFF. Additionally, the UTF-8 writer does not
|
||||
* support any character that requires 4 or more UTF-8 encoded bytes.
|
||||
*/
|
||||
public class UTF_8_Writer extends com.sun.cldc.i18n.StreamWriter {
|
||||
|
||||
/** pending high surrogate code unit, or zero */
|
||||
protected int pendingSurrogate;
|
||||
|
||||
/** This value replaces invalid characters
|
||||
* (that is, surrogates code units without a pair) */
|
||||
static final private int replacementValue = 0x3f;
|
||||
|
||||
/**
|
||||
* Write a portion of an array of characters.
|
||||
*
|
||||
* @param cbuf Array of characters
|
||||
* @param off Offset from which to start writing characters
|
||||
* @param len Number of characters to write
|
||||
*
|
||||
* @exception IOException If an I/O error occurs
|
||||
*/
|
||||
public void write(char cbuf[], int off, int len) throws IOException {
|
||||
out.write(encodeUTF8(cbuf, off, len));
|
||||
}
|
||||
|
||||
private native byte[] encodeUTF8(char cbuf[], int off, int len);
|
||||
|
||||
/**
|
||||
* Get the size in bytes of an array of chars.
|
||||
*
|
||||
* @param cbuf Source buffer
|
||||
* @param offset Offset at which to start counting character sizes
|
||||
* @param length number of characters to use for counting
|
||||
*
|
||||
* @return number of bytes that the characters would be converted to
|
||||
*/
|
||||
public native int sizeOf(char[] cbuf, int offset, int length);
|
||||
|
||||
/**
|
||||
* Open the writer.
|
||||
*
|
||||
* @param outputStream
|
||||
* @param encoding encoding
|
||||
* @return the writer
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public Writer open(OutputStream outputStream, String encoding)
|
||||
throws UnsupportedEncodingException {
|
||||
pendingSurrogate = 0;
|
||||
return super.open(outputStream,encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the writer and the output stream.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (0 != pendingSurrogate) {
|
||||
// write replacement value instead of the unpaired surrogate
|
||||
byte[] outputByte = new byte[1];
|
||||
outputByte[0] = replacementValue;
|
||||
out.write(outputByte, 0, 1);
|
||||
}
|
||||
pendingSurrogate = 0;
|
||||
super.close();
|
||||
}
|
||||
|
||||
// flush() can do nothing with pendingSurrogate because the surrogate
|
||||
// contains only a portion of the character code, and the second half
|
||||
// is still expected to arrive.
|
||||
// public void flush() throws IOException { super.flush(); }
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License version 2 for more details (a copy is
|
||||
* included at /legal/license.txt).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this work; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*/
|
||||
|
||||
package java.io;
|
||||
|
||||
import com.sun.cldchi.jvm.JVM;
|
||||
import org.mozilla.internal.Sys;
|
||||
|
||||
/**
|
||||
* A <code>ByteArrayInputStream</code> contains
|
||||
* an internal buffer that contains bytes that
|
||||
* may be read from the stream. An internal
|
||||
* counter keeps track of the next byte to
|
||||
* be supplied by the <code>read</code> method.
|
||||
*
|
||||
* @version 12/17/01 (CLDC 1.1)
|
||||
* @since JDK1.0, CLDC 1.0
|
||||
*/
|
||||
public
|
||||
class ByteArrayInputStream extends InputStream {
|
||||
|
||||
/**
|
||||
* An array of bytes that was provided
|
||||
* by the creator of the stream. Elements <code>buf[0]</code>
|
||||
* through <code>buf[count-1]</code> are the
|
||||
* only bytes that can ever be read from the
|
||||
* stream; element <code>buf[pos]</code> is
|
||||
* the next byte to be read.
|
||||
*/
|
||||
protected byte buf[];
|
||||
|
||||
/**
|
||||
* The index of the next character to read from the input stream buffer.
|
||||
* This value should always be nonnegative
|
||||
* and not larger than the value of <code>count</code>.
|
||||
* The next byte to be read from the input stream buffer
|
||||
* will be <code>buf[pos]</code>.
|
||||
*/
|
||||
protected int pos;
|
||||
|
||||
/**
|
||||
* The currently marked position in the stream.
|
||||
* ByteArrayInputStream objects are marked at position zero by
|
||||
* default when constructed. They may be marked at another
|
||||
* position within the buffer by the <code>mark()</code> method.
|
||||
* The current buffer position is set to this point by the
|
||||
* <code>reset()</code> method.
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
protected int mark = 0;
|
||||
|
||||
/**
|
||||
* The index one greater than the last valid character in the input
|
||||
* stream buffer.
|
||||
* This value should always be nonnegative
|
||||
* and not larger than the length of <code>buf</code>.
|
||||
* It is one greater than the position of
|
||||
* the last byte within <code>buf</code> that
|
||||
* can ever be read from the input stream buffer.
|
||||
*/
|
||||
protected int count;
|
||||
|
||||
/**
|
||||
* Creates a <code>ByteArrayInputStream</code>
|
||||
* so that it uses <code>buf</code> as its
|
||||
* buffer array.
|
||||
* The buffer array is not copied.
|
||||
* The initial value of <code>pos</code>
|
||||
* is <code>0</code> and the initial value
|
||||
* of <code>count</code> is the length of
|
||||
* <code>buf</code>.
|
||||
*
|
||||
* @param buf the input buffer.
|
||||
*/
|
||||
public ByteArrayInputStream(byte buf[]) {
|
||||
this.buf = buf;
|
||||
this.pos = 0;
|
||||
this.count = buf.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates <code>ByteArrayInputStream</code>
|
||||
* that uses <code>buf</code> as its
|
||||
* buffer array. The initial value of <code>pos</code>
|
||||
* is <code>offset</code> and the initial value
|
||||
* of <code>count</code> is <code>offset+length</code>.
|
||||
* The buffer array is not copied.
|
||||
* <p>
|
||||
* Note that if bytes are simply read from
|
||||
* the resulting input stream, elements <code>buf[pos]</code>
|
||||
* through <code>buf[pos+len-1]</code> will
|
||||
* be read; however, if a <code>reset</code>
|
||||
* operation is performed, then bytes <code>buf[0]</code>
|
||||
* through b<code>uf[pos-1]</code> will then
|
||||
* become available for input.
|
||||
*
|
||||
* @param buf the input buffer.
|
||||
* @param offset the offset in the buffer of the first byte to read.
|
||||
* @param length the maximum number of bytes to read from the buffer.
|
||||
*/
|
||||
public ByteArrayInputStream(byte buf[], int offset, int length) {
|
||||
this.buf = buf;
|
||||
this.pos = offset;
|
||||
this.count = Math.min(offset + length, buf.length);
|
||||
this.mark = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next byte of data from this input stream. The value
|
||||
* byte is returned as an <code>int</code> in the range
|
||||
* <code>0</code> to <code>255</code>. If no byte is available
|
||||
* because the end of the stream has been reached, the value
|
||||
* <code>-1</code> is returned.
|
||||
* <p>
|
||||
* This <code>read</code> method
|
||||
* cannot block.
|
||||
*
|
||||
* @return the next byte of data, or <code>-1</code> if the end of the
|
||||
* stream has been reached.
|
||||
*/
|
||||
public int read() {
|
||||
return (pos < count) ? (buf[pos++] & 0xff) : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to <code>len</code> bytes of data into an array of bytes
|
||||
* from this input stream.
|
||||
* If <code>pos</code> equals <code>count</code>,
|
||||
* then <code>-1</code> is returned to indicate
|
||||
* end of file. Otherwise, the number <code>k</code>
|
||||
* of bytes read is equal to the smaller of
|
||||
* <code>len</code> and <code>count-pos</code>.
|
||||
* If <code>k</code> is positive, then bytes
|
||||
* <code>buf[pos]</code> through <code>buf[pos+k-1]</code>
|
||||
* are copied into <code>b[off]</code> through
|
||||
* <code>b[off+k-1]</code> in the manner performed
|
||||
* by <code>System.arraycopy</code>. The
|
||||
* value <code>k</code> is added into <code>pos</code>
|
||||
* and <code>k</code> is returned.
|
||||
* <p>
|
||||
* This <code>read</code> method cannot block.
|
||||
*
|
||||
* @param b the buffer into which the data is read.
|
||||
* @param off the start offset of the data.
|
||||
* @param len the maximum number of bytes read.
|
||||
* @return the total number of bytes read into the buffer, or
|
||||
* <code>-1</code> if there is no more data because the end of
|
||||
* the stream has been reached.
|
||||
*/
|
||||
public int read(byte b[], int off, int len) {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if ((off < 0) || (off > b.length) || (len < 0) ||
|
||||
((off + len) > b.length) || ((off + len) < 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
if (pos >= count) {
|
||||
return -1;
|
||||
}
|
||||
if (pos + len > count) {
|
||||
len = count - pos;
|
||||
}
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
Sys.copyArray(buf, pos, b, off, len);
|
||||
pos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips <code>n</code> bytes of input from this input stream. Fewer
|
||||
* bytes might be skipped if the end of the input stream is reached.
|
||||
* The actual number <code>k</code>
|
||||
* of bytes to be skipped is equal to the smaller
|
||||
* of <code>n</code> and <code>count-pos</code>.
|
||||
* The value <code>k</code> is added into <code>pos</code>
|
||||
* and <code>k</code> is returned.
|
||||
*
|
||||
* @param n the number of bytes to be skipped.
|
||||
* @return the actual number of bytes skipped.
|
||||
*/
|
||||
public long skip(long n) {
|
||||
if (pos + n > count) {
|
||||
n = count - pos;
|
||||
}
|
||||
if (n < 0) {
|
||||
return 0;
|
||||
}
|
||||
pos += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that can be read from this input
|
||||
* stream without blocking.
|
||||
* The value returned is
|
||||
* <code>count - pos</code>,
|
||||
* which is the number of bytes remaining to be read from the input buffer.
|
||||
*
|
||||
* @return the number of bytes that can be read from the input stream
|
||||
* without blocking.
|
||||
*/
|
||||
public int available() {
|
||||
return count - pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if ByteArrayInputStream supports mark/reset.
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
public boolean markSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current marked position in the stream.
|
||||
* ByteArrayInputStream objects are marked at position zero by
|
||||
* default when constructed. They may be marked at another
|
||||
* position within the buffer by this method.
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
public void mark(int readAheadLimit) {
|
||||
mark = pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the buffer to the marked position. The marked position
|
||||
* is the beginning unless another position was marked.
|
||||
* The value of <code>pos</code> is set to 0.
|
||||
*/
|
||||
public void reset() {
|
||||
pos = mark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this input stream and releases any system resources
|
||||
* associated with the stream.
|
||||
* <p>
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License version 2 for more details (a copy is
|
||||
* included at /legal/license.txt).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this work; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*/
|
||||
|
||||
package java.io;
|
||||
|
||||
import com.sun.cldchi.jvm.JVM;
|
||||
import org.mozilla.internal.Sys;
|
||||
|
||||
/**
|
||||
* This class implements an output stream in which the data is
|
||||
* written into a byte array. The buffer automatically grows as data
|
||||
* is written to it.
|
||||
* The data can be retrieved using <code>toByteArray()</code> and
|
||||
* <code>toString()</code>.
|
||||
* @version 12/17/01 (CLDC 1.1)
|
||||
* @since JDK1.0, CLDC 1.0
|
||||
*/
|
||||
|
||||
public class ByteArrayOutputStream extends OutputStream {
|
||||
|
||||
/**
|
||||
* The buffer where data is stored.
|
||||
*/
|
||||
protected byte buf[];
|
||||
|
||||
/**
|
||||
* The number of valid bytes in the buffer.
|
||||
*/
|
||||
protected int count;
|
||||
|
||||
/**
|
||||
* Flag indicating whether the stream has been closed.
|
||||
*/
|
||||
private boolean isClosed = false;
|
||||
|
||||
/**
|
||||
* Creates a new byte array output stream. The buffer capacity is
|
||||
* initially 32 bytes, though its size increases if necessary.
|
||||
*/
|
||||
public ByteArrayOutputStream() {
|
||||
this(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new byte array output stream, with a buffer capacity of
|
||||
* the specified size, in bytes.
|
||||
*
|
||||
* @param size the initial size.
|
||||
* @exception IllegalArgumentException if size is negative.
|
||||
*/
|
||||
public ByteArrayOutputStream(int size) {
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
/* #ifdef VERBOSE_EXCEPTIONS */
|
||||
/// skipped "Negative initial size: " + size
|
||||
/* #endif */
|
||||
);
|
||||
}
|
||||
buf = new byte[size];
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the specified byte to this byte array output stream.
|
||||
*
|
||||
* @param b the byte to be written.
|
||||
*/
|
||||
public void write(int b) {
|
||||
int newcount = count + 1;
|
||||
if (newcount > buf.length) {
|
||||
byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];
|
||||
Sys.copyArray(buf, 0, newbuf, 0, count);
|
||||
buf = newbuf;
|
||||
}
|
||||
buf[count] = (byte)b;
|
||||
count = newcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes <code>len</code> bytes from the specified byte array
|
||||
* starting at offset <code>off</code> to this byte array output stream.
|
||||
*
|
||||
* @param b the data.
|
||||
* @param off the start offset in the data.
|
||||
* @param len the number of bytes to write.
|
||||
*/
|
||||
public void write(byte b[], int off, int len) {
|
||||
if ((off < 0) || (off > b.length) || (len < 0) ||
|
||||
((off + len) > b.length) || ((off + len) < 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0) {
|
||||
return;
|
||||
}
|
||||
int newcount = count + len;
|
||||
if (newcount > buf.length) {
|
||||
byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];
|
||||
Sys.copyArray(buf, 0, newbuf, 0, count);
|
||||
buf = newbuf;
|
||||
}
|
||||
Sys.copyArray(b, off, buf, count, len);
|
||||
count = newcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the <code>count</code> field of this byte array output
|
||||
* stream to zero, so that all currently accumulated output in the
|
||||
* output stream is discarded. The output stream can be used again,
|
||||
* reusing the already allocated buffer space.
|
||||
*
|
||||
* @see ByteArrayInputStream#count
|
||||
*/
|
||||
public void reset() {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a newly allocated byte array. Its size is the current
|
||||
* size of this output stream and the valid contents of the buffer
|
||||
* have been copied into it.
|
||||
*
|
||||
* @return the current contents of this output stream, as a byte array.
|
||||
* @see java.io.ByteArrayOutputStream#size()
|
||||
*/
|
||||
public byte toByteArray()[] {
|
||||
if (isClosed && buf.length == count) {
|
||||
return buf;
|
||||
} else {
|
||||
byte newbuf[] = new byte[count];
|
||||
Sys.copyArray(buf, 0, newbuf, 0, count);
|
||||
return newbuf;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current size of the buffer.
|
||||
*
|
||||
* @return the value of the <code>count</code> field, which is the number
|
||||
* of valid bytes in this output stream.
|
||||
* @see java.io.ByteArrayOutputStream#count
|
||||
*/
|
||||
public int size() {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the buffer's contents into a string, translating bytes into
|
||||
* characters according to the platform's default character encoding.
|
||||
*
|
||||
* @return String translated from the buffer's contents.
|
||||
* @since JDK1.1
|
||||
*/
|
||||
public String toString() {
|
||||
return new String(buf, 0, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this output stream and releases any system resources
|
||||
* associated with this stream. A closed stream cannot perform
|
||||
* output operations and cannot be reopened.
|
||||
* <p>
|
||||
*
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
isClosed = true;
|
||||
}
|
||||
|
||||
}
|
|
@ -29,6 +29,7 @@ package java.lang;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import com.sun.cldc.i18n.*;
|
||||
import com.sun.cldchi.jvm.JVM;
|
||||
import org.mozilla.internal.Sys;
|
||||
|
||||
/**
|
||||
* The <code>String</code> class represents character strings. All
|
||||
|
@ -97,6 +98,9 @@ class String {
|
|||
/** The count is the number of characters in the String. */
|
||||
private int count;
|
||||
|
||||
/** Immutable, so we can cache the hash code. */
|
||||
private int cachedHashCode;
|
||||
|
||||
/**
|
||||
* Initializes a newly created <code>String</code> object so that it
|
||||
* represents an empty character sequence.
|
||||
|
@ -260,10 +264,12 @@ class String {
|
|||
* <code>null</code>.
|
||||
*/
|
||||
public String (StringBuffer buffer) {
|
||||
buffer.setShared();
|
||||
this.value = buffer.getValue();
|
||||
this.offset = 0;
|
||||
this.count = buffer.length();
|
||||
synchronized(buffer) {
|
||||
buffer.setShared();
|
||||
this.value = buffer.getValue();
|
||||
this.offset = 0;
|
||||
this.count = buffer.length();
|
||||
}
|
||||
}
|
||||
|
||||
// Package private constructor which shares value array for speed.
|
||||
|
@ -363,8 +369,8 @@ class String {
|
|||
);
|
||||
}
|
||||
// NOTE: dst not checked, cannot use unchecked arraycopy
|
||||
System.arraycopy(value, offset + srcBegin, dst, dstBegin,
|
||||
srcEnd - srcBegin);
|
||||
Sys.copyArray(value, offset + srcBegin, dst, dstBegin,
|
||||
srcEnd - srcBegin);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -711,6 +717,9 @@ class String {
|
|||
* @return a hash code value for this object.
|
||||
*/
|
||||
public int hashCode() {
|
||||
if (cachedHashCode > 0) {
|
||||
return cachedHashCode;
|
||||
}
|
||||
int h = 0;
|
||||
int off = offset;
|
||||
char val[] = value;
|
||||
|
@ -719,6 +728,7 @@ class String {
|
|||
for (int i = 0; i < len; i++) {
|
||||
h = 31*h + val[off++];
|
||||
}
|
||||
cachedHashCode = h;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License version 2 for more details (a copy is
|
||||
* included at /legal/license.txt).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this work; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*/
|
||||
|
||||
package org.mozilla.internal;
|
||||
|
||||
import java.io.*;
|
||||
import com.sun.cldchi.io.*;
|
||||
import java.security.*;
|
||||
import java.util.PropertyPermission;
|
||||
|
||||
/**
|
||||
* The <code>Sys</code> class contains several useful privileged functions.
|
||||
*/
|
||||
public final class Sys {
|
||||
private Sys() { }
|
||||
|
||||
public static void copyArray(byte [] src, int srcOffset,
|
||||
byte [] dst, int dstOffset,
|
||||
int length) {
|
||||
if (src == dst) {
|
||||
System.arraycopy(src, srcOffset, dst, dstOffset, length);
|
||||
return;
|
||||
}
|
||||
|
||||
if (srcOffset < 0 || (srcOffset + length) > src.length || dstOffset < 0 || (dstOffset + length) > dst.length || length < 0) {
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid index.");
|
||||
}
|
||||
|
||||
for (int n = 0; n < length; ++n) {
|
||||
dst[dstOffset++] = src[srcOffset++];
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyArray(char [] src, int srcOffset,
|
||||
char [] dst, int dstOffset,
|
||||
int length) {
|
||||
if (src == dst) {
|
||||
System.arraycopy(src, srcOffset, dst, dstOffset, length);
|
||||
return;
|
||||
}
|
||||
|
||||
if (srcOffset < 0 || (srcOffset + length) > src.length || dstOffset < 0 || (dstOffset + length) > dst.length || length < 0) {
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid index.");
|
||||
}
|
||||
|
||||
for (int n = 0; n < length; ++n) {
|
||||
dst[dstOffset++] = src[srcOffset++];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evals code in the JS shell, only available in non-release builds as an
|
||||
* escape hatch for the purpose of testing and profiling.
|
||||
*/
|
||||
public native static void eval(String src);
|
||||
}
|
|
@ -86,6 +86,9 @@ module J2ME {
|
|||
}
|
||||
|
||||
export function isFinalMethod(methodInfo: MethodInfo): boolean {
|
||||
if (isFinalClass(methodInfo.classInfo)) {
|
||||
return true;
|
||||
}
|
||||
// XXX Determine whether we can start using the code in this function.
|
||||
return false;
|
||||
var result = methodInfo.isFinal;
|
||||
|
|
116
jit/baseline.ts
116
jit/baseline.ts
|
@ -35,6 +35,17 @@ module J2ME {
|
|||
"java/lang/Object.<init>.()V": "undefined"
|
||||
};
|
||||
|
||||
/**
|
||||
* These methods have special powers. Methods are added to this set based on the regexp patterns in |privilegedPatterns|.
|
||||
*/
|
||||
var privilegedMethods = {};
|
||||
|
||||
var privilegedPatterns = [
|
||||
"org/mozilla/internal/Sys*"
|
||||
// "com/sun/*",
|
||||
// "java/*"
|
||||
];
|
||||
|
||||
/**
|
||||
* Emits optimization results inline as comments in the generated source.
|
||||
*/
|
||||
|
@ -60,18 +71,42 @@ module J2ME {
|
|||
* Emits array bounds checks. Although this is necessary for correctness, most
|
||||
* applications work without them.
|
||||
*/
|
||||
var emitCheckArrayBounds = true;
|
||||
export var emitCheckArrayBounds = true;
|
||||
|
||||
/**
|
||||
* Inline calls to runtime methods whenever possible.
|
||||
*/
|
||||
export var inlineRuntimeCalls = true;
|
||||
|
||||
/**
|
||||
* Emits array store type checks. Although this is necessary for correctness,
|
||||
* most applications work without them.
|
||||
*/
|
||||
var emitCheckArrayStore = true;
|
||||
export var emitCheckArrayStore = true;
|
||||
|
||||
/**
|
||||
* Unsafe methods.
|
||||
*/
|
||||
function isPrivileged(methodInfo: MethodInfo) {
|
||||
var privileged = privilegedMethods[methodInfo.implKey];
|
||||
if (privileged) {
|
||||
return true;
|
||||
} else if (privileged === false) {
|
||||
return false;
|
||||
}
|
||||
// Check patterns.
|
||||
for (var i = 0; i < privilegedPatterns.length; i++) {
|
||||
if (methodInfo.implKey.match(privilegedPatterns[i])) {
|
||||
return privilegedMethods[methodInfo.implKey] = true;
|
||||
}
|
||||
}
|
||||
return privilegedMethods[methodInfo.implKey] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits preemption checks for methods that already yield.
|
||||
*/
|
||||
var emitCheckPreemption = false;
|
||||
export var emitCheckPreemption = false;
|
||||
|
||||
export function baselineCompileMethod(methodInfo: MethodInfo, target: CompilationTarget): CompiledMethodInfo {
|
||||
var compileExceptions = true;
|
||||
|
@ -237,6 +272,8 @@ module J2ME {
|
|||
private lockObject: string;
|
||||
private hasOSREntryPoint = false;
|
||||
private entryBlock: number;
|
||||
private isPrivileged: boolean;
|
||||
|
||||
static localNames = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
|
||||
|
||||
/**
|
||||
|
@ -260,6 +297,7 @@ module J2ME {
|
|||
this.bodyEmitter = new Emitter(target !== CompilationTarget.Runtime);
|
||||
this.blockEmitter = new Emitter(target !== CompilationTarget.Runtime);
|
||||
this.target = target;
|
||||
this.isPrivileged = isPrivileged(this.methodInfo);
|
||||
}
|
||||
|
||||
compile(): CompiledMethodInfo {
|
||||
|
@ -283,7 +321,7 @@ module J2ME {
|
|||
if (this.hasMonitorEnter) {
|
||||
this.bodyEmitter.prependLn("var th = $.ctx.thread;");
|
||||
}
|
||||
return new CompiledMethodInfo(this.parameters, this.bodyEmitter.toString(), this.referencedClasses, this.blockMap.getOSREntryPoints());
|
||||
return new CompiledMethodInfo(this.parameters, this.bodyEmitter.toString(), this.referencedClasses, this.hasOSREntryPoint ? this.blockMap.getOSREntryPoints() : []);
|
||||
}
|
||||
|
||||
needsVariable(name: string) {
|
||||
|
@ -373,9 +411,7 @@ module J2ME {
|
|||
check += "(" + this.peek(Kind.Reference) + ", " + classConstant(classInfo) + ")";
|
||||
check = " && " + check;
|
||||
}
|
||||
this.bodyEmitter.enter("if (pc >= " + handler.start_pc + " && pc < " + handler.end_pc + check + ") {");
|
||||
this.bodyEmitter.writeLn("pc = " + this.getBlockIndex(handler.handler_pc) + "; continue;");
|
||||
this.bodyEmitter.leave("}");
|
||||
this.bodyEmitter.writeLn("if (pc >= " + handler.start_pc + " && pc < " + handler.end_pc + check + ") { pc = " + this.getBlockIndex(handler.handler_pc) + "; continue; }");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -465,10 +501,11 @@ module J2ME {
|
|||
var needsOSREntryPoint = false;
|
||||
var needsEntryDispatch = false;
|
||||
|
||||
var blocks = this.blockMap.blocks;
|
||||
var blockMap = this.blockMap;
|
||||
var blocks = blockMap.blocks;
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
var block = blocks[i];
|
||||
if (block.isLoopHeader && !block.isInnerLoopHeader()) {
|
||||
if (blockMap.invokeCount > 0 && block.isLoopHeader && !block.isInnerLoopHeader()) {
|
||||
needsOSREntryPoint = true;
|
||||
needsEntryDispatch = true;
|
||||
}
|
||||
|
@ -748,6 +785,14 @@ module J2ME {
|
|||
emitDebugInfoComments && this.blockEmitter.writeLn("// Inlining: " + methodInfo.implKey);
|
||||
call = inlineMethods[methodInfo.implKey];
|
||||
}
|
||||
if (!(calleeCanYield || emitCompilerAssertions)) {
|
||||
if (types[0].kind !== Kind.Void) {
|
||||
this.emitPush(types[0].kind, call);
|
||||
} else {
|
||||
this.blockEmitter.writeLn(call + ";");
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.needsVariable("re");
|
||||
this.blockEmitter.writeLn("re = " + call + ";");
|
||||
if (calleeCanYield) {
|
||||
|
@ -760,13 +805,38 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
|
||||
emitNegativeArraySizeCheck(length: string) {
|
||||
if (this.isPrivileged) {
|
||||
return;
|
||||
}
|
||||
this.blockEmitter.writeLn(length + " < 0 && TN();");
|
||||
}
|
||||
|
||||
emitBoundsCheck(array: string, index: string) {
|
||||
if (this.isPrivileged || !emitCheckArrayBounds) {
|
||||
return;
|
||||
}
|
||||
if (inlineRuntimeCalls) {
|
||||
this.blockEmitter.writeLn("if ((" + index + " >>> 0) >= (" + array + ".length >>> 0)) TI(" + index + ");");
|
||||
} else {
|
||||
this.blockEmitter.writeLn("CAB(" + array + ", " + index + ");");
|
||||
}
|
||||
}
|
||||
|
||||
emitArrayStoreCheck(array: string, value: string) {
|
||||
if (this.isPrivileged || !emitCheckArrayStore) {
|
||||
return;
|
||||
}
|
||||
this.blockEmitter.writeLn("CAS(" + array + ", " + value + ");");
|
||||
}
|
||||
|
||||
emitStoreIndexed(kind: Kind) {
|
||||
var value = this.pop(stackKind(kind));
|
||||
var index = this.pop(Kind.Int);
|
||||
var array = this.pop(Kind.Reference);
|
||||
emitCheckArrayBounds && this.blockEmitter.writeLn("CAB(" + array + ", " + index + ");");
|
||||
this.emitBoundsCheck(array, index);
|
||||
if (kind === Kind.Reference) {
|
||||
emitCheckArrayStore && this.blockEmitter.writeLn("CAS(" + array + ", " + value + ");");
|
||||
this.emitArrayStoreCheck(array, value);
|
||||
}
|
||||
this.blockEmitter.writeLn(array + "[" + index + "] = " + value + ";");
|
||||
}
|
||||
|
@ -774,12 +844,13 @@ module J2ME {
|
|||
emitLoadIndexed(kind: Kind) {
|
||||
var index = this.pop(Kind.Int);
|
||||
var array = this.pop(Kind.Reference);
|
||||
emitCheckArrayBounds && this.blockEmitter.writeLn("CAB(" + array + ", " + index + ");");
|
||||
this.emitBoundsCheck(array, index);
|
||||
this.emitPush(kind, array + "[" + index + "]");
|
||||
}
|
||||
|
||||
emitIncrement(stream: BytecodeStream) {
|
||||
this.blockEmitter.writeLn(this.getLocal(stream.readLocalIndex()) + " += " + stream.readIncrement() + ";");
|
||||
var local = this.getLocal(stream.readLocalIndex());
|
||||
this.blockEmitter.writeLn(local + " = " + local + " + " + stream.readIncrement() + " | 0;");
|
||||
}
|
||||
|
||||
emitGoto(block: Block, stream: BytecodeStream) {
|
||||
|
@ -827,6 +898,7 @@ module J2ME {
|
|||
emitNewTypeArray(typeCode: number) {
|
||||
var kind = arrayTypeCodeToKind(typeCode);
|
||||
var length = this.pop(Kind.Int);
|
||||
this.emitNegativeArraySizeCheck(length);
|
||||
this.emitPush(Kind.Reference, "new " + kindToTypedArrayName(kind) + "(" + length + ")");
|
||||
}
|
||||
|
||||
|
@ -858,6 +930,7 @@ module J2ME {
|
|||
var classInfo = this.lookupClass(cpi);
|
||||
this.emitClassInitializationCheck(classInfo);
|
||||
var length = this.pop(Kind.Int);
|
||||
this.emitNegativeArraySizeCheck(length);
|
||||
this.emitPush(Kind.Reference, "NA(" + classConstant(classInfo) + ", " + length + ")");
|
||||
}
|
||||
|
||||
|
@ -944,13 +1017,24 @@ module J2ME {
|
|||
Debug.unexpected(Bytecodes[opcode]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
emitDivideByZeroCheck(kind: Kind, value: string) {
|
||||
if (this.isPrivileged) {
|
||||
return;
|
||||
}
|
||||
if (inlineRuntimeCalls && kind !== Kind.Long) {
|
||||
this.blockEmitter.writeLn(value + " === 0 && TA();");
|
||||
} else {
|
||||
var checkName = kind === Kind.Long ? "CDZL" : "CDZ";
|
||||
this.blockEmitter.writeLn(checkName + "(" + value + ");");
|
||||
}
|
||||
}
|
||||
|
||||
emitArithmeticOp(result: Kind, opcode: Bytecodes, canTrap: boolean) {
|
||||
var y = this.pop(result);
|
||||
var x = this.pop(result);
|
||||
if (canTrap) {
|
||||
var checkName = result === Kind.Long ? "CDZL" : "CDZ";
|
||||
this.blockEmitter.writeLn(checkName + "(" + y + ");");
|
||||
this.emitDivideByZeroCheck(result, y);
|
||||
}
|
||||
var v;
|
||||
switch(opcode) {
|
||||
|
|
|
@ -87,6 +87,7 @@ module J2ME.Bytecode {
|
|||
method: MethodInfo;
|
||||
blocks: Block [];
|
||||
hasBackwardBranches: boolean;
|
||||
invokeCount: number;
|
||||
private blockMap: Block [];
|
||||
private startBlock: Block;
|
||||
private canTrap: Uint32ArrayBitSet;
|
||||
|
@ -96,6 +97,7 @@ module J2ME.Bytecode {
|
|||
this.blocks = [];
|
||||
this.method = method;
|
||||
this.hasBackwardBranches = false;
|
||||
this.invokeCount = 0;
|
||||
this.blockMap = new Array<Block>(method.code.length);
|
||||
this.canTrap = new Uint32ArrayBitSet(this.blockMap.length);
|
||||
this.exceptionHandlers = this.method.exception_table;
|
||||
|
@ -289,6 +291,15 @@ module J2ME.Bytecode {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case Bytecodes.INVOKEVIRTUAL:
|
||||
case Bytecodes.INVOKESPECIAL:
|
||||
case Bytecodes.INVOKESTATIC:
|
||||
case Bytecodes.INVOKEINTERFACE:
|
||||
this.invokeCount ++;
|
||||
if (this.canTrapAt(opcode, bci)) {
|
||||
this.canTrap.set(bci);
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
if (this.canTrapAt(opcode, bci)) {
|
||||
this.canTrap.set(bci);
|
||||
|
|
23
jsshell.js
23
jsshell.js
|
@ -65,13 +65,22 @@ var document = {
|
|||
},
|
||||
getBoundingClientRect: function() {
|
||||
return { top: 0, left: 0, width: 0, height: 0 };
|
||||
}
|
||||
},
|
||||
querySelector: function() {
|
||||
return { style: "" };
|
||||
},
|
||||
dispatchEvent: function(event) {
|
||||
},
|
||||
style: "",
|
||||
};
|
||||
},
|
||||
addEventListener: function() {
|
||||
},
|
||||
};
|
||||
|
||||
var Event = function() {
|
||||
}
|
||||
|
||||
var config = {
|
||||
logConsole: "native",
|
||||
args: "",
|
||||
|
@ -81,8 +90,9 @@ try {
|
|||
load("libs/relooper.js", "build/j2me.js","libs/zipfile.js", "blackBox.js",
|
||||
"libs/encoding.js", "util.js",
|
||||
"override.js", "vm/tags.js", "native.js", "tests/override.js",
|
||||
"string.js", "midp/midp.js",
|
||||
"libs/long.js", "midp/crypto.js", "libs/forge/md5.js", "libs/forge/util.js");
|
||||
"midp/midp.js", "midp/gestures.js",
|
||||
"libs/long.js", "midp/crypto.js", "libs/forge/md5.js", "libs/forge/util.js",
|
||||
"build/classes.jar.js");
|
||||
|
||||
// load("build/classes.jar.js");
|
||||
// load("build/program.jar.js");
|
||||
|
@ -96,6 +106,7 @@ try {
|
|||
|
||||
CLASSES.addPath("java/classes.jar", snarf("java/classes.jar", "binary").buffer);
|
||||
CLASSES.addPath("tests/tests.jar", snarf("tests/tests.jar", "binary").buffer);
|
||||
CLASSES.addPath("bench/benchmark.jar", snarf("bench/benchmark.jar", "binary").buffer);
|
||||
//CLASSES.addPath("program.jar", snarf("program.jar", "binary").buffer);
|
||||
|
||||
CLASSES.initializeBuiltinClasses();
|
||||
|
@ -103,9 +114,7 @@ try {
|
|||
var start = dateNow();
|
||||
var jvm = new JVM();
|
||||
|
||||
J2ME.writers = J2ME.WriterFlags.JIT;
|
||||
|
||||
print("INITIALIZATION TIME: " + (dateNow() - start));
|
||||
J2ME.writers = J2ME.WriterFlags.None;
|
||||
|
||||
start = dateNow();
|
||||
var runtime = jvm.startIsolate0(scriptArgs[0], config.args);
|
||||
|
@ -114,8 +123,6 @@ try {
|
|||
(callbacks.shift())();
|
||||
}
|
||||
|
||||
print("RUNNING TIME: " + (dateNow() - start));
|
||||
|
||||
// J2ME.interpreterCounter.traceSorted(new J2ME.IndentingWriter());
|
||||
|
||||
} catch (x) {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
16
main.html.in
16
main.html.in
|
@ -14,6 +14,10 @@
|
|||
<script type="text/javascript" src="config/midlet.js" defer></script>
|
||||
<script type="text/javascript" src="config/build.js" defer></script>
|
||||
<script type="text/javascript" src="config/urlparams.js" defer></script>
|
||||
<!-- #if BENCHMARK == "true" -->
|
||||
<script type="text/javascript" src="benchmark.js" defer></script>
|
||||
<script type="text/javascript" src="libs/ttest.js" defer></script>
|
||||
<!-- #endif -->
|
||||
<!-- #if PROFILE == "true" -->
|
||||
<script type="text/javascript" src="build/shumway.js" defer></script>
|
||||
<!-- #endif -->
|
||||
|
@ -34,7 +38,6 @@
|
|||
<script type="text/javascript" src="override.js" defer></script>
|
||||
<script type="text/javascript" src="vm/tags.js" defer></script>
|
||||
<script type="text/javascript" src="native.js" defer></script>
|
||||
<script type="text/javascript" src="string.js" defer></script>
|
||||
<script type="text/javascript" src="libs/load.js" defer></script>
|
||||
<script type="text/javascript" src="libs/zipfile.js" defer></script>
|
||||
<script type="text/javascript" src="libs/long.js" defer></script>
|
||||
|
@ -142,7 +145,18 @@
|
|||
<button id="sampleCounters2">One sample for 100ms (2s)</button>
|
||||
<button id="start">Start</button>
|
||||
<button id="loadAllClasses">Load All Classes</button>
|
||||
|
||||
</section>
|
||||
<!-- #if BENCHMARK == "true" -->
|
||||
<section id="benchmark">
|
||||
<button id="benchmark-startup-run">Run Startup Benchmark</button>
|
||||
<button id="benchmark-startup-baseline">Build Benchmark Baseline</button>
|
||||
<label><input type="number" min="1" max="100" id="benchmark-num-rounds"> Rounds</label>
|
||||
<label><input type="number" id="benchmark-round-delay" min="0" max="20000"> Round Delay(ms)</label>
|
||||
<label><input type="checkbox" id="benchmark-delete-fs">Delete FS before round</label>
|
||||
<label><input type="checkbox" id="benchmark-delete-jit-cache">Delete JIT cache before round</label>
|
||||
</section>
|
||||
<!-- #endif -->
|
||||
</div>
|
||||
<div id="display">
|
||||
<section id="sidebar" data-type="sidebar" style="display:none">
|
||||
|
|
8
main.js
8
main.js
|
@ -15,6 +15,10 @@ if (config.midletClassName == "RunTests") {
|
|||
jars.push("tests/tests.jar");
|
||||
}
|
||||
|
||||
if (typeof Benchmark !== "undefined") {
|
||||
Benchmark.startup.init();
|
||||
}
|
||||
|
||||
if (config.jars) {
|
||||
jars = jars.concat(config.jars.split(":"));
|
||||
}
|
||||
|
@ -196,6 +200,10 @@ document.getElementById("loadAllClasses").onclick = function() {
|
|||
loadAllClasses();
|
||||
};
|
||||
|
||||
if (typeof Benchmark !== "undefined") {
|
||||
Benchmark.initUI("benchmark");
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
document.getElementById("deleteDatabase").onclick = function() {
|
||||
indexedDB.deleteDatabase("asyncStorage");
|
||||
|
|
105
midp/fs.js
105
midp/fs.js
|
@ -65,43 +65,37 @@ Native["com/sun/midp/rms/RecordStoreFile.spaceAvailableRecordStore.(ILjava/lang/
|
|||
Native["com/sun/midp/rms/RecordStoreFile.openRecordStoreFile.(Ljava/lang/String;Ljava/lang/String;I)I"] =
|
||||
function(filenameBase, name, ext) {
|
||||
var ctx = $.ctx;
|
||||
asyncImpl("I", new Promise(function(resolve, reject) {
|
||||
var path = RECORD_STORE_BASE + "/" + util.fromJavaString(filenameBase) + "/" + util.fromJavaString(name) + "." + ext;
|
||||
|
||||
function openCallback(fd) {
|
||||
ctx.setAsCurrentContext();
|
||||
if (fd == -1) {
|
||||
reject($.newIOException("openRecordStoreFile: open failed"));
|
||||
} else {
|
||||
resolve(fd); // handle
|
||||
}
|
||||
}
|
||||
var path = RECORD_STORE_BASE + "/" + util.fromJavaString(filenameBase) + "/" + util.fromJavaString(name) + "." + ext;
|
||||
|
||||
|
||||
if (fs.exists(path)) {
|
||||
fs.open(path, openCallback);
|
||||
} else {
|
||||
// Per the reference impl, create the file if it doesn't exist.
|
||||
var dirname = fs.dirname(path);
|
||||
if (fs.mkdirp(dirname)) {
|
||||
if (fs.create(path, new Blob())) {
|
||||
fs.open(path, openCallback);
|
||||
} else {
|
||||
// TODO: determine if this is actually necessary, as I think
|
||||
// we're still in synchronous execution of the native here.
|
||||
function open() {
|
||||
asyncImpl("I", new Promise(function(resolve, reject) {
|
||||
fs.open(path, function(fd) {
|
||||
if (fd == -1) {
|
||||
ctx.setAsCurrentContext();
|
||||
|
||||
reject($.newIOException("openRecordStoreFile: create failed"));
|
||||
reject($.newIOException("openRecordStoreFile: open failed"));
|
||||
} else {
|
||||
resolve(fd); // handle
|
||||
}
|
||||
} else {
|
||||
// TODO: determine if this is actually necessary, as I think
|
||||
// we're still in synchronous execution of the native here.
|
||||
ctx.setAsCurrentContext();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
reject($.newIOException("openRecordStoreFile: mkdirp failed"));
|
||||
}
|
||||
if (fs.exists(path)) {
|
||||
open();
|
||||
} else {
|
||||
// Per the reference impl, create the file if it doesn't exist.
|
||||
var dirname = fs.dirname(path);
|
||||
if (!fs.mkdirp(dirname)) {
|
||||
throw $.newIOException("openRecordStoreFile: mkdirp failed");
|
||||
}
|
||||
}));
|
||||
|
||||
if (!fs.create(path, new Blob())) {
|
||||
throw $.newIOException("openRecordStoreFile: create failed");
|
||||
}
|
||||
|
||||
open();
|
||||
}
|
||||
};
|
||||
|
||||
Native["com/sun/midp/rms/RecordStoreFile.setPosition.(II)V"] = function(handle, pos) {
|
||||
|
@ -492,8 +486,7 @@ Native["com/sun/cdc/io/j2me/file/DefaultFileHandler.closeForReadWrite.()V"] = fu
|
|||
};
|
||||
|
||||
Native["com/sun/cdc/io/j2me/file/DefaultFileHandler.read.([BII)I"] = function(b, off, len) {
|
||||
var pathname = util.fromJavaString(this.$nativePath);
|
||||
DEBUG_FS && console.log("DefaultFileHandler.read: " + pathname);
|
||||
DEBUG_FS && console.log("DefaultFileHandler.read: " + util.fromJavaString(this.$nativePath));
|
||||
var fd = this.$nativeDescriptor;
|
||||
|
||||
if (off < 0 || len < 0 || off > b.byteLength || (b.byteLength - off) < len) {
|
||||
|
@ -512,8 +505,7 @@ Native["com/sun/cdc/io/j2me/file/DefaultFileHandler.read.([BII)I"] = function(b,
|
|||
};
|
||||
|
||||
Native["com/sun/cdc/io/j2me/file/DefaultFileHandler.write.([BII)I"] = function(b, off, len) {
|
||||
var pathname = util.fromJavaString(this.$nativePath);
|
||||
DEBUG_FS && console.log("DefaultFileHandler.write: " + pathname);
|
||||
DEBUG_FS && console.log("DefaultFileHandler.write: " + util.fromJavaString(this.$nativePath));
|
||||
var fd = this.$nativeDescriptor;
|
||||
fs.write(fd, b.subarray(off, off + len));
|
||||
// The "length of data really written," which is always the length requested
|
||||
|
@ -522,22 +514,19 @@ Native["com/sun/cdc/io/j2me/file/DefaultFileHandler.write.([BII)I"] = function(b
|
|||
};
|
||||
|
||||
Native["com/sun/cdc/io/j2me/file/DefaultFileHandler.positionForWrite.(J)V"] = function(offset) {
|
||||
var pathname = util.fromJavaString(this.$nativePath);
|
||||
DEBUG_FS && console.log("DefaultFileHandler.positionForWrite: " + pathname);
|
||||
DEBUG_FS && console.log("DefaultFileHandler.positionForWrite: " + util.fromJavaString(this.$nativePath));
|
||||
var fd = this.$nativeDescriptor;
|
||||
fs.setpos(fd, offset.toNumber());
|
||||
};
|
||||
|
||||
Native["com/sun/cdc/io/j2me/file/DefaultFileHandler.flush.()V"] = function() {
|
||||
var pathname = util.fromJavaString(this.$nativePath);
|
||||
DEBUG_FS && console.log("DefaultFileHandler.flush: " + pathname);
|
||||
DEBUG_FS && console.log("DefaultFileHandler.flush: " + util.fromJavaString(this.$nativePath));
|
||||
var fd = this.$nativeDescriptor;
|
||||
fs.flush(fd);
|
||||
};
|
||||
|
||||
Native["com/sun/cdc/io/j2me/file/DefaultFileHandler.close.()V"] = function() {
|
||||
var pathname = util.fromJavaString(this.$nativePath);
|
||||
DEBUG_FS && console.log("DefaultFileHandler.close: " + pathname);
|
||||
DEBUG_FS && console.log("DefaultFileHandler.close: " + util.fromJavaString(this.$nativePath));
|
||||
|
||||
MIDP.closeFileHandler(this, "read");
|
||||
MIDP.closeFileHandler(this, "write");
|
||||
|
@ -616,10 +605,9 @@ DEBUG_FS && console.log("getSuiteIdString: " + id);
|
|||
};
|
||||
|
||||
Native["com/sun/cdc/io/j2me/file/Protocol.available.()I"] = function() {
|
||||
var pathname = util.fromJavaString(this.$fileHandler.$nativePath);
|
||||
var fd = this.$fileHandler.$nativeDescriptor;
|
||||
var available = fs.getsize(fd) - fs.getpos(fd);
|
||||
DEBUG_FS && console.log("Protocol.available: " + pathname + ": " + available);
|
||||
DEBUG_FS && console.log("Protocol.available: " + util.fromJavaString(this.$fileHandler.$nativePath) + ": " + available);
|
||||
return available;
|
||||
};
|
||||
|
||||
|
@ -627,30 +615,29 @@ Native["com/sun/midp/io/j2me/storage/RandomAccessStream.open.(Ljava/lang/String;
|
|||
var path = "/" + util.fromJavaString(fileName);
|
||||
|
||||
var ctx = $.ctx;
|
||||
asyncImpl("I", new Promise(function(resolve, reject) {
|
||||
function open() {
|
||||
|
||||
function open() {
|
||||
asyncImpl("I", new Promise(function(resolve, reject) {
|
||||
fs.open(path, function(fd) {
|
||||
ctx.setAsCurrentContext();
|
||||
if (fd == -1) {
|
||||
ctx.setAsCurrentContext();
|
||||
reject($.newIOException("RandomAccessStream::open(" + path + ") failed opening the file"));
|
||||
} else {
|
||||
resolve(fd);
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if (fs.exists(path)) {
|
||||
open();
|
||||
} else if (mode == 1) {
|
||||
ctx.setAsCurrentContext();
|
||||
reject($.newIOException("RandomAccessStream::open(" + path + ") file doesn't exist"));
|
||||
} else if (fs.create(path, new Blob())) {
|
||||
open();
|
||||
} else {
|
||||
ctx.setAsCurrentContext();
|
||||
reject($.newIOException("RandomAccessStream::open(" + path + ") failed creating the file"));
|
||||
}
|
||||
}));
|
||||
if (fs.exists(path)) {
|
||||
open();
|
||||
} else if (mode == 1) {
|
||||
throw $.newIOException("RandomAccessStream::open(" + path + ") file doesn't exist");
|
||||
} else if (fs.create(path, new Blob())) {
|
||||
open();
|
||||
} else {
|
||||
throw $.newIOException("RandomAccessStream::open(" + path + ") failed creating the file");
|
||||
}
|
||||
};
|
||||
|
||||
Native["com/sun/midp/io/j2me/storage/RandomAccessStream.read.(I[BII)I"] =
|
||||
|
|
|
@ -29,89 +29,3 @@ Native["com/nokia/mid/ui/gestures/GestureInteractiveZone.contains.(II)Z"] = func
|
|||
Native["com/nokia/mid/ui/gestures/GestureInteractiveZone.supports.(I)Z"] = function(type) {
|
||||
return ((type & this.gestures) == type) ? 1 : 0;
|
||||
};
|
||||
|
||||
Override["com/nokia/mid/ui/gestures/GestureEventImpl.<init>.(IIIIIFIIIIIIIIII)V"] =
|
||||
function(type, dragDistanceX, dragDistanceY, startX, startY, flickDirection, flickSpeed, flickSpeedX, flickSpeedY,
|
||||
pinchDistanceStarting, pinchDistanceCurrent, pinchDistanceChange, pinchCenterX, pinchCenterY,
|
||||
pinchCenterChangeX, pinchCenterChangeY) {
|
||||
this.type = type;
|
||||
this.dragDistanceX = dragDistanceX;
|
||||
this.dragDistanceY = dragDistanceY;
|
||||
this.startX = startX;
|
||||
this.startY = startY;
|
||||
this.flickDirection = flickDirection;
|
||||
this.flickSpeed = flickSpeed;
|
||||
this.flickSpeedX = flickSpeedX;
|
||||
this.flickSpeedY = flickSpeedY;
|
||||
this.pinchDistanceStarting = pinchDistanceStarting;
|
||||
this.pinchDistanceCurrent = pinchDistanceCurrent;
|
||||
this.pinchDistanceChange = pinchDistanceChange;
|
||||
this.pinchCenterX = pinchCenterX;
|
||||
this.pinchCenterY = pinchCenterY;
|
||||
this.pinchCenterChangeX = pinchCenterChangeX;
|
||||
this.pinchCenterChangeY = pinchCenterChangeY;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getType.()I"] = function() {
|
||||
return this.type;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getDragDistanceX.()I"] = function() {
|
||||
return this.dragDistanceX;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getDragDistanceY.()I"] = function() {
|
||||
return this.dragDistanceY;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getStartX.()I"] = function() {
|
||||
return this.startX;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getStartY.()I"] = function() {
|
||||
return this.startY;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getFlickDirection.()F"] = function() {
|
||||
return this.flickDirection;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getFlickSpeed.()I"] = function() {
|
||||
return this.flickSpeed;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getFlickSpeedX.()I"] = function() {
|
||||
return this.flickSpeedX;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getFlickSpeedY.()I"] = function() {
|
||||
return this.flickSpeedY;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getPinchDistanceStarting.()I"] = function() {
|
||||
return this.pinchDistanceStarting;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getPinchDistanceCurrent.()I"] = function() {
|
||||
return this.pinchDistanceCurrent;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getPinchDistanceChange.()I"] = function() {
|
||||
return this.pinchDistanceChange;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getPinchCenterX.()I"] = function() {
|
||||
return this.pinchCenterX;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getPinchCenterY.()I"] = function() {
|
||||
return this.pinchCenterY;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getPinchCenterChangeX.()I"] = function() {
|
||||
return this.pinchCenterChangeX;
|
||||
};
|
||||
|
||||
Native["com/nokia/mid/ui/gestures/GestureEventImpl.getPinchCenterChangeY.()I"] = function() {
|
||||
return this.pinchCenterChangeY;
|
||||
};
|
||||
|
|
394
midp/gfx.js
394
midp/gfx.js
|
@ -413,38 +413,7 @@ var currentlyFocusedTextEditor;
|
|||
var BOTTOM = 32;
|
||||
var BASELINE = 64;
|
||||
|
||||
function withGraphics(g) {
|
||||
var img = g.img,
|
||||
c = null;
|
||||
|
||||
if (img === null) {
|
||||
c = MIDP.Context2D;
|
||||
} else {
|
||||
var imgData = img.imageData,
|
||||
c = imgData.context;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
function withClip(g, c, x, y) {
|
||||
if (g.clipped) {
|
||||
c.beginPath();
|
||||
c.rect(g.clipX1, g.clipY1, g.clipX2 - g.clipX1, g.clipY2 - g.clipY1);
|
||||
c.clip();
|
||||
}
|
||||
|
||||
x += g.transX;
|
||||
y += g.transY;
|
||||
|
||||
return [x, y];
|
||||
}
|
||||
|
||||
function withAnchor(g, c, anchor, x, y, w, h) {
|
||||
var pair = withClip(g, c, x, y);
|
||||
x = pair[0];
|
||||
y = pair[1];
|
||||
|
||||
if (anchor & RIGHT) {
|
||||
x -= w;
|
||||
} else if (anchor & HCENTER) {
|
||||
|
@ -714,11 +683,11 @@ var currentlyFocusedTextEditor;
|
|||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.getClipX.()I"] = function() {
|
||||
return this.clipX1 - this.transX;
|
||||
return this.clipX1;
|
||||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.getClipY.()I"] = function() {
|
||||
return this.clipY1 - this.transY;
|
||||
return this.clipY1;
|
||||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.getClipWidth.()I"] = function() {
|
||||
|
@ -730,10 +699,10 @@ var currentlyFocusedTextEditor;
|
|||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.getClip.([I)V"] = function(region) {
|
||||
region[0] = this.clipX1 - this.transX;
|
||||
region[1] = this.clipY1 - this.transY;
|
||||
region[2] = this.clipX2 - this.transX;
|
||||
region[3] = this.clipY2 - this.transY;
|
||||
region[0] = this.clipX1;
|
||||
region[1] = this.clipY1;
|
||||
region[2] = this.clipX2;
|
||||
region[3] = this.clipY2;
|
||||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.clipRect.(IIII)V"] = function(x, y, width, height) {
|
||||
|
@ -813,20 +782,9 @@ var currentlyFocusedTextEditor;
|
|||
|
||||
context.putImageData(imageData, 0, 0);
|
||||
|
||||
var c = withGraphics(graphics);
|
||||
if (graphics.clipped) {
|
||||
c.save();
|
||||
}
|
||||
|
||||
var pair = withClip(graphics, c, x, y);
|
||||
x = pair[0];
|
||||
y = pair[1];
|
||||
var c = graphics.context2D;
|
||||
|
||||
c.drawImage(context.canvas, x, y);
|
||||
|
||||
if (graphics.clipped) {
|
||||
c.restore();
|
||||
}
|
||||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.render.(Ljavax/microedition/lcdui/Image;III)Z"] = function(image, x, y, anchor) {
|
||||
|
@ -836,10 +794,7 @@ var currentlyFocusedTextEditor;
|
|||
function renderImage(g, image, x, y, anchor) {
|
||||
var texture = image.imageData.context.canvas;
|
||||
|
||||
var c = withGraphics(g);
|
||||
if (g.clipped) {
|
||||
c.save();
|
||||
}
|
||||
var c = g.context2D;
|
||||
|
||||
var pair = withAnchor(g, c, anchor, x, y, texture.width, texture.height);
|
||||
x = pair[0];
|
||||
|
@ -847,10 +802,6 @@ var currentlyFocusedTextEditor;
|
|||
|
||||
c.drawImage(texture, x, y);
|
||||
|
||||
if (g.clipped) {
|
||||
c.restore();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -896,73 +847,47 @@ var currentlyFocusedTextEditor;
|
|||
}
|
||||
|
||||
function setClip(g, x, y, width, height) {
|
||||
var translatedX1, translatedY1;
|
||||
var translatedX2, translatedY2;
|
||||
var newX1 = Math.max(0, x) & 0x7fff;
|
||||
var newX2 = Math.min(g.maxWidth, x + width) & 0x7fff;
|
||||
var newY1 = Math.max(0, y) & 0x7fff;
|
||||
var newY2 = Math.min(g.maxHeight, y + height) & 0x7fff;
|
||||
|
||||
// If width or height is zero or less then zero,
|
||||
// we do not preserve the current clipping and
|
||||
// set all clipping values to zero.
|
||||
if ((width <= 0) || (height <= 0)) {
|
||||
g.clipX1 = g.clipY1 = g.clipX2 = g.clipY2 = 0;
|
||||
g.clipped = true;
|
||||
if (g.runtimeClipEnforce) {
|
||||
newX1 = Math.max(newX1, g.systemClipX1);
|
||||
newY1 = Math.max(newY1, g.systemClipY1);
|
||||
newX2 = Math.min(newX2, g.systemClipX2);
|
||||
newY2 = Math.min(newY2, g.systemClipY2);
|
||||
}
|
||||
|
||||
if (width <= 0 || height <= 0 || newX2 <= newX1 || newY2 <= newY1) {
|
||||
newX1 = newY1 = newX2 = newY2 = 0;
|
||||
}
|
||||
|
||||
if (newX1 == g.clipX1 && newX2 == g.clipX2 && newY1 == g.clipY1 && newY2 == g.clipY2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Translate the given coordinates
|
||||
translatedX1 = x + g.transX;
|
||||
translatedY1 = y + g.transY;
|
||||
|
||||
// Detect Overflow
|
||||
translatedX1 = Math.max(0, translatedX1);
|
||||
translatedX1 = Math.min(translatedX1, g.maxWidth);
|
||||
translatedY1 = Math.max(0, translatedY1);
|
||||
translatedY1 = Math.min(translatedY1, g.maxHeight);
|
||||
|
||||
g.clipX1 = (translatedX1 & 0x7fff);
|
||||
g.clipY1 = (translatedY1 & 0x7fff);
|
||||
|
||||
if ((translatedX1 >= g.maxWidth)
|
||||
|| (translatedY1 >= g.maxHeight)) {
|
||||
g.clipX1 = g.clipY1 = g.clipX2 = g.clipY2 = 0;
|
||||
g.clipped = true;
|
||||
return;
|
||||
// If we're expanding the clip rect, we need to restore the pre-clipped context
|
||||
if (newX1 < g.clipX1 || newX2 > g.clipX2 || newY1 < g.clipY1 || newY2 > g.clipY2) {
|
||||
g.context2D.restore();
|
||||
g.context2D.translate(g.transX, g.transY);
|
||||
g.context2D.save();
|
||||
}
|
||||
|
||||
// Check against the runtime library clip values
|
||||
if (g.runtimeClipEnforce) {
|
||||
if (g.clipX1 < g.systemClipX1)
|
||||
clipX1 = g.systemClipX1;
|
||||
if (g.clipY1 < g.systemClipY1) {
|
||||
clipY1 = g.systemClipY1;
|
||||
}
|
||||
}
|
||||
g.clipped = newX1 > 0 ||
|
||||
newY1 > 0 ||
|
||||
newX2 < g.maxWidth ||
|
||||
newY2 < g.maxHeight;
|
||||
|
||||
// Translate the given width, height to abs. coordinates
|
||||
translatedX2 = x + g.transX + width;
|
||||
translatedY2 = y + g.transY + height;
|
||||
g.clipX1 = newX1;
|
||||
g.clipX2 = newX2;
|
||||
g.clipY1 = newY1;
|
||||
g.clipY2 = newY2;
|
||||
|
||||
// Detect overflow
|
||||
translatedX2 = Math.max(0, translatedX2);
|
||||
translatedX2 = Math.min(translatedX2, g.maxWidth);
|
||||
translatedY2 = Math.max(0, translatedY2);
|
||||
translatedY2 = Math.min(translatedY2, g.maxHeight);
|
||||
|
||||
g.clipX2 = (translatedX2 & 0x7FFF);
|
||||
g.clipY2 = (translatedY2 & 0x7FFF);
|
||||
|
||||
// Check against the runtime library clip values
|
||||
if (g.runtimeClipEnforce) {
|
||||
if (g.clipX2 > g.systemClipX2) {
|
||||
g.clipX2 = g.systemClipX2;
|
||||
}
|
||||
if (g.clipY2 > g.systemClipY2) {
|
||||
g.clipY2 = g.systemClipY2;
|
||||
}
|
||||
}
|
||||
|
||||
if ((g.clipX1 != 0) || (g.clipY1 != 0)
|
||||
|| (g.clipX2 != g.maxWidth) || (g.clipY2 != g.maxHeight)) {
|
||||
g.clipped = true;
|
||||
if (g.clipped) {
|
||||
g.context2D.beginPath();
|
||||
g.context2D.rect(g.clipX1, g.clipY1, g.clipX2 - g.clipX1, g.clipY2 - g.clipY1);
|
||||
g.context2D.clip();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -998,12 +923,15 @@ var currentlyFocusedTextEditor;
|
|||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.initScreen0.(III)V"] = function(displayId, w, h) {
|
||||
this.context2D = MIDP.Context2D;
|
||||
this.displayId = displayId;
|
||||
setDimensions(this, w, h);
|
||||
resetGC(this);
|
||||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.initImage0.(Ljavax/microedition/lcdui/Image;II)V"] = function(img, w, h) {
|
||||
this.context2D = img.imageData.context;
|
||||
this.context2D.save();
|
||||
this.img = img;
|
||||
setDimensions(this, w, h);
|
||||
resetGC(this);
|
||||
|
@ -1022,98 +950,47 @@ var currentlyFocusedTextEditor;
|
|||
|
||||
function reset(g, x1, y1, x2, y2) {
|
||||
resetGC(g);
|
||||
g.transX = g.transY = 0;
|
||||
translate(g, -g.transX, -g.transY);
|
||||
setClip(g, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
function translate(g, x, y) {
|
||||
g.transX += x;
|
||||
g.transY += y;
|
||||
g.context2D.translate(x, y);
|
||||
}
|
||||
|
||||
function setDimensions(g, w, h) {
|
||||
g.maxWidth = w & 0x7fff;
|
||||
g.maxHeight = h & 0x7fff;
|
||||
g.transX = g.transY = 0;
|
||||
translate(g, -g.transX, -g.transY);
|
||||
setClip(g, 0, 0, g.maxWidth, g.maxHeight);
|
||||
}
|
||||
|
||||
function clipRect(g, x, y, width, height) {
|
||||
var translatedX1, translatedY1;
|
||||
var translatedX2, translatedY2;
|
||||
var newX1 = Math.max(0, x) & 0x7fff;
|
||||
var newX2 = Math.min(g.maxWidth, x + width) & 0x7fff;
|
||||
var newY1 = Math.max(0, y) & 0x7fff;
|
||||
var newY2 = Math.min(g.maxHeight, y + height) & 0x7fff;
|
||||
|
||||
if (width <= 0 || height <= 0) {
|
||||
g.clipX1 = Math.max(g.clipX1, newX1) & 0x7fff;
|
||||
g.clipY1 = Math.max(g.clipY1, newY1) & 0x7fff;
|
||||
g.clipX2 = Math.min(g.clipX2, newX2) & 0x7fff;
|
||||
g.clipY2 = Math.min(g.clipY2, newY2) & 0x7fff;
|
||||
|
||||
if (width <= 0 || height <= 0 || g.clipX2 <= g.clipX1 || g.clipY2 <= g.clipY1) {
|
||||
g.clipX1 = g.clipY1 = g.clipX2 = g.clipY2 = 0;
|
||||
g.clipped = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Translate the given coordinates
|
||||
translatedX1 = x + g.transX;
|
||||
translatedY1 = y + g.transY;
|
||||
g.clipped = g.clipX1 > 0 ||
|
||||
g.clipY1 > 0 ||
|
||||
g.clipX2 < g.maxWidth ||
|
||||
g.clipY2 < g.maxHeight;
|
||||
|
||||
// Detect overflow
|
||||
if (translatedX1 < 0) {
|
||||
translatedX1 = (x < 0 || g.transX < 0) ? 0 : g.maxWidth;
|
||||
}
|
||||
if (translatedY1 < 0) {
|
||||
translatedY1 = (y < 0 || g.transY < 0) ? 0 : g.maxHeight;
|
||||
}
|
||||
|
||||
// If the passed in rect is below our current clip
|
||||
if ((g.clipX2 < translatedX1) || (g.clipY2 < translatedY1)) {
|
||||
// we have no intersection
|
||||
g.clipX1 = g.clipY1 = g.clipX2 = g.clipY2 = 0;
|
||||
g.clipped = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (translatedX1 > g.clipX1) {
|
||||
g.clipX1 = (translatedX1 & 0x7fff);
|
||||
g.clipped = true;
|
||||
}
|
||||
|
||||
if (translatedY1 > g.clipY1) {
|
||||
g.clipY1 = (translatedY1 & 0x7fff);
|
||||
g.clipped = true;
|
||||
}
|
||||
|
||||
// Start handling bottom right area
|
||||
|
||||
translatedX2 = x + g.transX + width;
|
||||
translatedY2 = y + g.transY + height;
|
||||
|
||||
// Detect Overflow
|
||||
if (translatedX2 < 0) {
|
||||
translatedX2 = (x < 0 || g.transX < 0) ? translatedX1 : g.maxWidth;
|
||||
}
|
||||
if (translatedY2 < 0) {
|
||||
translatedY2 = (y < 0 || g.transY < 0) ? translatedY1 : g.maxHeight;
|
||||
}
|
||||
|
||||
// If the passed in rect is above our current clip
|
||||
if (translatedX2 < g.clipX1 || translatedY2 < g.clipY1) {
|
||||
// we have no intersection
|
||||
g.clipX1 = g.clipY1 = g.clipX2 = g.clipY2 = 0;
|
||||
g.clipped = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (translatedX2 <= g.clipX2) {
|
||||
g.clipX2 = translatedX2 & 0xffff;
|
||||
g.clipped = true;
|
||||
}
|
||||
|
||||
if (translatedY2 <= g.clipY2) {
|
||||
g.clipY2 = translatedY2 & 0xffff;
|
||||
g.clipped = true;
|
||||
}
|
||||
|
||||
if (g.clipped == true) {
|
||||
if (g.clipX2 < g.clipX1)
|
||||
g.clipX2 = g.clipX1;
|
||||
if (g.clipY2 < g.clipY1)
|
||||
g.clipY2 = g.clipY1;
|
||||
if (g.clipped) {
|
||||
g.context2D.beginPath();
|
||||
g.context2D.rect(g.clipX1, g.clipY1, g.clipX2 - g.clipX1, g.clipY2 - g.clipY1);
|
||||
g.context2D.clip();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1142,14 +1019,7 @@ var currentlyFocusedTextEditor;
|
|||
function drawString(g, str, x, y, anchor, isOpaque) {
|
||||
var font = g.currentFont;
|
||||
|
||||
var c = withGraphics(g);
|
||||
if (g.clipped) {
|
||||
c.save();
|
||||
}
|
||||
|
||||
var pair = withClip(g, c, x, y);
|
||||
x = pair[0];
|
||||
y = pair[1];
|
||||
var c = g.context2D;
|
||||
|
||||
if (isOpaque) {
|
||||
withOpaquePixel(g, c);
|
||||
|
@ -1178,10 +1048,6 @@ var currentlyFocusedTextEditor;
|
|||
x += font.size;
|
||||
}
|
||||
});
|
||||
|
||||
if (g.clipped) {
|
||||
c.restore();
|
||||
}
|
||||
}
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.drawString.(Ljava/lang/String;III)V"] = function(str, x, y, anchor) {
|
||||
|
@ -1200,35 +1066,19 @@ var currentlyFocusedTextEditor;
|
|||
Native["javax/microedition/lcdui/Graphics.drawChar.(CIII)V"] = function(jChr, x, y, anchor) {
|
||||
var chr = String.fromCharCode(jChr);
|
||||
|
||||
var c = withGraphics(this);
|
||||
if (this.clipped) {
|
||||
c.save();
|
||||
}
|
||||
var c = this.context2D;
|
||||
|
||||
var pair = withClip(this, c, x, y);
|
||||
var pair = withTextAnchor(this, c, anchor, x, y, chr);
|
||||
x = pair[0];
|
||||
y = pair[1];
|
||||
|
||||
pair = withTextAnchor(this, c, anchor, x, y, chr), x = pair[0], y = pair[1];
|
||||
|
||||
withPixel(this, c);
|
||||
|
||||
c.fillText(chr, x, y);
|
||||
|
||||
if (this.clipped) {
|
||||
c.restore();
|
||||
}
|
||||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.fillTriangle.(IIIIII)V"] = function(x1, y1, x2, y2, x3, y3) {
|
||||
var c = withGraphics(this);
|
||||
if (this.clipped) {
|
||||
c.save();
|
||||
}
|
||||
|
||||
var pair = withClip(this, c, x1, y1);
|
||||
var x = pair[0];
|
||||
var y = pair[1];
|
||||
var c = this.context2D;
|
||||
|
||||
withPixel(this, c);
|
||||
|
||||
|
@ -1238,15 +1088,11 @@ var currentlyFocusedTextEditor;
|
|||
var dy2 = (y3 - y1) || 1;
|
||||
|
||||
c.beginPath();
|
||||
c.moveTo(x, y);
|
||||
c.lineTo(x + dx1, y + dy1);
|
||||
c.lineTo(x + dx2, y + dy2);
|
||||
c.moveTo(x1, y1);
|
||||
c.lineTo(x1 + dx1, y1 + dy1);
|
||||
c.lineTo(x1 + dx2, y1 + dy2);
|
||||
c.closePath();
|
||||
c.fill();
|
||||
|
||||
if (this.clipped) {
|
||||
c.restore();
|
||||
}
|
||||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.drawRect.(IIII)V"] = function(x, y, w, h) {
|
||||
|
@ -1254,14 +1100,7 @@ var currentlyFocusedTextEditor;
|
|||
return;
|
||||
}
|
||||
|
||||
var c = withGraphics(this);
|
||||
if (this.clipped) {
|
||||
c.save();
|
||||
}
|
||||
|
||||
var pair = withClip(this, c, x, y);
|
||||
x = pair[0];
|
||||
y = pair[1];
|
||||
var c = this.context2D;
|
||||
|
||||
withPixel(this, c);
|
||||
|
||||
|
@ -1269,10 +1108,6 @@ var currentlyFocusedTextEditor;
|
|||
h = h || 1;
|
||||
|
||||
c.strokeRect(x, y, w, h);
|
||||
|
||||
if (this.clipped) {
|
||||
c.restore();
|
||||
}
|
||||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.drawRoundRect.(IIIIII)V"] = function(x, y, w, h, arcWidth, arcHeight) {
|
||||
|
@ -1280,14 +1115,7 @@ var currentlyFocusedTextEditor;
|
|||
return;
|
||||
}
|
||||
|
||||
var c = withGraphics(this);
|
||||
if (this.clipped) {
|
||||
c.save();
|
||||
}
|
||||
|
||||
var pair = withClip(this, c, x, y);
|
||||
x = pair[0];
|
||||
y = pair[1];
|
||||
var c = this.context2D;
|
||||
|
||||
withPixel(this, c);
|
||||
|
||||
|
@ -1297,10 +1125,6 @@ var currentlyFocusedTextEditor;
|
|||
c.beginPath();
|
||||
createRoundRect(c, x, y, w, h, arcWidth, arcHeight);
|
||||
c.stroke();
|
||||
|
||||
if (this.clipped) {
|
||||
c.restore();
|
||||
}
|
||||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.fillRect.(IIII)V"] = function(x, y, w, h) {
|
||||
|
@ -1308,14 +1132,7 @@ var currentlyFocusedTextEditor;
|
|||
return;
|
||||
}
|
||||
|
||||
var c = withGraphics(this);
|
||||
if (this.clipped) {
|
||||
c.save();
|
||||
}
|
||||
|
||||
var pair = withClip(this, c, x, y);
|
||||
x = pair[0];
|
||||
y = pair[1];
|
||||
var c = this.context2D;
|
||||
|
||||
withPixel(this, c);
|
||||
|
||||
|
@ -1323,10 +1140,6 @@ var currentlyFocusedTextEditor;
|
|||
h = h || 1;
|
||||
|
||||
c.fillRect(x, y, w, h);
|
||||
|
||||
if (this.clipped) {
|
||||
c.restore();
|
||||
}
|
||||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.fillRoundRect.(IIIIII)V"] = function(x, y, w, h, arcWidth, arcHeight) {
|
||||
|
@ -1334,14 +1147,7 @@ var currentlyFocusedTextEditor;
|
|||
return;
|
||||
}
|
||||
|
||||
var c = withGraphics(this);
|
||||
if (this.clipped) {
|
||||
c.save();
|
||||
}
|
||||
|
||||
var pair = withClip(this, c, x, y);
|
||||
x = pair[0];
|
||||
y = pair[1];
|
||||
var c = this.context2D;
|
||||
|
||||
withPixel(this, c);
|
||||
|
||||
|
@ -1351,10 +1157,6 @@ var currentlyFocusedTextEditor;
|
|||
c.beginPath();
|
||||
createRoundRect(c, x, y, w, h, arcWidth, arcHeight);
|
||||
c.fill();
|
||||
|
||||
if (this.clipped) {
|
||||
c.restore();
|
||||
}
|
||||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.drawArc.(IIIIII)V"] = function(x, y, width, height, startAngle, arcAngle) {
|
||||
|
@ -1362,7 +1164,7 @@ var currentlyFocusedTextEditor;
|
|||
return;
|
||||
}
|
||||
|
||||
var c = withGraphics(this);
|
||||
var c = this.context2D;
|
||||
|
||||
withPixel(this, c);
|
||||
|
||||
|
@ -1378,7 +1180,7 @@ var currentlyFocusedTextEditor;
|
|||
return;
|
||||
}
|
||||
|
||||
var c = withGraphics(this);
|
||||
var c = this.context2D;
|
||||
|
||||
withPixel(this, c);
|
||||
|
||||
|
@ -1404,8 +1206,8 @@ var currentlyFocusedTextEditor;
|
|||
var imgData = image.imageData,
|
||||
texture = imgData.context.canvas;
|
||||
|
||||
var c = withGraphics(g);
|
||||
if (g.clipped || transform !== TRANS_NONE) {
|
||||
var c = g.context2D;
|
||||
if (transform !== TRANS_NONE) {
|
||||
c.save();
|
||||
}
|
||||
|
||||
|
@ -1427,7 +1229,7 @@ var currentlyFocusedTextEditor;
|
|||
|
||||
c.drawImage(texture, sx, sy, sw, sh, x, y, sw, sh);
|
||||
|
||||
if (g.clipped || transform !== TRANS_NONE) {
|
||||
if (transform !== TRANS_NONE) {
|
||||
c.restore();
|
||||
}
|
||||
|
||||
|
@ -1435,35 +1237,24 @@ var currentlyFocusedTextEditor;
|
|||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.drawLine.(IIII)V"] = function(x1, y1, x2, y2) {
|
||||
var c = withGraphics(this);
|
||||
if (this.clipped) {
|
||||
c.save();
|
||||
}
|
||||
|
||||
var pair = withClip(this, c, x1, y1);
|
||||
var x = pair[0];
|
||||
var y = pair[1];
|
||||
var c = this.context2D;
|
||||
|
||||
withPixel(this, c);
|
||||
|
||||
var dx = (x2 - x1);
|
||||
var dy = (y2 - y1);
|
||||
if (dx === 0) {
|
||||
x += .5;
|
||||
x1 += .5;
|
||||
}
|
||||
if (dy === 0) {
|
||||
y += .5;
|
||||
y1 += .5;
|
||||
}
|
||||
|
||||
c.beginPath();
|
||||
c.moveTo(x, y);
|
||||
c.lineTo(x + dx, y + dy);
|
||||
c.moveTo(x1, y1);
|
||||
c.lineTo(x1 + dx, y1 + dy);
|
||||
c.stroke();
|
||||
c.closePath();
|
||||
|
||||
if (this.clipped) {
|
||||
c.restore();
|
||||
}
|
||||
};
|
||||
|
||||
Native["javax/microedition/lcdui/Graphics.drawRGB.([IIIIIIIZ)V"] =
|
||||
|
@ -1477,20 +1268,9 @@ var currentlyFocusedTextEditor;
|
|||
|
||||
context.putImageData(imageData, 0, 0);
|
||||
|
||||
var c = withGraphics(this);
|
||||
if (this.clipped) {
|
||||
c.save();
|
||||
}
|
||||
|
||||
var pair = withClip(this, c, x, y);
|
||||
x = pair[0];
|
||||
y = pair[1];
|
||||
var c = this.context2D;
|
||||
|
||||
c.drawImage(context.canvas, x, y);
|
||||
|
||||
if (this.clipped) {
|
||||
c.restore();
|
||||
}
|
||||
};
|
||||
|
||||
var textEditorId = 0,
|
||||
|
|
142
midp/media.js
142
midp/media.js
|
@ -71,6 +71,8 @@ Media.extToFormat = new Map([
|
|||
["png", "PNG"],
|
||||
["wav", "wav"],
|
||||
["ogg", "ogg"],
|
||||
["mp4", "MPEG4"],
|
||||
["webm", "WebM"],
|
||||
]);
|
||||
|
||||
Media.contentTypeToFormat = new Map([
|
||||
|
@ -80,6 +82,8 @@ Media.contentTypeToFormat = new Map([
|
|||
["audio/mpeg", "MPEG_layer_3"],
|
||||
["image/jpeg", "JPEG"],
|
||||
["image/png", "PNG"],
|
||||
["video/mp4", "MPEG4"],
|
||||
["video/webm", "WebM"],
|
||||
]);
|
||||
|
||||
Media.formatToContentType = new Map();
|
||||
|
@ -89,6 +93,7 @@ for (var elem of Media.contentTypeToFormat) {
|
|||
|
||||
Media.supportedAudioFormats = ["MPEG_layer_3", "wav", "amr", "ogg"];
|
||||
Media.supportedImageFormats = ["JPEG", "PNG"];
|
||||
Media.supportedVideoFormats = ["MPEG4", "WebM"];
|
||||
|
||||
Media.EVENT_MEDIA_END_OF_MEDIA = 1;
|
||||
Media.EVENT_MEDIA_SNAPSHOT_FINISHED = 11;
|
||||
|
@ -316,8 +321,6 @@ function ImagePlayer(playerContainer) {
|
|||
}
|
||||
|
||||
ImagePlayer.prototype.realize = function() {
|
||||
var objectUrl;
|
||||
|
||||
var ctx = $.ctx;
|
||||
|
||||
var p = new Promise((function(resolve, reject) {
|
||||
|
@ -332,19 +335,20 @@ ImagePlayer.prototype.realize = function() {
|
|||
var imgData = fs.read(fd);
|
||||
fs.close(fd);
|
||||
this.image.src = URL.createObjectURL(new Blob([ imgData ]));
|
||||
objectUrl = this.image.src;
|
||||
}).bind(this));
|
||||
} else {
|
||||
this.image.src = this.url;
|
||||
}
|
||||
}).bind(this));
|
||||
|
||||
p.done(function() {
|
||||
if (!objectUrl) {
|
||||
p.catch(function() {
|
||||
// Ignore promise rejection, we only need to revoke the object URL
|
||||
}).then((function() {
|
||||
if (!this.image.src) {
|
||||
return;
|
||||
}
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
});
|
||||
URL.revokeObjectURL(this.image.src);
|
||||
}).bind(this));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
@ -385,6 +389,123 @@ ImagePlayer.prototype.setVisible = function(visible) {
|
|||
this.image.style.visibility = visible ? "visible" : "hidden";
|
||||
}
|
||||
|
||||
function VideoPlayer(playerContainer) {
|
||||
this.playerContainer = playerContainer;
|
||||
|
||||
this.video = document.createElement("video");
|
||||
this.video.style.position = "absolute";
|
||||
this.video.style.visibility = "hidden";
|
||||
|
||||
this.isVideoControlSupported = true;
|
||||
this.isVolumeControlSupported = true;
|
||||
|
||||
// VideoPlayer::start could be called while the video element
|
||||
// is hidden, causing the call to HTMLVideoElement::play to be
|
||||
// ignored.
|
||||
// Thus, we need to call HTMLVideoElement::play when the element
|
||||
// gets visible.
|
||||
this.isPlaying = false;
|
||||
}
|
||||
|
||||
VideoPlayer.prototype.realize = function() {
|
||||
var ctx = $.ctx;
|
||||
|
||||
var p = new Promise((function(resolve, reject) {
|
||||
this.video.addEventListener("canplay", (function onCanPlay() {
|
||||
this.video.removeEventListener("canplay", onCanPlay);
|
||||
resolve(1);
|
||||
}).bind(this));
|
||||
|
||||
this.video.onerror = function() {
|
||||
ctx.setAsCurrentContext();
|
||||
reject($.newMediaException("Failed to load video"));
|
||||
};
|
||||
|
||||
if (this.playerContainer.url.startsWith("file")) {
|
||||
fs.open(this.playerContainer.url.substring(7), (function(fd) {
|
||||
var videoData = fs.read(fd);
|
||||
fs.close(fd);
|
||||
this.video.src = URL.createObjectURL(new Blob([ videoData ]),
|
||||
{ type: this.playerContainer.contentType });
|
||||
}).bind(this));
|
||||
} else {
|
||||
this.video.src = this.playerContainer.url;
|
||||
}
|
||||
}).bind(this));
|
||||
|
||||
p.catch(function() {
|
||||
// Ignore promise rejection, we only need to revoke the object URL
|
||||
}).then((function() {
|
||||
if (!this.video.src) {
|
||||
return;
|
||||
}
|
||||
URL.revokeObjectURL(this.video.src);
|
||||
}).bind(this));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
VideoPlayer.prototype.start = function() {
|
||||
if (this.video.style.visibility === "hidden") {
|
||||
this.isPlaying = true;
|
||||
} else {
|
||||
this.video.play();
|
||||
}
|
||||
}
|
||||
|
||||
VideoPlayer.prototype.pause = function() {
|
||||
this.video.pause();
|
||||
this.isPlaying = false;
|
||||
}
|
||||
|
||||
VideoPlayer.prototype.close = function() {
|
||||
if (this.video.parentNode) {
|
||||
this.video.parentNode.removeChild(this.video);
|
||||
}
|
||||
this.pause();
|
||||
}
|
||||
|
||||
VideoPlayer.prototype.getMediaTime = function() {
|
||||
return Math.round(this.video.currentTime * 1000);
|
||||
}
|
||||
|
||||
VideoPlayer.prototype.getWidth = function() {
|
||||
return this.video.videoWidth;
|
||||
}
|
||||
|
||||
VideoPlayer.prototype.getHeight = function() {
|
||||
return this.video.videoHeight;
|
||||
}
|
||||
|
||||
VideoPlayer.prototype.setLocation = function(x, y, w, h) {
|
||||
this.video.style.left = x + "px";
|
||||
this.video.style.top = y + "px";
|
||||
this.video.style.width = w + "px";
|
||||
this.video.style.height = h + "px";
|
||||
document.getElementById("main").appendChild(this.video);
|
||||
}
|
||||
|
||||
VideoPlayer.prototype.setVisible = function(visible) {
|
||||
this.video.style.visibility = visible ? "visible" : "hidden";
|
||||
if (visible && this.isPlaying) {
|
||||
this.video.play();
|
||||
}
|
||||
}
|
||||
|
||||
VideoPlayer.prototype.getVolume = function() {
|
||||
return Math.floor(this.video.volume * 100);
|
||||
};
|
||||
|
||||
VideoPlayer.prototype.setVolume = function(level) {
|
||||
if (level < 0) {
|
||||
level = 0;
|
||||
} else if (level > 100) {
|
||||
level = 100;
|
||||
}
|
||||
this.video.volume = level / 100;
|
||||
return level;
|
||||
};
|
||||
|
||||
function ImageRecorder(playerContainer) {
|
||||
this.playerContainer = playerContainer;
|
||||
|
||||
|
@ -411,9 +532,9 @@ ImageRecorder.prototype.realize = function() {
|
|||
}
|
||||
|
||||
ImageRecorder.prototype.recipient = function(message) {
|
||||
this.ctx.setAsCurrentContext();
|
||||
switch (message.type) {
|
||||
case "initerror":
|
||||
this.ctx.setAsCurrentContext();
|
||||
if (message.name == "PermissionDeniedError") {
|
||||
this.realizeRejector($.newSecurityException("Not permitted to init camera"));
|
||||
} else {
|
||||
|
@ -470,7 +591,7 @@ ImageRecorder.prototype.getHeight = function() {
|
|||
}
|
||||
|
||||
ImageRecorder.prototype.setLocation = function(x, y, w, h) {
|
||||
var displayElem = document.getElementById("main");
|
||||
var displayElem = document.getElementById("display");
|
||||
this.sender({
|
||||
type: "setPosition",
|
||||
x: x + displayElem.offsetLeft,
|
||||
|
@ -581,6 +702,9 @@ PlayerContainer.prototype.realize = function(contentType) {
|
|||
this.player = new ImagePlayer(this);
|
||||
}
|
||||
this.player.realize().then(resolve, reject);
|
||||
} else if (Media.supportedVideoFormats.indexOf(this.mediaFormat) !== -1) {
|
||||
this.player = new VideoPlayer(this);
|
||||
this.player.realize().then(resolve, reject);
|
||||
} else {
|
||||
console.warn("Unsupported media format (" + this.mediaFormat + ") for " + this.url);
|
||||
resolve(0);
|
||||
|
|
|
@ -767,7 +767,9 @@ MIDP.Context2D = (function() {
|
|||
mouseDownInfo = null; // Clear the way for the next gesture.
|
||||
});
|
||||
|
||||
return c.getContext("2d");
|
||||
var ret = c.getContext("2d");
|
||||
ret.save();
|
||||
return ret;
|
||||
})();
|
||||
|
||||
Native["com/sun/midp/midletsuite/MIDletSuiteStorage.loadSuitesIcons0.()I"] = function() {
|
||||
|
|
|
@ -145,17 +145,17 @@ Native["com/sun/midp/io/j2me/socket/Protocol.read0.([BII)I"] = function(data, of
|
|||
Native["com/sun/midp/io/j2me/socket/Protocol.write0.([BII)I"] = function(data, offset, length) {
|
||||
var ctx = $.ctx;
|
||||
asyncImpl("I", new Promise(function(resolve, reject) {
|
||||
ctx.setAsCurrentContext();
|
||||
if (this.socket.isClosed) {
|
||||
ctx.setAsCurrentContext();
|
||||
reject($.newIOException("socket is closed"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.socket.onsend = function(message) {
|
||||
ctx.setAsCurrentContext();
|
||||
this.socket.onsend = null;
|
||||
if ("error" in message) {
|
||||
console.error(message.error);
|
||||
ctx.setAsCurrentContext();
|
||||
reject($.newIOException("error writing to socket"));
|
||||
} else if (message.result) {
|
||||
resolve(length);
|
||||
|
|
166
native.js
166
native.js
|
@ -465,6 +465,9 @@ Native["java/lang/Runtime.totalMemory.()J"] = function() {
|
|||
};
|
||||
|
||||
Native["java/lang/Runtime.gc.()V"] = function() {
|
||||
if (typeof gc !== "undefined") {
|
||||
gc(); // gc exists in the spidermonkey shell.
|
||||
}
|
||||
};
|
||||
|
||||
Native["java/lang/Math.floor.(D)D"] = function(val) {
|
||||
|
@ -708,7 +711,6 @@ var waitingForLinks = {};
|
|||
Native["com/sun/midp/links/LinkPortal.getLinkCount0.()I"] = function() {
|
||||
var ctx = $.ctx;
|
||||
asyncImpl("I", new Promise(function(resolve, reject) {
|
||||
ctx.setAsCurrentContext();
|
||||
var isolateId = ctx.runtime.isolate.id;
|
||||
|
||||
if (!links[isolateId]) {
|
||||
|
@ -754,24 +756,6 @@ Native["com/sun/midp/links/Link.receive0.(Lcom/sun/midp/links/LinkMessage;Lcom/s
|
|||
asyncImpl("V", new Promise(function(){}));
|
||||
};
|
||||
|
||||
Native["com/sun/cldc/i18n/j2me/UTF_8_Reader.init.([B)V"] = function(data) {
|
||||
this.decoded = new TextDecoder("UTF-8").decode(data);
|
||||
};
|
||||
|
||||
Native["com/sun/cldc/i18n/j2me/UTF_8_Reader.readNative.([CII)I"] = function(cbuf, off, len) {
|
||||
if (this.decoded.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
cbuf[i + off] = this.decoded.charCodeAt(i);
|
||||
}
|
||||
|
||||
this.decoded = this.decoded.substring(len);
|
||||
|
||||
return len;
|
||||
};
|
||||
|
||||
Native["java/io/DataInputStream.bytesToUTF.([B)Ljava/lang/String;"] = function(bytearr) {
|
||||
var array = new Int8Array(bytearr.buffer);
|
||||
try {
|
||||
|
@ -826,129 +810,6 @@ Native["java/io/DataOutputStream.UTFToBytes.(Ljava/lang/String;)[B"] = function(
|
|||
return bytearr;
|
||||
};
|
||||
|
||||
Native["com/sun/cldc/i18n/j2me/UTF_8_Writer.encodeUTF8.([CII)[B"] = function(cbuf, off, len) {
|
||||
var outputArray = [];
|
||||
|
||||
var pendingSurrogate = this.pendingSurrogate;
|
||||
|
||||
var inputChar = 0;
|
||||
var outputSize = 0;
|
||||
var count = 0;
|
||||
|
||||
while (count < len) {
|
||||
var outputByte = new Int8Array(4); // Never more than 4 encoded bytes
|
||||
inputChar = 0xffff & cbuf[off + count];
|
||||
if (0 != pendingSurrogate) {
|
||||
if (0xdc00 <= inputChar && inputChar <= 0xdfff) {
|
||||
//000u uuuu xxxx xxxx xxxx xxxx
|
||||
//1101 10ww wwxx xxxx 1101 11xx xxxx xxxx
|
||||
var highHalf = (pendingSurrogate & 0x03ff) + 0x0040;
|
||||
var lowHalf = inputChar & 0x03ff;
|
||||
inputChar = (highHalf << 10) | lowHalf;
|
||||
} else {
|
||||
// write replacement value instead of unpaired surrogate
|
||||
outputByte[0] = replacementValue;
|
||||
outputSize = 1;
|
||||
outputArray.push(outputByte.subarray(0, outputSize));
|
||||
}
|
||||
pendingSurrogate = 0;
|
||||
}
|
||||
if (inputChar < 0x80) {
|
||||
outputByte[0] = inputChar;
|
||||
outputSize = 1;
|
||||
} else if (inputChar < 0x800) {
|
||||
outputByte[0] = 0xc0 | ((inputChar >> 6) & 0x1f);
|
||||
outputByte[1] = 0x80 | (inputChar & 0x3f);
|
||||
outputSize = 2;
|
||||
} else if (0xd800 <= inputChar && inputChar <= 0xdbff) {
|
||||
pendingSurrogate = inputChar;
|
||||
outputSize = 0;
|
||||
} else if (0xdc00 <= inputChar && inputChar <= 0xdfff) {
|
||||
// unpaired surrogate
|
||||
outputByte[0] = replacementValue;
|
||||
outputSize = 1;
|
||||
} else if (inputChar < 0x10000) {
|
||||
outputByte[0] = 0xe0 | ((inputChar >> 12) & 0x0f);
|
||||
outputByte[1] = 0x80 | ((inputChar >> 6) & 0x3f);
|
||||
outputByte[2] = 0x80 | (inputChar & 0x3f);
|
||||
outputSize = 3;
|
||||
} else {
|
||||
/* 21 bits: 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
|
||||
* a aabb bbbb cccc ccdd dddd
|
||||
*/
|
||||
outputByte[0] = 0xf0 | ((inputChar >> 18) & 0x07);
|
||||
outputByte[1] = 0x80 | ((inputChar >> 12) & 0x3f);
|
||||
outputByte[2] = 0x80 | ((inputChar >> 6) & 0x3f);
|
||||
outputByte[3] = 0x80 | (inputChar & 0x3f);
|
||||
outputSize = 4;
|
||||
}
|
||||
outputArray.push(outputByte.subarray(0, outputSize));
|
||||
count++;
|
||||
}
|
||||
|
||||
this.pendingSurrogate = pendingSurrogate;
|
||||
|
||||
var totalSize = outputArray.reduce(function(total, cur) {
|
||||
return total + cur.length;
|
||||
}, 0);
|
||||
|
||||
var res = J2ME.newByteArray(totalSize);
|
||||
outputArray.reduce(function(total, cur) {
|
||||
res.set(cur, total);
|
||||
return total + cur.length;
|
||||
}, 0);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
Native["com/sun/cldc/i18n/j2me/UTF_8_Writer.sizeOf.([CII)I"] = function(cbuf, off, len) {
|
||||
var inputChar = 0;
|
||||
var outputSize = 0;
|
||||
var outputCount = 0;
|
||||
var count = 0;
|
||||
var localPendingSurrogate = this.pendingSurrogate;
|
||||
while (count < length) {
|
||||
inputChar = 0xffff & cbuf[offset + count];
|
||||
if (0 != localPendingSurrogate) {
|
||||
if (0xdc00 <= inputChar && inputChar <= 0xdfff) {
|
||||
//000u uuuu xxxx xxxx xxxx xxxx
|
||||
//1101 10ww wwxx xxxx 1101 11xx xxxx xxxx
|
||||
var highHalf = (localPendingSurrogate & 0x03ff) + 0x0040;
|
||||
var lowHalf = inputChar & 0x03ff;
|
||||
inputChar = (highHalf << 10) | lowHalf;
|
||||
} else {
|
||||
// going to write replacement value instead of unpaired surrogate
|
||||
outputSize = 1;
|
||||
outputCount += outputSize;
|
||||
}
|
||||
localPendingSurrogate = 0;
|
||||
}
|
||||
if (inputChar < 0x80) {
|
||||
outputSize = 1;
|
||||
} else if (inputChar < 0x800) {
|
||||
outputSize = 2;
|
||||
} else if (0xd800 <= inputChar && inputChar <= 0xdbff) {
|
||||
localPendingSurrogate = inputChar;
|
||||
outputSize = 0;
|
||||
} else if (0xdc00 <= inputChar && inputChar <= 0xdfff) {
|
||||
// unpaired surrogate
|
||||
// going to output replacementValue;
|
||||
outputSize = 1;
|
||||
} else if (inputChar < 0x10000) {
|
||||
outputSize = 3;
|
||||
} else {
|
||||
/* 21 bits: 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
|
||||
* a aabb bbbb cccc ccdd dddd
|
||||
*/
|
||||
outputSize = 4;
|
||||
}
|
||||
outputCount += outputSize;
|
||||
count++;
|
||||
}
|
||||
|
||||
return outputCount;
|
||||
};
|
||||
|
||||
Native["com/sun/j2me/content/AppProxy.midletIsAdded.(ILjava/lang/String;)V"] = function(suiteId, className) {
|
||||
console.warn("com/sun/j2me/content/AppProxy.midletIsAdded.(ILjava/lang/String;)V not implemented");
|
||||
};
|
||||
|
@ -971,8 +832,8 @@ Native["com/nokia/mid/impl/jms/core/Launcher.handleContent.(Ljava/lang/String;)V
|
|||
// the root dir to make sure it's valid.
|
||||
fileName = "/" + fileName;
|
||||
fs.open(fileName, function(fd) {
|
||||
ctx.setAsCurrentContext();
|
||||
if (fd == -1) {
|
||||
ctx.setAsCurrentContext();
|
||||
console.error("File not found: " + fileName);
|
||||
reject($.newException("File not found: " + fileName));
|
||||
return;
|
||||
|
@ -1034,3 +895,22 @@ function addUnimplementedNative(signature, returnValue) {
|
|||
|
||||
Native[signature] = function() { return warnOnce() };
|
||||
}
|
||||
|
||||
Native["org/mozilla/internal/Sys.eval.(Ljava/lang/String;)V"] = function(src) {
|
||||
if (!release) {
|
||||
eval(J2ME.fromJavaString(src));
|
||||
}
|
||||
};
|
||||
|
||||
Native["java/lang/String.intern.()Ljava/lang/String;"] = function() {
|
||||
var string = util.fromJavaString(this);
|
||||
|
||||
var internedString = J2ME.internedStrings.get(string);
|
||||
|
||||
if (internedString) {
|
||||
return internedString;
|
||||
} else {
|
||||
J2ME.internedStrings.set(string, this);
|
||||
return this;
|
||||
}
|
||||
};
|
123
override.js
123
override.js
|
@ -42,129 +42,6 @@ function asyncImpl(returnKind, promise) {
|
|||
$.pause("Async");
|
||||
}
|
||||
|
||||
Override["java/lang/Math.min.(II)I"] = function(a, b) {
|
||||
return Math.min(a, b);
|
||||
};
|
||||
|
||||
Override["java/io/ByteArrayOutputStream.write.([BII)V"] = function(b, off, len) {
|
||||
if ((off < 0) || (off > b.length) || (len < 0) ||
|
||||
((off + len) > b.length)) {
|
||||
throw $.newIndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var count = this.count;
|
||||
var buf = this.buf;
|
||||
|
||||
var newcount = count + len;
|
||||
if (newcount > buf.length) {
|
||||
var newbuf = J2ME.newByteArray(Math.max(buf.length << 1, newcount));
|
||||
newbuf.set(buf);
|
||||
buf = newbuf;
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
buf.set(b.subarray(off, off + len), count);
|
||||
this.count = newcount;
|
||||
};
|
||||
|
||||
Override["java/io/ByteArrayOutputStream.write.(I)V"] = function(value) {
|
||||
var count = this.count;
|
||||
var buf = this.buf;
|
||||
|
||||
var newcount = count + 1;
|
||||
if (newcount > buf.length) {
|
||||
var newbuf = J2ME.newByteArray(Math.max(buf.length << 1, newcount));
|
||||
newbuf.set(buf);
|
||||
buf = newbuf;
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
buf[count] = value;
|
||||
this.count = newcount;
|
||||
};
|
||||
|
||||
Override["java/io/ByteArrayInputStream.<init>.([B)V"] = function(buf) {
|
||||
if (!buf) {
|
||||
throw $.newNullPointerException();
|
||||
}
|
||||
|
||||
this.buf = buf;
|
||||
this.pos = this.mark = 0;
|
||||
this.count = buf.length;
|
||||
};
|
||||
|
||||
Override["java/io/ByteArrayInputStream.<init>.([BII)V"] = function(buf, offset, length) {
|
||||
if (!buf) {
|
||||
throw $.newNullPointerException();
|
||||
}
|
||||
|
||||
this.buf = buf;
|
||||
this.pos = this.mark = offset;
|
||||
this.count = (offset + length <= buf.length) ? (offset + length) : buf.length;
|
||||
};
|
||||
|
||||
Override["java/io/ByteArrayInputStream.read.()I"] = function() {
|
||||
return (this.pos < this.count) ? (this.buf[this.pos++] & 0xFF) : -1;
|
||||
};
|
||||
|
||||
Override["java/io/ByteArrayInputStream.read.([BII)I"] = function(b, off, len) {
|
||||
if (!b) {
|
||||
throw $.newNullPointerException();
|
||||
}
|
||||
|
||||
if ((off < 0) || (off > b.length) || (len < 0) ||
|
||||
((off + len) > b.length)) {
|
||||
throw $.newIndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
if (this.pos >= this.count) {
|
||||
return -1;
|
||||
}
|
||||
if (this.pos + len > this.count) {
|
||||
len = this.count - this.pos;
|
||||
}
|
||||
if (len === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
b.set(this.buf.subarray(this.pos, this.pos + len), off);
|
||||
|
||||
this.pos += len;
|
||||
return len;
|
||||
};
|
||||
|
||||
Override["java/io/ByteArrayInputStream.skip.(J)J"] = function(long) {
|
||||
var n = long.toNumber();
|
||||
|
||||
if (this.pos + n > this.count) {
|
||||
n = this.count - this.pos;
|
||||
}
|
||||
|
||||
if (n < 0) {
|
||||
return Long.fromNumber(0);
|
||||
}
|
||||
|
||||
this.pos += n;
|
||||
|
||||
return Long.fromNumber(n);
|
||||
};
|
||||
|
||||
Override["java/io/ByteArrayInputStream.available.()I"] = function() {
|
||||
return this.count - this.pos;
|
||||
};
|
||||
|
||||
Override["java/io/ByteArrayInputStream.mark.(I)V"] = function(readAheadLimit) {
|
||||
this.mark = this.pos;
|
||||
};
|
||||
|
||||
Override["java/io/ByteArrayInputStream.reset.()V"] = function() {
|
||||
this.pos = this.mark;
|
||||
};
|
||||
|
||||
// The following Permissions methods are overriden to avoid expensive calls to
|
||||
// DomainPolicy.loadValues. This has the added benefit that we avoid many other
|
||||
// computations.
|
||||
|
|
621
string.js
621
string.js
|
@ -1,621 +0,0 @@
|
|||
/* -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* string.js: Native implementations of String and StringBuffer.
|
||||
*
|
||||
* Methods are defined in the same order as the Java source.
|
||||
* Any missing methods have been noted in comments.
|
||||
*/
|
||||
|
||||
//################################################################
|
||||
// java.lang.String (manipulated via the 'str' property)
|
||||
|
||||
function isString(obj) {
|
||||
return obj && obj.str !== undefined;
|
||||
}
|
||||
|
||||
//****************************************************************
|
||||
// Constructors
|
||||
|
||||
Override["java/lang/String.<init>.()V"] = function() {
|
||||
this.str = "";
|
||||
};
|
||||
|
||||
Override["java/lang/String.<init>.(Ljava/lang/String;)V"] = function(jStr) {
|
||||
if (!jStr) {
|
||||
throw $.newNullPointerException();
|
||||
}
|
||||
this.str = jStr.str;
|
||||
};
|
||||
|
||||
Override["java/lang/String.<init>.([C)V"] = function(chars) {
|
||||
if (!chars) {
|
||||
throw $.newNullPointerException();
|
||||
}
|
||||
this.str = util.fromJavaChars(chars);
|
||||
};
|
||||
|
||||
Override["java/lang/String.<init>.([CII)V"] = function(value, offset, count) {
|
||||
if (offset < 0 || count < 0 || offset > value.length - count) {
|
||||
throw $.newIndexOutOfBoundsException();
|
||||
}
|
||||
this.str = util.fromJavaChars(value, offset, count);
|
||||
};
|
||||
|
||||
// Several constructors below share this implementation:
|
||||
function constructFromByteArray(bytes, off, len, enc) {
|
||||
enc = normalizeEncoding(enc);
|
||||
bytes = bytes.subarray(off, off + len);
|
||||
try {
|
||||
this.str = new TextDecoder(enc).decode(bytes);
|
||||
} catch(e) {
|
||||
throw $.newUnsupportedEncodingException();
|
||||
}
|
||||
}
|
||||
|
||||
Override["java/lang/String.<init>.([BIILjava/lang/String;)V"] =
|
||||
function(bytes, off, len, enc) {
|
||||
constructFromByteArray.call(this, bytes, off, len, enc.str);
|
||||
};
|
||||
|
||||
Override["java/lang/String.<init>.([BLjava/lang/String;)V"] =
|
||||
function(bytes, enc) {
|
||||
constructFromByteArray.call(this, bytes, 0, bytes.length, enc.str);
|
||||
};
|
||||
|
||||
Override["java/lang/String.<init>.([BII)V"] =
|
||||
function(bytes, offset, len) {
|
||||
constructFromByteArray.call(this, bytes, offset, len, "UTF-8");
|
||||
};
|
||||
|
||||
Override["java/lang/String.<init>.([B)V"] =
|
||||
function(bytes) {
|
||||
constructFromByteArray.call(this, bytes, 0, bytes.length, "UTF-8");
|
||||
};
|
||||
|
||||
Override["java/lang/String.<init>.(Ljava/lang/StringBuffer;)V"] =
|
||||
function(jBuffer) {
|
||||
this.str = util.fromJavaChars(jBuffer.buf, 0, jBuffer.count);
|
||||
};
|
||||
|
||||
Override["java/lang/String.<init>.(II[C)V"] =
|
||||
function(offset, count, value) {
|
||||
this.str = util.fromJavaChars(value, offset, count);
|
||||
};
|
||||
|
||||
//****************************************************************
|
||||
// Methods
|
||||
|
||||
Override["java/lang/String.length.()I"] = function() {
|
||||
return this.str.length;
|
||||
};
|
||||
|
||||
Override["java/lang/String.charAt.(I)C"] = function(index) {
|
||||
if (index < 0 || index >= this.str.length) {
|
||||
throw $.newIndexOutOfBoundsException();
|
||||
}
|
||||
return this.str.charCodeAt(index);
|
||||
};
|
||||
|
||||
Override["java/lang/String.getChars.(II[CI)V"] = function(srcBegin, srcEnd, dst, dstBegin) {
|
||||
if (srcBegin < 0 || srcEnd > this.str.length || srcBegin > srcEnd ||
|
||||
dstBegin + (srcEnd - srcBegin) > dst.length || dstBegin < 0) {
|
||||
throw $.newIndexOutOfBoundsException();
|
||||
}
|
||||
dst.set(util.stringToCharArray(this.str.substring(srcBegin, srcEnd)), dstBegin);
|
||||
};
|
||||
|
||||
// Java returns encodings like "UTF_16"; TextEncoder and friends only
|
||||
// like hyphens, not underscores.
|
||||
function normalizeEncoding(enc) {
|
||||
var encoding = enc.toLowerCase().replace(/_/g, '-');
|
||||
if (encoding == "utf-16") {
|
||||
encoding = "utf-16be"; // Java defaults to big-endian, JS to little-endian.
|
||||
}
|
||||
return encoding;
|
||||
}
|
||||
|
||||
Override["java/lang/String.getBytes.(Ljava/lang/String;)[B"] = function(jEnc) {
|
||||
try {
|
||||
var encoding = normalizeEncoding(jEnc.str);
|
||||
return new Int8Array(new TextEncoder(encoding).encode(this.str));
|
||||
} catch (e) {
|
||||
throw $.newUnsupportedEncodingException();
|
||||
}
|
||||
};
|
||||
|
||||
Override["java/lang/String.getBytes.()[B"] = function() {
|
||||
return new Int8Array(new TextEncoder("utf-8").encode(this.str));
|
||||
};
|
||||
|
||||
Override["java/lang/String.equals.(Ljava/lang/Object;)Z"] = function(anObject) {
|
||||
return (isString(anObject) && anObject.str === this.str) ? 1 : 0;
|
||||
};
|
||||
|
||||
Override["java/lang/String.equalsIgnoreCase.(Ljava/lang/String;)Z"] = function(anotherString) {
|
||||
return (isString(anotherString) && anotherString.str.toLowerCase() === this.str.toLowerCase()) ? 1 : 0;
|
||||
};
|
||||
|
||||
Override["java/lang/String.compareTo.(Ljava/lang/String;)I"] = function(anotherString) {
|
||||
// Sadly, JS String doesn't have a compareTo() method, so we must
|
||||
// replicate the Java algorithm. (There is String.localeCompare, but
|
||||
// that only returns {-1, 0, 1}, not a distance measure, which this
|
||||
// requires.
|
||||
var len1 = this.str.length;
|
||||
var len2 = anotherString.str.length;
|
||||
var n = Math.min(len1, len2);
|
||||
var v1 = this.str;
|
||||
var v2 = anotherString.str;
|
||||
for (var k = 0; k < n; k++) {
|
||||
var c1 = v1.charCodeAt(k);
|
||||
var c2 = v2.charCodeAt(k);
|
||||
if (c1 != c2) {
|
||||
return c1 - c2;
|
||||
}
|
||||
}
|
||||
return len1 - len2;
|
||||
};
|
||||
|
||||
Override["java/lang/String.regionMatches.(ZILjava/lang/String;II)Z"] = function(ignoreCase, toffset, other, ooffset, len) {
|
||||
var a = (ignoreCase ? this.str.toLowerCase() : this.str);
|
||||
var b = (ignoreCase ? other.str.toLowerCase() : other.str);
|
||||
return a.substr(toffset, len) === b.substr(ooffset, len) ? 1 : 0;
|
||||
};
|
||||
|
||||
Override["java/lang/String.startsWith.(Ljava/lang/String;I)Z"] = function(prefix, toffset) {
|
||||
return this.str.substr(toffset, prefix.str.length) === prefix.str ? 1 : 0;
|
||||
};
|
||||
|
||||
Override["java/lang/String.startsWith.(Ljava/lang/String;)Z"] = function(prefix) {
|
||||
return this.str.substr(0, prefix.str.length) === prefix.str ? 1 : 0;
|
||||
};
|
||||
|
||||
Override["java/lang/String.endsWith.(Ljava/lang/String;)Z"] = function(suffix) {
|
||||
return this.str.indexOf(suffix.str, this.str.length - suffix.str.length) !== -1 ? 1 : 0;
|
||||
};
|
||||
|
||||
Override["java/lang/String.hashCode.()I"] = function() {
|
||||
var hash = 0;
|
||||
for (var i = 0; i < this.str.length; i++) {
|
||||
hash = Math.imul(31, hash) + this.str.charCodeAt(i) | 0;
|
||||
}
|
||||
return hash;
|
||||
};
|
||||
|
||||
Override["java/lang/String.indexOf.(I)I"] = function(ch) {
|
||||
return this.str.indexOf(String.fromCharCode(ch));
|
||||
};
|
||||
|
||||
Override["java/lang/String.indexOf.(II)I"] = function(ch, fromIndex) {
|
||||
return this.str.indexOf(String.fromCharCode(ch), fromIndex);
|
||||
};
|
||||
|
||||
Override["java/lang/String.lastIndexOf.(I)I"] = function(ch) {
|
||||
return this.str.lastIndexOf(String.fromCharCode(ch));
|
||||
};
|
||||
|
||||
Override["java/lang/String.lastIndexOf.(II)I"] = function(ch, fromIndex) {
|
||||
return this.str.lastIndexOf(String.fromCharCode(ch), fromIndex);
|
||||
};
|
||||
|
||||
Override["java/lang/String.indexOf.(Ljava/lang/String;)I"] = function(s) {
|
||||
return this.str.indexOf(s.str);
|
||||
};
|
||||
|
||||
Override["java/lang/String.indexOf.(Ljava/lang/String;I)I"] = function(s, fromIndex) {
|
||||
return this.str.indexOf(s.str, fromIndex);
|
||||
};
|
||||
|
||||
Override["java/lang/String.substring.(I)Ljava/lang/String;"] = function(beginIndex) {
|
||||
if (beginIndex < 0 || beginIndex > this.str.length) {
|
||||
throw $.newIndexOutOfBoundsException();
|
||||
}
|
||||
return J2ME.newString(this.str.substring(beginIndex));
|
||||
};
|
||||
|
||||
Override["java/lang/String.substring.(II)Ljava/lang/String;"] = function(beginIndex, endIndex) {
|
||||
if (beginIndex < 0 || endIndex > this.str.length || beginIndex > endIndex) {
|
||||
throw $.newIndexOutOfBoundsException();
|
||||
}
|
||||
return J2ME.newString(this.str.substring(beginIndex, endIndex));
|
||||
};
|
||||
|
||||
Override["java/lang/String.concat.(Ljava/lang/String;)Ljava/lang/String;"] = function(s) {
|
||||
return J2ME.newString(this.str + s.str);
|
||||
};
|
||||
|
||||
// via MDN:
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
}
|
||||
|
||||
Override["java/lang/String.replace.(CC)Ljava/lang/String;"] = function(oldChar, newChar) {
|
||||
// Using a RegExp here to replace all matches of oldChar, rather than just the first.
|
||||
return J2ME.newString(this.str.replace(
|
||||
new RegExp(escapeRegExp(String.fromCharCode(oldChar)), "g"),
|
||||
String.fromCharCode(newChar)));
|
||||
};
|
||||
|
||||
Override["java/lang/String.toLowerCase.()Ljava/lang/String;"] = function() {
|
||||
return J2ME.newString(this.str.toLowerCase());
|
||||
};
|
||||
|
||||
Override["java/lang/String.toUpperCase.()Ljava/lang/String;"] = function() {
|
||||
return J2ME.newString(this.str.toUpperCase());
|
||||
};
|
||||
|
||||
Override["java/lang/String.trim.()Ljava/lang/String;"] = function() {
|
||||
// Java's String.trim() removes any character <= ASCII 32;
|
||||
// JavaScript's only removes a few whitespacey chars.
|
||||
var start = 0;
|
||||
var end = this.str.length;
|
||||
while (start < end && this.str.charCodeAt(start) <= 32) {
|
||||
start++;
|
||||
}
|
||||
while (start < end && this.str.charCodeAt(end - 1) <= 32) {
|
||||
end--;
|
||||
}
|
||||
|
||||
return J2ME.newString(this.str.substring(start, end));
|
||||
};
|
||||
|
||||
Override["java/lang/String.toString.()Ljava/lang/String;"] = function() {
|
||||
return this; // Note: returning "this" so that we keep the same object.
|
||||
};
|
||||
|
||||
Override["java/lang/String.toCharArray.()[C"] = function() {
|
||||
return util.stringToCharArray(this.str);
|
||||
};
|
||||
|
||||
//****************************************************************
|
||||
// String.valueOf() for various types
|
||||
|
||||
// NOTE: String.valueOf(Object) left in Java to avoid having to call
|
||||
// back into Java for Object.toString().
|
||||
|
||||
Override["java/lang/String.valueOf.([C)Ljava/lang/String;"] = function(chars) {
|
||||
if (!chars) {
|
||||
throw $.newNullPointerException();
|
||||
}
|
||||
return J2ME.newString(util.fromJavaChars(chars));
|
||||
};
|
||||
|
||||
Override["java/lang/String.valueOf.([CII)Ljava/lang/String;"] = function(chars, offset, count) {
|
||||
if (!chars) {
|
||||
throw $.newNullPointerException();
|
||||
}
|
||||
return J2ME.newString(util.fromJavaChars(chars, offset, count));
|
||||
};
|
||||
|
||||
Override["java/lang/String.valueOf.(Z)Ljava/lang/String;"] = function(bool) {
|
||||
return J2ME.newString(bool ? "true" : "false");
|
||||
};
|
||||
|
||||
Override["java/lang/String.valueOf.(C)Ljava/lang/String;"] = function(ch) {
|
||||
return J2ME.newString(String.fromCharCode(ch));
|
||||
};
|
||||
|
||||
Override["java/lang/String.valueOf.(I)Ljava/lang/String;"] = function(n) {
|
||||
return J2ME.newString(n.toString());
|
||||
};
|
||||
|
||||
Override["java/lang/String.valueOf.(J)Ljava/lang/String;"] = function(n) {
|
||||
return J2ME.newString(n.toString());
|
||||
};
|
||||
|
||||
|
||||
// String.valueOf(float) and String.valueOf(double) have been left in
|
||||
// Java for now, as they require support for complex formatting rules.
|
||||
// Additionally, their tests check for coverage of nuanced things like
|
||||
// positive zero vs. negative zero, which we don't currently support.
|
||||
|
||||
var internedStrings = J2ME.internedStrings;
|
||||
|
||||
Native["java/lang/String.intern.()Ljava/lang/String;"] = function() {
|
||||
var string = util.fromJavaString(this);
|
||||
|
||||
var internedString = internedStrings.get(string);
|
||||
|
||||
if (internedString) {
|
||||
return internedString;
|
||||
} else {
|
||||
internedStrings.set(string, this);
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//################################################################
|
||||
// java.lang.StringBuffer (manipulated via the 'buf' property)
|
||||
|
||||
Override["java/lang/StringBuffer.<init>.()V"] = function() {
|
||||
this.buf = new Uint16Array(16); // Initial buffer size: 16, per the Java implementation.
|
||||
this.count = 0;
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.<init>.(I)V"] = function(length) {
|
||||
if (length < 0) {
|
||||
throw $.newNegativeArraySizeException();
|
||||
}
|
||||
this.buf = new Uint16Array(length);
|
||||
this.count = 0;
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.<init>.(Ljava/lang/String;)V"] = function(jStr) {
|
||||
var stringBuf = util.stringToCharArray(jStr.str);
|
||||
this.buf = new Uint16Array(stringBuf.length + 16); // Add 16, per the Java implementation.
|
||||
this.buf.set(stringBuf, 0);
|
||||
this.count = stringBuf.length;
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.length.()I"] = function() {
|
||||
return this.count;
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.capacity.()I"] = function() {
|
||||
return this.buf.length;
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.copy.()V"] = function() {
|
||||
// We don't support copying (there's no need unless we also support shared buffers).
|
||||
};
|
||||
|
||||
/**
|
||||
* Expand capacity to max(minCapacity, (capacity + 1) * 2).
|
||||
*
|
||||
* @this StringBuffer
|
||||
* @param {number} minCapacity
|
||||
*/
|
||||
function expandCapacity(minCapacity) {
|
||||
var newCapacity = (this.buf.length + 1) << 1;
|
||||
if (minCapacity > newCapacity) {
|
||||
newCapacity = minCapacity;
|
||||
}
|
||||
|
||||
var oldBuf = this.buf;
|
||||
this.buf = new Uint16Array(newCapacity);
|
||||
this.buf.set(oldBuf, 0);
|
||||
}
|
||||
|
||||
Override["java/lang/StringBuffer.ensureCapacity.(I)V"] = function(minCapacity) {
|
||||
if (this.buf.length < minCapacity) {
|
||||
expandCapacity.call(this, minCapacity);
|
||||
}
|
||||
};
|
||||
|
||||
// StringBuffer.expandCapacity is private and not needed with these overrides.
|
||||
|
||||
Override["java/lang/StringBuffer.setLength.(I)V"] = function(newLength) {
|
||||
if (newLength < 0) {
|
||||
throw $.newStringIndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
if (newLength > this.buf.length) {
|
||||
expandCapacity.call(this, newLength);
|
||||
}
|
||||
for (; this.count < newLength; this.count++) {
|
||||
this.buf[this.count] = '\0';
|
||||
}
|
||||
this.count = newLength;
|
||||
};
|
||||
|
||||
|
||||
Override["java/lang/StringBuffer.charAt.(I)C"] = function(index) {
|
||||
if (index < 0 || index >= this.count) {
|
||||
throw $.newStringIndexOutOfBoundsException();
|
||||
}
|
||||
return this.buf[index];
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.getChars.(II[CI)V"] = function(srcBegin, srcEnd, dst, dstBegin) {
|
||||
if (srcBegin < 0 || srcEnd < 0 || srcEnd > this.count || srcBegin > srcEnd) {
|
||||
throw $.newStringIndexOutOfBoundsException();
|
||||
}
|
||||
if (dstBegin + (srcEnd - srcBegin) > dst.length || dstBegin < 0) {
|
||||
throw $.newArrayIndexOutOfBoundsException();
|
||||
}
|
||||
dst.set(this.buf.subarray(srcBegin, srcEnd), dstBegin);
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.setCharAt.(IC)V"] = function(index, ch) {
|
||||
if (index < 0 || index >= this.count) {
|
||||
throw $.newStringIndexOutOfBoundsException();
|
||||
}
|
||||
this.buf[index] = ch;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Append `data`, which should be either a JS String or a Uint16Array.
|
||||
* Data must not be null.
|
||||
*
|
||||
* @this StringBuffer
|
||||
* @param {Uint16Array|string} data
|
||||
* @return this
|
||||
*/
|
||||
function stringBufferAppend(data) {
|
||||
if (data == null) {
|
||||
throw $.newNullPointerException();
|
||||
}
|
||||
if (!(data instanceof Uint16Array)) {
|
||||
data = util.stringToCharArray(data);
|
||||
}
|
||||
if (this.buf.length < this.count + data.length) {
|
||||
expandCapacity.call(this, this.count + data.length);
|
||||
}
|
||||
this.buf.set(data, this.count);
|
||||
this.count += data.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
// StringBuffer.append(java.lang.Object) left in Java to avoid Object.toString().
|
||||
|
||||
Override["java/lang/StringBuffer.append.(Ljava/lang/String;)Ljava/lang/StringBuffer;"] = function(jStr) {
|
||||
return stringBufferAppend.call(this, jStr ? jStr.str : "null");
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.append.([C)Ljava/lang/StringBuffer;"] = function(chars) {
|
||||
if (chars == null) {
|
||||
throw $.newNullPointerException();
|
||||
}
|
||||
return stringBufferAppend.call(this, chars);
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.append.([CII)Ljava/lang/StringBuffer;"] = function(chars, offset, length) {
|
||||
if (chars == null) {
|
||||
throw $.newNullPointerException();
|
||||
}
|
||||
if (offset < 0 || offset + length > chars.length) {
|
||||
throw $.newArrayIndexOutOfBoundsException();
|
||||
}
|
||||
return stringBufferAppend.call(this, chars.subarray(offset, offset + length));
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.append.(Z)Ljava/lang/StringBuffer;"] = function(bool) {
|
||||
return stringBufferAppend.call(this, bool ? "true" : "false");
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.append.(C)Ljava/lang/StringBuffer;"] = function(ch) {
|
||||
if (this.buf.length < this.count + 1) {
|
||||
expandCapacity.call(this, this.count + 1);
|
||||
}
|
||||
this.buf[this.count++] = ch;
|
||||
return this;
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.append.(I)Ljava/lang/StringBuffer;"] = function(n) {
|
||||
return stringBufferAppend.call(this, n + "");
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.append.(J)Ljava/lang/StringBuffer;"] = function(n) {
|
||||
return stringBufferAppend.call(this, n + "");
|
||||
};
|
||||
|
||||
// StringBuffer.append(float) left in Java (see String.valueOf(float) above).
|
||||
|
||||
// StringBuffer.append(double) left in Java (see String.valueOf(double) above).
|
||||
|
||||
/**
|
||||
* Delete characters between [start, end).
|
||||
*
|
||||
* @this StringBuffer
|
||||
* @param {number} start
|
||||
* @param {number} end
|
||||
* @return this
|
||||
*/
|
||||
function stringBufferDelete(start, end) {
|
||||
if (start < 0) {
|
||||
throw $.newStringIndexOutOfBoundsException();
|
||||
}
|
||||
if (end > this.count) {
|
||||
end = this.count;
|
||||
}
|
||||
if (start > end) {
|
||||
throw $.newStringIndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
var len = end - start;
|
||||
if (len > 0) {
|
||||
// When Gecko 34 is released, we can use TypedArray.copyWithin() instead.
|
||||
this.buf.set(this.buf.subarray(end, this.count), start);
|
||||
this.count -= len;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Override["java/lang/StringBuffer.delete.(II)Ljava/lang/StringBuffer;"] = stringBufferDelete;
|
||||
|
||||
Override["java/lang/StringBuffer.deleteCharAt.(I)Ljava/lang/StringBuffer;"] = function(index) {
|
||||
if (index >= this.count) {
|
||||
// stringBufferDelete handles the other boundary checks; this check is specific to deleteCharAt.
|
||||
throw $.newStringIndexOutOfBoundsException();
|
||||
}
|
||||
return stringBufferDelete.call(this, index, index + 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert `data` at the given `offset`.
|
||||
*
|
||||
* @this StringBuffer
|
||||
* @param {number} offset
|
||||
* @param {Uint16Array|string} data
|
||||
* @return this
|
||||
*/
|
||||
function stringBufferInsert(offset, data) {
|
||||
if (data == null) {
|
||||
throw $.newNullPointerException();
|
||||
}
|
||||
if (offset < 0 || offset > this.count) {
|
||||
throw $.newArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (!(data instanceof Uint16Array)) {
|
||||
data = util.stringToCharArray(data);
|
||||
}
|
||||
if (this.buf.length < this.count + data.length) {
|
||||
expandCapacity.call(this, this.count + data.length);
|
||||
}
|
||||
// When Gecko 34 is released, we can use TypedArray.copyWithin() instead.
|
||||
this.buf.set(this.buf.subarray(offset, this.count), offset + data.length);
|
||||
this.buf.set(data, offset);
|
||||
this.count += data.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
// StringBuffer.insert(Object) left in Java (for String.valueOf()).
|
||||
|
||||
Override["java/lang/StringBuffer.insert.(ILjava/lang/String;)Ljava/lang/StringBuffer;"] = function(offset, jStr) {
|
||||
return stringBufferInsert.call(this, offset, jStr ? jStr.str : "null");
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.insert.(I[C)Ljava/lang/StringBuffer;"] = function(offset, chars) {
|
||||
return stringBufferInsert.call(this, offset, chars);
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.insert.(IZ)Ljava/lang/StringBuffer;"] = function(offset, bool) {
|
||||
return stringBufferInsert.call(this, offset, bool ? "true" : "false");
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.insert.(IC)Ljava/lang/StringBuffer;"] = function(offset, ch) {
|
||||
return stringBufferInsert.call(this, offset, String.fromCharCode(ch));
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.insert.(II)Ljava/lang/StringBuffer;"] = function(offset, n) {
|
||||
return stringBufferInsert.call(this, offset, n + "");
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.insert.(IJ)Ljava/lang/StringBuffer;"] = function(offset, n) {
|
||||
return stringBufferInsert.call(this, offset, n + "");
|
||||
};
|
||||
|
||||
// StringBuffer.insert(float) left in Java.
|
||||
|
||||
// StringBuffer.insert(double) left in Java.
|
||||
|
||||
Override["java/lang/StringBuffer.reverse.()Ljava/lang/StringBuffer;"] = function() {
|
||||
var buf = this.buf;
|
||||
for (var i = 0, j = this.count - 1; i < j; i++, j--) {
|
||||
var tmp = buf[i];
|
||||
buf[i] = buf[j];
|
||||
buf[j] = tmp;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.toString.()Ljava/lang/String;"] = function() {
|
||||
return J2ME.newString(util.fromJavaChars(this.buf, 0, this.count));
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.setShared.()V"] = function() {
|
||||
// Our StringBuffers are never shared. Everyone gets their very own!
|
||||
};
|
||||
|
||||
Override["java/lang/StringBuffer.getValue.()[C"] = function() {
|
||||
// In theory, this method should only be called by String (which
|
||||
// we've overridden to not do), so it should never be called. In any
|
||||
// case, mutating this buf would have the same effect here as it
|
||||
// would in Java.
|
||||
return this.buf;
|
||||
};
|
|
@ -1,61 +0,0 @@
|
|||
import java.lang.Object;
|
||||
import java.lang.System;
|
||||
import java.util.Vector;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
class JITBenchmark {
|
||||
|
||||
public static int size = 1024 * 256;
|
||||
|
||||
public static void createObjectArrays() {
|
||||
Object array = null;
|
||||
for (int i = 0; i < size; i++) {
|
||||
array = new Object[64];
|
||||
array = new Object[128];
|
||||
array = new Object[256];
|
||||
array = new Object[512];
|
||||
}
|
||||
}
|
||||
|
||||
public static void createPrimitiveArrays() {
|
||||
Object array = null;
|
||||
for (int i = 0; i < size; i++) {
|
||||
array = new int[64];
|
||||
array = new int[128];
|
||||
array = new int[256];
|
||||
array = new int[512];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void writeByteArrayOutputStream() {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < size * 8; i++) {
|
||||
stream.write(i);
|
||||
stream.write(i);
|
||||
stream.write(i);
|
||||
stream.write(i);
|
||||
}
|
||||
|
||||
System.out.println("Length: " + stream.size());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
long start = 0;
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
System.out.println("createObjectArrays: ...");
|
||||
// createObjectArrays();
|
||||
System.out.println("createObjectArrays: " + (System.currentTimeMillis() - start));
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
System.out.println("createPrimitiveArrays: ...");
|
||||
// createPrimitiveArrays();
|
||||
System.out.println("createPrimitiveArrays: " + (System.currentTimeMillis() - start));
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
System.out.println("writeByteArrayOutputStream: ...");
|
||||
writeByteArrayOutputStream();
|
||||
System.out.println("writeByteArrayOutputStream: " + (System.currentTimeMillis() - start));
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ PACKAGE_FILES = \
|
|||
javax/microedition/media/audio.3gp \
|
||||
javax/microedition/media/audio.amr \
|
||||
javax/microedition/media/hello.ogg \
|
||||
javax/microedition/media/test.webm \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(JSR_256),1)
|
||||
|
@ -44,6 +45,9 @@ all: tests.jar
|
|||
../java/classes.jar:
|
||||
cd ../java && make
|
||||
|
||||
javax/microedition/media/test.webm: gfx/images/red.png
|
||||
ffmpeg -loop 1 -i gfx/images/red.png -t 10 javax/microedition/media/test.webm
|
||||
|
||||
Testlets.java: $(SRCS) $(JASMIN_SRCS) Makefile
|
||||
echo "public class Testlets {" > $@
|
||||
echo " static String[] list = {" >> $@
|
||||
|
|
|
@ -67,6 +67,7 @@ var gfxTests = [
|
|||
{ name: "gfx/MediaImageTest", maxDifferent: 0 },
|
||||
{ name: "gfx/TextEditorGfxTest", maxDifferent: 1375 },
|
||||
{ name: "gfx/DrawStringWithCopyrightAndRegisteredSymbols", maxDifferent: 244 },
|
||||
{ name: "gfx/VideoPlayerTest", maxDifferent: 0 },
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -32,9 +32,9 @@ import gnu.testlet.Testlet;
|
|||
import java.io.*;
|
||||
|
||||
public class TestUtfReaders implements Testlet {
|
||||
public int getExpectedPass() { return 63; }
|
||||
public int getExpectedPass() { return 72; }
|
||||
public int getExpectedFail() { return 0; }
|
||||
public int getExpectedKnownFail() { return 3; }
|
||||
public int getExpectedKnownFail() { return 0; }
|
||||
TestHarness th;
|
||||
|
||||
public String teststr1 = "你好世界";
|
||||
|
@ -85,12 +85,8 @@ public class TestUtfReaders implements Testlet {
|
|||
|
||||
th.check(s, s2);
|
||||
} catch (Throwable t) {
|
||||
if (e.equals("UTF_8")) {
|
||||
th.todo(false, "Unexpected exception");
|
||||
} else {
|
||||
th.fail("Unexpected exception: " + t);
|
||||
t.printStackTrace();
|
||||
}
|
||||
th.fail("Unexpected exception: " + t);
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package gfx;
|
||||
|
||||
import javax.microedition.lcdui.*;
|
||||
import javax.microedition.midlet.*;
|
||||
import java.io.*;
|
||||
import javax.microedition.io.*;
|
||||
import javax.microedition.io.file.*;
|
||||
import javax.microedition.media.*;
|
||||
import javax.microedition.media.control.*;
|
||||
import gnu.testlet.TestUtils;
|
||||
|
||||
public class VideoPlayerTest extends MIDlet implements PlayerListener {
|
||||
private VideoControl videoControl;
|
||||
|
||||
class TestCanvas extends Canvas {
|
||||
protected void paint(Graphics g) {
|
||||
g.setColor(0x00FFFFFF);
|
||||
g.fillRect(0, 0, getWidth(), getHeight());
|
||||
|
||||
videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO, this);
|
||||
try {
|
||||
videoControl.setDisplayLocation(20, 20);
|
||||
videoControl.setDisplaySize(77, 42);
|
||||
} catch (MediaException me) {
|
||||
System.out.println("FAIL");
|
||||
}
|
||||
|
||||
videoControl.setVisible(true);
|
||||
|
||||
System.out.println("PAINTED");
|
||||
}
|
||||
}
|
||||
|
||||
public void startApp() {
|
||||
try {
|
||||
String dirPath = System.getProperty("fileconn.dir.private");
|
||||
FileConnection file = (FileConnection)Connector.open(dirPath + "test.webm", Connector.READ_WRITE);
|
||||
if (!file.exists()) {
|
||||
file.create();
|
||||
}
|
||||
OutputStream os = file.openDataOutputStream();
|
||||
InputStream is = getClass().getResourceAsStream("/javax/microedition/media/test.webm");
|
||||
os.write(TestUtils.read(is));
|
||||
os.close();
|
||||
|
||||
Player player = Manager.createPlayer(dirPath + "test.webm");
|
||||
|
||||
player.addPlayerListener(this);
|
||||
|
||||
player.realize();
|
||||
|
||||
videoControl = (VideoControl)player.getControl("VideoControl");
|
||||
|
||||
TestCanvas test = new TestCanvas();
|
||||
test.setFullScreenMode(true);
|
||||
Display.getDisplay(this).setCurrent(test);
|
||||
|
||||
player.start();
|
||||
|
||||
file.delete();
|
||||
file.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("FAIL - Unexpected exception: " + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void playerUpdate(Player player, String event, Object eventData) {
|
||||
}
|
||||
|
||||
public void pauseApp() {
|
||||
}
|
||||
|
||||
public void destroyApp(boolean unconditional) {
|
||||
}
|
||||
}
|
||||
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.0 KiB |
|
@ -0,0 +1,77 @@
|
|||
package javax.microedition.media;
|
||||
|
||||
import gnu.testlet.TestHarness;
|
||||
import gnu.testlet.Testlet;
|
||||
import gnu.testlet.TestUtils;
|
||||
import javax.microedition.lcdui.*;
|
||||
import javax.microedition.midlet.*;
|
||||
import java.io.*;
|
||||
import javax.microedition.io.*;
|
||||
import javax.microedition.io.file.*;
|
||||
import javax.microedition.media.*;
|
||||
import javax.microedition.media.control.*;
|
||||
|
||||
public class TestVideoPlayer implements Testlet, PlayerListener {
|
||||
public int getExpectedPass() { return 3; }
|
||||
public int getExpectedFail() { return 0; }
|
||||
public int getExpectedKnownFail() { return 0; }
|
||||
|
||||
boolean started = false;
|
||||
|
||||
public void test(TestHarness th) {
|
||||
try {
|
||||
Form form = new Form("Test");
|
||||
|
||||
String dirPath = System.getProperty("fileconn.dir.private");
|
||||
FileConnection file = (FileConnection)Connector.open(dirPath + "test.webm", Connector.READ_WRITE);
|
||||
if (!file.exists()) {
|
||||
file.create();
|
||||
}
|
||||
OutputStream os = file.openDataOutputStream();
|
||||
InputStream is = getClass().getResourceAsStream("/javax/microedition/media/test.webm");
|
||||
os.write(TestUtils.read(is));
|
||||
os.close();
|
||||
|
||||
Player player = Manager.createPlayer(dirPath + "test.webm");
|
||||
|
||||
player.addPlayerListener(this);
|
||||
|
||||
player.realize();
|
||||
|
||||
VideoControl videoControl = (VideoControl)player.getControl("VideoControl");
|
||||
|
||||
th.check(videoControl.getSourceHeight(), 42);
|
||||
th.check(videoControl.getSourceWidth(), 77);
|
||||
|
||||
Item videoItem = (Item)videoControl.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE, null);
|
||||
form.append(videoItem);
|
||||
|
||||
player.start();
|
||||
|
||||
synchronized (this) {
|
||||
while (!started) {
|
||||
this.wait();
|
||||
}
|
||||
}
|
||||
th.check(started);
|
||||
|
||||
player.close();
|
||||
|
||||
file.delete();
|
||||
file.close();
|
||||
} catch (Exception e) {
|
||||
th.fail("Unexpected exception: " + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void playerUpdate(Player player, String event, Object eventData) {
|
||||
if (event.equals("started")) {
|
||||
started = true;
|
||||
synchronized (this) {
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Двоичный файл не отображается.
|
@ -24,8 +24,10 @@ Native["gnu/testlet/vm/NativeTest.throwException.()V"] = function() {
|
|||
Native["gnu/testlet/vm/NativeTest.throwExceptionAfterPause.()V"] = function() {
|
||||
var ctx = $.ctx;
|
||||
asyncImpl("V", new Promise(function(resolve, reject) {
|
||||
ctx.setAsCurrentContext();
|
||||
setTimeout(reject.bind(null, $.newNullPointerException("An exception")), 100);
|
||||
setTimeout(function() {
|
||||
ctx.setAsCurrentContext();
|
||||
reject($.newNullPointerException("An exception"))
|
||||
}, 100);
|
||||
}));
|
||||
};
|
||||
|
||||
|
|
|
@ -67,7 +67,10 @@ module J2ME {
|
|||
"java/lang/StringBuffer",
|
||||
"java/util/Vector",
|
||||
"java/io/IOException",
|
||||
"java/lang/IllegalArgumentException"
|
||||
"java/lang/IllegalArgumentException",
|
||||
"java/lang/IndexOutOfBoundsException",
|
||||
"java/lang/StringIndexOutOfBoundsException",
|
||||
"org/mozilla/internal/Sys"
|
||||
];
|
||||
|
||||
for (var i = 0; i < classNames.length; i++) {
|
||||
|
|
|
@ -506,13 +506,13 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
|
||||
newStringConstant(s: string): java.lang.String {
|
||||
if (internedStrings.has(s)) {
|
||||
return internedStrings.get(s);
|
||||
newStringConstant(jsString: string): java.lang.String {
|
||||
if (internedStrings.has(jsString)) {
|
||||
return internedStrings.get(jsString);
|
||||
}
|
||||
var obj = J2ME.newString(s);
|
||||
internedStrings.set(s, obj);
|
||||
return obj;
|
||||
var javaString = J2ME.newString(jsString);
|
||||
internedStrings.set(jsString, javaString);
|
||||
return javaString;
|
||||
}
|
||||
|
||||
setStatic(field, value) {
|
||||
|
@ -1133,7 +1133,13 @@ module J2ME {
|
|||
switch (classInfo.className) {
|
||||
case "java/lang/Object": Klasses.java.lang.Object = klass; break;
|
||||
case "java/lang/Class" : Klasses.java.lang.Class = klass; break;
|
||||
case "java/lang/String": Klasses.java.lang.String = klass; break;
|
||||
case "java/lang/String": Klasses.java.lang.String = klass;
|
||||
Object.defineProperty(klass.prototype, "viewString", {
|
||||
get: function () {
|
||||
return fromJavaString(this);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "java/lang/Thread": Klasses.java.lang.Thread = klass; break;
|
||||
case "java/lang/Exception": Klasses.java.lang.Exception = klass; break;
|
||||
case "java/lang/IllegalArgumentException": Klasses.java.lang.IllegalArgumentException = klass; break;
|
||||
|
@ -1657,27 +1663,42 @@ module J2ME {
|
|||
return new klass();
|
||||
}
|
||||
|
||||
export function newString(str: string): java.lang.String {
|
||||
if (str === null || str === undefined) {
|
||||
export function newString(value: any): java.lang.String {
|
||||
if (value === null || value === undefined) {
|
||||
return null;
|
||||
}
|
||||
var jsString = String(value);
|
||||
var object = <java.lang.String>newObject(Klasses.java.lang.String);
|
||||
object.str = str;
|
||||
var array = new Uint16Array(jsString.length);
|
||||
var length = jsString.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
array[i] = jsString.charCodeAt(i);
|
||||
}
|
||||
object.value = array;
|
||||
object.count = length;
|
||||
// Cache JS string.
|
||||
object._value = jsString;
|
||||
object._count = length;
|
||||
object._offset = 0;
|
||||
return object;
|
||||
}
|
||||
|
||||
export function newStringConstant(str: string): java.lang.String {
|
||||
return $.newStringConstant(str);
|
||||
};
|
||||
export function newStringConstant(jsString: string): java.lang.String {
|
||||
return $.newStringConstant(jsString);
|
||||
}
|
||||
|
||||
export function newArray(klass: Klass, size: number) {
|
||||
if (size < 0) {
|
||||
throw $.newNegativeArraySizeException();
|
||||
throwNegativeArraySizeException();
|
||||
}
|
||||
var constructor: any = getArrayKlass(klass);
|
||||
return new constructor(size);
|
||||
}
|
||||
|
||||
export function throwNegativeArraySizeException() {
|
||||
throw $.newNegativeArraySizeException();
|
||||
}
|
||||
|
||||
export function newObjectArray(size: number): java.lang.Object[] {
|
||||
return newArray(Klasses.java.lang.Object, size);
|
||||
}
|
||||
|
@ -1733,22 +1754,31 @@ module J2ME {
|
|||
return "[" + value.klass.classInfo.className + hashcode + "]";
|
||||
}
|
||||
|
||||
export function fromJavaString(value: java.lang.String): string {
|
||||
if (!value) {
|
||||
export function fromJavaString(javaString: java.lang.String): string {
|
||||
if (!javaString) {
|
||||
return null;
|
||||
}
|
||||
return value.str;
|
||||
var o = javaString.offset;
|
||||
var c = javaString.count;
|
||||
if (javaString._value !== undefined && javaString._offset === o && javaString._count === c) {
|
||||
return javaString._value;
|
||||
}
|
||||
// Cache decoded string. The buffer is immutable, but I think that the offset or count can change.
|
||||
javaString._value = util.fromJavaChars(javaString.value, o, c);
|
||||
javaString._offset = o;
|
||||
javaString._count = c;
|
||||
return javaString._value;
|
||||
}
|
||||
|
||||
export function checkDivideByZero(value: number) {
|
||||
if (value === 0) {
|
||||
throw $.newArithmeticException("/ by zero");
|
||||
throwArithmeticException();
|
||||
}
|
||||
}
|
||||
|
||||
export function checkDivideByZeroLong(value: Long) {
|
||||
if (value.isZero()) {
|
||||
throw $.newArithmeticException("/ by zero");
|
||||
throwArithmeticException();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1765,6 +1795,14 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
|
||||
export function throwArrayIndexOutOfBoundsException(index: number) {
|
||||
throw $.newArrayIndexOutOfBoundsException(String(index));
|
||||
}
|
||||
|
||||
export function throwArithmeticException() {
|
||||
throw $.newArithmeticException("/ by zero");
|
||||
}
|
||||
|
||||
export function checkArrayStore(array: java.lang.Object, value: any) {
|
||||
var arrayKlass = array.klass;
|
||||
if (value && !isAssignableTo(value.klass, arrayKlass.elementKlass)) {
|
||||
|
@ -1889,6 +1927,9 @@ var CAS = J2ME.checkArrayStore;
|
|||
var ME = J2ME.monitorEnter;
|
||||
var MX = J2ME.monitorExit;
|
||||
var TE = J2ME.translateException;
|
||||
var TI = J2ME.throwArrayIndexOutOfBoundsException;
|
||||
var TA = J2ME.throwArithmeticException;
|
||||
var TN = J2ME.throwNegativeArraySizeException;
|
||||
|
||||
var PE = J2ME.preempt;
|
||||
var PS = 0; // Preemption samples.
|
||||
|
|
Загрузка…
Ссылка в новой задаче