Merge pull request #7176 from yurydelendik/smask-resume

Allow SMask be resumed after restore() and better transform after SMask
This commit is contained in:
Jonas Jenwald 2016-04-11 15:57:40 +02:00
commit be6754a1a0
6 changed files with 110 additions and 8 deletions

View File

@ -432,7 +432,8 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
this.fillAlpha = 1; this.fillAlpha = 1;
this.strokeAlpha = 1; this.strokeAlpha = 1;
this.lineWidth = 1; this.lineWidth = 1;
this.activeSMask = null; // nonclonable field (see the save method below) this.activeSMask = null;
this.resumeSMaskCtx = null; // nonclonable field (see the save method below)
this.old = old; this.old = old;
} }
@ -869,6 +870,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}, },
endDrawing: function CanvasGraphics_endDrawing() { endDrawing: function CanvasGraphics_endDrawing() {
// Finishing all opened operations such as SMask group painting.
if (this.current.activeSMask !== null) {
this.endSMaskGroup();
}
this.ctx.restore(); this.ctx.restore();
if (this.transparentCanvas) { if (this.transparentCanvas) {
@ -977,7 +983,16 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
break; break;
case 'SMask': case 'SMask':
if (this.current.activeSMask) { if (this.current.activeSMask) {
this.endSMaskGroup(); // If SMask is currrenly used, it needs to be suspended or
// finished. Suspend only makes sense when at least one save()
// was performed and state needs to be reverted on restore().
if (this.stateStack.length > 0 &&
(this.stateStack[this.stateStack.length - 1].activeSMask ===
this.current.activeSMask)) {
this.suspendSMaskGroup();
} else {
this.endSMaskGroup();
}
} }
this.current.activeSMask = value ? this.tempSMask : null; this.current.activeSMask = value ? this.tempSMask : null;
if (this.current.activeSMask) { if (this.current.activeSMask) {
@ -1006,6 +1021,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY); groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);
groupCtx.transform.apply(groupCtx, currentTransform); groupCtx.transform.apply(groupCtx, currentTransform);
activeSMask.startTransformInverse = groupCtx.mozCurrentTransformInverse;
copyCtxState(currentCtx, groupCtx); copyCtxState(currentCtx, groupCtx);
this.ctx = groupCtx; this.ctx = groupCtx;
this.setGState([ this.setGState([
@ -1016,6 +1033,43 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.groupStack.push(currentCtx); this.groupStack.push(currentCtx);
this.groupLevel++; this.groupLevel++;
}, },
suspendSMaskGroup: function CanvasGraphics_endSMaskGroup() {
// Similar to endSMaskGroup, the intermediate canvas has to be composed
// and future ctx state restored.
var groupCtx = this.ctx;
this.groupLevel--;
this.ctx = this.groupStack.pop();
composeSMask(this.ctx, this.current.activeSMask, groupCtx);
this.ctx.restore();
this.ctx.save(); // save is needed since SMask will be resumed.
copyCtxState(groupCtx, this.ctx);
// Saving state for resuming.
this.current.resumeSMaskCtx = groupCtx;
// Transform was changed in the SMask canvas, reflecting this change on
// this.ctx.
var deltaTransform = Util.transform(
this.current.activeSMask.startTransformInverse,
groupCtx.mozCurrentTransform);
this.ctx.transform.apply(this.ctx, deltaTransform);
// SMask was composed, the results at the groupCtx can be cleared.
groupCtx.save();
groupCtx.setTransform(1, 0, 0, 1, 0, 0);
groupCtx.clearRect(0, 0, groupCtx.canvas.width, groupCtx.canvas.height);
groupCtx.restore();
},
resumeSMaskGroup: function CanvasGraphics_endSMaskGroup() {
// Resuming state saved by suspendSMaskGroup. We don't need to restore
// any groupCtx state since restore() command (the only caller) will do
// that for us. See also beginSMaskGroup.
var groupCtx = this.current.resumeSMaskCtx;
var currentCtx = this.ctx;
this.ctx = groupCtx;
this.groupStack.push(currentCtx);
this.groupLevel++;
},
endSMaskGroup: function CanvasGraphics_endSMaskGroup() { endSMaskGroup: function CanvasGraphics_endSMaskGroup() {
var groupCtx = this.ctx; var groupCtx = this.ctx;
this.groupLevel--; this.groupLevel--;
@ -1024,20 +1078,34 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
composeSMask(this.ctx, this.current.activeSMask, groupCtx); composeSMask(this.ctx, this.current.activeSMask, groupCtx);
this.ctx.restore(); this.ctx.restore();
copyCtxState(groupCtx, this.ctx); copyCtxState(groupCtx, this.ctx);
// Transform was changed in the SMask canvas, reflecting this change on
// this.ctx.
var deltaTransform = Util.transform(
this.current.activeSMask.startTransformInverse,
groupCtx.mozCurrentTransform);
this.ctx.transform.apply(this.ctx, deltaTransform);
}, },
save: function CanvasGraphics_save() { save: function CanvasGraphics_save() {
this.ctx.save(); this.ctx.save();
var old = this.current; var old = this.current;
this.stateStack.push(old); this.stateStack.push(old);
this.current = old.clone(); this.current = old.clone();
this.current.activeSMask = null; this.current.resumeSMaskCtx = null;
}, },
restore: function CanvasGraphics_restore() { restore: function CanvasGraphics_restore() {
if (this.stateStack.length !== 0) { // SMask was suspended, we just need to resume it.
if (this.current.activeSMask !== null) { if (this.current.resumeSMaskCtx) {
this.endSMaskGroup(); this.resumeSMaskGroup();
} }
// SMask has to be finished once there is no states that are using the
// same SMask.
if (this.current.activeSMask !== null && (this.stateStack.length === 0 ||
this.stateStack[this.stateStack.length - 1].activeSMask !==
this.current.activeSMask)) {
this.endSMaskGroup();
}
if (this.stateStack.length !== 0) {
this.current = this.stateStack.pop(); this.current = this.stateStack.pop();
this.ctx.restore(); this.ctx.restore();
@ -1825,7 +1893,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
scaleY: scaleY, scaleY: scaleY,
subtype: group.smask.subtype, subtype: group.smask.subtype,
backdrop: group.smask.backdrop, backdrop: group.smask.backdrop,
transferMap: group.smask.transferMap || null transferMap: group.smask.transferMap || null,
startTransformInverse: null, // used during suspend operation
}); });
} else { } else {
// Setup the current ctx so when the group is popped we draw it at the // Setup the current ctx so when the group is popped we draw it at the
@ -1845,6 +1914,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
]); ]);
this.groupStack.push(currentCtx); this.groupStack.push(currentCtx);
this.groupLevel++; this.groupLevel++;
// Reseting mask state, masks will be applied on restore of the group.
this.current.activeSMask = null;
}, },
endGroup: function CanvasGraphics_endGroup(group) { endGroup: function CanvasGraphics_endGroup(group) {

View File

@ -215,6 +215,7 @@
!issue6069.pdf !issue6069.pdf
!issue6106.pdf !issue6106.pdf
!issue6296.pdf !issue6296.pdf
!bug852992_reduced.pdf
!issue6298.pdf !issue6298.pdf
!issue6889.pdf !issue6889.pdf
!bug1001080.pdf !bug1001080.pdf

View File

@ -0,0 +1 @@
https://bugzilla.mozilla.org/attachment.cgi?id=8653724

Binary file not shown.

View File

@ -0,0 +1 @@
http://web.archive.org/web/20160405054842/http://www.sec.gov/investor/pubs/sec-guide-to-proxy-brochures.pdf

View File

@ -1503,6 +1503,33 @@
"link": true, "link": true,
"type": "eq" "type": "eq"
}, },
{
"id": "bug852992",
"file": "pdfs/bug852992_reduced.pdf",
"md5": "c11439fe3b7f8bc39d89dcff58c50a0c",
"rounds": 1,
"type": "eq"
},
{
"id": "bug1199237",
"file": "pdfs/bug1199237.pdf",
"md5": "e9a63d3207ccc65a4955d5723546e962",
"rounds": 1,
"firstPage": 1,
"lastPage": 1,
"link": true,
"type": "eq"
},
{
"id": "issue6165",
"file": "pdfs/issue6165.pdf",
"md5": "84ebde43b9121aa2ef8026388a4f4244",
"rounds": 1,
"firstPage": 1,
"lastPage": 1,
"link": true,
"type": "eq"
},
{ {
"id": "issue6019-text", "id": "issue6019-text",
"file": "pdfs/issue6019.pdf", "file": "pdfs/issue6019.pdf",