gfx/thebes/gfxMacPlatformFontList.mm

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: ObjC; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * ***** BEGIN LICENSE BLOCK *****
michael@0 3 * Version: BSD
michael@0 4 *
michael@0 5 * Copyright (C) 2006-2009 Mozilla Corporation. All rights reserved.
michael@0 6 *
michael@0 7 * Contributor(s):
michael@0 8 * Vladimir Vukicevic <vladimir@pobox.com>
michael@0 9 * Masayuki Nakano <masayuki@d-toybox.com>
michael@0 10 * John Daggett <jdaggett@mozilla.com>
michael@0 11 * Jonathan Kew <jfkthame@gmail.com>
michael@0 12 *
michael@0 13 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
michael@0 14 *
michael@0 15 * Redistribution and use in source and binary forms, with or without
michael@0 16 * modification, are permitted provided that the following conditions
michael@0 17 * are met:
michael@0 18 *
michael@0 19 * 1. Redistributions of source code must retain the above copyright
michael@0 20 * notice, this list of conditions and the following disclaimer.
michael@0 21 * 2. Redistributions in binary form must reproduce the above copyright
michael@0 22 * notice, this list of conditions and the following disclaimer in the
michael@0 23 * documentation and/or other materials provided with the distribution.
michael@0 24 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
michael@0 25 * its contributors may be used to endorse or promote products derived
michael@0 26 * from this software without specific prior written permission.
michael@0 27 *
michael@0 28 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
michael@0 29 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
michael@0 30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
michael@0 31 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
michael@0 32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
michael@0 33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
michael@0 34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
michael@0 35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
michael@0 37 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 38 *
michael@0 39 * ***** END LICENSE BLOCK ***** */
michael@0 40
michael@0 41 #ifdef MOZ_LOGGING
michael@0 42 #define FORCE_PR_LOG /* Allow logging in the release build */
michael@0 43 #endif
michael@0 44 #include "prlog.h"
michael@0 45
michael@0 46 #include <algorithm>
michael@0 47
michael@0 48 #import <AppKit/AppKit.h>
michael@0 49
michael@0 50 #include "gfxPlatformMac.h"
michael@0 51 #include "gfxMacPlatformFontList.h"
michael@0 52 #include "gfxMacFont.h"
michael@0 53 #include "gfxUserFontSet.h"
michael@0 54 #include "harfbuzz/hb.h"
michael@0 55
michael@0 56 #include "nsServiceManagerUtils.h"
michael@0 57 #include "nsTArray.h"
michael@0 58
michael@0 59 #include "nsDirectoryServiceUtils.h"
michael@0 60 #include "nsDirectoryServiceDefs.h"
michael@0 61 #include "nsISimpleEnumerator.h"
michael@0 62 #include "nsCharTraits.h"
michael@0 63 #include "nsCocoaFeatures.h"
michael@0 64 #include "gfxFontConstants.h"
michael@0 65
michael@0 66 #include "mozilla/MemoryReporting.h"
michael@0 67 #include "mozilla/Preferences.h"
michael@0 68 #include "mozilla/Telemetry.h"
michael@0 69 #include "mozilla/gfx/2D.h"
michael@0 70
michael@0 71 #include <unistd.h>
michael@0 72 #include <time.h>
michael@0 73
michael@0 74 using namespace mozilla;
michael@0 75
michael@0 76 class nsAutoreleasePool {
michael@0 77 public:
michael@0 78 nsAutoreleasePool()
michael@0 79 {
michael@0 80 mLocalPool = [[NSAutoreleasePool alloc] init];
michael@0 81 }
michael@0 82 ~nsAutoreleasePool()
michael@0 83 {
michael@0 84 [mLocalPool release];
michael@0 85 }
michael@0 86 private:
michael@0 87 NSAutoreleasePool *mLocalPool;
michael@0 88 };
michael@0 89
michael@0 90 // indexes into the NSArray objects that the Cocoa font manager returns
michael@0 91 // as the available members of a family
michael@0 92 #define INDEX_FONT_POSTSCRIPT_NAME 0
michael@0 93 #define INDEX_FONT_FACE_NAME 1
michael@0 94 #define INDEX_FONT_WEIGHT 2
michael@0 95 #define INDEX_FONT_TRAITS 3
michael@0 96
michael@0 97 static const int kAppleMaxWeight = 14;
michael@0 98 static const int kAppleExtraLightWeight = 3;
michael@0 99 static const int kAppleUltraLightWeight = 2;
michael@0 100
michael@0 101 static const int gAppleWeightToCSSWeight[] = {
michael@0 102 0,
michael@0 103 1, // 1.
michael@0 104 1, // 2. W1, ultralight
michael@0 105 2, // 3. W2, extralight
michael@0 106 3, // 4. W3, light
michael@0 107 4, // 5. W4, semilight
michael@0 108 5, // 6. W5, medium
michael@0 109 6, // 7.
michael@0 110 6, // 8. W6, semibold
michael@0 111 7, // 9. W7, bold
michael@0 112 8, // 10. W8, extrabold
michael@0 113 8, // 11.
michael@0 114 9, // 12. W9, ultrabold
michael@0 115 9, // 13
michael@0 116 9 // 14
michael@0 117 };
michael@0 118
michael@0 119 // cache Cocoa's "shared font manager" for performance
michael@0 120 static NSFontManager *sFontManager;
michael@0 121
michael@0 122 static void GetStringForNSString(const NSString *aSrc, nsAString& aDist)
michael@0 123 {
michael@0 124 aDist.SetLength([aSrc length]);
michael@0 125 [aSrc getCharacters:reinterpret_cast<unichar*>(aDist.BeginWriting())];
michael@0 126 }
michael@0 127
michael@0 128 static NSString* GetNSStringForString(const nsAString& aSrc)
michael@0 129 {
michael@0 130 return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(aSrc.BeginReading())
michael@0 131 length:aSrc.Length()];
michael@0 132 }
michael@0 133
michael@0 134 #ifdef PR_LOGGING
michael@0 135
michael@0 136 #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
michael@0 137 PR_LOG_DEBUG, args)
michael@0 138 #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
michael@0 139 gfxPlatform::GetLog(eGfxLog_fontlist), \
michael@0 140 PR_LOG_DEBUG)
michael@0 141 #define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
michael@0 142 gfxPlatform::GetLog(eGfxLog_cmapdata), \
michael@0 143 PR_LOG_DEBUG)
michael@0 144
michael@0 145 #endif // PR_LOGGING
michael@0 146
michael@0 147 #pragma mark-
michael@0 148
michael@0 149 // Complex scripts will not render correctly unless appropriate AAT or OT
michael@0 150 // layout tables are present.
michael@0 151 // For OpenType, we also check that the GSUB table supports the relevant
michael@0 152 // script tag, to avoid using things like Arial Unicode MS for Lao (it has
michael@0 153 // the characters, but lacks OpenType support).
michael@0 154
michael@0 155 // TODO: consider whether we should move this to gfxFontEntry and do similar
michael@0 156 // cmap-masking on other platforms to avoid using fonts that won't shape
michael@0 157 // properly.
michael@0 158
michael@0 159 nsresult
michael@0 160 MacOSFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
michael@0 161 {
michael@0 162 // attempt this once, if errors occur leave a blank cmap
michael@0 163 if (mCharacterMap) {
michael@0 164 return NS_OK;
michael@0 165 }
michael@0 166
michael@0 167 nsRefPtr<gfxCharacterMap> charmap;
michael@0 168 nsresult rv;
michael@0 169 bool symbolFont;
michael@0 170
michael@0 171 if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
michael@0 172 mUVSOffset,
michael@0 173 symbolFont))) {
michael@0 174 rv = NS_OK;
michael@0 175 } else {
michael@0 176 uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
michael@0 177 charmap = new gfxCharacterMap();
michael@0 178 AutoTable cmapTable(this, kCMAP);
michael@0 179
michael@0 180 if (cmapTable) {
michael@0 181 bool unicodeFont = false, symbolFont = false; // currently ignored
michael@0 182 uint32_t cmapLen;
michael@0 183 const uint8_t* cmapData =
michael@0 184 reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
michael@0 185 &cmapLen));
michael@0 186 rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
michael@0 187 *charmap, mUVSOffset,
michael@0 188 unicodeFont, symbolFont);
michael@0 189 } else {
michael@0 190 rv = NS_ERROR_NOT_AVAILABLE;
michael@0 191 }
michael@0 192 }
michael@0 193
michael@0 194 if (NS_SUCCEEDED(rv) && !HasGraphiteTables()) {
michael@0 195 // We assume a Graphite font knows what it's doing,
michael@0 196 // and provides whatever shaping is needed for the
michael@0 197 // characters it supports, so only check/clear the
michael@0 198 // complex-script ranges for non-Graphite fonts
michael@0 199
michael@0 200 // for layout support, check for the presence of mort/morx and/or
michael@0 201 // opentype layout tables
michael@0 202 bool hasAATLayout = HasFontTable(TRUETYPE_TAG('m','o','r','x')) ||
michael@0 203 HasFontTable(TRUETYPE_TAG('m','o','r','t'));
michael@0 204 bool hasGSUB = HasFontTable(TRUETYPE_TAG('G','S','U','B'));
michael@0 205 bool hasGPOS = HasFontTable(TRUETYPE_TAG('G','P','O','S'));
michael@0 206 if (hasAATLayout && !(hasGSUB || hasGPOS)) {
michael@0 207 mRequiresAAT = true; // prefer CoreText if font has no OTL tables
michael@0 208 }
michael@0 209
michael@0 210 for (const ScriptRange* sr = gfxPlatformFontList::sComplexScriptRanges;
michael@0 211 sr->rangeStart; sr++) {
michael@0 212 // check to see if the cmap includes complex script codepoints
michael@0 213 if (charmap->TestRange(sr->rangeStart, sr->rangeEnd)) {
michael@0 214 if (hasAATLayout) {
michael@0 215 // prefer CoreText for Apple's complex-script fonts,
michael@0 216 // even if they also have some OpenType tables
michael@0 217 // (e.g. Geeza Pro Bold on 10.6; see bug 614903)
michael@0 218 mRequiresAAT = true;
michael@0 219 // and don't mask off complex-script ranges, we assume
michael@0 220 // the AAT tables will provide the necessary shaping
michael@0 221 continue;
michael@0 222 }
michael@0 223
michael@0 224 // We check for GSUB here, as GPOS alone would not be ok.
michael@0 225 if (hasGSUB && SupportsScriptInGSUB(sr->tags)) {
michael@0 226 continue;
michael@0 227 }
michael@0 228
michael@0 229 charmap->ClearRange(sr->rangeStart, sr->rangeEnd);
michael@0 230 }
michael@0 231 }
michael@0 232 }
michael@0 233
michael@0 234 mHasCmapTable = NS_SUCCEEDED(rv);
michael@0 235 if (mHasCmapTable) {
michael@0 236 gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
michael@0 237 mCharacterMap = pfl->FindCharMap(charmap);
michael@0 238 } else {
michael@0 239 // if error occurred, initialize to null cmap
michael@0 240 mCharacterMap = new gfxCharacterMap();
michael@0 241 }
michael@0 242
michael@0 243 #ifdef PR_LOGGING
michael@0 244 LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
michael@0 245 NS_ConvertUTF16toUTF8(mName).get(),
michael@0 246 charmap->SizeOfIncludingThis(moz_malloc_size_of),
michael@0 247 charmap->mHash, mCharacterMap == charmap ? " new" : ""));
michael@0 248 if (LOG_CMAPDATA_ENABLED()) {
michael@0 249 char prefix[256];
michael@0 250 sprintf(prefix, "(cmapdata) name: %.220s",
michael@0 251 NS_ConvertUTF16toUTF8(mName).get());
michael@0 252 charmap->Dump(prefix, eGfxLog_cmapdata);
michael@0 253 }
michael@0 254 #endif
michael@0 255
michael@0 256 return rv;
michael@0 257 }
michael@0 258
michael@0 259 gfxFont*
michael@0 260 MacOSFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold)
michael@0 261 {
michael@0 262 return new gfxMacFont(this, aFontStyle, aNeedsBold);
michael@0 263 }
michael@0 264
michael@0 265 bool
michael@0 266 MacOSFontEntry::IsCFF()
michael@0 267 {
michael@0 268 if (!mIsCFFInitialized) {
michael@0 269 mIsCFFInitialized = true;
michael@0 270 mIsCFF = HasFontTable(TRUETYPE_TAG('C','F','F',' '));
michael@0 271 }
michael@0 272
michael@0 273 return mIsCFF;
michael@0 274 }
michael@0 275
michael@0 276 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
michael@0 277 int32_t aWeight,
michael@0 278 bool aIsStandardFace)
michael@0 279 : gfxFontEntry(aPostscriptName, aIsStandardFace),
michael@0 280 mFontRef(NULL),
michael@0 281 mFontRefInitialized(false),
michael@0 282 mRequiresAAT(false),
michael@0 283 mIsCFF(false),
michael@0 284 mIsCFFInitialized(false)
michael@0 285 {
michael@0 286 mWeight = aWeight;
michael@0 287 }
michael@0 288
michael@0 289 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
michael@0 290 CGFontRef aFontRef,
michael@0 291 uint16_t aWeight, uint16_t aStretch,
michael@0 292 uint32_t aItalicStyle,
michael@0 293 bool aIsUserFont, bool aIsLocal)
michael@0 294 : gfxFontEntry(aPostscriptName, false),
michael@0 295 mFontRef(NULL),
michael@0 296 mFontRefInitialized(false),
michael@0 297 mRequiresAAT(false),
michael@0 298 mIsCFF(false),
michael@0 299 mIsCFFInitialized(false)
michael@0 300 {
michael@0 301 mFontRef = aFontRef;
michael@0 302 mFontRefInitialized = true;
michael@0 303 ::CFRetain(mFontRef);
michael@0 304
michael@0 305 mWeight = aWeight;
michael@0 306 mStretch = aStretch;
michael@0 307 mFixedPitch = false; // xxx - do we need this for downloaded fonts?
michael@0 308 mItalic = (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
michael@0 309 mIsUserFont = aIsUserFont;
michael@0 310 mIsLocalUserFont = aIsLocal;
michael@0 311 }
michael@0 312
michael@0 313 CGFontRef
michael@0 314 MacOSFontEntry::GetFontRef()
michael@0 315 {
michael@0 316 if (!mFontRefInitialized) {
michael@0 317 mFontRefInitialized = true;
michael@0 318 NSString *psname = GetNSStringForString(mName);
michael@0 319 mFontRef = ::CGFontCreateWithFontName(CFStringRef(psname));
michael@0 320 }
michael@0 321 return mFontRef;
michael@0 322 }
michael@0 323
michael@0 324 /*static*/ void
michael@0 325 MacOSFontEntry::DestroyBlobFunc(void* aUserData)
michael@0 326 {
michael@0 327 ::CFRelease((CFDataRef)aUserData);
michael@0 328 }
michael@0 329
michael@0 330 hb_blob_t *
michael@0 331 MacOSFontEntry::GetFontTable(uint32_t aTag)
michael@0 332 {
michael@0 333 CGFontRef fontRef = GetFontRef();
michael@0 334 if (!fontRef) {
michael@0 335 return nullptr;
michael@0 336 }
michael@0 337
michael@0 338 CFDataRef dataRef = ::CGFontCopyTableForTag(fontRef, aTag);
michael@0 339 if (dataRef) {
michael@0 340 return hb_blob_create((const char*)::CFDataGetBytePtr(dataRef),
michael@0 341 ::CFDataGetLength(dataRef),
michael@0 342 HB_MEMORY_MODE_READONLY,
michael@0 343 (void*)dataRef, DestroyBlobFunc);
michael@0 344 }
michael@0 345
michael@0 346 return nullptr;
michael@0 347 }
michael@0 348
michael@0 349 bool
michael@0 350 MacOSFontEntry::HasFontTable(uint32_t aTableTag)
michael@0 351 {
michael@0 352 nsAutoreleasePool localPool;
michael@0 353
michael@0 354 CGFontRef fontRef = GetFontRef();
michael@0 355 if (!fontRef) {
michael@0 356 return false;
michael@0 357 }
michael@0 358
michael@0 359 CFDataRef tableData = ::CGFontCopyTableForTag(fontRef, aTableTag);
michael@0 360 if (!tableData) {
michael@0 361 return false;
michael@0 362 }
michael@0 363
michael@0 364 ::CFRelease(tableData);
michael@0 365 return true;
michael@0 366 }
michael@0 367
michael@0 368 void
michael@0 369 MacOSFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
michael@0 370 FontListSizes* aSizes) const
michael@0 371 {
michael@0 372 aSizes->mFontListSize += aMallocSizeOf(this);
michael@0 373 AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
michael@0 374 }
michael@0 375
michael@0 376 /* gfxMacFontFamily */
michael@0 377 #pragma mark-
michael@0 378
michael@0 379 class gfxMacFontFamily : public gfxFontFamily
michael@0 380 {
michael@0 381 public:
michael@0 382 gfxMacFontFamily(nsAString& aName) :
michael@0 383 gfxFontFamily(aName)
michael@0 384 {}
michael@0 385
michael@0 386 virtual ~gfxMacFontFamily() {}
michael@0 387
michael@0 388 virtual void LocalizedName(nsAString& aLocalizedName);
michael@0 389
michael@0 390 virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr);
michael@0 391 };
michael@0 392
michael@0 393 void
michael@0 394 gfxMacFontFamily::LocalizedName(nsAString& aLocalizedName)
michael@0 395 {
michael@0 396 nsAutoreleasePool localPool;
michael@0 397
michael@0 398 if (!HasOtherFamilyNames()) {
michael@0 399 aLocalizedName = mName;
michael@0 400 return;
michael@0 401 }
michael@0 402
michael@0 403 NSString *family = GetNSStringForString(mName);
michael@0 404 NSString *localized = [sFontManager
michael@0 405 localizedNameForFamily:family
michael@0 406 face:nil];
michael@0 407
michael@0 408 if (localized) {
michael@0 409 GetStringForNSString(localized, aLocalizedName);
michael@0 410 return;
michael@0 411 }
michael@0 412
michael@0 413 // failed to get localized name, just use the canonical one
michael@0 414 aLocalizedName = mName;
michael@0 415 }
michael@0 416
michael@0 417 // Return the CSS weight value to use for the given face, overriding what
michael@0 418 // AppKit gives us (used to adjust families with bad weight values, see
michael@0 419 // bug 931426).
michael@0 420 // A return value of 0 indicates no override - use the existing weight.
michael@0 421 static inline int
michael@0 422 GetWeightOverride(const nsAString& aPSName)
michael@0 423 {
michael@0 424 nsAutoCString prefName("font.weight-override.");
michael@0 425 // The PostScript name is required to be ASCII; if it's not, the font is
michael@0 426 // broken anyway, so we really don't care that this is lossy.
michael@0 427 LossyAppendUTF16toASCII(aPSName, prefName);
michael@0 428 return Preferences::GetInt(prefName.get(), 0);
michael@0 429 }
michael@0 430
michael@0 431 void
michael@0 432 gfxMacFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
michael@0 433 {
michael@0 434 if (mHasStyles)
michael@0 435 return;
michael@0 436
michael@0 437 nsAutoreleasePool localPool;
michael@0 438
michael@0 439 NSString *family = GetNSStringForString(mName);
michael@0 440
michael@0 441 // create a font entry for each face
michael@0 442 NSArray *fontfaces = [sFontManager
michael@0 443 availableMembersOfFontFamily:family]; // returns an array of [psname, style name, weight, traits] elements, goofy api
michael@0 444 int faceCount = [fontfaces count];
michael@0 445 int faceIndex;
michael@0 446
michael@0 447 for (faceIndex = 0; faceIndex < faceCount; faceIndex++) {
michael@0 448 NSArray *face = [fontfaces objectAtIndex:faceIndex];
michael@0 449 NSString *psname = [face objectAtIndex:INDEX_FONT_POSTSCRIPT_NAME];
michael@0 450 int32_t appKitWeight = [[face objectAtIndex:INDEX_FONT_WEIGHT] unsignedIntValue];
michael@0 451 uint32_t macTraits = [[face objectAtIndex:INDEX_FONT_TRAITS] unsignedIntValue];
michael@0 452 NSString *facename = [face objectAtIndex:INDEX_FONT_FACE_NAME];
michael@0 453 bool isStandardFace = false;
michael@0 454
michael@0 455 if (appKitWeight == kAppleExtraLightWeight) {
michael@0 456 // if the facename contains UltraLight, set the weight to the ultralight weight value
michael@0 457 NSRange range = [facename rangeOfString:@"ultralight" options:NSCaseInsensitiveSearch];
michael@0 458 if (range.location != NSNotFound) {
michael@0 459 appKitWeight = kAppleUltraLightWeight;
michael@0 460 }
michael@0 461 }
michael@0 462
michael@0 463 // make a nsString
michael@0 464 nsAutoString postscriptFontName;
michael@0 465 GetStringForNSString(psname, postscriptFontName);
michael@0 466
michael@0 467 int32_t cssWeight = GetWeightOverride(postscriptFontName);
michael@0 468 if (cssWeight) {
michael@0 469 // scale down and clamp, to get a value from 1..9
michael@0 470 cssWeight = ((cssWeight + 50) / 100);
michael@0 471 cssWeight = std::max(1, std::min(cssWeight, 9));
michael@0 472 } else {
michael@0 473 cssWeight =
michael@0 474 gfxMacPlatformFontList::AppleWeightToCSSWeight(appKitWeight);
michael@0 475 }
michael@0 476 cssWeight *= 100; // scale up to CSS values
michael@0 477
michael@0 478 if ([facename isEqualToString:@"Regular"] ||
michael@0 479 [facename isEqualToString:@"Bold"] ||
michael@0 480 [facename isEqualToString:@"Italic"] ||
michael@0 481 [facename isEqualToString:@"Oblique"] ||
michael@0 482 [facename isEqualToString:@"Bold Italic"] ||
michael@0 483 [facename isEqualToString:@"Bold Oblique"])
michael@0 484 {
michael@0 485 isStandardFace = true;
michael@0 486 }
michael@0 487
michael@0 488 // create a font entry
michael@0 489 MacOSFontEntry *fontEntry =
michael@0 490 new MacOSFontEntry(postscriptFontName, cssWeight, isStandardFace);
michael@0 491 if (!fontEntry) {
michael@0 492 break;
michael@0 493 }
michael@0 494
michael@0 495 // set additional properties based on the traits reported by Cocoa
michael@0 496 if (macTraits & (NSCondensedFontMask | NSNarrowFontMask | NSCompressedFontMask)) {
michael@0 497 fontEntry->mStretch = NS_FONT_STRETCH_CONDENSED;
michael@0 498 } else if (macTraits & NSExpandedFontMask) {
michael@0 499 fontEntry->mStretch = NS_FONT_STRETCH_EXPANDED;
michael@0 500 }
michael@0 501 // Cocoa fails to set the Italic traits bit for HelveticaLightItalic,
michael@0 502 // at least (see bug 611855), so check for style name endings as well
michael@0 503 if ((macTraits & NSItalicFontMask) ||
michael@0 504 [facename hasSuffix:@"Italic"] ||
michael@0 505 [facename hasSuffix:@"Oblique"])
michael@0 506 {
michael@0 507 fontEntry->mItalic = true;
michael@0 508 }
michael@0 509 if (macTraits & NSFixedPitchFontMask) {
michael@0 510 fontEntry->mFixedPitch = true;
michael@0 511 }
michael@0 512
michael@0 513 #ifdef PR_LOGGING
michael@0 514 if (LOG_FONTLIST_ENABLED()) {
michael@0 515 LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
michael@0 516 " with style: %s weight: %d stretch: %d"
michael@0 517 " (apple-weight: %d macTraits: %8.8x)",
michael@0 518 NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
michael@0 519 NS_ConvertUTF16toUTF8(Name()).get(),
michael@0 520 fontEntry->IsItalic() ? "italic" : "normal",
michael@0 521 cssWeight, fontEntry->Stretch(),
michael@0 522 appKitWeight, macTraits));
michael@0 523 }
michael@0 524 #endif
michael@0 525
michael@0 526 // insert into font entry array of family
michael@0 527 AddFontEntry(fontEntry);
michael@0 528 }
michael@0 529
michael@0 530 SortAvailableFonts();
michael@0 531 SetHasStyles(true);
michael@0 532
michael@0 533 if (mIsBadUnderlineFamily) {
michael@0 534 SetBadUnderlineFonts();
michael@0 535 }
michael@0 536 }
michael@0 537
michael@0 538
michael@0 539 /* gfxSingleFaceMacFontFamily */
michael@0 540 #pragma mark-
michael@0 541
michael@0 542 class gfxSingleFaceMacFontFamily : public gfxFontFamily
michael@0 543 {
michael@0 544 public:
michael@0 545 gfxSingleFaceMacFontFamily(nsAString& aName) :
michael@0 546 gfxFontFamily(aName)
michael@0 547 {
michael@0 548 mFaceNamesInitialized = true; // omit from face name lists
michael@0 549 }
michael@0 550
michael@0 551 virtual ~gfxSingleFaceMacFontFamily() {}
michael@0 552
michael@0 553 virtual void LocalizedName(nsAString& aLocalizedName);
michael@0 554
michael@0 555 virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList);
michael@0 556 };
michael@0 557
michael@0 558 void
michael@0 559 gfxSingleFaceMacFontFamily::LocalizedName(nsAString& aLocalizedName)
michael@0 560 {
michael@0 561 nsAutoreleasePool localPool;
michael@0 562
michael@0 563 if (!HasOtherFamilyNames()) {
michael@0 564 aLocalizedName = mName;
michael@0 565 return;
michael@0 566 }
michael@0 567
michael@0 568 gfxFontEntry *fe = mAvailableFonts[0];
michael@0 569 NSFont *font = [NSFont fontWithName:GetNSStringForString(fe->Name())
michael@0 570 size:0.0];
michael@0 571 if (font) {
michael@0 572 NSString *localized = [font displayName];
michael@0 573 if (localized) {
michael@0 574 GetStringForNSString(localized, aLocalizedName);
michael@0 575 return;
michael@0 576 }
michael@0 577 }
michael@0 578
michael@0 579 // failed to get localized name, just use the canonical one
michael@0 580 aLocalizedName = mName;
michael@0 581 }
michael@0 582
michael@0 583 void
michael@0 584 gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
michael@0 585 {
michael@0 586 if (mOtherFamilyNamesInitialized) {
michael@0 587 return;
michael@0 588 }
michael@0 589
michael@0 590 gfxFontEntry *fe = mAvailableFonts[0];
michael@0 591 if (!fe) {
michael@0 592 return;
michael@0 593 }
michael@0 594
michael@0 595 const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
michael@0 596
michael@0 597 gfxFontEntry::AutoTable nameTable(fe, kNAME);
michael@0 598 if (!nameTable) {
michael@0 599 return;
michael@0 600 }
michael@0 601
michael@0 602 mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
michael@0 603 nameTable,
michael@0 604 true);
michael@0 605
michael@0 606 mOtherFamilyNamesInitialized = true;
michael@0 607 }
michael@0 608
michael@0 609
michael@0 610 /* gfxMacPlatformFontList */
michael@0 611 #pragma mark-
michael@0 612
michael@0 613 gfxMacPlatformFontList::gfxMacPlatformFontList() :
michael@0 614 gfxPlatformFontList(false),
michael@0 615 mDefaultFont(nullptr)
michael@0 616 {
michael@0 617 ::CFNotificationCenterAddObserver(::CFNotificationCenterGetLocalCenter(),
michael@0 618 this,
michael@0 619 RegisteredFontsChangedNotificationCallback,
michael@0 620 kCTFontManagerRegisteredFontsChangedNotification,
michael@0 621 0,
michael@0 622 CFNotificationSuspensionBehaviorDeliverImmediately);
michael@0 623
michael@0 624 // cache this in a static variable so that MacOSFontFamily objects
michael@0 625 // don't have to repeatedly look it up
michael@0 626 sFontManager = [NSFontManager sharedFontManager];
michael@0 627 }
michael@0 628
michael@0 629 gfxMacPlatformFontList::~gfxMacPlatformFontList()
michael@0 630 {
michael@0 631 if (mDefaultFont) {
michael@0 632 ::CFRelease(mDefaultFont);
michael@0 633 }
michael@0 634 }
michael@0 635
michael@0 636 nsresult
michael@0 637 gfxMacPlatformFontList::InitFontList()
michael@0 638 {
michael@0 639 nsAutoreleasePool localPool;
michael@0 640
michael@0 641 Telemetry::AutoTimer<Telemetry::MAC_INITFONTLIST_TOTAL> timer;
michael@0 642
michael@0 643 // reset font lists
michael@0 644 gfxPlatformFontList::InitFontList();
michael@0 645
michael@0 646 // iterate over available families
michael@0 647
michael@0 648 CFArrayRef familyNames = CTFontManagerCopyAvailableFontFamilyNames();
michael@0 649
michael@0 650 // iterate over families
michael@0 651 uint32_t i, numFamilies;
michael@0 652
michael@0 653 numFamilies = CFArrayGetCount(familyNames);
michael@0 654 for (i = 0; i < numFamilies; i++) {
michael@0 655 CFStringRef family = (CFStringRef)CFArrayGetValueAtIndex(familyNames, i);
michael@0 656
michael@0 657 // CTFontManager includes weird internal family names and
michael@0 658 // LastResort, skip over those
michael@0 659 if (!family ||
michael@0 660 ::CFStringHasPrefix(family, CFSTR(".")) ||
michael@0 661 CFStringCompare(family, CFSTR("LastResort"),
michael@0 662 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
michael@0 663 continue;
michael@0 664 }
michael@0 665
michael@0 666 nsAutoTArray<UniChar, 1024> buffer;
michael@0 667 CFIndex len = ::CFStringGetLength(family);
michael@0 668 buffer.SetLength(len+1);
michael@0 669 ::CFStringGetCharacters(family, ::CFRangeMake(0, len),
michael@0 670 buffer.Elements());
michael@0 671 buffer[len] = 0;
michael@0 672 nsAutoString familyName(reinterpret_cast<char16_t*>(buffer.Elements()), len);
michael@0 673
michael@0 674 // create a family entry
michael@0 675 gfxFontFamily *familyEntry = new gfxMacFontFamily(familyName);
michael@0 676 if (!familyEntry) break;
michael@0 677
michael@0 678 // add the family entry to the hash table
michael@0 679 ToLowerCase(familyName);
michael@0 680 mFontFamilies.Put(familyName, familyEntry);
michael@0 681
michael@0 682 // check the bad underline blacklist
michael@0 683 if (mBadUnderlineFamilyNames.Contains(familyName))
michael@0 684 familyEntry->SetBadUnderlineFamily();
michael@0 685 }
michael@0 686
michael@0 687 CFRelease(familyNames);
michael@0 688
michael@0 689 InitSingleFaceList();
michael@0 690
michael@0 691 // to avoid full search of font name tables, seed the other names table with localized names from
michael@0 692 // some of the prefs fonts which are accessed via their localized names. changes in the pref fonts will only cause
michael@0 693 // a font lookup miss earlier. this is a simple optimization, it's not required for correctness
michael@0 694 PreloadNamesList();
michael@0 695
michael@0 696 // start the delayed cmap loader
michael@0 697 GetPrefsAndStartLoader();
michael@0 698
michael@0 699 return NS_OK;
michael@0 700 }
michael@0 701
michael@0 702 void
michael@0 703 gfxMacPlatformFontList::InitSingleFaceList()
michael@0 704 {
michael@0 705 nsAutoTArray<nsString, 10> singleFaceFonts;
michael@0 706 gfxFontUtils::GetPrefsFontList("font.single-face-list", singleFaceFonts);
michael@0 707
michael@0 708 uint32_t numFonts = singleFaceFonts.Length();
michael@0 709 for (uint32_t i = 0; i < numFonts; i++) {
michael@0 710 #ifdef PR_LOGGING
michael@0 711 LOG_FONTLIST(("(fontlist-singleface) face name: %s\n",
michael@0 712 NS_ConvertUTF16toUTF8(singleFaceFonts[i]).get()));
michael@0 713 #endif
michael@0 714 gfxFontEntry *fontEntry = LookupLocalFont(nullptr, singleFaceFonts[i]);
michael@0 715 if (fontEntry) {
michael@0 716 nsAutoString familyName, key;
michael@0 717 familyName = singleFaceFonts[i];
michael@0 718 GenerateFontListKey(familyName, key);
michael@0 719 #ifdef PR_LOGGING
michael@0 720 LOG_FONTLIST(("(fontlist-singleface) family name: %s, key: %s\n",
michael@0 721 NS_ConvertUTF16toUTF8(familyName).get(),
michael@0 722 NS_ConvertUTF16toUTF8(key).get()));
michael@0 723 #endif
michael@0 724
michael@0 725 // add only if doesn't exist already
michael@0 726 if (!mFontFamilies.GetWeak(key)) {
michael@0 727 gfxFontFamily *familyEntry =
michael@0 728 new gfxSingleFaceMacFontFamily(familyName);
michael@0 729 familyEntry->AddFontEntry(fontEntry);
michael@0 730 familyEntry->SetHasStyles(true);
michael@0 731 mFontFamilies.Put(key, familyEntry);
michael@0 732 #ifdef PR_LOGGING
michael@0 733 LOG_FONTLIST(("(fontlist-singleface) added new family\n",
michael@0 734 NS_ConvertUTF16toUTF8(familyName).get(),
michael@0 735 NS_ConvertUTF16toUTF8(key).get()));
michael@0 736 #endif
michael@0 737 }
michael@0 738 }
michael@0 739 }
michael@0 740 }
michael@0 741
michael@0 742 bool
michael@0 743 gfxMacPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
michael@0 744 {
michael@0 745 gfxFontFamily *family = FindFamily(aFontName);
michael@0 746 if (family) {
michael@0 747 family->LocalizedName(aFamilyName);
michael@0 748 return true;
michael@0 749 }
michael@0 750
michael@0 751 return false;
michael@0 752 }
michael@0 753
michael@0 754 void
michael@0 755 gfxMacPlatformFontList::RegisteredFontsChangedNotificationCallback(CFNotificationCenterRef center,
michael@0 756 void *observer,
michael@0 757 CFStringRef name,
michael@0 758 const void *object,
michael@0 759 CFDictionaryRef userInfo)
michael@0 760 {
michael@0 761 if (!::CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification)) {
michael@0 762 return;
michael@0 763 }
michael@0 764
michael@0 765 gfxMacPlatformFontList* fl = static_cast<gfxMacPlatformFontList*>(observer);
michael@0 766
michael@0 767 // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
michael@0 768 fl->UpdateFontList();
michael@0 769
michael@0 770 // modify a preference that will trigger reflow everywhere
michael@0 771 fl->ForceGlobalReflow();
michael@0 772 }
michael@0 773
michael@0 774 gfxFontEntry*
michael@0 775 gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh,
michael@0 776 int32_t aRunScript,
michael@0 777 const gfxFontStyle* aMatchStyle,
michael@0 778 uint32_t& aCmapCount,
michael@0 779 gfxFontFamily** aMatchedFamily)
michael@0 780 {
michael@0 781 bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
michael@0 782
michael@0 783 if (useCmaps) {
michael@0 784 return gfxPlatformFontList::GlobalFontFallback(aCh,
michael@0 785 aRunScript,
michael@0 786 aMatchStyle,
michael@0 787 aCmapCount,
michael@0 788 aMatchedFamily);
michael@0 789 }
michael@0 790
michael@0 791 CFStringRef str;
michael@0 792 UniChar ch[2];
michael@0 793 CFIndex len = 1;
michael@0 794
michael@0 795 if (IS_IN_BMP(aCh)) {
michael@0 796 ch[0] = aCh;
michael@0 797 str = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 1,
michael@0 798 kCFAllocatorNull);
michael@0 799 } else {
michael@0 800 ch[0] = H_SURROGATE(aCh);
michael@0 801 ch[1] = L_SURROGATE(aCh);
michael@0 802 str = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 2,
michael@0 803 kCFAllocatorNull);
michael@0 804 if (!str) {
michael@0 805 return nullptr;
michael@0 806 }
michael@0 807 len = 2;
michael@0 808 }
michael@0 809
michael@0 810 // use CoreText to find the fallback family
michael@0 811
michael@0 812 gfxFontEntry *fontEntry = nullptr;
michael@0 813 CTFontRef fallback;
michael@0 814 bool cantUseFallbackFont = false;
michael@0 815
michael@0 816 if (!mDefaultFont) {
michael@0 817 mDefaultFont = ::CTFontCreateWithName(CFSTR("LucidaGrande"), 12.f,
michael@0 818 NULL);
michael@0 819 }
michael@0 820
michael@0 821 fallback = ::CTFontCreateForString(mDefaultFont, str,
michael@0 822 ::CFRangeMake(0, len));
michael@0 823
michael@0 824 if (fallback) {
michael@0 825 CFStringRef familyName = ::CTFontCopyFamilyName(fallback);
michael@0 826 ::CFRelease(fallback);
michael@0 827
michael@0 828 if (familyName &&
michael@0 829 ::CFStringCompare(familyName, CFSTR("LastResort"),
michael@0 830 kCFCompareCaseInsensitive) != kCFCompareEqualTo)
michael@0 831 {
michael@0 832 nsAutoTArray<UniChar, 1024> buffer;
michael@0 833 CFIndex len = ::CFStringGetLength(familyName);
michael@0 834 buffer.SetLength(len+1);
michael@0 835 ::CFStringGetCharacters(familyName, ::CFRangeMake(0, len),
michael@0 836 buffer.Elements());
michael@0 837 buffer[len] = 0;
michael@0 838 nsDependentString familyName(reinterpret_cast<char16_t*>(buffer.Elements()), len);
michael@0 839
michael@0 840 bool needsBold; // ignored in the system fallback case
michael@0 841
michael@0 842 gfxFontFamily *family = FindFamily(familyName);
michael@0 843 if (family) {
michael@0 844 fontEntry = family->FindFontForStyle(*aMatchStyle, needsBold);
michael@0 845 if (fontEntry) {
michael@0 846 if (fontEntry->TestCharacterMap(aCh)) {
michael@0 847 *aMatchedFamily = family;
michael@0 848 } else {
michael@0 849 fontEntry = nullptr;
michael@0 850 cantUseFallbackFont = true;
michael@0 851 }
michael@0 852 }
michael@0 853 }
michael@0 854 }
michael@0 855
michael@0 856 if (familyName) {
michael@0 857 ::CFRelease(familyName);
michael@0 858 }
michael@0 859 }
michael@0 860
michael@0 861 if (cantUseFallbackFont) {
michael@0 862 Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, cantUseFallbackFont);
michael@0 863 }
michael@0 864
michael@0 865 ::CFRelease(str);
michael@0 866
michael@0 867 return fontEntry;
michael@0 868 }
michael@0 869
michael@0 870 gfxFontFamily*
michael@0 871 gfxMacPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle)
michael@0 872 {
michael@0 873 nsAutoreleasePool localPool;
michael@0 874
michael@0 875 NSString *defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
michael@0 876 nsAutoString familyName;
michael@0 877
michael@0 878 GetStringForNSString(defaultFamily, familyName);
michael@0 879 return FindFamily(familyName);
michael@0 880 }
michael@0 881
michael@0 882 int32_t
michael@0 883 gfxMacPlatformFontList::AppleWeightToCSSWeight(int32_t aAppleWeight)
michael@0 884 {
michael@0 885 if (aAppleWeight < 1)
michael@0 886 aAppleWeight = 1;
michael@0 887 else if (aAppleWeight > kAppleMaxWeight)
michael@0 888 aAppleWeight = kAppleMaxWeight;
michael@0 889 return gAppleWeightToCSSWeight[aAppleWeight];
michael@0 890 }
michael@0 891
michael@0 892 gfxFontEntry*
michael@0 893 gfxMacPlatformFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
michael@0 894 const nsAString& aFontName)
michael@0 895 {
michael@0 896 nsAutoreleasePool localPool;
michael@0 897
michael@0 898 NSString *faceName = GetNSStringForString(aFontName);
michael@0 899 MacOSFontEntry *newFontEntry;
michael@0 900
michael@0 901 // lookup face based on postscript or full name
michael@0 902 CGFontRef fontRef = ::CGFontCreateWithFontName(CFStringRef(faceName));
michael@0 903 if (!fontRef) {
michael@0 904 return nullptr;
michael@0 905 }
michael@0 906
michael@0 907 if (aProxyEntry) {
michael@0 908 uint16_t w = aProxyEntry->mWeight;
michael@0 909 NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
michael@0 910
michael@0 911 newFontEntry =
michael@0 912 new MacOSFontEntry(aFontName, fontRef,
michael@0 913 w, aProxyEntry->mStretch,
michael@0 914 aProxyEntry->mItalic ?
michael@0 915 NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL,
michael@0 916 true, true);
michael@0 917 } else {
michael@0 918 newFontEntry =
michael@0 919 new MacOSFontEntry(aFontName, fontRef,
michael@0 920 400, 0, NS_FONT_STYLE_NORMAL,
michael@0 921 false, false);
michael@0 922 }
michael@0 923 ::CFRelease(fontRef);
michael@0 924
michael@0 925 return newFontEntry;
michael@0 926 }
michael@0 927
michael@0 928 static void ReleaseData(void *info, const void *data, size_t size)
michael@0 929 {
michael@0 930 NS_Free((void*)data);
michael@0 931 }
michael@0 932
michael@0 933 gfxFontEntry*
michael@0 934 gfxMacPlatformFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
michael@0 935 const uint8_t *aFontData,
michael@0 936 uint32_t aLength)
michael@0 937 {
michael@0 938 NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
michael@0 939
michael@0 940 uint16_t w = aProxyEntry->mWeight;
michael@0 941 NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
michael@0 942
michael@0 943 // create the font entry
michael@0 944 nsAutoString uniqueName;
michael@0 945
michael@0 946 nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
michael@0 947 if (NS_FAILED(rv)) {
michael@0 948 return nullptr;
michael@0 949 }
michael@0 950
michael@0 951 CGDataProviderRef provider =
michael@0 952 ::CGDataProviderCreateWithData(nullptr, aFontData, aLength,
michael@0 953 &ReleaseData);
michael@0 954 CGFontRef fontRef = ::CGFontCreateWithDataProvider(provider);
michael@0 955 ::CGDataProviderRelease(provider);
michael@0 956
michael@0 957 if (!fontRef) {
michael@0 958 return nullptr;
michael@0 959 }
michael@0 960
michael@0 961 nsAutoPtr<MacOSFontEntry>
michael@0 962 newFontEntry(new MacOSFontEntry(uniqueName, fontRef, w,
michael@0 963 aProxyEntry->mStretch,
michael@0 964 aProxyEntry->mItalic ?
michael@0 965 NS_FONT_STYLE_ITALIC :
michael@0 966 NS_FONT_STYLE_NORMAL,
michael@0 967 true, false));
michael@0 968 ::CFRelease(fontRef);
michael@0 969
michael@0 970 // if succeeded and font cmap is good, return the new font
michael@0 971 if (newFontEntry->mIsValid && NS_SUCCEEDED(newFontEntry->ReadCMAP())) {
michael@0 972 return newFontEntry.forget();
michael@0 973 }
michael@0 974
michael@0 975 // if something is funky about this font, delete immediately
michael@0 976
michael@0 977 #if DEBUG
michael@0 978 NS_WARNING("downloaded font not loaded properly");
michael@0 979 #endif
michael@0 980
michael@0 981 return nullptr;
michael@0 982 }
michael@0 983
michael@0 984 // used to load system-wide font info on off-main thread
michael@0 985 class MacFontInfo : public FontInfoData {
michael@0 986 public:
michael@0 987 MacFontInfo(bool aLoadOtherNames,
michael@0 988 bool aLoadFaceNames,
michael@0 989 bool aLoadCmaps) :
michael@0 990 FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps)
michael@0 991 {}
michael@0 992
michael@0 993 virtual ~MacFontInfo() {}
michael@0 994
michael@0 995 virtual void Load() {
michael@0 996 nsAutoreleasePool localPool;
michael@0 997 // bug 975460 - async font loader crashes sometimes under 10.6, disable
michael@0 998 if (nsCocoaFeatures::OnLionOrLater()) {
michael@0 999 FontInfoData::Load();
michael@0 1000 }
michael@0 1001 }
michael@0 1002
michael@0 1003 // loads font data for all members of a given family
michael@0 1004 virtual void LoadFontFamilyData(const nsAString& aFamilyName);
michael@0 1005 };
michael@0 1006
michael@0 1007 void
michael@0 1008 MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
michael@0 1009 {
michael@0 1010 // family name ==> CTFontDescriptor
michael@0 1011 NSString *famName = GetNSStringForString(aFamilyName);
michael@0 1012 CFStringRef family = CFStringRef(famName);
michael@0 1013
michael@0 1014 CFMutableDictionaryRef attr =
michael@0 1015 CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
michael@0 1016 &kCFTypeDictionaryValueCallBacks);
michael@0 1017 CFDictionaryAddValue(attr, kCTFontFamilyNameAttribute, family);
michael@0 1018 CTFontDescriptorRef fd = CTFontDescriptorCreateWithAttributes(attr);
michael@0 1019 CFRelease(attr);
michael@0 1020 CFArrayRef matchingFonts =
michael@0 1021 CTFontDescriptorCreateMatchingFontDescriptors(fd, NULL);
michael@0 1022 CFRelease(fd);
michael@0 1023 if (!matchingFonts) {
michael@0 1024 return;
michael@0 1025 }
michael@0 1026
michael@0 1027 nsTArray<nsString> otherFamilyNames;
michael@0 1028 bool hasOtherFamilyNames = true;
michael@0 1029
michael@0 1030 // iterate over faces in the family
michael@0 1031 int f, numFaces = (int) CFArrayGetCount(matchingFonts);
michael@0 1032 for (f = 0; f < numFaces; f++) {
michael@0 1033 mLoadStats.fonts++;
michael@0 1034
michael@0 1035 CTFontDescriptorRef faceDesc =
michael@0 1036 (CTFontDescriptorRef)CFArrayGetValueAtIndex(matchingFonts, f);
michael@0 1037 if (!faceDesc) {
michael@0 1038 continue;
michael@0 1039 }
michael@0 1040 CTFontRef fontRef = CTFontCreateWithFontDescriptor(faceDesc,
michael@0 1041 0.0, nullptr);
michael@0 1042 if (!fontRef) {
michael@0 1043 NS_WARNING("failed to create a CTFontRef");
michael@0 1044 continue;
michael@0 1045 }
michael@0 1046
michael@0 1047 if (mLoadCmaps) {
michael@0 1048 // face name
michael@0 1049 CFStringRef faceName = (CFStringRef)
michael@0 1050 CTFontDescriptorCopyAttribute(faceDesc, kCTFontNameAttribute);
michael@0 1051
michael@0 1052 nsAutoTArray<UniChar, 1024> buffer;
michael@0 1053 CFIndex len = CFStringGetLength(faceName);
michael@0 1054 buffer.SetLength(len+1);
michael@0 1055 CFStringGetCharacters(faceName, ::CFRangeMake(0, len),
michael@0 1056 buffer.Elements());
michael@0 1057 buffer[len] = 0;
michael@0 1058 nsAutoString fontName(reinterpret_cast<char16_t*>(buffer.Elements()),
michael@0 1059 len);
michael@0 1060
michael@0 1061 // load the cmap data
michael@0 1062 FontFaceData fontData;
michael@0 1063 CFDataRef cmapTable = CTFontCopyTable(fontRef, kCTFontTableCmap,
michael@0 1064 kCTFontTableOptionNoOptions);
michael@0 1065
michael@0 1066 if (cmapTable) {
michael@0 1067 bool unicodeFont = false, symbolFont = false; // ignored
michael@0 1068 const uint8_t *cmapData =
michael@0 1069 (const uint8_t*)CFDataGetBytePtr(cmapTable);
michael@0 1070 uint32_t cmapLen = CFDataGetLength(cmapTable);
michael@0 1071 nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
michael@0 1072 uint32_t offset;
michael@0 1073 nsresult rv;
michael@0 1074
michael@0 1075 rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, offset,
michael@0 1076 unicodeFont, symbolFont);
michael@0 1077 if (NS_SUCCEEDED(rv)) {
michael@0 1078 fontData.mCharacterMap = charmap;
michael@0 1079 fontData.mUVSOffset = offset;
michael@0 1080 fontData.mSymbolFont = symbolFont;
michael@0 1081 mLoadStats.cmaps++;
michael@0 1082 }
michael@0 1083 CFRelease(cmapTable);
michael@0 1084 }
michael@0 1085
michael@0 1086 mFontFaceData.Put(fontName, fontData);
michael@0 1087 CFRelease(faceName);
michael@0 1088 }
michael@0 1089
michael@0 1090 if (mLoadOtherNames && hasOtherFamilyNames) {
michael@0 1091 CFDataRef nameTable = CTFontCopyTable(fontRef, kCTFontTableName,
michael@0 1092 kCTFontTableOptionNoOptions);
michael@0 1093
michael@0 1094 if (nameTable) {
michael@0 1095 const char *nameData = (const char*)CFDataGetBytePtr(nameTable);
michael@0 1096 uint32_t nameLen = CFDataGetLength(nameTable);
michael@0 1097 gfxFontFamily::ReadOtherFamilyNamesForFace(aFamilyName,
michael@0 1098 nameData, nameLen,
michael@0 1099 otherFamilyNames,
michael@0 1100 false);
michael@0 1101 hasOtherFamilyNames = otherFamilyNames.Length() != 0;
michael@0 1102 CFRelease(nameTable);
michael@0 1103 }
michael@0 1104 }
michael@0 1105
michael@0 1106 CFRelease(fontRef);
michael@0 1107 }
michael@0 1108 CFRelease(matchingFonts);
michael@0 1109
michael@0 1110 // if found other names, insert them in the hash table
michael@0 1111 if (otherFamilyNames.Length() != 0) {
michael@0 1112 mOtherFamilyNames.Put(aFamilyName, otherFamilyNames);
michael@0 1113 mLoadStats.othernames += otherFamilyNames.Length();
michael@0 1114 }
michael@0 1115 }
michael@0 1116
michael@0 1117 already_AddRefed<FontInfoData>
michael@0 1118 gfxMacPlatformFontList::CreateFontInfoData()
michael@0 1119 {
michael@0 1120 bool loadCmaps = !UsesSystemFallback() ||
michael@0 1121 gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
michael@0 1122
michael@0 1123 nsRefPtr<MacFontInfo> fi =
michael@0 1124 new MacFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps);
michael@0 1125 return fi.forget();
michael@0 1126 }
michael@0 1127

mercurial