Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / tracing / tracks / trace_model_track.js
1 // Copyright (c) 2012 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 tvcm.requireStylesheet('tracing.tracks.trace_model_track');
8
9 tvcm.require('tvcm.measuring_stick');
10 tvcm.require('tracing.tracks.container_track');
11 tvcm.require('tracing.tracks.kernel_track');
12 tvcm.require('tracing.tracks.process_track');
13 tvcm.require('tracing.draw_helpers');
14 tvcm.require('tvcm.ui');
15
16 tvcm.exportTo('tracing.tracks', function() {
17
18   /**
19    * Visualizes a Model by building ProcessTracks and
20    * CpuTracks.
21    * @constructor
22    */
23   var TraceModelTrack = tvcm.ui.define(
24       'trace-model-track', tracing.tracks.ContainerTrack);
25
26   TraceModelTrack.prototype = {
27
28     __proto__: tracing.tracks.ContainerTrack.prototype,
29
30     decorate: function(viewport) {
31       tracing.tracks.ContainerTrack.prototype.decorate.call(this, viewport);
32       this.classList.add('model-track');
33     },
34
35     detach: function() {
36       tracing.tracks.ContainerTrack.prototype.detach.call(this);
37     },
38
39     get model() {
40       return this.model_;
41     },
42
43     set model(model) {
44       this.model_ = model;
45       this.updateContents_();
46     },
47
48     get hasVisibleContent() {
49       return this.children.length > 0;
50     },
51
52     updateContents_: function() {
53       this.textContent = '';
54       if (!this.model_)
55         return;
56
57       this.appendKernelTrack_();
58
59       // Get a sorted list of processes.
60       var processes = this.model_.getAllProcesses();
61       processes.sort(tracing.trace_model.Process.compare);
62
63       for (var i = 0; i < processes.length; ++i) {
64         var process = processes[i];
65
66         var track = new tracing.tracks.ProcessTrack(this.viewport);
67         track.process = process;
68         if (!track.hasVisibleContent)
69           continue;
70
71         this.appendChild(track);
72       }
73       this.viewport_.rebuildEventToTrackMap();
74     },
75
76     addEventsToTrackMap: function(eventToTrackMap) {
77       if (!this.model_)
78         return;
79
80       var tracks = this.children;
81       for (var i = 0; i < tracks.length; ++i)
82         tracks[i].addEventsToTrackMap(eventToTrackMap);
83
84       if (this.instantEvents === undefined)
85         return;
86
87       var vp = this.viewport_;
88       this.instantEvents.forEach(function(ev) {
89         eventToTrackMap.addEvent(ev, this);
90       }.bind(this));
91     },
92
93     appendKernelTrack_: function() {
94       var kernel = this.model.kernel;
95       var track = new tracing.tracks.KernelTrack(this.viewport);
96       track.kernel = this.model.kernel;
97       if (!track.hasVisibleContent)
98         return;
99       this.appendChild(track);
100     },
101
102     drawTrack: function(type) {
103       var ctx = this.context();
104
105       var pixelRatio = window.devicePixelRatio || 1;
106       var bounds = this.getBoundingClientRect();
107       var canvasBounds = ctx.canvas.getBoundingClientRect();
108
109       ctx.save();
110       ctx.translate(0, pixelRatio * (bounds.top - canvasBounds.top));
111
112       var dt = this.viewport.currentDisplayTransform;
113       var viewLWorld = dt.xViewToWorld(0);
114       var viewRWorld = dt.xViewToWorld(bounds.width * pixelRatio);
115
116       switch (type) {
117         case tracing.tracks.DrawType.GRID:
118           this.viewport.drawMajorMarkLines(ctx);
119           // The model is the only thing that draws grid lines.
120           ctx.restore();
121           return;
122
123         case tracing.tracks.DrawType.FLOW_ARROWS:
124           if (this.model_.flowIntervalTree.size === 0) {
125             ctx.restore();
126             return;
127           }
128
129           this.drawFlowArrows_(viewLWorld, viewRWorld);
130           ctx.restore();
131           return;
132
133         case tracing.tracks.DrawType.INSTANT_EVENT:
134           if (!this.model_.instantEvents ||
135               this.model_.instantEvents.length === 0)
136             break;
137
138           tracing.drawInstantSlicesAsLines(
139               ctx,
140               this.viewport.currentDisplayTransform,
141               viewLWorld,
142               viewRWorld,
143               bounds.height,
144               this.model_.instantEvents,
145               1);
146
147           break;
148
149         case tracing.tracks.DrawType.MARKERS:
150           if (!this.viewport.interestRange.isEmpty) {
151             this.viewport.interestRange.draw(ctx, viewLWorld, viewRWorld);
152             this.viewport.interestRange.drawIndicators(
153                 ctx, viewLWorld, viewRWorld);
154           }
155           ctx.restore();
156           return;
157       }
158       ctx.restore();
159
160       tracing.tracks.ContainerTrack.prototype.drawTrack.call(this, type);
161     },
162
163     drawFlowArrows_: function(viewLWorld, viewRWorld) {
164       var ctx = this.context();
165       var dt = this.viewport.currentDisplayTransform;
166       dt.applyTransformToCanvas(ctx);
167
168       var pixWidth = dt.xViewVectorToWorld(1);
169
170       ctx.strokeStyle = 'rgba(0, 0, 0, 0.4)';
171       ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
172       ctx.lineWidth = pixWidth > 1.0 ? 1 : pixWidth;
173
174       var events =
175           this.model_.flowIntervalTree.findIntersection(viewLWorld, viewRWorld);
176
177       var minWidth = 2 * pixWidth;
178       var canvasBounds = ctx.canvas.getBoundingClientRect();
179
180       for (var i = 0; i < events.length; ++i) {
181         var startEvent = events[i][0];
182         var endEvent = events[i][1];
183
184         // Skip lines that will be, essentially, vertical.
185         var distance = endEvent.start - startEvent.start;
186         if (distance <= minWidth)
187           continue;
188
189         this.drawFlowArrowBetween_(
190             ctx, startEvent, endEvent, canvasBounds, pixWidth);
191       }
192     },
193
194     drawFlowArrowBetween_: function(ctx, startEvent, endEvent,
195                                     canvasBounds, pixWidth) {
196       var pixelRatio = window.devicePixelRatio || 1;
197
198       var startTrack = this.viewport.trackForEvent(startEvent);
199       var endTrack = this.viewport.trackForEvent(endEvent);
200
201       var startBounds = startTrack.getBoundingClientRect();
202       var endBounds = endTrack.getBoundingClientRect();
203
204       var startSize = startBounds.left + startBounds.top +
205           startBounds.bottom + startBounds.right;
206       var endSize = endBounds.left + endBounds.top +
207           endBounds.bottom + endBounds.right;
208       // Nothing to do if both ends of the track are collapsed.
209       if (startSize === 0 && endSize === 0)
210         return;
211
212       var startY = this.calculateTrackY_(startTrack, canvasBounds);
213       var endY = this.calculateTrackY_(endTrack, canvasBounds);
214
215       var pixelStartY = pixelRatio * startY;
216       var pixelEndY = pixelRatio * endY;
217       var half = (endEvent.start - startEvent.start) / 2;
218
219       ctx.beginPath();
220       ctx.moveTo(startEvent.start, pixelStartY);
221       ctx.bezierCurveTo(
222           startEvent.start + half, pixelStartY,
223           startEvent.start + half, pixelEndY,
224           endEvent.start, pixelEndY);
225       ctx.stroke();
226
227       var arrowWidth = 5 * pixWidth * pixelRatio;
228       var distance = endEvent.start - startEvent.start;
229       if (distance <= (2 * arrowWidth))
230         return;
231
232       var tipX = endEvent.start;
233       var tipY = pixelEndY;
234       var arrowHeight = (endBounds.height / 4) * pixelRatio;
235       tracing.drawTriangle(ctx,
236           tipX, tipY,
237           tipX - arrowWidth, tipY - arrowHeight,
238           tipX - arrowWidth, tipY + arrowHeight);
239       ctx.fill();
240     },
241
242     calculateTrackY_: function(track, canvasBounds) {
243       var bounds = track.getBoundingClientRect();
244       var size = bounds.left + bounds.top + bounds.bottom + bounds.right;
245       if (size === 0)
246         return this.calculateTrackY_(track.parentNode, canvasBounds);
247
248       return bounds.top - canvasBounds.top + (bounds.height / 2);
249     },
250
251     addIntersectingItemsInRangeToSelectionInWorldSpace: function(
252         loWX, hiWX, viewPixWidthWorld, selection) {
253       function onPickHit(instantEvent) {
254         selection.push(instantEvent);
255       }
256       tvcm.iterateOverIntersectingIntervals(this.model_.instantEvents,
257           function(x) { return x.start; },
258           function(x) { return x.duration; },
259           loWX, hiWX,
260           onPickHit.bind(this));
261
262       tracing.tracks.ContainerTrack.prototype.
263           addIntersectingItemsInRangeToSelectionInWorldSpace.
264           apply(this, arguments);
265     },
266
267     addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY,
268                                          selection) {
269       this.addClosestInstantEventToSelection(this.model_.instantEvents,
270                                              worldX, worldMaxDist, selection);
271       tracing.tracks.ContainerTrack.prototype.addClosestEventToSelection.
272           apply(this, arguments);
273     }
274   };
275
276   return {
277     TraceModelTrack: TraceModelTrack
278   };
279 });