blob: 532c4bce34d03ac0d721a077e55836737ae09a9a [file] [log] [blame]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {TransformType} from 'common/geometry/transform_utils';
import {Timestamp} from 'common/time/time';
import {TimeDuration} from 'common/time/time_duration';
import {RawDataUtils} from 'parsers/raw_data_utils';
import {CujType} from 'trace/cujs/cuj_type';
import {PropertyTreeNode} from './property_tree_node';
const EMPTY_OBJ_STRING = '{empty}';
const EMPTY_ARRAY_STRING = '[empty]';
function formatAsDecimal(value: number): string {
if (!Number.isInteger(value)) {
return value.toFixed(3).toString();
}
return value.toString();
}
function formatAsHex(value: number, upperCase = false): string {
if (value < 0) {
value += Math.pow(2, 32); // convert to 2's complement
}
let hexValue = value.toString(16);
if (upperCase) {
hexValue = hexValue.toUpperCase();
}
return '0x' + hexValue;
}
interface PropertyFormatter {
format(node: PropertyTreeNode): string;
}
class DefaultPropertyFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
const value = node.getValue();
if (Array.isArray(value) && value.length === 0) {
return EMPTY_ARRAY_STRING;
}
if (typeof value === 'number') {
return formatAsDecimal(value);
}
if (value?.toString) return value.toString();
return `${value}`;
}
}
const DEFAULT_PROPERTY_FORMATTER = new DefaultPropertyFormatter();
class ColorFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
const rNode = node.getChildByName('r');
const gNode = node.getChildByName('g');
const bNode = node.getChildByName('b');
const alphaNode = node.getChildByName('a');
const r = formatAsDecimal(rNode?.getValue() ?? 0);
const g = formatAsDecimal(gNode?.getValue() ?? 0);
const b = formatAsDecimal(bNode?.getValue() ?? 0);
const rgbString = `(${r}, ${g}, ${b})`;
if (rNode && gNode && bNode && !alphaNode) {
return rgbString;
}
const alpha = formatAsDecimal(alphaNode?.getValue() ?? 0);
const alphaString = `alpha: ${alpha}`;
if (RawDataUtils.isEmptyObj(node)) {
return `${EMPTY_OBJ_STRING}, ${alphaString}`;
}
return `${rgbString}, ${alphaString}`;
}
}
const COLOR_FORMATTER = new ColorFormatter();
class RectFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
if (!RawDataUtils.isRect(node) || RawDataUtils.isEmptyObj(node)) {
return EMPTY_OBJ_STRING;
}
const left = formatAsDecimal(node.getChildByName('left')?.getValue() ?? 0);
const top = formatAsDecimal(node.getChildByName('top')?.getValue() ?? 0);
const right = formatAsDecimal(
node.getChildByName('right')?.getValue() ?? 0,
);
const bottom = formatAsDecimal(
node.getChildByName('bottom')?.getValue() ?? 0,
);
return `(${left}, ${top}) - (${right}, ${bottom})`;
}
}
const RECT_FORMATTER = new RectFormatter();
class BufferFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
return `w: ${node.getChildByName('width')?.getValue() ?? 0}, h: ${
node.getChildByName('height')?.getValue() ?? 0
}, stride: ${node.getChildByName('stride')?.getValue()}, format: ${node
.getChildByName('format')
?.getValue()}`;
}
}
const BUFFER_FORMATTER = new BufferFormatter();
class LayerIdFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
const value = node.getValue();
return value === -1 || value === 0 ? 'none' : `${value}`;
}
}
const LAYER_ID_FORMATTER = new LayerIdFormatter();
class MatrixFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
const dsdx = formatAsDecimal(node.getChildByName('dsdx')?.getValue() ?? 0);
const dtdx = formatAsDecimal(node.getChildByName('dtdx')?.getValue() ?? 0);
const dtdy = formatAsDecimal(node.getChildByName('dtdy')?.getValue() ?? 0);
const dsdy = formatAsDecimal(node.getChildByName('dsdy')?.getValue() ?? 0);
const tx = node.getChildByName('tx');
const ty = node.getChildByName('ty');
if (
dsdx === '0' &&
dtdx === '0' &&
dsdy === '0' &&
dtdy === '0' &&
!tx &&
!ty
) {
return 'null';
}
const matrix22 = `dsdx: ${dsdx}, dtdx: ${dtdx}, dtdy: ${dtdy}, dsdy: ${dsdy}`;
if (!tx && !ty) {
return matrix22;
}
return (
matrix22 +
`, tx: ${formatAsDecimal(tx?.getValue() ?? 0)}, ty: ${formatAsDecimal(
ty?.getValue() ?? 0,
)}`
);
}
}
const MATRIX_FORMATTER = new MatrixFormatter();
class TransformFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
const type = node.getChildByName('type');
return type !== undefined
? TransformType.getTypeFlags(type.getValue() ?? 0)
: 'null';
}
}
const TRANSFORM_FORMATTER = new TransformFormatter();
class SizeFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
return `${node.getChildByName('w')?.getValue() ?? 0} x ${
node.getChildByName('h')?.getValue() ?? 0
}`;
}
}
const SIZE_FORMATTER = new SizeFormatter();
class PositionFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
const x = formatAsDecimal(node.getChildByName('x')?.getValue() ?? 0);
const y = formatAsDecimal(node.getChildByName('y')?.getValue() ?? 0);
return `x: ${x}, y: ${y}`;
}
}
const POSITION_FORMATTER = new PositionFormatter();
class RegionFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
let res = 'SkRegion(';
node
.getChildByName('rect')
?.getAllChildren()
.forEach((rectNode: PropertyTreeNode) => {
res += `(${rectNode.getChildByName('left')?.getValue() ?? 0}, ${
rectNode.getChildByName('top')?.getValue() ?? 0
}, ${rectNode.getChildByName('right')?.getValue() ?? 0}, ${
rectNode.getChildByName('bottom')?.getValue() ?? 0
})`;
});
return res + ')';
}
}
const REGION_FORMATTER = new RegionFormatter();
class EnumFormatter implements PropertyFormatter {
constructor(
private readonly valuesById: {[key: number]: string},
private readonly overrideValue?: string,
) {}
format(node: PropertyTreeNode): string {
const value = node.getValue();
if (typeof value === 'number' && this.valuesById[value]) {
return this.valuesById[value];
}
if (typeof value === 'bigint' && this.valuesById[Number(value)]) {
return this.valuesById[Number(value)];
}
return this.overrideValue ?? `${value}`;
}
}
class FixedStringFormatter implements PropertyFormatter {
constructor(private readonly fixedStringValue: string) {}
format(node: PropertyTreeNode): string {
return this.fixedStringValue;
}
}
class TimestampNodeFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
const timestamp = node.getValue();
if (timestamp instanceof Timestamp || timestamp instanceof TimeDuration) {
return timestamp.format();
}
return 'null';
}
}
const TIMESTAMP_NODE_FORMATTER = new TimestampNodeFormatter();
class CujTypeFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
const cujTypeId: string = `${node.getValue()}`;
let cujTypeString: string | undefined;
if (cujTypeId in CujType) {
cujTypeString = CujType[cujTypeId as keyof typeof CujType];
} else {
cujTypeString = 'UNKNOWN';
}
return `${cujTypeString} (${cujTypeId})`;
}
}
const CUJ_TYPE_FORMATTER = new CujTypeFormatter();
class HexFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
return formatAsHex(node.getValue() ?? 0);
}
}
const HEX_FORMATTER = new HexFormatter();
class UpperCaseFormatter implements PropertyFormatter {
format(node: PropertyTreeNode): string {
return node.getValue()?.toString().toUpperCase() ?? '';
}
}
const UPPER_CASE_FORMATTER = new UpperCaseFormatter();
export {
BUFFER_FORMATTER,
COLOR_FORMATTER,
CUJ_TYPE_FORMATTER,
DEFAULT_PROPERTY_FORMATTER,
EMPTY_ARRAY_STRING,
EMPTY_OBJ_STRING,
EnumFormatter,
FixedStringFormatter,
HEX_FORMATTER,
LAYER_ID_FORMATTER,
MATRIX_FORMATTER,
POSITION_FORMATTER,
PropertyFormatter,
RECT_FORMATTER,
REGION_FORMATTER,
SIZE_FORMATTER,
TIMESTAMP_NODE_FORMATTER,
TRANSFORM_FORMATTER,
UPPER_CASE_FORMATTER,
formatAsHex,
};