1/*
2 * Copyright 2014 The Chromium Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7/**
8 * @constructor
9 * @extends {WebInspector.VBox}
10 */
11WebInspector.TimelineLayersView = function()
12{
13    WebInspector.VBox.call(this);
14
15    this._paintTiles = [];
16    this._layers3DView = new WebInspector.Layers3DView();
17    this._layers3DView.addEventListener(WebInspector.Layers3DView.Events.ObjectSelected, this._onObjectSelected, this);
18    this._layers3DView.addEventListener(WebInspector.Layers3DView.Events.ObjectHovered, this._onObjectHovered, this);
19    this._layers3DView.addEventListener(WebInspector.Layers3DView.Events.JumpToPaintEventRequested, this._jumpToPaintEvent, this);
20    this._layers3DView.show(this.element);
21}
22
23WebInspector.TimelineLayersView.prototype = {
24    /**
25     * @param {!WebInspector.DeferredLayerTree} deferredLayerTree
26     * @param {?Array.<!WebInspector.LayerPaintEvent>} paints
27     */
28    showLayerTree: function(deferredLayerTree, paints)
29    {
30        this._disposeTiles();
31        this._deferredLayerTree = deferredLayerTree;
32        this._paints = paints;
33        if (this.isShowing())
34            this._update();
35        else
36            this._updateWhenVisible = true;
37    },
38
39    wasShown: function()
40    {
41        if (this._updateWhenVisible) {
42            this._updateWhenVisible = false;
43            this._update();
44        }
45    },
46
47    /**
48     * @param {!WebInspector.TimelineModel} model
49     * @param {!WebInspector.TimelineModeViewDelegate} delegate
50     */
51    setTimelineModelAndDelegate: function(model, delegate)
52    {
53        this._model = model;
54        this._delegate = delegate;
55    },
56
57    /**
58     * @param {!WebInspector.Event} event
59     */
60    _jumpToPaintEvent: function(event)
61    {
62        var traceEvent = event.data;
63        var eventRecord;
64
65        /**
66         * @param {!WebInspector.TimelineModel.Record} record
67         * @return {boolean}
68         */
69        function findRecordWithEvent(record)
70        {
71            if (record.traceEvent() === traceEvent) {
72                eventRecord = record;
73                return true;
74            }
75            return false;
76        }
77
78        this._model.forAllRecords(findRecordWithEvent);
79        if (eventRecord) {
80            var selection = WebInspector.TimelineSelection.fromRecord(eventRecord);
81            this._delegate.select(selection);
82        }
83    },
84
85    _update: function()
86    {
87        var layerTree;
88
89        this._target = this._deferredLayerTree.target();
90        var originalTiles = this._paintTiles;
91        var tilesReadyBarrier = new CallbackBarrier();
92        this._deferredLayerTree.resolve(tilesReadyBarrier.createCallback(onLayersReady));
93        for (var i = 0; this._paints && i < this._paints.length; ++i)
94            this._paints[i].loadPicture(tilesReadyBarrier.createCallback(onSnapshotLoaded.bind(this, this._paints[i])));
95        tilesReadyBarrier.callWhenDone(onLayersAndTilesReady.bind(this));
96
97        /**
98         * @param {!WebInspector.LayerTreeBase} resolvedLayerTree
99         */
100        function onLayersReady(resolvedLayerTree)
101        {
102            layerTree = resolvedLayerTree;
103        }
104
105        /**
106         * @param {!WebInspector.LayerPaintEvent} paintEvent
107         * @param {?Array.<number>} rect
108         * @param {?WebInspector.PaintProfilerSnapshot} snapshot
109         * @this {WebInspector.TimelineLayersView}
110         */
111        function onSnapshotLoaded(paintEvent, rect, snapshot)
112        {
113            if (!rect || !snapshot)
114                return;
115            // We're too late and there's a new generation of tiles being loaded.
116            if (originalTiles !== this._paintTiles) {
117                snapshot.dispose();
118                return;
119            }
120            this._paintTiles.push({layerId: paintEvent.layerId(), rect: rect, snapshot: snapshot, traceEvent: paintEvent.event()});
121        }
122
123        /**
124         * @this {WebInspector.TimelineLayersView}
125         */
126        function onLayersAndTilesReady()
127        {
128            this._layers3DView.setLayerTree(layerTree);
129            this._layers3DView.setTiles(this._paintTiles);
130        }
131    },
132
133    /**
134     * @param {?WebInspector.Layers3DView.ActiveObject} activeObject
135     */
136    _selectObject: function(activeObject)
137    {
138        var layer = activeObject && activeObject.layer;
139        if (this._currentlySelectedLayer === activeObject)
140            return;
141        this._currentlySelectedLayer = activeObject;
142        this._toggleNodeHighlight(layer ? layer.nodeForSelfOrAncestor() : null);
143        this._layers3DView.selectObject(activeObject);
144    },
145
146    /**
147     * @param {?WebInspector.Layers3DView.ActiveObject} activeObject
148     */
149    _hoverObject: function(activeObject)
150    {
151        var layer = activeObject && activeObject.layer;
152        if (this._currentlyHoveredLayer === activeObject)
153            return;
154        this._currentlyHoveredLayer = activeObject;
155        this._toggleNodeHighlight(layer ? layer.nodeForSelfOrAncestor() : null);
156        this._layers3DView.hoverObject(activeObject);
157    },
158
159    /**
160     * @param {?WebInspector.DOMNode} node
161     */
162    _toggleNodeHighlight: function(node)
163    {
164        if (node) {
165            node.highlightForTwoSeconds();
166            return;
167        }
168        if (this._target)
169            this._target.domModel.hideDOMNodeHighlight();
170
171    },
172
173    /**
174     * @param {!WebInspector.Event} event
175     */
176    _onObjectSelected: function(event)
177    {
178        var activeObject = /** @type {!WebInspector.Layers3DView.ActiveObject} */ (event.data);
179        this._selectObject(activeObject);
180    },
181
182    /**
183     * @param {!WebInspector.Event} event
184     */
185    _onObjectHovered: function(event)
186    {
187        var activeObject = /** @type {!WebInspector.Layers3DView.ActiveObject} */ (event.data);
188        this._hoverObject(activeObject);
189    },
190
191    _disposeTiles: function()
192    {
193        for (var i = 0; i < this._paintTiles.length; ++i)
194            this._paintTiles[i].snapshot.dispose();
195        this._paintTiles = [];
196    },
197
198    __proto__: WebInspector.VBox.prototype
199}
200