Bug 1885822 - part 2: Make `WSScanResult` always have non-null `mContent` if it reached something r=m_kato

Currently, it checks whether `mContent` is `nullptr` or not even if the scanner
reached something.  However, this makes the users of this object check whether
it has reasonable content or not and that makes the users messy.  Therefore,
the scanning method should guarantee that it's always error if it does not reach
any content.

Depends on D207681

Differential Revision: https://phabricator.services.mozilla.com/D207682
This commit is contained in:
Masayuki Nakano 2024-04-22 06:31:10 +00:00
Родитель 83e6cf0743
Коммит 7edcf9c3ee
8 изменённых файлов: 118 добавлений и 90 удалений

Просмотреть файл

@ -1604,7 +1604,7 @@ nsresult HTMLEditor::InsertLineBreakAsSubAction() {
NS_WARNING("Inserted <br> was unexpectedly removed");
return Err(NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE);
}
WSScanResult backwardScanFromBeforeBRElementResult =
const WSScanResult backwardScanFromBeforeBRElementResult =
WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundary(
editingHost,
EditorDOMPoint(unwrappedInsertBRElementResult.GetNewNode()),
@ -1615,7 +1615,7 @@ nsresult HTMLEditor::InsertLineBreakAsSubAction() {
return Err(NS_ERROR_FAILURE);
}
WSScanResult forwardScanFromAfterBRElementResult =
const WSScanResult forwardScanFromAfterBRElementResult =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
editingHost, pointToPutCaret,
BlockInlineCheck::UseComputedDisplayStyle);
@ -2254,7 +2254,7 @@ Result<CreateElementResult, nsresult> HTMLEditor::HandleInsertBRElement(
aEditingHost, {EmptyCheckOption::TreatNonEditableContentAsInvisible});
WSRunScanner wsRunScanner(&aEditingHost, aPointToBreak,
BlockInlineCheck::UseComputedDisplayStyle);
WSScanResult backwardScanResult =
const WSScanResult backwardScanResult =
wsRunScanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(aPointToBreak);
if (MOZ_UNLIKELY(backwardScanResult.Failed())) {
NS_WARNING(
@ -2262,7 +2262,7 @@ Result<CreateElementResult, nsresult> HTMLEditor::HandleInsertBRElement(
return Err(NS_ERROR_FAILURE);
}
const bool brElementIsAfterBlock = backwardScanResult.ReachedBlockBoundary();
WSScanResult forwardScanResult =
const WSScanResult forwardScanResult =
wsRunScanner.ScanNextVisibleNodeOrBlockBoundaryFrom(aPointToBreak);
if (MOZ_UNLIKELY(forwardScanResult.Failed())) {
NS_WARNING("WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom() failed");
@ -2383,7 +2383,7 @@ Result<CreateElementResult, nsresult> HTMLEditor::HandleInsertBRElement(
std::move(pointToPutCaret));
}
WSScanResult forwardScanFromAfterBRElementResult =
const WSScanResult forwardScanFromAfterBRElementResult =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
&aEditingHost, afterBRElement,
BlockInlineCheck::UseComputedDisplayStyle);
@ -2612,7 +2612,7 @@ HTMLEditor::HandleInsertParagraphInMailCiteElement(
// mailquote (in either inline or block case). The latter can confuse a
// user if they click there and start typing, because being in the
// mailquote may affect wrapping behavior, or font color, etc.
WSScanResult forwardScanFromPointToSplitResult =
const WSScanResult forwardScanFromPointToSplitResult =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
&aEditingHost, pointToSplit, BlockInlineCheck::UseHTMLDefaultStyle);
if (forwardScanFromPointToSplitResult.Failed()) {
@ -2726,7 +2726,7 @@ HTMLEditor::HandleInsertParagraphInMailCiteElement(
// XXX Cannot we replace this complicated check with just a call of
// HTMLEditUtils::IsVisibleBRElement with
// resultOfInsertingBRElement.inspect()?
WSScanResult backwardScanFromPointToCreateNewBRElementResult =
const WSScanResult backwardScanFromPointToCreateNewBRElementResult =
WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundary(
&aEditingHost, pointToCreateNewBRElement,
BlockInlineCheck::UseComputedDisplayStyle);
@ -2743,7 +2743,7 @@ HTMLEditor::HandleInsertParagraphInMailCiteElement(
.ReachedSpecialContent()) {
return NS_SUCCESS_DOM_NO_OPERATION;
}
WSScanResult forwardScanFromPointAfterNewBRElementResult =
const WSScanResult forwardScanFromPointAfterNewBRElementResult =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
&aEditingHost,
EditorRawDOMPoint::After(pointToCreateNewBRElement),
@ -7654,7 +7654,7 @@ HTMLEditor::GetRangeExtendedToHardLineEdgesForBlockEditAction(
// element even if selected in a blocked phrase element or
// non-HTMLelement.
BlockInlineCheck::UseHTMLDefaultStyle);
WSScanResult scanResultAtEnd =
const WSScanResult scanResultAtEnd =
wsScannerAtEnd.ScanPreviousVisibleNodeOrBlockBoundaryFrom(endPoint);
if (scanResultAtEnd.Failed()) {
NS_WARNING(
@ -7692,7 +7692,7 @@ HTMLEditor::GetRangeExtendedToHardLineEdgesForBlockEditAction(
// selection past that, it would visibly change meaning of users selection.
WSRunScanner wsScannerAtStart(&aEditingHost, startPoint,
BlockInlineCheck::UseHTMLDefaultStyle);
WSScanResult scanResultAtStart =
const WSScanResult scanResultAtStart =
wsScannerAtStart.ScanNextVisibleNodeOrBlockBoundaryFrom(startPoint);
if (scanResultAtStart.Failed()) {
NS_WARNING("WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom() failed");
@ -8944,7 +8944,7 @@ HTMLEditor::HandleInsertParagraphInListItemElement(
// If the right list item element is not empty, we need to consider where to
// put caret in it. If it has non-container inline elements, <br> or <hr>, at
// the element is proper position.
WSScanResult forwardScanFromStartOfListItemResult =
const WSScanResult forwardScanFromStartOfListItemResult =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
&aEditingHost, EditorRawDOMPoint(&rightListItemElement, 0u),
BlockInlineCheck::UseComputedDisplayStyle);

Просмотреть файл

@ -2203,7 +2203,7 @@ nsIContent* HTMLEditUtils::GetContentToPreserveInlineStyles(
return aPoint.template ContainerAs<nsIContent>();
}
for (auto point = aPoint.template To<EditorRawDOMPoint>(); point.IsSet();) {
WSScanResult nextVisibleThing =
const WSScanResult nextVisibleThing =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
&aEditingHost, point,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
@ -2215,8 +2215,8 @@ nsIContent* HTMLEditUtils::GetContentToPreserveInlineStyles(
// view of users.
if (nextVisibleThing.ReachedSpecialContent() &&
nextVisibleThing.IsContentEditable() &&
nextVisibleThing.GetContent()->IsElement() &&
!nextVisibleThing.GetContent()->HasChildNodes() &&
nextVisibleThing.ContentIsElement() &&
!nextVisibleThing.ElementPtr()->HasChildNodes() &&
HTMLEditUtils::IsContainerNode(*nextVisibleThing.ElementPtr())) {
point.SetAfter(nextVisibleThing.ElementPtr());
continue;
@ -2260,13 +2260,12 @@ EditorDOMPointType HTMLEditUtils::GetBetterInsertionPointFor(
// If the insertion position is after the last visible item in a line,
// i.e., the insertion position is just before a visible line break <br>,
// we want to skip to the position just after the line break (see bug 68767).
WSScanResult forwardScanFromPointToInsertResult =
const WSScanResult forwardScanFromPointToInsertResult =
wsScannerForPointToInsert.ScanNextVisibleNodeOrBlockBoundaryFrom(
pointToInsert);
// So, if the next visible node isn't a <br> element, we can insert the block
// level element to the point.
if (!forwardScanFromPointToInsertResult.GetContent() ||
!forwardScanFromPointToInsertResult.ReachedBRElement()) {
if (!forwardScanFromPointToInsertResult.ReachedBRElement()) {
return pointToInsert;
}
@ -2274,7 +2273,7 @@ EditorDOMPointType HTMLEditUtils::GetBetterInsertionPointFor(
// positioned at the beginning of a block, in that case skipping the <br>
// would not insert the <br> at the caret position, but after the current
// empty line.
WSScanResult backwardScanFromPointToInsertResult =
const WSScanResult backwardScanFromPointToInsertResult =
wsScannerForPointToInsert.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
pointToInsert);
// So, if there is no previous visible node,
@ -2282,7 +2281,7 @@ EditorDOMPointType HTMLEditUtils::GetBetterInsertionPointFor(
// or, if the previous visible node is different block,
// we need to skip the following <br>. So, otherwise, we can insert the
// block at the insertion point.
if (!backwardScanFromPointToInsertResult.GetContent() ||
if (backwardScanFromPointToInsertResult.Failed() ||
backwardScanFromPointToInsertResult.ReachedBRElement() ||
backwardScanFromPointToInsertResult.ReachedCurrentBlockBoundary()) {
return pointToInsert;
@ -2310,7 +2309,7 @@ EditorDOMPointType HTMLEditUtils::GetBetterCaretPositionToInsertText(
if (aPoint.IsEndOfContainer()) {
WSRunScanner scanner(&aEditingHost, aPoint,
BlockInlineCheck::UseComputedDisplayStyle);
WSScanResult previousThing =
const WSScanResult previousThing =
scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(aPoint);
if (previousThing.InVisibleOrCollapsibleCharacters()) {
return EditorDOMPointType::AtEndOf(*previousThing.TextPtr());

Просмотреть файл

@ -1150,7 +1150,7 @@ nsresult HTMLEditor::MaybeCollapseSelectionAtFirstEditableNode(
if (Text* text = leafContent->GetAsText()) {
// If there is editable and visible text node, move caret at first of
// the visible character.
WSScanResult scanResultInTextNode =
const WSScanResult scanResultInTextNode =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
editingHost, EditorRawDOMPoint(text, 0),
BlockInlineCheck::UseComputedDisplayStyle);

Просмотреть файл

@ -505,7 +505,7 @@ HTMLEditor::HTMLWithContextInserter::GetNewCaretPointAfterInsertingHTML(
editingHost,
EditorDOMPoint(wsRunScannerAtCaret.GetStartReasonContent()),
BlockInlineCheck::UseComputedDisplayStyle);
WSScanResult backwardScanFromPointToCaretResult =
const WSScanResult backwardScanFromPointToCaretResult =
wsRunScannerAtStartReason.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
pointToPutCaret);
if (backwardScanFromPointToCaretResult.InVisibleOrCollapsibleCharacters()) {

Просмотреть файл

@ -1371,7 +1371,7 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDelete(
WSRunScanner wsRunScannerAtCaret(
editingHost, caretPoint,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
WSScanResult scanFromCaretPointResult =
const WSScanResult scanFromCaretPointResult =
aDirectionAndAmount == nsIEditor::eNext
? wsRunScannerAtCaret.ScanNextVisibleNodeOrBlockBoundaryFrom(
caretPoint)
@ -1383,26 +1383,21 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDelete(
"failed");
return NS_ERROR_FAILURE;
}
if (!scanFromCaretPointResult.GetContent()) {
return NS_SUCCESS_DOM_NO_OPERATION;
}
MOZ_ASSERT(scanFromCaretPointResult.GetContent());
if (scanFromCaretPointResult.ReachedBRElement()) {
if (scanFromCaretPointResult.BRElementPtr() ==
wsRunScannerAtCaret.GetEditingHost()) {
return NS_OK;
}
if (!EditorUtils::IsEditableContent(
*scanFromCaretPointResult.BRElementPtr(), EditorType::HTML)) {
if (!scanFromCaretPointResult.IsContentEditable()) {
return NS_SUCCESS_DOM_NO_OPERATION;
}
if (HTMLEditUtils::IsInvisibleBRElement(
*scanFromCaretPointResult.BRElementPtr())) {
if (scanFromCaretPointResult.ReachedInvisibleBRElement()) {
EditorDOMPoint newCaretPosition =
aDirectionAndAmount == nsIEditor::eNext
? EditorDOMPoint::After(
*scanFromCaretPointResult.BRElementPtr())
: EditorDOMPoint(scanFromCaretPointResult.BRElementPtr());
? scanFromCaretPointResult.PointAfterContent<EditorDOMPoint>()
: scanFromCaretPointResult.PointAtContent<EditorDOMPoint>();
if (NS_WARN_IF(!newCaretPosition.IsSet())) {
return NS_ERROR_FAILURE;
}
@ -1450,7 +1445,7 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDelete(
// Otherwise, extend the range to contain the invisible `<br>`
// element.
if (EditorRawDOMPoint(scanFromCaretPointResult.BRElementPtr())
if (scanFromCaretPointResult.PointAtContent<EditorRawDOMPoint>()
.IsBefore(
aRangesToDelete
.GetFirstRangeStartPoint<EditorRawDOMPoint>())) {
@ -1463,12 +1458,11 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDelete(
return rv;
}
if (aRangesToDelete.GetFirstRangeEndPoint<EditorRawDOMPoint>()
.IsBefore(EditorRawDOMPoint::After(
*scanFromCaretPointResult.BRElementPtr()))) {
.IsBefore(scanFromCaretPointResult
.PointAfterContent<EditorRawDOMPoint>())) {
nsresult rv = aRangesToDelete.FirstRangeRef()->SetStartAndEnd(
aRangesToDelete.FirstRangeRef()->StartRef(),
EditorRawDOMPoint::After(
*scanFromCaretPointResult.BRElementPtr())
scanFromCaretPointResult.PointAfterContent<EditorRawDOMPoint>()
.ToRawRangeBoundary());
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"nsRange::SetStartAndEnd() failed");
@ -1670,7 +1664,7 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::Run(
WSRunScanner wsRunScannerAtCaret(
&aEditingHost, caretPoint.ref(),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
WSScanResult scanFromCaretPointResult =
const WSScanResult scanFromCaretPointResult =
aDirectionAndAmount == nsIEditor::eNext
? wsRunScannerAtCaret.ScanNextVisibleNodeOrBlockBoundaryFrom(
caretPoint.ref())
@ -1682,20 +1676,17 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::Run(
"failed");
return Err(NS_ERROR_FAILURE);
}
if (!scanFromCaretPointResult.GetContent()) {
return EditActionResult::CanceledResult();
}
MOZ_ASSERT(scanFromCaretPointResult.GetContent());
// Short circuit for invisible breaks. delete them and recurse.
if (scanFromCaretPointResult.ReachedBRElement()) {
if (scanFromCaretPointResult.BRElementPtr() == &aEditingHost) {
return EditActionResult::HandledResult();
}
if (!EditorUtils::IsEditableContent(
*scanFromCaretPointResult.BRElementPtr(), EditorType::HTML)) {
if (!scanFromCaretPointResult.IsContentEditable()) {
return EditActionResult::CanceledResult();
}
if (HTMLEditUtils::IsInvisibleBRElement(
*scanFromCaretPointResult.BRElementPtr())) {
if (scanFromCaretPointResult.ReachedInvisibleBRElement()) {
// TODO: We should extend the range to delete again before/after
// the caret point and use `HandleDeleteNonCollapsedRanges()`
// instead after we would create delete range computation
@ -1728,7 +1719,7 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::Run(
WSRunScanner wsRunScannerAtCaret(
&aEditingHost, caretPoint.ref(),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
WSScanResult scanFromCaretPointResult =
const WSScanResult scanFromCaretPointResult =
aDirectionAndAmount == nsIEditor::eNext
? wsRunScannerAtCaret
.ScanNextVisibleNodeOrBlockBoundaryFrom(
@ -1742,7 +1733,7 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::Run(
"VisibleNodeOrBlockBoundaryFrom() failed");
return Err(NS_ERROR_FAILURE);
}
if (MOZ_UNLIKELY(
if (NS_WARN_IF(
scanFromCaretPointResult.ReachedInvisibleBRElement())) {
return Err(NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE);
}
@ -1826,7 +1817,7 @@ HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDeleteAroundCollapsedRanges(
}
if (aScanFromCaretPointResult.ReachedOtherBlockElement()) {
if (NS_WARN_IF(!aScanFromCaretPointResult.GetContent()->IsElement())) {
if (NS_WARN_IF(!aScanFromCaretPointResult.ContentIsElement())) {
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(!aRangesToDelete.Ranges().IsEmpty());
@ -1855,7 +1846,7 @@ HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDeleteAroundCollapsedRanges(
}
if (aScanFromCaretPointResult.ReachedCurrentBlockBoundary()) {
if (NS_WARN_IF(!aScanFromCaretPointResult.GetContent()->IsElement())) {
if (NS_WARN_IF(!aScanFromCaretPointResult.ContentIsElement())) {
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(!aRangesToDelete.Ranges().IsEmpty());
@ -1959,7 +1950,7 @@ HTMLEditor::AutoDeleteRangesHandler::HandleDeleteAroundCollapsedRanges(
}
if (aScanFromCaretPointResult.InNonCollapsibleCharacters()) {
if (NS_WARN_IF(!aScanFromCaretPointResult.GetContent()->IsText())) {
if (NS_WARN_IF(!aScanFromCaretPointResult.ContentIsText())) {
return Err(NS_ERROR_FAILURE);
}
Result<CaretPoint, nsresult> caretPointOrError =
@ -2019,7 +2010,7 @@ HTMLEditor::AutoDeleteRangesHandler::HandleDeleteAroundCollapsedRanges(
}
if (aScanFromCaretPointResult.ReachedOtherBlockElement()) {
if (NS_WARN_IF(!aScanFromCaretPointResult.GetContent()->IsElement())) {
if (NS_WARN_IF(!aScanFromCaretPointResult.ContentIsElement())) {
return Err(NS_ERROR_FAILURE);
}
MOZ_ASSERT(!aRangesToDelete.Ranges().IsEmpty());
@ -2050,7 +2041,7 @@ HTMLEditor::AutoDeleteRangesHandler::HandleDeleteAroundCollapsedRanges(
}
if (aScanFromCaretPointResult.ReachedCurrentBlockBoundary()) {
if (NS_WARN_IF(!aScanFromCaretPointResult.GetContent()->IsElement())) {
if (NS_WARN_IF(!aScanFromCaretPointResult.ContentIsElement())) {
return Err(NS_ERROR_FAILURE);
}
MOZ_ASSERT(!aRangesToDelete.Ranges().IsEmpty());
@ -2519,7 +2510,7 @@ bool HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::
// Next to a block. See if we are between the block and a `<br>`.
// If so, we really want to delete the `<br>`. Else join content at
// selection to the block.
WSScanResult scanFromCaretResult =
const WSScanResult scanFromCaretResult =
aDirectionAndAmount == nsIEditor::eNext
? aWSRunScannerAtCaret.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
aCaretPoint)
@ -2564,7 +2555,7 @@ HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::DeleteBRElement(
}
WSRunScanner scanner(&aEditingHost, EditorRawDOMPoint(mBRElement),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
WSScanResult maybePreviousText =
const WSScanResult maybePreviousText =
scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
EditorRawDOMPoint(mBRElement));
if (maybePreviousText.IsContentEditable() &&
@ -2572,8 +2563,9 @@ HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::DeleteBRElement(
!HTMLEditor::GetLinkElement(maybePreviousText.TextPtr())) {
return maybePreviousText.Point<EditorDOMPoint>();
}
WSScanResult maybeNextText = scanner.ScanNextVisibleNodeOrBlockBoundaryFrom(
EditorRawDOMPoint::After(*mBRElement));
const WSScanResult maybeNextText =
scanner.ScanNextVisibleNodeOrBlockBoundaryFrom(
EditorRawDOMPoint::After(*mBRElement));
if (maybeNextText.IsContentEditable() &&
maybeNextText.InVisibleOrCollapsibleCharacters()) {
return maybeNextText.Point<EditorDOMPoint>();
@ -3744,7 +3736,7 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::
aHTMLEditor.GetEditAction())) {
WSRunScanner scanner(&aEditingHost, startOfRightContent,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
WSScanResult maybePreviousText =
const WSScanResult maybePreviousText =
scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(startOfRightContent);
if (maybePreviousText.IsContentEditable() &&
maybePreviousText.InVisibleOrCollapsibleCharacters()) {
@ -4319,7 +4311,7 @@ HTMLEditor::AutoDeleteRangesHandler::DeleteParentBlocksWithTransactionIfEmpty(
}
// Next, check there is visible contents after the point in current block.
WSScanResult forwardScanFromPointResult =
const WSScanResult forwardScanFromPointResult =
wsScannerForPoint.ScanNextVisibleNodeOrBlockBoundaryFrom(aPoint);
if (forwardScanFromPointResult.Failed()) {
NS_WARNING("WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom() failed");
@ -4340,7 +4332,7 @@ HTMLEditor::AutoDeleteRangesHandler::DeleteParentBlocksWithTransactionIfEmpty(
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
if (wsScannerForPoint.GetEndReasonContent()->GetNextSibling()) {
WSScanResult scanResult =
const WSScanResult scanResult =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
editingHost,
EditorRawDOMPoint::After(
@ -5169,7 +5161,7 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::
aHTMLEditor.GetEditAction())) {
WSRunScanner scanner(&aEditingHost, startOfRightContent,
BlockInlineCheck::UseComputedDisplayStyle);
WSScanResult maybePreviousText =
const WSScanResult maybePreviousText =
scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(startOfRightContent);
if (maybePreviousText.IsContentEditable() &&
maybePreviousText.InVisibleOrCollapsibleCharacters()) {
@ -6798,7 +6790,7 @@ HTMLEditor::AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete(
if (rangeToDelete.StartRef().GetContainer() !=
closestBlockAncestorOrInlineEditingHost) {
for (;;) {
WSScanResult backwardScanFromStartResult =
const WSScanResult backwardScanFromStartResult =
WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundary(
closestEditingHost, rangeToDelete.StartRef(),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
@ -6856,7 +6848,7 @@ HTMLEditor::AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete(
WSRunScanner wsScannerAtEnd(
closestEditingHost, rangeToDelete.EndRef(),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
WSScanResult forwardScanFromEndResult =
const WSScanResult forwardScanFromEndResult =
wsScannerAtEnd.ScanNextVisibleNodeOrBlockBoundaryFrom(
rangeToDelete.EndRef());
if (forwardScanFromEndResult.ReachedBRElement()) {

Просмотреть файл

@ -1914,7 +1914,7 @@ HTMLEditor::AutoInlineStyleSetter::ExtendOrShrinkRangeToApplyTheStyle(
// range to contain the <br> element.
EditorDOMRange range(aRange);
if (range.EndRef().IsInContentNode()) {
WSScanResult nextContentData =
const WSScanResult nextContentData =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
&aEditingHost, range.EndRef(),
BlockInlineCheck::UseComputedDisplayOutsideStyle);

Просмотреть файл

@ -1723,17 +1723,21 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
MOZ_ASSERT(aPoint.IsSet());
MOZ_ASSERT(aPoint.IsInComposedDoc());
if (MOZ_UNLIKELY(!aPoint.IsSet())) {
return WSScanResult::Error();
}
// We may not be able to check editable state in uncomposed tree as expected.
// For example, only some descendants in an editing host is temporarily
// removed from the tree, they are not editable unless nested contenteditable
// attribute is set to "true".
if (MOZ_UNLIKELY(!aPoint.IsInComposedDoc())) {
return WSScanResult(aPoint.template ContainerAs<nsIContent>(),
return WSScanResult(*aPoint.template ContainerAs<nsIContent>(),
WSType::InUncomposedDoc, mBlockInlineCheck);
}
if (!TextFragmentDataAtStartRef().IsInitialized()) {
return WSScanResult(nullptr, WSType::UnexpectedError, mBlockInlineCheck);
return WSScanResult::Error();
}
// If the range has visible text and start of the visible text is before
@ -1746,7 +1750,7 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
// things now. Whether keep scanning editable things or not should be
// considered by the caller.
if (aPoint.GetChild() && !aPoint.GetChild()->IsEditable()) {
return WSScanResult(aPoint.GetChild(), WSType::SpecialContent,
return WSScanResult(*aPoint.GetChild(), WSType::SpecialContent,
mBlockInlineCheck);
}
const auto atPreviousChar =
@ -1762,15 +1766,26 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
}
}
if (NS_WARN_IF(TextFragmentDataAtStartRef().StartRawReason() ==
WSType::UnexpectedError)) {
return WSScanResult::Error();
}
// Otherwise, return the start of the range.
if (TextFragmentDataAtStartRef().GetStartReasonContent() !=
TextFragmentDataAtStartRef().StartRef().GetContainer()) {
if (NS_WARN_IF(!TextFragmentDataAtStartRef().GetStartReasonContent())) {
return WSScanResult::Error();
}
// In this case, TextFragmentDataAtStartRef().StartRef().Offset() is not
// meaningful.
return WSScanResult(TextFragmentDataAtStartRef().GetStartReasonContent(),
return WSScanResult(*TextFragmentDataAtStartRef().GetStartReasonContent(),
TextFragmentDataAtStartRef().StartRawReason(),
mBlockInlineCheck);
}
if (NS_WARN_IF(!TextFragmentDataAtStartRef().StartRef().IsSet())) {
return WSScanResult::Error();
}
return WSScanResult(TextFragmentDataAtStartRef().StartRef(),
TextFragmentDataAtStartRef().StartRawReason(),
mBlockInlineCheck);
@ -1782,17 +1797,21 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
MOZ_ASSERT(aPoint.IsSet());
MOZ_ASSERT(aPoint.IsInComposedDoc());
if (MOZ_UNLIKELY(!aPoint.IsSet())) {
return WSScanResult::Error();
}
// We may not be able to check editable state in uncomposed tree as expected.
// For example, only some descendants in an editing host is temporarily
// removed from the tree, they are not editable unless nested contenteditable
// attribute is set to "true".
if (MOZ_UNLIKELY(!aPoint.IsInComposedDoc())) {
return WSScanResult(aPoint.template ContainerAs<nsIContent>(),
return WSScanResult(*aPoint.template ContainerAs<nsIContent>(),
WSType::InUncomposedDoc, mBlockInlineCheck);
}
if (!TextFragmentDataAtStartRef().IsInitialized()) {
return WSScanResult(nullptr, WSType::UnexpectedError, mBlockInlineCheck);
return WSScanResult::Error();
}
// If the range has visible text and aPoint equals or is before the end of the
@ -1805,7 +1824,7 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
// things now. Whether keep scanning editable things or not should be
// considered by the caller.
if (aPoint.GetChild() && !aPoint.GetChild()->IsEditable()) {
return WSScanResult(aPoint.GetChild(), WSType::SpecialContent,
return WSScanResult(*aPoint.GetChild(), WSType::SpecialContent,
mBlockInlineCheck);
}
const auto atNextChar =
@ -1821,15 +1840,26 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
}
}
if (NS_WARN_IF(TextFragmentDataAtStartRef().EndRawReason() ==
WSType::UnexpectedError)) {
return WSScanResult::Error();
}
// Otherwise, return the end of the range.
if (TextFragmentDataAtStartRef().GetEndReasonContent() !=
TextFragmentDataAtStartRef().EndRef().GetContainer()) {
if (NS_WARN_IF(!TextFragmentDataAtStartRef().GetEndReasonContent())) {
return WSScanResult::Error();
}
// In this case, TextFragmentDataAtStartRef().EndRef().Offset() is not
// meaningful.
return WSScanResult(TextFragmentDataAtStartRef().GetEndReasonContent(),
return WSScanResult(*TextFragmentDataAtStartRef().GetEndReasonContent(),
TextFragmentDataAtStartRef().EndRawReason(),
mBlockInlineCheck);
}
if (NS_WARN_IF(!TextFragmentDataAtStartRef().EndRef().IsSet())) {
return WSScanResult::Error();
}
return WSScanResult(TextFragmentDataAtStartRef().EndRef(),
TextFragmentDataAtStartRef().EndRawReason(),
mBlockInlineCheck);

Просмотреть файл

@ -95,11 +95,16 @@ class MOZ_STACK_CLASS WSScanResult final {
friend class WSRunScanner; // Because of WSType.
explicit WSScanResult(WSType aReason) : mReason(aReason) {
MOZ_ASSERT(mReason == WSType::UnexpectedError ||
mReason == WSType::NotInitialized);
}
public:
WSScanResult() = delete;
MOZ_NEVER_INLINE_DEBUG WSScanResult(nsIContent* aContent, WSType aReason,
MOZ_NEVER_INLINE_DEBUG WSScanResult(nsIContent& aContent, WSType aReason,
BlockInlineCheck aBlockInlineCheck)
: mContent(aContent), mReason(aReason) {
: mContent(&aContent), mReason(aReason) {
AssertIfInvalidData(aBlockInlineCheck);
}
MOZ_NEVER_INLINE_DEBUG WSScanResult(const EditorDOMPoint& aPoint,
@ -111,6 +116,8 @@ class MOZ_STACK_CLASS WSScanResult final {
AssertIfInvalidData(aBlockInlineCheck);
}
static WSScanResult Error() { return WSScanResult(WSType::UnexpectedError); }
MOZ_NEVER_INLINE_DEBUG void AssertIfInvalidData(
BlockInlineCheck aBlockInlineCheck) const {
#ifdef DEBUG
@ -124,37 +131,33 @@ class MOZ_STACK_CLASS WSScanResult final {
mReason == WSType::CurrentBlockBoundary ||
mReason == WSType::OtherBlockBoundary);
MOZ_ASSERT_IF(mReason == WSType::UnexpectedError, !mContent);
MOZ_ASSERT_IF(mReason != WSType::UnexpectedError, mContent);
MOZ_ASSERT_IF(mReason == WSType::InUncomposedDoc,
mContent && !mContent->IsInComposedDoc());
!mContent->IsInComposedDoc());
MOZ_ASSERT_IF(mContent && !mContent->IsInComposedDoc(),
mReason == WSType::InUncomposedDoc);
MOZ_ASSERT_IF(mReason == WSType::NonCollapsibleCharacters ||
mReason == WSType::CollapsibleWhiteSpaces,
mContent && mContent->IsText());
mContent->IsText());
MOZ_ASSERT_IF(mReason == WSType::BRElement,
mContent && mContent->IsHTMLElement(nsGkAtoms::br));
MOZ_ASSERT_IF(mReason == WSType::PreformattedLineBreak,
mContent && mContent->IsText() &&
EditorUtils::IsNewLinePreformatted(*mContent));
mContent->IsHTMLElement(nsGkAtoms::br));
MOZ_ASSERT_IF(
mReason == WSType::PreformattedLineBreak,
mContent->IsText() && EditorUtils::IsNewLinePreformatted(*mContent));
MOZ_ASSERT_IF(
mReason == WSType::SpecialContent,
mContent &&
((mContent->IsText() && !mContent->IsEditable()) ||
(!mContent->IsHTMLElement(nsGkAtoms::br) &&
!HTMLEditUtils::IsBlockElement(*mContent, aBlockInlineCheck))));
(mContent->IsText() && !mContent->IsEditable()) ||
(!mContent->IsHTMLElement(nsGkAtoms::br) &&
!HTMLEditUtils::IsBlockElement(*mContent, aBlockInlineCheck)));
MOZ_ASSERT_IF(mReason == WSType::OtherBlockBoundary,
mContent && HTMLEditUtils::IsBlockElement(*mContent,
aBlockInlineCheck));
HTMLEditUtils::IsBlockElement(*mContent, aBlockInlineCheck));
// If mReason is WSType::CurrentBlockBoundary, mContent can be any content.
// In most cases, it's current block element which is editable. However, if
// there is no editable block parent, this is topmost editable inline
// content. Additionally, if there is no editable content, this is the
// container start of scanner and is not editable.
if (mReason == WSType::CurrentBlockBoundary) {
if (!mContent ||
// This is what the most preferred result is mContent itself is a
// block.
HTMLEditUtils::IsBlockElement(*mContent, aBlockInlineCheck) ||
if (HTMLEditUtils::IsBlockElement(*mContent, aBlockInlineCheck) ||
// If mContent is not editable, we cannot check whether there is no
// block ancestor in the limiter which we don't have. Therefore,
// let's skip the ancestor check.
@ -193,6 +196,10 @@ class MOZ_STACK_CLASS WSScanResult final {
return mContent && mContent->IsElement();
}
[[nodiscard]] bool ContentIsText() const {
return mContent && mContent->IsText();
}
/**
* The following accessors makes it easier to understand each callers.
*/