@@ -868,29 +868,75 @@ function activeRegionCandidatePriority(node: VomNode, viewportCoverage: number):
868868 return 1 ;
869869}
870870
871+ function paintLineageByFrame (
872+ node : VomNode ,
873+ parentMap : Map < number , number | null > ,
874+ nodesById : Map < number , VomNode > ,
875+ ) : Map < string | undefined , VomNode > {
876+ const lineage = new Map < string | undefined , VomNode > ( ) ;
877+ let current : VomNode | undefined = node ;
878+ let guard = 0 ;
879+ while ( current && guard <= parentMap . size ) {
880+ if ( ! lineage . has ( current . frameId ) ) lineage . set ( current . frameId , current ) ;
881+ const parentId : number | null = parentMap . get ( current . id ) ?? null ;
882+ current = parentId === null ? undefined : nodesById . get ( parentId ) ;
883+ guard += 1 ;
884+ }
885+ return lineage ;
886+ }
887+
888+ /** Resolve both nodes to the nearest document where their paint order is comparable. */
889+ function comparablePaintNodes (
890+ target : VomNode ,
891+ blocker : VomNode ,
892+ parentMap : Map < number , number | null > ,
893+ nodesById : Map < number , VomNode > ,
894+ ) : { target : VomNode ; blocker : VomNode } | null {
895+ if ( target . frameId === blocker . frameId ) return { target, blocker } ;
896+ const targetLineage = paintLineageByFrame ( target , parentMap , nodesById ) ;
897+ let blockerInFrame : VomNode | undefined = blocker ;
898+ let guard = 0 ;
899+ while ( blockerInFrame && guard <= parentMap . size ) {
900+ const targetInFrame = targetLineage . get ( blockerInFrame . frameId ) ;
901+ if ( targetInFrame ) return { target : targetInFrame , blocker : blockerInFrame } ;
902+ const parentId : number | null = parentMap . get ( blockerInFrame . id ) ?? null ;
903+ blockerInFrame = parentId === null ? undefined : nodesById . get ( parentId ) ;
904+ guard += 1 ;
905+ }
906+ return null ;
907+ }
908+
871909function isBlockedByRegion (
872910 target : VomNode ,
873911 blocker : VomNode ,
874912 parentMap : Map < number , number | null > ,
913+ nodesById : Map < number , VomNode > ,
875914 viewportCoverage : number ,
876915) : boolean {
877916 if ( target . id === blocker . id ) return false ;
878917 if ( isAncestorOf ( parentMap , blocker . id , target . id ) ) return false ;
879918 if ( isAncestorOf ( parentMap , target . id , blocker . id ) ) return false ;
880919 if ( ! target . rect || ! blocker . rect ) return false ;
920+ const paintNodes = comparablePaintNodes ( target , blocker , parentMap , nodesById ) ;
921+ if ( ! paintNodes ) return false ;
881922
882923 const points = interactionPoints ( target . rect ) ;
883924
884925 if (
885926 viewportCoverage < 0.9 &&
886- target . paintOrder >= blocker . paintOrder &&
927+ paintNodes . target . paintOrder >= paintNodes . blocker . paintOrder &&
887928 points . some ( ( [ x , y ] ) => rectContains ( blocker . rect as Rect , x , y ) )
888929 ) {
889930 return false ;
890931 }
891932
892- if ( blocker . paintOrder < target . paintOrder ) return false ;
893- if ( blocker . paintOrder === target . paintOrder && blocker . id <= target . id ) return false ;
933+ if ( paintNodes . blocker . paintOrder < paintNodes . target . paintOrder ) return false ;
934+ if (
935+ paintNodes . blocker . paintOrder === paintNodes . target . paintOrder &&
936+ paintNodes . blocker . id <= paintNodes . target . id
937+ ) {
938+ return false ;
939+ }
894940 if ( viewportCoverage >= 0.9 ) return true ;
895941
896942 return points . some ( ( [ x , y ] ) => rectContains ( blocker . rect as Rect , x , y ) ) ;
@@ -914,6 +960,7 @@ function collectDescendantsOfIds(nodes: VomNode[], roots: Set<number>): Set<numb
914960
915961function applyActiveRegionPolicy ( nodes : VomNode [ ] , scene : VomScene ) : VomNode [ ] {
916962 const parentMap = buildParentMap ( nodes ) ;
963+ const nodesById = new Map ( nodes . map ( ( node ) => [ node . id , node ] ) ) ;
917964 const candidates = nodes
918965 . filter ( isPositionedRegionCandidate )
919966 . map ( ( node ) => {
@@ -930,7 +977,7 @@ function applyActiveRegionPolicy(nodes: VomNode[], scene: VomScene): VomNode[] {
930977 for ( const target of nodes ) {
931978 if ( ! isVomReferenceNode ( target ) ) continue ;
932979 const blocked = candidates . some ( ( candidate ) =>
933- isBlockedByRegion ( target , candidate . node , parentMap , candidate . viewportCoverage ) ,
980+ isBlockedByRegion ( target , candidate . node , parentMap , nodesById , candidate . viewportCoverage ) ,
934981 ) ;
935982 if ( blocked ) blockedRoots . add ( target . id ) ;
936983 }
@@ -985,7 +1032,7 @@ function renderDoubleLayer(scene: VomScene, layer: BlockingLayer, options: VomOp
9851032export function renderVom ( scene : VomScene , options : VomOptions = { } ) : VomResult {
9861033 const nodes = applyVomInteractionRecovery ( scene . nodes ) ;
9871034 const renderScene = { ...scene , nodes } ;
988- const layer = detectBlockingLayer ( nodes , scene . viewport ) ;
1035+ const layer = detectBlockingLayer ( nodes , scene . viewport , scene . rootFrameId ) ;
9891036 if ( layer ) return renderDoubleLayer ( renderScene , layer , options ) ;
9901037 const visibleNodes = options . activeRegionPolicy ? applyActiveRegionPolicy ( nodes , scene ) : nodes ;
9911038
0 commit comments