1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 * @fileoverview Graphical view of LayerTreeImpl, with controls for
9 * type of layer content shown and info bar for content-loading warnings.
12 tvcm.requireStylesheet('cc.layer_tree_quad_stack_view');
14 tvcm.require('tvcm.color');
15 tvcm.require('tvcm.properties');
16 tvcm.require('tvcm.raf');
17 tvcm.require('tvcm.quad');
18 tvcm.require('tvcm.range');
19 tvcm.require('cc.picture');
20 tvcm.require('cc.render_pass');
21 tvcm.require('cc.tile');
22 tvcm.require('cc.debug_colors');
23 tvcm.require('tvcm.ui.quad_stack_view');
24 tvcm.require('tvcm.ui.info_bar');
27 tvcm.exportTo('cc', function() {
29 var TILE_HEATMAP_TYPE = {};
30 TILE_HEATMAP_TYPE.NONE = 0;
31 TILE_HEATMAP_TYPE.SCHEDULED_PRIORITY = 1;
32 TILE_HEATMAP_TYPE.DISTANCE_TO_VISIBLE = 2;
33 TILE_HEATMAP_TYPE.TIME_TO_VISIBLE = 3;
34 TILE_HEATMAP_TYPE.USING_GPU_MEMORY = 4;
36 function createTileRectsSelectorBaseOptions() {
37 return [{label: 'None', value: 'none'},
38 {label: 'Coverage Rects', value: 'coverage'}];
44 var LayerTreeQuadStackView = tvcm.ui.define('layer-tree-quad-stack-view');
46 LayerTreeQuadStackView.prototype = {
47 __proto__: HTMLDivElement.prototype,
49 decorate: function() {
50 this.isRenderPassQuads_ = false;
51 this.pictureAsImageData_ = {}; // Maps picture.guid to PictureAsImageData.
53 this.controls_ = document.createElement('top-controls');
54 this.infoBar_ = new tvcm.ui.InfoBar();
55 this.quadStackView_ = new tvcm.ui.QuadStackView();
56 this.quadStackView_.addEventListener(
57 'selectionchange', this.onQuadStackViewSelectionChange_.bind(this));
59 var m = tvcm.ui.MOUSE_SELECTOR_MODE;
60 var mms = this.quadStackView_.mouseModeSelector;
61 mms.settingsKey = 'cc.layerTreeQuadStackView.mouseModeSelector';
62 mms.setKeyCodeForMode(m.SELECTION, 'Z'.charCodeAt(0));
63 mms.setKeyCodeForMode(m.PANSCAN, 'X'.charCodeAt(0));
64 mms.setKeyCodeForMode(m.ZOOM, 'C'.charCodeAt(0));
65 mms.setKeyCodeForMode(m.ROTATE, 'V'.charCodeAt(0));
67 this.appendChild(this.controls_);
68 this.appendChild(this.infoBar_);
69 this.appendChild(this.quadStackView_);
71 this.tileRectsSelector_ = tvcm.ui.createSelector(
72 this, 'howToShowTiles',
73 'layerView.howToShowTiles', 'none',
74 createTileRectsSelectorBaseOptions());
75 this.controls_.appendChild(this.tileRectsSelector_);
77 var tileHeatmapText = tvcm.ui.createSpan({
78 textContent: 'Tile heatmap:'
80 this.controls_.appendChild(tileHeatmapText);
82 var tileHeatmapSelector = tvcm.ui.createSelector(
83 this, 'tileHeatmapType',
84 'layerView.tileHeatmapType', TILE_HEATMAP_TYPE.NONE,
86 value: TILE_HEATMAP_TYPE.NONE},
87 {label: 'Scheduled Priority',
88 value: TILE_HEATMAP_TYPE.SCHEDULED_PRIORITY},
89 {label: 'Distance to Visible',
90 value: TILE_HEATMAP_TYPE.DISTANCE_TO_VISIBLE},
91 {label: 'Time to Visible',
92 value: TILE_HEATMAP_TYPE.TIME_TO_VISIBLE},
93 {label: 'Is using GPU memory',
94 value: TILE_HEATMAP_TYPE.USING_GPU_MEMORY}
96 this.controls_.appendChild(tileHeatmapSelector);
98 var showOtherLayersCheckbox = tvcm.ui.createCheckBox(
99 this, 'showOtherLayers',
100 'layerView.showOtherLayers', true,
101 'Other layers/passes');
102 showOtherLayersCheckbox.title =
103 'When checked, show all layers, selected or not.';
104 this.controls_.appendChild(showOtherLayersCheckbox);
106 var showInvalidationsCheckbox = tvcm.ui.createCheckBox(
107 this, 'showInvalidations',
108 'layerView.showInvalidations', true,
110 showInvalidationsCheckbox.title =
111 'When checked, compositing invalidations are highlighted in red';
112 this.controls_.appendChild(showInvalidationsCheckbox);
114 var showUnrecordedRegionCheckbox = tvcm.ui.createCheckBox(
115 this, 'showUnrecordedRegion',
116 'layerView.showUnrecordedRegion', true,
118 showUnrecordedRegionCheckbox.title =
119 'When checked, unrecorded areas are highlighted in yellow';
120 this.controls_.appendChild(showUnrecordedRegionCheckbox);
122 var showBottlenecksCheckbox = tvcm.ui.createCheckBox(
123 this, 'showBottlenecks',
124 'layerView.showBottlenecks', true,
126 showBottlenecksCheckbox.title =
127 'When checked, scroll bottlenecks are highlighted';
128 this.controls_.appendChild(showBottlenecksCheckbox);
130 var showLayoutRectsCheckbox = tvcm.ui.createCheckBox(
131 this, 'showLayoutRects',
132 'layerView.showLayoutRects', false,
134 showLayoutRectsCheckbox.title =
135 'When checked, shows rects for regions where layout happened';
136 this.controls_.appendChild(showLayoutRectsCheckbox);
138 var showContentsCheckbox = tvcm.ui.createCheckBox(
139 this, 'showContents',
140 'layerView.showContents', true,
142 showContentsCheckbox.title =
143 'When checked, show the rendered contents inside the layer outlines';
144 this.controls_.appendChild(showContentsCheckbox);
146 var showAnimationBoundsCheckbox = tvcm.ui.createCheckBox(
147 this, 'showAnimationBounds',
148 'layerView.showAnimationBounds', false,
150 showAnimationBoundsCheckbox.title = 'When checked, show a border around' +
151 ' a layer showing the extent of its animation.';
152 this.controls_.appendChild(showAnimationBoundsCheckbox);
155 get layerTreeImpl() {
156 return this.layerTreeImpl_;
159 set whichTree(whichTree) {
160 this.whichTree_ = whichTree;
163 set isRenderPassQuads(newValue) {
164 this.isRenderPassQuads_ = newValue;
167 set layerTreeImpl(layerTreeImpl) {
168 // FIXME(pdr): We may want to clear pictureAsImageData_ here to save
169 // memory at the cost of performance. Note that
170 // pictureAsImageData_ will be cleared when this is
171 // destructed, but this view might live for several
173 this.layerTreeImpl_ = layerTreeImpl;
174 this.selection = undefined;
177 get showOtherLayers() {
178 return this.showOtherLayers_;
181 set showOtherLayers(show) {
182 this.showOtherLayers_ = show;
183 this.updateContents_();
186 get showAnimationBounds() {
187 return this.showAnimationBounds_;
190 set showAnimationBounds(show) {
191 this.showAnimationBounds_ = show;
192 this.updateContents_();
196 return this.showContents_;
199 set showContents(show) {
200 this.showContents_ = show;
201 this.updateContents_();
204 get showInvalidations() {
205 return this.showInvalidations_;
208 set showInvalidations(show) {
209 this.showInvalidations_ = show;
210 this.updateContents_();
213 get showUnrecordedRegion() {
214 return this.showUnrecordedRegion_;
217 set showUnrecordedRegion(show) {
218 this.showUnrecordedRegion_ = show;
219 this.updateContents_();
222 get showBottlenecks() {
223 return this.showBottlenecks_;
226 set showBottlenecks(show) {
227 this.showBottlenecks_ = show;
228 this.updateContents_();
231 get showLayoutRects() {
232 return this.showLayoutRects_;
235 set showLayoutRects(show) {
236 this.showLayoutRects_ = show;
237 this.updateContents_();
240 get howToShowTiles() {
241 return this.howToShowTiles_;
244 set howToShowTiles(val) {
245 // Make sure val is something we expect.
248 (val === 'coverage') ||
249 !isNaN(parseFloat(val)));
251 this.howToShowTiles_ = val;
252 this.updateContents_();
255 get tileHeatmapType() {
256 return this.tileHeatmapType_;
259 set tileHeatmapType(val) {
260 this.tileHeatmapType_ = val;
261 this.updateContents_();
265 return this.selection_;
268 set selection(selection) {
269 tvcm.setPropertyAndDispatchChange(this, 'selection', selection);
270 this.updateContents_();
273 regenerateContent: function() {
274 this.updateTilesSelector_();
275 this.updateContents_();
278 onQuadStackViewSelectionChange_: function(e) {
279 var selectableQuads = e.quads.filter(function(q) {
280 return q.selectionToSetIfClicked !== undefined;
282 if (selectableQuads.length == 0) {
283 this.selection = undefined;
287 // Sort the quads low to high on stackingGroupId.
288 selectableQuads.sort(function(x, y) {
289 var z = x.stackingGroupId - y.stackingGroupId;
292 return x.selectionToSetIfClicked.specicifity -
293 y.selectionToSetIfClicked.specicifity;
296 // TODO(nduca): Support selecting N things at once.
297 var quadToSelect = selectableQuads[selectableQuads.length - 1];
298 this.selection = quadToSelect.selectionToSetIfClicked;
301 scheduleUpdateContents_: function() {
302 if (this.updateContentsPending_)
304 this.updateContentsPending_ = true;
305 tvcm.requestAnimationFrameInThisFrameIfPossible(
306 this.updateContents_, this);
309 updateContents_: function() {
310 if (!this.layerTreeImpl_)
314 var status = this.computePictureLoadingStatus_();
315 if (!status.picturesComplete)
318 var lthi = this.layerTreeImpl_.layerTreeHostImpl;
319 var lthiInstance = lthi.objectInstance;
320 var worldViewportRect = tvcm.Rect.fromXYWH(
322 lthi.deviceViewportSize.width, lthi.deviceViewportSize.height);
323 this.quadStackView_.deviceRect = worldViewportRect;
324 if (this.isRenderPassQuads_)
325 this.quadStackView_.quads = this.generateRenderPassQuads();
327 this.quadStackView_.quads = this.generateLayerQuads();
329 this.updateInfoBar_(status.messages);
332 updateTilesSelector_: function() {
333 var data = createTileRectsSelectorBaseOptions();
335 if (this.layerTreeImpl_) {
336 // First get all of the scales information from LTHI.
337 var lthi = this.layerTreeImpl_.layerTreeHostImpl;
338 var scaleNames = lthi.getContentsScaleNames();
339 for (var scale in scaleNames) {
341 label: 'Scale ' + scale + ' (' + scaleNames[scale] + ')',
347 // Then create a new selector and replace the old one.
348 var new_selector = tvcm.ui.createSelector(
349 this, 'howToShowTiles',
350 'layerView.howToShowTiles', 'none',
352 this.controls_.replaceChild(new_selector, this.tileRectsSelector_);
353 this.tileRectsSelector_ = new_selector;
356 computePictureLoadingStatus_: function() {
357 // Figure out if we can draw the quads yet. While we're at it, figure out
358 // if we have any warnings we need to show.
359 var layers = this.layers;
362 picturesComplete: true
364 if (this.showContents) {
365 var hasPendingRasterizeImage = false;
366 var firstPictureError = undefined;
367 var hasMissingLayerRect = false;
368 var hasUnresolvedPictureRef = false;
369 for (var i = 0; i < layers.length; i++) {
370 var layer = layers[i];
371 for (var ir = 0; ir < layer.pictures.length; ++ir) {
372 var picture = layer.pictures[ir];
375 hasUnresolvedPictureRef = true;
378 if (!picture.layerRect) {
379 hasMissingLayerRect = true;
383 var pictureAsImageData = this.pictureAsImageData_[picture.guid];
384 if (!pictureAsImageData) {
385 hasPendingRasterizeImage = true;
386 this.pictureAsImageData_[picture.guid] =
387 cc.PictureAsImageData.Pending(this);
389 {stopIndex: undefined},
390 function(pictureImageData) {
391 var picture_ = pictureImageData.picture;
392 this.pictureAsImageData_[picture_.guid] = pictureImageData;
393 this.scheduleUpdateContents_();
397 if (pictureAsImageData.isPending()) {
398 hasPendingRasterizeImage = true;
401 if (pictureAsImageData.error) {
402 if (!firstPictureError)
403 firstPictureError = pictureAsImageData.error;
408 if (hasPendingRasterizeImage) {
409 status.picturesComplete = false;
411 if (hasUnresolvedPictureRef) {
412 status.messages.push({
413 header: 'Missing picture',
414 details: 'Your trace didnt have pictures for every layer. ' +
415 'Old chrome versions had this problem'});
417 if (hasMissingLayerRect) {
418 status.messages.push({
419 header: 'Missing layer rect',
420 details: 'Your trace may be corrupt or from a very old ' +
421 'Chrome revision.'});
423 if (firstPictureError) {
424 status.messages.push({
425 header: 'Cannot rasterize',
426 details: firstPictureError});
433 get selectedRenderPass() {
435 return this.selection.renderPass_;
438 get selectedLayer() {
439 if (this.selection) {
440 var selectedLayerId = this.selection.associatedLayerId;
441 return this.layerTreeImpl_.findLayerWithId(selectedLayerId);
447 this.layerTreeImpl.layerTreeHostImpl.args.frame.renderPasses;
448 if (!this.showOtherLayers) {
449 var selectedRenderPass = this.selectedRenderPass;
450 if (selectedRenderPass)
451 renderPasses = [selectedRenderPass];
457 var layers = this.layerTreeImpl.renderSurfaceLayerList;
458 if (!this.showOtherLayers) {
459 var selectedLayer = this.selectedLayer;
461 layers = [selectedLayer];
466 appendImageQuads_: function(quads, layer, layerQuad) {
467 // Generate image quads for the layer
468 for (var ir = 0; ir < layer.pictures.length; ++ir) {
469 var picture = layer.pictures[ir];
470 if (!picture.layerRect)
473 var unitRect = picture.layerRect.asUVRectInside(layer.bounds);
474 var iq = layerQuad.projectUnitRect(unitRect);
476 var pictureData = this.pictureAsImageData_[picture.guid];
477 if (this.showContents && pictureData && pictureData.imageData) {
478 iq.imageData = pictureData.imageData;
479 iq.borderColor = 'rgba(0,0,0,0)';
481 iq.imageData = undefined;
484 iq.stackingGroupId = layerQuad.stackingGroupId;
489 appendAnimationQuads_: function(quads, layer, layerQuad) {
490 if (!layer.animationBoundsRect)
493 var rect = layer.animationBoundsRect;
494 var abq = tvcm.Quad.fromRect(rect);
496 abq.backgroundColor = 'rgba(164,191,48,0.5)';
497 abq.borderColor = 'rgba(205,255,0,0.75)';
498 abq.borderWidth = 3.0;
499 abq.stackingGroupId = layerQuad.stackingGroupId;
500 abq.selectionToSetIfClicked = new cc.AnimationRectSelection(
505 appendInvalidationQuads_: function(quads, layer, layerQuad) {
506 // Generate the invalidation rect quads.
507 for (var ir = 0; ir < layer.invalidation.rects.length; ir++) {
508 var rect = layer.invalidation.rects[ir];
509 var unitRect = rect.asUVRectInside(layer.bounds);
510 var iq = layerQuad.projectUnitRect(unitRect);
511 iq.backgroundColor = 'rgba(255, 0, 0, 0.1)';
512 iq.borderColor = 'rgba(255, 0, 0, 1)';
513 iq.stackingGroupId = layerQuad.stackingGroupId;
514 iq.selectionToSetIfClicked = new cc.LayerRectSelection(
515 layer, 'Invalidation rect', rect, rect);
520 appendUnrecordedRegionQuads_: function(quads, layer, layerQuad) {
521 // Generate the unrecorded region quads.
522 for (var ir = 0; ir < layer.unrecordedRegion.rects.length; ir++) {
523 var rect = layer.unrecordedRegion.rects[ir];
524 var unitRect = rect.asUVRectInside(layer.bounds);
525 var iq = layerQuad.projectUnitRect(unitRect);
526 iq.backgroundColor = 'rgba(240, 230, 140, 0.3)';
527 iq.borderColor = 'rgba(240, 230, 140, 1)';
528 iq.stackingGroupId = layerQuad.stackingGroupId;
529 iq.selectionToSetIfClicked = new cc.LayerRectSelection(
530 layer, 'Unrecorded area', rect, rect);
535 appendBottleneckQuads_: function(quads, layer, layerQuad, stackingGroupId) {
536 function processRegion(region, label, borderColor) {
537 var backgroundColor = borderColor.clone();
538 backgroundColor.a = 0.4 * (borderColor.a || 1.0);
540 for (var ir = 0; ir < region.rects.length; ir++) {
541 var rect = region.rects[ir];
542 var unitRect = rect.asUVRectInside(layer.bounds);
543 var iq = layerQuad.projectUnitRect(unitRect);
544 iq.backgroundColor = backgroundColor.toString();
545 iq.borderColor = borderColor.toString();
546 iq.borderWidth = 4.0;
547 iq.stackingGroupId = stackingGroupId;
548 iq.selectionToSetIfClicked = new cc.LayerRectSelection(
549 layer, label, rect, rect);
554 processRegion(layer.touchEventHandlerRegion, 'Touch listener',
555 tvcm.Color.fromString('rgb(228, 226, 27)'));
556 processRegion(layer.wheelEventHandlerRegion, 'Wheel listener',
557 tvcm.Color.fromString('rgb(176, 205, 29)'));
558 processRegion(layer.nonFastScrollableRegion, 'Repaints on scroll',
559 tvcm.Color.fromString('rgb(213, 134, 32)'));
562 appendTileCoverageRectQuads_: function(
563 quads, layer, layerQuad, heatmapType) {
564 if (!layer.tileCoverageRects)
568 for (var ct = 0; ct < layer.tileCoverageRects.length; ++ct) {
569 var tile = layer.tileCoverageRects[ct].tile;
570 if (tile !== undefined)
574 var lthi = this.layerTreeImpl_.layerTreeHostImpl;
576 this.getMinMaxForHeatmap_(lthi.tiles, heatmapType);
578 this.computeHeatmapColors_(tiles, minMax, heatmapType);
581 for (var ct = 0; ct < layer.tileCoverageRects.length; ++ct) {
582 var rect = layer.tileCoverageRects[ct].geometryRect;
583 rect = rect.scale(1.0 / layer.geometryContentsScale);
585 var tile = layer.tileCoverageRects[ct].tile;
587 var unitRect = rect.asUVRectInside(layer.bounds);
588 var quad = layerQuad.projectUnitRect(unitRect);
590 quad.backgroundColor = 'rgba(0, 0, 0, 0)';
591 quad.stackingGroupId = layerQuad.stackingGroupId;
592 var type = cc.tileTypes.missing;
594 type = tile.getTypeForLayer(layer);
595 quad.backgroundColor = heatmapColors[heatIndex];
599 quad.borderColor = cc.tileBorder[type].color;
600 quad.borderWidth = cc.tileBorder[type].width;
603 label = 'coverageRect';
605 label = 'checkerboard coverageRect';
606 quad.selectionToSetIfClicked = new cc.LayerRectSelection(
607 layer, label, rect, layer.tileCoverageRects[ct]);
613 appendLayoutRectQuads_: function(quads, layer, layerQuad) {
614 if (!layer.layoutRects) {
618 for (var ct = 0; ct < layer.layoutRects.length; ++ct) {
619 var rect = layer.layoutRects[ct].geometryRect;
620 rect = rect.scale(1.0 / layer.geometryContentsScale);
622 var unitRect = rect.asUVRectInside(layer.bounds);
623 var quad = layerQuad.projectUnitRect(unitRect);
625 quad.backgroundColor = 'rgba(0, 0, 0, 0)';
626 quad.stackingGroupId = layerQuad.stackingGroupId;
628 quad.borderColor = 'rgba(0, 0, 200, 0.7)';
629 quad.borderWidth = 2;
631 label = 'Layout rect';
632 quad.selectionToSetIfClicked = new cc.LayerRectSelection(
639 getValueForHeatmap_: function(tile, heatmapType) {
640 if (heatmapType == TILE_HEATMAP_TYPE.SCHEDULED_PRIORITY) {
641 return tile.scheduledPriority == 0 ?
643 tile.scheduledPriority;
644 } else if (heatmapType == TILE_HEATMAP_TYPE.DISTANCE_TO_VISIBLE) {
645 return tile.distanceToVisible;
646 } else if (heatmapType == TILE_HEATMAP_TYPE.TIME_TO_VISIBLE) {
647 return Math.min(5, tile.timeToVisible);
648 } else if (heatmapType == TILE_HEATMAP_TYPE.USING_GPU_MEMORY) {
649 if (tile.isSolidColor)
651 return tile.isUsingGpuMemory ? 0 : 1;
655 getMinMaxForHeatmap_: function(tiles, heatmapType) {
656 var range = new tvcm.Range();
657 if (heatmapType == TILE_HEATMAP_TYPE.USING_GPU_MEMORY) {
663 for (var i = 0; i < tiles.length; ++i) {
664 var value = this.getValueForHeatmap_(tiles[i], heatmapType);
665 if (value == undefined)
667 range.addValue(value);
669 if (range.range == 0)
674 computeHeatmapColors_: function(tiles, minMax, heatmapType) {
675 var min = minMax.min;
676 var max = minMax.max;
678 var color = function(value) {
679 var hue = 120 * (1 - (value - min) / (max - min));
682 return 'hsla(' + hue + ', 100%, 50%, 0.5)';
686 for (var i = 0; i < tiles.length; ++i) {
688 var value = this.getValueForHeatmap_(tile, heatmapType);
689 if (value !== undefined)
690 values.push(color(value));
692 values.push(undefined);
698 appendTilesWithScaleQuads_: function(
699 quads, layer, layerQuad, scale, heatmapType) {
700 var lthi = this.layerTreeImpl_.layerTreeHostImpl;
703 for (var i = 0; i < lthi.tiles.length; ++i) {
704 var tile = lthi.tiles[i];
706 if (Math.abs(tile.contentsScale - scale) > 1e-6)
709 // TODO(vmpstr): Make the stiching of tiles and layers a part of
710 // tile construction (issue 346)
711 if (layer.layerId != tile.layerId)
718 this.getMinMaxForHeatmap_(lthi.tiles, heatmapType);
720 this.computeHeatmapColors_(tiles, minMax, heatmapType);
722 for (var i = 0; i < tiles.length; ++i) {
724 var rect = tile.layerRect;
727 var unitRect = rect.asUVRectInside(layer.bounds);
728 var quad = layerQuad.projectUnitRect(unitRect);
730 quad.backgroundColor = 'rgba(0, 0, 0, 0)';
731 quad.stackingGroupId = layerQuad.stackingGroupId;
733 var type = tile.getTypeForLayer(layer);
734 quad.borderColor = cc.tileBorder[type].color;
735 quad.borderWidth = cc.tileBorder[type].width;
737 quad.backgroundColor = heatmapColors[i];
738 quad.selectionToSetIfClicked = new cc.TileSelection(tile);
743 appendSelectionQuads_: function(quads, layer, layerQuad) {
744 var selection = this.selection;
745 var rect = selection.layerRect;
749 var unitRect = rect.asUVRectInside(layer.bounds);
750 var quad = layerQuad.projectUnitRect(unitRect);
752 var colorId = tvcm.ui.getStringColorId(selection.title);
753 colorId += tvcm.ui.getColorPaletteHighlightIdBoost();
755 var color = tvcm.Color.fromString(tvcm.ui.getColorPalette()[colorId]);
757 var quadForDrawing = quad.clone();
758 quadForDrawing.backgroundColor = color.withAlpha(0.5).toString();
759 quadForDrawing.borderColor = color.withAlpha(1.0).darken().toString();
760 quadForDrawing.stackingGroupId = layerQuad.stackingGroupId;
761 quads.push(quadForDrawing);
764 generateRenderPassQuads: function() {
765 if (!this.layerTreeImpl.layerTreeHostImpl.args.frame)
767 var renderPasses = this.renderPasses;
772 for (var i = 0; i < renderPasses.length; ++i) {
773 var quadList = renderPasses[i].quadList;
774 for (var j = 0; j < quadList.length; ++j) {
775 var drawQuad = quadList[j];
776 var quad = drawQuad.rectAsTargetSpaceQuad.clone();
777 quad.borderColor = 'rgb(170, 204, 238)';
778 quad.borderWidth = 2;
779 quad.stackingGroupId = i;
786 generateLayerQuads: function() {
787 this.updateContentsPending_ = false;
789 // Generate the quads for the view.
790 var layers = this.layers;
792 var nextStackingGroupId = 0;
793 var alreadyVisitedLayerIds = {};
795 for (var i = 1; i <= layers.length; i++) {
796 // Generate quads back-to-front.
797 var layer = layers[layers.length - i];
798 alreadyVisitedLayerIds[layer.layerId] = true;
799 if (layer.objectInstance.name == 'cc::NinePatchLayerImpl')
802 var layerQuad = layer.layerQuad.clone();
803 if (layer.usingGpuRasterization) {
804 var pixelRatio = window.devicePixelRatio || 1;
805 layerQuad.borderWidth = 2.0 * pixelRatio;
806 layerQuad.borderColor = 'rgba(154,205,50,0.75)';
808 layerQuad.borderColor = 'rgba(0,0,0,0.75)';
810 layerQuad.stackingGroupId = nextStackingGroupId++;
811 layerQuad.selectionToSetIfClicked = new cc.LayerSelection(layer);
812 layerQuad.layer = layer;
813 if (this.showOtherLayers && this.selectedLayer == layer)
814 layerQuad.upperBorderColor = 'rgb(156,189,45)';
816 if (this.showAnimationBounds)
817 this.appendAnimationQuads_(quads, layer, layerQuad);
819 this.appendImageQuads_(quads, layer, layerQuad);
820 quads.push(layerQuad);
823 if (this.showInvalidations)
824 this.appendInvalidationQuads_(quads, layer, layerQuad);
825 if (this.showUnrecordedRegion)
826 this.appendUnrecordedRegionQuads_(quads, layer, layerQuad);
827 if (this.showBottlenecks)
828 this.appendBottleneckQuads_(quads, layer, layerQuad,
829 layerQuad.stackingGroupId);
830 if (this.showLayoutRects)
831 this.appendLayoutRectQuads_(quads, layer, layerQuad);
833 if (this.howToShowTiles === 'coverage') {
834 this.appendTileCoverageRectQuads_(
835 quads, layer, layerQuad, this.tileHeatmapType);
836 } else if (this.howToShowTiles !== 'none') {
837 this.appendTilesWithScaleQuads_(
838 quads, layer, layerQuad,
839 this.howToShowTiles, this.tileHeatmapType);
842 if (this.selectedLayer === layer)
843 this.appendSelectionQuads_(quads, layer, layerQuad);
846 this.layerTreeImpl.iterLayers(function(layer, depth, isMask, isReplica) {
847 if (!this.showOtherLayers && this.selectedLayer != layer)
849 if (alreadyVisitedLayerIds[layer.layerId])
851 var layerQuad = layer.layerQuad;
852 var stackingGroupId = nextStackingGroupId++;
853 if (this.showBottlenecks)
854 this.appendBottleneckQuads_(quads, layer, layerQuad, stackingGroupId);
860 updateInfoBar_: function(infoBarMessages) {
861 if (infoBarMessages.length) {
862 this.infoBar_.removeAllButtons();
863 this.infoBar_.message = 'Some problems were encountered...';
864 this.infoBar_.addButton('More info...', function(e) {
865 var overlay = new tvcm.ui.Overlay();
866 overlay.textContent = '';
867 infoBarMessages.forEach(function(message) {
868 var title = document.createElement('h3');
869 title.textContent = message.header;
871 var details = document.createElement('div');
872 details.textContent = message.details;
874 overlay.appendChild(title);
875 overlay.appendChild(details);
877 overlay.visible = true;
882 this.infoBar_.visible = true;
884 this.infoBar_.removeAllButtons();
885 this.infoBar_.message = '';
886 this.infoBar_.visible = false;
892 LayerTreeQuadStackView: LayerTreeQuadStackView