4 changed files with 556 additions and 550 deletions
@ -1,260 +1,239 @@
@@ -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; |
||||
// WebWorker Proxy for JpegStream.
|
||||
var JpegStreamProxy = (function() { |
||||
function constructor(bytes, dict) { |
||||
this.id = JpegStreamProxyCounter++; |
||||
this.dict = dict; |
||||
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;
|
||||
// Tell the main thread to create an image.
|
||||
postMessage("jpeg_stream"); |
||||
postMessage({ |
||||
id: this.id, |
||||
str: bytesToString(bytes) |
||||
}); |
||||
} |
||||
|
||||
constructor.prototype = { |
||||
getImage: function() { |
||||
return this; |
||||
}, |
||||
getChar: function() { |
||||
error("internal error: getChar is not valid on JpegStream"); |
||||
} |
||||
}; |
||||
|
||||
constructor.prototype = { |
||||
getImage: function() { |
||||
return this; |
||||
// return this.domImage;
|
||||
}, |
||||
getChar: function() { |
||||
error("internal error: getChar is not valid on JpegStream"); |
||||
} |
||||
}; |
||||
|
||||
return constructor; |
||||
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]]); |
||||
} |
||||
stack.push(["$createLinearGradient", [x0, y0, x1, y1]]); |
||||
this.addColorStop = function(i, rgba) { |
||||
stack.push(["$addColorStop", [i, rgba]]); |
||||
} |
||||
} |
||||
|
||||
// Really simple PatternProxy.
|
||||
var patternProxyCounter = 0; |
||||
function PatternProxy(stack, object, kind) { |
||||
this.id = patternProxyCounter++; |
||||
this.id = patternProxyCounter++; |
||||
|
||||
if (!(object instanceof CanvasProxy) ) { |
||||
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
|
||||
// gets flushed only if needed.
|
||||
object.flush(); |
||||
stack.push(["$createPatternFromCanvas", [this.id, object.id, kind]]); |
||||
if (!(object instanceof CanvasProxy) ) { |
||||
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
|
||||
// gets flushed only if needed.
|
||||
object.flush(); |
||||
stack.push(["$createPatternFromCanvas", [this.id, object.id, kind]]); |
||||
} |
||||
|
||||
var canvasProxyCounter = 0; |
||||
function CanvasProxy(width, height) { |
||||
this.id = canvasProxyCounter++; |
||||
|
||||
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; |
||||
} |
||||
|
||||
// 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; |
||||
|
||||
var ctxFunc = [ |
||||
"createRadialGradient", |
||||
"arcTo", |
||||
"arc", |
||||
"fillText", |
||||
"strokeText", |
||||
// "drawImage",
|
||||
// "getImageData",
|
||||
// "putImageData",
|
||||
"createImageData", |
||||
"drawWindow", |
||||
"save", |
||||
"restore", |
||||
"scale", |
||||
"rotate", |
||||
"translate", |
||||
"transform", |
||||
"setTransform", |
||||
// "createLinearGradient",
|
||||
// "createPattern",
|
||||
"clearRect", |
||||
"fillRect", |
||||
"strokeRect", |
||||
"beginPath", |
||||
"closePath", |
||||
"moveTo", |
||||
"lineTo", |
||||
"quadraticCurveTo", |
||||
"bezierCurveTo", |
||||
"rect", |
||||
"fill", |
||||
"stroke", |
||||
"clip", |
||||
"measureText", |
||||
"isPointInPath", |
||||
|
||||
"$setCurrentX", |
||||
"$addCurrentX", |
||||
"$saveCurrentX", |
||||
"$restoreCurrentX", |
||||
"$showText" |
||||
]; |
||||
|
||||
ctx.createPattern = function(object, kind) { |
||||
return new PatternProxy(stack, object, kind); |
||||
} |
||||
this.id = canvasProxyCounter++; |
||||
|
||||
ctx.createLinearGradient = function(x0, y0, x1, y1) { |
||||
return new GradientProxy(stack, x0, y0, x1, y1); |
||||
} |
||||
// The `stack` holds the rendering calls and gets flushed to the main thead.
|
||||
var stack = this.$stack = []; |
||||
|
||||
ctx.getImageData = function(x, y, w, h) { |
||||
return { |
||||
width: w, |
||||
height: h, |
||||
data: Uint8ClampedArray(w * h * 4) |
||||
}; |
||||
// Dummy context that gets exposed.
|
||||
var ctx = {}; |
||||
this.getContext = function(type) { |
||||
if (type != "2d") { |
||||
throw "CanvasProxy can only provide a 2d context."; |
||||
} |
||||
|
||||
ctx.putImageData = function(data, x, y, width, height) { |
||||
stack.push(["$putImageData", [data, x, y, width, height]]); |
||||
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 = [ |
||||
"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", |
||||
|
||||
// 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.
|
||||
"$setCurrentX", |
||||
"$addCurrentX", |
||||
"$saveCurrentX", |
||||
"$restoreCurrentX", |
||||
"$showText" |
||||
]; |
||||
|
||||
function buildFuncCall(name) { |
||||
return function() { |
||||
// console.log("funcCall", name)
|
||||
stack.push([name, Array.prototype.slice.call(arguments)]); |
||||
} |
||||
|
||||
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]]) |
||||
} else { |
||||
throw "unkown type to drawImage"; |
||||
} |
||||
} |
||||
|
||||
function buildFuncCall(name) { |
||||
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); |
||||
} |
||||
|
||||
// Some function calls that need more work.
|
||||
|
||||
ctx.createPattern = function(object, kind) { |
||||
return new PatternProxy(stack, object, kind); |
||||
} |
||||
|
||||
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]]) |
||||
} else { |
||||
throw "unkown type to drawImage"; |
||||
} |
||||
var name; |
||||
for (var i = 0; i < ctxFunc.length; i++) { |
||||
name = ctxFunc[i]; |
||||
ctx[name] = buildFuncCall(name); |
||||
} |
||||
|
||||
// Setup property access to `ctx`.
|
||||
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" |
||||
} |
||||
|
||||
function buildGetter(name) { |
||||
return function() { |
||||
return ctx["$" + name]; |
||||
} |
||||
} |
||||
|
||||
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 buildSetter(name) { |
||||
return function(value) { |
||||
stack.push(["$", name, value]); |
||||
return ctx["$" + name] = value; |
||||
} |
||||
} |
||||
|
||||
function buildGetter(name) { |
||||
return function() { |
||||
return ctx["$" + name]; |
||||
} |
||||
} |
||||
for (var name in ctxProp) { |
||||
ctx["$" + name] = ctxProp[name]; |
||||
ctx.__defineGetter__(name, buildGetter(name)); |
||||
|
||||
function buildSetter(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)); |
||||
} |
||||
|
||||
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() { |
||||
postMessage("canvas_proxy_stack"); |
||||
postMessage({ |
||||
id: this.id, |
||||
stack: this.$stack, |
||||
width: this.width, |
||||
height: this.height |
||||
}); |
||||
this.$stack.length = 0; |
||||
postMessage("canvas_proxy_stack"); |
||||
postMessage({ |
||||
id: this.id, |
||||
stack: this.$stack, |
||||
width: this.width, |
||||
height: this.height |
||||
}); |
||||
this.$stack.length = 0; |
||||
} |
||||
|
@ -0,0 +1,294 @@
@@ -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