diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 6ab42fc095c8..7af9cef8101a 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -4494,7 +4494,6 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final mSetTextCount++; auto* pfl = gfxPlatformFontList::PlatformFontList(); pfl->Lock(); - mFontgrp->CheckForUpdatedPlatformList(); mFontgrp->UpdateUserFonts(); // ensure user font generation is current // adjust flags for current direction run gfx::ShapedTextFlags flags = mTextRunFlags; @@ -5128,9 +5127,6 @@ gfxFontGroup* CanvasRenderingContext2D::GetCurrentFontStyle() { NS_ERROR("Default canvas font is invalid"); } } - } else { - // The fontgroup needs to check if its cached families/faces are valid. - fontGroup->CheckForUpdatedPlatformList(); } return fontGroup; diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 409546806b04..78ff1027bd6e 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1871,9 +1871,8 @@ gfxFontGroup::gfxFontGroup(nsPresContext* aPresContext, break; } // We don't use SetUserFontSet() here, as we want to unconditionally call - // BuildFontList() rather than only do UpdateUserFonts() if it changed. - mCurrGeneration = GetGeneration(); - BuildFontList(); + // EnsureFontList() rather than only do UpdateUserFonts() if it changed. + mCurrGeneration = 0; } gfxFontGroup::~gfxFontGroup() { @@ -1887,11 +1886,58 @@ static StyleGenericFontFamily GetDefaultGeneric(nsAtom* aLanguage) { ->GetDefaultGeneric(); } -void gfxFontGroup::BuildFontList() { - // initialize fonts in the font family list +class DeferredClearResolvedFonts final : public nsIRunnable { + public: + NS_DECL_THREADSAFE_ISUPPORTS + + DeferredClearResolvedFonts() = delete; + explicit DeferredClearResolvedFonts( + const DeferredClearResolvedFonts& aOther) = delete; + explicit DeferredClearResolvedFonts( + nsTArray&& aFontList) + : mFontList(std::move(aFontList)) {} + + protected: + virtual ~DeferredClearResolvedFonts() {} + + NS_IMETHOD Run(void) override { + mFontList.Clear(); + return NS_OK; + } + + nsTArray mFontList; +}; + +NS_IMPL_ISUPPORTS(DeferredClearResolvedFonts, nsIRunnable) + +void gfxFontGroup::EnsureFontList() { + // Ensure resolved font instances are valid; discard them if necessary. + auto* pfl = gfxPlatformFontList::PlatformFontList(); + if (mFontListGeneration != pfl->GetGeneration()) { + // Forget cached fonts that may no longer be valid. + mLastPrefFamily = FontFamily(); + mLastPrefFont = nullptr; + mDefaultFont = nullptr; + mResolvedFonts = false; + } + + // If we have already resolved the font list, just return. + if (mResolvedFonts) { + return; + } + + // Discard existing fonts; but if we're in servo traversal, defer the actual + // deletion. + // XXX(jfkthame) is this really necessary, or is the assertion in + // ~gfxUserFontFamily() obsolete? + if (gfxFontUtils::IsInServoTraversal()) { + NS_DispatchToMainThread(new DeferredClearResolvedFonts(std::move(mFonts))); + } else { + mFonts.Clear(); + } + + // (Re-)build the list of fonts. AutoTArray fonts; - gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); - mFontListGeneration = pfl->GetGeneration(); // lookup fonts in the fontlist for (const StyleSingleFontFamily& name : mFamilyList.list.AsSpan()) { @@ -1935,6 +1981,9 @@ void gfxFontGroup::BuildFontList() { AddFamilyToFontList(f.mFamily.mUnshared, f.mGeneric); } } + + mFontListGeneration = pfl->GetGeneration(); + mResolvedFonts = true; } void gfxFontGroup::AddPlatformFont(const nsACString& aName, bool aQuotedName, @@ -2228,8 +2277,7 @@ already_AddRefed gfxFontGroup::GetDefaultFont() { already_AddRefed gfxFontGroup::GetFirstValidFont( uint32_t aCh, StyleGenericFontFamily* aGeneric, bool* aIsFirst) { - // Ensure cached font instances are valid. - CheckForUpdatedPlatformList(); + EnsureFontList(); uint32_t count = mFonts.Length(); bool loading = false; @@ -2313,6 +2361,7 @@ already_AddRefed gfxFontGroup::GetFirstValidFont( } already_AddRefed gfxFontGroup::GetFirstMathFont() { + EnsureFontList(); uint32_t count = mFonts.Length(); for (uint32_t i = 0; i < count; ++i) { RefPtr font = GetFontAt(i); @@ -3625,26 +3674,22 @@ void gfxFontGroup::SetUserFontSet(gfxUserFontSet* aUserFontSet) { } uint64_t gfxFontGroup::GetGeneration() { - if (!mUserFontSet) return 0; - return mUserFontSet->GetGeneration(); + return mUserFontSet ? mUserFontSet->GetGeneration() : 0; } uint64_t gfxFontGroup::GetRebuildGeneration() { - if (!mUserFontSet) return 0; - return mUserFontSet->GetRebuildGeneration(); + return mUserFontSet ? mUserFontSet->GetRebuildGeneration() : 0; } void gfxFontGroup::UpdateUserFonts() { if (mCurrGeneration < GetRebuildGeneration()) { // fonts in userfont set changed, need to redo the fontlist - mFonts.Clear(); + mResolvedFonts = false; ClearCachedData(); - BuildFontList(); mCurrGeneration = GetGeneration(); } else if (mCurrGeneration != GetGeneration()) { // load state change occurred, verify load state and validity of fonts ClearCachedData(); - uint32_t len = mFonts.Length(); for (uint32_t i = 0; i < len; i++) { FamilyFace& ff = mFonts[i]; @@ -3653,22 +3698,30 @@ void gfxFontGroup::UpdateUserFonts() { } ff.CheckState(mSkipDrawing); } - mCurrGeneration = GetGeneration(); } } bool gfxFontGroup::ContainsUserFont(const gfxUserFontEntry* aUserFont) { UpdateUserFonts(); - // search through the fonts list for a specific user font - uint32_t len = mFonts.Length(); - for (uint32_t i = 0; i < len; i++) { - FamilyFace& ff = mFonts[i]; - if (ff.EqualsUserFont(aUserFont)) { - return true; + + // If we have resolved the font list to concrete font faces, search through + // the list for a specific user font face. + if (mResolvedFonts) { + uint32_t len = mFonts.Length(); + for (uint32_t i = 0; i < len; i++) { + FamilyFace& ff = mFonts[i]; + if (ff.EqualsUserFont(aUserFont)) { + return true; + } } + return false; } - return false; + + // If the font list is currently not resolved, we assume it might use the + // given face. (This method is only called when we have already seen that + // the family name is present in the list.) + return true; } already_AddRefed gfxFontGroup::WhichPrefFontSupportsChar( diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index 61cdd3b2516d..53ec85cbf7f4 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -904,6 +904,8 @@ class gfxFontGroup final : public gfxTextRunFactory { public: typedef mozilla::intl::Script Script; typedef gfxShapedText::CompressedGlyph CompressedGlyph; + friend class MathMLTextRunFactory; + friend class nsCaseTransformTextRunFactory; static void Shutdown(); // platform must call this to release the languageAtomService @@ -1062,18 +1064,6 @@ class gfxFontGroup final : public gfxTextRunFactory { int32_t aAppUnitsPerDevPixel, mozilla::gfx::ShapedTextFlags aFlags, LazyReferenceDrawTargetGetter& aRefDrawTargetGetter); - void CheckForUpdatedPlatformList() { - auto* pfl = gfxPlatformFontList::PlatformFontList(); - if (mFontListGeneration != pfl->GetGeneration()) { - // Forget cached fonts that may no longer be valid. - mLastPrefFamily = FontFamily(); - mLastPrefFont = nullptr; - mDefaultFont = nullptr; - mFonts.Clear(); - BuildFontList(); - } - } - nsAtom* Language() const { return mLanguage.get(); } // Get font metrics to be used as the basis for CSS font-relative units. @@ -1086,6 +1076,7 @@ class gfxFontGroup final : public gfxTextRunFactory { protected: friend class mozilla::PostTraversalTask; + friend class DeferredClearResolvedFonts; struct TextRange { TextRange(uint32_t aStart, uint32_t aEnd, gfxFont* aFont, @@ -1401,6 +1392,8 @@ class gfxFontGroup final : public gfxTextRunFactory { bool mExplicitLanguage; // Does mLanguage come from an explicit attribute? + bool mResolvedFonts = false; // Whether the mFonts array has been set up. + eFontPresentation mEmojiPresentation = eFontPresentation::Any; // Generic font family used to select among font prefs during fallback. @@ -1427,8 +1420,9 @@ class gfxFontGroup final : public gfxTextRunFactory { const T* aString, uint32_t aLength, const Parameters* aParams, mozilla::gfx::ShapedTextFlags aFlags, nsTextFrameUtils::Flags aFlags2); - // Initialize the list of fonts - void BuildFontList(); + // Ensure the font-family list & style properties from CSS/prefs/defaults is + // resolved to the array of available font faces we'll actually use. + void EnsureFontList(); // Get the font at index i within the fontlist, for character aCh (in case // of fonts with multiple resources and unicode-range partitioning). diff --git a/layout/generic/MathMLTextRunFactory.cpp b/layout/generic/MathMLTextRunFactory.cpp index 03d6c0d5ed4f..e5c959d6c507 100644 --- a/layout/generic/MathMLTextRunFactory.cpp +++ b/layout/generic/MathMLTextRunFactory.cpp @@ -519,8 +519,8 @@ void MathMLTextRunFactory::RebuildTextRun( StyleMathVariant mathVar = StyleMathVariant::None; bool doMathvariantStyling = true; - // Ensure it will be safe to call FindFontForChar in the loop below. - fontGroup->CheckForUpdatedPlatformList(); + // Ensure the fontGroup is ready to be searched. + fontGroup->EnsureFontList(); for (uint32_t i = 0; i < length; ++i) { int extraChars = 0; diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 7de667643643..75fe7d241932 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -2385,14 +2385,7 @@ already_AddRefed BuildTextRunsScanner::BuildTextRunForFrames( fontInflation = nsLayoutUtils::FontSizeInflationFor(firstFrame); fontGroup = GetInflatedFontGroupForFrame(firstFrame); } - - if (fontGroup) { - // Refresh fontgroup if necessary, before trying to build textruns. - fontGroup->CheckForUpdatedPlatformList(); - } else { - DestroyUserData(userDataToDestroy); - return nullptr; - } + MOZ_ASSERT(fontGroup); if (flags2 & nsTextFrameUtils::Flags::HasTab) { flags |= gfx::ShapedTextFlags::TEXT_ENABLE_SPACING; diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp index 29fbade0005e..140223815b7a 100644 --- a/layout/generic/nsTextRunTransformations.cpp +++ b/layout/generic/nsTextRunTransformations.cpp @@ -770,10 +770,11 @@ bool nsCaseTransformTextRunFactory::TransformString( // Bug 930504. Some platforms do not have fonts for Mathematical // Alphanumeric Symbols. Hence we only perform the transform if a // character is actually available. + auto* fontGroup = aTextRun->GetFontGroup(); + fontGroup->EnsureFontList(); FontMatchType matchType; - RefPtr mathFont = - aTextRun->GetFontGroup()->FindFontForChar( - ch2, 0, 0, intl::Script::COMMON, nullptr, &matchType); + RefPtr mathFont = fontGroup->FindFontForChar( + ch2, 0, 0, intl::Script::COMMON, nullptr, &matchType); if (mathFont) { ch = ch2; }