Bug 419744. Load font cmap info via a background task. r+sr=stuart

This commit is contained in:
jdaggett@mozilla.com 2008-04-03 19:01:22 -07:00
parent ad19a6a80e
commit 87dc00328b
7 changed files with 333 additions and 36 deletions

View File

@ -47,6 +47,11 @@
#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
@ -264,9 +269,11 @@ public:
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;
}
@ -333,4 +340,110 @@ public:
};
// 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 */

View File

@ -69,10 +69,13 @@ public:
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;

View File

@ -39,6 +39,7 @@
#ifndef GFX_WINDOWS_PLATFORM_H
#define GFX_WINDOWS_PLATFORM_H
#include "gfxFontUtils.h"
#include "gfxWindowsSurface.h"
#include "gfxWindowsFonts.h"
#include "gfxPlatform.h"
@ -48,7 +49,7 @@
#include <windows.h>
class THEBES_API gfxWindowsPlatform : public gfxPlatform {
class THEBES_API gfxWindowsPlatform : public gfxPlatform, private gfxFontInfoLoader {
public:
gfxWindowsPlatform();
virtual ~gfxWindowsPlatform();
@ -65,6 +66,8 @@ public:
nsresult UpdateFontList();
void GetFontFamilyList(nsTArray<nsRefPtr<FontFamily> >& aFamilyArray);
nsresult ResolveFontName(const nsAString& aFontName,
FontResolverCallback aCallback,
void *aClosure, PRBool& aAborted);
@ -128,6 +131,11 @@ private:
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;
@ -137,6 +145,12 @@ private:
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 */

View File

@ -151,6 +151,14 @@ public:
// 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; }
@ -188,7 +196,7 @@ public:
virtual void ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor);
};
class gfxQuartzFontCache {
class gfxQuartzFontCache : private gfxFontInfoLoader {
public:
static gfxQuartzFontCache* SharedFontCache() {
return sSharedFontCache;
@ -216,6 +224,7 @@ public:
PRBool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
void UpdateFontList() { InitFontList(); }
void GetFontFamilyList(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamilyArray);
MacOSFontEntry* FindFontForChar(const PRUint32 aCh, gfxAtsuiFont *aPrevFont);
@ -263,7 +272,7 @@ private:
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);
@ -273,6 +282,11 @@ private:
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;
@ -286,10 +300,15 @@ private:
// 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_ */

View File

@ -53,11 +53,16 @@
- (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[] = {
@ -84,7 +89,7 @@ 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()
@ -168,15 +173,16 @@ 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);
@ -234,6 +240,9 @@ MacOSFontEntry::ReadCMAP()
}
}
PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-cmap) psname: %s, size: %d\n",
NS_ConvertUTF16toUTF8(mPostscriptName).get(), mCharacterMap.GetSize()));
return rv;
}
@ -248,11 +257,11 @@ public:
AddOtherFamilyNameFunctor(gfxQuartzFontCache *aFontCache) :
mFontCache(aFontCache)
{}
void operator() (MacOSFamilyEntry *aFamilyEntry, nsAString& aOtherName) {
mFontCache->AddOtherFamilyName(aFamilyEntry, aOtherName);
}
gfxQuartzFontCache *mFontCache;
};
@ -584,14 +593,14 @@ static PRBool ReadOtherFamilyNamesForFace(AddOtherFamilyNameFunctor& aOtherFamil
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;
@ -609,7 +618,7 @@ static PRBool ReadOtherFamilyNamesForFace(AddOtherFamilyNameFunctor& aOtherFamil
// any other error, bail
if (err != noErr)
return foundNames;
if (useFullName) {
if (nameCode != kFontFullName)
continue;
@ -619,9 +628,9 @@ static PRBool ReadOtherFamilyNamesForFace(AddOtherFamilyNameFunctor& aOtherFamil
}
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) {
@ -631,7 +640,7 @@ static PRBool ReadOtherFamilyNamesForFace(AddOtherFamilyNameFunctor& aOtherFamil
aOtherFamilyFunctor(aFamilyEntry, otherFamilyName);
foundNames = PR_TRUE;
}
[name release];
}
}
@ -712,12 +721,13 @@ void SingleFaceFamily::ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFam
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,
@ -741,7 +751,8 @@ gfxQuartzFontCache::InitFontList()
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
@ -812,6 +823,10 @@ gfxQuartzFontCache::InitFontList()
mCodepointsWithNoFonts.set(0xfffd); // unknown
InitBadUnderlineList();
// start the delayed cmap loader
StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps);
}
void
@ -918,18 +933,18 @@ gfxQuartzFontCache::EliminateDuplicateFaces(const nsAString& 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++) {
@ -939,7 +954,7 @@ gfxQuartzFontCache::EliminateDuplicateFaces(const nsAString& aFamilyName)
break;
}
}
// find the italic face
if (nonitalic) {
italic = nsnull;
@ -951,7 +966,7 @@ gfxQuartzFontCache::EliminateDuplicateFaces(const nsAString& aFamilyName)
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()) {
@ -1083,10 +1098,10 @@ struct FontListData {
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);
@ -1106,6 +1121,30 @@ gfxQuartzFontCache::GetFontList (const nsACString& aLangGroup,
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)
{
@ -1123,13 +1162,13 @@ gfxQuartzFontCache::FindFontForChar(const PRUint32 aCh, gfxAtsuiFont *aPrevFont)
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;
@ -1145,7 +1184,7 @@ gfxQuartzFontCache::FindFamily(const nsAString& aFamily)
MacOSFamilyEntry *familyEntry;
PRBool found;
GenerateFontListKey(aFamily, key);
// lookup in canonical (i.e. English) family name list
if ((familyEntry = mFontFamilies.GetWeak(key, &found))) {
return familyEntry;
@ -1218,3 +1257,41 @@ gfxQuartzFontCache::AddOtherFamilyName(MacOSFamilyEntry *aFamilyEntry, nsAString
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;
}

View File

@ -226,7 +226,9 @@ FontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
// 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);
@ -240,6 +242,8 @@ FontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
void
FontFamily::FindStyleVariations()
{
if (mHasStyles)
return;
mHasStyles = PR_TRUE;
HDC hdc = GetDC(nsnull);
@ -1420,7 +1424,7 @@ public:
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 &&

View File

@ -58,6 +58,11 @@
//#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)
{
@ -77,6 +82,7 @@ gfxWindowsPlatform::PrefChangedCallback(const char *aPrefName, void *closure)
}
gfxWindowsPlatform::gfxWindowsPlatform()
: mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
{
mFonts.Init(200);
mFontAliases.Init(20);
@ -202,7 +208,8 @@ gfxWindowsPlatform::UpdateFontList()
mFontSubstitutes.Clear();
mPrefFonts.Clear();
mCodepointsWithNoFonts.reset();
CancelLoader();
LOGFONTW logFont;
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfFaceName[0] = 0;
@ -213,6 +220,9 @@ gfxWindowsPlatform::UpdateFontList()
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)
@ -263,6 +273,30 @@ gfxWindowsPlatform::UpdateFontList()
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);
@ -541,3 +575,36 @@ gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<
{
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;
}