First pass on review: worker.js -> pdf_worker.js, Font.bind cleanup + other stuff
This commit is contained in:
parent
405c367ece
commit
229edf24d4
@ -1,3 +1,7 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
"use strict";
|
||||
|
||||
var JpegStreamProxyCounter = 0;
|
||||
// WebWorker Proxy for JpegStream.
|
||||
@ -29,16 +33,16 @@ var JpegStreamProxy = (function() {
|
||||
// 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]]);
|
||||
function GradientProxy(cmdQueue, x0, y0, x1, y1) {
|
||||
cmdQueue.push(["$createLinearGradient", [x0, y0, x1, y1]]);
|
||||
this.addColorStop = function(i, rgba) {
|
||||
stack.push(["$addColorStop", [i, rgba]]);
|
||||
cmdQueue.push(["$addColorStop", [i, rgba]]);
|
||||
}
|
||||
}
|
||||
|
||||
// Really simple PatternProxy.
|
||||
var patternProxyCounter = 0;
|
||||
function PatternProxy(stack, object, kind) {
|
||||
function PatternProxy(cmdQueue, object, kind) {
|
||||
this.id = patternProxyCounter++;
|
||||
|
||||
if (!(object instanceof CanvasProxy) ) {
|
||||
@ -49,7 +53,7 @@ function PatternProxy(stack, object, kind) {
|
||||
// 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]]);
|
||||
cmdQueue.push(["$createPatternFromCanvas", [this.id, object.id, kind]]);
|
||||
}
|
||||
|
||||
var canvasProxyCounter = 0;
|
||||
@ -57,7 +61,7 @@ function CanvasProxy(width, height) {
|
||||
this.id = canvasProxyCounter++;
|
||||
|
||||
// The `stack` holds the rendering calls and gets flushed to the main thead.
|
||||
var stack = this.$stack = [];
|
||||
var cmdQueue = this.cmdQueue = [];
|
||||
|
||||
// Dummy context that gets exposed.
|
||||
var ctx = {};
|
||||
@ -119,7 +123,7 @@ function CanvasProxy(width, height) {
|
||||
function buildFuncCall(name) {
|
||||
return function() {
|
||||
// console.log("funcCall", name)
|
||||
stack.push([name, Array.prototype.slice.call(arguments)]);
|
||||
cmdQueue.push([name, Array.prototype.slice.call(arguments)]);
|
||||
}
|
||||
}
|
||||
var name;
|
||||
@ -131,11 +135,11 @@ function CanvasProxy(width, height) {
|
||||
// Some function calls that need more work.
|
||||
|
||||
ctx.createPattern = function(object, kind) {
|
||||
return new PatternProxy(stack, object, kind);
|
||||
return new PatternProxy(cmdQueue, object, kind);
|
||||
}
|
||||
|
||||
ctx.createLinearGradient = function(x0, y0, x1, y1) {
|
||||
return new GradientProxy(stack, x0, y0, x1, y1);
|
||||
return new GradientProxy(cmdQueue, x0, y0, x1, y1);
|
||||
}
|
||||
|
||||
ctx.getImageData = function(x, y, w, h) {
|
||||
@ -147,16 +151,16 @@ function CanvasProxy(width, height) {
|
||||
}
|
||||
|
||||
ctx.putImageData = function(data, x, y, width, height) {
|
||||
stack.push(["$putImageData", [data, x, y, width, height]]);
|
||||
cmdQueue.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]]);
|
||||
cmdQueue.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]])
|
||||
cmdQueue.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]])
|
||||
} else {
|
||||
throw "unkown type to drawImage";
|
||||
}
|
||||
@ -192,11 +196,26 @@ function CanvasProxy(width, height) {
|
||||
|
||||
function buildSetter(name) {
|
||||
return function(value) {
|
||||
stack.push(["$", name, value]);
|
||||
cmdQueue.push(["$", name, value]);
|
||||
return ctx["$" + name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
cmdQueue.push(["$" + name + "Gradient"]);
|
||||
} else if (value instanceof PatternProxy) {
|
||||
cmdQueue.push(["$" + name + "Pattern", [value.id]]);
|
||||
} else {
|
||||
cmdQueue.push(["$", name, value]);
|
||||
return ctx["$" + name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var name in ctxProp) {
|
||||
ctx["$" + name] = ctxProp[name];
|
||||
ctx.__defineGetter__(name, buildGetter(name));
|
||||
@ -204,18 +223,6 @@ function CanvasProxy(width, height) {
|
||||
// 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));
|
||||
@ -224,16 +231,16 @@ function CanvasProxy(width, height) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the current stack of the CanvasProxy over to the main thread and
|
||||
* resets the stack.
|
||||
* Sends the current cmdQueue of the CanvasProxy over to the main thread and
|
||||
* resets the cmdQueue.
|
||||
*/
|
||||
CanvasProxy.prototype.flush = function() {
|
||||
postMessage("canvas_proxy_stack");
|
||||
postMessage("canvas_proxy_cmd_queue");
|
||||
postMessage({
|
||||
id: this.id,
|
||||
stack: this.$stack,
|
||||
width: this.width,
|
||||
height: this.height
|
||||
id: this.id,
|
||||
cmdQueue: this.cmdQueue,
|
||||
width: this.width,
|
||||
height: this.height
|
||||
});
|
||||
this.$stack.length = 0;
|
||||
this.cmdQueue.length = 0;
|
||||
}
|
||||
|
92
fonts.js
92
fonts.js
@ -759,88 +759,15 @@ var Font = (function () {
|
||||
var data = this.font;
|
||||
var fontName = this.name;
|
||||
|
||||
var isWorker = (typeof window == "undefined");
|
||||
/** Hack begin */
|
||||
if (!isWorker) {
|
||||
|
||||
// Actually there is not event when a font has finished downloading so
|
||||
// the following code are a dirty hack to 'guess' when a font is ready
|
||||
var canvas = document.createElement("canvas");
|
||||
var style = "border: 1px solid black; position:absolute; top: " +
|
||||
(debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px";
|
||||
canvas.setAttribute("style", style);
|
||||
canvas.setAttribute("width", 340);
|
||||
canvas.setAttribute("heigth", 100);
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
// Get the font size canvas think it will be for 'spaces'
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial";
|
||||
var testString = " ";
|
||||
|
||||
// When debugging use the characters provided by the charsets to visually
|
||||
// see what's happening instead of 'spaces'
|
||||
var debug = false;
|
||||
if (debug) {
|
||||
var name = document.createElement("font");
|
||||
name.setAttribute("style", "position: absolute; left: 20px; top: " +
|
||||
(100 * fontCount + 60) + "px");
|
||||
name.innerHTML = fontName;
|
||||
document.body.appendChild(name);
|
||||
|
||||
// Retrieve font charset
|
||||
var charset = Fonts[fontName].properties.charset || [];
|
||||
|
||||
// if the charset is too small make it repeat a few times
|
||||
var count = 30;
|
||||
while (count-- && charset.length <= 30)
|
||||
charset = charset.concat(charset.slice());
|
||||
|
||||
for (var i = 0; i < charset.length; i++) {
|
||||
var unicode = GlyphsUnicode[charset[i]];
|
||||
if (!unicode)
|
||||
continue;
|
||||
testString += String.fromCharCode(unicode);
|
||||
}
|
||||
|
||||
ctx.fillText(testString, 20, 20);
|
||||
}
|
||||
|
||||
// Periodicaly check for the width of the testString, it will be
|
||||
// different once the real font has loaded
|
||||
var textWidth = ctx.measureText(testString).width;
|
||||
|
||||
var interval = window.setInterval(function canvasInterval(self) {
|
||||
this.start = this.start || Date.now();
|
||||
ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial";
|
||||
|
||||
// For some reasons the font has not loaded, so mark it loaded for the
|
||||
// page to proceed but cry
|
||||
if ((Date.now() - this.start) >= kMaxWaitForFontFace) {
|
||||
window.clearInterval(interval);
|
||||
Fonts[fontName].loading = false;
|
||||
warn("Is " + fontName + " for charset: " + charset + " loaded?");
|
||||
this.start = 0;
|
||||
} else if (textWidth != ctx.measureText(testString).width) {
|
||||
window.clearInterval(interval);
|
||||
Fonts[fontName].loading = false;
|
||||
this.start = 0;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
ctx.fillText(testString, 20, 50);
|
||||
}, 30, this);
|
||||
}
|
||||
|
||||
/** Hack end */
|
||||
//
|
||||
// Get the base64 encoding of the binary font data
|
||||
var str = "";
|
||||
var length = data.length;
|
||||
for (var i = 0; i < length; ++i)
|
||||
str += String.fromCharCode(data[i]);
|
||||
|
||||
if (isWorker) {
|
||||
// Insert the font-face css on the page. In a web worker, this needs to
|
||||
// be forwareded on the main thread.
|
||||
if (typeof window == "undefined") {
|
||||
postMessage("font");
|
||||
postMessage(JSON.stringify({
|
||||
str: str,
|
||||
@ -855,6 +782,19 @@ var Font = (function () {
|
||||
var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}";
|
||||
var styleSheet = document.styleSheets[0];
|
||||
styleSheet.insertRule(rule, styleSheet.length);
|
||||
|
||||
var div = document.createElement("div");
|
||||
div.innerHTML += "<div style='font-family:" +
|
||||
fontName +
|
||||
";'>j</div>";
|
||||
document.body.appendChild(div);
|
||||
|
||||
Fonts[fontName].loading = true;
|
||||
window.setTimeout(function() {
|
||||
Fonts[fontName].loading = false;
|
||||
// Timeout of just `0`, `10` doesn't work here, but for me all values
|
||||
// above work. Setting value to 50ms.
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
8
pdf.js
8
pdf.js
@ -2645,9 +2645,7 @@ var CanvasGraphics = (function() {
|
||||
}
|
||||
|
||||
var fn = Function("objpool", src);
|
||||
var ret = function (gfx) { fn.call(gfx, objpool); };
|
||||
ret.src = src;
|
||||
return ret;
|
||||
return function (gfx) { fn.call(gfx, objpool); };
|
||||
},
|
||||
|
||||
endDrawing: function() {
|
||||
@ -3015,8 +3013,8 @@ var CanvasGraphics = (function() {
|
||||
var botRight = applyMatrix([x0 + xstep, y0 + ystep], matrix);
|
||||
|
||||
var tmpCanvas = new this.ScratchCanvas(
|
||||
Math.ceil(botRight[0] - topLeft[0]), // WIDTH
|
||||
Math.ceil(botRight[1] - topLeft[1]) // HEIGHT
|
||||
Math.ceil(botRight[0] - topLeft[0]), // width
|
||||
Math.ceil(botRight[1] - topLeft[1]) // height
|
||||
);
|
||||
|
||||
// set the new canvas element context as the graphics context
|
||||
|
@ -1,3 +1,6 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
"use strict";
|
||||
|
||||
var timer = null;
|
@ -14,6 +14,7 @@ window.onload = function() {
|
||||
pdfDoc.onChangePage = function(numPage) {
|
||||
document.getElementById("pageNumber").value = numPage;
|
||||
}
|
||||
// pdfDoc.open("canvas.pdf", function() {
|
||||
pdfDoc.open("compressed.tracemonkey-pldi-09.pdf", function() {
|
||||
document.getElementById("numPages").innerHTML = "/" + pdfDoc.numPages;
|
||||
})
|
||||
|
@ -1,3 +1,6 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
"use strict";
|
||||
|
||||
function WorkerPDFDoc(canvas) {
|
||||
@ -128,10 +131,11 @@ function WorkerPDFDoc(canvas) {
|
||||
}
|
||||
}
|
||||
|
||||
function renderProxyCanvas(canvas, stack) {
|
||||
function renderProxyCanvas(canvas, cmdQueue) {
|
||||
var ctx = canvas.getContext("2d");
|
||||
for (var i = 0; i < stack.length; i++) {
|
||||
var opp = stack[i];
|
||||
var cmdQueueLength = cmdQueue.length;
|
||||
for (var i = 0; i < cmdQueueLength; i++) {
|
||||
var opp = cmdQueue[i];
|
||||
if (opp[0] == "$") {
|
||||
ctx[opp[1]] = opp[2];
|
||||
} else if (opp[0] in ctxSpecial) {
|
||||
@ -146,7 +150,7 @@ function WorkerPDFDoc(canvas) {
|
||||
* onMessage state machine.
|
||||
*/
|
||||
const WAIT = 0;
|
||||
const CANVAS_PROXY_STACK = 1;
|
||||
const CANVAS_PROXY_CMD_QUEUE = 1;
|
||||
const LOG = 2;
|
||||
const FONT = 3;
|
||||
const PDF_NUM_PAGE = 4;
|
||||
@ -170,8 +174,8 @@ function WorkerPDFDoc(canvas) {
|
||||
onMessageState = LOG;
|
||||
return;
|
||||
|
||||
case "canvas_proxy_stack":
|
||||
onMessageState = CANVAS_PROXY_STACK;
|
||||
case "canvas_proxy_cmd_queue":
|
||||
onMessageState = CANVAS_PROXY_CMD_QUEUE;
|
||||
return;
|
||||
|
||||
case "font":
|
||||
@ -215,6 +219,7 @@ function WorkerPDFDoc(canvas) {
|
||||
// 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.
|
||||
var div = document.createElement("div");
|
||||
document.getElementById("fonts").innerHTML += "<div style='font-family:" + data.fontName + "'>j</div>";
|
||||
|
||||
onMessageState = WAIT;
|
||||
@ -225,9 +230,9 @@ function WorkerPDFDoc(canvas) {
|
||||
onMessageState = WAIT;
|
||||
break;
|
||||
|
||||
case CANVAS_PROXY_STACK:
|
||||
case CANVAS_PROXY_CMD_QUEUE:
|
||||
var id = data.id;
|
||||
var stack = data.stack;
|
||||
var cmdQueue = data.cmdQueue;
|
||||
|
||||
// Check if there is already a canvas with the given id. If not,
|
||||
// create a new canvas.
|
||||
@ -242,7 +247,7 @@ function WorkerPDFDoc(canvas) {
|
||||
// rendering at the end of the event queue ensures this.
|
||||
setTimeout(function() {
|
||||
if (id == 0) tic();
|
||||
renderProxyCanvas(canvasList[id], stack);
|
||||
renderProxyCanvas(canvasList[id], cmdQueue);
|
||||
if (id == 0) toc("canvas rendering")
|
||||
}, 0);
|
||||
onMessageState = WAIT;
|
||||
|
Loading…
Reference in New Issue
Block a user