chrome-devtools-frontend
Version:
Chrome DevTools UI
170 lines (143 loc) • 4.79 kB
text/typescript
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import type * as Protocol from '../../generated/protocol.js';
import {DOMModel, type DOMNode} from './DOMModel.js';
import type {SnapshotWithRect} from './PaintProfiler.js';
import type {Target} from './Target.js';
export interface Layer {
id(): string;
parentId(): string|null;
parent(): Layer|null;
isRoot(): boolean;
children(): Layer[];
addChild(child: Layer): void;
node(): DOMNode|null;
nodeForSelfOrAncestor(): DOMNode|null;
offsetX(): number;
offsetY(): number;
width(): number;
height(): number;
transform(): number[]|null;
quad(): number[];
anchorPoint(): number[];
invisible(): boolean;
paintCount(): number;
lastPaintRect(): Protocol.DOM.Rect|null;
scrollRects(): Protocol.LayerTree.ScrollRect[];
stickyPositionConstraint(): StickyPositionConstraint|null;
gpuMemoryUsage(): number;
requestCompositingReasons(): Promise<string[]>;
requestCompositingReasonIds(): Promise<string[]>;
drawsContent(): boolean;
snapshots(): Array<Promise<SnapshotWithRect|null>>;
}
export namespace Layer {
export const enum ScrollRectType {
NON_FAST_SCROLLABLE = 'NonFastScrollable',
TOUCH_EVENT_HANDLER = 'TouchEventHandler',
WHEEL_EVENT_HANDLER = 'WheelEventHandler',
REPAINTS_ON_SCROLL = 'RepaintsOnScroll',
MAIN_THREAD_SCROLL_REASON = 'MainThreadScrollingReason',
}
}
export class StickyPositionConstraint {
readonly #stickyBoxRect: Protocol.DOM.Rect;
readonly #containingBlockRect: Protocol.DOM.Rect;
readonly #nearestLayerShiftingStickyBox: Layer|null;
readonly #nearestLayerShiftingContainingBlock: Layer|null;
constructor(layerTree: LayerTreeBase|null, constraint: Protocol.LayerTree.StickyPositionConstraint) {
this.#stickyBoxRect = constraint.stickyBoxRect;
this.#containingBlockRect = constraint.containingBlockRect;
this.#nearestLayerShiftingStickyBox = null;
if (layerTree && constraint.nearestLayerShiftingStickyBox) {
this.#nearestLayerShiftingStickyBox = layerTree.layerById(constraint.nearestLayerShiftingStickyBox);
}
this.#nearestLayerShiftingContainingBlock = null;
if (layerTree && constraint.nearestLayerShiftingContainingBlock) {
this.#nearestLayerShiftingContainingBlock = layerTree.layerById(constraint.nearestLayerShiftingContainingBlock);
}
}
stickyBoxRect(): Protocol.DOM.Rect {
return this.#stickyBoxRect;
}
containingBlockRect(): Protocol.DOM.Rect {
return this.#containingBlockRect;
}
nearestLayerShiftingStickyBox(): Layer|null {
return this.#nearestLayerShiftingStickyBox;
}
nearestLayerShiftingContainingBlock(): Layer|null {
return this.#nearestLayerShiftingContainingBlock;
}
}
export class LayerTreeBase {
readonly #target: Target|null;
#domModel: DOMModel|null;
layersById = new Map<string|number, Layer>();
#root: Layer|null = null;
#contentRoot: Layer|null = null;
readonly #backendNodeIdToNode = new Map<Protocol.DOM.BackendNodeId, DOMNode|null>();
#viewportSize?: {
width: number,
height: number,
};
constructor(target: Target|null) {
this.#target = target;
this.#domModel = target ? target.model(DOMModel) : null;
}
target(): Target|null {
return this.#target;
}
root(): Layer|null {
return this.#root;
}
setRoot(root: Layer|null): void {
this.#root = root;
}
contentRoot(): Layer|null {
return this.#contentRoot;
}
setContentRoot(contentRoot: Layer|null): void {
this.#contentRoot = contentRoot;
}
forEachLayer<T>(callback: (arg0: Layer) => T, root?: Layer|null): T|boolean {
if (!root) {
root = this.root();
if (!root) {
return false;
}
}
return callback(root) || root.children().some(this.forEachLayer.bind(this, callback));
}
layerById(id: string): Layer|null {
return this.layersById.get(id) || null;
}
async resolveBackendNodeIds(requestedNodeIds: Set<Protocol.DOM.BackendNodeId>): Promise<void> {
if (!requestedNodeIds.size || !this.#domModel) {
return;
}
const nodesMap = await this.#domModel.pushNodesByBackendIdsToFrontend(requestedNodeIds);
if (!nodesMap) {
return;
}
for (const nodeId of nodesMap.keys()) {
this.#backendNodeIdToNode.set(nodeId, nodesMap.get(nodeId) || null);
}
}
backendNodeIdToNode(): Map<Protocol.DOM.BackendNodeId, DOMNode|null> {
return this.#backendNodeIdToNode;
}
setViewportSize(viewportSize: {
width: number,
height: number,
}): void {
this.#viewportSize = viewportSize;
}
viewportSize(): {
width: number,
height: number,
}|undefined {
return this.#viewportSize;
}
}