Merge changes I85f52bd3,Ia91262e4,Ie084d288,I693815ff,If696d330, ...
* changes: WinScope: Support missing layers Winscope: Fix how layers with transforms and positions are rendered WinScope: Modify instead of replacing proto objects Support SF traces without any layers (needed when booting SF) Winscope: Translate layer flags in Surface flinger dump Update `Display default` checkbox label Add Type to transform objects. Fix visibility rule for SF traces on Winscope Allow SF traces to omit default values on the property list Fix "TypeError: Cannot read property 'x' of null" on SF traces Display only elements actually visible on the screen as "Visible" Display SF layer based on size, crop & parent instead of buffer size WinScope: Support boundless surfaces in WinScope Winscope: Use a unique stableId for all layers and wm entries Winscope: keep backwards compatibility prior to windowFrames
This commit is contained in:
@@ -17,6 +17,15 @@
|
|||||||
<md-whiteframe md-tag="md-toolbar">
|
<md-whiteframe md-tag="md-toolbar">
|
||||||
<h1 class="md-title" style="flex: 1">{{title}}</h1>
|
<h1 class="md-title" style="flex: 1">{{title}}</h1>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<md-checkbox v-model="store.displayDefaults">Show default properties
|
||||||
|
<md-tooltip md-direction="bottom">
|
||||||
|
If checked, shows the value of all properties.
|
||||||
|
Otherwise, hides all properties whose value is the default for its data type.
|
||||||
|
</md-tooltip>
|
||||||
|
</md-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
<input type="file" @change="onLoadFile" id="upload-file" v-show="false"/>
|
<input type="file" @change="onLoadFile" id="upload-file" v-show="false"/>
|
||||||
<label class="md-button md-accent md-raised md-theme-default" for="upload-file">Open File</label>
|
<label class="md-button md-accent md-raised md-theme-default" for="upload-file">Open File</label>
|
||||||
|
|
||||||
@@ -82,6 +91,7 @@ import LocalStore from './localstore.js'
|
|||||||
import {transform_json} from './transform.js'
|
import {transform_json} from './transform.js'
|
||||||
import {transform_layers, transform_layers_trace} from './transform_sf.js'
|
import {transform_layers, transform_layers_trace} from './transform_sf.js'
|
||||||
import {transform_window_service, transform_window_trace} from './transform_wm.js'
|
import {transform_window_service, transform_window_trace} from './transform_wm.js'
|
||||||
|
import {fill_transform_data, format_transform_type, is_simple_transform} from './matrix_utils.js'
|
||||||
|
|
||||||
|
|
||||||
var protoDefs = protobuf.Root.fromJSON(jsonProtoDefs)
|
var protoDefs = protobuf.Root.fromJSON(jsonProtoDefs)
|
||||||
@@ -98,14 +108,24 @@ function formatProto(obj) {
|
|||||||
if (!obj || !obj.$type) {
|
if (!obj || !obj.$type) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (obj.$type.fullName === '.android.surfaceflinger.RectProto') {
|
if (obj.$type.fullName === '.android.surfaceflinger.RectProto' ||
|
||||||
return `(${obj.left},${obj.top})-(${obj.right},${obj.bottom})`;
|
obj.$type.fullName === '.android.graphics.RectProto') {
|
||||||
} else if (obj.$type.fullName === '.android.surfaceflinger.PositionProto') {
|
return `(${obj.left}, ${obj.top}) - (${obj.right}, ${obj.bottom})`;
|
||||||
return `(${obj.x},${obj.y})`;
|
} else if (obj.$type.fullName === '.android.surfaceflinger.FloatRectProto') {
|
||||||
|
return `(${obj.left.toFixed(3)}, ${obj.top.toFixed(3)}) - (${obj.right.toFixed(3)}, ${obj.bottom.toFixed(3)})`;
|
||||||
|
}
|
||||||
|
else if (obj.$type.fullName === '.android.surfaceflinger.PositionProto') {
|
||||||
|
return `(${obj.x.toFixed(3)}, ${obj.y.toFixed(3)})`;
|
||||||
} else if (obj.$type.fullName === '.android.surfaceflinger.SizeProto') {
|
} else if (obj.$type.fullName === '.android.surfaceflinger.SizeProto') {
|
||||||
return `${obj.w}x${obj.h}`;
|
return `${obj.w} x ${obj.h}`;
|
||||||
} else if (obj.$type.fullName === '.android.surfaceflinger.ColorProto') {
|
} else if (obj.$type.fullName === '.android.surfaceflinger.ColorProto') {
|
||||||
return `r:${obj.r} g:${obj.g} b:${obj.b} a:${obj.a}`;
|
return `r:${obj.r} g:${obj.g} \n b:${obj.b} a:${obj.a}`;
|
||||||
|
} else if (obj.$type.fullName === '.android.surfaceflinger.TransformProto') {
|
||||||
|
var transform_type = format_transform_type(obj);
|
||||||
|
if (is_simple_transform(obj)) {
|
||||||
|
return `${transform_type}`;
|
||||||
|
}
|
||||||
|
return `${transform_type} dsdx:${obj.dsdx.toFixed(3)} dtdx:${obj.dtdx.toFixed(3)} dsdy:${obj.dsdy.toFixed(3)} dtdy:${obj.dtdy.toFixed(3)}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,6 +175,7 @@ export default {
|
|||||||
store: LocalStore('app', {
|
store: LocalStore('app', {
|
||||||
flattened: false,
|
flattened: false,
|
||||||
onlyVisible: false,
|
onlyVisible: false,
|
||||||
|
displayDefaults: true
|
||||||
}),
|
}),
|
||||||
FILE_TYPES,
|
FILE_TYPES,
|
||||||
fileType: "auto",
|
fileType: "auto",
|
||||||
@@ -189,9 +210,46 @@ export default {
|
|||||||
}
|
}
|
||||||
this.title = this.filename + " (loading " + filetype.name + ")";
|
this.title = this.filename + " (loading " + filetype.name + ")";
|
||||||
|
|
||||||
|
// Replace enum values with string representation and
|
||||||
|
// add default values to the proto objects. This function also handles
|
||||||
|
// a special case with TransformProtos where the matrix may be derived
|
||||||
|
// from the transform type.
|
||||||
|
function modifyProtoFields(protoObj, displayDefaults) {
|
||||||
|
if (!protoObj || protoObj !== Object(protoObj) || !protoObj.$type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (var fieldName in protoObj.$type.fields) {
|
||||||
|
var fieldProperties = protoObj.$type.fields[fieldName];
|
||||||
|
var field = protoObj[fieldName];
|
||||||
|
|
||||||
|
if (Array.isArray(field)) {
|
||||||
|
field.forEach((item, _) => {
|
||||||
|
modifyProtoFields(item, displayDefaults);
|
||||||
|
})
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayDefaults && !(field)) {
|
||||||
|
protoObj[fieldName] = fieldProperties.defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldProperties.type === 'TransformProto'){
|
||||||
|
fill_transform_data(protoObj[fieldName]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldProperties.resolvedType && fieldProperties.resolvedType.valuesById) {
|
||||||
|
protoObj[fieldName] = fieldProperties.resolvedType.valuesById[protoObj[fieldProperties.name]];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyProtoFields(protoObj[fieldName], displayDefaults);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var decoded = filetype.protoType.decode(buffer);
|
var decoded = filetype.protoType.decode(buffer);
|
||||||
decoded = filetype.protoType.toObject(decoded, {enums: String, defaults: true});
|
modifyProtoFields(decoded, this.store.displayDefaults);
|
||||||
var transformed = filetype.transform(decoded);
|
var transformed = filetype.transform(decoded);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
this.title = this.filename + " (loading " + filetype.name + "):" + ex;
|
this.title = this.filename + " (loading " + filetype.name + "):" + ex;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export default {
|
|||||||
var w = this.s(r.right) - this.s(r.left);
|
var w = this.s(r.right) - this.s(r.left);
|
||||||
var h = this.s(r.bottom) - this.s(r.top);
|
var h = this.s(r.bottom) - this.s(r.top);
|
||||||
var t = r.transform;
|
var t = r.transform;
|
||||||
var tr = t ? `matrix(${t.dsdx}, ${t.dtdx}, ${t.dsdy}, ${t.dtdy}, 0, 0)` : '';
|
var tr = t ? `matrix(${t.dsdx}, ${t.dtdx}, ${t.dsdy}, ${t.dtdy}, ${this.s(t.tx)}, ${this.s(t.ty)})` : '';
|
||||||
return `top: ${y}px; left: ${x}px; height: ${h}px; width: ${w}px;` +
|
return `top: ${y}px; left: ${x}px; height: ${h}px; width: ${w}px;` +
|
||||||
`transform: ${tr}; transform-origin: 0 0;`
|
`transform: ${tr}; transform-origin: 0 0;`
|
||||||
},
|
},
|
||||||
|
|||||||
175
tools/winscope/src/matrix_utils.js
Normal file
175
tools/winscope/src/matrix_utils.js
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* transform type flags */
|
||||||
|
const TRANSLATE_VAL = 0x0001;
|
||||||
|
const ROTATE_VAL = 0x0002;
|
||||||
|
const SCALE_VAL = 0x0004;
|
||||||
|
|
||||||
|
/* orientation flags */
|
||||||
|
const FLIP_H_VAL = 0x0100; // (1 << 0 << 8)
|
||||||
|
const FLIP_V_VAL = 0x0200; // (1 << 1 << 8)
|
||||||
|
const ROT_90_VAL = 0x0400; // (1 << 2 << 8)
|
||||||
|
const ROT_INVALID_VAL = 0x8000; // (0x80 << 8)
|
||||||
|
|
||||||
|
function is_proto_2(transform) {
|
||||||
|
/*
|
||||||
|
* Checks if the loaded file was a stored with ProtoBuf2 or Protobuf3
|
||||||
|
*
|
||||||
|
* Proto2 files don't have a Type for the transform object but all other
|
||||||
|
* fields of the transform are set.
|
||||||
|
*
|
||||||
|
* Proto3 has a type field for the transform but doesn't store default
|
||||||
|
* values (0 for transform type), also, the framework/native implementation
|
||||||
|
* doesn't write a transform in case it is an identity matrix.
|
||||||
|
*/
|
||||||
|
var propertyNames = Object.getOwnPropertyNames(transform);
|
||||||
|
return (!propertyNames.includes("type") && propertyNames.includes("dsdx"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_simple_transform(transform) {
|
||||||
|
transform = transform || {};
|
||||||
|
if (is_proto_2(transform)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return is_type_flag_clear(transform, ROT_INVALID_VAL|SCALE_VAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a transform type into readable format.
|
||||||
|
* Adapted from the dump function from framework/native
|
||||||
|
*
|
||||||
|
* @param {*} transform Transform object ot be converter
|
||||||
|
*/
|
||||||
|
function format_transform_type(transform) {
|
||||||
|
if (is_proto_2(transform)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_type_flag_clear(transform, SCALE_VAL | ROTATE_VAL | TRANSLATE_VAL)) {
|
||||||
|
return "IDENTITY";
|
||||||
|
}
|
||||||
|
|
||||||
|
var type_flags = [];
|
||||||
|
if (is_type_flag_set(transform, SCALE_VAL)) {
|
||||||
|
type_flags.push("SCALE");
|
||||||
|
}
|
||||||
|
if (is_type_flag_set(transform, TRANSLATE_VAL)) {
|
||||||
|
type_flags.push("TRANSLATE");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_type_flag_set(transform, ROT_INVALID_VAL)) {
|
||||||
|
type_flags.push("ROT_INVALID");
|
||||||
|
} else if (is_type_flag_set(transform, ROT_90_VAL|FLIP_V_VAL|FLIP_H_VAL)) {
|
||||||
|
type_flags.push("ROT_270");
|
||||||
|
} else if (is_type_flag_set(transform, FLIP_V_VAL|FLIP_H_VAL)) {
|
||||||
|
type_flags.push("ROT_180");
|
||||||
|
} else {
|
||||||
|
if (is_type_flag_set(transform, ROT_90_VAL)) {
|
||||||
|
type_flags.push("ROT_90");
|
||||||
|
}
|
||||||
|
if (is_type_flag_set(transform, FLIP_V_VAL)) {
|
||||||
|
type_flags.push("FLIP_V");
|
||||||
|
}
|
||||||
|
if (is_type_flag_set(transform, FLIP_H_VAL)) {
|
||||||
|
type_flags.push("FLIP_H");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type_flags.length == 0) {
|
||||||
|
throw "Unknown transform type " + transform ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_flags.join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures all values of the transform object are set.
|
||||||
|
*/
|
||||||
|
function fill_transform_data(transform) {
|
||||||
|
function fill_simple_transform(transform) {
|
||||||
|
// ROT_270 = ROT_90|FLIP_H|FLIP_V;
|
||||||
|
if (is_type_flag_set(transform, ROT_90_VAL|FLIP_V_VAL|FLIP_H_VAL)) {
|
||||||
|
transform.dsdx = 0.0;
|
||||||
|
transform.dtdx = -1.0;
|
||||||
|
transform.dsdy = 1.0;
|
||||||
|
transform.dtdy = 0.0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ROT_180 = FLIP_H|FLIP_V;
|
||||||
|
if (is_type_flag_set(transform, FLIP_V_VAL|FLIP_H_VAL)) {
|
||||||
|
transform.dsdx = -1.0;
|
||||||
|
transform.dtdx = 0.0;
|
||||||
|
transform.dsdy = 0.0;
|
||||||
|
transform.dtdy = -1.0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ROT_90
|
||||||
|
if (is_type_flag_set(transform, ROT_90_VAL)) {
|
||||||
|
transform.dsdx = 0.0;
|
||||||
|
transform.dtdx = 1.0;
|
||||||
|
transform.dsdy = -1.0;
|
||||||
|
transform.dtdy = 0.0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDENTITY
|
||||||
|
if (is_type_flag_clear(transform, SCALE_VAL | ROTATE_VAL)) {
|
||||||
|
transform.dsdx = 1.0;
|
||||||
|
transform.dtdx = 0.0;
|
||||||
|
transform.dsdy = 0.0;
|
||||||
|
transform.dtdy = 1.0;
|
||||||
|
transform.type = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "Unknown transform type " + transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!transform) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_proto_2(transform)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_simple_transform(transform)){
|
||||||
|
fill_simple_transform(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
transform.dsdx = transform.dsdx || 0.0;
|
||||||
|
transform.dtdx = transform.dtdx || 0.0;
|
||||||
|
transform.dsdy = transform.dsdy || 0.0;
|
||||||
|
transform.dtdy = transform.dtdy || 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_type_flag_set(transform, bits) {
|
||||||
|
transform = transform || {};
|
||||||
|
var type = transform.type || 0;
|
||||||
|
return (type & bits) === bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_type_flag_clear(transform, bits) {
|
||||||
|
transform = transform || {};
|
||||||
|
var type = transform.type || 0;
|
||||||
|
return (type & bits) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {format_transform_type, fill_transform_data, is_simple_transform};
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function transform({obj, kind, name, children, timestamp, rect, bounds, highlight, rects_transform, chips, visible, flattened}) {
|
function transform({obj, kind, name, children, timestamp, rect, bounds, highlight, rects_transform, chips, visible, flattened, stableId}) {
|
||||||
function call(fn, arg) {
|
function call(fn, arg) {
|
||||||
return (typeof fn == 'function') ? fn(arg) : fn;
|
return (typeof fn == 'function') ? fn(arg) : fn;
|
||||||
}
|
}
|
||||||
@@ -55,6 +55,9 @@ function transform({obj, kind, name, children, timestamp, rect, bounds, highligh
|
|||||||
var kindResolved = call(kind, obj);
|
var kindResolved = call(kind, obj);
|
||||||
var nameResolved = call(name, obj);
|
var nameResolved = call(name, obj);
|
||||||
var rectResolved = call(rect, obj);
|
var rectResolved = call(rect, obj);
|
||||||
|
var stableIdResolved = (stableId === undefined) ?
|
||||||
|
kindResolved + '|-|' + nameResolved :
|
||||||
|
call(stableId, obj);
|
||||||
|
|
||||||
var result = {
|
var result = {
|
||||||
kind: kindResolved,
|
kind: kindResolved,
|
||||||
@@ -68,7 +71,7 @@ function transform({obj, kind, name, children, timestamp, rect, bounds, highligh
|
|||||||
rects: rects_transform(concat(rectResolved, transformed_children, (e) => e.rects)),
|
rects: rects_transform(concat(rectResolved, transformed_children, (e) => e.rects)),
|
||||||
highlight: call(highlight, obj),
|
highlight: call(highlight, obj),
|
||||||
chips: call(chips, obj),
|
chips: call(chips, obj),
|
||||||
stableId: kindResolved + "|-|" + nameResolved,
|
stableId: stableIdResolved,
|
||||||
visible: call(visible, obj),
|
visible: call(visible, obj),
|
||||||
childrenVisible: transformed_children.some((c) => {
|
childrenVisible: transformed_children.some((c) => {
|
||||||
return c.childrenVisible || c.visible
|
return c.childrenVisible || c.visible
|
||||||
|
|||||||
@@ -16,7 +16,11 @@
|
|||||||
|
|
||||||
import {transform, nanos_to_string, get_visible_chip} from './transform.js'
|
import {transform, nanos_to_string, get_visible_chip} from './transform.js'
|
||||||
|
|
||||||
const FLAG_HIDDEN = 0x1;
|
// Layer flags
|
||||||
|
const FLAG_HIDDEN = 0x01;
|
||||||
|
const FLAG_OPAQUE = 0x02;
|
||||||
|
const FLAG_SECURE = 0x80;
|
||||||
|
|
||||||
var RELATIVE_Z_CHIP = {short: 'RelZ',
|
var RELATIVE_Z_CHIP = {short: 'RelZ',
|
||||||
long: "Is relative Z-ordered to another surface",
|
long: "Is relative Z-ordered to another surface",
|
||||||
class: 'warn'};
|
class: 'warn'};
|
||||||
@@ -27,36 +31,139 @@ var MISSING_LAYER = {short: 'MissingLayer',
|
|||||||
long: "This layer was referenced from the parent, but not present in the trace",
|
long: "This layer was referenced from the parent, but not present in the trace",
|
||||||
class: 'error'};
|
class: 'error'};
|
||||||
|
|
||||||
function transform_layer(layer, {parentHidden}) {
|
function transform_layer(layer, {parentBounds, parentHidden}) {
|
||||||
function transform_rect(layer) {
|
|
||||||
var pos = layer.position || {};
|
|
||||||
var size = layer.size || {};
|
|
||||||
|
|
||||||
|
function get_size(layer) {
|
||||||
|
var size = layer.size || {w: 0, h: 0};
|
||||||
return {
|
return {
|
||||||
left: pos.x || 0,
|
left: 0,
|
||||||
right: pos.x + size.w || 0,
|
right: size.w,
|
||||||
top: pos.y || 0,
|
top: 0,
|
||||||
bottom: pos.y + size.h || 0,
|
bottom: size.h
|
||||||
label: layer.name,
|
};
|
||||||
transform: layer.transform,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_crop(layer) {
|
||||||
|
var crop = layer.crop || {left: 0, top: 0, right: 0 , bottom:0};
|
||||||
|
return {
|
||||||
|
left: crop.left || 0,
|
||||||
|
right: crop.right || 0,
|
||||||
|
top: crop.top || 0,
|
||||||
|
bottom: crop.bottom || 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function intersect(bounds, crop) {
|
||||||
|
return {
|
||||||
|
left: Math.max(crop.left, bounds.left),
|
||||||
|
right: Math.min(crop.right, bounds.right),
|
||||||
|
top: Math.max(crop.top, bounds.top),
|
||||||
|
bottom: Math.min(crop.bottom, bounds.bottom),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_empty_rect(rect) {
|
||||||
|
var right = rect.right || 0;
|
||||||
|
var left = rect.left || 0;
|
||||||
|
var top = rect.top || 0;
|
||||||
|
var bottom = rect.bottom || 0;
|
||||||
|
|
||||||
|
return (right - left) <= 0 || (bottom - top) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_cropped_bounds(layer, parentBounds) {
|
||||||
|
var size = get_size(layer);
|
||||||
|
var crop = get_crop(layer);
|
||||||
|
if (!is_empty_rect(size) && !is_empty_rect(crop)) {
|
||||||
|
return intersect(size, crop);
|
||||||
|
}
|
||||||
|
if (!is_empty_rect(size)) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
if (!is_empty_rect(crop)) {
|
||||||
|
return crop;
|
||||||
|
}
|
||||||
|
return parentBounds || { left: 0, right: 0, top: 0, bottom: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
function offset_to(bounds, x, y) {
|
||||||
|
return {
|
||||||
|
right: bounds.right - (bounds.left - x),
|
||||||
|
bottom: bounds.bottom - (bounds.top - y),
|
||||||
|
left: x,
|
||||||
|
top: y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function transform_bounds(layer, parentBounds) {
|
||||||
|
var result = layer.bounds || get_cropped_bounds(layer, parentBounds);
|
||||||
|
var tx = (layer.position) ? layer.position.x || 0 : 0;
|
||||||
|
var ty = (layer.position) ? layer.position.y || 0 : 0;
|
||||||
|
result = offset_to(result, 0, 0);
|
||||||
|
result.label = layer.name;
|
||||||
|
result.transform = layer.transform;
|
||||||
|
result.transform.tx = tx;
|
||||||
|
result.transform.ty = ty;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_opaque(layer) {
|
||||||
|
return layer.color == undefined || (layer.color.a || 0) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_empty(region) {
|
||||||
|
return region == undefined ||
|
||||||
|
region.rect == undefined ||
|
||||||
|
region.rect.length == 0 ||
|
||||||
|
region.rect.every(function(r) { return is_empty_rect(r) } );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the layer is visible on screen according to its type,
|
||||||
|
* active buffer content, alpha and visible regions.
|
||||||
|
*
|
||||||
|
* @param {layer} layer
|
||||||
|
* @returns if the layer is visible on screen or not
|
||||||
|
*/
|
||||||
|
function is_visible(layer) {
|
||||||
|
var visible = (layer.activeBuffer || layer.type === 'ColorLayer')
|
||||||
|
&& !hidden && is_opaque(layer);
|
||||||
|
visible &= !is_empty(layer.visibleRegion);
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
function postprocess_flags(layer) {
|
||||||
|
if (!layer.flags) return;
|
||||||
|
var verboseFlags = [];
|
||||||
|
if (layer.flags & FLAG_HIDDEN) {
|
||||||
|
verboseFlags.push("HIDDEN");
|
||||||
|
}
|
||||||
|
if (layer.flags & FLAG_OPAQUE) {
|
||||||
|
verboseFlags.push("OPAQUE");
|
||||||
|
}
|
||||||
|
if (layer.flags & FLAG_SECURE) {
|
||||||
|
verboseFlags.push("SECURE");
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.flags = verboseFlags.join('|') + " (" + layer.flags + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
var chips = [];
|
var chips = [];
|
||||||
var rect = transform_rect(layer);
|
var rect = transform_bounds(layer, parentBounds);
|
||||||
var hidden = (layer.flags & FLAG_HIDDEN) != 0 || parentHidden;
|
var hidden = (layer.flags & FLAG_HIDDEN) != 0 || parentHidden;
|
||||||
var visible = (layer.activeBuffer || layer.type === 'ColorLayer')
|
var visible = is_visible(layer);
|
||||||
&& !hidden && layer.color.a > 0;
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
chips.push(get_visible_chip());
|
chips.push(get_visible_chip());
|
||||||
} else {
|
} else {
|
||||||
rect = undefined;
|
rect = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bounds = undefined;
|
var bounds = undefined;
|
||||||
if (layer.name.startsWith("Display Root#0")) {
|
if (layer.name.startsWith("Display Root#0") && layer.sourceBounds) {
|
||||||
bounds = {width: layer.size.w, height: layer.size.h};
|
bounds = {width: layer.sourceBounds.right, height: layer.sourceBounds.bottom};
|
||||||
}
|
}
|
||||||
if (layer.zOrderRelativeOf !== -1) {
|
|
||||||
|
if ((layer.zOrderRelativeOf || -1) !== -1) {
|
||||||
chips.push(RELATIVE_Z_CHIP);
|
chips.push(RELATIVE_Z_CHIP);
|
||||||
}
|
}
|
||||||
if (layer.zOrderRelativeParentOf !== undefined) {
|
if (layer.zOrderRelativeParentOf !== undefined) {
|
||||||
@@ -67,7 +174,9 @@ function transform_layer(layer, {parentHidden}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var transform_layer_with_parent_hidden =
|
var transform_layer_with_parent_hidden =
|
||||||
(layer) => transform_layer(layer, {parentHidden: hidden});
|
(layer) => transform_layer(layer, {parentBounds: rect, parentHidden: hidden});
|
||||||
|
|
||||||
|
postprocess_flags(layer);
|
||||||
|
|
||||||
return transform({
|
return transform({
|
||||||
obj: layer,
|
obj: layer,
|
||||||
@@ -89,16 +198,20 @@ function missingLayer(childId) {
|
|||||||
name: "layer #" + childId,
|
name: "layer #" + childId,
|
||||||
missing: true,
|
missing: true,
|
||||||
zOrderRelativeOf: -1,
|
zOrderRelativeOf: -1,
|
||||||
|
transform: {dsdx:1, dtdx:0, dsdy:0, dtdy:1},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function transform_layers(layers) {
|
function transform_layers(layers) {
|
||||||
var idToItem = {};
|
var idToItem = {};
|
||||||
var isChild = {}
|
var isChild = {}
|
||||||
layers.layers.forEach((e) => {
|
|
||||||
|
var layersList = layers.layers || [];
|
||||||
|
|
||||||
|
layersList.forEach((e) => {
|
||||||
idToItem[e.id] = e;
|
idToItem[e.id] = e;
|
||||||
});
|
});
|
||||||
layers.layers.forEach((e) => {
|
layersList.forEach((e) => {
|
||||||
e.resolvedChildren = [];
|
e.resolvedChildren = [];
|
||||||
if (Array.isArray(e.children)) {
|
if (Array.isArray(e.children)) {
|
||||||
e.resolvedChildren = e.children.map(
|
e.resolvedChildren = e.children.map(
|
||||||
@@ -107,11 +220,12 @@ function transform_layers(layers) {
|
|||||||
isChild[childId] = true;
|
isChild[childId] = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (e.zOrderRelativeOf !== -1) {
|
if ((e.zOrderRelativeOf || -1) !== -1) {
|
||||||
idToItem[e.zOrderRelativeOf].zOrderRelativeParentOf = e.id;
|
idToItem[e.zOrderRelativeOf].zOrderRelativeParentOf = e.id;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var roots = layers.layers.filter((e) => !isChild[e.id]);
|
|
||||||
|
var roots = layersList.filter((e) => !isChild[e.id]);
|
||||||
|
|
||||||
function foreachTree(nodes, fun) {
|
function foreachTree(nodes, fun) {
|
||||||
nodes.forEach((n) => {
|
nodes.forEach((n) => {
|
||||||
@@ -121,12 +235,15 @@ function transform_layers(layers) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var idToTransformed = {};
|
var idToTransformed = {};
|
||||||
var transformed_roots = roots.map(transform_layer);
|
var transformed_roots = roots.map((r) =>
|
||||||
|
transform_layer(r, {parentBounds: {left: 0, right: 0, top: 0, bottom: 0},
|
||||||
|
parentHidden: false}));
|
||||||
|
|
||||||
foreachTree(transformed_roots, (n) => {
|
foreachTree(transformed_roots, (n) => {
|
||||||
idToTransformed[n.obj.id] = n;
|
idToTransformed[n.obj.id] = n;
|
||||||
});
|
});
|
||||||
var flattened = [];
|
var flattened = [];
|
||||||
layers.layers.forEach((e) => {
|
layersList.forEach((e) => {
|
||||||
flattened.push(idToTransformed[e.id]);
|
flattened.push(idToTransformed[e.id]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -159,11 +276,12 @@ function transform_layers_entry(entry) {
|
|||||||
[[entry.layers], transform_layers],
|
[[entry.layers], transform_layers],
|
||||||
],
|
],
|
||||||
timestamp: entry.elapsedRealtimeNanos,
|
timestamp: entry.elapsedRealtimeNanos,
|
||||||
|
stableId: 'entry',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function transform_layers_trace(entries) {
|
function transform_layers_trace(entries) {
|
||||||
return transform({
|
var r = transform({
|
||||||
obj: entries,
|
obj: entries,
|
||||||
kind: 'layerstrace',
|
kind: 'layerstrace',
|
||||||
name: 'layerstrace',
|
name: 'layerstrace',
|
||||||
@@ -171,6 +289,8 @@ function transform_layers_trace(entries) {
|
|||||||
[entries.entry, transform_layers_entry],
|
[entries.entry, transform_layers_entry],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {transform_layers, transform_layers_trace};
|
export {transform_layers, transform_layers_trace};
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ function transform_window(entry) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var name = renderIdentifier(entry.identifier)
|
var name = renderIdentifier(entry.identifier)
|
||||||
var rect = transform_rect(entry.windowFrames.frame, name);
|
var rect = transform_rect((entry.windowFrames || entry).frame, name);
|
||||||
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
chips.push(get_visible_chip());
|
chips.push(get_visible_chip());
|
||||||
@@ -182,6 +182,7 @@ function transform_entry(entry) {
|
|||||||
[[entry.windowManagerService.policy], transform_policy],
|
[[entry.windowManagerService.policy], transform_policy],
|
||||||
],
|
],
|
||||||
timestamp: entry.elapsedRealtimeNanos,
|
timestamp: entry.elapsedRealtimeNanos,
|
||||||
|
stableId: 'entry',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user