зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1838250 - Avoid O(n^2) behavior in nsTextFrame::GetCharacterRectsInRange. r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D183382
This commit is contained in:
Родитель
52c561897c
Коммит
90a0aae39c
|
@ -7450,27 +7450,31 @@ nsresult nsTextFrame::GetCharacterRectsInRange(int32_t aInOffset,
|
|||
// place if it's positioned there
|
||||
properties.InitializeForDisplay(false);
|
||||
|
||||
// Initialize iter; this will call FindClusterStart if necessary to align
|
||||
// iter to a cluster boundary.
|
||||
UpdateIteratorFromOffset(properties, aInOffset, iter);
|
||||
nsPoint point = GetPointFromIterator(iter, properties);
|
||||
|
||||
const int32_t kContentEnd = GetContentEnd();
|
||||
const int32_t kEndOffset = std::min(aInOffset + aLength, kContentEnd);
|
||||
while (aInOffset < kEndOffset) {
|
||||
if (!iter.IsOriginalCharSkipped() &&
|
||||
!mTextRun->IsClusterStart(iter.GetSkippedOffset())) {
|
||||
FindClusterStart(mTextRun,
|
||||
properties.GetStart().GetOriginalOffset() +
|
||||
properties.GetOriginalLength(),
|
||||
&iter);
|
||||
}
|
||||
|
||||
nsPoint point = GetPointFromIterator(iter, properties);
|
||||
nsRect rect;
|
||||
rect.x = point.x;
|
||||
rect.y = point.y;
|
||||
if (aInOffset >= kEndOffset) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aRects.SetCapacity(aRects.Length() + kEndOffset - aInOffset,
|
||||
mozilla::fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
do {
|
||||
MOZ_ASSERT(point == GetPointFromIterator(iter, properties),
|
||||
"character position error!");
|
||||
|
||||
// Measure to the end of the cluster.
|
||||
nscoord iSize = 0;
|
||||
gfxSkipCharsIterator nextIter(iter);
|
||||
if (aInOffset < kContentEnd) {
|
||||
gfxSkipCharsIterator nextIter(iter);
|
||||
nextIter.AdvanceOriginal(1);
|
||||
if (!nextIter.IsOriginalCharSkipped() &&
|
||||
!mTextRun->IsClusterStart(nextIter.GetSkippedOffset()) &&
|
||||
|
@ -7484,6 +7488,12 @@ nsresult nsTextFrame::GetCharacterRectsInRange(int32_t aInOffset,
|
|||
iSize = NSToCoordCeilClamped(advance);
|
||||
}
|
||||
|
||||
// Compute the cluster rect, depending on directionality, and update
|
||||
// point to the origin we'll need for the next cluster.
|
||||
nsRect rect;
|
||||
rect.x = point.x;
|
||||
rect.y = point.y;
|
||||
|
||||
if (mTextRun->IsVertical()) {
|
||||
rect.width = mRect.width;
|
||||
rect.height = iSize;
|
||||
|
@ -7492,6 +7502,9 @@ nsresult nsTextFrame::GetCharacterRectsInRange(int32_t aInOffset,
|
|||
// bottom left instead of the top left. Move the origin to the top left
|
||||
// by subtracting the character's height.
|
||||
rect.y -= rect.height;
|
||||
point.y -= iSize;
|
||||
} else {
|
||||
point.y += iSize;
|
||||
}
|
||||
} else {
|
||||
rect.width = iSize;
|
||||
|
@ -7505,15 +7518,22 @@ nsresult nsTextFrame::GetCharacterRectsInRange(int32_t aInOffset,
|
|||
// subtracting the character's width. This is intentionally done after
|
||||
// GetTextCombineScaleFactor() so we use the final, scaled width.
|
||||
rect.x -= rect.width;
|
||||
point.x -= iSize;
|
||||
} else {
|
||||
point.x += iSize;
|
||||
}
|
||||
}
|
||||
aRects.AppendElement(rect);
|
||||
aInOffset++;
|
||||
// Don't advance iter if we've reached the end
|
||||
if (aInOffset < kEndOffset) {
|
||||
iter.AdvanceOriginal(1);
|
||||
|
||||
// Set the rect for all characters in the cluster.
|
||||
int32_t end = std::min(kEndOffset, nextIter.GetOriginalOffset());
|
||||
while (aInOffset < end) {
|
||||
aRects.AppendElement(rect);
|
||||
aInOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
// Advance iter for the next cluster.
|
||||
iter = nextIter;
|
||||
} while (aInOffset < kEndOffset);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче