Skip to content

Commit

Permalink
Bug 1789967 - part 2: Make TextEditor and HTMLEditor implement `E…
Browse files Browse the repository at this point in the history
…ditorBase::CollapseSelectionToEndOfLastLeafNode` by themselves r=m_kato

It does different thing for `TextEditor` and `HTMLEditor`, and used almost
internally.  Therefore, it should be implemented in the sub classes and
we should name them better.

Differential Revision: https://phabricator.services.mozilla.com/D157407
  • Loading branch information
masayuki-nakano committed Sep 22, 2022
1 parent f1dd8bf commit 2f0ed11
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 67 deletions.
5 changes: 2 additions & 3 deletions editor/libeditor/DeleteRangeTransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,8 @@ NS_IMETHODIMP DeleteRangeTransaction::DoTransaction() {

OwningNonNull<EditorBase> editorBase = *mEditorBase;
rv = editorBase->CollapseSelectionTo(EditorRawDOMPoint(startRef));
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rv),
"EditorBase::CollapseSelectionToEndOfLastLeafNode() failed");
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"EditorBase::CollapseSelectionTo() failed");
return rv;
}

Expand Down
48 changes: 2 additions & 46 deletions editor/libeditor/EditorBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "EditorBase.h"

#include "ErrorList.h"
#include "mozilla/DebugOnly.h" // for DebugOnly

#include <stdio.h> // for nullptr, stdout
Expand Down Expand Up @@ -1343,52 +1344,7 @@ MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP EditorBase::BeginningOfDocument() {
return rv;
}

NS_IMETHODIMP EditorBase::EndOfDocument() {
AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
if (NS_WARN_IF(!editActionData.CanHandle())) {
return NS_ERROR_NOT_INITIALIZED;
}
nsresult rv = CollapseSelectionToEndOfLastLeafNode();
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rv),
"EditorBase::CollapseSelectionToEndOfLastLeafNode() failed");
// This is low level API for XUL applcation. So, we should return raw
// error code here.
return rv;
}

nsresult EditorBase::CollapseSelectionToEndOfLastLeafNode() const {
MOZ_ASSERT(IsEditActionDataAvailable());

// XXX Why doesn't this check if the document is alive?
if (NS_WARN_IF(!IsInitialized())) {
return NS_ERROR_NOT_INITIALIZED;
}

// get the root element
Element* rootElement = GetRoot();
if (NS_WARN_IF(!rootElement)) {
return NS_ERROR_NULL_POINTER;
}

nsIContent* lastLeafContent = rootElement;
if (IsTextEditor()) {
lastLeafContent = rootElement->GetFirstChild();
MOZ_ASSERT(lastLeafContent && lastLeafContent->IsText());
} else {
for (nsIContent* child = lastLeafContent->GetLastChild();
child && HTMLEditUtils::IsContainerNode(*child);
child = child->GetLastChild()) {
lastLeafContent = child;
}
}

nsresult rv =
CollapseSelectionToEndOf(OwningNonNull<nsINode>(*lastLeafContent));
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"EditorBase::CollapseSelectionToEndOf() failed");
return rv;
}
NS_IMETHODIMP EditorBase::EndOfDocument() { return NS_ERROR_NOT_IMPLEMENTED; }

NS_IMETHODIMP EditorBase::GetDocumentModified(bool* aOutDocModified) {
if (NS_WARN_IF(!aOutDocModified)) {
Expand Down
6 changes: 0 additions & 6 deletions editor/libeditor/EditorBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -1920,12 +1920,6 @@ class EditorBase : public nsIEditor,
CollapseSelectionTo(EditorRawDOMPoint::AtEndOf(aNode), aRv);
}

/**
* CollapseSelectionToEnd() collapses the selection to the last leaf content
* of the editor.
*/
MOZ_CAN_RUN_SCRIPT nsresult CollapseSelectionToEndOfLastLeafNode() const;

/**
* AllowsTransactionsToChangeSelection() returns true if editor allows any
* transactions to change Selection. Otherwise, transactions shouldn't
Expand Down
6 changes: 4 additions & 2 deletions editor/libeditor/HTMLEditSubActionHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,11 @@ nsresult HTMLEditor::InitEditorContentAndSelection() {
// removed by the web app and if they call `Selection::AddRange()`,
// it may cause multiple selection ranges.
if (!SelectionRef().RangeCount()) {
nsresult rv = CollapseSelectionToEndOfLastLeafNode();
nsresult rv = CollapseSelectionToEndOfLastLeafNodeOfDocument();
if (NS_FAILED(rv)) {
NS_WARNING("EditorBase::CollapseSelectionToEndOfLastLeafNode() failed");
NS_WARNING(
"HTMLEditor::CollapseSelectionToEndOfLastLeafNodeOfDocument() "
"failed");
return rv;
}
}
Expand Down
40 changes: 40 additions & 0 deletions editor/libeditor/HTMLEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,46 @@ NS_IMETHODIMP HTMLEditor::BeginningOfDocument() {
return rv;
}

NS_IMETHODIMP HTMLEditor::EndOfDocument() {
AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
if (NS_WARN_IF(!editActionData.CanHandle())) {
return NS_ERROR_NOT_INITIALIZED;
}
nsresult rv = CollapseSelectionToEndOfLastLeafNodeOfDocument();
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rv),
"HTMLEditor::CollapseSelectionToEndOfLastLeafNodeOfDocument() failed");
// This is low level API for embedders and chrome script so that we can return
// raw error code here.
return rv;
}

nsresult HTMLEditor::CollapseSelectionToEndOfLastLeafNodeOfDocument() const {
MOZ_ASSERT(IsEditActionDataAvailable());

RefPtr<Element> bodyOrDocumentElement = GetRoot();
if (NS_WARN_IF(!bodyOrDocumentElement)) {
return NS_ERROR_NULL_POINTER;
}

auto pointToPutCaret = [&]() -> EditorRawDOMPoint {
nsCOMPtr<nsIContent> lastLeafContent = HTMLEditUtils::GetLastLeafContent(
*bodyOrDocumentElement, {LeafNodeType::OnlyLeafNode});
if (!lastLeafContent) {
return EditorRawDOMPoint::AtEndOf(*bodyOrDocumentElement);
}
// TODO: We should put caret into text node if it's visible.
return lastLeafContent->IsText() ||
HTMLEditUtils::IsContainerNode(*lastLeafContent)
? EditorRawDOMPoint::AtEndOf(*lastLeafContent)
: EditorRawDOMPoint(lastLeafContent);
}();
nsresult rv = CollapseSelectionTo(pointToPutCaret);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"EditorBase::CollapseSelectionTo() failed");
return rv;
}

void HTMLEditor::InitializeSelectionAncestorLimit(
nsIContent& aAncestorLimit) const {
MOZ_ASSERT(IsEditActionDataAvailable());
Expand Down
8 changes: 8 additions & 0 deletions editor/libeditor/HTMLEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ class HTMLEditor final : public EditorBase,

// EditorBase overrides
MOZ_CAN_RUN_SCRIPT NS_IMETHOD BeginningOfDocument() final;
MOZ_CAN_RUN_SCRIPT NS_IMETHOD EndOfDocument() final;

NS_IMETHOD GetDocumentCharacterSet(nsACString& aCharacterSet) final;
MOZ_CAN_RUN_SCRIPT NS_IMETHOD
Expand Down Expand Up @@ -2685,6 +2686,13 @@ class HTMLEditor final : public EditorBase,
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InitEditorContentAndSelection();

/**
* Collapse `Selection` to the last leaf content of the <body> or the document
* element.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
CollapseSelectionToEndOfLastLeafNodeOfDocument() const;

MOZ_CAN_RUN_SCRIPT nsresult SelectAllInternal() final;

[[nodiscard]] Element* ComputeEditingHostInternal(
Expand Down
8 changes: 4 additions & 4 deletions editor/libeditor/TextEditSubActionHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,16 +271,16 @@ nsresult TextEditor::EnsureCaretNotAtEndOfTextNode() {
return NS_OK;
}

nsresult rv = CollapseSelectionToEndOfLastLeafNode();
nsresult rv = CollapseSelectionToEndOfTextNode();
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
NS_WARNING(
"EditorBase::CollapseSelectionToEndOfLastLeafNode() caused destroying "
"the editor");
"TextEditor::CollapseSelectionToEndOfTextNode() caused destroying the "
"editor");
return NS_ERROR_EDITOR_DESTROYED;
}
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rv),
"EditorBase::CollapseSelectionToEndOfLastLeafNode() failed, but ignored");
"TextEditor::CollapseSelectionToEndOfTextNode() failed, but ignored");

return NS_OK;
}
Expand Down
44 changes: 38 additions & 6 deletions editor/libeditor/TextEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/TextEditor.h"
#include "TextEditor.h"

#include <algorithm>

#include "EditAction.h"
#include "EditAggregateTransaction.h"
#include "EditorDOMPoint.h"
#include "HTMLEditor.h"
#include "HTMLEditUtils.h"
#include "InternetCiter.h"
#include "PlaceholderTransaction.h"
#include "gfxFontUtils.h"

#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/Assertions.h"
#include "mozilla/ContentIterator.h"
#include "mozilla/EditAction.h"
#include "mozilla/EditorDOMPoint.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/mozalloc.h"
Expand All @@ -31,6 +32,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/StaticRange.h"

#include "nsAString.h"
#include "nsCRT.h"
#include "nsCaret.h"
Expand Down Expand Up @@ -108,6 +110,36 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextEditor)
NS_INTERFACE_MAP_ENTRY(nsINamed)
NS_INTERFACE_MAP_END_INHERITING(EditorBase)

NS_IMETHODIMP TextEditor::EndOfDocument() {
AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
if (NS_WARN_IF(!editActionData.CanHandle())) {
return NS_ERROR_NOT_INITIALIZED;
}
nsresult rv = CollapseSelectionToEndOfTextNode();
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"TextEditor::CollapseSelectionToEndOfTextNode() failed");
// This is low level API for embedders and chrome script so that we can return
// raw error code here.
return rv;
}

nsresult TextEditor::CollapseSelectionToEndOfTextNode() {
MOZ_ASSERT(IsEditActionDataAvailable());

Element* anonymousDivElement = GetRoot();
if (NS_WARN_IF(!anonymousDivElement)) {
return NS_ERROR_NULL_POINTER;
}

RefPtr<Text> textNode =
Text::FromNodeOrNull(anonymousDivElement->GetFirstChild());
MOZ_ASSERT(textNode);
nsresult rv = CollapseSelectionToEndOf(*textNode);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"EditorBase::CollapseSelectionToEndOf() failed");
return rv;
}

nsresult TextEditor::Init(Document& aDocument, Element& aAnonymousDivElement,
nsISelectionController& aSelectionController,
uint32_t aFlags,
Expand Down Expand Up @@ -160,9 +192,9 @@ nsresult TextEditor::InitEditorContentAndSelection() {
// If the selection hasn't been set up yet, set it up collapsed to the end of
// our editable content.
if (!SelectionRef().RangeCount()) {
nsresult rv = CollapseSelectionToEndOfLastLeafNode();
nsresult rv = CollapseSelectionToEndOfTextNode();
if (NS_FAILED(rv)) {
NS_WARNING("EditorBase::CollapseSelectionToEndOfLastLeafNode() failed");
NS_WARNING("EditorBase::CollapseSelectionToEndOfTextNode() failed");
return rv;
}
}
Expand Down
7 changes: 7 additions & 0 deletions editor/libeditor/TextEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class TextEditor final : public EditorBase,
NS_DECL_NSINAMED

// Overrides of nsIEditor
MOZ_CAN_RUN_SCRIPT NS_IMETHOD EndOfDocument() final;
MOZ_CAN_RUN_SCRIPT NS_IMETHOD InsertLineBreak() final;
NS_IMETHOD GetTextLength(uint32_t* aCount) final;
MOZ_CAN_RUN_SCRIPT NS_IMETHOD Paste(int32_t aClipboardType) final {
Expand Down Expand Up @@ -540,6 +541,12 @@ class TextEditor final : public EditorBase,
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InitEditorContentAndSelection();

/**
* Collapse `Selection` to end of the text node in the anonymous <div>
* element.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult CollapseSelectionToEndOfTextNode();

/**
* Make the given selection span the entire document.
*/
Expand Down

0 comments on commit 2f0ed11

Please sign in to comment.