mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to b2g-inbound.
This commit is contained in:
commit
41ac0e7e12
1
.hgtags
1
.hgtags
@ -104,3 +104,4 @@ ba2cc1eda988a1614d8986ae145d28e1268409b9 Tagging for mozilla-central version bum
|
||||
ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE-m
|
||||
0000000000000000000000000000000000000000 FIREFOX_AURORA_29_BASE-m
|
||||
ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE
|
||||
9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
|
||||
|
@ -13,7 +13,7 @@ ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/
|
||||
ac_add_options --disable-elf-hack
|
||||
ac_add_options --enable-debug-symbols
|
||||
ac_add_options --enable-debug
|
||||
#ac_add_options --with-ccache
|
||||
#. "$topsrcdir/build/mozconfig.cache"
|
||||
ENABLE_MARIONETTE=1
|
||||
|
||||
# Enable dump() from JS.
|
||||
|
@ -14,7 +14,7 @@ ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/
|
||||
ac_add_options --disable-elf-hack
|
||||
ac_add_options --enable-debug-symbols
|
||||
# ac_add_options --enable-profiling
|
||||
#ac_add_options --with-ccache
|
||||
#. "$topsrcdir/build/mozconfig.cache"
|
||||
ENABLE_MARIONETTE=1
|
||||
|
||||
# Enable dump() from JS.
|
||||
|
@ -22,7 +22,7 @@ export MOZ_TELEMETRY_REPORTING=1
|
||||
# DISABLED WHILE NOT ON TRY ac_add_options --enable-warnings-as-errors
|
||||
|
||||
# Use ccache
|
||||
ac_add_options --with-ccache=/usr/bin/ccache
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
#B2G options
|
||||
ac_add_options --enable-application=b2g
|
||||
|
@ -22,7 +22,7 @@ export MOZ_TELEMETRY_REPORTING=1
|
||||
# DISABLED WHILE NOT ON TRY ac_add_options --enable-warnings-as-errors
|
||||
|
||||
# Use ccache
|
||||
ac_add_options --with-ccache=/usr/bin/ccache
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
#B2G options
|
||||
ac_add_options --enable-application=b2g
|
||||
|
@ -20,7 +20,7 @@ ac_add_options --enable-warnings-as-errors
|
||||
# B2G Stuff
|
||||
ac_add_options --enable-application=b2g
|
||||
ac_add_options --enable-debug-symbols
|
||||
ac_add_options --with-ccache
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
ENABLE_MARIONETTE=1
|
||||
|
||||
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||
|
@ -195,8 +195,12 @@ let gFxAccounts = {
|
||||
},
|
||||
|
||||
onMenuPanelCommand: function (event) {
|
||||
if (event.originalTarget.hasAttribute("signedin")) {
|
||||
let button = event.originalTarget;
|
||||
|
||||
if (button.hasAttribute("signedin")) {
|
||||
this.openPreferences();
|
||||
} else if (button.hasAttribute("failed")) {
|
||||
this.openSignInAgainPage();
|
||||
} else {
|
||||
this.openAccountsPage();
|
||||
}
|
||||
|
@ -30,6 +30,13 @@
|
||||
<menupopup id="customization-toolbar-menu" onpopupshowing="onViewToolbarsPopupShowing(event)"/>
|
||||
</button>
|
||||
<spacer flex="1"/>
|
||||
<label id="customization-undo-reset"
|
||||
hidden="true"
|
||||
onclick="gCustomizeMode.undoReset();"
|
||||
onkeypress="gCustomizeMode.undoReset();"
|
||||
class="text-link">
|
||||
&undoCmd.label;
|
||||
</label>
|
||||
<button id="customization-reset-button" oncommand="gCustomizeMode.reset();" label="&customizeMode.restoreDefaults;" class="customizationmode-button"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
@ -174,13 +174,6 @@
|
||||
this.setAttribute("viewtype", "main");
|
||||
}
|
||||
|
||||
this._mainViewObserver.observe(this._mainView, {
|
||||
attributes: true,
|
||||
characterData: true,
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
this._shiftMainView();
|
||||
]]></body>
|
||||
</method>
|
||||
@ -289,7 +282,21 @@
|
||||
break;
|
||||
case "popupshowing":
|
||||
this.setAttribute("panelopen", "true");
|
||||
// Bug 941196 - The panel can get taller when opening a subview. Disabling
|
||||
// autoPositioning means that the panel won't jump around if an opened
|
||||
// subview causes the panel to exceed the dimensions of the screen in the
|
||||
// direction that the panel originally opened in. This property resets
|
||||
// every time the popup closes, which is why we have to set it each time.
|
||||
this._panel.autoPosition = false;
|
||||
this._syncContainerWithMainView();
|
||||
|
||||
this._mainViewObserver.observe(this._mainView, {
|
||||
attributes: true,
|
||||
characterData: true,
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
break;
|
||||
case "popupshown":
|
||||
this._setMaxHeight();
|
||||
@ -298,6 +305,7 @@
|
||||
this.removeAttribute("panelopen");
|
||||
this._mainView.style.removeProperty("height");
|
||||
this.showMainView();
|
||||
this._mainViewObserver.disconnect();
|
||||
break;
|
||||
}
|
||||
]]></body>
|
||||
|
@ -128,6 +128,8 @@ let gGroupWrapperCache = new Map();
|
||||
let gSingleWrapperCache = new WeakMap();
|
||||
let gListeners = new Set();
|
||||
|
||||
let gUIStateBeforeReset = null;
|
||||
|
||||
let gModuleName = "[CustomizableUI]";
|
||||
#include logging.js
|
||||
|
||||
@ -693,6 +695,10 @@ let CustomizableUIInternal = {
|
||||
|
||||
onWidgetAdded: function(aWidgetId, aArea, aPosition) {
|
||||
this.insertNode(aWidgetId, aArea, aPosition, true);
|
||||
|
||||
if (!gResetting) {
|
||||
gUIStateBeforeReset = null;
|
||||
}
|
||||
},
|
||||
|
||||
onWidgetRemoved: function(aWidgetId, aArea) {
|
||||
@ -749,10 +755,20 @@ let CustomizableUIInternal = {
|
||||
windowCache.delete(aWidgetId);
|
||||
}
|
||||
}
|
||||
if (!gResetting) {
|
||||
gUIStateBeforeReset = null;
|
||||
}
|
||||
},
|
||||
|
||||
onWidgetMoved: function(aWidgetId, aArea, aOldPosition, aNewPosition) {
|
||||
this.insertNode(aWidgetId, aArea, aNewPosition);
|
||||
if (!gResetting) {
|
||||
gUIStateBeforeReset = null;
|
||||
}
|
||||
},
|
||||
|
||||
onCustomizeEnd: function(aWindow) {
|
||||
gUIStateBeforeReset = null;
|
||||
},
|
||||
|
||||
registerBuildArea: function(aArea, aNode) {
|
||||
@ -2049,6 +2065,20 @@ let CustomizableUIInternal = {
|
||||
|
||||
reset: function() {
|
||||
gResetting = true;
|
||||
this._resetUIState();
|
||||
|
||||
// Rebuild each registered area (across windows) to reflect the state that
|
||||
// was reset above.
|
||||
this._rebuildRegisteredAreas();
|
||||
|
||||
gResetting = false;
|
||||
},
|
||||
|
||||
_resetUIState: function() {
|
||||
try {
|
||||
gUIStateBeforeReset = Services.prefs.getCharPref(kPrefCustomizationState);
|
||||
} catch(e) { }
|
||||
|
||||
Services.prefs.clearUserPref(kPrefCustomizationState);
|
||||
LOG("State reset");
|
||||
|
||||
@ -2062,9 +2092,9 @@ let CustomizableUIInternal = {
|
||||
for (let [areaId,] of gAreas) {
|
||||
this.restoreStateForArea(areaId);
|
||||
}
|
||||
},
|
||||
|
||||
// Rebuild each registered area (across windows) to reflect the state that
|
||||
// was reset above.
|
||||
_rebuildRegisteredAreas: function() {
|
||||
for (let [areaId, areaNodes] of gBuildAreas) {
|
||||
let placements = gPlacements.get(areaId);
|
||||
for (let areaNode of areaNodes) {
|
||||
@ -2078,7 +2108,23 @@ let CustomizableUIInternal = {
|
||||
}
|
||||
}
|
||||
}
|
||||
gResetting = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Undoes a previous reset, restoring the state of the UI to the state prior to the reset.
|
||||
*/
|
||||
undoReset: function() {
|
||||
if (!gUIStateBeforeReset) {
|
||||
return;
|
||||
}
|
||||
Services.prefs.setCharPref(kPrefCustomizationState, gUIStateBeforeReset);
|
||||
this.loadSavedState();
|
||||
for (let areaId of Object.keys(gSavedState.placements)) {
|
||||
let placements = gSavedState.placements[areaId];
|
||||
gPlacements.set(areaId, placements);
|
||||
}
|
||||
this._rebuildRegisteredAreas();
|
||||
gUIStateBeforeReset = null;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2832,6 +2878,25 @@ this.CustomizableUI = {
|
||||
reset: function() {
|
||||
CustomizableUIInternal.reset();
|
||||
},
|
||||
|
||||
/**
|
||||
* Undo the previous reset, can only be called immediately after a reset.
|
||||
* @return a promise that will be resolved when the operation is complete.
|
||||
*/
|
||||
undoReset: function() {
|
||||
CustomizableUIInternal.undoReset();
|
||||
},
|
||||
|
||||
/**
|
||||
* Can the last Restore Defaults operation be undone.
|
||||
*
|
||||
* @return A boolean stating whether an undo of the
|
||||
* Restore Defaults can be performed.
|
||||
*/
|
||||
get canUndoReset() {
|
||||
return !!gUIStateBeforeReset;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the placement of a widget. This is by far the best way to obtain
|
||||
* information about what the state of your widget is. The internals of
|
||||
|
@ -239,6 +239,7 @@ CustomizeMode.prototype = {
|
||||
document.getElementById("PanelUI-quit").setAttribute("disabled", true);
|
||||
|
||||
this._updateResetButton();
|
||||
this._updateUndoResetButton();
|
||||
|
||||
this._skipSourceNodeCheck = Services.prefs.getPrefType(kSkipSourceNodePref) == Ci.nsIPrefBranch.PREF_BOOL &&
|
||||
Services.prefs.getBoolPref(kSkipSourceNodePref);
|
||||
@ -854,12 +855,35 @@ CustomizeMode.prototype = {
|
||||
this.persistCurrentSets(true);
|
||||
|
||||
this._updateResetButton();
|
||||
this._updateUndoResetButton();
|
||||
this._updateEmptyPaletteNotice();
|
||||
this._showPanelCustomizationPlaceholders();
|
||||
this.resetting = false;
|
||||
}.bind(this)).then(null, ERROR);
|
||||
},
|
||||
|
||||
undoReset: function() {
|
||||
this.resetting = true;
|
||||
|
||||
return Task.spawn(function() {
|
||||
this._removePanelCustomizationPlaceholders();
|
||||
yield this.depopulatePalette();
|
||||
yield this._unwrapToolbarItems();
|
||||
|
||||
CustomizableUI.undoReset();
|
||||
|
||||
yield this._wrapToolbarItems();
|
||||
yield this.populatePalette();
|
||||
|
||||
this.persistCurrentSets(true);
|
||||
|
||||
this._updateResetButton();
|
||||
this._updateUndoResetButton();
|
||||
this._updateEmptyPaletteNotice();
|
||||
this.resetting = false;
|
||||
}.bind(this)).then(null, ERROR);
|
||||
},
|
||||
|
||||
_onToolbarVisibilityChange: function(aEvent) {
|
||||
let toolbar = aEvent.target;
|
||||
if (aEvent.detail.visible && toolbar.getAttribute("customizable") == "true") {
|
||||
@ -958,6 +982,7 @@ CustomizeMode.prototype = {
|
||||
this._changed = true;
|
||||
if (!this.resetting) {
|
||||
this._updateResetButton();
|
||||
this._updateUndoResetButton();
|
||||
this._updateEmptyPaletteNotice();
|
||||
}
|
||||
this.dispatchToolboxEvent("customizationchange");
|
||||
@ -973,6 +998,11 @@ CustomizeMode.prototype = {
|
||||
btn.disabled = CustomizableUI.inDefaultState;
|
||||
},
|
||||
|
||||
_updateUndoResetButton: function() {
|
||||
let undoReset = this.document.getElementById("customization-undo-reset");
|
||||
undoReset.hidden = !CustomizableUI.canUndoReset;
|
||||
},
|
||||
|
||||
handleEvent: function(aEvent) {
|
||||
switch(aEvent.type) {
|
||||
case "toolbarvisibilitychange":
|
||||
|
@ -65,4 +65,5 @@ skip-if = os == "linux"
|
||||
[browser_956602_remove_special_widget.js]
|
||||
[browser_969427_recreate_destroyed_widget_after_reset.js]
|
||||
[browser_969661_character_encoding_navbar_disabled.js]
|
||||
[browser_970511_undo_restore_default.js]
|
||||
[browser_panel_toggle.js]
|
||||
|
@ -0,0 +1,65 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Restoring default should show an "undo" option which undoes the restoring operation.
|
||||
add_task(function() {
|
||||
let homeButtonId = "home-button";
|
||||
CustomizableUI.removeWidgetFromArea(homeButtonId);
|
||||
yield startCustomizing();
|
||||
ok(!CustomizableUI.inDefaultState, "Not in default state to begin with");
|
||||
is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
|
||||
let undoReset = document.getElementById("customization-undo-reset");
|
||||
is(undoReset.hidden, true, "The undo button is hidden before reset");
|
||||
|
||||
yield gCustomizeMode.reset();
|
||||
|
||||
ok(CustomizableUI.inDefaultState, "In default state after reset");
|
||||
is(undoReset.hidden, false, "The undo button is visible after reset");
|
||||
|
||||
undoReset.click();
|
||||
yield waitForCondition(function() !gCustomizeMode.resetting);
|
||||
ok(!CustomizableUI.inDefaultState, "Not in default state after reset-undo");
|
||||
is(undoReset.hidden, true, "The undo button is hidden after clicking on the undo button");
|
||||
is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
|
||||
|
||||
yield gCustomizeMode.reset();
|
||||
});
|
||||
|
||||
// Performing an action after a reset will hide the reset button.
|
||||
add_task(function() {
|
||||
let homeButtonId = "home-button";
|
||||
CustomizableUI.removeWidgetFromArea(homeButtonId);
|
||||
ok(!CustomizableUI.inDefaultState, "Not in default state to begin with");
|
||||
is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
|
||||
let undoReset = document.getElementById("customization-undo-reset");
|
||||
is(undoReset.hidden, true, "The undo button is hidden before reset");
|
||||
|
||||
yield gCustomizeMode.reset();
|
||||
|
||||
ok(CustomizableUI.inDefaultState, "In default state after reset");
|
||||
is(undoReset.hidden, false, "The undo button is visible after reset");
|
||||
|
||||
CustomizableUI.addWidgetToArea(homeButtonId, CustomizableUI.AREA_PANEL);
|
||||
is(undoReset.hidden, true, "The undo button is hidden after another change");
|
||||
});
|
||||
|
||||
// "Restore defaults", exiting customize, and re-entering shouldn't show the Undo button
|
||||
add_task(function() {
|
||||
let undoReset = document.getElementById("customization-undo-reset");
|
||||
is(undoReset.hidden, true, "The undo button is hidden before a reset");
|
||||
ok(!CustomizableUI.inDefaultState, "The browser should not be in default state");
|
||||
yield gCustomizeMode.reset();
|
||||
|
||||
is(undoReset.hidden, false, "The undo button is hidden after a reset");
|
||||
yield endCustomizing();
|
||||
yield startCustomizing();
|
||||
is(undoReset.hidden, true, "The undo reset button should be hidden after entering customization mode");
|
||||
});
|
||||
|
||||
add_task(function asyncCleanup() {
|
||||
yield gCustomizeMode.reset();
|
||||
yield endCustomizing();
|
||||
});
|
@ -10,7 +10,7 @@ ac_add_options --disable-unified-compilation
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
#Use ccache
|
||||
ac_add_options --with-ccache=/usr/bin/ccache
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
|
||||
ac_add_options --enable-warnings-as-errors
|
||||
|
@ -13,6 +13,6 @@ ac_add_options --enable-js-diagnostics
|
||||
STRIP_FLAGS="--strip-debug"
|
||||
|
||||
# Use ccache
|
||||
ac_add_options --with-ccache=/usr/bin/ccache
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
. "$topsrcdir/build/mozconfig.common.override"
|
||||
|
@ -8,7 +8,7 @@ ac_add_options --enable-signmar
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
# Use ccache
|
||||
ac_add_options --with-ccache=/usr/bin/ccache
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
|
||||
ac_add_options --enable-warnings-as-errors
|
||||
|
@ -13,6 +13,6 @@ ac_add_options --enable-js-diagnostics
|
||||
STRIP_FLAGS="--strip-debug"
|
||||
|
||||
# Use ccache
|
||||
ac_add_options --with-ccache=/usr/bin/ccache
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
. "$topsrcdir/build/mozconfig.common.override"
|
||||
|
@ -4,7 +4,7 @@ ac_add_options --with-l10n-base=../../../l10n
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --with-macbundlename-prefix=Firefox
|
||||
ac_add_options --with-ccache
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
|
@ -3,6 +3,6 @@
|
||||
ac_add_options --with-l10n-base=../../l10n
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --with-ccache
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
. "$topsrcdir/build/mozconfig.common.override"
|
||||
|
@ -29,6 +29,7 @@ whitelist['nightly']['linux32'] += [
|
||||
'CC="ccache $REAL_CC"',
|
||||
'mk_add_options PROFILE_GEN_SCRIPT=@TOPSRCDIR@/build/profile_pageloader.pl',
|
||||
'ac_add_options --with-ccache=/usr/bin/ccache',
|
||||
'. "$topsrcdir/build/mozconfig.cache"',
|
||||
'export MOZILLA_OFFICIAL=1',
|
||||
'export MOZ_TELEMETRY_REPORTING=1',
|
||||
"mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
|
||||
@ -42,6 +43,7 @@ whitelist['nightly']['linux64'] += [
|
||||
"mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
|
||||
'STRIP_FLAGS="--strip-debug"',
|
||||
'ac_add_options --with-ccache=/usr/bin/ccache',
|
||||
'. "$topsrcdir/build/mozconfig.cache"',
|
||||
'ac_add_options --disable-elf-hack # --enable-elf-hack conflicts with --enable-profiling',
|
||||
]
|
||||
|
||||
@ -49,6 +51,7 @@ whitelist['nightly']['macosx-universal'] += [
|
||||
'ac_add_options --with-macbundlename-prefix=Firefox',
|
||||
'mk_add_options MOZ_MAKE_FLAGS="-j12"',
|
||||
'ac_add_options --with-ccache',
|
||||
'. "$topsrcdir/build/mozconfig.cache"',
|
||||
'ac_add_options --disable-install-strip',
|
||||
'ac_add_options --enable-instruments',
|
||||
'ac_add_options --enable-dtrace',
|
||||
|
@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"size": 40,
|
||||
"digest": "459b332864aece4742cd1a6886e56cf3f202e5c27bb481cfae6145ce3e2e52fb34d1448788c6618e58a26a64e415341895326d293e0d2968e56efc0ae990acd0",
|
||||
"size": 81,
|
||||
"digest": "59002eae04fa3534df3bbb0026dff50d3872313551514f9ccdf33080c8b8e34a6295b3b6f2c078b3ddef099023897a42adb65d34c9364f84dac5b8e7d022bf39",
|
||||
"algorithm": "sha512",
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
@ -10,5 +10,11 @@
|
||||
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz"
|
||||
},
|
||||
{
|
||||
"size": 150816,
|
||||
"digest": "af25ecf03b65795d21f011939984b130db167a4efc4f306700f373854f9d7ae664662cb7812c3d737eace7f3735324daa6eb540b5e42f90189b0d9a8dd5f4c9f",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.xz"
|
||||
}
|
||||
]
|
||||
|
@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"size": 40,
|
||||
"digest": "459b332864aece4742cd1a6886e56cf3f202e5c27bb481cfae6145ce3e2e52fb34d1448788c6618e58a26a64e415341895326d293e0d2968e56efc0ae990acd0",
|
||||
"size": 81,
|
||||
"digest": "59002eae04fa3534df3bbb0026dff50d3872313551514f9ccdf33080c8b8e34a6295b3b6f2c078b3ddef099023897a42adb65d34c9364f84dac5b8e7d022bf39",
|
||||
"algorithm": "sha512",
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
@ -10,5 +10,11 @@
|
||||
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz"
|
||||
},
|
||||
{
|
||||
"size": 150816,
|
||||
"digest": "af25ecf03b65795d21f011939984b130db167a4efc4f306700f373854f9d7ae664662cb7812c3d737eace7f3735324daa6eb540b5e42f90189b0d9a8dd5f4c9f",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.xz"
|
||||
}
|
||||
]
|
||||
|
@ -240,7 +240,11 @@ let DebuggerController = {
|
||||
} else {
|
||||
this._startDebuggingTab(startedDebugging.resolve);
|
||||
const startedTracing = promise.defer();
|
||||
this._startTracingTab(traceActor, startedTracing.resolve);
|
||||
if (Prefs.tracerEnabled && traceActor) {
|
||||
this._startTracingTab(traceActor, startedTracing.resolve);
|
||||
} else {
|
||||
startedTracing.resolve();
|
||||
}
|
||||
|
||||
return promise.all([startedDebugging.promise, startedTracing.promise]);
|
||||
}
|
||||
|
@ -214,6 +214,7 @@ support-files =
|
||||
[browser_dbg_tracing-03.js]
|
||||
[browser_dbg_tracing-04.js]
|
||||
[browser_dbg_tracing-05.js]
|
||||
[browser_dbg_tracing-06.js]
|
||||
[browser_dbg_variables-view-01.js]
|
||||
[browser_dbg_variables-view-02.js]
|
||||
[browser_dbg_variables-view-03.js]
|
||||
|
39
browser/devtools/debugger/test/browser_dbg_tracing-06.js
Normal file
39
browser/devtools/debugger/test/browser_dbg_tracing-06.js
Normal file
@ -0,0 +1,39 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test that the tracer doesn't connect to the backend when tracing is disabled.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_tracing-01.html";
|
||||
const TRACER_PREF = "devtools.debugger.tracer";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gOriginalPref = Services.prefs.getBoolPref(TRACER_PREF);
|
||||
Services.prefs.setBoolPref(TRACER_PREF, false);
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
|
||||
waitForSourceShown(gPanel, "code_tracing-01.js")
|
||||
.then(() => {
|
||||
ok(!gDebugger.DebuggerController.traceClient, "Should not have a trace client");
|
||||
closeDebuggerAndFinish(gPanel);
|
||||
})
|
||||
.then(null, aError => {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
Services.prefs.setBoolPref(TRACER_PREF, gOriginalPref);
|
||||
});
|
@ -13,8 +13,10 @@ support-files =
|
||||
# Bug 916763 - too many intermittent failures
|
||||
skip-if = true
|
||||
[browser_inspector_markup_edit.js]
|
||||
# Bug 904953 - too many intermittent failures on Linux
|
||||
skip-if = os == "linux"
|
||||
[browser_inspector_markup_edit_2.js]
|
||||
[browser_inspector_markup_edit_3.js]
|
||||
[browser_inspector_markup_edit_4.js]
|
||||
[browser_inspector_markup_add_attributes.js]
|
||||
[browser_inspector_markup_edit_outerhtml.js]
|
||||
[browser_inspector_markup_edit_outerhtml2.js]
|
||||
[browser_inspector_markup_mutation.js]
|
||||
|
@ -0,0 +1,170 @@
|
||||
/* Any copyright", " is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests that adding various types of attributes to nodes in the markup-view
|
||||
* works as expected. Also checks that the changes are properly undoable and
|
||||
* redoable. For each step in the test, we:
|
||||
* - Create a new DIV
|
||||
* - Make the change, check that the change was made as we expect
|
||||
* - Undo the change, check that the node is back in its original state
|
||||
* - Redo the change, check that the node change was made again correctly.
|
||||
*/
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let TEST_URL = "data:text/html,<div>markup-view attributes addition test</div>";
|
||||
let TEST_DATA = [{
|
||||
desc: "Add an attribute value without closing \"",
|
||||
enteredText: 'style="display: block;',
|
||||
expectedAttributes: {
|
||||
style: "display: block;"
|
||||
}
|
||||
}, {
|
||||
desc: "Add an attribute value without closing '",
|
||||
enteredText: "style='display: inline;",
|
||||
expectedAttributes: {
|
||||
style: "display: inline;"
|
||||
}
|
||||
}, {
|
||||
desc: "Add an attribute wrapped with with double quotes double quote in it",
|
||||
enteredText: 'style="display: "inline',
|
||||
expectedAttributes: {
|
||||
style: "display: ",
|
||||
inline: ""
|
||||
}
|
||||
}, {
|
||||
desc: "Add an attribute wrapped with single quotes with single quote in it",
|
||||
enteredText: "style='display: 'inline",
|
||||
expectedAttributes: {
|
||||
style: "display: ",
|
||||
inline: ""
|
||||
}
|
||||
}, {
|
||||
desc: "Add an attribute with no value",
|
||||
enteredText: "disabled",
|
||||
expectedAttributes: {
|
||||
disabled: ""
|
||||
}
|
||||
}, {
|
||||
desc: "Add multiple attributes with no value",
|
||||
enteredText: "disabled autofocus",
|
||||
expectedAttributes: {
|
||||
disabled: "",
|
||||
autofocus: ""
|
||||
}
|
||||
}, {
|
||||
desc: "Add multiple attributes with no value, and some with value",
|
||||
enteredText: "disabled name='name' data-test='test' autofocus",
|
||||
expectedAttributes: {
|
||||
disabled: "",
|
||||
autofocus: "",
|
||||
name: "name",
|
||||
'data-test': "test"
|
||||
}
|
||||
}, {
|
||||
desc: "Add attribute with xmlns",
|
||||
enteredText: "xmlns:edi='http://ecommerce.example.org/schema'",
|
||||
expectedAttributes: {
|
||||
'xmlns:edi': "http://ecommerce.example.org/schema"
|
||||
}
|
||||
}, {
|
||||
desc: "Mixed single and double quotes",
|
||||
enteredText: "name=\"hi\" maxlength='not a number'",
|
||||
expectedAttributes: {
|
||||
maxlength: "not a number",
|
||||
name: "hi"
|
||||
}
|
||||
}, {
|
||||
desc: "Invalid attribute name",
|
||||
enteredText: "x='y' <why-would-you-do-this>=\"???\"",
|
||||
expectedAttributes: {
|
||||
x: "y"
|
||||
}
|
||||
}, {
|
||||
desc: "Double quote wrapped in single quotes",
|
||||
enteredText: "x='h\"i'",
|
||||
expectedAttributes: {
|
||||
x: "h\"i"
|
||||
}
|
||||
}, {
|
||||
desc: "Single quote wrapped in double quotes",
|
||||
enteredText: "x=\"h'i\"",
|
||||
expectedAttributes: {
|
||||
x: "h'i"
|
||||
}
|
||||
}, {
|
||||
desc: "No quote wrapping",
|
||||
enteredText: "a=b x=y data-test=Some spaced data",
|
||||
expectedAttributes: {
|
||||
a: "b",
|
||||
x: "y",
|
||||
"data-test": "Some",
|
||||
spaced: "",
|
||||
data: ""
|
||||
}
|
||||
}, {
|
||||
desc: "Duplicate Attributes",
|
||||
enteredText: "a=b a='c' a=\"d\"",
|
||||
expectedAttributes: {
|
||||
a: "b"
|
||||
}
|
||||
}, {
|
||||
desc: "Inline styles",
|
||||
enteredText: "style=\"font-family: 'Lucida Grande', sans-serif; font-size: 75%;\"",
|
||||
expectedAttributes: {
|
||||
style: "font-family: 'Lucida Grande', sans-serif; font-size: 75%;"
|
||||
}
|
||||
}, {
|
||||
desc: "Object attribute names",
|
||||
enteredText: "toString=\"true\" hasOwnProperty=\"false\"",
|
||||
expectedAttributes: {
|
||||
toString: "true",
|
||||
hasOwnProperty: "false"
|
||||
}
|
||||
}, {
|
||||
desc: "Add event handlers",
|
||||
enteredText: "onclick=\"javascript: throw new Error('wont fire');\" onload=\"alert('here');\"",
|
||||
expectedAttributes: {
|
||||
onclick: "javascript: throw new Error('wont fire');",
|
||||
onload: "alert('here');"
|
||||
}
|
||||
}];
|
||||
|
||||
function test() {
|
||||
Task.spawn(function() {
|
||||
info("Opening the inspector on the test URL");
|
||||
let args = yield addTab(TEST_URL).then(openInspector);
|
||||
let inspector = args.inspector;
|
||||
let markup = inspector.markup;
|
||||
|
||||
info("Selecting the test node");
|
||||
let div = getNode("div");
|
||||
yield selectNode(div, inspector);
|
||||
let editor = getContainerForRawNode(markup, div).editor;
|
||||
|
||||
for (let test of TEST_DATA) {
|
||||
info("Starting test: " + test.desc);
|
||||
|
||||
info("Enter the new attribute(s) test: " + test.enteredText);
|
||||
let nodeMutated = inspector.once("markupmutation");
|
||||
setEditableFieldValue(editor.newAttr, test.enteredText, inspector);
|
||||
yield nodeMutated;
|
||||
|
||||
info("Assert that the attribute(s) has/have been applied correctly");
|
||||
assertAttributes(div, test.expectedAttributes);
|
||||
|
||||
info("Undo the change");
|
||||
yield undoChange(inspector);
|
||||
|
||||
info("Assert that the attribute(s) has/have been removed correctly");
|
||||
assertAttributes(div, {});
|
||||
}
|
||||
|
||||
yield inspector.once("inspector-updated");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
}).then(null, ok.bind(null, false)).then(finish);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,51 @@
|
||||
/* Any copyright", " is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests that an existing attribute can be modified
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
const TEST_URL = "data:text/html,<div id='test-div'>Test modifying my ID attribute</div>";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function() {
|
||||
info("Opening the inspector on the test page");
|
||||
let {toolbox, inspector} = yield addTab(TEST_URL).then(openInspector);
|
||||
|
||||
info("Selecting the test node");
|
||||
let node = content.document.getElementById("test-div");
|
||||
yield selectNode(node, inspector);
|
||||
|
||||
info("Verify attributes, only ID should be there for now");
|
||||
assertAttributes(node, {
|
||||
id: "test-div"
|
||||
});
|
||||
|
||||
info("Focus the ID attribute and change its content");
|
||||
let editor = getContainerForRawNode(inspector.markup, node).editor;
|
||||
let attr = editor.attrs["id"].querySelector(".editable");
|
||||
let mutated = inspector.once("markupmutation");
|
||||
setEditableFieldValue(attr,
|
||||
attr.textContent + ' class="newclass" style="color:green"', inspector);
|
||||
yield mutated;
|
||||
|
||||
info("Verify attributes, should have ID, class and style");
|
||||
assertAttributes(node, {
|
||||
id: "test-div",
|
||||
class: "newclass",
|
||||
style: "color:green"
|
||||
});
|
||||
|
||||
info("Trying to undo the change");
|
||||
yield undoChange(inspector);
|
||||
assertAttributes(node, {
|
||||
id: "test-div"
|
||||
});
|
||||
|
||||
yield inspector.once("inspector-updated");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
}).then(null, ok.bind(null, false)).then(finish);
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/* Any copyright", " is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests that a node's tagname can be edited in the markup-view
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
const TEST_URL = "data:text/html,<div id='retag-me'><div id='retag-me-2'></div></div>";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function() {
|
||||
info("Opening the inspector on the test page");
|
||||
let {toolbox, inspector} = yield addTab(TEST_URL).then(openInspector);
|
||||
|
||||
yield inspector.markup.expandAll();
|
||||
|
||||
info("Selecting the test node");
|
||||
let node = content.document.getElementById("retag-me");
|
||||
let child = content.document.querySelector("#retag-me-2");
|
||||
yield selectNode(node, inspector);
|
||||
|
||||
let container = getContainerForRawNode(inspector.markup, node);
|
||||
is(node.tagName, "DIV", "We've got #retag-me element, it's a DIV");
|
||||
ok(container.expanded, "It is expanded");
|
||||
is(child.parentNode, node, "Child #retag-me-2 is inside #retag-me");
|
||||
|
||||
info("Changing the tagname");
|
||||
let mutated = inspector.once("markupmutation");
|
||||
let tagEditor = container.editor.tag;
|
||||
setEditableFieldValue(tagEditor, "p", inspector);
|
||||
yield mutated;
|
||||
|
||||
info("Checking that the tagname change was done");
|
||||
let node = content.document.getElementById("retag-me");
|
||||
let container = getContainerForRawNode(inspector.markup, node);
|
||||
is(node.tagName, "P", "We've got #retag-me, it should now be a P");
|
||||
ok(container.expanded, "It is still expanded");
|
||||
ok(container.selected, "It is still selected");
|
||||
is(child.parentNode, node, "Child #retag-me-2 is still inside #retag-me");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
}).then(null, ok.bind(null, false)).then(finish);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/* Any copyright", " is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests that a node can be deleted from the markup-view with the delete key
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
const TEST_URL = "data:text/html,<div id='delete-me'></div>";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function() {
|
||||
info("Opening the inspector on the test page");
|
||||
let {toolbox, inspector} = yield addTab(TEST_URL).then(openInspector);
|
||||
|
||||
info("Selecting the test node by clicking on it to make sure it receives focus");
|
||||
let node = content.document.getElementById("delete-me");
|
||||
yield clickContainer(node, inspector);
|
||||
|
||||
info("Deleting the element with the keyboard");
|
||||
let mutated = inspector.once("markupmutation");
|
||||
EventUtils.sendKey("delete", inspector.panelWin);
|
||||
yield mutated;
|
||||
|
||||
info("Checking that it's gone, baby gone!");
|
||||
ok(!content.document.getElementById("delete-me"), "The test node does not exist");
|
||||
|
||||
yield undoChange(inspector);
|
||||
ok(content.document.getElementById("delete-me"), "The test node is back!");
|
||||
|
||||
yield inspector.once("inspector-updated");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
}).then(null, ok.bind(null, false)).then(finish);
|
||||
}
|
@ -8,6 +8,7 @@ let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
|
||||
let promise = devtools.require("sdk/core/promise");
|
||||
let {getInplaceEditorForSpan: inplaceEditor} = devtools.require("devtools/shared/inplace-editor");
|
||||
|
||||
// Clear preferences that may be set during the course of tests.
|
||||
function clearUserPrefs() {
|
||||
@ -18,15 +19,23 @@ function clearUserPrefs() {
|
||||
|
||||
registerCleanupFunction(clearUserPrefs);
|
||||
|
||||
Services.prefs.setBoolPref("devtools.debugger.log", true);
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("devtools.debugger.log");
|
||||
});
|
||||
/**
|
||||
* Add a new test tab in the browser and load the given url.
|
||||
* @param {String} url The url to be loaded in the new tab
|
||||
* @return a promise that resolves when the url is loaded
|
||||
*/
|
||||
function addTab(url) {
|
||||
let def = promise.defer();
|
||||
|
||||
function getContainerForRawNode(markupView, rawNode) {
|
||||
let front = markupView.walker.frontForRawNode(rawNode);
|
||||
let container = markupView.getContainer(front);
|
||||
return container;
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
info("URL " + url + " loading complete into new test tab");
|
||||
waitForFocus(def.resolve, content);
|
||||
}, true);
|
||||
content.location = url;
|
||||
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -34,19 +43,41 @@ function getContainerForRawNode(markupView, rawNode) {
|
||||
* @return a promise that resolves when the inspector is ready
|
||||
*/
|
||||
function openInspector() {
|
||||
let deferred = promise.defer();
|
||||
let def = promise.defer();
|
||||
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
||||
info("Toolbox open");
|
||||
let inspector = toolbox.getCurrentPanel();
|
||||
inspector.once("inspector-updated", () => {
|
||||
deferred.resolve({toolbox: toolbox, inspector: inspector});
|
||||
info("Inspector panel active and ready");
|
||||
def.resolve({toolbox: toolbox, inspector: inspector});
|
||||
});
|
||||
}).then(null, console.error);
|
||||
|
||||
return deferred.promise;
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MarkupContainer object instance that corresponds to the given
|
||||
* HTML node
|
||||
* @param {MarkupView} markupView The instance of MarkupView currently loaded into the inspector panel
|
||||
* @param {DOMNode} rawNode The DOM node for which the container is required
|
||||
* @return {MarkupContainer}
|
||||
*/
|
||||
function getContainerForRawNode(markupView, rawNode) {
|
||||
let front = markupView.walker.frontForRawNode(rawNode);
|
||||
let container = markupView.getContainer(front);
|
||||
ok(container, "A markup-container object was found");
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple DOM node accesor function that takes either a node or a string css
|
||||
* selector as argument and returns the corresponding node
|
||||
* @param {String|DOMNode} nodeOrSelector
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
function getNode(nodeOrSelector) {
|
||||
let node = nodeOrSelector;
|
||||
|
||||
@ -61,23 +92,30 @@ function getNode(nodeOrSelector) {
|
||||
/**
|
||||
* Set the inspector's current selection to a node or to the first match of the
|
||||
* given css selector
|
||||
* @param {String|DOMNode} nodeOrSelector
|
||||
* @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
|
||||
* @param {String} reason Defaults to "test" which instructs the inspector not to highlight the node upon selection
|
||||
* @return a promise that resolves when the inspector is updated with the new
|
||||
* node
|
||||
*/
|
||||
function selectNode(nodeOrSelector, inspector) {
|
||||
function selectNode(nodeOrSelector, inspector, reason="test") {
|
||||
info("Selecting the node " + nodeOrSelector);
|
||||
let node = getNode(nodeOrSelector);
|
||||
let updated = inspector.once("inspector-updated");
|
||||
inspector.selection.setNode(node, "test");
|
||||
inspector.selection.setNode(node, reason);
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate a mouse-over on the markup-container (a line in the markup-view)
|
||||
* that corresponds to the node or selector passed.
|
||||
* @param {String|DOMNode} nodeOrSelector
|
||||
* @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
|
||||
* @return a promise that resolves when the container is hovered and the higlighter
|
||||
* is shown on the corresponding node
|
||||
*/
|
||||
function hoverContainer(nodeOrSelector, inspector) {
|
||||
info("Hovering over the markup-container for node " + nodeOrSelector);
|
||||
let highlit = inspector.toolbox.once("node-highlight");
|
||||
let container = getContainerForRawNode(inspector.markup, getNode(nodeOrSelector));
|
||||
EventUtils.synthesizeMouse(container.tagLine, 2, 2, {type: "mousemove"},
|
||||
@ -88,9 +126,12 @@ function hoverContainer(nodeOrSelector, inspector) {
|
||||
/**
|
||||
* Simulate a click on the markup-container (a line in the markup-view)
|
||||
* that corresponds to the node or selector passed.
|
||||
* @param {String|DOMNode} nodeOrSelector
|
||||
* @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
|
||||
* @return a promise that resolves when the node has been selected.
|
||||
*/
|
||||
function clickContainer(nodeOrSelector, inspector) {
|
||||
info("Clicking on the markup-container for node " + nodeOrSelector);
|
||||
let updated = inspector.once("inspector-updated");
|
||||
let container = getContainerForRawNode(inspector.markup, getNode(nodeOrSelector));
|
||||
EventUtils.synthesizeMouseAtCenter(container.tagLine, {type: "mousedown"},
|
||||
@ -102,6 +143,7 @@ function clickContainer(nodeOrSelector, inspector) {
|
||||
|
||||
/**
|
||||
* Checks if the highlighter is visible currently
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isHighlighterVisible() {
|
||||
let outline = gBrowser.selectedBrowser.parentNode.querySelector(".highlighter-container .highlighter-outline");
|
||||
@ -110,18 +152,91 @@ function isHighlighterVisible() {
|
||||
|
||||
/**
|
||||
* Simulate the mouse leaving the markup-view area
|
||||
* @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
|
||||
* @return a promise when done
|
||||
*/
|
||||
function mouseLeaveMarkupView(inspector) {
|
||||
let deferred = promise.defer();
|
||||
info("Leaving the markup-view area");
|
||||
let def = promise.defer();
|
||||
|
||||
// Find another element to mouseover over in order to leave the markup-view
|
||||
let btn = inspector.toolbox.doc.querySelector(".toolbox-dock-button");
|
||||
|
||||
EventUtils.synthesizeMouse(btn, 2, 2, {type: "mousemove"},
|
||||
inspector.toolbox.doc.defaultView);
|
||||
executeSoon(deferred.resolve);
|
||||
executeSoon(def.resolve);
|
||||
|
||||
return deferred.promise;
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus a given editable element, enter edit mode, set value, and commit
|
||||
* @param {DOMNode} field The element that gets editable after receiving focus and <ENTER> keypress
|
||||
* @param {String} value The string value to be set into the edited field
|
||||
* @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
|
||||
*/
|
||||
function setEditableFieldValue(field, value, inspector) {
|
||||
field.focus();
|
||||
EventUtils.sendKey("return", inspector.panelWin);
|
||||
let input = inplaceEditor(field).input;
|
||||
ok(input, "Found editable field for setting value: " + value);
|
||||
input.value = value;
|
||||
EventUtils.sendKey("return", inspector.panelWin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a node has the given attributes
|
||||
*
|
||||
* @param {HTMLNode} element The node to check.
|
||||
* @param {Object} attrs An object containing the attributes to check.
|
||||
* e.g. {id: "id1", class: "someclass"}
|
||||
*
|
||||
* Note that node.getAttribute() returns attribute values provided by the HTML
|
||||
* parser. The parser only provides unescaped entities so & will return &.
|
||||
*/
|
||||
function assertAttributes(element, attrs) {
|
||||
is(element.attributes.length, Object.keys(attrs).length,
|
||||
"Node has the correct number of attributes.");
|
||||
for (let attr in attrs) {
|
||||
is(element.getAttribute(attr), attrs[attr],
|
||||
"Node has the correct " + attr + " attribute.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo the last markup-view action and wait for the corresponding mutation to
|
||||
* occur
|
||||
* @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
|
||||
* @return a promise that resolves when the markup-mutation has been treated or
|
||||
* rejects if no undo action is possible
|
||||
*/
|
||||
function undoChange(inspector) {
|
||||
let canUndo = inspector.markup.undo.canUndo();
|
||||
ok(canUndo, "The last change in the markup-view can be undone");
|
||||
if (!canUndo) {
|
||||
return promise.reject();
|
||||
}
|
||||
|
||||
let mutated = inspector.once("markupmutation");
|
||||
inspector.markup.undo.undo();
|
||||
return mutated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redo the last markup-view action and wait for the corresponding mutation to
|
||||
* occur
|
||||
* @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
|
||||
* @return a promise that resolves when the markup-mutation has been treated or
|
||||
* rejects if no redo action is possible
|
||||
*/
|
||||
function redoChange(inspector) {
|
||||
let canRedo = inspector.markup.undo.canRedo();
|
||||
ok(canRedo, "The last change in the markup-view can be redone");
|
||||
if (!canRedo) {
|
||||
return promise.reject();
|
||||
}
|
||||
|
||||
let mutated = inspector.once("markupmutation");
|
||||
inspector.markup.undo.redo();
|
||||
return mutated;
|
||||
}
|
||||
|
153
browser/devtools/styleinspector/css-parsing-utils.js
Normal file
153
browser/devtools/styleinspector/css-parsing-utils.js
Normal file
@ -0,0 +1,153 @@
|
||||
/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const cssTokenizer = require("devtools/sourceeditor/css-tokenizer");
|
||||
|
||||
/**
|
||||
* Returns the string enclosed in quotes
|
||||
*/
|
||||
function quoteString(string) {
|
||||
let hasDoubleQuotes = string.contains('"');
|
||||
let hasSingleQuotes = string.contains("'");
|
||||
|
||||
if (hasDoubleQuotes && !hasSingleQuotes) {
|
||||
// In this case, no escaping required, just enclose in single-quotes
|
||||
return "'" + string + "'";
|
||||
}
|
||||
|
||||
// In all other cases, enclose in double-quotes, and escape any double-quote
|
||||
// that may be in the string
|
||||
return '"' + string.replace(/"/g, '\"') + '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of CSS declarations given an string.
|
||||
* For example, parseDeclarations("width: 1px; height: 1px") would return
|
||||
* [{name:"width", value: "1px"}, {name: "height", "value": "1px"}]
|
||||
*
|
||||
* The input string is assumed to only contain declarations so { and } characters
|
||||
* will be treated as part of either the property or value, depending where it's
|
||||
* found.
|
||||
*
|
||||
* @param {string} inputString
|
||||
* An input string of CSS
|
||||
* @return {Array} an array of objects with the following signature:
|
||||
* [{"name": string, "value": string, "priority": string}, ...]
|
||||
*/
|
||||
function parseDeclarations(inputString) {
|
||||
let tokens = cssTokenizer(inputString);
|
||||
|
||||
let declarations = [{name: "", value: "", priority: ""}];
|
||||
|
||||
let current = "", hasBang = false, lastProp;
|
||||
for (let token of tokens) {
|
||||
lastProp = declarations[declarations.length - 1];
|
||||
|
||||
if (token.tokenType === ":") {
|
||||
if (!lastProp.name) {
|
||||
// Set the current declaration name if there's no name yet
|
||||
lastProp.name = current.trim();
|
||||
current = "";
|
||||
hasBang = false;
|
||||
} else {
|
||||
// Otherwise, just append ':' to the current value (declaration value
|
||||
// with colons)
|
||||
current += ":";
|
||||
}
|
||||
} else if (token.tokenType === ";") {
|
||||
lastProp.value = current.trim();
|
||||
current = "";
|
||||
hasBang = false;
|
||||
declarations.push({name: "", value: "", priority: ""});
|
||||
} else {
|
||||
switch(token.tokenType) {
|
||||
case "IDENT":
|
||||
if (token.value === "important" && hasBang) {
|
||||
lastProp.priority = "important";
|
||||
hasBang = false;
|
||||
} else {
|
||||
if (hasBang) {
|
||||
current += "!";
|
||||
}
|
||||
current += token.value;
|
||||
}
|
||||
break;
|
||||
case "WHITESPACE":
|
||||
current += " ";
|
||||
break;
|
||||
case "DIMENSION":
|
||||
current += token.repr;
|
||||
break;
|
||||
case "HASH":
|
||||
current += "#" + token.value;
|
||||
break;
|
||||
case "URL":
|
||||
current += "url(" + quoteString(token.value) + ")";
|
||||
break;
|
||||
case "FUNCTION":
|
||||
current += token.value + "(";
|
||||
break;
|
||||
case ")":
|
||||
current += token.tokenType;
|
||||
break;
|
||||
case "EOF":
|
||||
break;
|
||||
case "DELIM":
|
||||
if (token.value === "!") {
|
||||
hasBang = true;
|
||||
} else {
|
||||
current += token.value;
|
||||
}
|
||||
break;
|
||||
case "STRING":
|
||||
current += quoteString(token.value);
|
||||
break;
|
||||
case "{":
|
||||
case "}":
|
||||
current += token.tokenType;
|
||||
break;
|
||||
default:
|
||||
current += token.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle whatever trailing properties or values might still be there
|
||||
if (current) {
|
||||
if (!lastProp.name) {
|
||||
// Trailing property found, e.g. p1:v1;p2:v2;p3
|
||||
lastProp.name = current.trim();
|
||||
} else {
|
||||
// Trailing value found, i.e. value without an ending ;
|
||||
lastProp.value += current.trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove declarations that have neither a name nor a value
|
||||
declarations = declarations.filter(prop => prop.name || prop.value);
|
||||
|
||||
return declarations;
|
||||
};
|
||||
exports.parseDeclarations = parseDeclarations;
|
||||
|
||||
/**
|
||||
* Expects a single CSS value to be passed as the input and parses the value
|
||||
* and priority.
|
||||
*
|
||||
* @param {string} value The value from the text editor.
|
||||
* @return {object} an object with 'value' and 'priority' properties.
|
||||
*/
|
||||
function parseSingleValue(value) {
|
||||
let declaration = parseDeclarations("a: " + value + ";")[0];
|
||||
return {
|
||||
value: declaration ? declaration.value : "",
|
||||
priority: declaration ? declaration.priority : ""
|
||||
};
|
||||
};
|
||||
exports.parseSingleValue = parseSingleValue;
|
@ -14,7 +14,8 @@ const {ELEMENT_STYLE, PSEUDO_ELEMENTS} = require("devtools/server/actors/styles"
|
||||
const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
const {Tooltip, SwatchColorPickerTooltip} = require("devtools/shared/widgets/Tooltip");
|
||||
const {OutputParser} = require("devtools/output-parser");
|
||||
const { PrefObserver, PREF_ORIG_SOURCES } = require("devtools/styleeditor/utils");
|
||||
const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/styleeditor/utils");
|
||||
const {parseSingleValue, parseDeclarations} = require("devtools/styleinspector/css-parsing-utils");
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
@ -582,7 +583,7 @@ Rule.prototype = {
|
||||
|
||||
let promise = aModifications.apply().then(() => {
|
||||
let cssProps = {};
|
||||
for (let cssProp of parseCSSText(this.style.cssText)) {
|
||||
for (let cssProp of parseDeclarations(this.style.cssText)) {
|
||||
cssProps[cssProp.name] = cssProp;
|
||||
}
|
||||
|
||||
@ -692,7 +693,7 @@ Rule.prototype = {
|
||||
_getTextProperties: function() {
|
||||
let textProps = [];
|
||||
let store = this.elementStyle.store;
|
||||
let props = parseCSSText(this.style.cssText);
|
||||
let props = parseDeclarations(this.style.cssText);
|
||||
for (let prop of props) {
|
||||
let name = prop.name;
|
||||
if (this.inherited && !domUtils.isInheritedProperty(name)) {
|
||||
@ -1850,17 +1851,13 @@ RuleEditor.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Deal with adding declarations later (once editor has been destroyed).
|
||||
// If aValue is just a name, will make a new property with empty value.
|
||||
this.multipleAddedProperties = parseCSSText(aValue);
|
||||
if (!this.multipleAddedProperties.length) {
|
||||
this.multipleAddedProperties = [{
|
||||
name: aValue,
|
||||
value: "",
|
||||
priority: ""
|
||||
}];
|
||||
}
|
||||
// parseDeclarations allows for name-less declarations, but in the present
|
||||
// case, we're creating a new declaration, it doesn't make sense to accept
|
||||
// these entries
|
||||
this.multipleAddedProperties = parseDeclarations(aValue).filter(d => d.name);
|
||||
|
||||
// Blur the editor field now and deal with adding declarations later when
|
||||
// the field gets destroyed (see _newPropertyDestroy)
|
||||
this.editor.input.blur();
|
||||
},
|
||||
|
||||
@ -2263,17 +2260,16 @@ TextPropertyEditor.prototype = {
|
||||
if (aValue.trim() === "") {
|
||||
this.remove();
|
||||
} else {
|
||||
|
||||
// Adding multiple rules inside of name field overwrites the current
|
||||
// property with the first, then adds any more onto the property list.
|
||||
let properties = parseCSSText(aValue);
|
||||
if (properties.length > 0) {
|
||||
this.prop.setName(properties[0].name);
|
||||
this.prop.setValue(properties[0].value, properties[0].priority);
|
||||
let properties = parseDeclarations(aValue);
|
||||
|
||||
this.ruleEditor.addProperties(properties.slice(1), this.prop);
|
||||
} else {
|
||||
this.prop.setName(aValue);
|
||||
if (properties.length) {
|
||||
this.prop.setName(properties[0].name);
|
||||
if (properties.length > 1) {
|
||||
this.prop.setValue(properties[0].value, properties[0].priority);
|
||||
this.ruleEditor.addProperties(properties.slice(1), this.prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2320,7 +2316,7 @@ TextPropertyEditor.prototype = {
|
||||
let {propertiesToAdd,firstValue} = this._getValueAndExtraProperties(aValue);
|
||||
|
||||
// First, set this property value (common case, only modified a property)
|
||||
let val = parseCSSValue(firstValue);
|
||||
let val = parseSingleValue(firstValue);
|
||||
this.prop.setValue(val.value, val.priority);
|
||||
this.removeOnRevert = false;
|
||||
this.committed.value = this.prop.value;
|
||||
@ -2356,36 +2352,31 @@ TextPropertyEditor.prototype = {
|
||||
* firstValue: A string containing a simple value, like
|
||||
* "red" or "100px!important"
|
||||
* propertiesToAdd: An array with additional properties, following the
|
||||
* parseCSSText format of {name,value,priority}
|
||||
* parseDeclarations format of {name,value,priority}
|
||||
*/
|
||||
_getValueAndExtraProperties: function(aValue) {
|
||||
// The inplace editor will prevent manual typing of multiple properties,
|
||||
// but we need to deal with the case during a paste event.
|
||||
// Adding multiple properties inside of value editor sets value with the
|
||||
// first, then adds any more onto the property list (below this property).
|
||||
let properties = parseCSSText(aValue);
|
||||
let propertiesToAdd = [];
|
||||
let firstValue = aValue;
|
||||
let propertiesToAdd = [];
|
||||
|
||||
if (properties.length > 0) {
|
||||
// If text like "red; width: 1px;" was entered in, handle this as two
|
||||
// separate properties (setting value here to red and adding a new prop).
|
||||
let propertiesNoName = parseCSSText("a:" + aValue);
|
||||
let enteredValueFirst = propertiesNoName.length > properties.length;
|
||||
let properties = parseDeclarations(aValue);
|
||||
|
||||
let firstProp = properties[0];
|
||||
propertiesToAdd = properties.slice(1);
|
||||
|
||||
if (enteredValueFirst) {
|
||||
firstProp = propertiesNoName[0];
|
||||
propertiesToAdd = propertiesNoName.slice(1);
|
||||
// Check to see if the input string can be parsed as multiple properties
|
||||
if (properties.length) {
|
||||
// Get the first property value (if any), and any remaining properties (if any)
|
||||
if (!properties[0].name && properties[0].value) {
|
||||
firstValue = properties[0].value;
|
||||
propertiesToAdd = properties.slice(1);
|
||||
}
|
||||
// In some cases, the value could be a property:value pair itself.
|
||||
// Join them as one value string and append potentially following properties
|
||||
else if (properties[0].name && properties[0].value) {
|
||||
firstValue = properties[0].name + ": " + properties[0].value;
|
||||
propertiesToAdd = properties.slice(1);
|
||||
}
|
||||
|
||||
// If "red; width: 1px", then set value to "red"
|
||||
// If "color: red; width: 1px;", then set value to "color: red;"
|
||||
firstValue = enteredValueFirst ?
|
||||
firstProp.value + "!" + firstProp.priority :
|
||||
firstProp.name + ": " + firstProp.value + "!" + firstProp.priority;
|
||||
}
|
||||
|
||||
return {
|
||||
@ -2395,7 +2386,7 @@ TextPropertyEditor.prototype = {
|
||||
},
|
||||
|
||||
_applyNewValue: function(aValue) {
|
||||
let val = parseCSSValue(aValue);
|
||||
let val = parseSingleValue(aValue);
|
||||
// Any property should be removed if has an empty value.
|
||||
if (val.value.trim() === "") {
|
||||
this.remove();
|
||||
@ -2419,7 +2410,7 @@ TextPropertyEditor.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let val = parseCSSValue(aValue);
|
||||
let val = parseSingleValue(aValue);
|
||||
|
||||
// Live previewing the change without committing just yet, that'll be done in _onValueDone
|
||||
// If it was not a valid value, apply an empty string to reset the live preview
|
||||
@ -2439,7 +2430,7 @@ TextPropertyEditor.prototype = {
|
||||
isValid: function(aValue) {
|
||||
let name = this.prop.name;
|
||||
let value = typeof aValue == "undefined" ? this.prop.value : aValue;
|
||||
let val = parseCSSValue(value);
|
||||
let val = parseSingleValue(value);
|
||||
|
||||
let style = this.doc.createElementNS(HTML_NS, "div").style;
|
||||
let prefs = Services.prefs;
|
||||
@ -2605,64 +2596,14 @@ function throttle(func, wait, scope) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull priority (!important) out of the value provided by a
|
||||
* value editor.
|
||||
*
|
||||
* @param {string} aValue
|
||||
* The value from the text editor.
|
||||
* @return {object} an object with 'value' and 'priority' properties.
|
||||
*/
|
||||
function parseCSSValue(aValue) {
|
||||
let pieces = aValue.split("!", 2);
|
||||
return {
|
||||
value: pieces[0].trim(),
|
||||
priority: (pieces.length > 1 ? pieces[1].trim() : "")
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of CSS properties given an input string
|
||||
* For example, parseCSSText("width: 1px; height: 1px") would return
|
||||
* [{name:"width", value: "1px"}, {name: "height", "value": "1px"}]
|
||||
*
|
||||
* @param {string} aCssText
|
||||
* An input string of CSS
|
||||
* @return {Array} an array of objects with the following signature:
|
||||
* [{"name": string, "value": string, "priority": string}, ...]
|
||||
*/
|
||||
function parseCSSText(aCssText) {
|
||||
let lines = aCssText.match(CSS_LINE_RE);
|
||||
let props = [];
|
||||
|
||||
[].forEach.call(lines, (line, i) => {
|
||||
let [, name, value, priority] = CSS_PROP_RE.exec(line) || [];
|
||||
|
||||
// If this is ending with an unfinished line, add it onto the end
|
||||
// with an empty value
|
||||
if (!name && line && i > 0) {
|
||||
name = line;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
props.push({
|
||||
name: name.trim(),
|
||||
value: value || "",
|
||||
priority: priority || ""
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler that causes a blur on the target if the input has
|
||||
* multiple CSS properties as the value.
|
||||
*/
|
||||
function blurOnMultipleProperties(e) {
|
||||
setTimeout(() => {
|
||||
if (parseCSSText(e.target.value).length) {
|
||||
let props = parseDeclarations(e.target.value);
|
||||
if (props.length > 1) {
|
||||
e.target.blur();
|
||||
}
|
||||
}, 0);
|
||||
|
@ -55,7 +55,6 @@ support-files = browser_ruleview_pseudoelement.html
|
||||
[browser_bug765105_background_image_tooltip.js]
|
||||
[browser_bug889638_rule_view_color_picker.js]
|
||||
[browser_bug726427_csstransform_tooltip.js]
|
||||
|
||||
[browser_bug940500_rule_view_pick_gradient_color.js]
|
||||
[browser_ruleview_original_source_link.js]
|
||||
support-files =
|
||||
@ -67,3 +66,4 @@ support-files =
|
||||
[browser_bug946331_close_tooltip_on_new_selection.js]
|
||||
[browser_bug942297_user_property_reset.js]
|
||||
[browser_styleinspector_outputparser.js]
|
||||
[browser_bug970532_mathml_element.js]
|
||||
|
@ -0,0 +1,70 @@
|
||||
/* Any copyright", " is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests that the rule-view displays correctly on MathML elements
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
const TEST_URL = [
|
||||
"data:text/html,",
|
||||
"<div>",
|
||||
" <math xmlns=\"http://www.w3.org/1998/Math/MathML\">",
|
||||
" <mfrac>",
|
||||
" <msubsup>",
|
||||
" <mi>a</mi>",
|
||||
" <mi>i</mi>",
|
||||
" <mi>j</mi>",
|
||||
" </msubsup>",
|
||||
" <msub>",
|
||||
" <mi>x</mi>",
|
||||
" <mn>0</mn>",
|
||||
" </msub>",
|
||||
" </mfrac>",
|
||||
" </math>",
|
||||
"</div>"
|
||||
].join("");
|
||||
|
||||
function test() {
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
waitForFocus(runTests, content);
|
||||
}, true);
|
||||
content.location = TEST_URL;
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
openRuleView((inspector, ruleView) => {
|
||||
Task.spawn(function() {
|
||||
info("Select the DIV node and verify the rule-view shows rules");
|
||||
yield selectNode("div", inspector);
|
||||
ok(ruleView.element.querySelectorAll(".ruleview-rule").length,
|
||||
"The rule-view shows rules for the div element");
|
||||
|
||||
info("Select various MathML nodes and verify the rule-view is empty");
|
||||
yield selectNode("math", inspector);
|
||||
ok(!ruleView.element.querySelectorAll(".ruleview-rule").length,
|
||||
"The rule-view is empty for the math element");
|
||||
|
||||
yield selectNode("msubsup", inspector);
|
||||
ok(!ruleView.element.querySelectorAll(".ruleview-rule").length,
|
||||
"The rule-view is empty for the msubsup element");
|
||||
|
||||
yield selectNode("mn", inspector);
|
||||
ok(!ruleView.element.querySelectorAll(".ruleview-rule").length,
|
||||
"The rule-view is empty for the mn element");
|
||||
|
||||
info("Select again the DIV node and verify the rule-view shows rules");
|
||||
yield selectNode("div", inspector);
|
||||
ok(ruleView.element.querySelectorAll(".ruleview-rule").length,
|
||||
"The rule-view shows rules for the div element");
|
||||
}).then(null, ok.bind(null, false)).then(finishUp);
|
||||
});
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
@ -6,6 +6,8 @@ let doc;
|
||||
let ruleWindow;
|
||||
let ruleView;
|
||||
let inspector;
|
||||
let TEST_URL = 'url("http://example.com/browser/browser/devtools/' +
|
||||
'styleinspector/test/test-image.png")';
|
||||
|
||||
function startTest()
|
||||
{
|
||||
@ -140,7 +142,7 @@ function testEditProperty()
|
||||
let value = idRuleEditor.rule.domRule._rawStyle().getPropertyValue("border-color");
|
||||
is(value, "red", "border-color should have been set.");
|
||||
is(propEditor.isValid(), true, "red should be a valid entry");
|
||||
finishTest();
|
||||
testEditPropertyWithColon();
|
||||
}));
|
||||
});
|
||||
|
||||
@ -159,6 +161,43 @@ function testEditProperty()
|
||||
ruleWindow);
|
||||
}
|
||||
|
||||
function testEditPropertyWithColon()
|
||||
{
|
||||
let idRuleEditor = ruleView.element.children[1]._ruleEditor;
|
||||
let propEditor = idRuleEditor.rule.textProps[0].editor;
|
||||
waitForEditorFocus(propEditor.element, function onNewElement(aEditor) {
|
||||
is(inplaceEditor(propEditor.nameSpan), aEditor, "Next focused editor should be the name editor.");
|
||||
let input = aEditor.input;
|
||||
waitForEditorFocus(propEditor.element, function onNewName(aEditor) {
|
||||
promiseDone(expectRuleChange(idRuleEditor.rule).then(() => {
|
||||
input = aEditor.input;
|
||||
is(inplaceEditor(propEditor.valueSpan), aEditor, "Focus should have moved to the value.");
|
||||
|
||||
waitForEditorBlur(aEditor, function() {
|
||||
promiseDone(expectRuleChange(idRuleEditor.rule).then(() => {
|
||||
let value = idRuleEditor.rule.domRule._rawStyle().getPropertyValue("background-image");
|
||||
is(value, TEST_URL, "background-image should have been set.");
|
||||
is(propEditor.isValid(), true, "the test URL should be a valid entry");
|
||||
finishTest();
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
for (let ch of (TEST_URL + ";")) {
|
||||
EventUtils.sendChar(ch, ruleWindow);
|
||||
}
|
||||
}));
|
||||
});
|
||||
for (let ch of "background-image:") {
|
||||
EventUtils.sendChar(ch, ruleWindow);
|
||||
}
|
||||
});
|
||||
|
||||
EventUtils.synthesizeMouse(propEditor.nameSpan, 32, 1,
|
||||
{ },
|
||||
ruleWindow);
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
inspector = ruleWindow = ruleView = null;
|
||||
|
@ -28,13 +28,15 @@ function selectNewElement()
|
||||
let newElement = doc.createElement("div");
|
||||
newElement.textContent = "Test Element";
|
||||
doc.body.appendChild(newElement);
|
||||
inspector.selection.setNode(newElement);
|
||||
|
||||
inspector.selection.setNode(newElement, "test");
|
||||
let def = promise.defer();
|
||||
ruleView.element.addEventListener("CssRuleViewRefreshed", function changed() {
|
||||
ruleView.element.removeEventListener("CssRuleViewRefreshed", changed);
|
||||
elementRuleEditor = ruleView.element.children[0]._ruleEditor;
|
||||
def.resolve();
|
||||
});
|
||||
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
|
@ -79,6 +79,42 @@ function openComputedView(callback)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple DOM node accesor function that takes either a node or a string css
|
||||
* selector as argument and returns the corresponding node
|
||||
* @param {String|DOMNode} nodeOrSelector
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
function getNode(nodeOrSelector)
|
||||
{
|
||||
let node = nodeOrSelector;
|
||||
|
||||
if (typeof nodeOrSelector === "string") {
|
||||
node = content.document.querySelector(nodeOrSelector);
|
||||
ok(node, "A node was found for selector " + nodeOrSelector);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the inspector's current selection to a node or to the first match of the
|
||||
* given css selector
|
||||
* @param {String|DOMNode} nodeOrSelector
|
||||
* @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
|
||||
* @param {String} reason Defaults to "test" which instructs the inspector not to highlight the node upon selection
|
||||
* @return a promise that resolves when the inspector is updated with the new
|
||||
* node
|
||||
*/
|
||||
function selectNode(nodeOrSelector, inspector, reason="test")
|
||||
{
|
||||
info("Selecting the node " + nodeOrSelector);
|
||||
let node = getNode(nodeOrSelector);
|
||||
let updated = inspector.once("inspector-updated");
|
||||
inspector.selection.setNode(node, reason);
|
||||
return updated;
|
||||
}
|
||||
|
||||
function addStyle(aDocument, aString)
|
||||
{
|
||||
let node = aDocument.createElement('style');
|
||||
|
@ -5,3 +5,4 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
|
||||
|
@ -0,0 +1,206 @@
|
||||
/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
||||
const {parseDeclarations} = devtools.require("devtools/styleinspector/css-parsing-utils");
|
||||
|
||||
const TEST_DATA = [
|
||||
// Simple test
|
||||
{
|
||||
input: "p:v;",
|
||||
expected: [{name: "p", value: "v", priority: ""}]
|
||||
},
|
||||
// Simple test
|
||||
{
|
||||
input: "this:is;a:test;",
|
||||
expected: [
|
||||
{name: "this", value: "is", priority: ""},
|
||||
{name: "a", value: "test", priority: ""}
|
||||
]
|
||||
},
|
||||
// Test a single declaration with semi-colon
|
||||
{
|
||||
input: "name:value;",
|
||||
expected: [{name: "name", value: "value", priority: ""}]
|
||||
},
|
||||
// Test a single declaration without semi-colon
|
||||
{
|
||||
input: "name:value",
|
||||
expected: [{name: "name", value: "value", priority: ""}]
|
||||
},
|
||||
// Test multiple declarations separated by whitespaces and carriage returns and tabs
|
||||
{
|
||||
input: "p1 : v1 ; \t\t \n p2:v2; \n\n\n\n\t p3 : v3;",
|
||||
expected: [
|
||||
{name: "p1", value: "v1", priority: ""},
|
||||
{name: "p2", value: "v2", priority: ""},
|
||||
{name: "p3", value: "v3", priority: ""},
|
||||
]
|
||||
},
|
||||
// Test simple priority
|
||||
{
|
||||
input: "p1: v1; p2: v2 !important;",
|
||||
expected: [
|
||||
{name: "p1", value: "v1", priority: ""},
|
||||
{name: "p2", value: "v2", priority: "important"}
|
||||
]
|
||||
},
|
||||
// Test simple priority
|
||||
{
|
||||
input: "p1: v1 !important; p2: v2",
|
||||
expected: [
|
||||
{name: "p1", value: "v1", priority: "important"},
|
||||
{name: "p2", value: "v2", priority: ""}
|
||||
]
|
||||
},
|
||||
// Test simple priority
|
||||
{
|
||||
input: "p1: v1 ! important; p2: v2 ! important;",
|
||||
expected: [
|
||||
{name: "p1", value: "v1", priority: "important"},
|
||||
{name: "p2", value: "v2", priority: "important"}
|
||||
]
|
||||
},
|
||||
// Test invalid priority
|
||||
{
|
||||
input: "p1: v1 important;",
|
||||
expected: [
|
||||
{name: "p1", value: "v1 important", priority: ""}
|
||||
]
|
||||
},
|
||||
// Test various types of background-image urls
|
||||
{
|
||||
input: "background-image: url(../../relative/image.png)",
|
||||
expected: [{name: "background-image", value: "url(\"../../relative/image.png\")", priority: ""}]
|
||||
},
|
||||
{
|
||||
input: "background-image: url(http://site.com/test.png)",
|
||||
expected: [{name: "background-image", value: "url(\"http://site.com/test.png\")", priority: ""}]
|
||||
},
|
||||
{
|
||||
input: "background-image: url(wow.gif)",
|
||||
expected: [{name: "background-image", value: "url(\"wow.gif\")", priority: ""}]
|
||||
},
|
||||
// Test that urls with :;{} characters in them are parsed correctly
|
||||
{
|
||||
input: "background: red url(\"http://site.com/image{}:;.png?id=4#wat\") repeat top right",
|
||||
expected: [
|
||||
{name: "background", value: "red url(\"http://site.com/image{}:;.png?id=4#wat\") repeat top right", priority: ""}
|
||||
]
|
||||
},
|
||||
// Test that an empty string results in an empty array
|
||||
{input: "", expected: []},
|
||||
// Test that a string comprised only of whitespaces results in an empty array
|
||||
{input: " \n \n \n \n \t \t\t\t ", expected: []},
|
||||
// Test that a null input throws an exception
|
||||
{input: null, throws: true},
|
||||
// Test that a undefined input throws an exception
|
||||
{input: undefined, throws: true},
|
||||
// Test that :;{} characters in quoted content are not parsed as multiple declarations
|
||||
{
|
||||
input: "content: \";color:red;}selector{color:yellow;\"",
|
||||
expected: [
|
||||
{name: "content", value: "\";color:red;}selector{color:yellow;\"", priority: ""}
|
||||
]
|
||||
},
|
||||
// Test that rules aren't parsed, just declarations. So { and } found after a
|
||||
// property name should be part of the property name, same for values.
|
||||
{
|
||||
input: "body {color:red;} p {color: blue;}",
|
||||
expected: [
|
||||
{name: "body {color", value: "red", priority: ""},
|
||||
{name: "} p {color", value: "blue", priority: ""},
|
||||
{name: "}", value: "", priority: ""}
|
||||
]
|
||||
},
|
||||
// Test unbalanced : and ;
|
||||
{
|
||||
input: "color :red : font : arial;",
|
||||
expected : [
|
||||
{name: "color", value: "red : font : arial", priority: ""}
|
||||
]
|
||||
},
|
||||
{input: "background: red;;;;;", expected: [{name: "background", value: "red", priority: ""}]},
|
||||
{input: "background:;", expected: [{name: "background", value: "", priority: ""}]},
|
||||
{input: ";;;;;", expected: []},
|
||||
{input: ":;:;", expected: []},
|
||||
// Test name only
|
||||
{input: "color", expected: [
|
||||
{name: "color", value: "", priority: ""}
|
||||
]},
|
||||
// Test trailing name without :
|
||||
{input: "color:blue;font", expected: [
|
||||
{name: "color", value: "blue", priority: ""},
|
||||
{name: "font", value: "", priority: ""}
|
||||
]},
|
||||
// Test trailing name with :
|
||||
{input: "color:blue;font:", expected: [
|
||||
{name: "color", value: "blue", priority: ""},
|
||||
{name: "font", value: "", priority: ""}
|
||||
]},
|
||||
// Test leading value
|
||||
{input: "Arial;color:blue;", expected: [
|
||||
{name: "", value: "Arial", priority: ""},
|
||||
{name: "color", value: "blue", priority: ""}
|
||||
]},
|
||||
// Test hex colors
|
||||
{input: "color: #333", expected: [{name: "color", value: "#333", priority: ""}]},
|
||||
{input: "color: #456789", expected: [{name: "color", value: "#456789", priority: ""}]},
|
||||
{input: "wat: #XYZ", expected: [{name: "wat", value: "#XYZ", priority: ""}]},
|
||||
// Test string/url quotes escaping
|
||||
{input: "content: \"this is a 'string'\"", expected: [{name: "content", value: "\"this is a 'string'\"", priority: ""}]},
|
||||
{input: 'content: "this is a \\"string\\""', expected: [{name: "content", value: '\'this is a "string"\'', priority: ""}]},
|
||||
{input: "content: 'this is a \"string\"'", expected: [{name: "content", value: '\'this is a "string"\'', priority: ""}]},
|
||||
{input: "content: 'this is a \\'string\\'", expected: [{name: "content", value: '"this is a \'string\'"', priority: ""}]},
|
||||
{input: "content: 'this \\' is a \" really strange string'", expected: [{name: "content", value: '"this \' is a \" really strange string"', priority: ""}]},
|
||||
{
|
||||
input: "content: \"a not s\\\
|
||||
o very long title\"",
|
||||
expected: [
|
||||
{name: "content", value: '"a not s\
|
||||
o very long title"', priority: ""}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
for (let test of TEST_DATA) {
|
||||
do_print("Test input string " + test.input);
|
||||
let output;
|
||||
try {
|
||||
output = parseDeclarations(test.input);
|
||||
} catch (e) {
|
||||
do_print("parseDeclarations threw an exception with the given input string");
|
||||
if (test.throws) {
|
||||
do_print("Exception expected");
|
||||
do_check_true(true);
|
||||
} else {
|
||||
do_print("Exception unexpected\n" + e);
|
||||
do_check_true(false);
|
||||
}
|
||||
}
|
||||
if (output) {
|
||||
assertOutput(output, test.expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertOutput(actual, expected) {
|
||||
if (actual.length === expected.length) {
|
||||
for (let i = 0; i < expected.length; i ++) {
|
||||
do_check_true(!!actual[i]);
|
||||
do_print("Check that the output item has the expected name, value and priority");
|
||||
do_check_eq(expected[i].name, actual[i].name);
|
||||
do_check_eq(expected[i].value, actual[i].value);
|
||||
do_check_eq(expected[i].priority, actual[i].priority);
|
||||
}
|
||||
} else {
|
||||
for (let prop of actual) {
|
||||
do_print("Actual output contained: {name: "+prop.name+", value: "+prop.value+", priority: "+prop.priority+"}");
|
||||
}
|
||||
do_check_eq(actual.length, expected.length);
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
||||
const {parseSingleValue} = devtools.require("devtools/styleinspector/css-parsing-utils");
|
||||
|
||||
const TEST_DATA = [
|
||||
{input: null, throws: true},
|
||||
{input: undefined, throws: true},
|
||||
{input: "", expected: {value: "", priority: ""}},
|
||||
{input: " \t \t \n\n ", expected: {value: "", priority: ""}},
|
||||
{input: "blue", expected: {value: "blue", priority: ""}},
|
||||
{input: "blue !important", expected: {value: "blue", priority: "important"}},
|
||||
{input: "blue!important", expected: {value: "blue", priority: "important"}},
|
||||
{input: "blue ! important", expected: {value: "blue", priority: "important"}},
|
||||
{input: "blue ! important", expected: {value: "blue", priority: "important"}},
|
||||
{input: "blue !", expected: {value: "blue", priority: ""}},
|
||||
{input: "blue !mportant", expected: {value: "blue !mportant", priority: ""}},
|
||||
{input: " blue !important ", expected: {value: "blue", priority: "important"}},
|
||||
{
|
||||
input: "url(\"http://url.com/whyWouldYouDoThat!important.png\") !important",
|
||||
expected: {
|
||||
value: "url(\"http://url.com/whyWouldYouDoThat!important.png\")",
|
||||
priority: "important"
|
||||
}
|
||||
},
|
||||
{
|
||||
input: "url(\"http://url.com/whyWouldYouDoThat!important.png\")",
|
||||
expected: {
|
||||
value: "url(\"http://url.com/whyWouldYouDoThat!important.png\")",
|
||||
priority: ""
|
||||
}
|
||||
},
|
||||
{
|
||||
input: "\"content!important\" !important",
|
||||
expected: {
|
||||
value: "\"content!important\"",
|
||||
priority: "important"
|
||||
}
|
||||
},
|
||||
{
|
||||
input: "\"content!important\"",
|
||||
expected: {
|
||||
value: "\"content!important\"",
|
||||
priority: ""
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
for (let test of TEST_DATA) {
|
||||
do_print("Test input value " + test.input);
|
||||
try {
|
||||
let output = parseSingleValue(test.input);
|
||||
assertOutput(output, test.expected);
|
||||
} catch (e) {
|
||||
do_print("parseSingleValue threw an exception with the given input value");
|
||||
if (test.throws) {
|
||||
do_print("Exception expected");
|
||||
do_check_true(true);
|
||||
} else {
|
||||
do_print("Exception unexpected\n" + e);
|
||||
do_check_true(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertOutput(actual, expected) {
|
||||
do_print("Check that the output has the expected value and priority");
|
||||
do_check_eq(expected.value, actual.value);
|
||||
do_check_eq(expected.priority, actual.priority);
|
||||
}
|
7
browser/devtools/styleinspector/test/unit/xpcshell.ini
Normal file
7
browser/devtools/styleinspector/test/unit/xpcshell.ini
Normal file
@ -0,0 +1,7 @@
|
||||
[DEFAULT]
|
||||
head =
|
||||
tail =
|
||||
firefox-appdir = browser
|
||||
|
||||
[test_parseDeclarations.js]
|
||||
[test_parseSingleValue.js]
|
@ -12,51 +12,36 @@
|
||||
const TEST_URI = "data:text/html;charset=utf-8,<div style='font-size:3em;" +
|
||||
"foobarCssParser:baz'>test CSS parser filter</div>";
|
||||
|
||||
function onContentLoaded()
|
||||
{
|
||||
browser.removeEventListener("load", onContentLoaded, true);
|
||||
|
||||
let HUD = HUDService.getHudByWindow(content);
|
||||
let hudId = HUD.hudId;
|
||||
let outputNode = HUD.outputNode;
|
||||
|
||||
HUD.jsterm.clearOutput();
|
||||
|
||||
waitForSuccess({
|
||||
name: "css error displayed",
|
||||
validatorFn: function()
|
||||
{
|
||||
return outputNode.textContent.indexOf("foobarCssParser") > -1;
|
||||
},
|
||||
successFn: function()
|
||||
{
|
||||
HUD.setFilterState("cssparser", false);
|
||||
|
||||
let msg = "the unknown CSS property warning is not displayed, " +
|
||||
"after filtering";
|
||||
testLogEntry(outputNode, "foobarCssParser", msg, true, true);
|
||||
|
||||
HUD.setFilterState("cssparser", true);
|
||||
finishTest();
|
||||
},
|
||||
failureFn: finishTest,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit test for bug 589162:
|
||||
* CSS filtering on the console does not work
|
||||
*/
|
||||
function test()
|
||||
{
|
||||
addTab(TEST_URI);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
function test() {
|
||||
Task.spawn(runner).then(finishTest);
|
||||
|
||||
openConsole(null, function() {
|
||||
browser.addEventListener("load", onContentLoaded, true);
|
||||
content.location.reload();
|
||||
function* runner() {
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
let hud = yield openConsole(tab);
|
||||
|
||||
// CSS warnings are disabled by default.
|
||||
hud.setFilterState("cssparser", true);
|
||||
hud.jsterm.clearOutput();
|
||||
|
||||
content.location.reload();
|
||||
|
||||
yield waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
text: "foobarCssParser",
|
||||
category: CATEGORY_CSS,
|
||||
severity: SEVERITY_WARNING,
|
||||
}],
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
hud.setFilterState("cssparser", false);
|
||||
|
||||
let msg = "the unknown CSS property warning is not displayed, " +
|
||||
"after filtering";
|
||||
testLogEntry(hud.outputNode, "foobarCssParser", msg, true, true);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
|
||||
"@mozilla.org/xre/app-info;1", "nsICrashReporter");
|
||||
#endif
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CrashMonitor",
|
||||
"resource://gre/modules/CrashMonitor.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
|
||||
"@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
|
||||
|
||||
@ -76,6 +79,25 @@ SessionStore.prototype = {
|
||||
// swallow exception that occurs if metro-tabs measure is already set up
|
||||
}
|
||||
|
||||
CrashMonitor.previousCheckpoints.then(checkpoints => {
|
||||
let previousSessionCrashed = false;
|
||||
|
||||
if (checkpoints) {
|
||||
// If the previous session finished writing the final state, we'll
|
||||
// assume there was no crash.
|
||||
previousSessionCrashed = !checkpoints["sessionstore-final-state-write-complete"];
|
||||
} else {
|
||||
// If no checkpoints are saved, this is the first run with CrashMonitor or the
|
||||
// metroSessionCheckpoints file was corrupted/deleted, so fallback to defining
|
||||
// a crash as init-ing with an unexpected previousExecutionState
|
||||
// 1 == RUNNING, 2 == SUSPENDED
|
||||
previousSessionCrashed = Services.metro.previousExecutionState == 1 ||
|
||||
Services.metro.previousExecutionState == 2;
|
||||
}
|
||||
|
||||
Services.telemetry.getHistogramById("SHUTDOWN_OK").add(!previousSessionCrashed);
|
||||
});
|
||||
|
||||
try {
|
||||
let shutdownWasUnclean = false;
|
||||
|
||||
@ -291,8 +313,8 @@ SessionStore.prototype = {
|
||||
if (this._saveTimer) {
|
||||
this._saveTimer.cancel();
|
||||
this._saveTimer = null;
|
||||
this.saveState();
|
||||
}
|
||||
this.saveState();
|
||||
break;
|
||||
case "browser:purge-session-history": // catch sanitization
|
||||
this._clearDisk();
|
||||
@ -644,6 +666,9 @@ SessionStore.prototype = {
|
||||
let istream = converter.convertToInputStream(aData);
|
||||
NetUtil.asyncCopy(istream, ostream, function(rc) {
|
||||
if (Components.isSuccessCode(rc)) {
|
||||
if (Services.startup.shuttingDown) {
|
||||
Services.obs.notifyObservers(null, "sessionstore-final-state-write-complete", "");
|
||||
}
|
||||
Services.obs.notifyObservers(null, "sessionstore-state-write-complete", "");
|
||||
}
|
||||
});
|
||||
|
@ -640,12 +640,6 @@ tabmodalprompt:not([promptType="promptUserAndPass"]) .infoContainer {
|
||||
|
||||
.meta {
|
||||
background-color: @panel_light_color@;
|
||||
/* bug 969354
|
||||
background-image: url("chrome://browser/skin/images/firefox-watermark.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-attachment: fixed;
|
||||
*/
|
||||
}
|
||||
|
||||
/* needs to observe the viewstate */
|
||||
|
@ -38,3 +38,19 @@
|
||||
#start-container[viewstate="snapped"] .meta-section:not([expanded]) > richgrid {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
/* Watermark */
|
||||
#startui-body::after {
|
||||
content: '';
|
||||
width: 256px;
|
||||
height: 256px;
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-top: -128px;
|
||||
margin-left: -128px;
|
||||
z-index: -1;
|
||||
background-image: url("chrome://browser/skin/images/firefox-watermark.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
|
@ -697,9 +697,13 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
||||
#sync-button {
|
||||
-moz-image-region: rect(0px 144px 24px 120px);
|
||||
}
|
||||
#sync-button[status="active"] {
|
||||
list-style-image: url("chrome://browser/skin/sync-24-throbber.png");
|
||||
-moz-image-region: rect(0px 24px 24px 0px);
|
||||
#sync-button[cui-areatype="toolbar"][status="active"] {
|
||||
list-style-image: url("chrome://browser/skin/syncProgress-toolbar.png");
|
||||
-moz-image-region: rect(0px 18px 18px 0px);
|
||||
}
|
||||
#sync-button[cui-areatype="menu-panel"][status="active"] {
|
||||
list-style-image: url("chrome://browser/skin/syncProgress-menuPanel.png");
|
||||
-moz-image-region: rect(0px 32px 32px 0px);
|
||||
}
|
||||
|
||||
#feed-button {
|
||||
|
@ -109,6 +109,10 @@
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.theme-light .ruleview-overridden {
|
||||
-moz-text-decoration-color: #667380; /* Content (Text) - Dark Grey */
|
||||
}
|
||||
|
||||
.styleinspector-propertyeditor {
|
||||
border: 1px solid #CCC;
|
||||
padding: 0;
|
||||
|
@ -269,15 +269,15 @@ browser.jar:
|
||||
skin/classic/browser/devtools/app-manager/noise.png (../shared/devtools/app-manager/images/noise.png)
|
||||
skin/classic/browser/devtools/app-manager/default-app-icon.png (../shared/devtools/app-manager/images/default-app-icon.png)
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/browser/sync-16-throbber.png
|
||||
skin/classic/browser/sync-16.png
|
||||
skin/classic/browser/sync-24-throbber.png
|
||||
skin/classic/browser/sync-32.png
|
||||
skin/classic/browser/sync-bg.png
|
||||
skin/classic/browser/sync-128.png
|
||||
skin/classic/browser/sync-desktopIcon.png
|
||||
skin/classic/browser/sync-mobileIcon.png
|
||||
skin/classic/browser/sync-notification-24.png
|
||||
skin/classic/browser/syncProgress-menuPanel.png
|
||||
skin/classic/browser/syncProgress-toolbar.png
|
||||
skin/classic/browser/syncSetup.css
|
||||
skin/classic/browser/syncCommon.css
|
||||
skin/classic/browser/syncQuota.css
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
BIN
browser/themes/linux/syncProgress-menuPanel.png
Normal file
BIN
browser/themes/linux/syncProgress-menuPanel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
browser/themes/linux/syncProgress-toolbar.png
Normal file
BIN
browser/themes/linux/syncProgress-toolbar.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 623 B |
@ -113,6 +113,10 @@
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.theme-light .ruleview-overridden {
|
||||
-moz-text-decoration-color: #667380; /* Content (Text) - Dark Grey */
|
||||
}
|
||||
|
||||
.styleinspector-propertyeditor {
|
||||
border: 1px solid #CCC;
|
||||
padding: 0;
|
||||
|
@ -104,6 +104,15 @@
|
||||
inset 0 1px rgb(196, 196, 196);
|
||||
}
|
||||
|
||||
#customization-undo-reset {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
%ifdef XP_MACOSX
|
||||
padding-top: 6px;
|
||||
%else
|
||||
padding-top: 7px;
|
||||
%endif
|
||||
}
|
||||
|
||||
#main-window[customize-entered] #customization-panel-container {
|
||||
background-image: url("chrome://browser/skin/customizableui/customizeMode-separatorHorizontal.png"),
|
||||
|
@ -109,6 +109,10 @@
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.theme-light .ruleview-overridden {
|
||||
-moz-text-decoration-color: #667380; /* Content (Text) - Dark Grey */
|
||||
}
|
||||
|
||||
.styleinspector-propertyeditor {
|
||||
border: 1px solid #CCC;
|
||||
padding: 0;
|
||||
|
@ -68,7 +68,7 @@ ac_echo_options() {
|
||||
|
||||
# Main
|
||||
#--------------------------------------------------
|
||||
topsrcdir=`dirname $0`
|
||||
topsrcdir=$(cd `dirname $0`; pwd -W 2>/dev/null || pwd)
|
||||
ac_options=
|
||||
mozconfig_ac_options=
|
||||
|
||||
|
@ -73,7 +73,7 @@ crashreporter
|
||||
Always defined.
|
||||
|
||||
datareporting
|
||||
Whether data reporting (MOZ_DATA_REPORTING) is enabled for this build.
|
||||
Whether data reporting (MOZ_DATA_REPORTING) is enabled for this build.
|
||||
|
||||
Values are ``true`` and ``false``.
|
||||
|
||||
@ -86,6 +86,13 @@ debug
|
||||
|
||||
Always defined.
|
||||
|
||||
healthreport
|
||||
Whether the Health Report feature is enabled.
|
||||
|
||||
Values are ``true`` and ``false``.
|
||||
|
||||
Always defined.
|
||||
|
||||
mozconfig
|
||||
The path of the :ref:`mozconfig file <mozconfig>` used to produce this build.
|
||||
|
||||
@ -133,3 +140,16 @@ topsrcdir
|
||||
|
||||
Always defined.
|
||||
|
||||
wave
|
||||
Whether Wave audio support is enabled.
|
||||
|
||||
Values are ``true`` and ``false``.
|
||||
|
||||
Always defined.
|
||||
|
||||
webm
|
||||
Whether WebM support is enabled.
|
||||
|
||||
Values are ``true`` and ``false``.
|
||||
|
||||
Always defined.
|
||||
|
26
build/mozconfig.cache
Normal file
26
build/mozconfig.cache
Normal file
@ -0,0 +1,26 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Setup for build cache
|
||||
|
||||
bucket=
|
||||
if test -f "$topsrcdir/sccache/sccache.py"; then
|
||||
case `hostname` in
|
||||
try*spot*.use1.mozilla.com|try*ec2*.use1.mozilla.com)
|
||||
bucket=mozilla-releng-s3-cache-us-east-1-try
|
||||
;;
|
||||
try*spot*.usw2.mozilla.com|try*ec2*.usw2.mozilla.com)
|
||||
bucket=mozilla-releng-s3-cache-us-west-2-try
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test -z "$bucket"; then
|
||||
ac_add_options --with-ccache
|
||||
else
|
||||
mk_add_options "export SCCACHE_BUCKET=$bucket"
|
||||
mk_add_options "export SCCACHE_NAMESERVER=169.254.169.253"
|
||||
export CC="python2.7 $topsrcdir/sccache/sccache.py $CC"
|
||||
export CXX="python2.7 $topsrcdir/sccache/sccache.py $CXX"
|
||||
fi
|
22
configure.in
22
configure.in
@ -1455,8 +1455,12 @@ if test "$GNU_CXX"; then
|
||||
|
||||
# Turn off the following warnings that -Wall turns on:
|
||||
# -Wno-invalid-offsetof - we use offsetof on non-POD types frequently
|
||||
# -Wno-inline-new-delete - we inline 'new' and 'delete' in mozalloc
|
||||
# for performance reasons, and because GCC and clang accept it (though
|
||||
# clang warns about it).
|
||||
#
|
||||
MOZ_CXX_SUPPORTS_WARNING(-Wno-, invalid-offsetof, ac_cxx_has_wno_invalid_offsetof)
|
||||
MOZ_CXX_SUPPORTS_WARNING(-Wno-, inline-new-delete, ac_cxx_has_wno_inline_new_delete)
|
||||
|
||||
if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then
|
||||
# Don't use -Wcast-align with ICC or clang
|
||||
@ -5509,6 +5513,8 @@ MOZ_ARG_ENABLE_STRING(gstreamer,
|
||||
# API version, eg 0.10, 1.0 etc
|
||||
if test -z "$enableval" -o "$enableval" = "yes"; then
|
||||
GST_API_VERSION=0.10
|
||||
elif test "$enableval" = "no"; then
|
||||
MOZ_GSTREAMER=
|
||||
else
|
||||
GST_API_VERSION=$enableval
|
||||
fi],
|
||||
@ -7683,14 +7689,6 @@ dnl =
|
||||
dnl ========================================================
|
||||
MOZ_ARG_HEADER(Static build options)
|
||||
|
||||
if test -n "$JS_SHARED_LIBRARY"; then
|
||||
MOZ_JS_LIBS="$MOZ_JS_SHARED_LIBS"
|
||||
else
|
||||
MOZ_JS_LIBS="$MOZ_JS_STATIC_LIBS"
|
||||
AC_DEFINE(MOZ_STATIC_JS)
|
||||
fi
|
||||
AC_SUBST(JS_SHARED_LIBRARY)
|
||||
|
||||
AC_SUBST(LIBXUL_LIBS)
|
||||
XPCOM_LIBS="$LIBXUL_LIBS"
|
||||
|
||||
@ -8746,6 +8744,14 @@ if test -n "$MOZ_NATIVE_ICU"; then
|
||||
MOZ_JS_STATIC_LIBS="$MOZ_JS_STATIC_LIBS $MOZ_ICU_LIBS"
|
||||
fi
|
||||
|
||||
if test -n "$JS_SHARED_LIBRARY"; then
|
||||
MOZ_JS_LIBS="$MOZ_JS_SHARED_LIBS"
|
||||
else
|
||||
MOZ_JS_LIBS="$MOZ_JS_STATIC_LIBS"
|
||||
AC_DEFINE(MOZ_STATIC_JS)
|
||||
fi
|
||||
AC_SUBST(JS_SHARED_LIBRARY)
|
||||
|
||||
MOZ_CREATE_CONFIG_STATUS()
|
||||
|
||||
# No need to run subconfigures when building with LIBXUL_SDK_DIR
|
||||
|
@ -1640,17 +1640,16 @@ public:
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
|
||||
nsISupports *native, const nsIID* aIID,
|
||||
JS::MutableHandle<JS::Value> vp,
|
||||
bool aAllowWrapping = false)
|
||||
JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
return WrapNative(cx, scope, native, nullptr, aIID, vp, aAllowWrapping);
|
||||
return WrapNative(cx, scope, native, nullptr, aIID, vp, true);
|
||||
}
|
||||
|
||||
// Same as the WrapNative above, but use this one if aIID is nsISupports' IID.
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
|
||||
nsISupports *native, JS::MutableHandle<JS::Value> vp,
|
||||
bool aAllowWrapping = false)
|
||||
bool aAllowWrapping = true)
|
||||
{
|
||||
return WrapNative(cx, scope, native, nullptr, nullptr, vp, aAllowWrapping);
|
||||
}
|
||||
@ -1659,7 +1658,7 @@ public:
|
||||
static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
|
||||
nsISupports *native, nsWrapperCache *cache,
|
||||
JS::MutableHandle<JS::Value> vp,
|
||||
bool aAllowWrapping = false)
|
||||
bool aAllowWrapping = true)
|
||||
{
|
||||
return WrapNative(cx, scope, native, cache, nullptr, vp, aAllowWrapping);
|
||||
}
|
||||
|
@ -5672,7 +5672,7 @@ nsContentUtils::CreateBlobBuffer(JSContext* aCx,
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
return nsContentUtils::WrapNative(aCx, scope, blob, aBlob, true);
|
||||
return nsContentUtils::WrapNative(aCx, scope, blob, aBlob);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -11447,7 +11447,7 @@ nsDocument::Evaluate(const nsAString& aExpression, nsIDOMNode* aContextNode,
|
||||
{
|
||||
return XPathEvaluator()->Evaluate(aExpression, aContextNode, aResolver, aType,
|
||||
aInResult, aResult);
|
||||
}
|
||||
}
|
||||
|
||||
// This is just a hack around the fact that window.document is not
|
||||
// [Unforgeable] yet.
|
||||
@ -11477,13 +11477,15 @@ nsIDocument::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aScope)
|
||||
JS::Rooted<JS::Value> winVal(aCx);
|
||||
nsresult rv = nsContentUtils::WrapNative(aCx, obj, win,
|
||||
&NS_GET_IID(nsIDOMWindow),
|
||||
&winVal,
|
||||
false);
|
||||
&winVal);
|
||||
if (NS_FAILED(rv)) {
|
||||
Throw(aCx, rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(&winVal.toObject() == js::UncheckedUnwrap(&winVal.toObject()),
|
||||
"WrapNative shouldn't create a cross-compartment wrapper");
|
||||
|
||||
NS_NAMED_LITERAL_STRING(doc_str, "document");
|
||||
|
||||
if (!JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(winVal), doc_str.get(),
|
||||
|
@ -927,7 +927,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||
|
||||
JS::Rooted<JS::Value> targetv(cx);
|
||||
JS::Rooted<JSObject*> global(cx, JS_GetGlobalForObject(cx, object));
|
||||
nsresult rv = nsContentUtils::WrapNative(cx, global, aTarget, &targetv, true);
|
||||
nsresult rv = nsContentUtils::WrapNative(cx, global, aTarget, &targetv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JS::Rooted<JSObject*> cpows(cx);
|
||||
@ -1018,7 +1018,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||
defaultThisValue = aTarget;
|
||||
}
|
||||
JS::Rooted<JSObject*> global(cx, JS_GetGlobalForObject(cx, object));
|
||||
nsresult rv = nsContentUtils::WrapNative(cx, global, defaultThisValue, &thisValue, true);
|
||||
nsresult rv = nsContentUtils::WrapNative(cx, global, defaultThisValue, &thisValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
// If the listener is a JS object which has receiveMessage function:
|
||||
|
@ -992,8 +992,7 @@ nsXMLHttpRequest::GetResponse(JSContext* aCx, ErrorResult& aRv)
|
||||
|
||||
JS::Rooted<JS::Value> result(aCx, JSVAL_NULL);
|
||||
JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
aRv = nsContentUtils::WrapNative(aCx, scope, mResponseBlob, &result,
|
||||
true);
|
||||
aRv = nsContentUtils::WrapNative(aCx, scope, mResponseBlob, &result);
|
||||
return result;
|
||||
}
|
||||
case XML_HTTP_RESPONSE_TYPE_DOCUMENT:
|
||||
@ -1004,8 +1003,7 @@ nsXMLHttpRequest::GetResponse(JSContext* aCx, ErrorResult& aRv)
|
||||
|
||||
JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
JS::Rooted<JS::Value> result(aCx, JSVAL_NULL);
|
||||
aRv = nsContentUtils::WrapNative(aCx, scope, mResponseXML, &result,
|
||||
true);
|
||||
aRv = nsContentUtils::WrapNative(aCx, scope, mResponseXML, &result);
|
||||
return result;
|
||||
}
|
||||
case XML_HTTP_RESPONSE_TYPE_JSON:
|
||||
|
@ -37,10 +37,11 @@ const JSClass sHTMLDocumentAllClass = {
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
nsHTMLDocumentSH::DocumentAllGetProperty, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub, /* enumerate */
|
||||
(JSResolveOp)nsHTMLDocumentSH::DocumentAllNewResolve, /* resolve */
|
||||
JS_ConvertStub, /* convert */
|
||||
nsHTMLDocumentSH::ReleaseDocument /* finalize */
|
||||
JS_EnumerateStub,
|
||||
(JSResolveOp)nsHTMLDocumentSH::DocumentAllNewResolve,
|
||||
JS_ConvertStub,
|
||||
nsHTMLDocumentSH::ReleaseDocument,
|
||||
nsHTMLDocumentSH::CallToGetPropMapper
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
@ -371,12 +372,14 @@ bool
|
||||
nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
// Handle document.all("foo") style access to document.all.
|
||||
|
||||
if (args.length() != 1) {
|
||||
// XXX: Should throw NS_ERROR_XPC_NOT_ENOUGH_ARGS for argc < 1,
|
||||
// and create a new NS_ERROR_XPC_TOO_MANY_ARGS for argc > 1? IE
|
||||
// accepts nothing other than one arg.
|
||||
xpc::Throw(cx, NS_ERROR_INVALID_ARG);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -386,9 +389,16 @@ nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, unsigned argc, jsval *vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> self(cx, JS_THIS_OBJECT(cx, vp));
|
||||
if (!self) {
|
||||
return false;
|
||||
// If we are called via document.all(id) instead of document.all.item(i) or
|
||||
// another method, use the document.all callee object as self.
|
||||
JS::Rooted<JSObject*> self(cx);
|
||||
if (args.calleev().isObject() &&
|
||||
JS_GetClass(&args.calleev().toObject()) == &sHTMLDocumentAllClass) {
|
||||
self = &args.calleev().toObject();
|
||||
} else {
|
||||
self = JS_THIS_OBJECT(cx, vp);
|
||||
if (!self)
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t length;
|
||||
|
@ -153,6 +153,16 @@ ChannelMediaResource::OnStartRequest(nsIRequest* aRequest)
|
||||
nsresult rv = aRequest->GetStatus(&status);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (status == NS_BINDING_ABORTED) {
|
||||
// Request was aborted before we had a chance to receive any data, or
|
||||
// even an OnStartRequest(). Close the channel. This is important, as
|
||||
// we don't want to mess up our state, as if we're cloned that would
|
||||
// cause the clone to copy incorrect metadata (like whether we're
|
||||
// infinite for example).
|
||||
CloseChannel();
|
||||
return status;
|
||||
}
|
||||
|
||||
if (element->ShouldCheckAllowOrigin()) {
|
||||
// If the request was cancelled by nsCORSListenerProxy due to failing
|
||||
// the CORS security check, send an error through to the media element.
|
||||
|
@ -1602,7 +1602,7 @@ Navigator::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
|
||||
}
|
||||
|
||||
if (JSVAL_IS_PRIMITIVE(prop_val) && !JSVAL_IS_NULL(prop_val)) {
|
||||
rv = nsContentUtils::WrapNative(aCx, aObject, native, &prop_val, true);
|
||||
rv = nsContentUtils::WrapNative(aCx, aObject, native, &prop_val);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return Throw(aCx, rv);
|
||||
|
@ -15,7 +15,7 @@
|
||||
"use strict";
|
||||
|
||||
try {
|
||||
document.all.item();
|
||||
document.all();
|
||||
} catch (e) {
|
||||
is(typeof e, "object");
|
||||
is(e.filename, location);
|
||||
|
@ -276,6 +276,25 @@ static uint64_t gContentChildID = 1;
|
||||
// Can't be a static constant.
|
||||
#define MAGIC_PREALLOCATED_APP_MANIFEST_URL NS_LITERAL_STRING("{{template}}")
|
||||
|
||||
static const char* sObserverTopics[] = {
|
||||
"xpcom-shutdown",
|
||||
NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
|
||||
"child-memory-reporter-request",
|
||||
"memory-pressure",
|
||||
"child-gc-request",
|
||||
"child-cc-request",
|
||||
"child-mmu-request",
|
||||
"last-pb-context-exited",
|
||||
"file-watcher-update",
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
NS_VOLUME_STATE_CHANGED,
|
||||
"phone-state-changed",
|
||||
#endif
|
||||
#ifdef ACCESSIBILITY
|
||||
"a11y-init-or-shutdown",
|
||||
#endif
|
||||
};
|
||||
|
||||
/* static */ already_AddRefed<ContentParent>
|
||||
ContentParent::RunNuwaProcess()
|
||||
{
|
||||
@ -652,22 +671,10 @@ ContentParent::Init()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(this, "xpcom-shutdown", false);
|
||||
obs->AddObserver(this, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, false);
|
||||
obs->AddObserver(this, "child-memory-reporter-request", false);
|
||||
obs->AddObserver(this, "memory-pressure", false);
|
||||
obs->AddObserver(this, "child-gc-request", false);
|
||||
obs->AddObserver(this, "child-cc-request", false);
|
||||
obs->AddObserver(this, "child-mmu-request", false);
|
||||
obs->AddObserver(this, "last-pb-context-exited", false);
|
||||
obs->AddObserver(this, "file-watcher-update", false);
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false);
|
||||
obs->AddObserver(this, "phone-state-changed", false);
|
||||
#endif
|
||||
#ifdef ACCESSIBILITY
|
||||
obs->AddObserver(this, "a11y-init-or-shutdown", false);
|
||||
#endif
|
||||
size_t length = ArrayLength(sObserverTopics);
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
obs->AddObserver(this, sObserverTopics[i], false);
|
||||
}
|
||||
}
|
||||
Preferences::AddStrongObserver(this, "");
|
||||
nsCOMPtr<nsIThreadInternal>
|
||||
@ -1036,22 +1043,11 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
||||
kungFuDeathGrip(static_cast<nsIThreadObserver*>(this));
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this), "xpcom-shutdown");
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this), "memory-pressure");
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-memory-reporter-request");
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this), NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC);
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-gc-request");
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-cc-request");
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-mmu-request");
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this), "last-pb-context-exited");
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this), "file-watcher-update");
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this), NS_VOLUME_STATE_CHANGED);
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this), "phone-state-changed");
|
||||
#endif
|
||||
#ifdef ACCESSIBILITY
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this), "a11y-init-or-shutdown");
|
||||
#endif
|
||||
size_t length = ArrayLength(sObserverTopics);
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
obs->RemoveObserver(static_cast<nsIObserver*>(this),
|
||||
sObserverTopics[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (ppm) {
|
||||
|
@ -178,7 +178,8 @@ nsXBLProtoImpl::InitTargetObjects(nsXBLPrototypeBinding* aBinding,
|
||||
bool defineOnGlobal = dom::XULElementBinding::ConstructorEnabled(cx, global);
|
||||
dom::XULElementBinding::GetConstructorObject(cx, global, defineOnGlobal);
|
||||
|
||||
rv = nsContentUtils::WrapNative(cx, global, aBoundElement, &v);
|
||||
rv = nsContentUtils::WrapNative(cx, global, aBoundElement, &v,
|
||||
/* aAllowWrapping = */ false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JS::Rooted<JSObject*> value(cx, &v.toObject());
|
||||
|
@ -307,8 +307,7 @@ nsXBLPrototypeHandler::ExecuteHandler(EventTarget* aTarget,
|
||||
// scope if one doesn't already exist, and potentially wraps it cross-
|
||||
// compartment into our scope (via aAllowWrapping=true).
|
||||
JS::Rooted<JS::Value> targetV(cx, JS::UndefinedValue());
|
||||
rv = nsContentUtils::WrapNative(cx, scopeObject, scriptTarget, &targetV,
|
||||
/* aAllowWrapping = */ true);
|
||||
rv = nsContentUtils::WrapNative(cx, scopeObject, scriptTarget, &targetV);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Next, clone the generic handler to be parented to the target.
|
||||
|
@ -444,10 +444,12 @@ LayerManagerComposite::Render()
|
||||
/** Our more efficient but less powerful alter ego, if one is available. */
|
||||
nsRefPtr<Composer2D> composer2D = mCompositor->GetWidget()->GetComposer2D();
|
||||
|
||||
if (mFPS && composer2D && composer2D->TryRender(mRoot, mWorldMatrix)) {
|
||||
double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
|
||||
if (gfxPlatform::GetPrefLayersDrawFPS()) {
|
||||
printf_stderr("HWComposer: FPS is %g\n", fps);
|
||||
if (composer2D && composer2D->TryRender(mRoot, mWorldMatrix)) {
|
||||
if (mFPS) {
|
||||
double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
|
||||
if (gfxPlatform::GetPrefLayersDrawFPS()) {
|
||||
printf_stderr("HWComposer: FPS is %g\n", fps);
|
||||
}
|
||||
}
|
||||
mCompositor->EndFrameForExternalComposition(mWorldMatrix);
|
||||
return;
|
||||
|
@ -1274,12 +1274,30 @@ CairoTextureClientD3D9::Lock(OpenMode)
|
||||
if (!IsValid() || !IsAllocated()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
|
||||
// If the device has failed then we should not lock the surface,
|
||||
// even if we could.
|
||||
mD3D9Surface = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mD3D9Surface) {
|
||||
HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(mD3D9Surface));
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to get texture surface level.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mIsLocked = true;
|
||||
|
||||
if (mNeedsClear) {
|
||||
mDrawTarget = GetAsDrawTarget();
|
||||
mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
|
||||
mNeedsClear = false;
|
||||
}
|
||||
mIsLocked = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1318,27 +1336,11 @@ CairoTextureClientD3D9::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
|
||||
TemporaryRef<gfx::DrawTarget>
|
||||
CairoTextureClientD3D9::GetAsDrawTarget()
|
||||
{
|
||||
MOZ_ASSERT(mIsLocked && mTexture);
|
||||
MOZ_ASSERT(mIsLocked && mD3D9Surface);
|
||||
if (mDrawTarget) {
|
||||
return mDrawTarget;
|
||||
}
|
||||
|
||||
if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
|
||||
// If the device has failed then we should not lock the surface,
|
||||
// even if we could.
|
||||
mD3D9Surface = nullptr;
|
||||
mTexture = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mD3D9Surface) {
|
||||
HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(mD3D9Surface));
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to get texture surface level.");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (ContentForFormat(mFormat) == gfxContentType::COLOR) {
|
||||
mSurface = new gfxWindowsSurface(mD3D9Surface);
|
||||
if (!mSurface || mSurface->CairoStatus()) {
|
||||
|
10
js/src/jit-test/tests/parallel/bug971385.js
Normal file
10
js/src/jit-test/tests/parallel/bug971385.js
Normal file
@ -0,0 +1,10 @@
|
||||
// |jit-test| slow;
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
function f() {
|
||||
Array.buildPar(6, function() {});
|
||||
f();
|
||||
}
|
||||
|
||||
if (getBuildConfiguration().parallelJS)
|
||||
assertThrowsInstanceOf(f, InternalError);
|
@ -975,6 +975,16 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
||||
IonSpew(IonSpew_BaselineBailouts, " Set resumeAddr=%p", opReturnAddr);
|
||||
}
|
||||
|
||||
if (cx->runtime()->spsProfiler.enabled() && blFrame->hasPushedSPSFrame()) {
|
||||
// Set PC index to 0 for the innermost frame to match what the
|
||||
// interpreter and Baseline do: they update the SPS pc for
|
||||
// JSOP_CALL ops but set it to 0 when running other ops. Ion code
|
||||
// can set the pc to NullPCIndex and this will confuse SPS when
|
||||
// Baseline calls into the VM at non-CALL ops and re-enters JS.
|
||||
IonSpew(IonSpew_BaselineBailouts, " Setting PCidx for last frame to 0");
|
||||
cx->runtime()->spsProfiler.updatePC(script, script->code());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1213,7 +1213,7 @@ GetPropertyIC::tryAttachNative(JSContext *cx, IonScript *ion, HandleObject obj,
|
||||
|
||||
*emitted = true;
|
||||
|
||||
MacroAssembler masm(cx, ion);
|
||||
MacroAssembler masm(cx, ion, script_, pc_);
|
||||
SkipRoot skip(cx, &masm);
|
||||
|
||||
RepatchStubAppender attacher(*this);
|
||||
@ -1370,7 +1370,7 @@ GetPropertyIC::tryAttachDOMProxyShadowed(JSContext *cx, IonScript *ion,
|
||||
*emitted = true;
|
||||
|
||||
Label failures;
|
||||
MacroAssembler masm(cx, ion);
|
||||
MacroAssembler masm(cx, ion, script_, pc_);
|
||||
RepatchStubAppender attacher(*this);
|
||||
|
||||
// Guard on the shape of the object.
|
||||
@ -1437,7 +1437,7 @@ GetPropertyIC::tryAttachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, Handle
|
||||
}
|
||||
|
||||
Label failures;
|
||||
MacroAssembler masm(cx, ion);
|
||||
MacroAssembler masm(cx, ion, script_, pc_);
|
||||
RepatchStubAppender attacher(*this);
|
||||
|
||||
// Guard on the shape of the object.
|
||||
@ -1552,7 +1552,7 @@ GetPropertyIC::tryAttachGenericProxy(JSContext *cx, IonScript *ion, HandleObject
|
||||
*emitted = true;
|
||||
|
||||
Label failures;
|
||||
MacroAssembler masm(cx, ion);
|
||||
MacroAssembler masm(cx, ion, script_, pc_);
|
||||
RepatchStubAppender attacher(*this);
|
||||
|
||||
Register scratchReg = output().valueReg().scratchReg();
|
||||
@ -2120,7 +2120,7 @@ SetPropertyIC::attachGenericProxy(JSContext *cx, IonScript *ion, void *returnAdd
|
||||
{
|
||||
JS_ASSERT(!hasGenericProxyStub());
|
||||
|
||||
MacroAssembler masm(cx, ion);
|
||||
MacroAssembler masm(cx, ion, script_, pc_);
|
||||
RepatchStubAppender attacher(*this);
|
||||
|
||||
Label failures;
|
||||
@ -2177,7 +2177,7 @@ SetPropertyIC::attachDOMProxyShadowed(JSContext *cx, IonScript *ion, HandleObjec
|
||||
JS_ASSERT(IsCacheableDOMProxy(obj));
|
||||
|
||||
Label failures;
|
||||
MacroAssembler masm(cx, ion);
|
||||
MacroAssembler masm(cx, ion, script_, pc_);
|
||||
RepatchStubAppender attacher(*this);
|
||||
|
||||
// Guard on the shape of the object.
|
||||
@ -2407,7 +2407,7 @@ SetPropertyIC::attachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, HandleObj
|
||||
JS_ASSERT(IsCacheableDOMProxy(obj));
|
||||
|
||||
Label failures;
|
||||
MacroAssembler masm(cx, ion);
|
||||
MacroAssembler masm(cx, ion, script_, pc_);
|
||||
RepatchStubAppender attacher(*this);
|
||||
|
||||
// Guard on the shape of the object.
|
||||
@ -2462,7 +2462,7 @@ SetPropertyIC::attachCallSetter(JSContext *cx, IonScript *ion,
|
||||
{
|
||||
JS_ASSERT(obj->isNative());
|
||||
|
||||
MacroAssembler masm(cx, ion);
|
||||
MacroAssembler masm(cx, ion, script_, pc_);
|
||||
RepatchStubAppender attacher(*this);
|
||||
|
||||
Label failure;
|
||||
@ -4243,7 +4243,7 @@ bool
|
||||
NameIC::attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
|
||||
HandleShape shape, void *returnAddr)
|
||||
{
|
||||
MacroAssembler masm(cx, ion);
|
||||
MacroAssembler masm(cx, ion, script_, pc_);
|
||||
|
||||
RepatchStubAppender attacher(*this);
|
||||
if (!GenerateCallGetter(cx, ion, masm, attacher, obj, name(), holder, shape, liveRegs_,
|
||||
|
@ -172,6 +172,10 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
bool enoughMemory_;
|
||||
bool embedsNurseryPointers_;
|
||||
|
||||
// SPS instrumentation, only used for Ion caches.
|
||||
mozilla::Maybe<IonInstrumentation> spsInstrumentation_;
|
||||
jsbytecode *spsPc_;
|
||||
|
||||
private:
|
||||
// This field is used to manage profiling instrumentation output. If
|
||||
// provided and enabled, then instrumentation will be emitted around call
|
||||
@ -212,7 +216,8 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
|
||||
// This constructor should only be used when there is no IonContext active
|
||||
// (for example, Trampoline-$(ARCH).cpp and IonCaches.cpp).
|
||||
MacroAssembler(JSContext *cx, IonScript *ion = nullptr)
|
||||
MacroAssembler(JSContext *cx, IonScript *ion = nullptr,
|
||||
JSScript *script = nullptr, jsbytecode *pc = nullptr)
|
||||
: enoughMemory_(true),
|
||||
embedsNurseryPointers_(false),
|
||||
sps_(nullptr)
|
||||
@ -225,8 +230,17 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
initWithAllocator();
|
||||
m_buffer.id = GetIonContext()->getNextAssemblerId();
|
||||
#endif
|
||||
if (ion)
|
||||
if (ion) {
|
||||
setFramePushed(ion->frameSize());
|
||||
if (pc && cx->runtime()->spsProfiler.enabled()) {
|
||||
// We have to update the SPS pc when this IC stub calls into
|
||||
// the VM.
|
||||
spsPc_ = pc;
|
||||
spsInstrumentation_.construct(&cx->runtime()->spsProfiler, &spsPc_);
|
||||
sps_ = spsInstrumentation_.addr();
|
||||
sps_->setPushed(script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// asm.js compilation handles its own IonContet-pushing
|
||||
|
@ -29,6 +29,7 @@ UNIFIED_SOURCES += [
|
||||
'testException.cpp',
|
||||
'testExternalStrings.cpp',
|
||||
'testFindSCCs.cpp',
|
||||
'testFreshGlobalEvalRedefinition.cpp',
|
||||
'testFuncCallback.cpp',
|
||||
'testFunctionProperties.cpp',
|
||||
'testGCExactRooting.cpp',
|
||||
|
47
js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp
Normal file
47
js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
static bool
|
||||
GlobalEnumerate(JSContext *cx, JS::Handle<JSObject*> obj)
|
||||
{
|
||||
return JS_EnumerateStandardClasses(cx, obj);
|
||||
}
|
||||
|
||||
static bool
|
||||
GlobalResolve(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id)
|
||||
{
|
||||
bool resolved = false;
|
||||
return JS_ResolveStandardClass(cx, obj, id, &resolved);
|
||||
}
|
||||
|
||||
BEGIN_TEST(testRedefineGlobalEval)
|
||||
{
|
||||
static const JSClass cls = {
|
||||
"global", JSCLASS_GLOBAL_FLAGS,
|
||||
JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
|
||||
GlobalEnumerate, GlobalResolve, JS_ConvertStub
|
||||
};
|
||||
|
||||
/* Create the global object. */
|
||||
JS::CompartmentOptions options;
|
||||
options.setVersion(JSVERSION_LATEST);
|
||||
JS::Rooted<JSObject*> g(cx, JS_NewGlobalObject(cx, &cls, nullptr, JS::FireOnNewGlobalHook, options));
|
||||
if (!g)
|
||||
return false;
|
||||
|
||||
JSAutoCompartment ac(cx, g);
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
CHECK(JS_GetProperty(cx, g, "Object", &v));
|
||||
|
||||
static const char data[] = "Object.defineProperty(this, 'eval', { configurable: false });";
|
||||
CHECK(JS_EvaluateScript(cx, g, data, mozilla::ArrayLength(data) - 1, __FILE__, __LINE__, v.address()));
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testRedefineGlobalEval)
|
@ -27,7 +27,9 @@ CONFIGURE_SUBST_FILES += [
|
||||
'js.pc',
|
||||
]
|
||||
|
||||
if not CONFIG['JS_STANDALONE']:
|
||||
if CONFIG['JS_STANDALONE']:
|
||||
DEFINES['IMPL_MFBT'] = True
|
||||
else:
|
||||
CONFIGURE_SUBST_FILES += [
|
||||
'../../config/autoconf-js.mk',
|
||||
'../../config/emptyvars-js.mk',
|
||||
|
28
js/src/tests/ecma_5/Exceptions/error-expando-reconfigure.js
Normal file
28
js/src/tests/ecma_5/Exceptions/error-expando-reconfigure.js
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var gTestfile = "error-expando-reconfigure.js"
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 961494;
|
||||
var summary =
|
||||
"Reconfiguring the first expando property added to an Error object " +
|
||||
"shouldn't assert";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
var err = new Error(); // no message argument => no err.message property
|
||||
err.expando = 17;
|
||||
Object.defineProperty(err, "expando", { configurable: false });
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
@ -130,8 +130,17 @@ SPSProfiler::enter(JSScript *script, JSFunction *maybeFun)
|
||||
if (str == nullptr)
|
||||
return false;
|
||||
|
||||
JS_ASSERT_IF(*size_ > 0 && *size_ - 1 < max_ && stack_[*size_ - 1].js(),
|
||||
stack_[*size_ - 1].pc() != nullptr);
|
||||
#ifdef DEBUG
|
||||
// In debug builds, assert the JS pseudo frames already on the stack
|
||||
// have a non-null pc. Only look at the top frames to avoid quadratic
|
||||
// behavior.
|
||||
if (*size_ > 0 && *size_ - 1 < max_) {
|
||||
size_t start = (*size_ > 4) ? *size_ - 4 : 0;
|
||||
for (size_t i = start; i < *size_ - 1; i++)
|
||||
MOZ_ASSERT_IF(stack_[i].js(), stack_[i].pc() != nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
push(str, nullptr, script, script->code());
|
||||
return true;
|
||||
}
|
||||
|
@ -352,10 +352,20 @@ JSObject::getChildPropertyOnDictionary(ThreadSafeContext *cx, JS::HandleObject o
|
||||
return nullptr;
|
||||
child.setSlot(slot);
|
||||
} else {
|
||||
/* Slots can only be allocated out of order on objects in dictionary mode. */
|
||||
/*
|
||||
* Slots can only be allocated out of order on objects in
|
||||
* dictionary mode. Otherwise the child's slot must be after the
|
||||
* parent's slot (if it has one), because slot number determines
|
||||
* slot span for objects with that shape. Usually child slot
|
||||
* *immediately* follows parent slot, but there may be a slot gap
|
||||
* when the object uses some -- but not all -- of its reserved
|
||||
* slots to store properties.
|
||||
*/
|
||||
JS_ASSERT(obj->inDictionaryMode() ||
|
||||
parent->hasMissingSlot() ||
|
||||
child.slot() == parent->maybeSlot() + 1);
|
||||
child.slot() == parent->maybeSlot() + 1 ||
|
||||
(parent->maybeSlot() + 1 < JSSLOT_FREE(obj->getClass()) &&
|
||||
child.slot() == JSSLOT_FREE(obj->getClass())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -549,6 +549,12 @@ ScriptFrameIter::settleOnActivation()
|
||||
data_.state_ = JIT;
|
||||
return;
|
||||
}
|
||||
|
||||
// ForkJoin activations don't contain iterable frames, so skip them.
|
||||
if (activation->isForkJoin()) {
|
||||
++data_.activations_;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
JS_ASSERT(activation->isInterpreter());
|
||||
|
@ -32,7 +32,7 @@ nsTArrayToJSArray(JSContext* aCx, const nsTArray<T>& aSourceArray,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JS::RootedValue wrappedVal(aCx);
|
||||
rv = nsContentUtils::WrapNative(aCx, global, obj, &wrappedVal, true);
|
||||
rv = nsContentUtils::WrapNative(aCx, global, obj, &wrappedVal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!JS_SetElement(aCx, arrayObj, index, wrappedVal)) {
|
||||
|
@ -379,8 +379,6 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
{
|
||||
NS_PRECONDITION(d, "bad param");
|
||||
|
||||
bool isDOMString = true;
|
||||
|
||||
AutoJSContext cx;
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
@ -473,81 +471,62 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
|
||||
case nsXPTType::T_ASTRING:
|
||||
{
|
||||
isDOMString = false;
|
||||
if (JSVAL_IS_VOID(s)) {
|
||||
if (useAllocator)
|
||||
*((const nsAString**)d) = &NullString();
|
||||
else
|
||||
(**((nsAString**)d)).SetIsVoid(true);
|
||||
return true;
|
||||
}
|
||||
// Fall through to T_DOMSTRING case.
|
||||
}
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
{
|
||||
static const char16_t EMPTY_STRING[] = { '\0' };
|
||||
static const char16_t VOID_STRING[] = { 'u', 'n', 'd', 'e', 'f', 'i', 'n', 'e', 'd', '\0' };
|
||||
|
||||
if (JSVAL_IS_NULL(s)) {
|
||||
if (useAllocator)
|
||||
*((const nsAString**)d) = &NullString();
|
||||
else
|
||||
(**((nsAString**)d)).SetIsVoid(true);
|
||||
return true;
|
||||
}
|
||||
size_t length = 0;
|
||||
const char16_t* chars = nullptr;
|
||||
JSString* str = nullptr;
|
||||
bool isNewString = false;
|
||||
uint32_t length = 0;
|
||||
|
||||
if (JSVAL_IS_VOID(s)) {
|
||||
if (isDOMString) {
|
||||
chars = VOID_STRING;
|
||||
length = ArrayLength(VOID_STRING) - 1;
|
||||
} else {
|
||||
chars = EMPTY_STRING;
|
||||
length = 0;
|
||||
}
|
||||
} else if (!JSVAL_IS_NULL(s)) {
|
||||
if (!JSVAL_IS_VOID(s)) {
|
||||
str = ToString(cx, s);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
length = (uint32_t) JS_GetStringLength(str);
|
||||
if (length) {
|
||||
chars = JS_GetStringCharsZ(cx, str);
|
||||
if (!chars)
|
||||
return false;
|
||||
if (STRING_TO_JSVAL(str) != s)
|
||||
isNewString = true;
|
||||
} else {
|
||||
str = nullptr;
|
||||
chars = EMPTY_STRING;
|
||||
chars = useAllocator ? JS_GetStringCharsZAndLength(cx, str, &length)
|
||||
: JS_GetStringCharsAndLength(cx, str, &length);
|
||||
if (!chars)
|
||||
return false;
|
||||
|
||||
if (!length) {
|
||||
if (useAllocator)
|
||||
*((const nsAString**)d) = &EmptyString();
|
||||
else
|
||||
(**((nsAString**)d)).Truncate();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
nsString* ws;
|
||||
if (useAllocator) {
|
||||
// XXX extra string copy when isNewString
|
||||
if (str && !isNewString) {
|
||||
size_t strLength;
|
||||
const jschar *strChars = JS_GetStringCharsZAndLength(cx, str, &strLength);
|
||||
if (!strChars)
|
||||
return false;
|
||||
|
||||
XPCReadableJSStringWrapper *wrapper =
|
||||
nsXPConnect::GetRuntimeInstance()->NewStringWrapper(strChars, strLength);
|
||||
if (!wrapper)
|
||||
return false;
|
||||
|
||||
*((const nsAString**)d) = wrapper;
|
||||
} else if (JSVAL_IS_NULL(s)) {
|
||||
XPCReadableJSStringWrapper *wrapper =
|
||||
new XPCReadableJSStringWrapper();
|
||||
if (!wrapper)
|
||||
return false;
|
||||
|
||||
*((const nsAString**)d) = wrapper;
|
||||
} else {
|
||||
// use nsString to encourage sharing
|
||||
const nsAString *rs = new nsString(chars, length);
|
||||
if (!rs)
|
||||
return false;
|
||||
*((const nsAString**)d) = rs;
|
||||
}
|
||||
ws = nsXPConnect::GetRuntimeInstance()->NewShortLivedString();
|
||||
*((const nsString**)d) = ws;
|
||||
} else {
|
||||
nsAString* ws = *((nsAString**)d);
|
||||
ws = *((nsString**)d);
|
||||
}
|
||||
|
||||
if (JSVAL_IS_NULL(s) || (!isDOMString && JSVAL_IS_VOID(s))) {
|
||||
ws->Truncate();
|
||||
ws->SetIsVoid(true);
|
||||
} else
|
||||
ws->Assign(chars, length);
|
||||
if (!str) {
|
||||
ws->AssignLiteral(MOZ_UTF16("undefined"));
|
||||
} else if (useAllocator && STRING_TO_JSVAL(str) == s) {
|
||||
// The JS string will exist over the function call.
|
||||
// We don't need to copy the characters in this case.
|
||||
ws->Rebind(chars, length);
|
||||
} else {
|
||||
ws->Assign(chars, length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -622,20 +601,14 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
{
|
||||
const jschar* chars;
|
||||
uint32_t length;
|
||||
size_t length;
|
||||
JSString* str;
|
||||
|
||||
if (JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s)) {
|
||||
if (useAllocator) {
|
||||
nsACString *rs = new nsCString();
|
||||
if (!rs)
|
||||
return false;
|
||||
|
||||
rs->SetIsVoid(true);
|
||||
*((nsACString**)d) = rs;
|
||||
*((const nsACString**)d) = &NullCString();
|
||||
} else {
|
||||
nsCString* rs = *((nsCString**)d);
|
||||
rs->Truncate();
|
||||
rs->SetIsVoid(true);
|
||||
}
|
||||
return true;
|
||||
@ -644,11 +617,19 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
// The JS val is neither null nor void...
|
||||
|
||||
if (!(str = ToString(cx, s))||
|
||||
!(chars = JS_GetStringCharsZ(cx, str))) {
|
||||
!(chars = JS_GetStringCharsAndLength(cx, str, &length))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
length = JS_GetStringLength(str);
|
||||
if (!length) {
|
||||
if (useAllocator) {
|
||||
*((const nsACString**)d) = &EmptyCString();
|
||||
} else {
|
||||
nsCString* rs = *((nsCString**)d);
|
||||
rs->Truncate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCString *rs;
|
||||
if (useAllocator) {
|
||||
@ -661,9 +642,7 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
} else {
|
||||
rs = *((nsCString**)d);
|
||||
}
|
||||
const char16_t* start = (const char16_t*)chars;
|
||||
const char16_t* end = start + length;
|
||||
CopyUTF16toUTF8(nsDependentSubstring(start, end), *rs);
|
||||
CopyUTF16toUTF8(Substring(chars, length), *rs);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -696,6 +675,16 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!length) {
|
||||
if (useAllocator) {
|
||||
*((const nsACString**)d) = &EmptyCString();
|
||||
} else {
|
||||
nsCString* rs = *((nsCString**)d);
|
||||
rs->Truncate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsACString *rs;
|
||||
if (useAllocator) {
|
||||
rs = new nsCString();
|
||||
|
@ -1415,38 +1415,32 @@ XPCJSRuntime::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
|
||||
return n;
|
||||
}
|
||||
|
||||
XPCReadableJSStringWrapper *
|
||||
XPCJSRuntime::NewStringWrapper(const char16_t *str, uint32_t len)
|
||||
nsString*
|
||||
XPCJSRuntime::NewShortLivedString()
|
||||
{
|
||||
for (uint32_t i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i) {
|
||||
StringWrapperEntry& ent = mScratchStrings[i];
|
||||
|
||||
if (!ent.mInUse) {
|
||||
ent.mInUse = true;
|
||||
|
||||
// Construct the string using placement new.
|
||||
|
||||
return new (ent.mString.addr()) XPCReadableJSStringWrapper(str, len);
|
||||
if (mScratchStrings[i].empty()) {
|
||||
mScratchStrings[i].construct();
|
||||
return mScratchStrings[i].addr();
|
||||
}
|
||||
}
|
||||
|
||||
// All our internal string wrappers are used, allocate a new string.
|
||||
|
||||
return new XPCReadableJSStringWrapper(str, len);
|
||||
return new nsString();
|
||||
}
|
||||
|
||||
void
|
||||
XPCJSRuntime::DeleteString(nsAString *string)
|
||||
XPCJSRuntime::DeleteShortLivedString(nsString *string)
|
||||
{
|
||||
if (string == &EmptyString() || string == &NullString())
|
||||
return;
|
||||
|
||||
for (uint32_t i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i) {
|
||||
StringWrapperEntry& ent = mScratchStrings[i];
|
||||
if (string == ent.mString.addr()) {
|
||||
if (!mScratchStrings[i].empty() &&
|
||||
mScratchStrings[i].addr() == string) {
|
||||
// One of our internal strings is no longer in use, mark
|
||||
// it as such and destroy the string.
|
||||
|
||||
ent.mInUse = false;
|
||||
ent.mString.addr()->~XPCReadableJSStringWrapper();
|
||||
|
||||
// it as such and free its data.
|
||||
mScratchStrings[i].destroy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1566,7 +1560,7 @@ XPCJSRuntime::~XPCJSRuntime()
|
||||
|
||||
#ifdef DEBUG
|
||||
for (uint32_t i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i) {
|
||||
MOZ_ASSERT(!mScratchStrings[i].mInUse, "Uh, string wrapper still in use!");
|
||||
MOZ_ASSERT(mScratchStrings[i].empty(), "Short lived string still in use");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -51,6 +51,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsICrashReporter.h"
|
||||
#endif
|
||||
|
||||
@ -68,7 +69,7 @@ public:
|
||||
~XPCShellDirProvider() { }
|
||||
|
||||
// The platform resource folder
|
||||
bool SetGREDir(const char *dir);
|
||||
void SetGREDir(nsIFile *greDir);
|
||||
void ClearGREDir() { mGREDir = nullptr; }
|
||||
// The application resource folder
|
||||
void SetAppDir(nsIFile *appFile);
|
||||
@ -1364,16 +1365,32 @@ XRE_XPCShellMain(int argc, char **argv, char **envp)
|
||||
|
||||
dirprovider.SetAppFile(appFile);
|
||||
|
||||
nsCOMPtr<nsIFile> greDir;
|
||||
if (argc > 1 && !strcmp(argv[1], "-g")) {
|
||||
if (argc < 3)
|
||||
return usage();
|
||||
|
||||
if (!dirprovider.SetGREDir(argv[2])) {
|
||||
printf("SetGREDir failed.\n");
|
||||
rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(greDir));
|
||||
if (NS_FAILED(rv)) {
|
||||
printf("Couldn't use given GRE dir.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
dirprovider.SetGREDir(greDir);
|
||||
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
} else {
|
||||
nsAutoString workingDir;
|
||||
if (!GetCurrentWorkingDirectory(workingDir)) {
|
||||
printf("GetCurrentWorkingDirectory failed.\n");
|
||||
return 1;
|
||||
}
|
||||
rv = NS_NewLocalFile(workingDir, true, getter_AddRefs(greDir));
|
||||
if (NS_FAILED(rv)) {
|
||||
printf("NS_NewLocalFile failed.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > 1 && !strcmp(argv[1], "-a")) {
|
||||
@ -1411,10 +1428,15 @@ XRE_XPCShellMain(int argc, char **argv, char **envp)
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
// This is needed during startup and also shutdown, so keep it out
|
||||
// of the nested scope.
|
||||
// Special exception: will remain usable after NS_ShutdownXPCOM
|
||||
nsCOMPtr<nsICrashReporter> crashReporter;
|
||||
const char *val = getenv("MOZ_CRASHREPORTER");
|
||||
if (val && *val) {
|
||||
rv = CrashReporter::SetExceptionHandler(greDir, true);
|
||||
if (NS_FAILED(rv)) {
|
||||
printf("CrashReporter::SetExceptionHandler failed!\n");
|
||||
return 1;
|
||||
}
|
||||
MOZ_ASSERT(CrashReporter::GetEnabled());
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
@ -1442,14 +1464,6 @@ XRE_XPCShellMain(int argc, char **argv, char **envp)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
const char *val = getenv("MOZ_CRASHREPORTER");
|
||||
crashReporter = do_GetService("@mozilla.org/toolkit/crash-reporter;1");
|
||||
if (val && *val) {
|
||||
crashReporter->SetEnabled(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIJSRuntimeService> rtsvc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
|
||||
// get the JSRuntime from the runtime svc
|
||||
if (!rtsvc) {
|
||||
@ -1618,10 +1632,8 @@ XRE_XPCShellMain(int argc, char **argv, char **envp)
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
// Shut down the crashreporter service to prevent leaking some strings it holds.
|
||||
if (crashReporter) {
|
||||
crashReporter->SetEnabled(false);
|
||||
crashReporter = nullptr;
|
||||
}
|
||||
if (CrashReporter::GetEnabled())
|
||||
CrashReporter::UnsetExceptionHandler();
|
||||
#endif
|
||||
|
||||
NS_LogTerm();
|
||||
@ -1629,11 +1641,10 @@ XRE_XPCShellMain(int argc, char **argv, char **envp)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
XPCShellDirProvider::SetGREDir(const char *dir)
|
||||
void
|
||||
XPCShellDirProvider::SetGREDir(nsIFile* greDir)
|
||||
{
|
||||
nsresult rv = XRE_GetFileFromPath(dir, getter_AddRefs(mGREDir));
|
||||
return NS_SUCCEEDED(rv);
|
||||
mGREDir = greDir;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2311,11 +2311,15 @@ CallMethodHelper::CleanupParam(nsXPTCMiniVariant& param, nsXPTType& type)
|
||||
break;
|
||||
case nsXPTType::T_ASTRING:
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
nsXPConnect::GetRuntimeInstance()->DeleteString((nsAString*)param.val.p);
|
||||
nsXPConnect::GetRuntimeInstance()->DeleteShortLivedString((nsString*)param.val.p);
|
||||
break;
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
case nsXPTType::T_CSTRING:
|
||||
delete (nsCString*) param.val.p;
|
||||
{
|
||||
nsCString* rs = (nsCString*)param.val.p;
|
||||
if (rs != &EmptyCString() && rs != &NullCString())
|
||||
delete rs;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(!type.IsArithmetic(), "Cleanup requested on unexpected type.");
|
||||
@ -2363,10 +2367,10 @@ CallMethodHelper::HandleDipperParam(nsXPTCVariant* dp,
|
||||
type_tag == nsXPTType::T_CSTRING,
|
||||
"Unexpected dipper type!");
|
||||
|
||||
// ASTRING and DOMSTRING are very similar, and both use nsAutoString.
|
||||
// ASTRING and DOMSTRING are very similar, and both use nsString.
|
||||
// UTF8_STRING and CSTRING are also quite similar, and both use nsCString.
|
||||
if (type_tag == nsXPTType::T_ASTRING || type_tag == nsXPTType::T_DOMSTRING)
|
||||
dp->val.p = new nsAutoString();
|
||||
dp->val.p = nsXPConnect::GetRuntimeInstance()->NewShortLivedString();
|
||||
else
|
||||
dp->val.p = new nsCString();
|
||||
|
||||
|
@ -548,7 +548,7 @@ nsXPConnect::WrapNative(JSContext * aJSContext,
|
||||
RootedObject aScope(aJSContext, aScopeArg);
|
||||
RootedValue v(aJSContext);
|
||||
return NativeInterface2JSObject(aScope, aCOMObj, nullptr, &aIID,
|
||||
false, &v, aHolder);
|
||||
true, &v, aHolder);
|
||||
}
|
||||
|
||||
/* void wrapNativeToJSVal (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDPtr aIID, out jsval aVal, out nsIXPConnectJSObjectHolder aHolder); */
|
||||
|
@ -80,6 +80,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/GuardObjects.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
#include <math.h>
|
||||
@ -393,33 +394,6 @@ private:
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// class to export a JSString as an const nsAString, no refcounting :(
|
||||
class XPCReadableJSStringWrapper : public nsDependentString
|
||||
{
|
||||
public:
|
||||
typedef nsDependentString::char_traits char_traits;
|
||||
|
||||
XPCReadableJSStringWrapper(const char16_t *chars, size_t length) :
|
||||
nsDependentString(chars, length)
|
||||
{ }
|
||||
|
||||
XPCReadableJSStringWrapper() :
|
||||
nsDependentString(char_traits::sEmptyBuffer, char_traits::sEmptyBuffer)
|
||||
{ SetIsVoid(true); }
|
||||
|
||||
bool init(JSContext* aContext, JSString* str)
|
||||
{
|
||||
size_t length;
|
||||
const jschar* chars = JS_GetStringCharsZAndLength(aContext, str, &length);
|
||||
if (!chars)
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(IsEmpty(), "init() on initialized string");
|
||||
new(static_cast<nsDependentString *>(this)) nsDependentString(chars, length);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// In the current xpconnect system there can only be one XPCJSRuntime.
|
||||
// So, xpconnect can only be used on one JSRuntime within the process.
|
||||
|
||||
@ -580,8 +554,8 @@ public:
|
||||
|
||||
~XPCJSRuntime();
|
||||
|
||||
XPCReadableJSStringWrapper *NewStringWrapper(const char16_t *str, uint32_t len);
|
||||
void DeleteString(nsAString *string);
|
||||
nsString* NewShortLivedString();
|
||||
void DeleteShortLivedString(nsString *string);
|
||||
|
||||
void AddGCCallback(xpcGCCallback cb);
|
||||
void RemoveGCCallback(xpcGCCallback cb);
|
||||
@ -646,20 +620,7 @@ private:
|
||||
|
||||
#define XPCCCX_STRING_CACHE_SIZE 2
|
||||
|
||||
// String wrapper entry, holds a string, and a boolean that tells
|
||||
// whether the string is in use or not.
|
||||
//
|
||||
// NB: The string is not stored by value so that we avoid the cost of
|
||||
// construction/destruction.
|
||||
struct StringWrapperEntry
|
||||
{
|
||||
StringWrapperEntry() : mInUse(false) { }
|
||||
|
||||
mozilla::AlignedStorage2<XPCReadableJSStringWrapper> mString;
|
||||
bool mInUse;
|
||||
};
|
||||
|
||||
StringWrapperEntry mScratchStrings[XPCCCX_STRING_CACHE_SIZE];
|
||||
mozilla::Maybe<nsString> mScratchStrings[XPCCCX_STRING_CACHE_SIZE];
|
||||
|
||||
friend class Watchdog;
|
||||
friend class AutoLockWatchdog;
|
||||
|
@ -2392,68 +2392,64 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
|
||||
else
|
||||
#endif
|
||||
if (aDocElement->IsSVG()) {
|
||||
if (aDocElement->Tag() == nsGkAtoms::svg) {
|
||||
// We're going to call the right function ourselves, so no need to give a
|
||||
// function to this FrameConstructionData.
|
||||
|
||||
// XXXbz on the other hand, if we converted this whole function to
|
||||
// FrameConstructionData/Item, then we'd need the right function
|
||||
// here... but would probably be able to get away with less code in this
|
||||
// function in general.
|
||||
// Use a null PendingBinding, since our binding is not in fact pending.
|
||||
static const FrameConstructionData rootSVGData = FCDATA_DECL(0, nullptr);
|
||||
nsRefPtr<nsStyleContext> extraRef(styleContext);
|
||||
FrameConstructionItem item(&rootSVGData, aDocElement,
|
||||
aDocElement->Tag(), kNameSpaceID_SVG,
|
||||
nullptr, extraRef.forget(), true, nullptr);
|
||||
|
||||
nsFrameItems frameItems;
|
||||
contentFrame = ConstructOuterSVG(state, item, mDocElementContainingBlock,
|
||||
styleContext->StyleDisplay(),
|
||||
frameItems);
|
||||
newFrame = frameItems.FirstChild();
|
||||
NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
|
||||
} else {
|
||||
if (aDocElement->Tag() != nsGkAtoms::svg) {
|
||||
return nullptr;
|
||||
}
|
||||
// We're going to call the right function ourselves, so no need to give a
|
||||
// function to this FrameConstructionData.
|
||||
|
||||
// XXXbz on the other hand, if we converted this whole function to
|
||||
// FrameConstructionData/Item, then we'd need the right function
|
||||
// here... but would probably be able to get away with less code in this
|
||||
// function in general.
|
||||
// Use a null PendingBinding, since our binding is not in fact pending.
|
||||
static const FrameConstructionData rootSVGData = FCDATA_DECL(0, nullptr);
|
||||
nsRefPtr<nsStyleContext> extraRef(styleContext);
|
||||
FrameConstructionItem item(&rootSVGData, aDocElement,
|
||||
aDocElement->Tag(), kNameSpaceID_SVG,
|
||||
nullptr, extraRef.forget(), true, nullptr);
|
||||
|
||||
nsFrameItems frameItems;
|
||||
contentFrame = ConstructOuterSVG(state, item, mDocElementContainingBlock,
|
||||
styleContext->StyleDisplay(),
|
||||
frameItems);
|
||||
newFrame = frameItems.FirstChild();
|
||||
NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
|
||||
} else if (display->mDisplay == NS_STYLE_DISPLAY_TABLE) {
|
||||
// We're going to call the right function ourselves, so no need to give a
|
||||
// function to this FrameConstructionData.
|
||||
|
||||
// XXXbz on the other hand, if we converted this whole function to
|
||||
// FrameConstructionData/Item, then we'd need the right function
|
||||
// here... but would probably be able to get away with less code in this
|
||||
// function in general.
|
||||
// Use a null PendingBinding, since our binding is not in fact pending.
|
||||
static const FrameConstructionData rootTableData = FCDATA_DECL(0, nullptr);
|
||||
nsRefPtr<nsStyleContext> extraRef(styleContext);
|
||||
FrameConstructionItem item(&rootTableData, aDocElement,
|
||||
aDocElement->Tag(), kNameSpaceID_None,
|
||||
nullptr, extraRef.forget(), true, nullptr);
|
||||
|
||||
nsFrameItems frameItems;
|
||||
// if the document is a table then just populate it.
|
||||
contentFrame = ConstructTable(state, item, mDocElementContainingBlock,
|
||||
styleContext->StyleDisplay(),
|
||||
frameItems);
|
||||
newFrame = frameItems.FirstChild();
|
||||
NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
|
||||
} else {
|
||||
bool docElemIsTable = (display->mDisplay == NS_STYLE_DISPLAY_TABLE);
|
||||
if (docElemIsTable) {
|
||||
// We're going to call the right function ourselves, so no need to give a
|
||||
// function to this FrameConstructionData.
|
||||
|
||||
// XXXbz on the other hand, if we converted this whole function to
|
||||
// FrameConstructionData/Item, then we'd need the right function
|
||||
// here... but would probably be able to get away with less code in this
|
||||
// function in general.
|
||||
// Use a null PendingBinding, since our binding is not in fact pending.
|
||||
static const FrameConstructionData rootTableData = FCDATA_DECL(0, nullptr);
|
||||
nsRefPtr<nsStyleContext> extraRef(styleContext);
|
||||
FrameConstructionItem item(&rootTableData, aDocElement,
|
||||
aDocElement->Tag(), kNameSpaceID_None,
|
||||
nullptr, extraRef.forget(), true, nullptr);
|
||||
|
||||
nsFrameItems frameItems;
|
||||
// if the document is a table then just populate it.
|
||||
contentFrame = ConstructTable(state, item, mDocElementContainingBlock,
|
||||
styleContext->StyleDisplay(),
|
||||
frameItems);
|
||||
newFrame = frameItems.FirstChild();
|
||||
NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
|
||||
} else {
|
||||
contentFrame = NS_NewBlockFormattingContext(mPresShell, styleContext);
|
||||
nsFrameItems frameItems;
|
||||
// Use a null PendingBinding, since our binding is not in fact pending.
|
||||
ConstructBlock(state, display, aDocElement,
|
||||
state.GetGeometricParent(display,
|
||||
mDocElementContainingBlock),
|
||||
mDocElementContainingBlock, styleContext,
|
||||
&contentFrame, frameItems,
|
||||
display->IsPositioned(contentFrame) ? contentFrame : nullptr,
|
||||
nullptr);
|
||||
newFrame = frameItems.FirstChild();
|
||||
NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
|
||||
}
|
||||
contentFrame = NS_NewBlockFormattingContext(mPresShell, styleContext);
|
||||
nsFrameItems frameItems;
|
||||
// Use a null PendingBinding, since our binding is not in fact pending.
|
||||
ConstructBlock(state, display, aDocElement,
|
||||
state.GetGeometricParent(display,
|
||||
mDocElementContainingBlock),
|
||||
mDocElementContainingBlock, styleContext,
|
||||
&contentFrame, frameItems,
|
||||
display->IsPositioned(contentFrame) ? contentFrame : nullptr,
|
||||
nullptr);
|
||||
newFrame = frameItems.FirstChild();
|
||||
NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
|
||||
}
|
||||
|
||||
MOZ_ASSERT(newFrame);
|
||||
|
@ -192,6 +192,21 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// For unicode-bidi: plaintext, reset the direction of the writing mode from
|
||||
// the bidi paragraph level of the content
|
||||
|
||||
//XXX change uint8_t to UBiDiLevel after bug 924851
|
||||
void SetDirectionFromBidiLevel(uint8_t level)
|
||||
{
|
||||
if (level & 1) {
|
||||
// odd level, set RTL
|
||||
mWritingMode |= eBidiMask;
|
||||
} else {
|
||||
// even level, set LTR
|
||||
mWritingMode &= ~eBidiMask;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two WritingModes for equality.
|
||||
*/
|
||||
|
@ -3087,9 +3087,11 @@ nsFlexContainerFrame::DoFlexLayout(nsPresContext* aPresContext,
|
||||
/* virtual */ nscoord
|
||||
nsFlexContainerFrame::GetMinWidth(nsRenderingContext* aRenderingContext)
|
||||
{
|
||||
nscoord minWidth = 0;
|
||||
DISPLAY_MIN_WIDTH(this, minWidth);
|
||||
|
||||
FlexboxAxisTracker axisTracker(this);
|
||||
|
||||
nscoord minWidth = 0;
|
||||
for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
|
||||
nscoord childMinWidth =
|
||||
nsLayoutUtils::IntrinsicForContainer(aRenderingContext, e.get(),
|
||||
@ -3111,6 +3113,9 @@ nsFlexContainerFrame::GetMinWidth(nsRenderingContext* aRenderingContext)
|
||||
/* virtual */ nscoord
|
||||
nsFlexContainerFrame::GetPrefWidth(nsRenderingContext* aRenderingContext)
|
||||
{
|
||||
nscoord prefWidth = 0;
|
||||
DISPLAY_PREF_WIDTH(this, prefWidth);
|
||||
|
||||
// XXXdholbert Optimization: We could cache our intrinsic widths like
|
||||
// nsBlockFrame does (and return it early from this function if it's set).
|
||||
// Whenever anything happens that might change it, set it to
|
||||
@ -3118,7 +3123,6 @@ nsFlexContainerFrame::GetPrefWidth(nsRenderingContext* aRenderingContext)
|
||||
// does)
|
||||
FlexboxAxisTracker axisTracker(this);
|
||||
|
||||
nscoord prefWidth = 0;
|
||||
for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
|
||||
nscoord childPrefWidth =
|
||||
nsLayoutUtils::IntrinsicForContainer(aRenderingContext, e.get(),
|
||||
|
@ -686,6 +686,15 @@ public:
|
||||
nsRect GetRectRelativeToSelf() const {
|
||||
return nsRect(nsPoint(0, 0), mRect.Size());
|
||||
}
|
||||
/**
|
||||
* Rect and position in logical coordinates in the frame's writing mode
|
||||
*/
|
||||
mozilla::LogicalRect GetLogicalRect(nscoord aContainerWidth) const {
|
||||
return mozilla::LogicalRect(GetWritingMode(), GetRect(), aContainerWidth);
|
||||
}
|
||||
mozilla::LogicalPoint GetLogicalPosition(nscoord aContainerWidth) const {
|
||||
return GetLogicalRect(aContainerWidth).Origin(GetWritingMode());
|
||||
}
|
||||
|
||||
/**
|
||||
* When we change the size of the frame's border-box rect, we may need to
|
||||
@ -703,6 +712,22 @@ public:
|
||||
mRect = aRect;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set this frame's rect from a logical rect in its own writing direction
|
||||
*/
|
||||
void SetRectFromLogicalRect(const mozilla::LogicalRect& aRect,
|
||||
nscoord aContainerWidth) {
|
||||
SetRectFromLogicalRect(GetWritingMode(), aRect, aContainerWidth);
|
||||
}
|
||||
/**
|
||||
* Set this frame's rect from a logical rect in a different writing direction
|
||||
* (GetPhysicalRect will assert if the writing mode doesn't match)
|
||||
*/
|
||||
void SetRectFromLogicalRect(mozilla::WritingMode aWritingMode,
|
||||
const mozilla::LogicalRect& aRect,
|
||||
nscoord aContainerWidth) {
|
||||
SetRect(aRect.GetPhysicalRect(aWritingMode, aContainerWidth));
|
||||
}
|
||||
void SetSize(const nsSize& aSize) {
|
||||
SetRect(nsRect(mRect.TopLeft(), aSize));
|
||||
}
|
||||
|
@ -2890,7 +2890,7 @@ public:
|
||||
const gfxSkipCharsIterator& GetEndHint() { return mTempIterator; }
|
||||
|
||||
protected:
|
||||
void SetupJustificationSpacing();
|
||||
void SetupJustificationSpacing(bool aPostReflow);
|
||||
|
||||
void InitFontGroupAndFontMetrics() {
|
||||
float inflation = (mWhichTextRun == nsTextFrame::eInflated)
|
||||
@ -3274,7 +3274,7 @@ PropertyProvider::InitializeForDisplay(bool aTrimAfter)
|
||||
mFrame->GetTrimmedOffsets(mFrag, aTrimAfter);
|
||||
mStart.SetOriginalOffset(trimmed.mStart);
|
||||
mLength = trimmed.mLength;
|
||||
SetupJustificationSpacing();
|
||||
SetupJustificationSpacing(true);
|
||||
}
|
||||
|
||||
void
|
||||
@ -3284,7 +3284,7 @@ PropertyProvider::InitializeForMeasure()
|
||||
mFrame->GetTrimmedOffsets(mFrag, true, false);
|
||||
mStart.SetOriginalOffset(trimmed.mStart);
|
||||
mLength = trimmed.mLength;
|
||||
SetupJustificationSpacing();
|
||||
SetupJustificationSpacing(false);
|
||||
}
|
||||
|
||||
|
||||
@ -3326,7 +3326,7 @@ PropertyProvider::FindJustificationRange(gfxSkipCharsIterator* aStart,
|
||||
}
|
||||
|
||||
void
|
||||
PropertyProvider::SetupJustificationSpacing()
|
||||
PropertyProvider::SetupJustificationSpacing(bool aPostReflow)
|
||||
{
|
||||
NS_PRECONDITION(mLength != INT32_MAX, "Can't call this with undefined length");
|
||||
|
||||
@ -3338,7 +3338,7 @@ PropertyProvider::SetupJustificationSpacing()
|
||||
// called with false for aTrimAfter, we still shouldn't be assigning
|
||||
// justification space to any trailing whitespace.
|
||||
nsTextFrame::TrimmedOffsets trimmed =
|
||||
mFrame->GetTrimmedOffsets(mFrag, true);
|
||||
mFrame->GetTrimmedOffsets(mFrag, true, aPostReflow);
|
||||
end.AdvanceOriginal(trimmed.mLength);
|
||||
gfxSkipCharsIterator realEnd(end);
|
||||
FindJustificationRange(&start, &end);
|
||||
|
@ -249,6 +249,7 @@
|
||||
android:label="@string/crash_reporter_title"
|
||||
android:icon="@drawable/crash_reporter"
|
||||
android:theme="@style/Gecko"
|
||||
android:exported="false"
|
||||
android:excludeFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.reportCrash" />
|
||||
|
@ -6,6 +6,7 @@
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import org.mozilla.gecko.SiteIdentity.SecurityMode;
|
||||
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.gfx.Layer;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
@ -418,9 +419,9 @@ public class Tab {
|
||||
return;
|
||||
}
|
||||
|
||||
mBookmark = BrowserDB.isBookmark(getContentResolver(), url);
|
||||
mReadingListItem = BrowserDB.isReadingListItem(getContentResolver(), url);
|
||||
|
||||
final int flags = BrowserDB.getItemFlags(getContentResolver(), url);
|
||||
mBookmark = (flags & Bookmarks.FLAG_BOOKMARK) > 0;
|
||||
mReadingListItem = (flags & Bookmarks.FLAG_READING) > 0;
|
||||
Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.MENU_UPDATED);
|
||||
}
|
||||
});
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user