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"
48 #include "nsIPref.h" // for pref changes callback notification
49 #include "nsServiceManagerUtils.h"
51 // _atsFontID is private; add it in our new category to NSFont
52 @interface NSFont (MozillaCategory)
53 - (ATSUFontID)_atsFontID;
56 #define INDEX_FONT_POSTSCRIPT_NAME 0
57 #define INDEX_FONT_FACE_NAME 1
58 #define INDEX_FONT_WEIGHT 2
59 #define INDEX_FONT_TRAITS 3
61 static const int kAppleMaxWeight = 14;
63 static const int gAppleWeightToCSSWeight[] = {
66 1, // 2. W1, ultralight
67 2, // 3. W2, extralight
69 4, // 5. W4, semilight
74 8, // 10. W8, extrabold
76 9, // 12. W9, ultrabold
82 static void GetStringForNSString(const NSString *aSrc, nsAString& aDist)
84 aDist.SetLength([aSrc length]);
85 [aSrc getCharacters:aDist.BeginWriting()];
88 static NSString* GetNSStringForString(const nsAString& aSrc)
90 return [NSString stringWithCharacters:aSrc.BeginReading()
91 length:aSrc.Length()];
94 static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
97 gfxQuartzFontCache::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
100 ToLowerCase(aResult);
106 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
107 PRInt32 aAppleWeight, PRUint32 aTraits, MacOSFamilyEntry *aFamily)
108 : mPostscriptName(aPostscriptName), mTraits(aTraits), mFamily(aFamily), mATSUFontID(0),
109 mCmapInitialized(0), mATSUIDInitialized(0)
111 mWeight = gfxQuartzFontCache::AppleWeightToCSSWeight(aAppleWeight);
115 MacOSFontEntry::FamilyName()
117 return mFamily->Name();
120 PRBool MacOSFontEntry::IsFixedPitch() {
121 return mTraits & NSFixedPitchFontMask;
124 PRBool MacOSFontEntry::IsItalicStyle() {
125 return mTraits & NSItalicFontMask;
128 PRBool MacOSFontEntry::IsBold() {
129 return mTraits & NSBoldFontMask;
132 ATSUFontID MacOSFontEntry::GetFontID()
134 if (!mATSUIDInitialized) {
135 mATSUIDInitialized = PR_TRUE;
136 NSString *psname = GetNSStringForString(mPostscriptName);
137 NSFont *font = [NSFont fontWithName:psname size:0.0];
138 if (font) mATSUFontID = [font _atsFontID];
144 MacOSFontEntry::ReadCMAP()
149 if (mCmapInitialized) return NS_OK;
150 ATSUFontID fontID = GetFontID();
152 // attempt this once, if errors occur leave a blank cmap
153 mCmapInitialized = PR_TRUE;
155 status = ATSFontGetTable(fontID, 'cmap', 0, 0, 0, &size);
156 //printf( "cmap size: %s %d\n", NS_ConvertUTF16toUTF8(mName).get(), size );
157 NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
159 nsAutoTArray<PRUint8,16384> buffer;
160 if (!buffer.AppendElements(size))
161 return NS_ERROR_OUT_OF_MEMORY;
162 PRUint8 *cmap = buffer.Elements();
164 status = ATSFontGetTable(fontID, 'cmap', 0, size, cmap, &size);
165 NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
167 nsresult rv = NS_ERROR_FAILURE;
168 PRPackedBool unicodeFont, symbolFont; // currently ignored
169 rv = gfxFontUtils::ReadCMAP(cmap, size, mCharacterMap, mUnicodeRanges, unicodeFont, symbolFont);
175 /* MacOSFamilyEntry */
178 static const PRUint32 kTraits_NonNormalWidthMask = NSNarrowFontMask | NSExpandedFontMask |
179 NSCondensedFontMask | NSCompressedFontMask | NSFixedPitchFontMask;
182 MacOSFamilyEntry::FindFont(const gfxFontStyle* aStyle)
184 // short-circuit the single face per family case
185 if (mAvailableFonts.Length() == 1) return mAvailableFonts[0];
187 PRBool found = PR_FALSE;
188 PRBool isItalic = (aStyle->style == FONT_STYLE_ITALIC || aStyle->style == FONT_STYLE_OBLIQUE);
189 MacOSFontEntry* fontsWithTraits[10];
191 memset(fontsWithTraits, 0, sizeof(fontsWithTraits));
193 // match italic faces
195 // first search for italic normal width fonts
196 found = FindFontsWithTraits(fontsWithTraits, NSItalicFontMask, kTraits_NonNormalWidthMask);
198 // if not found, italic any width ones
200 found = FindFontsWithTraits(fontsWithTraits, NSItalicFontMask, 0);
204 // match non-italic faces, if no italic faces fall through here
206 // look for normal width fonts
207 found = FindFontsWithTraits(fontsWithTraits, NSUnitalicFontMask, kTraits_NonNormalWidthMask);
209 // if not found, any face will do
211 found = FindFontsWithTraits(fontsWithTraits, NSUnitalicFontMask, 0);
215 // still not found?!? family must only contain italic fonts when looking for a normal
216 // face, just use the whole list
218 found = FindFontsWithTraits(fontsWithTraits, 0, 0);
220 NS_ASSERTION(found, "Font family containing no faces");
221 if (!found) return nsnull;
223 MacOSFontEntry* chosenFont = FindFontWeight(fontsWithTraits, aStyle);
224 NS_ASSERTION(chosenFont, "Somehow selected a null font entry when choosing based on font weight");
229 MacOSFamilyEntry::FindFontForChar(FontSearch *aMatchData)
231 PRUint32 numFonts, i;
233 // xxx - optimization point - keep a bit vector with the union of supported unicode ranges
234 // by all fonts for this family and bail immediately if the character is not in any of
235 // this family's cmaps
237 // iterate over fonts
238 numFonts = mAvailableFonts.Length();
239 for (i = 0; i < numFonts; i++) {
240 MacOSFontEntry *fe = mAvailableFonts[i];
243 if (fe->TestCharacterMap(aMatchData->ch)) {
247 // if we didn't match any characters don't bother wasting more time.
251 // omitting from original windows code -- family name, lang group, pitch
252 // not available in current FontEntry implementation
254 if (aMatchData->fontToMatch) {
255 const gfxFontStyle *style = aMatchData->fontToMatch->GetStyle();
258 if (fe->IsItalicStyle() &&
259 (style->style == FONT_STYLE_ITALIC || style->style == FONT_STYLE_ITALIC)) {
264 PRInt8 baseWeight, weightDistance;
265 style->ComputeWeightAndOffset(&baseWeight, &weightDistance);
267 // xxx - not entirely correct, the one unit of weight distance reflects
268 // the "next bolder/lighter face"
269 PRUint32 targetWeight = (baseWeight * 100) + (weightDistance * 100);
271 PRUint32 entryWeight = fe->Weight() * 100;
272 if (entryWeight == targetWeight) {
275 PRUint32 diffWeight = abs(entryWeight - targetWeight);
276 if (diffWeight <= 100) // favor faces close in weight
280 // if no font to match, prefer non-bold, non-italic fonts
281 if (!fe->IsItalicStyle() && !fe->IsBold())
285 // xxx - add whether AAT font with morphing info for specific lang groups
287 if (rank > aMatchData->matchRank
288 || (rank == aMatchData->matchRank && Compare(fe->Name(), aMatchData->bestMatch->Name()) > 0))
290 aMatchData->bestMatch = fe;
291 aMatchData->matchRank = rank;
298 MacOSFamilyEntry::FindFontsWithTraits(MacOSFontEntry* aFontsForWeights[], PRUint32 aPosTraitsMask,
299 PRUint32 aNegTraitsMask)
301 PRUint32 numFonts, i;
302 PRBool found = PR_FALSE;
304 // iterate over fonts
305 numFonts = mAvailableFonts.Length();
306 for (i = 0; i < numFonts; i++) {
307 MacOSFontEntry *fe = mAvailableFonts[i];
309 // if traits match, add to list of fonts
310 PRUint32 traits = fe->Traits();
312 // aPosTraitsMask == 0 ==> match all
313 if ( (!aPosTraitsMask || (traits & aPosTraitsMask)) && !(traits & aNegTraitsMask)) {
314 PRInt32 weight = fe->Weight();
316 // always prefer the first font for a given weight, helps deal a bit with
317 // families with lots of faces (e.g. Minion Pro)
318 if (!aFontsForWeights[weight]) {
319 aFontsForWeights[weight] = fe;
328 MacOSFamilyEntry::FindFontWeight(MacOSFontEntry* aFontsForWeights[], const gfxFontStyle* aStyle)
330 // calculate the desired weight from the style
331 PRInt32 w, direction, offset, baseMatch;
332 PRInt8 baseWeight, weightDistance;
334 aStyle->ComputeWeightAndOffset(&baseWeight, &weightDistance);
335 NS_ASSERTION(baseWeight != 0, "Style with font weight 0 (whacked)");
337 // choose the weight that matches the base weight using CSS Fonts spec rules
339 // have the desired weight ==> use it
341 if (aFontsForWeights[baseWeight]) {
343 baseMatch = baseWeight;
347 // CSS2.1 and draft CSS3 Fonts specs are ambiguous about how to handle missing 400 weight face
348 // substitute 400 and 500 for each other (example: Futura family that ships with Mac OS X)
349 if (baseWeight == 4 && aFontsForWeights[5]) {
351 } else if (baseWeight == 5 && aFontsForWeights[4]) {
355 // otherwise, use explicit CSS rules
356 // weights above 400 ==> look up in weights, then down, otherwise look down, then up
357 direction = (baseWeight > 4 ? 1 : -1);
359 // search in one direction
360 for (w = baseWeight + direction; w >= 1 && w <= 9; w += direction) {
361 if (aFontsForWeights[w]) {
367 // not found? switch direction and search the remaining entries
369 direction = -direction;
370 for (w = baseWeight + direction; w >= 1 && w <= 9; w += direction) {
371 if (aFontsForWeights[w]) {
380 // at this point, should have found an entry matching the base weight
381 NS_ASSERTION(baseMatch, "Somehow didn't find matching weight");
383 // handle weight offsets
384 if (weightDistance) {
385 direction = (weightDistance < 0 ? -1 : 1);
386 offset = abs(weightDistance);
388 // look for bolder/lighter face [offset] number of faces away from the base face
389 // e.g. weight = 698 with Helvetica Neue ==> offset = 2, direction = -1,
390 // baseMatch starts at 7 (Bold), then 4 (Regular), then 2 (Light)
391 for (w = baseMatch + direction; w >= 1 && w <= 9 && offset; w += direction) {
392 if (aFontsForWeights[w]) {
399 NS_ASSERTION(aFontsForWeights[baseMatch], "Chose a weight without a corresponding face");
400 return aFontsForWeights[baseMatch];
403 /* gfxQuartzFontCache */
406 gfxQuartzFontCache *gfxQuartzFontCache::sSharedFontCache = nsnull;
408 gfxQuartzFontCache::gfxQuartzFontCache()
410 mFontFamilies.Init(100);
411 mLocalizedFamilies.Init(30);
415 ::ATSFontNotificationSubscribe(ATSNotification,
416 kATSFontNotifyOptionDefault,
417 (void*)this, nsnull);
419 // pref changes notification setup
420 nsCOMPtr<nsIPref> pref = do_GetService(NS_PREF_CONTRACTID);
421 pref->RegisterCallback("font.", PrefChangedCallback, this);
422 pref->RegisterCallback("font.name-list.", PrefChangedCallback, this);
423 pref->RegisterCallback("intl.accept_languages", PrefChangedCallback, this); // hmmmm...
427 static NSString* CreateNameFromBuffer(const UInt8 *aBuf, ByteCount aLength,
428 FontPlatformCode aPlatformCode, FontScriptCode aScriptCode, FontLanguageCode aLangCode )
430 CFStringRef outName = NULL;
432 if (aPlatformCode == kFontMacintoshPlatform) {
433 TextEncoding encoding;
434 OSStatus err = GetTextEncodingFromScriptInfo(aScriptCode, aLangCode,
435 kTextRegionDontCare, &encoding);
437 // some fonts are sloppy about the language code (e.g Arial Hebrew, Corsiva Hebrew)
438 // try again without the lang code to avoid bad combinations
439 OSStatus err = GetTextEncodingFromScriptInfo(aScriptCode, kTextLanguageDontCare,
440 kTextRegionDontCare, &encoding);
443 outName = CFStringCreateWithBytes(kCFAllocatorDefault, aBuf,
444 aLength, (CFStringEncoding) encoding, false);
445 } else if (aPlatformCode == kFontUnicodePlatform) {
446 outName = CFStringCreateWithCharacters(kCFAllocatorDefault, (UniChar*)aBuf, aLength/2);
447 } else if (aPlatformCode == kFontMicrosoftPlatform) {
448 if ( aScriptCode == 0 ) {
449 outName = CFStringCreateWithBytes(kCFAllocatorDefault, aBuf,
450 aLength, kCFStringEncodingUTF16BE, false);
452 outName = CFStringCreateWithCharacters(kCFAllocatorDefault, (UniChar*)aBuf, aLength/2);
456 return (NSString*) outName;
460 // 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
462 kMozillaFontPreferredFamilyName = 16,
465 // xxx - rather than use ATSUI calls, probably faster to load name table directly,
466 // this avoids copying around strings that are of no interest
468 static void ReadLocalizedNames(NSString *familyName, NSArray *faceArray,
469 int faceIndex, NSMutableArray *localizedNames)
472 ItemCount i, nameCount;
475 NSArray *face = [faceArray objectAtIndex:faceIndex];
476 NSString *psname = [face objectAtIndex:INDEX_FONT_POSTSCRIPT_NAME];
477 NSFont *font = [NSFont fontWithName:psname size:0.0];
478 fontID = [font _atsFontID];
480 err = ATSUCountFontNames(fontID, &nameCount);
481 for (i = 0; i < nameCount; i++) {
483 FontNameCode nameCode;
484 FontPlatformCode platformCode;
485 FontScriptCode scriptCode;
486 FontLanguageCode langCode;
487 const ByteCount kBufLength = 2048;
488 char buf[kBufLength];
491 err = ATSUGetIndFontName(fontID, i, kBufLength, buf, &len, &nameCode, &platformCode, &scriptCode, &langCode);
492 if (!(nameCode == kFontFamilyName || nameCode == kMozillaFontPreferredFamilyName)) continue;
493 if (len >= kBufLength) continue;
496 NSString *name = CreateNameFromBuffer((UInt8*)buf, len, platformCode, scriptCode, langCode);
497 NSString *foundName = nil;
499 // add if not same as canonical family name or already in list of names
502 if (![name isEqualToString:familyName]) {
504 // search other localized names
505 int j, lnameCount = [localizedNames count];
507 for (j = 0; j < lnameCount; j++) {
508 lname = [localizedNames objectAtIndex:j];
509 if ([lname isEqualToString:name]) {
515 // didn't find it in the list? add it
517 [localizedNames addObject:name];
526 const int kIndexNormalFace_NotFound = -1;
527 const PRUint32 kNonNormalTraits = NSItalicFontMask | NSBoldFontMask | NSNarrowFontMask | NSExpandedFontMask | NSCondensedFontMask | NSCompressedFontMask;
530 gfxQuartzFontCache::InitFontList()
532 mFontFamilies.Clear();
533 mLocalizedFamilies.Clear();
535 mCodepointsWithNoFonts.reset();
537 // iterate over available families
538 NSFontManager *fontManager = [NSFontManager sharedFontManager];
539 NSEnumerator *families = [[fontManager availableFontFamilies] objectEnumerator]; // returns "canonical", non-localized family name
541 NSMutableArray* localizedNames = [[NSMutableArray alloc] init];
542 nsAutoString availableFamilyName, postscriptFontName, localizedName;
544 NSString *availableFamily = nil;
545 while ((availableFamily = [families nextObject])) {
548 GetStringForNSString(availableFamily, availableFamilyName);
550 // create a family entry
551 nsRefPtr<MacOSFamilyEntry> familyEntry = new MacOSFamilyEntry(availableFamilyName);
552 if (!familyEntry) break;
554 // create a font entry for each face
555 NSArray *fontfaces = [fontManager availableMembersOfFontFamily:availableFamily]; // returns an array of [psname, style name, weight, traits] elements, goofy api
556 int faceCount = [fontfaces count];
557 int normalFaceIndex = kIndexNormalFace_NotFound;
560 for (faceIndex = 0; faceIndex < faceCount; faceIndex++) {
561 NSArray *face = [fontfaces objectAtIndex:faceIndex];
562 NSString *psname = [face objectAtIndex:INDEX_FONT_POSTSCRIPT_NAME];
563 PRInt32 weight = [[face objectAtIndex:INDEX_FONT_WEIGHT] unsignedIntValue];
564 PRUint32 traits = [[face objectAtIndex:INDEX_FONT_TRAITS] unsignedIntValue];
566 // 10.5 doesn't set NSUnitalicFontMask and NSUnboldFontMask - manually set these for consistency
567 if (!(traits & NSBoldFontMask))
568 traits |= NSUnboldFontMask;
569 if (!(traits & NSItalicFontMask))
570 traits |= NSUnitalicFontMask;
572 PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(init) family: %s, psname: %s, face: %s, apple-weight: %d, css-weight: %d, traits: %8.8x\n",
573 [availableFamily UTF8String], [psname UTF8String], [[face objectAtIndex:INDEX_FONT_FACE_NAME] UTF8String], weight, gfxQuartzFontCache::AppleWeightToCSSWeight(weight), traits ));
576 GetStringForNSString(psname, postscriptFontName);
578 // create a font entry
579 nsRefPtr<MacOSFontEntry> fontEntry = new MacOSFontEntry(postscriptFontName, weight, traits, familyEntry);
580 if (!fontEntry) break;
582 // insert into font entry array of family
583 familyEntry->AddFontEntry(fontEntry);
585 // if normal face not found yet, check the traits for this one
586 if ( normalFaceIndex == kIndexNormalFace_NotFound && !(traits & kNonNormalTraits))
587 normalFaceIndex = faceIndex;
590 // if no normal face, just use the first face in the array of available ones
591 if ( normalFaceIndex == kIndexNormalFace_NotFound )
594 // read the name table for the normal face; if localized names exist for that face, scan all font entries for more localized names
595 [localizedNames removeAllObjects];
596 ReadLocalizedNames(availableFamily, fontfaces, normalFaceIndex, localizedNames);
597 if ([localizedNames count] != 0) {
598 for (faceIndex = 0; faceIndex < faceCount; faceIndex++) {
599 if (faceIndex == normalFaceIndex) continue;
600 ReadLocalizedNames(availableFamily, fontfaces, faceIndex, localizedNames);
604 // add the family entry to the hash table
605 ToLowerCase(availableFamilyName);
606 mFontFamilies.Put(availableFamilyName, familyEntry);
608 // add in an entry for each of the localized names
609 int lnameIndex, lnameCount = [localizedNames count];
610 for (lnameIndex = 0; lnameIndex < lnameCount; lnameIndex++) {
611 GetStringForNSString([localizedNames objectAtIndex:lnameIndex], localizedName);
612 ToLowerCase(localizedName);
613 mLocalizedFamilies.Put(localizedName, familyEntry);
618 // xxx - deal with quirks (e.g. Osaka-Mono)
620 // xxx - need to remove bogus Helvetica/Courier italic faces (Cocoa inanity!)
622 // initialize ranges of characters for which system-wide font search should be skipped
623 mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
624 mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
625 mCodepointsWithNoFonts.set(0xfffd); // unknown
627 [localizedNames release];
631 gfxQuartzFontCache::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
634 nsRefPtr<MacOSFamilyEntry> familyEntry;
635 GenerateFontListKey(aFontName, key);
637 if (mFontFamilies.Get(key, &familyEntry) || mLocalizedFamilies.Get(key, &familyEntry)) {
638 aResolvedFontName = familyEntry->Name();
645 gfxQuartzFontCache::ATSNotification(ATSFontNotificationInfoRef aInfo,
648 // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
649 gfxQuartzFontCache *qfc = (gfxQuartzFontCache*)aUserArg;
650 qfc->UpdateFontList();
654 gfxQuartzFontCache::PrefChangedCallback(const char *aPrefName, void *closure)
656 // XXX this could be made to only clear out the cache for the prefs that were changed
657 // but it probably isn't that big a deal.
658 gfxQuartzFontCache *qfc = static_cast<gfxQuartzFontCache *>(closure);
659 qfc->mPrefFonts.Clear();
664 gfxQuartzFontCache::GetDefaultFont(const gfxFontStyle* aStyle)
666 NSString *defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
667 nsAutoString familyName;
669 GetStringForNSString(defaultFamily, familyName);
670 return FindFontForFamily(familyName, aStyle);
673 struct FontListData {
674 FontListData(const nsACString& aLangGroup,
675 const nsACString& aGenericFamily,
676 nsStringArray& aListOfFonts) :
677 mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
678 mListOfFonts(aListOfFonts) {}
679 const nsACString& mLangGroup;
680 const nsACString& mGenericFamily;
681 nsStringArray& mListOfFonts;
684 PLDHashOperator PR_CALLBACK
685 gfxQuartzFontCache::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
686 nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
689 FontListData *data = (FontListData*)aUserArg;
690 data->mListOfFonts.AppendString(aFamilyEntry->Name());
691 return PL_DHASH_NEXT;
695 gfxQuartzFontCache::GetFontList (const nsACString& aLangGroup,
696 const nsACString& aGenericFamily,
697 nsStringArray& aListOfFonts)
699 FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
701 mFontFamilies.Enumerate(gfxQuartzFontCache::HashEnumFuncForFamilies, &data);
704 aListOfFonts.Compact();
708 gfxQuartzFontCache::FindFontForChar(const PRUint32 aCh, gfxAtsuiFont *aPrevFont)
710 // is codepoint with no matching font? return null immediately
711 if (mCodepointsWithNoFonts.test(aCh)) {
715 FontSearch data(aCh, aPrevFont);
717 // iterate over all font families to find a font that support the character
718 mFontFamilies.Enumerate(gfxQuartzFontCache::FindFontForCharProc, &data);
720 // no match? add to set of non-matching codepoints
721 if (!data.bestMatch) {
722 mCodepointsWithNoFonts.set(aCh);
725 return data.bestMatch;
728 PLDHashOperator PR_CALLBACK
729 gfxQuartzFontCache::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
732 FontSearch *data = (FontSearch*)userArg;
734 // evaluate all fonts in this family for a match
735 aFamilyEntry->FindFontForChar(data);
736 return PL_DHASH_NEXT;
740 gfxQuartzFontCache::FindFamily(const nsAString& aFamily)
743 nsRefPtr<MacOSFamilyEntry> familyEntry;
744 GenerateFontListKey(aFamily, key);
746 if (mFontFamilies.Get(key, &familyEntry) || mLocalizedFamilies.Get(key, &familyEntry)) {
753 gfxQuartzFontCache::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle)
755 MacOSFamilyEntry *familyEntry = FindFamily(aFamily);
758 return familyEntry->FindFont(aStyle);
764 gfxQuartzFontCache::AppleWeightToCSSWeight(PRInt32 aAppleWeight)
766 if (aAppleWeight < 1)
768 else if (aAppleWeight > kAppleMaxWeight)
769 aAppleWeight = kAppleMaxWeight;
770 return gAppleWeightToCSSWeight[aAppleWeight];
774 gfxQuartzFontCache::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> > *array)
776 return mPrefFonts.Get(PRUint32(aLangGroup), array);
780 gfxQuartzFontCache::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> >& array)
782 mPrefFonts.Put(PRUint32(aLangGroup), array);