feat: solver consumes CSS contain:paint for clippedBy diagnostics
- Add Contain=5 to geometry world ClipKind enum (avoids collision with topology engine's CONTAIN=3 vs Mask=3) - Fix CDP isClippingElement() to detect contain:paint (style.contain) - CDP topology builder sets clipKind=5 for contain:paint, 1 for overflow - Enrich clippedByPredicate with clipKind metric: 1=contain:paint, 2=overflow (hidden/scroll/auto) - Reads world.clipping.clipKind of the reference's clip node
This commit is contained in:
@@ -156,6 +156,7 @@ export async function extractTopology(
|
|||||||
|
|
||||||
function isClippingElement(el) {
|
function isClippingElement(el) {
|
||||||
const style = window.getComputedStyle(el)
|
const style = window.getComputedStyle(el)
|
||||||
|
if (style.contain && style.contain.includes('paint')) return true
|
||||||
return style.overflowX === 'hidden' || style.overflowX === 'scroll' || style.overflowX === 'auto' ||
|
return style.overflowX === 'hidden' || style.overflowX === 'scroll' || style.overflowX === 'auto' ||
|
||||||
style.overflowY === 'hidden' || style.overflowY === 'scroll' || style.overflowY === 'auto' ||
|
style.overflowY === 'hidden' || style.overflowY === 'scroll' || style.overflowY === 'auto' ||
|
||||||
style.clipPath !== 'none'
|
style.clipPath !== 'none'
|
||||||
@@ -252,10 +253,12 @@ export async function extractTopology(
|
|||||||
|
|
||||||
if (isClippingElement(el)) {
|
if (isClippingElement(el)) {
|
||||||
const r = rectFor(el)
|
const r = rectFor(el)
|
||||||
|
const style = window.getComputedStyle(el)
|
||||||
|
const isContainPaint = style.contain && style.contain.includes('paint')
|
||||||
results.clipping.push({
|
results.clipping.push({
|
||||||
clipNodeId: results.clipping.length,
|
clipNodeId: results.clipping.length,
|
||||||
subjectId,
|
subjectId,
|
||||||
clipKind: 1,
|
clipKind: isContainPaint ? 5 : 1,
|
||||||
clipLeft: r.left,
|
clipLeft: r.left,
|
||||||
clipTop: r.top,
|
clipTop: r.top,
|
||||||
clipRight: r.right,
|
clipRight: r.right,
|
||||||
|
|||||||
@@ -330,6 +330,7 @@ export const enum ClipKind {
|
|||||||
ClipPath = 2,
|
ClipPath = 2,
|
||||||
Mask = 3,
|
Mask = 3,
|
||||||
SvgClip = 4,
|
SvgClip = 4,
|
||||||
|
Contain = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Clipping {
|
export interface Clipping {
|
||||||
|
|||||||
@@ -687,7 +687,19 @@ export const clippedByPredicate: PredicateEvaluator = {
|
|||||||
// Simplified: check if subject's clipping root is the reference
|
// Simplified: check if subject's clipping root is the reference
|
||||||
const clipRoot = world.topology.clippingRootOf[subjectId - 1] ?? 0;
|
const clipRoot = world.topology.clippingRootOf[subjectId - 1] ?? 0;
|
||||||
const pass = clipRoot === referenceId;
|
const pass = clipRoot === referenceId;
|
||||||
return makePredicateResult(pass ? 'true' : 'false', {}, [subjectId, referenceId]);
|
// Determine clip kind from the clipping table entry for the reference.
|
||||||
|
// Encoding: 1=contain:paint, 2=overflow:hidden/scroll/auto
|
||||||
|
const metrics: Record<string, number> = {};
|
||||||
|
if (referenceId !== undefined) {
|
||||||
|
const { clipping } = world;
|
||||||
|
for (let i = 0; i < clipping.subjectId.length; i++) {
|
||||||
|
if (clipping.subjectId[i] === referenceId) {
|
||||||
|
metrics.clipKind = clipping.clipKind[i] === 5 /* Contain */ ? 1 : 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return makePredicateResult(pass ? 'true' : 'false', metrics, [subjectId, referenceId]);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user