blob: 71d65cfd200e0ab78214f88e206bf8c47c1b279e [file] [log] [blame]
/*
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008, 2009 Anthony Ricaud <rik@webkit.org>
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @constructor
* @param {number} minimum
* @param {number} maximum
*/
WebInspector.NetworkTimeBoundary = function(minimum, maximum)
{
this.minimum = minimum;
this.maximum = maximum;
}
WebInspector.NetworkTimeBoundary.prototype = {
/**
* @param {!WebInspector.NetworkTimeBoundary} other
* @return {boolean}
*/
equals: function(other)
{
return (this.minimum === other.minimum) && (this.maximum === other.maximum);
}
}
/**
* @constructor
* @extends {WebInspector.Object}
* @implements {WebInspector.TimelineGrid.Calculator}
*/
WebInspector.NetworkTimeCalculator = function(startAtZero)
{
this.startAtZero = startAtZero;
this._boundryChangedEventThrottler = new WebInspector.Throttler(0);
/** @type {?WebInspector.NetworkTimeBoundary} */
this._window = null;
}
/** @enum {string} */
WebInspector.NetworkTimeCalculator.Events = {
BoundariesChanged: "BoundariesChanged"
}
/** @type {!WebInspector.UIStringFormat} */
WebInspector.NetworkTimeCalculator._latencyDownloadTotalFormat = new WebInspector.UIStringFormat("%s latency, %s download (%s total)");
/** @type {!WebInspector.UIStringFormat} */
WebInspector.NetworkTimeCalculator._latencyFormat = new WebInspector.UIStringFormat("%s latency");
/** @type {!WebInspector.UIStringFormat} */
WebInspector.NetworkTimeCalculator._downloadFormat = new WebInspector.UIStringFormat("%s download");
/** @type {!WebInspector.UIStringFormat} */
WebInspector.NetworkTimeCalculator._fromServiceWorkerFormat = new WebInspector.UIStringFormat("%s (from ServiceWorker)");
/** @type {!WebInspector.UIStringFormat} */
WebInspector.NetworkTimeCalculator._fromCacheFormat = new WebInspector.UIStringFormat("%s (from cache)");
WebInspector.NetworkTimeCalculator.prototype = {
/**
* @param {?WebInspector.NetworkTimeBoundary} window
*/
setWindow: function(window)
{
this._window = window;
this._boundaryChanged();
},
setInitialUserFriendlyBoundaries: function()
{
this._minimumBoundary = 0;
this._maximumBoundary = 1;
},
/**
* @override
* @return {number}
*/
paddingLeft: function()
{
return 0;
},
/**
* @override
* @param {number} time
* @return {number}
*/
computePosition: function(time)
{
return (time - this.minimumBoundary()) / this.boundarySpan() * this._workingArea;
},
/**
* @override
* @param {number} value
* @param {number=} precision
* @return {string}
*/
formatTime: function(value, precision)
{
return Number.secondsToString(value, !!precision);
},
/**
* @override
* @return {number}
*/
minimumBoundary: function()
{
return this._window ? this._window.minimum : this._minimumBoundary;
},
/**
* @override
* @return {number}
*/
zeroTime: function()
{
return this._minimumBoundary;
},
/**
* @override
* @return {number}
*/
maximumBoundary: function()
{
return this._window ? this._window.maximum : this._maximumBoundary;
},
/**
* @return {!WebInspector.NetworkTimeBoundary}
*/
boundary: function()
{
return new WebInspector.NetworkTimeBoundary(this.minimumBoundary(), this.maximumBoundary());
},
/**
* @override
* @return {number}
*/
boundarySpan: function()
{
return this.maximumBoundary() - this.minimumBoundary();
},
reset: function()
{
delete this._minimumBoundary;
delete this._maximumBoundary;
this._boundaryChanged();
},
/**
* @return {number}
*/
_value: function(item)
{
return 0;
},
/**
* @param {number} clientWidth
*/
setDisplayWindow: function(clientWidth)
{
this._workingArea = clientWidth;
},
/**
* @param {!WebInspector.NetworkRequest} request
* @return {!{start: number, middle: number, end: number}}
*/
computeBarGraphPercentages: function(request)
{
if (request.startTime !== -1)
var start = ((request.startTime - this.minimumBoundary()) / this.boundarySpan()) * 100;
else
var start = 0;
if (request.responseReceivedTime !== -1)
var middle = ((request.responseReceivedTime - this.minimumBoundary()) / this.boundarySpan()) * 100;
else
var middle = (this.startAtZero ? start : 100);
if (request.endTime !== -1)
var end = ((request.endTime - this.minimumBoundary()) / this.boundarySpan()) * 100;
else
var end = (this.startAtZero ? middle : 100);
if (this.startAtZero) {
end -= start;
middle -= start;
start = 0;
}
return {start: start, middle: middle, end: end};
},
/**
* @param {number} eventTime
* @return {number}
*/
computePercentageFromEventTime: function(eventTime)
{
// This function computes a percentage in terms of the total loading time
// of a specific event. If startAtZero is set, then this is useless, and we
// want to return 0.
if (eventTime !== -1 && !this.startAtZero)
return ((eventTime - this.minimumBoundary()) / this.boundarySpan()) * 100;
return 0;
},
/**
* @param {number} percentage
* @return {number}
*/
percentageToTime: function(percentage)
{
return percentage * this.boundarySpan() / 100 + this.minimumBoundary();
},
_boundaryChanged: function()
{
this._boundryChangedEventThrottler.schedule(dispatchEvent.bind(this));
/**
* @return {!Promise.<undefined>}
* @this {WebInspector.NetworkTimeCalculator}
*/
function dispatchEvent()
{
this.dispatchEventToListeners(WebInspector.NetworkTimeCalculator.Events.BoundariesChanged);
return Promise.resolve();
}
},
/**
* @param {number} eventTime
*/
updateBoundariesForEventTime: function(eventTime)
{
if (eventTime === -1 || this.startAtZero)
return;
if (this._maximumBoundary === undefined || eventTime > this._maximumBoundary) {
this._maximumBoundary = eventTime;
this._boundaryChanged();
}
},
/**
* @param {!WebInspector.NetworkRequest} request
* @return {!{left: string, right: string, tooltip: (string|undefined)}}
*/
computeBarGraphLabels: function(request)
{
var rightLabel = "";
if (request.responseReceivedTime !== -1 && request.endTime !== -1)
rightLabel = Number.secondsToString(request.endTime - request.responseReceivedTime);
var hasLatency = request.latency > 0;
if (hasLatency)
var leftLabel = Number.secondsToString(request.latency);
else
var leftLabel = rightLabel;
if (request.timing)
return {left: leftLabel, right: rightLabel};
if (hasLatency && rightLabel) {
var total = Number.secondsToString(request.duration);
var tooltip = WebInspector.NetworkTimeCalculator._latencyDownloadTotalFormat.format(leftLabel, rightLabel, total);
} else if (hasLatency) {
var tooltip = WebInspector.NetworkTimeCalculator._latencyFormat.format(leftLabel);
} else if (rightLabel) {
var tooltip = WebInspector.NetworkTimeCalculator._downloadFormat.format(rightLabel);
}
if (request.fetchedViaServiceWorker)
tooltip = WebInspector.NetworkTimeCalculator._fromServiceWorkerFormat.format(tooltip);
else if (request.cached())
tooltip = WebInspector.NetworkTimeCalculator._fromCacheFormat.format(tooltip);
return {left: leftLabel, right: rightLabel, tooltip: tooltip};
},
/**
* @param {!WebInspector.NetworkRequest} request
*/
updateBoundaries: function(request)
{
var lowerBound = this._lowerBound(request);
var upperBound = this._upperBound(request);
var changed = false;
if (lowerBound !== -1 || this.startAtZero)
changed = this._extendBoundariesToIncludeTimestamp(this.startAtZero ? 0 : lowerBound);
if (upperBound !== -1)
changed = this._extendBoundariesToIncludeTimestamp(upperBound) || changed;
if (changed)
this._boundaryChanged();
},
/**
* @param {number} timestamp
* @return {boolean}
*/
_extendBoundariesToIncludeTimestamp: function(timestamp)
{
var previousMinimumBoundary = this._minimumBoundary;
var previousMaximumBoundary = this._maximumBoundary;
if (typeof this._minimumBoundary === "undefined" || typeof this._maximumBoundary === "undefined") {
this._minimumBoundary = timestamp;
this._maximumBoundary = timestamp + 1;
} else {
this._minimumBoundary = Math.min(timestamp, this._minimumBoundary);
this._maximumBoundary = Math.max(timestamp, this._minimumBoundary + 1, this._maximumBoundary);
}
return previousMinimumBoundary !== this._minimumBoundary || previousMaximumBoundary !== this._maximumBoundary;
},
/**
* @param {!WebInspector.NetworkRequest} request
* @return {number}
*/
_lowerBound: function(request)
{
return 0;
},
/**
* @param {!WebInspector.NetworkRequest} request
* @return {number}
*/
_upperBound: function(request)
{
return 0;
},
__proto__: WebInspector.Object.prototype
}
/**
* @constructor
* @extends {WebInspector.NetworkTimeCalculator}
*/
WebInspector.NetworkTransferTimeCalculator = function()
{
WebInspector.NetworkTimeCalculator.call(this, false);
}
WebInspector.NetworkTransferTimeCalculator.prototype = {
/**
* @override
* @param {number} value
* @param {number=} precision
* @return {string}
*/
formatTime: function(value, precision)
{
return Number.secondsToString(value - this.zeroTime(), !!precision);
},
/**
* @override
* @param {!WebInspector.NetworkRequest} request
* @return {number}
*/
_lowerBound: function(request)
{
return request.issueTime();
},
/**
* @override
* @param {!WebInspector.NetworkRequest} request
* @return {number}
*/
_upperBound: function(request)
{
return request.endTime;
},
__proto__: WebInspector.NetworkTimeCalculator.prototype
}
/**
* @constructor
* @extends {WebInspector.NetworkTimeCalculator}
*/
WebInspector.NetworkTransferDurationCalculator = function()
{
WebInspector.NetworkTimeCalculator.call(this, true);
}
WebInspector.NetworkTransferDurationCalculator.prototype = {
/**
* @override
* @param {number} value
* @param {number=} precision
* @return {string}
*/
formatTime: function(value, precision)
{
return Number.secondsToString(value, !!precision);
},
/**
* @override
* @param {!WebInspector.NetworkRequest} request
* @return {number}
*/
_upperBound: function(request)
{
return request.duration;
},
__proto__: WebInspector.NetworkTimeCalculator.prototype
}