diff --git a/editor/libeditor/TextEditSubActionHandler.cpp b/editor/libeditor/TextEditSubActionHandler.cpp index 8987343236a4..e9698eb34220 100644 --- a/editor/libeditor/TextEditSubActionHandler.cpp +++ b/editor/libeditor/TextEditSubActionHandler.cpp @@ -527,9 +527,7 @@ Result TextEditor::SetTextWithoutTransaction( MaybeDoAutoPasswordMasking(); - RefPtr anonymousDivElement = GetRoot(); - RefPtr textNode = - Text::FromNodeOrNull(anonymousDivElement->GetFirstChild()); + const RefPtr textNode = GetTextNode(); MOZ_ASSERT(textNode); // We can use this fast path only when: @@ -624,8 +622,8 @@ Result TextEditor::HandleDeleteSelectionInternal( return Err(NS_ERROR_FAILURE); } - if (const Text* theTextNode = AsTextEditor()->GetTextNode()) { - rangesToDelete.EnsureRangesInTextNode(*theTextNode); + if (const Text* const textNode = GetTextNode()) { + rangesToDelete.EnsureRangesInTextNode(*textNode); } Result caretPointOrError = @@ -706,7 +704,7 @@ TextEditor::ComputeValueFromTextNodeAndBRElement(nsAString& aValue) const { return EditActionResult::HandledResult(); } - Text* textNode = Text::FromNodeOrNull(anonymousDivElement->GetFirstChild()); + const Text* const textNode = GetTextNode(); MOZ_ASSERT(textNode); if (!textNode->Length()) { diff --git a/editor/libeditor/TextEditor.cpp b/editor/libeditor/TextEditor.cpp index 217b25881fe9..5e75b513a025 100644 --- a/editor/libeditor/TextEditor.cpp +++ b/editor/libeditor/TextEditor.cpp @@ -480,56 +480,23 @@ already_AddRefed TextEditor::GetInputEventTargetElement() const { } bool TextEditor::IsEmpty() const { - // Even if there is no padding
element for empty editor, we should be - // detected as empty editor if all the children are text nodes and these - // have no content. - Element* anonymousDivElement = GetRoot(); - if (!anonymousDivElement) { - return true; // Don't warn it, this is possible, e.g., 997805.html - } - - MOZ_ASSERT(anonymousDivElement->GetFirstChild() && - anonymousDivElement->GetFirstChild()->IsText()); - - // Only when there is non-empty text node, we are not empty. - return !anonymousDivElement->GetFirstChild()->Length(); + const Text* const textNode = GetTextNode(); + MOZ_DIAGNOSTIC_ASSERT_IF(textNode, + !Text::FromNodeOrNull(textNode->GetNextSibling())); + return !textNode || !textNode->TextDataLength(); } NS_IMETHODIMP TextEditor::GetTextLength(uint32_t* aCount) { MOZ_ASSERT(aCount); - // initialize out params - *aCount = 0; - - // special-case for empty document, to account for the padding
element - // for empty editor. - // XXX This should be overridden by `HTMLEditor` and we should return the - // first text node's length from `TextEditor` instead. The following - // code is too expensive. - if (IsEmpty()) { - return NS_OK; - } - - Element* rootElement = GetRoot(); - if (NS_WARN_IF(!rootElement)) { + if (NS_WARN_IF(!GetRoot())) { return NS_ERROR_FAILURE; } - uint32_t totalLength = 0; - PostContentIterator postOrderIter; - DebugOnly rvIgnored = postOrderIter.Init(rootElement); - NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored), - "PostContentIterator::Init() failed, but ignored"); - EditorType editorType = GetEditorType(); - for (; !postOrderIter.IsDone(); postOrderIter.Next()) { - nsINode* currentNode = postOrderIter.GetCurrentNode(); - if (currentNode && currentNode->IsText() && - EditorUtils::IsEditableContent(*currentNode->AsText(), editorType)) { - totalLength += currentNode->Length(); - } - } - - *aCount = totalLength; + const Text* const textNode = GetTextNode(); + MOZ_DIAGNOSTIC_ASSERT_IF(textNode, + !Text::FromNodeOrNull(textNode->GetNextSibling())); + *aCount = textNode ? textNode->TextDataLength() : 0u; return NS_OK; } @@ -947,11 +914,10 @@ nsresult TextEditor::SetUnmaskRangeInternal(uint32_t aStart, uint32_t aLength, return NS_ERROR_NOT_AVAILABLE; } - Element* rootElement = GetRoot(); - if (NS_WARN_IF(!rootElement)) { + if (NS_WARN_IF(!GetRoot())) { return NS_ERROR_NOT_INITIALIZED; } - Text* text = Text::FromNodeOrNull(rootElement->GetFirstChild()); + Text* const text = GetTextNode(); if (!text || !text->Length()) { // There is no anonymous text node in the editor. return aStart > 0 && aStart != UINT32_MAX ? NS_ERROR_INVALID_ARG : NS_OK; @@ -965,8 +931,8 @@ nsresult TextEditor::SetUnmaskRangeInternal(uint32_t aStart, uint32_t aLength, // If aStart is middle of a surrogate pair, expand it to include the // preceding high surrogate because the caller may want to show a // character before the character at `aStart + 1`. - const nsTextFragment* textFragment = text->GetText(); - if (textFragment->IsLowSurrogateFollowingHighSurrogateAt(aStart)) { + const nsTextFragment& textFragment = text->TextFragment(); + if (textFragment.IsLowSurrogateFollowingHighSurrogateAt(aStart)) { mPasswordMaskData->mUnmaskedStart = aStart - 1; // If caller collapses the range, keep it. Otherwise, expand the length. if (aLength > 0) { @@ -981,7 +947,7 @@ nsresult TextEditor::SetUnmaskRangeInternal(uint32_t aStart, uint32_t aLength, // the following low surrogate because the caller may want to show a // character after the character at `aStart + aLength`. if (UnmaskedEnd() < valueLength && - textFragment->IsLowSurrogateFollowingHighSurrogateAt(UnmaskedEnd())) { + textFragment.IsLowSurrogateFollowingHighSurrogateAt(UnmaskedEnd())) { mPasswordMaskData->mUnmaskedLength++; } // If it's first time to mask the unmasking characters with timer, create diff --git a/editor/libeditor/TextEditor.h b/editor/libeditor/TextEditor.h index 6004b2b3f8e6..0bee159e5404 100644 --- a/editor/libeditor/TextEditor.h +++ b/editor/libeditor/TextEditor.h @@ -259,6 +259,10 @@ class TextEditor final : public EditorBase, } } + /** + * Return the `Text` node in the anonymous
. Note that the anonymous + *
can have only one `Text` for the storage of the value of this editor. + */ dom::Text* GetTextNode() { MOZ_DIAGNOSTIC_ASSERT(GetRoot()); MOZ_DIAGNOSTIC_ASSERT(GetRoot()->GetFirstChild());