Bug 1007202 - Create a framerate widget, r=pbrosset,rcampbell

This commit is contained in:
Victor Porof 2014-05-29 09:54:00 -04:00
parent 14da6bad13
commit 91363cf86d
17 changed files with 2426 additions and 3 deletions

View File

@ -121,9 +121,9 @@ browser.jar:
content/browser/devtools/app-manager/index.js (app-manager/content/index.js)
content/browser/devtools/app-manager/help.xhtml (app-manager/content/help.xhtml)
content/browser/devtools/app-manager/manifest-editor.js (app-manager/content/manifest-editor.js)
content/browser/devtools/graphs-frame.xhtml (shared/widgets/graphs-frame.xhtml)
content/browser/devtools/spectrum-frame.xhtml (shared/widgets/spectrum-frame.xhtml)
content/browser/devtools/spectrum.css (shared/widgets/spectrum.css)
content/browser/devtools/eyedropper.xul (eyedropper/eyedropper.xul)
content/browser/devtools/eyedropper/crosshairs.css (eyedropper/crosshairs.css)
content/browser/devtools/eyedropper/nocursor.css (eyedropper/nocursor.css)

View File

@ -11,6 +11,16 @@ support-files =
leakhunt.js
[browser_css_color.js]
[browser_graphs-01.js]
[browser_graphs-02.js]
[browser_graphs-03.js]
[browser_graphs-04.js]
[browser_graphs-05.js]
[browser_graphs-06.js]
[browser_graphs-07.js]
[browser_graphs-08.js]
[browser_graphs-09.js]
[browser_graphs-10.js]
[browser_layoutHelpers.js]
[browser_observableobject.js]
[browser_outputparser.js]

View File

@ -0,0 +1,63 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that graph widgets works properly.
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();
doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
let graph = new LineGraphWidget(doc.body, "fps");
yield graph.once("ready");
testGraph(host, graph);
graph.destroy();
host.destroy();
}
function testGraph(host, graph) {
ok(graph._container.classList.contains("line-graph-widget-container"),
"The correct graph container was created.");
ok(graph._canvas.classList.contains("line-graph-widget-canvas"),
"The correct graph container was created.");
let bounds = host.frame.getBoundingClientRect();
is(graph.width, bounds.width * window.devicePixelRatio,
"The graph has the correct width.");
is(graph.height, bounds.height * window.devicePixelRatio,
"The graph has the correct height.");
ok(graph._cursor.x === null,
"The graph's cursor X coordinate is initially null.");
ok(graph._cursor.y === null,
"The graph's cursor Y coordinate is initially null.");
ok(graph._selection.start === null,
"The graph's selection start value is initially null.");
ok(graph._selection.end === null,
"The graph's selection end value is initially null.");
ok(graph._selectionDragger.origin === null,
"The graph's dragger origin value is initially null.");
ok(graph._selectionDragger.anchor.start === null,
"The graph's dragger anchor start value is initially null.");
ok(graph._selectionDragger.anchor.end === null,
"The graph's dragger anchor end value is initially null.");
ok(graph._selectionResizer.margin === null,
"The graph's resizer margin value is initially null.");
}

View File

@ -0,0 +1,71 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that graph widgets can properly add data and regions.
const TEST_DATA = {"112":48,"213":59,"313":60,"413":59,"530":59,"646":58,"747":60,"863":48,"980":37,"1097":30,"1213":29,"1330":23,"1430":10,"1534":17,"1645":20,"1746":22,"1846":39,"1963":26,"2080":27,"2197":35,"2312":47,"2412":53,"2514":60,"2630":37,"2730":36,"2830":37,"2946":36,"3046":40,"3163":47,"3280":41,"3380":35,"3480":27,"3580":39,"3680":42,"3780":49,"3880":55,"3980":60,"4080":60,"4180":60};
const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
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 graph.once("ready");
testGraph(graph);
graph.destroy();
host.destroy();
}
function testGraph(graph) {
let thrown1;
try {
graph.setRegions(TEST_REGIONS);
} catch (e) {
thrown1 = true;
}
ok(thrown1, "Setting regions before setting data shouldn't work.");
graph.setData(TEST_DATA);
graph.setRegions(TEST_REGIONS);
let thrown2;
try {
graph.setRegions(TEST_REGIONS);
} catch (e) {
thrown2 = true;
}
ok(thrown2, "Setting regions twice shouldn't work.");
ok(graph.hasData(), "The graph should now have the data source set.");
ok(graph.hasRegions(), "The graph should now have the regions set.");
is(graph.dataScaleX,
graph.width / 4180, // last key in TEST_DATA
"The data scale on the X axis is correct.");
is(graph.dataScaleY,
graph.height / 60 * 0.85, // max value in TEST_DATA * GRAPH_DAMPEN_VALUES
"The data scale on the Y axis is correct.");
for (let i = 0; i < TEST_REGIONS.length; i++) {
let original = TEST_REGIONS[i];
let normalized = graph._regions[i];
is(original.start * graph.dataScaleX, normalized.start,
"The region's start value was properly normalized.");
is(original.end * graph.dataScaleX, normalized.end,
"The region's end value was properly normalized.");
}
}

View File

@ -0,0 +1,113 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that graph widgets can handle clients getting/setting the
// selection or cursor.
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 graph.once("ready");
yield testSelection(graph);
yield testCursor(graph);
graph.destroy();
host.destroy();
}
function* testSelection(graph) {
ok(graph.getSelection().start === null,
"The graph's selection should initially have a null start value.");
ok(graph.getSelection().end === null,
"The graph's selection should initially have a null end value.");
ok(!graph.hasSelection(),
"There shouldn't initially be any selection.");
let selected = graph.once("selecting");
graph.setSelection({ start: 100, end: 200 });
yield selected;
ok(true, "A 'selecting' event has been fired.");
ok(graph.hasSelection(),
"There should now be a selection.");
is(graph.getSelection().start, 100,
"The graph's selection now has an updated start value.");
is(graph.getSelection().end, 200,
"The graph's selection now has an updated end value.");
let thrown;
try {
graph.setSelection({ start: null, end: null });
} catch(e) {
thrown = true;
}
ok(thrown, "Setting a null selection shouldn't work.");
ok(graph.hasSelection(),
"There should still be a selection.");
let deselected = graph.once("deselecting");
graph.dropSelection();
yield deselected;
ok(true, "A 'deselecting' event has been fired.");
ok(!graph.hasSelection(),
"There shouldn't be any selection anymore.");
ok(graph.getSelection().start === null,
"The graph's selection now has a null start value.");
ok(graph.getSelection().end === null,
"The graph's selection now has a null end value.");
}
function* testCursor(graph) {
ok(graph.getCursor().x === null,
"The graph's cursor should initially have a null X value.");
ok(graph.getCursor().y === null,
"The graph's cursor should initially have a null Y value.");
ok(!graph.hasCursor(),
"There shouldn't initially be any cursor.");
graph.setCursor({ x: 100, y: 50 });
ok(graph.hasCursor(),
"There should now be a cursor.");
is(graph.getCursor().x, 100,
"The graph's cursor now has an updated start value.");
is(graph.getCursor().y, 50,
"The graph's cursor now has an updated end value.");
let thrown;
try {
graph.setCursor({ x: null, y: null });
} catch(e) {
thrown = true;
}
ok(thrown, "Setting a null cursor shouldn't work.");
ok(graph.hasCursor(),
"There should still be a cursor.");
graph.dropCursor();
ok(!graph.hasCursor(),
"There shouldn't be any cursor anymore.");
ok(graph.getCursor().x === null,
"The graph's cursor now has a null start value.");
ok(graph.getCursor().y === null,
"The graph's cursor now has a null end value.");
}

View File

@ -0,0 +1,71 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that graph widgets can correctly compare selections and cursors.
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 graph.once("ready");
testGraph(graph);
graph.destroy();
host.destroy();
}
function testGraph(graph) {
ok(!graph.hasSelection(),
"There shouldn't initially be any selection.");
is(graph.getSelectionWidth(), 0,
"The selection width should be 0 when there's no selection.");
graph.setSelection({ start: 100, end: 200 });
ok(graph.hasSelection(),
"There should now be a selection.");
is(graph.getSelectionWidth(), 100,
"The selection width should now be 100.");
ok(graph.isSelectionDifferent({ start: 100, end: 201 }),
"The selection was correctly reported to be different (1).");
ok(graph.isSelectionDifferent({ start: 101, end: 200 }),
"The selection was correctly reported to be different (2).");
ok(graph.isSelectionDifferent({ start: null, end: null }),
"The selection was correctly reported to be different (3).");
ok(graph.isSelectionDifferent(null),
"The selection was correctly reported to be different (4).");
ok(!graph.isSelectionDifferent({ start: 100, end: 200 }),
"The selection was incorrectly reported to be different (1).");
ok(!graph.isSelectionDifferent(graph.getSelection()),
"The selection was incorrectly reported to be different (2).");
graph.setCursor({ x: 100, y: 50 });
ok(graph.isCursorDifferent({ x: 100, y: 51 }),
"The cursor was correctly reported to be different (1).");
ok(graph.isCursorDifferent({ x: 101, y: 50 }),
"The cursor was correctly reported to be different (2).");
ok(graph.isCursorDifferent({ x: null, y: null }),
"The cursor was correctly reported to be different (3).");
ok(graph.isCursorDifferent(null),
"The cursor was correctly reported to be different (4).");
ok(!graph.isCursorDifferent({ x: 100, y: 50 }),
"The cursor was incorrectly reported to be different (1).");
ok(!graph.isCursorDifferent(graph.getCursor()),
"The cursor was incorrectly reported to be different (2).");
}

View File

@ -0,0 +1,135 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that graph widgets can correctly determine which regions are hovered.
const TEST_DATA = {"112":48,"213":59,"313":60,"413":59,"530":59,"646":58,"747":60,"863":48,"980":37,"1097":30,"1213":29,"1330":23,"1430":10,"1534":17,"1645":20,"1746":22,"1846":39,"1963":26,"2080":27,"2197":35,"2312":47,"2412":53,"2514":60,"2630":37,"2730":36,"2830":37,"2946":36,"3046":40,"3163":47,"3280":41,"3380":35,"3480":27,"3580":39,"3680":42,"3780":49,"3880":55,"3980":60,"4080":60,"4180":60};
const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
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 graph.once("ready");
testGraph(graph);
graph.destroy();
host.destroy();
}
function testGraph(graph) {
ok(!graph.getHoveredRegion(),
"There should be no hovered region yet because there's no regions.");
ok(!graph._isHoveringStartBoundary(),
"The graph start boundary should not be hovered.");
ok(!graph._isHoveringEndBoundary(),
"The graph end boundary should not be hovered.");
ok(!graph._isHoveringSelectionContents(),
"The graph contents should not be hovered.");
ok(!graph._isHoveringSelectionContentsOrBoundaries(),
"The graph contents or boundaries should not be hovered.");
graph.setData(TEST_DATA);
graph.setRegions(TEST_REGIONS);
ok(!graph.getHoveredRegion(),
"There should be no hovered region yet because there's no cursor.");
graph.setCursor({ x: TEST_REGIONS[0].start * graph.dataScaleX - 1, y: 0 });
ok(!graph.getHoveredRegion(),
"There shouldn't be any hovered region yet.");
graph.setCursor({ x: TEST_REGIONS[0].start * graph.dataScaleX + 1, y: 0 });
ok(graph.getHoveredRegion(),
"There should be a hovered region now.");
is(graph.getHoveredRegion().start, 320 * graph.dataScaleX,
"The reported hovered region is correct (1).");
is(graph.getHoveredRegion().end, 460 * graph.dataScaleX,
"The reported hovered region is correct (2).");
graph.setSelection({ start: 100, end: 200 });
info("Setting cursor over the left boundary.");
graph.setCursor({ x: 100, y: 0 });
ok(graph._isHoveringStartBoundary(),
"The graph start boundary should be hovered.");
ok(!graph._isHoveringEndBoundary(),
"The graph end boundary should not be hovered.");
ok(!graph._isHoveringSelectionContents(),
"The graph contents should not be hovered.");
ok(graph._isHoveringSelectionContentsOrBoundaries(),
"The graph contents or boundaries should be hovered.");
info("Setting cursor near the left boundary.");
graph.setCursor({ x: 105, y: 0 });
ok(graph._isHoveringStartBoundary(),
"The graph start boundary should be hovered.");
ok(!graph._isHoveringEndBoundary(),
"The graph end boundary should not be hovered.");
ok(graph._isHoveringSelectionContents(),
"The graph contents should be hovered.");
ok(graph._isHoveringSelectionContentsOrBoundaries(),
"The graph contents or boundaries should be hovered.");
info("Setting cursor over the selection.");
graph.setCursor({ x: 150, y: 0 });
ok(!graph._isHoveringStartBoundary(),
"The graph start boundary should not be hovered.");
ok(!graph._isHoveringEndBoundary(),
"The graph end boundary should not be hovered.");
ok(graph._isHoveringSelectionContents(),
"The graph contents should be hovered.");
ok(graph._isHoveringSelectionContentsOrBoundaries(),
"The graph contents or boundaries should be hovered.");
info("Setting cursor near the right boundary.");
graph.setCursor({ x: 195, y: 0 });
ok(!graph._isHoveringStartBoundary(),
"The graph start boundary should not be hovered.");
ok(graph._isHoveringEndBoundary(),
"The graph end boundary should be hovered.");
ok(graph._isHoveringSelectionContents(),
"The graph contents should be hovered.");
ok(graph._isHoveringSelectionContentsOrBoundaries(),
"The graph contents or boundaries should be hovered.");
info("Setting cursor over the right boundary.");
graph.setCursor({ x: 200, y: 0 });
ok(!graph._isHoveringStartBoundary(),
"The graph start boundary should not be hovered.");
ok(graph._isHoveringEndBoundary(),
"The graph end boundary should be hovered.");
ok(!graph._isHoveringSelectionContents(),
"The graph contents should not be hovered.");
ok(graph._isHoveringSelectionContentsOrBoundaries(),
"The graph contents or boundaries should be hovered.");
info("Setting away from the selection.");
graph.setCursor({ x: 300, y: 0 });
ok(!graph._isHoveringStartBoundary(),
"The graph start boundary should not be hovered.");
ok(!graph._isHoveringEndBoundary(),
"The graph end boundary should not be hovered.");
ok(!graph._isHoveringSelectionContents(),
"The graph contents should not be hovered.");
ok(!graph._isHoveringSelectionContentsOrBoundaries(),
"The graph contents or boundaries should not be hovered.");
}

View File

@ -0,0 +1,56 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests if clicking on regions adds a selection spanning that region.
const TEST_DATA = {"112":48,"213":59,"313":60,"413":59,"530":59,"646":58,"747":60,"863":48,"980":37,"1097":30,"1213":29,"1330":23,"1430":10,"1534":17,"1645":20,"1746":22,"1846":39,"1963":26,"2080":27,"2197":35,"2312":47,"2412":53,"2514":60,"2630":37,"2730":36,"2830":37,"2946":36,"3046":40,"3163":47,"3280":41,"3380":35,"3480":27,"3580":39,"3680":42,"3780":49,"3880":55,"3980":60,"4080":60,"4180":60};
const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
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 graph.once("ready");
testGraph(graph);
graph.destroy();
host.destroy();
}
function testGraph(graph) {
graph.setData(TEST_DATA);
graph.setRegions(TEST_REGIONS);
click(graph, (graph._regions[0].start + graph._regions[0].end) / 2);
is(graph.getSelection().start, graph._regions[0].start,
"The first region is now selected (1).");
is(graph.getSelection().end, graph._regions[0].end,
"The first region is now selected (2).");
click(graph, (graph._regions[1].start + graph._regions[1].end) / 2);
is(graph.getSelection().start, graph._regions[1].start,
"The second region is now selected (1).");
is(graph.getSelection().end, graph._regions[1].end,
"The second region is now selected (2).");
}
// EventUtils just doesn't work!
function click(graph, x, y = 1) {
x /= window.devicePixelRatio;
y /= window.devicePixelRatio;
graph._onMouseMove({ clientX: x, clientY: y });
graph._onMouseDown({ clientX: x, clientY: y });
graph._onMouseUp({ clientX: x, clientY: y });
}

View File

@ -0,0 +1,204 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests if selecting, resizing, moving selections and zooming in/out works.
const TEST_DATA = {"112":48,"213":59,"313":60,"413":59,"530":59,"646":58,"747":60,"863":48,"980":37,"1097":30,"1213":29,"1330":23,"1430":10,"1534":17,"1645":20,"1746":22,"1846":39,"1963":26,"2080":27,"2197":35,"2312":47,"2412":53,"2514":60,"2630":37,"2730":36,"2830":37,"2946":36,"3046":40,"3163":47,"3280":41,"3380":35,"3480":27,"3580":39,"3680":42,"3780":49,"3880":55,"3980":60,"4080":60,"4180":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");
yield graph.once("ready");
testGraph(graph);
graph.destroy();
host.destroy();
}
function testGraph(graph) {
graph.setData(TEST_DATA);
info("Making a selection.");
dragStart(graph, 300);
ok(graph.hasSelectionInProgress(),
"The selection should start (1).");
is(graph.getSelection().start, 300,
"The current selection start value is correct (1).");
is(graph.getSelection().end, 300,
"The current selection end value is correct (1).");
hover(graph, 400);
ok(graph.hasSelectionInProgress(),
"The selection should still be in progress (2).");
is(graph.getSelection().start, 300,
"The current selection start value is correct (2).");
is(graph.getSelection().end, 400,
"The current selection end value is correct (2).");
dragStop(graph, 500);
ok(!graph.hasSelectionInProgress(),
"The selection should have stopped (3).");
is(graph.getSelection().start, 300,
"The current selection start value is correct (3).");
is(graph.getSelection().end, 500,
"The current selection end value is correct (3).");
info("Making a new selection.");
dragStart(graph, 200);
ok(graph.hasSelectionInProgress(),
"The selection should start (4).");
is(graph.getSelection().start, 200,
"The current selection start value is correct (4).");
is(graph.getSelection().end, 200,
"The current selection end value is correct (4).");
hover(graph, 300);
ok(graph.hasSelectionInProgress(),
"The selection should still be in progress (5).");
is(graph.getSelection().start, 200,
"The current selection start value is correct (5).");
is(graph.getSelection().end, 300,
"The current selection end value is correct (5).");
dragStop(graph, 400);
ok(!graph.hasSelectionInProgress(),
"The selection should have stopped (6).");
is(graph.getSelection().start, 200,
"The current selection start value is correct (6).");
is(graph.getSelection().end, 400,
"The current selection end value is correct (6).");
info("Resizing by dragging the end handlebar.");
dragStart(graph, 400);
is(graph.getSelection().start, 200,
"The current selection start value is correct (7).");
is(graph.getSelection().end, 400,
"The current selection end value is correct (7).");
dragStop(graph, 600);
is(graph.getSelection().start, 200,
"The current selection start value is correct (8).");
is(graph.getSelection().end, 600,
"The current selection end value is correct (8).");
info("Resizing by dragging the start handlebar.");
dragStart(graph, 200);
is(graph.getSelection().start, 200,
"The current selection start value is correct (9).");
is(graph.getSelection().end, 600,
"The current selection end value is correct (9).");
dragStop(graph, 100);
is(graph.getSelection().start, 100,
"The current selection start value is correct (10).");
is(graph.getSelection().end, 600,
"The current selection end value is correct (10).");
info("Moving by dragging the selection.");
dragStart(graph, 300);
hover(graph, 400);
is(graph.getSelection().start, 200,
"The current selection start value is correct (11).");
is(graph.getSelection().end, 700,
"The current selection end value is correct (11).");
dragStop(graph, 500);
is(graph.getSelection().start, 300,
"The current selection start value is correct (12).");
is(graph.getSelection().end, 800,
"The current selection end value is correct (12).");
info("Zooming in by scrolling inside the selection.");
scroll(graph, -1000, 600);
is(graph.getSelection().start, 525,
"The current selection start value is correct (13).");
is(graph.getSelection().end, 650,
"The current selection end value is correct (13).");
info("Zooming out by scrolling inside the selection.");
scroll(graph, 1000, 600);
is(graph.getSelection().start, 468.75,
"The current selection start value is correct (14).");
is(graph.getSelection().end, 687.5,
"The current selection end value is correct (14).");
info("Sliding left by scrolling outside the selection.");
scroll(graph, 100, 900);
is(graph.getSelection().start, 458.75,
"The current selection start value is correct (15).");
is(graph.getSelection().end, 677.5,
"The current selection end value is correct (15).");
info("Sliding right by scrolling outside the selection.");
scroll(graph, -100, 900);
is(graph.getSelection().start, 468.75,
"The current selection start value is correct (16).");
is(graph.getSelection().end, 687.5,
"The current selection end value is correct (16).");
info("Zooming out a lot.");
scroll(graph, Number.MAX_SAFE_INTEGER, 500);
is(graph.getSelection().start, 1,
"The current selection start value is correct (17).");
is(graph.getSelection().end, graph.width - 1,
"The current selection end value is correct (17).");
}
// EventUtils just doesn't work!
function hover(graph, x, y = 1) {
x /= window.devicePixelRatio;
y /= window.devicePixelRatio;
graph._onMouseMove({ clientX: x, clientY: y });
}
function click(graph, x, y = 1) {
x /= window.devicePixelRatio;
y /= window.devicePixelRatio;
graph._onMouseMove({ clientX: x, clientY: y });
graph._onMouseDown({ clientX: x, clientY: y });
graph._onMouseUp({ clientX: x, clientY: y });
}
function dragStart(graph, x, y = 1) {
x /= window.devicePixelRatio;
y /= window.devicePixelRatio;
graph._onMouseMove({ clientX: x, clientY: y });
graph._onMouseDown({ clientX: x, clientY: y });
}
function dragStop(graph, x, y = 1) {
x /= window.devicePixelRatio;
y /= window.devicePixelRatio;
graph._onMouseMove({ clientX: x, clientY: y });
graph._onMouseUp({ clientX: x, clientY: y });
}
function scroll(graph, wheel, x, y = 1) {
x /= window.devicePixelRatio;
y /= window.devicePixelRatio;
graph._onMouseMove({ clientX: x, clientY: y });
graph._onMouseWheel({ clientX: x, clientY: y, detail: wheel });
}

View File

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests if a selection is dropped when clicking outside of it.
const TEST_DATA = {"112":48,"213":59,"313":60,"413":59,"530":59,"646":58,"747":60,"863":48,"980":37,"1097":30,"1213":29,"1330":23,"1430":10,"1534":17,"1645":20,"1746":22,"1846":39,"1963":26,"2080":27,"2197":35,"2312":47,"2412":53,"2514":60,"2630":37,"2730":36,"2830":37,"2946":36,"3046":40,"3163":47,"3280":41,"3380":35,"3480":27,"3580":39,"3680":42,"3780":49,"3880":55,"3980":60,"4080":60,"4180":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");
yield graph.once("ready");
testGraph(graph);
graph.destroy();
host.destroy();
}
function testGraph(graph) {
graph.setData(TEST_DATA);
dragStart(graph, 300);
dragStop(graph, 500);
ok(graph.hasSelection(),
"A selection should be available.");
is(graph.getSelection().start, 300,
"The current selection start value is correct.");
is(graph.getSelection().end, 500,
"The current selection end value is correct.");
click(graph, 600);
ok(!graph.hasSelection(),
"The selection should be dropped.");
}
// EventUtils just doesn't work!
function click(graph, x, y = 1) {
x /= window.devicePixelRatio;
y /= window.devicePixelRatio;
graph._onMouseMove({ clientX: x, clientY: y });
graph._onMouseDown({ clientX: x, clientY: y });
graph._onMouseUp({ clientX: x, clientY: y });
}
function dragStart(graph, x, y = 1) {
x /= window.devicePixelRatio;
y /= window.devicePixelRatio;
graph._onMouseMove({ clientX: x, clientY: y });
graph._onMouseDown({ clientX: x, clientY: y });
}
function dragStop(graph, x, y = 1) {
x /= window.devicePixelRatio;
y /= window.devicePixelRatio;
graph._onMouseMove({ clientX: x, clientY: y });
graph._onMouseUp({ clientX: x, clientY: y });
}

View File

@ -0,0 +1,67 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that line graphs properly create the gutter and tooltips.
const TEST_DATA = {"112":48,"213":59,"313":60,"413":59,"530":59,"646":58,"747":60,"863":48,"980":37,"1097":30,"1213":29,"1330":23,"1430":10,"1534":17,"1645":20,"1746":22,"1846":39,"1963":26,"2080":27,"2197":35,"2312":47,"2412":53,"2514":60,"2630":37,"2730":36,"2830":37,"2946":36,"3046":40,"3163":47,"3280":41,"3380":35,"3480":27,"3580":39,"3680":42,"3780":49,"3880":55,"3980":60,"4080":60,"4180":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");
yield graph.once("ready");
testGraph(graph);
graph.destroy();
host.destroy();
}
function testGraph(graph) {
graph.setData(TEST_DATA);
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",
"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.");
is(graph._minTooltip.querySelector("[text=metric]").textContent, "fps",
"The minimum tooltip displays the correct metric.");
is(parseInt(graph._maxTooltip.style.top), 22,
"The maximum tooltip is positioned correctly.");
is(parseInt(graph._avgTooltip.style.top), 61,
"The average tooltip is positioned correctly.");
is(parseInt(graph._minTooltip.style.top), 128,
"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.");
}

View File

@ -0,0 +1,142 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that line graph properly handles resizing.
const TEST_DATA = {"112":48,"213":59,"313":60,"413":59,"530":59,"646":58,"747":60,"863":48,"980":37,"1097":30,"1213":29,"1330":23,"1430":10,"1534":17,"1645":20,"1746":22,"1846":39,"1963":26,"2080":27,"2197":35,"2312":47,"2412":53,"2514":60,"2630":37,"2730":36,"2830":37,"2946":36,"3046":40,"3163":47,"3280":41,"3380":35,"3480":27,"3580":39,"3680":42,"3780":49,"3880":55,"3980":60,"4080":60,"4180":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("window");
doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
let graph = new LineGraphWidget(doc.body, "fps");
yield graph.once("ready");
let refreshCount = 0;
graph.on("refresh", () => refreshCount++);
yield testGraph(host, graph);
is(refreshCount, 2, "The graph should've been refreshed 2 times.");
graph.destroy();
host.destroy();
}
function* testGraph(host, graph) {
graph.setData(TEST_DATA);
let initialBounds = host.frame.getBoundingClientRect();
host._window.resizeBy(-100, -100);
yield graph.once("refresh");
let newBounds = host.frame.getBoundingClientRect();
is(initialBounds.width - newBounds.width, 100,
"The window was properly resized (1).");
is(initialBounds.height - newBounds.height, 100,
"The window was properly resized (2).");
is(graph.width, newBounds.width * window.devicePixelRatio,
"The graph has the correct width (1).");
is(graph.height, newBounds.height * window.devicePixelRatio,
"The graph has the correct height (1).");
info("Making a selection.");
dragStart(graph, 300);
ok(graph.hasSelectionInProgress(),
"The selection should start (1).");
is(graph.getSelection().start, 300,
"The current selection start value is correct (1).");
is(graph.getSelection().end, 300,
"The current selection end value is correct (1).");
hover(graph, 400);
ok(graph.hasSelectionInProgress(),
"The selection should still be in progress (2).");
is(graph.getSelection().start, 300,
"The current selection start value is correct (2).");
is(graph.getSelection().end, 400,
"The current selection end value is correct (2).");
dragStop(graph, 500);
ok(!graph.hasSelectionInProgress(),
"The selection should have stopped (3).");
is(graph.getSelection().start, 300,
"The current selection start value is correct (3).");
is(graph.getSelection().end, 500,
"The current selection end value is correct (3).");
host._window.resizeBy(100, 100);
yield graph.once("refresh");
let newerBounds = host.frame.getBoundingClientRect();
is(initialBounds.width - newerBounds.width, 0,
"The window was properly resized (3).");
is(initialBounds.height - newerBounds.height, 0,
"The window was properly resized (4).");
is(graph.width, newerBounds.width * window.devicePixelRatio,
"The graph has the correct width (2).");
is(graph.height, newerBounds.height * window.devicePixelRatio,
"The graph has the correct height (2).");
info("Making a new selection.");
dragStart(graph, 200);
ok(graph.hasSelectionInProgress(),
"The selection should start (4).");
is(graph.getSelection().start, 200,
"The current selection start value is correct (4).");
is(graph.getSelection().end, 200,
"The current selection end value is correct (4).");
hover(graph, 300);
ok(graph.hasSelectionInProgress(),
"The selection should still be in progress (5).");
is(graph.getSelection().start, 200,
"The current selection start value is correct (5).");
is(graph.getSelection().end, 300,
"The current selection end value is correct (5).");
dragStop(graph, 400);
ok(!graph.hasSelectionInProgress(),
"The selection should have stopped (6).");
is(graph.getSelection().start, 200,
"The current selection start value is correct (6).");
is(graph.getSelection().end, 400,
"The current selection end value is correct (6).");
}
// EventUtils just doesn't work!
function hover(graph, x, y = 1) {
x /= window.devicePixelRatio;
y /= window.devicePixelRatio;
graph._onMouseMove({ clientX: x, clientY: y });
}
function dragStart(graph, x, y = 1) {
x /= window.devicePixelRatio;
y /= window.devicePixelRatio;
graph._onMouseMove({ clientX: x, clientY: y });
graph._onMouseDown({ clientX: x, clientY: y });
}
function dragStop(graph, x, y = 1) {
x /= window.devicePixelRatio;
y /= window.devicePixelRatio;
graph._onMouseMove({ clientX: x, clientY: y });
graph._onMouseUp({ clientX: x, clientY: y });
}

View File

@ -3,8 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let TargetFactory = devtools.TargetFactory;
let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
let TargetFactory = devtools.TargetFactory;
gDevTools.testing = true;
SimpleTest.registerCleanupFunction(() => {
@ -32,6 +32,12 @@ function addTab(aURL, aCallback)
browser.addEventListener("load", onTabLoad, true);
}
function promiseTab(aURL) {
let deferred = Promise.defer();
addTab(aURL, deferred.resolve);
return deferred.promise;
}
registerCleanupFunction(function tearDown() {
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
@ -125,3 +131,16 @@ function oneTimeObserve(name, callback) {
};
Services.obs.addObserver(func, name, false);
}
function* createHost(type = "bottom", src = "data:text/html;charset=utf-8,") {
let host = new Hosts[type](gBrowser.selectedTab);
let iframe = yield host.create();
let loaded = Promise.defer();
let domHelper = new DOMHelpers(iframe.contentWindow);
iframe.setAttribute("src", src);
domHelper.onceDOMReady(loaded.resolve);
yield loaded.promise;
return [host, iframe.contentWindow, iframe.contentDocument];
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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/. -->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" href="chrome://browser/skin/devtools/common.css" type="text/css"/>
<link rel="stylesheet" href="chrome://browser/skin/devtools/widgets.css" ype="text/css"/>
<script type="application/javascript;version=1.8" src="theme-switching.js"/>
<style>
body {
overflow: hidden;
margin: 0;
padding: 0;
}
</style>
</head>
<body role="application">
<div id="graph-container">
<canvas id="graph-canvas"></canvas>
</div>
</body>
</html>

View File

@ -908,6 +908,154 @@
visibility: hidden;
}
/* Canvas graphs */
.graph-widget-canvas {
width: 100%;
height: 100%;
}
.graph-widget-canvas[input=hovering-background] {
cursor: text;
}
.graph-widget-canvas[input=hovering-region] {
cursor: pointer;
}
.graph-widget-canvas[input=hovering-selection-start-boundary],
.graph-widget-canvas[input=hovering-selection-end-boundary],
.graph-widget-canvas[input=adjusting-selection-boundary] {
cursor: col-resize;
}
.graph-widget-canvas[input=hovering-selection-contents] {
cursor: grab;
}
.graph-widget-canvas[input=dragging-selection-contents] {
cursor: grabbing;
}
.graph-widget-canvas ~ * {
pointer-events: none;
}
/* Line graph widget */
.line-graph-widget-container {
position: relative;
}
.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);
}
.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;
}
.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;
}
.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]::before {
-moz-border-end: 3px solid rgba(255,255,255,0.75);
left: -3px;
}
.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: calc(10px + 6px);
}
.line-graph-widget-tooltip[type=minimum] {
left: calc(10px + 6px);
}
.line-graph-widget-tooltip[type=average] {
right: 6px;
}
.line-graph-widget-tooltip > [text=info] {
color: #18191a;
}
.line-graph-widget-tooltip > [text=value] {
-moz-margin-start: 3px;
}
.line-graph-widget-tooltip > [text=metric] {
-moz-margin-start: 1px;
color: #667380;
}
.line-graph-widget-tooltip > [text=value],
.line-graph-widget-tooltip > [text=metric] {
text-shadow: 1px 0px rgba(255,255,255,0.6),
-1px 0px rgba(255,255,255,0.6),
0px -1px rgba(255,255,255,0.6),
0px 1px rgba(255,255,255,0.6);
}
.line-graph-widget-tooltip[type=maximum] > [text=value] {
color: #2cbb0f;
}
.line-graph-widget-tooltip[type=minimum] > [text=value] {
color: #ed2655;
}
.line-graph-widget-tooltip[type=average] > [text=value] {
color: #d97e00;
}
/* Charts */
.generic-chart-container {

View File

@ -82,7 +82,7 @@ let FramerateActor = exports.FramerateActor = protocol.ActorClass({
let frameCount = 0;
while (ticks[pivotTick++] < bucketTime) frameCount++;
let framerate = 1000 / (bucketTime / frameCount);
let framerate = 1000 / (resolution / frameCount);
timeline[bucketTime] = framerate;
}