chrome-devtools-frontend
Version:
Chrome DevTools UI
82 lines (70 loc) • 2.46 kB
text/typescript
// Copyright 2023 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {needsLogging} from './LoggingConfig.js';
interface ElementWithParent {
element: Element;
parent?: Element;
slot?: Element;
}
export function getDomState(documents: Document[]): {loggables: ElementWithParent[], shadowRoots: ShadowRoot[]} {
const loggables: ElementWithParent[] = [];
const shadowRoots: ShadowRoot[] = [];
const queue: ElementWithParent[] = [];
const enqueue = (children: HTMLCollection|Element[], parent?: Element): void => {
for (const child of children) {
queue.push({element: child, parent});
}
};
for (const document of documents) {
enqueue(document.body.children);
}
let head = 0;
const dequeue = (): ElementWithParent => queue[head++];
while (true) {
const top = dequeue();
if (!top) {
break;
}
const {element} = top;
if (element.localName === 'template') {
continue;
}
let {parent} = top;
if (needsLogging(element)) {
loggables.push({element, parent});
parent = element;
}
if (element.localName === 'slot' && (element as HTMLSlotElement).assignedElements().length) {
enqueue((element as HTMLSlotElement).assignedElements(), parent);
} else if (element.shadowRoot) {
shadowRoots.push(element.shadowRoot);
enqueue(element.shadowRoot.children, parent);
} else {
enqueue(element.children, parent);
}
}
return {loggables, shadowRoots};
}
const MIN_ELEMENT_SIZE_FOR_IMPRESSIONS = 10;
export function visibleOverlap(element: Element, viewportRect: DOMRect): DOMRect|null {
const elementRect = element.getBoundingClientRect();
const overlap = intersection(viewportRect, elementRect);
const sizeThreshold = Math.max(Math.min(MIN_ELEMENT_SIZE_FOR_IMPRESSIONS, elementRect.width, elementRect.height), 1);
if (!overlap || overlap.width < sizeThreshold || overlap.height < sizeThreshold) {
return null;
}
return overlap;
}
function intersection(a: DOMRect, b: DOMRect): DOMRect|null {
const x0 = Math.max(a.left, b.left);
const x1 = Math.min(a.left + a.width, b.left + b.width);
if (x0 <= x1) {
const y0 = Math.max(a.top, b.top);
const y1 = Math.min(a.top + a.height, b.top + b.height);
if (y0 <= y1) {
return new DOMRect(x0, y0, x1 - x0, y1 - y0);
}
}
return null;
}