From c4f8b966cba916141af0204b4d574b87a6b8ca62 Mon Sep 17 00:00:00 2001 From: Vincent Hilla Date: Tue, 9 Jul 2024 08:00:32 +0000 Subject: [PATCH] Bug 1881225 - Consider CDATASections for dir=auto. r=emilio Differential Revision: https://phabricator.services.mozilla.com/D209697 --- dom/base/CharacterData.cpp | 8 +-- dom/base/DirectionalityUtils.cpp | 50 ++++++------- dom/base/DirectionalityUtils.h | 10 +-- dom/base/Text.cpp | 14 ++++ dom/base/Text.h | 3 + dom/base/nsINode.h | 7 +- dom/base/nsTextNode.cpp | 15 ---- dom/base/nsTextNode.h | 3 - .../global-attributes/cdata-dir_auto.html | 71 +++++++++++++++++++ .../global-attributes/cdata-iframe.xhtml | 32 +++++++++ 10 files changed, 154 insertions(+), 59 deletions(-) create mode 100644 testing/web-platform/tests/html/dom/elements/global-attributes/cdata-dir_auto.html create mode 100644 testing/web-platform/tests/html/dom/elements/global-attributes/cdata-iframe.xhtml diff --git a/dom/base/CharacterData.cpp b/dom/base/CharacterData.cpp index 2157087db8da..9e1b6ec98567 100644 --- a/dom/base/CharacterData.cpp +++ b/dom/base/CharacterData.cpp @@ -250,9 +250,7 @@ nsresult CharacterData::SetTextInternal( auto oldDir = Directionality::Unset; const bool dirAffectsAncestor = - NodeType() == TEXT_NODE && - TextNodeWillChangeDirection(static_cast(this), &oldDir, - aOffset); + IsText() && TextNodeWillChangeDirection(AsText(), &oldDir, aOffset); if (aOffset == 0 && endOffset == textLength) { // Replacing whole text or old text was empty. @@ -313,8 +311,8 @@ nsresult CharacterData::SetTextInternal( if (dirAffectsAncestor) { // dirAffectsAncestor being true implies that we have a text node, see // above. - MOZ_ASSERT(NodeType() == TEXT_NODE); - TextNodeChangedDirection(static_cast(this), oldDir, aNotify); + MOZ_ASSERT(IsText()); + TextNodeChangedDirection(AsText(), oldDir, aNotify); } // Notify observers diff --git a/dom/base/DirectionalityUtils.cpp b/dom/base/DirectionalityUtils.cpp index 2e4ada480051..fb82ac316c2d 100644 --- a/dom/base/DirectionalityUtils.cpp +++ b/dom/base/DirectionalityUtils.cpp @@ -145,12 +145,12 @@ #include "mozilla/dom/HTMLInputElement.h" #include "mozilla/dom/HTMLSlotElement.h" #include "mozilla/dom/ShadowRoot.h" +#include "mozilla/dom/Text.h" #include "mozilla/dom/UnbindContext.h" #include "mozilla/intl/UnicodeProperties.h" #include "nsUnicodeProperties.h" #include "nsTextFragment.h" #include "nsAttrValue.h" -#include "nsTextNode.h" namespace mozilla { @@ -158,6 +158,7 @@ using mozilla::dom::Element; using mozilla::dom::HTMLInputElement; using mozilla::dom::HTMLSlotElement; using mozilla::dom::ShadowRoot; +using mozilla::dom::Text; static nsIContent* GetParentOrHostOrSlot(const nsIContent* aContent) { if (HTMLSlotElement* slot = aContent->GetAssignedSlot()) { @@ -228,7 +229,7 @@ inline static bool TextChildrenAffectDirAutoAncestor(nsIContent* aContent) { aContent->NodeOrAncestorHasDirAuto(); } -inline static bool NodeAffectsDirAutoAncestor(nsTextNode* aTextNode) { +inline static bool NodeAffectsDirAutoAncestor(Text* aTextNode) { nsIContent* parent = GetParentOrHostOrSlot(aTextNode); return parent && TextChildrenAffectDirAutoAncestor(parent) && !aTextNode->IsInNativeAnonymousSubtree(); @@ -292,7 +293,7 @@ static Directionality GetDirectionFromText(const char* aText, return Directionality::Unset; } -static Directionality GetDirectionFromText(const mozilla::dom::Text* aTextNode, +static Directionality GetDirectionFromText(const Text* aTextNode, uint32_t* aFirstStrong = nullptr) { const nsTextFragment* frag = &aTextNode->TextFragment(); if (frag->Is2b()) { @@ -302,7 +303,7 @@ static Directionality GetDirectionFromText(const mozilla::dom::Text* aTextNode, return GetDirectionFromText(frag->Get1b(), frag->GetLength(), aFirstStrong); } -static nsTextNode* WalkDescendantsAndGetDirectionFromText( +static Text* WalkDescendantsAndGetDirectionFromText( nsINode* aRoot, Directionality* aDirectionality) { nsIContent* child = aRoot->GetFirstChild(); while (child) { @@ -317,8 +318,7 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText( const nsTArray>& assignedNodes = slot->AssignedNodes(); for (uint32_t i = 0; i < assignedNodes.Length(); ++i) { nsIContent* assignedNode = assignedNodes[i]->AsContent(); - if (assignedNode->NodeType() == nsINode::TEXT_NODE) { - auto* text = static_cast(assignedNode); + if (auto* text = Text::FromNode(assignedNode)) { Directionality textNodeDir = GetDirectionFromText(text); if (textNodeDir != Directionality::Unset) { *aDirectionality = textNodeDir; @@ -326,8 +326,8 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText( } } else if (assignedNode->IsElement() && AffectsDirectionOfAncestors(assignedNode->AsElement())) { - nsTextNode* text = WalkDescendantsAndGetDirectionFromText( - assignedNode, aDirectionality); + Text* text = WalkDescendantsAndGetDirectionFromText(assignedNode, + aDirectionality); if (text) { return text; } @@ -335,8 +335,7 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText( } } - if (child->NodeType() == nsINode::TEXT_NODE) { - auto* text = static_cast(child); + if (auto* text = Text::FromNode(child)) { Directionality textNodeDir = GetDirectionFromText(text); if (textNodeDir != Directionality::Unset) { *aDirectionality = textNodeDir; @@ -355,8 +354,8 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText( * * @return the text node containing the character that determined the direction */ -static nsTextNode* WalkDescendantsSetDirectionFromText(Element* aElement, - bool aNotify) { +static Text* WalkDescendantsSetDirectionFromText(Element* aElement, + bool aNotify) { MOZ_ASSERT(aElement, "Must have an element"); MOZ_ASSERT(aElement->HasDirAuto(), "Element must have dir=auto"); @@ -368,7 +367,7 @@ static nsTextNode* WalkDescendantsSetDirectionFromText(Element* aElement, // Check the text in Shadow DOM. if (ShadowRoot* shadowRoot = aElement->GetShadowRoot()) { - nsTextNode* text = + Text* text = WalkDescendantsAndGetDirectionFromText(shadowRoot, &textNodeDir); if (text) { aElement->SetDirectionality(textNodeDir, aNotify); @@ -377,8 +376,7 @@ static nsTextNode* WalkDescendantsSetDirectionFromText(Element* aElement, } // Check the text in light DOM. - nsTextNode* text = - WalkDescendantsAndGetDirectionFromText(aElement, &textNodeDir); + Text* text = WalkDescendantsAndGetDirectionFromText(aElement, &textNodeDir); if (text) { aElement->SetDirectionality(textNodeDir, aNotify); return text; @@ -494,8 +492,7 @@ void SetDirectionalityOnDescendants(Element* aElement, Directionality aDir, static void ResetAutoDirection(Element* aElement, bool aNotify) { MOZ_ASSERT(aElement->HasDirAuto()); - nsTextNode* setByNode = - WalkDescendantsSetDirectionFromText(aElement, aNotify); + Text* setByNode = WalkDescendantsSetDirectionFromText(aElement, aNotify); if (setByNode) { setByNode->SetMaySetDirAuto(); } @@ -516,7 +513,7 @@ void WalkAncestorsResetAutoDirection(Element* aElement, bool aNotify) { if (!parentElement || !parentElement->HasDirAuto()) { continue; } - nsTextNode* setByNode = + Text* setByNode = WalkDescendantsSetDirectionFromText(parentElement, aNotify); if (setByNode) { setByNode->SetMaySetDirAuto(); @@ -638,7 +635,7 @@ void WalkDescendantsSetDirAuto(Element* aElement, bool aNotify) { SetAncestorHasDirAutoOnDescendants(aElement); } - nsTextNode* textNode = WalkDescendantsSetDirectionFromText(aElement, aNotify); + Text* textNode = WalkDescendantsSetDirectionFromText(aElement, aNotify); if (textNode) { textNode->SetMaySetDirAuto(); } @@ -716,13 +713,12 @@ static DirAutoElementResult FindDirAutoElementFrom(nsIContent* aContent) { return {nullptr, false}; } -static DirAutoElementResult FindDirAutoElementForText(nsTextNode* aTextNode) { - MOZ_ASSERT(aTextNode->NodeType() == nsINode::TEXT_NODE, - "Must be a text node"); +static DirAutoElementResult FindDirAutoElementForText(Text* aTextNode) { + MOZ_ASSERT(aTextNode->IsText(), "Must be a text node"); return FindDirAutoElementFrom(GetParentOrHostOrSlot(aTextNode)); } -static DirAutoElementResult SetAncestorDirectionIfAuto(nsTextNode* aTextNode, +static DirAutoElementResult SetAncestorDirectionIfAuto(Text* aTextNode, Directionality aDir, bool aNotify = true) { auto result = FindDirAutoElementForText(aTextNode); @@ -741,7 +737,7 @@ static DirAutoElementResult SetAncestorDirectionIfAuto(nsTextNode* aTextNode, return result; } -bool TextNodeWillChangeDirection(nsTextNode* aTextNode, Directionality* aOldDir, +bool TextNodeWillChangeDirection(Text* aTextNode, Directionality* aOldDir, uint32_t aOffset) { if (!NodeAffectsDirAutoAncestor(aTextNode)) { return false; @@ -754,7 +750,7 @@ bool TextNodeWillChangeDirection(nsTextNode* aTextNode, Directionality* aOldDir, return (aOffset <= firstStrong); } -void TextNodeChangedDirection(nsTextNode* aTextNode, Directionality aOldDir, +void TextNodeChangedDirection(Text* aTextNode, Directionality aOldDir, bool aNotify) { MOZ_ASSERT(NodeAffectsDirAutoAncestor(aTextNode), "Caller should check"); Directionality newDir = GetDirectionFromText(aTextNode); @@ -771,7 +767,7 @@ void TextNodeChangedDirection(nsTextNode* aTextNode, Directionality aOldDir, } } -void SetDirectionFromNewTextNode(nsTextNode* aTextNode) { +void SetDirectionFromNewTextNode(Text* aTextNode) { if (!NodeAffectsDirAutoAncestor(aTextNode)) { return; } @@ -787,7 +783,7 @@ void SetDirectionFromNewTextNode(nsTextNode* aTextNode) { } } -void ResetDirectionSetByTextNode(nsTextNode* aTextNode, +void ResetDirectionSetByTextNode(Text* aTextNode, dom::UnbindContext& aContext) { MOZ_ASSERT(!aTextNode->IsInComposedDoc(), "Should be disconnected already"); if (!aTextNode->MaySetDirAuto()) { diff --git a/dom/base/DirectionalityUtils.h b/dom/base/DirectionalityUtils.h index 0012a1d4be1b..131e11e6bb66 100644 --- a/dom/base/DirectionalityUtils.h +++ b/dom/base/DirectionalityUtils.h @@ -13,11 +13,11 @@ class nsIContent; class nsINode; class nsAttrValue; -class nsTextNode; namespace mozilla::dom { class Element; class HTMLSlotElement; +class Text; struct UnbindContext; } // namespace mozilla::dom @@ -115,27 +115,27 @@ void WalkDescendantsClearAncestorDirAuto(nsIContent* aContent); * * @return whether the text node affects the directionality of any element */ -bool TextNodeWillChangeDirection(nsTextNode* aTextNode, Directionality* aOldDir, +bool TextNodeWillChangeDirection(dom::Text* aTextNode, Directionality* aOldDir, uint32_t aOffset); /** * After the contents of a text node have changed, change the directionality * of any elements whose directionality is determined by that node */ -void TextNodeChangedDirection(nsTextNode* aTextNode, Directionality aOldDir, +void TextNodeChangedDirection(dom::Text* aTextNode, Directionality aOldDir, bool aNotify); /** * When a text node is appended to an element, find any ancestors with dir=auto * whose directionality will be determined by the text node */ -void SetDirectionFromNewTextNode(nsTextNode* aTextNode); +void SetDirectionFromNewTextNode(dom::Text* aTextNode); /** * When a text node is removed from a document, find any ancestors whose * directionality it determined and redetermine their directionality */ -void ResetDirectionSetByTextNode(nsTextNode*, dom::UnbindContext&); +void ResetDirectionSetByTextNode(dom::Text*, dom::UnbindContext&); /** * Set the directionality of an element according to the directionality of the diff --git a/dom/base/Text.cpp b/dom/base/Text.cpp index a6cc317d4dca..7b93cc335ad2 100644 --- a/dom/base/Text.cpp +++ b/dom/base/Text.cpp @@ -124,6 +124,20 @@ already_AddRefed Text::Constructor(const GlobalObject& aGlobal, return window->GetDoc()->CreateTextNode(aData); } +nsresult Text::BindToTree(BindContext& aContext, nsINode& aParent) { + nsresult rv = CharacterData::BindToTree(aContext, aParent); + NS_ENSURE_SUCCESS(rv, rv); + + SetDirectionFromNewTextNode(this); + + return NS_OK; +} + +void Text::UnbindFromTree(UnbindContext& aContext) { + CharacterData::UnbindFromTree(aContext); + ResetDirectionSetByTextNode(this, aContext); +} + bool Text::HasTextForTranslation() { if (mText.Is2b()) { // The fragment contains non-8bit characters which means there diff --git a/dom/base/Text.h b/dom/base/Text.h index a221014203fd..9f69b47091bc 100644 --- a/dom/base/Text.h +++ b/dom/base/Text.h @@ -29,6 +29,9 @@ class Text : public CharacterData { const nsAString& aData, ErrorResult& aRv); + nsresult BindToTree(BindContext&, nsINode& aParent) override; + void UnbindFromTree(UnbindContext&) override; + /** * Method to see if the text node contains data that is useful * for a translation: i.e., it consists of more than just whitespace, diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h index 6f980f472aef..ecc032af3f4f 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -2071,16 +2071,15 @@ class nsINode : public mozilla::dom::EventTarget { void ClearHasValidDir() { ClearBoolFlag(NodeHasValidDirAttribute); } bool HasValidDir() const { return GetBoolFlag(NodeHasValidDirAttribute); } void SetMaySetDirAuto() { - // FIXME(bug 1881225): dir=auto should probably work on CDATA too. - MOZ_ASSERT(NodeType() == TEXT_NODE); + MOZ_ASSERT(IsText()); SetBoolFlag(NodeMaySetDirAuto); } bool MaySetDirAuto() const { - MOZ_ASSERT(NodeType() == TEXT_NODE); + MOZ_ASSERT(IsText()); return GetBoolFlag(NodeMaySetDirAuto); } void ClearMaySetDirAuto() { - MOZ_ASSERT(NodeType() == TEXT_NODE); + MOZ_ASSERT(IsText()); ClearBoolFlag(NodeMaySetDirAuto); } void SetAncestorHasDirAuto() { SetBoolFlag(NodeAncestorHasDirAuto); } diff --git a/dom/base/nsTextNode.cpp b/dom/base/nsTextNode.cpp index e34b581c402b..dd5796ed4cce 100644 --- a/dom/base/nsTextNode.cpp +++ b/dom/base/nsTextNode.cpp @@ -11,7 +11,6 @@ #include "nsTextNode.h" #include "mozilla/dom/TextBinding.h" #include "nsContentUtils.h" -#include "mozilla/dom/DirectionalityUtils.h" #include "mozilla/dom/Document.h" #include "nsThreadUtils.h" #include "nsStubMutationObserver.h" @@ -114,20 +113,6 @@ nsresult nsTextNode::AppendTextForNormalize(const char16_t* aBuffer, &details); } -nsresult nsTextNode::BindToTree(BindContext& aContext, nsINode& aParent) { - nsresult rv = CharacterData::BindToTree(aContext, aParent); - NS_ENSURE_SUCCESS(rv, rv); - - SetDirectionFromNewTextNode(this); - - return NS_OK; -} - -void nsTextNode::UnbindFromTree(UnbindContext& aContext) { - CharacterData::UnbindFromTree(aContext); - ResetDirectionSetByTextNode(this, aContext); -} - #ifdef MOZ_DOM_LIST void nsTextNode::List(FILE* out, int32_t aIndent) const { int32_t index; diff --git a/dom/base/nsTextNode.h b/dom/base/nsTextNode.h index b39497a3b1f4..a162e0fed1f3 100644 --- a/dom/base/nsTextNode.h +++ b/dom/base/nsTextNode.h @@ -44,9 +44,6 @@ class nsTextNode : public mozilla::dom::Text { already_AddRefed CloneDataNode( mozilla::dom::NodeInfo* aNodeInfo, bool aCloneText) const override; - nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(UnbindContext&) override; - nsresult AppendTextForNormalize(const char16_t* aBuffer, uint32_t aLength, bool aNotify, nsIContent* aNextSibling); diff --git a/testing/web-platform/tests/html/dom/elements/global-attributes/cdata-dir_auto.html b/testing/web-platform/tests/html/dom/elements/global-attributes/cdata-dir_auto.html new file mode 100644 index 000000000000..91231f7e6c6e --- /dev/null +++ b/testing/web-platform/tests/html/dom/elements/global-attributes/cdata-dir_auto.html @@ -0,0 +1,71 @@ + + + + + + + + + +
+ اختبر +
+ + + + + + diff --git a/testing/web-platform/tests/html/dom/elements/global-attributes/cdata-iframe.xhtml b/testing/web-platform/tests/html/dom/elements/global-attributes/cdata-iframe.xhtml new file mode 100644 index 000000000000..0c48cbef4fc3 --- /dev/null +++ b/testing/web-platform/tests/html/dom/elements/global-attributes/cdata-iframe.xhtml @@ -0,0 +1,32 @@ + + + +
+ + + +