Skip to content

Commit cb0ece1

Browse files
tinchox5claude
andcommitted
fix(capture): preserve parent session across nested iframe capture
rasterizeIframe rasterizes the iframe via a nested snapdom capture, which runs its own captureDOM → applyCachePolicy and REASSIGNS cache.session.{nodeMap,styleMap,styleCache} to fresh instances mid-clone. That orphans every entry the parent cloned before reaching the iframe. After #440 made inlineBackgroundImages resolve clone→source via cache.session.nodeMap, those orphaned subtrees were skipped, so a remote background/mask on a sibling of the iframe was silently dropped (visual demo d6: the mask gradient rendered as a full square instead of a ring). Snapshot and restore the parent session around the nested capture so it stays intact. Keeps #440's nodeMap recursion; covers pseudo/iconFonts too. Also fixes a brittle assertion in the #439 background test (the browser normalizes the `green`/`purple` color keywords to rgb()). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 5be5025 commit cb0ece1

2 files changed

Lines changed: 14 additions & 2 deletions

File tree

__tests__/module.background.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ describe('inlineBackgroundImages', () => {
8181
link(cln, src); link(cln1, src1); link(cln2, src2)
8282
await inlineBackgroundImages(src, cln, new WeakMap())
8383

84-
expect(cln1.style.backgroundImage).toContain('green')
85-
expect(cln2.style.backgroundImage).toContain('purple')
84+
expect(cln1.style.backgroundImage).toContain('rgb(0, 128, 0)')
85+
expect(cln2.style.backgroundImage).toContain('rgb(128, 0, 128)')
8686
})
8787

8888
it('skips multiple injected elements at various positions', async () => {

src/utils/clone.helpers.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,11 +420,23 @@ export async function rasterizeIframe(iframe, sessionCache, options) {
420420

421421
// Pin viewport so body background fills exactly content box (fixes 400x110 → 400x150)
422422
const unpin = pinIframeViewport(doc, contentWidth, contentHeight)
423+
// The nested capture below runs its own captureDOM → applyCachePolicy, which REASSIGNS
424+
// cache.session.{nodeMap,styleMap,styleCache} to fresh instances. That orphans every entry
425+
// the parent capture cloned before reaching this iframe, so the parent's later
426+
// inlineBackgroundImages/pseudo recursion (which resolve clone→source via cache.session.nodeMap)
427+
// skip those subtrees — e.g. a remote background/mask on a sibling of the iframe is silently
428+
// dropped. Snapshot and restore the parent session around the nested call so it stays intact.
429+
const parentNodeMap = cache.session.nodeMap
430+
const parentStyleMap = cache.session.styleMap
431+
const parentStyleCache = cache.session.styleCache
423432
let imgEl
424433
try {
425434
imgEl = await snap.toPng(doc.documentElement, nested)
426435
} finally {
427436
unpin()
437+
cache.session.nodeMap = parentNodeMap
438+
cache.session.styleMap = parentStyleMap
439+
cache.session.styleCache = parentStyleCache
428440
}
429441

430442
// Build <img> (bitmap) sized to content box

0 commit comments

Comments
 (0)