2011-06-23 20:09:36 +09:00
|
|
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
|
|
|
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
|
|
|
|
2011-07-06 15:06:45 +09:00
|
|
|
'use strict';
|
2011-06-22 17:40:51 +09:00
|
|
|
|
2011-06-22 21:02:54 +09:00
|
|
|
var JpegStreamProxyCounter = 0;
|
|
|
|
// WebWorker Proxy for JpegStream.
|
|
|
|
var JpegStreamProxy = (function() {
|
2011-06-23 05:54:16 +09:00
|
|
|
function constructor(bytes, dict) {
|
|
|
|
this.id = JpegStreamProxyCounter++;
|
|
|
|
this.dict = dict;
|
2011-06-22 21:02:54 +09:00
|
|
|
|
2011-06-23 05:54:16 +09:00
|
|
|
// Tell the main thread to create an image.
|
|
|
|
postMessage({
|
2011-07-06 15:06:45 +09:00
|
|
|
action: 'jpeg_stream',
|
2011-06-23 21:36:45 +09:00
|
|
|
data: {
|
|
|
|
id: this.id,
|
|
|
|
raw: bytesToString(bytes)
|
|
|
|
}
|
2011-06-23 05:54:16 +09:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
constructor.prototype = {
|
|
|
|
getImage: function() {
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
getChar: function() {
|
2011-07-06 15:06:45 +09:00
|
|
|
error('internal error: getChar is not valid on JpegStream');
|
2011-06-22 21:02:54 +09:00
|
|
|
}
|
2011-06-23 05:54:16 +09:00
|
|
|
};
|
2011-06-22 21:02:54 +09:00
|
|
|
|
2011-06-23 05:54:16 +09:00
|
|
|
return constructor;
|
2011-06-22 21:02:54 +09:00
|
|
|
})();
|
|
|
|
|
2011-06-22 21:25:21 +09:00
|
|
|
// Really simple GradientProxy. There is currently only one active gradient at
|
|
|
|
// the time, meaning you can't create a gradient, create a second one and then
|
|
|
|
// use the first one again. As this isn't used in pdf.js right now, it's okay.
|
2011-06-23 20:09:36 +09:00
|
|
|
function GradientProxy(cmdQueue, x0, y0, x1, y1) {
|
2011-07-06 15:06:45 +09:00
|
|
|
cmdQueue.push(['$createLinearGradient', [x0, y0, x1, y1]]);
|
2011-06-23 05:54:16 +09:00
|
|
|
this.addColorStop = function(i, rgba) {
|
2011-07-06 15:06:45 +09:00
|
|
|
cmdQueue.push(['$addColorStop', [i, rgba]]);
|
2011-06-23 05:54:16 +09:00
|
|
|
}
|
2011-06-22 21:25:21 +09:00
|
|
|
}
|
|
|
|
|
2011-06-23 05:54:16 +09:00
|
|
|
// Really simple PatternProxy.
|
2011-06-23 04:17:32 +09:00
|
|
|
var patternProxyCounter = 0;
|
2011-06-23 20:09:36 +09:00
|
|
|
function PatternProxy(cmdQueue, object, kind) {
|
2011-06-23 05:54:16 +09:00
|
|
|
this.id = patternProxyCounter++;
|
2011-06-23 04:17:32 +09:00
|
|
|
|
2011-07-06 15:06:45 +09:00
|
|
|
if (!(object instanceof CanvasProxy)) {
|
|
|
|
throw 'unkown type to createPattern';
|
2011-06-23 05:54:16 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
// Flush the object here to ensure it's available on the main thread.
|
|
|
|
// TODO: Make some kind of dependency management, such that the object
|
|
|
|
// gets flushed only if needed.
|
|
|
|
object.flush();
|
2011-07-06 15:06:45 +09:00
|
|
|
cmdQueue.push(['$createPatternFromCanvas', [this.id, object.id, kind]]);
|
2011-06-23 04:17:32 +09:00
|
|
|
}
|
|
|
|
|
2011-06-23 03:49:33 +09:00
|
|
|
var canvasProxyCounter = 0;
|
2011-06-22 06:33:11 +09:00
|
|
|
function CanvasProxy(width, height) {
|
2011-06-23 05:54:16 +09:00
|
|
|
this.id = canvasProxyCounter++;
|
2011-06-23 04:17:32 +09:00
|
|
|
|
2011-06-23 05:54:16 +09:00
|
|
|
// The `stack` holds the rendering calls and gets flushed to the main thead.
|
2011-06-23 20:09:36 +09:00
|
|
|
var cmdQueue = this.cmdQueue = [];
|
2011-06-22 21:25:21 +09:00
|
|
|
|
2011-06-23 05:54:16 +09:00
|
|
|
// Dummy context that gets exposed.
|
|
|
|
var ctx = {};
|
|
|
|
this.getContext = function(type) {
|
2011-07-06 15:06:45 +09:00
|
|
|
if (type != '2d') {
|
|
|
|
throw 'CanvasProxy can only provide a 2d context.';
|
2011-06-23 03:49:33 +09:00
|
|
|
}
|
2011-06-23 05:54:16 +09:00
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Expose only the minimum of the canvas object - there is no dom to do
|
|
|
|
// more here.
|
|
|
|
this.width = width;
|
|
|
|
this.height = height;
|
|
|
|
ctx.canvas = this;
|
|
|
|
|
|
|
|
// Setup function calls to `ctx`.
|
|
|
|
var ctxFunc = [
|
2011-07-06 15:06:45 +09:00
|
|
|
'createRadialGradient',
|
|
|
|
'arcTo',
|
|
|
|
'arc',
|
|
|
|
'fillText',
|
|
|
|
'strokeText',
|
|
|
|
'createImageData',
|
|
|
|
'drawWindow',
|
|
|
|
'save',
|
|
|
|
'restore',
|
|
|
|
'scale',
|
|
|
|
'rotate',
|
|
|
|
'translate',
|
|
|
|
'transform',
|
|
|
|
'setTransform',
|
|
|
|
'clearRect',
|
|
|
|
'fillRect',
|
|
|
|
'strokeRect',
|
|
|
|
'beginPath',
|
|
|
|
'closePath',
|
|
|
|
'moveTo',
|
|
|
|
'lineTo',
|
|
|
|
'quadraticCurveTo',
|
|
|
|
'bezierCurveTo',
|
|
|
|
'rect',
|
|
|
|
'fill',
|
|
|
|
'stroke',
|
|
|
|
'clip',
|
|
|
|
'measureText',
|
|
|
|
'isPointInPath',
|
2011-06-23 05:54:16 +09:00
|
|
|
|
|
|
|
// These functions are necessary to track the rendering currentX state.
|
|
|
|
// The exact values can be computed on the main thread only, as the
|
|
|
|
// worker has no idea about text width.
|
2011-07-06 15:06:45 +09:00
|
|
|
'$setCurrentX',
|
|
|
|
'$addCurrentX',
|
|
|
|
'$saveCurrentX',
|
|
|
|
'$restoreCurrentX',
|
|
|
|
'$showText',
|
|
|
|
'$setFont'
|
2011-06-23 05:54:16 +09:00
|
|
|
];
|
|
|
|
|
|
|
|
function buildFuncCall(name) {
|
|
|
|
return function() {
|
|
|
|
// console.log("funcCall", name)
|
2011-06-23 20:09:36 +09:00
|
|
|
cmdQueue.push([name, Array.prototype.slice.call(arguments)]);
|
2011-06-23 03:49:33 +09:00
|
|
|
}
|
2011-06-23 05:54:16 +09:00
|
|
|
}
|
|
|
|
var name;
|
|
|
|
for (var i = 0; i < ctxFunc.length; i++) {
|
|
|
|
name = ctxFunc[i];
|
|
|
|
ctx[name] = buildFuncCall(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Some function calls that need more work.
|
|
|
|
|
|
|
|
ctx.createPattern = function(object, kind) {
|
2011-06-23 20:09:36 +09:00
|
|
|
return new PatternProxy(cmdQueue, object, kind);
|
2011-06-23 05:54:16 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx.createLinearGradient = function(x0, y0, x1, y1) {
|
2011-06-23 20:09:36 +09:00
|
|
|
return new GradientProxy(cmdQueue, x0, y0, x1, y1);
|
2011-06-23 05:54:16 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2011-07-06 15:06:45 +09:00
|
|
|
cmdQueue.push(['$putImageData', [data, x, y, width, height]]);
|
2011-06-23 05:54:16 +09:00
|
|
|
}
|
|
|
|
|
2011-07-06 15:06:45 +09:00
|
|
|
ctx.drawImage = function(image, x, y, width, height,
|
|
|
|
sx, sy, swidth, sheight) {
|
2011-06-23 05:54:16 +09:00
|
|
|
if (image instanceof CanvasProxy) {
|
|
|
|
// Send the image/CanvasProxy to the main thread.
|
|
|
|
image.flush();
|
2011-07-06 15:06:45 +09:00
|
|
|
cmdQueue.push(['$drawCanvas', [image.id, x, y, sx, sy, swidth, sheight]]);
|
|
|
|
} else if (image instanceof JpegStreamProxy) {
|
|
|
|
cmdQueue.push(['$drawImage', [image.id, x, y, sx, sy, swidth, sheight]]);
|
2011-06-23 05:54:16 +09:00
|
|
|
} else {
|
2011-07-06 15:06:45 +09:00
|
|
|
throw 'unkown type to drawImage';
|
2011-06-22 06:33:11 +09:00
|
|
|
}
|
2011-06-23 05:54:16 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
// Setup property access to `ctx`.
|
|
|
|
var ctxProp = {
|
|
|
|
// "canvas"
|
2011-07-06 15:06:45 +09:00
|
|
|
'globalAlpha': '1',
|
|
|
|
'globalCompositeOperation': 'source-over',
|
|
|
|
'strokeStyle': '#000000',
|
|
|
|
'fillStyle': '#000000',
|
|
|
|
'lineWidth': '1',
|
|
|
|
'lineCap': 'butt',
|
|
|
|
'lineJoin': 'miter',
|
|
|
|
'miterLimit': '10',
|
|
|
|
'shadowOffsetX': '0',
|
|
|
|
'shadowOffsetY': '0',
|
|
|
|
'shadowBlur': '0',
|
|
|
|
'shadowColor': 'rgba(0, 0, 0, 0)',
|
|
|
|
'font': '10px sans-serif',
|
|
|
|
'textAlign': 'start',
|
|
|
|
'textBaseline': 'alphabetic',
|
|
|
|
'mozTextStyle': '10px sans-serif',
|
|
|
|
'mozImageSmoothingEnabled': 'true'
|
|
|
|
};
|
2011-06-23 05:54:16 +09:00
|
|
|
|
|
|
|
function buildGetter(name) {
|
|
|
|
return function() {
|
2011-07-06 15:06:45 +09:00
|
|
|
return ctx['$' + name];
|
2011-06-22 06:33:11 +09:00
|
|
|
}
|
2011-06-23 05:54:16 +09:00
|
|
|
}
|
2011-06-22 06:33:11 +09:00
|
|
|
|
2011-06-23 05:54:16 +09:00
|
|
|
function buildSetter(name) {
|
|
|
|
return function(value) {
|
2011-07-06 15:06:45 +09:00
|
|
|
cmdQueue.push(['$', name, value]);
|
|
|
|
return ctx['$' + name] = value;
|
2011-06-22 06:33:11 +09:00
|
|
|
}
|
2011-06-23 05:54:16 +09:00
|
|
|
}
|
2011-06-22 06:33:11 +09:00
|
|
|
|
2011-06-23 20:09:36 +09:00
|
|
|
// Setting the value to `stroke|fillStyle` needs special handling, as it
|
|
|
|
// might gets an gradient/pattern.
|
|
|
|
function buildSetterStyle(name) {
|
|
|
|
return function(value) {
|
|
|
|
if (value instanceof GradientProxy) {
|
2011-07-06 15:06:45 +09:00
|
|
|
cmdQueue.push(['$' + name + 'Gradient']);
|
2011-06-23 20:09:36 +09:00
|
|
|
} else if (value instanceof PatternProxy) {
|
2011-07-06 15:06:45 +09:00
|
|
|
cmdQueue.push(['$' + name + 'Pattern', [value.id]]);
|
2011-06-23 20:09:36 +09:00
|
|
|
} else {
|
2011-07-06 15:06:45 +09:00
|
|
|
cmdQueue.push(['$', name, value]);
|
|
|
|
return ctx['$' + name] = value;
|
2011-06-23 20:09:36 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-23 05:54:16 +09:00
|
|
|
for (var name in ctxProp) {
|
2011-07-06 15:06:45 +09:00
|
|
|
ctx['$' + name] = ctxProp[name];
|
2011-06-23 05:54:16 +09:00
|
|
|
ctx.__defineGetter__(name, buildGetter(name));
|
2011-06-22 06:33:11 +09:00
|
|
|
|
2011-06-23 05:54:16 +09:00
|
|
|
// Special treatment for `fillStyle` and `strokeStyle`: The passed style
|
|
|
|
// might be a gradient. Need to check for that.
|
2011-07-06 15:06:45 +09:00
|
|
|
if (name == 'fillStyle' || name == 'strokeStyle') {
|
2011-06-23 05:54:16 +09:00
|
|
|
ctx.__defineSetter__(name, buildSetterStyle(name));
|
|
|
|
} else {
|
|
|
|
ctx.__defineSetter__(name, buildSetter(name));
|
2011-06-22 06:33:11 +09:00
|
|
|
}
|
2011-06-23 05:54:16 +09:00
|
|
|
}
|
2011-06-22 06:33:11 +09:00
|
|
|
}
|
|
|
|
|
2011-06-23 05:54:16 +09:00
|
|
|
/**
|
2011-06-23 20:09:36 +09:00
|
|
|
* Sends the current cmdQueue of the CanvasProxy over to the main thread and
|
|
|
|
* resets the cmdQueue.
|
2011-06-23 05:54:16 +09:00
|
|
|
*/
|
2011-06-22 06:33:11 +09:00
|
|
|
CanvasProxy.prototype.flush = function() {
|
2011-06-23 05:54:16 +09:00
|
|
|
postMessage({
|
2011-07-06 15:06:45 +09:00
|
|
|
action: 'canvas_proxy_cmd_queue',
|
2011-06-23 20:25:59 +09:00
|
|
|
data: {
|
2011-07-06 15:06:45 +09:00
|
|
|
id: this.id,
|
|
|
|
cmdQueue: this.cmdQueue,
|
|
|
|
width: this.width,
|
|
|
|
height: this.height
|
2011-06-23 20:25:59 +09:00
|
|
|
}
|
2011-06-23 05:54:16 +09:00
|
|
|
});
|
2011-06-23 20:09:36 +09:00
|
|
|
this.cmdQueue.length = 0;
|
2011-07-06 15:06:45 +09:00
|
|
|
};
|