summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/gfxMacPlatformFontList.mm
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/thebes/gfxMacPlatformFontList.mm')
-rw-r--r--gfx/thebes/gfxMacPlatformFontList.mm2223
1 files changed, 2223 insertions, 0 deletions
diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm
new file mode 100644
index 0000000000..deeccad879
--- /dev/null
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -0,0 +1,2223 @@
+/* -*- Mode: ObjC; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: BSD
+ *
+ * Copyright (C) 2006-2009 Mozilla Corporation. All rights reserved.
+ *
+ * Contributor(s):
+ * Vladimir Vukicevic <vladimir@pobox.com>
+ * Masayuki Nakano <masayuki@d-toybox.com>
+ * John Daggett <jdaggett@mozilla.com>
+ * Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mozilla/Logging.h"
+
+#include <algorithm>
+
+#import <AppKit/AppKit.h>
+
+#include "gfxFontConstants.h"
+#include "gfxPlatformMac.h"
+#include "gfxMacPlatformFontList.h"
+#include "gfxMacFont.h"
+#include "gfxUserFontSet.h"
+#include "SharedFontList-impl.h"
+
+#include "harfbuzz/hb.h"
+
+#include "AppleUtils.h"
+#include "MainThreadUtils.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsIDirectoryEnumerator.h"
+#include "nsCharTraits.h"
+#include "nsCocoaFeatures.h"
+#include "nsCocoaUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsTArray.h"
+
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/FontPropertyTypes.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/ProfilerLabels.h"
+#include "mozilla/Sprintf.h"
+#include "mozilla/StaticPrefs_gfx.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/gfx/2D.h"
+
+#include <unistd.h>
+#include <time.h>
+#include <dlfcn.h>
+
+#include "StandardFonts-macos.inc"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+
+// Building with newer macOS SDKs can cause a bunch of font-family names to be hidden
+// from the Core Text API we use to enumerate available fonts. Because some content still
+// benefits from having these names recognized, we forcibly include them in the list.
+// Some day we might want to drop support for these.
+#define USE_DEPRECATED_FONT_FAMILY_NAMES 1
+
+#if USE_DEPRECATED_FONT_FAMILY_NAMES
+// List generated by diffing the arrays returned by CTFontManagerCopyAvailableFontFamilyNames()
+// when built with MACOSX_DEPLOYMENT_TARGET=10.12 vs 11.0, to identify the font family names
+// that Core Text is treating as "deprecated" and hiding from the app on newer systems.
+constexpr nsLiteralCString kDeprecatedFontFamilies[] = {
+ // Dot-prefixed font families are supposed to be hidden from the user-visible
+ // font list anyhow, so we don't need to add them here.
+ // ".Al Bayan PUA"_ns,
+ // ".Al Nile PUA"_ns,
+ // ".Al Tarikh PUA"_ns,
+ // ".Apple Color Emoji UI"_ns,
+ // ".Apple SD Gothic NeoI"_ns,
+ // ".Aqua Kana"_ns,
+ // ".Arial Hebrew Desk Interface"_ns,
+ // ".Baghdad PUA"_ns,
+ // ".Beirut PUA"_ns,
+ // ".Damascus PUA"_ns,
+ // ".DecoType Naskh PUA"_ns,
+ // ".Diwan Kufi PUA"_ns,
+ // ".Farah PUA"_ns,
+ // ".Geeza Pro Interface"_ns,
+ // ".Geeza Pro PUA"_ns,
+ // ".Helvetica LT MM"_ns,
+ // ".Hiragino Kaku Gothic Interface"_ns,
+ // ".Hiragino Sans GB Interface"_ns,
+ // ".Keyboard"_ns,
+ // ".KufiStandardGK PUA"_ns,
+ // ".LastResort"_ns,
+ // ".Lucida Grande UI"_ns,
+ // ".Muna PUA"_ns,
+ // ".Nadeem PUA"_ns,
+ // ".New York"_ns,
+ // ".Noto Nastaliq Urdu UI"_ns,
+ // ".PingFang HK"_ns,
+ // ".PingFang SC"_ns,
+ // ".PingFang TC"_ns,
+ // ".Sana PUA"_ns,
+ // ".Savoye LET CC."_ns,
+ // ".SF Arabic"_ns,
+ // ".SF Compact Rounded"_ns,
+ // ".SF Compact"_ns,
+ // ".SF NS Mono"_ns,
+ // ".SF NS Rounded"_ns,
+ // ".SF NS"_ns,
+ // ".Times LT MM"_ns,
+ "Hiragino Kaku Gothic Pro"_ns,
+ "Hiragino Kaku Gothic ProN"_ns,
+ "Hiragino Kaku Gothic Std"_ns,
+ "Hiragino Kaku Gothic StdN"_ns,
+ "Hiragino Maru Gothic Pro"_ns,
+ "Hiragino Mincho Pro"_ns,
+ "Iowan Old Style"_ns,
+ "Noto Sans Adlam"_ns,
+ "Noto Sans Armenian"_ns,
+ "Noto Sans Avestan"_ns,
+ "Noto Sans Bamum"_ns,
+ "Noto Sans Bassa Vah"_ns,
+ "Noto Sans Batak"_ns,
+ "Noto Sans Bhaiksuki"_ns,
+ "Noto Sans Brahmi"_ns,
+ "Noto Sans Buginese"_ns,
+ "Noto Sans Buhid"_ns,
+ "Noto Sans Carian"_ns,
+ "Noto Sans Caucasian Albanian"_ns,
+ "Noto Sans Chakma"_ns,
+ "Noto Sans Cham"_ns,
+ "Noto Sans Coptic"_ns,
+ "Noto Sans Cuneiform"_ns,
+ "Noto Sans Cypriot"_ns,
+ "Noto Sans Duployan"_ns,
+ "Noto Sans Egyptian Hieroglyphs"_ns,
+ "Noto Sans Elbasan"_ns,
+ "Noto Sans Glagolitic"_ns,
+ "Noto Sans Gothic"_ns,
+ "Noto Sans Gunjala Gondi"_ns,
+ "Noto Sans Hanifi Rohingya"_ns,
+ "Noto Sans Hanunoo"_ns,
+ "Noto Sans Hatran"_ns,
+ "Noto Sans Imperial Aramaic"_ns,
+ "Noto Sans Inscriptional Pahlavi"_ns,
+ "Noto Sans Inscriptional Parthian"_ns,
+ "Noto Sans Javanese"_ns,
+ "Noto Sans Kaithi"_ns,
+ "Noto Sans Kayah Li"_ns,
+ "Noto Sans Kharoshthi"_ns,
+ "Noto Sans Khojki"_ns,
+ "Noto Sans Khudawadi"_ns,
+ "Noto Sans Lepcha"_ns,
+ "Noto Sans Limbu"_ns,
+ "Noto Sans Linear A"_ns,
+ "Noto Sans Linear B"_ns,
+ "Noto Sans Lisu"_ns,
+ "Noto Sans Lycian"_ns,
+ "Noto Sans Lydian"_ns,
+ "Noto Sans Mahajani"_ns,
+ "Noto Sans Mandaic"_ns,
+ "Noto Sans Manichaean"_ns,
+ "Noto Sans Marchen"_ns,
+ "Noto Sans Masaram Gondi"_ns,
+ "Noto Sans Meetei Mayek"_ns,
+ "Noto Sans Mende Kikakui"_ns,
+ "Noto Sans Meroitic"_ns,
+ "Noto Sans Miao"_ns,
+ "Noto Sans Modi"_ns,
+ "Noto Sans Mongolian"_ns,
+ "Noto Sans Mro"_ns,
+ "Noto Sans Multani"_ns,
+ "Noto Sans Nabataean"_ns,
+ "Noto Sans New Tai Lue"_ns,
+ "Noto Sans Newa"_ns,
+ "Noto Sans NKo"_ns,
+ "Noto Sans Ol Chiki"_ns,
+ "Noto Sans Old Hungarian"_ns,
+ "Noto Sans Old Italic"_ns,
+ "Noto Sans Old North Arabian"_ns,
+ "Noto Sans Old Permic"_ns,
+ "Noto Sans Old Persian"_ns,
+ "Noto Sans Old South Arabian"_ns,
+ "Noto Sans Old Turkic"_ns,
+ "Noto Sans Osage"_ns,
+ "Noto Sans Osmanya"_ns,
+ "Noto Sans Pahawh Hmong"_ns,
+ "Noto Sans Palmyrene"_ns,
+ "Noto Sans Pau Cin Hau"_ns,
+ "Noto Sans PhagsPa"_ns,
+ "Noto Sans Phoenician"_ns,
+ "Noto Sans Psalter Pahlavi"_ns,
+ "Noto Sans Rejang"_ns,
+ "Noto Sans Samaritan"_ns,
+ "Noto Sans Saurashtra"_ns,
+ "Noto Sans Sharada"_ns,
+ "Noto Sans Siddham"_ns,
+ "Noto Sans Sora Sompeng"_ns,
+ "Noto Sans Sundanese"_ns,
+ "Noto Sans Syloti Nagri"_ns,
+ "Noto Sans Syriac"_ns,
+ "Noto Sans Tagalog"_ns,
+ "Noto Sans Tagbanwa"_ns,
+ "Noto Sans Tai Le"_ns,
+ "Noto Sans Tai Tham"_ns,
+ "Noto Sans Tai Viet"_ns,
+ "Noto Sans Takri"_ns,
+ "Noto Sans Thaana"_ns,
+ "Noto Sans Tifinagh"_ns,
+ "Noto Sans Tirhuta"_ns,
+ "Noto Sans Ugaritic"_ns,
+ "Noto Sans Vai"_ns,
+ "Noto Sans Wancho"_ns,
+ "Noto Sans Warang Citi"_ns,
+ "Noto Sans Yi"_ns,
+ "Noto Sans Zawgyi"_ns,
+ "Noto Serif Ahom"_ns,
+ "Noto Serif Balinese"_ns,
+ "Noto Serif Yezidi"_ns,
+ "Athelas"_ns,
+ "Courier"_ns,
+ "Marion"_ns,
+ "Seravek"_ns,
+ "Superclarendon"_ns,
+ "Times"_ns,
+};
+#endif // USE_DEPRECATED_FONT_FAMILY_NAMES
+
+// indexes into the NSArray objects that the Cocoa font manager returns
+// as the available members of a family
+#define INDEX_FONT_POSTSCRIPT_NAME 0
+#define INDEX_FONT_FACE_NAME 1
+#define INDEX_FONT_WEIGHT 2
+#define INDEX_FONT_TRAITS 3
+
+static const int kAppleMaxWeight = 14;
+static const int kAppleExtraLightWeight = 3;
+static const int kAppleUltraLightWeight = 2;
+
+static const int gAppleWeightToCSSWeight[] = {
+ 0,
+ 1, // 1.
+ 1, // 2. W1, ultralight
+ 2, // 3. W2, extralight
+ 3, // 4. W3, light
+ 4, // 5. W4, semilight
+ 5, // 6. W5, medium
+ 6, // 7.
+ 6, // 8. W6, semibold
+ 7, // 9. W7, bold
+ 8, // 10. W8, extrabold
+ 8, // 11.
+ 9, // 12. W9, ultrabold
+ 9, // 13
+ 9 // 14
+};
+
+// cache Cocoa's "shared font manager" for performance
+static NSFontManager* sFontManager;
+
+static void GetStringForNSString(const NSString* aSrc, nsAString& aDest) {
+ aDest.SetLength([aSrc length]);
+ [aSrc getCharacters:reinterpret_cast<unichar*>(aDest.BeginWriting())
+ range:NSMakeRange(0, [aSrc length])];
+}
+
+static NSString* GetNSStringForString(const nsAString& aSrc) {
+ return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(aSrc.BeginReading())
+ length:aSrc.Length()];
+}
+
+#define LOG_FONTLIST(args) \
+ MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), mozilla::LogLevel::Debug, args)
+#define LOG_FONTLIST_ENABLED() \
+ MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_fontlist), mozilla::LogLevel::Debug)
+#define LOG_CMAPDATA_ENABLED() \
+ MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_cmapdata), mozilla::LogLevel::Debug)
+
+#pragma mark -
+
+// Complex scripts will not render correctly unless appropriate AAT or OT
+// layout tables are present.
+// For OpenType, we also check that the GSUB table supports the relevant
+// script tag, to avoid using things like Arial Unicode MS for Lao (it has
+// the characters, but lacks OpenType support).
+
+// TODO: consider whether we should move this to gfxFontEntry and do similar
+// cmap-masking on other platforms to avoid using fonts that won't shape
+// properly.
+
+nsresult MacOSFontEntry::ReadCMAP(FontInfoData* aFontInfoData) {
+ // attempt this once, if errors occur leave a blank cmap
+ if (mCharacterMap || mShmemCharacterMap) {
+ return NS_OK;
+ }
+
+ RefPtr<gfxCharacterMap> charmap;
+ nsresult rv;
+
+ uint32_t uvsOffset = 0;
+ if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData, uvsOffset))) {
+ rv = NS_OK;
+ } else {
+ uint32_t kCMAP = TRUETYPE_TAG('c', 'm', 'a', 'p');
+ charmap = new gfxCharacterMap();
+ AutoTable cmapTable(this, kCMAP);
+
+ if (cmapTable) {
+ uint32_t cmapLen;
+ const uint8_t* cmapData =
+ reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable, &cmapLen));
+ rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, uvsOffset);
+ } else {
+ rv = NS_ERROR_NOT_AVAILABLE;
+ }
+ }
+ mUVSOffset.exchange(uvsOffset);
+
+ if (NS_SUCCEEDED(rv) && !mIsDataUserFont && !HasGraphiteTables()) {
+ // For downloadable fonts, trust the author and don't
+ // try to munge the cmap based on script shaping support.
+
+ // We also assume a Graphite font knows what it's doing,
+ // and provides whatever shaping is needed for the
+ // characters it supports, so only check/clear the
+ // complex-script ranges for non-Graphite fonts
+
+ // for layout support, check for the presence of mort/morx/kerx and/or
+ // opentype layout tables
+ bool hasAATLayout = HasFontTable(TRUETYPE_TAG('m', 'o', 'r', 'x')) ||
+ HasFontTable(TRUETYPE_TAG('m', 'o', 'r', 't'));
+ bool hasAppleKerning = HasFontTable(TRUETYPE_TAG('k', 'e', 'r', 'x'));
+ bool hasGSUB = HasFontTable(TRUETYPE_TAG('G', 'S', 'U', 'B'));
+ bool hasGPOS = HasFontTable(TRUETYPE_TAG('G', 'P', 'O', 'S'));
+ if ((hasAATLayout && !(hasGSUB || hasGPOS)) || hasAppleKerning) {
+ mRequiresAAT = true; // prefer CoreText if font has no OTL tables,
+ // or if it uses the Apple-specific 'kerx'
+ // variant of kerning table
+ }
+
+ for (const ScriptRange* sr = gfxPlatformFontList::sComplexScriptRanges; sr->rangeStart; sr++) {
+ // check to see if the cmap includes complex script codepoints
+ if (charmap->TestRange(sr->rangeStart, sr->rangeEnd)) {
+ if (hasAATLayout) {
+ // prefer CoreText for Apple's complex-script fonts,
+ // even if they also have some OpenType tables
+ // (e.g. Geeza Pro Bold on 10.6; see bug 614903)
+ mRequiresAAT = true;
+ // and don't mask off complex-script ranges, we assume
+ // the AAT tables will provide the necessary shaping
+ continue;
+ }
+
+ // We check for GSUB here, as GPOS alone would not be ok.
+ if (hasGSUB && SupportsScriptInGSUB(sr->tags, sr->numTags)) {
+ continue;
+ }
+
+ charmap->ClearRange(sr->rangeStart, sr->rangeEnd);
+ }
+ }
+
+ // Bug 1360309, 1393624: several of Apple's Chinese fonts have spurious
+ // blank glyphs for obscure Tibetan and Arabic-script codepoints.
+ // Blocklist these so that font fallback will not use them.
+ if (mRequiresAAT &&
+ (FamilyName().EqualsLiteral("Songti SC") || FamilyName().EqualsLiteral("Songti TC") ||
+ FamilyName().EqualsLiteral("STSong") ||
+ // Bug 1390980: on 10.11, the Kaiti fonts are also affected.
+ FamilyName().EqualsLiteral("Kaiti SC") || FamilyName().EqualsLiteral("Kaiti TC") ||
+ FamilyName().EqualsLiteral("STKaiti"))) {
+ charmap->ClearRange(0x0f6b, 0x0f70);
+ charmap->ClearRange(0x0f8c, 0x0f8f);
+ charmap->clear(0x0f98);
+ charmap->clear(0x0fbd);
+ charmap->ClearRange(0x0fcd, 0x0fff);
+ charmap->clear(0x0620);
+ charmap->clear(0x065f);
+ charmap->ClearRange(0x06ee, 0x06ef);
+ charmap->clear(0x06ff);
+ }
+ }
+
+ bool setCharMap = true;
+ if (NS_SUCCEEDED(rv)) {
+ gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
+ fontlist::FontList* sharedFontList = pfl->SharedFontList();
+ if (!IsUserFont() && mShmemFace) {
+ mShmemFace->SetCharacterMap(sharedFontList, charmap); // async
+ if (TrySetShmemCharacterMap()) {
+ setCharMap = false;
+ }
+ } else {
+ charmap = pfl->FindCharMap(charmap);
+ }
+ mHasCmapTable = true;
+ } else {
+ // if error occurred, initialize to null cmap
+ charmap = new gfxCharacterMap();
+ mHasCmapTable = false;
+ }
+ if (setCharMap) {
+ // Temporarily retain charmap, until the shared version is
+ // ready for use.
+ if (mCharacterMap.compareExchange(nullptr, charmap.get())) {
+ charmap.get()->AddRef();
+ }
+ }
+
+ LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %zu hash: %8.8x%s\n", mName.get(),
+ charmap->SizeOfIncludingThis(moz_malloc_size_of), charmap->mHash,
+ mCharacterMap == charmap ? " new" : ""));
+ if (LOG_CMAPDATA_ENABLED()) {
+ char prefix[256];
+ SprintfLiteral(prefix, "(cmapdata) name: %.220s", mName.get());
+ charmap->Dump(prefix, eGfxLog_cmapdata);
+ }
+
+ return rv;
+}
+
+gfxFont* MacOSFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle) {
+ RefPtr<UnscaledFontMac> unscaledFont(mUnscaledFont);
+ if (!unscaledFont) {
+ CGFontRef baseFont = GetFontRef();
+ if (!baseFont) {
+ return nullptr;
+ }
+ unscaledFont = new UnscaledFontMac(baseFont, mIsDataUserFont);
+ mUnscaledFont = unscaledFont;
+ }
+
+ return new gfxMacFont(unscaledFont, this, aFontStyle);
+}
+
+bool MacOSFontEntry::HasVariations() {
+ if (!mHasVariationsInitialized) {
+ mHasVariationsInitialized = true;
+ mHasVariations =
+ gfxPlatform::HasVariationFontSupport() && HasFontTable(TRUETYPE_TAG('f', 'v', 'a', 'r'));
+ }
+
+ return mHasVariations;
+}
+
+void MacOSFontEntry::GetVariationAxes(nsTArray<gfxFontVariationAxis>& aVariationAxes) {
+ // We could do this by creating a CTFont and calling CTFontCopyVariationAxes,
+ // but it is expensive to instantiate a CTFont for every face just to set up
+ // the axis information.
+ // Instead we use gfxFontUtils to read the font tables directly.
+ gfxFontUtils::GetVariationData(this, &aVariationAxes, nullptr);
+}
+
+void MacOSFontEntry::GetVariationInstances(nsTArray<gfxFontVariationInstance>& aInstances) {
+ // Core Text doesn't offer API for this, so we use gfxFontUtils to read the
+ // font tables directly.
+ gfxFontUtils::GetVariationData(this, nullptr, &aInstances);
+}
+
+bool MacOSFontEntry::IsCFF() {
+ if (!mIsCFFInitialized) {
+ mIsCFFInitialized = true;
+ mIsCFF = HasFontTable(TRUETYPE_TAG('C', 'F', 'F', ' '));
+ }
+
+ return mIsCFF;
+}
+
+MacOSFontEntry::MacOSFontEntry(const nsACString& aPostscriptName, WeightRange aWeight,
+ bool aIsStandardFace, double aSizeHint)
+ : gfxFontEntry(aPostscriptName, aIsStandardFace),
+ mFontRef(NULL),
+ mSizeHint(aSizeHint),
+ mFontRefInitialized(false),
+ mRequiresAAT(false),
+ mIsCFF(false),
+ mIsCFFInitialized(false),
+ mHasVariations(false),
+ mHasVariationsInitialized(false),
+ mHasAATSmallCaps(false),
+ mHasAATSmallCapsInitialized(false) {
+ mWeightRange = aWeight;
+ mOpszAxis.mTag = 0;
+}
+
+MacOSFontEntry::MacOSFontEntry(const nsACString& aPostscriptName, CGFontRef aFontRef,
+ WeightRange aWeight, StretchRange aStretch, SlantStyleRange aStyle,
+ bool aIsDataUserFont, bool aIsLocalUserFont)
+ : gfxFontEntry(aPostscriptName, false),
+ mFontRef(NULL),
+ mSizeHint(0.0),
+ mFontRefInitialized(false),
+ mRequiresAAT(false),
+ mIsCFF(false),
+ mIsCFFInitialized(false),
+ mHasVariations(false),
+ mHasVariationsInitialized(false),
+ mHasAATSmallCaps(false),
+ mHasAATSmallCapsInitialized(false) {
+ mFontRef = aFontRef;
+ mFontRefInitialized = true;
+ ::CFRetain(mFontRef);
+
+ mWeightRange = aWeight;
+ mStretchRange = aStretch;
+ mFixedPitch = false; // xxx - do we need this for downloaded fonts?
+ mStyleRange = aStyle;
+ mOpszAxis.mTag = 0;
+
+ NS_ASSERTION(!(aIsDataUserFont && aIsLocalUserFont),
+ "userfont is either a data font or a local font");
+ mIsDataUserFont = aIsDataUserFont;
+ mIsLocalUserFont = aIsLocalUserFont;
+}
+
+gfxFontEntry* MacOSFontEntry::Clone() const {
+ MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
+ MacOSFontEntry* fe = new MacOSFontEntry(Name(), Weight(), mStandardFace, mSizeHint);
+ fe->mStyleRange = mStyleRange;
+ fe->mStretchRange = mStretchRange;
+ fe->mFixedPitch = mFixedPitch;
+ return fe;
+}
+
+CGFontRef MacOSFontEntry::GetFontRef() {
+ if (!mFontRefInitialized) {
+ // Cache the CGFontRef, to be released by our destructor.
+ mFontRef = CreateOrCopyFontRef();
+ mFontRefInitialized = true;
+ }
+ // Return a non-retained reference; caller does not need to release.
+ return mFontRef;
+}
+
+CGFontRef MacOSFontEntry::CreateOrCopyFontRef() {
+ if (mFontRef) {
+ // We have a cached CGFont, just add a reference. Caller must
+ // release, but we'll still own our reference.
+ ::CGFontRetain(mFontRef);
+ return mFontRef;
+ }
+
+ CrashReporter::AutoAnnotateCrashReport autoFontName(CrashReporter::Annotation::FontName, mName);
+
+ // Create a new CGFont; caller will own the only reference to it.
+ NSString* psname = GetNSStringForString(NS_ConvertUTF8toUTF16(mName));
+ CGFontRef ref = CGFontCreateWithFontName(CFStringRef(psname));
+ if (!ref) {
+ // This happens on macOS 10.12 for font entry names that start with
+ // .AppleSystemUIFont. For those fonts, we need to go through NSFont
+ // to get the correct CGFontRef.
+ // Both the Text and the Display variant of the display font use
+ // .AppleSystemUIFontSomethingSomething as their member names.
+ // That's why we're carrying along mSizeHint to this place so that
+ // we get the variant that we want for this family.
+ NSFont* font = [NSFont fontWithName:psname size:mSizeHint];
+ if (font) {
+ ref = CTFontCopyGraphicsFont((CTFontRef)font, nullptr);
+ }
+ }
+ return ref; // Not saved in mFontRef; caller will own the reference
+}
+
+// For a logging build, we wrap the CFDataRef in a FontTableRec so that we can
+// use the MOZ_COUNT_[CD]TOR macros in it. A release build without logging
+// does not get this overhead.
+class FontTableRec {
+ public:
+ explicit FontTableRec(CFDataRef aDataRef) : mDataRef(aDataRef) { MOZ_COUNT_CTOR(FontTableRec); }
+
+ ~FontTableRec() {
+ MOZ_COUNT_DTOR(FontTableRec);
+ ::CFRelease(mDataRef);
+ }
+
+ private:
+ CFDataRef mDataRef;
+};
+
+/*static*/ void MacOSFontEntry::DestroyBlobFunc(void* aUserData) {
+#ifdef NS_BUILD_REFCNT_LOGGING
+ FontTableRec* ftr = static_cast<FontTableRec*>(aUserData);
+ delete ftr;
+#else
+ ::CFRelease((CFDataRef)aUserData);
+#endif
+}
+
+hb_blob_t* MacOSFontEntry::GetFontTable(uint32_t aTag) {
+ AutoCFRelease<CGFontRef> fontRef = CreateOrCopyFontRef();
+ if (!fontRef) {
+ return nullptr;
+ }
+
+ CFDataRef dataRef = ::CGFontCopyTableForTag(fontRef, aTag);
+ if (dataRef) {
+ return hb_blob_create((const char*)::CFDataGetBytePtr(dataRef), ::CFDataGetLength(dataRef),
+ HB_MEMORY_MODE_READONLY,
+#ifdef NS_BUILD_REFCNT_LOGGING
+ new FontTableRec(dataRef),
+#else
+ (void*)dataRef,
+#endif
+ DestroyBlobFunc);
+ }
+
+ return nullptr;
+}
+
+bool MacOSFontEntry::HasFontTable(uint32_t aTableTag) {
+ if (mAvailableTables.Count() == 0) {
+ nsAutoreleasePool localPool;
+
+ AutoCFRelease<CGFontRef> fontRef = CreateOrCopyFontRef();
+ if (!fontRef) {
+ return false;
+ }
+ AutoCFRelease<CFArrayRef> tags = ::CGFontCopyTableTags(fontRef);
+ if (!tags) {
+ return false;
+ }
+ int numTags = (int)::CFArrayGetCount(tags);
+ for (int t = 0; t < numTags; t++) {
+ uint32_t tag = (uint32_t)(uintptr_t)::CFArrayGetValueAtIndex(tags, t);
+ mAvailableTables.PutEntry(tag);
+ }
+ }
+
+ return mAvailableTables.GetEntry(aTableTag);
+}
+
+static bool CheckForAATSmallCaps(CFArrayRef aFeatures) {
+ // Walk the array of feature descriptors from the font, and see whether
+ // a small-caps feature setting is available.
+ // Just bail out (returning false) if at any point we fail to find the
+ // expected dictionary keys, etc; if the font has bad data, we don't even
+ // try to search the rest of it.
+ auto numFeatures = CFArrayGetCount(aFeatures);
+ for (auto f = 0; f < numFeatures; ++f) {
+ auto featureDict = (CFDictionaryRef)CFArrayGetValueAtIndex(aFeatures, f);
+ if (!featureDict) {
+ return false;
+ }
+ auto featureNum =
+ (CFNumberRef)CFDictionaryGetValue(featureDict, CFSTR("CTFeatureTypeIdentifier"));
+ if (!featureNum) {
+ return false;
+ }
+ int16_t featureType;
+ if (!CFNumberGetValue(featureNum, kCFNumberSInt16Type, &featureType)) {
+ return false;
+ }
+ if (featureType == kLetterCaseType || featureType == kLowerCaseType) {
+ // Which selector to look for, depending whether we've found the
+ // legacy LetterCase feature or the new LowerCase one.
+ const uint16_t smallCaps =
+ (featureType == kLetterCaseType) ? kSmallCapsSelector : kLowerCaseSmallCapsSelector;
+ auto selectors =
+ (CFArrayRef)CFDictionaryGetValue(featureDict, CFSTR("CTFeatureTypeSelectors"));
+ if (!selectors) {
+ return false;
+ }
+ auto numSelectors = CFArrayGetCount(selectors);
+ for (auto s = 0; s < numSelectors; s++) {
+ auto selectorDict = (CFDictionaryRef)CFArrayGetValueAtIndex(selectors, s);
+ if (!selectorDict) {
+ return false;
+ }
+ auto selectorNum =
+ (CFNumberRef)CFDictionaryGetValue(selectorDict, CFSTR("CTFeatureSelectorIdentifier"));
+ if (!selectorNum) {
+ return false;
+ }
+ int16_t selectorValue;
+ if (!CFNumberGetValue(selectorNum, kCFNumberSInt16Type, &selectorValue)) {
+ return false;
+ }
+ if (selectorValue == smallCaps) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool MacOSFontEntry::SupportsOpenTypeFeature(Script aScript, uint32_t aFeatureTag) {
+ // If we're going to shape with Core Text, we don't support added
+ // OpenType features (aside from any CT applies by default), except
+ // for 'smcp' which we map to an AAT feature selector.
+ if (RequiresAATLayout()) {
+ if (aFeatureTag != HB_TAG('s', 'm', 'c', 'p')) {
+ return false;
+ }
+ if (mHasAATSmallCapsInitialized) {
+ return mHasAATSmallCaps;
+ }
+ mHasAATSmallCapsInitialized = true;
+ CGFontRef cgFont = GetFontRef();
+ if (!cgFont) {
+ return mHasAATSmallCaps;
+ }
+
+ CrashReporter::AutoAnnotateCrashReport autoFontName(CrashReporter::Annotation::FontName,
+ FamilyName());
+
+ AutoCFRelease<CTFontRef> ctFont = CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr);
+ if (ctFont) {
+ AutoCFRelease<CFArrayRef> features = CTFontCopyFeatures(ctFont);
+ if (features) {
+ mHasAATSmallCaps = CheckForAATSmallCaps(features);
+ }
+ }
+ return mHasAATSmallCaps;
+ }
+ return gfxFontEntry::SupportsOpenTypeFeature(aScript, aFeatureTag);
+}
+
+void MacOSFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+ FontListSizes* aSizes) const {
+ aSizes->mFontListSize += aMallocSizeOf(this);
+ AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
+}
+
+/* gfxMacFontFamily */
+#pragma mark -
+
+class gfxMacFontFamily final : public gfxFontFamily {
+ public:
+ gfxMacFontFamily(const nsACString& aName, FontVisibility aVisibility, double aSizeHint = 0.0)
+ : gfxFontFamily(aName, aVisibility), mSizeHint(aSizeHint) {}
+
+ gfxMacFontFamily(const nsACString& aName, NSFont* aSystemFont)
+ : gfxFontFamily(aName, FontVisibility::Unknown), mForSystemFont(aSystemFont) {
+ // I don't think the system font instance is at much risk of being deleted,
+ // but to be on the safe side let's retain a reference until we're finished
+ // using it for lazy initialization.
+ [mForSystemFont retain];
+ }
+
+ virtual ~gfxMacFontFamily() = default;
+
+ void LocalizedName(nsACString& aLocalizedName) override;
+
+ void FindStyleVariationsLocked(FontInfoData* aFontInfoData = nullptr)
+ MOZ_REQUIRES(mLock) override;
+
+ protected:
+ double mSizeHint = 0.0;
+
+ // If non-null, this is a family representing the system UI font, and should use
+ // the given NSFont as the basis for initialization as the normal font-manager APIs
+ // based on family name won't handle it.
+ NSFont* mForSystemFont = nullptr;
+};
+
+void gfxMacFontFamily::LocalizedName(nsACString& aLocalizedName) {
+ nsAutoreleasePool localPool;
+
+ // It's unsafe to call HasOtherFamilyNames off the main thread because
+ // it entrains FindStyleVariations, which calls GetWeightOverride, which
+ // retrieves prefs. And the pref names can change (via user overrides),
+ // so we can't use StaticPrefs to access them.
+ if (NS_IsMainThread() && !HasOtherFamilyNames()) {
+ aLocalizedName = mName;
+ return;
+ }
+
+ NSString* family = GetNSStringForString(NS_ConvertUTF8toUTF16(mName));
+ NSString* localized = [sFontManager localizedNameForFamily:family face:nil];
+
+ if (localized) {
+ nsAutoString locName;
+ GetStringForNSString(localized, locName);
+ CopyUTF16toUTF8(locName, aLocalizedName);
+ return;
+ }
+
+ // failed to get localized name, just use the canonical one
+ aLocalizedName = mName;
+}
+
+// Return the CSS weight value to use for the given face, overriding what
+// AppKit gives us (used to adjust families with bad weight values, see
+// bug 931426).
+// A return value of 0 indicates no override - use the existing weight.
+static inline int GetWeightOverride(const nsAString& aPSName) {
+ nsAutoCString prefName("font.weight-override.");
+ // The PostScript name is required to be ASCII; if it's not, the font is
+ // broken anyway, so we really don't care that this is lossy.
+ LossyAppendUTF16toASCII(aPSName, prefName);
+ return Preferences::GetInt(prefName.get(), 0);
+}
+
+void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
+ if (mHasStyles) {
+ return;
+ }
+
+ AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("gfxMacFontFamily::FindStyleVariations", LAYOUT, mName);
+
+ nsAutoreleasePool localPool;
+
+ if (mForSystemFont) {
+ MOZ_ASSERT(gfxPlatform::HasVariationFontSupport());
+
+ auto addToFamily = [&](NSFont* aNSFont) MOZ_REQUIRES(mLock) {
+ NSString* psNameNS = [[aNSFont fontDescriptor] postscriptName];
+ nsAutoString nameUTF16;
+ nsAutoCString psName;
+ nsCocoaUtils::GetStringForNSString(psNameNS, nameUTF16);
+ CopyUTF16toUTF8(nameUTF16, psName);
+
+ auto* fe = new MacOSFontEntry(psName, WeightRange(FontWeight::NORMAL), true, 0.0);
+
+ // Set the appropriate style, assuming it may not have a variation range.
+ fe->mStyleRange = SlantStyleRange(
+ ([[aNSFont fontDescriptor] symbolicTraits] & NSFontItalicTrait) ? FontSlantStyle::ITALIC
+ : FontSlantStyle::NORMAL);
+
+ // Set up weight (and width, if present) ranges.
+ fe->SetupVariationRanges();
+ AddFontEntryLocked(fe);
+ };
+
+ addToFamily(mForSystemFont);
+
+ // See if there is a corresponding italic face, and add it to the family.
+ NSFont* italicFont = [sFontManager convertFont:mForSystemFont toHaveTrait:NSItalicFontMask];
+ if (italicFont != mForSystemFont) {
+ addToFamily(italicFont);
+ }
+
+ [mForSystemFont release];
+ mForSystemFont = nullptr;
+ SetHasStyles(true);
+
+ return;
+ }
+
+ NSString* family = GetNSStringForString(NS_ConvertUTF8toUTF16(mName));
+
+ // create a font entry for each face
+ NSArray* fontfaces = [sFontManager
+ availableMembersOfFontFamily:family]; // returns an array of [psname, style name, weight,
+ // traits] elements, goofy api
+ int faceCount = [fontfaces count];
+ int faceIndex;
+
+ for (faceIndex = 0; faceIndex < faceCount; faceIndex++) {
+ NSArray* face = [fontfaces objectAtIndex:faceIndex];
+ NSString* psname = [face objectAtIndex:INDEX_FONT_POSTSCRIPT_NAME];
+ int32_t appKitWeight = [[face objectAtIndex:INDEX_FONT_WEIGHT] unsignedIntValue];
+ uint32_t macTraits = [[face objectAtIndex:INDEX_FONT_TRAITS] unsignedIntValue];
+ NSString* facename = [face objectAtIndex:INDEX_FONT_FACE_NAME];
+ bool isStandardFace = false;
+
+ if (appKitWeight == kAppleExtraLightWeight) {
+ // if the facename contains UltraLight, set the weight to the ultralight weight value
+ NSRange range = [facename rangeOfString:@"ultralight" options:NSCaseInsensitiveSearch];
+ if (range.location != NSNotFound) {
+ appKitWeight = kAppleUltraLightWeight;
+ }
+ }
+
+ // make a nsString
+ nsAutoString postscriptFontName;
+ GetStringForNSString(psname, postscriptFontName);
+
+ int32_t cssWeight = gfxMacPlatformFontList::AppleWeightToCSSWeight(appKitWeight);
+ // If we are on the startup-time InitFontList thread, we skip this as it
+ // wants to retrieve faces for the default font family, but cannot safely
+ // call the Preferences APIs. Fortunately, the default font doesn't actually
+ // depend on a weight override pref.
+ if (!gfxPlatformFontList::IsInitFontListThread()) {
+ int32_t weightOverride = GetWeightOverride(postscriptFontName);
+ if (weightOverride) {
+ // scale down and clamp, to get a value from 1..9
+ cssWeight = ((weightOverride + 50) / 100);
+ cssWeight = std::max(1, std::min(cssWeight, 9));
+ }
+ }
+ cssWeight *= 100; // scale up to CSS values
+
+ if ([facename isEqualToString:@"Regular"] || [facename isEqualToString:@"Bold"] ||
+ [facename isEqualToString:@"Italic"] || [facename isEqualToString:@"Oblique"] ||
+ [facename isEqualToString:@"Bold Italic"] || [facename isEqualToString:@"Bold Oblique"]) {
+ isStandardFace = true;
+ }
+
+ // create a font entry
+ MacOSFontEntry* fontEntry =
+ new MacOSFontEntry(NS_ConvertUTF16toUTF8(postscriptFontName),
+ WeightRange(FontWeight::FromInt(cssWeight)), isStandardFace, mSizeHint);
+ if (!fontEntry) {
+ break;
+ }
+
+ // set additional properties based on the traits reported by Cocoa
+ if (macTraits & (NSCondensedFontMask | NSNarrowFontMask | NSCompressedFontMask)) {
+ fontEntry->mStretchRange = StretchRange(FontStretch::CONDENSED);
+ } else if (macTraits & NSExpandedFontMask) {
+ fontEntry->mStretchRange = StretchRange(FontStretch::EXPANDED);
+ }
+ // Cocoa fails to set the Italic traits bit for HelveticaLightItalic,
+ // at least (see bug 611855), so check for style name endings as well
+ if ((macTraits & NSItalicFontMask) || [facename hasSuffix:@"Italic"] ||
+ [facename hasSuffix:@"Oblique"]) {
+ fontEntry->mStyleRange = SlantStyleRange(FontSlantStyle::ITALIC);
+ }
+ if (macTraits & NSFixedPitchFontMask) {
+ fontEntry->mFixedPitch = true;
+ }
+
+ if (gfxPlatform::HasVariationFontSupport()) {
+ fontEntry->SetupVariationRanges();
+ }
+
+ if (LOG_FONTLIST_ENABLED()) {
+ nsAutoCString weightString;
+ fontEntry->Weight().ToString(weightString);
+ nsAutoCString stretchString;
+ fontEntry->Stretch().ToString(stretchString);
+ LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
+ " with style: %s weight: %s stretch: %s"
+ " (apple-weight: %d macTraits: %8.8x)",
+ fontEntry->Name().get(), Name().get(),
+ fontEntry->IsItalic() ? "italic" : "normal", weightString.get(),
+ stretchString.get(), appKitWeight, macTraits));
+ }
+
+ // insert into font entry array of family
+ AddFontEntryLocked(fontEntry);
+ }
+
+ SortAvailableFonts();
+ SetHasStyles(true);
+
+ if (mIsBadUnderlineFamily) {
+ SetBadUnderlineFonts();
+ }
+
+ CheckForSimpleFamily();
+}
+
+/* gfxSingleFaceMacFontFamily */
+#pragma mark -
+
+class gfxSingleFaceMacFontFamily final : public gfxFontFamily {
+ public:
+ gfxSingleFaceMacFontFamily(const nsACString& aName, FontVisibility aVisibility)
+ : gfxFontFamily(aName, aVisibility) {
+ mFaceNamesInitialized = true; // omit from face name lists
+ }
+
+ virtual ~gfxSingleFaceMacFontFamily() = default;
+
+ void FindStyleVariationsLocked(FontInfoData* aFontInfoData = nullptr)
+ MOZ_REQUIRES(mLock) override{};
+
+ void LocalizedName(nsACString& aLocalizedName) override;
+
+ void ReadOtherFamilyNames(gfxPlatformFontList* aPlatformFontList) override;
+
+ bool IsSingleFaceFamily() const override { return true; }
+};
+
+void gfxSingleFaceMacFontFamily::LocalizedName(nsACString& aLocalizedName) {
+ nsAutoreleasePool localPool;
+
+ AutoReadLock lock(mLock);
+
+ if (!HasOtherFamilyNames()) {
+ aLocalizedName = mName;
+ return;
+ }
+
+ gfxFontEntry* fe = mAvailableFonts[0];
+ NSFont* font = [NSFont fontWithName:GetNSStringForString(NS_ConvertUTF8toUTF16(fe->Name()))
+ size:0.0];
+ if (font) {
+ NSString* localized = [font displayName];
+ if (localized) {
+ nsAutoString locName;
+ GetStringForNSString(localized, locName);
+ CopyUTF16toUTF8(locName, aLocalizedName);
+ return;
+ }
+ }
+
+ // failed to get localized name, just use the canonical one
+ aLocalizedName = mName;
+}
+
+void gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList* aPlatformFontList) {
+ AutoWriteLock lock(mLock);
+ if (mOtherFamilyNamesInitialized) {
+ return;
+ }
+
+ gfxFontEntry* fe = mAvailableFonts[0];
+ if (!fe) {
+ return;
+ }
+
+ const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
+
+ gfxFontEntry::AutoTable nameTable(fe, kNAME);
+ if (!nameTable) {
+ return;
+ }
+
+ mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable, true);
+
+ mOtherFamilyNamesInitialized = true;
+}
+
+/* gfxMacPlatformFontList */
+#pragma mark -
+
+gfxMacPlatformFontList::gfxMacPlatformFontList()
+ : gfxPlatformFontList(false), mDefaultFont(nullptr), mUseSizeSensitiveSystemFont(false) {
+ CheckFamilyList(kBaseFonts);
+
+#ifdef MOZ_BUNDLED_FONTS
+ // We activate bundled fonts if the pref is > 0 (on) or < 0 (auto), only an
+ // explicit value of 0 (off) will disable them.
+ if (StaticPrefs::gfx_bundled_fonts_activate_AtStartup() != 0) {
+ TimeStamp start = TimeStamp::Now();
+ ActivateBundledFonts();
+ TimeStamp end = TimeStamp::Now();
+ Telemetry::Accumulate(Telemetry::FONTLIST_BUNDLEDFONTS_ACTIVATE,
+ (end - start).ToMilliseconds());
+ }
+#endif
+
+ // cache this in a static variable so that MacOSFontFamily objects
+ // don't have to repeatedly look it up
+ sFontManager = [NSFontManager sharedFontManager];
+
+ // Load the font-list preferences now, so that we don't have to do it from
+ // Init[Shared]FontListForPlatform, which may be called off-main-thread.
+ gfxFontUtils::GetPrefsFontList("font.single-face-list", mSingleFaceFonts);
+ gfxFontUtils::GetPrefsFontList("font.preload-names-list", mPreloadFonts);
+}
+
+gfxMacPlatformFontList::~gfxMacPlatformFontList() {
+ AutoLock lock(mLock);
+
+ if (XRE_IsParentProcess()) {
+ ::CFNotificationCenterRemoveObserver(::CFNotificationCenterGetLocalCenter(), this,
+ kCTFontManagerRegisteredFontsChangedNotification, 0);
+ }
+
+ if (mDefaultFont) {
+ ::CFRelease(mDefaultFont);
+ }
+}
+
+void gfxMacPlatformFontList::AddFamily(const nsACString& aFamilyName, FontVisibility aVisibility) {
+ double sizeHint = 0.0;
+ if (aVisibility == FontVisibility::Hidden && mUseSizeSensitiveSystemFont &&
+ mSystemDisplayFontFamilyName.Equals(aFamilyName)) {
+ sizeHint = 128.0;
+ }
+
+ nsAutoCString key;
+ ToLowerCase(aFamilyName, key);
+
+ RefPtr<gfxFontFamily> familyEntry = new gfxMacFontFamily(aFamilyName, aVisibility, sizeHint);
+ mFontFamilies.InsertOrUpdate(key, RefPtr{familyEntry});
+
+ // check the bad underline blocklist
+ if (mBadUnderlineFamilyNames.ContainsSorted(key)) {
+ familyEntry->SetBadUnderlineFamily();
+ }
+}
+
+FontVisibility gfxMacPlatformFontList::GetVisibilityForFamily(const nsACString& aName) const {
+ if (aName[0] == '.' || aName.LowerCaseEqualsLiteral("lastresort")) {
+ return FontVisibility::Hidden;
+ }
+ if (FamilyInList(aName, kBaseFonts)) {
+ return FontVisibility::Base;
+ }
+#ifdef MOZ_BUNDLED_FONTS
+ if (mBundledFamilies.Contains(aName)) {
+ return FontVisibility::Base;
+ }
+#endif
+ return FontVisibility::User;
+}
+
+void gfxMacPlatformFontList::AddFamily(CFStringRef aFamily) {
+ NSString* family = (NSString*)aFamily;
+
+ // CTFontManager includes weird internal family names and
+ // LastResort, skip over those
+ if (!family || [family caseInsensitiveCompare:@"LastResort"] == NSOrderedSame ||
+ [family caseInsensitiveCompare:@".LastResort"] == NSOrderedSame) {
+ return;
+ }
+
+ nsAutoString familyName;
+ nsCocoaUtils::GetStringForNSString(family, familyName);
+
+ NS_ConvertUTF16toUTF8 nameUtf8(familyName);
+ AddFamily(nameUtf8, GetVisibilityForFamily(nameUtf8));
+}
+
+/* static */
+void gfxMacPlatformFontList::ActivateFontsFromDir(const nsACString& aDir,
+ nsTHashSet<nsCStringHashKey>* aLoadedFamilies) {
+ AutoCFRelease<CFURLRef> directory = CFURLCreateFromFileSystemRepresentation(
+ kCFAllocatorDefault, (const UInt8*)nsPromiseFlatCString(aDir).get(), aDir.Length(), true);
+ if (!directory) {
+ return;
+ }
+ AutoCFRelease<CFURLEnumeratorRef> enumerator = CFURLEnumeratorCreateForDirectoryURL(
+ kCFAllocatorDefault, directory, kCFURLEnumeratorDefaultBehavior, nullptr);
+ if (!enumerator) {
+ return;
+ }
+ AutoCFRelease<CFMutableArrayRef> urls =
+ ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ if (!urls) {
+ return;
+ }
+
+ CFURLRef url;
+ CFURLEnumeratorResult result;
+ do {
+ result = CFURLEnumeratorGetNextURL(enumerator, &url, nullptr);
+ if (result != kCFURLEnumeratorSuccess) {
+ continue;
+ }
+ CFArrayAppendValue(urls, url);
+
+ if (!aLoadedFamilies) {
+ continue;
+ }
+ AutoCFRelease<CFArrayRef> descriptors = CTFontManagerCreateFontDescriptorsFromURL(url);
+ if (!descriptors || !CFArrayGetCount(descriptors)) {
+ continue;
+ }
+ CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descriptors, 0);
+ AutoCFRelease<CFStringRef> name =
+ (CFStringRef)CTFontDescriptorCopyAttribute(desc, kCTFontFamilyNameAttribute);
+ nsAutoCString key;
+ key.SetLength((CFStringGetLength(name) + 1) * 3);
+ if (CFStringGetCString(name, key.BeginWriting(), key.Length(), kCFStringEncodingUTF8)) {
+ key.SetLength(strlen(key.get()));
+ aLoadedFamilies->Insert(key);
+ }
+ } while (result != kCFURLEnumeratorEnd);
+
+ CTFontManagerRegisterFontsForURLs(urls, kCTFontManagerScopeProcess, nullptr);
+}
+
+void gfxMacPlatformFontList::ReadSystemFontList(dom::SystemFontList* aList)
+ MOZ_NO_THREAD_SAFETY_ANALYSIS {
+ // Note: We rely on the records for mSystemTextFontFamilyName and
+ // mSystemDisplayFontFamilyName (if present) being *before* the main
+ // font list, so that those names are known in the content process
+ // by the time we add the actual family records to the font list.
+ aList->entries().AppendElement(FontFamilyListEntry(
+ mSystemTextFontFamilyName, FontVisibility::Unknown, kTextSizeSystemFontFamily));
+ if (mUseSizeSensitiveSystemFont) {
+ aList->entries().AppendElement(FontFamilyListEntry(
+ mSystemDisplayFontFamilyName, FontVisibility::Unknown, kDisplaySizeSystemFontFamily));
+ }
+ // Now collect the list of available families, with visibility attributes.
+ for (auto f = mFontFamilies.Iter(); !f.Done(); f.Next()) {
+ auto macFamily = f.Data().get();
+ if (macFamily->IsSingleFaceFamily()) {
+ continue; // skip, this will be recreated separately in the child
+ }
+ aList->entries().AppendElement(
+ FontFamilyListEntry(macFamily->Name(), macFamily->Visibility(), kStandardFontFamily));
+ }
+}
+
+void gfxMacPlatformFontList::PreloadNamesList() {
+ uint32_t numFonts = mPreloadFonts.Length();
+ for (uint32_t i = 0; i < numFonts; i++) {
+ nsAutoCString key;
+ GenerateFontListKey(mPreloadFonts[i], key);
+
+ // only search canonical names!
+ gfxFontFamily* familyEntry = mFontFamilies.GetWeak(key);
+ if (familyEntry) {
+ familyEntry->ReadOtherFamilyNames(this);
+ }
+ }
+}
+
+#if USE_DEPRECATED_FONT_FAMILY_NAMES
+static bool DeprecatedFamilyIsAvailable(const nsACString& aName) {
+ NSString* family = GetNSStringForString(NS_ConvertUTF8toUTF16(aName));
+ return [[sFontManager availableMembersOfFontFamily:family] count] > 0;
+}
+#endif
+
+nsresult gfxMacPlatformFontList::InitFontListForPlatform() {
+ nsAutoreleasePool localPool;
+
+ // The font registration thread was created early in startup, to give the
+ // system a head start on activating all the supplemental-language fonts.
+ // Here, we need to wait until it has finished its work.
+ gfxPlatformMac::WaitForFontRegistration();
+
+ Telemetry::AutoTimer<Telemetry::MAC_INITFONTLIST_TOTAL> timer;
+
+ InitSystemFontNames();
+
+ if (XRE_IsParentProcess()) {
+ static bool firstTime = true;
+ if (firstTime) {
+ ::CFNotificationCenterAddObserver(::CFNotificationCenterGetLocalCenter(), this,
+ RegisteredFontsChangedNotificationCallback,
+ kCTFontManagerRegisteredFontsChangedNotification, 0,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+ firstTime = false;
+ }
+
+ // We're not a content process, so get the available fonts directly
+ // from Core Text.
+ AutoCFRelease<CFArrayRef> familyNames = CTFontManagerCopyAvailableFontFamilyNames();
+ for (NSString* familyName in (NSArray*)(CFArrayRef)familyNames) {
+ AddFamily((CFStringRef)familyName);
+ }
+#if USE_DEPRECATED_FONT_FAMILY_NAMES
+ for (const auto& name : kDeprecatedFontFamilies) {
+ if (DeprecatedFamilyIsAvailable(name)) {
+ AddFamily(name, GetVisibilityForFamily(name));
+ }
+ }
+#endif
+ } else {
+ // Content process: use font list passed from the chrome process via
+ // the GetXPCOMProcessAttributes message, because it's much faster than
+ // querying Core Text again in the child.
+ auto& fontList = dom::ContentChild::GetSingleton()->SystemFontList();
+ for (FontFamilyListEntry& ffe : fontList.entries()) {
+ switch (ffe.entryType()) {
+ case kStandardFontFamily:
+ // On Catalina or later, we pre-initialize system font-family entries
+ // in InitSystemFontNames(), so we can just skip them here.
+ if (nsCocoaFeatures::OnCatalinaOrLater() &&
+ (ffe.familyName() == mSystemTextFontFamilyName ||
+ ffe.familyName() == mSystemDisplayFontFamilyName)) {
+ continue;
+ }
+ AddFamily(ffe.familyName(), ffe.visibility());
+ break;
+ case kTextSizeSystemFontFamily:
+ mSystemTextFontFamilyName = ffe.familyName();
+ break;
+ case kDisplaySizeSystemFontFamily:
+ mSystemDisplayFontFamilyName = ffe.familyName();
+ mUseSizeSensitiveSystemFont = true;
+ break;
+ }
+ }
+ fontList.entries().Clear();
+ }
+
+ InitSingleFaceList();
+
+ // to avoid full search of font name tables, seed the other names table with localized names from
+ // some of the prefs fonts which are accessed via their localized names. changes in the pref
+ // fonts will only cause a font lookup miss earlier. this is a simple optimization, it's not
+ // required for correctness
+ PreloadNamesList();
+
+ // start the delayed cmap loader
+ GetPrefsAndStartLoader();
+
+ return NS_OK;
+}
+
+void gfxMacPlatformFontList::InitSharedFontListForPlatform() {
+ nsAutoreleasePool localPool;
+
+ gfxPlatformMac::WaitForFontRegistration();
+
+ InitSystemFontNames();
+
+ if (XRE_IsParentProcess()) {
+ // Only the parent process listens for OS font-changed notifications;
+ // after rebuilding its list, it will update the content processes.
+ static bool firstTime = true;
+ if (firstTime) {
+ ::CFNotificationCenterAddObserver(::CFNotificationCenterGetLocalCenter(), this,
+ RegisteredFontsChangedNotificationCallback,
+ kCTFontManagerRegisteredFontsChangedNotification, 0,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+ firstTime = false;
+ }
+
+ AutoCFRelease<CFArrayRef> familyNames = CTFontManagerCopyAvailableFontFamilyNames();
+ nsTArray<fontlist::Family::InitData> families;
+ families.SetCapacity(CFArrayGetCount(familyNames)
+#if USE_DEPRECATED_FONT_FAMILY_NAMES
+ + ArrayLength(kDeprecatedFontFamilies)
+#endif
+ );
+ for (NSString* familyName in (NSArray*)(CFArrayRef)familyNames) {
+ nsAutoString name16;
+ GetStringForNSString(familyName, name16);
+ NS_ConvertUTF16toUTF8 name(name16);
+ nsAutoCString key;
+ GenerateFontListKey(name, key);
+ families.AppendElement(fontlist::Family::InitData(key, name, fontlist::Family::kNoIndex,
+ GetVisibilityForFamily(name)));
+ }
+#if USE_DEPRECATED_FONT_FAMILY_NAMES
+ for (const nsACString& name : kDeprecatedFontFamilies) {
+ if (DeprecatedFamilyIsAvailable(name)) {
+ nsAutoCString key;
+ GenerateFontListKey(name, key);
+ families.AppendElement(fontlist::Family::InitData(key, name, fontlist::Family::kNoIndex,
+ GetVisibilityForFamily(name)));
+ }
+ }
+#endif
+ SharedFontList()->SetFamilyNames(families);
+ InitAliasesForSingleFaceList();
+ GetPrefsAndStartLoader();
+ }
+}
+
+void gfxMacPlatformFontList::InitAliasesForSingleFaceList() {
+ for (const auto& familyName : mSingleFaceFonts) {
+ LOG_FONTLIST(("(fontlist-singleface) face name: %s\n", familyName.get()));
+ // Each entry in the "single face families" list is expected to be a
+ // colon-separated pair of FaceName:Family,
+ // where FaceName is the individual face name (psname) of a font
+ // that should be exposed as a separate family name,
+ // and Family is the standard family to which that face belongs.
+ // The only such face listed by default is
+ // Osaka-Mono:Osaka
+ auto colon = familyName.FindChar(':');
+ if (colon == kNotFound) {
+ continue;
+ }
+
+ // Look for the parent family in the main font family list,
+ // and ensure we have loaded its list of available faces.
+ nsAutoCString key;
+ GenerateFontListKey(Substring(familyName, colon + 1), key);
+ fontlist::Family* family = SharedFontList()->FindFamily(key);
+ if (!family) {
+ // The parent family is not present, so just ignore this entry.
+ continue;
+ }
+ if (!family->IsInitialized()) {
+ if (!gfxPlatformFontList::InitializeFamily(family)) {
+ // This shouldn't ever fail, but if it does, we can safely ignore it.
+ MOZ_ASSERT(false, "failed to initialize font family");
+ continue;
+ }
+ }
+
+ // Truncate the entry from prefs at the colon, so now it is just the
+ // desired single-face-family name.
+ nsAutoCString aliasName(Substring(familyName, 0, colon));
+
+ // Look through the family's faces to see if this one is present.
+ fontlist::FontList* list = SharedFontList();
+ const fontlist::Pointer* facePtrs = family->Faces(list);
+ for (size_t i = 0; i < family->NumFaces(); i++) {
+ if (facePtrs[i].IsNull()) {
+ continue;
+ }
+ auto face = static_cast<const fontlist::Face*>(facePtrs[i].ToPtr(list));
+ if (face->mDescriptor.AsString(list).Equals(aliasName)) {
+ // Found it! Create an entry in the Alias table.
+ GenerateFontListKey(aliasName, key);
+ if (SharedFontList()->FindFamily(key) || mAliasTable.Get(key)) {
+ // If the family name is already known, something's misconfigured;
+ // just ignore it.
+ MOZ_ASSERT(false, "single-face family already known");
+ break;
+ }
+ auto aliasData = mAliasTable.GetOrInsertNew(key);
+ // The "alias" here isn't based on an existing family, so we don't call
+ // aliasData->InitFromFamily(); the various flags are left as defaults.
+ aliasData->mFaces.AppendElement(facePtrs[i]);
+ aliasData->mBaseFamily = aliasName;
+ aliasData->mVisibility = family->Visibility();
+ break;
+ }
+ }
+ }
+ if (!mAliasTable.IsEmpty()) {
+ // This will be updated when the font loader completes, but we require
+ // at least the Osaka-Mono alias to be available immediately.
+ SharedFontList()->SetAliases(mAliasTable);
+ }
+}
+
+void gfxMacPlatformFontList::InitSingleFaceList() {
+ for (const auto& familyName : mSingleFaceFonts) {
+ LOG_FONTLIST(("(fontlist-singleface) face name: %s\n", familyName.get()));
+ // Each entry in the "single face families" list is expected to be a
+ // colon-separated pair of FaceName:Family,
+ // where FaceName is the individual face name (psname) of a font
+ // that should be exposed as a separate family name,
+ // and Family is the standard family to which that face belongs.
+ // The only such face listed by default is
+ // Osaka-Mono:Osaka
+ auto colon = familyName.FindChar(':');
+ if (colon == kNotFound) {
+ continue;
+ }
+
+ // Look for the parent family in the main font family list,
+ // and ensure we have loaded its list of available faces.
+ nsAutoCString key(Substring(familyName, colon + 1));
+ ToLowerCase(key);
+ gfxFontFamily* family = mFontFamilies.GetWeak(key);
+ if (!family || family->IsHidden()) {
+ continue;
+ }
+ family->FindStyleVariations();
+
+ // Truncate the entry from prefs at the colon, so now it is just the
+ // desired single-face-family name.
+ nsAutoCString aliasName(Substring(familyName, 0, colon));
+
+ // Look through the family's faces to see if this one is present.
+ const gfxFontEntry* fe = nullptr;
+ family->ReadLock();
+ for (const auto& face : family->GetFontList()) {
+ if (face->Name().Equals(aliasName)) {
+ fe = face;
+ break;
+ }
+ }
+ family->ReadUnlock();
+ if (!fe) {
+ continue;
+ }
+
+ // We found the correct face, so create the single-face family record.
+ GenerateFontListKey(aliasName, key);
+ LOG_FONTLIST(("(fontlist-singleface) family name: %s, key: %s\n", aliasName.get(), key.get()));
+
+ // add only if doesn't exist already
+ if (!mFontFamilies.GetWeak(key)) {
+ RefPtr<gfxFontFamily> familyEntry =
+ new gfxSingleFaceMacFontFamily(aliasName, family->Visibility());
+ // We need a separate font entry, because its family name will
+ // differ from the one we found in the main list.
+ MacOSFontEntry* fontEntry = new MacOSFontEntry(
+ fe->Name(), fe->Weight(), true, static_cast<const MacOSFontEntry*>(fe)->mSizeHint);
+ familyEntry->AddFontEntry(fontEntry);
+ familyEntry->SetHasStyles(true);
+ mFontFamilies.InsertOrUpdate(key, std::move(familyEntry));
+ LOG_FONTLIST(
+ ("(fontlist-singleface) added new family: %s, key: %s\n", aliasName.get(), key.get()));
+ }
+ }
+}
+
+// System fonts under OSX may contain weird "meta" names but if we create
+// a new font using just the Postscript name, the NSFont api returns an object
+// with the actual real family name. For example, under OSX 10.11:
+//
+// [[NSFont menuFontOfSize:8.0] familyName] ==> .AppleSystemUIFont
+// [[NSFont fontWithName:[[[NSFont menuFontOfSize:8.0] fontDescriptor] postscriptName]
+// size:8.0] familyName] ==> .SF NS Text
+
+static NSString* GetRealFamilyName(NSFont* aFont) {
+ NSString* psName = [[aFont fontDescriptor] postscriptName];
+ // With newer macOS versions and SDKs (e.g. when compiled against SDK 10.15),
+ // [NSFont fontWithName:] fails for hidden system fonts, because the underlying
+ // Core Text functions it uses reject such names and tell us to use the special
+ // CTFontCreateUIFontForLanguage API instead.
+ // To work around this, as we don't yet work directly with the CTFontUIFontType
+ // identifiers, we create a Core Graphics font (as it doesn't reject system font
+ // names), and use this to create a Core Text font that we can query for the
+ // family name.
+ // Eventually we should move to using CTFontUIFontType constants to identify
+ // system fonts, and eliminate the need to instantiate them (indirectly) from
+ // their postscript names.
+ AutoCFRelease<CGFontRef> cgFont = CGFontCreateWithFontName(CFStringRef(psName));
+ if (!cgFont) {
+ return [aFont familyName];
+ }
+
+ AutoCFRelease<CTFontRef> ctFont = CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr);
+ if (!ctFont) {
+ return [aFont familyName];
+ }
+ NSString* familyName = (NSString*)CTFontCopyFamilyName(ctFont);
+
+ return [familyName autorelease];
+}
+
+// System fonts under OSX 10.11 use a combination of two families, one
+// for text sizes and another for larger, display sizes. Each has a
+// different number of weights. There aren't efficient API's for looking
+// this information up, so hard code the logic here but confirm via
+// debug assertions that the logic is correct.
+
+const CGFloat kTextDisplayCrossover = 20.0; // use text family below this size
+
+void gfxMacPlatformFontList::InitSystemFontNames() {
+ // On Catalina+, the system font uses optical sizing rather than individual
+ // faces, so we don't need to look for a separate display-sized face.
+ mUseSizeSensitiveSystemFont = !nsCocoaFeatures::OnCatalinaOrLater();
+
+ // text font family
+ NSFont* sys = [NSFont systemFontOfSize:0.0];
+ NSString* textFamilyName = GetRealFamilyName(sys);
+ nsAutoString familyName;
+ nsCocoaUtils::GetStringForNSString(textFamilyName, familyName);
+ CopyUTF16toUTF8(familyName, mSystemTextFontFamilyName);
+
+ // On Catalina or later, we store an in-process gfxFontFamily for the system font
+ // even if using the shared fontlist to manage "normal" fonts, because the hidden
+ // system fonts may be excluded from the font list altogether.
+ if (nsCocoaFeatures::OnCatalinaOrLater()) {
+ // This family will be populated based on the given NSFont.
+ RefPtr<gfxFontFamily> fam = new gfxMacFontFamily(mSystemTextFontFamilyName, sys);
+ if (fam) {
+ nsAutoCString key;
+ GenerateFontListKey(mSystemTextFontFamilyName, key);
+ mFontFamilies.InsertOrUpdate(key, std::move(fam));
+ }
+ }
+
+ // display font family, if on OSX 10.11 - 10.14
+ if (mUseSizeSensitiveSystemFont) {
+ NSFont* displaySys = [NSFont systemFontOfSize:128.0];
+ NSString* displayFamilyName = GetRealFamilyName(displaySys);
+ if ([displayFamilyName isEqualToString:textFamilyName]) {
+ mUseSizeSensitiveSystemFont = false;
+ } else {
+ nsCocoaUtils::GetStringForNSString(displayFamilyName, familyName);
+ CopyUTF16toUTF8(familyName, mSystemDisplayFontFamilyName);
+ }
+ }
+
+#ifdef DEBUG
+ // different system font API's always map to the same family under OSX, so
+ // just assume that and emit a warning if that ever changes
+ NSString* sysFamily = GetRealFamilyName([NSFont systemFontOfSize:0.0]);
+ if ([sysFamily compare:GetRealFamilyName([NSFont boldSystemFontOfSize:0.0])] != NSOrderedSame ||
+ [sysFamily compare:GetRealFamilyName([NSFont controlContentFontOfSize:0.0])] !=
+ NSOrderedSame ||
+ [sysFamily compare:GetRealFamilyName([NSFont menuBarFontOfSize:0.0])] != NSOrderedSame ||
+ [sysFamily compare:GetRealFamilyName([NSFont toolTipsFontOfSize:0.0])] != NSOrderedSame) {
+ NS_WARNING("system font types map to different font families"
+ " -- please log a bug!!");
+ }
+#endif
+}
+
+gfxFontFamily* gfxMacPlatformFontList::FindSystemFontFamily(const nsACString& aFamily) {
+ nsAutoCString key;
+ GenerateFontListKey(aFamily, key);
+
+ gfxFontFamily* familyEntry;
+ if ((familyEntry = mFontFamilies.GetWeak(key))) {
+ return CheckFamily(familyEntry);
+ }
+
+ return nullptr;
+}
+
+void gfxMacPlatformFontList::RegisteredFontsChangedNotificationCallback(
+ CFNotificationCenterRef center, void* observer, CFStringRef name, const void* object,
+ CFDictionaryRef userInfo) {
+ if (!::CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification)) {
+ return;
+ }
+
+ gfxMacPlatformFontList* fl = static_cast<gfxMacPlatformFontList*>(observer);
+ if (!fl->IsInitialized()) {
+ return;
+ }
+
+ // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
+ fl->UpdateFontList();
+
+ gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::Yes);
+ dom::ContentParent::NotifyUpdatedFonts(true);
+}
+
+gfxFontEntry* gfxMacPlatformFontList::PlatformGlobalFontFallback(nsPresContext* aPresContext,
+ const uint32_t aCh,
+ Script aRunScript,
+ const gfxFontStyle* aMatchStyle,
+ FontFamily& aMatchedFamily) {
+ CFStringRef str;
+ UniChar ch[2];
+ CFIndex length = 1;
+
+ if (IS_IN_BMP(aCh)) {
+ ch[0] = aCh;
+ str = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 1, kCFAllocatorNull);
+ } else {
+ ch[0] = H_SURROGATE(aCh);
+ ch[1] = L_SURROGATE(aCh);
+ str = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 2, kCFAllocatorNull);
+ if (!str) {
+ return nullptr;
+ }
+ length = 2;
+ }
+
+ // use CoreText to find the fallback family
+
+ gfxFontEntry* fontEntry = nullptr;
+ bool cantUseFallbackFont = false;
+
+ if (!mDefaultFont) {
+ mDefaultFont = ::CTFontCreateWithName(CFSTR("LucidaGrande"), 12.f, NULL);
+ }
+
+ AutoCFRelease<CTFontRef> fallback =
+ ::CTFontCreateForString(mDefaultFont, str, ::CFRangeMake(0, length));
+
+ if (fallback) {
+ AutoCFRelease<CFStringRef> familyNameRef = ::CTFontCopyFamilyName(fallback);
+
+ if (familyNameRef &&
+ ::CFStringCompare(familyNameRef, CFSTR("LastResort"), kCFCompareCaseInsensitive) !=
+ kCFCompareEqualTo &&
+ ::CFStringCompare(familyNameRef, CFSTR(".LastResort"), kCFCompareCaseInsensitive) !=
+ kCFCompareEqualTo) {
+ AutoTArray<UniChar, 1024> buffer;
+ CFIndex familyNameLen = ::CFStringGetLength(familyNameRef);
+ buffer.SetLength(familyNameLen + 1);
+ ::CFStringGetCharacters(familyNameRef, ::CFRangeMake(0, familyNameLen), buffer.Elements());
+ buffer[familyNameLen] = 0;
+ NS_ConvertUTF16toUTF8 familyNameString(reinterpret_cast<char16_t*>(buffer.Elements()),
+ familyNameLen);
+
+ if (SharedFontList()) {
+ fontlist::Family* family = FindSharedFamily(aPresContext, familyNameString);
+ if (family) {
+ fontlist::Face* face = family->FindFaceForStyle(SharedFontList(), *aMatchStyle);
+ if (face) {
+ fontEntry = GetOrCreateFontEntryLocked(face, family);
+ }
+ if (fontEntry) {
+ if (fontEntry->HasCharacter(aCh)) {
+ aMatchedFamily = FontFamily(family);
+ } else {
+ fontEntry = nullptr;
+ cantUseFallbackFont = true;
+ }
+ }
+ }
+ }
+
+ // The macOS system font does not appear in the shared font list, so if
+ // we didn't find the fallback font above, we should also check for an
+ // unshared fontFamily in the system list.
+ if (!fontEntry) {
+ gfxFontFamily* family = FindSystemFontFamily(familyNameString);
+ if (family) {
+ fontEntry = family->FindFontForStyle(*aMatchStyle);
+ if (fontEntry) {
+ if (fontEntry->HasCharacter(aCh)) {
+ aMatchedFamily = FontFamily(family);
+ } else {
+ fontEntry = nullptr;
+ cantUseFallbackFont = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (cantUseFallbackFont) {
+ Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, cantUseFallbackFont);
+ }
+
+ ::CFRelease(str);
+
+ return fontEntry;
+}
+
+FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform(nsPresContext* aPresContext,
+ const gfxFontStyle* aStyle,
+ nsAtom* aLanguage) {
+ nsAutoreleasePool localPool;
+
+ NSString* defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
+ nsAutoString familyName;
+
+ GetStringForNSString(defaultFamily, familyName);
+ return FindFamily(aPresContext, NS_ConvertUTF16toUTF8(familyName));
+}
+
+int32_t gfxMacPlatformFontList::AppleWeightToCSSWeight(int32_t aAppleWeight) {
+ if (aAppleWeight < 1)
+ aAppleWeight = 1;
+ else if (aAppleWeight > kAppleMaxWeight)
+ aAppleWeight = kAppleMaxWeight;
+ return gAppleWeightToCSSWeight[aAppleWeight];
+}
+
+gfxFontEntry* gfxMacPlatformFontList::LookupLocalFont(nsPresContext* aPresContext,
+ const nsACString& aFontName,
+ WeightRange aWeightForEntry,
+ StretchRange aStretchForEntry,
+ SlantStyleRange aStyleForEntry) {
+ if (aFontName.IsEmpty() || aFontName[0] == '.') {
+ return nullptr;
+ }
+
+ AutoLock lock(mLock);
+
+ nsAutoreleasePool localPool;
+
+ CrashReporter::AutoAnnotateCrashReport autoFontName(CrashReporter::Annotation::FontName,
+ aFontName);
+
+ NSString* faceName = GetNSStringForString(NS_ConvertUTF8toUTF16(aFontName));
+
+ // lookup face based on postscript or full name
+ AutoCFRelease<CGFontRef> fontRef = CGFontCreateWithFontName(CFStringRef(faceName));
+ if (!fontRef) {
+ return nullptr;
+ }
+
+ // It's possible for CGFontCreateWithFontName to return a font that has been
+ // deactivated/uninstalled, or a font that is excluded from the font list due
+ // to CSS font-visibility restriction. So we need to check whether this font is
+ // allowed to be used.
+
+ // CGFontRef doesn't offer a family-name API, so we go via a CTFontRef.
+ AutoCFRelease<CTFontRef> ctFont = CTFontCreateWithGraphicsFont(fontRef, 0.0, nullptr, nullptr);
+ if (!ctFont) {
+ return nullptr;
+ }
+ AutoCFRelease<CFStringRef> name = CTFontCopyFamilyName(ctFont);
+
+ // Convert the family name to a key suitable for font-list lookup (8-bit, lowercased).
+ nsAutoCString key;
+ // CFStringGetLength is in UTF-16 code units. The maximum this count can expand
+ // when converted to UTF-8 is 3x. We add 1 to ensure there will also be space for
+ // null-termination of the resulting C string.
+ key.SetLength((CFStringGetLength(name) + 1) * 3);
+ if (!CFStringGetCString(name, key.BeginWriting(), key.Length(), kCFStringEncodingUTF8)) {
+ // This shouldn't ever happen, but if it does we just bail.
+ NS_WARNING("Failed to get family name?");
+ key.Truncate(0);
+ }
+ if (key.IsEmpty()) {
+ return nullptr;
+ }
+ // Reset our string length to match the actual C string we got, which will usually
+ // be much shorter than the maximal buffer we allocated.
+ key.Truncate(strlen(key.get()));
+ ToLowerCase(key);
+ // If the family can't be looked up, this font is not available for use.
+ FontFamily family = FindFamily(aPresContext, key);
+ if (family.IsNull()) {
+ return nullptr;
+ }
+
+ return new MacOSFontEntry(aFontName, fontRef, aWeightForEntry, aStretchForEntry, aStyleForEntry,
+ false, true);
+}
+
+static void ReleaseData(void* info, const void* data, size_t size) { free((void*)data); }
+
+gfxFontEntry* gfxMacPlatformFontList::MakePlatformFont(const nsACString& aFontName,
+ WeightRange aWeightForEntry,
+ StretchRange aStretchForEntry,
+ SlantStyleRange aStyleForEntry,
+ const uint8_t* aFontData, uint32_t aLength) {
+ NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
+
+ // create the font entry
+ nsAutoString uniqueName;
+
+ nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
+ if (NS_FAILED(rv)) {
+ return nullptr;
+ }
+
+ CrashReporter::AutoAnnotateCrashReport autoFontName(CrashReporter::Annotation::FontName,
+ aFontName);
+
+ AutoCFRelease<CGDataProviderRef> provider =
+ ::CGDataProviderCreateWithData(nullptr, aFontData, aLength, &ReleaseData);
+ AutoCFRelease<CGFontRef> fontRef = ::CGFontCreateWithDataProvider(provider);
+ if (!fontRef) {
+ return nullptr;
+ }
+
+ auto newFontEntry =
+ MakeUnique<MacOSFontEntry>(NS_ConvertUTF16toUTF8(uniqueName), fontRef, aWeightForEntry,
+ aStretchForEntry, aStyleForEntry, true, false);
+ return newFontEntry.release();
+}
+
+// Webkit code uses a system font meta name, so mimic that here
+// WebCore/platform/graphics/mac/FontCacheMac.mm
+static const char kSystemFont_system[] = "-apple-system";
+
+bool gfxMacPlatformFontList::FindAndAddFamiliesLocked(
+ nsPresContext* aPresContext, StyleGenericFontFamily aGeneric, const nsACString& aFamily,
+ nsTArray<FamilyAndGeneric>* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle,
+ nsAtom* aLanguage, gfxFloat aDevToCssSize) {
+ if (aFamily.EqualsLiteral(kSystemFont_system)) {
+ // Search for special system font name, -apple-system. This is not done via
+ // the shared fontlist on Catalina or later, because the hidden system font
+ // may not be included there; we create a separate gfxFontFamily to manage
+ // this family.
+ const nsCString& systemFontFamilyName =
+ mUseSizeSensitiveSystemFont && aStyle &&
+ (aStyle->size * aDevToCssSize) >= kTextDisplayCrossover
+ ? mSystemDisplayFontFamilyName
+ : mSystemTextFontFamilyName;
+ if (SharedFontList() && !nsCocoaFeatures::OnCatalinaOrLater()) {
+ FindFamiliesFlags flags = aFlags | FindFamiliesFlags::eSearchHiddenFamilies;
+ return gfxPlatformFontList::FindAndAddFamiliesLocked(aPresContext, aGeneric,
+ systemFontFamilyName, aOutput, flags,
+ aStyle, aLanguage, aDevToCssSize);
+ } else {
+ if (auto* fam = FindSystemFontFamily(systemFontFamilyName)) {
+ aOutput->AppendElement(fam);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return gfxPlatformFontList::FindAndAddFamiliesLocked(aPresContext, aGeneric, aFamily, aOutput,
+ aFlags, aStyle, aLanguage, aDevToCssSize);
+}
+
+void gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID,
+ nsACString& aSystemFontName,
+ gfxFontStyle& aFontStyle) {
+ // Provide a local pool because we may be called from stylo threads.
+ nsAutoreleasePool localPool;
+
+ // code moved here from widget/cocoa/nsLookAndFeel.mm
+ NSFont* font = nullptr;
+ char* systemFontName = nullptr;
+ switch (aSystemFontID) {
+ case LookAndFeel::FontID::MessageBox:
+ case LookAndFeel::FontID::StatusBar:
+ case LookAndFeel::FontID::MozList:
+ case LookAndFeel::FontID::MozField:
+ case LookAndFeel::FontID::MozButton:
+ font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
+ systemFontName = (char*)kSystemFont_system;
+ break;
+
+ case LookAndFeel::FontID::SmallCaption:
+ font = [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]];
+ systemFontName = (char*)kSystemFont_system;
+ break;
+
+ case LookAndFeel::FontID::Icon: // used in urlbar; tried labelFont, but too small
+ font = [NSFont controlContentFontOfSize:0.0];
+ systemFontName = (char*)kSystemFont_system;
+ break;
+
+ case LookAndFeel::FontID::MozPullDownMenu:
+ font = [NSFont menuBarFontOfSize:0.0];
+ systemFontName = (char*)kSystemFont_system;
+ break;
+
+ case LookAndFeel::FontID::Caption:
+ case LookAndFeel::FontID::Menu:
+ default:
+ font = [NSFont systemFontOfSize:0.0];
+ systemFontName = (char*)kSystemFont_system;
+ break;
+ }
+ NS_ASSERTION(font, "system font not set");
+ NS_ASSERTION(systemFontName, "system font name not set");
+
+ if (systemFontName) {
+ aSystemFontName.AssignASCII(systemFontName);
+ }
+
+ NSFontSymbolicTraits traits = [[font fontDescriptor] symbolicTraits];
+ aFontStyle.style = (traits & NSFontItalicTrait) ? FontSlantStyle::ITALIC : FontSlantStyle::NORMAL;
+ aFontStyle.weight = (traits & NSFontBoldTrait) ? FontWeight::BOLD : FontWeight::NORMAL;
+ aFontStyle.stretch = (traits & NSFontExpandedTrait) ? FontStretch::EXPANDED
+ : (traits & NSFontCondensedTrait) ? FontStretch::CONDENSED
+ : FontStretch::NORMAL;
+ aFontStyle.size = [font pointSize];
+ aFontStyle.systemFont = true;
+}
+
+// used to load system-wide font info on off-main thread
+class MacFontInfo final : public FontInfoData {
+ public:
+ MacFontInfo(bool aLoadOtherNames, bool aLoadFaceNames, bool aLoadCmaps, RecursiveMutex& aLock)
+ : FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps), mLock(aLock) {}
+
+ virtual ~MacFontInfo() = default;
+
+ virtual void Load() {
+ nsAutoreleasePool localPool;
+ FontInfoData::Load();
+ }
+
+ // loads font data for all members of a given family
+ virtual void LoadFontFamilyData(const nsACString& aFamilyName);
+
+ RecursiveMutex& mLock;
+};
+
+void MacFontInfo::LoadFontFamilyData(const nsACString& aFamilyName) {
+ CrashReporter::AutoAnnotateCrashReport autoFontName(CrashReporter::Annotation::FontName,
+ aFamilyName);
+ // Prevent this from running concurrently with CGFont operations on the main thread,
+ // because the macOS font cache is fragile with concurrent access. This appears to be
+ // a vulnerability within CoreText in versions of macOS before macOS 13. In time, we
+ // can remove this lock.
+ RecursiveMutexAutoLock lock(mLock);
+
+ // family name ==> CTFontDescriptor
+ NSString* famName = GetNSStringForString(NS_ConvertUTF8toUTF16(aFamilyName));
+ CFStringRef family = CFStringRef(famName);
+
+ AutoCFRelease<CFMutableDictionaryRef> attr = CFDictionaryCreateMutable(
+ NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFDictionaryAddValue(attr, kCTFontFamilyNameAttribute, family);
+ AutoCFRelease<CTFontDescriptorRef> fd = CTFontDescriptorCreateWithAttributes(attr);
+ AutoCFRelease<CFArrayRef> matchingFonts = CTFontDescriptorCreateMatchingFontDescriptors(fd, NULL);
+ if (!matchingFonts) {
+ return;
+ }
+
+ nsTArray<nsCString> otherFamilyNames;
+ bool hasOtherFamilyNames = true;
+
+ // iterate over faces in the family
+ int f, numFaces = (int)CFArrayGetCount(matchingFonts);
+ for (f = 0; f < numFaces; f++) {
+ mLoadStats.fonts++;
+
+ CTFontDescriptorRef faceDesc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(matchingFonts, f);
+ if (!faceDesc) {
+ continue;
+ }
+ AutoCFRelease<CTFontRef> fontRef = CTFontCreateWithFontDescriptor(faceDesc, 0.0, nullptr);
+ if (!fontRef) {
+ NS_WARNING("failed to create a CTFontRef");
+ continue;
+ }
+
+ if (mLoadCmaps) {
+ // face name
+ AutoCFRelease<CFStringRef> faceName =
+ (CFStringRef)CTFontDescriptorCopyAttribute(faceDesc, kCTFontNameAttribute);
+
+ AutoTArray<UniChar, 1024> buffer;
+ CFIndex len = CFStringGetLength(faceName);
+ buffer.SetLength(len + 1);
+ CFStringGetCharacters(faceName, ::CFRangeMake(0, len), buffer.Elements());
+ buffer[len] = 0;
+ NS_ConvertUTF16toUTF8 fontName(reinterpret_cast<char16_t*>(buffer.Elements()), len);
+
+ // load the cmap data
+ FontFaceData fontData;
+ AutoCFRelease<CFDataRef> cmapTable =
+ CTFontCopyTable(fontRef, kCTFontTableCmap, kCTFontTableOptionNoOptions);
+
+ if (cmapTable) {
+ const uint8_t* cmapData = (const uint8_t*)CFDataGetBytePtr(cmapTable);
+ uint32_t cmapLen = CFDataGetLength(cmapTable);
+ RefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
+ uint32_t offset;
+ nsresult rv;
+
+ rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, offset);
+ if (NS_SUCCEEDED(rv)) {
+ fontData.mCharacterMap = charmap;
+ fontData.mUVSOffset = offset;
+ mLoadStats.cmaps++;
+ }
+ }
+
+ mFontFaceData.InsertOrUpdate(fontName, fontData);
+ }
+
+ if (mLoadOtherNames && hasOtherFamilyNames) {
+ AutoCFRelease<CFDataRef> nameTable =
+ CTFontCopyTable(fontRef, kCTFontTableName, kCTFontTableOptionNoOptions);
+
+ if (nameTable) {
+ const char* nameData = (const char*)CFDataGetBytePtr(nameTable);
+ uint32_t nameLen = CFDataGetLength(nameTable);
+ gfxFontUtils::ReadOtherFamilyNamesForFace(aFamilyName, nameData, nameLen, otherFamilyNames,
+ false);
+ hasOtherFamilyNames = otherFamilyNames.Length() != 0;
+ }
+ }
+ }
+
+ // if found other names, insert them in the hash table
+ if (otherFamilyNames.Length() != 0) {
+ mOtherFamilyNames.InsertOrUpdate(aFamilyName, otherFamilyNames);
+ mLoadStats.othernames += otherFamilyNames.Length();
+ }
+}
+
+already_AddRefed<FontInfoData> gfxMacPlatformFontList::CreateFontInfoData() {
+ bool loadCmaps =
+ !UsesSystemFallback() || gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
+
+ mLock.AssertCurrentThreadIn();
+ RefPtr<MacFontInfo> fi = new MacFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps, mLock);
+ return fi.forget();
+}
+
+gfxFontFamily* gfxMacPlatformFontList::CreateFontFamily(const nsACString& aName,
+ FontVisibility aVisibility) const {
+ return new gfxMacFontFamily(aName, aVisibility);
+}
+
+gfxFontEntry* gfxMacPlatformFontList::CreateFontEntry(fontlist::Face* aFace,
+ const fontlist::Family* aFamily) {
+ MacOSFontEntry* fe =
+ new MacOSFontEntry(aFace->mDescriptor.AsString(SharedFontList()), aFace->mWeight, false,
+ 0.0); // XXX standardFace, sizeHint
+ fe->InitializeFrom(aFace, aFamily);
+ return fe;
+}
+
+void gfxMacPlatformFontList::GetFacesInitDataForFamily(const fontlist::Family* aFamily,
+ nsTArray<fontlist::Face::InitData>& aFaces,
+ bool aLoadCmaps) const {
+ nsAutoreleasePool localPool;
+
+ auto name = aFamily->Key().AsString(SharedFontList());
+ NSString* family = GetNSStringForString(NS_ConvertUTF8toUTF16(name));
+
+ CrashReporter::AutoAnnotateCrashReport autoFontName(CrashReporter::Annotation::FontName, name);
+
+ // returns an array of [psname, style name, weight, traits] elements, goofy api
+ NSArray* fontfaces = [sFontManager availableMembersOfFontFamily:family];
+ int faceCount = [fontfaces count];
+ for (int faceIndex = 0; faceIndex < faceCount; faceIndex++) {
+ NSArray* face = [fontfaces objectAtIndex:faceIndex];
+ NSString* psname = [face objectAtIndex:INDEX_FONT_POSTSCRIPT_NAME];
+ int32_t appKitWeight = [[face objectAtIndex:INDEX_FONT_WEIGHT] unsignedIntValue];
+ uint32_t macTraits = [[face objectAtIndex:INDEX_FONT_TRAITS] unsignedIntValue];
+ NSString* facename = [face objectAtIndex:INDEX_FONT_FACE_NAME];
+
+ if (appKitWeight == kAppleExtraLightWeight) {
+ // if the facename contains UltraLight, set the weight to the ultralight weight value
+ NSRange range = [facename rangeOfString:@"ultralight" options:NSCaseInsensitiveSearch];
+ if (range.location != NSNotFound) {
+ appKitWeight = kAppleUltraLightWeight;
+ }
+ }
+
+ // make a nsString
+ nsAutoString postscriptFontName;
+ GetStringForNSString(psname, postscriptFontName);
+
+ int32_t cssWeight = gfxMacPlatformFontList::AppleWeightToCSSWeight(appKitWeight);
+ if (PR_GetCurrentThread() != sInitFontListThread) {
+ int32_t weightOverride = GetWeightOverride(postscriptFontName);
+ if (weightOverride) {
+ // scale down and clamp, to get a value from 1..9
+ cssWeight = ((weightOverride + 50) / 100);
+ cssWeight = std::max(1, std::min(cssWeight, 9));
+ }
+ }
+ cssWeight *= 100; // scale up to CSS values
+
+ StretchRange stretch(FontStretch::NORMAL);
+ if (macTraits & (NSCondensedFontMask | NSNarrowFontMask | NSCompressedFontMask)) {
+ stretch = StretchRange(FontStretch::CONDENSED);
+ } else if (macTraits & NSExpandedFontMask) {
+ stretch = StretchRange(FontStretch::EXPANDED);
+ }
+ // Cocoa fails to set the Italic traits bit for HelveticaLightItalic,
+ // at least (see bug 611855), so check for style name endings as well
+ SlantStyleRange slantStyle(FontSlantStyle::NORMAL);
+ if ((macTraits & NSItalicFontMask) || [facename hasSuffix:@"Italic"] ||
+ [facename hasSuffix:@"Oblique"]) {
+ slantStyle = SlantStyleRange(FontSlantStyle::ITALIC);
+ }
+
+ bool fixedPitch = (macTraits & NSFixedPitchFontMask) ? true : false;
+
+ RefPtr<gfxCharacterMap> charmap;
+ if (aLoadCmaps) {
+ AutoCFRelease<CGFontRef> font = CGFontCreateWithFontName(CFStringRef(psname));
+ if (font) {
+ uint32_t kCMAP = TRUETYPE_TAG('c', 'm', 'a', 'p');
+ AutoCFRelease<CFDataRef> data = CGFontCopyTableForTag(font, kCMAP);
+ if (data) {
+ uint32_t offset;
+ charmap = new gfxCharacterMap();
+ gfxFontUtils::ReadCMAP(CFDataGetBytePtr(data), CFDataGetLength(data), *charmap, offset);
+ }
+ }
+ }
+
+ // Ensure that a face named "Regular" goes to the front of the list, so it
+ // will take precedence over other faces with the same style attributes but
+ // a different name (such as "Outline").
+ auto data = fontlist::Face::InitData{
+ NS_ConvertUTF16toUTF8(postscriptFontName),
+ 0,
+ fixedPitch,
+ WeightRange(FontWeight::FromInt(cssWeight)),
+ stretch,
+ slantStyle,
+ charmap,
+ };
+ if ([facename caseInsensitiveCompare:@"Regular"] == NSOrderedSame) {
+ aFaces.InsertElementAt(0, std::move(data));
+ } else {
+ aFaces.AppendElement(std::move(data));
+ }
+ }
+}
+
+void gfxMacPlatformFontList::ReadFaceNamesForFamily(fontlist::Family* aFamily,
+ bool aNeedFullnamePostscriptNames) {
+ if (!aFamily->IsInitialized()) {
+ if (!InitializeFamily(aFamily)) {
+ return;
+ }
+ }
+ const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
+ fontlist::FontList* list = SharedFontList();
+ nsAutoCString canonicalName(aFamily->DisplayName().AsString(list));
+ const fontlist::Pointer* facePtrs = aFamily->Faces(list);
+ for (uint32_t i = 0, n = aFamily->NumFaces(); i < n; i++) {
+ auto face = static_cast<fontlist::Face*>(facePtrs[i].ToPtr(list));
+ if (!face) {
+ continue;
+ }
+ nsAutoCString name(face->mDescriptor.AsString(list));
+ // We create a temporary MacOSFontEntry just to read family names from the
+ // 'name' table in the font resource. The style attributes here are ignored
+ // as this entry is not used for font style matching.
+ // The size hint might be used to select which face is accessed in the case
+ // of the macOS UI font; see MacOSFontEntry::GetFontRef(). We pass 16.0 in
+ // order to get a standard text-size face in this case, although it's
+ // unlikely to matter for the purpose of just reading family names.
+ auto fe = MakeUnique<MacOSFontEntry>(name, WeightRange(FontWeight::NORMAL), false, 16.0);
+ if (!fe) {
+ continue;
+ }
+ gfxFontEntry::AutoTable nameTable(fe.get(), kNAME);
+ if (!nameTable) {
+ continue;
+ }
+ uint32_t dataLength;
+ const char* nameData = hb_blob_get_data(nameTable, &dataLength);
+ AutoTArray<nsCString, 4> otherFamilyNames;
+ gfxFontUtils::ReadOtherFamilyNamesForFace(canonicalName, nameData, dataLength, otherFamilyNames,
+ false);
+ for (const auto& alias : otherFamilyNames) {
+ nsAutoCString key;
+ GenerateFontListKey(alias, key);
+ auto aliasData = mAliasTable.GetOrInsertNew(key);
+ aliasData->InitFromFamily(aFamily, canonicalName);
+ aliasData->mFaces.AppendElement(facePtrs[i]);
+ }
+ }
+}
+
+#ifdef MOZ_BUNDLED_FONTS
+void gfxMacPlatformFontList::ActivateBundledFonts() {
+ nsCOMPtr<nsIFile> localDir;
+ if (NS_FAILED(NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir)))) {
+ return;
+ }
+ if (NS_FAILED(localDir->Append(u"fonts"_ns))) {
+ return;
+ }
+ nsAutoCString path;
+ if (NS_FAILED(localDir->GetNativePath(path))) {
+ return;
+ }
+ ActivateFontsFromDir(path, &mBundledFamilies);
+}
+#endif