chrome-devtools-frontend
Version:
Chrome DevTools UI
110 lines (95 loc) • 4.58 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 type * as Trace from '../../../models/trace/trace.js';
import * as TraceBounds from '../../../services/trace_bounds/trace_bounds.js';
export function flattenBreadcrumbs(initialBreadcrumb: Trace.Types.File.Breadcrumb): Trace.Types.File.Breadcrumb[] {
const allBreadcrumbs: Trace.Types.File.Breadcrumb[] = [initialBreadcrumb];
let breadcrumbsIter: Trace.Types.File.Breadcrumb = initialBreadcrumb;
while (breadcrumbsIter.child !== null) {
const iterChild = breadcrumbsIter.child;
if (iterChild !== null) {
allBreadcrumbs.push(iterChild);
breadcrumbsIter = iterChild;
}
}
return allBreadcrumbs;
}
export interface SetActiveBreadcrumbOptions {
removeChildBreadcrumbs: boolean;
updateVisibleWindow: boolean;
}
export class Breadcrumbs {
initialBreadcrumb: Trace.Types.File.Breadcrumb;
activeBreadcrumb: Trace.Types.File.Breadcrumb;
constructor(initialTraceWindow: Trace.Types.Timing.TraceWindowMicro) {
this.initialBreadcrumb = {
window: initialTraceWindow,
child: null,
};
let lastBreadcrumb = this.initialBreadcrumb;
while (lastBreadcrumb.child !== null) {
lastBreadcrumb = lastBreadcrumb.child;
}
this.activeBreadcrumb = lastBreadcrumb;
}
add(newBreadcrumbTraceWindow: Trace.Types.Timing.TraceWindowMicro): Trace.Types.File.Breadcrumb {
if (!this.isTraceWindowWithinTraceWindow(newBreadcrumbTraceWindow, this.activeBreadcrumb.window)) {
throw new Error('Can not add a breadcrumb that is equal to or is outside of the parent breadcrumb TimeWindow');
}
const newBreadcrumb = {
window: newBreadcrumbTraceWindow,
child: null,
};
// To add a new Breadcrumb to the Breadcrumbs Linked List, set the child of active breadcrumb
// to the new breadcrumb and update the active Breadcrumb to the newly added one
this.activeBreadcrumb.child = newBreadcrumb;
this.setActiveBreadcrumb(newBreadcrumb, {removeChildBreadcrumbs: false, updateVisibleWindow: true});
return newBreadcrumb;
}
// Breadcumb should be within the bounds of the parent and can not have both start and end be equal to the parent
isTraceWindowWithinTraceWindow(
child: Trace.Types.Timing.TraceWindowMicro, parent: Trace.Types.Timing.TraceWindowMicro): boolean {
return (child.min >= parent.min && child.max <= parent.max) &&
!(child.min === parent.min && child.max === parent.max);
}
// Used to set an initial breadcrumbs from modifications loaded from a file
setInitialBreadcrumbFromLoadedModifications(initialBreadcrumb: Trace.Types.File.Breadcrumb): void {
this.initialBreadcrumb = initialBreadcrumb;
// Make last breadcrumb active
let lastBreadcrumb = initialBreadcrumb;
while (lastBreadcrumb.child !== null) {
lastBreadcrumb = lastBreadcrumb.child;
}
this.setActiveBreadcrumb(lastBreadcrumb, {removeChildBreadcrumbs: false, updateVisibleWindow: true});
}
/**
* Sets a breadcrumb to be active.
* Doing this will update the minimap bounds and optionally based on the
* `updateVisibleWindow` parameter, it will also update the active window.
* The reason `updateVisibleWindow` is configurable is because if we are
* changing which breadcrumb is active because we want to reveal something to
* the user, we may have already updated the visible timeline window, but we
* are activating the breadcrumb to show the user that they are now within
* this breadcrumb. This is used when revealing insights and annotations.
*/
setActiveBreadcrumb(activeBreadcrumb: Trace.Types.File.Breadcrumb, options: SetActiveBreadcrumbOptions): void {
// If the children of the activated breadcrumb need to be removed, set the child on the
// activated breadcrumb to null. Since breadcrumbs are a linked list, this will remove all
// of the following children.
if (options.removeChildBreadcrumbs) {
activeBreadcrumb.child = null;
}
// When we assign a new active breadcrumb, both the minimap bounds and the visible
// window get set to that breadcrumb's window.
this.activeBreadcrumb = activeBreadcrumb;
TraceBounds.TraceBounds.BoundsManager.instance().setMiniMapBounds(
activeBreadcrumb.window,
);
if (options.updateVisibleWindow) {
TraceBounds.TraceBounds.BoundsManager.instance().setTimelineVisibleWindow(
activeBreadcrumb.window,
);
}
}
}