Index: chrome/browser/resources/gpu_internals/timeline.js |
diff --git a/chrome/browser/resources/gpu_internals/timeline.js b/chrome/browser/resources/gpu_internals/timeline.js |
deleted file mode 100644 |
index 79305cbc6e14da396231d48dad2f6c1b631d299a..0000000000000000000000000000000000000000 |
--- a/chrome/browser/resources/gpu_internals/timeline.js |
+++ /dev/null |
@@ -1,587 +0,0 @@ |
-// Copyright (c) 2011 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. |
- |
-/** |
- * @fileoverview Interactive visualizaiton of TimelineModel objects |
- * based loosely on gantt charts. Each thread in the TimelineModel is given a |
- * set of TimelineTracks, one per subrow in the thread. The Timeline class |
- * acts as a controller, creating the individual tracks, while TimelineTracks |
- * do actual drawing. |
- * |
- * Visually, the Timeline produces (prettier) visualizations like the following: |
- * Thread1: AAAAAAAAAA AAAAA |
- * BBBB BB |
- * Thread2: CCCCCC CCCCC |
- * |
- */ |
-cr.define('gpu', function() { |
- |
- /** |
- * The TimelineViewport manages the transform used for navigating |
- * within the timeline. It is a simple transform: |
- * x' = (x+pan) * scale |
- * |
- * The timeline code tries to avoid directly accessing this transform, |
- * instead using this class to do conversion between world and view space, |
- * as well as the math for centering the viewport in various interesting |
- * ways. |
- * |
- * @constructor |
- * @extends {cr.EventTarget} |
- */ |
- function TimelineViewport() { |
- this.scaleX_ = 1; |
- this.panX_ = 0; |
- this.gridTimebase_ = 0; |
- this.gridStep_ = 1000 / 60; |
- this.gridEnabled_ = false; |
- } |
- |
- TimelineViewport.prototype = { |
- __proto__: cr.EventTarget.prototype, |
- |
- get scaleX() { |
- return this.scaleX_; |
- }, |
- set scaleX(s) { |
- var changed = this.scaleX_ != s; |
- if (changed) { |
- this.scaleX_ = s; |
- cr.dispatchSimpleEvent(this, 'change'); |
- } |
- }, |
- |
- get panX() { |
- return this.panX_; |
- }, |
- set panX(p) { |
- var changed = this.panX_ != p; |
- if (changed) { |
- this.panX_ = p; |
- cr.dispatchSimpleEvent(this, 'change'); |
- } |
- }, |
- |
- setPanAndScale: function(p, s) { |
- var changed = this.scaleX_ != s || this.panX_ != p; |
- if (changed) { |
- this.scaleX_ = s; |
- this.panX_ = p; |
- cr.dispatchSimpleEvent(this, 'change'); |
- } |
- }, |
- |
- xWorldToView: function(x) { |
- return (x + this.panX_) * this.scaleX_; |
- }, |
- |
- xWorldVectorToView: function(x) { |
- return x * this.scaleX_; |
- }, |
- |
- xViewToWorld: function(x) { |
- return (x / this.scaleX_) - this.panX_; |
- }, |
- |
- xViewVectorToWorld: function(x) { |
- return x / this.scaleX_; |
- }, |
- |
- xPanWorldPosToViewPos: function(worldX, viewX, viewWidth) { |
- if (typeof viewX == 'string') { |
- if (viewX == 'left') { |
- viewX = 0; |
- } else if (viewX == 'center') { |
- viewX = viewWidth / 2; |
- } else if (viewX == 'right') { |
- viewX = viewWidth - 1; |
- } else { |
- throw Error('unrecognized string for viewPos. left|center|right'); |
- } |
- } |
- this.panX = (viewX / this.scaleX_) - worldX; |
- }, |
- |
- get gridEnabled() { |
- return this.gridEnabled_; |
- }, |
- |
- set gridEnabled(enabled) { |
- if (this.gridEnabled_ == enabled) |
- return; |
- this.gridEnabled_ = enabled && true; |
- cr.dispatchSimpleEvent(this, 'change'); |
- }, |
- |
- get gridTimebase() { |
- return this.gridTimebase_; |
- }, |
- |
- set gridTimebase(timebase) { |
- if (this.gridTimebase_ == timebase) |
- return; |
- this.gridTimebase_ = timebase; |
- cr.dispatchSimpleEvent(this, 'change'); |
- }, |
- |
- get gridStep() { |
- return this.gridStep_; |
- }, |
- |
- applyTransformToCanavs: function(ctx) { |
- ctx.transform(this.scaleX_, 0, 0, 1, this.panX_ * this.scaleX_, 0); |
- } |
- }; |
- |
- /** |
- * Renders a TimelineModel into a div element, making one |
- * TimelineTrack for each subrow in each thread of the model, managing |
- * overall track layout, and handling user interaction with the |
- * viewport. |
- * |
- * @constructor |
- * @extends {HTMLDivElement} |
- */ |
- Timeline = cr.ui.define('div'); |
- |
- Timeline.prototype = { |
- __proto__: HTMLDivElement.prototype, |
- |
- model_: null, |
- |
- decorate: function() { |
- this.classList.add('timeline'); |
- this.needsViewportReset_ = false; |
- |
- this.viewport_ = new TimelineViewport(); |
- this.viewport_.addEventListener('change', |
- this.viewportChange_.bind(this)); |
- |
- this.invalidatePending_ = false; |
- |
- this.tracks_ = this.ownerDocument.createElement('div'); |
- this.tracks_.invalidate = this.invalidate.bind(this); |
- this.appendChild(this.tracks_); |
- |
- this.dragBox_ = this.ownerDocument.createElement('div'); |
- this.dragBox_.className = 'timeline-drag-box'; |
- this.appendChild(this.dragBox_); |
- |
- // The following code uses a setInterval to monitor the timeline control |
- // for size changes. This is so that we can keep the canvas' bitmap size |
- // correctly synchronized with its presentation size. |
- // TODO(nduca): detect this in a more efficient way, e.g. iframe hack. |
- this.lastSize_ = this.clientWidth + 'x' + this.clientHeight; |
- this.ownerDocument.defaultView.setInterval(function() { |
- var curSize = this.clientWidth + 'x' + this.clientHeight; |
- if (this.clientWidth && curSize != this.lastSize_) { |
- this.lastSize_ = curSize; |
- this.onResize(); |
- } |
- }.bind(this), 250); |
- |
- document.addEventListener('keypress', this.onKeypress_.bind(this)); |
- document.addEventListener('keydown', this.onKeydown_.bind(this)); |
- document.addEventListener('mousedown', this.onMouseDown_.bind(this)); |
- document.addEventListener('mousemove', this.onMouseMove_.bind(this)); |
- document.addEventListener('mouseup', this.onMouseUp_.bind(this)); |
- document.addEventListener('dblclick', this.onDblClick_.bind(this)); |
- |
- this.lastMouseViewPos_ = {x: 0, y: 0}; |
- |
- this.selection_ = []; |
- }, |
- |
- get model() { |
- return this.model_; |
- }, |
- |
- set model(model) { |
- if (!model) |
- throw Error('Model cannot be null'); |
- if (this.model) { |
- throw Error('Cannot set model twice.'); |
- } |
- this.model_ = model; |
- |
- // Create tracks. |
- this.tracks_.textContent = ''; |
- var threads = model.getAllThreads(); |
- threads.sort(gpu.TimelineThread.compare); |
- for (var tI = 0; tI < threads.length; tI++) { |
- var thread = threads[tI]; |
- var track = new TimelineThreadTrack(); |
- track.thread = thread; |
- track.viewport = this.viewport_; |
- this.tracks_.appendChild(track); |
- |
- } |
- |
- this.needsViewportReset_ = true; |
- }, |
- |
- viewportChange_: function() { |
- this.invalidate(); |
- }, |
- |
- invalidate: function() { |
- if (this.invalidatePending_) |
- return; |
- this.invalidatePending_ = true; |
- window.setTimeout(function() { |
- this.invalidatePending_ = false; |
- this.redrawAllTracks_(); |
- }.bind(this), 0); |
- }, |
- |
- onResize: function() { |
- for (var i = 0; i < this.tracks_.children.length; ++i) { |
- var track = this.tracks_.children[i]; |
- track.onResize(); |
- } |
- }, |
- |
- redrawAllTracks_: function() { |
- if (this.needsViewportReset_ && this.clientWidth != 0) { |
- this.needsViewportReset_ = false; |
- /* update viewport */ |
- var rangeTimestamp = this.model_.maxTimestamp - |
- this.model_.minTimestamp; |
- var w = this.firstCanvas.width; |
- console.log('viewport was reset with w=', w); |
- var scaleX = w / rangeTimestamp; |
- var panX = -this.model_.minTimestamp; |
- this.viewport_.setPanAndScale(panX, scaleX); |
- } |
- for (var i = 0; i < this.tracks_.children.length; ++i) { |
- this.tracks_.children[i].redraw(); |
- } |
- }, |
- |
- updateChildViewports_: function() { |
- for (var cI = 0; cI < this.tracks_.children.length; ++cI) { |
- var child = this.tracks_.children[cI]; |
- child.setViewport(this.panX, this.scaleX); |
- } |
- }, |
- |
- onKeypress_: function(e) { |
- var vp = this.viewport_; |
- if (!this.firstCanvas) |
- return; |
- var viewWidth = this.firstCanvas.clientWidth; |
- var curMouseV, curCenterW; |
- switch (e.keyCode) { |
- case 101: // e |
- var vX = this.lastMouseViewPos_.x; |
- var wX = vp.xViewToWorld(this.lastMouseViewPos_.x); |
- var distFromCenter = vX - (viewWidth / 2); |
- var percFromCenter = distFromCenter / viewWidth; |
- var percFromCenterSq = percFromCenter * percFromCenter; |
- vp.xPanWorldPosToViewPos(wX, 'center', viewWidth); |
- break; |
- case 119: // w |
- this.zoomBy_(1.5); |
- break; |
- case 115: // s |
- this.zoomBy_(1 / 1.5); |
- break; |
- case 103: // g |
- this.onGridToggle_(true); |
- break; |
- case 71: // G |
- this.onGridToggle_(false); |
- break; |
- case 87: // W |
- this.zoomBy_(10); |
- break; |
- case 83: // S |
- this.zoomBy_(1 / 10); |
- break; |
- case 97: // a |
- vp.panX += vp.xViewVectorToWorld(viewWidth * 0.1); |
- break; |
- case 100: // d |
- vp.panX -= vp.xViewVectorToWorld(viewWidth * 0.1); |
- break; |
- case 65: // A |
- vp.panX += vp.xViewVectorToWorld(viewWidth * 0.5); |
- break; |
- case 68: // D |
- vp.panX -= vp.xViewVectorToWorld(viewWidth * 0.5); |
- break; |
- } |
- }, |
- |
- // Not all keys send a keypress. |
- onKeydown_: function(e) { |
- switch (e.keyCode) { |
- case 37: // left arrow |
- this.selectPrevious_(e); |
- e.preventDefault(); |
- break; |
- case 39: // right arrow |
- this.selectNext_(e); |
- e.preventDefault(); |
- break; |
- case 9: // TAB |
- if (e.shiftKey) |
- this.selectPrevious_(e); |
- else |
- this.selectNext_(e); |
- e.preventDefault(); |
- break; |
- } |
- }, |
- |
- /** |
- * Zoom in or out on the timeline by the given scale factor. |
- * @param {integer} scale The scale factor to apply. If <1, zooms out. |
- */ |
- zoomBy_: function(scale) { |
- if (!this.firstCanvas) |
- return; |
- var vp = this.viewport_; |
- var viewWidth = this.firstCanvas.clientWidth; |
- var curMouseV = this.lastMouseViewPos_.x; |
- var curCenterW = vp.xViewToWorld(curMouseV); |
- vp.scaleX = vp.scaleX * scale; |
- vp.xPanWorldPosToViewPos(curCenterW, curMouseV, viewWidth); |
- }, |
- |
- /** Select the next slice on the timeline. Applies to each track. */ |
- selectNext_: function(e) { |
- this.selectAdjoining_(e, true); |
- }, |
- |
- /** Select the previous slice on the timeline. Applies to each track. */ |
- selectPrevious_: function(e) { |
- this.selectAdjoining_(e, false); |
- }, |
- |
- /** |
- * Helper for selection previous or next. |
- * @param {Event} The current event. |
- * @param {boolean} forwardp If true, select one forward (next). |
- * Else, select previous. |
- */ |
- selectAdjoining_: function(e, forwardp) { |
- var i, track, slice, adjoining; |
- var selection = []; |
- // Clear old selection; try and select next. |
- for (i = 0; i < this.selection_.length; ++i) { |
- adjoining = undefined; |
- this.selection_[i].slice.selected = false; |
- var track = this.selection_[i].track; |
- var slice = this.selection_[i].slice; |
- if (slice) { |
- if (forwardp) |
- adjoining = track.pickNext(slice); |
- else |
- adjoining = track.pickPrevious(slice); |
- } |
- if (adjoining != undefined) |
- selection.push({track: track, slice: adjoining}); |
- } |
- // Activate the new selection. |
- this.selection_ = selection; |
- for (i = 0; i < this.selection_.length; ++i) |
- this.selection_[i].slice.selected = true; |
- cr.dispatchSimpleEvent(this, 'selectionChange'); |
- this.invalidate(); // Cause tracks to redraw. |
- e.preventDefault(); |
- }, |
- |
- get keyHelp() { |
- return 'Keyboard shortcuts:\n' + |
- ' w/s : Zoom in/out (with shift: go faster)\n' + |
- ' a/d : Pan left/right\n' + |
- ' e : Center on mouse\n' + |
- ' g/G : Shows grid at the start/end of the selected task\n' + |
- ' <-,^TAB : Select previous event on current timeline\n' + |
- ' ->, TAB : Select next event on current timeline\n' + |
- '\n' + |
- 'Dbl-click to zoom in; Shift dbl-click to zoom out\n'; |
- |
- |
- }, |
- |
- get selection() { |
- return this.selection_; |
- }, |
- |
- get firstCanvas() { |
- return this.tracks_.firstChild ? |
- this.tracks_.firstChild.firstCanvas : undefined; |
- }, |
- |
- showDragBox_: function() { |
- this.dragBox_.hidden = false; |
- }, |
- |
- hideDragBox_: function() { |
- this.dragBox_.style.left = '-1000px'; |
- this.dragBox_.style.top = '-1000px'; |
- this.dragBox_.style.width = 0; |
- this.dragBox_.style.height = 0; |
- this.dragBox_.hidden = true; |
- }, |
- |
- get dragBoxVisible_() { |
- return this.dragBox_.hidden == false; |
- }, |
- |
- setDragBoxPosition_: function(eDown, eCur) { |
- var loX = Math.min(eDown.clientX, eCur.clientX); |
- var hiX = Math.max(eDown.clientX, eCur.clientX); |
- var loY = Math.min(eDown.clientY, eCur.clientY); |
- var hiY = Math.max(eDown.clientY, eCur.clientY); |
- |
- this.dragBox_.style.left = loX + 'px'; |
- this.dragBox_.style.top = loY + 'px'; |
- this.dragBox_.style.width = hiX - loX + 'px'; |
- this.dragBox_.style.height = hiY - loY + 'px'; |
- |
- var canv = this.firstCanvas; |
- var loWX = this.viewport_.xViewToWorld(loX - canv.offsetLeft); |
- var hiWX = this.viewport_.xViewToWorld(hiX - canv.offsetLeft); |
- |
- var roundedDuration = Math.round((hiWX - loWX) * 100) / 100; |
- this.dragBox_.textContent = roundedDuration + 'ms'; |
- |
- var e = new cr.Event('selectionChanging'); |
- e.loWX = loWX; |
- e.hiWX = hiWX; |
- this.dispatchEvent(e); |
- }, |
- |
- onGridToggle_: function(left) { |
- var tb; |
- if (left) |
- tb = Math.min.apply(Math, this.selection_.map( |
- function(x) { return x.slice.start; })); |
- else |
- tb = Math.max.apply(Math, this.selection_.map( |
- function(x) { return x.slice.end; })); |
- |
- // Shift the timebase left until its just left of minTimestamp. |
- var numInterfvalsSinceStart = Math.ceil((tb - this.model_.minTimestamp) / |
- this.viewport_.gridStep_); |
- this.viewport_.gridTimebase = tb - |
- (numInterfvalsSinceStart + 1) * this.viewport_.gridStep_; |
- this.viewport_.gridEnabled = true; |
- }, |
- |
- onMouseDown_: function(e) { |
- if (e.clientX < this.offsetLeft || |
- e.clientX >= this.offsetLeft + this.offsetWidth || |
- e.clientY < this.offsetTop || |
- e.clientY >= this.offsetTop + this.offsetHeight) |
- return; |
- |
- var canv = this.firstCanvas; |
- var pos = { |
- x: e.clientX - canv.offsetLeft, |
- y: e.clientY - canv.offsetTop |
- }; |
- |
- var wX = this.viewport_.xViewToWorld(pos.x); |
- |
- this.dragBeginEvent_ = e; |
- e.preventDefault(); |
- }, |
- |
- onMouseMove_: function(e) { |
- if (!this.firstCanvas) |
- return; |
- var canv = this.firstCanvas; |
- var pos = { |
- x: e.clientX - canv.offsetLeft, |
- y: e.clientY - canv.offsetTop |
- }; |
- |
- // Remember position. Used during keyboard zooming. |
- this.lastMouseViewPos_ = pos; |
- |
- // Initiate the drag box if needed. |
- if (this.dragBeginEvent_ && !this.dragBoxVisible_) { |
- this.showDragBox_(); |
- this.setDragBoxPosition_(e, e); |
- } |
- |
- // Update the drag box |
- if (this.dragBeginEvent_) { |
- this.setDragBoxPosition_(this.dragBeginEvent_, e); |
- } |
- }, |
- |
- onMouseUp_: function(e) { |
- var i; |
- if (this.dragBeginEvent_) { |
- // Stop the dragging. |
- this.hideDragBox_(); |
- var eDown = this.dragBeginEvent_; |
- this.dragBeginEvent_ = null; |
- |
- // Figure out extents of the drag. |
- var loX = Math.min(eDown.clientX, e.clientX); |
- var hiX = Math.max(eDown.clientX, e.clientX); |
- var loY = Math.min(eDown.clientY, e.clientY); |
- var hiY = Math.max(eDown.clientY, e.clientY); |
- |
- // Convert to worldspace. |
- var canv = this.firstCanvas; |
- var loWX = this.viewport_.xViewToWorld(loX - canv.offsetLeft); |
- var hiWX = this.viewport_.xViewToWorld(hiX - canv.offsetLeft); |
- |
- // Clear old selection. |
- for (i = 0; i < this.selection_.length; ++i) { |
- this.selection_[i].slice.selected = false; |
- } |
- |
- // Figure out what has been hit. |
- var selection = []; |
- function addHit(type, track, slice) { |
- selection.push({track: track, slice: slice}); |
- } |
- for (i = 0; i < this.tracks_.children.length; ++i) { |
- var track = this.tracks_.children[i]; |
- |
- // Only check tracks that insersect the rect. |
- var trackClientRect = track.getBoundingClientRect(); |
- var a = Math.max(loY, trackClientRect.top); |
- var b = Math.min(hiY, trackClientRect.bottom); |
- if (a <= b) { |
- track.pickRange(loWX, hiWX, loY, hiY, addHit); |
- } |
- } |
- // Activate the new selection. |
- this.selection_ = selection; |
- cr.dispatchSimpleEvent(this, 'selectionChange'); |
- for (i = 0; i < this.selection_.length; ++i) { |
- this.selection_[i].slice.selected = true; |
- } |
- this.invalidate(); // Cause tracks to redraw. |
- } |
- }, |
- |
- onDblClick_: function(e) { |
- var scale = 4; |
- if (e.shiftKey) |
- scale = 1 / scale; |
- this.zoomBy_(scale); |
- e.preventDefault(); |
- }, |
- }; |
- |
- /** |
- * The TimelineModel being viewed by the timeline |
- * @type {TimelineModel} |
- */ |
- cr.defineProperty(Timeline, 'model', cr.PropertyKind.JS); |
- |
- return { |
- Timeline: Timeline |
- }; |
-}); |