Merge branch 'master' of github.com:andreasgal/pdf.js
This commit is contained in:
commit
35f5fe3a16
38
fonts.js
38
fonts.js
@ -64,8 +64,8 @@ var Fonts = {
|
||||
var unicode = encoding[charcode];
|
||||
|
||||
// Check if the glyph has already been converted
|
||||
if (unicode instanceof Name)
|
||||
unicode = encoding[unicode] = GlyphsUnicode[unicode.name];
|
||||
if (!IsNum(unicode))
|
||||
unicode = encoding[unicode] = GlyphsUnicode[unicode.name];
|
||||
|
||||
// Handle surrogate pairs
|
||||
if (unicode > 0xFFFF) {
|
||||
@ -165,6 +165,7 @@ var Font = (function () {
|
||||
warn("Font " + properties.type + " is not supported");
|
||||
break;
|
||||
}
|
||||
this.data = data;
|
||||
|
||||
Fonts[name] = {
|
||||
data: data,
|
||||
@ -779,9 +780,18 @@ var Font = (function () {
|
||||
});
|
||||
},
|
||||
|
||||
bindDOM: function font_bindDom(data) {
|
||||
bindDOM: function font_bindDom(data, callback) {
|
||||
var fontName = this.name;
|
||||
|
||||
// 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);
|
||||
|
||||
/** Hack begin */
|
||||
// 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
|
||||
@ -801,15 +811,19 @@ var Font = (function () {
|
||||
|
||||
// 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 + " loaded?");
|
||||
this.start = 0;
|
||||
} else if (textWidth != ctx.measureText(testString).width) {
|
||||
window.clearInterval(interval);
|
||||
Fonts[fontName].loading = false;
|
||||
this.start = 0;
|
||||
if (textWidth == ctx.measureText(testString).width) {
|
||||
if ((Date.now() - this.start) < kMaxWaitForFontFace) {
|
||||
return;
|
||||
} else {
|
||||
warn("Is " + fontName + " loaded?");
|
||||
}
|
||||
}
|
||||
|
||||
window.clearInterval(interval);
|
||||
Fonts[fontName].loading = false;
|
||||
this.start = 0;
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}, 30, this);
|
||||
|
||||
|
37
pdf.js
37
pdf.js
@ -816,7 +816,7 @@ var DecryptStream = (function() {
|
||||
DecodeStream.call(this);
|
||||
}
|
||||
|
||||
const chunkSize = 512;
|
||||
var chunkSize = 512;
|
||||
|
||||
constructor.prototype = Object.create(DecodeStream.prototype);
|
||||
constructor.prototype.readBlock = function() {
|
||||
@ -910,18 +910,18 @@ var Ascii85Stream = (function() {
|
||||
|
||||
var CCITTFaxStream = (function() {
|
||||
|
||||
const ccittEOL = -2;
|
||||
const twoDimPass = 0;
|
||||
const twoDimHoriz = 1;
|
||||
const twoDimVert0 = 2;
|
||||
const twoDimVertR1 = 3;
|
||||
const twoDimVertL1 = 4;
|
||||
const twoDimVertR2 = 5;
|
||||
const twoDimVertL2 = 6;
|
||||
const twoDimVertR3 = 7;
|
||||
const twoDimVertL3 = 8;
|
||||
var ccittEOL = -2;
|
||||
var twoDimPass = 0;
|
||||
var twoDimHoriz = 1;
|
||||
var twoDimVert0 = 2;
|
||||
var twoDimVertR1 = 3;
|
||||
var twoDimVertL1 = 4;
|
||||
var twoDimVertR2 = 5;
|
||||
var twoDimVertL2 = 6;
|
||||
var twoDimVertR3 = 7;
|
||||
var twoDimVertL3 = 8;
|
||||
|
||||
const twoDimTable = [
|
||||
var twoDimTable = [
|
||||
[-1, -1], [-1, -1], // 000000x
|
||||
[7, twoDimVertL3], // 0000010
|
||||
[7, twoDimVertR3], // 0000011
|
||||
@ -989,7 +989,7 @@ var CCITTFaxStream = (function() {
|
||||
[1, twoDimVert0], [1, twoDimVert0]
|
||||
];
|
||||
|
||||
const whiteTable1 = [
|
||||
var whiteTable1 = [
|
||||
[-1, -1], // 00000
|
||||
[12, ccittEOL], // 00001
|
||||
[-1, -1], [-1, -1], // 0001x
|
||||
@ -1011,7 +1011,7 @@ var CCITTFaxStream = (function() {
|
||||
[12, 2560] // 11111
|
||||
];
|
||||
|
||||
const whiteTable2 = [
|
||||
var whiteTable2 = [
|
||||
[-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000000xx
|
||||
[8, 29], [8, 29], // 00000010x
|
||||
[8, 30], [8, 30], // 00000011x
|
||||
@ -1175,7 +1175,7 @@ var CCITTFaxStream = (function() {
|
||||
[4, 7], [4, 7], [4, 7], [4, 7]
|
||||
];
|
||||
|
||||
const blackTable1 = [
|
||||
var blackTable1 = [
|
||||
[-1, -1], [-1, -1], // 000000000000x
|
||||
[12, ccittEOL], [12, ccittEOL], // 000000000001x
|
||||
[-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000001xx
|
||||
@ -1236,7 +1236,7 @@ var CCITTFaxStream = (function() {
|
||||
[10, 64], [10, 64], [10, 64], [10, 64]
|
||||
];
|
||||
|
||||
const blackTable2 = [
|
||||
var blackTable2 = [
|
||||
[8, 13], [8, 13], [8, 13], [8, 13], // 00000100xxxx
|
||||
[8, 13], [8, 13], [8, 13], [8, 13],
|
||||
[8, 13], [8, 13], [8, 13], [8, 13],
|
||||
@ -1315,7 +1315,7 @@ var CCITTFaxStream = (function() {
|
||||
[7, 12], [7, 12], [7, 12], [7, 12]
|
||||
];
|
||||
|
||||
const blackTable3 = [
|
||||
var blackTable3 = [
|
||||
[-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000xx
|
||||
[6, 9], // 000100
|
||||
[6, 8], // 000101
|
||||
@ -3819,6 +3819,9 @@ var CanvasGraphics = (function() {
|
||||
|
||||
this.current.fontSize = size;
|
||||
this.ctx.font = this.current.fontSize +'px "' + fontName + '", Symbol';
|
||||
if (this.ctx.$setFont) {
|
||||
this.ctx.$setFont(fontName);
|
||||
}
|
||||
},
|
||||
setTextRenderingMode: function(mode) {
|
||||
TODO("text rendering mode");
|
||||
|
@ -1,7 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Simple pdf.js page worker viewer</title>
|
||||
<script type="text/javascript" src="worker_client.js"></script>
|
||||
<script type="text/javascript" src="fonts.js"></script>
|
||||
<script type="text/javascript" src="glyphlist.js"></script>
|
||||
<script type="text/javascript" src="pdf.js"></script>
|
||||
<script type="text/javascript" src="worker/client.js"></script>
|
||||
<script>
|
||||
|
||||
|
||||
|
@ -119,7 +119,8 @@ function CanvasProxy(width, height) {
|
||||
"$addCurrentX",
|
||||
"$saveCurrentX",
|
||||
"$restoreCurrentX",
|
||||
"$showText"
|
||||
"$showText",
|
||||
"$setFont"
|
||||
];
|
||||
|
||||
function buildFuncCall(name) {
|
@ -18,12 +18,124 @@ 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);
|
||||
|
||||
this.$handleFontLoadedCallback = this.handleFontLoadedCallback.bind(this);
|
||||
}
|
||||
|
||||
FontWorker.prototype = {
|
||||
handleFontLoadedCallback: function() {
|
||||
// Decrease the number of fonts wainting to be loaded.
|
||||
this.fontsWaiting--;
|
||||
// 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]();
|
||||
}
|
||||
this.fontsWaitingCallbacks.length = 0;
|
||||
}
|
||||
},
|
||||
|
||||
actionHandler: {
|
||||
"log": function(data) {
|
||||
console.log.apply(console, data);
|
||||
},
|
||||
|
||||
"fonts": function(data) {
|
||||
// console.log("got processed fonts from worker", Object.keys(data));
|
||||
for (name in data) {
|
||||
// Update the
|
||||
Fonts[name].properties = {
|
||||
encoding: data[name].encoding
|
||||
}
|
||||
|
||||
// Call `Font.prototype.bindDOM` to make the font get loaded on the page.
|
||||
Font.prototype.bindDOM.call(
|
||||
Fonts[name],
|
||||
data[name].str,
|
||||
// IsLoadedCallback.
|
||||
this.$handleFontLoadedCallback
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
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] = {
|
||||
name: font.name,
|
||||
mimetype: font.mimetype,
|
||||
// This is set later on the worker replay. For some fonts, the encoding
|
||||
// is calculated during the conversion process happening on the worker
|
||||
// and therefore is not available right now.
|
||||
// properties: {
|
||||
// encoding: font.properties.encoding
|
||||
// },
|
||||
cache: Object.create(null)
|
||||
};
|
||||
|
||||
// Mark this font to be handled later.
|
||||
notLoaded.push(font);
|
||||
// Increate the number of fonts to wait for.
|
||||
this.fontsWaiting++;
|
||||
}
|
||||
|
||||
console.time("ensureFonts");
|
||||
// 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) {
|
||||
console.log("fonts -> FontWorker");
|
||||
// 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('pdf_worker.js');
|
||||
this.worker = new Worker('worker/pdf.js');
|
||||
this.fontWorker = new FontWorker();
|
||||
this.waitingForFonts = false;
|
||||
this.waitingForFontsCallback = [];
|
||||
|
||||
this.numPage = 1;
|
||||
this.numPages = null;
|
||||
@ -56,6 +168,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 +249,10 @@ function WorkerPDFDoc(canvas) {
|
||||
throw "Pattern not found";
|
||||
}
|
||||
this.strokeStyle = pattern;
|
||||
},
|
||||
|
||||
"$setFont": function(name) {
|
||||
Fonts.active = name;
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,6 +304,18 @@ 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]();
|
||||
}
|
||||
this.waitingForFontsCallback.length = 0;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
"jpeg_stream": function(data) {
|
||||
var img = new Image();
|
||||
@ -207,11 +336,9 @@ 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");
|
||||
console.time("main canvas rendering");
|
||||
var ctx = this.ctx;
|
||||
ctx.save();
|
||||
ctx.fillStyle = "rgb(255, 255, 255)";
|
||||
@ -219,12 +346,27 @@ function WorkerPDFDoc(canvas) {
|
||||
ctx.restore();
|
||||
}
|
||||
renderProxyCanvas(canvasList[id], cmdQueue);
|
||||
if (id == 0) console.timeEnd("canvas rendering")
|
||||
}, 0, this);
|
||||
if (id == 0) {
|
||||
console.timeEnd("main canvas rendering");
|
||||
console.timeEnd(">>> total page display time:");
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
if (this.waitingForFonts) {
|
||||
if (id == 0) {
|
||||
console.log("want to render, but not all fonts are there", id);
|
||||
this.waitingForFontsCallback.push(renderData);
|
||||
} else {
|
||||
// console.log("assume canvas doesn't have fonts", id);
|
||||
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 +374,7 @@ function WorkerPDFDoc(canvas) {
|
||||
} else {
|
||||
throw "Unkown action from worker: " + data.action;
|
||||
}
|
||||
}
|
||||
}.bind(this)
|
||||
}
|
||||
|
||||
WorkerPDFDoc.prototype.open = function(url, callback) {
|
||||
@ -255,6 +397,8 @@ WorkerPDFDoc.prototype.open = function(url, callback) {
|
||||
|
||||
WorkerPDFDoc.prototype.showPage = function(numPage) {
|
||||
this.numPage = parseInt(numPage);
|
||||
console.log("=== start rendering page " + numPage + " ===");
|
||||
console.time(">>> total page display time:");
|
||||
this.worker.postMessage(numPage);
|
||||
if (this.onChangePage) {
|
||||
this.onChangePage(numPage);
|
27
worker/console.js
Normal file
27
worker/console.js
Normal file
@ -0,0 +1,27 @@
|
||||
/* -*- 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 consoleTimer = {};
|
||||
var console = {
|
||||
log: function log() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
postMessage({
|
||||
action: "log",
|
||||
data: args
|
||||
});
|
||||
},
|
||||
|
||||
time: function(name) {
|
||||
consoleTimer[name] = Date.now();
|
||||
},
|
||||
|
||||
timeEnd: function(name) {
|
||||
var time = consoleTimer[name];
|
||||
if (time == null) {
|
||||
throw "Unkown timer name " + name;
|
||||
}
|
||||
this.log("Timer:", name, Date.now() - time);
|
||||
}
|
||||
}
|
65
worker/font.js
Normal file
65
worker/font.js
Normal file
@ -0,0 +1,65 @@
|
||||
/* -*- 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;
|
||||
}
|
||||
}
|
@ -27,10 +27,11 @@ var console = {
|
||||
}
|
||||
|
||||
//
|
||||
importScripts("canvas_proxy.js");
|
||||
importScripts("pdf.js");
|
||||
importScripts("fonts.js");
|
||||
importScripts("glyphlist.js")
|
||||
importScripts("console.js")
|
||||
importScripts("canvas.js");
|
||||
importScripts("../pdf.js");
|
||||
importScripts("../fonts.js");
|
||||
importScripts("../glyphlist.js")
|
||||
|
||||
// Use the JpegStreamProxy proxy.
|
||||
JpegStream = JpegStreamProxy;
|
||||
@ -65,21 +66,14 @@ onmessage = function(event) {
|
||||
page.compile(gfx, fonts);
|
||||
console.timeEnd("compile");
|
||||
|
||||
// Send fonts to the main thread.
|
||||
console.time("fonts");
|
||||
// Inspect fonts and translate the missing one.
|
||||
var count = fonts.length;
|
||||
for (var i = 0; i < count; i++) {
|
||||
var font = fonts[i];
|
||||
if (Fonts[font.name]) {
|
||||
fontsReady = fontsReady && !Fonts[font.name].loading;
|
||||
continue;
|
||||
}
|
||||
|
||||
// This "builds" the font and sents it over to the main thread.
|
||||
new Font(font.name, font.file, font.properties);
|
||||
}
|
||||
postMessage({
|
||||
action: "fonts",
|
||||
data: fonts
|
||||
});
|
||||
console.timeEnd("fonts");
|
||||
|
||||
|
||||
console.time("display");
|
||||
page.display(gfx);
|
||||
canvas.flush();
|
Loading…
Reference in New Issue
Block a user