Bug 1677566 - part 2: Make `HTMLEditUtils` treat a found non-editable element as a leaf node even if it has children r=m_kato

Blink treats each non-editable node as an atomic object.  E.g., deleting or
forward-deleting from next to a non-editable element, it deletes only one
non-editable element.

Unfortunately, our layout treat adjacent non-editable nodes as a node.
Therefore, the adding WPTs do not work, but they are not new regression of
this patch.

Differential Revision: https://phabricator.services.mozilla.com/D107587
This commit is contained in:
Masayuki Nakano 2021-03-09 23:57:54 +00:00
Родитель e659ab60ed
Коммит 1229430221
12 изменённых файлов: 139 добавлений и 70 удалений

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

@ -126,7 +126,8 @@ namespace mozilla {
using namespace dom;
using namespace widget;
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
using LeafNodeType = HTMLEditUtils::LeafNodeType;
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
/*****************************************************************************
* mozilla::EditorBase
@ -2585,7 +2586,7 @@ nsINode* EditorBase::GetFirstEditableNode(nsINode* aRoot) {
EditorType editorType = GetEditorType();
nsIContent* content =
HTMLEditUtils::GetFirstLeafChild(*aRoot, ChildBlockBoundary::TreatAsLeaf);
HTMLEditUtils::GetFirstLeafChild(*aRoot, {LeafNodeType::OnlyLeafNode});
if (content && !EditorUtils::IsEditableContent(*content, editorType)) {
content = GetNextEditableNode(*content);
}
@ -2830,8 +2831,9 @@ nsIContent* EditorBase::GetPreviousNodeInternal(const EditorRawDOMPoint& aPoint,
// unless there isn't one, in which case we are at the end of the node
// and want the deep-right child.
nsIContent* lastLeafContent = HTMLEditUtils::GetLastLeafChild(
*aPoint.GetContainer(), aNoBlockCrossing ? ChildBlockBoundary::TreatAsLeaf
: ChildBlockBoundary::Ignore);
*aPoint.GetContainer(),
{aNoBlockCrossing ? LeafNodeType::LeafNodeOrChildBlock
: LeafNodeType::OnlyLeafNode});
if (!lastLeafContent) {
return nullptr;
}
@ -2884,8 +2886,9 @@ nsIContent* EditorBase::GetNextNodeInternal(const EditorRawDOMPoint& aPoint,
}
nsIContent* firstLeafContent = HTMLEditUtils::GetFirstLeafChild(
*point.GetChild(), aNoBlockCrossing ? ChildBlockBoundary::TreatAsLeaf
: ChildBlockBoundary::Ignore);
*point.GetChild(),
{aNoBlockCrossing ? LeafNodeType::LeafNodeOrChildBlock
: LeafNodeType::OnlyLeafNode});
if (!firstLeafContent) {
return point.GetChild();
}
@ -2936,13 +2939,12 @@ nsIContent* EditorBase::FindNextLeafNode(const nsINode* aCurrentNode,
// don't look inside prevsib, since it is a block
return sibling;
}
ChildBlockBoundary childBlockBoundary =
bNoBlockCrossing ? ChildBlockBoundary::TreatAsLeaf
: ChildBlockBoundary::Ignore;
const LeafNodeTypes leafNodeTypes = {
bNoBlockCrossing ? LeafNodeType::LeafNodeOrChildBlock
: LeafNodeType::OnlyLeafNode};
nsIContent* leafContent =
aGoForward
? HTMLEditUtils::GetFirstLeafChild(*sibling, childBlockBoundary)
: HTMLEditUtils::GetLastLeafChild(*sibling, childBlockBoundary);
aGoForward ? HTMLEditUtils::GetFirstLeafChild(*sibling, leafNodeTypes)
: HTMLEditUtils::GetLastLeafChild(*sibling, leafNodeTypes);
return leafContent ? leafContent : sibling;
}

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

@ -71,7 +71,8 @@ class nsISupports;
namespace mozilla {
using namespace dom;
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
using LeafNodeType = HTMLEditUtils::LeafNodeType;
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
using StyleDifference = HTMLEditUtils::StyleDifference;
/********************************************************
@ -2195,7 +2196,8 @@ HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces(
// Try to put caret next to immediately after previous editable leaf.
nsIContent* previousContent =
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
newCaretPosition, *currentBlock, editingHost);
newCaretPosition, *currentBlock,
{LeafNodeType::LeafNodeOrNonEditableNode}, editingHost);
if (previousContent && !HTMLEditUtils::IsBlockElement(*previousContent)) {
newCaretPosition =
previousContent->IsText() ||
@ -2207,7 +2209,9 @@ HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces(
// a child block, look for next editable leaf instead.
else if (nsIContent* nextContent =
HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
newCaretPosition, *currentBlock, editingHost)) {
newCaretPosition, *currentBlock,
{LeafNodeType::LeafNodeOrNonEditableNode},
editingHost)) {
newCaretPosition = nextContent->IsText() ||
HTMLEditUtils::IsContainerNode(*nextContent)
? EditorDOMPoint(nextContent, 0)
@ -5344,7 +5348,7 @@ nsresult HTMLEditor::MaybeExtendSelectionToHardLineEdgesForBlockEditAction() {
// endpoint is just after the close of a block.
nsIContent* child = HTMLEditUtils::GetLastLeafChild(
*wsScannerAtEnd.StartReasonOtherBlockElementPtr(),
ChildBlockBoundary::TreatAsLeaf);
{LeafNodeType::LeafNodeOrChildBlock});
if (child) {
newEndPoint.SetAfter(child);
}
@ -5378,7 +5382,7 @@ nsresult HTMLEditor::MaybeExtendSelectionToHardLineEdgesForBlockEditAction() {
// startpoint is just before the start of a block.
nsINode* child = HTMLEditUtils::GetFirstLeafChild(
*wsScannerAtStart.EndReasonOtherBlockElementPtr(),
ChildBlockBoundary::TreatAsLeaf);
{LeafNodeType::LeafNodeOrChildBlock});
if (child) {
newStartPoint.Set(child);
}
@ -6766,7 +6770,7 @@ nsresult HTMLEditor::SplitParagraph(
// selection to beginning of right hand para;
// look inside any containers that are up front.
nsCOMPtr<nsIContent> child = HTMLEditUtils::GetFirstLeafChild(
aParentDivOrP, ChildBlockBoundary::TreatAsLeaf);
aParentDivOrP, {LeafNodeType::LeafNodeOrChildBlock});
if (child && (child->IsText() || HTMLEditUtils::IsContainerNode(*child))) {
nsresult rv = CollapseSelectionToStartOf(*child);
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {

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

@ -9,6 +9,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/EditorDOMPoint.h"
#include "mozilla/EditorUtils.h"
#include "mozilla/EnumSet.h"
#include "mozilla/Maybe.h"
#include "mozilla/dom/AbstractRange.h"
#include "mozilla/dom/AncestorIterator.h"
@ -307,46 +308,58 @@ class HTMLEditUtils final {
/**
* GetLastLeafChild() returns rightmost leaf content in aNode. It depends on
* aChildBlockBoundary whether this scans into a block child or treat
* block as a leaf.
* aLeafNodeTypes whether this which types of nodes are treated as leaf nodes.
*/
enum class ChildBlockBoundary {
enum class LeafNodeType {
// Even if there is a child block, keep scanning a leaf content in it.
Ignore,
// If there is a child block, return it.
TreatAsLeaf,
OnlyLeafNode,
// If there is a child block, return it too. Note that this does not
// mean that block siblings are not treated as leaf nodes.
LeafNodeOrChildBlock,
// If there is a non-editable element if and only if scanning from editable
// node, return it too.
LeafNodeOrNonEditableNode,
};
using LeafNodeTypes = EnumSet<LeafNodeType>;
static nsIContent* GetLastLeafChild(nsINode& aNode,
ChildBlockBoundary aChildBlockBoundary) {
const LeafNodeTypes& aLeafNodeTypes) {
for (nsIContent* content = aNode.GetLastChild(); content;
content = content->GetLastChild()) {
if (aChildBlockBoundary == ChildBlockBoundary::TreatAsLeaf &&
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrChildBlock) &&
HTMLEditUtils::IsBlockElement(*content)) {
return content;
}
if (!content->HasChildren()) {
return content;
}
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
aNode.IsEditable() && !content->IsEditable()) {
return content;
}
}
return nullptr;
}
/**
* GetFirstLeafChild() returns leftmost leaf content in aNode. It depends on
* aChildBlockBoundary whether this scans into a block child or treat
* aLeafNodeTypes whether this scans into a block child or treat
* block as a leaf.
*/
static nsIContent* GetFirstLeafChild(nsINode& aNode,
ChildBlockBoundary aChildBlockBoundary) {
const LeafNodeTypes& aLeafNodeTypes) {
for (nsIContent* content = aNode.GetFirstChild(); content;
content = content->GetFirstChild()) {
if (aChildBlockBoundary == ChildBlockBoundary::TreatAsLeaf &&
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrChildBlock) &&
HTMLEditUtils::IsBlockElement(*content)) {
return content;
}
if (!content->HasChildren()) {
return content;
}
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
aNode.IsEditable() && !content->IsEditable()) {
return content;
}
}
return nullptr;
}
@ -361,12 +374,14 @@ class HTMLEditUtils final {
* @param aCurrentBlock Must be ancestor of aStartContent. Dispite
* the name, inline content is allowed if
* aStartContent is in an inline editing host.
* @param aLeafNodeTypes See LeafNodeType.
* @param aAncestorLimiter Optional, setting this guarantees the
* result is in aAncestorLimiter unless
* aStartContent is not a descendant of this.
*/
static nsIContent* GetNextLeafContentOrNextBlockElement(
const nsIContent& aStartContent, const nsIContent& aCurrentBlock,
const LeafNodeTypes& aLeafNodeTypes,
const Element* aAncestorLimiter = nullptr) {
if (&aStartContent == aAncestorLimiter) {
return nullptr;
@ -402,10 +417,14 @@ class HTMLEditUtils final {
if (HTMLEditUtils::IsBlockElement(*nextContent)) {
return nextContent;
}
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
aStartContent.IsEditable() && !nextContent->IsEditable()) {
return nextContent;
}
if (HTMLEditUtils::IsContainerNode(*nextContent)) {
// Else if it's a container, get deep leftmost child
if (nsIContent* child = HTMLEditUtils::GetFirstLeafChild(
*nextContent, ChildBlockBoundary::Ignore)) {
if (nsIContent* child =
HTMLEditUtils::GetFirstLeafChild(*nextContent, aLeafNodeTypes)) {
return child;
}
}
@ -420,7 +439,7 @@ class HTMLEditUtils final {
template <typename PT, typename CT>
static nsIContent* GetNextLeafContentOrNextBlockElement(
const EditorDOMPointBase<PT, CT>& aStartPoint,
const nsIContent& aCurrentBlock,
const nsIContent& aCurrentBlock, const LeafNodeTypes& aLeafNodeTypes,
const Element* aAncestorLimiter = nullptr) {
MOZ_ASSERT(aStartPoint.IsSet());
@ -429,11 +448,13 @@ class HTMLEditUtils final {
}
if (aStartPoint.IsInTextNode()) {
return HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
*aStartPoint.ContainerAsText(), aCurrentBlock, aAncestorLimiter);
*aStartPoint.ContainerAsText(), aCurrentBlock, aLeafNodeTypes,
aAncestorLimiter);
}
if (!HTMLEditUtils::IsContainerNode(*aStartPoint.ContainerAsContent())) {
return HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
*aStartPoint.ContainerAsContent(), aCurrentBlock, aAncestorLimiter);
*aStartPoint.ContainerAsContent(), aCurrentBlock, aLeafNodeTypes,
aAncestorLimiter);
}
nsCOMPtr<nsIContent> nextContent = aStartPoint.GetChild();
@ -445,17 +466,23 @@ class HTMLEditUtils final {
// We are at end of non-block container
return HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
*aStartPoint.ContainerAsContent(), aCurrentBlock, aAncestorLimiter);
*aStartPoint.ContainerAsContent(), aCurrentBlock, aLeafNodeTypes,
aAncestorLimiter);
}
// We have a next node. If it's a block, return it.
if (HTMLEditUtils::IsBlockElement(*nextContent)) {
return nextContent;
}
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
aStartPoint.GetContainer()->IsEditable() &&
!nextContent->IsEditable()) {
return nextContent;
}
if (HTMLEditUtils::IsContainerNode(*nextContent)) {
// else if it's a container, get deep leftmost child
if (nsIContent* child = HTMLEditUtils::GetFirstLeafChild(
*nextContent, ChildBlockBoundary::Ignore)) {
if (nsIContent* child =
HTMLEditUtils::GetFirstLeafChild(*nextContent, aLeafNodeTypes)) {
return child;
}
}
@ -474,12 +501,14 @@ class HTMLEditUtils final {
* @param aCurrentBlock Must be ancestor of aStartContent. Dispite
* the name, inline content is allowed if
* aStartContent is in an inline editing host.
* @param aLeafNodeTypes See LeafNodeType.
* @param aAncestorLimiter Optional, setting this guarantees the
* result is in aAncestorLimiter unless
* aStartContent is not a descendant of this.
*/
static nsIContent* GetPreviousLeafContentOrPreviousBlockElement(
const nsIContent& aStartContent, const nsIContent& aCurrentBlock,
const LeafNodeTypes& aLeafNodeTypes,
const Element* aAncestorLimiter = nullptr) {
if (&aStartContent == aAncestorLimiter) {
return nullptr;
@ -515,10 +544,14 @@ class HTMLEditUtils final {
if (HTMLEditUtils::IsBlockElement(*previousContent)) {
return previousContent;
}
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
aStartContent.IsEditable() && !previousContent->IsEditable()) {
return previousContent;
}
if (HTMLEditUtils::IsContainerNode(*previousContent)) {
// Else if it's a container, get deep rightmost child
if (nsIContent* child = HTMLEditUtils::GetLastLeafChild(
*previousContent, ChildBlockBoundary::Ignore)) {
if (nsIContent* child = HTMLEditUtils::GetLastLeafChild(*previousContent,
aLeafNodeTypes)) {
return child;
}
}
@ -533,7 +566,7 @@ class HTMLEditUtils final {
template <typename PT, typename CT>
static nsIContent* GetPreviousLeafContentOrPreviousBlockElement(
const EditorDOMPointBase<PT, CT>& aStartPoint,
const nsIContent& aCurrentBlock,
const nsIContent& aCurrentBlock, const LeafNodeTypes& aLeafNodeTypes,
const Element* aAncestorLimiter = nullptr) {
MOZ_ASSERT(aStartPoint.IsSet());
@ -542,11 +575,13 @@ class HTMLEditUtils final {
}
if (aStartPoint.IsInTextNode()) {
return HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*aStartPoint.ContainerAsText(), aCurrentBlock, aAncestorLimiter);
*aStartPoint.ContainerAsText(), aCurrentBlock, aLeafNodeTypes,
aAncestorLimiter);
}
if (!HTMLEditUtils::IsContainerNode(*aStartPoint.ContainerAsContent())) {
return HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*aStartPoint.ContainerAsContent(), aCurrentBlock, aAncestorLimiter);
*aStartPoint.ContainerAsContent(), aCurrentBlock, aLeafNodeTypes,
aAncestorLimiter);
}
if (aStartPoint.IsStartOfContainer()) {
@ -557,7 +592,8 @@ class HTMLEditUtils final {
// We are at start of non-block container
return HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*aStartPoint.ContainerAsContent(), aCurrentBlock, aAncestorLimiter);
*aStartPoint.ContainerAsContent(), aCurrentBlock, aLeafNodeTypes,
aAncestorLimiter);
}
nsCOMPtr<nsIContent> previousContent =
@ -570,10 +606,15 @@ class HTMLEditUtils final {
if (HTMLEditUtils::IsBlockElement(*previousContent)) {
return previousContent;
}
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
aStartPoint.GetContainer()->IsEditable() &&
!previousContent->IsEditable()) {
return previousContent;
}
if (HTMLEditUtils::IsContainerNode(*previousContent)) {
// Else if it's a container, get deep rightmost child
if (nsIContent* child = HTMLEditUtils::GetLastLeafChild(
*previousContent, ChildBlockBoundary::Ignore)) {
if (nsIContent* child = HTMLEditUtils::GetLastLeafChild(*previousContent,
aLeafNodeTypes)) {
return child;
}
}

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

@ -69,7 +69,8 @@ namespace mozilla {
using namespace dom;
using namespace widget;
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
using LeafNodeType = HTMLEditUtils::LeafNodeType;
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
const char16_t kNBSP = 160;
@ -2856,7 +2857,7 @@ already_AddRefed<Element> HTMLEditor::GetSelectedElement(const nsAtom* aTagName,
return nullptr;
}
nsIContent* firstEditableLeaf = HTMLEditUtils::GetFirstLeafChild(
*nextSibling, ChildBlockBoundary::Ignore);
*nextSibling, {LeafNodeType::OnlyLeafNode});
if (firstEditableLeaf &&
firstEditableLeaf->IsHTMLElement(nsGkAtoms::br)) {
return nullptr;
@ -5116,7 +5117,7 @@ nsIContent* HTMLEditor::GetLastEditableChild(nsINode& aNode) const {
nsIContent* HTMLEditor::GetFirstEditableLeaf(nsINode& aNode) const {
nsIContent* child =
HTMLEditUtils::GetFirstLeafChild(aNode, ChildBlockBoundary::Ignore);
HTMLEditUtils::GetFirstLeafChild(aNode, {LeafNodeType::OnlyLeafNode});
while (child && (!EditorUtils::IsEditableContent(*child, EditorType::HTML) ||
child->HasChildren())) {
child = GetNextEditableHTMLNode(*child);
@ -5132,7 +5133,7 @@ nsIContent* HTMLEditor::GetFirstEditableLeaf(nsINode& aNode) const {
nsIContent* HTMLEditor::GetLastEditableLeaf(nsINode& aNode) const {
nsIContent* child =
HTMLEditUtils::GetLastLeafChild(aNode, ChildBlockBoundary::Ignore);
HTMLEditUtils::GetLastLeafChild(aNode, {LeafNodeType::OnlyLeafNode});
while (child && (!EditorUtils::IsEditableContent(*child, EditorType::HTML) ||
child->HasChildren())) {
child = GetPreviousEditableHTMLNode(*child);

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

@ -47,7 +47,8 @@ namespace mozilla {
using namespace dom;
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
using LeafNodeType = HTMLEditUtils::LeafNodeType;
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
nsresult HTMLEditor::SetInlinePropertyAsAction(nsAtom& aProperty,
nsAtom* aAttribute,
@ -991,7 +992,7 @@ EditResult HTMLEditor::ClearStyleAt(const EditorDOMPoint& aPoint,
// `<p><b><i>a</i></b><b><i></i></b><b><i>bc</i></b></p>`.
// ^^^^^^^^^^^^^^
nsIContent* firstLeafChildOfNextNode = HTMLEditUtils::GetFirstLeafChild(
*splitResult.GetNextNode(), ChildBlockBoundary::Ignore);
*splitResult.GetNextNode(), {LeafNodeType::OnlyLeafNode});
EditorDOMPoint atStartOfNextNode(firstLeafChildOfNextNode
? firstLeafChildOfNextNode
: splitResult.GetNextNode(),
@ -1050,7 +1051,7 @@ EditResult HTMLEditor::ClearStyleAt(const EditorDOMPoint& aPoint,
// E.g., `<p><b><i>a</i></b><b><i><br></i></b><b><i>bc</i></b></p>`
nsIContent* firstLeafChildOfPreviousNode = HTMLEditUtils::GetFirstLeafChild(
*splitResultAtStartOfNextNode.GetPreviousNode(),
ChildBlockBoundary::Ignore);
{LeafNodeType::OnlyLeafNode});
EditorDOMPoint pointToPutCaret(
firstLeafChildOfPreviousNode
? firstLeafChildOfPreviousNode

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

@ -70,7 +70,8 @@ namespace mozilla {
using namespace dom;
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
using LeafNodeType = HTMLEditUtils::LeafNodeType;
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
TextEditor::TextEditor()
: mMaxTextLength(-1),
@ -1018,7 +1019,7 @@ nsresult TextEditor::UndoAsAction(uint32_t aCount, nsIPrincipal* aPrincipal) {
// and redo are relatively rare, it makes sense to take the (small)
// performance hit here.
nsIContent* firstLeafChild = HTMLEditUtils::GetFirstLeafChild(
*mRootElement, ChildBlockBoundary::Ignore);
*mRootElement, {LeafNodeType::OnlyLeafNode});
if (firstLeafChild &&
EditorUtils::IsPaddingBRElementForEmptyEditor(*firstLeafChild)) {
mPaddingBRElementForEmptyEditor =

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

@ -36,7 +36,8 @@ namespace mozilla {
using namespace dom;
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
using LeafNodeType = HTMLEditUtils::LeafNodeType;
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
const char16_t kNBSP = 160;
@ -1259,6 +1260,12 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
TextFragmentDataAtStartRef().VisibleWhiteSpacesDataRef();
if (visibleWhiteSpaces.IsInitialized() &&
visibleWhiteSpaces.StartRef().IsBefore(aPoint)) {
// If the visible things are not editable, we shouldn't scan "editable"
// things now. Whether keep scanning editable things or not should be
// considered by the caller.
if (aPoint.GetChild() && !aPoint.GetChild()->IsEditable()) {
return WSScanResult(aPoint.GetChild(), WSType::SpecialContent);
}
EditorDOMPointInText atPreviousChar = GetPreviousEditableCharPoint(aPoint);
// When it's a non-empty text node, return it.
if (atPreviousChar.IsSet() && !atPreviousChar.IsContainerEmpty()) {
@ -1297,6 +1304,12 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
TextFragmentDataAtStartRef().VisibleWhiteSpacesDataRef();
if (visibleWhiteSpaces.IsInitialized() &&
aPoint.EqualsOrIsBefore(visibleWhiteSpaces.EndRef())) {
// If the visible things are not editable, we shouldn't scan "editable"
// things now. Whether keep scanning editable things or not should be
// considered by the caller.
if (aPoint.GetChild() && !aPoint.GetChild()->IsEditable()) {
return WSScanResult(aPoint.GetChild(), WSType::SpecialContent);
}
EditorDOMPointInText atNextChar = GetInclusiveNextEditableCharPoint(aPoint);
// When it's a non-empty text node, return it.
if (atNextChar.IsSet() && !atNextChar.IsContainerEmpty()) {
@ -1448,7 +1461,7 @@ WSRunScanner::TextFragmentData::BoundaryData WSRunScanner::TextFragmentData::
nsIContent* previousLeafContentOrBlock =
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
aPoint, aEditableBlockParentOrTopmostEditableInlineContent,
aEditingHost);
{LeafNodeType::LeafNodeOrNonEditableNode}, aEditingHost);
if (!previousLeafContentOrBlock) {
// no prior node means we exhausted
// aEditableBlockParentOrTopmostEditableInlineContent
@ -1580,7 +1593,7 @@ WSRunScanner::TextFragmentData::BoundaryData::ScanCollapsibleWhiteSpaceEndFrom(
nsIContent* nextLeafContentOrBlock =
HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
aPoint, aEditableBlockParentOrTopmostEditableInlineElement,
aEditingHost);
{LeafNodeType::LeafNodeOrNonEditableNode}, aEditingHost);
if (!nextLeafContentOrBlock) {
// no next node means we exhausted
// aEditableBlockParentOrTopmostEditableInlineElement
@ -2280,7 +2293,7 @@ WSRunScanner::TextFragmentData::GetInclusiveNextEditableCharPoint(
aPoint.CanContainerHaveChildren() ? aPoint.GetChild() : nullptr) {
nsIContent* leafContent = child->HasChildren()
? HTMLEditUtils::GetFirstLeafChild(
*child, ChildBlockBoundary::Ignore)
*child, {LeafNodeType::OnlyLeafNode})
: child;
if (NS_WARN_IF(!leafContent)) {
return EditorDOMPointInText();
@ -2326,11 +2339,11 @@ WSRunScanner::TextFragmentData::GetInclusiveNextEditableCharPoint(
HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
*point.ContainerAsContent(),
*editableBlockParentOrTopmostEditableInlineContent,
mEditingHost);
{LeafNodeType::LeafNodeOrNonEditableNode}, mEditingHost);
nextContent;
nextContent = HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
*nextContent, *editableBlockParentOrTopmostEditableInlineContent,
mEditingHost)) {
{LeafNodeType::LeafNodeOrNonEditableNode}, mEditingHost)) {
if (!nextContent->IsText() || !nextContent->IsEditable()) {
if (nextContent == GetEndReasonContent()) {
break; // Reached end of current runs.
@ -2360,7 +2373,7 @@ WSRunScanner::TextFragmentData::GetPreviousEditableCharPoint(
nsIContent* leafContent =
previousChild->HasChildren()
? HTMLEditUtils::GetLastLeafChild(*previousChild,
ChildBlockBoundary::Ignore)
{LeafNodeType::OnlyLeafNode})
: previousChild;
if (NS_WARN_IF(!leafContent)) {
return EditorDOMPointInText();
@ -2407,13 +2420,13 @@ WSRunScanner::TextFragmentData::GetPreviousEditableCharPoint(
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*point.ContainerAsContent(),
*editableBlockParentOrTopmostEditableInlineContent,
mEditingHost);
{LeafNodeType::LeafNodeOrNonEditableNode}, mEditingHost);
previousContent;
previousContent =
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*previousContent,
*editableBlockParentOrTopmostEditableInlineContent,
mEditingHost)) {
{LeafNodeType::LeafNodeOrNonEditableNode}, mEditingHost)) {
if (!previousContent->IsText() || !previousContent->IsEditable()) {
if (previousContent == GetStartReasonContent()) {
break; // Reached start of current runs.

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

@ -700,3 +700,5 @@
[[["delete",""\]\] "foo<div contenteditable=false>bar</div>[\]baz" compare innerHTML]
expected: FAIL
[[["delete",""\]\] "foo<span contenteditable=false>bar</span><span contenteditable=false>baz</span>[\]qux" compare innerHTML]
expected: FAIL

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

@ -613,9 +613,6 @@
[[["forwarddelete",""\]\] "<div>abc[\] </div>" compare innerHTML]
expected: FAIL
[[["forwarddelete",""\]\] "foo[\]<span contenteditable=false><span>b</span><span>a</span><span>r</span></span>baz": execCommand("forwarddelete", false, "") return value]
expected: FAIL
[[["forwarddelete",""\]\] "foo[\]<span contenteditable=false><span>b</span><span>a</span><span>r</span></span>baz" compare innerHTML]
[[["forwarddelete",""\]\] "foo[\]<span contenteditable=false>bar</span><span contenteditable=false>baz</span>qux" compare innerHTML]
expected: FAIL

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

@ -102,6 +102,3 @@
[Delete at "<div>abc <ul><li> def[\] </li></ul> ghi</div>"]
expected: FAIL
[Delete at "<p>abc[\]<span contenteditable=\"false\">def</span>ghi</p>"]
expected: FAIL

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

@ -2565,6 +2565,11 @@ var browserTests = [
"foo{}baz",
[true],
{"delete":[false,false,"",false,false,""]}],
["foo<span contenteditable=false>bar</span><span contenteditable=false>baz</span>[]qux",
[["delete",""]],
"foo<span contenteditable=\"false\">bar</span>[]qux",
[true],
{"delete":[false,false,"",false,false,""]}],
["foo<span contenteditable=false><span>b</span><span>a</span><span>r</span></span>[]baz",
[["delete",""]],
"foo{}baz",

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

@ -2450,6 +2450,11 @@ var browserTests = [
"foo{}baz",
[true],
{"forwarddelete":[false,false,"",false,false,""]}],
["foo[]<span contenteditable=false>bar</span><span contenteditable=false>baz</span>qux",
[["forwarddelete",""]],
"foo[]<span contenteditable=\"false\">baz</span>qux",
[true],
{"forwarddelete":[false,false,"",false,false,""]}],
["foo[]<span contenteditable=false><span>b</span><span>a</span><span>r</span></span>baz",
[["forwarddelete",""]],
"foo{}baz",