chromium/content/browser/resources/webxr_internals/session_statistics_table.ts

// 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.

import {CustomElement} from 'chrome://resources/js/custom_element.js';

import {getTemplate} from './session_statistics_table.html.js';
import type {XrFrameStatistics, XrLogMessage} from './xr_session.mojom-webui.js';


const COLUMN_NAMES = ['Logs'];

export class SessionStatisticsTable extends CustomElement {
  textLines: string[];
  totalDuration: bigint;
  static override get template() {
    return getTemplate();
  }

  constructor() {
    super();

    this.totalDuration = 0n;
    this.textLines = [COLUMN_NAMES.join(', ')];
    const table =
        this.getRequiredElement<HTMLTableElement>('#session-statistics-table');

    const headerRow = table.insertRow();
    COLUMN_NAMES.forEach((columnName) => {
      const headerCell = document.createElement('th');
      headerCell.textContent = columnName;
      headerRow.appendChild(headerCell);
    });


    // Add event listener to the button
    const button = this.getRequiredElement<HTMLTableElement>('#copy-button');
    button.addEventListener('click', () => {
      this.copyToClipboard();
    });
  }

  addXrSessionStatisticsRow(xrSessionStatistics: XrFrameStatistics) {
    const durationInMilliseconds =
        xrSessionStatistics.duration.microseconds / 1000n;
    this.totalDuration += durationInMilliseconds;
    const durationInSeconds = durationInMilliseconds / 1000n;

    const fps = xrSessionStatistics.numFrames / durationInSeconds;
    const droppedFrames = xrSessionStatistics.droppedFrames / durationInSeconds;
    const frameDataTime =
        (Number(xrSessionStatistics.frameDataTime.microseconds) * 1.0 / 1000)
            .toFixed(2);
    const animationFrameTime =
        (Number(xrSessionStatistics.pageAnimationFrameTime.microseconds) * 1.0 /
         1000)
            .toFixed(2);
    const cellValues = [
      `${this.totalDuration}`,
      `${fps}`,
      `${droppedFrames}`,
      `${frameDataTime}`,
      `${animationFrameTime}`,
    ];

    this.textLines.push(cellValues.join(', '));

    const cellValuesString = `Duration:${this.totalDuration}ms, Frame Rate:${
        fps}, Dropped Frames:${droppedFrames}, Frame Data Time:${
        frameDataTime}ms/frame, Animation Frame Time:${
        animationFrameTime}ms/frame`;
    this.addRow([cellValuesString]);
  }

  addRow(cellValues: string[]) {
    const table =
        this.getRequiredElement<HTMLTableElement>('#session-statistics-table');
    const newRow = table.insertRow();

    cellValues.forEach((value) => {
      const cell = newRow.insertCell();
      cell.textContent = value;
    });
  }

  // Method to copy textLines to clipboard
  async copyToClipboard(): Promise<void> {
    const textToCopy = this.textLines.join('\n');
    await navigator.clipboard.writeText(textToCopy);
  }

  addConsoleMessageRow(xrLogMessage: XrLogMessage) {
    const message = xrLogMessage.message;
    this.addRow([message]);
  }
}

// Declare the custom element
declare global {
  interface HTMLElementTagNameMap {
    'session-statistics-table': SessionStatisticsTable;
  }
}

customElements.define('session-statistics-table', SessionStatisticsTable);