Skip to content

Commit

Permalink
Bug 1865012 Part 1 - Make accessing first-continuation and first-in-f…
Browse files Browse the repository at this point in the history
…low constant time. r=dholbert

Differential Revision: https://phabricator.services.mozilla.com/D197757
  • Loading branch information
aethanyc committed Jan 23, 2024
1 parent 3075ad0 commit d7ac9e2
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 11 deletions.
79 changes: 70 additions & 9 deletions layout/generic/nsSplittableFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ NS_QUERYFRAME_HEAD(nsSplittableFrame)
NS_QUERYFRAME_ENTRY(nsSplittableFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsIFrame)

// These frame properties cache the first-continuation and first-in-flow frame
// pointers. All nsSplittableFrames other than the first one in the continuation
// chain will have these properties set.
NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(FirstContinuationProperty, nsIFrame);
NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(FirstInFlowProperty, nsIFrame);

void nsSplittableFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) {
if (aPrevInFlow) {
Expand Down Expand Up @@ -51,6 +57,7 @@ void nsSplittableFrame::SetPrevContinuation(nsIFrame* aFrame) {
"creating a loop in continuation chain!");
mPrevContinuation = aFrame;
RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
UpdateFirstContinuationAndFirstInFlowCache();
}

nsIFrame* nsSplittableFrame::GetNextContinuation() const {
Expand All @@ -69,12 +76,19 @@ void nsSplittableFrame::SetNextContinuation(nsIFrame* aFrame) {
}

nsIFrame* nsSplittableFrame::FirstContinuation() const {
nsSplittableFrame* firstContinuation = const_cast<nsSplittableFrame*>(this);
while (firstContinuation->mPrevContinuation) {
firstContinuation =
static_cast<nsSplittableFrame*>(firstContinuation->mPrevContinuation);
if (!GetPrevContinuation()) {
MOZ_ASSERT(
!HasProperty(FirstContinuationProperty()),
"The property shouldn't be present on first-continuation itself!");
return const_cast<nsSplittableFrame*>(this);
}
MOZ_ASSERT(firstContinuation, "post-condition failed");

nsIFrame* firstContinuation = GetProperty(FirstContinuationProperty());
MOZ_ASSERT(firstContinuation,
"The property should be set and non-null on all continuations "
"after the first!");
MOZ_ASSERT(!firstContinuation->GetPrevContinuation(),
"First continuation shouldn't have a prev continuation!");
return firstContinuation;
}

Expand Down Expand Up @@ -126,6 +140,7 @@ void nsSplittableFrame::SetPrevInFlow(nsIFrame* aFrame) {
"creating a loop in continuation chain!");
mPrevContinuation = aFrame;
AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
UpdateFirstContinuationAndFirstInFlowCache();
}

nsIFrame* nsSplittableFrame::GetNextInFlow() const {
Expand All @@ -147,11 +162,18 @@ void nsSplittableFrame::SetNextInFlow(nsIFrame* aFrame) {
}

nsIFrame* nsSplittableFrame::FirstInFlow() const {
nsSplittableFrame* firstInFlow = const_cast<nsSplittableFrame*>(this);
while (nsIFrame* prev = firstInFlow->GetPrevInFlow()) {
firstInFlow = static_cast<nsSplittableFrame*>(prev);
if (!GetPrevInFlow()) {
MOZ_ASSERT(!HasProperty(FirstInFlowProperty()),
"The property shouldn't be present on first-in-flow itself!");
return const_cast<nsSplittableFrame*>(this);
}
MOZ_ASSERT(firstInFlow, "post-condition failed");

nsIFrame* firstInFlow = GetProperty(FirstInFlowProperty());
MOZ_ASSERT(firstInFlow,
"The property should be set and non-null on all in-flows after "
"the first!");
MOZ_ASSERT(!firstInFlow->GetPrevInFlow(),
"First-in-flow shouldn't have a prev-in-flow!");
return firstInFlow;
}

Expand Down Expand Up @@ -195,6 +217,45 @@ void nsSplittableFrame::RemoveFromFlow(nsIFrame* aFrame) {
aFrame->SetPrevInFlow(nullptr);
}

void nsSplittableFrame::UpdateFirstContinuationAndFirstInFlowCache() {
nsIFrame* oldCachedFirstContinuation =
GetProperty(FirstContinuationProperty());
nsIFrame* newFirstContinuation;
if (nsIFrame* prevContinuation = GetPrevContinuation()) {
newFirstContinuation = prevContinuation->FirstContinuation();
SetProperty(FirstContinuationProperty(), newFirstContinuation);
} else {
newFirstContinuation = this;
RemoveProperty(FirstContinuationProperty());
}

if (oldCachedFirstContinuation != newFirstContinuation) {
// Update the first-continuation cache for our next-continuations in the
// chain.
for (nsIFrame* next = GetNextContinuation(); next;
next = next->GetNextContinuation()) {
next->SetProperty(FirstContinuationProperty(), newFirstContinuation);
}
}

nsIFrame* oldCachedFirstInFlow = GetProperty(FirstInFlowProperty());
nsIFrame* newFirstInFlow;
if (nsIFrame* prevInFlow = GetPrevInFlow()) {
newFirstInFlow = prevInFlow->FirstInFlow();
SetProperty(FirstInFlowProperty(), newFirstInFlow);
} else {
newFirstInFlow = this;
RemoveProperty(FirstInFlowProperty());
}

if (oldCachedFirstInFlow != newFirstInFlow) {
// Update the first-in-flow cache for our next-in-flows in the chain.
for (nsIFrame* next = GetNextInFlow(); next; next = next->GetNextInFlow()) {
next->SetProperty(FirstInFlowProperty(), newFirstInFlow);
}
}
}

NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ConsumedBSizeProperty, nscoord);

nscoord nsSplittableFrame::CalcAndCacheConsumedBSize() {
Expand Down
22 changes: 20 additions & 2 deletions layout/generic/nsSplittableFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,13 @@ class nsSplittableFrame : public nsIFrame {
nsIFrame* GetPrevContinuation() const final;
nsIFrame* GetNextContinuation() const final;

// Set a previous/next non-fluid continuation.
// Set a previous non-fluid continuation.
void SetPrevContinuation(nsIFrame*) final;

// Set a next non-fluid continuation.
//
// WARNING: this method updates caches for next-continuations, so it has O(n)
// time complexity over the length of next-continuations in the chain.
void SetNextContinuation(nsIFrame*) final;

// Get the first/last continuation for this frame.
Expand All @@ -64,8 +69,13 @@ class nsSplittableFrame : public nsIFrame {
nsIFrame* GetPrevInFlow() const final;
nsIFrame* GetNextInFlow() const final;

// Set a previous/next fluid continuation.
// Set a previous fluid continuation.
void SetPrevInFlow(nsIFrame*) final;

// Set a next fluid continuation.
//
// WARNING: this method updates caches for next-continuations, so it has O(n)
// time complexity over the length of next-continuations in the chain.
void SetNextInFlow(nsIFrame*) final;

// Get the first/last frame in the current flow.
Expand All @@ -82,6 +92,14 @@ class nsSplittableFrame : public nsIFrame {
ClassID aID)
: nsIFrame(aStyle, aPresContext, aID) {}

// Update the first-continuation and first-in-flow cache for this frame and
// the next-continuations in the chain.
//
// Note: this function assumes that the first-continuation and first-in-flow
// caches are already up-to-date on this frame's
// prev-continuation/prev-in-flow frame (if there is such a frame).
void UpdateFirstContinuationAndFirstInFlowCache();

/**
* Return the sum of the block-axis content size of our previous
* continuations.
Expand Down

0 comments on commit d7ac9e2

Please sign in to comment.