Bug 1749103 - Avoid thrashing gfxDWriteFont's ScaledFonts between canvas and content. r=jfkthame

This is essentially a partial revert of a cleanup done in bug 1742896. If canvas and content
are using the same underlying gfxDWriteFont and simultaneously retrieving a ScaledFont, this
may cause the ScaledFont to get repeatedly destroyed and re-instantiated every time we switch
from one context to the other. If this destruction happens at an inopportune time while WR
is still using a blob image with the font, it can potentially trigger undesirable assertions.

For now, duplicate the part of Bas' original patch from bug 1730722 that separatedly cached
the GDI and non-GDI versions of the ScaledFont. This way, both will exist for the lifetime
of the underlying gfxDWriteFont and thus avoid the thrashing.

Differential Revision: https://phabricator.services.mozilla.com/D135442
This commit is contained in:
Lee Salzman 2022-01-13 16:18:47 +00:00
parent 09dc5b2ce7
commit 93d24303eb
4 changed files with 26 additions and 17 deletions

View File

@ -84,8 +84,7 @@ gfxDWriteFont::gfxDWriteFont(const RefPtr<UnscaledFontDWrite>& aUnscaledFont,
mMetrics(nullptr), mMetrics(nullptr),
mUseSubpixelPositions(false), mUseSubpixelPositions(false),
mAllowManualShowGlyphs(true), mAllowManualShowGlyphs(true),
mAzureScaledFontUsedClearType(false), mAzureScaledFontUsedClearType(false) {
mAzureScaledFontForcedGDI(false) {
// If the IDWriteFontFace1 interface is available, we can use that for // If the IDWriteFontFace1 interface is available, we can use that for
// faster glyph width retrieval. // faster glyph width retrieval.
mFontFace->QueryInterface(__uuidof(IDWriteFontFace1), mFontFace->QueryInterface(__uuidof(IDWriteFontFace1),
@ -754,12 +753,14 @@ void gfxDWriteFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
already_AddRefed<ScaledFont> gfxDWriteFont::GetScaledFont( already_AddRefed<ScaledFont> gfxDWriteFont::GetScaledFont(
const TextRunDrawParams& aRunParams) { const TextRunDrawParams& aRunParams) {
bool forceGDI = aRunParams.allowGDI && GetForceGDIClassic(); if (mAzureScaledFontUsedClearType != UsingClearType()) {
if (mAzureScaledFontUsedClearType != UsingClearType() ||
mAzureScaledFontForcedGDI != forceGDI) {
mAzureScaledFont = nullptr; mAzureScaledFont = nullptr;
mAzureScaledFontGDI = nullptr;
} }
if (!mAzureScaledFont) { bool forceGDI = aRunParams.allowGDI && GetForceGDIClassic();
RefPtr<ScaledFont>& azureScaledFont =
forceGDI ? mAzureScaledFontGDI : mAzureScaledFont;
if (!azureScaledFont) {
gfxDWriteFontEntry* fe = static_cast<gfxDWriteFontEntry*>(mFontEntry.get()); gfxDWriteFontEntry* fe = static_cast<gfxDWriteFontEntry*>(mFontEntry.get());
bool useEmbeddedBitmap = bool useEmbeddedBitmap =
(gfxVars::SystemTextRenderingMode() == DWRITE_RENDERING_MODE_DEFAULT || (gfxVars::SystemTextRenderingMode() == DWRITE_RENDERING_MODE_DEFAULT ||
@ -767,19 +768,17 @@ already_AddRefed<ScaledFont> gfxDWriteFont::GetScaledFont(
fe->IsCJKFont() && HasBitmapStrikeForSize(NS_lround(mAdjustedSize)); fe->IsCJKFont() && HasBitmapStrikeForSize(NS_lround(mAdjustedSize));
const gfxFontStyle* fontStyle = GetStyle(); const gfxFontStyle* fontStyle = GetStyle();
mAzureScaledFont = Factory::CreateScaledFontForDWriteFont( azureScaledFont = Factory::CreateScaledFontForDWriteFont(
mFontFace, fontStyle, GetUnscaledFont(), GetAdjustedSize(), mFontFace, fontStyle, GetUnscaledFont(), GetAdjustedSize(),
useEmbeddedBitmap, forceGDI); useEmbeddedBitmap, forceGDI);
if (!mAzureScaledFont) { if (!azureScaledFont) {
return nullptr; return nullptr;
} }
InitializeScaledFont(); InitializeScaledFont(azureScaledFont);
mAzureScaledFontUsedClearType = UsingClearType(); mAzureScaledFontUsedClearType = UsingClearType();
mAzureScaledFontForcedGDI = forceGDI;
} }
RefPtr<ScaledFont> scaledFont(mAzureScaledFont); return do_AddRef(azureScaledFont);
return scaledFont.forget();
} }
bool gfxDWriteFont::ShouldRoundXOffset(cairo_t* aCairo) const { bool gfxDWriteFont::ShouldRoundXOffset(cairo_t* aCairo) const {

View File

@ -103,7 +103,11 @@ class gfxDWriteFont final : public gfxFont {
// Used to record the sUseClearType setting at the time mAzureScaledFont // Used to record the sUseClearType setting at the time mAzureScaledFont
// was set up, so we can tell if it's stale and needs to be re-created. // was set up, so we can tell if it's stale and needs to be re-created.
bool mAzureScaledFontUsedClearType; bool mAzureScaledFontUsedClearType;
bool mAzureScaledFontForcedGDI;
// Cache the GDI version of the ScaledFont so that font keys and other
// meta-data can remain stable even if there is thrashing between GDI and
// non-GDI usage.
RefPtr<mozilla::gfx::ScaledFont> mAzureScaledFontGDI;
bool UsingClearType() { bool UsingClearType() {
return mozilla::gfx::gfxVars::SystemTextQuality() == CLEARTYPE_QUALITY; return mozilla::gfx::gfxVars::SystemTextQuality() == CLEARTYPE_QUALITY;

View File

@ -1552,14 +1552,15 @@ already_AddRefed<mozilla::gfx::ScaledFont> gfxFont::GetScaledFont(
return GetScaledFont(params); return GetScaledFont(params);
} }
void gfxFont::InitializeScaledFont() { void gfxFont::InitializeScaledFont(
if (!mAzureScaledFont) { const RefPtr<mozilla::gfx::ScaledFont>& aScaledFont) {
if (!aScaledFont) {
return; return;
} }
float angle = AngleForSyntheticOblique(); float angle = AngleForSyntheticOblique();
if (angle != 0.0f) { if (angle != 0.0f) {
mAzureScaledFont->SetSyntheticObliqueAngle(angle); aScaledFont->SetSyntheticObliqueAngle(angle);
} }
} }

View File

@ -1901,7 +1901,12 @@ class gfxFont {
already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFont( already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFont(
mozilla::gfx::DrawTarget* aDrawTarget); mozilla::gfx::DrawTarget* aDrawTarget);
void InitializeScaledFont(); // gfxFont implementations may cache ScaledFont versions other than the
// default, so InitializeScaledFont must support explicitly specifying
// other ScaledFonts than the default to initialize.
void InitializeScaledFont(
const RefPtr<mozilla::gfx::ScaledFont>& aScaledFont);
void InitializeScaledFont() { InitializeScaledFont(mAzureScaledFont); }
bool KerningDisabled() { return mKerningSet && !mKerningEnabled; } bool KerningDisabled() { return mKerningSet && !mKerningEnabled; }