mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-06-22 16:05:56 +02:00
Merge pull request #21455 from calixteman/bug1873345
Draw non-isolated blend-mode groups against their backdrop (bug 1873345)
This commit is contained in:
commit
fdeed2af5e
@ -5025,16 +5025,7 @@ class HighlightAnnotation extends MarkupAnnotation {
|
||||
|
||||
const quadPoints = (this.data.quadPoints = getQuadPoints(dict, null));
|
||||
if (quadPoints) {
|
||||
const resources = this.appearance?.dict.get("Resources");
|
||||
|
||||
if (!this.appearance || !resources?.has("ExtGState")) {
|
||||
if (this.appearance) {
|
||||
// Workaround for cases where there's no /ExtGState-entry directly
|
||||
// available, e.g. when the appearance stream contains a /XObject of
|
||||
// the /Form-type, since that causes the highlighting to completely
|
||||
// obscure the PDF content below it (fixes issue13242.pdf).
|
||||
warn("HighlightAnnotation - ignoring built-in appearance stream.");
|
||||
}
|
||||
if (!this.appearance) {
|
||||
// Default color is yellow in Acrobat Reader
|
||||
const fillColor = getPdfColorArray(this.color, [1, 1, 0]);
|
||||
const fillAlpha = dict.get("CA");
|
||||
|
||||
@ -523,6 +523,7 @@ class PartialEvaluator {
|
||||
isolated: false,
|
||||
knockout: false,
|
||||
needsIsolation: false,
|
||||
hasSoftMask: false,
|
||||
isGray: false,
|
||||
};
|
||||
|
||||
@ -573,6 +574,7 @@ class PartialEvaluator {
|
||||
|
||||
if (group) {
|
||||
groupOptions.needsIsolation = newOpList.needsIsolation || !!smask;
|
||||
groupOptions.hasSoftMask = newOpList.hasSoftMask || !!smask;
|
||||
operatorList.addOp(OPS.beginGroup, [groupOptions]);
|
||||
operatorList.addOp(OPS.paintFormXObjectBegin, args);
|
||||
operatorList.addOpList(newOpList);
|
||||
|
||||
@ -830,24 +830,29 @@ class OperatorList {
|
||||
* operations require being drawn in isolation (i.e. on a separate canvas).
|
||||
* A group/pattern needs isolation when it uses non-default compositing
|
||||
* (blend mode) or a soft mask. The result is exposed via `needsIsolation`.
|
||||
*
|
||||
* `hasSoftMask` separately flags the use of a soft mask: unlike a plain blend
|
||||
* mode, which a non-isolated group can apply directly against its backdrop, a
|
||||
* soft mask always requires a real intermediate canvas (see bug 1873345).
|
||||
*/
|
||||
class CheckedOperatorList extends OperatorList {
|
||||
needsIsolation = false;
|
||||
|
||||
hasSoftMask = false;
|
||||
|
||||
addOp(fn, args) {
|
||||
if (!this.needsIsolation) {
|
||||
if (!this.needsIsolation || !this.hasSoftMask) {
|
||||
if (fn === OPS.beginGroup) {
|
||||
// Propagate isolation only if the nested group itself needs it.
|
||||
this.needsIsolation = args[0].needsIsolation;
|
||||
this.needsIsolation ||= args[0].needsIsolation;
|
||||
this.hasSoftMask ||= args[0].hasSoftMask;
|
||||
} else if (fn === OPS.setGState) {
|
||||
for (const [key, val] of args[0]) {
|
||||
if (key === "BM" && val !== "source-over") {
|
||||
this.needsIsolation = true;
|
||||
break;
|
||||
}
|
||||
if (key === "SMask" && val !== false) {
|
||||
} else if (key === "SMask" && val !== false) {
|
||||
this.needsIsolation = true;
|
||||
break;
|
||||
this.hasSoftMask = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3210,12 +3210,13 @@ class CanvasGraphics {
|
||||
}
|
||||
|
||||
const currentCtx = this.ctx;
|
||||
if (!group.isolated && !group.knockout && this.#knockoutGroupLevel === 0) {
|
||||
info("TODO: Fully support non-isolated non-knockout groups.");
|
||||
}
|
||||
|
||||
if (
|
||||
!group.needsIsolation &&
|
||||
// A non-isolated group blends with its backdrop, so drawing it directly
|
||||
// on the parent canvas (rather than on a transparent intermediate one)
|
||||
// is correct even when it contains blend modes (bug 1873345). A soft
|
||||
// mask still needs its own canvas though, and an isolated group requires
|
||||
// a transparent backdrop, so both keep the intermediate canvas.
|
||||
(!group.needsIsolation || (!group.isolated && !group.hasSoftMask)) &&
|
||||
!group.knockout &&
|
||||
!group.isGray &&
|
||||
this.#knockoutGroupLevel === 0 &&
|
||||
@ -3234,12 +3235,24 @@ class CanvasGraphics {
|
||||
}
|
||||
currentCtx.clip(clip);
|
||||
}
|
||||
// Unlike the intermediate-canvas path below, the content is drawn
|
||||
// straight onto the parent canvas with no later compositing step, so the
|
||||
// inherited blend mode, alpha constants and transfer function must stay
|
||||
// active here rather than being reset (issue 20722); the conditions
|
||||
// above already guarantee a Normal blend and an opaque (ca === 1) state.
|
||||
this.groupStack.push(null); // null = no intermediate canvas
|
||||
this.#groupStackMeta.push(null);
|
||||
this.groupLevel++;
|
||||
return;
|
||||
}
|
||||
|
||||
// Reached only when the direct path above didn't apply, e.g. a soft mask,
|
||||
// non-default group alpha or blend mode: we still composite on a
|
||||
// transparent intermediate canvas rather than the real backdrop.
|
||||
if (!group.isolated && !group.knockout && this.#knockoutGroupLevel === 0) {
|
||||
info("TODO: Fully support non-isolated non-knockout groups.");
|
||||
}
|
||||
|
||||
const currentTransform = getCurrentTransform(currentCtx);
|
||||
if (group.matrix) {
|
||||
currentCtx.transform(...group.matrix);
|
||||
|
||||
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -936,3 +936,4 @@
|
||||
!bug1802506.pdf
|
||||
!checkbox_no_appearance.pdf
|
||||
!opt_demo.pdf
|
||||
!bug1873345.pdf
|
||||
|
||||
BIN
test/pdfs/bug1873345.pdf
Normal file
BIN
test/pdfs/bug1873345.pdf
Normal file
Binary file not shown.
@ -6786,6 +6786,13 @@
|
||||
"type": "eq",
|
||||
"about": "Every blend mode that PDF supports."
|
||||
},
|
||||
{
|
||||
"id": "bug1873345",
|
||||
"file": "pdfs/bug1873345.pdf",
|
||||
"md5": "03483b94a2c02ac5f98c17ccf14de8ea",
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
},
|
||||
{
|
||||
"id": "transparency_group",
|
||||
"file": "pdfs/transparency_group.pdf",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user