Bug 1646817 - Support DocumentChannel process switching in sidebars and popups r...
[gecko.git] / widget / cocoa / nsCocoaFeatures.mm
blob5f1138baf0c9f11f8132d5d0baff5d7a7a3d5c35
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 // This file makes some assumptions about the versions of macOS.
7 // We are assuming that the major, minor and bugfix versions are each less than
8 // 256.
9 // There are MOZ_ASSERTs for that.
11 // The formula for the version integer is (major << 16) + (minor << 8) + bugfix.
13 #define MACOS_VERSION_MASK 0x00FFFFFF
14 #define MACOS_MAJOR_VERSION_MASK 0x00FFFFFF
15 #define MACOS_MINOR_VERSION_MASK 0x00FFFFFF
16 #define MACOS_BUGFIX_VERSION_MASK 0x00FFFFFF
17 #define MACOS_VERSION_10_0_HEX 0x000A0000
18 #define MACOS_VERSION_10_9_HEX 0x000A0900
19 #define MACOS_VERSION_10_10_HEX 0x000A0A00
20 #define MACOS_VERSION_10_11_HEX 0x000A0B00
21 #define MACOS_VERSION_10_12_HEX 0x000A0C00
22 #define MACOS_VERSION_10_13_HEX 0x000A0D00
23 #define MACOS_VERSION_10_14_HEX 0x000A0E00
24 #define MACOS_VERSION_10_15_HEX 0x000A0F00
25 #define MACOS_VERSION_10_16_HEX 0x000A1000
26 #define MACOS_VERSION_11_0_HEX 0x000B0000
28 #include "nsCocoaFeatures.h"
29 #include "nsCocoaUtils.h"
30 #include "nsDebug.h"
31 #include "nsObjCExceptions.h"
33 #import <Cocoa/Cocoa.h>
34 #include <sys/sysctl.h>
36 /*static*/ int32_t nsCocoaFeatures::mOSVersion = 0;
38 // This should not be called with unchecked aMajor, which should be >= 10.
39 inline int32_t AssembleVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix) {
40   MOZ_ASSERT(aMajor >= 10);
41   return (aMajor << 16) + (aMinor << 8) + aBugFix;
44 int32_t nsCocoaFeatures::ExtractMajorVersion(int32_t aVersion) {
45   MOZ_ASSERT((aVersion & MACOS_VERSION_MASK) == aVersion);
46   return (aVersion & 0xFF0000) >> 16;
49 int32_t nsCocoaFeatures::ExtractMinorVersion(int32_t aVersion) {
50   MOZ_ASSERT((aVersion & MACOS_VERSION_MASK) == aVersion);
51   return (aVersion & 0xFF00) >> 8;
54 int32_t nsCocoaFeatures::ExtractBugFixVersion(int32_t aVersion) {
55   MOZ_ASSERT((aVersion & MACOS_VERSION_MASK) == aVersion);
56   return aVersion & 0xFF;
59 static int intAtStringIndex(NSArray* array, int index) {
60   return [(NSString*)[array objectAtIndex:index] integerValue];
63 void nsCocoaFeatures::GetSystemVersion(int& major, int& minor, int& bugfix) {
64   major = minor = bugfix = 0;
66   NSString* versionString = [[NSDictionary
67       dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]
68       objectForKey:@"ProductVersion"];
69   if (!versionString) {
70     NS_ERROR("Couldn't read /System/Library/CoreServices/SystemVersion.plist to determine macOS "
71              "version.");
72     return;
73   }
74   NSArray* versions = [versionString componentsSeparatedByString:@"."];
75   NSUInteger count = [versions count];
76   if (count > 0) {
77     major = intAtStringIndex(versions, 0);
78     if (count > 1) {
79       minor = intAtStringIndex(versions, 1);
80       if (count > 2) {
81         bugfix = intAtStringIndex(versions, 2);
82       }
83     }
84   }
87 int32_t nsCocoaFeatures::GetVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix) {
88   int32_t macOSVersion;
89   if (aMajor < 10) {
90     aMajor = 10;
91     NS_ERROR("Couldn't determine macOS version, assuming 10.9");
92     macOSVersion = MACOS_VERSION_10_9_HEX;
93   } else if (aMajor == 10 && aMinor < 9) {
94     aMinor = 9;
95     NS_ERROR("macOS version too old, assuming 10.9");
96     macOSVersion = MACOS_VERSION_10_9_HEX;
97   } else {
98     MOZ_ASSERT(aMajor >= 10);
99     MOZ_ASSERT(aMajor < 256);
100     MOZ_ASSERT(aMinor >= 0);
101     MOZ_ASSERT(aMinor < 256);
102     MOZ_ASSERT(aBugFix >= 0);
103     MOZ_ASSERT(aBugFix < 256);
104     macOSVersion = AssembleVersion(aMajor, aMinor, aBugFix);
105   }
106   MOZ_ASSERT(aMajor == ExtractMajorVersion(macOSVersion));
107   MOZ_ASSERT(aMinor == ExtractMinorVersion(macOSVersion));
108   MOZ_ASSERT(aBugFix == ExtractBugFixVersion(macOSVersion));
109   return macOSVersion;
112 /*static*/ void nsCocoaFeatures::InitializeVersionNumbers() {
113   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
115   // Provide an autorelease pool to avoid leaking Cocoa objects,
116   // as this gets called before the main autorelease pool is in place.
117   nsAutoreleasePool localPool;
119   int major, minor, bugfix;
120   GetSystemVersion(major, minor, bugfix);
121   mOSVersion = GetVersion(major, minor, bugfix);
123   NS_OBJC_END_TRY_ABORT_BLOCK;
126 /* static */ int32_t nsCocoaFeatures::macOSVersion() {
127   // Don't let this be called while we're first setting the value...
128   MOZ_ASSERT((mOSVersion & MACOS_VERSION_MASK) >= 0);
129   if (!mOSVersion) {
130     mOSVersion = -1;
131     InitializeVersionNumbers();
132   }
133   return mOSVersion;
136 /* static */ int32_t nsCocoaFeatures::macOSVersionMajor() {
137   return ExtractMajorVersion(macOSVersion());
140 /* static */ int32_t nsCocoaFeatures::macOSVersionMinor() {
141   return ExtractMinorVersion(macOSVersion());
144 /* static */ int32_t nsCocoaFeatures::macOSVersionBugFix() {
145   return ExtractBugFixVersion(macOSVersion());
148 /* static */ bool nsCocoaFeatures::OnSierraExactly() {
149   return (macOSVersion() >= MACOS_VERSION_10_12_HEX) && (macOSVersion() < MACOS_VERSION_10_13_HEX);
152 /* Version of OnSierraExactly as global function callable from cairo & skia */
153 bool Gecko_OnSierraExactly() { return nsCocoaFeatures::OnSierraExactly(); }
155 /* static */ bool nsCocoaFeatures::OnHighSierraOrLater() {
156   return (macOSVersion() >= MACOS_VERSION_10_13_HEX);
159 /* static */ bool nsCocoaFeatures::OnMojaveOrLater() {
160   return (macOSVersion() >= MACOS_VERSION_10_14_HEX);
163 /* static */ bool nsCocoaFeatures::OnCatalinaOrLater() {
164   return (macOSVersion() >= MACOS_VERSION_10_15_HEX);
167 /* static */ bool nsCocoaFeatures::OnBigSurOrLater() {
168   // Account for the version being 10.16 (which occurs when the
169   // application is linked with an older SDK) or 11.0 on Big Sur.
170   return ((macOSVersion() >= MACOS_VERSION_10_16_HEX) ||
171           (macOSVersion() >= MACOS_VERSION_11_0_HEX));
174 /* static */ bool nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor, int32_t aMinor,
175                                                     int32_t aBugFix) {
176   return macOSVersion() >= GetVersion(aMajor, aMinor, aBugFix);
180  * Returns true if the process is running under Rosetta translation. Returns
181  * false if running natively or if an error was encountered. We use the
182  * `sysctl.proc_translated` sysctl which is documented by Apple to be used
183  * for this purpose. Note: using this in a sandboxed process requires allowing
184  * the sysctl in the sandbox policy.
185  */
186 /* static */ bool nsCocoaFeatures::ProcessIsRosettaTranslated() {
187   int ret = 0;
188   size_t size = sizeof(ret);
189   if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
190     if (errno != ENOENT) {
191       fprintf(stderr, "Failed to check for translation environment\n");
192     }
193     return false;
194   }
195   return (ret == 1);