diff --git a/gfx/thebes/public/gfxPangoFonts.h b/gfx/thebes/public/gfxPangoFonts.h index f7035faab5e..6a370468eca 100644 --- a/gfx/thebes/public/gfxPangoFonts.h +++ b/gfx/thebes/public/gfxPangoFonts.h @@ -54,6 +54,9 @@ // anything other than simple Latin work though! //#define ENABLE_FAST_PATH_ALWAYS +#include "nsDataHashtable.h" +#include "nsClassHashtable.h" + class gfxPangoTextRun; class gfxPangoFont : public gfxFont { @@ -156,4 +159,43 @@ protected: void *closure); }; +class gfxPangoFontWrapper { +public: + gfxPangoFontWrapper(PangoFont *aFont) { + mFont = aFont; + g_object_ref(mFont); + } + ~gfxPangoFontWrapper() { + if (mFont) + g_object_unref(mFont); + } + PangoFont* Get() { return mFont; } +private: + PangoFont *mFont; +}; + +class gfxPangoFontCache +{ +public: + gfxPangoFontCache(); + ~gfxPangoFontCache(); + + static gfxPangoFontCache* GetPangoFontCache() { + if (!sPangoFontCache) + sPangoFontCache = new gfxPangoFontCache(); + return sPangoFontCache; + } + static void Shutdown() { + if (sPangoFontCache) + delete sPangoFontCache; + sPangoFontCache = nsnull; + } + + void Put(const PangoFontDescription *aFontDesc, PangoFont *aPangoFont); + PangoFont* Get(const PangoFontDescription *aFontDesc); +private: + static gfxPangoFontCache *sPangoFontCache; + nsClassHashtable mPangoFonts; +}; + #endif /* GFX_PANGOFONTS_H */ diff --git a/gfx/thebes/src/gfxPangoFonts.cpp b/gfx/thebes/src/gfxPangoFonts.cpp index 81bbbe4a510..6bbd24ab5f2 100644 --- a/gfx/thebes/src/gfxPangoFonts.cpp +++ b/gfx/thebes/src/gfxPangoFonts.cpp @@ -94,6 +94,8 @@ static PangoLanguage *GetPangoLanguage(const nsACString& aLangGroup); +/* static */ gfxPangoFontCache* gfxPangoFontCache::sPangoFontCache = nsnull; + /** ** gfxPangoFontGroup **/ @@ -207,6 +209,8 @@ gfxPangoFont::~gfxPangoFont() /* static */ void gfxPangoFont::Shutdown() { + gfxPangoFontCache::Shutdown(); + // This just cleans up memory used by Pango's caches and may cause an // assert and crash in cairo (Bug 399556), so only do this when we care // about cleaning up memory on shutdown. @@ -280,6 +284,22 @@ ThebesStyleToPangoWeight (const gfxFontStyle *fs) return (PangoWeight)fcWeights[fcWeight]; } +static PangoFont* +LoadPangoFont(PangoContext *aPangoCtx, const PangoFontDescription *aPangoFontDesc) +{ + gfxPangoFontCache *cache = gfxPangoFontCache::GetPangoFontCache(); + if (!cache) + return nsnull; // Error + PangoFont* pangoFont = cache->Get(aPangoFontDesc); + if (!pangoFont) { + pangoFont = pango_context_load_font(aPangoCtx, aPangoFontDesc); + if (pangoFont) { + cache->Put(aPangoFontDesc, pangoFont); + } + } + return pangoFont; +} + void gfxPangoFont::RealizePangoFont() { @@ -302,24 +322,23 @@ gfxPangoFont::RealizePangoFont() pango_context_set_language(pangoCtx, lang); } - gfxFloat size = GetStyle()->size; pango_font_description_set_absolute_size(pangoFontDesc, size * PANGO_SCALE); - mPangoFont = pango_context_load_font(pangoCtx, pangoFontDesc); + mPangoFont = LoadPangoFont(pangoCtx, pangoFontDesc); // Checking mPangoFont to avoid infinite recursion through GetCharSize if (size != 0.0 && GetStyle()->sizeAdjust != 0.0 && mPangoFont) { // Could try xHeight from TrueType/OpenType fonts. - gfxSize isz, lsz; - GetCharSize('x', isz, lsz); + gfxSize isz, lsz; + GetCharSize('x', isz, lsz); if (isz.height != 0.0) { gfxFloat aspect = isz.height / size; size = GetStyle()->GetAdjustedSize(aspect); pango_font_description_set_absolute_size(pangoFontDesc, size * PANGO_SCALE); - g_object_unref(mPangoFont); - mPangoFont = pango_context_load_font(pangoCtx, pangoFontDesc); + g_object_unref(mPangoFont); + mPangoFont = LoadPangoFont(pangoCtx, pangoFontDesc); } } @@ -1447,3 +1466,36 @@ static const MozPangoLangGroup PangoAllLangGroup[] = { }; #define NUM_PANGO_ALL_LANG_GROUPS (G_N_ELEMENTS (PangoAllLangGroup)) + +gfxPangoFontCache::gfxPangoFontCache() +{ + mPangoFonts.Init(500); +} + +gfxPangoFontCache::~gfxPangoFontCache() +{ +} + +void +gfxPangoFontCache::Put(const PangoFontDescription *aFontDesc, PangoFont *aPangoFont) +{ + if (mPangoFonts.Count() > 5000) + mPangoFonts.Clear(); + PRUint32 key = pango_font_description_hash(aFontDesc); + gfxPangoFontWrapper *value = new gfxPangoFontWrapper(aPangoFont); + if (!value) + return; + mPangoFonts.Put(key, value); +} + +PangoFont* +gfxPangoFontCache::Get(const PangoFontDescription *aFontDesc) +{ + PRUint32 key = pango_font_description_hash(aFontDesc); + gfxPangoFontWrapper *value; + if (!mPangoFonts.Get(key, &value)) + return nsnull; + PangoFont *font = value->Get(); + g_object_ref(font); + return font; +}