Bug 1851529 - Set clang-format ColumnLimit consistently. r=sylvestre,necko-reviewers,kershaw

For some reason, its value in the Google style we use is 80... except
for Objective-C, where it's 100, which led to things like:
https://hg.mozilla.org/mozilla-central/rev/31bf68247e6e
https://hg.mozilla.org/mozilla-central/rev/64ceb33533a4.

There's probably a discussion to have about whether 80 is the right
limit, but since it's what's used for everything except ObjC, let's roll
with it.

# ignore-this-changeset

Differential Revision: https://phabricator.services.mozilla.com/D187409
This commit is contained in:
Mike Hommey 2023-09-05 11:23:01 +00:00
parent ccc3244a24
commit 9331b9fb07
126 changed files with 8385 additions and 5412 deletions

View file

@ -1,4 +1,5 @@
BasedOnStyle: Google BasedOnStyle: Google
ColumnLimit: 80
# Prevent the loss of indentation with these macros # Prevent the loss of indentation with these macros
MacroBlockBegin: "^\ MacroBlockBegin: "^\

View file

@ -24,27 +24,32 @@ using namespace mozilla::a11y;
// xpcAccessibleMacNSObjectWrapper // xpcAccessibleMacNSObjectWrapper
NS_IMPL_ISUPPORTS(xpcAccessibleMacNSObjectWrapper, nsIAccessibleMacNSObjectWrapper) NS_IMPL_ISUPPORTS(xpcAccessibleMacNSObjectWrapper,
nsIAccessibleMacNSObjectWrapper)
xpcAccessibleMacNSObjectWrapper::xpcAccessibleMacNSObjectWrapper(id aNativeObj) xpcAccessibleMacNSObjectWrapper::xpcAccessibleMacNSObjectWrapper(id aNativeObj)
: mNativeObject(aNativeObj) { : mNativeObject(aNativeObj) {
[mNativeObject retain]; [mNativeObject retain];
} }
xpcAccessibleMacNSObjectWrapper::~xpcAccessibleMacNSObjectWrapper() { [mNativeObject release]; } xpcAccessibleMacNSObjectWrapper::~xpcAccessibleMacNSObjectWrapper() {
[mNativeObject release];
}
id xpcAccessibleMacNSObjectWrapper::GetNativeObject() { return mNativeObject; } id xpcAccessibleMacNSObjectWrapper::GetNativeObject() { return mNativeObject; }
// xpcAccessibleMacInterface // xpcAccessibleMacInterface
NS_IMPL_ISUPPORTS_INHERITED(xpcAccessibleMacInterface, xpcAccessibleMacNSObjectWrapper, NS_IMPL_ISUPPORTS_INHERITED(xpcAccessibleMacInterface,
xpcAccessibleMacNSObjectWrapper,
nsIAccessibleMacInterface) nsIAccessibleMacInterface)
xpcAccessibleMacInterface::xpcAccessibleMacInterface(Accessible* aObj) xpcAccessibleMacInterface::xpcAccessibleMacInterface(Accessible* aObj)
: xpcAccessibleMacNSObjectWrapper(GetNativeFromGeckoAccessible(aObj)) {} : xpcAccessibleMacNSObjectWrapper(GetNativeFromGeckoAccessible(aObj)) {}
NS_IMETHODIMP NS_IMETHODIMP
xpcAccessibleMacInterface::GetAttributeNames(nsTArray<nsString>& aAttributeNames) { xpcAccessibleMacInterface::GetAttributeNames(
nsTArray<nsString>& aAttributeNames) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN NS_OBJC_BEGIN_TRY_BLOCK_RETURN
if (!mNativeObject || [mNativeObject isExpired]) { if (!mNativeObject || [mNativeObject isExpired]) {
@ -63,14 +68,16 @@ xpcAccessibleMacInterface::GetAttributeNames(nsTArray<nsString>& aAttributeNames
} }
NS_IMETHODIMP NS_IMETHODIMP
xpcAccessibleMacInterface::GetParameterizedAttributeNames(nsTArray<nsString>& aAttributeNames) { xpcAccessibleMacInterface::GetParameterizedAttributeNames(
nsTArray<nsString>& aAttributeNames) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN NS_OBJC_BEGIN_TRY_BLOCK_RETURN
if (!mNativeObject || [mNativeObject isExpired]) { if (!mNativeObject || [mNativeObject isExpired]) {
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
for (NSString* name in [mNativeObject accessibilityParameterizedAttributeNames]) { for (NSString* name in
[mNativeObject accessibilityParameterizedAttributeNames]) {
nsAutoString attribName; nsAutoString attribName;
nsCocoaUtils::GetStringForNSString(name, attribName); nsCocoaUtils::GetStringForNSString(name, attribName);
aAttributeNames.AppendElement(attribName); aAttributeNames.AppendElement(attribName);
@ -117,7 +124,8 @@ xpcAccessibleMacInterface::PerformAction(const nsAString& aActionName) {
} }
NS_IMETHODIMP NS_IMETHODIMP
xpcAccessibleMacInterface::GetAttributeValue(const nsAString& aAttributeName, JSContext* aCx, xpcAccessibleMacInterface::GetAttributeValue(const nsAString& aAttributeName,
JSContext* aCx,
JS::MutableHandleValue aResult) { JS::MutableHandleValue aResult) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN NS_OBJC_BEGIN_TRY_BLOCK_RETURN
@ -126,17 +134,20 @@ xpcAccessibleMacInterface::GetAttributeValue(const nsAString& aAttributeName, JS
} }
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName); NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
return NSObjectToJsValue([mNativeObject accessibilityAttributeValue:attribName], aCx, aResult); return NSObjectToJsValue(
[mNativeObject accessibilityAttributeValue:attribName], aCx, aResult);
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE) NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE)
} }
NS_IMETHODIMP NS_IMETHODIMP
xpcAccessibleMacInterface::IsAttributeSettable(const nsAString& aAttributeName, bool* aIsSettable) { xpcAccessibleMacInterface::IsAttributeSettable(const nsAString& aAttributeName,
bool* aIsSettable) {
NS_ENSURE_ARG_POINTER(aIsSettable); NS_ENSURE_ARG_POINTER(aIsSettable);
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName); NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
if ([mNativeObject respondsToSelector:@selector(accessibilityIsAttributeSettable:)]) { if ([mNativeObject
respondsToSelector:@selector(accessibilityIsAttributeSettable:)]) {
*aIsSettable = [mNativeObject accessibilityIsAttributeSettable:attribName]; *aIsSettable = [mNativeObject accessibilityIsAttributeSettable:attribName];
return NS_OK; return NS_OK;
} }
@ -146,13 +157,15 @@ xpcAccessibleMacInterface::IsAttributeSettable(const nsAString& aAttributeName,
NS_IMETHODIMP NS_IMETHODIMP
xpcAccessibleMacInterface::SetAttributeValue(const nsAString& aAttributeName, xpcAccessibleMacInterface::SetAttributeValue(const nsAString& aAttributeName,
JS::HandleValue aAttributeValue, JSContext* aCx) { JS::HandleValue aAttributeValue,
JSContext* aCx) {
nsresult rv = NS_OK; nsresult rv = NS_OK;
id obj = JsValueToNSObject(aAttributeValue, aCx, &rv); id obj = JsValueToNSObject(aAttributeValue, aCx, &rv);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName); NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
if ([mNativeObject respondsToSelector:@selector(accessibilitySetValue:forAttribute:)]) { if ([mNativeObject respondsToSelector:@selector(accessibilitySetValue:
forAttribute:)]) {
// The NSObject has an attribute setter, call that. // The NSObject has an attribute setter, call that.
[mNativeObject accessibilitySetValue:obj forAttribute:attribName]; [mNativeObject accessibilitySetValue:obj forAttribute:attribName];
return NS_OK; return NS_OK;
@ -162,29 +175,30 @@ xpcAccessibleMacInterface::SetAttributeValue(const nsAString& aAttributeName,
} }
NS_IMETHODIMP NS_IMETHODIMP
xpcAccessibleMacInterface::GetParameterizedAttributeValue(const nsAString& aAttributeName, xpcAccessibleMacInterface::GetParameterizedAttributeValue(
JS::HandleValue aParameter, const nsAString& aAttributeName, JS::HandleValue aParameter, JSContext* aCx,
JSContext* aCx, JS::MutableHandleValue aResult) {
JS::MutableHandleValue aResult) {
nsresult rv = NS_OK; nsresult rv = NS_OK;
id paramObj = JsValueToNSObject(aParameter, aCx, &rv); id paramObj = JsValueToNSObject(aParameter, aCx, &rv);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName); NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
return NSObjectToJsValue( return NSObjectToJsValue([mNativeObject accessibilityAttributeValue:attribName
[mNativeObject accessibilityAttributeValue:attribName forParameter:paramObj], aCx, aResult); forParameter:paramObj],
aCx, aResult);
} }
bool xpcAccessibleMacInterface::SupportsSelector(SEL aSelector) { bool xpcAccessibleMacInterface::SupportsSelector(SEL aSelector) {
// return true if we have this selector, and if isAccessibilitySelectorAllowed // return true if we have this selector, and if isAccessibilitySelectorAllowed
// is implemented too whether it is "allowed". // is implemented too whether it is "allowed".
return [mNativeObject respondsToSelector:aSelector] && return [mNativeObject respondsToSelector:aSelector] &&
(![mNativeObject respondsToSelector:@selector(isAccessibilitySelectorAllowed:selector:)] || (![mNativeObject respondsToSelector:@selector
(isAccessibilitySelectorAllowed:selector:)] ||
[mNativeObject isAccessibilitySelectorAllowed:aSelector]); [mNativeObject isAccessibilitySelectorAllowed:aSelector]);
} }
nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx, nsresult xpcAccessibleMacInterface::NSObjectToJsValue(
JS::MutableHandleValue aResult) { id aObj, JSContext* aCx, JS::MutableHandleValue aResult) {
if (!aObj) { if (!aObj) {
aResult.set(JS::NullValue()); aResult.set(JS::NullValue());
} else if ([aObj isKindOfClass:[NSString class]]) { } else if ([aObj isKindOfClass:[NSString class]]) {
@ -201,7 +215,8 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
} else { } else {
if (!mozilla::dom::ToJSValue(aCx, [(NSNumber*)aObj doubleValue], aResult)) { if (!mozilla::dom::ToJSValue(aCx, [(NSNumber*)aObj doubleValue],
aResult)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
} }
@ -209,18 +224,25 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
strcmp([(NSValue*)aObj objCType], @encode(NSPoint)) == 0) { strcmp([(NSValue*)aObj objCType], @encode(NSPoint)) == 0) {
NSPoint point = [(NSValue*)aObj pointValue]; NSPoint point = [(NSValue*)aObj pointValue];
return NSObjectToJsValue( return NSObjectToJsValue(
@[ [NSNumber numberWithDouble:point.x], [NSNumber numberWithDouble:point.y] ], aCx, @[
aResult); [NSNumber numberWithDouble:point.x],
[NSNumber numberWithDouble:point.y]
],
aCx, aResult);
} else if ([aObj isKindOfClass:[NSValue class]] && } else if ([aObj isKindOfClass:[NSValue class]] &&
strcmp([(NSValue*)aObj objCType], @encode(NSSize)) == 0) { strcmp([(NSValue*)aObj objCType], @encode(NSSize)) == 0) {
NSSize size = [(NSValue*)aObj sizeValue]; NSSize size = [(NSValue*)aObj sizeValue];
return NSObjectToJsValue( return NSObjectToJsValue(
@[ [NSNumber numberWithDouble:size.width], [NSNumber numberWithDouble:size.height] ], aCx, @[
aResult); [NSNumber numberWithDouble:size.width],
[NSNumber numberWithDouble:size.height]
],
aCx, aResult);
} else if ([aObj isKindOfClass:[NSValue class]] && } else if ([aObj isKindOfClass:[NSValue class]] &&
strcmp([(NSValue*)aObj objCType], @encode(NSRange)) == 0) { strcmp([(NSValue*)aObj objCType], @encode(NSRange)) == 0) {
NSRange range = [(NSValue*)aObj rangeValue]; NSRange range = [(NSValue*)aObj rangeValue];
return NSObjectToJsValue(@[ @(range.location), @(range.length) ], aCx, aResult); return NSObjectToJsValue(@[ @(range.location), @(range.length) ], aCx,
aResult);
} else if ([aObj isKindOfClass:[NSValue class]] && } else if ([aObj isKindOfClass:[NSValue class]] &&
strcmp([(NSValue*)aObj objCType], @encode(NSRect)) == 0) { strcmp([(NSValue*)aObj objCType], @encode(NSRect)) == 0) {
NSRect rect = [(NSValue*)aObj rectValue]; NSRect rect = [(NSValue*)aObj rectValue];
@ -263,14 +285,18 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
[attrStr [attrStr
enumerateAttributesInRange:NSMakeRange(0, [attrStr length]) enumerateAttributesInRange:NSMakeRange(0, [attrStr length])
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired options:
usingBlock:^(NSDictionary* attributes, NSRange range, BOOL* stop) { NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
NSString* str = [[attrStr string] substringWithRange:range]; usingBlock:^(NSDictionary* attributes, NSRange range,
BOOL* stop) {
NSString* str =
[[attrStr string] substringWithRange:range];
if (!str || !attributes) { if (!str || !attributes) {
return; return;
} }
NSMutableDictionary* attrRun = [attributes mutableCopy]; NSMutableDictionary* attrRun =
[attributes mutableCopy];
attrRun[@"string"] = str; attrRun[@"string"] = str;
[attrRunArray addObject:attrRun]; [attrRunArray addObject:attrRun];
@ -282,28 +308,34 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
return NSObjectToJsValue(attrRunArray, aCx, aResult); return NSObjectToJsValue(attrRunArray, aCx, aResult);
} else if (CFGetTypeID(aObj) == CGColorGetTypeID()) { } else if (CFGetTypeID(aObj) == CGColorGetTypeID()) {
const CGFloat* components = CGColorGetComponents((CGColorRef)aObj); const CGFloat* components = CGColorGetComponents((CGColorRef)aObj);
NSString* hexString = NSString* hexString = [NSString
[NSString stringWithFormat:@"#%02x%02x%02x", (int)(components[0] * 0xff), stringWithFormat:@"#%02x%02x%02x", (int)(components[0] * 0xff),
(int)(components[1] * 0xff), (int)(components[2] * 0xff)]; (int)(components[1] * 0xff),
(int)(components[2] * 0xff)];
return NSObjectToJsValue(hexString, aCx, aResult); return NSObjectToJsValue(hexString, aCx, aResult);
} else if ([aObj respondsToSelector:@selector(isAccessibilityElement)]) { } else if ([aObj respondsToSelector:@selector(isAccessibilityElement)]) {
// We expect all of our accessibility objects to implement isAccessibilityElement // We expect all of our accessibility objects to implement
// at the very least. If it is implemented we will assume its an accessibility object. // isAccessibilityElement at the very least. If it is implemented we will
nsCOMPtr<nsIAccessibleMacInterface> obj = new xpcAccessibleMacInterface(aObj); // assume its an accessibility object.
return nsContentUtils::WrapNative(aCx, obj, &NS_GET_IID(nsIAccessibleMacInterface), aResult); nsCOMPtr<nsIAccessibleMacInterface> obj =
new xpcAccessibleMacInterface(aObj);
return nsContentUtils::WrapNative(
aCx, obj, &NS_GET_IID(nsIAccessibleMacInterface), aResult);
} else { } else {
// If this is any other kind of NSObject, just wrap it and return it. // If this is any other kind of NSObject, just wrap it and return it.
// It will be opaque and immutable on the JS side, but it can be // It will be opaque and immutable on the JS side, but it can be
// brought back to us in an argument. // brought back to us in an argument.
nsCOMPtr<nsIAccessibleMacNSObjectWrapper> obj = new xpcAccessibleMacNSObjectWrapper(aObj); nsCOMPtr<nsIAccessibleMacNSObjectWrapper> obj =
return nsContentUtils::WrapNative(aCx, obj, &NS_GET_IID(nsIAccessibleMacNSObjectWrapper), new xpcAccessibleMacNSObjectWrapper(aObj);
aResult); return nsContentUtils::WrapNative(
aCx, obj, &NS_GET_IID(nsIAccessibleMacNSObjectWrapper), aResult);
} }
return NS_OK; return NS_OK;
} }
id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue, JSContext* aCx, id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue,
JSContext* aCx,
nsresult* aResult) { nsresult* aResult) {
*aResult = NS_OK; *aResult = NS_OK;
if (aValue.isInt32()) { if (aValue.isInt32()) {
@ -363,9 +395,11 @@ id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue, JSContex
nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect(); nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect();
nsCOMPtr<nsIXPConnectWrappedNative> wrappedObj; nsCOMPtr<nsIXPConnectWrappedNative> wrappedObj;
nsresult rv = xpc->GetWrappedNativeOfJSObject(aCx, obj, getter_AddRefs(wrappedObj)); nsresult rv =
xpc->GetWrappedNativeOfJSObject(aCx, obj, getter_AddRefs(wrappedObj));
NS_ENSURE_SUCCESS(rv, nil); NS_ENSURE_SUCCESS(rv, nil);
nsCOMPtr<nsIAccessibleMacNSObjectWrapper> macObjIface = do_QueryInterface(wrappedObj->Native()); nsCOMPtr<nsIAccessibleMacNSObjectWrapper> macObjIface =
do_QueryInterface(wrappedObj->Native());
return macObjIface->GetNativeObject(); return macObjIface->GetNativeObject();
} }
@ -373,7 +407,8 @@ id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue, JSContex
return nil; return nil;
} }
id xpcAccessibleMacInterface::JsValueToNSValue(JS::HandleObject aObject, JSContext* aCx, id xpcAccessibleMacInterface::JsValueToNSValue(JS::HandleObject aObject,
JSContext* aCx,
nsresult* aResult) { nsresult* aResult) {
*aResult = NS_ERROR_FAILURE; *aResult = NS_ERROR_FAILURE;
JS::RootedValue valueTypeValue(aCx); JS::RootedValue valueTypeValue(aCx);
@ -421,14 +456,15 @@ id xpcAccessibleMacInterface::JsValueToNSValue(JS::HandleObject aObject, JSConte
} }
*aResult = NS_OK; *aResult = NS_OK;
return [NSValue valueWithRange:NSMakeRange(locationValue.toInt32(), lengthValue.toInt32())]; return [NSValue valueWithRange:NSMakeRange(locationValue.toInt32(),
lengthValue.toInt32())];
} }
return nil; return nil;
} }
id xpcAccessibleMacInterface::JsValueToSpecifiedNSObject(JS::HandleObject aObject, JSContext* aCx, id xpcAccessibleMacInterface::JsValueToSpecifiedNSObject(
nsresult* aResult) { JS::HandleObject aObject, JSContext* aCx, nsresult* aResult) {
*aResult = NS_ERROR_FAILURE; *aResult = NS_ERROR_FAILURE;
JS::RootedValue objectTypeValue(aCx); JS::RootedValue objectTypeValue(aCx);
if (!JS_GetProperty(aCx, aObject, "objectType", &objectTypeValue)) { if (!JS_GetProperty(aCx, aObject, "objectType", &objectTypeValue)) {
@ -509,7 +545,8 @@ xpcAccessibleMacEvent::~xpcAccessibleMacEvent() {
NS_IMETHODIMP NS_IMETHODIMP
xpcAccessibleMacEvent::GetMacIface(nsIAccessibleMacInterface** aMacIface) { xpcAccessibleMacEvent::GetMacIface(nsIAccessibleMacInterface** aMacIface) {
RefPtr<xpcAccessibleMacInterface> macIface = new xpcAccessibleMacInterface(mNativeObject); RefPtr<xpcAccessibleMacInterface> macIface =
new xpcAccessibleMacInterface(mNativeObject);
macIface.forget(aMacIface); macIface.forget(aMacIface);
return NS_OK; return NS_OK;
} }
@ -519,20 +556,25 @@ xpcAccessibleMacEvent::GetData(JSContext* aCx, JS::MutableHandleValue aData) {
return xpcAccessibleMacInterface::NSObjectToJsValue(mData, aCx, aData); return xpcAccessibleMacInterface::NSObjectToJsValue(mData, aCx, aData);
} }
void xpcAccessibleMacEvent::FireEvent(id aNativeObj, id aNotification, id aUserInfo) { void xpcAccessibleMacEvent::FireEvent(id aNativeObj, id aNotification,
if (nsCOMPtr<nsIObserverService> obsService = services::GetObserverService()) { id aUserInfo) {
if (nsCOMPtr<nsIObserverService> obsService =
services::GetObserverService()) {
nsCOMPtr<nsISimpleEnumerator> observers; nsCOMPtr<nsISimpleEnumerator> observers;
// Get all observers for the mac event topic. // Get all observers for the mac event topic.
obsService->EnumerateObservers(NS_ACCESSIBLE_MAC_EVENT_TOPIC, getter_AddRefs(observers)); obsService->EnumerateObservers(NS_ACCESSIBLE_MAC_EVENT_TOPIC,
getter_AddRefs(observers));
if (observers) { if (observers) {
bool hasObservers = false; bool hasObservers = false;
observers->HasMoreElements(&hasObservers); observers->HasMoreElements(&hasObservers);
// If we have observers, notify them. // If we have observers, notify them.
if (hasObservers) { if (hasObservers) {
nsCOMPtr<nsIAccessibleMacEvent> xpcIface = new xpcAccessibleMacEvent(aNativeObj, aUserInfo); nsCOMPtr<nsIAccessibleMacEvent> xpcIface =
new xpcAccessibleMacEvent(aNativeObj, aUserInfo);
nsAutoString notificationStr; nsAutoString notificationStr;
nsCocoaUtils::GetStringForNSString(aNotification, notificationStr); nsCocoaUtils::GetStringForNSString(aNotification, notificationStr);
obsService->NotifyObservers(xpcIface, NS_ACCESSIBLE_MAC_EVENT_TOPIC, notificationStr.get()); obsService->NotifyObservers(xpcIface, NS_ACCESSIBLE_MAC_EVENT_TOPIC,
notificationStr.get());
} }
} }
} }

View file

@ -19,7 +19,8 @@ NS_IMPL_ISUPPORTS(nsKeychainMigrationUtils, nsIKeychainMigrationUtils)
NS_IMETHODIMP NS_IMETHODIMP
nsKeychainMigrationUtils::GetGenericPassword(const nsACString& aServiceName, nsKeychainMigrationUtils::GetGenericPassword(const nsACString& aServiceName,
const nsACString& aAccountName, nsACString& aKey) { const nsACString& aAccountName,
nsACString& aKey) {
// To retrieve a secret, we create a CFDictionary of the form: // To retrieve a secret, we create a CFDictionary of the form:
// { class: generic password, // { class: generic password,
// service: the given service name // service: the given service name
@ -31,9 +32,12 @@ nsKeychainMigrationUtils::GetGenericPassword(const nsACString& aServiceName,
// matching the given service and account names. We then extract the data // matching the given service and account names. We then extract the data
// (i.e. the secret) and return it. // (i.e. the secret) and return it.
NSDictionary* searchDictionary = @{ NSDictionary* searchDictionary = @{
(__bridge NSString*)kSecClass : (__bridge NSString*)kSecClassGenericPassword, (__bridge NSString*)
(__bridge NSString*)kSecAttrService : nsCocoaUtils::ToNSString(aServiceName), kSecClass : (__bridge NSString*)kSecClassGenericPassword,
(__bridge NSString*)kSecAttrAccount : nsCocoaUtils::ToNSString(aAccountName), (__bridge NSString*)
kSecAttrService : nsCocoaUtils::ToNSString(aServiceName),
(__bridge NSString*)
kSecAttrAccount : nsCocoaUtils::ToNSString(aAccountName),
(__bridge NSString*)kSecMatchLimit : (__bridge NSString*)kSecMatchLimitOne, (__bridge NSString*)kSecMatchLimit : (__bridge NSString*)kSecMatchLimitOne,
(__bridge NSString*)kSecReturnAttributes : @YES, (__bridge NSString*)kSecReturnAttributes : @YES,
(__bridge NSString*)kSecReturnData : @YES (__bridge NSString*)kSecReturnData : @YES
@ -41,9 +45,11 @@ nsKeychainMigrationUtils::GetGenericPassword(const nsACString& aServiceName,
CFTypeRef item; CFTypeRef item;
// https://developer.apple.com/documentation/security/1398306-secitemcopymatching // https://developer.apple.com/documentation/security/1398306-secitemcopymatching
OSStatus rv = SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, &item); OSStatus rv =
SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, &item);
if (rv != errSecSuccess) { if (rv != errSecSuccess) {
MOZ_LOG(gKeychainUtilsLog, LogLevel::Debug, ("SecItemCopyMatching failed: %d", rv)); MOZ_LOG(gKeychainUtilsLog, LogLevel::Debug,
("SecItemCopyMatching failed: %d", rv));
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
NSDictionary* resultDict = [(__bridge NSDictionary*)item autorelease]; NSDictionary* resultDict = [(__bridge NSDictionary*)item autorelease];
@ -53,8 +59,8 @@ nsKeychainMigrationUtils::GetGenericPassword(const nsACString& aServiceName,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
if ([secret length] != 0) { if ([secret length] != 0) {
// We assume that the data is UTF-8 encoded since that seems to be common and // We assume that the data is UTF-8 encoded since that seems to be common
// Keychain Access shows it with that encoding. // and Keychain Access shows it with that encoding.
aKey.Assign(reinterpret_cast<const char*>([secret bytes]), [secret length]); aKey.Assign(reinterpret_cast<const char*>([secret bytes]), [secret length]);
} }

View file

@ -18,27 +18,31 @@ using namespace mozilla::widget;
static const int kSystemDefinedEventMediaKeysSubtype = 8; static const int kSystemDefinedEventMediaKeysSubtype = 8;
static void SendFakeEvent(RefPtr<MediaHardwareKeysEventSourceMac>& aSource, int aKeyData) { static void SendFakeEvent(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeSystemDefined int aKeyData) {
location:NSZeroPoint NSEvent* event =
modifierFlags:0 [NSEvent otherEventWithType:NSEventTypeSystemDefined
timestamp:0 location:NSZeroPoint
windowNumber:0 modifierFlags:0
context:nil timestamp:0
subtype:kSystemDefinedEventMediaKeysSubtype windowNumber:0
data1:aKeyData context:nil
data2:0]; subtype:kSystemDefinedEventMediaKeysSubtype
aSource->EventTapCallback(nullptr, static_cast<CGEventType>(0), [event CGEvent], aSource.get()); data1:aKeyData
data2:0];
aSource->EventTapCallback(nullptr, static_cast<CGEventType>(0),
[event CGEvent], aSource.get());
} }
static void NotifyFakeNonMediaKey(RefPtr<MediaHardwareKeysEventSourceMac>& aSource, static void NotifyFakeNonMediaKey(
bool aIsKeyPressed) { RefPtr<MediaHardwareKeysEventSourceMac>& aSource, bool aIsKeyPressed) {
int keyData = 0 | ((aIsKeyPressed ? 0xA : 0xB) << 8); int keyData = 0 | ((aIsKeyPressed ? 0xA : 0xB) << 8);
SendFakeEvent(aSource, keyData); SendFakeEvent(aSource, keyData);
} }
static void NotifyFakeMediaControlKey(RefPtr<MediaHardwareKeysEventSourceMac>& aSource, static void NotifyFakeMediaControlKey(
MediaControlKey aEvent, bool aIsKeyPressed) { RefPtr<MediaHardwareKeysEventSourceMac>& aSource, MediaControlKey aEvent,
bool aIsKeyPressed) {
int keyData = 0; int keyData = 0;
if (aEvent == MediaControlKey::Playpause) { if (aEvent == MediaControlKey::Playpause) {
keyData = NX_KEYTYPE_PLAY << 16; keyData = NX_KEYTYPE_PLAY << 16;
@ -51,27 +55,30 @@ static void NotifyFakeMediaControlKey(RefPtr<MediaHardwareKeysEventSourceMac>& a
SendFakeEvent(aSource, keyData); SendFakeEvent(aSource, keyData);
} }
static void NotifyKeyPressedMediaKey(RefPtr<MediaHardwareKeysEventSourceMac>& aSource, static void NotifyKeyPressedMediaKey(
MediaControlKey aEvent) { RefPtr<MediaHardwareKeysEventSourceMac>& aSource, MediaControlKey aEvent) {
NotifyFakeMediaControlKey(aSource, aEvent, true /* key pressed */); NotifyFakeMediaControlKey(aSource, aEvent, true /* key pressed */);
} }
static void NotifyKeyReleasedMediaKeysEvent(RefPtr<MediaHardwareKeysEventSourceMac>& aSource, static void NotifyKeyReleasedMediaKeysEvent(
MediaControlKey aEvent) { RefPtr<MediaHardwareKeysEventSourceMac>& aSource, MediaControlKey aEvent) {
NotifyFakeMediaControlKey(aSource, aEvent, false /* key released */); NotifyFakeMediaControlKey(aSource, aEvent, false /* key released */);
} }
static void NotifyKeyPressedNonMediaKeysEvents(RefPtr<MediaHardwareKeysEventSourceMac>& aSource) { static void NotifyKeyPressedNonMediaKeysEvents(
RefPtr<MediaHardwareKeysEventSourceMac>& aSource) {
NotifyFakeNonMediaKey(aSource, true /* key pressed */); NotifyFakeNonMediaKey(aSource, true /* key pressed */);
} }
static void NotifyKeyReleasedNonMediaKeysEvents(RefPtr<MediaHardwareKeysEventSourceMac>& aSource) { static void NotifyKeyReleasedNonMediaKeysEvents(
RefPtr<MediaHardwareKeysEventSourceMac>& aSource) {
NotifyFakeNonMediaKey(aSource, false /* key released */); NotifyFakeNonMediaKey(aSource, false /* key released */);
} }
TEST(MediaHardwareKeysEventSourceMac, TestKeyPressedMediaKeysEvent) TEST(MediaHardwareKeysEventSourceMac, TestKeyPressedMediaKeysEvent)
{ {
RefPtr<MediaHardwareKeysEventSourceMac> source = new MediaHardwareKeysEventSourceMac(); RefPtr<MediaHardwareKeysEventSourceMac> source =
new MediaHardwareKeysEventSourceMac();
ASSERT_TRUE(source->GetListenersNum() == 0); ASSERT_TRUE(source->GetListenersNum() == 0);
RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest(); RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
@ -94,7 +101,8 @@ TEST(MediaHardwareKeysEventSourceMac, TestKeyPressedMediaKeysEvent)
TEST(MediaHardwareKeysEventSourceMac, TestKeyReleasedMediaKeysEvent) TEST(MediaHardwareKeysEventSourceMac, TestKeyReleasedMediaKeysEvent)
{ {
RefPtr<MediaHardwareKeysEventSourceMac> source = new MediaHardwareKeysEventSourceMac(); RefPtr<MediaHardwareKeysEventSourceMac> source =
new MediaHardwareKeysEventSourceMac();
ASSERT_TRUE(source->GetListenersNum() == 0); ASSERT_TRUE(source->GetListenersNum() == 0);
RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest(); RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
@ -117,7 +125,8 @@ TEST(MediaHardwareKeysEventSourceMac, TestKeyReleasedMediaKeysEvent)
TEST(MediaHardwareKeysEventSourceMac, TestNonMediaKeysEvent) TEST(MediaHardwareKeysEventSourceMac, TestNonMediaKeysEvent)
{ {
RefPtr<MediaHardwareKeysEventSourceMac> source = new MediaHardwareKeysEventSourceMac(); RefPtr<MediaHardwareKeysEventSourceMac> source =
new MediaHardwareKeysEventSourceMac();
ASSERT_TRUE(source->GetListenersNum() == 0); ASSERT_TRUE(source->GetListenersNum() == 0);
RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest(); RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();

View file

@ -123,7 +123,8 @@ TEST(MediaHardwareKeysEventSourceMacMediaCenter, TestMediaCenterPrevNextEvent)
ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Nexttrack)); ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Nexttrack));
MediaCenterEventHandler previousHandler = source->CreatePreviousTrackHandler(); MediaCenterEventHandler previousHandler =
source->CreatePreviousTrackHandler();
previousHandler(nil); previousHandler(nil);
@ -153,9 +154,12 @@ TEST(MediaHardwareKeysEventSourceMacMediaCenter, TestSetMetadata)
// before checking the result. // before checking the result.
PR_Sleep(PR_SecondsToInterval(1)); PR_Sleep(PR_SecondsToInterval(1));
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter]; MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyTitle] isEqualToString:@"MediaPlayback"]); ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyTitle]
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyArtist] isEqualToString:@"Firefox"]); isEqualToString:@"MediaPlayback"]);
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyAlbumTitle] isEqualToString:@"Mozilla"]); ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyArtist]
isEqualToString:@"Firefox"]);
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyAlbumTitle]
isEqualToString:@"Mozilla"]);
source->Close(); source->Close();
PR_Sleep(PR_SecondsToInterval(1)); PR_Sleep(PR_SecondsToInterval(1));

View file

@ -28,11 +28,13 @@ using namespace webrtc;
using namespace videocapturemodule; using namespace videocapturemodule;
static NSArray* camera_presets = @[ static NSArray* camera_presets = @[
AVCaptureSessionPreset352x288, AVCaptureSessionPreset640x480, AVCaptureSessionPreset1280x720 AVCaptureSessionPreset352x288, AVCaptureSessionPreset640x480,
AVCaptureSessionPreset1280x720
]; ];
#define IOS_UNSUPPORTED() \ #define IOS_UNSUPPORTED() \
RTC_LOG(LS_ERROR) << __FUNCTION__ << " is not supported on the iOS platform."; \ RTC_LOG(LS_ERROR) << __FUNCTION__ \
<< " is not supported on the iOS platform."; \
return -1; return -1;
VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo() { VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo() {
@ -60,7 +62,8 @@ int32_t DeviceInfoIos::Init() {
for (NSString* preset in camera_presets) { for (NSString* preset in camera_presets) {
BOOL support = [avDevice supportsAVCaptureSessionPreset:preset]; BOOL support = [avDevice supportsAVCaptureSessionPreset:preset];
if (support) { if (support) {
VideoCaptureCapability capability = [DeviceInfoIosObjC capabilityForPreset:preset]; VideoCaptureCapability capability =
[DeviceInfoIosObjC capabilityForPreset:preset];
capabilityVector.push_back(capability); capabilityVector.push_back(capability);
} }
} }
@ -73,31 +76,36 @@ int32_t DeviceInfoIos::Init() {
} }
std::string deviceIdCopy(deviceId); std::string deviceIdCopy(deviceId);
std::pair<std::string, VideoCaptureCapabilities> mapPair = std::pair<std::string, VideoCaptureCapabilities> mapPair =
std::pair<std::string, VideoCaptureCapabilities>(deviceIdCopy, capabilityVector); std::pair<std::string, VideoCaptureCapabilities>(deviceIdCopy,
capabilityVector);
_capabilitiesMap.insert(mapPair); _capabilitiesMap.insert(mapPair);
} }
return 0; return 0;
} }
uint32_t DeviceInfoIos::NumberOfDevices() { return [DeviceInfoIosObjC captureDeviceCount]; } uint32_t DeviceInfoIos::NumberOfDevices() {
return [DeviceInfoIosObjC captureDeviceCount];
}
int32_t DeviceInfoIos::GetDeviceName(uint32_t deviceNumber, char* deviceNameUTF8, int32_t DeviceInfoIos::GetDeviceName(
uint32_t deviceNameUTF8Length, char* deviceUniqueIdUTF8, uint32_t deviceNumber, char* deviceNameUTF8, uint32_t deviceNameUTF8Length,
uint32_t deviceUniqueIdUTF8Length, char* productUniqueIdUTF8, char* deviceUniqueIdUTF8, uint32_t deviceUniqueIdUTF8Length,
uint32_t productUniqueIdUTF8Length, pid_t* pid) { char* productUniqueIdUTF8, uint32_t productUniqueIdUTF8Length, pid_t* pid) {
if (deviceNumber >= NumberOfDevices()) { if (deviceNumber >= NumberOfDevices()) {
return -1; return -1;
} }
NSString* deviceName = [DeviceInfoIosObjC deviceNameForIndex:deviceNumber]; NSString* deviceName = [DeviceInfoIosObjC deviceNameForIndex:deviceNumber];
NSString* deviceUniqueId = [DeviceInfoIosObjC deviceUniqueIdForIndex:deviceNumber]; NSString* deviceUniqueId =
[DeviceInfoIosObjC deviceUniqueIdForIndex:deviceNumber];
strncpy(deviceNameUTF8, [deviceName UTF8String], deviceNameUTF8Length); strncpy(deviceNameUTF8, [deviceName UTF8String], deviceNameUTF8Length);
deviceNameUTF8[deviceNameUTF8Length - 1] = '\0'; deviceNameUTF8[deviceNameUTF8Length - 1] = '\0';
strncpy(deviceUniqueIdUTF8, deviceUniqueId.UTF8String, deviceUniqueIdUTF8Length); strncpy(deviceUniqueIdUTF8, deviceUniqueId.UTF8String,
deviceUniqueIdUTF8Length);
deviceUniqueIdUTF8[deviceUniqueIdUTF8Length - 1] = '\0'; deviceUniqueIdUTF8[deviceUniqueIdUTF8Length - 1] = '\0';
if (productUniqueIdUTF8) { if (productUniqueIdUTF8) {
@ -140,14 +148,14 @@ int32_t DeviceInfoIos::GetCapability(const char* deviceUniqueIdUTF8,
return -1; return -1;
} }
int32_t DeviceInfoIos::DisplayCaptureSettingsDialogBox(const char* deviceUniqueIdUTF8, int32_t DeviceInfoIos::DisplayCaptureSettingsDialogBox(
const char* dialogTitleUTF8, const char* deviceUniqueIdUTF8, const char* dialogTitleUTF8,
void* parentWindow, uint32_t positionX, void* parentWindow, uint32_t positionX, uint32_t positionY) {
uint32_t positionY) {
IOS_UNSUPPORTED(); IOS_UNSUPPORTED();
} }
int32_t DeviceInfoIos::GetOrientation(const char* deviceUniqueIdUTF8, VideoRotation& orientation) { int32_t DeviceInfoIos::GetOrientation(const char* deviceUniqueIdUTF8,
VideoRotation& orientation) {
if (strcmp(deviceUniqueIdUTF8, "Front Camera") == 0) { if (strcmp(deviceUniqueIdUTF8, "Front Camera") == 0) {
orientation = kVideoRotation_0; orientation = kVideoRotation_0;
} else { } else {

View file

@ -17,12 +17,14 @@
namespace webrtc::videocapturemodule { namespace webrtc::videocapturemodule {
/* static */ /* static */
int32_t DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(Float64 aRate) { int32_t DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(
Float64 aRate) {
return static_cast<int32_t>(aRate); return static_cast<int32_t>(aRate);
} }
/* static */ /* static */
webrtc::VideoType DeviceInfoAvFoundation::ConvertFourCCToVideoType(FourCharCode aCode) { webrtc::VideoType DeviceInfoAvFoundation::ConvertFourCCToVideoType(
FourCharCode aCode) {
switch (aCode) { switch (aCode) {
case kCVPixelFormatType_420YpCbCr8Planar: case kCVPixelFormatType_420YpCbCr8Planar:
case kCVPixelFormatType_420YpCbCr8PlanarFullRange: case kCVPixelFormatType_420YpCbCr8PlanarFullRange:
@ -57,11 +59,14 @@ webrtc::VideoType DeviceInfoAvFoundation::ConvertFourCCToVideoType(FourCharCode
} }
DeviceInfoAvFoundation::DeviceInfoAvFoundation() DeviceInfoAvFoundation::DeviceInfoAvFoundation()
: mInvalidateCapabilities(false), mDeviceChangeCaptureInfo([[DeviceInfoIosObjC alloc] init]) { : mInvalidateCapabilities(false),
mDeviceChangeCaptureInfo([[DeviceInfoIosObjC alloc] init]) {
[mDeviceChangeCaptureInfo registerOwner:this]; [mDeviceChangeCaptureInfo registerOwner:this];
} }
DeviceInfoAvFoundation::~DeviceInfoAvFoundation() { [mDeviceChangeCaptureInfo registerOwner:nil]; } DeviceInfoAvFoundation::~DeviceInfoAvFoundation() {
[mDeviceChangeCaptureInfo registerOwner:nil];
}
void DeviceInfoAvFoundation::DeviceChange() { void DeviceInfoAvFoundation::DeviceChange() {
mInvalidateCapabilities = true; mInvalidateCapabilities = true;
@ -74,12 +79,11 @@ uint32_t DeviceInfoAvFoundation::NumberOfDevices() {
return mDevicesAndCapabilities.size(); return mDevicesAndCapabilities.size();
} }
int32_t DeviceInfoAvFoundation::GetDeviceName(uint32_t aDeviceNumber, char* aDeviceNameUTF8, int32_t DeviceInfoAvFoundation::GetDeviceName(
uint32_t aDeviceNameLength, char* aDeviceUniqueIdUTF8, uint32_t aDeviceNumber, char* aDeviceNameUTF8, uint32_t aDeviceNameLength,
uint32_t aDeviceUniqueIdUTF8Length, char* aDeviceUniqueIdUTF8, uint32_t aDeviceUniqueIdUTF8Length,
char* /* aProductUniqueIdUTF8 */, char* /* aProductUniqueIdUTF8 */, uint32_t /* aProductUniqueIdUTF8Length */,
uint32_t /* aProductUniqueIdUTF8Length */, pid_t* /* aPid */) {
pid_t* /* aPid */) {
RTC_DCHECK_RUN_ON(&mChecker); RTC_DCHECK_RUN_ON(&mChecker);
// Don't EnsureCapabilitiesMap() here, since: // Don't EnsureCapabilitiesMap() here, since:
// 1) That might invalidate the capabilities map // 1) That might invalidate the capabilities map
@ -100,7 +104,8 @@ int32_t DeviceInfoAvFoundation::GetDeviceName(uint32_t aDeviceNumber, char* aDev
return 0; return 0;
} }
int32_t DeviceInfoAvFoundation::NumberOfCapabilities(const char* aDeviceUniqueIdUTF8) { int32_t DeviceInfoAvFoundation::NumberOfCapabilities(
const char* aDeviceUniqueIdUTF8) {
RTC_DCHECK_RUN_ON(&mChecker); RTC_DCHECK_RUN_ON(&mChecker);
std::string deviceUniqueId(aDeviceUniqueIdUTF8); std::string deviceUniqueId(aDeviceUniqueIdUTF8);
@ -113,9 +118,9 @@ int32_t DeviceInfoAvFoundation::NumberOfCapabilities(const char* aDeviceUniqueId
return static_cast<int32_t>(capabilities.size()); return static_cast<int32_t>(capabilities.size());
} }
int32_t DeviceInfoAvFoundation::GetCapability(const char* aDeviceUniqueIdUTF8, int32_t DeviceInfoAvFoundation::GetCapability(
const uint32_t aDeviceCapabilityNumber, const char* aDeviceUniqueIdUTF8, const uint32_t aDeviceCapabilityNumber,
VideoCaptureCapability& aCapability) { VideoCaptureCapability& aCapability) {
RTC_DCHECK_RUN_ON(&mChecker); RTC_DCHECK_RUN_ON(&mChecker);
std::string deviceUniqueId(aDeviceUniqueIdUTF8); std::string deviceUniqueId(aDeviceUniqueIdUTF8);
@ -133,7 +138,8 @@ int32_t DeviceInfoAvFoundation::GetCapability(const char* aDeviceUniqueIdUTF8,
return 0; return 0;
} }
int32_t DeviceInfoAvFoundation::CreateCapabilityMap(const char* aDeviceUniqueIdUTF8) { int32_t DeviceInfoAvFoundation::CreateCapabilityMap(
const char* aDeviceUniqueIdUTF8) {
RTC_DCHECK_RUN_ON(&mChecker); RTC_DCHECK_RUN_ON(&mChecker);
const size_t deviceUniqueIdUTF8Length = strlen(aDeviceUniqueIdUTF8); const size_t deviceUniqueIdUTF8Length = strlen(aDeviceUniqueIdUTF8);
@ -141,7 +147,8 @@ int32_t DeviceInfoAvFoundation::CreateCapabilityMap(const char* aDeviceUniqueIdU
RTC_LOG(LS_INFO) << "Device name too long"; RTC_LOG(LS_INFO) << "Device name too long";
return -1; return -1;
} }
RTC_LOG(LS_INFO) << "CreateCapabilityMap called for device " << aDeviceUniqueIdUTF8; RTC_LOG(LS_INFO) << "CreateCapabilityMap called for device "
<< aDeviceUniqueIdUTF8;
std::string deviceUniqueId(aDeviceUniqueIdUTF8); std::string deviceUniqueId(aDeviceUniqueIdUTF8);
const auto* tup = FindDeviceAndCapabilities(deviceUniqueId); const auto* tup = FindDeviceAndCapabilities(deviceUniqueId);
if (!tup) { if (!tup) {
@ -151,16 +158,18 @@ int32_t DeviceInfoAvFoundation::CreateCapabilityMap(const char* aDeviceUniqueIdU
// Store the new used device name // Store the new used device name
_lastUsedDeviceNameLength = deviceUniqueIdUTF8Length; _lastUsedDeviceNameLength = deviceUniqueIdUTF8Length;
_lastUsedDeviceName = _lastUsedDeviceName = static_cast<char*>(
static_cast<char*>(realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1)); realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1));
memcpy(_lastUsedDeviceName, aDeviceUniqueIdUTF8, _lastUsedDeviceNameLength + 1); memcpy(_lastUsedDeviceName, aDeviceUniqueIdUTF8,
_lastUsedDeviceNameLength + 1);
const auto& [_, __, capabilities] = *tup; const auto& [_, __, capabilities] = *tup;
_captureCapabilities = capabilities; _captureCapabilities = capabilities;
return static_cast<int32_t>(_captureCapabilities.size()); return static_cast<int32_t>(_captureCapabilities.size());
} }
auto DeviceInfoAvFoundation::FindDeviceAndCapabilities(const std::string& aDeviceUniqueId) const auto DeviceInfoAvFoundation::FindDeviceAndCapabilities(
const std::string& aDeviceUniqueId) const
-> const std::tuple<std::string, std::string, VideoCaptureCapabilities>* { -> const std::tuple<std::string, std::string, VideoCaptureCapabilities>* {
RTC_DCHECK_RUN_ON(&mChecker); RTC_DCHECK_RUN_ON(&mChecker);
for (const auto& tup : mDevicesAndCapabilities) { for (const auto& tup : mDevicesAndCapabilities) {
@ -185,13 +194,14 @@ void DeviceInfoAvFoundation::EnsureCapabilitiesMap() {
for (AVCaptureDevice* device in [RTCCameraVideoCapturer captureDevices]) { for (AVCaptureDevice* device in [RTCCameraVideoCapturer captureDevices]) {
std::string uniqueId = [NSString stdStringForString:device.uniqueID]; std::string uniqueId = [NSString stdStringForString:device.uniqueID];
std::string name = [NSString stdStringForString:device.localizedName]; std::string name = [NSString stdStringForString:device.localizedName];
auto& [_, __, capabilities] = auto& [_, __, capabilities] = mDevicesAndCapabilities.emplace_back(
mDevicesAndCapabilities.emplace_back(uniqueId, name, VideoCaptureCapabilities()); uniqueId, name, VideoCaptureCapabilities());
for (AVCaptureDeviceFormat* format in for (AVCaptureDeviceFormat* format in
[RTCCameraVideoCapturer supportedFormatsForDevice:device]) { [RTCCameraVideoCapturer supportedFormatsForDevice:device]) {
VideoCaptureCapability cap; VideoCaptureCapability cap;
FourCharCode fourcc = CMFormatDescriptionGetMediaSubType(format.formatDescription); FourCharCode fourcc =
CMFormatDescriptionGetMediaSubType(format.formatDescription);
cap.videoType = ConvertFourCCToVideoType(fourcc); cap.videoType = ConvertFourCCToVideoType(fourcc);
CMVideoDimensions dimensions = CMVideoDimensions dimensions =
CMVideoFormatDescriptionGetDimensions(format.formatDescription); CMVideoFormatDescriptionGetDimensions(format.formatDescription);

View file

@ -34,7 +34,8 @@
if (!_owner && owner) { if (!_owner && owner) {
[self configureObservers]; [self configureObservers];
} else if (_owner && !owner) { } else if (_owner && !owner) {
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter]; NSNotificationCenter* notificationCenter =
[NSNotificationCenter defaultCenter];
for (id observer in _observers) { for (id observer in _observers) {
[notificationCenter removeObserver:observer]; [notificationCenter removeObserver:observer];
} }
@ -47,7 +48,8 @@
+ (int)captureDeviceCount { + (int)captureDeviceCount {
int cnt = 0; int cnt = 0;
@try { @try {
for (AVCaptureDevice* device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) { for (AVCaptureDevice* device in
[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
if ([device isSuspended]) { if ([device isSuspended]) {
continue; continue;
} }
@ -62,7 +64,8 @@
+ (AVCaptureDevice*)captureDeviceForIndex:(int)index { + (AVCaptureDevice*)captureDeviceForIndex:(int)index {
int cnt = 0; int cnt = 0;
@try { @try {
for (AVCaptureDevice* device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) { for (AVCaptureDevice* device in
[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
if ([device isSuspended]) { if ([device isSuspended]) {
continue; continue;
} }
@ -79,7 +82,8 @@
} }
+ (AVCaptureDevice*)captureDeviceForUniqueId:(NSString*)uniqueId { + (AVCaptureDevice*)captureDeviceForUniqueId:(NSString*)uniqueId {
for (AVCaptureDevice* device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) { for (AVCaptureDevice* device in
[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
if ([device isSuspended]) { if ([device isSuspended]) {
continue; continue;
} }
@ -133,34 +137,36 @@
- (void)configureObservers { - (void)configureObservers {
// register device connected / disconnected event // register device connected / disconnected event
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter]; NSNotificationCenter* notificationCenter =
[NSNotificationCenter defaultCenter];
id deviceWasConnectedObserver = id deviceWasConnectedObserver = [notificationCenter
[notificationCenter addObserverForName:AVCaptureDeviceWasConnectedNotification addObserverForName:AVCaptureDeviceWasConnectedNotification
object:nil object:nil
queue:[NSOperationQueue mainQueue] queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification* note) { usingBlock:^(NSNotification* note) {
[_lock lock]; [_lock lock];
AVCaptureDevice* device = [note object]; AVCaptureDevice* device = [note object];
BOOL isVideoDevice = [device hasMediaType:AVMediaTypeVideo]; BOOL isVideoDevice = [device hasMediaType:AVMediaTypeVideo];
if (isVideoDevice && _owner) _owner->DeviceChange(); if (isVideoDevice && _owner) _owner->DeviceChange();
[_lock unlock]; [_lock unlock];
}]; }];
id deviceWasDisconnectedObserver = id deviceWasDisconnectedObserver = [notificationCenter
[notificationCenter addObserverForName:AVCaptureDeviceWasDisconnectedNotification addObserverForName:AVCaptureDeviceWasDisconnectedNotification
object:nil object:nil
queue:[NSOperationQueue mainQueue] queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification* note) { usingBlock:^(NSNotification* note) {
[_lock lock]; [_lock lock];
AVCaptureDevice* device = [note object]; AVCaptureDevice* device = [note object];
BOOL isVideoDevice = [device hasMediaType:AVMediaTypeVideo]; BOOL isVideoDevice = [device hasMediaType:AVMediaTypeVideo];
if (isVideoDevice && _owner) _owner->DeviceChange(); if (isVideoDevice && _owner) _owner->DeviceChange();
[_lock unlock]; [_lock unlock];
}]; }];
_observers = [[NSArray alloc] _observers =
initWithObjects:deviceWasConnectedObserver, deviceWasDisconnectedObserver, nil]; [[NSArray alloc] initWithObjects:deviceWasConnectedObserver,
deviceWasDisconnectedObserver, nil];
} }
@end @end

View file

@ -57,18 +57,22 @@ using namespace webrtc::videocapturemodule;
} }
// create and configure a new output (using callbacks) // create and configure a new output (using callbacks)
AVCaptureVideoDataOutput* captureOutput = [[AVCaptureVideoDataOutput alloc] init]; AVCaptureVideoDataOutput* captureOutput =
[[AVCaptureVideoDataOutput alloc] init];
NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey; NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
NSNumber* val = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_422YpCbCr8]; NSNumber* val =
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:val forKey:key]; [NSNumber numberWithUnsignedInt:kCVPixelFormatType_422YpCbCr8];
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:val
forKey:key];
captureOutput.videoSettings = videoSettings; captureOutput.videoSettings = videoSettings;
// add new output // add new output
if ([_captureSession canAddOutput:captureOutput]) { if ([_captureSession canAddOutput:captureOutput]) {
[_captureSession addOutput:captureOutput]; [_captureSession addOutput:captureOutput];
} else { } else {
RTC_LOG(LS_ERROR) << __FUNCTION__ << ": Could not add output to AVCaptureSession"; RTC_LOG(LS_ERROR) << __FUNCTION__
<< ": Could not add output to AVCaptureSession";
} }
#ifdef WEBRTC_IOS #ifdef WEBRTC_IOS
@ -86,12 +90,14 @@ using namespace webrtc::videocapturemodule;
#endif #endif
} }
// Create a serial queue on which video capture will run. By setting the target, // Create a serial queue on which video capture will run. By setting the
// blocks should still run on DISPATH_QUEUE_PRIORITY_DEFAULT rather than creating // target, blocks should still run on DISPATH_QUEUE_PRIORITY_DEFAULT rather
// a new thread. // than creating a new thread.
_frameQueue = dispatch_queue_create("org.webrtc.videocapture", DISPATCH_QUEUE_SERIAL); _frameQueue =
dispatch_set_target_queue(_frameQueue, dispatch_queue_create("org.webrtc.videocapture", DISPATCH_QUEUE_SERIAL);
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); dispatch_set_target_queue(
_frameQueue,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
return self; return self;
} }
@ -144,11 +150,13 @@ using namespace webrtc::videocapturemodule;
if (capability.width > 1280 || capability.height > 720) { if (capability.width > 1280 || capability.height > 720) {
return NO; return NO;
} }
} else if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) { } else if ([_captureSession
canSetSessionPreset:AVCaptureSessionPreset640x480]) {
if (capability.width > 640 || capability.height > 480) { if (capability.width > 640 || capability.height > 480) {
return NO; return NO;
} }
} else if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset352x288]) { } else if ([_captureSession
canSetSessionPreset:AVCaptureSessionPreset352x288]) {
if (capability.width > 352 || capability.height > 288) { if (capability.width > 352 || capability.height > 288) {
return NO; return NO;
} }
@ -175,8 +183,10 @@ using namespace webrtc::videocapturemodule;
return [[_captureSession outputs] firstObject]; return [[_captureSession outputs] firstObject];
} }
- (void)startCaptureInBackgroundWithOutput:(AVCaptureVideoDataOutput*)currentOutput { - (void)startCaptureInBackgroundWithOutput:
NSString* captureQuality = [NSString stringWithString:AVCaptureSessionPresetLow]; (AVCaptureVideoDataOutput*)currentOutput {
NSString* captureQuality =
[NSString stringWithString:AVCaptureSessionPresetLow];
if (_capability.width >= 1280 || _capability.height >= 720) { if (_capability.width >= 1280 || _capability.height >= 720) {
captureQuality = [NSString stringWithString:AVCaptureSessionPreset1280x720]; captureQuality = [NSString stringWithString:AVCaptureSessionPreset1280x720];
} else if (_capability.width >= 640 || _capability.height >= 480) { } else if (_capability.width >= 640 || _capability.height >= 480) {
@ -214,7 +224,8 @@ using namespace webrtc::videocapturemodule;
_connection.videoOrientation = AVCaptureVideoOrientationPortrait; _connection.videoOrientation = AVCaptureVideoOrientationPortrait;
break; break;
case UIDeviceOrientationPortraitUpsideDown: case UIDeviceOrientationPortraitUpsideDown:
_connection.videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown; _connection.videoOrientation =
AVCaptureVideoOrientationPortraitUpsideDown;
break; break;
case UIDeviceOrientationLandscapeLeft: case UIDeviceOrientationLandscapeLeft:
_connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight; _connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
@ -236,7 +247,8 @@ using namespace webrtc::videocapturemodule;
- (void)onVideoError:(NSNotification*)notification { - (void)onVideoError:(NSNotification*)notification {
NSLog(@"onVideoError: %@", notification); NSLog(@"onVideoError: %@", notification);
// TODO(sjlee): make the specific error handling with this notification. // TODO(sjlee): make the specific error handling with this notification.
RTC_LOG(LS_ERROR) << __FUNCTION__ << ": [AVCaptureSession startRunning] error."; RTC_LOG(LS_ERROR) << __FUNCTION__
<< ": [AVCaptureSession startRunning] error.";
} }
- (BOOL)stopCapture { - (BOOL)stopCapture {
@ -265,7 +277,8 @@ using namespace webrtc::videocapturemodule;
NSArray* currentInputs = [_captureSession inputs]; NSArray* currentInputs = [_captureSession inputs];
// remove current input // remove current input
if ([currentInputs count] > 0) { if ([currentInputs count] > 0) {
AVCaptureInput* currentInput = (AVCaptureInput*)[currentInputs objectAtIndex:0]; AVCaptureInput* currentInput =
(AVCaptureInput*)[currentInputs objectAtIndex:0];
[_captureSession removeInput:currentInput]; [_captureSession removeInput:currentInput];
} }
@ -277,7 +290,8 @@ using namespace webrtc::videocapturemodule;
return NO; return NO;
} }
AVCaptureDevice* captureDevice = [DeviceInfoIosObjC captureDeviceForUniqueId:uniqueId]; AVCaptureDevice* captureDevice =
[DeviceInfoIosObjC captureDeviceForUniqueId:uniqueId];
if (!captureDevice) { if (!captureDevice) {
return NO; return NO;
@ -285,13 +299,15 @@ using namespace webrtc::videocapturemodule;
// now create capture session input out of AVCaptureDevice // now create capture session input out of AVCaptureDevice
NSError* deviceError = nil; NSError* deviceError = nil;
AVCaptureDeviceInput* newCaptureInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice AVCaptureDeviceInput* newCaptureInput =
error:&deviceError]; [AVCaptureDeviceInput deviceInputWithDevice:captureDevice
error:&deviceError];
if (!newCaptureInput) { if (!newCaptureInput) {
const char* errorMessage = [[deviceError localizedDescription] UTF8String]; const char* errorMessage = [[deviceError localizedDescription] UTF8String];
RTC_LOG(LS_ERROR) << __FUNCTION__ << ": deviceInputWithDevice error:" << errorMessage; RTC_LOG(LS_ERROR) << __FUNCTION__
<< ": deviceInputWithDevice error:" << errorMessage;
return NO; return NO;
} }

View file

@ -23,7 +23,8 @@ using namespace mozilla;
using namespace webrtc; using namespace webrtc;
using namespace videocapturemodule; using namespace videocapturemodule;
rtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create(const char* deviceUniqueIdUTF8) { rtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create(
const char* deviceUniqueIdUTF8) {
if (StaticPrefs::media_getusermedia_camera_macavf_enabled_AtStartup()) { if (StaticPrefs::media_getusermedia_camera_macavf_enabled_AtStartup()) {
return VideoCaptureAvFoundation::Create(deviceUniqueIdUTF8); return VideoCaptureAvFoundation::Create(deviceUniqueIdUTF8);
} }
@ -44,12 +45,14 @@ VideoCaptureIos::~VideoCaptureIos() {
} }
} }
rtc::scoped_refptr<VideoCaptureModule> VideoCaptureIos::Create(const char* deviceUniqueIdUTF8) { rtc::scoped_refptr<VideoCaptureModule> VideoCaptureIos::Create(
const char* deviceUniqueIdUTF8) {
if (!deviceUniqueIdUTF8[0]) { if (!deviceUniqueIdUTF8[0]) {
return NULL; return NULL;
} }
rtc::scoped_refptr<VideoCaptureIos> capture_module(new rtc::RefCountedObject<VideoCaptureIos>()); rtc::scoped_refptr<VideoCaptureIos> capture_module(
new rtc::RefCountedObject<VideoCaptureIos>());
const int32_t name_length = strlen(deviceUniqueIdUTF8); const int32_t name_length = strlen(deviceUniqueIdUTF8);
if (name_length >= kVideoCaptureUniqueNameLength) return nullptr; if (name_length >= kVideoCaptureUniqueNameLength) return nullptr;
@ -65,14 +68,16 @@ rtc::scoped_refptr<VideoCaptureModule> VideoCaptureIos::Create(const char* devic
} }
if (![capture_module->capture_device_ if (![capture_module->capture_device_
setCaptureDeviceByUniqueId:[[NSString alloc] initWithCString:deviceUniqueIdUTF8 setCaptureDeviceByUniqueId:
encoding:NSUTF8StringEncoding]]) { [[NSString alloc] initWithCString:deviceUniqueIdUTF8
encoding:NSUTF8StringEncoding]]) {
return nullptr; return nullptr;
} }
return capture_module; return capture_module;
} }
int32_t VideoCaptureIos::StartCapture(const VideoCaptureCapability& capability) { int32_t VideoCaptureIos::StartCapture(
const VideoCaptureCapability& capability) {
capability_ = capability; capability_ = capability;
if (![capture_device_ startCaptureWithCapability:capability]) { if (![capture_device_ startCaptureWithCapability:capability]) {

View file

@ -38,30 +38,37 @@ webrtc::VideoRotation ToNativeRotation(RTCVideoRotation aRotation) {
case RTCVideoRotation_270: case RTCVideoRotation_270:
return webrtc::kVideoRotation_270; return webrtc::kVideoRotation_270;
default: default:
MOZ_CRASH_UNSAFE_PRINTF("Unexpected rotation %d", static_cast<int>(aRotation)); MOZ_CRASH_UNSAFE_PRINTF("Unexpected rotation %d",
static_cast<int>(aRotation));
return webrtc::kVideoRotation_0; return webrtc::kVideoRotation_0;
} }
} }
AVCaptureDeviceFormat* _Nullable FindFormat(AVCaptureDevice* _Nonnull aDevice, AVCaptureDeviceFormat* _Nullable FindFormat(
webrtc::VideoCaptureCapability aCapability) { AVCaptureDevice* _Nonnull aDevice,
webrtc::VideoCaptureCapability aCapability) {
for (AVCaptureDeviceFormat* format in [aDevice formats]) { for (AVCaptureDeviceFormat* format in [aDevice formats]) {
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription); CMVideoDimensions dimensions =
CMVideoFormatDescriptionGetDimensions(format.formatDescription);
if (dimensions.width != aCapability.width) { if (dimensions.width != aCapability.width) {
continue; continue;
} }
if (dimensions.height != aCapability.height) { if (dimensions.height != aCapability.height) {
continue; continue;
} }
FourCharCode fourcc = CMFormatDescriptionGetMediaSubType(format.formatDescription); FourCharCode fourcc =
if (aCapability.videoType != DeviceInfoAvFoundation::ConvertFourCCToVideoType(fourcc)) { CMFormatDescriptionGetMediaSubType(format.formatDescription);
if (aCapability.videoType !=
DeviceInfoAvFoundation::ConvertFourCCToVideoType(fourcc)) {
continue; continue;
} }
if ([format.videoSupportedFrameRateRanges if ([format.videoSupportedFrameRateRanges
indexOfObjectPassingTest:^BOOL(AVFrameRateRange* _Nonnull obj, NSUInteger idx, indexOfObjectPassingTest:^BOOL(AVFrameRateRange* _Nonnull obj,
NSUInteger idx,
BOOL* _Nonnull stop) { BOOL* _Nonnull stop) {
return static_cast<BOOL>(DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS( return static_cast<BOOL>(
obj.maxFrameRate) == aCapability.maxFPS); DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(
obj.maxFrameRate) == aCapability.maxFPS);
}] == NSNotFound) { }] == NSNotFound) {
continue; continue;
} }
@ -73,7 +80,8 @@ AVCaptureDeviceFormat* _Nullable FindFormat(AVCaptureDevice* _Nonnull aDevice,
} // namespace } // namespace
@implementation VideoCaptureAdapter @implementation VideoCaptureAdapter
- (void)setCapturer:(webrtc::videocapturemodule::VideoCaptureAvFoundation* _Nullable)capturer { - (void)setCapturer:
(webrtc::videocapturemodule::VideoCaptureAvFoundation* _Nullable)capturer {
webrtc::MutexLock lock(&_mutex); webrtc::MutexLock lock(&_mutex);
_capturer = capturer; _capturer = capturer;
} }
@ -91,10 +99,12 @@ AVCaptureDeviceFormat* _Nullable FindFormat(AVCaptureDevice* _Nonnull aDevice,
@end @end
namespace webrtc::videocapturemodule { namespace webrtc::videocapturemodule {
VideoCaptureAvFoundation::VideoCaptureAvFoundation(AVCaptureDevice* _Nonnull aDevice) VideoCaptureAvFoundation::VideoCaptureAvFoundation(
AVCaptureDevice* _Nonnull aDevice)
: mDevice(aDevice), : mDevice(aDevice),
mAdapter([[VideoCaptureAdapter alloc] init]), mAdapter([[VideoCaptureAdapter alloc] init]),
mCapturer([[RTC_OBJC_TYPE(RTCCameraVideoCapturer) alloc] initWithDelegate:mAdapter]), mCapturer([[RTC_OBJC_TYPE(RTCCameraVideoCapturer) alloc]
initWithDelegate:mAdapter]),
mCallbackThreadId() { mCallbackThreadId() {
const char* uniqueId = [[aDevice uniqueID] UTF8String]; const char* uniqueId = [[aDevice uniqueID] UTF8String];
size_t len = strlen(uniqueId); size_t len = strlen(uniqueId);
@ -123,7 +133,8 @@ rtc::scoped_refptr<VideoCaptureModule> VideoCaptureAvFoundation::Create(
return nullptr; return nullptr;
} }
int32_t VideoCaptureAvFoundation::StartCapture(const VideoCaptureCapability& aCapability) { int32_t VideoCaptureAvFoundation::StartCapture(
const VideoCaptureCapability& aCapability) {
RTC_DCHECK_RUN_ON(&mChecker); RTC_DCHECK_RUN_ON(&mChecker);
AVCaptureDeviceFormat* format = FindFormat(mDevice, aCapability); AVCaptureDeviceFormat* format = FindFormat(mDevice, aCapability);
if (!format) { if (!format) {
@ -133,7 +144,8 @@ int32_t VideoCaptureAvFoundation::StartCapture(const VideoCaptureCapability& aCa
{ {
MutexLock lock(&api_lock_); MutexLock lock(&api_lock_);
if (mCapability) { if (mCapability) {
if (mCapability->width == aCapability.width && mCapability->height == aCapability.height && if (mCapability->width == aCapability.width &&
mCapability->height == aCapability.height &&
mCapability->maxFPS == aCapability.maxFPS && mCapability->maxFPS == aCapability.maxFPS &&
mCapability->videoType == aCapability.videoType) { mCapability->videoType == aCapability.videoType) {
return 0; return 0;
@ -250,28 +262,33 @@ bool VideoCaptureAvFoundation::CaptureStarted() {
return mCapability.isSome(); return mCapability.isSome();
} }
int32_t VideoCaptureAvFoundation::CaptureSettings(VideoCaptureCapability& aSettings) { int32_t VideoCaptureAvFoundation::CaptureSettings(
VideoCaptureCapability& aSettings) {
MOZ_CRASH("Unexpected call"); MOZ_CRASH("Unexpected call");
return -1; return -1;
} }
int32_t VideoCaptureAvFoundation::OnFrame(__strong RTCVideoFrame* _Nonnull aFrame) { int32_t VideoCaptureAvFoundation::OnFrame(
__strong RTCVideoFrame* _Nonnull aFrame) {
MaybeRegisterCallbackThread(); MaybeRegisterCallbackThread();
if (MutexLock lock(&api_lock_); MOZ_LIKELY(mTrackingId)) { if (MutexLock lock(&api_lock_); MOZ_LIKELY(mTrackingId)) {
mCaptureRecorder.Start(0, "VideoCaptureAVFoundation"_ns, *mTrackingId, aFrame.width, mCaptureRecorder.Start(
aFrame.height, mImageType.valueOr(CaptureStage::ImageType::Unknown)); 0, "VideoCaptureAVFoundation"_ns, *mTrackingId, aFrame.width,
aFrame.height, mImageType.valueOr(CaptureStage::ImageType::Unknown));
if (mCapability && mCapability->videoType != webrtc::VideoType::kI420) { if (mCapability && mCapability->videoType != webrtc::VideoType::kI420) {
mConversionRecorder.Start(0, "VideoCaptureAVFoundation"_ns, *mTrackingId, aFrame.width, mConversionRecorder.Start(0, "VideoCaptureAVFoundation"_ns, *mTrackingId,
aFrame.height); aFrame.width, aFrame.height);
} }
} }
const int64_t timestamp_us = aFrame.timeStampNs / rtc::kNumNanosecsPerMicrosec; const int64_t timestamp_us =
aFrame.timeStampNs / rtc::kNumNanosecsPerMicrosec;
RTCI420Buffer* buffer = [aFrame.buffer toI420]; RTCI420Buffer* buffer = [aFrame.buffer toI420];
mConversionRecorder.Record(0); mConversionRecorder.Record(0);
// Accessing the (intended-to-be-private) native buffer directly is hacky but lets us skip two // Accessing the (intended-to-be-private) native buffer directly is hacky but
// copies // lets us skip two copies
rtc::scoped_refptr<webrtc::I420BufferInterface> nativeBuffer = buffer.nativeI420Buffer; rtc::scoped_refptr<webrtc::I420BufferInterface> nativeBuffer =
buffer.nativeI420Buffer;
auto frame = webrtc::VideoFrame::Builder() auto frame = webrtc::VideoFrame::Builder()
.set_video_frame_buffer(nativeBuffer) .set_video_frame_buffer(nativeBuffer)
.set_rotation(ToNativeRotation(aFrame.rotation)) .set_rotation(ToNativeRotation(aFrame.rotation))
@ -288,8 +305,8 @@ void VideoCaptureAvFoundation::SetTrackingId(uint32_t aTrackingIdProcId) {
RTC_DCHECK_RUN_ON(&mChecker); RTC_DCHECK_RUN_ON(&mChecker);
MutexLock lock(&api_lock_); MutexLock lock(&api_lock_);
if (NS_WARN_IF(mTrackingId.isSome())) { if (NS_WARN_IF(mTrackingId.isSome())) {
// This capture instance must be shared across multiple camera requests. For now ignore other // This capture instance must be shared across multiple camera requests. For
// requests than the first. // now ignore other requests than the first.
return; return;
} }
mTrackingId.emplace(TrackingId::Source::Camera, aTrackingIdProcId); mTrackingId.emplace(TrackingId::Source::Camera, aTrackingIdProcId);
@ -301,6 +318,7 @@ void VideoCaptureAvFoundation::MaybeRegisterCallbackThread() {
return; return;
} }
mCallbackThreadId = id; mCallbackThreadId = id;
CallbackThreadRegistry::Get()->Register(mCallbackThreadId, "VideoCaptureAVFoundationCallback"); CallbackThreadRegistry::Get()->Register(mCallbackThreadId,
"VideoCaptureAVFoundationCallback");
} }
} // namespace webrtc::videocapturemodule } // namespace webrtc::videocapturemodule

View file

@ -1,4 +1,5 @@
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset:
* 2 -*- */
/* vim: set ts=2 sw=2 et tw=80: */ /* vim: set ts=2 sw=2 et tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public /* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -37,7 +38,8 @@ class SpeechTaskCallback final : public nsISpeechTaskCallback {
const nsTArray<size_t>& aOffsets); const nsTArray<size_t>& aOffsets);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SpeechTaskCallback, nsISpeechTaskCallback) NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SpeechTaskCallback,
nsISpeechTaskCallback)
NS_DECL_NSISPEECHTASKCALLBACK NS_DECL_NSISPEECHTASKCALLBACK
@ -79,7 +81,8 @@ class SpeechTaskCallback final : public nsISpeechTaskCallback {
mCallback->OnWillSpeakWord(aRange.location, aRange.length); mCallback->OnWillSpeakWord(aRange.location, aRange.length);
} }
- (void)speechSynthesizer:(NSSpeechSynthesizer*)aSender didFinishSpeaking:(BOOL)aFinishedSpeaking { - (void)speechSynthesizer:(NSSpeechSynthesizer*)aSender
didFinishSpeaking:(BOOL)aFinishedSpeaking {
mCallback->OnDidFinishSpeaking(); mCallback->OnDidFinishSpeaking();
} }
@ -101,9 +104,13 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechTaskCallback) NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechTaskCallback)
NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechTaskCallback) NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechTaskCallback)
SpeechTaskCallback::SpeechTaskCallback(nsISpeechTask* aTask, NSSpeechSynthesizer* aSynth, SpeechTaskCallback::SpeechTaskCallback(nsISpeechTask* aTask,
NSSpeechSynthesizer* aSynth,
const nsTArray<size_t>& aOffsets) const nsTArray<size_t>& aOffsets)
: mTask(aTask), mSpeechSynthesizer(aSynth), mCurrentIndex(0), mOffsets(aOffsets.Clone()) { : mTask(aTask),
mSpeechSynthesizer(aSynth),
mCurrentIndex(0),
mOffsets(aOffsets.Clone()) {
mDelegate = [[SpeechDelegate alloc] initWithCallback:this]; mDelegate = [[SpeechDelegate alloc] initWithCallback:this];
[mSpeechSynthesizer setDelegate:mDelegate]; [mSpeechSynthesizer setDelegate:mDelegate];
mStartingTime = TimeStamp::Now(); mStartingTime = TimeStamp::Now();
@ -179,7 +186,8 @@ void SpeechTaskCallback::OnWillSpeakWord(uint32_t aIndex, uint32_t aLength) {
if (!mTask) { if (!mTask) {
return; return;
} }
mTask->DispatchBoundary(u"word"_ns, GetTimeDurationFromStart(), mCurrentIndex, aLength, 1); mTask->DispatchBoundary(u"word"_ns, GetTimeDurationFromStart(), mCurrentIndex,
aLength, 1);
} }
void SpeechTaskCallback::OnError(uint32_t aIndex) { void SpeechTaskCallback::OnError(uint32_t aIndex) {
@ -210,8 +218,11 @@ struct OSXVoice {
class RegisterVoicesRunnable final : public Runnable { class RegisterVoicesRunnable final : public Runnable {
public: public:
RegisterVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService, nsTArray<OSXVoice>& aList) RegisterVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService,
: Runnable("RegisterVoicesRunnable"), mSpeechService(aSpeechService), mVoices(aList) {} nsTArray<OSXVoice>& aList)
: Runnable("RegisterVoicesRunnable"),
mSpeechService(aSpeechService),
mVoices(aList) {}
NS_IMETHOD Run() override; NS_IMETHOD Run() override;
@ -226,13 +237,15 @@ class RegisterVoicesRunnable final : public Runnable {
NS_IMETHODIMP NS_IMETHODIMP
RegisterVoicesRunnable::Run() { RegisterVoicesRunnable::Run() {
nsresult rv; nsresult rv;
nsCOMPtr<nsISynthVoiceRegistry> registry = do_GetService(NS_SYNTHVOICEREGISTRY_CONTRACTID, &rv); nsCOMPtr<nsISynthVoiceRegistry> registry =
do_GetService(NS_SYNTHVOICEREGISTRY_CONTRACTID, &rv);
if (!registry) { if (!registry) {
return rv; return rv;
} }
for (OSXVoice voice : mVoices) { for (OSXVoice voice : mVoices) {
rv = registry->AddVoice(mSpeechService, voice.mUri, voice.mName, voice.mLocale, true, false); rv = registry->AddVoice(mSpeechService, voice.mUri, voice.mName,
voice.mLocale, true, false);
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
continue; continue;
} }
@ -275,11 +288,14 @@ EnumVoicesRunnable::Run() {
NSDictionary* attr = [NSSpeechSynthesizer attributesForVoice:voice]; NSDictionary* attr = [NSSpeechSynthesizer attributesForVoice:voice];
nsAutoString identifier; nsAutoString identifier;
nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceIdentifier], identifier); nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceIdentifier],
identifier);
nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceName], item.mName); nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceName],
item.mName);
nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceLocaleIdentifier], item.mLocale); nsCocoaUtils::GetStringForNSString(
[attr objectForKey:NSVoiceLocaleIdentifier], item.mLocale);
item.mLocale.ReplaceChar('_', '-'); item.mLocale.ReplaceChar('_', '-');
item.mUri.AssignLiteral("urn:moz-tts:osx:"); item.mUri.AssignLiteral("urn:moz-tts:osx:");
@ -292,16 +308,19 @@ EnumVoicesRunnable::Run() {
list.AppendElement(item); list.AppendElement(item);
} }
RefPtr<RegisterVoicesRunnable> runnable = new RegisterVoicesRunnable(mSpeechService, list); RefPtr<RegisterVoicesRunnable> runnable =
new RegisterVoicesRunnable(mSpeechService, list);
NS_DispatchAndSpinEventLoopUntilComplete("EnumVoicesRunnable"_ns, NS_DispatchAndSpinEventLoopUntilComplete("EnumVoicesRunnable"_ns,
GetMainThreadSerialEventTarget(), runnable.forget()); GetMainThreadSerialEventTarget(),
runnable.forget());
return NS_OK; return NS_OK;
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
} }
StaticRefPtr<OSXSpeechSynthesizerService> OSXSpeechSynthesizerService::sSingleton; StaticRefPtr<OSXSpeechSynthesizerService>
OSXSpeechSynthesizerService::sSingleton;
NS_INTERFACE_MAP_BEGIN(OSXSpeechSynthesizerService) NS_INTERFACE_MAP_BEGIN(OSXSpeechSynthesizerService)
NS_INTERFACE_MAP_ENTRY(nsISpeechService) NS_INTERFACE_MAP_ENTRY(nsISpeechService)
@ -312,7 +331,8 @@ NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(OSXSpeechSynthesizerService) NS_IMPL_ADDREF(OSXSpeechSynthesizerService)
NS_IMPL_RELEASE(OSXSpeechSynthesizerService) NS_IMPL_RELEASE(OSXSpeechSynthesizerService)
OSXSpeechSynthesizerService::OSXSpeechSynthesizerService() : mInitialized(false) {} OSXSpeechSynthesizerService::OSXSpeechSynthesizerService()
: mInitialized(false) {}
bool OSXSpeechSynthesizerService::Init() { bool OSXSpeechSynthesizerService::Init() {
if (Preferences::GetBool("media.webspeech.synth.test") || if (Preferences::GetBool("media.webspeech.synth.test") ||
@ -335,8 +355,10 @@ bool OSXSpeechSynthesizerService::Init() {
} }
NS_IMETHODIMP NS_IMETHODIMP
OSXSpeechSynthesizerService::Speak(const nsAString& aText, const nsAString& aUri, float aVolume, OSXSpeechSynthesizerService::Speak(const nsAString& aText,
float aRate, float aPitch, nsISpeechTask* aTask) { const nsAString& aUri, float aVolume,
float aRate, float aPitch,
nsISpeechTask* aTask) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
MOZ_ASSERT(StringBeginsWith(aUri, u"urn:moz-tts:osx:"_ns), MOZ_ASSERT(StringBeginsWith(aUri, u"urn:moz-tts:osx:"_ns),
@ -348,11 +370,16 @@ OSXSpeechSynthesizerService::Speak(const nsAString& aText, const nsAString& aUri
[synth setVoice:identifier]; [synth setVoice:identifier];
// default rate is 180-220 // default rate is 180-220
[synth setObject:[NSNumber numberWithInt:aRate * 200] forProperty:NSSpeechRateProperty error:nil]; [synth setObject:[NSNumber numberWithInt:aRate * 200]
forProperty:NSSpeechRateProperty
error:nil];
// volume allows 0.0-1.0 // volume allows 0.0-1.0
[synth setObject:[NSNumber numberWithFloat:aVolume] forProperty:NSSpeechVolumeProperty error:nil]; [synth setObject:[NSNumber numberWithFloat:aVolume]
forProperty:NSSpeechVolumeProperty
error:nil];
// Use default pitch value to calculate this // Use default pitch value to calculate this
NSNumber* defaultPitch = [synth objectForProperty:NSSpeechPitchBaseProperty error:nil]; NSNumber* defaultPitch = [synth objectForProperty:NSSpeechPitchBaseProperty
error:nil];
if (defaultPitch) { if (defaultPitch) {
int newPitch = [defaultPitch intValue] * (aPitch / 2 + 0.5); int newPitch = [defaultPitch intValue] * (aPitch / 2 + 0.5);
[synth setObject:[NSNumber numberWithInt:newPitch] [synth setObject:[NSNumber numberWithInt:newPitch]
@ -370,8 +397,8 @@ OSXSpeechSynthesizerService::Speak(const nsAString& aText, const nsAString& aUri
// This loop looks for occurances of "[[" or "]]", escapes them, and // This loop looks for occurances of "[[" or "]]", escapes them, and
// populates the offsets array to supply a map to the original offsets. // populates the offsets array to supply a map to the original offsets.
for (size_t i = 0; i < aText.Length(); i++) { for (size_t i = 0; i < aText.Length(); i++) {
if (aText.Length() > i + 1 && if (aText.Length() > i + 1 && ((aText[i] == ']' && aText[i + 1] == ']') ||
((aText[i] == ']' && aText[i + 1] == ']') || (aText[i] == '[' && aText[i + 1] == '['))) { (aText[i] == '[' && aText[i + 1] == '['))) {
escapedText.AppendLiteral(DLIM_ESCAPE_START); escapedText.AppendLiteral(DLIM_ESCAPE_START);
offsets.AppendElements(strlen(DLIM_ESCAPE_START)); offsets.AppendElements(strlen(DLIM_ESCAPE_START));
escapedText.Append(aText[i]); escapedText.Append(aText[i]);
@ -386,7 +413,8 @@ OSXSpeechSynthesizerService::Speak(const nsAString& aText, const nsAString& aUri
} }
} }
RefPtr<SpeechTaskCallback> callback = new SpeechTaskCallback(aTask, synth, offsets); RefPtr<SpeechTaskCallback> callback =
new SpeechTaskCallback(aTask, synth, offsets);
nsresult rv = aTask->Setup(callback); nsresult rv = aTask->Setup(callback);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -413,7 +441,8 @@ OSXSpeechSynthesizerService* OSXSpeechSynthesizerService::GetInstance() {
} }
if (!sSingleton) { if (!sSingleton) {
RefPtr<OSXSpeechSynthesizerService> speechService = new OSXSpeechSynthesizerService(); RefPtr<OSXSpeechSynthesizerService> speechService =
new OSXSpeechSynthesizerService();
if (speechService->Init()) { if (speechService->Init()) {
sSingleton = speechService; sSingleton = speechService;
ClearOnShutdown(&sSingleton); ClearOnShutdown(&sSingleton);
@ -422,7 +451,8 @@ OSXSpeechSynthesizerService* OSXSpeechSynthesizerService::GetInstance() {
return sSingleton; return sSingleton;
} }
already_AddRefed<OSXSpeechSynthesizerService> OSXSpeechSynthesizerService::GetInstanceForService() { already_AddRefed<OSXSpeechSynthesizerService>
OSXSpeechSynthesizerService::GetInstanceForService() {
RefPtr<OSXSpeechSynthesizerService> speechService = GetInstance(); RefPtr<OSXSpeechSynthesizerService> speechService = GetInstance();
return speechService.forget(); return speechService.forget();
} }

View file

@ -29,15 +29,18 @@
using namespace mozilla; using namespace mozilla;
static const CLLocationAccuracy kHIGH_ACCURACY = kCLLocationAccuracyBest; static const CLLocationAccuracy kHIGH_ACCURACY = kCLLocationAccuracyBest;
static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTenMeters; static const CLLocationAccuracy kDEFAULT_ACCURACY =
kCLLocationAccuracyNearestTenMeters;
@interface LocationDelegate : NSObject <CLLocationManagerDelegate> { @interface LocationDelegate : NSObject <CLLocationManagerDelegate> {
CoreLocationLocationProvider* mProvider; CoreLocationLocationProvider* mProvider;
} }
- (id)init:(CoreLocationLocationProvider*)aProvider; - (id)init:(CoreLocationLocationProvider*)aProvider;
- (void)locationManager:(CLLocationManager*)aManager didFailWithError:(NSError*)aError; - (void)locationManager:(CLLocationManager*)aManager
- (void)locationManager:(CLLocationManager*)aManager didUpdateLocations:(NSArray*)locations; didFailWithError:(NSError*)aError;
- (void)locationManager:(CLLocationManager*)aManager
didUpdateLocations:(NSArray*)locations;
@end @end
@ -50,28 +53,32 @@ static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTe
return self; return self;
} }
- (void)locationManager:(CLLocationManager*)aManager didFailWithError:(NSError*)aError { - (void)locationManager:(CLLocationManager*)aManager
nsCOMPtr<nsIConsoleService> console = do_GetService(NS_CONSOLESERVICE_CONTRACTID); didFailWithError:(NSError*)aError {
nsCOMPtr<nsIConsoleService> console =
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
NS_ENSURE_TRUE_VOID(console); NS_ENSURE_TRUE_VOID(console);
NSString* message = NSString* message = [@"Failed to acquire position: "
[@"Failed to acquire position: " stringByAppendingString:[aError localizedDescription]]; stringByAppendingString:[aError localizedDescription]];
console->LogStringMessage(NS_ConvertUTF8toUTF16([message UTF8String]).get()); console->LogStringMessage(NS_ConvertUTF8toUTF16([message UTF8String]).get());
if ([aError code] == kCLErrorDenied) { if ([aError code] == kCLErrorDenied) {
mProvider->NotifyError(dom::GeolocationPositionError_Binding::PERMISSION_DENIED); mProvider->NotifyError(
dom::GeolocationPositionError_Binding::PERMISSION_DENIED);
return; return;
} }
// The CL provider does not fallback to GeoIP, so use NetworkGeolocationProvider for this. // The CL provider does not fallback to GeoIP, so use
// The concept here is: on error, hand off geolocation to MLS, which will then report // NetworkGeolocationProvider for this. The concept here is: on error, hand
// back a location or error. // off geolocation to MLS, which will then report back a location or error.
mProvider->CreateMLSFallbackProvider(); mProvider->CreateMLSFallbackProvider();
} }
- (void)locationManager:(CLLocationManager*)aManager didUpdateLocations:(NSArray*)aLocations { - (void)locationManager:(CLLocationManager*)aManager
didUpdateLocations:(NSArray*)aLocations {
if (aLocations.count < 1) { if (aLocations.count < 1) {
return; return;
} }
@ -92,24 +99,29 @@ static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTe
altitudeAccuracy = UnspecifiedNaN<double>(); altitudeAccuracy = UnspecifiedNaN<double>();
} }
double speed = location.speed >= 0 ? location.speed : UnspecifiedNaN<double>(); double speed =
location.speed >= 0 ? location.speed : UnspecifiedNaN<double>();
double heading = location.course >= 0 ? location.course : UnspecifiedNaN<double>(); double heading =
location.course >= 0 ? location.course : UnspecifiedNaN<double>();
// nsGeoPositionCoords will convert NaNs to null for optional properties of // nsGeoPositionCoords will convert NaNs to null for optional properties of
// the JavaScript Coordinates object. // the JavaScript Coordinates object.
nsCOMPtr<nsIDOMGeoPosition> geoPosition = new nsGeoPosition( nsCOMPtr<nsIDOMGeoPosition> geoPosition = new nsGeoPosition(
location.coordinate.latitude, location.coordinate.longitude, altitude, location.coordinate.latitude, location.coordinate.longitude, altitude,
location.horizontalAccuracy, altitudeAccuracy, heading, speed, PR_Now() / PR_USEC_PER_MSEC); location.horizontalAccuracy, altitudeAccuracy, heading, speed,
PR_Now() / PR_USEC_PER_MSEC);
mProvider->Update(geoPosition); mProvider->Update(geoPosition);
Telemetry::Accumulate(Telemetry::GEOLOCATION_OSX_SOURCE_IS_MLS, false); Telemetry::Accumulate(Telemetry::GEOLOCATION_OSX_SOURCE_IS_MLS, false);
} }
@end @end
NS_IMPL_ISUPPORTS(CoreLocationLocationProvider::MLSUpdate, nsIGeolocationUpdate); NS_IMPL_ISUPPORTS(CoreLocationLocationProvider::MLSUpdate,
nsIGeolocationUpdate);
CoreLocationLocationProvider::MLSUpdate::MLSUpdate(CoreLocationLocationProvider& parentProvider) CoreLocationLocationProvider::MLSUpdate::MLSUpdate(
CoreLocationLocationProvider& parentProvider)
: mParentLocationProvider(parentProvider) {} : mParentLocationProvider(parentProvider) {}
NS_IMETHODIMP NS_IMETHODIMP
@ -175,7 +187,8 @@ CoreLocationLocationProvider::Startup() {
mCLObjects = clObjs.release(); mCLObjects = clObjs.release();
} }
// Must be stopped before starting or response (success or failure) is not guaranteed // Must be stopped before starting or response (success or failure) is not
// guaranteed
[mCLObjects->mLocationManager stopUpdatingLocation]; [mCLObjects->mLocationManager stopUpdatingLocation];
[mCLObjects->mLocationManager startUpdatingLocation]; [mCLObjects->mLocationManager startUpdatingLocation];
return NS_OK; return NS_OK;
@ -212,7 +225,8 @@ NS_IMETHODIMP
CoreLocationLocationProvider::SetHighAccuracy(bool aEnable) { CoreLocationLocationProvider::SetHighAccuracy(bool aEnable) {
NS_ENSURE_STATE(mCLObjects); NS_ENSURE_STATE(mCLObjects);
mCLObjects->mLocationManager.desiredAccuracy = (aEnable ? kHIGH_ACCURACY : kDEFAULT_ACCURACY); mCLObjects->mLocationManager.desiredAccuracy =
(aEnable ? kHIGH_ACCURACY : kDEFAULT_ACCURACY);
return NS_OK; return NS_OK;
} }

View file

@ -32,7 +32,8 @@ nsOSPermissionRequest::GetScreenCapturePermissionState(uint16_t* aScreen) {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsOSPermissionRequest::RequestVideoCapturePermission(JSContext* aCx, Promise** aPromiseOut) { nsOSPermissionRequest::RequestVideoCapturePermission(JSContext* aCx,
Promise** aPromiseOut) {
RefPtr<Promise> promiseHandle; RefPtr<Promise> promiseHandle;
nsresult rv = GetPromise(aCx, promiseHandle); nsresult rv = GetPromise(aCx, promiseHandle);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
@ -45,7 +46,8 @@ nsOSPermissionRequest::RequestVideoCapturePermission(JSContext* aCx, Promise** a
} }
NS_IMETHODIMP NS_IMETHODIMP
nsOSPermissionRequest::RequestAudioCapturePermission(JSContext* aCx, Promise** aPromiseOut) { nsOSPermissionRequest::RequestAudioCapturePermission(JSContext* aCx,
Promise** aPromiseOut) {
RefPtr<Promise> promiseHandle; RefPtr<Promise> promiseHandle;
nsresult rv = GetPromise(aCx, promiseHandle); nsresult rv = GetPromise(aCx, promiseHandle);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {

View file

@ -37,7 +37,8 @@ class CGLLibrary {
return true; return true;
} }
if (!mOGLLibrary) { if (!mOGLLibrary) {
mOGLLibrary = PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL"); mOGLLibrary =
PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL");
if (!mOGLLibrary) { if (!mOGLLibrary) {
NS_WARNING("Couldn't load OpenGL Framework."); NS_WARNING("Couldn't load OpenGL Framework.");
return false; return false;
@ -59,7 +60,8 @@ CGLLibrary sCGLLibrary;
GLContextCGL::GLContextCGL(const GLContextDesc& desc, NSOpenGLContext* context) GLContextCGL::GLContextCGL(const GLContextDesc& desc, NSOpenGLContext* context)
: GLContext(desc), mContext(context) { : GLContext(desc), mContext(context) {
CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback, this); CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback,
this);
} }
GLContextCGL::~GLContextCGL() { GLContextCGL::~GLContextCGL() {
@ -89,33 +91,39 @@ bool GLContextCGL::MakeCurrentImpl() const {
// Use non-blocking swap in "ASAP mode". // Use non-blocking swap in "ASAP mode".
// ASAP mode means that rendering is iterated as fast as possible. // ASAP mode means that rendering is iterated as fast as possible.
// ASAP mode is entered when layout.frame_rate=0 (requires restart). // ASAP mode is entered when layout.frame_rate=0 (requires restart).
// If swapInt is 1, then glSwapBuffers will block and wait for a vblank signal. // If swapInt is 1, then glSwapBuffers will block and wait for a vblank
// When we're iterating as fast as possible, however, we want a non-blocking // signal. When we're iterating as fast as possible, however, we want a
// glSwapBuffers, which will happen when swapInt==0. // non-blocking glSwapBuffers, which will happen when swapInt==0.
GLint swapInt = StaticPrefs::layout_frame_rate() == 0 ? 0 : 1; GLint swapInt = StaticPrefs::layout_frame_rate() == 0 ? 0 : 1;
[mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; [mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
} }
return true; return true;
} }
bool GLContextCGL::IsCurrentImpl() const { return [NSOpenGLContext currentContext] == mContext; } bool GLContextCGL::IsCurrentImpl() const {
return [NSOpenGLContext currentContext] == mContext;
}
/* static */ void GLContextCGL::DisplayReconfigurationCallback(CGDirectDisplayID aDisplay, /* static */ void GLContextCGL::DisplayReconfigurationCallback(
CGDisplayChangeSummaryFlags aFlags, CGDirectDisplayID aDisplay, CGDisplayChangeSummaryFlags aFlags,
void* aUserInfo) { void* aUserInfo) {
if (aFlags & kCGDisplaySetModeFlag) { if (aFlags & kCGDisplaySetModeFlag) {
static_cast<GLContextCGL*>(aUserInfo)->mActiveGPUSwitchMayHaveOccurred = true; static_cast<GLContextCGL*>(aUserInfo)->mActiveGPUSwitchMayHaveOccurred =
true;
} }
} }
static NSOpenGLContext* CreateWithFormat(const NSOpenGLPixelFormatAttribute* attribs) { static NSOpenGLContext* CreateWithFormat(
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; const NSOpenGLPixelFormatAttribute* attribs) {
NSOpenGLPixelFormat* format =
[[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
if (!format) { if (!format) {
NS_WARNING("Failed to create NSOpenGLPixelFormat."); NS_WARNING("Failed to create NSOpenGLPixelFormat.");
return nullptr; return nullptr;
} }
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:nullptr]; NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format
shareContext:nullptr];
[format release]; [format release];
@ -124,30 +132,40 @@ static NSOpenGLContext* CreateWithFormat(const NSOpenGLPixelFormatAttribute* att
// Get the "OpenGL display mask" for a fresh context. The return value of this // Get the "OpenGL display mask" for a fresh context. The return value of this
// function depends on the time at which this function is called. // function depends on the time at which this function is called.
// In practice, on a Macbook Pro with an integrated and a discrete GPU, this function returns the // In practice, on a Macbook Pro with an integrated and a discrete GPU, this
// display mask for the GPU that currently drives the internal display. // function returns the display mask for the GPU that currently drives the
// internal display.
// //
// Quick reference of the concepts involved in the code below: // Quick reference of the concepts involved in the code below:
// GPU switch: On Mac devices with an integrated and a discrete GPU, a GPU switch changes which // GPU switch: On Mac devices with an integrated and a discrete GPU, a GPU
// GPU drives the internal display. Both GPUs are still usable at all times. (When the // switch changes which
// integrated GPU is driving the internal display, using the discrete GPU can incur a longer // GPU drives the internal display. Both GPUs are still usable at all times.
// warm-up cost.) // (When the integrated GPU is driving the internal display, using the
// Virtual screen: A CGL concept. A "virtual screen" corresponds to a GL renderer. There's one // discrete GPU can incur a longer warm-up cost.)
// for the integrated GPU, one for each discrete GPU, and one for the Apple software renderer. // Virtual screen: A CGL concept. A "virtual screen" corresponds to a GL
// The list of virtual screens is per-NSOpenGLPixelFormat; it is filtered down to only the // renderer. There's one
// renderers that support the requirements from the pixel format attributes. Indexes into this // for the integrated GPU, one for each discrete GPU, and one for the Apple
// list (such as currentVirtualScreen) cannot be used interchangably across different // software renderer. The list of virtual screens is
// NSOpenGLPixelFormat instances. // per-NSOpenGLPixelFormat; it is filtered down to only the renderers that
// Display mask: A bitset per GL renderer. Different renderers have disjoint display masks. The // support the requirements from the pixel format attributes. Indexes into
// this list (such as currentVirtualScreen) cannot be used interchangably
// across different NSOpenGLPixelFormat instances.
// Display mask: A bitset per GL renderer. Different renderers have disjoint
// display masks. The
// Apple software renderer has all bits zeroed. For each CGDirectDisplayID, // Apple software renderer has all bits zeroed. For each CGDirectDisplayID,
// CGDisplayIDToOpenGLDisplayMask(displayID) returns a single bit in the display mask. // CGDisplayIDToOpenGLDisplayMask(displayID) returns a single bit in the
// CGDirectDisplayID: An ID for each (physical screen, GPU which can drive this screen) pair. The // display mask.
// current CGDirectDisplayID for an NSScreen object can be obtained using [[[screen // CGDirectDisplayID: An ID for each (physical screen, GPU which can drive
// deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]; it changes depending on // this screen) pair. The
// which GPU is currently driving the screen. // current CGDirectDisplayID for an NSScreen object can be obtained using
// [[[screen deviceDescription] objectForKey:@"NSScreenNumber"]
// unsignedIntValue]; it changes depending on which GPU is currently driving
// the screen.
static CGOpenGLDisplayMask GetFreshContextDisplayMask() { static CGOpenGLDisplayMask GetFreshContextDisplayMask() {
NSOpenGLPixelFormatAttribute attribs[] = {NSOpenGLPFAAllowOfflineRenderers, 0}; NSOpenGLPixelFormatAttribute attribs[] = {NSOpenGLPFAAllowOfflineRenderers,
NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; 0};
NSOpenGLPixelFormat* pixelFormat =
[[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
MOZ_RELEASE_ASSERT(pixelFormat); MOZ_RELEASE_ASSERT(pixelFormat);
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
shareContext:nullptr]; shareContext:nullptr];
@ -185,13 +203,15 @@ void GLContextCGL::MigrateToActiveGPU() {
return; return;
} }
// Find the "virtual screen" with a display mask that matches newPreferredDisplayMask, if // Find the "virtual screen" with a display mask that matches
// available, and switch the context over to it. // newPreferredDisplayMask, if available, and switch the context over to it.
// This code was inspired by equivalent functionality in -[NSOpenGLContext update] which only // This code was inspired by equivalent functionality in -[NSOpenGLContext
// kicks in for contexts that present via a CAOpenGLLayer. // update] which only kicks in for contexts that present via a CAOpenGLLayer.
for (const auto i : IntegerRange([pixelFormat numberOfVirtualScreens])) { for (const auto i : IntegerRange([pixelFormat numberOfVirtualScreens])) {
GLint displayMask = 0; GLint displayMask = 0;
[pixelFormat getValues:&displayMask forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:i]; [pixelFormat getValues:&displayMask
forAttribute:NSOpenGLPFAScreenMask
forVirtualScreen:i];
if (IsSameGPU(displayMask, newPreferredDisplayMask)) { if (IsSameGPU(displayMask, newPreferredDisplayMask)) {
CGLSetVirtualScreen([mContext CGLContextObj], i); CGLSetVirtualScreen([mContext CGLContextObj], i);
return; return;
@ -212,7 +232,9 @@ bool GLContextCGL::SwapBuffers() {
return true; return true;
} }
void GLContextCGL::GetWSIInfo(nsCString* const out) const { out->AppendLiteral("CGL"); } void GLContextCGL::GetWSIInfo(nsCString* const out) const {
out->AppendLiteral("CGL");
}
Maybe<SymbolLoader> GLContextCGL::GetSymbolLoader() const { Maybe<SymbolLoader> GLContextCGL::GetSymbolLoader() const {
const auto& lib = sCGLLibrary.Library(); const auto& lib = sCGLLibrary.Library();
@ -220,7 +242,8 @@ Maybe<SymbolLoader> GLContextCGL::GetSymbolLoader() const {
} }
already_AddRefed<GLContext> GLContextProviderCGL::CreateForCompositorWidget( already_AddRefed<GLContext> GLContextProviderCGL::CreateForCompositorWidget(
CompositorWidget* aCompositorWidget, bool aHardwareWebRender, bool aForceAccelerated) { CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
bool aForceAccelerated) {
CreateContextFlags flags = CreateContextFlags::ALLOW_OFFLINE_RENDERER; CreateContextFlags flags = CreateContextFlags::ALLOW_OFFLINE_RENDERER;
if (aForceAccelerated) { if (aForceAccelerated) {
flags |= CreateContextFlags::FORBID_SOFTWARE; flags |= CreateContextFlags::FORBID_SOFTWARE;
@ -232,7 +255,8 @@ already_AddRefed<GLContext> GLContextProviderCGL::CreateForCompositorWidget(
return CreateHeadless({flags}, &failureUnused); return CreateHeadless({flags}, &failureUnused);
} }
static RefPtr<GLContextCGL> CreateOffscreenFBOContext(GLContextCreateDesc desc) { static RefPtr<GLContextCGL> CreateOffscreenFBOContext(
GLContextCreateDesc desc) {
if (!sCGLLibrary.EnsureInitialized()) { if (!sCGLLibrary.EnsureInitialized()) {
return nullptr; return nullptr;
} }
@ -247,8 +271,9 @@ static RefPtr<GLContextCGL> CreateOffscreenFBOContext(GLContextCreateDesc desc)
} }
if (flags & CreateContextFlags::ALLOW_OFFLINE_RENDERER || if (flags & CreateContextFlags::ALLOW_OFFLINE_RENDERER ||
!(flags & CreateContextFlags::HIGH_POWER)) { !(flags & CreateContextFlags::HIGH_POWER)) {
// This is really poorly named on Apple's part, but "AllowOfflineRenderers" means // This is really poorly named on Apple's part, but "AllowOfflineRenderers"
// that we want to allow running on the iGPU instead of requiring the dGPU. // means that we want to allow running on the iGPU instead of requiring the
// dGPU.
attribs.push_back(NSOpenGLPFAAllowOfflineRenderers); attribs.push_back(NSOpenGLPFAAllowOfflineRenderers);
} }
@ -298,8 +323,8 @@ static RefPtr<GLContextCGL> CreateOffscreenFBOContext(GLContextCreateDesc desc)
return glContext; return glContext;
} }
already_AddRefed<GLContext> GLContextProviderCGL::CreateHeadless(const GLContextCreateDesc& desc, already_AddRefed<GLContext> GLContextProviderCGL::CreateHeadless(
nsACString* const out_failureId) { const GLContextCreateDesc& desc, nsACString* const out_failureId) {
auto gl = CreateOffscreenFBOContext(desc); auto gl = CreateOffscreenFBOContext(desc);
if (!gl) { if (!gl) {
*out_failureId = "FEATURE_FAILURE_CGL_FBO"_ns; *out_failureId = "FEATURE_FAILURE_CGL_FBO"_ns;

View file

@ -52,7 +52,8 @@ bool GLContextEAGL::AttachToWindow(nsIWidget* aWidget) {
// This should only be called once // This should only be called once
MOZ_ASSERT(!mBackbufferFB && !mBackbufferRB); MOZ_ASSERT(!mBackbufferFB && !mBackbufferRB);
UIView* view = reinterpret_cast<UIView*>(aWidget->GetNativeData(NS_NATIVE_WIDGET)); UIView* view =
reinterpret_cast<UIView*>(aWidget->GetNativeData(NS_NATIVE_WIDGET));
if (!view) { if (!view) {
MOZ_CRASH("no view!"); MOZ_CRASH("no view!");
@ -82,10 +83,11 @@ bool GLContextEAGL::RecreateRB() {
[mContext renderbufferStorage:LOCAL_GL_RENDERBUFFER fromDrawable:layer]; [mContext renderbufferStorage:LOCAL_GL_RENDERBUFFER fromDrawable:layer];
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackbufferFB); fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackbufferFB);
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_RENDERBUFFER, fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
mBackbufferRB); LOCAL_GL_RENDERBUFFER, mBackbufferRB);
return LOCAL_GL_FRAMEBUFFER_COMPLETE == fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); return LOCAL_GL_FRAMEBUFFER_COMPLETE ==
fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
} }
bool GLContextEAGL::MakeCurrentImpl() const { bool GLContextEAGL::MakeCurrentImpl() const {
@ -97,7 +99,9 @@ bool GLContextEAGL::MakeCurrentImpl() const {
return true; return true;
} }
bool GLContextEAGL::IsCurrentImpl() const { return [EAGLContext currentContext] == mContext; } bool GLContextEAGL::IsCurrentImpl() const {
return [EAGLContext currentContext] == mContext;
}
static PRFuncPtr GLAPIENTRY GetLoadedProcAddress(const char* const name) { static PRFuncPtr GLAPIENTRY GetLoadedProcAddress(const char* const name) {
PRLibrary* lib = nullptr; PRLibrary* lib = nullptr;
@ -121,7 +125,9 @@ bool GLContextEAGL::SwapBuffers() {
return true; return true;
} }
void GLContextEAGL::GetWSIInfo(nsCString* const out) const { out->AppendLiteral("EAGL"); } void GLContextEAGL::GetWSIInfo(nsCString* const out) const {
out->AppendLiteral("EAGL");
}
static GLContextEAGL* GetGlobalContextEAGL() { static GLContextEAGL* GetGlobalContextEAGL() {
return static_cast<GLContextEAGL*>(GLContextProviderEAGL::GetGlobalContext()); return static_cast<GLContextEAGL*>(GLContextProviderEAGL::GetGlobalContext());
@ -129,14 +135,16 @@ static GLContextEAGL* GetGlobalContextEAGL() {
static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc, static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
GLContextEAGL* sharedContext) { GLContextEAGL* sharedContext) {
EAGLRenderingAPI apis[] = {kEAGLRenderingAPIOpenGLES3, kEAGLRenderingAPIOpenGLES2}; EAGLRenderingAPI apis[] = {kEAGLRenderingAPIOpenGLES3,
kEAGLRenderingAPIOpenGLES2};
// Try to create a GLES3 context if we can, otherwise fall back to GLES2 // Try to create a GLES3 context if we can, otherwise fall back to GLES2
EAGLContext* context = nullptr; EAGLContext* context = nullptr;
for (EAGLRenderingAPI api : apis) { for (EAGLRenderingAPI api : apis) {
if (sharedContext) { if (sharedContext) {
context = [[EAGLContext alloc] initWithAPI:api context = [[EAGLContext alloc]
sharegroup:sharedContext->GetEAGLContext().sharegroup]; initWithAPI:api
sharegroup:sharedContext->GetEAGLContext().sharegroup];
} else { } else {
context = [[EAGLContext alloc] initWithAPI:api]; context = [[EAGLContext alloc] initWithAPI:api];
} }
@ -150,7 +158,8 @@ static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
return nullptr; return nullptr;
} }
RefPtr<GLContextEAGL> glContext = new GLContextEAGL(desc, context, sharedContext); RefPtr<GLContextEAGL> glContext =
new GLContextEAGL(desc, context, sharedContext);
if (!glContext->Init()) { if (!glContext->Init()) {
glContext = nullptr; glContext = nullptr;
return nullptr; return nullptr;
@ -160,7 +169,8 @@ static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
} }
already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget( already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
CompositorWidget* aCompositorWidget, bool aHardwareWebRender, bool aForceAccelerated) { CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
bool aForceAccelerated) {
if (!aCompositorWidget) { if (!aCompositorWidget) {
MOZ_ASSERT(false); MOZ_ASSERT(false);
return nullptr; return nullptr;
@ -172,7 +182,8 @@ already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
return nullptr; return nullptr;
} }
if (!GLContextEAGL::Cast(glContext)->AttachToWindow(aCompositorWidget->RealWidget())) { if (!GLContextEAGL::Cast(glContext)->AttachToWindow(
aCompositorWidget->RealWidget())) {
return nullptr; return nullptr;
} }
@ -193,7 +204,8 @@ GLContext* GLContextProviderEAGL::GetGlobalContext() {
if (!triedToCreateContext) { if (!triedToCreateContext) {
triedToCreateContext = true; triedToCreateContext = true;
MOZ_RELEASE_ASSERT(!gGlobalContext, "GFX: Global GL context already initialized."); MOZ_RELEASE_ASSERT(!gGlobalContext,
"GFX: Global GL context already initialized.");
RefPtr<GLContext> temp = CreateHeadless(CreateContextFlags::NONE); RefPtr<GLContext> temp = CreateHeadless(CreateContextFlags::NONE);
gGlobalContext = temp; gGlobalContext = temp;

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nullptr; c-basic-offset: 2 -*- /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -36,11 +36,13 @@ using gl::GLContextCGL;
// SurfacePoolCA::LockedPool // SurfacePoolCA::LockedPool
SurfacePoolCA::LockedPool::LockedPool(size_t aPoolSizeLimit) : mPoolSizeLimit(aPoolSizeLimit) {} SurfacePoolCA::LockedPool::LockedPool(size_t aPoolSizeLimit)
: mPoolSizeLimit(aPoolSizeLimit) {}
SurfacePoolCA::LockedPool::~LockedPool() { SurfacePoolCA::LockedPool::~LockedPool() {
MOZ_RELEASE_ASSERT(mWrappers.empty(), MOZ_RELEASE_ASSERT(
"Any outstanding wrappers should have kept the surface pool alive"); mWrappers.empty(),
"Any outstanding wrappers should have kept the surface pool alive");
MOZ_RELEASE_ASSERT(mInUseEntries.empty(), MOZ_RELEASE_ASSERT(mInUseEntries.empty(),
"Leak! No more surfaces should be in use at this point."); "Leak! No more surfaces should be in use at this point.");
// Remove all entries in mPendingEntries and mAvailableEntries. // Remove all entries in mPendingEntries and mAvailableEntries.
@ -50,8 +52,8 @@ SurfacePoolCA::LockedPool::~LockedPool() {
}); });
} }
RefPtr<SurfacePoolCAWrapperForGL> SurfacePoolCA::LockedPool::GetWrapperForGL(SurfacePoolCA* aPool, RefPtr<SurfacePoolCAWrapperForGL> SurfacePoolCA::LockedPool::GetWrapperForGL(
GLContext* aGL) { SurfacePoolCA* aPool, GLContext* aGL) {
auto& wrapper = mWrappers[aGL]; auto& wrapper = mWrappers[aGL];
if (!wrapper) { if (!wrapper) {
wrapper = new SurfacePoolCAWrapperForGL(aPool, aGL); wrapper = new SurfacePoolCAWrapperForGL(aPool, aGL);
@ -71,7 +73,8 @@ void SurfacePoolCA::LockedPool::DestroyGLResourcesForContext(GLContext* aGL) {
template <typename F> template <typename F>
void SurfacePoolCA::LockedPool::MutateEntryStorage(const char* aMutationType, void SurfacePoolCA::LockedPool::MutateEntryStorage(const char* aMutationType,
const gfx::IntSize& aSize, F aFn) { const gfx::IntSize& aSize,
F aFn) {
[[maybe_unused]] size_t inUseCountBefore = mInUseEntries.size(); [[maybe_unused]] size_t inUseCountBefore = mInUseEntries.size();
[[maybe_unused]] size_t pendingCountBefore = mPendingEntries.Length(); [[maybe_unused]] size_t pendingCountBefore = mPendingEntries.Length();
[[maybe_unused]] size_t availableCountBefore = mAvailableEntries.Length(); [[maybe_unused]] size_t availableCountBefore = mAvailableEntries.Length();
@ -84,9 +87,11 @@ void SurfacePoolCA::LockedPool::MutateEntryStorage(const char* aMutationType,
"SurfacePool", GRAPHICS, MarkerTiming::IntervalUntilNowFrom(before), "SurfacePool", GRAPHICS, MarkerTiming::IntervalUntilNowFrom(before),
nsPrintfCString("%d -> %d in use | %d -> %d waiting for | %d -> %d " nsPrintfCString("%d -> %d in use | %d -> %d waiting for | %d -> %d "
"available | %s %dx%d | %dMB total memory", "available | %s %dx%d | %dMB total memory",
int(inUseCountBefore), int(mInUseEntries.size()), int(pendingCountBefore), int(inUseCountBefore), int(mInUseEntries.size()),
int(mPendingEntries.Length()), int(availableCountBefore), int(pendingCountBefore), int(mPendingEntries.Length()),
int(mAvailableEntries.Length()), aMutationType, aSize.width, aSize.height, int(availableCountBefore),
int(mAvailableEntries.Length()), aMutationType,
aSize.width, aSize.height,
int(EstimateTotalMemory() / 1000 / 1000))); int(EstimateTotalMemory() / 1000 / 1000)));
} }
} }
@ -126,8 +131,8 @@ uint64_t SurfacePoolCA::LockedPool::EstimateTotalMemory() {
return memBytes; return memBytes;
} }
bool SurfacePoolCA::LockedPool::CanRecycleSurfaceForRequest(const SurfacePoolEntry& aEntry, bool SurfacePoolCA::LockedPool::CanRecycleSurfaceForRequest(
const IntSize& aSize, GLContext* aGL) { const SurfacePoolEntry& aEntry, const IntSize& aSize, GLContext* aGL) {
if (aEntry.mSize != aSize) { if (aEntry.mSize != aSize) {
return false; return false;
} }
@ -137,14 +142,16 @@ bool SurfacePoolCA::LockedPool::CanRecycleSurfaceForRequest(const SurfacePoolEnt
return true; return true;
} }
CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::LockedPool::ObtainSurfaceFromPool(const IntSize& aSize, CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::LockedPool::ObtainSurfaceFromPool(
GLContext* aGL) { const IntSize& aSize, GLContext* aGL) {
// Do a linear scan through mAvailableEntries to find an eligible surface, going from oldest to // Do a linear scan through mAvailableEntries to find an eligible surface,
// newest. The size of this array is limited, so the linear scan is fast. // going from oldest to newest. The size of this array is limited, so the
auto iterToRecycle = std::find_if(mAvailableEntries.begin(), mAvailableEntries.end(), // linear scan is fast.
[&](const SurfacePoolEntry& aEntry) { auto iterToRecycle =
return CanRecycleSurfaceForRequest(aEntry, aSize, aGL); std::find_if(mAvailableEntries.begin(), mAvailableEntries.end(),
}); [&](const SurfacePoolEntry& aEntry) {
return CanRecycleSurfaceForRequest(aEntry, aSize, aGL);
});
if (iterToRecycle != mAvailableEntries.end()) { if (iterToRecycle != mAvailableEntries.end()) {
CFTypeRefPtr<IOSurfaceRef> surface = iterToRecycle->mIOSurface; CFTypeRefPtr<IOSurfaceRef> surface = iterToRecycle->mIOSurface;
MOZ_RELEASE_ASSERT(surface.get(), "Available surfaces should be non-null."); MOZ_RELEASE_ASSERT(surface.get(), "Available surfaces should be non-null.");
@ -156,18 +163,22 @@ CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::LockedPool::ObtainSurfaceFromPool(cons
return surface; return surface;
} }
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("IOSurface creation", GRAPHICS_TileAllocation, AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
nsPrintfCString("%dx%d", aSize.width, aSize.height)); "IOSurface creation", GRAPHICS_TileAllocation,
nsPrintfCString("%dx%d", aSize.width, aSize.height));
CFTypeRefPtr<IOSurfaceRef> surface = CFTypeRefPtr<IOSurfaceRef> surface =
CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(IOSurfaceCreate((__bridge CFDictionaryRef) @{ CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
(__bridge NSString*)kIOSurfaceWidth : @(aSize.width), IOSurfaceCreate((__bridge CFDictionaryRef) @{
(__bridge NSString*)kIOSurfaceHeight : @(aSize.height), (__bridge NSString*)kIOSurfaceWidth : @(aSize.width),
(__bridge NSString*)kIOSurfacePixelFormat : @(kCVPixelFormatType_32BGRA), (__bridge NSString*)kIOSurfaceHeight : @(aSize.height),
(__bridge NSString*)kIOSurfaceBytesPerElement : @(4), (__bridge NSString*)
})); kIOSurfacePixelFormat : @(kCVPixelFormatType_32BGRA),
(__bridge NSString*)kIOSurfaceBytesPerElement : @(4),
}));
if (surface) { if (surface) {
if (StaticPrefs::gfx_color_management_native_srgb()) { if (StaticPrefs::gfx_color_management_native_srgb()) {
IOSurfaceSetValue(surface.get(), CFSTR("IOSurfaceColorSpace"), kCGColorSpaceSRGB); IOSurfaceSetValue(surface.get(), CFSTR("IOSurfaceColorSpace"),
kCGColorSpaceSRGB);
} }
// Create a new entry in mInUseEntries. // Create a new entry in mInUseEntries.
MutateEntryStorage("Create", aSize, [&]() { MutateEntryStorage("Create", aSize, [&]() {
@ -177,16 +188,18 @@ CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::LockedPool::ObtainSurfaceFromPool(cons
return surface; return surface;
} }
void SurfacePoolCA::LockedPool::ReturnSurfaceToPool(CFTypeRefPtr<IOSurfaceRef> aSurface) { void SurfacePoolCA::LockedPool::ReturnSurfaceToPool(
CFTypeRefPtr<IOSurfaceRef> aSurface) {
auto inUseEntryIter = mInUseEntries.find(aSurface); auto inUseEntryIter = mInUseEntries.find(aSurface);
MOZ_RELEASE_ASSERT(inUseEntryIter != mInUseEntries.end()); MOZ_RELEASE_ASSERT(inUseEntryIter != mInUseEntries.end());
if (IOSurfaceIsInUse(aSurface.get())) { if (IOSurfaceIsInUse(aSurface.get())) {
// Move the entry from mInUseEntries to mPendingEntries. // Move the entry from mInUseEntries to mPendingEntries.
MutateEntryStorage("Start waiting for", IntSize(inUseEntryIter->second.mSize), [&]() { MutateEntryStorage(
mPendingEntries.AppendElement( "Start waiting for", IntSize(inUseEntryIter->second.mSize), [&]() {
PendingSurfaceEntry{std::move(inUseEntryIter->second), mCollectionGeneration, 0}); mPendingEntries.AppendElement(PendingSurfaceEntry{
mInUseEntries.erase(inUseEntryIter); std::move(inUseEntryIter->second), mCollectionGeneration, 0});
}); mInUseEntries.erase(inUseEntryIter);
});
} else { } else {
// Move the entry from mInUseEntries to mAvailableEntries. // Move the entry from mInUseEntries to mAvailableEntries.
MOZ_RELEASE_ASSERT(inUseEntryIter->second.mIOSurface.get(), MOZ_RELEASE_ASSERT(inUseEntryIter->second.mIOSurface.get(),
@ -199,14 +212,16 @@ void SurfacePoolCA::LockedPool::ReturnSurfaceToPool(CFTypeRefPtr<IOSurfaceRef> a
} }
void SurfacePoolCA::LockedPool::EnforcePoolSizeLimit() { void SurfacePoolCA::LockedPool::EnforcePoolSizeLimit() {
// Enforce the pool size limit, removing least-recently-used entries as necessary. // Enforce the pool size limit, removing least-recently-used entries as
// necessary.
while (mAvailableEntries.Length() > mPoolSizeLimit) { while (mAvailableEntries.Length() > mPoolSizeLimit) {
MutateEntryStorage("Evict", IntSize(mAvailableEntries[0].mSize), MutateEntryStorage("Evict", IntSize(mAvailableEntries[0].mSize),
[&]() { mAvailableEntries.RemoveElementAt(0); }); [&]() { mAvailableEntries.RemoveElementAt(0); });
} }
} }
uint64_t SurfacePoolCA::LockedPool::CollectPendingSurfaces(uint64_t aCheckGenerationsUpTo) { uint64_t SurfacePoolCA::LockedPool::CollectPendingSurfaces(
uint64_t aCheckGenerationsUpTo) {
mCollectionGeneration++; mCollectionGeneration++;
// Loop from back to front, potentially deleting items as we iterate. // Loop from back to front, potentially deleting items as we iterate.
@ -218,18 +233,21 @@ uint64_t SurfacePoolCA::LockedPool::CollectPendingSurfaces(uint64_t aCheckGenera
if (pendingSurf.mPreviousCheckGeneration > aCheckGenerationsUpTo) { if (pendingSurf.mPreviousCheckGeneration > aCheckGenerationsUpTo) {
continue; continue;
} }
// Check if the window server is still using the surface. As long as it is doing that, we cannot // Check if the window server is still using the surface. As long as it is
// move the surface to mAvailableSurfaces because anything we draw to it could reach the screen // doing that, we cannot move the surface to mAvailableSurfaces because
// in a place where we don't expect it. // anything we draw to it could reach the screen in a place where we don't
// expect it.
if (IOSurfaceIsInUse(pendingSurf.mEntry.mIOSurface.get())) { if (IOSurfaceIsInUse(pendingSurf.mEntry.mIOSurface.get())) {
// The surface is still in use. Update mPreviousCheckGeneration and mCheckCount. // The surface is still in use. Update mPreviousCheckGeneration and
// mCheckCount.
pendingSurf.mPreviousCheckGeneration = mCollectionGeneration; pendingSurf.mPreviousCheckGeneration = mCollectionGeneration;
pendingSurf.mCheckCount++; pendingSurf.mCheckCount++;
if (pendingSurf.mCheckCount >= 30) { if (pendingSurf.mCheckCount >= 30) {
// The window server has been holding on to this surface for an unreasonably long time. This // The window server has been holding on to this surface for an
// is known to happen sometimes, for example in occluded windows or after a GPU switch. In // unreasonably long time. This is known to happen sometimes, for
// that case, release our references to the surface so that it's Not Our Problem anymore. // example in occluded windows or after a GPU switch. In that case,
// Remove the entry from mPendingEntries. // release our references to the surface so that it's Not Our Problem
// anymore. Remove the entry from mPendingEntries.
MutateEntryStorage("Eject", IntSize(pendingSurf.mEntry.mSize), MutateEntryStorage("Eject", IntSize(pendingSurf.mEntry.mSize),
[&]() { mPendingEntries.RemoveElementAt(i); }); [&]() { mPendingEntries.RemoveElementAt(i); });
} }
@ -238,30 +256,33 @@ uint64_t SurfacePoolCA::LockedPool::CollectPendingSurfaces(uint64_t aCheckGenera
// Move the entry from mPendingEntries to mAvailableEntries. // Move the entry from mPendingEntries to mAvailableEntries.
MOZ_RELEASE_ASSERT(pendingSurf.mEntry.mIOSurface.get(), MOZ_RELEASE_ASSERT(pendingSurf.mEntry.mIOSurface.get(),
"Pending surfaces should be non-null."); "Pending surfaces should be non-null.");
MutateEntryStorage("Stop waiting for", IntSize(pendingSurf.mEntry.mSize), [&]() { MutateEntryStorage(
mAvailableEntries.AppendElement(std::move(pendingSurf.mEntry)); "Stop waiting for", IntSize(pendingSurf.mEntry.mSize), [&]() {
mPendingEntries.RemoveElementAt(i); mAvailableEntries.AppendElement(std::move(pendingSurf.mEntry));
}); mPendingEntries.RemoveElementAt(i);
});
} }
} }
return mCollectionGeneration; return mCollectionGeneration;
} }
void SurfacePoolCA::LockedPool::OnWrapperDestroyed(gl::GLContext* aGL, void SurfacePoolCA::LockedPool::OnWrapperDestroyed(
SurfacePoolCAWrapperForGL* aWrapper) { gl::GLContext* aGL, SurfacePoolCAWrapperForGL* aWrapper) {
if (aGL) { if (aGL) {
DestroyGLResourcesForContext(aGL); DestroyGLResourcesForContext(aGL);
} }
auto iter = mWrappers.find(aGL); auto iter = mWrappers.find(aGL);
MOZ_RELEASE_ASSERT(iter != mWrappers.end()); MOZ_RELEASE_ASSERT(iter != mWrappers.end());
MOZ_RELEASE_ASSERT(iter->second == aWrapper, "Only one SurfacePoolCAWrapperForGL object should " MOZ_RELEASE_ASSERT(iter->second == aWrapper,
"exist for each GLContext* at any time"); "Only one SurfacePoolCAWrapperForGL object should "
"exist for each GLContext* at any time");
mWrappers.erase(iter); mWrappers.erase(iter);
} }
Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface( Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
CFTypeRefPtr<IOSurfaceRef> aSurface, GLContext* aGL, bool aNeedsDepthBuffer) { CFTypeRefPtr<IOSurfaceRef> aSurface, GLContext* aGL,
bool aNeedsDepthBuffer) {
MOZ_RELEASE_ASSERT(aGL); MOZ_RELEASE_ASSERT(aGL);
auto inUseEntryIter = mInUseEntries.find(aSurface); auto inUseEntryIter = mInUseEntries.find(aSurface);
@ -271,7 +292,8 @@ Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
if (entry.mGLResources) { if (entry.mGLResources) {
// We have an existing framebuffer. // We have an existing framebuffer.
MOZ_RELEASE_ASSERT(entry.mGLResources->mGLContext == aGL, MOZ_RELEASE_ASSERT(entry.mGLResources->mGLContext == aGL,
"Recycled surface that still had GL resources from a different GL context. " "Recycled surface that still had GL resources from a "
"different GL context. "
"This shouldn't happen."); "This shouldn't happen.");
if (!aNeedsDepthBuffer || entry.mGLResources->mFramebuffer->HasDepth()) { if (!aNeedsDepthBuffer || entry.mGLResources->mFramebuffer->HasDepth()) {
return Some(entry.mGLResources->mFramebuffer->mFB); return Some(entry.mGLResources->mFramebuffer->mFB);
@ -294,13 +316,16 @@ Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
GLuint tex = aGL->CreateTexture(); GLuint tex = aGL->CreateTexture();
{ {
const gl::ScopedBindTexture bindTex(aGL, tex, LOCAL_GL_TEXTURE_RECTANGLE_ARB); const gl::ScopedBindTexture bindTex(aGL, tex,
CGLTexImageIOSurface2D(cgl->GetCGLContext(), LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_RGBA, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
entry.mSize.width, entry.mSize.height, LOCAL_GL_BGRA, CGLTexImageIOSurface2D(cgl->GetCGLContext(), LOCAL_GL_TEXTURE_RECTANGLE_ARB,
LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV, entry.mIOSurface.get(), 0); LOCAL_GL_RGBA, entry.mSize.width, entry.mSize.height,
LOCAL_GL_BGRA, LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV,
entry.mIOSurface.get(), 0);
} }
auto fb = CreateFramebufferForTexture(aGL, entry.mSize, tex, aNeedsDepthBuffer); auto fb =
CreateFramebufferForTexture(aGL, entry.mSize, tex, aNeedsDepthBuffer);
if (!fb) { if (!fb) {
// Framebuffer completeness check may have failed. // Framebuffer completeness check may have failed.
return {}; return {};
@ -311,10 +336,12 @@ Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
return Some(fbo); return Some(fbo);
} }
RefPtr<gl::DepthAndStencilBuffer> SurfacePoolCA::LockedPool::GetDepthBufferForSharing( RefPtr<gl::DepthAndStencilBuffer>
GLContext* aGL, const IntSize& aSize) { SurfacePoolCA::LockedPool::GetDepthBufferForSharing(GLContext* aGL,
const IntSize& aSize) {
// Clean out entries for which the weak pointer has become null. // Clean out entries for which the weak pointer has become null.
mDepthBuffers.RemoveElementsBy([&](const DepthBufferEntry& entry) { return !entry.mBuffer; }); mDepthBuffers.RemoveElementsBy(
[&](const DepthBufferEntry& entry) { return !entry.mBuffer; });
for (const auto& entry : mDepthBuffers) { for (const auto& entry : mDepthBuffers) {
if (entry.mGLContext == aGL && entry.mSize == aSize) { if (entry.mGLContext == aGL && entry.mSize == aSize) {
@ -324,22 +351,29 @@ RefPtr<gl::DepthAndStencilBuffer> SurfacePoolCA::LockedPool::GetDepthBufferForSh
return nullptr; return nullptr;
} }
UniquePtr<gl::MozFramebuffer> SurfacePoolCA::LockedPool::CreateFramebufferForTexture( UniquePtr<gl::MozFramebuffer>
GLContext* aGL, const IntSize& aSize, GLuint aTexture, bool aNeedsDepthBuffer) { SurfacePoolCA::LockedPool::CreateFramebufferForTexture(GLContext* aGL,
const IntSize& aSize,
GLuint aTexture,
bool aNeedsDepthBuffer) {
if (aNeedsDepthBuffer) { if (aNeedsDepthBuffer) {
// Try to find an existing depth buffer of aSize in aGL and create a framebuffer that shares it. // Try to find an existing depth buffer of aSize in aGL and create a
// framebuffer that shares it.
if (auto buffer = GetDepthBufferForSharing(aGL, aSize)) { if (auto buffer = GetDepthBufferForSharing(aGL, aSize)) {
return gl::MozFramebuffer::CreateForBackingWithSharedDepthAndStencil( return gl::MozFramebuffer::CreateForBackingWithSharedDepthAndStencil(
aSize, 0, LOCAL_GL_TEXTURE_RECTANGLE_ARB, aTexture, buffer); aSize, 0, LOCAL_GL_TEXTURE_RECTANGLE_ARB, aTexture, buffer);
} }
} }
// No depth buffer needed or we didn't find one. Create a framebuffer with a new depth buffer and // No depth buffer needed or we didn't find one. Create a framebuffer with a
// store a weak pointer to the new depth buffer in mDepthBuffers. // new depth buffer and store a weak pointer to the new depth buffer in
// mDepthBuffers.
UniquePtr<gl::MozFramebuffer> fb = gl::MozFramebuffer::CreateForBacking( UniquePtr<gl::MozFramebuffer> fb = gl::MozFramebuffer::CreateForBacking(
aGL, aSize, 0, aNeedsDepthBuffer, LOCAL_GL_TEXTURE_RECTANGLE_ARB, aTexture); aGL, aSize, 0, aNeedsDepthBuffer, LOCAL_GL_TEXTURE_RECTANGLE_ARB,
aTexture);
if (fb && fb->GetDepthAndStencilBuffer()) { if (fb && fb->GetDepthAndStencilBuffer()) {
mDepthBuffers.AppendElement(DepthBufferEntry{aGL, aSize, fb->GetDepthAndStencilBuffer().get()}); mDepthBuffers.AppendElement(
DepthBufferEntry{aGL, aSize, fb->GetDepthAndStencilBuffer().get()});
} }
return fb; return fb;
@ -347,8 +381,9 @@ UniquePtr<gl::MozFramebuffer> SurfacePoolCA::LockedPool::CreateFramebufferForTex
// SurfacePoolHandleCA // SurfacePoolHandleCA
SurfacePoolHandleCA::SurfacePoolHandleCA(RefPtr<SurfacePoolCAWrapperForGL>&& aPoolWrapper, SurfacePoolHandleCA::SurfacePoolHandleCA(
uint64_t aCurrentCollectionGeneration) RefPtr<SurfacePoolCAWrapperForGL>&& aPoolWrapper,
uint64_t aCurrentCollectionGeneration)
: mPoolWrapper(aPoolWrapper), : mPoolWrapper(aPoolWrapper),
mPreviousFrameCollectionGeneration( mPreviousFrameCollectionGeneration(
"SurfacePoolHandleCA::mPreviousFrameCollectionGeneration") { "SurfacePoolHandleCA::mPreviousFrameCollectionGeneration") {
@ -363,20 +398,24 @@ void SurfacePoolHandleCA::OnBeginFrame() {
*generation = mPoolWrapper->mPool->CollectPendingSurfaces(*generation); *generation = mPoolWrapper->mPool->CollectPendingSurfaces(*generation);
} }
void SurfacePoolHandleCA::OnEndFrame() { mPoolWrapper->mPool->EnforcePoolSizeLimit(); } void SurfacePoolHandleCA::OnEndFrame() {
mPoolWrapper->mPool->EnforcePoolSizeLimit();
}
CFTypeRefPtr<IOSurfaceRef> SurfacePoolHandleCA::ObtainSurfaceFromPool(const IntSize& aSize) { CFTypeRefPtr<IOSurfaceRef> SurfacePoolHandleCA::ObtainSurfaceFromPool(
const IntSize& aSize) {
return mPoolWrapper->mPool->ObtainSurfaceFromPool(aSize, mPoolWrapper->mGL); return mPoolWrapper->mPool->ObtainSurfaceFromPool(aSize, mPoolWrapper->mGL);
} }
void SurfacePoolHandleCA::ReturnSurfaceToPool(CFTypeRefPtr<IOSurfaceRef> aSurface) { void SurfacePoolHandleCA::ReturnSurfaceToPool(
CFTypeRefPtr<IOSurfaceRef> aSurface) {
mPoolWrapper->mPool->ReturnSurfaceToPool(aSurface); mPoolWrapper->mPool->ReturnSurfaceToPool(aSurface);
} }
Maybe<GLuint> SurfacePoolHandleCA::GetFramebufferForSurface(CFTypeRefPtr<IOSurfaceRef> aSurface, Maybe<GLuint> SurfacePoolHandleCA::GetFramebufferForSurface(
bool aNeedsDepthBuffer) { CFTypeRefPtr<IOSurfaceRef> aSurface, bool aNeedsDepthBuffer) {
return mPoolWrapper->mPool->GetFramebufferForSurface(aSurface, mPoolWrapper->mGL, return mPoolWrapper->mPool->GetFramebufferForSurface(
aNeedsDepthBuffer); aSurface, mPoolWrapper->mGL, aNeedsDepthBuffer);
} }
// SurfacePoolCA // SurfacePoolCA
@ -405,8 +444,8 @@ void SurfacePoolCA::DestroyGLResourcesForContext(GLContext* aGL) {
pool->DestroyGLResourcesForContext(aGL); pool->DestroyGLResourcesForContext(aGL);
} }
CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::ObtainSurfaceFromPool(const IntSize& aSize, CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::ObtainSurfaceFromPool(
GLContext* aGL) { const IntSize& aSize, GLContext* aGL) {
auto pool = mPool.Lock(); auto pool = mPool.Lock();
return pool->ObtainSurfaceFromPool(aSize, aGL); return pool->ObtainSurfaceFromPool(aSize, aGL);
} }
@ -425,13 +464,15 @@ void SurfacePoolCA::EnforcePoolSizeLimit() {
pool->EnforcePoolSizeLimit(); pool->EnforcePoolSizeLimit();
} }
Maybe<GLuint> SurfacePoolCA::GetFramebufferForSurface(CFTypeRefPtr<IOSurfaceRef> aSurface, Maybe<GLuint> SurfacePoolCA::GetFramebufferForSurface(
GLContext* aGL, bool aNeedsDepthBuffer) { CFTypeRefPtr<IOSurfaceRef> aSurface, GLContext* aGL,
bool aNeedsDepthBuffer) {
auto pool = mPool.Lock(); auto pool = mPool.Lock();
return pool->GetFramebufferForSurface(aSurface, aGL, aNeedsDepthBuffer); return pool->GetFramebufferForSurface(aSurface, aGL, aNeedsDepthBuffer);
} }
void SurfacePoolCA::OnWrapperDestroyed(gl::GLContext* aGL, SurfacePoolCAWrapperForGL* aWrapper) { void SurfacePoolCA::OnWrapperDestroyed(gl::GLContext* aGL,
SurfacePoolCAWrapperForGL* aWrapper) {
auto pool = mPool.Lock(); auto pool = mPool.Lock();
return pool->OnWrapperDestroyed(aGL, aWrapper); return pool->OnWrapperDestroyed(aGL, aWrapper);
} }

View file

@ -15,10 +15,14 @@
namespace mozilla::gfx { namespace mozilla::gfx {
static size_t PutBytesNull(void* info, const void* buffer, size_t count) { return count; } static size_t PutBytesNull(void* info, const void* buffer, size_t count) {
return count;
}
PrintTargetCG::PrintTargetCG(CGContextRef aPrintToStreamContext, PMPrintSession aPrintSession, PrintTargetCG::PrintTargetCG(CGContextRef aPrintToStreamContext,
PMPageFormat aPageFormat, PMPrintSettings aPrintSettings, PMPrintSession aPrintSession,
PMPageFormat aPageFormat,
PMPrintSettings aPrintSettings,
const IntSize& aSize) const IntSize& aSize)
: PrintTarget(/* aCairoSurface */ nullptr, aSize), : PrintTarget(/* aCairoSurface */ nullptr, aSize),
mPrintToStreamContext(aPrintToStreamContext), mPrintToStreamContext(aPrintToStreamContext),
@ -53,14 +57,16 @@ PrintTargetCG::~PrintTargetCG() {
NS_OBJC_END_TRY_IGNORE_BLOCK; NS_OBJC_END_TRY_IGNORE_BLOCK;
} }
static size_t WriteStreamBytes(void* aInfo, const void* aBuffer, size_t aCount) { static size_t WriteStreamBytes(void* aInfo, const void* aBuffer,
size_t aCount) {
auto* stream = static_cast<nsIOutputStream*>(aInfo); auto* stream = static_cast<nsIOutputStream*>(aInfo);
auto* data = static_cast<const char*>(aBuffer); auto* data = static_cast<const char*>(aBuffer);
size_t remaining = aCount; size_t remaining = aCount;
do { do {
uint32_t wrote = 0; uint32_t wrote = 0;
// Handle potential narrowing from size_t to uint32_t. // Handle potential narrowing from size_t to uint32_t.
uint32_t toWrite = uint32_t(std::min(remaining, size_t(std::numeric_limits<uint32_t>::max()))); uint32_t toWrite = uint32_t(
std::min(remaining, size_t(std::numeric_limits<uint32_t>::max())));
if (NS_WARN_IF(NS_FAILED(stream->Write(data, toWrite, &wrote)))) { if (NS_WARN_IF(NS_FAILED(stream->Write(data, toWrite, &wrote)))) {
break; break;
} }
@ -87,21 +93,25 @@ static CGContextRef CreatePrintToStreamContext(nsIOutputStream* aOutputStream,
CGDataConsumerRef consumer = CGDataConsumerCreate(aOutputStream, &callbacks); CGDataConsumerRef consumer = CGDataConsumerCreate(aOutputStream, &callbacks);
// This metadata is added by the CorePrinting APIs in the non-stream case. // This metadata is added by the CorePrinting APIs in the non-stream case.
NSString* bundleName = NSString* bundleName = [NSBundle.mainBundle.localizedInfoDictionary
[NSBundle.mainBundle.localizedInfoDictionary objectForKey:(NSString*)kCFBundleNameKey]; objectForKey:(NSString*)kCFBundleNameKey];
CFMutableDictionaryRef auxiliaryInfo = CFDictionaryCreateMutable( CFMutableDictionaryRef auxiliaryInfo = CFDictionaryCreateMutable(
kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks,
CFDictionaryAddValue(auxiliaryInfo, kCGPDFContextCreator, (__bridge CFStringRef)bundleName); &kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(auxiliaryInfo, kCGPDFContextCreator,
(__bridge CFStringRef)bundleName);
CGContextRef pdfContext = CGPDFContextCreate(consumer, &pageBox, auxiliaryInfo); CGContextRef pdfContext =
CGPDFContextCreate(consumer, &pageBox, auxiliaryInfo);
CGDataConsumerRelease(consumer); CGDataConsumerRelease(consumer);
CFRelease(auxiliaryInfo); CFRelease(auxiliaryInfo);
return pdfContext; return pdfContext;
} }
/* static */ already_AddRefed<PrintTargetCG> PrintTargetCG::CreateOrNull( /* static */ already_AddRefed<PrintTargetCG> PrintTargetCG::CreateOrNull(
nsIOutputStream* aOutputStream, PMPrintSession aPrintSession, PMPageFormat aPageFormat, nsIOutputStream* aOutputStream, PMPrintSession aPrintSession,
PMPrintSettings aPrintSettings, const IntSize& aSize) { PMPageFormat aPageFormat, PMPrintSettings aPrintSettings,
const IntSize& aSize) {
if (!Factory::CheckSurfaceSize(aSize)) { if (!Factory::CheckSurfaceSize(aSize)) {
return nullptr; return nullptr;
} }
@ -114,8 +124,8 @@ static CGContextRef CreatePrintToStreamContext(nsIOutputStream* aOutputStream,
} }
} }
RefPtr<PrintTargetCG> target = RefPtr<PrintTargetCG> target = new PrintTargetCG(
new PrintTargetCG(printToStreamContext, aPrintSession, aPageFormat, aPrintSettings, aSize); printToStreamContext, aPrintSession, aPageFormat, aPrintSettings, aSize);
return target.forget(); return target.forget();
} }
@ -129,8 +139,8 @@ already_AddRefed<DrawTarget> PrintTargetCG::GetReferenceDrawTarget() {
CGContextRef pdfContext = CGPDFContextCreate(consumer, nullptr, nullptr); CGContextRef pdfContext = CGPDFContextCreate(consumer, nullptr, nullptr);
CGDataConsumerRelease(consumer); CGDataConsumerRelease(consumer);
cairo_surface_t* similar = cairo_surface_t* similar = cairo_quartz_surface_create_for_cg_context(
cairo_quartz_surface_create_for_cg_context(pdfContext, size.width, size.height); pdfContext, size.width, size.height);
CGContextRelease(pdfContext); CGContextRelease(pdfContext);
@ -138,7 +148,8 @@ already_AddRefed<DrawTarget> PrintTargetCG::GetReferenceDrawTarget() {
return nullptr; return nullptr;
} }
RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForCairoSurface(similar, size); RefPtr<DrawTarget> dt =
Factory::CreateDrawTargetForCairoSurface(similar, size);
// The DT addrefs the surface, so we need drop our own reference to it: // The DT addrefs the surface, so we need drop our own reference to it:
cairo_surface_destroy(similar); cairo_surface_destroy(similar);
@ -152,7 +163,8 @@ already_AddRefed<DrawTarget> PrintTargetCG::GetReferenceDrawTarget() {
return do_AddRef(mRefDT); return do_AddRef(mRefDT);
} }
nsresult PrintTargetCG::BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName, nsresult PrintTargetCG::BeginPrinting(const nsAString& aTitle,
const nsAString& aPrintToFileName,
int32_t aStartPage, int32_t aEndPage) { int32_t aStartPage, int32_t aEndPage) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
@ -182,7 +194,8 @@ nsresult PrintTargetCG::BeginPrinting(const nsAString& aTitle, const nsAString&
status = ::PMSetLastPage(mPrintSettings, aEndPage, false); status = ::PMSetLastPage(mPrintSettings, aEndPage, false);
NS_ASSERTION(status == noErr, "PMSetLastPage failed"); NS_ASSERTION(status == noErr, "PMSetLastPage failed");
status = ::PMSessionBeginCGDocumentNoDialog(mPrintSession, mPrintSettings, mPageFormat); status = ::PMSessionBeginCGDocumentNoDialog(mPrintSession, mPrintSettings,
mPageFormat);
return status == noErr ? NS_OK : NS_ERROR_ABORT; return status == noErr ? NS_OK : NS_ERROR_ABORT;
@ -224,11 +237,13 @@ nsresult PrintTargetCG::BeginPage(const IntSize& aSizeInPoints) {
if (StaticPrefs::layout_css_page_orientation_enabled()) { if (StaticPrefs::layout_css_page_orientation_enabled()) {
::PMOrientation pageOrientation = ::PMOrientation pageOrientation =
aSizeInPoints.width < aSizeInPoints.height ? kPMPortrait : kPMLandscape; aSizeInPoints.width < aSizeInPoints.height ? kPMPortrait
: kPMLandscape;
::PMSetOrientation(mPageFormat, pageOrientation, kPMUnlocked); ::PMSetOrientation(mPageFormat, pageOrientation, kPMUnlocked);
// We don't need to reset the orientation, since we set it for every page. // We don't need to reset the orientation, since we set it for every page.
} }
OSStatus status = ::PMSessionBeginPageNoDialog(mPrintSession, mPageFormat, nullptr); OSStatus status =
::PMSessionBeginPageNoDialog(mPrintSession, mPageFormat, nullptr);
if (status != noErr) { if (status != noErr) {
return NS_ERROR_ABORT; return NS_ERROR_ABORT;
} }
@ -257,7 +272,8 @@ nsresult PrintTargetCG::BeginPage(const IntSize& aSizeInPoints) {
CGContextTranslateCTM(context, 0, height); CGContextTranslateCTM(context, 0, height);
CGContextScaleCTM(context, 1.0, -1.0); CGContextScaleCTM(context, 1.0, -1.0);
cairo_surface_t* surface = cairo_quartz_surface_create_for_cg_context(context, width, height); cairo_surface_t* surface =
cairo_quartz_surface_create_for_cg_context(context, width, height);
if (cairo_surface_status(surface)) { if (cairo_surface_status(surface)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;

View file

@ -63,8 +63,9 @@ static void GetStringForNSString(const NSString* aSrc, nsAString& aDest) {
} }
static NSString* GetNSStringForString(const nsAString& aSrc) { static NSString* GetNSStringForString(const nsAString& aSrc) {
return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(aSrc.BeginReading()) return [NSString
length:aSrc.Length()]; stringWithCharacters:reinterpret_cast<const unichar*>(aSrc.BeginReading())
length:aSrc.Length()];
} }
#define LOG_FONTLIST(args) \ #define LOG_FONTLIST(args) \
@ -77,7 +78,8 @@ static NSString* GetNSStringForString(const nsAString& aSrc) {
class gfxMacFontFamily final : public CTFontFamily { class gfxMacFontFamily final : public CTFontFamily {
public: public:
gfxMacFontFamily(const nsACString& aName, NSFont* aSystemFont) gfxMacFontFamily(const nsACString& aName, NSFont* aSystemFont)
: CTFontFamily(aName, FontVisibility::Unknown), mForSystemFont(aSystemFont) { : CTFontFamily(aName, FontVisibility::Unknown),
mForSystemFont(aSystemFont) {
// I don't think the system font instance is at much risk of being deleted, // I don't think the system font instance is at much risk of being deleted,
// but to be on the safe side let's retain a reference until we're finished // but to be on the safe side let's retain a reference until we're finished
// using it for lazy initialization. // using it for lazy initialization.
@ -88,9 +90,9 @@ class gfxMacFontFamily final : public CTFontFamily {
MOZ_REQUIRES(mLock) override; MOZ_REQUIRES(mLock) override;
protected: protected:
// If non-null, this is a family representing the system UI font, and should use // If non-null, this is a family representing the system UI font, and should
// the given NSFont as the basis for initialization as the normal font-manager APIs // use the given NSFont as the basis for initialization as the normal
// based on family name won't handle it. // font-manager APIs based on family name won't handle it.
NSFont* mForSystemFont = nullptr; NSFont* mForSystemFont = nullptr;
}; };
@ -99,7 +101,8 @@ void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
return; return;
} }
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("gfxMacFontFamily::FindStyleVariations", LAYOUT, mName); AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("gfxMacFontFamily::FindStyleVariations",
LAYOUT, mName);
nsAutoreleasePool localPool; nsAutoreleasePool localPool;
@ -113,12 +116,14 @@ void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
nsCocoaUtils::GetStringForNSString(psNameNS, nameUTF16); nsCocoaUtils::GetStringForNSString(psNameNS, nameUTF16);
CopyUTF16toUTF8(nameUTF16, psName); CopyUTF16toUTF8(nameUTF16, psName);
auto* fe = new CTFontEntry(psName, WeightRange(FontWeight::NORMAL), true, 0.0); auto* fe =
new CTFontEntry(psName, WeightRange(FontWeight::NORMAL), true, 0.0);
// Set the appropriate style, assuming it may not have a variation range. // Set the appropriate style, assuming it may not have a variation range.
fe->mStyleRange = SlantStyleRange( fe->mStyleRange = SlantStyleRange(
([[aNSFont fontDescriptor] symbolicTraits] & NSFontItalicTrait) ? FontSlantStyle::ITALIC ([[aNSFont fontDescriptor] symbolicTraits] & NSFontItalicTrait)
: FontSlantStyle::NORMAL); ? FontSlantStyle::ITALIC
: FontSlantStyle::NORMAL);
// Set up weight (and width, if present) ranges. // Set up weight (and width, if present) ranges.
fe->SetupVariationRanges(); fe->SetupVariationRanges();
@ -128,7 +133,8 @@ void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
addToFamily(mForSystemFont); addToFamily(mForSystemFont);
// See if there is a corresponding italic face, and add it to the family. // See if there is a corresponding italic face, and add it to the family.
NSFont* italicFont = [sFontManager convertFont:mForSystemFont toHaveTrait:NSItalicFontMask]; NSFont* italicFont = [sFontManager convertFont:mForSystemFont
toHaveTrait:NSItalicFontMask];
if (italicFont != mForSystemFont) { if (italicFont != mForSystemFont) {
addToFamily(italicFont); addToFamily(italicFont);
} }
@ -147,7 +153,8 @@ void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
class gfxSingleFaceMacFontFamily final : public gfxFontFamily { class gfxSingleFaceMacFontFamily final : public gfxFontFamily {
public: public:
gfxSingleFaceMacFontFamily(const nsACString& aName, FontVisibility aVisibility) gfxSingleFaceMacFontFamily(const nsACString& aName,
FontVisibility aVisibility)
: gfxFontFamily(aName, aVisibility) { : gfxFontFamily(aName, aVisibility) {
mFaceNamesInitialized = true; // omit from face name lists mFaceNamesInitialized = true; // omit from face name lists
} }
@ -175,8 +182,9 @@ void gfxSingleFaceMacFontFamily::LocalizedName(nsACString& aLocalizedName) {
} }
gfxFontEntry* fe = mAvailableFonts[0]; gfxFontEntry* fe = mAvailableFonts[0];
NSFont* font = [NSFont fontWithName:GetNSStringForString(NS_ConvertUTF8toUTF16(fe->Name())) NSFont* font = [NSFont
size:0.0]; fontWithName:GetNSStringForString(NS_ConvertUTF8toUTF16(fe->Name()))
size:0.0];
if (font) { if (font) {
NSString* localized = [font displayName]; NSString* localized = [font displayName];
if (localized) { if (localized) {
@ -191,7 +199,8 @@ void gfxSingleFaceMacFontFamily::LocalizedName(nsACString& aLocalizedName) {
aLocalizedName = mName; aLocalizedName = mName;
} }
void gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList* aPlatformFontList) { void gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(
gfxPlatformFontList* aPlatformFontList) {
AutoWriteLock lock(mLock); AutoWriteLock lock(mLock);
if (mOtherFamilyNamesInitialized) { if (mOtherFamilyNamesInitialized) {
return; return;
@ -209,7 +218,8 @@ void gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList* aPlat
return; return;
} }
mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable, true); mHasOtherFamilyNames =
ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable, true);
mOtherFamilyNamesInitialized = true; mOtherFamilyNamesInitialized = true;
} }
@ -229,7 +239,8 @@ gfxMacPlatformFontList::gfxMacPlatformFontList() : CoreTextFontList() {
gfxFontUtils::GetPrefsFontList("font.single-face-list", mSingleFaceFonts); gfxFontUtils::GetPrefsFontList("font.single-face-list", mSingleFaceFonts);
} }
FontVisibility gfxMacPlatformFontList::GetVisibilityForFamily(const nsACString& aName) const { FontVisibility gfxMacPlatformFontList::GetVisibilityForFamily(
const nsACString& aName) const {
if (aName[0] == '.' || aName.LowerCaseEqualsLiteral("lastresort")) { if (aName[0] == '.' || aName.LowerCaseEqualsLiteral("lastresort")) {
return FontVisibility::Hidden; return FontVisibility::Hidden;
} }
@ -244,7 +255,8 @@ FontVisibility gfxMacPlatformFontList::GetVisibilityForFamily(const nsACString&
return FontVisibility::User; return FontVisibility::User;
} }
bool gfxMacPlatformFontList::DeprecatedFamilyIsAvailable(const nsACString& aName) { bool gfxMacPlatformFontList::DeprecatedFamilyIsAvailable(
const nsACString& aName) {
NSString* family = GetNSStringForString(NS_ConvertUTF8toUTF16(aName)); NSString* family = GetNSStringForString(NS_ConvertUTF8toUTF16(aName));
return [[sFontManager availableMembersOfFontFamily:family] count] > 0; return [[sFontManager availableMembersOfFontFamily:family] count] > 0;
} }
@ -364,7 +376,8 @@ void gfxMacPlatformFontList::InitSingleFaceList() {
// We found the correct face, so create the single-face family record. // We found the correct face, so create the single-face family record.
GenerateFontListKey(aliasName, key); GenerateFontListKey(aliasName, key);
LOG_FONTLIST(("(fontlist-singleface) family name: %s, key: %s\n", aliasName.get(), key.get())); LOG_FONTLIST(("(fontlist-singleface) family name: %s, key: %s\n",
aliasName.get(), key.get()));
// add only if doesn't exist already // add only if doesn't exist already
if (!mFontFamilies.GetWeak(key)) { if (!mFontFamilies.GetWeak(key)) {
@ -372,13 +385,14 @@ void gfxMacPlatformFontList::InitSingleFaceList() {
new gfxSingleFaceMacFontFamily(aliasName, family->Visibility()); new gfxSingleFaceMacFontFamily(aliasName, family->Visibility());
// We need a separate font entry, because its family name will // We need a separate font entry, because its family name will
// differ from the one we found in the main list. // differ from the one we found in the main list.
CTFontEntry* fontEntry = new CTFontEntry(fe->Name(), fe->Weight(), true, CTFontEntry* fontEntry =
static_cast<const CTFontEntry*>(fe)->mSizeHint); new CTFontEntry(fe->Name(), fe->Weight(), true,
static_cast<const CTFontEntry*>(fe)->mSizeHint);
familyEntry->AddFontEntry(fontEntry); familyEntry->AddFontEntry(fontEntry);
familyEntry->SetHasStyles(true); familyEntry->SetHasStyles(true);
mFontFamilies.InsertOrUpdate(key, std::move(familyEntry)); mFontFamilies.InsertOrUpdate(key, std::move(familyEntry));
LOG_FONTLIST( LOG_FONTLIST(("(fontlist-singleface) added new family: %s, key: %s\n",
("(fontlist-singleface) added new family: %s, key: %s\n", aliasName.get(), key.get())); aliasName.get(), key.get()));
} }
} }
} }
@ -404,12 +418,14 @@ static NSString* GetRealFamilyName(NSFont* aFont) {
// Eventually we should move to using CTFontUIFontType constants to identify // Eventually we should move to using CTFontUIFontType constants to identify
// system fonts, and eliminate the need to instantiate them (indirectly) from // system fonts, and eliminate the need to instantiate them (indirectly) from
// their postscript names. // their postscript names.
AutoCFRelease<CGFontRef> cgFont = CGFontCreateWithFontName(CFStringRef(psName)); AutoCFRelease<CGFontRef> cgFont =
CGFontCreateWithFontName(CFStringRef(psName));
if (!cgFont) { if (!cgFont) {
return [aFont familyName]; return [aFont familyName];
} }
AutoCFRelease<CTFontRef> ctFont = CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr); AutoCFRelease<CTFontRef> ctFont =
CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr);
if (!ctFont) { if (!ctFont) {
return [aFont familyName]; return [aFont familyName];
} }
@ -441,7 +457,8 @@ void gfxMacPlatformFontList::InitSystemFontNames() {
// the hidden system fonts may be excluded from the font list altogether. // the hidden system fonts may be excluded from the font list altogether.
if (nsCocoaFeatures::OnCatalinaOrLater()) { if (nsCocoaFeatures::OnCatalinaOrLater()) {
// This family will be populated based on the given NSFont. // This family will be populated based on the given NSFont.
RefPtr<gfxFontFamily> fam = new gfxMacFontFamily(mSystemTextFontFamilyName, sys); RefPtr<gfxFontFamily> fam =
new gfxMacFontFamily(mSystemTextFontFamilyName, sys);
if (fam) { if (fam) {
nsAutoCString key; nsAutoCString key;
GenerateFontListKey(mSystemTextFontFamilyName, key); GenerateFontListKey(mSystemTextFontFamilyName, key);
@ -465,20 +482,23 @@ void gfxMacPlatformFontList::InitSystemFontNames() {
// different system font API's always map to the same family under OSX, so // different system font API's always map to the same family under OSX, so
// just assume that and emit a warning if that ever changes // just assume that and emit a warning if that ever changes
NSString* sysFamily = GetRealFamilyName([NSFont systemFontOfSize:0.0]); NSString* sysFamily = GetRealFamilyName([NSFont systemFontOfSize:0.0]);
if ([sysFamily compare:GetRealFamilyName([NSFont boldSystemFontOfSize:0.0])] != NSOrderedSame || if ([sysFamily compare:GetRealFamilyName([NSFont
[sysFamily compare:GetRealFamilyName([NSFont controlContentFontOfSize:0.0])] != boldSystemFontOfSize:0.0])] != NSOrderedSame ||
[sysFamily compare:GetRealFamilyName([NSFont
controlContentFontOfSize:0.0])] != NSOrderedSame ||
[sysFamily compare:GetRealFamilyName([NSFont menuBarFontOfSize:0.0])] !=
NSOrderedSame || NSOrderedSame ||
[sysFamily compare:GetRealFamilyName([NSFont menuBarFontOfSize:0.0])] != NSOrderedSame || [sysFamily compare:GetRealFamilyName([NSFont toolTipsFontOfSize:0.0])] !=
[sysFamily compare:GetRealFamilyName([NSFont toolTipsFontOfSize:0.0])] != NSOrderedSame) { NSOrderedSame) {
NS_WARNING("system font types map to different font families" NS_WARNING("system font types map to different font families"
" -- please log a bug!!"); " -- please log a bug!!");
} }
#endif #endif
} }
FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform(nsPresContext* aPresContext, FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform(
const gfxFontStyle* aStyle, nsPresContext* aPresContext, const gfxFontStyle* aStyle,
nsAtom* aLanguage) { nsAtom* aLanguage) {
nsAutoreleasePool localPool; nsAutoreleasePool localPool;
NSString* defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName]; NSString* defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
@ -538,11 +558,14 @@ void gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID,
} }
NSFontSymbolicTraits traits = [[font fontDescriptor] symbolicTraits]; NSFontSymbolicTraits traits = [[font fontDescriptor] symbolicTraits];
aFontStyle.style = (traits & NSFontItalicTrait) ? FontSlantStyle::ITALIC : FontSlantStyle::NORMAL; aFontStyle.style = (traits & NSFontItalicTrait) ? FontSlantStyle::ITALIC
aFontStyle.weight = (traits & NSFontBoldTrait) ? FontWeight::BOLD : FontWeight::NORMAL; : FontSlantStyle::NORMAL;
aFontStyle.stretch = (traits & NSFontExpandedTrait) ? FontStretch::EXPANDED aFontStyle.weight =
: (traits & NSFontCondensedTrait) ? FontStretch::CONDENSED (traits & NSFontBoldTrait) ? FontWeight::BOLD : FontWeight::NORMAL;
: FontStretch::NORMAL; aFontStyle.stretch = (traits & NSFontExpandedTrait) ? FontStretch::EXPANDED
: (traits & NSFontCondensedTrait)
? FontStretch::CONDENSED
: FontStretch::NORMAL;
aFontStyle.size = [font pointSize]; aFontStyle.size = [font pointSize];
aFontStyle.systemFont = true; aFontStyle.systemFont = true;
} }

View file

@ -21,7 +21,8 @@ static io_connect_t sDataPort = IO_OBJECT_NULL;
static uint64_t sLastMean = -1; static uint64_t sLastMean = -1;
static float LMUvalueToLux(uint64_t aValue) { static float LMUvalueToLux(uint64_t aValue) {
// Conversion formula from regression. See Bug 793728. // Conversion formula from regression. See Bug 793728.
// -3*(10^-27)*x^4 + 2.6*(10^-19)*x^3 + -3.4*(10^-12)*x^2 + 3.9*(10^-5)*x - 0.19 // -3*(10^-27)*x^4 + 2.6*(10^-19)*x^3 + -3.4*(10^-12)*x^2 + 3.9*(10^-5)*x -
// 0.19
long double powerC4 = 1 / pow((long double)10, 27); long double powerC4 = 1 / pow((long double)10, 27);
long double powerC3 = 1 / pow((long double)10, 19); long double powerC3 = 1 / pow((long double)10, 19);
long double powerC2 = 1 / pow((long double)10, 12); long double powerC2 = 1 / pow((long double)10, 12);
@ -54,7 +55,8 @@ void UpdateHandler(nsITimer* aTimer, void* aClosure) {
uint32_t outputs = 2; uint32_t outputs = 2;
uint64_t lightLMU[outputs]; uint64_t lightLMU[outputs];
kr = IOConnectCallMethod(sDataPort, 0, nil, 0, nil, 0, lightLMU, &outputs, nil, 0); kr = IOConnectCallMethod(sDataPort, 0, nil, 0, nil, 0, lightLMU, &outputs,
nil, 0);
if (kr == KERN_SUCCESS) { if (kr == KERN_SUCCESS) {
uint64_t mean = (lightLMU[0] + lightLMU[1]) / 2; uint64_t mean = (lightLMU[0] + lightLMU[1]) / 2;
if (mean == sLastMean) { if (mean == sLastMean) {
@ -84,8 +86,8 @@ void EnableSensorNotifications(SensorType aSensor) {
} }
} else if (aSensor == SENSOR_LIGHT) { } else if (aSensor == SENSOR_LIGHT) {
io_service_t serviceObject; io_service_t serviceObject;
serviceObject = serviceObject = IOServiceGetMatchingService(
IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleLMUController")); kIOMasterPortDefault, IOServiceMatching("AppleLMUController"));
if (!serviceObject) { if (!serviceObject) {
return; return;
} }
@ -104,14 +106,15 @@ void EnableSensorNotifications(SensorType aSensor) {
if (!sUpdateTimer) { if (!sUpdateTimer) {
CallCreateInstance("@mozilla.org/timer;1", &sUpdateTimer); CallCreateInstance("@mozilla.org/timer;1", &sUpdateTimer);
if (sUpdateTimer) { if (sUpdateTimer) {
sUpdateTimer->InitWithNamedFuncCallback(UpdateHandler, nullptr, DEFAULT_SENSOR_POLL, sUpdateTimer->InitWithNamedFuncCallback(
nsITimer::TYPE_REPEATING_SLACK, UpdateHandler, nullptr, DEFAULT_SENSOR_POLL,
"hal_impl::UpdateHandler"); nsITimer::TYPE_REPEATING_SLACK, "hal_impl::UpdateHandler");
} }
} }
} }
void DisableSensorNotifications(SensorType aSensor) { void DisableSensorNotifications(SensorType aSensor) {
if (!sActiveSensors[aSensor] || (aSensor != SENSOR_ACCELERATION && aSensor != SENSOR_LIGHT)) { if (!sActiveSensors[aSensor] ||
(aSensor != SENSOR_ACCELERATION && aSensor != SENSOR_LIGHT)) {
return; return;
} }

View file

@ -80,20 +80,21 @@ typedef struct sensorSpec {
// //
// These values came from SeisMaCalibrate calibration reports. In general I've // These values came from SeisMaCalibrate calibration reports. In general I've
// found the following: // found the following:
// - All Intel-based SMSs have 250 counts per g, centered on 0, but the signs // - All Intel-based SMSs have 250 counts per g, centered on 0, but the
// are different (and in one case two axes are swapped) // signs are different (and in one case two axes are swapped)
// - PowerBooks and iBooks all have sensors centered on 0, and reading // - PowerBooks and iBooks all have sensors centered on 0, and reading
// 50-53 steps per gravity (but with differing polarities!) // 50-53 steps per gravity (but with differing polarities!)
// - PowerBooks and iBooks of the same model all have the same axis polarities // - PowerBooks and iBooks of the same model all have the same axis
// polarities
// - PowerBook and iBook access methods are model- and OS version-specific // - PowerBook and iBook access methods are model- and OS version-specific
// //
// So, the sequence of tests is: // So, the sequence of tests is:
// - Try model-specific access methods. Note that the test is for a match to the // - Try model-specific access methods. Note that the test is for a match
// beginning of the model name, e.g. the record with model name "MacBook" // to the beginning of the model name, e.g. the record with model name
// matches computer models "MacBookPro1,2" and "MacBook1,1" (and "" // "MacBook" matches computer models "MacBookPro1,2" and "MacBook1,1" (and ""
// matches any model). // matches any model).
// - If no model-specific record's access fails, then try each model-independent // - If no model-specific record's access fails, then try each
// access method in order, stopping when one works. // model-independent access method in order, stopping when one works.
static const sensorSpec sensors[] = { static const sensorSpec sensors[] = {
// ****** Model-dependent methods ****** // ****** Model-dependent methods ******
// The PowerBook5,6 is one of the G4 models that seems to lose // The PowerBook5,6 is one of the G4 models that seems to lose
@ -142,7 +143,8 @@ static const sensorSpec sensors[] = {
5, 5,
40, 40,
{{1, 0, 2, 0, 251}, {1, 2, 2, 0, -251}, {1, 4, 2, 0, -251}}}, {{1, 0, 2, 0, 251}, {1, 2, 2, 0, -251}, {1, 4, 2, 0, -251}}},
// MacBook Pro Core 2 Duo 15" AND 17" with LED backlight, introduced June '07. // MacBook Pro Core 2 Duo 15" AND 17" with LED backlight, introduced June
// '07.
// NOTE! The 17" machines have the signs of their X and Y axes reversed // NOTE! The 17" machines have the signs of their X and Y axes reversed
// from this calibration, but there's no clear way to discriminate between // from this calibration, but there's no clear way to discriminate between
// the two machines. // the two machines.
@ -169,7 +171,8 @@ static const sensorSpec sensors[] = {
5, 5,
40, 40,
{{1, 0, 2, 0, -251}, {1, 2, 2, 0, -251}, {1, 4, 2, 0, 251}}}, {{1, 0, 2, 0, -251}, {1, 2, 2, 0, -251}, {1, 4, 2, 0, 251}}},
// This is speculative, based on a single user's report. Looks like the X and Y axes // This is speculative, based on a single user's report. Looks like the X
// and Y axes
// are swapped. This is true for no other known Appple laptop. // are swapped. This is true for no other known Appple laptop.
{"MacBookPro5,3", {"MacBookPro5,3",
"SMCMotionSensor", "SMCMotionSensor",
@ -185,10 +188,18 @@ static const sensorSpec sensors[] = {
// ****** Model-independent methods ****** // ****** Model-independent methods ******
// Seen once with PowerBook6,8 under system 10.3.9; I suspect // Seen once with PowerBook6,8 under system 10.3.9; I suspect
// other G4-based 10.3.* systems might use this // other G4-based 10.3.* systems might use this
{"", "IOI2CMotionSensor", 24, 60, {{1, 0, 1, 0, 51.5}, {1, 1, 1, 0, 51.5}, {1, 2, 1, 0, 51.5}}}, {"",
"IOI2CMotionSensor",
24,
60,
{{1, 0, 1, 0, 51.5}, {1, 1, 1, 0, 51.5}, {1, 2, 1, 0, 51.5}}},
// PowerBook5,6 , PowerBook5,7 , PowerBook6,7 , PowerBook6,8 // PowerBook5,6 , PowerBook5,7 , PowerBook6,7 , PowerBook6,8
// under OS X 10.4.* // under OS X 10.4.*
{"", "IOI2CMotionSensor", 21, 60, {{1, 0, 1, 0, 51.5}, {1, 1, 1, 0, 51.5}, {1, 2, 1, 0, 51.5}}}, {"",
"IOI2CMotionSensor",
21,
60,
{{1, 0, 1, 0, 51.5}, {1, 1, 1, 0, 51.5}, {1, 2, 1, 0, 51.5}}},
// PowerBook5,8 , PowerBook5,9 under OS X 10.4.* // PowerBook5,8 , PowerBook5,9 under OS X 10.4.*
{"", {"",
"PMUMotionSensor", "PMUMotionSensor",
@ -200,9 +211,11 @@ static const sensorSpec sensors[] = {
{1, 0, 1, 0, -51.5}, {1, 0, 1, 0, -51.5},
{1, 1, 1, -6, -51.5}, {1, 1, 1, -6, -51.5},
{1, 2, 1, 0, -51.5}}}, {1, 2, 1, 0, -51.5}}},
// All MacBook, MacBookPro models. Hardware (at least on early MacBookPro 15") // All MacBook, MacBookPro models. Hardware (at least on early MacBookPro
// 15")
// is Kionix KXM52-1050 three-axis accelerometer chip. Data is at // is Kionix KXM52-1050 three-axis accelerometer chip. Data is at
// http://kionix.com/Product-Index/product-index.htm. Specific MB and MBP models // http://kionix.com/Product-Index/product-index.htm. Specific MB and MBP
// models
// that use this are: // that use this are:
// MacBook1,1 // MacBook1,1
// MacBook2,1 // MacBook2,1
@ -215,13 +228,18 @@ static const sensorSpec sensors[] = {
// MacBookPro1,2 // MacBookPro1,2
// MacBookPro4,1 // MacBookPro4,1
// MacBookPro5,5 // MacBookPro5,5
{"", "SMCMotionSensor", 5, 40, {{1, 0, 2, 0, 251}, {1, 2, 2, 0, 251}, {1, 4, 2, 0, 251}}}}; {"",
"SMCMotionSensor",
5,
40,
{{1, 0, 2, 0, 251}, {1, 2, 2, 0, 251}, {1, 4, 2, 0, 251}}}};
#define SENSOR_COUNT (sizeof(sensors) / sizeof(sensorSpec)) #define SENSOR_COUNT (sizeof(sensors) / sizeof(sensorSpec))
#pragma mark Internal prototypes #pragma mark Internal prototypes
static int getData(sms_acceleration* accel, int calibrated, id logObject, SEL logSelector); static int getData(sms_acceleration* accel, int calibrated, id logObject,
SEL logSelector);
static float getAxis(int which, int calibrated); static float getAxis(int which, int calibrated);
static int signExtend(int value, int size); static int signExtend(int value, int size);
static NSString* getModelName(void); static NSString* getModelName(void);
@ -259,7 +277,8 @@ static float onegs[3]; // X, Y and Z one-g calibration values
// Name of configuration for given axis' zero (axis specified by integer) // Name of configuration for given axis' zero (axis specified by integer)
#define ZERO_NAME(a) [NSString stringWithFormat:@"%@-Axis-Zero", INT_TO_AXIS(a)] #define ZERO_NAME(a) [NSString stringWithFormat:@"%@-Axis-Zero", INT_TO_AXIS(a)]
// Name of configuration for given axis' oneg (axis specified by integer) // Name of configuration for given axis' oneg (axis specified by integer)
#define ONEG_NAME(a) [NSString stringWithFormat:@"%@-Axis-One-g", INT_TO_AXIS(a)] #define ONEG_NAME(a) \
[NSString stringWithFormat:@"%@-Axis-One-g", INT_TO_AXIS(a)]
// Name of "Is calibrated" preference // Name of "Is calibrated" preference
#define CALIBRATED_NAME (@"Calibrated") #define CALIBRATED_NAME (@"Calibrated")
// Application domain for SeisMac library // Application domain for SeisMac library
@ -271,19 +290,22 @@ static float onegs[3]; // X, Y and Z one-g calibration values
if (logObject) { \ if (logObject) { \
[logObject performSelector:logSelector withObject:message]; \ [logObject performSelector:logSelector withObject:message]; \
} }
#define LOG_ARG(format, var1) \ #define LOG_ARG(format, var1) \
if (logObject) { \ if (logObject) { \
[logObject performSelector:logSelector withObject:[NSString stringWithFormat:format, var1]]; \ [logObject performSelector:logSelector \
withObject:[NSString stringWithFormat:format, var1]]; \
} }
#define LOG_2ARG(format, var1, var2) \ #define LOG_2ARG(format, var1, var2) \
if (logObject) { \ if (logObject) { \
[logObject performSelector:logSelector \ [logObject \
withObject:[NSString stringWithFormat:format, var1, var2]]; \ performSelector:logSelector \
withObject:[NSString stringWithFormat:format, var1, var2]]; \
} }
#define LOG_3ARG(format, var1, var2, var3) \ #define LOG_3ARG(format, var1, var2, var3) \
if (logObject) { \ if (logObject) { \
[logObject performSelector:logSelector \ [logObject \
withObject:[NSString stringWithFormat:format, var1, var2, var3]]; \ performSelector:logSelector \
withObject:[NSString stringWithFormat:format, var1, var2, var3]]; \
} }
#pragma mark Function definitions #pragma mark Function definitions
@ -322,11 +344,12 @@ int smsStartup(id logObject, SEL logSelector) {
recordSize = sensors[sensorNum].recordSize; recordSize = sensors[sensorNum].recordSize;
function = sensors[sensorNum].function; function = sensors[sensorNum].function;
LOG_3ARG(@"Trying service \"%s\" with selector %d and %d byte record:\n", serviceName, function, LOG_3ARG(@"Trying service \"%s\" with selector %d and %d byte record:\n",
recordSize); serviceName, function, recordSize);
NSString* targetName = [NSString stringWithCString:sensors[sensorNum].model NSString* targetName =
encoding:NSMacOSRomanStringEncoding]; [NSString stringWithCString:sensors[sensorNum].model
encoding:NSMacOSRomanStringEncoding];
LOG_ARG(@" Comparing model name to target \"%@\": ", targetName); LOG_ARG(@" Comparing model name to target \"%@\": ", targetName);
if ([targetName length] == 0 || [modelName hasPrefix:targetName]) { if ([targetName length] == 0 || [modelName hasPrefix:targetName]) {
LOG(@"success.\n"); LOG(@"success.\n");
@ -350,7 +373,8 @@ int smsStartup(id logObject, SEL logSelector) {
} }
LOG(@" Getting list of matching services: "); LOG(@" Getting list of matching services: ");
result = IOServiceGetMatchingServices(kIOMasterPortDefault, dict, &iterator); result =
IOServiceGetMatchingServices(kIOMasterPortDefault, dict, &iterator);
if (result == KERN_SUCCESS) { if (result == KERN_SUCCESS) {
LOG(@"success.\n"); LOG(@"success.\n");
@ -386,7 +410,9 @@ int smsStartup(id logObject, SEL logSelector) {
} }
continue; continue;
} else if (connection == 0) { } else if (connection == 0) {
LOG_ARG(@"'success', but didn't get a connection (return value was: 0x%x).\n", result); LOG_ARG(
@"'success', but didn't get a connection (return value was: 0x%x).\n",
result);
IOObjectRelease(device); IOObjectRelease(device);
if (failure_result < SMS_FAIL_CONNECTION) { if (failure_result < SMS_FAIL_CONNECTION) {
failure_result = SMS_FAIL_CONNECTION; failure_result = SMS_FAIL_CONNECTION;
@ -551,14 +577,15 @@ void smsGetBufferData(char* buffer) {
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
const size_t InStructSize = recordSize; const size_t InStructSize = recordSize;
size_t OutStructSize = recordSize; size_t OutStructSize = recordSize;
result = result = IOConnectCallStructMethod(connection,
IOConnectCallStructMethod(connection, function, // magic kernel function number
function, // magic kernel function number (const void*)iRecord, InStructSize,
(const void*)iRecord, InStructSize, (void*)buffer, &OutStructSize); (void*)buffer, &OutStructSize);
#else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050 #else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
result = IOConnectMethodStructureIStructureO(connection, result = IOConnectMethodStructureIStructureO(
function, // magic kernel function number connection,
iSize, &oSize, iRecord, buffer); function, // magic kernel function number
iSize, &oSize, iRecord, buffer);
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050 #endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
if (result != KERN_SUCCESS) { if (result != KERN_SUCCESS) {
@ -580,9 +607,10 @@ NSString* smsGetCalibrationDescription(void) {
[s appendString:@"---- SeisMac Calibration Record ----\n \n"]; [s appendString:@"---- SeisMac Calibration Record ----\n \n"];
[s appendFormat:@"Machine model: %@\n", getModelName()]; [s appendFormat:@"Machine model: %@\n", getModelName()];
[s appendFormat:@"OS X build: %@\n", getOSVersion()]; [s appendFormat:@"OS X build: %@\n", getOSVersion()];
[s appendFormat:@"SeisMacLib version %s, record %d\n \n", SMSLIB_VERSION, sensorNum]; [s appendFormat:@"SeisMacLib version %s, record %d\n \n", SMSLIB_VERSION,
[s appendFormat:@"Using service \"%s\", function index %d, size %d\n \n", serviceName, function, sensorNum];
recordSize]; [s appendFormat:@"Using service \"%s\", function index %d, size %d\n \n",
serviceName, function, recordSize];
if (prefIntRead(CALIBRATED_NAME, &success) && success) { if (prefIntRead(CALIBRATED_NAME, &success) && success) {
[s appendString:@"Calibration values (from calibration):\n"]; [s appendString:@"Calibration values (from calibration):\n"];
} else { } else {
@ -670,7 +698,8 @@ static void deleteCalibration(void) {
static float prefFloatRead(NSString* prefName, BOOL* success) { static float prefFloatRead(NSString* prefName, BOOL* success) {
float result = 0.0f; float result = 0.0f;
CFPropertyListRef ref = CFPreferencesCopyAppValue((CFStringRef)prefName, APP_ID); CFPropertyListRef ref =
CFPreferencesCopyAppValue((CFStringRef)prefName, APP_ID);
// If there isn't such a preference, fail // If there isn't such a preference, fail
if (ref == NULL) { if (ref == NULL) {
*success = NO; *success = NO;
@ -682,7 +711,8 @@ static float prefFloatRead(NSString* prefName, BOOL* success) {
// Is it a floating point number? // Is it a floating point number?
if (CFNumberIsFloatType((CFNumberRef)ref)) { if (CFNumberIsFloatType((CFNumberRef)ref)) {
// Yup: grab it. // Yup: grab it.
*success = CFNumberGetValue((__CFNumber*)ref, kCFNumberFloat32Type, &result); *success =
CFNumberGetValue((__CFNumber*)ref, kCFNumberFloat32Type, &result);
} else { } else {
// Nope: grab as an integer, and convert to a float. // Nope: grab as an integer, and convert to a float.
long num; long num;
@ -707,7 +737,8 @@ static float prefFloatRead(NSString* prefName, BOOL* success) {
// Writes a named floating point value to the stored preferences. // Writes a named floating point value to the stored preferences.
static void prefFloatWrite(NSString* prefName, float prefValue) { static void prefFloatWrite(NSString* prefName, float prefValue) {
CFNumberRef cfFloat = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &prefValue); CFNumberRef cfFloat =
CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &prefValue);
CFPreferencesSetAppValue((CFStringRef)prefName, cfFloat, APP_ID); CFPreferencesSetAppValue((CFStringRef)prefName, cfFloat, APP_ID);
CFRelease(cfFloat); CFRelease(cfFloat);
} }
@ -715,7 +746,8 @@ static void prefFloatWrite(NSString* prefName, float prefValue) {
// Reads a named integer value from the stored preferences. // Reads a named integer value from the stored preferences.
static int prefIntRead(NSString* prefName, BOOL* success) { static int prefIntRead(NSString* prefName, BOOL* success) {
Boolean internalSuccess; Boolean internalSuccess;
CFIndex result = CFPreferencesGetAppIntegerValue((CFStringRef)prefName, APP_ID, &internalSuccess); CFIndex result = CFPreferencesGetAppIntegerValue((CFStringRef)prefName,
APP_ID, &internalSuccess);
*success = internalSuccess; *success = internalSuccess;
return result; return result;
@ -723,7 +755,8 @@ static int prefIntRead(NSString* prefName, BOOL* success) {
// Writes a named integer value to the stored preferences. // Writes a named integer value to the stored preferences.
static void prefIntWrite(NSString* prefName, int prefValue) { static void prefIntWrite(NSString* prefName, int prefValue) {
CFPreferencesSetAppValue((CFStringRef)prefName, (CFNumberRef)[NSNumber numberWithInt:prefValue], CFPreferencesSetAppValue((CFStringRef)prefName,
(CFNumberRef)[NSNumber numberWithInt:prefValue],
APP_ID); APP_ID);
} }
@ -736,7 +769,8 @@ static void prefDelete(NSString* prefName) {
static void prefSynchronize(void) { CFPreferencesAppSynchronize(APP_ID); } static void prefSynchronize(void) { CFPreferencesAppSynchronize(APP_ID); }
// Internal version of accelGetData, with logging // Internal version of accelGetData, with logging
int getData(sms_acceleration* accel, int calibrated, id logObject, SEL logSelector) { int getData(sms_acceleration* accel, int calibrated, id logObject,
SEL logSelector) {
IOItemCount iSize = recordSize; IOItemCount iSize = recordSize;
IOByteCount oSize = recordSize; IOByteCount oSize = recordSize;
kern_return_t result; kern_return_t result;
@ -754,14 +788,15 @@ int getData(sms_acceleration* accel, int calibrated, id logObject, SEL logSelect
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
const size_t InStructSize = recordSize; const size_t InStructSize = recordSize;
size_t OutStructSize = recordSize; size_t OutStructSize = recordSize;
result = result = IOConnectCallStructMethod(connection,
IOConnectCallStructMethod(connection, function, // magic kernel function number
function, // magic kernel function number (const void*)iRecord, InStructSize,
(const void*)iRecord, InStructSize, (void*)oRecord, &OutStructSize); (void*)oRecord, &OutStructSize);
#else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050 #else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
result = IOConnectMethodStructureIStructureO(connection, result = IOConnectMethodStructureIStructureO(
function, // magic kernel function number connection,
iSize, &oSize, iRecord, oRecord); function, // magic kernel function number
iSize, &oSize, iRecord, oRecord);
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050 #endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
if (result != KERN_SUCCESS) { if (result != KERN_SUCCESS) {
@ -845,11 +880,13 @@ NSString* getModelName(void) {
// Returns the current OS X version and build (e.g. "10.4.7 (build 8J2135a)") // Returns the current OS X version and build (e.g. "10.4.7 (build 8J2135a)")
NSString* getOSVersion(void) { NSString* getOSVersion(void) {
NSDictionary* dict = [NSDictionary NSDictionary* dict =
dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]; [NSDictionary dictionaryWithContentsOfFile:
@"/System/Library/CoreServices/SystemVersion.plist"];
NSString* versionString = [dict objectForKey:@"ProductVersion"]; NSString* versionString = [dict objectForKey:@"ProductVersion"];
NSString* buildString = [dict objectForKey:@"ProductBuildVersion"]; NSString* buildString = [dict objectForKey:@"ProductBuildVersion"];
NSString* wholeString = [NSString stringWithFormat:@"%@ (build %@)", versionString, buildString]; NSString* wholeString =
[NSString stringWithFormat:@"%@ (build %@)", versionString, buildString];
return wholeString; return wholeString;
} }

View file

@ -42,7 +42,8 @@ nsIconChannel::~nsIconChannel() {
} }
} }
NS_IMPL_ISUPPORTS(nsIconChannel, nsIChannel, nsIRequest, nsIRequestObserver, nsIStreamListener) NS_IMPL_ISUPPORTS(nsIconChannel, nsIChannel, nsIRequest, nsIRequestObserver,
nsIStreamListener)
nsresult nsIconChannel::Init(nsIURI* uri) { nsresult nsIconChannel::Init(nsIURI* uri) {
NS_ASSERTION(uri, "no uri"); NS_ASSERTION(uri, "no uri");
@ -73,7 +74,8 @@ NS_IMETHODIMP nsIconChannel::GetCanceledReason(nsACString& aReason) {
return GetCanceledReasonImpl(aReason); return GetCanceledReasonImpl(aReason);
} }
NS_IMETHODIMP nsIconChannel::CancelWithReason(nsresult aStatus, const nsACString& aReason) { NS_IMETHODIMP nsIconChannel::CancelWithReason(nsresult aStatus,
const nsACString& aReason) {
return CancelWithReasonImpl(aStatus, aReason); return CancelWithReasonImpl(aStatus, aReason);
} }
@ -121,8 +123,8 @@ nsIconChannel::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
// nsIStreamListener methods // nsIStreamListener methods
NS_IMETHODIMP NS_IMETHODIMP
nsIconChannel::OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aStream, uint64_t aOffset, nsIconChannel::OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aStream,
uint32_t aCount) { uint64_t aOffset, uint32_t aCount) {
if (mListener) { if (mListener) {
return mListener->OnDataAvailable(this, aStream, aOffset, aCount); return mListener->OnDataAvailable(this, aStream, aOffset, aCount);
} }
@ -156,13 +158,15 @@ nsIconChannel::GetURI(nsIURI** aURI) {
NS_IMETHODIMP NS_IMETHODIMP
nsIconChannel::Open(nsIInputStream** _retval) { nsIconChannel::Open(nsIInputStream** _retval) {
nsCOMPtr<nsIStreamListener> listener; nsCOMPtr<nsIStreamListener> listener;
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener); nsresult rv =
nsContentSecurityManager::doContentSecurityCheck(this, listener);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return MakeInputStream(_retval, false); return MakeInputStream(_retval, false);
} }
nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile** aLocalFile, uint32_t* aDesiredImageSize, nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile** aLocalFile,
uint32_t* aDesiredImageSize,
nsACString& aContentType, nsACString& aContentType,
nsACString& aFileExtension) { nsACString& aFileExtension) {
nsresult rv = NS_OK; nsresult rv = NS_OK;
@ -196,18 +200,21 @@ nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile** aLocalFile, uint32_t* a
NS_IMETHODIMP NS_IMETHODIMP
nsIconChannel::AsyncOpen(nsIStreamListener* aListener) { nsIconChannel::AsyncOpen(nsIStreamListener* aListener) {
nsCOMPtr<nsIStreamListener> listener = aListener; nsCOMPtr<nsIStreamListener> listener = aListener;
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener); nsresult rv =
nsContentSecurityManager::doContentSecurityCheck(this, listener);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
mCallbacks = nullptr; mCallbacks = nullptr;
return rv; return rv;
} }
MOZ_ASSERT(mLoadInfo->GetSecurityMode() == 0 || mLoadInfo->GetInitialSecurityCheckDone() || MOZ_ASSERT(
(mLoadInfo->GetSecurityMode() == mLoadInfo->GetSecurityMode() == 0 ||
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL && mLoadInfo->GetInitialSecurityCheckDone() ||
mLoadInfo->GetLoadingPrincipal() && (mLoadInfo->GetSecurityMode() ==
mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()), nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL &&
"security flags in loadInfo but doContentSecurityCheck() not called"); mLoadInfo->GetLoadingPrincipal() &&
mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()),
"security flags in loadInfo but doContentSecurityCheck() not called");
nsCOMPtr<nsIInputStream> inStream; nsCOMPtr<nsIInputStream> inStream;
rv = MakeInputStream(getter_AddRefs(inStream), true); rv = MakeInputStream(getter_AddRefs(inStream), true);
@ -218,7 +225,8 @@ nsIconChannel::AsyncOpen(nsIStreamListener* aListener) {
// Init our stream pump // Init our stream pump
nsCOMPtr<nsISerialEventTarget> target = nsCOMPtr<nsISerialEventTarget> target =
nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo, mozilla::TaskCategory::Other); nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo,
mozilla::TaskCategory::Other);
rv = mPump->Init(inStream, 0, 0, false, target); rv = mPump->Init(inStream, 0, 0, false, target);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
mCallbacks = nullptr; mCallbacks = nullptr;
@ -240,15 +248,16 @@ nsIconChannel::AsyncOpen(nsIStreamListener* aListener) {
return rv; return rv;
} }
nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlocking) { nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval,
bool aNonBlocking) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
nsCString contentType; nsCString contentType;
nsAutoCString fileExt; nsAutoCString fileExt;
nsCOMPtr<nsIFile> fileloc; // file we want an icon for nsCOMPtr<nsIFile> fileloc; // file we want an icon for
uint32_t desiredImageSize; uint32_t desiredImageSize;
nsresult rv = nsresult rv = ExtractIconInfoFromUrl(getter_AddRefs(fileloc),
ExtractIconInfoFromUrl(getter_AddRefs(fileloc), &desiredImageSize, contentType, fileExt); &desiredImageSize, contentType, fileExt);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
bool fileExists = false; bool fileExists = false;
@ -265,7 +274,8 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlock
CFURLRef macURL; CFURLRef macURL;
if (NS_SUCCEEDED(localFileMac->GetCFURL(&macURL))) { if (NS_SUCCEEDED(localFileMac->GetCFURL(&macURL))) {
iconImage = [[NSWorkspace sharedWorkspace] iconForFile:[(NSURL*)macURL path]]; iconImage =
[[NSWorkspace sharedWorkspace] iconForFile:[(NSURL*)macURL path]];
::CFRelease(macURL); ::CFRelease(macURL);
} }
} }
@ -278,7 +288,8 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlock
// If we still don't have an icon, get the generic document icon. // If we still don't have an icon, get the generic document icon.
if (!iconImage) { if (!iconImage) {
iconImage = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeUnknown]; iconImage =
[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeUnknown];
} }
if (!iconImage) { if (!iconImage) {
@ -296,8 +307,10 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlock
// account when it requests these icons; e.g. it will request an icon with // account when it requests these icons; e.g. it will request an icon with
// size 16, place it in a 16x16 CSS pixel sized image, and then display it in // size 16, place it in a 16x16 CSS pixel sized image, and then display it in
// a window on a HiDPI screen where the icon now covers 32x32 physical screen // a window on a HiDPI screen where the icon now covers 32x32 physical screen
// pixels. So we just always double the size here in order to prevent blurriness. // pixels. So we just always double the size here in order to prevent
uint32_t size = (desiredImageSize < 128) ? desiredImageSize * 2 : desiredImageSize; // blurriness.
uint32_t size =
(desiredImageSize < 128) ? desiredImageSize * 2 : desiredImageSize;
uint32_t width = size; uint32_t width = size;
uint32_t height = size; uint32_t height = size;
@ -322,14 +335,15 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlock
// This gives us the image data in the format we want: BGRA, four bytes per // This gives us the image data in the format we want: BGRA, four bytes per
// pixel, in host endianness, with premultiplied alpha. // pixel, in host endianness, with premultiplied alpha.
CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGContextRef ctx = CGBitmapContextCreate(
CGBitmapContextCreate(imageBuf, width, height, 8 /* bitsPerComponent */, width * 4, cs, imageBuf, width, height, 8 /* bitsPerComponent */, width * 4, cs,
kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst); kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(cs); CGColorSpaceRelease(cs);
NSGraphicsContext* oldContext = [NSGraphicsContext currentContext]; NSGraphicsContext* oldContext = [NSGraphicsContext currentContext];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithCGContext:ctx [NSGraphicsContext
flipped:NO]]; setCurrentContext:[NSGraphicsContext graphicsContextWithCGContext:ctx
flipped:NO]];
[iconImage drawInRect:NSMakeRect(0, 0, width, height)]; [iconImage drawInRect:NSMakeRect(0, 0, width, height)];
@ -340,8 +354,8 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlock
// Now, create a pipe and stuff our data into it // Now, create a pipe and stuff our data into it
nsCOMPtr<nsIInputStream> inStream; nsCOMPtr<nsIInputStream> inStream;
nsCOMPtr<nsIOutputStream> outStream; nsCOMPtr<nsIOutputStream> outStream;
NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream), bufferCapacity, bufferCapacity, NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream),
aNonBlocking); bufferCapacity, bufferCapacity, aNonBlocking);
uint32_t written; uint32_t written;
rv = outStream->Write((char*)fileBuf.get(), bufferCapacity, &written); rv = outStream->Write((char*)fileBuf.get(), bufferCapacity, &written);
@ -368,10 +382,14 @@ nsIconChannel::SetLoadFlags(uint32_t aLoadAttributes) {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsIconChannel::GetTRRMode(nsIRequest::TRRMode* aTRRMode) { return GetTRRModeImpl(aTRRMode); } nsIconChannel::GetTRRMode(nsIRequest::TRRMode* aTRRMode) {
return GetTRRModeImpl(aTRRMode);
}
NS_IMETHODIMP NS_IMETHODIMP
nsIconChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode) { return SetTRRModeImpl(aTRRMode); } nsIconChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode) {
return SetTRRModeImpl(aTRRMode);
}
NS_IMETHODIMP NS_IMETHODIMP
nsIconChannel::GetIsDocument(bool* aIsDocument) { nsIconChannel::GetIsDocument(bool* aIsDocument) {
@ -415,17 +433,20 @@ nsIconChannel::SetContentDisposition(uint32_t aContentDisposition) {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsIconChannel::GetContentDispositionFilename(nsAString& aContentDispositionFilename) { nsIconChannel::GetContentDispositionFilename(
nsAString& aContentDispositionFilename) {
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsIconChannel::SetContentDispositionFilename(const nsAString& aContentDispositionFilename) { nsIconChannel::SetContentDispositionFilename(
const nsAString& aContentDispositionFilename) {
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsIconChannel::GetContentDispositionHeader(nsACString& aContentDispositionHeader) { nsIconChannel::GetContentDispositionHeader(
nsACString& aContentDispositionHeader) {
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
@ -481,14 +502,16 @@ nsIconChannel::SetLoadInfo(nsILoadInfo* aLoadInfo) {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsIconChannel::GetNotificationCallbacks(nsIInterfaceRequestor** aNotificationCallbacks) { nsIconChannel::GetNotificationCallbacks(
nsIInterfaceRequestor** aNotificationCallbacks) {
*aNotificationCallbacks = mCallbacks.get(); *aNotificationCallbacks = mCallbacks.get();
NS_IF_ADDREF(*aNotificationCallbacks); NS_IF_ADDREF(*aNotificationCallbacks);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsIconChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) { nsIconChannel::SetNotificationCallbacks(
nsIInterfaceRequestor* aNotificationCallbacks) {
mCallbacks = aNotificationCallbacks; mCallbacks = aNotificationCallbacks;
return NS_OK; return NS_OK;
} }

View file

@ -7,7 +7,8 @@
#include "base/logging.h" #include "base/logging.h"
@interface CrApplication () @interface CrApplication ()
@property(readwrite, getter=isHandlingSendEvent, nonatomic) BOOL handlingSendEvent; @property(readwrite, getter=isHandlingSendEvent, nonatomic)
BOOL handlingSendEvent;
@end @end
@implementation CrApplication @implementation CrApplication
@ -19,7 +20,8 @@
+ (NSApplication*)sharedApplication { + (NSApplication*)sharedApplication {
NSApplication* app = [super sharedApplication]; NSApplication* app = [super sharedApplication];
if (![NSApp isKindOfClass:self]) { if (![NSApp isKindOfClass:self]) {
CHROMIUM_LOG(ERROR) << "NSApp should be of type " << [[self className] UTF8String] << ", not " CHROMIUM_LOG(ERROR) << "NSApp should be of type "
<< [[self className] UTF8String] << ", not "
<< [[NSApp className] UTF8String]; << [[NSApp className] UTF8String];
DCHECK(false) << "NSApp is of wrong type"; DCHECK(false) << "NSApp is of wrong type";
} }
@ -59,6 +61,8 @@ ScopedSendingEvent::ScopedSendingEvent()
[app_ setHandlingSendEvent:YES]; [app_ setHandlingSendEvent:YES];
} }
ScopedSendingEvent::~ScopedSendingEvent() { [app_ setHandlingSendEvent:handling_]; } ScopedSendingEvent::~ScopedSendingEvent() {
[app_ setHandlingSendEvent:handling_];
}
} // namespace chrome_application_mac } // namespace chrome_application_mac

View file

@ -22,7 +22,8 @@ bool AmIBundled() {
if (GetProcessBundleLocation(&psn, &fsref) != noErr) return false; if (GetProcessBundleLocation(&psn, &fsref) != noErr) return false;
FSCatalogInfo info; FSCatalogInfo info;
if (FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info, NULL, NULL, NULL) != noErr) { if (FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info, NULL, NULL, NULL) !=
noErr) {
return false; return false;
} }

View file

@ -19,7 +19,8 @@ namespace {
void NoOp(void* info) {} void NoOp(void* info) {}
const CFTimeInterval kCFTimeIntervalMax = std::numeric_limits<CFTimeInterval>::max(); const CFTimeInterval kCFTimeIntervalMax =
std::numeric_limits<CFTimeInterval>::max();
} // namespace } // namespace
@ -57,12 +58,13 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
// as needed when ScheduleDelayedWork is called. // as needed when ScheduleDelayedWork is called.
CFRunLoopTimerContext timer_context = CFRunLoopTimerContext(); CFRunLoopTimerContext timer_context = CFRunLoopTimerContext();
timer_context.info = this; timer_context.info = this;
delayed_work_timer_ = CFRunLoopTimerCreate(NULL, // allocator delayed_work_timer_ =
kCFTimeIntervalMax, // fire time CFRunLoopTimerCreate(NULL, // allocator
kCFTimeIntervalMax, // interval kCFTimeIntervalMax, // fire time
0, // flags kCFTimeIntervalMax, // interval
0, // priority 0, // flags
RunDelayedWorkTimer, &timer_context); 0, // priority
RunDelayedWorkTimer, &timer_context);
CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes); CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
CFRunLoopSourceContext source_context = CFRunLoopSourceContext(); CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
@ -89,36 +91,42 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
0, // priority 0, // priority
&source_context); &source_context);
CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_, kCFRunLoopCommonModes); CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_,
kCFRunLoopCommonModes);
CFRunLoopObserverContext observer_context = CFRunLoopObserverContext(); CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
observer_context.info = this; observer_context.info = this;
pre_wait_observer_ = CFRunLoopObserverCreate(NULL, // allocator pre_wait_observer_ =
kCFRunLoopBeforeWaiting, CFRunLoopObserverCreate(NULL, // allocator
true, // repeat kCFRunLoopBeforeWaiting,
0, // priority true, // repeat
PreWaitObserver, &observer_context); 0, // priority
PreWaitObserver, &observer_context);
CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes); CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
pre_source_observer_ = CFRunLoopObserverCreate(NULL, // allocator pre_source_observer_ =
kCFRunLoopBeforeSources, CFRunLoopObserverCreate(NULL, // allocator
true, // repeat kCFRunLoopBeforeSources,
0, // priority true, // repeat
PreSourceObserver, &observer_context); 0, // priority
PreSourceObserver, &observer_context);
CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes); CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes);
enter_exit_observer_ = CFRunLoopObserverCreate(NULL, // allocator enter_exit_observer_ =
kCFRunLoopEntry | kCFRunLoopExit, CFRunLoopObserverCreate(NULL, // allocator
true, // repeat kCFRunLoopEntry | kCFRunLoopExit,
0, // priority true, // repeat
EnterExitObserver, &observer_context); 0, // priority
EnterExitObserver, &observer_context);
CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes); CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
root_power_domain_ = IORegisterForSystemPower( root_power_domain_ = IORegisterForSystemPower(this, &power_notification_port_,
this, &power_notification_port_, PowerStateNotification, &power_notification_object_); PowerStateNotification,
&power_notification_object_);
if (root_power_domain_ != MACH_PORT_NULL) { if (root_power_domain_ != MACH_PORT_NULL) {
CFRunLoopAddSource(run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_), CFRunLoopAddSource(
kCFRunLoopCommonModes); run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_),
kCFRunLoopCommonModes);
} }
} }
@ -127,23 +135,27 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
// same number of run loops must be running when this object is destroyed. // same number of run loops must be running when this object is destroyed.
MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() { MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() {
if (root_power_domain_ != MACH_PORT_NULL) { if (root_power_domain_ != MACH_PORT_NULL) {
CFRunLoopRemoveSource(run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_), CFRunLoopRemoveSource(
kCFRunLoopCommonModes); run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_),
kCFRunLoopCommonModes);
IODeregisterForSystemPower(&power_notification_object_); IODeregisterForSystemPower(&power_notification_object_);
IOServiceClose(root_power_domain_); IOServiceClose(root_power_domain_);
IONotificationPortDestroy(power_notification_port_); IONotificationPortDestroy(power_notification_port_);
} }
CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes); CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_,
kCFRunLoopCommonModes);
CFRelease(enter_exit_observer_); CFRelease(enter_exit_observer_);
CFRunLoopRemoveObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes); CFRunLoopRemoveObserver(run_loop_, pre_source_observer_,
kCFRunLoopCommonModes);
CFRelease(pre_source_observer_); CFRelease(pre_source_observer_);
CFRunLoopRemoveObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes); CFRunLoopRemoveObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
CFRelease(pre_wait_observer_); CFRelease(pre_wait_observer_);
CFRunLoopRemoveSource(run_loop_, nesting_deferred_work_source_, kCFRunLoopCommonModes); CFRunLoopRemoveSource(run_loop_, nesting_deferred_work_source_,
kCFRunLoopCommonModes);
CFRelease(nesting_deferred_work_source_); CFRelease(nesting_deferred_work_source_);
CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes); CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
@ -203,7 +215,8 @@ void MessagePumpCFRunLoopBase::ScheduleWork() {
} }
// Must be called on the run loop thread. // Must be called on the run loop thread.
void MessagePumpCFRunLoopBase::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { void MessagePumpCFRunLoopBase::ScheduleDelayedWork(
const TimeTicks& delayed_work_time) {
TimeDelta delta = delayed_work_time - TimeTicks::Now(); TimeDelta delta = delayed_work_time - TimeTicks::Now();
delayed_work_fire_time_ = CFAbsoluteTimeGetCurrent() + delta.InSecondsF(); delayed_work_fire_time_ = CFAbsoluteTimeGetCurrent() + delta.InSecondsF();
CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_); CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_);
@ -211,7 +224,8 @@ void MessagePumpCFRunLoopBase::ScheduleDelayedWork(const TimeTicks& delayed_work
// Called from the run loop. // Called from the run loop.
// static // static
void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info) { void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer,
void* info) {
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
// The timer won't fire again until it's reset. // The timer won't fire again until it's reset.
@ -392,7 +406,8 @@ void MessagePumpCFRunLoopBase::MaybeScheduleNestingDeferredWork() {
// Called from the run loop. // Called from the run loop.
// static // static
void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer, void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
CFRunLoopActivity activity, void* info) { CFRunLoopActivity activity,
void* info) {
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
// Attempt to do some idle work before going to sleep. // Attempt to do some idle work before going to sleep.
@ -408,7 +423,8 @@ void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
// Called from the run loop. // Called from the run loop.
// static // static
void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer, void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer,
CFRunLoopActivity activity, void* info) { CFRunLoopActivity activity,
void* info) {
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
// The run loop has reached the top of the loop and is about to begin // The run loop has reached the top of the loop and is about to begin
@ -422,7 +438,8 @@ void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer,
// Called from the run loop. // Called from the run loop.
// static // static
void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer, void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
CFRunLoopActivity activity, void* info) { CFRunLoopActivity activity,
void* info) {
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
switch (activity) { switch (activity) {
@ -463,7 +480,8 @@ void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
// Called from the run loop. // Called from the run loop.
// static // static
void MessagePumpCFRunLoopBase::PowerStateNotification(void* info, io_service_t service, void MessagePumpCFRunLoopBase::PowerStateNotification(void* info,
io_service_t service,
uint32_t message_type, uint32_t message_type,
void* message_argument) { void* message_argument) {
// CFRunLoopTimer (NSTimer) is scheduled in terms of CFAbsoluteTime, which // CFRunLoopTimer (NSTimer) is scheduled in terms of CFAbsoluteTime, which
@ -508,7 +526,8 @@ void MessagePumpCFRunLoopBase::PowerStateNotification(void* info, io_service_t s
switch (message_type) { switch (message_type) {
case kIOMessageSystemWillPowerOn: case kIOMessageSystemWillPowerOn:
if (self->delayed_work_fire_time_ != kCFTimeIntervalMax) { if (self->delayed_work_fire_time_ != kCFTimeIntervalMax) {
CFRunLoopTimerSetNextFireDate(self->delayed_work_timer_, self->delayed_work_fire_time_); CFRunLoopTimerSetNextFireDate(self->delayed_work_timer_,
self->delayed_work_fire_time_);
} }
break; break;
@ -517,7 +536,8 @@ void MessagePumpCFRunLoopBase::PowerStateNotification(void* info, io_service_t s
// The system will wait for 30 seconds before entering sleep if neither // The system will wait for 30 seconds before entering sleep if neither
// IOAllowPowerChange nor IOCancelPowerChange are called. That would be // IOAllowPowerChange nor IOCancelPowerChange are called. That would be
// pretty antisocial. // pretty antisocial.
IOAllowPowerChange(self->root_power_domain_, reinterpret_cast<long>(message_argument)); IOAllowPowerChange(self->root_power_domain_,
reinterpret_cast<long>(message_argument));
break; break;
default: default:
@ -546,7 +566,8 @@ void MessagePumpCFRunLoop::DoRun(Delegate* delegate) {
int result; int result;
do { do {
MessagePumpScopedAutoreleasePool autorelease_pool(this); MessagePumpScopedAutoreleasePool autorelease_pool(this);
result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, kCFTimeIntervalMax, false); result =
CFRunLoopRunInMode(kCFRunLoopDefaultMode, kCFTimeIntervalMax, false);
} while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished); } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished);
} }
@ -568,7 +589,8 @@ void MessagePumpCFRunLoop::Quit() {
// Called by MessagePumpCFRunLoopBase::EnterExitObserver. // Called by MessagePumpCFRunLoopBase::EnterExitObserver.
void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) { void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) {
if (activity == kCFRunLoopExit && nesting_level() == run_nesting_level() && quit_pending_) { if (activity == kCFRunLoopExit && nesting_level() == run_nesting_level() &&
quit_pending_) {
// Quit was called while loops other than those managed by this object // Quit was called while loops other than those managed by this object
// were running further inside a run loop managed by this object. Now // were running further inside a run loop managed by this object. Now
// that all unmanaged inner run loops are gone, stop the loop running // that all unmanaged inner run loops are gone, stop the loop running
@ -595,7 +617,8 @@ MessagePumpNSRunLoop::~MessagePumpNSRunLoop() {
void MessagePumpNSRunLoop::DoRun(Delegate* delegate) { void MessagePumpNSRunLoop::DoRun(Delegate* delegate) {
while (keep_running_) { while (keep_running_) {
// NSRunLoop manages autorelease pools itself. // NSRunLoop manages autorelease pools itself.
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
} }
keep_running_ = true; keep_running_ = true;

View file

@ -42,7 +42,9 @@ void InitThreading() {
static BOOL multithreaded = [NSThread isMultiThreaded]; static BOOL multithreaded = [NSThread isMultiThreaded];
if (!multithreaded) { if (!multithreaded) {
[NSThread detachNewThreadSelector:@selector(noOp) toTarget:[NoOp class] withObject:nil]; [NSThread detachNewThreadSelector:@selector(noOp)
toTarget:[NoOp class]
withObject:nil];
multithreaded = YES; multithreaded = YES;
DCHECK([NSThread isMultiThreaded]); DCHECK([NSThread isMultiThreaded]);

View file

@ -41,7 +41,8 @@ static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
namespace base { namespace base {
Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv, Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
const LaunchOptions& options, ProcessHandle* process_handle) { const LaunchOptions& options,
ProcessHandle* process_handle) {
Result<Ok, LaunchError> retval = Ok(); Result<Ok, LaunchError> retval = Ok();
char* argv_copy[argv.size() + 1]; char* argv_copy[argv.size() + 1];
@ -52,7 +53,8 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
EnvironmentArray env_storage; EnvironmentArray env_storage;
const EnvironmentArray& vars = const EnvironmentArray& vars =
options.full_env ? options.full_env : (env_storage = BuildEnvironmentArray(options.env_map)); options.full_env ? options.full_env
: (env_storage = BuildEnvironmentArray(options.env_map));
posix_spawn_file_actions_t file_actions; posix_spawn_file_actions_t file_actions;
int err = posix_spawn_file_actions_init(&file_actions); int err = posix_spawn_file_actions_init(&file_actions);
@ -60,8 +62,8 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
DLOG(WARNING) << "posix_spawn_file_actions_init failed"; DLOG(WARNING) << "posix_spawn_file_actions_init failed";
return Err(LaunchError("posix_spawn_file_actions_init", err)); return Err(LaunchError("posix_spawn_file_actions_init", err));
} }
auto file_actions_guard = auto file_actions_guard = mozilla::MakeScopeExit(
mozilla::MakeScopeExit([&file_actions] { posix_spawn_file_actions_destroy(&file_actions); }); [&file_actions] { posix_spawn_file_actions_destroy(&file_actions); });
// Turn fds_to_remap array into a set of dup2 calls. // Turn fds_to_remap array into a set of dup2 calls.
// //
@ -85,7 +87,8 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
} }
if (!options.workdir.empty()) { if (!options.workdir.empty()) {
int rv = posix_spawn_file_actions_addchdir_np(&file_actions, options.workdir.c_str()); int rv = posix_spawn_file_actions_addchdir_np(&file_actions,
options.workdir.c_str());
if (rv != 0) { if (rv != 0) {
DLOG(WARNING) << "posix_spawn_file_actions_addchdir_np failed"; DLOG(WARNING) << "posix_spawn_file_actions_addchdir_np failed";
return Err(LaunchError("posix_spawn_file_actions_addchdir", rv)); return Err(LaunchError("posix_spawn_file_actions_addchdir", rv));
@ -99,15 +102,16 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
DLOG(WARNING) << "posix_spawnattr_init failed"; DLOG(WARNING) << "posix_spawnattr_init failed";
return Err(LaunchError("posix_spawnattr_init", err)); return Err(LaunchError("posix_spawnattr_init", err));
} }
auto spawnattr_guard = auto spawnattr_guard = mozilla::MakeScopeExit(
mozilla::MakeScopeExit([&spawnattr] { posix_spawnattr_destroy(&spawnattr); }); [&spawnattr] { posix_spawnattr_destroy(&spawnattr); });
#if defined(XP_MACOSX) && defined(__aarch64__) #if defined(XP_MACOSX) && defined(__aarch64__)
if (options.arch == PROCESS_ARCH_X86_64) { if (options.arch == PROCESS_ARCH_X86_64) {
cpu_type_t cpu_pref = CPU_TYPE_X86_64; cpu_type_t cpu_pref = CPU_TYPE_X86_64;
size_t count = 1; size_t count = 1;
size_t ocount = 0; size_t ocount = 0;
int rv = posix_spawnattr_setbinpref_np(&spawnattr, count, &cpu_pref, &ocount); int rv =
posix_spawnattr_setbinpref_np(&spawnattr, count, &cpu_pref, &ocount);
if ((rv != 0) || (ocount != count)) { if ((rv != 0) || (ocount != count)) {
DLOG(WARNING) << "posix_spawnattr_setbinpref_np failed"; DLOG(WARNING) << "posix_spawnattr_setbinpref_np failed";
return Err(LaunchError("posix_spawnattr_setbinpref_np", rv)); return Err(LaunchError("posix_spawnattr_setbinpref_np", rv));
@ -142,15 +146,16 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
} }
int pid = 0; int pid = 0;
int spawn_succeeded = int spawn_succeeded = (posix_spawnp(&pid, argv_copy[0], &file_actions,
(posix_spawnp(&pid, argv_copy[0], &file_actions, &spawnattr, argv_copy, vars.get()) == 0); &spawnattr, argv_copy, vars.get()) == 0);
bool process_handle_valid = pid > 0; bool process_handle_valid = pid > 0;
if (!spawn_succeeded || !process_handle_valid) { if (!spawn_succeeded || !process_handle_valid) {
DLOG(WARNING) << "posix_spawnp failed"; DLOG(WARNING) << "posix_spawnp failed";
retval = Err(LaunchError("posix_spawnp", spawn_succeeded)); retval = Err(LaunchError("posix_spawnp", spawn_succeeded));
} else { } else {
gProcessLog.print("==> process %d launched child process %d\n", GetCurrentProcId(), pid); gProcessLog.print("==> process %d launched child process %d\n",
GetCurrentProcId(), pid);
if (options.wait) HANDLE_EINTR(waitpid(pid, 0, 0)); if (options.wait) HANDLE_EINTR(waitpid(pid, 0, 0));
if (process_handle) *process_handle = pid; if (process_handle) *process_handle = pid;
@ -159,7 +164,8 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
return retval; return retval;
} }
Result<Ok, LaunchError> LaunchApp(const CommandLine& cl, const LaunchOptions& options, Result<Ok, LaunchError> LaunchApp(const CommandLine& cl,
const LaunchOptions& options,
ProcessHandle* process_handle) { ProcessHandle* process_handle) {
return LaunchApp(cl.argv(), options, process_handle); return LaunchApp(cl.argv(), options, process_handle);
} }

View file

@ -15,7 +15,9 @@ ScopedNSAutoreleasePool::ScopedNSAutoreleasePool()
DCHECK(autorelease_pool_); DCHECK(autorelease_pool_);
} }
ScopedNSAutoreleasePool::~ScopedNSAutoreleasePool() { [autorelease_pool_ drain]; } ScopedNSAutoreleasePool::~ScopedNSAutoreleasePool() {
[autorelease_pool_ drain];
}
// Cycle the internal pool, allowing everything there to get cleaned up and // Cycle the internal pool, allowing everything there to get cleaned up and
// start anew. // start anew.

View file

@ -44,11 +44,12 @@ static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring,
out_size * sizeof(UInt8) / sizeof(typename StringType::value_type) + 1; out_size * sizeof(UInt8) / sizeof(typename StringType::value_type) + 1;
std::vector<typename StringType::value_type> out_buffer(elements); std::vector<typename StringType::value_type> out_buffer(elements);
converted = CFStringGetBytes(cfstring, whole_string, encoding, converted =
0, // lossByte CFStringGetBytes(cfstring, whole_string, encoding,
false, // isExternalRepresentation 0, // lossByte
reinterpret_cast<UInt8*>(&out_buffer[0]), out_size, false, // isExternalRepresentation
NULL); // usedBufLen reinterpret_cast<UInt8*>(&out_buffer[0]), out_size,
NULL); // usedBufLen
if (converted == 0) return StringType(); if (converted == 0) return StringType();
out_buffer[elements - 1] = '\0'; out_buffer[elements - 1] = '\0';
@ -61,31 +62,33 @@ static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring,
// //
// Do not assert in this function since it is used by the asssertion code! // Do not assert in this function since it is used by the asssertion code!
template <typename InStringType, typename OutStringType> template <typename InStringType, typename OutStringType>
static OutStringType STLStringToSTLStringWithEncodingsT(const InStringType& in, static OutStringType STLStringToSTLStringWithEncodingsT(
CFStringEncoding in_encoding, const InStringType& in, CFStringEncoding in_encoding,
CFStringEncoding out_encoding) { CFStringEncoding out_encoding) {
typename InStringType::size_type in_length = in.length(); typename InStringType::size_type in_length = in.length();
if (in_length == 0) return OutStringType(); if (in_length == 0) return OutStringType();
scoped_cftyperef<CFStringRef> cfstring(CFStringCreateWithBytesNoCopy( scoped_cftyperef<CFStringRef> cfstring(CFStringCreateWithBytesNoCopy(
NULL, reinterpret_cast<const UInt8*>(in.data()), NULL, reinterpret_cast<const UInt8*>(in.data()),
in_length * sizeof(typename InStringType::value_type), in_encoding, false, kCFAllocatorNull)); in_length * sizeof(typename InStringType::value_type), in_encoding, false,
kCFAllocatorNull));
if (!cfstring) return OutStringType(); if (!cfstring) return OutStringType();
return CFStringToSTLStringWithEncodingT<OutStringType>(cfstring, out_encoding); return CFStringToSTLStringWithEncodingT<OutStringType>(cfstring,
out_encoding);
} }
// Given an STL string |in| with an encoding specified by |in_encoding|, // Given an STL string |in| with an encoding specified by |in_encoding|,
// return it as a CFStringRef. Returns NULL on failure. // return it as a CFStringRef. Returns NULL on failure.
template <typename StringType> template <typename StringType>
static CFStringRef STLStringToCFStringWithEncodingsT(const StringType& in, static CFStringRef STLStringToCFStringWithEncodingsT(
CFStringEncoding in_encoding) { const StringType& in, CFStringEncoding in_encoding) {
typename StringType::size_type in_length = in.length(); typename StringType::size_type in_length = in.length();
if (in_length == 0) return CFSTR(""); if (in_length == 0) return CFSTR("");
return CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(in.data()), return CFStringCreateWithBytes(
in_length * sizeof(typename StringType::value_type), in_encoding, kCFAllocatorDefault, reinterpret_cast<const UInt8*>(in.data()),
false); in_length * sizeof(typename StringType::value_type), in_encoding, false);
} }
// Specify the byte ordering explicitly, otherwise CFString will be confused // Specify the byte ordering explicitly, otherwise CFString will be confused
@ -102,18 +105,22 @@ static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32LE;
// Do not assert in this function since it is used by the asssertion code! // Do not assert in this function since it is used by the asssertion code!
std::string SysWideToUTF8(const std::wstring& wide) { std::string SysWideToUTF8(const std::wstring& wide) {
return STLStringToSTLStringWithEncodingsT<std::wstring, std::string>(wide, kWideStringEncoding, return STLStringToSTLStringWithEncodingsT<std::wstring, std::string>(
kNarrowStringEncoding); wide, kWideStringEncoding, kNarrowStringEncoding);
} }
// Do not assert in this function since it is used by the asssertion code! // Do not assert in this function since it is used by the asssertion code!
std::wstring SysUTF8ToWide(const StringPiece& utf8) { std::wstring SysUTF8ToWide(const StringPiece& utf8) {
return STLStringToSTLStringWithEncodingsT<StringPiece, std::wstring>(utf8, kNarrowStringEncoding, return STLStringToSTLStringWithEncodingsT<StringPiece, std::wstring>(
kWideStringEncoding); utf8, kNarrowStringEncoding, kWideStringEncoding);
} }
std::string SysWideToNativeMB(const std::wstring& wide) { return SysWideToUTF8(wide); } std::string SysWideToNativeMB(const std::wstring& wide) {
return SysWideToUTF8(wide);
}
std::wstring SysNativeMBToWide(const StringPiece& native_mb) { return SysUTF8ToWide(native_mb); } std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
return SysUTF8ToWide(native_mb);
}
} // namespace base } // namespace base

View file

@ -20,7 +20,8 @@ NS_IMPL_ADDREF_INHERITED(MessagePumpForNonMainUIThreads, MessagePump)
NS_IMPL_RELEASE_INHERITED(MessagePumpForNonMainUIThreads, MessagePump) NS_IMPL_RELEASE_INHERITED(MessagePumpForNonMainUIThreads, MessagePump)
NS_IMPL_QUERY_INTERFACE(MessagePumpForNonMainUIThreads, nsIThreadObserver) NS_IMPL_QUERY_INTERFACE(MessagePumpForNonMainUIThreads, nsIThreadObserver)
MessagePumpForNonMainUIThreads::MessagePumpForNonMainUIThreads(nsISerialEventTarget* aEventTarget) MessagePumpForNonMainUIThreads::MessagePumpForNonMainUIThreads(
nsISerialEventTarget* aEventTarget)
: mEventTarget(aEventTarget), keep_running_(true) { : mEventTarget(aEventTarget), keep_running_(true) {
MOZ_ASSERT(mEventTarget); MOZ_ASSERT(mEventTarget);
CFRunLoopSourceContext source_context = CFRunLoopSourceContext(); CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
@ -36,13 +37,15 @@ MessagePumpForNonMainUIThreads::~MessagePumpForNonMainUIThreads() {
CFRelease(quit_source_); CFRelease(quit_source_);
} }
void MessagePumpForNonMainUIThreads::DoRun(base::MessagePump::Delegate* aDelegate) { void MessagePumpForNonMainUIThreads::DoRun(
// If this is a chromium thread and no nsThread is associated with it, this call will create a base::MessagePump::Delegate* aDelegate) {
// new nsThread. // If this is a chromium thread and no nsThread is associated with it, this
// call will create a new nsThread.
nsIThread* thread = NS_GetCurrentThread(); nsIThread* thread = NS_GetCurrentThread();
MOZ_ASSERT(thread); MOZ_ASSERT(thread);
// Set the main thread observer so we can wake up when xpcom events need to get processed. // Set the main thread observer so we can wake up when xpcom events need to
// get processed.
nsCOMPtr<nsIThreadInternal> ti(do_QueryInterface(thread)); nsCOMPtr<nsIThreadInternal> ti(do_QueryInterface(thread));
MOZ_ASSERT(ti); MOZ_ASSERT(ti);
ti->SetObserver(this); ti->SetObserver(this);
@ -63,7 +66,8 @@ void MessagePumpForNonMainUIThreads::DoRun(base::MessagePump::Delegate* aDelegat
// Now process the CFRunLoop. It exits after running once. // Now process the CFRunLoop. It exits after running once.
// NSRunLoop manages autorelease pools itself. // NSRunLoop manages autorelease pools itself.
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
} }
ti->SetObserver(nullptr); ti->SetObserver(nullptr);
@ -77,14 +81,15 @@ void MessagePumpForNonMainUIThreads::Quit() {
} }
NS_IMETHODIMP MessagePumpForNonMainUIThreads::OnDispatchedEvent() { NS_IMETHODIMP MessagePumpForNonMainUIThreads::OnDispatchedEvent() {
// ScheduleWork will signal an input source to the run loop, making it exit so it can process the // ScheduleWork will signal an input source to the run loop, making it exit so
// xpcom event. // it can process the xpcom event.
ScheduleWork(); ScheduleWork();
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
MessagePumpForNonMainUIThreads::OnProcessNextEvent(nsIThreadInternal* thread, bool mayWait) { MessagePumpForNonMainUIThreads::OnProcessNextEvent(nsIThreadInternal* thread,
bool mayWait) {
return NS_OK; return NS_OK;
} }

View file

@ -25,28 +25,32 @@ void SetThisProcessName(const char* aProcessName) {
return; return;
} }
NSString* currentName = NSString* currentName = [[[NSBundle mainBundle] localizedInfoDictionary]
[[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:(NSString*)kCFBundleNameKey]; objectForKey:(NSString*)kCFBundleNameKey];
char formattedName[1024]; char formattedName[1024];
SprintfLiteral(formattedName, "%s %s", [currentName UTF8String], aProcessName); SprintfLiteral(formattedName, "%s %s", [currentName UTF8String],
aProcessName);
aProcessName = formattedName; aProcessName = formattedName;
// This function is based on Chrome/Webkit's and relies on potentially dangerous SPI. // This function is based on Chrome/Webkit's and relies on potentially
// dangerous SPI.
typedef CFTypeRef (*LSGetASNType)(); typedef CFTypeRef (*LSGetASNType)();
typedef OSStatus (*LSSetInformationItemType)(int, CFTypeRef, CFStringRef, CFStringRef, typedef OSStatus (*LSSetInformationItemType)(int, CFTypeRef, CFStringRef,
CFDictionaryRef*); CFStringRef, CFDictionaryRef*);
CFBundleRef launchServices = ::CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices")); CFBundleRef launchServices =
::CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
if (!launchServices) { if (!launchServices) {
NS_WARNING("Failed to set process name: Could not open LaunchServices bundle"); NS_WARNING(
"Failed to set process name: Could not open LaunchServices bundle");
return; return;
} }
if (!sApplicationASN) { if (!sApplicationASN) {
sApplicationASN = sApplicationASN = ::CFBundleGetFunctionPointerForName(
::CFBundleGetFunctionPointerForName(launchServices, CFSTR("_LSGetCurrentApplicationASN")); launchServices, CFSTR("_LSGetCurrentApplicationASN"));
if (!sApplicationASN) { if (!sApplicationASN) {
NS_WARNING("Failed to set process name: Could not get function pointer " NS_WARNING("Failed to set process name: Could not get function pointer "
"for LaunchServices"); "for LaunchServices");
@ -64,12 +68,13 @@ void SetThisProcessName(const char* aProcessName) {
LSSetInformationItemType setInformationItemFunc = LSSetInformationItemType setInformationItemFunc =
reinterpret_cast<LSSetInformationItemType>(sApplicationInfoItem); reinterpret_cast<LSSetInformationItemType>(sApplicationInfoItem);
void* displayNameKeyAddr = void* displayNameKeyAddr = ::CFBundleGetDataPointerForName(
::CFBundleGetDataPointerForName(launchServices, CFSTR("_kLSDisplayNameKey")); launchServices, CFSTR("_kLSDisplayNameKey"));
CFStringRef displayNameKey = nil; CFStringRef displayNameKey = nil;
if (displayNameKeyAddr) { if (displayNameKeyAddr) {
displayNameKey = reinterpret_cast<CFStringRef>(*(CFStringRef*)displayNameKeyAddr); displayNameKey =
reinterpret_cast<CFStringRef>(*(CFStringRef*)displayNameKeyAddr);
} }
// We need this to ensure we have a connection to the Process Manager, not // We need this to ensure we have a connection to the Process Manager, not
@ -81,20 +86,22 @@ void SetThisProcessName(const char* aProcessName) {
CFTypeRef currentAsn = getASNFunc ? getASNFunc() : nullptr; CFTypeRef currentAsn = getASNFunc ? getASNFunc() : nullptr;
if (!getASNFunc || !setInformationItemFunc || !displayNameKey || !currentAsn) { if (!getASNFunc || !setInformationItemFunc || !displayNameKey ||
!currentAsn) {
NS_WARNING("Failed to set process name: Accessing launchServices failed"); NS_WARNING("Failed to set process name: Accessing launchServices failed");
return; return;
} }
CFStringRef processName = ::CFStringCreateWithCString(nil, aProcessName, kCFStringEncodingASCII); CFStringRef processName =
::CFStringCreateWithCString(nil, aProcessName, kCFStringEncodingASCII);
if (!processName) { if (!processName) {
NS_WARNING("Failed to set process name: Could not create CFStringRef"); NS_WARNING("Failed to set process name: Could not create CFStringRef");
return; return;
} }
OSErr err = OSErr err = setInformationItemFunc(UNDOCUMENTED_SESSION_CONSTANT, currentAsn,
setInformationItemFunc(UNDOCUMENTED_SESSION_CONSTANT, currentAsn, displayNameKey, processName, displayNameKey, processName,
nil); // Optional out param nil); // Optional out param
::CFRelease(processName); ::CFRelease(processName);
if (err != noErr) { if (err != noErr) {
NS_WARNING("Failed to set process name: LSSetInformationItemType err"); NS_WARNING("Failed to set process name: LSSetInformationItemType err");

View file

@ -71,12 +71,13 @@ bool SharedMemoryBasic::Create(size_t size) {
memory_object_size_t memoryObjectSize = round_page(size); memory_object_size_t memoryObjectSize = round_page(size);
kern_return_t kr = mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0, kern_return_t kr =
MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT, mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0,
getter_Transfers(mPort), MACH_PORT_NULL); MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
getter_Transfers(mPort), MACH_PORT_NULL);
if (kr != KERN_SUCCESS || memoryObjectSize < round_page(size)) { if (kr != KERN_SUCCESS || memoryObjectSize < round_page(size)) {
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", size, mach_error_string(kr), LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", size,
kr); mach_error_string(kr), kr);
CloseHandle(); CloseHandle();
return false; return false;
} }
@ -101,12 +102,15 @@ bool SharedMemoryBasic::Map(size_t size, void* fixed_address) {
} }
kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0, kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0,
fixed_address ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE, mPort.get(), 0, false, fixed_address ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE,
vmProtection, vmProtection, VM_INHERIT_NONE); mPort.get(), 0, false, vmProtection, vmProtection,
VM_INHERIT_NONE);
if (kr != KERN_SUCCESS) { if (kr != KERN_SUCCESS) {
if (!fixed_address) { if (!fixed_address) {
LOG_ERROR("Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n", size, LOG_ERROR(
mach_task_self(), mach_port_t(mPort.get()), mach_error_string(kr), kr); "Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
size, mach_task_self(), mach_port_t(mPort.get()),
mach_error_string(kr), kr);
} }
return false; return false;
} }
@ -116,7 +120,8 @@ bool SharedMemoryBasic::Map(size_t size, void* fixed_address) {
if (kr != KERN_SUCCESS) { if (kr != KERN_SUCCESS) {
LOG_ERROR("Failed to unmap shared memory at unsuitable address " LOG_ERROR("Failed to unmap shared memory at unsuitable address "
"(%zu bytes) from %x, port %x. %s (%x)\n", "(%zu bytes) from %x, port %x. %s (%x)\n",
size, mach_task_self(), mach_port_t(mPort.get()), mach_error_string(kr), kr); size, mach_task_self(), mach_port_t(mPort.get()),
mach_error_string(kr), kr);
} }
return false; return false;
} }
@ -129,8 +134,9 @@ bool SharedMemoryBasic::Map(size_t size, void* fixed_address) {
void* SharedMemoryBasic::FindFreeAddressSpace(size_t size) { void* SharedMemoryBasic::FindFreeAddressSpace(size_t size) {
mach_vm_address_t address = 0; mach_vm_address_t address = 0;
size = round_page(size); size = round_page(size);
if (mach_vm_map(mach_task_self(), &address, size, 0, VM_FLAGS_ANYWHERE, MEMORY_OBJECT_NULL, 0, if (mach_vm_map(mach_task_self(), &address, size, 0, VM_FLAGS_ANYWHERE,
false, VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_NONE) != KERN_SUCCESS || MEMORY_OBJECT_NULL, 0, false, VM_PROT_NONE, VM_PROT_NONE,
VM_INHERIT_NONE) != KERN_SUCCESS ||
vm_deallocate(mach_task_self(), address, size) != KERN_SUCCESS) { vm_deallocate(mach_task_self(), address, size) != KERN_SUCCESS) {
return nullptr; return nullptr;
} }
@ -146,9 +152,11 @@ void SharedMemoryBasic::Unmap() {
return; return;
} }
vm_address_t address = toVMAddress(mMemory); vm_address_t address = toVMAddress(mMemory);
kern_return_t kr = vm_deallocate(mach_task_self(), address, round_page(mMappedSize)); kern_return_t kr =
vm_deallocate(mach_task_self(), address, round_page(mMappedSize));
if (kr != KERN_SUCCESS) { if (kr != KERN_SUCCESS) {
LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n", mach_error_string(kr), kr); LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
mach_error_string(kr), kr);
return; return;
} }
mMemory = nullptr; mMemory = nullptr;
@ -161,7 +169,9 @@ void SharedMemoryBasic::CloseHandle() {
} }
} }
bool SharedMemoryBasic::IsHandleValid(const Handle& aHandle) const { return aHandle != nullptr; } bool SharedMemoryBasic::IsHandleValid(const Handle& aHandle) const {
return aHandle != nullptr;
}
} // namespace ipc } // namespace ipc
} // namespace mozilla } // namespace mozilla

View file

@ -75,7 +75,9 @@ static OSStatus getErrorCodeBool(Boolean success) {
} }
// If given a NULL pointer, return the error code. // If given a NULL pointer, return the error code.
static OSStatus getErrorCodePtr(const void* value) { return getErrorCodeBool(value != nullptr); } static OSStatus getErrorCodePtr(const void* value) {
return getErrorCodeBool(value != nullptr);
}
// Convenience function to allow NULL input. // Convenience function to allow NULL input.
static void CFReleaseSafe(CFTypeRef cf) { static void CFReleaseSafe(CFTypeRef cf) {
@ -86,8 +88,8 @@ static void CFReleaseSafe(CFTypeRef cf) {
} }
} }
NS_IMPL_ISUPPORTS(nsNetworkLinkService, nsINetworkLinkService, nsIObserver, nsITimerCallback, NS_IMPL_ISUPPORTS(nsNetworkLinkService, nsINetworkLinkService, nsIObserver,
nsINamed) nsITimerCallback, nsINamed)
nsNetworkLinkService::nsNetworkLinkService() nsNetworkLinkService::nsNetworkLinkService()
: mLinkUp(true), : mLinkUp(true),
@ -129,7 +131,8 @@ nsNetworkLinkService::GetNetworkID(nsACString& aNetworkID) {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsNetworkLinkService::GetPlatformDNSIndications(uint32_t* aPlatformDNSIndications) { nsNetworkLinkService::GetPlatformDNSIndications(
uint32_t* aPlatformDNSIndications) {
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
@ -139,8 +142,9 @@ void nsNetworkLinkService::GetDnsSuffixListInternal() {
auto sendNotification = mozilla::MakeScopeExit([self = RefPtr{this}] { auto sendNotification = mozilla::MakeScopeExit([self = RefPtr{this}] {
NS_DispatchToMainThread(NS_NewRunnableFunction( NS_DispatchToMainThread(NS_NewRunnableFunction(
"nsNetworkLinkService::GetDnsSuffixListInternal", "nsNetworkLinkService::GetDnsSuffixListInternal", [self]() {
[self]() { self->NotifyObservers(NS_DNS_SUFFIX_LIST_UPDATED_TOPIC, nullptr); })); self->NotifyObservers(NS_DNS_SUFFIX_LIST_UPDATED_TOPIC, nullptr);
}));
}); });
nsTArray<nsCString> result; nsTArray<nsCString> result;
@ -176,15 +180,17 @@ nsNetworkLinkService::GetResolvers(nsTArray<RefPtr<nsINetAddr>>& aResolvers) {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsNetworkLinkService::GetNativeResolvers(nsTArray<mozilla::net::NetAddr>& aResolvers) { nsNetworkLinkService::GetNativeResolvers(
nsTArray<mozilla::net::NetAddr>& aResolvers) {
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
#ifndef SA_SIZE #ifndef SA_SIZE
# define SA_SIZE(sa) \ # define SA_SIZE(sa) \
((!(sa) || ((struct sockaddr*)(sa))->sa_len == 0) \ ((!(sa) || ((struct sockaddr*)(sa))->sa_len == 0) \
? sizeof(uint32_t) \ ? sizeof(uint32_t) \
: 1 + ((((struct sockaddr*)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1))) : 1 + ((((struct sockaddr*)(sa))->sa_len - 1) | \
(sizeof(uint32_t) - 1)))
#endif #endif
static bool getMac(struct sockaddr_dl* sdl, char* buf, size_t bufsize) { static bool getMac(struct sockaddr_dl* sdl, char* buf, size_t bufsize) {
@ -196,14 +202,14 @@ static bool getMac(struct sockaddr_dl* sdl, char* buf, size_t bufsize) {
return false; return false;
} }
snprintf(buf, bufsize, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], snprintf(buf, bufsize, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1],
mac[5]); mac[2], mac[3], mac[4], mac[5]);
return true; return true;
} }
/* If the IP matches, get the MAC and return true */ /* If the IP matches, get the MAC and return true */
static bool matchIp(struct sockaddr_dl* sdl, struct sockaddr_inarp* addr, char* ip, char* buf, static bool matchIp(struct sockaddr_dl* sdl, struct sockaddr_inarp* addr,
size_t bufsize) { char* ip, char* buf, size_t bufsize) {
if (sdl->sdl_alen) { if (sdl->sdl_alen) {
if (!strcmp(inet_ntoa(addr->sin_addr), ip)) { if (!strcmp(inet_ntoa(addr->sin_addr), ip)) {
if (getMac(sdl, buf, bufsize)) { if (getMac(sdl, buf, bufsize)) {
@ -275,8 +281,10 @@ static bool scanArp(char* ip, char* mac, size_t maclen) {
struct rt_msghdr* rtm; struct rt_msghdr* rtm;
for (next = &buf[0]; next < lim; next += rtm->rtm_msglen) { for (next = &buf[0]; next < lim; next += rtm->rtm_msglen) {
rtm = reinterpret_cast<struct rt_msghdr*>(next); rtm = reinterpret_cast<struct rt_msghdr*>(next);
struct sockaddr_inarp* sin2 = reinterpret_cast<struct sockaddr_inarp*>(rtm + 1); struct sockaddr_inarp* sin2 =
struct sockaddr_dl* sdl = reinterpret_cast<struct sockaddr_dl*>((char*)sin2 + SA_SIZE(sin2)); reinterpret_cast<struct sockaddr_inarp*>(rtm + 1);
struct sockaddr_dl* sdl =
reinterpret_cast<struct sockaddr_dl*>((char*)sin2 + SA_SIZE(sin2));
if (matchIp(sdl, sin2, ip, mac, maclen)) { if (matchIp(sdl, sin2, ip, mac, maclen)) {
return true; return true;
} }
@ -285,9 +293,10 @@ static bool scanArp(char* ip, char* mac, size_t maclen) {
return false; return false;
} }
// Append the mac address of rtm to `stringsToHash`. If it's not in arp table, append // Append the mac address of rtm to `stringsToHash`. If it's not in arp table,
// ifname and IP address. // append ifname and IP address.
static bool parseHashKey(struct rt_msghdr* rtm, nsTArray<nsCString>& stringsToHash, static bool parseHashKey(struct rt_msghdr* rtm,
nsTArray<nsCString>& stringsToHash,
bool skipDstCheck) { bool skipDstCheck) {
struct sockaddr* sa; struct sockaddr* sa;
struct sockaddr_in* sockin; struct sockaddr_in* sockin;
@ -317,8 +326,8 @@ static bool parseHashKey(struct rt_msghdr* rtm, nsTArray<nsCString>& stringsToHa
return false; return false;
} }
struct sockaddr* gateway = struct sockaddr* gateway = reinterpret_cast<struct sockaddr*>(
reinterpret_cast<struct sockaddr*>((char*)sa + RTAX_GATEWAY * SA_SIZE(sa)); (char*)sa + RTAX_GATEWAY * SA_SIZE(sa));
if (!gateway) { if (!gateway) {
return false; return false;
@ -440,7 +449,8 @@ bool nsNetworkLinkService::RoutingFromKernel(nsTArray<nsCString>& aHash) {
sin->sin_addr = mRouteCheckIPv4; sin->sin_addr = mRouteCheckIPv4;
if (write(sockfd, rtm, rtm->rtm_msglen) == -1) { if (write(sockfd, rtm, rtm->rtm_msglen) == -1) {
LOG(("RoutingFromKernel: write() failed. No route to the predefine destincation")); LOG(("RoutingFromKernel: write() failed. No route to the predefine "
"destincation"));
return false; return false;
} }
@ -451,9 +461,11 @@ bool nsNetworkLinkService::RoutingFromKernel(nsTArray<nsCString>& aHash) {
return false; return false;
} }
LOG(("RoutingFromKernel: read() rtm_type: %d (%d), rtm_pid: %d (%d), rtm_seq: %d (%d)\n", LOG(("RoutingFromKernel: read() rtm_type: %d (%d), rtm_pid: %d (%d), "
"rtm_seq: %d (%d)\n",
rtm->rtm_type, RTM_GET, rtm->rtm_pid, pid, rtm->rtm_seq, seq)); rtm->rtm_type, RTM_GET, rtm->rtm_pid, pid, rtm->rtm_seq, seq));
} while (rtm->rtm_type != RTM_GET || rtm->rtm_pid != pid || rtm->rtm_seq != seq); } while (rtm->rtm_type != RTM_GET || rtm->rtm_pid != pid ||
rtm->rtm_seq != seq);
return parseHashKey(rtm, aHash, true); return parseHashKey(rtm, aHash, true);
} }
@ -489,8 +501,9 @@ bool nsNetworkLinkService::IPv4NetworkId(SHA1Sum* aSHA1) {
// //
void nsNetworkLinkService::HashSortedPrefixesAndNetmasks( void nsNetworkLinkService::HashSortedPrefixesAndNetmasks(
std::vector<prefix_and_netmask> prefixAndNetmaskStore, SHA1Sum* sha1) { std::vector<prefix_and_netmask> prefixAndNetmaskStore, SHA1Sum* sha1) {
// getifaddrs does not guarantee the interfaces will always be in the same order. // getifaddrs does not guarantee the interfaces will always be in the same
// We want to make sure the hash remains consistent Regardless of the interface order. // order. We want to make sure the hash remains consistent Regardless of the
// interface order.
std::sort(prefixAndNetmaskStore.begin(), prefixAndNetmaskStore.end(), std::sort(prefixAndNetmaskStore.begin(), prefixAndNetmaskStore.end(),
[](prefix_and_netmask a, prefix_and_netmask b) { [](prefix_and_netmask a, prefix_and_netmask b) {
// compare prefixStore // compare prefixStore
@ -521,7 +534,8 @@ bool nsNetworkLinkService::IPv6NetworkId(SHA1Sum* sha1) {
if ((AF_INET6 == ifa->ifa_addr->sa_family) && if ((AF_INET6 == ifa->ifa_addr->sa_family) &&
!(ifa->ifa_flags & (IFF_POINTOPOINT | IFF_LOOPBACK))) { !(ifa->ifa_flags & (IFF_POINTOPOINT | IFF_LOOPBACK))) {
// only IPv6 interfaces that aren't pointtopoint or loopback // only IPv6 interfaces that aren't pointtopoint or loopback
struct sockaddr_in6* sin_netmask = (struct sockaddr_in6*)ifa->ifa_netmask; struct sockaddr_in6* sin_netmask =
(struct sockaddr_in6*)ifa->ifa_netmask;
if (sin_netmask) { if (sin_netmask) {
struct sockaddr_in6* sin_addr = (struct sockaddr_in6*)ifa->ifa_addr; struct sockaddr_in6* sin_addr = (struct sockaddr_in6*)ifa->ifa_addr;
int scope = net::utils::ipv6_scope(sin_addr->sin6_addr.s6_addr); int scope = net::utils::ipv6_scope(sin_addr->sin6_addr.s6_addr);
@ -530,17 +544,20 @@ bool nsNetworkLinkService::IPv6NetworkId(SHA1Sum* sha1) {
memset(&prefix, 0, sizeof(prefix)); memset(&prefix, 0, sizeof(prefix));
// Get the prefix by combining the address and netmask. // Get the prefix by combining the address and netmask.
for (size_t i = 0; i < sizeof(prefix); ++i) { for (size_t i = 0; i < sizeof(prefix); ++i) {
prefix.s6_addr[i] = prefix.s6_addr[i] = sin_addr->sin6_addr.s6_addr[i] &
sin_addr->sin6_addr.s6_addr[i] & sin_netmask->sin6_addr.s6_addr[i]; sin_netmask->sin6_addr.s6_addr[i];
} }
// check if prefix and netmask was already found // check if prefix and netmask was already found
auto prefixAndNetmask = std::make_pair(prefix, sin_netmask->sin6_addr); auto prefixAndNetmask =
std::make_pair(prefix, sin_netmask->sin6_addr);
auto foundPosition = std::find_if( auto foundPosition = std::find_if(
prefixAndNetmaskStore.begin(), prefixAndNetmaskStore.end(), prefixAndNetmaskStore.begin(), prefixAndNetmaskStore.end(),
[&prefixAndNetmask](prefix_and_netmask current) { [&prefixAndNetmask](prefix_and_netmask current) {
return memcmp(&prefixAndNetmask.first, &current.first, sizeof(in6_addr)) == 0 && return memcmp(&prefixAndNetmask.first, &current.first,
memcmp(&prefixAndNetmask.second, &current.second, sizeof(in6_addr)) == 0; sizeof(in6_addr)) == 0 &&
memcmp(&prefixAndNetmask.second, &current.second,
sizeof(in6_addr)) == 0;
}); });
if (foundPosition != prefixAndNetmaskStore.end()) { if (foundPosition != prefixAndNetmaskStore.end()) {
continue; continue;
@ -557,7 +574,8 @@ bool nsNetworkLinkService::IPv6NetworkId(SHA1Sum* sha1) {
return false; return false;
} }
nsNetworkLinkService::HashSortedPrefixesAndNetmasks(prefixAndNetmaskStore, sha1); nsNetworkLinkService::HashSortedPrefixesAndNetmasks(prefixAndNetmaskStore,
sha1);
return true; return true;
} }
@ -577,15 +595,17 @@ void nsNetworkLinkService::calculateNetworkIdWithDelay(uint32_t aDelay) {
return; return;
} }
nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); nsCOMPtr<nsIEventTarget> target =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
if (!target) { if (!target) {
return; return;
} }
MOZ_ALWAYS_SUCCEEDS( MOZ_ALWAYS_SUCCEEDS(target->Dispatch(
target->Dispatch(NewRunnableMethod("nsNetworkLinkService::calculateNetworkIdInternal", this, NewRunnableMethod("nsNetworkLinkService::calculateNetworkIdInternal",
&nsNetworkLinkService::calculateNetworkIdInternal), this,
NS_DISPATCH_NORMAL)); &nsNetworkLinkService::calculateNetworkIdInternal),
NS_DISPATCH_NORMAL));
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -615,7 +635,8 @@ void nsNetworkLinkService::calculateNetworkIdInternal(void) {
SeedNetworkId(sha1); SeedNetworkId(sha1);
uint8_t digest[SHA1Sum::kHashSize]; uint8_t digest[SHA1Sum::kHashSize];
sha1.finish(digest); sha1.finish(digest);
nsAutoCString newString(reinterpret_cast<char*>(digest), SHA1Sum::kHashSize); nsAutoCString newString(reinterpret_cast<char*>(digest),
SHA1Sum::kHashSize);
nsresult rv = Base64Encode(newString, output); nsresult rv = Base64Encode(newString, output);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
LOG(("networkid: id %s\n", output.get())); LOG(("networkid: id %s\n", output.get()));
@ -652,16 +673,17 @@ void nsNetworkLinkService::calculateNetworkIdInternal(void) {
if (idChanged && !initialIDCalculation) { if (idChanged && !initialIDCalculation) {
RefPtr<nsNetworkLinkService> self = this; RefPtr<nsNetworkLinkService> self = this;
NS_DispatchToMainThread( NS_DispatchToMainThread(NS_NewRunnableFunction(
NS_NewRunnableFunction("nsNetworkLinkService::calculateNetworkIdInternal", "nsNetworkLinkService::calculateNetworkIdInternal",
[self]() { self->OnNetworkIdChanged(); })); [self]() { self->OnNetworkIdChanged(); }));
} }
initialIDCalculation = false; initialIDCalculation = false;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsNetworkLinkService::Observe(nsISupports* subject, const char* topic, const char16_t* data) { nsNetworkLinkService::Observe(nsISupports* subject, const char* topic,
const char16_t* data) {
if (!strcmp(topic, "xpcom-shutdown")) { if (!strcmp(topic, "xpcom-shutdown")) {
Shutdown(); Shutdown();
} }
@ -671,14 +693,17 @@ nsNetworkLinkService::Observe(nsISupports* subject, const char* topic, const cha
/* static */ /* static */
void nsNetworkLinkService::NetworkConfigChanged(SCDynamicStoreRef aStoreREf, void nsNetworkLinkService::NetworkConfigChanged(SCDynamicStoreRef aStoreREf,
CFArrayRef aChangedKeys, void* aInfo) { CFArrayRef aChangedKeys,
void* aInfo) {
LOG(("nsNetworkLinkService::NetworkConfigChanged")); LOG(("nsNetworkLinkService::NetworkConfigChanged"));
bool ipConfigChanged = false; bool ipConfigChanged = false;
bool dnsConfigChanged = false; bool dnsConfigChanged = false;
for (CFIndex i = 0; i < CFArrayGetCount(aChangedKeys); ++i) { for (CFIndex i = 0; i < CFArrayGetCount(aChangedKeys); ++i) {
CFStringRef key = static_cast<CFStringRef>(CFArrayGetValueAtIndex(aChangedKeys, i)); CFStringRef key =
if (CFStringHasSuffix(key, kSCEntNetIPv4) || CFStringHasSuffix(key, kSCEntNetIPv6)) { static_cast<CFStringRef>(CFArrayGetValueAtIndex(aChangedKeys, i));
if (CFStringHasSuffix(key, kSCEntNetIPv4) ||
CFStringHasSuffix(key, kSCEntNetIPv6)) {
ipConfigChanged = true; ipConfigChanged = true;
} }
if (CFStringHasSuffix(key, kSCEntNetDNS)) { if (CFStringHasSuffix(key, kSCEntNetDNS)) {
@ -698,7 +723,8 @@ void nsNetworkLinkService::NetworkConfigChanged(SCDynamicStoreRef aStoreREf,
void nsNetworkLinkService::DNSConfigChanged(uint32_t aDelayMs) { void nsNetworkLinkService::DNSConfigChanged(uint32_t aDelayMs) {
LOG(("nsNetworkLinkService::DNSConfigChanged")); LOG(("nsNetworkLinkService::DNSConfigChanged"));
nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); nsCOMPtr<nsIEventTarget> target =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
if (!target) { if (!target) {
return; return;
} }
@ -717,9 +743,9 @@ void nsNetworkLinkService::DNSConfigChanged(uint32_t aDelayMs) {
"nsNetworkLinkService::GetDnsSuffixListInternal", target)); "nsNetworkLinkService::GetDnsSuffixListInternal", target));
mDNSConfigChangedTimers.AppendElement(timer); mDNSConfigChangedTimers.AppendElement(timer);
} else { } else {
MOZ_ALWAYS_SUCCEEDS(target->Dispatch( MOZ_ALWAYS_SUCCEEDS(target->Dispatch(NS_NewRunnableFunction(
NS_NewRunnableFunction("nsNetworkLinkService::GetDnsSuffixListInternal", "nsNetworkLinkService::GetDnsSuffixListInternal",
[self = RefPtr{this}]() { self->GetDnsSuffixListInternal(); }))); [self = RefPtr{this}]() { self->GetDnsSuffixListInternal(); })));
} }
} }
@ -745,13 +771,15 @@ nsresult nsNetworkLinkService::Init(void) {
bzero(&addr, sizeof(addr)); bzero(&addr, sizeof(addr));
addr.sin_len = sizeof(addr); addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
mReachability = ::SCNetworkReachabilityCreateWithAddress(nullptr, (struct sockaddr*)&addr); mReachability = ::SCNetworkReachabilityCreateWithAddress(
nullptr, (struct sockaddr*)&addr);
if (!mReachability) { if (!mReachability) {
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
SCNetworkReachabilityContext context = {0, this, nullptr, nullptr, nullptr}; SCNetworkReachabilityContext context = {0, this, nullptr, nullptr, nullptr};
if (!::SCNetworkReachabilitySetCallback(mReachability, ReachabilityChanged, &context)) { if (!::SCNetworkReachabilitySetCallback(mReachability, ReachabilityChanged,
&context)) {
NS_WARNING("SCNetworkReachabilitySetCallback failed."); NS_WARNING("SCNetworkReachabilitySetCallback failed.");
::CFRelease(mReachability); ::CFRelease(mReachability);
mReachability = nullptr; mReachability = nullptr;
@ -759,24 +787,25 @@ nsresult nsNetworkLinkService::Init(void) {
} }
SCDynamicStoreContext storeContext = {0, this, nullptr, nullptr, nullptr}; SCDynamicStoreContext storeContext = {0, this, nullptr, nullptr, nullptr};
mStoreRef = ::SCDynamicStoreCreate(nullptr, CFSTR("IPAndDNSChangeCallbackSCF"), mStoreRef =
NetworkConfigChanged, &storeContext); ::SCDynamicStoreCreate(nullptr, CFSTR("IPAndDNSChangeCallbackSCF"),
NetworkConfigChanged, &storeContext);
CFStringRef patterns[4] = {nullptr, nullptr, nullptr, nullptr}; CFStringRef patterns[4] = {nullptr, nullptr, nullptr, nullptr};
OSStatus err = getErrorCodePtr(mStoreRef); OSStatus err = getErrorCodePtr(mStoreRef);
if (err == noErr) { if (err == noErr) {
// This pattern is "State:/Network/Service/[^/]+/IPv4". // This pattern is "State:/Network/Service/[^/]+/IPv4".
patterns[0] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(nullptr, kSCDynamicStoreDomainState, patterns[0] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(
kSCCompAnyRegex, kSCEntNetIPv4); nullptr, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
// This pattern is "State:/Network/Service/[^/]+/IPv6". // This pattern is "State:/Network/Service/[^/]+/IPv6".
patterns[1] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(nullptr, kSCDynamicStoreDomainState, patterns[1] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(
kSCCompAnyRegex, kSCEntNetIPv6); nullptr, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
// This pattern is "State:/Network/Service/[^/]+/DNS". // This pattern is "State:/Network/Service/[^/]+/DNS".
patterns[2] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(nullptr, kSCDynamicStoreDomainState, patterns[2] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(
kSCCompAnyRegex, kSCEntNetDNS); nullptr, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetDNS);
// This pattern is "Setup:/Network/Service/[^/]+/DNS". // This pattern is "Setup:/Network/Service/[^/]+/DNS".
patterns[3] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(nullptr, kSCDynamicStoreDomainSetup, patterns[3] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(
kSCCompAnyRegex, kSCEntNetDNS); nullptr, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetDNS);
if (!patterns[0] || !patterns[1] || !patterns[2] || !patterns[3]) { if (!patterns[0] || !patterns[1] || !patterns[2] || !patterns[3]) {
err = -1; err = -1;
} }
@ -788,13 +817,15 @@ nsresult nsNetworkLinkService::Init(void) {
// that match that pattern list, then create our run loop // that match that pattern list, then create our run loop
// source. // source.
if (err == noErr) { if (err == noErr) {
patternList = ::CFArrayCreate(nullptr, (const void**)patterns, 4, &kCFTypeArrayCallBacks); patternList = ::CFArrayCreate(nullptr, (const void**)patterns, 4,
&kCFTypeArrayCallBacks);
if (!patternList) { if (!patternList) {
err = -1; err = -1;
} }
} }
if (err == noErr) { if (err == noErr) {
err = getErrorCodeBool(::SCDynamicStoreSetNotificationKeys(mStoreRef, nullptr, patternList)); err = getErrorCodeBool(
::SCDynamicStoreSetNotificationKeys(mStoreRef, nullptr, patternList));
} }
if (err == noErr) { if (err == noErr) {
@ -925,26 +956,31 @@ void nsNetworkLinkService::OnReachabilityChanged() {
return; return;
} }
NotifyObservers(NS_NETWORK_LINK_TOPIC, NotifyObservers(NS_NETWORK_LINK_TOPIC, mLinkUp ? NS_NETWORK_LINK_DATA_UP
mLinkUp ? NS_NETWORK_LINK_DATA_UP : NS_NETWORK_LINK_DATA_DOWN); : NS_NETWORK_LINK_DATA_DOWN);
} }
void nsNetworkLinkService::NotifyObservers(const char* aTopic, const char* aData) { void nsNetworkLinkService::NotifyObservers(const char* aTopic,
const char* aData) {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
LOG(("nsNetworkLinkService::NotifyObservers: topic:%s data:%s\n", aTopic, aData ? aData : "")); LOG(("nsNetworkLinkService::NotifyObservers: topic:%s data:%s\n", aTopic,
aData ? aData : ""));
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) { if (observerService) {
observerService->NotifyObservers(static_cast<nsINetworkLinkService*>(this), aTopic, observerService->NotifyObservers(
aData ? NS_ConvertASCIItoUTF16(aData).get() : nullptr); static_cast<nsINetworkLinkService*>(this), aTopic,
aData ? NS_ConvertASCIItoUTF16(aData).get() : nullptr);
} }
} }
/* static */ /* static */
void nsNetworkLinkService::ReachabilityChanged(SCNetworkReachabilityRef target, void nsNetworkLinkService::ReachabilityChanged(SCNetworkReachabilityRef target,
SCNetworkConnectionFlags flags, void* info) { SCNetworkConnectionFlags flags,
void* info) {
LOG(("nsNetworkLinkService::ReachabilityChanged")); LOG(("nsNetworkLinkService::ReachabilityChanged"));
nsNetworkLinkService* service = static_cast<nsNetworkLinkService*>(info); nsNetworkLinkService* service = static_cast<nsNetworkLinkService*>(info);

View file

@ -29,7 +29,8 @@ nsresult WifiScannerImpl::GetAccessPointsFromWLAN(
@try { @try {
NSBundle* bundle = [[[NSBundle alloc] NSBundle* bundle = [[[NSBundle alloc]
initWithPath:@"/System/Library/Frameworks/CoreWLAN.framework"] autorelease]; initWithPath:@"/System/Library/Frameworks/CoreWLAN.framework"]
autorelease];
if (!bundle) { if (!bundle) {
[pool release]; [pool release];
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
@ -41,7 +42,8 @@ nsresult WifiScannerImpl::GetAccessPointsFromWLAN(
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
id scanResult = [[CWI_class interface] scanForNetworksWithSSID:nil error:nil]; id scanResult = [[CWI_class interface] scanForNetworksWithSSID:nil
error:nil];
if (!scanResult) { if (!scanResult) {
[pool release]; [pool release];
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
@ -73,7 +75,8 @@ nsresult WifiScannerImpl::GetAccessPointsFromWLAN(
NSString* macString = [anObject bssid]; NSString* macString = [anObject bssid];
if (macString && ([macString length] == 17)) { if (macString && ([macString length] == 17)) {
for (NSUInteger i = 0; i < 6; ++i) { for (NSUInteger i = 0; i < 6; ++i) {
NSString* part = [macString substringWithRange:NSMakeRange(i * 3, 2)]; NSString* part =
[macString substringWithRange:NSMakeRange(i * 3, 2)];
NSScanner* scanner = [NSScanner scannerWithString:part]; NSScanner* scanner = [NSScanner scannerWithString:part];
unsigned int data = 0; unsigned int data = 0;
if (![scanner scanHexInt:&data]) { if (![scanner scanHexInt:&data]) {

View file

@ -35,12 +35,15 @@ nsresult ReauthenticateUserMacOS(const nsAString& aPrompt,
localizedReason:prompt localizedReason:prompt
reply:^(BOOL success, NSError* error) { reply:^(BOOL success, NSError* error) {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
// error is not particularly useful in this context, and we have no // error is not particularly useful in this context, and
// mechanism to really return it. We could use it to set the nsresult, // we have no mechanism to really return it. We could
// but this is a best-effort mechanism and there's no particular case for // use it to set the nsresult, but this is a best-effort
// propagating up XPCOM. The one exception being a user account that // mechanism and there's no particular case for
// has no passcode set, which we handle below. // propagating up XPCOM. The one exception being a user
errorPasswordNotSet = error && [error code] == kPasswordNotSetErrorCode; // account that has no passcode set, which we handle
// below.
errorPasswordNotSet =
error && [error code] == kPasswordNotSetErrorCode;
biometricSuccess = success || errorPasswordNotSet; biometricSuccess = success || errorPasswordNotSet;
dispatch_semaphore_signal(sema); dispatch_semaphore_signal(sema);
}); });

View file

@ -33,7 +33,8 @@
// Undocumented sandbox setup routines. // Undocumented sandbox setup routines.
extern "C" int sandbox_init_with_parameters(const char* profile, uint64_t flags, extern "C" int sandbox_init_with_parameters(const char* profile, uint64_t flags,
const char* const parameters[], char** errorbuf); const char* const parameters[],
char** errorbuf);
extern "C" void sandbox_free_error(char* errorbuf); extern "C" void sandbox_free_error(char* errorbuf);
extern "C" int sandbox_check(pid_t pid, const char* operation, int type, ...); extern "C" int sandbox_check(pid_t pid, const char* operation, int type, ...);
@ -50,7 +51,8 @@ class OSXVersion {
static void Get(int32_t& aMajor, int32_t& aMinor); static void Get(int32_t& aMajor, int32_t& aMinor);
private: private:
static void GetSystemVersion(int32_t& aMajor, int32_t& aMinor, int32_t& aBugFix); static void GetSystemVersion(int32_t& aMajor, int32_t& aMinor,
int32_t& aBugFix);
static bool mCached; static bool mCached;
static int32_t mOSXVersionMajor; static int32_t mOSXVersionMajor;
static int32_t mOSXVersionMinor; static int32_t mOSXVersionMinor;
@ -72,23 +74,26 @@ void OSXVersion::Get(int32_t& aMajor, int32_t& aMinor) {
aMinor = mOSXVersionMinor; aMinor = mOSXVersionMinor;
} }
void OSXVersion::GetSystemVersion(int32_t& aMajor, int32_t& aMinor, int32_t& aBugFix) { void OSXVersion::GetSystemVersion(int32_t& aMajor, int32_t& aMinor,
int32_t& aBugFix) {
SInt32 major = 0, minor = 0, bugfix = 0; SInt32 major = 0, minor = 0, bugfix = 0;
CFURLRef url = CFURLCreateWithString( CFURLRef url = CFURLCreateWithString(
kCFAllocatorDefault, CFSTR("file:///System/Library/CoreServices/SystemVersion.plist"), NULL); kCFAllocatorDefault,
CFSTR("file:///System/Library/CoreServices/SystemVersion.plist"), NULL);
CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url); CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
CFReadStreamOpen(stream); CFReadStreamOpen(stream);
CFDictionaryRef sysVersionPlist = (CFDictionaryRef)CFPropertyListCreateWithStream( CFDictionaryRef sysVersionPlist =
kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, NULL); (CFDictionaryRef)CFPropertyListCreateWithStream(
kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, NULL);
CFReadStreamClose(stream); CFReadStreamClose(stream);
CFRelease(stream); CFRelease(stream);
CFRelease(url); CFRelease(url);
CFStringRef versionString = CFStringRef versionString = (CFStringRef)CFDictionaryGetValue(
(CFStringRef)CFDictionaryGetValue(sysVersionPlist, CFSTR("ProductVersion")); sysVersionPlist, CFSTR("ProductVersion"));
CFArrayRef versions = CFArrayRef versions = CFStringCreateArrayBySeparatingStrings(
CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, versionString, CFSTR(".")); kCFAllocatorDefault, versionString, CFSTR("."));
CFIndex count = CFArrayGetCount(versions); CFIndex count = CFArrayGetCount(versions);
if (count > 0) { if (count > 0) {
CFStringRef component = (CFStringRef)CFArrayGetValueAtIndex(versions, 0); CFStringRef component = (CFStringRef)CFArrayGetValueAtIndex(versions, 0);
@ -188,22 +193,26 @@ void MacSandboxInfo::AppendAsParams(std::vector<std::string>& aParams) const {
} }
} }
void MacSandboxInfo::AppendStartupParam(std::vector<std::string>& aParams) const { void MacSandboxInfo::AppendStartupParam(
std::vector<std::string>& aParams) const {
aParams.push_back("-sbStartup"); aParams.push_back("-sbStartup");
} }
void MacSandboxInfo::AppendLoggingParam(std::vector<std::string>& aParams) const { void MacSandboxInfo::AppendLoggingParam(
std::vector<std::string>& aParams) const {
if (this->shouldLog) { if (this->shouldLog) {
aParams.push_back("-sbLogging"); aParams.push_back("-sbLogging");
} }
} }
void MacSandboxInfo::AppendAppPathParam(std::vector<std::string>& aParams) const { void MacSandboxInfo::AppendAppPathParam(
std::vector<std::string>& aParams) const {
aParams.push_back("-sbAppPath"); aParams.push_back("-sbAppPath");
aParams.push_back(this->appPath); aParams.push_back(this->appPath);
} }
void MacSandboxInfo::AppendPluginPathParam(std::vector<std::string>& aParams) const { void MacSandboxInfo::AppendPluginPathParam(
std::vector<std::string>& aParams) const {
aParams.push_back("-sbPluginPath"); aParams.push_back("-sbPluginPath");
aParams.push_back(this->pluginPath); aParams.push_back(this->pluginPath);
} }
@ -230,13 +239,15 @@ void MacSandboxInfo::AppendAudioParam(std::vector<std::string>& aParams) const {
} }
} }
void MacSandboxInfo::AppendWindowServerParam(std::vector<std::string>& aParams) const { void MacSandboxInfo::AppendWindowServerParam(
std::vector<std::string>& aParams) const {
if (this->hasWindowServer) { if (this->hasWindowServer) {
aParams.push_back("-sbAllowWindowServer"); aParams.push_back("-sbAllowWindowServer");
} }
} }
void MacSandboxInfo::AppendReadPathParams(std::vector<std::string>& aParams) const { void MacSandboxInfo::AppendReadPathParams(
std::vector<std::string>& aParams) const {
if (!this->testingReadPath1.empty()) { if (!this->testingReadPath1.empty()) {
aParams.push_back("-sbTestingReadPath"); aParams.push_back("-sbTestingReadPath");
aParams.push_back(this->testingReadPath1.c_str()); aParams.push_back(this->testingReadPath1.c_str());
@ -256,7 +267,8 @@ void MacSandboxInfo::AppendReadPathParams(std::vector<std::string>& aParams) con
} }
#ifdef DEBUG #ifdef DEBUG
void MacSandboxInfo::AppendDebugWriteDirParam(std::vector<std::string>& aParams) const { void MacSandboxInfo::AppendDebugWriteDirParam(
std::vector<std::string>& aParams) const {
if (!this->debugWriteDir.empty()) { if (!this->debugWriteDir.empty()) {
aParams.push_back("-sbDebugWriteDir"); aParams.push_back("-sbDebugWriteDir");
aParams.push_back(this->debugWriteDir.c_str()); aParams.push_back(this->debugWriteDir.c_str());
@ -430,7 +442,8 @@ bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage) {
profile.append(SandboxPolicyContentAudioAddend); profile.append(SandboxPolicyContentAudioAddend);
} }
} else { } else {
fprintf(stderr, "Content sandbox disabled due to sandbox level setting\n"); fprintf(stderr,
"Content sandbox disabled due to sandbox level setting\n");
return false; return false;
} }
} else { } else {
@ -465,7 +478,8 @@ bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage) {
params.push_back(nullptr); params.push_back(nullptr);
char* errorbuf = NULL; char* errorbuf = NULL;
int rv = sandbox_init_with_parameters(profile.c_str(), 0, params.data(), &errorbuf); int rv = sandbox_init_with_parameters(profile.c_str(), 0, params.data(),
&errorbuf);
if (rv) { if (rv) {
if (errorbuf) { if (errorbuf) {
char* msg = NULL; char* msg = NULL;
@ -490,7 +504,8 @@ bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage) {
* command line arguments. Return false if any sandbox parameters needed * command line arguments. Return false if any sandbox parameters needed
* for early startup of the sandbox are not present in the arguments. * for early startup of the sandbox are not present in the arguments.
*/ */
bool GetContentSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) { bool GetContentSandboxParamsFromArgs(int aArgc, char** aArgv,
MacSandboxInfo& aInfo) {
// Ensure we find these paramaters in the command // Ensure we find these paramaters in the command
// line arguments. Return false if any are missing. // line arguments. Return false if any are missing.
bool foundSandboxLevel = false; bool foundSandboxLevel = false;
@ -604,7 +619,8 @@ bool GetContentSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aI
return true; return true;
} }
bool GetUtilitySandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo, bool GetUtilitySandboxParamsFromArgs(int aArgc, char** aArgv,
MacSandboxInfo& aInfo,
bool aSandboxingKindRequired = true) { bool aSandboxingKindRequired = true) {
// Ensure we find these paramaters in the command // Ensure we find these paramaters in the command
// line arguments. Return false if any are missing. // line arguments. Return false if any are missing.
@ -650,11 +666,13 @@ bool GetUtilitySandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aI
return true; return true;
} }
bool GetSocketSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) { bool GetSocketSandboxParamsFromArgs(int aArgc, char** aArgv,
MacSandboxInfo& aInfo) {
return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false); return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false);
} }
bool GetPluginSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) { bool GetPluginSandboxParamsFromArgs(int aArgc, char** aArgv,
MacSandboxInfo& aInfo) {
// Ensure we find these paramaters in the command // Ensure we find these paramaters in the command
// line arguments. Return false if any are missing. // line arguments. Return false if any are missing.
bool foundAppPath = false; bool foundAppPath = false;
@ -725,7 +743,8 @@ bool GetPluginSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aIn
return true; return true;
} }
bool GetRDDSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) { bool GetRDDSandboxParamsFromArgs(int aArgc, char** aArgv,
MacSandboxInfo& aInfo) {
return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false); return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false);
} }
@ -733,8 +752,8 @@ bool GetRDDSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo)
* Returns true if no errors were encountered or if early sandbox startup is * Returns true if no errors were encountered or if early sandbox startup is
* not enabled for this process. Returns false if an error was encountered. * not enabled for this process. Returns false if an error was encountered.
*/ */
bool StartMacSandboxIfEnabled(const MacSandboxType aSandboxType, int aArgc, char** aArgv, bool StartMacSandboxIfEnabled(const MacSandboxType aSandboxType, int aArgc,
std::string& aErrorMessage) { char** aArgv, std::string& aErrorMessage) {
bool earlyStartupEnabled = false; bool earlyStartupEnabled = false;
// Check for the -sbStartup CLI parameter which // Check for the -sbStartup CLI parameter which
@ -796,7 +815,9 @@ bool IsMacSandboxStarted() { return sandbox_check(getpid(), NULL, 0) == 1; }
#ifdef DEBUG #ifdef DEBUG
// sandbox_check returns 1 if the specified process is sandboxed // sandbox_check returns 1 if the specified process is sandboxed
void AssertMacSandboxEnabled() { MOZ_ASSERT(sandbox_check(getpid(), NULL, 0) == 1); } void AssertMacSandboxEnabled() {
MOZ_ASSERT(sandbox_check(getpid(), NULL, 0) == 1);
}
#endif /* DEBUG */ #endif /* DEBUG */
} // namespace mozilla } // namespace mozilla

View file

@ -12,8 +12,8 @@
NS_IMPL_ISUPPORTS(nsParentalControlsService, nsIParentalControlsService) NS_IMPL_ISUPPORTS(nsParentalControlsService, nsIParentalControlsService)
nsParentalControlsService::nsParentalControlsService() : mEnabled(false) { nsParentalControlsService::nsParentalControlsService() : mEnabled(false) {
mEnabled = CFPreferencesAppValueIsForced(CFSTR("restrictWeb"), mEnabled = CFPreferencesAppValueIsForced(
CFSTR("com.apple.familycontrols.contentfilter")); CFSTR("restrictWeb"), CFSTR("com.apple.familycontrols.contentfilter"));
} }
nsParentalControlsService::~nsParentalControlsService() {} nsParentalControlsService::~nsParentalControlsService() {}
@ -37,13 +37,14 @@ nsParentalControlsService::GetLoggingEnabled(bool* aResult) {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsParentalControlsService::Log(int16_t aEntryType, bool blocked, nsIURI* aSource, nsParentalControlsService::Log(int16_t aEntryType, bool blocked,
nsIFile* aTarget) { nsIURI* aSource, nsIFile* aTarget) {
// silently drop on the floor // silently drop on the floor
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsParentalControlsService::IsAllowed(int16_t aAction, nsIURI* aUri, bool* _retval) { nsParentalControlsService::IsAllowed(int16_t aAction, nsIURI* aUri,
bool* _retval) {
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }

View file

@ -31,7 +31,8 @@ namespace mozilla {
nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult) { nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult) {
struct proc_taskinfo pti; struct proc_taskinfo pti;
if ((unsigned long)proc_pidinfo(getpid(), PROC_PIDTASKINFO, 0, &pti, PROC_PIDTASKINFO_SIZE) < if ((unsigned long)proc_pidinfo(getpid(), PROC_PIDTASKINFO, 0, &pti,
PROC_PIDTASKINFO_SIZE) <
PROC_PIDTASKINFO_SIZE) { PROC_PIDTASKINFO_SIZE) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -39,16 +40,16 @@ nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult) {
mach_timebase_info_data_t timebase; mach_timebase_info_data_t timebase;
GetTimeBase(&timebase); GetTimeBase(&timebase);
*aResult = (pti.pti_total_user + pti.pti_total_system) * timebase.numer / timebase.denom / *aResult = (pti.pti_total_user + pti.pti_total_system) * timebase.numer /
PR_NSEC_PER_MSEC; timebase.denom / PR_NSEC_PER_MSEC;
return NS_OK; return NS_OK;
} }
nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult) { nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult) {
task_power_info_v2_data_t task_power_info; task_power_info_v2_data_t task_power_info;
mach_msg_type_number_t count = TASK_POWER_INFO_V2_COUNT; mach_msg_type_number_t count = TASK_POWER_INFO_V2_COUNT;
kern_return_t kr = kern_return_t kr = task_info(mach_task_self(), TASK_POWER_INFO_V2,
task_info(mach_task_self(), TASK_POWER_INFO_V2, (task_info_t)&task_power_info, &count); (task_info_t)&task_power_info, &count);
if (kr != KERN_SUCCESS) { if (kr != KERN_SUCCESS) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -59,7 +60,8 @@ nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult) {
int GetCycleTimeFrequencyMHz() { return 0; } int GetCycleTimeFrequencyMHz() { return 0; }
ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&& aRequests) { ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(
nsTArray<ProcInfoRequest>&& aRequests) {
ProcInfoPromise::ResolveOrRejectValue result; ProcInfoPromise::ResolveOrRejectValue result;
HashMap<base::ProcessId, ProcInfo> gathered; HashMap<base::ProcessId, ProcInfo> gathered;
@ -81,14 +83,16 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
info.utilityActors = std::move(request.utilityInfo); info.utilityActors = std::move(request.utilityInfo);
struct proc_taskinfo pti; struct proc_taskinfo pti;
if ((unsigned long)proc_pidinfo(request.pid, PROC_PIDTASKINFO, 0, &pti, PROC_PIDTASKINFO_SIZE) < if ((unsigned long)proc_pidinfo(request.pid, PROC_PIDTASKINFO, 0, &pti,
PROC_PIDTASKINFO_SIZE) <
PROC_PIDTASKINFO_SIZE) { PROC_PIDTASKINFO_SIZE) {
// Can't read data for this process. // Can't read data for this process.
// Probably either a sandboxing issue or a race condition, e.g. // Probably either a sandboxing issue or a race condition, e.g.
// the process has been just been killed. Regardless, skip process. // the process has been just been killed. Regardless, skip process.
continue; continue;
} }
info.cpuTime = (pti.pti_total_user + pti.pti_total_system) * timebase.numer / timebase.denom; info.cpuTime = (pti.pti_total_user + pti.pti_total_system) *
timebase.numer / timebase.denom;
mach_port_t selectedTask; mach_port_t selectedTask;
// If we did not get a task from a child process, we use mach_task_self() // If we did not get a task from a child process, we use mach_task_self()
@ -102,7 +106,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
// matches the value in the 'Memory' column of the Activity Monitor. // matches the value in the 'Memory' column of the Activity Monitor.
task_vm_info_data_t task_vm_info; task_vm_info_data_t task_vm_info;
mach_msg_type_number_t count = TASK_VM_INFO_COUNT; mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
kern_return_t kr = task_info(selectedTask, TASK_VM_INFO, (task_info_t)&task_vm_info, &count); kern_return_t kr = task_info(selectedTask, TASK_VM_INFO,
(task_info_t)&task_vm_info, &count);
info.memory = kr == KERN_SUCCESS ? task_vm_info.phys_footprint : 0; info.memory = kr == KERN_SUCCESS ? task_vm_info.phys_footprint : 0;
// Now getting threads info // Now getting threads info
@ -123,8 +128,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
} }
// Deallocate the thread list. // Deallocate the thread list.
// Note that this deallocation is entirely undocumented, so the following code is based // Note that this deallocation is entirely undocumented, so the following
// on guesswork and random examples found on the web. // code is based on guesswork and random examples found on the web.
auto guardThreadCount = MakeScopeExit([&] { auto guardThreadCount = MakeScopeExit([&] {
if (threadList == nullptr) { if (threadList == nullptr) {
return; return;
@ -141,8 +146,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
// Basic thread info. // Basic thread info.
thread_extended_info_data_t threadInfoData; thread_extended_info_data_t threadInfoData;
count = THREAD_EXTENDED_INFO_COUNT; count = THREAD_EXTENDED_INFO_COUNT;
kret = kret = thread_info(threadList[i], THREAD_EXTENDED_INFO,
thread_info(threadList[i], THREAD_EXTENDED_INFO, (thread_info_t)&threadInfoData, &count); (thread_info_t)&threadInfoData, &count);
if (kret != KERN_SUCCESS) { if (kret != KERN_SUCCESS) {
continue; continue;
} }
@ -150,8 +155,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
// Getting the thread id. // Getting the thread id.
thread_identifier_info identifierInfo; thread_identifier_info identifierInfo;
count = THREAD_IDENTIFIER_INFO_COUNT; count = THREAD_IDENTIFIER_INFO_COUNT;
kret = thread_info(threadList[i], THREAD_IDENTIFIER_INFO, (thread_info_t)&identifierInfo, kret = thread_info(threadList[i], THREAD_IDENTIFIER_INFO,
&count); (thread_info_t)&identifierInfo, &count);
if (kret != KERN_SUCCESS) { if (kret != KERN_SUCCESS) {
continue; continue;
} }
@ -162,7 +167,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
result.SetReject(NS_ERROR_OUT_OF_MEMORY); result.SetReject(NS_ERROR_OUT_OF_MEMORY);
return result; return result;
} }
thread->cpuTime = threadInfoData.pth_user_time + threadInfoData.pth_system_time; thread->cpuTime =
threadInfoData.pth_user_time + threadInfoData.pth_system_time;
thread->name.AssignASCII(threadInfoData.pth_name); thread->name.AssignASCII(threadInfoData.pth_name);
thread->tid = identifierInfo.thread_id; thread->tid = identifierInfo.thread_id;
} }

View file

@ -18,21 +18,21 @@ using namespace mozilla;
nsresult nsMacRemoteClient::Init() { return NS_OK; } nsresult nsMacRemoteClient::Init() { return NS_OK; }
nsresult nsMacRemoteClient::SendCommandLine(const char* aProgram, const char* aProfile, nsresult nsMacRemoteClient::SendCommandLine(
int32_t argc, char** argv, const char* aProgram, const char* aProfile, int32_t argc, char** argv,
const char* aDesktopStartupID, char** aResponse, const char* aDesktopStartupID, char** aResponse, bool* aSucceeded) {
bool* aSucceeded) {
mozilla::MacAutoreleasePool pool; mozilla::MacAutoreleasePool pool;
*aSucceeded = false; *aSucceeded = false;
nsString className; nsString className;
BuildClassName(aProgram, aProfile, className); BuildClassName(aProgram, aProfile, className);
NSString* serverNameString = NSString* serverNameString = [NSString
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(className.get()) stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
length:className.Length()]; length:className.Length()];
CFMessagePortRef messageServer = CFMessagePortCreateRemote(0, (CFStringRef)serverNameString); CFMessagePortRef messageServer =
CFMessagePortCreateRemote(0, (CFStringRef)serverNameString);
if (messageServer) { if (messageServer) {
// Getting current process directory // Getting current process directory
@ -48,7 +48,8 @@ nsresult nsMacRemoteClient::SendCommandLine(const char* aProgram, const char* aP
NSData* data = [NSKeyedArchiver archivedDataWithRootObject:dict]; NSData* data = [NSKeyedArchiver archivedDataWithRootObject:dict];
CFMessagePortSendRequest(messageServer, 0, (CFDataRef)data, 10.0, 0.0, NULL, NULL); CFMessagePortSendRequest(messageServer, 0, (CFDataRef)data, 10.0, 0.0, NULL,
NULL);
CFMessagePortInvalidate(messageServer); CFMessagePortInvalidate(messageServer);
CFRelease(messageServer); CFRelease(messageServer);

View file

@ -22,20 +22,22 @@
#include "nsXPCOM.h" #include "nsXPCOM.h"
#include "RemoteUtils.h" #include "RemoteUtils.h"
CFDataRef messageServerCallback(CFMessagePortRef aLocal, int32_t aMsgid, CFDataRef aData, CFDataRef messageServerCallback(CFMessagePortRef aLocal, int32_t aMsgid,
void* aInfo) { CFDataRef aData, void* aInfo) {
// One of the clients submitted a structure. // One of the clients submitted a structure.
static_cast<nsMacRemoteServer*>(aInfo)->HandleCommandLine(aData); static_cast<nsMacRemoteServer*>(aInfo)->HandleCommandLine(aData);
return NULL; return NULL;
} }
// aData contains serialized Dictionary, which in turn contains command line arguments // aData contains serialized Dictionary, which in turn contains command line
// arguments
void nsMacRemoteServer::HandleCommandLine(CFDataRef aData) { void nsMacRemoteServer::HandleCommandLine(CFDataRef aData) {
mozilla::MacAutoreleasePool pool; mozilla::MacAutoreleasePool pool;
if (aData) { if (aData) {
NSDictionary* dict = [NSKeyedUnarchiver unarchiveObjectWithData:(NSData*)aData]; NSDictionary* dict =
[NSKeyedUnarchiver unarchiveObjectWithData:(NSData*)aData];
if (dict && [dict isKindOfClass:[NSDictionary class]]) { if (dict && [dict isKindOfClass:[NSDictionary class]]) {
NSArray* args = dict[@"args"]; NSArray* args = dict[@"args"];
if (!args) { if (!args) {
@ -54,7 +56,8 @@ void nsMacRemoteServer::HandleCommandLine(CFDataRef aData) {
argv[i] = arg; argv[i] = arg;
} }
nsresult rv = cmdLine->Init(argc, argv, nullptr, nsICommandLine::STATE_REMOTE_AUTO); nsresult rv =
cmdLine->Init(argc, argv, nullptr, nsICommandLine::STATE_REMOTE_AUTO);
// Cleaning up C array. // Cleaning up C array.
delete[] argv; delete[] argv;
@ -75,21 +78,22 @@ void nsMacRemoteServer::HandleCommandLine(CFDataRef aData) {
} }
} }
nsresult nsMacRemoteServer::Startup(const char* aAppName, const char* aProfileName) { nsresult nsMacRemoteServer::Startup(const char* aAppName,
const char* aProfileName) {
// This is the first instance ever. // This is the first instance ever.
// Let's register a notification listener here, // Let's register a notification listener here,
// In case future instances would want to notify us about command line arguments // In case future instances would want to notify us about command line
// passed to them. Note, that if mozilla process is restarting, we still need to // arguments passed to them. Note, that if mozilla process is restarting, we
// register for notifications. // still need to register for notifications.
mozilla::MacAutoreleasePool pool; mozilla::MacAutoreleasePool pool;
nsString className; nsString className;
BuildClassName(aAppName, aProfileName, className); BuildClassName(aAppName, aProfileName, className);
NSString* serverNameString = NSString* serverNameString = [NSString
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(className.get()) stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
length:className.Length()]; length:className.Length()];
CFMessagePortContext context; CFMessagePortContext context;
context.copyDescription = NULL; context.copyDescription = NULL;
@ -97,8 +101,9 @@ nsresult nsMacRemoteServer::Startup(const char* aAppName, const char* aProfileNa
context.release = NULL; context.release = NULL;
context.retain = NULL; context.retain = NULL;
context.version = NULL; context.version = NULL;
mMessageServer = CFMessagePortCreateLocal(NULL, (CFStringRef)serverNameString, mMessageServer =
messageServerCallback, &context, NULL); CFMessagePortCreateLocal(NULL, (CFStringRef)serverNameString,
messageServerCallback, &context, NULL);
if (!mMessageServer) { if (!mMessageServer) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }

View file

@ -61,7 +61,8 @@ static bool RestartApplication() {
// Set spawn attributes. // Set spawn attributes.
size_t attr_count = sizeof(pref_cpu_types) / sizeof(pref_cpu_types[0]); size_t attr_count = sizeof(pref_cpu_types) / sizeof(pref_cpu_types[0]);
size_t attr_ocount = 0; size_t attr_ocount = 0;
if (posix_spawnattr_setbinpref_np(&spawnattr, attr_count, pref_cpu_types, &attr_ocount) != 0 || if (posix_spawnattr_setbinpref_np(&spawnattr, attr_count, pref_cpu_types,
&attr_ocount) != 0 ||
attr_ocount != attr_count) { attr_ocount != attr_count) {
posix_spawnattr_destroy(&spawnattr); posix_spawnattr_destroy(&spawnattr);
return false; return false;
@ -89,7 +90,8 @@ static bool RestartApplication() {
gUI = self; gUI = self;
[mWindow center]; [mWindow center];
[mWindow setTitle:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]]; [mWindow setTitle:[[NSBundle mainBundle]
objectForInfoDictionaryKey:@"CFBundleName"]];
[NSApp activateIgnoringOtherApps:YES]; [NSApp activateIgnoringOtherApps:YES];
} }
@ -189,7 +191,9 @@ static bool RestartApplication() {
[self setView:mErrorView animate:NO]; [self setView:mErrorView animate:NO];
[mErrorHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)]; [mErrorHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)];
[self setStringFitVertically:mErrorLabel string:NSSTR(message) resizeWindow:YES]; [self setStringFitVertically:mErrorLabel
string:NSSTR(message)
resizeWindow:YES];
[mErrorCloseButton setTitle:Str(ST_OK)]; [mErrorCloseButton setTitle:Str(ST_OK)];
[mErrorCloseButton setKeyEquivalent:@"\r"]; [mErrorCloseButton setKeyEquivalent:@"\r"];
@ -199,19 +203,22 @@ static bool RestartApplication() {
- (void)showReportInfo { - (void)showReportInfo {
NSDictionary* boldAttr = @{ NSDictionary* boldAttr = @{
NSFontAttributeName : [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]], NSFontAttributeName :
[NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]],
NSForegroundColorAttributeName : NSColor.textColor, NSForegroundColorAttributeName : NSColor.textColor,
}; };
NSDictionary* normalAttr = @{ NSDictionary* normalAttr = @{
NSFontAttributeName : [NSFont systemFontOfSize:[NSFont smallSystemFontSize]], NSFontAttributeName :
[NSFont systemFontOfSize:[NSFont smallSystemFontSize]],
NSForegroundColorAttributeName : NSColor.textColor, NSForegroundColorAttributeName : NSColor.textColor,
}; };
[mViewReportTextView setString:@""]; [mViewReportTextView setString:@""];
for (Json::ValueConstIterator iter = gQueryParameters.begin(); iter != gQueryParameters.end(); for (Json::ValueConstIterator iter = gQueryParameters.begin();
++iter) { iter != gQueryParameters.end(); ++iter) {
NSAttributedString* key = [[NSAttributedString alloc] initWithString:NSSTR(iter.name() + ": ") NSAttributedString* key =
attributes:boldAttr]; [[NSAttributedString alloc] initWithString:NSSTR(iter.name() + ": ")
attributes:boldAttr];
string str; string str;
if (iter->isString()) { if (iter->isString()) {
str = iter->asString(); str = iter->asString();
@ -220,24 +227,27 @@ static bool RestartApplication() {
builder["indentation"] = ""; builder["indentation"] = "";
str = writeString(builder, *iter); str = writeString(builder, *iter);
} }
NSAttributedString* value = [[NSAttributedString alloc] initWithString:NSSTR(str + "\n") NSAttributedString* value =
attributes:normalAttr]; [[NSAttributedString alloc] initWithString:NSSTR(str + "\n")
attributes:normalAttr];
[[mViewReportTextView textStorage] appendAttributedString:key]; [[mViewReportTextView textStorage] appendAttributedString:key];
[[mViewReportTextView textStorage] appendAttributedString:value]; [[mViewReportTextView textStorage] appendAttributedString:value];
[key release]; [key release];
[value release]; [value release];
} }
NSAttributedString* extra = NSAttributedString* extra = [[NSAttributedString alloc]
[[NSAttributedString alloc] initWithString:NSSTR("\n" + gStrings[ST_EXTRAREPORTINFO]) initWithString:NSSTR("\n" + gStrings[ST_EXTRAREPORTINFO])
attributes:normalAttr]; attributes:normalAttr];
[[mViewReportTextView textStorage] appendAttributedString:extra]; [[mViewReportTextView textStorage] appendAttributedString:extra];
[extra release]; [extra release];
} }
- (void)maybeSubmitReport { - (void)maybeSubmitReport {
if ([mSubmitReportButton state] == NSOnState) { if ([mSubmitReportButton state] == NSOnState) {
[self setStringFitVertically:mProgressText string:Str(ST_REPORTDURINGSUBMIT) resizeWindow:YES]; [self setStringFitVertically:mProgressText
string:Str(ST_REPORTDURINGSUBMIT)
resizeWindow:YES];
// disable all the controls // disable all the controls
[self enableControls:NO]; [self enableControls:NO];
[mSubmitReportButton setEnabled:NO]; [mSubmitReportButton setEnabled:NO];
@ -258,7 +268,8 @@ static bool RestartApplication() {
- (IBAction)submitReportClicked:(id)sender { - (IBAction)submitReportClicked:(id)sender {
[self updateSubmit]; [self updateSubmit];
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setBool:([mSubmitReportButton state] == NSOnState) forKey:@"submitReport"]; [userDefaults setBool:([mSubmitReportButton state] == NSOnState)
forKey:@"submitReport"];
[userDefaults synchronize]; [userDefaults synchronize];
} }
@ -288,14 +299,16 @@ static bool RestartApplication() {
- (IBAction)includeURLClicked:(id)sender { - (IBAction)includeURLClicked:(id)sender {
[self updateURL]; [self updateURL];
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setBool:([mIncludeURLButton state] == NSOnState) forKey:@"IncludeURL"]; [userDefaults setBool:([mIncludeURLButton state] == NSOnState)
forKey:@"IncludeURL"];
[userDefaults synchronize]; [userDefaults synchronize];
} }
- (void)textDidChange:(NSNotification*)aNotification { - (void)textDidChange:(NSNotification*)aNotification {
// update comment parameter // update comment parameter
if ([[[mCommentText textStorage] mutableString] length] > 0) if ([[[mCommentText textStorage] mutableString] length] > 0)
gQueryParameters["Comments"] = [[[mCommentText textStorage] mutableString] UTF8String]; gQueryParameters["Comments"] =
[[[mCommentText textStorage] mutableString] UTF8String];
else else
gQueryParameters.removeMember("Comments"); gQueryParameters.removeMember("Comments");
} }
@ -308,7 +321,8 @@ static bool RestartApplication() {
if (([[aTextView string] lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + if (([[aTextView string] lengthOfBytesUsingEncoding:NSUTF8StringEncoding] +
[replacementString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] - [replacementString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] -
[[[aTextView string] substringWithRange:affectedCharRange] [[[aTextView string] substringWithRange:affectedCharRange]
lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) > MAX_COMMENT_LENGTH) { lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) >
MAX_COMMENT_LENGTH) {
return NO; return NO;
} }
return YES; return YES;
@ -331,8 +345,8 @@ static bool RestartApplication() {
if (gRestartArgs.size() == 0) { if (gRestartArgs.size() == 0) {
[mRestartButton removeFromSuperview]; [mRestartButton removeFromSuperview];
if (!gRTLlayout) { if (!gRTLlayout) {
closeFrame.origin.x = closeFrame.origin.x = restartFrame.origin.x +
restartFrame.origin.x + (restartFrame.size.width - closeFrame.size.width); (restartFrame.size.width - closeFrame.size.width);
} else { } else {
closeFrame.origin.x = restartFrame.origin.x; closeFrame.origin.x = restartFrame.origin.x;
} }
@ -357,7 +371,8 @@ static bool RestartApplication() {
// possibly resize window if both buttons no longer fit // possibly resize window if both buttons no longer fit
// leave 20 px from either side of the window, and 12 px // leave 20 px from either side of the window, and 12 px
// between the buttons // between the buttons
float neededWidth = closeFrame.size.width + restartFrame.size.width + 2 * 20 + 12; float neededWidth =
closeFrame.size.width + restartFrame.size.width + 2 * 20 + 12;
if (neededWidth > windowFrame.size.width) { if (neededWidth > windowFrame.size.width) {
windowFrame.size.width = neededWidth; windowFrame.size.width = neededWidth;
@ -379,7 +394,8 @@ static bool RestartApplication() {
[checkbox setFrame:frame]; [checkbox setFrame:frame];
} }
// keep existing spacing on left side, + 20 px spare on right // keep existing spacing on left side, + 20 px spare on right
float neededWidth = frame.origin.x + checkbox.intrinsicContentSize.width + 20; float neededWidth =
frame.origin.x + checkbox.intrinsicContentSize.width + 20;
if (neededWidth > windowFrame.size.width) { if (neededWidth > windowFrame.size.width) {
windowFrame.size.width = neededWidth; windowFrame.size.width = neededWidth;
[mWindow setFrame:windowFrame display:true animate:NO]; [mWindow setFrame:windowFrame display:true animate:NO];
@ -395,8 +411,9 @@ static bool RestartApplication() {
// now pin all the controls (except quit/submit) in place, // now pin all the controls (except quit/submit) in place,
// if we lengthen the window after this, it's just to lengthen // if we lengthen the window after this, it's just to lengthen
// the progress text, so nothing above that text should move. // the progress text, so nothing above that text should move.
NSView* views[] = {mSubmitReportButton, mViewReportButton, mCommentScrollView, NSView* views[] = {mSubmitReportButton, mViewReportButton,
mIncludeURLButton, mProgressIndicator, mProgressText}; mCommentScrollView, mIncludeURLButton,
mProgressIndicator, mProgressText};
for (auto view : views) { for (auto view : views) {
[view setAutoresizingMask:NSViewMinYMargin]; [view setAutoresizingMask:NSViewMinYMargin];
} }
@ -454,7 +471,9 @@ static bool RestartApplication() {
- (void)updateSubmit { - (void)updateSubmit {
if ([mSubmitReportButton state] == NSOnState) { if ([mSubmitReportButton state] == NSOnState) {
[self setStringFitVertically:mProgressText string:Str(ST_REPORTPRESUBMIT) resizeWindow:YES]; [self setStringFitVertically:mProgressText
string:Str(ST_REPORTPRESUBMIT)
resizeWindow:YES];
[mProgressText setHidden:NO]; [mProgressText setHidden:NO];
// enable all the controls // enable all the controls
[self enableControls:YES]; [self enableControls:YES];
@ -490,18 +509,24 @@ static bool RestartApplication() {
[NSApp terminate:self]; [NSApp terminate:self];
} }
[self setStringFitVertically:mProgressText string:Str(ST_SUBMITFAILED) resizeWindow:YES]; [self setStringFitVertically:mProgressText
string:Str(ST_SUBMITFAILED)
resizeWindow:YES];
// quit after 5 seconds // quit after 5 seconds
[self performSelector:@selector(closeMeDown:) withObject:nil afterDelay:5.0]; [self performSelector:@selector(closeMeDown:)
withObject:nil
afterDelay:5.0];
} }
[NSThread detachNewThreadSelector:@selector(uploadThread:) toTarget:self withObject:mPost]; [NSThread detachNewThreadSelector:@selector(uploadThread:)
toTarget:self
withObject:mPost];
} }
- (bool)setupPost { - (bool)setupPost {
NSURL* url = NSURL* url = [NSURL
[NSURL URLWithString:[NSSTR(gSendURL) URLWithString:[NSSTR(gSendURL) stringByAddingPercentEscapesUsingEncoding:
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; NSUTF8StringEncoding]];
if (!url) return false; if (!url) return false;
mPost = [[HTTPMultipartUpload alloc] initWithURL:url]; mPost = [[HTTPMultipartUpload alloc] initWithURL:url];
@ -514,7 +539,8 @@ static bool RestartApplication() {
Json::StreamWriterBuilder builder; Json::StreamWriterBuilder builder;
builder["indentation"] = ""; builder["indentation"] = "";
string output = writeString(builder, gQueryParameters).append("\r\n"); string output = writeString(builder, gQueryParameters).append("\r\n");
NSMutableString* parameters = [[NSMutableString alloc] initWithUTF8String:output.c_str()]; NSMutableString* parameters =
[[NSMutableString alloc] initWithUTF8String:output.c_str()];
[mPost setParameters:parameters]; [mPost setParameters:parameters];
[parameters release]; [parameters release];
@ -535,7 +561,8 @@ static bool RestartApplication() {
// if data is nil, we probably logged an error in uploadThread // if data is nil, we probably logged an error in uploadThread
if (data != nil && response != nil) { if (data != nil && response != nil) {
ostringstream message; ostringstream message;
message << "Crash report submission failed: server returned status " << [response statusCode]; message << "Crash report submission failed: server returned status "
<< [response statusCode];
LogMessage(message.str()); LogMessage(message.str());
} }
} else { } else {
@ -563,9 +590,13 @@ static bool RestartApplication() {
[mProgressIndicator stopAnimation:self]; [mProgressIndicator stopAnimation:self];
if (success) { if (success) {
[self setStringFitVertically:mProgressText string:Str(ST_REPORTSUBMITSUCCESS) resizeWindow:YES]; [self setStringFitVertically:mProgressText
string:Str(ST_REPORTSUBMITSUCCESS)
resizeWindow:YES];
} else { } else {
[self setStringFitVertically:mProgressText string:Str(ST_SUBMITFAILED) resizeWindow:YES]; [self setStringFitVertically:mProgressText
string:Str(ST_SUBMITFAILED)
resizeWindow:YES];
} }
// quit after 5 seconds // quit after 5 seconds
[self performSelector:@selector(closeMeDown:) withObject:nil afterDelay:5.0]; [self performSelector:@selector(closeMeDown:) withObject:nil afterDelay:5.0];
@ -582,13 +613,16 @@ static bool RestartApplication() {
LogMessage("Crash report submission failed: " + message); LogMessage("Crash report submission failed: " + message);
} }
[self performSelectorOnMainThread:@selector(uploadComplete:) withObject:data waitUntilDone:YES]; [self performSelectorOnMainThread:@selector(uploadComplete:)
withObject:data
waitUntilDone:YES];
[autoreleasepool release]; [autoreleasepool release];
} }
// to get auto-quit when we close the window // to get auto-quit when we close the window
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication { - (BOOL)applicationShouldTerminateAfterLastWindowClosed:
(NSApplication*)theApplication {
return YES; return YES;
} }
@ -621,10 +655,12 @@ static bool RestartApplication() {
- (void)setPlaceholder:(NSString*)placeholder { - (void)setPlaceholder:(NSString*)placeholder {
NSColor* txtColor = [NSColor disabledControlTextColor]; NSColor* txtColor = [NSColor disabledControlTextColor];
NSDictionary* txtDict = NSDictionary* txtDict = [NSDictionary
[NSDictionary dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName, nil]; dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName,
mPlaceHolderString = [[NSMutableAttributedString alloc] initWithString:placeholder nil];
attributes:txtDict]; mPlaceHolderString =
[[NSMutableAttributedString alloc] initWithString:placeholder
attributes:txtDict];
if (gRTLlayout) if (gRTLlayout)
[mPlaceHolderString setAlignment:NSTextAlignmentRight [mPlaceHolderString setAlignment:NSTextAlignmentRight
range:NSMakeRange(0, [placeholder length])]; range:NSMakeRange(0, [placeholder length])];
@ -649,9 +685,11 @@ static bool RestartApplication() {
txtColor = [NSColor textColor]; txtColor = [NSColor textColor];
else else
txtColor = [NSColor disabledControlTextColor]; txtColor = [NSColor disabledControlTextColor];
NSDictionary* txtDict = NSDictionary* txtDict = [NSDictionary
[NSDictionary dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName, nil]; dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName,
colorString = [[NSAttributedString alloc] initWithString:[self string] attributes:txtDict]; nil];
colorString = [[NSAttributedString alloc] initWithString:[self string]
attributes:txtDict];
[[self textStorage] setAttributedString:colorString]; [[self textStorage] setAttributedString:colorString];
[self setInsertionPointColor:txtColor]; [self setInsertionPointColor:txtColor];
[colorString release]; [colorString release];
@ -671,14 +709,16 @@ bool UIInit() {
gMainPool = [[NSAutoreleasePool alloc] init]; gMainPool = [[NSAutoreleasePool alloc] init];
[NSApplication sharedApplication]; [NSApplication sharedApplication];
if (gStrings.find("isRTL") != gStrings.end() && gStrings["isRTL"] == "yes") gRTLlayout = true; if (gStrings.find("isRTL") != gStrings.end() && gStrings["isRTL"] == "yes")
gRTLlayout = true;
if (gAutoSubmit) { if (gAutoSubmit) {
gUI = [[CrashReporterUI alloc] init]; gUI = [[CrashReporterUI alloc] init];
} else { } else {
[[NSBundle mainBundle] loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu") [[NSBundle mainBundle]
owner:NSApp loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu")
topLevelObjects:nil]; owner:NSApp
topLevelObjects:nil];
} }
return true; return true;
@ -724,9 +764,10 @@ bool UIGetIniPath(string& path) {
return true; return true;
} }
bool UIGetSettingsPath(const string& vendor, const string& product, string& settingsPath) { bool UIGetSettingsPath(const string& vendor, const string& product,
NSArray* paths = string& settingsPath) {
NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); NSArray* paths = NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString* destPath = [paths firstObject]; NSString* destPath = [paths firstObject];
// Note that MacOS ignores the vendor when creating the profile hierarchy - // Note that MacOS ignores the vendor when creating the profile hierarchy -
@ -751,10 +792,12 @@ bool UIMoveFile(const string& file, const string& newfile) {
if (errno != EXDEV) return false; if (errno != EXDEV) return false;
NSFileManager* fileManager = [NSFileManager defaultManager]; NSFileManager* fileManager = [NSFileManager defaultManager];
NSString* source = [fileManager stringWithFileSystemRepresentation:file.c_str() NSString* source =
length:file.length()]; [fileManager stringWithFileSystemRepresentation:file.c_str()
NSString* dest = [fileManager stringWithFileSystemRepresentation:newfile.c_str() length:file.length()];
length:newfile.length()]; NSString* dest =
[fileManager stringWithFileSystemRepresentation:newfile.c_str()
length:newfile.length()];
if (!source || !dest) return false; if (!source || !dest) return false;
[fileManager moveItemAtPath:source toPath:dest error:NULL]; [fileManager moveItemAtPath:source toPath:dest error:NULL];

View file

@ -55,7 +55,8 @@ bool IsBinaryArmExecutable(const char* executablePath) {
bool isArmExecutable = false; bool isArmExecutable = false;
CFURLRef url = ::CFURLCreateFromFileSystemRepresentation( CFURLRef url = ::CFURLCreateFromFileSystemRepresentation(
kCFAllocatorDefault, (const UInt8*)executablePath, strlen(executablePath), false); kCFAllocatorDefault, (const UInt8*)executablePath, strlen(executablePath),
false);
if (!url) { if (!url) {
return false; return false;
} }
@ -68,7 +69,8 @@ bool IsBinaryArmExecutable(const char* executablePath) {
CFIndex archCount = ::CFArrayGetCount(archs); CFIndex archCount = ::CFArrayGetCount(archs);
for (CFIndex i = 0; i < archCount; i++) { for (CFIndex i = 0; i < archCount; i++) {
CFNumberRef currentArch = static_cast<CFNumberRef>(::CFArrayGetValueAtIndex(archs, i)); CFNumberRef currentArch =
static_cast<CFNumberRef>(::CFArrayGetValueAtIndex(archs, i));
int currentArchInt = 0; int currentArchInt = 0;
if (!::CFNumberGetValue(currentArch, kCFNumberIntType, &currentArchInt)) { if (!::CFNumberGetValue(currentArch, kCFNumberIntType, &currentArchInt)) {
continue; continue;
@ -161,7 +163,8 @@ void LaunchMacPostProcess(const char* aAppBundle) {
// Launch helper to perform post processing for the update; this is the Mac // Launch helper to perform post processing for the update; this is the Mac
// analogue of LaunchWinPostProcess (PostUpdateWin). // analogue of LaunchWinPostProcess (PostUpdateWin).
NSString* iniPath = [NSString stringWithUTF8String:aAppBundle]; NSString* iniPath = [NSString stringWithUTF8String:aAppBundle];
iniPath = [iniPath stringByAppendingPathComponent:@"Contents/Resources/updater.ini"]; iniPath = [iniPath
stringByAppendingPathComponent:@"Contents/Resources/updater.ini"];
NSFileManager* fileManager = [NSFileManager defaultManager]; NSFileManager* fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:iniPath]) { if (![fileManager fileExistsAtPath:iniPath]) {
@ -171,8 +174,8 @@ void LaunchMacPostProcess(const char* aAppBundle) {
int readResult; int readResult;
mozilla::UniquePtr<char[]> values[2]; mozilla::UniquePtr<char[]> values[2];
readResult = readResult = ReadStrings([iniPath UTF8String], "ExeRelPath\0ExeArg\0", 2,
ReadStrings([iniPath UTF8String], "ExeRelPath\0ExeArg\0", 2, values, "PostUpdateMac"); values, "PostUpdateMac");
if (readResult) { if (readResult) {
return; return;
} }
@ -194,7 +197,8 @@ void LaunchMacPostProcess(const char* aAppBundle) {
exeFullPath = [exeFullPath stringByAppendingPathComponent:exeRelPath]; exeFullPath = [exeFullPath stringByAppendingPathComponent:exeRelPath];
mozilla::UniquePtr<char[]> optVal; mozilla::UniquePtr<char[]> optVal;
readResult = ReadStrings([iniPath UTF8String], "ExeAsync\0", 1, &optVal, "PostUpdateMac"); readResult = ReadStrings([iniPath UTF8String], "ExeAsync\0", 1, &optVal,
"PostUpdateMac");
NSTask* task = [[NSTask alloc] init]; NSTask* task = [[NSTask alloc] init];
[task setLaunchPath:exeFullPath]; [task setLaunchPath:exeFullPath];
@ -223,8 +227,10 @@ id ConnectToUpdateServer() {
updateServer = (id)[NSConnection updateServer = (id)[NSConnection
rootProxyForConnectionWithRegisteredName:@"org.mozilla.updater.server" rootProxyForConnectionWithRegisteredName:@"org.mozilla.updater.server"
host:nil host:nil
usingNameServer:[NSSocketPortNameServer sharedInstance]]; usingNameServer:[NSSocketPortNameServer
if (!updateServer || ![updateServer respondsToSelector:@selector(abort)] || sharedInstance]];
if (!updateServer ||
![updateServer respondsToSelector:@selector(abort)] ||
![updateServer respondsToSelector:@selector(getArguments)] || ![updateServer respondsToSelector:@selector(getArguments)] ||
![updateServer respondsToSelector:@selector(shutdown)]) { ![updateServer respondsToSelector:@selector(shutdown)]) {
NSLog(@"Server doesn't exist or doesn't provide correct selectors."); NSLog(@"Server doesn't exist or doesn't provide correct selectors.");
@ -262,9 +268,13 @@ void CleanupElevatedMacUpdate(bool aFailureOccurred) {
} }
NSFileManager* manager = [NSFileManager defaultManager]; NSFileManager* manager = [NSFileManager defaultManager];
[manager removeItemAtPath:@"/Library/PrivilegedHelperTools/org.mozilla.updater" error:nil]; [manager
[manager removeItemAtPath:@"/Library/LaunchDaemons/org.mozilla.updater.plist" error:nil]; removeItemAtPath:@"/Library/PrivilegedHelperTools/org.mozilla.updater"
const char* launchctlArgs[] = {"/bin/launchctl", "remove", "org.mozilla.updater"}; error:nil];
[manager removeItemAtPath:@"/Library/LaunchDaemons/org.mozilla.updater.plist"
error:nil];
const char* launchctlArgs[] = {"/bin/launchctl", "remove",
"org.mozilla.updater"};
// The following call will terminate the current process due to the "remove" // The following call will terminate the current process due to the "remove"
// argument in launchctlArgs. // argument in launchctlArgs.
LaunchChild(3, launchctlArgs); LaunchChild(3, launchctlArgs);
@ -282,13 +292,15 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
} }
@try { @try {
NSArray* updaterArguments = [updateServer performSelector:@selector(getArguments)]; NSArray* updaterArguments =
[updateServer performSelector:@selector(getArguments)];
*argc = [updaterArguments count]; *argc = [updaterArguments count];
char** tempArgv = (char**)malloc(sizeof(char*) * (*argc)); char** tempArgv = (char**)malloc(sizeof(char*) * (*argc));
for (int i = 0; i < *argc; i++) { for (int i = 0; i < *argc; i++) {
int argLen = [[updaterArguments objectAtIndex:i] length] + 1; int argLen = [[updaterArguments objectAtIndex:i] length] + 1;
tempArgv[i] = (char*)malloc(argLen); tempArgv[i] = (char*)malloc(argLen);
strncpy(tempArgv[i], [[updaterArguments objectAtIndex:i] UTF8String], argLen); strncpy(tempArgv[i], [[updaterArguments objectAtIndex:i] UTF8String],
argLen);
} }
*argv = tempArgv; *argv = tempArgv;
} @catch (NSException* e) { } @catch (NSException* e) {
@ -334,7 +346,8 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
- (BOOL)runServer { - (BOOL)runServer {
NSPort* serverPort = [NSSocketPort port]; NSPort* serverPort = [NSSocketPort port];
NSConnection* server = [NSConnection connectionWithReceivePort:serverPort sendPort:serverPort]; NSConnection* server = [NSConnection connectionWithReceivePort:serverPort
sendPort:serverPort];
[server setRootObject:self]; [server setRootObject:self];
if ([server registerName:@"org.mozilla.updater.server" if ([server registerName:@"org.mozilla.updater.server"
withNameServer:[NSSocketPortNameServer sharedInstance]] == NO) { withNameServer:[NSSocketPortNameServer sharedInstance]] == NO) {
@ -343,8 +356,9 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
return NO; return NO;
} }
while ([self shouldKeepRunning] && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode while ([self shouldKeepRunning] &&
beforeDate:[NSDate distantFuture]]) [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]])
; ;
return ![self wasAborted]; return ![self wasAborted];
} }
@ -394,9 +408,11 @@ bool IsOwnedByGroupAdmin(const char* aAppBundle) {
NSString* appDir = [NSString stringWithUTF8String:aAppBundle]; NSString* appDir = [NSString stringWithUTF8String:aAppBundle];
NSFileManager* fileManager = [NSFileManager defaultManager]; NSFileManager* fileManager = [NSFileManager defaultManager];
NSDictionary* attributes = [fileManager attributesOfItemAtPath:appDir error:nil]; NSDictionary* attributes = [fileManager attributesOfItemAtPath:appDir
error:nil];
bool isOwnedByAdmin = false; bool isOwnedByAdmin = false;
if (attributes && [[attributes valueForKey:NSFileGroupOwnerAccountID] intValue] == 80) { if (attributes &&
[[attributes valueForKey:NSFileGroupOwnerAccountID] intValue] == 80) {
isOwnedByAdmin = true; isOwnedByAdmin = true;
} }
return isOwnedByAdmin; return isOwnedByAdmin;
@ -425,13 +441,14 @@ void SetGroupOwnershipAndPermissions(const char* aAppBundle) {
return; return;
} }
NSArray* permKeys = NSArray* permKeys = [NSArray
[NSArray arrayWithObjects:NSFileGroupOwnerAccountID, NSFilePosixPermissions, nil]; arrayWithObjects:NSFileGroupOwnerAccountID, NSFilePosixPermissions, nil];
// For all descendants of Firefox.app, set group ownership to 80 ("admin") and // For all descendants of Firefox.app, set group ownership to 80 ("admin") and
// ensure write permission for the group. // ensure write permission for the group.
for (NSString* currPath in paths) { for (NSString* currPath in paths) {
NSString* child = [appDir stringByAppendingPathComponent:currPath]; NSString* child = [appDir stringByAppendingPathComponent:currPath];
NSDictionary* oldAttributes = [fileManager attributesOfItemAtPath:child error:&error]; NSDictionary* oldAttributes = [fileManager attributesOfItemAtPath:child
error:&error];
if (error) { if (error) {
return; return;
} }
@ -440,12 +457,20 @@ void SetGroupOwnershipAndPermissions(const char* aAppBundle) {
if ([oldAttributes fileType] == NSFileTypeSymbolicLink) { if ([oldAttributes fileType] == NSFileTypeSymbolicLink) {
continue; continue;
} }
NSNumber* oldPerms = (NSNumber*)[oldAttributes valueForKey:NSFilePosixPermissions]; NSNumber* oldPerms =
(NSNumber*)[oldAttributes valueForKey:NSFilePosixPermissions];
NSArray* permObjects = [NSArray NSArray* permObjects = [NSArray
arrayWithObjects:[NSNumber numberWithUnsignedLong:80], arrayWithObjects:[NSNumber numberWithUnsignedLong:80],
[NSNumber numberWithUnsignedLong:[oldPerms shortValue] | 020], nil]; [NSNumber
NSDictionary* attributes = [NSDictionary dictionaryWithObjects:permObjects forKeys:permKeys]; numberWithUnsignedLong:[oldPerms shortValue] |
if (![fileManager setAttributes:attributes ofItemAtPath:child error:&error] || error) { 020],
nil];
NSDictionary* attributes = [NSDictionary dictionaryWithObjects:permObjects
forKeys:permKeys];
if (![fileManager setAttributes:attributes
ofItemAtPath:child
error:&error] ||
error) {
return; return;
} }
} }
@ -483,7 +508,9 @@ bool PerformInstallationFromDMG(int argc, char** argv) {
} }
NSString* bundlePath = [NSString stringWithUTF8String:argv[2]]; NSString* bundlePath = [NSString stringWithUTF8String:argv[2]];
NSString* destPath = [NSString stringWithUTF8String:argv[3]]; NSString* destPath = [NSString stringWithUTF8String:argv[3]];
if ([[NSFileManager defaultManager] copyItemAtPath:bundlePath toPath:destPath error:nil]) { if ([[NSFileManager defaultManager] copyItemAtPath:bundlePath
toPath:destPath
error:nil]) {
RegisterAppWithLaunchServices(destPath); RegisterAppWithLaunchServices(destPath);
StripQuarantineBit(destPath); StripQuarantineBit(destPath);
return true; return true;

View file

@ -32,12 +32,14 @@ static const char* sUpdatePath;
NSWindow* w = [progressBar window]; NSWindow* w = [progressBar window];
[w setTitle:[NSString stringWithUTF8String:sLabels.title.get()]]; [w setTitle:[NSString stringWithUTF8String:sLabels.title.get()]];
[progressTextField setStringValue:[NSString stringWithUTF8String:sLabels.info.get()]]; [progressTextField
setStringValue:[NSString stringWithUTF8String:sLabels.info.get()]];
NSRect origTextFrame = [progressTextField frame]; NSRect origTextFrame = [progressTextField frame];
[progressTextField sizeToFit]; [progressTextField sizeToFit];
int widthAdjust = progressTextField.frame.size.width - origTextFrame.size.width; int widthAdjust =
progressTextField.frame.size.width - origTextFrame.size.width;
if (widthAdjust > 0) { if (widthAdjust > 0) {
NSRect f; NSRect f;
@ -118,7 +120,9 @@ int ShowProgressUI(bool indeterminate) {
sIndeterminate = indeterminate; sIndeterminate = indeterminate;
[NSApplication sharedApplication]; [NSApplication sharedApplication];
[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp topLevelObjects:nil]; [[NSBundle mainBundle] loadNibNamed:@"MainMenu"
owner:NSApp
topLevelObjects:nil];
[NSApp run]; [NSApp run];
return 0; return 0;

View file

@ -34,8 +34,8 @@ class nsOSXSystemProxySettings : public nsISystemProxySettings {
nsresult GetAutoconfigURL(nsAutoCString& aResult) const; nsresult GetAutoconfigURL(nsAutoCString& aResult) const;
// Find the SystemConfiguration proxy & port for a given URI // Find the SystemConfiguration proxy & port for a given URI
nsresult FindSCProxyPort(const nsACString& aScheme, nsACString& aResultHost, int32_t& aResultPort, nsresult FindSCProxyPort(const nsACString& aScheme, nsACString& aResultHost,
bool& aResultSocksProxy); int32_t& aResultPort, bool& aResultSocksProxy);
// is host:port on the proxy exception list? // is host:port on the proxy exception list?
bool IsInExceptionList(const nsACString& aHost) const; bool IsInExceptionList(const nsACString& aHost) const;
@ -69,22 +69,26 @@ nsOSXSystemProxySettings::GetMainThreadOnly(bool* aMainThreadOnly) {
} }
// Mapping of URI schemes to SystemConfiguration keys // Mapping of URI schemes to SystemConfiguration keys
const nsOSXSystemProxySettings::SchemeMapping nsOSXSystemProxySettings::gSchemeMappingList[] = { const nsOSXSystemProxySettings::SchemeMapping
{"http", kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort, nsOSXSystemProxySettings::gSchemeMappingList[] = {
false}, {"http", kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy,
{"https", kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSProxy, kSCPropNetProxiesHTTPSPort, kSCPropNetProxiesHTTPPort, false},
false}, {"https", kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSProxy,
{"ftp", kSCPropNetProxiesFTPEnable, kSCPropNetProxiesFTPProxy, kSCPropNetProxiesFTPPort, false}, kSCPropNetProxiesHTTPSPort, false},
{"socks", kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort, {"ftp", kSCPropNetProxiesFTPEnable, kSCPropNetProxiesFTPProxy,
true}, kSCPropNetProxiesFTPPort, false},
{NULL, NULL, NULL, NULL, false}, {"socks", kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy,
kSCPropNetProxiesSOCKSPort, true},
{NULL, NULL, NULL, NULL, false},
}; };
static void ProxyHasChangedWrapper(SCDynamicStoreRef aStore, CFArrayRef aChangedKeys, void* aInfo) { static void ProxyHasChangedWrapper(SCDynamicStoreRef aStore,
CFArrayRef aChangedKeys, void* aInfo) {
static_cast<nsOSXSystemProxySettings*>(aInfo)->ProxyHasChanged(); static_cast<nsOSXSystemProxySettings*>(aInfo)->ProxyHasChanged();
} }
nsOSXSystemProxySettings::nsOSXSystemProxySettings() : mSystemDynamicStore(NULL), mProxyDict(NULL) { nsOSXSystemProxySettings::nsOSXSystemProxySettings()
: mSystemDynamicStore(NULL), mProxyDict(NULL) {
mContext = (SCDynamicStoreContext){0, this, NULL, NULL, NULL}; mContext = (SCDynamicStoreContext){0, this, NULL, NULL, NULL};
} }
@ -94,15 +98,16 @@ nsresult nsOSXSystemProxySettings::Init() {
// Register for notification of proxy setting changes // Register for notification of proxy setting changes
// See: // See:
// http://developer.apple.com/documentation/Networking/Conceptual/CFNetwork/CFStreamTasks/chapter_4_section_5.html // http://developer.apple.com/documentation/Networking/Conceptual/CFNetwork/CFStreamTasks/chapter_4_section_5.html
mSystemDynamicStore = mSystemDynamicStore = SCDynamicStoreCreate(NULL, CFSTR("Mozilla"),
SCDynamicStoreCreate(NULL, CFSTR("Mozilla"), ProxyHasChangedWrapper, &mContext); ProxyHasChangedWrapper, &mContext);
if (!mSystemDynamicStore) return NS_ERROR_FAILURE; if (!mSystemDynamicStore) return NS_ERROR_FAILURE;
// Set up the store to monitor any changes to the proxies // Set up the store to monitor any changes to the proxies
CFStringRef proxiesKey = SCDynamicStoreKeyCreateProxies(NULL); CFStringRef proxiesKey = SCDynamicStoreKeyCreateProxies(NULL);
if (!proxiesKey) return NS_ERROR_FAILURE; if (!proxiesKey) return NS_ERROR_FAILURE;
CFArrayRef keyArray = CFArrayCreate(NULL, (const void**)(&proxiesKey), 1, &kCFTypeArrayCallBacks); CFArrayRef keyArray = CFArrayCreate(NULL, (const void**)(&proxiesKey), 1,
&kCFTypeArrayCallBacks);
CFRelease(proxiesKey); CFRelease(proxiesKey);
if (!keyArray) return NS_ERROR_FAILURE; if (!keyArray) return NS_ERROR_FAILURE;
@ -113,7 +118,8 @@ nsresult nsOSXSystemProxySettings::Init() {
CFRunLoopSourceRef storeRLSource = CFRunLoopSourceRef storeRLSource =
SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0); SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0);
if (!storeRLSource) return NS_ERROR_FAILURE; if (!storeRLSource) return NS_ERROR_FAILURE;
CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLSource, kCFRunLoopCommonModes); CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLSource,
kCFRunLoopCommonModes);
CFRelease(storeRLSource); CFRelease(storeRLSource);
// Load the initial copy of proxy info // Load the initial copy of proxy info
@ -135,7 +141,8 @@ nsOSXSystemProxySettings::~nsOSXSystemProxySettings() {
if (mSystemDynamicStore) { if (mSystemDynamicStore) {
// Invalidate the dynamic store's run loop source // Invalidate the dynamic store's run loop source
// to get the store out of the run loop // to get the store out of the run loop
CFRunLoopSourceRef rls = SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0); CFRunLoopSourceRef rls =
SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0);
if (rls) { if (rls) {
CFRunLoopSourceInvalidate(rls); CFRunLoopSourceInvalidate(rls);
CFRelease(rls); CFRelease(rls);
@ -158,20 +165,24 @@ void nsOSXSystemProxySettings::ProxyHasChanged() {
} }
nsresult nsOSXSystemProxySettings::FindSCProxyPort(const nsACString& aScheme, nsresult nsOSXSystemProxySettings::FindSCProxyPort(const nsACString& aScheme,
nsACString& aResultHost, int32_t& aResultPort, nsACString& aResultHost,
int32_t& aResultPort,
bool& aResultSocksProxy) { bool& aResultSocksProxy) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NS_ENSURE_TRUE(mProxyDict != NULL, NS_ERROR_FAILURE); NS_ENSURE_TRUE(mProxyDict != NULL, NS_ERROR_FAILURE);
for (const SchemeMapping* keys = gSchemeMappingList; keys->mScheme != NULL; ++keys) { for (const SchemeMapping* keys = gSchemeMappingList; keys->mScheme != NULL;
++keys) {
// Check for matching scheme (when appropriate) // Check for matching scheme (when appropriate)
if (strcasecmp(keys->mScheme, PromiseFlatCString(aScheme).get()) && !keys->mIsSocksProxy) if (strcasecmp(keys->mScheme, PromiseFlatCString(aScheme).get()) &&
!keys->mIsSocksProxy)
continue; continue;
// Check the proxy is enabled // Check the proxy is enabled
NSNumber* enabled = [mProxyDict objectForKey:(NSString*)keys->mEnabled]; NSNumber* enabled = [mProxyDict objectForKey:(NSString*)keys->mEnabled];
NS_ENSURE_TRUE(enabled == NULL || [enabled isKindOfClass:[NSNumber class]], NS_ERROR_FAILURE); NS_ENSURE_TRUE(enabled == NULL || [enabled isKindOfClass:[NSNumber class]],
NS_ERROR_FAILURE);
if ([enabled intValue] == 0) continue; if ([enabled intValue] == 0) continue;
// Get the proxy host // Get the proxy host
@ -198,17 +209,21 @@ nsresult nsOSXSystemProxySettings::FindSCProxyPort(const nsACString& aScheme,
bool nsOSXSystemProxySettings::IsAutoconfigEnabled() const { bool nsOSXSystemProxySettings::IsAutoconfigEnabled() const {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NSNumber* value = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigEnable]; NSNumber* value = [mProxyDict
NS_ENSURE_TRUE(value == NULL || [value isKindOfClass:[NSNumber class]], false); objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigEnable];
NS_ENSURE_TRUE(value == NULL || [value isKindOfClass:[NSNumber class]],
false);
return ([value intValue] != 0); return ([value intValue] != 0);
NS_OBJC_END_TRY_BLOCK_RETURN(false); NS_OBJC_END_TRY_BLOCK_RETURN(false);
} }
nsresult nsOSXSystemProxySettings::GetAutoconfigURL(nsAutoCString& aResult) const { nsresult nsOSXSystemProxySettings::GetAutoconfigURL(
nsAutoCString& aResult) const {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NSString* value = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigURLString]; NSString* value = [mProxyDict
objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigURLString];
if (value != NULL) { if (value != NULL) {
NS_ENSURE_TRUE([value isKindOfClass:[NSString class]], NS_ERROR_FAILURE); NS_ENSURE_TRUE([value isKindOfClass:[NSString class]], NS_ERROR_FAILURE);
aResult.Assign([value UTF8String]); aResult.Assign([value UTF8String]);
@ -220,20 +235,25 @@ nsresult nsOSXSystemProxySettings::GetAutoconfigURL(nsAutoCString& aResult) cons
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
} }
bool nsOSXSystemProxySettings::IsInExceptionList(const nsACString& aHost) const { bool nsOSXSystemProxySettings::IsInExceptionList(
const nsACString& aHost) const {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NS_ENSURE_TRUE(mProxyDict != NULL, false); NS_ENSURE_TRUE(mProxyDict != NULL, false);
NSArray* exceptionList = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList]; NSArray* exceptionList =
NS_ENSURE_TRUE(exceptionList == NULL || [exceptionList isKindOfClass:[NSArray class]], false); [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList];
NS_ENSURE_TRUE(
exceptionList == NULL || [exceptionList isKindOfClass:[NSArray class]],
false);
NSEnumerator* exceptionEnumerator = [exceptionList objectEnumerator]; NSEnumerator* exceptionEnumerator = [exceptionList objectEnumerator];
NSString* currentValue = NULL; NSString* currentValue = NULL;
while ((currentValue = [exceptionEnumerator nextObject])) { while ((currentValue = [exceptionEnumerator nextObject])) {
NS_ENSURE_TRUE([currentValue isKindOfClass:[NSString class]], false); NS_ENSURE_TRUE([currentValue isKindOfClass:[NSString class]], false);
nsAutoCString overrideStr([currentValue UTF8String]); nsAutoCString overrideStr([currentValue UTF8String]);
if (mozilla::toolkit::system::IsHostProxyEntry(aHost, overrideStr)) return true; if (mozilla::toolkit::system::IsHostProxyEntry(aHost, overrideStr))
return true;
} }
NS_OBJC_END_TRY_BLOCK_RETURN(false); NS_OBJC_END_TRY_BLOCK_RETURN(false);
@ -257,7 +277,8 @@ nsresult nsOSXSystemProxySettings::GetPACURI(nsACString& aResult) {
nsresult nsOSXSystemProxySettings::GetProxyForURI(const nsACString& aSpec, nsresult nsOSXSystemProxySettings::GetProxyForURI(const nsACString& aSpec,
const nsACString& aScheme, const nsACString& aScheme,
const nsACString& aHost, const int32_t aPort, const nsACString& aHost,
const int32_t aPort,
nsACString& aResult) { nsACString& aResult) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
@ -283,7 +304,8 @@ using namespace mozilla::net;
class OSXSystemProxySettingsAsync final : public nsOSXSystemProxySettings { class OSXSystemProxySettingsAsync final : public nsOSXSystemProxySettings {
public: public:
NS_INLINE_DECL_REFCOUNTING_INHERITED(OSXSystemProxySettingsAsync, nsOSXSystemProxySettings) NS_INLINE_DECL_REFCOUNTING_INHERITED(OSXSystemProxySettingsAsync,
nsOSXSystemProxySettings)
NS_DECL_NSISYSTEMPROXYSETTINGS NS_DECL_NSISYSTEMPROXYSETTINGS
OSXSystemProxySettingsAsync(); OSXSystemProxySettingsAsync();
@ -314,7 +336,8 @@ void OSXSystemProxySettingsAsync::OnProxyConfigChangedInternal() {
} }
// proxies (for now: PROXY and SOCKS) // proxies (for now: PROXY and SOCKS)
for (const SchemeMapping* keys = gSchemeMappingList; keys->mScheme != NULL; ++keys) { for (const SchemeMapping* keys = gSchemeMappingList; keys->mScheme != NULL;
++keys) {
// Check the proxy is enabled // Check the proxy is enabled
NSNumber* enabled = [mProxyDict objectForKey:(NSString*)keys->mEnabled]; NSNumber* enabled = [mProxyDict objectForKey:(NSString*)keys->mEnabled];
if (!(enabled == NULL || [enabled isKindOfClass:[NSNumber class]])) { if (!(enabled == NULL || [enabled isKindOfClass:[NSNumber class]])) {
@ -342,17 +365,20 @@ void OSXSystemProxySettingsAsync::OnProxyConfigChangedInternal() {
} }
int32_t resultPort = [port intValue]; int32_t resultPort = [port intValue];
ProxyServer server(ProxyConfig::ToProxyType(keys->mScheme), resultHost, resultPort); ProxyServer server(ProxyConfig::ToProxyType(keys->mScheme), resultHost,
resultPort);
config.Rules().mProxyServers[server.Type()] = std::move(server); config.Rules().mProxyServers[server.Type()] = std::move(server);
} }
// exceptions // exceptions
NSArray* exceptionList = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList]; NSArray* exceptionList =
[mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList];
if (exceptionList != NULL && [exceptionList isKindOfClass:[NSArray class]]) { if (exceptionList != NULL && [exceptionList isKindOfClass:[NSArray class]]) {
NSEnumerator* exceptionEnumerator = [exceptionList objectEnumerator]; NSEnumerator* exceptionEnumerator = [exceptionList objectEnumerator];
NSString* currentValue = NULL; NSString* currentValue = NULL;
while ((currentValue = [exceptionEnumerator nextObject])) { while ((currentValue = [exceptionEnumerator nextObject])) {
if (currentValue != NULL && [currentValue isKindOfClass:[NSString class]]) { if (currentValue != NULL &&
[currentValue isKindOfClass:[NSString class]]) {
nsCString overrideStr([currentValue UTF8String]); nsCString overrideStr([currentValue UTF8String]);
config.ByPassRules().mExceptions.AppendElement(std::move(overrideStr)); config.ByPassRules().mExceptions.AppendElement(std::move(overrideStr));
} }
@ -374,8 +400,10 @@ OSXSystemProxySettingsAsync::GetPACURI(nsACString& aResult) {
} }
NS_IMETHODIMP NS_IMETHODIMP
OSXSystemProxySettingsAsync::GetProxyForURI(const nsACString& aSpec, const nsACString& aScheme, OSXSystemProxySettingsAsync::GetProxyForURI(const nsACString& aSpec,
const nsACString& aHost, const int32_t aPort, const nsACString& aScheme,
const nsACString& aHost,
const int32_t aPort,
nsACString& aResult) { nsACString& aResult) {
for (const auto& bypassRule : mConfig.ByPassRules().mExceptions) { for (const auto& bypassRule : mConfig.ByPassRules().mExceptions) {
if (mozilla::toolkit::system::IsHostProxyEntry(aHost, bypassRule)) { if (mozilla::toolkit::system::IsHostProxyEntry(aHost, bypassRule)) {
@ -389,9 +417,10 @@ OSXSystemProxySettingsAsync::GetProxyForURI(const nsACString& aSpec, const nsACS
} }
NS_IMPL_COMPONENT_FACTORY(nsOSXSystemProxySettings) { NS_IMPL_COMPONENT_FACTORY(nsOSXSystemProxySettings) {
auto settings = mozilla::StaticPrefs::network_proxy_detect_system_proxy_changes() auto settings =
? mozilla::MakeRefPtr<OSXSystemProxySettingsAsync>() mozilla::StaticPrefs::network_proxy_detect_system_proxy_changes()
: mozilla::MakeRefPtr<nsOSXSystemProxySettings>(); ? mozilla::MakeRefPtr<OSXSystemProxySettingsAsync>()
: mozilla::MakeRefPtr<nsOSXSystemProxySettings>();
if (NS_SUCCEEDED(settings->Init())) { if (NS_SUCCEEDED(settings->Init())) {
return settings.forget().downcast<nsISupports>(); return settings.forget().downcast<nsISupports>();
} }

View file

@ -5,8 +5,9 @@
// NSApplication delegate for Mac OS X Cocoa API. // NSApplication delegate for Mac OS X Cocoa API.
// As of 10.4 Tiger, the system can send six kinds of Apple Events to an application; // As of 10.4 Tiger, the system can send six kinds of Apple Events to an
// a well-behaved XUL app should have some kind of handling for all of them. // application; a well-behaved XUL app should have some kind of handling for all
// of them.
// //
// See // See
// http://developer.apple.com/documentation/Cocoa/Conceptual/ScriptableCocoaApplications/SApps_handle_AEs/chapter_11_section_3.html // http://developer.apple.com/documentation/Cocoa/Conceptual/ScriptableCocoaApplications/SApps_handle_AEs/chapter_11_section_3.html
@ -92,7 +93,9 @@ void SetupMacApplicationDelegate(bool* gRestartedByOS) {
// This call makes it so that application:openFile: doesn't get bogus calls // This call makes it so that application:openFile: doesn't get bogus calls
// from Cocoa doing its own parsing of the argument string. And yes, we need // from Cocoa doing its own parsing of the argument string. And yes, we need
// to use a string with a boolean value in it. That's just how it works. // to use a string with a boolean value in it. That's just how it works.
[[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"]; [[NSUserDefaults standardUserDefaults]
setObject:@"NO"
forKey:@"NSTreatUnknownArgumentsAsOpen"];
// Create the delegate. This should be around for the lifetime of the app. // Create the delegate. This should be around for the lifetime of the app.
id<NSApplicationDelegate> delegate = [[MacApplicationDelegate alloc] init]; id<NSApplicationDelegate> delegate = [[MacApplicationDelegate alloc] init];
@ -164,9 +167,11 @@ void ProcessPendingGetURLAppleEvents() {
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
NSAppleEventManager* aeMgr = [NSAppleEventManager sharedAppleEventManager]; NSAppleEventManager* aeMgr = [NSAppleEventManager sharedAppleEventManager];
[aeMgr removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL]; [aeMgr removeEventHandlerForEventClass:kInternetEventClass
andEventID:kAEGetURL];
[aeMgr removeEventHandlerForEventClass:'WWW!' andEventID:'OURL']; [aeMgr removeEventHandlerForEventClass:'WWW!' andEventID:'OURL'];
[aeMgr removeEventHandlerForEventClass:kCoreEventClass andEventID:kAEOpenDocuments]; [aeMgr removeEventHandlerForEventClass:kCoreEventClass
andEventID:kAEOpenDocuments];
[super dealloc]; [super dealloc];
NS_OBJC_END_TRY_IGNORE_BLOCK; NS_OBJC_END_TRY_IGNORE_BLOCK;
@ -175,7 +180,8 @@ void ProcessPendingGetURLAppleEvents() {
// The method that NSApplication calls upon a request to reopen, such as when // The method that NSApplication calls upon a request to reopen, such as when
// the Dock icon is clicked and no windows are open. A "visible" window may be // the Dock icon is clicked and no windows are open. A "visible" window may be
// miniaturized, so we can't skip nsCocoaNativeReOpen() if 'flag' is 'true'. // miniaturized, so we can't skip nsCocoaNativeReOpen() if 'flag' is 'true'.
- (BOOL)applicationShouldHandleReopen:(NSApplication*)theApp hasVisibleWindows:(BOOL)flag { - (BOOL)applicationShouldHandleReopen:(NSApplication*)theApp
hasVisibleWindows:(BOOL)flag {
nsCOMPtr<nsINativeAppSupport> nas = NS_GetNativeAppSupport(); nsCOMPtr<nsINativeAppSupport> nas = NS_GetNativeAppSupport();
NS_ENSURE_TRUE(nas, NO); NS_ENSURE_TRUE(nas, NO);
@ -187,9 +193,10 @@ void ProcessPendingGetURLAppleEvents() {
return NO; return NO;
} }
// The method that NSApplication calls when documents are requested to be opened. // The method that NSApplication calls when documents are requested to be
// It will be called once for each selected document. // opened. It will be called once for each selected document.
- (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename { - (BOOL)application:(NSApplication*)theApplication
openFile:(NSString*)filename {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NSURL* url = [NSURL fileURLWithPath:filename]; NSURL* url = [NSURL fileURLWithPath:filename];
@ -199,10 +206,12 @@ void ProcessPendingGetURLAppleEvents() {
if (!urlString) return NO; if (!urlString) return NO;
// Add the URL to any command line we're currently setting up. // Add the URL to any command line we're currently setting up.
if (CommandLineServiceMac::AddURLToCurrentCommandLine([urlString UTF8String])) return YES; if (CommandLineServiceMac::AddURLToCurrentCommandLine([urlString UTF8String]))
return YES;
nsCOMPtr<nsILocalFileMac> inFile; nsCOMPtr<nsILocalFileMac> inFile;
nsresult rv = NS_NewLocalFileWithCFURL((CFURLRef)url, true, getter_AddRefs(inFile)); nsresult rv =
NS_NewLocalFileWithCFURL((CFURLRef)url, true, getter_AddRefs(inFile));
if (NS_FAILED(rv)) return NO; if (NS_FAILED(rv)) return NO;
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine()); nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
@ -212,14 +221,16 @@ void ProcessPendingGetURLAppleEvents() {
if (NS_FAILED(rv)) return NO; if (NS_FAILED(rv)) return NO;
nsCOMPtr<nsIFile> workingDir; nsCOMPtr<nsIFile> workingDir;
rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir)); rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR,
getter_AddRefs(workingDir));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
// Couldn't find a working dir. Uh oh. Good job cmdline::Init can cope. // Couldn't find a working dir. Uh oh. Good job cmdline::Init can cope.
workingDir = nullptr; workingDir = nullptr;
} }
const char* argv[3] = {nullptr, "-file", filePath.get()}; const char* argv[3] = {nullptr, "-file", filePath.get()};
rv = cmdLine->Init(3, argv, workingDir, nsICommandLine::STATE_REMOTE_EXPLICIT); rv =
cmdLine->Init(3, argv, workingDir, nsICommandLine::STATE_REMOTE_EXPLICIT);
if (NS_FAILED(rv)) return NO; if (NS_FAILED(rv)) return NO;
if (NS_SUCCEEDED(cmdLine->Run())) return YES; if (NS_SUCCEEDED(cmdLine->Run())) return YES;
@ -229,10 +240,11 @@ void ProcessPendingGetURLAppleEvents() {
NS_OBJC_END_TRY_BLOCK_RETURN(NO); NS_OBJC_END_TRY_BLOCK_RETURN(NO);
} }
// The method that NSApplication calls when documents are requested to be printed // The method that NSApplication calls when documents are requested to be
// from the Finder (under the "File" menu). // printed from the Finder (under the "File" menu). It will be called once for
// It will be called once for each selected document. // each selected document.
- (BOOL)application:(NSApplication*)theApplication printFile:(NSString*)filename { - (BOOL)application:(NSApplication*)theApplication
printFile:(NSString*)filename {
return NO; return NO;
} }
@ -256,7 +268,8 @@ void ProcessPendingGetURLAppleEvents() {
if (NS_FAILED(rv) || !dockMenuInterface) return menu; if (NS_FAILED(rv) || !dockMenuInterface) return menu;
RefPtr<mozilla::widget::NativeMenuMac> dockMenu = RefPtr<mozilla::widget::NativeMenuMac> dockMenu =
static_cast<nsStandaloneNativeMenu*>(dockMenuInterface.get())->GetNativeMenu(); static_cast<nsStandaloneNativeMenu*>(dockMenuInterface.get())
->GetNativeMenu();
// Give the menu the opportunity to update itself before display. // Give the menu the opportunity to update itself before display.
dockMenu->MenuWillOpen(); dockMenu->MenuWillOpen();
@ -288,16 +301,21 @@ void ProcessPendingGetURLAppleEvents() {
- (void)applicationWillFinishLaunching:(NSNotification*)notification { - (void)applicationWillFinishLaunching:(NSNotification*)notification {
// We provide our own full screen menu item, so we don't want the OS providing // We provide our own full screen menu item, so we don't want the OS providing
// one as well. // one as well.
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"]; [[NSUserDefaults standardUserDefaults]
setBool:NO
forKey:@"NSFullScreenMenuItemEverywhere"];
} }
// If we don't handle applicationShouldTerminate:, a call to [NSApp terminate:] // If we don't handle applicationShouldTerminate:, a call to [NSApp terminate:]
// (from the browser or from the OS) can result in an unclean shutdown. // (from the browser or from the OS) can result in an unclean shutdown.
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender { - (NSApplicationTerminateReply)applicationShouldTerminate:
nsCOMPtr<nsIObserverService> obsServ = do_GetService("@mozilla.org/observer-service;1"); (NSApplication*)sender {
nsCOMPtr<nsIObserverService> obsServ =
do_GetService("@mozilla.org/observer-service;1");
if (!obsServ) return NSTerminateNow; if (!obsServ) return NSTerminateNow;
nsCOMPtr<nsISupportsPRBool> cancelQuit = do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID); nsCOMPtr<nsISupportsPRBool> cancelQuit =
do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
if (!cancelQuit) return NSTerminateNow; if (!cancelQuit) return NSTerminateNow;
cancelQuit->SetData(false); cancelQuit->SetData(false);
@ -307,7 +325,8 @@ void ProcessPendingGetURLAppleEvents() {
cancelQuit->GetData(&abortQuit); cancelQuit->GetData(&abortQuit);
if (abortQuit) return NSTerminateCancel; if (abortQuit) return NSTerminateCancel;
nsCOMPtr<nsIAppStartup> appService = do_GetService("@mozilla.org/toolkit/app-startup;1"); nsCOMPtr<nsIAppStartup> appService =
do_GetService("@mozilla.org/toolkit/app-startup;1");
if (appService) { if (appService) {
bool userAllowedQuit = true; bool userAllowedQuit = true;
appService->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit); appService->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit);
@ -325,22 +344,28 @@ void ProcessPendingGetURLAppleEvents() {
AutoAutoreleasePool pool; AutoAutoreleasePool pool;
bool isGetURLEvent = ([event eventClass] == kInternetEventClass && [event eventID] == kAEGetURL); bool isGetURLEvent = ([event eventClass] == kInternetEventClass &&
[event eventID] == kAEGetURL);
if (isGetURLEvent) sProcessedGetURLEvent = true; if (isGetURLEvent) sProcessedGetURLEvent = true;
if (isGetURLEvent || ([event eventClass] == 'WWW!' && [event eventID] == 'OURL')) { if (isGetURLEvent ||
NSString* urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; ([event eventClass] == 'WWW!' && [event eventID] == 'OURL')) {
NSString* urlString =
[[event paramDescriptorForKeyword:keyDirectObject] stringValue];
NSURL* url = [NSURL URLWithString:urlString]; NSURL* url = [NSURL URLWithString:urlString];
[self openURL:url]; [self openURL:url];
} else if ([event eventClass] == kCoreEventClass && [event eventID] == kAEOpenDocuments) { } else if ([event eventClass] == kCoreEventClass &&
NSAppleEventDescriptor* fileListDescriptor = [event paramDescriptorForKeyword:keyDirectObject]; [event eventID] == kAEOpenDocuments) {
NSAppleEventDescriptor* fileListDescriptor =
[event paramDescriptorForKeyword:keyDirectObject];
if (!fileListDescriptor) return; if (!fileListDescriptor) return;
// Descriptor list indexing is one-based... // Descriptor list indexing is one-based...
NSInteger numberOfFiles = [fileListDescriptor numberOfItems]; NSInteger numberOfFiles = [fileListDescriptor numberOfItems];
for (NSInteger i = 1; i <= numberOfFiles; i++) { for (NSInteger i = 1; i <= numberOfFiles; i++) {
NSString* urlString = [[fileListDescriptor descriptorAtIndex:i] stringValue]; NSString* urlString =
[[fileListDescriptor descriptorAtIndex:i] stringValue];
if (!urlString) continue; if (!urlString) continue;
// We need a path, not a URL // We need a path, not a URL
@ -359,12 +384,15 @@ void ProcessPendingGetURLAppleEvents() {
- (BOOL)application:(NSApplication*)application - (BOOL)application:(NSApplication*)application
continueUserActivity:(NSUserActivity*)userActivity continueUserActivity:(NSUserActivity*)userActivity
#if defined(MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 #if defined(MAC_OS_X_VERSION_10_14) && \
restorationHandler:(void (^)(NSArray<id<NSUserActivityRestoring>>*))restorationHandler { MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
restorationHandler:
(void (^)(NSArray<id<NSUserActivityRestoring>>*))restorationHandler {
#else #else
restorationHandler:(void (^)(NSArray*))restorationHandler { restorationHandler:(void (^)(NSArray*))restorationHandler {
#endif #endif
if (![userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { if (![userActivity.activityType
isEqualToString:NSUserActivityTypeBrowsingWeb]) {
return NO; return NO;
} }
@ -378,7 +406,8 @@ void ProcessPendingGetURLAppleEvents() {
} }
- (BOOL)openURL:(NSURL*)url { - (BOOL)openURL:(NSURL*)url {
if (!url || !url.scheme || [url.scheme caseInsensitiveCompare:@"chrome"] == NSOrderedSame) { if (!url || !url.scheme ||
[url.scheme caseInsensitiveCompare:@"chrome"] == NSOrderedSame) {
return NO; return NO;
} }
@ -390,14 +419,16 @@ void ProcessPendingGetURLAppleEvents() {
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine()); nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
nsCOMPtr<nsIFile> workingDir; nsCOMPtr<nsIFile> workingDir;
nsresult rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir)); nsresult rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR,
getter_AddRefs(workingDir));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
// Couldn't find a working dir. Uh oh. Good job cmdline::Init can cope. // Couldn't find a working dir. Uh oh. Good job cmdline::Init can cope.
workingDir = nullptr; workingDir = nullptr;
} }
const char* argv[3] = {nullptr, "-url", urlString}; const char* argv[3] = {nullptr, "-url", urlString};
rv = cmdLine->Init(3, argv, workingDir, nsICommandLine::STATE_REMOTE_EXPLICIT); rv =
cmdLine->Init(3, argv, workingDir, nsICommandLine::STATE_REMOTE_EXPLICIT);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return NO; return NO;
} }

View file

@ -26,7 +26,8 @@ void LaunchChildMac(int aArgc, char** aArgv, pid_t* aPid) {
for (int i = 1; i < aArgc; i++) { for (int i = 1; i < aArgc; i++) {
[arguments addObject:[NSString stringWithUTF8String:aArgv[i]]]; [arguments addObject:[NSString stringWithUTF8String:aArgv[i]]];
} }
NSTask* child = [NSTask launchedTaskWithLaunchPath:launchPath arguments:arguments]; NSTask* child = [NSTask launchedTaskWithLaunchPath:launchPath
arguments:arguments];
if (aPid) { if (aPid) {
*aPid = [child processIdentifier]; *aPid = [child processIdentifier];
// We used to use waitpid to wait for the process to terminate. This is // We used to use waitpid to wait for the process to terminate. This is
@ -43,31 +44,36 @@ bool InstallPrivilegedHelper() {
AuthorizationRef authRef = NULL; AuthorizationRef authRef = NULL;
OSStatus status = AuthorizationCreate( OSStatus status = AuthorizationCreate(
NULL, kAuthorizationEmptyEnvironment, NULL, kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed, &authRef); kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed,
&authRef);
if (status != errAuthorizationSuccess) { if (status != errAuthorizationSuccess) {
// AuthorizationCreate really shouldn't fail. // AuthorizationCreate really shouldn't fail.
NSLog(@"AuthorizationCreate failed! NSOSStatusErrorDomain / %d", (int)status); NSLog(@"AuthorizationCreate failed! NSOSStatusErrorDomain / %d",
(int)status);
return NO; return NO;
} }
BOOL result = NO; BOOL result = NO;
AuthorizationItem authItem = {kSMRightBlessPrivilegedHelper, 0, NULL, 0}; AuthorizationItem authItem = {kSMRightBlessPrivilegedHelper, 0, NULL, 0};
AuthorizationRights authRights = {1, &authItem}; AuthorizationRights authRights = {1, &authItem};
AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | AuthorizationFlags flags =
kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
// Obtain the right to install our privileged helper tool. // Obtain the right to install our privileged helper tool.
status = status = AuthorizationCopyRights(authRef, &authRights,
AuthorizationCopyRights(authRef, &authRights, kAuthorizationEmptyEnvironment, flags, NULL); kAuthorizationEmptyEnvironment, flags, NULL);
if (status != errAuthorizationSuccess) { if (status != errAuthorizationSuccess) {
NSLog(@"AuthorizationCopyRights failed! NSOSStatusErrorDomain / %d", (int)status); NSLog(@"AuthorizationCopyRights failed! NSOSStatusErrorDomain / %d",
(int)status);
} else { } else {
CFErrorRef cfError; CFErrorRef cfError;
// This does all the work of verifying the helper tool against the // This does all the work of verifying the helper tool against the
// application and vice-versa. Once verification has passed, the embedded // application and vice-versa. Once verification has passed, the embedded
// launchd.plist is extracted and placed in /Library/LaunchDaemons and then // launchd.plist is extracted and placed in /Library/LaunchDaemons and then
// loaded. The executable is placed in /Library/PrivilegedHelperTools. // loaded. The executable is placed in /Library/PrivilegedHelperTools.
result = (BOOL)SMJobBless(kSMDomainSystemLaunchd, (CFStringRef) @"org.mozilla.updater", authRef, result = (BOOL)SMJobBless(kSMDomainSystemLaunchd,
(CFStringRef) @"org.mozilla.updater", authRef,
&cfError); &cfError);
if (!result) { if (!result) {
NSLog(@"Unable to install helper!"); NSLog(@"Unable to install helper!");
@ -90,7 +96,8 @@ void AbortElevatedUpdate() {
updateServer = (id)[NSConnection updateServer = (id)[NSConnection
rootProxyForConnectionWithRegisteredName:@"org.mozilla.updater.server" rootProxyForConnectionWithRegisteredName:@"org.mozilla.updater.server"
host:nil host:nil
usingNameServer:[NSSocketPortNameServer sharedInstance]]; usingNameServer:[NSSocketPortNameServer
sharedInstance]];
if (updateServer && [updateServer respondsToSelector:@selector(abort)]) { if (updateServer && [updateServer respondsToSelector:@selector(abort)]) {
[updateServer performSelector:@selector(abort)]; [updateServer performSelector:@selector(abort)];
return; return;

View file

@ -59,30 +59,37 @@ static bool AskUserIfWeShouldLaunchExistingInstall() {
ErrorResult rv; ErrorResult rv;
nsAutoCString mozTitle, mozMessage, mozLaunchExisting, mozLaunchFromDMG; nsAutoCString mozTitle, mozMessage, mozLaunchExisting, mozLaunchFromDMG;
l10n->FormatValueSync("prompt-to-launch-existing-app-title"_ns, {}, mozTitle, rv); l10n->FormatValueSync("prompt-to-launch-existing-app-title"_ns, {}, mozTitle,
rv);
if (rv.Failed()) { if (rv.Failed()) {
return false; return false;
} }
l10n->FormatValueSync("prompt-to-launch-existing-app-message"_ns, {}, mozMessage, rv); l10n->FormatValueSync("prompt-to-launch-existing-app-message"_ns, {},
mozMessage, rv);
if (rv.Failed()) { if (rv.Failed()) {
return false; return false;
} }
l10n->FormatValueSync("prompt-to-launch-existing-app-yes-button"_ns, {}, mozLaunchExisting, rv); l10n->FormatValueSync("prompt-to-launch-existing-app-yes-button"_ns, {},
mozLaunchExisting, rv);
if (rv.Failed()) { if (rv.Failed()) {
return false; return false;
} }
l10n->FormatValueSync("prompt-to-launch-existing-app-no-button"_ns, {}, mozLaunchFromDMG, rv); l10n->FormatValueSync("prompt-to-launch-existing-app-no-button"_ns, {},
mozLaunchFromDMG, rv);
if (rv.Failed()) { if (rv.Failed()) {
return false; return false;
} }
NSString* title = [NSString stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())]; NSString* title = [NSString
NSString* message = stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())]; NSString* message = [NSString
stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
NSString* launchExisting = NSString* launchExisting =
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozLaunchExisting.get())]; [NSString stringWithUTF8String:reinterpret_cast<const char*>(
mozLaunchExisting.get())];
NSString* launchFromDMG = NSString* launchFromDMG =
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozLaunchFromDMG.get())]; [NSString stringWithUTF8String:reinterpret_cast<const char*>(
mozLaunchFromDMG.get())];
NSAlert* alert = [[[NSAlert alloc] init] autorelease]; NSAlert* alert = [[[NSAlert alloc] init] autorelease];
@ -144,18 +151,20 @@ static bool AskUserIfWeShouldInstall() {
if (rv.Failed()) { if (rv.Failed()) {
return false; return false;
} }
l10n->FormatValueSync("prompt-to-install-no-button"_ns, {}, mozDontInstall, rv); l10n->FormatValueSync("prompt-to-install-no-button"_ns, {}, mozDontInstall,
rv);
if (rv.Failed()) { if (rv.Failed()) {
return false; return false;
} }
NSString* title = [NSString stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())]; NSString* title = [NSString
NSString* message = stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())]; NSString* message = [NSString
NSString* install = stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozInstall.get())]; NSString* install = [NSString
NSString* dontInstall = stringWithUTF8String:reinterpret_cast<const char*>(mozInstall.get())];
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozDontInstall.get())]; NSString* dontInstall = [NSString
stringWithUTF8String:reinterpret_cast<const char*>(mozDontInstall.get())];
NSAlert* alert = [[[NSAlert alloc] init] autorelease]; NSAlert* alert = [[[NSAlert alloc] init] autorelease];
@ -179,15 +188,15 @@ static bool AskUserIfWeShouldInstall() {
// AskUserIfWeShouldInstall // AskUserIfWeShouldInstall
// | // |
// | ---> [NSApp run] // | ---> [NSApp run]
// | | // | |
// | | -----> task // | | ---> task
// | | | -----------> [alert runModal] // | | | ----> [alert runModal]
// | | | | (User selects button) // | | | | (User selects button)
// | | | <--------------- done // | | | <--------- done
// | | | // | | |
// | | | -----------> [NSApp stop:nil] // | | | -----> [NSApp stop:nil]
// | | | <----------- // | | | <-----
// | | <-------- // | | <-----
// | <------- // | <-------
// done // done
__block NSInteger result = -1; __block NSInteger result = -1;
@ -225,9 +234,10 @@ static void ShowInstallFailedDialog() {
return; return;
} }
NSString* title = [NSString stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())]; NSString* title = [NSString
NSString* message = stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())]; NSString* message = [NSString
stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
NSAlert* alert = [[[NSAlert alloc] init] autorelease]; NSAlert* alert = [[[NSAlert alloc] init] autorelease];
@ -322,8 +332,9 @@ static bool InstallFromPath(NSString* aBundlePath, NSString* aDestPath) {
NSString* destDir = [aDestPath stringByDeletingLastPathComponent]; NSString* destDir = [aDestPath stringByDeletingLastPathComponent];
if (!installSuccessful && ![fileManager isWritableFileAtPath:destDir]) { if (!installSuccessful && ![fileManager isWritableFileAtPath:destDir]) {
NSString* updaterBinPath = [NSString pathWithComponents:@[ NSString* updaterBinPath = [NSString pathWithComponents:@[
aBundlePath, @"Contents", @"MacOS", [NSString stringWithUTF8String:UPDATER_APP], @"Contents", aBundlePath, @"Contents", @"MacOS",
@"MacOS", [NSString stringWithUTF8String:UPDATER_BIN] [NSString stringWithUTF8String:UPDATER_APP], @"Contents", @"MacOS",
[NSString stringWithUTF8String:UPDATER_BIN]
]]; ]];
NSArray* arguments = @[ @"-dmgInstall", aBundlePath, aDestPath ]; NSArray* arguments = @[ @"-dmgInstall", aBundlePath, aDestPath ];
@ -354,7 +365,8 @@ static bool InstallFromPath(NSString* aBundlePath, NSString* aDestPath) {
bool IsAppRunningFromDmg() { bool IsAppRunningFromDmg() {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
const char* path = [[[NSBundle mainBundle] bundlePath] fileSystemRepresentation]; const char* path =
[[[NSBundle mainBundle] bundlePath] fileSystemRepresentation];
struct statfs statfsBuf; struct statfs statfsBuf;
if (statfs(path, &statfsBuf) != 0) { if (statfs(path, &statfsBuf) != 0) {
@ -388,11 +400,13 @@ bool IsAppRunningFromDmg() {
// Get the IOMedia object: // Get the IOMedia object:
// (Note: IOServiceGetMatchingServices takes ownership of serviceDict's ref.) // (Note: IOServiceGetMatchingServices takes ownership of serviceDict's ref.)
CFMutableDictionaryRef serviceDict = IOBSDNameMatching(kIOMasterPortDefault, 0, bsdDeviceName); CFMutableDictionaryRef serviceDict =
IOBSDNameMatching(kIOMasterPortDefault, 0, bsdDeviceName);
if (!serviceDict) { if (!serviceDict) {
return false; return false;
} }
io_service_t media = IOServiceGetMatchingService(kIOMasterPortDefault, serviceDict); io_service_t media =
IOServiceGetMatchingService(kIOMasterPortDefault, serviceDict);
if (!media || !IOObjectConformsTo(media, "IOMedia")) { if (!media || !IOObjectConformsTo(media, "IOMedia")) {
return false; return false;
} }
@ -401,14 +415,16 @@ bool IsAppRunningFromDmg() {
// (taking care to start with `media` itself): // (taking care to start with `media` itself):
io_service_t imageDrive = IO_OBJECT_NULL; io_service_t imageDrive = IO_OBJECT_NULL;
io_iterator_t iter; io_iterator_t iter;
if (IORegistryEntryCreateIterator(media, kIOServicePlane, if (IORegistryEntryCreateIterator(
kIORegistryIterateRecursively | kIORegistryIterateParents, media, kIOServicePlane,
&iter) != KERN_SUCCESS) { kIORegistryIterateRecursively | kIORegistryIterateParents,
&iter) != KERN_SUCCESS) {
IOObjectRelease(media); IOObjectRelease(media);
return false; return false;
} }
const char* imageClass = const char* imageClass = nsCocoaFeatures::OnMontereyOrLater()
nsCocoaFeatures::OnMontereyOrLater() ? "AppleDiskImageDevice" : "IOHDIXHDDrive"; ? "AppleDiskImageDevice"
: "IOHDIXHDDrive";
for (imageDrive = media; imageDrive; imageDrive = IOIteratorNext(iter)) { for (imageDrive = media; imageDrive; imageDrive = IOIteratorNext(iter)) {
if (IOObjectConformsTo(imageDrive, imageClass)) { if (IOObjectConformsTo(imageDrive, imageClass)) {
break; break;
@ -446,20 +462,22 @@ bool MaybeInstallAndRelaunch() {
// The Applications directory may not be at /Applications, although in // The Applications directory may not be at /Applications, although in
// practice we're unlikely to encounter since run-from-.dmg is really an // practice we're unlikely to encounter since run-from-.dmg is really an
// issue with novice mac users. Still, look it up correctly: // issue with novice mac users. Still, look it up correctly:
NSArray* applicationsDirs = NSArray* applicationsDirs = NSSearchPathForDirectoriesInDomains(
NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSLocalDomainMask, YES); NSApplicationDirectory, NSLocalDomainMask, YES);
NSString* applicationsDir = applicationsDirs[0]; NSString* applicationsDir = applicationsDirs[0];
// Sanity check dir exists // Sanity check dir exists
NSFileManager* fileManager = [NSFileManager defaultManager]; NSFileManager* fileManager = [NSFileManager defaultManager];
BOOL isDir; BOOL isDir;
if (![fileManager fileExistsAtPath:applicationsDir isDirectory:&isDir] || !isDir) { if (![fileManager fileExistsAtPath:applicationsDir isDirectory:&isDir] ||
!isDir) {
return false; return false;
} }
NSString* bundlePath = [[NSBundle mainBundle] bundlePath]; NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
NSString* appName = [bundlePath lastPathComponent]; NSString* appName = [bundlePath lastPathComponent];
NSString* destPath = [applicationsDir stringByAppendingPathComponent:appName]; NSString* destPath =
[applicationsDir stringByAppendingPathComponent:appName];
// If the app (an app of the same name) is already installed we can't really // If the app (an app of the same name) is already installed we can't really
// tell without asking if we're dealing with the edge case of an // tell without asking if we're dealing with the edge case of an

View file

@ -8,8 +8,10 @@
#include "UIKitDirProvider.h" #include "UIKitDirProvider.h"
bool GetUIKitDirectory(bool aLocal, nsACString& aUserDir) { bool GetUIKitDirectory(bool aLocal, nsACString& aUserDir) {
NSSearchPathDirectory directory = aLocal ? NSCachesDirectory : NSApplicationSupportDirectory; NSSearchPathDirectory directory =
NSArray* paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES); aLocal ? NSCachesDirectory : NSApplicationSupportDirectory;
NSArray* paths =
NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
if ([paths count] == 0) { if ([paths count] == 0) {
return false; return false;
} }

View file

@ -21,8 +21,8 @@ static bool sBuildingCommandLine = false;
void AddToCommandLine(const char* inArgText) { void AddToCommandLine(const char* inArgText) {
if (sArgsUsed >= sArgsAllocated - 1) { if (sArgsUsed >= sArgsAllocated - 1) {
// realloc does not free the given pointer if allocation fails // realloc does not free the given pointer if allocation fails
char** temp = char** temp = static_cast<char**>(
static_cast<char**>(realloc(sArgs, (sArgsAllocated + kArgsGrowSize) * sizeof(char*))); realloc(sArgs, (sArgsAllocated + kArgsGrowSize) * sizeof(char*)));
if (!temp) return; if (!temp) return;
sArgs = temp; sArgs = temp;
sArgsAllocated += kArgsGrowSize; sArgsAllocated += kArgsGrowSize;
@ -67,7 +67,8 @@ void SetupMacCommandLine(int& argc, char**& argv, bool forRestart) {
// if the parent is in the foreground. This will be communicated in a // if the parent is in the foreground. This will be communicated in a
// command-line argument to the child. // command-line argument to the child.
if (forRestart) { if (forRestart) {
NSRunningApplication* frontApp = [[NSWorkspace sharedWorkspace] frontmostApplication]; NSRunningApplication* frontApp =
[[NSWorkspace sharedWorkspace] frontmostApplication];
if ([frontApp isEqual:[NSRunningApplication currentApplication]]) { if ([frontApp isEqual:[NSRunningApplication currentApplication]]) {
AddToCommandLine("-foreground"); AddToCommandLine("-foreground");
} }

View file

@ -119,7 +119,8 @@ nsNativeAppSupportCocoa::ReOpen() {
windowList->HasMoreElements(&more); windowList->HasMoreElements(&more);
continue; continue;
} }
NSWindow* cocoaWindow = (NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW); NSWindow* cocoaWindow =
(NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
if (![cocoaWindow isMiniaturized]) { if (![cocoaWindow isMiniaturized]) {
haveNonMiniaturized = true; haveNonMiniaturized = true;
break; // have un-minimized windows, nothing to do break; // have un-minimized windows, nothing to do
@ -154,7 +155,8 @@ nsNativeAppSupportCocoa::ReOpen() {
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine()); nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
nsresult rv; nsresult rv;
rv = cmdLine->Init(0, argv, nullptr, nsICommandLine::STATE_REMOTE_EXPLICIT); rv = cmdLine->Init(0, argv, nullptr,
nsICommandLine::STATE_REMOTE_EXPLICIT);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return cmdLine->Run(); return cmdLine->Run();

View file

@ -13,8 +13,10 @@ bool IsRecursivelyWritable(const char* aPath) {
NSString* rootPath = [NSString stringWithUTF8String:aPath]; NSString* rootPath = [NSString stringWithUTF8String:aPath];
NSFileManager* fileManager = [NSFileManager defaultManager]; NSFileManager* fileManager = [NSFileManager defaultManager];
NSError* error = nil; NSError* error = nil;
NSArray* subPaths = [fileManager subpathsOfDirectoryAtPath:rootPath error:&error]; NSArray* subPaths = [fileManager subpathsOfDirectoryAtPath:rootPath
NSMutableArray* paths = [NSMutableArray arrayWithCapacity:[subPaths count] + 1]; error:&error];
NSMutableArray* paths =
[NSMutableArray arrayWithCapacity:[subPaths count] + 1];
[paths addObject:@""]; [paths addObject:@""];
[paths addObjectsFromArray:subPaths]; [paths addObjectsFromArray:subPaths];
@ -26,7 +28,8 @@ bool IsRecursivelyWritable(const char* aPath) {
for (NSString* currPath in paths) { for (NSString* currPath in paths) {
NSString* child = [rootPath stringByAppendingPathComponent:currPath]; NSString* child = [rootPath stringByAppendingPathComponent:currPath];
NSDictionary* attributes = [fileManager attributesOfItemAtPath:child error:&error]; NSDictionary* attributes = [fileManager attributesOfItemAtPath:child
error:&error];
if (error) { if (error) {
[pool drain]; [pool drain];
return false; return false;

View file

@ -10,7 +10,8 @@
#include "nsILocalFileMac.h" #include "nsILocalFileMac.h"
#include "nsIURI.h" #include "nsIURI.h"
// We override this to make sure app bundles display their pretty name (without .app suffix) // We override this to make sure app bundles display their pretty name (without
// .app suffix)
NS_IMETHODIMP nsLocalHandlerAppMac::GetName(nsAString& aName) { NS_IMETHODIMP nsLocalHandlerAppMac::GetName(nsAString& aName) {
if (mExecutable) { if (mExecutable) {
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(mExecutable); nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(mExecutable);
@ -30,7 +31,8 @@ NS_IMETHODIMP nsLocalHandlerAppMac::GetName(nsAString& aName) {
* somewhere more central (see bug 389922). * somewhere more central (see bug 389922).
*/ */
NS_IMETHODIMP NS_IMETHODIMP
nsLocalHandlerAppMac::LaunchWithURI(nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) { nsLocalHandlerAppMac::LaunchWithURI(
nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
nsresult rv; nsresult rv;
@ -45,14 +47,15 @@ nsLocalHandlerAppMac::LaunchWithURI(nsIURI* aURI, mozilla::dom::BrowsingContext*
aURI->GetAsciiSpec(uriSpec); aURI->GetAsciiSpec(uriSpec);
const UInt8* uriString = reinterpret_cast<const UInt8*>(uriSpec.get()); const UInt8* uriString = reinterpret_cast<const UInt8*>(uriSpec.get());
CFURLRef uri = CFURLRef uri = ::CFURLCreateWithBytes(NULL, uriString, uriSpec.Length(),
::CFURLCreateWithBytes(NULL, uriString, uriSpec.Length(), kCFStringEncodingUTF8, NULL); kCFStringEncodingUTF8, NULL);
if (!uri) { if (!uri) {
::CFRelease(appURL); ::CFRelease(appURL);
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
CFArrayRef uris = ::CFArrayCreate(NULL, reinterpret_cast<const void**>(&uri), 1, NULL); CFArrayRef uris =
::CFArrayCreate(NULL, reinterpret_cast<const void**>(&uri), 1, NULL);
if (!uris) { if (!uris) {
::CFRelease(uri); ::CFRelease(uri);
::CFRelease(appURL); ::CFRelease(appURL);

View file

@ -11,8 +11,10 @@
#include "nsMIMEInfoMac.h" #include "nsMIMEInfoMac.h"
#include "nsILocalFileMac.h" #include "nsILocalFileMac.h"
// We override this to make sure app bundles display their pretty name (without .app suffix) // We override this to make sure app bundles display their pretty name (without
NS_IMETHODIMP nsMIMEInfoMac::GetDefaultDescription(nsAString& aDefaultDescription) { // .app suffix)
NS_IMETHODIMP nsMIMEInfoMac::GetDefaultDescription(
nsAString& aDefaultDescription) {
nsCOMPtr<nsIFile> defaultApp = GetDefaultApplication(); nsCOMPtr<nsIFile> defaultApp = GetDefaultApplication();
if (defaultApp) { if (defaultApp) {
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(defaultApp); nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(defaultApp);
@ -43,7 +45,8 @@ nsMIMEInfoMac::LaunchWithFile(nsIFile* aFile) {
if (mPreferredAction == useHelperApp) { if (mPreferredAction == useHelperApp) {
// we don't yet support passing content by value (rather than reference) // we don't yet support passing content by value (rather than reference)
// to web apps. at some point, we will probably want to. // to web apps. at some point, we will probably want to.
nsCOMPtr<nsILocalHandlerApp> localHandlerApp = do_QueryInterface(mPreferredApplication, &rv); nsCOMPtr<nsILocalHandlerApp> localHandlerApp =
do_QueryInterface(mPreferredApplication, &rv);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
rv = localHandlerApp->GetExecutable(getter_AddRefs(application)); rv = localHandlerApp->GetExecutable(getter_AddRefs(application));
@ -68,7 +71,8 @@ nsMIMEInfoMac::LaunchWithFile(nsIFile* aFile) {
tempFile->GetFSRef(&tempFileRef); tempFile->GetFSRef(&tempFileRef);
FSRef appFSRef; FSRef appFSRef;
if (::LSGetApplicationForItem(&tempFileRef, kLSRolesAll, &appFSRef, nullptr) == noErr) { if (::LSGetApplicationForItem(&tempFileRef, kLSRolesAll, &appFSRef,
nullptr) == noErr) {
app = (do_CreateInstance("@mozilla.org/file/local;1")); app = (do_CreateInstance("@mozilla.org/file/local;1"));
if (!app) return NS_ERROR_FAILURE; if (!app) return NS_ERROR_FAILURE;
app->InitWithFSRef(&appFSRef); app->InitWithFSRef(&appFSRef);
@ -91,8 +95,9 @@ nsresult nsMIMEInfoMac::LoadUriInternal(nsIURI* aURI) {
nsAutoCString uri; nsAutoCString uri;
aURI->GetSpec(uri); aURI->GetSpec(uri);
if (!uri.IsEmpty()) { if (!uri.IsEmpty()) {
CFURLRef myURLRef = ::CFURLCreateWithBytes(kCFAllocatorDefault, (const UInt8*)uri.get(), CFURLRef myURLRef =
strlen(uri.get()), kCFStringEncodingUTF8, NULL); ::CFURLCreateWithBytes(kCFAllocatorDefault, (const UInt8*)uri.get(),
strlen(uri.get()), kCFStringEncodingUTF8, NULL);
if (myURLRef) { if (myURLRef) {
OSStatus status = ::LSOpenCFURLRef(myURLRef, NULL); OSStatus status = ::LSOpenCFURLRef(myURLRef, NULL);
if (status == noErr) rv = NS_OK; if (status == noErr) rv = NS_OK;

View file

@ -25,7 +25,8 @@
#import <ApplicationServices/ApplicationServices.h> #import <ApplicationServices/ApplicationServices.h>
// chrome URL's // chrome URL's
#define HELPERAPPLAUNCHER_BUNDLE_URL "chrome://global/locale/helperAppLauncher.properties" #define HELPERAPPLAUNCHER_BUNDLE_URL \
"chrome://global/locale/helperAppLauncher.properties"
#define BRAND_BUNDLE_URL "chrome://branding/locale/brand.properties" #define BRAND_BUNDLE_URL "chrome://branding/locale/brand.properties"
nsresult GetDefaultBundleURL(const nsACString& aScheme, CFURLRef* aBundleURL) { nsresult GetDefaultBundleURL(const nsACString& aScheme, CFURLRef* aBundleURL) {
@ -34,18 +35,20 @@ nsresult GetDefaultBundleURL(const nsACString& aScheme, CFURLRef* aBundleURL) {
nsresult rv = NS_ERROR_NOT_AVAILABLE; nsresult rv = NS_ERROR_NOT_AVAILABLE;
CFStringRef schemeCFString = ::CFStringCreateWithBytes( CFStringRef schemeCFString = ::CFStringCreateWithBytes(
kCFAllocatorDefault, (const UInt8*)PromiseFlatCString(aScheme).get(), aScheme.Length(), kCFAllocatorDefault, (const UInt8*)PromiseFlatCString(aScheme).get(),
kCFStringEncodingUTF8, false); aScheme.Length(), kCFStringEncodingUTF8, false);
if (schemeCFString) { if (schemeCFString) {
CFStringRef lookupCFString = CFStringRef lookupCFString =
::CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:"), schemeCFString); ::CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:"), schemeCFString);
if (lookupCFString) { if (lookupCFString) {
CFURLRef lookupCFURL = ::CFURLCreateWithString(NULL, lookupCFString, NULL); CFURLRef lookupCFURL =
::CFURLCreateWithString(NULL, lookupCFString, NULL);
if (lookupCFURL) { if (lookupCFURL) {
*aBundleURL = ::LSCopyDefaultApplicationURLForURL(lookupCFURL, kLSRolesAll, NULL); *aBundleURL =
::LSCopyDefaultApplicationURLForURL(lookupCFURL, kLSRolesAll, NULL);
if (*aBundleURL) { if (*aBundleURL) {
rv = NS_OK; rv = NS_OK;
} }
@ -88,15 +91,15 @@ using mozilla::LogLevel;
nsOSHelperAppService::~nsOSHelperAppService() {} nsOSHelperAppService::~nsOSHelperAppService() {}
nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char* aProtocolScheme, nsresult nsOSHelperAppService::OSProtocolHandlerExists(
bool* aHandlerExists) { const char* aProtocolScheme, bool* aHandlerExists) {
// CFStringCreateWithBytes() can fail even if we're not out of memory -- // CFStringCreateWithBytes() can fail even if we're not out of memory --
// for example if the 'bytes' parameter is something very weird (like // for example if the 'bytes' parameter is something very weird (like
// "\xFF\xFF~"), or possibly if it can't be interpreted as using what's // "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
// specified in the 'encoding' parameter. See bug 548719. // specified in the 'encoding' parameter. See bug 548719.
CFStringRef schemeString = CFStringRef schemeString = ::CFStringCreateWithBytes(
::CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8*)aProtocolScheme, kCFAllocatorDefault, (const UInt8*)aProtocolScheme,
strlen(aProtocolScheme), kCFStringEncodingUTF8, false); strlen(aProtocolScheme), kCFStringEncodingUTF8, false);
if (schemeString) { if (schemeString) {
// LSCopyDefaultHandlerForURLScheme() can fail to find the default handler // LSCopyDefaultHandlerForURLScheme() can fail to find the default handler
// for aProtocolScheme when it's never been explicitly set (using // for aProtocolScheme when it's never been explicitly set (using
@ -118,8 +121,8 @@ nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char* aProtocolSche
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(
nsAString& _retval) { const nsACString& aScheme, nsAString& _retval) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
nsresult rv = NS_ERROR_NOT_AVAILABLE; nsresult rv = NS_ERROR_NOT_AVAILABLE;
@ -136,14 +139,17 @@ NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString&
// Get the human-readable name of the bundle // Get the human-readable name of the bundle
CFStringRef bundleName = CFStringRef bundleName =
(CFStringRef)::CFBundleGetValueForInfoDictionaryKey(handlerBundle, kCFBundleNameKey); (CFStringRef)::CFBundleGetValueForInfoDictionaryKey(handlerBundle,
kCFBundleNameKey);
if (bundleName) { if (bundleName) {
AutoTArray<UniChar, 255> buffer; AutoTArray<UniChar, 255> buffer;
CFIndex bundleNameLength = ::CFStringGetLength(bundleName); CFIndex bundleNameLength = ::CFStringGetLength(bundleName);
buffer.SetLength(bundleNameLength); buffer.SetLength(bundleNameLength);
::CFStringGetCharacters(bundleName, CFRangeMake(0, bundleNameLength), buffer.Elements()); ::CFStringGetCharacters(bundleName, CFRangeMake(0, bundleNameLength),
_retval.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), bundleNameLength); buffer.Elements());
_retval.Assign(reinterpret_cast<char16_t*>(buffer.Elements()),
bundleNameLength);
rv = NS_OK; rv = NS_OK;
} }
::CFRelease(handlerBundle); ::CFRelease(handlerBundle);
@ -155,8 +161,8 @@ NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString&
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
} }
NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme, NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(
bool* _retval) { const nsACString& aScheme, bool* _retval) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
nsresult rv = NS_ERROR_NOT_AVAILABLE; nsresult rv = NS_ERROR_NOT_AVAILABLE;
@ -164,7 +170,8 @@ NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACS
CFURLRef handlerBundleURL; CFURLRef handlerBundleURL;
rv = GetDefaultBundleURL(aScheme, &handlerBundleURL); rv = GetDefaultBundleURL(aScheme, &handlerBundleURL);
if (NS_SUCCEEDED(rv) && handlerBundleURL) { if (NS_SUCCEEDED(rv) && handlerBundleURL) {
// Ensure we don't accidentally return success if we can't get an app bundle. // Ensure we don't accidentally return success if we can't get an app
// bundle.
rv = NS_ERROR_NOT_AVAILABLE; rv = NS_ERROR_NOT_AVAILABLE;
CFBundleRef appBundle = ::CFBundleGetMainBundle(); CFBundleRef appBundle = ::CFBundleGetMainBundle();
if (appBundle) { if (appBundle) {
@ -181,23 +188,25 @@ NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACS
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
} }
nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t* aPlatformAppPath, nsresult nsOSHelperAppService::GetFileTokenForPath(
nsIFile** aFile) { const char16_t* aPlatformAppPath, nsIFile** aFile) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
nsresult rv; nsresult rv;
nsCOMPtr<nsILocalFileMac> localFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); nsCOMPtr<nsILocalFileMac> localFile(
do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
CFURLRef pathAsCFURL; CFURLRef pathAsCFURL;
CFStringRef pathAsCFString = ::CFStringCreateWithCharacters( CFStringRef pathAsCFString = ::CFStringCreateWithCharacters(
NULL, reinterpret_cast<const UniChar*>(aPlatformAppPath), NS_strlen(aPlatformAppPath)); NULL, reinterpret_cast<const UniChar*>(aPlatformAppPath),
NS_strlen(aPlatformAppPath));
if (!pathAsCFString) return NS_ERROR_OUT_OF_MEMORY; if (!pathAsCFString) return NS_ERROR_OUT_OF_MEMORY;
if (::CFStringGetCharacterAtIndex(pathAsCFString, 0) == '/') { if (::CFStringGetCharacterAtIndex(pathAsCFString, 0) == '/') {
// we have a Posix path // we have a Posix path
pathAsCFURL = pathAsCFURL = ::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString,
::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString, kCFURLPOSIXPathStyle, false); kCFURLPOSIXPathStyle, false);
if (!pathAsCFURL) { if (!pathAsCFURL) {
::CFRelease(pathAsCFString); ::CFRelease(pathAsCFString);
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
@ -214,8 +223,8 @@ nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t* aPlatformAppP
return NS_ERROR_FILE_UNRECOGNIZED_PATH; return NS_ERROR_FILE_UNRECOGNIZED_PATH;
} }
pathAsCFURL = pathAsCFURL = ::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString,
::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString, kCFURLHFSPathStyle, false); kCFURLHFSPathStyle, false);
if (!pathAsCFURL) { if (!pathAsCFURL) {
::CFRelease(pathAsCFString); ::CFRelease(pathAsCFString);
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
@ -259,7 +268,8 @@ static CFArrayRef GetMIMETypesHandledByApp(FSRef* aAppRef) {
if (!infoDict) { if (!infoDict) {
return NULL; return NULL;
} }
CFTypeRef cfObject = ::CFDictionaryGetValue(infoDict, CFSTR("CFBundleDocumentTypes")); CFTypeRef cfObject =
::CFDictionaryGetValue(infoDict, CFSTR("CFBundleDocumentTypes"));
if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) { if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) {
::CFRelease(infoDict); ::CFRelease(infoDict);
return NULL; return NULL;
@ -307,7 +317,8 @@ static CFArrayRef GetMIMETypesHandledByApp(FSRef* aAppRef) {
} }
nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
const nsACString& aFileExt, bool* aFound, const nsACString& aFileExt,
bool* aFound,
nsIMIMEInfo** aMIMEInfo) { nsIMIMEInfo** aMIMEInfo) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(XRE_IsParentProcess());
@ -318,7 +329,8 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
const nsCString& flatExt = PromiseFlatCString(aFileExt); const nsCString& flatExt = PromiseFlatCString(aFileExt);
MOZ_LOG(sLog, LogLevel::Debug, MOZ_LOG(sLog, LogLevel::Debug,
("Mac: HelperAppService lookup for type '%s' ext '%s'\n", flatType.get(), flatExt.get())); ("Mac: HelperAppService lookup for type '%s' ext '%s'\n",
flatType.get(), flatExt.get()));
// Create a Mac-specific MIME info so we can use Mac-specific members. // Create a Mac-specific MIME info so we can use Mac-specific members.
RefPtr<nsMIMEInfoMac> mimeInfoMac = new nsMIMEInfoMac(aMIMEType); RefPtr<nsMIMEInfoMac> mimeInfoMac = new nsMIMEInfoMac(aMIMEType);
@ -337,13 +349,15 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
CFStringRef cfMIMEType = NULL; CFStringRef cfMIMEType = NULL;
if (!aMIMEType.IsEmpty()) { if (!aMIMEType.IsEmpty()) {
typeIsOctetStream = aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM); typeIsOctetStream =
aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM);
CFURLRef appURL = NULL; CFURLRef appURL = NULL;
// CFStringCreateWithCString() can fail even if we're not out of memory -- // CFStringCreateWithCString() can fail even if we're not out of memory --
// for example if the 'cStr' parameter is something very weird (like // for example if the 'cStr' parameter is something very weird (like
// "\xFF\xFF~"), or possibly if it can't be interpreted as using what's // "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
// specified in the 'encoding' parameter. See bug 548719. // specified in the 'encoding' parameter. See bug 548719.
cfMIMEType = ::CFStringCreateWithCString(NULL, flatType.get(), kCFStringEncodingUTF8); cfMIMEType = ::CFStringCreateWithCString(NULL, flatType.get(),
kCFStringEncodingUTF8);
if (cfMIMEType) { if (cfMIMEType) {
err = ::LSCopyApplicationForMIMEType(cfMIMEType, kLSRolesAll, &appURL); err = ::LSCopyApplicationForMIMEType(cfMIMEType, kLSRolesAll, &appURL);
if ((err == noErr) && appURL && ::CFURLGetFSRef(appURL, &typeAppFSRef)) { if ((err == noErr) && appURL && ::CFURLGetFSRef(appURL, &typeAppFSRef)) {
@ -361,13 +375,15 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
// for example if the 'cStr' parameter is something very weird (like // for example if the 'cStr' parameter is something very weird (like
// "\xFF\xFF~"), or possibly if it can't be interpreted as using what's // "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
// specified in the 'encoding' parameter. See bug 548719. // specified in the 'encoding' parameter. See bug 548719.
CFStringRef cfExt = ::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8); CFStringRef cfExt =
::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8);
if (cfExt) { if (cfExt) {
err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, cfExt, kLSRolesAll, err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, cfExt,
&extAppFSRef, nullptr); kLSRolesAll, &extAppFSRef, nullptr);
if (err == noErr) { if (err == noErr) {
haveAppForExt = true; haveAppForExt = true;
MOZ_LOG(sLog, LogLevel::Debug, ("LSGetApplicationForInfo found a default application\n")); MOZ_LOG(sLog, LogLevel::Debug,
("LSGetApplicationForInfo found a default application\n"));
} }
::CFRelease(cfExt); ::CFRelease(cfExt);
} }
@ -375,7 +391,8 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
if (haveAppForType && haveAppForExt) { if (haveAppForType && haveAppForExt) {
// Do aMIMEType and aFileExt match? // Do aMIMEType and aFileExt match?
if (::FSCompareFSRefs((const FSRef*)&typeAppFSRef, (const FSRef*)&extAppFSRef) == noErr) { if (::FSCompareFSRefs((const FSRef*)&typeAppFSRef,
(const FSRef*)&extAppFSRef) == noErr) {
typeAppIsDefault = true; typeAppIsDefault = true;
*aFound = true; *aFound = true;
} }
@ -418,9 +435,10 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
CFArrayRef extAppMIMETypes = GetMIMETypesHandledByApp(&extAppFSRef); CFArrayRef extAppMIMETypes = GetMIMETypesHandledByApp(&extAppFSRef);
if (extAppMIMETypes) { if (extAppMIMETypes) {
if (cfMIMEType) { if (cfMIMEType) {
if (::CFArrayContainsValue(extAppMIMETypes, if (::CFArrayContainsValue(
::CFRangeMake(0, ::CFArrayGetCount(extAppMIMETypes)), extAppMIMETypes,
cfMIMEType)) { ::CFRangeMake(0, ::CFArrayGetCount(extAppMIMETypes)),
cfMIMEType)) {
extAppIsDefault = true; extAppIsDefault = true;
*aFound = true; *aFound = true;
} }
@ -445,11 +463,13 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
// the doc for this method says that if we have a MIME type (in // the doc for this method says that if we have a MIME type (in
// aMIMEType), we need to give it preference.) // aMIMEType), we need to give it preference.)
NSURLFileTypeMappings* map = [NSURLFileTypeMappings sharedMappings]; NSURLFileTypeMappings* map = [NSURLFileTypeMappings sharedMappings];
NSString* extStr = [NSString stringWithCString:flatExt.get() encoding:NSASCIIStringEncoding]; NSString* extStr = [NSString stringWithCString:flatExt.get()
encoding:NSASCIIStringEncoding];
NSString* typeStr = map ? [map MIMETypeForExtension:extStr] : NULL; NSString* typeStr = map ? [map MIMETypeForExtension:extStr] : NULL;
if (typeStr) { if (typeStr) {
nsAutoCString mimeType; nsAutoCString mimeType;
mimeType.Assign((char*)[typeStr cStringUsingEncoding:NSASCIIStringEncoding]); mimeType.Assign(
(char*)[typeStr cStringUsingEncoding:NSASCIIStringEncoding]);
mimeInfoMac->SetMIMEType(mimeType); mimeInfoMac->SetMIMEType(mimeType);
haveAppForType = true; haveAppForType = true;
} else { } else {
@ -476,7 +496,8 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
if (haveAppForExt) mimeInfoMac->AppendExtension(aFileExt); if (haveAppForExt) mimeInfoMac->AppendExtension(aFileExt);
nsresult rv; nsresult rv;
nsCOMPtr<nsILocalFileMac> app(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); nsCOMPtr<nsILocalFileMac> app(
do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
[localPool release]; [localPool release];
return rv; return rv;
@ -485,20 +506,22 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
CFStringRef cfAppName = NULL; CFStringRef cfAppName = NULL;
if (typeAppIsDefault) { if (typeAppIsDefault) {
app->InitWithFSRef(&typeAppFSRef); app->InitWithFSRef(&typeAppFSRef);
::LSCopyItemAttribute((const FSRef*)&typeAppFSRef, kLSRolesAll, kLSItemDisplayName, ::LSCopyItemAttribute((const FSRef*)&typeAppFSRef, kLSRolesAll,
(CFTypeRef*)&cfAppName); kLSItemDisplayName, (CFTypeRef*)&cfAppName);
} else { } else {
app->InitWithFSRef(&extAppFSRef); app->InitWithFSRef(&extAppFSRef);
::LSCopyItemAttribute((const FSRef*)&extAppFSRef, kLSRolesAll, kLSItemDisplayName, ::LSCopyItemAttribute((const FSRef*)&extAppFSRef, kLSRolesAll,
(CFTypeRef*)&cfAppName); kLSItemDisplayName, (CFTypeRef*)&cfAppName);
} }
if (cfAppName) { if (cfAppName) {
AutoTArray<UniChar, 255> buffer; AutoTArray<UniChar, 255> buffer;
CFIndex appNameLength = ::CFStringGetLength(cfAppName); CFIndex appNameLength = ::CFStringGetLength(cfAppName);
buffer.SetLength(appNameLength); buffer.SetLength(appNameLength);
::CFStringGetCharacters(cfAppName, CFRangeMake(0, appNameLength), buffer.Elements()); ::CFStringGetCharacters(cfAppName, CFRangeMake(0, appNameLength),
buffer.Elements());
nsAutoString appName; nsAutoString appName;
appName.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), appNameLength); appName.Assign(reinterpret_cast<char16_t*>(buffer.Elements()),
appNameLength);
mimeInfoMac->SetDefaultDescription(appName); mimeInfoMac->SetDefaultDescription(appName);
::CFRelease(cfAppName); ::CFRelease(cfAppName);
} }
@ -516,25 +539,29 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
// If we have a MIME type, make sure its extension list is included in our // If we have a MIME type, make sure its extension list is included in our
// list. // list.
NSURLFileTypeMappings* map = [NSURLFileTypeMappings sharedMappings]; NSURLFileTypeMappings* map = [NSURLFileTypeMappings sharedMappings];
NSString* typeStr = [NSString stringWithCString:mimeType.get() encoding:NSASCIIStringEncoding]; NSString* typeStr = [NSString stringWithCString:mimeType.get()
encoding:NSASCIIStringEncoding];
NSArray* extensionsList = map ? [map extensionsForMIMEType:typeStr] : NULL; NSArray* extensionsList = map ? [map extensionsForMIMEType:typeStr] : NULL;
if (extensionsList) { if (extensionsList) {
for (NSString* extension in extensionsList) { for (NSString* extension in extensionsList) {
nsAutoCString ext; nsAutoCString ext;
ext.Assign((char*)[extension cStringUsingEncoding:NSASCIIStringEncoding]); ext.Assign(
(char*)[extension cStringUsingEncoding:NSASCIIStringEncoding]);
mimeInfoMac->AppendExtension(ext); mimeInfoMac->AppendExtension(ext);
} }
} }
if (CFStringRef cfType = if (CFStringRef cfType = ::CFStringCreateWithCString(
::CFStringCreateWithCString(NULL, mimeType.get(), kCFStringEncodingUTF8)) { NULL, mimeType.get(), kCFStringEncodingUTF8)) {
if (CFStringRef cfTypeDesc = ::UTTypeCopyDescription(cfType)) { if (CFStringRef cfTypeDesc = ::UTTypeCopyDescription(cfType)) {
AutoTArray<UniChar, 255> buffer; AutoTArray<UniChar, 255> buffer;
CFIndex typeDescLength = ::CFStringGetLength(cfTypeDesc); CFIndex typeDescLength = ::CFStringGetLength(cfTypeDesc);
buffer.SetLength(typeDescLength); buffer.SetLength(typeDescLength);
::CFStringGetCharacters(cfTypeDesc, CFRangeMake(0, typeDescLength), buffer.Elements()); ::CFStringGetCharacters(cfTypeDesc, CFRangeMake(0, typeDescLength),
buffer.Elements());
nsAutoString typeDesc; nsAutoString typeDesc;
typeDesc.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), typeDescLength); typeDesc.Assign(reinterpret_cast<char16_t*>(buffer.Elements()),
typeDescLength);
mimeInfoMac->SetDescription(typeDesc); mimeInfoMac->SetDescription(typeDesc);
::CFRelease(cfTypeDesc); ::CFRelease(cfTypeDesc);
} }
@ -542,7 +569,8 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
} }
} }
MOZ_LOG(sLog, LogLevel::Debug, ("OS gave us: type '%s' found '%i'\n", mimeType.get(), *aFound)); MOZ_LOG(sLog, LogLevel::Debug,
("OS gave us: type '%s' found '%i'\n", mimeType.get(), *aFound));
[localPool release]; [localPool release];
mimeInfoMac.forget(aMIMEInfo); mimeInfoMac.forget(aMIMEInfo);
@ -552,14 +580,17 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
} }
NS_IMETHODIMP NS_IMETHODIMP
nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found, nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme,
bool* found,
nsIHandlerInfo** _retval) { nsIHandlerInfo** _retval) {
NS_ASSERTION(!aScheme.IsEmpty(), "No scheme was specified!"); NS_ASSERTION(!aScheme.IsEmpty(), "No scheme was specified!");
nsresult rv = OSProtocolHandlerExists(nsPromiseFlatCString(aScheme).get(), found); nsresult rv =
OSProtocolHandlerExists(nsPromiseFlatCString(aScheme).get(), found);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
nsMIMEInfoMac* handlerInfo = new nsMIMEInfoMac(aScheme, nsMIMEInfoBase::eProtocolInfo); nsMIMEInfoMac* handlerInfo =
new nsMIMEInfoMac(aScheme, nsMIMEInfoBase::eProtocolInfo);
NS_ENSURE_TRUE(handlerInfo, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(handlerInfo, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(*_retval = handlerInfo); NS_ADDREF(*_retval = handlerInfo);

View file

@ -10,7 +10,7 @@
#include "nsIURI.h" #include "nsIURI.h"
NS_IMETHODIMP NS_IMETHODIMP
nsLocalHandlerAppUIKit::LaunchWithURI(nsIURI* aURI, nsLocalHandlerAppUIKit::LaunchWithURI(
mozilla::dom::BrowsingContext* aBrowsingContext) { nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }

View file

@ -7,6 +7,10 @@
#include "nsMIMEInfoUIKit.h" #include "nsMIMEInfoUIKit.h"
NS_IMETHODIMP NS_IMETHODIMP
nsMIMEInfoUIKit::LaunchWithFile(nsIFile* aFile) { return NS_ERROR_NOT_IMPLEMENTED; } nsMIMEInfoUIKit::LaunchWithFile(nsIFile* aFile) {
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult nsMIMEInfoUIKit::LoadUriInternal(nsIURI* aURI) { return NS_ERROR_NOT_IMPLEMENTED; } nsresult nsMIMEInfoUIKit::LoadUriInternal(nsIURI* aURI) {
return NS_ERROR_NOT_IMPLEMENTED;
}

View file

@ -10,43 +10,48 @@ nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService() {}
nsOSHelperAppService::~nsOSHelperAppService() {} nsOSHelperAppService::~nsOSHelperAppService() {}
nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char* aProtocolScheme, nsresult nsOSHelperAppService::OSProtocolHandlerExists(
bool* aHandlerExists) { const char* aProtocolScheme, bool* aHandlerExists) {
*aHandlerExists = false; *aHandlerExists = false;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsAString& _retval) { nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme,
nsAString& _retval) {
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme, bool* _retval) { nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(
const nsACString& aScheme, bool* _retval) {
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t* aPlatformAppPath, nsresult nsOSHelperAppService::GetFileTokenForPath(
nsIFile** aFile) { const char16_t* aPlatformAppPath, nsIFile** aFile) {
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsOSHelperAppService::GetFromTypeAndExtension(const nsACString& aType, const nsACString& aFileExt, nsOSHelperAppService::GetFromTypeAndExtension(const nsACString& aType,
const nsACString& aFileExt,
nsIMIMEInfo** aMIMEInfo) { nsIMIMEInfo** aMIMEInfo) {
return nsExternalHelperAppService::GetFromTypeAndExtension(aType, aFileExt, aMIMEInfo); return nsExternalHelperAppService::GetFromTypeAndExtension(aType, aFileExt,
aMIMEInfo);
} }
NS_IMETHODIMP nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, NS_IMETHODIMP nsOSHelperAppService::GetMIMEInfoFromOS(
const nsACString& aFileExt, bool* aFound, const nsACString& aMIMEType, const nsACString& aFileExt, bool* aFound,
nsIMIMEInfo** aMIMEInfo) { nsIMIMEInfo** aMIMEInfo) {
*aMIMEInfo = nullptr; *aMIMEInfo = nullptr;
*aFound = false; *aFound = false;
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found, nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme,
bool* found,
nsIHandlerInfo** _retval) { nsIHandlerInfo** _retval) {
*found = false; *found = false;
return NS_OK; return NS_OK;

View file

@ -29,7 +29,8 @@ static void ToolbarThemePrefChanged(const char* aPref, void* aUserInfo);
if (XRE_IsParentProcess()) { if (XRE_IsParentProcess()) {
mozilla::Preferences::RegisterCallbackAndCall( mozilla::Preferences::RegisterCallbackAndCall(
&ToolbarThemePrefChanged, &ToolbarThemePrefChanged,
nsDependentCString(mozilla::StaticPrefs::GetPrefName_browser_theme_toolbar_theme())); nsDependentCString(
mozilla::StaticPrefs::GetPrefName_browser_theme_toolbar_theme()));
} }
} }
return sInstance; return sInstance;
@ -60,9 +61,10 @@ static void ToolbarThemePrefChanged(const char* aPref, void* aUserInfo);
} }
+ (NSSet*)keyPathsForValuesAffectingEffectiveAppearance { + (NSSet*)keyPathsForValuesAffectingEffectiveAppearance {
// Automatically notify any key-value observers of our effectiveAppearance property whenever the // Automatically notify any key-value observers of our effectiveAppearance
// pref or the NSApp's effectiveAppearance change. // property whenever the pref or the NSApp's effectiveAppearance change.
return [NSSet setWithObjects:@"toolbarTheme", @"_app.effectiveAppearance", nil]; return
[NSSet setWithObjects:@"toolbarTheme", @"_app.effectiveAppearance", nil];
} }
- (NSAppearance*)effectiveAppearance { - (NSAppearance*)effectiveAppearance {

View file

@ -52,15 +52,16 @@ void SetDesktopImage(nsIFile* aImage) {
} }
// Use existing options for this screen // Use existing options for this screen
NSDictionary* screenOptions = NSDictionary* screenOptions = [[NSWorkspace sharedWorkspace]
[[NSWorkspace sharedWorkspace] desktopImageOptionsForScreen:currentScreen]; desktopImageOptionsForScreen:currentScreen];
NSError* error = nil; NSError* error = nil;
if (![[NSWorkspace sharedWorkspace] setDesktopImageURL:url if (![[NSWorkspace sharedWorkspace] setDesktopImageURL:url
forScreen:currentScreen forScreen:currentScreen
options:screenOptions options:screenOptions
error:&error]) { error:&error]) {
LOG("%s ERROR: setDesktopImageURL failed (%ld)", __func__, (long)[error code]); LOG("%s ERROR: setDesktopImageURL failed (%ld)", __func__,
(long)[error code]);
} }
} }

View file

@ -31,7 +31,9 @@ using namespace mozilla::widget;
NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug) NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
#endif #endif
GfxInfo::GfxInfo() : mNumGPUsDetected(0), mOSXVersion{0} { mAdapterRAM[0] = mAdapterRAM[1] = 0; } GfxInfo::GfxInfo() : mNumGPUsDetected(0), mOSXVersion{0} {
mAdapterRAM[0] = mAdapterRAM[1] = 0;
}
static OperatingSystem OSXVersionToOperatingSystem(uint32_t aOSXVersion) { static OperatingSystem OSXVersionToOperatingSystem(uint32_t aOSXVersion) {
switch (nsCocoaFeatures::ExtractMajorVersion(aOSXVersion)) { switch (nsCocoaFeatures::ExtractMajorVersion(aOSXVersion)) {
@ -78,10 +80,11 @@ static OperatingSystem OSXVersionToOperatingSystem(uint32_t aOSXVersion) {
return OperatingSystem::Unknown; return OperatingSystem::Unknown;
} }
// The following three functions are derived from Chromium code // The following three functions are derived from Chromium code
static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort, CFStringRef propertyName) { static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort,
return IORegistryEntrySearchCFProperty(dspPort, kIOServicePlane, propertyName, CFStringRef propertyName) {
kCFAllocatorDefault, return IORegistryEntrySearchCFProperty(
kIORegistryIterateRecursively | kIORegistryIterateParents); dspPort, kIOServicePlane, propertyName, kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents);
} }
static uint32_t IntValueOfCFData(CFDataRef d) { static uint32_t IntValueOfCFData(CFDataRef d) {
@ -100,29 +103,33 @@ void GfxInfo::GetDeviceInfo() {
CFMutableDictionaryRef pci_dev_dict = IOServiceMatching("IOPCIDevice"); CFMutableDictionaryRef pci_dev_dict = IOServiceMatching("IOPCIDevice");
io_iterator_t io_iter; io_iterator_t io_iter;
if (IOServiceGetMatchingServices(kIOMasterPortDefault, pci_dev_dict, &io_iter) != if (IOServiceGetMatchingServices(kIOMasterPortDefault, pci_dev_dict,
kIOReturnSuccess) { &io_iter) != kIOReturnSuccess) {
MOZ_DIAGNOSTIC_ASSERT(false, MOZ_DIAGNOSTIC_ASSERT(
"Failed to detect any GPUs (couldn't enumerate IOPCIDevice services)"); false,
"Failed to detect any GPUs (couldn't enumerate IOPCIDevice services)");
return; return;
} }
io_registry_entry_t entry = IO_OBJECT_NULL; io_registry_entry_t entry = IO_OBJECT_NULL;
while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) { while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
constexpr uint32_t kClassCodeDisplayVGA = 0x30000; constexpr uint32_t kClassCodeDisplayVGA = 0x30000;
CFTypeRef class_code_ref = SearchPortForProperty(entry, CFSTR("class-code")); CFTypeRef class_code_ref =
SearchPortForProperty(entry, CFSTR("class-code"));
if (class_code_ref) { if (class_code_ref) {
const uint32_t class_code = IntValueOfCFData((CFDataRef)class_code_ref); const uint32_t class_code = IntValueOfCFData((CFDataRef)class_code_ref);
CFRelease(class_code_ref); CFRelease(class_code_ref);
if (class_code == kClassCodeDisplayVGA) { if (class_code == kClassCodeDisplayVGA) {
CFTypeRef vendor_id_ref = SearchPortForProperty(entry, CFSTR("vendor-id")); CFTypeRef vendor_id_ref =
SearchPortForProperty(entry, CFSTR("vendor-id"));
if (vendor_id_ref) { if (vendor_id_ref) {
mAdapterVendorID[mNumGPUsDetected].AppendPrintf( mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
"0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref)); "0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
CFRelease(vendor_id_ref); CFRelease(vendor_id_ref);
} }
CFTypeRef device_id_ref = SearchPortForProperty(entry, CFSTR("device-id")); CFTypeRef device_id_ref =
SearchPortForProperty(entry, CFSTR("device-id"));
if (device_id_ref) { if (device_id_ref) {
mAdapterDeviceID[mNumGPUsDetected].AppendPrintf( mAdapterDeviceID[mNumGPUsDetected].AppendPrintf(
"0x%04x", IntValueOfCFData((CFDataRef)device_id_ref)); "0x%04x", IntValueOfCFData((CFDataRef)device_id_ref));
@ -145,14 +152,15 @@ void GfxInfo::GetDeviceInfo() {
} }
CFMutableDictionaryRef agx_dev_dict = IOServiceMatching("AGXAccelerator"); CFMutableDictionaryRef agx_dev_dict = IOServiceMatching("AGXAccelerator");
if (IOServiceGetMatchingServices(kIOMasterPortDefault, agx_dev_dict, &io_iter) == if (IOServiceGetMatchingServices(kIOMasterPortDefault, agx_dev_dict,
kIOReturnSuccess) { &io_iter) == kIOReturnSuccess) {
io_registry_entry_t entry = IO_OBJECT_NULL; io_registry_entry_t entry = IO_OBJECT_NULL;
while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) { while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
CFTypeRef vendor_id_ref = SearchPortForProperty(entry, CFSTR("vendor-id")); CFTypeRef vendor_id_ref =
SearchPortForProperty(entry, CFSTR("vendor-id"));
if (vendor_id_ref) { if (vendor_id_ref) {
mAdapterVendorID[mNumGPUsDetected].AppendPrintf("0x%04x", mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
IntValueOfCFData((CFDataRef)vendor_id_ref)); "0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
CFRelease(vendor_id_ref); CFRelease(vendor_id_ref);
++mNumGPUsDetected; ++mNumGPUsDetected;
} }
@ -189,22 +197,32 @@ NS_IMETHODIMP
GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; } GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
/* readonly attribute bool HasBattery; */ /* readonly attribute bool HasBattery; */
NS_IMETHODIMP GfxInfo::GetHasBattery(bool* aHasBattery) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP GfxInfo::GetHasBattery(bool* aHasBattery) {
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute DOMString DWriteVersion; */ /* readonly attribute DOMString DWriteVersion; */
NS_IMETHODIMP NS_IMETHODIMP
GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) { return NS_ERROR_FAILURE; } GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) {
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP NS_IMETHODIMP
GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) { return NS_ERROR_FAILURE; } GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) {
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString cleartypeParameters; */ /* readonly attribute DOMString cleartypeParameters; */
NS_IMETHODIMP NS_IMETHODIMP
GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) { return NS_ERROR_FAILURE; } GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) {
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString windowProtocol; */ /* readonly attribute DOMString windowProtocol; */
NS_IMETHODIMP NS_IMETHODIMP
GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) { return NS_ERROR_NOT_IMPLEMENTED; } GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) {
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute DOMString testType; */ /* readonly attribute DOMString testType; */
NS_IMETHODIMP NS_IMETHODIMP
@ -348,14 +366,20 @@ GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) {
/* readonly attribute DOMString adapterSubsysID; */ /* readonly attribute DOMString adapterSubsysID; */
NS_IMETHODIMP NS_IMETHODIMP
GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) { return NS_ERROR_FAILURE; } GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) {
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterSubsysID2; */ /* readonly attribute DOMString adapterSubsysID2; */
NS_IMETHODIMP NS_IMETHODIMP
GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) { return NS_ERROR_FAILURE; } GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) {
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP NS_IMETHODIMP
GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) { return NS_ERROR_NOT_IMPLEMENTED; } GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute boolean isGPU2Active; */ /* readonly attribute boolean isGPU2Active; */
NS_IMETHODIMP NS_IMETHODIMP
@ -372,60 +396,70 @@ void GfxInfo::AddCrashReportAnnotations() {
GetAdapterDriverVersion(driverVersion); GetAdapterDriverVersion(driverVersion);
CopyUTF16toUTF8(driverVersion, narrowDriverVersion); CopyUTF16toUTF8(driverVersion, narrowDriverVersion);
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID, narrowVendorID); CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID, narrowDeviceID); narrowVendorID);
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDriverVersion, CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
narrowDriverVersion); narrowDeviceID);
CrashReporter::AnnotateCrashReport(
CrashReporter::Annotation::AdapterDriverVersion, narrowDriverVersion);
} }
// We don't support checking driver versions on Mac. // We don't support checking driver versions on Mac.
#define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, device, features, blockOn, ruleId) \ #define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, device, features, blockOn, ruleId) \
APPEND_TO_DRIVER_BLOCKLIST(os, device, features, blockOn, DRIVER_COMPARISON_IGNORED, \ APPEND_TO_DRIVER_BLOCKLIST(os, device, features, blockOn, \
V(0, 0, 0, 0), ruleId, "") DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), ruleId, \
"")
const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() { const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
if (!sDriverInfo->Length()) { if (!sDriverInfo->Length()) {
IMPLEMENT_MAC_DRIVER_BLOCKLIST( IMPLEMENT_MAC_DRIVER_BLOCKLIST(
OperatingSystem::OSX, DeviceFamily::RadeonX1000, nsIGfxInfo::FEATURE_OPENGL_LAYERS, OperatingSystem::OSX, DeviceFamily::RadeonX1000,
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D"); nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
"FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D");
IMPLEMENT_MAC_DRIVER_BLOCKLIST( IMPLEMENT_MAC_DRIVER_BLOCKLIST(
OperatingSystem::OSX, DeviceFamily::Geforce7300GT, nsIGfxInfo::FEATURE_WEBGL_OPENGL, OperatingSystem::OSX, DeviceFamily::Geforce7300GT,
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_7300_NO_WEBGL"); nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, DeviceFamily::IntelHDGraphicsToIvyBridge, "FEATURE_FAILURE_MAC_7300_NO_WEBGL");
nsIGfxInfo::FEATURE_GL_SWIZZLE, IMPLEMENT_MAC_DRIVER_BLOCKLIST(
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, OperatingSystem::OSX, DeviceFamily::IntelHDGraphicsToIvyBridge,
"FEATURE_FAILURE_MAC_INTELHD4000_NO_SWIZZLE"); nsIGfxInfo::FEATURE_GL_SWIZZLE, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
// We block texture swizzling everwhere on mac because it's broken in some configurations "FEATURE_FAILURE_MAC_INTELHD4000_NO_SWIZZLE");
// and we want to support GPU switching. // We block texture swizzling everwhere on mac because it's broken in some
// configurations and we want to support GPU switching.
IMPLEMENT_MAC_DRIVER_BLOCKLIST( IMPLEMENT_MAC_DRIVER_BLOCKLIST(
OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_GL_SWIZZLE, OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_GL_SWIZZLE,
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_GPU_SWITCHING_NO_SWIZZLE"); nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
"FEATURE_FAILURE_MAC_GPU_SWITCHING_NO_SWIZZLE");
// Older generation Intel devices do not perform well with WebRender. // Older generation Intel devices do not perform well with WebRender.
IMPLEMENT_MAC_DRIVER_BLOCKLIST( IMPLEMENT_MAC_DRIVER_BLOCKLIST(
OperatingSystem::OSX, DeviceFamily::IntelWebRenderBlocked, nsIGfxInfo::FEATURE_WEBRENDER, OperatingSystem::OSX, DeviceFamily::IntelWebRenderBlocked,
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_INTEL_GEN5_OR_OLDER"); nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
"FEATURE_FAILURE_INTEL_GEN5_OR_OLDER");
// Intel HD3000 disabled due to bug 1661505 // Intel HD3000 disabled due to bug 1661505
IMPLEMENT_MAC_DRIVER_BLOCKLIST( IMPLEMENT_MAC_DRIVER_BLOCKLIST(
OperatingSystem::OSX, DeviceFamily::IntelSandyBridge, nsIGfxInfo::FEATURE_WEBRENDER, OperatingSystem::OSX, DeviceFamily::IntelSandyBridge,
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_INTEL_MAC_HD3000_NO_WEBRENDER"); nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
"FEATURE_FAILURE_INTEL_MAC_HD3000_NO_WEBRENDER");
// wgpu doesn't safely support OOB behavior on Metal yet. // wgpu doesn't safely support OOB behavior on Metal yet.
IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, DeviceFamily::All, IMPLEMENT_MAC_DRIVER_BLOCKLIST(
nsIGfxInfo::FEATURE_WEBGPU, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_WEBGPU,
"FEATURE_FAILURE_MAC_WGPU_NO_METAL_BOUNDS_CHECKS"); nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
"FEATURE_FAILURE_MAC_WGPU_NO_METAL_BOUNDS_CHECKS");
} }
return *sDriverInfo; return *sDriverInfo;
} }
OperatingSystem GfxInfo::GetOperatingSystem() { return OSXVersionToOperatingSystem(mOSXVersion); } OperatingSystem GfxInfo::GetOperatingSystem() {
return OSXVersionToOperatingSystem(mOSXVersion);
}
nsresult GfxInfo::GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus, nsresult GfxInfo::GetFeatureStatusImpl(
nsAString& aSuggestedDriverVersion, int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
const nsTArray<GfxDriverInfo>& aDriverInfo, const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
nsACString& aFailureId, OperatingSystem* aOS /* = nullptr */) {
OperatingSystem* aOS /* = nullptr */) {
NS_ENSURE_ARG_POINTER(aStatus); NS_ENSURE_ARG_POINTER(aStatus);
aSuggestedDriverVersion.SetIsVoid(true); aSuggestedDriverVersion.SetIsVoid(true);
*aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
@ -436,7 +470,8 @@ nsresult GfxInfo::GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
return NS_OK; return NS_OK;
} }
// Don't evaluate special cases when we're evaluating the downloaded blocklist. // Don't evaluate special cases when we're evaluating the downloaded
// blocklist.
if (!aDriverInfo.Length()) { if (!aDriverInfo.Length()) {
if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) { if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
// See bug 1249659 // See bug 1249659
@ -460,8 +495,8 @@ nsresult GfxInfo::GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
} }
} }
return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, return GfxInfoBase::GetFeatureStatusImpl(
aFailureId, &os); aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
} }
#ifdef DEBUG #ifdef DEBUG

View file

@ -23,19 +23,20 @@
+ (NSImage*)iconImageFromImageContainer:(imgIContainer*)aImage + (NSImage*)iconImageFromImageContainer:(imgIContainer*)aImage
withSize:(NSSize)aSize withSize:(NSSize)aSize
presContext:(const nsPresContext*)aPresContext presContext:(const nsPresContext*)aPresContext
computedStyle:(const mozilla::ComputedStyle*)aComputedStyle computedStyle:
(const mozilla::ComputedStyle*)aComputedStyle
scaleFactor:(CGFloat)aScaleFactor { scaleFactor:(CGFloat)aScaleFactor {
bool isEntirelyBlack = false; bool isEntirelyBlack = false;
NSImage* retainedImage = nil; NSImage* retainedImage = nil;
nsresult rv; nsresult rv;
if (aScaleFactor != 0.0f) { if (aScaleFactor != 0.0f) {
rv = nsCocoaUtils::CreateNSImageFromImageContainer(aImage, imgIContainer::FRAME_CURRENT, rv = nsCocoaUtils::CreateNSImageFromImageContainer(
aPresContext, aComputedStyle, &retainedImage, aImage, imgIContainer::FRAME_CURRENT, aPresContext, aComputedStyle,
aScaleFactor, &isEntirelyBlack); &retainedImage, aScaleFactor, &isEntirelyBlack);
} else { } else {
rv = nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer( rv = nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
aImage, imgIContainer::FRAME_CURRENT, aPresContext, aComputedStyle, &retainedImage, aImage, imgIContainer::FRAME_CURRENT, aPresContext, aComputedStyle,
&isEntirelyBlack); &retainedImage, &isEntirelyBlack);
} }
NSImage* image = [retainedImage autorelease]; NSImage* image = [retainedImage autorelease];

View file

@ -68,7 +68,8 @@ static BOOL sNeedToUnwindForMenuClosing = NO;
withAppearance:(NSAppearance*)aAppearance withAppearance:(NSAppearance*)aAppearance
asContextMenu:(BOOL)aIsContextMenu { asContextMenu:(BOOL)aIsContextMenu {
MOZ_RELEASE_ASSERT(!mPendingOpening, MOZ_RELEASE_ASSERT(!mPendingOpening,
"A menu is already waiting to open. Before opening the next one, either wait " "A menu is already waiting to open. Before opening the "
"next one, either wait "
"for this one to open or cancel the request."); "for this one to open or cancel the request.");
NSInteger handle = ++mLastHandle; NSInteger handle = ++mLastHandle;
@ -134,33 +135,36 @@ static BOOL sNeedToUnwindForMenuClosing = NO;
asContextMenu:(BOOL)aIsContextMenu { asContextMenu:(BOOL)aIsContextMenu {
// There are multiple ways to display an NSMenu as a context menu. // There are multiple ways to display an NSMenu as a context menu.
// //
// 1. We can return the NSMenu from -[ChildView menuForEvent:] and the NSView will open it for // 1. We can return the NSMenu from -[ChildView menuForEvent:] and the NSView
// us. // will open it for us.
// 2. We can call +[NSMenu popUpContextMenu:withEvent:forView:] inside a mouseDown handler with a // 2. We can call +[NSMenu popUpContextMenu:withEvent:forView:] inside a
// real mouse down event. // mouseDown handler with a real mouse down event.
// 3. We can call +[NSMenu popUpContextMenu:withEvent:forView:] at a later time, with a real // 3. We can call +[NSMenu popUpContextMenu:withEvent:forView:] at a later
// mouse event that we stored earlier. // time, with a real mouse event that we stored earlier.
// 4. We can call +[NSMenu popUpContextMenu:withEvent:forView:] at any time, with a synthetic // 4. We can call +[NSMenu popUpContextMenu:withEvent:forView:] at any time,
// mouse event that we create just for that purpose. // with a synthetic mouse event that we create just for that purpose.
// 5. We can call -[NSMenu popUpMenuPositioningItem:atLocation:inView:] and it just takes a // 5. We can call -[NSMenu popUpMenuPositioningItem:atLocation:inView:] and
// position, not an event. // it just takes a position, not an event.
// //
// 1-4 look the same, 5 looks different: 5 is made for use with NSPopUpButton, where the selected // 1-4 look the same, 5 looks different: 5 is made for use with NSPopUpButton,
// item needs to be shown at a specific position. If a tall menu is opened with a position close // where the selected item needs to be shown at a specific position. If a tall
// to the bottom edge of the screen, 5 results in a cropped menu with scroll arrows, even if the // menu is opened with a position close to the bottom edge of the screen, 5
// entire menu would fit on the screen, due to the positioning constraint. // results in a cropped menu with scroll arrows, even if the entire menu would
// 1-2 only work if the menu contents are known synchronously during the call to menuForEvent or // fit on the screen, due to the positioning constraint. 1-2 only work if the
// menu contents are known synchronously during the call to menuForEvent or
// during the mouseDown event handler. // during the mouseDown event handler.
// NativeMenuMac::ShowAsContextMenu can be called at any time. It could be called during a // NativeMenuMac::ShowAsContextMenu can be called at any time. It could be
// menuForEvent call (during a "contextmenu" event handler), or during a mouseDown handler, or at // called during a menuForEvent call (during a "contextmenu" event handler),
// a later time. // or during a mouseDown handler, or at a later time. The code below uses
// The code below uses option 4 as the preferred option for context menus because it's the // option 4 as the preferred option for context menus because it's the
// simplest: It works in all scenarios and it doesn't have the drawbacks of option 5. For popups // simplest: It works in all scenarios and it doesn't have the drawbacks of
// that aren't context menus and that should be positioned as close as possible to the given // option 5. For popups that aren't context menus and that should be
// screen position, we use option 5. // positioned as close as possible to the given screen position, we use
// option 5.
if (aAppearance) { if (aAppearance) {
#if !defined(MAC_OS_VERSION_11_0) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_11_0 #if !defined(MAC_OS_VERSION_11_0) || \
MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_11_0
if (nsCocoaFeatures::OnBigSurOrLater()) { if (nsCocoaFeatures::OnBigSurOrLater()) {
#else #else
if (@available(macOS 11.0, *)) { if (@available(macOS 11.0, *)) {
@ -174,18 +178,21 @@ static BOOL sNeedToUnwindForMenuClosing = NO;
if (aView) { if (aView) {
NSWindow* window = aView.window; NSWindow* window = aView.window;
NSPoint locationInWindow = nsCocoaUtils::ConvertPointFromScreen(window, aPosition); NSPoint locationInWindow =
nsCocoaUtils::ConvertPointFromScreen(window, aPosition);
if (aIsContextMenu) { if (aIsContextMenu) {
// Create a synthetic event at the right location and open the menu [option 4]. // Create a synthetic event at the right location and open the menu
NSEvent* event = [NSEvent mouseEventWithType:NSEventTypeRightMouseDown // [option 4].
location:locationInWindow NSEvent* event =
modifierFlags:0 [NSEvent mouseEventWithType:NSEventTypeRightMouseDown
timestamp:NSProcessInfo.processInfo.systemUptime location:locationInWindow
windowNumber:window.windowNumber modifierFlags:0
context:nil timestamp:NSProcessInfo.processInfo.systemUptime
eventNumber:0 windowNumber:window.windowNumber
clickCount:1 context:nil
pressure:0.0f]; eventNumber:0
clickCount:1
pressure:0.0f];
[NSMenu popUpContextMenu:aMenu withEvent:event forView:aView]; [NSMenu popUpContextMenu:aMenu withEvent:event forView:aView];
} else { } else {
// For popups which are not context menus, we open the menu using [option // For popups which are not context menus, we open the menu using [option
@ -193,14 +200,18 @@ static BOOL sNeedToUnwindForMenuClosing = NO;
// corner of the menu. This path is used for anchored menupopups, so we // corner of the menu. This path is used for anchored menupopups, so we
// prefer option 5 over option 4 so that the menu doesn't get flipped if // prefer option 5 over option 4 so that the menu doesn't get flipped if
// space is tight. // space is tight.
NSPoint locationInView = [aView convertPoint:locationInWindow fromView:nil]; NSPoint locationInView = [aView convertPoint:locationInWindow
[aMenu popUpMenuPositioningItem:nil atLocation:locationInView inView:aView]; fromView:nil];
[aMenu popUpMenuPositioningItem:nil
atLocation:locationInView
inView:aView];
} }
} else { } else {
// Open the menu using popUpMenuPositioningItem:atLocation:inView: [option 5]. // Open the menu using popUpMenuPositioningItem:atLocation:inView: [option
// This is not preferred, because it positions the menu differently from how a native context // 5]. This is not preferred, because it positions the menu differently from
// menu would be positioned; it enforces aPosition for the top left corner even if this // how a native context menu would be positioned; it enforces aPosition for
// means that the menu will be displayed in a clipped fashion with scroll arrows. // the top left corner even if this means that the menu will be displayed in
// a clipped fashion with scroll arrows.
[aMenu popUpMenuPositioningItem:nil atLocation:aPosition inView:nil]; [aMenu popUpMenuPositioningItem:nil atLocation:aPosition inView:nil];
} }
} }

View file

@ -70,7 +70,9 @@ static MediaControlKey ToMediaControlKey(int aKeyCode) {
namespace mozilla { namespace mozilla {
namespace widget { namespace widget {
bool MediaHardwareKeysEventSourceMac::IsOpened() const { return mEventTap && mEventTapSource; } bool MediaHardwareKeysEventSourceMac::IsOpened() const {
return mEventTap && mEventTapSource;
}
bool MediaHardwareKeysEventSourceMac::Open() { bool MediaHardwareKeysEventSourceMac::Open() {
LOG("Open MediaHardwareKeysEventSourceMac"); LOG("Open MediaHardwareKeysEventSourceMac");
@ -89,22 +91,24 @@ bool MediaHardwareKeysEventSourceMac::StartEventTap() {
MOZ_ASSERT(!mEventTapSource); MOZ_ASSERT(!mEventTapSource);
// Add an event tap to intercept the system defined media key events. // Add an event tap to intercept the system defined media key events.
mEventTap = mEventTap = CGEventTapCreate(
CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
CGEventMaskBit(NX_SYSDEFINED), EventTapCallback, this); CGEventMaskBit(NX_SYSDEFINED), EventTapCallback, this);
if (!mEventTap) { if (!mEventTap) {
LOG("Fail to create event tap"); LOG("Fail to create event tap");
return false; return false;
} }
mEventTapSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, mEventTap, 0); mEventTapSource =
CFMachPortCreateRunLoopSource(kCFAllocatorDefault, mEventTap, 0);
if (!mEventTapSource) { if (!mEventTapSource) {
LOG("Fail to create an event tap source."); LOG("Fail to create an event tap source.");
return false; return false;
} }
LOG("Add an event tap source to current loop"); LOG("Add an event tap source to current loop");
CFRunLoopAddSource(CFRunLoopGetCurrent(), mEventTapSource, kCFRunLoopCommonModes); CFRunLoopAddSource(CFRunLoopGetCurrent(), mEventTapSource,
kCFRunLoopCommonModes);
return true; return true;
} }
@ -115,18 +119,20 @@ void MediaHardwareKeysEventSourceMac::StopEventTap() {
mEventTap = nullptr; mEventTap = nullptr;
} }
if (mEventTapSource) { if (mEventTapSource) {
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mEventTapSource, kCFRunLoopCommonModes); CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mEventTapSource,
kCFRunLoopCommonModes);
CFRelease(mEventTapSource); CFRelease(mEventTapSource);
mEventTapSource = nullptr; mEventTapSource = nullptr;
} }
} }
CGEventRef MediaHardwareKeysEventSourceMac::EventTapCallback(CGEventTapProxy proxy, CGEventRef MediaHardwareKeysEventSourceMac::EventTapCallback(
CGEventType type, CGEventRef event, CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) {
void* refcon) {
// Re-enable event tap when receiving disabled events. // Re-enable event tap when receiving disabled events.
MediaHardwareKeysEventSourceMac* source = static_cast<MediaHardwareKeysEventSourceMac*>(refcon); MediaHardwareKeysEventSourceMac* source =
if (type == kCGEventTapDisabledByUserInput || type == kCGEventTapDisabledByTimeout) { static_cast<MediaHardwareKeysEventSourceMac*>(refcon);
if (type == kCGEventTapDisabledByUserInput ||
type == kCGEventTapDisabledByTimeout) {
MOZ_ASSERT(source->mEventTap); MOZ_ASSERT(source->mEventTap);
CGEventTapEnable(source->mEventTap, true); CGEventTapEnable(source->mEventTap, true);
return event; return event;
@ -151,8 +157,9 @@ CGEventRef MediaHardwareKeysEventSourceMac::EventTapCallback(CGEventTapProxy pro
// - keyRepeat = (keyFlags & 0x1); // - keyRepeat = (keyFlags & 0x1);
const NSInteger data1 = [nsEvent data1]; const NSInteger data1 = [nsEvent data1];
int keyCode = (data1 & 0xFFFF0000) >> 16; int keyCode = (data1 & 0xFFFF0000) >> 16;
if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_NEXT && keyCode != NX_KEYTYPE_PREVIOUS && if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_NEXT &&
keyCode != NX_KEYTYPE_FAST && keyCode != NX_KEYTYPE_REWIND) { keyCode != NX_KEYTYPE_PREVIOUS && keyCode != NX_KEYTYPE_FAST &&
keyCode != NX_KEYTYPE_REWIND) {
return event; return event;
} }
@ -173,7 +180,8 @@ CGEventRef MediaHardwareKeysEventSourceMac::EventTapCallback(CGEventTapProxy pro
} }
LOG2("Get media key %s", source, ToMediaControlKeyStr(keyCode)); LOG2("Get media key %s", source, ToMediaControlKeyStr(keyCode));
for (auto iter = source->mListeners.begin(); iter != source->mListeners.end(); ++iter) { for (auto iter = source->mListeners.begin(); iter != source->mListeners.end();
++iter) {
(*iter)->OnActionPerformed(MediaControlAction(ToMediaControlKey(keyCode))); (*iter)->OnActionPerformed(MediaControlAction(ToMediaControlKey(keyCode)));
} }
return event; return event;

View file

@ -13,39 +13,45 @@ using namespace mozilla::dom;
// avoid redefined macro in unified build // avoid redefined macro in unified build
#undef LOG #undef LOG
#define LOG(msg, ...) \ #define LOG(msg, ...) \
MOZ_LOG(gMediaControlLog, LogLevel::Debug, \ MOZ_LOG(gMediaControlLog, LogLevel::Debug, \
("MediaHardwareKeysEventSourceMacMediaCenter=%p, " msg, this, ##__VA_ARGS__)) ("MediaHardwareKeysEventSourceMacMediaCenter=%p, " msg, this, \
##__VA_ARGS__))
namespace mozilla { namespace mozilla {
namespace widget { namespace widget {
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayPauseHandler() { MediaCenterEventHandler
MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayPauseHandler() {
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) { return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter]; MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
center.playbackState = center.playbackState == MPNowPlayingPlaybackStatePlaying center.playbackState =
? MPNowPlayingPlaybackStatePaused center.playbackState == MPNowPlayingPlaybackStatePlaying
: MPNowPlayingPlaybackStatePlaying; ? MPNowPlayingPlaybackStatePaused
: MPNowPlayingPlaybackStatePlaying;
HandleEvent(MediaControlKey::Playpause); HandleEvent(MediaControlKey::Playpause);
return MPRemoteCommandHandlerStatusSuccess; return MPRemoteCommandHandlerStatusSuccess;
}); });
} }
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreateNextTrackHandler() { MediaCenterEventHandler
MediaHardwareKeysEventSourceMacMediaCenter::CreateNextTrackHandler() {
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) { return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
HandleEvent(MediaControlKey::Nexttrack); HandleEvent(MediaControlKey::Nexttrack);
return MPRemoteCommandHandlerStatusSuccess; return MPRemoteCommandHandlerStatusSuccess;
}); });
} }
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePreviousTrackHandler() { MediaCenterEventHandler
MediaHardwareKeysEventSourceMacMediaCenter::CreatePreviousTrackHandler() {
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) { return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
HandleEvent(MediaControlKey::Previoustrack); HandleEvent(MediaControlKey::Previoustrack);
return MPRemoteCommandHandlerStatusSuccess; return MPRemoteCommandHandlerStatusSuccess;
}); });
} }
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayHandler() { MediaCenterEventHandler
MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayHandler() {
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) { return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter]; MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
if (center.playbackState != MPNowPlayingPlaybackStatePlaying) { if (center.playbackState != MPNowPlayingPlaybackStatePlaying) {
@ -56,7 +62,8 @@ MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayHa
}); });
} }
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePauseHandler() { MediaCenterEventHandler
MediaHardwareKeysEventSourceMacMediaCenter::CreatePauseHandler() {
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) { return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter]; MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
if (center.playbackState != MPNowPlayingPlaybackStatePaused) { if (center.playbackState != MPNowPlayingPlaybackStatePaused) {
@ -67,7 +74,8 @@ MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePauseH
}); });
} }
MediaHardwareKeysEventSourceMacMediaCenter::MediaHardwareKeysEventSourceMacMediaCenter() { MediaHardwareKeysEventSourceMacMediaCenter::
MediaHardwareKeysEventSourceMacMediaCenter() {
mPlayPauseHandler = CreatePlayPauseHandler(); mPlayPauseHandler = CreatePlayPauseHandler();
mNextTrackHandler = CreateNextTrackHandler(); mNextTrackHandler = CreateNextTrackHandler();
mPreviousTrackHandler = CreatePreviousTrackHandler(); mPreviousTrackHandler = CreatePreviousTrackHandler();
@ -76,7 +84,8 @@ MediaHardwareKeysEventSourceMacMediaCenter::MediaHardwareKeysEventSourceMacMedia
LOG("Create MediaHardwareKeysEventSourceMacMediaCenter"); LOG("Create MediaHardwareKeysEventSourceMacMediaCenter");
} }
MediaHardwareKeysEventSourceMacMediaCenter::~MediaHardwareKeysEventSourceMacMediaCenter() { MediaHardwareKeysEventSourceMacMediaCenter::
~MediaHardwareKeysEventSourceMacMediaCenter() {
LOG("Destroy MediaHardwareKeysEventSourceMacMediaCenter"); LOG("Destroy MediaHardwareKeysEventSourceMacMediaCenter");
EndListeningForEvents(); EndListeningForEvents();
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter]; MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
@ -86,13 +95,15 @@ MediaHardwareKeysEventSourceMacMediaCenter::~MediaHardwareKeysEventSourceMacMedi
void MediaHardwareKeysEventSourceMacMediaCenter::BeginListeningForEvents() { void MediaHardwareKeysEventSourceMacMediaCenter::BeginListeningForEvents() {
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter]; MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
center.playbackState = MPNowPlayingPlaybackStatePlaying; center.playbackState = MPNowPlayingPlaybackStatePlaying;
MPRemoteCommandCenter* commandCenter = [MPRemoteCommandCenter sharedCommandCenter]; MPRemoteCommandCenter* commandCenter =
[MPRemoteCommandCenter sharedCommandCenter];
commandCenter.togglePlayPauseCommand.enabled = true; commandCenter.togglePlayPauseCommand.enabled = true;
[commandCenter.togglePlayPauseCommand addTargetWithHandler:mPlayPauseHandler]; [commandCenter.togglePlayPauseCommand addTargetWithHandler:mPlayPauseHandler];
commandCenter.nextTrackCommand.enabled = true; commandCenter.nextTrackCommand.enabled = true;
[commandCenter.nextTrackCommand addTargetWithHandler:mNextTrackHandler]; [commandCenter.nextTrackCommand addTargetWithHandler:mNextTrackHandler];
commandCenter.previousTrackCommand.enabled = true; commandCenter.previousTrackCommand.enabled = true;
[commandCenter.previousTrackCommand addTargetWithHandler:mPreviousTrackHandler]; [commandCenter.previousTrackCommand
addTargetWithHandler:mPreviousTrackHandler];
commandCenter.playCommand.enabled = true; commandCenter.playCommand.enabled = true;
[commandCenter.playCommand addTargetWithHandler:mPlayHandler]; [commandCenter.playCommand addTargetWithHandler:mPlayHandler];
commandCenter.pauseCommand.enabled = true; commandCenter.pauseCommand.enabled = true;
@ -103,7 +114,8 @@ void MediaHardwareKeysEventSourceMacMediaCenter::EndListeningForEvents() {
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter]; MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
center.playbackState = MPNowPlayingPlaybackStatePaused; center.playbackState = MPNowPlayingPlaybackStatePaused;
center.nowPlayingInfo = nil; center.nowPlayingInfo = nil;
MPRemoteCommandCenter* commandCenter = [MPRemoteCommandCenter sharedCommandCenter]; MPRemoteCommandCenter* commandCenter =
[MPRemoteCommandCenter sharedCommandCenter];
commandCenter.togglePlayPauseCommand.enabled = false; commandCenter.togglePlayPauseCommand.enabled = false;
[commandCenter.togglePlayPauseCommand removeTarget:nil]; [commandCenter.togglePlayPauseCommand removeTarget:nil];
commandCenter.nextTrackCommand.enabled = false; commandCenter.nextTrackCommand.enabled = false;
@ -131,9 +143,12 @@ void MediaHardwareKeysEventSourceMacMediaCenter::Close() {
MediaControlKeySource::Close(); MediaControlKeySource::Close();
} }
bool MediaHardwareKeysEventSourceMacMediaCenter::IsOpened() const { return mOpened; } bool MediaHardwareKeysEventSourceMacMediaCenter::IsOpened() const {
return mOpened;
}
void MediaHardwareKeysEventSourceMacMediaCenter::HandleEvent(MediaControlKey aEvent) { void MediaHardwareKeysEventSourceMacMediaCenter::HandleEvent(
MediaControlKey aEvent) {
for (auto iter = mListeners.begin(); iter != mListeners.end(); ++iter) { for (auto iter = mListeners.begin(); iter != mListeners.end(); ++iter) {
(*iter)->OnActionPerformed(MediaControlAction(aEvent)); (*iter)->OnActionPerformed(MediaControlAction(aEvent));
} }

View file

@ -56,12 +56,16 @@ void NativeKeyBindings::Shutdown() {
NativeKeyBindings::NativeKeyBindings() {} NativeKeyBindings::NativeKeyBindings() {}
inline objc_selector* ToObjcSelectorPtr(SEL aSel) { return reinterpret_cast<objc_selector*>(aSel); } inline objc_selector* ToObjcSelectorPtr(SEL aSel) {
#define SEL_TO_COMMAND(aSel, aCommand) \ return reinterpret_cast<objc_selector*>(aSel);
mSelectorToCommand.InsertOrUpdate(ToObjcSelectorPtr(@selector(aSel)), aCommand) }
#define SEL_TO_COMMAND(aSel, aCommand) \
mSelectorToCommand.InsertOrUpdate(ToObjcSelectorPtr(@selector(aSel)), \
aCommand)
void NativeKeyBindings::Init(NativeKeyBindingsType aType) { void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info, ("%p NativeKeyBindings::Init", this)); MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
("%p NativeKeyBindings::Init", this));
// Many selectors have a one-to-one mapping to a Gecko command. Those mappings // Many selectors have a one-to-one mapping to a Gecko command. Those mappings
// are registered in mSelectorToCommand. // are registered in mSelectorToCommand.
@ -88,7 +92,8 @@ void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
// TODO: deleteTo* selectors are also supposed to add text to a kill buffer // TODO: deleteTo* selectors are also supposed to add text to a kill buffer
SEL_TO_COMMAND(deleteToBeginningOfLine:, Command::DeleteToBeginningOfLine); SEL_TO_COMMAND(deleteToBeginningOfLine:, Command::DeleteToBeginningOfLine);
SEL_TO_COMMAND(deleteToBeginningOfParagraph:, Command::DeleteToBeginningOfLine); SEL_TO_COMMAND(deleteToBeginningOfParagraph:,
Command::DeleteToBeginningOfLine);
SEL_TO_COMMAND(deleteToEndOfLine:, Command::DeleteToEndOfLine); SEL_TO_COMMAND(deleteToEndOfLine:, Command::DeleteToEndOfLine);
SEL_TO_COMMAND(deleteToEndOfParagraph:, Command::DeleteToEndOfLine); SEL_TO_COMMAND(deleteToEndOfParagraph:, Command::DeleteToEndOfLine);
// SEL_TO_COMMAND(deleteToMark:, ); // SEL_TO_COMMAND(deleteToMark:, );
@ -119,26 +124,34 @@ void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
SEL_TO_COMMAND(moveForwardAndModifySelection:, Command::SelectCharNext); SEL_TO_COMMAND(moveForwardAndModifySelection:, Command::SelectCharNext);
SEL_TO_COMMAND(moveLeft:, Command::CharPrevious); SEL_TO_COMMAND(moveLeft:, Command::CharPrevious);
SEL_TO_COMMAND(moveLeftAndModifySelection:, Command::SelectCharPrevious); SEL_TO_COMMAND(moveLeftAndModifySelection:, Command::SelectCharPrevious);
SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:, Command::SelectBeginLine); SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:,
SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:, Command::SelectEndLine); Command::SelectBeginLine);
SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:,
Command::SelectEndLine);
SEL_TO_COMMAND(moveRight:, Command::CharNext); SEL_TO_COMMAND(moveRight:, Command::CharNext);
SEL_TO_COMMAND(moveRightAndModifySelection:, Command::SelectCharNext); SEL_TO_COMMAND(moveRightAndModifySelection:, Command::SelectCharNext);
SEL_TO_COMMAND(moveToBeginningOfDocument:, Command::MoveTop); SEL_TO_COMMAND(moveToBeginningOfDocument:, Command::MoveTop);
SEL_TO_COMMAND(moveToBeginningOfDocumentAndModifySelection:, Command::SelectTop); SEL_TO_COMMAND(moveToBeginningOfDocumentAndModifySelection:,
Command::SelectTop);
SEL_TO_COMMAND(moveToBeginningOfLine:, Command::BeginLine); SEL_TO_COMMAND(moveToBeginningOfLine:, Command::BeginLine);
SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:, Command::SelectBeginLine); SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:,
Command::SelectBeginLine);
SEL_TO_COMMAND(moveToBeginningOfParagraph:, Command::BeginLine); SEL_TO_COMMAND(moveToBeginningOfParagraph:, Command::BeginLine);
SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:, Command::SelectBeginLine); SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:,
Command::SelectBeginLine);
SEL_TO_COMMAND(moveToEndOfDocument:, Command::MoveBottom); SEL_TO_COMMAND(moveToEndOfDocument:, Command::MoveBottom);
SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, Command::SelectBottom); SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, Command::SelectBottom);
SEL_TO_COMMAND(moveToEndOfLine:, Command::EndLine); SEL_TO_COMMAND(moveToEndOfLine:, Command::EndLine);
SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, Command::SelectEndLine); SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, Command::SelectEndLine);
SEL_TO_COMMAND(moveToEndOfParagraph:, Command::EndLine); SEL_TO_COMMAND(moveToEndOfParagraph:, Command::EndLine);
SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:, Command::SelectEndLine); SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:,
Command::SelectEndLine);
SEL_TO_COMMAND(moveToLeftEndOfLine:, Command::BeginLine); SEL_TO_COMMAND(moveToLeftEndOfLine:, Command::BeginLine);
SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:, Command::SelectBeginLine); SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:,
Command::SelectBeginLine);
SEL_TO_COMMAND(moveToRightEndOfLine:, Command::EndLine); SEL_TO_COMMAND(moveToRightEndOfLine:, Command::EndLine);
SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:, Command::SelectEndLine); SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:,
Command::SelectEndLine);
if (aType == NativeKeyBindingsType::SingleLineEditor) { if (aType == NativeKeyBindingsType::SingleLineEditor) {
SEL_TO_COMMAND(moveUp:, Command::BeginLine); SEL_TO_COMMAND(moveUp:, Command::BeginLine);
} else { } else {
@ -146,7 +159,8 @@ void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
} }
SEL_TO_COMMAND(moveUpAndModifySelection:, Command::SelectLinePrevious); SEL_TO_COMMAND(moveUpAndModifySelection:, Command::SelectLinePrevious);
SEL_TO_COMMAND(moveWordBackward:, Command::WordPrevious); SEL_TO_COMMAND(moveWordBackward:, Command::WordPrevious);
SEL_TO_COMMAND(moveWordBackwardAndModifySelection:, Command::SelectWordPrevious); SEL_TO_COMMAND(moveWordBackwardAndModifySelection:,
Command::SelectWordPrevious);
SEL_TO_COMMAND(moveWordForward:, Command::WordNext); SEL_TO_COMMAND(moveWordForward:, Command::WordNext);
SEL_TO_COMMAND(moveWordForwardAndModifySelection:, Command::SelectWordNext); SEL_TO_COMMAND(moveWordForwardAndModifySelection:, Command::SelectWordNext);
SEL_TO_COMMAND(moveWordLeft:, Command::WordPrevious); SEL_TO_COMMAND(moveWordLeft:, Command::WordPrevious);
@ -191,7 +205,8 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
MOZ_ASSERT(!aEvent.mFlags.mIsSynthesizedForTests); MOZ_ASSERT(!aEvent.mFlags.mIsSynthesizedForTests);
MOZ_ASSERT(aCommands.IsEmpty()); MOZ_ASSERT(aCommands.IsEmpty());
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info, ("%p NativeKeyBindings::GetEditCommands", this)); MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
("%p NativeKeyBindings::GetEditCommands", this));
// Recover the current event, which should always be the key down we are // Recover the current event, which should always be the key down we are
// responding to. // responding to.
@ -200,7 +215,8 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
if (!cocoaEvent || [cocoaEvent type] != NSEventTypeKeyDown) { if (!cocoaEvent || [cocoaEvent type] != NSEventTypeKeyDown) {
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info, MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
("%p NativeKeyBindings::GetEditCommands, no Cocoa key down event", this)); ("%p NativeKeyBindings::GetEditCommands, no Cocoa key down event",
this));
return; return;
} }
@ -210,7 +226,8 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
NSEvent* originalEvent = cocoaEvent; NSEvent* originalEvent = cocoaEvent;
// TODO: Use KeyNameIndex rather than legacy keyCode. // TODO: Use KeyNameIndex rather than legacy keyCode.
uint32_t remappedGeckoKeyCode = aEvent.GetRemappedKeyCode(aWritingMode.ref()); uint32_t remappedGeckoKeyCode =
aEvent.GetRemappedKeyCode(aWritingMode.ref());
uint32_t remappedCocoaKeyCode = 0; uint32_t remappedCocoaKeyCode = 0;
switch (remappedGeckoKeyCode) { switch (remappedGeckoKeyCode) {
case NS_VK_UP: case NS_VK_UP:
@ -229,8 +246,10 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
MOZ_ASSERT_UNREACHABLE("Add a case for the new remapped key"); MOZ_ASSERT_UNREACHABLE("Add a case for the new remapped key");
return; return;
} }
unichar ch = nsCocoaUtils::ConvertGeckoKeyCodeToMacCharCode(remappedGeckoKeyCode); unichar ch =
NSString* chars = [[[NSString alloc] initWithCharacters:&ch length:1] autorelease]; nsCocoaUtils::ConvertGeckoKeyCodeToMacCharCode(remappedGeckoKeyCode);
NSString* chars = [[[NSString alloc] initWithCharacters:&ch
length:1] autorelease];
cocoaEvent = [NSEvent keyEventWithType:[originalEvent type] cocoaEvent = [NSEvent keyEventWithType:[originalEvent type]
location:[originalEvent locationInWindow] location:[originalEvent locationInWindow]
modifierFlags:[originalEvent modifierFlags] modifierFlags:[originalEvent modifierFlags]
@ -272,11 +291,12 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
LogEditCommands(aCommands, "NativeKeyBindings::GetEditCommands"); LogEditCommands(aCommands, "NativeKeyBindings::GetEditCommands");
} }
void NativeKeyBindings::AppendEditCommandsForSelector(objc_selector* aSelector, void NativeKeyBindings::AppendEditCommandsForSelector(
nsTArray<CommandInt>& aCommands) const { objc_selector* aSelector, nsTArray<CommandInt>& aCommands) const {
// Try to find a simple mapping in the hashtable // Try to find a simple mapping in the hashtable
Command geckoCommand = Command::DoNothing; Command geckoCommand = Command::DoNothing;
if (mSelectorToCommand.Get(aSelector, &geckoCommand) && geckoCommand != Command::DoNothing) { if (mSelectorToCommand.Get(aSelector, &geckoCommand) &&
geckoCommand != Command::DoNothing) {
aCommands.AppendElement(static_cast<CommandInt>(geckoCommand)); aCommands.AppendElement(static_cast<CommandInt>(geckoCommand));
} else if (aSelector == ToObjcSelectorPtr(@selector(selectLine:))) { } else if (aSelector == ToObjcSelectorPtr(@selector(selectLine:))) {
// This is functional, but Cocoa's version is direction-less in that // This is functional, but Cocoa's version is direction-less in that
@ -300,7 +320,8 @@ void NativeKeyBindings::LogEditCommands(const nsTArray<CommandInt>& aCommands,
} }
if (aCommands.IsEmpty()) { if (aCommands.IsEmpty()) {
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info, ("%p %s, no edit commands", this, aDescription)); MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
("%p %s, no edit commands", this, aDescription));
return; return;
} }
@ -313,10 +334,9 @@ void NativeKeyBindings::LogEditCommands(const nsTArray<CommandInt>& aCommands,
} }
// static // static
void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, void NativeKeyBindings::GetEditCommandsForTests(
const WidgetKeyboardEvent& aEvent, NativeKeyBindingsType aType, const WidgetKeyboardEvent& aEvent,
const Maybe<WritingMode>& aWritingMode, const Maybe<WritingMode>& aWritingMode, nsTArray<CommandInt>& aCommands) {
nsTArray<CommandInt>& aCommands) {
MOZ_DIAGNOSTIC_ASSERT(aEvent.IsTrusted()); MOZ_DIAGNOSTIC_ASSERT(aEvent.IsTrusted());
// The following mapping is checked on Big Sur. Some of them are defined in: // The following mapping is checked on Big Sur. Some of them are defined in:
@ -325,8 +345,9 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
if (NS_WARN_IF(!instance)) { if (NS_WARN_IF(!instance)) {
return; return;
} }
switch (aWritingMode.isSome() ? aEvent.GetRemappedKeyNameIndex(aWritingMode.ref()) switch (aWritingMode.isSome()
: aEvent.mKeyNameIndex) { ? aEvent.GetRemappedKeyNameIndex(aWritingMode.ref())
: aEvent.mKeyNameIndex) {
case KEY_NAME_INDEX_USE_STRING: case KEY_NAME_INDEX_USE_STRING:
if (!aEvent.IsControl() || aEvent.IsAlt() || aEvent.IsMeta()) { if (!aEvent.IsControl() || aEvent.IsAlt() || aEvent.IsMeta()) {
break; break;
@ -337,21 +358,23 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() !aEvent.IsShift()
? ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:)) ? ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:))
: ToObjcSelectorPtr(@selector(moveToBeginningOfParagraphAndModifySelection:)), : ToObjcSelectorPtr(@selector(
moveToBeginningOfParagraphAndModifySelection:)),
aCommands); aCommands);
break; break;
case 'b': case 'b':
case 'B': case 'B':
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveBackward:)) !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveBackward:))
: ToObjcSelectorPtr(@selector(moveBackwardAndModifySelection:)), : ToObjcSelectorPtr(@selector(
moveBackwardAndModifySelection:)),
aCommands); aCommands);
break; break;
case 'd': case 'd':
case 'D': case 'D':
if (!aEvent.IsShift()) { if (!aEvent.IsShift()) {
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteForward:)), instance->AppendEditCommandsForSelector(
aCommands); ToObjcSelectorPtr(@selector(deleteForward:)), aCommands);
} }
break; break;
case 'e': case 'e':
@ -359,42 +382,47 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() !aEvent.IsShift()
? ToObjcSelectorPtr(@selector(moveToEndOfParagraph:)) ? ToObjcSelectorPtr(@selector(moveToEndOfParagraph:))
: ToObjcSelectorPtr(@selector(moveToEndOfParagraphAndModifySelection:)), : ToObjcSelectorPtr(
@selector(moveToEndOfParagraphAndModifySelection:)),
aCommands); aCommands);
break; break;
case 'f': case 'f':
case 'F': case 'F':
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveForward:)) !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveForward:))
: ToObjcSelectorPtr(@selector(moveForwardAndModifySelection:)), : ToObjcSelectorPtr(@selector(
moveForwardAndModifySelection:)),
aCommands); aCommands);
break; break;
case 'h': case 'h':
case 'H': case 'H':
if (!aEvent.IsShift()) { if (!aEvent.IsShift()) {
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteBackward:)), instance->AppendEditCommandsForSelector(
aCommands); ToObjcSelectorPtr(@selector(deleteBackward:)), aCommands);
} }
break; break;
case 'k': case 'k':
case 'K': case 'K':
if (!aEvent.IsShift()) { if (!aEvent.IsShift()) {
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
ToObjcSelectorPtr(@selector(deleteToEndOfParagraph:)), aCommands); ToObjcSelectorPtr(@selector(deleteToEndOfParagraph:)),
aCommands);
} }
break; break;
case 'n': case 'n':
case 'N': case 'N':
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveDown:)) !aEvent.IsShift()
: ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)), ? ToObjcSelectorPtr(@selector(moveDown:))
: ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
aCommands); aCommands);
break; break;
case 'p': case 'p':
case 'P': case 'P':
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveUp:)) !aEvent.IsShift()
: ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)), ? ToObjcSelectorPtr(@selector(moveUp:))
: ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
aCommands); aCommands);
break; break;
default: default:
@ -413,21 +441,22 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
} }
if (aEvent.IsAlt()) { if (aEvent.IsAlt()) {
// Shift and Control are ignored. // Shift and Control are ignored.
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteWordBackward:)), instance->AppendEditCommandsForSelector(
aCommands); ToObjcSelectorPtr(@selector(deleteWordBackward:)), aCommands);
break; break;
} }
if (aEvent.IsControl()) { if (aEvent.IsControl()) {
if (aEvent.IsShift()) { if (aEvent.IsShift()) {
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
ToObjcSelectorPtr(@selector(deleteBackwardByDecomposingPreviousCharacter:)), ToObjcSelectorPtr(
@selector(deleteBackwardByDecomposingPreviousCharacter:)),
aCommands); aCommands);
} }
break; break;
} }
// Shift is ignored. // Shift is ignored.
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteBackward:)), instance->AppendEditCommandsForSelector(
aCommands); ToObjcSelectorPtr(@selector(deleteBackward:)), aCommands);
break; break;
case KEY_NAME_INDEX_Delete: case KEY_NAME_INDEX_Delete:
if (aEvent.IsControl() || aEvent.IsMeta()) { if (aEvent.IsControl() || aEvent.IsMeta()) {
@ -435,13 +464,13 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
} }
if (aEvent.IsAlt()) { if (aEvent.IsAlt()) {
// Shift is ignored. // Shift is ignored.
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteWordForward:)), instance->AppendEditCommandsForSelector(
aCommands); ToObjcSelectorPtr(@selector(deleteWordForward:)), aCommands);
break; break;
} }
// Shift is ignored. // Shift is ignored.
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteForward:)), instance->AppendEditCommandsForSelector(
aCommands); ToObjcSelectorPtr(@selector(deleteForward:)), aCommands);
break; break;
case KEY_NAME_INDEX_PageDown: case KEY_NAME_INDEX_PageDown:
if (aEvent.IsControl() || aEvent.IsMeta()) { if (aEvent.IsControl() || aEvent.IsMeta()) {
@ -449,12 +478,14 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
} }
if (aEvent.IsAlt()) { if (aEvent.IsAlt()) {
// Shift is ignored. // Shift is ignored.
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(pageDown:)), aCommands); instance->AppendEditCommandsForSelector(
ToObjcSelectorPtr(@selector(pageDown:)), aCommands);
break; break;
} }
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(scrollPageDown:)) !aEvent.IsShift()
: ToObjcSelectorPtr(@selector(pageDownAndModifySelection:)), ? ToObjcSelectorPtr(@selector(scrollPageDown:))
: ToObjcSelectorPtr(@selector(pageDownAndModifySelection:)),
aCommands); aCommands);
break; break;
case KEY_NAME_INDEX_PageUp: case KEY_NAME_INDEX_PageUp:
@ -463,12 +494,14 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
} }
if (aEvent.IsAlt()) { if (aEvent.IsAlt()) {
// Shift is ignored. // Shift is ignored.
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(pageUp:)), aCommands); instance->AppendEditCommandsForSelector(
ToObjcSelectorPtr(@selector(pageUp:)), aCommands);
break; break;
} }
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(scrollPageUp:)) !aEvent.IsShift()
: ToObjcSelectorPtr(@selector(pageUpAndModifySelection:)), ? ToObjcSelectorPtr(@selector(scrollPageUp:))
: ToObjcSelectorPtr(@selector(pageUpAndModifySelection:)),
aCommands); aCommands);
break; break;
case KEY_NAME_INDEX_Home: case KEY_NAME_INDEX_Home:
@ -478,7 +511,8 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() !aEvent.IsShift()
? ToObjcSelectorPtr(@selector(scrollToBeginningOfDocument:)) ? ToObjcSelectorPtr(@selector(scrollToBeginningOfDocument:))
: ToObjcSelectorPtr(@selector(moveToBeginningOfDocumentAndModifySelection:)), : ToObjcSelectorPtr(
@selector(moveToBeginningOfDocumentAndModifySelection:)),
aCommands); aCommands);
break; break;
case KEY_NAME_INDEX_End: case KEY_NAME_INDEX_End:
@ -486,8 +520,10 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
break; break;
} }
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(scrollToEndOfDocument:)) !aEvent.IsShift()
: ToObjcSelectorPtr(@selector(moveToEndOfDocumentAndModifySelection:)), ? ToObjcSelectorPtr(@selector(scrollToEndOfDocument:))
: ToObjcSelectorPtr(@selector
(moveToEndOfDocumentAndModifySelection:)),
aCommands); aCommands);
break; break;
case KEY_NAME_INDEX_ArrowLeft: case KEY_NAME_INDEX_ArrowLeft:
@ -498,7 +534,8 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() !aEvent.IsShift()
? ToObjcSelectorPtr(@selector(moveToLeftEndOfLine:)) ? ToObjcSelectorPtr(@selector(moveToLeftEndOfLine:))
: ToObjcSelectorPtr(@selector(moveToLeftEndOfLineAndModifySelection:)), : ToObjcSelectorPtr(@selector
(moveToLeftEndOfLineAndModifySelection:)),
aCommands); aCommands);
break; break;
} }
@ -506,8 +543,9 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
break; break;
} }
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveLeft:)) !aEvent.IsShift()
: ToObjcSelectorPtr(@selector(moveLeftAndModifySelection:)), ? ToObjcSelectorPtr(@selector(moveLeft:))
: ToObjcSelectorPtr(@selector(moveLeftAndModifySelection:)),
aCommands); aCommands);
break; break;
case KEY_NAME_INDEX_ArrowRight: case KEY_NAME_INDEX_ArrowRight:
@ -518,7 +556,8 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() !aEvent.IsShift()
? ToObjcSelectorPtr(@selector(moveToRightEndOfLine:)) ? ToObjcSelectorPtr(@selector(moveToRightEndOfLine:))
: ToObjcSelectorPtr(@selector(moveToRightEndOfLineAndModifySelection:)), : ToObjcSelectorPtr(@selector
(moveToRightEndOfLineAndModifySelection:)),
aCommands); aCommands);
break; break;
} }
@ -526,8 +565,9 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
break; break;
} }
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveRight:)) !aEvent.IsShift()
: ToObjcSelectorPtr(@selector(moveRightAndModifySelection:)), ? ToObjcSelectorPtr(@selector(moveRight:))
: ToObjcSelectorPtr(@selector(moveRightAndModifySelection:)),
aCommands); aCommands);
break; break;
case KEY_NAME_INDEX_ArrowUp: case KEY_NAME_INDEX_ArrowUp:
@ -541,25 +581,30 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() !aEvent.IsShift()
? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:)) ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:))
: ToObjcSelectorPtr(@selector(moveToBegginingOfDocumentAndModifySelection:)), : ToObjcSelectorPtr(
@selector(moveToBegginingOfDocumentAndModifySelection:)),
aCommands); aCommands);
break; break;
} }
if (aEvent.IsAlt()) { if (aEvent.IsAlt()) {
if (!aEvent.IsShift()) { if (!aEvent.IsShift()) {
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(moveBackward:)),
aCommands);
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:)), aCommands); ToObjcSelectorPtr(@selector(moveBackward:)), aCommands);
instance->AppendEditCommandsForSelector(
ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:)),
aCommands);
break; break;
} }
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
ToObjcSelectorPtr(@selector(moveParagraphBackwardAndModifySelection:)), aCommands); ToObjcSelectorPtr(@selector
(moveParagraphBackwardAndModifySelection:)),
aCommands);
break; break;
} }
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveUp:)) !aEvent.IsShift()
: ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)), ? ToObjcSelectorPtr(@selector(moveUp:))
: ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
aCommands); aCommands);
break; break;
case KEY_NAME_INDEX_ArrowDown: case KEY_NAME_INDEX_ArrowDown:
@ -573,32 +618,37 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() !aEvent.IsShift()
? ToObjcSelectorPtr(@selector(moveToEndOfDocument:)) ? ToObjcSelectorPtr(@selector(moveToEndOfDocument:))
: ToObjcSelectorPtr(@selector(moveToEndOfDocumentAndModifySelection:)), : ToObjcSelectorPtr(@selector
(moveToEndOfDocumentAndModifySelection:)),
aCommands); aCommands);
break; break;
} }
if (aEvent.IsAlt()) { if (aEvent.IsAlt()) {
if (!aEvent.IsShift()) { if (!aEvent.IsShift()) {
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(moveForward:)), instance->AppendEditCommandsForSelector(
aCommands); ToObjcSelectorPtr(@selector(moveForward:)), aCommands);
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
ToObjcSelectorPtr(@selector(moveToEndOfParagraph:)), aCommands); ToObjcSelectorPtr(@selector(moveToEndOfParagraph:)), aCommands);
break; break;
} }
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
ToObjcSelectorPtr(@selector(moveParagraphForwardAndModifySelection:)), aCommands); ToObjcSelectorPtr(@selector
(moveParagraphForwardAndModifySelection:)),
aCommands);
break; break;
} }
instance->AppendEditCommandsForSelector( instance->AppendEditCommandsForSelector(
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveDown:)) !aEvent.IsShift()
: ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)), ? ToObjcSelectorPtr(@selector(moveDown:))
: ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
aCommands); aCommands);
break; break;
default: default:
break; break;
} }
instance->LogEditCommands(aCommands, "NativeKeyBindings::GetEditCommandsForTests"); instance->LogEditCommands(aCommands,
"NativeKeyBindings::GetEditCommandsForTests");
} }
} // namespace widget } // namespace widget

View file

@ -37,7 +37,8 @@ namespace widget {
NativeMenuMac::NativeMenuMac(dom::Element* aElement) NativeMenuMac::NativeMenuMac(dom::Element* aElement)
: mElement(aElement), mContainerStatusBarItem(nil) { : mElement(aElement), mContainerStatusBarItem(nil) {
MOZ_RELEASE_ASSERT(aElement->IsAnyOfXULElements(nsGkAtoms::menu, nsGkAtoms::menupopup)); MOZ_RELEASE_ASSERT(
aElement->IsAnyOfXULElements(nsGkAtoms::menu, nsGkAtoms::menupopup));
mMenuGroupOwner = new nsMenuGroupOwnerX(aElement, nullptr); mMenuGroupOwner = new nsMenuGroupOwnerX(aElement, nullptr);
mMenu = MakeRefPtr<nsMenuX>(nullptr, mMenuGroupOwner, aElement); mMenu = MakeRefPtr<nsMenuX>(nullptr, mMenuGroupOwner, aElement);
mMenu->SetObserver(this); mMenu->SetObserver(this);
@ -78,9 +79,11 @@ bool NativeMenuMac::ActivateNativeMenuItemAt(const nsAString& aIndexString) {
nsMenuUtilsX::CheckNativeMenuConsistency(menu); nsMenuUtilsX::CheckNativeMenuConsistency(menu);
NSString* locationString = NSString* locationString =
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(aIndexString.BeginReading()) [NSString stringWithCharacters:reinterpret_cast<const unichar*>(
aIndexString.BeginReading())
length:aIndexString.Length()]; length:aIndexString.Length()];
NSMenuItem* item = nsMenuUtilsX::NativeMenuItemWithLocation(menu, locationString, false); NSMenuItem* item =
nsMenuUtilsX::NativeMenuItemWithLocation(menu, locationString, false);
// We can't perform an action on an item with a submenu, that will raise // We can't perform an action on an item with a submenu, that will raise
// an obj-c exception. // an obj-c exception.
@ -106,9 +109,11 @@ void NativeMenuMac::ForceUpdateNativeMenuAt(const nsAString& aIndexString) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
NSString* locationString = NSString* locationString =
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(aIndexString.BeginReading()) [NSString stringWithCharacters:reinterpret_cast<const unichar*>(
aIndexString.BeginReading())
length:aIndexString.Length()]; length:aIndexString.Length()];
NSArray<NSString*>* indexes = [locationString componentsSeparatedByString:@"|"]; NSArray<NSString*>* indexes =
[locationString componentsSeparatedByString:@"|"];
RefPtr<nsMenuX> currentMenu = mMenu.get(); RefPtr<nsMenuX> currentMenu = mMenu.get();
// now find the correct submenu // now find the correct submenu
@ -124,7 +129,9 @@ void NativeMenuMac::ForceUpdateNativeMenuAt(const nsAString& aIndexString) {
} }
RefPtr<nsIContent> content = targetMenu->match( RefPtr<nsIContent> content = targetMenu->match(
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); }, [](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); }); [](const RefPtr<nsMenuItemX>& aMenuItem) {
return aMenuItem->Content();
});
if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(content)) { if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(content)) {
visible++; visible++;
if (targetMenu->is<RefPtr<nsMenuX>>() && visible == (targetIndex + 1)) { if (targetMenu->is<RefPtr<nsMenuX>>() && visible == (targetIndex + 1)) {
@ -175,8 +182,8 @@ void NativeMenuMac::OnMenuWillOpen(dom::Element* aPopupElement) {
return; return;
} }
// Our caller isn't keeping us alive, so make sure we stay alive throughout this function in case // Our caller isn't keeping us alive, so make sure we stay alive throughout
// one of the observer notifications destroys us. // this function in case one of the observer notifications destroys us.
RefPtr<NativeMenuMac> kungFuDeathGrip(this); RefPtr<NativeMenuMac> kungFuDeathGrip(this);
for (NativeMenu::Observer* observer : mObservers.Clone()) { for (NativeMenu::Observer* observer : mObservers.Clone()) {
@ -185,8 +192,8 @@ void NativeMenuMac::OnMenuWillOpen(dom::Element* aPopupElement) {
} }
void NativeMenuMac::OnMenuDidOpen(dom::Element* aPopupElement) { void NativeMenuMac::OnMenuDidOpen(dom::Element* aPopupElement) {
// Our caller isn't keeping us alive, so make sure we stay alive throughout this function in case // Our caller isn't keeping us alive, so make sure we stay alive throughout
// one of the observer notifications destroys us. // this function in case one of the observer notifications destroys us.
RefPtr<NativeMenuMac> kungFuDeathGrip(this); RefPtr<NativeMenuMac> kungFuDeathGrip(this);
for (NativeMenu::Observer* observer : mObservers.Clone()) { for (NativeMenu::Observer* observer : mObservers.Clone()) {
@ -200,8 +207,8 @@ void NativeMenuMac::OnMenuDidOpen(dom::Element* aPopupElement) {
void NativeMenuMac::OnMenuWillActivateItem(dom::Element* aPopupElement, void NativeMenuMac::OnMenuWillActivateItem(dom::Element* aPopupElement,
dom::Element* aMenuItemElement) { dom::Element* aMenuItemElement) {
// Our caller isn't keeping us alive, so make sure we stay alive throughout this function in case // Our caller isn't keeping us alive, so make sure we stay alive throughout
// one of the observer notifications destroys us. // this function in case one of the observer notifications destroys us.
RefPtr<NativeMenuMac> kungFuDeathGrip(this); RefPtr<NativeMenuMac> kungFuDeathGrip(this);
for (NativeMenu::Observer* observer : mObservers.Clone()) { for (NativeMenu::Observer* observer : mObservers.Clone()) {
@ -210,8 +217,8 @@ void NativeMenuMac::OnMenuWillActivateItem(dom::Element* aPopupElement,
} }
void NativeMenuMac::OnMenuClosed(dom::Element* aPopupElement) { void NativeMenuMac::OnMenuClosed(dom::Element* aPopupElement) {
// Our caller isn't keeping us alive, so make sure we stay alive throughout this function in case // Our caller isn't keeping us alive, so make sure we stay alive throughout
// one of the observer notifications destroys us. // this function in case one of the observer notifications destroys us.
RefPtr<NativeMenuMac> kungFuDeathGrip(this); RefPtr<NativeMenuMac> kungFuDeathGrip(this);
for (NativeMenu::Observer* observer : mObservers.Clone()) { for (NativeMenu::Observer* observer : mObservers.Clone()) {
@ -236,7 +243,8 @@ static NSAppearance* NativeAppearanceForContent(nsIContent* aContent) {
return NSAppearanceForColorScheme(LookAndFeel::ColorSchemeForFrame(f)); return NSAppearanceForColorScheme(LookAndFeel::ColorSchemeForFrame(f));
} }
void NativeMenuMac::ShowAsContextMenu(nsIFrame* aClickedFrame, const CSSIntPoint& aPosition, void NativeMenuMac::ShowAsContextMenu(nsIFrame* aClickedFrame,
const CSSIntPoint& aPosition,
bool aIsContextMenu) { bool aIsContextMenu) {
nsPresContext* pc = aClickedFrame->PresContext(); nsPresContext* pc = aClickedFrame->PresContext();
auto cssToDesktopScale = auto cssToDesktopScale =
@ -250,24 +258,29 @@ void NativeMenuMac::ShowAsContextMenu(nsIFrame* aClickedFrame, const CSSIntPoint
NSAppearance* appearance = NativeAppearanceForContent(mMenu->Content()); NSAppearance* appearance = NativeAppearanceForContent(mMenu->Content());
NSPoint locationOnScreen = nsCocoaUtils::GeckoPointToCocoaPoint(desktopPoint); NSPoint locationOnScreen = nsCocoaUtils::GeckoPointToCocoaPoint(desktopPoint);
// Let the MOZMenuOpeningCoordinator do the actual opening, so that this ShowAsContextMenu call // Let the MOZMenuOpeningCoordinator do the actual opening, so that this
// does not spawn a nested event loop, which would be surprising to our callers. // ShowAsContextMenu call does not spawn a nested event loop, which would be
mOpeningHandle = [MOZMenuOpeningCoordinator.sharedInstance asynchronouslyOpenMenu:menu // surprising to our callers.
atScreenPosition:locationOnScreen mOpeningHandle = [MOZMenuOpeningCoordinator.sharedInstance
forView:view asynchronouslyOpenMenu:menu
withAppearance:appearance atScreenPosition:locationOnScreen
asContextMenu:aIsContextMenu]; forView:view
withAppearance:appearance
asContextMenu:aIsContextMenu];
} }
bool NativeMenuMac::Close() { bool NativeMenuMac::Close() {
if (mOpeningHandle) { if (mOpeningHandle) {
// In case the menu was trying to open, but this Close() call interrupted it, cancel opening. // In case the menu was trying to open, but this Close() call interrupted
[MOZMenuOpeningCoordinator.sharedInstance cancelAsynchronousOpening:mOpeningHandle]; // it, cancel opening.
[MOZMenuOpeningCoordinator.sharedInstance
cancelAsynchronousOpening:mOpeningHandle];
} }
return mMenu->Close(); return mMenu->Close();
} }
RefPtr<nsMenuX> NativeMenuMac::GetOpenMenuContainingElement(dom::Element* aElement) { RefPtr<nsMenuX> NativeMenuMac::GetOpenMenuContainingElement(
dom::Element* aElement) {
nsTArray<RefPtr<dom::Element>> submenuChain; nsTArray<RefPtr<dom::Element>> submenuChain;
RefPtr<dom::Element> currentElement = aElement->GetParentElement(); RefPtr<dom::Element> currentElement = aElement->GetParentElement();
while (currentElement && currentElement != mElement) { while (currentElement && currentElement != mElement) {
@ -281,7 +294,8 @@ RefPtr<nsMenuX> NativeMenuMac::GetOpenMenuContainingElement(dom::Element* aEleme
return nullptr; return nullptr;
} }
// Traverse submenuChain from shallow to deep, to find the nsMenuX that contains aElement. // Traverse submenuChain from shallow to deep, to find the nsMenuX that
// contains aElement.
submenuChain.Reverse(); submenuChain.Reverse();
RefPtr<nsMenuX> menu = mMenu; RefPtr<nsMenuX> menu = mMenu;
for (const auto& submenu : submenuChain) { for (const auto& submenu : submenuChain) {
@ -321,7 +335,8 @@ static NSEventModifierFlags ConvertModifierFlags(Modifiers aModifiers) {
return flags; return flags;
} }
void NativeMenuMac::ActivateItem(dom::Element* aItemElement, Modifiers aModifiers, int16_t aButton, void NativeMenuMac::ActivateItem(dom::Element* aItemElement,
Modifiers aModifiers, int16_t aButton,
ErrorResult& aRv) { ErrorResult& aRv) {
RefPtr<nsMenuX> menu = GetOpenMenuContainingElement(aItemElement); RefPtr<nsMenuX> menu = GetOpenMenuContainingElement(aItemElement);
if (!menu) { if (!menu) {
@ -343,27 +358,29 @@ void NativeMenuMac::ActivateItem(dom::Element* aItemElement, Modifiers aModifier
NSMenuItem* nativeItem = [item->NativeNSMenuItem() retain]; NSMenuItem* nativeItem = [item->NativeNSMenuItem() retain];
// First, initiate the closing of the NSMenu. // First, initiate the closing of the NSMenu.
// This synchronously calls the menu delegate's menuDidClose handler. So menuDidClose is // This synchronously calls the menu delegate's menuDidClose handler. So
// what runs first; this matches the order of events for user-initiated menu item activation. // menuDidClose is what runs first; this matches the order of events for
// This call doesn't immediately hide the menu; the menu only hides once the stack unwinds // user-initiated menu item activation. This call doesn't immediately hide the
// from NSMenu's nested "tracking" event loop. // menu; the menu only hides once the stack unwinds from NSMenu's nested
// "tracking" event loop.
[mMenu->NativeNSMenu() cancelTrackingWithoutAnimation]; [mMenu->NativeNSMenu() cancelTrackingWithoutAnimation];
// Next, call OnWillActivateItem. This also matches the order of calls that happen when a user // Next, call OnWillActivateItem. This also matches the order of calls that
// activates a menu item in the real world: -[MenuDelegate menu:willActivateItem:] runs after // happen when a user activates a menu item in the real world: -[MenuDelegate
// menuDidClose. // menu:willActivateItem:] runs after menuDidClose.
menu->OnWillActivateItem(nativeItem); menu->OnWillActivateItem(nativeItem);
// Finally, call ActivateItemAfterClosing. This also mimics the order in the real world: // Finally, call ActivateItemAfterClosing. This also mimics the order in the
// menuItemHit is called after menu:willActivateItem:. // real world: menuItemHit is called after menu:willActivateItem:.
menu->ActivateItemAfterClosing(std::move(item), ConvertModifierFlags(aModifiers), aButton); menu->ActivateItemAfterClosing(std::move(item),
ConvertModifierFlags(aModifiers), aButton);
// Tell our native event loop that it should not process any more work before // Tell our native event loop that it should not process any more work before
// unwinding the stack, so that we can get out of the menu's nested event loop // unwinding the stack, so that we can get out of the menu's nested event loop
// as fast as possible. This was needed to fix spurious failures in tests, where // as fast as possible. This was needed to fix spurious failures in tests,
// a call to cancelTrackingWithoutAnimation was ignored if more native events were // where a call to cancelTrackingWithoutAnimation was ignored if more native
// processed before the event loop was exited. As a result, the menu stayed open // events were processed before the event loop was exited. As a result, the
// forever and the test never finished. // menu stayed open forever and the test never finished.
MOZMenuOpeningCoordinator.needToUnwindForMenuClosing = YES; MOZMenuOpeningCoordinator.needToUnwindForMenuClosing = YES;
[nativeItem release]; [nativeItem release];

View file

@ -14,14 +14,19 @@
namespace mozilla::widget { namespace mozilla::widget {
void NativeMenuSupport::CreateNativeMenuBar(nsIWidget* aParent, dom::Element* aMenuBarElement) { void NativeMenuSupport::CreateNativeMenuBar(nsIWidget* aParent,
MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Attempting to create native menu bar on wrong thread!"); dom::Element* aMenuBarElement) {
MOZ_RELEASE_ASSERT(NS_IsMainThread(),
"Attempting to create native menu bar on wrong thread!");
// Create the menubar and give it to the parent window. The parent takes ownership. // Create the menubar and give it to the parent window. The parent takes
static_cast<nsCocoaWindow*>(aParent)->SetMenuBar(MakeRefPtr<nsMenuBarX>(aMenuBarElement)); // ownership.
static_cast<nsCocoaWindow*>(aParent)->SetMenuBar(
MakeRefPtr<nsMenuBarX>(aMenuBarElement));
} }
already_AddRefed<NativeMenu> NativeMenuSupport::CreateNativeContextMenu(dom::Element* aPopup) { already_AddRefed<NativeMenu> NativeMenuSupport::CreateNativeContextMenu(
dom::Element* aPopup) {
return MakeAndAddRef<NativeMenuMac>(aPopup); return MakeAndAddRef<NativeMenuMac>(aPopup);
} }

View file

@ -55,7 +55,8 @@ using namespace mozilla;
- (void)_removeDisplayedNotification:(id<FakeNSUserNotification>)notification; - (void)_removeDisplayedNotification:(id<FakeNSUserNotification>)notification;
@end @end
@interface mozNotificationCenterDelegate : NSObject <NSUserNotificationCenterDelegate> { @interface mozNotificationCenterDelegate
: NSObject <NSUserNotificationCenterDelegate> {
OSXNotificationCenter* mOSXNC; OSXNotificationCenter* mOSXNC;
} }
- (id)initWithOSXNC:(OSXNotificationCenter*)osxnc; - (id)initWithOSXNC:(OSXNotificationCenter*)osxnc;
@ -78,11 +79,12 @@ using namespace mozilla;
didActivateNotification:(id<FakeNSUserNotification>)notification { didActivateNotification:(id<FakeNSUserNotification>)notification {
unsigned long long additionalActionIndex = ULLONG_MAX; unsigned long long additionalActionIndex = ULLONG_MAX;
if ([notification respondsToSelector:@selector(_alternateActionIndex)]) { if ([notification respondsToSelector:@selector(_alternateActionIndex)]) {
NSNumber* alternateActionIndex = [(NSObject*)notification valueForKey:@"_alternateActionIndex"]; NSNumber* alternateActionIndex =
[(NSObject*)notification valueForKey:@"_alternateActionIndex"];
additionalActionIndex = [alternateActionIndex unsignedLongLongValue]; additionalActionIndex = [alternateActionIndex unsignedLongLongValue];
} }
mOSXNC->OnActivate([[notification userInfo] valueForKey:@"name"], notification.activationType, mOSXNC->OnActivate([[notification userInfo] valueForKey:@"name"],
additionalActionIndex); notification.activationType, additionalActionIndex);
} }
- (BOOL)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center - (BOOL)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center
@ -100,7 +102,8 @@ using namespace mozilla;
} }
} }
// This is an undocumented method that we need to be notified if a user clicks the close button. // This is an undocumented method that we need to be notified if a user clicks
// the close button.
- (void)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center - (void)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center
didDismissAlert:(id<FakeNSUserNotification>)notification { didDismissAlert:(id<FakeNSUserNotification>)notification {
NSString* name = [[notification userInfo] valueForKey:@"name"]; NSString* name = [[notification userInfo] valueForKey:@"name"];
@ -122,7 +125,8 @@ class OSXNotificationInfo final : public nsISupports {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
OSXNotificationInfo(NSString* name, nsIObserver* observer, const nsAString& alertCookie); OSXNotificationInfo(NSString* name, nsIObserver* observer,
const nsAString& alertCookie);
NSString* mName; NSString* mName;
nsCOMPtr<nsIObserver> mObserver; nsCOMPtr<nsIObserver> mObserver;
@ -183,50 +187,56 @@ OSXNotificationCenter::~OSXNotificationCenter() {
NS_OBJC_END_TRY_IGNORE_BLOCK; NS_OBJC_END_TRY_IGNORE_BLOCK;
} }
NS_IMPL_ISUPPORTS(OSXNotificationCenter, nsIAlertsService, nsIAlertsIconData, nsIAlertsDoNotDisturb, NS_IMPL_ISUPPORTS(OSXNotificationCenter, nsIAlertsService, nsIAlertsIconData,
nsIAlertNotificationImageListener) nsIAlertsDoNotDisturb, nsIAlertNotificationImageListener)
nsresult OSXNotificationCenter::Init() { nsresult OSXNotificationCenter::Init() {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
return (!!NSClassFromString(@"NSUserNotification")) ? NS_OK : NS_ERROR_FAILURE; return (!!NSClassFromString(@"NSUserNotification")) ? NS_OK
: NS_ERROR_FAILURE;
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
} }
NS_IMETHODIMP NS_IMETHODIMP
OSXNotificationCenter::ShowAlertNotification( OSXNotificationCenter::ShowAlertNotification(
const nsAString& aImageUrl, const nsAString& aAlertTitle, const nsAString& aAlertText, const nsAString& aImageUrl, const nsAString& aAlertTitle,
bool aAlertTextClickable, const nsAString& aAlertCookie, nsIObserver* aAlertListener, const nsAString& aAlertText, bool aAlertTextClickable,
const nsAString& aAlertCookie, nsIObserver* aAlertListener,
const nsAString& aAlertName, const nsAString& aBidi, const nsAString& aLang, const nsAString& aAlertName, const nsAString& aBidi, const nsAString& aLang,
const nsAString& aData, nsIPrincipal* aPrincipal, bool aInPrivateBrowsing, const nsAString& aData, nsIPrincipal* aPrincipal, bool aInPrivateBrowsing,
bool aRequireInteraction) { bool aRequireInteraction) {
nsCOMPtr<nsIAlertNotification> alert = do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID); nsCOMPtr<nsIAlertNotification> alert =
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE); NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
// vibrate is unused for now // vibrate is unused for now
nsTArray<uint32_t> vibrate; nsTArray<uint32_t> vibrate;
nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable, nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle, aAlertText,
aAlertCookie, aBidi, aLang, aData, aPrincipal, aInPrivateBrowsing, aAlertTextClickable, aAlertCookie, aBidi, aLang,
aData, aPrincipal, aInPrivateBrowsing,
aRequireInteraction, false, vibrate); aRequireInteraction, false, vibrate);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return ShowAlert(alert, aAlertListener); return ShowAlert(alert, aAlertListener);
} }
NS_IMETHODIMP NS_IMETHODIMP
OSXNotificationCenter::ShowPersistentNotification(const nsAString& aPersistentData, OSXNotificationCenter::ShowPersistentNotification(
nsIAlertNotification* aAlert, const nsAString& aPersistentData, nsIAlertNotification* aAlert,
nsIObserver* aAlertListener) { nsIObserver* aAlertListener) {
return ShowAlert(aAlert, aAlertListener); return ShowAlert(aAlert, aAlertListener);
} }
NS_IMETHODIMP NS_IMETHODIMP
OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert, nsIObserver* aAlertListener) { OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert,
nsIObserver* aAlertListener) {
return ShowAlertWithIconData(aAlert, aAlertListener, 0, nullptr); return ShowAlertWithIconData(aAlert, aAlertListener, 0, nullptr);
} }
NS_IMETHODIMP NS_IMETHODIMP
OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert, OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
nsIObserver* aAlertListener, uint32_t aIconSize, nsIObserver* aAlertListener,
uint32_t aIconSize,
const uint8_t* aIconData) { const uint8_t* aIconData) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
@ -248,13 +258,16 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
rv = aAlert->GetSource(hostPort); rv = aAlert->GetSource(hostPort);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIStringBundle> bundle; nsCOMPtr<nsIStringBundle> bundle;
nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID); nsCOMPtr<nsIStringBundleService> sbs =
sbs->CreateBundle("chrome://alerts/locale/alert.properties", getter_AddRefs(bundle)); do_GetService(NS_STRINGBUNDLE_CONTRACTID);
sbs->CreateBundle("chrome://alerts/locale/alert.properties",
getter_AddRefs(bundle));
if (!hostPort.IsEmpty() && bundle) { if (!hostPort.IsEmpty() && bundle) {
AutoTArray<nsString, 1> formatStrings = {hostPort}; AutoTArray<nsString, 1> formatStrings = {hostPort};
nsAutoString notificationSource; nsAutoString notificationSource;
bundle->FormatStringFromName("source.label", formatStrings, notificationSource); bundle->FormatStringFromName("source.label", formatStrings,
notificationSource);
notification.subtitle = nsCocoaUtils::ToNSString(notificationSource); notification.subtitle = nsCocoaUtils::ToNSString(notificationSource);
} }
@ -268,17 +281,19 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
notification.soundName = isSilent ? nil : NSUserNotificationDefaultSoundName; notification.soundName = isSilent ? nil : NSUserNotificationDefaultSoundName;
notification.hasActionButton = NO; notification.hasActionButton = NO;
// If this is not an application/extension alert, show additional actions dealing with // If this is not an application/extension alert, show additional actions
// permissions. // dealing with permissions.
bool isActionable; bool isActionable;
if (bundle && NS_SUCCEEDED(aAlert->GetActionable(&isActionable)) && isActionable) { if (bundle && NS_SUCCEEDED(aAlert->GetActionable(&isActionable)) &&
nsAutoString closeButtonTitle, actionButtonTitle, disableButtonTitle, settingsButtonTitle; isActionable) {
nsAutoString closeButtonTitle, actionButtonTitle, disableButtonTitle,
settingsButtonTitle;
bundle->GetStringFromName("closeButton.title", closeButtonTitle); bundle->GetStringFromName("closeButton.title", closeButtonTitle);
bundle->GetStringFromName("actionButton.label", actionButtonTitle); bundle->GetStringFromName("actionButton.label", actionButtonTitle);
if (!hostPort.IsEmpty()) { if (!hostPort.IsEmpty()) {
AutoTArray<nsString, 1> formatStrings = {hostPort}; AutoTArray<nsString, 1> formatStrings = {hostPort};
bundle->FormatStringFromName("webActions.disableForOrigin.label", formatStrings, bundle->FormatStringFromName("webActions.disableForOrigin.label",
disableButtonTitle); formatStrings, disableButtonTitle);
} }
bundle->GetStringFromName("webActions.settings.label", settingsButtonTitle); bundle->GetStringFromName("webActions.settings.label", settingsButtonTitle);
@ -288,15 +303,20 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
// Notification Center preferences, and doesn't support the alternate // Notification Center preferences, and doesn't support the alternate
// action menu. // action menu.
if ([notification respondsToSelector:@selector(set_showsButtons:)] && if ([notification respondsToSelector:@selector(set_showsButtons:)] &&
[notification respondsToSelector:@selector(set_alwaysShowAlternateActionMenu:)] && [notification
[notification respondsToSelector:@selector(set_alternateActionButtonTitles:)]) { respondsToSelector:@selector(set_alwaysShowAlternateActionMenu:)] &&
[notification
respondsToSelector:@selector(set_alternateActionButtonTitles:)]) {
notification.hasActionButton = YES; notification.hasActionButton = YES;
notification.actionButtonTitle = nsCocoaUtils::ToNSString(actionButtonTitle); notification.actionButtonTitle =
nsCocoaUtils::ToNSString(actionButtonTitle);
[(NSObject*)notification setValue:@(YES) forKey:@"_showsButtons"]; [(NSObject*)notification setValue:@(YES) forKey:@"_showsButtons"];
[(NSObject*)notification setValue:@(YES) forKey:@"_alwaysShowAlternateActionMenu"]; [(NSObject*)notification setValue:@(YES)
forKey:@"_alwaysShowAlternateActionMenu"];
[(NSObject*)notification setValue:@[ [(NSObject*)notification setValue:@[
nsCocoaUtils::ToNSString(disableButtonTitle), nsCocoaUtils::ToNSString(settingsButtonTitle) nsCocoaUtils::ToNSString(disableButtonTitle),
nsCocoaUtils::ToNSString(settingsButtonTitle)
] ]
forKey:@"_alternateActionButtonTitles"]; forKey:@"_alternateActionButtonTitles"];
} }
@ -315,19 +335,22 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
if (!alertName) { if (!alertName) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
notification.userInfo = notification.userInfo = [NSDictionary
[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:alertName, nil] dictionaryWithObjects:[NSArray arrayWithObjects:alertName, nil]
forKeys:[NSArray arrayWithObjects:@"name", nil]]; forKeys:[NSArray arrayWithObjects:@"name", nil]];
nsAutoString cookie; nsAutoString cookie;
rv = aAlert->GetCookie(cookie); rv = aAlert->GetCookie(cookie);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
OSXNotificationInfo* osxni = new OSXNotificationInfo(alertName, aAlertListener, cookie); OSXNotificationInfo* osxni =
new OSXNotificationInfo(alertName, aAlertListener, cookie);
// Show the favicon if supported on this version of OS X. // Show the favicon if supported on this version of OS X.
if (aIconSize > 0 && [notification respondsToSelector:@selector(set_identityImage:)] && if (aIconSize > 0 &&
[notification respondsToSelector:@selector(set_identityImageHasBorder:)]) { [notification respondsToSelector:@selector(set_identityImage:)] &&
[notification
respondsToSelector:@selector(set_identityImageHasBorder:)]) {
NSData* iconData = [NSData dataWithBytes:aIconData length:aIconSize]; NSData* iconData = [NSData dataWithBytes:aIconData length:aIconSize];
NSImage* icon = [[[NSImage alloc] initWithData:iconData] autorelease]; NSImage* icon = [[[NSImage alloc] initWithData:iconData] autorelease];
@ -339,8 +362,8 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing); rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Show the notification without waiting for an image if there is no icon URL or // Show the notification without waiting for an image if there is no icon URL
// notification icons are not supported on this version of OS X. // or notification icons are not supported on this version of OS X.
if (![unClass instancesRespondToSelector:@selector(setContentImage:)]) { if (![unClass instancesRespondToSelector:@selector(setContentImage:)]) {
CloseAlertCocoaString(alertName); CloseAlertCocoaString(alertName);
mActiveAlerts.AppendElement(osxni); mActiveAlerts.AppendElement(osxni);
@ -353,7 +376,8 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
mPendingAlerts.AppendElement(osxni); mPendingAlerts.AppendElement(osxni);
osxni->mPendingNotification = notification; osxni->mPendingNotification = notification;
// Wait six seconds for the image to load. // Wait six seconds for the image to load.
rv = aAlert->LoadImage(6000, this, osxni, getter_AddRefs(osxni->mIconRequest)); rv = aAlert->LoadImage(6000, this, osxni,
getter_AddRefs(osxni->mIconRequest));
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
ShowPendingNotification(osxni); ShowPendingNotification(osxni);
} }
@ -365,7 +389,8 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
} }
NS_IMETHODIMP NS_IMETHODIMP
OSXNotificationCenter::CloseAlert(const nsAString& aAlertName, bool aContextClosed) { OSXNotificationCenter::CloseAlert(const nsAString& aAlertName,
bool aContextClosed) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NSString* alertName = nsCocoaUtils::ToNSString(aAlertName); NSString* alertName = nsCocoaUtils::ToNSString(aAlertName);
@ -396,7 +421,8 @@ void OSXNotificationCenter::CloseAlertCocoaString(NSString* aAlertName) {
OSXNotificationInfo* osxni = mActiveAlerts[i]; OSXNotificationInfo* osxni = mActiveAlerts[i];
if ([aAlertName isEqualToString:osxni->mName]) { if ([aAlertName isEqualToString:osxni->mName]) {
if (osxni->mObserver) { if (osxni->mObserver) {
osxni->mObserver->Observe(nullptr, "alertfinished", osxni->mCookie.get()); osxni->mObserver->Observe(nullptr, "alertfinished",
osxni->mCookie.get());
} }
if (osxni->mIconRequest) { if (osxni->mIconRequest) {
osxni->mIconRequest->Cancel(NS_BINDING_ABORTED); osxni->mIconRequest->Cancel(NS_BINDING_ABORTED);
@ -410,9 +436,9 @@ void OSXNotificationCenter::CloseAlertCocoaString(NSString* aAlertName) {
NS_OBJC_END_TRY_IGNORE_BLOCK; NS_OBJC_END_TRY_IGNORE_BLOCK;
} }
void OSXNotificationCenter::OnActivate(NSString* aAlertName, void OSXNotificationCenter::OnActivate(
NSUserNotificationActivationType aActivationType, NSString* aAlertName, NSUserNotificationActivationType aActivationType,
unsigned long long aAdditionalActionIndex) { unsigned long long aAdditionalActionIndex) {
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
if (!aAlertName) { if (!aAlertName) {
@ -428,18 +454,22 @@ void OSXNotificationCenter::OnActivate(NSString* aAlertName,
case NSUserNotificationActivationTypeActionButtonClicked: case NSUserNotificationActivationTypeActionButtonClicked:
switch (aAdditionalActionIndex) { switch (aAdditionalActionIndex) {
case OSXNotificationActionDisable: case OSXNotificationActionDisable:
osxni->mObserver->Observe(nullptr, "alertdisablecallback", osxni->mCookie.get()); osxni->mObserver->Observe(nullptr, "alertdisablecallback",
osxni->mCookie.get());
break; break;
case OSXNotificationActionSettings: case OSXNotificationActionSettings:
osxni->mObserver->Observe(nullptr, "alertsettingscallback", osxni->mCookie.get()); osxni->mObserver->Observe(nullptr, "alertsettingscallback",
osxni->mCookie.get());
break; break;
default: default:
NS_WARNING("Unknown NSUserNotification additional action clicked"); NS_WARNING(
"Unknown NSUserNotification additional action clicked");
break; break;
} }
break; break;
default: default:
osxni->mObserver->Observe(nullptr, "alertclickcallback", osxni->mCookie.get()); osxni->mObserver->Observe(nullptr, "alertclickcallback",
osxni->mCookie.get());
break; break;
} }
} }
@ -450,7 +480,8 @@ void OSXNotificationCenter::OnActivate(NSString* aAlertName,
NS_OBJC_END_TRY_IGNORE_BLOCK; NS_OBJC_END_TRY_IGNORE_BLOCK;
} }
void OSXNotificationCenter::ShowPendingNotification(OSXNotificationInfo* osxni) { void OSXNotificationCenter::ShowPendingNotification(
OSXNotificationInfo* osxni) {
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
if (osxni->mIconRequest) { if (osxni->mIconRequest) {
@ -496,7 +527,8 @@ OSXNotificationCenter::OnImageMissing(nsISupports* aUserData) {
} }
NS_IMETHODIMP NS_IMETHODIMP
OSXNotificationCenter::OnImageReady(nsISupports* aUserData, imgIRequest* aRequest) { OSXNotificationCenter::OnImageReady(nsISupports* aUserData,
imgIRequest* aRequest) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
nsCOMPtr<imgIContainer> image; nsCOMPtr<imgIContainer> image;
@ -511,9 +543,10 @@ OSXNotificationCenter::OnImageReady(nsISupports* aUserData, imgIRequest* aReques
} }
NSImage* cocoaImage = nil; NSImage* cocoaImage = nil;
// TODO: Pass pres context / ComputedStyle here to support context paint properties // TODO: Pass pres context / ComputedStyle here to support context paint
nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(image, imgIContainer::FRAME_FIRST, // properties
nullptr, nullptr, &cocoaImage); nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
image, imgIContainer::FRAME_FIRST, nullptr, nullptr, &cocoaImage);
(osxni->mPendingNotification).contentImage = cocoaImage; (osxni->mPendingNotification).contentImage = cocoaImage;
[cocoaImage release]; [cocoaImage release];
ShowPendingNotification(osxni); ShowPendingNotification(osxni);
@ -525,7 +558,9 @@ OSXNotificationCenter::OnImageReady(nsISupports* aUserData, imgIRequest* aReques
// nsIAlertsDoNotDisturb // nsIAlertsDoNotDisturb
NS_IMETHODIMP NS_IMETHODIMP
OSXNotificationCenter::GetManualDoNotDisturb(bool* aRetVal) { return NS_ERROR_NOT_IMPLEMENTED; } OSXNotificationCenter::GetManualDoNotDisturb(bool* aRetVal) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP NS_IMETHODIMP
OSXNotificationCenter::SetManualDoNotDisturb(bool aDoNotDisturb) { OSXNotificationCenter::SetManualDoNotDisturb(bool aDoNotDisturb) {

View file

@ -79,19 +79,20 @@ ScreenHelperCocoa::~ScreenHelperCocoa() {
static already_AddRefed<Screen> MakeScreen(NSScreen* aScreen) { static already_AddRefed<Screen> MakeScreen(NSScreen* aScreen) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
DesktopToLayoutDeviceScale contentsScaleFactor(nsCocoaUtils::GetBackingScaleFactor(aScreen)); DesktopToLayoutDeviceScale contentsScaleFactor(
nsCocoaUtils::GetBackingScaleFactor(aScreen));
CSSToLayoutDeviceScale defaultCssScaleFactor(contentsScaleFactor.scale); CSSToLayoutDeviceScale defaultCssScaleFactor(contentsScaleFactor.scale);
NSRect frame = [aScreen frame]; NSRect frame = [aScreen frame];
LayoutDeviceIntRect rect = LayoutDeviceIntRect rect = nsCocoaUtils::CocoaRectToGeckoRectDevPix(
nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, contentsScaleFactor.scale); frame, contentsScaleFactor.scale);
frame = [aScreen visibleFrame]; frame = [aScreen visibleFrame];
LayoutDeviceIntRect availRect = LayoutDeviceIntRect availRect = nsCocoaUtils::CocoaRectToGeckoRectDevPix(
nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, contentsScaleFactor.scale); frame, contentsScaleFactor.scale);
// aScreen may be capable of displaying multiple pixel depths, for example by // aScreen may be capable of displaying multiple pixel depths, for example by
// transitioning to an HDR-capable depth when required by a window displayed on // transitioning to an HDR-capable depth when required by a window displayed
// the screen. We want to note the maximum capabilities of the screen, so we use // on the screen. We want to note the maximum capabilities of the screen, so
// the largest depth it offers. // we use the largest depth it offers.
uint32_t pixelDepth = 0; uint32_t pixelDepth = 0;
const NSWindowDepth* depths = [aScreen supportedWindowDepths]; const NSWindowDepth* depths = [aScreen supportedWindowDepths];
for (size_t d = 0; NSWindowDepth depth = depths[d]; d++) { for (size_t d = 0; NSWindowDepth depth = depths[d]; d++) {
@ -116,16 +117,17 @@ static already_AddRefed<Screen> MakeScreen(NSScreen* aScreen) {
dpi = rect.height / (heightMM / MM_PER_INCH_FLOAT); dpi = rect.height / (heightMM / MM_PER_INCH_FLOAT);
} }
MOZ_LOG(sScreenLog, LogLevel::Debug, MOZ_LOG(sScreenLog, LogLevel::Debug,
("New screen [%d %d %d %d (%d %d %d %d) %d %f %f %f]", rect.x, rect.y, rect.width, ("New screen [%d %d %d %d (%d %d %d %d) %d %f %f %f]", rect.x, rect.y,
rect.height, availRect.x, availRect.y, availRect.width, availRect.height, pixelDepth, rect.width, rect.height, availRect.x, availRect.y, availRect.width,
contentsScaleFactor.scale, defaultCssScaleFactor.scale, dpi)); availRect.height, pixelDepth, contentsScaleFactor.scale,
defaultCssScaleFactor.scale, dpi));
// Getting the refresh rate is a little hard on OS X. We could use // Getting the refresh rate is a little hard on OS X. We could use
// CVDisplayLinkGetNominalOutputVideoRefreshPeriod, but that's a little // CVDisplayLinkGetNominalOutputVideoRefreshPeriod, but that's a little
// involved. Ideally we could query it from vsync. For now, we leave it out. // involved. Ideally we could query it from vsync. For now, we leave it out.
RefPtr<Screen> screen = RefPtr<Screen> screen = new Screen(rect, availRect, pixelDepth, pixelDepth, 0,
new Screen(rect, availRect, pixelDepth, pixelDepth, 0, contentsScaleFactor, contentsScaleFactor, defaultCssScaleFactor,
defaultCssScaleFactor, dpi, Screen::IsPseudoDisplay::No); dpi, Screen::IsPseudoDisplay::No);
return screen.forget(); return screen.forget();
NS_OBJC_END_TRY_BLOCK_RETURN(nullptr); NS_OBJC_END_TRY_BLOCK_RETURN(nullptr);
@ -164,7 +166,8 @@ NSScreen* ScreenHelperCocoa::CocoaScreenForScreen(nsIScreen* aScreen) {
aScreen->GetRect(&rect.x, &rect.y, &rect.width, &rect.height); aScreen->GetRect(&rect.x, &rect.y, &rect.width, &rect.height);
aScreen->GetContentsScaleFactor(&scale); aScreen->GetContentsScaleFactor(&scale);
NSRect frame = [screen frame]; NSRect frame = [screen frame];
LayoutDeviceIntRect frameRect = nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, scale); LayoutDeviceIntRect frameRect =
nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, scale);
if (rect == frameRect) { if (rect == frameRect) {
return screen; return screen;
} }

File diff suppressed because it is too large Load diff

View file

@ -18,7 +18,8 @@
namespace mozilla::widget { namespace mozilla::widget {
auto TextRecognition::DoFindText(gfx::DataSourceSurface& aSurface, auto TextRecognition::DoFindText(gfx::DataSourceSurface& aSurface,
const nsTArray<nsCString>& aLanguages) -> RefPtr<NativePromise> { const nsTArray<nsCString>& aLanguages)
-> RefPtr<NativePromise> {
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK NS_OBJC_BEGIN_TRY_IGNORE_BLOCK
// TODO - Is this the most efficient path? Maybe we can write a new // TODO - Is this the most efficient path? Maybe we can write a new
@ -26,7 +27,8 @@ auto TextRecognition::DoFindText(gfx::DataSourceSurface& aSurface,
CGImageRef imageRef = NULL; CGImageRef imageRef = NULL;
nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(&aSurface, &imageRef); nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(&aSurface, &imageRef);
if (NS_FAILED(rv) || !imageRef) { if (NS_FAILED(rv) || !imageRef) {
return NativePromise::CreateAndReject("Failed to create CGImage"_ns, __func__); return NativePromise::CreateAndReject("Failed to create CGImage"_ns,
__func__);
} }
auto promise = MakeRefPtr<NativePromise::Private>(__func__); auto promise = MakeRefPtr<NativePromise::Private>(__func__);
@ -48,47 +50,63 @@ auto TextRecognition::DoFindText(gfx::DataSourceSurface& aSurface,
dom::TextRecognitionResult result; dom::TextRecognitionResult result;
dom::TextRecognitionResult* pResult = &result; dom::TextRecognitionResult* pResult = &result;
// Define the request to use, which also handles the result. It will be run below // Define the request to use, which also handles the result. It will
// directly in this thread. After creating this request. // be run below directly in this thread. After creating this
VNRecognizeTextRequest* textRecognitionRequest = [[VNRecognizeTextRequest alloc] // request.
initWithCompletionHandler:^(VNRequest* _Nonnull request, NSError* _Nullable error) { VNRecognizeTextRequest* textRecognitionRequest =
NSArray<VNRecognizedTextObservation*>* observations = request.results; [[VNRecognizeTextRequest alloc] initWithCompletionHandler:^(
VNRequest* _Nonnull request,
NSError* _Nullable error) {
NSArray<VNRecognizedTextObservation*>* observations =
request.results;
[observations [observations enumerateObjectsUsingBlock:^(
enumerateObjectsUsingBlock:^(VNRecognizedTextObservation* _Nonnull obj, VNRecognizedTextObservation* _Nonnull obj,
NSUInteger idx, BOOL* _Nonnull stop) { NSUInteger idx, BOOL* _Nonnull stop) {
// Requests the n top candidates for a recognized text string. // Requests the n top candidates for a recognized text
VNRecognizedText* recognizedText = [obj topCandidates:1].firstObject; // string.
VNRecognizedText* recognizedText =
[obj topCandidates:1].firstObject;
// https://developer.apple.com/documentation/vision/vnrecognizedtext?language=objc // https://developer.apple.com/documentation/vision/vnrecognizedtext?language=objc
auto& quad = *pResult->quads().AppendElement(); auto& quad = *pResult->quads().AppendElement();
CopyCocoaStringToXPCOMString(recognizedText.string, quad.string()); CopyCocoaStringToXPCOMString(recognizedText.string,
quad.confidence() = recognizedText.confidence; quad.string());
quad.confidence() = recognizedText.confidence;
auto ToImagePoint = [](CGPoint aPoint) -> ImagePoint { auto ToImagePoint = [](CGPoint aPoint) -> ImagePoint {
return {static_cast<float>(aPoint.x), static_cast<float>(aPoint.y)}; return {static_cast<float>(aPoint.x),
}; static_cast<float>(aPoint.y)};
*quad.points().AppendElement() = ToImagePoint(obj.bottomLeft); };
*quad.points().AppendElement() = ToImagePoint(obj.topLeft); *quad.points().AppendElement() =
*quad.points().AppendElement() = ToImagePoint(obj.topRight); ToImagePoint(obj.bottomLeft);
*quad.points().AppendElement() = ToImagePoint(obj.bottomRight); *quad.points().AppendElement() = ToImagePoint(obj.topLeft);
}]; *quad.points().AppendElement() = ToImagePoint(obj.topRight);
*quad.points().AppendElement() =
ToImagePoint(obj.bottomRight);
}];
}]; }];
textRecognitionRequest.recognitionLevel = VNRequestTextRecognitionLevelAccurate; textRecognitionRequest.recognitionLevel =
VNRequestTextRecognitionLevelAccurate;
textRecognitionRequest.recognitionLanguages = recognitionLanguages; textRecognitionRequest.recognitionLanguages = recognitionLanguages;
textRecognitionRequest.usesLanguageCorrection = true; textRecognitionRequest.usesLanguageCorrection = true;
// Send out the request. This blocks execution of this thread with an expensive // Send out the request. This blocks execution of this thread with
// CPU call. // an expensive CPU call.
NSError* error = nil; NSError* error = nil;
VNImageRequestHandler* requestHandler = VNImageRequestHandler* requestHandler =
[[[VNImageRequestHandler alloc] initWithCGImage:imageRef options:@{}] autorelease]; [[[VNImageRequestHandler alloc] initWithCGImage:imageRef
options:@{}]
autorelease];
[requestHandler performRequests:@[ textRecognitionRequest ] error:&error]; [requestHandler performRequests:@[ textRecognitionRequest ]
error:&error];
if (error != nil) { if (error != nil) {
promise->Reject( promise->Reject(
nsPrintfCString("Failed to perform text recognition request (%ld)\n", error.code), nsPrintfCString(
"Failed to perform text recognition request (%ld)\n",
error.code),
__func__); __func__);
} else { } else {
promise->Resolve(std::move(result), __func__); promise->Resolve(std::move(result), __func__);

View file

@ -16,27 +16,29 @@ using namespace mozilla;
@interface MOZVibrantView : NSVisualEffectView { @interface MOZVibrantView : NSVisualEffectView {
VibrancyType mType; VibrancyType mType;
} }
- (instancetype)initWithFrame:(NSRect)aRect vibrancyType:(VibrancyType)aVibrancyType; - (instancetype)initWithFrame:(NSRect)aRect
vibrancyType:(VibrancyType)aVibrancyType;
@end @end
@interface MOZVibrantLeafView : MOZVibrantView @interface MOZVibrantLeafView : MOZVibrantView
@end @end
static NSVisualEffectState VisualEffectStateForVibrancyType(VibrancyType aType) { static NSVisualEffectState VisualEffectStateForVibrancyType(
VibrancyType aType) {
switch (aType) { switch (aType) {
case VibrancyType::TOOLTIP: case VibrancyType::TOOLTIP:
case VibrancyType::MENU: case VibrancyType::MENU:
case VibrancyType::HIGHLIGHTED_MENUITEM: case VibrancyType::HIGHLIGHTED_MENUITEM:
// Tooltip and menu windows are never "key", so we need to tell the vibrancy effect to look // Tooltip and menu windows are never "key", so we need to tell the
// active regardless of window state. // vibrancy effect to look active regardless of window state.
return NSVisualEffectStateActive; return NSVisualEffectStateActive;
default: default:
return NSVisualEffectStateFollowsWindowActiveState; return NSVisualEffectStateFollowsWindowActiveState;
} }
} }
static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(VibrancyType aType, static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(
BOOL* aOutIsEmphasized) { VibrancyType aType, BOOL* aOutIsEmphasized) {
switch (aType) { switch (aType) {
case VibrancyType::TOOLTIP: case VibrancyType::TOOLTIP:
return (NSVisualEffectMaterial)NSVisualEffectMaterialToolTip; return (NSVisualEffectMaterial)NSVisualEffectMaterialToolTip;
@ -90,8 +92,8 @@ static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(VibrancyType a
@end @end
bool VibrancyManager::UpdateVibrantRegion(VibrancyType aType, bool VibrancyManager::UpdateVibrantRegion(
const LayoutDeviceIntRegion& aRegion) { VibrancyType aType, const LayoutDeviceIntRegion& aRegion) {
if (aRegion.IsEmpty()) { if (aRegion.IsEmpty()) {
return mVibrantRegions.Remove(uint32_t(aType)); return mVibrantRegions.Remove(uint32_t(aType));
} }
@ -109,7 +111,10 @@ LayoutDeviceIntRegion VibrancyManager::GetUnionOfVibrantRegions() const {
return result; return result;
} }
/* static */ NSView* VibrancyManager::CreateEffectView(VibrancyType aType, BOOL aIsContainer) { /* static */ NSView* VibrancyManager::CreateEffectView(VibrancyType aType,
return aIsContainer ? [[MOZVibrantView alloc] initWithFrame:NSZeroRect vibrancyType:aType] BOOL aIsContainer) {
: [[MOZVibrantLeafView alloc] initWithFrame:NSZeroRect vibrancyType:aType]; return aIsContainer ? [[MOZVibrantView alloc] initWithFrame:NSZeroRect
vibrancyType:aType]
: [[MOZVibrantLeafView alloc] initWithFrame:NSZeroRect
vibrancyType:aType];
} }

View file

@ -18,7 +18,8 @@ ViewRegion::~ViewRegion() {
} }
bool ViewRegion::UpdateRegion(const LayoutDeviceIntRegion& aRegion, bool ViewRegion::UpdateRegion(const LayoutDeviceIntRegion& aRegion,
const nsChildView& aCoordinateConverter, NSView* aContainerView, const nsChildView& aCoordinateConverter,
NSView* aContainerView,
NSView* (^aViewCreationCallback)()) { NSView* (^aViewCreationCallback)()) {
if (mRegion == aRegion) { if (mRegion == aRegion) {
return false; return false;
@ -33,7 +34,8 @@ bool ViewRegion::UpdateRegion(const LayoutDeviceIntRegion& aRegion,
// The mViews array is now empty. // The mViews array is now empty.
size_t i = 0; size_t i = 0;
for (auto iter = aRegion.RectIter(); !iter.Done() || i < viewsToRecycle.Length(); i++) { for (auto iter = aRegion.RectIter();
!iter.Done() || i < viewsToRecycle.Length(); i++) {
if (!iter.Done()) { if (!iter.Done()) {
NSView* view = nil; NSView* view = nil;
NSRect rect = aCoordinateConverter.DevPixelsToCocoaPoints(iter.Get()); NSRect rect = aCoordinateConverter.DevPixelsToCocoaPoints(iter.Get());

View file

@ -57,7 +57,8 @@
using namespace mozilla; using namespace mozilla;
using namespace mozilla::widget; using namespace mozilla::widget;
#define WAKE_LOCK_LOG(...) MOZ_LOG(gMacWakeLockLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) #define WAKE_LOCK_LOG(...) \
MOZ_LOG(gMacWakeLockLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
static mozilla::LazyLogModule gMacWakeLockLog("MacWakeLock"); static mozilla::LazyLogModule gMacWakeLockLog("MacWakeLock");
// A wake lock listener that disables screen saver when requested by // A wake lock listener that disables screen saver when requested by
@ -74,24 +75,30 @@ class MacWakeLockListener final : public nsIDOMMozWakeLockListener {
IOPMAssertionID mAssertionNoDisplaySleepID = kIOPMNullAssertionID; IOPMAssertionID mAssertionNoDisplaySleepID = kIOPMNullAssertionID;
IOPMAssertionID mAssertionNoIdleSleepID = kIOPMNullAssertionID; IOPMAssertionID mAssertionNoIdleSleepID = kIOPMNullAssertionID;
NS_IMETHOD Callback(const nsAString& aTopic, const nsAString& aState) override { NS_IMETHOD Callback(const nsAString& aTopic,
const nsAString& aState) override {
if (!aTopic.EqualsASCII("screen") && !aTopic.EqualsASCII("audio-playing") && if (!aTopic.EqualsASCII("screen") && !aTopic.EqualsASCII("audio-playing") &&
!aTopic.EqualsASCII("video-playing")) { !aTopic.EqualsASCII("video-playing")) {
return NS_OK; return NS_OK;
} }
// we should still hold the lock for background audio. // we should still hold the lock for background audio.
if (aTopic.EqualsASCII("audio-playing") && aState.EqualsASCII("locked-background")) { if (aTopic.EqualsASCII("audio-playing") &&
aState.EqualsASCII("locked-background")) {
WAKE_LOCK_LOG("keep audio playing even in background"); WAKE_LOCK_LOG("keep audio playing even in background");
return NS_OK; return NS_OK;
} }
bool shouldKeepDisplayOn = aTopic.EqualsASCII("screen") || aTopic.EqualsASCII("video-playing"); bool shouldKeepDisplayOn =
CFStringRef assertionType = aTopic.EqualsASCII("screen") || aTopic.EqualsASCII("video-playing");
shouldKeepDisplayOn ? kIOPMAssertionTypeNoDisplaySleep : kIOPMAssertionTypeNoIdleSleep; CFStringRef assertionType = shouldKeepDisplayOn
IOPMAssertionID& assertionId = ? kIOPMAssertionTypeNoDisplaySleep
shouldKeepDisplayOn ? mAssertionNoDisplaySleepID : mAssertionNoIdleSleepID; : kIOPMAssertionTypeNoIdleSleep;
WAKE_LOCK_LOG("topic=%s, state=%s, shouldKeepDisplayOn=%d", NS_ConvertUTF16toUTF8(aTopic).get(), IOPMAssertionID& assertionId = shouldKeepDisplayOn
? mAssertionNoDisplaySleepID
: mAssertionNoIdleSleepID;
WAKE_LOCK_LOG("topic=%s, state=%s, shouldKeepDisplayOn=%d",
NS_ConvertUTF16toUTF8(aTopic).get(),
NS_ConvertUTF16toUTF8(aState).get(), shouldKeepDisplayOn); NS_ConvertUTF16toUTF8(aState).get(), shouldKeepDisplayOn);
// Note the wake lock code ensures that we're not sent duplicate // Note the wake lock code ensures that we're not sent duplicate
@ -103,9 +110,10 @@ class MacWakeLockListener final : public nsIDOMMozWakeLockListener {
} }
// Prevent screen saver. // Prevent screen saver.
CFStringRef cf_topic = ::CFStringCreateWithCharacters( CFStringRef cf_topic = ::CFStringCreateWithCharacters(
kCFAllocatorDefault, reinterpret_cast<const UniChar*>(aTopic.Data()), aTopic.Length()); kCFAllocatorDefault, reinterpret_cast<const UniChar*>(aTopic.Data()),
IOReturn success = ::IOPMAssertionCreateWithName(assertionType, kIOPMAssertionLevelOn, aTopic.Length());
cf_topic, &assertionId); IOReturn success = ::IOPMAssertionCreateWithName(
assertionType, kIOPMAssertionLevelOn, cf_topic, &assertionId);
CFRelease(cf_topic); CFRelease(cf_topic);
if (success != kIOReturnSuccess) { if (success != kIOReturnSuccess) {
WAKE_LOCK_LOG("failed to disable screensaver"); WAKE_LOCK_LOG("failed to disable screensaver");
@ -133,19 +141,21 @@ static bool gAppShellMethodsSwizzled = false;
void OnUncaughtException(NSException* aException) { void OnUncaughtException(NSException* aException) {
nsObjCExceptionLog(aException); nsObjCExceptionLog(aException);
MOZ_CRASH("Uncaught Objective C exception from NSSetUncaughtExceptionHandler"); MOZ_CRASH(
"Uncaught Objective C exception from NSSetUncaughtExceptionHandler");
} }
@implementation GeckoNSApplication @implementation GeckoNSApplication
// Load is called very early during startup, when the Objective C runtime loads this class. // Load is called very early during startup, when the Objective C runtime loads
// this class.
+ (void)load { + (void)load {
NSSetUncaughtExceptionHandler(OnUncaughtException); NSSetUncaughtExceptionHandler(OnUncaughtException);
} }
// This method is called from NSDefaultTopLevelErrorHandler, which is invoked when an Objective C // This method is called from NSDefaultTopLevelErrorHandler, which is invoked
// exception propagates up into the native event loop. It is possible that it is also called in // when an Objective C exception propagates up into the native event loop. It is
// other cases. // possible that it is also called in other cases.
- (void)reportException:(NSException*)aException { - (void)reportException:(NSException*)aException {
if (ShouldIgnoreObjCException(aException)) { if (ShouldIgnoreObjCException(aException)) {
return; return;
@ -154,14 +164,16 @@ void OnUncaughtException(NSException* aException) {
nsObjCExceptionLog(aException); nsObjCExceptionLog(aException);
#ifdef NIGHTLY_BUILD #ifdef NIGHTLY_BUILD
MOZ_CRASH("Uncaught Objective C exception from -[GeckoNSApplication reportException:]"); MOZ_CRASH("Uncaught Objective C exception from -[GeckoNSApplication "
"reportException:]");
#endif #endif
} }
- (void)sendEvent:(NSEvent*)anEvent { - (void)sendEvent:(NSEvent*)anEvent {
mozilla::BackgroundHangMonitor().NotifyActivity(); mozilla::BackgroundHangMonitor().NotifyActivity();
if ([anEvent type] == NSEventTypeApplicationDefined && [anEvent subtype] == kEventSubtypeTrace) { if ([anEvent type] == NSEventTypeApplicationDefined &&
[anEvent subtype] == kEventSubtypeTrace) {
mozilla::SignalTracerThread(); mozilla::SignalTracerThread();
return; return;
} }
@ -208,7 +220,8 @@ void OnUncaughtException(NSException* aException) {
NS_IMETHODIMP NS_IMETHODIMP
nsAppShell::ResumeNative(void) { nsAppShell::ResumeNative(void) {
nsresult retval = nsBaseAppShell::ResumeNative(); nsresult retval = nsBaseAppShell::ResumeNative();
if (NS_SUCCEEDED(retval) && (mSuspendNativeCount == 0) && mSkippedNativeCallback) { if (NS_SUCCEEDED(retval) && (mSuspendNativeCount == 0) &&
mSkippedNativeCallback) {
mSkippedNativeCallback = false; mSkippedNativeCallback = false;
ScheduleNativeEventCallback(); ScheduleNativeEventCallback();
} }
@ -243,11 +256,13 @@ nsAppShell::~nsAppShell() {
if (mCFRunLoop) { if (mCFRunLoop) {
if (mCFRunLoopSource) { if (mCFRunLoopSource) {
::CFRunLoopRemoveSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes); ::CFRunLoopRemoveSource(mCFRunLoop, mCFRunLoopSource,
kCFRunLoopCommonModes);
::CFRelease(mCFRunLoopSource); ::CFRelease(mCFRunLoopSource);
} }
if (mCFRunLoopObserver) { if (mCFRunLoopObserver) {
::CFRunLoopRemoveObserver(mCFRunLoop, mCFRunLoopObserver, kCFRunLoopCommonModes); ::CFRunLoopRemoveObserver(mCFRunLoop, mCFRunLoopObserver,
kCFRunLoopCommonModes);
::CFRelease(mCFRunLoopObserver); ::CFRelease(mCFRunLoopObserver);
} }
::CFRelease(mCFRunLoop); ::CFRelease(mCFRunLoop);
@ -274,7 +289,8 @@ static void AddScreenWakeLockListener() {
sWakeLockListener = new MacWakeLockListener(); sWakeLockListener = new MacWakeLockListener();
sPowerManagerService->AddWakeLockListener(sWakeLockListener); sPowerManagerService->AddWakeLockListener(sWakeLockListener);
} else { } else {
NS_WARNING("Failed to retrieve PowerManagerService, wakelocks will be broken!"); NS_WARNING(
"Failed to retrieve PowerManagerService, wakelocks will be broken!");
} }
} }
@ -288,8 +304,8 @@ static void RemoveScreenWakeLockListener() {
} }
} }
void RunLoopObserverCallback(CFRunLoopObserverRef aObserver, CFRunLoopActivity aActivity, void RunLoopObserverCallback(CFRunLoopObserverRef aObserver,
void* aInfo) { CFRunLoopActivity aActivity, void* aInfo) {
static_cast<nsAppShell*>(aInfo)->OnRunLoopActivityChanged(aActivity); static_cast<nsAppShell*>(aInfo)->OnRunLoopActivityChanged(aActivity);
} }
@ -298,30 +314,34 @@ void nsAppShell::OnRunLoopActivityChanged(CFRunLoopActivity aActivity) {
mozilla::BackgroundHangMonitor().NotifyWait(); mozilla::BackgroundHangMonitor().NotifyWait();
} }
// When the event loop is in its waiting state, we would like the profiler to know that the thread // When the event loop is in its waiting state, we would like the profiler to
// is idle. The usual way to notify the profiler of idleness would be to place a profiler label // know that the thread is idle. The usual way to notify the profiler of
// frame with the IDLE category on the stack, for the duration of the function that does the // idleness would be to place a profiler label frame with the IDLE category on
// waiting. However, since macOS uses an event loop model where "the event loop calls you", we do // the stack, for the duration of the function that does the waiting. However,
// not control the function that does the waiting; the waiting happens inside CFRunLoop code. // since macOS uses an event loop model where "the event loop calls you", we
// Instead, the run loop notifies us when it enters and exits the waiting state, by calling this // do not control the function that does the waiting; the waiting happens
// function. // inside CFRunLoop code. Instead, the run loop notifies us when it enters and
// So we do not have a function under our control that stays on the stack for the duration of the // exits the waiting state, by calling this function. So we do not have a
// wait. So, rather than putting an AutoProfilerLabel on the stack, we will manually push and pop // function under our control that stays on the stack for the duration of the
// the label frame here. // wait. So, rather than putting an AutoProfilerLabel on the stack, we will
// The location in the stack where this label frame is inserted is somewhat arbitrary. In // manually push and pop the label frame here. The location in the stack where
// practice, the label frame will be at the very tip of the stack, looking like it's "inside" the // this label frame is inserted is somewhat arbitrary. In practice, the label
// frame will be at the very tip of the stack, looking like it's "inside" the
// mach_msg_trap wait function. // mach_msg_trap wait function.
if (aActivity == kCFRunLoopBeforeWaiting) { if (aActivity == kCFRunLoopBeforeWaiting) {
using ThreadRegistration = mozilla::profiler::ThreadRegistration; using ThreadRegistration = mozilla::profiler::ThreadRegistration;
ThreadRegistration::WithOnThreadRef([&](ThreadRegistration::OnThreadRef aOnThreadRef) { ThreadRegistration::WithOnThreadRef(
ProfilingStack& profilingStack = [&](ThreadRegistration::OnThreadRef aOnThreadRef) {
aOnThreadRef.UnlockedConstReaderAndAtomicRWRef().ProfilingStackRef(); ProfilingStack& profilingStack =
mProfilingStackWhileWaiting = &profilingStack; aOnThreadRef.UnlockedConstReaderAndAtomicRWRef()
uint8_t variableOnStack = 0; .ProfilingStackRef();
profilingStack.pushLabelFrame("Native event loop idle", nullptr, &variableOnStack, mProfilingStackWhileWaiting = &profilingStack;
JS::ProfilingCategoryPair::IDLE, 0); uint8_t variableOnStack = 0;
profiler_thread_sleep(); profilingStack.pushLabelFrame("Native event loop idle", nullptr,
}); &variableOnStack,
JS::ProfilingCategoryPair::IDLE, 0);
profiler_thread_sleep();
});
} else { } else {
if (mProfilingStackWhileWaiting) { if (mProfilingStackWhileWaiting) {
mProfilingStackWhileWaiting->pop(); mProfilingStackWhileWaiting->pop();
@ -356,8 +376,9 @@ nsresult nsAppShell::Init() {
mAutoreleasePools = ::CFArrayCreateMutable(nullptr, 0, nullptr); mAutoreleasePools = ::CFArrayCreateMutable(nullptr, 0, nullptr);
NS_ENSURE_STATE(mAutoreleasePools); NS_ENSURE_STATE(mAutoreleasePools);
bool isNSApplicationProcessType = (XRE_GetProcessType() != GeckoProcessType_RDD) && bool isNSApplicationProcessType =
(XRE_GetProcessType() != GeckoProcessType_Socket); (XRE_GetProcessType() != GeckoProcessType_RDD) &&
(XRE_GetProcessType() != GeckoProcessType_Socket);
if (isNSApplicationProcessType) { if (isNSApplicationProcessType) {
// This call initializes NSApplication unless: // This call initializes NSApplication unless:
@ -391,14 +412,15 @@ nsresult nsAppShell::Init() {
::CFRunLoopAddSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes); ::CFRunLoopAddSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes);
// Add a CFRunLoopObserver so that the profiler can be notified when we enter and exit the waiting // Add a CFRunLoopObserver so that the profiler can be notified when we enter
// state. // and exit the waiting state.
CFRunLoopObserverContext observerContext; CFRunLoopObserverContext observerContext;
PodZero(&observerContext); PodZero(&observerContext);
observerContext.info = this; observerContext.info = this;
mCFRunLoopObserver = ::CFRunLoopObserverCreate( mCFRunLoopObserver = ::CFRunLoopObserverCreate(
kCFAllocatorDefault, kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting | kCFRunLoopExit, true, kCFAllocatorDefault,
kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting | kCFRunLoopExit, true,
0, RunLoopObserverCallback, &observerContext); 0, RunLoopObserverCallback, &observerContext);
NS_ENSURE_STATE(mCFRunLoopObserver); NS_ENSURE_STATE(mCFRunLoopObserver);
@ -491,9 +513,10 @@ void nsAppShell::ProcessGeckoEvents(void* aInfo) {
// DummyEvent inserted by nsBaseAppShell::OnProcessNextEvent. This second // DummyEvent inserted by nsBaseAppShell::OnProcessNextEvent. This second
// event will cause the second call to AcquireFirstMatchingEventInQueue in // event will cause the second call to AcquireFirstMatchingEventInQueue in
// nsAppShell::ProcessNextNativeEvent to return true. Which makes // nsAppShell::ProcessNextNativeEvent to return true. Which makes
// nsBaseAppShell::OnProcessNextEvent call nsAppShell::ProcessNextNativeEvent // nsBaseAppShell::OnProcessNextEvent call
// again during which it will loop until it sleeps because ProcessGeckoEvents() // nsAppShell::ProcessNextNativeEvent again during which it will loop until
// won't be called for the DummyEvent. // it sleeps because ProcessGeckoEvents() won't be called for the
// DummyEvent.
// //
// This is not a good approach and we should fix things up so that only // This is not a good approach and we should fix things up so that only
// one postEvent is needed. // one postEvent is needed.
@ -551,8 +574,8 @@ void nsAppShell::ProcessGeckoEvents(void* aInfo) {
if (self->mTerminated) { if (self->mTerminated) {
int32_t releaseCount = 0; int32_t releaseCount = 0;
if (self->mNativeEventScheduledDepth > self->mNativeEventCallbackDepth) { if (self->mNativeEventScheduledDepth > self->mNativeEventCallbackDepth) {
releaseCount = releaseCount = PR_ATOMIC_SET(&self->mNativeEventScheduledDepth,
PR_ATOMIC_SET(&self->mNativeEventScheduledDepth, self->mNativeEventCallbackDepth); self->mNativeEventCallbackDepth);
} }
while (releaseCount-- > self->mNativeEventCallbackDepth) self->Release(); while (releaseCount-- > self->mNativeEventCallbackDepth) self->Release();
} else { } else {
@ -651,10 +674,10 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
if (mTerminated) return false; if (mTerminated) return false;
// Do not call -[NSApplication nextEventMatchingMask:...] when we're trying to close a native // Do not call -[NSApplication nextEventMatchingMask:...] when we're trying to
// menu. Doing so could confuse the NSMenu's closing mechanism. Instead, we try to unwind the // close a native menu. Doing so could confuse the NSMenu's closing mechanism.
// stack as quickly as possible and return to the parent event loop. At that point, native events // Instead, we try to unwind the stack as quickly as possible and return to
// will be processed. // the parent event loop. At that point, native events will be processed.
if (MOZMenuOpeningCoordinator.needToUnwindForMenuClosing) { if (MOZMenuOpeningCoordinator.needToUnwindForMenuClosing) {
return false; return false;
} }
@ -700,12 +723,13 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
} }
} else { } else {
// In at least 10.15, AcquireFirstMatchingEventInQueue will move 1 // In at least 10.15, AcquireFirstMatchingEventInQueue will move 1
// CGEvent from the CGEvent queue into the Carbon event queue. Unfortunately, // CGEvent from the CGEvent queue into the Carbon event queue.
// once an event has been moved to the Carbon event queue it's no longer a // Unfortunately, once an event has been moved to the Carbon event queue
// candidate for coalescing. This means that even if we don't remove the // it's no longer a candidate for coalescing. This means that even if we
// event from the queue, just calling AcquireFirstMatchingEventInQueue can // don't remove the event from the queue, just calling
// cause behaviour change. Prior to bug 1690687 landing, the event that we got // AcquireFirstMatchingEventInQueue can cause behaviour change. Prior to
// from AcquireFirstMatchingEventInQueue was often our own ApplicationDefined // bug 1690687 landing, the event that we got from
// AcquireFirstMatchingEventInQueue was often our own ApplicationDefined
// event. However, once we stopped posting that event on every Gecko // event. However, once we stopped posting that event on every Gecko
// event we're much more likely to get a CGEvent. When we have a high // event we're much more likely to get a CGEvent. When we have a high
// amount of load on the main thread, we end up alternating between Gecko // amount of load on the main thread, we end up alternating between Gecko
@ -719,8 +743,8 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
// AcquireFirstMatchingEventInQueue() doesn't spin the (native) event // AcquireFirstMatchingEventInQueue() doesn't spin the (native) event
// loop, though it does queue up any newly available events from the // loop, though it does queue up any newly available events from the
// window server. // window server.
EventRef currentEvent = EventRef currentEvent = AcquireFirstMatchingEventInQueue(
AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL, kEventQueueOptionsNone); currentEventQueue, 0, NULL, kEventQueueOptionsNone);
if (!currentEvent) { if (!currentEvent) {
continue; continue;
} }
@ -729,7 +753,8 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
UInt32 eventClass = GetEventClass(currentEvent); UInt32 eventClass = GetEventClass(currentEvent);
bool osCocoaEvent = bool osCocoaEvent =
((eventClass == 'appl') || (eventClass == kEventClassAppleEvent) || ((eventClass == 'appl') || (eventClass == kEventClassAppleEvent) ||
((eventClass == 'cgs ') && (eventKind != NSEventTypeApplicationDefined))); ((eventClass == 'cgs ') &&
(eventKind != NSEventTypeApplicationDefined)));
// If attrs is kEventAttributeUserEvent or kEventAttributeMonitored // If attrs is kEventAttributeUserEvent or kEventAttributeMonitored
// (i.e. a user input event), we shouldn't process it here while // (i.e. a user input event), we shouldn't process it here while
// aMayWait is false. Likewise if currentEvent will eventually be // aMayWait is false. Likewise if currentEvent will eventually be
@ -761,8 +786,9 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
} while (mRunningEventLoop); } while (mRunningEventLoop);
if (eventProcessed) { if (eventProcessed) {
moreEvents = (AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL, moreEvents =
kEventQueueOptionsNone) != NULL); (AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL,
kEventQueueOptionsNone) != NULL);
} }
mRunningEventLoop = wasRunningEventLoop; mRunningEventLoop = wasRunningEventLoop;
@ -790,7 +816,9 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
// (Ventura) than on other versions of macOS. So we only use this hack on // (Ventura) than on other versions of macOS. So we only use this hack on
// macOS 13 and up. // macOS 13 and up.
static void PinSidecarCoreTextCStringSections() { static void PinSidecarCoreTextCStringSections() {
if (!dlopen("/System/Library/PrivateFrameworks/SidecarCore.framework/SidecarCore", RTLD_LAZY)) { if (!dlopen(
"/System/Library/PrivateFrameworks/SidecarCore.framework/SidecarCore",
RTLD_LAZY)) {
return; return;
} }
@ -798,7 +826,8 @@ static void PinSidecarCoreTextCStringSections() {
// normally runs automatically on the first Cmd-key combination. // normally runs automatically on the first Cmd-key combination.
Class displayManagerClass = NSClassFromString(@"SidecarDisplayManager"); Class displayManagerClass = NSClassFromString(@"SidecarDisplayManager");
if ([displayManagerClass respondsToSelector:@selector(sharedManager)]) { if ([displayManagerClass respondsToSelector:@selector(sharedManager)]) {
id sharedManager = [displayManagerClass performSelector:@selector(sharedManager)]; id sharedManager =
[displayManagerClass performSelector:@selector(sharedManager)];
if ([sharedManager respondsToSelector:@selector(devices)]) { if ([sharedManager respondsToSelector:@selector(devices)]) {
[sharedManager performSelector:@selector(devices)]; [sharedManager performSelector:@selector(devices)];
} }
@ -877,7 +906,8 @@ nsAppShell::Exit(void) {
// [NSApp stop:], so we have to assume that one extra call to [NSApp stop:] // [NSApp stop:], so we have to assume that one extra call to [NSApp stop:]
// will do the job.) // will do the job.)
BOOL cocoaModal = [NSApp _isRunningModal]; BOOL cocoaModal = [NSApp _isRunningModal];
NS_ASSERTION(!cocoaModal, "Don't call nsAppShell::Exit() from a modal event loop!"); NS_ASSERTION(!cocoaModal,
"Don't call nsAppShell::Exit() from a modal event loop!");
if (cocoaModal) [NSApp stop:nullptr]; if (cocoaModal) [NSApp stop:nullptr];
[NSApp stop:nullptr]; [NSApp stop:nullptr];
@ -911,7 +941,8 @@ NS_IMETHODIMP
nsAppShell::OnProcessNextEvent(nsIThreadInternal* aThread, bool aMayWait) { nsAppShell::OnProcessNextEvent(nsIThreadInternal* aThread, bool aMayWait) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NS_ASSERTION(mAutoreleasePools, "No stack on which to store autorelease pool"); NS_ASSERTION(mAutoreleasePools,
"No stack on which to store autorelease pool");
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
::CFArrayAppendValue(mAutoreleasePools, pool); ::CFArrayAppendValue(mAutoreleasePools, pool);
@ -929,15 +960,17 @@ nsAppShell::OnProcessNextEvent(nsIThreadInternal* aThread, bool aMayWait) {
// //
// public // public
NS_IMETHODIMP NS_IMETHODIMP
nsAppShell::AfterProcessNextEvent(nsIThreadInternal* aThread, bool aEventWasProcessed) { nsAppShell::AfterProcessNextEvent(nsIThreadInternal* aThread,
bool aEventWasProcessed) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
CFIndex count = ::CFArrayGetCount(mAutoreleasePools); CFIndex count = ::CFArrayGetCount(mAutoreleasePools);
NS_ASSERTION(mAutoreleasePools && count, "Processed an event, but there's no autorelease pool?"); NS_ASSERTION(mAutoreleasePools && count,
"Processed an event, but there's no autorelease pool?");
const NSAutoreleasePool* pool = const NSAutoreleasePool* pool = static_cast<const NSAutoreleasePool*>(
static_cast<const NSAutoreleasePool*>(::CFArrayGetValueAtIndex(mAutoreleasePools, count - 1)); ::CFArrayGetValueAtIndex(mAutoreleasePools, count - 1));
::CFArrayRemoveValueAtIndex(mAutoreleasePools, count - 1); ::CFArrayRemoveValueAtIndex(mAutoreleasePools, count - 1);
[pool release]; [pool release];
@ -952,11 +985,11 @@ void nsAppShell::InitMemoryPressureObserver() {
// values. Hence this may need to be augmented with polling of the memory // values. Hence this may need to be augmented with polling of the memory
// pressure sysctls for lower latency reactions to OS memory pressure. This // pressure sysctls for lower latency reactions to OS memory pressure. This
// was also observed when using DISPATCH_QUEUE_PRIORITY_HIGH. // was also observed when using DISPATCH_QUEUE_PRIORITY_HIGH.
mMemoryPressureSource = mMemoryPressureSource = dispatch_source_create(
dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0, DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0,
DISPATCH_MEMORYPRESSURE_NORMAL | DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_NORMAL | DISPATCH_MEMORYPRESSURE_WARN |
DISPATCH_MEMORYPRESSURE_CRITICAL, DISPATCH_MEMORYPRESSURE_CRITICAL,
dispatch_get_main_queue()); dispatch_get_main_queue());
dispatch_source_set_event_handler(mMemoryPressureSource, ^{ dispatch_source_set_event_handler(mMemoryPressureSource, ^{
dispatch_source_memorypressure_flags_t pressureLevel = dispatch_source_memorypressure_flags_t pressureLevel =
@ -971,7 +1004,8 @@ void nsAppShell::InitMemoryPressureObserver() {
nsAvailableMemoryWatcherBase::GetSingleton()); nsAvailableMemoryWatcherBase::GetSingleton());
} }
void nsAppShell::OnMemoryPressureChanged(dispatch_source_memorypressure_flags_t aPressureLevel) { void nsAppShell::OnMemoryPressureChanged(
dispatch_source_memorypressure_flags_t aPressureLevel) {
// The memory pressure dispatch source is created (above) with // The memory pressure dispatch source is created (above) with
// dispatch_get_main_queue() which always fires on the main thread. // dispatch_get_main_queue() which always fires on the main thread.
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
@ -1008,18 +1042,21 @@ void nsAppShell::OnMemoryPressureChanged(dispatch_source_memorypressure_flags_t
if ((self = [self init])) { if ((self = [self init])) {
mAppShell = aAppShell; mAppShell = aAppShell;
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter]
selector:@selector(applicationWillTerminate:) addObserver:self
name:NSApplicationWillTerminateNotification selector:@selector(applicationWillTerminate:)
object:NSApp]; name:NSApplicationWillTerminateNotification
[[NSNotificationCenter defaultCenter] addObserver:self object:NSApp];
selector:@selector(applicationDidBecomeActive:) [[NSNotificationCenter defaultCenter]
name:NSApplicationDidBecomeActiveNotification addObserver:self
object:NSApp]; selector:@selector(applicationDidBecomeActive:)
[[NSNotificationCenter defaultCenter] addObserver:self name:NSApplicationDidBecomeActiveNotification
selector:@selector(timezoneChanged:) object:NSApp];
name:NSSystemTimeZoneDidChangeNotification [[NSNotificationCenter defaultCenter]
object:nil]; addObserver:self
selector:@selector(timezoneChanged:)
name:NSSystemTimeZoneDidChangeNotification
object:nil];
} }
return self; return self;
@ -1061,12 +1098,14 @@ void nsAppShell::OnMemoryPressureChanged(dispatch_source_memorypressure_flags_t
NSEvent* currentEvent = [NSApp currentEvent]; NSEvent* currentEvent = [NSApp currentEvent];
if (currentEvent) { if (currentEvent) {
TextInputHandler::sLastModifierState = TextInputHandler::sLastModifierState =
[currentEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; [currentEvent modifierFlags] &
NSEventModifierFlagDeviceIndependentFlagsMask;
} }
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) { if (observerService) {
observerService->NotifyObservers(nullptr, NS_WIDGET_MAC_APP_ACTIVATE_OBSERVER_TOPIC, nullptr); observerService->NotifyObservers(
nullptr, NS_WIDGET_MAC_APP_ACTIVATE_OBSERVER_TOPIC, nullptr);
} }
NS_OBJC_END_TRY_IGNORE_BLOCK; NS_OBJC_END_TRY_IGNORE_BLOCK;
@ -1111,8 +1150,9 @@ void nsAppShell::OnMemoryPressureChanged(dispatch_source_memorypressure_flags_t
// in XRE_Main(), which in particular means that ScopedXPCOMStartup's destructor // in XRE_Main(), which in particular means that ScopedXPCOMStartup's destructor
// and NS_ShutdownXPCOM() never get called. // and NS_ShutdownXPCOM() never get called.
- (void)nsAppShell_NSApplication_terminate:(id)sender { - (void)nsAppShell_NSApplication_terminate:(id)sender {
[[NSNotificationCenter defaultCenter] postNotificationName:NSApplicationWillTerminateNotification [[NSNotificationCenter defaultCenter]
object:NSApp]; postNotificationName:NSApplicationWillTerminateNotification
object:NSApp];
} }
@end @end

File diff suppressed because it is too large Load diff

View file

@ -32,9 +32,10 @@ mozilla::StaticRefPtr<nsITransferable> nsClipboard::sSelectionCache;
int32_t nsClipboard::sSelectionCacheChangeCount = 0; int32_t nsClipboard::sSelectionCacheChangeCount = 0;
nsClipboard::nsClipboard() nsClipboard::nsClipboard()
: nsBaseClipboard(mozilla::dom::ClipboardCapabilities(false /* supportsSelectionClipboard */, : nsBaseClipboard(mozilla::dom::ClipboardCapabilities(
true /* supportsFindClipboard */, false /* supportsSelectionClipboard */,
true /* supportsSelectionCache */)) {} true /* supportsFindClipboard */,
true /* supportsSelectionCache */)) {}
nsClipboard::~nsClipboard() { ClearSelectionCache(); } nsClipboard::~nsClipboard() { ClearSelectionCache(); }
@ -45,15 +46,16 @@ namespace {
// We separate this into its own function because after an @try, all local // We separate this into its own function because after an @try, all local
// variables within that function get marked as volatile, and our C++ type // variables within that function get marked as volatile, and our C++ type
// system doesn't like volatile things. // system doesn't like volatile things.
static NSData* GetDataFromPasteboard(NSPasteboard* aPasteboard, NSString* aType) { static NSData* GetDataFromPasteboard(NSPasteboard* aPasteboard,
NSString* aType) {
NSData* data = nil; NSData* data = nil;
@try { @try {
data = [aPasteboard dataForType:aType]; data = [aPasteboard dataForType:aType];
} @catch (NSException* e) { } @catch (NSException* e) {
NS_WARNING( NS_WARNING(nsPrintfCString("Exception raised while getting data from the "
nsPrintfCString("Exception raised while getting data from the pasteboard: \"%s - %s\"", "pasteboard: \"%s - %s\"",
[[e name] UTF8String], [[e reason] UTF8String]) [[e name] UTF8String], [[e reason] UTF8String])
.get()); .get());
mozilla::Unused << e; mozilla::Unused << e;
} }
return data; return data;
@ -80,7 +82,8 @@ void nsClipboard::SetSelectionCache(nsITransferable* aTransferable) {
void nsClipboard::ClearSelectionCache() { SetSelectionCache(nullptr); } void nsClipboard::ClearSelectionCache() { SetSelectionCache(nullptr); }
NS_IMETHODIMP NS_IMETHODIMP
nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboardOwner* aOwner, nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable,
nsIClipboardOwner* aOwner,
int32_t aWhichClipboard) { int32_t aWhichClipboard) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
@ -92,7 +95,8 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboard
return NS_OK; return NS_OK;
} }
NSDictionary* pasteboardOutputDict = PasteboardDictFromTransferable(aTransferable); NSDictionary* pasteboardOutputDict =
PasteboardDictFromTransferable(aTransferable);
if (!pasteboardOutputDict) return NS_ERROR_FAILURE; if (!pasteboardOutputDict) return NS_ERROR_FAILURE;
unsigned int outputCount = [pasteboardOutputDict count]; unsigned int outputCount = [pasteboardOutputDict count];
@ -100,8 +104,10 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboard
NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard); NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard);
MOZ_ASSERT(cocoaPasteboard); MOZ_ASSERT(cocoaPasteboard);
if (aWhichClipboard == kFindClipboard) { if (aWhichClipboard == kFindClipboard) {
NSString* stringType = [UTIHelper stringFromPboardType:NSPasteboardTypeString]; NSString* stringType =
[cocoaPasteboard declareTypes:[NSArray arrayWithObject:stringType] owner:nil]; [UTIHelper stringFromPboardType:NSPasteboardTypeString];
[cocoaPasteboard declareTypes:[NSArray arrayWithObject:stringType]
owner:nil];
} else { } else {
// Write everything else out to the general pasteboard. // Write everything else out to the general pasteboard.
MOZ_ASSERT(aWhichClipboard == kGlobalClipboard); MOZ_ASSERT(aWhichClipboard == kGlobalClipboard);
@ -112,32 +118,48 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboard
NSString* currentKey = [outputKeys objectAtIndex:i]; NSString* currentKey = [outputKeys objectAtIndex:i];
id currentValue = [pasteboardOutputDict valueForKey:currentKey]; id currentValue = [pasteboardOutputDict valueForKey:currentKey];
if (aWhichClipboard == kFindClipboard) { if (aWhichClipboard == kFindClipboard) {
if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeString]]) { if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:
NSPasteboardTypeString]]) {
[cocoaPasteboard setString:currentValue forType:currentKey]; [cocoaPasteboard setString:currentValue forType:currentKey];
} }
} else { } else {
if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeString]] || if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:
[currentKey isEqualToString:[UTIHelper stringFromPboardType:kPublicUrlPboardType]] || NSPasteboardTypeString]] ||
[currentKey isEqualToString:[UTIHelper stringFromPboardType:kPublicUrlNamePboardType]]) { [currentKey
isEqualToString:[UTIHelper
stringFromPboardType:kPublicUrlPboardType]] ||
[currentKey
isEqualToString:
[UTIHelper stringFromPboardType:kPublicUrlNamePboardType]]) {
[cocoaPasteboard setString:currentValue forType:currentKey]; [cocoaPasteboard setString:currentValue forType:currentKey];
} else if ([currentKey } else if ([currentKey
isEqualToString:[UTIHelper stringFromPboardType:kUrlsWithTitlesPboardType]]) { isEqualToString:
[cocoaPasteboard setPropertyList:[pasteboardOutputDict valueForKey:currentKey] [UTIHelper
forType:currentKey]; stringFromPboardType:kUrlsWithTitlesPboardType]]) {
[cocoaPasteboard
setPropertyList:[pasteboardOutputDict valueForKey:currentKey]
forType:currentKey];
} else if ([currentKey } else if ([currentKey
isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeHTML]]) { isEqualToString:[UTIHelper stringFromPboardType:
[cocoaPasteboard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue)) NSPasteboardTypeHTML]]) {
forType:currentKey]; [cocoaPasteboard
setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
forType:currentKey];
} else if ([currentKey } else if ([currentKey
isEqualToString:[UTIHelper stringFromPboardType:kMozFileUrlsPboardType]]) { isEqualToString:[UTIHelper stringFromPboardType:
kMozFileUrlsPboardType]]) {
[cocoaPasteboard writeObjects:currentValue]; [cocoaPasteboard writeObjects:currentValue];
} else if ([currentKey } else if ([currentKey
isEqualToString:[UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]]) { isEqualToString:
[UTIHelper
stringFromPboardType:(NSString*)kUTTypeFileURL]]) {
[cocoaPasteboard setString:currentValue forType:currentKey]; [cocoaPasteboard setString:currentValue forType:currentKey];
} else if ([currentKey } else if ([currentKey
isEqualToString:[UTIHelper stringFromPboardType:kPasteboardConcealedType]]) { isEqualToString:
// It's fine to set the data to null for this field - this field is an addition [UTIHelper
// to a value's other type and works like a flag. stringFromPboardType:kPasteboardConcealedType]]) {
// It's fine to set the data to null for this field - this field is an
// addition to a value's other type and works like a flag.
[cocoaPasteboard setData:NULL forType:currentKey]; [cocoaPasteboard setData:NULL forType:currentKey];
} else { } else {
[cocoaPasteboard setData:currentValue forType:currentKey]; [cocoaPasteboard setData:currentValue forType:currentKey];
@ -150,12 +172,12 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboard
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
} }
nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable, nsresult nsClipboard::TransferableFromPasteboard(
NSPasteboard* cocoaPasteboard) { nsITransferable* aTransferable, NSPasteboard* cocoaPasteboard) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
// get flavor list that includes all acceptable flavors (including ones obtained through // get flavor list that includes all acceptable flavors (including ones
// conversion) // obtained through conversion)
nsTArray<nsCString> flavors; nsTArray<nsCString> flavors;
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors); nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
if (NS_FAILED(rv)) return NS_ERROR_FAILURE; if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
@ -173,8 +195,8 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
} }
NSData* stringData; NSData* stringData;
bool isRTF = bool isRTF = [pboardType
[pboardType isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeRTF]]; isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeRTF]];
if (isRTF) { if (isRTF) {
stringData = [pString dataUsingEncoding:NSASCIIStringEncoding]; stringData = [pString dataUsingEncoding:NSASCIIStringEncoding];
} else { } else {
@ -187,23 +209,25 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
} }
[stringData getBytes:clipboardDataPtr length:dataLength]; [stringData getBytes:clipboardDataPtr length:dataLength];
// The DOM only wants LF, so convert from MacOS line endings to DOM line endings. // The DOM only wants LF, so convert from MacOS line endings to DOM line
// endings.
int32_t signedDataLength = dataLength; int32_t signedDataLength = dataLength;
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(isRTF, &clipboardDataPtr, nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(
&signedDataLength); isRTF, &clipboardDataPtr, &signedDataLength);
dataLength = signedDataLength; dataLength = signedDataLength;
// skip BOM (Byte Order Mark to distinguish little or big endian) // skip BOM (Byte Order Mark to distinguish little or big endian)
char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr; char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
if ((dataLength > 2) && if ((dataLength > 2) && ((clipboardDataPtrNoBOM[0] == 0xFEFF) ||
((clipboardDataPtrNoBOM[0] == 0xFEFF) || (clipboardDataPtrNoBOM[0] == 0xFFFE))) { (clipboardDataPtrNoBOM[0] == 0xFFFE))) {
dataLength -= sizeof(char16_t); dataLength -= sizeof(char16_t);
clipboardDataPtrNoBOM += 1; clipboardDataPtrNoBOM += 1;
} }
nsCOMPtr<nsISupports> genericDataWrapper; nsCOMPtr<nsISupports> genericDataWrapper;
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength, nsPrimitiveHelpers::CreatePrimitiveForData(
getter_AddRefs(genericDataWrapper)); flavorStr, clipboardDataPtrNoBOM, dataLength,
getter_AddRefs(genericDataWrapper));
aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper); aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
free(clipboardDataPtr); free(clipboardDataPtr);
break; break;
@ -220,11 +244,14 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
continue; continue;
} }
nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable, flavorStr, item); nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable,
flavorStr, item);
} else if (flavorStr.EqualsLiteral(kCustomTypesMime)) { } else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
NSString* type = [cocoaPasteboard NSString* type = [cocoaPasteboard
availableTypeFromArray: availableTypeFromArray:
[NSArray arrayWithObject:[UTIHelper stringFromPboardType:kMozCustomTypesPboardType]]]; [NSArray
arrayWithObject:[UTIHelper stringFromPboardType:
kMozCustomTypesPboardType]]];
if (!type) { if (!type) {
continue; continue;
} }
@ -242,19 +269,26 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
[pasteboardData getBytes:clipboardDataPtr length:dataLength]; [pasteboardData getBytes:clipboardDataPtr length:dataLength];
nsCOMPtr<nsISupports> genericDataWrapper; nsCOMPtr<nsISupports> genericDataWrapper;
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtr, dataLength, nsPrimitiveHelpers::CreatePrimitiveForData(
getter_AddRefs(genericDataWrapper)); flavorStr, clipboardDataPtr, dataLength,
getter_AddRefs(genericDataWrapper));
aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper); aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
free(clipboardDataPtr); free(clipboardDataPtr);
} else if (flavorStr.EqualsLiteral(kJPEGImageMime) || flavorStr.EqualsLiteral(kJPGImageMime) || } else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime)) { flavorStr.EqualsLiteral(kJPGImageMime) ||
flavorStr.EqualsLiteral(kPNGImageMime) ||
flavorStr.EqualsLiteral(kGIFImageMime)) {
// Figure out if there's data on the pasteboard we can grab (sanity check) // Figure out if there's data on the pasteboard we can grab (sanity check)
NSString* type = [cocoaPasteboard NSString* type = [cocoaPasteboard
availableTypeFromArray: availableTypeFromArray:
[NSArray arrayWithObjects:[UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL], [NSArray
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF], arrayWithObjects:
[UTIHelper stringFromPboardType:NSPasteboardTypePNG], nil]]; [UTIHelper
stringFromPboardType:(NSString*)kUTTypeFileURL],
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
[UTIHelper stringFromPboardType:NSPasteboardTypePNG],
nil]];
if (!type) continue; if (!type) continue;
// Read data off the clipboard // Read data off the clipboard
@ -263,7 +297,8 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
// Figure out what type we're converting to // Figure out what type we're converting to
CFStringRef outputType = NULL; CFStringRef outputType = NULL;
if (flavorStr.EqualsLiteral(kJPEGImageMime) || flavorStr.EqualsLiteral(kJPGImageMime)) if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
flavorStr.EqualsLiteral(kJPGImageMime))
outputType = CFSTR("public.jpeg"); outputType = CFSTR("public.jpeg");
else if (flavorStr.EqualsLiteral(kPNGImageMime)) else if (flavorStr.EqualsLiteral(kPNGImageMime))
outputType = CFSTR("public.png"); outputType = CFSTR("public.png");
@ -276,20 +311,23 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
// Note that ImageIO, like all CF APIs, allows NULLs to propagate freely // Note that ImageIO, like all CF APIs, allows NULLs to propagate freely
// and safely in most cases (like ObjC). A notable exception is CFRelease. // and safely in most cases (like ObjC). A notable exception is CFRelease.
NSDictionary* options = [NSDictionary NSDictionary* options = [NSDictionary
dictionaryWithObjectsAndKeys:(NSNumber*)kCFBooleanTrue, kCGImageSourceShouldAllowFloat, dictionaryWithObjectsAndKeys:(NSNumber*)kCFBooleanTrue,
type, kCGImageSourceTypeIdentifierHint, nil]; kCGImageSourceShouldAllowFloat, type,
kCGImageSourceTypeIdentifierHint, nil];
CGImageSourceRef source = nullptr; CGImageSourceRef source = nullptr;
if (type == [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]) { if (type == [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]) {
NSString* urlStr = [cocoaPasteboard stringForType:type]; NSString* urlStr = [cocoaPasteboard stringForType:type];
NSURL* url = [NSURL URLWithString:urlStr]; NSURL* url = [NSURL URLWithString:urlStr];
source = CGImageSourceCreateWithURL((CFURLRef)url, (CFDictionaryRef)options); source =
CGImageSourceCreateWithURL((CFURLRef)url, (CFDictionaryRef)options);
} else { } else {
source = CGImageSourceCreateWithData((CFDataRef)pasteboardData, (CFDictionaryRef)options); source = CGImageSourceCreateWithData((CFDataRef)pasteboardData,
(CFDictionaryRef)options);
} }
NSMutableData* encodedData = [NSMutableData data]; NSMutableData* encodedData = [NSMutableData data];
CGImageDestinationRef dest = CGImageDestinationRef dest = CGImageDestinationCreateWithData(
CGImageDestinationCreateWithData((CFMutableDataRef)encodedData, outputType, 1, NULL); (CFMutableDataRef)encodedData, outputType, 1, NULL);
CGImageDestinationAddImageFromSource(dest, source, 0, NULL); CGImageDestinationAddImageFromSource(dest, source, 0, NULL);
bool successfullyConverted = CGImageDestinationFinalize(dest); bool successfullyConverted = CGImageDestinationFinalize(dest);
@ -297,7 +335,8 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
// Put the converted data in a form Gecko can understand // Put the converted data in a form Gecko can understand
nsCOMPtr<nsIInputStream> byteStream; nsCOMPtr<nsIInputStream> byteStream;
NS_NewByteInputStream(getter_AddRefs(byteStream), NS_NewByteInputStream(getter_AddRefs(byteStream),
mozilla::Span((const char*)[encodedData bytes], [encodedData length]), mozilla::Span((const char*)[encodedData bytes],
[encodedData length]),
NS_ASSIGNMENT_COPY); NS_ASSIGNMENT_COPY);
aTransferable->SetTransferData(flavorStr.get(), byteStream); aTransferable->SetTransferData(flavorStr.get(), byteStream);
@ -321,19 +360,21 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
} }
NS_IMETHODIMP NS_IMETHODIMP
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard) { nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable,
int32_t aWhichClipboard) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
MOZ_DIAGNOSTIC_ASSERT(aTransferable); MOZ_DIAGNOSTIC_ASSERT(aTransferable);
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)); MOZ_DIAGNOSTIC_ASSERT(
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
if (kSelectionCache == aWhichClipboard) { if (kSelectionCache == aWhichClipboard) {
if (!sSelectionCache) { if (!sSelectionCache) {
return NS_OK; return NS_OK;
} }
// get flavor list that includes all acceptable flavors (including ones obtained through // get flavor list that includes all acceptable flavors (including ones
// conversion) // obtained through conversion)
nsTArray<nsCString> flavors; nsTArray<nsCString> flavors;
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors); nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
@ -342,7 +383,8 @@ nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhi
for (const auto& flavor : flavors) { for (const auto& flavor : flavors) {
nsCOMPtr<nsISupports> dataSupports; nsCOMPtr<nsISupports> dataSupports;
rv = sSelectionCache->GetTransferData(flavor.get(), getter_AddRefs(dataSupports)); rv = sSelectionCache->GetTransferData(flavor.get(),
getter_AddRefs(dataSupports));
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
CLIPBOARD_LOG("%s: getting %s from cache.", __FUNCTION__, flavor.get()); CLIPBOARD_LOG("%s: getting %s from cache.", __FUNCTION__, flavor.get());
aTransferable->SetTransferData(flavor.get(), dataSupports); aTransferable->SetTransferData(flavor.get(), dataSupports);
@ -364,18 +406,22 @@ nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhi
} }
// returns true if we have *any* of the passed in flavors available for pasting // returns true if we have *any* of the passed in flavors available for pasting
mozilla::Result<bool, nsresult> nsClipboard::HasNativeClipboardDataMatchingFlavors( mozilla::Result<bool, nsresult>
nsClipboard::HasNativeClipboardDataMatchingFlavors(
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard) { const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)); MOZ_DIAGNOSTIC_ASSERT(
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
if (kSelectionCache == aWhichClipboard) { if (kSelectionCache == aWhichClipboard) {
nsTArray<nsCString> transferableFlavors; nsTArray<nsCString> transferableFlavors;
if (sSelectionCache && if (sSelectionCache &&
NS_SUCCEEDED(sSelectionCache->FlavorsTransferableCanImport(transferableFlavors))) { NS_SUCCEEDED(sSelectionCache->FlavorsTransferableCanImport(
transferableFlavors))) {
if (CLIPBOARD_LOG_ENABLED()) { if (CLIPBOARD_LOG_ENABLED()) {
CLIPBOARD_LOG(" SelectionCache types (nums %zu)\n", transferableFlavors.Length()); CLIPBOARD_LOG(" SelectionCache types (nums %zu)\n",
transferableFlavors.Length());
for (const auto& transferableFlavor : transferableFlavors) { for (const auto& transferableFlavor : transferableFlavors) {
CLIPBOARD_LOG(" MIME %s", transferableFlavor.get()); CLIPBOARD_LOG(" MIME %s", transferableFlavor.get());
} }
@ -417,8 +463,8 @@ mozilla::Result<bool, nsresult> nsClipboard::HasNativeClipboardDataMatchingFlavo
for (auto& mimeType : aFlavorList) { for (auto& mimeType : aFlavorList) {
NSString* pboardType = nil; NSString* pboardType = nil;
if (nsClipboard::IsStringType(mimeType, &pboardType)) { if (nsClipboard::IsStringType(mimeType, &pboardType)) {
NSString* availableType = NSString* availableType = [cocoaPasteboard
[cocoaPasteboard availableTypeFromArray:[NSArray arrayWithObject:pboardType]]; availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
if (availableType && [availableType isEqualToString:pboardType]) { if (availableType && [availableType isEqualToString:pboardType]) {
CLIPBOARD_LOG(" has %s\n", mimeType.get()); CLIPBOARD_LOG(" has %s\n", mimeType.get());
return true; return true;
@ -426,17 +472,24 @@ mozilla::Result<bool, nsresult> nsClipboard::HasNativeClipboardDataMatchingFlavo
} else if (mimeType.EqualsLiteral(kCustomTypesMime)) { } else if (mimeType.EqualsLiteral(kCustomTypesMime)) {
NSString* availableType = [cocoaPasteboard NSString* availableType = [cocoaPasteboard
availableTypeFromArray: availableTypeFromArray:
[NSArray arrayWithObject:[UTIHelper stringFromPboardType:kMozCustomTypesPboardType]]]; [NSArray
arrayWithObject:[UTIHelper stringFromPboardType:
kMozCustomTypesPboardType]]];
if (availableType) { if (availableType) {
CLIPBOARD_LOG(" has %s\n", mimeType.get()); CLIPBOARD_LOG(" has %s\n", mimeType.get());
return true; return true;
} }
} else if (mimeType.EqualsLiteral(kJPEGImageMime) || mimeType.EqualsLiteral(kJPGImageMime) || } else if (mimeType.EqualsLiteral(kJPEGImageMime) ||
mimeType.EqualsLiteral(kPNGImageMime) || mimeType.EqualsLiteral(kGIFImageMime)) { mimeType.EqualsLiteral(kJPGImageMime) ||
mimeType.EqualsLiteral(kPNGImageMime) ||
mimeType.EqualsLiteral(kGIFImageMime)) {
NSString* availableType = [cocoaPasteboard NSString* availableType = [cocoaPasteboard
availableTypeFromArray: availableTypeFromArray:
[NSArray arrayWithObjects:[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF], [NSArray
[UTIHelper stringFromPboardType:NSPasteboardTypePNG], nil]]; arrayWithObjects:
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
[UTIHelper stringFromPboardType:NSPasteboardTypePNG],
nil]];
if (availableType) { if (availableType) {
CLIPBOARD_LOG(" has %s\n", mimeType.get()); CLIPBOARD_LOG(" has %s\n", mimeType.get());
return true; return true;
@ -449,9 +502,11 @@ mozilla::Result<bool, nsresult> nsClipboard::HasNativeClipboardDataMatchingFlavo
if (NSPasteboardItem* item = [items objectAtIndex:0]) { if (NSPasteboardItem* item = [items objectAtIndex:0]) {
if (NSString *availableType = [item if (NSString *availableType = [item
availableTypeFromArray: availableTypeFromArray:
[NSArray arrayWithObjects:[UTIHelper [NSArray
stringFromPboardType:(NSString*)kUTTypeFileURL], arrayWithObjects:[UTIHelper
nil]]) { stringFromPboardType:
(NSString*)kUTTypeFileURL],
nil]]) {
CLIPBOARD_LOG(" has %s\n", mimeType.get()); CLIPBOARD_LOG(" has %s\n", mimeType.get());
return true; return true;
} }
@ -481,10 +536,10 @@ mozilla::Maybe<uint32_t> nsClipboard::FindIndexOfImageFlavor(
return mozilla::Nothing(); return mozilla::Nothing();
} }
// This function converts anything that other applications might understand into the system format // This function converts anything that other applications might understand into
// and puts it into a dictionary which it returns. // the system format and puts it into a dictionary which it returns. static
// static NSDictionary* nsClipboard::PasteboardDictFromTransferable(
NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable) { nsITransferable* aTransferable) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
if (!aTransferable) { if (!aTransferable) {
@ -499,29 +554,33 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
return nil; return nil;
} }
const mozilla::Maybe<uint32_t> imageFlavorIndex = nsClipboard::FindIndexOfImageFlavor(flavors); const mozilla::Maybe<uint32_t> imageFlavorIndex =
nsClipboard::FindIndexOfImageFlavor(flavors);
if (imageFlavorIndex) { if (imageFlavorIndex) {
// When right-clicking and "Copy Image" is clicked on macOS, some apps expect the // When right-clicking and "Copy Image" is clicked on macOS, some apps
// first flavor to be the image flavor. See bug 1689992. For other apps, the // expect the first flavor to be the image flavor. See bug 1689992. For
// order shouldn't matter. // other apps, the order shouldn't matter.
std::swap(*flavors.begin(), flavors[*imageFlavorIndex]); std::swap(*flavors.begin(), flavors[*imageFlavorIndex]);
} }
for (uint32_t i = 0; i < flavors.Length(); i++) { for (uint32_t i = 0; i < flavors.Length(); i++) {
nsCString& flavorStr = flavors[i]; nsCString& flavorStr = flavors[i];
CLIPBOARD_LOG("writing out clipboard data of type %s (%d)\n", flavorStr.get(), i); CLIPBOARD_LOG("writing out clipboard data of type %s (%d)\n",
flavorStr.get(), i);
NSString* pboardType = nil; NSString* pboardType = nil;
if (nsClipboard::IsStringType(flavorStr, &pboardType)) { if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
nsCOMPtr<nsISupports> genericDataWrapper; nsCOMPtr<nsISupports> genericDataWrapper;
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(genericDataWrapper)); rv = aTransferable->GetTransferData(flavorStr.get(),
getter_AddRefs(genericDataWrapper));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
continue; continue;
} }
nsAutoString data; nsAutoString data;
if (nsCOMPtr<nsISupportsString> text = do_QueryInterface(genericDataWrapper)) { if (nsCOMPtr<nsISupportsString> text =
do_QueryInterface(genericDataWrapper)) {
text->GetData(data); text->GetData(data);
} }
@ -540,26 +599,32 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
} }
if (aTransferable->GetIsPrivateData()) { if (aTransferable->GetIsPrivateData()) {
// In the case of password strings, we want to include the key for concealed type. // In the case of password strings, we want to include the key for
// These will be flagged as private data. // concealed type. These will be flagged as private data.
[pasteboardOutputDict setObject:nativeString [pasteboardOutputDict
forKey:[UTIHelper stringFromPboardType:kPasteboardConcealedType]]; setObject:nativeString
forKey:[UTIHelper
stringFromPboardType:kPasteboardConcealedType]];
} }
} else if (flavorStr.EqualsLiteral(kCustomTypesMime)) { } else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
nsCOMPtr<nsISupports> genericDataWrapper; nsCOMPtr<nsISupports> genericDataWrapper;
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(genericDataWrapper)); rv = aTransferable->GetTransferData(flavorStr.get(),
getter_AddRefs(genericDataWrapper));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
continue; continue;
} }
nsAutoCString data; nsAutoCString data;
if (nsCOMPtr<nsISupportsCString> text = do_QueryInterface(genericDataWrapper)) { if (nsCOMPtr<nsISupportsCString> text =
do_QueryInterface(genericDataWrapper)) {
text->GetData(data); text->GetData(data);
} }
if (!data.IsEmpty()) { if (!data.IsEmpty()) {
NSData* nativeData = [NSData dataWithBytes:data.get() length:data.Length()]; NSData* nativeData = [NSData dataWithBytes:data.get()
NSString* customType = [UTIHelper stringFromPboardType:kMozCustomTypesPboardType]; length:data.Length()];
NSString* customType =
[UTIHelper stringFromPboardType:kMozCustomTypesPboardType];
if (!nativeData) { if (!nativeData) {
continue; continue;
} }
@ -567,7 +632,8 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
} }
} else if (nsClipboard::IsImageType(flavorStr)) { } else if (nsClipboard::IsImageType(flavorStr)) {
nsCOMPtr<nsISupports> transferSupports; nsCOMPtr<nsISupports> transferSupports;
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(transferSupports)); rv = aTransferable->GetTransferData(flavorStr.get(),
getter_AddRefs(transferSupports));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
continue; continue;
} }
@ -578,9 +644,9 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
continue; continue;
} }
RefPtr<SourceSurface> surface = RefPtr<SourceSurface> surface = image->GetFrame(
image->GetFrame(imgIContainer::FRAME_CURRENT, imgIContainer::FRAME_CURRENT,
imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY); imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
if (!surface) { if (!surface) {
continue; continue;
} }
@ -592,8 +658,8 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
// Convert the CGImageRef to TIFF data. // Convert the CGImageRef to TIFF data.
CFMutableDataRef tiffData = CFDataCreateMutable(kCFAllocatorDefault, 0); CFMutableDataRef tiffData = CFDataCreateMutable(kCFAllocatorDefault, 0);
CGImageDestinationRef destRef = CGImageDestinationRef destRef = CGImageDestinationCreateWithData(
CGImageDestinationCreateWithData(tiffData, CFSTR("public.tiff"), 1, NULL); tiffData, CFSTR("public.tiff"), 1, NULL);
CGImageDestinationAddImage(destRef, imageRef, NULL); CGImageDestinationAddImage(destRef, imageRef, NULL);
bool successfullyConverted = CGImageDestinationFinalize(destRef); bool successfullyConverted = CGImageDestinationFinalize(destRef);
@ -609,12 +675,14 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
continue; continue;
} }
NSString* tiffType = [UTIHelper stringFromPboardType:NSPasteboardTypeTIFF]; NSString* tiffType =
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF];
[pasteboardOutputDict setObject:(NSMutableData*)tiffData forKey:tiffType]; [pasteboardOutputDict setObject:(NSMutableData*)tiffData forKey:tiffType];
CFRelease(tiffData); CFRelease(tiffData);
} else if (flavorStr.EqualsLiteral(kFileMime)) { } else if (flavorStr.EqualsLiteral(kFileMime)) {
nsCOMPtr<nsISupports> genericFile; nsCOMPtr<nsISupports> genericFile;
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(genericFile)); rv = aTransferable->GetTransferData(flavorStr.get(),
getter_AddRefs(genericFile));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
continue; continue;
} }
@ -635,18 +703,22 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
if (!url || ![url absoluteString]) { if (!url || ![url absoluteString]) {
continue; continue;
} }
NSString* fileUTType = [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]; NSString* fileUTType =
[UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL];
[pasteboardOutputDict setObject:[url absoluteString] forKey:fileUTType]; [pasteboardOutputDict setObject:[url absoluteString] forKey:fileUTType];
} else if (flavorStr.EqualsLiteral(kFilePromiseMime)) { } else if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
NSString* urlPromise = NSString* urlPromise = [UTIHelper
[UTIHelper stringFromPboardType:(NSString*)kPasteboardTypeFileURLPromise]; stringFromPboardType:(NSString*)kPasteboardTypeFileURLPromise];
NSString* urlPromiseContent = NSString* urlPromiseContent = [UTIHelper
[UTIHelper stringFromPboardType:(NSString*)kPasteboardTypeFilePromiseContent]; stringFromPboardType:(NSString*)kPasteboardTypeFilePromiseContent];
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""] forKey:urlPromise]; [pasteboardOutputDict setObject:[NSArray arrayWithObject:@""]
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""] forKey:urlPromiseContent]; forKey:urlPromise];
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""]
forKey:urlPromiseContent];
} else if (flavorStr.EqualsLiteral(kURLMime)) { } else if (flavorStr.EqualsLiteral(kURLMime)) {
nsCOMPtr<nsISupports> genericURL; nsCOMPtr<nsISupports> genericURL;
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(genericURL)); rv = aTransferable->GetTransferData(flavorStr.get(),
getter_AddRefs(genericURL));
nsCOMPtr<nsISupportsString> urlObject(do_QueryInterface(genericURL)); nsCOMPtr<nsISupportsString> urlObject(do_QueryInterface(genericURL));
nsAutoString url; nsAutoString url;
@ -662,10 +734,12 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
nsAutoString urlTitle; nsAutoString urlTitle;
urlObject->GetData(urlTitle); urlObject->GetData(urlTitle);
urlTitle.Mid(urlTitle, newlinePos + 1, urlTitle.Length() - (newlinePos + 1)); urlTitle.Mid(urlTitle, newlinePos + 1,
urlTitle.Length() - (newlinePos + 1));
nativeTitle = nativeTitle =
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(urlTitle.get()) [NSString stringWithCharacters:reinterpret_cast<const unichar*>(
urlTitle.get())
length:urlTitle.Length()]; length:urlTitle.Length()];
} }
// The Finder doesn't like getting random binary data aka // The Finder doesn't like getting random binary data aka
@ -673,24 +747,29 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
// ASCII. // ASCII.
nsAutoCString utf8Data = NS_ConvertUTF16toUTF8(url.get(), url.Length()); nsAutoCString utf8Data = NS_ConvertUTF16toUTF8(url.get(), url.Length());
nsAutoCString escData; nsAutoCString escData;
NS_EscapeURL(utf8Data.get(), utf8Data.Length(), esc_OnlyNonASCII | esc_AlwaysCopy, escData); NS_EscapeURL(utf8Data.get(), utf8Data.Length(),
esc_OnlyNonASCII | esc_AlwaysCopy, escData);
NSString* nativeURL = [NSString stringWithUTF8String:escData.get()]; NSString* nativeURL = [NSString stringWithUTF8String:escData.get()];
NSString* publicUrl = [UTIHelper stringFromPboardType:kPublicUrlPboardType]; NSString* publicUrl =
[UTIHelper stringFromPboardType:kPublicUrlPboardType];
if (!nativeURL) { if (!nativeURL) {
continue; continue;
} }
[pasteboardOutputDict setObject:nativeURL forKey:publicUrl]; [pasteboardOutputDict setObject:nativeURL forKey:publicUrl];
if (nativeTitle) { if (nativeTitle) {
NSArray* urlsAndTitles = @[ @[ nativeURL ], @[ nativeTitle ] ]; NSArray* urlsAndTitles = @[ @[ nativeURL ], @[ nativeTitle ] ];
NSString* urlName = [UTIHelper stringFromPboardType:kPublicUrlNamePboardType]; NSString* urlName =
NSString* urlsWithTitles = [UTIHelper stringFromPboardType:kUrlsWithTitlesPboardType]; [UTIHelper stringFromPboardType:kPublicUrlNamePboardType];
NSString* urlsWithTitles =
[UTIHelper stringFromPboardType:kUrlsWithTitlesPboardType];
[pasteboardOutputDict setObject:nativeTitle forKey:urlName]; [pasteboardOutputDict setObject:nativeTitle forKey:urlName];
[pasteboardOutputDict setObject:urlsAndTitles forKey:urlsWithTitles]; [pasteboardOutputDict setObject:urlsAndTitles forKey:urlsWithTitles];
} }
} }
// If it wasn't a type that we recognize as exportable we don't put it on the system // If it wasn't a type that we recognize as exportable we don't put it on
// clipboard. We'll just access it from our cached transferable when we need it. // the system clipboard. We'll just access it from our cached transferable
// when we need it.
} }
return pasteboardOutputDict; return pasteboardOutputDict;
@ -698,7 +777,8 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
NS_OBJC_END_TRY_BLOCK_RETURN(nil); NS_OBJC_END_TRY_BLOCK_RETURN(nil);
} }
bool nsClipboard::IsStringType(const nsCString& aMIMEType, NSString** aPboardType) { bool nsClipboard::IsStringType(const nsCString& aMIMEType,
NSString** aPboardType) {
if (aMIMEType.EqualsLiteral(kTextMime)) { if (aMIMEType.EqualsLiteral(kTextMime)) {
*aPboardType = [UTIHelper stringFromPboardType:NSPasteboardTypeString]; *aPboardType = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
return true; return true;
@ -715,29 +795,33 @@ bool nsClipboard::IsStringType(const nsCString& aMIMEType, NSString** aPboardTyp
// static // static
bool nsClipboard::IsImageType(const nsACString& aMIMEType) { bool nsClipboard::IsImageType(const nsACString& aMIMEType) {
return aMIMEType.EqualsLiteral(kPNGImageMime) || aMIMEType.EqualsLiteral(kJPEGImageMime) || return aMIMEType.EqualsLiteral(kPNGImageMime) ||
aMIMEType.EqualsLiteral(kJPGImageMime) || aMIMEType.EqualsLiteral(kGIFImageMime) || aMIMEType.EqualsLiteral(kJPEGImageMime) ||
aMIMEType.EqualsLiteral(kJPGImageMime) ||
aMIMEType.EqualsLiteral(kGIFImageMime) ||
aMIMEType.EqualsLiteral(kNativeImageMime); aMIMEType.EqualsLiteral(kNativeImageMime);
} }
NSString* nsClipboard::WrapHtmlForSystemPasteboard(NSString* aString) { NSString* nsClipboard::WrapHtmlForSystemPasteboard(NSString* aString) {
NSString* wrapped = [NSString NSString* wrapped =
stringWithFormat:@"<html>" [NSString stringWithFormat:@"<html>"
"<head>" "<head>"
"<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">" "<meta http-equiv=\"content-type\" "
"</head>" "content=\"text/html; charset=utf-8\">"
"<body>" "</head>"
"%@" "<body>"
"</body>" "%@"
"</html>", "</body>"
aString]; "</html>",
aString];
return wrapped; return wrapped;
} }
nsresult nsClipboard::EmptyNativeClipboardData(int32_t aWhichClipboard) { nsresult nsClipboard::EmptyNativeClipboardData(int32_t aWhichClipboard) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)); MOZ_DIAGNOSTIC_ASSERT(
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
if (kSelectionCache == aWhichClipboard) { if (kSelectionCache == aWhichClipboard) {
ClearSelectionCache(); ClearSelectionCache();
@ -753,11 +837,12 @@ nsresult nsClipboard::EmptyNativeClipboardData(int32_t aWhichClipboard) {
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
} }
mozilla::Result<int32_t, nsresult> nsClipboard::GetNativeClipboardSequenceNumber( mozilla::Result<int32_t, nsresult>
int32_t aWhichClipboard) { nsClipboard::GetNativeClipboardSequenceNumber(int32_t aWhichClipboard) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)); MOZ_DIAGNOSTIC_ASSERT(
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
if (kSelectionCache == aWhichClipboard) { if (kSelectionCache == aWhichClipboard) {
return sSelectionCacheChangeCount; return sSelectionCacheChangeCount;

View file

@ -38,7 +38,8 @@
/*static*/ int32_t nsCocoaFeatures::mOSVersion = 0; /*static*/ int32_t nsCocoaFeatures::mOSVersion = 0;
// This should not be called with unchecked aMajor, which should be >= 10. // This should not be called with unchecked aMajor, which should be >= 10.
inline int32_t AssembleVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix) { inline int32_t AssembleVersion(int32_t aMajor, int32_t aMinor,
int32_t aBugFix) {
MOZ_ASSERT(aMajor >= 10); MOZ_ASSERT(aMajor >= 10);
return (aMajor << 16) + (aMinor << 8) + aBugFix; return (aMajor << 16) + (aMinor << 8) + aBugFix;
} }
@ -65,11 +66,13 @@ static int intAtStringIndex(NSArray* array, int index) {
void nsCocoaFeatures::GetSystemVersion(int& major, int& minor, int& bugfix) { void nsCocoaFeatures::GetSystemVersion(int& major, int& minor, int& bugfix) {
major = minor = bugfix = 0; major = minor = bugfix = 0;
NSString* versionString = [[NSDictionary NSString* versionString =
dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"] [[NSDictionary dictionaryWithContentsOfFile:
objectForKey:@"ProductVersion"]; @"/System/Library/CoreServices/SystemVersion.plist"]
objectForKey:@"ProductVersion"];
if (!versionString) { if (!versionString) {
NS_ERROR("Couldn't read /System/Library/CoreServices/SystemVersion.plist to determine macOS " NS_ERROR("Couldn't read /System/Library/CoreServices/SystemVersion.plist "
"to determine macOS "
"version."); "version.");
return; return;
} }
@ -86,7 +89,8 @@ void nsCocoaFeatures::GetSystemVersion(int& major, int& minor, int& bugfix) {
} }
} }
int32_t nsCocoaFeatures::GetVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix) { int32_t nsCocoaFeatures::GetVersion(int32_t aMajor, int32_t aMinor,
int32_t aBugFix) {
int32_t macOSVersion; int32_t macOSVersion;
if (aMajor < 10) { if (aMajor < 10) {
aMajor = 10; aMajor = 10;
@ -148,7 +152,8 @@ int32_t nsCocoaFeatures::GetVersion(int32_t aMajor, int32_t aMinor, int32_t aBug
} }
/* static */ bool nsCocoaFeatures::OnSierraExactly() { /* static */ bool nsCocoaFeatures::OnSierraExactly() {
return (macOSVersion() >= MACOS_VERSION_10_12_HEX) && (macOSVersion() < MACOS_VERSION_10_13_HEX); return (macOSVersion() >= MACOS_VERSION_10_12_HEX) &&
(macOSVersion() < MACOS_VERSION_10_13_HEX);
} }
/* Version of OnSierraExactly as global function callable from cairo & skia */ /* Version of OnSierraExactly as global function callable from cairo & skia */
@ -195,7 +200,8 @@ bool Gecko_OnSierraExactly() { return nsCocoaFeatures::OnSierraExactly(); }
return (macOSVersion() >= MACOS_VERSION_13_0_HEX); return (macOSVersion() >= MACOS_VERSION_13_0_HEX);
} }
/* static */ bool nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor, int32_t aMinor, /* static */ bool nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor,
int32_t aMinor,
int32_t aBugFix) { int32_t aBugFix) {
return macOSVersion() >= GetVersion(aMajor, aMinor, aBugFix); return macOSVersion() >= GetVersion(aMajor, aMinor, aBugFix);
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -96,25 +96,30 @@ nsColorPicker::~nsColorPicker() {
// TODO(bug 1805397): Implement default colors // TODO(bug 1805397): Implement default colors
NS_IMETHODIMP NS_IMETHODIMP
nsColorPicker::Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle, nsColorPicker::Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
const nsAString& aInitialColor, const nsTArray<nsString>& aDefaultColors) { const nsAString& aInitialColor,
MOZ_ASSERT(NS_IsMainThread(), "Color pickers can only be opened from main thread currently"); const nsTArray<nsString>& aDefaultColors) {
MOZ_ASSERT(NS_IsMainThread(),
"Color pickers can only be opened from main thread currently");
mTitle = aTitle; mTitle = aTitle;
mColor = aInitialColor; mColor = aInitialColor;
mColorPanelWrapper = [[NSColorPanelWrapper alloc] initWithPicker:this]; mColorPanelWrapper = [[NSColorPanelWrapper alloc] initWithPicker:this];
return NS_OK; return NS_OK;
} }
/* static */ NSColor* nsColorPicker::GetNSColorFromHexString(const nsAString& aColor) { /* static */ NSColor* nsColorPicker::GetNSColorFromHexString(
const nsAString& aColor) {
NSString* str = nsCocoaUtils::ToNSString(aColor); NSString* str = nsCocoaUtils::ToNSString(aColor);
double red = HexStrToInt([str substringWithRange:NSMakeRange(1, 2)]) / 255.0; double red = HexStrToInt([str substringWithRange:NSMakeRange(1, 2)]) / 255.0;
double green = HexStrToInt([str substringWithRange:NSMakeRange(3, 2)]) / 255.0; double green =
HexStrToInt([str substringWithRange:NSMakeRange(3, 2)]) / 255.0;
double blue = HexStrToInt([str substringWithRange:NSMakeRange(5, 2)]) / 255.0; double blue = HexStrToInt([str substringWithRange:NSMakeRange(5, 2)]) / 255.0;
return [NSColor colorWithDeviceRed:red green:green blue:blue alpha:1.0]; return [NSColor colorWithDeviceRed:red green:green blue:blue alpha:1.0];
} }
/* static */ void nsColorPicker::GetHexStringFromNSColor(NSColor* aColor, nsAString& aResult) { /* static */ void nsColorPicker::GetHexStringFromNSColor(NSColor* aColor,
nsAString& aResult) {
CGFloat redFloat, greenFloat, blueFloat; CGFloat redFloat, greenFloat, blueFloat;
NSColor* color = aColor; NSColor* color = aColor;
@ -126,7 +131,8 @@ nsColorPicker::Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
} }
nsCocoaUtils::GetStringForNSString( nsCocoaUtils::GetStringForNSString(
[NSString stringWithFormat:@"#%02x%02x%02x", (int)(redFloat * 255), (int)(greenFloat * 255), [NSString stringWithFormat:@"#%02x%02x%02x", (int)(redFloat * 255),
(int)(greenFloat * 255),
(int)(blueFloat * 255)], (int)(blueFloat * 255)],
aResult); aResult);
} }
@ -136,7 +142,8 @@ nsColorPicker::Open(nsIColorPickerShownCallback* aCallback) {
MOZ_ASSERT(aCallback); MOZ_ASSERT(aCallback);
mCallback = aCallback; mCallback = aCallback;
[mColorPanelWrapper open:GetNSColorFromHexString(mColor) title:nsCocoaUtils::ToNSString(mTitle)]; [mColorPanelWrapper open:GetNSColorFromHexString(mColor)
title:nsCocoaUtils::ToNSString(mTitle)];
NS_ADDREF_THIS(); NS_ADDREF_THIS();

View file

@ -20,8 +20,8 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
/*! @method getCursor: /*! @method getCursor:
@abstract Get a reference to the native Mac representation of a cursor. @abstract Get a reference to the native Mac representation of a cursor.
@discussion Gets a reference to the Mac native implementation of a cursor. @discussion Gets a reference to the Mac native implementation of a cursor.
If the cursor has been requested before, it is retreived from the cursor cache, If the cursor has been requested before, it is retreived from
otherwise it is created and cached. the cursor cache, otherwise it is created and cached.
@param aCursor the cursor to get @param aCursor the cursor to get
@result the Mac native implementation of the cursor @result the Mac native implementation of the cursor
*/ */
@ -29,8 +29,9 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
/*! @method setMacCursor: /*! @method setMacCursor:
@abstract Set the current Mac native cursor @abstract Set the current Mac native cursor
@discussion Sets the current cursor - this routine is what actually causes the cursor to change. @discussion Sets the current cursor - this routine is what actually causes the
The argument is retained and the old cursor is released. cursor to change. The argument is retained and the old cursor is
released.
@param aMacCursor the cursor to set @param aMacCursor the cursor to set
@result NS_OK @result NS_OK
*/ */
@ -38,7 +39,8 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
/*! @method createCursor: /*! @method createCursor:
@abstract Create a Mac native representation of a cursor. @abstract Create a Mac native representation of a cursor.
@discussion Creates a version of the Mac native representation of this cursor @discussion Creates a version of the Mac native representation of this
cursor.
@param aCursor the cursor to create @param aCursor the cursor to create
@result the Mac native implementation of the cursor @result the Mac native implementation of the cursor
*/ */
@ -76,92 +78,128 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor];
case eCursor_wait: case eCursor_wait:
case eCursor_spinning: { case eCursor_spinning: {
return [nsMacCursor cursorWithCursor:[NSCursor busyButClickableCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor busyButClickableCursor]
type:aCursor];
} }
case eCursor_select: case eCursor_select:
return [nsMacCursor cursorWithCursor:[NSCursor IBeamCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor IBeamCursor] type:aCursor];
case eCursor_hyperlink: case eCursor_hyperlink:
return [nsMacCursor cursorWithCursor:[NSCursor pointingHandCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor pointingHandCursor]
type:aCursor];
case eCursor_crosshair: case eCursor_crosshair:
return [nsMacCursor cursorWithCursor:[NSCursor crosshairCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor crosshairCursor]
type:aCursor];
case eCursor_move: case eCursor_move:
return [nsMacCursor cursorWithImageNamed:@"move" hotSpot:NSMakePoint(12, 12) type:aCursor]; return [nsMacCursor cursorWithImageNamed:@"move"
hotSpot:NSMakePoint(12, 12)
type:aCursor];
case eCursor_help: case eCursor_help:
return [nsMacCursor cursorWithImageNamed:@"help" hotSpot:NSMakePoint(12, 12) type:aCursor]; return [nsMacCursor cursorWithImageNamed:@"help"
hotSpot:NSMakePoint(12, 12)
type:aCursor];
case eCursor_copy: { case eCursor_copy: {
SEL cursorSelector = @selector(dragCopyCursor); SEL cursorSelector = @selector(dragCopyCursor);
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] return [nsMacCursor
? [NSCursor performSelector:cursorSelector] cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
: [NSCursor arrowCursor] ? [NSCursor performSelector:cursorSelector]
type:aCursor]; : [NSCursor arrowCursor]
type:aCursor];
} }
case eCursor_alias: { case eCursor_alias: {
SEL cursorSelector = @selector(dragLinkCursor); SEL cursorSelector = @selector(dragLinkCursor);
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] return [nsMacCursor
? [NSCursor performSelector:cursorSelector] cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
: [NSCursor arrowCursor] ? [NSCursor performSelector:cursorSelector]
type:aCursor]; : [NSCursor arrowCursor]
type:aCursor];
} }
case eCursor_context_menu: { case eCursor_context_menu: {
SEL cursorSelector = @selector(contextualMenuCursor); SEL cursorSelector = @selector(contextualMenuCursor);
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] return [nsMacCursor
? [NSCursor performSelector:cursorSelector] cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
: [NSCursor arrowCursor] ? [NSCursor performSelector:cursorSelector]
type:aCursor]; : [NSCursor arrowCursor]
type:aCursor];
} }
case eCursor_cell: case eCursor_cell:
return [nsMacCursor cursorWithImageNamed:@"cell" hotSpot:NSMakePoint(12, 12) type:aCursor]; return [nsMacCursor cursorWithImageNamed:@"cell"
hotSpot:NSMakePoint(12, 12)
type:aCursor];
case eCursor_grab: case eCursor_grab:
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor]
type:aCursor];
case eCursor_grabbing: case eCursor_grabbing:
return [nsMacCursor cursorWithCursor:[NSCursor closedHandCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor closedHandCursor]
type:aCursor];
case eCursor_zoom_in: case eCursor_zoom_in:
return [nsMacCursor cursorWithImageNamed:@"zoomIn" hotSpot:NSMakePoint(10, 10) type:aCursor]; return [nsMacCursor cursorWithImageNamed:@"zoomIn"
hotSpot:NSMakePoint(10, 10)
type:aCursor];
case eCursor_zoom_out: case eCursor_zoom_out:
return [nsMacCursor cursorWithImageNamed:@"zoomOut" hotSpot:NSMakePoint(10, 10) type:aCursor]; return [nsMacCursor cursorWithImageNamed:@"zoomOut"
hotSpot:NSMakePoint(10, 10)
type:aCursor];
case eCursor_vertical_text: case eCursor_vertical_text:
return [nsMacCursor cursorWithImageNamed:@"vtIBeam" hotSpot:NSMakePoint(12, 11) type:aCursor]; return [nsMacCursor cursorWithImageNamed:@"vtIBeam"
hotSpot:NSMakePoint(12, 11)
type:aCursor];
case eCursor_all_scroll: case eCursor_all_scroll:
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor]
type:aCursor];
case eCursor_not_allowed: case eCursor_not_allowed:
case eCursor_no_drop: { case eCursor_no_drop: {
SEL cursorSelector = @selector(operationNotAllowedCursor); SEL cursorSelector = @selector(operationNotAllowedCursor);
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] return [nsMacCursor
? [NSCursor performSelector:cursorSelector] cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
: [NSCursor arrowCursor] ? [NSCursor performSelector:cursorSelector]
type:aCursor]; : [NSCursor arrowCursor]
type:aCursor];
} }
// Resize Cursors: // Resize Cursors:
// North // North
case eCursor_n_resize: case eCursor_n_resize:
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor resizeUpCursor]
type:aCursor];
// North East // North East
case eCursor_ne_resize: case eCursor_ne_resize:
return [nsMacCursor cursorWithImageNamed:@"sizeNE" hotSpot:NSMakePoint(12, 11) type:aCursor]; return [nsMacCursor cursorWithImageNamed:@"sizeNE"
hotSpot:NSMakePoint(12, 11)
type:aCursor];
// East // East
case eCursor_e_resize: case eCursor_e_resize:
return [nsMacCursor cursorWithCursor:[NSCursor resizeRightCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor resizeRightCursor]
type:aCursor];
// South East // South East
case eCursor_se_resize: case eCursor_se_resize:
return [nsMacCursor cursorWithImageNamed:@"sizeSE" hotSpot:NSMakePoint(12, 12) type:aCursor]; return [nsMacCursor cursorWithImageNamed:@"sizeSE"
hotSpot:NSMakePoint(12, 12)
type:aCursor];
// South // South
case eCursor_s_resize: case eCursor_s_resize:
return [nsMacCursor cursorWithCursor:[NSCursor resizeDownCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor resizeDownCursor]
type:aCursor];
// South West // South West
case eCursor_sw_resize: case eCursor_sw_resize:
return [nsMacCursor cursorWithImageNamed:@"sizeSW" hotSpot:NSMakePoint(10, 12) type:aCursor]; return [nsMacCursor cursorWithImageNamed:@"sizeSW"
hotSpot:NSMakePoint(10, 12)
type:aCursor];
// West // West
case eCursor_w_resize: case eCursor_w_resize:
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftCursor]
type:aCursor];
// North West // North West
case eCursor_nw_resize: case eCursor_nw_resize:
return [nsMacCursor cursorWithImageNamed:@"sizeNW" hotSpot:NSMakePoint(11, 11) type:aCursor]; return [nsMacCursor cursorWithImageNamed:@"sizeNW"
hotSpot:NSMakePoint(11, 11)
type:aCursor];
// North & South // North & South
case eCursor_ns_resize: case eCursor_ns_resize:
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpDownCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor resizeUpDownCursor]
type:aCursor];
// East & West // East & West
case eCursor_ew_resize: case eCursor_ew_resize:
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftRightCursor] type:aCursor]; return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftRightCursor]
type:aCursor];
// North East & South West // North East & South West
case eCursor_nesw_resize: case eCursor_nesw_resize:
return [nsMacCursor cursorWithImageNamed:@"sizeNESW" return [nsMacCursor cursorWithImageNamed:@"sizeNESW"
@ -241,8 +279,10 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
widgetScaleFactor:(CGFloat)scaleFactor { widgetScaleFactor:(CGFloat)scaleFactor {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
// As the user moves the mouse, this gets called repeatedly with the same aCursorImage // As the user moves the mouse, this gets called repeatedly with the same
if (sCurrentCursor == aCursor && sCurrentCursorScaleFactor == scaleFactor && mCurrentMacCursor) { // aCursorImage
if (sCurrentCursor == aCursor && sCurrentCursorScaleFactor == scaleFactor &&
mCurrentMacCursor) {
// Native dragging can unset our cursor apparently (see bug 1739352). // Native dragging can unset our cursor apparently (see bug 1739352).
if (MOZ_UNLIKELY(![mCurrentMacCursor isSet])) { if (MOZ_UNLIKELY(![mCurrentMacCursor isSet])) {
[mCurrentMacCursor set]; [mCurrentMacCursor set];
@ -265,7 +305,8 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
NSImage* cursorImage; NSImage* cursorImage;
nsresult rv = nsCocoaUtils::CreateNSImageFromImageContainer( nsresult rv = nsCocoaUtils::CreateNSImageFromImageContainer(
aCursor.mContainer, imgIContainer::FRAME_FIRST, nullptr, nullptr, &cursorImage, scaleFactor); aCursor.mContainer, imgIContainer::FRAME_FIRST, nullptr, nullptr,
&cursorImage, scaleFactor);
if (NS_FAILED(rv) || !cursorImage) { if (NS_FAILED(rv) || !cursorImage) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -277,11 +318,14 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
} }
// if the hotspot is nonsensical, make it 0,0 // if the hotspot is nonsensical, make it 0,0
uint32_t hotspotX = aCursor.mHotspotX > (uint32_t(size.width) - 1) ? 0 : aCursor.mHotspotX; uint32_t hotspotX =
uint32_t hotspotY = aCursor.mHotspotY > (uint32_t(size.height) - 1) ? 0 : aCursor.mHotspotY; aCursor.mHotspotX > (uint32_t(size.width) - 1) ? 0 : aCursor.mHotspotX;
uint32_t hotspotY =
aCursor.mHotspotY > (uint32_t(size.height) - 1) ? 0 : aCursor.mHotspotY;
NSPoint hotSpot = ::NSMakePoint(hotspotX, hotspotY); NSPoint hotSpot = ::NSMakePoint(hotspotX, hotspotY);
[self setMacCursor:[nsMacCursor cursorWithCursor:[[NSCursor alloc] initWithImage:cursorImage [self setMacCursor:[nsMacCursor cursorWithCursor:[[NSCursor alloc]
hotSpot:hotSpot] initWithImage:cursorImage
hotSpot:hotSpot]
type:kCustomCursor]]; type:kCustomCursor]];
[cursorImage release]; [cursorImage release];
return NS_OK; return NS_OK;
@ -292,7 +336,8 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
- (nsMacCursor*)getCursor:(enum nsCursor)aCursor { - (nsMacCursor*)getCursor:(enum nsCursor)aCursor {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
nsMacCursor* result = [mCursors objectForKey:[NSNumber numberWithInt:aCursor]]; nsMacCursor* result =
[mCursors objectForKey:[NSNumber numberWithInt:aCursor]];
if (!result) { if (!result) {
result = [nsCursorManager createCursor:aCursor]; result = [nsCursorManager createCursor:aCursor];
[mCursors setObject:result forKey:[NSNumber numberWithInt:aCursor]]; [mCursors setObject:result forKey:[NSNumber numberWithInt:aCursor]];

View file

@ -67,7 +67,8 @@ nsDeviceContextSpecX::~nsDeviceContextSpecX() {
NS_IMPL_ISUPPORTS(nsDeviceContextSpecX, nsIDeviceContextSpec) NS_IMPL_ISUPPORTS(nsDeviceContextSpecX, nsIDeviceContextSpec)
NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS, bool aIsPrintPreview) { NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS,
bool aIsPrintPreview) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
RefPtr<nsPrintSettingsX> settings(do_QueryObject(aPS)); RefPtr<nsPrintSettingsX> settings(do_QueryObject(aPS));
@ -81,7 +82,8 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS, bool aIsPrintPre
if (!printInfo) { if (!printInfo) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
if (aPS->GetOutputDestination() == nsIPrintSettings::kOutputDestinationStream) { if (aPS->GetOutputDestination() ==
nsIPrintSettings::kOutputDestinationStream) {
aPS->GetOutputStream(getter_AddRefs(mOutputStream)); aPS->GetOutputStream(getter_AddRefs(mOutputStream));
if (!mOutputStream) { if (!mOutputStream) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -108,17 +110,20 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS, bool aIsPrintPre
// TODO: Currently we do not support using SkPDF for kPMDestinationFax or // TODO: Currently we do not support using SkPDF for kPMDestinationFax or
// kPMDestinationProcessPDF ("Add PDF to iBooks, etc.), and we only support // kPMDestinationProcessPDF ("Add PDF to iBooks, etc.), and we only support
// it for kPMDestinationFile if the destination file is a PDF. // it for kPMDestinationFile if the destination file is a PDF.
// XXX Could PMWorkflowSubmitPDFWithSettings/PMPrinterPrintWithProvider help? // XXX Could PMWorkflowSubmitPDFWithSettings/PMPrinterPrintWithProvider
// help?
OSStatus status = noErr; OSStatus status = noErr;
PMDestinationType destination; PMDestinationType destination;
status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings, &destination); status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings,
&destination);
if (status == noErr) { if (status == noErr) {
if (destination == kPMDestinationPrinter || destination == kPMDestinationPreview) { if (destination == kPMDestinationPrinter ||
destination == kPMDestinationPreview) {
mPrintViaSkPDF = true; mPrintViaSkPDF = true;
} else if (destination == kPMDestinationFile) { } else if (destination == kPMDestinationFile) {
AutoCFRelease<CFURLRef> destURL(nullptr); AutoCFRelease<CFURLRef> destURL(nullptr);
status = status = ::PMSessionCopyDestinationLocation(
::PMSessionCopyDestinationLocation(mPrintSession, mPMPrintSettings, destURL.receive()); mPrintSession, mPMPrintSettings, destURL.receive());
if (status == noErr) { if (status == noErr) {
AutoCFRelease<CFStringRef> destPathRef = AutoCFRelease<CFStringRef> destPathRef =
CFURLCopyFileSystemPath(destURL, kCFURLPOSIXPathStyle); CFURLCopyFileSystemPath(destURL, kCFURLPOSIXPathStyle);
@ -139,16 +144,20 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS, bool aIsPrintPre
// We don't actually currently support/use kOutputFormatPDF on mac, but // We don't actually currently support/use kOutputFormatPDF on mac, but
// this is for completeness in case we add that (we probably need to in // this is for completeness in case we add that (we probably need to in
// order to support adding links into saved PDFs, for example). // order to support adding links into saved PDFs, for example).
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE, u"pdf_file"_ns, 1); Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE,
u"pdf_file"_ns, 1);
} else { } else {
PMDestinationType destination; PMDestinationType destination;
OSStatus status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings, &destination); OSStatus status = ::PMSessionGetDestinationType(
if (status == noErr && mPrintSession, mPMPrintSettings, &destination);
(destination == kPMDestinationFile || destination == kPMDestinationPreview || if (status == noErr && (destination == kPMDestinationFile ||
destination == kPMDestinationProcessPDF)) { destination == kPMDestinationPreview ||
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE, u"pdf_file"_ns, 1); destination == kPMDestinationProcessPDF)) {
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE,
u"pdf_file"_ns, 1);
} else { } else {
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE, u"unknown"_ns, 1); Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE,
u"unknown"_ns, 1);
} }
} }
@ -157,9 +166,9 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS, bool aIsPrintPre
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
} }
NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(const nsAString& aTitle, NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(
const nsAString& aPrintToFileName, const nsAString& aTitle, const nsAString& aPrintToFileName,
int32_t aStartPage, int32_t aEndPage) { int32_t aStartPage, int32_t aEndPage) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
return NS_OK; return NS_OK;
@ -168,7 +177,8 @@ NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(const nsAString& aTitle,
} }
RefPtr<PrintEndDocumentPromise> nsDeviceContextSpecX::EndDocument() { RefPtr<PrintEndDocumentPromise> nsDeviceContextSpecX::EndDocument() {
return nsIDeviceContextSpec::EndDocumentPromiseFromResult(DoEndDocument(), __func__); return nsIDeviceContextSpec::EndDocumentPromiseFromResult(DoEndDocument(),
__func__);
} }
nsresult nsDeviceContextSpecX::DoEndDocument() { nsresult nsDeviceContextSpecX::DoEndDocument() {
@ -183,14 +193,15 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
AutoCFRelease<CFURLRef> pdfURL(nullptr); AutoCFRelease<CFURLRef> pdfURL(nullptr);
// Note that the caller is responsible to release pdfURL according to nsILocalFileMac.idl, // Note that the caller is responsible to release pdfURL according to
// even though we didn't follow the Core Foundation naming conventions here (the method // nsILocalFileMac.idl, even though we didn't follow the Core Foundation
// should've been called CopyCFURL). // naming conventions here (the method should've been called CopyCFURL).
nsresult rv = tmpPDFFile->GetCFURL(pdfURL.receive()); nsresult rv = tmpPDFFile->GetCFURL(pdfURL.receive());
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
PMDestinationType destination; PMDestinationType destination;
status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings, &destination); status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings,
&destination);
switch (destination) { switch (destination) {
case kPMDestinationPrinter: { case kPMDestinationPrinter: {
@ -200,13 +211,14 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
CFStringRef mimeType = CFSTR("application/pdf"); CFStringRef mimeType = CFSTR("application/pdf");
status = ::PMPrinterPrintWithFile(currentPrinter, mPMPrintSettings, mPageFormat, mimeType, status = ::PMPrinterPrintWithFile(currentPrinter, mPMPrintSettings,
pdfURL); mPageFormat, mimeType, pdfURL);
break; break;
} }
case kPMDestinationPreview: { case kPMDestinationPreview: {
// XXXjwatt Or should we use CocoaFileUtils::RevealFileInFinder(pdfURL); // XXXjwatt Or should we use CocoaFileUtils::RevealFileInFinder(pdfURL);
AutoCFRelease<CFStringRef> pdfPath = CFURLCopyFileSystemPath(pdfURL, kCFURLPOSIXPathStyle); AutoCFRelease<CFStringRef> pdfPath =
CFURLCopyFileSystemPath(pdfURL, kCFURLPOSIXPathStyle);
NSString* path = (NSString*)CFStringRef(pdfPath); NSString* path = (NSString*)CFStringRef(pdfPath);
NSWorkspace* ws = [NSWorkspace sharedWorkspace]; NSWorkspace* ws = [NSWorkspace sharedWorkspace];
[ws openFile:path]; [ws openFile:path];
@ -214,8 +226,8 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
} }
case kPMDestinationFile: { case kPMDestinationFile: {
AutoCFRelease<CFURLRef> destURL(nullptr); AutoCFRelease<CFURLRef> destURL(nullptr);
status = status = ::PMSessionCopyDestinationLocation(
::PMSessionCopyDestinationLocation(mPrintSession, mPMPrintSettings, destURL.receive()); mPrintSession, mPMPrintSettings, destURL.receive());
if (status == noErr) { if (status == noErr) {
AutoCFRelease<CFStringRef> sourcePathRef = AutoCFRelease<CFStringRef> sourcePathRef =
CFURLCopyFileSystemPath(pdfURL, kCFURLPOSIXPathStyle); CFURLCopyFileSystemPath(pdfURL, kCFURLPOSIXPathStyle);
@ -234,12 +246,14 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
if ([fileManager fileExistsAtPath:sourcePath]) { if ([fileManager fileExistsAtPath:sourcePath]) {
NSURL* src = static_cast<NSURL*>(CFURLRef(pdfURL)); NSURL* src = static_cast<NSURL*>(CFURLRef(pdfURL));
NSURL* dest = static_cast<NSURL*>(CFURLRef(destURL)); NSURL* dest = static_cast<NSURL*>(CFURLRef(destURL));
bool ok = [fileManager replaceItemAtURL:dest bool ok = [fileManager
withItemAtURL:src replaceItemAtURL:dest
backupItemName:nil withItemAtURL:src
options:NSFileManagerItemReplacementUsingNewMetadataOnly backupItemName:nil
resultingItemURL:nil options:
error:nil]; NSFileManagerItemReplacementUsingNewMetadataOnly
resultingItemURL:nil
error:nil];
if (!ok) { if (!ok) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -261,8 +275,8 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
} }
void nsDeviceContextSpecX::GetPaperRect(double* aTop, double* aLeft, double* aBottom, void nsDeviceContextSpecX::GetPaperRect(double* aTop, double* aLeft,
double* aRight) { double* aBottom, double* aRight) {
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
PMRect paperRect; PMRect paperRect;
@ -286,7 +300,8 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecX::MakePrintTarget() {
#ifdef MOZ_ENABLE_SKIA_PDF #ifdef MOZ_ENABLE_SKIA_PDF
if (mPrintViaSkPDF) { if (mPrintViaSkPDF) {
// TODO: Add support for stream printing via SkPDF if we enable that again. // TODO: Add support for stream printing via SkPDF if we enable that again.
nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mTempFile)); nsresult rv =
NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mTempFile));
NS_ENSURE_SUCCESS(rv, nullptr); NS_ENSURE_SUCCESS(rv, nullptr);
nsAutoCString tempPath("tmp-printing.pdf"); nsAutoCString tempPath("tmp-printing.pdf");
mTempFile->AppendNative(tempPath); mTempFile->AppendNative(tempPath);
@ -298,6 +313,6 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecX::MakePrintTarget() {
} }
#endif #endif
return PrintTargetCG::CreateOrNull(mOutputStream, mPrintSession, mPageFormat, mPMPrintSettings, return PrintTargetCG::CreateOrNull(mOutputStream, mPrintSession, mPageFormat,
size); mPMPrintSettings, size);
} }

View file

@ -49,24 +49,29 @@ nsDragService::nsDragService()
nsDragService::~nsDragService() {} nsDragService::~nsDragService() {}
NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSIntRegion>& aRegion, NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode,
const Maybe<CSSIntRegion>& aRegion,
NSPoint* aDragPoint) { NSPoint* aDragPoint) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView); CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
LayoutDeviceIntRect dragRect(0, 0, 20, 20); LayoutDeviceIntRect dragRect(0, 0, 20, 20);
NSImage* image = ConstructDragImage(mSourceNode, aRegion, mScreenPosition, &dragRect); NSImage* image =
ConstructDragImage(mSourceNode, aRegion, mScreenPosition, &dragRect);
if (!image) { if (!image) {
// if no image was returned, just draw a rectangle // if no image was returned, just draw a rectangle
NSSize size; NSSize size;
size.width = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.width, scaleFactor); size.width =
size.height = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.height, scaleFactor); nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.width, scaleFactor);
size.height =
nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.height, scaleFactor);
image = [NSImage imageWithSize:size image = [NSImage imageWithSize:size
flipped:YES flipped:YES
drawingHandler:^BOOL(NSRect dstRect) { drawingHandler:^BOOL(NSRect dstRect) {
[[NSColor grayColor] set]; [[NSColor grayColor] set];
NSBezierPath* path = [NSBezierPath bezierPathWithRect:dstRect]; NSBezierPath* path =
[NSBezierPath bezierPathWithRect:dstRect];
[path setLineWidth:2.0]; [path setLineWidth:2.0];
[path stroke]; [path stroke];
return YES; return YES;
@ -85,8 +90,10 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
NS_OBJC_END_TRY_BLOCK_RETURN(nil); NS_OBJC_END_TRY_BLOCK_RETURN(nil);
} }
NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSIntRegion>& aRegion, NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode,
CSSIntPoint aPoint, LayoutDeviceIntRect* aDragRect) { const Maybe<CSSIntRegion>& aRegion,
CSSIntPoint aPoint,
LayoutDeviceIntRect* aDragRect) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView); CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
@ -97,8 +104,8 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
if (pc && (!aDragRect->width || !aDragRect->height)) { if (pc && (!aDragRect->width || !aDragRect->height)) {
// just use some suitable defaults // just use some suitable defaults
int32_t size = nsCocoaUtils::CocoaPointsToDevPixels(20, scaleFactor); int32_t size = nsCocoaUtils::CocoaPointsToDevPixels(20, scaleFactor);
aDragRect->SetRect(pc->CSSPixelsToDevPixels(aPoint.x), pc->CSSPixelsToDevPixels(aPoint.y), size, aDragRect->SetRect(pc->CSSPixelsToDevPixels(aPoint.x),
size); pc->CSSPixelsToDevPixels(aPoint.y), size, size);
} }
if (NS_FAILED(rv) || !surface) return nil; if (NS_FAILED(rv) || !surface) return nil;
@ -106,21 +113,23 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
uint32_t width = aDragRect->width; uint32_t width = aDragRect->width;
uint32_t height = aDragRect->height; uint32_t height = aDragRect->height;
RefPtr<DataSourceSurface> dataSurface = RefPtr<DataSourceSurface> dataSurface = Factory::CreateDataSourceSurface(
Factory::CreateDataSourceSurface(IntSize(width, height), SurfaceFormat::B8G8R8A8); IntSize(width, height), SurfaceFormat::B8G8R8A8);
DataSourceSurface::MappedSurface map; DataSourceSurface::MappedSurface map;
if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) { if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
return nil; return nil;
} }
RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData( RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
BackendType::CAIRO, map.mData, dataSurface->GetSize(), map.mStride, dataSurface->GetFormat()); BackendType::CAIRO, map.mData, dataSurface->GetSize(), map.mStride,
dataSurface->GetFormat());
if (!dt) { if (!dt) {
dataSurface->Unmap(); dataSurface->Unmap();
return nil; return nil;
} }
dt->FillRect(gfx::Rect(0, 0, width, height), SurfacePattern(surface, ExtendMode::CLAMP), dt->FillRect(gfx::Rect(0, 0, width, height),
SurfacePattern(surface, ExtendMode::CLAMP),
DrawOptions(1.0f, CompositionOp::OP_SOURCE)); DrawOptions(1.0f, CompositionOp::OP_SOURCE));
NSBitmapImageRep* imageRep = NSBitmapImageRep* imageRep =
@ -140,7 +149,8 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
uint8_t* src = map.mData + i * map.mStride; uint8_t* src = map.mData + i * map.mStride;
for (uint32_t j = 0; j < width; ++j) { for (uint32_t j = 0; j < width; ++j) {
// Reduce transparency overall by multipying by a factor. Remember, Alpha // Reduce transparency overall by multipying by a factor. Remember, Alpha
// is premultipled here. Also, Quartz likes RGBA, so do that translation as well. // is premultipled here. Also, Quartz likes RGBA, so do that translation
// as well.
#ifdef IS_BIG_ENDIAN #ifdef IS_BIG_ENDIAN
dest[0] = uint8_t(src[1] * DRAG_TRANSLUCENCY); dest[0] = uint8_t(src[1] * DRAG_TRANSLUCENCY);
dest[1] = uint8_t(src[2] * DRAG_TRANSLUCENCY); dest[1] = uint8_t(src[2] * DRAG_TRANSLUCENCY);
@ -158,8 +168,8 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
} }
dataSurface->Unmap(); dataSurface->Unmap();
NSImage* image = NSImage* image = [[NSImage alloc]
[[NSImage alloc] initWithSize:NSMakeSize(width / scaleFactor, height / scaleFactor)]; initWithSize:NSMakeSize(width / scaleFactor, height / scaleFactor)];
[image addRepresentation:imageRep]; [image addRepresentation:imageRep];
[imageRep release]; [imageRep release];
@ -168,9 +178,9 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
NS_OBJC_END_TRY_BLOCK_RETURN(nil); NS_OBJC_END_TRY_BLOCK_RETURN(nil);
} }
nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray, nsresult nsDragService::InvokeDragSessionImpl(
const Maybe<CSSIntRegion>& aRegion, nsIArray* aTransferableArray, const Maybe<CSSIntRegion>& aRegion,
uint32_t aActionType) { uint32_t aActionType) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
#ifdef NIGHTLY_BUILD #ifdef NIGHTLY_BUILD
@ -178,10 +188,11 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
#endif #endif
if (!gLastDragView) { if (!gLastDragView) {
// gLastDragView is non-null between -[ChildView mouseDown:] and -[ChildView mouseUp:]. // gLastDragView is non-null between -[ChildView mouseDown:] and -[ChildView
// If we get here with gLastDragView being null, that means that the mouse button has already // mouseUp:]. If we get here with gLastDragView being null, that means that
// been released. In that case we need to abort the drag because the OS won't know where to drop // the mouse button has already been released. In that case we need to abort
// whatever's being dragged, and we might end up with a stuck drag & drop session. // the drag because the OS won't know where to drop whatever's being
// dragged, and we might end up with a stuck drag & drop session.
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -205,7 +216,8 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
gDraggedTransferables->GetLength(&count); gDraggedTransferables->GetLength(&count);
for (uint32_t j = 0; j < count; j++) { for (uint32_t j = 0; j < count; j++) {
nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(aTransferableArray, j); nsCOMPtr<nsITransferable> currentTransferable =
do_QueryElementAt(aTransferableArray, j);
if (!currentTransferable) { if (!currentTransferable) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -234,7 +246,8 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
localDragRect.origin.x = draggingPoint.x; localDragRect.origin.x = draggingPoint.x;
localDragRect.origin.y = draggingPoint.y - localDragRect.size.height; localDragRect.origin.y = draggingPoint.y - localDragRect.size.height;
NSDraggingItem* dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:pbItem]; NSDraggingItem* dragItem =
[[NSDraggingItem alloc] initWithPasteboardWriter:pbItem];
[pbItem release]; [pbItem release];
[dragItem setDraggingFrame:localDragRect contents:image]; [dragItem setDraggingFrame:localDragRect contents:image];
@ -242,7 +255,8 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
nsBaseDragService::OpenDragPopup(); nsBaseDragService::OpenDragPopup();
NSDraggingSession* draggingSession = [mNativeDragView NSDraggingSession* draggingSession = [mNativeDragView
beginDraggingSessionWithItems:[NSArray arrayWithObject:[dragItem autorelease]] beginDraggingSessionWithItems:[NSArray
arrayWithObject:[dragItem autorelease]]
event:mNativeDragEvent event:mNativeDragEvent
source:mNativeDragView]; source:mNativeDragView];
draggingSession.animatesToStartingPositionsOnCancelOrFail = draggingSession.animatesToStartingPositionsOnCancelOrFail =
@ -261,24 +275,26 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
// get flavor list that includes all acceptable flavors (including ones obtained through // get flavor list that includes all acceptable flavors (including ones
// conversion) // obtained through conversion)
nsTArray<nsCString> flavors; nsTArray<nsCString> flavors;
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors); nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
// if this drag originated within Mozilla we should just use the cached data from // if this drag originated within Mozilla we should just use the cached data
// when the drag started if possible // from when the drag started if possible
if (mDataItems) { if (mDataItems) {
nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(mDataItems, aItemIndex); nsCOMPtr<nsITransferable> currentTransferable =
do_QueryElementAt(mDataItems, aItemIndex);
if (currentTransferable) { if (currentTransferable) {
for (uint32_t i = 0; i < flavors.Length(); i++) { for (uint32_t i = 0; i < flavors.Length(); i++) {
nsCString& flavorStr = flavors[i]; nsCString& flavorStr = flavors[i];
nsCOMPtr<nsISupports> dataSupports; nsCOMPtr<nsISupports> dataSupports;
rv = currentTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(dataSupports)); rv = currentTransferable->GetTransferData(flavorStr.get(),
getter_AddRefs(dataSupports));
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
aTransferable->SetTransferData(flavorStr.get(), dataSupports); aTransferable->SetTransferData(flavorStr.get(), dataSupports);
return NS_OK; // maybe try to fill in more types? Is there a point? return NS_OK; // maybe try to fill in more types? Is there a point?
@ -304,7 +320,8 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
// now check the actual clipboard for data // now check the actual clipboard for data
for (uint32_t i = 0; i < flavors.Length(); i++) { for (uint32_t i = 0; i < flavors.Length(); i++) {
nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable, flavors[i], item); nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable,
flavors[i], item);
} }
return NS_OK; return NS_OK;
@ -327,7 +344,8 @@ nsDragService::IsDataFlavorSupported(const char* aDataFlavor, bool* _retval) {
uint32_t dataItemsCount; uint32_t dataItemsCount;
mDataItems->GetLength(&dataItemsCount); mDataItems->GetLength(&dataItemsCount);
for (unsigned int i = 0; i < dataItemsCount; i++) { for (unsigned int i = 0; i < dataItemsCount; i++) {
nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(mDataItems, i); nsCOMPtr<nsITransferable> currentTransferable =
do_QueryElementAt(mDataItems, i);
if (!currentTransferable) continue; if (!currentTransferable) continue;
nsTArray<nsCString> flavors; nsTArray<nsCString> flavors;
@ -352,7 +370,8 @@ nsDragService::IsDataFlavorSupported(const char* aDataFlavor, bool* _retval) {
type = [UTIHelper stringFromPboardType:NSPasteboardTypeString]; type = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
} else if (dataFlavor.EqualsLiteral(kHTMLMime)) { } else if (dataFlavor.EqualsLiteral(kHTMLMime)) {
type = [UTIHelper stringFromPboardType:NSPasteboardTypeHTML]; type = [UTIHelper stringFromPboardType:NSPasteboardTypeHTML];
} else if (dataFlavor.EqualsLiteral(kURLMime) || dataFlavor.EqualsLiteral(kURLDataMime)) { } else if (dataFlavor.EqualsLiteral(kURLMime) ||
dataFlavor.EqualsLiteral(kURLDataMime)) {
type = [UTIHelper stringFromPboardType:kPublicUrlPboardType]; type = [UTIHelper stringFromPboardType:kPublicUrlPboardType];
} else if (dataFlavor.EqualsLiteral(kURLDescriptionMime)) { } else if (dataFlavor.EqualsLiteral(kURLDescriptionMime)) {
type = [UTIHelper stringFromPboardType:kPublicUrlNamePboardType]; type = [UTIHelper stringFromPboardType:kPublicUrlNamePboardType];
@ -362,9 +381,10 @@ nsDragService::IsDataFlavorSupported(const char* aDataFlavor, bool* _retval) {
type = [UTIHelper stringFromPboardType:kMozCustomTypesPboardType]; type = [UTIHelper stringFromPboardType:kMozCustomTypesPboardType];
} }
NSString* availableType = NSString* availableType = [globalDragPboard
[globalDragPboard availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]]; availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]];
if (availableType && nsCocoaUtils::IsValidPasteboardType(availableType, allowFileURL)) { if (availableType &&
nsCocoaUtils::IsValidPasteboardType(availableType, allowFileURL)) {
*_retval = true; *_retval = true;
} }
@ -396,19 +416,22 @@ nsDragService::GetNumDropItems(uint32_t* aNumItems) {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsDragService::UpdateDragImage(nsINode* aImage, int32_t aImageX, int32_t aImageY) { nsDragService::UpdateDragImage(nsINode* aImage, int32_t aImageX,
int32_t aImageY) {
nsBaseDragService::UpdateDragImage(aImage, aImageX, aImageY); nsBaseDragService::UpdateDragImage(aImage, aImageX, aImageY);
mDragImageChanged = true; mDragImageChanged = true;
return NS_OK; return NS_OK;
} }
void nsDragService::DragMovedWithView(NSDraggingSession* aSession, NSPoint aPoint) { void nsDragService::DragMovedWithView(NSDraggingSession* aSession,
NSPoint aPoint) {
aPoint.y = nsCocoaUtils::FlippedScreenY(aPoint.y); aPoint.y = nsCocoaUtils::FlippedScreenY(aPoint.y);
// XXX It feels like we should be using the backing scale factor at aPoint // XXX It feels like we should be using the backing scale factor at aPoint
// rather than the initial drag view, but I've seen no ill effects of this. // rather than the initial drag view, but I've seen no ill effects of this.
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView); CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
LayoutDeviceIntPoint devPoint = nsCocoaUtils::CocoaPointsToDevPixels(aPoint, scaleFactor); LayoutDeviceIntPoint devPoint =
nsCocoaUtils::CocoaPointsToDevPixels(aPoint, scaleFactor);
// If the image has changed, call enumerateDraggingItemsWithOptions to get // If the image has changed, call enumerateDraggingItemsWithOptions to get
// the item being dragged and update its image. // the item being dragged and update its image.
@ -422,32 +445,39 @@ void nsDragService::DragMovedWithView(NSDraggingSession* aSession, NSPoint aPoin
} }
if (pc) { if (pc) {
void (^changeImageBlock)(NSDraggingItem*, NSInteger, BOOL*) = void (^changeImageBlock)(NSDraggingItem*, NSInteger, BOOL*) = ^(
^(NSDraggingItem* draggingItem, NSInteger idx, BOOL* stop) { NSDraggingItem* draggingItem, NSInteger idx, BOOL* stop) {
// We never add more than one item right now, but check just in case. // We never add more than one item right now, but check just in case.
if (idx > 0) { if (idx > 0) {
return; return;
} }
nsPoint pt = nsPoint pt = LayoutDevicePixel::ToAppUnits(
LayoutDevicePixel::ToAppUnits(devPoint, pc->DeviceContext()->AppUnitsPerDevPixel()); devPoint, pc->DeviceContext()->AppUnitsPerDevPixel());
CSSIntPoint screenPoint = CSSIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x), CSSIntPoint screenPoint =
nsPresContext::AppUnitsToIntCSSPixels(pt.y)); CSSIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
nsPresContext::AppUnitsToIntCSSPixels(pt.y));
// Create a new image; if one isn't returned don't change the current one. // Create a new image; if one isn't returned don't change the current
LayoutDeviceIntRect newRect; // one.
NSImage* image = ConstructDragImage(mSourceNode, Nothing(), screenPoint, &newRect); LayoutDeviceIntRect newRect;
if (image) { NSImage* image =
NSRect draggingRect = nsCocoaUtils::GeckoRectToCocoaRectDevPix(newRect, scaleFactor); ConstructDragImage(mSourceNode, Nothing(), screenPoint, &newRect);
[draggingItem setDraggingFrame:draggingRect contents:image]; if (image) {
} NSRect draggingRect =
}; nsCocoaUtils::GeckoRectToCocoaRectDevPix(newRect, scaleFactor);
[draggingItem setDraggingFrame:draggingRect contents:image];
}
};
[aSession enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationConcurrent [aSession
forView:nil enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationConcurrent
classes:[NSArray arrayWithObject:[NSPasteboardItem class]] forView:nil
searchOptions:@{} classes:[NSArray
usingBlock:changeImageBlock]; arrayWithObject:
[NSPasteboardItem class]]
searchOptions:@{}
usingBlock:changeImageBlock];
} }
} }

View file

@ -59,9 +59,11 @@ static void SetShowHiddenFileState(NSSavePanel* panel) {
if (gCallSecretHiddenFileAPI) { if (gCallSecretHiddenFileAPI) {
// invoke a method to get a Cocoa-internal nav view // invoke a method to get a Cocoa-internal nav view
SEL navViewSelector = @selector(_navView); SEL navViewSelector = @selector(_navView);
NSMethodSignature* navViewSignature = [panel methodSignatureForSelector:navViewSelector]; NSMethodSignature* navViewSignature =
[panel methodSignatureForSelector:navViewSelector];
if (!navViewSignature) return; if (!navViewSignature) return;
NSInvocation* navViewInvocation = [NSInvocation invocationWithMethodSignature:navViewSignature]; NSInvocation* navViewInvocation =
[NSInvocation invocationWithMethodSignature:navViewSignature];
[navViewInvocation setSelector:navViewSelector]; [navViewInvocation setSelector:navViewSelector];
[navViewInvocation setTarget:panel]; [navViewInvocation setTarget:panel];
[navViewInvocation invoke]; [navViewInvocation invoke];
@ -90,27 +92,32 @@ nsFilePicker::nsFilePicker() : mSelectedTypeIndex(0) {}
nsFilePicker::~nsFilePicker() {} nsFilePicker::~nsFilePicker() {}
void nsFilePicker::InitNative(nsIWidget* aParent, const nsAString& aTitle) { mTitle = aTitle; } void nsFilePicker::InitNative(nsIWidget* aParent, const nsAString& aTitle) {
mTitle = aTitle;
}
NSView* nsFilePicker::GetAccessoryView() { NSView* nsFilePicker::GetAccessoryView() {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NSView* accessoryView = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)] autorelease]; NSView* accessoryView =
[[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)] autorelease];
// Set a label's default value. // Set a label's default value.
NSString* label = @"Format:"; NSString* label = @"Format:";
// Try to get the localized string. // Try to get the localized string.
nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID); nsCOMPtr<nsIStringBundleService> sbs =
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
nsCOMPtr<nsIStringBundle> bundle; nsCOMPtr<nsIStringBundle> bundle;
nsresult rv = nsresult rv = sbs->CreateBundle(
sbs->CreateBundle("chrome://global/locale/filepicker.properties", getter_AddRefs(bundle)); "chrome://global/locale/filepicker.properties", getter_AddRefs(bundle));
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
nsAutoString locaLabel; nsAutoString locaLabel;
rv = bundle->GetStringFromName("formatLabel", locaLabel); rv = bundle->GetStringFromName("formatLabel", locaLabel);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
label = [NSString stringWithCharacters:reinterpret_cast<const unichar*>(locaLabel.get()) label = [NSString
length:locaLabel.Length()]; stringWithCharacters:reinterpret_cast<const unichar*>(locaLabel.get())
length:locaLabel.Length()];
} }
} }
@ -127,8 +134,9 @@ NSView* nsFilePicker::GetAccessoryView() {
[textField sizeToFit]; [textField sizeToFit];
// set up popup button // set up popup button
NSPopUpButton* popupButton = [[[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 0, 0) NSPopUpButton* popupButton =
pullsDown:NO] autorelease]; [[[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)
pullsDown:NO] autorelease];
uint32_t numMenuItems = mTitles.Length(); uint32_t numMenuItems = mTitles.Length();
for (uint32_t i = 0; i < numMenuItems; i++) { for (uint32_t i = 0; i < numMenuItems; i++) {
const nsString& currentTitle = mTitles[i]; const nsString& currentTitle = mTitles[i];
@ -136,11 +144,13 @@ NSView* nsFilePicker::GetAccessoryView() {
if (currentTitle.IsEmpty()) { if (currentTitle.IsEmpty()) {
const nsString& currentFilter = mFilters[i]; const nsString& currentFilter = mFilters[i];
titleString = titleString =
[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(currentFilter.get()) [[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(
currentFilter.get())
length:currentFilter.Length()]; length:currentFilter.Length()];
} else { } else {
titleString = titleString =
[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(currentTitle.get()) [[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(
currentTitle.get())
length:currentTitle.Length()]; length:currentTitle.Length()];
} }
[popupButton addItemWithTitle:titleString]; [popupButton addItemWithTitle:titleString];
@ -149,28 +159,34 @@ NSView* nsFilePicker::GetAccessoryView() {
if (mSelectedTypeIndex >= 0 && (uint32_t)mSelectedTypeIndex < numMenuItems) if (mSelectedTypeIndex >= 0 && (uint32_t)mSelectedTypeIndex < numMenuItems)
[popupButton selectItemAtIndex:mSelectedTypeIndex]; [popupButton selectItemAtIndex:mSelectedTypeIndex];
[popupButton setTag:kSaveTypeControlTag]; [popupButton setTag:kSaveTypeControlTag];
[popupButton sizeToFit]; // we have to do sizeToFit to get the height calculated for us [popupButton sizeToFit]; // we have to do sizeToFit to get the height
// This is just a default width that works well, doesn't truncate the vast majority of // calculated for us
// things that might end up in the menu. // This is just a default width that works well, doesn't truncate the vast
// majority of things that might end up in the menu.
[popupButton setFrameSize:NSMakeSize(180, [popupButton frame].size.height)]; [popupButton setFrameSize:NSMakeSize(180, [popupButton frame].size.height)];
// position everything based on control sizes with kAccessoryViewPadding pix padding // position everything based on control sizes with kAccessoryViewPadding pix
// on each side kAccessoryViewPadding pix horizontal padding between controls // padding on each side kAccessoryViewPadding pix horizontal padding between
// controls
float greatestHeight = [textField frame].size.height; float greatestHeight = [textField frame].size.height;
if ([popupButton frame].size.height > greatestHeight) if ([popupButton frame].size.height > greatestHeight)
greatestHeight = [popupButton frame].size.height; greatestHeight = [popupButton frame].size.height;
float totalViewHeight = greatestHeight + kAccessoryViewPadding * 2; float totalViewHeight = greatestHeight + kAccessoryViewPadding * 2;
float totalViewWidth = float totalViewWidth = [textField frame].size.width +
[textField frame].size.width + [popupButton frame].size.width + kAccessoryViewPadding * 3; [popupButton frame].size.width +
kAccessoryViewPadding * 3;
[accessoryView setFrameSize:NSMakeSize(totalViewWidth, totalViewHeight)]; [accessoryView setFrameSize:NSMakeSize(totalViewWidth, totalViewHeight)];
float textFieldOriginY = float textFieldOriginY =
((greatestHeight - [textField frame].size.height) / 2 + 1) + kAccessoryViewPadding; ((greatestHeight - [textField frame].size.height) / 2 + 1) +
[textField setFrameOrigin:NSMakePoint(kAccessoryViewPadding, textFieldOriginY)]; kAccessoryViewPadding;
[textField
setFrameOrigin:NSMakePoint(kAccessoryViewPadding, textFieldOriginY)];
float popupOriginX = [textField frame].size.width + kAccessoryViewPadding * 2; float popupOriginX = [textField frame].size.width + kAccessoryViewPadding * 2;
float popupOriginY = float popupOriginY =
((greatestHeight - [popupButton frame].size.height) / 2) + kAccessoryViewPadding; ((greatestHeight - [popupButton frame].size.height) / 2) +
kAccessoryViewPadding;
[popupButton setFrameOrigin:NSMakePoint(popupOriginX, popupOriginY)]; [popupButton setFrameOrigin:NSMakePoint(popupOriginX, popupOriginY)];
[accessoryView addSubview:textField]; [accessoryView addSubview:textField];
@ -255,9 +271,10 @@ static void UpdatePanelFileTypes(NSOpenPanel* aPanel, NSArray* aFilters) {
} }
@end @end
// Use OpenPanel to do a GetFile. Returns |returnOK| if the user presses OK in the dialog. // Use OpenPanel to do a GetFile. Returns |returnOK| if the user presses OK in
nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(bool inAllowMultiple, // the dialog.
nsCOMArray<nsIFile>& outFiles) { nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(
bool inAllowMultiple, nsCOMArray<nsIFile>& outFiles) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
ResultCode retVal = nsIFilePicker::returnCancel; ResultCode retVal = nsIFilePicker::returnCancel;
@ -308,10 +325,11 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(bool inAllowMultiple,
[observer setOpenPanel:thePanel]; [observer setOpenPanel:thePanel];
[observer setFilePicker:this]; [observer setFilePicker:this];
[[NSNotificationCenter defaultCenter] addObserver:observer [[NSNotificationCenter defaultCenter]
selector:@selector(menuChangedItem:) addObserver:observer
name:NSMenuWillSendActionNotification selector:@selector(menuChangedItem:)
object:nil]; name:NSMenuWillSendActionNotification
object:nil];
UpdatePanelFileTypes(thePanel, filters); UpdatePanelFileTypes(thePanel, filters);
result = [thePanel runModal]; result = [thePanel runModal];
@ -343,7 +361,8 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(bool inAllowMultiple,
nsCOMPtr<nsIFile> localFile; nsCOMPtr<nsIFile> localFile;
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile)); NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile));
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile); nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)url))) { if (macLocalFile &&
NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)url))) {
outFiles.AppendObject(localFile); outFiles.AppendObject(localFile);
} }
} }
@ -355,10 +374,13 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(bool inAllowMultiple,
NS_OBJC_END_TRY_BLOCK_RETURN(nsIFilePicker::returnOK); NS_OBJC_END_TRY_BLOCK_RETURN(nsIFilePicker::returnOK);
} }
// Use OpenPanel to do a GetFolder. Returns |returnOK| if the user presses OK in the dialog. // Use OpenPanel to do a GetFolder. Returns |returnOK| if the user presses OK in
// the dialog.
nsIFilePicker::ResultCode nsFilePicker::GetLocalFolder(nsIFile** outFile) { nsIFilePicker::ResultCode nsFilePicker::GetLocalFolder(nsIFile** outFile) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer"); NS_ASSERTION(
outFile,
"this protected member function expects a null initialized out pointer");
ResultCode retVal = nsIFilePicker::returnCancel; ResultCode retVal = nsIFilePicker::returnCancel;
NSOpenPanel* thePanel = [NSOpenPanel openPanel]; NSOpenPanel* thePanel = [NSOpenPanel openPanel];
@ -394,7 +416,8 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFolder(nsIFile** outFile) {
nsCOMPtr<nsIFile> localFile; nsCOMPtr<nsIFile> localFile;
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile)); NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile));
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile); nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)theURL))) { if (macLocalFile &&
NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)theURL))) {
*outFile = localFile; *outFile = localFile;
NS_ADDREF(*outFile); NS_ADDREF(*outFile);
retVal = returnOK; retVal = returnOK;
@ -409,7 +432,9 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFolder(nsIFile** outFile) {
// Returns |returnOK| if the user presses OK in the dialog. // Returns |returnOK| if the user presses OK in the dialog.
nsIFilePicker::ResultCode nsFilePicker::PutLocalFile(nsIFile** outFile) { nsIFilePicker::ResultCode nsFilePicker::PutLocalFile(nsIFile** outFile) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer"); NS_ASSERTION(
outFile,
"this protected member function expects a null initialized out pointer");
ResultCode retVal = nsIFilePicker::returnCancel; ResultCode retVal = nsIFilePicker::returnCancel;
NSSavePanel* thePanel = [NSSavePanel savePanel]; NSSavePanel* thePanel = [NSSavePanel savePanel];
@ -423,8 +448,9 @@ nsIFilePicker::ResultCode nsFilePicker::PutLocalFile(nsIFile** outFile) {
[thePanel setAccessoryView:accessoryView]; [thePanel setAccessoryView:accessoryView];
// set up default file name // set up default file name
NSString* defaultFilename = [NSString stringWithCharacters:(const unichar*)mDefaultFilename.get() NSString* defaultFilename =
length:mDefaultFilename.Length()]; [NSString stringWithCharacters:(const unichar*)mDefaultFilename.get()
length:mDefaultFilename.Length()];
// Set up the allowed type. This prevents the extension from being selected. // Set up the allowed type. This prevents the extension from being selected.
NSString* extension = defaultFilename.pathExtension; NSString* extension = defaultFilename.pathExtension;
@ -440,12 +466,13 @@ nsIFilePicker::ResultCode nsFilePicker::PutLocalFile(nsIFile** outFile) {
// trying to add a non-default extension. To avoid the confusion, we ensure // trying to add a non-default extension. To avoid the confusion, we ensure
// that all extensions are shown in the panel if the remaining extension is // that all extensions are shown in the panel if the remaining extension is
// known by the OS. // known by the OS.
NSString* fileName = [[defaultFilename lastPathComponent] stringByDeletingPathExtension]; NSString* fileName =
[[defaultFilename lastPathComponent] stringByDeletingPathExtension];
NSString* otherExtension = fileName.pathExtension; NSString* otherExtension = fileName.pathExtension;
if (otherExtension.length != 0) { if (otherExtension.length != 0) {
// There's another extension here. Get the UTI. // There's another extension here. Get the UTI.
CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, CFStringRef type = UTTypeCreatePreferredIdentifierForTag(
(CFStringRef)otherExtension, NULL); kUTTagClassFilenameExtension, (CFStringRef)otherExtension, NULL);
if (type) { if (type) {
if (!CFStringHasPrefix(type, CFSTR("dyn."))) { if (!CFStringHasPrefix(type, CFSTR("dyn."))) {
// We have a UTI, otherwise the type would have a "dyn." prefix. Ensure // We have a UTI, otherwise the type would have a "dyn." prefix. Ensure
@ -480,11 +507,13 @@ nsIFilePicker::ResultCode nsFilePicker::PutLocalFile(nsIFile** outFile) {
nsCOMPtr<nsIFile> localFile; nsCOMPtr<nsIFile> localFile;
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile)); NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile));
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile); nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)fileURL))) { if (macLocalFile &&
NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)fileURL))) {
*outFile = localFile; *outFile = localFile;
NS_ADDREF(*outFile); NS_ADDREF(*outFile);
// We tell if we are replacing or not by just looking to see if the file exists. // We tell if we are replacing or not by just looking to see if the file
// The user could not have hit OK and not meant to replace the file. // exists. The user could not have hit OK and not meant to replace the
// file.
if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]])
retVal = returnReplace; retVal = returnReplace;
else else
@ -505,7 +534,8 @@ NSArray* nsFilePicker::GetFilterList() {
} }
if (mFilters.Length() <= (uint32_t)mSelectedTypeIndex) { if (mFilters.Length() <= (uint32_t)mSelectedTypeIndex) {
NS_WARNING("An out of range index has been selected. Using the first index instead."); NS_WARNING("An out of range index has been selected. Using the first index "
"instead.");
mSelectedTypeIndex = 0; mSelectedTypeIndex = 0;
} }
@ -522,17 +552,21 @@ NSArray* nsFilePicker::GetFilterList() {
// in the format "ext" by NSOpenPanel. So we need to filter some characters. // in the format "ext" by NSOpenPanel. So we need to filter some characters.
NSMutableString* filterString = [[[NSMutableString alloc] NSMutableString* filterString = [[[NSMutableString alloc]
initWithString:[NSString initWithString:[NSString
stringWithCharacters:reinterpret_cast<const unichar*>(filterWide.get()) stringWithCharacters:reinterpret_cast<const unichar*>(
length:filterWide.Length()]] autorelease]; filterWide.get())
NSCharacterSet* set = [NSCharacterSet characterSetWithCharactersInString:@". *"]; length:filterWide.Length()]]
autorelease];
NSCharacterSet* set =
[NSCharacterSet characterSetWithCharactersInString:@". *"];
NSRange range = [filterString rangeOfCharacterFromSet:set]; NSRange range = [filterString rangeOfCharacterFromSet:set];
while (range.length) { while (range.length) {
[filterString replaceCharactersInRange:range withString:@""]; [filterString replaceCharactersInRange:range withString:@""];
range = [filterString rangeOfCharacterFromSet:set]; range = [filterString rangeOfCharacterFromSet:set];
} }
return return [[[NSArray alloc]
[[[NSArray alloc] initWithArray:[filterString componentsSeparatedByString:@";"]] autorelease]; initWithArray:[filterString componentsSeparatedByString:@";"]]
autorelease];
NS_OBJC_END_TRY_BLOCK_RETURN(nil); NS_OBJC_END_TRY_BLOCK_RETURN(nil);
} }
@ -546,8 +580,10 @@ void nsFilePicker::SetDialogTitle(const nsString& inTitle, id aPanel) {
length:inTitle.Length()]]; length:inTitle.Length()]];
if (!mOkButtonLabel.IsEmpty()) { if (!mOkButtonLabel.IsEmpty()) {
[aPanel setPrompt:[NSString stringWithCharacters:(const unichar*)mOkButtonLabel.get() [aPanel
length:mOkButtonLabel.Length()]]; setPrompt:[NSString
stringWithCharacters:(const unichar*)mOkButtonLabel.get()
length:mOkButtonLabel.Length()]];
} }
NS_OBJC_END_TRY_IGNORE_BLOCK; NS_OBJC_END_TRY_IGNORE_BLOCK;
@ -562,9 +598,9 @@ NSString* nsFilePicker::PanelDefaultDirectory() {
if (mDisplayDirectory) { if (mDisplayDirectory) {
nsAutoString pathStr; nsAutoString pathStr;
mDisplayDirectory->GetPath(pathStr); mDisplayDirectory->GetPath(pathStr);
directory = directory = [[[NSString alloc]
[[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(pathStr.get()) initWithCharacters:reinterpret_cast<const unichar*>(pathStr.get())
length:pathStr.Length()] autorelease]; length:pathStr.Length()] autorelease];
} }
return directory; return directory;
@ -602,7 +638,9 @@ NS_IMETHODIMP nsFilePicker::SetDefaultString(const nsAString& aString) {
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsFilePicker::GetDefaultString(nsAString& aString) { return NS_ERROR_FAILURE; } NS_IMETHODIMP nsFilePicker::GetDefaultString(nsAString& aString) {
return NS_ERROR_FAILURE;
}
// The default extension to use for files // The default extension to use for files
NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension) { NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension) {
@ -610,7 +648,9 @@ NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension) {
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const nsAString& aExtension) { return NS_OK; } NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const nsAString& aExtension) {
return NS_OK;
}
// Append an entry to the filters array // Append an entry to the filters array
NS_IMETHODIMP NS_IMETHODIMP

View file

@ -47,18 +47,22 @@ void nsLookAndFeel::NativeInit() {
} }
static nscolor GetColorFromNSColor(NSColor* aColor) { static nscolor GetColorFromNSColor(NSColor* aColor) {
NSColor* deviceColor = [aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]; NSColor* deviceColor =
[aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
return NS_RGBA((unsigned int)(deviceColor.redComponent * 255.0), return NS_RGBA((unsigned int)(deviceColor.redComponent * 255.0),
(unsigned int)(deviceColor.greenComponent * 255.0), (unsigned int)(deviceColor.greenComponent * 255.0),
(unsigned int)(deviceColor.blueComponent * 255.0), (unsigned int)(deviceColor.blueComponent * 255.0),
(unsigned int)(deviceColor.alphaComponent * 255.0)); (unsigned int)(deviceColor.alphaComponent * 255.0));
} }
static nscolor GetColorFromNSColorWithCustomAlpha(NSColor* aColor, float alpha) { static nscolor GetColorFromNSColorWithCustomAlpha(NSColor* aColor,
NSColor* deviceColor = [aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]; float alpha) {
NSColor* deviceColor =
[aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
return NS_RGBA((unsigned int)(deviceColor.redComponent * 255.0), return NS_RGBA((unsigned int)(deviceColor.redComponent * 255.0),
(unsigned int)(deviceColor.greenComponent * 255.0), (unsigned int)(deviceColor.greenComponent * 255.0),
(unsigned int)(deviceColor.blueComponent * 255.0), (unsigned int)(alpha * 255.0)); (unsigned int)(deviceColor.blueComponent * 255.0),
(unsigned int)(alpha * 255.0));
} }
// Turns an opaque selection color into a partially transparent selection color, // Turns an opaque selection color into a partially transparent selection color,
@ -74,11 +78,12 @@ static nscolor GetColorFromNSColorWithCustomAlpha(NSColor* aColor, float alpha)
// whereas white text on dark blue (which what you get if you mix // whereas white text on dark blue (which what you get if you mix
// partially-transparent light blue with the black textbox background) has much // partially-transparent light blue with the black textbox background) has much
// better contrast. // better contrast.
nscolor nsLookAndFeel::ProcessSelectionBackground(nscolor aColor, ColorScheme aScheme) { nscolor nsLookAndFeel::ProcessSelectionBackground(nscolor aColor,
ColorScheme aScheme) {
if (aScheme == ColorScheme::Dark) { if (aScheme == ColorScheme::Dark) {
// When we use a dark selection color, we do not change alpha because we do // When we use a dark selection color, we do not change alpha because we do
// not use dark selection in content. The dark system color is appropriate for // not use dark selection in content. The dark system color is appropriate
// Firefox UI without needing to adjust its alpha. // for Firefox UI without needing to adjust its alpha.
return aColor; return aColor;
} }
uint16_t hue, sat, value; uint16_t hue, sat, value;
@ -100,7 +105,8 @@ nscolor nsLookAndFeel::ProcessSelectionBackground(nscolor aColor, ColorScheme aS
return resultColor; return resultColor;
} }
nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor& aColor) { nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme,
nscolor& aColor) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK NS_OBJC_BEGIN_TRY_ABORT_BLOCK
NSAppearance.currentAppearance = NSAppearanceForColorScheme(aScheme); NSAppearance.currentAppearance = NSAppearanceForColorScheme(aScheme);
@ -108,18 +114,19 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
nscolor color = 0; nscolor color = 0;
switch (aID) { switch (aID) {
case ColorID::Infobackground: case ColorID::Infobackground:
color = aScheme == ColorScheme::Light ? NS_RGB(0xdd, 0xdd, 0xdd) color = aScheme == ColorScheme::Light
: GetColorFromNSColor(NSColor.windowBackgroundColor); ? NS_RGB(0xdd, 0xdd, 0xdd)
: GetColorFromNSColor(NSColor.windowBackgroundColor);
break; break;
case ColorID::Highlight: case ColorID::Highlight:
color = ProcessSelectionBackground(GetColorFromNSColor(NSColor.selectedTextBackgroundColor), color = ProcessSelectionBackground(
aScheme); GetColorFromNSColor(NSColor.selectedTextBackgroundColor), aScheme);
break; break;
// This is used to gray out the selection when it's not focused. Used with // This is used to gray out the selection when it's not focused. Used with
// nsISelectionController::SELECTION_DISABLED. // nsISelectionController::SELECTION_DISABLED.
case ColorID::TextSelectDisabledBackground: case ColorID::TextSelectDisabledBackground:
color = ProcessSelectionBackground(GetColorFromNSColor(NSColor.secondarySelectedControlColor), color = ProcessSelectionBackground(
aScheme); GetColorFromNSColor(NSColor.secondarySelectedControlColor), aScheme);
break; break;
case ColorID::MozMenuhoverdisabled: case ColorID::MozMenuhoverdisabled:
aColor = NS_TRANSPARENT; aColor = NS_TRANSPARENT;
@ -158,23 +165,26 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
// //
// css2 system colors http://www.w3.org/TR/REC-CSS2/ui.html#system-colors // css2 system colors http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
// //
// It's really hard to effectively map these to the Appearance Manager properly, // It's really hard to effectively map these to the Appearance Manager
// since they are modeled word for word after the win32 system colors and don't have any // properly, since they are modeled word for word after the win32 system
// real counterparts in the Mac world. I'm sure we'll be tweaking these for // colors and don't have any real counterparts in the Mac world. I'm sure
// years to come. // we'll be tweaking these for years to come.
// //
// Thanks to mpt26@student.canterbury.ac.nz for the hardcoded values that form the defaults // Thanks to mpt26@student.canterbury.ac.nz for the hardcoded values that
// form the defaults
// if querying the Appearance Manager fails ;) // if querying the Appearance Manager fails ;)
// //
case ColorID::MozMacDefaultbuttontext: case ColorID::MozMacDefaultbuttontext:
color = NS_RGB(0xFF, 0xFF, 0xFF); color = NS_RGB(0xFF, 0xFF, 0xFF);
break; break;
case ColorID::MozButtonactivetext: case ColorID::MozButtonactivetext:
// Pre-macOS 12, pressed buttons were filled with the highlight color and the text was white. // Pre-macOS 12, pressed buttons were filled with the highlight color and
// Starting with macOS 12, pressed (non-default) buttons are filled with medium gray and the // the text was white. Starting with macOS 12, pressed (non-default)
// text color is the same as in the non-pressed state. // buttons are filled with medium gray and the text color is the same as
color = nsCocoaFeatures::OnMontereyOrLater() ? GetColorFromNSColor(NSColor.controlTextColor) // in the non-pressed state.
: NS_RGB(0xFF, 0xFF, 0xFF); color = nsCocoaFeatures::OnMontereyOrLater()
? GetColorFromNSColor(NSColor.controlTextColor)
: NS_RGB(0xFF, 0xFF, 0xFF);
break; break;
case ColorID::Menutext: case ColorID::Menutext:
case ColorID::Infotext: case ColorID::Infotext:
@ -209,18 +219,22 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
break; break;
case ColorID::Buttonshadow: case ColorID::Buttonshadow:
case ColorID::Threeddarkshadow: case ColorID::Threeddarkshadow:
color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID) : NS_RGB(0xDC, 0xDC, 0xDC); color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID)
: NS_RGB(0xDC, 0xDC, 0xDC);
break; break;
case ColorID::Threedshadow: case ColorID::Threedshadow:
color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID) : NS_RGB(0xE0, 0xE0, 0xE0); color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID)
: NS_RGB(0xE0, 0xE0, 0xE0);
break; break;
case ColorID::Threedface: case ColorID::Threedface:
color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID) : NS_RGB(0xF0, 0xF0, 0xF0); color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID)
: NS_RGB(0xF0, 0xF0, 0xF0);
break; break;
case ColorID::Threedlightshadow: case ColorID::Threedlightshadow:
case ColorID::Buttonborder: case ColorID::Buttonborder:
case ColorID::MozDisabledfield: case ColorID::MozDisabledfield:
color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID) : NS_RGB(0xDA, 0xDA, 0xDA); color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID)
: NS_RGB(0xDA, 0xDA, 0xDA);
break; break;
case ColorID::Menu: case ColorID::Menu:
color = GetColorFromNSColor(NSColor.textBackgroundColor); color = GetColorFromNSColor(NSColor.textBackgroundColor);
@ -248,7 +262,8 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
color = GetColorFromNSColor(NSColor.controlTextColor); color = GetColorFromNSColor(NSColor.controlTextColor);
break; break;
case ColorID::MozMacFocusring: case ColorID::MozMacFocusring:
color = GetColorFromNSColorWithCustomAlpha(NSColor.keyboardFocusIndicatorColor, 0.48); color = GetColorFromNSColorWithCustomAlpha(
NSColor.keyboardFocusIndicatorColor, 0.48);
break; break;
case ColorID::MozMacMenutextdisable: case ColorID::MozMacMenutextdisable:
color = NS_RGB(0x98, 0x98, 0x98); color = NS_RGB(0x98, 0x98, 0x98);
@ -266,11 +281,13 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
break; break;
case ColorID::MozEventreerow: case ColorID::MozEventreerow:
// Background color of even list rows. // Background color of even list rows.
color = GetColorFromNSColor(NSColor.controlAlternatingRowBackgroundColors[0]); color =
GetColorFromNSColor(NSColor.controlAlternatingRowBackgroundColors[0]);
break; break;
case ColorID::MozOddtreerow: case ColorID::MozOddtreerow:
// Background color of odd list rows. // Background color of odd list rows.
color = GetColorFromNSColor(NSColor.controlAlternatingRowBackgroundColors[1]); color =
GetColorFromNSColor(NSColor.controlAlternatingRowBackgroundColors[1]);
break; break;
case ColorID::MozNativehyperlinktext: case ColorID::MozNativehyperlinktext:
color = GetColorFromNSColor(NSColor.linkColor); color = GetColorFromNSColor(NSColor.linkColor);
@ -281,13 +298,16 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
case ColorID::MozMacTooltip: case ColorID::MozMacTooltip:
case ColorID::MozMacMenupopup: case ColorID::MozMacMenupopup:
case ColorID::MozMacMenuitem: case ColorID::MozMacMenuitem:
color = aScheme == ColorScheme::Light ? NS_RGB(0xf6, 0xf6, 0xf6) : NS_RGB(0x28, 0x28, 0x28); color = aScheme == ColorScheme::Light ? NS_RGB(0xf6, 0xf6, 0xf6)
: NS_RGB(0x28, 0x28, 0x28);
break; break;
case ColorID::MozMacSourceList: case ColorID::MozMacSourceList:
color = aScheme == ColorScheme::Light ? NS_RGB(0xf6, 0xf6, 0xf6) : NS_RGB(0x2d, 0x2d, 0x2d); color = aScheme == ColorScheme::Light ? NS_RGB(0xf6, 0xf6, 0xf6)
: NS_RGB(0x2d, 0x2d, 0x2d);
break; break;
case ColorID::MozMacSourceListSelection: case ColorID::MozMacSourceListSelection:
color = aScheme == ColorScheme::Light ? NS_RGB(0xd3, 0xd3, 0xd3) : NS_RGB(0x2d, 0x2d, 0x2d); color = aScheme == ColorScheme::Light ? NS_RGB(0xd3, 0xd3, 0xd3)
: NS_RGB(0x2d, 0x2d, 0x2d);
break; break;
case ColorID::MozMacActiveMenuitem: case ColorID::MozMacActiveMenuitem:
case ColorID::MozMacActiveSourceListSelection: case ColorID::MozMacActiveSourceListSelection:
@ -298,7 +318,8 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
case ColorID::Inactivecaption: case ColorID::Inactivecaption:
case ColorID::Activecaption: { case ColorID::Activecaption: {
if (aScheme == ColorScheme::Light && if (aScheme == ColorScheme::Light &&
NSWorkspace.sharedWorkspace.accessibilityDisplayShouldIncreaseContrast) { NSWorkspace.sharedWorkspace
.accessibilityDisplayShouldIncreaseContrast) {
// This has better contrast than the stand-in colors. // This has better contrast than the stand-in colors.
aColor = GetColorFromNSColor(NSColor.windowBackgroundColor); aColor = GetColorFromNSColor(NSColor.windowBackgroundColor);
return NS_OK; return NS_OK;
@ -410,11 +431,13 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
aResult = NS_ALERT_TOP; aResult = NS_ALERT_TOP;
break; break;
case IntID::TabFocusModel: case IntID::TabFocusModel:
aResult = [NSApp isFullKeyboardAccessEnabled] ? nsIContent::eTabFocus_any aResult = [NSApp isFullKeyboardAccessEnabled]
: nsIContent::eTabFocus_textControlsMask; ? nsIContent::eTabFocus_any
: nsIContent::eTabFocus_textControlsMask;
break; break;
case IntID::ScrollToClick: { case IntID::ScrollToClick: {
aResult = [[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollerPagingBehavior"]; aResult = [[NSUserDefaults standardUserDefaults]
boolForKey:@"AppleScrollerPagingBehavior"];
} break; } break;
case IntID::ChosenMenuItemsShouldBlink: case IntID::ChosenMenuItemsShouldBlink:
aResult = 1; aResult = 1;
@ -444,19 +467,24 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
aResult = SystemWantsDarkTheme(); aResult = SystemWantsDarkTheme();
break; break;
case IntID::PrefersReducedMotion: case IntID::PrefersReducedMotion:
aResult = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceMotion; aResult =
NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceMotion;
break; break;
case IntID::PrefersReducedTransparency: case IntID::PrefersReducedTransparency:
aResult = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceTransparency; aResult = NSWorkspace.sharedWorkspace
.accessibilityDisplayShouldReduceTransparency;
break; break;
case IntID::InvertedColors: case IntID::InvertedColors:
aResult = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldInvertColors; aResult =
NSWorkspace.sharedWorkspace.accessibilityDisplayShouldInvertColors;
break; break;
case IntID::UseAccessibilityTheme: case IntID::UseAccessibilityTheme:
aResult = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldIncreaseContrast; aResult = NSWorkspace.sharedWorkspace
.accessibilityDisplayShouldIncreaseContrast;
break; break;
case IntID::VideoDynamicRange: { case IntID::VideoDynamicRange: {
// If the platform says it supports HDR, then we claim to support video-dynamic-range. // If the platform says it supports HDR, then we claim to support
// video-dynamic-range.
gfxPlatform* platform = gfxPlatform::GetPlatform(); gfxPlatform* platform = gfxPlatform::GetPlatform();
MOZ_ASSERT(platform); MOZ_ASSERT(platform);
aResult = platform->SupportsHDR(); aResult = platform->SupportsHDR();
@ -487,7 +515,8 @@ nsresult nsLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
aResult = 2.0f; aResult = 2.0f;
break; break;
case FloatID::CursorScale: { case FloatID::CursorScale: {
id uaDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.universalaccess"]; id uaDefaults = [[NSUserDefaults alloc]
initWithSuiteName:@"com.apple.universalaccess"];
float f = [uaDefaults floatForKey:@"mouseDriverCursorSize"]; float f = [uaDefaults floatForKey:@"mouseDriverCursorSize"];
[uaDefaults release]; [uaDefaults release];
aResult = f > 0.0 ? f : 1.0; // default to 1.0 if value not available aResult = f > 0.0 ? f : 1.0; // default to 1.0 if value not available
@ -504,24 +533,29 @@ nsresult nsLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
} }
bool nsLookAndFeel::SystemWantsDarkTheme() { bool nsLookAndFeel::SystemWantsDarkTheme() {
// This returns true if the macOS system appearance is set to dark mode, false otherwise. // This returns true if the macOS system appearance is set to dark mode, false
NSAppearanceName aquaOrDarkAqua = [NSApp.effectiveAppearance // otherwise.
bestMatchFromAppearancesWithNames:@[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]]; NSAppearanceName aquaOrDarkAqua =
[NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:@[
NSAppearanceNameAqua, NSAppearanceNameDarkAqua
]];
return [aquaOrDarkAqua isEqualToString:NSAppearanceNameDarkAqua]; return [aquaOrDarkAqua isEqualToString:NSAppearanceNameDarkAqua];
} }
/*static*/ /*static*/
bool nsLookAndFeel::IsSystemOrientationRTL() { bool nsLookAndFeel::IsSystemOrientationRTL() {
NSWindow* window = [[NSWindow alloc] initWithContentRect:NSZeroRect NSWindow* window =
styleMask:NSWindowStyleMaskBorderless [[NSWindow alloc] initWithContentRect:NSZeroRect
backing:NSBackingStoreBuffered styleMask:NSWindowStyleMaskBorderless
defer:NO]; backing:NSBackingStoreBuffered
defer:NO];
auto direction = window.windowTitlebarLayoutDirection; auto direction = window.windowTitlebarLayoutDirection;
[window release]; [window release];
return direction == NSUserInterfaceLayoutDirectionRightToLeft; return direction == NSUserInterfaceLayoutDirectionRightToLeft;
} }
bool nsLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName, gfxFontStyle& aFontStyle) { bool nsLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName,
gfxFontStyle& aFontStyle) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
nsAutoCString name; nsAutoCString name;
@ -535,8 +569,10 @@ bool nsLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName, gfxFontStyle&
void nsLookAndFeel::RecordAccessibilityTelemetry() { void nsLookAndFeel::RecordAccessibilityTelemetry() {
if ([[NSWorkspace sharedWorkspace] if ([[NSWorkspace sharedWorkspace]
respondsToSelector:@selector(accessibilityDisplayShouldInvertColors)]) { respondsToSelector:@selector
bool val = [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldInvertColors]; (accessibilityDisplayShouldInvertColors)]) {
bool val =
[[NSWorkspace sharedWorkspace] accessibilityDisplayShouldInvertColors];
Telemetry::ScalarSet(Telemetry::ScalarID::A11Y_INVERT_COLORS, val); Telemetry::ScalarSet(Telemetry::ScalarID::A11Y_INVERT_COLORS, val);
} }
} }
@ -553,14 +589,16 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
- (instancetype)init { - (instancetype)init {
self = [super init]; self = [super init];
[NSNotificationCenter.defaultCenter addObserver:self [NSNotificationCenter.defaultCenter
selector:@selector(colorsChanged) addObserver:self
name:NSControlTintDidChangeNotification selector:@selector(colorsChanged)
object:nil]; name:NSControlTintDidChangeNotification
[NSNotificationCenter.defaultCenter addObserver:self object:nil];
selector:@selector(colorsChanged) [NSNotificationCenter.defaultCenter
name:NSSystemColorsDidChangeNotification addObserver:self
object:nil]; selector:@selector(colorsChanged)
name:NSSystemColorsDidChangeNotification
object:nil];
[NSWorkspace.sharedWorkspace.notificationCenter [NSWorkspace.sharedWorkspace.notificationCenter
addObserver:self addObserver:self
@ -568,10 +606,11 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
name:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification name:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification
object:nil]; object:nil];
[NSNotificationCenter.defaultCenter addObserver:self [NSNotificationCenter.defaultCenter
selector:@selector(scrollbarsChanged) addObserver:self
name:NSPreferredScrollerStyleDidChangeNotification selector:@selector(scrollbarsChanged)
object:nil]; name:NSPreferredScrollerStyleDidChangeNotification
object:nil];
[NSDistributedNotificationCenter.defaultCenter [NSDistributedNotificationCenter.defaultCenter
addObserver:self addObserver:self
selector:@selector(scrollbarsChanged) selector:@selector(scrollbarsChanged)
@ -595,7 +634,10 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
forKeyPath:@"effectiveAppearance" forKeyPath:@"effectiveAppearance"
options:0 options:0
context:nil]; context:nil];
[NSApp addObserver:self forKeyPath:@"effectiveAppearance" options:0 context:nil]; [NSApp addObserver:self
forKeyPath:@"effectiveAppearance"
options:0
context:nil];
return self; return self;
} }
@ -607,7 +649,10 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
if ([keyPath isEqualToString:@"effectiveAppearance"]) { if ([keyPath isEqualToString:@"effectiveAppearance"]) {
[self entireThemeChanged]; [self entireThemeChanged];
} else { } else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; [super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
} }
} }
@ -620,11 +665,12 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
} }
- (void)mediaQueriesChanged { - (void)mediaQueriesChanged {
// Changing`Invert Colors` sends AccessibilityDisplayOptionsDidChangeNotifications. // Changing`Invert Colors` sends
// We monitor that setting via telemetry, so call into that // AccessibilityDisplayOptionsDidChangeNotifications. We monitor that setting
// recording method here. // via telemetry, so call into that recording method here.
nsLookAndFeel::RecordAccessibilityTelemetry(); nsLookAndFeel::RecordAccessibilityTelemetry();
LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::MediaQueriesOnly); LookAndFeel::NotifyChangedAllWindows(
widget::ThemeChangeKind::MediaQueriesOnly);
} }
- (void)colorsChanged { - (void)colorsChanged {
@ -632,9 +678,12 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
} }
- (void)cachedValuesChanged { - (void)cachedValuesChanged {
// We only need to re-cache (and broadcast) updated LookAndFeel values, so that they're // We only need to re-cache (and broadcast) updated LookAndFeel values, so
// up-to-date the next time they're queried. No further change handling is needed. // that they're up-to-date the next time they're queried. No further change
// TODO: Add a change hint for this which avoids the unnecessary media query invalidation. // handling is needed.
LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::MediaQueriesOnly); // TODO: Add a change hint for this which avoids the unnecessary media query
// invalidation.
LookAndFeel::NotifyChangedAllWindows(
widget::ThemeChangeKind::MediaQueriesOnly);
} }
@end @end

View file

@ -12,9 +12,9 @@
/*! @category nsMacCursor (PrivateMethods) /*! @category nsMacCursor (PrivateMethods)
@abstract Private methods internal to the nsMacCursor class. @abstract Private methods internal to the nsMacCursor class.
@discussion <code>nsMacCursor</code> is effectively an abstract class. It does not define @discussion <code>nsMacCursor</code> is effectively an abstract class. It
complete behaviour in and of itself, the subclasses defined in this file provide the useful does not define complete behaviour in and of itself, the subclasses defined
implementations. in this file provide the useful implementations.
*/ */
@interface nsMacCursor (PrivateMethods) @interface nsMacCursor (PrivateMethods)
@ -27,56 +27,62 @@
/*! @method numFrames /*! @method numFrames
@abstract Query the number of frames in this cursor's animation. @abstract Query the number of frames in this cursor's animation.
@discussion Returns the number of frames in this cursor's animation. Static cursors return 1. @discussion Returns the number of frames in this cursor's animation. Static
cursors return 1.
*/ */
- (int)numFrames; - (int)numFrames;
/*! @method createTimer /*! @method createTimer
@abstract Create a Timer to use to animate the cursor. @abstract Create a Timer to use to animate the cursor.
@discussion Creates an instance of <code>NSTimer</code> which is used to drive the cursor @discussion Creates an instance of <code>NSTimer</code> which is used to
animation. This method should only be called for cursors that are animated. drive the cursor animation. This method should only be called for cursors
that are animated.
*/ */
- (void)createTimer; - (void)createTimer;
/*! @method destroyTimer /*! @method destroyTimer
@abstract Destroy any timer instance associated with this cursor. @abstract Destroy any timer instance associated with this cursor.
@discussion Invalidates and releases any <code>NSTimer</code> instance associated with this @discussion Invalidates and releases any <code>NSTimer</code> instance
cursor. associated with this cursor.
*/ */
- (void)destroyTimer; - (void)destroyTimer;
/*! @method destroyTimer /*! @method destroyTimer
@abstract Destroy any timer instance associated with this cursor. @abstract Destroy any timer instance associated with this cursor.
@discussion Invalidates and releases any <code>NSTimer</code> instance associated with this @discussion Invalidates and releases any <code>NSTimer</code> instance
cursor. associated with this cursor.
*/ */
/*! @method advanceAnimatedCursor: /*! @method advanceAnimatedCursor:
@abstract Method called by animation timer to perform animation. @abstract Method called by animation timer to perform animation.
@discussion Called by an animated cursor's associated timer to advance the animation to the next @discussion Called by an animated cursor's associated timer to advance the
frame. Determines which frame should occur next and sets the cursor to that frame. animation to the next frame. Determines which frame should occur next and
sets the cursor to that frame.
@param aTimer the timer causing the animation @param aTimer the timer causing the animation
*/ */
- (void)advanceAnimatedCursor:(NSTimer*)aTimer; - (void)advanceAnimatedCursor:(NSTimer*)aTimer;
/*! @method setFrame: /*! @method setFrame:
@abstract Sets the current cursor, using an index to determine which frame in the animation to @abstract Sets the current cursor, using an index to determine which frame
display. in the animation to display.
@discussion Sets the current cursor. The frame index determines which frame is shown if the @discussion Sets the current cursor. The frame index determines which frame
cursor is animated. Frames and numbered from <code>0</code> to <code>-[nsMacCursor numFrames] - is shown if the cursor is animated. Frames and numbered from <code>0</code>
1</code>. A static cursor has a single frame, numbered 0. to <code>-[nsMacCursor numFrames] - 1</code>. A static cursor has a single
@param aFrameIndex the index indicating which frame from the animation to display frame, numbered 0.
@param aFrameIndex the index indicating which frame from the animation
to display
*/ */
- (void)setFrame:(int)aFrameIndex; - (void)setFrame:(int)aFrameIndex;
@end @end
/*! @class nsCocoaCursor /*! @class nsCocoaCursor
@abstract Implementation of <code>nsMacCursor</code> that uses Cocoa <code>NSCursor</code> @abstract Implementation of <code>nsMacCursor</code> that uses Cocoa
instances. <code>NSCursor</code> instances.
@discussion Displays a static or animated cursor, using Cocoa <code>NSCursor</code> instances. @discussion Displays a static or animated cursor, using Cocoa
These can be either built-in <code>NSCursor</code> instances, or custom <code>NSCursor</code>s <code>NSCursor</code> instances. These can be either built-in
created from images. When more than one <code>NSCursor</code> is provided, the cursor will use <code>NSCursor</code> instances, or custom <code>NSCursor</code>s created
these as animation frames. from images. When more than one <code>NSCursor</code> is provided, the cursor
will use these as animation frames.
*/ */
@interface nsCocoaCursor : nsMacCursor { @interface nsCocoaCursor : nsMacCursor {
@private @private
@ -85,13 +91,16 @@
} }
/*! @method initWithFrames: /*! @method initWithFrames:
@abstract Create an animated cursor by specifying the frames to use for the animation. @abstract Create an animated cursor by specifying the frames to use for
@discussion Creates a cursor that will animate by cycling through the given frames. Each element the animation.
of the array must be an instance of <code>NSCursor</code> @discussion Creates a cursor that will animate by cycling through the given
@param aCursorFrames an array of <code>NSCursor</code>, representing the frames of an frames. Each element of the array must be an instance of
animated cursor, in the order they should be played. <code>NSCursor</code>
@param aCursorFrames an array of <code>NSCursor</code>, representing
the frames of an animated cursor, in the order they should be played.
@param aType the corresponding <code>nsCursor</code> constant @param aType the corresponding <code>nsCursor</code> constant
@result an instance of <code>nsCocoaCursor</code> that will animate the given cursor frames @result an instance of <code>nsCocoaCursor</code> that will animate the
given cursor frames
*/ */
- (id)initWithFrames:(NSArray*)aCursorFrames type:(nsCursor)aType; - (id)initWithFrames:(NSArray*)aCursorFrames type:(nsCursor)aType;
@ -106,18 +115,22 @@
- (id)initWithCursor:(NSCursor*)aCursor type:(nsCursor)aType; - (id)initWithCursor:(NSCursor*)aCursor type:(nsCursor)aType;
/*! @method initWithImageNamed:hotSpot: /*! @method initWithImageNamed:hotSpot:
@abstract Create a cursor by specifying the name of an image resource to use for the cursor @abstract Create a cursor by specifying the name of an image resource to
and a hotspot. use for the cursor and a hotspot.
@discussion Creates a cursor by loading the named image using the <code>+[NSImage @discussion Creates a cursor by loading the named image using the
imageNamed:]</code> method. <p>The image must be compatible with any restrictions laid down by <code>+[NSImage imageNamed:]</code> method. <p>The image must be compatible
<code>NSCursor</code>. These vary by operating system version.</p> <p>The hotspot precisely with any restrictions laid down by <code>NSCursor</code>. These vary by
determines the point where the user clicks when using the cursor.</p> operating system version.</p> <p>The hotspot precisely determines the point
where the user clicks when using the cursor.</p>
@param aCursor the name of the image to use for the cursor @param aCursor the name of the image to use for the cursor
@param aPoint the point within the cursor to use as the hotspot @param aPoint the point within the cursor to use as the hotspot
@param aType the corresponding <code>nsCursor</code> constant @param aType the corresponding <code>nsCursor</code> constant
@result an instance of <code>nsCocoaCursor</code> that uses the given image and hotspot @result an instance of <code>nsCocoaCursor</code> that uses the given
image and hotspot
*/ */
- (id)initWithImageNamed:(NSString*)aCursorImage hotSpot:(NSPoint)aPoint type:(nsCursor)aType; - (id)initWithImageNamed:(NSString*)aCursorImage
hotSpot:(NSPoint)aPoint
type:(nsCursor)aType;
@end @end
@ -126,7 +139,8 @@
+ (nsMacCursor*)cursorWithCursor:(NSCursor*)aCursor type:(nsCursor)aType { + (nsMacCursor*)cursorWithCursor:(NSCursor*)aCursor type:(nsCursor)aType {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
return [[[nsCocoaCursor alloc] initWithCursor:aCursor type:aType] autorelease]; return [[[nsCocoaCursor alloc] initWithCursor:aCursor
type:aType] autorelease];
NS_OBJC_END_TRY_BLOCK_RETURN(nil); NS_OBJC_END_TRY_BLOCK_RETURN(nil);
} }
@ -136,7 +150,8 @@
type:(nsCursor)aType { type:(nsCursor)aType {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
return [[[nsCocoaCursor alloc] initWithImageNamed:aCursorImage hotSpot:aPoint return [[[nsCocoaCursor alloc] initWithImageNamed:aCursorImage
hotSpot:aPoint
type:aType] autorelease]; type:aType] autorelease];
NS_OBJC_END_TRY_BLOCK_RETURN(nil); NS_OBJC_END_TRY_BLOCK_RETURN(nil);
@ -145,12 +160,14 @@
+ (nsMacCursor*)cursorWithFrames:(NSArray*)aCursorFrames type:(nsCursor)aType { + (nsMacCursor*)cursorWithFrames:(NSArray*)aCursorFrames type:(nsCursor)aType {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
return [[[nsCocoaCursor alloc] initWithFrames:aCursorFrames type:aType] autorelease]; return [[[nsCocoaCursor alloc] initWithFrames:aCursorFrames
type:aType] autorelease];
NS_OBJC_END_TRY_BLOCK_RETURN(nil); NS_OBJC_END_TRY_BLOCK_RETURN(nil);
} }
+ (NSCursor*)cocoaCursorWithImageNamed:(NSString*)imageName hotSpot:(NSPoint)aPoint { + (NSCursor*)cocoaCursorWithImageNamed:(NSString*)imageName
hotSpot:(NSPoint)aPoint {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
nsCOMPtr<nsIFile> resDir; nsCOMPtr<nsIFile> resDir;
@ -174,22 +191,26 @@
pathToImage = [pathToImage stringByAppendingPathExtension:@"png"]; pathToImage = [pathToImage stringByAppendingPathExtension:@"png"];
pathToHiDpiImage = [pathToHiDpiImage stringByAppendingPathExtension:@"png"]; pathToHiDpiImage = [pathToHiDpiImage stringByAppendingPathExtension:@"png"];
cursorImage = [[[NSImage alloc] initWithContentsOfFile:pathToImage] autorelease]; cursorImage =
[[[NSImage alloc] initWithContentsOfFile:pathToImage] autorelease];
if (!cursorImage) goto INIT_FAILURE; if (!cursorImage) goto INIT_FAILURE;
// Note 1: There are a few different ways to get a hidpi image via // Note 1: There are a few different ways to get a hidpi image via
// initWithContentsOfFile. We let the OS handle this here: when the // initWithContentsOfFile. We let the OS handle this here: when the
// file basename ends in "@2x", it will be displayed at native resolution // file basename ends in "@2x", it will be displayed at native resolution
// instead of being pixel-doubled. See bug 784909 comment 7 for alternates ways. // instead of being pixel-doubled. See bug 784909 comment 7 for alternates
// ways.
// //
// Note 2: The OS is picky, and will ignore the hidpi representation // Note 2: The OS is picky, and will ignore the hidpi representation
// unless it is exactly twice the size of the lowdpi image. // unless it is exactly twice the size of the lowdpi image.
hiDpiCursorImage = [[[NSImage alloc] initWithContentsOfFile:pathToHiDpiImage] autorelease]; hiDpiCursorImage =
[[[NSImage alloc] initWithContentsOfFile:pathToHiDpiImage] autorelease];
if (hiDpiCursorImage) { if (hiDpiCursorImage) {
NSImageRep* imageRep = [[hiDpiCursorImage representations] objectAtIndex:0]; NSImageRep* imageRep = [[hiDpiCursorImage representations] objectAtIndex:0];
[cursorImage addRepresentation:imageRep]; [cursorImage addRepresentation:imageRep];
} }
return [[[NSCursor alloc] initWithImage:cursorImage hotSpot:aPoint] autorelease]; return [[[NSCursor alloc] initWithImage:cursorImage
hotSpot:aPoint] autorelease];
INIT_FAILURE: INIT_FAILURE:
NS_WARNING("Problem getting path to cursor image file!"); NS_WARNING("Problem getting path to cursor image file!");
@ -236,11 +257,12 @@ INIT_FAILURE:
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK; NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
if (!mTimer) { if (!mTimer) {
mTimer = [[NSTimer scheduledTimerWithTimeInterval:0.25 mTimer = [[NSTimer
target:self scheduledTimerWithTimeInterval:0.25
selector:@selector(advanceAnimatedCursor:) target:self
userInfo:nil selector:@selector(advanceAnimatedCursor:)
repeats:YES] retain]; userInfo:nil
repeats:YES] retain];
} }
NS_OBJC_END_TRY_IGNORE_BLOCK; NS_OBJC_END_TRY_IGNORE_BLOCK;
@ -316,11 +338,15 @@ INIT_FAILURE:
NS_OBJC_END_TRY_BLOCK_RETURN(nil); NS_OBJC_END_TRY_BLOCK_RETURN(nil);
} }
- (id)initWithImageNamed:(NSString*)aCursorImage hotSpot:(NSPoint)aPoint type:(nsCursor)aType { - (id)initWithImageNamed:(NSString*)aCursorImage
hotSpot:(NSPoint)aPoint
type:(nsCursor)aType {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
return [self initWithCursor:[nsMacCursor cocoaCursorWithImageNamed:aCursorImage hotSpot:aPoint] return
type:aType]; [self initWithCursor:[nsMacCursor cocoaCursorWithImageNamed:aCursorImage
hotSpot:aPoint]
type:aType];
NS_OBJC_END_TRY_BLOCK_RETURN(nil); NS_OBJC_END_TRY_BLOCK_RETURN(nil);
} }

View file

@ -32,7 +32,8 @@ NS_IMPL_ISUPPORTS(nsMacDockSupport, nsIMacDockSupport, nsITaskbarProgress)
@synthesize fractionValue = mFractionValue; @synthesize fractionValue = mFractionValue;
- (void)drawRect:(NSRect)aRect { - (void)drawRect:(NSRect)aRect {
// Erase the background behind this view, i.e. cut a rectangle hole in the icon. // Erase the background behind this view, i.e. cut a rectangle hole in the
// icon.
[[NSColor clearColor] set]; [[NSColor clearColor] set];
NSRectFill(self.bounds); NSRectFill(self.bounds);
@ -103,7 +104,8 @@ NS_IMETHODIMP
nsMacDockSupport::ActivateApplication(bool aIgnoreOtherApplications) { nsMacDockSupport::ActivateApplication(bool aIgnoreOtherApplications) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
[[NSApplication sharedApplication] activateIgnoringOtherApps:aIgnoreOtherApplications]; [[NSApplication sharedApplication]
activateIgnoringOtherApps:aIgnoreOtherApplications];
return NS_OK; return NS_OK;
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
@ -118,9 +120,11 @@ nsMacDockSupport::SetBadgeText(const nsAString& aBadgeText) {
if (aBadgeText.IsEmpty()) if (aBadgeText.IsEmpty())
[tile setBadgeLabel:nil]; [tile setBadgeLabel:nil];
else else
[tile setBadgeLabel:[NSString [tile
stringWithCharacters:reinterpret_cast<const unichar*>(mBadgeText.get()) setBadgeLabel:[NSString
length:mBadgeText.Length()]]; stringWithCharacters:reinterpret_cast<const unichar*>(
mBadgeText.get())
length:mBadgeText.Length()]];
return NS_OK; return NS_OK;
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
@ -133,8 +137,8 @@ nsMacDockSupport::GetBadgeText(nsAString& aBadgeText) {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsMacDockSupport::SetProgressState(nsTaskbarProgressState aState, uint64_t aCurrentValue, nsMacDockSupport::SetProgressState(nsTaskbarProgressState aState,
uint64_t aMaxValue) { uint64_t aCurrentValue, uint64_t aMaxValue) {
NS_ENSURE_ARG_RANGE(aState, 0, STATE_PAUSED); NS_ENSURE_ARG_RANGE(aState, 0, STATE_PAUSED);
if (aState == STATE_NO_PROGRESS || aState == STATE_INDETERMINATE) { if (aState == STATE_NO_PROGRESS || aState == STATE_INDETERMINATE) {
NS_ENSURE_TRUE(aCurrentValue == 0, NS_ERROR_INVALID_ARG); NS_ENSURE_TRUE(aCurrentValue == 0, NS_ERROR_INVALID_ARG);
@ -162,22 +166,26 @@ nsresult nsMacDockSupport::UpdateDockTile() {
// Create the following NSView hierarchy: // Create the following NSView hierarchy:
// * mDockTileWrapperView (NSView) // * mDockTileWrapperView (NSView)
// * imageView (NSImageView) <- has the application icon // * imageView (NSImageView) <- has the application icon
// * mProgressDockOverlayView (MOZProgressDockOverlayView) <- draws the progress bar // * mProgressDockOverlayView (MOZProgressDockOverlayView) <- draws the
// progress bar
mDockTileWrapperView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 32, 32)]; mDockTileWrapperView =
mDockTileWrapperView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 32, 32)];
mDockTileWrapperView.autoresizingMask =
NSViewWidthSizable | NSViewHeightSizable;
NSImageView* imageView = [[NSImageView alloc] initWithFrame:[mDockTileWrapperView bounds]]; NSImageView* imageView =
[[NSImageView alloc] initWithFrame:[mDockTileWrapperView bounds]];
imageView.image = [NSImage imageNamed:@"NSApplicationIcon"]; imageView.image = [NSImage imageNamed:@"NSApplicationIcon"];
imageView.imageScaling = NSImageScaleAxesIndependently; imageView.imageScaling = NSImageScaleAxesIndependently;
imageView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; imageView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[mDockTileWrapperView addSubview:imageView]; [mDockTileWrapperView addSubview:imageView];
mProgressDockOverlayView = mProgressDockOverlayView = [[MOZProgressDockOverlayView alloc]
[[MOZProgressDockOverlayView alloc] initWithFrame:NSMakeRect(1, 3, 30, 4)]; initWithFrame:NSMakeRect(1, 3, 30, 4)];
mProgressDockOverlayView.autoresizingMask = NSViewMinXMargin | NSViewWidthSizable | mProgressDockOverlayView.autoresizingMask =
NSViewMaxXMargin | NSViewMinYMargin | NSViewMinXMargin | NSViewWidthSizable | NSViewMaxXMargin |
NSViewHeightSizable | NSViewMaxYMargin; NSViewMinYMargin | NSViewHeightSizable | NSViewMaxYMargin;
[mDockTileWrapperView addSubview:mProgressDockOverlayView]; [mDockTileWrapperView addSubview:mProgressDockOverlayView];
} }
if (NSApp.dockTile.contentView != mDockTileWrapperView) { if (NSApp.dockTile.contentView != mDockTileWrapperView) {
@ -205,21 +213,23 @@ nsresult nsMacDockSupport::UpdateDockTile() {
extern "C" { extern "C" {
// Private CFURL API used by the Dock. // Private CFURL API used by the Dock.
CFPropertyListRef _CFURLCopyPropertyListRepresentation(CFURLRef url); CFPropertyListRef _CFURLCopyPropertyListRepresentation(CFURLRef url);
CFURLRef _CFURLCreateFromPropertyListRepresentation(CFAllocatorRef alloc, CFURLRef _CFURLCreateFromPropertyListRepresentation(
CFPropertyListRef pListRepresentation); CFAllocatorRef alloc, CFPropertyListRef pListRepresentation);
} // extern "C" } // extern "C"
namespace { namespace {
const NSArray* const browserAppNames = const NSArray* const browserAppNames = [NSArray
[NSArray arrayWithObjects:@"Firefox.app", @"Firefox Beta.app", @"Firefox Nightly.app", arrayWithObjects:@"Firefox.app", @"Firefox Beta.app",
@"Safari.app", @"WebKit.app", @"Google Chrome.app", @"Firefox Nightly.app", @"Safari.app", @"WebKit.app",
@"Google Chrome Canary.app", @"Chromium.app", @"Opera.app", nil]; @"Google Chrome.app", @"Google Chrome Canary.app",
@"Chromium.app", @"Opera.app", nil];
constexpr NSString* const kDockDomainName = @"com.apple.dock"; constexpr NSString* const kDockDomainName = @"com.apple.dock";
// See https://developer.apple.com/documentation/devicemanagement/dock // See https://developer.apple.com/documentation/devicemanagement/dock
constexpr NSString* const kDockPersistentAppsKey = @"persistent-apps"; constexpr NSString* const kDockPersistentAppsKey = @"persistent-apps";
// See https://developer.apple.com/documentation/devicemanagement/dock/staticitem // See
// https://developer.apple.com/documentation/devicemanagement/dock/staticitem
constexpr NSString* const kDockTileDataKey = @"tile-data"; constexpr NSString* const kDockTileDataKey = @"tile-data";
constexpr NSString* const kDockFileDataKey = @"file-data"; constexpr NSString* const kDockFileDataKey = @"file-data";
@ -247,7 +257,8 @@ NSString* GetPathForApp(NSDictionary* aPersistantApp) {
// Some special tiles may not have DockFileData but we can ignore those. // Some special tiles may not have DockFileData but we can ignore those.
return nil; return nil;
} }
NSURL* url = CFBridgingRelease(_CFURLCreateFromPropertyListRepresentation(NULL, fileData)); NSURL* url = CFBridgingRelease(
_CFURLCreateFromPropertyListRepresentation(NULL, fileData));
if (!url) { if (!url) {
return nil; return nil;
} }
@ -257,7 +268,8 @@ NSString* GetPathForApp(NSDictionary* aPersistantApp) {
// The only reliable way to get our changes to take effect seems to be to use // The only reliable way to get our changes to take effect seems to be to use
// `kill`. // `kill`.
void RefreshDock(NSDictionary* aDockPlist) { void RefreshDock(NSDictionary* aDockPlist) {
[[NSUserDefaults standardUserDefaults] setPersistentDomain:aDockPlist forName:kDockDomainName]; [[NSUserDefaults standardUserDefaults] setPersistentDomain:aDockPlist
forName:kDockDomainName];
NSRunningApplication* dockApp = [[NSRunningApplication NSRunningApplication* dockApp = [[NSRunningApplication
runningApplicationsWithBundleIdentifier:@"com.apple.dock"] firstObject]; runningApplicationsWithBundleIdentifier:@"com.apple.dock"] firstObject];
if (!dockApp) { if (!dockApp) {
@ -276,8 +288,8 @@ nsresult nsMacDockSupport::GetIsAppInDock(bool* aIsInDock) {
*aIsInDock = false; *aIsInDock = false;
NSDictionary* dockPlist = NSDictionary* dockPlist = [[NSUserDefaults standardUserDefaults]
[[NSUserDefaults standardUserDefaults] persistentDomainForName:kDockDomainName]; persistentDomainForName:kDockDomainName];
if (!dockPlist) { if (!dockPlist) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -302,22 +314,22 @@ nsresult nsMacDockSupport::GetIsAppInDock(bool* aIsInDock) {
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
} }
nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(const nsAString& aAppPath, nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(
const nsAString& aAppToReplacePath, const nsAString& aAppPath, const nsAString& aAppToReplacePath,
bool* aIsInDock) { bool* aIsInDock) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
MOZ_ASSERT(aAppPath != aAppToReplacePath || !aAppPath.IsEmpty()); MOZ_ASSERT(aAppPath != aAppToReplacePath || !aAppPath.IsEmpty());
*aIsInDock = false; *aIsInDock = false;
NSString* appPath = NSString* appPath = !aAppPath.IsEmpty() ? nsCocoaUtils::ToNSString(aAppPath)
!aAppPath.IsEmpty() ? nsCocoaUtils::ToNSString(aAppPath) : [[NSBundle mainBundle] bundlePath]; : [[NSBundle mainBundle] bundlePath];
NSString* appToReplacePath = nsCocoaUtils::ToNSString(aAppToReplacePath); NSString* appToReplacePath = nsCocoaUtils::ToNSString(aAppToReplacePath);
NSMutableDictionary* dockPlist = NSMutableDictionary* dockPlist = [NSMutableDictionary
[NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults]
persistentDomainForName:kDockDomainName]]; persistentDomainForName:kDockDomainName]];
if (!dockPlist) { if (!dockPlist) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -335,11 +347,13 @@ nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(const nsAString& aAppPath,
NSUInteger toReplaceAppIndex = NSNotFound; NSUInteger toReplaceAppIndex = NSNotFound;
NSUInteger lastBrowserAppIndex = NSNotFound; NSUInteger lastBrowserAppIndex = NSNotFound;
for (NSUInteger index = 0; index < [persistentApps count]; ++index) { for (NSUInteger index = 0; index < [persistentApps count]; ++index) {
NSString* persistentAppPath = GetPathForApp([persistentApps objectAtIndex:index]); NSString* persistentAppPath =
GetPathForApp([persistentApps objectAtIndex:index]);
if ([persistentAppPath isEqualToString:appPath]) { if ([persistentAppPath isEqualToString:appPath]) {
preexistingAppIndex = index; preexistingAppIndex = index;
} else if (appToReplacePath && [persistentAppPath isEqualToString:appToReplacePath]) { } else if (appToReplacePath &&
[persistentAppPath isEqualToString:appToReplacePath]) {
toReplaceAppIndex = index; toReplaceAppIndex = index;
} else { } else {
NSString* appName = [appPath lastPathComponent]; NSString* appName = [appPath lastPathComponent];
@ -381,14 +395,16 @@ nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(const nsAString& aAppPath,
NSDictionary* newDockTile = nullptr; NSDictionary* newDockTile = nullptr;
{ {
NSURL* appUrl = [NSURL fileURLWithPath:appPath isDirectory:YES]; NSURL* appUrl = [NSURL fileURLWithPath:appPath isDirectory:YES];
NSDictionary* dict = NSDictionary* dict = CFBridgingRelease(
CFBridgingRelease(_CFURLCopyPropertyListRepresentation((__bridge CFURLRef)appUrl)); _CFURLCopyPropertyListRepresentation((__bridge CFURLRef)appUrl));
if (!dict) { if (!dict) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
NSDictionary* dockTileData = [NSDictionary dictionaryWithObject:dict forKey:kDockFileDataKey]; NSDictionary* dockTileData =
[NSDictionary dictionaryWithObject:dict forKey:kDockFileDataKey];
if (dockTileData) { if (dockTileData) {
newDockTile = [NSDictionary dictionaryWithObject:dockTileData forKey:kDockTileDataKey]; newDockTile = [NSDictionary dictionaryWithObject:dockTileData
forKey:kDockTileDataKey];
} }
if (!newDockTile) { if (!newDockTile) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -397,7 +413,8 @@ nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(const nsAString& aAppPath,
// Update the Dock: // Update the Dock:
if (toReplaceAppIndex != NSNotFound) { if (toReplaceAppIndex != NSNotFound) {
[persistentApps replaceObjectAtIndex:toReplaceAppIndex withObject:newDockTile]; [persistentApps replaceObjectAtIndex:toReplaceAppIndex
withObject:newDockTile];
} else { } else {
NSUInteger index; NSUInteger index;
if (sameNameAppIndex != NSNotFound) { if (sameNameAppIndex != NSNotFound) {

View file

@ -1,4 +1,5 @@
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset:
* 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */ /* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public /* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -24,16 +25,19 @@ nsMacFinderProgress::~nsMacFinderProgress() {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsMacFinderProgress::Init(const nsAString& path, nsMacFinderProgress::Init(
nsIMacFinderProgressCanceledCallback* cancellationCallback) { const nsAString& path,
nsIMacFinderProgressCanceledCallback* cancellationCallback) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NSURL* pathUrl = [NSURL NSURL* pathUrl = [NSURL
fileURLWithPath:[NSString fileURLWithPath:[NSString
stringWithCharacters:reinterpret_cast<const unichar*>(path.BeginReading()) stringWithCharacters:reinterpret_cast<const unichar*>(
path.BeginReading())
length:path.Length()]]; length:path.Length()]];
NSDictionary* userInfo = @{ NSDictionary* userInfo = @{
@"NSProgressFileOperationKindKey" : @"NSProgressFileOperationKindDownloading", @"NSProgressFileOperationKindKey" :
@"NSProgressFileOperationKindDownloading",
@"NSProgressFileURLKey" : pathUrl @"NSProgressFileURLKey" : pathUrl
}; };
@ -41,13 +45,14 @@ nsMacFinderProgress::Init(const nsAString& path,
mProgress.kind = NSProgressKindFile; mProgress.kind = NSProgressKindFile;
mProgress.cancellable = YES; mProgress.cancellable = YES;
nsMainThreadPtrHandle<nsIMacFinderProgressCanceledCallback> cancellationCallbackHandle( nsMainThreadPtrHandle<nsIMacFinderProgressCanceledCallback>
new nsMainThreadPtrHolder<nsIMacFinderProgressCanceledCallback>( cancellationCallbackHandle(
"MacFinderProgress::CancellationCallback", cancellationCallback)); new nsMainThreadPtrHolder<nsIMacFinderProgressCanceledCallback>(
"MacFinderProgress::CancellationCallback", cancellationCallback));
mProgress.cancellationHandler = ^{ mProgress.cancellationHandler = ^{
NS_DispatchToMainThread( NS_DispatchToMainThread(NS_NewRunnableFunction(
NS_NewRunnableFunction("MacFinderProgress::Canceled", [cancellationCallbackHandle] { "MacFinderProgress::Canceled", [cancellationCallbackHandle] {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
cancellationCallbackHandle->Canceled(); cancellationCallbackHandle->Canceled();
})); }));
@ -61,7 +66,8 @@ nsMacFinderProgress::Init(const nsAString& path,
} }
NS_IMETHODIMP NS_IMETHODIMP
nsMacFinderProgress::UpdateProgress(uint64_t currentProgress, uint64_t totalProgress) { nsMacFinderProgress::UpdateProgress(uint64_t currentProgress,
uint64_t totalProgress) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
if (mProgress) { if (mProgress) {
mProgress.totalUnitCount = totalProgress; mProgress.totalUnitCount = totalProgress;

View file

@ -15,11 +15,13 @@
NS_IMPL_ISUPPORTS(nsMacSharingService, nsIMacSharingService) NS_IMPL_ISUPPORTS(nsMacSharingService, nsIMacSharingService)
NSString* const remindersServiceName = @"com.apple.reminders.RemindersShareExtension"; NSString* const remindersServiceName =
@"com.apple.reminders.RemindersShareExtension";
// These are some undocumented constants also used by Safari // These are some undocumented constants also used by Safari
// to let us open the preferences window // to let us open the preferences window
NSString* const extensionPrefPanePath = @"/System/Library/PreferencePanes/Extensions.prefPane"; NSString* const extensionPrefPanePath =
@"/System/Library/PreferencePanes/Extensions.prefPane";
const UInt32 openSharingSubpaneDescriptorType = 'ptru'; const UInt32 openSharingSubpaneDescriptorType = 'ptru';
NSString* const openSharingSubpaneActionKey = @"action"; NSString* const openSharingSubpaneActionKey = @"action";
NSString* const openSharingSubpaneActionValue = @"revealExtensionPoint"; NSString* const openSharingSubpaneActionValue = @"revealExtensionPoint";
@ -31,10 +33,11 @@ NSString* const openSharingSubpaneProtocolValue = @"com.apple.share-services";
- (id)name; - (id)name;
@end @end
// Filter providers that we do not want to expose to the user, because they are duplicates or do not // Filter providers that we do not want to expose to the user, because they are
// work correctly within the context // duplicates or do not work correctly within the context
static bool ShouldIgnoreProvider(NSString* aProviderName) { static bool ShouldIgnoreProvider(NSString* aProviderName) {
return [aProviderName isEqualToString:@"com.apple.share.System.add-to-safari-reading-list"]; return [aProviderName
isEqualToString:@"com.apple.share.System.add-to-safari-reading-list"];
} }
// Clean up the activity once the share is complete // Clean up the activity once the share is complete
@ -61,7 +64,8 @@ static bool ShouldIgnoreProvider(NSString* aProviderName) {
mShareActivity = nil; mShareActivity = nil;
} }
- (void)sharingService:(NSSharingService*)sharingService didShareItems:(NSArray*)items { - (void)sharingService:(NSSharingService*)sharingService
didShareItems:(NSArray*)items {
[self cleanup]; [self cleanup];
} }
@ -80,16 +84,18 @@ static bool ShouldIgnoreProvider(NSString* aProviderName) {
static NSString* NSImageToBase64(const NSImage* aImage) { static NSString* NSImageToBase64(const NSImage* aImage) {
CGImageRef cgRef = [aImage CGImageForProposedRect:nil context:nil hints:nil]; CGImageRef cgRef = [aImage CGImageForProposedRect:nil context:nil hints:nil];
NSBitmapImageRep* bitmapRep = [[NSBitmapImageRep alloc] initWithCGImage:cgRef]; NSBitmapImageRep* bitmapRep =
[[NSBitmapImageRep alloc] initWithCGImage:cgRef];
[bitmapRep setSize:[aImage size]]; [bitmapRep setSize:[aImage size]];
NSData* imageData = [bitmapRep representationUsingType:NSPNGFileType properties:@{}]; NSData* imageData = [bitmapRep representationUsingType:NSPNGFileType
properties:@{}];
NSString* base64Encoded = [imageData base64EncodedStringWithOptions:0]; NSString* base64Encoded = [imageData base64EncodedStringWithOptions:0];
[bitmapRep release]; [bitmapRep release];
return [NSString stringWithFormat:@"data:image/png;base64,%@", base64Encoded]; return [NSString stringWithFormat:@"data:image/png;base64,%@", base64Encoded];
} }
static void SetStrAttribute(JSContext* aCx, JS::Rooted<JSObject*>& aObj, const char* aKey, static void SetStrAttribute(JSContext* aCx, JS::Rooted<JSObject*>& aObj,
NSString* aVal) { const char* aKey, NSString* aVal) {
nsAutoString strVal; nsAutoString strVal;
mozilla::CopyCocoaStringToXPCOMString(aVal, strVal); mozilla::CopyCocoaStringToXPCOMString(aVal, strVal);
JS::Rooted<JSString*> title(aCx, JS_NewUCStringCopyZ(aCx, strVal.get())); JS::Rooted<JSString*> title(aCx, JS_NewUCStringCopyZ(aCx, strVal.get()));
@ -97,8 +103,9 @@ static void SetStrAttribute(JSContext* aCx, JS::Rooted<JSObject*>& aObj, const c
JS_SetProperty(aCx, aObj, aKey, attVal); JS_SetProperty(aCx, aObj, aKey, attVal);
} }
nsresult nsMacSharingService::GetSharingProviders(const nsAString& aPageUrl, JSContext* aCx, nsresult nsMacSharingService::GetSharingProviders(
JS::MutableHandle<JS::Value> aResult) { const nsAString& aPageUrl, JSContext* aCx,
JS::MutableHandle<JS::Value> aResult) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NSURL* url = nsCocoaUtils::ToNSURL(aPageUrl); NSURL* url = nsCocoaUtils::ToNSURL(aPageUrl);
@ -135,18 +142,20 @@ NS_IMETHODIMP
nsMacSharingService::OpenSharingPreferences() { nsMacSharingService::OpenSharingPreferences() {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NSURL* prefPaneURL = [NSURL fileURLWithPath:extensionPrefPanePath isDirectory:YES]; NSURL* prefPaneURL = [NSURL fileURLWithPath:extensionPrefPanePath
isDirectory:YES];
NSDictionary* args = @{ NSDictionary* args = @{
openSharingSubpaneActionKey : openSharingSubpaneActionValue, openSharingSubpaneActionKey : openSharingSubpaneActionValue,
openSharingSubpaneProtocolKey : openSharingSubpaneProtocolValue openSharingSubpaneProtocolKey : openSharingSubpaneProtocolValue
}; };
NSData* data = [NSPropertyListSerialization dataWithPropertyList:args NSData* data = [NSPropertyListSerialization
format:NSPropertyListXMLFormat_v1_0 dataWithPropertyList:args
options:0 format:NSPropertyListXMLFormat_v1_0
error:nil]; options:0
NSAppleEventDescriptor* descriptor = error:nil];
[[NSAppleEventDescriptor alloc] initWithDescriptorType:openSharingSubpaneDescriptorType NSAppleEventDescriptor* descriptor = [[NSAppleEventDescriptor alloc]
data:data]; initWithDescriptorType:openSharingSubpaneDescriptorType
data:data];
[[NSWorkspace sharedWorkspace] openURLs:@[ prefPaneURL ] [[NSWorkspace sharedWorkspace] openURLs:@[ prefPaneURL ]
withAppBundleIdentifier:nil withAppBundleIdentifier:nil
@ -161,19 +170,21 @@ nsMacSharingService::OpenSharingPreferences() {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsMacSharingService::ShareUrl(const nsAString& aServiceName, const nsAString& aPageUrl, nsMacSharingService::ShareUrl(const nsAString& aServiceName,
const nsAString& aPageUrl,
const nsAString& aPageTitle) { const nsAString& aPageTitle) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
NSString* serviceName = nsCocoaUtils::ToNSString(aServiceName); NSString* serviceName = nsCocoaUtils::ToNSString(aServiceName);
NSURL* pageUrl = nsCocoaUtils::ToNSURL(aPageUrl); NSURL* pageUrl = nsCocoaUtils::ToNSURL(aPageUrl);
NSString* pageTitle = nsCocoaUtils::ToNSString(aPageTitle); NSString* pageTitle = nsCocoaUtils::ToNSString(aPageTitle);
NSSharingService* service = [NSSharingService sharingServiceNamed:serviceName]; NSSharingService* service =
[NSSharingService sharingServiceNamed:serviceName];
// Reminders fetch its data from an activity, not the share data // Reminders fetch its data from an activity, not the share data
if ([[service name] isEqual:remindersServiceName]) { if ([[service name] isEqual:remindersServiceName]) {
NSUserActivity* shareActivity = NSUserActivity* shareActivity = [[NSUserActivity alloc]
[[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb]; initWithActivityType:NSUserActivityTypeBrowsingWeb];
if ([pageUrl.scheme hasPrefix:@"http"]) { if ([pageUrl.scheme hasPrefix:@"http"]) {
[shareActivity setWebpageURL:pageUrl]; [shareActivity setWebpageURL:pageUrl];

View file

@ -13,7 +13,8 @@
NS_IMPL_ISUPPORTS(nsMacUserActivityUpdater, nsIMacUserActivityUpdater) NS_IMPL_ISUPPORTS(nsMacUserActivityUpdater, nsIMacUserActivityUpdater)
NS_IMETHODIMP NS_IMETHODIMP
nsMacUserActivityUpdater::UpdateLocation(const nsAString& aPageUrl, const nsAString& aPageTitle, nsMacUserActivityUpdater::UpdateLocation(const nsAString& aPageUrl,
const nsAString& aPageTitle,
nsIBaseWindow* aWindow) { nsIBaseWindow* aWindow) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
if (gfxPlatform::IsHeadless()) { if (gfxPlatform::IsHeadless()) {
@ -27,8 +28,8 @@ nsMacUserActivityUpdater::UpdateLocation(const nsAString& aPageUrl, const nsAStr
} }
NSURL* pageUrl = nsCocoaUtils::ToNSURL(aPageUrl); NSURL* pageUrl = nsCocoaUtils::ToNSURL(aPageUrl);
if (!pageUrl || if (!pageUrl || (![pageUrl.scheme isEqualToString:@"https"] &&
(![pageUrl.scheme isEqualToString:@"https"] && ![pageUrl.scheme isEqualToString:@"http"])) { ![pageUrl.scheme isEqualToString:@"http"])) {
[cocoaWin.userActivity invalidate]; [cocoaWin.userActivity invalidate];
return NS_OK; return NS_OK;
} }
@ -38,8 +39,8 @@ nsMacUserActivityUpdater::UpdateLocation(const nsAString& aPageUrl, const nsAStr
pageTitle = pageUrl.absoluteString; pageTitle = pageUrl.absoluteString;
} }
NSUserActivity* userActivity = NSUserActivity* userActivity = [[NSUserActivity alloc]
[[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb]; initWithActivityType:NSUserActivityTypeBrowsingWeb];
userActivity.webpageURL = pageUrl; userActivity.webpageURL = pageUrl;
userActivity.title = pageTitle; userActivity.title = pageTitle;
cocoaWin.userActivity = userActivity; cocoaWin.userActivity = userActivity;

View file

@ -13,25 +13,28 @@
#include "nsObjCExceptions.h" #include "nsObjCExceptions.h"
// Find the path to the app with the given bundleIdentifier, if any. // Find the path to the app with the given bundleIdentifier, if any.
// Note that the OS will return the path to the newest binary, if there is more than one. // Note that the OS will return the path to the newest binary, if there is more
// The determination of 'newest' is complex and beyond the scope of this comment. // than one. The determination of 'newest' is complex and beyond the scope of
// this comment.
NS_IMPL_ISUPPORTS(nsMacWebAppUtils, nsIMacWebAppUtils) NS_IMPL_ISUPPORTS(nsMacWebAppUtils, nsIMacWebAppUtils)
NS_IMETHODIMP nsMacWebAppUtils::PathForAppWithIdentifier(const nsAString& bundleIdentifier, NS_IMETHODIMP nsMacWebAppUtils::PathForAppWithIdentifier(
nsAString& outPath) { const nsAString& bundleIdentifier, nsAString& outPath) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
outPath.Truncate(); outPath.Truncate();
nsAutoreleasePool localPool; nsAutoreleasePool localPool;
// note that the result of this expression might be nil, meaning no matching app was found. // note that the result of this expression might be nil, meaning no matching
// app was found.
NSString* temp = [[NSWorkspace sharedWorkspace] NSString* temp = [[NSWorkspace sharedWorkspace]
absolutePathForAppBundleWithIdentifier: absolutePathForAppBundleWithIdentifier:
[NSString stringWithCharacters:reinterpret_cast<const unichar*>( [NSString
((nsString)bundleIdentifier).get()) stringWithCharacters:reinterpret_cast<const unichar*>(
length:((nsString)bundleIdentifier).Length()]]; ((nsString)bundleIdentifier).get())
length:((nsString)bundleIdentifier).Length()]];
if (temp) { if (temp) {
// Copy out the resultant absolute path into outPath if non-nil. // Copy out the resultant absolute path into outPath if non-nil.
@ -43,18 +46,20 @@ NS_IMETHODIMP nsMacWebAppUtils::PathForAppWithIdentifier(const nsAString& bundle
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
} }
NS_IMETHODIMP nsMacWebAppUtils::LaunchAppWithIdentifier(const nsAString& bundleIdentifier) { NS_IMETHODIMP nsMacWebAppUtils::LaunchAppWithIdentifier(
const nsAString& bundleIdentifier) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
nsAutoreleasePool localPool; nsAutoreleasePool localPool;
// Note this might return false, meaning the app wasnt launched for some reason. // Note this might return false, meaning the app wasnt launched for some
// reason.
BOOL success = [[NSWorkspace sharedWorkspace] BOOL success = [[NSWorkspace sharedWorkspace]
launchAppWithBundleIdentifier:[NSString launchAppWithBundleIdentifier:
stringWithCharacters:reinterpret_cast<const unichar*>( [NSString
((nsString)bundleIdentifier) stringWithCharacters:reinterpret_cast<const unichar*>(
.get()) ((nsString)bundleIdentifier).get())
length:((nsString)bundleIdentifier).Length()] length:((nsString)bundleIdentifier).Length()]
options:(NSWorkspaceLaunchOptions)0 options:(NSWorkspaceLaunchOptions)0
additionalEventParamDescriptor:nil additionalEventParamDescriptor:nil
launchIdentifier:NULL]; launchIdentifier:NULL];
@ -64,7 +69,8 @@ NS_IMETHODIMP nsMacWebAppUtils::LaunchAppWithIdentifier(const nsAString& bundleI
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
} }
NS_IMETHODIMP nsMacWebAppUtils::TrashApp(const nsAString& path, nsITrashAppCallback* aCallback) { NS_IMETHODIMP nsMacWebAppUtils::TrashApp(const nsAString& path,
nsITrashAppCallback* aCallback) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
if (NS_WARN_IF(!aCallback)) { if (NS_WARN_IF(!aCallback)) {
@ -74,11 +80,13 @@ NS_IMETHODIMP nsMacWebAppUtils::TrashApp(const nsAString& path, nsITrashAppCallb
nsCOMPtr<nsITrashAppCallback> callback = aCallback; nsCOMPtr<nsITrashAppCallback> callback = aCallback;
NSString* tempString = NSString* tempString =
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(((nsString)path).get()) [NSString stringWithCharacters:reinterpret_cast<const unichar*>(
((nsString)path).get())
length:path.Length()]; length:path.Length()];
[[NSWorkspace sharedWorkspace] [[NSWorkspace sharedWorkspace]
recycleURLs:[NSArray arrayWithObject:[NSURL fileURLWithPath:tempString]] recycleURLs:[NSArray
arrayWithObject:[NSURL fileURLWithPath:tempString]]
completionHandler:^(NSDictionary* newURLs, NSError* error) { completionHandler:^(NSDictionary* newURLs, NSError* error) {
nsresult rv = (error == nil) ? NS_OK : NS_ERROR_FAILURE; nsresult rv = (error == nil) ? NS_OK : NS_ERROR_FAILURE;
callback->TrashAppFinished(rv); callback->TrashAppFinished(rv);

View file

@ -41,10 +41,11 @@ BOOL gSomeMenuBarPainted = NO;
// defined in nsCocoaWindow.mm. // defined in nsCocoaWindow.mm.
extern BOOL sTouchBarIsInitialized; extern BOOL sTouchBarIsInitialized;
// We keep references to the first quit and pref item content nodes we find, which // We keep references to the first quit and pref item content nodes we find,
// will be from the hidden window. We use these when the document for the current // which will be from the hidden window. We use these when the document for the
// window does not have a quit or pref item. We don't need strong refs here because // current window does not have a quit or pref item. We don't need strong refs
// these items are always strong ref'd by their owning menu bar (instance variable). // here because these items are always strong ref'd by their owning menu bar
// (instance variable).
static nsIContent* sAboutItemContent = nullptr; static nsIContent* sAboutItemContent = nullptr;
static nsIContent* sPrefItemContent = nullptr; static nsIContent* sPrefItemContent = nullptr;
static nsIContent* sAccountItemContent = nullptr; static nsIContent* sAccountItemContent = nullptr;
@ -140,8 +141,9 @@ void nsMenuBarX::ConstructNativeMenus() {
for (nsIContent* menuContent = mContent->GetFirstChild(); menuContent; for (nsIContent* menuContent = mContent->GetFirstChild(); menuContent;
menuContent = menuContent->GetNextSibling()) { menuContent = menuContent->GetNextSibling()) {
if (menuContent->IsXULElement(nsGkAtoms::menu)) { if (menuContent->IsXULElement(nsGkAtoms::menu)) {
InsertMenuAtIndex(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, menuContent->AsElement()), InsertMenuAtIndex(
GetMenuCount()); MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, menuContent->AsElement()),
GetMenuCount());
} }
} }
} }
@ -156,7 +158,8 @@ void nsMenuBarX::ConstructFallbackNativeMenus() {
nsCOMPtr<nsIStringBundle> stringBundle; nsCOMPtr<nsIStringBundle> stringBundle;
nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID); nsCOMPtr<nsIStringBundleService> bundleSvc =
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
bundleSvc->CreateBundle("chrome://global/locale/fallbackMenubar.properties", bundleSvc->CreateBundle("chrome://global/locale/fallbackMenubar.properties",
getter_AddRefs(stringBundle)); getter_AddRefs(stringBundle));
@ -173,8 +176,10 @@ void nsMenuBarX::ConstructFallbackNativeMenus() {
stringBundle->GetStringFromName(labelProp, labelUTF16); stringBundle->GetStringFromName(labelProp, labelUTF16);
stringBundle->GetStringFromName(keyProp, keyUTF16); stringBundle->GetStringFromName(keyProp, keyUTF16);
NSString* labelStr = [NSString stringWithUTF8String:NS_ConvertUTF16toUTF8(labelUTF16).get()]; NSString* labelStr =
NSString* keyStr = [NSString stringWithUTF8String:NS_ConvertUTF16toUTF8(keyUTF16).get()]; [NSString stringWithUTF8String:NS_ConvertUTF16toUTF8(labelUTF16).get()];
NSString* keyStr =
[NSString stringWithUTF8String:NS_ConvertUTF16toUTF8(keyUTF16).get()];
if (!nsMenuBarX::sNativeEventTarget) { if (!nsMenuBarX::sNativeEventTarget) {
nsMenuBarX::sNativeEventTarget = [[NativeMenuItemTarget alloc] init]; nsMenuBarX::sNativeEventTarget = [[NativeMenuItemTarget alloc] init];
@ -182,12 +187,14 @@ void nsMenuBarX::ConstructFallbackNativeMenus() {
sApplicationMenu = [[[[NSApp mainMenu] itemAtIndex:0] submenu] retain]; sApplicationMenu = [[[[NSApp mainMenu] itemAtIndex:0] submenu] retain];
if (!mApplicationMenuDelegate) { if (!mApplicationMenuDelegate) {
mApplicationMenuDelegate = [[ApplicationMenuDelegate alloc] initWithApplicationMenu:this]; mApplicationMenuDelegate =
[[ApplicationMenuDelegate alloc] initWithApplicationMenu:this];
} }
sApplicationMenu.delegate = mApplicationMenuDelegate; sApplicationMenu.delegate = mApplicationMenuDelegate;
NSMenuItem* quitMenuItem = [[[NSMenuItem alloc] initWithTitle:labelStr NSMenuItem* quitMenuItem =
action:@selector(menuItemHit:) [[[NSMenuItem alloc] initWithTitle:labelStr
keyEquivalent:keyStr] autorelease]; action:@selector(menuItemHit:)
keyEquivalent:keyStr] autorelease];
quitMenuItem.target = nsMenuBarX::sNativeEventTarget; quitMenuItem.target = nsMenuBarX::sNativeEventTarget;
quitMenuItem.tag = eCommand_ID_Quit; quitMenuItem.tag = eCommand_ID_Quit;
[sApplicationMenu addItem:quitMenuItem]; [sApplicationMenu addItem:quitMenuItem];
@ -201,7 +208,8 @@ uint32_t nsMenuBarX::GetMenuCount() { return mMenuArray.Length(); }
bool nsMenuBarX::MenuContainsAppMenu() { bool nsMenuBarX::MenuContainsAppMenu() {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
return (mNativeMenu.numberOfItems > 0 && [mNativeMenu itemAtIndex:0].submenu == sApplicationMenu); return (mNativeMenu.numberOfItems > 0 &&
[mNativeMenu itemAtIndex:0].submenu == sApplicationMenu);
NS_OBJC_END_TRY_ABORT_BLOCK; NS_OBJC_END_TRY_ABORT_BLOCK;
} }
@ -220,8 +228,9 @@ void nsMenuBarX::InsertMenuAtIndex(RefPtr<nsMenuX>&& aMenu, uint32_t aIndex) {
// Hook the new Application menu up to the menu bar. // Hook the new Application menu up to the menu bar.
NSMenu* mainMenu = NSApp.mainMenu; NSMenu* mainMenu = NSApp.mainMenu;
NS_ASSERTION(mainMenu.numberOfItems > 0, NS_ASSERTION(
"Main menu does not have any items, something is terribly wrong!"); mainMenu.numberOfItems > 0,
"Main menu does not have any items, something is terribly wrong!");
[mainMenu itemAtIndex:0].submenu = sApplicationMenu; [mainMenu itemAtIndex:0].submenu = sApplicationMenu;
} }
@ -230,7 +239,8 @@ void nsMenuBarX::InsertMenuAtIndex(RefPtr<nsMenuX>&& aMenu, uint32_t aIndex) {
// hook up submenus // hook up submenus
RefPtr<nsIContent> menuContent = aMenu->Content(); RefPtr<nsIContent> menuContent = aMenu->Content();
if (menuContent->GetChildCount() > 0 && !nsMenuUtilsX::NodeIsHiddenOrCollapsed(menuContent)) { if (menuContent->GetChildCount() > 0 &&
!nsMenuUtilsX::NodeIsHiddenOrCollapsed(menuContent)) {
MenuChildChangedVisibility(MenuChild(aMenu), true); MenuChildChangedVisibility(MenuChild(aMenu), true);
} }
@ -263,11 +273,14 @@ void nsMenuBarX::RemoveMenuAtIndex(uint32_t aIndex) {
NS_OBJC_END_TRY_ABORT_BLOCK; NS_OBJC_END_TRY_ABORT_BLOCK;
} }
void nsMenuBarX::ObserveAttributeChanged(mozilla::dom::Document* aDocument, nsIContent* aContent, void nsMenuBarX::ObserveAttributeChanged(mozilla::dom::Document* aDocument,
nsIContent* aContent,
nsAtom* aAttribute) {} nsAtom* aAttribute) {}
void nsMenuBarX::ObserveContentRemoved(mozilla::dom::Document* aDocument, nsIContent* aContainer, void nsMenuBarX::ObserveContentRemoved(mozilla::dom::Document* aDocument,
nsIContent* aChild, nsIContent* aPreviousSibling) { nsIContent* aContainer,
nsIContent* aChild,
nsIContent* aPreviousSibling) {
nsINode* parent = NODE_FROM(aContainer, aDocument); nsINode* parent = NODE_FROM(aContainer, aDocument);
MOZ_ASSERT(parent); MOZ_ASSERT(parent);
const Maybe<uint32_t> index = parent->ComputeIndexOf(aPreviousSibling); const Maybe<uint32_t> index = parent->ComputeIndexOf(aPreviousSibling);
@ -275,7 +288,8 @@ void nsMenuBarX::ObserveContentRemoved(mozilla::dom::Document* aDocument, nsICon
RemoveMenuAtIndex(index.isSome() ? *index + 1u : 0u); RemoveMenuAtIndex(index.isSome() ? *index + 1u : 0u);
} }
void nsMenuBarX::ObserveContentInserted(mozilla::dom::Document* aDocument, nsIContent* aContainer, void nsMenuBarX::ObserveContentInserted(mozilla::dom::Document* aDocument,
nsIContent* aContainer,
nsIContent* aChild) { nsIContent* aChild) {
InsertMenuAtIndex(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, aChild), InsertMenuAtIndex(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, aChild),
aContainer->ComputeIndexOf(aChild).valueOr(UINT32_MAX)); aContainer->ComputeIndexOf(aChild).valueOr(UINT32_MAX));
@ -285,7 +299,8 @@ void nsMenuBarX::ForceUpdateNativeMenuAt(const nsAString& aIndexString) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
NSString* locationString = NSString* locationString =
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(aIndexString.BeginReading()) [NSString stringWithCharacters:reinterpret_cast<const unichar*>(
aIndexString.BeginReading())
length:aIndexString.Length()]; length:aIndexString.Length()];
NSArray* indexes = [locationString componentsSeparatedByString:@"|"]; NSArray* indexes = [locationString componentsSeparatedByString:@"|"];
unsigned int indexCount = indexes.count; unsigned int indexCount = indexes.count;
@ -329,7 +344,9 @@ void nsMenuBarX::ForceUpdateNativeMenuAt(const nsAString& aIndexString) {
} }
RefPtr<nsIContent> content = targetMenu->match( RefPtr<nsIContent> content = targetMenu->match(
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); }, [](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); }); [](const RefPtr<nsMenuItemX>& aMenuItem) {
return aMenuItem->Content();
});
if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(content)) { if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(content)) {
visible++; visible++;
if (targetMenu->is<RefPtr<nsMenuX>>() && visible == (targetIndex + 1)) { if (targetMenu->is<RefPtr<nsMenuX>>() && visible == (targetIndex + 1)) {
@ -408,8 +425,9 @@ nsresult nsMenuBarX::Paint() {
// We have to keep the same menu item for the Application menu so we keep // We have to keep the same menu item for the Application menu so we keep
// passing it along. // passing it along.
NSMenu* outgoingMenu = NSApp.mainMenu; NSMenu* outgoingMenu = NSApp.mainMenu;
NS_ASSERTION(outgoingMenu.numberOfItems > 0, NS_ASSERTION(
"Main menu does not have any items, something is terribly wrong!"); outgoingMenu.numberOfItems > 0,
"Main menu does not have any items, something is terribly wrong!");
NSMenuItem* appMenuItem = [[outgoingMenu itemAtIndex:0] retain]; NSMenuItem* appMenuItem = [[outgoingMenu itemAtIndex:0] retain];
[outgoingMenu removeItemAtIndex:0]; [outgoingMenu removeItemAtIndex:0];
@ -456,8 +474,10 @@ bool nsMenuBarX::PerformKeyEquivalent(NSEvent* aEvent) {
return [mNativeMenu performSuperKeyEquivalent:aEvent]; return [mNativeMenu performSuperKeyEquivalent:aEvent];
} }
void nsMenuBarX::MenuChildChangedVisibility(const MenuChild& aChild, bool aIsVisible) { void nsMenuBarX::MenuChildChangedVisibility(const MenuChild& aChild,
MOZ_RELEASE_ASSERT(aChild.is<RefPtr<nsMenuX>>(), "nsMenuBarX only has nsMenuX children"); bool aIsVisible) {
MOZ_RELEASE_ASSERT(aChild.is<RefPtr<nsMenuX>>(),
"nsMenuBarX only has nsMenuX children");
const RefPtr<nsMenuX>& child = aChild.as<RefPtr<nsMenuX>>(); const RefPtr<nsMenuX>& child = aChild.as<RefPtr<nsMenuX>>();
NSMenuItem* item = child->NativeNSMenuItem(); NSMenuItem* item = child->NativeNSMenuItem();
if (aIsVisible) { if (aIsVisible) {
@ -475,8 +495,9 @@ NSInteger nsMenuBarX::CalculateNativeInsertionPoint(nsMenuX* aChild) {
return insertionPoint; return insertionPoint;
} }
// Only count items that are inside a menu. // Only count items that are inside a menu.
// XXXmstange Not sure what would cause free-standing items. Maybe for collapsed/hidden menus? // XXXmstange Not sure what would cause free-standing items. Maybe for
// In that case, an nsMenuX::IsVisible() method would be better. // collapsed/hidden menus? In that case, an nsMenuX::IsVisible() method
// would be better.
if (currMenu->NativeNSMenuItem().menu) { if (currMenu->NativeNSMenuItem().menu) {
insertionPoint++; insertionPoint++;
} }
@ -486,10 +507,12 @@ NSInteger nsMenuBarX::CalculateNativeInsertionPoint(nsMenuX* aChild) {
// Hide the item in the menu by setting the 'hidden' attribute. Returns it so // Hide the item in the menu by setting the 'hidden' attribute. Returns it so
// the caller can hang onto it if they so choose. // the caller can hang onto it if they so choose.
RefPtr<Element> nsMenuBarX::HideItem(mozilla::dom::Document* aDocument, const nsAString& aID) { RefPtr<Element> nsMenuBarX::HideItem(mozilla::dom::Document* aDocument,
const nsAString& aID) {
RefPtr<Element> menuElement = aDocument->GetElementById(aID); RefPtr<Element> menuElement = aDocument->GetElementById(aID);
if (menuElement) { if (menuElement) {
menuElement->SetAttr(kNameSpaceID_None, nsGkAtoms::hidden, u"true"_ns, false); menuElement->SetAttr(kNameSpaceID_None, nsGkAtoms::hidden, u"true"_ns,
false);
} }
return menuElement; return menuElement;
} }
@ -536,7 +559,8 @@ void nsMenuBarX::AquifyMenuBar() {
} }
// for creating menu items destined for the Application menu // for creating menu items destined for the Application menu
NSMenuItem* nsMenuBarX::CreateNativeAppMenuItem(nsMenuX* aMenu, const nsAString& aNodeID, NSMenuItem* nsMenuBarX::CreateNativeAppMenuItem(nsMenuX* aMenu,
const nsAString& aNodeID,
SEL aAction, int aTag, SEL aAction, int aTag,
NativeMenuItemTarget* aTarget) { NativeMenuItemTarget* aTarget) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@ -553,8 +577,8 @@ NSMenuItem* nsMenuBarX::CreateNativeAppMenuItem(nsMenuX* aMenu, const nsAString&
// Check collapsed rather than hidden since the app menu items are always // Check collapsed rather than hidden since the app menu items are always
// hidden in AquifyMenuBar. // hidden in AquifyMenuBar.
if (menuItem->AttrValueIs(kNameSpaceID_None, nsGkAtoms::collapsed, nsGkAtoms::_true, if (menuItem->AttrValueIs(kNameSpaceID_None, nsGkAtoms::collapsed,
eCaseMatters)) { nsGkAtoms::_true, eCaseMatters)) {
return nil; return nil;
} }
@ -577,20 +601,23 @@ NSMenuItem* nsMenuBarX::CreateNativeAppMenuItem(nsMenuX* aMenu, const nsAString&
nsAutoString keyChar(u" "_ns); nsAutoString keyChar(u" "_ns);
keyElement->GetAttr(nsGkAtoms::key, keyChar); keyElement->GetAttr(nsGkAtoms::key, keyChar);
if (!keyChar.EqualsLiteral(" ")) { if (!keyChar.EqualsLiteral(" ")) {
keyEquiv = [[NSString stringWithCharacters:reinterpret_cast<const unichar*>(keyChar.get()) keyEquiv = [[NSString
length:keyChar.Length()] lowercaseString]; stringWithCharacters:reinterpret_cast<const unichar*>(keyChar.get())
length:keyChar.Length()] lowercaseString];
} }
// now grab the key equivalent modifiers // now grab the key equivalent modifiers
nsAutoString modifiersStr; nsAutoString modifiersStr;
keyElement->GetAttr(nsGkAtoms::modifiers, modifiersStr); keyElement->GetAttr(nsGkAtoms::modifiers, modifiersStr);
uint8_t geckoModifiers = nsMenuUtilsX::GeckoModifiersForNodeAttribute(modifiersStr); uint8_t geckoModifiers =
macKeyModifiers = nsMenuUtilsX::MacModifiersForGeckoModifiers(geckoModifiers); nsMenuUtilsX::GeckoModifiersForNodeAttribute(modifiersStr);
macKeyModifiers =
nsMenuUtilsX::MacModifiersForGeckoModifiers(geckoModifiers);
} }
} }
// get the label into NSString-form // get the label into NSString-form
NSString* labelString = NSString* labelString = [NSString
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(label.get()) stringWithCharacters:reinterpret_cast<const unichar*>(label.get())
length:label.Length()]; length:label.Length()];
if (!labelString) { if (!labelString) {
labelString = @""; labelString = @"";
@ -634,7 +661,8 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
= Preferences... = <- menu_preferences = Preferences... = <- menu_preferences
= Account Settings = <- menu_accountmgr Only on Thunderbird = Account Settings = <- menu_accountmgr Only on Thunderbird
======================== ========================
= Services > = <- menu_mac_services <- (do not define key equivalent) = Services > = <- menu_mac_services <- (do not define key
equivalent)
======================== ========================
= Hide App = <- menu_mac_hide_app = Hide App = <- menu_mac_hide_app
= Hide Others = <- menu_mac_hide_others = Hide Others = <- menu_mac_hide_others
@ -646,34 +674,37 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
======================== ========================
If any of them are ommitted from the application's DOM, we just don't add If any of them are ommitted from the application's DOM, we just don't add
them. We always add a "Quit" item, but if an app developer does not provide a them. We always add a "Quit" item, but if an app developer does not provide
DOM node with the right ID for the Quit item, we add it in English. App a DOM node with the right ID for the Quit item, we add it in English. App
developers need only add each node with a label and a key equivalent (if they developers need only add each node with a label and a key equivalent (if
want one). Other attributes are optional. Like so: they want one). Other attributes are optional. Like so:
<menuitem id="menu_preferences" <menuitem id="menu_preferences"
label="&preferencesCmdMac.label;" label="&preferencesCmdMac.label;"
key="open_prefs_key"/> key="open_prefs_key"/>
We need to use this system for localization purposes, until we have a better way We need to use this system for localization purposes, until we have a better
to define the Application menu to be used on Mac OS X. way to define the Application menu to be used on Mac OS X.
*/ */
if (sApplicationMenu) { if (sApplicationMenu) {
if (!mApplicationMenuDelegate) { if (!mApplicationMenuDelegate) {
mApplicationMenuDelegate = [[ApplicationMenuDelegate alloc] initWithApplicationMenu:this]; mApplicationMenuDelegate =
[[ApplicationMenuDelegate alloc] initWithApplicationMenu:this];
} }
sApplicationMenu.delegate = mApplicationMenuDelegate; sApplicationMenu.delegate = mApplicationMenuDelegate;
// This code reads attributes we are going to care about from the DOM elements // This code reads attributes we are going to care about from the DOM
// elements
NSMenuItem* itemBeingAdded = nil; NSMenuItem* itemBeingAdded = nil;
BOOL addAboutSeparator = FALSE; BOOL addAboutSeparator = FALSE;
BOOL addPrefsSeparator = FALSE; BOOL addPrefsSeparator = FALSE;
// Add the About menu item // Add the About menu item
itemBeingAdded = CreateNativeAppMenuItem(aMenu, u"aboutName"_ns, @selector(menuItemHit:), itemBeingAdded = CreateNativeAppMenuItem(
eCommand_ID_About, nsMenuBarX::sNativeEventTarget); aMenu, u"aboutName"_ns, @selector(menuItemHit:), eCommand_ID_About,
nsMenuBarX::sNativeEventTarget);
if (itemBeingAdded) { if (itemBeingAdded) {
[sApplicationMenu addItem:itemBeingAdded]; [sApplicationMenu addItem:itemBeingAdded];
[itemBeingAdded release]; [itemBeingAdded release];
@ -688,8 +719,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
} }
// Add the Preferences menu item // Add the Preferences menu item
itemBeingAdded = CreateNativeAppMenuItem(aMenu, u"menu_preferences"_ns, @selector(menuItemHit:), itemBeingAdded = CreateNativeAppMenuItem(
eCommand_ID_Prefs, nsMenuBarX::sNativeEventTarget); aMenu, u"menu_preferences"_ns, @selector(menuItemHit:),
eCommand_ID_Prefs, nsMenuBarX::sNativeEventTarget);
if (itemBeingAdded) { if (itemBeingAdded) {
[sApplicationMenu addItem:itemBeingAdded]; [sApplicationMenu addItem:itemBeingAdded];
[itemBeingAdded release]; [itemBeingAdded release];
@ -699,8 +731,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
} }
// Add the Account Settings menu item. This is Thunderbird only // Add the Account Settings menu item. This is Thunderbird only
itemBeingAdded = CreateNativeAppMenuItem(aMenu, u"menu_accountmgr"_ns, @selector(menuItemHit:), itemBeingAdded = CreateNativeAppMenuItem(
eCommand_ID_Account, nsMenuBarX::sNativeEventTarget); aMenu, u"menu_accountmgr"_ns, @selector(menuItemHit:),
eCommand_ID_Account, nsMenuBarX::sNativeEventTarget);
if (itemBeingAdded) { if (itemBeingAdded) {
[sApplicationMenu addItem:itemBeingAdded]; [sApplicationMenu addItem:itemBeingAdded];
[itemBeingAdded release]; [itemBeingAdded release];
@ -713,7 +746,8 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
} }
// Add Services menu item // Add Services menu item
itemBeingAdded = CreateNativeAppMenuItem(aMenu, u"menu_mac_services"_ns, nil, 0, nil); itemBeingAdded =
CreateNativeAppMenuItem(aMenu, u"menu_mac_services"_ns, nil, 0, nil);
if (itemBeingAdded) { if (itemBeingAdded) {
[sApplicationMenu addItem:itemBeingAdded]; [sApplicationMenu addItem:itemBeingAdded];
@ -732,9 +766,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
BOOL addHideShowSeparator = FALSE; BOOL addHideShowSeparator = FALSE;
// Add menu item to hide this application // Add menu item to hide this application
itemBeingAdded = itemBeingAdded = CreateNativeAppMenuItem(
CreateNativeAppMenuItem(aMenu, u"menu_mac_hide_app"_ns, @selector(menuItemHit:), aMenu, u"menu_mac_hide_app"_ns, @selector(menuItemHit:),
eCommand_ID_HideApp, nsMenuBarX::sNativeEventTarget); eCommand_ID_HideApp, nsMenuBarX::sNativeEventTarget);
if (itemBeingAdded) { if (itemBeingAdded) {
[sApplicationMenu addItem:itemBeingAdded]; [sApplicationMenu addItem:itemBeingAdded];
[itemBeingAdded release]; [itemBeingAdded release];
@ -744,9 +778,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
} }
// Add menu item to hide other applications // Add menu item to hide other applications
itemBeingAdded = itemBeingAdded = CreateNativeAppMenuItem(
CreateNativeAppMenuItem(aMenu, u"menu_mac_hide_others"_ns, @selector(menuItemHit:), aMenu, u"menu_mac_hide_others"_ns, @selector(menuItemHit:),
eCommand_ID_HideOthers, nsMenuBarX::sNativeEventTarget); eCommand_ID_HideOthers, nsMenuBarX::sNativeEventTarget);
if (itemBeingAdded) { if (itemBeingAdded) {
[sApplicationMenu addItem:itemBeingAdded]; [sApplicationMenu addItem:itemBeingAdded];
[itemBeingAdded release]; [itemBeingAdded release];
@ -756,9 +790,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
} }
// Add menu item to show all applications // Add menu item to show all applications
itemBeingAdded = itemBeingAdded = CreateNativeAppMenuItem(
CreateNativeAppMenuItem(aMenu, u"menu_mac_show_all"_ns, @selector(menuItemHit:), aMenu, u"menu_mac_show_all"_ns, @selector(menuItemHit:),
eCommand_ID_ShowAll, nsMenuBarX::sNativeEventTarget); eCommand_ID_ShowAll, nsMenuBarX::sNativeEventTarget);
if (itemBeingAdded) { if (itemBeingAdded) {
[sApplicationMenu addItem:itemBeingAdded]; [sApplicationMenu addItem:itemBeingAdded];
[itemBeingAdded release]; [itemBeingAdded release];
@ -775,9 +809,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
BOOL addTouchBarSeparator = NO; BOOL addTouchBarSeparator = NO;
// Add Touch Bar customization menu item. // Add Touch Bar customization menu item.
itemBeingAdded = itemBeingAdded = CreateNativeAppMenuItem(
CreateNativeAppMenuItem(aMenu, u"menu_mac_touch_bar"_ns, @selector(menuItemHit:), aMenu, u"menu_mac_touch_bar"_ns, @selector(menuItemHit:),
eCommand_ID_TouchBar, nsMenuBarX::sNativeEventTarget); eCommand_ID_TouchBar, nsMenuBarX::sNativeEventTarget);
if (itemBeingAdded) { if (itemBeingAdded) {
[sApplicationMenu addItem:itemBeingAdded]; [sApplicationMenu addItem:itemBeingAdded];
@ -797,9 +831,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
} }
// Add quit menu item // Add quit menu item
itemBeingAdded = itemBeingAdded = CreateNativeAppMenuItem(
CreateNativeAppMenuItem(aMenu, u"menu_FileQuitItem"_ns, @selector(menuItemHit:), aMenu, u"menu_FileQuitItem"_ns, @selector(menuItemHit:),
eCommand_ID_Quit, nsMenuBarX::sNativeEventTarget); eCommand_ID_Quit, nsMenuBarX::sNativeEventTarget);
if (itemBeingAdded) { if (itemBeingAdded) {
[sApplicationMenu addItem:itemBeingAdded]; [sApplicationMenu addItem:itemBeingAdded];
[itemBeingAdded release]; [itemBeingAdded release];
@ -807,9 +841,10 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
} else { } else {
// the current application does not have a DOM node for "Quit". Add one // the current application does not have a DOM node for "Quit". Add one
// anyway, in English. // anyway, in English.
NSMenuItem* defaultQuitItem = [[[NSMenuItem alloc] initWithTitle:@"Quit" NSMenuItem* defaultQuitItem =
action:@selector(menuItemHit:) [[[NSMenuItem alloc] initWithTitle:@"Quit"
keyEquivalent:@"q"] autorelease]; action:@selector(menuItemHit:)
keyEquivalent:@"q"] autorelease];
defaultQuitItem.target = nsMenuBarX::sNativeEventTarget; defaultQuitItem.target = nsMenuBarX::sNativeEventTarget;
defaultQuitItem.tag = eCommand_ID_Quit; defaultQuitItem.tag = eCommand_ID_Quit;
[sApplicationMenu addItem:defaultQuitItem]; [sApplicationMenu addItem:defaultQuitItem];
@ -860,9 +895,9 @@ static BOOL gMenuItemsExecuteCommands = YES;
[super performKeyEquivalent:aEvent]; [super performKeyEquivalent:aEvent];
gMenuItemsExecuteCommands = YES; // return to default gMenuItemsExecuteCommands = YES; // return to default
// Return YES if we invoked a command and there is now no key window or we changed // Return YES if we invoked a command and there is now no key window or we
// the first responder. In this case we do not want to propagate the event because // changed the first responder. In this case we do not want to propagate the
// we don't want it handled again. // event because we don't want it handled again.
if (!NSApp.keyWindow || NSApp.keyWindow.firstResponder != firstResponder) { if (!NSApp.keyWindow || NSApp.keyWindow.firstResponder != firstResponder) {
return YES; return YES;
} }
@ -898,7 +933,8 @@ static BOOL gMenuItemsExecuteCommands = YES;
nsMenuGroupOwnerX* menuGroupOwner = nullptr; nsMenuGroupOwnerX* menuGroupOwner = nullptr;
nsMenuBarX* menuBar = nullptr; nsMenuBarX* menuBar = nullptr;
MOZMenuItemRepresentedObject* representedObject = nativeMenuItem.representedObject; MOZMenuItemRepresentedObject* representedObject =
nativeMenuItem.representedObject;
if (representedObject) { if (representedObject) {
menuGroupOwner = representedObject.menuGroupOwner; menuGroupOwner = representedObject.menuGroupOwner;
@ -914,13 +950,15 @@ static BOOL gMenuItemsExecuteCommands = YES;
[(MenuDelegate*)menu.delegate menu:menu willActivateItem:nativeMenuItem]; [(MenuDelegate*)menu.delegate menu:menu willActivateItem:nativeMenuItem];
} }
// Get the modifier flags and button for this menu item activation. The menu system does not pass // Get the modifier flags and button for this menu item activation. The menu
// an NSEvent to our action selector, but we can query the current NSEvent instead. The current // system does not pass an NSEvent to our action selector, but we can query
// NSEvent can be a key event or a mouseup event, depending on how the menu item is activated. // the current NSEvent instead. The current NSEvent can be a key event or a
NSEventModifierFlags modifierFlags = NSApp.currentEvent ? NSApp.currentEvent.modifierFlags : 0; // mouseup event, depending on how the menu item is activated.
mozilla::MouseButton button = NSApp.currentEvent NSEventModifierFlags modifierFlags =
? nsCocoaUtils::ButtonForEvent(NSApp.currentEvent) NSApp.currentEvent ? NSApp.currentEvent.modifierFlags : 0;
: mozilla::MouseButton::ePrimary; mozilla::MouseButton button =
NSApp.currentEvent ? nsCocoaUtils::ButtonForEvent(NSApp.currentEvent)
: mozilla::MouseButton::ePrimary;
// Do special processing if this is for an app-global command. // Do special processing if this is for an app-global command.
if (tag == eCommand_ID_About) { if (tag == eCommand_ID_About) {
@ -968,13 +1006,15 @@ static BOOL gMenuItemsExecuteCommands = YES;
if (menuBar && menuBar->mQuitItemContent) { if (menuBar && menuBar->mQuitItemContent) {
mostSpecificContent = menuBar->mQuitItemContent; mostSpecificContent = menuBar->mQuitItemContent;
} }
// If we have some content for quit we execute it. Otherwise we send a native app terminate // If we have some content for quit we execute it. Otherwise we send a
// message. If you want to stop a quit from happening, provide quit content and return // native app terminate message. If you want to stop a quit from happening,
// the event as unhandled. // provide quit content and return the event as unhandled.
if (mostSpecificContent) { if (mostSpecificContent) {
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent, modifierFlags, button); nsMenuUtilsX::DispatchCommandTo(mostSpecificContent, modifierFlags,
button);
} else { } else {
nsCOMPtr<nsIAppStartup> appStartup = mozilla::components::AppStartup::Service(); nsCOMPtr<nsIAppStartup> appStartup =
mozilla::components::AppStartup::Service();
if (appStartup) { if (appStartup) {
bool userAllowedQuit = true; bool userAllowedQuit = true;
appStartup->Quit(nsIAppStartup::eAttemptQuit, 0, &userAllowedQuit); appStartup->Quit(nsIAppStartup::eAttemptQuit, 0, &userAllowedQuit);
@ -986,12 +1026,13 @@ static BOOL gMenuItemsExecuteCommands = YES;
// given the commandID, look it up in our hashtable and dispatch to // given the commandID, look it up in our hashtable and dispatch to
// that menu item. // that menu item.
if (menuGroupOwner) { if (menuGroupOwner) {
if (RefPtr<nsMenuItemX> menuItem = if (RefPtr<nsMenuItemX> menuItem = menuGroupOwner->GetMenuItemForCommandID(
menuGroupOwner->GetMenuItemForCommandID(static_cast<uint32_t>(tag))) { static_cast<uint32_t>(tag))) {
if (nsMenuUtilsX::gIsSynchronouslyActivatingNativeMenuItemDuringTest) { if (nsMenuUtilsX::gIsSynchronouslyActivatingNativeMenuItemDuringTest) {
menuItem->DoCommand(modifierFlags, button); menuItem->DoCommand(modifierFlags, button);
} else if (RefPtr<nsMenuX> menu = menuItem->ParentMenu()) { } else if (RefPtr<nsMenuX> menu = menuItem->ParentMenu()) {
menu->ActivateItemAfterClosing(std::move(menuItem), modifierFlags, button); menu->ActivateItemAfterClosing(std::move(menuItem), modifierFlags,
button);
} }
} }
} }
@ -1041,7 +1082,9 @@ static BOOL gMenuItemsExecuteCommands = YES;
- (NSMenuItem*)addItemWithTitle:(NSString*)aString - (NSMenuItem*)addItemWithTitle:(NSString*)aString
action:(SEL)aSelector action:(SEL)aSelector
keyEquivalent:(NSString*)aKeyEquiv { keyEquivalent:(NSString*)aKeyEquiv {
NSMenuItem* newItem = [super addItemWithTitle:aString action:aSelector keyEquivalent:aKeyEquiv]; NSMenuItem* newItem = [super addItemWithTitle:aString
action:aSelector
keyEquivalent:aKeyEquiv];
[self _overrideClassOfMenuItem:newItem]; [self _overrideClassOfMenuItem:newItem];
return newItem; return newItem;
} }

View file

@ -26,13 +26,16 @@ using namespace mozilla;
NS_IMPL_ISUPPORTS(nsMenuGroupOwnerX, nsIObserver, nsIMutationObserver) NS_IMPL_ISUPPORTS(nsMenuGroupOwnerX, nsIObserver, nsIMutationObserver)
nsMenuGroupOwnerX::nsMenuGroupOwnerX(mozilla::dom::Element* aElement, nsMenuBarX* aMenuBarIfMenuBar) nsMenuGroupOwnerX::nsMenuGroupOwnerX(mozilla::dom::Element* aElement,
nsMenuBarX* aMenuBarIfMenuBar)
: mContent(aElement), mMenuBar(aMenuBarIfMenuBar) { : mContent(aElement), mMenuBar(aMenuBarIfMenuBar) {
mRepresentedObject = [[MOZMenuItemRepresentedObject alloc] initWithMenuGroupOwner:this]; mRepresentedObject =
[[MOZMenuItemRepresentedObject alloc] initWithMenuGroupOwner:this];
} }
nsMenuGroupOwnerX::~nsMenuGroupOwnerX() { nsMenuGroupOwnerX::~nsMenuGroupOwnerX() {
MOZ_ASSERT(mContentToObserverTable.Count() == 0, "have outstanding mutation observers!\n"); MOZ_ASSERT(mContentToObserverTable.Count() == 0,
"have outstanding mutation observers!\n");
[mRepresentedObject setMenuGroupOwner:nullptr]; [mRepresentedObject setMenuGroupOwner:nullptr];
[mRepresentedObject release]; [mRepresentedObject release];
} }
@ -41,11 +44,11 @@ nsMenuGroupOwnerX::~nsMenuGroupOwnerX() {
// nsIMutationObserver // nsIMutationObserver
// //
void nsMenuGroupOwnerX::CharacterDataWillChange(nsIContent* aContent, void nsMenuGroupOwnerX::CharacterDataWillChange(
const CharacterDataChangeInfo&) {} nsIContent* aContent, const CharacterDataChangeInfo&) {}
void nsMenuGroupOwnerX::CharacterDataChanged(nsIContent* aContent, const CharacterDataChangeInfo&) { void nsMenuGroupOwnerX::CharacterDataChanged(nsIContent* aContent,
} const CharacterDataChangeInfo&) {}
void nsMenuGroupOwnerX::ContentAppended(nsIContent* aFirstNewContent) { void nsMenuGroupOwnerX::ContentAppended(nsIContent* aFirstNewContent) {
for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) { for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
@ -55,10 +58,13 @@ void nsMenuGroupOwnerX::ContentAppended(nsIContent* aFirstNewContent) {
void nsMenuGroupOwnerX::NodeWillBeDestroyed(nsINode* aNode) {} void nsMenuGroupOwnerX::NodeWillBeDestroyed(nsINode* aNode) {}
void nsMenuGroupOwnerX::AttributeWillChange(dom::Element* aElement, int32_t aNameSpaceID, void nsMenuGroupOwnerX::AttributeWillChange(dom::Element* aElement,
nsAtom* aAttribute, int32_t aModType) {} int32_t aNameSpaceID,
nsAtom* aAttribute,
int32_t aModType) {}
void nsMenuGroupOwnerX::AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID, void nsMenuGroupOwnerX::AttributeChanged(dom::Element* aElement,
int32_t aNameSpaceID,
nsAtom* aAttribute, int32_t aModType, nsAtom* aAttribute, int32_t aModType,
const nsAttrValue* aOldValue) { const nsAttrValue* aOldValue) {
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this); nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
@ -68,7 +74,8 @@ void nsMenuGroupOwnerX::AttributeChanged(dom::Element* aElement, int32_t aNameSp
} }
} }
void nsMenuGroupOwnerX::ContentRemoved(nsIContent* aChild, nsIContent* aPreviousSibling) { void nsMenuGroupOwnerX::ContentRemoved(nsIContent* aChild,
nsIContent* aPreviousSibling) {
nsIContent* container = aChild->GetParent(); nsIContent* container = aChild->GetParent();
if (!container) { if (!container) {
return; return;
@ -77,7 +84,8 @@ void nsMenuGroupOwnerX::ContentRemoved(nsIContent* aChild, nsIContent* aPrevious
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this); nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
nsChangeObserver* obs = LookupContentChangeObserver(container); nsChangeObserver* obs = LookupContentChangeObserver(container);
if (obs) { if (obs) {
obs->ObserveContentRemoved(aChild->OwnerDoc(), container, aChild, aPreviousSibling); obs->ObserveContentRemoved(aChild->OwnerDoc(), container, aChild,
aPreviousSibling);
} else if (container != mContent) { } else if (container != mContent) {
// We do a lookup on the parent container in case things were removed // We do a lookup on the parent container in case things were removed
// under a "menupopup" item. That is basically a wrapper for the contents // under a "menupopup" item. That is basically a wrapper for the contents
@ -86,7 +94,8 @@ void nsMenuGroupOwnerX::ContentRemoved(nsIContent* aChild, nsIContent* aPrevious
if (parent) { if (parent) {
obs = LookupContentChangeObserver(parent); obs = LookupContentChangeObserver(parent);
if (obs) { if (obs) {
obs->ObserveContentRemoved(aChild->OwnerDoc(), container, aChild, aPreviousSibling); obs->ObserveContentRemoved(aChild->OwnerDoc(), container, aChild,
aPreviousSibling);
} }
} }
} }
@ -118,18 +127,18 @@ void nsMenuGroupOwnerX::ContentInserted(nsIContent* aChild) {
void nsMenuGroupOwnerX::ParentChainChanged(nsIContent* aContent) {} void nsMenuGroupOwnerX::ParentChainChanged(nsIContent* aContent) {}
void nsMenuGroupOwnerX::ARIAAttributeDefaultWillChange(mozilla::dom::Element* aElement, void nsMenuGroupOwnerX::ARIAAttributeDefaultWillChange(
nsAtom* aAttribute, int32_t aModType) {} mozilla::dom::Element* aElement, nsAtom* aAttribute, int32_t aModType) {}
void nsMenuGroupOwnerX::ARIAAttributeDefaultChanged(mozilla::dom::Element* aElement, void nsMenuGroupOwnerX::ARIAAttributeDefaultChanged(
nsAtom* aAttribute, int32_t aModType) {} mozilla::dom::Element* aElement, nsAtom* aAttribute, int32_t aModType) {}
// For change management, we don't use a |nsSupportsHashtable| because // For change management, we don't use a |nsSupportsHashtable| because
// we know that the lifetime of all these items is bounded by the // we know that the lifetime of all these items is bounded by the
// lifetime of the menubar. No need to add any more strong refs to the // lifetime of the menubar. No need to add any more strong refs to the
// picture because the containment hierarchy already uses strong refs. // picture because the containment hierarchy already uses strong refs.
void nsMenuGroupOwnerX::RegisterForContentChanges(nsIContent* aContent, void nsMenuGroupOwnerX::RegisterForContentChanges(
nsChangeObserver* aMenuObject) { nsIContent* aContent, nsChangeObserver* aMenuObject) {
if (!mContentToObserverTable.Contains(aContent)) { if (!mContentToObserverTable.Contains(aContent)) {
aContent->AddMutationObserver(this); aContent->AddMutationObserver(this);
} }
@ -158,7 +167,8 @@ void nsMenuGroupOwnerX::UnregisterForLocaleChanges() {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsMenuGroupOwnerX::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { nsMenuGroupOwnerX::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
if (mMenuBar && !strcmp(aTopic, "intl:app-locales-changed")) { if (mMenuBar && !strcmp(aTopic, "intl:app-locales-changed")) {
// Rebuild the menu with the new locale strings. // Rebuild the menu with the new locale strings.
mMenuBar->SetNeedsRebuild(); mMenuBar->SetNeedsRebuild();
@ -166,7 +176,8 @@ nsMenuGroupOwnerX::Observe(nsISupports* aSubject, const char* aTopic, const char
return NS_OK; return NS_OK;
} }
nsChangeObserver* nsMenuGroupOwnerX::LookupContentChangeObserver(nsIContent* aContent) { nsChangeObserver* nsMenuGroupOwnerX::LookupContentChangeObserver(
nsIContent* aContent) {
nsChangeObserver* result; nsChangeObserver* result;
if (mContentToObserverTable.Get(aContent, &result)) { if (mContentToObserverTable.Get(aContent, &result)) {
return result; return result;
@ -206,7 +217,8 @@ nsMenuItemX* nsMenuGroupOwnerX::GetMenuItemForCommandID(uint32_t aCommandID) {
} }
@implementation MOZMenuItemRepresentedObject { @implementation MOZMenuItemRepresentedObject {
nsMenuGroupOwnerX* mMenuGroupOwner; // weak, cleared by nsMenuGroupOwnerX's destructor nsMenuGroupOwnerX*
mMenuGroupOwner; // weak, cleared by nsMenuGroupOwnerX's destructor
} }
- (id)initWithMenuGroupOwner:(nsMenuGroupOwnerX*)aMenuGroupOwner { - (id)initWithMenuGroupOwner:(nsMenuGroupOwnerX*)aMenuGroupOwner {

View file

@ -62,8 +62,8 @@ void nsMenuItemIconX::SetupIcon(nsIContent* aContent) {
bool shouldHaveIcon = StartIconLoad(aContent); bool shouldHaveIcon = StartIconLoad(aContent);
if (!shouldHaveIcon) { if (!shouldHaveIcon) {
// There is no icon for this menu item, as an error occurred while loading it. // There is no icon for this menu item, as an error occurred while loading
// An icon might have been set earlier or the place holder icon may have // it. An icon might have been set earlier or the place holder icon may have
// been set. Clear it. // been set. Clear it.
if (mIconImage) { if (mIconImage) {
[mIconImage release]; [mIconImage release];
@ -73,8 +73,9 @@ void nsMenuItemIconX::SetupIcon(nsIContent* aContent) {
} }
if (!mIconImage) { if (!mIconImage) {
// Set a placeholder icon, so that the menuitem reserves space for the icon during the load and // Set a placeholder icon, so that the menuitem reserves space for the icon
// there is no sudden shift once the icon finishes loading. // during the load and there is no sudden shift once the icon finishes
// loading.
NSSize iconSize = NSMakeSize(kIconSize, kIconSize); NSSize iconSize = NSMakeSize(kIconSize, kIconSize);
mIconImage = [[MOZIconHelper placeholderIconWithSize:iconSize] retain]; mIconImage = [[MOZIconHelper placeholderIconWithSize:iconSize] retain];
} }
@ -100,7 +101,8 @@ already_AddRefed<nsIURI> nsMenuItemIconX::GetIconURI(nsIContent* aContent) {
// First, look at the content node's "image" attribute. // First, look at the content node's "image" attribute.
nsAutoString imageURIString; nsAutoString imageURIString;
bool hasImageAttr = bool hasImageAttr =
aContent->IsElement() && aContent->AsElement()->GetAttr(nsGkAtoms::image, imageURIString); aContent->IsElement() &&
aContent->AsElement()->GetAttr(nsGkAtoms::image, imageURIString);
if (hasImageAttr) { if (hasImageAttr) {
// Use the URL from the image attribute. // Use the URL from the image attribute.
@ -121,7 +123,8 @@ already_AddRefed<nsIURI> nsMenuItemIconX::GetIconURI(nsIContent* aContent) {
return nullptr; return nullptr;
} }
RefPtr<const ComputedStyle> sc = nsComputedDOMStyle::GetComputedStyle(aContent->AsElement()); RefPtr<const ComputedStyle> sc =
nsComputedDOMStyle::GetComputedStyle(aContent->AsElement());
if (!sc) { if (!sc) {
return nullptr; return nullptr;
} }
@ -149,11 +152,12 @@ nsresult nsMenuItemIconX::OnComplete(imgIContainer* aImage) {
mIconImage = nil; mIconImage = nil;
} }
RefPtr<nsPresContext> pc = mPresContext.get(); RefPtr<nsPresContext> pc = mPresContext.get();
mIconImage = [[MOZIconHelper iconImageFromImageContainer:aImage mIconImage = [[MOZIconHelper
withSize:NSMakeSize(kIconSize, kIconSize) iconImageFromImageContainer:aImage
presContext:pc withSize:NSMakeSize(kIconSize, kIconSize)
computedStyle:mComputedStyle presContext:pc
scaleFactor:0.0f] retain]; computedStyle:mComputedStyle
scaleFactor:0.0f] retain];
mComputedStyle = nullptr; mComputedStyle = nullptr;
mPresContext = nullptr; mPresContext = nullptr;

View file

@ -26,14 +26,19 @@ using namespace mozilla;
using mozilla::dom::CallerType; using mozilla::dom::CallerType;
using mozilla::dom::Event; using mozilla::dom::Event;
nsMenuItemX::nsMenuItemX(nsMenuX* aParent, const nsString& aLabel, EMenuItemType aItemType, nsMenuItemX::nsMenuItemX(nsMenuX* aParent, const nsString& aLabel,
EMenuItemType aItemType,
nsMenuGroupOwnerX* aMenuGroupOwner, nsIContent* aNode) nsMenuGroupOwnerX* aMenuGroupOwner, nsIContent* aNode)
: mContent(aNode), mType(aItemType), mMenuParent(aParent), mMenuGroupOwner(aMenuGroupOwner) { : mContent(aNode),
mType(aItemType),
mMenuParent(aParent),
mMenuGroupOwner(aMenuGroupOwner) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
MOZ_COUNT_CTOR(nsMenuItemX); MOZ_COUNT_CTOR(nsMenuItemX);
MOZ_RELEASE_ASSERT(mContent->IsElement(), "nsMenuItemX should only be created for elements"); MOZ_RELEASE_ASSERT(mContent->IsElement(),
"nsMenuItemX should only be created for elements");
NS_ASSERTION(mMenuGroupOwner, "No menu owner given, must have one!"); NS_ASSERTION(mMenuGroupOwner, "No menu owner given, must have one!");
mMenuGroupOwner->RegisterForContentChanges(mContent, this); mMenuGroupOwner->RegisterForContentChanges(mContent, this);
@ -57,28 +62,29 @@ nsMenuItemX::nsMenuItemX(nsMenuX* aParent, const nsString& aLabel, EMenuItemType
} }
} }
// decide enabled state based on command content if it exists, otherwise do it based // decide enabled state based on command content if it exists, otherwise do it
// on our own content // based on our own content
bool isEnabled; bool isEnabled;
if (mCommandElement) { if (mCommandElement) {
isEnabled = !mCommandElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, isEnabled = !mCommandElement->AttrValueIs(
nsGkAtoms::_true, eCaseMatters); kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters);
} else { } else {
isEnabled = !mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, isEnabled = !mContent->AsElement()->AttrValueIs(
nsGkAtoms::_true, eCaseMatters); kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters);
} }
// set up the native menu item // set up the native menu item
if (mType == eSeparatorMenuItemType) { if (mType == eSeparatorMenuItemType) {
mNativeMenuItem = [[NSMenuItem separatorItem] retain]; mNativeMenuItem = [[NSMenuItem separatorItem] retain];
} else { } else {
NSString* newCocoaLabelString = nsMenuUtilsX::GetTruncatedCocoaLabel(aLabel); NSString* newCocoaLabelString =
nsMenuUtilsX::GetTruncatedCocoaLabel(aLabel);
mNativeMenuItem = [[NSMenuItem alloc] initWithTitle:newCocoaLabelString mNativeMenuItem = [[NSMenuItem alloc] initWithTitle:newCocoaLabelString
action:nil action:nil
keyEquivalent:@""]; keyEquivalent:@""];
mIsChecked = mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked, mIsChecked = mContent->AsElement()->AttrValueIs(
nsGkAtoms::_true, eCaseMatters); kNameSpaceID_None, nsGkAtoms::checked, nsGkAtoms::_true, eCaseMatters);
mNativeMenuItem.enabled = isEnabled; mNativeMenuItem.enabled = isEnabled;
mNativeMenuItem.state = mIsChecked ? NSOnState : NSOffState; mNativeMenuItem.state = mIsChecked ? NSOnState : NSOffState;
@ -141,9 +147,11 @@ nsresult nsMenuItemX::SetChecked(bool aIsChecked) {
// update the content model. This will also handle unchecking our siblings // update the content model. This will also handle unchecking our siblings
// if we are a radiomenu // if we are a radiomenu
if (mIsChecked) { if (mIsChecked) {
mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, u"true"_ns, true); mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::checked,
u"true"_ns, true);
} else { } else {
mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked, true); mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
true);
} }
// update native menu item // update native menu item
@ -158,10 +166,13 @@ EMenuItemType nsMenuItemX::GetMenuItemType() { return mType; }
// Executes the "cached" javaScript command. // Executes the "cached" javaScript command.
// Returns NS_OK if the command was executed properly, otherwise an error code. // Returns NS_OK if the command was executed properly, otherwise an error code.
void nsMenuItemX::DoCommand(NSEventModifierFlags aModifierFlags, int16_t aButton) { void nsMenuItemX::DoCommand(NSEventModifierFlags aModifierFlags,
int16_t aButton) {
// flip "checked" state if we're a checkbox menu, or an un-checked radio menu // flip "checked" state if we're a checkbox menu, or an un-checked radio menu
if (mType == eCheckboxMenuItemType || (mType == eRadioMenuItemType && !mIsChecked)) { if (mType == eCheckboxMenuItemType ||
if (!mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::autocheck, (mType == eRadioMenuItemType && !mIsChecked)) {
if (!mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::autocheck,
nsGkAtoms::_false, eCaseMatters)) { nsGkAtoms::_false, eCaseMatters)) {
SetChecked(!mIsChecked); SetChecked(!mIsChecked);
} }
@ -171,7 +182,8 @@ void nsMenuItemX::DoCommand(NSEventModifierFlags aModifierFlags, int16_t aButton
nsMenuUtilsX::DispatchCommandTo(mContent, aModifierFlags, aButton); nsMenuUtilsX::DispatchCommandTo(mContent, aModifierFlags, aButton);
} }
nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName, bool* preventDefaultCalled) { nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName,
bool* preventDefaultCalled) {
if (!mContent) { if (!mContent) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -181,7 +193,8 @@ nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName, bool* preventD
// create DOM event // create DOM event
ErrorResult rv; ErrorResult rv;
RefPtr<Event> event = parentDoc->CreateEvent(u"Events"_ns, CallerType::System, rv); RefPtr<Event> event =
parentDoc->CreateEvent(u"Events"_ns, CallerType::System, rv);
if (rv.Failed()) { if (rv.Failed()) {
NS_WARNING("Failed to create Event"); NS_WARNING("Failed to create Event");
return rv.StealNSResult(); return rv.StealNSResult();
@ -192,7 +205,8 @@ nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName, bool* preventD
event->SetTrusted(true); event->SetTrusted(true);
// send DOM event // send DOM event
*preventDefaultCalled = mContent->DispatchEvent(*event, CallerType::System, rv); *preventDefaultCalled =
mContent->DispatchEvent(*event, CallerType::System, rv);
if (rv.Failed()) { if (rv.Failed()) {
NS_WARNING("Failed to send DOM event via EventTarget"); NS_WARNING("Failed to send DOM event via EventTarget");
return rv.StealNSResult(); return rv.StealNSResult();
@ -220,9 +234,10 @@ void nsMenuItemX::UncheckRadioSiblings(nsIContent* aCheckedContent) {
sibling = sibling->GetNextSibling()) { sibling = sibling->GetNextSibling()) {
if (sibling != aCheckedContent && sibling->IsElement()) { // skip this node if (sibling != aCheckedContent && sibling->IsElement()) { // skip this node
// if the current sibling is in the same group, clear it // if the current sibling is in the same group, clear it
if (sibling->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, myGroupName, if (sibling->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
eCaseMatters)) { myGroupName, eCaseMatters)) {
sibling->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, u"false"_ns, true); sibling->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::checked,
u"false"_ns, true);
} }
} }
} }
@ -236,7 +251,8 @@ void nsMenuItemX::SetKeyEquiv() {
mContent->AsElement()->GetAttr(nsGkAtoms::key, keyValue); mContent->AsElement()->GetAttr(nsGkAtoms::key, keyValue);
if (!keyValue.IsEmpty() && mContent->GetUncomposedDoc()) { if (!keyValue.IsEmpty() && mContent->GetUncomposedDoc()) {
dom::Element* keyContent = mContent->GetUncomposedDoc()->GetElementById(keyValue); dom::Element* keyContent =
mContent->GetUncomposedDoc()->GetElementById(keyValue);
if (keyContent) { if (keyContent) {
nsAutoString keyChar; nsAutoString keyChar;
bool hasKey = keyContent->GetAttr(nsGkAtoms::key, keyChar); bool hasKey = keyContent->GetAttr(nsGkAtoms::key, keyChar);
@ -244,7 +260,8 @@ void nsMenuItemX::SetKeyEquiv() {
if (!hasKey || keyChar.IsEmpty()) { if (!hasKey || keyChar.IsEmpty()) {
nsAutoString keyCodeName; nsAutoString keyCodeName;
keyContent->GetAttr(nsGkAtoms::keycode, keyCodeName); keyContent->GetAttr(nsGkAtoms::keycode, keyCodeName);
uint32_t charCode = nsCocoaUtils::ConvertGeckoNameToMacCharCode(keyCodeName); uint32_t charCode =
nsCocoaUtils::ConvertGeckoNameToMacCharCode(keyCodeName);
if (charCode) { if (charCode) {
keyChar.Assign(charCode); keyChar.Assign(charCode);
} else { } else {
@ -254,13 +271,16 @@ void nsMenuItemX::SetKeyEquiv() {
nsAutoString modifiersStr; nsAutoString modifiersStr;
keyContent->GetAttr(nsGkAtoms::modifiers, modifiersStr); keyContent->GetAttr(nsGkAtoms::modifiers, modifiersStr);
uint8_t modifiers = nsMenuUtilsX::GeckoModifiersForNodeAttribute(modifiersStr); uint8_t modifiers =
nsMenuUtilsX::GeckoModifiersForNodeAttribute(modifiersStr);
unsigned int macModifiers = nsMenuUtilsX::MacModifiersForGeckoModifiers(modifiers); unsigned int macModifiers =
nsMenuUtilsX::MacModifiersForGeckoModifiers(modifiers);
mNativeMenuItem.keyEquivalentModifierMask = macModifiers; mNativeMenuItem.keyEquivalentModifierMask = macModifiers;
NSString* keyEquivalent = [[NSString stringWithCharacters:(unichar*)keyChar.get() NSString* keyEquivalent =
length:keyChar.Length()] lowercaseString]; [[NSString stringWithCharacters:(unichar*)keyChar.get()
length:keyChar.Length()] lowercaseString];
if ([keyEquivalent isEqualToString:@" "]) { if ([keyEquivalent isEqualToString:@" "]) {
mNativeMenuItem.keyEquivalent = @""; mNativeMenuItem.keyEquivalent = @"";
} else { } else {
@ -279,7 +299,8 @@ void nsMenuItemX::SetKeyEquiv() {
void nsMenuItemX::Dump(uint32_t aIndent) const { void nsMenuItemX::Dump(uint32_t aIndent) const {
printf("%*s - item [%p] %-16s <%s>\n", aIndent * 2, "", this, printf("%*s - item [%p] %-16s <%s>\n", aIndent * 2, "", this,
mType == eSeparatorMenuItemType ? "----" : [mNativeMenuItem.title UTF8String], mType == eSeparatorMenuItemType ? "----"
: [mNativeMenuItem.title UTF8String],
NS_ConvertUTF16toUTF8(mContent->NodeName()).get()); NS_ConvertUTF16toUTF8(mContent->NodeName()).get());
} }
@ -287,7 +308,8 @@ void nsMenuItemX::Dump(uint32_t aIndent) const {
// nsChangeObserver // nsChangeObserver
// //
void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent* aContent, void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument,
nsIContent* aContent,
nsAtom* aAttribute) { nsAtom* aAttribute) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@ -300,17 +322,20 @@ void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent*
// if we're a radio menu, uncheck our sibling radio items. No need to // if we're a radio menu, uncheck our sibling radio items. No need to
// do any of this if we're just a normal check menu. // do any of this if we're just a normal check menu.
if (mType == eRadioMenuItemType && if (mType == eRadioMenuItemType &&
mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked, mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::checked,
nsGkAtoms::_true, eCaseMatters)) { nsGkAtoms::_true, eCaseMatters)) {
UncheckRadioSiblings(mContent); UncheckRadioSiblings(mContent);
} }
mMenuParent->SetRebuild(true); mMenuParent->SetRebuild(true);
} else if (aAttribute == nsGkAtoms::hidden || aAttribute == nsGkAtoms::collapsed) { } else if (aAttribute == nsGkAtoms::hidden ||
aAttribute == nsGkAtoms::collapsed) {
bool isVisible = !nsMenuUtilsX::NodeIsHiddenOrCollapsed(mContent); bool isVisible = !nsMenuUtilsX::NodeIsHiddenOrCollapsed(mContent);
if (isVisible != mIsVisible) { if (isVisible != mIsVisible) {
mIsVisible = isVisible; mIsVisible = isVisible;
RefPtr<nsMenuItemX> self = this; RefPtr<nsMenuItemX> self = this;
mMenuParent->MenuChildChangedVisibility(nsMenuParentX::MenuChild(self), isVisible); mMenuParent->MenuChildChangedVisibility(nsMenuParentX::MenuChild(self),
isVisible);
if (mIsVisible) { if (mIsVisible) {
SetupIcon(); SetupIcon();
} }
@ -328,7 +353,8 @@ void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent*
SetupIcon(); SetupIcon();
} else if (aAttribute == nsGkAtoms::disabled) { } else if (aAttribute == nsGkAtoms::disabled) {
mNativeMenuItem.enabled = !aContent->AsElement()->AttrValueIs( mNativeMenuItem.enabled = !aContent->AsElement()->AttrValueIs(
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters); kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true,
eCaseMatters);
} }
} else if (aContent == mCommandElement) { } else if (aContent == mCommandElement) {
// the only thing that really matters when the menu isn't showing is the // the only thing that really matters when the menu isn't showing is the
@ -342,15 +368,17 @@ void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent*
if (!commandDisabled.Equals(menuDisabled)) { if (!commandDisabled.Equals(menuDisabled)) {
// The menu's disabled state needs to be updated to match the command. // The menu's disabled state needs to be updated to match the command.
if (commandDisabled.IsEmpty()) { if (commandDisabled.IsEmpty()) {
mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true); mContent->AsElement()->UnsetAttr(kNameSpaceID_None,
nsGkAtoms::disabled, true);
} else { } else {
mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, commandDisabled, mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled,
true); commandDisabled, true);
} }
} }
// now we sync our native menu item with the command DOM node // now we sync our native menu item with the command DOM node
mNativeMenuItem.enabled = !aContent->AsElement()->AttrValueIs( mNativeMenuItem.enabled = !aContent->AsElement()->AttrValueIs(
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters); kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true,
eCaseMatters);
} }
} }
@ -362,8 +390,10 @@ bool IsMenuStructureElement(nsIContent* aContent) {
nsGkAtoms::menuseparator); nsGkAtoms::menuseparator);
} }
void nsMenuItemX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aContainer, void nsMenuItemX::ObserveContentRemoved(dom::Document* aDocument,
nsIContent* aChild, nsIContent* aPreviousSibling) { nsIContent* aContainer,
nsIContent* aChild,
nsIContent* aPreviousSibling) {
MOZ_RELEASE_ASSERT(mMenuGroupOwner); MOZ_RELEASE_ASSERT(mMenuGroupOwner);
MOZ_RELEASE_ASSERT(mMenuParent); MOZ_RELEASE_ASSERT(mMenuParent);
@ -376,7 +406,8 @@ void nsMenuItemX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aC
} }
} }
void nsMenuItemX::ObserveContentInserted(dom::Document* aDocument, nsIContent* aContainer, void nsMenuItemX::ObserveContentInserted(dom::Document* aDocument,
nsIContent* aContainer,
nsIContent* aChild) { nsIContent* aChild) {
MOZ_RELEASE_ASSERT(mMenuParent); MOZ_RELEASE_ASSERT(mMenuParent);
@ -390,7 +421,8 @@ void nsMenuItemX::ObserveContentInserted(dom::Document* aDocument, nsIContent* a
void nsMenuItemX::SetupIcon() { void nsMenuItemX::SetupIcon() {
if (mType != eRegularMenuItemType) { if (mType != eRegularMenuItemType) {
// Don't support icons on checkbox and radio menuitems, for consistency with Windows & Linux. // Don't support icons on checkbox and radio menuitems, for consistency with
// Windows & Linux.
return; return;
} }
@ -398,4 +430,6 @@ void nsMenuItemX::SetupIcon() {
mNativeMenuItem.image = mIcon->GetIconImage(); mNativeMenuItem.image = mIcon->GetIconImage();
} }
void nsMenuItemX::IconUpdated() { mNativeMenuItem.image = mIcon->GetIconImage(); } void nsMenuItemX::IconUpdated() {
mNativeMenuItem.image = mIcon->GetIconImage();
}

View file

@ -28,7 +28,8 @@ using namespace mozilla;
bool nsMenuUtilsX::gIsSynchronouslyActivatingNativeMenuItemDuringTest = false; bool nsMenuUtilsX::gIsSynchronouslyActivatingNativeMenuItemDuringTest = false;
void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent, void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent,
NSEventModifierFlags aModifierFlags, int16_t aButton) { NSEventModifierFlags aModifierFlags,
int16_t aButton) {
MOZ_ASSERT(aTargetContent, "null ptr"); MOZ_ASSERT(aTargetContent, "null ptr");
dom::Document* doc = aTargetContent->OwnerDoc(); dom::Document* doc = aTargetContent->OwnerDoc();
@ -43,8 +44,9 @@ void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent,
IgnoredErrorResult rv; IgnoredErrorResult rv;
event->InitCommandEvent(u"command"_ns, true, true, event->InitCommandEvent(u"command"_ns, true, true,
nsGlobalWindowInner::Cast(doc->GetInnerWindow()), 0, ctrlKey, altKey, nsGlobalWindowInner::Cast(doc->GetInnerWindow()), 0,
shiftKey, cmdKey, aButton, nullptr, 0, rv); ctrlKey, altKey, shiftKey, cmdKey, aButton, nullptr,
0, rv);
if (!rv.Failed()) { if (!rv.Failed()) {
event->SetTrusted(true); event->SetTrusted(true);
aTargetContent->DispatchEvent(*event); aTargetContent->DispatchEvent(*event);
@ -55,17 +57,19 @@ void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent,
NSString* nsMenuUtilsX::GetTruncatedCocoaLabel(const nsString& itemLabel) { NSString* nsMenuUtilsX::GetTruncatedCocoaLabel(const nsString& itemLabel) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
// We want to truncate long strings to some reasonable pixel length but there is no // We want to truncate long strings to some reasonable pixel length but there
// good API for doing that which works for all OS versions and architectures. For now // is no good API for doing that which works for all OS versions and
// we'll do nothing for consistency and depend on good user interface design to limit // architectures. For now we'll do nothing for consistency and depend on good
// string lengths. // user interface design to limit string lengths.
return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(itemLabel.get()) return [NSString
length:itemLabel.Length()]; stringWithCharacters:reinterpret_cast<const unichar*>(itemLabel.get())
length:itemLabel.Length()];
NS_OBJC_END_TRY_ABORT_BLOCK; NS_OBJC_END_TRY_ABORT_BLOCK;
} }
uint8_t nsMenuUtilsX::GeckoModifiersForNodeAttribute(const nsString& modifiersAttribute) { uint8_t nsMenuUtilsX::GeckoModifiersForNodeAttribute(
const nsString& modifiersAttribute) {
uint8_t modifiers = knsMenuItemNoModifier; uint8_t modifiers = knsMenuItemNoModifier;
char* str = ToNewCString(modifiersAttribute); char* str = ToNewCString(modifiersAttribute);
char* newStr; char* newStr;
@ -87,7 +91,8 @@ uint8_t nsMenuUtilsX::GeckoModifiersForNodeAttribute(const nsString& modifiersAt
return modifiers; return modifiers;
} }
unsigned int nsMenuUtilsX::MacModifiersForGeckoModifiers(uint8_t geckoModifiers) { unsigned int nsMenuUtilsX::MacModifiersForGeckoModifiers(
uint8_t geckoModifiers) {
unsigned int macModifiers = 0; unsigned int macModifiers = 0;
if (geckoModifiers & knsMenuItemShiftModifier) { if (geckoModifiers & knsMenuItemShiftModifier) {
@ -109,7 +114,8 @@ unsigned int nsMenuUtilsX::MacModifiersForGeckoModifiers(uint8_t geckoModifiers)
nsMenuBarX* nsMenuUtilsX::GetHiddenWindowMenuBar() { nsMenuBarX* nsMenuUtilsX::GetHiddenWindowMenuBar() {
nsIWidget* hiddenWindowWidgetNoCOMPtr = nsCocoaUtils::GetHiddenWindowWidget(); nsIWidget* hiddenWindowWidgetNoCOMPtr = nsCocoaUtils::GetHiddenWindowWidget();
if (hiddenWindowWidgetNoCOMPtr) { if (hiddenWindowWidgetNoCOMPtr) {
return static_cast<nsCocoaWindow*>(hiddenWindowWidgetNoCOMPtr)->GetMenuBar(); return static_cast<nsCocoaWindow*>(hiddenWindowWidgetNoCOMPtr)
->GetMenuBar();
} }
return nullptr; return nullptr;
} }
@ -123,9 +129,9 @@ NSMenuItem* nsMenuUtilsX::GetStandardEditMenuItem() {
// app-modal dialogs and Gecko-modal dialogs that open above them. So what // app-modal dialogs and Gecko-modal dialogs that open above them. So what
// we return here isn't always released before it needs to be added to // we return here isn't always released before it needs to be added to
// another menu. See bmo bug 468393. // another menu. See bmo bug 468393.
NSMenuItem* standardEditMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Edit" NSMenuItem* standardEditMenuItem =
action:nil [[[NSMenuItem alloc] initWithTitle:@"Edit" action:nil
keyEquivalent:@""] autorelease]; keyEquivalent:@""] autorelease];
NSMenu* standardEditMenu = [[NSMenu alloc] initWithTitle:@"Edit"]; NSMenu* standardEditMenu = [[NSMenu alloc] initWithTitle:@"Edit"];
standardEditMenuItem.submenu = standardEditMenu; standardEditMenuItem.submenu = standardEditMenu;
[standardEditMenu release]; [standardEditMenu release];
@ -176,9 +182,10 @@ NSMenuItem* nsMenuUtilsX::GetStandardEditMenuItem() {
[deleteItem release]; [deleteItem release];
// Add Select All // Add Select All
NSMenuItem* selectAllItem = [[NSMenuItem alloc] initWithTitle:@"Select All" NSMenuItem* selectAllItem =
action:@selector(selectAll:) [[NSMenuItem alloc] initWithTitle:@"Select All"
keyEquivalent:@"a"]; action:@selector(selectAll:)
keyEquivalent:@"a"];
[standardEditMenu addItem:selectAllItem]; [standardEditMenu addItem:selectAllItem];
[selectAllItem release]; [selectAllItem release];
@ -188,16 +195,19 @@ NSMenuItem* nsMenuUtilsX::GetStandardEditMenuItem() {
} }
bool nsMenuUtilsX::NodeIsHiddenOrCollapsed(nsIContent* aContent) { bool nsMenuUtilsX::NodeIsHiddenOrCollapsed(nsIContent* aContent) {
return aContent->IsElement() && return aContent->IsElement() && (aContent->AsElement()->AttrValueIs(
(aContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden, nsGkAtoms::_true, kNameSpaceID_None, nsGkAtoms::hidden,
eCaseMatters) || nsGkAtoms::_true, eCaseMatters) ||
aContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::collapsed, aContent->AsElement()->AttrValueIs(
nsGkAtoms::_true, eCaseMatters)); kNameSpaceID_None, nsGkAtoms::collapsed,
nsGkAtoms::_true, eCaseMatters));
} }
NSMenuItem* nsMenuUtilsX::NativeMenuItemWithLocation(NSMenu* aRootMenu, NSString* aLocationString, NSMenuItem* nsMenuUtilsX::NativeMenuItemWithLocation(NSMenu* aRootMenu,
NSString* aLocationString,
bool aIsMenuBar) { bool aIsMenuBar) {
NSArray<NSString*>* indexes = [aLocationString componentsSeparatedByString:@"|"]; NSArray<NSString*>* indexes =
[aLocationString componentsSeparatedByString:@"|"];
unsigned int pathLength = indexes.count; unsigned int pathLength = indexes.count;
if (pathLength == 0) { if (pathLength == 0) {
return nil; return nil;
@ -207,7 +217,8 @@ NSMenuItem* nsMenuUtilsX::NativeMenuItemWithLocation(NSMenu* aRootMenu, NSString
for (unsigned int depth = 0; depth < pathLength; depth++) { for (unsigned int depth = 0; depth < pathLength; depth++) {
NSInteger targetIndex = [indexes objectAtIndex:depth].integerValue; NSInteger targetIndex = [indexes objectAtIndex:depth].integerValue;
if (aIsMenuBar && depth == 0) { if (aIsMenuBar && depth == 0) {
// We remove the application menu from consideration for the top-level menu. // We remove the application menu from consideration for the top-level
// menu.
targetIndex++; targetIndex++;
} }
int itemCount = currentSubmenu.numberOfItems; int itemCount = currentSubmenu.numberOfItems;
@ -230,20 +241,24 @@ NSMenuItem* nsMenuUtilsX::NativeMenuItemWithLocation(NSMenu* aRootMenu, NSString
return nil; return nil;
} }
static void CheckNativeMenuConsistencyImpl(NSMenu* aMenu, std::unordered_set<void*>& aSeenObjects); static void CheckNativeMenuConsistencyImpl(
NSMenu* aMenu, std::unordered_set<void*>& aSeenObjects);
static void CheckNativeMenuItemConsistencyImpl(NSMenuItem* aMenuItem, static void CheckNativeMenuItemConsistencyImpl(
std::unordered_set<void*>& aSeenObjects) { NSMenuItem* aMenuItem, std::unordered_set<void*>& aSeenObjects) {
bool inserted = aSeenObjects.insert(aMenuItem).second; bool inserted = aSeenObjects.insert(aMenuItem).second;
MOZ_RELEASE_ASSERT(inserted, "Duplicate NSMenuItem object in native menu structure"); MOZ_RELEASE_ASSERT(inserted,
"Duplicate NSMenuItem object in native menu structure");
if (aMenuItem.hasSubmenu) { if (aMenuItem.hasSubmenu) {
CheckNativeMenuConsistencyImpl(aMenuItem.submenu, aSeenObjects); CheckNativeMenuConsistencyImpl(aMenuItem.submenu, aSeenObjects);
} }
} }
static void CheckNativeMenuConsistencyImpl(NSMenu* aMenu, std::unordered_set<void*>& aSeenObjects) { static void CheckNativeMenuConsistencyImpl(
NSMenu* aMenu, std::unordered_set<void*>& aSeenObjects) {
bool inserted = aSeenObjects.insert(aMenu).second; bool inserted = aSeenObjects.insert(aMenu).second;
MOZ_RELEASE_ASSERT(inserted, "Duplicate NSMenu object in native menu structure"); MOZ_RELEASE_ASSERT(inserted,
"Duplicate NSMenu object in native menu structure");
for (NSMenuItem* item in aMenu.itemArray) { for (NSMenuItem* item in aMenu.itemArray) {
CheckNativeMenuItemConsistencyImpl(item, aSeenObjects); CheckNativeMenuItemConsistencyImpl(item, aSeenObjects);
} }
@ -278,16 +293,20 @@ static void DumpNativeNSMenuItemImpl(NSMenuItem* aItem, uint32_t aIndent,
if (aIndexInParentMenu) { if (aIndexInParentMenu) {
printf("[%d] ", *aIndexInParentMenu); printf("[%d] ", *aIndexInParentMenu);
} }
printf("NSMenuItem [%p] %-16s%s\n", aItem, printf(
aItem.isSeparatorItem ? "----" "NSMenuItem [%p] %-16s%s\n", aItem,
: (aItem.title.length == 0 ? "(no title)" : aItem.title.UTF8String), aItem.isSeparatorItem
aItem.hasSubmenu ? " [hasSubmenu]" : ""); ? "----"
: (aItem.title.length == 0 ? "(no title)" : aItem.title.UTF8String),
aItem.hasSubmenu ? " [hasSubmenu]" : "");
if (aItem.hasSubmenu) { if (aItem.hasSubmenu) {
DumpNativeNSMenuImpl(aItem.submenu, aIndent + 1); DumpNativeNSMenuImpl(aItem.submenu, aIndent + 1);
} }
} }
void nsMenuUtilsX::DumpNativeMenu(NSMenu* aMenu) { DumpNativeNSMenuImpl(aMenu, 0); } void nsMenuUtilsX::DumpNativeMenu(NSMenu* aMenu) {
DumpNativeNSMenuImpl(aMenu, 0);
}
void nsMenuUtilsX::DumpNativeMenuItem(NSMenuItem* aMenuItem) { void nsMenuUtilsX::DumpNativeMenuItem(NSMenuItem* aMenuItem) {
DumpNativeNSMenuItemImpl(aMenuItem, 0, Nothing()); DumpNativeNSMenuItemImpl(aMenuItem, 0, Nothing());

View file

@ -57,20 +57,25 @@ static void SwizzleDynamicIndexingMethods() {
nsToolkit::SwizzleMethods([NSMenu class], @selector(_addItem:toTable:), nsToolkit::SwizzleMethods([NSMenu class], @selector(_addItem:toTable:),
@selector(nsMenuX_NSMenu_addItem:toTable:), true); @selector(nsMenuX_NSMenu_addItem:toTable:), true);
nsToolkit::SwizzleMethods([NSMenu class], @selector(_removeItem:fromTable:), nsToolkit::SwizzleMethods([NSMenu class], @selector(_removeItem:fromTable:),
@selector(nsMenuX_NSMenu_removeItem:fromTable:), true); @selector(nsMenuX_NSMenu_removeItem:fromTable:),
true);
// On SnowLeopard the Shortcut framework (which contains the // On SnowLeopard the Shortcut framework (which contains the
// SCTGRLIndex class) is loaded on demand, whenever the user first opens // SCTGRLIndex class) is loaded on demand, whenever the user first opens
// a menu (which normally hasn't happened yet). So we need to load it // a menu (which normally hasn't happened yet). So we need to load it
// here explicitly. // here explicitly.
dlopen("/System/Library/PrivateFrameworks/Shortcut.framework/Shortcut", RTLD_LAZY); dlopen("/System/Library/PrivateFrameworks/Shortcut.framework/Shortcut",
RTLD_LAZY);
Class SCTGRLIndexClass = ::NSClassFromString(@"SCTGRLIndex"); Class SCTGRLIndexClass = ::NSClassFromString(@"SCTGRLIndex");
nsToolkit::SwizzleMethods(SCTGRLIndexClass, @selector(indexMenuBarDynamically), nsToolkit::SwizzleMethods(
@selector(nsMenuX_SCTGRLIndex_indexMenuBarDynamically)); SCTGRLIndexClass, @selector(indexMenuBarDynamically),
@selector(nsMenuX_SCTGRLIndex_indexMenuBarDynamically));
Class NSServicesMenuUpdaterClass = ::NSClassFromString(@"_NSServicesMenuUpdater"); Class NSServicesMenuUpdaterClass =
nsToolkit::SwizzleMethods(NSServicesMenuUpdaterClass, ::NSClassFromString(@"_NSServicesMenuUpdater");
@selector(populateMenu:withServiceEntries:forDisplay:), nsToolkit::SwizzleMethods(
@selector(nsMenuX_populateMenu:withServiceEntries:forDisplay:)); NSServicesMenuUpdaterClass,
@selector(populateMenu:withServiceEntries:forDisplay:),
@selector(nsMenuX_populateMenu:withServiceEntries:forDisplay:));
gMenuMethodsSwizzled = true; gMenuMethodsSwizzled = true;
} }
@ -79,7 +84,8 @@ static void SwizzleDynamicIndexingMethods() {
// nsMenuX // nsMenuX
// //
nsMenuX::nsMenuX(nsMenuParentX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner, nsIContent* aContent) nsMenuX::nsMenuX(nsMenuParentX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner,
nsIContent* aContent)
: mContent(aContent), mParent(aParent), mMenuGroupOwner(aMenuGroupOwner) { : mContent(aContent), mParent(aParent), mMenuGroupOwner(aMenuGroupOwner) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@ -98,7 +104,8 @@ nsMenuX::nsMenuX(nsMenuParentX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner, nsI
} }
mNativeMenu = CreateMenuWithGeckoString(mLabel); mNativeMenu = CreateMenuWithGeckoString(mLabel);
// register this menu to be notified when changes are made to our content object // register this menu to be notified when changes are made to our content
// object
NS_ASSERTION(mMenuGroupOwner, "No menu owner given, must have one"); NS_ASSERTION(mMenuGroupOwner, "No menu owner given, must have one");
mMenuGroupOwner->RegisterForContentChanges(mContent, this); mMenuGroupOwner->RegisterForContentChanges(mContent, this);
@ -111,8 +118,9 @@ nsMenuX::nsMenuX(nsMenuParentX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner, nsI
mNativeMenuItem.submenu = mNativeMenu; mNativeMenuItem.submenu = mNativeMenu;
SetEnabled(!mContent->IsElement() || SetEnabled(!mContent->IsElement() ||
!mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, !mContent->AsElement()->AttrValueIs(
nsGkAtoms::_true, eCaseMatters)); kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true,
eCaseMatters));
// We call RebuildMenu here because keyboard commands are dependent upon // We call RebuildMenu here because keyboard commands are dependent upon
// native menu items being created. If we only call RebuildMenu when a menu // native menu items being created. If we only call RebuildMenu when a menu
@ -168,8 +176,9 @@ nsMenuX::~nsMenuX() {
void nsMenuX::DetachFromGroupOwnerRecursive() { void nsMenuX::DetachFromGroupOwnerRecursive() {
if (!mMenuGroupOwner) { if (!mMenuGroupOwner) {
// Don't recurse if this subtree is already detached. // Don't recurse if this subtree is already detached.
// This avoids repeated recursion during the destruction of nested nsMenuX structures. // This avoids repeated recursion during the destruction of nested nsMenuX
// Our invariant is: If we are detached, all of our contents are also detached. // structures. Our invariant is: If we are detached, all of our contents are
// also detached.
return; return;
} }
@ -180,8 +189,13 @@ void nsMenuX::DetachFromGroupOwnerRecursive() {
// Also detach all our children. // Also detach all our children.
for (auto& child : mMenuChildren) { for (auto& child : mMenuChildren) {
child.match([](const RefPtr<nsMenuX>& aMenu) { aMenu->DetachFromGroupOwnerRecursive(); }, child.match(
[](const RefPtr<nsMenuItemX>& aMenuItem) { aMenuItem->DetachFromGroupOwner(); }); [](const RefPtr<nsMenuX>& aMenu) {
aMenu->DetachFromGroupOwnerRecursive();
},
[](const RefPtr<nsMenuItemX>& aMenuItem) {
aMenuItem->DetachFromGroupOwner();
});
} }
} }
@ -199,7 +213,8 @@ void nsMenuX::OnMenuDidOpen(dom::Element* aPopupElement) {
} }
} }
void nsMenuX::OnMenuWillActivateItem(dom::Element* aPopupElement, dom::Element* aMenuItemElement) { void nsMenuX::OnMenuWillActivateItem(dom::Element* aPopupElement,
dom::Element* aMenuItemElement) {
RefPtr<nsMenuX> kungFuDeathGrip(this); RefPtr<nsMenuX> kungFuDeathGrip(this);
if (mObserver) { if (mObserver) {
mObserver->OnMenuWillActivateItem(aPopupElement, aMenuItemElement); mObserver->OnMenuWillActivateItem(aPopupElement, aMenuItemElement);
@ -219,12 +234,16 @@ void nsMenuX::AddMenuChild(MenuChild&& aChild) {
WillInsertChild(aChild); WillInsertChild(aChild);
mMenuChildren.AppendElement(aChild); mMenuChildren.AppendElement(aChild);
bool isVisible = bool isVisible = aChild.match(
aChild.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); }, [](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->IsVisible(); }); [](const RefPtr<nsMenuItemX>& aMenuItem) {
return aMenuItem->IsVisible();
});
NSMenuItem* nativeItem = aChild.match( NSMenuItem* nativeItem = aChild.match(
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); }, [](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); },
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->NativeNSMenuItem(); }); [](const RefPtr<nsMenuItemX>& aMenuItem) {
return aMenuItem->NativeNSMenuItem();
});
if (isVisible) { if (isVisible) {
RemovePlaceholderIfPresent(); RemovePlaceholderIfPresent();
@ -242,9 +261,11 @@ void nsMenuX::InsertMenuChild(MenuChild&& aChild) {
size_t insertionIndex = FindInsertionIndex(aChild); size_t insertionIndex = FindInsertionIndex(aChild);
mMenuChildren.InsertElementAt(insertionIndex, aChild); mMenuChildren.InsertElementAt(insertionIndex, aChild);
bool isVisible = bool isVisible = aChild.match(
aChild.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); }, [](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->IsVisible(); }); [](const RefPtr<nsMenuItemX>& aMenuItem) {
return aMenuItem->IsVisible();
});
if (isVisible) { if (isVisible) {
MenuChildChangedVisibility(aChild, true); MenuChildChangedVisibility(aChild, true);
} }
@ -253,9 +274,11 @@ void nsMenuX::InsertMenuChild(MenuChild&& aChild) {
} }
void nsMenuX::RemoveMenuChild(const MenuChild& aChild) { void nsMenuX::RemoveMenuChild(const MenuChild& aChild) {
bool isVisible = bool isVisible = aChild.match(
aChild.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); }, [](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->IsVisible(); }); [](const RefPtr<nsMenuItemX>& aMenuItem) {
return aMenuItem->IsVisible();
});
if (isVisible) { if (isVisible) {
MenuChildChangedVisibility(aChild, false); MenuChildChangedVisibility(aChild, false);
} }
@ -268,16 +291,20 @@ size_t nsMenuX::FindInsertionIndex(const MenuChild& aChild) {
nsCOMPtr<nsIContent> menuPopup = GetMenuPopupContent(); nsCOMPtr<nsIContent> menuPopup = GetMenuPopupContent();
MOZ_RELEASE_ASSERT(menuPopup); MOZ_RELEASE_ASSERT(menuPopup);
RefPtr<nsIContent> insertedContent = RefPtr<nsIContent> insertedContent = aChild.match(
aChild.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); }, [](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); }); [](const RefPtr<nsMenuItemX>& aMenuItem) {
return aMenuItem->Content();
});
MOZ_RELEASE_ASSERT(insertedContent->GetParent() == menuPopup); MOZ_RELEASE_ASSERT(insertedContent->GetParent() == menuPopup);
// Iterate over menuPopup's children (insertedContent's siblings) until we encounter // Iterate over menuPopup's children (insertedContent's siblings) until we
// insertedContent. At the same time, keep track of the index in mMenuChildren. // encounter insertedContent. At the same time, keep track of the index in
// mMenuChildren.
size_t index = 0; size_t index = 0;
for (nsIContent* child = menuPopup->GetFirstChild(); child && index < mMenuChildren.Length(); for (nsIContent* child = menuPopup->GetFirstChild();
child && index < mMenuChildren.Length();
child = child->GetNextSibling()) { child = child->GetNextSibling()) {
if (child == insertedContent) { if (child == insertedContent) {
break; break;
@ -285,7 +312,9 @@ size_t nsMenuX::FindInsertionIndex(const MenuChild& aChild) {
RefPtr<nsIContent> contentAtIndex = mMenuChildren[index].match( RefPtr<nsIContent> contentAtIndex = mMenuChildren[index].match(
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); }, [](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); }); [](const RefPtr<nsMenuItemX>& aMenuItem) {
return aMenuItem->Content();
});
if (child == contentAtIndex) { if (child == contentAtIndex) {
index++; index++;
} }
@ -313,7 +342,8 @@ nsresult nsMenuX::GetVisibleItemCount(uint32_t& aCount) {
} }
// Only includes visible items. Note that this is provides O(N) access // Only includes visible items. Note that this is provides O(N) access
// If you need to iterate or search, consider using GetItemAt and doing your own filtering // If you need to iterate or search, consider using GetItemAt and doing your own
// filtering
Maybe<nsMenuX::MenuChild> nsMenuX::GetVisibleItemAt(uint32_t aPos) { Maybe<nsMenuX::MenuChild> nsMenuX::GetVisibleItemAt(uint32_t aPos) {
uint32_t count = mMenuChildren.Length(); uint32_t count = mMenuChildren.Length();
if (aPos >= mVisibleItemsCount || aPos >= count) { if (aPos >= mVisibleItemsCount || aPos >= count) {
@ -329,9 +359,11 @@ Maybe<nsMenuX::MenuChild> nsMenuX::GetVisibleItemAt(uint32_t aPos) {
uint32_t visibleNodeIndex = 0; uint32_t visibleNodeIndex = 0;
for (uint32_t i = 0; i < count; i++) { for (uint32_t i = 0; i < count; i++) {
MenuChild item = *GetItemAt(i); MenuChild item = *GetItemAt(i);
RefPtr<nsIContent> content = RefPtr<nsIContent> content = item.match(
item.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); }, [](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); }); [](const RefPtr<nsMenuItemX>& aMenuItem) {
return aMenuItem->Content();
});
if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(content)) { if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(content)) {
if (aPos == visibleNodeIndex) { if (aPos == visibleNodeIndex) {
// we found the visible node we're looking for, return it // we found the visible node we're looking for, return it
@ -344,11 +376,14 @@ Maybe<nsMenuX::MenuChild> nsMenuX::GetVisibleItemAt(uint32_t aPos) {
return {}; return {};
} }
Maybe<nsMenuX::MenuChild> nsMenuX::GetItemForElement(Element* aMenuChildElement) { Maybe<nsMenuX::MenuChild> nsMenuX::GetItemForElement(
Element* aMenuChildElement) {
for (auto& child : mMenuChildren) { for (auto& child : mMenuChildren) {
RefPtr<nsIContent> content = RefPtr<nsIContent> content = child.match(
child.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); }, [](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); }); [](const RefPtr<nsMenuItemX>& aMenuItem) {
return aMenuItem->Content();
});
if (content == aMenuChildElement) { if (content == aMenuChildElement) {
return Some(child); return Some(child);
} }
@ -397,7 +432,8 @@ void nsMenuX::MenuOpened() {
return; return;
} }
// Make sure we fire any pending popupshown / popuphiding / popuphidden events first. // Make sure we fire any pending popupshown / popuphiding / popuphidden events
// first.
FlushMenuOpenedRunnable(); FlushMenuOpenedRunnable();
FlushMenuClosedRunnable(); FlushMenuClosedRunnable();
@ -405,10 +441,11 @@ void nsMenuX::MenuOpened() {
// Fire popupshowing now. // Fire popupshowing now.
bool approvedToOpen = OnOpen(); bool approvedToOpen = OnOpen();
if (!approvedToOpen) { if (!approvedToOpen) {
// We can only stop menus from opening which we open ourselves. We cannot stop menubar root // We can only stop menus from opening which we open ourselves. We cannot
// menus or menu submenus from opening. // stop menubar root menus or menu submenus from opening. For context
// For context menus, we can call OnOpen() before we ask the system to open the menu. // menus, we can call OnOpen() before we ask the system to open the menu.
NS_WARNING("The popupshowing event had preventDefault() called on it, but in MenuOpened() it " NS_WARNING("The popupshowing event had preventDefault() called on it, "
"but in MenuOpened() it "
"is too late to stop the menu from opening."); "is too late to stop the menu from opening.");
} }
} }
@ -425,10 +462,9 @@ void nsMenuX::MenuOpened() {
} }
// Fire the popupshown event in MenuOpenedAsync. // Fire the popupshown event in MenuOpenedAsync.
// MenuOpened() is called during menuWillOpen, and if cancelTracking is called now, menuDidClose // MenuOpened() is called during menuWillOpen, and if cancelTracking is called
// will not be called. // now, menuDidClose will not be called. The runnable object must not hold a
// The runnable object must not hold a strong reference to the nsMenuX, so that there is no // strong reference to the nsMenuX, so that there is no reference cycle.
// reference cycle.
class MenuOpenedAsyncRunnable final : public mozilla::CancelableRunnable { class MenuOpenedAsyncRunnable final : public mozilla::CancelableRunnable {
public: public:
explicit MenuOpenedAsyncRunnable(nsMenuX* aMenu) explicit MenuOpenedAsyncRunnable(nsMenuX* aMenu)
@ -470,7 +506,8 @@ void nsMenuX::MenuOpenedAsync() {
// Open the node. // Open the node.
if (mContent->IsElement()) { if (mContent->IsElement()) {
mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::open, u"true"_ns, true); mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::open,
u"true"_ns, true);
} }
RefPtr<nsIContent> popupContent = GetMenuPopupContent(); RefPtr<nsIContent> popupContent = GetMenuPopupContent();
@ -482,7 +519,8 @@ void nsMenuX::MenuOpenedAsync() {
// Fire popupshown. // Fire popupshown.
nsEventStatus status = nsEventStatus_eIgnore; nsEventStatus status = nsEventStatus_eIgnore;
WidgetMouseEvent event(true, eXULPopupShown, nullptr, WidgetMouseEvent::eReal); WidgetMouseEvent event(true, eXULPopupShown, nullptr,
WidgetMouseEvent::eReal);
RefPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent; RefPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent;
EventDispatcher::Dispatch(dispatchTo, nullptr, &event, nullptr, &status); EventDispatcher::Dispatch(dispatchTo, nullptr, &event, nullptr, &status);
} }
@ -495,7 +533,8 @@ void nsMenuX::MenuClosed() {
// Make sure we fire any pending popupshown events first. // Make sure we fire any pending popupshown events first.
FlushMenuOpenedRunnable(); FlushMenuOpenedRunnable();
// If any of our submenus were opened programmatically, make sure they get closed first. // If any of our submenus were opened programmatically, make sure they get
// closed first.
for (auto& child : mMenuChildren) { for (auto& child : mMenuChildren) {
if (child.is<RefPtr<nsMenuX>>()) { if (child.is<RefPtr<nsMenuX>>()) {
child.as<RefPtr<nsMenuX>>()->MenuClosed(); child.as<RefPtr<nsMenuX>>()->MenuClosed();
@ -505,11 +544,11 @@ void nsMenuX::MenuClosed() {
mIsOpen = false; mIsOpen = false;
// Do the rest of the MenuClosed work in MenuClosedAsync. // Do the rest of the MenuClosed work in MenuClosedAsync.
// MenuClosed() is called from -[NSMenuDelegate menuDidClose:]. If a menuitem was clicked, // MenuClosed() is called from -[NSMenuDelegate menuDidClose:]. If a menuitem
// menuDidClose is called *before* menuItemHit for the clicked menu item is called. // was clicked, menuDidClose is called *before* menuItemHit for the clicked
// This runnable will be canceled if ~nsMenuX runs before the runnable. // menu item is called. This runnable will be canceled if ~nsMenuX runs before
// The runnable object must not hold a strong reference to the nsMenuX, so that there is no // the runnable. The runnable object must not hold a strong reference to the
// reference cycle. // nsMenuX, so that there is no reference cycle.
class MenuClosedAsyncRunnable final : public mozilla::CancelableRunnable { class MenuClosedAsyncRunnable final : public mozilla::CancelableRunnable {
public: public:
explicit MenuClosedAsyncRunnable(nsMenuX* aMenu) explicit MenuClosedAsyncRunnable(nsMenuX* aMenu)
@ -538,7 +577,8 @@ void nsMenuX::MenuClosed() {
} }
void nsMenuX::FlushMenuClosedRunnable() { void nsMenuX::FlushMenuClosedRunnable() {
// If any of our submenus have a pending menu closed runnable, make sure those run first. // If any of our submenus have a pending menu closed runnable, make sure those
// run first.
for (auto& child : mMenuChildren) { for (auto& child : mMenuChildren) {
if (child.is<RefPtr<nsMenuX>>()) { if (child.is<RefPtr<nsMenuX>>()) {
child.as<RefPtr<nsMenuX>>()->FlushMenuClosedRunnable(); child.as<RefPtr<nsMenuX>>()->FlushMenuClosedRunnable();
@ -569,8 +609,10 @@ void nsMenuX::MenuClosedAsync() {
nsCOMPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent; nsCOMPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent;
nsEventStatus status = nsEventStatus_eIgnore; nsEventStatus status = nsEventStatus_eIgnore;
WidgetMouseEvent popupHiding(true, eXULPopupHiding, nullptr, WidgetMouseEvent::eReal); WidgetMouseEvent popupHiding(true, eXULPopupHiding, nullptr,
EventDispatcher::Dispatch(dispatchTo, nullptr, &popupHiding, nullptr, &status); WidgetMouseEvent::eReal);
EventDispatcher::Dispatch(dispatchTo, nullptr, &popupHiding, nullptr,
&status);
mIsOpenForGecko = false; mIsOpenForGecko = false;
@ -578,8 +620,10 @@ void nsMenuX::MenuClosedAsync() {
mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, true); mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, true);
} }
WidgetMouseEvent popupHidden(true, eXULPopupHidden, nullptr, WidgetMouseEvent::eReal); WidgetMouseEvent popupHidden(true, eXULPopupHidden, nullptr,
EventDispatcher::Dispatch(dispatchTo, nullptr, &popupHidden, nullptr, &status); WidgetMouseEvent::eReal);
EventDispatcher::Dispatch(dispatchTo, nullptr, &popupHidden, nullptr,
&status);
// Notify our observer. // Notify our observer.
if (mObserver && popupContent) { if (mObserver && popupContent) {
@ -587,17 +631,22 @@ void nsMenuX::MenuClosedAsync() {
} }
} }
void nsMenuX::ActivateItemAfterClosing(RefPtr<nsMenuItemX>&& aItem, NSEventModifierFlags aModifiers, void nsMenuX::ActivateItemAfterClosing(RefPtr<nsMenuItemX>&& aItem,
NSEventModifierFlags aModifiers,
int16_t aButton) { int16_t aButton) {
if (mIsOpenForGecko) { if (mIsOpenForGecko) {
// Queue the event into mPendingCommandEvents. We will call aItem->DoCommand in // Queue the event into mPendingCommandEvents. We will call aItem->DoCommand
// MenuClosedAsync(). We rely on the assumption that MenuClosedAsync will run soon. // in MenuClosedAsync(). We rely on the assumption that MenuClosedAsync will
mPendingCommandEvents.AppendElement(PendingCommandEvent{std::move(aItem), aModifiers, aButton}); // run soon.
mPendingCommandEvents.AppendElement(
PendingCommandEvent{std::move(aItem), aModifiers, aButton});
} else { } else {
// The menu item was activated outside of a regular open / activate / close sequence. // The menu item was activated outside of a regular open / activate / close
// This happens in multiple cases: // sequence. This happens in multiple cases:
// - When a menu item is activated by a keyboard shortcut while all windows are closed // - When a menu item is activated by a keyboard shortcut while all windows
// (otherwise those shortcuts go through Gecko's manual keyboard handling) // are closed
// (otherwise those shortcuts go through Gecko's manual keyboard
// handling)
// - When a menu item in the Dock menu is clicked // - When a menu item in the Dock menu is clicked
// - During native menu tests // - During native menu tests
// //
@ -610,10 +659,11 @@ bool nsMenuX::Close() {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if (mDidFirePopupshowingAndIsApprovedToOpen && !mIsOpen) { if (mDidFirePopupshowingAndIsApprovedToOpen && !mIsOpen) {
// Close is being called right after this menu was opened, but before MenuOpened() had a chance // Close is being called right after this menu was opened, but before
// to run. Call it here so that we can go through the entire popupshown -> popuphiding -> // MenuOpened() had a chance to run. Call it here so that we can go through
// popuphidden sequence. Some callers expect to get a popuphidden event even if they close the // the entire popupshown -> popuphiding -> popuphidden sequence. Some
// popup before it was fully open. // callers expect to get a popuphidden event even if they close the popup
// before it was fully open.
MenuOpened(); MenuOpened();
} }
@ -623,11 +673,12 @@ bool nsMenuX::Close() {
if (mIsOpen) { if (mIsOpen) {
// Close the menu. // Close the menu.
// We usually don't get here during normal Firefox usage: If the user closes the menu by // We usually don't get here during normal Firefox usage: If the user closes
// clicking an item, or by clicking outside the menu, or by pressing escape, then the menu gets // the menu by clicking an item, or by clicking outside the menu, or by
// closed by macOS, and not by a call to nsMenuX::Close(). // pressing escape, then the menu gets closed by macOS, and not by a call to
// If we do get here, it's usually because we're running an automated test. Close the menu // nsMenuX::Close(). If we do get here, it's usually because we're running
// without the fade-out animation so that we don't unnecessarily slow down the automated tests. // an automated test. Close the menu without the fade-out animation so that
// we don't unnecessarily slow down the automated tests.
[mNativeMenu cancelTrackingWithoutAnimation]; [mNativeMenu cancelTrackingWithoutAnimation];
MOZMenuOpeningCoordinator.needToUnwindForMenuClosing = YES; MOZMenuOpeningCoordinator.needToUnwindForMenuClosing = YES;
@ -642,7 +693,8 @@ bool nsMenuX::Close() {
NS_OBJC_END_TRY_ABORT_BLOCK; NS_OBJC_END_TRY_ABORT_BLOCK;
} }
void nsMenuX::OnHighlightedItemChanged(const Maybe<uint32_t>& aNewHighlightedIndex) { void nsMenuX::OnHighlightedItemChanged(
const Maybe<uint32_t>& aNewHighlightedIndex) {
if (mHighlightedItemIndex == aNewHighlightedIndex) { if (mHighlightedItemIndex == aNewHighlightedIndex) {
return; return;
} }
@ -651,16 +703,16 @@ void nsMenuX::OnHighlightedItemChanged(const Maybe<uint32_t>& aNewHighlightedInd
Maybe<nsMenuX::MenuChild> target = GetVisibleItemAt(*mHighlightedItemIndex); Maybe<nsMenuX::MenuChild> target = GetVisibleItemAt(*mHighlightedItemIndex);
if (target && target->is<RefPtr<nsMenuItemX>>()) { if (target && target->is<RefPtr<nsMenuItemX>>()) {
bool handlerCalledPreventDefault; // but we don't actually care bool handlerCalledPreventDefault; // but we don't actually care
target->as<RefPtr<nsMenuItemX>>()->DispatchDOMEvent(u"DOMMenuItemInactive"_ns, target->as<RefPtr<nsMenuItemX>>()->DispatchDOMEvent(
&handlerCalledPreventDefault); u"DOMMenuItemInactive"_ns, &handlerCalledPreventDefault);
} }
} }
if (aNewHighlightedIndex) { if (aNewHighlightedIndex) {
Maybe<nsMenuX::MenuChild> target = GetVisibleItemAt(*aNewHighlightedIndex); Maybe<nsMenuX::MenuChild> target = GetVisibleItemAt(*aNewHighlightedIndex);
if (target && target->is<RefPtr<nsMenuItemX>>()) { if (target && target->is<RefPtr<nsMenuItemX>>()) {
bool handlerCalledPreventDefault; // but we don't actually care bool handlerCalledPreventDefault; // but we don't actually care
target->as<RefPtr<nsMenuItemX>>()->DispatchDOMEvent(u"DOMMenuItemActive"_ns, target->as<RefPtr<nsMenuItemX>>()->DispatchDOMEvent(
&handlerCalledPreventDefault); u"DOMMenuItemActive"_ns, &handlerCalledPreventDefault);
} }
} }
mHighlightedItemIndex = aNewHighlightedIndex; mHighlightedItemIndex = aNewHighlightedIndex;
@ -672,21 +724,25 @@ void nsMenuX::OnWillActivateItem(NSMenuItem* aItem) {
} }
if (mMenuGroupOwner && mObserver) { if (mMenuGroupOwner && mObserver) {
nsMenuItemX* item = mMenuGroupOwner->GetMenuItemForCommandID(uint32_t(aItem.tag)); nsMenuItemX* item =
mMenuGroupOwner->GetMenuItemForCommandID(uint32_t(aItem.tag));
if (item && item->Content()->IsElement()) { if (item && item->Content()->IsElement()) {
RefPtr<dom::Element> itemElement = item->Content()->AsElement(); RefPtr<dom::Element> itemElement = item->Content()->AsElement();
if (nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent()) { if (nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent()) {
mObserver->OnMenuWillActivateItem(popupContent->AsElement(), itemElement); mObserver->OnMenuWillActivateItem(popupContent->AsElement(),
itemElement);
} }
} }
} }
} }
// Flushes style. // Flushes style.
static NSUserInterfaceLayoutDirection DirectionForElement(dom::Element* aElement) { static NSUserInterfaceLayoutDirection DirectionForElement(
// Get the direction from the computed style so that inheritance into submenus is respected. dom::Element* aElement) {
// aElement may not have a frame. // Get the direction from the computed style so that inheritance into submenus
RefPtr<const ComputedStyle> sc = nsComputedDOMStyle::GetComputedStyle(aElement); // is respected. aElement may not have a frame.
RefPtr<const ComputedStyle> sc =
nsComputedDOMStyle::GetComputedStyle(aElement);
if (!sc) { if (!sc) {
return NSApp.userInterfaceLayoutDirection; return NSApp.userInterfaceLayoutDirection;
} }
@ -711,11 +767,13 @@ void nsMenuX::RebuildMenu() {
} }
if (menuPopup->IsElement()) { if (menuPopup->IsElement()) {
mNativeMenu.userInterfaceLayoutDirection = DirectionForElement(menuPopup->AsElement()); mNativeMenu.userInterfaceLayoutDirection =
DirectionForElement(menuPopup->AsElement());
} }
// Iterate over the kids // Iterate over the kids
for (nsIContent* child = menuPopup->GetFirstChild(); child; child = child->GetNextSibling()) { for (nsIContent* child = menuPopup->GetFirstChild(); child;
child = child->GetNextSibling()) {
if (Maybe<MenuChild> menuChild = CreateMenuChild(child)) { if (Maybe<MenuChild> menuChild = CreateMenuChild(child)) {
AddMenuChild(std::move(*menuChild)); AddMenuChild(std::move(*menuChild));
} }
@ -732,9 +790,12 @@ void nsMenuX::InsertPlaceholderIfNeeded() {
if ([mNativeMenu numberOfItems] == 0) { if ([mNativeMenu numberOfItems] == 0) {
MOZ_RELEASE_ASSERT(mVisibleItemsCount == 0); MOZ_RELEASE_ASSERT(mVisibleItemsCount == 0);
NSMenuItem* item = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; NSMenuItem* item = [[NSMenuItem alloc] initWithTitle:@""
action:nil
keyEquivalent:@""];
item.enabled = NO; item.enabled = NO;
item.view = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 150, 1)] autorelease]; item.view =
[[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 150, 1)] autorelease];
[mNativeMenu addItem:item]; [mNativeMenu addItem:item];
[item release]; [item release];
} }
@ -800,11 +861,13 @@ GeckoNSMenu* nsMenuX::CreateMenuWithGeckoString(nsString& aMenuTitle) {
} }
Maybe<nsMenuX::MenuChild> nsMenuX::CreateMenuChild(nsIContent* aContent) { Maybe<nsMenuX::MenuChild> nsMenuX::CreateMenuChild(nsIContent* aContent) {
if (aContent->IsAnyOfXULElements(nsGkAtoms::menuitem, nsGkAtoms::menuseparator)) { if (aContent->IsAnyOfXULElements(nsGkAtoms::menuitem,
nsGkAtoms::menuseparator)) {
return Some(MenuChild(CreateMenuItem(aContent))); return Some(MenuChild(CreateMenuItem(aContent)));
} }
if (aContent->IsXULElement(nsGkAtoms::menu)) { if (aContent->IsXULElement(nsGkAtoms::menu)) {
return Some(MenuChild(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, aContent))); return Some(
MenuChild(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, aContent)));
} }
return {}; return {};
} }
@ -821,9 +884,10 @@ RefPtr<nsMenuItemX> nsMenuX::CreateMenuItem(nsIContent* aMenuItemContent) {
if (aMenuItemContent->IsXULElement(nsGkAtoms::menuseparator)) { if (aMenuItemContent->IsXULElement(nsGkAtoms::menuseparator)) {
itemType = eSeparatorMenuItemType; itemType = eSeparatorMenuItemType;
} else if (aMenuItemContent->IsElement()) { } else if (aMenuItemContent->IsElement()) {
static Element::AttrValuesArray strings[] = {nsGkAtoms::checkbox, nsGkAtoms::radio, nullptr}; static Element::AttrValuesArray strings[] = {nsGkAtoms::checkbox,
switch (aMenuItemContent->AsElement()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type, nsGkAtoms::radio, nullptr};
strings, eCaseMatters)) { switch (aMenuItemContent->AsElement()->FindAttrValueIn(
kNameSpaceID_None, nsGkAtoms::type, strings, eCaseMatters)) {
case 0: case 0:
itemType = eCheckboxMenuItemType; itemType = eCheckboxMenuItemType;
break; break;
@ -833,17 +897,20 @@ RefPtr<nsMenuItemX> nsMenuX::CreateMenuItem(nsIContent* aMenuItemContent) {
} }
} }
return MakeRefPtr<nsMenuItemX>(this, menuitemName, itemType, mMenuGroupOwner, aMenuItemContent); return MakeRefPtr<nsMenuItemX>(this, menuitemName, itemType, mMenuGroupOwner,
aMenuItemContent);
} }
// This menu is about to open. Returns false if the handler wants to stop the opening of the menu. // This menu is about to open. Returns false if the handler wants to stop the
// opening of the menu.
bool nsMenuX::OnOpen() { bool nsMenuX::OnOpen() {
if (mDidFirePopupshowingAndIsApprovedToOpen) { if (mDidFirePopupshowingAndIsApprovedToOpen) {
return true; return true;
} }
if (mIsOpen) { if (mIsOpen) {
NS_WARNING("nsMenuX::OnOpen() called while the menu is already considered to be open. This " NS_WARNING("nsMenuX::OnOpen() called while the menu is already considered "
"to be open. This "
"seems odd."); "seems odd.");
} }
@ -854,7 +921,8 @@ bool nsMenuX::OnOpen() {
} }
nsEventStatus status = nsEventStatus_eIgnore; nsEventStatus status = nsEventStatus_eIgnore;
WidgetMouseEvent event(true, eXULPopupShowing, nullptr, WidgetMouseEvent::eReal); WidgetMouseEvent event(true, eXULPopupShowing, nullptr,
WidgetMouseEvent::eReal);
nsresult rv = NS_OK; nsresult rv = NS_OK;
RefPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent; RefPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent;
@ -886,9 +954,9 @@ void nsMenuX::DidFirePopupShowing() {
} }
} }
// Find the |menupopup| child in the |popup| representing this menu. It should be one // Find the |menupopup| child in the |popup| representing this menu. It should
// of a very few children so we won't be iterating over a bazillion menu items to find // be one of a very few children so we won't be iterating over a bazillion menu
// it (so the strcmp won't kill us). // items to find it (so the strcmp won't kill us).
already_AddRefed<nsIContent> nsMenuX::GetMenuPopupContent() { already_AddRefed<nsIContent> nsMenuX::GetMenuPopupContent() {
// Check to see if we are a "menupopup" node (if we are a native menu). // Check to see if we are a "menupopup" node (if we are a native menu).
if (mContent->IsXULElement(nsGkAtoms::menupopup)) { if (mContent->IsXULElement(nsGkAtoms::menupopup)) {
@ -935,7 +1003,8 @@ bool nsMenuX::IsXULWindowMenu(nsIContent* aMenuContent) {
// nsChangeObserver // nsChangeObserver
// //
void nsMenuX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent* aContent, void nsMenuX::ObserveAttributeChanged(dom::Document* aDocument,
nsIContent* aContent,
nsAtom* aAttribute) { nsAtom* aAttribute) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@ -945,14 +1014,17 @@ void nsMenuX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent* aCon
} }
if (aAttribute == nsGkAtoms::disabled) { if (aAttribute == nsGkAtoms::disabled) {
SetEnabled(!mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, SetEnabled(!mContent->AsElement()->AttrValueIs(
nsGkAtoms::_true, eCaseMatters)); kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true,
eCaseMatters));
} else if (aAttribute == nsGkAtoms::label) { } else if (aAttribute == nsGkAtoms::label) {
mContent->AsElement()->GetAttr(nsGkAtoms::label, mLabel); mContent->AsElement()->GetAttr(nsGkAtoms::label, mLabel);
NSString* newCocoaLabelString = nsMenuUtilsX::GetTruncatedCocoaLabel(mLabel); NSString* newCocoaLabelString =
nsMenuUtilsX::GetTruncatedCocoaLabel(mLabel);
mNativeMenu.title = newCocoaLabelString; mNativeMenu.title = newCocoaLabelString;
mNativeMenuItem.title = newCocoaLabelString; mNativeMenuItem.title = newCocoaLabelString;
} else if (aAttribute == nsGkAtoms::hidden || aAttribute == nsGkAtoms::collapsed) { } else if (aAttribute == nsGkAtoms::hidden ||
aAttribute == nsGkAtoms::collapsed) {
SetRebuild(true); SetRebuild(true);
bool newVisible = !nsMenuUtilsX::NodeIsHiddenOrCollapsed(mContent); bool newVisible = !nsMenuUtilsX::NodeIsHiddenOrCollapsed(mContent);
@ -977,8 +1049,9 @@ void nsMenuX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent* aCon
NS_OBJC_END_TRY_ABORT_BLOCK; NS_OBJC_END_TRY_ABORT_BLOCK;
} }
void nsMenuX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aContainer, void nsMenuX::ObserveContentRemoved(dom::Document* aDocument,
nsIContent* aChild, nsIContent* aPreviousSibling) { nsIContent* aContainer, nsIContent* aChild,
nsIContent* aPreviousSibling) {
if (gConstructingMenu) { if (gConstructingMenu) {
return; return;
} }
@ -991,7 +1064,8 @@ void nsMenuX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aConta
return; return;
} }
// The menu is currently open. Remove the child from mMenuChildren and from our NSMenu. // The menu is currently open. Remove the child from mMenuChildren and from
// our NSMenu.
nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent(); nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent();
if (popupContent && aContainer == popupContent && aChild->IsElement()) { if (popupContent && aContainer == popupContent && aChild->IsElement()) {
if (Maybe<MenuChild> child = GetItemForElement(aChild->AsElement())) { if (Maybe<MenuChild> child = GetItemForElement(aChild->AsElement())) {
@ -1000,7 +1074,8 @@ void nsMenuX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aConta
} }
} }
void nsMenuX::ObserveContentInserted(dom::Document* aDocument, nsIContent* aContainer, void nsMenuX::ObserveContentInserted(dom::Document* aDocument,
nsIContent* aContainer,
nsIContent* aChild) { nsIContent* aChild) {
if (gConstructingMenu) { if (gConstructingMenu) {
return; return;
@ -1013,7 +1088,8 @@ void nsMenuX::ObserveContentInserted(dom::Document* aDocument, nsIContent* aCont
return; return;
} }
// The menu is currently open. Insert the child into mMenuChildren and into our NSMenu. // The menu is currently open. Insert the child into mMenuChildren and into
// our NSMenu.
nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent(); nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent();
if (popupContent && aContainer == popupContent) { if (popupContent && aContainer == popupContent) {
if (Maybe<MenuChild> child = CreateMenuChild(aChild)) { if (Maybe<MenuChild> child = CreateMenuChild(aChild)) {
@ -1034,22 +1110,27 @@ void nsMenuX::IconUpdated() {
} }
} }
void nsMenuX::MenuChildChangedVisibility(const MenuChild& aChild, bool aIsVisible) { void nsMenuX::MenuChildChangedVisibility(const MenuChild& aChild,
bool aIsVisible) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
NSMenuItem* nativeItem = aChild.match( NSMenuItem* nativeItem = aChild.match(
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); }, [](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); },
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->NativeNSMenuItem(); }); [](const RefPtr<nsMenuItemX>& aMenuItem) {
return aMenuItem->NativeNSMenuItem();
});
if (aIsVisible) { if (aIsVisible) {
MOZ_RELEASE_ASSERT(!nativeItem.menu, MOZ_RELEASE_ASSERT(
"The native item should not be in a menu while it is hidden"); !nativeItem.menu,
"The native item should not be in a menu while it is hidden");
RemovePlaceholderIfPresent(); RemovePlaceholderIfPresent();
NSInteger insertionPoint = CalculateNativeInsertionPoint(aChild); NSInteger insertionPoint = CalculateNativeInsertionPoint(aChild);
[mNativeMenu insertItem:nativeItem atIndex:insertionPoint]; [mNativeMenu insertItem:nativeItem atIndex:insertionPoint];
mVisibleItemsCount++; mVisibleItemsCount++;
} else { } else {
MOZ_RELEASE_ASSERT([mNativeMenu indexOfItem:nativeItem] != -1, MOZ_RELEASE_ASSERT(
"The native item should be in this menu while it is visible"); [mNativeMenu indexOfItem:nativeItem] != -1,
"The native item should be in this menu while it is visible");
[mNativeMenu removeItem:nativeItem]; [mNativeMenu removeItem:nativeItem];
mVisibleItemsCount--; mVisibleItemsCount--;
InsertPlaceholderIfNeeded(); InsertPlaceholderIfNeeded();
@ -1067,7 +1148,9 @@ NSInteger nsMenuX::CalculateNativeInsertionPoint(const MenuChild& aChild) {
} }
NSMenuItem* nativeItem = currItem.match( NSMenuItem* nativeItem = currItem.match(
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); }, [](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); },
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->NativeNSMenuItem(); }); [](const RefPtr<nsMenuItemX>& aMenuItem) {
return aMenuItem->NativeNSMenuItem();
});
// Only count visible items. // Only count visible items.
if (nativeItem.menu) { if (nativeItem.menu) {
insertionPoint++; insertionPoint++;
@ -1077,9 +1160,10 @@ NSInteger nsMenuX::CalculateNativeInsertionPoint(const MenuChild& aChild) {
} }
void nsMenuX::Dump(uint32_t aIndent) const { void nsMenuX::Dump(uint32_t aIndent) const {
printf("%*s - menu [%p] %-16s <%s>", aIndent * 2, "", this, printf(
mLabel.IsEmpty() ? "(empty label)" : NS_ConvertUTF16toUTF8(mLabel).get(), "%*s - menu [%p] %-16s <%s>", aIndent * 2, "", this,
NS_ConvertUTF16toUTF8(mContent->NodeName()).get()); mLabel.IsEmpty() ? "(empty label)" : NS_ConvertUTF16toUTF8(mLabel).get(),
NS_ConvertUTF16toUTF8(mContent->NodeName()).get());
if (mNeedsRebuild) { if (mNeedsRebuild) {
printf(" [NeedsRebuild]"); printf(" [NeedsRebuild]");
} }
@ -1095,8 +1179,11 @@ void nsMenuX::Dump(uint32_t aIndent) const {
printf(" (%d visible items)", int(mVisibleItemsCount)); printf(" (%d visible items)", int(mVisibleItemsCount));
printf("\n"); printf("\n");
for (const auto& subitem : mMenuChildren) { for (const auto& subitem : mMenuChildren) {
subitem.match([=](const RefPtr<nsMenuX>& aMenu) { aMenu->Dump(aIndent + 1); }, subitem.match(
[=](const RefPtr<nsMenuItemX>& aMenuItem) { aMenuItem->Dump(aIndent + 1); }); [=](const RefPtr<nsMenuX>& aMenu) { aMenu->Dump(aIndent + 1); },
[=](const RefPtr<nsMenuItemX>& aMenuItem) {
aMenuItem->Dump(aIndent + 1);
});
} }
} }
@ -1108,8 +1195,8 @@ void nsMenuX::Dump(uint32_t aIndent) const {
- (id)initWithGeckoMenu:(nsMenuX*)geckoMenu { - (id)initWithGeckoMenu:(nsMenuX*)geckoMenu {
if ((self = [super init])) { if ((self = [super init])) {
NS_ASSERTION(geckoMenu, NS_ASSERTION(geckoMenu, "Cannot initialize native menu delegate with NULL "
"Cannot initialize native menu delegate with NULL gecko menu! Will crash!"); "gecko menu! Will crash!");
mGeckoMenu = geckoMenu; mGeckoMenu = geckoMenu;
mBlocksToRunWhenOpen = [[NSMutableArray alloc] init]; mBlocksToRunWhenOpen = [[NSMutableArray alloc] init];
} }
@ -1131,7 +1218,8 @@ void nsMenuX::Dump(uint32_t aIndent) const {
} }
Maybe<uint32_t> index = Maybe<uint32_t> index =
aItem ? Some(static_cast<uint32_t>([aMenu indexOfItem:aItem])) : Nothing(); aItem ? Some(static_cast<uint32_t>([aMenu indexOfItem:aItem]))
: Nothing();
mGeckoMenu->OnHighlightedItemChanged(index); mGeckoMenu->OnHighlightedItemChanged(index);
} }
@ -1269,7 +1357,8 @@ static NSMutableDictionary* gShadowKeyEquivDB = nil;
- (int)removeTable:(NSMapTable*)aTable { - (int)removeTable:(NSMapTable*)aTable {
if (aTable) { if (aTable) {
NSValue* objectToRemove = [mTables member:[NSValue valueWithPointer:aTable]]; NSValue* objectToRemove =
[mTables member:[NSValue valueWithPointer:aTable]];
if (objectToRemove) { if (objectToRemove) {
[mTables removeObject:objectToRemove]; [mTables removeObject:objectToRemove];
} }
@ -1281,7 +1370,8 @@ static NSMutableDictionary* gShadowKeyEquivDB = nil;
@interface NSMenu (MethodSwizzling) @interface NSMenu (MethodSwizzling)
+ (void)nsMenuX_NSMenu_addItem:(NSMenuItem*)aItem toTable:(NSMapTable*)aTable; + (void)nsMenuX_NSMenu_addItem:(NSMenuItem*)aItem toTable:(NSMapTable*)aTable;
+ (void)nsMenuX_NSMenu_removeItem:(NSMenuItem*)aItem fromTable:(NSMapTable*)aTable; + (void)nsMenuX_NSMenu_removeItem:(NSMenuItem*)aItem
fromTable:(NSMapTable*)aTable;
@end @end
@implementation NSMenu (MethodSwizzling) @implementation NSMenu (MethodSwizzling)
@ -1304,7 +1394,8 @@ static NSMutableDictionary* gShadowKeyEquivDB = nil;
[self nsMenuX_NSMenu_addItem:aItem toTable:aTable]; [self nsMenuX_NSMenu_addItem:aItem toTable:aTable];
} }
+ (void)nsMenuX_NSMenu_removeItem:(NSMenuItem*)aItem fromTable:(NSMapTable*)aTable { + (void)nsMenuX_NSMenu_removeItem:(NSMenuItem*)aItem
fromTable:(NSMapTable*)aTable {
[self nsMenuX_NSMenu_removeItem:aItem fromTable:aTable]; [self nsMenuX_NSMenu_removeItem:aItem fromTable:aTable];
if (aItem && aTable) { if (aItem && aTable) {
@ -1382,7 +1473,9 @@ static NSMutableDictionary* gShadowKeyEquivDB = nil;
} }
} }
[self nsMenuX_populateMenu:aMenu withServiceEntries:filteredServices forDisplay:aForDisplay]; [self nsMenuX_populateMenu:aMenu
withServiceEntries:filteredServices
forDisplay:aForDisplay];
} }
@end @end

File diff suppressed because it is too large Load diff

View file

@ -73,7 +73,8 @@ NS_IMETHODIMP
nsPrintDialogServiceX::Init() { return NS_OK; } nsPrintDialogServiceX::Init() { return NS_OK; }
NS_IMETHODIMP NS_IMETHODIMP
nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSelection, nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent,
bool aHaveSelection,
nsIPrintSettings* aSettings) { nsIPrintSettings* aSettings) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN; NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
@ -84,7 +85,8 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
NSPrintInfo* printInfo = settingsX->CreateOrCopyPrintInfo(/* aWithScaling = */ true); NSPrintInfo* printInfo =
settingsX->CreateOrCopyPrintInfo(/* aWithScaling = */ true);
if (NS_WARN_IF(!printInfo)) { if (NS_WARN_IF(!printInfo)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -100,7 +102,8 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
NULL, reinterpret_cast<const UniChar*>(adjustedTitle.BeginReading()), NULL, reinterpret_cast<const UniChar*>(adjustedTitle.BeginReading()),
adjustedTitle.Length()); adjustedTitle.Length());
if (cfTitleString) { if (cfTitleString) {
auto pmPrintSettings = static_cast<PMPrintSettings>([printInfo PMPrintSettings]); auto pmPrintSettings =
static_cast<PMPrintSettings>([printInfo PMPrintSettings]);
::PMPrintSettingsSetJobName(pmPrintSettings, cfTitleString); ::PMPrintSettingsSetJobName(pmPrintSettings, cfTitleString);
[printInfo updateFromPMPrintSettings]; [printInfo updateFromPMPrintSettings];
CFRelease(cfTitleString); CFRelease(cfTitleString);
@ -117,8 +120,8 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
// [panel runModal] will look for it. We create the view because otherwise // [panel runModal] will look for it. We create the view because otherwise
// we'll get unrelated warnings printed to the console. // we'll get unrelated warnings printed to the console.
NSView* tmpView = [[NSView alloc] init]; NSView* tmpView = [[NSView alloc] init];
NSPrintOperation* printOperation = [NSPrintOperation printOperationWithView:tmpView NSPrintOperation* printOperation =
printInfo:printInfo]; [NSPrintOperation printOperationWithView:tmpView printInfo:printInfo];
[NSPrintOperation setCurrentOperation:printOperation]; [NSPrintOperation setCurrentOperation:printOperation];
NSPrintPanel* panel = [NSPrintPanel printPanel]; NSPrintPanel* panel = [NSPrintPanel printPanel];
@ -136,8 +139,9 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
int button = [panel runModal]; int button = [panel runModal];
nsCocoaUtils::CleanUpAfterNativeAppModalDialog(); nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
// Retrieve a printInfo with the updated settings. (The NSPrintOperation operates on a // Retrieve a printInfo with the updated settings. (The NSPrintOperation
// copy, so the object we passed in will not have been modified.) // operates on a copy, so the object we passed in will not have been
// modified.)
NSPrintInfo* result = [[NSPrintOperation currentOperation] printInfo]; NSPrintInfo* result = [[NSPrintOperation currentOperation] printInfo];
if (!result) { if (!result) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -164,9 +168,9 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
[viewController exportSettings]; [viewController exportSettings];
// Update our settings object based on the user's choices in the dialog. // Update our settings object based on the user's choices in the dialog.
// We tell settingsX to adopt this printInfo so that it will be used to run print job, // We tell settingsX to adopt this printInfo so that it will be used to run
// so that any printer-specific custom settings from print dialog extension panels // print job, so that any printer-specific custom settings from print dialog
// will be carried through. // extension panels will be carried through.
settingsX->SetFromPrintInfo(result, /* aAdoptPrintInfo = */ true); settingsX->SetFromPrintInfo(result, /* aAdoptPrintInfo = */ true);
return NS_OK; return NS_OK;
@ -188,7 +192,8 @@ nsPrintDialogServiceX::ShowPageSetupDialog(mozIDOMWindowProxy* aParent,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
NSPrintInfo* printInfo = settingsX->CreateOrCopyPrintInfo(/* aWithScaling = */ true); NSPrintInfo* printInfo =
settingsX->CreateOrCopyPrintInfo(/* aWithScaling = */ true);
if (NS_WARN_IF(!printInfo)) { if (NS_WARN_IF(!printInfo)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -200,15 +205,17 @@ nsPrintDialogServiceX::ShowPageSetupDialog(mozIDOMWindowProxy* aParent,
nsCocoaUtils::CleanUpAfterNativeAppModalDialog(); nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
if (button == NSFileHandlingPanelOKButton) { if (button == NSFileHandlingPanelOKButton) {
// The Page Setup dialog does not include non-standard settings that need to be preserved, // The Page Setup dialog does not include non-standard settings that need to
// separate from what the base printSettings object handles, so we do not need it to adopt // be preserved, separate from what the base printSettings object handles,
// the printInfo object here. // so we do not need it to adopt the printInfo object here.
settingsX->SetFromPrintInfo(printInfo, /* aAdoptPrintInfo = */ false); settingsX->SetFromPrintInfo(printInfo, /* aAdoptPrintInfo = */ false);
nsCOMPtr<nsIPrintSettingsService> printSettingsService = nsCOMPtr<nsIPrintSettingsService> printSettingsService =
do_GetService("@mozilla.org/gfx/printsettings-service;1"); do_GetService("@mozilla.org/gfx/printsettings-service;1");
if (printSettingsService && Preferences::GetBool("print.save_print_settings", false)) { if (printSettingsService &&
Preferences::GetBool("print.save_print_settings", false)) {
uint32_t flags = nsIPrintSettings::kInitSavePaperSize | uint32_t flags = nsIPrintSettings::kInitSavePaperSize |
nsIPrintSettings::kInitSaveOrientation | nsIPrintSettings::kInitSaveScaling; nsIPrintSettings::kInitSaveOrientation |
nsIPrintSettings::kInitSaveScaling;
printSettingsService->MaybeSavePrintSettingsToPrefs(aNSSettings, flags); printSettingsService->MaybeSavePrintSettingsToPrefs(aNSSettings, flags);
} }
return NS_OK; return NS_OK;
@ -234,7 +241,9 @@ nsPrintDialogServiceX::ShowPageSetupDialog(mozIDOMWindowProxy* aParent,
withFrame:(NSRect)aRect withFrame:(NSRect)aRect
alignment:(NSTextAlignment)aAlignment; alignment:(NSTextAlignment)aAlignment;
- (void)addLabel:(const char*)aLabel withFrame:(NSRect)aRect alignment:(NSTextAlignment)aAlignment; - (void)addLabel:(const char*)aLabel
withFrame:(NSRect)aRect
alignment:(NSTextAlignment)aAlignment;
- (void)addLabel:(const char*)aLabel withFrame:(NSRect)aRect; - (void)addLabel:(const char*)aLabel withFrame:(NSRect)aRect;
@ -243,7 +252,8 @@ nsPrintDialogServiceX::ShowPageSetupDialog(mozIDOMWindowProxy* aParent,
- (NSButton*)checkboxWithLabel:(const char*)aLabel andFrame:(NSRect)aRect; - (NSButton*)checkboxWithLabel:(const char*)aLabel andFrame:(NSRect)aRect;
- (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect - (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect
selectedItem:(const nsAString&)aCurrentString; selectedItem:
(const nsAString&)aCurrentString;
- (void)addOptionsSection:(bool)aHaveSelection; - (void)addOptionsSection:(bool)aHaveSelection;
@ -265,7 +275,8 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
// Public methods // Public methods
- (id)initWithSettings:(nsIPrintSettings*)aSettings haveSelection:(bool)aHaveSelection { - (id)initWithSettings:(nsIPrintSettings*)aSettings
haveSelection:(bool)aHaveSelection {
[super initWithFrame:NSMakeRect(0, 0, 540, 185)]; [super initWithFrame:NSMakeRect(0, 0, 540, 185)];
mSettings = aSettings; mSettings = aSettings;
@ -278,7 +289,8 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
} }
- (void)exportSettings { - (void)exportSettings {
mSettings->SetPrintSelectionOnly([mPrintSelectionOnlyCheckbox state] == NSOnState); mSettings->SetPrintSelectionOnly([mPrintSelectionOnlyCheckbox state] ==
NSOnState);
mSettings->SetShrinkToFit([mShrinkToFitCheckbox state] == NSOnState); mSettings->SetShrinkToFit([mShrinkToFitCheckbox state] == NSOnState);
mSettings->SetPrintBGColors([mPrintBGColorsCheckbox state] == NSOnState); mSettings->SetPrintBGColors([mPrintBGColorsCheckbox state] == NSOnState);
mSettings->SetPrintBGImages([mPrintBGImagesCheckbox state] == NSOnState); mSettings->SetPrintBGImages([mPrintBGImagesCheckbox state] == NSOnState);
@ -294,8 +306,10 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
// Localization // Localization
- (void)initBundle { - (void)initBundle {
nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID); nsCOMPtr<nsIStringBundleService> bundleSvc =
bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties", &mPrintBundle); do_GetService(NS_STRINGBUNDLE_CONTRACTID);
bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties",
&mPrintBundle);
} }
- (NSString*)localizedString:(const char*)aKey { - (NSString*)localizedString:(const char*)aKey {
@ -303,11 +317,14 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
nsAutoString intlString; nsAutoString intlString;
mPrintBundle->GetStringFromName(aKey, intlString); mPrintBundle->GetStringFromName(aKey, intlString);
NSMutableString* s = NSMutableString* s = [NSMutableString
[NSMutableString stringWithUTF8String:NS_ConvertUTF16toUTF8(intlString).get()]; stringWithUTF8String:NS_ConvertUTF16toUTF8(intlString).get()];
// Remove all underscores (they're used in the GTK dialog for accesskeys). // Remove all underscores (they're used in the GTK dialog for accesskeys).
[s replaceOccurrencesOfString:@"_" withString:@"" options:0 range:NSMakeRange(0, [s length])]; [s replaceOccurrencesOfString:@"_"
withString:@""
options:0
range:NSMakeRange(0, [s length])];
return s; return s;
} }
@ -328,7 +345,9 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
return label; return label;
} }
- (void)addLabel:(const char*)aLabel withFrame:(NSRect)aRect alignment:(NSTextAlignment)aAlignment { - (void)addLabel:(const char*)aLabel
withFrame:(NSRect)aRect
alignment:(NSTextAlignment)aAlignment {
NSTextField* label = [self label:aLabel withFrame:aRect alignment:aAlignment]; NSTextField* label = [self label:aLabel withFrame:aRect alignment:aAlignment];
[self addSubview:label]; [self addSubview:label];
} }
@ -352,16 +371,19 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
} }
- (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect - (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect
selectedItem:(const nsAString&)aCurrentString { selectedItem:
NSPopUpButton* list = [[[NSPopUpButton alloc] initWithFrame:aRect pullsDown:NO] autorelease]; (const nsAString&)aCurrentString {
NSPopUpButton* list = [[[NSPopUpButton alloc] initWithFrame:aRect
pullsDown:NO] autorelease];
[list setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; [list setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
[[list cell] setControlSize:NSControlSizeSmall]; [[list cell] setControlSize:NSControlSizeSmall];
NSArray* items = [NSArray arrayWithObjects:[self localizedString:"headerFooterBlank"], NSArray* items = [NSArray
[self localizedString:"headerFooterTitle"], arrayWithObjects:[self localizedString:"headerFooterBlank"],
[self localizedString:"headerFooterURL"], [self localizedString:"headerFooterTitle"],
[self localizedString:"headerFooterDate"], [self localizedString:"headerFooterURL"],
[self localizedString:"headerFooterPage"], [self localizedString:"headerFooterDate"],
[self localizedString:"headerFooterPageTotal"], nil]; [self localizedString:"headerFooterPage"],
[self localizedString:"headerFooterPageTotal"], nil];
[list addItemsWithTitles:items]; [list addItemsWithTitles:items];
NS_ConvertUTF16toUTF8 currentStringUTF8(aCurrentString); NS_ConvertUTF16toUTF8 currentStringUTF8(aCurrentString);
@ -382,8 +404,9 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
[self addLabel:"optionsTitleMac" withFrame:NSMakeRect(0, 155, 151, 22)]; [self addLabel:"optionsTitleMac" withFrame:NSMakeRect(0, 155, 151, 22)];
// "Print Selection Only" // "Print Selection Only"
mPrintSelectionOnlyCheckbox = [self checkboxWithLabel:"selectionOnly" mPrintSelectionOnlyCheckbox =
andFrame:NSMakeRect(156, 155, 0, 0)]; [self checkboxWithLabel:"selectionOnly"
andFrame:NSMakeRect(156, 155, 0, 0)];
[mPrintSelectionOnlyCheckbox setEnabled:aHaveSelection]; [mPrintSelectionOnlyCheckbox setEnabled:aHaveSelection];
if (mSettings->GetPrintSelectionOnly()) { if (mSettings->GetPrintSelectionOnly()) {
@ -393,7 +416,8 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
[self addSubview:mPrintSelectionOnlyCheckbox]; [self addSubview:mPrintSelectionOnlyCheckbox];
// "Shrink To Fit" // "Shrink To Fit"
mShrinkToFitCheckbox = [self checkboxWithLabel:"shrinkToFit" andFrame:NSMakeRect(156, 133, 0, 0)]; mShrinkToFitCheckbox = [self checkboxWithLabel:"shrinkToFit"
andFrame:NSMakeRect(156, 133, 0, 0)];
bool shrinkToFit; bool shrinkToFit;
mSettings->GetShrinkToFit(&shrinkToFit); mSettings->GetShrinkToFit(&shrinkToFit);
@ -437,33 +461,39 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
nsString sel; nsString sel;
mSettings->GetHeaderStrLeft(sel); mSettings->GetHeaderStrLeft(sel);
mHeaderLeftList = [self headerFooterItemListWithFrame:NSMakeRect(156, 44, 100, 22) mHeaderLeftList =
selectedItem:sel]; [self headerFooterItemListWithFrame:NSMakeRect(156, 44, 100, 22)
selectedItem:sel];
[self addSubview:mHeaderLeftList]; [self addSubview:mHeaderLeftList];
mSettings->GetHeaderStrCenter(sel); mSettings->GetHeaderStrCenter(sel);
mHeaderCenterList = [self headerFooterItemListWithFrame:NSMakeRect(256, 44, 100, 22) mHeaderCenterList =
selectedItem:sel]; [self headerFooterItemListWithFrame:NSMakeRect(256, 44, 100, 22)
selectedItem:sel];
[self addSubview:mHeaderCenterList]; [self addSubview:mHeaderCenterList];
mSettings->GetHeaderStrRight(sel); mSettings->GetHeaderStrRight(sel);
mHeaderRightList = [self headerFooterItemListWithFrame:NSMakeRect(356, 44, 100, 22) mHeaderRightList =
selectedItem:sel]; [self headerFooterItemListWithFrame:NSMakeRect(356, 44, 100, 22)
selectedItem:sel];
[self addSubview:mHeaderRightList]; [self addSubview:mHeaderRightList];
mSettings->GetFooterStrLeft(sel); mSettings->GetFooterStrLeft(sel);
mFooterLeftList = [self headerFooterItemListWithFrame:NSMakeRect(156, 0, 100, 22) mFooterLeftList =
selectedItem:sel]; [self headerFooterItemListWithFrame:NSMakeRect(156, 0, 100, 22)
selectedItem:sel];
[self addSubview:mFooterLeftList]; [self addSubview:mFooterLeftList];
mSettings->GetFooterStrCenter(sel); mSettings->GetFooterStrCenter(sel);
mFooterCenterList = [self headerFooterItemListWithFrame:NSMakeRect(256, 0, 100, 22) mFooterCenterList =
selectedItem:sel]; [self headerFooterItemListWithFrame:NSMakeRect(256, 0, 100, 22)
selectedItem:sel];
[self addSubview:mFooterCenterList]; [self addSubview:mFooterCenterList];
mSettings->GetFooterStrRight(sel); mSettings->GetFooterStrRight(sel);
mFooterRightList = [self headerFooterItemListWithFrame:NSMakeRect(356, 0, 100, 22) mFooterRightList =
selectedItem:sel]; [self headerFooterItemListWithFrame:NSMakeRect(356, 0, 100, 22)
selectedItem:sel];
[self addSubview:mFooterRightList]; [self addSubview:mFooterRightList];
} }
@ -502,8 +532,9 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
- (NSString*)summaryValueForCheckbox:(NSButton*)aCheckbox { - (NSString*)summaryValueForCheckbox:(NSButton*)aCheckbox {
if (![aCheckbox isEnabled]) return [self localizedString:"summaryNAValue"]; if (![aCheckbox isEnabled]) return [self localizedString:"summaryNAValue"];
return [aCheckbox state] == NSOnState ? [self localizedString:"summaryOnValue"] return [aCheckbox state] == NSOnState
: [self localizedString:"summaryOffValue"]; ? [self localizedString:"summaryOnValue"]
: [self localizedString:"summaryOffValue"];
} }
- (NSString*)headerSummaryValue { - (NSString*)headerSummaryValue {
@ -513,7 +544,8 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
stringByAppendingString: stringByAppendingString:
[[mHeaderCenterList titleOfSelectedItem] [[mHeaderCenterList titleOfSelectedItem]
stringByAppendingString: stringByAppendingString:
[@", " stringByAppendingString:[mHeaderRightList titleOfSelectedItem]]]]]; [@", " stringByAppendingString:
[mHeaderRightList titleOfSelectedItem]]]]];
} }
- (NSString*)footerSummaryValue { - (NSString*)footerSummaryValue {
@ -523,43 +555,49 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
stringByAppendingString: stringByAppendingString:
[[mFooterCenterList titleOfSelectedItem] [[mFooterCenterList titleOfSelectedItem]
stringByAppendingString: stringByAppendingString:
[@", " stringByAppendingString:[mFooterRightList titleOfSelectedItem]]]]]; [@", " stringByAppendingString:
[mFooterRightList titleOfSelectedItem]]]]];
} }
- (NSArray*)localizedSummaryItems { - (NSArray*)localizedSummaryItems {
return [NSArray return [NSArray
arrayWithObjects: arrayWithObjects:
[NSDictionary [NSDictionary
dictionaryWithObjectsAndKeys:[self localizedString:"summarySelectionOnlyTitle"], dictionaryWithObjectsAndKeys:
NSPrintPanelAccessorySummaryItemNameKey, [self localizedString:"summarySelectionOnlyTitle"],
[self NSPrintPanelAccessorySummaryItemNameKey,
summaryValueForCheckbox:mPrintSelectionOnlyCheckbox], [self summaryValueForCheckbox:mPrintSelectionOnlyCheckbox],
NSPrintPanelAccessorySummaryItemDescriptionKey, nil], NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
[NSDictionary dictionaryWithObjectsAndKeys:
[self localizedString:"summaryShrinkToFitTitle"],
NSPrintPanelAccessorySummaryItemNameKey,
[self summaryValueForCheckbox:mShrinkToFitCheckbox],
NSPrintPanelAccessorySummaryItemDescriptionKey,
nil],
[NSDictionary [NSDictionary
dictionaryWithObjectsAndKeys:[self localizedString:"summaryShrinkToFitTitle"], dictionaryWithObjectsAndKeys:
NSPrintPanelAccessorySummaryItemNameKey, [self localizedString:"summaryPrintBGColorsTitle"],
[self summaryValueForCheckbox:mShrinkToFitCheckbox], NSPrintPanelAccessorySummaryItemNameKey,
NSPrintPanelAccessorySummaryItemDescriptionKey, nil], [self summaryValueForCheckbox:mPrintBGColorsCheckbox],
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
[NSDictionary [NSDictionary
dictionaryWithObjectsAndKeys:[self localizedString:"summaryPrintBGColorsTitle"], dictionaryWithObjectsAndKeys:
NSPrintPanelAccessorySummaryItemNameKey, [self localizedString:"summaryPrintBGImagesTitle"],
[self summaryValueForCheckbox:mPrintBGColorsCheckbox], NSPrintPanelAccessorySummaryItemNameKey,
NSPrintPanelAccessorySummaryItemDescriptionKey, nil], [self summaryValueForCheckbox:mPrintBGImagesCheckbox],
[NSDictionary NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
dictionaryWithObjectsAndKeys:[self localizedString:"summaryPrintBGImagesTitle"], [NSDictionary dictionaryWithObjectsAndKeys:
NSPrintPanelAccessorySummaryItemNameKey, [self localizedString:"summaryHeaderTitle"],
[self summaryValueForCheckbox:mPrintBGImagesCheckbox], NSPrintPanelAccessorySummaryItemNameKey,
NSPrintPanelAccessorySummaryItemDescriptionKey, nil], [self headerSummaryValue],
[NSDictionary dictionaryWithObjectsAndKeys:[self localizedString:"summaryHeaderTitle"], NSPrintPanelAccessorySummaryItemDescriptionKey,
NSPrintPanelAccessorySummaryItemNameKey, nil],
[self headerSummaryValue], [NSDictionary dictionaryWithObjectsAndKeys:
NSPrintPanelAccessorySummaryItemDescriptionKey, [self localizedString:"summaryFooterTitle"],
nil], NSPrintPanelAccessorySummaryItemNameKey,
[NSDictionary dictionaryWithObjectsAndKeys:[self localizedString:"summaryFooterTitle"], [self footerSummaryValue],
NSPrintPanelAccessorySummaryItemNameKey, NSPrintPanelAccessorySummaryItemDescriptionKey,
[self footerSummaryValue], nil],
NSPrintPanelAccessorySummaryItemDescriptionKey,
nil],
nil]; nil];
} }
@ -569,11 +607,13 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
@implementation PrintPanelAccessoryController @implementation PrintPanelAccessoryController
- (id)initWithSettings:(nsIPrintSettings*)aSettings haveSelection:(bool)aHaveSelection { - (id)initWithSettings:(nsIPrintSettings*)aSettings
haveSelection:(bool)aHaveSelection {
[super initWithNibName:nil bundle:nil]; [super initWithNibName:nil bundle:nil];
NSView* accView = [[PrintPanelAccessoryView alloc] initWithSettings:aSettings NSView* accView =
haveSelection:aHaveSelection]; [[PrintPanelAccessoryView alloc] initWithSettings:aSettings
haveSelection:aHaveSelection];
[self setView:accView]; [self setView:accView];
[accView release]; [accView release];
return self; return self;

Some files were not shown because too many files have changed in this diff Show more