зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1725555 - patch 2 - Enable the primary nsTextFrame to provide, and cache, an array of all the continuations in the chain. r=emilio
This allows us to binary-search the continuations from nsRange::CollectClientRectsAndText, instead of linear-searching the linked list for every range we need to look up. Depends on D122998 Differential Revision: https://phabricator.services.mozilla.com/D122999
This commit is contained in:
Родитель
2dddbe283f
Коммит
6481b69a6c
|
@ -2647,10 +2647,40 @@ static nsresult GetPartialTextRect(RectCallback* aCallback,
|
||||||
if (textFrame) {
|
if (textFrame) {
|
||||||
nsIFrame* relativeTo =
|
nsIFrame* relativeTo =
|
||||||
nsLayoutUtils::GetContainingBlockForClientRect(textFrame);
|
nsLayoutUtils::GetContainingBlockForClientRect(textFrame);
|
||||||
for (nsTextFrame* f = textFrame; f;
|
|
||||||
f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
|
// Try to binary-search the list of continuations for the starting point.
|
||||||
|
// (GetContinuations is fallible; if it returns nullptr, we'll just start
|
||||||
|
// from the beginning.)
|
||||||
|
nsTArray<nsTextFrame*>* continuations = textFrame->GetContinuations();
|
||||||
|
nsTextFrame* f = textFrame;
|
||||||
|
if (continuations) {
|
||||||
|
size_t index;
|
||||||
|
if (BinarySearchIf(
|
||||||
|
*continuations, 0, continuations->Length(),
|
||||||
|
[=](nsTextFrame* aFrame) -> int {
|
||||||
|
if (aStartOffset < aFrame->GetContentOffset()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (aStartOffset > aFrame->GetContentOffset()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
&index)) {
|
||||||
|
f = (*continuations)[index];
|
||||||
|
} else {
|
||||||
|
f = (*continuations)[index ? index - 1 : 0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; f; f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
|
||||||
int32_t fstart = f->GetContentOffset(), fend = f->GetContentEnd();
|
int32_t fstart = f->GetContentOffset(), fend = f->GetContentEnd();
|
||||||
if (fend <= aStartOffset || fstart >= aEndOffset) continue;
|
if (fend <= aStartOffset) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fstart >= aEndOffset) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate the text content offsets we'll need if text is requested.
|
// Calculate the text content offsets we'll need if text is requested.
|
||||||
int32_t textContentStart = fstart;
|
int32_t textContentStart = fstart;
|
||||||
|
|
|
@ -4384,6 +4384,35 @@ void nsTextFrame::DestroyFrom(nsIFrame* aDestructRoot,
|
||||||
nsIFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
|
nsIFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsTArray<nsTextFrame*>* nsTextFrame::GetContinuations() {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
// Only for use on the primary frame, which has no prev-continuation.
|
||||||
|
MOZ_ASSERT(!GetPrevContinuation());
|
||||||
|
if (!mNextContinuation) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (mHasContinuationsProperty) {
|
||||||
|
return GetProperty(ContinuationsProperty());
|
||||||
|
}
|
||||||
|
size_t count = 0;
|
||||||
|
for (nsIFrame* f = this; f; f = f->GetNextContinuation()) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
auto* continuations = new nsTArray<nsTextFrame*>;
|
||||||
|
if (continuations->SetCapacity(count, fallible)) {
|
||||||
|
for (nsTextFrame* f = this; f;
|
||||||
|
f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
|
||||||
|
continuations->AppendElement(f);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete continuations;
|
||||||
|
continuations = nullptr;
|
||||||
|
}
|
||||||
|
AddProperty(ContinuationsProperty(), continuations);
|
||||||
|
mHasContinuationsProperty = true;
|
||||||
|
return continuations;
|
||||||
|
}
|
||||||
|
|
||||||
class nsContinuingTextFrame final : public nsTextFrame {
|
class nsContinuingTextFrame final : public nsTextFrame {
|
||||||
public:
|
public:
|
||||||
NS_DECL_FRAMEARENA_HELPERS(nsContinuingTextFrame)
|
NS_DECL_FRAMEARENA_HELPERS(nsContinuingTextFrame)
|
||||||
|
@ -4410,10 +4439,16 @@ class nsContinuingTextFrame final : public nsTextFrame {
|
||||||
nsTextFrame* prevFirst = mFirstContinuation;
|
nsTextFrame* prevFirst = mFirstContinuation;
|
||||||
if (mPrevContinuation) {
|
if (mPrevContinuation) {
|
||||||
mFirstContinuation = mPrevContinuation->FirstContinuation();
|
mFirstContinuation = mPrevContinuation->FirstContinuation();
|
||||||
|
if (mFirstContinuation) {
|
||||||
|
mFirstContinuation->ClearCachedContinuations();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mFirstContinuation = nullptr;
|
mFirstContinuation = nullptr;
|
||||||
}
|
}
|
||||||
if (mFirstContinuation != prevFirst) {
|
if (mFirstContinuation != prevFirst) {
|
||||||
|
if (prevFirst) {
|
||||||
|
prevFirst->ClearCachedContinuations();
|
||||||
|
}
|
||||||
auto* f = static_cast<nsContinuingTextFrame*>(mNextContinuation);
|
auto* f = static_cast<nsContinuingTextFrame*>(mNextContinuation);
|
||||||
while (f) {
|
while (f) {
|
||||||
f->mFirstContinuation = mFirstContinuation;
|
f->mFirstContinuation = mFirstContinuation;
|
||||||
|
@ -4438,10 +4473,16 @@ class nsContinuingTextFrame final : public nsTextFrame {
|
||||||
nsTextFrame* prevFirst = mFirstContinuation;
|
nsTextFrame* prevFirst = mFirstContinuation;
|
||||||
if (mPrevContinuation) {
|
if (mPrevContinuation) {
|
||||||
mFirstContinuation = mPrevContinuation->FirstContinuation();
|
mFirstContinuation = mPrevContinuation->FirstContinuation();
|
||||||
|
if (mFirstContinuation) {
|
||||||
|
mFirstContinuation->ClearCachedContinuations();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mFirstContinuation = nullptr;
|
mFirstContinuation = nullptr;
|
||||||
}
|
}
|
||||||
if (mFirstContinuation != prevFirst) {
|
if (mFirstContinuation != prevFirst) {
|
||||||
|
if (prevFirst) {
|
||||||
|
prevFirst->ClearCachedContinuations();
|
||||||
|
}
|
||||||
auto* f = static_cast<nsContinuingTextFrame*>(mNextContinuation);
|
auto* f = static_cast<nsContinuingTextFrame*>(mNextContinuation);
|
||||||
while (f) {
|
while (f) {
|
||||||
f->mFirstContinuation = mFirstContinuation;
|
f->mFirstContinuation = mFirstContinuation;
|
||||||
|
@ -4457,6 +4498,8 @@ class nsContinuingTextFrame final : public nsTextFrame {
|
||||||
return mFirstContinuation;
|
return mFirstContinuation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nsTArray<nsTextFrame*>* GetContinuations() final { return nullptr; }
|
||||||
|
|
||||||
void AddInlineMinISize(gfxContext* aRenderingContext,
|
void AddInlineMinISize(gfxContext* aRenderingContext,
|
||||||
InlineMinISizeData* aData) final;
|
InlineMinISizeData* aData) final;
|
||||||
void AddInlinePrefISize(gfxContext* aRenderingContext,
|
void AddInlinePrefISize(gfxContext* aRenderingContext,
|
||||||
|
@ -9121,6 +9164,12 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
||||||
RemoveStateBits(TEXT_REFLOW_FLAGS | TEXT_WHITESPACE_FLAGS);
|
RemoveStateBits(TEXT_REFLOW_FLAGS | TEXT_WHITESPACE_FLAGS);
|
||||||
mReflowRequestedForCharDataChange = false;
|
mReflowRequestedForCharDataChange = false;
|
||||||
RemoveProperty(WebRenderTextBounds());
|
RemoveProperty(WebRenderTextBounds());
|
||||||
|
|
||||||
|
// Discard cached continuations array that will be invalidated by the reflow.
|
||||||
|
if (nsTextFrame* first = FirstContinuation()) {
|
||||||
|
first->ClearCachedContinuations();
|
||||||
|
}
|
||||||
|
|
||||||
// Temporarily map all possible content while we construct our new textrun.
|
// Temporarily map all possible content while we construct our new textrun.
|
||||||
// so that when doing reflow our styles prevail over any part of the
|
// so that when doing reflow our styles prevail over any part of the
|
||||||
// textrun we look at. Note that next-in-flows may be mapping the same
|
// textrun we look at. Note that next-in-flows may be mapping the same
|
||||||
|
|
|
@ -214,6 +214,9 @@ class nsTextFrame : public nsIFrame {
|
||||||
// nsQueryFrame
|
// nsQueryFrame
|
||||||
NS_DECL_QUERYFRAME
|
NS_DECL_QUERYFRAME
|
||||||
|
|
||||||
|
NS_DECLARE_FRAME_PROPERTY_DELETABLE(ContinuationsProperty,
|
||||||
|
nsTArray<nsTextFrame*>)
|
||||||
|
|
||||||
// nsIFrame
|
// nsIFrame
|
||||||
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||||
const nsDisplayListSet& aLists) final;
|
const nsDisplayListSet& aLists) final;
|
||||||
|
@ -781,6 +784,11 @@ class nsTextFrame : public nsIFrame {
|
||||||
|
|
||||||
nsRect WebRenderBounds();
|
nsRect WebRenderBounds();
|
||||||
|
|
||||||
|
// Return pointer to an array of all frames in the continuation chain, or
|
||||||
|
// null if we're too short of memory. (This is only meant to be called on the
|
||||||
|
// first text frame in the chain; continuations will always return null.)
|
||||||
|
virtual nsTArray<nsTextFrame*>* GetContinuations();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~nsTextFrame();
|
virtual ~nsTextFrame();
|
||||||
|
|
||||||
|
@ -815,6 +823,9 @@ class nsTextFrame : public nsIFrame {
|
||||||
};
|
};
|
||||||
mutable SelectionState mIsSelected;
|
mutable SelectionState mIsSelected;
|
||||||
|
|
||||||
|
// Whether a cached continuations array is present.
|
||||||
|
bool mHasContinuationsProperty = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the frame is part of a Selection.
|
* Return true if the frame is part of a Selection.
|
||||||
* Helper method to implement the public IsSelected() API.
|
* Helper method to implement the public IsSelected() API.
|
||||||
|
@ -999,6 +1010,16 @@ class nsTextFrame : public nsIFrame {
|
||||||
|
|
||||||
void ClearMetrics(ReflowOutput& aMetrics);
|
void ClearMetrics(ReflowOutput& aMetrics);
|
||||||
|
|
||||||
|
// Clear any cached continuations array; this should be called whenever the
|
||||||
|
// chain is modified.
|
||||||
|
void ClearCachedContinuations() {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
if (mHasContinuationsProperty) {
|
||||||
|
RemoveProperty(ContinuationsProperty());
|
||||||
|
mHasContinuationsProperty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UpdateIteratorFromOffset() updates the iterator from a given offset.
|
* UpdateIteratorFromOffset() updates the iterator from a given offset.
|
||||||
* Also, aInOffset may be updated to cluster start if aInOffset isn't
|
* Also, aInOffset may be updated to cluster start if aInOffset isn't
|
||||||
|
@ -1010,8 +1031,6 @@ class nsTextFrame : public nsIFrame {
|
||||||
|
|
||||||
nsPoint GetPointFromIterator(const gfxSkipCharsIterator& aIter,
|
nsPoint GetPointFromIterator(const gfxSkipCharsIterator& aIter,
|
||||||
PropertyProvider& aProperties);
|
PropertyProvider& aProperties);
|
||||||
|
|
||||||
public:
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsTextFrame::TrimmedOffsetFlags)
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsTextFrame::TrimmedOffsetFlags)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче