Bug 1314932 - Reduce content-process startup time on MacOSX by passing the system font list from chrome to content process via the GetXPCOMProcessAttributes message. r=mstange
authorJonathan Kew <jkew@mozilla.com>
Tue, 15 Nov 2016 13:58:29 +0000
changeset 322751 bc0e63d09f83724c32ac7abe92c75b041b1c9b03
parent 322750 c004650aece0c99f056e9980dca0eed58638982f
child 322752 b7d42c3980d12dff16df9f6077f34279aeef49d6
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +0000
reviewersmstange
bugs1314932
milestone53.0a1
Bug 1314932 - Reduce content-process startup time on MacOSX by passing the system font list from chrome to content process via the GetXPCOMProcessAttributes message. r=mstange
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
gfx/thebes/gfxMacPlatformFontList.h
gfx/thebes/gfxMacPlatformFontList.mm
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxPlatformMac.cpp
gfx/thebes/gfxPlatformMac.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -927,17 +927,18 @@ ContentChild::InitXPCOM()
   bool isConnected;
   ClipboardCapabilities clipboardCaps;
   DomainPolicyClone domainPolicy;
   StructuredCloneData initialData;
 
   SendGetXPCOMProcessAttributes(&isOffline, &isConnected,
                                 &isLangRTL, &haveBidiKeyboards,
                                 &mAvailableDictionaries,
-                                &clipboardCaps, &domainPolicy, &initialData);
+                                &clipboardCaps, &domainPolicy, &initialData,
+                                &mFontFamilies);
   RecvSetOffline(isOffline);
   RecvSetConnectivity(isConnected);
   RecvBidiKeyboardNotify(isLangRTL, haveBidiKeyboards);
 
   // Create the CPOW manager as soon as possible.
   SendPJavaScriptConstructor();
 
   if (domainPolicy.active()) {
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -628,16 +628,23 @@ public:
   virtual bool
   RecvBlobURLUnregistration(const nsCString& aURI) override;
 
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
   bool
   SendGetA11yContentId();
 #endif // defined(XP_WIN) && defined(ACCESSIBILITY)
 
+  // Get a reference to the font family list passed from the chrome process,
+  // for use during gfx initialization.
+  InfallibleTArray<mozilla::dom::FontFamilyListEntry>&
+  SystemFontFamilyList() {
+    return mFontFamilies;
+  }
+
   /**
    * Helper function for protocols that use the GPU process when available.
    * Overrides FatalError to just be a warning when communicating with the
    * GPU process since we don't want to crash the content process when the
    * GPU process crashes.
    */
   static void FatalErrorIfNotUsingGPUProcess(const char* const aProtocolName,
                                              const char* const aErrorMsg,
@@ -653,16 +660,21 @@ private:
 
   InfallibleTArray<nsAutoPtr<AlertObserver> > mAlertObservers;
   RefPtr<ConsoleListener> mConsoleListener;
 
   nsTHashtable<nsPtrHashKey<nsIObserver>> mIdleObservers;
 
   InfallibleTArray<nsString> mAvailableDictionaries;
 
+  // Temporary storage for a list of available font families, passed from the
+  // parent process and used to initialize gfx in the child. Currently used
+  // only on MacOSX.
+  InfallibleTArray<mozilla::dom::FontFamilyListEntry> mFontFamilies;
+
   /**
    * An ID unique to the process containing our corresponding
    * content parent.
    *
    * We expect our content parent to set this ID immediately after opening a
    * channel to us.
    */
   ContentParentId mID;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2882,17 +2882,18 @@ ContentParent::RecvGetProcessAttributes(
 bool
 ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
                                              bool* aIsConnected,
                                              bool* aIsLangRTL,
                                              bool* aHaveBidiKeyboards,
                                              InfallibleTArray<nsString>* dictionaries,
                                              ClipboardCapabilities* clipboardCaps,
                                              DomainPolicyClone* domainPolicy,
-                                             StructuredCloneData* aInitialData)
+                                             StructuredCloneData* aInitialData,
+                                             InfallibleTArray<FontFamilyListEntry>* fontFamilies)
 {
   nsCOMPtr<nsIIOService> io(do_GetIOService());
   MOZ_ASSERT(io, "No IO service?");
   DebugOnly<nsresult> rv = io->GetOffline(aIsOffline);
   MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
 
   rv = io->GetConnectivity(aIsConnected);
   MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
@@ -2939,16 +2940,19 @@ ContentParent::RecvGetXPCOMProcessAttrib
     ErrorResult rv;
     aInitialData->Write(jsapi.cx(), init, rv);
     if (NS_WARN_IF(rv.Failed())) {
       rv.SuppressException();
       return false;
     }
   }
 
+  // This is only implemented (returns a non-empty list) by MacOSX at present.
+  gfxPlatform::GetPlatform()->GetSystemFontFamilyList(fontFamilies);
+
   return true;
 }
 
 mozilla::jsipc::PJavaScriptParent *
 ContentParent::AllocPJavaScriptParent()
 {
   MOZ_ASSERT(ManagedPJavaScriptParent().IsEmpty());
   return nsIContentParent::AllocPJavaScriptParent();
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -707,17 +707,19 @@ private:
   virtual bool
   RecvGetXPCOMProcessAttributes(bool* aIsOffline,
                                 bool* aIsConnected,
                                 bool* aIsLangRTL,
                                 bool* aHaveBidiKeyboards,
                                 InfallibleTArray<nsString>* dictionaries,
                                 ClipboardCapabilities* clipboardCaps,
                                 DomainPolicyClone* domainPolicy,
-                                StructuredCloneData* initialData) override;
+                                StructuredCloneData* initialData,
+                                InfallibleTArray<FontFamilyListEntry>* fontFamilies)
+                                override;
 
   virtual bool
   DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*) override;
 
   virtual bool
   DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent*) override;
 
   virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -100,27 +100,38 @@ union ChromeRegistryItem
     ChromePackage;
     OverrideMapping;
     SubstitutionMapping;
 };
 
 namespace mozilla {
 namespace dom {
 
+// Used on Android/B2G to pass the list of fonts on the device
+// to the child process
 struct FontListEntry {
     nsString  familyName;
     nsString  faceName;
     nsCString filepath;
     uint16_t  weight;
     int16_t   stretch;
     uint8_t   italic;
     uint8_t   index;
     bool      isHidden;
 };
 
+// Used on Mac OS X to pass the list of font families (not faces)
+// from chrome to content processes.
+// The entryType field distinguishes several types of font family
+// record; see gfxMacPlatformFontList.h for values and meaning.
+struct FontFamilyListEntry {
+    nsString familyName;
+    uint8_t  entryType;
+};
+
 struct DeviceStorageFreeSpaceParams
 {
   nsString type;
   nsString storageName;
 };
 
 struct DeviceStorageUsedSpaceParams
 {
@@ -687,17 +698,18 @@ parent:
      */
     sync GetProcessAttributes()
         returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
     sync GetXPCOMProcessAttributes()
         returns (bool isOffline, bool isConnected, bool isLangRTL,
                  bool haveBidiKeyboards, nsString[] dictionaries,
                  ClipboardCapabilities clipboardCaps,
                  DomainPolicyClone domainPolicy,
-                 StructuredCloneData initialData);
+                 StructuredCloneData initialData,
+                 FontFamilyListEntry[] fontFamilies /* used on MacOSX only */);
 
     sync CreateChildProcess(IPCTabContext context,
                             ProcessPriority priority,
                             TabId openerTabId)
         returns (ContentParentId cpId, bool isForApp, bool isForBrowser, TabId tabId);
     sync BridgeToChildProcess(ContentParentId cpId);
 
     async CreateGMPService();
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -103,16 +103,27 @@ public:
 
     // lookup the system font for a particular system font type and set
     // the name and style characteristics
     void LookupSystemFont(mozilla::LookAndFeel::FontID aSystemFontID,
                           nsAString& aSystemFontName,
                           gfxFontStyle &aFontStyle,
                           float aDevPixPerCSSPixel);
 
+    // Values for the entryType field in FontFamilyListEntry records passed
+    // from chrome to content process.
+    enum FontFamilyEntryType {
+        kStandardFontFamily = 0, // a standard installed font family
+        kHiddenSystemFontFamily = 1, // hidden system family, not exposed to UI
+        kTextSizeSystemFontFamily = 2, // name of 'system' font at text sizes
+        kDisplaySizeSystemFontFamily = 3 // 'system' font at display sizes
+    };
+    void GetSystemFontFamilyList(
+        InfallibleTArray<mozilla::dom::FontFamilyListEntry>* aList);
+
 protected:
     virtual gfxFontFamily*
     GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override;
 
 private:
     friend class gfxPlatformMac;
 
     gfxMacPlatformFontList();
@@ -149,16 +160,18 @@ private:
 
     // Add the specified family to mSystemFontFamilies or mFontFamilies.
     // Ideally we'd use NSString* instead of CFStringRef here, but this header
     // file is included in .cpp files, so we can't use objective C classes here.
     // But CFStringRef and NSString* are the same thing anyway (they're
     // toll-free bridged).
     void AddFamily(CFStringRef aFamily);
 
+    void AddFamily(const nsAString& aFamilyName, bool aSystemFont);
+
 #ifdef MOZ_BUNDLED_FONTS
     void ActivateBundledFonts();
 #endif
 
     enum {
         kATSGenerationInitial = -1
     };
 
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -57,28 +57,31 @@
 #include "nsDirectoryServiceDefs.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsISimpleEnumerator.h"
 #include "nsCharTraits.h"
 #include "nsCocoaFeatures.h"
 #include "nsCocoaUtils.h"
 #include "gfxFontConstants.h"
 
+#include "mozilla/dom/ContentChild.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/gfx/2D.h"
 
 #include <unistd.h>
 #include <time.h>
 #include <dlfcn.h>
 
 using namespace mozilla;
 
+using mozilla::dom::FontFamilyListEntry;
+
 // indexes into the NSArray objects that the Cocoa font manager returns
 // as the available members of a family
 #define INDEX_FONT_POSTSCRIPT_NAME 0
 #define INDEX_FONT_FACE_NAME 1
 #define INDEX_FONT_WEIGHT 2
 #define INDEX_FONT_TRAITS 3
 
 static const int kAppleMaxWeight = 14;
@@ -411,27 +414,32 @@ MacOSFontEntry::AddSizeOfIncludingThis(M
 }
 
 /* gfxMacFontFamily */
 #pragma mark-
 
 class gfxMacFontFamily : public gfxFontFamily
 {
 public:
-    explicit gfxMacFontFamily(nsAString& aName, double aSizeHint) :
+    explicit gfxMacFontFamily(const nsAString& aName, double aSizeHint) :
         gfxFontFamily(aName),
         mSizeHint(aSizeHint)
     {}
 
     virtual ~gfxMacFontFamily() {}
 
     virtual void LocalizedName(nsAString& aLocalizedName);
 
     virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr);
 
+    virtual bool IsSingleFaceFamily() const
+    {
+        return false;
+    }
+
 protected:
     double mSizeHint;
 };
 
 void
 gfxMacFontFamily::LocalizedName(nsAString& aLocalizedName)
 {
     nsAutoreleasePool localPool;
@@ -575,27 +583,32 @@ gfxMacFontFamily::FindStyleVariations(Fo
 }
 
 /* gfxSingleFaceMacFontFamily */
 #pragma mark-
 
 class gfxSingleFaceMacFontFamily : public gfxFontFamily
 {
 public:
-    explicit gfxSingleFaceMacFontFamily(nsAString& aName) :
+    explicit gfxSingleFaceMacFontFamily(const nsAString& aName) :
         gfxFontFamily(aName)
     {
         mFaceNamesInitialized = true; // omit from face name lists
     }
 
     virtual ~gfxSingleFaceMacFontFamily() {}
 
     virtual void LocalizedName(nsAString& aLocalizedName);
 
     virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList);
+
+    virtual bool IsSingleFaceFamily() const
+    {
+        return true;
+    }
 };
 
 void
 gfxSingleFaceMacFontFamily::LocalizedName(nsAString& aLocalizedName)
 {
     nsAutoreleasePool localPool;
 
     if (!HasOtherFamilyNames()) {
@@ -671,73 +684,136 @@ gfxMacPlatformFontList::gfxMacPlatformFo
 gfxMacPlatformFontList::~gfxMacPlatformFontList()
 {
     if (mDefaultFont) {
         ::CFRelease(mDefaultFont);
     }
 }
 
 void
+gfxMacPlatformFontList::AddFamily(const nsAString& aFamilyName,
+                                  bool aSystemFont)
+{
+    FontFamilyTable& table =
+        aSystemFont ? mSystemFontFamilies : mFontFamilies;
+
+    double sizeHint = 0.0;
+    if (aSystemFont && mUseSizeSensitiveSystemFont &&
+        mSystemDisplayFontFamilyName.Equals(aFamilyName)) {
+        sizeHint = 128.0;
+    }
+
+    nsAutoString key;
+    ToLowerCase(aFamilyName, key);
+
+    RefPtr<gfxFontFamily> familyEntry =
+        new gfxMacFontFamily(aFamilyName, sizeHint);
+    table.Put(key, familyEntry);
+
+    // check the bad underline blacklist
+    if (mBadUnderlineFamilyNames.Contains(key)) {
+        familyEntry->SetBadUnderlineFamily();
+    }
+}
+
+void
 gfxMacPlatformFontList::AddFamily(CFStringRef aFamily)
 {
     NSString* family = (NSString*)aFamily;
 
     // CTFontManager includes weird internal family names and
     // LastResort, skip over those
     if (!family || [family caseInsensitiveCompare:@"LastResort"] == NSOrderedSame) {
         return;
     }
 
-    bool hiddenSystemFont = [family hasPrefix:@"."];
-
-    FontFamilyTable& table =
-        hiddenSystemFont ? mSystemFontFamilies : mFontFamilies;
-
     nsAutoString familyName;
     nsCocoaUtils::GetStringForNSString(family, familyName);
 
-    double sizeHint = 0.0;
-    if (hiddenSystemFont && mUseSizeSensitiveSystemFont &&
-        mSystemDisplayFontFamilyName.Equals(familyName)) {
-        sizeHint = 128.0;
+    bool isHiddenSystemFont = familyName[0] == '.';
+    AddFamily(familyName, isHiddenSystemFont);
+}
+
+void
+gfxMacPlatformFontList::GetSystemFontFamilyList(
+    InfallibleTArray<FontFamilyListEntry>* aList)
+{
+    // Note: We rely on the records for mSystemTextFontFamilyName and
+    // mSystemDisplayFontFamilyName (if present) being *before* the main
+    // font list, so that those names are known in the content process
+    // by the time we add the actual family records to the font list.
+    aList->AppendElement(FontFamilyListEntry(mSystemTextFontFamilyName,
+                                             kTextSizeSystemFontFamily));
+    if (mUseSizeSensitiveSystemFont) {
+        aList->AppendElement(FontFamilyListEntry(mSystemDisplayFontFamilyName,
+                                                 kDisplaySizeSystemFontFamily));
     }
 
-    nsAutoString key;
-    ToLowerCase(familyName, key);
-
-    RefPtr<gfxFontFamily> familyEntry = new gfxMacFontFamily(familyName, sizeHint);
-    table.Put(key, familyEntry);
-
-    // check the bad underline blacklist
-    if (mBadUnderlineFamilyNames.Contains(key)) {
-        familyEntry->SetBadUnderlineFamily();
+    // Now collect the lists of available families, both hidden and visible.
+    for (auto f = mSystemFontFamilies.Iter(); !f.Done(); f.Next()) {
+        aList->AppendElement(FontFamilyListEntry(f.Data()->Name(),
+                                                 kHiddenSystemFontFamily));
+    }
+    for (auto f = mFontFamilies.Iter(); !f.Done(); f.Next()) {
+        auto macFamily = static_cast<gfxMacFontFamily*>(f.Data().get());
+        if (macFamily->IsSingleFaceFamily()) {
+            continue; // skip, this will be recreated separately in the child
+        }
+        aList->AppendElement(FontFamilyListEntry(macFamily->Name(),
+                                                 kStandardFontFamily));
     }
 }
 
 nsresult
 gfxMacPlatformFontList::InitFontListForPlatform()
 {
     nsAutoreleasePool localPool;
 
     Telemetry::AutoTimer<Telemetry::MAC_INITFONTLIST_TOTAL> timer;
 
     // reset system font list
     mSystemFontFamilies.Clear();
-    
-    // iterate over available families
 
-    InitSystemFontNames();
-
-    CFArrayRef familyNames = CTFontManagerCopyAvailableFontFamilyNames();
-
-    for (NSString* familyName in (NSArray*)familyNames) {
-        AddFamily((CFStringRef)familyName);
+    if (XRE_IsContentProcess()) {
+        // Content process: use font list passed from the chrome process via
+        // the GetXPCOMProcessAttributes message, because it's much faster than
+        // querying Core Text again in the child.
+        mozilla::dom::ContentChild* cc =
+            mozilla::dom::ContentChild::GetSingleton();
+        for (auto f : cc->SystemFontFamilyList()) {
+            switch (f.entryType()) {
+            case kStandardFontFamily:
+                AddFamily(f.familyName(), false);
+                break;
+            case kHiddenSystemFontFamily:
+                AddFamily(f.familyName(), true);
+                break;
+            case kTextSizeSystemFontFamily:
+                mSystemTextFontFamilyName = f.familyName();
+                break;
+            case kDisplaySizeSystemFontFamily:
+                mSystemDisplayFontFamilyName = f.familyName();
+                mUseSizeSensitiveSystemFont = true;
+                break;
+            }
+        }
+        // The ContentChild doesn't need the font list any longer.
+        cc->SystemFontFamilyList().Clear();
     }
 
-    CFRelease(familyNames);
+    // If this is the chrome process, or if for some reason we failed to get
+    // a usable list above, get the available fonts from Core Text.
+    if (!mFontFamilies.Count()) {
+        InitSystemFontNames();
+        CFArrayRef familyNames = CTFontManagerCopyAvailableFontFamilyNames();
+        for (NSString* familyName in (NSArray*)familyNames) {
+            AddFamily((CFStringRef)familyName);
+        }
+        CFRelease(familyNames);
+    }
 
     InitSingleFaceList();
 
     // to avoid full search of font name tables, seed the other names table with localized names from
     // some of the prefs fonts which are accessed via their localized names.  changes in the pref fonts will only cause
     // a font lookup miss earlier. this is a simple optimization, it's not required for correctness
     PreloadNamesList();
 
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -57,16 +57,19 @@ class FeatureState;
 
 inline uint32_t
 BackendTypeBit(BackendType b)
 {
   return 1 << uint8_t(b);
 }
 
 } // namespace gfx
+namespace dom {
+class FontFamilyListEntry;
+}
 } // namespace mozilla
 
 #define MOZ_PERFORMANCE_WARNING(module, ...) \
   do { \
     if (gfxPlatform::PerfWarnings()) { \
       printf_stderr("[" module "] " __VA_ARGS__); \
     } \
   } while (0)
@@ -314,16 +317,25 @@ public:
      * that correspond to the given language group or generic font family
      * (or both, or neither).
      */
     virtual nsresult GetFontList(nsIAtom *aLangGroup,
                                  const nsACString& aGenericFamily,
                                  nsTArray<nsString>& aListOfFonts);
 
     /**
+     * Fill aFontFamilies with a list of FontFamilyListEntry records for the
+     * available fonts on the platform; used to pass the list from chrome to
+     * content process. Currently implemented only on MacOSX.
+     */
+    virtual void GetSystemFontFamilyList(
+      InfallibleTArray<mozilla::dom::FontFamilyListEntry>* aFontFamilies)
+    { }
+
+    /**
      * Rebuilds the any cached system font lists
      */
     virtual nsresult UpdateFontList();
 
     /**
      * Create the platform font-list object (gfxPlatformFontList concrete subclass).
      * This function is responsible to create the appropriate subclass of
      * gfxPlatformFontList *and* to call its InitFontList() method.
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -25,16 +25,18 @@
 #include <CoreVideo/CoreVideo.h>
 
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "VsyncSource.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
+using mozilla::dom::FontFamilyListEntry;
+
 // cribbed from CTFontManager.h
 enum {
    kAutoActivationDisabled = 1
 };
 typedef uint32_t AutoActivationSetting;
 
 // bug 567552 - disable auto-activation of fonts
 
@@ -105,16 +107,24 @@ gfxPlatformMac::CreatePlatformFontList()
     gfxPlatformFontList* list = new gfxMacPlatformFontList();
     if (NS_SUCCEEDED(list->InitFontList())) {
         return list;
     }
     gfxPlatformFontList::Shutdown();
     return nullptr;
 }
 
+void
+gfxPlatformMac::GetSystemFontFamilyList(
+    InfallibleTArray<FontFamilyListEntry>* aFontFamilies)
+{
+    gfxMacPlatformFontList::PlatformFontList()->
+        GetSystemFontFamilyList(aFontFamilies);
+}
+
 already_AddRefed<gfxASurface>
 gfxPlatformMac::CreateOffscreenSurface(const IntSize& aSize,
                                        gfxImageFormat aFormat)
 {
     if (!Factory::AllowedSurfaceSize(aSize)) {
         return nullptr;
     }
 
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -37,16 +37,20 @@ public:
     CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                     const gfxFontStyle *aStyle,
                     gfxTextPerfMetrics* aTextPerf,
                     gfxUserFontSet *aUserFontSet,
                     gfxFloat aDevToCssSize) override;
 
     virtual gfxPlatformFontList* CreatePlatformFontList() override;
 
+    void
+    GetSystemFontFamilyList(InfallibleTArray<mozilla::dom::FontFamilyListEntry>*
+                            aFontFamilies) override;
+
     bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) override;
 
     virtual void GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
                                         Script aRunScript,
                                         nsTArray<const char*>& aFontList) override;
 
     // lookup the system font for a particular system font type and set
     // the name and style characteristics