mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Bug 1268021 - Implement memory reporting for the user-font cache. r=njn
This commit is contained in:
parent
dac4222c8f
commit
fb5e0a3be3
@ -99,7 +99,8 @@ gfxFontEntry::gfxFontEntry() :
|
||||
mUnitsPerEm(0),
|
||||
mHBFace(nullptr),
|
||||
mGrFace(nullptr),
|
||||
mGrFaceRefCnt(0)
|
||||
mGrFaceRefCnt(0),
|
||||
mComputedSizeOfUserFont(0)
|
||||
{
|
||||
memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
|
||||
memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
|
||||
@ -138,7 +139,8 @@ gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
|
||||
mUnitsPerEm(0),
|
||||
mHBFace(nullptr),
|
||||
mGrFace(nullptr),
|
||||
mGrFaceRefCnt(0)
|
||||
mGrFaceRefCnt(0),
|
||||
mComputedSizeOfUserFont(0)
|
||||
{
|
||||
memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
|
||||
memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
|
||||
@ -1146,6 +1148,32 @@ gfxFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
||||
AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
||||
}
|
||||
|
||||
// This is used to report the size of an individual downloaded font in the
|
||||
// user font cache. (Fonts that are part of the platform font list accumulate
|
||||
// their sizes to the font list's reporter using the AddSizeOf... methods
|
||||
// above.)
|
||||
size_t
|
||||
gfxFontEntry::ComputedSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
FontListSizes s = { 0 };
|
||||
AddSizeOfExcludingThis(aMallocSizeOf, &s);
|
||||
|
||||
// When reporting memory used for the main platform font list,
|
||||
// where we're typically summing the totals for a few hundred font faces,
|
||||
// we report the fields of FontListSizes separately.
|
||||
// But for downloaded user fonts, the actual resource data (added below)
|
||||
// will dominate, and the minor overhead of these pieces isn't worth
|
||||
// splitting out for an individual font.
|
||||
size_t result = s.mFontListSize + s.mFontTableCacheSize + s.mCharMapsSize;
|
||||
|
||||
if (mIsDataUserFont) {
|
||||
MOZ_ASSERT(mComputedSizeOfUserFont > 0, "user font with no data?");
|
||||
result += mComputedSizeOfUserFont;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// class gfxFontFamily
|
||||
|
@ -375,12 +375,17 @@ public:
|
||||
// the fonts belonging to this font entry.
|
||||
void NotifyFontDestroyed(gfxFont* aFont);
|
||||
|
||||
// For memory reporting
|
||||
// For memory reporting of the platform font list.
|
||||
virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
FontListSizes* aSizes) const;
|
||||
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
FontListSizes* aSizes) const;
|
||||
|
||||
// Used for reporting on individual font entries in the user font cache,
|
||||
// which are not present in the platform font list.
|
||||
size_t
|
||||
ComputedSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
// Used when checking for complex script support, to mask off cmap ranges
|
||||
struct ScriptRange {
|
||||
uint32_t rangeStart;
|
||||
@ -453,6 +458,7 @@ protected:
|
||||
friend class gfxUserFcFontEntry;
|
||||
friend class gfxFontFamily;
|
||||
friend class gfxSingleFaceMacFontFamily;
|
||||
friend class gfxUserFontEntry;
|
||||
|
||||
gfxFontEntry();
|
||||
|
||||
@ -531,6 +537,12 @@ protected:
|
||||
static void GrReleaseTable(const void *aAppFaceHandle,
|
||||
const void *aTableBuffer);
|
||||
|
||||
// For memory reporting: size of user-font data belonging to this entry.
|
||||
// We record this in the font entry because the actual data block may be
|
||||
// handed over to platform APIs, so that it would become difficult (and
|
||||
// platform-specific) to measure it directly at report-gathering time.
|
||||
uint32_t mComputedSizeOfUserFont;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Font table hashtable, to support GetFontTable for harfbuzz.
|
||||
|
@ -602,6 +602,8 @@ gfxUserFontEntry::SetLoadState(UserFontLoadState aLoadState)
|
||||
mUserFontLoadState = aLoadState;
|
||||
}
|
||||
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(UserFontMallocSizeOfOnAlloc)
|
||||
|
||||
bool
|
||||
gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
|
||||
{
|
||||
@ -628,6 +630,7 @@ gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
|
||||
// if necessary. The original data in aFontData is left unchanged.
|
||||
uint32_t saneLen;
|
||||
uint32_t fontCompressionRatio = 0;
|
||||
size_t computedSize = 0;
|
||||
const uint8_t* saneData =
|
||||
SanitizeOpenTypeData(aFontData, aLength, saneLen, fontType);
|
||||
if (!saneData) {
|
||||
@ -651,6 +654,15 @@ gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
|
||||
// arbitrary/malicious data from the web.
|
||||
gfxFontUtils::GetFullNameFromSFNT(saneData, saneLen,
|
||||
originalFullName);
|
||||
|
||||
// Record size for memory reporting purposes. We measure this now
|
||||
// because by the time we potentially want to collect reports, this
|
||||
// data block may have been handed off to opaque OS font APIs that
|
||||
// don't allow us to retrieve or measure it directly.
|
||||
// The *OnAlloc function will also tell DMD about this block, as the
|
||||
// OS font code may hold on to it for an extended period.
|
||||
computedSize = UserFontMallocSizeOfOnAlloc(saneData);
|
||||
|
||||
// Here ownership of saneData is passed to the platform,
|
||||
// which will delete it when no longer required
|
||||
fe = gfxPlatform::GetPlatform()->MakePlatformFont(mName,
|
||||
@ -665,6 +677,8 @@ gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
|
||||
}
|
||||
|
||||
if (fe) {
|
||||
fe->mComputedSizeOfUserFont = computedSize;
|
||||
|
||||
// Save a copy of the metadata block (if present) for nsIDOMFontFace
|
||||
// to use if required. Ownership of the metadata block will be passed
|
||||
// to the gfxUserFontData record below.
|
||||
@ -1151,6 +1165,13 @@ gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry* aFontEntry,
|
||||
obs->AddObserver(flusher, "last-pb-context-exited", false);
|
||||
obs->AddObserver(flusher, "xpcom-shutdown", false);
|
||||
}
|
||||
|
||||
// Create and register a memory reporter for sUserFonts.
|
||||
// This reporter is never unregistered, but that's OK because
|
||||
// the reporter checks whether sUserFonts is null, so it would
|
||||
// be safe to call even after UserFontCache::Shutdown has deleted
|
||||
// the cache.
|
||||
RegisterStrongMemoryReporter(new MemoryReporter());
|
||||
}
|
||||
|
||||
if (data->mLength) {
|
||||
@ -1277,6 +1298,89 @@ gfxUserFontSet::UserFontCache::Shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(UserFontsMallocSizeOf)
|
||||
|
||||
nsresult
|
||||
gfxUserFontSet::UserFontCache::Entry::ReportMemory(nsIMemoryReporterCallback* aCb,
|
||||
nsISupports* aClosure,
|
||||
bool aAnonymize)
|
||||
{
|
||||
nsAutoCString path("explicit/gfx/user-fonts/font(");
|
||||
|
||||
if (aAnonymize) {
|
||||
path.AppendPrintf("<anonymized-%p>", this);
|
||||
} else {
|
||||
if (mFontEntry) { // this should always be present
|
||||
NS_ConvertUTF16toUTF8 familyName(mFontEntry->mFamilyName);
|
||||
path.AppendPrintf("family=%s", familyName.get());
|
||||
}
|
||||
if (mURI) {
|
||||
nsCString spec;
|
||||
mURI->GetSpec(spec);
|
||||
spec.ReplaceChar('/', '\\');
|
||||
// Some fonts are loaded using horrendously-long data: URIs;
|
||||
// truncate those before reporting them.
|
||||
bool isData;
|
||||
if (NS_SUCCEEDED(mURI->SchemeIs("data", &isData)) && isData &&
|
||||
spec.Length() > 255) {
|
||||
spec.Truncate(252);
|
||||
spec.Append("...");
|
||||
}
|
||||
path.AppendPrintf(", url=%s", spec.get());
|
||||
}
|
||||
if (mPrincipal) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
mPrincipal->GetURI(getter_AddRefs(uri));
|
||||
nsCString spec;
|
||||
uri->GetSpec(spec);
|
||||
if (!spec.IsEmpty()) {
|
||||
// Include a clue as to who loaded this resource. (Note that
|
||||
// because of font entry sharing, other pages may now be using
|
||||
// this resource, and the original page may not even be loaded
|
||||
// any longer.)
|
||||
spec.ReplaceChar('/', '\\');
|
||||
path.AppendPrintf(", principal=%s", spec.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
path.Append(')');
|
||||
|
||||
return aCb->
|
||||
Callback(EmptyCString(), path,
|
||||
nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
|
||||
mFontEntry->ComputedSizeOfExcludingThis(UserFontsMallocSizeOf),
|
||||
NS_LITERAL_CSTRING("Memory used by @font-face resource."),
|
||||
aClosure);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(gfxUserFontSet::UserFontCache::MemoryReporter,
|
||||
nsIMemoryReporter)
|
||||
|
||||
NS_IMETHODIMP
|
||||
gfxUserFontSet::UserFontCache::MemoryReporter::CollectReports(
|
||||
nsIMemoryReporterCallback* aCb, nsISupports* aClosure, bool aAnonymize)
|
||||
{
|
||||
if (!sUserFonts) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
for (auto it = sUserFonts->Iter(); !it.Done(); it.Next()) {
|
||||
nsresult rv = it.Get()->ReportMemory(aCb, aClosure, aAnonymize);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return aCb->
|
||||
Callback(EmptyCString(),
|
||||
NS_LITERAL_CSTRING("explicit/gfx/user-fonts/cache-overhead"),
|
||||
nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
|
||||
sUserFonts->ShallowSizeOfIncludingThis(UserFontsMallocSizeOf),
|
||||
NS_LITERAL_CSTRING("Memory used by the @font-face cache, "
|
||||
"not counting the actual font resources."),
|
||||
aClosure);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_USERFONT_CACHE
|
||||
|
||||
void
|
||||
|
@ -322,6 +322,17 @@ public:
|
||||
// Clear everything so that we don't leak URIs and Principals.
|
||||
static void Shutdown();
|
||||
|
||||
// Memory-reporting support.
|
||||
class MemoryReporter final : public nsIMemoryReporter
|
||||
{
|
||||
private:
|
||||
~MemoryReporter() { }
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMEMORYREPORTER
|
||||
};
|
||||
|
||||
#ifdef DEBUG_USERFONT_CACHE
|
||||
// dump contents
|
||||
static void Dump();
|
||||
@ -437,6 +448,10 @@ public:
|
||||
bool IsPersistent() const { return mPersistence == kPersistent; }
|
||||
bool IsPrivate() const { return mPrivate; }
|
||||
|
||||
nsresult ReportMemory(nsIMemoryReporterCallback* aCb,
|
||||
nsISupports* aClosure,
|
||||
bool aAnonymize);
|
||||
|
||||
#ifdef DEBUG_USERFONT_CACHE
|
||||
void Dump();
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user