--- 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;
+}
+