diff --git a/accessible/tests/browser/mac/head.js b/accessible/tests/browser/mac/head.js index 55203e4d84c2..a99ac2f401be 100644 --- a/accessible/tests/browser/mac/head.js +++ b/accessible/tests/browser/mac/head.js @@ -4,7 +4,7 @@ "use strict"; -/* exported getNativeInterface, waitForMacEventWithInfo, waitForMacEvent, NSRange */ +/* exported getNativeInterface, waitForMacEventWithInfo, waitForMacEvent, NSRange, NSDictionary */ // Load the shared-head file first. /* import-globals-from ../shared-head.js */ @@ -56,3 +56,10 @@ function NSRange(location, length) { value: [location, length], }; } + +function NSDictionary(dict) { + return { + objectType: "NSDictionary", + object: dict, + }; +} diff --git a/accessible/xpcom/xpcAccessibleMacInterface.h b/accessible/xpcom/xpcAccessibleMacInterface.h index 950c3dbabd6c..cb969022e03e 100644 --- a/accessible/xpcom/xpcAccessibleMacInterface.h +++ b/accessible/xpcom/xpcAccessibleMacInterface.h @@ -71,6 +71,12 @@ class xpcAccessibleMacInterface : public xpcAccessibleMacNSObjectWrapper, id JsValueToNSValue(JS::HandleObject aObject, JSContext* aCx, nsresult* aResult); + // Convert a js value to a specified NSObject. This is called + // by JsValueToNSObject when encountering a JS object with + // a "object" and "objcetType" property. + id JsValueToSpecifiedNSObject(JS::HandleObject aObject, JSContext* aCx, + nsresult* aResult); + private: xpcAccessibleMacInterface(const xpcAccessibleMacInterface&) = delete; xpcAccessibleMacInterface& operator=(const xpcAccessibleMacInterface&) = diff --git a/accessible/xpcom/xpcAccessibleMacInterface.mm b/accessible/xpcom/xpcAccessibleMacInterface.mm index 6b251bbd178a..b7c6d80fc694 100644 --- a/accessible/xpcom/xpcAccessibleMacInterface.mm +++ b/accessible/xpcom/xpcAccessibleMacInterface.mm @@ -298,6 +298,16 @@ id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue, JSContex return JsValueToNSValue(obj, aCx, aResult); } + bool hasObjectType; + bool hasObject; + JS_HasOwnProperty(aCx, obj, "objectType", &hasObjectType); + JS_HasOwnProperty(aCx, obj, "object", &hasObject); + if (hasObjectType && hasObject) { + // A js object representing an NSDictionary looks like this: + // { objectType: "NSDictionary", value: {k: v, k: v, ...} } + return JsValueToSpecifiedNSObject(obj, aCx, aResult); + } + // This may be another nsIAccessibleMacInterface instance. // If so, return the wrapped NSObject. nsCOMPtr xpc = nsIXPConnect::XPConnect(); @@ -367,6 +377,68 @@ id xpcAccessibleMacInterface::JsValueToNSValue(JS::HandleObject aObject, JSConte return nil; } +id xpcAccessibleMacInterface::JsValueToSpecifiedNSObject(JS::HandleObject aObject, JSContext* aCx, + nsresult* aResult) { + *aResult = NS_ERROR_FAILURE; + JS::RootedValue objectTypeValue(aCx); + if (!JS_GetProperty(aCx, aObject, "objetType", &objectTypeValue)) { + NS_WARNING("Could not get objectType"); + return nil; + } + + JS::RootedValue objectValue(aCx); + if (!JS_GetProperty(aCx, aObject, "object", &objectValue)) { + NS_WARNING("Could not get object"); + return nil; + } + + nsAutoJSString objectType; + if (!objectTypeValue.isString() || !objectType.init(aCx, objectTypeValue)) { + NS_WARNING("objectType is not a string"); + return nil; + } + + bool isObject = objectValue.isObjectOrNull(); + if (!isObject) { + NS_WARNING("object is not a JSON object"); + return nil; + } + + JS::Rooted object(aCx, objectValue.toObjectOrNull()); + + if (objectType.EqualsLiteral("NSDictionary")) { + JS::Rooted ids(aCx, JS::IdVector(aCx)); + if (!JS_Enumerate(aCx, object, &ids)) { + NS_WARNING("Unable to get keys from dictionary object"); + return nil; + } + + NSMutableDictionary* dict = [[NSMutableDictionary alloc] init]; + + for (size_t i = 0, n = ids.length(); i < n; i++) { + nsresult rv = NS_OK; + // get current key + JS::RootedValue currentKey(aCx); + JS_IdToValue(aCx, ids[i], ¤tKey); + id unwrappedKey = JsValueToNSObject(currentKey, aCx, &rv); + NS_ENSURE_SUCCESS(rv, nil); + MOZ_ASSERT([unwrappedKey isKindOfClass:[NSString class]]); + + // get associated value for current key + JS::RootedValue currentValue(aCx); + JS_GetPropertyById(aCx, object, ids[i], ¤tValue); + id unwrappedValue = JsValueToNSObject(currentValue, aCx, &rv); + NS_ENSURE_SUCCESS(rv, nil); + dict[unwrappedKey] = unwrappedValue; + } + + *aResult = NS_OK; + return dict; + } + + return nil; +} + NS_IMPL_ISUPPORTS(xpcAccessibleMacEvent, nsIAccessibleMacEvent) xpcAccessibleMacEvent::xpcAccessibleMacEvent(id aNativeObj, id aData)