diff --git a/browser/components/aboutlogins/content/aboutLogins.html b/browser/components/aboutlogins/content/aboutLogins.html index 7a5b3d0b0c2de..88bb54f13e9b3 100644 --- a/browser/components/aboutlogins/content/aboutLogins.html +++ b/browser/components/aboutlogins/content/aboutLogins.html @@ -198,6 +198,7 @@

diff --git a/browser/components/aboutlogins/content/components/fxaccounts-button.css b/browser/components/aboutlogins/content/components/fxaccounts-button.css index 139bf974cd577..03a0a455b24bf 100644 --- a/browser/components/aboutlogins/content/components/fxaccounts-button.css +++ b/browser/components/aboutlogins/content/components/fxaccounts-button.css @@ -28,7 +28,6 @@ } .fxaccount-email { - font-weight: 600; font-size: .9em; vertical-align: middle; } diff --git a/browser/components/aboutlogins/content/components/login-item.css b/browser/components/aboutlogins/content/components/login-item.css index 8a01debd3c110..d8f35bf012135 100644 --- a/browser/components/aboutlogins/content/components/login-item.css +++ b/browser/components/aboutlogins/content/components/login-item.css @@ -148,7 +148,7 @@ input[type="url"][readOnly]:hover:active { display: block; font-size: smaller; color: var(--in-content-deemphasized-text); - margin-bottom: 5px; + margin-bottom: 8px; } :host([data-editing]) .detail-cell input:not([readOnly]):not([type="checkbox"]) { diff --git a/browser/components/aboutlogins/content/components/login-item.js b/browser/components/aboutlogins/content/components/login-item.js index 556dc2c37d372..95d87926a8c91 100644 --- a/browser/components/aboutlogins/content/components/login-item.js +++ b/browser/components/aboutlogins/content/components/login-item.js @@ -146,7 +146,8 @@ export default class LoginItem extends HTMLElement { this._title.textContent = this._login.title; this._originInput.defaultValue = this._login.origin || ""; this._usernameInput.defaultValue = this._login.username || ""; - this._passwordInput.defaultValue = this._login.password || ""; + // The password gets filled in _updatePasswordRevealState + if (this.dataset.editing) { this._usernameInput.removeAttribute("data-l10n-id"); this._usernameInput.placeholder = ""; @@ -246,7 +247,8 @@ export default class LoginItem extends HTMLElement { case "click": { let classList = event.currentTarget.classList; if (classList.contains("reveal-password-checkbox")) { - if (this._revealCheckbox.checked) { + // We prompt for the master password when entering edit mode already. + if (this._revealCheckbox.checked && !this.dataset.editing) { let masterPasswordAuth = await new Promise(resolve => { window.AboutLoginsUtils.promptForMasterPassword(resolve); }); @@ -344,6 +346,13 @@ export default class LoginItem extends HTMLElement { return; } if (classList.contains("edit-button")) { + let masterPasswordAuth = await new Promise(resolve => { + window.AboutLoginsUtils.promptForMasterPassword(resolve); + }); + if (!masterPasswordAuth) { + return; + } + this._toggleEditing(); this.render(); @@ -680,7 +689,15 @@ export default class LoginItem extends HTMLElement { let { checked } = this._revealCheckbox; let inputType = checked ? "text" : "password"; - this._passwordInput.setAttribute("type", inputType); + this._passwordInput.type = inputType; + // Don't include the password value in the attribute when it's supposed to be + // masked so that it's not trivial to bypass the Master Password prompt with + // the inspector in devtools. + let password = this._login.password || ""; + // We prompt for the master password before entering edit mode so we can use + // the password in the markup then. + this._passwordInput.defaultValue = + checked || this.dataset.editing ? password : " ".repeat(password.length); } } customElements.define("login-item", LoginItem); diff --git a/browser/components/aboutlogins/tests/browser/browser_aaa_eventTelemetry_run_first.js b/browser/components/aboutlogins/tests/browser/browser_aaa_eventTelemetry_run_first.js index ce4e72137cb9f..9c7e80ccfe16c 100644 --- a/browser/components/aboutlogins/tests/browser/browser_aaa_eventTelemetry_run_first.js +++ b/browser/components/aboutlogins/tests/browser/browser_aaa_eventTelemetry_run_first.js @@ -79,7 +79,7 @@ add_task(async function test_telemetry_events() { let promiseNewTab = BrowserTestUtils.waitForNewTab( gBrowser, - TEST_LOGIN2.origin + TEST_LOGIN2.origin + "/" ); await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() { let loginItem = content.document.querySelector("login-item"); diff --git a/browser/components/aboutlogins/tests/browser/browser_openSite.js b/browser/components/aboutlogins/tests/browser/browser_openSite.js index 8c8aa45378ed7..a747be387c05b 100644 --- a/browser/components/aboutlogins/tests/browser/browser_openSite.js +++ b/browser/components/aboutlogins/tests/browser/browser_openSite.js @@ -16,7 +16,7 @@ add_task(async function setup() { add_task(async function test_launch_login_item() { let promiseNewTab = BrowserTestUtils.waitForNewTab( gBrowser, - TEST_LOGIN1.origin + TEST_LOGIN1.origin + "/" ); let browser = gBrowser.selectedBrowser; diff --git a/browser/components/aboutlogins/tests/browser/browser_updateLogin.js b/browser/components/aboutlogins/tests/browser/browser_updateLogin.js index 8c002093d79f6..8298a8357d827 100644 --- a/browser/components/aboutlogins/tests/browser/browser_updateLogin.js +++ b/browser/components/aboutlogins/tests/browser/browser_updateLogin.js @@ -63,6 +63,10 @@ add_task(async function test_login_item() { async function test_discard_dialog(exitPoint) { editButton.click(); + await ContentTaskUtils.waitForCondition( + () => loginItem.dataset.editing, + "Entering edit mode" + ); await Promise.resolve(); usernameInput.value += "-undome"; @@ -102,7 +106,7 @@ add_task(async function test_login_item() { ); is( passwordInput.value, - login.password, + " ".repeat(login.password.length), "Password change should be reverted" ); is( @@ -118,6 +122,10 @@ add_task(async function test_login_item() { await test_discard_dialog(cancelButton); editButton.click(); + await ContentTaskUtils.waitForCondition( + () => loginItem.dataset.editing, + "Entering edit mode" + ); await Promise.resolve(); let revealCheckbox = loginItem.shadowRoot.querySelector( @@ -132,6 +140,8 @@ add_task(async function test_login_item() { usernameInput.value += "-saveme"; passwordInput.value += "-saveme"; + // Cache the value since it will change upon leaving edit mode. + let passwordInputValue = passwordInput.value; ok(loginItem.dataset.editing, "LoginItem should be in 'edit' mode"); let saveChangesButton = loginItem.shadowRoot.querySelector( @@ -145,7 +155,7 @@ add_task(async function test_login_item() { return ( updatedLogin && updatedLogin.username == usernameInput.value && - updatedLogin.password == passwordInput.value + updatedLogin.password == passwordInputValue ); }, "Waiting for corresponding login in login list to update"); @@ -164,6 +174,10 @@ add_task(async function test_login_item() { ); editButton.click(); + await ContentTaskUtils.waitForCondition( + () => loginItem.dataset.editing, + "Entering edit mode" + ); await Promise.resolve(); ok(loginItem.dataset.editing, "LoginItem should be in 'edit' mode"); diff --git a/browser/components/aboutlogins/tests/browser/head.js b/browser/components/aboutlogins/tests/browser/head.js index c1e5485298402..26d97d990ffb8 100644 --- a/browser/components/aboutlogins/tests/browser/head.js +++ b/browser/components/aboutlogins/tests/browser/head.js @@ -8,8 +8,8 @@ let nsLoginInfo = new Components.Constructor( ); let TEST_LOGIN1 = new nsLoginInfo( - "https://example.com/", - "https://example.com/", + "https://example.com", + "https://example.com", null, "user1", "pass1", @@ -17,8 +17,8 @@ let TEST_LOGIN1 = new nsLoginInfo( "password" ); let TEST_LOGIN2 = new nsLoginInfo( - "https://2.example.com/", - "https://2.example.com/", + "https://2.example.com", + "https://2.example.com", null, "user2", "pass2", @@ -27,8 +27,8 @@ let TEST_LOGIN2 = new nsLoginInfo( ); let TEST_LOGIN3 = new nsLoginInfo( - "https://breached.com/", - "https://breached.com/", + "https://breached.com", + "https://breached.com", null, "breachedLogin1", "pass3", diff --git a/browser/components/aboutlogins/tests/chrome/test_login_item.html b/browser/components/aboutlogins/tests/chrome/test_login_item.html index 10cdc42b1018b..131c543a382b8 100644 --- a/browser/components/aboutlogins/tests/chrome/test_login_item.html +++ b/browser/components/aboutlogins/tests/chrome/test_login_item.html @@ -89,7 +89,7 @@ let usernameInput = gLoginItem.shadowRoot.querySelector("input[name='username']"); is(usernameInput.value, TEST_LOGIN_1.username, "username should be populated"); is(document.l10n.getAttributes(usernameInput).id, "about-logins-login-item-username", "username field should have default placeholder when not editing"); - is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, TEST_LOGIN_1.password, "password should be populated"); + is(gLoginItem.shadowRoot.querySelector("input[name='password']").value.length, TEST_LOGIN_1.password.length, "password mask text should be populated"); is(document.l10n.getAttributes(gLoginItem.shadowRoot.querySelector(".time-created")).args.timeCreated, TEST_LOGIN_1.timeCreated, "time-created should be populated"); is(document.l10n.getAttributes(gLoginItem.shadowRoot.querySelector(".time-changed")).args.timeChanged, TEST_LOGIN_1.timePasswordChanged, "time-changed should be populated"); is(document.l10n.getAttributes(gLoginItem.shadowRoot.querySelector(".time-used")).args.timeUsed, TEST_LOGIN_1.timeLastUsed, "time-used should be populated"); @@ -126,6 +126,7 @@ usernameInput.placeholder = "dummy placeholder"; gLoginItem.shadowRoot.querySelector(".edit-button").click(); + await asyncElementRendered(); is( document.l10n.getAttributes(usernameInput).id, null, @@ -160,6 +161,7 @@ usernameInput.placeholder = "dummy placeholder"; gLoginItem.shadowRoot.querySelector(".edit-button").click(); await asyncElementRendered(); + await asyncElementRendered(); ok(gLoginItem.dataset.editing, "loginItem should be in 'edit' mode"); ok(isHidden(gLoginItem.shadowRoot.querySelector(".edit-button")), "edit button should be hidden in 'edit' mode"); @@ -199,6 +201,7 @@ add_task(async function test_edit_login_cancel() { gLoginItem.setLogin(TEST_LOGIN_1); gLoginItem.shadowRoot.querySelector(".edit-button").click(); + await asyncElementRendered(); ok(gLoginItem.dataset.editing, "loginItem should be in 'edit' mode"); is(!!gLoginItem.dataset.isNewLogin, false, @@ -231,6 +234,8 @@ let editButton = gLoginItem.shadowRoot.querySelector(".edit-button"); editButton.click(); + await asyncElementRendered(); + ok(revealCheckbox.checked, "reveal-checkbox should remain checked when entering 'edit' mode"); gLoginItem.shadowRoot.querySelector(".cancel-button").click(); ok(!revealCheckbox.checked, "reveal-checkbox should be unchecked after canceling 'edit' mode"); @@ -307,7 +312,7 @@ is(gLoginItem.shadowRoot.querySelector("input[name='origin']").value, TEST_LOGIN_1.origin, "origin should be unchanged"); is(gLoginItem.shadowRoot.querySelector("input[name='username']").value, TEST_LOGIN_1.username, "username should be unchanged"); - is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, TEST_LOGIN_1.password, "password should be unchanged"); + is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, " ".repeat(TEST_LOGIN_1.password.length), "password length should be unchanged"); is(document.l10n.getAttributes(gLoginItem.shadowRoot.querySelector(".time-created")).args.timeCreated, TEST_LOGIN_1.timeCreated, "time-created should be unchanged"); is(document.l10n.getAttributes(gLoginItem.shadowRoot.querySelector(".time-changed")).args.timeChanged, TEST_LOGIN_1.timePasswordChanged, "time-changed should be unchanged"); is(document.l10n.getAttributes(gLoginItem.shadowRoot.querySelector(".time-used")).args.timeUsed, TEST_LOGIN_1.timeLastUsed, "time-used should be unchanged"); @@ -321,7 +326,7 @@ is(gLoginItem.shadowRoot.querySelector("input[name='origin']").value, TEST_LOGIN_1.origin, "origin should be unchanged"); is(gLoginItem.shadowRoot.querySelector("input[name='username']").value, TEST_LOGIN_1.username, "username should be unchanged"); - is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, TEST_LOGIN_1.password, "password should be unchanged"); + is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, " ".repeat(TEST_LOGIN_1.password.length), "password length should be unchanged"); is(document.l10n.getAttributes(gLoginItem.shadowRoot.querySelector(".time-created")).args.timeCreated, TEST_LOGIN_1.timeCreated, "time-created should be unchanged"); is(document.l10n.getAttributes(gLoginItem.shadowRoot.querySelector(".time-changed")).args.timeChanged, TEST_LOGIN_1.timePasswordChanged, "time-changed should be unchanged"); is(document.l10n.getAttributes(gLoginItem.shadowRoot.querySelector(".time-used")).args.timeUsed, TEST_LOGIN_1.timeLastUsed, "time-used should be unchanged"); @@ -335,7 +340,7 @@ is(gLoginItem.shadowRoot.querySelector("input[name='origin']").value, modifiedLogin.origin, "origin should be updated"); is(gLoginItem.shadowRoot.querySelector("input[name='username']").value, modifiedLogin.username, "username should be updated"); - is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, modifiedLogin.password, "password should be updated"); + is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, " ".repeat(modifiedLogin.password.length), "password length should be updated"); is(document.l10n.getAttributes(gLoginItem.shadowRoot.querySelector(".time-created")).args.timeCreated, modifiedLogin.timeCreated, "time-created should be updated"); is(document.l10n.getAttributes(gLoginItem.shadowRoot.querySelector(".time-changed")).args.timeChanged, modifiedLogin.timePasswordChanged, "time-changed should be updated"); is(document.l10n.getAttributes(gLoginItem.shadowRoot.querySelector(".time-used")).args.timeUsed, modifiedLogin.timeLastUsed, "time-used should be updated"); diff --git a/build/unix/elfhack/elfhack.cpp b/build/unix/elfhack/elfhack.cpp index 2c24cbac4b577..ec01e54674b28 100644 --- a/build/unix/elfhack/elfhack.cpp +++ b/build/unix/elfhack/elfhack.cpp @@ -194,7 +194,7 @@ class ElfRelHackCode_Section : public ElfSection { ~ElfRelHackCode_Section() { delete elf; } - void serialize(std::ofstream& file, char ei_class, char ei_data) { + void serialize(std::ofstream& file, char ei_class, char ei_data) override { // Readjust code offsets for (std::vector::iterator c = code.begin(); c != code.end(); ++c) @@ -217,7 +217,7 @@ class ElfRelHackCode_Section : public ElfSection { ElfSection::serialize(file, ei_class, ei_data); } - bool isRelocatable() { return false; } + bool isRelocatable() override { return false; } unsigned int getEntryPoint() { return entry_point; } diff --git a/config/recurse.mk b/config/recurse.mk index 91cbc2a1d68c9..7e979e47bf59f 100644 --- a/config/recurse.mk +++ b/config/recurse.mk @@ -203,7 +203,9 @@ $(addprefix build/unix/stdc++compat/,target host) build/clang-plugin/host: confi # export, which ensures it exists before recursing the rust targets, tricking # Make into keeping them early. $(rust_targets): $(DEPTH)/.cargo/config +ifndef TEST_MOZBUILD export:: $(DEPTH)/.cargo/config +endif # When building gtest as part of the build (LINK_GTEST_DURING_COMPILE), # force the build system to get to it first, so that it can be linked diff --git a/devtools/client/debugger/src/utils/utils.js b/devtools/client/debugger/src/utils/utils.js index b188c8a67b451..c4a9a023cbf06 100644 --- a/devtools/client/debugger/src/utils/utils.js +++ b/devtools/client/debugger/src/utils/utils.js @@ -5,7 +5,7 @@ // @flow import type { SourceContent } from "../types"; -import { saveAs } from "devtools-modules"; +import { DevToolsUtils } from "devtools-modules"; /** * Utils for utils, by utils @@ -62,5 +62,5 @@ export function downloadFile(content: SourceContent, fileName: string) { } const data = new TextEncoder().encode(content.value); - saveAs(window, data, fileName); + DevToolsUtils.saveAs(window, data, fileName); } diff --git a/devtools/client/shared/build/build-debugger.js b/devtools/client/shared/build/build-debugger.js index 78af39fd7e24a..a96dbb0e8ae34 100644 --- a/devtools/client/shared/build/build-debugger.js +++ b/devtools/client/shared/build/build-debugger.js @@ -72,6 +72,7 @@ const moduleMapping = { asyncStoreHelper: "devtools/client/shared/async-store-helper", asyncStorage: "devtools/shared/async-storage", PluralForm: "devtools/shared/plural-form", + DevToolsUtils: "devtools/shared/DevToolsUtils", }; /* diff --git a/editor/libeditor/HTMLEditRules.cpp b/editor/libeditor/HTMLEditRules.cpp index f359e340a854e..676fe56600d95 100644 --- a/editor/libeditor/HTMLEditRules.cpp +++ b/editor/libeditor/HTMLEditRules.cpp @@ -223,6 +223,10 @@ template Element* HTMLEditor::GetInvisibleBRElementAt( const EditorDOMPoint& aPoint); template Element* HTMLEditor::GetInvisibleBRElementAt( const EditorRawDOMPoint& aPoint); +template nsIContent* HTMLEditor::FindNearEditableContent( + const EditorDOMPoint& aPoint, nsIEditor::EDirection aDirection); +template nsIContent* HTMLEditor::FindNearEditableContent( + const EditorRawDOMPoint& aPoint, nsIEditor::EDirection aDirection); HTMLEditRules::HTMLEditRules() : mHTMLEditor(nullptr), mInitialized(false) { mIsHTMLEditRules = true; @@ -361,10 +365,14 @@ nsresult HTMLEditRules::BeforeEdit() { } // Check that selection is in subtree defined by body node - nsresult rv = ConfirmSelectionInBody(); + nsresult rv = + MOZ_KnownLive(HTMLEditorRef()).EnsureSelectionInBodyOrDocumentElement(); if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) { return NS_ERROR_EDITOR_DESTROYED; } + NS_WARNING_ASSERTION( + NS_SUCCEEDED(rv), + "EnsureSelectionInBodyOrDocumentElement() failed, but ignored"); return NS_OK; } @@ -415,11 +423,14 @@ nsresult HTMLEditRules::AfterEdit() { nsresult HTMLEditRules::AfterEditInner() { MOZ_ASSERT(IsEditorDataAvailable()); - nsresult rv = ConfirmSelectionInBody(); + nsresult rv = + MOZ_KnownLive(HTMLEditorRef()).EnsureSelectionInBodyOrDocumentElement(); if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) { return NS_ERROR_EDITOR_DESTROYED; } - NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to normalize Selection"); + NS_WARNING_ASSERTION( + NS_SUCCEEDED(rv), + "EnsureSelectionInBodyOrDocumentElement() failed, but ignored"); switch (HTMLEditorRef().GetTopLevelEditSubAction()) { case EditSubAction::eReplaceHeadWithHTMLSource: case EditSubAction::eCreatePaddingBRElementForEmptyEditor: @@ -614,7 +625,8 @@ nsresult HTMLEditRules::AfterEditInner() { // did it. if (!HTMLEditorRef() .TopLevelEditSubActionDataRef() - .mDidDeleteEmptyParentBlocks) { + .mDidDeleteEmptyParentBlocks && + SelectionRefPtr()->IsCollapsed()) { switch (HTMLEditorRef().GetTopLevelEditSubAction()) { case EditSubAction::eInsertText: case EditSubAction::eInsertTextComingFromIME: @@ -623,8 +635,13 @@ nsresult HTMLEditRules::AfterEditInner() { case EditSubAction::eInsertParagraphSeparator: case EditSubAction::ePasteHTMLContent: case EditSubAction::eInsertHTMLSource: - rv = AdjustSelection( - HTMLEditorRef().GetDirectionOfTopLevelEditSubAction()); + // XXX AdjustCaretPositionAndEnsurePaddingBRElement() intentionally + // does not create padding `
` element for empty editor. + // Investigate which is better that whether this should does it + // or wait MaybeCreatePaddingBRElementForEmptyEditor(). + rv = MOZ_KnownLive(HTMLEditorRef()) + .AdjustCaretPositionAndEnsurePaddingBRElement( + HTMLEditorRef().GetDirectionOfTopLevelEditSubAction()); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -788,8 +805,6 @@ nsresult HTMLEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel, return WillAbsolutePosition(aCancel, aHandled); case EditSubAction::eSetPositionToStatic: return WillRemoveAbsolutePosition(aCancel, aHandled); - case EditSubAction::eSetOrClearAlignment: - return WillAlign(*aInfo.alignType, aCancel, aHandled); case EditSubAction::eInsertElement: case EditSubAction::eInsertQuotedText: { nsresult rv = MOZ_KnownLive(HTMLEditorRef()).WillInsert(aCancel); @@ -813,6 +828,7 @@ nsresult HTMLEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel, case EditSubAction::eUndo: case EditSubAction::eRedo: case EditSubAction::eRemoveList: + case EditSubAction::eSetOrClearAlignment: MOZ_ASSERT_UNREACHABLE("This path should've been dead code"); return NS_ERROR_UNEXPECTED; default: @@ -835,9 +851,6 @@ nsresult HTMLEditRules::DidDoAction(EditSubActionInfo& aInfo, return NS_OK; case EditSubAction::eDeleteSelectedContent: return DidDeleteSelection(); - case EditSubAction::eSetOrClearAlignment: - return MOZ_KnownLive(HTMLEditorRef()) - .MaybeInsertPaddingBRElementForEmptyLastLineAtSelection(); case EditSubAction::eSetPositionToAbsolute: { nsresult rv = MOZ_KnownLive(HTMLEditorRef()) @@ -860,6 +873,7 @@ nsresult HTMLEditRules::DidDoAction(EditSubActionInfo& aInfo, case EditSubAction::eUndo: case EditSubAction::eRedo: case EditSubAction::eRemoveList: + case EditSubAction::eSetOrClearAlignment: MOZ_ASSERT_UNREACHABLE("This path should've been dead code"); return NS_ERROR_UNEXPECTED; default: @@ -6273,54 +6287,61 @@ bool HTMLEditor::IsEmptyBlockElement(Element& aElement, return NS_SUCCEEDED(rv) && isEmpty; } -nsresult HTMLEditRules::WillAlign(const nsAString& aAlignType, bool* aCancel, - bool* aHandled) { - MOZ_ASSERT(IsEditorDataAvailable()); - MOZ_ASSERT(aCancel && aHandled); +EditActionResult HTMLEditor::AlignAsSubAction(const nsAString& aAlignType) { + MOZ_ASSERT(IsEditActionDataAvailable()); - *aCancel = false; - *aHandled = false; + AutoPlaceholderBatch treatAsOneTransaction(*this); + AutoEditSubActionNotifier startToHandleEditSubAction( + *this, EditSubAction::eSetOrClearAlignment, nsIEditor::eNext); + + EditActionResult result = CanHandleHTMLEditSubAction(); + if (NS_WARN_IF(result.Failed()) || result.Canceled()) { + return result; + } // FYI: Ignore cancel result of WillInsert(). - nsresult rv = MOZ_KnownLive(HTMLEditorRef()).WillInsert(); + nsresult rv = WillInsert(); if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) { - return NS_ERROR_EDITOR_DESTROYED; + return EditActionResult(NS_ERROR_EDITOR_DESTROYED); } - NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed"); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed, but ignored"); if (!SelectionRefPtr()->IsCollapsed()) { - nsresult rv = MOZ_KnownLive(HTMLEditorRef()) - .MaybeExtendSelectionToHardLineEdgesForBlockEditAction(); + nsresult rv = MaybeExtendSelectionToHardLineEdgesForBlockEditAction(); if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; + return EditActionResult(rv); } } - *aHandled = true; + // AlignContentsAtSelection() creates AutoSelectionRestorer. Therefore, + // we need to check whether we've been destroyed or not even if it returns + // NS_OK. rv = AlignContentsAtSelection(aAlignType); - if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED) || - NS_WARN_IF(!CanHandleEditAction())) { - return NS_ERROR_EDITOR_DESTROYED; + if (NS_WARN_IF(Destroyed())) { + return EditActionHandled(NS_ERROR_EDITOR_DESTROYED); } if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; + return EditActionHandled(rv); } - return NS_OK; + + rv = MaybeInsertPaddingBRElementForEmptyLastLineAtSelection(); + NS_WARNING_ASSERTION( + NS_SUCCEEDED(rv), + "MaybeInsertPaddingBRElementForEmptyLastLineAtSelection() failed"); + return EditActionHandled(rv); } -nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) { - AutoSelectionRestorer restoreSelectionLater(HTMLEditorRef()); +nsresult HTMLEditor::AlignContentsAtSelection(const nsAString& aAlignType) { + AutoSelectionRestorer restoreSelectionLater(*this); // Convert the selection ranges into "promoted" selection ranges: This // basically just expands the range to include the immediate block parent, // and then further expands to include any ancestors whose children are all // in the range AutoTArray, 64> nodeArray; - nsresult rv = - MOZ_KnownLive(HTMLEditorRef()) - .SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges( - nodeArray, EditSubAction::eSetOrClearAlignment, - HTMLEditor::CollectNonEditableNodes::Yes); + nsresult rv = SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges( + nodeArray, EditSubAction::eSetOrClearAlignment, + CollectNonEditableNodes::Yes); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -6328,7 +6349,7 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) { // If we don't have any nodes, or we have only a single br, then we are // creating an empty alignment div. We have to do some different things for // these. - bool emptyDiv = nodeArray.IsEmpty(); + bool createEmptyDivElement = nodeArray.IsEmpty(); if (nodeArray.Length() == 1) { OwningNonNull node = nodeArray[0]; @@ -6336,27 +6357,28 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) { // The node is a table element, an hr, a paragraph, a div or a section // header; in HTML 4, it can directly carry the ALIGN attribute and we // don't need to make a div! If we are in CSS mode, all the work is done - // in AlignBlock - rv = AlignBlock(MOZ_KnownLive(*node->AsElement()), aAlignType, - ResetAlignOf::OnlyDescendants); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - return NS_OK; + // in SetBlockElementAlign(). + nsresult rv = + SetBlockElementAlign(MOZ_KnownLive(*node->AsElement()), aAlignType, + EditTarget::OnlyDescendantsExceptTable); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetBlockElementAlign() failed"); + return rv; } if (TextEditUtils::IsBreak(node)) { - // The special case emptyDiv code (below) that consumes BRs can cause - // tables to split if the start node of the selection is not in a table - // cell or caption, for example parent is a . Avoid this unnecessary - // splitting if possible by leaving emptyDiv FALSE so that we fall - // through to the normal case alignment code. + // The special case createEmptyDivElement code (below) that consumes + // `
` elements can cause tables to split if the start node of the + // selection is not in a table cell or caption, for example parent is a + // ``. Avoid this unnecessary splitting if possible by leaving + // createEmptyDivElement false so that we fall through to the normal case + // alignment code. // - // XXX: It seems a little error prone for the emptyDiv special case code - // to assume that the start node of the selection is the parent of the - // single node in the nodeArray, as the paragraph above points out. Do we - // rely on the selection start node because of the fact that nodeArray - // can be empty? We should probably revisit this issue. - kin + // XXX: It seems a little error prone for the createEmptyDivElement + // special case code to assume that the start node of the selection + // is the parent of the single node in the nodeArray, as the + // paragraph above points out. Do we rely on the selection start + // node because of the fact that nodeArray can be empty? We should + // probably revisit this issue. - kin nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0); if (NS_WARN_IF(!firstRange)) { @@ -6367,128 +6389,145 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) { return NS_ERROR_FAILURE; } nsINode* parent = atStartOfSelection.Container(); - emptyDiv = !HTMLEditUtils::IsTableElement(parent) || - HTMLEditUtils::IsTableCellOrCaption(*parent); + createEmptyDivElement = !HTMLEditUtils::IsTableElement(parent) || + HTMLEditUtils::IsTableCellOrCaption(*parent); } } - if (emptyDiv) { - nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0); - if (NS_WARN_IF(!firstRange)) { - return NS_ERROR_FAILURE; - } - EditorDOMPoint atStartOfSelection(firstRange->StartRef()); - if (NS_WARN_IF(!atStartOfSelection.IsSet())) { - return NS_ERROR_FAILURE; + if (createEmptyDivElement) { + EditActionResult result = + AlignContentsAtSelectionWithEmptyDivElement(aAlignType); + NS_WARNING_ASSERTION( + result.Succeeded(), + "AlignContentsAtSelectionWithEmptyDivElement() failed"); + if (result.Handled()) { + restoreSelectionLater.Abort(); } + return rv; + } - SplitNodeResult splitNodeResult = - MOZ_KnownLive(HTMLEditorRef()) - .MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div, - atStartOfSelection); - if (NS_WARN_IF(splitNodeResult.Failed())) { - return splitNodeResult.Rv(); - } + rv = AlignNodesAndDescendants(nodeArray, aAlignType); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AlignNodesAndDescendants() failed"); + return rv; +} + +EditActionResult HTMLEditor::AlignContentsAtSelectionWithEmptyDivElement( + const nsAString& aAlignType) { + MOZ_ASSERT(IsTopLevelEditSubActionDataAvailable()); + + nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0); + if (NS_WARN_IF(!firstRange)) { + return EditActionResult(NS_ERROR_FAILURE); + } + + EditorDOMPoint atStartOfSelection(firstRange->StartRef()); + if (NS_WARN_IF(!atStartOfSelection.IsSet())) { + return EditActionResult(NS_ERROR_FAILURE); + } + + SplitNodeResult splitNodeResult = MaybeSplitAncestorsForInsertWithTransaction( + *nsGkAtoms::div, atStartOfSelection); + if (NS_WARN_IF(splitNodeResult.Failed())) { + return EditActionResult(splitNodeResult.Rv()); + } + + EditorDOMPoint pointToInsertDiv(splitNodeResult.SplitPoint()); - // Consume a trailing br, if any. This is to keep an alignment from - // creating extra lines, if possible. - nsCOMPtr brContent = - HTMLEditorRef().GetNextEditableHTMLNodeInBlock( - splitNodeResult.SplitPoint()); - EditorDOMPoint pointToInsertDiv(splitNodeResult.SplitPoint()); - if (brContent && TextEditUtils::IsBreak(brContent)) { + // Consume a trailing br, if any. This is to keep an alignment from + // creating extra lines, if possible. + if (nsCOMPtr maybeBRContent = + GetNextEditableHTMLNodeInBlock(splitNodeResult.SplitPoint())) { + if (TextEditUtils::IsBreak(maybeBRContent) && pointToInsertDiv.GetChild()) { // Making use of html structure... if next node after where we are // putting our div is not a block, then the br we found is in same block // we are, so it's safe to consume it. - nsCOMPtr sibling; - if (pointToInsertDiv.GetChild()) { - sibling = - HTMLEditorRef().GetNextHTMLSibling(pointToInsertDiv.GetChild()); - } - if (sibling && !HTMLEditor::NodeIsBlockStatic(*sibling)) { - AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertDiv); - rv = MOZ_KnownLive(HTMLEditorRef()) - .DeleteNodeWithTransaction(*brContent); - if (NS_WARN_IF(!CanHandleEditAction())) { - return NS_ERROR_EDITOR_DESTROYED; - } - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; + if (nsIContent* nextEditableSibling = + GetNextHTMLSibling(pointToInsertDiv.GetChild())) { + if (!HTMLEditor::NodeIsBlockStatic(*nextEditableSibling)) { + AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertDiv); + nsresult rv = DeleteNodeWithTransaction(*maybeBRContent); + if (NS_WARN_IF(Destroyed())) { + return EditActionResult(NS_ERROR_EDITOR_DESTROYED); + } + if (NS_WARN_IF(NS_FAILED(rv))) { + return EditActionResult(rv); + } } } } - RefPtr div = - MOZ_KnownLive(HTMLEditorRef()) - .CreateNodeWithTransaction(*nsGkAtoms::div, pointToInsertDiv); - if (NS_WARN_IF(!CanHandleEditAction())) { - return NS_ERROR_EDITOR_DESTROYED; - } - if (NS_WARN_IF(!div)) { - return NS_ERROR_FAILURE; - } - // Remember our new block for postprocessing - HTMLEditorRef().TopLevelEditSubActionDataRef().mNewBlockElement = div; - // Set up the alignment on the div, using HTML or CSS - rv = AlignBlock(*div, aAlignType, ResetAlignOf::OnlyDescendants); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - // Put in a padding
element for empty last line so that it won't get - // deleted. - CreateElementResult createPaddingBRResult = - MOZ_KnownLive(HTMLEditorRef()) - .InsertPaddingBRElementForEmptyLastLineWithTransaction( - EditorDOMPoint(div, 0)); - if (NS_WARN_IF(createPaddingBRResult.Failed())) { - return createPaddingBRResult.Rv(); - } - EditorRawDOMPoint atStartOfDiv(div, 0); - // Don't restore the selection - restoreSelectionLater.Abort(); - ErrorResult error; - SelectionRefPtr()->Collapse(atStartOfDiv, error); - if (NS_WARN_IF(!CanHandleEditAction())) { - error.SuppressException(); - return NS_ERROR_EDITOR_DESTROYED; - } - if (NS_WARN_IF(error.Failed())) { - return error.StealNSResult(); - } - return NS_OK; } - // Next we detect all the transitions in the array, where a transition - // means that adjacent nodes in the array don't have the same parent. + RefPtr divElement = + CreateNodeWithTransaction(*nsGkAtoms::div, pointToInsertDiv); + if (NS_WARN_IF(Destroyed())) { + return EditActionResult(NS_ERROR_EDITOR_DESTROYED); + } + if (NS_WARN_IF(!divElement)) { + return EditActionResult(NS_ERROR_FAILURE); + } + // Remember our new block for postprocessing + TopLevelEditSubActionDataRef().mNewBlockElement = divElement; + // Set up the alignment on the div, using HTML or CSS + nsresult rv = SetBlockElementAlign(*divElement, aAlignType, + EditTarget::OnlyDescendantsExceptTable); + if (NS_WARN_IF(NS_FAILED(rv))) { + return EditActionResult(rv); + } + // Put in a padding
element for empty last line so that it won't get + // deleted. + CreateElementResult createPaddingBRResult = + InsertPaddingBRElementForEmptyLastLineWithTransaction( + EditorDOMPoint(divElement, 0)); + if (NS_WARN_IF(createPaddingBRResult.Failed())) { + return EditActionResult(createPaddingBRResult.Rv()); + } + EditorRawDOMPoint atStartOfDiv(divElement, 0); + ErrorResult error; + SelectionRefPtr()->Collapse(atStartOfDiv, error); + if (NS_WARN_IF(Destroyed())) { + error.SuppressException(); + return EditActionHandled(NS_ERROR_EDITOR_DESTROYED); + } + NS_WARNING_ASSERTION(!error.Failed(), "Selection::Collapse() failed"); + return EditActionHandled(error.StealNSResult()); +} +nsresult HTMLEditor::AlignNodesAndDescendants( + nsTArray>& aArrayOfNodes, + const nsAString& aAlignType) { + // Detect all the transitions in the array, where a transition means that + // adjacent nodes in the array don't have the same parent. AutoTArray transitionList; - HTMLEditor::MakeTransitionList(nodeArray, transitionList); + HTMLEditor::MakeTransitionList(aArrayOfNodes, transitionList); // Okay, now go through all the nodes and give them an align attrib or put // them in a div, or whatever is appropriate. Woohoo! - nsCOMPtr curDiv; - bool useCSS = HTMLEditorRef().IsCSSEnabled(); + RefPtr createdDivElement; + bool useCSS = IsCSSEnabled(); int32_t indexOfTransitionList = -1; - for (OwningNonNull& curNode : nodeArray) { + for (OwningNonNull& curNode : aArrayOfNodes) { ++indexOfTransitionList; // Ignore all non-editable nodes. Leave them be. - if (!HTMLEditorRef().IsEditable(curNode)) { + if (!IsEditable(curNode)) { continue; } // The node is a table element, an hr, a paragraph, a div or a section // header; in HTML 4, it can directly carry the ALIGN attribute and we // don't need to nest it, just set the alignment. In CSS, assign the - // corresponding CSS styles in AlignBlock + // corresponding CSS styles in SetBlockElementAlign(). if (HTMLEditUtils::SupportsAlignAttr(*curNode)) { - rv = AlignBlock(MOZ_KnownLive(*curNode->AsElement()), aAlignType, - ResetAlignOf::ElementAndDescendants); + nsresult rv = + SetBlockElementAlign(MOZ_KnownLive(*curNode->AsElement()), aAlignType, + EditTarget::NodeAndDescendantsExceptTable); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - // Clear out curDiv so that we don't put nodes after this one into it - curDiv = nullptr; + // Clear out createdDivElement so that we don't put nodes after this one + // into it + createdDivElement = nullptr; continue; } @@ -6500,12 +6539,11 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) { // Skip insignificant formatting text nodes to prevent unnecessary // structure splitting! bool isEmptyTextNode = false; - if (curNode->GetAsText() && + if (curNode->IsText() && ((HTMLEditUtils::IsTableElement(atCurNode.GetContainer()) && !HTMLEditUtils::IsTableCellOrCaption(*atCurNode.GetContainer())) || HTMLEditUtils::IsList(atCurNode.GetContainer()) || - (NS_SUCCEEDED( - HTMLEditorRef().IsEmptyNode(curNode, &isEmptyTextNode)) && + (NS_SUCCEEDED(IsEmptyNode(curNode, &isEmptyTextNode)) && isEmptyTextNode))) { continue; } @@ -6515,82 +6553,84 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) { if (HTMLEditUtils::IsListItem(curNode) || HTMLEditUtils::IsList(curNode)) { Element* listOrListItemElement = curNode->AsElement(); AutoEditorDOMPointOffsetInvalidator lockChild(atCurNode); - rv = MOZ_KnownLive(HTMLEditorRef()) - .RemoveAlignFromDescendants( - MOZ_KnownLive(*listOrListItemElement), aAlignType, - HTMLEditor::EditTarget::OnlyDescendantsExceptTable); + nsresult rv = RemoveAlignFromDescendants( + MOZ_KnownLive(*listOrListItemElement), aAlignType, + EditTarget::OnlyDescendantsExceptTable); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + if (useCSS) { - HTMLEditorRef().mCSSEditUtils->SetCSSEquivalentToHTMLStyle( + mCSSEditUtils->SetCSSEquivalentToHTMLStyle( MOZ_KnownLive(listOrListItemElement), nullptr, nsGkAtoms::align, &aAlignType, false); - if (NS_WARN_IF(!CanHandleEditAction())) { + if (NS_WARN_IF(Destroyed())) { return NS_ERROR_EDITOR_DESTROYED; } - curDiv = nullptr; + createdDivElement = nullptr; continue; } + if (HTMLEditUtils::IsList(atCurNode.GetContainer())) { // If we don't use CSS, add a content to list element: they have to // be inside another list, i.e., >= second level of nesting. // XXX AlignContentsInAllTableCellsAndListItems() handles only list // item elements and table cells. Is it intentional? Why don't // we need to align contents in other type blocks? - rv = MOZ_KnownLive(HTMLEditorRef()) - .AlignContentsInAllTableCellsAndListItems( - MOZ_KnownLive(*listOrListItemElement), aAlignType); + nsresult rv = AlignContentsInAllTableCellsAndListItems( + MOZ_KnownLive(*listOrListItemElement), aAlignType); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - curDiv = nullptr; + createdDivElement = nullptr; continue; } - // Clear out curDiv so that we don't put nodes after this one into it + + // Clear out createdDivElement so that we don't put nodes after this one + // into it } // Need to make a div to put things in if we haven't already, or if this // node doesn't go in div we used earlier. - if (!curDiv || transitionList[indexOfTransitionList]) { + if (!createdDivElement || transitionList[indexOfTransitionList]) { // First, check that our element can contain a div. - if (!HTMLEditorRef().CanContainTag(*atCurNode.GetContainer(), - *nsGkAtoms::div)) { - // Cancelled + if (!CanContainTag(*atCurNode.GetContainer(), *nsGkAtoms::div)) { + // XXX Why do we return NS_OK here rather than returning error or + // doing continue? return NS_OK; } SplitNodeResult splitNodeResult = - MOZ_KnownLive(HTMLEditorRef()) - .MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div, - atCurNode); + MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div, + atCurNode); if (NS_WARN_IF(splitNodeResult.Failed())) { return splitNodeResult.Rv(); } - curDiv = MOZ_KnownLive(HTMLEditorRef()) - .CreateNodeWithTransaction(*nsGkAtoms::div, - splitNodeResult.SplitPoint()); - if (NS_WARN_IF(!CanHandleEditAction())) { + createdDivElement = CreateNodeWithTransaction( + *nsGkAtoms::div, splitNodeResult.SplitPoint()); + if (NS_WARN_IF(Destroyed())) { return NS_ERROR_EDITOR_DESTROYED; } - if (NS_WARN_IF(!curDiv)) { + if (NS_WARN_IF(!createdDivElement)) { return NS_ERROR_FAILURE; } // Remember our new block for postprocessing - HTMLEditorRef().TopLevelEditSubActionDataRef().mNewBlockElement = curDiv; + TopLevelEditSubActionDataRef().mNewBlockElement = createdDivElement; // Set up the alignment on the div - rv = AlignBlock(*curDiv, aAlignType, ResetAlignOf::OnlyDescendants); + nsresult rv = + SetBlockElementAlign(*createdDivElement, aAlignType, + EditTarget::OnlyDescendantsExceptTable); if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) { return NS_ERROR_EDITOR_DESTROYED; } - NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to align the
"); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), + "SetBlockElementAlign() failed, but ignored"); } // Tuck the node into the end of the active div - rv = MOZ_KnownLive(HTMLEditorRef()) - .MoveNodeToEndWithTransaction(MOZ_KnownLive(*curNode->AsContent()), - *curDiv); - if (NS_WARN_IF(!CanHandleEditAction())) { + nsresult rv = MoveNodeToEndWithTransaction( + MOZ_KnownLive(*curNode->AsContent()), *createdDivElement); + if (NS_WARN_IF(Destroyed())) { return NS_ERROR_EDITOR_DESTROYED; } if (NS_WARN_IF(NS_FAILED(rv))) { @@ -9681,70 +9721,62 @@ void HTMLEditRules::CheckInterlinePosition() { } } -nsresult HTMLEditRules::AdjustSelection(nsIEditor::EDirection aAction) { - MOZ_ASSERT(IsEditorDataAvailable()); - - // if the selection isn't collapsed, do nothing. - // moose: one thing to do instead is check for the case of - // only a single break selected, and collapse it. Good thing? Beats me. - if (!SelectionRefPtr()->IsCollapsed()) { - return NS_OK; - } +nsresult HTMLEditor::AdjustCaretPositionAndEnsurePaddingBRElement( + nsIEditor::EDirection aDirectionAndAmount) { + MOZ_ASSERT(IsEditActionDataAvailable()); + MOZ_ASSERT(SelectionRefPtr()->IsCollapsed()); - // get the (collapsed) selection location EditorDOMPoint point(EditorBase::GetStartPoint(*SelectionRefPtr())); if (NS_WARN_IF(!point.IsSet())) { return NS_ERROR_FAILURE; } - // are we in an editable node? - while (!HTMLEditorRef().IsEditable(point.GetContainer())) { - // scan up the tree until we find an editable place to be + // If selection start is not editable, climb up the tree until editable one. + while (!IsEditable(point.GetContainer())) { point.Set(point.GetContainer()); if (NS_WARN_IF(!point.IsSet())) { return NS_ERROR_FAILURE; } } - // make sure we aren't in an empty block - user will see no cursor. If this - // is happening, put a
in the block if allowed. - RefPtr theblock = HTMLEditorRef().GetBlock(*point.GetContainer()); - - if (theblock && HTMLEditorRef().IsEditable(theblock)) { - bool isEmptyNode; - nsresult rv = - HTMLEditorRef().IsEmptyNode(theblock, &isEmptyNode, false, false); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - // check if br can go into the destination node - if (isEmptyNode && - HTMLEditorRef().CanContainTag(*point.GetContainer(), *nsGkAtoms::br)) { - Element* rootElement = HTMLEditorRef().GetRoot(); - if (NS_WARN_IF(!rootElement)) { - return NS_ERROR_FAILURE; + // If caret is in empty block element, we need to insert a `
` element + // because the block should have one-line height. + if (RefPtr blockElement = GetBlock(*point.GetContainer())) { + if (IsEditable(blockElement)) { + bool isEmptyNode; + nsresult rv = IsEmptyNode(blockElement, &isEmptyNode, false, false); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } - if (point.GetContainer() == rootElement) { - // Our root node is completely empty. Don't add a
here. - // AfterEditInner() will add one for us when it calls - // TextEditor::MaybeCreatePaddingBRElementForEmptyEditor()! + if (isEmptyNode && CanContainTag(*point.GetContainer(), *nsGkAtoms::br)) { + Element* bodyOrDocumentElement = GetRoot(); + if (NS_WARN_IF(!bodyOrDocumentElement)) { + return NS_ERROR_FAILURE; + } + if (point.GetContainer() == bodyOrDocumentElement) { + // Our root node is completely empty. Don't add a
here. + // AfterEditInner() will add one for us when it calls + // TextEditor::MaybeCreatePaddingBRElementForEmptyEditor(). + // XXX This kind of dependency between methods makes us spaghetti. + // Let's handle it here later. + // XXX This looks odd check. If active editing host is not a + // ``, what are we doing? + return NS_OK; + } + CreateElementResult createPaddingBRResult = + InsertPaddingBRElementForEmptyLastLineWithTransaction(point); + if (NS_WARN_IF(createPaddingBRResult.Failed())) { + return createPaddingBRResult.Rv(); + } return NS_OK; } - - // we know we can skip the rest of this routine given the cirumstance - CreateElementResult createPaddingBRResult = - MOZ_KnownLive(HTMLEditorRef()) - .InsertPaddingBRElementForEmptyLastLineWithTransaction(point); - if (NS_WARN_IF(createPaddingBRResult.Failed())) { - return createPaddingBRResult.Rv(); - } - return NS_OK; } } - // are we in a text node? + // XXX Perhaps, we should do something if we're in a data node but not + // a text node. if (point.IsInTextNode()) { - return NS_OK; // we LIKE it when we are in a text node. that RULZ + return NS_OK; } // Do we need to insert a padding
element for empty last line? We do @@ -9753,118 +9785,125 @@ nsresult HTMLEditRules::AdjustSelection(nsIEditor::EDirection aAction) { // 2) prior node is a br AND // 3) that br is not visible - nsCOMPtr nearNode = - HTMLEditorRef().GetPreviousEditableHTMLNode(point); - if (nearNode) { - // is nearNode also a descendant of same block? - RefPtr block = HTMLEditorRef().GetBlock(*point.GetContainer()); - RefPtr nearBlock = HTMLEditorRef().GetBlockNodeParent(nearNode); - if (block && block == nearBlock) { - if (nearNode && TextEditUtils::IsBreak(nearNode)) { - if (!HTMLEditorRef().IsVisibleBRElement(nearNode)) { - // need to insert special moz BR. Why? Because if we don't - // the user will see no new line for the break. Also, things - // like table cells won't grow in height. - CreateElementResult createPaddingBRResult = - MOZ_KnownLive(HTMLEditorRef()) - .InsertPaddingBRElementForEmptyLastLineWithTransaction(point); - if (NS_WARN_IF(createPaddingBRResult.Failed())) { - return createPaddingBRResult.Rv(); - } - point.Set(createPaddingBRResult.GetNewNode()); - // Selection stays *before* padding
element for empty last - // line, sticking to it. - ErrorResult error; - SelectionRefPtr()->SetInterlinePosition(true, error); - if (NS_WARN_IF(!CanHandleEditAction())) { - error.SuppressException(); - return NS_ERROR_EDITOR_DESTROYED; - } - NS_WARNING_ASSERTION(!error.Failed(), + if (nsCOMPtr previousEditableContent = + GetPreviousEditableHTMLNode(point)) { + RefPtr blockElementAtCaret = GetBlock(*point.GetContainer()); + RefPtr blockElementParentAtPreviousEditableContent = + GetBlockNodeParent(previousEditableContent); + // If previous editable content of caret is in same block and a `
` + // element, we need to adjust interline position. + if (blockElementAtCaret && + blockElementAtCaret == blockElementParentAtPreviousEditableContent && + previousEditableContent && + TextEditUtils::IsBreak(previousEditableContent)) { + // If it's an invisible `
` element, we need to insert a padding + // `
` element for making empty line have one-line height. + if (!IsVisibleBRElement(previousEditableContent)) { + CreateElementResult createPaddingBRResult = + InsertPaddingBRElementForEmptyLastLineWithTransaction(point); + if (NS_WARN_IF(createPaddingBRResult.Failed())) { + return createPaddingBRResult.Rv(); + } + point.Set(createPaddingBRResult.GetNewNode()); + // Selection stays *before* padding `
` element for empty last + // line, sticking to it. + IgnoredErrorResult ignoredError; + SelectionRefPtr()->SetInterlinePosition(true, ignoredError); + if (NS_WARN_IF(Destroyed())) { + return NS_ERROR_EDITOR_DESTROYED; + } + NS_WARNING_ASSERTION(!ignoredError.Failed(), + "Failed to set interline position"); + ErrorResult error; + SelectionRefPtr()->Collapse(point, error); + if (NS_WARN_IF(Destroyed())) { + error.SuppressException(); + return NS_ERROR_EDITOR_DESTROYED; + } + if (NS_WARN_IF(error.Failed())) { + return error.StealNSResult(); + } + } + // If it's a visible `
` element and next editable content is a + // padding `
` element, we need to set interline position. + else if (nsIContent* nextEditableContentInBlock = + GetNextEditableHTMLNodeInBlock(*previousEditableContent)) { + if (EditorBase::IsPaddingBRElementForEmptyLastLine( + *nextEditableContentInBlock)) { + // Make it stick to the padding `
` element so that it will be + // on blank line. + IgnoredErrorResult ignoredError; + SelectionRefPtr()->SetInterlinePosition(true, ignoredError); + NS_WARNING_ASSERTION(!ignoredError.Failed(), "Failed to set interline position"); - error = NS_OK; - SelectionRefPtr()->Collapse(point, error); - if (NS_WARN_IF(!CanHandleEditAction())) { - error.SuppressException(); - return NS_ERROR_EDITOR_DESTROYED; - } - if (NS_WARN_IF(error.Failed())) { - return error.StealNSResult(); - } - } else { - nsCOMPtr nextNode = - HTMLEditorRef().GetNextEditableHTMLNodeInBlock(*nearNode); - if (nextNode && - EditorBase::IsPaddingBRElementForEmptyLastLine(*nextNode)) { - // Selection between a
element and a padding
element for - // empty last line. Make it stick to the padding
element so - // that it will be on blank line. - IgnoredErrorResult ignoredError; - SelectionRefPtr()->SetInterlinePosition(true, ignoredError); - NS_WARNING_ASSERTION(!ignoredError.Failed(), - "Failed to set interline position"); - } } } } } - // we aren't in a textnode: are we adjacent to text or a break or an image? - nearNode = HTMLEditorRef().GetPreviousEditableHTMLNodeInBlock(point); - if (nearNode && - (TextEditUtils::IsBreak(nearNode) || EditorBase::IsTextNode(nearNode) || - HTMLEditUtils::IsImage(nearNode) || - nearNode->IsHTMLElement(nsGkAtoms::hr))) { - // this is a good place for the caret to be - return NS_OK; + // If previous editable content in same block is `
`, text node, `` + // or `
`, current caret position is fine. + if (nsIContent* previousEditableContentInBlock = + GetPreviousEditableHTMLNodeInBlock(point)) { + if (TextEditUtils::IsBreak(previousEditableContentInBlock) || + EditorBase::IsTextNode(previousEditableContentInBlock) || + HTMLEditUtils::IsImage(previousEditableContentInBlock) || + previousEditableContentInBlock->IsHTMLElement(nsGkAtoms::hr)) { + return NS_OK; + } } - nearNode = HTMLEditorRef().GetNextEditableHTMLNodeInBlock(point); - if (nearNode && - (TextEditUtils::IsBreak(nearNode) || EditorBase::IsTextNode(nearNode) || - nearNode->IsAnyOfHTMLElements(nsGkAtoms::img, nsGkAtoms::hr))) { - return NS_OK; // this is a good place for the caret to be + // If next editable content in same block is `
`, text node, `` or + // `
`, current caret position is fine. + if (nsIContent* nextEditableContentInBlock = + GetNextEditableHTMLNodeInBlock(point)) { + if (TextEditUtils::IsBreak(nextEditableContentInBlock) || + EditorBase::IsTextNode(nextEditableContentInBlock) || + nextEditableContentInBlock->IsAnyOfHTMLElements(nsGkAtoms::img, + nsGkAtoms::hr)) { + return NS_OK; + } } - // look for a nearby text node. - // prefer the correct direction. - nearNode = FindNearEditableNode(point, aAction); - if (!nearNode) { + // Otherwise, look for a near editable content towards edit action direction. + + // If there is no editable content, keep current caret position. + nsIContent* nearEditableContent = + FindNearEditableContent(point, aDirectionAndAmount); + if (!nearEditableContent) { return NS_OK; } - EditorDOMPoint pt = HTMLEditorRef().GetGoodCaretPointFor(*nearNode, aAction); + EditorDOMPoint pointToPutCaret = + GetGoodCaretPointFor(*nearEditableContent, aDirectionAndAmount); + if (NS_WARN_IF(!pointToPutCaret.IsSet())) { + return NS_ERROR_FAILURE; + } ErrorResult error; - SelectionRefPtr()->Collapse(pt, error); - if (NS_WARN_IF(!CanHandleEditAction())) { + SelectionRefPtr()->Collapse(pointToPutCaret, error); + if (NS_WARN_IF(Destroyed())) { error.SuppressException(); return NS_ERROR_EDITOR_DESTROYED; } - if (NS_WARN_IF(error.Failed())) { - return error.StealNSResult(); - } - return NS_OK; + NS_WARNING_ASSERTION(!error.Failed(), "Selection::Collapse() failed"); + return error.StealNSResult(); } template -nsIContent* HTMLEditRules::FindNearEditableNode( +nsIContent* HTMLEditor::FindNearEditableContent( const EditorDOMPointBase& aPoint, nsIEditor::EDirection aDirection) { - MOZ_ASSERT(IsEditorDataAvailable()); - - if (NS_WARN_IF(!aPoint.IsSet())) { - return nullptr; - } + MOZ_ASSERT(IsEditActionDataAvailable()); MOZ_ASSERT(aPoint.IsSetAndValid()); - nsIContent* nearNode = nullptr; + nsIContent* editableContent = nullptr; if (aDirection == nsIEditor::ePrevious) { - nearNode = HTMLEditorRef().GetPreviousEditableHTMLNode(aPoint); - if (!nearNode) { + editableContent = GetPreviousEditableHTMLNode(aPoint); + if (!editableContent) { return nullptr; // Not illegal. } } else { - nearNode = HTMLEditorRef().GetNextEditableHTMLNode(aPoint); - if (NS_WARN_IF(!nearNode)) { + editableContent = GetNextEditableHTMLNode(aPoint); + if (NS_WARN_IF(!editableContent)) { // Perhaps, illegal because the node pointed by aPoint isn't editable // and nobody of previous nodes is editable. return nullptr; @@ -9873,32 +9912,32 @@ nsIContent* HTMLEditRules::FindNearEditableNode( // scan in the right direction until we find an eligible text node, // but don't cross any breaks, images, or table elements. - // XXX This comment sounds odd. |nearNode| may have already crossed breaks - // and/or images. - while (nearNode && !(EditorBase::IsTextNode(nearNode) || - TextEditUtils::IsBreak(nearNode) || - HTMLEditUtils::IsImage(nearNode))) { + // XXX This comment sounds odd. editableContent may have already crossed + // breaks and/or images if they are non-editable. + while (editableContent && !EditorBase::IsTextNode(editableContent) && + !TextEditUtils::IsBreak(editableContent) && + !HTMLEditUtils::IsImage(editableContent)) { if (aDirection == nsIEditor::ePrevious) { - nearNode = HTMLEditorRef().GetPreviousEditableHTMLNode(*nearNode); - if (NS_WARN_IF(!nearNode)) { + editableContent = GetPreviousEditableHTMLNode(*editableContent); + if (NS_WARN_IF(!editableContent)) { return nullptr; } } else { - nearNode = HTMLEditorRef().GetNextEditableHTMLNode(*nearNode); - if (NS_WARN_IF(!nearNode)) { + editableContent = GetNextEditableHTMLNode(*editableContent); + if (NS_WARN_IF(!editableContent)) { return nullptr; } } } // don't cross any table elements - if (HTMLEditor::NodesInDifferentTableElements(*nearNode, + if (HTMLEditor::NodesInDifferentTableElements(*editableContent, *aPoint.GetContainer())) { return nullptr; } // otherwise, ok, we have found a good spot to put the selection - return nearNode; + return editableContent; } // static @@ -9994,14 +10033,8 @@ nsresult HTMLEditRules::RemoveEmptyNodesInChangedRange() { // These node types are candidates if selection is not in them. If // it is one of these, don't delete if selection inside. This is so // we can create empty headings, etc., for the user to type into. - bool isSelectionEndInNode; - rv = SelectionEndpointInNode(node, &isSelectionEndInNode); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - if (!isSelectionEndInNode) { - isCandidate = true; - } + isCandidate = !HTMLEditorRef().StartOrEndOfSelectionRangesIsIn( + *node->AsContent()); } } @@ -10075,25 +10108,18 @@ nsresult HTMLEditRules::RemoveEmptyNodesInChangedRange() { return NS_OK; } -nsresult HTMLEditRules::SelectionEndpointInNode(nsINode* aNode, bool* aResult) { - MOZ_ASSERT(IsEditorDataAvailable()); - - NS_ENSURE_TRUE(aNode && aResult, NS_ERROR_NULL_POINTER); - - *aResult = false; +bool HTMLEditor::StartOrEndOfSelectionRangesIsIn(nsIContent& aContent) const { + MOZ_ASSERT(IsEditActionDataAvailable()); - uint32_t rangeCount = SelectionRefPtr()->RangeCount(); - for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) { - RefPtr range = SelectionRefPtr()->GetRangeAt(rangeIdx); + for (uint32_t i = 0; i < SelectionRefPtr()->RangeCount(); ++i) { + nsRange* range = SelectionRefPtr()->GetRangeAt(i); nsINode* startContainer = range->GetStartContainer(); if (startContainer) { - if (aNode == startContainer) { - *aResult = true; - return NS_OK; + if (&aContent == startContainer) { + return true; } - if (EditorUtils::IsDescendantOf(*startContainer, *aNode)) { - *aResult = true; - return NS_OK; + if (EditorUtils::IsDescendantOf(*startContainer, aContent)) { + return true; } } nsINode* endContainer = range->GetEndContainer(); @@ -10101,17 +10127,15 @@ nsresult HTMLEditRules::SelectionEndpointInNode(nsINode* aNode, bool* aResult) { continue; } if (endContainer) { - if (aNode == endContainer) { - *aResult = true; - return NS_OK; + if (&aContent == endContainer) { + return true; } - if (EditorUtils::IsDescendantOf(*endContainer, *aNode)) { - *aResult = true; - return NS_OK; + if (EditorUtils::IsDescendantOf(*endContainer, aContent)) { + return true; } } } - return NS_OK; + return false; } nsresult HTMLEditor::LiftUpListItemElement( @@ -10275,12 +10299,12 @@ nsresult HTMLEditor::DestroyListStructureRecursively(Element& aListElement) { return NS_OK; } -nsresult HTMLEditRules::ConfirmSelectionInBody() { - MOZ_ASSERT(IsEditorDataAvailable()); +nsresult HTMLEditor::EnsureSelectionInBodyOrDocumentElement() { + MOZ_ASSERT(IsEditActionDataAvailable()); - Element* rootElement = HTMLEditorRef().GetRoot(); - if (NS_WARN_IF(!rootElement)) { - return NS_ERROR_UNEXPECTED; + RefPtr bodyOrDocumentElement = GetRoot(); + if (NS_WARN_IF(!bodyOrDocumentElement)) { + return NS_ERROR_FAILURE; } EditorRawDOMPoint selectionStartPoint( @@ -10289,6 +10313,12 @@ nsresult HTMLEditRules::ConfirmSelectionInBody() { return NS_ERROR_FAILURE; } + // XXX This does wrong things. Web apps can put any elements as sibling + // of `` element. Therefore, this collapses `Selection` into + // the `` element which `HTMLDocument.body` is set to. So, + // this makes users impossible to modify content outside of the + // `` element even if caret is in an editing host. + // Check that selection start container is inside the element. // XXXsmaug this code is insane. nsINode* temp = selectionStartPoint.GetContainer(); @@ -10299,13 +10329,14 @@ nsresult HTMLEditRules::ConfirmSelectionInBody() { // If we aren't in the element, force the issue. if (!temp) { IgnoredErrorResult ignoredError; - SelectionRefPtr()->Collapse(RawRangeBoundary(rootElement, 0), ignoredError); - if (NS_WARN_IF(!CanHandleEditAction())) { + SelectionRefPtr()->Collapse(RawRangeBoundary(bodyOrDocumentElement, 0), + ignoredError); + if (NS_WARN_IF(Destroyed())) { return NS_ERROR_EDITOR_DESTROYED; } NS_WARNING_ASSERTION( !ignoredError.Failed(), - "Failed to collapse selection at start of the root element"); + "Selection::Collapse() with start of editing host failed, but ignored"); return NS_OK; } @@ -10325,13 +10356,14 @@ nsresult HTMLEditRules::ConfirmSelectionInBody() { // If we aren't in the element, force the issue. if (!temp) { IgnoredErrorResult ignoredError; - SelectionRefPtr()->Collapse(RawRangeBoundary(rootElement, 0), ignoredError); - if (NS_WARN_IF(!CanHandleEditAction())) { + SelectionRefPtr()->Collapse(RawRangeBoundary(bodyOrDocumentElement, 0), + ignoredError); + if (NS_WARN_IF(Destroyed())) { return NS_ERROR_EDITOR_DESTROYED; } NS_WARNING_ASSERTION( !ignoredError.Failed(), - "Failed to collapse selection at start of the root element"); + "Selection::Collapse() with start of editing host failed, but ignored"); } return NS_OK; @@ -10772,61 +10804,31 @@ nsresult HTMLEditor::EnsureHardLineEndsWithLastChildOf( return NS_OK; } -nsresult HTMLEditRules::AlignBlock(Element& aElement, - const nsAString& aAlignType, - ResetAlignOf aResetAlignOf) { - MOZ_ASSERT(IsEditorDataAvailable()); - - if (!HTMLEditor::NodeIsBlockStatic(aElement) && - !aElement.IsHTMLElement(nsGkAtoms::hr)) { - // We deal only with blocks; early way out - return NS_OK; - } +nsresult HTMLEditor::SetBlockElementAlign(Element& aBlockOrHRElement, + const nsAString& aAlignType, + EditTarget aEditTarget) { + MOZ_ASSERT(IsEditActionDataAvailable()); + MOZ_ASSERT(HTMLEditor::NodeIsBlockStatic(aBlockOrHRElement) || + aBlockOrHRElement.IsHTMLElement(nsGkAtoms::hr)); + MOZ_ASSERT(IsCSSEnabled() || + HTMLEditUtils::SupportsAlignAttr(aBlockOrHRElement)); - if (!aElement.IsHTMLElement(nsGkAtoms::table)) { + if (!aBlockOrHRElement.IsHTMLElement(nsGkAtoms::table)) { nsresult rv = - MOZ_KnownLive(HTMLEditorRef()) - .RemoveAlignFromDescendants( - aElement, aAlignType, - aResetAlignOf == ResetAlignOf::OnlyDescendants - ? HTMLEditor::EditTarget::OnlyDescendantsExceptTable - : HTMLEditor::EditTarget::NodeAndDescendantsExceptTable); + RemoveAlignFromDescendants(aBlockOrHRElement, aAlignType, aEditTarget); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } - if (HTMLEditorRef().IsCSSEnabled()) { - // Let's use CSS alignment; we use margin-left and margin-right for tables - // and text-align for other block-level elements - nsresult rv = MOZ_KnownLive(HTMLEditorRef()) - .SetAttributeOrEquivalent(&aElement, nsGkAtoms::align, - aAlignType, false); - if (NS_WARN_IF(!CanHandleEditAction())) { - return NS_ERROR_EDITOR_DESTROYED; - } - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - return NS_OK; - } - - // HTML case; this code is supposed to be called ONLY if the element - // supports the align attribute but we'll never know... - if (NS_WARN_IF(!HTMLEditUtils::SupportsAlignAttr(aElement))) { - // XXX error? - return NS_OK; - } - - nsresult rv = MOZ_KnownLive(HTMLEditorRef()) - .SetAttributeOrEquivalent(&aElement, nsGkAtoms::align, - aAlignType, false); - if (NS_WARN_IF(!CanHandleEditAction())) { + nsresult rv = SetAttributeOrEquivalent(&aBlockOrHRElement, nsGkAtoms::align, + aAlignType, false); + if (NS_WARN_IF(Destroyed())) { return NS_ERROR_EDITOR_DESTROYED; } - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - return NS_OK; + NS_WARNING_ASSERTION( + NS_SUCCEEDED(rv), + "SetAttributeOrEquivalent() failed to set `align` attribute or property"); + return rv; } nsresult HTMLEditor::ChangeMarginStart(Element& aElement, diff --git a/editor/libeditor/HTMLEditRules.h b/editor/libeditor/HTMLEditRules.h index 6809c5e7eceb1..893b5da7779ac 100644 --- a/editor/libeditor/HTMLEditRules.h +++ b/editor/libeditor/HTMLEditRules.h @@ -113,19 +113,6 @@ class HTMLEditRules : public TextEditRules { */ MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult DidDeleteSelection(); - /** - * Called before aligning contents around Selection. This method actually - * sets align attributes to align contents. - * - * @param aAlignType New align attribute value where the contents - * should be aligned to. - * @param aCancel Returns true if the operation is canceled. - * @param aHandled Returns true if the edit action is handled. - */ - MOZ_CAN_RUN_SCRIPT - nsresult WillAlign(const nsAString& aAlignType, bool* aCancel, - bool* aHandled); - /** * Called before changing absolute positioned element to static positioned. * This method actually changes the position property of nearest absolute @@ -191,20 +178,6 @@ class HTMLEditRules : public TextEditRules { MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult DidAbsolutePosition(); - /** - * AlignContentsAtSelection() aligns contents around Selection to aAlignType. - * This creates AutoSelectionRestorer. Therefore, even if this returns - * NS_OK, CanHandleEditAction() may return false if the editor is destroyed - * during restoring the Selection. So, every caller needs to check if - * CanHandleEditAction() returns true before modifying the DOM tree or - * changing Selection. - * - * @param aAlignType New align attribute value where the contents - * should be aligned to. - */ - MOZ_CAN_RUN_SCRIPT - MOZ_MUST_USE nsresult AlignContentsAtSelection(const nsAString& aAlignType); - nsresult AppendInnerFormatNodes(nsTArray>& aArray, nsINode* aNode); nsresult GetFormatString(nsINode* aNode, nsAString& outFormat); @@ -236,33 +209,6 @@ class HTMLEditRules : public TextEditRules { void CheckInterlinePosition(); - /** - * AdjustSelection() may adjust Selection range to nearest editable content. - * Despite of the name, this may change the DOM tree. If it needs to create - * a
to put caret, this tries to create a
element. - * - * @param aAction Maybe used to look for a good point to put caret. - */ - MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult - AdjustSelection(nsIEditor::EDirection aAction); - - /** - * FindNearEditableNode() tries to find an editable node near aPoint. - * - * @param aPoint The DOM point where to start to search from. - * @param aDirection If nsIEditor::ePrevious is set, this searches an - * editable node from next nodes. Otherwise, from - * previous nodes. - * @return If found, returns non-nullptr. Otherwise, nullptr. - * Note that if found node is in different table element, - * this returns nullptr. - * And also if aDirection is not nsIEditor::ePrevious, - * the result may be the node pointed by aPoint. - */ - template - nsIContent* FindNearEditableNode(const EditorDOMPointBase& aPoint, - nsIEditor::EDirection aDirection); - /** * RemoveEmptyNodesInChangedRange() removes all empty nodes in * TopLevelEditSubActionData::mChangedRange. However, if mail-cite node has @@ -276,35 +222,6 @@ class HTMLEditRules : public TextEditRules { MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult RemoveEmptyNodesInChangedRange(); - nsresult SelectionEndpointInNode(nsINode* aNode, bool* aResult); - - /** - * ConfirmSelectionInBody() makes sure that Selection is in editor root - * element typically element (see HTMLEditor::UpdateRootElement()) - * and only one Selection range. - * XXX This method is not necessary because even if selection is outside the - * element, elements outside the element should be - * editable, e.g., any element can be inserted siblings as element - * and other browsers allow to edit such elements. - */ - MOZ_MUST_USE nsresult ConfirmSelectionInBody(); - - /** - * AlignBlock() resets align attribute, text-align property, etc first. - * Then, aligns contents of aElement on aAlignType. - * - * @param aElement The element whose contents will be aligned. - * @param aAlignType Boundary or "center" which contents should be - * aligned on. - * @param aResetAlignOf Resets align of whether element and its - * descendants or only descendants. - */ - enum class ResetAlignOf { ElementAndDescendants, OnlyDescendants }; - MOZ_CAN_RUN_SCRIPT - MOZ_MUST_USE nsresult AlignBlock(Element& aElement, - const nsAString& aAlignType, - ResetAlignOf aResetAlignOf); - /** * DocumentModifiedWorker() is called by DocumentModified() either * synchronously or asynchronously. diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index 6c088ad92f71c..318855ff8264d 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -2205,28 +2205,9 @@ nsresult HTMLEditor::AlignAsAction(const nsAString& aAlignType, return NS_ERROR_NOT_INITIALIZED; } - // Protect the edit rules object from dying - RefPtr rules(mRules); - - AutoPlaceholderBatch treatAsOneTransaction(*this); - AutoEditSubActionNotifier startToHandleEditSubAction( - *this, EditSubAction::eSetOrClearAlignment, nsIEditor::eNext); - - bool cancel, handled; - - // Find out if the selection is collapsed: - EditSubActionInfo subActionInfo(EditSubAction::eSetOrClearAlignment); - subActionInfo.alignType = &aAlignType; - nsresult rv = rules->WillDoAction(subActionInfo, &cancel, &handled); - if (cancel || NS_FAILED(rv)) { - return EditorBase::ToGenericNSResult(rv); - } - - rv = rules->DidDoAction(subActionInfo, rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return EditorBase::ToGenericNSResult(rv); - } - return NS_OK; + EditActionResult result = AlignAsSubAction(aAlignType); + NS_WARNING_ASSERTION(result.Succeeded(), "AlignAsSubAction() failed"); + return EditorBase::ToGenericNSResult(result.Rv()); } Element* HTMLEditor::GetElementOrParentByTagName(const nsAtom& aTagName, diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h index ac869558198d0..9a27baf2cf718 100644 --- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -259,8 +259,8 @@ class HTMLEditor final : public TextEditor, MOZ_CAN_RUN_SCRIPT nsresult SetParagraphFormatAsAction( const nsAString& aParagraphFormat, nsIPrincipal* aPrincipal = nullptr); - nsresult AlignAsAction(const nsAString& aAlignType, - nsIPrincipal* aPrincipal = nullptr); + MOZ_CAN_RUN_SCRIPT nsresult AlignAsAction(const nsAString& aAlignType, + nsIPrincipal* aPrincipal = nullptr); MOZ_CAN_RUN_SCRIPT nsresult RemoveListAsAction( const nsAString& aListType, nsIPrincipal* aPrincipal = nullptr); @@ -2501,6 +2501,116 @@ class HTMLEditor final : public TextEditor, MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult RemoveAlignFromDescendants( Element& aElement, const nsAString& aAlignType, EditTarget aEditTarget); + /** + * SetBlockElementAlign() resets `align` attribute, `text-align` property + * of descendants of aBlockOrHRElement except `` element descendants. + * Then, set `align` attribute or `text-align` property of aBlockOrHRElement. + * + * @param aBlockOrHRElement The element whose contents will be aligned. + * This must be a block element or `
` element. + * If we're not in CSS mode, this element has + * to support `align` attribute (i.e., + * `HTMLEditUtils::SupportsAlignAttr()` must + * return true). + * @param aAlignType Boundary or "center" which contents should be + * aligned on. + * @param aEditTarget If `OnlyDescendantsExceptTable`, modifies only + * descendants of aBlockOrHRElement. + * If `NodeAndDescendantsExceptTable`, modifies + * aBlockOrHRElement and its descendants. + */ + MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult + SetBlockElementAlign(Element& aBlockOrHRElement, const nsAString& aAlignType, + EditTarget aEditTarget); + + /** + * AlignContentsAtSelectionWithEmptyDivElement() inserts new `
` element + * at `Selection` to align selected contents. This returns as "handled" + * if this modifies `Selection` so that callers shouldn't modify `Selection` + * in such case especially when using AutoSelectionRestorer. + * + * @param aAlignType New align attribute value where the contents + * should be aligned to. + */ + MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE EditActionResult + AlignContentsAtSelectionWithEmptyDivElement(const nsAString& aAlignType); + + /** + * AlignNodesAndDescendants() make contents of nodes in aArrayOfNodes and + * their descendants aligned to aAlignType. + * + * @param aAlignType New align attribute value where the contents + * should be aligned to. + */ + MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult + AlignNodesAndDescendants(nsTArray>& aArrayOfNodes, + const nsAString& aAlignType); + + /** + * AlignContentsAtSelection() aligns contents around Selection to aAlignType. + * This creates AutoSelectionRestorer. Therefore, even if this returns + * NS_OK, we might have been destroyed. So, every caller needs to check if + * Destroyed() returns false before modifying the DOM tree or changing + * Selection. + * NOTE: Call AlignAsSubAction() instead. + * + * @param aAlignType New align attribute value where the contents + * should be aligned to. + */ + MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult + AlignContentsAtSelection(const nsAString& aAlignType); + + /** + * AlignAsSubAction() handles "align" command with `Selection`. + * + * @param aAlignType New align attribute value where the contents + * should be aligned to. + */ + MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE EditActionResult + AlignAsSubAction(const nsAString& aAlignType); + + /** + * StartOrEndOfSelectionRangesIsIn() returns true if start or end of one + * of selection ranges is in aContent. + */ + bool StartOrEndOfSelectionRangesIsIn(nsIContent& aContent) const; + + /** + * FindNearEditableContent() tries to find an editable node near aPoint. + * + * @param aPoint The DOM point where to start to search from. + * @param aDirection If nsIEditor::ePrevious is set, this searches an + * editable node from next nodes. Otherwise, from + * previous nodes. + * @return If found, returns non-nullptr. Otherwise, nullptr. + * Note that if found node is in different table element, + * this returns nullptr. + * And also if aDirection is not nsIEditor::ePrevious, + * the result may be the node pointed by aPoint. + */ + template + nsIContent* FindNearEditableContent(const EditorDOMPointBase& aPoint, + nsIEditor::EDirection aDirection); + + /** + * AdjustCaretPositionAndEnsurePaddingBRElement() may adjust caret + * position to nearest editable content and if padding `
` element is + * necessary at caret position, this creates it. + * + * @param aDirectionAndAmount Direction of the edit action. + */ + MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult + AdjustCaretPositionAndEnsurePaddingBRElement( + nsIEditor::EDirection aDirectionAndAmount); + + /** + * EnsureSelectionInBodyOrDocumentElement() collapse `Selection` to the + * primary `` element or document element when `Selection` crosses + * `` element's boundary. + */ + MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult + EnsureSelectionInBodyOrDocumentElement(); + protected: // Called by helper classes. virtual void OnStartToHandleTopLevelEditSubAction( EditSubAction aEditSubAction, nsIEditor::EDirection aDirection) override; diff --git a/editor/nsIHTMLEditor.idl b/editor/nsIHTMLEditor.idl index 2aba22a346d88..d0d650317b3ba 100644 --- a/editor/nsIHTMLEditor.idl +++ b/editor/nsIHTMLEditor.idl @@ -307,6 +307,7 @@ interface nsIHTMLEditor : nsISupports * Document me! * */ + [can_run_script] void align(in AString aAlign); /** diff --git a/gfx/wr/Cargo.lock b/gfx/wr/Cargo.lock index af7a494d4ea0d..b9f38edc437d8 100644 --- a/gfx/wr/Cargo.lock +++ b/gfx/wr/Cargo.lock @@ -174,6 +174,9 @@ dependencies = [ name = "cc" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "cfg-if" @@ -420,7 +423,7 @@ version = "0.1.0" dependencies = [ "euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", - "mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "mozangle 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "webrender 0.60.0", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "winit 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -592,17 +595,17 @@ dependencies = [ [[package]] name = "gl_generator" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "khronos_api 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "gl_generator" -version = "0.11.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -781,11 +784,6 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "khronos_api" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "khronos_api" version = "3.1.0" @@ -939,12 +937,13 @@ dependencies = [ [[package]] name = "mozangle" -version = "0.1.7" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gl_generator 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1834,7 +1833,7 @@ dependencies = [ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "mozangle 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "plane-split 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", "png 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1995,7 +1994,7 @@ dependencies = [ "image 0.22.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "mozangle 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "osmesa-src 0.1.1 (git+https://github.com/servo/osmesa-src)", "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2050,14 +2049,6 @@ name = "xdg" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "xml-rs" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "xml-rs" version = "0.8.0" @@ -2148,7 +2139,7 @@ dependencies = [ "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3414b424657317e708489d2857d9575f4403698428b040b609b9d1c1a84a2c" "checksum gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39a23d5e872a275135d66895d954269cf5e8661d234eb1c2480f4ce0d586acbd" -"checksum gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a795170cbd85b5a7baa58d6d7525cae6a03e486859860c220f7ebbbdd379d0a" +"checksum gl_generator 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ca98bbde17256e02d17336a6bdb5a50f7d0ccacee502e191d3e3d0ec2f96f84a" "checksum gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7f46fd8874e043ffac0d638ed1567a2584f7814f6d72b4db37ab1689004a26c4" "checksum glutin 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb26027a84c3b9e1949ef0df0b6a3db8d0c124243a5c161ea25c7def90cb1474" "checksum glutin_egl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "23f48987ab6cb2b61ad903b59e54a2fd0c380a7baff68cffd6826b69a73dd326" @@ -2166,7 +2157,6 @@ dependencies = [ "checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682" "checksum jpeg-decoder 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0dfe27a6c0dabd772d0f9b9f8701c4ca12c4d1eebcadf2be1f6f70396f6a1434" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum khronos_api 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "037ab472c33f67b5fbd3e9163a2645319e5356fcd355efa6d4eb7fff4bbcb554" "checksum khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" @@ -2187,7 +2177,7 @@ dependencies = [ "checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" "checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "45a8a18a41cfab0fde25cc2f43ea89064d211a0fbb33225b8ff93ab20406e0e7" +"checksum mozangle 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "75a61b5a06b6f362eb45590ddf2643c255768a7039bcde1dc70320b97e7f9651" "checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" "checksum nix 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "319fffb13b63c0f4ff5a4e1c97566e7e741561ff5d03bf8bbf11653454bbd70b" "checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" @@ -2301,7 +2291,6 @@ dependencies = [ "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)" = "940586acb859ea05c53971ac231685799a7ec1dee66ac0bccc0e6ad96e06b4e3" "checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" -"checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" "checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5" "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" "checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e" diff --git a/gfx/wr/direct-composition/Cargo.toml b/gfx/wr/direct-composition/Cargo.toml index d21934a36c7bf..ce8d598b002e9 100644 --- a/gfx/wr/direct-composition/Cargo.toml +++ b/gfx/wr/direct-composition/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" [target.'cfg(windows)'.dependencies] euclid = "0.20" gleam = "0.6.2" -mozangle = {version = "0.1", features = ["egl"]} +mozangle = {version = "0.2.7", features = ["egl"]} webrender = {path = "../webrender"} winapi = {version = "0.3", features = ["winerror", "d3d11", "dcomp"]} winit = "0.19" diff --git a/gfx/wr/servo-tidy.toml b/gfx/wr/servo-tidy.toml index 13189aa7ba287..30bfde55233df 100644 --- a/gfx/wr/servo-tidy.toml +++ b/gfx/wr/servo-tidy.toml @@ -8,7 +8,6 @@ check-alphabetical-order = false packages = [ "crossbeam-utils", "gl_generator", - "khronos_api", "lazy_static", "nix", "percent-encoding", @@ -17,7 +16,6 @@ packages = [ "winapi", "core-graphics", "core-text", - "xml-rs", "yaml-rust", ] diff --git a/gfx/wr/webrender/Cargo.toml b/gfx/wr/webrender/Cargo.toml index cde7c0f582a67..f7abc1713b404 100644 --- a/gfx/wr/webrender/Cargo.toml +++ b/gfx/wr/webrender/Cargo.toml @@ -54,7 +54,7 @@ ws = { optional = true, version = "0.9" } svg_fmt = "0.4" [dev-dependencies] -mozangle = "0.1" +mozangle = "0.2" rand = "0.4" [target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies] diff --git a/gfx/wr/wrench/Cargo.toml b/gfx/wr/wrench/Cargo.toml index a0424ef129daa..60be1bdcc417a 100644 --- a/gfx/wr/wrench/Cargo.toml +++ b/gfx/wr/wrench/Cargo.toml @@ -42,7 +42,7 @@ headless = [ "osmesa-sys", "osmesa-src" ] [target.'cfg(target_os = "windows")'.dependencies] dwrote = "0.9" -mozangle = {version = "0.1.5", features = ["egl"]} +mozangle = {version = "0.2", features = ["egl"]} [target.'cfg(all(unix, not(target_os = "android")))'.dependencies] font-loader = "0.7" diff --git a/layout/generic/crashtests/1248227.html b/layout/generic/crashtests/1248227.html new file mode 100644 index 0000000000000..2b2f3ff982492 --- /dev/null +++ b/layout/generic/crashtests/1248227.html @@ -0,0 +1,13 @@ + + + + + + +
+ +
+
+
+ + diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index d2bf6128a64f7..b66c889cf527e 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -653,6 +653,7 @@ load 1233191.html load 1233607.html load 1234701-1.html load 1234701-2.html +load 1248227.html load 1271765.html pref(layout.css.xul-box-display-values.content.enabled,true) asserts(2) asserts-if(Android,1) load 1272983-1.html # bug 586628 pref(layout.css.xul-box-display-values.content.enabled,true) asserts(2) asserts-if(Android,1) load 1272983-2.html # bug 586628 diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py index 9baf334504df2..872cd0f21c604 100644 --- a/python/mozbuild/mozbuild/backend/recursivemake.py +++ b/python/mozbuild/mozbuild/backend/recursivemake.py @@ -1827,3 +1827,9 @@ def _handle_webidl_build(self, bindings_dir, unified_source_mapping, webidls_mk = mozpath.join(bindings_dir, 'webidlsrcs.mk') with self._write_file(webidls_mk) as fh: mk.dump(fh, removal_guard=False) + + # Add the test directory to the compile graph. + if self.environment.substs.get('ENABLE_TESTS'): + self._compile_graph[mozpath.join( + mozpath.relpath(bindings_dir, self.environment.topobjdir), + 'test', 'target-objects')] diff --git a/taskcluster/ci/build/linux.yml b/taskcluster/ci/build/linux.yml index 4c82f2cf68b3b..f677b4c665419 100644 --- a/taskcluster/ci/build/linux.yml +++ b/taskcluster/ci/build/linux.yml @@ -1171,7 +1171,7 @@ linux64-aarch64/opt: fetches: toolchain: - linux64-binutils - - linux64-clang + - linux64-clang-aarch64-cross - linux64-rust - linux64-rust-size - linux64-cbindgen diff --git a/taskcluster/ci/toolchain/clang.yml b/taskcluster/ci/toolchain/clang.yml index 81ac5eb7665e8..215dc99d183b3 100644 --- a/taskcluster/ci/toolchain/clang.yml +++ b/taskcluster/ci/toolchain/clang.yml @@ -145,7 +145,7 @@ linux64-clang-8-aarch64-cross: - 'build/build-clang/clang-8-linux64-aarch64-cross.json' resources: - 'build/build-clang/clang-8-linux64-aarch64-cross.json' - toolchain-alias: linux64-aarch64-cross + toolchain-alias: linux64-clang-aarch64-cross toolchain-artifact: public/build/clang.tar.xz fetches: fetch: diff --git a/toolkit/actors/ZoomParent.jsm b/toolkit/actors/ZoomParent.jsm index 36c871b0d31ba..53e131bbddc08 100644 --- a/toolkit/actors/ZoomParent.jsm +++ b/toolkit/actors/ZoomParent.jsm @@ -8,7 +8,7 @@ var EXPORTED_SYMBOLS = ["ZoomParent"]; class ZoomParent extends JSWindowActorParent { receiveMessage(message) { - let browser = this.browsingContext.embedderElement; + let browser = this.browsingContext.top.embedderElement; if (!browser) { return; } diff --git a/toolkit/library/Makefile.in b/toolkit/library/build/Makefile.in similarity index 100% rename from toolkit/library/Makefile.in rename to toolkit/library/build/Makefile.in