Merge ImageCanvasProxy and CanvasProxy. Add support for rendering multiple canvas objects on the worker and assemble them again on the main thread.

This commit is contained in:
Julian Viereck 2011-06-22 20:49:33 +02:00
parent c9c24ee5c3
commit 897ac256fc
3 changed files with 95 additions and 45 deletions

View File

@ -1,23 +1,23 @@
var ImageCanvasProxyCounter = 0; // var ImageCanvasProxyCounter = 0;
function ImageCanvasProxy(width, height) { // function ImageCanvasProxy(width, height) {
this.id = ImageCanvasProxyCounter++; // this.id = ImageCanvasProxyCounter++;
this.width = width; // this.width = width;
this.height = height; // this.height = height;
//
// Using `Uint8ClampedArray` seems to be the type of ImageData - at least // // Using `Uint8ClampedArray` seems to be the type of ImageData - at least
// Firebug tells me so. // // Firebug tells me so.
this.imgData = { // this.imgData = {
data: Uint8ClampedArray(width * height * 4) // data: Uint8ClampedArray(width * height * 4)
}; // };
} // }
//
ImageCanvasProxy.prototype.putImageData = function(imgData) { // ImageCanvasProxy.prototype.putImageData = function(imgData) {
// this.ctx.putImageData(imgData, 0, 0); // // this.ctx.putImageData(imgData, 0, 0);
} // }
//
ImageCanvasProxy.prototype.getCanvas = function() { // ImageCanvasProxy.prototype.getCanvas = function() {
return this; // return this;
} // }
var JpegStreamProxyCounter = 0; var JpegStreamProxyCounter = 0;
// WebWorker Proxy for JpegStream. // WebWorker Proxy for JpegStream.
@ -61,7 +61,10 @@ function GradientProxy(stack, x0, y0, x1, y1) {
} }
} }
var canvasProxyCounter = 0;
function CanvasProxy(width, height) { function CanvasProxy(width, height) {
this.id = canvasProxyCounter++;
var stack = this.$stack = []; var stack = this.$stack = [];
// Dummy context exposed. // Dummy context exposed.
@ -73,12 +76,15 @@ function CanvasProxy(width, height) {
return ctx; return ctx;
} }
this.getCanvas = function() {
return this;
}
// Expose only the minimum of the canvas object - there is no dom to do // Expose only the minimum of the canvas object - there is no dom to do
// more here. // more here.
ctx.canvas = { this.width = width;
width: width, this.height = height;
height: height ctx.canvas = this;
}
var ctxFunc = [ var ctxFunc = [
"createRadialGradient", "createRadialGradient",
@ -127,9 +133,23 @@ function CanvasProxy(width, height) {
return new GradientProxy(stack, x0, y0, x1, y1); return new GradientProxy(stack, x0, y0, x1, y1);
} }
ctx.getImageData = function(x, y, w, h) {
return {
width: w,
height: h,
data: Uint8ClampedArray(w * h * 4)
};
}
ctx.putImageData = function(data, x, y, width, height) {
stack.push(["$putImageData", [data, x, y, width, height]]);
}
ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) { ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) {
if (image instanceof ImageCanvasProxy) { if (image instanceof CanvasProxy) {
stack.push(["$drawCanvas", [image.imgData, x, y, image.width, image.height]]); // Send the image/CanvasProxy to the main thread.
image.flush();
stack.push(["$drawCanvas", [image.id, x, y, sx, sy, swidth, sheight]]);
} else if(image instanceof JpegStreamProxy) { } else if(image instanceof JpegStreamProxy) {
stack.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]]) stack.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]])
} else { } else {
@ -214,6 +234,11 @@ function CanvasProxy(width, height) {
CanvasProxy.prototype.flush = function() { CanvasProxy.prototype.flush = function() {
postMessage("canvas_proxy_stack"); postMessage("canvas_proxy_stack");
postMessage(this.$stack); postMessage({
id: this.id,
stack: this.$stack,
width: this.width,
height: this.height
});
this.$stack.length = 0; this.$stack.length = 0;
} }

View File

@ -13,7 +13,8 @@ function toc(msg) {
} }
var myWorker = new Worker('worker.js'); var myWorker = new Worker('worker.js');
var images = {}; var imagesList = {};
var canvasList = {};
var gradient; var gradient;
var currentX = 0; var currentX = 0;
@ -41,27 +42,40 @@ var special = {
currentX += this.measureText(text).width; currentX += this.measureText(text).width;
}, },
"$drawCanvas": function(data, x, y, width, height) { "$putImageData": function(imageData, x, y) {
// Ugly: getImageData is called here only to get an object of the right // Ugly: getImageData is called here only to get an object of the right
// shape - we are not interessted in the data, as we set it the line // shape - we are not interessted in the data, as we set it the line
// afterwards to something custome. // afterwards to something custome.
// Can we do better here? // Can we do better here?
var imgData = ctx.getImageData(0, 0, width, height); var imgData = this.getImageData(0, 0, imageData.width, imageData.height);
imgData.data = data; imgData.data = imageData.data;
ctx.putImageData(imgData, x, y); this.putImageData(imgData, x, y);
}, },
"$drawImage": function(id, x, y, sx, sy, swidth, sheight) { "$drawImage": function(id, x, y, sx, sy, swidth, sheight) {
var image = images[id]; var image = imagesList[id];
if (!image) { if (!image) {
throw "Image not found"; throw "Image not found";
} }
ctx.drawImage(image, x, y, image.width, image.height, this.drawImage(image, x, y, image.width, image.height,
sx, sy, swidth, sheight); sx, sy, swidth, sheight);
}, },
"$drawCanvas": function(id, x, y, sx, sy, swidth, sheight) {
var canvas = canvasList[id];
if (!canvas) {
throw "Canvas not found";
}
if (sheight != null) {
this.drawImage(canvas, x, y, canvas.width, canvas.height,
sx, sy, swidth, sheight);
} else {
this.drawImage(canvas, x, y, canvas.width, canvas.height);
}
},
"$createLinearGradient": function(x0, y0, x1, y1) { "$createLinearGradient": function(x0, y0, x1, y1) {
gradient = ctx.createLinearGradient(x0, y0, x1, y1); gradient = this.createLinearGradient(x0, y0, x1, y1);
}, },
"$addColorStop": function(i, rgba) { "$addColorStop": function(i, rgba) {
@ -69,16 +83,17 @@ var special = {
}, },
"$fillStyleGradient": function() { "$fillStyleGradient": function() {
ctx.fillStyle = gradient; this.fillStyle = gradient;
}, },
"$strokeStyleGradient": function() { "$strokeStyleGradient": function() {
ctx.strokeStyle = gradient; this.strokeStyle = gradient;
} }
} }
var gStack; var gStack;
function renderProxyCanvas(stack) { function renderProxyCanvas(canvas, stack) {
var ctx = canvas.getContext("2d");
for (var i = 0; i < stack.length; i++) { for (var i = 0; i < stack.length; i++) {
// for (var i = 0; i < 1000; i++) { // for (var i = 0; i < 1000; i++) {
var opp = stack[i]; var opp = stack[i];
@ -135,7 +150,7 @@ myWorker.onmessage = function(event) {
case JPEG_STREAM: case JPEG_STREAM:
var img = new Image(); var img = new Image();
img.src = "data:image/jpeg;base64," + window.btoa(data.str); img.src = "data:image/jpeg;base64," + window.btoa(data.str);
images[data.id] = img; imagesList[data.id] = img;
console.log("got image", data.id) console.log("got image", data.id)
break; break;
@ -171,16 +186,25 @@ myWorker.onmessage = function(event) {
break; break;
case CANVAS_PROXY_STACK: case CANVAS_PROXY_STACK:
var stack = data; var id = data.id;
var stack = data.stack;
gStack = stack; gStack = stack;
console.log("canvas stack size", stack.length)
// Check if there is already a canvas with the given id. If not,
// create a new canvas.
if (!canvasList[id]) {
var newCanvas = document.createElement("canvas");
newCanvas.width = data.width;
newCanvas.height = data.height;
canvasList[id] = newCanvas;
}
// There might be fonts that need to get loaded. Shedule the // There might be fonts that need to get loaded. Shedule the
// rendering at the end of the event queue ensures this. // rendering at the end of the event queue ensures this.
setTimeout(function() { setTimeout(function() {
tic(); if (id == 0) tic();
renderProxyCanvas(stack); renderProxyCanvas(canvasList[id], stack);
toc("canvas rendering") if (id == 0) toc("canvas rendering")
}, 0); }, 0);
onMessageState = WAIT; onMessageState = WAIT;
break; break;
@ -234,6 +258,7 @@ function prevPage() {
window.onload = function() { window.onload = function() {
window.canvas = document.getElementById("canvas"); window.canvas = document.getElementById("canvas");
window.ctx = canvas.getContext("2d"); window.ctx = canvas.getContext("2d");
canvasList[0] = window.canvas;
open("compressed.tracemonkey-pldi-09.pdf"); open("compressed.tracemonkey-pldi-09.pdf");
} }
</script> </script>

View File

@ -49,7 +49,7 @@ onmessage = function(event) {
// page.compile will collect all fonts for us, once we have loaded them // page.compile will collect all fonts for us, once we have loaded them
// we can trigger the actual page rendering with page.display // we can trigger the actual page rendering with page.display
var fonts = []; var fonts = [];
var gfx = new CanvasGraphics(canvas.getContext("2d"), ImageCanvasProxy); var gfx = new CanvasGraphics(canvas.getContext("2d"), CanvasProxy);
page.compile(gfx, fonts); page.compile(gfx, fonts);
// Inspect fonts and translate the missing one. // Inspect fonts and translate the missing one.