--- a/browser/devtools/shared/test/browser.ini
+++ b/browser/devtools/shared/test/browser.ini
@@ -19,19 +19,17 @@ support-files =
[browser_graphs-02.js]
[browser_graphs-03.js]
[browser_graphs-04.js]
[browser_graphs-05.js]
[browser_graphs-06.js]
[browser_graphs-07a.js]
[browser_graphs-07b.js]
[browser_graphs-08.js]
-[browser_graphs-09a.js]
-[browser_graphs-09b.js]
-[browser_graphs-09c.js]
+[browser_graphs-09.js]
[browser_graphs-10a.js]
[browser_graphs-10b.js]
[browser_graphs-11a.js]
[browser_graphs-11b.js]
[browser_graphs-12.js]
[browser_graphs-13.js]
[browser_graphs-14.js]
[browser_inplace-editor.js]
rename from browser/devtools/shared/test/browser_graphs-09a.js
rename to browser/devtools/shared/test/browser_graphs-09.js
--- a/browser/devtools/shared/test/browser_graphs-09a.js
+++ b/browser/devtools/shared/test/browser_graphs-09.js
@@ -22,47 +22,31 @@ function* performTest() {
yield testGraph(graph);
graph.destroy();
host.destroy();
}
function* testGraph(graph) {
- info("Should be able to set the graph data before waiting for the ready event.");
+ info("Should be able to set the grpah data before waiting for the ready event.");
yield graph.setDataWhenReady(TEST_DATA);
ok(graph.hasData(), "Data was set successfully.");
- is(graph._gutter.hidden, false,
- "The gutter should not be hidden because the tooltips have arrows.");
- is(graph._maxTooltip.hidden, false,
- "The max tooltip should not be hidden.");
- is(graph._avgTooltip.hidden, false,
- "The avg tooltip should not be hidden.");
- is(graph._minTooltip.hidden, false,
- "The min tooltip should not be hidden.");
-
- is(graph._maxTooltip.getAttribute("with-arrows"), "true",
- "The maximum tooltip has the correct 'with-arrows' attribute.");
- is(graph._avgTooltip.getAttribute("with-arrows"), "true",
- "The average tooltip has the correct 'with-arrows' attribute.");
- is(graph._minTooltip.getAttribute("with-arrows"), "true",
- "The minimum tooltip has the correct 'with-arrows' attribute.");
-
is(graph._maxTooltip.querySelector("[text=info]").textContent, "max",
"The maximum tooltip displays the correct info.");
is(graph._avgTooltip.querySelector("[text=info]").textContent, "avg",
"The average tooltip displays the correct info.");
is(graph._minTooltip.querySelector("[text=info]").textContent, "min",
"The minimum tooltip displays the correct info.");
is(graph._maxTooltip.querySelector("[text=value]").textContent, "60",
"The maximum tooltip displays the correct value.");
- is(graph._avgTooltip.querySelector("[text=value]").textContent, "41.71",
+ is(graph._avgTooltip.querySelector("[text=value]").textContent, "41",
"The average tooltip displays the correct value.");
is(graph._minTooltip.querySelector("[text=value]").textContent, "10",
"The minimum tooltip displays the correct value.");
is(graph._maxTooltip.querySelector("[text=metric]").textContent, "fps",
"The maximum tooltip displays the correct metric.");
is(graph._avgTooltip.querySelector("[text=metric]").textContent, "fps",
"The average tooltip displays the correct metric.");
deleted file mode 100644
--- a/browser/devtools/shared/test/browser_graphs-09b.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-// Tests that line graphs properly use the tooltips configuration properties.
-
-const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
-let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
-let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
-
-let test = Task.async(function*() {
- yield promiseTab("about:blank");
- yield performTest();
- gBrowser.removeCurrentTab();
- finish();
-});
-
-function* performTest() {
- let [host, win, doc] = yield createHost();
- let graph = new LineGraphWidget(doc.body, "fps");
- graph.withTooltipArrows = false;
- graph.withFixedTooltipPositions = true;
-
- yield testGraph(graph);
-
- graph.destroy();
- host.destroy();
-}
-
-function* testGraph(graph) {
- yield graph.setDataWhenReady(TEST_DATA);
-
- is(graph._gutter.hidden, true,
- "The gutter should be hidden because the tooltips don't have arrows.");
- is(graph._maxTooltip.hidden, false,
- "The max tooltip should not be hidden.");
- is(graph._avgTooltip.hidden, false,
- "The avg tooltip should not be hidden.");
- is(graph._minTooltip.hidden, false,
- "The min tooltip should not be hidden.");
-
- is(graph._maxTooltip.getAttribute("with-arrows"), "false",
- "The maximum tooltip has the correct 'with-arrows' attribute.");
- is(graph._avgTooltip.getAttribute("with-arrows"), "false",
- "The average tooltip has the correct 'with-arrows' attribute.");
- is(graph._minTooltip.getAttribute("with-arrows"), "false",
- "The minimum tooltip has the correct 'with-arrows' attribute.");
-
- is(parseInt(graph._maxTooltip.style.top), 8,
- "The maximum tooltip is positioned correctly.");
- is(parseInt(graph._avgTooltip.style.top), 8,
- "The average tooltip is positioned correctly.");
- is(parseInt(graph._minTooltip.style.top), 142,
- "The minimum tooltip is positioned correctly.");
-
- is(parseInt(graph._maxGutterLine.style.top), 22,
- "The maximum gutter line is positioned correctly.");
- is(parseInt(graph._avgGutterLine.style.top), 61,
- "The average gutter line is positioned correctly.");
- is(parseInt(graph._minGutterLine.style.top), 128,
- "The minimum gutter line is positioned correctly.");
-}
deleted file mode 100644
--- a/browser/devtools/shared/test/browser_graphs-09c.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-// Tests that line graphs hide the tooltips when there's no data available.
-
-const TEST_DATA = [];
-let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
-let {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
-let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
-let {Hosts} = devtools.require("devtools/framework/toolbox-hosts");
-
-let test = Task.async(function*() {
- yield promiseTab("about:blank");
- yield performTest();
- gBrowser.removeCurrentTab();
- finish();
-});
-
-function* performTest() {
- let [host, win, doc] = yield createHost();
- let graph = new LineGraphWidget(doc.body, "fps");
-
- yield testGraph(graph);
-
- graph.destroy();
- host.destroy();
-}
-
-function* testGraph(graph) {
- yield graph.setDataWhenReady(TEST_DATA);
-
- is(graph._gutter.hidden, false,
- "The gutter should not be hidden.");
- is(graph._maxTooltip.hidden, true,
- "The max tooltip should be hidden.");
- is(graph._avgTooltip.hidden, true,
- "The avg tooltip should be hidden.");
- is(graph._minTooltip.hidden, true,
- "The min tooltip should be hidden.");
-}
--- a/browser/devtools/shared/widgets/Graphs.jsm
+++ b/browser/devtools/shared/widgets/Graphs.jsm
@@ -14,17 +14,16 @@ this.EXPORTED_SYMBOLS = [
"AbstractCanvasGraph",
"LineGraphWidget",
"BarGraphWidget",
"CanvasGraphUtils"
];
const HTML_NS = "http://www.w3.org/1999/xhtml";
const GRAPH_SRC = "chrome://browser/content/devtools/graphs-frame.xhtml";
-const L10N = new ViewHelpers.L10N();
// Generic constants.
const GRAPH_RESIZE_EVENTS_DRAIN = 100; // ms
const GRAPH_WHEEL_ZOOM_SENSITIVITY = 0.00075;
const GRAPH_WHEEL_SCROLL_SENSITIVITY = 0.1;
const GRAPH_WHEEL_MIN_SELECTION_WIDTH = 10; // px
@@ -40,19 +39,18 @@ const GRAPH_STRIPE_PATTERN_WIDTH = 16; /
const GRAPH_STRIPE_PATTERN_HEIGHT = 16; // px
const GRAPH_STRIPE_PATTERN_LINE_WIDTH = 2; // px
const GRAPH_STRIPE_PATTERN_LINE_SPACING = 4; // px
// Line graph constants.
const LINE_GRAPH_DAMPEN_VALUES = 0.85;
const LINE_GRAPH_MIN_SQUARED_DISTANCE_BETWEEN_POINTS = 400; // 20 px
-const LINE_GRAPH_TOOLTIP_SAFE_BOUNDS = 8; // px
+const LINE_GRAPH_TOOLTIP_SAFE_BOUNDS = 10; // px
-const LINE_GRAPH_BACKGROUND_COLOR = "#0088cc";
const LINE_GRAPH_STROKE_WIDTH = 1; // px
const LINE_GRAPH_STROKE_COLOR = "rgba(255,255,255,0.9)";
const LINE_GRAPH_HELPER_LINES_DASH = [5]; // px
const LINE_GRAPH_HELPER_LINES_WIDTH = 1; // px
const LINE_GRAPH_MAXIMUM_LINE_COLOR = "rgba(255,255,255,0.4)";
const LINE_GRAPH_AVERAGE_LINE_COLOR = "rgba(255,255,255,0.7)";
const LINE_GRAPH_MINIMUM_LINE_COLOR = "rgba(255,255,255,0.9)";
const LINE_GRAPH_BACKGROUND_GRADIENT_START = "rgba(255,255,255,0.25)";
@@ -484,28 +482,26 @@ AbstractCanvasGraph.prototype = {
this.emit("deselecting");
},
/**
* Gets whether or not this graph has a selection.
* @return boolean
*/
hasSelection: function() {
- return this._selection &&
- this._selection.start != null && this._selection.end != null;
+ return this._selection.start != null && this._selection.end != null;
},
/**
* Gets whether or not a selection is currently being made, for example
* via a click+drag operation.
* @return boolean
*/
hasSelectionInProgress: function() {
- return this._selection &&
- this._selection.start != null && this._selection.end == null;
+ return this._selection.start != null && this._selection.end == null;
},
/**
* Specifies whether or not mouse selection is allowed.
* @type boolean
*/
selectionEnabled: true,
@@ -551,17 +547,17 @@ AbstractCanvasGraph.prototype = {
this._shouldRedraw = true;
},
/**
* Gets whether or not this graph has a visible cursor.
* @return boolean
*/
hasCursor: function() {
- return this._cursor && this._cursor.x != null;
+ return this._cursor.x != null;
},
/**
* Specifies if this graph's selection is different from another one.
*
* @param object other
* The other graph's selection, as { start, end } values.
*/
@@ -1175,104 +1171,76 @@ this.LineGraphWidget = function(parent,
this._minGutterLine = this._createGutterLine("minimum");
this._maxTooltip = this._createTooltip("maximum", "start", "max", metric);
this._avgTooltip = this._createTooltip("average", "end", "avg", metric);
this._minTooltip = this._createTooltip("minimum", "start", "min", metric);
});
}
LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
- backgroundColor: LINE_GRAPH_BACKGROUND_COLOR,
- backgroundGradientStart: LINE_GRAPH_BACKGROUND_GRADIENT_START,
- backgroundGradientEnd: LINE_GRAPH_BACKGROUND_GRADIENT_END,
- strokeColor: LINE_GRAPH_STROKE_COLOR,
- strokeWidth: LINE_GRAPH_STROKE_WIDTH,
- maximumLineColor: LINE_GRAPH_MAXIMUM_LINE_COLOR,
- averageLineColor: LINE_GRAPH_AVERAGE_LINE_COLOR,
- minimumLineColor: LINE_GRAPH_MINIMUM_LINE_COLOR,
clipheadLineColor: LINE_GRAPH_CLIPHEAD_LINE_COLOR,
selectionLineColor: LINE_GRAPH_SELECTION_LINE_COLOR,
selectionBackgroundColor: LINE_GRAPH_SELECTION_BACKGROUND_COLOR,
selectionStripesColor: LINE_GRAPH_SELECTION_STRIPES_COLOR,
regionBackgroundColor: LINE_GRAPH_REGION_BACKGROUND_COLOR,
regionStripesColor: LINE_GRAPH_REGION_STRIPES_COLOR,
/**
* Optionally offsets the `delta` in the data source by this scalar.
*/
dataOffsetX: 0,
/**
- * The scalar used to multiply the graph values to leave some headroom
- * on the top.
- */
- dampenValuesFactor: LINE_GRAPH_DAMPEN_VALUES,
-
- /**
* Points that are too close too each other in the graph will not be rendered.
* This scalar specifies the required minimum squared distance between points.
*/
minDistanceBetweenPoints: LINE_GRAPH_MIN_SQUARED_DISTANCE_BETWEEN_POINTS,
/**
- * Specifies if min/max/avg tooltips have arrow handlers on their sides.
- */
- withTooltipArrows: true,
-
- /**
- * Specifies if min/max/avg tooltips are positioned based on the actual
- * values, or just placed next to the graph corners.
- */
- withFixedTooltipPositions: false,
-
- /**
* Renders the graph's data source.
* @see AbstractCanvasGraph.prototype.buildGraphImage
*/
buildGraphImage: function() {
let { canvas, ctx } = this._getNamedCanvas("line-graph-data");
let width = this._width;
let height = this._height;
let totalTicks = this._data.length;
- let firstTick = totalTicks ? this._data[0].delta : 0;
- let lastTick = totalTicks ? this._data[totalTicks - 1].delta : 0;
+ let firstTick = this._data[0].delta;
+ let lastTick = this._data[totalTicks - 1].delta;
let maxValue = Number.MIN_SAFE_INTEGER;
let minValue = Number.MAX_SAFE_INTEGER;
let sumValues = 0;
for (let { delta, value } of this._data) {
maxValue = Math.max(value, maxValue);
minValue = Math.min(value, minValue);
sumValues += value;
}
let dataScaleX = this.dataScaleX = width / (lastTick - this.dataOffsetX);
- let dataScaleY = this.dataScaleY = height / maxValue * this.dampenValuesFactor;
+ let dataScaleY = this.dataScaleY = height / maxValue * LINE_GRAPH_DAMPEN_VALUES;
/**
* Calculates the squared distance between two 2D points.
*/
function distSquared(x0, y0, x1, y1) {
let xs = x1 - x0;
let ys = y1 - y0;
return xs * xs + ys * ys;
}
// Draw the graph.
- ctx.fillStyle = this.backgroundColor;
- ctx.fillRect(0, 0, width, height);
-
let gradient = ctx.createLinearGradient(0, height / 2, 0, height);
- gradient.addColorStop(0, this.backgroundGradientStart);
- gradient.addColorStop(1, this.backgroundGradientEnd);
+ gradient.addColorStop(0, LINE_GRAPH_BACKGROUND_GRADIENT_START);
+ gradient.addColorStop(1, LINE_GRAPH_BACKGROUND_GRADIENT_END);
ctx.fillStyle = gradient;
- ctx.strokeStyle = this.strokeColor;
- ctx.lineWidth = this.strokeWidth * this._pixelRatio;
+ ctx.strokeStyle = LINE_GRAPH_STROKE_COLOR;
+ ctx.lineWidth = LINE_GRAPH_STROKE_WIDTH * this._pixelRatio;
ctx.beginPath();
let prevX = 0;
let prevY = 0;
for (let { delta, value } of this._data) {
let currX = (delta - this.dataOffsetX) * dataScaleX;
let currY = height - value * dataScaleY;
@@ -1295,93 +1263,77 @@ LineGraphWidget.prototype = Heritage.ext
}
}
ctx.fill();
ctx.stroke();
// Draw the maximum value horizontal line.
- ctx.strokeStyle = this.maximumLineColor;
+ ctx.strokeStyle = LINE_GRAPH_MAXIMUM_LINE_COLOR;
ctx.lineWidth = LINE_GRAPH_HELPER_LINES_WIDTH;
ctx.setLineDash(LINE_GRAPH_HELPER_LINES_DASH);
ctx.beginPath();
- let maximumY = height - maxValue * dataScaleY;
+ let maximumY = height - maxValue * dataScaleY - ctx.lineWidth;
ctx.moveTo(0, maximumY);
ctx.lineTo(width, maximumY);
ctx.stroke();
// Draw the average value horizontal line.
- ctx.strokeStyle = this.averageLineColor;
+ ctx.strokeStyle = LINE_GRAPH_AVERAGE_LINE_COLOR;
ctx.lineWidth = LINE_GRAPH_HELPER_LINES_WIDTH;
ctx.setLineDash(LINE_GRAPH_HELPER_LINES_DASH);
ctx.beginPath();
- let avgValue = totalTicks ? sumValues / totalTicks : 0;
- let averageY = height - avgValue * dataScaleY;
+ let avgValue = sumValues / totalTicks;
+ let averageY = height - avgValue * dataScaleY - ctx.lineWidth;
ctx.moveTo(0, averageY);
ctx.lineTo(width, averageY);
ctx.stroke();
// Draw the minimum value horizontal line.
- ctx.strokeStyle = this.minimumLineColor;
+ ctx.strokeStyle = LINE_GRAPH_MINIMUM_LINE_COLOR;
ctx.lineWidth = LINE_GRAPH_HELPER_LINES_WIDTH;
ctx.setLineDash(LINE_GRAPH_HELPER_LINES_DASH);
ctx.beginPath();
- let minimumY = height - minValue * dataScaleY;
+ let minimumY = height - minValue * dataScaleY - ctx.lineWidth;
ctx.moveTo(0, minimumY);
ctx.lineTo(width, minimumY);
ctx.stroke();
// Update the tooltips text and gutter lines.
- this._maxTooltip.querySelector("[text=value]").textContent =
- L10N.numberWithDecimals(maxValue, 2);
- this._avgTooltip.querySelector("[text=value]").textContent =
- L10N.numberWithDecimals(avgValue, 2);
- this._minTooltip.querySelector("[text=value]").textContent =
- L10N.numberWithDecimals(minValue, 2);
+ this._maxTooltip.querySelector("[text=value]").textContent = maxValue|0;
+ this._avgTooltip.querySelector("[text=value]").textContent = avgValue|0;
+ this._minTooltip.querySelector("[text=value]").textContent = minValue|0;
/**
* Constrains a value to a range.
*/
function clamp(value, min, max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
let bottom = height / this._pixelRatio;
- let maxPosY = map(maxValue * this.dampenValuesFactor, 0, maxValue, bottom, 0);
- let avgPosY = map(avgValue * this.dampenValuesFactor, 0, maxValue, bottom, 0);
- let minPosY = map(minValue * this.dampenValuesFactor, 0, maxValue, bottom, 0);
+ let maxPosY = map(maxValue * LINE_GRAPH_DAMPEN_VALUES, 0, maxValue, bottom, 0);
+ let avgPosY = map(avgValue * LINE_GRAPH_DAMPEN_VALUES, 0, maxValue, bottom, 0);
+ let minPosY = map(minValue * LINE_GRAPH_DAMPEN_VALUES, 0, maxValue, bottom, 0);
let safeTop = LINE_GRAPH_TOOLTIP_SAFE_BOUNDS;
let safeBottom = bottom - LINE_GRAPH_TOOLTIP_SAFE_BOUNDS;
- this._maxTooltip.style.top = (this.withFixedTooltipPositions
- ? safeTop : clamp(maxPosY, safeTop, safeBottom)) + "px";
- this._avgTooltip.style.top = (this.withFixedTooltipPositions
- ? safeTop : clamp(avgPosY, safeTop, safeBottom)) + "px";
- this._minTooltip.style.top = (this.withFixedTooltipPositions
- ? safeBottom : clamp(minPosY, safeTop, safeBottom)) + "px";
-
- this._maxGutterLine.style.top = maxPosY + "px";
- this._avgGutterLine.style.top = avgPosY + "px";
- this._minGutterLine.style.top = minPosY + "px";
-
- this._maxTooltip.setAttribute("with-arrows", this.withTooltipArrows);
- this._avgTooltip.setAttribute("with-arrows", this.withTooltipArrows);
- this._minTooltip.setAttribute("with-arrows", this.withTooltipArrows);
-
- this._gutter.hidden = !this.withTooltipArrows;
- this._maxTooltip.hidden = !totalTicks;
- this._avgTooltip.hidden = !totalTicks;
- this._minTooltip.hidden = !totalTicks;
+ this._maxTooltip.style.top = clamp(maxPosY, safeTop, safeBottom) + "px";
+ this._avgTooltip.style.top = clamp(avgPosY, safeTop, safeBottom) + "px";
+ this._minTooltip.style.top = clamp(minPosY, safeTop, safeBottom) + "px";
+ this._maxGutterLine.style.top = clamp(maxPosY, safeTop, safeBottom) + "px";
+ this._avgGutterLine.style.top = clamp(avgPosY, safeTop, safeBottom) + "px";
+ this._minGutterLine.style.top = clamp(minPosY, safeTop, safeBottom) + "px";
return canvas;
},
/**
* Creates the gutter node when constructing this graph.
* @return nsIDOMNode
*/
@@ -1510,22 +1462,16 @@ BarGraphWidget.prototype = Heritage.exte
format: null,
/**
* Optionally offsets the `delta` in the data source by this scalar.
*/
dataOffsetX: 0,
/**
- * The scalar used to multiply the graph values to leave some headroom
- * on the top.
- */
- dampenValuesFactor: BAR_GRAPH_DAMPEN_VALUES,
-
- /**
* Bars that are too close too each other in the graph will be combined.
* This scalar specifies the required minimum width of each bar.
*/
minBarsWidth: BAR_GRAPH_MIN_BARS_WIDTH,
/**
* Blocks in a bar that are too thin inside the bar will not be rendered.
* This scalar specifies the required minimum height of each block.
@@ -1569,17 +1515,17 @@ BarGraphWidget.prototype = Heritage.exte
let minBarsWidth = this.minBarsWidth * this._pixelRatio;
let minBlocksHeight = this.minBlocksHeight * this._pixelRatio;
let dataScaleX = this.dataScaleX = width / (lastTick - this.dataOffsetX);
let dataScaleY = this.dataScaleY = height / this._calcMaxHeight({
data: this._data,
dataScaleX: dataScaleX,
minBarsWidth: minBarsWidth
- }) * this.dampenValuesFactor;
+ }) * BAR_GRAPH_DAMPEN_VALUES;
// Draw the graph.
// Iterate over the blocks, then the bars, to draw all rectangles of
// the same color in a single pass. See the @constructor for more
// information about the data source, and how a "bar" contains "blocks".
this._blocksBoundingRects = [];
@@ -1972,23 +1918,16 @@ this.CanvasGraphUtils = {
/**
* Makes sure selections in one graph are reflected in another.
*/
linkSelection: function(graph1, graph2) {
if (!graph1 || !graph2) {
return;
}
-
- if (graph1.hasSelection()) {
- graph2.setSelection(graph1.getSelection());
- } else {
- graph2.dropSelection();
- }
-
graph1.on("selecting", () => {
graph2.setSelection(graph1.getSelection());
});
graph2.on("selecting", () => {
graph1.setSelection(graph2.getSelection());
});
graph1.on("deselecting", () => {
graph2.dropSelection();
--- a/browser/devtools/timeline/moz.build
+++ b/browser/devtools/timeline/moz.build
@@ -1,14 +1,13 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXTRA_JS_MODULES.devtools.timeline += [
'panel.js',
'widgets/global.js',
- 'widgets/markers-overview.js',
- 'widgets/memory-overview.js',
+ 'widgets/overview.js',
'widgets/waterfall.js'
]
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
--- a/browser/devtools/timeline/test/browser.ini
+++ b/browser/devtools/timeline/test/browser.ini
@@ -4,15 +4,13 @@ support-files =
doc_simple-test.html
head.js
[browser_timeline_aaa_run_first_leaktest.js]
[browser_timeline_blueprint.js]
[browser_timeline_overview-initial-selection-01.js]
[browser_timeline_overview-initial-selection-02.js]
[browser_timeline_overview-update.js]
-skip-if = debug # Bug 1096256
[browser_timeline_panels.js]
-[browser_timeline_recording-without-memory.js]
[browser_timeline_recording.js]
[browser_timeline_waterfall-background.js]
[browser_timeline_waterfall-generic.js]
[browser_timeline_waterfall-styles.js]
--- a/browser/devtools/timeline/test/browser_timeline_overview-initial-selection-01.js
+++ b/browser/devtools/timeline/test/browser_timeline_overview-initial-selection-01.js
@@ -3,45 +3,39 @@
/**
* Tests if the overview has an initial selection when recording has finished
* and there is data available.
*/
let test = Task.async(function*() {
let { target, panel } = yield initTimelinePanel(SIMPLE_URL);
- let { $, EVENTS, TimelineView, TimelineController } = panel.panelWin;
+ let { EVENTS, TimelineView, TimelineController } = panel.panelWin;
let { OVERVIEW_INITIAL_SELECTION_RATIO: selectionRatio } = panel.panelWin;
- $("#memory-checkbox").checked = true;
- yield TimelineController.updateMemoryRecording();
-
yield TimelineController.toggleRecording();
ok(true, "Recording has started.");
let updated = 0;
panel.panelWin.on(EVENTS.OVERVIEW_UPDATED, () => updated++);
ok((yield waitUntil(() => updated > 10)),
"The overview graph was updated a bunch of times.");
ok((yield waitUntil(() => TimelineController.getMarkers().length > 0)),
"There are some markers available.");
- ok((yield waitUntil(() => TimelineController.getMemory().length > 0)),
- "There are some memory measurements available now.");
yield TimelineController.toggleRecording();
ok(true, "Recording has ended.");
- let interval = TimelineController.getInterval();
let markers = TimelineController.getMarkers();
- let selection = TimelineView.markersOverview.getSelection();
+ let selection = TimelineView.overview.getSelection();
is((selection.start) | 0,
- ((markers[0].start - interval.startTime) * TimelineView.markersOverview.dataScaleX) | 0,
+ ((markers[0].start - markers.startTime) * TimelineView.overview.dataScaleX) | 0,
"The initial selection start is correct.");
is((selection.end - selection.start) | 0,
- (selectionRatio * TimelineView.markersOverview.width) | 0,
+ (selectionRatio * TimelineView.overview.width) | 0,
"The initial selection end is correct.");
yield teardown(panel);
finish();
});
--- a/browser/devtools/timeline/test/browser_timeline_overview-initial-selection-02.js
+++ b/browser/devtools/timeline/test/browser_timeline_overview-initial-selection-02.js
@@ -3,36 +3,30 @@
/**
* Tests if the overview has no initial selection when recording has finished
* and there is no data available.
*/
let test = Task.async(function*() {
let { target, panel } = yield initTimelinePanel(SIMPLE_URL);
- let { $, EVENTS, TimelineView, TimelineController } = panel.panelWin;
+ let { EVENTS, TimelineView, TimelineController } = panel.panelWin;
let { OVERVIEW_INITIAL_SELECTION_RATIO: selectionRatio } = panel.panelWin;
- $("#memory-checkbox").checked = true;
- yield TimelineController.updateMemoryRecording();
-
yield TimelineController.toggleRecording();
ok(true, "Recording has started.");
yield TimelineController._stopRecordingAndDiscardData();
ok(true, "Recording has ended.");
let markers = TimelineController.getMarkers();
- let memory = TimelineController.getMemory();
- let selection = TimelineView.markersOverview.getSelection();
+ let selection = TimelineView.overview.getSelection();
is(markers.length, 0,
"There are no markers available.");
- is(memory.length, 0,
- "There are no memory measurements available.");
is(selection.start, null,
"The initial selection start is correct.");
is(selection.end, null,
"The initial selection end is correct.");
yield teardown(panel);
finish();
});
--- a/browser/devtools/timeline/test/browser_timeline_overview-update.js
+++ b/browser/devtools/timeline/test/browser_timeline_overview-update.js
@@ -1,73 +1,48 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
- * Tests if the markers and memory overviews are continuously updated.
+ * Tests if the overview graph is continuously updated.
*/
let test = Task.async(function*() {
let { target, panel } = yield initTimelinePanel("about:blank");
- let { $, EVENTS, TimelineView, TimelineController } = panel.panelWin;
-
- $("#memory-checkbox").checked = true;
- yield TimelineController.updateMemoryRecording();
+ let { EVENTS, TimelineView, TimelineController } = panel.panelWin;
yield DevToolsUtils.waitForTime(1000);
yield TimelineController.toggleRecording();
ok(true, "Recording has started.");
- ok("selectionEnabled" in TimelineView.markersOverview,
- "The selection should not be enabled for the markers overview (1).");
- is(TimelineView.markersOverview.selectionEnabled, false,
- "The selection should not be enabled for the markers overview (2).");
- is(TimelineView.markersOverview.hasSelection(), false,
- "The markers overview shouldn't have a selection before recording.");
-
- ok("selectionEnabled" in TimelineView.memoryOverview,
- "The selection should not be enabled for the memory overview (1).");
- is(TimelineView.memoryOverview.selectionEnabled, false,
- "The selection should not be enabled for the memory overview (2).");
- is(TimelineView.memoryOverview.hasSelection(), false,
- "The memory overview shouldn't have a selection before recording.");
+ ok("selectionEnabled" in TimelineView.overview,
+ "The selection should not be enabled for the overview graph (1).");
+ is(TimelineView.overview.selectionEnabled, false,
+ "The selection should not be enabled for the overview graph (2).");
+ is(TimelineView.overview.hasSelection(), false,
+ "The overview graph shouldn't have a selection before recording.");
let updated = 0;
panel.panelWin.on(EVENTS.OVERVIEW_UPDATED, () => updated++);
ok((yield waitUntil(() => updated > 10)),
- "The overviews were updated a bunch of times.");
+ "The overview graph was updated a bunch of times.");
- ok("selectionEnabled" in TimelineView.markersOverview,
- "The selection should still not be enabled for the markers overview (3).");
- is(TimelineView.markersOverview.selectionEnabled, false,
- "The selection should still not be enabled for the markers overview (4).");
- is(TimelineView.markersOverview.hasSelection(), false,
- "The markers overview should not have a selection while recording.");
-
- ok("selectionEnabled" in TimelineView.memoryOverview,
- "The selection should still not be enabled for the memory overview (3).");
- is(TimelineView.memoryOverview.selectionEnabled, false,
- "The selection should still not be enabled for the memory overview (4).");
- is(TimelineView.memoryOverview.hasSelection(), false,
- "The memory overview should not have a selection while recording.");
+ ok("selectionEnabled" in TimelineView.overview,
+ "The selection should still not be enabled for the overview graph (3).");
+ is(TimelineView.overview.selectionEnabled, false,
+ "The selection should still not be enabled for the overview graph (4).");
+ is(TimelineView.overview.hasSelection(), false,
+ "The overview graph should not have a selection while recording.");
yield TimelineController.toggleRecording();
ok(true, "Recording has ended.");
is(TimelineController.getMarkers().length, 0,
"There are no markers available.");
- ok(TimelineController.getMemory().length >= 10,
- "There are some memory measurements available.");
-
- is(TimelineView.markersOverview.selectionEnabled, true,
- "The selection should now be enabled for the markers overview.");
- is(TimelineView.markersOverview.hasSelection(), false,
- "The markers overview should not have a selection after recording.");
-
- is(TimelineView.memoryOverview.selectionEnabled, true,
- "The selection should now be enabled for the memory overview.");
- is(TimelineView.memoryOverview.hasSelection(), false,
- "The memory overview should not have a selection after recording.");
+ is(TimelineView.overview.selectionEnabled, true,
+ "The selection should now be enabled for the overview graph.");
+ is(TimelineView.overview.hasSelection(), false,
+ "The overview graph should not have a selection after recording.");
yield teardown(panel);
finish();
});
deleted file mode 100644
--- a/browser/devtools/timeline/test/browser_timeline_recording-without-memory.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests if the timeline actor isn't unnecessarily asked to record memory.
- */
-
-let test = Task.async(function*() {
- let { target, panel } = yield initTimelinePanel(SIMPLE_URL);
- let { $, EVENTS, TimelineView, TimelineController } = panel.panelWin;
-
- yield TimelineController.toggleRecording();
- ok(true, "Recording has started.");
-
- let updated = 0;
- panel.panelWin.on(EVENTS.OVERVIEW_UPDATED, () => updated++);
-
- ok((yield waitUntil(() => updated > 10)),
- "The overview graph was updated a bunch of times.");
- ok((yield waitUntil(() => TimelineController.getMarkers().length > 0)),
- "There are some markers available.");
-
- yield TimelineController.toggleRecording();
- ok(true, "Recording has ended.");
-
- let markers = TimelineController.getMarkers();
- let memory = TimelineController.getMemory();
-
- isnot(markers.length, 0,
- "There are some markers available.");
- is(memory.length, 0,
- "There are no memory measurements available.");
-
- yield teardown(panel);
- finish();
-});
--- a/browser/devtools/timeline/test/browser_timeline_recording.js
+++ b/browser/devtools/timeline/test/browser_timeline_recording.js
@@ -2,39 +2,33 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the timeline can properly start and stop a recording.
*/
let test = Task.async(function*() {
let { target, panel } = yield initTimelinePanel(SIMPLE_URL);
- let { $, gFront, TimelineController } = panel.panelWin;
-
- $("#memory-checkbox").checked = true;
- yield TimelineController.updateMemoryRecording();
+ let { gFront, TimelineController } = panel.panelWin;
is((yield gFront.isRecording()), false,
"The timeline actor should not be recording when the tool starts.");
is(TimelineController.getMarkers().length, 0,
"There should be no markers available when the tool starts.");
yield TimelineController.toggleRecording();
is((yield gFront.isRecording()), true,
"The timeline actor should be recording now.");
ok((yield waitUntil(() => TimelineController.getMarkers().length > 0)),
"There are some markers available now.");
- ok((yield waitUntil(() => TimelineController.getMemory().length > 0)),
- "There are some memory measurements available now.");
- ok("startTime" in TimelineController.getInterval(),
- "A `startTime` field was set on the recording data.");
- ok("endTime" in TimelineController.getInterval(),
- "An `endTime` field was set on the recording data.");
-
- ok(TimelineController.getInterval().endTime >
- TimelineController.getInterval().startTime,
+ ok("startTime" in TimelineController.getMarkers(),
+ "A `startTime` field was set on the markers array.");
+ ok("endTime" in TimelineController.getMarkers(),
+ "An `endTime` field was set on the markers array.");
+ ok(TimelineController.getMarkers().endTime >
+ TimelineController.getMarkers().startTime,
"Some time has passed since the recording started.");
yield teardown(panel);
finish();
});
--- a/browser/devtools/timeline/test/browser_timeline_waterfall-background.js
+++ b/browser/devtools/timeline/test/browser_timeline_waterfall-background.js
@@ -12,17 +12,17 @@ let test = Task.async(function*() {
yield TimelineController.toggleRecording();
ok(true, "Recording has started.");
let updated = 0;
panel.panelWin.on(EVENTS.OVERVIEW_UPDATED, () => updated++);
ok((yield waitUntil(() => updated > 0)),
- "The overview graphs were updated a bunch of times.");
+ "The overview graph was updated a bunch of times.");
ok((yield waitUntil(() => TimelineController.getMarkers().length > 0)),
"There are some markers available.");
yield TimelineController.toggleRecording();
ok(true, "Recording has ended.");
// Test the waterfall background.
--- a/browser/devtools/timeline/test/browser_timeline_waterfall-generic.js
+++ b/browser/devtools/timeline/test/browser_timeline_waterfall-generic.js
@@ -11,58 +11,58 @@ let test = Task.async(function*() {
yield TimelineController.toggleRecording();
ok(true, "Recording has started.");
let updated = 0;
panel.panelWin.on(EVENTS.OVERVIEW_UPDATED, () => updated++);
ok((yield waitUntil(() => updated > 0)),
- "The overview graphs were updated a bunch of times.");
+ "The overview graph was updated a bunch of times.");
ok((yield waitUntil(() => TimelineController.getMarkers().length > 0)),
"There are some markers available.");
yield TimelineController.toggleRecording();
ok(true, "Recording has ended.");
// Test the header container.
- ok($(".waterfall-header-container"),
+ ok($(".timeline-header-container"),
"A header container should have been created.");
// Test the header sidebar (left).
- ok($(".waterfall-header-container > .waterfall-sidebar"),
+ ok($(".timeline-header-sidebar"),
"A header sidebar node should have been created.");
- ok($(".waterfall-header-container > .waterfall-sidebar > .waterfall-header-name"),
+ ok($(".timeline-header-sidebar > .timeline-header-name"),
"A header name label should have been created inside the sidebar.");
// Test the header ticks (right).
- ok($(".waterfall-header-ticks"),
+ ok($(".timeline-header-ticks"),
"A header ticks node should have been created.");
- ok($$(".waterfall-header-ticks > .waterfall-header-tick").length > 0,
+ ok($$(".timeline-header-ticks > .timeline-header-tick").length > 0,
"Some header tick labels should have been created inside the tick node.");
// Test the markers container.
- ok($(".waterfall-marker-container"),
+ ok($(".timeline-marker-container"),
"A marker container should have been created.");
// Test the markers sidebar (left).
- ok($$(".waterfall-marker-container > .waterfall-sidebar").length,
+ ok($$(".timeline-marker-sidebar").length,
"Some marker sidebar nodes should have been created.");
- ok($$(".waterfall-marker-container > .waterfall-sidebar:not(spacer) > .waterfall-marker-bullet").length,
+ ok($$(".timeline-marker-sidebar:not(spacer) > .timeline-marker-bullet").length,
"Some marker color bullets should have been created inside the sidebar.");
- ok($$(".waterfall-marker-container > .waterfall-sidebar:not(spacer) > .waterfall-marker-name").length,
+ ok($$(".timeline-marker-sidebar:not(spacer) > .timeline-marker-name").length,
"Some marker name labels should have been created inside the sidebar.");
// Test the markers waterfall (right).
- ok($$(".waterfall-marker-item").length,
+ ok($$(".timeline-marker-waterfall").length,
"Some marker waterfall nodes should have been created.");
- ok($$(".waterfall-marker-item:not(spacer) > .waterfall-marker-bar").length,
+ ok($$(".timeline-marker-waterfall:not(spacer) > .timeline-marker-bar").length,
"Some marker color bars should have been created inside the waterfall.");
yield teardown(panel);
finish();
});
--- a/browser/devtools/timeline/test/browser_timeline_waterfall-styles.js
+++ b/browser/devtools/timeline/test/browser_timeline_waterfall-styles.js
@@ -22,17 +22,17 @@ let test = Task.async(function*() {
yield TimelineController.toggleRecording();
ok(true, "Recording has started.");
let updated = 0;
panel.panelWin.on(EVENTS.OVERVIEW_UPDATED, () => updated++);
ok((yield waitUntil(() => updated > 0)),
- "The overview graphs were updated a bunch of times.");
+ "The overview graph was updated a bunch of times.");
ok((yield waitUntil(() => TimelineController.getMarkers().length > 0)),
"There are some markers available.");
yield TimelineController.toggleRecording();
ok(true, "Recording has ended.");
// Test the table sidebars.
--- a/browser/devtools/timeline/timeline.js
+++ b/browser/devtools/timeline/timeline.js
@@ -7,39 +7,34 @@ const { classes: Cc, interfaces: Ci, uti
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/devtools/Loader.jsm");
devtools.lazyRequireGetter(this, "promise");
devtools.lazyRequireGetter(this, "EventEmitter",
"devtools/toolkit/event-emitter");
-devtools.lazyRequireGetter(this, "MarkersOverview",
- "devtools/timeline/markers-overview", true);
-devtools.lazyRequireGetter(this, "MemoryOverview",
- "devtools/timeline/memory-overview", true);
+devtools.lazyRequireGetter(this, "Overview",
+ "devtools/timeline/overview", true);
devtools.lazyRequireGetter(this, "Waterfall",
"devtools/timeline/waterfall", true);
-devtools.lazyImporter(this, "CanvasGraphUtils",
- "resource:///modules/devtools/Graphs.jsm");
-
devtools.lazyImporter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
const OVERVIEW_UPDATE_INTERVAL = 200;
const OVERVIEW_INITIAL_SELECTION_RATIO = 0.15;
// The panel's window global is an EventEmitter firing the following events:
const EVENTS = {
// When a recording is started or stopped, via the `stopwatch` button.
RECORDING_STARTED: "Timeline:RecordingStarted",
RECORDING_ENDED: "Timeline:RecordingEnded",
- // When the overview graphs are populated with new markers.
+ // When the overview graph is populated with new markers.
OVERVIEW_UPDATED: "Timeline:OverviewUpdated",
// When the waterfall view is populated with new markers.
WATERFALL_UPDATED: "Timeline:WaterfallUpdated"
};
/**
* The current target and the timeline front, set by this tool's host.
@@ -63,330 +58,225 @@ let shutdownTimeline = Task.async(functi
yield gFront.stop();
});
/**
* Functions handling the timeline frontend controller.
*/
let TimelineController = {
/**
- * Permanent storage for the markers and the memory measurements streamed by
- * the backend, along with the start and end timestamps.
+ * Permanent storage for the markers streamed by the backend.
*/
- _starTime: 0,
- _endTime: 0,
_markers: [],
- _memory: [],
/**
* Initialization function, called when the tool is started.
*/
initialize: function() {
this._onRecordingTick = this._onRecordingTick.bind(this);
this._onMarkers = this._onMarkers.bind(this);
- this._onMemory = this._onMemory.bind(this);
gFront.on("markers", this._onMarkers);
- gFront.on("memory", this._onMemory);
},
/**
* Destruction function, called when the tool is closed.
*/
destroy: function() {
gFront.off("markers", this._onMarkers);
- gFront.off("memory", this._onMemory);
- },
-
- /**
- * Gets the { stat, end } time interval for this recording.
- * @return object
- */
- getInterval: function() {
- return { startTime: this._startTime, endTime: this._endTime };
},
/**
* Gets the accumulated markers in this recording.
- * @return array
+ * @return array.
*/
getMarkers: function() {
return this._markers;
},
/**
- * Gets the accumulated memory measurements in this recording.
- * @return array
- */
- getMemory: function() {
- return this._memory;
- },
-
- /**
- * Updates the views to show or hide the memory recording data.
- */
- updateMemoryRecording: Task.async(function*() {
- if ($("#memory-checkbox").checked) {
- yield TimelineView.showMemoryOverview();
- } else {
- yield TimelineView.hideMemoryOverview();
- }
- }),
-
- /**
* Starts/stops the timeline recording and streaming.
*/
toggleRecording: Task.async(function*() {
let isRecording = yield gFront.isRecording();
if (isRecording == false) {
yield this._startRecording();
} else {
yield this._stopRecording();
}
}),
/**
* Starts the recording, updating the UI as needed.
*/
_startRecording: function*() {
TimelineView.handleRecordingStarted();
-
- let withMemory = $("#memory-checkbox").checked;
- let startTime = yield gFront.start({ withMemory });
-
+ let startTime = yield gFront.start();
// Times must come from the actor in order to be self-consistent.
// However, we also want to update the view with the elapsed time
// even when the actor is not generating data. To do this we get
// the local time and use it to compute a reasonable elapsed time.
// See _onRecordingTick.
this._localStartTime = performance.now();
- this._startTime = startTime;
- this._endTime = startTime;
+
this._markers = [];
- this._memory = [];
+ this._markers.startTime = startTime;
+ this._markers.endTime = startTime;
this._updateId = setInterval(this._onRecordingTick, OVERVIEW_UPDATE_INTERVAL);
},
/**
* Stops the recording, updating the UI as needed.
*/
_stopRecording: function*() {
clearInterval(this._updateId);
// Sorting markers is only important when displayed in the waterfall.
this._markers = this._markers.sort((a,b) => (a.start > b.start));
- TimelineView.handleRecordingUpdate();
+ TimelineView.handleMarkersUpdate(this._markers);
TimelineView.handleRecordingEnded();
yield gFront.stop();
},
/**
* Used in tests. Stops the recording, discarding the accumulated markers and
* updating the UI as needed.
*/
_stopRecordingAndDiscardData: function*() {
yield this._stopRecording();
this._markers.length = 0;
- this._memory.length = 0;
},
/**
* Callback handling the "markers" event on the timeline front.
*
* @param array markers
* A list of new markers collected since the last time this
* function was invoked.
* @param number endTime
* A time after the last marker in markers was collected.
*/
_onMarkers: function(markers, endTime) {
Array.prototype.push.apply(this._markers, markers);
- this._endTime = endTime;
- },
-
- /**
- * Callback handling the "memory" event on the timeline front.
- *
- * @param number delta
- * The number of milliseconds elapsed since epoch.
- * @param object measurement
- * A detailed breakdown of the current memory usage.
- */
- _onMemory: function(delta, measurement) {
- this._memory.push({ delta, value: measurement.total / 1024 / 1024 });
+ this._markers.endTime = endTime;
},
/**
* Callback invoked at a fixed interval while recording.
- * Updates the current time and the timeline overview.
+ * Updates the markers store with the current time and the timeline overview.
*/
_onRecordingTick: function() {
// Compute an approximate ending time for the view. This is
// needed to ensure that the view updates even when new data is
// not being generated.
- let fakeTime = this._startTime + (performance.now() - this._localStartTime);
- if (fakeTime > this._endTime) {
- this._endTime = fakeTime;
+ let fakeTime = this._markers.startTime + (performance.now() - this._localStartTime);
+ if (fakeTime > this._markers.endTime) {
+ this._markers.endTime = fakeTime;
}
- TimelineView.handleRecordingUpdate();
+ TimelineView.handleMarkersUpdate(this._markers);
}
};
/**
* Functions handling the timeline frontend view.
*/
let TimelineView = {
/**
* Initialization function, called when the tool is started.
*/
initialize: Task.async(function*() {
- this.markersOverview = new MarkersOverview($("#markers-overview"));
+ this.overview = new Overview($("#timeline-overview"));
this.waterfall = new Waterfall($("#timeline-waterfall"));
this._onSelecting = this._onSelecting.bind(this);
this._onRefresh = this._onRefresh.bind(this);
- this.markersOverview.on("selecting", this._onSelecting);
- this.markersOverview.on("refresh", this._onRefresh);
+ this.overview.on("selecting", this._onSelecting);
+ this.overview.on("refresh", this._onRefresh);
- yield this.markersOverview.ready();
+ yield this.overview.ready();
yield this.waterfall.recalculateBounds();
}),
/**
* Destruction function, called when the tool is closed.
*/
destroy: function() {
- this.markersOverview.off("selecting", this._onSelecting);
- this.markersOverview.off("refresh", this._onRefresh);
- this.markersOverview.destroy();
-
- // The memory overview graph is not always available.
- if (this.memoryOverview) {
- this.memoryOverview.destroy();
- }
- },
-
- /**
- * Shows the memory overview graph.
- */
- showMemoryOverview: Task.async(function*() {
- this.memoryOverview = new MemoryOverview($("#memory-overview"));
- yield this.memoryOverview.ready();
-
- let interval = TimelineController.getInterval();
- let memory = TimelineController.getMemory();
- this.memoryOverview.setData({ interval, memory });
-
- CanvasGraphUtils.linkAnimation(this.markersOverview, this.memoryOverview);
- CanvasGraphUtils.linkSelection(this.markersOverview, this.memoryOverview);
- }),
-
- /**
- * Hides the memory overview graph.
- */
- hideMemoryOverview: function() {
- if (!this.memoryOverview) {
- return;
- }
- this.memoryOverview.destroy();
- this.memoryOverview = null;
+ this.overview.off("selecting", this._onSelecting);
+ this.overview.off("refresh", this._onRefresh);
+ this.overview.destroy();
},
/**
* Signals that a recording session has started and triggers the appropriate
* changes in the UI.
*/
handleRecordingStarted: function() {
$("#record-button").setAttribute("checked", "true");
- $("#memory-checkbox").setAttribute("disabled", "true");
$("#timeline-pane").selectedPanel = $("#recording-notice");
- this.markersOverview.clearView();
-
- // The memory overview graph is not always available.
- if (this.memoryOverview) {
- this.memoryOverview.clearView();
- }
-
+ this.overview.selectionEnabled = false;
+ this.overview.dropSelection();
+ this.overview.setData([]);
this.waterfall.clearView();
window.emit(EVENTS.RECORDING_STARTED);
},
/**
* Signals that a recording session has ended and triggers the appropriate
* changes in the UI.
*/
handleRecordingEnded: function() {
$("#record-button").removeAttribute("checked");
- $("#memory-checkbox").removeAttribute("disabled");
$("#timeline-pane").selectedPanel = $("#timeline-waterfall");
- this.markersOverview.selectionEnabled = true;
+ this.overview.selectionEnabled = true;
- // The memory overview graph is not always available.
- if (this.memoryOverview) {
- this.memoryOverview.selectionEnabled = true;
- }
-
- let interval = TimelineController.getInterval();
let markers = TimelineController.getMarkers();
- let memory = TimelineController.getMemory();
-
if (markers.length) {
- let start = (markers[0].start - interval.startTime) * this.markersOverview.dataScaleX;
- let end = start + this.markersOverview.width * OVERVIEW_INITIAL_SELECTION_RATIO;
- this.markersOverview.setSelection({ start, end });
+ let start = (markers[0].start - markers.startTime) * this.overview.dataScaleX;
+ let end = start + this.overview.width * OVERVIEW_INITIAL_SELECTION_RATIO;
+ this.overview.setSelection({ start, end });
} else {
- let timeStart = interval.startTime;
- let timeEnd = interval.endTime;
- this.waterfall.setData(markers, timeStart, timeStart, timeEnd);
+ let duration = markers.endTime - markers.startTime;
+ this.waterfall.setData(markers, markers.startTime, markers.endTime);
}
window.emit(EVENTS.RECORDING_ENDED);
},
/**
* Signals that a new set of markers was made available by the controller,
* or that the overview graph needs to be updated.
+ *
+ * @param array markers
+ * A list of new markers collected since the recording has started.
*/
- handleRecordingUpdate: function() {
- let interval = TimelineController.getInterval();
- let markers = TimelineController.getMarkers();
- let memory = TimelineController.getMemory();
-
- this.markersOverview.setData({ interval, markers });
-
- // The memory overview graph is not always available.
- if (this.memoryOverview) {
- this.memoryOverview.setData({ interval, memory });
- }
-
+ handleMarkersUpdate: function(markers) {
+ this.overview.setData(markers);
window.emit(EVENTS.OVERVIEW_UPDATED);
},
/**
* Callback handling the "selecting" event on the timeline overview.
*/
_onSelecting: function() {
- if (!this.markersOverview.hasSelection() &&
- !this.markersOverview.hasSelectionInProgress()) {
+ if (!this.overview.hasSelection() &&
+ !this.overview.hasSelectionInProgress()) {
this.waterfall.clearView();
return;
}
- let selection = this.markersOverview.getSelection();
- let start = selection.start / this.markersOverview.dataScaleX;
- let end = selection.end / this.markersOverview.dataScaleX;
+ let selection = this.overview.getSelection();
+ let start = selection.start / this.overview.dataScaleX;
+ let end = selection.end / this.overview.dataScaleX;
let markers = TimelineController.getMarkers();
- let interval = TimelineController.getInterval();
-
- let timeStart = interval.startTime + Math.min(start, end);
- let timeEnd = interval.startTime + Math.max(start, end);
- this.waterfall.setData(markers, interval.startTime, timeStart, timeEnd);
+ let timeStart = markers.startTime + Math.min(start, end);
+ let timeEnd = markers.startTime + Math.max(start, end);
+ this.waterfall.setData(markers, timeStart, timeEnd);
},
/**
* Callback handling the "refresh" event on the timeline overview.
*/
_onRefresh: function() {
this.waterfall.recalculateBounds();
this._onSelecting();
--- a/browser/devtools/timeline/timeline.xul
+++ b/browser/devtools/timeline/timeline.xul
@@ -20,27 +20,23 @@
class="devtools-toolbar">
<hbox id="recordings-controls"
class="devtools-toolbarbutton-group"
align="center">
<toolbarbutton id="record-button"
class="devtools-toolbarbutton"
oncommand="TimelineController.toggleRecording()"
tooltiptext="&timelineUI.recordButton.tooltip;"/>
- <checkbox id="memory-checkbox"
- label="&timelineUI.memoryCheckbox.label;"
- oncommand="TimelineController.updateMemoryRecording()"
- tooltiptext="&timelineUI.memoryCheckbox.tooltip;"/>
+ <spacer flex="1"/>
<label id="record-label"
value="&timelineUI.recordLabel;"/>
</hbox>
</toolbar>
- <vbox id="markers-overview"/>
- <vbox id="memory-overview"/>
+ <vbox id="timeline-overview"/>
<deck id="timeline-pane"
flex="1">
<hbox id="empty-notice"
class="notice-container"
align="center"
pack="center"
flex="1">
deleted file mode 100644
--- a/browser/devtools/timeline/widgets/memory-overview.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-/**
- * This file contains the "memory overview" graph, a simple representation of
- * of all the memory measurements taken while streaming the timeline data.
- */
-
-const {Cc, Ci, Cu, Cr} = require("chrome");
-
-Cu.import("resource:///modules/devtools/Graphs.jsm");
-Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
-
-loader.lazyRequireGetter(this, "L10N",
- "devtools/timeline/global", true);
-
-const HTML_NS = "http://www.w3.org/1999/xhtml";
-
-const OVERVIEW_HEIGHT = 30; // px
-
-const OVERVIEW_BACKGROUND_COLOR = "#fff";
-const OVERVIEW_BACKGROUND_GRADIENT_START = "rgba(0,136,204,0.1)";
-const OVERVIEW_BACKGROUND_GRADIENT_END = "rgba(0,136,204,0.0)";
-const OVERVIEW_STROKE_WIDTH = 1; // px
-const OVERVIEW_STROKE_COLOR = "rgba(0,136,204,1)";
-const OVERVIEW_CLIPHEAD_LINE_COLOR = "#666";
-const OVERVIEW_SELECTION_LINE_COLOR = "#555";
-const OVERVIEW_MAXIMUM_LINE_COLOR = "rgba(0,136,204,0.4)";
-const OVERVIEW_AVERAGE_LINE_COLOR = "rgba(0,136,204,0.7)";
-const OVERVIEW_MINIMUM_LINE_COLOR = "rgba(0,136,204,0.9)";
-
-const OVERVIEW_SELECTION_BACKGROUND_COLOR = "rgba(76,158,217,0.25)";
-const OVERVIEW_SELECTION_STRIPES_COLOR = "rgba(255,255,255,0.1)";
-
-/**
- * An overview for the memory data.
- *
- * @param nsIDOMNode parent
- * The parent node holding the overview.
- */
-function MemoryOverview(parent) {
- LineGraphWidget.call(this, parent, L10N.getStr("graphs.memory"));
-
- this.once("ready", () => {
- // Populate this overview with some dummy initial data.
- this.setData({ interval: { startTime: 0, endTime: 1000 }, memory: [] });
- });
-}
-
-MemoryOverview.prototype = Heritage.extend(LineGraphWidget.prototype, {
- dampenValuesFactor: 0.95,
- fixedHeight: OVERVIEW_HEIGHT,
- backgroundColor: OVERVIEW_BACKGROUND_COLOR,
- backgroundGradientStart: OVERVIEW_BACKGROUND_GRADIENT_START,
- backgroundGradientEnd: OVERVIEW_BACKGROUND_GRADIENT_END,
- strokeColor: OVERVIEW_STROKE_COLOR,
- strokeWidth: OVERVIEW_STROKE_WIDTH,
- maximumLineColor: OVERVIEW_MAXIMUM_LINE_COLOR,
- averageLineColor: OVERVIEW_AVERAGE_LINE_COLOR,
- minimumLineColor: OVERVIEW_MINIMUM_LINE_COLOR,
- clipheadLineColor: OVERVIEW_CLIPHEAD_LINE_COLOR,
- selectionLineColor: OVERVIEW_SELECTION_LINE_COLOR,
- selectionBackgroundColor: OVERVIEW_SELECTION_BACKGROUND_COLOR,
- selectionStripesColor: OVERVIEW_SELECTION_STRIPES_COLOR,
- withTooltipArrows: false,
- withFixedTooltipPositions: true,
-
- /**
- * Disables selection and empties this graph.
- */
- clearView: function() {
- this.selectionEnabled = false;
- this.dropSelection();
- this.setData({ interval: { startTime: 0, endTime: 0 }, memory: [] });
- },
-
- /**
- * Sets the data source for this graph.
- */
- setData: function({ interval, memory }) {
- this.dataOffsetX = interval.startTime;
- LineGraphWidget.prototype.setData.call(this, memory);
- }
-});
-
-exports.MemoryOverview = MemoryOverview;
rename from browser/devtools/timeline/widgets/markers-overview.js
rename to browser/devtools/timeline/widgets/overview.js
--- a/browser/devtools/timeline/widgets/markers-overview.js
+++ b/browser/devtools/timeline/widgets/overview.js
@@ -1,73 +1,73 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
- * This file contains the "markers overview" graph, which is a minimap of all
- * the timeline data. Regions inside it may be selected, determining which
- * markers are visible in the "waterfall".
+ * This file contains the "overview" graph, which is a minimap of all the
+ * timeline data. Regions inside it may be selected, determining which markers
+ * are visible in the "waterfall".
*/
const {Cc, Ci, Cu, Cr} = require("chrome");
Cu.import("resource:///modules/devtools/Graphs.jsm");
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
loader.lazyRequireGetter(this, "L10N",
"devtools/timeline/global", true);
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
"devtools/timeline/global", true);
const HTML_NS = "http://www.w3.org/1999/xhtml";
-const OVERVIEW_HEADER_HEIGHT = 14; // px
-const OVERVIEW_BODY_HEIGHT = 55; // 11px * 5 groups
+const OVERVIEW_HEADER_HEIGHT = 20; // px
+const OVERVIEW_BODY_HEIGHT = 50; // px
const OVERVIEW_BACKGROUND_COLOR = "#fff";
const OVERVIEW_CLIPHEAD_LINE_COLOR = "#666";
const OVERVIEW_SELECTION_LINE_COLOR = "#555";
const OVERVIEW_SELECTION_BACKGROUND_COLOR = "rgba(76,158,217,0.25)";
const OVERVIEW_SELECTION_STRIPES_COLOR = "rgba(255,255,255,0.1)";
const OVERVIEW_HEADER_TICKS_MULTIPLE = 100; // ms
const OVERVIEW_HEADER_TICKS_SPACING_MIN = 75; // px
const OVERVIEW_HEADER_SAFE_BOUNDS = 50; // px
-const OVERVIEW_HEADER_BACKGROUND = "#fff";
+const OVERVIEW_HEADER_BACKGROUND = "#ebeced";
const OVERVIEW_HEADER_TEXT_COLOR = "#18191a";
const OVERVIEW_HEADER_TEXT_FONT_SIZE = 9; // px
const OVERVIEW_HEADER_TEXT_FONT_FAMILY = "sans-serif";
-const OVERVIEW_HEADER_TEXT_PADDING_LEFT = 6; // px
-const OVERVIEW_HEADER_TEXT_PADDING_TOP = 1; // px
-const OVERVIEW_TIMELINE_STROKES = "#ccc";
+const OVERVIEW_HEADER_TEXT_PADDING = 6; // px
+const OVERVIEW_TIMELINE_STROKES = "#aaa";
const OVERVIEW_MARKERS_COLOR_STOPS = [0, 0.1, 0.75, 1];
const OVERVIEW_MARKER_DURATION_MIN = 4; // ms
-const OVERVIEW_GROUP_VERTICAL_PADDING = 5; // px
+const OVERVIEW_GROUP_VERTICAL_PADDING = 6; // px
const OVERVIEW_GROUP_ALTERNATING_BACKGROUND = "rgba(0,0,0,0.05)";
/**
- * An overview for the markers data.
+ * An overview for the timeline data.
*
* @param nsIDOMNode parent
* The parent node holding the overview.
*/
-function MarkersOverview(parent, ...args) {
- AbstractCanvasGraph.apply(this, [parent, "markers-overview", ...args]);
+function Overview(parent, ...args) {
+ AbstractCanvasGraph.apply(this, [parent, "timeline-overview", ...args]);
this.once("ready", () => {
- // Set the list of names, properties and colors used to paint this overview.
this.setBlueprint(TIMELINE_BLUEPRINT);
- // Populate this overview with some dummy initial data.
- this.setData({ interval: { startTime: 0, endTime: 1000 }, markers: [] });
+ var preview = [];
+ preview.startTime = 0;
+ preview.endTime = 1000;
+ this.setData(preview);
});
}
-MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
+Overview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
fixedHeight: OVERVIEW_HEADER_HEIGHT + OVERVIEW_BODY_HEIGHT,
clipheadLineColor: OVERVIEW_CLIPHEAD_LINE_COLOR,
selectionLineColor: OVERVIEW_SELECTION_LINE_COLOR,
selectionBackgroundColor: OVERVIEW_SELECTION_BACKGROUND_COLOR,
selectionStripesColor: OVERVIEW_SELECTION_STRIPES_COLOR,
/**
* List of names and colors used to paint this overview.
@@ -79,97 +79,83 @@ MarkersOverview.prototype = Heritage.ext
for (let type in blueprint) {
this._paintBatches.set(type, { style: blueprint[type], batch: [] });
this._lastGroup = Math.max(this._lastGroup, blueprint[type].group);
}
},
/**
- * Disables selection and empties this graph.
- */
- clearView: function() {
- this.selectionEnabled = false;
- this.dropSelection();
- this.setData({ interval: { startTime: 0, endTime: 0 }, markers: [] });
- },
-
- /**
* Renders the graph's data source.
* @see AbstractCanvasGraph.prototype.buildGraphImage
*/
buildGraphImage: function() {
- let { interval, markers } = this._data;
- let { startTime, endTime } = interval;
-
let { canvas, ctx } = this._getNamedCanvas("overview-data");
let canvasWidth = this._width;
let canvasHeight = this._height;
let safeBounds = OVERVIEW_HEADER_SAFE_BOUNDS * this._pixelRatio;
let availableWidth = canvasWidth - safeBounds;
// Group markers into separate paint batches. This is necessary to
// draw all markers sharing the same style at once.
- for (let marker of markers) {
+ for (let marker of this._data) {
this._paintBatches.get(marker.name).batch.push(marker);
}
// Calculate each group's height, and the time-based scaling.
let totalGroups = this._lastGroup + 1;
let headerHeight = OVERVIEW_HEADER_HEIGHT * this._pixelRatio;
let groupHeight = OVERVIEW_BODY_HEIGHT * this._pixelRatio / totalGroups;
let groupPadding = OVERVIEW_GROUP_VERTICAL_PADDING * this._pixelRatio;
- let totalTime = (endTime - startTime) || 0;
+ let totalTime = (this._data.endTime - this._data.startTime) || 0;
let dataScale = this.dataScaleX = availableWidth / totalTime;
// Draw the header and overview background.
ctx.fillStyle = OVERVIEW_HEADER_BACKGROUND;
ctx.fillRect(0, 0, canvasWidth, headerHeight);
ctx.fillStyle = OVERVIEW_BACKGROUND_COLOR;
ctx.fillRect(0, headerHeight, canvasWidth, canvasHeight);
// Draw the alternating odd/even group backgrounds.
ctx.fillStyle = OVERVIEW_GROUP_ALTERNATING_BACKGROUND;
ctx.beginPath();
- for (let i = 0; i < totalGroups; i += 2) {
+ for (let i = 1; i < totalGroups; i += 2) {
let top = headerHeight + i * groupHeight;
ctx.rect(0, top, canvasWidth, groupHeight);
}
ctx.fill();
// Draw the timeline header ticks.
+ ctx.textBaseline = "middle";
let fontSize = OVERVIEW_HEADER_TEXT_FONT_SIZE * this._pixelRatio;
let fontFamily = OVERVIEW_HEADER_TEXT_FONT_FAMILY;
- let textPaddingLeft = OVERVIEW_HEADER_TEXT_PADDING_LEFT * this._pixelRatio;
- let textPaddingTop = OVERVIEW_HEADER_TEXT_PADDING_TOP * this._pixelRatio;
- let tickInterval = this._findOptimalTickInterval(dataScale);
-
- ctx.textBaseline = "middle";
ctx.font = fontSize + "px " + fontFamily;
ctx.fillStyle = OVERVIEW_HEADER_TEXT_COLOR;
ctx.strokeStyle = OVERVIEW_TIMELINE_STROKES;
ctx.beginPath();
+ let tickInterval = this._findOptimalTickInterval(dataScale);
+ let headerTextPadding = OVERVIEW_HEADER_TEXT_PADDING * this._pixelRatio;
+
for (let x = 0; x < availableWidth; x += tickInterval) {
- let lineLeft = x;
- let textLeft = lineLeft + textPaddingLeft;
+ let left = x + headerTextPadding;
let time = Math.round(x / dataScale);
let label = L10N.getFormatStr("timeline.tick", time);
- ctx.fillText(label, textLeft, headerHeight / 2 + textPaddingTop);
- ctx.moveTo(lineLeft, 0);
- ctx.lineTo(lineLeft, canvasHeight);
+ ctx.fillText(label, left, headerHeight / 2 + 1);
+ ctx.moveTo(x, 0);
+ ctx.lineTo(x, canvasHeight);
}
ctx.stroke();
// Draw the timeline markers.
for (let [, { style, batch }] of this._paintBatches) {
let top = headerHeight + style.group * groupHeight + groupPadding / 2;
@@ -179,18 +165,18 @@ MarkersOverview.prototype = Heritage.ext
gradient.addColorStop(OVERVIEW_MARKERS_COLOR_STOPS[0], style.stroke);
gradient.addColorStop(OVERVIEW_MARKERS_COLOR_STOPS[1], style.fill);
gradient.addColorStop(OVERVIEW_MARKERS_COLOR_STOPS[2], style.fill);
gradient.addColorStop(OVERVIEW_MARKERS_COLOR_STOPS[3], style.stroke);
ctx.fillStyle = gradient;
ctx.beginPath();
for (let { start, end } of batch) {
- start -= interval.startTime;
- end -= interval.startTime;
+ start -= this._data.startTime;
+ end -= this._data.startTime;
let left = start * dataScale;
let duration = Math.max(end - start, OVERVIEW_MARKER_DURATION_MIN);
let width = Math.max(duration * dataScale, this._pixelRatio);
ctx.rect(left, top, width, height);
}
ctx.fill();
@@ -217,9 +203,9 @@ MarkersOverview.prototype = Heritage.ext
timingStep <<= 1;
continue;
}
return scaledStep;
}
}
});
-exports.MarkersOverview = MarkersOverview;
+exports.Overview = Overview;
--- a/browser/devtools/timeline/widgets/waterfall.js
+++ b/browser/devtools/timeline/widgets/waterfall.js
@@ -17,51 +17,51 @@ loader.lazyRequireGetter(this, "TIMELINE
loader.lazyImporter(this, "setNamedTimeout",
"resource:///modules/devtools/ViewHelpers.jsm");
loader.lazyImporter(this, "clearNamedTimeout",
"resource:///modules/devtools/ViewHelpers.jsm");
const HTML_NS = "http://www.w3.org/1999/xhtml";
-const WATERFALL_SIDEBAR_WIDTH = 150; // px
+const TIMELINE_IMMEDIATE_DRAW_MARKERS_COUNT = 30;
+const TIMELINE_FLUSH_OUTSTANDING_MARKERS_DELAY = 75; // ms
-const WATERFALL_IMMEDIATE_DRAW_MARKERS_COUNT = 30;
-const WATERFALL_FLUSH_OUTSTANDING_MARKERS_DELAY = 75; // ms
+const TIMELINE_HEADER_TICKS_MULTIPLE = 5; // ms
+const TIMELINE_HEADER_TICKS_SPACING_MIN = 50; // px
+const TIMELINE_HEADER_TEXT_PADDING = 3; // px
-const WATERFALL_HEADER_TICKS_MULTIPLE = 5; // ms
-const WATERFALL_HEADER_TICKS_SPACING_MIN = 50; // px
-const WATERFALL_HEADER_TEXT_PADDING = 3; // px
+const TIMELINE_MARKER_SIDEBAR_WIDTH = 150; // px
+const TIMELINE_MARKER_BAR_WIDTH_MIN = 5; // px
const WATERFALL_BACKGROUND_TICKS_MULTIPLE = 5; // ms
const WATERFALL_BACKGROUND_TICKS_SCALES = 3;
const WATERFALL_BACKGROUND_TICKS_SPACING_MIN = 10; // px
const WATERFALL_BACKGROUND_TICKS_COLOR_RGB = [128, 136, 144];
const WATERFALL_BACKGROUND_TICKS_OPACITY_MIN = 32; // byte
const WATERFALL_BACKGROUND_TICKS_OPACITY_ADD = 32; // byte
-const WATERFALL_MARKER_BAR_WIDTH_MIN = 5; // px
/**
* A detailed waterfall view for the timeline data.
*
* @param nsIDOMNode parent
* The parent node holding the waterfall.
*/
function Waterfall(parent) {
this._parent = parent;
this._document = parent.ownerDocument;
this._fragment = this._document.createDocumentFragment();
this._outstandingMarkers = [];
this._headerContents = this._document.createElement("hbox");
- this._headerContents.className = "waterfall-header-contents";
+ this._headerContents.className = "timeline-header-contents";
this._parent.appendChild(this._headerContents);
this._listContents = this._document.createElement("vbox");
- this._listContents.className = "waterfall-list-contents";
+ this._listContents.className = "timeline-list-contents";
this._listContents.setAttribute("flex", "1");
this._parent.appendChild(this._listContents);
this._isRTL = this._getRTL();
// Lazy require is a bit slow, and these are hot objects.
this._l10n = L10N;
this._blueprint = TIMELINE_BLUEPRINT;
@@ -70,31 +70,28 @@ function Waterfall(parent) {
}
Waterfall.prototype = {
/**
* Populates this view with the provided data source.
*
* @param array markers
* A list of markers received from the controller.
- * @param number timeEpoch
- * The absolute time (in milliseconds) when the recording started.
* @param number timeStart
* The time (in milliseconds) to start drawing from.
* @param number timeEnd
* The time (in milliseconds) to end drawing at.
*/
- setData: function(markers, timeEpoch, timeStart, timeEnd) {
+ setData: function(markers, timeStart, timeEnd) {
this.clearView();
let dataScale = this._waterfallWidth / (timeEnd - timeStart);
this._drawWaterfallBackground(dataScale);
-
// Label the header as if the first possible marker was at T=0.
- this._buildHeader(this._headerContents, timeStart - timeEpoch, dataScale);
+ this._buildHeader(this._headerContents, timeStart - markers.startTime, dataScale);
this._buildMarkers(this._listContents, markers, timeStart, timeEnd, dataScale);
},
/**
* Depopulates this view.
*/
clearView: function() {
while (this._headerContents.hasChildNodes()) {
@@ -109,66 +106,66 @@ Waterfall.prototype = {
},
/**
* Calculates and stores the available width for the waterfall.
* This should be invoked every time the container window is resized.
*/
recalculateBounds: function() {
let bounds = this._parent.getBoundingClientRect();
- this._waterfallWidth = bounds.width - WATERFALL_SIDEBAR_WIDTH;
+ this._waterfallWidth = bounds.width - TIMELINE_MARKER_SIDEBAR_WIDTH;
},
/**
* Creates the header part of this view.
*
* @param nsIDOMNode parent
* The parent node holding the header.
* @param number timeStart
* @see Waterfall.prototype.setData
* @param number dataScale
* The time scale of the data source.
*/
_buildHeader: function(parent, timeStart, dataScale) {
let container = this._document.createElement("hbox");
- container.className = "waterfall-header-container";
+ container.className = "timeline-header-container";
container.setAttribute("flex", "1");
let sidebar = this._document.createElement("hbox");
- sidebar.className = "waterfall-sidebar theme-sidebar";
- sidebar.setAttribute("width", WATERFALL_SIDEBAR_WIDTH);
+ sidebar.className = "timeline-header-sidebar theme-sidebar";
+ sidebar.setAttribute("width", TIMELINE_MARKER_SIDEBAR_WIDTH);
sidebar.setAttribute("align", "center");
container.appendChild(sidebar);
let name = this._document.createElement("label");
- name.className = "plain waterfall-header-name";
+ name.className = "plain timeline-header-name";
name.setAttribute("value", this._l10n.getStr("timeline.records"));
sidebar.appendChild(name);
let ticks = this._document.createElement("hbox");
- ticks.className = "waterfall-header-ticks waterfall-background-ticks";
+ ticks.className = "timeline-header-ticks";
ticks.setAttribute("align", "center");
ticks.setAttribute("flex", "1");
container.appendChild(ticks);
let offset = this._isRTL ? this._waterfallWidth : 0;
let direction = this._isRTL ? -1 : 1;
let tickInterval = this._findOptimalTickInterval({
- ticksMultiple: WATERFALL_HEADER_TICKS_MULTIPLE,
- ticksSpacingMin: WATERFALL_HEADER_TICKS_SPACING_MIN,
+ ticksMultiple: TIMELINE_HEADER_TICKS_MULTIPLE,
+ ticksSpacingMin: TIMELINE_HEADER_TICKS_SPACING_MIN,
dataScale: dataScale
});
for (let x = 0; x < this._waterfallWidth; x += tickInterval) {
- let start = x + direction * WATERFALL_HEADER_TEXT_PADDING;
+ let start = x + direction * TIMELINE_HEADER_TEXT_PADDING;
let time = Math.round(timeStart + x / dataScale);
let label = this._l10n.getFormatStr("timeline.tick", time);
let node = this._document.createElement("label");
- node.className = "plain waterfall-header-tick";
+ node.className = "plain timeline-header-tick";
node.style.transform = "translateX(" + (start - offset) + "px)";
node.setAttribute("value", label);
ticks.appendChild(node);
}
parent.appendChild(container);
},
@@ -188,32 +185,32 @@ Waterfall.prototype = {
for (let marker of markers) {
if (!isMarkerInRange(marker, timeStart, timeEnd)) {
continue;
}
// Only build and display a finite number of markers initially, to
// preserve a snappy UI. After a certain delay, continue building the
// outstanding markers while there's (hopefully) no user interaction.
let arguments_ = [this._fragment, marker, timeStart, dataScale];
- if (processed++ < WATERFALL_IMMEDIATE_DRAW_MARKERS_COUNT) {
+ if (processed++ < TIMELINE_IMMEDIATE_DRAW_MARKERS_COUNT) {
this._buildMarker.apply(this, arguments_);
} else {
this._outstandingMarkers.push(arguments_);
}
}
// If there are no outstanding markers, add a dummy "spacer" at the end
// to fill up any remaining available space in the UI.
if (!this._outstandingMarkers.length) {
this._buildMarker(this._fragment, null);
}
// Otherwise prepare flushing the outstanding markers after a small delay.
else {
this._setNamedTimeout("flush-outstanding-markers",
- WATERFALL_FLUSH_OUTSTANDING_MARKERS_DELAY,
+ TIMELINE_FLUSH_OUTSTANDING_MARKERS_DELAY,
() => this._buildOutstandingMarkers(parent));
}
parent.appendChild(this._fragment);
},
/**
* Finishes building the outstanding markers in this view.
@@ -239,17 +236,17 @@ Waterfall.prototype = {
* The { name, start, end } marker in the data source.
* @param timeStart
* @see Waterfall.prototype.setData
* @param number dataScale
* @see Waterfall.prototype._buildMarkers
*/
_buildMarker: function(parent, marker, timeStart, dataScale) {
let container = this._document.createElement("hbox");
- container.className = "waterfall-marker-container";
+ container.className = "timeline-marker-container";
if (marker) {
this._buildMarkerSidebar(container, marker);
this._buildMarkerWaterfall(container, marker, timeStart, dataScale);
} else {
this._buildMarkerSpacer(container);
container.setAttribute("flex", "1");
container.setAttribute("is-spacer", "");
@@ -265,31 +262,31 @@ Waterfall.prototype = {
* The container node representing the marker in this view.
* @param object marker
* @see Waterfall.prototype._buildMarker
*/
_buildMarkerSidebar: function(container, marker) {
let blueprint = this._blueprint[marker.name];
let sidebar = this._document.createElement("hbox");
- sidebar.className = "waterfall-sidebar theme-sidebar";
- sidebar.setAttribute("width", WATERFALL_SIDEBAR_WIDTH);
+ sidebar.className = "timeline-marker-sidebar theme-sidebar";
+ sidebar.setAttribute("width", TIMELINE_MARKER_SIDEBAR_WIDTH);
sidebar.setAttribute("align", "center");
let bullet = this._document.createElement("hbox");
- bullet.className = "waterfall-marker-bullet";
+ bullet.className = "timeline-marker-bullet";
bullet.style.backgroundColor = blueprint.fill;
bullet.style.borderColor = blueprint.stroke;
bullet.setAttribute("type", marker.name);
sidebar.appendChild(bullet);
let name = this._document.createElement("label");
name.setAttribute("crop", "end");
name.setAttribute("flex", "1");
- name.className = "plain waterfall-marker-name";
+ name.className = "plain timeline-marker-name";
let label;
if (marker.detail && marker.detail.causeName) {
label = this._l10n.getFormatStr("timeline.markerDetailFormat",
blueprint.label,
marker.detail.causeName);
} else {
label = blueprint.label;
@@ -312,49 +309,48 @@ Waterfall.prototype = {
* @see Waterfall.prototype.setData
* @param number dataScale
* @see Waterfall.prototype._buildMarkers
*/
_buildMarkerWaterfall: function(container, marker, timeStart, dataScale) {
let blueprint = this._blueprint[marker.name];
let waterfall = this._document.createElement("hbox");
- waterfall.className = "waterfall-marker-item waterfall-background-ticks";
- waterfall.setAttribute("align", "center");
+ waterfall.className = "timeline-marker-waterfall";
waterfall.setAttribute("flex", "1");
let start = (marker.start - timeStart) * dataScale;
let width = (marker.end - marker.start) * dataScale;
let offset = this._isRTL ? this._waterfallWidth : 0;
let bar = this._document.createElement("hbox");
- bar.className = "waterfall-marker-bar";
+ bar.className = "timeline-marker-bar";
bar.style.backgroundColor = blueprint.fill;
bar.style.borderColor = blueprint.stroke;
bar.style.transform = "translateX(" + (start - offset) + "px)";
bar.setAttribute("type", marker.name);
- bar.setAttribute("width", Math.max(width, WATERFALL_MARKER_BAR_WIDTH_MIN));
+ bar.setAttribute("width", Math.max(width, TIMELINE_MARKER_BAR_WIDTH_MIN));
waterfall.appendChild(bar);
container.appendChild(waterfall);
},
/**
* Creates a dummy spacer as an empty marker.
*
* @param nsIDOMNode container
* The container node representing the marker.
*/
_buildMarkerSpacer: function(container) {
let sidebarSpacer = this._document.createElement("spacer");
- sidebarSpacer.className = "waterfall-sidebar theme-sidebar";
- sidebarSpacer.setAttribute("width", WATERFALL_SIDEBAR_WIDTH);
+ sidebarSpacer.className = "timeline-marker-sidebar theme-sidebar";
+ sidebarSpacer.setAttribute("width", TIMELINE_MARKER_SIDEBAR_WIDTH);
let waterfallSpacer = this._document.createElement("spacer");
- waterfallSpacer.className = "waterfall-marker-item waterfall-background-ticks";
+ waterfallSpacer.className = "timeline-marker-waterfall";
waterfallSpacer.setAttribute("flex", "1");
container.appendChild(sidebarSpacer);
container.appendChild(waterfallSpacer);
},
/**
* Creates the background displayed on the marker's waterfall.
--- a/browser/locales/en-US/chrome/browser/devtools/timeline.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/timeline.dtd
@@ -10,29 +10,20 @@
- You want to make that choice consistent across the developer tools.
- A good criteria is the language in which you'd find the best
- documentation on web development on the web. -->
<!-- LOCALIZATION NOTE (timelineUI.recordButton): This string is displayed
- on a button that starts a new recording. -->
<!ENTITY timelineUI.recordButton.tooltip "Record timeline operations">
-<!-- LOCALIZATION NOTE (timelineUI.recordLabel): This string is displayed
+<!-- LOCALIZATION NOTE (timelineUI.recordButton): This string is displayed
- as a label to signal that a recording is in progress. -->
<!ENTITY timelineUI.recordLabel "Recording…">
-<!-- LOCALIZATION NOTE (timelineUI.timelineUI.memoryCheckbox.label): This string
- - is displayed next to a checkbox determining whether or not memory
- - measurements are enabled. -->
-<!ENTITY timelineUI.memoryCheckbox.label "Memory">
-
-<!-- LOCALIZATION NOTE (timelineUI.timelineUI.memoryCheckbox.tooltip): This string
- - is displayed next to the memory checkbox -->
-<!ENTITY timelineUI.memoryCheckbox.tooltip "Enable memory measurements">
-
<!-- LOCALIZATION NOTE (timelineUI.emptyNotice1/2): This is the label shown
- in the timeline view when empty. -->
<!ENTITY timelineUI.emptyNotice1 "Click on the">
<!ENTITY timelineUI.emptyNotice2 "button to start recording timeline events.">
<!-- LOCALIZATION NOTE (timelineUI.stopNotice1/2): This is the label shown
- in the timeline view while recording. -->
<!ENTITY timelineUI.stopNotice1 "Click on the">
--- a/browser/locales/en-US/chrome/browser/devtools/timeline.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/timeline.properties
@@ -36,19 +36,13 @@ timeline.records=RECORDS
# LOCALIZATION NOTE (timeline.label.*):
# These strings are displayed in the timeline waterfall, identifying markers.
timeline.label.styles=Styles
timeline.label.reflow=Reflow
timeline.label.paint=Paint
timeline.label.domevent=DOM Event
timeline.label.consoleTime=Console
-# LOCALIZATION NOTE (graphs.memory):
-# This string is displayed in the memory graph of the Performance tool,
-# as the unit used to memory consumption. This label should be kept
-# AS SHORT AS POSSIBLE so it doesn't obstruct important parts of the graph.
-graphs.memory=MB
-
# LOCALIZATION NOTE (timeline.markerDetailFormat):
# Some timeline markers come with details, like a size, a name, a js function.
# %1$S is replaced with one of the above label (timeline.label.*) and %2$S
# with the details. For examples: Paint (200x100), or console.time (FOO)
timeline.markerDetailFormat=%1$S (%2$S)
--- a/browser/themes/shared/devtools/timeline.inc.css
+++ b/browser/themes/shared/devtools/timeline.inc.css
@@ -43,113 +43,117 @@
list-style-image: url(profiler-stopwatch-checked.svg);
}
#empty-notice button .button-text,
#recording-notice button .button-text {
display: none;
}
-.theme-dark #timeline-pane {
- border-top: 1px solid #000;
+.theme-dark #timeline-overview {
+ border-bottom: 1px solid #000;
}
-.theme-light #timeline-pane {
- border-top: 1px solid #aaa;
+.theme-light #timeline-overview {
+ border-bottom: 1px solid #aaa;
}
-.waterfall-list-contents {
+.timeline-list-contents {
/* Hack: force hardware acceleration */
transform: translateZ(1px);
overflow-x: hidden;
overflow-y: auto;
}
-.waterfall-background-ticks {
+.timeline-header-ticks,
+.timeline-marker-waterfall {
/* Background created on a <canvas> in js. */
/* @see browser/devtools/timeline/widgets/waterfall.js */
background-image: -moz-element(#waterfall-background);
background-repeat: repeat-y;
background-position: -1px center;
}
-.waterfall-marker-container[is-spacer] {
+.timeline-marker-waterfall {
+ overflow: hidden;
+}
+
+.timeline-marker-container[is-spacer] {
pointer-events: none;
}
-.theme-dark .waterfall-marker-container:not([is-spacer]):nth-child(2n) {
+.theme-dark .timeline-marker-container:not([is-spacer]):nth-child(2n) {
background-color: rgba(255,255,255,0.03);
}
-.theme-light .waterfall-marker-container:not([is-spacer]):nth-child(2n) {
+.theme-light .timeline-marker-container:not([is-spacer]):nth-child(2n) {
background-color: rgba(128,128,128,0.03);
}
-.theme-dark .waterfall-marker-container:hover {
+.theme-dark .timeline-marker-container:hover {
background-color: rgba(255,255,255,0.1) !important;
}
-.theme-light .waterfall-marker-container:hover {
+.theme-light .timeline-marker-container:hover {
background-color: rgba(128,128,128,0.1) !important;
}
-.waterfall-marker-item {
- overflow: hidden;
-}
-
-.waterfall-sidebar {
+.timeline-header-sidebar,
+.timeline-marker-sidebar {
-moz-border-end: 1px solid;
}
-.theme-dark .waterfall-sidebar {
+.theme-dark .timeline-header-sidebar,
+.theme-dark .timeline-marker-sidebar {
-moz-border-end-color: #000;
}
-.theme-light .waterfall-sidebar {
+.theme-light .timeline-header-sidebar,
+.theme-light .timeline-marker-sidebar {
-moz-border-end-color: #aaa;
}
-.waterfall-marker-container:hover > .waterfall-sidebar {
+.timeline-header-sidebar {
+ padding: 5px;
+}
+
+.timeline-marker-sidebar {
+ padding: 2px;
+}
+
+.timeline-marker-container:hover > .timeline-marker-sidebar {
background-color: transparent;
}
-.waterfall-header-name {
- padding: 4px;
-}
-
-.waterfall-header-tick {
+.timeline-header-tick {
width: 100px;
font-size: 9px;
transform-origin: left center;
}
-.theme-dark .waterfall-header-tick {
+.theme-dark .timeline-header-tick {
color: #a9bacb;
}
-.theme-light .waterfall-header-tick {
+.theme-light .timeline-header-tick {
color: #292e33;
}
-.waterfall-header-tick:not(:first-child) {
+.timeline-header-tick:not(:first-child) {
-moz-margin-start: -100px !important; /* Don't affect layout. */
}
-.waterfall-marker-bullet {
+.timeline-marker-bullet {
width: 8px;
height: 8px;
-moz-margin-start: 8px;
-moz-margin-end: 6px;
border: 1px solid;
border-radius: 1px;
}
-.waterfall-marker-name {
- font-size: 95%;
- padding-bottom: 1px !important;
-}
-
-.waterfall-marker-bar {
- height: 9px;
+.timeline-marker-bar {
+ margin-top: 4px;
+ margin-bottom: 4px;
border: 1px solid;
border-radius: 1px;
transform-origin: left center;
}
--- a/browser/themes/shared/devtools/widgets.inc.css
+++ b/browser/themes/shared/devtools/widgets.inc.css
@@ -933,31 +933,36 @@
}
.graph-widget-canvas[input=dragging-selection-contents] {
cursor: grabbing;
}
/* Line graph widget */
+.line-graph-widget-canvas {
+ background: #0088cc;
+}
+
.line-graph-widget-gutter {
position: absolute;
background: rgba(255,255,255,0.75);
width: 10px;
height: 100%;
top: 0;
left: 0;
border-right: 1px solid rgba(255,255,255,0.25);
pointer-events: none;
}
.line-graph-widget-gutter-line {
position: absolute;
width: 100%;
border-top: 1px solid;
+ transform: translateY(-1px);
}
.line-graph-widget-gutter-line[type=maximum] {
border-color: #2cbb0f;
}
.line-graph-widget-gutter-line[type=minimum] {
border-color: #ed2655;
@@ -965,66 +970,55 @@
.line-graph-widget-gutter-line[type=average] {
border-color: #d97e00;
}
.line-graph-widget-tooltip {
position: absolute;
background: rgba(255,255,255,0.75);
+ box-shadow: 0 2px 1px rgba(0,0,0,0.1);
border-radius: 2px;
line-height: 15px;
-moz-padding-start: 6px;
-moz-padding-end: 6px;
transform: translateY(-50%);
font-size: 80%;
z-index: 1;
pointer-events: none;
}
-.line-graph-widget-tooltip[with-arrows=true]::before {
+.line-graph-widget-tooltip::before {
content: "";
position: absolute;
border-top: 3px solid transparent;
border-bottom: 3px solid transparent;
top: calc(50% - 3px);
}
-.line-graph-widget-tooltip[arrow=start][with-arrows=true]::before {
+.line-graph-widget-tooltip[arrow=start]::before {
-moz-border-end: 3px solid rgba(255,255,255,0.75);
left: -3px;
}
-.line-graph-widget-tooltip[arrow=end][with-arrows=true]::before {
+.line-graph-widget-tooltip[arrow=end]::before {
-moz-border-start: 3px solid rgba(255,255,255,0.75);
right: -3px;
}
.line-graph-widget-tooltip[type=maximum] {
- left: -1px;
+ left: calc(10px + 6px);
}
.line-graph-widget-tooltip[type=minimum] {
- left: -1px;
+ left: calc(10px + 6px);
}
.line-graph-widget-tooltip[type=average] {
- right: -1px;
-}
-
-.line-graph-widget-tooltip[type=maximum][with-arrows=true] {
- left: 14px;
-}
-
-.line-graph-widget-tooltip[type=minimum][with-arrows=true] {
- left: 14px;
-}
-
-.line-graph-widget-tooltip[type=average][with-arrows=true] {
- right: 4px;
+ right: 6px;
}
.line-graph-widget-tooltip > [text=info] {
color: #18191a;
}
.line-graph-widget-tooltip > [text=value] {
-moz-margin-start: 3px;