xref: /aosp_15_r20/development/tools/winscope/src/parsers/surface_flinger/computations/layer_extractor.ts (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1/*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import {assertDefined} from 'common/assert_utils';
18import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node';
19
20export class LayerExtractor {
21  static extractLayersTopToBottom(
22    layer: HierarchyTreeNode,
23  ): HierarchyTreeNode[] {
24    const traverseList: HierarchyTreeNode[] = [];
25
26    const sortedZChildren = layer
27      .getRelativeChildren()
28      .concat(
29        layer.getAllChildren().filter((child) => child.getZParent() === layer),
30      )
31      .sort((a, b) => LayerExtractor.compareByZAndLayerId(a, b));
32
33    if (layer.isRoot()) {
34      sortedZChildren.forEach((c) => {
35        traverseList.push(...LayerExtractor.extractLayersTopToBottom(c));
36      });
37    } else {
38      const layerZ = LayerExtractor.getZ(layer);
39      const sortedZChildrenBelowRoot = sortedZChildren.filter(
40        (child) => LayerExtractor.getZ(child) < layerZ,
41      );
42      const sortedZChildrenAboveRoot = sortedZChildren.filter(
43        (child) => LayerExtractor.getZ(child) >= layerZ,
44      );
45
46      sortedZChildrenAboveRoot.forEach((c) => {
47        traverseList.push(...LayerExtractor.extractLayersTopToBottom(c));
48      });
49      traverseList.push(layer);
50      sortedZChildrenBelowRoot.forEach((c) => {
51        traverseList.push(...LayerExtractor.extractLayersTopToBottom(c));
52      });
53    }
54    return traverseList;
55  }
56
57  private static compareByZAndLayerId(
58    a: HierarchyTreeNode,
59    b: HierarchyTreeNode,
60  ): number {
61    const aZ = LayerExtractor.getZ(a);
62    const bZ = LayerExtractor.getZ(b);
63
64    if (aZ > bZ) return -1;
65    if (aZ < bZ) return 1;
66
67    // When z-order is the same, the layer with larger ID is on top
68    const aId = a.getEagerPropertyByName('id')?.getValue();
69    const bId = b.getEagerPropertyByName('id')?.getValue();
70    return aId < bId ? 1 : -1;
71  }
72
73  private static getZ(node: HierarchyTreeNode): number {
74    return assertDefined(node.getEagerPropertyByName('z')).getValue();
75  }
76}
77