Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / src / cc / layer_tree_quad_stack_view.js
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.
4
5 'use strict';
6
7 /**
8  * @fileoverview Graphical view of  LayerTreeImpl, with controls for
9  * type of layer content shown and info bar for content-loading warnings.
10  */
11
12 base.requireStylesheet('cc.layer_tree_quad_stack_view');
13
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');
25
26
27 base.exportTo('cc', function() {
28
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;
35
36   function createTileRectsSelectorBaseOptions() {
37     return [{label: 'None', value: 'none'},
38             {label: 'Coverage Rects', value: 'coverage'}];
39   }
40
41   /**
42    * @constructor
43    */
44   var LayerTreeQuadStackView = ui.define('layer-tree-quad-stack-view');
45
46   LayerTreeQuadStackView.prototype = {
47     __proto__: HTMLDivElement.prototype,
48
49     decorate: function() {
50       this.isRenderPassQuads_ = false;
51       this.pictureAsImageData_ = {}; // Maps picture.guid to PictureAsImageData.
52       this.messages_ = [];
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));
58
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));
66
67       this.appendChild(this.controls_);
68       this.appendChild(this.infoBar_);
69       this.appendChild(this.quadStackView_);
70
71       this.tileRectsSelector_ = ui.createSelector(
72           this, 'howToShowTiles',
73           'layerView.howToShowTiles', 'none',
74           createTileRectsSelectorBaseOptions());
75       this.controls_.appendChild(this.tileRectsSelector_);
76
77       var tileHeatmapText = ui.createSpan({
78         textContent: 'Tile heatmap:'
79       });
80       this.controls_.appendChild(tileHeatmapText);
81
82       var tileHeatmapSelector = ui.createSelector(
83           this, 'tileHeatmapType',
84           'layerView.tileHeatmapType', TILE_HEATMAP_TYPE.NONE,
85           [{label: '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}
95           ]);
96       this.controls_.appendChild(tileHeatmapSelector);
97
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);
105
106       var showInvalidationsCheckbox = ui.createCheckBox(
107           this, 'showInvalidations',
108           'layerView.showInvalidations', true,
109           'Invalidations');
110       showInvalidationsCheckbox.title =
111           'When checked, compositing invalidations are highlighted in red';
112       this.controls_.appendChild(showInvalidationsCheckbox);
113
114       var showUnrecordedRegionCheckbox = ui.createCheckBox(
115           this, 'showUnrecordedRegion',
116           'layerView.showUnrecordedRegion', true,
117           'Unrecorded area');
118       showUnrecordedRegionCheckbox.title =
119           'When checked, unrecorded areas are highlighted in yellow';
120       this.controls_.appendChild(showUnrecordedRegionCheckbox);
121
122       var showBottlenecksCheckbox = ui.createCheckBox(
123           this, 'showBottlenecks',
124           'layerView.showBottlenecks', true,
125           'Bottlenecks');
126       showBottlenecksCheckbox.title =
127           'When checked, scroll bottlenecks are highlighted';
128       this.controls_.appendChild(showBottlenecksCheckbox);
129
130       var showLayoutRectsCheckbox = ui.createCheckBox(
131           this, 'showLayoutRects',
132           'layerView.showLayoutRects', false,
133           'Layout rects');
134       showLayoutRectsCheckbox.title =
135           'When checked, shows rects for regions where layout happened';
136       this.controls_.appendChild(showLayoutRectsCheckbox);
137
138       var showContentsCheckbox = ui.createCheckBox(
139           this, 'showContents',
140           'layerView.showContents', true,
141           'Contents');
142       showContentsCheckbox.title =
143           'When checked, show the rendered contents inside the layer outlines';
144       this.controls_.appendChild(showContentsCheckbox);
145     },
146
147     get layerTreeImpl() {
148       return this.layerTreeImpl_;
149     },
150
151     set whichTree(whichTree) {
152       this.whichTree_ = whichTree;
153     },
154
155     set isRenderPassQuads(newValue) {
156       this.isRenderPassQuads_ = newValue;
157     },
158
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
164       //             layerTreeImpls.
165       this.layerTreeImpl_ = layerTreeImpl;
166       this.selection = undefined;
167     },
168
169     get showOtherLayers() {
170       return this.showOtherLayers_;
171     },
172
173     set showOtherLayers(show) {
174       this.showOtherLayers_ = show;
175       this.updateContents_();
176     },
177
178     get showContents() {
179       return this.showContents_;
180     },
181
182     set showContents(show) {
183       this.showContents_ = show;
184       this.updateContents_();
185     },
186
187     get showInvalidations() {
188       return this.showInvalidations_;
189     },
190
191     set showInvalidations(show) {
192       this.showInvalidations_ = show;
193       this.updateContents_();
194     },
195
196     get showUnrecordedRegion() {
197       return this.showUnrecordedRegion_;
198     },
199
200     set showUnrecordedRegion(show) {
201       this.showUnrecordedRegion_ = show;
202       this.updateContents_();
203     },
204
205     get showBottlenecks() {
206       return this.showBottlenecks_;
207     },
208
209     set showBottlenecks(show) {
210       this.showBottlenecks_ = show;
211       this.updateContents_();
212     },
213
214     get showLayoutRects() {
215       return this.showLayoutRects_;
216     },
217
218     set showLayoutRects(show) {
219       this.showLayoutRects_ = show;
220       this.updateContents_();
221     },
222
223     get howToShowTiles() {
224       return this.howToShowTiles_;
225     },
226
227     set howToShowTiles(val) {
228       // Make sure val is something we expect.
229       console.assert(
230           (val === 'none') ||
231           (val === 'coverage') ||
232           !isNaN(parseFloat(val)));
233
234       this.howToShowTiles_ = val;
235       this.updateContents_();
236     },
237
238     get tileHeatmapType() {
239       return this.tileHeatmapType_;
240     },
241
242     set tileHeatmapType(val) {
243       this.tileHeatmapType_ = val;
244       this.updateContents_();
245     },
246
247     get selection() {
248       return this.selection_;
249     },
250
251     set selection(selection) {
252       base.setPropertyAndDispatchChange(this, 'selection', selection);
253       this.updateContents_();
254     },
255
256     regenerateContent: function() {
257       this.updateTilesSelector_();
258       this.updateContents_();
259     },
260
261     onQuadStackViewSelectionChange_: function(e) {
262       var selectableQuads = e.quads.filter(function(q) {
263         return q.selectionToSetIfClicked !== undefined;
264       });
265       if (selectableQuads.length == 0) {
266         this.selection = undefined;
267         return;
268       }
269
270       // Sort the quads low to high on stackingGroupId.
271       selectableQuads.sort(function(x, y) {
272         var z = x.stackingGroupId - y.stackingGroupId;
273         if (z != 0)
274           return z;
275         return x.selectionToSetIfClicked.specicifity -
276             y.selectionToSetIfClicked.specicifity;
277       });
278
279       // TODO(nduca): Support selecting N things at once.
280       var quadToSelect = selectableQuads[selectableQuads.length - 1];
281       this.selection = quadToSelect.selectionToSetIfClicked;
282     },
283
284     scheduleUpdateContents_: function() {
285       if (this.updateContentsPending_)
286         return;
287       this.updateContentsPending_ = true;
288       base.requestAnimationFrameInThisFrameIfPossible(
289           this.updateContents_, this);
290     },
291
292     updateContents_: function() {
293       if (!this.layerTreeImpl_)
294         return;
295
296
297       var status = this.computePictureLoadingStatus_();
298       if (!status.picturesComplete)
299         return;
300
301       var lthi = this.layerTreeImpl_.layerTreeHostImpl;
302       var lthiInstance = lthi.objectInstance;
303       var worldViewportRect = base.Rect.fromXYWH(
304           0, 0,
305           lthi.deviceViewportSize.width, lthi.deviceViewportSize.height);
306       this.quadStackView_.deviceRect = worldViewportRect;
307       if (this.isRenderPassQuads_)
308         this.quadStackView_.quads = this.generateRenderPassQuads();
309       else
310         this.quadStackView_.quads = this.generateLayerQuads();
311
312       this.updateInfoBar_(status.messages);
313     },
314
315     updateTilesSelector_: function() {
316       var data = createTileRectsSelectorBaseOptions();
317
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) {
323           data.push({
324             label: 'Scale ' + scale + ' (' + scaleNames[scale] + ')',
325             value: scale
326           });
327         }
328       }
329
330       // Then create a new selector and replace the old one.
331       var new_selector = ui.createSelector(
332           this, 'howToShowTiles',
333           'layerView.howToShowTiles', 'none',
334           data);
335       this.controls_.replaceChild(new_selector, this.tileRectsSelector_);
336       this.tileRectsSelector_ = new_selector;
337     },
338
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;
343       var status = {
344         messages: [],
345         picturesComplete: true
346       };
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];
356
357             if (picture.idRef) {
358               hasUnresolvedPictureRef = true;
359               continue;
360             }
361             if (!picture.layerRect) {
362               hasMissingLayerRect = true;
363               continue;
364             }
365
366             var pictureAsImageData = this.pictureAsImageData_[picture.guid];
367             if (!pictureAsImageData) {
368               hasPendingRasterizeImage = true;
369               this.pictureAsImageData_[picture.guid] =
370                   cc.PictureAsImageData.Pending(this);
371               picture.rasterize(
372                   {stopIndex: undefined},
373                   function(pictureImageData) {
374                     var picture_ = pictureImageData.picture;
375                     this.pictureAsImageData_[picture_.guid] = pictureImageData;
376                     this.scheduleUpdateContents_();
377                   }.bind(this));
378               continue;
379             }
380             if (pictureAsImageData.isPending()) {
381               hasPendingRasterizeImage = true;
382               continue;
383             }
384             if (pictureAsImageData.error) {
385               if (!firstPictureError)
386                 firstPictureError = pictureAsImageData.error;
387               break;
388             }
389           }
390         }
391         if (hasPendingRasterizeImage) {
392           status.picturesComplete = false;
393         } else {
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'});
399           }
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.'});
405           }
406           if (firstPictureError) {
407             status.messages.push({
408               header: 'Cannot rasterize',
409               details: firstPictureError});
410           }
411         }
412       }
413       return status;
414     },
415
416     get selectedRenderPass() {
417       if (this.selection)
418         return this.selection.renderPass_;
419     },
420
421     get selectedLayer() {
422       if (this.selection) {
423         var selectedLayerId = this.selection.associatedLayerId;
424         return this.layerTreeImpl_.findLayerWithId(selectedLayerId);
425       }
426     },
427
428     get renderPasses() {
429       var renderPasses =
430           this.layerTreeImpl.layerTreeHostImpl.args.frame.renderPasses;
431       if (!this.showOtherLayers) {
432         var selectedRenderPass = this.selectedRenderPass;
433         if (selectedRenderPass)
434           renderPasses = [selectedRenderPass];
435       }
436       return renderPasses;
437     },
438
439     get layers() {
440       var layers = this.layerTreeImpl.renderSurfaceLayerList;
441       if (!this.showOtherLayers) {
442         var selectedLayer = this.selectedLayer;
443         if (selectedLayer)
444           layers = [selectedLayer];
445       }
446       return layers;
447     },
448
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)
454           continue;
455
456         var unitRect = picture.layerRect.asUVRectInside(layer.bounds);
457         var iq = layerQuad.projectUnitRect(unitRect);
458
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)';
463         } else {
464           iq.imageData = undefined;
465         }
466
467         iq.stackingGroupId = layerQuad.stackingGroupId;
468         quads.push(iq);
469       }
470     },
471
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);
483         quads.push(iq);
484       }
485     },
486
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);
498         quads.push(iq);
499       }
500     },
501
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);
506
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);
517           quads.push(iq);
518         }
519       }
520
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)'));
527     },
528
529     appendTileCoverageRectQuads_: function(
530         quads, layer, layerQuad, heatmapType) {
531       if (!layer.tileCoverageRects)
532         return;
533
534       var tiles = [];
535       for (var ct = 0; ct < layer.tileCoverageRects.length; ++ct) {
536         var tile = layer.tileCoverageRects[ct].tile;
537         if (tile !== undefined)
538           tiles.push(tile);
539       }
540
541       var lthi = this.layerTreeImpl_.layerTreeHostImpl;
542       var minMax =
543           this.getMinMaxForHeatmap_(lthi.tiles, heatmapType);
544       var heatmapColors =
545           this.computeHeatmapColors_(tiles, minMax, heatmapType);
546       var heatIndex = 0;
547
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);
551
552         var tile = layer.tileCoverageRects[ct].tile;
553
554         var unitRect = rect.asUVRectInside(layer.bounds);
555         var quad = layerQuad.projectUnitRect(unitRect);
556
557         quad.backgroundColor = 'rgba(0, 0, 0, 0)';
558         quad.stackingGroupId = layerQuad.stackingGroupId;
559         var type = cc.tileTypes.missing;
560         if (tile) {
561           type = tile.getTypeForLayer(layer);
562           quad.backgroundColor = heatmapColors[heatIndex];
563           ++heatIndex;
564         }
565
566         quad.borderColor = cc.tileBorder[type].color;
567         quad.borderWidth = cc.tileBorder[type].width;
568         var label;
569         if (tile)
570           label = 'coverageRect';
571         else
572           label = 'checkerboard coverageRect';
573         quad.selectionToSetIfClicked = new cc.LayerRectSelection(
574             layer, label, rect, layer.tileCoverageRects[ct]);
575
576         quads.push(quad);
577       }
578     },
579
580     appendLayoutRectQuads_: function(quads, layer, layerQuad) {
581       if (!layer.layoutRects) {
582         return;
583       }
584
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);
588
589         var unitRect = rect.asUVRectInside(layer.bounds);
590         var quad = layerQuad.projectUnitRect(unitRect);
591
592         quad.backgroundColor = 'rgba(0, 0, 0, 0)';
593         quad.stackingGroupId = layerQuad.stackingGroupId;
594
595         quad.borderColor = 'rgba(0, 0, 200, 0.7)';
596         quad.borderWidth = 2;
597         var label;
598         label = 'Layout rect';
599         quad.selectionToSetIfClicked = new cc.LayerRectSelection(
600             layer, label, rect);
601
602         quads.push(quad);
603       }
604     },
605
606     getValueForHeatmap_: function(tile, heatmapType) {
607       if (heatmapType == TILE_HEATMAP_TYPE.SCHEDULED_PRIORITY) {
608         return tile.scheduledPriority == 0 ?
609             undefined :
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)
617           return 0.5;
618         return tile.isUsingGpuMemory ? 0 : 1;
619       }
620     },
621
622     getMinMaxForHeatmap_: function(tiles, heatmapType) {
623       var range = new base.Range();
624       if (heatmapType == TILE_HEATMAP_TYPE.USING_GPU_MEMORY) {
625         range.addValue(0);
626         range.addValue(1);
627         return range;
628       }
629
630       for (var i = 0; i < tiles.length; ++i) {
631         var value = this.getValueForHeatmap_(tiles[i], heatmapType);
632         if (value == undefined)
633           continue;
634         range.addValue(value);
635       }
636       if (range.range == 0)
637         range.addValue(1);
638       return range;
639     },
640
641     computeHeatmapColors_: function(tiles, minMax, heatmapType) {
642       var min = minMax.min;
643       var max = minMax.max;
644
645       var color = function(value) {
646         var hue = 120 * (1 - (value - min) / (max - min));
647         if (hue < 0)
648           hue = 0;
649         return 'hsla(' + hue + ', 100%, 50%, 0.5)';
650       };
651
652       var values = [];
653       for (var i = 0; i < tiles.length; ++i) {
654         var tile = tiles[i];
655         var value = this.getValueForHeatmap_(tile, heatmapType);
656         if (value !== undefined)
657           values.push(color(value));
658         else
659           values.push(undefined);
660       }
661
662       return values;
663     },
664
665     appendTilesWithScaleQuads_: function(
666         quads, layer, layerQuad, scale, heatmapType) {
667       var lthi = this.layerTreeImpl_.layerTreeHostImpl;
668
669       var tiles = [];
670       for (var i = 0; i < lthi.tiles.length; ++i) {
671         var tile = lthi.tiles[i];
672
673         if (Math.abs(tile.contentsScale - scale) > 1e-6)
674           continue;
675
676         // TODO(vmpstr): Make the stiching of tiles and layers a part of
677         // tile construction (issue 346)
678         if (layer.layerId != tile.layerId)
679           continue;
680
681         tiles.push(tile);
682       }
683
684       var minMax =
685           this.getMinMaxForHeatmap_(lthi.tiles, heatmapType);
686       var heatmapColors =
687           this.computeHeatmapColors_(tiles, minMax, heatmapType);
688
689       for (var i = 0; i < tiles.length; ++i) {
690         var tile = tiles[i];
691         var rect = tile.layerRect;
692         if (!tile.layerRect)
693           continue;
694         var unitRect = rect.asUVRectInside(layer.bounds);
695         var quad = layerQuad.projectUnitRect(unitRect);
696
697         quad.backgroundColor = 'rgba(0, 0, 0, 0)';
698         quad.stackingGroupId = layerQuad.stackingGroupId;
699
700         var type = tile.getTypeForLayer(layer);
701         quad.borderColor = cc.tileBorder[type].color;
702         quad.borderWidth = cc.tileBorder[type].width;
703
704         quad.backgroundColor = heatmapColors[i];
705         quad.selectionToSetIfClicked = new cc.TileSelection(tile);
706         quads.push(quad);
707       }
708     },
709
710     appendSelectionQuads_: function(quads, layer, layerQuad) {
711       var selection = this.selection;
712       var rect = selection.layerRect;
713       if (!rect)
714         return [];
715
716       var unitRect = rect.asUVRectInside(layer.bounds);
717       var quad = layerQuad.projectUnitRect(unitRect);
718
719       var colorId = tracing.getStringColorId(selection.title);
720       colorId += tracing.getColorPaletteHighlightIdBoost();
721
722       var color = base.Color.fromString(tracing.getColorPalette()[colorId]);
723
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);
729     },
730
731     generateRenderPassQuads: function() {
732       if (!this.layerTreeImpl.layerTreeHostImpl.args.frame)
733         return [];
734       var renderPasses = this.renderPasses;
735       if (!renderPasses)
736         return [];
737
738       var quads = [];
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;
747           quads.push(quad);
748         }
749       }
750       return quads;
751     },
752
753     generateLayerQuads: function() {
754       this.updateContentsPending_ = false;
755
756       // Generate the quads for the view.
757       var layers = this.layers;
758       var quads = [];
759       var nextStackingGroupId = 0;
760       var alreadyVisitedLayerIds = {};
761
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')
767           continue;
768
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)';
776
777         this.appendImageQuads_(quads, layer, layerQuad);
778         quads.push(layerQuad);
779
780
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);
790
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);
798         }
799
800         if (this.selectedLayer === layer)
801           this.appendSelectionQuads_(quads, layer, layerQuad);
802       }
803
804       this.layerTreeImpl.iterLayers(function(layer, depth, isMask, isReplica) {
805         if (!this.showOtherLayers && this.selectedLayer != layer)
806           return;
807         if (alreadyVisitedLayerIds[layer.layerId])
808           return;
809         var layerQuad = layer.layerQuad;
810         var stackingGroupId = nextStackingGroupId++;
811         if (this.showBottlenecks)
812           this.appendBottleneckQuads_(quads, layer, layerQuad, stackingGroupId);
813       }, this);
814
815       return quads;
816     },
817
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;
828
829             var details = document.createElement('div');
830             details.textContent = message.details;
831
832             overlay.appendChild(title);
833             overlay.appendChild(details);
834           });
835           overlay.visible = true;
836
837           e.stopPropagation();
838           return false;
839         });
840         this.infoBar_.visible = true;
841       } else {
842         this.infoBar_.removeAllButtons();
843         this.infoBar_.message = '';
844         this.infoBar_.visible = false;
845       }
846     }
847   };
848
849   return {
850     LayerTreeQuadStackView: LayerTreeQuadStackView
851   };
852 });