Skip to content

Commit 69b7207

Browse files
committed
Separate page objects/images from the fonts; does not store large images
1 parent d2c1868 commit 69b7207

File tree

7 files changed

+97
-73
lines changed

7 files changed

+97
-73
lines changed

src/api.js

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,10 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
172172
this.transport = transport;
173173
this.stats = new StatTimer();
174174
this.stats.enabled = !!globalScope.PDFJS.enableStats;
175-
this.objs = transport.objs;
175+
this.commonObjs = transport.commonObjs;
176+
this.objs = new PDFObjects();
176177
this.renderInProgress = false;
178+
this.cleanupAfterRender = false;
177179
}
178180
PDFPageProxy.prototype = {
179181
/**
@@ -263,9 +265,10 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
263265
var self = this;
264266
function complete(error) {
265267
self.renderInProgress = false;
266-
if (self.destroyed) {
267-
delete self.operatorList;
268+
if (self.destroyed || self.cleanupAfterRender) {
268269
delete self.displayReadyPromise;
270+
delete self.operatorList;
271+
self.objs.clear();
269272
}
270273

271274
if (error)
@@ -283,7 +286,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
283286
return;
284287
}
285288

286-
var gfx = new CanvasGraphics(params.canvasContext,
289+
var gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
287290
this.objs, params.textLayer);
288291
try {
289292
this.display(gfx, params.viewport, complete, continueCallback);
@@ -329,7 +332,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
329332
// Convert the font names to the corresponding font obj.
330333
var fontObjs = [];
331334
for (var i = 0, ii = fonts.length; i < ii; i++) {
332-
var obj = this.objs.objs[fonts[i]].data;
335+
var obj = this.commonObjs.getData(fonts[i]);
333336
if (obj.error) {
334337
warn('Error during font loading: ' + obj.error);
335338
continue;
@@ -423,6 +426,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
423426
if (!this.renderInProgress) {
424427
delete this.operatorList;
425428
delete this.displayReadyPromise;
429+
this.objs.clear();
426430
}
427431
}
428432
};
@@ -434,7 +438,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
434438
var WorkerTransport = (function WorkerTransportClosure() {
435439
function WorkerTransport(workerInitializedPromise, workerReadyPromise) {
436440
this.workerReadyPromise = workerReadyPromise;
437-
this.objs = new PDFObjects();
441+
this.commonObjs = new PDFObjects();
438442

439443
this.pageCache = [];
440444
this.pagePromises = [];
@@ -569,21 +573,13 @@ var WorkerTransport = (function WorkerTransportClosure() {
569573
page.startRenderingFromOperatorList(data.operatorList, depFonts);
570574
}, this);
571575

572-
messageHandler.on('obj', function transportObj(data) {
576+
messageHandler.on('commonobj', function transportObj(data) {
573577
var id = data[0];
574578
var type = data[1];
575-
if (this.objs.hasData(id))
579+
if (this.commonObjs.hasData(id))
576580
return;
577581

578582
switch (type) {
579-
case 'JpegStream':
580-
var imageData = data[2];
581-
loadJpegStream(id, imageData, this.objs);
582-
break;
583-
case 'Image':
584-
var imageData = data[2];
585-
this.objs.resolve(id, imageData);
586-
break;
587583
case 'Font':
588584
var exportedData = data[2];
589585

@@ -594,10 +590,39 @@ var WorkerTransport = (function WorkerTransportClosure() {
594590
font = new ErrorFont(exportedData.error);
595591
else
596592
font = new Font(exportedData);
597-
this.objs.resolve(id, font);
593+
this.commonObjs.resolve(id, font);
594+
break;
595+
default:
596+
error('Got unknown common object type ' + type);
597+
}
598+
}, this);
599+
600+
messageHandler.on('obj', function transportObj(data) {
601+
var id = data[0];
602+
var pageIndex = data[1];
603+
var type = data[2];
604+
var pageProxy = this.pageCache[pageIndex];
605+
if (pageProxy.objs.hasData(id))
606+
return;
607+
608+
switch (type) {
609+
case 'JpegStream':
610+
var imageData = data[3];
611+
loadJpegStream(id, imageData, pageProxy.objs);
612+
break;
613+
case 'Image':
614+
var imageData = data[3];
615+
pageProxy.objs.resolve(id, imageData);
616+
617+
// heuristics that will allow not to store large data
618+
var MAX_IMAGE_SIZE_TO_STORE = 8000000;
619+
if ('data' in imageData &&
620+
imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) {
621+
pageProxy.cleanupAfterRender = true;
622+
}
598623
break;
599624
default:
600-
error('Got unkown object type ' + type);
625+
error('Got unknown object type ' + type);
601626
}
602627
}, this);
603628

src/canvas.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,13 +208,14 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
208208
// before it stops and shedules a continue of execution.
209209
var kExecutionTime = 15;
210210

211-
function CanvasGraphics(canvasCtx, objs, textLayer) {
211+
function CanvasGraphics(canvasCtx, commonObjs, objs, textLayer) {
212212
this.ctx = canvasCtx;
213213
this.current = new CanvasExtraState();
214214
this.stateStack = [];
215215
this.pendingClip = null;
216216
this.res = null;
217217
this.xobjs = null;
218+
this.commonObjs = commonObjs;
218219
this.objs = objs;
219220
this.textLayer = textLayer;
220221
if (canvasCtx) {
@@ -283,6 +284,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
283284
var executionEndIdx;
284285
var endTime = Date.now() + kExecutionTime;
285286

287+
var commonObjs = this.commonObjs;
286288
var objs = this.objs;
287289
var fnName;
288290
var slowCommands = this.slowCommands;
@@ -301,13 +303,18 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
301303
var deps = argsArray[i];
302304
for (var n = 0, nn = deps.length; n < nn; n++) {
303305
var depObjId = deps[n];
306+
var common = depObjId.substring(0, 2) == 'g_';
304307

305308
// If the promise isn't resolved yet, add the continueCallback
306309
// to the promise and bail out.
307-
if (!objs.isResolved(depObjId)) {
310+
if (!common && !objs.isResolved(depObjId)) {
308311
objs.get(depObjId, continueCallback);
309312
return i;
310313
}
314+
if (common && !commonObjs.isResolved(depObjId)) {
315+
commonObjs.get(depObjId, continueCallback);
316+
return i;
317+
}
311318
}
312319
}
313320

@@ -620,7 +627,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
620627
this.current.leading = -leading;
621628
},
622629
setFont: function CanvasGraphics_setFont(fontRefName, size) {
623-
var fontObj = this.objs.get(fontRefName);
630+
var fontObj = this.commonObjs.get(fontRefName);
624631
var current = this.current;
625632

626633
if (!fontObj)

src/core.js

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ globalScope.PDFJS.getPdf = getPdf;
9797
globalScope.PDFJS.pdfBug = false;
9898

9999
var Page = (function PageClosure() {
100-
function Page(xref, pageNumber, pageDict, ref) {
101-
this.pageNumber = pageNumber;
100+
function Page(xref, pageIndex, pageDict, ref) {
101+
this.pageIndex = pageIndex;
102102
this.pageDict = pageDict;
103103
this.xref = xref;
104104
this.ref = ref;
@@ -167,14 +167,11 @@ var Page = (function PageClosure() {
167167
}
168168
return shadow(this, 'rotate', rotate);
169169
},
170-
171-
getOperatorList: function Page_getOperatorList(handler, dependency) {
172-
var xref = this.xref;
170+
getContentStream: function Page_getContentStream() {
173171
var content = this.content;
174-
var resources = this.resources;
175172
if (isArray(content)) {
176173
// fetching items
177-
var streams = [];
174+
var xref = this.xref;
178175
var i, n = content.length;
179176
var streams = [];
180177
for (i = 0; i < n; ++i)
@@ -184,13 +181,19 @@ var Page = (function PageClosure() {
184181
content.reset();
185182
} else if (!content) {
186183
// replacing non-existent page content with empty one
187-
content = new Stream(new Uint8Array(0));
184+
content = new NullStream();
188185
}
189-
186+
return content;
187+
},
188+
getOperatorList: function Page_getOperatorList(handler, dependency) {
189+
var xref = this.xref;
190+
var contentStream = this.getContentStream();
191+
var resources = this.resources;
190192
var pe = this.pe = new PartialEvaluator(
191-
xref, handler, 'p' + this.pageNumber + '_');
193+
xref, handler, this.pageIndex,
194+
'p' + this.pageIndex + '_');
192195

193-
return pe.getOperatorList(content, resources, dependency);
196+
return pe.getOperatorList(contentStream, resources, dependency);
194197
},
195198
extractTextContent: function Page_extractTextContent() {
196199
var handler = {
@@ -199,40 +202,13 @@ var Page = (function PageClosure() {
199202
};
200203

201204
var xref = this.xref;
202-
var content = xref.fetchIfRef(this.content);
205+
var contentStream = this.getContentStream();
203206
var resources = xref.fetchIfRef(this.resources);
204-
if (isArray(content)) {
205-
// fetching items
206-
var i, n = content.length;
207-
var streams = [];
208-
for (i = 0; i < n; ++i)
209-
streams.push(xref.fetchIfRef(content[i]));
210-
content = new StreamsSequenceStream(streams);
211-
} else if (isStream(content)) {
212-
content.reset();
213-
}
214207

215208
var pe = new PartialEvaluator(
216-
xref, handler, 'p' + this.pageNumber + '_');
217-
return pe.getTextContent(content, resources);
218-
},
219-
220-
ensureFonts: function Page_ensureFonts(fonts, callback) {
221-
this.stats.time('Font Loading');
222-
// Convert the font names to the corresponding font obj.
223-
for (var i = 0, ii = fonts.length; i < ii; i++) {
224-
fonts[i] = this.objs.objs[fonts[i]].data;
225-
}
226-
227-
// Load all the fonts
228-
FontLoader.bind(
229-
fonts,
230-
function pageEnsureFontsFontObjs(fontObjs) {
231-
this.stats.timeEnd('Font Loading');
232-
233-
callback.call(this);
234-
}.bind(this)
235-
);
209+
xref, handler, this.pageIndex,
210+
'p' + this.pageIndex + '_');
211+
return pe.getTextContent(contentStream, resources);
236212
},
237213
getLinks: function Page_getLinks() {
238214
var links = [];

src/evaluator.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
'use strict';
1919

2020
var PartialEvaluator = (function PartialEvaluatorClosure() {
21-
function PartialEvaluator(xref, handler, uniquePrefix) {
21+
function PartialEvaluator(xref, handler, pageIndex, uniquePrefix) {
2222
this.state = new EvalState();
2323
this.stateStack = [];
2424

2525
this.xref = xref;
2626
this.handler = handler;
27+
this.pageIndex = pageIndex;
2728
this.uniquePrefix = uniquePrefix;
2829
this.objIdCounter = 0;
2930
this.fontIdCounter = 0;
@@ -151,15 +152,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
151152
if (!isDict(font)) {
152153
return {
153154
translated: new ErrorFont('Font ' + fontName + ' is not available'),
154-
loadedName: 'font_' + this.uniquePrefix + this.fontIdCounter
155+
loadedName: 'g_font_' + this.uniquePrefix + this.fontIdCounter
155156
};
156157
}
157158

158159
var loadedName = font.loadedName;
159160
if (!loadedName) {
160161
// keep track of each font we translated so the caller can
161162
// load them asynchronously before calling display on a page
162-
loadedName = 'font_' + this.uniquePrefix + this.fontIdCounter;
163+
loadedName = 'g_font_' + this.uniquePrefix + this.fontIdCounter;
163164
font.loadedName = loadedName;
164165

165166
var translated;
@@ -197,6 +198,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
197198
var self = this;
198199
var xref = this.xref;
199200
var handler = this.handler;
201+
var pageIndex = this.pageIndex;
200202
var uniquePrefix = this.uniquePrefix || '';
201203

202204
function insertDependency(depList) {
@@ -217,7 +219,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
217219
if (!font.sent) {
218220
var data = font.translated.exportData();
219221

220-
handler.send('obj', [
222+
handler.send('commonobj', [
221223
loadedName,
222224
'Font',
223225
data
@@ -271,7 +273,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
271273
image.isNativelySupported(xref, resources)) {
272274
// These JPEGs don't need any more processing so we can just send it.
273275
fn = 'paintJpegXObject';
274-
handler.send('obj', [objId, 'JpegStream', image.getIR()]);
276+
handler.send('obj', [objId, pageIndex, 'JpegStream', image.getIR()]);
275277
return;
276278
}
277279

@@ -287,7 +289,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
287289
};
288290
var pixels = imgData.data;
289291
imageObj.fillRgbaBuffer(pixels, drawWidth, drawHeight);
290-
handler.send('obj', [objId, 'Image', imgData]);
292+
handler.send('obj', [objId, pageIndex, 'Image', imgData]);
291293
}, handler, xref, resources, image, inline);
292294
}
293295

src/obj.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -754,8 +754,6 @@ var PDFObjects = (function PDFObjectsClosure() {
754754
}
755755

756756
PDFObjects.prototype = {
757-
objs: null,
758-
759757
/**
760758
* Internal function.
761759
* Ensures there is an object defined for `objId`. Stores `data` on the
@@ -832,13 +830,29 @@ var PDFObjects = (function PDFObjectsClosure() {
832830
}
833831
},
834832

833+
/**
834+
* Returns the data of `objId` if object exists, null otherwise.
835+
*/
836+
getData: function PDFObjects_getData(objId) {
837+
var objs = this.objs;
838+
if (!objs[objId] || !objs[objId].hasData) {
839+
return null;
840+
} else {
841+
return objs[objId].data;
842+
}
843+
},
844+
835845
/**
836846
* Sets the data of an object but *doesn't* resolve it.
837847
*/
838848
setData: function PDFObjects_setData(objId, data) {
839849
// Watchout! If you call `this.ensureObj(objId, data)` you're going to
840850
// create a *resolved* promise which shouldn't be the case!
841851
this.ensureObj(objId).data = data;
852+
},
853+
854+
clear: function PDFObjects_clear() {
855+
this.objs = {};
842856
}
843857
};
844858
return PDFObjects;

src/pattern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ var TilingPattern = (function TilingPatternClosure() {
286286

287287
// set the new canvas element context as the graphics context
288288
var tmpCtx = tmpCanvas.getContext('2d');
289-
var graphics = new CanvasGraphics(tmpCtx, objs);
289+
var graphics = new CanvasGraphics(tmpCtx, null, objs);
290290

291291
switch (paintType) {
292292
case PaintType.COLORED:

0 commit comments

Comments
 (0)