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 "gfxMacFont.h"
13 #include "gfxCoreTextShaper.h"
14 #include "gfxTextRun.h"
15 #include "gfxUserFontSet.h"
16 #include "gfxConfig.h"
18 #include "AppleUtils.h"
20 #include "mozilla/Preferences.h"
21 #include "mozilla/VsyncDispatcher.h"
22 #ifdef MOZ_WIDGET_COCOA
23 # include "nsCocoaFeatures.h"
25 #include "nsComponentManagerUtils.h"
27 #include "nsUnicodeProperties.h"
29 #include "gfx2DGlue.h"
30 #include "GeckoProfiler.h"
31 #include "nsThreadUtils.h"
33 #ifdef MOZ_BUNDLED_FONTS
34 # include "mozilla/Telemetry.h"
35 # include "nsDirectoryServiceDefs.h"
36 # include "mozilla/StaticPrefs_gfx.h"
40 #include <CoreVideo/CoreVideo.h>
42 #include "mozilla/layers/CompositorBridgeParent.h"
43 #include "mozilla/layers/SurfacePool.h"
44 #include "VsyncSource.h"
46 using namespace mozilla
;
47 using namespace mozilla::gfx
;
48 using namespace mozilla::unicode
;
50 using mozilla::dom::SystemFontList
;
52 #ifdef MOZ_WIDGET_COCOA
53 # include "gfxMacPlatformFontList.h"
54 using PlatformFontListClass
= gfxMacPlatformFontList
;
56 # include "IOSPlatformFontList.h"
57 using PlatformFontListClass
= IOSPlatformFontList
;
60 // A bunch of fonts for "additional language support" are shipped in a
61 // "Language Support" directory, and don't show up in the standard font
62 // list returned by CTFontManagerCopyAvailableFontFamilyNames unless
63 // we explicitly activate them.
64 static const nsLiteralCString kLangFontsDirs
[] = {
65 "/Library/Application Support/Apple/Fonts/Language Support"_ns
,
66 "/System/Library/Fonts/Supplemental"_ns
};
69 void gfxPlatformMac::FontRegistrationCallback(void* aUnused
) {
70 AUTO_PROFILER_REGISTER_THREAD("RegisterFonts");
71 PR_SetCurrentThreadName("RegisterFonts");
73 for (const auto& dir
: kLangFontsDirs
) {
74 PlatformFontListClass::ActivateFontsFromDir(dir
);
78 PRThread
* gfxPlatformMac::sFontRegistrationThread
= nullptr;
80 /* This is called from XPCOM_Init during startup (before gfxPlatform has been
81 initialized), so that it can kick off the font activation on a secondary
82 thread, and hope that it'll be finished by the time we're ready to build
85 void gfxPlatformMac::RegisterSupplementalFonts() {
86 if (XRE_GetProcessType() == GeckoProcessType_Default
) {
87 // We activate the fonts on a separate thread, to minimize the startup-
89 sFontRegistrationThread
= PR_CreateThread(
90 PR_USER_THREAD
, FontRegistrationCallback
, nullptr, PR_PRIORITY_NORMAL
,
91 PR_GLOBAL_THREAD
, PR_JOINABLE_THREAD
, 0);
96 void gfxPlatformMac::WaitForFontRegistration() {
97 if (sFontRegistrationThread
) {
98 PR_JoinThread(sFontRegistrationThread
);
99 sFontRegistrationThread
= nullptr;
103 gfxPlatformMac::gfxPlatformMac() {
104 mFontAntiAliasingThreshold
= ReadAntiAliasingThreshold();
106 InitBackendPrefs(GetBackendPrefs());
109 gfxPlatformMac::~gfxPlatformMac() { gfxCoreTextShaper::Shutdown(); }
111 BackendPrefsData
gfxPlatformMac::GetBackendPrefs() const {
112 BackendPrefsData data
;
114 data
.mCanvasBitmask
= BackendTypeBit(BackendType::SKIA
);
115 data
.mContentBitmask
= BackendTypeBit(BackendType::SKIA
);
116 data
.mCanvasDefault
= BackendType::SKIA
;
117 data
.mContentDefault
= BackendType::SKIA
;
122 bool gfxPlatformMac::CreatePlatformFontList() {
123 return gfxPlatformFontList::Initialize(new PlatformFontListClass
);
126 void gfxPlatformMac::ReadSystemFontList(SystemFontList
* aFontList
) {
127 PlatformFontListClass::PlatformFontList()->ReadSystemFontList(aFontList
);
130 already_AddRefed
<gfxASurface
> gfxPlatformMac::CreateOffscreenSurface(
131 const IntSize
& aSize
, gfxImageFormat aFormat
) {
132 if (!Factory::AllowedSurfaceSize(aSize
)) {
136 RefPtr
<gfxASurface
> newSurface
= new gfxQuartzSurface(aSize
, aFormat
);
137 return newSurface
.forget();
140 void gfxPlatformMac::GetCommonFallbackFonts(uint32_t aCh
, Script aRunScript
,
141 eFontPresentation aPresentation
,
142 nsTArray
<const char*>& aFontList
) {
143 if (PrefersColor(aPresentation
)) {
144 aFontList
.AppendElement("Apple Color Emoji");
147 switch (aRunScript
) {
148 case Script::INVALID
:
149 case Script::NUM_SCRIPT_CODES
:
150 // Ensure the switch covers all the Script enum values.
151 MOZ_ASSERT_UNREACHABLE("bad script code");
155 case Script::INHERITED
:
156 // In most cases, COMMON and INHERITED characters will be merged into
157 // their context, but if they occur without any specific script context
158 // we'll just try common default fonts here.
160 case Script::CYRILLIC
:
162 aFontList
.AppendElement("Lucida Grande");
165 case Script::MATHEMATICAL_NOTATION
:
166 case Script::SYMBOLS
:
167 case Script::SYMBOLS_EMOJI
:
168 // Not currently returned by script run resolution (but see below, after
172 // CJK-related script codes are a bit troublesome because of unification;
173 // we'll probably just get HAN much of the time, so the choice of which
174 // language font to try for fallback is rather arbitrary. Usually, though,
175 // we hope that font prefs will have handled this earlier.
176 case Script::BOPOMOFO
:
177 case Script::HAN_WITH_BOPOMOFO
:
178 case Script::SIMPLIFIED_HAN
:
180 aFontList
.AppendElement("Songti SC");
182 // macOS installations with MS Office may have these -ExtB fonts
183 aFontList
.AppendElement("SimSun-ExtB");
187 // Currently, we don't resolve script runs to this value, but we may do so
188 // in future if we get better at handling things like `lang=zh-Hant`, not
189 // just resolving based on the Unicode text.
190 case Script::TRADITIONAL_HAN
:
191 aFontList
.AppendElement("Songti TC");
193 // macOS installations with MS Office may have these -ExtB fonts
194 aFontList
.AppendElement("MingLiU-ExtB");
198 case Script::HIRAGANA
:
199 case Script::KATAKANA
:
200 case Script::KATAKANA_OR_HIRAGANA
:
201 case Script::JAPANESE
:
202 aFontList
.AppendElement("Hiragino Sans");
203 aFontList
.AppendElement("Hiragino Kaku Gothic ProN");
209 aFontList
.AppendElement("Nanum Gothic");
210 aFontList
.AppendElement("Apple SD Gothic Neo");
213 // For most other scripts, macOS comes with a default font we can use.
215 aFontList
.AppendElement("Geeza Pro");
217 case Script::ARMENIAN
:
218 aFontList
.AppendElement("Mshtakan");
220 case Script::BENGALI
:
221 aFontList
.AppendElement("Bangla Sangam MN");
223 case Script::CHEROKEE
:
224 aFontList
.AppendElement("Plantagenet Cherokee");
227 aFontList
.AppendElement("Noto Sans Coptic");
229 case Script::DESERET
:
230 aFontList
.AppendElement("Baskerville");
232 case Script::DEVANAGARI
:
233 aFontList
.AppendElement("Devanagari Sangam MN");
235 case Script::ETHIOPIC
:
236 aFontList
.AppendElement("Kefa");
238 case Script::GEORGIAN
:
239 aFontList
.AppendElement("Helvetica");
242 aFontList
.AppendElement("Noto Sans Gothic");
244 case Script::GUJARATI
:
245 aFontList
.AppendElement("Gujarati Sangam MN");
247 case Script::GURMUKHI
:
248 aFontList
.AppendElement("Gurmukhi MN");
251 aFontList
.AppendElement("Lucida Grande");
253 case Script::KANNADA
:
254 aFontList
.AppendElement("Kannada MN");
257 aFontList
.AppendElement("Khmer MN");
260 aFontList
.AppendElement("Lao MN");
262 case Script::MALAYALAM
:
263 aFontList
.AppendElement("Malayalam Sangam MN");
265 case Script::MONGOLIAN
:
266 aFontList
.AppendElement("Noto Sans Mongolian");
268 case Script::MYANMAR
:
269 aFontList
.AppendElement("Myanmar MN");
272 aFontList
.AppendElement("Noto Sans Ogham");
274 case Script::OLD_ITALIC
:
275 aFontList
.AppendElement("Noto Sans Old Italic");
278 aFontList
.AppendElement("Oriya Sangam MN");
281 aFontList
.AppendElement("Noto Sans Runic");
283 case Script::SINHALA
:
284 aFontList
.AppendElement("Sinhala Sangam MN");
287 aFontList
.AppendElement("Noto Sans Syriac");
290 aFontList
.AppendElement("Tamil MN");
293 aFontList
.AppendElement("Telugu MN");
296 aFontList
.AppendElement("Noto Sans Thaana");
299 aFontList
.AppendElement("Thonburi");
301 case Script::TIBETAN
:
302 aFontList
.AppendElement("Kailasa");
304 case Script::CANADIAN_ABORIGINAL
:
305 aFontList
.AppendElement("Euphemia UCAS");
308 aFontList
.AppendElement("Noto Sans Yi");
309 aFontList
.AppendElement("STHeiti");
311 case Script::TAGALOG
:
312 aFontList
.AppendElement("Noto Sans Tagalog");
314 case Script::HANUNOO
:
315 aFontList
.AppendElement("Noto Sans Hanunoo");
318 aFontList
.AppendElement("Noto Sans Buhid");
320 case Script::TAGBANWA
:
321 aFontList
.AppendElement("Noto Sans Tagbanwa");
323 case Script::BRAILLE
:
324 aFontList
.AppendElement("Apple Braille");
326 case Script::CYPRIOT
:
327 aFontList
.AppendElement("Noto Sans Cypriot");
330 aFontList
.AppendElement("Noto Sans Limbu");
332 case Script::LINEAR_B
:
333 aFontList
.AppendElement("Noto Sans Linear B");
335 case Script::OSMANYA
:
336 aFontList
.AppendElement("Noto Sans Osmanya");
338 case Script::SHAVIAN
:
339 aFontList
.AppendElement("Noto Sans Shavian");
342 aFontList
.AppendElement("Noto Sans Tai Le");
344 case Script::UGARITIC
:
345 aFontList
.AppendElement("Noto Sans Ugaritic");
347 case Script::BUGINESE
:
348 aFontList
.AppendElement("Noto Sans Buginese");
350 case Script::GLAGOLITIC
:
351 aFontList
.AppendElement("Noto Sans Glagolitic");
353 case Script::KHAROSHTHI
:
354 aFontList
.AppendElement("Noto Sans Kharoshthi");
356 case Script::SYLOTI_NAGRI
:
357 aFontList
.AppendElement("Noto Sans Syloti Nagri");
359 case Script::NEW_TAI_LUE
:
360 aFontList
.AppendElement("Noto Sans New Tai Lue");
362 case Script::TIFINAGH
:
363 aFontList
.AppendElement("Noto Sans Tifinagh");
365 case Script::OLD_PERSIAN
:
366 aFontList
.AppendElement("Noto Sans Old Persian");
368 case Script::BALINESE
:
369 aFontList
.AppendElement("Noto Sans Balinese");
372 aFontList
.AppendElement("Noto Sans Batak");
375 aFontList
.AppendElement("Noto Sans Brahmi");
378 aFontList
.AppendElement("Noto Sans Cham");
380 case Script::EGYPTIAN_HIEROGLYPHS
:
381 aFontList
.AppendElement("Noto Sans Egyptian Hieroglyphs");
383 case Script::PAHAWH_HMONG
:
384 aFontList
.AppendElement("Noto Sans Pahawh Hmong");
386 case Script::OLD_HUNGARIAN
:
387 aFontList
.AppendElement("Noto Sans Old Hungarian");
389 case Script::JAVANESE
:
390 aFontList
.AppendElement("Noto Sans Javanese");
392 case Script::KAYAH_LI
:
393 aFontList
.AppendElement("Noto Sans Kayah Li");
396 aFontList
.AppendElement("Noto Sans Lepcha");
398 case Script::LINEAR_A
:
399 aFontList
.AppendElement("Noto Sans Linear A");
401 case Script::MANDAIC
:
402 aFontList
.AppendElement("Noto Sans Mandaic");
405 aFontList
.AppendElement("Noto Sans NKo");
407 case Script::OLD_TURKIC
:
408 aFontList
.AppendElement("Noto Sans Old Turkic");
410 case Script::OLD_PERMIC
:
411 aFontList
.AppendElement("Noto Sans Old Permic");
413 case Script::PHAGS_PA
:
414 aFontList
.AppendElement("Noto Sans PhagsPa");
416 case Script::PHOENICIAN
:
417 aFontList
.AppendElement("Noto Sans Phoenician");
420 aFontList
.AppendElement("Noto Sans Miao");
423 aFontList
.AppendElement("Noto Sans Vai");
425 case Script::CUNEIFORM
:
426 aFontList
.AppendElement("Noto Sans Cuneiform");
429 aFontList
.AppendElement("Noto Sans Carian");
431 case Script::TAI_THAM
:
432 aFontList
.AppendElement("Noto Sans Tai Tham");
435 aFontList
.AppendElement("Noto Sans Lycian");
438 aFontList
.AppendElement("Noto Sans Lydian");
440 case Script::OL_CHIKI
:
441 aFontList
.AppendElement("Noto Sans Ol Chiki");
444 aFontList
.AppendElement("Noto Sans Rejang");
446 case Script::SAURASHTRA
:
447 aFontList
.AppendElement("Noto Sans Saurashtra");
449 case Script::SUNDANESE
:
450 aFontList
.AppendElement("Noto Sans Sundanese");
452 case Script::MEETEI_MAYEK
:
453 aFontList
.AppendElement("Noto Sans Meetei Mayek");
455 case Script::IMPERIAL_ARAMAIC
:
456 aFontList
.AppendElement("Noto Sans Imperial Aramaic");
458 case Script::AVESTAN
:
459 aFontList
.AppendElement("Noto Sans Avestan");
462 aFontList
.AppendElement("Noto Sans Chakma");
465 aFontList
.AppendElement("Noto Sans Kaithi");
467 case Script::MANICHAEAN
:
468 aFontList
.AppendElement("Noto Sans Manichaean");
470 case Script::INSCRIPTIONAL_PAHLAVI
:
471 aFontList
.AppendElement("Noto Sans Inscriptional Pahlavi");
473 case Script::PSALTER_PAHLAVI
:
474 aFontList
.AppendElement("Noto Sans Psalter Pahlavi");
476 case Script::INSCRIPTIONAL_PARTHIAN
:
477 aFontList
.AppendElement("Noto Sans Inscriptional Parthian");
479 case Script::SAMARITAN
:
480 aFontList
.AppendElement("Noto Sans Samaritan");
482 case Script::TAI_VIET
:
483 aFontList
.AppendElement("Noto Sans Tai Viet");
486 aFontList
.AppendElement("Noto Sans Bamum");
489 aFontList
.AppendElement("Noto Sans Lisu");
491 case Script::OLD_SOUTH_ARABIAN
:
492 aFontList
.AppendElement("Noto Sans Old South Arabian");
494 case Script::BASSA_VAH
:
495 aFontList
.AppendElement("Noto Sans Bassa Vah");
497 case Script::DUPLOYAN
:
498 aFontList
.AppendElement("Noto Sans Duployan");
500 case Script::ELBASAN
:
501 aFontList
.AppendElement("Noto Sans Elbasan");
503 case Script::GRANTHA
:
504 aFontList
.AppendElement("Noto Sans Grantha");
506 case Script::MENDE_KIKAKUI
:
507 aFontList
.AppendElement("Noto Sans Mende Kikakui");
509 case Script::MEROITIC_CURSIVE
:
510 case Script::MEROITIC_HIEROGLYPHS
:
511 aFontList
.AppendElement("Noto Sans Meroitic");
513 case Script::OLD_NORTH_ARABIAN
:
514 aFontList
.AppendElement("Noto Sans Old North Arabian");
516 case Script::NABATAEAN
:
517 aFontList
.AppendElement("Noto Sans Nabataean");
519 case Script::PALMYRENE
:
520 aFontList
.AppendElement("Noto Sans Palmyrene");
522 case Script::KHUDAWADI
:
523 aFontList
.AppendElement("Noto Sans Khudawadi");
525 case Script::WARANG_CITI
:
526 aFontList
.AppendElement("Noto Sans Warang Citi");
529 aFontList
.AppendElement("Noto Sans Mro");
531 case Script::SHARADA
:
532 aFontList
.AppendElement("Noto Sans Sharada");
534 case Script::SORA_SOMPENG
:
535 aFontList
.AppendElement("Noto Sans Sora Sompeng");
538 aFontList
.AppendElement("Noto Sans Takri");
541 aFontList
.AppendElement("Noto Sans Khojki");
543 case Script::TIRHUTA
:
544 aFontList
.AppendElement("Noto Sans Tirhuta");
546 case Script::CAUCASIAN_ALBANIAN
:
547 aFontList
.AppendElement("Noto Sans Caucasian Albanian");
549 case Script::MAHAJANI
:
550 aFontList
.AppendElement("Noto Sans Mahajani");
553 aFontList
.AppendElement("Noto Serif Ahom");
556 aFontList
.AppendElement("Noto Sans Hatran");
559 aFontList
.AppendElement("Noto Sans Modi");
561 case Script::MULTANI
:
562 aFontList
.AppendElement("Noto Sans Multani");
564 case Script::PAU_CIN_HAU
:
565 aFontList
.AppendElement("Noto Sans Pau Cin Hau");
567 case Script::SIDDHAM
:
568 aFontList
.AppendElement("Noto Sans Siddham");
571 aFontList
.AppendElement("Noto Sans Adlam");
573 case Script::BHAIKSUKI
:
574 aFontList
.AppendElement("Noto Sans Bhaiksuki");
576 case Script::MARCHEN
:
577 aFontList
.AppendElement("Noto Sans Marchen");
580 aFontList
.AppendElement("Noto Sans Newa");
583 aFontList
.AppendElement("Noto Sans Osage");
585 case Script::HANIFI_ROHINGYA
:
586 aFontList
.AppendElement("Noto Sans Hanifi Rohingya");
589 aFontList
.AppendElement("Noto Sans Wancho");
592 // Script codes for which no commonly-installed font is currently known.
593 // Probably future macOS versions will add Noto fonts for many of these,
594 // so we should watch for updates.
595 case Script::OLD_CHURCH_SLAVONIC_CYRILLIC
:
596 case Script::DEMOTIC_EGYPTIAN
:
597 case Script::HIERATIC_EGYPTIAN
:
598 case Script::BLISSYMBOLS
:
600 case Script::KHUTSURI
:
601 case Script::HARAPPAN_INDUS
:
602 case Script::LATIN_FRAKTUR
:
603 case Script::LATIN_GAELIC
:
604 case Script::MAYAN_HIEROGLYPHS
:
605 case Script::RONGORONGO
:
607 case Script::ESTRANGELO_SYRIAC
:
608 case Script::WESTERN_SYRIAC
:
609 case Script::EASTERN_SYRIAC
:
610 case Script::TENGWAR
:
611 case Script::VISIBLE_SPEECH
:
612 case Script::UNWRITTEN_LANGUAGES
:
613 case Script::UNKNOWN
:
614 case Script::SIGNWRITING
:
616 case Script::BOOK_PAHLAVI
:
617 case Script::NAKHI_GEBA
:
621 case Script::JURCHEN
:
625 case Script::ANATOLIAN_HIEROGLYPHS
:
626 case Script::MASARAM_GONDI
:
627 case Script::SOYOMBO
:
628 case Script::ZANABAZAR_SQUARE
:
630 case Script::GUNJALA_GONDI
:
631 case Script::MAKASAR
:
632 case Script::MEDEFAIDRIN
:
633 case Script::SOGDIAN
:
634 case Script::OLD_SOGDIAN
:
635 case Script::ELYMAIC
:
636 case Script::NYIAKENG_PUACHUE_HMONG
:
637 case Script::NANDINAGARI
:
638 case Script::CHORASMIAN
:
639 case Script::DIVES_AKURU
:
640 case Script::KHITAN_SMALL_SCRIPT
:
642 case Script::CYPRO_MINOAN
:
643 case Script::OLD_UYGHUR
:
646 case Script::VITHKUQI
:
648 case Script::NAG_MUNDARI
:
652 // Symbols/dingbats are generally Script=COMMON but may be resolved to any
653 // surrounding script run. So we'll always append a couple of likely fonts
654 // for such characters.
655 const uint32_t b
= aCh
>> 8;
656 if (aRunScript
== Script::COMMON
|| // Stray COMMON chars not resolved
657 (b
>= 0x20 && b
<= 0x2b) || b
== 0x2e || // BMP symbols/punctuation/etc
658 GetGenCategory(aCh
) == nsUGenCategory::kSymbol
||
659 GetGenCategory(aCh
) == nsUGenCategory::kPunctuation
) {
661 aFontList
.AppendElement("Zapf Dingbats");
663 aFontList
.AppendElement("Geneva");
664 aFontList
.AppendElement("STIXGeneral");
665 aFontList
.AppendElement("Apple Symbols");
666 // Japanese fonts also cover a lot of miscellaneous symbols
667 aFontList
.AppendElement("Hiragino Sans");
668 aFontList
.AppendElement("Hiragino Kaku Gothic ProN");
671 // Arial Unicode MS has lots of glyphs for obscure characters; try it as a
673 aFontList
.AppendElement("Arial Unicode MS");
677 void gfxPlatformMac::LookupSystemFont(
678 mozilla::LookAndFeel::FontID aSystemFontID
, nsACString
& aSystemFontName
,
679 gfxFontStyle
& aFontStyle
) {
680 return PlatformFontListClass::LookupSystemFont(aSystemFontID
, aSystemFontName
,
684 uint32_t gfxPlatformMac::ReadAntiAliasingThreshold() {
685 uint32_t threshold
= 0; // default == no threshold
687 // first read prefs flag to determine whether to use the setting or not
688 bool useAntiAliasingThreshold
=
689 Preferences::GetBool("gfx.use_text_smoothing_setting", false);
691 // if the pref setting is disabled, return 0 which effectively disables this
693 if (!useAntiAliasingThreshold
) return threshold
;
695 // value set via Appearance pref panel, "Turn off text smoothing for font
696 // sizes xxx and smaller"
697 CFNumberRef prefValue
= (CFNumberRef
)CFPreferencesCopyAppValue(
698 CFSTR("AppleAntiAliasingThreshold"), kCFPreferencesCurrentApplication
);
701 if (!CFNumberGetValue(prefValue
, kCFNumberIntType
, &threshold
)) {
704 CFRelease(prefValue
);
710 bool gfxPlatformMac::AccelerateLayersByDefault() { return true; }
712 #ifdef MOZ_WIDGET_COCOA
713 // This is the renderer output callback function, called on the vsync thread
714 static CVReturn
VsyncCallback(CVDisplayLinkRef aDisplayLink
,
715 const CVTimeStamp
* aNow
,
716 const CVTimeStamp
* aOutputTime
,
717 CVOptionFlags aFlagsIn
, CVOptionFlags
* aFlagsOut
,
718 void* aDisplayLinkContext
);
720 class OSXVsyncSource final
: public VsyncSource
{
723 : mDisplayLink(nullptr, "OSXVsyncSource::OSXDisplay::mDisplayLink") {
724 MOZ_ASSERT(NS_IsMainThread());
725 mTimer
= NS_NewTimer();
726 CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback
,
730 virtual ~OSXVsyncSource() {
731 MOZ_ASSERT(NS_IsMainThread());
732 CGDisplayRemoveReconfigurationCallback(DisplayReconfigurationCallback
,
736 static void RetryEnableVsync(nsITimer
* aTimer
, void* aOsxVsyncSource
) {
737 MOZ_ASSERT(NS_IsMainThread());
738 OSXVsyncSource
* osxVsyncSource
=
739 static_cast<OSXVsyncSource
*>(aOsxVsyncSource
);
740 MOZ_ASSERT(osxVsyncSource
);
741 osxVsyncSource
->EnableVsync();
744 void EnableVsync() override
{
745 MOZ_ASSERT(NS_IsMainThread());
746 if (IsVsyncEnabled()) {
750 auto displayLink
= mDisplayLink
.Lock();
752 // Create a display link capable of being used with all active displays
753 // TODO: See if we need to create an active DisplayLink for each monitor
754 // in multi-monitor situations. According to the docs, it is compatible
755 // with all displays running on the computer But if we have different
756 // monitors at different display rates, we may hit issues.
757 CVReturn retval
= CVDisplayLinkCreateWithActiveCGDisplays(&*displayLink
);
759 // Workaround for bug 1201401: CVDisplayLinkCreateWithCGDisplays()
760 // (called by CVDisplayLinkCreateWithActiveCGDisplays()) sometimes
761 // creates a CVDisplayLinkRef with an uninitialized (nulled) internal
762 // pointer. If we continue to use this CVDisplayLinkRef, we will
763 // eventually crash in CVCGDisplayLink::getDisplayTimes(), where the
764 // internal pointer is dereferenced. Fortunately, when this happens
765 // another internal variable is also left uninitialized (zeroed),
766 // which is accessible via CVDisplayLinkGetCurrentCGDisplay(). In
767 // normal conditions the current display is never zero.
768 if ((retval
== kCVReturnSuccess
) &&
769 (CVDisplayLinkGetCurrentCGDisplay(*displayLink
) == 0)) {
770 retval
= kCVReturnInvalidDisplay
;
773 if (retval
!= kCVReturnSuccess
) {
775 "Could not create a display link with all active displays. "
777 CVDisplayLinkRelease(*displayLink
);
778 *displayLink
= nullptr;
780 // bug 1142708 - When coming back from sleep,
781 // or when changing displays, active displays may not be ready yet,
782 // even if listening for the kIOMessageSystemHasPoweredOn event
783 // from OS X sleep notifications.
784 // Active displays are those that are drawable.
785 // bug 1144638 - When changing display configurations and getting
786 // notifications from CGDisplayReconfigurationCallBack, the
787 // callback gets called twice for each active display
788 // so it's difficult to know when all displays are active.
789 // Instead, try again soon. The delay is arbitrary. 100ms chosen
790 // because on a late 2013 15" retina, it takes about that
791 // long to come back up from sleep.
792 uint32_t delay
= 100;
793 mTimer
->InitWithNamedFuncCallback(RetryEnableVsync
, this, delay
,
794 nsITimer::TYPE_ONE_SHOT
,
799 if (CVDisplayLinkSetOutputCallback(*displayLink
, &VsyncCallback
, this) !=
801 NS_WARNING("Could not set displaylink output callback");
802 CVDisplayLinkRelease(*displayLink
);
803 *displayLink
= nullptr;
807 mPreviousTimestamp
= TimeStamp::Now();
808 if (CVDisplayLinkStart(*displayLink
) != kCVReturnSuccess
) {
809 NS_WARNING("Could not activate the display link");
810 CVDisplayLinkRelease(*displayLink
);
811 *displayLink
= nullptr;
815 CVDisplayLinkGetNominalOutputVideoRefreshPeriod(*displayLink
);
816 if (vsyncRate
.flags
& kCVTimeIsIndefinite
) {
817 NS_WARNING("Could not get vsync rate, setting to 60.");
818 mVsyncRate
= TimeDuration::FromMilliseconds(1000.0 / 60.0);
820 int64_t timeValue
= vsyncRate
.timeValue
;
821 int64_t timeScale
= vsyncRate
.timeScale
;
822 const int milliseconds
= 1000;
823 float rateInMs
= ((double)timeValue
/ (double)timeScale
) * milliseconds
;
824 mVsyncRate
= TimeDuration::FromMilliseconds(rateInMs
);
828 void DisableVsync() override
{
829 MOZ_ASSERT(NS_IsMainThread());
830 if (!IsVsyncEnabled()) {
834 // Release the display link
835 auto displayLink
= mDisplayLink
.Lock();
837 CVDisplayLinkRelease(*displayLink
);
838 *displayLink
= nullptr;
842 bool IsVsyncEnabled() override
{
843 MOZ_ASSERT(NS_IsMainThread());
844 auto displayLink
= mDisplayLink
.Lock();
845 return *displayLink
!= nullptr;
848 TimeDuration
GetVsyncRate() override
{ return mVsyncRate
; }
850 void Shutdown() override
{
851 MOZ_ASSERT(NS_IsMainThread());
857 // The vsync timestamps given by the CVDisplayLinkCallback are
858 // in the future for the NEXT frame. Large parts of Gecko, such
859 // as animations assume a timestamp at either now or in the past.
860 // Normalize the timestamps given to the VsyncDispatchers to the vsync
861 // that just occured, not the vsync that is upcoming.
862 TimeStamp mPreviousTimestamp
;
865 static void DisplayReconfigurationCallback(CGDirectDisplayID aDisplay
,
866 CGDisplayChangeSummaryFlags aFlags
,
868 static_cast<OSXVsyncSource
*>(aUserInfo
)->OnDisplayReconfiguration(aDisplay
,
872 void OnDisplayReconfiguration(CGDirectDisplayID aDisplay
,
873 CGDisplayChangeSummaryFlags aFlags
) {
874 // Display reconfiguration notifications are fired in two phases: Before
875 // the reconfiguration and after the reconfiguration.
876 // All displays are notified before (with a "BeginConfiguration" flag),
877 // and the reconfigured displays are notified again after the
879 if (aFlags
& kCGDisplayBeginConfigurationFlag
) {
880 // We're only interested in the "after" notification, for the display
881 // link's current display.
885 if (!NS_IsMainThread()) {
889 bool didReconfigureCurrentDisplayLinkDisplay
= false;
891 auto displayLink
= mDisplayLink
.Lock();
892 didReconfigureCurrentDisplayLinkDisplay
=
894 CVDisplayLinkGetCurrentCGDisplay(*displayLink
) == aDisplay
;
897 if (didReconfigureCurrentDisplayLinkDisplay
) {
898 // The link's current display has been reconfigured.
899 // Recreate the display link, because otherwise it may be stuck with a
900 // "removed" display forever and never notify us again.
906 // Accessed from main thread and from display reconfiguration callback
907 // thread... which also happens to be the main thread.
908 DataMutex
<CVDisplayLinkRef
> mDisplayLink
;
910 // Accessed only from the main thread.
911 RefPtr
<nsITimer
> mTimer
;
912 TimeDuration mVsyncRate
;
915 static CVReturn
VsyncCallback(CVDisplayLinkRef aDisplayLink
,
916 const CVTimeStamp
* aNow
,
917 const CVTimeStamp
* aOutputTime
,
918 CVOptionFlags aFlagsIn
, CVOptionFlags
* aFlagsOut
,
919 void* aDisplayLinkContext
) {
920 // Executed on OS X hardware vsync thread
921 OSXVsyncSource
* vsyncSource
= (OSXVsyncSource
*)aDisplayLinkContext
;
923 mozilla::TimeStamp outputTime
=
924 mozilla::TimeStamp::FromSystemTime(aOutputTime
->hostTime
);
925 mozilla::TimeStamp nextVsync
= outputTime
;
926 mozilla::TimeStamp previousVsync
= vsyncSource
->mPreviousTimestamp
;
927 mozilla::TimeStamp now
= TimeStamp::Now();
929 // Snow leopard sometimes sends vsync timestamps very far in the past.
930 // Normalize the vsync timestamps to now.
931 if (nextVsync
<= previousVsync
) {
934 } else if (now
< previousVsync
) {
935 // Bug 1158321 - The VsyncCallback can sometimes execute before the reported
936 // vsync time. In those cases, normalize the timestamp to Now() as sending
937 // timestamps in the future has undefined behavior. See the comment above
938 // OSXVsyncSource::mPreviousTimestamp
942 vsyncSource
->mPreviousTimestamp
= nextVsync
;
944 vsyncSource
->NotifyVsync(previousVsync
, outputTime
);
945 return kCVReturnSuccess
;
949 already_AddRefed
<mozilla::gfx::VsyncSource
>
950 gfxPlatformMac::CreateGlobalHardwareVsyncSource() {
951 #ifdef MOZ_WIDGET_COCOA
952 RefPtr
<VsyncSource
> osxVsyncSource
= new OSXVsyncSource();
953 osxVsyncSource
->EnableVsync();
954 if (!osxVsyncSource
->IsVsyncEnabled()) {
956 "OS X Vsync source not enabled. Falling back to software vsync.");
957 return GetSoftwareVsyncSource();
960 osxVsyncSource
->DisableVsync();
961 return osxVsyncSource
.forget();
963 // TODO: CADisplayLink
964 return GetSoftwareVsyncSource();
968 nsTArray
<uint8_t> gfxPlatformMac::GetPlatformCMSOutputProfileData() {
969 nsTArray
<uint8_t> prefProfileData
= GetPrefCMSOutputProfileData();
970 if (!prefProfileData
.IsEmpty()) {
971 return prefProfileData
;
974 CGColorSpaceRef cspace
= nil
;
975 #ifdef MOZ_WIDGET_COCOA
976 cspace
= ::CGDisplayCopyColorSpace(::CGMainDisplayID());
979 cspace
= ::CGColorSpaceCreateDeviceRGB();
982 return nsTArray
<uint8_t>();
985 CFDataRef iccp
= ::CGColorSpaceCopyICCData(cspace
);
990 return nsTArray
<uint8_t>();
993 // copy to external buffer
994 size_t size
= static_cast<size_t>(::CFDataGetLength(iccp
));
996 nsTArray
<uint8_t> result
;
999 result
.AppendElements(::CFDataGetBytePtr(iccp
), size
);
1007 bool gfxPlatformMac::CheckVariationFontSupport() { return true; }
1009 void gfxPlatformMac::InitPlatformGPUProcessPrefs() {
1010 FeatureState
& gpuProc
= gfxConfig::GetFeature(Feature::GPU_PROCESS
);
1011 gpuProc
.ForceDisable(FeatureStatus::Blocked
,
1012 "GPU process does not work on Mac",
1013 "FEATURE_FAILURE_MAC_GPU_PROC"_ns
);