Bug 1341724 - Part 4: stylo: Make font metrics usage threadsafe; r?heycam
MozReview-Commit-ID: 3EqpUy09UuI
--- a/gfx/src/nsDeviceContext.cpp
+++ b/gfx/src/nsDeviceContext.cpp
@@ -203,25 +203,30 @@ nsDeviceContext::nsDeviceContext()
nsDeviceContext::~nsDeviceContext()
{
if (mFontCache) {
mFontCache->Destroy();
}
}
-already_AddRefed<nsFontMetrics>
-nsDeviceContext::GetMetricsFor(const nsFont& aFont,
- const nsFontMetrics::Params& aParams)
+void
+nsDeviceContext::InitFontCache()
{
if (!mFontCache) {
mFontCache = new nsFontCache();
mFontCache->Init(this);
}
+}
+already_AddRefed<nsFontMetrics>
+nsDeviceContext::GetMetricsFor(const nsFont& aFont,
+ const nsFontMetrics::Params& aParams)
+{
+ InitFontCache();
return mFontCache->GetMetricsFor(aFont, aParams);
}
nsresult
nsDeviceContext::FlushFontCache(void)
{
if (mFontCache)
mFontCache->Flush();
--- a/gfx/src/nsDeviceContext.h
+++ b/gfx/src/nsDeviceContext.h
@@ -50,16 +50,22 @@ public:
/**
* Initialize the device context from a widget
* @param aWidget a widget to initialize the device context from
* @return error status
*/
nsresult Init(nsIWidget *aWidget);
+ /*
+ * Initialize the font cache if it hasn't been initialized yet.
+ * (Needed for stylo)
+ */
+ void InitFontCache();
+
/**
* Initialize the device context from a device context spec
* @param aDevSpec the specification of the printing device
* @return error status
*/
nsresult InitForPrinting(nsIDeviceContextSpec *aDevSpec);
/**
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -141,16 +141,18 @@ nsFontMetrics::nsFontMetrics(const nsFon
gfxFloat(mDeviceContext->AppUnitsPerCSSPixel());
mFontGroup = gfxPlatform::GetPlatform()->
CreateFontGroup(aFont.fontlist, &style, aParams.textPerf,
aParams.userFontSet, devToCssSize);
}
nsFontMetrics::~nsFontMetrics()
{
+ // Should not be dropped by stylo
+ MOZ_ASSERT(NS_IsMainThread());
if (mDeviceContext) {
mDeviceContext->FontMetricsDeleted(this);
}
}
void
nsFontMetrics::Destroy()
{
--- a/gfx/src/nsFontMetrics.h
+++ b/gfx/src/nsFontMetrics.h
@@ -56,17 +56,18 @@ public:
gfxFont::Orientation orientation = gfxFont::eHorizontal;
gfxUserFontSet* userFontSet = nullptr;
gfxTextPerfMetrics* textPerf = nullptr;
};
nsFontMetrics(const nsFont& aFont, const Params& aParams,
nsDeviceContext *aContext);
- NS_INLINE_DECL_REFCOUNTING(nsFontMetrics)
+ // Used by stylo
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsFontMetrics)
/**
* Destroy this font metrics. This breaks the association between
* the font metrics and the device context.
*/
void Destroy();
/**
--- a/gfx/thebes/gfxFcPlatformFontList.cpp
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -1062,16 +1062,23 @@ gfxFontconfigFontFamily::FindAllFontsFor
skipped++;
}
// Remove any compacted entries from the current group.
if (skipped) {
aFontEntryList.TruncateLength(aFontEntryList.Length() - skipped);
}
}
+/* virtual */
+gfxFontconfigFontFamily::~gfxFontconfigFontFamily()
+ {
+ // Should not be dropped by stylo
+ MOZ_ASSERT(NS_IsMainThread());
+}
+
gfxFontconfigFont::gfxFontconfigFont(cairo_scaled_font_t *aScaledFont,
FcPattern *aPattern,
gfxFloat aAdjustedSize,
gfxFontEntry *aFontEntry,
const gfxFontStyle *aFontStyle,
bool aNeedsBold) :
gfxFontconfigFontBase(aScaledFont, aPattern, aFontEntry, aFontStyle)
{
--- a/gfx/thebes/gfxFcPlatformFontList.h
+++ b/gfx/thebes/gfxFcPlatformFontList.h
@@ -190,17 +190,17 @@ public:
}
void
FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
nsTArray<gfxFontEntry*>& aFontEntryList,
bool& aNeedsSyntheticBold) override;
protected:
- virtual ~gfxFontconfigFontFamily() { }
+ virtual ~gfxFontconfigFontFamily();
nsTArray<nsCountedRef<FcPattern> > mFontPatterns;
bool mContainsAppFonts;
bool mHasNonScalableFaces;
};
class gfxFontconfigFont : public gfxFontconfigFontBase {
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -89,16 +89,23 @@ uint32_t gGlyphExtentsSetupFallBackToTig
* observes memory-pressure notification and tells fonts to clear their
* shaped-word caches to free up memory.
*/
MOZ_DEFINE_MALLOC_SIZE_OF(FontCacheMallocSizeOf)
NS_IMPL_ISUPPORTS(gfxFontCache::MemoryReporter, nsIMemoryReporter)
+/*virtual*/
+gfxTextRunFactory::~gfxTextRunFactory()
+{
+ // Should not be dropped by stylo
+ MOZ_ASSERT(NS_IsMainThread());
+}
+
NS_IMETHODIMP
gfxFontCache::MemoryReporter::CollectReports(
nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
{
FontCacheSizes sizes;
gfxFontCache::GetCache()->AddSizeOfIncludingThis(&FontCacheMallocSizeOf,
&sizes);
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -20,16 +20,17 @@
#include "nsExpirationTracker.h"
#include "gfxPlatform.h"
#include "nsIAtom.h"
#include "mozilla/HashFunctions.h"
#include "nsIMemoryReporter.h"
#include "nsIObserver.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Attributes.h"
+#include "MainThreadUtils.h"
#include <algorithm>
#include "DrawMode.h"
#include "nsDataHashtable.h"
#include "harfbuzz/hb.h"
#include "mozilla/gfx/2D.h"
#include "nsColor.h"
typedef struct _cairo cairo_t;
@@ -448,17 +449,18 @@ public:
cumulative.textrunConst += current.textrunConst;
cumulative.textrunDestr += current.textrunDestr;
cumulative.genericLookups += current.genericLookups;
memset(¤t, 0, sizeof(current));
}
};
class gfxTextRunFactory {
- NS_INLINE_DECL_REFCOUNTING(gfxTextRunFactory)
+ // Used by stylo
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxTextRunFactory)
public:
typedef mozilla::gfx::DrawTarget DrawTarget;
// Flags in the mask 0xFFFF0000 are reserved for textrun clients
// Flags in the mask 0x0000F000 are reserved for per-platform fonts
// Flags in the mask 0x00000FFF are set by the textrun creator.
enum {
@@ -587,17 +589,17 @@ public:
uint32_t *mInitialBreaks;
uint32_t mInitialBreakCount;
// The ratio to use to convert device pixels to application layout units
int32_t mAppUnitsPerDevUnit;
};
protected:
// Protected destructor, to discourage deletion outside of Release():
- virtual ~gfxTextRunFactory() {}
+ virtual ~gfxTextRunFactory();
};
/**
* gfxFontShaper
*
* This class implements text shaping (character to glyph mapping and
* glyph layout). There is a gfxFontShaper subclass for each text layout
* technology (uniscribe, core text, harfbuzz,....) we support.
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -136,16 +136,18 @@ gfxFontEntry::gfxFontEntry(const nsAStri
mComputedSizeOfUserFont(0)
{
memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
}
gfxFontEntry::~gfxFontEntry()
{
+ // Should not be dropped by stylo
+ MOZ_ASSERT(NS_IsMainThread());
if (mCOLR) {
hb_blob_destroy(mCOLR);
}
if (mCPAL) {
hb_blob_destroy(mCPAL);
}
@@ -1531,16 +1533,23 @@ gfxFontFamily::SearchAllFontsForChar(Glo
aMatchData->mBestMatch = fe;
aMatchData->mMatchedFamily = this;
aMatchData->mMatchRank = rank;
}
}
}
}
+/*virtual*/
+gfxFontFamily::~gfxFontFamily()
+{
+ // Should not be dropped by stylo
+ MOZ_ASSERT(NS_IsMainThread());
+}
+
/*static*/ void
gfxFontFamily::ReadOtherFamilyNamesForFace(const nsAString& aFamilyName,
const char *aNameData,
uint32_t aDataLength,
nsTArray<nsString>& aOtherFamilyNames,
bool useFullName)
{
const gfxFontUtils::NameHeader *nameHeader =
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -10,16 +10,17 @@
#include "nsString.h"
#include "gfxFontConstants.h"
#include "gfxFontFeatures.h"
#include "gfxFontUtils.h"
#include "nsTArray.h"
#include "nsTHashtable.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/MemoryReporting.h"
+#include "MainThreadUtils.h"
#include "nsUnicodeScriptCodes.h"
#include "nsDataHashtable.h"
#include "harfbuzz/hb.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/UniquePtr.h"
typedef struct gr_face gr_face;
@@ -96,17 +97,18 @@ private:
gfxCharacterMap& operator=(const gfxCharacterMap&);
};
class gfxFontEntry {
public:
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::unicode::Script Script;
- NS_INLINE_DECL_REFCOUNTING(gfxFontEntry)
+ // Used by stylo
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxFontEntry)
explicit gfxFontEntry(const nsAString& aName, bool aIsStandardFace = false);
// unique name for the face, *not* the family; not necessarily the
// "real" or user-friendly name, may be an internal identifier
const nsString& Name() const { return mName; }
// family name
@@ -582,17 +584,18 @@ struct GlobalFontMatch {
RefPtr<gfxFontEntry> mBestMatch; // current best match
RefPtr<gfxFontFamily> mMatchedFamily; // the family it belongs to
uint32_t mCount; // number of fonts matched
uint32_t mCmapsTested; // number of cmaps tested
};
class gfxFontFamily {
public:
- NS_INLINE_DECL_REFCOUNTING(gfxFontFamily)
+ // Used by stylo
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxFontFamily)
explicit gfxFontFamily(const nsAString& aName) :
mName(aName),
mOtherFamilyNamesInitialized(false),
mHasOtherFamilyNames(false),
mFaceNamesInitialized(false),
mHasStyles(false),
mIsSimpleFamily(false),
@@ -725,19 +728,17 @@ public:
#endif
void SetSkipSpaceFeatureCheck(bool aSkipCheck) {
mSkipDefaultFeatureSpaceCheck = aSkipCheck;
}
protected:
// Protected destructor, to discourage deletion outside of Release():
- virtual ~gfxFontFamily()
- {
- }
+ virtual ~gfxFontFamily();
bool ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
hb_blob_t *aNameTable,
bool useFullName = false);
// set whether this font family is in "bad" underline offset blacklist.
void SetBadUnderlineFonts() {
uint32_t i, numFonts = mAvailableFonts.Length();
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -1245,22 +1245,28 @@ void
gfxPlatformFontList::GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames)
{
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
RefPtr<gfxFontFamily>& family = iter.Data();
aFontFamilyNames.AppendElement(family->Name());
}
}
-nsILanguageAtomService*
-gfxPlatformFontList::GetLangService()
+void
+gfxPlatformFontList::InitLangService()
{
if (!mLangService) {
mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
}
+}
+
+nsILanguageAtomService*
+gfxPlatformFontList::GetLangService()
+{
+ InitLangService();
NS_ASSERTION(mLangService, "no language service!");
return mLangService;
}
nsIAtom*
gfxPlatformFontList::GetLangGroup(nsIAtom* aLanguage)
{
// map lang ==> langGroup
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -117,16 +117,19 @@ public:
nsresult InitFontList();
virtual void GetFontList(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts);
void UpdateFontList();
+ // Initialize the contained mLangService (for stylo, must be done in advance on main thread)
+ void InitLangService();
+
virtual void ClearLangGroupPrefFonts();
virtual void GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily> >& aFamilyArray);
gfxFontEntry*
SystemFindFontForChar(uint32_t aCh, uint32_t aNextCh,
Script aRunScript,
const gfxFontStyle* aStyle);
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -1715,16 +1715,18 @@ gfxFontGroup::gfxFontGroup(const FontFam
// We don't use SetUserFontSet() here, as we want to unconditionally call
// BuildFontList() rather than only do UpdateUserFonts() if it changed.
mCurrGeneration = GetGeneration();
BuildFontList();
}
gfxFontGroup::~gfxFontGroup()
{
+ // Should not be dropped by stylo
+ MOZ_ASSERT(NS_IsMainThread());
}
void
gfxFontGroup::BuildFontList()
{
// initialize fonts in the font family list
AutoTArray<gfxFontFamily*,10> fonts;
gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -317,16 +317,23 @@ gfxUserFontData::SizeOfIncludingThis(Mal
{
return aMallocSizeOf(this)
+ mMetadata.ShallowSizeOfExcludingThis(aMallocSizeOf)
+ mLocalName.SizeOfExcludingThisIfUnshared(aMallocSizeOf)
+ mRealName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
// Not counting mURI and mPrincipal, as those will be shared.
}
+/*virtual*/
+gfxUserFontFamily::~gfxUserFontFamily()
+{
+ // Should not be dropped by stylo
+ MOZ_ASSERT(NS_IsMainThread());
+}
+
void
gfxUserFontEntry::GetFamilyNameAndURIForLogging(nsACString& aFamilyName,
nsACString& aURI)
{
aFamilyName.Assign(NS_ConvertUTF16toUTF8(mFamilyName));
aURI.Truncate();
if (mSrcIndex == mSrcList.Length()) {
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -129,17 +129,17 @@ public:
class gfxUserFontFamily : public gfxFontFamily {
public:
friend class gfxUserFontSet;
explicit gfxUserFontFamily(const nsAString& aName)
: gfxFontFamily(aName) { }
- virtual ~gfxUserFontFamily() { }
+ virtual ~gfxUserFontFamily();
// add the given font entry to the end of the family's list
void AddFontEntry(gfxFontEntry* aFontEntry) {
// keep ref while removing existing entry
RefPtr<gfxFontEntry> fe = aFontEntry;
// remove existing entry, if already present
mAvailableFonts.RemoveElement(aFontEntry);
// insert at the beginning so that the last-defined font is the first
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -34,16 +34,17 @@ EXPORTS += [
'gfxFontVariations.h',
'gfxGradientCache.h',
'gfxImageSurface.h',
'gfxLineSegment.h',
'gfxMathTable.h',
'gfxMatrix.h',
'gfxPattern.h',
'gfxPlatform.h',
+ 'gfxPlatformFontList.h',
'gfxPoint.h',
'gfxPrefs.h',
'gfxQuad.h',
'gfxQuaternion.h',
'gfxRect.h',
'gfxSharedImageSurface.h',
'gfxSkipChars.h',
'gfxSVGGlyphs.h',
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1569,21 +1569,21 @@ ShutdownServo()
GeckoFontMetrics
Gecko_GetFontMetrics(RawGeckoPresContextBorrowed aPresContext,
bool aIsVertical,
const nsStyleFont* aFont,
nscoord aFontSize,
bool aUseUserFontSet)
{
MutexAutoLock lock(*sServoFontMetricsLock);
- aPresContext->SetUsesExChUnits(true);
GeckoFontMetrics ret;
// Safe because we are locked, and this function is only
// ever called from Servo parallel traversal or the main thread
nsPresContext* presContext = const_cast<nsPresContext*>(aPresContext);
+ presContext->SetUsesExChUnits(true);
RefPtr<nsFontMetrics> fm = nsRuleNode::GetMetricsFor(presContext, aIsVertical,
aFont, aFontSize,
aUseUserFontSet);
ret.mXSize = fm->XHeight();
gfxFloat zeroWidth = fm->GetThebesFontGroup()->GetFirstValidFont()->
GetMetrics(fm->Orientation()).zeroOrAveCharWidth;
ret.mChSize = ceil(aPresContext->AppUnitsPerDevPixel() * zeroWidth);
return ret;
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -1,25 +1,27 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ServoStyleSet.h"
+#include "gfxPlatformFontList.h"
#include "mozilla/DocumentStyleRootIterator.h"
#include "mozilla/ServoRestyleManager.h"
#include "mozilla/dom/AnonymousContent.h"
#include "mozilla/dom/ChildIterator.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ElementInlines.h"
#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "nsCSSAnonBoxes.h"
#include "nsCSSPseudoElements.h"
+#include "nsDeviceContext.h"
#include "nsHTMLStyleSheet.h"
#include "nsIDocumentInlines.h"
#include "nsPrintfCString.h"
#include "nsStyleContext.h"
#include "nsStyleSet.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -36,16 +38,19 @@ ServoStyleSet::~ServoStyleSet()
}
void
ServoStyleSet::Init(nsPresContext* aPresContext)
{
mPresContext = aPresContext;
mRawSet.reset(Servo_StyleSet_Init(aPresContext));
+ mPresContext->DeviceContext()->InitFontCache();
+ gfxPlatformFontList::PlatformFontList()->InitLangService();
+
// Now that we have an mRawSet, go ahead and notify about whatever stylesheets
// we have so far.
for (auto& sheetArray : mSheets) {
for (auto& sheet : sheetArray) {
// There's no guarantee this will create a list on the servo side whose
// ordering matches the list that would have been created had all those
// sheets been appended/prepended/etc after we had mRawSet. But hopefully
// that's OK (e.g. because servo doesn't care about the relative ordering
@@ -193,16 +198,19 @@ ServoStyleSet::ResolveMappedAttrDeclarat
void
ServoStyleSet::PreTraverseSync()
{
ResolveMappedAttrDeclarationBlocks();
// This is lazily computed and pseudo matching needs to access
// it so force computation early.
mPresContext->Document()->GetDocumentState();
+
+ // Ensure that the @font-face data is not stale
+ mPresContext->Document()->GetUserFontSet();
}
void
ServoStyleSet::PreTraverse()
{
PreTraverseSync();
// Process animation stuff that we should avoid doing during the parallel