UNPKG

chrome-devtools-frontend

Version:
123 lines (103 loc) 4.97 kB
// 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); } }