Browse Source

Fix #7798: Refactor scratch canvas usage.

Fixes extra canvas create calls.
Fixes unnecessary call of `new DOMCanvasFactory`.
Fixes undefined error of DOMCanvasFactory.
Fixes failures in some of the tests.
Fixes expected behaviour.
Remove unused vars.
Mukul Mishra 8 years ago
parent
commit
32817633c9
  1. 25
      src/display/api.js
  2. 32
      src/display/canvas.js
  3. 28
      src/display/dom_utils.js
  4. 1
      src/display/font_loader.js
  5. 1
      src/display/text_layer.js
  6. 2
      src/display/webgl.js

25
src/display/api.js

@ -61,9 +61,9 @@ var warn = sharedUtil.warn;
var FontFaceObject = displayFontLoader.FontFaceObject; var FontFaceObject = displayFontLoader.FontFaceObject;
var FontLoader = displayFontLoader.FontLoader; var FontLoader = displayFontLoader.FontLoader;
var CanvasGraphics = displayCanvas.CanvasGraphics; var CanvasGraphics = displayCanvas.CanvasGraphics;
var createScratchCanvas = displayCanvas.createScratchCanvas;
var Metadata = displayMetadata.Metadata; var Metadata = displayMetadata.Metadata;
var getDefaultSetting = displayDOMUtils.getDefaultSetting; var getDefaultSetting = displayDOMUtils.getDefaultSetting;
var DOMCanvasFactory = displayDOMUtils.DOMCanvasFactory;
var DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536 var DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536
@ -697,6 +697,9 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* called each time the rendering is paused. To continue * called each time the rendering is paused. To continue
* rendering call the function that is the first argument * rendering call the function that is the first argument
* to the callback. * to the callback.
* @property {Object} canvasFactory - (optional) The factory that will be used
* when creating canvases. The default value is
* {DOMCanvasFactory}.
*/ */
/** /**
@ -805,6 +808,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
var renderingIntent = (params.intent === 'print' ? 'print' : 'display'); var renderingIntent = (params.intent === 'print' ? 'print' : 'display');
var renderInteractiveForms = (params.renderInteractiveForms === true ? var renderInteractiveForms = (params.renderInteractiveForms === true ?
true : /* Default */ false); true : /* Default */ false);
var canvasFactory = params.canvasFactory || new DOMCanvasFactory();
if (!this.intentStates[renderingIntent]) { if (!this.intentStates[renderingIntent]) {
this.intentStates[renderingIntent] = Object.create(null); this.intentStates[renderingIntent] = Object.create(null);
@ -834,7 +838,8 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
this.objs, this.objs,
this.commonObjs, this.commonObjs,
intentState.operatorList, intentState.operatorList,
this.pageNumber); this.pageNumber,
canvasFactory);
internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print'; internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print';
if (!intentState.renderTasks) { if (!intentState.renderTasks) {
intentState.renderTasks = []; intentState.renderTasks = [];
@ -1727,6 +1732,12 @@ var WorkerTransport = (function WorkerTransportClosure() {
return Promise.reject(new Error('Worker was destroyed')); return Promise.reject(new Error('Worker was destroyed'));
} }
if (typeof document === 'undefined') {
// Make sure that this code is not executing in node.js, as
// it's using DOM image, and there is no library to support that.
return Promise.reject(new Error('"document" is not defined.'));
}
var imageUrl = data[0]; var imageUrl = data[0];
var components = data[1]; var components = data[1];
if (components !== 3 && components !== 1) { if (components !== 3 && components !== 1) {
@ -1742,7 +1753,9 @@ var WorkerTransport = (function WorkerTransportClosure() {
var size = width * height; var size = width * height;
var rgbaLength = size * 4; var rgbaLength = size * 4;
var buf = new Uint8Array(size * components); var buf = new Uint8Array(size * components);
var tmpCanvas = createScratchCanvas(width, height); var tmpCanvas = document.createElement('canvas');
tmpCanvas.width = width;
tmpCanvas.height = height;
var tmpCtx = tmpCanvas.getContext('2d'); var tmpCtx = tmpCanvas.getContext('2d');
tmpCtx.drawImage(img, 0, 0); tmpCtx.drawImage(img, 0, 0);
var data = tmpCtx.getImageData(0, 0, width, height).data; var data = tmpCtx.getImageData(0, 0, width, height).data;
@ -2030,7 +2043,7 @@ var RenderTask = (function RenderTaskClosure() {
var InternalRenderTask = (function InternalRenderTaskClosure() { var InternalRenderTask = (function InternalRenderTaskClosure() {
function InternalRenderTask(callback, params, objs, commonObjs, operatorList, function InternalRenderTask(callback, params, objs, commonObjs, operatorList,
pageNumber) { pageNumber, canvasFactory) {
this.callback = callback; this.callback = callback;
this.params = params; this.params = params;
this.objs = objs; this.objs = objs;
@ -2038,6 +2051,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
this.operatorListIdx = null; this.operatorListIdx = null;
this.operatorList = operatorList; this.operatorList = operatorList;
this.pageNumber = pageNumber; this.pageNumber = pageNumber;
this.canvasFactory = canvasFactory;
this.running = false; this.running = false;
this.graphicsReadyCallback = null; this.graphicsReadyCallback = null;
this.graphicsReady = false; this.graphicsReady = false;
@ -2068,7 +2082,8 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
var params = this.params; var params = this.params;
this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs, this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
this.objs, params.imageLayer); this.objs, this.canvasFactory,
params.imageLayer);
this.gfx.beginDrawing(params.transform, params.viewport, transparency); this.gfx.beginDrawing(params.transform, params.viewport, transparency);
this.operatorListIdx = 0; this.operatorListIdx = 0;

32
src/display/canvas.js

@ -80,13 +80,6 @@ var IsLittleEndianCached = {
} }
}; };
function createScratchCanvas(width, height) {
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
return canvas;
}
function addContextCurrentTransform(ctx) { function addContextCurrentTransform(ctx) {
// If the context doesn't expose a `mozCurrentTransform`, add a JS based one. // If the context doesn't expose a `mozCurrentTransform`, add a JS based one.
if (!ctx.mozCurrentTransform) { if (!ctx.mozCurrentTransform) {
@ -204,7 +197,8 @@ function addContextCurrentTransform(ctx) {
} }
var CachedCanvases = (function CachedCanvasesClosure() { var CachedCanvases = (function CachedCanvasesClosure() {
function CachedCanvases() { function CachedCanvases(canvasFactory) {
this.canvasFactory = canvasFactory;
this.cache = Object.create(null); this.cache = Object.create(null);
} }
CachedCanvases.prototype = { CachedCanvases.prototype = {
@ -213,12 +207,11 @@ var CachedCanvases = (function CachedCanvasesClosure() {
var canvasEntry; var canvasEntry;
if (this.cache[id] !== undefined) { if (this.cache[id] !== undefined) {
canvasEntry = this.cache[id]; canvasEntry = this.cache[id];
canvasEntry.canvas.width = width; this.canvasFactory.reset(canvasEntry.canvas, width, height);
canvasEntry.canvas.height = height;
// reset canvas transform for emulated mozCurrentTransform, if needed // reset canvas transform for emulated mozCurrentTransform, if needed
canvasEntry.context.setTransform(1, 0, 0, 1, 0, 0); canvasEntry.context.setTransform(1, 0, 0, 1, 0, 0);
} else { } else {
var canvas = createScratchCanvas(width, height); var canvas = this.canvasFactory.create(width, height);
var ctx = canvas.getContext('2d'); var ctx = canvas.getContext('2d');
if (trackTransform) { if (trackTransform) {
addContextCurrentTransform(ctx); addContextCurrentTransform(ctx);
@ -230,10 +223,7 @@ var CachedCanvases = (function CachedCanvasesClosure() {
clear: function () { clear: function () {
for (var id in this.cache) { for (var id in this.cache) {
var canvasEntry = this.cache[id]; var canvasEntry = this.cache[id];
// Zeroing the width and height causes Firefox to release graphics this.canvasFactory.destroy(canvasEntry.canvas);
// resources immediately, which can greatly reduce memory consumption.
canvasEntry.canvas.width = 0;
canvasEntry.canvas.height = 0;
delete this.cache[id]; delete this.cache[id];
} }
} }
@ -456,7 +446,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// Defines the number of steps before checking the execution time // Defines the number of steps before checking the execution time
var EXECUTION_STEPS = 10; var EXECUTION_STEPS = 10;
function CanvasGraphics(canvasCtx, commonObjs, objs, imageLayer) { function CanvasGraphics(canvasCtx, commonObjs, objs, canvasFactory,
imageLayer) {
this.ctx = canvasCtx; this.ctx = canvasCtx;
this.current = new CanvasExtraState(); this.current = new CanvasExtraState();
this.stateStack = []; this.stateStack = [];
@ -466,6 +457,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.xobjs = null; this.xobjs = null;
this.commonObjs = commonObjs; this.commonObjs = commonObjs;
this.objs = objs; this.objs = objs;
this.canvasFactory = canvasFactory;
this.imageLayer = imageLayer; this.imageLayer = imageLayer;
this.groupStack = []; this.groupStack = [];
this.processingType3 = null; this.processingType3 = null;
@ -477,7 +469,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.smaskStack = []; this.smaskStack = [];
this.smaskCounter = 0; this.smaskCounter = 0;
this.tempSMask = null; this.tempSMask = null;
this.cachedCanvases = new CachedCanvases(); this.cachedCanvases = new CachedCanvases(this.canvasFactory);
if (canvasCtx) { if (canvasCtx) {
// NOTE: if mozCurrentTransform is polyfilled, then the current state of // NOTE: if mozCurrentTransform is polyfilled, then the current state of
// the transformation must already be set in canvasCtx._transformMatrix. // the transformation must already be set in canvasCtx._transformMatrix.
@ -1454,7 +1446,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
get isFontSubpixelAAEnabled() { get isFontSubpixelAAEnabled() {
// Checks if anti-aliasing is enabled when scaled text is painted. // Checks if anti-aliasing is enabled when scaled text is painted.
// On Windows GDI scaled fonts looks bad. // On Windows GDI scaled fonts looks bad.
var ctx = document.createElement('canvas').getContext('2d'); var ctx = this.canvasFactory.create(10, 10).getContext('2d');
ctx.scale(1.5, 1); ctx.scale(1.5, 1);
ctx.fillText('I', 0, 10); ctx.fillText('I', 0, 10);
var data = ctx.getImageData(0, 0, 10, 10).data; var data = ctx.getImageData(0, 0, 10, 10).data;
@ -1700,7 +1692,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var self = this; var self = this;
var canvasGraphicsFactory = { var canvasGraphicsFactory = {
createCanvasGraphics: function (ctx) { createCanvasGraphics: function (ctx) {
return new CanvasGraphics(ctx, self.commonObjs, self.objs); return new CanvasGraphics(ctx, self.commonObjs, self.objs,
self.canvasFactory);
} }
}; };
pattern = new TilingPattern(IR, color, this.ctx, canvasGraphicsFactory, pattern = new TilingPattern(IR, color, this.ctx, canvasGraphicsFactory,
@ -2320,5 +2313,4 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
})(); })();
exports.CanvasGraphics = CanvasGraphics; exports.CanvasGraphics = CanvasGraphics;
exports.createScratchCanvas = createScratchCanvas;
})); }));

28
src/display/dom_utils.js

@ -26,6 +26,7 @@
} }
}(this, function (exports, sharedUtil) { }(this, function (exports, sharedUtil) {
var assert = sharedUtil.assert;
var removeNullCharacters = sharedUtil.removeNullCharacters; var removeNullCharacters = sharedUtil.removeNullCharacters;
var warn = sharedUtil.warn; var warn = sharedUtil.warn;
var deprecated = sharedUtil.deprecated; var deprecated = sharedUtil.deprecated;
@ -33,6 +34,32 @@ var createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl;
var DEFAULT_LINK_REL = 'noopener noreferrer nofollow'; var DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
function DOMCanvasFactory() {}
DOMCanvasFactory.prototype = {
create: function DOMCanvasFactory_create(width, height) {
assert(width > 0 && height > 0, 'invalid canvas size');
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
return canvas;
},
reset: function DOMCanvasFactory_reset(canvas, width, height) {
assert(canvas, 'canvas is not specified');
assert(width > 0 && height > 0, 'invalid canvas size');
canvas.width = width;
canvas.height = height;
},
destroy: function DOMCanvasFactory_destroy(canvas) {
assert(canvas, 'canvas is not specified');
// Zeroing the width and height cause Firefox to release graphics
// resources immediately, which can greatly reduce memory consumption.
canvas.width = 0;
canvas.height = 0;
}
};
/** /**
* Optimised CSS custom property getter/setter. * Optimised CSS custom property getter/setter.
* @class * @class
@ -248,4 +275,5 @@ exports.LinkTarget = LinkTarget;
exports.hasCanvasTypedArrays = hasCanvasTypedArrays; exports.hasCanvasTypedArrays = hasCanvasTypedArrays;
exports.getDefaultSetting = getDefaultSetting; exports.getDefaultSetting = getDefaultSetting;
exports.DEFAULT_LINK_REL = DEFAULT_LINK_REL; exports.DEFAULT_LINK_REL = DEFAULT_LINK_REL;
exports.DOMCanvasFactory = DOMCanvasFactory;
})); }));

1
src/display/font_loader.js

@ -216,6 +216,7 @@ if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {
var i, ii; var i, ii;
// The temporary canvas is used to determine if fonts are loaded.
var canvas = document.createElement('canvas'); var canvas = document.createElement('canvas');
canvas.width = 1; canvas.width = 1;
canvas.height = 1; canvas.height = 1;

1
src/display/text_layer.js

@ -186,6 +186,7 @@ var renderTextLayer = (function renderTextLayerClosure() {
return; return;
} }
// The temporary canvas is used to measure text length in the DOM.
var canvas = document.createElement('canvas'); var canvas = document.createElement('canvas');
if (typeof PDFJSDev === 'undefined' || if (typeof PDFJSDev === 'undefined' ||
PDFJSDev.test('FIREFOX || MOZCENTRAL || GENERIC')) { PDFJSDev.test('FIREFOX || MOZCENTRAL || GENERIC')) {

2
src/display/webgl.js

@ -83,6 +83,8 @@ var WebGLUtils = (function WebGLUtilsClosure() {
if (currentGL) { if (currentGL) {
return; return;
} }
// The temporary canvas is used in the WebGL context.
currentCanvas = document.createElement('canvas'); currentCanvas = document.createElement('canvas');
currentGL = currentCanvas.getContext('webgl', currentGL = currentCanvas.getContext('webgl',
{ premultipliedalpha: false }); { premultipliedalpha: false });

Loading…
Cancel
Save