| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="stylesheet" href="/tracing/ui/extras/chrome/cc/layer_picker.css"> |
| |
| <link rel="import" href="/tracing/base/unit.html"> |
| <link rel="import" href="/tracing/extras/chrome/cc/constants.html"> |
| <link rel="import" href="/tracing/extras/chrome/cc/layer_tree_host_impl.html"> |
| <link rel="import" href="/tracing/extras/chrome/cc/util.html"> |
| <link rel="import" href="/tracing/model/event.html"> |
| <link rel="import" href="/tracing/ui/analysis/generic_object_view.html"> |
| <link rel="import" href="/tracing/ui/base/dom_helpers.html"> |
| <link rel="import" href="/tracing/ui/base/drag_handle.html"> |
| <link rel="import" href="/tracing/ui/base/list_view.html"> |
| <link rel="import" href="/tracing/ui/extras/chrome/cc/selection.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.exportTo('tr.ui.e.chrome.cc', function() { |
| var constants = tr.e.cc.constants; |
| var RENDER_PASS_QUADS = |
| Math.max(constants.ACTIVE_TREE, constants.PENDING_TREE) + 1; |
| |
| /** |
| * @constructor |
| */ |
| var LayerPicker = tr.ui.b.define('tr-ui-e-chrome-cc-layer-picker'); |
| |
| LayerPicker.prototype = { |
| __proto__: HTMLUnknownElement.prototype, |
| |
| decorate: function() { |
| this.lthi_ = undefined; |
| this.controls_ = document.createElement('top-controls'); |
| this.renderPassQuads_ = false; |
| |
| |
| this.itemList_ = new tr.ui.b.ListView(); |
| Polymer.dom(this).appendChild(this.controls_); |
| |
| Polymer.dom(this).appendChild(this.itemList_); |
| |
| this.itemList_.addEventListener( |
| 'selection-changed', this.onItemSelectionChanged_.bind(this)); |
| |
| Polymer.dom(this.controls_).appendChild(tr.ui.b.createSelector( |
| this, 'whichTree', |
| 'layerPicker.whichTree', constants.ACTIVE_TREE, |
| [{label: 'Active tree', value: constants.ACTIVE_TREE}, |
| {label: 'Pending tree', value: constants.PENDING_TREE}, |
| {label: 'Render pass quads', value: RENDER_PASS_QUADS}])); |
| |
| this.showPureTransformLayers_ = false; |
| var showPureTransformLayers = tr.ui.b.createCheckBox( |
| this, 'showPureTransformLayers', |
| 'layerPicker.showPureTransformLayers', false, |
| 'Transform layers'); |
| Polymer.dom(showPureTransformLayers).classList.add( |
| 'show-transform-layers'); |
| showPureTransformLayers.title = |
| 'When checked, pure transform layers are shown'; |
| Polymer.dom(this.controls_).appendChild(showPureTransformLayers); |
| }, |
| |
| get lthiSnapshot() { |
| return this.lthiSnapshot_; |
| }, |
| |
| set lthiSnapshot(lthiSnapshot) { |
| this.lthiSnapshot_ = lthiSnapshot; |
| this.updateContents_(); |
| }, |
| |
| get whichTree() { |
| return this.renderPassQuads_ ? constants.ACTIVE_TREE : this.whichTree_; |
| }, |
| |
| set whichTree(whichTree) { |
| this.whichTree_ = whichTree; |
| this.renderPassQuads_ = (whichTree == RENDER_PASS_QUADS); |
| this.updateContents_(); |
| tr.b.dispatchSimpleEvent(this, 'selection-change', false); |
| }, |
| |
| get layerTreeImpl() { |
| if (this.lthiSnapshot === undefined) |
| return undefined; |
| return this.lthiSnapshot.getTree(this.whichTree); |
| }, |
| |
| get isRenderPassQuads() { |
| return this.renderPassQuads_; |
| }, |
| |
| get showPureTransformLayers() { |
| return this.showPureTransformLayers_; |
| }, |
| |
| set showPureTransformLayers(show) { |
| if (this.showPureTransformLayers_ === show) |
| return; |
| this.showPureTransformLayers_ = show; |
| this.updateContents_(); |
| }, |
| |
| getRenderPassInfos_: function() { |
| if (!this.lthiSnapshot_) |
| return []; |
| |
| var renderPassInfo = []; |
| if (!this.lthiSnapshot_.args.frame || |
| !this.lthiSnapshot_.args.frame.renderPasses) |
| return renderPassInfo; |
| |
| var renderPasses = this.lthiSnapshot_.args.frame.renderPasses; |
| for (var i = 0; i < renderPasses.length; ++i) { |
| var info = {renderPass: renderPasses[i], |
| depth: 0, |
| id: i, |
| name: 'cc::RenderPass'}; |
| renderPassInfo.push(info); |
| } |
| return renderPassInfo; |
| }, |
| |
| getLayerInfos_: function() { |
| if (!this.lthiSnapshot_) |
| return []; |
| |
| var tree = this.lthiSnapshot_.getTree(this.whichTree_); |
| if (!tree) |
| return []; |
| |
| var layerInfos = []; |
| |
| var showPureTransformLayers = this.showPureTransformLayers_; |
| |
| function isPureTransformLayer(layer) { |
| if (layer.args.compositingReasons && |
| layer.args.compositingReasons.length != 1 && |
| layer.args.compositingReasons[0] != 'No reasons given') |
| return false; |
| |
| if (layer.args.drawsContent) |
| return false; |
| |
| return true; |
| } |
| var visitedLayers = {}; |
| function visitLayer(layer, depth, isMask, isReplica) { |
| if (visitedLayers[layer.layerId]) |
| return; |
| visitedLayers[layer.layerId] = true; |
| var info = {layer: layer, |
| depth: depth}; |
| |
| if (layer.args.drawsContent) |
| info.name = layer.objectInstance.name; |
| else |
| info.name = 'cc::LayerImpl'; |
| |
| if (layer.usingGpuRasterization) |
| info.name += ' (G)'; |
| |
| info.isMaskLayer = isMask; |
| info.replicaLayer = isReplica; |
| |
| if (showPureTransformLayers || !isPureTransformLayer(layer)) |
| layerInfos.push(info); |
| |
| } |
| tree.iterLayers(visitLayer); |
| return layerInfos; |
| }, |
| |
| updateContents_: function() { |
| if (this.renderPassQuads_) |
| this.updateRenderPassContents_(); |
| else |
| this.updateLayerContents_(); |
| }, |
| |
| updateRenderPassContents_: function() { |
| this.itemList_.clear(); |
| |
| var selectedRenderPassId; |
| if (this.selection_ && this.selection_.associatedRenderPassId) |
| selectedRenderPassId = this.selection_.associatedRenderPassId; |
| |
| var renderPassInfos = this.getRenderPassInfos_(); |
| renderPassInfos.forEach(function(renderPassInfo) { |
| var renderPass = renderPassInfo.renderPass; |
| var id = renderPassInfo.id; |
| |
| var item = this.createElementWithDepth_(renderPassInfo.depth); |
| var labelEl = Polymer.dom(item).appendChild(tr.ui.b.createSpan()); |
| |
| Polymer.dom(labelEl).textContent = renderPassInfo.name + ' ' + id; |
| item.renderPass = renderPass; |
| item.renderPassId = id; |
| Polymer.dom(this.itemList_).appendChild(item); |
| |
| if (id == selectedRenderPassId) { |
| renderPass.selectionState = |
| tr.model.SelectionState.SELECTED; |
| } |
| }, this); |
| }, |
| |
| updateLayerContents_: function() { |
| this.changingItemSelection_ = true; |
| try { |
| this.itemList_.clear(); |
| |
| var selectedLayerId; |
| if (this.selection_ && this.selection_.associatedLayerId) |
| selectedLayerId = this.selection_.associatedLayerId; |
| |
| var layerInfos = this.getLayerInfos_(); |
| layerInfos.forEach(function(layerInfo) { |
| var layer = layerInfo.layer; |
| var id = layer.layerId; |
| |
| var item = this.createElementWithDepth_(layerInfo.depth); |
| var labelEl = Polymer.dom(item).appendChild(tr.ui.b.createSpan()); |
| |
| Polymer.dom(labelEl).textContent = layerInfo.name + ' ' + id; |
| |
| var notesEl = Polymer.dom(item).appendChild(tr.ui.b.createSpan()); |
| if (layerInfo.isMaskLayer) |
| Polymer.dom(notesEl).textContent += '(mask)'; |
| if (layerInfo.isReplicaLayer) |
| Polymer.dom(notesEl).textContent += '(replica)'; |
| |
| if ((layer.gpuMemoryUsageInBytes !== undefined) && |
| (layer.gpuMemoryUsageInBytes > 0)) { |
| var gpuUsageStr = tr.b.Unit.byName.sizeInBytes.format( |
| layer.gpuMemoryUsageInBytes); |
| Polymer.dom(notesEl).textContent += ' (' + gpuUsageStr + ' MiB)'; |
| } |
| |
| item.layer = layer; |
| Polymer.dom(this.itemList_).appendChild(item); |
| |
| if (layer.layerId == selectedLayerId) { |
| layer.selectionState = tr.model.SelectionState.SELECTED; |
| item.selected = true; |
| } |
| }, this); |
| } finally { |
| this.changingItemSelection_ = false; |
| } |
| }, |
| |
| createElementWithDepth_: function(depth) { |
| var item = document.createElement('div'); |
| |
| var indentEl = Polymer.dom(item).appendChild(tr.ui.b.createSpan()); |
| indentEl.style.whiteSpace = 'pre'; |
| for (var i = 0; i < depth; i++) { |
| Polymer.dom(indentEl).textContent = |
| Polymer.dom(indentEl).textContent + ' '; |
| } |
| return item; |
| }, |
| |
| onItemSelectionChanged_: function(e) { |
| if (this.changingItemSelection_) |
| return; |
| if (this.renderPassQuads_) |
| this.onRenderPassSelected_(e); |
| else |
| this.onLayerSelected_(e); |
| tr.b.dispatchSimpleEvent(this, 'selection-change', false); |
| }, |
| |
| onRenderPassSelected_: function(e) { |
| var selectedRenderPass; |
| var selectedRenderPassId; |
| if (this.itemList_.selectedElement) { |
| selectedRenderPass = this.itemList_.selectedElement.renderPass; |
| selectedRenderPassId = |
| this.itemList_.selectedElement.renderPassId; |
| } |
| |
| if (selectedRenderPass) { |
| this.selection_ = new tr.ui.e.chrome.cc.RenderPassSelection( |
| selectedRenderPass, selectedRenderPassId); |
| } else { |
| this.selection_ = undefined; |
| } |
| }, |
| |
| onLayerSelected_: function(e) { |
| var selectedLayer; |
| if (this.itemList_.selectedElement) |
| selectedLayer = this.itemList_.selectedElement.layer; |
| |
| if (selectedLayer) |
| this.selection_ = new tr.ui.e.chrome.cc.LayerSelection(selectedLayer); |
| else |
| this.selection_ = undefined; |
| }, |
| |
| get selection() { |
| return this.selection_; |
| }, |
| |
| set selection(selection) { |
| if (this.selection_ == selection) |
| return; |
| this.selection_ = selection; |
| this.updateContents_(); |
| } |
| }; |
| |
| return { |
| LayerPicker: LayerPicker |
| }; |
| }); |
| </script> |