Bug 1742933 - part 11: Create a pref to get back the traditional behavior r=m_kato

For avoiding simple back-out of the patches when we get serious regression
reports, we should have a pref to disable the new pref.

Differential Revision: https://phabricator.services.mozilla.com/D140475
This commit is contained in:
Masayuki Nakano
2022-03-11 09:21:36 +00:00
parent 846510e59b
commit 16c8061d35
5 changed files with 133 additions and 59 deletions

View File

@@ -3052,15 +3052,21 @@ EditActionResult HTMLEditor::ChangeSelectedHardLinesToList(
[&](Element& aListElement) MOZ_CAN_RUN_SCRIPT_BOUNDARY { [&](Element& aListElement) MOZ_CAN_RUN_SCRIPT_BOUNDARY {
Result<RefPtr<Element>, nsresult> listItemElementOrError = Result<RefPtr<Element>, nsresult> listItemElementOrError =
CreateAndInsertElement( CreateAndInsertElement(
WithTransaction::No, aListItemElementTagName, aListElement.IsInComposedDoc() ? WithTransaction::Yes
: WithTransaction::No,
aListItemElementTagName,
EditorDOMPoint(&aListElement, 0u), EditorDOMPoint(&aListElement, 0u),
[](Element& aListItemElement) -> nsresult { [](Element& aListItemElement) -> nsresult {
return NS_OK; return NS_OK;
}); });
if (listItemElementOrError.isErr()) { if (listItemElementOrError.isErr()) {
NS_WARNING( NS_WARNING(nsPrintfCString(
"HTMLEditor::CreateAndInsertElement(WithTransaction::Yes) " "HTMLEditor::CreateAndInsertElement(%s) failed",
"failed"); ToString(aListElement.IsInComposedDoc()
? WithTransaction::Yes
: WithTransaction::No)
.c_str())
.get());
return listItemElementOrError.unwrapErr(); return listItemElementOrError.unwrapErr();
} }
MOZ_ASSERT(listItemElementOrError.inspect()); MOZ_ASSERT(listItemElementOrError.inspect());
@@ -5707,13 +5713,17 @@ nsresult HTMLEditor::AlignBlockContentsWithDivElement(
WithTransaction::Yes, *nsGkAtoms::div, EditorDOMPoint(&aBlockElement, 0u), WithTransaction::Yes, *nsGkAtoms::div, EditorDOMPoint(&aBlockElement, 0u),
// MOZ_CAN_RUN_SCRIPT_BOUNDARY due to bug 1758868 // MOZ_CAN_RUN_SCRIPT_BOUNDARY due to bug 1758868
[&](Element& aDivElement) MOZ_CAN_RUN_SCRIPT_BOUNDARY { [&](Element& aDivElement) MOZ_CAN_RUN_SCRIPT_BOUNDARY {
// aDivElement has not been connected yet so that we do not need // If aDivElement has not been connected yet, we do not need transaction
// transaction of setting align attribute here. // of setting align attribute here.
nsresult rv = SetAttributeOrEquivalent(&aDivElement, nsGkAtoms::align, nsresult rv =
aAlignType, false); SetAttributeOrEquivalent(&aDivElement, nsGkAtoms::align, aAlignType,
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), !aDivElement.IsInComposedDoc());
"EditorBase::SetAttributeOrEquivalent(" NS_WARNING_ASSERTION(
"nsGkAtoms::align) failed"); NS_SUCCEEDED(rv),
nsPrintfCString("EditorBase::SetAttributeOrEquivalent(nsGkAtoms:: "
"align, \"...\", %s) failed",
!aDivElement.IsInComposedDoc() ? "true" : "false")
.get());
return rv; return rv;
}); });
if (maybeNewDivElement.isErr()) { if (maybeNewDivElement.isErr()) {
@@ -6953,15 +6963,23 @@ nsresult HTMLEditor::HandleInsertParagraphInHeadingElement(
[&](Element& aDivOrParagraphElement) MOZ_CAN_RUN_SCRIPT_BOUNDARY { [&](Element& aDivOrParagraphElement) MOZ_CAN_RUN_SCRIPT_BOUNDARY {
// We don't make inserting new <br> element undoable // We don't make inserting new <br> element undoable
// because removing the new element from the DOM tree // because removing the new element from the DOM tree
// gets same result for the user. // gets same result for the user if aDivOrParagraphElement
// has not been connected yet.
Result<RefPtr<Element>, nsresult> brElementOrError = Result<RefPtr<Element>, nsresult> brElementOrError =
InsertBRElement( InsertBRElement(
WithTransaction::No, aDivOrParagraphElement.IsInComposedDoc()
? WithTransaction::Yes
: WithTransaction::No,
EditorDOMPoint(&aDivOrParagraphElement, 0u)); EditorDOMPoint(&aDivOrParagraphElement, 0u));
if (brElementOrError.isErr()) { if (brElementOrError.isErr()) {
NS_WARNING( NS_WARNING(
"HTMLEditor::InsertBRElement(WithTransaction::No) " nsPrintfCString(
"failed"); "HTMLEditor::InsertBRElement(%s) failed",
ToString(aDivOrParagraphElement.IsInComposedDoc()
? WithTransaction::Yes
: WithTransaction::No)
.c_str())
.get());
return brElementOrError.unwrapErr(); return brElementOrError.unwrapErr();
} }
return NS_OK; return NS_OK;
@@ -7392,13 +7410,20 @@ nsresult HTMLEditor::HandleInsertParagraphInListItemElement(
[&](Element& aDivOrParagraphElement) MOZ_CAN_RUN_SCRIPT_BOUNDARY { [&](Element& aDivOrParagraphElement) MOZ_CAN_RUN_SCRIPT_BOUNDARY {
// We don't make inserting new <br> element undoable because // We don't make inserting new <br> element undoable because
// removing the new element from the DOM tree gets same result for // removing the new element from the DOM tree gets same result for
// the user. // the user if aDivOrParagraphElement has not been connected yet.
Result<RefPtr<Element>, nsresult> brElementOrError = Result<RefPtr<Element>, nsresult> brElementOrError =
InsertBRElement(WithTransaction::No, InsertBRElement(aDivOrParagraphElement.IsInComposedDoc()
? WithTransaction::Yes
: WithTransaction::No,
EditorDOMPoint(&aDivOrParagraphElement, 0u)); EditorDOMPoint(&aDivOrParagraphElement, 0u));
if (brElementOrError.isErr()) { if (brElementOrError.isErr()) {
NS_WARNING( NS_WARNING(nsPrintfCString(
"HTMLEditor::InsertBRElement(WithTransaction::No) failed"); "HTMLEditor::InsertBRElement(%s) failed",
ToString(aDivOrParagraphElement.IsInComposedDoc()
? WithTransaction::Yes
: WithTransaction::No)
.c_str())
.get());
return brElementOrError.unwrapErr(); return brElementOrError.unwrapErr();
} }
return NS_OK; return NS_OK;

View File

@@ -473,21 +473,29 @@ NS_IMETHODIMP HTMLEditor::SetDocumentCharacterSet(
CreateAndInsertElement( CreateAndInsertElement(
WithTransaction::Yes, *nsGkAtoms::meta, WithTransaction::Yes, *nsGkAtoms::meta,
EditorDOMPoint(primaryHeadElement, 0), [&](Element& aMetaElement) { EditorDOMPoint(primaryHeadElement, 0), [&](Element& aMetaElement) {
DebugOnly<nsresult> rvIgnored = DebugOnly<nsresult> rvIgnored = aMetaElement.SetAttr(
aMetaElement.SetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, kNameSpaceID_None, nsGkAtoms::httpEquiv, u"Content-Type"_ns,
u"Content-Type"_ns, false); aMetaElement.IsInComposedDoc());
NS_WARNING_ASSERTION( NS_WARNING_ASSERTION(
NS_SUCCEEDED(rvIgnored), NS_SUCCEEDED(rvIgnored),
"Element::SetAttr(nsGkAtoms::httpEquiv, Content-Type) " nsPrintfCString(
"failed, but ignored"); "Element::SetAttr(nsGkAtoms::httpEquiv, \"Content-Type\", "
"%s) failed, but ignored",
aMetaElement.IsInComposedDoc() ? "true" : "false")
.get());
rvIgnored = rvIgnored =
aMetaElement.SetAttr(kNameSpaceID_None, nsGkAtoms::content, aMetaElement.SetAttr(kNameSpaceID_None, nsGkAtoms::content,
u"text/html;charset="_ns + u"text/html;charset="_ns +
NS_ConvertASCIItoUTF16(aCharacterSet), NS_ConvertASCIItoUTF16(aCharacterSet),
false); aMetaElement.IsInComposedDoc());
NS_WARNING_ASSERTION( NS_WARNING_ASSERTION(
NS_SUCCEEDED(rvIgnored), NS_SUCCEEDED(rvIgnored),
"Element::SetAttr(nsGkAtoms::content) failed, but ignored"); nsPrintfCString(
"Element::SetAttr(nsGkAtoms::content, "
"\"text/html;charset=%s\", %s) failed, but ignored",
nsPromiseFlatCString(aCharacterSet).get(),
aMetaElement.IsInComposedDoc() ? "true" : "false")
.get());
return NS_OK; return NS_OK;
}); });
if (maybeNewMetaElement.isErr()) { if (maybeNewMetaElement.isErr()) {
@@ -2975,9 +2983,8 @@ Result<RefPtr<Element>, nsresult> HTMLEditor::CreateAndInsertElement(
// CreatElementTransaction since we can use InsertNodeTransaction // CreatElementTransaction since we can use InsertNodeTransaction
// instead. // instead.
RefPtr<Element> newElement;
nsresult rv; nsresult rv;
newElement = CreateHTMLContent(&aTagName); RefPtr<Element> newElement = CreateHTMLContent(&aTagName);
NS_WARNING_ASSERTION(newElement, "EditorBase::CreateHTMLContent() failed"); NS_WARNING_ASSERTION(newElement, "EditorBase::CreateHTMLContent() failed");
if (MOZ_LIKELY(newElement)) { if (MOZ_LIKELY(newElement)) {
rv = MarkElementDirty(*newElement); rv = MarkElementDirty(*newElement);
@@ -2988,12 +2995,14 @@ Result<RefPtr<Element>, nsresult> HTMLEditor::CreateAndInsertElement(
NS_WARNING_ASSERTION( NS_WARNING_ASSERTION(
NS_SUCCEEDED(rv), NS_SUCCEEDED(rv),
"EditorBase::MarkElementDirty() failed, but ignored"); "EditorBase::MarkElementDirty() failed, but ignored");
if (StaticPrefs::editor_initialize_element_before_connect()) {
rv = aInitializer(*newElement); rv = aInitializer(*newElement);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "aInitializer failed"); NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "aInitializer failed");
if (MOZ_UNLIKELY(rv != NS_ERROR_EDITOR_DESTROYED && if (MOZ_UNLIKELY(rv != NS_ERROR_EDITOR_DESTROYED &&
NS_WARN_IF(Destroyed()))) { NS_WARN_IF(Destroyed()))) {
rv = NS_ERROR_EDITOR_DESTROYED; rv = NS_ERROR_EDITOR_DESTROYED;
} }
}
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
RefPtr<InsertNodeTransaction> transaction = RefPtr<InsertNodeTransaction> transaction =
InsertNodeTransaction::Create(*this, *newElement, aPointToInsert); InsertNodeTransaction::Create(*this, *newElement, aPointToInsert);
@@ -3046,6 +3055,18 @@ Result<RefPtr<Element>, nsresult> HTMLEditor::CreateAndInsertElement(
return Err(rv); return Err(rv);
} }
if (!StaticPrefs::editor_initialize_element_before_connect() && newElement) {
rv = aInitializer(*newElement);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "aInitializer failed");
if (MOZ_UNLIKELY(rv != NS_ERROR_EDITOR_DESTROYED &&
NS_WARN_IF(Destroyed()))) {
rv = NS_ERROR_EDITOR_DESTROYED;
}
if (NS_FAILED(rv)) {
return Err(rv);
}
}
return newElement; return newElement;
} }

View File

@@ -1498,10 +1498,10 @@ class HTMLEditor final : public EditorBase,
* Note that this point will be invalid once this * Note that this point will be invalid once this
* method inserts the new element. * method inserts the new element.
* @param aInitializer A function to initialize the new element before * @param aInitializer A function to initialize the new element before
* connecting the element into the DOM tree. * or after (depends on the pref) connecting the
* Note that this should not touch outside given * element into the DOM tree. Note that this should
* element because doing it would break range * not touch outside given element because doing it
* updater's result. * would break range updater's result.
* @return The created new element node or an error. * @return The created new element node or an error.
*/ */
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<RefPtr<Element>, nsresult> [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<RefPtr<Element>, nsresult>
@@ -1545,10 +1545,10 @@ class HTMLEditor final : public EditorBase,
* kept if and only if a <br> element follows * kept if and only if a <br> element follows
* split point. * split point.
* @param aInitializer A function to initialize the new element before * @param aInitializer A function to initialize the new element before
* connecting the element into the DOM tree. * or after (depends on the pref) connecting the
* Note that this should not touch outside given * element into the DOM tree. Note that this should
* element because doing it would break range * not touch outside given element because doing it
* updater's result. * would break range updater's result.
*/ */
enum class BRElementNextToSplitPoint { Keep, Delete }; enum class BRElementNextToSplitPoint { Keep, Delete };
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<RefPtr<Element>, nsresult> [[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<RefPtr<Element>, nsresult>
@@ -3428,10 +3428,10 @@ class HTMLEditor final : public EditorBase,
* *
* @param aTag The element name to be created. * @param aTag The element name to be created.
* @param aInitializer A function to initialize the new element before * @param aInitializer A function to initialize the new element before
* connecting the element into the DOM tree. * or after (depends on the pref) connecting the
* Note that this should not touch outside given * element into the DOM tree. Note that this should
* element because doing it would break range * not touch outside given element because doing it
* updater's result. * would break range updater's result.
*/ */
MOZ_CAN_RUN_SCRIPT Result<RefPtr<Element>, nsresult> MOZ_CAN_RUN_SCRIPT Result<RefPtr<Element>, nsresult>
DeleteSelectionAndCreateElement( DeleteSelectionAndCreateElement(

View File

@@ -64,6 +64,7 @@
#include "nsLinebreakConverter.h" #include "nsLinebreakConverter.h"
#include "nsLiteralString.h" #include "nsLiteralString.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "nsPrintfCString.h"
#include "nsRange.h" #include "nsRange.h"
#include "nsReadableUtils.h" #include "nsReadableUtils.h"
#include "nsServiceManagerUtils.h" #include "nsServiceManagerUtils.h"
@@ -2485,10 +2486,15 @@ nsresult HTMLEditor::PasteAsQuotationAsAction(int32_t aClipboardType,
// MOZ_CAN_RUN_SCRIPT_BOUNDARY due to bug 1758868 // MOZ_CAN_RUN_SCRIPT_BOUNDARY due to bug 1758868
[&](Element& aBlockquoteElement) MOZ_CAN_RUN_SCRIPT_BOUNDARY { [&](Element& aBlockquoteElement) MOZ_CAN_RUN_SCRIPT_BOUNDARY {
DebugOnly<nsresult> rvIgnored = aBlockquoteElement.SetAttr( DebugOnly<nsresult> rvIgnored = aBlockquoteElement.SetAttr(
kNameSpaceID_None, nsGkAtoms::type, u"cite"_ns, false); kNameSpaceID_None, nsGkAtoms::type, u"cite"_ns,
aBlockquoteElement.IsInComposedDoc());
NS_WARNING_ASSERTION( NS_WARNING_ASSERTION(
NS_SUCCEEDED(rvIgnored), NS_SUCCEEDED(rvIgnored),
"Element::SetAttr(nsGkAtoms::type, cite) failed, but ignored"); nsPrintfCString(
"Element::SetAttr(nsGkAtoms::type, \"cite\", %s) "
"failed, but ignored",
aBlockquoteElement.IsInComposedDoc() ? "true" : "false")
.get());
return NS_OK; return NS_OK;
}); });
if (MOZ_UNLIKELY(blockquoteElementOrError.isErr() || if (MOZ_UNLIKELY(blockquoteElementOrError.isErr() ||
@@ -2892,10 +2898,15 @@ nsresult HTMLEditor::InsertAsPlaintextQuotation(const nsAString& aQuotedText,
*nsGkAtoms::span, [](Element& aSpanElement) { *nsGkAtoms::span, [](Element& aSpanElement) {
// Add an attribute on the pre node so we'll know it's a quotation. // Add an attribute on the pre node so we'll know it's a quotation.
DebugOnly<nsresult> rvIgnored = aSpanElement.SetAttr( DebugOnly<nsresult> rvIgnored = aSpanElement.SetAttr(
kNameSpaceID_None, nsGkAtoms::mozquote, u"true"_ns, false); kNameSpaceID_None, nsGkAtoms::mozquote, u"true"_ns,
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored), aSpanElement.IsInComposedDoc());
"Element::SetAttr(nsGkAtoms::mozquote, " NS_WARNING_ASSERTION(
"\"true\", false) failed"); NS_SUCCEEDED(rvIgnored),
nsPrintfCString(
"Element::SetAttr(nsGkAtoms::mozquote, \"true\", %s) "
"failed",
aSpanElement.IsInComposedDoc() ? "true" : "false")
.get());
// Allow wrapping on spans so long lines get wrapped to the screen. // Allow wrapping on spans so long lines get wrapped to the screen.
if (aSpanElement.GetParent() && if (aSpanElement.GetParent() &&
aSpanElement.GetParent()->IsHTMLElement(nsGkAtoms::body)) { aSpanElement.GetParent()->IsHTMLElement(nsGkAtoms::body)) {
@@ -3151,16 +3162,26 @@ nsresult HTMLEditor::InsertAsCitedQuotationInternal(
[&](Element& aBlockquoteElement) MOZ_CAN_RUN_SCRIPT_BOUNDARY { [&](Element& aBlockquoteElement) MOZ_CAN_RUN_SCRIPT_BOUNDARY {
// Try to set type=cite. Ignore it if this fails. // Try to set type=cite. Ignore it if this fails.
DebugOnly<nsresult> rvIgnored = aBlockquoteElement.SetAttr( DebugOnly<nsresult> rvIgnored = aBlockquoteElement.SetAttr(
kNameSpaceID_None, nsGkAtoms::type, u"cite"_ns, false); kNameSpaceID_None, nsGkAtoms::type, u"cite"_ns,
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored), aBlockquoteElement.IsInComposedDoc());
"Element::SetAttr(nsGkAtoms::type, " NS_WARNING_ASSERTION(
"\"cite\", false) failed, but ignored"); NS_SUCCEEDED(rvIgnored),
nsPrintfCString(
"Element::SetAttr(nsGkAtoms::type, \"cite\", %s) failed, "
"but ignored",
aBlockquoteElement.IsInComposedDoc() ? "true" : "false")
.get());
if (!aCitation.IsEmpty()) { if (!aCitation.IsEmpty()) {
DebugOnly<nsresult> rvIgnored = aBlockquoteElement.SetAttr( DebugOnly<nsresult> rvIgnored = aBlockquoteElement.SetAttr(
kNameSpaceID_None, nsGkAtoms::cite, aCitation, false); kNameSpaceID_None, nsGkAtoms::cite, aCitation,
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored), aBlockquoteElement.IsInComposedDoc());
"Element::SetAttr(nsGkAtoms::cite, " NS_WARNING_ASSERTION(
"\"...\", false) failed, but ignored"); NS_SUCCEEDED(rvIgnored),
nsPrintfCString(
"Element::SetAttr(nsGkAtoms::cite, \"...\", %s) failed, "
"but ignored",
aBlockquoteElement.IsInComposedDoc() ? "true" : "false")
.get());
} }
return NS_OK; return NS_OK;
}); });

View File

@@ -4422,6 +4422,13 @@
value: true value: true
mirror: always mirror: always
# Whether editor initializes attributes and/or child nodes of newly inserting
# element before or after connecting to the DOM tree.
- name: editor.initialize_element_before_connect
type: bool
value: true
mirror: always
# Delay to mask last input character in password fields. # Delay to mask last input character in password fields.
# If negative value, to use platform's default behavior. # If negative value, to use platform's default behavior.
# If 0, no delay to mask password. # If 0, no delay to mask password.