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 base.requireStylesheet('cc.layer_tree_quad_stack_view');
14 base.require('base.color');
15 base.require('base.properties');
16 base.require('base.raf');
17 base.require('base.quad');
18 base.require('base.range');
19 base.require('cc.picture');
20 base.require('cc.render_pass');
21 base.require('cc.tile');
22 base.require('cc.debug_colors');
23 base.require('ui.quad_stack_view');
24 base.require('ui.info_bar');
27 base.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 = 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 ui.InfoBar();
55 this.quadStackView_ = new ui.QuadStackView();
56 this.quadStackView_.addEventListener(
57 'selectionchange', this.onQuadStackViewSelectionChange_.bind(this));
59 var m = 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_ = ui.createSelector(
72 this, 'howToShowTiles',
73 'layerView.howToShowTiles', 'none',
74 createTileRectsSelectorBaseOptions());
75 this.controls_.appendChild(this.tileRectsSelector_);
77 var tileHeatmapText = ui.createSpan({
78 textContent: 'Tile heatmap:'
80 this.controls_.appendChild(tileHeatmapText);
82 var tileHeatmapSelector = 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 = 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 = 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 = 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 = 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 = 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 = 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);
147 get layerTreeImpl() {
148 return this.layerTreeImpl_;
151 set whichTree(whichTree) {
152 this.whichTree_ = whichTree;
155 set isRenderPassQuads(newValue) {
156 this.isRenderPassQuads_ = newValue;
159 set layerTreeImpl(layerTreeImpl) {
160 // FIXME(pdr): We may want to clear pictureAsImageData_ here to save
161 // memory at the cost of performance. Note that
162 // pictureAsImageData_ will be cleared when this is
163 // destructed, but this view might live for several
165 this.layerTreeImpl_ = layerTreeImpl;
166 this.selection = undefined;
169 get showOtherLayers() {
170 return this.showOtherLayers_;
173 set showOtherLayers(show) {
174 this.showOtherLayers_ = show;
175 this.updateContents_();
179 return this.showContents_;
182 set showContents(show) {
183 this.showContents_ = show;
184 this.updateContents_();
187 get showInvalidations() {
188 return this.showInvalidations_;
191 set showInvalidations(show) {
192 this.showInvalidations_ = show;
193 this.updateContents_();
196 get showUnrecordedRegion() {
197 return this.showUnrecordedRegion_;
200 set showUnrecordedRegion(show) {
201 this.showUnrecordedRegion_ = show;
202 this.updateContents_();
205 get showBottlenecks() {
206 return this.showBottlenecks_;
209 set showBottlenecks(show) {
210 this.showBottlenecks_ = show;
211 this.updateContents_();
214 get showLayoutRects() {
215 return this.showLayoutRects_;
218 set showLayoutRects(show) {
219 this.showLayoutRects_ = show;
220 this.updateContents_();
223 get howToShowTiles() {
224 return this.howToShowTiles_;
227 set howToShowTiles(val) {
228 // Make sure val is something we expect.
231 (val === 'coverage') ||
232 !isNaN(parseFloat(val)));
234 this.howToShowTiles_ = val;
235 this.updateContents_();
238 get tileHeatmapType() {
239 return this.tileHeatmapType_;
242 set tileHeatmapType(val) {
243 this.tileHeatmapType_ = val;
244 this.updateContents_();
248 return this.selection_;
251 set selection(selection) {
252 base.setPropertyAndDispatchChange(this, 'selection', selection);
253 this.updateContents_();
256 regenerateContent: function() {
257 this.updateTilesSelector_();
258 this.updateContents_();
261 onQuadStackViewSelectionChange_: function(e) {
262 var selectableQuads = e.quads.filter(function(q) {
263 return q.selectionToSetIfClicked !== undefined;
265 if (selectableQuads.length == 0) {
266 this.selection = undefined;
270 // Sort the quads low to high on stackingGroupId.
271 selectableQuads.sort(function(x, y) {
272 var z = x.stackingGroupId - y.stackingGroupId;
275 return x.selectionToSetIfClicked.specicifity -
276 y.selectionToSetIfClicked.specicifity;
279 // TODO(nduca): Support selecting N things at once.
280 var quadToSelect = selectableQuads[selectableQuads.length - 1];
281 this.selection = quadToSelect.selectionToSetIfClicked;
284 scheduleUpdateContents_: function() {
285 if (this.updateContentsPending_)
287 this.updateContentsPending_ = true;
288 base.requestAnimationFrameInThisFrameIfPossible(
289 this.updateContents_, this);
292 updateContents_: function() {
293 if (!this.layerTreeImpl_)
297 var status = this.computePictureLoadingStatus_();
298 if (!status.picturesComplete)
301 var lthi = this.layerTreeImpl_.layerTreeHostImpl;
302 var lthiInstance = lthi.objectInstance;
303 var worldViewportRect = base.Rect.fromXYWH(
305 lthi.deviceViewportSize.width, lthi.deviceViewportSize.height);
306 this.quadStackView_.deviceRect = worldViewportRect;
307 if (this.isRenderPassQuads_)
308 this.quadStackView_.quads = this.generateRenderPassQuads();
310 this.quadStackView_.quads = this.generateLayerQuads();
312 this.updateInfoBar_(status.messages);
315 updateTilesSelector_: function() {
316 var data = createTileRectsSelectorBaseOptions();
318 if (this.layerTreeImpl_) {
319 // First get all of the scales information from LTHI.
320 var lthi = this.layerTreeImpl_.layerTreeHostImpl;
321 var scaleNames = lthi.getContentsScaleNames();
322 for (var scale in scaleNames) {
324 label: 'Scale ' + scale + ' (' + scaleNames[scale] + ')',
330 // Then create a new selector and replace the old one.
331 var new_selector = ui.createSelector(
332 this, 'howToShowTiles',
333 'layerView.howToShowTiles', 'none',
335 this.controls_.replaceChild(new_selector, this.tileRectsSelector_);
336 this.tileRectsSelector_ = new_selector;
339 computePictureLoadingStatus_: function() {
340 // Figure out if we can draw the quads yet. While we're at it, figure out
341 // if we have any warnings we need to show.
342 var layers = this.layers;
345 picturesComplete: true
347 if (this.showContents) {
348 var hasPendingRasterizeImage = false;
349 var firstPictureError = undefined;
350 var hasMissingLayerRect = false;
351 var hasUnresolvedPictureRef = false;
352 for (var i = 0; i < layers.length; i++) {
353 var layer = layers[i];
354 for (var ir = 0; ir < layer.pictures.length; ++ir) {
355 var picture = layer.pictures[ir];
358 hasUnresolvedPictureRef = true;
361 if (!picture.layerRect) {
362 hasMissingLayerRect = true;
366 var pictureAsImageData = this.pictureAsImageData_[picture.guid];
367 if (!pictureAsImageData) {
368 hasPendingRasterizeImage = true;
369 this.pictureAsImageData_[picture.guid] =
370 cc.PictureAsImageData.Pending(this);
372 {stopIndex: undefined},
373 function(pictureImageData) {
374 var picture_ = pictureImageData.picture;
375 this.pictureAsImageData_[picture_.guid] = pictureImageData;
376 this.scheduleUpdateContents_();
380 if (pictureAsImageData.isPending()) {
381 hasPendingRasterizeImage = true;
384 if (pictureAsImageData.error) {
385 if (!firstPictureError)
386 firstPictureError = pictureAsImageData.error;
391 if (hasPendingRasterizeImage) {
392 status.picturesComplete = false;
394 if (hasUnresolvedPictureRef) {
395 status.messages.push({
396 header: 'Missing picture',
397 details: 'Your trace didnt have pictures for every layer. ' +
398 'Old chrome versions had this problem'});
400 if (hasMissingLayerRect) {
401 status.messages.push({
402 header: 'Missing layer rect',
403 details: 'Your trace may be corrupt or from a very old ' +
404 'Chrome revision.'});
406 if (firstPictureError) {
407 status.messages.push({
408 header: 'Cannot rasterize',
409 details: firstPictureError});
416 get selectedRenderPass() {
418 return this.selection.renderPass_;
421 get selectedLayer() {
422 if (this.selection) {
423 var selectedLayerId = this.selection.associatedLayerId;
424 return this.layerTreeImpl_.findLayerWithId(selectedLayerId);
430 this.layerTreeImpl.layerTreeHostImpl.args.frame.renderPasses;
431 if (!this.showOtherLayers) {
432 var selectedRenderPass = this.selectedRenderPass;
433 if (selectedRenderPass)
434 renderPasses = [selectedRenderPass];
440 var layers = this.layerTreeImpl.renderSurfaceLayerList;
441 if (!this.showOtherLayers) {
442 var selectedLayer = this.selectedLayer;
444 layers = [selectedLayer];
449 appendImageQuads_: function(quads, layer, layerQuad) {
450 // Generate image quads for the layer
451 for (var ir = 0; ir < layer.pictures.length; ++ir) {
452 var picture = layer.pictures[ir];
453 if (!picture.layerRect)
456 var unitRect = picture.layerRect.asUVRectInside(layer.bounds);
457 var iq = layerQuad.projectUnitRect(unitRect);
459 var pictureData = this.pictureAsImageData_[picture.guid];
460 if (this.showContents && pictureData && pictureData.imageData) {
461 iq.imageData = pictureData.imageData;
462 iq.borderColor = 'rgba(0,0,0,0)';
464 iq.imageData = undefined;
467 iq.stackingGroupId = layerQuad.stackingGroupId;
472 appendInvalidationQuads_: function(quads, layer, layerQuad) {
473 // Generate the invalidation rect quads.
474 for (var ir = 0; ir < layer.invalidation.rects.length; ir++) {
475 var rect = layer.invalidation.rects[ir];
476 var unitRect = rect.asUVRectInside(layer.bounds);
477 var iq = layerQuad.projectUnitRect(unitRect);
478 iq.backgroundColor = 'rgba(255, 0, 0, 0.1)';
479 iq.borderColor = 'rgba(255, 0, 0, 1)';
480 iq.stackingGroupId = layerQuad.stackingGroupId;
481 iq.selectionToSetIfClicked = new cc.LayerRectSelection(
482 layer, 'Invalidation rect', rect, rect);
487 appendUnrecordedRegionQuads_: function(quads, layer, layerQuad) {
488 // Generate the unrecorded region quads.
489 for (var ir = 0; ir < layer.unrecordedRegion.rects.length; ir++) {
490 var rect = layer.unrecordedRegion.rects[ir];
491 var unitRect = rect.asUVRectInside(layer.bounds);
492 var iq = layerQuad.projectUnitRect(unitRect);
493 iq.backgroundColor = 'rgba(240, 230, 140, 0.3)';
494 iq.borderColor = 'rgba(240, 230, 140, 1)';
495 iq.stackingGroupId = layerQuad.stackingGroupId;
496 iq.selectionToSetIfClicked = new cc.LayerRectSelection(
497 layer, 'Unrecorded area', rect, rect);
502 appendBottleneckQuads_: function(quads, layer, layerQuad, stackingGroupId) {
503 function processRegion(region, label, borderColor) {
504 var backgroundColor = borderColor.clone();
505 backgroundColor.a = 0.4 * (borderColor.a || 1.0);
507 for (var ir = 0; ir < region.rects.length; ir++) {
508 var rect = region.rects[ir];
509 var unitRect = rect.asUVRectInside(layer.bounds);
510 var iq = layerQuad.projectUnitRect(unitRect);
511 iq.backgroundColor = backgroundColor.toString();
512 iq.borderColor = borderColor.toString();
513 iq.borderWidth = 4.0;
514 iq.stackingGroupId = stackingGroupId;
515 iq.selectionToSetIfClicked = new cc.LayerRectSelection(
516 layer, label, rect, rect);
521 processRegion(layer.touchEventHandlerRegion, 'Touch listener',
522 base.Color.fromString('rgb(228, 226, 27)'));
523 processRegion(layer.wheelEventHandlerRegion, 'Wheel listener',
524 base.Color.fromString('rgb(176, 205, 29)'));
525 processRegion(layer.nonFastScrollableRegion, 'Repaints on scroll',
526 base.Color.fromString('rgb(213, 134, 32)'));
529 appendTileCoverageRectQuads_: function(
530 quads, layer, layerQuad, heatmapType) {
531 if (!layer.tileCoverageRects)
535 for (var ct = 0; ct < layer.tileCoverageRects.length; ++ct) {
536 var tile = layer.tileCoverageRects[ct].tile;
537 if (tile !== undefined)
541 var lthi = this.layerTreeImpl_.layerTreeHostImpl;
543 this.getMinMaxForHeatmap_(lthi.tiles, heatmapType);
545 this.computeHeatmapColors_(tiles, minMax, heatmapType);
548 for (var ct = 0; ct < layer.tileCoverageRects.length; ++ct) {
549 var rect = layer.tileCoverageRects[ct].geometryRect;
550 rect = rect.scale(1.0 / layer.geometryContentsScale);
552 var tile = layer.tileCoverageRects[ct].tile;
554 var unitRect = rect.asUVRectInside(layer.bounds);
555 var quad = layerQuad.projectUnitRect(unitRect);
557 quad.backgroundColor = 'rgba(0, 0, 0, 0)';
558 quad.stackingGroupId = layerQuad.stackingGroupId;
559 var type = cc.tileTypes.missing;
561 type = tile.getTypeForLayer(layer);
562 quad.backgroundColor = heatmapColors[heatIndex];
566 quad.borderColor = cc.tileBorder[type].color;
567 quad.borderWidth = cc.tileBorder[type].width;
570 label = 'coverageRect';
572 label = 'checkerboard coverageRect';
573 quad.selectionToSetIfClicked = new cc.LayerRectSelection(
574 layer, label, rect, layer.tileCoverageRects[ct]);
580 appendLayoutRectQuads_: function(quads, layer, layerQuad) {
581 if (!layer.layoutRects) {
585 for (var ct = 0; ct < layer.layoutRects.length; ++ct) {
586 var rect = layer.layoutRects[ct].geometryRect;
587 rect = rect.scale(1.0 / layer.geometryContentsScale);
589 var unitRect = rect.asUVRectInside(layer.bounds);
590 var quad = layerQuad.projectUnitRect(unitRect);
592 quad.backgroundColor = 'rgba(0, 0, 0, 0)';
593 quad.stackingGroupId = layerQuad.stackingGroupId;
595 quad.borderColor = 'rgba(0, 0, 200, 0.7)';
596 quad.borderWidth = 2;
598 label = 'Layout rect';
599 quad.selectionToSetIfClicked = new cc.LayerRectSelection(
606 getValueForHeatmap_: function(tile, heatmapType) {
607 if (heatmapType == TILE_HEATMAP_TYPE.SCHEDULED_PRIORITY) {
608 return tile.scheduledPriority == 0 ?
610 tile.scheduledPriority;
611 } else if (heatmapType == TILE_HEATMAP_TYPE.DISTANCE_TO_VISIBLE) {
612 return tile.distanceToVisible;
613 } else if (heatmapType == TILE_HEATMAP_TYPE.TIME_TO_VISIBLE) {
614 return Math.min(5, tile.timeToVisible);
615 } else if (heatmapType == TILE_HEATMAP_TYPE.USING_GPU_MEMORY) {
616 if (tile.isSolidColor)
618 return tile.isUsingGpuMemory ? 0 : 1;
622 getMinMaxForHeatmap_: function(tiles, heatmapType) {
623 var range = new base.Range();
624 if (heatmapType == TILE_HEATMAP_TYPE.USING_GPU_MEMORY) {
630 for (var i = 0; i < tiles.length; ++i) {
631 var value = this.getValueForHeatmap_(tiles[i], heatmapType);
632 if (value == undefined)
634 range.addValue(value);
636 if (range.range == 0)
641 computeHeatmapColors_: function(tiles, minMax, heatmapType) {
642 var min = minMax.min;
643 var max = minMax.max;
645 var color = function(value) {
646 var hue = 120 * (1 - (value - min) / (max - min));
649 return 'hsla(' + hue + ', 100%, 50%, 0.5)';
653 for (var i = 0; i < tiles.length; ++i) {
655 var value = this.getValueForHeatmap_(tile, heatmapType);
656 if (value !== undefined)
657 values.push(color(value));
659 values.push(undefined);
665 appendTilesWithScaleQuads_: function(
666 quads, layer, layerQuad, scale, heatmapType) {
667 var lthi = this.layerTreeImpl_.layerTreeHostImpl;
670 for (var i = 0; i < lthi.tiles.length; ++i) {
671 var tile = lthi.tiles[i];
673 if (Math.abs(tile.contentsScale - scale) > 1e-6)
676 // TODO(vmpstr): Make the stiching of tiles and layers a part of
677 // tile construction (issue 346)
678 if (layer.layerId != tile.layerId)
685 this.getMinMaxForHeatmap_(lthi.tiles, heatmapType);
687 this.computeHeatmapColors_(tiles, minMax, heatmapType);
689 for (var i = 0; i < tiles.length; ++i) {
691 var rect = tile.layerRect;
694 var unitRect = rect.asUVRectInside(layer.bounds);
695 var quad = layerQuad.projectUnitRect(unitRect);
697 quad.backgroundColor = 'rgba(0, 0, 0, 0)';
698 quad.stackingGroupId = layerQuad.stackingGroupId;
700 var type = tile.getTypeForLayer(layer);
701 quad.borderColor = cc.tileBorder[type].color;
702 quad.borderWidth = cc.tileBorder[type].width;
704 quad.backgroundColor = heatmapColors[i];
705 quad.selectionToSetIfClicked = new cc.TileSelection(tile);
710 appendSelectionQuads_: function(quads, layer, layerQuad) {
711 var selection = this.selection;
712 var rect = selection.layerRect;
716 var unitRect = rect.asUVRectInside(layer.bounds);
717 var quad = layerQuad.projectUnitRect(unitRect);
719 var colorId = tracing.getStringColorId(selection.title);
720 colorId += tracing.getColorPaletteHighlightIdBoost();
722 var color = base.Color.fromString(tracing.getColorPalette()[colorId]);
724 var quadForDrawing = quad.clone();
725 quadForDrawing.backgroundColor = color.withAlpha(0.5).toString();
726 quadForDrawing.borderColor = color.withAlpha(1.0).darken().toString();
727 quadForDrawing.stackingGroupId = layerQuad.stackingGroupId;
728 quads.push(quadForDrawing);
731 generateRenderPassQuads: function() {
732 if (!this.layerTreeImpl.layerTreeHostImpl.args.frame)
734 var renderPasses = this.renderPasses;
739 for (var i = 0; i < renderPasses.length; ++i) {
740 var quadList = renderPasses[i].quadList;
741 for (var j = 0; j < quadList.length; ++j) {
742 var drawQuad = quadList[j];
743 var quad = drawQuad.rectAsTargetSpaceQuad.clone();
744 quad.borderColor = 'rgb(170, 204, 238)';
745 quad.borderWidth = 2;
746 quad.stackingGroupId = i;
753 generateLayerQuads: function() {
754 this.updateContentsPending_ = false;
756 // Generate the quads for the view.
757 var layers = this.layers;
759 var nextStackingGroupId = 0;
760 var alreadyVisitedLayerIds = {};
762 for (var i = 1; i <= layers.length; i++) {
763 // Generate quads back-to-front.
764 var layer = layers[layers.length - i];
765 alreadyVisitedLayerIds[layer.layerId] = true;
766 if (layer.objectInstance.name == 'cc::NinePatchLayerImpl')
769 var layerQuad = layer.layerQuad.clone();
770 layerQuad.borderColor = 'rgba(0,0,0,0.75)';
771 layerQuad.stackingGroupId = nextStackingGroupId++;
772 layerQuad.selectionToSetIfClicked = new cc.LayerSelection(layer);
773 layerQuad.layer = layer;
774 if (this.showOtherLayers && this.selectedLayer == layer)
775 layerQuad.upperBorderColor = 'rgb(156,189,45)';
777 this.appendImageQuads_(quads, layer, layerQuad);
778 quads.push(layerQuad);
781 if (this.showInvalidations)
782 this.appendInvalidationQuads_(quads, layer, layerQuad);
783 if (this.showUnrecordedRegion)
784 this.appendUnrecordedRegionQuads_(quads, layer, layerQuad);
785 if (this.showBottlenecks)
786 this.appendBottleneckQuads_(quads, layer, layerQuad,
787 layerQuad.stackingGroupId);
788 if (this.showLayoutRects)
789 this.appendLayoutRectQuads_(quads, layer, layerQuad);
791 if (this.howToShowTiles === 'coverage') {
792 this.appendTileCoverageRectQuads_(
793 quads, layer, layerQuad, this.tileHeatmapType);
794 } else if (this.howToShowTiles !== 'none') {
795 this.appendTilesWithScaleQuads_(
796 quads, layer, layerQuad,
797 this.howToShowTiles, this.tileHeatmapType);
800 if (this.selectedLayer === layer)
801 this.appendSelectionQuads_(quads, layer, layerQuad);
804 this.layerTreeImpl.iterLayers(function(layer, depth, isMask, isReplica) {
805 if (!this.showOtherLayers && this.selectedLayer != layer)
807 if (alreadyVisitedLayerIds[layer.layerId])
809 var layerQuad = layer.layerQuad;
810 var stackingGroupId = nextStackingGroupId++;
811 if (this.showBottlenecks)
812 this.appendBottleneckQuads_(quads, layer, layerQuad, stackingGroupId);
818 updateInfoBar_: function(infoBarMessages) {
819 if (infoBarMessages.length) {
820 this.infoBar_.removeAllButtons();
821 this.infoBar_.message = 'Some problems were encountered...';
822 this.infoBar_.addButton('More info...', function(e) {
823 var overlay = new ui.Overlay();
824 overlay.textContent = '';
825 infoBarMessages.forEach(function(message) {
826 var title = document.createElement('h3');
827 title.textContent = message.header;
829 var details = document.createElement('div');
830 details.textContent = message.details;
832 overlay.appendChild(title);
833 overlay.appendChild(details);
835 overlay.visible = true;
840 this.infoBar_.visible = true;
842 this.infoBar_.removeAllButtons();
843 this.infoBar_.message = '';
844 this.infoBar_.visible = false;
850 LayerTreeQuadStackView: LayerTreeQuadStackView