зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1627175 - part 15: Create `HTMLEditUtils::GetFirstLeafChild()` instead of `EditorBase::GetLeftmostChild()` r=m_kato
This is used by `TextEditor::UndoAsAction()` too, so, it might be better to be in `EditorUtils`. However, it is completely designed for `HTMLEditor` and ideally, `UndoAsAction` should be overridden by `HTMLEditor` too and `TextEditor` should use faster path because of its content is in anonymous subtree. But we don't have any merit to do that instead of avoiding virtual call. Differential Revision: https://phabricator.services.mozilla.com/D74362
This commit is contained in:
Родитель
8317bb8abb
Коммит
8c859f8589
|
@ -2581,7 +2581,8 @@ nsINode* EditorBase::GetFirstEditableNode(nsINode* aRoot) {
|
|||
MOZ_ASSERT(aRoot);
|
||||
|
||||
EditorType editorType = GetEditorType();
|
||||
nsIContent* content = GetLeftmostChild(aRoot);
|
||||
nsIContent* content =
|
||||
HTMLEditUtils::GetFirstLeafChild(*aRoot, ChildBlockBoundary::TreatAsLeaf);
|
||||
if (content && !EditorUtils::IsEditableContent(*content, editorType)) {
|
||||
content = GetNextEditableNode(*content);
|
||||
}
|
||||
|
@ -2904,24 +2905,25 @@ nsIContent* EditorBase::GetNextNodeInternal(const EditorRawDOMPoint& aPoint,
|
|||
return point.GetChild();
|
||||
}
|
||||
|
||||
nsIContent* leftMostContent =
|
||||
GetLeftmostChild(point.GetChild(), aNoBlockCrossing);
|
||||
if (!leftMostContent) {
|
||||
nsIContent* firstLeafContent = HTMLEditUtils::GetFirstLeafChild(
|
||||
*point.GetChild(), aNoBlockCrossing ? ChildBlockBoundary::TreatAsLeaf
|
||||
: ChildBlockBoundary::Ignore);
|
||||
if (!firstLeafContent) {
|
||||
return point.GetChild();
|
||||
}
|
||||
|
||||
if (!IsDescendantOfEditorRoot(leftMostContent)) {
|
||||
if (!IsDescendantOfEditorRoot(firstLeafContent)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ((!aFindEditableNode ||
|
||||
EditorUtils::IsEditableContent(*leftMostContent, GetEditorType())) &&
|
||||
(aFindAnyDataNode || EditorUtils::IsElementOrText(*leftMostContent))) {
|
||||
return leftMostContent;
|
||||
EditorUtils::IsEditableContent(*firstLeafContent, GetEditorType())) &&
|
||||
(aFindAnyDataNode || EditorUtils::IsElementOrText(*firstLeafContent))) {
|
||||
return firstLeafContent;
|
||||
}
|
||||
|
||||
// restart the search from the non-editable node we just found
|
||||
return GetNextNodeInternal(*leftMostContent, aFindEditableNode,
|
||||
return GetNextNodeInternal(*firstLeafContent, aFindEditableNode,
|
||||
aFindAnyDataNode, aNoBlockCrossing);
|
||||
}
|
||||
|
||||
|
@ -2955,17 +2957,14 @@ nsIContent* EditorBase::FindNextLeafNode(nsINode* aCurrentNode, bool aGoForward,
|
|||
// don't look inside prevsib, since it is a block
|
||||
return sibling;
|
||||
}
|
||||
nsIContent* leaf =
|
||||
ChildBlockBoundary childBlockBoundary =
|
||||
bNoBlockCrossing ? ChildBlockBoundary::TreatAsLeaf
|
||||
: ChildBlockBoundary::Ignore;
|
||||
nsIContent* leafContent =
|
||||
aGoForward
|
||||
? GetLeftmostChild(sibling, bNoBlockCrossing)
|
||||
: HTMLEditUtils::GetLastLeafChild(
|
||||
*sibling, bNoBlockCrossing ? ChildBlockBoundary::TreatAsLeaf
|
||||
: ChildBlockBoundary::Ignore);
|
||||
if (!leaf) {
|
||||
return sibling;
|
||||
}
|
||||
|
||||
return leaf;
|
||||
? HTMLEditUtils::GetFirstLeafChild(*sibling, childBlockBoundary)
|
||||
: HTMLEditUtils::GetLastLeafChild(*sibling, childBlockBoundary);
|
||||
return leafContent ? leafContent : sibling;
|
||||
}
|
||||
|
||||
nsINode* parent = cur->GetParentNode();
|
||||
|
@ -3018,30 +3017,6 @@ nsIContent* EditorBase::FindNode(nsINode* aCurrentNode, bool aGoForward,
|
|||
bNoBlockCrossing);
|
||||
}
|
||||
|
||||
nsIContent* EditorBase::GetLeftmostChild(nsINode* aCurrentNode,
|
||||
bool bNoBlockCrossing) const {
|
||||
if (NS_WARN_IF(!aCurrentNode)) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIContent* content = aCurrentNode->GetFirstChild();
|
||||
if (!content) {
|
||||
return nullptr;
|
||||
}
|
||||
for (;;) {
|
||||
if (bNoBlockCrossing && HTMLEditUtils::IsBlockElement(*content)) {
|
||||
return content;
|
||||
}
|
||||
nsIContent* next = content->GetFirstChild();
|
||||
if (!next) {
|
||||
return content;
|
||||
}
|
||||
content = next;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE("What part of for(;;) do you not understand?");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool EditorBase::IsRoot(nsINode* inNode) const {
|
||||
if (NS_WARN_IF(!inNode)) {
|
||||
return false;
|
||||
|
|
|
@ -1695,13 +1695,6 @@ class EditorBase : public nsIEditor,
|
|||
return GetNextNodeInternal(aNode, true, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the leftmost child of aCurrentNode;
|
||||
* return nullptr if aCurrentNode has no children.
|
||||
*/
|
||||
nsIContent* GetLeftmostChild(nsINode* aCurrentNode,
|
||||
bool bNoBlockCrossing = false) const;
|
||||
|
||||
/**
|
||||
* Returns true if aNode is our root node.
|
||||
*/
|
||||
|
|
|
@ -7859,8 +7859,9 @@ nsresult HTMLEditor::MaybeExtendSelectionToHardLineEdgesForBlockEditAction() {
|
|||
// of going "down" into a block and "up" out of a block.
|
||||
if (wsScannerAtStart.EndsByOtherBlockElement()) {
|
||||
// startpoint is just before the start of a block.
|
||||
nsINode* child = GetLeftmostChild(
|
||||
wsScannerAtStart.EndReasonOtherBlockElementPtr(), true);
|
||||
nsINode* child = HTMLEditUtils::GetFirstLeafChild(
|
||||
*wsScannerAtStart.EndReasonOtherBlockElementPtr(),
|
||||
ChildBlockBoundary::TreatAsLeaf);
|
||||
if (child) {
|
||||
newStartPoint.Set(child);
|
||||
}
|
||||
|
@ -9243,7 +9244,8 @@ nsresult HTMLEditor::SplitParagraph(
|
|||
|
||||
// selection to beginning of right hand para;
|
||||
// look inside any containers that are up front.
|
||||
nsCOMPtr<nsIContent> child = GetLeftmostChild(&aParentDivOrP, true);
|
||||
nsCOMPtr<nsIContent> child = HTMLEditUtils::GetFirstLeafChild(
|
||||
aParentDivOrP, ChildBlockBoundary::TreatAsLeaf);
|
||||
if (child && (child->IsText() || HTMLEditUtils::IsContainerNode(*child))) {
|
||||
nsresult rv = CollapseSelectionToStartOf(*child);
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
|
|
|
@ -220,6 +220,26 @@ class HTMLEditUtils final {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetFirstLeafChild() returns leftmost leaf content in aNode. It depends on
|
||||
* aChildBlockBoundary whether this scans into a block child or treat
|
||||
* block as a leaf.
|
||||
*/
|
||||
static nsIContent* GetFirstLeafChild(nsINode& aNode,
|
||||
ChildBlockBoundary aChildBlockBoundary) {
|
||||
for (nsIContent* content = aNode.GetFirstChild(); content;
|
||||
content = content->GetFirstChild()) {
|
||||
if (aChildBlockBoundary == ChildBlockBoundary::TreatAsLeaf &&
|
||||
HTMLEditUtils::IsBlockElement(*content)) {
|
||||
return content;
|
||||
}
|
||||
if (!content->HasChildren()) {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetAncestorBlockElement() returns parent or nearest ancestor of aContent
|
||||
* which is a block element. If aAncestorLimiter is not nullptr,
|
||||
|
|
|
@ -2745,7 +2745,8 @@ already_AddRefed<Element> HTMLEditor::GetSelectedElement(const nsAtom* aTagName,
|
|||
if (nextSibling->IsHTMLElement(nsGkAtoms::br)) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIContent* firstEditableLeaf = GetLeftmostChild(nextSibling);
|
||||
nsIContent* firstEditableLeaf = HTMLEditUtils::GetFirstLeafChild(
|
||||
*nextSibling, ChildBlockBoundary::Ignore);
|
||||
if (firstEditableLeaf &&
|
||||
firstEditableLeaf->IsHTMLElement(nsGkAtoms::br)) {
|
||||
return nullptr;
|
||||
|
@ -4960,7 +4961,8 @@ nsIContent* HTMLEditor::GetLastEditableChild(nsINode& aNode) const {
|
|||
}
|
||||
|
||||
nsIContent* HTMLEditor::GetFirstEditableLeaf(nsINode& aNode) const {
|
||||
nsIContent* child = GetLeftmostChild(&aNode);
|
||||
nsIContent* child =
|
||||
HTMLEditUtils::GetFirstLeafChild(aNode, ChildBlockBoundary::Ignore);
|
||||
while (child && (!EditorUtils::IsEditableContent(*child, EditorType::HTML) ||
|
||||
child->HasChildren())) {
|
||||
child = GetNextEditableHTMLNode(*child);
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace mozilla {
|
|||
|
||||
using namespace dom;
|
||||
|
||||
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
|
||||
|
||||
nsresult HTMLEditor::SetInlinePropertyAsAction(nsAtom& aProperty,
|
||||
nsAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
|
@ -880,10 +882,10 @@ EditResult HTMLEditor::ClearStyleAt(const EditorDOMPoint& aPoint,
|
|||
// the next node. The first example should become
|
||||
// `<p><b><i>a</i></b><b><i></i></b><b><i>bc</i></b></p>`.
|
||||
// ^^^^^^^^^^^^^^
|
||||
nsIContent* leftmostChildOfNextNode =
|
||||
GetLeftmostChild(splitResult.GetNextNode());
|
||||
EditorDOMPoint atStartOfNextNode(leftmostChildOfNextNode
|
||||
? leftmostChildOfNextNode
|
||||
nsIContent* firstLeafChildOfNextNode = HTMLEditUtils::GetFirstLeafChild(
|
||||
*splitResult.GetNextNode(), ChildBlockBoundary::Ignore);
|
||||
EditorDOMPoint atStartOfNextNode(firstLeafChildOfNextNode
|
||||
? firstLeafChildOfNextNode
|
||||
: splitResult.GetNextNode(),
|
||||
0);
|
||||
RefPtr<HTMLBRElement> brElement;
|
||||
|
@ -938,10 +940,12 @@ EditResult HTMLEditor::ClearStyleAt(const EditorDOMPoint& aPoint,
|
|||
// Now, we want to put `<br>` element into the empty split node if
|
||||
// it was in next node of the first split.
|
||||
// E.g., `<p><b><i>a</i></b><b><i><br></i></b><b><i>bc</i></b></p>`
|
||||
nsIContent* leftmostChild =
|
||||
GetLeftmostChild(splitResultAtStartOfNextNode.GetPreviousNode());
|
||||
nsIContent* firstLeafChildOfPreviousNode = HTMLEditUtils::GetFirstLeafChild(
|
||||
*splitResultAtStartOfNextNode.GetPreviousNode(),
|
||||
ChildBlockBoundary::Ignore);
|
||||
EditorDOMPoint pointToPutCaret(
|
||||
leftmostChild ? leftmostChild
|
||||
firstLeafChildOfPreviousNode
|
||||
? firstLeafChildOfPreviousNode
|
||||
: splitResultAtStartOfNextNode.GetPreviousNode(),
|
||||
0);
|
||||
// If the right node starts with a `<br>`, suck it out of right node and into
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "EditAggregateTransaction.h"
|
||||
#include "HTMLEditUtils.h"
|
||||
#include "InternetCiter.h"
|
||||
#include "PlaceholderTransaction.h"
|
||||
#include "gfxFontUtils.h"
|
||||
|
@ -69,6 +70,8 @@ namespace mozilla {
|
|||
|
||||
using namespace dom;
|
||||
|
||||
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
|
||||
|
||||
TextEditor::TextEditor()
|
||||
: mMaxTextLength(-1),
|
||||
mUnmaskedStart(UINT32_MAX),
|
||||
|
@ -1000,11 +1003,12 @@ nsresult TextEditor::UndoAsAction(uint32_t aCount, nsIPrincipal* aPrincipal) {
|
|||
// at redo, or doing it everywhere else that might care. Since undo
|
||||
// and redo are relatively rare, it makes sense to take the (small)
|
||||
// performance hit here.
|
||||
nsIContent* leftMostChild = GetLeftmostChild(mRootElement);
|
||||
if (leftMostChild &&
|
||||
EditorUtils::IsPaddingBRElementForEmptyEditor(*leftMostChild)) {
|
||||
nsIContent* firstLeafChild = HTMLEditUtils::GetFirstLeafChild(
|
||||
*mRootElement, ChildBlockBoundary::Ignore);
|
||||
if (firstLeafChild &&
|
||||
EditorUtils::IsPaddingBRElementForEmptyEditor(*firstLeafChild)) {
|
||||
mPaddingBRElementForEmptyEditor =
|
||||
static_cast<HTMLBRElement*>(leftMostChild);
|
||||
static_cast<HTMLBRElement*>(firstLeafChild);
|
||||
} else {
|
||||
mPaddingBRElementForEmptyEditor = nullptr;
|
||||
}
|
||||
|
|
|
@ -1238,8 +1238,8 @@ nsIContent* WSRunScanner::GetNextWSNodeInner(nsINode* aStartNode,
|
|||
}
|
||||
if (HTMLEditUtils::IsContainerNode(*nextContent)) {
|
||||
// Else if it's a container, get deep leftmost child
|
||||
nsCOMPtr<nsIContent> child = mHTMLEditor->GetLeftmostChild(nextContent);
|
||||
if (child) {
|
||||
if (nsIContent* child = HTMLEditUtils::GetFirstLeafChild(
|
||||
*nextContent, ChildBlockBoundary::Ignore)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
@ -1283,8 +1283,8 @@ nsIContent* WSRunScanner::GetNextWSNode(const EditorDOMPoint& aPoint,
|
|||
}
|
||||
if (HTMLEditUtils::IsContainerNode(*nextContent)) {
|
||||
// else if it's a container, get deep leftmost child
|
||||
nsCOMPtr<nsIContent> child = mHTMLEditor->GetLeftmostChild(nextContent);
|
||||
if (child) {
|
||||
if (nsIContent* child = HTMLEditUtils::GetFirstLeafChild(
|
||||
*nextContent, ChildBlockBoundary::Ignore)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче