Bug 1646296 - part 6: Make `WSRunScanner::InitializeRange*()` stop using the loops which are rarely run twice and more r=m_kato

With the previous patches, we know that the loops in
`WSRunScanner::InitializeRangeStart()` and `WSRunScanner::InitializeRangeEnd()`
rarely run twice and more.  Therefore, we can make use recursive calls instead
of the loop.

Depends on D79970

Differential Revision: https://phabricator.services.mozilla.com/D79971
This commit is contained in:
Masayuki Nakano 2020-06-22 06:05:16 +00:00
Родитель 8d168248fa
Коммит 196304c105
1 изменённых файлов: 121 добавлений и 118 удалений

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

@ -792,74 +792,76 @@ void WSRunScanner::InitializeRangeStart(
const nsIContent& aEditableBlockParentOrTopmostEditableInlineContent) {
MOZ_ASSERT(aPoint.IsSetAndValid());
EditorDOMPoint start(aPoint);
// first look backwards to find preceding ws nodes
if (aPoint.IsInTextNode()) {
if (aPoint.IsInTextNode() && !aPoint.IsStartOfContainer()) {
if (InitializeRangeStartWithTextNode(
EditorDOMPointInText(aPoint.ContainerAsText(), aPoint.Offset()))) {
return;
}
// The text node does not have visible character, let's keep scanning
// preceding nodes.
start.Set(aPoint.ContainerAsText(), 0);
InitializeRangeStart(EditorDOMPoint(aPoint.ContainerAsText(), 0),
aEditableBlockParentOrTopmostEditableInlineContent);
return;
}
while (!mStartNode) {
// we haven't found the start of ws yet. Keep looking
nsIContent* previousLeafContentOrBlock =
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
start, aEditableBlockParentOrTopmostEditableInlineContent,
mEditingHost);
if (!previousLeafContentOrBlock) {
// no prior node means we exhausted
// aEditableBlockParentOrTopmostEditableInlineContent
mStartNode = start.GetContainer();
mStartOffset = start.Offset();
mStartReason = WSType::CurrentBlockBoundary;
// mStartReasonContent can be either a block element or any non-editable
// content in this case.
mStartReasonContent = const_cast<nsIContent*>(
&aEditableBlockParentOrTopmostEditableInlineContent);
return;
}
if (HTMLEditUtils::IsBlockElement(*previousLeafContentOrBlock)) {
mStartNode = start.GetContainer();
mStartOffset = start.Offset();
mStartReason = WSType::OtherBlockBoundary;
mStartReasonContent = previousLeafContentOrBlock;
return;
}
if (!previousLeafContentOrBlock->IsText() ||
!previousLeafContentOrBlock->IsEditable()) {
// it's a break or a special node, like <img>, that is not a block and
// not a break but still serves as a terminator to ws runs.
mStartNode = start.GetContainer();
mStartOffset = start.Offset();
mStartReason = previousLeafContentOrBlock->IsHTMLElement(nsGkAtoms::br)
? WSType::BRElement
: WSType::SpecialContent;
mStartReasonContent = previousLeafContentOrBlock;
return;
}
if (!previousLeafContentOrBlock->AsText()->TextFragment().GetLength()) {
// Zero length text node. Set start point to it
// so we can get past it!
start.Set(previousLeafContentOrBlock->AsText(), 0);
continue;
}
if (InitializeRangeStartWithTextNode(EditorDOMPointInText::AtEndOf(
*previousLeafContentOrBlock->AsText()))) {
return;
}
// The text node does not have visible character, let's keep scanning
// preceding nodes.
start.Set(previousLeafContentOrBlock->AsText(), 0);
// we haven't found the start of ws yet. Keep looking
nsIContent* previousLeafContentOrBlock =
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
aPoint, aEditableBlockParentOrTopmostEditableInlineContent,
mEditingHost);
if (!previousLeafContentOrBlock) {
// no prior node means we exhausted
// aEditableBlockParentOrTopmostEditableInlineContent
mStartNode = aPoint.GetContainer();
mStartOffset = aPoint.Offset();
mStartReason = WSType::CurrentBlockBoundary;
// mStartReasonContent can be either a block element or any non-editable
// content in this case.
mStartReasonContent = const_cast<nsIContent*>(
&aEditableBlockParentOrTopmostEditableInlineContent);
return;
}
if (HTMLEditUtils::IsBlockElement(*previousLeafContentOrBlock)) {
mStartNode = aPoint.GetContainer();
mStartOffset = aPoint.Offset();
mStartReason = WSType::OtherBlockBoundary;
mStartReasonContent = previousLeafContentOrBlock;
return;
}
if (!previousLeafContentOrBlock->IsText() ||
!previousLeafContentOrBlock->IsEditable()) {
// it's a break or a special node, like <img>, that is not a block and
// not a break but still serves as a terminator to ws runs.
mStartNode = aPoint.GetContainer();
mStartOffset = aPoint.Offset();
mStartReason = previousLeafContentOrBlock->IsHTMLElement(nsGkAtoms::br)
? WSType::BRElement
: WSType::SpecialContent;
mStartReasonContent = previousLeafContentOrBlock;
return;
}
if (!previousLeafContentOrBlock->AsText()->TextFragment().GetLength()) {
// Zero length text node. Set start point to it
// so we can get past it!
InitializeRangeStart(
EditorDOMPoint(previousLeafContentOrBlock->AsText(), 0),
aEditableBlockParentOrTopmostEditableInlineContent);
return;
}
if (InitializeRangeStartWithTextNode(EditorDOMPointInText::AtEndOf(
*previousLeafContentOrBlock->AsText()))) {
return;
}
// The text node does not have visible character, let's keep scanning
// preceding nodes.
InitializeRangeStart(EditorDOMPoint(previousLeafContentOrBlock->AsText(), 0),
aEditableBlockParentOrTopmostEditableInlineContent);
}
bool WSRunScanner::InitializeRangeEndWithTextNode(
@ -898,75 +900,76 @@ void WSRunScanner::InitializeRangeEnd(
const nsIContent& aEditableBlockParentOrTopmostEditableInlineContent) {
MOZ_ASSERT(aPoint.IsSetAndValid());
EditorDOMPoint end(aPoint);
if (aPoint.IsInTextNode()) {
if (aPoint.IsInTextNode() && !aPoint.IsEndOfContainer()) {
if (InitializeRangeEndWithTextNode(
EditorDOMPointInText(aPoint.ContainerAsText(), aPoint.Offset()))) {
return;
}
// The text node does not have visible character, let's keep scanning
// following nodes.
end.SetToEndOf(aPoint.ContainerAsText());
InitializeRangeEnd(EditorDOMPoint::AtEndOf(*aPoint.ContainerAsText()),
aEditableBlockParentOrTopmostEditableInlineContent);
return;
}
while (!mEndNode) {
// we haven't found the end of ws yet. Keep looking
nsIContent* nextLeafContentOrBlock =
HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
end, aEditableBlockParentOrTopmostEditableInlineContent,
mEditingHost);
if (!nextLeafContentOrBlock) {
// no next node means we exhausted
// aEditableBlockParentOrTopmostEditableInlineContent
mEndNode = end.GetContainer();
mEndOffset = end.Offset();
mEndReason = WSType::CurrentBlockBoundary;
// mEndReasonContent can be either a block element or any non-editable
// content in this case.
mEndReasonContent = const_cast<nsIContent*>(
&aEditableBlockParentOrTopmostEditableInlineContent);
return;
}
if (HTMLEditUtils::IsBlockElement(*nextLeafContentOrBlock)) {
// we encountered a new block. therefore no more ws.
mEndNode = end.GetContainer();
mEndOffset = end.Offset();
mEndReason = WSType::OtherBlockBoundary;
mEndReasonContent = nextLeafContentOrBlock;
return;
}
if (!nextLeafContentOrBlock->IsText() ||
!nextLeafContentOrBlock->IsEditable()) {
// we encountered a break or a special node, like <img>,
// that is not a block and not a break but still
// serves as a terminator to ws runs.
mEndNode = end.GetContainer();
mEndOffset = end.Offset();
mEndReason = nextLeafContentOrBlock->IsHTMLElement(nsGkAtoms::br)
? WSType::BRElement
: WSType::SpecialContent;
mEndReasonContent = nextLeafContentOrBlock;
return;
}
if (!nextLeafContentOrBlock->AsText()->TextFragment().GetLength()) {
// Zero length text node. Set end point to it
// so we can get past it!
end.Set(nextLeafContentOrBlock->AsText(), 0);
continue;
}
if (InitializeRangeEndWithTextNode(
EditorDOMPointInText(nextLeafContentOrBlock->AsText(), 0))) {
return;
}
// The text node does not have visible character, let's keep scanning
// following nodes.
end.SetToEndOf(nextLeafContentOrBlock->AsText());
// we haven't found the end of ws yet. Keep looking
nsIContent* nextLeafContentOrBlock =
HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
aPoint, aEditableBlockParentOrTopmostEditableInlineContent,
mEditingHost);
if (!nextLeafContentOrBlock) {
// no next node means we exhausted
// aEditableBlockParentOrTopmostEditableInlineContent
mEndNode = aPoint.GetContainer();
mEndOffset = aPoint.Offset();
mEndReason = WSType::CurrentBlockBoundary;
// mEndReasonContent can be either a block element or any non-editable
// content in this case.
mEndReasonContent = const_cast<nsIContent*>(
&aEditableBlockParentOrTopmostEditableInlineContent);
return;
}
if (HTMLEditUtils::IsBlockElement(*nextLeafContentOrBlock)) {
// we encountered a new block. therefore no more ws.
mEndNode = aPoint.GetContainer();
mEndOffset = aPoint.Offset();
mEndReason = WSType::OtherBlockBoundary;
mEndReasonContent = nextLeafContentOrBlock;
return;
}
if (!nextLeafContentOrBlock->IsText() ||
!nextLeafContentOrBlock->IsEditable()) {
// we encountered a break or a special node, like <img>,
// that is not a block and not a break but still
// serves as a terminator to ws runs.
mEndNode = aPoint.GetContainer();
mEndOffset = aPoint.Offset();
mEndReason = nextLeafContentOrBlock->IsHTMLElement(nsGkAtoms::br)
? WSType::BRElement
: WSType::SpecialContent;
mEndReasonContent = nextLeafContentOrBlock;
return;
}
if (!nextLeafContentOrBlock->AsText()->TextFragment().GetLength()) {
// Zero length text node. Set end point to it
// so we can get past it!
InitializeRangeEnd(EditorDOMPoint(nextLeafContentOrBlock->AsText(), 0),
aEditableBlockParentOrTopmostEditableInlineContent);
return;
}
if (InitializeRangeEndWithTextNode(
EditorDOMPointInText(nextLeafContentOrBlock->AsText(), 0))) {
return;
}
// The text node does not have visible character, let's keep scanning
// following nodes.
InitializeRangeEnd(EditorDOMPoint::AtEndOf(*nextLeafContentOrBlock->AsText()),
aEditableBlockParentOrTopmostEditableInlineContent);
}
void WSRunScanner::GetRuns() {