diff --git a/editor/libeditor/HTMLEditUtils.h b/editor/libeditor/HTMLEditUtils.h index d10a481d5851..46e1c1c91bbb 100644 --- a/editor/libeditor/HTMLEditUtils.h +++ b/editor/libeditor/HTMLEditUtils.h @@ -568,12 +568,25 @@ class HTMLEditUtils final { // If there is a non-editable element if and only if scanning from editable // node, return it too. LeafNodeOrNonEditableNode, + // Ignore non-editable content at walking the tree. + OnlyEditableLeafNode, }; using LeafNodeTypes = EnumSet; - static nsIContent* GetLastLeafContent(nsINode& aNode, - const LeafNodeTypes& aLeafNodeTypes) { - for (nsIContent* content = aNode.GetLastChild(); content; - content = content->GetLastChild()) { + static nsIContent* GetLastLeafContent( + nsINode& aNode, const LeafNodeTypes& aLeafNodeTypes, + const Element* aAncestorLimiter = nullptr) { + MOZ_ASSERT_IF( + aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode), + !aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode)); + for (nsIContent* content = aNode.GetLastChild(); content;) { + if (aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode) && + !EditorUtils::IsEditableContent(*content, + EditorUtils::EditorType::HTML)) { + content = HTMLEditUtils::GetPreviousContent( + *content, {WalkTreeOption::IgnoreNonEditableNode}, + aAncestorLimiter); + continue; + } if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrChildBlock) && HTMLEditUtils::IsBlockElement(*content)) { return content; @@ -585,6 +598,7 @@ class HTMLEditUtils final { aNode.IsEditable() && !content->IsEditable()) { return content; } + content = content->GetLastChild(); } return nullptr; } @@ -594,10 +608,21 @@ class HTMLEditUtils final { * on aLeafNodeTypes whether this scans into a block child or treat block as a * leaf. */ - static nsIContent* GetFirstLeafContent(const nsINode& aNode, - const LeafNodeTypes& aLeafNodeTypes) { - for (nsIContent* content = aNode.GetFirstChild(); content; - content = content->GetFirstChild()) { + static nsIContent* GetFirstLeafContent( + const nsINode& aNode, const LeafNodeTypes& aLeafNodeTypes, + const Element* aAncestorLimiter = nullptr) { + MOZ_ASSERT_IF( + aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode), + !aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode)); + for (nsIContent* content = aNode.GetFirstChild(); content;) { + if (aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode) && + !EditorUtils::IsEditableContent(*content, + EditorUtils::EditorType::HTML)) { + content = HTMLEditUtils::GetNextContent( + *content, {WalkTreeOption::IgnoreNonEditableNode}, + aAncestorLimiter); + continue; + } if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrChildBlock) && HTMLEditUtils::IsBlockElement(*content)) { return content; @@ -609,6 +634,7 @@ class HTMLEditUtils final { aNode.IsEditable() && !content->IsEditable()) { return content; } + content = content->GetFirstChild(); } return nullptr; } @@ -632,6 +658,10 @@ class HTMLEditUtils final { const nsIContent& aStartContent, const nsIContent& aCurrentBlock, const LeafNodeTypes& aLeafNodeTypes, const Element* aAncestorLimiter = nullptr) { + MOZ_ASSERT_IF( + aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode), + !aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode)); + if (&aStartContent == aAncestorLimiter) { return nullptr; } @@ -691,6 +721,11 @@ class HTMLEditUtils final { const nsIContent& aCurrentBlock, const LeafNodeTypes& aLeafNodeTypes, const Element* aAncestorLimiter = nullptr) { MOZ_ASSERT(aStartPoint.IsSet()); + MOZ_ASSERT_IF( + aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode), + !aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode)); + NS_ASSERTION(!aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode), + "Not implemented yet"); if (!aStartPoint.IsInContentNode()) { return nullptr; @@ -759,6 +794,12 @@ class HTMLEditUtils final { const nsIContent& aStartContent, const nsIContent& aCurrentBlock, const LeafNodeTypes& aLeafNodeTypes, const Element* aAncestorLimiter = nullptr) { + MOZ_ASSERT_IF( + aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode), + !aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode)); + NS_ASSERTION(!aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode), + "Not implemented yet"); + if (&aStartContent == aAncestorLimiter) { return nullptr; } @@ -818,6 +859,11 @@ class HTMLEditUtils final { const nsIContent& aCurrentBlock, const LeafNodeTypes& aLeafNodeTypes, const Element* aAncestorLimiter = nullptr) { MOZ_ASSERT(aStartPoint.IsSet()); + MOZ_ASSERT_IF( + aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode), + !aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode)); + NS_ASSERTION(!aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode), + "Not implemented yet"); if (!aStartPoint.IsInContentNode()) { return nullptr; diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index c7a6c8c244e6..9245065ab9ff 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -4932,42 +4932,6 @@ nsresult HTMLEditor::DeleteSelectionAndPrepareToCreateNode() { return error.StealNSResult(); } -nsIContent* HTMLEditor::GetFirstEditableLeaf(nsINode& aNode) const { - Element* editingHost = GetActiveEditingHost(); - if (NS_WARN_IF(!editingHost) || - editingHost->IsInclusiveDescendantOf(&aNode)) { - return nullptr; - } - nsIContent* child = - HTMLEditUtils::GetFirstLeafContent(aNode, {LeafNodeType::OnlyLeafNode}); - while (child && (!EditorUtils::IsEditableContent(*child, EditorType::HTML) || - child->HasChildren())) { - child = HTMLEditUtils::GetNextContent( - *child, {WalkTreeOption::IgnoreNonEditableNode}, - aNode.IsElement() ? aNode.AsElement() : editingHost); - } - - return child; -} - -nsIContent* HTMLEditor::GetLastEditableLeaf(nsINode& aNode) const { - Element* editingHost = GetActiveEditingHost(); - if (NS_WARN_IF(!editingHost) || - editingHost->IsInclusiveDescendantOf(&aNode)) { - return nullptr; - } - nsIContent* child = - HTMLEditUtils::GetLastLeafContent(aNode, {LeafNodeType::OnlyLeafNode}); - while (child && (!EditorUtils::IsEditableContent(*child, EditorType::HTML) || - child->HasChildren())) { - child = HTMLEditUtils::GetPreviousContent( - *child, {WalkTreeOption::IgnoreNonEditableNode}, - aNode.IsElement() ? aNode.AsElement() : editingHost); - } - - return child; -} - bool HTMLEditor::IsEmpty() const { if (mPaddingBRElementForEmptyEditor) { return true; diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h index c80d9d5cde8b..e383a81cc78f 100644 --- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -917,9 +917,6 @@ class HTMLEditor final : public TextEditor, SplitAncestorStyledInlineElementsAt(const EditorDOMPoint& aPointToSplit, nsAtom* aProperty, nsAtom* aAttribute); - nsIContent* GetFirstEditableLeaf(nsINode& aNode) const; - nsIContent* GetLastEditableLeaf(nsINode& aNode) const; - [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult GetInlinePropertyBase( nsAtom& aHTMLProperty, nsAtom* aAttribute, const nsAString* aValue, bool* aFirst, bool* aAny, bool* aAll, nsAString* outValue) const; diff --git a/editor/libeditor/HTMLEditorDataTransfer.cpp b/editor/libeditor/HTMLEditorDataTransfer.cpp index a79c62ce998e..1dc922c9381f 100644 --- a/editor/libeditor/HTMLEditorDataTransfer.cpp +++ b/editor/libeditor/HTMLEditorDataTransfer.cpp @@ -82,6 +82,7 @@ class nsISupports; namespace mozilla { using namespace dom; +using LeafNodeType = HTMLEditUtils::LeafNodeType; #define kInsertCookie "_moz_Insert Here_moz_" @@ -353,8 +354,9 @@ HTMLEditor::HTMLWithContextInserter::GetNewCaretPointAfterInsertingHTML( // but don't cross tables nsIContent* containerContent = nullptr; if (!HTMLEditUtils::IsTable(aLastInsertedPoint.GetChild())) { - containerContent = - mHTMLEditor.GetLastEditableLeaf(*aLastInsertedPoint.GetChild()); + containerContent = HTMLEditUtils::GetLastLeafContent( + *aLastInsertedPoint.GetChild(), {LeafNodeType::OnlyEditableLeafNode}, + aLastInsertedPoint.GetChild()->GetAsElementOrParentElement()); if (containerContent) { Element* mostDistantInclusiveAncestorTableElement = nullptr; for (Element* maybeTableElement = diff --git a/editor/libeditor/HTMLEditorDeleteHandler.cpp b/editor/libeditor/HTMLEditorDeleteHandler.cpp index 5f9cb6809be8..80131656fdb2 100644 --- a/editor/libeditor/HTMLEditorDeleteHandler.cpp +++ b/editor/libeditor/HTMLEditorDeleteHandler.cpp @@ -48,6 +48,7 @@ namespace mozilla { using namespace dom; using EmptyCheckOption = HTMLEditUtils::EmptyCheckOption; using InvisibleWhiteSpaces = HTMLEditUtils::InvisibleWhiteSpaces; +using LeafNodeType = HTMLEditUtils::LeafNodeType; using StyleDifference = HTMLEditUtils::StyleDifference; using TableBoundary = HTMLEditUtils::TableBoundary; using WalkTreeOption = HTMLEditUtils::WalkTreeOption; @@ -2434,13 +2435,15 @@ bool HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner:: // First find the adjacent node in the block if (aDirectionAndAmount == nsIEditor::ePrevious) { - mLeafContentInOtherBlock = - aHTMLEditor.GetLastEditableLeaf(aOtherBlockElement); + mLeafContentInOtherBlock = HTMLEditUtils::GetLastLeafContent( + aOtherBlockElement, {LeafNodeType::OnlyEditableLeafNode}, + &aOtherBlockElement); mLeftContent = mLeafContentInOtherBlock; mRightContent = aCaretPoint.GetContainerAsContent(); } else { - mLeafContentInOtherBlock = - aHTMLEditor.GetFirstEditableLeaf(aOtherBlockElement); + mLeafContentInOtherBlock = HTMLEditUtils::GetFirstLeafContent( + aOtherBlockElement, {LeafNodeType::OnlyEditableLeafNode}, + &aOtherBlockElement); mLeftContent = aCaretPoint.GetContainerAsContent(); mRightContent = mLeafContentInOtherBlock; }