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");
591 case Script::ARABIC_NASTALIQ
:
592 aFontList
.AppendElement("Noto Nastaliq Urdu");
595 // Script codes for which no commonly-installed font is currently known.
596 // Probably future macOS versions will add Noto fonts for many of these,
597 // so we should watch for updates.
598 case Script::OLD_CHURCH_SLAVONIC_CYRILLIC
:
599 case Script::DEMOTIC_EGYPTIAN
:
600 case Script::HIERATIC_EGYPTIAN
:
601 case Script::BLISSYMBOLS
:
603 case Script::KHUTSURI
:
604 case Script::HARAPPAN_INDUS
:
605 case Script::LATIN_FRAKTUR
:
606 case Script::LATIN_GAELIC
:
607 case Script::MAYAN_HIEROGLYPHS
:
608 case Script::RONGORONGO
:
610 case Script::ESTRANGELO_SYRIAC
:
611 case Script::WESTERN_SYRIAC
:
612 case Script::EASTERN_SYRIAC
:
613 case Script::TENGWAR
:
614 case Script::VISIBLE_SPEECH
:
615 case Script::UNWRITTEN_LANGUAGES
:
616 case Script::UNKNOWN
:
617 case Script::SIGNWRITING
:
619 case Script::BOOK_PAHLAVI
:
620 case Script::NAKHI_GEBA
:
624 case Script::JURCHEN
:
628 case Script::ANATOLIAN_HIEROGLYPHS
:
629 case Script::MASARAM_GONDI
:
630 case Script::SOYOMBO
:
631 case Script::ZANABAZAR_SQUARE
:
633 case Script::GUNJALA_GONDI
:
634 case Script::MAKASAR
:
635 case Script::MEDEFAIDRIN
:
636 case Script::SOGDIAN
:
637 case Script::OLD_SOGDIAN
:
638 case Script::ELYMAIC
:
639 case Script::NYIAKENG_PUACHUE_HMONG
:
640 case Script::NANDINAGARI
:
641 case Script::CHORASMIAN
:
642 case Script::DIVES_AKURU
:
643 case Script::KHITAN_SMALL_SCRIPT
:
645 case Script::CYPRO_MINOAN
:
646 case Script::OLD_UYGHUR
:
649 case Script::VITHKUQI
:
651 case Script::NAG_MUNDARI
:
653 case Script::GURUNG_KHEMA
:
654 case Script::KIRAT_RAI
:
655 case Script::OL_ONAL
:
656 case Script::SUNUWAR
:
658 case Script::TULU_TIGALARI
:
662 // Symbols/dingbats are generally Script=COMMON but may be resolved to any
663 // surrounding script run. So we'll always append a couple of likely fonts
664 // for such characters.
665 const uint32_t b
= aCh
>> 8;
666 if (aRunScript
== Script::COMMON
|| // Stray COMMON chars not resolved
667 (b
>= 0x20 && b
<= 0x2b) || b
== 0x2e || // BMP symbols/punctuation/etc
668 GetGenCategory(aCh
) == nsUGenCategory::kSymbol
||
669 GetGenCategory(aCh
) == nsUGenCategory::kPunctuation
) {
671 aFontList
.AppendElement("Zapf Dingbats");
673 aFontList
.AppendElement("Geneva");
674 aFontList
.AppendElement("STIXGeneral");
675 aFontList
.AppendElement("Apple Symbols");
676 // Japanese fonts also cover a lot of miscellaneous symbols
677 aFontList
.AppendElement("Hiragino Sans");
678 aFontList
.AppendElement("Hiragino Kaku Gothic ProN");
681 // Arial Unicode MS has lots of glyphs for obscure characters; try it as a
683 aFontList
.AppendElement("Arial Unicode MS");
687 void gfxPlatformMac::LookupSystemFont(
688 mozilla::LookAndFeel::FontID aSystemFontID
, nsACString
& aSystemFontName
,
689 gfxFontStyle
& aFontStyle
) {
690 return PlatformFontListClass::LookupSystemFont(aSystemFontID
, aSystemFontName
,
694 uint32_t gfxPlatformMac::ReadAntiAliasingThreshold() {
695 uint32_t threshold
= 0; // default == no threshold
697 // first read prefs flag to determine whether to use the setting or not
698 bool useAntiAliasingThreshold
=
699 Preferences::GetBool("gfx.use_text_smoothing_setting", false);
701 // if the pref setting is disabled, return 0 which effectively disables this
703 if (!useAntiAliasingThreshold
) return threshold
;
705 // value set via Appearance pref panel, "Turn off text smoothing for font
706 // sizes xxx and smaller"
707 CFNumberRef prefValue
= (CFNumberRef
)CFPreferencesCopyAppValue(
708 CFSTR("AppleAntiAliasingThreshold"), kCFPreferencesCurrentApplication
);
711 if (!CFNumberGetValue(prefValue
, kCFNumberIntType
, &threshold
)) {
714 CFRelease(prefValue
);
720 bool gfxPlatformMac::AccelerateLayersByDefault() { return true; }
722 #ifdef MOZ_WIDGET_COCOA
723 // This is the renderer output callback function, called on the vsync thread
724 static CVReturn
VsyncCallback(CVDisplayLinkRef aDisplayLink
,
725 const CVTimeStamp
* aNow
,
726 const CVTimeStamp
* aOutputTime
,
727 CVOptionFlags aFlagsIn
, CVOptionFlags
* aFlagsOut
,
728 void* aDisplayLinkContext
);
730 class OSXVsyncSource final
: public VsyncSource
{
733 : mDisplayLink(nullptr, "OSXVsyncSource::OSXDisplay::mDisplayLink") {
734 MOZ_ASSERT(NS_IsMainThread());
735 mTimer
= NS_NewTimer();
736 CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback
,
740 virtual ~OSXVsyncSource() {
741 MOZ_ASSERT(NS_IsMainThread());
742 CGDisplayRemoveReconfigurationCallback(DisplayReconfigurationCallback
,
746 static void RetryEnableVsync(nsITimer
* aTimer
, void* aOsxVsyncSource
) {
747 MOZ_ASSERT(NS_IsMainThread());
748 OSXVsyncSource
* osxVsyncSource
=
749 static_cast<OSXVsyncSource
*>(aOsxVsyncSource
);
750 MOZ_ASSERT(osxVsyncSource
);
751 osxVsyncSource
->EnableVsync();
754 void EnableVsync() override
{
755 MOZ_ASSERT(NS_IsMainThread());
756 if (IsVsyncEnabled()) {
760 auto displayLink
= mDisplayLink
.Lock();
762 // Create a display link capable of being used with all active displays
763 // TODO: See if we need to create an active DisplayLink for each monitor
764 // in multi-monitor situations. According to the docs, it is compatible
765 // with all displays running on the computer But if we have different
766 // monitors at different display rates, we may hit issues.
767 CVReturn retval
= CVDisplayLinkCreateWithActiveCGDisplays(&*displayLink
);
769 // Workaround for bug 1201401: CVDisplayLinkCreateWithCGDisplays()
770 // (called by CVDisplayLinkCreateWithActiveCGDisplays()) sometimes
771 // creates a CVDisplayLinkRef with an uninitialized (nulled) internal
772 // pointer. If we continue to use this CVDisplayLinkRef, we will
773 // eventually crash in CVCGDisplayLink::getDisplayTimes(), where the
774 // internal pointer is dereferenced. Fortunately, when this happens
775 // another internal variable is also left uninitialized (zeroed),
776 // which is accessible via CVDisplayLinkGetCurrentCGDisplay(). In
777 // normal conditions the current display is never zero.
778 if ((retval
== kCVReturnSuccess
) &&
779 (CVDisplayLinkGetCurrentCGDisplay(*displayLink
) == 0)) {
780 retval
= kCVReturnInvalidDisplay
;
783 if (retval
!= kCVReturnSuccess
) {
785 "Could not create a display link with all active displays. "
787 CVDisplayLinkRelease(*displayLink
);
788 *displayLink
= nullptr;
790 // bug 1142708 - When coming back from sleep,
791 // or when changing displays, active displays may not be ready yet,
792 // even if listening for the kIOMessageSystemHasPoweredOn event
793 // from OS X sleep notifications.
794 // Active displays are those that are drawable.
795 // bug 1144638 - When changing display configurations and getting
796 // notifications from CGDisplayReconfigurationCallBack, the
797 // callback gets called twice for each active display
798 // so it's difficult to know when all displays are active.
799 // Instead, try again soon. The delay is arbitrary. 100ms chosen
800 // because on a late 2013 15" retina, it takes about that
801 // long to come back up from sleep.
802 uint32_t delay
= 100;
803 mTimer
->InitWithNamedFuncCallback(RetryEnableVsync
, this, delay
,
804 nsITimer::TYPE_ONE_SHOT
,
809 if (CVDisplayLinkSetOutputCallback(*displayLink
, &VsyncCallback
, this) !=
811 NS_WARNING("Could not set displaylink output callback");
812 CVDisplayLinkRelease(*displayLink
);
813 *displayLink
= nullptr;
817 mPreviousTimestamp
= TimeStamp::Now();
818 if (CVDisplayLinkStart(*displayLink
) != kCVReturnSuccess
) {
819 NS_WARNING("Could not activate the display link");
820 CVDisplayLinkRelease(*displayLink
);
821 *displayLink
= nullptr;
825 CVDisplayLinkGetNominalOutputVideoRefreshPeriod(*displayLink
);
826 if (vsyncRate
.flags
& kCVTimeIsIndefinite
) {
827 NS_WARNING("Could not get vsync rate, setting to 60.");
828 mVsyncRate
= TimeDuration::FromMilliseconds(1000.0 / 60.0);
830 int64_t timeValue
= vsyncRate
.timeValue
;
831 int64_t timeScale
= vsyncRate
.timeScale
;
832 const int milliseconds
= 1000;
833 float rateInMs
= ((double)timeValue
/ (double)timeScale
) * milliseconds
;
834 mVsyncRate
= TimeDuration::FromMilliseconds(rateInMs
);
838 void DisableVsync() override
{
839 MOZ_ASSERT(NS_IsMainThread());
840 if (!IsVsyncEnabled()) {
844 // Release the display link
845 auto displayLink
= mDisplayLink
.Lock();
847 CVDisplayLinkRelease(*displayLink
);
848 *displayLink
= nullptr;
852 bool IsVsyncEnabled() override
{
853 MOZ_ASSERT(NS_IsMainThread());
854 auto displayLink
= mDisplayLink
.Lock();
855 return *displayLink
!= nullptr;
858 TimeDuration
GetVsyncRate() override
{ return mVsyncRate
; }
860 void Shutdown() override
{
861 MOZ_ASSERT(NS_IsMainThread());
867 // The vsync timestamps given by the CVDisplayLinkCallback are
868 // in the future for the NEXT frame. Large parts of Gecko, such
869 // as animations assume a timestamp at either now or in the past.
870 // Normalize the timestamps given to the VsyncDispatchers to the vsync
871 // that just occured, not the vsync that is upcoming.
872 TimeStamp mPreviousTimestamp
;
875 static void DisplayReconfigurationCallback(CGDirectDisplayID aDisplay
,
876 CGDisplayChangeSummaryFlags aFlags
,
878 static_cast<OSXVsyncSource
*>(aUserInfo
)->OnDisplayReconfiguration(aDisplay
,
882 void OnDisplayReconfiguration(CGDirectDisplayID aDisplay
,
883 CGDisplayChangeSummaryFlags aFlags
) {
884 // Display reconfiguration notifications are fired in two phases: Before
885 // the reconfiguration and after the reconfiguration.
886 // All displays are notified before (with a "BeginConfiguration" flag),
887 // and the reconfigured displays are notified again after the
889 if (aFlags
& kCGDisplayBeginConfigurationFlag
) {
890 // We're only interested in the "after" notification, for the display
891 // link's current display.
895 if (!NS_IsMainThread()) {
899 bool didReconfigureCurrentDisplayLinkDisplay
= false;
901 auto displayLink
= mDisplayLink
.Lock();
902 didReconfigureCurrentDisplayLinkDisplay
=
904 CVDisplayLinkGetCurrentCGDisplay(*displayLink
) == aDisplay
;
907 if (didReconfigureCurrentDisplayLinkDisplay
) {
908 // The link's current display has been reconfigured.
909 // Recreate the display link, because otherwise it may be stuck with a
910 // "removed" display forever and never notify us again.
916 // Accessed from main thread and from display reconfiguration callback
917 // thread... which also happens to be the main thread.
918 DataMutex
<CVDisplayLinkRef
> mDisplayLink
;
920 // Accessed only from the main thread.
921 RefPtr
<nsITimer
> mTimer
;
922 TimeDuration mVsyncRate
;
925 static CVReturn
VsyncCallback(CVDisplayLinkRef aDisplayLink
,
926 const CVTimeStamp
* aNow
,
927 const CVTimeStamp
* aOutputTime
,
928 CVOptionFlags aFlagsIn
, CVOptionFlags
* aFlagsOut
,
929 void* aDisplayLinkContext
) {
930 // Executed on OS X hardware vsync thread
931 OSXVsyncSource
* vsyncSource
= (OSXVsyncSource
*)aDisplayLinkContext
;
933 mozilla::TimeStamp outputTime
=
934 mozilla::TimeStamp::FromSystemTime(aOutputTime
->hostTime
);
935 mozilla::TimeStamp nextVsync
= outputTime
;
936 mozilla::TimeStamp previousVsync
= vsyncSource
->mPreviousTimestamp
;
937 mozilla::TimeStamp now
= TimeStamp::Now();
939 // Snow leopard sometimes sends vsync timestamps very far in the past.
940 // Normalize the vsync timestamps to now.
941 if (nextVsync
<= previousVsync
) {
944 } else if (now
< previousVsync
) {
945 // Bug 1158321 - The VsyncCallback can sometimes execute before the reported
946 // vsync time. In those cases, normalize the timestamp to Now() as sending
947 // timestamps in the future has undefined behavior. See the comment above
948 // OSXVsyncSource::mPreviousTimestamp
952 vsyncSource
->mPreviousTimestamp
= nextVsync
;
954 vsyncSource
->NotifyVsync(previousVsync
, outputTime
);
955 return kCVReturnSuccess
;
959 already_AddRefed
<mozilla::gfx::VsyncSource
>
960 gfxPlatformMac::CreateGlobalHardwareVsyncSource() {
961 #ifdef MOZ_WIDGET_COCOA
962 RefPtr
<VsyncSource
> osxVsyncSource
= new OSXVsyncSource();
963 osxVsyncSource
->EnableVsync();
964 if (!osxVsyncSource
->IsVsyncEnabled()) {
966 "OS X Vsync source not enabled. Falling back to software vsync.");
967 return GetSoftwareVsyncSource();
970 osxVsyncSource
->DisableVsync();
971 return osxVsyncSource
.forget();
973 // TODO: CADisplayLink
974 return GetSoftwareVsyncSource();
978 nsTArray
<uint8_t> gfxPlatformMac::GetPlatformCMSOutputProfileData() {
979 nsTArray
<uint8_t> prefProfileData
= GetPrefCMSOutputProfileData();
980 if (!prefProfileData
.IsEmpty()) {
981 return prefProfileData
;
984 CGColorSpaceRef cspace
= nil
;
985 #ifdef MOZ_WIDGET_COCOA
986 cspace
= ::CGDisplayCopyColorSpace(::CGMainDisplayID());
989 cspace
= ::CGColorSpaceCreateDeviceRGB();
992 return nsTArray
<uint8_t>();
995 CFDataRef iccp
= ::CGColorSpaceCopyICCData(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() { return true; }
1019 void gfxPlatformMac::InitPlatformGPUProcessPrefs() {
1020 FeatureState
& gpuProc
= gfxConfig::GetFeature(Feature::GPU_PROCESS
);
1021 gpuProc
.ForceDisable(FeatureStatus::Blocked
,
1022 "GPU process does not work on Mac",
1023 "FEATURE_FAILURE_MAC_GPU_PROC"_ns
);