1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// found in the LICENSE file.
4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen/**
7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * @fileoverview Renders an array of slices into the provided div,
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * using a child canvas element. Uses a FastRectRenderer to draw only
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * the visible slices.
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen */
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsencr.define('gpu', function() {
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const palletteBase = [
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {r: 0x45, g: 0x85, b: 0xaa},
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {r: 0xdc, g: 0x73, b: 0xa8},
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {r: 0x77, g: 0xb6, b: 0x94},
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {r: 0x23, g: 0xae, b: 0x6e},
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {r: 0x76, g: 0x5d, b: 0x9e},
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {r: 0x48, g: 0xd8, b: 0xfb},
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {r: 0xa9, g: 0xd7, b: 0x93},
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {r: 0x7c, g: 0x2d, b: 0x52},
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {r: 0x69, g: 0xc2, b: 0x75},
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {r: 0x76, g: 0xcf, b: 0xee},
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {r: 0x3d, g: 0x85, b: 0xd1},
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {r: 0x71, g: 0x0b, b: 0x54}];
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  function brighten(c) {
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return {r: Math.min(255, c.r + Math.floor(c.r * 0.45)),
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      g: Math.min(255, c.g + Math.floor(c.g * 0.45)),
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      b: Math.min(255, c.b + Math.floor(c.b * 0.45))};
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  function colorToString(c) {
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return 'rgb(' + c.r + ',' + c.g + ',' + c.b + ')';
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const selectedIdBoost = palletteBase.length;
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const pallette = palletteBase.concat(palletteBase.map(brighten)).
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      map(colorToString);
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  var textWidthMap = { };
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  function quickMeasureText(ctx, text) {
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    var w = textWidthMap[text];
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!w) {
45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      w = ctx.measureText(text).width;
46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      textWidthMap[text] = w;
47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return w;
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  /**
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * Generic base class for timeline tracks
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   */
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TimelineThreadTrack = cr.ui.define('div');
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TimelineThreadTrack.prototype = {
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    __proto__: HTMLDivElement.prototype,
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    decorate: function() {
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.className = 'timeline-thread-track';
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    set thread(thread) {
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.thread_ = thread;
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.updateChildTracks_();
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    set viewport(v) {
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.viewport_ = v;
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (var i = 0; i < this.tracks_.length; i++)
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        this.tracks_[i].viewport = v;
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.invalidate();
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    invalidate: function() {
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (this.parentNode)
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        this.parentNode.invalidate();
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    onResize: function() {
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (var i = 0; i < this.tracks_.length; i++)
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        this.tracks_[i].onResize();
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    get firstCanvas() {
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (this.tracks_.length)
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return this.tracks_[0].firstCanvas;
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return undefined;
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    redraw: function() {
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (var i = 0; i < this.tracks_.length; i++)
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        this.tracks_[i].redraw();
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    updateChildTracks_: function() {
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.textContent = '';
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.tracks_ = [];
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (this.thread_) {
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        for (var srI = 0; srI < this.thread_.subRows.length; ++srI) {
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          var track = new TimelineSliceTrack();
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          if (srI == 0)
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            track.heading = this.thread_.parent.pid + ': ' +
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                this.thread_.tid + ': ';
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          else
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            track.heading = '';
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          track.slices = this.thread_.subRows[srI];
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          track.viewport = this.viewport_;
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          this.tracks_.push(track);
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          this.appendChild(track);
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Picks a slice, if any, at a given location.
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} wX X location to search at, in worldspace.
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} wY Y location to search at, in offset space.
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     offset space.
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {function():*} onHitCallback Callback to call with the slice,
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     if one is found.
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @return {boolean} true if a slice was found, otherwise false.
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pick: function(wX, wY, onHitCallback) {
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (var i = 0; i < this.tracks_.length; i++) {
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var track = this.tracks_[i];
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (wY >= track.offsetTop && wY < track.offsetTop + track.offsetHeight)
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          return track.pick(wX, onHitCallback);
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return false;
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Finds slices intersecting the given interval.
136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} loWX Lower X bound of the interval to search, in
137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     worldspace.
138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} hiWX Upper X bound of the interval to search, in
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     worldspace.
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} loY Lower Y bound of the interval to search, in
141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     offset space.
142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} hiY Upper Y bound of the interval to search, in
143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     offset space.
144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {function():*} onHitCallback Function to call for each slice
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     intersecting the interval.
146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pickRange: function(loWX, hiWX, loY, hiY, onHitCallback) {
148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (var i = 0; i < this.tracks_.length; i++) {
149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var a = Math.max(loY, this.tracks_[i].offsetTop);
150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var b = Math.min(hiY, this.tracks_[i].offsetTop +
151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                         this.tracks_[i].offsetHeight);
152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (a <= b)
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          this.tracks_[i].pickRange(loWX, hiWX, loY, hiY, onHitCallback);
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  /**
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * Creates a new timeline track div element
160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @constructor
161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @extends {HTMLDivElement}
162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   */
163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TimelineSliceTrack = cr.ui.define('div');
164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TimelineSliceTrack.prototype = {
166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    __proto__: HTMLDivElement.prototype,
167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    decorate: function() {
169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.className = 'timeline-slice-track';
170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.slices_ = null;
171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.titleDiv_ = document.createElement('div');
173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.titleDiv_.className = 'timeline-slice-track-title';
174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.appendChild(this.titleDiv_);
175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.canvasContainer_ = document.createElement('div');
177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.canvasContainer_.className = 'timeline-slice-track-canvas-container';
178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.appendChild(this.canvasContainer_);
179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.canvas_ = document.createElement('canvas');
180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.canvas_.className = 'timeline-slice-track-canvas';
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.canvasContainer_.appendChild(this.canvas_);
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.ctx_ = this.canvas_.getContext('2d');
184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    set heading(text) {
187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.titleDiv_.textContent = text;
188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    set slices(slices) {
191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.slices_ = slices;
192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.invalidate();
193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    set viewport(v) {
196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.viewport_ = v;
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.invalidate();
198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    invalidate: function() {
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (this.parentNode)
202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        this.parentNode.invalidate();
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
205ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    get firstCanvas() {
206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return this.canvas_;
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    onResize: function() {
210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.canvas_.width = this.canvasContainer_.clientWidth;
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.canvas_.height = this.canvasContainer_.clientHeight;
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.invalidate();
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    redraw: function() {
216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (!this.viewport_)
217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return;
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var ctx = this.ctx_;
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var canvasW = this.canvas_.width;
220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var canvasH = this.canvas_.height;
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ctx.clearRect(0, 0, canvasW, canvasH);
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // culling...
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var vp = this.viewport_;
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var pixWidth = vp.xViewVectorToWorld(1);
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var viewLWorld = vp.xViewToWorld(0);
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var viewRWorld = vp.xViewToWorld(this.width);
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // begin rendering in world space
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ctx.save();
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      vp.applyTransformToCanavs(ctx);
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // tracks
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var tr = new gpu.FastRectRenderer(ctx, viewLWorld, 2 * pixWidth,
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                        2 * pixWidth, viewRWorld, pallette);
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      tr.setYandH(0, canvasH);
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var slices = this.slices_;
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (var i = 0; i < slices.length; ++i) {
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var slice = slices[i];
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var x = slice.start;
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var w = slice.duration;
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var colorId;
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        colorId = slice.selected ?
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            slice.colorId + selectedIdBoost :
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            slice.colorId;
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (w < pixWidth)
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          w = pixWidth;
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        tr.fillRect(x, w, colorId);
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      tr.flush();
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ctx.restore();
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // labels
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ctx.textAlign = 'center';
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ctx.textBaseline = 'top';
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ctx.font = '10px sans-serif';
259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ctx.strokeStyle = 'rgb(0,0,0)';
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ctx.fillStyle = 'rgb(0,0,0)';
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var quickDiscardThresshold = pixWidth * 20; // dont render until 20px wide
262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (var i = 0; i < slices.length; ++i) {
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var slice = slices[i];
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (slice.duration > quickDiscardThresshold) {
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          var labelWidth = quickMeasureText(ctx, slice.title) + 2;
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          var labelWidthWorld = pixWidth * labelWidth;
267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          if (labelWidthWorld < slice.duration) {
268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            var cX = vp.xWorldToView(slice.start + 0.5 * slice.duration);
269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            ctx.fillText(slice.title, cX, 2.5);
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          }
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Picks a slice, if any, at a given location.
277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} wX X location to search at, in worldspace.
278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} wY Y location to search at, in offset space.
279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     offset space.
280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {function():*} onHitCallback Callback to call with the slice,
281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     if one is found.
282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @return {boolean} true if a slice was found, otherwise false.
283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pick: function(wX, wY, onHitCallback) {
285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (wY < this.offsetTop || wY >= this.offsetTop + this.offsetHeight)
286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return false;
287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var x = gpu.findLowIndexInSortedIntervals(this.slices_,
288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          function(x) { return x.start; },
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          function(x) { return x.duration; },
290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          wX);
291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (x >= 0 && x < this.slices_.length) {
292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        onHitCallback('slice', this, this.slices_[x]);
293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return true;
294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return false;
296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Finds slices intersecting the given interval.
300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} loWX Lower X bound of the interval to search, in
301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     worldspace.
302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} hiWX Upper X bound of the interval to search, in
303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     worldspace.
304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} loY Lower Y bound of the interval to search, in
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     offset space.
306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} hiY Upper Y bound of the interval to search, in
307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     offset space.
308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {function():*} onHitCallback Function to call for each slice
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     intersecting the interval.
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pickRange: function(loWX, hiWX, loY, hiY, onHitCallback) {
312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var a = Math.max(loY, this.offsetTop);
313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var b = Math.min(hiY, this.offsetTop + this.offsetHeight);
314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (a > b)
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return;
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      function onPickHit(slice) {
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        onHitCallback('slice', this, slice);
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      gpu.iterateOverIntersectingIntervals(this.slices_,
321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          function(x) { return x.start; },
322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          function(x) { return x.duration; },
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          loWX, hiWX,
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          onPickHit);
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return {
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    TimelineSliceTrack: TimelineSliceTrack,
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    TimelineThreadTrack: TimelineThreadTrack
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen});
334