1 /* -*- Mode: ObjC; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * ***** BEGIN LICENSE BLOCK *****
5 * Copyright (C) 2006-2008 Mozilla Corporation. All rights reserved.
8 * Vladimir Vukicevic <vladimir@pobox.com>
9 * Masayuki Nakano <masayuki@d-toybox.com>
10 * John Daggett <jdaggett@mozilla.com>
11 * Jonathan Kew <jfkthame@gmail.com>
13 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
25 * its contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
29 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * ***** END LICENSE BLOCK ***** */
43 #import <AppKit/AppKit.h>
45 #include "gfxPlatformMac.h"
46 #include "gfxQuartzFontCache.h"
47 #include "gfxAtsuiFonts.h"
48 #include "gfxUserFontSet.h"
50 #include "nsIPref.h" // for pref changes callback notification
51 #include "nsServiceManagerUtils.h"
53 #include "nsDirectoryServiceUtils.h"
54 #include "nsDirectoryServiceDefs.h"
55 #include "nsISimpleEnumerator.h"
60 // _atsFontID is private; add it in our new category to NSFont
61 @interface NSFont (MozillaCategory)
62 - (ATSUFontID)_atsFontID;
65 // font info loader constants
66 static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
67 static const PRUint32 kIntervalBetweenLoadingCmaps = 150; // 150ms
68 static const PRUint32 kNumFontsPerSlice = 10; // read in info 10 fonts at a time
70 #define INDEX_FONT_POSTSCRIPT_NAME 0
71 #define INDEX_FONT_FACE_NAME 1
72 #define INDEX_FONT_WEIGHT 2
73 #define INDEX_FONT_TRAITS 3
75 static const int kAppleMaxWeight = 14;
77 static const int gAppleWeightToCSSWeight[] = {
80 1, // 2. W1, ultralight
81 2, // 3. W2, extralight
83 4, // 5. W4, semilight
88 8, // 10. W8, extrabold
90 9, // 12. W9, ultrabold
96 static void GetStringForNSString(const NSString *aSrc, nsAString& aDist)
98 aDist.SetLength([aSrc length]);
99 [aSrc getCharacters:aDist.BeginWriting()];
102 static NSString* GetNSStringForString(const nsAString& aSrc)
104 return [NSString stringWithCharacters:aSrc.BeginReading()
105 length:aSrc.Length()];
108 static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
111 gfxQuartzFontCache::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
114 ToLowerCase(aResult);
120 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
121 PRInt32 aAppleWeight, PRUint32 aTraits, MacOSFamilyEntry *aFamily)
122 : gfxFontEntry(aPostscriptName), mTraits(aTraits), mFamily(aFamily), mATSUFontID(0),
123 mATSUIDInitialized(0)
125 mWeight = gfxQuartzFontCache::AppleWeightToCSSWeight(aAppleWeight) * 100;
127 mItalic = (mTraits & NSItalicFontMask ? 1 : 0);
128 mFixedPitch = (mTraits & NSFixedPitchFontMask ? 1 : 0);
131 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, ATSUFontID aFontID,
132 PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle,
133 gfxUserFontData *aUserFontData)
135 // xxx - stretch is basically ignored for now
137 mATSUIDInitialized = PR_TRUE;
138 mATSUFontID = aFontID;
139 mUserFontData = aUserFontData;
142 mFixedPitch = PR_FALSE; // xxx - do we need this for downloaded fonts?
143 mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
145 mTraits = (mItalic ? NSItalicFontMask : NSUnitalicFontMask) |
146 (mFixedPitch ? NSFixedPitchFontMask : 0) |
147 (mWeight >= 600 ? NSBoldFontMask : NSUnboldFontMask);
149 mName = aPostscriptName;
153 MacOSFontEntry::FamilyName()
155 return mFamily->Name();
158 ATSUFontID MacOSFontEntry::GetFontID()
160 if (!mATSUIDInitialized) {
161 mATSUIDInitialized = PR_TRUE;
162 NSString *psname = GetNSStringForString(mName);
163 NSFont *font = [NSFont fontWithName:psname size:0.0];
164 if (font) mATSUFontID = [font _atsFontID];
169 // ATSUI requires AAT-enabled fonts to render complex scripts correctly.
170 // For now, simple clear out the cmap codepoints for fonts that have
171 // codepoints for complex scripts. (Bug 361986)
173 enum eComplexScript {
174 eComplexScriptArabic,
176 eComplexScriptTibetan
180 eComplexScript script;
185 const ScriptRange gScriptsThatRequireShaping[] = {
186 { eComplexScriptArabic, 0x0600, 0x077F }, // Basic Arabic and Arabic Supplement
187 { eComplexScriptIndic, 0x0900, 0x0D7F }, // Indic scripts - Devanagari, Bengali, ..., Malayalam
188 { eComplexScriptTibetan, 0x0F00, 0x0FFF } // Tibetan
189 // Thai seems to be "renderable" without AAT morphing tables
194 MacOSFontEntry::ReadCMAP()
197 ByteCount size, cmapSize;
199 if (mCmapInitialized) return NS_OK;
200 ATSUFontID fontID = GetFontID();
202 // attempt this once, if errors occur leave a blank cmap
203 mCmapInitialized = PR_TRUE;
205 status = ATSFontGetTable(fontID, 'cmap', 0, 0, 0, &size);
207 //printf( "cmap size: %s %d", NS_ConvertUTF16toUTF8(mName).get(), size );
209 if (status != noErr) {
211 sprintf(warnBuf, "ATSFontGetTable returned %d for (%s)", (PRInt32)status, NS_ConvertUTF16toUTF8(mName).get());
215 NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
217 nsAutoTArray<PRUint8,16384> buffer;
218 if (!buffer.AppendElements(size))
219 return NS_ERROR_OUT_OF_MEMORY;
220 PRUint8 *cmap = buffer.Elements();
222 status = ATSFontGetTable(fontID, 'cmap', 0, size, cmap, &size);
223 NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
225 nsresult rv = NS_ERROR_FAILURE;
226 PRPackedBool unicodeFont, symbolFont; // currently ignored
227 rv = gfxFontUtils::ReadCMAP(cmap, size, mCharacterMap, unicodeFont, symbolFont);
229 // for complex scripts, check for the presence of mort/morx
230 PRBool checkedForMorphTable = PR_FALSE, hasMorphTable = PR_FALSE;
232 PRUint32 s, numScripts = sizeof(gScriptsThatRequireShaping) / sizeof(ScriptRange);
234 for (s = 0; s < numScripts; s++) {
235 eComplexScript whichScript = gScriptsThatRequireShaping[s].script;
237 // check to see if the cmap includes complex script codepoints
238 if (mCharacterMap.TestRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd)) {
240 // check for mort/morx table, if haven't already
241 if (!checkedForMorphTable) {
242 status = ATSFontGetTable(fontID, 'morx', 0, 0, 0, &size);
243 if (status == noErr) {
244 checkedForMorphTable = PR_TRUE;
245 hasMorphTable = PR_TRUE;
247 // check for a mort table
248 status = ATSFontGetTable(fontID, 'mort', 0, 0, 0, &size);
249 checkedForMorphTable = PR_TRUE;
250 if (status == noErr) {
251 hasMorphTable = PR_TRUE;
256 // rude hack - the Chinese STxxx fonts on 10.4 contain morx tables and Arabic glyphs but
257 // lack the proper info for shaping Arabic, so exclude explicitly, ick
258 if (whichScript == eComplexScriptArabic && hasMorphTable) {
259 if (mName.CharAt(0) == 'S' && mName.CharAt(1) == 'T') {
260 mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd);
264 // general exclusion - if no morph table, exclude codepoints
265 if (!hasMorphTable) {
266 mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart, gScriptsThatRequireShaping[s].rangeEnd);
271 PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-cmap) psname: %s, size: %d\n",
272 NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
278 /* MacOSFamilyEntry */
281 // helper class for adding other family names back into font cache
282 class AddOtherFamilyNameFunctor
285 AddOtherFamilyNameFunctor(gfxQuartzFontCache *aFontCache) :
286 mFontCache(aFontCache)
289 void operator() (MacOSFamilyEntry *aFamilyEntry, nsAString& aOtherName) {
290 mFontCache->AddOtherFamilyName(aFamilyEntry, aOtherName);
293 gfxQuartzFontCache *mFontCache;
296 void MacOSFamilyEntry::LocalizedName(nsAString& aLocalizedName)
298 // no other names ==> only one name, just return it
299 if (!HasOtherFamilyNames()) {
300 aLocalizedName = mName;
304 NSFontManager *fontManager = [NSFontManager sharedFontManager];
306 // dig out the localized family name
307 NSString *family = GetNSStringForString(mName);
308 NSString *localizedFamily = [fontManager localizedNameForFamily:family face:nil];
310 if (localizedFamily) {
311 GetStringForNSString(localizedFamily, aLocalizedName);
313 // failed to get a localized name, just use the canonical name
314 aLocalizedName = mName;
318 PRBool MacOSFamilyEntry::HasOtherFamilyNames()
320 // need to read in other family names to determine this
321 if (!mOtherFamilyNamesInitialized) {
322 AddOtherFamilyNameFunctor addOtherNames(gfxQuartzFontCache::SharedFontCache());
323 ReadOtherFamilyNames(addOtherNames); // sets mHasOtherFamilyNames
325 return mHasOtherFamilyNames;
328 static const PRUint32 kTraits_NonNormalWidthMask = NSNarrowFontMask | NSExpandedFontMask |
329 NSCondensedFontMask | NSCompressedFontMask | NSFixedPitchFontMask;
332 MacOSFamilyEntry::FindFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
334 return static_cast<MacOSFontEntry*> (FindFontForStyle(*aStyle, aNeedsBold));
338 MacOSFamilyEntry::FindFont(const nsAString& aPostscriptName)
340 // find the font using a simple linear search
341 PRUint32 numFonts = mAvailableFonts.Length();
342 for (PRUint32 i = 0; i < numFonts; i++) {
343 MacOSFontEntry *fe = mAvailableFonts[i];
344 if (fe->Name() == aPostscriptName)
351 MacOSFamilyEntry::FindFontForChar(FontSearch *aMatchData)
353 // xxx - optimization point - keep a bit vector with the union of supported unicode ranges
354 // by all fonts for this family and bail immediately if the character is not in any of
355 // this family's cmaps
357 // iterate over fonts
358 PRUint32 numFonts = mAvailableFonts.Length();
359 for (PRUint32 i = 0; i < numFonts; i++) {
360 MacOSFontEntry *fe = mAvailableFonts[i];
363 if (fe->TestCharacterMap(aMatchData->ch)) {
367 // if we didn't match any characters don't bother wasting more time with this face.
371 // omitting from original windows code -- family name, lang group, pitch
372 // not available in current FontEntry implementation
374 if (aMatchData->fontToMatch) {
375 const gfxFontStyle *style = aMatchData->fontToMatch->GetStyle();
378 if (fe->IsItalic() &&
379 (style->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0) {
384 PRInt8 baseWeight, weightDistance;
385 style->ComputeWeightAndOffset(&baseWeight, &weightDistance);
387 // xxx - not entirely correct, the one unit of weight distance reflects
388 // the "next bolder/lighter face"
389 PRUint32 targetWeight = (baseWeight * 100) + (weightDistance * 100);
391 PRUint32 entryWeight = fe->Weight();
392 if (entryWeight == targetWeight) {
395 PRUint32 diffWeight = abs(entryWeight - targetWeight);
396 if (diffWeight <= 100) // favor faces close in weight
400 // if no font to match, prefer non-bold, non-italic fonts
401 if (!fe->IsItalic() && !fe->IsBold())
405 // xxx - add whether AAT font with morphing info for specific lang groups
407 if (rank > aMatchData->matchRank
408 || (rank == aMatchData->matchRank && Compare(fe->Name(), aMatchData->bestMatch->Name()) > 0))
410 aMatchData->bestMatch = fe;
411 aMatchData->matchRank = rank;
418 MacOSFamilyEntry::FindFontsWithTraits(gfxFontEntry* aFontsForWeights[], PRUint32 aPosTraitsMask,
419 PRUint32 aNegTraitsMask)
421 PRBool found = PR_FALSE;
423 // iterate over fonts
424 PRUint32 numFonts = mAvailableFonts.Length();
425 for (PRUint32 i = 0; i < numFonts; i++) {
426 MacOSFontEntry *fe = mAvailableFonts[i];
428 // if traits match, add to list of fonts
429 PRUint32 traits = fe->Traits();
431 // aPosTraitsMask == 0 ==> match all
432 if ((!aPosTraitsMask || (traits & aPosTraitsMask)) && !(traits & aNegTraitsMask)) {
433 PRInt32 weight = fe->Weight() / 100;
434 NS_ASSERTION(weight >= 1 && weight <= 9, "bogus font weight value!");
436 // always prefer the first font for a given weight, helps deal a bit with
437 // families with lots of faces (e.g. Minion Pro)
438 if (!aFontsForWeights[weight]) {
439 aFontsForWeights[weight] = fe;
448 MacOSFamilyEntry::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontStyle& aFontStyle)
450 // short-circuit the single face per family case
451 if (mAvailableFonts.Length() == 1) {
452 MacOSFontEntry *fe = mAvailableFonts[0];
453 PRUint32 weight = fe->Weight() / 100;
454 NS_ASSERTION(weight >= 1 && weight <= 9, "bogus font weight value!");
455 aFontsForWeights[weight] = fe;
459 PRBool found = PR_FALSE;
460 PRBool isItalic = (aFontStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
462 // match italic faces
464 // first search for italic normal width fonts
465 found = FindFontsWithTraits(aFontsForWeights, NSItalicFontMask, kTraits_NonNormalWidthMask);
467 // if not found, italic any width ones
469 found = FindFontsWithTraits(aFontsForWeights, NSItalicFontMask, 0);
473 // match non-italic faces, if no italic faces fall through here
475 // look for normal width fonts
476 found = FindFontsWithTraits(aFontsForWeights, NSUnitalicFontMask, kTraits_NonNormalWidthMask);
478 // if not found, any face will do
480 found = FindFontsWithTraits(aFontsForWeights, NSUnitalicFontMask, 0);
484 // still not found?!? family must only contain italic fonts when looking for a normal
485 // face, just use the whole list
487 found = FindFontsWithTraits(aFontsForWeights, 0, 0);
489 NS_ASSERTION(found, "Font family containing no faces");
494 static NSString* CreateNameFromBuffer(const UInt8 *aBuf, ByteCount aLength,
495 FontPlatformCode aPlatformCode, FontScriptCode aScriptCode, FontLanguageCode aLangCode)
497 CFStringRef outName = NULL;
499 if (aPlatformCode == kFontMacintoshPlatform) {
500 TextEncoding encoding;
501 OSStatus err = GetTextEncodingFromScriptInfo(aScriptCode, aLangCode,
502 kTextRegionDontCare, &encoding);
504 // some fonts are sloppy about the language code (e.g Arial Hebrew, Corsiva Hebrew)
505 // try again without the lang code to avoid bad combinations
506 OSStatus err = GetTextEncodingFromScriptInfo(aScriptCode, kTextLanguageDontCare,
507 kTextRegionDontCare, &encoding);
510 outName = CFStringCreateWithBytes(kCFAllocatorDefault, aBuf,
511 aLength, (CFStringEncoding) encoding, false);
512 } else if (aPlatformCode == kFontUnicodePlatform) {
513 outName = CFStringCreateWithCharacters(kCFAllocatorDefault, (UniChar*)aBuf, aLength/2);
514 } else if (aPlatformCode == kFontMicrosoftPlatform) {
515 if (aScriptCode == 0) {
516 outName = CFStringCreateWithBytes(kCFAllocatorDefault, aBuf,
517 aLength, kCFStringEncodingUTF16BE, false);
519 outName = CFStringCreateWithCharacters(kCFAllocatorDefault, (UniChar*)aBuf, aLength/2);
523 return (NSString*) outName;
526 // 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
528 kMozillaFontPreferredFamilyName = 16,
531 // xxx - rather than use ATSUI calls, probably faster to load name table directly,
532 // this avoids copying around strings that are of no interest
534 // returns true if other names were found, false otherwise
535 static PRBool ReadOtherFamilyNamesForFace(AddOtherFamilyNameFunctor& aOtherFamilyFunctor, MacOSFamilyEntry *aFamilyEntry,
536 NSString *familyName, ATSUFontID fontID, bool useFullName = false)
539 ItemCount i, nameCount;
540 PRBool foundNames = PR_FALSE;
542 if (fontID == kATSUInvalidFontID)
545 err = ATSUCountFontNames(fontID, &nameCount);
549 for (i = 0; i < nameCount; i++) {
551 FontNameCode nameCode;
552 FontPlatformCode platformCode;
553 FontScriptCode scriptCode;
554 FontLanguageCode langCode;
555 const ByteCount kBufLength = 2048;
556 char buf[kBufLength];
559 err = ATSUGetIndFontName(fontID, i, kBufLength, buf, &len, &nameCode, &platformCode, &scriptCode, &langCode);
560 // couldn't find a font name? just continue to the next name table entry
561 if (err == kATSUNoFontNameErr)
563 // any other error, bail
568 if (nameCode != kFontFullName)
571 if (!(nameCode == kFontFamilyName || nameCode == kMozillaFontPreferredFamilyName))
574 if (len >= kBufLength) continue;
577 NSString *name = CreateNameFromBuffer((UInt8*)buf, len, platformCode, scriptCode, langCode);
579 // add if not same as canonical family name or already in list of names
582 if (![name isEqualToString:familyName]) {
583 nsAutoString otherFamilyName;
584 GetStringForNSString(name, otherFamilyName);
585 aOtherFamilyFunctor(aFamilyEntry, otherFamilyName);
586 foundNames = PR_TRUE;
597 MacOSFamilyEntry::ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor)
599 if (mOtherFamilyNamesInitialized)
601 mOtherFamilyNamesInitialized = PR_TRUE;
603 NSString *familyName = GetNSStringForString(mName);
605 // read in other family names for the first face in the list
606 MacOSFontEntry *fe = mAvailableFonts[0];
608 mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aOtherFamilyFunctor, this, familyName, fe->GetFontID());
610 // read in other names for the first face in the list with the assumption
611 // that if extra names don't exist in that face then they don't exist in
612 // other faces for the same font
613 if (mHasOtherFamilyNames) {
614 PRUint32 numFonts, i;
616 // read in names for all faces, needed to catch cases where
617 // fonts all family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
618 numFonts = mAvailableFonts.Length();
619 for (i = 1; i < numFonts; i++) {
620 fe = mAvailableFonts[i];
621 ReadOtherFamilyNamesForFace(aOtherFamilyFunctor, this, familyName, fe->GetFontID());
626 /* SingleFaceFamily */
629 void SingleFaceFamily::LocalizedName(nsAString& aLocalizedName)
631 MacOSFontEntry *fontEntry;
633 // use the display name of the single face
634 fontEntry = mAvailableFonts[0];
638 NSFont *font = [NSFont fontWithName:GetNSStringForString(fontEntry->Name()) size:0.0];
642 NSString *fullname = [font displayName];
644 GetStringForNSString(fullname, aLocalizedName);
648 void SingleFaceFamily::ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor)
650 if (mOtherFamilyNamesInitialized)
652 mOtherFamilyNamesInitialized = PR_TRUE;
654 NSString *familyName = GetNSStringForString(mName);
656 // read in other family names for the first face in the list
657 MacOSFontEntry *fe = mAvailableFonts[0];
659 // read in other names, using the full font names as the family names
660 mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aOtherFamilyFunctor, this, familyName, fe->GetFontID(), true);
663 /* gfxQuartzFontCache */
666 gfxQuartzFontCache *gfxQuartzFontCache::sSharedFontCache = nsnull;
668 gfxQuartzFontCache::gfxQuartzFontCache()
669 : mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
671 mATSGeneration = PRUint32(kATSGenerationInitial);
673 mFontFamilies.Init(100);
674 mOtherFamilyNames.Init(30);
675 mOtherFamilyNamesInitialized = PR_FALSE;
679 ::ATSFontNotificationSubscribe(ATSNotification,
680 kATSFontNotifyOptionDefault,
681 (void*)this, nsnull);
683 // pref changes notification setup
684 nsCOMPtr<nsIPref> pref = do_GetService(NS_PREF_CONTRACTID);
685 pref->RegisterCallback("font.", PrefChangedCallback, this);
686 pref->RegisterCallback("font.name-list.", PrefChangedCallback, this);
687 pref->RegisterCallback("intl.accept_languages", PrefChangedCallback, this); // hmmmm...
691 const PRUint32 kNonNormalTraits = NSItalicFontMask | NSBoldFontMask | NSNarrowFontMask | NSExpandedFontMask | NSCondensedFontMask | NSCompressedFontMask;
694 gfxQuartzFontCache::InitFontList()
696 ATSGeneration currentGeneration = ATSGetGeneration();
698 // need to ignore notifications after adding each font
699 if (mATSGeneration == currentGeneration)
702 mATSGeneration = currentGeneration;
703 PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) updating to generation: %d", mATSGeneration));
705 mFontFamilies.Clear();
706 mOtherFamilyNames.Clear();
707 mOtherFamilyNamesInitialized = PR_FALSE;
709 mCodepointsWithNoFonts.reset();
712 // iterate over available families
713 NSFontManager *fontManager = [NSFontManager sharedFontManager];
714 NSEnumerator *families = [[fontManager availableFontFamilies] objectEnumerator]; // returns "canonical", non-localized family name
716 nsAutoString availableFamilyName, postscriptFontName;
718 NSString *availableFamily = nil;
719 while ((availableFamily = [families nextObject])) {
722 GetStringForNSString(availableFamily, availableFamilyName);
724 // create a family entry
725 MacOSFamilyEntry *familyEntry = new MacOSFamilyEntry(availableFamilyName);
726 if (!familyEntry) break;
728 // create a font entry for each face
729 NSArray *fontfaces = [fontManager availableMembersOfFontFamily:availableFamily]; // returns an array of [psname, style name, weight, traits] elements, goofy api
730 int faceCount = [fontfaces count];
733 for (faceIndex = 0; faceIndex < faceCount; faceIndex++) {
734 NSArray *face = [fontfaces objectAtIndex:faceIndex];
735 NSString *psname = [face objectAtIndex:INDEX_FONT_POSTSCRIPT_NAME];
736 PRInt32 weight = [[face objectAtIndex:INDEX_FONT_WEIGHT] unsignedIntValue];
737 PRUint32 traits = [[face objectAtIndex:INDEX_FONT_TRAITS] unsignedIntValue];
739 // 10.5 doesn't set NSUnitalicFontMask and NSUnboldFontMask - manually set these for consistency
740 if (!(traits & NSBoldFontMask))
741 traits |= NSUnboldFontMask;
742 if (!(traits & NSItalicFontMask))
743 traits |= NSUnitalicFontMask;
745 PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) family: %s, psname: %s, face: %s, apple-weight: %d, css-weight: %d, traits: %8.8x\n",
746 [availableFamily UTF8String], [psname UTF8String], [[face objectAtIndex:INDEX_FONT_FACE_NAME] UTF8String], weight, gfxQuartzFontCache::AppleWeightToCSSWeight(weight), traits));
749 GetStringForNSString(psname, postscriptFontName);
751 // create a font entry
752 MacOSFontEntry *fontEntry = new MacOSFontEntry(postscriptFontName, weight, traits, familyEntry);
753 if (!fontEntry) break;
755 // insert into font entry array of family
756 familyEntry->AddFontEntry(fontEntry);
759 // add the family entry to the hash table
760 ToLowerCase(availableFamilyName);
761 mFontFamilies.Put(availableFamilyName, familyEntry);
764 InitSingleFaceList();
766 // to avoid full search of font name tables, seed the other names table with localized names from
767 // some of the prefs fonts which are accessed via their localized names. changes in the pref fonts will only cause
768 // a font lookup miss earlier. this is a simple optimization, it's not required for correctness
771 // clean up various minor 10.4 font problems for specific fonts
772 if (gfxPlatformMac::GetPlatform()->OSXVersion() < MAC_OS_X_VERSION_10_5_HEX) {
773 // Cocoa calls report that italic faces exist for Courier and Helvetica,
774 // even though only bold faces exist so test for this using ATSUI id's (10.5 has proper faces)
775 EliminateDuplicateFaces(NS_LITERAL_STRING("Courier"));
776 EliminateDuplicateFaces(NS_LITERAL_STRING("Helvetica"));
778 // Cocoa reports that Courier and Monaco are not fixed-pitch fonts
779 // so explicitly tweak these settings
780 SetFixedPitch(NS_LITERAL_STRING("Courier"));
781 SetFixedPitch(NS_LITERAL_STRING("Monaco"));
784 // initialize ranges of characters for which system-wide font search should be skipped
785 mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
786 mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
788 InitBadUnderlineList();
790 // start the delayed cmap loader
791 StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps);
796 gfxQuartzFontCache::InitOtherFamilyNames()
798 mOtherFamilyNamesInitialized = PR_TRUE;
800 // iterate over all font families and read in other family names
801 mFontFamilies.Enumerate(gfxQuartzFontCache::InitOtherFamilyNamesProc, this);
804 PLDHashOperator PR_CALLBACK gfxQuartzFontCache::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
805 nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
808 gfxQuartzFontCache *fc = (gfxQuartzFontCache*) userArg;
809 AddOtherFamilyNameFunctor addOtherNames(fc);
810 aFamilyEntry->ReadOtherFamilyNames(addOtherNames);
811 return PL_DHASH_NEXT;
815 gfxQuartzFontCache::ReadOtherFamilyNamesForFamily(const nsAString& aFamilyName)
817 MacOSFamilyEntry *familyEntry = FindFamily(aFamilyName);
820 AddOtherFamilyNameFunctor addOtherNames(this);
821 familyEntry->ReadOtherFamilyNames(addOtherNames);
826 gfxQuartzFontCache::InitSingleFaceList()
828 nsAutoTArray<nsString, 10> singleFaceFonts;
829 gfxFontUtils::GetPrefsFontList("font.single-face-list", singleFaceFonts);
831 PRUint32 numFonts = singleFaceFonts.Length();
832 for (PRUint32 i = 0; i < numFonts; i++) {
833 nsAutoString availableFamilyName;
835 // lookup the font using NSFont
836 NSString *faceName = GetNSStringForString(singleFaceFonts[i]);
837 NSFont *font = [NSFont fontWithName:faceName size:0.0];
839 NSString *availableFamily = [font familyName];
840 GetStringForNSString(availableFamily, availableFamilyName);
842 MacOSFamilyEntry *familyEntry = FindFamily(availableFamilyName);
844 MacOSFontEntry *fontEntry = familyEntry->FindFont(singleFaceFonts[i]);
847 nsAutoString displayName, key;
849 // use the display name the canonical name
850 NSString *display = [font displayName];
851 GetStringForNSString(display, displayName);
852 GenerateFontListKey(displayName, key);
854 // add only if doesn't exist already
855 if (!(familyEntry = mFontFamilies.GetWeak(key, &found))) {
856 familyEntry = new SingleFaceFamily(displayName);
857 familyEntry->AddFontEntry(fontEntry);
858 mFontFamilies.Put(key, familyEntry);
859 PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-singleface) family: %s, psname: %s\n", [display UTF8String], [faceName UTF8String]));
861 fontEntry->mFamily = familyEntry;
871 gfxQuartzFontCache::PreloadNamesList()
873 nsAutoTArray<nsString, 10> preloadFonts;
874 gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
876 PRUint32 numFonts = preloadFonts.Length();
877 for (PRUint32 i = 0; i < numFonts; i++) {
880 GenerateFontListKey(preloadFonts[i], key);
882 // only search canonical names!
883 MacOSFamilyEntry *familyEntry = mFontFamilies.GetWeak(key, &found);
885 AddOtherFamilyNameFunctor addOtherNames(this);
886 familyEntry->ReadOtherFamilyNames(addOtherNames);
893 gfxQuartzFontCache::EliminateDuplicateFaces(const nsAString& aFamilyName)
895 MacOSFamilyEntry *family = FindFamily(aFamilyName);
898 nsTArray<nsRefPtr<MacOSFontEntry> >& fontlist = family->GetFontList();
900 PRUint32 i, bold, numFonts, italicIndex;
901 MacOSFontEntry *italic, *nonitalic;
902 PRUint32 boldtraits[2] = { 0, NSBoldFontMask };
904 // if normal and italic have the same ATSUI id, delete italic
905 // if bold and bold-italic have the same ATSUI id, delete bold-italic
907 // two iterations, one for normal, one for bold
908 for (bold = 0; bold < 2; bold++) {
909 numFonts = fontlist.Length();
911 // find the non-italic face
913 for (i = 0; i < numFonts; i++) {
914 PRUint32 traits = fontlist[i]->Traits();
915 if (((traits & NSBoldFontMask) == boldtraits[bold]) && !(traits & NSItalicFontMask)) {
916 nonitalic = fontlist[i];
921 // find the italic face
924 for (i = 0; i < numFonts; i++) {
925 PRUint32 traits = fontlist[i]->Traits();
926 if (((traits & NSBoldFontMask) == boldtraits[bold]) && (traits & NSItalicFontMask)) {
927 italic = fontlist[i];
933 // if italic face and non-italic face have matching ATSUI id's,
934 // the italic face is bogus so remove it
935 if (italic && italic->GetFontID() == nonitalic->GetFontID()) {
936 fontlist.RemoveElementAt(italicIndex);
943 gfxQuartzFontCache::SetFixedPitch(const nsAString& aFamilyName)
945 MacOSFamilyEntry *family = FindFamily(aFamilyName);
948 nsTArray<nsRefPtr<MacOSFontEntry> >& fontlist = family->GetFontList();
950 PRUint32 i, numFonts = fontlist.Length();
952 for (i = 0; i < numFonts; i++) {
953 fontlist[i]->mTraits |= NSFixedPitchFontMask;
954 fontlist[i]->mFixedPitch = 1;
959 gfxQuartzFontCache::InitBadUnderlineList()
961 nsAutoTArray<nsString, 10> blacklist;
962 gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
963 PRUint32 numFonts = blacklist.Length();
964 for (PRUint32 i = 0; i < numFonts; i++) {
967 GenerateFontListKey(blacklist[i], key);
969 MacOSFamilyEntry *familyEntry = mFontFamilies.GetWeak(key, &found);
971 familyEntry->SetBadUnderlineFont(PR_TRUE);
976 gfxQuartzFontCache::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
978 MacOSFamilyEntry *family = FindFamily(aFontName);
980 aResolvedFontName = family->Name();
987 gfxQuartzFontCache::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
989 MacOSFamilyEntry *family = FindFamily(aFontName);
991 family->LocalizedName(aFamilyName);
995 // Gecko 1.8 used Quickdraw font api's which produce a slightly different set of "family"
996 // names. Try to resolve based on these names, in case this is stored in an old profile
997 // 1.8: "Futura", "Futura Condensed" ==> 1.9: "Futura
1000 // convert of a NSString
1001 NSString *fontName = GetNSStringForString(aFontName);
1003 // name ==> family id ==> old-style FMFont
1004 ATSFontFamilyRef fmFontFamily = ATSFontFamilyFindFromName((CFStringRef)fontName, kATSOptionFlagsDefault);
1005 OSStatus err = FMGetFontFromFontFamilyInstance(fmFontFamily, 0, &fmFont, nsnull);
1006 if (err != noErr || fmFont == kInvalidFont)
1009 ATSFontRef atsFont = FMGetATSFontRefFromFont(fmFont);
1015 // now lookup the Postscript name
1016 err = ATSFontGetPostScriptName(atsFont, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
1020 // given an NSFont instance, Cocoa api's return the canonical family name
1021 NSString *canonicalfamily = [[NSFont fontWithName:psname size:0.0] familyName];
1024 nsAutoString familyName;
1026 // lookup again using the canonical family name
1027 GetStringForNSString(canonicalfamily, familyName);
1028 family = FindFamily(familyName);
1030 family->LocalizedName(aFamilyName);
1038 gfxQuartzFontCache::ATSNotification(ATSFontNotificationInfoRef aInfo,
1041 // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
1042 gfxQuartzFontCache *qfc = (gfxQuartzFontCache*)aUserArg;
1043 qfc->UpdateFontList();
1047 gfxQuartzFontCache::PrefChangedCallback(const char *aPrefName, void *closure)
1049 // XXX this could be made to only clear out the cache for the prefs that were changed
1050 // but it probably isn't that big a deal.
1051 gfxQuartzFontCache *qfc = static_cast<gfxQuartzFontCache *>(closure);
1052 qfc->mPrefFonts.Clear();
1057 gfxQuartzFontCache::GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
1059 NSString *defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
1060 nsAutoString familyName;
1062 GetStringForNSString(defaultFamily, familyName);
1063 return FindFontForFamily(familyName, aStyle, aNeedsBold);
1066 struct FontListData {
1067 FontListData(const nsACString& aLangGroup,
1068 const nsACString& aGenericFamily,
1069 nsStringArray& aListOfFonts) :
1070 mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
1071 mListOfFonts(aListOfFonts) {}
1072 const nsACString& mLangGroup;
1073 const nsACString& mGenericFamily;
1074 nsStringArray& mListOfFonts;
1077 PLDHashOperator PR_CALLBACK
1078 gfxQuartzFontCache::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
1079 nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
1082 FontListData *data = (FontListData*)aUserArg;
1084 nsAutoString localizedFamilyName;
1085 aFamilyEntry->LocalizedName(localizedFamilyName);
1086 data->mListOfFonts.AppendString(localizedFamilyName);
1087 return PL_DHASH_NEXT;
1091 gfxQuartzFontCache::GetFontList (const nsACString& aLangGroup,
1092 const nsACString& aGenericFamily,
1093 nsStringArray& aListOfFonts)
1095 FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
1097 mFontFamilies.Enumerate(gfxQuartzFontCache::HashEnumFuncForFamilies, &data);
1099 aListOfFonts.Sort();
1100 aListOfFonts.Compact();
1103 struct FontFamilyListData {
1104 FontFamilyListData(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamilyArray)
1105 : mFamilyArray(aFamilyArray)
1108 static PLDHashOperator PR_CALLBACK AppendFamily(nsStringHashKey::KeyType aKey,
1109 nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
1112 FontFamilyListData *data = (FontFamilyListData*)aUserArg;
1113 data->mFamilyArray.AppendElement(aFamilyEntry);
1114 return PL_DHASH_NEXT;
1117 nsTArray<nsRefPtr<MacOSFamilyEntry> >& mFamilyArray;
1121 gfxQuartzFontCache::GetFontFamilyList(nsTArray<nsRefPtr<MacOSFamilyEntry> >& aFamilyArray)
1123 FontFamilyListData data(aFamilyArray);
1124 mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
1128 gfxQuartzFontCache::FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont)
1130 // is codepoint with no matching font? return null immediately
1131 if (mCodepointsWithNoFonts.test(aCh)) {
1135 // short-circuit system font fallback for U+FFFD, used to represent encoding errors
1136 // just use Lucida Grande (system font, guaranteed to be around)
1137 // this helps speed up pages with lots of encoding errors, binary-as-text, etc.
1138 if (aCh == 0xFFFD) {
1139 MacOSFontEntry* fontEntry;
1140 PRBool needsBold; // ignored in the system fallback case
1143 fontEntry = FindFontForFamily(NS_LITERAL_STRING("Lucida Grande"), aPrevFont->GetStyle(), needsBold);
1145 gfxFontStyle normalStyle;
1146 fontEntry = FindFontForFamily(NS_LITERAL_STRING("Lucida Grande"), &normalStyle, needsBold);
1149 if (fontEntry && fontEntry->TestCharacterMap(aCh))
1153 FontSearch data(aCh, aPrevFont);
1155 // iterate over all font families to find a font that support the character
1156 mFontFamilies.Enumerate(gfxQuartzFontCache::FindFontForCharProc, &data);
1158 // no match? add to set of non-matching codepoints
1159 if (!data.bestMatch) {
1160 mCodepointsWithNoFonts.set(aCh);
1163 return data.bestMatch;
1166 PLDHashOperator PR_CALLBACK
1167 gfxQuartzFontCache::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
1170 FontSearch *data = (FontSearch*)userArg;
1172 // evaluate all fonts in this family for a match
1173 aFamilyEntry->FindFontForChar(data);
1174 return PL_DHASH_NEXT;
1178 gfxQuartzFontCache::FindFamily(const nsAString& aFamily)
1181 MacOSFamilyEntry *familyEntry;
1183 GenerateFontListKey(aFamily, key);
1185 // lookup in canonical (i.e. English) family name list
1186 if ((familyEntry = mFontFamilies.GetWeak(key, &found))) {
1190 // lookup in other family names list (mostly localized names)
1191 if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found))) {
1195 // name not found and other family names not yet fully initialized so
1196 // initialize the rest of the list and try again. this is done lazily
1197 // since reading name table entries is expensive
1198 if (!mOtherFamilyNamesInitialized) {
1199 InitOtherFamilyNames();
1200 if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found))) {
1209 gfxQuartzFontCache::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, PRBool& aNeedsBold)
1211 MacOSFamilyEntry *familyEntry = FindFamily(aFamily);
1213 aNeedsBold = PR_FALSE;
1216 return familyEntry->FindFont(aStyle, aNeedsBold);
1222 gfxQuartzFontCache::AppleWeightToCSSWeight(PRInt32 aAppleWeight)
1224 if (aAppleWeight < 1)
1226 else if (aAppleWeight > kAppleMaxWeight)
1227 aAppleWeight = kAppleMaxWeight;
1228 return gAppleWeightToCSSWeight[aAppleWeight];
1232 gfxQuartzFontCache::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> > *array)
1234 return mPrefFonts.Get(PRUint32(aLangGroup), array);
1238 gfxQuartzFontCache::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> >& array)
1240 mPrefFonts.Put(PRUint32(aLangGroup), array);
1244 gfxQuartzFontCache::AddOtherFamilyName(MacOSFamilyEntry *aFamilyEntry, nsAString& aOtherFamilyName)
1248 GenerateFontListKey(aOtherFamilyName, key);
1250 if (!mOtherFamilyNames.GetWeak(key, &found)) {
1251 mOtherFamilyNames.Put(key, aFamilyEntry);
1252 PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-otherfamily) canonical family: %s, other family: %s\n",
1253 NS_ConvertUTF16toUTF8(aFamilyEntry->Name()).get(),
1254 NS_ConvertUTF16toUTF8(aOtherFamilyName).get()));
1259 gfxQuartzFontCache::LookupLocalFont(const nsAString& aFontName)
1261 NSString *faceName = GetNSStringForString(aFontName);
1262 NSFont *font = [NSFont fontWithName:faceName size:0.0];
1265 nsAutoString availableFamilyName;
1266 NSString *availableFamily = [font familyName];
1267 GetStringForNSString(availableFamily, availableFamilyName);
1269 MacOSFamilyEntry *familyEntry = FindFamily(availableFamilyName);
1271 MacOSFontEntry *fontEntry = familyEntry->FindFont(aFontName);
1276 // didn't find the font
1280 // grumble, another non-publised Apple API dependency (found in Webkit code)
1281 // activated with this value, font will not be found via system lookup routines
1282 // it can only be used via the created ATSUFontID
1283 // needed to prevent one doc from finding a font used in a separate doc
1286 kPrivateATSFontContextPrivate = 3
1289 class MacOSUserFontData : public gfxUserFontData {
1291 MacOSUserFontData(ATSFontContainerRef aContainerRef)
1292 : mContainerRef(aContainerRef)
1295 virtual ~MacOSUserFontData()
1299 ATSFontDeactivate(mContainerRef, NULL, kATSOptionFlagsDefault);
1302 ATSFontContainerRef mContainerRef;
1306 gfxQuartzFontCache::MakePlatformFont(const gfxFontEntry *aProxyEntry,
1307 const PRUint8 *aFontData, PRUint32 aLength)
1311 NS_ASSERTION(aFontData && aLength != 0,
1312 "MakePlatformFont called with null data ptr");
1314 // do simple validation check on font data before
1315 // attempting to activate it
1316 if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength)) {
1319 const gfxProxyFontEntry *proxyEntry =
1320 static_cast<const gfxProxyFontEntry*> (aProxyEntry);
1321 sprintf(warnBuf, "downloaded font error, invalid font data for (%s)",
1322 NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
1323 NS_WARNING(warnBuf);
1329 ATSFontContainerRef containerRef;
1331 // we get occasional failures when multiple fonts are activated in quick succession
1332 // if the ATS font cache is damaged; to work around this, we can retry the activation
1333 const PRUint32 kMaxRetries = 3;
1334 PRUint32 retryCount = 0;
1335 while (retryCount++ < kMaxRetries) {
1336 err = ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength,
1337 kPrivateATSFontContextPrivate,
1338 kATSFontFormatUnspecified,
1340 kATSOptionFlagsDoNotNotify,
1342 mATSGeneration = ATSGetGeneration();
1347 const gfxProxyFontEntry *proxyEntry =
1348 static_cast<const gfxProxyFontEntry*> (aProxyEntry);
1349 sprintf(warnBuf, "downloaded font error, ATSFontActivateFromMemory err: %d for (%s)",
1351 NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
1352 NS_WARNING(warnBuf);
1357 // ignoring containers with multiple fonts, use the first face only for now
1358 err = ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1,
1363 const gfxProxyFontEntry *proxyEntry =
1364 static_cast<const gfxProxyFontEntry*> (aProxyEntry);
1365 sprintf(warnBuf, "downloaded font error, ATSFontFindFromContainer err: %d for (%s)",
1367 NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
1368 NS_WARNING(warnBuf);
1370 ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
1374 // now lookup the Postscript name; this may fail if the font cache is bad
1376 NSString *psname = NULL;
1377 nsAutoString postscriptName;
1378 err = ATSFontGetPostScriptName(fontRef, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
1380 GetStringForNSString(psname, postscriptName);
1385 const gfxProxyFontEntry *proxyEntry =
1386 static_cast<const gfxProxyFontEntry*> (aProxyEntry);
1387 sprintf(warnBuf, "ATSFontGetPostScriptName err = %d for (%s), retries = %d", (PRInt32)err,
1388 NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get(), retryCount);
1389 NS_WARNING(warnBuf);
1391 ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
1392 // retry the activation a couple of times if this fails
1393 // (may be a transient failure due to ATS font cache issues)
1397 // font entry will own this
1398 MacOSUserFontData *userFontData = new MacOSUserFontData(containerRef);
1400 if (!userFontData) {
1401 ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
1405 PRUint16 w = aProxyEntry->mWeight;
1406 NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
1408 // create the font entry
1409 MacOSFontEntry *newFontEntry =
1410 new MacOSFontEntry(postscriptName,
1411 FMGetFontFromATSFontRef(fontRef),
1412 w, aProxyEntry->mStretch,
1413 (PRUint32(aProxyEntry->mItalic) ?
1418 if (!newFontEntry) {
1419 delete userFontData;
1423 // if we succeeded (which should always be the case), return the new font
1424 if (newFontEntry->mIsValid)
1425 return newFontEntry;
1427 // if something is funky about this font, delete immediately
1430 const gfxProxyFontEntry *proxyEntry =
1431 static_cast<const gfxProxyFontEntry*> (aProxyEntry);
1432 sprintf(warnBuf, "downloaded font not loaded properly, removed face for (%s)",
1433 NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
1434 NS_WARNING(warnBuf);
1436 delete newFontEntry;
1438 // We don't retry from here; the ATS font cache issue would have caused failure earlier
1439 // so if we get here, there's something else bad going on within our font data structures.
1440 // Currently, there should be no way to reach here, as fontentry creation cannot fail
1441 // except by memory allocation failure.
1442 NS_WARNING("invalid font entry for a newly activated font");
1446 // if we get here, the activation failed (even with possible retries); can't use this font
1452 gfxQuartzFontCache::InitLoader()
1454 GetFontFamilyList(mFontFamiliesToLoad);
1456 mNumFamilies = mFontFamiliesToLoad.Length();
1460 gfxQuartzFontCache::RunLoader()
1462 PRUint32 i, endIndex = (mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies);
1464 // for each font family, load in various font info
1465 for (i = mStartIndex; i < endIndex; i++) {
1466 AddOtherFamilyNameFunctor addOtherNames(this);
1469 mFontFamiliesToLoad[i]->ReadCMAP();
1471 // read in other family names
1472 mFontFamiliesToLoad[i]->ReadOtherFamilyNames(addOtherNames);
1475 mStartIndex += mIncrement;
1476 if (mStartIndex < mNumFamilies)
1482 gfxQuartzFontCache::FinishLoader()
1484 mFontFamiliesToLoad.Clear();