Home | History | Annotate | Download | only in src
      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 Code for the timeline viewport.
      9  */
     10 base.require('event_target');
     11 base.exportTo('tracing', function() {
     12 
     13   function TimelineSelectionSliceHit(track, slice) {
     14     this.track = track;
     15     this.slice = slice;
     16   }
     17   TimelineSelectionSliceHit.prototype = {
     18     get selected() {
     19       return this.slice.selected;
     20     },
     21     set selected(v) {
     22       this.slice.selected = v;
     23     }
     24   };
     25 
     26   function TimelineSelectionCounterSampleHit(track, counter, sampleIndex) {
     27     this.track = track;
     28     this.counter = counter;
     29     this.sampleIndex = sampleIndex;
     30   }
     31   TimelineSelectionCounterSampleHit.prototype = {
     32     get selected() {
     33       return this.track.selectedSamples[this.sampleIndex] == true;
     34     },
     35     set selected(v) {
     36       if (v)
     37         this.track.selectedSamples[this.sampleIndex] = true;
     38       else
     39         this.track.selectedSamples[this.sampleIndex] = false;
     40       this.track.invalidate();
     41     }
     42   };
     43 
     44 
     45   /**
     46    * Represents a selection within a Timeline and its associated set of tracks.
     47    * @constructor
     48    */
     49   function TimelineSelection() {
     50     this.range_dirty_ = true;
     51     this.range_ = {};
     52     this.length_ = 0;
     53   }
     54   TimelineSelection.prototype = {
     55     __proto__: Object.prototype,
     56 
     57     get range() {
     58       if (this.range_dirty_) {
     59         var wmin = Infinity;
     60         var wmax = -wmin;
     61         for (var i = 0; i < this.length_; i++) {
     62           var hit = this[i];
     63           if (hit.slice) {
     64             wmin = Math.min(wmin, hit.slice.start);
     65             wmax = Math.max(wmax, hit.slice.end);
     66           }
     67         }
     68         this.range_ = {
     69           min: wmin,
     70           max: wmax
     71         };
     72         this.range_dirty_ = false;
     73       }
     74       return this.range_;
     75     },
     76 
     77     get duration() {
     78       return this.range.max - this.range.min;
     79     },
     80 
     81     get length() {
     82       return this.length_;
     83     },
     84 
     85     clear: function() {
     86       for (var i = 0; i < this.length_; ++i)
     87         delete this[i];
     88       this.length_ = 0;
     89       this.range_dirty_ = true;
     90     },
     91 
     92     push_: function(hit) {
     93       this[this.length_++] = hit;
     94       this.range_dirty_ = true;
     95       return hit;
     96     },
     97 
     98     addSlice: function(track, slice) {
     99       return this.push_(new TimelineSelectionSliceHit(track, slice));
    100     },
    101 
    102     addCounterSample: function(track, counter, sampleIndex) {
    103       return this.push_(
    104           new TimelineSelectionCounterSampleHit(
    105           track, counter, sampleIndex));
    106     },
    107 
    108     subSelection: function(index, count) {
    109       count = count || 1;
    110 
    111       var selection = new TimelineSelection();
    112       selection.range_dirty_ = true;
    113       if (index < 0 || index + count > this.length_)
    114         throw new Error('Index out of bounds');
    115 
    116       for (var i = index; i < index + count; i++)
    117         selection.push_(this[i]);
    118 
    119       return selection;
    120     },
    121 
    122     getCounterSampleHits: function() {
    123       var selection = new TimelineSelection();
    124       for (var i = 0; i < this.length_; i++)
    125         if (this[i] instanceof TimelineSelectionCounterSampleHit)
    126           selection.push_(this[i]);
    127         return selection;
    128     },
    129 
    130     getSliceHits: function() {
    131       var selection = new TimelineSelection();
    132       for (var i = 0; i < this.length_; i++)
    133         if (this[i] instanceof TimelineSelectionSliceHit)
    134           selection.push_(this[i]);
    135         return selection;
    136     },
    137 
    138     map: function(fn) {
    139       for (var i = 0; i < this.length_; i++)
    140         fn(this[i]);
    141     },
    142 
    143     /**
    144      * Helper for selection previous or next.
    145      * @param {boolean} forwardp If true, select one forward (next).
    146      *   Else, select previous.
    147      * @return {boolean} true if current selection changed.
    148      */
    149     getShiftedSelection: function(offset) {
    150       var newSelection = new TimelineSelection();
    151       for (var i = 0; i < this.length_; i++) {
    152         var hit = this[i];
    153         hit.track.addItemNearToProvidedHitToSelection(
    154             hit, offset, newSelection);
    155       }
    156 
    157       if (newSelection.length == 0)
    158         return undefined;
    159       return newSelection;
    160     }
    161   };
    162 
    163   return {
    164     TimelineSelectionSliceHit: TimelineSelectionSliceHit,
    165     TimelineSelectionCounterSampleHit: TimelineSelectionCounterSampleHit,
    166     TimelineSelection: TimelineSelection
    167   };
    168 });
    169