Bug 1509167 - Cache an nsFontMetrics reference in nsTextFrame so that we don't have to re-create it on every DrawText call. r=jwatt

This commit is contained in:
Jonathan Kew 2018-11-26 17:59:50 +00:00
parent 33bcfcbc16
commit 803d5550bd
2 changed files with 69 additions and 22 deletions

View File

@ -2040,6 +2040,22 @@ GetFontGroupForFrame(const nsIFrame* aFrame, float aFontSizeInflation,
return fontGroup;
}
static gfxFontGroup*
GetInflatedFontGroupForFrame(nsTextFrame* aFrame)
{
gfxTextRun* textRun = aFrame->GetTextRun(nsTextFrame::eInflated);
if (textRun) {
return textRun->GetFontGroup();
}
if (!aFrame->InflatedFontMetrics()) {
float inflation = nsLayoutUtils::FontSizeInflationFor(aFrame);
RefPtr<nsFontMetrics> metrics =
nsLayoutUtils::GetFontMetricsForFrame(aFrame, inflation);
aFrame->SetInflatedFontMetrics(metrics);
}
return aFrame->InflatedFontMetrics()->GetThebesFontGroup();
}
static already_AddRefed<DrawTarget>
CreateReferenceDrawTarget(const nsTextFrame* aTextFrame)
{
@ -2284,13 +2300,15 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
// Now build the textrun
nsTextFrame* firstFrame = mMappedFlows[0].mStartFrame;
float fontInflation;
gfxFontGroup* fontGroup;
if (mWhichTextRun == nsTextFrame::eNotInflated) {
fontInflation = 1.0f;
fontGroup = GetFontGroupForFrame(firstFrame, fontInflation);
} else {
fontInflation = nsLayoutUtils::FontSizeInflationFor(firstFrame);
fontGroup = GetInflatedFontGroupForFrame(firstFrame);
}
gfxFontGroup* fontGroup = GetFontGroupForFrame(firstFrame, fontInflation);
if (!fontGroup) {
DestroyUserData(userDataToDestroy);
return nullptr;
@ -3126,8 +3144,10 @@ public:
* *must* be called before this!!!
*/
PropertyProvider(nsTextFrame* aFrame, const gfxSkipCharsIterator& aStart,
nsTextFrame::TextRunType aWhichTextRun)
nsTextFrame::TextRunType aWhichTextRun,
nsFontMetrics* aFontMetrics)
: mTextRun(aFrame->GetTextRun(aWhichTextRun)), mFontGroup(nullptr),
mFontMetrics(aFontMetrics),
mTextStyle(aFrame->StyleText()),
mFrag(aFrame->GetContent()->GetText()),
mLineContainer(nullptr),
@ -3189,7 +3209,7 @@ public:
gfxFontGroup* GetFontGroup() const {
if (!mFontGroup) {
InitFontGroupAndFontMetrics();
mFontGroup = GetFontMetrics()->GetThebesFontGroup();
}
return mFontGroup;
}
@ -3216,10 +3236,21 @@ protected:
void SetupJustificationSpacing(bool aPostReflow);
void InitFontGroupAndFontMetrics() const {
float inflation = (mWhichTextRun == nsTextFrame::eInflated)
? mFrame->GetFontSizeInflation() : 1.0f;
mFontGroup = GetFontGroupForFrame(mFrame, inflation,
getter_AddRefs(mFontMetrics));
if (!mFontMetrics) {
if (mWhichTextRun == nsTextFrame::eInflated) {
if (!mFrame->InflatedFontMetrics()) {
float inflation = mFrame->GetFontSizeInflation();
mFontMetrics =
nsLayoutUtils::GetFontMetricsForFrame(mFrame, inflation);
mFrame->SetInflatedFontMetrics(mFontMetrics);
} else {
mFontMetrics = mFrame->InflatedFontMetrics();
}
} else {
mFontMetrics = nsLayoutUtils::GetFontMetricsForFrame(mFrame, 1.0f);
}
}
mFontGroup = mFontMetrics->GetThebesFontGroup();
}
const RefPtr<gfxTextRun> mTextRun;
@ -4760,6 +4791,7 @@ nsTextFrame::RemoveTextRun(gfxTextRun* aTextRun)
{
if (aTextRun == mTextRun) {
mTextRun = nullptr;
mFontMetrics = nullptr;
return true;
}
if ((GetStateBits() & TEXT_HAS_FONT_INFLATION) &&
@ -4779,6 +4811,10 @@ nsTextFrame::ClearTextRun(nsTextFrame* aStartContinuation,
return;
}
if (aWhichTextRun == nsTextFrame::eInflated) {
mFontMetrics = nullptr;
}
DebugOnly<bool> checkmTextrun = textRun == mTextRun;
UnhookTextRunFromFrames(textRun, aStartContinuation);
MOZ_ASSERT(checkmTextrun ? !mTextRun
@ -5538,7 +5574,7 @@ NS_DECLARE_FRAME_PROPERTY_DELETABLE(EmphasisMarkProperty, EmphasisMarkInfo)
static already_AddRefed<gfxTextRun>
GenerateTextRunForEmphasisMarks(nsTextFrame* aFrame,
nsFontMetrics* aFontMetrics,
gfxFontGroup* aFontGroup,
ComputedStyle* aComputedStyle,
const nsStyleText* aStyleText)
{
@ -5550,7 +5586,7 @@ GenerateTextRunForEmphasisMarks(nsTextFrame* aFrame,
// The emphasis marks should always be rendered upright per spec.
flags = gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_UPRIGHT;
}
return aFontMetrics->GetThebesFontGroup()->
return aFontGroup->
MakeTextRun<char16_t>(emphasisString.get(), emphasisString.Length(),
dt, appUnitsPerDevUnit, flags,
nsTextFrameUtils::Flags(), nullptr);
@ -5590,7 +5626,8 @@ nsTextFrame::UpdateTextEmphasis(WritingMode aWM, PropertyProvider& aProvider)
GetFontSizeInflation());
EmphasisMarkInfo* info = new EmphasisMarkInfo;
info->textRun =
GenerateTextRunForEmphasisMarks(this, fm, computedStyle, styleText);
GenerateTextRunForEmphasisMarks(this, fm->GetThebesFontGroup(),
computedStyle, styleText);
info->advance = info->textRun->GetAdvanceWidth();
// Calculate the baseline offset
@ -6725,7 +6762,7 @@ nsTextFrame::GetCaretColorAt(int32_t aOffset)
nscolor result = nsFrame::GetCaretColorAt(aOffset);
gfxSkipCharsIterator iter = EnsureTextRun(nsTextFrame::eInflated);
PropertyProvider provider(this, iter, nsTextFrame::eInflated);
PropertyProvider provider(this, iter, nsTextFrame::eInflated, mFontMetrics);
int32_t contentOffset = provider.GetStart().GetOriginalOffset();
int32_t contentLength = provider.GetOriginalLength();
MOZ_ASSERT(aOffset >= contentOffset &&
@ -6796,7 +6833,7 @@ nsTextFrame::MeasureCharClippedText(nscoord aVisIStartEdge,
if (!mTextRun)
return false;
PropertyProvider provider(this, iter, nsTextFrame::eInflated);
PropertyProvider provider(this, iter, nsTextFrame::eInflated, mFontMetrics);
// Trim trailing whitespace
provider.InitializeForDisplay(true);
@ -6982,7 +7019,7 @@ nsTextFrame::PaintText(const PaintTextParams& aParams,
if (!mTextRun)
return;
PropertyProvider provider(this, iter, nsTextFrame::eInflated);
PropertyProvider provider(this, iter, nsTextFrame::eInflated, mFontMetrics);
if (aItem.mIsFrameSelected.isNothing()) {
aItem.mIsFrameSelected.emplace(IsSelected());
}
@ -7501,7 +7538,7 @@ nsTextFrame::GetCharacterOffsetAtFramePointInternal(const nsPoint& aPoint,
if (!mTextRun)
return offsets;
PropertyProvider provider(this, iter, nsTextFrame::eInflated);
PropertyProvider provider(this, iter, nsTextFrame::eInflated, mFontMetrics);
// Trim leading but not trailing whitespace if possible
provider.InitializeForDisplay(false);
gfxFloat width = mTextRun->IsVertical()
@ -7593,9 +7630,7 @@ nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
nsRect givenRect = aRect;
RefPtr<nsFontMetrics> fm =
nsLayoutUtils::GetFontMetricsForFrame(this, GetFontSizeInflation());
gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
gfxFontGroup* fontGroup = GetInflatedFontGroupForFrame(this);
gfxFont* firstFont = fontGroup->GetFirstValidFont();
WritingMode wm = GetWritingMode();
bool verticalRun = wm.IsVertical();
@ -7795,7 +7830,7 @@ nsTextFrame::GetPointFromOffset(int32_t inOffset,
if (!mTextRun)
return NS_ERROR_FAILURE;
PropertyProvider properties(this, iter, nsTextFrame::eInflated);
PropertyProvider properties(this, iter, nsTextFrame::eInflated, mFontMetrics);
// Don't trim trailing whitespace, we want the caret to appear in the right
// place if it's positioned there
properties.InitializeForDisplay(false);
@ -7826,7 +7861,7 @@ nsTextFrame::GetCharacterRectsInRange(int32_t aInOffset,
}
gfxSkipCharsIterator iter = EnsureTextRun(nsTextFrame::eInflated);
PropertyProvider properties(this, iter, nsTextFrame::eInflated);
PropertyProvider properties(this, iter, nsTextFrame::eInflated, mFontMetrics);
// Don't trim trailing whitespace, we want the caret to appear in the right
// place if it's positioned there
properties.InitializeForDisplay(false);
@ -8724,6 +8759,7 @@ nsTextFrame::AddInlineMinISize(gfxContext *aRenderingContext,
// FIXME: Ideally, if we already have a text run, we'd move it to be
// the uninflated text run.
ClearTextRun(nullptr, nsTextFrame::eInflated);
mFontMetrics = nullptr;
}
nsTextFrame* f;
@ -8876,6 +8912,7 @@ nsTextFrame::AddInlinePrefISize(gfxContext *aRenderingContext,
// FIXME: Ideally, if we already have a text run, we'd move it to be
// the uninflated text run.
ClearTextRun(nullptr, nsTextFrame::eInflated);
mFontMetrics = nullptr;
}
nsTextFrame* f;
@ -8944,7 +8981,7 @@ nsTextFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const
return nsRect(0, 0, 0, 0);
PropertyProvider provider(const_cast<nsTextFrame*>(this), iter,
nsTextFrame::eInflated);
nsTextFrame::eInflated, mFontMetrics);
// Trim trailing whitespace
provider.InitializeForDisplay(true);
@ -8978,7 +9015,7 @@ nsTextFrame::GetPrefWidthTightBounds(gfxContext* aContext,
return NS_ERROR_FAILURE;
PropertyProvider provider(const_cast<nsTextFrame*>(this), iter,
nsTextFrame::eInflated);
nsTextFrame::eInflated, mFontMetrics);
provider.InitializeForMeasure();
gfxTextRun::Metrics metrics =
@ -9456,6 +9493,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
// FIXME: Ideally, if we already have a text run, we'd move it to be
// the uninflated text run.
ClearTextRun(nullptr, nsTextFrame::eInflated);
mFontMetrics = nullptr;
}
gfxSkipCharsIterator iter =
@ -9971,7 +10009,7 @@ nsTextFrame::RecomputeOverflow(nsIFrame* aBlockFrame)
if (!mTextRun)
return result;
PropertyProvider provider(this, iter, nsTextFrame::eInflated);
PropertyProvider provider(this, iter, nsTextFrame::eInflated, mFontMetrics);
// Don't trim trailing space, in case we need to paint it as selected.
provider.InitializeForDisplay(false);

View File

@ -19,6 +19,7 @@
#include "gfxSkipChars.h"
#include "gfxTextRun.h"
#include "nsDisplayList.h"
#include "nsFontMetrics.h"
#include "JustificationUtils.h"
#include "RubyUtils.h"
@ -670,9 +671,17 @@ public:
*/
void NotifyNativeAnonymousTextnodeChange(uint32_t aOldLength);
void SetInflatedFontMetrics(nsFontMetrics* aMetrics) {
mFontMetrics = aMetrics;
}
nsFontMetrics* InflatedFontMetrics() const {
return mFontMetrics;
}
protected:
virtual ~nsTextFrame();
RefPtr<nsFontMetrics> mFontMetrics;
RefPtr<gfxTextRun> mTextRun;
nsTextFrame* mNextContinuation;
// The key invariant here is that mContentOffset never decreases along