• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/**
8 * @fileoverview Renders an array of slices into the provided div,
9 * using a child canvas element. Uses a FastRectRenderer to draw only
10 * the visible slices.
11 */
12
13base.requireStylesheet('tracing.tracks.track');
14
15base.require('ui');
16base.require('ui.container_that_decorates_its_children');
17base.require('tracing.color_scheme');
18
19base.exportTo('tracing.tracks', function() {
20  var highlightIdBoost = tracing.getColorPaletteHighlightIdBoost();
21
22  /**
23   * The base class for all tracks.
24   * @constructor
25   */
26  var Track = ui.define('track', ui.ContainerThatDecoratesItsChildren);
27  Track.prototype = {
28    __proto__: ui.ContainerThatDecoratesItsChildren.prototype,
29
30    decorate: function(viewport) {
31      ui.ContainerThatDecoratesItsChildren.prototype.decorate.call(this);
32      if (viewport === undefined)
33        throw new Error('viewport is required when creating a Track.');
34
35      this.viewport_ = viewport;
36      this.classList.add('track');
37      this.categoryFilter_ = undefined;
38    },
39
40    get viewport() {
41      return this.viewport_;
42    },
43
44    context: function() {
45      // This is a little weird here, but we have to be able to walk up the
46      // parent tree to get the context.
47      if (!this.parentNode)
48        return undefined;
49      if (!this.parentNode.context)
50        throw new Error('Parent container does not support context() method.');
51      return this.parentNode.context();
52    },
53
54    get categoryFilter() {
55      return this.categoryFilter_;
56    },
57
58    set categoryFilter(categoryFilter) {
59      if (this.categoryFilter_ == categoryFilter)
60        return;
61      this.categoryFilter_ = categoryFilter;
62      this.updateContents_();
63    },
64
65    decorateChild_: function(childTrack) {
66      if (childTrack instanceof Track)
67        childTrack.categoryFilter = this.categoryFilter;
68    },
69
70    undecorateChild_: function(childTrack) {
71      if (childTrack.detach)
72        childTrack.detach();
73    },
74
75    updateContents_: function() {
76    },
77
78    drawTrack: function(type) {
79      var ctx = this.context();
80      if (ctx === undefined)
81        return;
82
83      ctx.save();
84      var worldBounds = this.setupCanvasForDraw_();
85      this.draw(type, worldBounds.left, worldBounds.right);
86      ctx.restore();
87    },
88
89    draw: function(type, viewLWorld, viewRWorld) {
90    },
91
92    setupCanvasForDraw_: function() {
93      var ctx = this.context();
94      var pixelRatio = window.devicePixelRatio || 1;
95      var bounds = this.getBoundingClientRect();
96      var canvasBounds = ctx.canvas.getBoundingClientRect();
97
98      ctx.translate(0, pixelRatio * (bounds.top - canvasBounds.top));
99
100      var viewLWorld = this.viewport.xViewToWorld(0);
101      var viewRWorld = this.viewport.xViewToWorld(bounds.width * pixelRatio);
102
103      return {left: viewLWorld, right: viewRWorld};
104    },
105
106    /**
107     * Called by all the addToSelection functions on the created selection
108     * hit objects. Override this function on parent classes to add
109     * context-specific information to the hit.
110     */
111    decorateHit: function(hit) {
112    },
113
114    addIntersectingItemsInRangeToSelection: function(
115        loVX, hiVX, loVY, hiVY, selection) {
116
117      var pixelRatio = window.devicePixelRatio || 1;
118      var viewPixWidthWorld = this.viewport.xViewVectorToWorld(1);
119      var loWX = this.viewport.xViewToWorld(loVX * pixelRatio);
120      var hiWX = this.viewport.xViewToWorld(hiVX * pixelRatio);
121
122      var clientRect = this.getBoundingClientRect();
123      var a = Math.max(loVY, clientRect.top);
124      var b = Math.min(hiVY, clientRect.bottom);
125      if (a > b)
126        return;
127
128      this.addIntersectingItemsInRangeToSelectionInWorldSpace(
129          loWX, hiWX, viewPixWidthWorld, selection);
130    },
131
132    addIntersectingItemsInRangeToSelectionInWorldSpace: function(
133        loWX, hiWX, viewPixWidthWorld, selection) {
134    },
135
136    drawInstantEvents_: function(instantEvents, viewLWorld, viewRWorld) {
137      var ctx = this.context();
138      var pixelRatio = window.devicePixelRatio || 1;
139
140      var bounds = this.getBoundingClientRect();
141      var height = bounds.height * pixelRatio;
142
143      // Culling parameters.
144      var vp = this.viewport;
145      var pixWidth = vp.xViewVectorToWorld(1);
146
147      var palette = tracing.getColorPalette();
148
149      // Begin rendering in world space.
150      ctx.save();
151      vp.applyTransformToCanvas(ctx);
152
153      var tr = new tracing.FastRectRenderer(ctx, 2 * pixWidth, 2 * pixWidth,
154                                            palette);
155      tr.setYandH(0, height);
156
157      var lowInstantEvent = base.findLowIndexInSortedArray(
158          instantEvents,
159          function(instantEvent) { return instantEvent.start; },
160          viewLWorld);
161
162      for (var i = lowInstantEvent; i < instantEvents.length; ++i) {
163        var instantEvent = instantEvents[i];
164        var x = instantEvent.start;
165        if (x > viewRWorld)
166          break;
167
168        // Less than 0.001 causes short events to disappear when zoomed in.
169        var w = Math.max(instantEvent.duration, 0.001);
170        var colorId = instantEvent.selected ?
171            instantEvent.colorId + highlightIdBoost :
172            instantEvent.colorId;
173
174        // InstantEvent: draw a triangle.  If zoomed too far, collapse
175        // into the FastRectRenderer.
176        if (pixWidth > 0.001) {
177          tr.fillRect(x, pixWidth, colorId);
178        } else {
179          ctx.fillStyle = palette[colorId];
180          ctx.beginPath();
181          ctx.moveTo(x - (4 * pixWidth), height);
182          ctx.lineTo(x, 0);
183          ctx.lineTo(x + (4 * pixWidth), height);
184          ctx.closePath();
185          ctx.fill();
186        }
187      }
188      tr.flush();
189      ctx.restore();
190    }
191  };
192
193  return {
194    Track: Track
195  };
196});
197