},
startRendering: function(canvasCtx, continuation) {
+ var gfx = new CanvasGraphics(canvasCtx);
+
+ // If there is already some code to render, then use it directly.
+ if (this.code) {
+ this.display(gfx);
+ return;
+ }
+
var self = this;
var stats = self.stats;
stats.compile = stats.fonts = stats.render = 0;
-
- var gfx = new CanvasGraphics(canvasCtx);
+
var fonts = [];
var images = new ImagesLoader();
- this.compile(gfx, fonts, images);
+ var preCompilation = this.preCompile(gfx, fonts, images);
stats.compile = Date.now();
-
- var displayContinuation = function() {
- // Always defer call to display() to work around bug in
- // Firefox error reporting from XHR callbacks.
- setTimeout(function() {
- var exc = null;
- // try {
- self.display(gfx);
- stats.render = Date.now();
- // } catch (e) {
- // exc = e.toString();
- // }
- continuation(exc);
- });
- };
// Make a copy of the necessary datat to build a font later. The `font`
// object will be sent to the main thread later on.
fonts = [];
for (var i = 0; i < fontsBackup.length; i++) {
var orgFont = fontsBackup[i];
- var orgFontObj = orgFont.fontObj;
var font = {
name: orgFont.name,
fonts.push(font);
}
+ this.startRenderingFromPreCompilation(gfx, preCompilation, fonts, images, continuation);
+ },
+
+ startRenderingFromPreCompilation: function(gfx, preCompilation, fonts, images, continuation) {
+ var self = this;
+
+ var displayContinuation = function() {
+ self.code = gfx.postCompile(preCompilation);
+
+ // Always defer call to display() to work around bug in
+ // Firefox error reporting from XHR callbacks.
+ setTimeout(function() {
+ var exc = null;
+ // try {
+ self.display(gfx);
+ stats.render = Date.now();
+ // } catch (e) {
+ // exc = e.toString();
+ // }
+ continuation(exc);
+ });
+ };
+
this.ensureFonts(fonts, function() {
images.notifyOnLoad(function() {
stats.images = Date.now();
content[i] = xref.fetchIfRef(content[i]);
content = new StreamsSequenceStream(content);
}
- return gfx.preCompile(content, xref, resources, fonts, images);
- },
-
- compile: function(gfx, fonts, images) {
- var preCompilation = this.preCompile(gfx, fonts, images);
- this.code = gfx.postCompile(preCompilation);
+ return gfx.preCompile(content, xref, resources, fonts, images,
+ this.pageNumber + "_");
},
ensureFonts: function(fonts, callback) {
<script type="text/javascript" src="../glyphlist.js"></script>
<script type="text/javascript" src="../metrics.js"></script>
<script type="text/javascript" src="../worker.js"></script>
+ <script type="text/javascript" src="../worker/message_handler.js"></script>
</head>
<body>
},
startRendering: function(ctx, callback, errback) {
+ this.ctx = ctx;
+ this.callback = callback;
// TODO: Place the worker magic HERE.
- this.page.startRendering(ctx, callback, errback);
+ // this.page.startRendering(ctx, callback, errback);
+
+ this.workerPDF.startRendering(this)
+ },
+
+ startRenderingFromPreCompilation: function(preCompilation, fonts, images) {
+ var gfx = new CanvasGraphics(this.ctx);
+
+ // TODO: Add proper handling for images loaded by the worker.
+ var images = new ImagesLoader();
+
+ this.page.startRenderingFromPreCompilation(gfx, preCompilation, fonts, images, this.callback);
},
getLinks: function() {
this.catalog = this.pdf.catalog;
this.pageCache = [];
+
+ this.worker = new Worker("worker/boot.js");
+ this.handler = new MessageHandler({
+ "page": function(data) {
+ var pageNum = data.pageNum;
+ var page = this.pageCache[pageNum];
+
+ page.startRenderingFromPreCompilation(data.preCompilation, data.fonts, data.images);
+ }
+ }, this.worker.postMessage, this);
+ this.worker.onmessage = this.handler.onMessage;
+
+ this.handler.send("doc", data);
}
constructor.prototype = {
return this.pdf.numPages;
},
+ startRendering: function(page) {
+ this.handler.send("page", page.page.pageNumber);
+ },
+
getPage: function(n) {
if (this.pageCache[n]) {
return this.pageCache[n];
--- /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('event_handler.js');
+importScripts('../pdf.js');
+importScripts('../fonts.js');
+importScripts('../crypto.js');
+importScripts('../glyphlist.js');
+
+// Listen for messages from the main thread.
+var pdfDoc = null;
+
+var handler = new MessageHandler({
+ "doc": function(data) {
+ pdfDocument = new PDFDoc(new Stream(data));
+ console.log("setup pdfDoc");
+ },
+
+ "page": function(pageNum) {
+ pageNum = parseInt(pageNum);
+ console.log("about to process page", pageNum);
+
+ var page = pdfDocument.getPage(pageNum);
+
+ // The following code does quite the same as Page.prototype.startRendering,
+ // but stops at one point and sends the result back to the main thread.
+ var gfx = new CanvasGraphics(canvasCtx);
+ var fonts = [];
+ // TODO: Figure out how image loading is handled inside the worker.
+ var images = new ImagesLoader();
+
+ // Pre compile the pdf page and fetch the fonts/images.
+ var preCompilation = page.preCompile(gfx, fonts, images);
+
+ // Extract the minimum of font data that is required to build all required
+ // font stuff on the main thread.
+ var fontsMin = [];
+ for (var i = 0; i < fonts.length; i++) {
+ var font = fonts[i];
+
+ fontsMin.push({
+ name: orgFont.name,
+ file: orgFont.file,
+ properties: orgFont.properties
+ });
+ }
+
+ // TODO: Handle images here.
+
+ handler.send("page", {
+ pageNum: pageNum,
+ fonts: fontsMin,
+ images: [],
+ preCompilation: preCompilation,
+ });
+ }
+}, postMessage);
+
+onmessage = handler.onMessage;
var args = Array.prototype.slice.call(arguments);
postMessage({
action: 'log',
- data: args
+ data: args
});
},
--- /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';
+
+
+function MessageHandler(actionHandler, postMessage, scope) {
+ this.onMessage = function(event) {
+ var data = event.data;
+ if (data.action in actionHandler) {
+ actionHandler[data.action].call(scope, data.data);
+ } else {
+ throw 'Unkown action from worker: ' + data.action;
+ }
+ };
+
+ this.send = function(actionName, data) {
+ postMessage({
+ action: actionName,
+ data: data
+ });
+ }
+}
\ No newline at end of file
+++ /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';
-
-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);
- }
-};
-
-//
-importScripts('console.js');
-importScripts('canvas.js');
-importScripts('../pdf.js');
-importScripts('../fonts.js');
-importScripts('../crypto.js');
-importScripts('../glyphlist.js');
-
-// Use the JpegStreamProxy proxy.
-JpegStream = JpegStreamProxy;
-
-// Create the WebWorkerProxyCanvas.
-var canvas = new CanvasProxy(1224, 1584);
-
-// Listen for messages from the main thread.
-var pdfDocument = null;
-onmessage = function(event) {
- var data = event.data;
- // If there is no pdfDocument yet, then the sent data is the PDFDocument.
- if (!pdfDocument) {
- pdfDocument = new PDFDoc(new Stream(data));
- postMessage({
- action: 'pdf_num_pages',
- data: pdfDocument.numPages
- });
- return;
- }
- // User requested to render a certain page.
- else {
- console.time('compile');
-
- // Let's try to render the first page...
- var page = pdfDocument.getPage(parseInt(data));
-
- var pdfToCssUnitsCoef = 96.0 / 72.0;
- var pageWidth = (page.mediaBox[2] - page.mediaBox[0]) * pdfToCssUnitsCoef;
- var pageHeight = (page.mediaBox[3] - page.mediaBox[1]) * pdfToCssUnitsCoef;
- postMessage({
- action: 'setup_page',
- data: pageWidth + ',' + pageHeight
- });
-
- // Set canvas size.
- canvas.width = pageWidth;
- canvas.height = pageHeight;
-
- // page.compile will collect all fonts for us, once we have loaded them
- // we can trigger the actual page rendering with page.display
- var fonts = [];
- var gfx = new CanvasGraphics(canvas.getContext('2d'), CanvasProxy);
- page.compile(gfx, fonts);
- console.timeEnd('compile');
-
- // Send fonts to the main thread.
- console.time('fonts');
- postMessage({
- action: 'fonts',
- data: fonts
- });
- console.timeEnd('fonts');
-
- console.time('display');
- page.display(gfx);
- canvas.flush();
- console.timeEnd('display');
- }
-};