merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Iris Hsiao 2017-05-02 11:04:36 +08:00
Родитель d40a38334b 30484a2cd3
Коммит 1401934d7b
65 изменённых файлов: 823 добавлений и 200 удалений

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

@ -4302,6 +4302,8 @@ function updateEditUIVisibility() {
let contextMenuPopupState = document.getElementById("contentAreaContextMenu").state;
let placesContextMenuPopupState = document.getElementById("placesContext").state;
let oldVisible = gEditUIVisible;
// The UI is visible if the Edit menu is opening or open, if the context menu
// is open, or if the toolbar has been customized to include the Cut, Copy,
// or Paste toolbar buttons.
@ -4310,18 +4312,35 @@ function updateEditUIVisibility() {
contextMenuPopupState == "showing" ||
contextMenuPopupState == "open" ||
placesContextMenuPopupState == "showing" ||
placesContextMenuPopupState == "open" ||
document.getElementById("edit-controls") ? true : false;
placesContextMenuPopupState == "open";
if (!gEditUIVisible) {
// Now check the edit-controls toolbar buttons.
let placement = CustomizableUI.getPlacementOfWidget("edit-controls");
let areaType = placement ? CustomizableUI.getAreaType(placement.area) : "";
if (areaType == CustomizableUI.TYPE_MENU_PANEL) {
let panelUIMenuPopupState = document.getElementById("PanelUI-popup").state;
if (panelUIMenuPopupState == "showing" || panelUIMenuPopupState == "open") {
gEditUIVisible = true;
}
} else if (areaType == CustomizableUI.TYPE_TOOLBAR) {
// The edit controls are on a toolbar, so they are visible.
gEditUIVisible = true;
}
}
// No need to update commands if the edit UI visibility has not changed.
if (gEditUIVisible == oldVisible) {
return;
}
// If UI is visible, update the edit commands' enabled state to reflect
// whether or not they are actually enabled for the current focus/selection.
if (gEditUIVisible)
if (gEditUIVisible) {
goUpdateGlobalEditMenuItems();
// Otherwise, enable all commands, so that keyboard shortcuts still work,
// then lazily determine their actual enabled state when the user presses
// a keyboard shortcut.
else {
} else {
// Otherwise, enable all commands, so that keyboard shortcuts still work,
// then lazily determine their actual enabled state when the user presses
// a keyboard shortcut.
goSetCommandEnabled("cmd_undo", true);
goSetCommandEnabled("cmd_redo", true);
goSetCommandEnabled("cmd_cut", true);

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

@ -1065,6 +1065,8 @@
return;
if (!aForceUpdate) {
document.commandDispatcher.lock();
TelemetryStopwatch.start("FX_TAB_SWITCH_UPDATE_MS");
if (!gMultiProcessBrowser) {
// old way of measuring tab paint which is not valid with e10s.
@ -1274,6 +1276,8 @@
this.tabContainer._setPositionalAttributes();
if (!gMultiProcessBrowser) {
document.commandDispatcher.unlock();
let event = new CustomEvent("TabSwitchDone", {
bubbles: true,
cancelable: true
@ -3981,6 +3985,8 @@
fromBrowser.removeAttribute("primary");
}
document.commandDispatcher.unlock();
let event = new CustomEvent("TabSwitchDone", {
bubbles: true,
cancelable: true

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

@ -16,4 +16,5 @@ skip-if = os == 'mac'
skip-if = !e10s # Pref and test only relevant for e10s.
[browser_opened_file_tab_navigated_to_web.js]
[browser_reload_deleted_file.js]
[browser_tabswitch_updatecommands.js]
[browser_viewsource_of_data_URI_in_file_process.js]

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

@ -0,0 +1,21 @@
// This test ensures that only one command update happens when switching tabs.
"use strict";
add_task(function* () {
const uri = "data:text/html,<body><input>";
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, uri);
let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, uri);
let updates = 0;
function countUpdates(event) { updates++; }
let updater = document.getElementById("editMenuCommandSetAll");
updater.addEventListener("commandupdate", countUpdates, true);
yield BrowserTestUtils.switchTab(gBrowser, tab1);
is(updates, 1, "only one command update per tab switch");
updater.removeEventListener("commandupdate", countUpdates, true);
yield BrowserTestUtils.removeTab(tab1);
yield BrowserTestUtils.removeTab(tab2);
});

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

@ -160,11 +160,6 @@ const PanelUI = {
return;
}
let editControlPlacement = CustomizableUI.getPlacementOfWidget("edit-controls");
if (editControlPlacement && editControlPlacement.area == CustomizableUI.AREA_PANEL) {
updateEditUIVisibility();
}
let personalBookmarksPlacement = CustomizableUI.getPlacementOfWidget("personal-bookmarks");
if (personalBookmarksPlacement &&
personalBookmarksPlacement.area == CustomizableUI.AREA_PANEL) {
@ -292,10 +287,14 @@ const PanelUI = {
switch (aEvent.type) {
case "popupshowing":
this._adjustLabelsForAutoHyphens();
updateEditUIVisibility();
// Fall through
case "popupshown":
// Fall through
case "popuphiding":
if (aEvent.type == "popuphiding") {
updateEditUIVisibility();
}
// Fall through
case "popuphidden":
this._updateNotifications();

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

@ -155,3 +155,5 @@ skip-if = os == "mac"
[browser_switch_to_customize_mode.js]
[browser_synced_tabs_menu.js]
[browser_check_tooltips_in_navbar.js]
[browser_editcontrols_update.js]
subsuite = clipboard

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

@ -0,0 +1,162 @@
// This test checks that the edit command enabled state (cut/paste) is updated
// properly when the edit controls are on the toolbar, popup and not present.
// It also verifies that the performance optimiation implemented by
// updateEditUIVisibility in browser.js is applied.
let isMac = navigator.platform.indexOf("Mac") == 0;
function checkState(allowCut, desc, testWindow = window) {
is(testWindow.document.getElementById("cmd_cut").getAttribute("disabled") == "true", !allowCut, desc + " - cut");
is(testWindow.document.getElementById("cmd_paste").getAttribute("disabled") == "true", false, desc + " - paste");
}
// Add a special controller to the urlbar and browser to listen in on when
// commands are being updated. Return a promise that resolves when 'count'
// updates have occurred.
function expectCommandUpdate(count, testWindow = window) {
return new Promise((resolve, reject) => {
let overrideController = {
supportsCommand(cmd) { return cmd == "cmd_delete"; },
isCommandEnabled(cmd) {
if (!count) {
ok(false, "unexpected update");
reject();
}
if (!--count) {
testWindow.gURLBar.controllers.removeControllerAt(0, overrideController);
testWindow.gBrowser.selectedBrowser.controllers.removeControllerAt(0, overrideController);
resolve(true);
}
}
};
if (!count) {
SimpleTest.executeSoon(() => {
testWindow.gURLBar.controllers.removeControllerAt(0, overrideController);
testWindow.gBrowser.selectedBrowser.controllers.removeControllerAt(0, overrideController);
resolve(false);
});
}
testWindow.gURLBar.controllers.insertControllerAt(0, overrideController);
testWindow.gBrowser.selectedBrowser.controllers.insertControllerAt(0, overrideController);
});
}
add_task(function* test_init() {
// Put something on the clipboard to verify that the paste button is properly enabled during the test.
let clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
yield new Promise(resolve => {
SimpleTest.waitForClipboard("Sample", function() { clipboardHelper.copyString("Sample"); }, resolve);
});
// Open and close the panel first so that it is fully initialized.
yield PanelUI.show();
let hiddenPromise = promisePanelHidden(window);
PanelUI.hide();
yield hiddenPromise;
});
// Test updating when the panel is open with the edit-controls on the panel.
// Updates should occur.
add_task(function* test_panelui_opened() {
gURLBar.focus();
gURLBar.value = "test";
yield PanelUI.show();
checkState(false, "Update when edit-controls is on panel and visible");
let overridePromise = expectCommandUpdate(1);
gURLBar.select();
yield overridePromise;
checkState(true, "Update when edit-controls is on panel and selection changed");
overridePromise = expectCommandUpdate(0);
let hiddenPromise = promisePanelHidden(window);
PanelUI.hide();
yield hiddenPromise;
yield overridePromise;
// Check that updates do not occur after the panel has been closed.
checkState(true, "Update when edit-controls is on panel and hidden");
// Mac will update the enabled st1ate even when the panel is closed so that
// main menubar shortcuts will work properly.
overridePromise = expectCommandUpdate(isMac ? 1 : 0);
gURLBar.select();
yield overridePromise;
checkState(true, "Update when edit-controls is on panel, hidden and selection changed");
});
// Test updating when the edit-controls are moved to the toolbar.
add_task(function* test_panelui_customize_to_toolbar() {
yield startCustomizing();
let navbar = document.getElementById("nav-bar").customizationTarget;
simulateItemDrag(document.getElementById("edit-controls"), navbar);
yield endCustomizing();
// updateEditUIVisibility should be called when customization ends but isn't. See bug 1359790.
updateEditUIVisibility();
let overridePromise = expectCommandUpdate(1);
gURLBar.select();
gURLBar.focus();
gURLBar.value = "other";
yield overridePromise;
checkState(false, "Update when edit-controls on toolbar and focused");
overridePromise = expectCommandUpdate(1);
gURLBar.select();
yield overridePromise;
checkState(true, "Update when edit-controls on toolbar and selection changed");
});
// Test updating when the edit-controls are moved to the palette.
add_task(function* test_panelui_customize_to_palette() {
yield startCustomizing();
let palette = document.getElementById("customization-palette");
simulateItemDrag(document.getElementById("edit-controls"), palette);
yield endCustomizing();
// updateEditUIVisibility should be called when customization ends but isn't. See bug 1359790.
updateEditUIVisibility();
let overridePromise = expectCommandUpdate(isMac ? 1 : 0);
gURLBar.focus();
gURLBar.value = "other";
gURLBar.select();
yield overridePromise;
// If the UI isn't found, the command is set to be enabled.
checkState(true, "Update when edit-controls is on palette, hidden and selection changed");
});
add_task(function* finish() {
yield resetCustomization();
});
// Test updating in the initial state when the edit-controls are on the panel but
// have not yet been created. This needs to be done in a new window to ensure that
// other tests haven't opened the panel.
add_task(function* test_initial_state() {
let testWindow = yield BrowserTestUtils.openNewBrowserWindow();
yield SimpleTest.promiseFocus(testWindow);
let overridePromise = expectCommandUpdate(isMac, testWindow);
testWindow.gURLBar.focus();
testWindow.gURLBar.value = "test";
yield overridePromise;
// Commands won't update when no edit UI is present. They default to being
// enabled so that keyboard shortcuts will work. The real enabled state will
// be checked when shortcut is pressed.
checkState(!isMac, "No update when edit-controls is on panel and not visible", testWindow);
yield BrowserTestUtils.closeWindow(testWindow);
yield SimpleTest.promiseFocus(window);
});

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

@ -12,5 +12,7 @@ STRIP_FLAGS="--strip-debug"
ac_add_options --with-branding=browser/branding/aurora
mk_add_options MOZ_PGO=1
. "$topsrcdir/build/mozconfig.common.override"
. "$topsrcdir/build/mozconfig.cache"

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

@ -12,5 +12,7 @@ STRIP_FLAGS="--strip-debug"
ac_add_options --with-branding=browser/branding/aurora
mk_add_options MOZ_PGO=1
. "$topsrcdir/build/mozconfig.common.override"
. "$topsrcdir/build/mozconfig.cache"

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

@ -8,5 +8,7 @@ ac_add_options --enable-verify-mar
ac_add_options --with-branding=browser/branding/aurora
mk_add_options MOZ_PGO=1
. "$topsrcdir/build/mozconfig.common.override"
. "$topsrcdir/build/mozconfig.cache"

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

@ -9,5 +9,7 @@ ac_add_options --enable-verify-mar
ac_add_options --with-branding=browser/branding/aurora
mk_add_options MOZ_PGO=1
. "$topsrcdir/build/mozconfig.common.override"
. "$topsrcdir/build/mozconfig.cache"

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

@ -13,6 +13,8 @@ function setConditionalBreakpoint(dbg, index, condition) {
selectMenuItem(dbg, 2);
yield waitForElement(dbg, ".conditional-breakpoint-panel input");
findElementWithSelector(dbg, ".conditional-breakpoint-panel input").focus();
// Position cursor reliably at the end of the text.
pressKey(dbg, "End")
type(dbg, condition);
pressKey(dbg, "Enter");
});

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

@ -32,6 +32,8 @@ async function addExpression(dbg, input) {
async function editExpression(dbg, input) {
info("updating the expression");
dblClickElement(dbg, "expressionNode", 1);
// Position cursor reliably at the end of the text.
pressKey(dbg, "End")
type(dbg, input);
pressKey(dbg, "Enter");
await waitForDispatch(dbg, "EVALUATE_EXPRESSION");

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

@ -560,6 +560,10 @@ const keyMappings = {
Enter: { code: "VK_RETURN" },
Up: { code: "VK_UP" },
Down: { code: "VK_DOWN" },
Right: { code: "VK_RIGHT" },
Left: { code: "VK_LEFT" },
End: { code: "VK_RIGHT", modifiers: cmdOrCtrl },
Start: { code: "VK_LEFT", modifiers: cmdOrCtrl },
Tab: { code: "VK_TAB" },
Escape: { code: "VK_ESCAPE" },
pauseKey: { code: "VK_F8" },

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

@ -297,6 +297,7 @@ bool nsContentUtils::sUseActivityCursor = false;
bool nsContentUtils::sAnimationsAPICoreEnabled = false;
bool nsContentUtils::sAnimationsAPIElementAnimateEnabled = false;
bool nsContentUtils::sGetBoxQuadsEnabled = false;
bool nsContentUtils::sSkipCursorMoveForSameValueSet = false;
int32_t nsContentUtils::sPrivacyMaxInnerWidth = 1000;
int32_t nsContentUtils::sPrivacyMaxInnerHeight = 1000;
@ -645,6 +646,10 @@ nsContentUtils::Init()
Preferences::AddBoolVarCache(&sGetBoxQuadsEnabled,
"layout.css.getBoxQuads.enabled", false);
Preferences::AddBoolVarCache(&sSkipCursorMoveForSameValueSet,
"dom.input.skip_cursor_move_for_same_value_set",
true);
Element::InitCCCallbacks();
nsCOMPtr<nsIUUIDGenerator> uuidGenerator =

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

@ -2888,6 +2888,13 @@ public:
*/
static uint64_t GenerateTabId();
/**
* Check whether we should skip moving the cursor for a same-value .value set
* on a text input or textarea.
*/
static bool
SkipCursorMoveForSameValueSet() { return sSkipCursorMoveForSameValueSet; }
private:
static bool InitializeEventTable();
@ -3012,6 +3019,7 @@ private:
static bool sAnimationsAPICoreEnabled;
static bool sAnimationsAPIElementAnimateEnabled;
static bool sGetBoxQuadsEnabled;
static bool sSkipCursorMoveForSameValueSet;
static uint32_t sCookiesLifetimePolicy;
static uint32_t sCookiesBehavior;

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

@ -573,7 +573,10 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins):
return False
def addExtendedAttributes(self, attrs):
assert len(attrs) == 0
if len(attrs) != 0:
raise WebIDLError("There are no extended attributes that are "
"allowed on external interfaces",
[attrs[0].location, self.location])
def resolve(self, parentScope):
pass
@ -1932,7 +1935,10 @@ class IDLDictionary(IDLObjectWithScope):
[member.location] + locations)
def addExtendedAttributes(self, attrs):
assert len(attrs) == 0
if len(attrs) != 0:
raise WebIDLError("There are no extended attributes that are "
"allowed on dictionaries",
[attrs[0].location, self.location])
def _getDependentObjects(self):
deps = set(self.members)
@ -1966,7 +1972,10 @@ class IDLEnum(IDLObjectWithIdentifier):
return True
def addExtendedAttributes(self, attrs):
assert len(attrs) == 0
if len(attrs) != 0:
raise WebIDLError("There are no extended attributes that are "
"allowed on enums",
[attrs[0].location, self.location])
def _getDependentObjects(self):
return set()
@ -2139,7 +2148,11 @@ class IDLType(IDLObject):
return self.nullable() and self.inner.callback._treatNonObjectAsNull
def addExtendedAttributes(self, attrs):
assert len(attrs) == 0
if len(attrs) != 0:
raise WebIDLError("There are no extended attributes that are "
"allowed on types, for now (but this is "
"changing; see bug 1359269)",
[attrs[0].location, self.location])
def resolveType(self, parentScope):
pass
@ -2707,7 +2720,10 @@ class IDLTypedef(IDLObjectWithIdentifier):
return True
def addExtendedAttributes(self, attrs):
assert len(attrs) == 0
if len(attrs) != 0:
raise WebIDLError("There are no extended attributes that are "
"allowed on typedefs",
[attrs[0].location, self.location])
def _getDependentObjects(self):
return self.innerType._getDependentObjects()
@ -5108,7 +5124,10 @@ class IDLImplementsStatement(IDLObject):
pass
def addExtendedAttributes(self, attrs):
assert len(attrs) == 0
if len(attrs) != 0:
raise WebIDLError("There are no extended attributes that are "
"allowed on implements statements",
[attrs[0].location, self.location])
class IDLExtendedAttribute(IDLObject):

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

@ -1974,9 +1974,10 @@ HTMLInputElement::SetValue(const nsAString& aValue, CallerType aCallerType,
GetValue(currentValue, aCallerType);
nsresult rv =
SetValueInternal(aValue, nsTextEditorState::eSetValue_ByContent |
nsTextEditorState::eSetValue_Notify |
nsTextEditorState::eSetValue_MoveCursorToEnd);
SetValueInternal(aValue,
nsTextEditorState::eSetValue_ByContent |
nsTextEditorState::eSetValue_Notify |
nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return;
@ -1987,9 +1988,10 @@ HTMLInputElement::SetValue(const nsAString& aValue, CallerType aCallerType,
}
} else {
nsresult rv =
SetValueInternal(aValue, nsTextEditorState::eSetValue_ByContent |
nsTextEditorState::eSetValue_Notify |
nsTextEditorState::eSetValue_MoveCursorToEnd);
SetValueInternal(aValue,
nsTextEditorState::eSetValue_ByContent |
nsTextEditorState::eSetValue_Notify |
nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return;
@ -2843,9 +2845,9 @@ HTMLInputElement::SetUserInput(const nsAString& aValue)
} else {
nsresult rv =
SetValueInternal(aValue,
nsTextEditorState::eSetValue_BySetUserInput |
nsTextEditorState::eSetValue_Notify|
nsTextEditorState::eSetValue_MoveCursorToEnd);
nsTextEditorState::eSetValue_BySetUserInput |
nsTextEditorState::eSetValue_Notify|
nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
NS_ENSURE_SUCCESS(rv, rv);
}

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

@ -404,9 +404,10 @@ HTMLTextAreaElement::SetValue(const nsAString& aValue)
GetValueInternal(currentValue, true);
nsresult rv =
SetValueInternal(aValue, nsTextEditorState::eSetValue_ByContent |
nsTextEditorState::eSetValue_Notify |
nsTextEditorState::eSetValue_MoveCursorToEnd);
SetValueInternal(aValue,
nsTextEditorState::eSetValue_ByContent |
nsTextEditorState::eSetValue_Notify |
nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
NS_ENSURE_SUCCESS(rv, rv);
if (mFocusedValue.Equals(currentValue)) {
@ -420,9 +421,9 @@ NS_IMETHODIMP
HTMLTextAreaElement::SetUserInput(const nsAString& aValue)
{
return SetValueInternal(aValue,
nsTextEditorState::eSetValue_BySetUserInput |
nsTextEditorState::eSetValue_Notify|
nsTextEditorState::eSetValue_MoveCursorToEnd);
nsTextEditorState::eSetValue_BySetUserInput |
nsTextEditorState::eSetValue_Notify|
nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
}
NS_IMETHODIMP

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

@ -2503,6 +2503,12 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
}
}
// \r is an illegal character in the dom, but people use them,
// so convert windows and mac platform linebreaks to \n:
if (!nsContentUtils::PlatformToDOMLineBreaks(newValue, fallible)) {
return false;
}
if (mEditor && mBoundFrame) {
// The InsertText call below might flush pending notifications, which
// could lead into a scheduled PrepareEditor to be called. That will
@ -2528,14 +2534,6 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
{
ValueSetter valueSetter(mEditor);
// \r is an illegal character in the dom, but people use them,
// so convert windows and mac platform linebreaks to \n:
if (newValue.FindChar(char16_t('\r')) != -1) {
if (!nsContentUtils::PlatformToDOMLineBreaks(newValue, fallible)) {
return false;
}
}
nsCOMPtr<nsIDOMDocument> domDoc;
mEditor->GetDocument(getter_AddRefs(domDoc));
if (!domDoc) {
@ -2638,33 +2636,42 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
if (!mValue) {
mValue.emplace();
}
nsString value;
if (!value.Assign(newValue, fallible)) {
return false;
}
if (!nsContentUtils::PlatformToDOMLineBreaks(value, fallible)) {
return false;
}
if (!mValue->Assign(value, fallible)) {
return false;
}
// Since we have no editor we presumably have cached selection state.
if (IsSelectionCached()) {
SelectionProperties& props = GetSelectionProperties();
if (aFlags & eSetValue_MoveCursorToEnd) {
props.SetStart(value.Length());
props.SetEnd(value.Length());
} else {
// Make sure our cached selection position is not outside the new value.
props.SetStart(std::min(props.GetStart(), value.Length()));
props.SetEnd(std::min(props.GetEnd(), value.Length()));
// We can't just early-return here if mValue->Equals(newValue), because
// ValueWasChanged and OnValueChanged below still need to be called.
if (!mValue->Equals(newValue) ||
!nsContentUtils::SkipCursorMoveForSameValueSet()) {
if (!mValue->Assign(newValue, fallible)) {
return false;
}
}
// Update the frame display if needed
if (mBoundFrame) {
mBoundFrame->UpdateValueDisplay(true);
// Since we have no editor we presumably have cached selection state.
if (IsSelectionCached()) {
SelectionProperties& props = GetSelectionProperties();
if (aFlags & eSetValue_MoveCursorToEndIfValueChanged) {
props.SetStart(newValue.Length());
props.SetEnd(newValue.Length());
props.SetDirection(nsITextControlFrame::eForward);
} else {
// Make sure our cached selection position is not outside the new value.
props.SetStart(std::min(props.GetStart(), newValue.Length()));
props.SetEnd(std::min(props.GetEnd(), newValue.Length()));
}
}
// Update the frame display if needed
if (mBoundFrame) {
mBoundFrame->UpdateValueDisplay(true);
}
} else {
// Even if our value is not actually changing, apparently we need to mark
// our SelectionProperties dirty to make accessibility tests happy.
// Probably because they depend on the SetSelectionRange() call we make on
// our frame in RestoreSelectionState, but I have no idea why they do.
if (IsSelectionCached()) {
SelectionProperties& props = GetSelectionProperties();
props.SetIsDirty();
}
}
}

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

@ -173,9 +173,11 @@ public:
// Whether the value change should be notified to the frame/contet nor not.
eSetValue_Notify = 1 << 2,
// Whether to move the cursor to end of the value (in the case when we have
// cached selection offsets). If this is not set, the cached selection
// offsets will simply be clamped to be within the length of the new value.
eSetValue_MoveCursorToEnd = 1 << 3,
// cached selection offsets), in the case when the value has changed. If
// this is not set, the cached selection offsets will simply be clamped to
// be within the length of the new value. In either case, if the value has
// not changed the cursor won't move.
eSetValue_MoveCursorToEndIfValueChanged = 1 << 3,
};
MOZ_MUST_USE bool SetValue(const nsAString& aValue, uint32_t aFlags);
void GetValue(nsAString& aValue, bool aIgnoreWrap) const;
@ -280,11 +282,16 @@ public:
mIsDirty = true;
mDirection = value;
}
// return true only if mStart, mEnd, or mDirection have been modified
// return true only if mStart, mEnd, or mDirection have been modified,
// or if SetIsDirty() was explicitly called.
bool IsDirty() const
{
return mIsDirty;
}
void SetIsDirty()
{
mIsDirty = true;
}
private:
uint32_t mStart, mEnd;
bool mIsDirty = false;

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

@ -31,4 +31,9 @@ interface nsIDOMXULCommandDispatcher : nsISupports
void rewindFocus();
void advanceFocusIntoSubtree(in nsIDOMElement elt);
attribute boolean suppressFocusScroll;
// When locked, command updating is batched until unlocked. Always ensure that
// lock and unlock is called in a pair.
void lock();
void unlock();
};

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

@ -5055,7 +5055,7 @@ ContentParent::ForceTabPaint(TabParent* aTabParent, uint64_t aLayerObserverEpoch
}
nsresult
ContentParent::AboutToLoadDocumentForChild(nsIChannel* aChannel)
ContentParent::AboutToLoadHttpFtpWyciwygDocumentForChild(nsIChannel* aChannel)
{
MOZ_ASSERT(aChannel);

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

@ -656,7 +656,7 @@ public:
// HTTP(S), FTP or wyciwyg channel for a content process. It is a useful
// place to start to kick off work as early as possible in response to such
// document loads.
nsresult AboutToLoadDocumentForChild(nsIChannel* aChannel);
nsresult AboutToLoadHttpFtpWyciwygDocumentForChild(nsIChannel* aChannel);
nsresult TransmitPermissionsForPrincipal(nsIPrincipal* aPrincipal);

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

@ -941,6 +941,10 @@ TabParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
#ifdef XP_WIN
a11y::WrapperFor(doc)->SetID(aMsaaID);
MOZ_ASSERT(!aDocCOMProxy.IsNull());
if (aDocCOMProxy.IsNull()) {
return IPC_FAIL(this, "Constructing a top-level PDocAccessible with null COM proxy");
}
RefPtr<IAccessible> proxy(aDocCOMProxy.Get());
doc->SetCOMInterface(proxy);
doc->MaybeInitWindowEmulation();

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

@ -42,7 +42,7 @@ static LazyLogModule gCommandLog("nsXULCommandDispatcher");
////////////////////////////////////////////////////////////////////////
nsXULCommandDispatcher::nsXULCommandDispatcher(nsIDocument* aDocument)
: mDocument(aDocument), mUpdaters(nullptr)
: mDocument(aDocument), mUpdaters(nullptr), mLocked(false)
{
}
@ -350,6 +350,14 @@ nsXULCommandDispatcher::RemoveCommandUpdater(nsIDOMElement* aElement)
NS_IMETHODIMP
nsXULCommandDispatcher::UpdateCommands(const nsAString& aEventName)
{
if (mLocked) {
if (!mPendingUpdates.Contains(aEventName)) {
mPendingUpdates.AppendElement(aEventName);
}
return NS_OK;
}
nsAutoString id;
nsCOMPtr<nsIDOMElement> element;
GetFocusedElement(getter_AddRefs(element));
@ -457,3 +465,30 @@ nsXULCommandDispatcher::SetSuppressFocusScroll(bool aSuppressFocusScroll)
return NS_OK;
}
NS_IMETHODIMP
nsXULCommandDispatcher::Lock()
{
// Since locking is used only as a performance optimization, we don't worry
// about nested lock calls. If that does happen, it just means we will unlock
// and process updates earlier.
mLocked = true;
return NS_OK;
}
NS_IMETHODIMP
nsXULCommandDispatcher::Unlock()
{
if (mLocked) {
mLocked = false;
// Handle any pending updates one at a time. In the unlikely case where a
// lock is added during the update, break out.
while (!mLocked && mPendingUpdates.Length() > 0) {
nsString name = mPendingUpdates.ElementAt(0);
mPendingUpdates.RemoveElementAt(0);
UpdateCommands(name);
}
}
return NS_OK;
}

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

@ -68,6 +68,9 @@ protected:
bool Matches(const nsString& aList,
const nsAString& aElement);
bool mLocked;
nsTArray<nsString> mPendingUpdates;
};
#endif // nsXULCommandDispatcher_h__

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

@ -300,7 +300,7 @@ bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp)
return false;
}
#if !defined(SK_ARM_HAS_NEON)
#if !defined(SK_ARM_HAS_NEON) || defined(SK_ARM_HAS_OPTIONAL_NEON)
static const SampleProc32 gSkBitmapProcStateSample32[] = {
S32_opaque_D32_nofilter_DXDY,
S32_alpha_D32_nofilter_DXDY,

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

@ -56,7 +56,7 @@ extern const SkBitmapProcState::MatrixProc RepeatX_RepeatY_Procs_neon[];
#endif // defined(SK_ARM_HAS_NEON)
// Compile non-neon code path if needed
#if !defined(SK_ARM_HAS_NEON)
#if !defined(SK_ARM_HAS_NEON) || defined(SK_ARM_HAS_OPTIONAL_NEON)
#define MAKENAME(suffix) ClampX_ClampY ## suffix
#define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max)
#define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max)

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

@ -1217,8 +1217,8 @@ gfxFT2FontList::FindFonts()
FinalizeFamilyMemberList(key, family, /* aSortFaces */ false );
}
LOG(("got font list from chrome process: %d faces in %d families "
"and %d in hidden families",
LOG(("got font list from chrome process: %" PRIdPTR " faces in %"
PRIu32 " families and %" PRIu32 " in hidden families",
fonts.Length(), mFontFamilies.Count(),
mHiddenFontFamilies.Count()));
return;

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

@ -1552,13 +1552,19 @@ class MOZ_STACK_CLASS TryEmitter
// stream and fixed-up later.
//
// If ShouldUseControl is DontUseControl, all that handling is skipped.
// DontUseControl is used by yield*, that matches to the following:
// * has only one catch block
// * has no catch guard
// * has JSOP_GOTO at the end of catch-block
// * has no non-local-jump
// * doesn't use finally block for normal completion of try-block and
// DontUseControl is used by yield* and the internal try-catch around
// IteratorClose. These internal uses must:
// * have only one catch block
// * have no catch guard
// * have JSOP_GOTO at the end of catch-block
// * have no non-local-jump
// * don't use finally block for normal completion of try-block and
// catch-block
//
// Additionally, a finally block may be emitted when ShouldUseControl is
// DontUseControl, even if the kind is not TryCatchFinally or TryFinally,
// because GOSUBs are not emitted. This internal use shares the
// requirements as above.
Maybe<TryFinallyControl> controlInfo_;
int depth_;
@ -1726,7 +1732,17 @@ class MOZ_STACK_CLASS TryEmitter
public:
bool emitFinally(const Maybe<uint32_t>& finallyPos = Nothing()) {
MOZ_ASSERT(hasFinally());
// If we are using controlInfo_ (i.e., emitting a syntactic try
// blocks), we must have specified up front if there will be a finally
// close. For internal try blocks, like those emitted for yield* and
// IteratorClose inside for-of loops, we can emitFinally even without
// specifying up front, since the internal try blocks emit no GOSUBs.
if (!controlInfo_) {
if (kind_ == TryCatch)
kind_ = TryCatchFinally;
} else {
MOZ_ASSERT(hasFinally());
}
if (state_ == Try) {
if (!emitTryEnd())
@ -2022,6 +2038,10 @@ class ForOfLoopControl : public LoopControl
// }
Maybe<TryEmitter> tryCatch_;
// Used to track if any yields were emitted between calls to to
// emitBeginCodeNeedingIteratorClose and emitEndCodeNeedingIteratorClose.
uint32_t numYieldsAtBeginCodeNeedingIterClose_;
bool allowSelfHosted_;
IteratorKind iterKind_;
@ -2031,16 +2051,22 @@ class ForOfLoopControl : public LoopControl
IteratorKind iterKind)
: LoopControl(bce, StatementKind::ForOfLoop),
iterDepth_(iterDepth),
numYieldsAtBeginCodeNeedingIterClose_(UINT32_MAX),
allowSelfHosted_(allowSelfHosted),
iterKind_(iterKind)
{
}
bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce) {
tryCatch_.emplace(bce, TryEmitter::TryCatch, TryEmitter::DontUseRetVal);
tryCatch_.emplace(bce, TryEmitter::TryCatch, TryEmitter::DontUseRetVal,
TryEmitter::DontUseControl);
if (!tryCatch_->emitTry())
return false;
MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldAndAwaitOffsetList.numYields;
return true;
}
@ -2078,10 +2104,33 @@ class ForOfLoopControl : public LoopControl
if (!bce->emit1(JSOP_THROW)) // ITER ...
return false;
// If any yields were emitted, then this for-of loop is inside a star
// generator and must handle the case of Generator.return. Like in
// yield*, it is handled with a finally block.
uint32_t numYieldsEmitted = bce->yieldAndAwaitOffsetList.numYields;
if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
if (!tryCatch_->emitFinally())
return false;
IfThenElseEmitter ifGeneratorClosing(bce);
if (!bce->emit1(JSOP_ISGENCLOSING)) // ITER ... FTYPE FVALUE CLOSING
return false;
if (!ifGeneratorClosing.emitIf()) // ITER ... FTYPE FVALUE
return false;
if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER
return false;
if (!emitIteratorClose(bce, CompletionKind::Normal)) // ITER ... FTYPE FVALUE
return false;
if (!ifGeneratorClosing.emitEnd()) // ITER ... FTYPE FVALUE
return false;
}
if (!tryCatch_->emitEnd())
return false;
tryCatch_.reset();
numYieldsAtBeginCodeNeedingIterClose_ = UINT32_MAX;
return true;
}
@ -4829,6 +4878,11 @@ BytecodeEmitter::emitYieldOp(JSOp op)
return false;
}
if (op == JSOP_AWAIT)
yieldAndAwaitOffsetList.numAwaits++;
else
yieldAndAwaitOffsetList.numYields++;
SET_UINT24(code(off), yieldAndAwaitIndex);
if (!yieldAndAwaitOffsetList.append(offset()))

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

@ -101,7 +101,9 @@ struct CGScopeNoteList {
struct CGYieldAndAwaitOffsetList {
Vector<uint32_t> list;
explicit CGYieldAndAwaitOffsetList(JSContext* cx) : list(cx) {}
uint32_t numYields;
uint32_t numAwaits;
explicit CGYieldAndAwaitOffsetList(JSContext* cx) : list(cx), numYields(0), numAwaits(0) {}
MOZ_MUST_USE bool append(uint32_t offset) { return list.append(offset); }
size_t length() const { return list.length(); }

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

@ -1277,12 +1277,12 @@ CacheIRCompiler::emitGuardIsInt32Index()
return true;
}
ValueOperand input = allocator.useValueRegister(masm, inputId);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
ValueOperand input = allocator.useValueRegister(masm, inputId);
Label notInt32, done;
masm.branchTestInt32(Assembler::NotEqual, input, &notInt32);
masm.unboxInt32(input, output);

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

@ -315,7 +315,7 @@ mapMemoryAt(void* desired, size_t length)
#if defined(__ia64__) || defined(__aarch64__) || \
(defined(__sparc__) && defined(__arch64__) && (defined(__NetBSD__) || defined(__linux__)))
MOZ_RELEASE_ASSERT(0xffff800000000000ULL & (uintptr_t(desired) + length - 1) == 0);
MOZ_RELEASE_ASSERT((0xffff800000000000ULL & (uintptr_t(desired) + length - 1)) == 0);
#endif
void* region = mmap(desired, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (region == MAP_FAILED)

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

@ -66,6 +66,8 @@
# define GETRANDOM_NR 318
# elif defined(__i386__)
# define GETRANDOM_NR 355
# elif defined(__aarch64__)
# define GETRANDOM_NR 278
# elif defined(__arm__)
# define GETRANDOM_NR 384
// Added other architectures:

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

@ -16,7 +16,7 @@
# include <pthread_np.h>
# endif
# if defined(ANDROID)
# if defined(ANDROID) && !defined(__aarch64__)
# include <sys/types.h>
# include <unistd.h>
# endif
@ -120,11 +120,11 @@ js::GetNativeStackBaseImpl()
rc = pthread_stackseg_np(pthread_self(), &ss);
stackBase = (void*)((size_t) ss.ss_sp - ss.ss_size);
stackSize = ss.ss_size;
# elif defined(ANDROID)
# elif defined(ANDROID) && !defined(__aarch64__)
if (gettid() == getpid()) {
// bionic's pthread_attr_getstack doesn't tell the truth for the main
// thread (see bug 846670). So we scan /proc/self/maps to find the
// segment which contains the stack.
// bionic's pthread_attr_getstack prior to API 21 doesn't tell the truth
// for the main thread (see bug 846670). So we scan /proc/self/maps to
// find the segment which contains the stack.
rc = -1;
// Put the string on the stack, otherwise there is the danger that it

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

@ -0,0 +1,58 @@
// Test that IteratorClose is called when a Generator is abruptly completed by
// Generator.return.
var returnCalled = 0;
function* wrapNoThrow() {
let iter = {
[Symbol.iterator]() {
return this;
},
next() {
return { value: 10, done: false };
},
return() {
returnCalled++;
return {};
}
};
for (const i of iter) {
yield i;
}
}
// Breaking calls Generator.return, which causes the yield above to resume with
// an abrupt completion of kind "return", which then calls
// iter.return.
for (const i of wrapNoThrow()) {
break;
}
assertEq(returnCalled, 1);
function* wrapThrow() {
let iter = {
[Symbol.iterator]() {
return this;
},
next() {
return { value: 10, done: false };
},
return() {
throw 42;
}
};
for (const i of iter) {
yield i;
}
}
// Breaking calls Generator.return, which, like above, calls iter.return. If
// iter.return throws, since the yield is resuming with an abrupt completion of
// kind "return", the newly thrown value takes precedence over returning.
assertThrowsValue(() => {
for (const i of wrapThrow()) {
break;
}
}, 42);
if (typeof reportCompare === "function")
reportCompare(0, 0);

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

@ -61,7 +61,7 @@ rdtsc(void)
return result;
}
#elif defined(__arm__)
#elif defined(__arm__) || defined(__aarch64__)
#include <sys/time.h>

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

@ -1374,6 +1374,7 @@ ProcessHasSignalHandlers()
sTriedInstallSignalHandlers = true;
#if defined(ANDROID)
# if !defined(__aarch64__)
// Before Android 4.4 (SDK version 19), there is a bug
// https://android-review.googlesource.com/#/c/52333
// in Bionic's pthread_join which causes pthread_join to return early when
@ -1385,6 +1386,7 @@ ProcessHasSignalHandlers()
if (atol(version_string) < 19)
return false;
}
# endif
# if defined(MOZ_LINKER)
// Signal handling is broken on some android systems.
if (IsSignalHandlingBroken())

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

@ -503,7 +503,7 @@ bool OmxDecoder::Init()
int64_t durationUs;
if (videoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
if (durationUs < 0)
LOG("video duration %lld should be nonnegative", durationUs);
LOG("video duration %" PRId64 " should be nonnegative", durationUs);
if (durationUs > totalDurationUs)
totalDurationUs = durationUs;
}
@ -536,7 +536,7 @@ bool OmxDecoder::Init()
int64_t durationUs;
if (audioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
if (durationUs < 0)
LOG("audio duration %lld should be nonnegative", durationUs);
LOG("audio duration %" PRId64 " should be nonnegative", durationUs);
if (durationUs > totalDurationUs)
totalDurationUs = durationUs;
}
@ -913,7 +913,7 @@ bool OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aSeekTimeUs,
}
if (timeUs < 0) {
LOG("frame time %lld must be nonnegative", timeUs);
LOG("frame time %" PRId64 " must be nonnegative", timeUs);
return false;
}
@ -977,7 +977,7 @@ bool OmxDecoder::ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs)
}
if (timeUs < 0) {
LOG("frame time %lld must be nonnegative", timeUs);
LOG("frame time %" PRId64 " must be nonnegative", timeUs);
return false;
}

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

@ -1155,10 +1155,10 @@ int32_t WebrtcMediaCodecVP8VideoDecoder::Decode(
const webrtc::CodecSpecificInfo* codecSpecificInfo,
int64_t renderTimeMs) {
CSFLogDebug(logTag, "%s, renderTimeMs = %lld ", __FUNCTION__, renderTimeMs);
CSFLogDebug(logTag, "%s, renderTimeMs = %" PRId64, __FUNCTION__, renderTimeMs);
if (inputImage._length== 0 || !inputImage._buffer) {
CSFLogDebug(logTag, "%s, input Image invalid. length = %d", __FUNCTION__, inputImage._length);
CSFLogDebug(logTag, "%s, input Image invalid. length = %" PRIdPTR, __FUNCTION__, inputImage._length);
return WEBRTC_VIDEO_CODEC_ERROR;
}

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

@ -49,4 +49,36 @@
# define PRIXPTR "X" /* uintptr_t */
#endif
/*
* Fix up Android's broken macros for [u]int_fastN_t. On ARM64, Android's
* PRI*FAST16/32 macros are defined as "d", but the types themselves are defined
* as long and unsigned long.
*/
#if defined(ANDROID) && defined(__LP64__)
# undef PRIdFAST16 /* int_fast16_t */
# define PRIdFAST16 PRId64 /* int_fast16_t */
# undef PRIiFAST16 /* int_fast16_t */
# define PRIiFAST16 PRIi64 /* int_fast16_t */
# undef PRIoFAST16 /* uint_fast16_t */
# define PRIoFAST16 PRIo64 /* uint_fast16_t */
# undef PRIuFAST16 /* uint_fast16_t */
# define PRIuFAST16 PRIu64 /* uint_fast16_t */
# undef PRIxFAST16 /* uint_fast16_t */
# define PRIxFAST16 PRIx64 /* uint_fast16_t */
# undef PRIXFAST16 /* uint_fast16_t */
# define PRIXFAST16 PRIX64 /* uint_fast16_t */
# undef PRIdFAST32 /* int_fast32_t */
# define PRIdFAST32 PRId64 /* int_fast32_t */
# undef PRIiFAST32 /* int_fast32_t */
# define PRIiFAST32 PRIi64 /* int_fast32_t */
# undef PRIoFAST32 /* uint_fast32_t */
# define PRIoFAST32 PRIo64 /* uint_fast32_t */
# undef PRIuFAST32 /* uint_fast32_t */
# define PRIuFAST32 PRIu64 /* uint_fast32_t */
# undef PRIxFAST32 /* uint_fast32_t */
# define PRIxFAST32 PRIx64 /* uint_fast32_t */
# undef PRIXFAST32 /* uint_fast32_t */
# define PRIXFAST32 PRIX64 /* uint_fast32_t */
#endif
#endif /* mozilla_IntegerPrintfMacros_h_ */

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

@ -921,3 +921,7 @@ pref("webchannel.allowObject.urlWhitelist", "https://accounts.firefox.com https:
pref("media.openUnsupportedTypeWithExternalApp", true);
pref("dom.keyboardevent.dispatch_during_composition", true);
#if CPU_ARCH == aarch64
pref("javascript.options.native_regexp", false);
#endif

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

@ -34,7 +34,7 @@ with Files('src/test/**'):
for var in ('APP_NAME', 'APP_VERSION'):
DEFINES[var] = CONFIG['MOZ_%s' % var]
for var in ('MOZ_UPDATER', 'MOZ_APP_UA_NAME', 'ANDROID_PACKAGE_NAME'):
for var in ('MOZ_UPDATER', 'MOZ_APP_UA_NAME', 'ANDROID_PACKAGE_NAME', 'CPU_ARCH'):
DEFINES[var] = CONFIG[var]
for var in ('MOZ_ANDROID_GCM', ):

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

@ -1251,6 +1251,10 @@ pref("dom.select_popup_in_parent.enabled", false);
// Enable Directory API. By default, disabled.
pref("dom.input.dirpicker", false);
// Enable not moving the cursor to end when a text input or textarea has .value
// set to the value it already has. By default, enabled.
pref("dom.input.skip_cursor_move_for_same_value_set", false);
// Enables system messages and activities
pref("dom.sysmsg.enabled", false);

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

@ -248,6 +248,17 @@ PrintError(const char* aPrefix)
LocalFree(lpMsgBuf);
}
static void
InitializeDbgHelpCriticalSection()
{
static bool initialized = false;
if (initialized) {
return;
}
::InitializeCriticalSection(&gDbgHelpCS);
initialized = true;
}
static unsigned int WINAPI WalkStackThread(void* aData);
static bool
@ -300,8 +311,7 @@ EnsureWalkThreadReady()
stackWalkThread = nullptr;
readyEvent = nullptr;
::InitializeCriticalSection(&gDbgHelpCS);
InitializeDbgHelpCriticalSection();
return walkThreadReady = true;
}
@ -851,9 +861,7 @@ EnsureSymInitialized()
return gInitialized;
}
if (!EnsureWalkThreadReady()) {
return false;
}
InitializeDbgHelpCriticalSection();
SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
retStat = SymInitialize(GetCurrentProcess(), nullptr, TRUE);

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

@ -462,7 +462,7 @@ FTPChannelParent::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
// performing a document load.
PContentParent* pcp = Manager()->Manager();
DebugOnly<nsresult> rv =
static_cast<ContentParent*>(pcp)->AboutToLoadDocumentForChild(chan);
static_cast<ContentParent*>(pcp)->AboutToLoadHttpFtpWyciwygDocumentForChild(chan);
MOZ_ASSERT(NS_SUCCEEDED(rv));
int64_t contentLength;

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

@ -1148,7 +1148,7 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
PContentParent* pcp = Manager()->Manager();
MOZ_ASSERT(pcp, "We should have a manager if our IPC isn't closed");
DebugOnly<nsresult> rv =
static_cast<ContentParent*>(pcp)->AboutToLoadDocumentForChild(chan);
static_cast<ContentParent*>(pcp)->AboutToLoadHttpFtpWyciwygDocumentForChild(chan);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}

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

@ -326,7 +326,7 @@ WyciwygChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext
// Send down any permissions which are relevant to this URL if we are
// performing a document load.
PContentParent* pcp = Manager()->Manager();
rv = static_cast<ContentParent*>(pcp)->AboutToLoadDocumentForChild(chan);
rv = static_cast<ContentParent*>(pcp)->AboutToLoadHttpFtpWyciwygDocumentForChild(chan);
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsresult status;

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

@ -77,7 +77,7 @@ linux64-devedition/opt:
job-name: linux64-opt
treeherder:
platform: linux64-devedition/opt
symbol: tc(DE)
symbol: tc(B)
worker-type: aws-provisioner-v1/gecko-{level}-b-linux
worker:
implementation: docker-worker
@ -176,7 +176,7 @@ linux-devedition/opt:
job-name: linux-opt
treeherder:
platform: linux32-devedition/opt
symbol: tc(DE)
symbol: tc(B)
worker-type: aws-provisioner-v1/gecko-{level}-b-linux
worker:
implementation: docker-worker

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

@ -6,7 +6,7 @@ macosx64/debug:
treeherder:
platform: osx-10-7/debug
symbol: tc(B)
tier: 2
tier: 1
worker-type: aws-provisioner-v1/gecko-{level}-b-macosx64
worker:
implementation: docker-worker

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

@ -238,9 +238,9 @@ def target_tasks_mozilla_beta(full_task_graph, parameters):
platform = task.attributes.get('build_platform')
if platform in ('linux64-pgo', 'linux-pgo', 'win32-pgo', 'win64-pgo',
'android-api-15-nightly', 'android-x86-nightly',
'win32', 'win64', 'macosx64'):
'win32', 'win64'):
return False
if platform in ('linux64', 'linux'):
if platform in ('linux64', 'linux', 'macosx64'):
if task.attributes['build_type'] == 'opt':
return False
# skip l10n, beetmover, balrog

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

@ -1,4 +1,6 @@
config = {
'src_mozconfig': 'browser/config/mozconfigs/macosx64/devedition',
'force_clobber': True,
'stage_platform': 'macosx64-devedition',
'stage_product': 'devedition',
}

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

@ -1,4 +1,6 @@
config = {
'src_mozconfig': 'browser/config/mozconfigs/win32/devedition',
'force_clobber': True,
'stage_platform': 'win32-devedition',
'stage_product': 'devedition',
}

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

@ -1,4 +1,6 @@
config = {
'src_mozconfig': 'browser/config/mozconfigs/win64/devedition',
'force_clobber': True,
'stage_platform': 'win64-devedition',
'stage_product': 'devedition',
}

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

@ -2044,9 +2044,8 @@ CreateJSHangHistogram(JSContext* cx, const Telemetry::HangHistogram& hang)
}
if (!hang.GetNativeStack().empty()) {
const Telemetry::HangStack& stack = hang.GetNativeStack();
const std::vector<uintptr_t>& frames = stack.GetNativeFrames();
Telemetry::ProcessedStack processed = Telemetry::GetStackAndModules(frames);
const Telemetry::NativeHangStack& stack = hang.GetNativeStack();
Telemetry::ProcessedStack processed = Telemetry::GetStackAndModules(stack);
CombinedStacks singleStack;
singleStack.AddStack(processed);

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

@ -45,13 +45,19 @@ public:
void Add(PRIntervalTime aTime);
};
/* A native stack is a simple list of pointers, so rather than building a
wrapper type, we typdef the type here. */
typedef std::vector<uintptr_t> NativeHangStack;
/* HangStack stores an array of const char pointers,
with optional internal storage for strings. */
class HangStack
{
public:
static const size_t sMaxInlineStorage = 8;
// The maximum depth for the native stack frames that we might collect.
// XXX: Consider moving this to a different object?
static const size_t sMaxNativeFrames = 25;
private:
@ -61,11 +67,6 @@ private:
// Stack entries can either be a static const char*
// or a pointer to within this buffer.
mozilla::Vector<char, 0> mBuffer;
// When a native stack is gathered, this vector holds the raw program counter
// values that MozStackWalk will return to us after it walks the stack.
// When gathering the Telemetry payload, Telemetry will take care of mapping
// these program counters to proper addresses within modules.
std::vector<uintptr_t> mNativeFrames;
public:
HangStack() {}
@ -76,6 +77,12 @@ public:
{
}
HangStack& operator=(HangStack&& aOther) {
mImpl = mozilla::Move(aOther.mImpl);
mBuffer = mozilla::Move(aOther.mBuffer);
return *this;
}
bool operator==(const HangStack& aOther) const {
for (size_t i = 0; i < length(); i++) {
if (!IsSameAsEntry(operator[](i), aOther[i])) {
@ -118,7 +125,6 @@ public:
void clear() {
mImpl.clear();
mBuffer.clear();
mNativeFrames.clear();
}
bool IsInBuffer(const char* aEntry) const {
@ -144,21 +150,6 @@ public:
const char* InfallibleAppendViaBuffer(const char* aText, size_t aLength);
const char* AppendViaBuffer(const char* aText, size_t aLength);
void EnsureNativeFrameCapacity(size_t aCapacity) {
mNativeFrames.reserve(aCapacity);
}
void AppendNativeFrame(uintptr_t aPc) {
MOZ_ASSERT(mNativeFrames.size() <= sMaxNativeFrames);
if (mNativeFrames.size() < sMaxNativeFrames) {
mNativeFrames.push_back(aPc);
}
}
const std::vector<uintptr_t>& GetNativeFrames() const {
return mNativeFrames;
}
};
/* A hang histogram consists of a stack associated with the
@ -170,7 +161,7 @@ private:
HangStack mStack;
// Native stack that corresponds to the pseudostack in mStack
HangStack mNativeStack;
NativeHangStack mNativeStack;
// Use a hash to speed comparisons
const uint32_t mHash;
// Annotations attributed to this stack
@ -182,6 +173,15 @@ public:
, mHash(GetHash(mStack))
{
}
explicit HangHistogram(HangStack&& aStack,
NativeHangStack&& aNativeStack)
: mStack(mozilla::Move(aStack))
, mNativeStack(mozilla::Move(aNativeStack))
, mHash(GetHash(mStack))
{
}
HangHistogram(HangHistogram&& aOther)
: TimeHistogram(mozilla::Move(aOther))
, mStack(mozilla::Move(aOther.mStack))
@ -198,10 +198,10 @@ public:
const HangStack& GetStack() const {
return mStack;
}
HangStack& GetNativeStack() {
NativeHangStack& GetNativeStack() {
return mNativeStack;
}
const HangStack& GetNativeStack() const {
const NativeHangStack& GetNativeStack() const {
return mNativeStack;
}
const HangMonitor::HangAnnotationsVector& GetAnnotations() const {
@ -231,16 +231,20 @@ private:
public:
TimeHistogram mActivity;
mozilla::Vector<HangHistogram, 4> mHangs;
uint32_t mNativeStackCnt;
explicit ThreadHangStats(const char* aName)
: mName(aName)
, mNativeStackCnt(0)
{
}
ThreadHangStats(ThreadHangStats&& aOther)
: mName(mozilla::Move(aOther.mName))
, mActivity(mozilla::Move(aOther.mActivity))
, mHangs(mozilla::Move(aOther.mHangs))
, mNativeStackCnt(aOther.mNativeStackCnt)
{
aOther.mNativeStackCnt = 0;
}
const char* GetName() const {
return mName.get();

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

@ -84,8 +84,8 @@ function run_test() {
notEqual(endHangs.hangs[0].stack.length, 0);
equal(typeof endHangs.hangs[0].stack[0], "string");
// Native stack gathering is only enabled on Windows.
if (mozinfo.os == "win") {
// Native stack gathering is only enabled on Windows x86.
if (mozinfo.os == "win" && mozinfo.bits == 32) {
// Make sure one of the hangs is a permanent
// hang containing a native stack.
ok(endHangs.hangs.some((hang) => (

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

@ -701,9 +701,17 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *appDir, int appArgc,
}
#elif defined(XP_MACOSX)
UpdateDriverSetupMacCommandLine(argc, argv, restart);
// LaunchChildMac uses posix_spawnp and prefers the current
// architecture when launching. It doesn't require a
// null-terminated string but it doesn't matter if we pass one.
// We need to detect whether elevation is required for this update. This can
// occur when an admin user installs the application, but another admin
// user attempts to update (see bug 394984).
if (restart && !IsRecursivelyWritable(installDirPath.get())) {
if (!LaunchElevatedUpdate(argc, argv, outpid)) {
LOG(("Failed to launch elevated update!"));
exit(1);
}
exit(0);
}
if (isStaged) {
// Launch the updater to replace the installation with the staged updated.
LaunchChildMac(argc, argv);
@ -711,6 +719,9 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *appDir, int appArgc,
// Launch the updater to either stage or apply an update.
LaunchChildMac(argc, argv, outpid);
}
if (restart) {
exit(0);
}
#else
if (isStaged) {
// Launch the updater to replace the installation with the staged updated.

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

@ -22,7 +22,6 @@
#include "mozilla/StaticPtr.h"
#include "mozilla/ThreadLocal.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Sprintf.h"
#include "mozilla/StaticPtr.h"
#include "PseudoStack.h"
#include "ThreadInfo.h"
@ -675,7 +674,7 @@ AddDynamicCodeLocationTag(ProfileBuffer* aBuffer, const char* aStr)
}
}
static const int SAMPLER_MAX_STRING_LENGTH = 128;
static const int SAMPLER_MAX_STRING_LENGTH = 512;
static void
AddPseudoEntry(PSLockRef aLock, ProfileBuffer* aBuffer,
@ -700,9 +699,17 @@ AddPseudoEntry(PSLockRef aLock, ProfileBuffer* aBuffer,
if (entry.isCopyLabel() || dynamicString) {
if (dynamicString) {
int bytesWritten =
SprintfLiteral(combinedStringBuffer, "%s %s", sampleLabel, dynamicString);
if (bytesWritten > 0) {
// Create a string that is sampleLabel + ' ' + annotationString.
// Avoid sprintf because it can take a lock on Windows, and this
// code runs during the profiler's "critical section" as defined
// in SamplerThread::SuspendAndSampleAndResumeThread.
size_t labelLength = strlen(sampleLabel);
size_t dynamicLength = strlen(dynamicString);
if (labelLength + 1 + dynamicLength < ArrayLength(combinedStringBuffer)) {
PodCopy(combinedStringBuffer, sampleLabel, labelLength);
combinedStringBuffer[labelLength] = ' ';
PodCopy(&combinedStringBuffer[labelLength + 1], dynamicString, dynamicLength);
combinedStringBuffer[labelLength + 1 + dynamicLength] = '\0';
sampleLabel = combinedStringBuffer;
}
}
@ -3069,5 +3076,16 @@ profiler_call_exit(void* aHandle)
pseudoStack->pop();
}
void*
profiler_get_stack_top()
{
PSAutoLock lock(gPSMutex);
ThreadInfo* threadInfo = FindLiveThreadInfo(lock);
if (threadInfo) {
return threadInfo->StackTop();
}
return nullptr;
}
// END externally visible functions
////////////////////////////////////////////////////////////////////////

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

@ -315,6 +315,12 @@ PROFILER_FUNC(double profiler_time(), 0)
PROFILER_FUNC_VOID(profiler_log(const char *str))
// Gets the stack top of the current thread.
//
// The thread must have been previously registered with the profiler, otherwise
// this method will return nullptr.
PROFILER_FUNC(void* profiler_get_stack_top(), nullptr)
// End of the functions defined whether the profiler is enabled or not.
#if defined(MOZ_GECKO_PROFILER)

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

@ -3418,7 +3418,7 @@ static const NSString* kStateCollectionBehavior = @"collectionBehavior";
- (void)restoreBackgroundColor
{
[super setBackgroundColor:mColor];
[super setBackgroundColor:mBackgroundColor];
}
- (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect

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

@ -32,6 +32,16 @@
// It can be scaled back again in the future
#define BHR_BETA_MOD 1;
// This variable controls the maximum number of native hang stacks which may be
// attached to a ping. This is due to how large native stacks can be. We want to
// reduce the chance of a ping being discarded due to it exceeding the maximum
// ping size.
//
// NOTE: 300 native hang stacks would, by a rough estimation based on stacks
// collected from nightly on March 21, 2017, take up approximately 168kb of
// space.
static const uint32_t kMaximumNativeHangStacks = 300;
// Maximum depth of the call stack in the reported thread hangs. This value represents
// the 99.9th percentile of the thread hangs stack depths reported by Telemetry.
static const size_t kMaxThreadHangStackDepth = 30;
@ -180,6 +190,8 @@ public:
ThreadStackHelper mStackHelper;
// Stack of current hang
Telemetry::HangStack mHangStack;
// Native stack of current hang
Telemetry::NativeHangStack mNativeHangStack;
// Statistics for telemetry
Telemetry::ThreadHangStats mStats;
// Annotations for the current hang
@ -332,7 +344,19 @@ BackgroundHangManager::RunMonitorThread()
if (MOZ_LIKELY(!currentThread->mHanging)) {
if (MOZ_UNLIKELY(hangTime >= currentThread->mTimeout)) {
// A hang started
currentThread->mStackHelper.GetStack(currentThread->mHangStack);
#ifdef NIGHTLY_BUILD
if (currentThread->mStats.mNativeStackCnt < kMaximumNativeHangStacks) {
// NOTE: In nightly builds of firefox we want to collect native stacks
// for all hangs, not just permahangs.
currentThread->mStats.mNativeStackCnt += 1;
currentThread->mStackHelper.GetPseudoAndNativeStack(
currentThread->mHangStack, currentThread->mNativeHangStack);
} else {
currentThread->mStackHelper.GetPseudoStack(currentThread->mHangStack);
}
#else
currentThread->mStackHelper.GetPseudoStack(currentThread->mHangStack);
#endif
currentThread->mHangStart = interval;
currentThread->mHanging = true;
currentThread->mAnnotations =
@ -451,7 +475,7 @@ BackgroundHangThread::ReportHang(PRIntervalTime aHangTime)
mHangStack.erase(mHangStack.begin() + 1, mHangStack.begin() + elementsToRemove);
}
Telemetry::HangHistogram newHistogram(Move(mHangStack));
Telemetry::HangHistogram newHistogram(Move(mHangStack), Move(mNativeHangStack));
for (Telemetry::HangHistogram* oldHistogram = mStats.mHangs.begin();
oldHistogram != mStats.mHangs.end(); oldHistogram++) {
if (newHistogram == *oldHistogram) {
@ -475,9 +499,12 @@ BackgroundHangThread::ReportPermaHang()
// mManager->mLock IS locked
Telemetry::HangHistogram& hang = ReportHang(mMaxTimeout);
Telemetry::HangStack& stack = hang.GetNativeStack();
Telemetry::NativeHangStack& stack = hang.GetNativeStack();
if (stack.empty()) {
mStackHelper.GetNativeStack(stack);
mStats.mNativeStackCnt += 1;
if (mStats.mNativeStackCnt <= kMaximumNativeHangStacks) {
mStackHelper.GetNativeStack(stack);
}
}
}

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

@ -134,6 +134,7 @@ ThreadStackHelper::ThreadStackHelper()
| THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION
#endif
, FALSE, 0);
mStackTop = profiler_get_stack_top();
MOZ_ASSERT(mInitialized);
#elif defined(XP_MACOSX)
mThreadID = mach_thread_self();
@ -164,40 +165,42 @@ public:
} // namespace
void
ThreadStackHelper::GetStack(Stack& aStack)
ThreadStackHelper::GetPseudoStack(Stack& aStack)
{
GetStackInternal(aStack, /* aAppendNativeStack */ false);
GetStacksInternal(&aStack, nullptr);
}
void
ThreadStackHelper::GetStackInternal(Stack& aStack, bool aAppendNativeStack)
ThreadStackHelper::GetStacksInternal(Stack* aStack, NativeStack* aNativeStack)
{
// Always run PrepareStackBuffer first to clear aStack
if (!PrepareStackBuffer(aStack)) {
if (aStack && !PrepareStackBuffer(*aStack)) {
// Skip and return empty aStack
return;
}
ScopedSetPtr<Stack> stackPtr(mStackToFill, &aStack);
ScopedSetPtr<Stack> stackPtr(mStackToFill, aStack);
#if defined(XP_LINUX)
if (!sInitialized) {
MOZ_ASSERT(false);
return;
}
siginfo_t uinfo = {};
uinfo.si_signo = sFillStackSignum;
uinfo.si_code = SI_QUEUE;
uinfo.si_pid = getpid();
uinfo.si_uid = getuid();
uinfo.si_value.sival_ptr = this;
if (::syscall(SYS_rt_tgsigqueueinfo, uinfo.si_pid,
mThreadID, sFillStackSignum, &uinfo)) {
// rt_tgsigqueueinfo was added in Linux 2.6.31.
// Could have failed because the syscall did not exist.
return;
if (aStack) {
siginfo_t uinfo = {};
uinfo.si_signo = sFillStackSignum;
uinfo.si_code = SI_QUEUE;
uinfo.si_pid = getpid();
uinfo.si_uid = getuid();
uinfo.si_value.sival_ptr = this;
if (::syscall(SYS_rt_tgsigqueueinfo, uinfo.si_pid,
mThreadID, sFillStackSignum, &uinfo)) {
// rt_tgsigqueueinfo was added in Linux 2.6.31.
// Could have failed because the syscall did not exist.
return;
}
MOZ_ALWAYS_TRUE(!::sem_wait(&mSem));
}
MOZ_ALWAYS_TRUE(!::sem_wait(&mSem));
#elif defined(XP_WIN)
if (!mInitialized) {
@ -205,9 +208,14 @@ ThreadStackHelper::GetStackInternal(Stack& aStack, bool aAppendNativeStack)
return;
}
if (aAppendNativeStack) {
aStack.EnsureNativeFrameCapacity(Telemetry::HangStack::sMaxNativeFrames);
// NOTE: We can only perform frame pointer stack walking on non win64
// platforms, because Win64 always omits frame pointers. We don't want to use
// MozStackWalk here, so we just skip collecting stacks entirely.
#ifndef MOZ_THREADSTACKHELPER_X64
if (aNativeStack) {
aNativeStack->reserve(Telemetry::HangStack::sMaxNativeFrames);
}
#endif
if (::SuspendThread(mThreadID) == DWORD(-1)) {
MOZ_ASSERT(false);
@ -218,21 +226,49 @@ ThreadStackHelper::GetStackInternal(Stack& aStack, bool aAppendNativeStack)
// GetThreadContext to ensure it's really suspended.
// See https://blogs.msdn.microsoft.com/oldnewthing/20150205-00/?p=44743.
CONTEXT context;
memset(&context, 0, sizeof(context));
context.ContextFlags = CONTEXT_CONTROL;
if (::GetThreadContext(mThreadID, &context)) {
FillStackBuffer();
}
if (aStack) {
FillStackBuffer();
}
if (aAppendNativeStack) {
auto callback = [](uint32_t, void* aPC, void*, void* aClosure) {
Stack* stack = static_cast<Stack*>(aClosure);
stack->AppendNativeFrame(reinterpret_cast<uintptr_t>(aPC));
};
#ifndef MOZ_THREADSTACKHELPER_X64
if (aNativeStack) {
auto callback = [](uint32_t, void* aPC, void*, void* aClosure) {
NativeStack* stack = static_cast<NativeStack*>(aClosure);
stack->push_back(reinterpret_cast<uintptr_t>(aPC));
};
MozStackWalk(callback, /* skipFrames */ 0,
/* maxFrames */ Telemetry::HangStack::sMaxNativeFrames,
reinterpret_cast<void*>(&aStack),
reinterpret_cast<uintptr_t>(mThreadID), nullptr);
// Now we need to get our frame pointer, our stack pointer, and our stack
// top. Rather than registering and storing the stack tops ourselves, we use
// the gecko profiler to look it up.
void** framePointer = reinterpret_cast<void**>(context.Ebp);
void** stackPointer = reinterpret_cast<void**>(context.Esp);
MOZ_ASSERT(mStackTop, "The thread should be registered by the profiler");
// Double check that the values we pulled for the thread make sense before
// walking the stack.
if (mStackTop && framePointer >= stackPointer && framePointer < mStackTop) {
// NOTE: In bug 1346415 this was changed to use FramePointerStackWalk.
// This was done because lowering the background hang timer threshold
// would cause it to fire on infra early during the boot process, causing
// a deadlock in MozStackWalk when the target thread was holding the
// windows-internal lock on the function table, as it would be suspended
// before we tried to grab the lock to walk its stack.
//
// FramePointerStackWalk is implemented entirely in userspace and thus
// doesn't have the same issues with deadlocking. Unfortunately as 64-bit
// windows is not guaranteed to have frame pointers, the stack walking
// code is only enabled on 32-bit windows builds (bug 1357829).
FramePointerStackWalk(callback, /* skipFrames */ 0,
/* maxFrames */ Telemetry::HangStack::sMaxNativeFrames,
reinterpret_cast<void*>(aNativeStack), framePointer,
mStackTop);
}
}
#endif
}
MOZ_ALWAYS_TRUE(::ResumeThread(mThreadID) != DWORD(-1));
@ -246,26 +282,34 @@ ThreadStackHelper::GetStackInternal(Stack& aStack, bool aAppendNativeStack)
}
# endif
if (::thread_suspend(mThreadID) != KERN_SUCCESS) {
MOZ_ASSERT(false);
return;
if (aStack) {
if (::thread_suspend(mThreadID) != KERN_SUCCESS) {
MOZ_ASSERT(false);
return;
}
FillStackBuffer();
MOZ_ALWAYS_TRUE(::thread_resume(mThreadID) == KERN_SUCCESS);
}
FillStackBuffer();
MOZ_ALWAYS_TRUE(::thread_resume(mThreadID) == KERN_SUCCESS);
#endif
}
void
ThreadStackHelper::GetNativeStack(Stack& aStack)
ThreadStackHelper::GetNativeStack(NativeStack& aNativeStack)
{
#ifdef MOZ_THREADSTACKHELPER_NATIVE
GetStackInternal(aStack, /* aAppendNativeStack */ true);
GetStacksInternal(nullptr, &aNativeStack);
#endif // MOZ_THREADSTACKHELPER_NATIVE
}
void
ThreadStackHelper::GetPseudoAndNativeStack(Stack& aStack, NativeStack& aNativeStack)
{
GetStacksInternal(&aStack, &aNativeStack);
}
#ifdef XP_LINUX
int ThreadStackHelper::sInitialized;

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

@ -60,6 +60,12 @@ class ThreadStackHelper
public:
typedef Telemetry::HangStack Stack;
// When a native stack is gathered, this vector holds the raw program counter
// values that FramePointerStackWalk will return to us after it walks the
// stack. When gathering the Telemetry payload, Telemetry will take care of
// mapping these program counters to proper addresses within modules.
typedef Telemetry::NativeHangStack NativeStack;
private:
Stack* mStackToFill;
#ifdef MOZ_THREADSTACKHELPER_PSEUDO
@ -99,18 +105,31 @@ public:
*
* @param aStack Stack instance to be filled.
*/
void GetStack(Stack& aStack);
void GetPseudoStack(Stack& aStack);
/**
* Retrieve the current native stack of the thread associated
* with this ThreadStackHelper.
*
* @param aNativeStack Stack instance to be filled.
* @param aNativeStack NativeStack instance to be filled.
*/
void GetNativeStack(Stack& aStack);
void GetNativeStack(NativeStack& aNativeStack);
/**
* Retrieve the current pseudostack and native stack of the thread associated
* with this ThreadStackHelper. This method only pauses the target thread once
* to get both stacks.
*
* @param aStack Stack instance to be filled with the pseudostack.
* @param aNativeStack NativeStack instance to be filled with the native stack.
*/
void GetPseudoAndNativeStack(Stack& aStack, NativeStack& aNativeStack);
private:
void GetStackInternal(Stack& aStack, bool aAppendNativeStack);
// Fill in the passed aStack and aNativeStack datastructures with backtraces.
// If only aStack needs to be collected, nullptr may be passed for
// aNativeStack, and vice versa.
void GetStacksInternal(Stack* aStack, NativeStack* aNativeStack);
#if defined(XP_LINUX)
private:
static int sInitialized;
@ -125,6 +144,7 @@ private:
private:
bool mInitialized;
HANDLE mThreadID;
void* mStackTop;
#elif defined(XP_MACOSX)
private: