Bug 964613 - check userfont sets for enabled/disabled local fonts when platform fontlist changes occur. r=jfkthame
authorJohn Daggett <jdaggett@mozilla.com>
Thu, 17 Apr 2014 23:17:22 +0900
changeset 179457 ff84ce7e5f85065cd9d40a81748aa538edd61173
parent 179456 21043f348d6520c995d1d8a8d05468ac41cb13f1
child 179458 993c3b5ff4596e3ac7425c8e723f5eb97bc17c50
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersjfkthame
bugs964613
milestone31.0a1
Bug 964613 - check userfont sets for enabled/disabled local fonts when platform fontlist changes occur. r=jfkthame
gfx/thebes/gfxMacPlatformFontList.mm
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxPlatformFontList.h
gfx/thebes/gfxUserFontSet.cpp
gfx/thebes/gfxUserFontSet.h
layout/style/nsFontFaceLoader.cpp
layout/style/nsFontFaceLoader.h
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -825,23 +825,23 @@ gfxMacPlatformFontList::RegisteredFontsC
                                                                    CFStringRef name,
                                                                    const void *object,
                                                                    CFDictionaryRef userInfo)
 {
     if (!::CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification)) {
         return;
     }
 
+    gfxMacPlatformFontList* fl = static_cast<gfxMacPlatformFontList*>(observer);
+
     // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
-    static_cast<gfxMacPlatformFontList*>(observer)->UpdateFontList();
+    fl->UpdateFontList();
 
     // modify a preference that will trigger reflow everywhere
-    static const char kPrefName[] = "font.internaluseonly.changed";
-    bool fontInternalChange = Preferences::GetBool(kPrefName, false);
-    Preferences::SetBool(kPrefName, !fontInternalChange);
+    fl->ForceGlobalReflow();
 }
 
 gfxFontEntry*
 gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh,
                                            int32_t aRunScript,
                                            const gfxFontStyle* aMatchStyle,
                                            uint32_t& aCmapCount,
                                            gfxFontFamily** aMatchedFamily)
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG /* Allow logging in the release build */
 #endif
 #include "prlog.h"
 
 #include "gfxPlatformFontList.h"
+#include "gfxUserFontSet.h"
 
 #include "nsUnicharUtils.h"
 #include "nsUnicodeRange.h"
 #include "nsUnicodeProperties.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
@@ -298,16 +299,31 @@ gfxPlatformFontList::ResolveFontName(con
     gfxFontFamily *family = FindFamily(aFontName);
     if (family) {
         aResolvedFontName = family->Name();
         return true;
     }
     return false;
 }
 
+static PLDHashOperator
+RebuildLocalFonts(nsPtrHashKey<gfxUserFontSet>* aKey,
+                  void* aClosure)
+{
+    aKey->GetKey()->RebuildLocalRules();
+    return PL_DHASH_NEXT;
+}
+
+void
+gfxPlatformFontList::UpdateFontList()
+{
+    InitFontList();
+    mUserFontSetList.EnumerateEntries(RebuildLocalFonts, nullptr);
+}
+
 struct FontListData {
     FontListData(nsIAtom *aLangGroup,
                  const nsACString& aGenericFamily,
                  nsTArray<nsString>& aListOfFonts) :
         mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
         mListOfFonts(aListOfFonts) {}
     nsIAtom *mLangGroup;
     const nsACString& mGenericFamily;
@@ -792,16 +808,21 @@ gfxPlatformFontList::LoadFontInfo()
 #ifdef PR_LOGGING
     if (LOG_FONTINIT_ENABLED()) {
         TimeDuration elapsed = TimeStamp::Now() - start;
         LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
                       elapsed.ToMilliseconds(), (done ? "true" : "false")));
     }
 #endif
 
+    if (done) {
+        mOtherFamilyNamesInitialized = true;
+        mFaceNamesInitialized = true;
+    }
+
     return done;
 }
 
 void 
 gfxPlatformFontList::CleanupLoader()
 {
     mFontFamiliesToLoad.Clear();
     mNumFamilies = 0;
@@ -815,18 +836,16 @@ gfxPlatformFontList::CleanupLoader()
                       mFontInfo->mLoadStats.families,
                       mFontInfo->mLoadStats.fonts,
                       mFontInfo->mLoadStats.cmaps,
                       mFontInfo->mLoadStats.facenames,
                       mFontInfo->mLoadStats.othernames));
     }
 #endif
 
-    mOtherFamilyNamesInitialized = true;
-    mFaceNamesInitialized = true;
     gfxFontInfoLoader::CleanupLoader();
 }
 
 void
 gfxPlatformFontList::GetPrefsAndStartLoader()
 {
     mIncrement =
         std::max(1u, Preferences::GetUint(FONT_LOADER_FAMILIES_PER_SLICE_PREF));
@@ -834,16 +853,25 @@ gfxPlatformFontList::GetPrefsAndStartLoa
     uint32_t delay =
         std::max(1u, Preferences::GetUint(FONT_LOADER_DELAY_PREF));
     uint32_t interval =
         std::max(1u, Preferences::GetUint(FONT_LOADER_INTERVAL_PREF));
 
     StartLoader(delay, interval);
 }
 
+void
+gfxPlatformFontList::ForceGlobalReflow()
+{
+    // modify a preference that will trigger reflow everywhere
+    static const char kPrefName[] = "font.internaluseonly.changed";
+    bool fontInternalChange = Preferences::GetBool(kPrefName, false);
+    Preferences::SetBool(kPrefName, !fontInternalChange);
+}
+
 // Support for memory reporting
 
 static size_t
 SizeOfFamilyEntryExcludingThis(const nsAString&               aKey,
                                const nsRefPtr<gfxFontFamily>& aFamily,
                                MallocSizeOf                   aMallocSizeOf,
                                void*                          aUserArg)
 {
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -77,16 +77,18 @@ protected:
 struct FontListSizes {
     uint32_t mFontListSize; // size of the font list and dependent objects
                             // (font family and face names, etc), but NOT
                             // including the font table cache and the cmaps
     uint32_t mFontTableCacheSize; // memory used for the gfxFontEntry table caches
     uint32_t mCharMapsSize; // memory used for cmap coverage info
 };
 
+class gfxUserFontSet;
+
 class gfxPlatformFontList : public gfxFontInfoLoader
 {
 public:
     static gfxPlatformFontList* PlatformFontList() {
         return sPlatformFontList;
     }
 
     static nsresult Init() {
@@ -110,17 +112,17 @@ public:
 
     void GetFontList (nsIAtom *aLangGroup,
                       const nsACString& aGenericFamily,
                       nsTArray<nsString>& aListOfFonts);
 
     virtual bool ResolveFontName(const nsAString& aFontName,
                                    nsAString& aResolvedFontName);
 
-    void UpdateFontList() { InitFontList(); }
+    void UpdateFontList();
 
     void ClearPrefFonts() { mPrefFonts.Clear(); }
 
     virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
 
     virtual gfxFontEntry*
     SystemFindFontForChar(const uint32_t aCh,
                           int32_t aRunScript,
@@ -173,16 +175,25 @@ public:
     gfxCharacterMap* FindCharMap(gfxCharacterMap *aCmap);
 
     // add a cmap to the shared cmap set
     gfxCharacterMap* AddCmap(const gfxCharacterMap *aCharMap);
 
     // remove the cmap from the shared cmap set
     void RemoveCmap(const gfxCharacterMap *aCharMap);
 
+    // keep track of userfont sets to notify when global fontlist changes occur
+    void AddUserFontSet(gfxUserFontSet *aUserFontSet) {
+        mUserFontSetList.PutEntry(aUserFontSet);
+    }
+
+    void RemoveUserFontSet(gfxUserFontSet *aUserFontSet) {
+        mUserFontSetList.RemoveEntry(aUserFontSet);
+    }
+
 protected:
     class MemoryReporter MOZ_FINAL : public nsIMemoryReporter
     {
     public:
         NS_DECL_ISUPPORTS
         NS_DECL_NSIMEMORYREPORTER
     };
 
@@ -249,16 +260,19 @@ protected:
     // gfxFontInfoLoader overrides, used to load in font cmaps
     virtual void InitLoader();
     virtual bool LoadFontInfo();
     virtual void CleanupLoader();
 
     // read the loader initialization prefs, and start it
     void GetPrefsAndStartLoader();
 
+    // for font list changes that affect all documents
+    void ForceGlobalReflow();
+
     // used by memory reporter to accumulate sizes of family names in the hash
     static size_t
     SizeOfFamilyNameEntryExcludingThis(const nsAString&               aKey,
                                        const nsRefPtr<gfxFontFamily>& aFamily,
                                        mozilla::MallocSizeOf          aMallocSizeOf,
                                        void*                          aUserArg);
 
     // canonical family name ==> family entry (unique, one name per family entry)
@@ -300,11 +314,13 @@ protected:
     // contains weak ptrs to cmaps shared by font entry objects
     nsTHashtable<CharMapHashKey> mSharedCmaps;
 
     // data used as part of the font cmap loading process
     nsTArray<nsRefPtr<gfxFontFamily> > mFontFamiliesToLoad;
     uint32_t mStartIndex;
     uint32_t mIncrement;
     uint32_t mNumFamilies;
+
+    nsTHashtable<nsPtrHashKey<gfxUserFontSet> > mUserFontSetList;
 };
 
 #endif /* GFXPLATFORMFONTLIST_H_ */
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -13,16 +13,17 @@
 #include "nsUnicharUtils.h"
 #include "nsNetUtil.h"
 #include "nsICacheService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIPrincipal.h"
 #include "gfxFontConstants.h"
 #include "mozilla/Services.h"
 #include "mozilla/gfx/2D.h"
+#include "gfxPlatformFontList.h"
 
 #include "opentype-sanitiser.h"
 #include "ots-memory-stream.h"
 
 using namespace mozilla;
 
 #ifdef PR_LOGGING
 PRLogModuleInfo *
@@ -97,23 +98,31 @@ gfxProxyFontEntry::Matches(const nsTArra
 gfxFont*
 gfxProxyFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold)
 {
     // cannot create an actual font for a proxy entry
     return nullptr;
 }
 
 gfxUserFontSet::gfxUserFontSet()
-    : mFontFamilies(5)
+    : mFontFamilies(5), mLocalRulesUsed(false)
 {
     IncrementGeneration();
+    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
+    if (fp) {
+        fp->AddUserFontSet(this);
+    }
 }
 
 gfxUserFontSet::~gfxUserFontSet()
 {
+    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
+    if (fp) {
+        fp->RemoveUserFontSet(this);
+    }
 }
 
 gfxFontEntry*
 gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
                             const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                             uint32_t aWeight,
                             int32_t aStretch,
                             uint32_t aItalicStyle,
@@ -534,16 +543,17 @@ gfxUserFontSet::LoadNext(gfxMixedFontFam
         const gfxFontFaceSrc& currSrc = aProxyEntry->mSrcList[aProxyEntry->mSrcIndex];
 
         // src local ==> lookup and load immediately
 
         if (currSrc.mIsLocal) {
             gfxFontEntry *fe =
                 gfxPlatform::GetPlatform()->LookupLocalFont(aProxyEntry,
                                                             currSrc.mLocalName);
+            mLocalRulesUsed = true;
             if (fe) {
                 LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
                      this, aProxyEntry->mSrcIndex,
                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
                      NS_ConvertUTF16toUTF8(aFamily->Name()).get(),
                      uint32_t(mGeneration)));
                 fe->mFeatureSettings.AppendElements(aProxyEntry->mFeatureSettings);
                 fe->mLanguageOverride = aProxyEntry->mLanguageOverride;
@@ -659,16 +669,23 @@ gfxUserFontSet::IncrementGeneration()
 {
     // add one, increment again if zero
     ++sFontSetGeneration;
     if (sFontSetGeneration == 0)
        ++sFontSetGeneration;
     mGeneration = sFontSetGeneration;
 }
 
+void
+gfxUserFontSet::RebuildLocalRules()
+{
+    if (mLocalRulesUsed) {
+        DoRebuildUserFontSet();
+    }
+}
 
 gfxFontEntry*
 gfxUserFontSet::LoadFont(gfxMixedFontFamily *aFamily,
                          gfxProxyFontEntry *aProxy,
                          const uint8_t *aFontData, uint32_t &aLength)
 {
     gfxFontEntry *fe = nullptr;
 
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -237,16 +237,19 @@ public:
 
     // generation - each time a face is loaded, generation is
     // incremented so that the change can be recognized 
     uint64_t GetGeneration() { return mGeneration; }
 
     // increment the generation on font load
     void IncrementGeneration();
 
+    // rebuild if local rules have been used
+    void RebuildLocalRules();
+
     class UserFontCache {
     public:
         // Record a loaded user-font in the cache. This requires that the
         // font-entry's userFontData has been set up already, as it relies
         // on the URI and Principal recorded there.
         static void CacheFont(gfxFontEntry *aFontEntry);
 
         // The given gfxFontEntry is being destroyed, so remove any record that
@@ -413,21 +416,27 @@ protected:
                                         gfxProxyFontEntry *aProxy,
                                         const uint8_t* aData,
                                         uint32_t aLength,
                                         uint32_t& aSaneLength,
                                         bool aIsCompressed);
 
     static bool OTSMessage(void *aUserData, const char *format, ...);
 
+    // helper method for performing the actual userfont set rebuild
+    virtual void DoRebuildUserFontSet() = 0;
+
     // font families defined by @font-face rules
     nsRefPtrHashtable<nsStringHashKey, gfxMixedFontFamily> mFontFamilies;
 
     uint64_t        mGeneration;
 
+    // true when local names have been looked up, false otherwise
+    bool mLocalRulesUsed;
+
     static PRLogModuleInfo* GetUserFontsLog();
 
 private:
     static void CopyWOFFMetadata(const uint8_t* aFontData,
                                  uint32_t aLength,
                                  FallibleTArray<uint8_t>* aMetadata,
                                  uint32_t* aMetaOrigLen);
 };
--- a/layout/style/nsFontFaceLoader.cpp
+++ b/layout/style/nsFontFaceLoader.cpp
@@ -485,19 +485,34 @@ nsUserFontSet::UpdateRules(const nsTArra
       }
     }
   }
 
   if (modified) {
     IncrementGeneration();
   }
 
+  // local rules have been rebuilt, so clear the flag
+  mLocalRulesUsed = false;
+
   return modified;
 }
 
+static bool
+HasLocalSrc(const nsCSSValue::Array *aSrcArr)
+{
+  size_t numSrc = aSrcArr->Count();
+  for (size_t i = 0; i < numSrc; i++) {
+    if (aSrcArr->Item(i).GetUnit() == eCSSUnit_Local_Font) {
+      return true;
+    }
+  }
+  return false;
+}
+
 void
 nsUserFontSet::InsertRule(nsCSSFontFaceRule* aRule, uint8_t aSheetType,
                           nsTArray<FontFaceRuleRecord>& aOldRules,
                           bool& aFontSetModified)
 {
   NS_ABORT_IF_FALSE(aRule->GetType() == mozilla::css::Rule::FONT_FACE_RULE,
                     "InsertRule passed a non-fontface CSS rule");
 
@@ -519,18 +534,30 @@ nsUserFontSet::InsertRule(nsCSSFontFaceR
     // usable font, so there is no point in processing it further.
     return;
   }
 
   // first, we check in oldRules; if the rule exists there, just move it
   // to the new rule list, and put the entry into the appropriate family
   for (uint32_t i = 0; i < aOldRules.Length(); ++i) {
     const FontFaceRuleRecord& ruleRec = aOldRules[i];
+
     if (ruleRec.mContainer.mRule == aRule &&
         ruleRec.mContainer.mSheetType == aSheetType) {
+
+      // if local rules were used, don't use the old font entry
+      // for rules containing src local usage
+      if (mLocalRulesUsed) {
+        aRule->GetDesc(eCSSFontDesc_Src, val);
+        unit = val.GetUnit();
+        if (unit == eCSSUnit_Array && HasLocalSrc(val.GetArrayValue())) {
+          break;
+        }
+      }
+
       AddFontFace(fontfamily, ruleRec.mFontEntry);
       mRules.AppendElement(ruleRec);
       aOldRules.RemoveElementAt(i);
       // note the set has been modified if an old rule was skipped to find
       // this one - something has been dropped, or ordering changed
       if (i > 0) {
         aFontSetModified = true;
       }
@@ -978,8 +1005,14 @@ nsUserFontSet::GetPrivateBrowsing()
   nsIPresShell* ps = mPresContext->PresShell();
   if (!ps) {
     return false;
   }
 
   nsCOMPtr<nsILoadContext> loadContext = ps->GetDocument()->GetLoadContext();
   return loadContext && loadContext->UsePrivateBrowsing();
 }
+
+void
+nsUserFontSet::DoRebuildUserFontSet()
+{
+  mPresContext->RebuildUserFontSet();
+}
--- a/layout/style/nsFontFaceLoader.h
+++ b/layout/style/nsFontFaceLoader.h
@@ -82,16 +82,18 @@ protected:
 
   virtual nsresult SyncLoadFontData(gfxProxyFontEntry* aFontToLoad,
                                     const gfxFontFaceSrc* aFontFaceSrc,
                                     uint8_t*& aBuffer,
                                     uint32_t& aBufferLength) MOZ_OVERRIDE;
 
   virtual bool GetPrivateBrowsing() MOZ_OVERRIDE;
 
+  virtual void DoRebuildUserFontSet() MOZ_OVERRIDE;
+
   nsPresContext* mPresContext;  // weak reference
 
   // Set of all loaders pointing to us. These are not strong pointers,
   // but that's OK because nsFontFaceLoader always calls RemoveLoader on
   // us before it dies (unless we die first).
   nsTHashtable< nsPtrHashKey<nsFontFaceLoader> > mLoaders;
 
   nsTArray<FontFaceRuleRecord>   mRules;