};
}
+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;
},
"$showText": function(y, text) {
+ text = Fonts.charsToUnicode(text);
this.translate(currentX, -1 * y);
this.fillText(text, 0, 0);
currentX += this.measureText(text).width;
throw "Pattern not found";
}
this.strokeStyle = pattern;
+ },
+
+ "$setFont": function(name) {
+ Fonts.active = name;
}
}
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();
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;
}
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) {
} else {
throw "Unkown action from worker: " + data.action;
}
- }
+ }.bind(this)
}
WorkerPDFDoc.prototype.open = function(url, callback) {
--- /dev/null
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+"use strict";
+
+importScripts("console.js");
+
+importScripts("../pdf.js");
+importScripts("../fonts.js");
+importScripts("../glyphlist.js")
+
+function fontDataToString(font) {
+ // Doing postMessage on objects make them lose their "shape". This adds the
+ // "shape" for all required objects agains, such that the encoding works as
+ // expected.
+ var fontFileDict = new Dict();
+ fontFileDict.map = font.file.dict.map;
+
+ var fontFile = new Stream(font.file.bytes, font.file.start, font.file.end - font.file.start, fontFileDict);
+ font.file = new FlateStream(fontFile);
+
+ // This will encode the font.
+ var fontObj = new Font(font.name, font.file, font.properties);
+
+ // Create string that is used for css later.
+ var str = "";
+ var data = fontObj.data;
+ var length = data.length;
+ for (var j = 0; j < length; j++)
+ str += String.fromCharCode(data[j]);
+
+ return {
+ str: str,
+ encoding: font.properties.encoding
+ }
+}
+
+/**
+* Functions to handle data sent by the MainThread.
+*/
+var actionHandler = {
+ "fonts": function(data) {
+ var fontData;
+ var result = {};
+ for (var i = 0; i < data.length; i++) {
+ fontData = data[i];
+ result[fontData.name] = fontDataToString(fontData);
+ }
+
+ postMessage({
+ action: "fonts",
+ data: result
+ })
+ },
+}
+
+// Listen to the MainThread for data and call actionHandler on it.
+this.onmessage = function(event) {
+ var data = event.data;
+ if (data.action in actionHandler) {
+ actionHandler[data.action].call(this, data.data);
+ } else {
+ throw "Unkown action from worker: " + data.action;
+ }
+}
\ No newline at end of file