1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "gfxPlatformMac.h"
8 #include "gfxQuartzSurface.h"
9 #include "mozilla/DataMutex.h"
10 #include "mozilla/gfx/2D.h"
12 #include "gfxMacPlatformFontList.h"
13 #include "gfxMacFont.h"
14 #include "gfxCoreTextShaper.h"
15 #include "gfxTextRun.h"
16 #include "gfxUserFontSet.h"
17 #include "gfxConfig.h"
19 #include "AppleUtils.h"
21 #include "mozilla/Preferences.h"
22 #include "mozilla/VsyncDispatcher.h"
23 #include "nsCocoaFeatures.h"
24 #include "nsComponentManagerUtils.h"
26 #include "nsUnicodeProperties.h"
28 #include "gfx2DGlue.h"
29 #include "GeckoProfiler.h"
30 #include "nsThreadUtils.h"
32 #ifdef MOZ_BUNDLED_FONTS
33 # include "mozilla/Telemetry.h"
34 # include "nsDirectoryServiceDefs.h"
35 # include "mozilla/StaticPrefs_gfx.h"
39 #include <CoreVideo/CoreVideo.h>
41 #include "mozilla/layers/CompositorBridgeParent.h"
42 #include "mozilla/layers/SurfacePool.h"
43 #include "VsyncSource.h"
45 using namespace mozilla
;
46 using namespace mozilla::gfx
;
47 using namespace mozilla::unicode
;
49 using mozilla::dom::SystemFontList
;
51 // A bunch of fonts for "additional language support" are shipped in a
52 // "Language Support" directory, and don't show up in the standard font
53 // list returned by CTFontManagerCopyAvailableFontFamilyNames unless
54 // we explicitly activate them.
55 static const nsLiteralCString kLangFontsDirs
[] = {
56 "/Library/Application Support/Apple/Fonts/Language Support"_ns
,
57 "/System/Library/Fonts/Supplemental"_ns
};
60 void gfxPlatformMac::FontRegistrationCallback(void* aUnused
) {
61 AUTO_PROFILER_REGISTER_THREAD("RegisterFonts");
62 PR_SetCurrentThreadName("RegisterFonts");
64 for (const auto& dir
: kLangFontsDirs
) {
65 gfxMacPlatformFontList::ActivateFontsFromDir(dir
);
69 PRThread
* gfxPlatformMac::sFontRegistrationThread
= nullptr;
71 /* This is called from XPCOM_Init during startup (before gfxPlatform has been
72 initialized), so that it can kick off the font activation on a secondary
73 thread, and hope that it'll be finished by the time we're ready to build
76 void gfxPlatformMac::RegisterSupplementalFonts() {
77 if (XRE_IsParentProcess()) {
78 sFontRegistrationThread
= PR_CreateThread(
79 PR_USER_THREAD
, FontRegistrationCallback
, nullptr, PR_PRIORITY_NORMAL
,
80 PR_GLOBAL_THREAD
, PR_JOINABLE_THREAD
, 0);
81 } else if (!nsCocoaFeatures::OnCatalinaOrLater()) {
82 // On Catalina+, it appears to be sufficient to activate fonts in the
83 // parent process; they are then also usable in child processes. But on
84 // pre-Catalina systems we need to explicitly activate them in each child
85 // process (per bug 1704273).
87 // But at least on 10.14 (Mojave), doing font registration on a separate
88 // thread in the content process seems crashy (bug 1708821), despite the
89 // CTFontManager.h header claiming that it's thread-safe. So we just do it
90 // immediately on the main thread, and accept the startup-time hit (sigh).
91 for (const auto& dir
: kLangFontsDirs
) {
92 gfxMacPlatformFontList::ActivateFontsFromDir(dir
);
98 void gfxPlatformMac::WaitForFontRegistration() {
99 if (sFontRegistrationThread
) {
100 PR_JoinThread(sFontRegistrationThread
);
101 sFontRegistrationThread
= nullptr;
105 gfxPlatformMac::gfxPlatformMac() {
106 mFontAntiAliasingThreshold
= ReadAntiAliasingThreshold();
108 InitBackendPrefs(GetBackendPrefs());
111 gfxPlatformMac::~gfxPlatformMac() { gfxCoreTextShaper::Shutdown(); }
113 BackendPrefsData
gfxPlatformMac::GetBackendPrefs() const {
114 BackendPrefsData data
;
116 data
.mCanvasBitmask
= BackendTypeBit(BackendType::SKIA
);
117 data
.mContentBitmask
= BackendTypeBit(BackendType::SKIA
);
118 data
.mCanvasDefault
= BackendType::SKIA
;
119 data
.mContentDefault
= BackendType::SKIA
;
124 bool gfxPlatformMac::CreatePlatformFontList() {
125 return gfxPlatformFontList::Initialize(new gfxMacPlatformFontList
);
128 void gfxPlatformMac::ReadSystemFontList(SystemFontList
* aFontList
) {
129 gfxMacPlatformFontList::PlatformFontList()->ReadSystemFontList(aFontList
);
132 already_AddRefed
<gfxASurface
> gfxPlatformMac::CreateOffscreenSurface(
133 const IntSize
& aSize
, gfxImageFormat aFormat
) {
134 if (!Factory::AllowedSurfaceSize(aSize
)) {
138 RefPtr
<gfxASurface
> newSurface
= new gfxQuartzSurface(aSize
, aFormat
);
139 return newSurface
.forget();
142 void gfxPlatformMac::GetCommonFallbackFonts(uint32_t aCh
, Script aRunScript
,
143 eFontPresentation aPresentation
,
144 nsTArray
<const char*>& aFontList
) {
145 if (PrefersColor(aPresentation
)) {
146 aFontList
.AppendElement("Apple Color Emoji");
149 switch (aRunScript
) {
150 case Script::INVALID
:
151 case Script::NUM_SCRIPT_CODES
:
152 // Ensure the switch covers all the Script enum values.
153 MOZ_ASSERT_UNREACHABLE("bad script code");
157 case Script::INHERITED
:
158 // In most cases, COMMON and INHERITED characters will be merged into
159 // their context, but if they occur without any specific script context
160 // we'll just try common default fonts here.
162 case Script::CYRILLIC
:
164 aFontList
.AppendElement("Lucida Grande");
167 case Script::MATHEMATICAL_NOTATION
:
168 case Script::SYMBOLS
:
169 case Script::SYMBOLS_EMOJI
:
170 // Not currently returned by script run resolution (but see below, after
174 // CJK-related script codes are a bit troublesome because of unification;
175 // we'll probably just get HAN much of the time, so the choice of which
176 // language font to try for fallback is rather arbitrary. Usually, though,
177 // we hope that font prefs will have handled this earlier.
178 case Script::BOPOMOFO
:
179 case Script::HAN_WITH_BOPOMOFO
:
180 case Script::SIMPLIFIED_HAN
:
182 aFontList
.AppendElement("Songti SC");
184 // macOS installations with MS Office may have these -ExtB fonts
185 aFontList
.AppendElement("SimSun-ExtB");
189 // Currently, we don't resolve script runs to this value, but we may do so
190 // in future if we get better at handling things like `lang=zh-Hant`, not
191 // just resolving based on the Unicode text.
192 case Script::TRADITIONAL_HAN
:
193 aFontList
.AppendElement("Songti TC");
195 // macOS installations with MS Office may have these -ExtB fonts
196 aFontList
.AppendElement("MingLiU-ExtB");
200 case Script::HIRAGANA
:
201 case Script::KATAKANA
:
202 case Script::KATAKANA_OR_HIRAGANA
:
203 case Script::JAPANESE
:
204 aFontList
.AppendElement("Hiragino Sans");
205 aFontList
.AppendElement("Hiragino Kaku Gothic ProN");
211 aFontList
.AppendElement("Nanum Gothic");
212 aFontList
.AppendElement("Apple SD Gothic Neo");
215 // For most other scripts, macOS comes with a default font we can use.
217 aFontList
.AppendElement("Geeza Pro");
219 case Script::ARMENIAN
:
220 aFontList
.AppendElement("Mshtakan");
222 case Script::BENGALI
:
223 aFontList
.AppendElement("Bangla Sangam MN");
225 case Script::CHEROKEE
:
226 aFontList
.AppendElement("Plantagenet Cherokee");
229 aFontList
.AppendElement("Noto Sans Coptic");
231 case Script::DESERET
:
232 aFontList
.AppendElement("Baskerville");
234 case Script::DEVANAGARI
:
235 aFontList
.AppendElement("Devanagari Sangam MN");
237 case Script::ETHIOPIC
:
238 aFontList
.AppendElement("Kefa");
240 case Script::GEORGIAN
:
241 aFontList
.AppendElement("Helvetica");
244 aFontList
.AppendElement("Noto Sans Gothic");
246 case Script::GUJARATI
:
247 aFontList
.AppendElement("Gujarati Sangam MN");
249 case Script::GURMUKHI
:
250 aFontList
.AppendElement("Gurmukhi MN");
253 aFontList
.AppendElement("Lucida Grande");
255 case Script::KANNADA
:
256 aFontList
.AppendElement("Kannada MN");
259 aFontList
.AppendElement("Khmer MN");
262 aFontList
.AppendElement("Lao MN");
264 case Script::MALAYALAM
:
265 aFontList
.AppendElement("Malayalam Sangam MN");
267 case Script::MONGOLIAN
:
268 aFontList
.AppendElement("Noto Sans Mongolian");
270 case Script::MYANMAR
:
271 aFontList
.AppendElement("Myanmar MN");
274 aFontList
.AppendElement("Noto Sans Ogham");
276 case Script::OLD_ITALIC
:
277 aFontList
.AppendElement("Noto Sans Old Italic");
280 aFontList
.AppendElement("Oriya Sangam MN");
283 aFontList
.AppendElement("Noto Sans Runic");
285 case Script::SINHALA
:
286 aFontList
.AppendElement("Sinhala Sangam MN");
289 aFontList
.AppendElement("Noto Sans Syriac");
292 aFontList
.AppendElement("Tamil MN");
295 aFontList
.AppendElement("Telugu MN");
298 aFontList
.AppendElement("Noto Sans Thaana");
301 aFontList
.AppendElement("Thonburi");
303 case Script::TIBETAN
:
304 aFontList
.AppendElement("Kailasa");
306 case Script::CANADIAN_ABORIGINAL
:
307 aFontList
.AppendElement("Euphemia UCAS");
310 aFontList
.AppendElement("Noto Sans Yi");
311 aFontList
.AppendElement("STHeiti");
313 case Script::TAGALOG
:
314 aFontList
.AppendElement("Noto Sans Tagalog");
316 case Script::HANUNOO
:
317 aFontList
.AppendElement("Noto Sans Hanunoo");
320 aFontList
.AppendElement("Noto Sans Buhid");
322 case Script::TAGBANWA
:
323 aFontList
.AppendElement("Noto Sans Tagbanwa");
325 case Script::BRAILLE
:
326 aFontList
.AppendElement("Apple Braille");
328 case Script::CYPRIOT
:
329 aFontList
.AppendElement("Noto Sans Cypriot");
332 aFontList
.AppendElement("Noto Sans Limbu");
334 case Script::LINEAR_B
:
335 aFontList
.AppendElement("Noto Sans Linear B");
337 case Script::OSMANYA
:
338 aFontList
.AppendElement("Noto Sans Osmanya");
340 case Script::SHAVIAN
:
341 aFontList
.AppendElement("Noto Sans Shavian");
344 aFontList
.AppendElement("Noto Sans Tai Le");
346 case Script::UGARITIC
:
347 aFontList
.AppendElement("Noto Sans Ugaritic");
349 case Script::BUGINESE
:
350 aFontList
.AppendElement("Noto Sans Buginese");
352 case Script::GLAGOLITIC
:
353 aFontList
.AppendElement("Noto Sans Glagolitic");
355 case Script::KHAROSHTHI
:
356 aFontList
.AppendElement("Noto Sans Kharoshthi");
358 case Script::SYLOTI_NAGRI
:
359 aFontList
.AppendElement("Noto Sans Syloti Nagri");
361 case Script::NEW_TAI_LUE
:
362 aFontList
.AppendElement("Noto Sans New Tai Lue");
364 case Script::TIFINAGH
:
365 aFontList
.AppendElement("Noto Sans Tifinagh");
367 case Script::OLD_PERSIAN
:
368 aFontList
.AppendElement("Noto Sans Old Persian");
370 case Script::BALINESE
:
371 aFontList
.AppendElement("Noto Sans Balinese");
374 aFontList
.AppendElement("Noto Sans Batak");
377 aFontList
.AppendElement("Noto Sans Brahmi");
380 aFontList
.AppendElement("Noto Sans Cham");
382 case Script::EGYPTIAN_HIEROGLYPHS
:
383 aFontList
.AppendElement("Noto Sans Egyptian Hieroglyphs");
385 case Script::PAHAWH_HMONG
:
386 aFontList
.AppendElement("Noto Sans Pahawh Hmong");
388 case Script::OLD_HUNGARIAN
:
389 aFontList
.AppendElement("Noto Sans Old Hungarian");
391 case Script::JAVANESE
:
392 aFontList
.AppendElement("Noto Sans Javanese");
394 case Script::KAYAH_LI
:
395 aFontList
.AppendElement("Noto Sans Kayah Li");
398 aFontList
.AppendElement("Noto Sans Lepcha");
400 case Script::LINEAR_A
:
401 aFontList
.AppendElement("Noto Sans Linear A");
403 case Script::MANDAIC
:
404 aFontList
.AppendElement("Noto Sans Mandaic");
407 aFontList
.AppendElement("Noto Sans NKo");
409 case Script::OLD_TURKIC
:
410 aFontList
.AppendElement("Noto Sans Old Turkic");
412 case Script::OLD_PERMIC
:
413 aFontList
.AppendElement("Noto Sans Old Permic");
415 case Script::PHAGS_PA
:
416 aFontList
.AppendElement("Noto Sans PhagsPa");
418 case Script::PHOENICIAN
:
419 aFontList
.AppendElement("Noto Sans Phoenician");
422 aFontList
.AppendElement("Noto Sans Miao");
425 aFontList
.AppendElement("Noto Sans Vai");
427 case Script::CUNEIFORM
:
428 aFontList
.AppendElement("Noto Sans Cuneiform");
431 aFontList
.AppendElement("Noto Sans Carian");
433 case Script::TAI_THAM
:
434 aFontList
.AppendElement("Noto Sans Tai Tham");
437 aFontList
.AppendElement("Noto Sans Lycian");
440 aFontList
.AppendElement("Noto Sans Lydian");
442 case Script::OL_CHIKI
:
443 aFontList
.AppendElement("Noto Sans Ol Chiki");
446 aFontList
.AppendElement("Noto Sans Rejang");
448 case Script::SAURASHTRA
:
449 aFontList
.AppendElement("Noto Sans Saurashtra");
451 case Script::SUNDANESE
:
452 aFontList
.AppendElement("Noto Sans Sundanese");
454 case Script::MEETEI_MAYEK
:
455 aFontList
.AppendElement("Noto Sans Meetei Mayek");
457 case Script::IMPERIAL_ARAMAIC
:
458 aFontList
.AppendElement("Noto Sans Imperial Aramaic");
460 case Script::AVESTAN
:
461 aFontList
.AppendElement("Noto Sans Avestan");
464 aFontList
.AppendElement("Noto Sans Chakma");
467 aFontList
.AppendElement("Noto Sans Kaithi");
469 case Script::MANICHAEAN
:
470 aFontList
.AppendElement("Noto Sans Manichaean");
472 case Script::INSCRIPTIONAL_PAHLAVI
:
473 aFontList
.AppendElement("Noto Sans Inscriptional Pahlavi");
475 case Script::PSALTER_PAHLAVI
:
476 aFontList
.AppendElement("Noto Sans Psalter Pahlavi");
478 case Script::INSCRIPTIONAL_PARTHIAN
:
479 aFontList
.AppendElement("Noto Sans Inscriptional Parthian");
481 case Script::SAMARITAN
:
482 aFontList
.AppendElement("Noto Sans Samaritan");
484 case Script::TAI_VIET
:
485 aFontList
.AppendElement("Noto Sans Tai Viet");
488 aFontList
.AppendElement("Noto Sans Bamum");
491 aFontList
.AppendElement("Noto Sans Lisu");
493 case Script::OLD_SOUTH_ARABIAN
:
494 aFontList
.AppendElement("Noto Sans Old South Arabian");
496 case Script::BASSA_VAH
:
497 aFontList
.AppendElement("Noto Sans Bassa Vah");
499 case Script::DUPLOYAN
:
500 aFontList
.AppendElement("Noto Sans Duployan");
502 case Script::ELBASAN
:
503 aFontList
.AppendElement("Noto Sans Elbasan");
505 case Script::GRANTHA
:
506 aFontList
.AppendElement("Noto Sans Grantha");
508 case Script::MENDE_KIKAKUI
:
509 aFontList
.AppendElement("Noto Sans Mende Kikakui");
511 case Script::MEROITIC_CURSIVE
:
512 case Script::MEROITIC_HIEROGLYPHS
:
513 aFontList
.AppendElement("Noto Sans Meroitic");
515 case Script::OLD_NORTH_ARABIAN
:
516 aFontList
.AppendElement("Noto Sans Old North Arabian");
518 case Script::NABATAEAN
:
519 aFontList
.AppendElement("Noto Sans Nabataean");
521 case Script::PALMYRENE
:
522 aFontList
.AppendElement("Noto Sans Palmyrene");
524 case Script::KHUDAWADI
:
525 aFontList
.AppendElement("Noto Sans Khudawadi");
527 case Script::WARANG_CITI
:
528 aFontList
.AppendElement("Noto Sans Warang Citi");
531 aFontList
.AppendElement("Noto Sans Mro");
533 case Script::SHARADA
:
534 aFontList
.AppendElement("Noto Sans Sharada");
536 case Script::SORA_SOMPENG
:
537 aFontList
.AppendElement("Noto Sans Sora Sompeng");
540 aFontList
.AppendElement("Noto Sans Takri");
543 aFontList
.AppendElement("Noto Sans Khojki");
545 case Script::TIRHUTA
:
546 aFontList
.AppendElement("Noto Sans Tirhuta");
548 case Script::CAUCASIAN_ALBANIAN
:
549 aFontList
.AppendElement("Noto Sans Caucasian Albanian");
551 case Script::MAHAJANI
:
552 aFontList
.AppendElement("Noto Sans Mahajani");
555 aFontList
.AppendElement("Noto Serif Ahom");
558 aFontList
.AppendElement("Noto Sans Hatran");
561 aFontList
.AppendElement("Noto Sans Modi");
563 case Script::MULTANI
:
564 aFontList
.AppendElement("Noto Sans Multani");
566 case Script::PAU_CIN_HAU
:
567 aFontList
.AppendElement("Noto Sans Pau Cin Hau");
569 case Script::SIDDHAM
:
570 aFontList
.AppendElement("Noto Sans Siddham");
573 aFontList
.AppendElement("Noto Sans Adlam");
575 case Script::BHAIKSUKI
:
576 aFontList
.AppendElement("Noto Sans Bhaiksuki");
578 case Script::MARCHEN
:
579 aFontList
.AppendElement("Noto Sans Marchen");
582 aFontList
.AppendElement("Noto Sans Newa");
585 aFontList
.AppendElement("Noto Sans Osage");
587 case Script::HANIFI_ROHINGYA
:
588 aFontList
.AppendElement("Noto Sans Hanifi Rohingya");
591 aFontList
.AppendElement("Noto Sans Wancho");
594 // Script codes for which no commonly-installed font is currently known.
595 // Probably future macOS versions will add Noto fonts for many of these,
596 // so we should watch for updates.
597 case Script::OLD_CHURCH_SLAVONIC_CYRILLIC
:
598 case Script::DEMOTIC_EGYPTIAN
:
599 case Script::HIERATIC_EGYPTIAN
:
600 case Script::BLISSYMBOLS
:
602 case Script::KHUTSURI
:
603 case Script::HARAPPAN_INDUS
:
604 case Script::LATIN_FRAKTUR
:
605 case Script::LATIN_GAELIC
:
606 case Script::MAYAN_HIEROGLYPHS
:
607 case Script::RONGORONGO
:
609 case Script::ESTRANGELO_SYRIAC
:
610 case Script::WESTERN_SYRIAC
:
611 case Script::EASTERN_SYRIAC
:
612 case Script::TENGWAR
:
613 case Script::VISIBLE_SPEECH
:
614 case Script::UNWRITTEN_LANGUAGES
:
615 case Script::UNKNOWN
:
616 case Script::SIGNWRITING
:
618 case Script::BOOK_PAHLAVI
:
619 case Script::NAKHI_GEBA
:
623 case Script::JURCHEN
:
627 case Script::ANATOLIAN_HIEROGLYPHS
:
628 case Script::MASARAM_GONDI
:
629 case Script::SOYOMBO
:
630 case Script::ZANABAZAR_SQUARE
:
632 case Script::GUNJALA_GONDI
:
633 case Script::MAKASAR
:
634 case Script::MEDEFAIDRIN
:
635 case Script::SOGDIAN
:
636 case Script::OLD_SOGDIAN
:
637 case Script::ELYMAIC
:
638 case Script::NYIAKENG_PUACHUE_HMONG
:
639 case Script::NANDINAGARI
:
640 case Script::CHORASMIAN
:
641 case Script::DIVES_AKURU
:
642 case Script::KHITAN_SMALL_SCRIPT
:
644 case Script::CYPRO_MINOAN
:
645 case Script::OLD_UYGHUR
:
648 case Script::VITHKUQI
:
650 case Script::NAG_MUNDARI
:
654 // Symbols/dingbats are generally Script=COMMON but may be resolved to any
655 // surrounding script run. So we'll always append a couple of likely fonts
656 // for such characters.
657 const uint32_t b
= aCh
>> 8;
658 if (aRunScript
== Script::COMMON
|| // Stray COMMON chars not resolved
659 (b
>= 0x20 && b
<= 0x2b) || b
== 0x2e || // BMP symbols/punctuation/etc
660 GetGenCategory(aCh
) == nsUGenCategory::kSymbol
||
661 GetGenCategory(aCh
) == nsUGenCategory::kPunctuation
) {
663 aFontList
.AppendElement("Zapf Dingbats");
665 aFontList
.AppendElement("Geneva");
666 aFontList
.AppendElement("STIXGeneral");
667 aFontList
.AppendElement("Apple Symbols");
668 // Japanese fonts also cover a lot of miscellaneous symbols
669 aFontList
.AppendElement("Hiragino Sans");
670 aFontList
.AppendElement("Hiragino Kaku Gothic ProN");
673 // Arial Unicode MS has lots of glyphs for obscure characters; try it as a
675 aFontList
.AppendElement("Arial Unicode MS");
679 void gfxPlatformMac::LookupSystemFont(
680 mozilla::LookAndFeel::FontID aSystemFontID
, nsACString
& aSystemFontName
,
681 gfxFontStyle
& aFontStyle
) {
682 gfxMacPlatformFontList
* pfl
= gfxMacPlatformFontList::PlatformFontList();
683 return pfl
->LookupSystemFont(aSystemFontID
, aSystemFontName
, aFontStyle
);
686 uint32_t gfxPlatformMac::ReadAntiAliasingThreshold() {
687 uint32_t threshold
= 0; // default == no threshold
689 // first read prefs flag to determine whether to use the setting or not
690 bool useAntiAliasingThreshold
=
691 Preferences::GetBool("gfx.use_text_smoothing_setting", false);
693 // if the pref setting is disabled, return 0 which effectively disables this
695 if (!useAntiAliasingThreshold
) return threshold
;
697 // value set via Appearance pref panel, "Turn off text smoothing for font
698 // sizes xxx and smaller"
699 CFNumberRef prefValue
= (CFNumberRef
)CFPreferencesCopyAppValue(
700 CFSTR("AppleAntiAliasingThreshold"), kCFPreferencesCurrentApplication
);
703 if (!CFNumberGetValue(prefValue
, kCFNumberIntType
, &threshold
)) {
706 CFRelease(prefValue
);
712 bool gfxPlatformMac::AccelerateLayersByDefault() { return true; }
714 // This is the renderer output callback function, called on the vsync thread
715 static CVReturn
VsyncCallback(CVDisplayLinkRef aDisplayLink
,
716 const CVTimeStamp
* aNow
,
717 const CVTimeStamp
* aOutputTime
,
718 CVOptionFlags aFlagsIn
, CVOptionFlags
* aFlagsOut
,
719 void* aDisplayLinkContext
);
721 class OSXVsyncSource final
: public VsyncSource
{
724 : mDisplayLink(nullptr, "OSXVsyncSource::OSXDisplay::mDisplayLink") {
725 MOZ_ASSERT(NS_IsMainThread());
726 mTimer
= NS_NewTimer();
727 CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback
,
731 virtual ~OSXVsyncSource() {
732 MOZ_ASSERT(NS_IsMainThread());
733 CGDisplayRemoveReconfigurationCallback(DisplayReconfigurationCallback
,
737 static void RetryEnableVsync(nsITimer
* aTimer
, void* aOsxVsyncSource
) {
738 MOZ_ASSERT(NS_IsMainThread());
739 OSXVsyncSource
* osxVsyncSource
=
740 static_cast<OSXVsyncSource
*>(aOsxVsyncSource
);
741 MOZ_ASSERT(osxVsyncSource
);
742 osxVsyncSource
->EnableVsync();
745 void EnableVsync() override
{
746 MOZ_ASSERT(NS_IsMainThread());
747 if (IsVsyncEnabled()) {
751 auto displayLink
= mDisplayLink
.Lock();
753 // Create a display link capable of being used with all active displays
754 // TODO: See if we need to create an active DisplayLink for each monitor
755 // in multi-monitor situations. According to the docs, it is compatible
756 // with all displays running on the computer But if we have different
757 // monitors at different display rates, we may hit issues.
758 CVReturn retval
= CVDisplayLinkCreateWithActiveCGDisplays(&*displayLink
);
760 // Workaround for bug 1201401: CVDisplayLinkCreateWithCGDisplays()
761 // (called by CVDisplayLinkCreateWithActiveCGDisplays()) sometimes
762 // creates a CVDisplayLinkRef with an uninitialized (nulled) internal
763 // pointer. If we continue to use this CVDisplayLinkRef, we will
764 // eventually crash in CVCGDisplayLink::getDisplayTimes(), where the
765 // internal pointer is dereferenced. Fortunately, when this happens
766 // another internal variable is also left uninitialized (zeroed),
767 // which is accessible via CVDisplayLinkGetCurrentCGDisplay(). In
768 // normal conditions the current display is never zero.
769 if ((retval
== kCVReturnSuccess
) &&
770 (CVDisplayLinkGetCurrentCGDisplay(*displayLink
) == 0)) {
771 retval
= kCVReturnInvalidDisplay
;
774 if (retval
!= kCVReturnSuccess
) {
776 "Could not create a display link with all active displays. "
778 CVDisplayLinkRelease(*displayLink
);
779 *displayLink
= nullptr;
781 // bug 1142708 - When coming back from sleep,
782 // or when changing displays, active displays may not be ready yet,
783 // even if listening for the kIOMessageSystemHasPoweredOn event
784 // from OS X sleep notifications.
785 // Active displays are those that are drawable.
786 // bug 1144638 - When changing display configurations and getting
787 // notifications from CGDisplayReconfigurationCallBack, the
788 // callback gets called twice for each active display
789 // so it's difficult to know when all displays are active.
790 // Instead, try again soon. The delay is arbitrary. 100ms chosen
791 // because on a late 2013 15" retina, it takes about that
792 // long to come back up from sleep.
793 uint32_t delay
= 100;
794 mTimer
->InitWithNamedFuncCallback(RetryEnableVsync
, this, delay
,
795 nsITimer::TYPE_ONE_SHOT
,
800 if (CVDisplayLinkSetOutputCallback(*displayLink
, &VsyncCallback
, this) !=
802 NS_WARNING("Could not set displaylink output callback");
803 CVDisplayLinkRelease(*displayLink
);
804 *displayLink
= nullptr;
808 mPreviousTimestamp
= TimeStamp::Now();
809 if (CVDisplayLinkStart(*displayLink
) != kCVReturnSuccess
) {
810 NS_WARNING("Could not activate the display link");
811 CVDisplayLinkRelease(*displayLink
);
812 *displayLink
= nullptr;
816 CVDisplayLinkGetNominalOutputVideoRefreshPeriod(*displayLink
);
817 if (vsyncRate
.flags
& kCVTimeIsIndefinite
) {
818 NS_WARNING("Could not get vsync rate, setting to 60.");
819 mVsyncRate
= TimeDuration::FromMilliseconds(1000.0 / 60.0);
821 int64_t timeValue
= vsyncRate
.timeValue
;
822 int64_t timeScale
= vsyncRate
.timeScale
;
823 const int milliseconds
= 1000;
824 float rateInMs
= ((double)timeValue
/ (double)timeScale
) * milliseconds
;
825 mVsyncRate
= TimeDuration::FromMilliseconds(rateInMs
);
829 void DisableVsync() override
{
830 MOZ_ASSERT(NS_IsMainThread());
831 if (!IsVsyncEnabled()) {
835 // Release the display link
836 auto displayLink
= mDisplayLink
.Lock();
838 CVDisplayLinkRelease(*displayLink
);
839 *displayLink
= nullptr;
843 bool IsVsyncEnabled() override
{
844 MOZ_ASSERT(NS_IsMainThread());
845 auto displayLink
= mDisplayLink
.Lock();
846 return *displayLink
!= nullptr;
849 TimeDuration
GetVsyncRate() override
{ return mVsyncRate
; }
851 void Shutdown() override
{
852 MOZ_ASSERT(NS_IsMainThread());
858 // The vsync timestamps given by the CVDisplayLinkCallback are
859 // in the future for the NEXT frame. Large parts of Gecko, such
860 // as animations assume a timestamp at either now or in the past.
861 // Normalize the timestamps given to the VsyncDispatchers to the vsync
862 // that just occured, not the vsync that is upcoming.
863 TimeStamp mPreviousTimestamp
;
866 static void DisplayReconfigurationCallback(CGDirectDisplayID aDisplay
,
867 CGDisplayChangeSummaryFlags aFlags
,
869 static_cast<OSXVsyncSource
*>(aUserInfo
)->OnDisplayReconfiguration(aDisplay
,
873 void OnDisplayReconfiguration(CGDirectDisplayID aDisplay
,
874 CGDisplayChangeSummaryFlags aFlags
) {
875 // Display reconfiguration notifications are fired in two phases: Before
876 // the reconfiguration and after the reconfiguration.
877 // All displays are notified before (with a "BeginConfiguration" flag),
878 // and the reconfigured displays are notified again after the
880 if (aFlags
& kCGDisplayBeginConfigurationFlag
) {
881 // We're only interested in the "after" notification, for the display
882 // link's current display.
886 if (!NS_IsMainThread()) {
890 bool didReconfigureCurrentDisplayLinkDisplay
= false;
892 auto displayLink
= mDisplayLink
.Lock();
893 didReconfigureCurrentDisplayLinkDisplay
=
895 CVDisplayLinkGetCurrentCGDisplay(*displayLink
) == aDisplay
;
898 if (didReconfigureCurrentDisplayLinkDisplay
) {
899 // The link's current display has been reconfigured.
900 // Recreate the display link, because otherwise it may be stuck with a
901 // "removed" display forever and never notify us again.
907 // Accessed from main thread and from display reconfiguration callback
908 // thread... which also happens to be the main thread.
909 DataMutex
<CVDisplayLinkRef
> mDisplayLink
;
911 // Accessed only from the main thread.
912 RefPtr
<nsITimer
> mTimer
;
913 TimeDuration mVsyncRate
;
916 static CVReturn
VsyncCallback(CVDisplayLinkRef aDisplayLink
,
917 const CVTimeStamp
* aNow
,
918 const CVTimeStamp
* aOutputTime
,
919 CVOptionFlags aFlagsIn
, CVOptionFlags
* aFlagsOut
,
920 void* aDisplayLinkContext
) {
921 // Executed on OS X hardware vsync thread
922 OSXVsyncSource
* vsyncSource
= (OSXVsyncSource
*)aDisplayLinkContext
;
924 mozilla::TimeStamp outputTime
=
925 mozilla::TimeStamp::FromSystemTime(aOutputTime
->hostTime
);
926 mozilla::TimeStamp nextVsync
= outputTime
;
927 mozilla::TimeStamp previousVsync
= vsyncSource
->mPreviousTimestamp
;
928 mozilla::TimeStamp now
= TimeStamp::Now();
930 // Snow leopard sometimes sends vsync timestamps very far in the past.
931 // Normalize the vsync timestamps to now.
932 if (nextVsync
<= previousVsync
) {
935 } else if (now
< previousVsync
) {
936 // Bug 1158321 - The VsyncCallback can sometimes execute before the reported
937 // vsync time. In those cases, normalize the timestamp to Now() as sending
938 // timestamps in the future has undefined behavior. See the comment above
939 // OSXVsyncSource::mPreviousTimestamp
943 vsyncSource
->mPreviousTimestamp
= nextVsync
;
945 vsyncSource
->NotifyVsync(previousVsync
, outputTime
);
946 return kCVReturnSuccess
;
949 already_AddRefed
<mozilla::gfx::VsyncSource
>
950 gfxPlatformMac::CreateGlobalHardwareVsyncSource() {
951 RefPtr
<VsyncSource
> osxVsyncSource
= new OSXVsyncSource();
952 osxVsyncSource
->EnableVsync();
953 if (!osxVsyncSource
->IsVsyncEnabled()) {
955 "OS X Vsync source not enabled. Falling back to software vsync.");
956 return GetSoftwareVsyncSource();
959 osxVsyncSource
->DisableVsync();
960 return osxVsyncSource
.forget();
963 bool gfxPlatformMac::SupportsHDR() {
964 // HDR has 3 requirements:
965 // 1) high peak brightness
966 // 2) high contrast ratio
967 // 3) color depth > 24
968 if (GetScreenDepth() <= 24) {
971 // Screen is capable. Is the OS capable?
972 #ifdef EARLY_BETA_OR_EARLIER
973 // More-or-less supported in Catalina.
974 return nsCocoaFeatures::OnCatalinaOrLater();
976 // Definitely supported in Big Sur.
977 return nsCocoaFeatures::OnBigSurOrLater();
981 nsTArray
<uint8_t> gfxPlatformMac::GetPlatformCMSOutputProfileData() {
982 nsTArray
<uint8_t> prefProfileData
= GetPrefCMSOutputProfileData();
983 if (!prefProfileData
.IsEmpty()) {
984 return prefProfileData
;
987 CGColorSpaceRef cspace
= ::CGDisplayCopyColorSpace(::CGMainDisplayID());
989 cspace
= ::CGColorSpaceCreateDeviceRGB();
992 return nsTArray
<uint8_t>();
995 CFDataRef iccp
= ::CGColorSpaceCopyICCProfile(cspace
);
1000 return nsTArray
<uint8_t>();
1003 // copy to external buffer
1004 size_t size
= static_cast<size_t>(::CFDataGetLength(iccp
));
1006 nsTArray
<uint8_t> result
;
1009 result
.AppendElements(::CFDataGetBytePtr(iccp
), size
);
1017 bool gfxPlatformMac::CheckVariationFontSupport() {
1018 // We don't allow variation fonts to be enabled before 10.13,
1019 // as although the Core Text APIs existed, they are known to be
1021 // (Note that Safari also requires 10.13 for variation-font support.)
1022 return nsCocoaFeatures::OnHighSierraOrLater();
1025 void gfxPlatformMac::InitPlatformGPUProcessPrefs() {
1026 FeatureState
& gpuProc
= gfxConfig::GetFeature(Feature::GPU_PROCESS
);
1027 gpuProc
.ForceDisable(FeatureStatus::Blocked
,
1028 "GPU process does not work on Mac",
1029 "FEATURE_FAILURE_MAC_GPU_PROC"_ns
);