[Pkg-javascript-commits] [pdf.js] 24/161: Caching inlined mask images
David Prévot
taffit at moszumanska.debian.org
Sat Apr 19 14:16:19 UTC 2014
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository pdf.js.
commit 257898b359e108fa373115870c89605ba270c090
Author: Yury Delendik <ydelendik at mozilla.com>
Date: Mon Feb 24 09:59:02 2014 -0600
Caching inlined mask images
---
src/core/evaluator.js | 98 +++++++++++++++++++++++++++++++++++++++++----------
src/core/parser.js | 45 ++++++++++++++++++++++-
src/display/canvas.js | 61 ++++++++++++++++++++++++--------
src/shared/util.js | 3 +-
4 files changed, 172 insertions(+), 35 deletions(-)
diff --git a/src/core/evaluator.js b/src/core/evaluator.js
index d05f1ee..54b4a9e 100644
--- a/src/core/evaluator.js
+++ b/src/core/evaluator.js
@@ -152,10 +152,16 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var canTransfer = image instanceof DecodeStream;
var inverseDecode = !!decode && decode[0] > 0;
- operatorList.addOp(OPS.paintImageMaskXObject,
- [PDFImage.createMask(imgArray, width, height, canTransfer,
- inverseDecode)]
- );
+ var imgData = PDFImage.createMask(imgArray, width, height,
+ canTransfer, inverseDecode);
+ imgData.cached = true;
+ var args = [imgData];
+ operatorList.addOp(OPS.paintImageMaskXObject, args);
+ if (cacheKey) {
+ cache.key = cacheKey;
+ cache.fn = OPS.paintImageMaskXObject;
+ cache.args = args;
+ }
return;
}
@@ -553,8 +559,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
args[0] = loadedName;
break;
case OPS.endInlineImage:
+ var cacheKey = args[0].cacheKey;
+ if (cacheKey && imageCache.key === cacheKey) {
+ operatorList.addOp(imageCache.fn, imageCache.args);
+ args = [];
+ continue;
+ }
self.buildPaintImageXObject(resources, args[0], true,
- operatorList);
+ operatorList, cacheKey, imageCache);
args = [];
continue;
case OPS.save:
@@ -1276,7 +1288,9 @@ var OperatorList = (function OperatorListClosure() {
case OPS.paintInlineImageXObjectGroup:
case OPS.paintImageMaskXObject:
var arg = argsArray[i][0]; // first param in imgData
- transfers.push(arg.data.buffer);
+ if (!arg.cached) {
+ transfers.push(arg.data.buffer);
+ }
break;
}
}
@@ -1774,6 +1788,7 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
// searching for (save, transform, paintImageMaskXObject, restore)+
var MIN_IMAGES_IN_MASKS_BLOCK = 10;
var MAX_IMAGES_IN_MASKS_BLOCK = 100;
+ var MAX_SAME_IMAGES_IN_MASKS_BLOCK = 1000;
var fnArray = context.fnArray, argsArray = context.argsArray;
var j = context.currentOperation - 3, i = j + 4;
@@ -1781,24 +1796,69 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
for (; i < ii && fnArray[i - 4] === fnArray[i]; i++) {
}
- var count = Math.min((i - j) >> 2, MAX_IMAGES_IN_MASKS_BLOCK);
+ var count = (i - j) >> 2;
if (count < MIN_IMAGES_IN_MASKS_BLOCK) {
context.currentOperation = i - 1;
return;
}
- var images = [];
- for (var q = 0; q < count; q++) {
- var transform = argsArray[j + (q << 2) + 1];
- var maskParams = argsArray[j + (q << 2) + 2][0];
- images.push({data: maskParams.data, width: maskParams.width,
- height: maskParams.height, transform: transform});
+
+ var isSameImage = false;
+ if (argsArray[j + 1][1] === 0 && argsArray[j + 1][2] === 0) {
+ i = j + 4;
+ isSameImage = true;
+ for (var q = 1; q < count; q++, i += 4) {
+ var prevTransformArgs = argsArray[i - 3];
+ var transformArgs = argsArray[i + 1];
+ if (argsArray[i - 2][0] !== argsArray[i + 2][0] ||
+ prevTransformArgs[0] !== transformArgs[0] ||
+ prevTransformArgs[1] !== transformArgs[1] ||
+ prevTransformArgs[2] !== transformArgs[2] ||
+ prevTransformArgs[3] !== transformArgs[3]) {
+ if (q < MIN_IMAGES_IN_MASKS_BLOCK) {
+ isSameImage = false;
+ } else {
+ count = q;
+ }
+ break; // different image or transform
+ }
+ }
}
- // replacing queue items
- squash(fnArray, j, count * 4, OPS.paintImageMaskXObjectGroup);
- argsArray.splice(j, count * 4, [images]);
- context.currentOperation = j;
- context.operationsLength -= count * 4 - 1;
+ if (isSameImage) {
+ count = Math.min(count, MAX_SAME_IMAGES_IN_MASKS_BLOCK);
+ var positions = new Float32Array(count * 2);
+ i = j + 1;
+ for (var q = 0; q < count; q++) {
+ var transformArgs = argsArray[i];
+ positions[(q << 1)] = transformArgs[4];
+ positions[(q << 1) + 1] = transformArgs[5];
+ i += 4;
+ }
+
+ // replacing queue items
+ squash(fnArray, j, count * 4, OPS.paintImageMaskXObjectRepeat);
+ argsArray.splice(j, count * 4, [argsArray[j + 2][0],
+ argsArray[j + 1][0], argsArray[j + 1][3], positions]);
+
+ context.currentOperation = j;
+ context.operationsLength -= count * 4 - 1;
+ } else {
+ count = Math.min(count, MAX_IMAGES_IN_MASKS_BLOCK);
+ var images = [];
+ for (var q = 0; q < count; q++) {
+ var transformArgs = argsArray[j + (q << 2) + 1];
+ var maskParams = argsArray[j + (q << 2) + 2][0];
+ images.push({data: maskParams.data, width: maskParams.width,
+ height: maskParams.height, transform: transformArgs});
+ }
+
+ // replacing queue items
+ squash(fnArray, j, count * 4, OPS.paintImageMaskXObjectGroup);
+ argsArray.splice(j, count * 4, [images]);
+
+ context.currentOperation = j;
+ context.operationsLength -= count * 4 - 1;
+ }
});
addState(InitialState,
@@ -1848,7 +1908,7 @@ var QueueOptimizer = (function QueueOptimizerClosure() {
var args = [argsArray[j + 2][0], argsArray[j + 1][0],
argsArray[j + 1][3], positions];
// replacing queue items
- squash(fnArray, j, count * 4, OPS.paintImageMaskXObjectRepeat);
+ squash(fnArray, j, count * 4, OPS.paintImageXObjectRepeat);
argsArray.splice(j, count * 4, args);
context.currentOperation = j;
diff --git a/src/core/parser.js b/src/core/parser.js
index 5d7aba4..0eb62c5 100644
--- a/src/core/parser.js
+++ b/src/core/parser.js
@@ -32,6 +32,11 @@ var Parser = (function ParserClosure() {
this.lexer = lexer;
this.allowStreams = allowStreams;
this.xref = xref;
+ this.imageCache = {
+ length: 0,
+ adler32: 0,
+ stream: null
+ };
this.refill();
}
@@ -169,10 +174,48 @@ var Parser = (function ParserClosure() {
var length = (stream.pos - 4) - startPos;
var imageStream = stream.makeSubStream(startPos, length, dict);
- if (cipherTransform)
+
+ // trying to cache repeat images, first we are trying to "warm up" caching
+ // using length, then comparing adler32
+ var MAX_LENGTH_TO_CACHE = 1000;
+ var cacheImage = false, adler32;
+ if (length < MAX_LENGTH_TO_CACHE && this.imageCache.length === length) {
+ var imageBytes = imageStream.getBytes();
+ imageStream.reset();
+
+ var a = 1;
+ var b = 0;
+ for (var i = 0, ii = imageBytes.length; i < ii; ++i) {
+ a = (a + (imageBytes[i] & 0xff)) % 65521;
+ b = (b + a) % 65521;
+ }
+ adler32 = (b << 16) | a;
+
+ if (this.imageCache.stream && this.imageCache.adler32 === adler32) {
+ this.buf2 = Cmd.get('EI');
+ this.shift();
+
+ this.imageCache.stream.reset();
+ return this.imageCache.stream;
+ }
+ cacheImage = true;
+ }
+ if (!cacheImage && !this.imageCache.stream) {
+ this.imageCache.length = length;
+ this.imageCache.stream = null;
+ }
+
+ if (cipherTransform) {
imageStream = cipherTransform.createStream(imageStream, length);
+ }
+
imageStream = this.filter(imageStream, dict, length);
imageStream.dict = dict;
+ if (cacheImage) {
+ imageStream.cacheKey = 'inline_' + length + '_' + adler32;
+ this.imageCache.adler32 = adler32;
+ this.imageCache.stream = imageStream;
+ }
this.buf2 = Cmd.get('EI');
this.shift();
diff --git a/src/display/canvas.js b/src/display/canvas.js
index 0226b87..0ff14ea 100644
--- a/src/display/canvas.js
+++ b/src/display/canvas.js
@@ -1924,6 +1924,39 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.paintInlineImageXObject(maskCanvas.canvas);
},
+ paintImageMaskXObjectRepeat:
+ function CanvasGraphics_paintImageMaskXObjectRepeat(imgData, scaleX,
+ scaleY, positions) {
+ var width = imgData.width;
+ var height = imgData.height;
+ var ctx = this.ctx;
+
+ var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height);
+ var maskCtx = maskCanvas.context;
+ maskCtx.save();
+
+ putBinaryImageMask(maskCtx, imgData);
+
+ maskCtx.globalCompositeOperation = 'source-in';
+
+ var fillColor = this.current.fillColor;
+ maskCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
+ fillColor.type === 'Pattern') ?
+ fillColor.getPattern(maskCtx, this) : fillColor;
+ maskCtx.fillRect(0, 0, width, height);
+
+ maskCtx.restore();
+
+ for (var i = 0, ii = positions.length; i < ii; i += 2) {
+ ctx.save();
+ ctx.transform(scaleX, 0, 0, scaleY, positions[i], positions[i + 1]);
+ ctx.scale(1, -1);
+ ctx.drawImage(maskCanvas.canvas, 0, 0, width, height,
+ 0, -1, 1, 1);
+ ctx.restore();
+ }
+ },
+
paintImageMaskXObjectGroup:
function CanvasGraphics_paintImageMaskXObjectGroup(images) {
var ctx = this.ctx;
@@ -1966,22 +1999,22 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.paintInlineImageXObject(imgData);
},
- paintImageMaskXObjectRepeat:
- function CanvasGraphics_paintImageMaskXObjectRepeat(objId, scaleX, scaleY,
+ paintImageXObjectRepeat:
+ function CanvasGraphics_paintImageXObjectRepeat(objId, scaleX, scaleY,
positions) {
- var imgData = this.objs.get(objId);
- if (!imgData) {
- error('Dependent image isn\'t ready yet');
- }
+ var imgData = this.objs.get(objId);
+ if (!imgData) {
+ error('Dependent image isn\'t ready yet');
+ }
- var width = imgData.width;
- var height = imgData.height;
- var map = [];
- for (var i = 0, ii = positions.length; i < ii; i += 2) {
- map.push({transform: [scaleX, 0, 0, scaleY, positions[i],
- positions[i + 1]], x: 0, y: 0, w: width, h: height});
- }
- this.paintInlineImageXObjectGroup(imgData, map);
+ var width = imgData.width;
+ var height = imgData.height;
+ var map = [];
+ for (var i = 0, ii = positions.length; i < ii; i += 2) {
+ map.push({transform: [scaleX, 0, 0, scaleY, positions[i],
+ positions[i + 1]], x: 0, y: 0, w: width, h: height});
+ }
+ this.paintInlineImageXObjectGroup(imgData, map);
},
paintInlineImageXObject:
diff --git a/src/shared/util.js b/src/shared/util.js
index 65b07a5..4803e6d 100644
--- a/src/shared/util.js
+++ b/src/shared/util.js
@@ -150,7 +150,8 @@ var OPS = PDFJS.OPS = {
paintImageXObject: 85,
paintInlineImageXObject: 86,
paintInlineImageXObjectGroup: 87,
- paintImageMaskXObjectRepeat: 88
+ paintImageXObjectRepeat: 88,
+ paintImageMaskXObjectRepeat: 89
};
// A notice for devs. These are good for things that are helpful to devs, such
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/pdf.js.git
More information about the Pkg-javascript-commits
mailing list