зеркало из 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) {
|
||||
nsIFrame* relativeTo =
|
||||
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();
|
||||
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.
|
||||
int32_t textContentStart = fstart;
|
||||
|
|
|
@ -4384,6 +4384,35 @@ void nsTextFrame::DestroyFrom(nsIFrame* aDestructRoot,
|
|||
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 {
|
||||
public:
|
||||
NS_DECL_FRAMEARENA_HELPERS(nsContinuingTextFrame)
|
||||
|
@ -4410,10 +4439,16 @@ class nsContinuingTextFrame final : public nsTextFrame {
|
|||
nsTextFrame* prevFirst = mFirstContinuation;
|
||||
if (mPrevContinuation) {
|
||||
mFirstContinuation = mPrevContinuation->FirstContinuation();
|
||||
if (mFirstContinuation) {
|
||||
mFirstContinuation->ClearCachedContinuations();
|
||||
}
|
||||
} else {
|
||||
mFirstContinuation = nullptr;
|
||||
}
|
||||
if (mFirstContinuation != prevFirst) {
|
||||
if (prevFirst) {
|
||||
prevFirst->ClearCachedContinuations();
|
||||
}
|
||||
auto* f = static_cast<nsContinuingTextFrame*>(mNextContinuation);
|
||||
while (f) {
|
||||
f->mFirstContinuation = mFirstContinuation;
|
||||
|
@ -4438,10 +4473,16 @@ class nsContinuingTextFrame final : public nsTextFrame {
|
|||
nsTextFrame* prevFirst = mFirstContinuation;
|
||||
if (mPrevContinuation) {
|
||||
mFirstContinuation = mPrevContinuation->FirstContinuation();
|
||||
if (mFirstContinuation) {
|
||||
mFirstContinuation->ClearCachedContinuations();
|
||||
}
|
||||
} else {
|
||||
mFirstContinuation = nullptr;
|
||||
}
|
||||
if (mFirstContinuation != prevFirst) {
|
||||
if (prevFirst) {
|
||||
prevFirst->ClearCachedContinuations();
|
||||
}
|
||||
auto* f = static_cast<nsContinuingTextFrame*>(mNextContinuation);
|
||||
while (f) {
|
||||
f->mFirstContinuation = mFirstContinuation;
|
||||
|
@ -4457,6 +4498,8 @@ class nsContinuingTextFrame final : public nsTextFrame {
|
|||
return mFirstContinuation;
|
||||
};
|
||||
|
||||
nsTArray<nsTextFrame*>* GetContinuations() final { return nullptr; }
|
||||
|
||||
void AddInlineMinISize(gfxContext* aRenderingContext,
|
||||
InlineMinISizeData* aData) final;
|
||||
void AddInlinePrefISize(gfxContext* aRenderingContext,
|
||||
|
@ -9121,6 +9164,12 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
|||
RemoveStateBits(TEXT_REFLOW_FLAGS | TEXT_WHITESPACE_FLAGS);
|
||||
mReflowRequestedForCharDataChange = false;
|
||||
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.
|
||||
// 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
|
||||
|
|
|
@ -214,6 +214,9 @@ class nsTextFrame : public nsIFrame {
|
|||
// nsQueryFrame
|
||||
NS_DECL_QUERYFRAME
|
||||
|
||||
NS_DECLARE_FRAME_PROPERTY_DELETABLE(ContinuationsProperty,
|
||||
nsTArray<nsTextFrame*>)
|
||||
|
||||
// nsIFrame
|
||||
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayListSet& aLists) final;
|
||||
|
@ -781,6 +784,11 @@ class nsTextFrame : public nsIFrame {
|
|||
|
||||
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:
|
||||
virtual ~nsTextFrame();
|
||||
|
||||
|
@ -815,6 +823,9 @@ class nsTextFrame : public nsIFrame {
|
|||
};
|
||||
mutable SelectionState mIsSelected;
|
||||
|
||||
// Whether a cached continuations array is present.
|
||||
bool mHasContinuationsProperty = false;
|
||||
|
||||
/**
|
||||
* Return true if the frame is part of a Selection.
|
||||
* Helper method to implement the public IsSelected() API.
|
||||
|
@ -999,6 +1010,16 @@ class nsTextFrame : public nsIFrame {
|
|||
|
||||
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.
|
||||
* 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,
|
||||
PropertyProvider& aProperties);
|
||||
|
||||
public:
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsTextFrame::TrimmedOffsetFlags)
|
||||
|
|
Загрузка…
Ссылка в новой задаче