From c8435823ca532d71c02294b1da4532797405297a Mon Sep 17 00:00:00 2001 From: Jonathan Kew <jkew@mozilla.com> Date: Wed, 24 Apr 2024 12:54:46 +0000 Subject: [PATCH] Bug 1878199 - patch 2 - If the FontFaceImpl has a user-font entry, hold its lock during Add/Remove font-set operations. a=dmeehan This should fix the intermittently-reported race here, by ensuring that access into the FontFaceImpl from GetUserFontSets(), called by the main thread, cannot race with changes being made by the AddFontSet()/RemoveFontSet() methods. (If the FontFaceImpl doesn't have an mUserFontEntry yet, then these methods don't need to lock, as only the owning thread will be touching it.) Original Revision: https://phabricator.services.mozilla.com/D207296 Differential Revision: https://phabricator.services.mozilla.com/D208098 --- layout/style/FontFaceImpl.cpp | 35 +++++++++++++++++++++++++---------- layout/style/FontFaceImpl.h | 7 ++----- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/layout/style/FontFaceImpl.cpp b/layout/style/FontFaceImpl.cpp index b927fd3f1b27d..bd7e6a595f3a4 100644 --- a/layout/style/FontFaceImpl.cpp +++ b/layout/style/FontFaceImpl.cpp @@ -676,25 +676,40 @@ bool FontFaceImpl::IsInFontFaceSet(FontFaceSetImpl* aFontFaceSet) const { void FontFaceImpl::AddFontFaceSet(FontFaceSetImpl* aFontFaceSet) { MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet)); - if (mFontFaceSet == aFontFaceSet) { - mInFontFaceSet = true; + auto doAddFontFaceSet = [&]() { + if (mFontFaceSet == aFontFaceSet) { + mInFontFaceSet = true; + } else { + mOtherFontFaceSets.AppendElement(aFontFaceSet); + } + }; + + if (mUserFontEntry) { + AutoWriteLock lock(mUserFontEntry->Lock()); + doAddFontFaceSet(); } else { - mOtherFontFaceSets.AppendElement(aFontFaceSet); + doAddFontFaceSet(); } } void FontFaceImpl::RemoveFontFaceSet(FontFaceSetImpl* aFontFaceSet) { MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet)); - if (mFontFaceSet == aFontFaceSet) { - mInFontFaceSet = false; - } else { - mOtherFontFaceSets.RemoveElement(aFontFaceSet); - } + auto doRemoveFontFaceSet = [&]() { + if (mFontFaceSet == aFontFaceSet) { + mInFontFaceSet = false; + } else { + mOtherFontFaceSets.RemoveElement(aFontFaceSet); + } + }; - // The caller should be holding a strong reference to the FontFaceSetImpl. if (mUserFontEntry) { - mUserFontEntry->CheckUserFontSet(); + AutoWriteLock lock(mUserFontEntry->Lock()); + doRemoveFontFaceSet(); + // The caller should be holding a strong reference to the FontFaceSetImpl. + mUserFontEntry->CheckUserFontSetLocked(); + } else { + doRemoveFontFaceSet(); } } diff --git a/layout/style/FontFaceImpl.h b/layout/style/FontFaceImpl.h index ec6783540d860..7f1279a248beb 100644 --- a/layout/style/FontFaceImpl.h +++ b/layout/style/FontFaceImpl.h @@ -56,11 +56,6 @@ class FontFaceImpl final { void GetUserFontSets(nsTArray<RefPtr<gfxUserFontSet>>& aResult) override; already_AddRefed<gfxUserFontSet> GetUserFontSet() const override; - void CheckUserFontSet() { - AutoWriteLock lock(mLock); - CheckUserFontSetLocked(); - } - #ifdef DEBUG bool HasUserFontSet(gfxUserFontSet* aFontSet) const { AutoReadLock lock(mLock); @@ -72,6 +67,8 @@ class FontFaceImpl final { void RemoveFontFace(FontFaceImpl* aOwner); void FindFontFaceOwners(nsTHashSet<FontFace*>& aOwners); + RWLock& Lock() const MOZ_RETURN_CAPABILITY(mLock) { return mLock; } + protected: void CheckUserFontSetLocked() MOZ_REQUIRES(mLock); -- GitLab