--- /dev/null
+function CanvasProxy(width, height) {
+ var stack = this.$stack = [];
+
+ // Expose only the minimum of the canvas object - there is no dom to do
+ // more here.
+ this.canvas = {
+ width: width,
+ height: height
+ }
+
+ var ctxFunc = [
+ "createRadialGradient",
+ "arcTo",
+ "arc",
+ "fillText",
+ "strokeText",
+ "drawImage",
+ "getImageData",
+ "putImageData",
+ "createImageData",
+ "drawWindow",
+ "save",
+ "restore",
+ "scale",
+ "rotate",
+ "translate",
+ "transform",
+ "setTransform",
+ "createLinearGradient",
+ "createPattern",
+ "clearRect",
+ "fillRect",
+ "strokeRect",
+ "beginPath",
+ "closePath",
+ "moveTo",
+ "lineTo",
+ "quadraticCurveTo",
+ "bezierCurveTo",
+ "rect",
+ "fill",
+ "stroke",
+ "clip",
+ "measureText",
+ "isPointInPath"
+ ];
+ function buildFuncCall(name) {
+ return function() {
+ console.log("funcCall", name)
+ stack.push([name, Array.prototype.slice.call(arguments)]);
+ }
+ }
+ var name;
+ for (var i = 0; i < ctxFunc.length; i++) {
+ name = ctxFunc[i];
+ this[name] = buildFuncCall(name);
+ }
+
+ var ctxProp = {
+ // "canvas"
+ "globalAlpha": "1",
+ "globalCompositeOperation": "source-over",
+ "strokeStyle": "#000000",
+ "fillStyle": "#000000",
+ "lineWidth": "1",
+ "lineCap": "butt",
+ "lineJoin": "miter",
+ "miterLimit": "10",
+ "shadowOffsetX": "0",
+ "shadowOffsetY": "0",
+ "shadowBlur": "0",
+ "shadowColor": "rgba(0, 0, 0, 0)",
+ "font": "10px sans-serif",
+ "textAlign": "start",
+ "textBaseline": "alphabetic",
+ "mozTextStyle": "10px sans-serif",
+ "mozImageSmoothingEnabled": "true",
+ "DRAWWINDOW_DRAW_CARET": "1",
+ "DRAWWINDOW_DO_NOT_FLUSH": "2",
+ "DRAWWINDOW_DRAW_VIEW": "4",
+ "DRAWWINDOW_USE_WIDGET_LAYERS": "8",
+ "DRAWWINDOW_ASYNC_DECODE_IMAGES": "16",
+ }
+
+ function buildGetter(name) {
+ return function() {
+ return this["$" + name];
+ }
+ }
+
+ function buildSetter(name) {
+ return function(value) {
+ stack.push(["$", name, value]);
+ return this["$" + name] = value;
+ }
+ }
+
+ for (var name in ctxProp) {
+ this["$" + name] = ctxProp[name];
+ this.__defineGetter__(name, buildGetter(name));
+ this.__defineSetter__(name, buildSetter(name));
+ }
+}
+
+CanvasProxy.prototype.flush = function() {
+ postMessage("canvas_proxy_stack");
+ postMessage(JSON.stringify(this.$stack));
+ this.$stack.length = 0;
+}
this.pendingClip = null;
this.res = null;
this.xobjs = null;
- this.map = {
+ }
+
+ constructor.prototype = {
+ map: {
// Graphics state
w: "setLineWidth",
J: "setLineCap",
}
var fn = Function("objpool", src);
- return function (gfx) { fn.call(gfx, objpool); };
+ var ret = function (gfx) { fn.call(gfx, objpool); };
+ ret.src = src;
+ return ret;
},
endDrawing: function() {
shadingFill: function(entryRef) {
var xref = this.xref;
var res = this.res;
+
var shadingRes = xref.fetchIfRef(res.get("Shading"));
if (!shadingRes)
error("No shading resource found");
break;
case "ICCBased":
var dict = stream.dict;
+
this.stream = stream;
this.dict = dict;
this.numComps = dict.get("N");
v = encode[i2] + ((v - domain[i2]) *
(encode[i2 + 1] - encode[i2]) /
(domain[i2 + 1] - domain[i2]));
+
// clip to the size
args[i] = clip(v, 0, size[i] - 1);
}
// decode
v = decode[i2] + (v * (decode[i2 + 1] - decode[i2]) /
((1 << bps) - 1));
+
// clip to the domain
output.push(clip(v, range[i2], range[i2 + 1]));
}
--- /dev/null
+<html>
+ <head>
+ <title>Simple pdf.js page viewer worker</title>
+<script>
+var myWorker = new Worker('worker.js');
+
+// var array = new Uint8Array(2);
+// array[0] = 1;
+// array[1] = 300;
+//
+const WAIT = 0;
+const CANVAS_PROXY_STACK = 1;
+const LOG = 2;
+
+var onMessageState = WAIT;
+myWorker.onmessage = function(event) {
+ var data = event.data;
+ console.log("onMessageRaw", data);
+ switch (onMessageState) {
+ case WAIT:
+ if (typeof data != "string") {
+ throw "expecting to get an string";
+ }
+ switch (data) {
+ case "log":
+ onMessageState = LOG;
+ return;
+ case "canvas_proxy_stack":
+ onMessageState = CANVAS_PROXY_STACK;
+ return;
+ default:
+ throw "unkown state: " + data
+ }
+ break;
+
+ case LOG:
+ console.log.apply(console, JSON.parse(data));
+ onMessageState = WAIT;
+ break;
+
+ case CANVAS_PROXY_STACK:
+ var stack = JSON.parse(data);
+ for (var i = 0; i < stack.length; i++) {
+ var opp = stack[i];
+ if (opp[0] == "$") {
+ console.log("set property", opp[1], opp[2]);
+ ctx[opp[1]] = opp[2];
+ } else {
+ console.log("execute", opp[0], opp[1]);
+ ctx[opp[0]].apply(ctx, opp[1]);
+ }
+ }
+ onMessageState = WAIT;
+ break;
+ }
+}
+//
+// myWorker.postMessage(array);
+
+function open(url) {
+ document.title = url;
+ var req = new XMLHttpRequest();
+ req.open("GET", url);
+ req.mozResponseType = req.responseType = "arraybuffer";
+ req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200;
+ req.onreadystatechange = function() {
+ if (req.readyState == 4 && req.status == req.expected) {
+ var data = req.mozResponseArrayBuffer || req.mozResponse ||
+ req.responseArrayBuffer || req.response;
+ myWorker.postMessage(data);
+ }
+ };
+ req.send(null);
+}
+
+window.onload = function() {
+ var ctx = window.ctx = document.getElementById("canvas").getContext("2d");
+ // for (var name in ctx) {
+ // if (!(ctx[name] instanceof Function)) {
+ // console.log('"' + name + '": "' + ctx[name] + '",');
+ // }
+ // }
+ open("compressed.tracemonkey-pldi-09.pdf");
+}
+</script>
+ <link rel="stylesheet" href="viewer.css"></link>
+ </head>
+
+ <body>
+ <div id="controls">
+ <input type="file" style="float: right; margin: auto 32px;" onChange="load(this.value.toString());"></input>
+ <!-- This only opens supported PDFs from the source path...
+ -- Can we use JSONP to overcome the same-origin restrictions? -->
+ <button onclick="prevPage();">Previous</button>
+ <button onclick="nextPage();">Next</button>
+ <input type="text" id="pageNumber" onchange="gotoPage(this.value);"
+ value="1" size="4"></input>
+ <span id="numPages">--</span>
+ <span id="info"></span>
+ </div>
+
+ <div id="viewer">
+ <!-- Canvas dimensions must be specified in CSS pixels. CSS pixels
+ are always 96 dpi. 816x1056 is 8.5x11in at 96dpi. -->
+ <!-- We're rendering here at 1.5x scale. -->
+ <canvas id="canvas" width="1224" height="1584"></canvas>
+ </div>
+ </body>
+</html>
+
--- /dev/null
+"use strict";
+
+function log() {
+ var args = Array.prototype.slice.call(arguments);
+ postMessage("log");
+ postMessage(JSON.stringify(args))
+}
+
+var console = {
+ log: log
+}
+
+importScripts("canvas_proxy.js");
+importScripts("pdf.js");
+importScripts("fonts.js");
+importScripts("glyphlist.js")
+
+// var array = new Uint8Array(2);
+// array[0] = 1;
+// array[1] = 300;
+// postMessage(array);
+
+var timer = null;
+function tic() {
+ timer = Date.now();
+}
+
+function toc(msg) {
+ log("Took ", (Date.now() - timer));
+ timer = null;
+}
+
+
+var canvas = new CanvasProxy(1224, 1584);
+// canvas.moveTo(0, 10);
+// canvas.lineTo(0, 20);
+// canvas.lineTo(500, 500);
+// canvas.flush();
+// canvas.stroke();
+// canvas.flush();
+log("test");
+
+onmessage = function(event) {
+ var data = event.data;
+ var pdfDocument = new PDFDoc(new Stream(data));
+ var numPages = pdfDocument.numPages;
+
+ tic();
+ // Let's try to render the first page...
+ var page = pdfDocument.getPage(1);
+
+ // 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);
+ page.compile(gfx, fonts);
+ toc("compiled page");
+
+ //
+ var fontsReady = true;
+ // 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;
+ }
+
+ new Font(font.name, font.file, font.properties);
+ fontsReady = false;
+ }
+
+ function delayLoadFont() {
+ for (var i = 0; i < count; i++) {
+ if (Fonts[font.name].loading)
+ return;
+ }
+ clearInterval(pageInterval);
+ page.display(gfx);
+
+ canvas.flush();
+ };
+
+ if (fontsReady) {
+ delayLoadFont();
+ } else {
+ pageInterval = setInterval(delayLoadFont, 10);
+ }
+ postMessage(page.code.src);
+}
+
+// function open(url) {
+// var req = new XMLHttpRequest();
+// req.open("GET", url);
+// // req.responseType = "arraybuffer";
+// req.expected = 0;//(document.URL.indexOf("file:") == 0) ? 0 : 200;
+// req.onreadystatechange = function() {
+// postMessage("loaded");
+// if (req.readyState == 4 && req.status == req.expected) {
+// var data = req.mozResponseArrayBuffer || req.mozResponse ||
+// req.responseArrayBuffer || req.response;
+// pdfDocument = new PDFDoc(new Stream(data));
+// numPages = pdfDocument.numPages;
+// // document.getElementById("numPages").innerHTML = numPages.toString();
+// // goToPage(pageNum);
+// }
+// };
+// req.send(null);
+// }
+//
+// open("compressed.tracemonkey-pldi-09.pdf")
\ No newline at end of file