Bug 1926483 - part 1: Make WSRunScanner instance free from editing host r=m_kato

If it scans starting from a editable point, it does not require the editing
host as an ancestor limiter.  Therefore, some users can be free from editing
host.

Differential Revision: https://phabricator.services.mozilla.com/D233791
This commit is contained in:
Masayuki Nakano
2025-01-24 05:00:47 +00:00
parent 94cf6b7230
commit 395226db0c
8 changed files with 122 additions and 123 deletions

View File

@@ -2323,7 +2323,8 @@ Result<CreateElementResult, nsresult> HTMLEditor::HandleInsertBRElement(
const bool editingHostIsEmpty = HTMLEditUtils::IsEmptyNode( const bool editingHostIsEmpty = HTMLEditUtils::IsEmptyNode(
aEditingHost, {EmptyCheckOption::TreatNonEditableContentAsInvisible}); aEditingHost, {EmptyCheckOption::TreatNonEditableContentAsInvisible});
WSRunScanner wsRunScanner(&aEditingHost, aPointToBreak, const WSRunScanner wsRunScanner(WSRunScanner::Scan::EditableNodes,
aPointToBreak,
BlockInlineCheck::UseComputedDisplayStyle); BlockInlineCheck::UseComputedDisplayStyle);
const WSScanResult backwardScanResult = const WSScanResult backwardScanResult =
wsRunScanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(aPointToBreak); wsRunScanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(aPointToBreak);
@@ -2619,7 +2620,8 @@ Result<EditorDOMPoint, nsresult> HTMLEditor::HandleInsertLinefeed(
// boundary. Note that it should always be <br> for avoiding padding line // boundary. Note that it should always be <br> for avoiding padding line
// breaks appear in `.textContent` value. // breaks appear in `.textContent` value.
if (pointToPutCaret.IsInContentNode() && pointToPutCaret.IsEndOfContainer()) { if (pointToPutCaret.IsInContentNode() && pointToPutCaret.IsEndOfContainer()) {
WSRunScanner wsScannerAtCaret(&aEditingHost, pointToPutCaret, const WSRunScanner wsScannerAtCaret(
WSRunScanner::Scan::EditableNodes, pointToPutCaret,
BlockInlineCheck::UseComputedDisplayStyle); BlockInlineCheck::UseComputedDisplayStyle);
if (wsScannerAtCaret.StartsFromPreformattedLineBreak() && if (wsScannerAtCaret.StartsFromPreformattedLineBreak() &&
(wsScannerAtCaret.EndsByBlockBoundary() || (wsScannerAtCaret.EndsByBlockBoundary() ||
@@ -7821,8 +7823,8 @@ HTMLEditor::GetRangeExtendedToHardLineEdgesForBlockEditAction(
// Is there any intervening visible white-space? If so we can't push // Is there any intervening visible white-space? If so we can't push
// selection past that, it would visibly change meaning of users selection. // selection past that, it would visibly change meaning of users selection.
WSRunScanner wsScannerAtEnd( const WSRunScanner wsScannerAtEnd(
&aEditingHost, endPoint, WSRunScanner::Scan::EditableNodes, endPoint,
// We should refer only the default style of HTML because we need to wrap // We should refer only the default style of HTML because we need to wrap
// any elements with a specific HTML element. So we should not refer // any elements with a specific HTML element. So we should not refer
// actual style. For example, we want to reformat parent HTML block // actual style. For example, we want to reformat parent HTML block
@@ -7866,7 +7868,8 @@ HTMLEditor::GetRangeExtendedToHardLineEdgesForBlockEditAction(
// Is there any intervening visible white-space? If so we can't push // Is there any intervening visible white-space? If so we can't push
// selection past that, it would visibly change meaning of users selection. // selection past that, it would visibly change meaning of users selection.
WSRunScanner wsScannerAtStart(&aEditingHost, startPoint, const WSRunScanner wsScannerAtStart(WSRunScanner::Scan::EditableNodes,
startPoint,
BlockInlineCheck::UseHTMLDefaultStyle); BlockInlineCheck::UseHTMLDefaultStyle);
const WSScanResult scanResultAtStart = const WSScanResult scanResultAtStart =
wsScannerAtStart.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom( wsScannerAtStart.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(

View File

@@ -114,17 +114,15 @@ template nsIContent* HTMLEditUtils::GetContentToPreserveInlineStyles(
const EditorRawDOMPoint& aPoint, const Element& aEditingHost); const EditorRawDOMPoint& aPoint, const Element& aEditingHost);
template EditorDOMPoint HTMLEditUtils::GetBetterInsertionPointFor( template EditorDOMPoint HTMLEditUtils::GetBetterInsertionPointFor(
const nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert, const nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert);
const Element& aEditingHost);
template EditorRawDOMPoint HTMLEditUtils::GetBetterInsertionPointFor( template EditorRawDOMPoint HTMLEditUtils::GetBetterInsertionPointFor(
const nsIContent& aContentToInsert, const EditorRawDOMPoint& aPointToInsert, const nsIContent& aContentToInsert,
const Element& aEditingHost); const EditorRawDOMPoint& aPointToInsert);
template EditorDOMPoint HTMLEditUtils::GetBetterInsertionPointFor( template EditorDOMPoint HTMLEditUtils::GetBetterInsertionPointFor(
const nsIContent& aContentToInsert, const EditorRawDOMPoint& aPointToInsert, const nsIContent& aContentToInsert,
const Element& aEditingHost); const EditorRawDOMPoint& aPointToInsert);
template EditorRawDOMPoint HTMLEditUtils::GetBetterInsertionPointFor( template EditorRawDOMPoint HTMLEditUtils::GetBetterInsertionPointFor(
const nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert, const nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert);
const Element& aEditingHost);
template EditorDOMPoint HTMLEditUtils::GetBetterCaretPositionToInsertText( template EditorDOMPoint HTMLEditUtils::GetBetterCaretPositionToInsertText(
const EditorDOMPoint& aPoint, const Element& aEditingHost); const EditorDOMPoint& aPoint, const Element& aEditingHost);
@@ -2546,6 +2544,9 @@ nsIContent* HTMLEditUtils::GetContentToPreserveInlineStyles(
if (nextVisibleThing.InVisibleOrCollapsibleCharacters()) { if (nextVisibleThing.InVisibleOrCollapsibleCharacters()) {
return nextVisibleThing.TextPtr(); return nextVisibleThing.TextPtr();
} }
if (nextVisibleThing.GetContent() == &aEditingHost) {
break;
}
// Ignore empty inline container elements because it's not visible for // Ignore empty inline container elements because it's not visible for
// users so that using the style will appear suddenly from point of // users so that using the style will appear suddenly from point of
// view of users. // view of users.
@@ -2566,18 +2567,16 @@ nsIContent* HTMLEditUtils::GetContentToPreserveInlineStyles(
template <typename EditorDOMPointType, typename EditorDOMPointTypeInput> template <typename EditorDOMPointType, typename EditorDOMPointTypeInput>
EditorDOMPointType HTMLEditUtils::GetBetterInsertionPointFor( EditorDOMPointType HTMLEditUtils::GetBetterInsertionPointFor(
const nsIContent& aContentToInsert, const nsIContent& aContentToInsert,
const EditorDOMPointTypeInput& aPointToInsert, const EditorDOMPointTypeInput& aPointToInsert) {
const Element& aEditingHost) {
if (NS_WARN_IF(!aPointToInsert.IsSet())) { if (NS_WARN_IF(!aPointToInsert.IsSet())) {
return EditorDOMPointType(); return EditorDOMPointType();
} }
auto pointToInsert = auto pointToInsert =
aPointToInsert.template GetNonAnonymousSubtreePoint<EditorDOMPointType>(); aPointToInsert.template GetNonAnonymousSubtreePoint<EditorDOMPointType>();
if (MOZ_UNLIKELY( if (NS_WARN_IF(!pointToInsert.IsSet()) ||
NS_WARN_IF(!pointToInsert.IsSet()) || NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(
NS_WARN_IF(!pointToInsert.GetContainer()->IsInclusiveDescendantOf( *pointToInsert.GetContainer()))) {
&aEditingHost)))) {
// Cannot insert aContentToInsert into this DOM tree. // Cannot insert aContentToInsert into this DOM tree.
return EditorDOMPointType(); return EditorDOMPointType();
} }
@@ -2589,8 +2588,8 @@ EditorDOMPointType HTMLEditUtils::GetBetterInsertionPointFor(
return pointToInsert; return pointToInsert;
} }
WSRunScanner wsScannerForPointToInsert( const WSRunScanner wsScannerForPointToInsert(
const_cast<Element*>(&aEditingHost), pointToInsert, WSRunScanner::Scan::EditableNodes, pointToInsert,
BlockInlineCheck::UseComputedDisplayStyle); BlockInlineCheck::UseComputedDisplayStyle);
// If the insertion position is after the last visible item in a line, // If the insertion position is after the last visible item in a line,
@@ -2644,10 +2643,9 @@ EditorDOMPointType HTMLEditUtils::GetBetterCaretPositionToInsertText(
return EditorDOMPointType(aPoint.GetChild(), 0u); return EditorDOMPointType(aPoint.GetChild(), 0u);
} }
if (aPoint.IsEndOfContainer()) { if (aPoint.IsEndOfContainer()) {
WSRunScanner scanner(&aEditingHost, aPoint,
BlockInlineCheck::UseComputedDisplayStyle);
const WSScanResult previousThing = const WSScanResult previousThing =
scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(aPoint); WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundary(
&aEditingHost, aPoint, BlockInlineCheck::UseComputedDisplayStyle);
if (previousThing.InVisibleOrCollapsibleCharacters()) { if (previousThing.InVisibleOrCollapsibleCharacters()) {
return EditorDOMPointType::AtEndOf(*previousThing.TextPtr()); return EditorDOMPointType::AtEndOf(*previousThing.TextPtr());
} }

View File

@@ -2364,7 +2364,6 @@ class HTMLEditUtils final {
* *
* @param aContentToInsert The content to insert. * @param aContentToInsert The content to insert.
* @param aPointToInsert A candidate point to insert the node. * @param aPointToInsert A candidate point to insert the node.
* @param aEditingHost The editing host containing aPointToInsert.
* @return Better insertion point if next visible node * @return Better insertion point if next visible node
* is a <br> element and previous visible node * is a <br> element and previous visible node
* is neither none, another <br> element nor * is neither none, another <br> element nor
@@ -2373,8 +2372,7 @@ class HTMLEditUtils final {
template <typename EditorDOMPointType, typename EditorDOMPointTypeInput> template <typename EditorDOMPointType, typename EditorDOMPointTypeInput>
static EditorDOMPointType GetBetterInsertionPointFor( static EditorDOMPointType GetBetterInsertionPointFor(
const nsIContent& aContentToInsert, const nsIContent& aContentToInsert,
const EditorDOMPointTypeInput& aPointToInsert, const EditorDOMPointTypeInput& aPointToInsert);
const Element& aEditingHost);
/** /**
* GetBetterCaretPositionToInsertText() returns better point to put caret * GetBetterCaretPositionToInsertText() returns better point to put caret

View File

@@ -2244,12 +2244,16 @@ nsresult HTMLEditor::InsertElementAtSelectionAsAction(
if (!SelectionRef().GetAnchorNode()) { if (!SelectionRef().GetAnchorNode()) {
return NS_OK; return NS_OK;
} }
if (NS_WARN_IF(!SelectionRef().GetAnchorNode()->IsInclusiveDescendantOf(
editingHost))) {
return NS_ERROR_FAILURE;
}
EditorRawDOMPoint atAnchor(SelectionRef().AnchorRef()); EditorRawDOMPoint atAnchor(SelectionRef().AnchorRef());
// Adjust position based on the node we are going to insert. // Adjust position based on the node we are going to insert.
EditorDOMPoint pointToInsert = EditorDOMPoint pointToInsert =
HTMLEditUtils::GetBetterInsertionPointFor<EditorDOMPoint>( HTMLEditUtils::GetBetterInsertionPointFor<EditorDOMPoint>(*aElement,
*aElement, atAnchor, *editingHost); atAnchor);
if (!pointToInsert.IsSet()) { if (!pointToInsert.IsSet()) {
NS_WARNING("HTMLEditUtils::GetBetterInsertionPointFor() failed"); NS_WARNING("HTMLEditUtils::GetBetterInsertionPointFor() failed");
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;

View File

@@ -501,8 +501,8 @@ HTMLEditor::HTMLWithContextInserter::FragmentFromPasteCreator final {
HTMLBRElement* HTMLBRElement*
HTMLEditor::HTMLWithContextInserter::GetInvisibleBRElementAtPoint( HTMLEditor::HTMLWithContextInserter::GetInvisibleBRElementAtPoint(
const EditorDOMPoint& aPointToInsert) const { const EditorDOMPoint& aPointToInsert) const {
WSRunScanner wsRunScannerAtInsertionPoint( const WSRunScanner wsRunScannerAtInsertionPoint(
mHTMLEditor.ComputeEditingHost(), aPointToInsert, WSRunScanner::Scan::EditableNodes, aPointToInsert,
BlockInlineCheck::UseComputedDisplayStyle); BlockInlineCheck::UseComputedDisplayStyle);
if (wsRunScannerAtInsertionPoint.EndsByInvisibleBRElement()) { if (wsRunScannerAtInsertionPoint.EndsByInvisibleBRElement()) {
return wsRunScannerAtInsertionPoint.EndReasonBRElementPtr(); return wsRunScannerAtInsertionPoint.EndReasonBRElementPtr();
@@ -563,14 +563,14 @@ HTMLEditor::HTMLWithContextInserter::GetNewCaretPointAfterInsertingHTML(
// Make sure we don't end up with selection collapsed after an invisible // Make sure we don't end up with selection collapsed after an invisible
// `<br>` element. // `<br>` element.
Element* editingHost = mHTMLEditor.ComputeEditingHost(); const WSRunScanner wsRunScannerAtCaret(
WSRunScanner wsRunScannerAtCaret(editingHost, pointToPutCaret, WSRunScanner::Scan::EditableNodes, pointToPutCaret,
BlockInlineCheck::UseComputedDisplayStyle); BlockInlineCheck::UseComputedDisplayStyle);
if (wsRunScannerAtCaret if (wsRunScannerAtCaret
.ScanPreviousVisibleNodeOrBlockBoundaryFrom(pointToPutCaret) .ScanPreviousVisibleNodeOrBlockBoundaryFrom(pointToPutCaret)
.ReachedInvisibleBRElement()) { .ReachedInvisibleBRElement()) {
WSRunScanner wsRunScannerAtStartReason( const WSRunScanner wsRunScannerAtStartReason(
editingHost, WSRunScanner::Scan::EditableNodes,
EditorDOMPoint(wsRunScannerAtCaret.GetStartReasonContent()), EditorDOMPoint(wsRunScannerAtCaret.GetStartReasonContent()),
BlockInlineCheck::UseComputedDisplayStyle); BlockInlineCheck::UseComputedDisplayStyle);
const WSScanResult backwardScanFromPointToCaretResult = const WSScanResult backwardScanFromPointToCaretResult =
@@ -830,11 +830,18 @@ Result<EditActionResult, nsresult> HTMLEditor::HTMLWithContextInserter::Run(
} }
// Adjust position based on the first node we are going to insert. // Adjust position based on the first node we are going to insert.
const auto candidatePointToInsert =
mHTMLEditor.GetFirstSelectionStartPoint<EditorRawDOMPoint>();
if (NS_WARN_IF(!candidatePointToInsert.IsSet()) ||
NS_WARN_IF(
!candidatePointToInsert.GetContainer()->IsInclusiveDescendantOf(
&mEditingHost))) {
return Err(NS_ERROR_FAILURE);
}
EditorDOMPoint pointToInsert = EditorDOMPoint pointToInsert =
HTMLEditUtils::GetBetterInsertionPointFor<EditorDOMPoint>( HTMLEditUtils::GetBetterInsertionPointFor<EditorDOMPoint>(
arrayOfTopMostChildContents[0], arrayOfTopMostChildContents[0],
mHTMLEditor.GetFirstSelectionStartPoint<EditorRawDOMPoint>(), mHTMLEditor.GetFirstSelectionStartPoint<EditorRawDOMPoint>());
mEditingHost);
if (!pointToInsert.IsSet()) { if (!pointToInsert.IsSet()) {
NS_WARNING("HTMLEditor::GetBetterInsertionPointFor() failed"); NS_WARNING("HTMLEditor::GetBetterInsertionPointFor() failed");
return Err(NS_ERROR_FAILURE); return Err(NS_ERROR_FAILURE);

View File

@@ -1517,8 +1517,8 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDelete(
EditorType::HTML)) { EditorType::HTML)) {
return NS_SUCCESS_DOM_NO_OPERATION; return NS_SUCCESS_DOM_NO_OPERATION;
} }
WSRunScanner wsRunScannerAtCaret( const WSRunScanner wsRunScannerAtCaret(
&aEditingHost, caretPoint, WSRunScanner::Scan::EditableNodes, caretPoint,
BlockInlineCheck::UseComputedDisplayOutsideStyle); BlockInlineCheck::UseComputedDisplayOutsideStyle);
const WSScanResult scanFromCaretPointResult = const WSScanResult scanFromCaretPointResult =
aDirectionAndAmount == nsIEditor::eNext aDirectionAndAmount == nsIEditor::eNext
@@ -1535,8 +1535,7 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDelete(
MOZ_ASSERT(scanFromCaretPointResult.GetContent()); MOZ_ASSERT(scanFromCaretPointResult.GetContent());
if (scanFromCaretPointResult.ReachedBRElement()) { if (scanFromCaretPointResult.ReachedBRElement()) {
if (scanFromCaretPointResult.BRElementPtr() == if (scanFromCaretPointResult.BRElementPtr() == &aEditingHost) {
wsRunScannerAtCaret.GetEditingHost()) {
return NS_OK; return NS_OK;
} }
if (!scanFromCaretPointResult.IsContentEditable()) { if (!scanFromCaretPointResult.IsContentEditable()) {
@@ -1812,8 +1811,8 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::Run(
*caretPoint.ref().ContainerAs<nsIContent>(), EditorType::HTML)) { *caretPoint.ref().ContainerAs<nsIContent>(), EditorType::HTML)) {
return EditActionResult::CanceledResult(); return EditActionResult::CanceledResult();
} }
WSRunScanner wsRunScannerAtCaret( const WSRunScanner wsRunScannerAtCaret(
&aEditingHost, caretPoint.ref(), WSRunScanner::Scan::EditableNodes, caretPoint.ref(),
BlockInlineCheck::UseComputedDisplayOutsideStyle); BlockInlineCheck::UseComputedDisplayOutsideStyle);
const WSScanResult scanFromCaretPointResult = const WSScanResult scanFromCaretPointResult =
aDirectionAndAmount == nsIEditor::eNext aDirectionAndAmount == nsIEditor::eNext
@@ -1872,8 +1871,8 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::Run(
NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT)) { NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT)) {
// Let's check whether there is new invisible `<br>` element // Let's check whether there is new invisible `<br>` element
// for avoiding infinite recursive calls. // for avoiding infinite recursive calls.
WSRunScanner wsRunScannerAtCaret( const WSRunScanner wsRunScannerAtCaret(
&aEditingHost, caretPoint.ref(), WSRunScanner::Scan::EditableNodes, caretPoint.ref(),
BlockInlineCheck::UseComputedDisplayOutsideStyle); BlockInlineCheck::UseComputedDisplayOutsideStyle);
const WSScanResult scanFromCaretPointResult = const WSScanResult scanFromCaretPointResult =
aDirectionAndAmount == nsIEditor::eNext aDirectionAndAmount == nsIEditor::eNext
@@ -1956,8 +1955,7 @@ HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDeleteAroundCollapsedRanges(
aScanFromCaretPointResult.ReachedBRElement() || aScanFromCaretPointResult.ReachedBRElement() ||
aScanFromCaretPointResult.ReachedHRElement() || aScanFromCaretPointResult.ReachedHRElement() ||
aScanFromCaretPointResult.ReachedNonEditableOtherBlockElement()) { aScanFromCaretPointResult.ReachedNonEditableOtherBlockElement()) {
if (aScanFromCaretPointResult.GetContent() == if (aScanFromCaretPointResult.GetContent() == &aEditingHost) {
aWSRunScannerAtCaret.GetEditingHost()) {
return NS_OK; return NS_OK;
} }
nsIContent* atomicContent = GetAtomicContentToDelete( nsIContent* atomicContent = GetAtomicContentToDelete(
@@ -2727,7 +2725,7 @@ HTMLEditor::AutoDeleteRangesHandler::HandleDeleteAtomicContent(
const Element& aEditingHost) { const Element& aEditingHost) {
MOZ_ASSERT(aHTMLEditor.IsEditActionDataAvailable()); MOZ_ASSERT(aHTMLEditor.IsEditActionDataAvailable());
MOZ_ASSERT(!HTMLEditUtils::IsInvisibleBRElement(aAtomicContent)); MOZ_ASSERT(!HTMLEditUtils::IsInvisibleBRElement(aAtomicContent));
MOZ_ASSERT(&aAtomicContent != aWSRunScannerAtCaret.GetEditingHost()); MOZ_ASSERT(!aAtomicContent.IsEditingHost());
EditorDOMPoint pointToPutCaret = aCaretPoint; EditorDOMPoint pointToPutCaret = aCaretPoint;
{ {
@@ -3084,7 +3082,8 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::
aHTMLEditor.GetEditAction())) { aHTMLEditor.GetEditAction())) {
return EditorDOMPoint(); return EditorDOMPoint();
} }
WSRunScanner scanner(&aEditingHost, EditorRawDOMPoint(mBRElement), const WSRunScanner scanner(
WSRunScanner::Scan::EditableNodes, EditorRawDOMPoint(mBRElement),
BlockInlineCheck::UseComputedDisplayOutsideStyle); BlockInlineCheck::UseComputedDisplayOutsideStyle);
const WSScanResult maybePreviousText = const WSScanResult maybePreviousText =
scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom( scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
@@ -4554,7 +4553,8 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::
// node because the other browsers insert following inputs into there. // node because the other browsers insert following inputs into there.
if (MayEditActionDeleteAroundCollapsedSelection( if (MayEditActionDeleteAroundCollapsedSelection(
aHTMLEditor.GetEditAction())) { aHTMLEditor.GetEditAction())) {
WSRunScanner scanner(&aEditingHost, startOfRightContent, const WSRunScanner scanner(
WSRunScanner::Scan::EditableNodes, startOfRightContent,
BlockInlineCheck::UseComputedDisplayOutsideStyle); BlockInlineCheck::UseComputedDisplayOutsideStyle);
const WSScanResult maybePreviousText = const WSScanResult maybePreviousText =
scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(startOfRightContent); scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(startOfRightContent);
@@ -5684,8 +5684,9 @@ HTMLEditor::AutoDeleteRangesHandler::DeleteParentBlocksWithTransactionIfEmpty(
// First, check there is visible contents before the point in current block. // First, check there is visible contents before the point in current block.
RefPtr<Element> editingHost = aHTMLEditor.ComputeEditingHost(); RefPtr<Element> editingHost = aHTMLEditor.ComputeEditingHost();
WSRunScanner wsScannerForPoint( const WSRunScanner wsScannerForPoint(
editingHost, aPoint, BlockInlineCheck::UseComputedDisplayOutsideStyle); WSRunScanner::Scan::EditableNodes, aPoint,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (!wsScannerForPoint.StartsFromCurrentBlockBoundary() && if (!wsScannerForPoint.StartsFromCurrentBlockBoundary() &&
!wsScannerForPoint.StartsFromInlineEditingHostBoundary()) { !wsScannerForPoint.StartsFromInlineEditingHostBoundary()) {
// If there is visible node before the point, we shouldn't remove the // If there is visible node before the point, we shouldn't remove the
@@ -6477,7 +6478,8 @@ Result<DeleteRangeResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::
// We should put caret to end of preceding text node if there is. // We should put caret to end of preceding text node if there is.
// Then, users can type text into it like the other browsers. // Then, users can type text into it like the other browsers.
auto pointToPutCaret = [&]() -> EditorDOMPoint { auto pointToPutCaret = [&]() -> EditorDOMPoint {
WSRunScanner scanner(&aEditingHost, maybeDeepStartOfRightContent, const WSRunScanner scanner(WSRunScanner::Scan::EditableNodes,
maybeDeepStartOfRightContent,
BlockInlineCheck::UseComputedDisplayStyle); BlockInlineCheck::UseComputedDisplayStyle);
const WSScanResult maybePreviousText = const WSScanResult maybePreviousText =
scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom( scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
@@ -8350,7 +8352,8 @@ HTMLEditor::AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete(
break; break;
} }
MOZ_ASSERT(backwardScanFromStartResult.GetContent() == MOZ_ASSERT(backwardScanFromStartResult.GetContent() ==
WSRunScanner(closestEditingHost, rangeToDelete.StartRef(), WSRunScanner(WSRunScanner::Scan::EditableNodes,
rangeToDelete.StartRef(),
BlockInlineCheck::UseComputedDisplayOutsideStyle) BlockInlineCheck::UseComputedDisplayOutsideStyle)
.GetStartReasonContent()); .GetStartReasonContent());
// We want to keep looking up. But stop if we are crossing table // We want to keep looking up. But stop if we are crossing table
@@ -8396,8 +8399,8 @@ HTMLEditor::AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete(
if (rangeToDelete.EndRef().GetContainer() != if (rangeToDelete.EndRef().GetContainer() !=
closestBlockAncestorOrInlineEditingHost) { closestBlockAncestorOrInlineEditingHost) {
for (;;) { for (;;) {
WSRunScanner wsScannerAtEnd( const WSRunScanner wsScannerAtEnd(
closestEditingHost, rangeToDelete.EndRef(), WSRunScanner::Scan::EditableNodes, rangeToDelete.EndRef(),
BlockInlineCheck::UseComputedDisplayOutsideStyle); BlockInlineCheck::UseComputedDisplayOutsideStyle);
const WSScanResult forwardScanFromEndResult = const WSScanResult forwardScanFromEndResult =
wsScannerAtEnd.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom( wsScannerAtEnd.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(

View File

@@ -83,13 +83,14 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
// If the visible things are not editable, we shouldn't scan "editable" // If the visible things are not editable, we shouldn't scan "editable"
// things now. Whether keep scanning editable things or not should be // things now. Whether keep scanning editable things or not should be
// considered by the caller. // considered by the caller.
if (aPoint.GetChild() && !aPoint.GetChild()->IsEditable()) { if (mScanMode == Scan::EditableNodes && aPoint.GetChild() &&
!HTMLEditUtils::IsSimplyEditableNode((*aPoint.GetChild()))) {
return WSScanResult(WSScanResult::ScanDirection::Backward, return WSScanResult(WSScanResult::ScanDirection::Backward,
*aPoint.GetChild(), WSType::SpecialContent, *aPoint.GetChild(), WSType::SpecialContent,
mBlockInlineCheck); mBlockInlineCheck);
} }
const auto atPreviousChar = const auto atPreviousChar =
GetPreviousEditableCharPoint<EditorRawDOMPointInText>(aPoint); GetPreviousCharPoint<EditorRawDOMPointInText>(aPoint);
// When it's a non-empty text node, return it. // When it's a non-empty text node, return it.
if (atPreviousChar.IsSet() && !atPreviousChar.IsContainerEmpty()) { if (atPreviousChar.IsSet() && !atPreviousChar.IsContainerEmpty()) {
MOZ_ASSERT(!atPreviousChar.IsEndOfContainer()); MOZ_ASSERT(!atPreviousChar.IsEndOfContainer());
@@ -180,13 +181,13 @@ WSScanResult WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(
// If the visible things are not editable, we shouldn't scan "editable" // If the visible things are not editable, we shouldn't scan "editable"
// things now. Whether keep scanning editable things or not should be // things now. Whether keep scanning editable things or not should be
// considered by the caller. // considered by the caller.
if (aPoint.GetChild() && !aPoint.GetChild()->IsEditable()) { if (mScanMode == Scan::EditableNodes && aPoint.GetChild() &&
!HTMLEditUtils::IsSimplyEditableNode(*aPoint.GetChild())) {
return WSScanResult(WSScanResult::ScanDirection::Forward, return WSScanResult(WSScanResult::ScanDirection::Forward,
*aPoint.GetChild(), WSType::SpecialContent, *aPoint.GetChild(), WSType::SpecialContent,
mBlockInlineCheck); mBlockInlineCheck);
} }
const auto atNextChar = const auto atNextChar = GetInclusiveNextCharPoint<EditorDOMPoint>(aPoint);
GetInclusiveNextEditableCharPoint<EditorDOMPoint>(aPoint);
// When it's a non-empty text node, return it. // When it's a non-empty text node, return it.
if (atNextChar.IsSet() && !atNextChar.IsContainerEmpty()) { if (atNextChar.IsSet() && !atNextChar.IsContainerEmpty()) {
return WSScanResult(WSScanResult::ScanDirection::Forward, atNextChar, return WSScanResult(WSScanResult::ScanDirection::Forward, atNextChar,
@@ -293,15 +294,6 @@ EditorDOMPointType WSRunScanner::GetFirstVisiblePoint(Text& aTextNode) {
return invisibleWhiteSpaceRange.EndRef().To<EditorDOMPointType>(); return invisibleWhiteSpaceRange.EndRef().To<EditorDOMPointType>();
} }
char16_t WSRunScanner::GetCharAt(Text* aTextNode, uint32_t aOffset) const {
// return 0 if we can't get a char, for whatever reason
if (NS_WARN_IF(!aTextNode) ||
NS_WARN_IF(aOffset >= aTextNode->TextDataLength())) {
return 0;
}
return aTextNode->TextFragment().CharAt(aOffset);
}
/***************************************************************************** /*****************************************************************************
* Implementation for new white-space normalizer * Implementation for new white-space normalizer
*****************************************************************************/ *****************************************************************************/

View File

@@ -435,14 +435,14 @@ class MOZ_STACK_CLASS WSRunScanner final {
} }
template <typename EditorDOMPointType> template <typename EditorDOMPointType>
WSRunScanner(const Element* aEditingHost, WSRunScanner(Scan aScanMode, const EditorDOMPointType& aScanStartPoint,
const EditorDOMPointType& aScanStartPoint, BlockInlineCheck aBlockInlineCheck,
BlockInlineCheck aBlockInlineCheck) const Element* aAncestorLimiter = nullptr)
: mScanStartPoint(aScanStartPoint.template To<EditorDOMPoint>()), : mScanStartPoint(aScanStartPoint.template To<EditorDOMPoint>()),
mEditingHost(const_cast<Element*>(aEditingHost)), mTextFragmentDataAtStart(aScanMode, mScanStartPoint, aBlockInlineCheck,
mTextFragmentDataAtStart(Scan::EditableNodes, mScanStartPoint, aAncestorLimiter),
aBlockInlineCheck), mBlockInlineCheck(aBlockInlineCheck),
mBlockInlineCheck(aBlockInlineCheck) {} mScanMode(aScanMode) {}
// ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom() returns the first visible // ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom() returns the first visible
// node at or after aPoint. If there is no visible nodes after aPoint, // node at or after aPoint. If there is no visible nodes after aPoint,
@@ -457,7 +457,8 @@ class MOZ_STACK_CLASS WSRunScanner final {
static WSScanResult ScanInclusiveNextVisibleNodeOrBlockBoundary( static WSScanResult ScanInclusiveNextVisibleNodeOrBlockBoundary(
const Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint, const Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint,
BlockInlineCheck aBlockInlineCheck) { BlockInlineCheck aBlockInlineCheck) {
return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck) return WSRunScanner(Scan::EditableNodes, aPoint, aBlockInlineCheck,
aEditingHost)
.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(aPoint); .ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(aPoint);
} }
@@ -474,7 +475,8 @@ class MOZ_STACK_CLASS WSRunScanner final {
static WSScanResult ScanPreviousVisibleNodeOrBlockBoundary( static WSScanResult ScanPreviousVisibleNodeOrBlockBoundary(
const Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint, const Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint,
BlockInlineCheck aBlockInlineCheck) { BlockInlineCheck aBlockInlineCheck) {
return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck) return WSRunScanner(Scan::EditableNodes, aPoint, aBlockInlineCheck,
aEditingHost)
.ScanPreviousVisibleNodeOrBlockBoundaryFrom(aPoint); .ScanPreviousVisibleNodeOrBlockBoundaryFrom(aPoint);
} }
@@ -494,8 +496,9 @@ class MOZ_STACK_CLASS WSRunScanner final {
return EditorDOMPointType(aPoint.template ContainerAs<Text>(), return EditorDOMPointType(aPoint.template ContainerAs<Text>(),
aPoint.Offset()); aPoint.Offset());
} }
return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck) return WSRunScanner(Scan::EditableNodes, aPoint, aBlockInlineCheck,
.GetInclusiveNextEditableCharPoint<EditorDOMPointType>(aPoint); aEditingHost)
.GetInclusiveNextCharPoint<EditorDOMPointType>(aPoint);
} }
/** /**
@@ -513,8 +516,9 @@ class MOZ_STACK_CLASS WSRunScanner final {
return EditorDOMPointType(aPoint.template ContainerAs<Text>(), return EditorDOMPointType(aPoint.template ContainerAs<Text>(),
aPoint.Offset() - 1); aPoint.Offset() - 1);
} }
return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck) return WSRunScanner(Scan::EditableNodes, aPoint, aBlockInlineCheck,
.GetPreviousEditableCharPoint<EditorDOMPointType>(aPoint); aEditingHost)
.GetPreviousCharPoint<EditorDOMPointType>(aPoint);
} }
/** /**
@@ -719,11 +723,6 @@ class MOZ_STACK_CLASS WSRunScanner final {
return TextFragmentDataAtStartRef().EndReasonBRElementPtr(); return TextFragmentDataAtStartRef().EndReasonBRElementPtr();
} }
/**
* Active editing host when this instance is created.
*/
Element* GetEditingHost() const { return mEditingHost; }
protected: protected:
using EditorType = EditorBase::EditorType; using EditorType = EditorBase::EditorType;
@@ -845,34 +844,36 @@ class MOZ_STACK_CLASS WSRunScanner final {
using PointPosition = VisibleWhiteSpacesData::PointPosition; using PointPosition = VisibleWhiteSpacesData::PointPosition;
/** /**
* GetInclusiveNextEditableCharPoint() returns aPoint if it points a character * Return aPoint if it points a character in a `Text` node, or start of next
* in an editable text node, or start of next editable text node otherwise. * `Text` node otherwise.
* FYI: For the performance, this does not check whether given container * FYI: For the performance, this does not check whether given container is
* is not after mStart.mReasonContent or not. * not after mStart.mReasonContent or not.
*/ */
template <typename EditorDOMPointType = EditorDOMPointInText, typename PT, template <typename EditorDOMPointType, typename PT, typename CT>
typename CT> EditorDOMPointType GetInclusiveNextCharPoint(
EditorDOMPointType GetInclusiveNextEditableCharPoint(
const EditorDOMPointBase<PT, CT>& aPoint) const { const EditorDOMPointBase<PT, CT>& aPoint) const {
return TextFragmentDataAtStartRef() return TextFragmentDataAtStartRef()
.GetInclusiveNextCharPoint<EditorDOMPointType>( .GetInclusiveNextCharPoint<EditorDOMPointType>(
aPoint, IgnoreNonEditableNodes::Yes); aPoint, mScanMode == Scan::EditableNodes
? IgnoreNonEditableNodes::Yes
: IgnoreNonEditableNodes::No);
} }
/** /**
* GetPreviousEditableCharPoint() returns previous editable point in a * Return the previous editable point in a `Text` node. Note that this
* text node. Note that this returns last character point when it meets * returns the last character point when it meets non-empty text node,
* non-empty text node, otherwise, returns a point in an empty text node. * otherwise, returns a point in an empty text node.
* FYI: For the performance, this does not check whether given container * FYI: For the performance, this does not check whether given container is
* is not before mEnd.mReasonContent or not. * not before mEnd.mReasonContent or not.
*/ */
template <typename EditorDOMPointType = EditorDOMPointInText, typename PT, template <typename EditorDOMPointType, typename PT, typename CT>
typename CT> EditorDOMPointType GetPreviousCharPoint(
EditorDOMPointType GetPreviousEditableCharPoint(
const EditorDOMPointBase<PT, CT>& aPoint) const { const EditorDOMPointBase<PT, CT>& aPoint) const {
return TextFragmentDataAtStartRef() return TextFragmentDataAtStartRef()
.GetPreviousCharPoint<EditorDOMPointType>(aPoint, .GetPreviousCharPoint<EditorDOMPointType>(
IgnoreNonEditableNodes::Yes); aPoint, mScanMode == Scan::EditableNodes
? IgnoreNonEditableNodes::Yes
: IgnoreNonEditableNodes::No);
} }
/** /**
@@ -882,7 +883,7 @@ class MOZ_STACK_CLASS WSRunScanner final {
* Note that this may return different text node from the container of * Note that this may return different text node from the container of
* aPointAtASCIIWhiteSpace. * aPointAtASCIIWhiteSpace.
*/ */
template <typename EditorDOMPointType = EditorDOMPointInText> template <typename EditorDOMPointType>
EditorDOMPointType GetEndOfCollapsibleASCIIWhiteSpaces( EditorDOMPointType GetEndOfCollapsibleASCIIWhiteSpaces(
const EditorDOMPointInText& aPointAtASCIIWhiteSpace, const EditorDOMPointInText& aPointAtASCIIWhiteSpace,
nsIEditor::EDirection aDirectionToDelete) const { nsIEditor::EDirection aDirectionToDelete) const {
@@ -902,7 +903,7 @@ class MOZ_STACK_CLASS WSRunScanner final {
* Note that this may return different text node from the container of * Note that this may return different text node from the container of
* aPointAtASCIIWhiteSpace. * aPointAtASCIIWhiteSpace.
*/ */
template <typename EditorDOMPointType = EditorDOMPointInText> template <typename EditorDOMPointType>
EditorDOMPointType GetFirstASCIIWhiteSpacePointCollapsedTo( EditorDOMPointType GetFirstASCIIWhiteSpacePointCollapsedTo(
const EditorDOMPointInText& aPointAtASCIIWhiteSpace, const EditorDOMPointInText& aPointAtASCIIWhiteSpace,
nsIEditor::EDirection aDirectionToDelete) const { nsIEditor::EDirection aDirectionToDelete) const {
@@ -914,11 +915,6 @@ class MOZ_STACK_CLASS WSRunScanner final {
aPointAtASCIIWhiteSpace, aDirectionToDelete); aPointAtASCIIWhiteSpace, aDirectionToDelete);
} }
EditorDOMPointInText GetPreviousCharPointFromPointInText(
const EditorDOMPointInText& aPoint) const;
char16_t GetCharAt(Text* aTextNode, uint32_t aOffset) const;
/** /**
* TextFragmentData stores the information of white-space sequence which * TextFragmentData stores the information of white-space sequence which
* contains `aPoint` of the constructor. * contains `aPoint` of the constructor.
@@ -1524,9 +1520,6 @@ class MOZ_STACK_CLASS WSRunScanner final {
// Together, the above represent the point at which we are building up ws // Together, the above represent the point at which we are building up ws
// info. // info.
// The editing host when the instance is created.
RefPtr<Element> mEditingHost;
private: private:
/** /**
* ComputeRangeInTextNodesContainingInvisibleWhiteSpaces() returns range * ComputeRangeInTextNodesContainingInvisibleWhiteSpaces() returns range
@@ -1545,6 +1538,7 @@ class MOZ_STACK_CLASS WSRunScanner final {
TextFragmentData mTextFragmentDataAtStart; TextFragmentData mTextFragmentDataAtStart;
const BlockInlineCheck mBlockInlineCheck; const BlockInlineCheck mBlockInlineCheck;
const Scan mScanMode;
friend class WhiteSpaceVisibilityKeeper; friend class WhiteSpaceVisibilityKeeper;
}; };