| // Copyright 2023 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_info_table.html.js'; |
| import * as TimeUtil from './time_util.js'; |
| import type {SessionRejectedRecord, SessionRequestedRecord, SessionStartedRecord, SessionStoppedRecord} from './webxr_internals.mojom-webui.js'; |
| import * as XRRuntimeUtil from './xr_runtime_util.js'; |
| import * as XRSessionUtil from './xr_session_util.js'; |
| |
| const COLUMN_NAMES = [ |
| 'Trace ID', |
| 'Session State', |
| 'Attributes', |
| ]; |
| |
| export class SessionInfoTableElement extends CustomElement { |
| private traceIdToTableCell: {[key: string]: HTMLTableCellElement} = {}; |
| |
| static override get template() { |
| return getTemplate(); |
| } |
| |
| constructor() { |
| super(); |
| |
| const table = |
| this.getRequiredElement<HTMLTableElement>('#session-info-table'); |
| |
| const headerRow = table.insertRow(); |
| COLUMN_NAMES.forEach((columnName) => { |
| const headerCell = document.createElement('th'); |
| headerCell.textContent = columnName; |
| headerRow.appendChild(headerCell); |
| }); |
| } |
| |
| addSessionRequestedRow(sessionRequestedRecord: SessionRequestedRecord) { |
| const {options, requestedTime} = sessionRequestedRecord; |
| const {traceId, mode, requiredFeatures, optionalFeatures, depthOptions} = |
| options; |
| |
| const attributes = [ |
| `Mode: ${XRSessionUtil.sessionModeToString(mode)}`, |
| `Required Features: ${ |
| requiredFeatures.map(XRSessionUtil.sessionFeatureToString) |
| .join(', ')}`, |
| `Optional Features: ${ |
| optionalFeatures.map(XRSessionUtil.sessionFeatureToString) |
| .join(', ')}`, |
| `Requested Time: ${TimeUtil.formatMojoTime(requestedTime)}`, |
| ]; |
| |
| const depthUsagePreferences = depthOptions?.usagePreferences || []; |
| if (depthUsagePreferences.length) { |
| attributes.push(`Depth Usage Preferences: ${ |
| depthUsagePreferences.map(XRSessionUtil.depthUsageToString) |
| .join(', ')}`); |
| } |
| |
| const depthDataFormatPreferences = |
| depthOptions?.dataFormatPreferences || []; |
| if (depthDataFormatPreferences.length) { |
| attributes.push(`Depth Data Format Preferences: ${ |
| depthDataFormatPreferences.map(XRSessionUtil.depthFormatToString) |
| .join(', ')}`); |
| } |
| |
| this.addSessionRow(traceId.toString(), 'Requested', attributes); |
| } |
| |
| addSessionRejectedRow(sessionRejectedRecord: SessionRejectedRecord) { |
| const { |
| traceId, |
| failureReason, |
| failureReasonDescription, |
| rejectedFeatures, |
| rejectedTime, |
| } = sessionRejectedRecord; |
| |
| const rejectedFeaturesDescription = rejectedFeatures.length ? |
| ` rejectedFeatures=${ |
| rejectedFeatures.map(XRSessionUtil.sessionFeatureToString) |
| .join(', ')}` : |
| ''; |
| const attributes = [ |
| `Failure Reason: ${ |
| XRSessionUtil.requestSessionErrorToString(failureReason)}`, |
| `Failure Reason Description: ${failureReasonDescription} ${ |
| rejectedFeaturesDescription}`, |
| `Rejected Time: ${TimeUtil.formatMojoTime(rejectedTime)}`, |
| ]; |
| |
| this.addSessionRow(traceId.toString(), 'Rejected', attributes); |
| } |
| |
| addSessionStartedRow(sessionStartedRecord: SessionStartedRecord) { |
| const {traceId, deviceId, startedTime} = sessionStartedRecord; |
| const attributes = [ |
| `Device Id: ${XRRuntimeUtil.deviceIdToString(deviceId)}`, |
| `Started Time: ${TimeUtil.formatMojoTime(startedTime)}`, |
| ]; |
| |
| this.addSessionRow(traceId.toString(), 'Started', attributes); |
| } |
| |
| addSessionStoppedRow(sessionStoppedRecord: SessionStoppedRecord) { |
| const {traceId, stoppedTime} = sessionStoppedRecord; |
| const attributes = [ |
| `Stopped Time: ${TimeUtil.formatMojoTime(stoppedTime)}`, |
| ]; |
| |
| this.addSessionRow(traceId.toString(), 'Stopped', attributes); |
| } |
| |
| private createTableCell(textContent: string = ''): HTMLTableCellElement { |
| const cell = document.createElement('td'); |
| cell.textContent = textContent; |
| return cell; |
| } |
| |
| private createAttributesList(attributes: string[]): HTMLUListElement { |
| const ul = document.createElement('ul'); |
| ul.style.padding = '0'; |
| |
| attributes.forEach((attribute) => { |
| const li = document.createElement('li'); |
| li.textContent = attribute; |
| ul.appendChild(li); |
| }); |
| |
| return ul; |
| } |
| |
| private updateTraceIdCell(traceId: string, newRow: HTMLTableRowElement) { |
| let traceIdCell = this.traceIdToTableCell[traceId]; |
| |
| if (traceIdCell === undefined) { |
| traceIdCell = this.createTableCell(traceId); |
| newRow.appendChild(traceIdCell); |
| traceIdCell.rowSpan = 1; |
| this.traceIdToTableCell[traceId] = traceIdCell; |
| } else { |
| traceIdCell.rowSpan++; |
| } |
| } |
| |
| private addSessionRow( |
| traceId: string, sessionType: string, attributes: string[]) { |
| const table = |
| this.getRequiredElement<HTMLTableElement>('#session-info-table'); |
| const newRow = table.insertRow(); |
| |
| this.updateTraceIdCell(traceId, newRow); |
| |
| const sessionTypeCell = this.createTableCell(sessionType); |
| newRow.appendChild(sessionTypeCell); |
| |
| const attributesCell = this.createTableCell(); |
| const ul = this.createAttributesList(attributes); |
| attributesCell.appendChild(ul); |
| newRow.appendChild(attributesCell); |
| } |
| } |
| |
| // Declare the custom element |
| declare global { |
| interface HTMLElementTagNameMap { |
| 'session-info-table': SessionInfoTableElement; |
| } |
| } |
| |
| customElements.define('session-info-table', SessionInfoTableElement); |