1// Copyright (c) 2013 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
7base.requireStylesheet('tracing.tracks.drawing_container');
8
9base.require('base.raf');
10base.require('tracing.tracks.track');
11base.require('ui');
12
13base.exportTo('tracing.tracks', function() {
14  var DrawType = {
15    SLICE: 1,
16    INSTANT_EVENT: 2
17  };
18
19  var DrawingContainer = ui.define('drawing-container', tracing.tracks.Track);
20
21  DrawingContainer.prototype = {
22    __proto__: tracing.tracks.Track.prototype,
23
24    decorate: function(viewport) {
25      tracing.tracks.Track.prototype.decorate.call(this, viewport);
26      this.classList.add('drawing-container');
27
28      this.canvas_ = document.createElement('canvas');
29      this.canvas_.className = 'drawing-container-canvas';
30      this.canvas_.style.left = tracing.constants.HEADING_WIDTH + 'px';
31      this.appendChild(this.canvas_);
32
33      this.ctx_ = this.canvas_.getContext('2d');
34
35      this.viewportChange_ = this.viewportChange_.bind(this);
36      this.viewport.addEventListener('change', this.viewportChange_);
37    },
38
39    // Needed to support the calls in TimelineTrackView.
40    get canvas() {
41      return this.canvas_;
42    },
43
44    context: function() {
45      return this.ctx_;
46    },
47
48    viewportChange_: function() {
49      this.invalidate();
50    },
51
52    invalidate: function() {
53      if (this.rafPending_)
54        return;
55      this.rafPending_ = true;
56
57      base.requestPreAnimationFrame(function() {
58        this.rafPending_ = false;
59        this.ctx_.clearRect(0, 0, this.canvas_.width, this.canvas_.height);
60        this.updateCanvasSizeIfNeeded_();
61
62        base.requestAnimationFrameInThisFrameIfPossible(function() {
63          for (var i = 0; i < this.children.length; ++i) {
64            if (!(this.children[i] instanceof tracing.tracks.Track))
65              continue;
66            this.children[i].drawTrack(DrawType.INSTANT_EVENT);
67          }
68
69          for (var i = 0; i < this.children.length; ++i) {
70            if (!(this.children[i] instanceof tracing.tracks.Track))
71              continue;
72            this.children[i].drawTrack(DrawType.SLICE);
73          }
74
75          var pixelRatio = window.devicePixelRatio || 1;
76          var bounds = this.canvas_.getBoundingClientRect();
77          var viewLWorld = this.viewport.xViewToWorld(0);
78          var viewRWorld = this.viewport.xViewToWorld(
79              bounds.width * pixelRatio);
80
81          this.viewport.drawGridLines(this.ctx_, viewLWorld, viewRWorld);
82          this.viewport.drawMarkerLines(this.ctx_, viewLWorld, viewRWorld);
83        }, this);
84      }, this);
85    },
86
87    updateCanvasSizeIfNeeded_: function() {
88      var visibleChildTracks =
89          base.asArray(this.children).filter(this.visibleFilter_);
90
91      var thisBounds = this.getBoundingClientRect();
92
93      var firstChildTrackBounds = visibleChildTracks[0].getBoundingClientRect();
94      var lastChildTrackBounds =
95          visibleChildTracks[visibleChildTracks.length - 1].
96              getBoundingClientRect();
97
98      var innerWidth = firstChildTrackBounds.width -
99          tracing.constants.HEADING_WIDTH;
100      var innerHeight = lastChildTrackBounds.bottom - firstChildTrackBounds.top;
101
102      var pixelRatio = window.devicePixelRatio || 1;
103      if (this.canvas_.width != innerWidth * pixelRatio) {
104        this.canvas_.width = innerWidth * pixelRatio;
105        this.canvas_.style.width = innerWidth + 'px';
106      }
107
108      if (this.canvas_.height != innerHeight * pixelRatio) {
109        this.canvas_.height = innerHeight * pixelRatio;
110        this.canvas_.style.height = innerHeight + 'px';
111      }
112
113      var canvasTop =
114          firstChildTrackBounds.top - thisBounds.top + this.scrollTop;
115      if (this.canvas_.style.top + 'px' !== canvasTop)
116        this.canvas_.style.top = canvasTop + 'px';
117    },
118
119    visibleFilter_: function(element) {
120      if (!(element instanceof tracing.tracks.Track))
121        return false;
122      return window.getComputedStyle(element).display !== 'none';
123    }
124  };
125
126  return {
127    DrawingContainer: DrawingContainer,
128    DrawType: DrawType
129  };
130});
131