Bug 1224965 p1 - add pref for max substitutions for generics under fontconfig. r=m_kato a=ritu
authorJohn Daggett <jdaggett@mozilla.com>
Tue, 01 Dec 2015 09:47:45 +0900
changeset 284881 f4892b39b7311837cbf49a6f20cacc8e105a01ae
parent 284880 503d2ac5795228ed192683d18464640c7881fcc3
child 284882 5ac27957690f76110f2eb3666b5f9599506265c3
push id195
push usercbook@mozilla.com
push dateTue, 01 Dec 2015 10:58:32 +0000
reviewersm_kato, ritu
bugs1224965
milestone44.0a2
Bug 1224965 p1 - add pref for max substitutions for generics under fontconfig. r=m_kato a=ritu
gfx/thebes/gfxFcPlatformFontList.cpp
gfx/thebes/gfxFcPlatformFontList.h
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxPlatformGtk.cpp
gfx/thebes/gfxPlatformGtk.h
modules/libpref/init/all.js
--- a/gfx/thebes/gfxFcPlatformFontList.cpp
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -24,16 +24,17 @@
 #include "nsCharSeparatedTokenizer.h"
 
 #include "mozilla/gfx/HelpersCairo.h"
 
 #include <fontconfig/fcfreetype.h>
 
 #ifdef MOZ_WIDGET_GTK
 #include <gdk/gdk.h>
+#include "gfxPlatformGtk.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::unicode;
 
 #ifndef FC_POSTSCRIPT_NAME
 #define FC_POSTSCRIPT_NAME  "postscriptname"      /* String */
 #endif
@@ -1546,17 +1547,17 @@ gfxFcPlatformFontList::AddGenericFonts(m
     PrefFontList* prefFonts = FindGenericFamilies(genericToLookup, aLanguage);
     NS_ASSERTION(prefFonts, "null generic font list");
     aFamilyList.AppendElements(*prefFonts);
 }
 
 void
 gfxFcPlatformFontList::ClearLangGroupPrefFonts()
 {
-    mGenericMappings.Clear();
+    ClearGenericMappings();
     gfxPlatformFontList::ClearLangGroupPrefFonts();
     mAlwaysUseFontconfigGenerics = PrefFontListsUseOnlyGenerics();
 }
 
 /* static */ FT_Library
 gfxFcPlatformFontList::GetFTLibrary()
 {
     if (!sCairoFTLibrary) {
@@ -1591,19 +1592,16 @@ gfxFcPlatformFontList::GetFTLibrary()
         }
 
         sCairoFTLibrary = face.get()->glyph->library;
     }
 
     return sCairoFTLibrary;
 }
 
-// a given generic will map to at most this many families
-const uint32_t kMaxGenericFamilies = 3;
-
 gfxPlatformFontList::PrefFontList*
 gfxFcPlatformFontList::FindGenericFamilies(const nsAString& aGeneric,
                                            nsIAtom* aLanguage)
 {
     // set up name
     NS_ConvertUTF16toUTF8 generic(aGeneric);
 
     nsAutoCString fcLang;
@@ -1646,16 +1644,17 @@ gfxFcPlatformFontList::FindGenericFamili
                                           nullptr, &result));
 
     if (!faces) {
       return nullptr;
     }
 
     // -- select the fonts to be used for the generic
     prefFonts = new PrefFontList; // can be empty but in practice won't happen
+    uint32_t limit = gfxPlatformGtk::GetPlatform()->MaxGenericSubstitions();
     for (int i = 0; i < faces->nfont; i++) {
         FcPattern* font = faces->fonts[i];
         FcChar8* mappedGeneric = nullptr;
 
         // not scalable? skip...
         FcBool scalable;
         if (FcPatternGetBool(font, FC_SCALABLE, 0, &scalable) != FcResultMatch ||
             !scalable) {
@@ -1665,17 +1664,17 @@ gfxFcPlatformFontList::FindGenericFamili
         FcPatternGetString(font, FC_FAMILY, 0, &mappedGeneric);
         if (mappedGeneric) {
             NS_ConvertUTF8toUTF16 mappedGenericName(ToCharPtr(mappedGeneric));
             gfxFontFamily* genericFamily =
                 gfxPlatformFontList::FindFamily(mappedGenericName);
             if (genericFamily && !prefFonts->Contains(genericFamily)) {
                 //printf("generic %s ==> %s\n", genericLang.get(), (const char*)mappedGeneric);
                 prefFonts->AppendElement(genericFamily);
-                if (prefFonts->Length() >= kMaxGenericFamilies) {
+                if (prefFonts->Length() >= limit) {
                     break;
                 }
             }
         }
     }
     mGenericMappings.Put(genericLang, prefFonts);
     return prefFonts;
 }
--- a/gfx/thebes/gfxFcPlatformFontList.h
+++ b/gfx/thebes/gfxFcPlatformFontList.h
@@ -234,16 +234,21 @@ public:
 
     // override to use fontconfig lookup for generics
     void AddGenericFonts(mozilla::FontFamilyType aGenericType,
                          nsIAtom* aLanguage,
                          nsTArray<gfxFontFamily*>& aFamilyList) override;
 
     void ClearLangGroupPrefFonts() override;
 
+    // clear out cached generic-lang ==> family-list mappings
+    void ClearGenericMappings() {
+        mGenericMappings.Clear();
+    }
+
     void GetSampleLangForGroup(nsIAtom* aLanguage, nsACString& aLangStr);
 
     static FT_Library GetFTLibrary();
 
 protected:
     virtual ~gfxFcPlatformFontList();
 
     // add all the font families found in a font set
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1767,18 +1767,18 @@ int32_t
 gfxPlatform::GetBidiNumeralOption()
 {
     if (mBidiNumeralOption == UNINITIALIZED_VALUE) {
         mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0);
     }
     return mBidiNumeralOption;
 }
 
-static void
-FlushFontAndWordCaches()
+/* static */ void
+gfxPlatform::FlushFontAndWordCaches()
 {
     gfxFontCache *fontCache = gfxFontCache::GetCache();
     if (fontCache) {
         fontCache->AgeAllGenerations();
         fontCache->FlushShapedWordCaches();
     }
 }
 
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -509,16 +509,19 @@ public:
      * Return sRGBA -> output device transform.
      */
     static qcms_transform* GetCMSRGBATransform();
 
     virtual void FontsPrefsChanged(const char *aPref);
 
     int32_t GetBidiNumeralOption();
 
+    static void
+    FlushFontAndWordCaches();
+
     /**
      * Returns a 1x1 surface that can be used to create graphics contexts
      * for measuring text etc as if they will be rendered to the screen
      */
     gfxASurface* ScreenReferenceSurface() { return mScreenReferenceSurface; }
     mozilla::gfx::DrawTarget* ScreenReferenceDrawTarget() { return mScreenReferenceDrawTarget; }
 
     virtual mozilla::gfx::SurfaceFormat Optimal2DFormatForContent(gfxContentType aContent);
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -42,16 +42,18 @@
 #endif /* MOZ_X11 */
 
 #include <fontconfig/fontconfig.h>
 
 #include "nsMathUtils.h"
 
 #define GDK_PIXMAP_SIZE_MAX 32767
 
+#define GFX_PREF_MAX_GENERIC_SUBSTITUTIONS "gfx.font_rendering.fontconfig.max_generic_substitutions"
+
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::unicode;
 
 gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nullptr;
 
 #if (MOZ_WIDGET_GTK == 2)
 static cairo_user_data_key_t cairo_gdk_drawable_key;
@@ -67,16 +69,18 @@ gfxPlatformGtk::gfxPlatformGtk()
 {
     gtk_init(nullptr, nullptr);
 
     sUseFcFontList = mozilla::Preferences::GetBool("gfx.font_rendering.fontconfig.fontlist.enabled");
     if (!sUseFcFontList && !sFontconfigUtils) {
         sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
     }
 
+    mMaxGenericSubstitutions = UNINITIALIZED_VALUE;
+
 #ifdef MOZ_X11
     sUseXRender = (GDK_IS_X11_DISPLAY(gdk_display_get_default())) ? 
                     mozilla::Preferences::GetBool("gfx.xrender.enabled") : false;
 #endif
 
     uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
     uint32_t contentMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
     InitBackendPrefs(canvasMask, BackendType::CAIRO,
@@ -359,16 +363,45 @@ gfxPlatformGtk::GetOffscreenFormat()
     GdkScreen *screen = gdk_screen_get_default();
     if (screen && gdk_visual_get_depth(gdk_visual_get_system()) == 16) {
         return gfxImageFormat::RGB16_565;
     }
 
     return gfxImageFormat::RGB24;
 }
 
+void gfxPlatformGtk::FontsPrefsChanged(const char *aPref)
+{
+    // only checking for generic substitions, pass other changes up
+    if (strcmp(GFX_PREF_MAX_GENERIC_SUBSTITUTIONS, aPref)) {
+        gfxPlatform::FontsPrefsChanged(aPref);
+        return;
+    }
+
+    mMaxGenericSubstitutions = UNINITIALIZED_VALUE;
+    if (sUseFcFontList) {
+        gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList();
+        pfl->ClearGenericMappings();
+        FlushFontAndWordCaches();
+    }
+}
+
+uint32_t gfxPlatformGtk::MaxGenericSubstitions()
+{
+    if (mMaxGenericSubstitutions == UNINITIALIZED_VALUE) {
+        mMaxGenericSubstitutions =
+            Preferences::GetInt(GFX_PREF_MAX_GENERIC_SUBSTITUTIONS, 3);
+        if (mMaxGenericSubstitutions < 0) {
+            mMaxGenericSubstitutions = 3;
+        }
+    }
+
+    return uint32_t(mMaxGenericSubstitutions);
+}
+
 void
 gfxPlatformGtk::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
 {
     mem = nullptr;
     size = 0;
 
 #ifdef MOZ_X11
     GdkDisplay *display = gdk_display_get_default();
--- a/gfx/thebes/gfxPlatformGtk.h
+++ b/gfx/thebes/gfxPlatformGtk.h
@@ -121,19 +121,26 @@ public:
     bool UseImageOffscreenSurfaces();
 
     virtual gfxImageFormat GetOffscreenFormat() override;
 
     bool SupportsApzWheelInput() const override {
       return true;
     }
 
+    void FontsPrefsChanged(const char *aPref) override;
+
+    // maximum number of fonts to substitute for a generic
+    uint32_t MaxGenericSubstitions();
+
 protected:
     static gfxFontconfigUtils *sFontconfigUtils;
 
+    int8_t mMaxGenericSubstitutions;
+
 private:
     virtual void GetPlatformCMSOutputProfile(void *&mem,
                                              size_t &size) override;
 
 #ifdef MOZ_X11
     static bool sUseXRender;
 #endif
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3855,16 +3855,19 @@ pref("intl.ime.use_simple_context_on_pas
 # gfxPangoFontGroup/gfxFontconfigUtils code for handling system fonts
 
 #ifdef MOZ_WIDGET_GTK
 #ifdef RELEASE_BUILD
 pref("gfx.font_rendering.fontconfig.fontlist.enabled", false);
 #else
 pref("gfx.font_rendering.fontconfig.fontlist.enabled", true);
 #endif
+
+// maximum number of fonts to substitute for a generic
+pref("gfx.font_rendering.fontconfig.max_generic_substitutions", 3);
 #endif
 
 # XP_UNIX
 #endif
 #endif
 #endif
 
 #if defined(ANDROID) || defined(MOZ_B2G)