Move client code into worker_client.js. Cleanup + comments + 2-space-indention
This commit is contained in:
parent
5e02659eb7
commit
405c367ece
399
canvas_proxy.js
399
canvas_proxy.js
@ -1,260 +1,239 @@
|
|||||||
// 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;
|
|
||||||
// }
|
|
||||||
|
|
||||||
var JpegStreamProxyCounter = 0;
|
var JpegStreamProxyCounter = 0;
|
||||||
// WebWorker Proxy for JpegStream.
|
// WebWorker Proxy for JpegStream.
|
||||||
var JpegStreamProxy = (function() {
|
var JpegStreamProxy = (function() {
|
||||||
function constructor(bytes, dict) {
|
function constructor(bytes, dict) {
|
||||||
this.id = JpegStreamProxyCounter++;
|
this.id = JpegStreamProxyCounter++;
|
||||||
this.dict = dict;
|
this.dict = dict;
|
||||||
|
|
||||||
// create DOM image.
|
// Tell the main thread to create an image.
|
||||||
postMessage("jpeg_stream");
|
postMessage("jpeg_stream");
|
||||||
postMessage({
|
postMessage({
|
||||||
id: this.id,
|
id: this.id,
|
||||||
str: bytesToString(bytes)
|
str: bytesToString(bytes)
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// var img = new Image();
|
constructor.prototype = {
|
||||||
// img.src = "data:image/jpeg;base64," + window.btoa(bytesToString(bytes));
|
getImage: function() {
|
||||||
// this.domImage = img;
|
return this;
|
||||||
|
},
|
||||||
|
getChar: function() {
|
||||||
|
error("internal error: getChar is not valid on JpegStream");
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
constructor.prototype = {
|
return constructor;
|
||||||
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
|
// 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
|
// 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.
|
// 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) {
|
function GradientProxy(stack, x0, y0, x1, y1) {
|
||||||
stack.push(["$createLinearGradient", [x0, y0, x1, y1]]);
|
stack.push(["$createLinearGradient", [x0, y0, x1, y1]]);
|
||||||
this.addColorStop = function(i, rgba) {
|
this.addColorStop = function(i, rgba) {
|
||||||
stack.push(["$addColorStop", [i, rgba]]);
|
stack.push(["$addColorStop", [i, rgba]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Really simple PatternProxy.
|
||||||
var patternProxyCounter = 0;
|
var patternProxyCounter = 0;
|
||||||
function PatternProxy(stack, object, kind) {
|
function PatternProxy(stack, object, kind) {
|
||||||
this.id = patternProxyCounter++;
|
this.id = patternProxyCounter++;
|
||||||
|
|
||||||
if (!(object instanceof CanvasProxy) ) {
|
if (!(object instanceof CanvasProxy) ) {
|
||||||
throw "unkown type to createPattern";
|
throw "unkown type to createPattern";
|
||||||
}
|
}
|
||||||
// Flush the object here to ensure it's available on the main thread.
|
|
||||||
// TODO: Make some kind of dependency management, such that the object
|
// Flush the object here to ensure it's available on the main thread.
|
||||||
// gets flushed only if needed.
|
// TODO: Make some kind of dependency management, such that the object
|
||||||
object.flush();
|
// gets flushed only if needed.
|
||||||
stack.push(["$createPatternFromCanvas", [this.id, object.id, kind]]);
|
object.flush();
|
||||||
|
stack.push(["$createPatternFromCanvas", [this.id, object.id, kind]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var canvasProxyCounter = 0;
|
var canvasProxyCounter = 0;
|
||||||
function CanvasProxy(width, height) {
|
function CanvasProxy(width, height) {
|
||||||
this.id = canvasProxyCounter++;
|
this.id = canvasProxyCounter++;
|
||||||
|
|
||||||
var stack = this.$stack = [];
|
// The `stack` holds the rendering calls and gets flushed to the main thead.
|
||||||
|
var stack = this.$stack = [];
|
||||||
|
|
||||||
// Dummy context exposed.
|
// Dummy context that gets exposed.
|
||||||
var ctx = {};
|
var ctx = {};
|
||||||
this.getContext = function(type) {
|
this.getContext = function(type) {
|
||||||
if (type != "2d") {
|
if (type != "2d") {
|
||||||
throw "CanvasProxy can only provide a 2d context.";
|
throw "CanvasProxy can only provide a 2d context.";
|
||||||
}
|
|
||||||
return ctx;
|
|
||||||
}
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
ctx.canvas = this;
|
ctx.canvas = this;
|
||||||
|
|
||||||
var ctxFunc = [
|
// Setup function calls to `ctx`.
|
||||||
"createRadialGradient",
|
var ctxFunc = [
|
||||||
"arcTo",
|
"createRadialGradient",
|
||||||
"arc",
|
"arcTo",
|
||||||
"fillText",
|
"arc",
|
||||||
"strokeText",
|
"fillText",
|
||||||
// "drawImage",
|
"strokeText",
|
||||||
// "getImageData",
|
"createImageData",
|
||||||
// "putImageData",
|
"drawWindow",
|
||||||
"createImageData",
|
"save",
|
||||||
"drawWindow",
|
"restore",
|
||||||
"save",
|
"scale",
|
||||||
"restore",
|
"rotate",
|
||||||
"scale",
|
"translate",
|
||||||
"rotate",
|
"transform",
|
||||||
"translate",
|
"setTransform",
|
||||||
"transform",
|
"clearRect",
|
||||||
"setTransform",
|
"fillRect",
|
||||||
// "createLinearGradient",
|
"strokeRect",
|
||||||
// "createPattern",
|
"beginPath",
|
||||||
"clearRect",
|
"closePath",
|
||||||
"fillRect",
|
"moveTo",
|
||||||
"strokeRect",
|
"lineTo",
|
||||||
"beginPath",
|
"quadraticCurveTo",
|
||||||
"closePath",
|
"bezierCurveTo",
|
||||||
"moveTo",
|
"rect",
|
||||||
"lineTo",
|
"fill",
|
||||||
"quadraticCurveTo",
|
"stroke",
|
||||||
"bezierCurveTo",
|
"clip",
|
||||||
"rect",
|
"measureText",
|
||||||
"fill",
|
"isPointInPath",
|
||||||
"stroke",
|
|
||||||
"clip",
|
|
||||||
"measureText",
|
|
||||||
"isPointInPath",
|
|
||||||
|
|
||||||
"$setCurrentX",
|
// These functions are necessary to track the rendering currentX state.
|
||||||
"$addCurrentX",
|
// The exact values can be computed on the main thread only, as the
|
||||||
"$saveCurrentX",
|
// worker has no idea about text width.
|
||||||
"$restoreCurrentX",
|
"$setCurrentX",
|
||||||
"$showText"
|
"$addCurrentX",
|
||||||
];
|
"$saveCurrentX",
|
||||||
|
"$restoreCurrentX",
|
||||||
|
"$showText"
|
||||||
|
];
|
||||||
|
|
||||||
ctx.createPattern = function(object, kind) {
|
function buildFuncCall(name) {
|
||||||
return new PatternProxy(stack, object, kind);
|
return function() {
|
||||||
|
// console.log("funcCall", name)
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
ctx.createLinearGradient = function(x0, y0, x1, y1) {
|
// Some function calls that need more work.
|
||||||
return new GradientProxy(stack, x0, y0, x1, y1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.getImageData = function(x, y, w, h) {
|
ctx.createPattern = function(object, kind) {
|
||||||
return {
|
return new PatternProxy(stack, object, kind);
|
||||||
width: w,
|
}
|
||||||
height: h,
|
|
||||||
data: Uint8ClampedArray(w * h * 4)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.putImageData = function(data, x, y, width, height) {
|
ctx.createLinearGradient = function(x0, y0, x1, y1) {
|
||||||
stack.push(["$putImageData", [data, x, y, width, height]]);
|
return new GradientProxy(stack, x0, y0, x1, y1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) {
|
ctx.getImageData = function(x, y, w, h) {
|
||||||
if (image instanceof CanvasProxy) {
|
return {
|
||||||
// Send the image/CanvasProxy to the main thread.
|
width: w,
|
||||||
image.flush();
|
height: h,
|
||||||
stack.push(["$drawCanvas", [image.id, x, y, sx, sy, swidth, sheight]]);
|
data: Uint8ClampedArray(w * h * 4)
|
||||||
} else if(image instanceof JpegStreamProxy) {
|
};
|
||||||
stack.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]])
|
}
|
||||||
} else {
|
|
||||||
throw "unkown type to drawImage";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildFuncCall(name) {
|
ctx.putImageData = function(data, x, y, width, height) {
|
||||||
return function() {
|
stack.push(["$putImageData", [data, x, y, width, height]]);
|
||||||
// console.log("funcCall", name)
|
}
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
var ctxProp = {
|
ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) {
|
||||||
// "canvas"
|
if (image instanceof CanvasProxy) {
|
||||||
"globalAlpha": "1",
|
// Send the image/CanvasProxy to the main thread.
|
||||||
"globalCompositeOperation": "source-over",
|
image.flush();
|
||||||
"strokeStyle": "#000000",
|
stack.push(["$drawCanvas", [image.id, x, y, sx, sy, swidth, sheight]]);
|
||||||
"fillStyle": "#000000",
|
} else if(image instanceof JpegStreamProxy) {
|
||||||
"lineWidth": "1",
|
stack.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]])
|
||||||
"lineCap": "butt",
|
} else {
|
||||||
"lineJoin": "miter",
|
throw "unkown type to drawImage";
|
||||||
"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) {
|
// Setup property access to `ctx`.
|
||||||
return function() {
|
var ctxProp = {
|
||||||
return ctx["$" + name];
|
// "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"
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildGetter(name) {
|
||||||
|
return function() {
|
||||||
|
return ctx["$" + name];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function buildSetter(name) {
|
function buildSetter(name) {
|
||||||
|
return function(value) {
|
||||||
|
stack.push(["$", name, value]);
|
||||||
|
return ctx["$" + name] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
return function(value) {
|
||||||
|
if (value instanceof GradientProxy) {
|
||||||
|
stack.push(["$" + name + "Gradient"]);
|
||||||
|
} else if (value instanceof PatternProxy) {
|
||||||
|
stack.push(["$" + name + "Pattern", [value.id]]);
|
||||||
|
} else {
|
||||||
stack.push(["$", name, value]);
|
stack.push(["$", name, value]);
|
||||||
return ctx["$" + name] = value;
|
return ctx["$" + name] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
ctx.__defineSetter__(name, buildSetterStyle(name));
|
||||||
|
} else {
|
||||||
|
ctx.__defineSetter__(name, buildSetter(name));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
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 if (value instanceof PatternProxy) {
|
|
||||||
stack.push(["$" + name + "Pattern", [value.id]]);
|
|
||||||
} else {
|
|
||||||
stack.push(["$", name, value]);
|
|
||||||
return ctx["$" + name] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.__defineSetter__(name, buildSetterStyle(name));
|
|
||||||
} else {
|
|
||||||
ctx.__defineSetter__(name, buildSetter(name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the current stack of the CanvasProxy over to the main thread and
|
||||||
|
* resets the stack.
|
||||||
|
*/
|
||||||
CanvasProxy.prototype.flush = function() {
|
CanvasProxy.prototype.flush = function() {
|
||||||
postMessage("canvas_proxy_stack");
|
postMessage("canvas_proxy_stack");
|
||||||
postMessage({
|
postMessage({
|
||||||
id: this.id,
|
id: this.id,
|
||||||
stack: this.$stack,
|
stack: this.$stack,
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height
|
height: this.height
|
||||||
});
|
});
|
||||||
this.$stack.length = 0;
|
this.$stack.length = 0;
|
||||||
}
|
}
|
||||||
|
@ -1,295 +1,22 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Simple pdf.js page viewer worker</title>
|
<title>Simple pdf.js page viewer worker</title>
|
||||||
|
<script type="text/javascript" src="worker_client.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
var timer = null
|
|
||||||
function tic() {
|
|
||||||
timer = Date.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
function toc(msg) {
|
|
||||||
console.log(msg + ": " + (Date.now() - timer) + "ms");
|
|
||||||
}
|
|
||||||
|
|
||||||
var myWorker = new Worker('worker.js');
|
|
||||||
var imagesList = {};
|
|
||||||
var canvasList = {};
|
|
||||||
var patternList = {};
|
|
||||||
var gradient;
|
|
||||||
|
|
||||||
var currentX = 0;
|
|
||||||
var currentXStack = [];
|
|
||||||
var special = {
|
|
||||||
"$setCurrentX": function(value) {
|
|
||||||
currentX = value;
|
|
||||||
},
|
|
||||||
|
|
||||||
"$addCurrentX": function(value) {
|
|
||||||
currentX += value;
|
|
||||||
},
|
|
||||||
|
|
||||||
"$saveCurrentX": function() {
|
|
||||||
currentXStack.push(currentX);
|
|
||||||
},
|
|
||||||
|
|
||||||
"$restoreCurrentX": function() {
|
|
||||||
currentX = currentXStack.pop();
|
|
||||||
},
|
|
||||||
|
|
||||||
"$showText": function(y, text, uniText) {
|
|
||||||
this.translate(currentX, -1 * y);
|
|
||||||
this.fillText(uniText, 0, 0);
|
|
||||||
currentX += this.measureText(text).width;
|
|
||||||
},
|
|
||||||
|
|
||||||
"$putImageData": function(imageData, x, y) {
|
|
||||||
var imgData = this.getImageData(0, 0, imageData.width, imageData.height);
|
|
||||||
|
|
||||||
// Store the .data property to avaid property lookups.
|
|
||||||
var imageRealData = imageData.data;
|
|
||||||
var imgRealData = imgData.data;
|
|
||||||
|
|
||||||
// Copy over the imageData.
|
|
||||||
var len = imageRealData.length;
|
|
||||||
while (len--)
|
|
||||||
imgRealData[len] = imageRealData[len]
|
|
||||||
|
|
||||||
this.putImageData(imgData, x, y);
|
|
||||||
},
|
|
||||||
|
|
||||||
"$drawImage": function(id, x, y, sx, sy, swidth, sheight) {
|
|
||||||
var image = imagesList[id];
|
|
||||||
if (!image) {
|
|
||||||
throw "Image not found";
|
|
||||||
}
|
|
||||||
this.drawImage(image, x, y, image.width, image.height,
|
|
||||||
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) {
|
|
||||||
gradient = this.createLinearGradient(x0, y0, x1, y1);
|
|
||||||
},
|
|
||||||
|
|
||||||
"$createPatternFromCanvas": function(patternId, canvasId, kind) {
|
|
||||||
var canvas = canvasList[canvasId];
|
|
||||||
if (!canvas) {
|
|
||||||
throw "Canvas not found";
|
|
||||||
}
|
|
||||||
patternList[patternId] = this.createPattern(canvas, kind);
|
|
||||||
},
|
|
||||||
|
|
||||||
"$addColorStop": function(i, rgba) {
|
|
||||||
gradient.addColorStop(i, rgba);
|
|
||||||
},
|
|
||||||
|
|
||||||
"$fillStyleGradient": function() {
|
|
||||||
this.fillStyle = gradient;
|
|
||||||
},
|
|
||||||
|
|
||||||
"$fillStylePattern": function(id) {
|
|
||||||
var pattern = patternList[id];
|
|
||||||
if (!pattern) {
|
|
||||||
throw "Pattern not found";
|
|
||||||
}
|
|
||||||
this.fillStyle = pattern;
|
|
||||||
},
|
|
||||||
|
|
||||||
"$strokeStyleGradient": function() {
|
|
||||||
this.strokeStyle = gradient;
|
|
||||||
},
|
|
||||||
|
|
||||||
"$strokeStylePattern": function(id) {
|
|
||||||
var pattern = patternList[id];
|
|
||||||
if (!pattern) {
|
|
||||||
throw "Pattern not found";
|
|
||||||
}
|
|
||||||
this.strokeStyle = pattern;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var gStack;
|
|
||||||
function renderProxyCanvas(canvas, stack) {
|
|
||||||
var ctx = canvas.getContext("2d");
|
|
||||||
for (var i = 0; i < stack.length; i++) {
|
|
||||||
// for (var i = 0; i < 1000; i++) {
|
|
||||||
var opp = stack[i];
|
|
||||||
if (opp[0] == "$") {
|
|
||||||
ctx[opp[1]] = opp[2];
|
|
||||||
} else if (opp[0] in special) {
|
|
||||||
special[opp[0]].apply(ctx, opp[1]);
|
|
||||||
} else {
|
|
||||||
ctx[opp[0]].apply(ctx, opp[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const WAIT = 0;
|
|
||||||
const CANVAS_PROXY_STACK = 1;
|
|
||||||
const LOG = 2;
|
|
||||||
const FONT = 3;
|
|
||||||
const PDF_NUM_PAGE = 4;
|
|
||||||
const JPEG_STREAM = 5;
|
|
||||||
|
|
||||||
var onMessageState = WAIT;
|
|
||||||
var fontStr = null;
|
|
||||||
var first = true;
|
|
||||||
var intervals = [];
|
|
||||||
myWorker.onmessage = function(event) {
|
|
||||||
var data = event.data;
|
|
||||||
// console.log("onMessageRaw", data);
|
|
||||||
switch (onMessageState) {
|
|
||||||
case WAIT:
|
|
||||||
if (typeof data != "string") {
|
|
||||||
throw "expecting to get an string";
|
|
||||||
}
|
|
||||||
switch (data) {
|
|
||||||
case "pdf_num_page":
|
|
||||||
onMessageState = PDF_NUM_PAGE;
|
|
||||||
return;
|
|
||||||
case "log":
|
|
||||||
onMessageState = LOG;
|
|
||||||
return;
|
|
||||||
case "canvas_proxy_stack":
|
|
||||||
onMessageState = CANVAS_PROXY_STACK;
|
|
||||||
return;
|
|
||||||
case "font":
|
|
||||||
onMessageState = FONT;
|
|
||||||
return;
|
|
||||||
case "jpeg_stream":
|
|
||||||
onMessageState = JPEG_STREAM;
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
throw "unkown state: " + data
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JPEG_STREAM:
|
|
||||||
var img = new Image();
|
|
||||||
img.src = "data:image/jpeg;base64," + window.btoa(data.str);
|
|
||||||
imagesList[data.id] = img;
|
|
||||||
console.log("got image", data.id)
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PDF_NUM_PAGE:
|
|
||||||
console.log(data);
|
|
||||||
maxPages = parseInt(data);
|
|
||||||
document.getElementById("numPages").innerHTML = "/" + data;
|
|
||||||
onMessageState = WAIT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FONT:
|
|
||||||
data = JSON.parse(data);
|
|
||||||
var base64 = window.btoa(data.str);
|
|
||||||
|
|
||||||
// Add the @font-face rule to the document
|
|
||||||
var url = "url(data:" + data.mimetype + ";base64," + base64 + ");";
|
|
||||||
var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}";
|
|
||||||
var styleSheet = document.styleSheets[0];
|
|
||||||
styleSheet.insertRule(rule, styleSheet.length);
|
|
||||||
|
|
||||||
// Just adding the font-face to the DOM doesn't make it load. It
|
|
||||||
// seems it's loaded once Gecko notices it's used. Therefore,
|
|
||||||
// add a div on the page using the loaded font.
|
|
||||||
document.getElementById("fonts").innerHTML += "<div style='font-family:" + data.fontName + "'>j</div>";
|
|
||||||
console.log("setup font", data.fontName);
|
|
||||||
|
|
||||||
onMessageState = WAIT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LOG:
|
|
||||||
console.log.apply(console, JSON.parse(data));
|
|
||||||
onMessageState = WAIT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CANVAS_PROXY_STACK:
|
|
||||||
var id = data.id;
|
|
||||||
var stack = data.stack;
|
|
||||||
gStack = stack;
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// rendering at the end of the event queue ensures this.
|
|
||||||
setTimeout(function() {
|
|
||||||
if (id == 0) tic();
|
|
||||||
renderProxyCanvas(canvasList[id], stack);
|
|
||||||
if (id == 0) toc("canvas rendering")
|
|
||||||
}, 0);
|
|
||||||
onMessageState = WAIT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// myWorker.postMessage(array);
|
|
||||||
|
|
||||||
var currentPage = 1;
|
|
||||||
var maxPages = 1;
|
|
||||||
function showPage(num) {
|
|
||||||
ctx.save();
|
|
||||||
ctx.fillStyle = "rgb(255, 255, 255)";
|
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
||||||
ctx.restore();
|
|
||||||
console.log("worker: page=" + num)
|
|
||||||
document.getElementById('pageNumber').value = num;
|
|
||||||
currentPage = parseInt(num);
|
|
||||||
myWorker.postMessage(num);
|
|
||||||
}
|
|
||||||
|
|
||||||
function open(url) {
|
|
||||||
document.title = url;
|
|
||||||
var req = new XMLHttpRequest();
|
|
||||||
req.open("GET", url);
|
|
||||||
req.mozResponseType = req.responseType = "arraybuffer";
|
|
||||||
req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200;
|
|
||||||
req.onreadystatechange = function() {
|
|
||||||
if (req.readyState == 4 && req.status == req.expected) {
|
|
||||||
var data = req.mozResponseArrayBuffer || req.mozResponse ||
|
|
||||||
req.responseArrayBuffer || req.response;
|
|
||||||
myWorker.postMessage(data);
|
|
||||||
showPage("2");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
req.send(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextPage() {
|
|
||||||
if (currentPage == maxPages) return;
|
|
||||||
currentPage++;
|
|
||||||
showPage(currentPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
function prevPage() {
|
|
||||||
if (currentPage == 1) return;
|
|
||||||
currentPage--;
|
|
||||||
showPage(currentPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var pdfDoc;
|
||||||
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");
|
pdfDoc = new WorkerPDFDoc(window.canvas);
|
||||||
|
pdfDoc.onChangePage = function(numPage) {
|
||||||
|
document.getElementById("pageNumber").value = numPage;
|
||||||
|
}
|
||||||
|
pdfDoc.open("compressed.tracemonkey-pldi-09.pdf", function() {
|
||||||
|
document.getElementById("numPages").innerHTML = "/" + pdfDoc.numPages;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" href="viewer.css"></link>
|
<link rel="stylesheet" href="viewer.css"></link>
|
||||||
@ -301,9 +28,9 @@ window.onload = function() {
|
|||||||
<input type="file" style="float: right; margin: auto 32px;" onChange="load(this.value.toString());"></input>
|
<input type="file" style="float: right; margin: auto 32px;" onChange="load(this.value.toString());"></input>
|
||||||
<!-- This only opens supported PDFs from the source path...
|
<!-- This only opens supported PDFs from the source path...
|
||||||
-- Can we use JSONP to overcome the same-origin restrictions? -->
|
-- Can we use JSONP to overcome the same-origin restrictions? -->
|
||||||
<button onclick="prevPage();">Previous</button>
|
<button onclick="pdfDoc.prevPage();">Previous</button>
|
||||||
<button onclick="nextPage();">Next</button>
|
<button onclick="pdfDoc.nextPage();">Next</button>
|
||||||
<input type="text" id="pageNumber" onchange="showPage(this.value);"
|
<input type="text" id="pageNumber" onchange="pdfDoc.showPage(this.value);"
|
||||||
value="1" size="4"></input>
|
value="1" size="4"></input>
|
||||||
<span id="numPages">--</span>
|
<span id="numPages">--</span>
|
||||||
<span id="info"></span>
|
<span id="info"></span>
|
||||||
|
96
worker.js
96
worker.js
@ -1,15 +1,26 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var timer = null;
|
||||||
|
function tic() {
|
||||||
|
timer = Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toc(msg) {
|
||||||
|
log(msg + ": " + (Date.now() - timer) + "ms");
|
||||||
|
timer = null;
|
||||||
|
}
|
||||||
|
|
||||||
function log() {
|
function log() {
|
||||||
var args = Array.prototype.slice.call(arguments);
|
var args = Array.prototype.slice.call(arguments);
|
||||||
postMessage("log");
|
postMessage("log");
|
||||||
postMessage(JSON.stringify(args))
|
postMessage(JSON.stringify(args))
|
||||||
}
|
}
|
||||||
|
|
||||||
var console = {
|
var console = {
|
||||||
log: log
|
log: log
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
importScripts("canvas_proxy.js");
|
importScripts("canvas_proxy.js");
|
||||||
importScripts("pdf.js");
|
importScripts("pdf.js");
|
||||||
importScripts("fonts.js");
|
importScripts("fonts.js");
|
||||||
@ -18,55 +29,50 @@ importScripts("glyphlist.js")
|
|||||||
// Use the JpegStreamProxy proxy.
|
// Use the JpegStreamProxy proxy.
|
||||||
JpegStream = JpegStreamProxy;
|
JpegStream = JpegStreamProxy;
|
||||||
|
|
||||||
var timer = null;
|
|
||||||
function tic() {
|
|
||||||
timer = Date.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
function toc(msg) {
|
|
||||||
log(msg + ": " + (Date.now() - timer) + "ms");
|
|
||||||
timer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the WebWorkerProxyCanvas.
|
// Create the WebWorkerProxyCanvas.
|
||||||
var canvas = new CanvasProxy(1224, 1584);
|
var canvas = new CanvasProxy(1224, 1584);
|
||||||
|
|
||||||
var pageInterval;
|
// Listen for messages from the main thread.
|
||||||
var pdfDocument = null;
|
var pdfDocument = null;
|
||||||
onmessage = function(event) {
|
onmessage = function(event) {
|
||||||
var data = event.data;
|
var data = event.data;
|
||||||
if (!pdfDocument) {
|
// If there is no pdfDocument yet, then the sent data is the PDFDocument.
|
||||||
pdfDocument = new PDFDoc(new Stream(data));
|
if (!pdfDocument) {
|
||||||
postMessage("pdf_num_page");
|
pdfDocument = new PDFDoc(new Stream(data));
|
||||||
postMessage(pdfDocument.numPages)
|
postMessage("pdf_num_page");
|
||||||
return;
|
postMessage(pdfDocument.numPages)
|
||||||
} else {
|
return;
|
||||||
tic();
|
}
|
||||||
|
// User requested to render a certain page.
|
||||||
|
else {
|
||||||
|
tic();
|
||||||
|
|
||||||
// Let's try to render the first page...
|
// Let's try to render the first page...
|
||||||
var page = pdfDocument.getPage(parseInt(data));
|
var page = pdfDocument.getPage(parseInt(data));
|
||||||
|
|
||||||
// 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"), CanvasProxy);
|
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.
|
||||||
var count = fonts.length;
|
var count = fonts.length;
|
||||||
for (var i = 0; i < count; i++) {
|
for (var i = 0; i < count; i++) {
|
||||||
var font = fonts[i];
|
var font = fonts[i];
|
||||||
if (Fonts[font.name]) {
|
if (Fonts[font.name]) {
|
||||||
fontsReady = fontsReady && !Fonts[font.name].loading;
|
fontsReady = fontsReady && !Fonts[font.name].loading;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This "builds" the font and sents it over to the main thread.
|
// This "builds" the font and sents it over to the main thread.
|
||||||
new Font(font.name, font.file, font.properties);
|
new Font(font.name, font.file, font.properties);
|
||||||
}
|
|
||||||
toc("compiled page");
|
|
||||||
|
|
||||||
page.display(gfx);
|
|
||||||
canvas.flush();
|
|
||||||
}
|
}
|
||||||
|
toc("compiled page");
|
||||||
|
|
||||||
|
tic()
|
||||||
|
page.display(gfx);
|
||||||
|
canvas.flush();
|
||||||
|
toc("displayed page");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
294
worker_client.js
Normal file
294
worker_client.js
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
function WorkerPDFDoc(canvas) {
|
||||||
|
var timer = null
|
||||||
|
function tic() {
|
||||||
|
timer = Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toc(msg) {
|
||||||
|
console.log(msg + ": " + (Date.now() - timer) + "ms");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ctx = canvas.getContext("2d");
|
||||||
|
this.canvas = canvas;
|
||||||
|
this.worker = new Worker('worker.js');
|
||||||
|
|
||||||
|
this.numPage = 1;
|
||||||
|
this.numPages = null;
|
||||||
|
|
||||||
|
var imagesList = {};
|
||||||
|
var canvasList = {
|
||||||
|
0: canvas
|
||||||
|
};
|
||||||
|
var patternList = {};
|
||||||
|
var gradient;
|
||||||
|
|
||||||
|
var currentX = 0;
|
||||||
|
var currentXStack = [];
|
||||||
|
|
||||||
|
var ctxSpecial = {
|
||||||
|
"$setCurrentX": function(value) {
|
||||||
|
currentX = value;
|
||||||
|
},
|
||||||
|
|
||||||
|
"$addCurrentX": function(value) {
|
||||||
|
currentX += value;
|
||||||
|
},
|
||||||
|
|
||||||
|
"$saveCurrentX": function() {
|
||||||
|
currentXStack.push(currentX);
|
||||||
|
},
|
||||||
|
|
||||||
|
"$restoreCurrentX": function() {
|
||||||
|
currentX = currentXStack.pop();
|
||||||
|
},
|
||||||
|
|
||||||
|
"$showText": function(y, text, uniText) {
|
||||||
|
this.translate(currentX, -1 * y);
|
||||||
|
this.fillText(uniText, 0, 0);
|
||||||
|
currentX += this.measureText(text).width;
|
||||||
|
},
|
||||||
|
|
||||||
|
"$putImageData": function(imageData, x, y) {
|
||||||
|
var imgData = this.getImageData(0, 0, imageData.width, imageData.height);
|
||||||
|
|
||||||
|
// Store the .data property to avaid property lookups.
|
||||||
|
var imageRealData = imageData.data;
|
||||||
|
var imgRealData = imgData.data;
|
||||||
|
|
||||||
|
// Copy over the imageData.
|
||||||
|
var len = imageRealData.length;
|
||||||
|
while (len--)
|
||||||
|
imgRealData[len] = imageRealData[len]
|
||||||
|
|
||||||
|
this.putImageData(imgData, x, y);
|
||||||
|
},
|
||||||
|
|
||||||
|
"$drawImage": function(id, x, y, sx, sy, swidth, sheight) {
|
||||||
|
var image = imagesList[id];
|
||||||
|
if (!image) {
|
||||||
|
throw "Image not found";
|
||||||
|
}
|
||||||
|
this.drawImage(image, x, y, image.width, image.height,
|
||||||
|
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) {
|
||||||
|
gradient = this.createLinearGradient(x0, y0, x1, y1);
|
||||||
|
},
|
||||||
|
|
||||||
|
"$createPatternFromCanvas": function(patternId, canvasId, kind) {
|
||||||
|
var canvas = canvasList[canvasId];
|
||||||
|
if (!canvas) {
|
||||||
|
throw "Canvas not found";
|
||||||
|
}
|
||||||
|
patternList[patternId] = this.createPattern(canvas, kind);
|
||||||
|
},
|
||||||
|
|
||||||
|
"$addColorStop": function(i, rgba) {
|
||||||
|
gradient.addColorStop(i, rgba);
|
||||||
|
},
|
||||||
|
|
||||||
|
"$fillStyleGradient": function() {
|
||||||
|
this.fillStyle = gradient;
|
||||||
|
},
|
||||||
|
|
||||||
|
"$fillStylePattern": function(id) {
|
||||||
|
var pattern = patternList[id];
|
||||||
|
if (!pattern) {
|
||||||
|
throw "Pattern not found";
|
||||||
|
}
|
||||||
|
this.fillStyle = pattern;
|
||||||
|
},
|
||||||
|
|
||||||
|
"$strokeStyleGradient": function() {
|
||||||
|
this.strokeStyle = gradient;
|
||||||
|
},
|
||||||
|
|
||||||
|
"$strokeStylePattern": function(id) {
|
||||||
|
var pattern = patternList[id];
|
||||||
|
if (!pattern) {
|
||||||
|
throw "Pattern not found";
|
||||||
|
}
|
||||||
|
this.strokeStyle = pattern;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderProxyCanvas(canvas, stack) {
|
||||||
|
var ctx = canvas.getContext("2d");
|
||||||
|
for (var i = 0; i < stack.length; i++) {
|
||||||
|
var opp = stack[i];
|
||||||
|
if (opp[0] == "$") {
|
||||||
|
ctx[opp[1]] = opp[2];
|
||||||
|
} else if (opp[0] in ctxSpecial) {
|
||||||
|
ctxSpecial[opp[0]].apply(ctx, opp[1]);
|
||||||
|
} else {
|
||||||
|
ctx[opp[0]].apply(ctx, opp[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onMessage state machine.
|
||||||
|
*/
|
||||||
|
const WAIT = 0;
|
||||||
|
const CANVAS_PROXY_STACK = 1;
|
||||||
|
const LOG = 2;
|
||||||
|
const FONT = 3;
|
||||||
|
const PDF_NUM_PAGE = 4;
|
||||||
|
const JPEG_STREAM = 5;
|
||||||
|
|
||||||
|
var onMessageState = WAIT;
|
||||||
|
this.worker.onmessage = function(event) {
|
||||||
|
var data = event.data;
|
||||||
|
// console.log("onMessageRaw", data);
|
||||||
|
switch (onMessageState) {
|
||||||
|
case WAIT:
|
||||||
|
if (typeof data != "string") {
|
||||||
|
throw "expecting to get an string";
|
||||||
|
}
|
||||||
|
switch (data) {
|
||||||
|
case "pdf_num_page":
|
||||||
|
onMessageState = PDF_NUM_PAGE;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case "log":
|
||||||
|
onMessageState = LOG;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case "canvas_proxy_stack":
|
||||||
|
onMessageState = CANVAS_PROXY_STACK;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case "font":
|
||||||
|
onMessageState = FONT;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case "jpeg_stream":
|
||||||
|
onMessageState = JPEG_STREAM;
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw "unkown state: " + data
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JPEG_STREAM:
|
||||||
|
var img = new Image();
|
||||||
|
img.src = "data:image/jpeg;base64," + window.btoa(data.str);
|
||||||
|
imagesList[data.id] = img;
|
||||||
|
console.log("got image", data.id)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PDF_NUM_PAGE:
|
||||||
|
this.numPages = parseInt(data);
|
||||||
|
if (this.loadCallback) {
|
||||||
|
this.loadCallback();
|
||||||
|
}
|
||||||
|
onMessageState = WAIT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FONT:
|
||||||
|
data = JSON.parse(data);
|
||||||
|
var base64 = window.btoa(data.str);
|
||||||
|
|
||||||
|
// Add the @font-face rule to the document
|
||||||
|
var url = "url(data:" + data.mimetype + ";base64," + base64 + ");";
|
||||||
|
var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}";
|
||||||
|
var styleSheet = document.styleSheets[0];
|
||||||
|
styleSheet.insertRule(rule, styleSheet.length);
|
||||||
|
|
||||||
|
// Just adding the font-face to the DOM doesn't make it load. It
|
||||||
|
// seems it's loaded once Gecko notices it's used. Therefore,
|
||||||
|
// add a div on the page using the loaded font.
|
||||||
|
document.getElementById("fonts").innerHTML += "<div style='font-family:" + data.fontName + "'>j</div>";
|
||||||
|
|
||||||
|
onMessageState = WAIT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LOG:
|
||||||
|
console.log.apply(console, JSON.parse(data));
|
||||||
|
onMessageState = WAIT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CANVAS_PROXY_STACK:
|
||||||
|
var id = data.id;
|
||||||
|
var stack = data.stack;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// rendering at the end of the event queue ensures this.
|
||||||
|
setTimeout(function() {
|
||||||
|
if (id == 0) tic();
|
||||||
|
renderProxyCanvas(canvasList[id], stack);
|
||||||
|
if (id == 0) toc("canvas rendering")
|
||||||
|
}, 0);
|
||||||
|
onMessageState = WAIT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerPDFDoc.prototype.open = function(url, callback) {
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
req.open("GET", url);
|
||||||
|
req.mozResponseType = req.responseType = "arraybuffer";
|
||||||
|
req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200;
|
||||||
|
req.onreadystatechange = function() {
|
||||||
|
if (req.readyState == 4 && req.status == req.expected) {
|
||||||
|
var data = req.mozResponseArrayBuffer || req.mozResponse ||
|
||||||
|
req.responseArrayBuffer || req.response;
|
||||||
|
|
||||||
|
this.loadCallback = callback;
|
||||||
|
this.worker.postMessage(data);
|
||||||
|
this.showPage(this.numPage);
|
||||||
|
}
|
||||||
|
}.bind(this);
|
||||||
|
req.send(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerPDFDoc.prototype.showPage = function(numPage) {
|
||||||
|
var ctx = this.ctx;
|
||||||
|
ctx.save();
|
||||||
|
ctx.fillStyle = "rgb(255, 255, 255)";
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.restore();
|
||||||
|
|
||||||
|
this.numPage = parseInt(numPage);
|
||||||
|
this.worker.postMessage(numPage);
|
||||||
|
if (this.onChangePage) {
|
||||||
|
this.onChangePage(numPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerPDFDoc.prototype.nextPage = function() {
|
||||||
|
if (this.numPage == this.numPages) return;
|
||||||
|
this.showPage(++this.numPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerPDFDoc.prototype.prevPage = function() {
|
||||||
|
if (this.numPage == 1) return;
|
||||||
|
this.showPage(--this.numPage);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user