forked from mirrors/gecko-dev
Bug 1891408 - part 2: Make WSScanResult::PointAtContent() return a point in a text node r=m_kato
When it's called, it just returns at the reached content node. However, this does not make sense when it reached a character in the text node. Depends on D207685 Differential Revision: https://phabricator.services.mozilla.com/D207686
This commit is contained in:
parent
49d46d78d6
commit
31cdc09f52
7 changed files with 179 additions and 81 deletions
|
|
@ -1616,7 +1616,7 @@ nsresult HTMLEditor::InsertLineBreakAsSubAction() {
|
|||
}
|
||||
|
||||
const WSScanResult forwardScanFromAfterBRElementResult =
|
||||
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
|
||||
WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundary(
|
||||
editingHost, pointToPutCaret,
|
||||
BlockInlineCheck::UseComputedDisplayStyle);
|
||||
if (MOZ_UNLIKELY(forwardScanFromAfterBRElementResult.Failed())) {
|
||||
|
|
@ -1663,8 +1663,8 @@ nsresult HTMLEditor::InsertLineBreakAsSubAction() {
|
|||
} else if (forwardScanFromAfterBRElementResult.ReachedSpecialContent()) {
|
||||
// Next inserting text should be inserted into styled inline elements if
|
||||
// they have first visible thing in the new line.
|
||||
pointToPutCaret =
|
||||
forwardScanFromAfterBRElementResult.PointAtContent<EditorDOMPoint>();
|
||||
pointToPutCaret = forwardScanFromAfterBRElementResult
|
||||
.PointAtReachedContent<EditorDOMPoint>();
|
||||
}
|
||||
|
||||
nsresult rv = CollapseSelectionTo(pointToPutCaret);
|
||||
|
|
@ -2281,7 +2281,8 @@ Result<CreateElementResult, nsresult> HTMLEditor::HandleInsertBRElement(
|
|||
// now.
|
||||
backwardScanResult.ReachedInlineEditingHostBoundary();
|
||||
const WSScanResult forwardScanResult =
|
||||
wsRunScanner.ScanNextVisibleNodeOrBlockBoundaryFrom(aPointToBreak);
|
||||
wsRunScanner.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(
|
||||
aPointToBreak);
|
||||
if (MOZ_UNLIKELY(forwardScanResult.Failed())) {
|
||||
NS_WARNING("WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom() failed");
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
|
|
@ -2405,7 +2406,7 @@ Result<CreateElementResult, nsresult> HTMLEditor::HandleInsertBRElement(
|
|||
}
|
||||
|
||||
const WSScanResult forwardScanFromAfterBRElementResult =
|
||||
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
|
||||
WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundary(
|
||||
&aEditingHost, afterBRElement,
|
||||
BlockInlineCheck::UseComputedDisplayStyle);
|
||||
if (MOZ_UNLIKELY(forwardScanFromAfterBRElementResult.Failed())) {
|
||||
|
|
@ -2642,7 +2643,7 @@ HTMLEditor::HandleInsertParagraphInMailCiteElement(
|
|||
// user if they click there and start typing, because being in the
|
||||
// mailquote may affect wrapping behavior, or font color, etc.
|
||||
const WSScanResult forwardScanFromPointToSplitResult =
|
||||
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
|
||||
WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundary(
|
||||
&aEditingHost, pointToSplit, BlockInlineCheck::UseHTMLDefaultStyle);
|
||||
if (forwardScanFromPointToSplitResult.Failed()) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
|
|
@ -2653,8 +2654,8 @@ HTMLEditor::HandleInsertParagraphInMailCiteElement(
|
|||
forwardScanFromPointToSplitResult.BRElementPtr() != &aMailCiteElement &&
|
||||
aMailCiteElement.Contains(
|
||||
forwardScanFromPointToSplitResult.BRElementPtr())) {
|
||||
pointToSplit =
|
||||
forwardScanFromPointToSplitResult.PointAfterContent<EditorDOMPoint>();
|
||||
pointToSplit = forwardScanFromPointToSplitResult
|
||||
.PointAfterReachedContent<EditorDOMPoint>();
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!pointToSplit.IsInContentNode())) {
|
||||
|
|
@ -2773,7 +2774,7 @@ HTMLEditor::HandleInsertParagraphInMailCiteElement(
|
|||
return NS_SUCCESS_DOM_NO_OPERATION;
|
||||
}
|
||||
const WSScanResult forwardScanFromPointAfterNewBRElementResult =
|
||||
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
|
||||
WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundary(
|
||||
&aEditingHost,
|
||||
EditorRawDOMPoint::After(pointToCreateNewBRElement),
|
||||
BlockInlineCheck::UseComputedDisplayStyle);
|
||||
|
|
@ -7725,7 +7726,8 @@ HTMLEditor::GetRangeExtendedToHardLineEdgesForBlockEditAction(
|
|||
WSRunScanner wsScannerAtStart(&aEditingHost, startPoint,
|
||||
BlockInlineCheck::UseHTMLDefaultStyle);
|
||||
const WSScanResult scanResultAtStart =
|
||||
wsScannerAtStart.ScanNextVisibleNodeOrBlockBoundaryFrom(startPoint);
|
||||
wsScannerAtStart.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(
|
||||
startPoint);
|
||||
if (scanResultAtStart.Failed()) {
|
||||
NS_WARNING("WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom() failed");
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
|
|
@ -8978,7 +8980,7 @@ HTMLEditor::HandleInsertParagraphInListItemElement(
|
|||
// put caret in it. If it has non-container inline elements, <br> or <hr>, at
|
||||
// the element is proper position.
|
||||
const WSScanResult forwardScanFromStartOfListItemResult =
|
||||
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
|
||||
WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundary(
|
||||
&aEditingHost, EditorRawDOMPoint(&rightListItemElement, 0u),
|
||||
BlockInlineCheck::UseComputedDisplayStyle);
|
||||
if (MOZ_UNLIKELY(forwardScanFromStartOfListItemResult.Failed())) {
|
||||
|
|
@ -8988,8 +8990,8 @@ HTMLEditor::HandleInsertParagraphInListItemElement(
|
|||
if (forwardScanFromStartOfListItemResult.ReachedSpecialContent() ||
|
||||
forwardScanFromStartOfListItemResult.ReachedBRElement() ||
|
||||
forwardScanFromStartOfListItemResult.ReachedHRElement()) {
|
||||
auto atFoundElement =
|
||||
forwardScanFromStartOfListItemResult.PointAtContent<EditorDOMPoint>();
|
||||
auto atFoundElement = forwardScanFromStartOfListItemResult
|
||||
.PointAtReachedContent<EditorDOMPoint>();
|
||||
if (NS_WARN_IF(!atFoundElement.IsSetAndValid())) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2204,7 +2204,7 @@ nsIContent* HTMLEditUtils::GetContentToPreserveInlineStyles(
|
|||
}
|
||||
for (auto point = aPoint.template To<EditorRawDOMPoint>(); point.IsSet();) {
|
||||
const WSScanResult nextVisibleThing =
|
||||
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
|
||||
WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundary(
|
||||
&aEditingHost, point,
|
||||
BlockInlineCheck::UseComputedDisplayOutsideStyle);
|
||||
if (nextVisibleThing.InVisibleOrCollapsibleCharacters()) {
|
||||
|
|
@ -2261,7 +2261,7 @@ EditorDOMPointType HTMLEditUtils::GetBetterInsertionPointFor(
|
|||
// 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).
|
||||
const WSScanResult forwardScanFromPointToInsertResult =
|
||||
wsScannerForPointToInsert.ScanNextVisibleNodeOrBlockBoundaryFrom(
|
||||
wsScannerForPointToInsert.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(
|
||||
pointToInsert);
|
||||
// So, if the next visible node isn't a <br> element, we can insert the block
|
||||
// level element to the point.
|
||||
|
|
@ -2289,7 +2289,7 @@ EditorDOMPointType HTMLEditUtils::GetBetterInsertionPointFor(
|
|||
}
|
||||
|
||||
return forwardScanFromPointToInsertResult
|
||||
.template PointAfterContent<EditorDOMPointType>();
|
||||
.template PointAfterReachedContent<EditorDOMPointType>();
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
|||
|
|
@ -1151,7 +1151,7 @@ nsresult HTMLEditor::MaybeCollapseSelectionAtFirstEditableNode(
|
|||
// If there is editable and visible text node, move caret at first of
|
||||
// the visible character.
|
||||
const WSScanResult scanResultInTextNode =
|
||||
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
|
||||
WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundary(
|
||||
editingHost, EditorRawDOMPoint(text, 0),
|
||||
BlockInlineCheck::UseComputedDisplayStyle);
|
||||
if ((scanResultInTextNode.InVisibleOrCollapsibleCharacters() ||
|
||||
|
|
|
|||
|
|
@ -1373,8 +1373,8 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDelete(
|
|||
BlockInlineCheck::UseComputedDisplayOutsideStyle);
|
||||
const WSScanResult scanFromCaretPointResult =
|
||||
aDirectionAndAmount == nsIEditor::eNext
|
||||
? wsRunScannerAtCaret.ScanNextVisibleNodeOrBlockBoundaryFrom(
|
||||
caretPoint)
|
||||
? wsRunScannerAtCaret
|
||||
.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(caretPoint)
|
||||
: wsRunScannerAtCaret.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
||||
caretPoint);
|
||||
if (scanFromCaretPointResult.Failed()) {
|
||||
|
|
@ -1396,8 +1396,10 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDelete(
|
|||
if (scanFromCaretPointResult.ReachedInvisibleBRElement()) {
|
||||
EditorDOMPoint newCaretPosition =
|
||||
aDirectionAndAmount == nsIEditor::eNext
|
||||
? scanFromCaretPointResult.PointAfterContent<EditorDOMPoint>()
|
||||
: scanFromCaretPointResult.PointAtContent<EditorDOMPoint>();
|
||||
? scanFromCaretPointResult
|
||||
.PointAfterReachedContent<EditorDOMPoint>()
|
||||
: scanFromCaretPointResult
|
||||
.PointAtReachedContent<EditorDOMPoint>();
|
||||
if (NS_WARN_IF(!newCaretPosition.IsSet())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
@ -1445,7 +1447,8 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDelete(
|
|||
|
||||
// Otherwise, extend the range to contain the invisible `<br>`
|
||||
// element.
|
||||
if (scanFromCaretPointResult.PointAtContent<EditorRawDOMPoint>()
|
||||
if (scanFromCaretPointResult
|
||||
.PointAtReachedContent<EditorRawDOMPoint>()
|
||||
.IsBefore(
|
||||
aRangesToDelete
|
||||
.GetFirstRangeStartPoint<EditorRawDOMPoint>())) {
|
||||
|
|
@ -1458,11 +1461,13 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDelete(
|
|||
return rv;
|
||||
}
|
||||
if (aRangesToDelete.GetFirstRangeEndPoint<EditorRawDOMPoint>()
|
||||
.IsBefore(scanFromCaretPointResult
|
||||
.PointAfterContent<EditorRawDOMPoint>())) {
|
||||
.IsBefore(
|
||||
scanFromCaretPointResult
|
||||
.PointAfterReachedContent<EditorRawDOMPoint>())) {
|
||||
nsresult rv = aRangesToDelete.FirstRangeRef()->SetStartAndEnd(
|
||||
aRangesToDelete.FirstRangeRef()->StartRef(),
|
||||
scanFromCaretPointResult.PointAfterContent<EditorRawDOMPoint>()
|
||||
scanFromCaretPointResult
|
||||
.PointAfterReachedContent<EditorRawDOMPoint>()
|
||||
.ToRawRangeBoundary());
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsRange::SetStartAndEnd() failed");
|
||||
|
|
@ -1666,8 +1671,9 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::Run(
|
|||
BlockInlineCheck::UseComputedDisplayOutsideStyle);
|
||||
const WSScanResult scanFromCaretPointResult =
|
||||
aDirectionAndAmount == nsIEditor::eNext
|
||||
? wsRunScannerAtCaret.ScanNextVisibleNodeOrBlockBoundaryFrom(
|
||||
caretPoint.ref())
|
||||
? wsRunScannerAtCaret
|
||||
.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(
|
||||
caretPoint.ref())
|
||||
: wsRunScannerAtCaret.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
||||
caretPoint.ref());
|
||||
if (MOZ_UNLIKELY(scanFromCaretPointResult.Failed())) {
|
||||
|
|
@ -1722,7 +1728,7 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::Run(
|
|||
const WSScanResult scanFromCaretPointResult =
|
||||
aDirectionAndAmount == nsIEditor::eNext
|
||||
? wsRunScannerAtCaret
|
||||
.ScanNextVisibleNodeOrBlockBoundaryFrom(
|
||||
.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(
|
||||
caretPoint.ref())
|
||||
: wsRunScannerAtCaret
|
||||
.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
||||
|
|
@ -2521,8 +2527,8 @@ bool HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::
|
|||
aDirectionAndAmount == nsIEditor::eNext
|
||||
? aWSRunScannerAtCaret.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
||||
aCaretPoint)
|
||||
: aWSRunScannerAtCaret.ScanNextVisibleNodeOrBlockBoundaryFrom(
|
||||
aCaretPoint);
|
||||
: aWSRunScannerAtCaret
|
||||
.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(aCaretPoint);
|
||||
// If we found a `<br>` element, we need to delete it instead of joining the
|
||||
// contents.
|
||||
if (scanFromCaretResult.ReachedBRElement()) {
|
||||
|
|
@ -2572,7 +2578,7 @@ HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::DeleteBRElement(
|
|||
return maybePreviousText.Point_Deprecated<EditorDOMPoint>();
|
||||
}
|
||||
const WSScanResult maybeNextText =
|
||||
scanner.ScanNextVisibleNodeOrBlockBoundaryFrom(
|
||||
scanner.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(
|
||||
EditorRawDOMPoint::After(*mBRElement));
|
||||
if (maybeNextText.IsContentEditable() &&
|
||||
maybeNextText.InVisibleOrCollapsibleCharacters()) {
|
||||
|
|
@ -4323,7 +4329,7 @@ HTMLEditor::AutoDeleteRangesHandler::DeleteParentBlocksWithTransactionIfEmpty(
|
|||
|
||||
// Next, check there is visible contents after the point in current block.
|
||||
const WSScanResult forwardScanFromPointResult =
|
||||
wsScannerForPoint.ScanNextVisibleNodeOrBlockBoundaryFrom(aPoint);
|
||||
wsScannerForPoint.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(aPoint);
|
||||
if (forwardScanFromPointResult.Failed()) {
|
||||
NS_WARNING("WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom() failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
@ -4344,7 +4350,7 @@ HTMLEditor::AutoDeleteRangesHandler::DeleteParentBlocksWithTransactionIfEmpty(
|
|||
}
|
||||
if (wsScannerForPoint.GetEndReasonContent()->GetNextSibling()) {
|
||||
const WSScanResult scanResult =
|
||||
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
|
||||
WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundary(
|
||||
editingHost,
|
||||
EditorRawDOMPoint::After(
|
||||
*wsScannerForPoint.GetEndReasonContent()),
|
||||
|
|
@ -6841,8 +6847,8 @@ HTMLEditor::AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete(
|
|||
*backwardScanFromStartResult.ElementPtr())) {
|
||||
break;
|
||||
}
|
||||
rangeToDelete.SetStart(
|
||||
backwardScanFromStartResult.PointAtContent<EditorRawDOMPoint>());
|
||||
rangeToDelete.SetStart(backwardScanFromStartResult
|
||||
.PointAtReachedContent<EditorRawDOMPoint>());
|
||||
}
|
||||
if (aFrameSelection && !aFrameSelection->IsValidSelectionPoint(
|
||||
rangeToDelete.StartRef().GetContainer())) {
|
||||
|
|
@ -6864,7 +6870,7 @@ HTMLEditor::AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete(
|
|||
closestEditingHost, rangeToDelete.EndRef(),
|
||||
BlockInlineCheck::UseComputedDisplayOutsideStyle);
|
||||
const WSScanResult forwardScanFromEndResult =
|
||||
wsScannerAtEnd.ScanNextVisibleNodeOrBlockBoundaryFrom(
|
||||
wsScannerAtEnd.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(
|
||||
rangeToDelete.EndRef());
|
||||
if (forwardScanFromEndResult.ReachedBRElement()) {
|
||||
// XXX In my understanding, this is odd. The end reason may not be
|
||||
|
|
@ -6909,7 +6915,8 @@ HTMLEditor::AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete(
|
|||
break;
|
||||
}
|
||||
rangeToDelete.SetEnd(
|
||||
forwardScanFromEndResult.PointAfterContent<EditorRawDOMPoint>());
|
||||
forwardScanFromEndResult
|
||||
.PointAfterReachedContent<EditorRawDOMPoint>());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1915,7 +1915,7 @@ HTMLEditor::AutoInlineStyleSetter::ExtendOrShrinkRangeToApplyTheStyle(
|
|||
EditorDOMRange range(aRange);
|
||||
if (range.EndRef().IsInContentNode()) {
|
||||
const WSScanResult nextContentData =
|
||||
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
|
||||
WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundary(
|
||||
&aEditingHost, range.EndRef(),
|
||||
BlockInlineCheck::UseComputedDisplayOutsideStyle);
|
||||
if (nextContentData.ReachedInvisibleBRElement() &&
|
||||
|
|
|
|||
|
|
@ -49,9 +49,11 @@ template WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
|||
const EditorDOMPoint& aPoint) const;
|
||||
template WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
||||
const EditorRawDOMPoint& aPoint) const;
|
||||
template WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
|
||||
template WSScanResult
|
||||
WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(
|
||||
const EditorDOMPoint& aPoint) const;
|
||||
template WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
|
||||
template WSScanResult
|
||||
WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(
|
||||
const EditorRawDOMPoint& aPoint) const;
|
||||
template EditorDOMPoint WSRunScanner::GetAfterLastVisiblePoint(
|
||||
Text& aTextNode, const Element* aAncestorLimiter);
|
||||
|
|
@ -1735,7 +1737,8 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
|||
// 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(WSScanResult::ScanDirection::Backward,
|
||||
*aPoint.template ContainerAs<nsIContent>(),
|
||||
WSType::InUncomposedDoc, mBlockInlineCheck);
|
||||
}
|
||||
|
||||
|
|
@ -1753,7 +1756,8 @@ 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(WSScanResult::ScanDirection::Backward,
|
||||
*aPoint.GetChild(), WSType::SpecialContent,
|
||||
mBlockInlineCheck);
|
||||
}
|
||||
const auto atPreviousChar =
|
||||
|
|
@ -1761,9 +1765,12 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
|||
// When it's a non-empty text node, return it.
|
||||
if (atPreviousChar.IsSet() && !atPreviousChar.IsContainerEmpty()) {
|
||||
MOZ_ASSERT(!atPreviousChar.IsEndOfContainer());
|
||||
return WSScanResult(atPreviousChar.template NextPoint<EditorDOMPoint>(),
|
||||
return WSScanResult(WSScanResult::ScanDirection::Backward,
|
||||
atPreviousChar.template NextPoint<EditorDOMPoint>(),
|
||||
atPreviousChar.IsCharCollapsibleASCIISpaceOrNBSP()
|
||||
? WSType::CollapsibleWhiteSpaces
|
||||
: atPreviousChar.IsCharPreformattedNewLine()
|
||||
? WSType::PreformattedLineBreak
|
||||
: WSType::NonCollapsibleCharacters,
|
||||
mBlockInlineCheck);
|
||||
}
|
||||
|
|
@ -1774,6 +1781,22 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
|||
return WSScanResult::Error();
|
||||
}
|
||||
|
||||
switch (TextFragmentDataAtStartRef().StartRawReason()) {
|
||||
case WSType::CollapsibleWhiteSpaces:
|
||||
case WSType::NonCollapsibleCharacters:
|
||||
case WSType::PreformattedLineBreak:
|
||||
MOZ_ASSERT(TextFragmentDataAtStartRef().StartRef().IsSet());
|
||||
// XXX: If we find the character at last of a text node and we started
|
||||
// scanning from following text node of it, some callers may work with the
|
||||
// point in the following text node instead of end of the found text node.
|
||||
return WSScanResult(WSScanResult::ScanDirection::Backward,
|
||||
TextFragmentDataAtStartRef().StartRef(),
|
||||
TextFragmentDataAtStartRef().StartRawReason(),
|
||||
mBlockInlineCheck);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise, return the start of the range.
|
||||
if (TextFragmentDataAtStartRef().GetStartReasonContent() !=
|
||||
TextFragmentDataAtStartRef().StartRef().GetContainer()) {
|
||||
|
|
@ -1782,20 +1805,22 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
|||
}
|
||||
// In this case, TextFragmentDataAtStartRef().StartRef().Offset() is not
|
||||
// meaningful.
|
||||
return WSScanResult(*TextFragmentDataAtStartRef().GetStartReasonContent(),
|
||||
return WSScanResult(WSScanResult::ScanDirection::Backward,
|
||||
*TextFragmentDataAtStartRef().GetStartReasonContent(),
|
||||
TextFragmentDataAtStartRef().StartRawReason(),
|
||||
mBlockInlineCheck);
|
||||
}
|
||||
if (NS_WARN_IF(!TextFragmentDataAtStartRef().StartRef().IsSet())) {
|
||||
return WSScanResult::Error();
|
||||
}
|
||||
return WSScanResult(TextFragmentDataAtStartRef().StartRef(),
|
||||
return WSScanResult(WSScanResult::ScanDirection::Backward,
|
||||
TextFragmentDataAtStartRef().StartRef(),
|
||||
TextFragmentDataAtStartRef().StartRawReason(),
|
||||
mBlockInlineCheck);
|
||||
}
|
||||
|
||||
template <typename PT, typename CT>
|
||||
WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
|
||||
WSScanResult WSRunScanner::ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(
|
||||
const EditorDOMPointBase<PT, CT>& aPoint) const {
|
||||
MOZ_ASSERT(aPoint.IsSet());
|
||||
MOZ_ASSERT(aPoint.IsInComposedDoc());
|
||||
|
|
@ -1809,7 +1834,8 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
|
|||
// 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(WSScanResult::ScanDirection::Forward,
|
||||
*aPoint.template ContainerAs<nsIContent>(),
|
||||
WSType::InUncomposedDoc, mBlockInlineCheck);
|
||||
}
|
||||
|
||||
|
|
@ -1827,17 +1853,21 @@ 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(WSScanResult::ScanDirection::Forward,
|
||||
*aPoint.GetChild(), WSType::SpecialContent,
|
||||
mBlockInlineCheck);
|
||||
}
|
||||
const auto atNextChar =
|
||||
GetInclusiveNextEditableCharPoint<EditorDOMPoint>(aPoint);
|
||||
// When it's a non-empty text node, return it.
|
||||
if (atNextChar.IsSet() && !atNextChar.IsContainerEmpty()) {
|
||||
return WSScanResult(atNextChar,
|
||||
return WSScanResult(WSScanResult::ScanDirection::Forward, atNextChar,
|
||||
!atNextChar.IsEndOfContainer() &&
|
||||
atNextChar.IsCharCollapsibleASCIISpaceOrNBSP()
|
||||
? WSType::CollapsibleWhiteSpaces
|
||||
: !atNextChar.IsEndOfContainer() &&
|
||||
atNextChar.IsCharPreformattedNewLine()
|
||||
? WSType::PreformattedLineBreak
|
||||
: WSType::NonCollapsibleCharacters,
|
||||
mBlockInlineCheck);
|
||||
}
|
||||
|
|
@ -1848,6 +1878,23 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
|
|||
return WSScanResult::Error();
|
||||
}
|
||||
|
||||
switch (TextFragmentDataAtStartRef().EndRawReason()) {
|
||||
case WSType::CollapsibleWhiteSpaces:
|
||||
case WSType::NonCollapsibleCharacters:
|
||||
case WSType::PreformattedLineBreak:
|
||||
MOZ_ASSERT(TextFragmentDataAtStartRef().StartRef().IsSet());
|
||||
// XXX: If we find the character at start of a text node and we
|
||||
// started scanning from preceding text node of it, some callers may want
|
||||
// to work with the point at end of the preceding text node instead of
|
||||
// start of the found text node.
|
||||
return WSScanResult(WSScanResult::ScanDirection::Forward,
|
||||
TextFragmentDataAtStartRef().EndRef(),
|
||||
TextFragmentDataAtStartRef().EndRawReason(),
|
||||
mBlockInlineCheck);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise, return the end of the range.
|
||||
if (TextFragmentDataAtStartRef().GetEndReasonContent() !=
|
||||
TextFragmentDataAtStartRef().EndRef().GetContainer()) {
|
||||
|
|
@ -1856,14 +1903,16 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
|
|||
}
|
||||
// In this case, TextFragmentDataAtStartRef().EndRef().Offset() is not
|
||||
// meaningful.
|
||||
return WSScanResult(*TextFragmentDataAtStartRef().GetEndReasonContent(),
|
||||
return WSScanResult(WSScanResult::ScanDirection::Forward,
|
||||
*TextFragmentDataAtStartRef().GetEndReasonContent(),
|
||||
TextFragmentDataAtStartRef().EndRawReason(),
|
||||
mBlockInlineCheck);
|
||||
}
|
||||
if (NS_WARN_IF(!TextFragmentDataAtStartRef().EndRef().IsSet())) {
|
||||
return WSScanResult::Error();
|
||||
}
|
||||
return WSScanResult(TextFragmentDataAtStartRef().EndRef(),
|
||||
return WSScanResult(WSScanResult::ScanDirection::Forward,
|
||||
TextFragmentDataAtStartRef().EndRef(),
|
||||
TextFragmentDataAtStartRef().EndRawReason(),
|
||||
mBlockInlineCheck);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,17 +106,24 @@ class MOZ_STACK_CLASS WSScanResult final {
|
|||
|
||||
public:
|
||||
WSScanResult() = delete;
|
||||
MOZ_NEVER_INLINE_DEBUG WSScanResult(nsIContent& aContent, WSType aReason,
|
||||
enum class ScanDirection : bool { Backward, Forward };
|
||||
MOZ_NEVER_INLINE_DEBUG WSScanResult(ScanDirection aScanDirection,
|
||||
nsIContent& aContent, WSType aReason,
|
||||
BlockInlineCheck aBlockInlineCheck)
|
||||
: mContent(&aContent), mReason(aReason) {
|
||||
: mContent(&aContent), mReason(aReason), mDirection(aScanDirection) {
|
||||
MOZ_ASSERT(aReason != WSType::CollapsibleWhiteSpaces &&
|
||||
aReason != WSType::NonCollapsibleCharacters &&
|
||||
aReason != WSType::PreformattedLineBreak);
|
||||
AssertIfInvalidData(aBlockInlineCheck);
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG WSScanResult(const EditorDOMPoint& aPoint,
|
||||
MOZ_NEVER_INLINE_DEBUG WSScanResult(ScanDirection aScanDirection,
|
||||
const EditorDOMPoint& aPoint,
|
||||
WSType aReason,
|
||||
BlockInlineCheck aBlockInlineCheck)
|
||||
: mContent(aPoint.GetContainerAs<nsIContent>()),
|
||||
mOffset(Some(aPoint.Offset())),
|
||||
mReason(aReason) {
|
||||
mReason(aReason),
|
||||
mDirection(aScanDirection) {
|
||||
AssertIfInvalidData(aBlockInlineCheck);
|
||||
}
|
||||
|
||||
|
|
@ -142,13 +149,31 @@ class MOZ_STACK_CLASS WSScanResult final {
|
|||
MOZ_ASSERT_IF(mContent && !mContent->IsInComposedDoc(),
|
||||
mReason == WSType::InUncomposedDoc);
|
||||
MOZ_ASSERT_IF(mReason == WSType::NonCollapsibleCharacters ||
|
||||
mReason == WSType::CollapsibleWhiteSpaces,
|
||||
mReason == WSType::CollapsibleWhiteSpaces ||
|
||||
mReason == WSType::PreformattedLineBreak,
|
||||
mContent->IsText());
|
||||
MOZ_ASSERT_IF(mReason == WSType::NonCollapsibleCharacters ||
|
||||
mReason == WSType::CollapsibleWhiteSpaces ||
|
||||
mReason == WSType::PreformattedLineBreak,
|
||||
mOffset.isSome());
|
||||
MOZ_ASSERT_IF(mReason == WSType::NonCollapsibleCharacters ||
|
||||
mReason == WSType::CollapsibleWhiteSpaces ||
|
||||
mReason == WSType::PreformattedLineBreak,
|
||||
mContent->AsText()->TextDataLength() > 0);
|
||||
MOZ_ASSERT_IF(mDirection == ScanDirection::Backward &&
|
||||
(mReason == WSType::NonCollapsibleCharacters ||
|
||||
mReason == WSType::CollapsibleWhiteSpaces ||
|
||||
mReason == WSType::PreformattedLineBreak),
|
||||
*mOffset > 0);
|
||||
MOZ_ASSERT_IF(mDirection == ScanDirection::Forward &&
|
||||
(mReason == WSType::NonCollapsibleCharacters ||
|
||||
mReason == WSType::CollapsibleWhiteSpaces ||
|
||||
mReason == WSType::PreformattedLineBreak),
|
||||
*mOffset < mContent->AsText()->TextDataLength());
|
||||
MOZ_ASSERT_IF(mReason == WSType::BRElement,
|
||||
mContent->IsHTMLElement(nsGkAtoms::br));
|
||||
MOZ_ASSERT_IF(
|
||||
mReason == WSType::PreformattedLineBreak,
|
||||
mContent->IsText() && EditorUtils::IsNewLinePreformatted(*mContent));
|
||||
MOZ_ASSERT_IF(mReason == WSType::PreformattedLineBreak,
|
||||
EditorUtils::IsNewLinePreformatted(*mContent));
|
||||
MOZ_ASSERT_IF(
|
||||
mReason == WSType::SpecialContent,
|
||||
(mContent->IsText() && !mContent->IsEditable()) ||
|
||||
|
|
@ -241,24 +266,34 @@ class MOZ_STACK_CLASS WSScanResult final {
|
|||
}
|
||||
|
||||
/**
|
||||
* PointAtContent() returns the position of found visible content or reached
|
||||
* block element.
|
||||
*/
|
||||
template <typename EditorDOMPointType>
|
||||
EditorDOMPointType PointAtContent() const {
|
||||
MOZ_ASSERT(mContent);
|
||||
return EditorDOMPointType(mContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* PointAfterContent() returns the position after found visible content or
|
||||
* PointAtReachedContent() returns the position of found visible content or
|
||||
* reached block element.
|
||||
*/
|
||||
template <typename EditorDOMPointType>
|
||||
EditorDOMPointType PointAfterContent() const {
|
||||
EditorDOMPointType PointAtReachedContent() const {
|
||||
MOZ_ASSERT(mContent);
|
||||
return mContent ? EditorDOMPointType::After(mContent)
|
||||
: EditorDOMPointType();
|
||||
switch (mReason) {
|
||||
case WSType::CollapsibleWhiteSpaces:
|
||||
case WSType::NonCollapsibleCharacters:
|
||||
case WSType::PreformattedLineBreak:
|
||||
MOZ_DIAGNOSTIC_ASSERT(mOffset.isSome());
|
||||
return mDirection == ScanDirection::Forward
|
||||
? EditorDOMPointType(mContent, mOffset.valueOr(0))
|
||||
: EditorDOMPointType(mContent,
|
||||
std::max(mOffset.valueOr(1), 1u) - 1);
|
||||
default:
|
||||
return EditorDOMPointType(mContent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PointAfterReachedContent() returns the position after found visible content
|
||||
* or reached block element.
|
||||
*/
|
||||
template <typename EditorDOMPointType>
|
||||
EditorDOMPointType PointAfterReachedContent() const {
|
||||
MOZ_ASSERT(mContent);
|
||||
return PointAtReachedContent<EditorDOMPointType>().template NextPoint();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -362,6 +397,7 @@ class MOZ_STACK_CLASS WSScanResult final {
|
|||
nsCOMPtr<nsIContent> mContent;
|
||||
Maybe<uint32_t> mOffset;
|
||||
WSType mReason;
|
||||
ScanDirection mDirection = ScanDirection::Backward;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS WSRunScanner final {
|
||||
|
|
@ -378,25 +414,29 @@ class MOZ_STACK_CLASS WSRunScanner final {
|
|||
aBlockInlineCheck),
|
||||
mBlockInlineCheck(aBlockInlineCheck) {}
|
||||
|
||||
// ScanNextVisibleNodeOrBlockBoundaryForwardFrom() returns the first visible
|
||||
// node after aPoint. If there is no visible nodes after aPoint, returns
|
||||
// topmost editable inline ancestor at end of current block. See comments
|
||||
// around WSScanResult for the detail.
|
||||
// ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom() returns the first visible
|
||||
// node at or after aPoint. If there is no visible nodes after aPoint,
|
||||
// returns topmost editable inline ancestor at end of current block. See
|
||||
// comments around WSScanResult for the detail. When you reach a character,
|
||||
// this returns WSScanResult both whose Point_Deprecated() and
|
||||
// PointAtReachedContent() return the found character position.
|
||||
template <typename PT, typename CT>
|
||||
WSScanResult ScanNextVisibleNodeOrBlockBoundaryFrom(
|
||||
WSScanResult ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(
|
||||
const EditorDOMPointBase<PT, CT>& aPoint) const;
|
||||
template <typename PT, typename CT>
|
||||
static WSScanResult ScanNextVisibleNodeOrBlockBoundary(
|
||||
static WSScanResult ScanInclusiveNextVisibleNodeOrBlockBoundary(
|
||||
const Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint,
|
||||
BlockInlineCheck aBlockInlineCheck) {
|
||||
return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck)
|
||||
.ScanNextVisibleNodeOrBlockBoundaryFrom(aPoint);
|
||||
.ScanInclusiveNextVisibleNodeOrBlockBoundaryFrom(aPoint);
|
||||
}
|
||||
|
||||
// ScanPreviousVisibleNodeOrBlockBoundaryFrom() returns the first visible node
|
||||
// before aPoint. If there is no visible nodes before aPoint, returns topmost
|
||||
// editable inline ancestor at start of current block. See comments around
|
||||
// WSScanResult for the detail.
|
||||
// WSScanResult for the detail. When you reach a character, this returns
|
||||
// WSScanResult whose Point_Deprecated() returns next point of the found
|
||||
// character and PointAtReachedContent() returns the point at found character.
|
||||
template <typename PT, typename CT>
|
||||
WSScanResult ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
||||
const EditorDOMPointBase<PT, CT>& aPoint) const;
|
||||
|
|
|
|||
Loading…
Reference in a new issue