Bug 1722968 - Add an optimization for GetAllInFlowRects to avoid expensive ancestor lookups in DOMIntersectionObserver. r=jwatt

Part of the issue with the profile in the blocked bug is that 30% of the
time is spent in nsLayoutUtils::FindNearestCommonAncestorFrame from
DOMIntersectionObserver::Update. That shouldn't be needed since in most
cases we know we're an ancestor.

We have an optimization for the root frame but DOMIntersectionObserver
keeps its rects relative to `target`. So we only need to do the
expensive transform for IB splits / fragmented flows.

Differential Revision: https://phabricator.services.mozilla.com/D121214
This commit is contained in:
Emilio Cobos Álvarez 2021-07-30 12:34:00 +00:00
Родитель eda5c43145
Коммит 9a783438a6
2 изменённых файлов: 29 добавлений и 11 удалений

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

@ -3711,9 +3711,11 @@ void nsLayoutUtils::AddBoxesForFrame(nsIFrame* aFrame,
void nsLayoutUtils::GetAllInFlowBoxes(nsIFrame* aFrame,
BoxCallback* aCallback) {
aCallback->mInTargetContinuation = false;
while (aFrame) {
AddBoxesForFrame(aFrame, aCallback);
aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame);
aCallback->mInTargetContinuation = true;
}
}
@ -3756,14 +3758,23 @@ struct BoxToRect : public nsLayoutUtils::BoxCallback {
const nsIFrame* mRelativeTo;
RectCallback* mCallback;
uint32_t mFlags;
// If the frame we're measuring relative to is the root, we know all frames
// are descendants of it, so we don't need to compute the common ancestor
// between a frame and mRelativeTo.
bool mRelativeToIsRoot;
// For the same reason, if the frame we're measuring relative to is the target
// (this is useful for IntersectionObserver), we know all frames are
// descendants of it except if we're in a continuation or ib-split-sibling of
// it.
bool mRelativeToIsTarget;
BoxToRect(const nsIFrame* aRelativeTo, RectCallback* aCallback,
uint32_t aFlags)
BoxToRect(const nsIFrame* aTargetFrame, const nsIFrame* aRelativeTo,
RectCallback* aCallback, uint32_t aFlags)
: mRelativeTo(aRelativeTo),
mCallback(aCallback),
mFlags(aFlags),
mRelativeToIsRoot(!aRelativeTo->GetParent()) {}
mRelativeToIsRoot(!aRelativeTo->GetParent()),
mRelativeToIsTarget(aRelativeTo == aTargetFrame) {}
virtual void AddBox(nsIFrame* aFrame) override {
nsRect r;
@ -3785,7 +3796,8 @@ struct BoxToRect : public nsLayoutUtils::BoxCallback {
}
}
if (mFlags & nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS) {
if (mRelativeToIsRoot) {
if (mRelativeToIsRoot ||
(mRelativeToIsTarget && !mInTargetContinuation)) {
r = nsLayoutUtils::TransformFrameRectToAncestor(outer, r, mRelativeTo);
} else {
nsLayoutUtils::TransformRect(outer, mRelativeTo, r);
@ -3800,9 +3812,11 @@ struct BoxToRect : public nsLayoutUtils::BoxCallback {
struct MOZ_RAII BoxToRectAndText : public BoxToRect {
Sequence<nsString>* mTextList;
BoxToRectAndText(const nsIFrame* aRelativeTo, RectCallback* aCallback,
Sequence<nsString>* aTextList, uint32_t aFlags)
: BoxToRect(aRelativeTo, aCallback, aFlags), mTextList(aTextList) {}
BoxToRectAndText(const nsIFrame* aTargetFrame, const nsIFrame* aRelativeTo,
RectCallback* aCallback, Sequence<nsString>* aTextList,
uint32_t aFlags)
: BoxToRect(aTargetFrame, aRelativeTo, aCallback, aFlags),
mTextList(aTextList) {}
static void AccumulateText(nsIFrame* aFrame, nsAString& aResult) {
MOZ_ASSERT(aFrame);
@ -3842,7 +3856,7 @@ void nsLayoutUtils::GetAllInFlowRects(nsIFrame* aFrame,
const nsIFrame* aRelativeTo,
RectCallback* aCallback,
uint32_t aFlags) {
BoxToRect converter(aRelativeTo, aCallback, aFlags);
BoxToRect converter(aFrame, aRelativeTo, aCallback, aFlags);
GetAllInFlowBoxes(aFrame, &converter);
}
@ -3851,7 +3865,7 @@ void nsLayoutUtils::GetAllInFlowRectsAndTexts(nsIFrame* aFrame,
RectCallback* aCallback,
Sequence<nsString>* aTextList,
uint32_t aFlags) {
BoxToRectAndText converter(aRelativeTo, aCallback, aTextList, aFlags);
BoxToRectAndText converter(aFrame, aRelativeTo, aCallback, aTextList, aFlags);
GetAllInFlowBoxes(aFrame, &converter);
}

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

@ -1241,9 +1241,13 @@ class nsLayoutUtils {
class BoxCallback {
public:
BoxCallback() : mIncludeCaptionBoxForTable(true) {}
BoxCallback() = default;
virtual void AddBox(nsIFrame* aFrame) = 0;
bool mIncludeCaptionBoxForTable;
bool mIncludeCaptionBoxForTable = true;
// Whether we are in a continuation or ib-split-sibling of the target we're
// measuring. This is useful because if we know we're in the target subtree
// and measuring against it we can avoid finding the common ancestor.
bool mInTargetContinuation = false;
};
/**
* Collect all CSS boxes associated with aFrame and its