diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 8dd2e6196bc9..1d2816d88177 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -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; }