1 /* -*- Mode: ObjC; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * ***** BEGIN LICENSE BLOCK *****
5 * Copyright (C) 2006 Mozilla Corporation. All rights reserved.
8 * Vladimir Vukicevic <vladimir@pobox.com>
9 * Masayuki Nakano <masayuki@d-toybox.com>
10 * John Daggett <jdaggett@mozilla.com>
12 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
24 * its contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
28 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
29 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
31 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
34 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 * ***** END LICENSE BLOCK ***** */
42 #import <AppKit/AppKit.h>
44 #include "gfxPlatformMac.h"
45 #include "gfxQuartzFontCache.h"
46 #include "gfxAtsuiFonts.h"
47 #include "gfxUserFontSet.h"
49 #include "nsIPref.h" // for pref changes callback notification
50 #include "nsServiceManagerUtils.h"
52 #include "nsDirectoryServiceUtils.h"
53 #include "nsDirectoryServiceDefs.h"
54 #include "nsISimpleEnumerator.h"
59 // _atsFontID is private; add it in our new category to NSFont
60 @interface NSFont (MozillaCategory)
61 - (ATSUFontID)_atsFontID;
64 // font info loader constants
65 static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
66 static const PRUint32 kIntervalBetweenLoadingCmaps = 150; // 150ms
67 static const PRUint32 kNumFontsPerSlice = 10; // read in info 10 fonts at a time
69 #define INDEX_FONT_POSTSCRIPT_NAME 0
70 #define INDEX_FONT_FACE_NAME 1
71 #define INDEX_FONT_WEIGHT 2
72 #define INDEX_FONT_TRAITS 3
74 static const int kAppleMaxWeight = 14;
76 static const int gAppleWeightToCSSWeight[] = {
79 1, // 2. W1, ultralight
80 2, // 3. W2, extralight
82 4, // 5. W4, semilight
87 8, // 10. W8, extrabold
89 9, // 12. W9, ultrabold
95 static void GetStringForNSString(const NSString *aSrc, nsAString& aDist)
97 aDist.SetLength([aSrc length]);
98 [aSrc getCharacters:aDist.BeginWriting()];
101 static NSString* GetNSStringForString(const nsAString& aSrc)
103 return [NSString stringWithCharacters:aSrc.BeginReading()
104 length:aSrc.Length()];
107 static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
110 gfxQuartzFontCache::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
113 ToLowerCase(aResult);
119 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
120 PRInt32 aAppleWeight, PRUint32 aTraits, MacOSFamilyEntry *aFamily)
121 : gfxFontEntry(aPostscriptName), mTraits(aTraits), mFamily(aFamily), mATSUFontID(0),
122 mATSUIDInitialized(0)
124 mWeight = gfxQuartzFontCache::AppleWeightToCSSWeight(aAppleWeight) * 100;
126 mItalic = (mTraits & NSItalicFontMask ? 1 : 0);
127 mFixedPitch = (mTraits & NSFixedPitchFontMask ? 1 : 0);
130 MacOSFontEntry::MacOSFontEntry(ATSUFontID aFontID, PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle, gfxUserFontData *aUserFontData)
132 // xxx - stretch is basically ignored for now
134 mATSUIDInitialized = PR_TRUE;
135 mATSUFontID = aFontID;
136 mUserFontData = aUserFontData;
139 mFixedPitch = PR_FALSE; // xxx - do we need this for downloaded fonts?
140 mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
142 mTraits = (mItalic ? NSItalicFontMask : NSUnitalicFontMask) |
143 (mFixedPitch ? NSFixedPitchFontMask : 0) |
144 (mWeight >= 600 ? NSBoldFontMask : NSUnboldFontMask);
146 // get the postscript name
148 NSString *psname = NULL;
150 // now lookup the Postscript name
151 err = ATSFontGetPostScriptName((ATSFontRef) aFontID, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
153 GetStringForNSString(psname, mName);
159 sprintf(warnBuf, "ATSFontGetPostScriptName err = %d", (PRInt32)err);
166 MacOSFontEntry::FamilyName()
168 return mFamily->Name();
171 ATSUFontID MacOSFontEntry::GetFontID()
173 if (!mATSUIDInitialized) {
174 mATSUIDInitialized = PR_TRUE;
175 NSString *psname = GetNSStringForString(mName);
176 NSFont *font = [NSFont fontWithName:psname size:0.0];
177 if (font) mATSUFontID = [font _atsFontID];
182 // ATSUI requires AAT-enabled fonts to render complex scripts correctly.
183 // For now, simple clear out the cmap codepoints for fonts that have
184 // codepoints for complex scripts. (Bug 361986)
186 enum eComplexScript {
187 eComplexScriptArabic,
189 eComplexScriptTibetan
193 eComplexScript script;
198 const ScriptRange gScriptsThatRequireShaping[] = {
199 { eComplexScriptArabic, 0x0600, 0x077F }, // Basic Arabic and Arabic Supplement
200 { eComplexScriptIndic, 0x0900, 0x0D7F }, // Indic scripts - Devanagari, Bengali, ..., Malayalam
201 { eComplexScriptTibetan, 0x0F00, 0x0FFF } // Tibetan
202 // Thai seems to be "renderable" without AAT morphing tables
207 MacOSFontEntry::ReadCMAP()
210 ByteCount size, cmapSize;
212 if (mCmapInitialized) return NS_OK;
213 ATSUFontID fontID = GetFontID();
215 // attempt this once, if errors occur leave a blank cmap
216 mCmapInitialized = PR_TRUE;
218 status = ATSFontGetTable(fontID, 'cmap', 0, 0, 0, &size);
220 //printf( "cmap size: %s %d", NS_ConvertUTF16toUTF8(mName).get(), size );
222 if (status != noErr) {
224 sprintf(warnBuf, "ATSFontGetTable returned %d for (%s)", (PRInt32)status, NS_ConvertUTF16toUTF8(mName).get());
228 NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
230 nsAutoTArray<PRUint8,16384> buffer;
231 if (!buffer.AppendElements(size))
232 return NS_ERROR_OUT_OF_MEMORY;
233 PRUint8 *cmap = buffer.Elements();
235 status = ATSFontGetTable(fontID, 'cmap', 0, size, cmap, &size);
236 NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
238 nsresult rv = NS_ERROR_FAILURE;
239 PRPackedBool unicodeFont, symbolFont; // currently ignored
240 rv = gfxFontUtils::ReadCMAP(cmap, size, mCharacterMap, unicodeFont, symbolFont);
242 // for complex scripts, check for the presence of mort/morx
243 PRBool checkedForMorphTable = PR_FALSE, hasMorphTable = PR_FALSE;
245 PRUint32 s, numScripts = sizeof(gScriptsThatRequireShaping) / sizeof(ScriptRange);
247 for (s = 0; s < numScripts; s++) {
248 eComplexScript whichScript = gScriptsThatRequireShaping[s].script;
250 // check to see if the cmap includes complex script codepoints
251 if (mCharacterMap.TestRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd)) {
253 // check for mort/morx table, if haven't already
254 if (!checkedForMorphTable) {
255 status = ATSFontGetTable(fontID, 'morx', 0, 0, 0, &size);
256 if (status == noErr) {
257 checkedForMorphTable = PR_TRUE;
258 hasMorphTable = PR_TRUE;
260 // check for a mort table
261 status = ATSFontGetTable(fontID, 'mort', 0, 0, 0, &size);
262 checkedForMorphTable = PR_TRUE;
263 if (status == noErr) {
264 hasMorphTable = PR_TRUE;
269 // rude hack - the Chinese STxxx fonts on 10.4 contain morx tables and Arabic glyphs but
270 // lack the proper info for shaping Arabic, so exclude explicitly, ick
271 if (whichScript == eComplexScriptArabic && hasMorphTable) {
272 if (mName.CharAt(0) == 'S' && mName.CharAt(1) == 'T') {
273 mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd);
277 // general exclusion - if no morph table, exclude codepoints
278 if (!hasMorphTable) {
279 mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd);
284 PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-cmap) psname: %s, size: %d\n",
285 NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
291 /* MacOSFamilyEntry */
294 // helper class for adding other family names back into font cache
295 class AddOtherFamilyNameFunctor
298 AddOtherFamilyNameFunctor(gfxQuartzFontCache *aFontCache) :
299 mFontCache(aFontCache)
302 void operator() (MacOSFamilyEntry *aFamilyEntry, nsAString& aOtherName) {
303 mFontCache->AddOtherFamilyName(aFamilyEntry, aOtherName);
306 gfxQuartzFontCache *mFontCache;
309 void MacOSFamilyEntry::LocalizedName(nsAString& aLocalizedName)
311 // no other names ==> only one name, just return it
312 if (!HasOtherFamilyNames()) {
313 aLocalizedName = mName;
317 NSFontManager *fontManager = [NSFontManager sharedFontManager];
319 // dig out the localized family name
320 NSString *family = GetNSStringForString(mName);
321 NSString *localizedFamily = [fontManager localizedNameForFamily:family face:nil];
323 if (localizedFamily) {
324 GetStringForNSString(localizedFamily, aLocalizedName);
326 // failed to get a localized name, just use the canonical name
327 aLocalizedName = mName;
331 PRBool MacOSFamilyEntry::HasOtherFamilyNames()
333 // need to read in other family names to determine this
334 if (!mOtherFamilyNamesInitialized) {
335 AddOtherFamilyNameFunctor addOtherNames(gfxQuartzFontCache::SharedFontCache());
336 ReadOtherFamilyNames(addOtherNames); // sets mHasOtherFamilyNames
338 return mHasOtherFamilyNames;
341 static const PRUint32 kTraits_NonNormalWidthMask = NSNarrowFontMask | NSExpandedFontMask |
342 NSCondensedFontMask | NSCompressedFontMask | NSFixedPitchFontMask;
345 MacOSFamilyEntry::FindFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
347 return static_cast<MacOSFontEntry*> (FindFontForStyle(*aStyle, aNeedsBold));
351 MacOSFamilyEntry::FindFont(const nsAString& aPostscriptName)
353 // find the font using a simple linear search
354 PRUint32 numFonts = mAvailableFonts.Length();
355 for (PRUint32 i = 0; i < numFonts; i++) {
356 MacOSFontEntry *fe = mAvailableFonts[i];
357 if (fe->Name() == aPostscriptName)
364 MacOSFamilyEntry::FindFontForChar(FontSearch *aMatchData)
366 // xxx - optimization point - keep a bit vector with the union of supported unicode ranges
367 // by all fonts for this family and bail immediately if the character is not in any of
368 // this family's cmaps
370 // iterate over fonts
371 PRUint32 numFonts = mAvailableFonts.Length();
372 for (PRUint32 i = 0; i < numFonts; i++) {
373 MacOSFontEntry *fe = mAvailableFonts[i];
376 if (fe->TestCharacterMap(aMatchData->ch)) {
380 // if we didn't match any characters don't bother wasting more time with this face.
384 // omitting from original windows code -- family name, lang group, pitch
385 // not available in current FontEntry implementation
387 if (aMatchData->fontToMatch) {
388 const gfxFontStyle *style = aMatchData->fontToMatch->GetStyle();
391 if (fe->IsItalic() &&
392 (style->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0) {
397 PRInt8 baseWeight, weightDistance;
398 style->ComputeWeightAndOffset(&baseWeight, &weightDistance);
400 // xxx - not entirely correct, the one unit of weight distance reflects
401 // the "next bolder/lighter face"
402 PRUint32 targetWeight = (baseWeight * 100) + (weightDistance * 100);
404 PRUint32 entryWeight = fe->Weight();
405 if (entryWeight == targetWeight) {
408 PRUint32 diffWeight = abs(entryWeight - targetWeight);
409 if (diffWeight <= 100) // favor faces close in weight
413 // if no font to match, prefer non-bold, non-italic fonts
414 if (!fe->IsItalic() && !fe->IsBold())
418 // xxx - add whether AAT font with morphing info for specific lang groups
420 if (rank > aMatchData->matchRank
421 || (rank == aMatchData->matchRank && Compare(fe->Name(), aMatchData->bestMatch->Name()) > 0))
423 aMatchData->bestMatch = fe;
424 aMatchData->matchRank = rank;
431 MacOSFamilyEntry::FindFontsWithTraits(gfxFontEntry* aFontsForWeights[], PRUint32 aPosTraitsMask,
432 PRUint32 aNegTraitsMask)
434 PRBool found = PR_FALSE;
436 // iterate over fonts
437 PRUint32 numFonts = mAvailableFonts.Length();
438 for (PRUint32 i = 0; i < numFonts; i++) {
439 MacOSFontEntry *fe = mAvailableFonts[i];
441 // if traits match, add to list of fonts
442 PRUint32 traits = fe->Traits();
444 // aPosTraitsMask == 0 ==> match all
445 if ((!aPosTraitsMask || (traits & aPosTraitsMask)) && !(traits & aNegTraitsMask)) {
446 PRInt32 weight = fe->Weight() / 100;
447 NS_ASSERTION(weight >= 1 && weight <= 9, "bogus font weight value!");
449 // always prefer the first font for a given weight, helps deal a bit with
450 // families with lots of faces (e.g. Minion Pro)
451 if (!aFontsForWeights[weight]) {
452 aFontsForWeights[weight] = fe;
461 MacOSFamilyEntry::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontStyle& aFontStyle)
463 // short-circuit the single face per family case
464 if (mAvailableFonts.Length() == 1) {
465 MacOSFontEntry *fe = mAvailableFonts[0];
466 PRUint32 weight = fe->Weight() / 100;
467 NS_ASSERTION(weight >= 1 && weight <= 9, "bogus font weight value!");
468 aFontsForWeights[weight] = fe;
472 PRBool found = PR_FALSE;
473 PRBool isItalic = (aFontStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
475 // match italic faces
477 // first search for italic normal width fonts
478 found = FindFontsWithTraits(aFontsForWeights, NSItalicFontMask, kTraits_NonNormalWidthMask);
480 // if not found, italic any width ones
482 found = FindFontsWithTraits(aFontsForWeights, NSItalicFontMask, 0);
486 // match non-italic faces, if no italic faces fall through here
488 // look for normal width fonts
489 found = FindFontsWithTraits(aFontsForWeights, NSUnitalicFontMask, kTraits_NonNormalWidthMask);
491 // if not found, any face will do
493 found = FindFontsWithTraits(aFontsForWeights, NSUnitalicFontMask, 0);
497 // still not found?!? family must only contain italic fonts when looking for a normal
498 // face, just use the whole list
500 found = FindFontsWithTraits(aFontsForWeights, 0, 0);
502 NS_ASSERTION(found, "Font family containing no faces");
507 static NSString* CreateNameFromBuffer(const UInt8 *aBuf, ByteCount aLength,
508 FontPlatformCode aPlatformCode, FontScriptCode aScriptCode, FontLanguageCode aLangCode)
510 CFStringRef outName = NULL;
512 if (aPlatformCode == kFontMacintoshPlatform) {
513 TextEncoding encoding;
514 OSStatus err = GetTextEncodingFromScriptInfo(aScriptCode, aLangCode,
515 kTextRegionDontCare, &encoding);
517 // some fonts are sloppy about the language code (e.g Arial Hebrew, Corsiva Hebrew)
518 // try again without the lang code to avoid bad combinations
519 OSStatus err = GetTextEncodingFromScriptInfo(aScriptCode, kTextLanguageDontCare,
520 kTextRegionDontCare, &encoding);
523 outName = CFStringCreateWithBytes(kCFAllocatorDefault, aBuf,
524 aLength, (CFStringEncoding) encoding, false);
525 } else if (aPlatformCode == kFontUnicodePlatform) {
526 outName = CFStringCreateWithCharacters(kCFAllocatorDefault, (UniChar*)aBuf, aLength/2);
527 } else if (aPlatformCode == kFontMicrosoftPlatform) {
528 if (aScriptCode == 0) {
529 outName = CFStringCreateWithBytes(kCFAllocatorDefault, aBuf,
530 aLength, kCFStringEncodingUTF16BE, false);
532 outName = CFStringCreateWithCharacters(kCFAllocatorDefault, (UniChar*)aBuf, aLength/2);
536 return (NSString*) outName;
539 // 10.4 headers only define TT/OT name table id's up to the license id (14) but 10.5 does, so use our own enum
541 kMozillaFontPreferredFamilyName = 16,
544 // xxx - rather than use ATSUI calls, probably faster to load name table directly,
545 // this avoids copying around strings that are of no interest
547 // returns true if other names were found, false otherwise
548 static PRBool ReadOtherFamilyNamesForFace(AddOtherFamilyNameFunctor& aOtherFamilyFunctor, MacOSFamilyEntry *aFamilyEntry,
549 NSString *familyName, ATSUFontID fontID, bool useFullName = false)
552 ItemCount i, nameCount;
553 PRBool foundNames = PR_FALSE;
555 if (fontID == kATSUInvalidFontID)
558 err = ATSUCountFontNames(fontID, &nameCount);
562 for (i = 0; i < nameCount; i++) {
564 FontNameCode nameCode;
565 FontPlatformCode platformCode;
566 FontScriptCode scriptCode;
567 FontLanguageCode langCode;
568 const ByteCount kBufLength = 2048;
569 char buf[kBufLength];
572 err = ATSUGetIndFontName(fontID, i, kBufLength, buf, &len, &nameCode, &platformCode, &scriptCode, &langCode);
573 // couldn't find a font name? just continue to the next name table entry
574 if (err == kATSUNoFontNameErr)
576 // any other error, bail
581 if (nameCode != kFontFullName)
584 if (!(nameCode == kFontFamilyName || nameCode == kMozillaFontPreferredFamilyName))
587 if (len >= kBufLength) continue;
590 NSString *name = CreateNameFromBuffer((UInt8*)buf, len, platformCode, scriptCode, langCode);
592 // add if not same as canonical family name or already in list of names
595 if (![name isEqualToString:familyName]) {
596 nsAutoString otherFamilyName;
597 GetStringForNSString(name, otherFamilyName);
598 aOtherFamilyFunctor(aFamilyEntry, otherFamilyName);
599 foundNames = PR_TRUE;
610 MacOSFamilyEntry::ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor)
612 if (mOtherFamilyNamesInitialized)
614 mOtherFamilyNamesInitialized = PR_TRUE;
616 NSString *familyName = GetNSStringForString(mName);
618 // read in other family names for the first face in the list
619 MacOSFontEntry *fe = mAvailableFonts[0];
621 mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aOtherFamilyFunctor, this, familyName, fe->GetFontID());
623 // read in other names for the first face in the list with the assumption
624 // that if extra names don't exist in that face then they don't exist in
625 // other faces for the same font
626 if (mHasOtherFamilyNames) {
627 PRUint32 numFonts, i;
629 // read in names for all faces, needed to catch cases where
630 // fonts all family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
631 numFonts = mAvailableFonts.Length();
632 for (i = 1; i < numFonts; i++) {
633 fe = mAvailableFonts[i];
634 ReadOtherFamilyNamesForFace(aOtherFamilyFunctor, this, familyName, fe->GetFontID());
639 /* SingleFaceFamily */
642 void SingleFaceFamily::LocalizedName(nsAString& aLocalizedName)
644 MacOSFontEntry *fontEntry;
646 // use the display name of the single face
647 fontEntry = mAvailableFonts[0];
651 NSFont *font = [NSFont fontWithName:GetNSStringForString(fontEntry->Name()) size:0.0];
655 NSString *fullname = [font displayName];
657 GetStringForNSString(fullname, aLocalizedName);
661 void SingleFaceFamily::ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor)
663 if (mOtherFamilyNamesInitialized)
665 mOtherFamilyNamesInitialized = PR_TRUE;
667 NSString *familyName = GetNSStringForString(mName);
669 // read in other family names for the first face in the list
670 MacOSFontEntry *fe = mAvailableFonts[0];
672 // read in other names, using the full font names as the family names
673 mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aOtherFamilyFunctor, this, familyName, fe->GetFontID(), true);
676 /* gfxQuartzFontCache */
679 gfxQuartzFontCache *gfxQuartzFontCache::sSharedFontCache = nsnull;
681 gfxQuartzFontCache::gfxQuartzFontCache()
682 : mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
684 mATSGeneration = PRUint32(kATSGenerationInitial);
686 mFontFamilies.Init(100);
687 mOtherFamilyNames.Init(30);
688 mOtherFamilyNamesInitialized = PR_FALSE;
692 ::ATSFontNotificationSubscribe(ATSNotification,
693 kATSFontNotifyOptionDefault,
694 (void*)this, nsnull);
696 // pref changes notification setup
697 nsCOMPtr<nsIPref> pref = do_GetService(NS_PREF_CONTRACTID);
698 pref->RegisterCallback("font.", PrefChangedCallback, this);
699 pref->RegisterCallback("font.name-list.", PrefChangedCallback, this);
700 pref->RegisterCallback("intl.accept_languages", PrefChangedCallback, this); // hmmmm...
704 const PRUint32 kNonNormalTraits = NSItalicFontMask | NSBoldFontMask | NSNarrowFontMask | NSExpandedFontMask | NSCondensedFontMask | NSCompressedFontMask;
707 gfxQuartzFontCache::InitFontList()
709 ATSGeneration currentGeneration = ATSGeneration();
711 // need to ignore notifications after adding each font
712 if (mATSGeneration == currentGeneration)
715 mATSGeneration = currentGeneration;
716 PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) updating to generation: %d", mATSGeneration));
718 mFontFamilies.Clear();
719 mOtherFamilyNames.Clear();
720 mOtherFamilyNamesInitialized = PR_FALSE;
722 mCodepointsWithNoFonts.reset();
725 // iterate over available families
726 NSFontManager *fontManager = [NSFontManager sharedFontManager];
727 NSEnumerator *families = [[fontManager availableFontFamilies] objectEnumerator]; // returns "canonical", non-localized family name
729 nsAutoString availableFamilyName, postscriptFontName;
731 NSString *availableFamily = nil;
732 while ((availableFamily = [families nextObject])) {
735 GetStringForNSString(availableFamily, availableFamilyName);
737 // create a family entry
738 MacOSFamilyEntry *familyEntry = new MacOSFamilyEntry(availableFamilyName);
739 if (!familyEntry) break;
741 // create a font entry for each face
742 NSArray *fontfaces = [fontManager availableMembersOfFontFamily:availableFamily]; // returns an array of [psname, style name, weight, traits] elements, goofy api
743 int faceCount = [fontfaces count];
746 for (faceIndex = 0; faceIndex < faceCount; faceIndex++) {
747 NSArray *face = [fontfaces objectAtIndex:faceIndex];
748 NSString *psname = [face objectAtIndex:INDEX_FONT_POSTSCRIPT_NAME];
749 PRInt32 weight = [[face objectAtIndex:INDEX_FONT_WEIGHT] unsignedIntValue];
750 PRUint32 traits = [[face objectAtIndex:INDEX_FONT_TRAITS] unsignedIntValue];
752 // 10.5 doesn't set NSUnitalicFontMask and NSUnboldFontMask - manually set these for consistency
753 if (!(traits & NSBoldFontMask))
754 traits |= NSUnboldFontMask;
755 if (!(traits & NSItalicFontMask))
756 traits |= NSUnitalicFontMask;
758 PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) family: %s, psname: %s, face: %s, apple-weight: %d, css-weight: %d, traits: %8.8x\n",
759 [availableFamily UTF8String], [psname UTF8String], [[face objectAtIndex:INDEX_FONT_FACE_NAME] UTF8String], weight, gfxQuartzFontCache::AppleWeightToCSSWeight(weight), traits));
762 GetStringForNSString(psname, postscriptFontName);
764 // create a font entry
765 MacOSFontEntry *fontEntry = new MacOSFontEntry(postscriptFontName, weight, traits, familyEntry);
766 if (!fontEntry) break;
768 // insert into font entry array of family
769 familyEntry->AddFontEntry(fontEntry);
772 // add the family entry to the hash table
773 ToLowerCase(availableFamilyName);
774 mFontFamilies.Put(availableFamilyName, familyEntry);
777 InitSingleFaceList();
779 // to avoid full search of font name tables, seed the other names table with localized names from
780 // some of the prefs fonts which are accessed via their localized names. changes in the pref fonts will only cause
781 // a font lookup miss earlier. this is a simple optimization, it's not required for correctness
784 // clean up various minor 10.4 font problems for specific fonts
785 if (gfxPlatformMac::GetPlatform()->OSXVersion() < MAC_OS_X_VERSION_10_5_HEX) {
786 // Cocoa calls report that italic faces exist for Courier and Helvetica,
787 // even though only bold faces exist so test for this using ATSUI id's (10.5 has proper faces)
788 EliminateDuplicateFaces(NS_LITERAL_STRING("Courier"));
789 EliminateDuplicateFaces(NS_LITERAL_STRING("Helvetica"));
791 // Cocoa reports that Courier and Monaco are not fixed-pitch fonts
792 // so explicitly tweak these settings
793 SetFixedPitch(NS_LITERAL_STRING("Courier"));
794 SetFixedPitch(NS_LITERAL_STRING("Monaco"));
797 // initialize ranges of characters for which system-wide font search should be skipped
798 mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
799 mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
801 InitBadUnderlineList();
803 // start the delayed cmap loader
804 StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps);
809 gfxQuartzFontCache::InitOtherFamilyNames()
811 mOtherFamilyNamesInitialized = PR_TRUE;
813 // iterate over all font families and read in other family names
814 mFontFamilies.Enumerate(gfxQuartzFontCache::InitOtherFamilyNamesProc, this);
817 PLDHashOperator PR_CALLBACK gfxQuartzFontCache::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
818 nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
821 gfxQuartzFontCache *fc = (gfxQuartzFontCache*) userArg;
822 AddOtherFamilyNameFunctor addOtherNames(fc);
823 aFamilyEntry->ReadOtherFamilyNames(addOtherNames);
824 return PL_DHASH_NEXT;
828 gfxQuartzFontCache::ReadOtherFamilyNamesForFamily(const nsAString& aFamilyName)
830 MacOSFamilyEntry *familyEntry = FindFamily(aFamilyName);
833 AddOtherFamilyNameFunctor addOtherNames(this);
834 familyEntry->ReadOtherFamilyNames(addOtherNames);
839 gfxQuartzFontCache::InitSingleFaceList()
841 nsAutoTArray<nsString, 10> singleFaceFonts;
842 gfxFontUtils::GetPrefsFontList("font.single-face-list", singleFaceFonts);
844 PRUint32 numFonts = singleFaceFonts.Length();
845 for (PRUint32 i = 0; i < numFonts; i++) {
846 nsAutoString availableFamilyName;
848 // lookup the font using NSFont
849 NSString *faceName = GetNSStringForString(singleFaceFonts[i]);
850 NSFont *font = [NSFont fontWithName:faceName size:0.0];
852 NSString *availableFamily = [font familyName];
853 GetStringForNSString(availableFamily, availableFamilyName);
855 MacOSFamilyEntry *familyEntry = FindFamily(availableFamilyName);
857 MacOSFontEntry *fontEntry = familyEntry->FindFont(singleFaceFonts[i]);
860 nsAutoString displayName, key;
862 // use the display name the canonical name
863 NSString *display = [font displayName];
864 GetStringForNSString(display, displayName);
865 GenerateFontListKey(displayName, key);
867 // add only if doesn't exist already
868 if (!(familyEntry = mFontFamilies.GetWeak(key, &found))) {
869 familyEntry = new SingleFaceFamily(displayName);
870 familyEntry->AddFontEntry(fontEntry);
871 mFontFamilies.Put(key, familyEntry);
872 PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-singleface) family: %s, psname: %s\n", [display UTF8String], [faceName UTF8String]));
874 fontEntry->mFamily = familyEntry;
884 gfxQuartzFontCache::PreloadNamesList()
886 nsAutoTArray<nsString, 10> preloadFonts;
887 gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
889 PRUint32 numFonts = preloadFonts.Length();
890 for (PRUint32 i = 0; i < numFonts; i++) {
893 GenerateFontListKey(preloadFonts[i], key);
895 // only search canonical names!
896 MacOSFamilyEntry *familyEntry = mFontFamilies.GetWeak(key, &found);
898 AddOtherFamilyNameFunctor addOtherNames(this);
899 familyEntry->ReadOtherFamilyNames(addOtherNames);
906 gfxQuartzFontCache::EliminateDuplicateFaces(const nsAString& aFamilyName)
908 MacOSFamilyEntry *family = FindFamily(aFamilyName);
911 nsTArray<nsRefPtr<MacOSFontEntry> >& fontlist = family->GetFontList();
913 PRUint32 i, bold, numFonts, italicIndex;
914 MacOSFontEntry *italic, *nonitalic;
915 PRUint32 boldtraits[2] = { 0, NSBoldFontMask };
917 // if normal and italic have the same ATSUI id, delete italic
918 // if bold and bold-italic have the same ATSUI id, delete bold-italic
920 // two iterations, one for normal, one for bold
921 for (bold = 0; bold < 2; bold++) {
922 numFonts = fontlist.Length();
924 // find the non-italic face
926 for (i = 0; i < numFonts; i++) {
927 PRUint32 traits = fontlist[i]->Traits();
928 if (((traits & NSBoldFontMask) == boldtraits[bold]) && !(traits & NSItalicFontMask)) {
929 nonitalic = fontlist[i];
934 // find the italic face
937 for (i = 0; i < numFonts; i++) {
938 PRUint32 traits = fontlist[i]->Traits();
939 if (((traits & NSBoldFontMask) == boldtraits[bold]) && (traits & NSItalicFontMask)) {
940 italic = fontlist[i];
946 // if italic face and non-italic face have matching ATSUI id's,
947 // the italic face is bogus so remove it
948 if (italic && italic->GetFontID() == nonitalic->GetFontID()) {
949 fontlist.RemoveElementAt(italicIndex);
956 gfxQuartzFontCache::SetFixedPitch(const nsAString& aFamilyName)
958 MacOSFamilyEntry *family = FindFamily(aFamilyName);
961 nsTArray<nsRefPtr<MacOSFontEntry> >& fontlist = family->GetFontList();
963 PRUint32 i, numFonts = fontlist.Length();
965 for (i = 0; i < numFonts; i++) {
966 fontlist[i]->mTraits |= NSFixedPitchFontMask;
967 fontlist[i]->mFixedPitch = 1;
972 gfxQuartzFontCache::InitBadUnderlineList()
974 nsAutoTArray<nsString, 10> blacklist;
975 gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
976 PRUint32 numFonts = blacklist.Length();
977 for (PRUint32 i = 0; i < numFonts; i++) {
980 GenerateFontListKey(blacklist[i], key);
982 MacOSFamilyEntry *familyEntry = mFontFamilies.GetWeak(key, &found);
984 familyEntry->SetBadUnderlineFont(PR_TRUE);
989 gfxQuartzFontCache::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
991 MacOSFamilyEntry *family = FindFamily(aFontName);
993 aResolvedFontName = family->Name();
1000 gfxQuartzFontCache::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
1002 MacOSFamilyEntry *family = FindFamily(aFontName);
1004 family->LocalizedName(aFamilyName);
1008 // Gecko 1.8 used Quickdraw font api's which produce a slightly different set of "family"
1009 // names. Try to resolve based on these names, in case this is stored in an old profile
1010 // 1.8: "Futura", "Futura Condensed" ==> 1.9: "Futura
1013 // convert of a NSString
1014 NSString *fontName = GetNSStringForString(aFontName);
1016 // name ==> family id ==> old-style FMFont
1017 ATSFontFamilyRef fmFontFamily = ATSFontFamilyFindFromName((CFStringRef)fontName, kATSOptionFlagsDefault);
1018 OSStatus err = FMGetFontFromFontFamilyInstance(fmFontFamily, 0, &fmFont, nsnull);
1019 if (err != noErr || fmFont == kInvalidFont)
1022 ATSFontRef atsFont = FMGetATSFontRefFromFont(fmFont);
1028 // now lookup the Postscript name
1029 err = ATSFontGetPostScriptName(atsFont, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
1033 // given an NSFont instance, Cocoa api's return the canonical family name
1034 NSString *canonicalfamily = [[NSFont fontWithName:psname size:0.0] familyName];
1037 nsAutoString familyName;
1039 // lookup again using the canonical family name
1040 GetStringForNSString(canonicalfamily, familyName);
1041 family = FindFamily(familyName);
1043 family->LocalizedName(aFamilyName);
1051 gfxQuartzFontCache::ATSNotification(ATSFontNotificationInfoRef aInfo,
1054 // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
1055 gfxQuartzFontCache *qfc = (gfxQuartzFontCache*)aUserArg;
1056 qfc->UpdateFontList();
1060 gfxQuartzFontCache::PrefChangedCallback(const char *aPrefName, void *closure)
1062 // XXX this could be made to only clear out the cache for the prefs that were changed
1063 // but it probably isn't that big a deal.
1064 gfxQuartzFontCache *qfc = static_cast<gfxQuartzFontCache *>(closure);
1065 qfc->mPrefFonts.Clear();
1070 gfxQuartzFontCache::GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
1072 NSString *defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
1073 nsAutoString familyName;
1075 GetStringForNSString(defaultFamily, familyName);
1076 return FindFontForFamily(familyName, aStyle, aNeedsBold);
1079 struct FontListData {
1080 FontListData(const nsACString& aLangGroup,
1081 const nsACString& aGenericFamily,
1082 nsStringArray& aListOfFonts) :
1083 mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
1084 mListOfFonts(aListOfFonts) {}
1085 const nsACString& mLangGroup;
1086 const nsACString& mGenericFamily;
1087 nsStringArray& mListOfFonts;
1090 PLDHashOperator PR_CALLBACK
1091 gfxQuartzFontCache::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
1092 nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
1095 FontListData *data = (FontListData*)aUserArg;
1097 nsAutoString localizedFamilyName;
1098 aFamilyEntry->LocalizedName(localizedFamilyName);
1099 data->mListOfFonts.AppendString(localizedFamilyName);
1100 return PL_DHASH_NEXT;
1104 gfxQuartzFontCache::GetFontList (const nsACString& aLangGroup,
1105 const nsACString& aGenericFamily,
1106 nsStringArray& aListOfFonts)
1108 FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
1110 mFontFamilies.Enumerate(gfxQuartzFontCache::HashEnumFuncForFamilies, &data);
1112 aListOfFonts.Sort();
1113 aListOfFonts.Compact();
1116 struct FontFamilyListData {
1117 FontFamilyListData(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamilyArray)
1118 : mFamilyArray(aFamilyArray)
1121 static PLDHashOperator PR_CALLBACK AppendFamily(nsStringHashKey::KeyType aKey,
1122 nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
1125 FontFamilyListData *data = (FontFamilyListData*)aUserArg;
1126 data->mFamilyArray.AppendElement(aFamilyEntry);
1127 return PL_DHASH_NEXT;
1130 nsTArray<nsRefPtr<MacOSFamilyEntry> >& mFamilyArray;
1134 gfxQuartzFontCache::GetFontFamilyList(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamilyArray)
1136 FontFamilyListData data(aFamilyArray);
1137 mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
1141 gfxQuartzFontCache::FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont)
1143 // is codepoint with no matching font? return null immediately
1144 if (mCodepointsWithNoFonts.test(aCh)) {
1148 // short-circuit system font fallback for U+FFFD, used to represent encoding errors
1149 // just use Lucida Grande (system font, guaranteed to be around)
1150 // this helps speed up pages with lots of encoding errors, binary-as-text, etc.
1151 if (aCh == 0xFFFD) {
1152 MacOSFontEntry* fontEntry;
1153 PRBool needsBold; // ignored in the system fallback case
1156 fontEntry = FindFontForFamily(NS_LITERAL_STRING("Lucida Grande"), aPrevFont->GetStyle(), needsBold);
1158 gfxFontStyle normalStyle;
1159 fontEntry = FindFontForFamily(NS_LITERAL_STRING("Lucida Grande"), &normalStyle, needsBold);
1162 if (fontEntry && fontEntry->TestCharacterMap(aCh))
1166 FontSearch data(aCh, aPrevFont);
1168 // iterate over all font families to find a font that support the character
1169 mFontFamilies.Enumerate(gfxQuartzFontCache::FindFontForCharProc, &data);
1171 // no match? add to set of non-matching codepoints
1172 if (!data.bestMatch) {
1173 mCodepointsWithNoFonts.set(aCh);
1176 return data.bestMatch;
1179 PLDHashOperator PR_CALLBACK
1180 gfxQuartzFontCache::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
1183 FontSearch *data = (FontSearch*)userArg;
1185 // evaluate all fonts in this family for a match
1186 aFamilyEntry->FindFontForChar(data);
1187 return PL_DHASH_NEXT;
1191 gfxQuartzFontCache::FindFamily(const nsAString& aFamily)
1194 MacOSFamilyEntry *familyEntry;
1196 GenerateFontListKey(aFamily, key);
1198 // lookup in canonical (i.e. English) family name list
1199 if ((familyEntry = mFontFamilies.GetWeak(key, &found))) {
1203 // lookup in other family names list (mostly localized names)
1204 if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found))) {
1208 // name not found and other family names not yet fully initialized so
1209 // initialize the rest of the list and try again. this is done lazily
1210 // since reading name table entries is expensive
1211 if (!mOtherFamilyNamesInitialized) {
1212 InitOtherFamilyNames();
1213 if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found))) {
1222 gfxQuartzFontCache::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, PRBool& aNeedsBold)
1224 MacOSFamilyEntry *familyEntry = FindFamily(aFamily);
1226 aNeedsBold = PR_FALSE;
1229 return familyEntry->FindFont(aStyle, aNeedsBold);
1235 gfxQuartzFontCache::AppleWeightToCSSWeight(PRInt32 aAppleWeight)
1237 if (aAppleWeight < 1)
1239 else if (aAppleWeight > kAppleMaxWeight)
1240 aAppleWeight = kAppleMaxWeight;
1241 return gAppleWeightToCSSWeight[aAppleWeight];
1245 gfxQuartzFontCache::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> > *array)
1247 return mPrefFonts.Get(PRUint32(aLangGroup), array);
1251 gfxQuartzFontCache::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> >& array)
1253 mPrefFonts.Put(PRUint32(aLangGroup), array);
1257 gfxQuartzFontCache::AddOtherFamilyName(MacOSFamilyEntry *aFamilyEntry, nsAString& aOtherFamilyName)
1261 GenerateFontListKey(aOtherFamilyName, key);
1263 if (!mOtherFamilyNames.GetWeak(key, &found)) {
1264 mOtherFamilyNames.Put(key, aFamilyEntry);
1265 PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-otherfamily) canonical family: %s, other family: %s\n",
1266 NS_ConvertUTF16toUTF8(aFamilyEntry->Name()).get(),
1267 NS_ConvertUTF16toUTF8(aOtherFamilyName).get()));
1272 gfxQuartzFontCache::LookupLocalFont(const nsAString& aFontName)
1274 NSString *faceName = GetNSStringForString(aFontName);
1275 NSFont *font = [NSFont fontWithName:faceName size:0.0];
1278 nsAutoString availableFamilyName;
1279 NSString *availableFamily = [font familyName];
1280 GetStringForNSString(availableFamily, availableFamilyName);
1282 MacOSFamilyEntry *familyEntry = FindFamily(availableFamilyName);
1284 MacOSFontEntry *fontEntry = familyEntry->FindFont(aFontName);
1289 // didn't find the font
1293 // grumble, another non-publised Apple API dependency (found in Webkit code)
1294 // activated with this value, font will not be found via system lookup routines
1295 // it can only be used via the created ATSUFontID
1296 // needed to prevent one doc from finding a font used in a separate doc
1299 kPrivateATSFontContextPrivate = 3
1302 class MacOSUserFontData : public gfxUserFontData {
1304 MacOSUserFontData(ATSFontContainerRef aContainerRef)
1305 : mContainerRef(aContainerRef)
1308 virtual ~MacOSUserFontData()
1312 ATSFontDeactivate(mContainerRef, NULL, kATSOptionFlagsDefault);
1315 ATSFontContainerRef mContainerRef;
1319 gfxQuartzFontCache::MakePlatformFont(const gfxFontEntry *aProxyEntry,
1320 const PRUint8 *aFontData, PRUint32 aLength)
1324 NS_ASSERTION(aFontData && aLength != 0,
1325 "MakePlatformFont called with null data ptr");
1327 // do simple validation check on font data before
1328 // attempting to activate it
1329 if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength)) {
1332 const gfxProxyFontEntry *proxyEntry =
1333 static_cast<const gfxProxyFontEntry*> (aProxyEntry);
1334 sprintf(warnBuf, "downloaded font error, invalid font data for (%s)",
1335 NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
1336 NS_WARNING(warnBuf);
1342 ATSFontContainerRef containerRef;
1344 err = ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength,
1345 kPrivateATSFontContextPrivate,
1346 kATSFontFormatUnspecified,
1348 kATSOptionFlagsDoNotNotify,
1354 const gfxProxyFontEntry *proxyEntry =
1355 static_cast<const gfxProxyFontEntry*> (aProxyEntry);
1356 sprintf(warnBuf, "downloaded font error, ATSFontActivateFromMemory err: %d for (%s)",
1358 NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
1359 NS_WARNING(warnBuf);
1364 mATSGeneration = ATSGeneration();
1366 // ignoring containers with multiple fonts, use the first face only for now
1367 err = ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1,
1368 (ATSFontRef*)&fontID, NULL);
1372 const gfxProxyFontEntry *proxyEntry =
1373 static_cast<const gfxProxyFontEntry*> (aProxyEntry);
1374 sprintf(warnBuf, "downloaded font error, ATSFontFindFromContainer err: %d for (%s)",
1376 NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
1377 NS_WARNING(warnBuf);
1379 ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
1383 // font entry will own this
1384 MacOSUserFontData *userFontData = new MacOSUserFontData(containerRef);
1386 if (!userFontData) {
1387 ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
1391 PRUint16 w = aProxyEntry->mWeight;
1392 NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
1394 MacOSFontEntry *newFontEntry =
1395 new MacOSFontEntry(fontID, w, aProxyEntry->mStretch,
1396 (PRUint32(aProxyEntry->mItalic) ?
1401 if (!newFontEntry) {
1402 delete userFontData;
1406 // if something is funky about this font, delete immediately
1407 if (newFontEntry && !newFontEntry->mIsValid) {
1410 const gfxProxyFontEntry *proxyEntry =
1411 static_cast<const gfxProxyFontEntry*> (aProxyEntry);
1412 sprintf(warnBuf, "downloaded font not loaded properly, removed face for (%s)",
1413 NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
1414 NS_WARNING(warnBuf);
1416 delete newFontEntry;
1420 return newFontEntry;
1425 gfxQuartzFontCache::InitLoader()
1427 GetFontFamilyList(mFontFamiliesToLoad);
1429 mNumFamilies = mFontFamiliesToLoad.Length();
1433 gfxQuartzFontCache::RunLoader()
1435 PRUint32 i, endIndex = (mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies);
1437 // for each font family, load in various font info
1438 for (i = mStartIndex; i < endIndex; i++) {
1439 AddOtherFamilyNameFunctor addOtherNames(this);
1442 mFontFamiliesToLoad[i]->ReadCMAP();
1444 // read in other family names
1445 mFontFamiliesToLoad[i]->ReadOtherFamilyNames(addOtherNames);
1448 mStartIndex += mIncrement;
1449 if (mStartIndex < mNumFamilies)
1455 gfxQuartzFontCache::FinishLoader()
1457 mFontFamiliesToLoad.Clear();