pdf.js/canvas_proxy.js

245 lines
6.7 KiB
JavaScript
Raw Normal View History

// var ImageCanvasProxyCounter = 0;
// function ImageCanvasProxy(width, height) {
// this.id = ImageCanvasProxyCounter++;
// this.width = width;
// this.height = height;
//
// // Using `Uint8ClampedArray` seems to be the type of ImageData - at least
// // Firebug tells me so.
// this.imgData = {
// data: Uint8ClampedArray(width * height * 4)
// };
// }
//
// ImageCanvasProxy.prototype.putImageData = function(imgData) {
// // this.ctx.putImageData(imgData, 0, 0);
// }
//
// ImageCanvasProxy.prototype.getCanvas = function() {
// return this;
// }
2011-06-22 17:40:51 +09:00
var JpegStreamProxyCounter = 0;
// WebWorker Proxy for JpegStream.
var JpegStreamProxy = (function() {
function constructor(bytes, dict) {
this.id = JpegStreamProxyCounter++;
this.dict = dict;
// create DOM image.
postMessage("jpeg_stream");
postMessage({
id: this.id,
str: bytesToString(bytes)
});
// var img = new Image();
// img.src = "data:image/jpeg;base64," + window.btoa(bytesToString(bytes));
// this.domImage = img;
}
constructor.prototype = {
getImage: function() {
return this;
// return this.domImage;
},
getChar: function() {
error("internal error: getChar is not valid on JpegStream");
}
};
return constructor;
})();
// 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.
function GradientProxy(stack, x0, y0, x1, y1) {
stack.push(["$createLinearGradient", [x0, y0, x1, y1]]);
this.addColorStop = function(i, rgba) {
stack.push(["$addColorStop", [i, rgba]]);
}
}
var canvasProxyCounter = 0;
2011-06-22 06:33:11 +09:00
function CanvasProxy(width, height) {
this.id = canvasProxyCounter++;
2011-06-22 06:33:11 +09:00
var stack = this.$stack = [];
// Dummy context exposed.
var ctx = {};
this.getContext = function(type) {
if (type != "2d") {
throw "CanvasProxy can only provide a 2d context.";
}
return ctx;
}
this.getCanvas = function() {
return this;
}
2011-06-22 06:33:11 +09:00
// 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;
2011-06-22 06:33:11 +09:00
var ctxFunc = [
"createRadialGradient",
"arcTo",
"arc",
"fillText",
"strokeText",
// "drawImage",
// "getImageData",
// "putImageData",
2011-06-22 06:33:11 +09:00
"createImageData",
"drawWindow",
"save",
"restore",
"scale",
"rotate",
"translate",
"transform",
"setTransform",
// "createLinearGradient",
2011-06-22 06:33:11 +09:00
"createPattern",
"clearRect",
"fillRect",
"strokeRect",
"beginPath",
"closePath",
"moveTo",
"lineTo",
"quadraticCurveTo",
"bezierCurveTo",
"rect",
"fill",
"stroke",
"clip",
"measureText",
"isPointInPath",
"$setCurrentX",
"$addCurrentX",
"$saveCurrentX",
"$restoreCurrentX",
"$showText"
2011-06-22 06:33:11 +09:00
];
ctx.createLinearGradient = function(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) {
if (image instanceof CanvasProxy) {
// 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) {
stack.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]])
2011-06-22 17:40:51 +09:00
} else {
throw "unkown type to drawImage";
}
}
2011-06-22 06:33:11 +09:00
function buildFuncCall(name) {
return function() {
// console.log("funcCall", name)
2011-06-22 06:33:11 +09:00
stack.push([name, Array.prototype.slice.call(arguments)]);
}
}
var name;
for (var i = 0; i < ctxFunc.length; i++) {
name = ctxFunc[i];
ctx[name] = buildFuncCall(name);
2011-06-22 06:33:11 +09:00
}
var ctxProp = {
// "canvas"
"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",
"DRAWWINDOW_DRAW_CARET": "1",
"DRAWWINDOW_DO_NOT_FLUSH": "2",
"DRAWWINDOW_DRAW_VIEW": "4",
"DRAWWINDOW_USE_WIDGET_LAYERS": "8",
"DRAWWINDOW_ASYNC_DECODE_IMAGES": "16",
}
function buildGetter(name) {
return function() {
return ctx["$" + name];
2011-06-22 06:33:11 +09:00
}
}
function buildSetter(name) {
return function(value) {
stack.push(["$", name, value]);
return ctx["$" + name] = value;
2011-06-22 06:33:11 +09:00
}
}
for (var name in ctxProp) {
ctx["$" + name] = ctxProp[name];
ctx.__defineGetter__(name, buildGetter(name));
// Special treatment for `fillStyle` and `strokeStyle`: The passed style
// might be a gradient. Need to check for that.
if (name == "fillStyle" || name == "strokeStyle") {
function buildSetterStyle(name) {
return function(value) {
if (value instanceof GradientProxy) {
stack.push(["$" + name + "Gradient"]);
} else {
stack.push(["$", name, value]);
return ctx["$" + name] = value;
}
}
}
ctx.__defineSetter__(name, buildSetterStyle(name));
} else {
ctx.__defineSetter__(name, buildSetter(name));
}
2011-06-22 06:33:11 +09:00
}
}
CanvasProxy.prototype.flush = function() {
postMessage("canvas_proxy_stack");
postMessage({
id: this.id,
stack: this.$stack,
width: this.width,
height: this.height
});
2011-06-22 06:33:11 +09:00
this.$stack.length = 0;
}