From 6f3fff579894c5a28cfa1dd0116a57593624b04c Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Fri, 15 Jul 2011 17:40:37 -0700 Subject: [PATCH 1/6] fix some bugs --- pdf.js | 55 +++++++++++++++++++++++++++++++++++++++++++------- test/driver.js | 5 ++++- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/pdf.js b/pdf.js index a3179406c..4de525be0 100644 --- a/pdf.js +++ b/pdf.js @@ -19,6 +19,7 @@ function warn(msg) { } function error(msg) { + console.log(backtrace()); throw new Error(msg); } @@ -43,6 +44,16 @@ function assertWellFormed(cond, msg) { malformed(msg); } +function backtrace() { + var stackStr; + try { + throw new Error(); + } catch(e) { + stackStr = e.stack; + }; + return stackStr.split('\n').slice(1).join('\n'); +} + function shadow(obj, prop, value) { Object.defineProperty(obj, prop, { value: value, enumerable: true, configurable: true, writable: false }); return value; @@ -2838,6 +2849,13 @@ var XRef = (function() { return this.fetch(obj); }, fetch: function(ref) { + + + if ("undefined" == typeof ref) { + console.log(backtrace()); + } + + var num = ref.num; var e = this.cache[num]; if (e) @@ -2960,7 +2978,7 @@ var Page = (function() { return shadow(this, 'mediaBox', ((IsArray(obj) && obj.length == 4) ? obj : null)); }, - startRendering: function(canvasCtx, continuation) { + startRendering: function(canvasCtx, continuation, onerror) { var self = this; var stats = self.stats; stats.compile = stats.fonts = stats.render = 0; @@ -2978,9 +2996,14 @@ var Page = (function() { // Always defer call to display() to work around bug in // Firefox error reporting from XHR callbacks. setTimeout(function () { - self.display(gfx); - stats.render = Date.now(); - continuation(); + var exc = null; + try { + self.display(gfx); + stats.render = Date.now(); + } catch (e) { + exc = e.toString(); + } + continuation(exc); }); }); }, @@ -3639,7 +3662,12 @@ var PartialEvaluator = (function() { if (!df) return null; compositeFont = true; - descendant = xref.fetch(df[0]); + + if (IsRef(df)) { + df = xref.fetch(df); + } + + descendant = xref.fetch(IsRef(df) ? df : df[0]); subType = descendant.get('Subtype'); fd = descendant.get('FontDescriptor'); } else { @@ -4765,6 +4793,15 @@ var ColorSpace = (function() { }; constructor.parse = function colorspace_parse(cs, xref, res) { + + + + if ("undefined" == typeof(cs)) + console.log(backtrace()); + + + + if (IsName(cs)) { var colorSpaces = res.get('ColorSpace'); if (colorSpaces) { @@ -4854,10 +4891,10 @@ var ColorSpace = (function() { case 'Lab': case 'DeviceN': default: - error("unrecognized color space object '" + mode + "'"); + error("unimplemented color space object '" + mode + "'"); } } else { - error('unrecognized color space object'); + error('unrecognized color space object: "'+ cs +"'"); } }; @@ -5131,6 +5168,10 @@ var PDFImage = (function() { this.bpc = bitsPerComponent; var colorSpace = dict.get('ColorSpace', 'CS'); + if (!colorSpace) { + TODO('JPX images (which don"t require color spaces'); + colorSpace = new Name('DeviceRGB'); + } this.colorSpace = ColorSpace.parse(colorSpace, xref, res); this.numComps = this.colorSpace.numComps; diff --git a/test/driver.js b/test/driver.js index e397f108b..a6b0b1dc2 100644 --- a/test/driver.js +++ b/test/driver.js @@ -111,7 +111,10 @@ function nextPage(task, loadError) { page.startRendering( ctx, - function() { snapshotCurrentPage(page, task, failure); }); + function(e) { + snapshotCurrentPage(page, task, + (!failure && e) ? ('render: '+ e) : failure); + }); } catch(e) { failure = 'page setup: '+ e.toString(); } From daf23a0341eddeb38a4762af3cb7a95b4dc33747 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Fri, 15 Jul 2011 18:41:52 -0700 Subject: [PATCH 2/6] remove debugging code --- pdf.js | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/pdf.js b/pdf.js index 4de525be0..05330db84 100644 --- a/pdf.js +++ b/pdf.js @@ -19,7 +19,7 @@ function warn(msg) { } function error(msg) { - console.log(backtrace()); + log(backtrace()); throw new Error(msg); } @@ -2849,13 +2849,6 @@ var XRef = (function() { return this.fetch(obj); }, fetch: function(ref) { - - - if ("undefined" == typeof ref) { - console.log(backtrace()); - } - - var num = ref.num; var e = this.cache[num]; if (e) @@ -4793,15 +4786,6 @@ var ColorSpace = (function() { }; constructor.parse = function colorspace_parse(cs, xref, res) { - - - - if ("undefined" == typeof(cs)) - console.log(backtrace()); - - - - if (IsName(cs)) { var colorSpaces = res.get('ColorSpace'); if (colorSpaces) { From d56cc9c5e82c431306a6f72d0f32d539e6e54e66 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Mon, 18 Jul 2011 12:09:26 +0200 Subject: [PATCH 3/6] Updating PartialEvaluator.eval syntax for better performance --- pdf.js | 41 +++++++++++++---------------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/pdf.js b/pdf.js index 05330db84..5e2aa87b1 100644 --- a/pdf.js +++ b/pdf.js @@ -3561,23 +3561,9 @@ var PartialEvaluator = (function() { eval: function(stream, xref, resources, fonts) { resources = xref.fetchIfRef(resources) || new Dict(); var xobjs = xref.fetchIfRef(resources.get('XObject')) || new Dict(); - var parser = new Parser(new Lexer(stream), false); - var objpool = []; - - function emitArg(arg) { - if (typeof arg == 'object' || typeof arg == 'string') { - var index = objpool.length; - objpool[index] = arg; - return 'objpool[' + index + ']'; - } - return arg; - } - - var src = ''; - - var args = []; - var obj; + var args = [], argsArray = [], fnArray = [], obj; + while (!IsEOF(obj = parser.getObj())) { if (IsCmd(obj)) { var cmd = obj.cmd; @@ -3600,9 +3586,9 @@ var PartialEvaluator = (function() { if ('Form' == type.name) { args[0].code = this.eval(xobj, - xref, - xobj.dict.get('Resources'), - fonts); + xref, + xobj.dict.get('Resources'), + fonts); } } } else if (cmd == 'Tf') { // eagerly collect all fonts @@ -3622,21 +3608,20 @@ var PartialEvaluator = (function() { } } - src += 'this.'; - src += fn; - src += '('; - src += args.map(emitArg).join(','); - src += ');\n'; - - args.length = 0; + fnArray.push(fn); + argsArray.push(args); + args = []; } else { assertWellFormed(args.length <= 33, 'Too many arguments'); args.push(obj); } } - var fn = Function('objpool', src); - return function(gfx) { fn.call(gfx, objpool); }; + return function(gfx) { + for(var i = 0, length = argsArray.length; i < length; i++) { + gfx[fnArray[i]].apply(gfx, argsArray[i]); + } + } }, translateFont: function(fontDict, xref, resources) { From aedd5057c4ae9849140b07ccf0896c75a51ffebe Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Mon, 18 Jul 2011 15:01:12 +0200 Subject: [PATCH 4/6] Updated syntax --- pdf.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pdf.js b/pdf.js index 5e2aa87b1..64e830f5d 100644 --- a/pdf.js +++ b/pdf.js @@ -3585,10 +3585,7 @@ var PartialEvaluator = (function() { ); if ('Form' == type.name) { - args[0].code = this.eval(xobj, - xref, - xobj.dict.get('Resources'), - fonts); + args[0].code = this.eval(xobj, xref, xobj.dict.get('Resources'), fonts); } } } else if (cmd == 'Tf') { // eagerly collect all fonts @@ -3618,9 +3615,8 @@ var PartialEvaluator = (function() { } return function(gfx) { - for(var i = 0, length = argsArray.length; i < length; i++) { + for(var i = 0, length = argsArray.length; i < length; i++) gfx[fnArray[i]].apply(gfx, argsArray[i]); - } } }, From 8d09c0d7a4a1b7815882e99393e7c9a891743992 Mon Sep 17 00:00:00 2001 From: sbarman Date: Wed, 20 Jul 2011 16:42:51 -0700 Subject: [PATCH 5/6] removed Fonts class --- fonts.js | 74 +++++++++++++++++++++++--------------------------------- pdf.js | 9 ++++--- 2 files changed, 36 insertions(+), 47 deletions(-) diff --git a/fonts.js b/fonts.js index 607e2aab9..94b93b0da 100755 --- a/fonts.js +++ b/fonts.js @@ -21,17 +21,13 @@ var kMaxWaitForFontFace = 1000; * http://cgit.freedesktop.org/poppler/poppler/tree/poppler/GfxFont.cc#n65 */ -var Fonts = (function Fonts() { +var FontMeasure = (function FontMeasure() { var kScalePrecision = 40; - var fonts = []; - if (!isWorker) { - var ctx = document.createElement('canvas').getContext('2d'); - ctx.scale(1 / kScalePrecision, 1); - } + var ctx = document.createElement('canvas').getContext('2d'); + ctx.scale(1 / kScalePrecision, 1); - var fontCount = 0; - + /* function FontInfo(name, data, properties) { this.name = name; this.data = data; @@ -40,28 +36,14 @@ var Fonts = (function Fonts() { this.loading = true; this.sizes = []; } +*/ var current; var measureCache; return { - registerFont: function fonts_registerFont(fontName, data, properties) { - var font = new FontInfo(fontName, data, properties); - fonts.push(font); - return font.id; - }, - blacklistFont: function fonts_blacklistFont(fontName) { - var id = registerFont(fontName, null, {}); - markLoaded(fontName); - return id; - }, - lookupById: function fonts_lookupById(id) { - return fonts[id]; - }, - setActive: function fonts_setActive(fontName, fontObj, size) { - // |current| can be null is fontName is a built-in font - // (e.g. "sans-serif") - if (fontObj && (current = fonts[fontObj.id])) { + setActive: function fonts_setActive(font, size) { + if (current = font) { var sizes = current.sizes; if (!(measureCache = sizes[size])) measureCache = sizes[size] = Object.create(null); @@ -69,10 +51,12 @@ var Fonts = (function Fonts() { measureCache = null } - ctx.font = (size * kScalePrecision) + 'px "' + fontName + '"'; + ctx.font = (size * kScalePrecision) + 'px "' + font.loadedName + '"'; }, measureText: function fonts_measureText(text) { var width; + // something is wrong with the caching, it is messing up page 12 in + // the tracemonkey paper if (measureCache && (width = measureCache[text])) return width; width = ctx.measureText(text).width / kScalePrecision; @@ -88,9 +72,9 @@ var FontLoader = { bind: function(fonts, callback) { function checkFontsLoaded() { - for (var i = 0; i < allIds.length; i++) { - var id = allIds[i]; - if (Fonts.lookupById(id).loading) { + for (var i = 0; i < objs.length; i++) { + var fontObj = objs[i]; + if (fontObj.loading) { return false; } } @@ -102,18 +86,17 @@ var FontLoader = { return true; } - var allIds = []; - var rules = [], names = [], ids = []; + var rules = [], names = [], objs = []; for (var i = 0; i < fonts.length; i++) { var font = fonts[i]; var obj = new Font(font.name, font.file, font.properties); - font.fontDict.fontObj = obj; - allIds.push(obj.id); + obj.loading = true; + objs.push(obj); var str = ''; - var data = Fonts.lookupById(obj.id).data; + var data = obj.data; var length = data.length; for (var j = 0; j < length; j++) str += String.fromCharCode(data[j]); @@ -122,13 +105,12 @@ var FontLoader = { if (rule) { rules.push(rule); names.push(obj.loadedName); - ids.push(obj.id); } } this.listeningForFontLoad = false; if (!isWorker && rules.length) { - FontLoader.prepareFontLoadEvent(rules, names, ids); + FontLoader.prepareFontLoadEvent(rules, names, objs); } if (!checkFontsLoaded()) { @@ -136,14 +118,14 @@ var FontLoader = { 'pdfjsFontLoad', checkFontsLoaded, false); } - return; + return objs; }, // Set things up so that at least one pdfjsFontLoad event is // dispatched when all the @font-face |rules| for |names| have been // loaded in a subdocument. It's expected that the load of |rules| // has already started in this (outer) document, so that they should // be ordered before the load in the subdocument. - prepareFontLoadEvent: function(rules, names, ids) { + prepareFontLoadEvent: function(rules, names, objs) { /** Hack begin */ // There's no event when a font has finished downloading so the // following code is a dirty hack to 'guess' when a font is @@ -184,8 +166,8 @@ var FontLoader = { 'message', function(e) { var fontNames = JSON.parse(e.data); - for (var i = 0; i < fontNames.length; ++i) { - var font = Fonts.lookupById(fontNames[i].substring(7) | 0); + for (var i = 0; i < objs.length; ++i) { + var font = objs[i]; font.loading = false; } var evt = document.createEvent('Events'); @@ -381,8 +363,7 @@ var Font = (function() { // If the font is to be ignored, register it like an already loaded font // to avoid the cost of waiting for it be be loaded by the platform. if (properties.ignore) { - this.id = Fonts.blacklistFont(name); - this.loadedName = 'pdfFont' + this.id; + this.loadedName = 'Arial'; return; } @@ -412,11 +393,15 @@ var Font = (function() { } this.data = data; this.type = properties.type; - this.id = Fonts.registerFont(name, data, properties); - this.loadedName = 'pdfFont' + this.id; + this.loadedName = getUniqueName(); this.compositeFont = properties.compositeFont; }; + var numFonts = 0; + function getUniqueName() { + return 'pdfFont' + numFonts++; + } + function stringToArray(str) { var array = []; for (var i = 0; i < str.length; ++i) @@ -746,6 +731,7 @@ var Font = (function() { font: null, mimetype: null, encoding: null, + sizes: [], checkAndRepair: function font_checkAndRepair(name, font, properties) { function readTableEntry(file) { diff --git a/pdf.js b/pdf.js index 64e830f5d..51426dce7 100644 --- a/pdf.js +++ b/pdf.js @@ -2982,7 +2982,7 @@ var Page = (function() { this.compile(gfx, fonts); stats.compile = Date.now(); - FontLoader.bind( + var fontObjs = FontLoader.bind( fonts, function() { stats.fonts = Date.now(); @@ -2999,6 +2999,9 @@ var Page = (function() { continuation(exc); }); }); + + for (var i = 0, ii = fonts.length; i < ii; ++i) + fonts[i].fontDict.fontObj = fontObjs[i]; }, @@ -4093,7 +4096,7 @@ var CanvasGraphics = (function() { this.ctx.$setFont(fontName, size); } else { this.ctx.font = size + 'px "' + fontName + '"'; - Fonts.setActive(fontName, fontObj, size); + FontMeasure.setActive(fontObj, size); } }, setTextRenderingMode: function(mode) { @@ -4145,7 +4148,7 @@ var CanvasGraphics = (function() { text = font.charsToUnicode(text); } ctx.fillText(text, 0, 0); - current.x += Fonts.measureText(text); + current.x += FontMeasure.measureText(text); } this.ctx.restore(); From daf4979e2f09ea58f670f596d843667a2eaa72f4 Mon Sep 17 00:00:00 2001 From: sbarman Date: Wed, 20 Jul 2011 17:10:04 -0700 Subject: [PATCH 6/6] cleanup --- fonts.js | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/fonts.js b/fonts.js index 94b93b0da..f33cab9c3 100755 --- a/fonts.js +++ b/fonts.js @@ -27,17 +27,6 @@ var FontMeasure = (function FontMeasure() { var ctx = document.createElement('canvas').getContext('2d'); ctx.scale(1 / kScalePrecision, 1); - /* - function FontInfo(name, data, properties) { - this.name = name; - this.data = data; - this.properties = properties; - this.id = fontCount++; - this.loading = true; - this.sizes = []; - } -*/ - var current; var measureCache; @@ -55,8 +44,6 @@ var FontMeasure = (function FontMeasure() { }, measureText: function fonts_measureText(text) { var width; - // something is wrong with the caching, it is messing up page 12 in - // the tracemonkey paper if (measureCache && (width = measureCache[text])) return width; width = ctx.measureText(text).width / kScalePrecision; @@ -359,6 +346,7 @@ var Font = (function() { this.name = name; this.textMatrix = properties.textMatrix || IDENTITY_MATRIX; this.encoding = properties.encoding; + this.sizes = []; // If the font is to be ignored, register it like an already loaded font // to avoid the cost of waiting for it be be loaded by the platform. @@ -731,7 +719,6 @@ var Font = (function() { font: null, mimetype: null, encoding: null, - sizes: [], checkAndRepair: function font_checkAndRepair(name, font, properties) { function readTableEntry(file) {