1<!DOCTYPE html>
2<!--
3Copyright (c) 2013 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import" href="/tracing/ui/tracks/multi_row_track.html">
9<link rel="import" href="/tracing/ui/tracks/slice_track.html">
10<link rel="import" href="/tracing/ui/base/ui.html">
11
12<script>
13'use strict';
14
15tr.exportTo('tr.ui.tracks', function() {
16  /**
17   * A track that displays a AsyncSliceGroup.
18   * @constructor
19   * @extends {MultiRowTrack}
20   */
21  var AsyncSliceGroupTrack = tr.ui.b.define(
22      'async-slice-group-track',
23      tr.ui.tracks.MultiRowTrack);
24
25  AsyncSliceGroupTrack.prototype = {
26
27    __proto__: tr.ui.tracks.MultiRowTrack.prototype,
28
29    decorate: function(viewport) {
30      tr.ui.tracks.MultiRowTrack.prototype.decorate.call(this, viewport);
31      this.classList.add('async-slice-group-track');
32      this.group_ = undefined;
33    },
34
35    addSubTrack_: function(slices) {
36      var track = new tr.ui.tracks.SliceTrack(this.viewport);
37      track.slices = slices;
38      this.appendChild(track);
39      track.asyncStyle = true;
40      return track;
41    },
42
43    get group() {
44      return this.group_;
45    },
46
47    set group(group) {
48      this.group_ = group;
49      this.setItemsToGroup(this.group_.slices, this.group_);
50    },
51
52    get eventContainer() {
53      return this.group;
54    },
55
56    addContainersToTrackMap: function(containerToTrackMap) {
57      tr.ui.tracks.MultiRowTrack.prototype.addContainersToTrackMap.apply(
58        this, arguments);
59      containerToTrackMap.addContainer(this.group, this);
60    },
61
62    /**
63     * Breaks up the list of slices into N rows, each of which is a list of
64     * slices that are non overlapping.
65     *
66     * It uses a very simple approach: walk through the slices in sorted order
67     * by start time. For each slice, try to fit it in an existing subRow. If
68     * it doesn't fit in any subrow, make another subRow. It then fits nested
69     * subSlices recursively into rows below parent slice according to which
70     * nested level the child is in.
71     */
72    buildSubRows_: function(slices, opt_skipSort) {
73      if (!opt_skipSort) {
74        slices.sort(function(x, y) {
75          return x.start - y.start;
76        });
77      }
78
79      // Helper function that returns true if it can put the slice on row n.
80      var findLevel = function(sliceToPut, rows, n) {
81        if (n >= rows.length)
82          return true; // We always can make empty rows to put the slice.
83        var subRow = rows[n];
84        var lastSliceInSubRow = subRow[subRow.length - 1];
85        if (sliceToPut.start >= lastSliceInSubRow.end) {
86          if (sliceToPut.subSlices === undefined ||
87              sliceToPut.subSlices.length === 0) {
88            return true;
89          }
90          // Make sure nested sub slices can be fitted in as well.
91          for (var i = 0; i < sliceToPut.subSlices.length; i++) {
92            if (!findLevel(sliceToPut.subSlices[i], rows, n + 1))
93              return false;
94          }
95          return true;
96        }
97        return false;
98      };
99
100      var subRows = [];
101      for (var i = 0; i < slices.length; i++) {
102        var slice = slices[i];
103
104        var found = false;
105        var index = subRows.length;
106        for (var j = 0; j < subRows.length; j++) {
107          if (findLevel(slice, subRows, j)) {
108            found = true;
109            index = j;
110            break;
111          }
112        }
113        if (!found)
114          subRows.push([]);
115        subRows[index].push(slice);
116
117        // Fit subSlices recursively into rows below parent.
118        var fitSubSlicesRecursively = function(subSlices, level, rows) {
119          if (subSlices === undefined || subSlices.length === 0)
120            return;
121          if (level === rows.length)
122            rows.push([]);
123          for (var h = 0; h < subSlices.length; h++) {
124            rows[level].push(subSlices[h]);
125            fitSubSlicesRecursively(subSlices[h].subSlices, level + 1, rows);
126          }
127        };
128        fitSubSlicesRecursively(slice.subSlices, index + 1, subRows);
129      }
130      return subRows;
131    }
132  };
133
134  return {
135    AsyncSliceGroupTrack: AsyncSliceGroupTrack
136  };
137});
138</script>
139