summaryrefslogtreecommitdiffstats
path: root/chrome/browser/resources/net_internals/waterfall_row.js
blob: d24595abc30bbac803dad141c38d675f50d76d81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var WaterfallRow = (function() {
  'use strict';

  /**
   * A WaterfallRow represents the row corresponding to a single SourceEntry
   * displayed by the EventsWaterfallView.
   *
   * @constructor
   */

  // TODO(viona):
  // -Support nested events.
  // -Handle updating length when an event is stalled.
  function WaterfallRow(parentView, sourceEntry, eventList) {
    this.parentView_ = parentView;
    this.sourceEntry_ = sourceEntry;

    this.eventTypes_ = eventList;
    this.description_ = sourceEntry.getDescription();

    this.createRow_();
  }

  WaterfallRow.prototype = {
    onSourceUpdated: function() {
      this.updateRow();
    },

    updateRow: function() {
      var scale = this.parentView_.getScaleFactor();
      // In some cases, the REQUEST_ALIVE event has been received, while the
      // URL Request to start the job has not been received. In that case, the
      // description obtained is incorrect. The following fixes that.
      if (this.description_ == '') {
        this.urlCell_.innerHTML = '';
        this.description_ = this.sourceEntry_.getDescription();
        addTextNode(this.urlCell_, this.description_);
      }

      this.barCell_.innerHTML = '';
      var matchingEventPairs = this.findLogEntryPairs_(this.eventTypes_);

      // Creates the spacing in the beginning to show start time.
      var startTime = this.parentView_.getStartTime();
      var sourceEntryStartTime = this.sourceEntry_.getStartTime();
      var delay = sourceEntryStartTime - startTime;
      var scaledMinTime = delay * scale;
      this.createNode_(this.barCell_, scaledMinTime, 'padding');

      var currentEnd = sourceEntryStartTime;
      for (var i = 0; i < matchingEventPairs.length; ++i) {
        var event = matchingEventPairs[i];
        var startTicks = event.startEntry.time;
        var endTicks = event.endEntry.time;
        event.eventType = event.startEntry.type;
        event.startTime = timeutil.convertTimeTicksToTime(startTicks);
        event.endTime = timeutil.convertTimeTicksToTime(endTicks);
        event.eventDuration = event.endTime - event.startTime;

        // Handles the spaces between events.
        if (currentEnd < event.startTime) {
          var eventDuration = event.startTime - currentEnd;
          var eventWidth = eventDuration * scale;
          this.createNode_(this.barCell_, eventWidth, this.type_);
        }

        // Creates event bars.
        var eventType = eventTypeToCssClass_(EventTypeNames[event.eventType]);
        var eventWidth = event.eventDuration * scale;
        this.createNode_(this.barCell_, eventWidth, eventType);
        currentEnd = event.startTime + event.eventDuration;
      }
      // Creates a bar for the part after the last event.
      if (this.getEndTime() > currentEnd) {
        var endWidth = (this.getEndTime() - currentEnd) * scale;
        this.createNode_(this.barCell_, endWidth, this.type_);
      }
    },

    getStartTime: function() {
      return this.sourceEntry_.getStartTime();
    },

    getEndTime: function() {
      return this.sourceEntry_.getEndTime();
    },

    createRow_: function() {
      // Create a row.
      var tr = addNode($(WaterfallView.TBODY_ID), 'tr');
      tr._id = this.sourceEntry_.getSourceId();
      this.row_ = tr;

      var idCell = addNode(tr, 'td');
      addTextNode(idCell, this.sourceEntry_.getSourceId());

      var urlCell = addNode(tr, 'td');
      urlCell.classList.add('waterfall-view-url-cell');
      addTextNode(urlCell, this.description_);
      this.urlCell_ = urlCell;

      // Creates the offset for where the color bar appears.
      var barCell = addNode(tr, 'td');
      barCell.classList.add('waterfall-view-row');
      this.barCell_ = barCell;

      this.updateRow();

      var sourceTypeString = this.sourceEntry_.getSourceTypeString();
      this.type_ = eventTypeToCssClass_(sourceTypeString);
    },

    // Generates nodes.
    createNode_: function(parentNode, durationScaled, eventType) {
      var newNode = addNode(parentNode, 'div');
      setNodeWidth(newNode, durationScaled);
      newNode.classList.add('waterfall-view-row-' + eventType);
      return newNode;
    },

    /**
     * Finds pairs of starting and ending events of all types that are in
     * typeList. Currently does not handle nested events. Can consider adding
     * starting events to a stack and popping off as their close events are
     * found. Returns an array of objects containing start/end entry pairs,
     * in the format {startEntry, endEntry}.
     */
    findLogEntryPairs_: function() {
      var typeList = this.eventTypes_;
      var matchingEventPairs = [];
      var startEntries = {};
      var entries = this.sourceEntry_.getLogEntries();
      for (var i = 0; i < entries.length; ++i) {
        var type = entries[i].type;
        if (typeList.indexOf(type) < 0) {
          continue;
        }
        if (entries[i].phase == EventPhase.PHASE_BEGIN) {
          startEntries[type] = entries[i];
        }
        if (startEntries[type] && entries[i].phase == EventPhase.PHASE_END) {
          var event = {
            startEntry: startEntries[type],
            endEntry: entries[i],
          };
          matchingEventPairs.push(event);
        }
      }
      return matchingEventPairs;
    },

  };

  function eventTypeToCssClass_(rawEventType) {
    return rawEventType.toLowerCase().replace(/_/g, '-');
  }

  return WaterfallRow;
})();