зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1774704 - part 1: Make `HTMLEditor::EnsureCaretInBlockElement` only computes new caret point in the given element r=m_kato
Differential Revision: https://phabricator.services.mozilla.com/D152963
This commit is contained in:
Родитель
7f6f9cf71c
Коммит
14dd35ea1d
|
@ -561,15 +561,30 @@ nsresult HTMLEditor::OnEndHandlingTopLevelEditSubActionInternal() {
|
|||
|
||||
// If we created a new block, make sure caret is in it.
|
||||
if (TopLevelEditSubActionDataRef().mNewBlockElement &&
|
||||
SelectionRef().IsCollapsed()) {
|
||||
nsresult rv = EnsureCaretInBlockElement(
|
||||
MOZ_KnownLive(*TopLevelEditSubActionDataRef().mNewBlockElement));
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
SelectionRef().IsCollapsed() && SelectionRef().RangeCount()) {
|
||||
const auto firstRangeStartPoint =
|
||||
GetFirstSelectionStartPoint<EditorRawDOMPoint>();
|
||||
if (MOZ_LIKELY(firstRangeStartPoint.IsSet())) {
|
||||
const Result<EditorRawDOMPoint, nsresult> pointToPutCaretOrError =
|
||||
HTMLEditUtils::ComputePointToPutCaretInElementIfOutside<
|
||||
EditorRawDOMPoint>(
|
||||
*TopLevelEditSubActionDataRef().mNewBlockElement,
|
||||
firstRangeStartPoint);
|
||||
if (MOZ_UNLIKELY(pointToPutCaretOrError.isErr())) {
|
||||
NS_WARNING(
|
||||
"HTMLEditUtils::ComputePointToPutCaretInElementIfOutside() "
|
||||
"failed, but ignored");
|
||||
} else if (pointToPutCaretOrError.inspect().IsSet()) {
|
||||
nsresult rv = CollapseSelectionTo(pointToPutCaretOrError.inspect());
|
||||
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
NS_WARNING("EditorBase::CollapseSelectionTo() failed");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
}
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"HTMLEditor::EnsureSelectionInBlockElement() failed, but ignored");
|
||||
}
|
||||
|
||||
// Adjust selection for insert text, html paste, and delete actions if
|
||||
|
@ -8805,79 +8820,6 @@ nsresult HTMLEditor::InsertBRElementToEmptyListItemsAndTableCellsInRange(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::EnsureCaretInBlockElement(Element& aElement) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT(SelectionRef().IsCollapsed());
|
||||
|
||||
const auto atCaret = GetFirstSelectionStartPoint<EditorRawDOMPoint>();
|
||||
if (NS_WARN_IF(!atCaret.IsSet())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Use ranges and RangeUtils::CompareNodeToRange() to compare selection
|
||||
// start to new block.
|
||||
RefPtr<StaticRange> staticRange =
|
||||
StaticRange::Create(atCaret.ToRawRangeBoundary(),
|
||||
atCaret.ToRawRangeBoundary(), IgnoreErrors());
|
||||
if (!staticRange) {
|
||||
NS_WARNING("StaticRange::Create() failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool nodeBefore, nodeAfter;
|
||||
nsresult rv = RangeUtils::CompareNodeToRange(&aElement, staticRange,
|
||||
&nodeBefore, &nodeAfter);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("RangeUtils::CompareNodeToRange() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (nodeBefore && nodeAfter) {
|
||||
return NS_OK; // selection is inside block
|
||||
}
|
||||
|
||||
if (nodeBefore) {
|
||||
// selection is after block. put at end of block.
|
||||
nsIContent* lastEditableContent = HTMLEditUtils::GetLastChild(
|
||||
aElement, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
if (!lastEditableContent) {
|
||||
lastEditableContent = &aElement;
|
||||
}
|
||||
EditorRawDOMPoint endPoint;
|
||||
if (lastEditableContent->IsText() ||
|
||||
HTMLEditUtils::IsContainerNode(*lastEditableContent)) {
|
||||
endPoint.SetToEndOf(lastEditableContent);
|
||||
} else {
|
||||
endPoint.SetAfter(lastEditableContent);
|
||||
if (NS_WARN_IF(!endPoint.IsSet())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
nsresult rv = CollapseSelectionTo(endPoint);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
// selection is before block. put at start of block.
|
||||
nsIContent* firstEditableContent = HTMLEditUtils::GetFirstChild(
|
||||
aElement, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
if (!firstEditableContent) {
|
||||
firstEditableContent = &aElement;
|
||||
}
|
||||
EditorRawDOMPoint atStartOfBlock;
|
||||
if (firstEditableContent->IsText() ||
|
||||
HTMLEditUtils::IsContainerNode(*firstEditableContent)) {
|
||||
atStartOfBlock.Set(firstEditableContent);
|
||||
} else {
|
||||
atStartOfBlock.Set(firstEditableContent, 0);
|
||||
}
|
||||
rv = CollapseSelectionTo(atStartOfBlock);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
void HTMLEditor::SetSelectionInterlinePosition() {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT(SelectionRef().IsCollapsed());
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "mozilla/ArrayUtils.h" // for ArrayLength
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc.
|
||||
#include "mozilla/RangeUtils.h" // for RangeUtils
|
||||
#include "mozilla/dom/Element.h" // for Element, nsINode
|
||||
#include "mozilla/dom/HTMLAnchorElement.h"
|
||||
#include "mozilla/dom/HTMLInputElement.h"
|
||||
|
@ -96,6 +97,19 @@ template EditorRawDOMPoint HTMLEditUtils::GetBetterInsertionPointFor(
|
|||
const nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert,
|
||||
const Element& aEditingHost);
|
||||
|
||||
template Result<EditorDOMPoint, nsresult>
|
||||
HTMLEditUtils::ComputePointToPutCaretInElementIfOutside(
|
||||
const Element& aElement, const EditorDOMPoint& aCurrentPoint);
|
||||
template Result<EditorRawDOMPoint, nsresult>
|
||||
HTMLEditUtils::ComputePointToPutCaretInElementIfOutside(
|
||||
const Element& aElement, const EditorDOMPoint& aCurrentPoint);
|
||||
template Result<EditorDOMPoint, nsresult>
|
||||
HTMLEditUtils::ComputePointToPutCaretInElementIfOutside(
|
||||
const Element& aElement, const EditorRawDOMPoint& aCurrentPoint);
|
||||
template Result<EditorRawDOMPoint, nsresult>
|
||||
HTMLEditUtils::ComputePointToPutCaretInElementIfOutside(
|
||||
const Element& aElement, const EditorRawDOMPoint& aCurrentPoint);
|
||||
|
||||
bool HTMLEditUtils::CanContentsBeJoined(const nsIContent& aLeftContent,
|
||||
const nsIContent& aRightContent,
|
||||
StyleDifference aStyleDifference) {
|
||||
|
@ -1794,6 +1808,69 @@ EditorDOMPointType HTMLEditUtils::GetBetterInsertionPointFor(
|
|||
.template PointAfterContent<EditorDOMPointType>();
|
||||
}
|
||||
|
||||
// static
|
||||
template <typename EditorDOMPointType, typename EditorDOMPointTypeInput>
|
||||
Result<EditorDOMPointType, nsresult>
|
||||
HTMLEditUtils::ComputePointToPutCaretInElementIfOutside(
|
||||
const Element& aElement, const EditorDOMPointTypeInput& aCurrentPoint) {
|
||||
MOZ_ASSERT(aCurrentPoint.IsSet());
|
||||
|
||||
// FYI: This was moved from
|
||||
// https://searchfox.org/mozilla-central/rev/d3c2f51d89c3ca008ff0cb5a057e77ccd973443e/editor/libeditor/HTMLEditSubActionHandler.cpp#9193
|
||||
|
||||
// Use ranges and RangeUtils::CompareNodeToRange() to compare selection
|
||||
// start to new block.
|
||||
RefPtr<StaticRange> staticRange =
|
||||
StaticRange::Create(aCurrentPoint.ToRawRangeBoundary(),
|
||||
aCurrentPoint.ToRawRangeBoundary(), IgnoreErrors());
|
||||
if (MOZ_UNLIKELY(!staticRange)) {
|
||||
NS_WARNING("StaticRange::Create() failed");
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
bool nodeBefore, nodeAfter;
|
||||
nsresult rv = RangeUtils::CompareNodeToRange(
|
||||
const_cast<Element*>(&aElement), staticRange, &nodeBefore, &nodeAfter);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("RangeUtils::CompareNodeToRange() failed");
|
||||
return Err(rv);
|
||||
}
|
||||
|
||||
if (nodeBefore && nodeAfter) {
|
||||
return EditorDOMPointType(); // aCurrentPoint is in aElement
|
||||
}
|
||||
|
||||
if (nodeBefore) {
|
||||
// selection is after block. put at end of block.
|
||||
const nsIContent* lastEditableContent = HTMLEditUtils::GetLastChild(
|
||||
aElement, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
if (!lastEditableContent) {
|
||||
lastEditableContent = &aElement;
|
||||
}
|
||||
if (lastEditableContent->IsText() ||
|
||||
HTMLEditUtils::IsContainerNode(*lastEditableContent)) {
|
||||
return EditorDOMPointType::AtEndOf(*lastEditableContent);
|
||||
}
|
||||
MOZ_ASSERT(lastEditableContent->GetParentNode());
|
||||
return EditorDOMPointType::After(*lastEditableContent);
|
||||
}
|
||||
|
||||
// selection is before block. put at start of block.
|
||||
const nsIContent* firstEditableContent = HTMLEditUtils::GetFirstChild(
|
||||
aElement, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
if (!firstEditableContent) {
|
||||
firstEditableContent = &aElement;
|
||||
}
|
||||
if (firstEditableContent->IsText() ||
|
||||
HTMLEditUtils::IsContainerNode(*firstEditableContent)) {
|
||||
MOZ_ASSERT(firstEditableContent->GetParentNode());
|
||||
// XXX Shouldn't this be EditorDOMPointType(firstEditableContent, 0u)?
|
||||
return EditorDOMPointType(firstEditableContent);
|
||||
}
|
||||
// XXX And shouldn't this be EditorDOMPointType(firstEditableContent)?
|
||||
return EditorDOMPointType(firstEditableContent, 0u);
|
||||
}
|
||||
|
||||
// static
|
||||
size_t HTMLEditUtils::CollectChildren(
|
||||
nsINode& aNode, nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/EnumSet.h"
|
||||
#include "mozilla/IntegerRange.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Result.h"
|
||||
#include "mozilla/dom/AbstractRange.h"
|
||||
#include "mozilla/dom/AncestorIterator.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
@ -1949,6 +1950,19 @@ class HTMLEditUtils final {
|
|||
const EditorDOMPointTypeInput& aPointToInsert,
|
||||
const Element& aEditingHost);
|
||||
|
||||
/**
|
||||
* ComputePointToPutCaretInElementIfOutside() returns a good point in aElement
|
||||
* to put caret if aCurrentPoint is outside of aElement.
|
||||
*
|
||||
* @param aElement The result is a point in aElement.
|
||||
* @param aCurrentPoint The current (candidate) caret point. Only if this
|
||||
* is outside aElement, returns a point in aElement.
|
||||
*/
|
||||
template <typename EditorDOMPointType, typename EditorDOMPointTypeInput>
|
||||
static Result<EditorDOMPointType, nsresult>
|
||||
ComputePointToPutCaretInElementIfOutside(
|
||||
const Element& aElement, const EditorDOMPointTypeInput& aCurrentPoint);
|
||||
|
||||
/**
|
||||
* Content-based query returns true if <aProperty aAttribute=aValue> effects
|
||||
* aNode. If <aProperty aAttribute=aValue> contains aNode, but
|
||||
|
|
|
@ -2612,14 +2612,6 @@ class HTMLEditor final : public EditorBase,
|
|||
*/
|
||||
void SetSelectionInterlinePosition();
|
||||
|
||||
/**
|
||||
* EnsureSelectionInBlockElement() may move caret into aElement or its
|
||||
* parent block if caret is outside of them. Don't call this when
|
||||
* `Selection` is not collapsed.
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
EnsureCaretInBlockElement(dom::Element& aElement);
|
||||
|
||||
/**
|
||||
* Called by `HTMLEditor::OnEndHandlingTopLevelEditSubAction()`. This may
|
||||
* adjust Selection, remove unnecessary empty nodes, create `<br>` elements
|
||||
|
|
Загрузка…
Ссылка в новой задаче