First pass on FontWorker

This commit is contained in:
Julian Viereck 2011-06-26 20:55:27 +02:00
parent c712712e67
commit b00df76044
8 changed files with 247 additions and 22 deletions

View file

@ -18,12 +18,115 @@ if (typeof console.time == "undefined") {
};
}
function FontWorker() {
this.worker = new Worker("worker/font.js");
this.fontsWaiting = 0;
this.fontsWaitingCallbacks = [];
// Listen to the WebWorker for data and call actionHandler on it.
this.worker.onmessage = function(event) {
var data = event.data;
var actionHandler = this.actionHandler
if (data.action in actionHandler) {
actionHandler[data.action].call(this, data.data);
} else {
throw "Unkown action from worker: " + data.action;
}
}.bind(this);
}
FontWorker.prototype = {
actionHandler: {
"fonts": function(data) {
// console.log("got processed fonts from worker", Object.keys(data));
for (name in data) {
var base64 = window.btoa(data[name]);
// Add the @font-face rule to the document
var url = "url(data:font/opentype;base64," + base64 + ");";
var rule = "@font-face { font-family:'" + name + "';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.
var div = document.createElement("div");
var style = 'font-family:"' + name +
'";position: absolute;top:-99999;left:-99999;z-index:-99999';
div.setAttribute("style", style);
document.body.appendChild(div);
this.fontsWaiting --;
}
// This timeout is necessary right now to make sure the fonts are really
// loaded at the point the callbacks are called.
setTimeout(function() {
// If all fonts are available now, then call all the callbacks.
if (this.fontsWaiting == 0) {
var callbacks = this.fontsWaitingCallbacks;
for (var i = 0; i < callbacks.length; i++) {
callbacks[i]();
}
}
}.bind(this), 100);
}
},
ensureFonts: function(data, callback) {
var font;
var notLoaded = [];
for (var i = 0; i < data.length; i++) {
font = data[i];
if (Fonts[font.name]) {
continue;
}
// Store only the data on Fonts that is needed later on, such that we
// hold track on as lease memory as possible.
Fonts[font.name] = {
properties: {
charset: font.properties.charset
},
cache: Object.create(null)
};
// Mark this font to be handled later.
notLoaded.push(font);
// Increate the number of fonts to wait for.
this.fontsWaiting++;
}
// If there are fonts, that need to get loaded, tell the FontWorker to get
// started and push the callback on the waiting-callback-stack.
if (notLoaded.length != 0) {
// Send the worker the fonts to work on.
this.worker.postMessage({
action: "fonts",
data: notLoaded
});
if (callback) {
this.fontsWaitingCallbacks.push(callback);
}
}
// All fonts are present? Well, then just call the callback if there is one.
else {
if (callback) {
callback();
}
}
},
}
function WorkerPDFDoc(canvas) {
var timer = null
this.ctx = canvas.getContext("2d");
this.canvas = canvas;
this.worker = new Worker('worker/pdf.js');
this.fontWorker = new FontWorker();
this.waitingForFonts = false;
this.waitingForFontsCallback = [];
this.numPage = 1;
this.numPages = null;
@ -56,6 +159,7 @@ function WorkerPDFDoc(canvas) {
},
"$showText": function(y, text) {
text = Fonts.charsToUnicode(text);
this.translate(currentX, -1 * y);
this.fillText(text, 0, 0);
currentX += this.measureText(text).width;
@ -136,6 +240,10 @@ function WorkerPDFDoc(canvas) {
throw "Pattern not found";
}
this.strokeStyle = pattern;
},
"$setFont": function(name) {
Fonts.active = name;
}
}
@ -187,6 +295,17 @@ function WorkerPDFDoc(canvas) {
div.setAttribute("style", style);
document.body.appendChild(div);
},
"fonts": function(data) {
this.waitingForFonts = true;
this.fontWorker.ensureFonts(data, function() {
this.waitingForFonts = false;
var callbacks = this.waitingForFontsCallback;
for (var i = 0; i < callbacks.length; i++) {
callbacks[i]();
}
}.bind(this));
},
"jpeg_stream": function(data) {
var img = new Image();
@ -207,9 +326,7 @@ function WorkerPDFDoc(canvas) {
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() {
var renderData = function() {
if (id == 0) {
console.time("canvas rendering");
var ctx = this.ctx;
@ -220,11 +337,18 @@ function WorkerPDFDoc(canvas) {
}
renderProxyCanvas(canvasList[id], cmdQueue);
if (id == 0) console.timeEnd("canvas rendering")
}, 0, this);
}.bind(this);
if (this.waitingForFonts) {
console.log("want to render, but not all fonts are there", id);
this.waitingForFontsCallback.push(renderData);
} else {
renderData();
}
}
}
// List to the WebWorker for data and call actionHandler on it.
// Listen to the WebWorker for data and call actionHandler on it.
this.worker.onmessage = function(event) {
var data = event.data;
if (data.action in actionHandler) {
@ -232,7 +356,7 @@ function WorkerPDFDoc(canvas) {
} else {
throw "Unkown action from worker: " + data.action;
}
}
}.bind(this)
}
WorkerPDFDoc.prototype.open = function(url, callback) {