chrome-devtools-frontend
Version:
Chrome DevTools UI
123 lines (103 loc) • 4.97 kB
text/typescript
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/* eslint-disable @devtools/no-imperative-dom-api */
import type * as Common from '../../../../core/common/common.js';
import * as TextUtils from '../../../../models/text_utils/text_utils.js';
import * as LinearMemoryInspectorComponents from '../../../../panels/linear_memory_inspector/components/components.js';
import * as UI from '../../legacy.js';
const MEMORY_TRANSFER_MIN_CHUNK_SIZE = 1000;
/**
* This is a slightly reduced version of `panels/LinearMemoryInspectorPane.LinearMemoryInspectorView.
*
* It's not hooked up to the LinearMemoryInspectorController and it operates on a fixed memory array thats
* known upfront.
*/
class LinearMemoryInspectorView extends UI.Widget.VBox {
#memory: Uint8Array = new Uint8Array([0]);
#address = 0;
#inspector = new LinearMemoryInspectorComponents.LinearMemoryInspector.LinearMemoryInspector();
constructor() {
super();
this.#inspector.addEventListener(
LinearMemoryInspectorComponents.LinearMemoryInspector.Events.MEMORY_REQUEST, this.#memoryRequested, this);
this.#inspector.addEventListener(
LinearMemoryInspectorComponents.LinearMemoryInspector.Events.ADDRESS_CHANGED,
(event: Common.EventTarget.EventTargetEvent<number>) => {
this.#address = event.data;
});
this.#inspector.show(this.contentElement);
}
override wasShown(): void {
super.wasShown();
this.refreshData();
}
setMemory(memory: Uint8Array<ArrayBuffer>): void {
this.#memory = memory;
this.refreshData();
}
refreshData(): void {
// TODO(szuend): The following lines are copied from `LinearMemoryInspectorController`. We can't reuse them
// as depending on a module in `panels/` from a component is a layering violation.
// Provide a chunk of memory that covers the address to show and some before and after
// as 1. the address shown is not necessarily at the beginning of a page and
// 2. to allow for fewer memory requests.
const memoryChunkStart = Math.max(0, this.#address - MEMORY_TRANSFER_MIN_CHUNK_SIZE / 2);
const memoryChunkEnd = memoryChunkStart + MEMORY_TRANSFER_MIN_CHUNK_SIZE;
const memory = this.#memory.slice(memoryChunkStart, memoryChunkEnd);
this.#inspector.memory = memory;
this.#inspector.address = this.#address;
this.#inspector.memoryOffset = memoryChunkStart;
this.#inspector.outerMemoryLength = this.#memory.length;
this.#inspector.hideValueInspector = true;
}
#memoryRequested(event: Common.EventTarget.EventTargetEvent<{start: number, end: number, address: number}>): void {
// TODO(szuend): The following lines are copied from `LinearMemoryInspectorController`. We can't reuse them
// as depending on a module in `panels/` from a component is a layering violation.
const {start, end, address} = event.data;
if (address < start || address >= end) {
throw new Error('Requested address is out of bounds.');
}
// Check that the requested start is within bounds.
// If the requested end is larger than the actual
// memory, it will be automatically capped when
// requesting the range.
if (start < 0 || start > end || start >= this.#memory.length) {
throw new Error('Requested range is out of bounds.');
}
const chunkEnd = Math.max(end, start + MEMORY_TRANSFER_MIN_CHUNK_SIZE);
const memory = this.#memory.slice(start, chunkEnd);
this.#inspector.memory = memory;
this.#inspector.address = address;
this.#inspector.memoryOffset = start;
this.#inspector.outerMemoryLength = this.#memory.length;
this.#inspector.hideValueInspector = true;
}
}
/**
* Adapter for the linear memory inspector that can show a {@link StreamingContentData}.
*/
export class StreamingContentHexView extends LinearMemoryInspectorView {
readonly #streamingContentData: TextUtils.StreamingContentData.StreamingContentData;
constructor(streamingContentData: TextUtils.StreamingContentData.StreamingContentData) {
super();
this.#streamingContentData = streamingContentData;
}
override wasShown(): void {
super.wasShown();
this.#updateMemoryFromContentData();
this.#streamingContentData.addEventListener(
TextUtils.StreamingContentData.Events.CHUNK_ADDED, this.#updateMemoryFromContentData, this);
// No need to call super.wasShown() as we call super.refreshData() ourselves.
}
override willHide(): void {
super.willHide();
this.#streamingContentData.removeEventListener(
TextUtils.StreamingContentData.Events.CHUNK_ADDED, this.#updateMemoryFromContentData, this);
}
#updateMemoryFromContentData(): void {
const binaryString = window.atob(this.#streamingContentData.content().base64);
const memory = Uint8Array.from(binaryString, m => m.codePointAt(0) as number);
this.setMemory(memory);
}
}