Bug 419744. Load font cmap info via a background task. r+sr=stuart
authorjdaggett@mozilla.com
Thu, 03 Apr 2008 19:01:22 -0700
changeset 13877 390ac5b332b938df1256702dc1a991dd21641b09
parent 13876 da756d080c18b9007343023cd018e9589fb933f5
child 13878 cf3ee1d2f8de581405c3257c2f7035673df2e28f
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs419744
milestone1.9pre
Bug 419744. Load font cmap info via a background task. r+sr=stuart
gfx/thebes/public/gfxFontUtils.h
gfx/thebes/public/gfxWindowsFonts.h
gfx/thebes/public/gfxWindowsPlatform.h
gfx/thebes/src/gfxQuartzFontCache.h
gfx/thebes/src/gfxQuartzFontCache.mm
gfx/thebes/src/gfxWindowsFonts.cpp
gfx/thebes/src/gfxWindowsPlatform.cpp
--- a/gfx/thebes/public/gfxFontUtils.h
+++ b/gfx/thebes/public/gfxFontUtils.h
@@ -42,16 +42,21 @@
 #include "gfxTypes.h"
 
 #include "prtypes.h"
 #include "gfxFont.h"
 #include "prcpucfg.h"
 
 #include "nsDataHashtable.h"
 
+#include "nsITimer.h"
+#include "nsCOMPtr.h"
+#include "nsIRunnable.h"
+#include "nsThreadUtils.h"
+
 /* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
 #ifdef __MINGW32__
 #undef min
 #undef max
 #endif
 
 #include <bitset>
 
@@ -259,19 +264,21 @@ public:
             for (PRUint32 bit = start; bit <= end; ++bit) {
                 block->mBits[bit>>3] &= ~(1 << (bit & 0x7));
             }
         }
     }
 
     PRUint32 GetSize() {
         PRUint32 size = 0;
-        for (PRUint32 i = 0; i < mBlocks.Length(); i++)
+        for (PRUint32 i = 0; i < mBlocks.Length(); i++) {
             if (mBlocks[i])
                 size += sizeof(Block);
+            size += sizeof(nsAutoPtr<Block>);
+        }
         return size;
     }
 
     // clear out all blocks in the array
     void reset() {
         PRUint32 i;
         for (i = 0; i < mBlocks.Length(); i++)
             mBlocks[i] = nsnull;    
@@ -328,9 +335,115 @@ public:
 
     static PRUint8 CharRangeBit(PRUint32 ch);
     
     // for a given font list pref name, set up a list of font names
     static void GetPrefsFontList(const char *aPrefName, nsTArray<nsAutoString>& aFontList);
 
 };
 
+// helper class for loading in font info spaced out at regular intervals
+
+class gfxFontInfoLoader {
+public:
+
+    // state transitions:
+    //   initial ---StartLoader with delay---> timer on delay
+    //   initial ---StartLoader without delay---> timer on interval
+    //   timer on delay ---LoaderTimerFire---> timer on interval
+    //   timer on delay ---CancelLoader---> timer off
+    //   timer on interval ---CancelLoader---> timer off
+    //   timer off ---StartLoader with delay---> timer on delay
+    //   timer off ---StartLoader without delay---> timer on interval
+    typedef enum {
+        stateInitial,
+        stateTimerOnDelay,
+        stateTimerOnInterval,
+        stateTimerOff
+    } TimerState;
+
+    gfxFontInfoLoader() :
+        mInterval(0), mState(stateInitial)
+    {
+    }
+
+    virtual ~gfxFontInfoLoader() {}
+
+    // start timer with an initial delay, then call Run method at regular intervals
+    void StartLoader(PRUint32 aDelay, PRUint32 aInterval) {
+        mInterval = aInterval;
+
+        // sanity check
+        if (mState != stateInitial && mState != stateTimerOff)
+            CancelLoader();
+
+        // set up timer
+        if (!mTimer) {
+            mTimer = do_CreateInstance("@mozilla.org/timer;1");
+            if (!mTimer) {
+                NS_WARNING("Failure to create font info loader timer");
+                return;
+            }
+        }
+
+        // need an initial delay?
+        PRUint32 timerInterval;
+
+        if (aDelay) {
+            mState = stateTimerOnDelay;
+            timerInterval = aDelay;
+        } else {
+            mState = stateTimerOnInterval;
+            timerInterval = mInterval;
+        }
+
+        InitLoader();
+
+        // start timer
+        mTimer->InitWithFuncCallback(LoaderTimerCallback, this, aDelay, nsITimer::TYPE_REPEATING_SLACK);
+    }
+
+    // cancel the timer and cleanup
+    void CancelLoader() {
+        if (mState == stateInitial)
+            return;
+        mState = stateTimerOff;
+        if (mTimer) {
+            mTimer->Cancel();
+        }
+        FinishLoader();
+    }
+
+protected:
+
+    // Init - initialization at start time after initial delay
+    virtual void InitLoader() = 0;
+
+    // Run - called at intervals, return true to indicate done
+    virtual PRBool RunLoader() = 0;
+
+    // Finish - cleanup after done
+    virtual void FinishLoader() = 0;
+
+    static void LoaderTimerCallback(nsITimer *aTimer, void *aThis) {
+        gfxFontInfoLoader *loader = (gfxFontInfoLoader*) aThis;
+        loader->LoaderTimerFire();
+    }
+
+    // start the timer, interval callbacks
+    void LoaderTimerFire() {
+        if (mState == stateTimerOnDelay) {
+            mState = stateTimerOnInterval;
+            mTimer->SetDelay(mInterval);
+        }
+
+        PRBool done = RunLoader();
+        if (done) {
+            CancelLoader();
+        }
+    }
+
+    nsCOMPtr<nsITimer> mTimer;
+    PRUint32 mInterval;
+    TimerState mState;
+};
+
 #endif /* GFX_FONT_UTILS_H */
--- a/gfx/thebes/public/gfxWindowsFonts.h
+++ b/gfx/thebes/public/gfxWindowsFonts.h
@@ -64,20 +64,23 @@ public:
     THEBES_INLINE_DECL_REFCOUNTING(FontFamily)
 
     FontFamily(const nsAString& aName) :
         mName(aName), mHasStyles(PR_FALSE), mIsBadUnderlineFont(PR_FALSE) { }
 
     FontEntry *FindFontEntry(const gfxFontStyle& aFontStyle);
 
 private:
+    friend class gfxWindowsPlatform;
+
+    void FindStyleVariations();
+
     static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
                                             const NEWTEXTMETRICEXW *nmetrics,
                                             DWORD fontType, LPARAM data);
-    void FindStyleVariations();
 
 public:
     nsTArray<nsRefPtr<FontEntry> > mVariations;
     nsString mName;
     PRPackedBool mIsBadUnderlineFont;
 
 private:
     PRBool mHasStyles;
--- a/gfx/thebes/public/gfxWindowsPlatform.h
+++ b/gfx/thebes/public/gfxWindowsPlatform.h
@@ -34,42 +34,45 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef GFX_WINDOWS_PLATFORM_H
 #define GFX_WINDOWS_PLATFORM_H
 
+#include "gfxFontUtils.h"
 #include "gfxWindowsSurface.h"
 #include "gfxWindowsFonts.h"
 #include "gfxPlatform.h"
 
 #include "nsVoidArray.h"
 #include "nsDataHashtable.h"
 
 #include <windows.h>
 
-class THEBES_API gfxWindowsPlatform : public gfxPlatform {
+class THEBES_API gfxWindowsPlatform : public gfxPlatform, private gfxFontInfoLoader {
 public:
     gfxWindowsPlatform();
     virtual ~gfxWindowsPlatform();
     static gfxWindowsPlatform *GetPlatform() {
         return (gfxWindowsPlatform*) gfxPlatform::GetPlatform();
     }
 
     already_AddRefed<gfxASurface> CreateOffscreenSurface(const gfxIntSize& size,
                                                          gfxASurface::gfxImageFormat imageFormat);
 
     nsresult GetFontList(const nsACString& aLangGroup,
                          const nsACString& aGenericFamily,
                          nsStringArray& aListOfFonts);
 
     nsresult UpdateFontList();
 
+    void GetFontFamilyList(nsTArray<nsRefPtr<FontFamily> >& aFamilyArray);
+
     nsresult ResolveFontName(const nsAString& aFontName,
                              FontResolverCallback aCallback,
                              void *aClosure, PRBool& aAborted);
 
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
                                   const gfxFontStyle *aStyle);
@@ -123,20 +126,31 @@ private:
     static PLDHashOperator PR_CALLBACK FindFontForCharProc(nsStringHashKey::KeyType aKey,
                                                              nsRefPtr<FontFamily>& aFontFamily,
                                                              void* userArg);
 
     virtual cmsHPROFILE GetPlatformCMSOutputProfile();
 
     static int PR_CALLBACK PrefChangedCallback(const char*, void*);
 
+    // gfxFontInfoLoader overrides, used to load in font cmaps
+    virtual void InitLoader();
+    virtual PRBool RunLoader();
+    virtual void FinishLoader();
+
     FontTable mFonts;
     FontTable mFontAliases;
     FontTable mFontSubstitutes;
     nsStringArray mNonExistingFonts;
 
     // when system-wide font lookup fails for a character, cache it to skip future searches
     gfxSparseBitSet mCodepointsWithNoFonts;
     
     nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<FontEntry> > > mPrefFonts;
+
+    // data used as part of the font cmap loading process
+    nsTArray<nsRefPtr<FontFamily> > mFontFamilies;
+    PRUint32 mStartIndex;
+    PRUint32 mIncrement;
+    PRUint32 mNumFamilies;
 };
 
 #endif /* GFX_WINDOWS_PLATFORM_H */
--- a/gfx/thebes/src/gfxQuartzFontCache.h
+++ b/gfx/thebes/src/gfxQuartzFontCache.h
@@ -146,16 +146,24 @@ public:
     void FindFontForChar(FontSearch *aMatchData);
     
     // read in other family names, if any, and use functor to add each into cache
     virtual void ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor);
     
     // search for a specific face using the Postscript name
     MacOSFontEntry* FindFont(const nsString& aPostscriptName);
 
+    // read in cmaps for all the faces
+    void ReadCMAP() {
+        PRUint32 i, numFonts = mAvailableFonts.Length();
+        for (i = 0; i < numFonts; i++)
+            mAvailableFonts[i]->ReadCMAP();
+    }
+
+
     // whether this font family is in "bad" underline offset blacklist.
     PRBool IsBadUnderlineFontFamily() { return mIsBadUnderlineFontFamily != 0; }
 
 protected:
     
     // add font entries into array that match specified traits, returned in array listed by weight
     // i.e. aFontsForWeights[4] ==> pointer to the font entry for a 400-weight face on return
     // returns true if one or more faces found
@@ -183,17 +191,17 @@ public:
     virtual ~SingleFaceFamily() {}
     
     virtual void LocalizedName(nsAString& aLocalizedName);
     
     // read in other family names, if any, and use functor to add each into cache
     virtual void ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor);
 };
 
-class gfxQuartzFontCache {
+class gfxQuartzFontCache : private gfxFontInfoLoader {
 public:
     static gfxQuartzFontCache* SharedFontCache() {
         return sSharedFontCache;
     }
 
     static nsresult Init() {
         NS_ASSERTION(!sSharedFontCache, "What's this doing here?");
         sSharedFontCache = new gfxQuartzFontCache();
@@ -211,16 +219,17 @@ public:
     void GetFontList (const nsACString& aLangGroup,
                       const nsACString& aGenericFamily,
                       nsStringArray& aListOfFonts);
     PRBool ResolveFontName(const nsAString& aFontName,
                            nsAString& aResolvedFontName);
     PRBool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
     void UpdateFontList() { InitFontList(); }
 
+    void GetFontFamilyList(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamilyArray);
 
     MacOSFontEntry* FindFontForChar(const PRUint32 aCh, gfxAtsuiFont *aPrevFont);
 
     MacOSFamilyEntry* FindFamily(const nsAString& aFamily);
     
     MacOSFontEntry* FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, PRBool& aNeedsBold);
     
     MacOSFontEntry* GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold);
@@ -258,38 +267,48 @@ private:
     void InitBadUnderlineList();
 
     // eliminate faces which have the same ATSUI id
     void EliminateDuplicateFaces(const nsAString& aFamilyName);
                                                              
     static PLDHashOperator PR_CALLBACK InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
                                                              nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
                                                              void* userArg);
-    
+
     void GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult);
     static void ATSNotification(ATSFontNotificationInfoRef aInfo, void* aUserArg);
     static int PR_CALLBACK PrefChangedCallback(const char *aPrefName, void *closure);
 
     static PLDHashOperator PR_CALLBACK
         HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
                                 nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
                                 void* aUserArg);
 
+    // gfxFontInfoLoader overrides, used to load in font cmaps
+    virtual void InitLoader();
+    virtual PRBool RunLoader();
+    virtual void FinishLoader();
+
     // canonical family name ==> family entry (unique, one name per family entry)
     nsRefPtrHashtable<nsStringHashKey, MacOSFamilyEntry> mFontFamilies;    
 
     // other family name ==> family entry (not unique, can have multiple names per 
     // family entry, only names *other* than the canonical names are stored here)
     nsRefPtrHashtable<nsStringHashKey, MacOSFamilyEntry> mOtherFamilyNames;    
 
     // cached pref font lists
     // maps list of family names ==> array of family entries, one per lang group
     nsDataHashtable<nsUint32HashKey, nsTArray<nsRefPtr<MacOSFamilyEntry> > > mPrefFonts;
 
     // when system-wide font lookup fails for a character, cache it to skip future searches
     gfxSparseBitSet mCodepointsWithNoFonts;
-    
+
     // flag set after InitOtherFamilyNames is called upon first name lookup miss
     PRPackedBool mOtherFamilyNamesInitialized;
 
+    // data used as part of the font cmap loading process
+    nsTArray<nsRefPtr<MacOSFamilyEntry> > mFontFamiliesToLoad;
+    PRUint32 mStartIndex;
+    PRUint32 mIncrement;
+    PRUint32 mNumFamilies;
 };
 
 #endif /* GFXQUARTZFONTCACHE_H_ */
--- a/gfx/thebes/src/gfxQuartzFontCache.mm
+++ b/gfx/thebes/src/gfxQuartzFontCache.mm
@@ -48,21 +48,26 @@
 #include "nsIPref.h"  // for pref changes callback notification
 #include "nsServiceManagerUtils.h"
 
 // _atsFontID is private; add it in our new category to NSFont
 @interface NSFont (MozillaCategory)
 - (ATSUFontID)_atsFontID;
 @end
 
+// font info loader constants
+static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
+static const PRUint32 kIntervalBetweenLoadingCmaps = 150; // 150ms
+static const PRUint32 kNumFontsPerSlice = 10; // read in info 10 fonts at a time
+
 #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;
 
 static const int gAppleWeightToCSSWeight[] = {
     0,
     1, // 1. 
     1, // 2.  W1, ultralight
     2, // 3.  W2, extralight
     3, // 4.  W3, light
@@ -79,17 +84,17 @@ static const int gAppleWeightToCSSWeight
 };
 
 
 static void GetStringForNSString(const NSString *aSrc, nsAString& aDist)
 {
     aDist.SetLength([aSrc length]);
     [aSrc getCharacters:aDist.BeginWriting()];
 }
- 
+
 static NSString* GetNSStringForString(const nsAString& aSrc)
 {
     return [NSString stringWithCharacters:aSrc.BeginReading()
                      length:aSrc.Length()];
 }
 
 static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
 
@@ -163,25 +168,26 @@ const ScriptRange gScriptsThatRequireSha
     // Thai seems to be "renderable" without AAT morphing tables
     // xxx - Lao, Khmer?
 };
 
 nsresult
 MacOSFontEntry::ReadCMAP()
 {
     OSStatus status;
-    ByteCount size;
-    
+    ByteCount size, cmapSize;
+
     if (mCmapInitialized) return NS_OK;
     ATSUFontID fontID = GetFontID();
-    
+
     // attempt this once, if errors occur leave a blank cmap
     mCmapInitialized = PR_TRUE;
-    
+
     status = ATSFontGetTable(fontID, 'cmap', 0, 0, 0, &size);
+    cmapSize = size;
     //printf( "cmap size: %s %d\n", NS_ConvertUTF16toUTF8(mName).get(), size );
     NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
 
     nsAutoTArray<PRUint8,16384> buffer;
     if (!buffer.AppendElements(size))
         return NS_ERROR_OUT_OF_MEMORY;
     PRUint8 *cmap = buffer.Elements();
 
@@ -229,35 +235,38 @@ MacOSFontEntry::ReadCMAP()
 
             // general exclusion - if no morph table, exclude codepoints
             if (!hasMorphTable) {
                 mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd);
             }
         }
     }
 
+    PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-cmap) psname: %s, size: %d\n", 
+                                        NS_ConvertUTF16toUTF8(mPostscriptName).get(), mCharacterMap.GetSize()));
+                                        
     return rv;
 }
 
 
 /* MacOSFamilyEntry */
 #pragma mark-
 
 // helper class for adding other family names back into font cache
 class AddOtherFamilyNameFunctor 
 {
 public:
     AddOtherFamilyNameFunctor(gfxQuartzFontCache *aFontCache) :
         mFontCache(aFontCache)
     {}
-        
+
     void operator() (MacOSFamilyEntry *aFamilyEntry, nsAString& aOtherName) {
         mFontCache->AddOtherFamilyName(aFamilyEntry, aOtherName);
     }
-    
+
     gfxQuartzFontCache *mFontCache;
 };
 
 void MacOSFamilyEntry::LocalizedName(nsAString& aLocalizedName)
 {
     // no other names ==> only one name, just return it
     if (!HasOtherFamilyNames()) {
         aLocalizedName = mName;
@@ -579,24 +588,24 @@ enum {
 
 // returns true if other names were found, false otherwise
 static PRBool ReadOtherFamilyNamesForFace(AddOtherFamilyNameFunctor& aOtherFamilyFunctor, MacOSFamilyEntry *aFamilyEntry,
                                         NSString *familyName, ATSUFontID fontID, bool useFullName = false)
 {
     OSStatus err;
     ItemCount i, nameCount;
     PRBool foundNames = PR_FALSE;
-    
+
     if (fontID == kATSUInvalidFontID)
         return foundNames;
 
     err = ATSUCountFontNames(fontID, &nameCount);
     if (err != noErr) 
         return foundNames;
-    
+
     for (i = 0; i < nameCount; i++) {
 
         FontNameCode nameCode;
         FontPlatformCode platformCode;
         FontScriptCode scriptCode;
         FontLanguageCode langCode;
         const ByteCount kBufLength = 2048;
         char buf[kBufLength];
@@ -604,39 +613,39 @@ static PRBool ReadOtherFamilyNamesForFac
 
         err = ATSUGetIndFontName(fontID, i, kBufLength, buf, &len, &nameCode, &platformCode, &scriptCode, &langCode);
         // couldn't find a font name? just continue to the next name table entry
         if (err == kATSUNoFontNameErr) 
             continue;
         // any other error, bail
         if (err != noErr) 
             return foundNames;
-        
+
         if (useFullName) {
             if (nameCode != kFontFullName)
                 continue;
         } else {
             if (!(nameCode == kFontFamilyName || nameCode == kMozillaFontPreferredFamilyName)) 
                 continue; 
         }
         if (len >= kBufLength) continue; 
         buf[len] = 0;
-        
+
         NSString *name = CreateNameFromBuffer((UInt8*)buf, len, platformCode, scriptCode, langCode);
-        
+
         // add if not same as canonical family name or already in list of names
         if (name) {
 
             if (![name isEqualToString:familyName]) {
                 nsAutoString otherFamilyName;
                 GetStringForNSString(name, otherFamilyName);
                 aOtherFamilyFunctor(aFamilyEntry, otherFamilyName);
                 foundNames = PR_TRUE;
             }
-    
+
             [name release];
         }
     }
 
     return foundNames;
 }
 
 void
@@ -707,22 +716,23 @@ void SingleFaceFamily::ReadOtherFamilyNa
 }
 
 /* gfxQuartzFontCache */
 #pragma mark-
 
 gfxQuartzFontCache *gfxQuartzFontCache::sSharedFontCache = nsnull;
 
 gfxQuartzFontCache::gfxQuartzFontCache()
+    : mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
 {
     mFontFamilies.Init(100);
     mOtherFamilyNames.Init(30);
     mOtherFamilyNamesInitialized = PR_FALSE;
     mPrefFonts.Init(10);
-
+    
     InitFontList();
     ::ATSFontNotificationSubscribe(ATSNotification,
                                    kATSFontNotifyOptionDefault,
                                    (void*)this, nsnull);
 
     // pref changes notification setup
     nsCOMPtr<nsIPref> pref = do_GetService(NS_PREF_CONTRACTID);
     pref->RegisterCallback("font.", PrefChangedCallback, this);
@@ -736,17 +746,18 @@ const PRUint32 kNonNormalTraits = NSItal
 void
 gfxQuartzFontCache::InitFontList()
 {
     mFontFamilies.Clear();
     mOtherFamilyNames.Clear();
     mOtherFamilyNamesInitialized = PR_FALSE;
     mPrefFonts.Clear();
     mCodepointsWithNoFonts.reset();
-    
+    CancelLoader();
+
     // iterate over available families
     NSFontManager *fontManager = [NSFontManager sharedFontManager];
     NSEnumerator *families = [[fontManager availableFontFamilies] objectEnumerator];  // returns "canonical", non-localized family name
     
     nsAutoString availableFamilyName, postscriptFontName;
    
     NSString *availableFamily = nil;
     while ((availableFamily = [families nextObject])) {
@@ -807,16 +818,20 @@ gfxQuartzFontCache::InitFontList()
     EliminateDuplicateFaces(NS_LITERAL_STRING("Helvetica"));
     
     // initialize ranges of characters for which system-wide font search should be skipped
     mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
     mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
     mCodepointsWithNoFonts.set(0xfffd);          // unknown
 
     InitBadUnderlineList();
+
+    // start the delayed cmap loader
+    StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps); 
+
 }
 
 void 
 gfxQuartzFontCache::InitOtherFamilyNames()
 {
     mOtherFamilyNamesInitialized = PR_TRUE;
     
     // iterate over all font families and read in other family names
@@ -913,50 +928,50 @@ gfxQuartzFontCache::PreloadNamesList()
 
 void 
 gfxQuartzFontCache::EliminateDuplicateFaces(const nsAString& aFamilyName)
 {
     MacOSFamilyEntry *family = FindFamily(aFamilyName);
     if (!family) return;
 
     nsTArray<nsRefPtr<MacOSFontEntry> >& fontlist = family->GetFontList();
-    
+
     PRUint32 i, bold, numFonts, italicIndex;
     MacOSFontEntry *italic, *nonitalic;
     PRUint32 boldtraits[2] = { 0, NSBoldFontMask };
-    
+
     // if normal and italic have the same ATSUI id, delete italic
     // if bold and bold-italic have the same ATSUI id, delete bold-italic
-    
+
     // two iterations, one for normal, one for bold
     for (bold = 0; bold < 2; bold++) {
         numFonts = fontlist.Length();
-        
+
         // find the non-italic face
         nonitalic = nsnull;
         for (i = 0; i < numFonts; i++) {
             PRUint32 traits = fontlist[i]->Traits();
             if (((traits & NSBoldFontMask) == boldtraits[bold]) && !(traits & NSItalicFontMask)) {
                 nonitalic = fontlist[i];
                 break;
             }
         }
-        
+
         // find the italic face
         if (nonitalic) {
             italic = nsnull;
             for (i = 0; i < numFonts; i++) {
                 PRUint32 traits = fontlist[i]->Traits();
                 if (((traits & NSBoldFontMask) == boldtraits[bold]) && (traits & NSItalicFontMask)) {
                     italic = fontlist[i];
                     italicIndex = i;
                     break;
                 }
             }
-            
+
             // if italic face and non-italic face have matching ATSUI id's, 
             // the italic face is bogus so remove it
             if (italic && italic->GetFontID() == nonitalic->GetFontID()) {
                 fontlist.RemoveElementAt(italicIndex);
             }
         }
     }
 }
@@ -1078,20 +1093,20 @@ struct FontListData {
     const nsACString& mLangGroup;
     const nsACString& mGenericFamily;
     nsStringArray& mListOfFonts;
 };
 
 PLDHashOperator PR_CALLBACK
 gfxQuartzFontCache::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
                                             nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
-                                            void* aUserArg)
+                                            void *aUserArg)
 {
     FontListData *data = (FontListData*)aUserArg;
-    
+
     nsAutoString localizedFamilyName;
     aFamilyEntry->LocalizedName(localizedFamilyName);
     data->mListOfFonts.AppendString(localizedFamilyName);
     return PL_DHASH_NEXT;
 }
 
 void
 gfxQuartzFontCache::GetFontList (const nsACString& aLangGroup,
@@ -1101,16 +1116,40 @@ gfxQuartzFontCache::GetFontList (const n
     FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
 
     mFontFamilies.Enumerate(gfxQuartzFontCache::HashEnumFuncForFamilies, &data);
 
     aListOfFonts.Sort();
     aListOfFonts.Compact();
 }
 
+struct FontFamilyListData {
+    FontFamilyListData(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamilyArray) 
+        : mFamilyArray(aFamilyArray)
+    {}
+
+    static PLDHashOperator PR_CALLBACK AppendFamily(nsStringHashKey::KeyType aKey,
+                                                    nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
+                                                    void *aUserArg)
+    {
+        FontFamilyListData *data = (FontFamilyListData*)aUserArg;
+        data->mFamilyArray.AppendElement(aFamilyEntry);
+        return PL_DHASH_NEXT;
+    }
+
+    nsTArray<nsRefPtr<MacOSFamilyEntry> >& mFamilyArray;
+};
+
+void
+gfxQuartzFontCache::GetFontFamilyList(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamilyArray)
+{
+    FontFamilyListData data(aFamilyArray);
+    mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
+}
+
 MacOSFontEntry*  
 gfxQuartzFontCache::FindFontForChar(const PRUint32 aCh, gfxAtsuiFont *aPrevFont)
 {
     // is codepoint with no matching font? return null immediately
     if (mCodepointsWithNoFonts.test(aCh)) {
         return nsnull;
     }
 
@@ -1118,39 +1157,39 @@ gfxQuartzFontCache::FindFontForChar(cons
 
     // iterate over all font families to find a font that support the character
     mFontFamilies.Enumerate(gfxQuartzFontCache::FindFontForCharProc, &data);
 
     // no match? add to set of non-matching codepoints
     if (!data.bestMatch) {
         mCodepointsWithNoFonts.set(aCh);
     }
-    
+
     return data.bestMatch;
 }
 
 PLDHashOperator PR_CALLBACK 
 gfxQuartzFontCache::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
-     void* userArg)
+     void *userArg)
 {
     FontSearch *data = (FontSearch*)userArg;
 
     // evaluate all fonts in this family for a match
     aFamilyEntry->FindFontForChar(data);
     return PL_DHASH_NEXT;
 }
 
 MacOSFamilyEntry* 
 gfxQuartzFontCache::FindFamily(const nsAString& aFamily)
 {
     nsAutoString key;
     MacOSFamilyEntry *familyEntry;
     PRBool found;
     GenerateFontListKey(aFamily, key);
-    
+
     // lookup in canonical (i.e. English) family name list
     if ((familyEntry = mFontFamilies.GetWeak(key, &found))) {
         return familyEntry;
     }
 
     // lookup in other family names list (mostly localized names)
     if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found))) {
         return familyEntry;
@@ -1213,8 +1252,46 @@ gfxQuartzFontCache::AddOtherFamilyName(M
 
     if (!mOtherFamilyNames.GetWeak(key, &found)) {
         mOtherFamilyNames.Put(key, aFamilyEntry);
         PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-otherfamily) canonical family: %s, other family: %s\n", 
                                             NS_ConvertUTF16toUTF8(aFamilyEntry->Name()).get(), 
                                             NS_ConvertUTF16toUTF8(aOtherFamilyName).get()));
     }
 }
+
+void 
+gfxQuartzFontCache::InitLoader()
+{
+    GetFontFamilyList(mFontFamiliesToLoad);
+    mStartIndex = 0;
+    mNumFamilies = mFontFamiliesToLoad.Length();
+}
+
+PRBool 
+gfxQuartzFontCache::RunLoader()
+{
+    PRUint32 i, endIndex = ( mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies );
+
+    // for each font family, load in various font info
+    for (i = mStartIndex; i < endIndex; i++) {
+        AddOtherFamilyNameFunctor addOtherNames(this);
+
+        // load the cmap
+        mFontFamiliesToLoad[i]->ReadCMAP();
+
+        // read in other family names
+        mFontFamiliesToLoad[i]->ReadOtherFamilyNames(addOtherNames);
+    }
+
+    mStartIndex += mIncrement;
+    if (mStartIndex < mNumFamilies)
+        return PR_FALSE;
+    return PR_TRUE;
+}
+
+void 
+gfxQuartzFontCache::FinishLoader()
+{
+    mFontFamiliesToLoad.Clear();
+    mNumFamilies = 0;
+}
+
--- a/gfx/thebes/src/gfxWindowsFonts.cpp
+++ b/gfx/thebes/src/gfxWindowsFonts.cpp
@@ -221,30 +221,34 @@ FontFamily::FamilyAddStylesProc(const EN
                 fe->mUnicodeFont = PR_TRUE;
             else
                 fe->mUnicodeFont = PR_FALSE;
 
             // For fonts where we failed to read the character map,
             // we should use GDI to slowly determine their cmap lazily
             fe->mForceGDI = PR_TRUE;
 
-            //printf("%d, %s failed to get cmap\n", aFontEntry->mIsType1, NS_ConvertUTF16toUTF8(aFontEntry->mName).get());
+            //printf("(fontinit-cmap) %s failed to get cmap, type1:%d \n", NS_ConvertUTF16toUTF8(fe->mFaceName).get(), (PRUint32)(fe->mIsType1));
+        } else {
+            //printf("(fontinit-cmap) %s cmap loaded, italic:%d, weight:%d\n", NS_ConvertUTF16toUTF8(fe->mFaceName).get(), (PRUint32)(fe->mItalic), (PRUint32)(fe->mWeight));
         }
 
         SelectObject(hdc, oldFont);
         DeleteObject(font);
     }
 
     return 1;
 }
 
 // general cmap reading routines moved to gfxFontUtils.cpp
 void
 FontFamily::FindStyleVariations()
 {
+    if (mHasStyles)
+        return;
     mHasStyles = PR_TRUE;
 
     HDC hdc = GetDC(nsnull);
 
     LOGFONTW logFont;
     memset(&logFont, 0, sizeof(LOGFONTW));
     logFont.lfCharSet = DEFAULT_CHARSET;
     logFont.lfPitchAndFamily = 0;
@@ -1415,17 +1419,17 @@ public:
                 for (j = 1; j < glyphCount; ++j) {
                     if (IsGlyphMissing(&sfp, k + j)) {
                         missing = PR_TRUE;
                     }
                 }
                 PRInt32 advance = mAdvances[k]*appUnitsPerDevUnit;
                 WORD glyph = mGlyphs[k];
                 NS_ASSERTION(!gfxFontGroup::IsInvalidChar(mRangeString[offset]),
-                		     "invalid character detected");
+                             "invalid character detected");
                 if (missing) {
                     if (NS_IS_HIGH_SURROGATE(mRangeString[offset]) &&
                         offset + 1 < mRangeLength &&
                         NS_IS_LOW_SURROGATE(mRangeString[offset + 1])) {
                         aRun->SetMissingGlyph(runOffset,
                                               SURROGATE_TO_UCS4(mRangeString[offset],
                                                                 mRangeString[offset + 1]));
                     } else {
--- a/gfx/thebes/src/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/src/gfxWindowsPlatform.cpp
@@ -53,16 +53,21 @@
 #include "gfxWindowsFonts.h"
 
 #include <string>
 
 #include "lcms.h"
 
 //#define DEBUG_CMAP_SIZE 1
 
+// font info loader constants
+static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
+static const PRUint32 kIntervalBetweenLoadingCmaps = 150; // 150ms
+static const PRUint32 kNumFontsPerSlice = 10; // read in info 10 fonts at a time
+
 static __inline void
 BuildKeyNameFromFontName(nsAString &aName)
 {
     if (aName.Length() >= LF_FACESIZE)
         aName.Truncate(LF_FACESIZE - 1);
     ToLowerCase(aName);
 }
 
@@ -72,16 +77,17 @@ gfxWindowsPlatform::PrefChangedCallback(
     // XXX this could be made to only clear out the cache for the prefs that were changed
     // but it probably isn't that big a deal.
     gfxWindowsPlatform *plat = static_cast<gfxWindowsPlatform *>(closure);
     plat->mPrefFonts.Clear();
     return 0;
 }
 
 gfxWindowsPlatform::gfxWindowsPlatform()
+    : mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
 {
     mFonts.Init(200);
     mFontAliases.Init(20);
     mFontSubstitutes.Init(50);
     mPrefFonts.Init(10);
 
     UpdateFontList();
 
@@ -197,27 +203,31 @@ gfxWindowsPlatform::UpdateFontList()
     if (fc)
         fc->AgeAllGenerations();
     mFonts.Clear();
     mFontAliases.Clear();
     mNonExistingFonts.Clear();
     mFontSubstitutes.Clear();
     mPrefFonts.Clear();
     mCodepointsWithNoFonts.reset();
-
+    CancelLoader();
+    
     LOGFONTW logFont;
     logFont.lfCharSet = DEFAULT_CHARSET;
     logFont.lfFaceName[0] = 0;
     logFont.lfPitchAndFamily = 0;
 
     // Use the screen DC here.. should we use something else for printing?
     HDC dc = ::GetDC(nsnull);
     EnumFontFamiliesExW(dc, &logFont, (FONTENUMPROCW)gfxWindowsPlatform::FontEnumProc, (LPARAM)&mFonts, 0);
     ::ReleaseDC(nsnull, dc);
 
+    // initialize the cmap loading process after font list has been initialized
+    StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps); 
+
     // Create the list of FontSubstitutes
     nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
     if (!regKey)
         return NS_ERROR_FAILURE;
      NS_NAMED_LITERAL_STRING(kFontSubstitutesKey, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
 
     nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
                                kFontSubstitutesKey, nsIWindowsRegKey::ACCESS_READ);
@@ -258,16 +268,40 @@ gfxWindowsPlatform::UpdateFontList()
     mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
     mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
 
     InitBadUnderlineList();
 
     return NS_OK;
 }
 
+struct FontFamilyListData {
+    FontFamilyListData(nsTArray<nsRefPtr<FontFamily> >& aFamilyArray) 
+        : mFamilyArray(aFamilyArray)
+    {}
+
+    static PLDHashOperator PR_CALLBACK AppendFamily(nsStringHashKey::KeyType aKey,
+                                                    nsRefPtr<FontFamily>& aFamilyEntry,
+                                                    void *aUserArg)
+    {
+        FontFamilyListData *data = (FontFamilyListData*)aUserArg;
+        data->mFamilyArray.AppendElement(aFamilyEntry);
+        return PL_DHASH_NEXT;
+    }
+
+    nsTArray<nsRefPtr<FontFamily> >& mFamilyArray;
+};
+
+void
+gfxWindowsPlatform::GetFontFamilyList(nsTArray<nsRefPtr<FontFamily> >& aFamilyArray)
+{
+    FontFamilyListData data(aFamilyArray);
+    mFonts.Enumerate(FontFamilyListData::AppendFamily, &data);
+}
+
 static PRBool SimpleResolverCallback(const nsAString& aName, void* aClosure)
 {
     nsString *result = static_cast<nsString*>(aClosure);
     result->Assign(aName);
     return PR_FALSE;
 }
 
 void
@@ -536,8 +570,41 @@ gfxWindowsPlatform::GetPrefFontEntries(c
     return mPrefFonts.Get(aKey, array);
 }
 
 void
 gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> >& array)
 {
     mPrefFonts.Put(aKey, array);
 }
+
+void 
+gfxWindowsPlatform::InitLoader()
+{
+    GetFontFamilyList(mFontFamilies);
+    mStartIndex = 0;
+    mNumFamilies = mFontFamilies.Length();
+}
+
+PRBool 
+gfxWindowsPlatform::RunLoader()
+{
+    PRUint32 i, endIndex = ( mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies );
+
+    // for each font family, load in various font info
+    for (i = mStartIndex; i < endIndex; i++) {
+        // load the cmaps for all variations
+        mFontFamilies[i]->FindStyleVariations();
+    }
+
+    mStartIndex += mIncrement;
+    if (mStartIndex < mNumFamilies)
+        return PR_FALSE;
+    return PR_TRUE;
+}
+
+void 
+gfxWindowsPlatform::FinishLoader()
+{
+    mFontFamilies.Clear();
+    mNumFamilies = 0;
+}
+