This commit is contained in:
Ryan VanderMeulen 2014-02-10 15:43:52 -05:00
Родитель a9b2832ad1 d2ef169276
Коммит d96528f975
34 изменённых файлов: 881 добавлений и 282 удалений

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

@ -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.