Skip to content

Commit 2dbbf82

Browse files
committed
fix(desktop): preserve nested PPTX blend backdrops
Probe non-member compositor descendants against the actual backdrop-dependent capture members and keep selected backdrop paint visible during isolation. Generated-By: looper 0.11.8 (runner=fixer, agent=codex)
1 parent ddc7933 commit 2dbbf82

2 files changed

Lines changed: 32 additions & 7 deletions

File tree

apps/desktop/src/main/deck-capture.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,21 @@ export function isolateLayeredPptxBackground(
883883
? Array.from(document.querySelectorAll<HTMLElement>(`[data-od-pptx-compositing-member="${id}"]`))
884884
: [],
885885
);
886+
const backdropDependentMembers = Array.from(compositingMembers).filter((element) => {
887+
const style = getComputedStyle(element);
888+
const mixBlendMode = (style.mixBlendMode || "normal").trim().toLowerCase();
889+
const backdropFilter = (
890+
style.backdropFilter ||
891+
style.getPropertyValue?.("backdrop-filter") ||
892+
style.getPropertyValue?.("-webkit-backdrop-filter") ||
893+
"none"
894+
).trim().toLowerCase();
895+
return (mixBlendMode !== "" && mixBlendMode !== "normal") ||
896+
(backdropFilter !== "" && backdropFilter !== "none");
897+
});
898+
const backdropPaintTargets = backdropDependentMembers.length > 0
899+
? backdropDependentMembers
900+
: [target];
886901
const entirePaintRoots = new Set(
887902
flattenCompositingContext
888903
? Array.from(compositingMembers).filter((element) =>
@@ -942,10 +957,13 @@ export function isolateLayeredPptxBackground(
942957
let sampledTogether = false;
943958
const paintsBehindAt = (x: number, y: number): boolean => {
944959
const paintStack = document.elementsFromPoint(x, y);
945-
const targetIndex = paintStack.indexOf(target);
946960
const elementIndex = paintStack.indexOf(element);
947-
if (targetIndex >= 0 && elementIndex >= 0) sampledTogether = true;
948-
return targetIndex >= 0 && elementIndex > targetIndex;
961+
if (elementIndex < 0) return false;
962+
return backdropPaintTargets.some((paintTarget) => {
963+
const targetIndex = paintStack.indexOf(paintTarget);
964+
if (targetIndex >= 0) sampledTogether = true;
965+
return targetIndex >= 0 && elementIndex > targetIndex;
966+
});
949967
};
950968
if (points.some(([x, y]) => paintsBehindAt(x, y))) return true;
951969

@@ -977,7 +995,10 @@ export function isolateLayeredPptxBackground(
977995
}
978996
return clips;
979997
};
980-
const clippedPaintBoxes = [...paintClipChain(element), ...paintClipChain(target)]
998+
const clippedPaintBoxes = [
999+
...paintClipChain(element),
1000+
...backdropPaintTargets.flatMap((paintTarget) => paintClipChain(paintTarget)),
1001+
]
9811002
.filter((candidate, index, candidates) => candidates.indexOf(candidate) === index);
9821003
if (clippedPaintBoxes.length === 0) return false;
9831004

@@ -1026,7 +1047,10 @@ export function isolateLayeredPptxBackground(
10261047
element.style.setProperty("pointer-events", "auto", "important");
10271048
}
10281049
for (const element of [slide, ...Array.from(slide.querySelectorAll<HTMLElement>("*"))]) {
1029-
if (element === target || element.contains(target) || target.contains(element)) continue;
1050+
const isCapturedDescendant = target.contains(element) && (
1051+
!flattenCompositingContext || compositingMembers.has(element)
1052+
);
1053+
if (element === target || element.contains(target) || isCapturedDescendant) continue;
10301054
if (paintsBehindTarget(element)) addBlendBackdropElement(element);
10311055
}
10321056

@@ -1115,6 +1139,7 @@ export function isolateLayeredPptxBackground(
11151139
);
11161140
continue;
11171141
}
1142+
if (blendBackdropElements.has(descendant)) continue;
11181143
if (!flattenCompositingContext) {
11191144
descendant.style.setProperty("visibility", "hidden", "important");
11201145
continue;

apps/desktop/tests/main/pptx-layered-background.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ describe('editable PPTX layered backgrounds', () => {
430430
expect(capture.largeAreaHitTests).toBeLessThanOrEqual(4_101);
431431
}, 20_000);
432432

433-
test('includes a 1px clipped stripe across a large layered blend backdrop', async () => {
433+
test('includes a 1px clipped backdrop nested in a layered blend compositor root', async () => {
434434
const capture = await probeDpr2LayeredBackgroundCapture();
435435

436436
expect(capture.largeStripeExportedRgb).toEqual(capture.largeStripeChromiumRgb);
@@ -1187,7 +1187,7 @@ app.whenReady().then(async () => {
11871187
if (!capture) throw new Error('No layered background capture was produced');
11881188
const image = nativeImage.createFromBuffer(Buffer.from(capture.dataUrl.split(',')[1], 'base64'));
11891189
const size = image.getSize();
1190-
const largeHtml = '<!doctype html><style>html,body{margin:0}.slide{position:relative;width:1920px;height:1080px}.backdrop,.large-target{position:absolute;inset:0}.backdrop{background:rgb(128,192,128);clip-path:polygon(7px 0,8px 0,8px 100%,7px 100%)}.large-target{background-image:linear-gradient(rgb(128,128,128),rgb(128,128,128)),linear-gradient(transparent,transparent);mix-blend-mode:multiply}</style><section class="slide"><div class="backdrop"></div><div class="large-target"></div></section>';
1190+
const largeHtml = '<!doctype html><style>html,body{margin:0}.slide{position:relative;width:1920px;height:1080px}.compositor{position:absolute;inset:0;opacity:.999}.backdrop,.large-target{position:absolute;inset:0}.backdrop{background:rgb(128,192,128);clip-path:polygon(7px 0,8px 0,8px 100%,7px 100%)}.large-target{background-image:linear-gradient(rgb(128,128,128),rgb(128,128,128)),linear-gradient(transparent,transparent);mix-blend-mode:multiply}</style><section class="slide"><div class="compositor"><div class="backdrop"></div><div class="large-target"></div></div></section>';
11911191
await window.loadURL('data:text/html;charset=utf-8,' + encodeURIComponent(largeHtml));
11921192
await nextFrames(window);
11931193
const dbg = window.webContents.debugger;

0 commit comments

Comments
 (0)