From a8dcb0dcd68635a41875617d33b700d4a9467e1e Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Wed, 22 Jun 2011 01:28:17 +0200 Subject: [PATCH] Most working, but once you add the font-css file to the web page, there is no font drawn at all --- canvas_proxy.js | 12 +++- fonts.js | 146 +++++++++++++++++++++++++-------------------- pdf.js | 34 +++++++++-- viewer_worker.html | 95 +++++++++++++++++++++++++---- worker.js | 56 +++++++++-------- 5 files changed, 235 insertions(+), 108 deletions(-) diff --git a/canvas_proxy.js b/canvas_proxy.js index 1b100beae..433166aac 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -42,11 +42,17 @@ function CanvasProxy(width, height) { "stroke", "clip", "measureText", - "isPointInPath" + "isPointInPath", + + "$setCurrentX", + "$addCurrentX", + "$saveCurrentX", + "$restoreCurrentX", + "$showText" ]; function buildFuncCall(name) { return function() { - console.log("funcCall", name) + // console.log("funcCall", name) stack.push([name, Array.prototype.slice.call(arguments)]); } } @@ -103,6 +109,8 @@ function CanvasProxy(width, height) { } CanvasProxy.prototype.flush = function() { + // postMessage("log"); + // postMessage(JSON.stringify([this.$stack.length])); postMessage("canvas_proxy_stack"); postMessage(JSON.stringify(this.$stack)); this.$stack.length = 0; diff --git a/fonts.js b/fonts.js index d5943b7a3..8c0abbcec 100644 --- a/fonts.js +++ b/fonts.js @@ -759,91 +759,109 @@ var Font = (function () { var data = this.font; var fontName = this.name; + var isWorker = (typeof window == "undefined"); /** Hack begin */ + if (!isWorker) { - // 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 - var canvas = document.createElement("canvas"); - var style = "border: 1px solid black; position:absolute; top: " + - (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; - canvas.setAttribute("style", style); - canvas.setAttribute("width", 340); - canvas.setAttribute("heigth", 100); - document.body.appendChild(canvas); + // 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 + var canvas = document.createElement("canvas"); + var style = "border: 1px solid black; position:absolute; top: " + + (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; + canvas.setAttribute("style", style); + canvas.setAttribute("width", 340); + canvas.setAttribute("heigth", 100); + document.body.appendChild(canvas); - // Get the font size canvas think it will be for 'spaces' - var ctx = canvas.getContext("2d"); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - var testString = " "; + // Get the font size canvas think it will be for 'spaces' + var ctx = canvas.getContext("2d"); + ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; + var testString = " "; - // When debugging use the characters provided by the charsets to visually - // see what's happening instead of 'spaces' - var debug = false; - if (debug) { - var name = document.createElement("font"); - name.setAttribute("style", "position: absolute; left: 20px; top: " + - (100 * fontCount + 60) + "px"); - name.innerHTML = fontName; - document.body.appendChild(name); + // When debugging use the characters provided by the charsets to visually + // see what's happening instead of 'spaces' + var debug = false; + if (debug) { + var name = document.createElement("font"); + name.setAttribute("style", "position: absolute; left: 20px; top: " + + (100 * fontCount + 60) + "px"); + name.innerHTML = fontName; + document.body.appendChild(name); - // Retrieve font charset - var charset = Fonts[fontName].properties.charset || []; + // Retrieve font charset + var charset = Fonts[fontName].properties.charset || []; - // if the charset is too small make it repeat a few times - var count = 30; - while (count-- && charset.length <= 30) - charset = charset.concat(charset.slice()); + // if the charset is too small make it repeat a few times + var count = 30; + while (count-- && charset.length <= 30) + charset = charset.concat(charset.slice()); - for (var i = 0; i < charset.length; i++) { - var unicode = GlyphsUnicode[charset[i]]; - if (!unicode) - continue; - testString += String.fromCharCode(unicode); - } + for (var i = 0; i < charset.length; i++) { + var unicode = GlyphsUnicode[charset[i]]; + if (!unicode) + continue; + testString += String.fromCharCode(unicode); + } - ctx.fillText(testString, 20, 20); - } + ctx.fillText(testString, 20, 20); + } - // Periodicaly check for the width of the testString, it will be - // different once the real font has loaded - var textWidth = ctx.measureText(testString).width; + // Periodicaly check for the width of the testString, it will be + // different once the real font has loaded + var textWidth = ctx.measureText(testString).width; - var interval = window.setInterval(function canvasInterval(self) { - this.start = this.start || Date.now(); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; + var interval = window.setInterval(function canvasInterval(self) { + this.start = this.start || Date.now(); + ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - // 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 + " for charset: " + charset + " loaded?"); - this.start = 0; - } else if (textWidth != ctx.measureText(testString).width) { - window.clearInterval(interval); - Fonts[fontName].loading = false; - this.start = 0; - } + // 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 + " for charset: " + charset + " loaded?"); + this.start = 0; + } else if (textWidth != ctx.measureText(testString).width) { + window.clearInterval(interval); + Fonts[fontName].loading = false; + this.start = 0; + } - if (debug) - ctx.fillText(testString, 20, 50); - }, 30, this); + if (debug) + ctx.fillText(testString, 20, 50); + }, 30, this); + } /** Hack end */ - + // // Get the base64 encoding of the binary font data var str = ""; var length = data.length; for (var i = 0; i < length; ++i) str += String.fromCharCode(data[i]); - var base64 = window.btoa(str); + if (isWorker) { + postMessage("font"); + postMessage(JSON.stringify({ + str: str, + mimetype: this.mimetype, + fontName: fontName, + })); - // Add the @font-face rule to the document - var url = "url(data:" + this.mimetype + ";base64," + base64 + ");"; - var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; - var styleSheet = document.styleSheets[0]; - styleSheet.insertRule(rule, styleSheet.length); + setTimeout(function() { + Fonts[fontName].loading = false; + }, kMaxWaitForFontFace); + } else { + var base64 = window.btoa(str); + + // Add the @font-face rule to the document + var url = "url(data:" + this.mimetype + ";base64," + base64 + ");"; + var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; + var styleSheet = document.styleSheets[0]; + styleSheet.insertRule(rule, styleSheet.length); + console.log("added font", fontName); + console.log(rule); + } } }; diff --git a/pdf.js b/pdf.js index 09d1c874e..80e9c1930 100644 --- a/pdf.js +++ b/pdf.js @@ -2674,12 +2674,18 @@ var CanvasGraphics = (function() { }, save: function() { this.ctx.save(); + if (this.ctx.$saveCurrentX) { + this.ctx.$saveCurrentX(); + } this.stateStack.push(this.current); this.current = new CanvasExtraState(); }, restore: function() { var prev = this.stateStack.pop(); if (prev) { + if (this.ctx.$restoreCurrentX) { + this.ctx.$restoreCurrentX(); + } this.current = prev; this.ctx.restore(); } @@ -2760,6 +2766,9 @@ var CanvasGraphics = (function() { // Text beginText: function() { this.current.textMatrix = IDENTITY_MATRIX; + if (this.ctx.$setCurrentX) { + this.ctx.$setCurrentX(0) + } this.current.x = this.current.lineX = 0; this.current.y = this.current.lineY = 0; }, @@ -2814,6 +2823,9 @@ var CanvasGraphics = (function() { moveText: function (x, y) { this.current.x = this.current.lineX += x; this.current.y = this.current.lineY += y; + if (this.ctx.$setCurrentX) { + this.ctx.$setCurrentX(this.current.x) + } }, setLeadingMoveText: function(x, y) { this.setLeading(-y); @@ -2821,6 +2833,10 @@ var CanvasGraphics = (function() { }, setTextMatrix: function(a, b, c, d, e, f) { this.current.textMatrix = [ a, b, c, d, e, f ]; + + if (this.ctx.$setCurrentX) { + this.$setCurrentX(0) + } this.current.x = this.current.lineX = 0; this.current.y = this.current.lineY = 0; }, @@ -2831,11 +2847,15 @@ var CanvasGraphics = (function() { this.ctx.save(); this.ctx.transform.apply(this.ctx, this.current.textMatrix); this.ctx.scale(1, -1); - this.ctx.translate(0, -2 * this.current.y); - text = Fonts.charsToUnicode(text); - this.ctx.fillText(text, this.current.x, this.current.y); - this.current.x += this.ctx.measureText(text).width; + if (this.ctx.$showText) { + this.ctx.$showText(this.current.y, Fonts.charsToUnicode(text)); + } else { + console.log(text, this.current.x); + text = Fonts.charsToUnicode(text); + this.ctx.fillText(text, 0, 0); + this.current.x += this.ctx.measureText(text).width; + } this.ctx.restore(); }, @@ -2843,7 +2863,11 @@ var CanvasGraphics = (function() { for (var i = 0; i < arr.length; ++i) { var e = arr[i]; if (IsNum(e)) { - this.current.x -= e * 0.001 * this.current.fontSize; + if (this.ctx.$addCurrentX) { + this.ctx.$addCurrentX(-e * 0.001 * this.current.fontSize) + } else { + this.current.x -= e * 0.001 * this.current.fontSize; + } } else if (IsString(e)) { this.showText(e); } else { diff --git a/viewer_worker.html b/viewer_worker.html index f9e1f0b32..dde249e55 100644 --- a/viewer_worker.html +++ b/viewer_worker.html @@ -11,11 +11,63 @@ var myWorker = new Worker('worker.js'); const WAIT = 0; const CANVAS_PROXY_STACK = 1; const LOG = 2; +const FONT = 3; + +var currentX = 0; +var currentXStack = []; +var special = { + "$setCurrentX": function(value) { + currentX = value; + }, + + "$addCurrentX": function(value) { + currentX += value; + }, + + "$saveCurrentX": function() { + currentXStack.push(currentX); + }, + + "$restoreCurrentX": function() { + currentX = currentXStack.pop(); + }, + + "$showText": function(y, text) { + console.log(text, currentX, y, this.measureText(text).width); + + this.translate(currentX, -1 * y); + this.fillText(text, 0, 0); + currentX += this.measureText(text).width; + } +} + +function renderProxyCanvas(stack) { + // for (var i = 0; i < stack.length; i++) { + for (var i = 0; i < 1000; i++) { + var opp = stack[i]; + if (opp[0] == "$") { + // console.log("set property", opp[1], opp[2]); + if (opp[1] == "font") { + ctx[opp[1]] = opp[2]; + // console.log("font", opp[2]); + } else { + ctx[opp[1]] = opp[2]; + } + + } else if (opp[0] in special) { + // console.log("sepcial", opp[0], opp[1]) + special[opp[0]].apply(ctx, opp[1]); + } else { + // console.log("execute", opp[0], opp[1]); + ctx[opp[0]].apply(ctx, opp[1]); + } + } +} var onMessageState = WAIT; myWorker.onmessage = function(event) { var data = event.data; - console.log("onMessageRaw", data); + // console.log("onMessageRaw", data); switch (onMessageState) { case WAIT: if (typeof data != "string") { @@ -28,11 +80,31 @@ myWorker.onmessage = function(event) { case "canvas_proxy_stack": onMessageState = CANVAS_PROXY_STACK; return; + case "font": + onMessageState = FONT; + return; default: throw "unkown state: " + data } break; + case FONT: + data = JSON.parse(data); + var base64 = window.btoa(data.str); + + // Add the @font-face rule to the document + var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; + var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; + var styleSheet = document.styleSheets[0]; + + // ONCE you uncomment this, there is no font painted at all :( + // styleSheet.insertRule(rule, styleSheet.length); + + console.log("added font", data.fontName); + // console.log(rule); + onMessageState = WAIT; + break; + case LOG: console.log.apply(console, JSON.parse(data)); onMessageState = WAIT; @@ -40,17 +112,14 @@ myWorker.onmessage = function(event) { 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]); - } - } + console.log("canvas stack", stack.length) + // console.log(stack.length); onMessageState = WAIT; + // return; + + setTimeout(function() { + renderProxyCanvas(stack); + }, 2000); break; } } @@ -75,6 +144,10 @@ function open(url) { window.onload = function() { var ctx = window.ctx = document.getElementById("canvas").getContext("2d"); + ctx.save(); + ctx.fillStyle = "rgb(255, 255, 255)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); // for (var name in ctx) { // if (!(ctx[name] instanceof Function)) { // console.log('"' + name + '": "' + ctx[name] + '",'); diff --git a/worker.js b/worker.js index fdc762afd..9ee9409bd 100644 --- a/worker.js +++ b/worker.js @@ -40,6 +40,7 @@ var canvas = new CanvasProxy(1224, 1584); // canvas.flush(); log("test"); +var pageInterval; onmessage = function(event) { var data = event.data; var pdfDocument = new PDFDoc(new Stream(data)); @@ -59,36 +60,39 @@ onmessage = function(event) { // 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; - } + // 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; - } + 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); + // function delayLoadFont() { + // for (var i = 0; i < count; i++) { + // if (Fonts[font.name].loading) + // return; + // } + // clearInterval(pageInterval); + // page.display(gfx); + // + // log("flush"); + // canvas.flush(); + // }; - canvas.flush(); - }; + // if (fontsReady) { + // delayLoadFont(); + // } else { + // pageInterval = setInterval(delayLoadFont, 10); + // } - if (fontsReady) { - delayLoadFont(); - } else { - pageInterval = setInterval(delayLoadFont, 10); - } - postMessage(page.code.src); + page.display(gfx); + canvas.flush(); } // function open(url) {