зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound.
This commit is contained in:
Коммит
d96528f975
|
@ -12,13 +12,13 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7ef494164bcd840dc23c7db106dff0a98f8ff15f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9fc36dde3a4a3c5ca200275b68ffb56b4173bec3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="0a8bdd0f43e2d8fc7d45b3b0d97125834c0ac72f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7ef494164bcd840dc23c7db106dff0a98f8ff15f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="9fc36dde3a4a3c5ca200275b68ffb56b4173bec3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="0a8bdd0f43e2d8fc7d45b3b0d97125834c0ac72f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
|
||||
<!-- Stock Android things -->
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7ef494164bcd840dc23c7db106dff0a98f8ff15f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9fc36dde3a4a3c5ca200275b68ffb56b4173bec3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="0a8bdd0f43e2d8fc7d45b3b0d97125834c0ac72f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"revision": "25b78e722d958fe667061a2d9e0733d0877607ac",
|
||||
"revision": "500d57309898b0514b1ad1a61a8d8274909428a4",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7ef494164bcd840dc23c7db106dff0a98f8ff15f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9fc36dde3a4a3c5ca200275b68ffb56b4173bec3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="0a8bdd0f43e2d8fc7d45b3b0d97125834c0ac72f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7ef494164bcd840dc23c7db106dff0a98f8ff15f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9fc36dde3a4a3c5ca200275b68ffb56b4173bec3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="0a8bdd0f43e2d8fc7d45b3b0d97125834c0ac72f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7ef494164bcd840dc23c7db106dff0a98f8ff15f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9fc36dde3a4a3c5ca200275b68ffb56b4173bec3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="0a8bdd0f43e2d8fc7d45b3b0d97125834c0ac72f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7ef494164bcd840dc23c7db106dff0a98f8ff15f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9fc36dde3a4a3c5ca200275b68ffb56b4173bec3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="0a8bdd0f43e2d8fc7d45b3b0d97125834c0ac72f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
|
||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7ef494164bcd840dc23c7db106dff0a98f8ff15f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="9fc36dde3a4a3c5ca200275b68ffb56b4173bec3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="0a8bdd0f43e2d8fc7d45b3b0d97125834c0ac72f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
|
||||
<!-- Stock Android things -->
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7ef494164bcd840dc23c7db106dff0a98f8ff15f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9fc36dde3a4a3c5ca200275b68ffb56b4173bec3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="0a8bdd0f43e2d8fc7d45b3b0d97125834c0ac72f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
|
||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
|
|
|
@ -1181,7 +1181,7 @@ pref("devtools.shadereditor.enabled", false);
|
|||
pref("devtools.chrome.enabled", false);
|
||||
|
||||
// Default theme ("dark" or "light")
|
||||
pref("devtools.theme", "light");
|
||||
pref("devtools.theme", "dark");
|
||||
|
||||
// Display the introductory text
|
||||
pref("devtools.gcli.hideIntro", false);
|
||||
|
|
|
@ -1991,7 +1991,7 @@ gcli.addCommand({
|
|||
name: 'paintflashing toggle',
|
||||
hidden: true,
|
||||
buttonId: "command-button-paintflashing",
|
||||
buttonClass: "command-button",
|
||||
buttonClass: "command-button command-button-invertable",
|
||||
state: {
|
||||
isChecked: function(aTarget) {
|
||||
if (aTarget.isLocalTab) {
|
||||
|
@ -2284,7 +2284,7 @@ gcli.addCommand({
|
|||
name: 'splitconsole',
|
||||
hidden: true,
|
||||
buttonId: "command-button-splitconsole",
|
||||
buttonClass: "command-button",
|
||||
buttonClass: "command-button command-button-invertable",
|
||||
tooltipText: gcli.lookup("splitconsoleTooltip"),
|
||||
state: {
|
||||
isChecked: function(aTarget) {
|
||||
|
|
|
@ -55,6 +55,11 @@ DevTools.prototype = {
|
|||
* A falsy value indicates that it cannot be hidden.
|
||||
* - icon: URL pointing to a graphic which will be used as the src for an
|
||||
* 16x16 img tag (string|required)
|
||||
* - invertIconForLightTheme: The icon can automatically have an inversion
|
||||
* filter applied (default is false). All builtin tools are true, but
|
||||
* addons may omit this to prevent unwanted changes to the `icon`
|
||||
* image. See browser/themes/shared/devtools/filters.svg#invert for
|
||||
* the filter being applied to the images (boolean|optional)
|
||||
* - url: URL pointing to a XUL/XHTML document containing the user interface
|
||||
* (string|required)
|
||||
* - label: Localized name for the tool to be displayed to the user
|
||||
|
|
|
@ -49,6 +49,12 @@ function continueTests(toolbox, panel) {
|
|||
ok(toolbox.getCurrentPanel(), "panel value is correct");
|
||||
is(toolbox.currentToolId, toolId, "toolbox _currentToolId is correct");
|
||||
|
||||
ok(!toolbox.doc.getElementById("toolbox-tab-" + toolId).hasAttribute("icon-invertable"),
|
||||
"The tool tab does not have the invertable attribute");
|
||||
|
||||
ok(toolbox.doc.getElementById("toolbox-tab-inspector").hasAttribute("icon-invertable"),
|
||||
"The builtin tool tabs do have the invertable attribute");
|
||||
|
||||
let toolDefinitions = gDevTools.getToolDefinitionMap();
|
||||
is(toolDefinitions.has(toolId), true, "The tool is in gDevTools");
|
||||
|
||||
|
|
|
@ -554,7 +554,7 @@ Toolbox.prototype = {
|
|||
_buildPickerButton: function() {
|
||||
this._pickerButton = this.doc.createElement("toolbarbutton");
|
||||
this._pickerButton.id = "command-button-pick";
|
||||
this._pickerButton.className = "command-button";
|
||||
this._pickerButton.className = "command-button command-button-invertable";
|
||||
this._pickerButton.setAttribute("tooltiptext", toolboxStrings("pickButton.tooltip"));
|
||||
|
||||
let container = this.doc.querySelector("#toolbox-buttons");
|
||||
|
@ -588,11 +588,14 @@ Toolbox.prototype = {
|
|||
// The radio element is not being used in the conventional way, thus
|
||||
// the devtools-tab class replaces the radio XBL binding with its base
|
||||
// binding (the control-item binding).
|
||||
radio.className = "toolbox-tab devtools-tab";
|
||||
radio.className = "devtools-tab";
|
||||
radio.id = "toolbox-tab-" + id;
|
||||
radio.setAttribute("toolid", id);
|
||||
radio.setAttribute("ordinal", toolDefinition.ordinal);
|
||||
radio.setAttribute("tooltiptext", toolDefinition.tooltip);
|
||||
if (toolDefinition.invertIconForLightTheme) {
|
||||
radio.setAttribute("icon-invertable", "true");
|
||||
}
|
||||
|
||||
radio.addEventListener("command", () => {
|
||||
this.selectTool(id);
|
||||
|
|
|
@ -61,6 +61,7 @@ Tools.options = {
|
|||
ordinal: 0,
|
||||
url: "chrome://browser/content/devtools/framework/toolbox-options.xul",
|
||||
icon: "chrome://browser/skin/devtools/tool-options.svg",
|
||||
invertIconForLightTheme: true,
|
||||
bgTheme: "theme-body",
|
||||
tooltip: l10n("optionsButton.tooltip", toolboxStrings),
|
||||
inMenu: false,
|
||||
|
@ -80,6 +81,7 @@ Tools.webConsole = {
|
|||
modifiers: Services.appinfo.OS == "Darwin" ? "accel,alt" : "accel,shift",
|
||||
ordinal: 1,
|
||||
icon: "chrome://browser/skin/devtools/tool-webconsole.svg",
|
||||
invertIconForLightTheme: true,
|
||||
url: "chrome://browser/content/devtools/webconsole.xul",
|
||||
label: l10n("ToolboxTabWebconsole.label", webConsoleStrings),
|
||||
menuLabel: l10n("MenuWebconsole.label", webConsoleStrings),
|
||||
|
@ -110,6 +112,7 @@ Tools.inspector = {
|
|||
ordinal: 2,
|
||||
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
|
||||
icon: "chrome://browser/skin/devtools/tool-inspector.svg",
|
||||
invertIconForLightTheme: true,
|
||||
url: "chrome://browser/content/devtools/inspector/inspector.xul",
|
||||
label: l10n("inspector.label", inspectorStrings),
|
||||
tooltip: l10n("inspector.tooltip", inspectorStrings),
|
||||
|
@ -137,6 +140,7 @@ Tools.jsdebugger = {
|
|||
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
|
||||
ordinal: 3,
|
||||
icon: "chrome://browser/skin/devtools/tool-debugger.svg",
|
||||
invertIconForLightTheme: true,
|
||||
highlightedicon: "chrome://browser/skin/devtools/tool-debugger-paused.svg",
|
||||
url: "chrome://browser/content/devtools/debugger.xul",
|
||||
label: l10n("ToolboxDebugger.label", debuggerStrings),
|
||||
|
@ -160,6 +164,7 @@ Tools.styleEditor = {
|
|||
accesskey: l10n("open.accesskey", styleEditorStrings),
|
||||
modifiers: "shift",
|
||||
icon: "chrome://browser/skin/devtools/tool-styleeditor.svg",
|
||||
invertIconForLightTheme: true,
|
||||
url: "chrome://browser/content/devtools/styleeditor.xul",
|
||||
label: l10n("ToolboxStyleEditor.label", styleEditorStrings),
|
||||
tooltip: l10n("ToolboxStyleEditor.tooltip2", styleEditorStrings),
|
||||
|
@ -180,6 +185,7 @@ Tools.shaderEditor = {
|
|||
ordinal: 5,
|
||||
visibilityswitch: "devtools.shadereditor.enabled",
|
||||
icon: "chrome://browser/skin/devtools/tool-styleeditor.svg",
|
||||
invertIconForLightTheme: true,
|
||||
url: "chrome://browser/content/devtools/shadereditor.xul",
|
||||
label: l10n("ToolboxShaderEditor.label", shaderEditorStrings),
|
||||
tooltip: l10n("ToolboxShaderEditor.tooltip", shaderEditorStrings),
|
||||
|
@ -202,6 +208,7 @@ Tools.jsprofiler = {
|
|||
modifiers: "shift",
|
||||
visibilityswitch: "devtools.profiler.enabled",
|
||||
icon: "chrome://browser/skin/devtools/tool-profiler.svg",
|
||||
invertIconForLightTheme: true,
|
||||
url: "chrome://browser/content/devtools/profiler.xul",
|
||||
label: l10n("profiler.label", profilerStrings),
|
||||
tooltip: l10n("profiler.tooltip2", profilerStrings),
|
||||
|
@ -225,6 +232,7 @@ Tools.netMonitor = {
|
|||
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
|
||||
visibilityswitch: "devtools.netmonitor.enabled",
|
||||
icon: "chrome://browser/skin/devtools/tool-network.svg",
|
||||
invertIconForLightTheme: true,
|
||||
url: "chrome://browser/content/devtools/netmonitor.xul",
|
||||
label: l10n("netmonitor.label", netMonitorStrings),
|
||||
tooltip: l10n("netmonitor.tooltip", netMonitorStrings),
|
||||
|
@ -245,6 +253,7 @@ Tools.scratchpad = {
|
|||
ordinal: 8,
|
||||
visibilityswitch: "devtools.scratchpad.enabled",
|
||||
icon: "chrome://browser/skin/devtools/tool-scratchpad.svg",
|
||||
invertIconForLightTheme: true,
|
||||
url: "chrome://browser/content/devtools/scratchpad.xul",
|
||||
label: l10n("scratchpad.label", scratchpadStrings),
|
||||
tooltip: l10n("scratchpad.tooltip", scratchpadStrings),
|
||||
|
|
|
@ -560,55 +560,107 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
* "flash" or "other".
|
||||
*/
|
||||
filterOn: function(aType = "all") {
|
||||
let target = $("#requests-menu-filter-" + aType + "-button");
|
||||
let buttons = document.querySelectorAll(".requests-menu-footer-button");
|
||||
|
||||
for (let button of buttons) {
|
||||
if (button != target) {
|
||||
button.removeAttribute("checked");
|
||||
} else {
|
||||
button.setAttribute("checked", "true");
|
||||
if (aType === "all") {
|
||||
// The filter "all" is special as it doesn't toggle.
|
||||
// - If some filters are selected and 'all' is clicked, the previously
|
||||
// selected filters will be disabled and 'all' is the only active one.
|
||||
// - If 'all' is already selected, do nothing.
|
||||
if (this._activeFilters.indexOf("all") !== -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Uncheck all other filters and select 'all'. Must create a copy as
|
||||
// _disableFilter removes the filters from the list while it's being
|
||||
// iterated. 'all' will be enabled automatically by _disableFilter once
|
||||
// the last filter is disabled.
|
||||
this._activeFilters.slice().forEach(this._disableFilter, this);
|
||||
}
|
||||
else if (this._activeFilters.indexOf(aType) === -1) {
|
||||
this._enableFilter(aType);
|
||||
}
|
||||
else {
|
||||
this._disableFilter(aType);
|
||||
}
|
||||
|
||||
// Filter on whatever was requested.
|
||||
switch (aType) {
|
||||
case "all":
|
||||
this.filterContents(() => true);
|
||||
break;
|
||||
case "html":
|
||||
this.filterContents(e => this.isHtml(e));
|
||||
break;
|
||||
case "css":
|
||||
this.filterContents(e => this.isCss(e));
|
||||
break;
|
||||
case "js":
|
||||
this.filterContents(e => this.isJs(e));
|
||||
break;
|
||||
case "xhr":
|
||||
this.filterContents(e => this.isXHR(e));
|
||||
break;
|
||||
case "fonts":
|
||||
this.filterContents(e => this.isFont(e));
|
||||
break;
|
||||
case "images":
|
||||
this.filterContents(e => this.isImage(e));
|
||||
break;
|
||||
case "media":
|
||||
this.filterContents(e => this.isMedia(e));
|
||||
break;
|
||||
case "flash":
|
||||
this.filterContents(e => this.isFlash(e));
|
||||
break;
|
||||
case "other":
|
||||
this.filterContents(e => this.isOther(e));
|
||||
break;
|
||||
}
|
||||
|
||||
this.filterContents(this._filterPredicate);
|
||||
this.refreshSummary();
|
||||
this.refreshZebra();
|
||||
},
|
||||
|
||||
/**
|
||||
* Disables the given filter, its button and toggles 'all' on if the filter to
|
||||
* be disabled is the last one active.
|
||||
*
|
||||
* @param string aType
|
||||
* Either "all", "html", "css", "js", "xhr", "fonts", "images", "media"
|
||||
* "flash" or "other".
|
||||
*/
|
||||
_disableFilter: function (aType) {
|
||||
// Remove the filter from list of active filters.
|
||||
this._activeFilters.splice(this._activeFilters.indexOf(aType), 1);
|
||||
|
||||
// Remove the checked status from the filter.
|
||||
let target = $("#requests-menu-filter-" + aType + "-button");
|
||||
target.removeAttribute("checked");
|
||||
|
||||
// Check if the filter disabled was the last one. If so, toggle all on.
|
||||
if (this._activeFilters.length === 0)
|
||||
this._enableFilter("all");
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables the given filter, its button and toggles 'all' off if the filter to
|
||||
* be enabled is the first one active.
|
||||
*
|
||||
* @param string aType
|
||||
* Either "all", "html", "css", "js", "xhr", "fonts", "images", "media"
|
||||
* "flash" or "other".
|
||||
*/
|
||||
_enableFilter: function (aType) {
|
||||
// Add the filter to the list of active filters.
|
||||
this._activeFilters.push(aType);
|
||||
|
||||
// Add the checked status to the filter button.
|
||||
let target = $("#requests-menu-filter-" + aType + "-button");
|
||||
target.setAttribute("checked", true);
|
||||
|
||||
// Check if 'all' was selected before. If so, disable it.
|
||||
if (aType !== "all" && this._activeFilters.indexOf("all") !== -1) {
|
||||
this._disableFilter("all");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a predicate that can be used to test if a request matches any of
|
||||
* the active filters.
|
||||
*/
|
||||
get _filterPredicate() {
|
||||
let filterPredicates = {
|
||||
"all": () => true,
|
||||
"html": this.isHtml,
|
||||
"css": this.isCss,
|
||||
"js": this.isJs,
|
||||
"xhr": this.isXHR,
|
||||
"fonts": this.isFont,
|
||||
"images": this.isImage,
|
||||
"media": this.isMedia,
|
||||
"flash": this.isFlash,
|
||||
"other": this.isOther
|
||||
};
|
||||
|
||||
if (this._activeFilters.length === 1) {
|
||||
// The simplest case: only one filter active.
|
||||
return filterPredicates[this._activeFilters[0]].bind(this);
|
||||
} else {
|
||||
// Multiple filters active.
|
||||
return requestItem => {
|
||||
return this._activeFilters.some(filterName => {
|
||||
return filterPredicates[filterName].call(this, requestItem);
|
||||
});
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sorts all network requests in this container by a specified detail.
|
||||
*
|
||||
|
@ -1526,7 +1578,8 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
_lastRequestEndedMillis: -1,
|
||||
_updateQueue: [],
|
||||
_updateTimeout: null,
|
||||
_resizeTimeout: null
|
||||
_resizeTimeout: null,
|
||||
_activeFilters: ["all"]
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,6 +24,7 @@ function test() {
|
|||
is(NetMonitorView.detailsPaneHidden, false,
|
||||
"The details pane should not be hidden after toggle button was pressed.");
|
||||
|
||||
// First test with single filters...
|
||||
testButtons("all");
|
||||
testContents([1, 1, 1, 1, 1, 1, 1, 1])
|
||||
.then(() => {
|
||||
|
@ -32,36 +33,44 @@ function test() {
|
|||
return testContents([1, 0, 0, 0, 0, 0, 0, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
// Reset filters
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
|
||||
testButtons("css");
|
||||
return testContents([0, 1, 0, 0, 0, 0, 0, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-js-button"));
|
||||
testButtons("js");
|
||||
return testContents([0, 0, 1, 0, 0, 0, 0, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-xhr-button"));
|
||||
testButtons("xhr");
|
||||
return testContents([1, 1, 1, 1, 1, 1, 1, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-fonts-button"));
|
||||
testButtons("fonts");
|
||||
return testContents([0, 0, 0, 1, 0, 0, 0, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-images-button"));
|
||||
testButtons("images");
|
||||
return testContents([0, 0, 0, 0, 1, 0, 0, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-media-button"));
|
||||
testButtons("media");
|
||||
return testContents([0, 0, 0, 0, 0, 1, 1, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
|
||||
testButtons("flash");
|
||||
return testContents([0, 0, 0, 0, 0, 0, 0, 1]);
|
||||
|
@ -71,24 +80,85 @@ function test() {
|
|||
testButtons("all");
|
||||
return testContents([1, 1, 1, 1, 1, 1, 1, 1]);
|
||||
})
|
||||
// ...then combine multiple filters together.
|
||||
.then(() => {
|
||||
// Enable filtering for html and css; should show request of both type.
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
|
||||
testButtonsCustom([0, 1, 1, 0, 0, 0, 0, 0, 0, 0]);
|
||||
return testContents([1, 1, 0, 0, 0, 0, 0, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
|
||||
testButtonsCustom([0, 1, 1, 0, 0, 0, 0, 0, 1, 0]);
|
||||
return testContents([1, 1, 0, 0, 0, 0, 0, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
// Disable some filters. Only one left active.
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
|
||||
testButtons("html");
|
||||
return testContents([1, 0, 0, 0, 0, 0, 0, 0]);
|
||||
})
|
||||
.then(() => {
|
||||
// Disable last active filter. Should toggle to all.
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
|
||||
testButtons("all");
|
||||
return testContents([1, 1, 1, 1, 1, 1, 1, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
// Enable few filters and click on all. Only "all" should be checked.
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
|
||||
testButtonsCustom([0, 1, 1, 0, 0, 0, 0, 0, 0]);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
testButtons("all");
|
||||
return testContents([1, 1, 1, 1, 1, 1, 1, 1]);
|
||||
})
|
||||
.then(() => {
|
||||
return teardown(aMonitor);
|
||||
})
|
||||
.then(finish);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests if a button for a filter of given type is the only one checked.
|
||||
*
|
||||
* @param string aFilterType
|
||||
* The type of the filter that should be the only one checked.
|
||||
*
|
||||
*/
|
||||
function testButtons(aFilterType) {
|
||||
let doc = aMonitor.panelWin.document;
|
||||
let target = doc.querySelector("#requests-menu-filter-" + aFilterType + "-button");
|
||||
let buttons = doc.querySelectorAll(".requests-menu-footer-button");
|
||||
|
||||
for (let button of buttons) {
|
||||
if (button != target) {
|
||||
is(button.hasAttribute("checked"), false,
|
||||
"The " + button.id + " button should not have a 'checked' attribute.");
|
||||
} else {
|
||||
// Only target should be checked.
|
||||
let checkStatus = [(button == target) ? 1 : 0 for (button of buttons)]
|
||||
|
||||
testButtonsCustom(checkStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if filter buttons have 'checked' attributes set correctly.
|
||||
*
|
||||
* @param array aIsChecked
|
||||
* An array specifying if a button at given index should have a
|
||||
* 'checked' attribute. For example, if the third item of the array
|
||||
* evaluates to true, the third button should be checked.
|
||||
*
|
||||
*/
|
||||
function testButtonsCustom(aIsChecked) {
|
||||
let doc = aMonitor.panelWin.document;
|
||||
let buttons = doc.querySelectorAll(".requests-menu-footer-button");
|
||||
for (let i = 0; i < aIsChecked.length; i++) {
|
||||
let button = buttons[i];
|
||||
if (aIsChecked[i]) {
|
||||
is(button.hasAttribute("checked"), true,
|
||||
"The " + button.id + " button should have a 'checked' attribute.");
|
||||
} else {
|
||||
is(button.hasAttribute("checked"), false,
|
||||
"The " + button.id + " button should not have a 'checked' attribute.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ gcli.addCommand({
|
|||
gcli.addCommand({
|
||||
name: 'resize toggle',
|
||||
buttonId: "command-button-responsive",
|
||||
buttonClass: "command-button",
|
||||
buttonClass: "command-button command-button-invertable",
|
||||
tooltipText: gcli.lookup("resizeModeToggleTooltip"),
|
||||
description: gcli.lookup('resizeModeToggleDesc'),
|
||||
manual: gcli.lookupFormat('resizeModeManual2', [BRAND_SHORT_NAME]),
|
||||
|
|
|
@ -12,7 +12,7 @@ Components.utils.import("resource://gre/modules/devtools/gcli.jsm");
|
|||
gcli.addCommand({
|
||||
name: "scratchpad",
|
||||
buttonId: "command-button-scratchpad",
|
||||
buttonClass: "command-button",
|
||||
buttonClass: "command-button command-button-invertable",
|
||||
tooltipText: gcli.lookup("scratchpadOpenTooltip"),
|
||||
hidden: true,
|
||||
exec: function(args, context) {
|
||||
|
|
|
@ -54,7 +54,7 @@ gcli.addCommand({
|
|||
gcli.addCommand({
|
||||
name: "tilt toggle",
|
||||
buttonId: "command-button-tilt",
|
||||
buttonClass: "command-button",
|
||||
buttonClass: "command-button command-button-invertable",
|
||||
tooltipText: gcli.lookup("tiltToggleTooltip"),
|
||||
hidden: true,
|
||||
state: {
|
||||
|
|
|
@ -15,31 +15,22 @@ function test()
|
|||
|
||||
let webconsole, browserconsole;
|
||||
|
||||
addTab(TEST_URI);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
Task.spawn(runner).then(finishTest);
|
||||
|
||||
openConsole(null, consoleOpened);
|
||||
}, true);
|
||||
function* runner() {
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
webconsole = yield openConsole(tab);
|
||||
ok(webconsole, "web console opened");
|
||||
|
||||
function consoleOpened(hud)
|
||||
{
|
||||
ok(hud, "web console opened");
|
||||
webconsole = hud;
|
||||
HUDService.toggleBrowserConsole().then(browserConsoleOpened);
|
||||
}
|
||||
|
||||
function browserConsoleOpened(hud)
|
||||
{
|
||||
ok(hud, "browser console opened");
|
||||
browserconsole = hud;
|
||||
browserconsole = yield HUDService.toggleBrowserConsole();
|
||||
ok(browserconsole, "browser console opened");
|
||||
|
||||
// Cause an exception in a script loaded with the addon-sdk loader.
|
||||
let toolbox = gDevTools.getToolbox(webconsole.target);
|
||||
let oldPanels = toolbox._toolPanels;
|
||||
toolbox._toolPanels = null;
|
||||
function fixToolbox()
|
||||
{
|
||||
|
||||
function fixToolbox() {
|
||||
toolbox._toolPanels = oldPanels;
|
||||
}
|
||||
|
||||
|
@ -51,24 +42,18 @@ function test()
|
|||
toolbox.getToolPanels();
|
||||
});
|
||||
|
||||
waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [
|
||||
{
|
||||
text: "TypeError: can't convert null to object",
|
||||
category: CATEGORY_JS,
|
||||
severity: SEVERITY_ERROR,
|
||||
},
|
||||
],
|
||||
}).then((results) => {
|
||||
fixToolbox();
|
||||
onMessageFound(results);
|
||||
let [result] = yield waitForMessages({
|
||||
webconsole: browserconsole,
|
||||
messages: [{
|
||||
text: "TypeError: can't convert null to object",
|
||||
category: CATEGORY_JS,
|
||||
severity: SEVERITY_ERROR,
|
||||
}],
|
||||
});
|
||||
}
|
||||
|
||||
function onMessageFound(results)
|
||||
{
|
||||
let msg = [...results[0].matched][0];
|
||||
fixToolbox();
|
||||
|
||||
let msg = [...result.matched][0];
|
||||
ok(msg, "message element found");
|
||||
let locationNode = msg.querySelector(".message-location");
|
||||
ok(locationNode, "message location element found");
|
||||
|
@ -79,17 +64,25 @@ function test()
|
|||
|
||||
let viewSource = browserconsole.viewSource;
|
||||
let URL = null;
|
||||
browserconsole.viewSource = (aURL) => URL = aURL;
|
||||
let clickPromise = promise.defer();
|
||||
browserconsole.viewSource = (aURL) => {
|
||||
info("browserconsole.viewSource() was invoked: " + aURL);
|
||||
URL = aURL;
|
||||
clickPromise.resolve(null);
|
||||
};
|
||||
|
||||
msg.scrollIntoView();
|
||||
EventUtils.synthesizeMouse(locationNode, 2, 2, {},
|
||||
browserconsole.iframeWindow);
|
||||
|
||||
info("wait for click on locationNode");
|
||||
yield clickPromise;
|
||||
|
||||
info("view-source url: " + URL);
|
||||
isnot(URL.indexOf("toolbox.js"), -1, "expected view source URL");
|
||||
ok(URL, "we have some source URL after the click");
|
||||
isnot(URL.indexOf("toolbox.js"), -1, "we have the expected view source URL");
|
||||
is(URL.indexOf("->"), -1, "no -> in the URL given to view-source");
|
||||
|
||||
browserconsole.viewSource = viewSource;
|
||||
|
||||
finishTest();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -753,10 +753,10 @@
|
|||
/* Invert the colors of certain dark theme images for displaying
|
||||
* inside of the light theme.
|
||||
*/
|
||||
.theme-light .devtools-tab > image,
|
||||
.theme-light .devtools-tab[icon-invertable] > image,
|
||||
.theme-light #toolbox-dock-buttons > toolbarbutton > image,
|
||||
.theme-light .command-button > image,
|
||||
.theme-light .command-button:active > image,
|
||||
.theme-light .command-button-invertable > image,
|
||||
.theme-light .command-button-invertable:active > image,
|
||||
.theme-light .devtools-closebutton > image,
|
||||
.theme-light .devtools-toolbarbutton > image,
|
||||
.theme-light .devtools-option-toolbarbutton > image,
|
||||
|
@ -771,9 +771,9 @@
|
|||
|
||||
/* Since selected backgrounds are blue, we want to use the normal
|
||||
* (light) icons. */
|
||||
.theme-light .command-button[checked=true]:not(:active) > image,
|
||||
.theme-light .devtools-tab[selected] > image,
|
||||
.theme-light .devtools-tab[highlighted] > image,
|
||||
.theme-light .command-button-invertable[checked=true]:not(:active) > image,
|
||||
.theme-light .devtools-tab[icon-invertable][selected] > image,
|
||||
.theme-light .devtools-tab[icon-invertable][highlighted] > image,
|
||||
.theme-light .devtools-option-toolbarbutton[open] > image,
|
||||
.theme-light #resume[checked] > image {
|
||||
filter: none !important;
|
||||
|
|
|
@ -174,6 +174,7 @@ public:
|
|||
MOZ_FINAL MOZ_OVERRIDE;
|
||||
virtual sp<MetaData> getTrackMetaData(
|
||||
size_t index, uint32_t flag = 0) MOZ_FINAL MOZ_OVERRIDE;
|
||||
virtual uint32_t flags() const MOZ_FINAL MOZ_OVERRIDE;
|
||||
|
||||
RtspExtractor(RtspMediaResource *aResource)
|
||||
: mRtspResource(aResource) {
|
||||
|
@ -256,15 +257,24 @@ sp<MetaData> RtspExtractor::getTrackMetaData(size_t index, uint32_t flag)
|
|||
return meta;
|
||||
}
|
||||
|
||||
uint32_t RtspExtractor::flags() const
|
||||
{
|
||||
if (mRtspResource->IsRealTime()) {
|
||||
return 0;
|
||||
} else {
|
||||
return MediaExtractor::CAN_SEEK;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult RtspOmxReader::InitOmxDecoder()
|
||||
{
|
||||
if (!mOmxDecoder.get()) {
|
||||
NS_ASSERTION(mDecoder, "RtspOmxReader mDecoder is null.");
|
||||
NS_ASSERTION(mDecoder->GetResource(),
|
||||
"RtspOmxReader mDecoder->GetResource() is null.");
|
||||
sp<MediaExtractor> extractor = new RtspExtractor(mRtspResource);
|
||||
mExtractor = new RtspExtractor(mRtspResource);
|
||||
mOmxDecoder = new OmxDecoder(mDecoder->GetResource(), mDecoder);
|
||||
if (!mOmxDecoder->Init(extractor)) {
|
||||
if (!mOmxDecoder->Init(mExtractor)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,11 @@ var manager = new MediaTestManager;
|
|||
var player = new Audio();
|
||||
|
||||
function startTest(test, token) {
|
||||
if (!player.canPlayType(test.type))
|
||||
if (!player.canPlayType(test.type)) {
|
||||
return;
|
||||
}
|
||||
manager.started(token);
|
||||
var a = new Audio(test.name);
|
||||
a.setAttribute("autoplay", false);
|
||||
a.addEventListener("canplaythrough",
|
||||
function(e){ e.target.play(); },
|
||||
false);
|
||||
|
|
|
@ -16,7 +16,7 @@ Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
|
|||
Cu.importGlobalProperties(["indexedDB"]);
|
||||
|
||||
const DB_NAME = "net_stats";
|
||||
const DB_VERSION = 6;
|
||||
const DB_VERSION = 7;
|
||||
const DEPRECATED_STORE_NAME = "net_stats";
|
||||
const STATS_STORE_NAME = "net_stats_store";
|
||||
const ALARMS_STORE_NAME = "net_alarm";
|
||||
|
@ -213,6 +213,94 @@ NetworkStatsDB.prototype = {
|
|||
if (DEBUG) {
|
||||
debug("Added new key 'serviceType' for version 6");
|
||||
}
|
||||
} else if (currVersion == 6) {
|
||||
// Replace threshold attribute of alarm index by relativeThreshold in alarms DB.
|
||||
// Now alarms are indexed by relativeThreshold, which is the threshold relative
|
||||
// to current system stats.
|
||||
let alarmsStore = aTransaction.objectStore(ALARMS_STORE_NAME);
|
||||
|
||||
// Delete "alarm" index.
|
||||
if (alarmsStore.indexNames.contains("alarm")) {
|
||||
alarmsStore.deleteIndex("alarm");
|
||||
}
|
||||
|
||||
// Create new "alarm" index.
|
||||
alarmsStore.createIndex("alarm", ['networkId','relativeThreshold'], { unique: false });
|
||||
|
||||
// Populate new "alarm" index attributes.
|
||||
alarmsStore.openCursor().onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor.value.relativeThreshold = cursor.value.threshold;
|
||||
cursor.value.absoluteThreshold = cursor.value.threshold;
|
||||
delete cursor.value.threshold;
|
||||
|
||||
cursor.update(cursor.value);
|
||||
cursor.continue();
|
||||
}
|
||||
|
||||
// Previous versions save accumulative totalBytes, increasing althought the system
|
||||
// reboots or resets stats. But is necessary to reset the total counters when reset
|
||||
// through 'clearInterfaceStats'.
|
||||
let statsStore = aTransaction.objectStore(STATS_STORE_NAME);
|
||||
let networks = [];
|
||||
// Find networks stored in the database.
|
||||
statsStore.index("network").openKeyCursor(null, "nextunique").onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
networks.push(cursor.key);
|
||||
cursor.continue();
|
||||
return;
|
||||
}
|
||||
|
||||
networks.forEach(function(network) {
|
||||
let lowerFilter = [0, "", network, 0];
|
||||
let upperFilter = [0, "", network, ""];
|
||||
let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
|
||||
|
||||
// Find number of samples for a given network.
|
||||
statsStore.count(range).onsuccess = function(event) {
|
||||
// If there are more samples than the max allowed, there is no way to know
|
||||
// when does reset take place.
|
||||
if (event.target.result >= VALUES_MAX_LENGTH) {
|
||||
return;
|
||||
}
|
||||
|
||||
let last = null;
|
||||
// Reset detected if the first sample totalCounters are different than bytes
|
||||
// counters. If so, the total counters should be recalculated.
|
||||
statsStore.openCursor(range).onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
return;
|
||||
}
|
||||
if (!last) {
|
||||
if (cursor.value.rxTotalBytes == cursor.value.rxBytes &&
|
||||
cursor.value.txTotalBytes == cursor.value.txBytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor.value.rxTotalBytes = cursor.value.rxBytes;
|
||||
cursor.value.txTotalBytes = cursor.value.txBytes;
|
||||
cursor.update(cursor.value);
|
||||
last = cursor.value;
|
||||
cursor.continue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Recalculate the total counter for last / current sample
|
||||
cursor.value.rxTotalBytes = last.rxTotalBytes + cursor.value.rxBytes;
|
||||
cursor.value.txTotalBytes = last.txTotalBytes + cursor.value.txBytes;
|
||||
cursor.update(cursor.value);
|
||||
last = cursor.value;
|
||||
cursor.continue();
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -515,6 +603,8 @@ NetworkStatsDB.prototype = {
|
|||
sample.serviceType = "";
|
||||
sample.rxBytes = 0;
|
||||
sample.txBytes = 0;
|
||||
sample.rxTotalBytes = 0;
|
||||
sample.txTotalBytes = 0;
|
||||
|
||||
self._saveStats(aTxn, aStore, sample);
|
||||
}
|
||||
|
@ -550,24 +640,78 @@ NetworkStatsDB.prototype = {
|
|||
debug("Get current stats for " + JSON.stringify(aNetwork) + " since " + aDate);
|
||||
}
|
||||
|
||||
let network = [aNetwork.id, aNetwork.type];
|
||||
if (aDate) {
|
||||
this._getCurrentStatsFromDate(network, aDate, aResultCb);
|
||||
return;
|
||||
}
|
||||
|
||||
this._getCurrentStats(network, aResultCb);
|
||||
},
|
||||
|
||||
_getCurrentStats: function _getCurrentStats(aNetwork, aResultCb) {
|
||||
this.dbNewTxn(STATS_STORE_NAME, "readonly", function(txn, store) {
|
||||
let request = null;
|
||||
let network = [aNetwork.id, aNetwork.type];
|
||||
if (aDate) {
|
||||
let start = this.normalizeDate(aDate);
|
||||
let lowerFilter = [0, network, start];
|
||||
let range = this.dbGlobal.IDBKeyRange.lowerBound(lowerFilter, false);
|
||||
request = store.openCursor(range);
|
||||
} else {
|
||||
request = store.index("network").openCursor(network, "prev");
|
||||
}
|
||||
let upperFilter = [0, "", aNetwork, Date.now()];
|
||||
let range = IDBKeyRange.upperBound(upperFilter, false);
|
||||
request = store.openCursor(range, "prev");
|
||||
|
||||
let result = { rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 0, txTotalBytes: 0 };
|
||||
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
txn.result = null;
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
txn.result = cursor.value;
|
||||
result.rxBytes = result.rxTotalBytes = cursor.value.rxTotalBytes;
|
||||
result.txBytes = result.txTotalBytes = cursor.value.txTotalBytes;
|
||||
}
|
||||
|
||||
txn.result = result;
|
||||
};
|
||||
}.bind(this), aResultCb);
|
||||
},
|
||||
|
||||
_getCurrentStatsFromDate: function _getCurrentStatsFromDate(aNetwork, aDate, aResultCb) {
|
||||
aDate = new Date(aDate);
|
||||
this.dbNewTxn(STATS_STORE_NAME, "readonly", function(txn, store) {
|
||||
let request = null;
|
||||
let start = this.normalizeDate(aDate);
|
||||
let lowerFilter = [0, "", aNetwork, start];
|
||||
let upperFilter = [0, "", aNetwork, Date.now()];
|
||||
|
||||
let range = IDBKeyRange.upperBound(upperFilter, false);
|
||||
|
||||
let result = { rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 0, txTotalBytes: 0 };
|
||||
|
||||
request = store.openCursor(range, "prev");
|
||||
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
result.rxBytes = result.rxTotalBytes = cursor.value.rxTotalBytes;
|
||||
result.txBytes = result.txTotalBytes = cursor.value.txTotalBytes;
|
||||
}
|
||||
|
||||
let timestamp = cursor.value.timestamp;
|
||||
let range = IDBKeyRange.lowerBound(lowerFilter, false);
|
||||
request = store.openCursor(range);
|
||||
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
if (cursor.value.timestamp == timestamp) {
|
||||
// There is one sample only.
|
||||
result.rxBytes = cursor.value.rxBytes;
|
||||
result.txBytes = cursor.value.txBytes;
|
||||
} else {
|
||||
result.rxBytes -= cursor.value.rxTotalBytes;
|
||||
result.txBytes -= cursor.value.txTotalBytes;
|
||||
}
|
||||
}
|
||||
|
||||
txn.result = result;
|
||||
};
|
||||
};
|
||||
}.bind(this), aResultCb);
|
||||
},
|
||||
|
@ -671,7 +815,7 @@ NetworkStatsDB.prototype = {
|
|||
aTxn.result = false;
|
||||
}
|
||||
|
||||
var network = [aNetwork.id, aNetwork.type];
|
||||
let network = [aNetwork.id, aNetwork.type];
|
||||
let request = aStore.index("network").openKeyCursor(IDBKeyRange.only(network));
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
if (event.target.result) {
|
||||
|
@ -717,7 +861,8 @@ NetworkStatsDB.prototype = {
|
|||
|
||||
alarmToRecord: function alarmToRecord(aAlarm) {
|
||||
let record = { networkId: aAlarm.networkId,
|
||||
threshold: aAlarm.threshold,
|
||||
absoluteThreshold: aAlarm.absoluteThreshold,
|
||||
relativeThreshold: aAlarm.relativeThreshold,
|
||||
data: aAlarm.data,
|
||||
manifestURL: aAlarm.manifestURL,
|
||||
pageURL: aAlarm.pageURL };
|
||||
|
@ -731,7 +876,8 @@ NetworkStatsDB.prototype = {
|
|||
|
||||
recordToAlarm: function recordToalarm(aRecord) {
|
||||
let alarm = { networkId: aRecord.networkId,
|
||||
threshold: aRecord.threshold,
|
||||
absoluteThreshold: aRecord.absoluteThreshold,
|
||||
relativeThreshold: aRecord.relativeThreshold,
|
||||
data: aRecord.data,
|
||||
manifestURL: aRecord.manifestURL,
|
||||
pageURL: aRecord.pageURL };
|
||||
|
@ -837,6 +983,7 @@ NetworkStatsDB.prototype = {
|
|||
},
|
||||
|
||||
getAlarms: function getAlarms(aNetworkId, aManifestURL, aResultCb) {
|
||||
let self = this;
|
||||
this.dbNewTxn(ALARMS_STORE_NAME, "readonly", function(txn, store) {
|
||||
if (DEBUG) {
|
||||
debug("Get alarms for " + aManifestURL);
|
||||
|
@ -851,12 +998,7 @@ NetworkStatsDB.prototype = {
|
|||
}
|
||||
|
||||
if (!aNetworkId || cursor.value.networkId == aNetworkId) {
|
||||
let alarm = { id: cursor.value.id,
|
||||
networkId: cursor.value.networkId,
|
||||
threshold: cursor.value.threshold,
|
||||
data: cursor.value.data };
|
||||
|
||||
txn.result.push(alarm);
|
||||
txn.result.push(self.recordToAlarm(cursor.value));
|
||||
}
|
||||
|
||||
cursor.continue();
|
||||
|
|
|
@ -237,6 +237,10 @@ NetworkStatsManager.prototype = {
|
|||
aOptions = Object.create(null);
|
||||
}
|
||||
|
||||
if (aOptions.startTime && aOptions.startTime.constructor.name !== "Date") {
|
||||
throw Components.results.NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
let request = this.createRequest();
|
||||
cpmm.sendAsyncMessage("NetworkStats:SetAlarm",
|
||||
{id: this.getRequestId(request),
|
||||
|
|
|
@ -331,10 +331,11 @@ this.NetworkStatsService = {
|
|||
this._networks[netId].status = NETWORK_STATUS_AWAY;
|
||||
this._currentAlarms[netId] = Object.create(null);
|
||||
aCallback(netId);
|
||||
return;
|
||||
}
|
||||
|
||||
aCallback(null);
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
getAvailableNetworks: function getAvailableNetworks(mm, msg) {
|
||||
|
@ -863,7 +864,7 @@ this.NetworkStatsService = {
|
|||
let alarm = result[i];
|
||||
alarms.push({ id: alarm.id,
|
||||
network: self._networks[alarm.networkId].network,
|
||||
threshold: alarm.threshold,
|
||||
threshold: alarm.absoluteThreshold,
|
||||
data: alarm.data });
|
||||
}
|
||||
|
||||
|
@ -931,22 +932,21 @@ this.NetworkStatsService = {
|
|||
let newAlarm = {
|
||||
id: null,
|
||||
networkId: aNetId,
|
||||
threshold: threshold,
|
||||
absoluteThreshold: null,
|
||||
absoluteThreshold: threshold,
|
||||
relativeThreshold: null,
|
||||
startTime: options.startTime,
|
||||
data: options.data,
|
||||
pageURL: options.pageURL,
|
||||
manifestURL: options.manifestURL
|
||||
};
|
||||
|
||||
self._updateThreshold(newAlarm, function onUpdate(error, _threshold) {
|
||||
self._getAlarmQuota(newAlarm, function onUpdate(error, quota) {
|
||||
if (error) {
|
||||
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
|
||||
{ id: msg.id, error: error, result: null });
|
||||
return;
|
||||
}
|
||||
|
||||
newAlarm.absoluteThreshold = _threshold.absoluteThreshold;
|
||||
self._db.addAlarm(newAlarm, function addSuccessCb(error, newId) {
|
||||
if (error) {
|
||||
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
|
||||
|
@ -971,7 +971,7 @@ this.NetworkStatsService = {
|
|||
_setAlarm: function _setAlarm(aAlarm, aCallback) {
|
||||
let currentAlarm = this._currentAlarms[aAlarm.networkId];
|
||||
if ((Object.getOwnPropertyNames(currentAlarm).length !== 0 &&
|
||||
aAlarm.absoluteThreshold > currentAlarm.alarm.absoluteThreshold) ||
|
||||
aAlarm.relativeThreshold > currentAlarm.alarm.relativeThreshold) ||
|
||||
this._networks[aAlarm.networkId].status != NETWORK_STATUS_READY) {
|
||||
aCallback(null, true);
|
||||
return;
|
||||
|
@ -979,7 +979,7 @@ this.NetworkStatsService = {
|
|||
|
||||
let self = this;
|
||||
|
||||
this._updateThreshold(aAlarm, function onUpdate(aError, aThreshold) {
|
||||
this._getAlarmQuota(aAlarm, function onUpdate(aError, aQuota) {
|
||||
if (aError) {
|
||||
aCallback(aError, null);
|
||||
return;
|
||||
|
@ -1001,7 +1001,7 @@ this.NetworkStatsService = {
|
|||
let interfaceName = self._networks[aAlarm.networkId].interfaceName;
|
||||
if (interfaceName) {
|
||||
networkService.setNetworkInterfaceAlarm(interfaceName,
|
||||
aThreshold.systemThreshold,
|
||||
aQuota,
|
||||
callback);
|
||||
return;
|
||||
}
|
||||
|
@ -1010,7 +1010,7 @@ this.NetworkStatsService = {
|
|||
});
|
||||
},
|
||||
|
||||
_updateThreshold: function _updateThreshold(aAlarm, aCallback) {
|
||||
_getAlarmQuota: function _getAlarmQuota(aAlarm, aCallback) {
|
||||
let self = this;
|
||||
this.updateStats(aAlarm.networkId, function onStatsUpdated(aResult, aMessage) {
|
||||
self._db.getCurrentStats(self._networks[aAlarm.networkId].network,
|
||||
|
@ -1023,28 +1023,19 @@ this.NetworkStatsService = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
// There are no stats for the network of the alarm, set them to default 0 in
|
||||
// order to be able to calculate the offset, systemThreshold and
|
||||
// absoluteThreshold.
|
||||
result = { rxTotalBytes: 0, txTotalBytes: 0,
|
||||
rxSystemBytes: 0, txSystemBytes: 0 };
|
||||
}
|
||||
|
||||
let offset = aAlarm.threshold - result.rxTotalBytes - result.txTotalBytes;
|
||||
let quota = aAlarm.absoluteThreshold - result.rxBytes - result.txBytes;
|
||||
|
||||
// Alarm set to a threshold lower than current rx/tx bytes.
|
||||
if (offset <= 0) {
|
||||
if (quota <= 0) {
|
||||
aCallback("InvalidStateError", null);
|
||||
return;
|
||||
}
|
||||
|
||||
let threshold = {
|
||||
systemThreshold: result.rxSystemBytes + result.txSystemBytes + offset,
|
||||
absoluteThreshold: result.rxTotalBytes + result.txTotalBytes + offset
|
||||
};
|
||||
aAlarm.relativeThreshold = aAlarm.startTime
|
||||
? result.rxTotalBytes + result.txTotalBytes + quota
|
||||
: aAlarm.absoluteThreshold;
|
||||
|
||||
aCallback(null, threshold);
|
||||
aCallback(null, quota);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
@ -1096,7 +1087,7 @@ this.NetworkStatsService = {
|
|||
let pageURI = Services.io.newURI(aAlarm.pageURL, null, null);
|
||||
|
||||
let alarm = { "id": aAlarm.id,
|
||||
"threshold": aAlarm.threshold,
|
||||
"threshold": aAlarm.absoluteThreshold,
|
||||
"data": aAlarm.data };
|
||||
messenger.sendMessage("networkstats-alarm", alarm, pageURI, manifestURI);
|
||||
}
|
||||
|
|
|
@ -734,30 +734,34 @@ var exampleManifestURL = "http://example.com/manifest.webapp";
|
|||
var testPageURL = "http://test.com/index.html";
|
||||
var testManifestURL = "http://test.com/manifest.webapp";
|
||||
|
||||
var alarms = [{ id: null,
|
||||
networkId: networkWifi,
|
||||
threshold: 10000,
|
||||
data: {foo: "something"},
|
||||
pageURL: examplePageURL,
|
||||
manifestURL: exampleManifestURL },
|
||||
{ id: null,
|
||||
networkId: networkWifi,
|
||||
threshold: 1000,
|
||||
data: {foo: "else"},
|
||||
pageURL: examplePageURL,
|
||||
manifestURL: exampleManifestURL },
|
||||
{ id: null,
|
||||
networkId: networkMobile,
|
||||
threshold: 100,
|
||||
data: {foo: "to"},
|
||||
pageURL: examplePageURL,
|
||||
manifestURL: exampleManifestURL },
|
||||
{ id: null,
|
||||
networkId: networkMobile,
|
||||
threshold: 10,
|
||||
data: {foo: "test"},
|
||||
pageURL: testPageURL,
|
||||
manifestURL: testManifestURL }];
|
||||
var alarms = [{ id: null,
|
||||
networkId: networkWifi,
|
||||
absoluteThreshold: 10000,
|
||||
relativeThreshold: 10000,
|
||||
data: {foo: "something"},
|
||||
pageURL: examplePageURL,
|
||||
manifestURL: exampleManifestURL },
|
||||
{ id: null,
|
||||
networkId: networkWifi,
|
||||
absoluteThreshold: 1000,
|
||||
relativeThreshold: 1000,
|
||||
data: {foo: "else"},
|
||||
pageURL: examplePageURL,
|
||||
manifestURL: exampleManifestURL },
|
||||
{ id: null,
|
||||
networkId: networkMobile,
|
||||
absoluteThreshold: 100,
|
||||
relativeThreshold: 100,
|
||||
data: {foo: "to"},
|
||||
pageURL: examplePageURL,
|
||||
manifestURL: exampleManifestURL },
|
||||
{ id: null,
|
||||
networkId: networkMobile,
|
||||
absoluteThreshold: 10,
|
||||
relativeThreshold: 10,
|
||||
data: {foo: "test"},
|
||||
pageURL: testPageURL,
|
||||
manifestURL: testManifestURL }];
|
||||
|
||||
var alarmsDbId = 1;
|
||||
|
||||
|
@ -772,7 +776,8 @@ add_test(function test_addAlarm() {
|
|||
do_check_eq(result.length, 1);
|
||||
do_check_eq(result[0].id, alarmsDbId);
|
||||
do_check_eq(result[0].networkId, alarms[0].networkId);
|
||||
do_check_eq(result[0].threshold, alarms[0].threshold);
|
||||
do_check_eq(result[0].absoluteThreshold, alarms[0].absoluteThreshold);
|
||||
do_check_eq(result[0].relativeThreshold, alarms[0].relativeThreshold);
|
||||
do_check_eq(result[0].data.foo, alarms[0].data.foo);
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -790,7 +795,8 @@ add_test(function test_getFirstAlarm() {
|
|||
do_check_eq(error, null);
|
||||
do_check_eq(result.id, alarmsDbId);
|
||||
do_check_eq(result.networkId, alarms[1].networkId);
|
||||
do_check_eq(result.threshold, alarms[1].threshold);
|
||||
do_check_eq(result.absoluteThreshold, alarms[1].absoluteThreshold);
|
||||
do_check_eq(result.relativeThreshold, alarms[1].relativeThreshold);
|
||||
do_check_eq(result.data.foo, alarms[1].data.foo);
|
||||
do_check_eq(result.pageURL, alarms[1].pageURL);
|
||||
do_check_eq(result.manifestURL, alarms[1].manifestURL);
|
||||
|
@ -808,7 +814,8 @@ add_test(function test_removeAlarm() {
|
|||
do_check_eq(error, null);
|
||||
do_check_eq(result.id, alarmsDbId - 1);
|
||||
do_check_eq(result.networkId, alarms[0].networkId);
|
||||
do_check_eq(result.threshold, alarms[0].threshold);
|
||||
do_check_eq(result.absoluteThreshold, alarms[0].absoluteThreshold);
|
||||
do_check_eq(result.relativeThreshold, alarms[0].relativeThreshold);
|
||||
do_check_eq(result.data.foo, alarms[0].data.foo);
|
||||
do_check_eq(result.pageURL, alarms[0].pageURL);
|
||||
do_check_eq(result.manifestURL, alarms[0].manifestURL);
|
||||
|
@ -897,7 +904,8 @@ add_test(function test_updateAlarm() {
|
|||
do_check_eq(error, null);
|
||||
do_check_eq(result.id, updatedAlarm.id);
|
||||
do_check_eq(result.networkId, updatedAlarm.networkId);
|
||||
do_check_eq(result.threshold, updatedAlarm.threshold);
|
||||
do_check_eq(result.absoluteThreshold, updatedAlarm.absoluteThreshold);
|
||||
do_check_eq(result.relativeThreshold, updatedAlarm.relativeThreshold);
|
||||
do_check_eq(result.data.foo, updatedAlarm.data.foo);
|
||||
do_check_eq(result.pageURL, updatedAlarm.pageURL);
|
||||
do_check_eq(result.manifestURL, updatedAlarm.manifestURL);
|
||||
|
|
|
@ -7,6 +7,8 @@ const NETWORK_STATUS_READY = 0;
|
|||
const NETWORK_STATUS_STANDBY = 1;
|
||||
const NETWORK_STATUS_AWAY = 2;
|
||||
|
||||
var wifiId = '00';
|
||||
|
||||
function getNetworks(callback) {
|
||||
NetworkStatsService._db.getAvailableNetworks(function onGetNetworks(aError, aResult) {
|
||||
callback(aError, aResult);
|
||||
|
@ -122,9 +124,34 @@ add_test(function test_updateStats_failure() {
|
|||
});
|
||||
});
|
||||
|
||||
// Define Mockup function to simulate a request to netd
|
||||
function MockNetdRequest(aCallback) {
|
||||
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
var event = {
|
||||
notify: function (timer) {
|
||||
aCallback();
|
||||
}
|
||||
};
|
||||
|
||||
timer.initWithCallback(event, 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
add_test(function test_queue() {
|
||||
// Fill networks with fake network interfaces
|
||||
// to enable netd async requests
|
||||
|
||||
// Overwrite update function of NetworkStatsService to avoid netd errors due to use
|
||||
// fake interfaces. First, original function is stored to restore it at the end of the
|
||||
// test.
|
||||
var updateFunctionBackup = NetworkStatsService.update;
|
||||
|
||||
NetworkStatsService.update = function update(aNetId, aCallback) {
|
||||
MockNetdRequest(function () {
|
||||
if (aCallback) {
|
||||
aCallback(true, "ok");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Fill networks with fake network interfaces to enable netd async requests.
|
||||
var network = {id: "1234", type: Ci.nsIDOMMozNetworkStatsManager.MOBILE};
|
||||
var netId1 = NetworkStatsService.getNetworkId(network.id, network.type);
|
||||
NetworkStatsService._networks[netId1] = { network: network,
|
||||
|
@ -140,33 +167,34 @@ add_test(function test_queue() {
|
|||
do_check_eq(NetworkStatsService.updateQueue.length, 2);
|
||||
do_check_eq(NetworkStatsService.updateQueue[0].callbacks.length, 1);
|
||||
|
||||
var i = 0;
|
||||
var updateCount = 0;
|
||||
var callback = function(success, msg) {
|
||||
return;
|
||||
i++;
|
||||
if (i >= updateCount) {
|
||||
NetworkStatsService.update = updateFunctionBackup;
|
||||
run_next_test();
|
||||
}
|
||||
};
|
||||
|
||||
NetworkStatsService.updateStats(netId1, callback);
|
||||
updateCount++;
|
||||
NetworkStatsService.updateStats(netId2, callback);
|
||||
updateCount++;
|
||||
|
||||
do_check_eq(NetworkStatsService.updateQueue.length, 2);
|
||||
do_check_eq(NetworkStatsService.updateQueue[0].callbacks.length, 2);
|
||||
do_check_eq(NetworkStatsService.updateQueue[0].callbacks[0], null);
|
||||
do_check_neq(NetworkStatsService.updateQueue[0].callbacks[1], null);
|
||||
|
||||
// Clear queue because in test environment requests for mobile networks
|
||||
// can not be handled.
|
||||
NetworkStatsService.updateQueue = [];
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
var wifiId = '00';
|
||||
add_test(function test_getAlarmQuota() {
|
||||
let alarm = { networkId: wifiId, absoluteThreshold: 10000 };
|
||||
|
||||
add_test(function test_updateThreshold() {
|
||||
let alarm = { networkId: wifiId, threshold: 10000 };
|
||||
|
||||
NetworkStatsService._updateThreshold(alarm, function onSet(error, threshold){
|
||||
NetworkStatsService._getAlarmQuota(alarm, function onSet(error, quota){
|
||||
do_check_eq(error, null);
|
||||
do_check_neq(threshold.systemThreshold, undefined);
|
||||
do_check_neq(threshold.absoluteThreshold, undefined);
|
||||
do_check_neq(quota, undefined);
|
||||
do_check_eq(alarm.absoluteThreshold, alarm.relativeThreshold);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
@ -222,6 +250,9 @@ add_test(function test_fireAlarm() {
|
|||
pageURL: testPageURL,
|
||||
manifestURL: testManifestURL };
|
||||
|
||||
// Set wifi status to standby to avoid connecting to netd when adding an alarm.
|
||||
NetworkStatsService._networks[wifiId].status = NETWORK_STATUS_STANDBY;
|
||||
|
||||
NetworkStatsService._db.addAlarm(alarm, function addSuccessCb(error, newId) {
|
||||
NetworkStatsService._db.getAlarms(Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
|
||||
testManifestURL, function onGet(error, result) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Effects.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Endian.h"
|
||||
#include "TexturePoolOGL.h"
|
||||
#include "mozilla/layers/TextureHostOGL.h"
|
||||
|
||||
|
@ -29,11 +30,16 @@
|
|||
#include <memory>
|
||||
#include "mozilla/Compression.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/SHA1.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsISocketTransport.h"
|
||||
#include "nsIServerSocket.h"
|
||||
#include "nsReadLine.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
|
@ -52,13 +58,267 @@ using namespace mozilla::gl;
|
|||
using namespace mozilla;
|
||||
|
||||
class DebugDataSender;
|
||||
class DebugGLData;
|
||||
|
||||
static bool gDebugConnected = false;
|
||||
static nsCOMPtr<nsIServerSocket> gDebugServerSocket;
|
||||
static nsCOMPtr<nsIThread> gDebugSenderThread;
|
||||
static nsCOMPtr<nsISocketTransport> gDebugSenderTransport;
|
||||
static nsCOMPtr<nsIOutputStream> gDebugStream;
|
||||
static nsCOMPtr<DebugDataSender> gCurrentSender;
|
||||
/* This class handle websocket protocol which included
|
||||
* handshake and data frame's header
|
||||
*/
|
||||
class LayerScopeWebSocketHandler : public nsIInputStreamCallback {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
enum SocketStateType {
|
||||
NoHandshake,
|
||||
HandshakeSuccess,
|
||||
HandshakeFailed
|
||||
};
|
||||
|
||||
LayerScopeWebSocketHandler()
|
||||
: mState(NoHandshake)
|
||||
{ }
|
||||
|
||||
virtual ~LayerScopeWebSocketHandler()
|
||||
{
|
||||
if (mTransport) {
|
||||
mTransport->Close(NS_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenStream(nsISocketTransport* aTransport) {
|
||||
MOZ_ASSERT(aTransport);
|
||||
|
||||
mTransport = aTransport;
|
||||
mTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING,
|
||||
0,
|
||||
0,
|
||||
getter_AddRefs(mOutputStream));
|
||||
|
||||
nsCOMPtr<nsIInputStream> debugInputStream;
|
||||
mTransport->OpenInputStream(0,
|
||||
0,
|
||||
0,
|
||||
getter_AddRefs(debugInputStream));
|
||||
mInputStream = do_QueryInterface(debugInputStream);
|
||||
mInputStream->AsyncWait(this, 0, 0, NS_GetCurrentThread());
|
||||
}
|
||||
|
||||
bool WriteToStream(void *ptr, uint32_t size) {
|
||||
if (mState == NoHandshake) {
|
||||
// Not yet handshake, just return true in case of
|
||||
// LayerScope remove this handle
|
||||
return true;
|
||||
} else if (mState == HandshakeFailed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate WebSocket header
|
||||
uint8_t wsHeader[10];
|
||||
int wsHeaderSize = 0;
|
||||
const uint8_t opcode = 0x2;
|
||||
wsHeader[0] = 0x80 | (opcode & 0x0f); // FIN + opcode;
|
||||
if (size <= 125) {
|
||||
wsHeaderSize = 2;
|
||||
wsHeader[1] = size;
|
||||
} else if (size < 65536) {
|
||||
wsHeaderSize = 4;
|
||||
wsHeader[1] = 0x7E;
|
||||
NetworkEndian::writeUint16(wsHeader + 2, size);
|
||||
} else {
|
||||
wsHeaderSize = 10;
|
||||
wsHeader[1] = 0x7F;
|
||||
NetworkEndian::writeUint64(wsHeader + 2, size);
|
||||
}
|
||||
|
||||
// Send WebSocket header
|
||||
nsresult rv;
|
||||
uint32_t cnt;
|
||||
rv = mOutputStream->Write(reinterpret_cast<char*>(wsHeader),
|
||||
wsHeaderSize, &cnt);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
uint32_t written = 0;
|
||||
while (written < size) {
|
||||
uint32_t cnt;
|
||||
rv = mOutputStream->Write(reinterpret_cast<char*>(ptr) + written,
|
||||
size - written, &cnt);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
written += cnt;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// nsIInputStreamCallback
|
||||
NS_IMETHODIMP OnInputStreamReady(nsIAsyncInputStream *stream) MOZ_OVERRIDE
|
||||
{
|
||||
nsTArray<nsCString> protocolString;
|
||||
ReadInputStreamData(protocolString);
|
||||
|
||||
if (WebSocketHandshake(protocolString)) {
|
||||
mState = HandshakeSuccess;
|
||||
} else {
|
||||
mState = HandshakeFailed;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
void ReadInputStreamData(nsTArray<nsCString>& aProtocolString)
|
||||
{
|
||||
nsLineBuffer<char> lineBuffer;
|
||||
nsCString line;
|
||||
bool more = true;
|
||||
do {
|
||||
NS_ReadLine(mInputStream.get(), &lineBuffer, line, &more);
|
||||
|
||||
if (line.Length() > 0) {
|
||||
aProtocolString.AppendElement(line);
|
||||
}
|
||||
} while (more && line.Length() > 0);
|
||||
}
|
||||
|
||||
bool WebSocketHandshake(nsTArray<nsCString>& aProtocolString)
|
||||
{
|
||||
nsresult rv;
|
||||
bool isWebSocket = false;
|
||||
nsCString version;
|
||||
nsCString wsKey;
|
||||
nsCString protocol;
|
||||
|
||||
// Validate WebSocket client request.
|
||||
if (aProtocolString.Length() == 0)
|
||||
return false;
|
||||
|
||||
// Check that the HTTP method is GET
|
||||
const char* HTTP_METHOD = "GET ";
|
||||
if (strncmp(aProtocolString[0].get(), HTTP_METHOD, strlen(HTTP_METHOD)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 1; i < aProtocolString.Length(); ++i) {
|
||||
const char* line = aProtocolString[i].get();
|
||||
const char* prop_pos = strchr(line, ':');
|
||||
if (prop_pos != nullptr) {
|
||||
nsCString key(line, prop_pos - line);
|
||||
nsCString value(prop_pos + 2);
|
||||
if (key.EqualsIgnoreCase("upgrade") &&
|
||||
value.EqualsIgnoreCase("websocket")) {
|
||||
isWebSocket = true;
|
||||
} else if (key.EqualsIgnoreCase("sec-websocket-version")) {
|
||||
version = value;
|
||||
} else if (key.EqualsIgnoreCase("sec-websocket-key")) {
|
||||
wsKey = value;
|
||||
} else if (key.EqualsIgnoreCase("sec-websocket-protocol")) {
|
||||
protocol = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isWebSocket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(version.Equals("7") || version.Equals("8") || version.Equals("13"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(protocol.EqualsIgnoreCase("binary"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Client request is valid. Start to generate and send server response.
|
||||
nsAutoCString guid("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
nsAutoCString res;
|
||||
SHA1Sum sha1;
|
||||
nsCString combined(wsKey + guid);
|
||||
sha1.update(combined.get(), combined.Length());
|
||||
uint8_t digest[SHA1Sum::HashSize]; // SHA1 digests are 20 bytes long.
|
||||
sha1.finish(digest);
|
||||
nsCString newString(reinterpret_cast<char*>(digest), SHA1Sum::HashSize);
|
||||
Base64Encode(newString, res);
|
||||
|
||||
nsCString response("HTTP/1.1 101 Switching Protocols\r\n");
|
||||
response.Append("Upgrade: websocket\r\n");
|
||||
response.Append("Connection: Upgrade\r\n");
|
||||
response.Append(nsCString("Sec-WebSocket-Accept: ") + res + nsCString("\r\n"));
|
||||
response.Append("Sec-WebSocket-Protocol: binary\r\n\r\n");
|
||||
uint32_t written = 0;
|
||||
uint32_t size = response.Length();
|
||||
while (written < size) {
|
||||
uint32_t cnt;
|
||||
rv = mOutputStream->Write(const_cast<char*>(response.get()) + written,
|
||||
size - written, &cnt);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
written += cnt;
|
||||
}
|
||||
mOutputStream->Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
nsCOMPtr<nsIAsyncInputStream> mInputStream;
|
||||
nsCOMPtr<nsISocketTransport> mTransport;
|
||||
SocketStateType mState;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(LayerScopeWebSocketHandler, nsIInputStreamCallback);
|
||||
|
||||
class LayerScopeWebSocketManager {
|
||||
public:
|
||||
LayerScopeWebSocketManager();
|
||||
~LayerScopeWebSocketManager();
|
||||
|
||||
void AddConnection(nsISocketTransport *aTransport)
|
||||
{
|
||||
MOZ_ASSERT(aTransport);
|
||||
nsRefPtr<LayerScopeWebSocketHandler> temp = new LayerScopeWebSocketHandler();
|
||||
temp->OpenStream(aTransport);
|
||||
mHandlers.AppendElement(temp.get());
|
||||
}
|
||||
|
||||
void RemoveConnection(uint32_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(aIndex < mHandlers.Length());
|
||||
mHandlers.RemoveElementAt(aIndex);
|
||||
}
|
||||
|
||||
void RemoveAllConnections()
|
||||
{
|
||||
mHandlers.Clear();
|
||||
}
|
||||
|
||||
bool WriteAll(void *ptr, uint32_t size)
|
||||
{
|
||||
for (int32_t i = mHandlers.Length() - 1; i >= 0; --i) {
|
||||
if (!mHandlers[i]->WriteToStream(ptr, size)) {
|
||||
// Send failed, remove this handler
|
||||
RemoveConnection(i);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsConnected()
|
||||
{
|
||||
return (mHandlers.Length() != 0) ? true : false;
|
||||
}
|
||||
|
||||
void AppendDebugData(DebugGLData *aDebugData);
|
||||
void DispatchDebugData();
|
||||
private:
|
||||
nsTArray<nsRefPtr<LayerScopeWebSocketHandler> > mHandlers;
|
||||
nsCOMPtr<nsIThread> mDebugSenderThread;
|
||||
nsCOMPtr<DebugDataSender> mCurrentSender;
|
||||
nsCOMPtr<nsIServerSocket> mServerSocket;
|
||||
};
|
||||
|
||||
static StaticAutoPtr<LayerScopeWebSocketManager> gLayerScopeWebSocketManager;
|
||||
|
||||
class DebugGLData : public LinkedListElement<DebugGLData> {
|
||||
public:
|
||||
|
@ -111,19 +371,9 @@ public:
|
|||
}
|
||||
|
||||
static bool WriteToStream(void *ptr, uint32_t size) {
|
||||
uint32_t written = 0;
|
||||
nsresult rv;
|
||||
while (written < size) {
|
||||
uint32_t cnt;
|
||||
rv = gDebugStream->Write(reinterpret_cast<char*>(ptr) + written,
|
||||
size - written, &cnt);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
written += cnt;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!gLayerScopeWebSocketManager)
|
||||
return true;
|
||||
return gLayerScopeWebSocketManager->WriteAll(ptr, size);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -284,23 +534,15 @@ protected:
|
|||
static bool
|
||||
CheckSender()
|
||||
{
|
||||
if (!gDebugConnected)
|
||||
if (!gLayerScopeWebSocketManager)
|
||||
return false;
|
||||
|
||||
// At some point we may want to support sending
|
||||
// data in between frames.
|
||||
#if 1
|
||||
if (!gCurrentSender)
|
||||
if (!gLayerScopeWebSocketManager->IsConnected())
|
||||
return false;
|
||||
#else
|
||||
if (!gCurrentSender)
|
||||
gCurrentSender = new DebugDataSender();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
class DebugListener : public nsIServerSocketListener
|
||||
{
|
||||
public:
|
||||
|
@ -315,10 +557,11 @@ public:
|
|||
NS_IMETHODIMP OnSocketAccepted(nsIServerSocket *aServ,
|
||||
nsISocketTransport *aTransport)
|
||||
{
|
||||
if (!gLayerScopeWebSocketManager)
|
||||
return NS_OK;
|
||||
|
||||
printf_stderr("*** LayerScope: Accepted connection\n");
|
||||
gDebugConnected = true;
|
||||
gDebugSenderTransport = aTransport;
|
||||
aTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, 0, 0, getter_AddRefs(gDebugStream));
|
||||
gLayerScopeWebSocketManager->AddConnection(aTransport);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -368,13 +611,6 @@ public:
|
|||
DebugGLData *d;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// If we got closed while trying to write some stuff earlier, just
|
||||
// throw away everything.
|
||||
if (!gDebugStream) {
|
||||
Cleanup();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
while ((d = mList->popFirst()) != nullptr) {
|
||||
std::auto_ptr<DebugGLData> cleaner(d);
|
||||
if (!d->Write()) {
|
||||
|
@ -386,10 +622,7 @@ public:
|
|||
Cleanup();
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
gDebugSenderTransport->Close(rv);
|
||||
gDebugConnected = false;
|
||||
gDebugStream = nullptr;
|
||||
gDebugServerSocket = nullptr;
|
||||
LayerScope::DestroyServerSocket();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -408,30 +641,26 @@ LayerScope::CreateServerSocket()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!gDebugSenderThread) {
|
||||
NS_NewThread(getter_AddRefs(gDebugSenderThread));
|
||||
}
|
||||
|
||||
if (!gDebugServerSocket) {
|
||||
gDebugServerSocket = do_CreateInstance(NS_SERVERSOCKET_CONTRACTID);
|
||||
int port = Preferences::GetInt("gfx.layerscope.port", 23456);
|
||||
gDebugServerSocket->Init(port, false, -1);
|
||||
gDebugServerSocket->AsyncListen(new DebugListener);
|
||||
if (!gLayerScopeWebSocketManager) {
|
||||
gLayerScopeWebSocketManager = new LayerScopeWebSocketManager();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerScope::DestroyServerSocket()
|
||||
{
|
||||
gDebugConnected = false;
|
||||
gDebugStream = nullptr;
|
||||
gDebugServerSocket = nullptr;
|
||||
if (gLayerScopeWebSocketManager) {
|
||||
gLayerScopeWebSocketManager->RemoveAllConnections();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerScope::BeginFrame(GLContext* aGLContext, int64_t aFrameStamp)
|
||||
{
|
||||
if (!gDebugConnected)
|
||||
if (!gLayerScopeWebSocketManager)
|
||||
return;
|
||||
|
||||
if (!gLayerScopeWebSocketManager->IsConnected())
|
||||
return;
|
||||
|
||||
#if 0
|
||||
|
@ -442,8 +671,7 @@ LayerScope::BeginFrame(GLContext* aGLContext, int64_t aFrameStamp)
|
|||
}
|
||||
#endif
|
||||
|
||||
gCurrentSender = new DebugDataSender();
|
||||
gCurrentSender->Append(new DebugGLData(DebugGLData::FrameStart, aGLContext, aFrameStamp));
|
||||
gLayerScopeWebSocketManager->AppendDebugData(new DebugGLData(DebugGLData::FrameStart, aGLContext, aFrameStamp));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -452,9 +680,8 @@ LayerScope::EndFrame(GLContext* aGLContext)
|
|||
if (!CheckSender())
|
||||
return;
|
||||
|
||||
gCurrentSender->Append(new DebugGLData(DebugGLData::FrameEnd, aGLContext));
|
||||
gDebugSenderThread->Dispatch(gCurrentSender, NS_DISPATCH_NORMAL);
|
||||
gCurrentSender = nullptr;
|
||||
gLayerScopeWebSocketManager->AppendDebugData(new DebugGLData(DebugGLData::FrameEnd, aGLContext));
|
||||
gLayerScopeWebSocketManager->DispatchDebugData();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -463,7 +690,7 @@ SendColor(void* aLayerRef, const gfxRGBA& aColor, int aWidth, int aHeight)
|
|||
if (!CheckSender())
|
||||
return;
|
||||
|
||||
gCurrentSender->Append(
|
||||
gLayerScopeWebSocketManager->AppendDebugData(
|
||||
new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight));
|
||||
}
|
||||
|
||||
|
@ -500,7 +727,7 @@ SendTextureSource(GLContext* aGLContext,
|
|||
gfxIntSize(size.width, size.height),
|
||||
shaderProgram, aFlipY);
|
||||
|
||||
gCurrentSender->Append(
|
||||
gLayerScopeWebSocketManager->AppendDebugData(
|
||||
new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
|
||||
textureId, img));
|
||||
}
|
||||
|
@ -585,5 +812,34 @@ LayerScope::SendEffectChain(GLContext* aGLContext,
|
|||
// TODO:
|
||||
}
|
||||
|
||||
LayerScopeWebSocketManager::LayerScopeWebSocketManager()
|
||||
{
|
||||
NS_NewThread(getter_AddRefs(mDebugSenderThread));
|
||||
|
||||
mServerSocket = do_CreateInstance(NS_SERVERSOCKET_CONTRACTID);
|
||||
int port = Preferences::GetInt("gfx.layerscope.port", 23456);
|
||||
mServerSocket->Init(port, false, -1);
|
||||
mServerSocket->AsyncListen(new DebugListener);
|
||||
}
|
||||
|
||||
LayerScopeWebSocketManager::~LayerScopeWebSocketManager()
|
||||
{
|
||||
}
|
||||
|
||||
void LayerScopeWebSocketManager::AppendDebugData(DebugGLData *aDebugData)
|
||||
{
|
||||
if (!mCurrentSender) {
|
||||
mCurrentSender = new DebugDataSender();
|
||||
}
|
||||
|
||||
mCurrentSender->Append(aDebugData);
|
||||
}
|
||||
|
||||
void LayerScopeWebSocketManager::DispatchDebugData()
|
||||
{
|
||||
mDebugSenderThread->Dispatch(mCurrentSender, NS_DISPATCH_NORMAL);
|
||||
mCurrentSender = nullptr;
|
||||
}
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <pthread.h>
|
||||
#include <alloca.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -141,7 +142,9 @@ TLSInfoList;
|
|||
* methods or do large allocations on the stack to avoid stack overflow.
|
||||
*/
|
||||
#ifndef NUWA_STACK_SIZE
|
||||
#define NUWA_STACK_SIZE (1024 * 32)
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_ALIGN_MASK 0xfffff000
|
||||
#define NUWA_STACK_SIZE (1024 * 128)
|
||||
#endif
|
||||
|
||||
#define NATIVE_THREAD_NAME_LENGTH 16
|
||||
|
@ -489,7 +492,18 @@ thread_info_new(void) {
|
|||
tinfo->recreatedThreadID = 0;
|
||||
tinfo->recreatedNativeThreadID = 0;
|
||||
tinfo->reacquireMutex = nullptr;
|
||||
tinfo->stk = malloc(NUWA_STACK_SIZE);
|
||||
tinfo->stk = malloc(NUWA_STACK_SIZE + PAGE_SIZE);
|
||||
|
||||
// We use a smaller stack size. Add protection to stack overflow: mprotect()
|
||||
// stack top (the page at the lowest address) so we crash instead of corrupt
|
||||
// other content that is malloc()'d.
|
||||
unsigned long long pageGuard = ((unsigned long long)tinfo->stk);
|
||||
pageGuard &= PAGE_ALIGN_MASK;
|
||||
if (pageGuard != (unsigned long long) tinfo->stk) {
|
||||
pageGuard += PAGE_SIZE; // Round up to be page-aligned.
|
||||
}
|
||||
mprotect((void*)pageGuard, PAGE_SIZE, PROT_READ);
|
||||
|
||||
pthread_attr_init(&tinfo->threadAttr);
|
||||
|
||||
REAL(pthread_mutex_lock)(&sThreadCountLock);
|
||||
|
|
|
@ -56,7 +56,7 @@ function truncate(text, newLength = kTruncateLength) {
|
|||
}
|
||||
}
|
||||
|
||||
function getMessage(error) {
|
||||
function getMessage(error, prefix = "") {
|
||||
let actual, expected;
|
||||
// Wrap calls to JSON.stringify in try...catch blocks, as they may throw. If
|
||||
// so, fall back to toString().
|
||||
|
@ -70,8 +70,12 @@ function getMessage(error) {
|
|||
} catch (ex) {
|
||||
expected = Object.prototype.toString.call(error.expected);
|
||||
}
|
||||
return truncate(actual) + " " + (error.operator ? error.operator + " " : "") +
|
||||
truncate(expected);
|
||||
let message = prefix;
|
||||
if (error.operator) {
|
||||
message += (prefix ? " - " : "") + truncate(actual) + " " + error.operator +
|
||||
" " + truncate(expected);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,7 +99,7 @@ Assert.AssertionError = function(options) {
|
|||
this.actual = options.actual;
|
||||
this.expected = options.expected;
|
||||
this.operator = options.operator;
|
||||
this.message = options.message || getMessage(this);
|
||||
this.message = getMessage(this, options.message);
|
||||
// The part of the stack that comes from this module is not interesting.
|
||||
let stack = Components.stack;
|
||||
do {
|
||||
|
|
|
@ -276,7 +276,7 @@ function run_test() {
|
|||
try {
|
||||
assert.equal(1, 2, "oh no");
|
||||
} catch (e) {
|
||||
assert.equal(e.toString().split("\n")[0], "AssertionError: oh no")
|
||||
assert.equal(e.toString().split("\n")[0], "AssertionError: oh no - 1 == 2")
|
||||
}
|
||||
|
||||
// Export Assert.jsm methods to become globally accessible.
|
||||
|
|
Загрузка…
Ссылка в новой задаче