PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/gfx/thebes/gfxMacPlatformFontList.mm

https://bitbucket.org/soko/mozilla-central
Objective C++ | 1301 lines | 948 code | 215 blank | 138 comment | 132 complexity | 611267b35137f39aa781f56b8748494b MD5 | raw file
Possible License(s): GPL-2.0, JSON, 0BSD, LGPL-3.0, AGPL-1.0, MIT, MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.1, Apache-2.0
  1. /* -*- Mode: ObjC; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * ***** BEGIN LICENSE BLOCK *****
  3. * Version: BSD
  4. *
  5. * Copyright (C) 2006-2009 Mozilla Corporation. All rights reserved.
  6. *
  7. * Contributor(s):
  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>
  12. *
  13. * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
  14. *
  15. * Redistribution and use in source and binary forms, with or without
  16. * modification, are permitted provided that the following conditions
  17. * are met:
  18. *
  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.
  27. *
  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.
  38. *
  39. * ***** END LICENSE BLOCK ***** */
  40. #ifdef MOZ_LOGGING
  41. #define FORCE_PR_LOG /* Allow logging in the release build */
  42. #endif
  43. #include "prlog.h"
  44. #include <Carbon/Carbon.h>
  45. #import <AppKit/AppKit.h>
  46. #include "gfxPlatformMac.h"
  47. #include "gfxMacPlatformFontList.h"
  48. #include "gfxMacFont.h"
  49. #include "gfxUserFontSet.h"
  50. #include "nsServiceManagerUtils.h"
  51. #include "nsTArray.h"
  52. #include "nsDirectoryServiceUtils.h"
  53. #include "nsDirectoryServiceDefs.h"
  54. #include "nsISimpleEnumerator.h"
  55. #include "nsCharTraits.h"
  56. #include "mozilla/Telemetry.h"
  57. #include <unistd.h>
  58. #include <time.h>
  59. using namespace mozilla;
  60. class nsAutoreleasePool {
  61. public:
  62. nsAutoreleasePool()
  63. {
  64. mLocalPool = [[NSAutoreleasePool alloc] init];
  65. }
  66. ~nsAutoreleasePool()
  67. {
  68. [mLocalPool release];
  69. }
  70. private:
  71. NSAutoreleasePool *mLocalPool;
  72. };
  73. // font info loader constants
  74. static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
  75. static const PRUint32 kIntervalBetweenLoadingCmaps = 150; // 150ms
  76. static const PRUint32 kNumFontsPerSlice = 10; // read in info 10 fonts at a time
  77. // indexes into the NSArray objects that the Cocoa font manager returns
  78. // as the available members of a family
  79. #define INDEX_FONT_POSTSCRIPT_NAME 0
  80. #define INDEX_FONT_FACE_NAME 1
  81. #define INDEX_FONT_WEIGHT 2
  82. #define INDEX_FONT_TRAITS 3
  83. static const int kAppleMaxWeight = 14;
  84. static const int kAppleExtraLightWeight = 3;
  85. static const int kAppleUltraLightWeight = 2;
  86. static const int gAppleWeightToCSSWeight[] = {
  87. 0,
  88. 1, // 1.
  89. 1, // 2. W1, ultralight
  90. 2, // 3. W2, extralight
  91. 3, // 4. W3, light
  92. 4, // 5. W4, semilight
  93. 5, // 6. W5, medium
  94. 6, // 7.
  95. 6, // 8. W6, semibold
  96. 7, // 9. W7, bold
  97. 8, // 10. W8, extrabold
  98. 8, // 11.
  99. 9, // 12. W9, ultrabold
  100. 9, // 13
  101. 9 // 14
  102. };
  103. // cache Cocoa's "shared font manager" for performance
  104. static NSFontManager *sFontManager;
  105. static void GetStringForNSString(const NSString *aSrc, nsAString& aDist)
  106. {
  107. aDist.SetLength([aSrc length]);
  108. [aSrc getCharacters:aDist.BeginWriting()];
  109. }
  110. static NSString* GetNSStringForString(const nsAString& aSrc)
  111. {
  112. return [NSString stringWithCharacters:aSrc.BeginReading()
  113. length:aSrc.Length()];
  114. }
  115. #ifdef PR_LOGGING
  116. #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
  117. PR_LOG_DEBUG, args)
  118. #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
  119. gfxPlatform::GetLog(eGfxLog_fontlist), \
  120. PR_LOG_DEBUG)
  121. #define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
  122. gfxPlatform::GetLog(eGfxLog_cmapdata), \
  123. PR_LOG_DEBUG)
  124. #endif // PR_LOGGING
  125. /* MacOSFontEntry - abstract superclass for ATS and CG font entries */
  126. #pragma mark-
  127. MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
  128. PRInt32 aWeight,
  129. gfxFontFamily *aFamily,
  130. bool aIsStandardFace)
  131. : gfxFontEntry(aPostscriptName, aFamily, aIsStandardFace),
  132. mFontRef(NULL),
  133. mFontRefInitialized(false),
  134. mRequiresAAT(false),
  135. mIsCFF(false),
  136. mIsCFFInitialized(false)
  137. {
  138. mWeight = aWeight;
  139. }
  140. // ATSUI requires AAT-enabled fonts to render complex scripts correctly.
  141. // For now, simple clear out the cmap codepoints for fonts that have
  142. // codepoints for complex scripts. (Bug 361986)
  143. // Core Text is similar, but can render Arabic using OpenType fonts as well.
  144. enum eComplexScript {
  145. eComplexScriptArabic,
  146. eComplexScriptIndic,
  147. eComplexScriptLaoTibetan
  148. };
  149. struct ScriptRange {
  150. eComplexScript script;
  151. PRUint32 rangeStart;
  152. PRUint32 rangeEnd;
  153. };
  154. const ScriptRange gScriptsThatRequireShaping[] = {
  155. { eComplexScriptArabic, 0x0600, 0x077F }, // Basic Arabic, Syriac, Arabic Supplement
  156. { eComplexScriptIndic, 0x0900, 0x0D7F }, // Indic scripts - Devanagari, Bengali, ..., Malayalam
  157. { eComplexScriptLaoTibetan, 0x0E80, 0x0FFF } // Lao, Tibetan
  158. // Thai seems to be "renderable" without AAT morphing tables
  159. // xxx - Khmer?
  160. };
  161. nsresult
  162. MacOSFontEntry::ReadCMAP()
  163. {
  164. // attempt this once, if errors occur leave a blank cmap
  165. if (mCharacterMap) {
  166. return NS_OK;
  167. }
  168. nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
  169. PRUint32 kCMAP = TRUETYPE_TAG('c','m','a','p');
  170. nsresult rv;
  171. AutoFallibleTArray<PRUint8,16384> cmap;
  172. rv = GetFontTable(kCMAP, cmap);
  173. bool unicodeFont = false, symbolFont = false; // currently ignored
  174. if (NS_SUCCEEDED(rv)) {
  175. rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
  176. *charmap, mUVSOffset,
  177. unicodeFont, symbolFont);
  178. }
  179. if (NS_SUCCEEDED(rv)) {
  180. // for layout support, check for the presence of mort/morx and/or
  181. // opentype layout tables
  182. bool hasAATLayout = HasFontTable(TRUETYPE_TAG('m','o','r','x')) ||
  183. HasFontTable(TRUETYPE_TAG('m','o','r','t'));
  184. bool hasGSUB = HasFontTable(TRUETYPE_TAG('G','S','U','B'));
  185. bool hasGPOS = HasFontTable(TRUETYPE_TAG('G','P','O','S'));
  186. if (hasAATLayout && !(hasGSUB || hasGPOS)) {
  187. mRequiresAAT = true; // prefer CoreText if font has no OTL tables
  188. }
  189. PRUint32 numScripts =
  190. sizeof(gScriptsThatRequireShaping) / sizeof(ScriptRange);
  191. for (PRUint32 s = 0; s < numScripts; s++) {
  192. eComplexScript whichScript = gScriptsThatRequireShaping[s].script;
  193. // check to see if the cmap includes complex script codepoints
  194. if (charmap->TestRange(gScriptsThatRequireShaping[s].rangeStart,
  195. gScriptsThatRequireShaping[s].rangeEnd)) {
  196. bool omitRange = true;
  197. if (hasAATLayout) {
  198. omitRange = false;
  199. // prefer CoreText for Apple's complex-script fonts,
  200. // even if they also have some OpenType tables
  201. // (e.g. Geeza Pro Bold on 10.6; see bug 614903)
  202. mRequiresAAT = true;
  203. } else if (whichScript == eComplexScriptArabic) {
  204. // special-case for Arabic:
  205. // even if there's no morph table, CoreText can shape Arabic
  206. // using OpenType layout; or if it's a downloaded font,
  207. // assume the site knows what it's doing (as harfbuzz will
  208. // be able to shape even though the font itself lacks tables
  209. // stripped during sanitization).
  210. // We check for GSUB here, as GPOS alone would not be ok
  211. // for Arabic shaping.
  212. if (hasGSUB || (mIsUserFont && !mIsLocalUserFont)) {
  213. // TODO: to be really thorough, we could check that the
  214. // GSUB table actually supports the 'arab' script tag.
  215. omitRange = false;
  216. }
  217. }
  218. if (omitRange) {
  219. charmap->ClearRange(gScriptsThatRequireShaping[s].rangeStart,
  220. gScriptsThatRequireShaping[s].rangeEnd);
  221. }
  222. }
  223. }
  224. }
  225. mHasCmapTable = NS_SUCCEEDED(rv);
  226. if (mHasCmapTable) {
  227. gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
  228. mCharacterMap = pfl->FindCharMap(charmap);
  229. } else {
  230. // if error occurred, initialize to null cmap
  231. mCharacterMap = new gfxCharacterMap();
  232. }
  233. #ifdef PR_LOGGING
  234. LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
  235. NS_ConvertUTF16toUTF8(mName).get(),
  236. charmap->SizeOfIncludingThis(moz_malloc_size_of),
  237. charmap->mHash, mCharacterMap == charmap ? " new" : ""));
  238. if (LOG_CMAPDATA_ENABLED()) {
  239. char prefix[256];
  240. sprintf(prefix, "(cmapdata) name: %.220s",
  241. NS_ConvertUTF16toUTF8(mName).get());
  242. charmap->Dump(prefix, eGfxLog_cmapdata);
  243. }
  244. #endif
  245. return rv;
  246. }
  247. gfxFont*
  248. MacOSFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold)
  249. {
  250. return new gfxMacFont(this, aFontStyle, aNeedsBold);
  251. }
  252. bool
  253. MacOSFontEntry::IsCFF()
  254. {
  255. if (!mIsCFFInitialized) {
  256. mIsCFFInitialized = true;
  257. mIsCFF = HasFontTable(TRUETYPE_TAG('C','F','F',' '));
  258. }
  259. return mIsCFF;
  260. }
  261. /* ATSFontEntry - used on Mac OS X 10.5.x */
  262. #pragma mark-
  263. ATSFontEntry::ATSFontEntry(const nsAString& aPostscriptName,
  264. PRInt32 aWeight,
  265. gfxFontFamily *aFamily,
  266. bool aIsStandardFace)
  267. : MacOSFontEntry(aPostscriptName, aWeight, aFamily, aIsStandardFace),
  268. mATSFontRef(kInvalidFont),
  269. mATSFontRefInitialized(false)
  270. {
  271. }
  272. ATSFontEntry::ATSFontEntry(const nsAString& aPostscriptName,
  273. ATSFontRef aFontRef,
  274. PRUint16 aWeight, PRUint16 aStretch,
  275. PRUint32 aItalicStyle,
  276. gfxUserFontData *aUserFontData,
  277. bool aIsLocal)
  278. : MacOSFontEntry(aPostscriptName, aWeight, nsnull, false)
  279. {
  280. mATSFontRef = aFontRef;
  281. mATSFontRefInitialized = true;
  282. mWeight = aWeight;
  283. mStretch = aStretch;
  284. mFixedPitch = false; // xxx - do we need this for downloaded fonts?
  285. mItalic = (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
  286. mUserFontData = aUserFontData;
  287. mIsUserFont = (aUserFontData != nsnull) || aIsLocal;
  288. mIsLocalUserFont = aIsLocal;
  289. }
  290. ATSFontRef
  291. ATSFontEntry::GetATSFontRef()
  292. {
  293. if (!mATSFontRefInitialized) {
  294. mATSFontRefInitialized = true;
  295. NSString *psname = GetNSStringForString(mName);
  296. mATSFontRef = ::ATSFontFindFromPostScriptName(CFStringRef(psname),
  297. kATSOptionFlagsDefault);
  298. }
  299. return mATSFontRef;
  300. }
  301. CGFontRef
  302. ATSFontEntry::GetFontRef()
  303. {
  304. if (mFontRefInitialized) {
  305. return mFontRef;
  306. }
  307. // GetATSFontRef will initialize mATSFontRef
  308. if (GetATSFontRef() == kInvalidFont) {
  309. return nsnull;
  310. }
  311. mFontRef = ::CGFontCreateWithPlatformFont(&mATSFontRef);
  312. mFontRefInitialized = true;
  313. return mFontRef;
  314. }
  315. nsresult
  316. ATSFontEntry::GetFontTable(PRUint32 aTableTag, FallibleTArray<PRUint8>& aBuffer)
  317. {
  318. nsAutoreleasePool localPool;
  319. ATSFontRef fontRef = GetATSFontRef();
  320. if (fontRef == kInvalidFont) {
  321. return NS_ERROR_FAILURE;
  322. }
  323. ByteCount dataLength;
  324. OSStatus status = ::ATSFontGetTable(fontRef, aTableTag, 0, 0, 0, &dataLength);
  325. if (status != noErr) {
  326. return NS_ERROR_FAILURE;
  327. }
  328. if (!aBuffer.SetLength(dataLength)) {
  329. return NS_ERROR_OUT_OF_MEMORY;
  330. }
  331. PRUint8 *dataPtr = aBuffer.Elements();
  332. status = ::ATSFontGetTable(fontRef, aTableTag, 0, dataLength, dataPtr, &dataLength);
  333. NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
  334. return NS_OK;
  335. }
  336. bool
  337. ATSFontEntry::HasFontTable(PRUint32 aTableTag)
  338. {
  339. ATSFontRef fontRef = GetATSFontRef();
  340. ByteCount size;
  341. return fontRef != kInvalidFont &&
  342. (::ATSFontGetTable(fontRef, aTableTag, 0, 0, 0, &size) == noErr);
  343. }
  344. void
  345. ATSFontEntry::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
  346. FontListSizes* aSizes) const
  347. {
  348. aSizes->mFontListSize += aMallocSizeOf(this);
  349. SizeOfExcludingThis(aMallocSizeOf, aSizes);
  350. }
  351. /* CGFontEntry - used on Mac OS X 10.6+ */
  352. #pragma mark-
  353. CGFontEntry::CGFontEntry(const nsAString& aPostscriptName,
  354. PRInt32 aWeight,
  355. gfxFontFamily *aFamily,
  356. bool aIsStandardFace)
  357. : MacOSFontEntry(aPostscriptName, aWeight, aFamily, aIsStandardFace)
  358. {
  359. }
  360. CGFontEntry::CGFontEntry(const nsAString& aPostscriptName,
  361. CGFontRef aFontRef,
  362. PRUint16 aWeight, PRUint16 aStretch,
  363. PRUint32 aItalicStyle,
  364. bool aIsUserFont, bool aIsLocal)
  365. : MacOSFontEntry(aPostscriptName, aWeight, nsnull, false)
  366. {
  367. mFontRef = aFontRef;
  368. mFontRefInitialized = true;
  369. ::CFRetain(mFontRef);
  370. mWeight = aWeight;
  371. mStretch = aStretch;
  372. mFixedPitch = false; // xxx - do we need this for downloaded fonts?
  373. mItalic = (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
  374. mIsUserFont = aIsUserFont;
  375. mIsLocalUserFont = aIsLocal;
  376. }
  377. CGFontRef
  378. CGFontEntry::GetFontRef()
  379. {
  380. if (!mFontRefInitialized) {
  381. mFontRefInitialized = true;
  382. NSString *psname = GetNSStringForString(mName);
  383. mFontRef = ::CGFontCreateWithFontName(CFStringRef(psname));
  384. }
  385. return mFontRef;
  386. }
  387. nsresult
  388. CGFontEntry::GetFontTable(PRUint32 aTableTag, FallibleTArray<PRUint8>& aBuffer)
  389. {
  390. nsAutoreleasePool localPool;
  391. CGFontRef fontRef = GetFontRef();
  392. if (!fontRef) {
  393. return NS_ERROR_FAILURE;
  394. }
  395. CFDataRef tableData = ::CGFontCopyTableForTag(fontRef, aTableTag);
  396. if (!tableData) {
  397. return NS_ERROR_FAILURE;
  398. }
  399. nsresult rval = NS_OK;
  400. CFIndex dataLength = ::CFDataGetLength(tableData);
  401. if (aBuffer.AppendElements(dataLength)) {
  402. ::CFDataGetBytes(tableData, ::CFRangeMake(0, dataLength),
  403. aBuffer.Elements());
  404. } else {
  405. rval = NS_ERROR_OUT_OF_MEMORY;
  406. }
  407. ::CFRelease(tableData);
  408. return rval;
  409. }
  410. bool
  411. CGFontEntry::HasFontTable(PRUint32 aTableTag)
  412. {
  413. nsAutoreleasePool localPool;
  414. CGFontRef fontRef = GetFontRef();
  415. if (!fontRef) {
  416. return false;
  417. }
  418. CFDataRef tableData = ::CGFontCopyTableForTag(fontRef, aTableTag);
  419. if (!tableData) {
  420. return false;
  421. }
  422. ::CFRelease(tableData);
  423. return true;
  424. }
  425. void
  426. CGFontEntry::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
  427. FontListSizes* aSizes) const
  428. {
  429. aSizes->mFontListSize += aMallocSizeOf(this);
  430. SizeOfExcludingThis(aMallocSizeOf, aSizes);
  431. }
  432. /* gfxMacFontFamily */
  433. #pragma mark-
  434. class gfxMacFontFamily : public gfxFontFamily
  435. {
  436. public:
  437. gfxMacFontFamily(nsAString& aName) :
  438. gfxFontFamily(aName)
  439. {}
  440. virtual ~gfxMacFontFamily() {}
  441. virtual void LocalizedName(nsAString& aLocalizedName);
  442. virtual void FindStyleVariations();
  443. };
  444. void
  445. gfxMacFontFamily::LocalizedName(nsAString& aLocalizedName)
  446. {
  447. nsAutoreleasePool localPool;
  448. if (!HasOtherFamilyNames()) {
  449. aLocalizedName = mName;
  450. return;
  451. }
  452. NSString *family = GetNSStringForString(mName);
  453. NSString *localized = [sFontManager
  454. localizedNameForFamily:family
  455. face:nil];
  456. if (localized) {
  457. GetStringForNSString(localized, aLocalizedName);
  458. return;
  459. }
  460. // failed to get localized name, just use the canonical one
  461. aLocalizedName = mName;
  462. }
  463. void
  464. gfxMacFontFamily::FindStyleVariations()
  465. {
  466. if (mHasStyles)
  467. return;
  468. nsAutoreleasePool localPool;
  469. NSString *family = GetNSStringForString(mName);
  470. // create a font entry for each face
  471. NSArray *fontfaces = [sFontManager
  472. availableMembersOfFontFamily:family]; // returns an array of [psname, style name, weight, traits] elements, goofy api
  473. int faceCount = [fontfaces count];
  474. int faceIndex;
  475. // Bug 420981 - under 10.5, UltraLight and Light have the same weight value
  476. bool needToCheckLightFaces =
  477. (gfxPlatformMac::GetPlatform()->OSXVersion() >= MAC_OS_X_VERSION_10_5_HEX);
  478. for (faceIndex = 0; faceIndex < faceCount; faceIndex++) {
  479. NSArray *face = [fontfaces objectAtIndex:faceIndex];
  480. NSString *psname = [face objectAtIndex:INDEX_FONT_POSTSCRIPT_NAME];
  481. PRInt32 appKitWeight = [[face objectAtIndex:INDEX_FONT_WEIGHT] unsignedIntValue];
  482. PRUint32 macTraits = [[face objectAtIndex:INDEX_FONT_TRAITS] unsignedIntValue];
  483. NSString *facename = [face objectAtIndex:INDEX_FONT_FACE_NAME];
  484. bool isStandardFace = false;
  485. if (needToCheckLightFaces && appKitWeight == kAppleExtraLightWeight) {
  486. // if the facename contains UltraLight, set the weight to the ultralight weight value
  487. NSRange range = [facename rangeOfString:@"ultralight" options:NSCaseInsensitiveSearch];
  488. if (range.location != NSNotFound) {
  489. appKitWeight = kAppleUltraLightWeight;
  490. }
  491. }
  492. PRInt32 cssWeight = gfxMacPlatformFontList::AppleWeightToCSSWeight(appKitWeight) * 100;
  493. // make a nsString
  494. nsAutoString postscriptFontName;
  495. GetStringForNSString(psname, postscriptFontName);
  496. if ([facename isEqualToString:@"Regular"] ||
  497. [facename isEqualToString:@"Bold"] ||
  498. [facename isEqualToString:@"Italic"] ||
  499. [facename isEqualToString:@"Oblique"] ||
  500. [facename isEqualToString:@"Bold Italic"] ||
  501. [facename isEqualToString:@"Bold Oblique"])
  502. {
  503. isStandardFace = true;
  504. }
  505. // create a font entry
  506. MacOSFontEntry *fontEntry;
  507. if (gfxMacPlatformFontList::UseATSFontEntry()) {
  508. fontEntry = new ATSFontEntry(postscriptFontName,
  509. cssWeight, this, isStandardFace);
  510. } else {
  511. fontEntry = new CGFontEntry(postscriptFontName,
  512. cssWeight, this, isStandardFace);
  513. }
  514. if (!fontEntry) {
  515. break;
  516. }
  517. // set additional properties based on the traits reported by Cocoa
  518. if (macTraits & (NSCondensedFontMask | NSNarrowFontMask | NSCompressedFontMask)) {
  519. fontEntry->mStretch = NS_FONT_STRETCH_CONDENSED;
  520. } else if (macTraits & NSExpandedFontMask) {
  521. fontEntry->mStretch = NS_FONT_STRETCH_EXPANDED;
  522. }
  523. // Cocoa fails to set the Italic traits bit for HelveticaLightItalic,
  524. // at least (see bug 611855), so check for style name endings as well
  525. if ((macTraits & NSItalicFontMask) ||
  526. [facename hasSuffix:@"Italic"] ||
  527. [facename hasSuffix:@"Oblique"])
  528. {
  529. fontEntry->mItalic = true;
  530. }
  531. if (macTraits & NSFixedPitchFontMask) {
  532. fontEntry->mFixedPitch = true;
  533. }
  534. #ifdef PR_LOGGING
  535. if (LOG_FONTLIST_ENABLED()) {
  536. LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
  537. " with style: %s weight: %d stretch: %d"
  538. " (apple-weight: %d macTraits: %8.8x)",
  539. NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
  540. NS_ConvertUTF16toUTF8(Name()).get(),
  541. fontEntry->IsItalic() ? "italic" : "normal",
  542. cssWeight, fontEntry->Stretch(),
  543. appKitWeight, macTraits));
  544. }
  545. #endif
  546. // insert into font entry array of family
  547. AddFontEntry(fontEntry);
  548. }
  549. SortAvailableFonts();
  550. SetHasStyles(true);
  551. if (mIsBadUnderlineFamily) {
  552. SetBadUnderlineFonts();
  553. }
  554. }
  555. /* gfxSingleFaceMacFontFamily */
  556. #pragma mark-
  557. class gfxSingleFaceMacFontFamily : public gfxFontFamily
  558. {
  559. public:
  560. gfxSingleFaceMacFontFamily(nsAString& aName) :
  561. gfxFontFamily(aName)
  562. {}
  563. virtual ~gfxSingleFaceMacFontFamily() {}
  564. virtual void LocalizedName(nsAString& aLocalizedName);
  565. virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList);
  566. };
  567. void
  568. gfxSingleFaceMacFontFamily::LocalizedName(nsAString& aLocalizedName)
  569. {
  570. nsAutoreleasePool localPool;
  571. if (!HasOtherFamilyNames()) {
  572. aLocalizedName = mName;
  573. return;
  574. }
  575. gfxFontEntry *fe = mAvailableFonts[0];
  576. NSFont *font = [NSFont fontWithName:GetNSStringForString(fe->Name())
  577. size:0.0];
  578. if (font) {
  579. NSString *localized = [font displayName];
  580. if (localized) {
  581. GetStringForNSString(localized, aLocalizedName);
  582. return;
  583. }
  584. }
  585. // failed to get localized name, just use the canonical one
  586. aLocalizedName = mName;
  587. }
  588. void
  589. gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
  590. {
  591. if (mOtherFamilyNamesInitialized)
  592. return;
  593. gfxFontEntry *fe = mAvailableFonts[0];
  594. if (!fe)
  595. return;
  596. const PRUint32 kNAME = TRUETYPE_TAG('n','a','m','e');
  597. AutoFallibleTArray<PRUint8,8192> buffer;
  598. if (fe->GetFontTable(kNAME, buffer) != NS_OK)
  599. return;
  600. mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
  601. buffer,
  602. true);
  603. mOtherFamilyNamesInitialized = true;
  604. }
  605. /* gfxMacPlatformFontList */
  606. #pragma mark-
  607. gfxMacPlatformFontList::gfxMacPlatformFontList() :
  608. gfxPlatformFontList(false), mATSGeneration(PRUint32(kATSGenerationInitial)),
  609. mDefaultFont(nsnull)
  610. {
  611. ::ATSFontNotificationSubscribe(ATSNotification,
  612. kATSFontNotifyOptionDefault,
  613. (void*)this, nsnull);
  614. // this should always be available (though we won't actually fail if it's missing,
  615. // we'll just end up doing a search and then caching the new result instead)
  616. mReplacementCharFallbackFamily = NS_LITERAL_STRING("Lucida Grande");
  617. // cache this in a static variable so that MacOSFontFamily objects
  618. // don't have to repeatedly look it up
  619. sFontManager = [NSFontManager sharedFontManager];
  620. }
  621. gfxMacPlatformFontList::~gfxMacPlatformFontList()
  622. {
  623. if (mDefaultFont) {
  624. ::CFRelease(mDefaultFont);
  625. }
  626. }
  627. nsresult
  628. gfxMacPlatformFontList::InitFontList()
  629. {
  630. nsAutoreleasePool localPool;
  631. ATSGeneration currentGeneration = ::ATSGetGeneration();
  632. // need to ignore notifications after adding each font
  633. if (mATSGeneration == currentGeneration)
  634. return NS_OK;
  635. Telemetry::AutoTimer<Telemetry::MAC_INITFONTLIST_TOTAL> timer;
  636. mATSGeneration = currentGeneration;
  637. #ifdef PR_LOGGING
  638. LOG_FONTLIST(("(fontlist) updating to generation: %d", mATSGeneration));
  639. #endif
  640. // reset font lists
  641. gfxPlatformFontList::InitFontList();
  642. // iterate over available families
  643. NSEnumerator *families = [[sFontManager availableFontFamilies]
  644. objectEnumerator]; // returns "canonical", non-localized family name
  645. nsAutoString availableFamilyName;
  646. NSString *availableFamily = nil;
  647. while ((availableFamily = [families nextObject])) {
  648. // make a nsString
  649. GetStringForNSString(availableFamily, availableFamilyName);
  650. // create a family entry
  651. gfxFontFamily *familyEntry = new gfxMacFontFamily(availableFamilyName);
  652. if (!familyEntry) break;
  653. // add the family entry to the hash table
  654. ToLowerCase(availableFamilyName);
  655. mFontFamilies.Put(availableFamilyName, familyEntry);
  656. // check the bad underline blacklist
  657. if (mBadUnderlineFamilyNames.Contains(availableFamilyName))
  658. familyEntry->SetBadUnderlineFamily();
  659. }
  660. InitSingleFaceList();
  661. // to avoid full search of font name tables, seed the other names table with localized names from
  662. // some of the prefs fonts which are accessed via their localized names. changes in the pref fonts will only cause
  663. // a font lookup miss earlier. this is a simple optimization, it's not required for correctness
  664. PreloadNamesList();
  665. // start the delayed cmap loader
  666. StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps);
  667. return NS_OK;
  668. }
  669. void
  670. gfxMacPlatformFontList::InitSingleFaceList()
  671. {
  672. nsAutoTArray<nsString, 10> singleFaceFonts;
  673. gfxFontUtils::GetPrefsFontList("font.single-face-list", singleFaceFonts);
  674. PRUint32 numFonts = singleFaceFonts.Length();
  675. for (PRUint32 i = 0; i < numFonts; i++) {
  676. #ifdef PR_LOGGING
  677. LOG_FONTLIST(("(fontlist-singleface) face name: %s\n",
  678. NS_ConvertUTF16toUTF8(singleFaceFonts[i]).get()));
  679. #endif
  680. gfxFontEntry *fontEntry = LookupLocalFont(nsnull, singleFaceFonts[i]);
  681. if (fontEntry) {
  682. nsAutoString familyName, key;
  683. familyName = singleFaceFonts[i];
  684. GenerateFontListKey(familyName, key);
  685. #ifdef PR_LOGGING
  686. LOG_FONTLIST(("(fontlist-singleface) family name: %s, key: %s\n",
  687. NS_ConvertUTF16toUTF8(familyName).get(),
  688. NS_ConvertUTF16toUTF8(key).get()));
  689. #endif
  690. // add only if doesn't exist already
  691. if (!mFontFamilies.GetWeak(key)) {
  692. gfxFontFamily *familyEntry =
  693. new gfxSingleFaceMacFontFamily(familyName);
  694. familyEntry->AddFontEntry(fontEntry);
  695. familyEntry->SetHasStyles(true);
  696. mFontFamilies.Put(key, familyEntry);
  697. fontEntry->mFamily = familyEntry;
  698. #ifdef PR_LOGGING
  699. LOG_FONTLIST(("(fontlist-singleface) added new family\n",
  700. NS_ConvertUTF16toUTF8(familyName).get(),
  701. NS_ConvertUTF16toUTF8(key).get()));
  702. #endif
  703. }
  704. }
  705. }
  706. }
  707. bool
  708. gfxMacPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
  709. {
  710. gfxFontFamily *family = FindFamily(aFontName);
  711. if (family) {
  712. family->LocalizedName(aFamilyName);
  713. return true;
  714. }
  715. // Gecko 1.8 used Quickdraw font api's which produce a slightly different set of "family"
  716. // names. Try to resolve based on these names, in case this is stored in an old profile
  717. // 1.8: "Futura", "Futura Condensed" ==> 1.9: "Futura"
  718. // convert the name to a Pascal-style Str255 to try as Quickdraw name
  719. Str255 qdname;
  720. NS_ConvertUTF16toUTF8 utf8name(aFontName);
  721. qdname[0] = NS_MAX<size_t>(255, strlen(utf8name.get()));
  722. memcpy(&qdname[1], utf8name.get(), qdname[0]);
  723. // look up the Quickdraw name
  724. ATSFontFamilyRef atsFamily = ::ATSFontFamilyFindFromQuickDrawName(qdname);
  725. if (atsFamily == (ATSFontFamilyRef)kInvalidFontFamily) {
  726. return false;
  727. }
  728. // if we found a family, get its ATS name
  729. CFStringRef cfName;
  730. OSStatus status = ::ATSFontFamilyGetName(atsFamily, kATSOptionFlagsDefault, &cfName);
  731. if (status != noErr) {
  732. return false;
  733. }
  734. // then use this to locate the family entry and retrieve its localized name
  735. nsAutoString familyName;
  736. GetStringForNSString((const NSString*)cfName, familyName);
  737. ::CFRelease(cfName);
  738. family = FindFamily(familyName);
  739. if (family) {
  740. family->LocalizedName(aFamilyName);
  741. return true;
  742. }
  743. return false;
  744. }
  745. void
  746. gfxMacPlatformFontList::ATSNotification(ATSFontNotificationInfoRef aInfo,
  747. void* aUserArg)
  748. {
  749. // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
  750. gfxMacPlatformFontList *qfc = (gfxMacPlatformFontList*)aUserArg;
  751. qfc->UpdateFontList();
  752. }
  753. gfxFontEntry*
  754. gfxMacPlatformFontList::GlobalFontFallback(const PRUint32 aCh,
  755. PRInt32 aRunScript,
  756. const gfxFontStyle* aMatchStyle,
  757. PRUint32& aCmapCount)
  758. {
  759. bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
  760. if (useCmaps) {
  761. return gfxPlatformFontList::GlobalFontFallback(aCh,
  762. aRunScript,
  763. aMatchStyle,
  764. aCmapCount);
  765. }
  766. CFStringRef str;
  767. UniChar ch[2];
  768. CFIndex len = 1;
  769. if (IS_IN_BMP(aCh)) {
  770. ch[0] = aCh;
  771. str = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 1,
  772. kCFAllocatorNull);
  773. } else {
  774. ch[0] = H_SURROGATE(aCh);
  775. ch[1] = L_SURROGATE(aCh);
  776. str = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 2,
  777. kCFAllocatorNull);
  778. if (!str) {
  779. return nsnull;
  780. }
  781. len = 2;
  782. }
  783. // use CoreText to find the fallback family
  784. gfxFontEntry *fontEntry = nsnull;
  785. CTFontRef fallback;
  786. bool cantUseFallbackFont = false;
  787. if (!mDefaultFont) {
  788. mDefaultFont = ::CTFontCreateWithName(CFSTR("Lucida Grande"), 12.f,
  789. NULL);
  790. }
  791. fallback = ::CTFontCreateForString(mDefaultFont, str,
  792. ::CFRangeMake(0, len));
  793. if (fallback) {
  794. CFStringRef familyName = ::CTFontCopyFamilyName(fallback);
  795. ::CFRelease(fallback);
  796. if (familyName &&
  797. ::CFStringCompare(familyName, CFSTR("LastResort"),
  798. kCFCompareCaseInsensitive) != kCFCompareEqualTo)
  799. {
  800. nsAutoTArray<UniChar, 1024> buffer;
  801. CFIndex len = ::CFStringGetLength(familyName);
  802. buffer.SetLength(len+1);
  803. ::CFStringGetCharacters(familyName, ::CFRangeMake(0, len),
  804. buffer.Elements());
  805. buffer[len] = 0;
  806. nsDependentString family(buffer.Elements(), len);
  807. bool needsBold; // ignored in the system fallback case
  808. fontEntry = FindFontForFamily(family, aMatchStyle, needsBold);
  809. if (fontEntry && !fontEntry->TestCharacterMap(aCh)) {
  810. fontEntry = nsnull;
  811. cantUseFallbackFont = true;
  812. }
  813. }
  814. if (familyName) {
  815. ::CFRelease(familyName);
  816. }
  817. }
  818. if (cantUseFallbackFont) {
  819. Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, cantUseFallbackFont);
  820. }
  821. ::CFRelease(str);
  822. return fontEntry;
  823. }
  824. gfxFontEntry*
  825. gfxMacPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle, bool& aNeedsBold)
  826. {
  827. nsAutoreleasePool localPool;
  828. NSString *defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
  829. nsAutoString familyName;
  830. GetStringForNSString(defaultFamily, familyName);
  831. return FindFontForFamily(familyName, aStyle, aNeedsBold);
  832. }
  833. PRInt32
  834. gfxMacPlatformFontList::AppleWeightToCSSWeight(PRInt32 aAppleWeight)
  835. {
  836. if (aAppleWeight < 1)
  837. aAppleWeight = 1;
  838. else if (aAppleWeight > kAppleMaxWeight)
  839. aAppleWeight = kAppleMaxWeight;
  840. return gAppleWeightToCSSWeight[aAppleWeight];
  841. }
  842. gfxFontEntry*
  843. gfxMacPlatformFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
  844. const nsAString& aFontName)
  845. {
  846. nsAutoreleasePool localPool;
  847. NSString *faceName = GetNSStringForString(aFontName);
  848. MacOSFontEntry *newFontEntry;
  849. if (UseATSFontEntry()) {
  850. // first lookup a single face based on postscript name
  851. ATSFontRef fontRef = ::ATSFontFindFromPostScriptName(CFStringRef(faceName),
  852. kATSOptionFlagsDefault);
  853. // if not found, lookup using full font name
  854. if (fontRef == kInvalidFont) {
  855. fontRef = ::ATSFontFindFromName(CFStringRef(faceName),
  856. kATSOptionFlagsDefault);
  857. if (fontRef == kInvalidFont) {
  858. return nsnull;
  859. }
  860. }
  861. if (aProxyEntry) {
  862. PRUint16 w = aProxyEntry->mWeight;
  863. NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
  864. newFontEntry =
  865. new ATSFontEntry(aFontName, fontRef,
  866. w, aProxyEntry->mStretch,
  867. aProxyEntry->mItalic ?
  868. NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL,
  869. nsnull, true);
  870. } else {
  871. newFontEntry =
  872. new ATSFontEntry(aFontName, fontRef,
  873. 400, 0, NS_FONT_STYLE_NORMAL, nsnull, false);
  874. }
  875. } else {
  876. // lookup face based on postscript or full name
  877. CGFontRef fontRef = ::CGFontCreateWithFontName(CFStringRef(faceName));
  878. if (!fontRef) {
  879. return nsnull;
  880. }
  881. if (aProxyEntry) {
  882. PRUint16 w = aProxyEntry->mWeight;
  883. NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
  884. newFontEntry =
  885. new CGFontEntry(aFontName, fontRef,
  886. w, aProxyEntry->mStretch,
  887. aProxyEntry->mItalic ?
  888. NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL,
  889. true, true);
  890. } else {
  891. newFontEntry =
  892. new CGFontEntry(aFontName, fontRef,
  893. 400, 0, NS_FONT_STYLE_NORMAL,
  894. false, false);
  895. }
  896. ::CFRelease(fontRef);
  897. }
  898. return newFontEntry;
  899. }
  900. gfxFontEntry*
  901. gfxMacPlatformFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
  902. const PRUint8 *aFontData,
  903. PRUint32 aLength)
  904. {
  905. return UseATSFontEntry()
  906. ? MakePlatformFontATS(aProxyEntry, aFontData, aLength)
  907. : MakePlatformFontCG(aProxyEntry, aFontData, aLength);
  908. }
  909. static void ReleaseData(void *info, const void *data, size_t size)
  910. {
  911. NS_Free((void*)data);
  912. }
  913. gfxFontEntry*
  914. gfxMacPlatformFontList::MakePlatformFontCG(const gfxProxyFontEntry *aProxyEntry,
  915. const PRUint8 *aFontData,
  916. PRUint32 aLength)
  917. {
  918. NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
  919. PRUint16 w = aProxyEntry->mWeight;
  920. NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
  921. // create the font entry
  922. nsAutoString uniqueName;
  923. nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
  924. if (NS_FAILED(rv)) {
  925. return nsnull;
  926. }
  927. CGDataProviderRef provider =
  928. ::CGDataProviderCreateWithData(nsnull, aFontData, aLength,
  929. &ReleaseData);
  930. CGFontRef fontRef = ::CGFontCreateWithDataProvider(provider);
  931. ::CGDataProviderRelease(provider);
  932. if (!fontRef) {
  933. return nsnull;
  934. }
  935. nsAutoPtr<CGFontEntry>
  936. newFontEntry(new CGFontEntry(uniqueName, fontRef, w,
  937. aProxyEntry->mStretch,
  938. aProxyEntry->mItalic ?
  939. NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL,
  940. true, false));
  941. ::CFRelease(fontRef);
  942. // if succeeded and font cmap is good, return the new font
  943. if (newFontEntry->mIsValid && NS_SUCCEEDED(newFontEntry->ReadCMAP())) {
  944. return newFontEntry.forget();
  945. }
  946. // if something is funky about this font, delete immediately
  947. #if DEBUG
  948. char warnBuf[1024];
  949. sprintf(warnBuf, "downloaded font not loaded properly, removed face for (%s)",
  950. NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
  951. NS_WARNING(warnBuf);
  952. #endif
  953. return nsnull;
  954. }
  955. // grumble, another non-publised Apple API dependency (found in Webkit code)
  956. // activated with this value, font will not be found via system lookup routines
  957. // it can only be used via the created ATSFontRef
  958. // needed to prevent one doc from finding a font used in a separate doc
  959. enum {
  960. kPrivateATSFontContextPrivate = 3
  961. };
  962. class ATSUserFontData : public gfxUserFontData {
  963. public:
  964. ATSUserFontData(ATSFontContainerRef aContainerRef)
  965. : mContainerRef(aContainerRef)
  966. { }
  967. virtual ~ATSUserFontData()
  968. {
  969. // deactivate font
  970. if (mContainerRef) {
  971. ::ATSFontDeactivate(mContainerRef, NULL, kATSOptionFlagsDefault);
  972. }
  973. }
  974. ATSFontContainerRef mContainerRef;
  975. };
  976. gfxFontEntry*
  977. gfxMacPlatformFontList::MakePlatformFontATS(const gfxProxyFontEntry *aProxyEntry,
  978. const PRUint8 *aFontData,
  979. PRUint32 aLength)
  980. {
  981. OSStatus err;
  982. NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
  983. // MakePlatformFont is responsible for deleting the font data with NS_Free
  984. // so we set up a stack object to ensure it is freed even if we take an
  985. // early exit
  986. struct FontDataDeleter {
  987. FontDataDeleter(const PRUint8 *aFontData)
  988. : mFontData(aFontData) { }
  989. ~FontDataDeleter() { NS_Free((void*)mFontData); }
  990. const PRUint8 *mFontData;
  991. };
  992. FontDataDeleter autoDelete(aFontData);
  993. ATSFontRef fontRef;
  994. ATSFontContainerRef containerRef;
  995. // we get occasional failures when multiple fonts are activated in quick succession
  996. // if the ATS font cache is damaged; to work around this, we can retry the activation
  997. const PRUint32 kMaxRetries = 3;
  998. PRUint32 retryCount = 0;
  999. while (retryCount++ < kMaxRetries) {
  1000. err = ::ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength,
  1001. kPrivateATSFontContextPrivate,
  1002. kATSFontFormatUnspecified,
  1003. NULL,
  1004. kATSOptionFlagsDoNotNotify,
  1005. &containerRef);
  1006. mATSGeneration = ::ATSGetGeneration();
  1007. if (err != noErr) {
  1008. #if DEBUG
  1009. char warnBuf[1024];
  1010. sprintf(warnBuf, "downloaded font error, ATSFontActivateFromMemory err: %d for (%s)",
  1011. PRInt32(err),
  1012. NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
  1013. NS_WARNING(warnBuf);
  1014. #endif
  1015. return nsnull;
  1016. }
  1017. // ignoring containers with multiple fonts, use the first face only for now
  1018. err = ::ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1,
  1019. &fontRef, NULL);
  1020. if (err != noErr) {
  1021. #if DEBUG
  1022. char warnBuf[1024];
  1023. sprintf(warnBuf, "downloaded font error, ATSFontFindFromContainer err: %d for (%s)",
  1024. PRInt32(err),
  1025. NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
  1026. NS_WARNING(warnBuf);
  1027. #endif
  1028. ::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
  1029. return nsnull;
  1030. }
  1031. // now lookup the Postscript name; this may fail if the font cache is bad
  1032. OSStatus err;
  1033. NSString *psname = NULL;
  1034. err = ::ATSFontGetPostScriptName(fontRef, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
  1035. if (err == noErr) {
  1036. [psname release];
  1037. } else {
  1038. #ifdef DEBUG
  1039. char warnBuf[1024];
  1040. sprintf(warnBuf, "ATSFontGetPostScriptName err = %d for (%s), retries = %d", (PRInt32)err,
  1041. NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get(), retryCount);
  1042. NS_WARNING(warnBuf);
  1043. #endif
  1044. ::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
  1045. // retry the activation a couple of times if this fails
  1046. // (may be a transient failure due to ATS font cache issues)
  1047. continue;
  1048. }
  1049. PRUint16 w = aProxyEntry->mWeight;
  1050. NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
  1051. nsAutoString uniqueName;
  1052. nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
  1053. if (NS_FAILED(rv)) {
  1054. return nsnull;
  1055. }
  1056. // font entry will own this
  1057. ATSUserFontData *userFontData = new ATSUserFontData(containerRef);
  1058. ATSFontEntry *newFontEntry =
  1059. new ATSFontEntry(uniqueName,
  1060. fontRef,
  1061. w, aProxyEntry->mStretch,
  1062. aProxyEntry->mItalic ?
  1063. NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL,
  1064. userFontData, false);
  1065. // if succeeded and font cmap is good, return the new font
  1066. if (newFontEntry->mIsValid && NS_SUCCEEDED(newFontEntry->ReadCMAP())) {
  1067. return newFontEntry;
  1068. }
  1069. // if something is funky about this font, delete immediately
  1070. #if DEBUG
  1071. char warnBuf[1024];
  1072. sprintf(warnBuf, "downloaded font not loaded properly, removed face for (%s)",
  1073. NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
  1074. NS_WARNING(warnBuf);
  1075. #endif
  1076. delete newFontEntry;
  1077. // We don't retry from here; the ATS font cache issue would have caused failure earlier
  1078. // so if we get here, there's something else bad going on within our font data structures.
  1079. // Currently, there should be no way to reach here, as fontentry creation cannot fail
  1080. // except by memory allocation failure.
  1081. NS_WARNING("invalid font entry for a newly activated font");
  1082. break;
  1083. }
  1084. // if we get here, the activation failed (even with possible retries); can't use this font
  1085. return nsnull;
  1086. }