From b7ac83da32110de6ea6af123a70a8a25362dec83 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Thu, 18 Aug 2011 07:43:45 -0500 Subject: [PATCH 01/16] LZW reducing memory usage --- pdf.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 2afed5f6b..eab5a35e2 100644 --- a/pdf.js +++ b/pdf.js @@ -1990,7 +1990,7 @@ var LZWStream = (function() { this.cachedData = 0; this.bitsCached = 0; - var maxLzwDictionarySize = 4097; + var maxLzwDictionarySize = 4096; var lzwState = { earlyChange: earlyChange, codeLength: 9, @@ -2036,6 +2036,9 @@ var LZWStream = (function() { var i, j, q; var lzwState = this.lzwState; + if (!lzwState) + return; // eof was found + var earlyChange = lzwState.earlyChange; var nextCode = lzwState.nextCode; var dictionaryValues = lzwState.dictionaryValues; @@ -2073,6 +2076,7 @@ var LZWStream = (function() { continue; } else { this.eof = true; + delete this.lzwState; break; } From bf9092b6609043e567cd06b8ec201a3f3934cc1b Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 16 Aug 2011 10:25:02 -0700 Subject: [PATCH 02/16] working on subroutines --- fonts.js | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/fonts.js b/fonts.js index 66d8428e2..e38edef8d 100755 --- a/fonts.js +++ b/fonts.js @@ -1598,6 +1598,17 @@ var Type1Parser = function() { var c = ''; var count = eexecStr.length; for (var i = 0; i < count; i++) { + var getToken = function() { + while(i < count && (eexecStr[i] == ' ' || eexecStr[i] == '\n')) + ++i; + + var t = ''; + while(i < count && !(eexecStr[i] == ' ' || eexecStr[i] == '\n')) + t += eexecStr[i++]; + + return t; + } + var c = eexecStr[i]; if ((glyphsSection || subrsSection) && c == 'R') { @@ -1627,7 +1638,25 @@ var Type1Parser = function() { glyphsSection = true; break; case '/Subrs': - subrsSection = true; + ++i; + var num = parseInt(getToken()); + getToken(); // read in 'array' + for (var j = 0; j < num; ++j) { + var t = getToken(); // read in 'dup' + if (t == 'ND') + break; + var index = parseInt(getToken()); + if (index > j) + j = index; + var length = parseInt(getToken()); + getToken(); // read in 'RD' + var data = eexec.slice(i + 1, i + 1 + length); + var encoded = decrypt(data, kCharStringsEncryptionKey, 4); + var str = decodeCharString(encoded); + i = i + 1 + length; + getToken(); //read in 'NP' + program.subrs[index] = str.charstring; + } break; case '/BlueValues': case '/OtherBlues': @@ -1909,8 +1938,13 @@ CFF.prototype = { for (var i = 0; i < bias; i++) type2Subrs.push([0x0B]); - for (var i = 0; i < count; i++) - type2Subrs.push(this.flattenCharstring(type1Subrs[i], this.commandsMap)); + for (var i = 0; i < count; i++) { + var subr = type1Subrs[i]; + if (!subr) + subr = [0x0B]; + + type2Subrs.push(this.flattenCharstring(subr, this.commandsMap)); + } return type2Subrs; }, From 5b359f1c1eef9e8a102f9c93b1f27ec046567516 Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 16 Aug 2011 14:49:12 -0700 Subject: [PATCH 03/16] still mucking with subroutines --- fonts.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fonts.js b/fonts.js index e38edef8d..356d7f948 100755 --- a/fonts.js +++ b/fonts.js @@ -1469,7 +1469,7 @@ var Type1Parser = function() { var value = ''; var count = array.length; for (var i = 0; i < count; i++) { - value = parseInt(array[i]); + value = array[i]; if (value < 32) { var command = null; @@ -1479,8 +1479,8 @@ var Type1Parser = function() { // TODO Clean this code if (escape == 16) { var index = charstring.pop(); - var argc = charstring.pop(); - var data = charstring.pop(); +// var argc = charstring.pop(); +// var data = charstring.pop(); // If the flex mechanishm is not used in a font program, Adobe // state that that entries 0, 1 and 2 can simply be replace by @@ -1492,8 +1492,8 @@ var Type1Parser = function() { // This is the same things about hint replacement, if it is not used // entry 3 can be replaced by {3} if (index == 3) { - charstring.push(3); - i++; +// charstring.push(3); +// i++; continue; } } @@ -1532,11 +1532,11 @@ var Type1Parser = function() { value = command; } else if (value <= 246) { - value = parseInt(value) - 139; + value = value - 139; } else if (value <= 250) { - value = ((value - 247) * 256) + parseInt(array[++i]) + 108; + value = ((value - 247) * 256) + array[++i] + 108; } else if (value <= 254) { - value = -((value - 251) * 256) - parseInt(array[++i]) - 108; + value = -((value - 251) * 256) - array[++i] - 108; } else { value = (array[++i] & 0xff) << 24 | (array[++i] & 0xff) << 16 | (array[++i] & 0xff) << 8 | (array[++i] & 0xff) << 0; From 7d5dcb5d43936f7d4144b99c3fa4e64743990f3d Mon Sep 17 00:00:00 2001 From: sbarman Date: Thu, 21 Jul 2011 11:51:39 -0700 Subject: [PATCH 04/16] added ability to write data to file --- fonts.js | 8 ++++++++ utils/fonts_utils.js | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/fonts.js b/fonts.js index 356d7f948..7dfa6ead7 100755 --- a/fonts.js +++ b/fonts.js @@ -446,6 +446,14 @@ var Font = (function Font() { break; } + var fileArr = []; + file.reset(); + for (var i = 0, ii = file.length; i < ii; ++i) + fileArr.push(file[i]); + + writeToFile(data, '/tmp/' + name + '_orig'); + writeToFile(fileArr, '/tmp/' + name + '_new'); + this.data = data; this.type = properties.type; this.textMatrix = properties.textMatrix; diff --git a/utils/fonts_utils.js b/utils/fonts_utils.js index edfc22186..98ea60757 100644 --- a/utils/fonts_utils.js +++ b/utils/fonts_utils.js @@ -1,8 +1,6 @@ /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -'use strict'; - /** * The Type2 reader code below is only used for debugging purpose since Type2 * is only a CharString format and is never used directly as a Font file. @@ -391,7 +389,7 @@ function writeToFile(aBytes, aFilePath) { var stream = Cc['@mozilla.org/network/file-output-stream;1'] .createInstance(Ci.nsIFileOutputStream); - stream.init(file, 0x04 | 0x08 | 0x20, 0x180, 0); + stream.init(file, 0x04 | 0x08 | 0x20, 0666, 0); var bos = Cc['@mozilla.org/binaryoutputstream;1'] .createInstance(Ci.nsIBinaryOutputStream); From 2ad39c20cf1f9fd597fa25e95bffbf5fcab112af Mon Sep 17 00:00:00 2001 From: sbarman Date: Thu, 21 Jul 2011 15:13:18 -0700 Subject: [PATCH 05/16] added include to fonts_util.js --- web/viewer.html | 1 + 1 file changed, 1 insertion(+) diff --git a/web/viewer.html b/web/viewer.html index 285dadb01..1abded240 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -10,6 +10,7 @@ + From 259f8c731771ab7fef5adfa8a1df76d95ce6d300 Mon Sep 17 00:00:00 2001 From: sbarman Date: Thu, 21 Jul 2011 15:13:49 -0700 Subject: [PATCH 06/16] added include to fonts_util.js --- web/viewer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/viewer.html b/web/viewer.html index 1abded240..5498d8a1c 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -10,7 +10,7 @@ - + From 04b14f7b8a51873583a3b0f305759e26ed0a1640 Mon Sep 17 00:00:00 2001 From: sbarman Date: Thu, 21 Jul 2011 15:18:00 -0700 Subject: [PATCH 07/16] fixed reading from sream --- fonts.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index 7dfa6ead7..e2f278523 100755 --- a/fonts.js +++ b/fonts.js @@ -448,11 +448,12 @@ var Font = (function Font() { var fileArr = []; file.reset(); + file = file.getBytes(); for (var i = 0, ii = file.length; i < ii; ++i) fileArr.push(file[i]); - writeToFile(data, '/tmp/' + name + '_orig'); - writeToFile(fileArr, '/tmp/' + name + '_new'); + writeToFile(data, '/tmp/' + name + '_new'); + writeToFile(fileArr, '/tmp/' + name + '_orig'); this.data = data; this.type = properties.type; From 8acc31ec83f424fafc54133abfa94c8867fbb02c Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 16 Aug 2011 16:14:29 -0700 Subject: [PATCH 08/16] Still testing type1 charstring conversion --- fonts.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fonts.js b/fonts.js index e2f278523..77183a602 100755 --- a/fonts.js +++ b/fonts.js @@ -1488,8 +1488,9 @@ var Type1Parser = function() { // TODO Clean this code if (escape == 16) { var index = charstring.pop(); -// var argc = charstring.pop(); -// var data = charstring.pop(); + var argc = charstring.pop(); + for (var j = 0; j < argc; j++) + var data = charstring.pop(); // If the flex mechanishm is not used in a font program, Adobe // state that that entries 0, 1 and 2 can simply be replace by @@ -1501,8 +1502,8 @@ var Type1Parser = function() { // This is the same things about hint replacement, if it is not used // entry 3 can be replaced by {3} if (index == 3) { -// charstring.push(3); -// i++; + charstring.push(3); + i++; continue; } } From 6fc25241cceaea916225a6ce5ce822a62af138ea Mon Sep 17 00:00:00 2001 From: Kalervo Kujala Date: Wed, 17 Aug 2011 01:33:00 +0300 Subject: [PATCH 09/16] Report results properly to test.py from driver.js. If the PDFDoc creation failed in driver.js then that was not informed back to test.py. This lead to State.remaining being off by one. And that did not let the test to end as expected. Instead the test hung indefinitely. This change now reveals TEST-UNEXPECTED-FAIL which was hidden previously. --- test/driver.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/test/driver.js b/test/driver.js index 92fc00af1..716046c4b 100644 --- a/test/driver.js +++ b/test/driver.js @@ -80,10 +80,19 @@ function nextTask() { } function isLastPage(task) { - return (!task.pdfDoc || (task.pageNum > task.pdfDoc.numPages)); + return (task.pageNum > task.pdfDoc.numPages); } function nextPage(task, loadError) { + var failure = loadError || ''; + + if (!task.pdfDoc) { + sendTaskResult(canvas.toDataURL('image/png'), task, failure); + log('done' + (failure ? ' (failed !: ' + failure + ')' : '') + '\n'); + ++currentTaskIdx, nextTask(); + return; + } + if (isLastPage(task)) { if (++task.round < task.rounds) { log(' Round ' + (1 + task.round) + '\n'); @@ -94,15 +103,13 @@ function nextPage(task, loadError) { } } - var failure = loadError || ''; - - var ctx = null; var page = null; + if (!failure) { try { log(' loading page ' + task.pageNum + '/' + task.pdfDoc.numPages + '... '); - ctx = canvas.getContext('2d'); + var ctx = canvas.getContext('2d'); page = task.pdfDoc.getPage(task.pageNum); var pdfToCssUnitsCoef = 96.0 / 72.0; @@ -179,7 +186,7 @@ var inFlightRequests = 0; function sendTaskResult(snapshot, task, failure) { var result = { browser: browser, id: task.id, - numPages: task.pdfDoc.numPages, + numPages: task.pdfDoc ? task.pdfDoc.numPages : 0, failure: failure, file: task.file, round: task.round, From b18b63a9a963dd5bb36547b56007f1047ddeef09 Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 16 Aug 2011 16:47:48 -0700 Subject: [PATCH 10/16] implemented curve2, partial fix for #325 --- pdf.js | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index 79ae776f6..081abfd20 100644 --- a/pdf.js +++ b/pdf.js @@ -4,7 +4,7 @@ 'use strict'; var ERRORS = 0, WARNINGS = 1, TODOS = 5; -var verbosity = WARNINGS; +var verbosity = TODOS; function log(msg) { if (console && console.log) @@ -4137,6 +4137,9 @@ var CanvasExtraState = (function() { this.charSpacing = 0; this.wordSpacing = 0; this.textHScale = 1; + // Path variables + this.pathX = 0; + this.pathY = 0; // Color spaces this.fillColorSpaceObj = null; this.strokeColorSpaceObj = null; @@ -4276,18 +4279,39 @@ var CanvasGraphics = (function() { // Path moveTo: function(x, y) { this.ctx.moveTo(x, y); + + var current = this.current; + current.pathX = x; + current.pathY = y; }, lineTo: function(x, y) { this.ctx.lineTo(x, y); + + var current = this.current; + current.pathX = x; + current.pathY = y; }, curveTo: function(x1, y1, x2, y2, x3, y3) { this.ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3); + + var current = this.current; + current.pathX = x3; + current.pathY = y3; }, curveTo2: function(x2, y2, x3, y3) { - TODO("'v' operator: need current point in gfx context"); + var current = this.current; + this.ctx.bezierCurveTo(current.pathX, current.pathY, x2, y2, x3, y3); +// TODO("'v' operator: need current point in gfx context"); + + current.pathX = x3; + current.pathY = y3; }, curveTo3: function(x1, y1, x3, y3) { this.curveTo(x1, y1, x3, y3, x3, y3); + + var current = this.current; + current.pathX = x3; + current.pathY = y3; }, closePath: function() { this.ctx.closePath(); From ac1000cc86d41e6bf0bf027e56550744c47b4bc5 Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 16 Aug 2011 16:49:26 -0700 Subject: [PATCH 11/16] cleanup --- pdf.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index 081abfd20..d9c1007bb 100644 --- a/pdf.js +++ b/pdf.js @@ -4,7 +4,7 @@ 'use strict'; var ERRORS = 0, WARNINGS = 1, TODOS = 5; -var verbosity = TODOS; +var verbosity = WARNINGS; function log(msg) { if (console && console.log) @@ -4301,7 +4301,6 @@ var CanvasGraphics = (function() { curveTo2: function(x2, y2, x3, y3) { var current = this.current; this.ctx.bezierCurveTo(current.pathX, current.pathY, x2, y2, x3, y3); -// TODO("'v' operator: need current point in gfx context"); current.pathX = x3; current.pathY = y3; From a48a74862ac4bc2e620bb931ca1885dab25c17b4 Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 16 Aug 2011 18:15:20 -0700 Subject: [PATCH 12/16] added stiched functions --- pdf.js | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/pdf.js b/pdf.js index d9c1007bb..45f5484f6 100644 --- a/pdf.js +++ b/pdf.js @@ -5727,7 +5727,7 @@ var PDFFunction = (function() { if (!typeFn) error('Unknown type of function'); - typeFn.call(this, fn, dict); + typeFn.call(this, fn, dict, xref); }; constructor.prototype = { @@ -5872,9 +5872,58 @@ var PDFFunction = (function() { return out; } }, - constructStiched: function() { - TODO('unhandled type of function'); - this.func = function() { return [255, 105, 180]; } + constructStiched: function(fn, dict, xref) { + var domain = dict.get('Domain'); + var range = dict.get('Range'); + + if (!domain) + error('No domain'); + + var inputSize = domain.length / 2; + if (inputSize != 1) + error('Bad domain for stiched function'); + + var fnRefs = dict.get('Functions'); + var fns = []; + for (var i = 0, ii = fnRefs.length; i < ii; ++i) + fns.push(new PDFFunction(xref, xref.fetchIfRef(fnRefs[i]))); + + var bounds = dict.get('Bounds'); + var encode = dict.get('Encode'); + + this.func = function(args) { + var clip = function(v, min, max) { + if (v > max) + v = max; + else if (v < min) + v = min; + return v; + } + + // clip to domain + var v = clip(args[0], domain[0], domain[1]); + // calulate which bound the value is in + for (var i = 0, ii = bounds.length; i < ii; ++i) { + if (v < bounds[i]) + break; + } + + // encode value into domain of function + var dmin = domain[0]; + if (i > 0) + dmin = bounds[i - 1]; + var dmax = domain[1]; + if (i < bounds.length) + dmax = bounds[i]; + + var rmin = encode[2 * i]; + var rmax = encode[2 * i + 1]; + + var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin); + + // call the appropropriate function + return fns[i].func([v2]); + } }, constructPostScript: function() { TODO('unhandled type of function'); From d24a00452ea43a33ddd8d7507d8d28b53bee5415 Mon Sep 17 00:00:00 2001 From: sbarman Date: Wed, 17 Aug 2011 09:22:54 -0700 Subject: [PATCH 13/16] combined pathX/Y with x/y and wrote setCurrentPoint function --- pdf.js | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/pdf.js b/pdf.js index 45f5484f6..2afed5f6b 100644 --- a/pdf.js +++ b/pdf.js @@ -4137,9 +4137,6 @@ var CanvasExtraState = (function() { this.charSpacing = 0; this.wordSpacing = 0; this.textHScale = 1; - // Path variables - this.pathX = 0; - this.pathY = 0; // Color spaces this.fillColorSpaceObj = null; this.strokeColorSpaceObj = null; @@ -4152,7 +4149,11 @@ var CanvasExtraState = (function() { constructor.prototype = { clone: function canvasextra_clone() { return Object.create(this); - } + }, + setCurrentPoint: function canvasextra_setCurrentPoint(x, y) { + this.x = x; + this.y = y; + }, }; return constructor; })(); @@ -4279,38 +4280,24 @@ var CanvasGraphics = (function() { // Path moveTo: function(x, y) { this.ctx.moveTo(x, y); - - var current = this.current; - current.pathX = x; - current.pathY = y; + this.current.setCurrentPoint(x, y); }, lineTo: function(x, y) { this.ctx.lineTo(x, y); - - var current = this.current; - current.pathX = x; - current.pathY = y; + this.current.setCurrentPoint(x, y); }, curveTo: function(x1, y1, x2, y2, x3, y3) { this.ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3); - - var current = this.current; - current.pathX = x3; - current.pathY = y3; + this.current.setCurrentPoint(x3, y3); }, curveTo2: function(x2, y2, x3, y3) { var current = this.current; - this.ctx.bezierCurveTo(current.pathX, current.pathY, x2, y2, x3, y3); - - current.pathX = x3; - current.pathY = y3; + this.ctx.bezierCurveTo(current.x, current.y, x2, y2, x3, y3); + current.setCurrentPoint(x3, y3); }, curveTo3: function(x1, y1, x3, y3) { this.curveTo(x1, y1, x3, y3, x3, y3); - - var current = this.current; - current.pathX = x3; - current.pathY = y3; + this.current.setCurrentPoint(x3, y3); }, closePath: function() { this.ctx.closePath(); From c9f9b8b1935128d9e159db155f4ac7361c7e5c6b Mon Sep 17 00:00:00 2001 From: sbarman Date: Wed, 17 Aug 2011 15:55:09 -0700 Subject: [PATCH 14/16] working font --- fonts.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fonts.js b/fonts.js index 77183a602..a55fc63a2 100755 --- a/fonts.js +++ b/fonts.js @@ -1490,7 +1490,7 @@ var Type1Parser = function() { var index = charstring.pop(); var argc = charstring.pop(); for (var j = 0; j < argc; j++) - var data = charstring.pop(); + charstring.push('drop'); // If the flex mechanishm is not used in a font program, Adobe // state that that entries 0, 1 and 2 can simply be replace by @@ -1976,6 +1976,8 @@ CFF.prototype = { 'sub': [12, 11], 'div': [12, 12], 'pop': [1, 12, 18], +// 'pop': [], + 'drop' : [12, 18], 'endchar': 14, 'rmoveto': 21, 'hmoveto': 22, From 32bde231570f9c12bcaafa82f58817ae1be1e0e6 Mon Sep 17 00:00:00 2001 From: sbarman Date: Wed, 17 Aug 2011 16:04:14 -0700 Subject: [PATCH 15/16] cleanup --- fonts.js | 1 - 1 file changed, 1 deletion(-) diff --git a/fonts.js b/fonts.js index a55fc63a2..eba88c6bf 100755 --- a/fonts.js +++ b/fonts.js @@ -1976,7 +1976,6 @@ CFF.prototype = { 'sub': [12, 11], 'div': [12, 12], 'pop': [1, 12, 18], -// 'pop': [], 'drop' : [12, 18], 'endchar': 14, 'rmoveto': 21, From fd0423b5c79c359b69f72175f77651a92d18489f Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Thu, 18 Aug 2011 19:55:14 -0500 Subject: [PATCH 16/16] image load pending --- pdf.js | 92 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 19 deletions(-) diff --git a/pdf.js b/pdf.js index eab5a35e2..34af6521f 100644 --- a/pdf.js +++ b/pdf.js @@ -806,6 +806,11 @@ var JpegStream = (function() { // create DOM image var img = new Image(); + img.onload = (function() { + this.loaded = true; + if (this.onLoad) + this.onLoad(); + }).bind(this); img.src = 'data:image/jpeg;base64,' + window.btoa(bytesToString(bytes)); this.domImage = img; } @@ -822,6 +827,44 @@ var JpegStream = (function() { return constructor; })(); +// Simple object to track the loading images +// Initialy for every that is in loading call imageLoading() +// and, when images onload is fired, call imageLoaded() +// When all images are loaded, the onLoad event is fired. +var ImagesLoader = (function() { + function constructor() { + this.loading = 0; + } + + constructor.prototype = { + imageLoading: function() { + ++this.loading; + }, + + imageLoaded: function() { + if (--this.loading == 0 && this.onLoad) { + this.onLoad(); + delete this.onLoad; + } + }, + + bind: function(jpegStream) { + if (jpegStream.loaded) + return; + this.imageLoading(); + jpegStream.onLoad = this.imageLoaded.bind(this); + }, + + notifyOnLoad: function(callback) { + if (this.loading == 0) + callback(); + this.onLoad = callback; + } + }; + + return constructor; +})(); + var DecryptStream = (function() { function constructor(str, decrypt) { this.str = str; @@ -3127,6 +3170,7 @@ var Page = (function() { create: Date.now(), compile: 0.0, fonts: 0.0, + images: 0.0, render: 0.0 }; this.xref = xref; @@ -3201,25 +3245,33 @@ var Page = (function() { var gfx = new CanvasGraphics(canvasCtx); var fonts = []; + var images = new ImagesLoader() - this.compile(gfx, fonts); + this.compile(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); + }); + }; + var fontObjs = FontLoader.bind( fonts, function() { stats.fonts = Date.now(); - // 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); + images.notifyOnLoad(function() { + stats.images = Date.now(); + displayContinuation(); }); }); @@ -3228,7 +3280,7 @@ var Page = (function() { }, - compile: function(gfx, fonts) { + compile: function(gfx, fonts, images) { if (this.code) { // content was compiled return; @@ -3240,14 +3292,14 @@ var Page = (function() { if (!IsArray(this.content)) { // content is not an array, shortcut content = xref.fetchIfRef(this.content); - this.code = gfx.compile(content, xref, resources, fonts); + this.code = gfx.compile(content, xref, resources, fonts, images); return; } // the content is an array, compiling all items var i, n = this.content.length, compiledItems = []; for (i = 0; i < n; ++i) { content = xref.fetchIfRef(this.content[i]); - compiledItems.push(gfx.compile(content, xref, resources, fonts)); + compiledItems.push(gfx.compile(content, xref, resources, fonts, images)); } // creating the function that executes all compiled items this.code = function(gfx) { @@ -3787,7 +3839,7 @@ var PartialEvaluator = (function() { }; constructor.prototype = { - eval: function(stream, xref, resources, fonts) { + eval: function(stream, xref, resources, fonts, images) { resources = xref.fetchIfRef(resources) || new Dict(); var xobjs = xref.fetchIfRef(resources.get('XObject')) || new Dict(); var patterns = xref.fetchIfRef(resources.get('Pattern')) || new Dict(); @@ -3832,8 +3884,10 @@ var PartialEvaluator = (function() { if ('Form' == type.name) { args[0].code = this.eval(xobj, xref, xobj.dict.get('Resources'), - fonts); + fonts, images); } + if (xobj instanceof JpegStream) + images.bind(xobj); // monitoring image load } } else if (cmd == 'Tf') { // eagerly collect all fonts var fontRes = resources.get('Font'); @@ -4209,9 +4263,9 @@ var CanvasGraphics = (function() { this.ctx.scale(cw / mediaBox.width, ch / mediaBox.height); }, - compile: function(stream, xref, resources, fonts) { + compile: function(stream, xref, resources, fonts, images) { var pe = new PartialEvaluator(); - return pe.eval(stream, xref, resources, fonts); + return pe.eval(stream, xref, resources, fonts, images); }, execute: function(code, xref, resources) {