Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / timeline / TimelineOverviewPane.js
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /**
32  * @constructor
33  * @extends {WebInspector.VBox}
34  * @param {!WebInspector.TimelineModel} model
35  * @param {!WebInspector.TimelineUIUtils} uiUtils
36  */
37 WebInspector.TimelineOverviewPane = function(model, uiUtils)
38 {
39     WebInspector.VBox.call(this);
40     this._uiUtils = uiUtils;
41     this.element.id = "timeline-overview-pane";
42
43     this._model = model;
44     this._overviewCalculator = new WebInspector.TimelineOverviewCalculator();
45
46     this._overviewGrid = new WebInspector.OverviewGrid("timeline");
47     this.element.appendChild(this._overviewGrid.element);
48
49     model.addEventListener(WebInspector.TimelineModel.Events.RecordsCleared, this._reset, this);
50     this._overviewGrid.addEventListener(WebInspector.OverviewGrid.Events.WindowChanged, this._onWindowChanged, this);
51     this._overviewControls = [];
52 }
53
54 WebInspector.TimelineOverviewPane.Events = {
55     WindowChanged: "WindowChanged"
56 };
57
58 WebInspector.TimelineOverviewPane.prototype = {
59     wasShown: function()
60     {
61         this.update();
62     },
63
64     onResize: function()
65     {
66         this.update();
67     },
68
69     /**
70      * @param {!Array.<!WebInspector.TimelineOverview>} overviewControls
71      */
72     setOverviewControls: function(overviewControls)
73     {
74         for (var i = 0; i < this._overviewControls.length; ++i) {
75             var overviewControl = this._overviewControls[i];
76             overviewControl.detach();
77             overviewControl.dispose();
78         }
79
80         for (var i = 0; i < overviewControls.length; ++i) {
81             overviewControls[i].setOverviewGrid(this._overviewGrid);
82             overviewControls[i].show(this._overviewGrid.element);
83         }
84         this._overviewControls = overviewControls;
85         this.update();
86     },
87
88     update: function()
89     {
90         if (!this.isShowing())
91             return;
92
93         if (this._model.isEmpty())
94             this._overviewCalculator._setWindow(0, 1000);
95         else
96             this._overviewCalculator._setWindow(this._model.minimumRecordTime(), this._model.maximumRecordTime());
97
98         this._overviewCalculator._setDisplayWindow(0, this._overviewGrid.clientWidth());
99         for (var i = 0; i < this._overviewControls.length; ++i)
100             this._overviewControls[i].update();
101         this._overviewGrid.updateDividers(this._overviewCalculator);
102         this._updateEventDividers();
103         this._updateWindow();
104     },
105
106     _updateEventDividers: function()
107     {
108         var records = this._model.eventDividerRecords();
109         this._overviewGrid.removeEventDividers();
110         var dividers = [];
111         for (var i = 0; i < records.length; ++i) {
112             var record = records[i];
113             var positions = this._overviewCalculator.computeBarGraphPercentages(record);
114             var dividerPosition = Math.round(positions.start * 10);
115             if (dividers[dividerPosition])
116                 continue;
117             var title = this._uiUtils.titleForRecord(record);
118             var divider = this._uiUtils.createEventDivider(record.type(), title);
119             divider.style.left = positions.start + "%";
120             dividers[dividerPosition] = divider;
121         }
122         this._overviewGrid.addEventDividers(dividers);
123     },
124
125     _reset: function()
126     {
127         this._overviewCalculator.reset();
128         this._overviewGrid.reset();
129         this._overviewGrid.setResizeEnabled(false);
130         this._overviewGrid.updateDividers(this._overviewCalculator);
131         for (var i = 0; i < this._overviewControls.length; ++i)
132             this._overviewControls[i].reset();
133         this.update();
134     },
135
136     /**
137      * @param {!WebInspector.Event} event
138      */
139     _onWindowChanged: function(event)
140     {
141         if (this._muteOnWindowChanged)
142             return;
143         // Always use first control as a time converter.
144         if (!this._overviewControls.length)
145             return;
146         var windowTimes = this._overviewControls[0].windowTimes(this._overviewGrid.windowLeft(), this._overviewGrid.windowRight());
147         this._windowStartTime = windowTimes.startTime;
148         this._windowEndTime = windowTimes.endTime;
149         this.dispatchEventToListeners(WebInspector.TimelineOverviewPane.Events.WindowChanged, windowTimes);
150     },
151
152     /**
153      * @param {number} startTime
154      * @param {number} endTime
155      */
156     requestWindowTimes: function(startTime, endTime)
157     {
158         if (startTime === this._windowStartTime && endTime === this._windowEndTime)
159             return;
160         this._windowStartTime = startTime;
161         this._windowEndTime = endTime;
162         this._updateWindow();
163         this.dispatchEventToListeners(WebInspector.TimelineOverviewPane.Events.WindowChanged, { startTime: startTime, endTime: endTime });
164     },
165
166     _updateWindow: function()
167     {
168         if (!this._overviewControls.length)
169             return;
170         var windowBoundaries = this._overviewControls[0].windowBoundaries(this._windowStartTime, this._windowEndTime);
171         this._muteOnWindowChanged = true;
172         this._overviewGrid.setWindow(windowBoundaries.left, windowBoundaries.right);
173         this._overviewGrid.setResizeEnabled(!!this._model.records().length);
174         this._muteOnWindowChanged = false;
175     },
176
177     __proto__: WebInspector.VBox.prototype
178 }
179
180 /**
181  * @constructor
182  * @implements {WebInspector.TimelineGrid.Calculator}
183  */
184 WebInspector.TimelineOverviewCalculator = function()
185 {
186 }
187
188 WebInspector.TimelineOverviewCalculator.prototype = {
189     /**
190      * @return {number}
191      */
192     paddingLeft: function()
193     {
194         return this._paddingLeft;
195     },
196
197     /**
198      * @param {number} time
199      * @return {number}
200      */
201     computePosition: function(time)
202     {
203         return (time - this._minimumBoundary) / this.boundarySpan() * this._workingArea + this._paddingLeft;
204     },
205
206     /**
207      * @return {!{start: number, end: number}}
208      */
209     computeBarGraphPercentages: function(record)
210     {
211         var start = (record.startTime() - this._minimumBoundary) / this.boundarySpan() * 100;
212         var end = (record.endTime() - this._minimumBoundary) / this.boundarySpan() * 100;
213         return {start: start, end: end};
214     },
215
216     /**
217      * @param {number=} minimumRecordTime
218      * @param {number=} maximumRecordTime
219      */
220     _setWindow: function(minimumRecordTime, maximumRecordTime)
221     {
222         this._minimumBoundary = minimumRecordTime;
223         this._maximumBoundary = maximumRecordTime;
224     },
225
226     /**
227      * @param {number} paddingLeft
228      * @param {number} clientWidth
229      */
230     _setDisplayWindow: function(paddingLeft, clientWidth)
231     {
232         this._workingArea = clientWidth - paddingLeft;
233         this._paddingLeft = paddingLeft;
234     },
235
236     reset: function()
237     {
238         this._setWindow(0, 1000);
239     },
240
241     /**
242      * @param {number} value
243      * @param {number=} precision
244      * @return {string}
245      */
246     formatTime: function(value, precision)
247     {
248         return Number.preciseMillisToString(value - this.zeroTime(), precision);
249     },
250
251     /**
252      * @return {number}
253      */
254     maximumBoundary: function()
255     {
256         return this._maximumBoundary;
257     },
258
259     /**
260      * @return {number}
261      */
262     minimumBoundary: function()
263     {
264         return this._minimumBoundary;
265     },
266
267     /**
268      * @return {number}
269      */
270     zeroTime: function()
271     {
272         return this._minimumBoundary;
273     },
274
275     /**
276      * @return {number}
277      */
278     boundarySpan: function()
279     {
280         return this._maximumBoundary - this._minimumBoundary;
281     }
282 }
283
284 /**
285  * @interface
286  */
287 WebInspector.TimelineOverview = function(model)
288 {
289 }
290
291 WebInspector.TimelineOverview.prototype = {
292     /**
293      * @param {?Element} parentElement
294      * @param {!Element=} insertBefore
295      */
296     show: function(parentElement, insertBefore) { },
297
298     /**
299      * @param {!WebInspector.OverviewGrid} grid
300      */
301     setOverviewGrid: function(grid) { },
302
303     update: function() { },
304
305     dispose: function() { },
306
307     reset: function() { },
308
309     /**
310      * @param {number} windowLeft
311      * @param {number} windowRight
312      * @return {!{startTime: number, endTime: number}}
313      */
314     windowTimes: function(windowLeft, windowRight) { },
315
316     /**
317      * @param {number} startTime
318      * @param {number} endTime
319      * @return {!{left: number, right: number}}
320      */
321     windowBoundaries: function(startTime, endTime) { },
322 }
323
324 /**
325  * @constructor
326  * @extends {WebInspector.VBox}
327  * @implements {WebInspector.TimelineOverview}
328  * @param {!WebInspector.TimelineModel} model
329  */
330 WebInspector.TimelineOverviewBase = function(model)
331 {
332     WebInspector.VBox.call(this);
333
334     this._model = model;
335     this._canvas = this.element.createChild("canvas", "fill");
336     this._context = this._canvas.getContext("2d");
337 }
338
339 WebInspector.TimelineOverviewBase.prototype = {
340     /**
341      * @param {!WebInspector.OverviewGrid} grid
342      */
343     setOverviewGrid: function(grid)
344     {
345     },
346
347     update: function()
348     {
349         this.resetCanvas();
350     },
351
352     dispose: function()
353     {
354     },
355
356     reset: function()
357     {
358     },
359
360     timelineStarted: function()
361     {
362     },
363
364     timelineStopped: function()
365     {
366     },
367
368     /**
369      * @param {number} windowLeft
370      * @param {number} windowRight
371      * @return {!{startTime: number, endTime: number}}
372      */
373     windowTimes: function(windowLeft, windowRight)
374     {
375         var absoluteMin = this._model.minimumRecordTime();
376         var timeSpan = this._model.maximumRecordTime() - absoluteMin;
377         return {
378             startTime: absoluteMin + timeSpan * windowLeft,
379             endTime: absoluteMin + timeSpan * windowRight
380         };
381     },
382
383     /**
384      * @param {number} startTime
385      * @param {number} endTime
386      * @return {!{left: number, right: number}}
387      */
388     windowBoundaries: function(startTime, endTime)
389     {
390         var absoluteMin = this._model.minimumRecordTime();
391         var timeSpan = this._model.maximumRecordTime() - absoluteMin;
392         var haveRecords = absoluteMin > 0;
393         return {
394             left: haveRecords && startTime ? Math.min((startTime - absoluteMin) / timeSpan, 1) : 0,
395             right: haveRecords && endTime < Infinity ? (endTime - absoluteMin) / timeSpan : 1
396         }
397     },
398
399     resetCanvas: function()
400     {
401         this._canvas.width = this.element.clientWidth * window.devicePixelRatio;
402         this._canvas.height = this.element.clientHeight * window.devicePixelRatio;
403     },
404
405     __proto__: WebInspector.VBox.prototype
406 }