Bug 1521579 - Only transform one bounding rect for text nodes when computing scroll anchoring bounding rect. r=dholbert

When visiting a text frame with many continuations, traversing ancestors to compute the
transform to the ancestor scroll frame can become very hot. This commit changes the
algorithm to translate all the text continuations to an ancestor that can then be
transformed just once.

Differential Revision: https://phabricator.services.mozilla.com/D17730

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ryan Hunt 2019-01-30 14:42:58 +00:00
Родитель 092461a72f
Коммит 585289697d
1 изменённых файлов: 26 добавлений и 4 удалений

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

@ -98,16 +98,38 @@ static nsRect FindScrollAnchoringBoundingRect(const nsIFrame* aScrollFrame,
nsIFrame* aCandidate) {
MOZ_ASSERT(nsLayoutUtils::IsProperAncestorFrame(aScrollFrame, aCandidate));
if (!!Text::FromNodeOrNull(aCandidate->GetContent())) {
// This is a frame for a text node. The spec says we need to accumulate the
// union of all line boxes in the coordinate space of the scroll frame
// accounting for transforms.
//
// To do this, we translate and accumulate the overflow rect for each text
// continuation to the coordinate space of the nearest ancestor block
// frame. Then we transform the resulting rect into the coordinate space of
// the scroll frame.
//
// Transforms aren't allowed on non-replaced inline boxes, so we can assume
// that these text node continuations will have the same transform as their
// nearest block ancestor. And it should be faster to transform their union
// rather than individually transforming each overflow rect
//
// XXX for fragmented blocks, blockAncestor will be an ancestor only to the
// text continuations in the first block continuation. GetOffsetTo
// should continue to work, but is it correct with transforms or a
// performance hazard?
nsIFrame* blockAncestor =
nsLayoutUtils::FindNearestBlockAncestor(aCandidate);
MOZ_ASSERT(
nsLayoutUtils::IsProperAncestorFrame(aScrollFrame, blockAncestor));
nsRect bounding;
for (nsIFrame* continuation = aCandidate->FirstContinuation(); continuation;
continuation = continuation->GetNextContinuation()) {
nsRect overflowRect =
continuation->GetScrollableOverflowRectRelativeToSelf();
nsRect transformed = nsLayoutUtils::TransformFrameRectToAncestor(
continuation, overflowRect, aScrollFrame);
bounding = bounding.Union(transformed);
overflowRect += continuation->GetOffsetTo(blockAncestor);
bounding = bounding.Union(overflowRect);
}
return bounding;
return nsLayoutUtils::TransformFrameRectToAncestor(blockAncestor, bounding,
aScrollFrame);
}
nsRect borderRect = aCandidate->GetRectRelativeToSelf();