зеркало из https://github.com/mozilla/pluotsorbet.git
1077 строки
40 KiB
JavaScript
1077 строки
40 KiB
JavaScript
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
|
|
|
|
'use strict';
|
|
|
|
(function(Native) {
|
|
Native.create("com/sun/midp/lcdui/DisplayDeviceContainer.getDisplayDevicesIds0.()[I", function() {
|
|
var ids = util.newPrimitiveArray("I", 1);
|
|
ids[0] = 1;
|
|
return ids;
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.getDisplayName0.(I)Ljava/lang/String;", function(id) {
|
|
return null;
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.isDisplayPrimary0.(I)Z", function(id) {
|
|
console.warn("DisplayDevice.isDisplayPrimary0.(I)Z not implemented (" + id + ")");
|
|
return true;
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.isbuildInDisplay0.(I)Z", function(id) {
|
|
return true;
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.getDisplayCapabilities0.(I)I", function(id) {
|
|
return 0x3ff;
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.isDisplayPenSupported0.(I)Z", function(id) {
|
|
return true;
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.isDisplayPenMotionSupported0.(I)Z", function(id) {
|
|
return true;
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.getReverseOrientation0.(I)Z", function(id) {
|
|
return false;
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.getScreenWidth0.(I)I", function(id) {
|
|
return MIDP.Context2D.canvas.width;
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.getScreenHeight0.(I)I", function(id) {
|
|
return MIDP.Context2D.canvas.height;
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.displayStateChanged0.(II)V", function(hardwareId, state) {
|
|
console.warn("DisplayDevice.displayStateChanged0.(II)V not implemented (" + hardwareId + ", " + state + ")");
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.setFullScreen0.(IIZ)V", function(hardwareId, displayId, mode) {
|
|
console.warn("DisplayDevice.setFullScreen0.(IIZ)V not implemented (" +
|
|
hardwareId + ", " + displayId + ", " + mode + ")");
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.gainedForeground0.(II)V", function(hardwareId, displayId) {
|
|
console.warn("DisplayDevice.gainedForeground0.(II)V not implemented (" + hardwareId + ", " + displayId + ")");
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDeviceAccess.vibrate0.(IZ)Z", function(displayId, on) {
|
|
return true;
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDeviceAccess.isBacklightSupported0.(I)Z", function(displayId) {
|
|
return true;
|
|
});
|
|
|
|
Native.create("com/sun/midp/lcdui/DisplayDevice.refresh0.(IIIIII)V", function(hardwareId, displayId, x1, y1, x2, y2) {
|
|
console.warn("DisplayDevice.refresh0.(IIIIII)V not implemented (" +
|
|
hardwareId + ", " + displayId + ", " + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ")");
|
|
});
|
|
|
|
function swapRB(pixel) {
|
|
return (pixel & 0xff00ff00) | ((pixel >> 16) & 0xff) | ((pixel & 0xff) << 16);
|
|
}
|
|
|
|
function swapRBAndSetAlpha(pixel) {
|
|
return swapRB(pixel) | 0xff000000;
|
|
}
|
|
|
|
/**
|
|
* Extract the image data from `context` and place it in `rgbData`.
|
|
*/
|
|
function contextToRgbData(context, rgbData, offset, scanlength, x, y, width, height, converterFunc) {
|
|
var pixels = new Uint32Array(context.getImageData(x, y, width, height).data.buffer);
|
|
|
|
var i = 0;
|
|
for (var y1 = y; y1 < y + height; y1++) {
|
|
for (var x1 = x; x1 < x + width; x1++) {
|
|
rgbData[offset + (x1 - x) + (y1 - y) * scanlength] = converterFunc(pixels[i++]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Insert `rgbData` into `context`.
|
|
*/
|
|
function rgbDataToContext(context, rgbData, offset, scanlength, converterFunc) {
|
|
var width = context.canvas.width;
|
|
var height = context.canvas.height;
|
|
var imageData = context.createImageData(width, height);
|
|
var pixels = new Uint32Array(imageData.data.buffer);
|
|
|
|
var i = 0;
|
|
for (var y = 0; y < height; ++y) {
|
|
var j = offset + y * scanlength;
|
|
|
|
for (var x = 0; x < width; ++x) {
|
|
pixels[i++] = converterFunc(rgbData[j++]);
|
|
}
|
|
}
|
|
|
|
context.putImageData(imageData, 0, 0);
|
|
}
|
|
|
|
function createContext2d(width, height) {
|
|
var canvas = document.createElement("canvas");
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
return canvas.getContext("2d");
|
|
}
|
|
|
|
function setImageData(imageData, width, height, data) {
|
|
imageData.class.getField("I.width.I").set(imageData, width);
|
|
imageData.class.getField("I.height.I").set(imageData, height);
|
|
imageData.nativeImageData = data;
|
|
}
|
|
|
|
/**
|
|
* Ensure the nativeImageData of the given image points to a
|
|
* Canvas Context2D, converting (and saving) it if necessary.
|
|
*
|
|
* @return {CanvasRenderingContext2D} context
|
|
*/
|
|
function convertNativeImageData(imageData) {
|
|
var data = imageData.nativeImageData;
|
|
|
|
if (!(data instanceof CanvasRenderingContext2D)) {
|
|
// Assume it's an image.
|
|
var context = createContext2d(data.width, data.height);
|
|
context.drawImage(data, 0, 0);
|
|
imageData.nativeImageData = data = context;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
Native.create("javax/microedition/lcdui/ImageDataFactory.createImmutableImageDecodeImage.(Ljavax/microedition/lcdui/ImageData;[BII)V",
|
|
function(imageData, bytes, offset, length) {
|
|
return new Promise(function(resolve, reject) {
|
|
var blob = new Blob([bytes.subarray(offset, offset + length)], { type: "image/png" });
|
|
var img = new Image();
|
|
img.src = URL.createObjectURL(blob);
|
|
img.onload = function() {
|
|
setImageData(imageData, img.naturalWidth, img.naturalHeight, img);
|
|
resolve();
|
|
}
|
|
img.onerror = function(e) {
|
|
reject(new JavaException("java/lang/IllegalArgumentException", "error decoding image"));
|
|
}
|
|
});
|
|
}, true);
|
|
|
|
Native.create("javax/microedition/lcdui/ImageDataFactory.createImmutableImageDataRegion.(Ljavax/microedition/lcdui/ImageData;Ljavax/microedition/lcdui/ImageData;IIIIIZ)V",
|
|
function(dataDest, dataSource, x, y, width, height, transform, isMutable) {
|
|
var context = createContext2d(width, height);
|
|
|
|
if (transform === TRANS_MIRROR || transform === TRANS_MIRROR_ROT180) {
|
|
context.scale(-1, 1);
|
|
} else if (transform === TRANS_MIRROR_ROT90 || transform === TRANS_MIRROR_ROT270) {
|
|
context.scale(1, -1);
|
|
} else if (transform === TRANS_ROT90 || transform === TRANS_MIRROR_ROT90) {
|
|
context.rotate(Math.PI / 2);
|
|
} else if (transform === TRANS_ROT180 || transform === TRANS_MIRROR_ROT180) {
|
|
context.rotate(Math.PI);
|
|
} else if (transform === TRANS_ROT270 || transform === TRANS_MIRROR_ROT270) {
|
|
context.rotate(1.5 * Math.PI);
|
|
}
|
|
|
|
context.drawImage(dataSource.nativeImageData, x, y, width, height, 0, 0, width, height);
|
|
|
|
setImageData(dataDest, width, height, context);
|
|
dataDest.class.getField("I.isMutable.Z").set(dataDest, isMutable);
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/ImageDataFactory.createMutableImageData.(Ljavax/microedition/lcdui/ImageData;II)V",
|
|
function(imageData, width, height) {
|
|
var context = createContext2d(width, height);
|
|
context.fillStyle = "rgb(255,255,255)"; // white
|
|
context.fillRect(0, 0, width, height);
|
|
setImageData(imageData, width, height, context);
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/ImageDataFactory.createImmutableImageDecodeRGBImage.(Ljavax/microedition/lcdui/ImageData;[IIIZ)V",
|
|
function(imageData, rgbData, width, height, processAlpha) {
|
|
var context = createContext2d(width, height);
|
|
rgbDataToContext(context, rgbData, 0, width, processAlpha ? swapRB : swapRBAndSetAlpha);
|
|
setImageData(imageData, width, height, context);
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/ImageData.getRGB.([IIIIIII)V", function(rgbData, offset, scanlength, x, y, width, height) {
|
|
contextToRgbData(convertNativeImageData(this), rgbData, offset, scanlength, x, y, width, height, swapRB);
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/DirectUtils.makeMutable.(Ljavax/microedition/lcdui/Image;)V", function(image) {
|
|
var imageData = image.class.getField("I.imageData.Ljavax/microedition/lcdui/ImageData;").get(image);
|
|
imageData.class.getField("I.isMutable.Z").set(imageData, 1);
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/DirectUtils.setPixels.(Ljavax/microedition/lcdui/Image;I)V", function(image, argb) {
|
|
var width = image.class.getField("I.width.I").get(image);
|
|
var height = image.class.getField("I.height.I").get(image);
|
|
var imageData = image.class.getField("I.imageData.Ljavax/microedition/lcdui/ImageData;").get(image);
|
|
|
|
var ctx = createContext2d(width, height);
|
|
setImageData(imageData, width, height, ctx);
|
|
|
|
var ctxImageData = ctx.createImageData(width, height);
|
|
var pixels = new Uint32Array(ctxImageData.data.buffer);
|
|
|
|
var color = swapRB(argb);
|
|
|
|
var i = 0;
|
|
for (var y = 0; y < height; ++y) {
|
|
for (var x = 0; x < width; ++x) {
|
|
pixels[i++] = color;
|
|
}
|
|
}
|
|
|
|
ctx.putImageData(ctxImageData, 0, 0);
|
|
});
|
|
|
|
var FACE_SYSTEM = 0;
|
|
var FACE_MONOSPACE = 32;
|
|
var FACE_PROPORTIONAL = 64;
|
|
var STYLE_PLAIN = 0;
|
|
var STYLE_BOLD = 1;
|
|
var STYLE_ITALIC = 2;
|
|
var STYLE_UNDERLINED = 4;
|
|
var SIZE_SMALL = 8;
|
|
var SIZE_MEDIUM = 0;
|
|
var SIZE_LARGE = 16;
|
|
|
|
Native.create("javax/microedition/lcdui/Font.init.(III)V", function(face, style, size) {
|
|
var defaultSize = Math.max(10, (MIDP.Context2D.canvas.height / 48) | 0);
|
|
if (size & SIZE_SMALL)
|
|
size = defaultSize / 1.25;
|
|
else if (size & SIZE_LARGE)
|
|
size = defaultSize * 1.25;
|
|
else
|
|
size = defaultSize;
|
|
size |= 0;
|
|
|
|
if (style & STYLE_BOLD)
|
|
style = "bold";
|
|
else if (style & STYLE_ITALIC)
|
|
style = "italic";
|
|
else
|
|
style = "";
|
|
|
|
if (face & FACE_MONOSPACE)
|
|
face = "monospace";
|
|
else if (face & FACE_PROPORTIONAL)
|
|
face = "sans-serif";
|
|
else
|
|
face = "Arial, Helvetica, sans-serif";
|
|
|
|
this.class.getField("I.baseline.I").set(this, (size/2)|0);
|
|
this.class.getField("I.height.I").set(this, (size * 1.3)|0);
|
|
this.css = style + " " + size + "pt " + face;
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Font.stringWidth.(Ljava/lang/String;)I", function(str) {
|
|
return withFont(this, MIDP.Context2D, util.fromJavaString(str));
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Font.charWidth.(C)I", function(char) {
|
|
return withFont(this, MIDP.Context2D, String.fromCharCode(char));
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Font.charsWidth.([CII)I", function(str, offset, len) {
|
|
return withFont(this, MIDP.Context2D, util.fromJavaChars(str).slice(offset, offset + len));
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Font.substringWidth.(Ljava/lang/String;II)I", function(str, offset, len) {
|
|
return withFont(this, MIDP.Context2D, util.fromJavaString(str).slice(offset, offset + len));
|
|
});
|
|
|
|
var HCENTER = 1;
|
|
var VCENTER = 2;
|
|
var LEFT = 4;
|
|
var RIGHT = 8;
|
|
var TOP = 16;
|
|
var BOTTOM = 32;
|
|
var BASELINE = 64;
|
|
|
|
function withGraphics(g, cb) {
|
|
var img = g.class.getField("I.img.Ljavax/microedition/lcdui/Image;").get(g),
|
|
c = null;
|
|
|
|
if (img === null) {
|
|
c = MIDP.Context2D;
|
|
} else {
|
|
var imgData = img.class.getField("I.imageData.Ljavax/microedition/lcdui/ImageData;").get(img),
|
|
c = imgData.nativeImageData;
|
|
}
|
|
cb(c);
|
|
}
|
|
|
|
function withClip(g, c, x, y, cb) {
|
|
var clipX1 = g.class.getField("I.clipX1.S").get(g),
|
|
clipY1 = g.class.getField("I.clipY1.S").get(g),
|
|
clipX2 = g.class.getField("I.clipX2.S").get(g),
|
|
clipY2 = g.class.getField("I.clipY2.S").get(g),
|
|
clipped = g.class.getField("I.clipped.Z").get(g),
|
|
transX = g.class.getField("I.transX.I").get(g),
|
|
transY = g.class.getField("I.transY.I").get(g);
|
|
c.save();
|
|
if (clipped) {
|
|
c.beginPath();
|
|
c.rect(clipX1, clipY1, clipX2 - clipX1, clipY2 - clipY1);
|
|
c.clip();
|
|
}
|
|
c.translate(transX, transY);
|
|
cb(x, y);
|
|
c.restore();
|
|
}
|
|
|
|
function withAnchor(g, c, anchor, x, y, w, h, cb) {
|
|
withClip(g, c, x, y, function(x, y) {
|
|
if (anchor & RIGHT)
|
|
x -= w;
|
|
if (anchor & HCENTER)
|
|
x -= (w/2)|0;
|
|
if (anchor & BOTTOM)
|
|
y -= h;
|
|
if (anchor & VCENTER)
|
|
y -= (h/2)|0;
|
|
cb(x, y);
|
|
});
|
|
}
|
|
|
|
function withFont(font, c, str) {
|
|
c.font = font.css;
|
|
return c.measureText(str).width | 0;
|
|
}
|
|
|
|
function withTextAnchor(g, c, anchor, x, y, str, cb) {
|
|
withClip(g, c, x, y, function(x, y) {
|
|
var w = withFont(g.class.getField("I.currentFont.Ljavax/microedition/lcdui/Font;").get(g), c, str);
|
|
c.textAlign = "left";
|
|
c.textBaseline = "top";
|
|
if (anchor & RIGHT)
|
|
x -= w;
|
|
if (anchor & HCENTER)
|
|
x -= (w/2)|0;
|
|
if (anchor & BOTTOM)
|
|
c.textBaseline = "bottom";
|
|
if (anchor & VCENTER)
|
|
c.textBaseline = "middle";
|
|
if (anchor & BASELINE)
|
|
c.textBaseline = "alphabetic";
|
|
cb(x, y, w);
|
|
});
|
|
}
|
|
|
|
function abgrIntToCSS(pixel) {
|
|
var a = (pixel >> 24) & 0xff;
|
|
var b = (pixel >> 16) & 0xff;
|
|
var g = (pixel >> 8) & 0xff;
|
|
var r = pixel & 0xff;
|
|
return "rgba(" + r + "," + g + "," + b + "," + (a/255) + ")";
|
|
};
|
|
|
|
function withPixel(g, c, cb) {
|
|
var pixel = g.class.getField("I.pixel.I").get(g);
|
|
c.save();
|
|
c.fillStyle = c.strokeStyle = abgrIntToCSS(pixel);
|
|
cb();
|
|
c.restore();
|
|
}
|
|
|
|
/**
|
|
* create the outline of an elliptical arc
|
|
* covering the specified rectangle.
|
|
* @param x the x-coordinate of the center of the ellipse.
|
|
* @param y y-coordinate of the center of the ellipse.
|
|
* @param rw the horizontal radius of the arc.
|
|
* @param rh the vertical radius of the arc.
|
|
* @param arcStart the beginning angle
|
|
* @param arcEnd the ending angle
|
|
* @param closed if true, draw a closed arc sector.
|
|
*/
|
|
function createEllipticalArc(c, x, y, rw, rh, arcStart, arcEnd, closed) {
|
|
c.save();
|
|
c.translate(x, y);
|
|
if (closed) {
|
|
c.moveTo(0, 0);
|
|
}
|
|
// draw circle arc which will be stretched into an oval arc
|
|
c.scale(1, rh / rw);
|
|
c.arc(0, 0, rw, arcStart, arcEnd, false);
|
|
if (closed) {
|
|
c.lineTo(0, 0);
|
|
}
|
|
c.restore();
|
|
}
|
|
|
|
/**
|
|
* Create a round rectangle path.
|
|
* @param x the x coordinate of the rectangle
|
|
* @param y the y coordinate of the rectangle
|
|
* @param width the width of the rectangle
|
|
* @param height the height of the rectangle
|
|
* @param arcWidth the horizontal diameter of the arc at the four corners
|
|
* @param arcHeight the vertical diameter of the arc at the four corners
|
|
*/
|
|
function createRoundRect(c, x, y, width, height, arcWidth, arcHeight) {
|
|
var rw = arcWidth / 2;
|
|
var rh = arcHeight / 2;
|
|
c.moveTo(x + rw, y);
|
|
c.lineTo(x + width - rw, y);
|
|
createEllipticalArc(c, x + width - rw, y + rh, rw, rh, 1.5 * Math.PI, 2 * Math.PI, false);
|
|
c.lineTo(x + width, y + height - rh);
|
|
createEllipticalArc(c, x + width - rw, y + height - rh, rw, rh, 0, 0.5 * Math.PI, false);
|
|
c.lineTo(x + rw, y + height);
|
|
createEllipticalArc(c, x + rw, y + height - rh, rw, rh, 0.5 * Math.PI, Math.PI, false);
|
|
c.lineTo(x, y + rh);
|
|
createEllipticalArc(c, x + rw, y + rh, rw, rh, Math.PI, 1.5 * Math.PI, false);
|
|
}
|
|
|
|
/**
|
|
* Like withPixel, but ignores alpha channel, setting the alpha value to 1.
|
|
* Useful when you suspect that the caller is specifying the alpha channel
|
|
* incorrectly, although we should actually figure out why that's happening.
|
|
*/
|
|
function withOpaquePixel(g, c, cb) {
|
|
var pixel = g.class.getField("I.pixel.I").get(g);
|
|
c.save();
|
|
var b = (pixel >> 16) & 0xff;
|
|
var g = (pixel >> 8) & 0xff;
|
|
var r = pixel & 0xff;
|
|
var style = "rgba(" + r + "," + g + "," + b + "," + 1 + ")";
|
|
c.fillStyle = c.strokeStyle = style;
|
|
cb();
|
|
c.restore();
|
|
}
|
|
|
|
function withSize(dx, dy, cb) {
|
|
if (!dx)
|
|
dx = 1;
|
|
if (!dy)
|
|
dy = 1;
|
|
cb(dx, dy);
|
|
}
|
|
|
|
function renderImage(graphics, image, x, y, anchor) {
|
|
var texture = image.class.getField("I.imageData.Ljavax/microedition/lcdui/ImageData;").get(image).nativeImageData;
|
|
|
|
if (!texture) {
|
|
console.warn("Graphics.render: image missing native data");
|
|
return;
|
|
}
|
|
|
|
if (texture instanceof CanvasRenderingContext2D) {
|
|
texture = texture.canvas; // Render the canvas, not the context.
|
|
}
|
|
|
|
withGraphics(graphics, function(c) {
|
|
withAnchor(graphics, c, anchor, x, y, texture.width, texture.height, function(x, y) {
|
|
c.drawImage(texture, x, y);
|
|
});
|
|
});
|
|
}
|
|
|
|
Override.create("com/sun/midp/chameleon/CGraphicsUtil.draw9pcsBackground.(Ljavax/microedition/lcdui/Graphics;IIII[Ljavax/microedition/lcdui/Image;)V",
|
|
function(g, x, y, w, h, image) {
|
|
if (image == null || image.length != 9) {
|
|
return;
|
|
}
|
|
|
|
var transX = g.class.getField("I.transX.I");
|
|
var transY = g.class.getField("I.transY.I");
|
|
|
|
transX.set(g, transX.get(g) + x);
|
|
transY.set(g, transY.get(g) + y);
|
|
|
|
// Top Border
|
|
var iW = image[1].class.getField("I.width.I").get(image[1]);
|
|
renderImage(g, image[0], 0, 0, LEFT | TOP);
|
|
w -= image[2].class.getField("I.width.I").get(image[2]);
|
|
for (var i = image[0].class.getField("I.width.I").get(image[0]); i < w; i += iW) {
|
|
renderImage(g, image[1], i, 0, LEFT | TOP);
|
|
}
|
|
w += image[2].class.getField("I.width.I").get(image[2]);
|
|
renderImage(g, image[2], w, 0, RIGHT | TOP);
|
|
|
|
// Tile middle rows
|
|
if (image[4] != null) {
|
|
iW = image[4].class.getField("I.width.I").get(image[4]);
|
|
}
|
|
var iH = image[3].class.getField("I.height.I").get(image[3]);
|
|
h -= image[6].class.getField("I.height.I").get(image[6]);
|
|
w -= image[5].class.getField("I.width.I").get(image[5]);
|
|
for (var i = image[0].class.getField("I.height.I").get(image[0]); i <= h; i += iH) {
|
|
renderImage(g, image[3], 0, i, LEFT | TOP);
|
|
for (var j = image[3].class.getField("I.width.I").get(image[3]); j <= w; j += iW) {
|
|
renderImage(g, image[4], j, i, LEFT | TOP);
|
|
}
|
|
renderImage(g, image[5], w + image[5].class.getField("I.width.I").get(image[5]), i,
|
|
RIGHT | TOP);
|
|
}
|
|
w += image[5].class.getField("I.width.I").get(image[5]);
|
|
h += image[6].class.getField("I.height.I").get(image[6]);
|
|
|
|
// Bottom border
|
|
iW = image[7].class.getField("I.width.I").get(image[7]);
|
|
renderImage(g, image[6], 0, h, LEFT | BOTTOM);
|
|
w -= image[8].class.getField("I.width.I").get(image[8]);
|
|
for (var i = image[6].class.getField("I.width.I").get(image[6]); i < w; i += iW) {
|
|
renderImage(g, image[7], i, h, LEFT | BOTTOM);
|
|
}
|
|
w += image[8].class.getField("I.width.I").get(image[8]);
|
|
renderImage(g, image[8], w, h, RIGHT | BOTTOM);
|
|
|
|
transX.set(g, transX.get(g) - x);
|
|
transY.set(g, transY.get(g) - y);
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.getDisplayColor.(I)I", function(color) {
|
|
return color;
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.getPixel.(IIZ)I", function(rgb, gray, isGray) {
|
|
return swapRB(rgb) | 0xff000000;
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/DirectGraphicsImp.setARGBColor.(I)V", function(rgba) {
|
|
var g = this.class.getField("I.graphics.Ljavax/microedition/lcdui/Graphics;").get(this);
|
|
var red = (rgba >> 16) & 0xff;
|
|
var green = (rgba >> 8) & 0xff;
|
|
var blue = rgba & 0xff;
|
|
g.class.getField("I.pixel.I").set(g, swapRB(rgba));
|
|
g.class.getField("I.rgbColor.I").set(g, rgba & 0x00ffffff);
|
|
// Conversion matches Graphics#grayVal(int, int, int).
|
|
g.class.getField("I.gray.I").set(g, (red * 76 + green * 150 + blue * 29) >> 8);
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/DirectGraphicsImp.getAlphaComponent.()I", function() {
|
|
var g = this.class.getField("I.graphics.Ljavax/microedition/lcdui/Graphics;").get(this);
|
|
var pixel = g.class.getField("I.pixel.I").get(g);
|
|
return (pixel >> 24) & 0xff;
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/DirectGraphicsImp.getPixels.([SIIIIIII)V",
|
|
function(pixels, offset, scanlength, x, y, width, height, format) {
|
|
if (pixels == null) {
|
|
throw new JavaException("java/lang/NullPointerException", "Pixels array is null");
|
|
}
|
|
|
|
var converterFunc = null;
|
|
if (format == 4444) { // TYPE_USHORT_4444_ARGB
|
|
converterFunc = function(rgba) {
|
|
var r = (rgba & 0xF0000000) >>> 20;
|
|
var g = (rgba & 0x00F00000) >> 16;
|
|
var b = (rgba & 0x0000F000) >> 12;
|
|
var a = (rgba & 0x000000F0) << 8;
|
|
return (a | r | g | b);
|
|
};
|
|
} else if (format == 565) { // TYPE_USHORT_565_RGB
|
|
converterFunc = function(rgba) {
|
|
var r = (rgba & 0xF8000000) >>> 16;
|
|
var g = (rgba & 0xFC0000) >>> 13;
|
|
var b = (rgba & 0xF800) >>> 11;
|
|
return (r | g | b);
|
|
};
|
|
} else {
|
|
throw new JavaException("java/lang/IllegalArgumentException", "Format unsupported");
|
|
}
|
|
|
|
var graphics = this.class.getField("I.graphics.Ljavax/microedition/lcdui/Graphics;").get(this);
|
|
var image = graphics.class.getField("I.img.Ljavax/microedition/lcdui/Image;").get(graphics);
|
|
var imageData = image.class.getField("I.imageData.Ljavax/microedition/lcdui/ImageData;").get(image);
|
|
|
|
contextToRgbData(convertNativeImageData(imageData), pixels, offset, scanlength, x, y, width, height, converterFunc);
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/DirectGraphicsImp.drawPixels.([SZIIIIIIII)V",
|
|
function(pixels, transparency, offset, scanlength, x, y, width, height, manipulation, format) {
|
|
if (pixels == null) {
|
|
throw new JavaException("java/lang/NullPointerException", "Pixels array is null");
|
|
}
|
|
|
|
var converterFunc = null;
|
|
if (format == 4444 && transparency && !manipulation) {
|
|
converterFunc = function(argb) {
|
|
var a = (argb & 0xF000) >>> 8;
|
|
var r = (argb & 0x0F00) << 20;
|
|
var g = (argb & 0x00F0) << 16;
|
|
var b = (argb & 0x000F) << 12;
|
|
return (r | g | b | a);
|
|
};
|
|
} else {
|
|
throw new JavaException("java/lang/IllegalArgumentException", "Format unsupported");
|
|
}
|
|
|
|
var graphics = this.class.getField("I.graphics.Ljavax/microedition/lcdui/Graphics;").get(this);
|
|
|
|
var context = createContext2d(width, height);
|
|
rgbDataToContext(context, pixels, offset, scanlength, converterFunc);
|
|
withGraphics(graphics, function(c) {
|
|
withClip(graphics, c, x, y, function(x, y) {
|
|
c.drawImage(context.canvas, x, y);
|
|
});
|
|
});
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.render.(Ljavax/microedition/lcdui/Image;III)Z", function(image, x, y, anchor) {
|
|
renderImage(this, image, x, y, anchor);
|
|
return true;
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.drawString.(Ljava/lang/String;III)V", function(jStr, x, y, anchor) {
|
|
var str = util.fromJavaString(jStr);
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withTextAnchor(g, c, anchor, x, y, str, function(x, y) {
|
|
withOpaquePixel(g, c, function() {
|
|
c.fillText(str, x, y);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.drawChars.([CIIIII)V", function(data, offset, len, x, y, anchor) {
|
|
var str = util.fromJavaChars(data, offset, len);
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withTextAnchor(g, c, anchor, x, y, str, function(x, y) {
|
|
withPixel(g, c, function() {
|
|
c.fillText(str, x, y);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.drawChar.(CIII)V", function(jChr, x, y, anchor) {
|
|
var chr = String.fromCharCode(jChr);
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withTextAnchor(g, c, anchor, x, y, chr, function(x, y) {
|
|
withPixel(g, c, function() {
|
|
c.fillText(chr, x, y);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.fillTriangle.(IIIIII)V", function(x1, y1, x2, y2, x3, y3) {
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withClip(g, c, x1, y1, function(x, y) {
|
|
withPixel(g, c, function() {
|
|
withSize(x2 - x1, y2 - y1, function(dx1, dy1) {
|
|
withSize(x3 - x1, y3 - y1, function(dx2, dy2) {
|
|
c.beginPath();
|
|
c.moveTo(x, y);
|
|
c.lineTo(x + dx1, y + dy1);
|
|
c.lineTo(x + dx2, y + dy2);
|
|
c.closePath();
|
|
c.fill();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.drawRect.(IIII)V", function(x, y, w, h) {
|
|
if (w < 0 || h < 0) {
|
|
return;
|
|
}
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withClip(g, c, x, y, function(x, y) {
|
|
withPixel(g, c, function() {
|
|
withSize(w, h, function(w, h) {
|
|
c.strokeRect(x, y, w, h);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.drawRoundRect.(IIIIII)V", function(x, y, w, h, arcWidth, arcHeight) {
|
|
if (w < 0 || h < 0) {
|
|
return;
|
|
}
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withClip(g, c, x, y, function(x, y) {
|
|
withPixel(g, c, function() {
|
|
withSize(w, h, function(w, h) {
|
|
c.beginPath();
|
|
createRoundRect(c, x, y, w, h, arcWidth, arcHeight);
|
|
c.stroke();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.fillRect.(IIII)V", function(x, y, w, h) {
|
|
if (w <= 0 || h <= 0) {
|
|
return;
|
|
}
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withClip(g, c, x, y, function(x, y) {
|
|
withPixel(g, c, function() {
|
|
withSize(w, h, function(w, h) {
|
|
c.fillRect(x, y, w, h);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.fillRoundRect.(IIIIII)V", function(x, y, w, h, arcWidth, arcHeight) {
|
|
if (w <= 0 || h <= 0) {
|
|
return;
|
|
}
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withClip(g, c, x, y, function(x, y) {
|
|
withPixel(g, c, function() {
|
|
withSize(w, h, function(w, h) {
|
|
c.beginPath();
|
|
createRoundRect(c, x, y, w, h, arcWidth, arcHeight);
|
|
c.fill();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.drawArc.(IIIIII)V", function(x, y, width, height, startAngle, arcAngle) {
|
|
if (width < 0 || height < 0) {
|
|
return;
|
|
}
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withPixel(g, c, function() {
|
|
var endRad = -startAngle * 0.0175;
|
|
var startRad = endRad - arcAngle * 0.0175;
|
|
c.beginPath();
|
|
createEllipticalArc(c, x, y, width / 2, height / 2, startRad, endRad, false);
|
|
c.stroke();
|
|
});
|
|
});
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.fillArc.(IIIIII)V", function(x, y, width, height, startAngle, arcAngle) {
|
|
if (width <= 0 || height <= 0) {
|
|
return;
|
|
}
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withPixel(g, c, function() {
|
|
var endRad = -startAngle * 0.0175;
|
|
var startRad = endRad - arcAngle * 0.0175;
|
|
c.beginPath();
|
|
c.moveTo(x, y);
|
|
createEllipticalArc(c, x, y, width / 2, height / 2, startRad, endRad, true);
|
|
c.moveTo(x, y);
|
|
c.fill();
|
|
});
|
|
});
|
|
});
|
|
|
|
var TRANS_NONE = 0;
|
|
var TRANS_MIRROR_ROT180 = 1;
|
|
var TRANS_MIRROR = 2;
|
|
var TRANS_ROT180 = 3;
|
|
var TRANS_MIRROR_ROT270 = 4;
|
|
var TRANS_ROT90 = 5;
|
|
var TRANS_ROT270 = 6;
|
|
var TRANS_MIRROR_ROT90 = 7;
|
|
|
|
Override.create("javax/microedition/lcdui/Graphics.drawRegion.(Ljavax/microedition/lcdui/Image;IIIIIIII)V",
|
|
function(image, sx, sy, sw, sh, transform, x, y, anchor) {
|
|
if (!image) {
|
|
throw new JavaException("java/lang/NullPointerException", "src image is null");
|
|
}
|
|
|
|
var imgData = image.class.getField("I.imageData.Ljavax/microedition/lcdui/ImageData;").get(image),
|
|
texture = imgData.nativeImageData;
|
|
|
|
if (texture instanceof CanvasRenderingContext2D) {
|
|
texture = texture.canvas; // Render the canvas, not the context.
|
|
}
|
|
|
|
var w = sw, h = sh;
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withAnchor(g, c, anchor, x, y, w, h, function(x, y) {
|
|
c.translate(x, y);
|
|
if (transform === TRANS_MIRROR || transform === TRANS_MIRROR_ROT180)
|
|
c.scale(-1, 1);
|
|
if (transform === TRANS_MIRROR_ROT90 || transform === TRANS_MIRROR_ROT270)
|
|
c.scale(1, -1);
|
|
if (transform === TRANS_ROT90 || transform === TRANS_MIRROR_ROT90)
|
|
c.rotate(Math.PI / 2);
|
|
if (transform === TRANS_ROT180 || transform === TRANS_MIRROR_ROT180)
|
|
c.rotate(Math.PI);
|
|
if (transform === TRANS_ROT270 || transform === TRANS_MIRROR_ROT270)
|
|
c.rotate(1.5 * Math.PI);
|
|
c.drawImage(texture, sx, sy, w, h, 0, 0, sw, sh);
|
|
});
|
|
});
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.drawLine.(IIII)V", function(x1, y1, x2, y2) {
|
|
var dx = x2 - x1, dy = y2 - y1;
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withClip(g, c, x1, y1, function(x, y) {
|
|
withSize(dx, dy, function(dx, dy) {
|
|
withPixel(g, c, function() {
|
|
var ctx = MIDP.Context2D;
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, y);
|
|
ctx.lineTo(x + dx, y + dy);
|
|
ctx.stroke();
|
|
ctx.closePath();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
Native.create("javax/microedition/lcdui/Graphics.drawRGB.([IIIIIIIZ)V",
|
|
function(rgbData, offset, scanlength, x, y, width, height, processAlpha) {
|
|
var context = createContext2d(width, height);
|
|
rgbDataToContext(context, rgbData, offset, scanlength, processAlpha ? swapRB : swapRBAndSetAlpha);
|
|
var g = this;
|
|
withGraphics(g, function(c) {
|
|
withClip(g, c, x, y, function(x, y) {
|
|
c.drawImage(context.canvas, x, y);
|
|
});
|
|
});
|
|
});
|
|
|
|
var textEditorId = 0,
|
|
textEditorResolve = null,
|
|
dirtyEditors = [];
|
|
|
|
function wakeTextEditorThread(id) {
|
|
dirtyEditors.push(id);
|
|
if (textEditorResolve) {
|
|
textEditorResolve();
|
|
textEditorResolve = null;
|
|
}
|
|
}
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.init.(Ljava/lang/String;IIII)I",
|
|
function(text, maxSize, constraints, width, height) {
|
|
if (constraints != 0) {
|
|
console.warn("TextEditor.constraints not implemented");
|
|
}
|
|
|
|
this.textEditorId = ++textEditorId;
|
|
this.textEditor = document.createElement("textarea");
|
|
this.visible = false;
|
|
this.focused = false;
|
|
this.backgroundColor = 0xFFFFFFFF | 0; // opaque white
|
|
this.foregroundColor = 0xFF000000 | 0; // opaque black
|
|
this.textEditor.style.border = "none";
|
|
this.textEditor.style.resize = "none";
|
|
this.textEditor.style.backgroundColor = abgrIntToCSS(this.backgroundColor);
|
|
this.textEditor.style.color = abgrIntToCSS(this.foregroundColor);
|
|
|
|
this.getCaretPosition = function() {
|
|
if (this.textEditor.parentNode) {
|
|
return this.textEditor.selectionStart;
|
|
}
|
|
if (this.caretPosition !== null) {
|
|
return this.caretPosition;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
this.setCaretPosition = function(index) {
|
|
if (this.textEditor.parentNode) {
|
|
this.textEditor.setSelectionRange(index, index);
|
|
} else {
|
|
this.caretPosition = index;
|
|
}
|
|
};
|
|
|
|
this.textEditor.value = util.fromJavaString(text);
|
|
this.setCaretPosition(this.textEditor.value.length);
|
|
|
|
this.textEditor.setAttribute("maxlength", maxSize);
|
|
this.textEditor.style.width = width + "px";
|
|
this.textEditor.style.height = height + "px";
|
|
this.textEditor.style.position = "absolute";
|
|
this.textEditor.style.visibility = "hidden";
|
|
this.textEditor.oninput = function(e) {
|
|
wakeTextEditorThread(this.textEditorId);
|
|
}.bind(this);
|
|
return textEditorId;
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/CanvasItem.attachNativeImpl.()V", function() {
|
|
document.getElementById("display").appendChild(this.textEditor);
|
|
if (this.caretPosition !== null) {
|
|
this.textEditor.setSelectionRange(this.caretPosition, this.caretPosition);
|
|
this.caretPosition = null;
|
|
}
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/CanvasItem.detachNativeImpl.()V", function() {
|
|
this.caretPosition = this.textEditor.selectionStart;
|
|
document.getElementById("display").removeChild(this.textEditor);
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/CanvasItem.setSize.(II)V", function(width, height) {
|
|
this.textEditor.style.width = width + "px";
|
|
this.textEditor.style.height = height + "px";
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/CanvasItem.setVisible.(Z)V", function(visible) {
|
|
if (visible && !this.visible) {
|
|
this.textEditor.style.visibility = "visible";
|
|
} else if (!visible && this.visible) {
|
|
this.textEditor.style.visibility = "hidden";
|
|
}
|
|
this.visible = visible;
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/CanvasItem.getWidth.()I", function() {
|
|
return parseInt(this.textEditor.style.width);
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/CanvasItem.getHeight.()I", function() {
|
|
return parseInt(this.textEditor.style.height);
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/CanvasItem.setPosition.(II)V", function(x, y) {
|
|
this.textEditor.style.left = x + "px";
|
|
this.textEditor.style.top = y + "px";
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/CanvasItem.getPositionX.()I", function() {
|
|
return parseInt(this.textEditor.style.left) || 0;
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/CanvasItem.getPositionY.()I", function() {
|
|
return parseInt(this.textEditor.style.top) || 0;
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/CanvasItem.isVisible.()Z", function() {
|
|
return this.visible;
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.setFocus.(Z)V", function(focused) {
|
|
if (focused && !this.focused) {
|
|
this.textEditor.focus();
|
|
} else if (!focused && this.focused) {
|
|
this.textEditor.blur();
|
|
}
|
|
this.focused = focused;
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.hasFocus.()Z", function() {
|
|
return this.focused;
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.setCaret.(I)V", function(index) {
|
|
this.setCaretPosition(index);
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.getCaretPosition.()I", function() {
|
|
return this.getCaretPosition();
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.getBackgroundColor.()I", function() {
|
|
return this.backgroundColor;
|
|
});
|
|
Native.create("com/nokia/mid/ui/TextEditor.getForegroundColor.()I", function() {
|
|
return this.foregroundColor;
|
|
});
|
|
Native.create("com/nokia/mid/ui/TextEditor.setBackgroundColor.(I)V", function(backgroundColor) {
|
|
this.backgroundColor = backgroundColor;
|
|
this.textEditor.style.backgroundColor = abgrIntToCSS(backgroundColor);
|
|
});
|
|
Native.create("com/nokia/mid/ui/TextEditor.setForegroundColor.(I)V", function(foregroundColor) {
|
|
this.foregroundColor = foregroundColor;
|
|
this.textEditor.style.color = abgrIntToCSS(foregroundColor);
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.getContent.()Ljava/lang/String;", function() {
|
|
return this.textEditor.value;
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.setContent.(Ljava/lang/String;)V", function(jStr) {
|
|
var str = util.fromJavaString(jStr);
|
|
this.textEditor.value = str;
|
|
this.setCaretPosition(str.length);
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.insert.(Ljava/lang/String;I)V", function(jStr, pos) {
|
|
var old = this.textEditor.value;
|
|
var str = util.fromJavaString(jStr);
|
|
this.textEditor.value = old.slice(0, pos) + str + old.slice(pos);
|
|
this.setCaretPosition(pos + str.length);
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.delete.(II)V", function(offset, length) {
|
|
var old = this.textEditor.value;
|
|
|
|
if (offset < 0 || offset > old.length || length < 0 || offset + length > old.length) {
|
|
throw new JavaException("java.lang.StringIndexOutOfBoundsException", "offset/length invalid");
|
|
}
|
|
|
|
this.textEditor.value = old.slice(0, offset) + old.slice(offset + length);
|
|
this.setCaretPosition(offset);
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.getMaxSize.()I", function() {
|
|
return parseInt(this.textEditor.getAttribute("maxlength"));
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.setMaxSize.(I)I", function(maxSize) {
|
|
if (this.textEditor.value.length > maxSize) {
|
|
this.textEditor.value = this.textEditor.value.substring(0, maxSize);
|
|
if (this.getCaretPosition() > maxSize) {
|
|
this.setCaretPosition(maxSize);
|
|
}
|
|
}
|
|
|
|
this.textEditor.setAttribute("maxlength", maxSize);
|
|
|
|
// The return value is the assigned size, which could be less than
|
|
// the size that was requested, although in this case we always set it
|
|
// to the requested size.
|
|
return maxSize;
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditor.size.()I", function() {
|
|
return this.textEditor.value.length;
|
|
});
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditorThread.sleep.()V", function() {
|
|
return new Promise(function(resolve, reject) {
|
|
if (!dirtyEditors.length) {
|
|
textEditorResolve = resolve;
|
|
} else {
|
|
resolve();
|
|
}
|
|
});
|
|
}, true);
|
|
|
|
Native.create("com/nokia/mid/ui/TextEditorThread.getNextDirtyEditor.()I", function() {
|
|
if (!dirtyEditors.length) {
|
|
console.error("ERROR: getNextDirtyEditor called but no dirty editors");
|
|
return 0;
|
|
}
|
|
|
|
return dirtyEditors.shift();
|
|
});
|
|
})(Native);
|