зеркало из https://github.com/mozilla/pjs.git
b=605872 refactor mFontTableCache, providing a sharing/saving distinction to fix a hb_blob_t leak r=jfkthame a=blocking
--HG-- extra : transplant_source : u%FB%E2%9D%A8g%1ASG%FB%A4%12%A2kGi%882%ED9
This commit is contained in:
Родитель
95764752f5
Коммит
735f50e2ac
|
@ -189,26 +189,132 @@ gfxFontEntry::FindOrMakeFont(const gfxFontStyle *aStyle, PRBool aNeedsBold)
|
|||
return f;
|
||||
}
|
||||
|
||||
gfxFontEntry::FontTableCacheEntry::FontTableCacheEntry
|
||||
(nsTArray<PRUint8>& aBuffer,
|
||||
PRUint32 aTag,
|
||||
nsClassHashtable<nsUint32HashKey,FontTableCacheEntry>& aCache)
|
||||
: mTag(aTag), mCache(aCache)
|
||||
/**
|
||||
* FontTableBlobData
|
||||
*
|
||||
* See FontTableHashEntry for the general strategy.
|
||||
*/
|
||||
|
||||
class gfxFontEntry::FontTableBlobData {
|
||||
public:
|
||||
// Adopts the content of aBuffer.
|
||||
// Pass a non-null aHashEntry only if it should be cleared if/when this
|
||||
// FontTableBlobData is deleted.
|
||||
FontTableBlobData(nsTArray<PRUint8>& aBuffer,
|
||||
FontTableHashEntry *aHashEntry)
|
||||
: mHashEntry(aHashEntry), mHashtable()
|
||||
{
|
||||
MOZ_COUNT_CTOR(FontTableBlobData);
|
||||
mTableData.SwapElements(aBuffer);
|
||||
}
|
||||
|
||||
~FontTableBlobData() {
|
||||
MOZ_COUNT_DTOR(FontTableBlobData);
|
||||
if (mHashEntry) {
|
||||
if (mHashtable) {
|
||||
mHashtable->RemoveEntry(mHashEntry->GetKey());
|
||||
} else {
|
||||
mHashEntry->Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Useful for creating blobs
|
||||
const char *GetTable() const
|
||||
{
|
||||
return reinterpret_cast<const char*>(mTableData.Elements());
|
||||
}
|
||||
PRUint32 GetTableLength() const { return mTableData.Length(); }
|
||||
|
||||
// Tell this FontTableBlobData to remove the HashEntry when this is
|
||||
// destroyed.
|
||||
void ManageHashEntry(nsTHashtable<FontTableHashEntry> *aHashtable)
|
||||
{
|
||||
mHashtable = aHashtable;
|
||||
}
|
||||
|
||||
// Disconnect from the HashEntry (because the blob has already been
|
||||
// removed from the hashtable).
|
||||
void ForgetHashEntry()
|
||||
{
|
||||
mHashEntry = nsnull;
|
||||
}
|
||||
|
||||
private:
|
||||
// The font table data block, owned (via adoption)
|
||||
nsTArray<PRUint8> mTableData;
|
||||
// The blob destroy function needs to know the hashtable entry,
|
||||
FontTableHashEntry *mHashEntry;
|
||||
// and the owning hashtable, so that it can remove the entry.
|
||||
nsTHashtable<FontTableHashEntry> *mHashtable;
|
||||
|
||||
// not implemented
|
||||
FontTableBlobData(const FontTableBlobData&);
|
||||
};
|
||||
|
||||
void
|
||||
gfxFontEntry::FontTableHashEntry::SaveTable(nsTArray<PRUint8>& aTable)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FontTableCacheEntry);
|
||||
mData.SwapElements(aBuffer);
|
||||
mBlob = hb_blob_create((const char*)mData.Elements(), mData.Length(),
|
||||
Clear();
|
||||
// adopts elements of aTable
|
||||
FontTableBlobData *data = new FontTableBlobData(aTable, nsnull);
|
||||
mBlob = hb_blob_create(data->GetTable(), data->GetTableLength(),
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
gfxFontEntry::FontTableCacheEntry::Destroy,
|
||||
this);
|
||||
DeleteFontTableBlobData, data);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
gfxFontEntry::FontTableCacheEntry::Destroy(void *aUserData)
|
||||
hb_blob_t *
|
||||
gfxFontEntry::FontTableHashEntry::
|
||||
ShareTableAndGetBlob(nsTArray<PRUint8>& aTable,
|
||||
nsTHashtable<FontTableHashEntry> *aHashtable)
|
||||
{
|
||||
gfxFontEntry::FontTableCacheEntry *ftce =
|
||||
static_cast<gfxFontEntry::FontTableCacheEntry*>(aUserData);
|
||||
ftce->mCache.Remove(ftce->mTag);
|
||||
Clear();
|
||||
// adopts elements of aTable
|
||||
mSharedBlobData = new FontTableBlobData(aTable, this);
|
||||
mBlob = hb_blob_create(mSharedBlobData->GetTable(),
|
||||
mSharedBlobData->GetTableLength(),
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
DeleteFontTableBlobData, mSharedBlobData);
|
||||
if (!mSharedBlobData) {
|
||||
// The FontTableBlobData was destroyed during hb_blob_create().
|
||||
// The (empty) blob is still be held in the hashtable with a strong
|
||||
// reference.
|
||||
return hb_blob_reference(mBlob);
|
||||
}
|
||||
|
||||
// Tell the FontTableBlobData to remove this hash entry when destroyed.
|
||||
// The hashtable does not keep a strong reference.
|
||||
mSharedBlobData->ManageHashEntry(aHashtable);
|
||||
return mBlob;
|
||||
}
|
||||
|
||||
void
|
||||
gfxFontEntry::FontTableHashEntry::Clear()
|
||||
{
|
||||
// If the FontTableBlobData is managing the hash entry, then the blob is
|
||||
// not owned by this HashEntry; otherwise there is strong reference to the
|
||||
// blob that must be removed.
|
||||
if (mSharedBlobData) {
|
||||
mSharedBlobData->ForgetHashEntry();
|
||||
mSharedBlobData = nsnull;
|
||||
} else if (mBlob) {
|
||||
hb_blob_destroy(mBlob);
|
||||
}
|
||||
mBlob = nsnull;
|
||||
}
|
||||
|
||||
// a hb_destroy_func for hb_blob_create
|
||||
|
||||
/* static */ void
|
||||
gfxFontEntry::FontTableHashEntry::DeleteFontTableBlobData(void *aBlobData)
|
||||
{
|
||||
delete static_cast<FontTableBlobData*>(aBlobData);
|
||||
}
|
||||
|
||||
hb_blob_t *
|
||||
gfxFontEntry::FontTableHashEntry::GetBlob() const
|
||||
{
|
||||
return hb_blob_reference(mBlob);
|
||||
}
|
||||
|
||||
hb_blob_t *
|
||||
|
@ -220,26 +326,22 @@ gfxFontEntry::GetFontTable(PRUint32 aTag)
|
|||
mFontTableCache.Init(10);
|
||||
}
|
||||
|
||||
FontTableCacheEntry *entry = nsnull;
|
||||
if (!mFontTableCache.Get(aTag, &entry)) {
|
||||
nsTArray<PRUint8> buffer;
|
||||
if (NS_SUCCEEDED(GetFontTable(aTag, buffer))) {
|
||||
entry = new FontTableCacheEntry(buffer, // adopts buffer elements
|
||||
aTag, mFontTableCache);
|
||||
if (mFontTableCache.Put(aTag, entry)) {
|
||||
return entry->GetBlob();
|
||||
}
|
||||
hb_blob_destroy(entry->GetBlob());
|
||||
delete entry; // we failed to cache it!
|
||||
return nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
FontTableHashEntry *entry = mFontTableCache.GetEntry(aTag);
|
||||
if (entry) {
|
||||
return hb_blob_reference(entry->GetBlob());
|
||||
return entry->GetBlob();
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
entry = mFontTableCache.PutEntry(aTag);
|
||||
if (NS_UNLIKELY(!entry)) { // OOM
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsTArray<PRUint8> buffer;
|
||||
if (NS_FAILED(GetFontTable(aTag, buffer))) {
|
||||
return nsnull; // leaves the null entry cached in the hashtable
|
||||
}
|
||||
|
||||
return entry->ShareTableAndGetBlob(buffer, &mFontTableCache);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -252,19 +354,13 @@ gfxFontEntry::PreloadFontTable(PRUint32 aTag, nsTArray<PRUint8>& aTable)
|
|||
mFontTableCache.Init(3);
|
||||
}
|
||||
|
||||
FontTableCacheEntry *entry = nsnull;
|
||||
if (mFontTableCache.Get(aTag, &entry)) {
|
||||
// this should never happen - it's a logic error in the calling code
|
||||
// (so ignore the fact that we'll leak the elements of aTable here)
|
||||
NS_NOTREACHED("can't preload table, already present in cache!");
|
||||
FontTableHashEntry *entry = mFontTableCache.PutEntry(aTag);
|
||||
if (NS_UNLIKELY(!entry)) { // OOM
|
||||
return;
|
||||
}
|
||||
|
||||
// this adopts the buffer elements of aTable
|
||||
entry = new FontTableCacheEntry(aTable, aTag, mFontTableCache);
|
||||
if (!mFontTableCache.Put(aTag, entry)) {
|
||||
NS_WARNING("failed to cache font table!");
|
||||
}
|
||||
// adopts elements of aTable
|
||||
entry->SaveTable(aTable);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
#include "gfxFontUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "gfxSkipChars.h"
|
||||
#include "gfxRect.h"
|
||||
|
@ -356,8 +355,10 @@ protected:
|
|||
|
||||
gfxFontFamily *mFamily;
|
||||
|
||||
/*
|
||||
* Font table cache, to support GetFontTable for harfbuzz.
|
||||
private:
|
||||
|
||||
/**
|
||||
* Font table hashtable, to support GetFontTable for harfbuzz.
|
||||
*
|
||||
* The harfbuzz shaper (and potentially other clients) needs access to raw
|
||||
* font table data. This needs to be cached so that it can be used
|
||||
|
@ -368,50 +369,86 @@ protected:
|
|||
* Because we may instantiate many gfxFonts for the same physical font
|
||||
* file (at different sizes), we should ensure that they can share a
|
||||
* single cached copy of the font tables. To do this, we implement table
|
||||
* access and caching on the fontEntry rather than the font itself.
|
||||
* access and sharing on the fontEntry rather than the font itself.
|
||||
*
|
||||
* The default implementation uses GetFontTable() to read font table
|
||||
* data into byte arrays, and caches these in a hashtable along with
|
||||
* hb_blob_t wrappers. The entry can then return blobs to harfbuzz.
|
||||
* data into byte arrays, and wraps them in blobs which are registered in
|
||||
* a hashtable. The hashtable can then return pre-existing blobs to
|
||||
* harfbuzz.
|
||||
*
|
||||
* Harfbuzz will "destroy" the blobs when it is finished with them;
|
||||
* they are created with a destroy callback that removes them from
|
||||
* the hashtable when all references are released.
|
||||
* Harfbuzz will "destroy" the blobs when it is finished with them. When
|
||||
* the last blob reference is removed, the FontTableBlobData user data
|
||||
* will remove the blob from the hashtable if still registered.
|
||||
*/
|
||||
class FontTableCacheEntry {
|
||||
public:
|
||||
// create a cache entry by adopting the content of an existing buffer
|
||||
FontTableCacheEntry(nsTArray<PRUint8>& aBuffer,
|
||||
PRUint32 aTag,
|
||||
nsClassHashtable<nsUint32HashKey,FontTableCacheEntry>& aCache);
|
||||
|
||||
~FontTableCacheEntry() {
|
||||
MOZ_COUNT_DTOR(FontTableCacheEntry);
|
||||
class FontTableBlobData;
|
||||
|
||||
/**
|
||||
* FontTableHashEntry manages the entries of hb_blob_ts for two
|
||||
* different situations:
|
||||
*
|
||||
* The common situation is to share font table across fonts with the same
|
||||
* font entry (but different sizes) for use by HarfBuzz. The hashtable
|
||||
* does not own a strong reference to the blob, but keeps a weak pointer,
|
||||
* managed by FontTableBlobData. Similarly FontTableBlobData keeps only a
|
||||
* weak pointer to the hashtable, managed by FontTableHashEntry.
|
||||
*
|
||||
* Some font tables are saved here before they would get stripped by OTS
|
||||
* sanitizing. These are retained for harfbuzz, which does its own
|
||||
* sanitizing. The hashtable owns a reference, so ownership is simple.
|
||||
*/
|
||||
|
||||
class FontTableHashEntry : public nsUint32HashKey
|
||||
{
|
||||
public:
|
||||
// Declarations for nsTHashtable
|
||||
|
||||
typedef nsUint32HashKey KeyClass;
|
||||
typedef KeyClass::KeyType KeyType;
|
||||
typedef KeyClass::KeyTypePointer KeyTypePointer;
|
||||
|
||||
FontTableHashEntry(KeyTypePointer aTag)
|
||||
: KeyClass(aTag), mBlob() { };
|
||||
// Copying transfers blob association.
|
||||
FontTableHashEntry(FontTableHashEntry& toCopy)
|
||||
: KeyClass(toCopy), mBlob(toCopy.mBlob)
|
||||
{
|
||||
toCopy.mBlob = nsnull;
|
||||
}
|
||||
|
||||
hb_blob_t *GetBlob() const { return mBlob; }
|
||||
~FontTableHashEntry() { Clear(); }
|
||||
|
||||
protected:
|
||||
// the data block, owned (via adoption) by the entry
|
||||
nsTArray<PRUint8> mData;
|
||||
// a harfbuzz blob wrapper that we can return to clients
|
||||
hb_blob_t *mBlob;
|
||||
// the blob destroy function needs to know the table tag
|
||||
// and the owning hashtable, so that it can remove the entry
|
||||
PRUint32 mTag;
|
||||
nsClassHashtable<nsUint32HashKey,FontTableCacheEntry>&
|
||||
mCache;
|
||||
// FontTable/Blob API
|
||||
|
||||
// Transfer (not copy) elements of aTable to a new hb_blob_t and
|
||||
// return ownership to the caller. A weak reference to the blob is
|
||||
// recorded in the hashtable entry so that others may use the same
|
||||
// table.
|
||||
hb_blob_t *
|
||||
ShareTableAndGetBlob(nsTArray<PRUint8>& aTable,
|
||||
nsTHashtable<FontTableHashEntry> *aHashtable);
|
||||
|
||||
// Transfer (not copy) elements of aTable to a new hb_blob_t that is
|
||||
// owned by the hashtable entry.
|
||||
void SaveTable(nsTArray<PRUint8>& aTable);
|
||||
|
||||
// Return a strong reference to the blob.
|
||||
// Callers must hb_blob_destroy the returned blob.
|
||||
hb_blob_t *GetBlob() const;
|
||||
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
static void DeleteFontTableBlobData(void *aBlobData);
|
||||
// not implemented
|
||||
FontTableCacheEntry(const FontTableCacheEntry&);
|
||||
FontTableHashEntry& operator=(FontTableHashEntry& toCopy);
|
||||
|
||||
static void Destroy(void *aUserData);
|
||||
FontTableBlobData *mSharedBlobData;
|
||||
hb_blob_t *mBlob;
|
||||
};
|
||||
|
||||
nsClassHashtable<nsUint32HashKey,FontTableCacheEntry> mFontTableCache;
|
||||
nsTHashtable<FontTableHashEntry> mFontTableCache;
|
||||
|
||||
private:
|
||||
gfxFontEntry(const gfxFontEntry&);
|
||||
gfxFontEntry& operator=(const gfxFontEntry&);
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче