First pass on review: worker.js -> pdf_worker.js, Font.bind cleanup + other stuff
This commit is contained in:
parent
4281f799e5
commit
a3d815074d
@ -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;
|
var JpegStreamProxyCounter = 0;
|
||||||
// WebWorker Proxy for JpegStream.
|
// WebWorker Proxy for JpegStream.
|
||||||
@ -29,16 +33,16 @@ var JpegStreamProxy = (function() {
|
|||||||
// 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(cmdQueue, x0, y0, x1, y1) {
|
||||||
stack.push(["$createLinearGradient", [x0, y0, x1, y1]]);
|
cmdQueue.push(["$createLinearGradient", [x0, y0, x1, y1]]);
|
||||||
this.addColorStop = function(i, rgba) {
|
this.addColorStop = function(i, rgba) {
|
||||||
stack.push(["$addColorStop", [i, rgba]]);
|
cmdQueue.push(["$addColorStop", [i, rgba]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Really simple PatternProxy.
|
// Really simple PatternProxy.
|
||||||
var patternProxyCounter = 0;
|
var patternProxyCounter = 0;
|
||||||
function PatternProxy(stack, object, kind) {
|
function PatternProxy(cmdQueue, object, kind) {
|
||||||
this.id = patternProxyCounter++;
|
this.id = patternProxyCounter++;
|
||||||
|
|
||||||
if (!(object instanceof CanvasProxy) ) {
|
if (!(object instanceof CanvasProxy) ) {
|
||||||
@ -49,7 +53,7 @@ function PatternProxy(stack, object, kind) {
|
|||||||
// TODO: Make some kind of dependency management, such that the object
|
// TODO: Make some kind of dependency management, such that the object
|
||||||
// gets flushed only if needed.
|
// gets flushed only if needed.
|
||||||
object.flush();
|
object.flush();
|
||||||
stack.push(["$createPatternFromCanvas", [this.id, object.id, kind]]);
|
cmdQueue.push(["$createPatternFromCanvas", [this.id, object.id, kind]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var canvasProxyCounter = 0;
|
var canvasProxyCounter = 0;
|
||||||
@ -57,7 +61,7 @@ function CanvasProxy(width, height) {
|
|||||||
this.id = canvasProxyCounter++;
|
this.id = canvasProxyCounter++;
|
||||||
|
|
||||||
// The `stack` holds the rendering calls and gets flushed to the main thead.
|
// 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.
|
// Dummy context that gets exposed.
|
||||||
var ctx = {};
|
var ctx = {};
|
||||||
@ -119,7 +123,7 @@ function CanvasProxy(width, height) {
|
|||||||
function buildFuncCall(name) {
|
function buildFuncCall(name) {
|
||||||
return function() {
|
return function() {
|
||||||
// console.log("funcCall", name)
|
// console.log("funcCall", name)
|
||||||
stack.push([name, Array.prototype.slice.call(arguments)]);
|
cmdQueue.push([name, Array.prototype.slice.call(arguments)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var name;
|
var name;
|
||||||
@ -131,11 +135,11 @@ function CanvasProxy(width, height) {
|
|||||||
// Some function calls that need more work.
|
// Some function calls that need more work.
|
||||||
|
|
||||||
ctx.createPattern = function(object, kind) {
|
ctx.createPattern = function(object, kind) {
|
||||||
return new PatternProxy(stack, object, kind);
|
return new PatternProxy(cmdQueue, object, kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.createLinearGradient = function(x0, y0, x1, y1) {
|
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) {
|
ctx.getImageData = function(x, y, w, h) {
|
||||||
@ -147,16 +151,16 @@ function CanvasProxy(width, height) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.putImageData = function(data, x, y, 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) {
|
ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) {
|
||||||
if (image instanceof CanvasProxy) {
|
if (image instanceof CanvasProxy) {
|
||||||
// Send the image/CanvasProxy to the main thread.
|
// Send the image/CanvasProxy to the main thread.
|
||||||
image.flush();
|
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) {
|
} 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 {
|
} else {
|
||||||
throw "unkown type to drawImage";
|
throw "unkown type to drawImage";
|
||||||
}
|
}
|
||||||
@ -192,11 +196,26 @@ function CanvasProxy(width, height) {
|
|||||||
|
|
||||||
function buildSetter(name) {
|
function buildSetter(name) {
|
||||||
return function(value) {
|
return function(value) {
|
||||||
stack.push(["$", name, value]);
|
cmdQueue.push(["$", name, value]);
|
||||||
return ctx["$" + 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) {
|
for (var name in ctxProp) {
|
||||||
ctx["$" + name] = ctxProp[name];
|
ctx["$" + name] = ctxProp[name];
|
||||||
ctx.__defineGetter__(name, buildGetter(name));
|
ctx.__defineGetter__(name, buildGetter(name));
|
||||||
@ -204,18 +223,6 @@ function CanvasProxy(width, height) {
|
|||||||
// Special treatment for `fillStyle` and `strokeStyle`: The passed style
|
// Special treatment for `fillStyle` and `strokeStyle`: The passed style
|
||||||
// might be a gradient. Need to check for that.
|
// might be a gradient. Need to check for that.
|
||||||
if (name == "fillStyle" || name == "strokeStyle") {
|
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));
|
ctx.__defineSetter__(name, buildSetterStyle(name));
|
||||||
} else {
|
} else {
|
||||||
ctx.__defineSetter__(name, buildSetter(name));
|
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
|
* Sends the current cmdQueue of the CanvasProxy over to the main thread and
|
||||||
* resets the stack.
|
* resets the cmdQueue.
|
||||||
*/
|
*/
|
||||||
CanvasProxy.prototype.flush = function() {
|
CanvasProxy.prototype.flush = function() {
|
||||||
postMessage("canvas_proxy_stack");
|
postMessage("canvas_proxy_cmd_queue");
|
||||||
postMessage({
|
postMessage({
|
||||||
id: this.id,
|
id: this.id,
|
||||||
stack: this.$stack,
|
cmdQueue: this.cmdQueue,
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height
|
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 data = this.font;
|
||||||
var fontName = this.name;
|
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
|
// Get the base64 encoding of the binary font data
|
||||||
var str = "";
|
var str = "";
|
||||||
var length = data.length;
|
var length = data.length;
|
||||||
for (var i = 0; i < length; ++i)
|
for (var i = 0; i < length; ++i)
|
||||||
str += String.fromCharCode(data[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("font");
|
||||||
postMessage(JSON.stringify({
|
postMessage(JSON.stringify({
|
||||||
str: str,
|
str: str,
|
||||||
@ -855,6 +782,19 @@ var Font = (function () {
|
|||||||
var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}";
|
var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}";
|
||||||
var styleSheet = document.styleSheets[0];
|
var styleSheet = document.styleSheets[0];
|
||||||
styleSheet.insertRule(rule, styleSheet.length);
|
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 fn = Function("objpool", src);
|
||||||
var ret = function (gfx) { fn.call(gfx, objpool); };
|
return function (gfx) { fn.call(gfx, objpool); };
|
||||||
ret.src = src;
|
|
||||||
return ret;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
endDrawing: function() {
|
endDrawing: function() {
|
||||||
@ -3015,8 +3013,8 @@ var CanvasGraphics = (function() {
|
|||||||
var botRight = applyMatrix([x0 + xstep, y0 + ystep], matrix);
|
var botRight = applyMatrix([x0 + xstep, y0 + ystep], matrix);
|
||||||
|
|
||||||
var tmpCanvas = new this.ScratchCanvas(
|
var tmpCanvas = new this.ScratchCanvas(
|
||||||
Math.ceil(botRight[0] - topLeft[0]), // WIDTH
|
Math.ceil(botRight[0] - topLeft[0]), // width
|
||||||
Math.ceil(botRight[1] - topLeft[1]) // HEIGHT
|
Math.ceil(botRight[1] - topLeft[1]) // height
|
||||||
);
|
);
|
||||||
|
|
||||||
// set the new canvas element context as the graphics context
|
// 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";
|
"use strict";
|
||||||
|
|
||||||
var timer = null;
|
var timer = null;
|
@ -14,6 +14,7 @@ window.onload = function() {
|
|||||||
pdfDoc.onChangePage = function(numPage) {
|
pdfDoc.onChangePage = function(numPage) {
|
||||||
document.getElementById("pageNumber").value = numPage;
|
document.getElementById("pageNumber").value = numPage;
|
||||||
}
|
}
|
||||||
|
// pdfDoc.open("canvas.pdf", function() {
|
||||||
pdfDoc.open("compressed.tracemonkey-pldi-09.pdf", function() {
|
pdfDoc.open("compressed.tracemonkey-pldi-09.pdf", function() {
|
||||||
document.getElementById("numPages").innerHTML = "/" + pdfDoc.numPages;
|
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";
|
"use strict";
|
||||||
|
|
||||||
function WorkerPDFDoc(canvas) {
|
function WorkerPDFDoc(canvas) {
|
||||||
@ -128,10 +131,11 @@ function WorkerPDFDoc(canvas) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderProxyCanvas(canvas, stack) {
|
function renderProxyCanvas(canvas, cmdQueue) {
|
||||||
var ctx = canvas.getContext("2d");
|
var ctx = canvas.getContext("2d");
|
||||||
for (var i = 0; i < stack.length; i++) {
|
var cmdQueueLength = cmdQueue.length;
|
||||||
var opp = stack[i];
|
for (var i = 0; i < cmdQueueLength; i++) {
|
||||||
|
var opp = cmdQueue[i];
|
||||||
if (opp[0] == "$") {
|
if (opp[0] == "$") {
|
||||||
ctx[opp[1]] = opp[2];
|
ctx[opp[1]] = opp[2];
|
||||||
} else if (opp[0] in ctxSpecial) {
|
} else if (opp[0] in ctxSpecial) {
|
||||||
@ -146,7 +150,7 @@ function WorkerPDFDoc(canvas) {
|
|||||||
* onMessage state machine.
|
* onMessage state machine.
|
||||||
*/
|
*/
|
||||||
const WAIT = 0;
|
const WAIT = 0;
|
||||||
const CANVAS_PROXY_STACK = 1;
|
const CANVAS_PROXY_CMD_QUEUE = 1;
|
||||||
const LOG = 2;
|
const LOG = 2;
|
||||||
const FONT = 3;
|
const FONT = 3;
|
||||||
const PDF_NUM_PAGE = 4;
|
const PDF_NUM_PAGE = 4;
|
||||||
@ -170,8 +174,8 @@ function WorkerPDFDoc(canvas) {
|
|||||||
onMessageState = LOG;
|
onMessageState = LOG;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case "canvas_proxy_stack":
|
case "canvas_proxy_cmd_queue":
|
||||||
onMessageState = CANVAS_PROXY_STACK;
|
onMessageState = CANVAS_PROXY_CMD_QUEUE;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case "font":
|
case "font":
|
||||||
@ -215,6 +219,7 @@ function WorkerPDFDoc(canvas) {
|
|||||||
// Just adding the font-face to the DOM doesn't make it load. It
|
// 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,
|
// seems it's loaded once Gecko notices it's used. Therefore,
|
||||||
// add a div on the page using the loaded font.
|
// 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>";
|
document.getElementById("fonts").innerHTML += "<div style='font-family:" + data.fontName + "'>j</div>";
|
||||||
|
|
||||||
onMessageState = WAIT;
|
onMessageState = WAIT;
|
||||||
@ -225,9 +230,9 @@ function WorkerPDFDoc(canvas) {
|
|||||||
onMessageState = WAIT;
|
onMessageState = WAIT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CANVAS_PROXY_STACK:
|
case CANVAS_PROXY_CMD_QUEUE:
|
||||||
var id = data.id;
|
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,
|
// Check if there is already a canvas with the given id. If not,
|
||||||
// create a new canvas.
|
// create a new canvas.
|
||||||
@ -242,7 +247,7 @@ function WorkerPDFDoc(canvas) {
|
|||||||
// rendering at the end of the event queue ensures this.
|
// rendering at the end of the event queue ensures this.
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
if (id == 0) tic();
|
if (id == 0) tic();
|
||||||
renderProxyCanvas(canvasList[id], stack);
|
renderProxyCanvas(canvasList[id], cmdQueue);
|
||||||
if (id == 0) toc("canvas rendering")
|
if (id == 0) toc("canvas rendering")
|
||||||
}, 0);
|
}, 0);
|
||||||
onMessageState = WAIT;
|
onMessageState = WAIT;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user