Bug 1121180 - Support dark theme in flamecharts for the performance tool. r=vp

--HG--
rename : browser/devtools/shared/widgets/FlameGraph.jsm => browser/devtools/shared/widgets/FlameGraph.js
This commit is contained in:
Jordan Santell 2015-04-06 11:53:00 -04:00
Родитель 494b81298b
Коммит a2ecc81eb0
17 изменённых файлов: 126 добавлений и 95 удалений

Просмотреть файл

@ -47,13 +47,13 @@ devtools.lazyRequireGetter(this, "JITOptimizations",
"devtools/shared/profiler/jit", true); "devtools/shared/profiler/jit", true);
devtools.lazyRequireGetter(this, "OptionsView", devtools.lazyRequireGetter(this, "OptionsView",
"devtools/shared/options-view", true); "devtools/shared/options-view", true);
devtools.lazyRequireGetter(this, "FlameGraphUtils",
"devtools/shared/widgets/FlameGraph", true);
devtools.lazyRequireGetter(this, "FlameGraph",
"devtools/shared/widgets/FlameGraph", true);
devtools.lazyImporter(this, "CanvasGraphUtils", devtools.lazyImporter(this, "CanvasGraphUtils",
"resource:///modules/devtools/Graphs.jsm"); "resource:///modules/devtools/Graphs.jsm");
devtools.lazyImporter(this, "FlameGraphUtils",
"resource:///modules/devtools/FlameGraph.jsm");
devtools.lazyImporter(this, "FlameGraph",
"resource:///modules/devtools/FlameGraph.jsm");
devtools.lazyImporter(this, "SideMenuWidget", devtools.lazyImporter(this, "SideMenuWidget",
"resource:///modules/devtools/SideMenuWidget.jsm"); "resource:///modules/devtools/SideMenuWidget.jsm");
devtools.lazyImporter(this, "PluralForm", devtools.lazyImporter(this, "PluralForm",

Просмотреть файл

@ -24,10 +24,13 @@ let JsFlameGraphView = Heritage.extend(DetailsSubview, {
this.graph = new FlameGraph($("#js-flamegraph-view")); this.graph = new FlameGraph($("#js-flamegraph-view"));
this.graph.timelineTickUnits = L10N.getStr("graphs.ms"); this.graph.timelineTickUnits = L10N.getStr("graphs.ms");
this.graph.setTheme(PerformanceController.getTheme());
yield this.graph.ready(); yield this.graph.ready();
this._onRangeChangeInGraph = this._onRangeChangeInGraph.bind(this); this._onRangeChangeInGraph = this._onRangeChangeInGraph.bind(this);
this._onThemeChanged = this._onThemeChanged.bind(this);
PerformanceController.on(EVENTS.THEME_CHANGED, this._onThemeChanged);
this.graph.on("selecting", this._onRangeChangeInGraph); this.graph.on("selecting", this._onRangeChangeInGraph);
}), }),
@ -37,6 +40,7 @@ let JsFlameGraphView = Heritage.extend(DetailsSubview, {
destroy: Task.async(function* () { destroy: Task.async(function* () {
DetailsSubview.destroy.call(this); DetailsSubview.destroy.call(this);
PerformanceController.off(EVENTS.THEME_CHANGED, this._onThemeChanged);
this.graph.off("selecting", this._onRangeChangeInGraph); this.graph.off("selecting", this._onRangeChangeInGraph);
yield this.graph.destroy(); yield this.graph.destroy();
@ -93,5 +97,13 @@ let JsFlameGraphView = Heritage.extend(DetailsSubview, {
FlameGraphUtils.removeFromCache(samples); FlameGraphUtils.removeFromCache(samples);
}, },
/**
* Called when `devtools.theme` changes.
*/
_onThemeChanged: function (_, theme) {
this.graph.setTheme(theme);
this.graph.refresh({ force: true });
},
toString: () => "[object JsFlameGraphView]" toString: () => "[object JsFlameGraphView]"
}); });

Просмотреть файл

@ -23,10 +23,13 @@ let MemoryFlameGraphView = Heritage.extend(DetailsSubview, {
this.graph = new FlameGraph($("#memory-flamegraph-view")); this.graph = new FlameGraph($("#memory-flamegraph-view"));
this.graph.timelineTickUnits = L10N.getStr("graphs.ms"); this.graph.timelineTickUnits = L10N.getStr("graphs.ms");
this.graph.setTheme(PerformanceController.getTheme());
yield this.graph.ready(); yield this.graph.ready();
this._onRangeChangeInGraph = this._onRangeChangeInGraph.bind(this); this._onRangeChangeInGraph = this._onRangeChangeInGraph.bind(this);
this._onThemeChanged = this._onThemeChanged.bind(this);
PerformanceController.on(EVENTS.THEME_CHANGED, this._onThemeChanged);
this.graph.on("selecting", this._onRangeChangeInGraph); this.graph.on("selecting", this._onRangeChangeInGraph);
}), }),
@ -36,6 +39,7 @@ let MemoryFlameGraphView = Heritage.extend(DetailsSubview, {
destroy: Task.async(function* () { destroy: Task.async(function* () {
DetailsSubview.destroy.call(this); DetailsSubview.destroy.call(this);
PerformanceController.off(EVENTS.THEME_CHANGED, this._onThemeChanged);
this.graph.off("selecting", this._onRangeChangeInGraph); this.graph.off("selecting", this._onRangeChangeInGraph);
yield this.graph.destroy(); yield this.graph.destroy();
@ -91,5 +95,13 @@ let MemoryFlameGraphView = Heritage.extend(DetailsSubview, {
FlameGraphUtils.removeFromCache(samples); FlameGraphUtils.removeFromCache(samples);
}, },
/**
* Called when `devtools.theme` changes.
*/
_onThemeChanged: function (_, theme) {
this.graph.setTheme(theme);
this.graph.refresh({ force: true });
},
toString: () => "[object MemoryFlameGraphView]" toString: () => "[object MemoryFlameGraphView]"
}); });

Просмотреть файл

@ -21,7 +21,6 @@ EXTRA_JS_MODULES.devtools += [
'widgets/AbstractTreeItem.jsm', 'widgets/AbstractTreeItem.jsm',
'widgets/BreadcrumbsWidget.jsm', 'widgets/BreadcrumbsWidget.jsm',
'widgets/Chart.jsm', 'widgets/Chart.jsm',
'widgets/FlameGraph.jsm',
'widgets/Graphs.jsm', 'widgets/Graphs.jsm',
'widgets/GraphsWorker.js', 'widgets/GraphsWorker.js',
'widgets/SideMenuWidget.jsm', 'widgets/SideMenuWidget.jsm',
@ -65,6 +64,7 @@ EXTRA_JS_MODULES.devtools.shared.widgets += [
'widgets/CubicBezierPresets.js', 'widgets/CubicBezierPresets.js',
'widgets/CubicBezierWidget.js', 'widgets/CubicBezierWidget.js',
'widgets/FastListWidget.js', 'widgets/FastListWidget.js',
'widgets/FlameGraph.js',
'widgets/Spectrum.js', 'widgets/Spectrum.js',
'widgets/TableWidget.js', 'widgets/TableWidget.js',
'widgets/Tooltip.js', 'widgets/Tooltip.js',

Просмотреть файл

@ -3,7 +3,7 @@
// Tests that flame graph widget works properly. // Tests that flame graph widget works properly.
let {FlameGraph} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {}); let {FlameGraph} = devtools.require("devtools/shared/widgets/FlameGraph");
let {Promise} = devtools.require("resource://gre/modules/Promise.jsm"); let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
add_task(function*() { add_task(function*() {

Просмотреть файл

@ -3,7 +3,7 @@
// Tests that flame graph widgets may have a fixed width or height. // Tests that flame graph widgets may have a fixed width or height.
let {FlameGraph} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {}); let {FlameGraph} = devtools.require("devtools/shared/widgets/FlameGraph");
let {Promise} = devtools.require("resource://gre/modules/Promise.jsm"); let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
add_task(function*() { add_task(function*() {

Просмотреть файл

@ -8,7 +8,7 @@ let TEST_BOUNDS = { startTime: 0, endTime: 150 };
let TEST_WIDTH = 200; let TEST_WIDTH = 200;
let TEST_HEIGHT = 100; let TEST_HEIGHT = 100;
let {FlameGraph} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {}); let {FlameGraph} = devtools.require("devtools/shared/widgets/FlameGraph");
let {Promise} = devtools.require("resource://gre/modules/Promise.jsm"); let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
add_task(function*() { add_task(function*() {

Просмотреть файл

@ -9,7 +9,7 @@ let TEST_WIDTH = 200;
let TEST_HEIGHT = 100; let TEST_HEIGHT = 100;
let TEST_DPI_DENSITIY = 2; let TEST_DPI_DENSITIY = 2;
let {FlameGraph} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {}); let {FlameGraph} = devtools.require("devtools/shared/widgets/FlameGraph");
let {Promise} = devtools.require("resource://gre/modules/Promise.jsm"); let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
add_task(function*() { add_task(function*() {

Просмотреть файл

@ -9,7 +9,7 @@ let TEST_WIDTH = 200;
let TEST_HEIGHT = 100; let TEST_HEIGHT = 100;
let TEST_DPI_DENSITIY = 2; let TEST_DPI_DENSITIY = 2;
let {FlameGraph} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {}); let {FlameGraph} = devtools.require("devtools/shared/widgets/FlameGraph");
let {Promise} = devtools.require("resource://gre/modules/Promise.jsm"); let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
add_task(function*() { add_task(function*() {

Просмотреть файл

@ -4,10 +4,10 @@
// Tests that text metrics in the flame graph widget work properly. // Tests that text metrics in the flame graph widget work properly.
let HTML_NS = "http://www.w3.org/1999/xhtml"; let HTML_NS = "http://www.w3.org/1999/xhtml";
let FLAME_GRAPH_BLOCK_TEXT_FONT_SIZE = 8; // px let FLAME_GRAPH_BLOCK_TEXT_FONT_SIZE = 9; // px
let FLAME_GRAPH_BLOCK_TEXT_FONT_FAMILY = "sans-serif"; let FLAME_GRAPH_BLOCK_TEXT_FONT_FAMILY = "sans-serif";
let {ViewHelpers} = Cu.import("resource:///modules/devtools/ViewHelpers.jsm", {}); let {ViewHelpers} = Cu.import("resource:///modules/devtools/ViewHelpers.jsm", {});
let {FlameGraph} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {}); let {FlameGraph} = devtools.require("devtools/shared/widgets/FlameGraph");
let {Promise} = devtools.require("resource://gre/modules/Promise.jsm"); let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
let L10N = new ViewHelpers.L10N(); let L10N = new ViewHelpers.L10N();

Просмотреть файл

@ -4,7 +4,7 @@
// Tests that text metrics and data conversion from profiler samples // Tests that text metrics and data conversion from profiler samples
// widget work properly in the flame graph. // widget work properly in the flame graph.
let {FlameGraphUtils} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {}); let {FlameGraphUtils, FLAME_GRAPH_BLOCK_HEIGHT} = devtools.require("devtools/shared/widgets/FlameGraph");
add_task(function*() { add_task(function*() {
yield promiseTab("about:blank"); yield promiseTab("about:blank");
@ -111,7 +111,7 @@ let EXPECTED_OUTPUT = [{
x: 50, x: 50,
y: 0, y: 0,
width: 410, width: 410,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "A" text: "A"
}] }]
}, { }, {
@ -121,9 +121,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "B" rawLocation: "B"
}, },
x: 50, x: 50,
y: 11, y: FLAME_GRAPH_BLOCK_HEIGHT,
width: 160, width: 160,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "B" text: "B"
}, { }, {
srcData: { srcData: {
@ -131,9 +131,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "B" rawLocation: "B"
}, },
x: 330, x: 330,
y: 11, y: FLAME_GRAPH_BLOCK_HEIGHT,
width: 130, width: 130,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "B" text: "B"
}] }]
}, { }, {
@ -145,7 +145,7 @@ let EXPECTED_OUTPUT = [{
x: 0, x: 0,
y: 0, y: 0,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "M" text: "M"
}, { }, {
srcData: { srcData: {
@ -153,9 +153,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "C" rawLocation: "C"
}, },
x: 50, x: 50,
y: 22, y: FLAME_GRAPH_BLOCK_HEIGHT * 2,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "C" text: "C"
}, { }, {
srcData: { srcData: {
@ -163,9 +163,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "C" rawLocation: "C"
}, },
x: 330, x: 330,
y: 22, y: FLAME_GRAPH_BLOCK_HEIGHT * 2,
width: 130, width: 130,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "C" text: "C"
}] }]
}, { }, {
@ -175,9 +175,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "N" rawLocation: "N"
}, },
x: 0, x: 0,
y: 11, y: FLAME_GRAPH_BLOCK_HEIGHT,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "N" text: "N"
}, { }, {
srcData: { srcData: {
@ -185,9 +185,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "D" rawLocation: "D"
}, },
x: 100, x: 100,
y: 22, y: FLAME_GRAPH_BLOCK_HEIGHT * 2,
width: 110, width: 110,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "D" text: "D"
}, { }, {
srcData: { srcData: {
@ -197,7 +197,7 @@ let EXPECTED_OUTPUT = [{
x: 460, x: 460,
y: 0, y: 0,
width: 40, width: 40,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "X" text: "X"
}] }]
}, { }, {
@ -207,9 +207,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "E" rawLocation: "E"
}, },
x: 210, x: 210,
y: 11, y: FLAME_GRAPH_BLOCK_HEIGHT,
width: 120, width: 120,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "E" text: "E"
}, { }, {
srcData: { srcData: {
@ -217,9 +217,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "Y" rawLocation: "Y"
}, },
x: 460, x: 460,
y: 11, y: FLAME_GRAPH_BLOCK_HEIGHT,
width: 40, width: 40,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "Y" text: "Y"
}] }]
}, { }, {
@ -229,9 +229,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "P" rawLocation: "P"
}, },
x: 0, x: 0,
y: 22, y: FLAME_GRAPH_BLOCK_HEIGHT * 2,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "P" text: "P"
}, { }, {
srcData: { srcData: {
@ -239,9 +239,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "F" rawLocation: "F"
}, },
x: 210, x: 210,
y: 22, y: FLAME_GRAPH_BLOCK_HEIGHT * 2,
width: 120, width: 120,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "F" text: "F"
}, { }, {
srcData: { srcData: {
@ -249,9 +249,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "Z" rawLocation: "Z"
}, },
x: 460, x: 460,
y: 22, y: FLAME_GRAPH_BLOCK_HEIGHT * 2,
width: 40, width: 40,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "Z" text: "Z"
}] }]
}, { }, {

Просмотреть файл

@ -3,7 +3,7 @@
// Tests consecutive duplicate frames are removed from the flame graph data. // Tests consecutive duplicate frames are removed from the flame graph data.
let {FlameGraphUtils} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {}); let {FlameGraphUtils, FLAME_GRAPH_BLOCK_HEIGHT} = devtools.require("devtools/shared/widgets/FlameGraph");
add_task(function*() { add_task(function*() {
yield promiseTab("about:blank"); yield promiseTab("about:blank");
@ -73,7 +73,7 @@ let EXPECTED_OUTPUT = [{
x: 0, x: 0,
y: 0, y: 0,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "A" text: "A"
}] }]
}, { }, {
@ -83,9 +83,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "B" rawLocation: "B"
}, },
x: 0, x: 0,
y: 11, y: FLAME_GRAPH_BLOCK_HEIGHT,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "B" text: "B"
}] }]
}, { }, {

Просмотреть файл

@ -3,7 +3,7 @@
// Tests if platform frames are removed from the flame graph data. // Tests if platform frames are removed from the flame graph data.
let {FlameGraphUtils} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {}); let {FlameGraphUtils, FLAME_GRAPH_BLOCK_HEIGHT} = devtools.require("devtools/shared/widgets/FlameGraph");
let {FrameNode} = devtools.require("devtools/shared/profiler/tree-model"); let {FrameNode} = devtools.require("devtools/shared/profiler/tree-model");
add_task(function*() { add_task(function*() {
@ -72,7 +72,7 @@ let EXPECTED_OUTPUT = [{
x: 0, x: 0,
y: 0, y: 0,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "http://A" text: "http://A"
}, { }, {
srcData: { srcData: {
@ -80,9 +80,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "file://C" rawLocation: "file://C"
}, },
x: 0, x: 0,
y: 22, y: FLAME_GRAPH_BLOCK_HEIGHT * 2,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "file://C" text: "file://C"
}] }]
}, { }, {
@ -102,9 +102,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "https://B" rawLocation: "https://B"
}, },
x: 0, x: 0,
y: 11, y: FLAME_GRAPH_BLOCK_HEIGHT,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "https://B" text: "https://B"
}] }]
}, { }, {

Просмотреть файл

@ -3,7 +3,7 @@
// Tests if (idle) nodes are added when necessary in the flame graph data. // Tests if (idle) nodes are added when necessary in the flame graph data.
let {FlameGraphUtils} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {}); let {FlameGraphUtils, FLAME_GRAPH_BLOCK_HEIGHT} = devtools.require("devtools/shared/widgets/FlameGraph");
let {FrameNode} = devtools.require("devtools/shared/profiler/tree-model"); let {FrameNode} = devtools.require("devtools/shared/profiler/tree-model");
add_task(function*() { add_task(function*() {
@ -96,7 +96,7 @@ let EXPECTED_OUTPUT = [{
x: 0, x: 0,
y: 0, y: 0,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "http://A" text: "http://A"
}, { }, {
srcData: { srcData: {
@ -104,9 +104,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "file://C" rawLocation: "file://C"
}, },
x: 0, x: 0,
y: 22, y: FLAME_GRAPH_BLOCK_HEIGHT * 2,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "file://C" text: "file://C"
}, { }, {
srcData: { srcData: {
@ -116,7 +116,7 @@ let EXPECTED_OUTPUT = [{
x: 100, x: 100,
y: 0, y: 0,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "http://A" text: "http://A"
}] }]
}, { }, {
@ -128,7 +128,7 @@ let EXPECTED_OUTPUT = [{
x: 50, x: 50,
y: 0, y: 0,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "\m/" text: "\m/"
}] }]
}, { }, {
@ -146,9 +146,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "https://B" rawLocation: "https://B"
}, },
x: 0, x: 0,
y: 11, y: FLAME_GRAPH_BLOCK_HEIGHT,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "https://B" text: "https://B"
}, { }, {
srcData: { srcData: {
@ -156,9 +156,9 @@ let EXPECTED_OUTPUT = [{
rawLocation: "https://B" rawLocation: "https://B"
}, },
x: 100, x: 100,
y: 11, y: FLAME_GRAPH_BLOCK_HEIGHT,
width: 50, width: 50,
height: 11, height: FLAME_GRAPH_BLOCK_HEIGHT,
text: "https://B" text: "https://B"
}] }]
}, { }, {

Просмотреть файл

@ -3,7 +3,7 @@
// Tests that flame graph data is cached, and that the cache may be cleared. // Tests that flame graph data is cached, and that the cache may be cleared.
let {FlameGraphUtils} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {}); let {FlameGraphUtils} = devtools.require("devtools/shared/widgets/FlameGraph");
add_task(function*() { add_task(function*() {
yield promiseTab("about:blank"); yield promiseTab("about:blank");

Просмотреть файл

@ -3,7 +3,7 @@
// Tests if (idle) nodes are added when necessary in the flame graph data. // Tests if (idle) nodes are added when necessary in the flame graph data.
let {FlameGraphUtils} = Cu.import("resource:///modules/devtools/FlameGraph.jsm", {}); let {FlameGraphUtils} = devtools.require("devtools/shared/widgets/FlameGraph");
let test = Task.async(function*() { let test = Task.async(function*() {
let hash1 = FlameGraphUtils._getStringHash("abc"); let hash1 = FlameGraphUtils._getStringHash("abc");

Просмотреть файл

@ -3,18 +3,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const Cu = Components.utils; const { ViewHelpers } = require("resource:///modules/devtools/ViewHelpers.jsm");
const { AbstractCanvasGraph, GraphArea, GraphAreaDragger } = require("resource:///modules/devtools/Graphs.jsm");
Cu.import("resource:///modules/devtools/ViewHelpers.jsm"); const { Promise } = require("resource://gre/modules/Promise.jsm");
Cu.import("resource:///modules/devtools/Graphs.jsm"); const { Task } = require("resource://gre/modules/Task.jsm");
const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise; const { getColor } = require("devtools/shared/theme");
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {}); const EventEmitter = require("devtools/toolkit/event-emitter");
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js", {});
this.EXPORTED_SYMBOLS = [
"FlameGraph",
"FlameGraphUtils"
];
const HTML_NS = "http://www.w3.org/1999/xhtml"; const HTML_NS = "http://www.w3.org/1999/xhtml";
const GRAPH_SRC = "chrome://browser/content/devtools/graphs-frame.xhtml"; const GRAPH_SRC = "chrome://browser/content/devtools/graphs-frame.xhtml";
@ -34,17 +28,14 @@ const TIMELINE_TICKS_MULTIPLE = 5; // ms
const TIMELINE_TICKS_SPACING_MIN = 75; // px const TIMELINE_TICKS_SPACING_MIN = 75; // px
const OVERVIEW_HEADER_HEIGHT = 16; // px const OVERVIEW_HEADER_HEIGHT = 16; // px
const OVERVIEW_HEADER_BACKGROUND = "rgba(255,255,255,0.7)";
const OVERVIEW_HEADER_TEXT_COLOR = "#18191a";
const OVERVIEW_HEADER_TEXT_FONT_SIZE = 9; // px const OVERVIEW_HEADER_TEXT_FONT_SIZE = 9; // px
const OVERVIEW_HEADER_TEXT_FONT_FAMILY = "sans-serif"; const OVERVIEW_HEADER_TEXT_FONT_FAMILY = "sans-serif";
const OVERVIEW_HEADER_TEXT_PADDING_LEFT = 6; // px const OVERVIEW_HEADER_TEXT_PADDING_LEFT = 6; // px
const OVERVIEW_HEADER_TEXT_PADDING_TOP = 5; // px const OVERVIEW_HEADER_TEXT_PADDING_TOP = 5; // px
const OVERVIEW_TIMELINE_STROKES = "#ddd"; const OVERVIEW_HEADER_TIMELINE_STROKE_COLOR = "rgba(128, 128, 128, 0.5)";
const FLAME_GRAPH_BLOCK_BORDER = 1; // px const FLAME_GRAPH_BLOCK_BORDER = 1; // px
const FLAME_GRAPH_BLOCK_TEXT_COLOR = "#000"; const FLAME_GRAPH_BLOCK_TEXT_FONT_SIZE = 9; // px
const FLAME_GRAPH_BLOCK_TEXT_FONT_SIZE = 8; // px
const FLAME_GRAPH_BLOCK_TEXT_FONT_FAMILY = "sans-serif"; const FLAME_GRAPH_BLOCK_TEXT_FONT_FAMILY = "sans-serif";
const FLAME_GRAPH_BLOCK_TEXT_PADDING_TOP = 0; // px const FLAME_GRAPH_BLOCK_TEXT_PADDING_TOP = 0; // px
const FLAME_GRAPH_BLOCK_TEXT_PADDING_LEFT = 3; // px const FLAME_GRAPH_BLOCK_TEXT_PADDING_LEFT = 3; // px
@ -101,7 +92,9 @@ function FlameGraph(parent, sharpness) {
EventEmitter.decorate(this); EventEmitter.decorate(this);
this._parent = parent; this._parent = parent;
this._ready = promise.defer(); this._ready = Promise.defer();
this.setTheme();
AbstractCanvasGraph.createIframe(GRAPH_SRC, parent, iframe => { AbstractCanvasGraph.createIframe(GRAPH_SRC, parent, iframe => {
this._iframe = iframe; this._iframe = iframe;
@ -215,14 +208,6 @@ FlameGraph.prototype = {
this.emit("destroyed"); this.emit("destroyed");
}), }),
/**
* Rendering options. Subclasses should override these.
*/
overviewHeaderBackgroundColor: OVERVIEW_HEADER_BACKGROUND,
overviewHeaderTextColor: OVERVIEW_HEADER_TEXT_COLOR,
overviewTimelineStrokes: OVERVIEW_TIMELINE_STROKES,
blockTextColor: FLAME_GRAPH_BLOCK_TEXT_COLOR,
/** /**
* Makes sure the canvas graph is of the specified width or height, and * Makes sure the canvas graph is of the specified width or height, and
* doesn't flex to fit all the available space. * doesn't flex to fit all the available space.
@ -330,14 +315,19 @@ FlameGraph.prototype = {
/** /**
* Updates this graph to reflect the new dimensions of the parent node. * Updates this graph to reflect the new dimensions of the parent node.
*
* @param boolean options.force
* Force redraw everything.
*/ */
refresh: function() { refresh: function(options={}) {
let bounds = this._parent.getBoundingClientRect(); let bounds = this._parent.getBoundingClientRect();
let newWidth = this.fixedWidth || bounds.width; let newWidth = this.fixedWidth || bounds.width;
let newHeight = this.fixedHeight || bounds.height; let newHeight = this.fixedHeight || bounds.height;
// Prevent redrawing everything if the graph's width & height won't change. // Prevent redrawing everything if the graph's width & height won't change,
if (this._width == newWidth * this._pixelRatio && // except if force=true.
if (!options.force &&
this._width == newWidth * this._pixelRatio &&
this._height == newHeight * this._pixelRatio) { this._height == newHeight * this._pixelRatio) {
this.emit("refresh-cancelled"); this.emit("refresh-cancelled");
return; return;
@ -354,6 +344,19 @@ FlameGraph.prototype = {
this.emit("refresh"); this.emit("refresh");
}, },
/**
* Sets the theme via `theme` to either "light" or "dark",
* and updates the internal styling to match. Requires a redraw
* to see the effects.
*/
setTheme: function (theme) {
theme = theme || "light";
this.overviewHeaderBackgroundColor = getColor("body-background", theme);
this.overviewHeaderTextColor = getColor("body-color", theme);
// Hard to get a color that is readable across both themes for the text on the flames
this.blockTextColor = getColor(theme === "dark" ? "selection-color" : "body-color", theme);
},
/** /**
* The contents of this graph are redrawn only when something changed, * The contents of this graph are redrawn only when something changed,
* like the data source, or the selection bounds etc. This flag tracks * like the data source, or the selection bounds etc. This flag tracks
@ -385,8 +388,8 @@ FlameGraph.prototype = {
let selection = this._selection; let selection = this._selection;
let selectionWidth = selection.end - selection.start; let selectionWidth = selection.end - selection.start;
let selectionScale = canvasWidth / selectionWidth; let selectionScale = canvasWidth / selectionWidth;
this._drawPyramid(this._data, this._verticalOffset, selection.start, selectionScale);
this._drawTicks(selection.start, selectionScale); this._drawTicks(selection.start, selectionScale);
this._drawPyramid(this._data, this._verticalOffset, selection.start, selectionScale);
this._shouldRedraw = false; this._shouldRedraw = false;
}, },
@ -416,7 +419,7 @@ FlameGraph.prototype = {
ctx.textBaseline = "top"; ctx.textBaseline = "top";
ctx.font = fontSize + "px " + fontFamily; ctx.font = fontSize + "px " + fontFamily;
ctx.fillStyle = this.overviewHeaderTextColor; ctx.fillStyle = this.overviewHeaderTextColor;
ctx.strokeStyle = this.overviewTimelineStrokes; ctx.strokeStyle = OVERVIEW_HEADER_TIMELINE_STROKE_COLOR;
ctx.beginPath(); ctx.beginPath();
for (let x = -scaledOffset % tickInterval; x < canvasWidth; x += tickInterval) { for (let x = -scaledOffset % tickInterval; x < canvasWidth; x += tickInterval) {
@ -926,14 +929,14 @@ FlameGraph.prototype = {
} }
}; };
const FLAME_GRAPH_BLOCK_HEIGHT = 11; // px const FLAME_GRAPH_BLOCK_HEIGHT = 12; // px
const PALLETTE_SIZE = 10; const PALLETTE_SIZE = 10;
const PALLETTE_HUE_OFFSET = Math.random() * 90; const PALLETTE_HUE_OFFSET = Math.random() * 90;
const PALLETTE_HUE_RANGE = 270; const PALLETTE_HUE_RANGE = 270;
const PALLETTE_SATURATION = 60; const PALLETTE_SATURATION = 100;
const PALLETTE_BRIGHTNESS = 75; const PALLETTE_BRIGHTNESS = 65;
const PALLETTE_OPACITY = 0.7; const PALLETTE_OPACITY = 0.55;
const COLOR_PALLETTE = Array.from(Array(PALLETTE_SIZE)).map((_, i) => "hsla" + const COLOR_PALLETTE = Array.from(Array(PALLETTE_SIZE)).map((_, i) => "hsla" +
"(" + ((PALLETTE_HUE_OFFSET + (i / PALLETTE_SIZE * PALLETTE_HUE_RANGE))|0 % 360) + "(" + ((PALLETTE_HUE_OFFSET + (i / PALLETTE_SIZE * PALLETTE_HUE_RANGE))|0 % 360) +
@ -1114,3 +1117,7 @@ let FlameGraphUtils = {
return hash; return hash;
} }
}; };
exports.FlameGraph = FlameGraph;
exports.FlameGraphUtils = FlameGraphUtils;
exports.FLAME_GRAPH_BLOCK_HEIGHT = FLAME_GRAPH_BLOCK_HEIGHT;