Skip to content

Commit 8a4a6f4

Browse files
committed
Merge pull request mozilla#3553 from yurydelendik/reduce-scratch-canvases
Reduce max size for pattern and limit group canvases
2 parents 0fc8bac + b8143b3 commit 8a4a6f4

File tree

2 files changed

+43
-38
lines changed

2 files changed

+43
-38
lines changed

src/display/canvas.js

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -158,19 +158,24 @@ function addContextCurrentTransform(ctx) {
158158
var CachedCanvases = (function CachedCanvasesClosure() {
159159
var cache = {};
160160
return {
161-
getCanvas: function CachedCanvases_getCanvas(id, width, height) {
162-
var canvas;
161+
getCanvas: function CachedCanvases_getCanvas(id, width, height,
162+
trackTransform) {
163+
var canvasEntry;
163164
if (id in cache) {
164-
canvas = cache[id];
165-
canvas.width = width;
166-
canvas.height = height;
165+
canvasEntry = cache[id];
166+
canvasEntry.canvas.width = width;
167+
canvasEntry.canvas.height = height;
167168
// reset canvas transform for emulated mozCurrentTransform, if needed
168-
canvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0);
169+
canvasEntry.context.setTransform(1, 0, 0, 1, 0, 0);
169170
} else {
170-
canvas = createScratchCanvas(width, height);
171-
cache[id] = canvas;
171+
var canvas = createScratchCanvas(width, height);
172+
var ctx = canvas.getContext('2d');
173+
if (trackTransform) {
174+
addContextCurrentTransform(ctx);
175+
}
176+
cache[id] = canvasEntry = {canvas: canvas, context: ctx};
172177
}
173-
return canvas;
178+
return canvasEntry;
174179
},
175180
clear: function () {
176181
cache = {};
@@ -399,6 +404,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
399404
// spec 8.7.2 NOTE 1.
400405
this.baseTransform = null;
401406
this.baseTransformStack = [];
407+
this.groupLevel = 0;
402408
if (canvasCtx) {
403409
addContextCurrentTransform(canvasCtx);
404410
}
@@ -745,7 +751,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
745751
// for patterns, we transform to pattern space, calculate
746752
// the pattern, call stroke, and restore to user space
747753
ctx.save();
748-
ctx.strokeStyle = strokeColor.getPattern(ctx);
754+
ctx.strokeStyle = strokeColor.getPattern(ctx, this);
749755
ctx.stroke();
750756
ctx.restore();
751757
} else {
@@ -769,7 +775,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
769775
if (fillColor && fillColor.hasOwnProperty('type') &&
770776
fillColor.type === 'Pattern') {
771777
ctx.save();
772-
ctx.fillStyle = fillColor.getPattern(ctx);
778+
ctx.fillStyle = fillColor.getPattern(ctx, this);
773779
needRestore = true;
774780
}
775781

@@ -1393,7 +1399,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
13931399

13941400
this.save();
13951401
var pattern = Pattern.shadingFromIR(patternIR);
1396-
ctx.fillStyle = pattern.getPattern(ctx);
1402+
ctx.fillStyle = pattern.getPattern(ctx, this);
13971403

13981404
var inv = ctx.mozCurrentTransformInverse;
13991405
if (inv) {
@@ -1505,9 +1511,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
15051511
var drawnWidth = Math.max(Math.ceil(bounds[2] - bounds[0]), 1);
15061512
var drawnHeight = Math.max(Math.ceil(bounds[3] - bounds[1]), 1);
15071513

1508-
var scratchCanvas = createScratchCanvas(drawnWidth, drawnHeight);
1509-
var groupCtx = scratchCanvas.getContext('2d');
1510-
addContextCurrentTransform(groupCtx);
1514+
var scratchCanvas = CachedCanvases.getCanvas(
1515+
'groupAt' + this.groupLevel, drawnWidth, drawnHeight, true);
1516+
var groupCtx = scratchCanvas.context;
15111517
// Since we created a new canvas that is just the size of the bounding box
15121518
// we have to translate the group ctx.
15131519
var offsetX = bounds[0];
@@ -1519,7 +1525,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
15191525
// location.
15201526
currentCtx.setTransform(1, 0, 0, 1, 0, 0);
15211527
currentCtx.translate(offsetX, offsetY);
1522-
15231528
// The transparency group inherits all off the current graphics state
15241529
// except the blend mode, soft mask, and alpha constants.
15251530
copyCtxState(currentCtx, groupCtx);
@@ -1531,9 +1536,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
15311536
['CA', 1]
15321537
]);
15331538
this.groupStack.push(currentCtx);
1539+
this.groupLevel++;
15341540
},
15351541

15361542
endGroup: function CanvasGraphics_endGroup(group) {
1543+
this.groupLevel--;
15371544
var groupCtx = this.ctx;
15381545
this.ctx = this.groupStack.pop();
15391546
// Turn off image smoothing to avoid sub pixel interpolation which can
@@ -1626,7 +1633,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
16261633
}
16271634

16281635
var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height);
1629-
var maskCtx = maskCanvas.getContext('2d');
1636+
var maskCtx = maskCanvas.context;
16301637
maskCtx.save();
16311638

16321639
putBinaryImageData(maskCtx, img);
@@ -1636,12 +1643,12 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
16361643
var fillColor = this.current.fillColor;
16371644
maskCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
16381645
fillColor.type === 'Pattern') ?
1639-
fillColor.getPattern(maskCtx) : fillColor;
1646+
fillColor.getPattern(maskCtx, this) : fillColor;
16401647
maskCtx.fillRect(0, 0, width, height);
16411648

16421649
maskCtx.restore();
16431650

1644-
this.paintInlineImageXObject(maskCanvas);
1651+
this.paintInlineImageXObject(maskCanvas.canvas);
16451652
},
16461653

16471654
paintImageMaskXObjectGroup:
@@ -1653,7 +1660,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
16531660
var width = image.width, height = image.height;
16541661

16551662
var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height);
1656-
var maskCtx = maskCanvas.getContext('2d');
1663+
var maskCtx = maskCanvas.context;
16571664
maskCtx.save();
16581665

16591666
putBinaryImageData(maskCtx, image);
@@ -1663,15 +1670,15 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
16631670
var fillColor = this.current.fillColor;
16641671
maskCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
16651672
fillColor.type === 'Pattern') ?
1666-
fillColor.getPattern(maskCtx) : fillColor;
1673+
fillColor.getPattern(maskCtx, this) : fillColor;
16671674
maskCtx.fillRect(0, 0, width, height);
16681675

16691676
maskCtx.restore();
16701677

16711678
ctx.save();
16721679
ctx.transform.apply(ctx, image.transform);
16731680
ctx.scale(1, -1);
1674-
ctx.drawImage(maskCanvas, 0, 0, width, height,
1681+
ctx.drawImage(maskCanvas.canvas, 0, 0, width, height,
16751682
0, -1, 1, 1);
16761683
ctx.restore();
16771684
}
@@ -1706,9 +1713,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
17061713
imgToPaint = imgData;
17071714
} else {
17081715
var tmpCanvas = CachedCanvases.getCanvas('inlineImage', width, height);
1709-
var tmpCtx = tmpCanvas.getContext('2d');
1716+
var tmpCtx = tmpCanvas.context;
17101717
putBinaryImageData(tmpCtx, imgData);
1711-
imgToPaint = tmpCanvas;
1718+
imgToPaint = tmpCanvas.canvas;
17121719
}
17131720

17141721
var paintWidth = width, paintHeight = height;
@@ -1729,11 +1736,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
17291736
}
17301737
var tmpCanvas = CachedCanvases.getCanvas(tmpCanvasId,
17311738
newWidth, newHeight);
1732-
tmpCtx = tmpCanvas.getContext('2d');
1739+
tmpCtx = tmpCanvas.context;
17331740
tmpCtx.clearRect(0, 0, newWidth, newHeight);
17341741
tmpCtx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight,
17351742
0, 0, newWidth, newHeight);
1736-
imgToPaint = tmpCanvas;
1743+
imgToPaint = tmpCanvas.canvas;
17371744
paintWidth = newWidth;
17381745
paintHeight = newHeight;
17391746
tmpCanvasId = tmpCanvasId === 'prescale1' ? 'prescale2' : 'prescale1';
@@ -1761,15 +1768,15 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
17611768
var h = imgData.height;
17621769

17631770
var tmpCanvas = CachedCanvases.getCanvas('inlineImage', w, h);
1764-
var tmpCtx = tmpCanvas.getContext('2d');
1771+
var tmpCtx = tmpCanvas.context;
17651772
putBinaryImageData(tmpCtx, imgData);
17661773

17671774
for (var i = 0, ii = map.length; i < ii; i++) {
17681775
var entry = map[i];
17691776
ctx.save();
17701777
ctx.transform.apply(ctx, entry.transform);
17711778
ctx.scale(1, -1);
1772-
ctx.drawImage(tmpCanvas, entry.x, entry.y, entry.w, entry.h,
1779+
ctx.drawImage(tmpCanvas.canvas, entry.x, entry.y, entry.w, entry.h,
17731780
0, -1, 1, 1);
17741781
if (this.imageLayer) {
17751782
var position = this.getCanvasPosition(entry.x, entry.y);

src/shared/pattern.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ var TilingPattern = (function TilingPatternClosure() {
269269
UNCOLORED: 2
270270
};
271271

272-
var MAX_PATTERN_SIZE = 8192;
272+
var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
273273

274274
function TilingPattern(IR, color, ctx, objs, commonObjs, baseTransform) {
275275
this.name = IR[1][0].name;
@@ -303,7 +303,7 @@ var TilingPattern = (function TilingPatternClosure() {
303303
};
304304

305305
TilingPattern.prototype = {
306-
createPatternCanvas: function TilinPattern_createPatternCanvas(tmpCanvas) {
306+
createPatternCanvas: function TilinPattern_createPatternCanvas(owner) {
307307
var operatorList = this.operatorList;
308308
var bbox = this.bbox;
309309
var xstep = this.xstep;
@@ -343,12 +343,10 @@ var TilingPattern = (function TilingPatternClosure() {
343343
height = Math.min(Math.ceil(Math.abs(height * combinedScale[1])),
344344
MAX_PATTERN_SIZE);
345345

346-
tmpCanvas.width = width;
347-
tmpCanvas.height = height;
348-
349-
// set the new canvas element context as the graphics context
350-
var tmpCtx = tmpCanvas.getContext('2d');
346+
var tmpCanvas = CachedCanvases.getCanvas('pattern', width, height, true);
347+
var tmpCtx = tmpCanvas.context;
351348
var graphics = new CanvasGraphics(tmpCtx, commonObjs, objs);
349+
graphics.groupLevel = owner.groupLevel;
352350

353351
this.setFillAndStrokeStyleToContext(tmpCtx, paintType, color);
354352

@@ -362,6 +360,7 @@ var TilingPattern = (function TilingPatternClosure() {
362360
this.clipBbox(graphics, bbox, x0, y0, x1, y1);
363361

364362
graphics.executeOperatorList(operatorList);
363+
return tmpCanvas.canvas;
365364
},
366365

367366
setScale: function TilingPattern_setScale(width, height, xstep, ystep) {
@@ -408,9 +407,8 @@ var TilingPattern = (function TilingPatternClosure() {
408407
}
409408
},
410409

411-
getPattern: function TilingPattern_getPattern() {
412-
var temporaryPatternCanvas = CachedCanvases.getCanvas('pattern');
413-
this.createPatternCanvas(temporaryPatternCanvas);
410+
getPattern: function TilingPattern_getPattern(ctx, owner) {
411+
var temporaryPatternCanvas = this.createPatternCanvas(owner);
414412

415413
var ctx = this.ctx;
416414
ctx.setTransform.apply(ctx, this.baseTransform);

0 commit comments

Comments
 (0)