AX: Add AXUIElementCountForSearchPredicate parameterized attribute.
authorsamuel_white@apple.com <samuel_white@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Dec 2013 00:36:23 +0000 (00:36 +0000)
committersamuel_white@apple.com <samuel_white@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Dec 2013 00:36:23 +0000 (00:36 +0000)
    https://bugs.webkit.org/show_bug.cgi?id=124561

    Reviewed by Chris Fleizach.

    Added test to verify that NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute
    works as it should and updated existing test that has exposes this new attribute.

    * platform/mac/accessibility/bounds-for-range-expected.txt:
    * platform/mac/accessibility/search-predicate-element-count-expected.txt: Added.
    * platform/mac/accessibility/search-predicate-element-count.html: Added.

    Added ability to fetch the number of elements that match a specific criteria. This will enable VoiceOver
    to interface with WebKit much more dynamically. We can now get an idea of how many interesting elements
    exist on a page, and then fetch them in chunks as needed.

    Test: platform/mac/accessibility/search-predicate-element-count.html

    * accessibility/AccessibilityObject.cpp:
    (WebCore::AccessibilityObject::isAccessibilityTextSearchMatch):
    * accessibility/AccessibilityObject.h:
    (WebCore::AccessibilitySearchCriteria::AccessibilitySearchCriteria):
    * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
    (accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute):
    (-[WebAccessibilityObjectWrapper accessibilityParameterizedAttributeNames]):
    (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):

    Added function to verify that NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute works as it should.

    * DumpRenderTree/AccessibilityUIElement.cpp:
    (uiElementCountForSearchPredicateCallback):
    (uiElementForSearchPredicateCallback):
    (AccessibilityUIElement::getJSClass):
    * DumpRenderTree/AccessibilityUIElement.h:
    * DumpRenderTree/atk/AccessibilityUIElementAtk.cpp:
    (AccessibilityUIElement::uiElementCountForSearchPredicate):
    * DumpRenderTree/ios/AccessibilityUIElementIOS.mm:
    (AccessibilityUIElement::uiElementCountForSearchPredicate):
    * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
    (searchPredicateParameterizedAttributeForSearchCriteria):
    (AccessibilityUIElement::uiElementCountForSearchPredicate):
    (AccessibilityUIElement::uiElementForSearchPredicate):
    * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
    (AccessibilityUIElement::uiElementCountForSearchPredicate):
    * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp:
    (WTR::AccessibilityUIElement::uiElementCountForSearchPredicate):
    * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
    * WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl:
    * WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp:
    (WTR::AccessibilityUIElement::uiElementCountForSearchPredicate):
    * WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm:
    (WTR::searchPredicateParameterizedAttributeForSearchCriteria):
    (WTR::AccessibilityUIElement::uiElementCountForSearchPredicate):
    (WTR::AccessibilityUIElement::uiElementForSearchPredicate):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@159980 268f45cc-cd09-0410-ab3c-d52691b4dbfc

20 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac/accessibility/bounds-for-range-expected.txt
LayoutTests/platform/mac/accessibility/search-predicate-element-count-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/search-predicate-element-count.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AccessibilityObject.cpp
Source/WebCore/accessibility/AccessibilityObject.h
Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
Tools/ChangeLog
Tools/DumpRenderTree/AccessibilityUIElement.cpp
Tools/DumpRenderTree/AccessibilityUIElement.h
Tools/DumpRenderTree/atk/AccessibilityUIElementAtk.cpp
Tools/DumpRenderTree/ios/AccessibilityUIElementIOS.mm
Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
Tools/DumpRenderTree/win/AccessibilityUIElementWin.cpp
Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp
Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h
Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl
Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp
Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm

index a82e720..7d274b4 100644 (file)
@@ -1,3 +1,17 @@
+2013-12-02  Samuel White  <samuel_white@apple.com>
+
+        AX: Add AXUIElementCountForSearchPredicate parameterized attribute.
+        https://bugs.webkit.org/show_bug.cgi?id=124561
+
+        Reviewed by Chris Fleizach.
+
+        Added test to verify that NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute
+        works as it should and updated existing test that has exposes this new attribute.
+
+        * platform/mac/accessibility/bounds-for-range-expected.txt:
+        * platform/mac/accessibility/search-predicate-element-count-expected.txt: Added.
+        * platform/mac/accessibility/search-predicate-element-count.html: Added.
+
 2013-12-02  Bem Jones-Bey  <bjonesbe@adobe.com>
 
         [css shapes] Layout support for new circle shape syntax
index c4c19b8..1effe7b 100644 (file)
@@ -55,6 +55,7 @@ AXStyleTextMarkerRangeForTextMarker
 AXLengthForTextMarkerRange
 AXBoundsForRange
 AXStringForRange
+AXUIElementCountForSearchPredicate
 AXUIElementsForSearchPredicate
 AXEndTextMarkerForBounds
 AXStartTextMarkerForBounds
diff --git a/LayoutTests/platform/mac/accessibility/search-predicate-element-count-expected.txt b/LayoutTests/platform/mac/accessibility/search-predicate-element-count-expected.txt
new file mode 100644 (file)
index 0000000..d3b1b58
--- /dev/null
@@ -0,0 +1,16 @@
+This tests that search predicate based element count results are accurate.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS elementCount is 2
+PASS elementCount is 3
+PASS elementCount is 4
+PASS elementCount is 5
+PASS elementCount is 6
+PASS elementCount is 6
+PASS elementCount is 4
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/mac/accessibility/search-predicate-element-count.html b/LayoutTests/platform/mac/accessibility/search-predicate-element-count.html
new file mode 100644 (file)
index 0000000..1168696
--- /dev/null
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+<style>
+    .offscreen {
+        position:relative;
+        top:9999px;
+    }
+</style>
+<title>Search Predicate Element Count</title>
+</head>
+<body>
+
+<div id="container">
+<p id="start">Start</p>
+<!-- Tables. -->
+<table border="1">
+<tr><th>A</th><th>B</th></tr>
+<tr><td>C</td><td>D</td></tr>
+</table>
+<table border="1">
+<tr><th>W</th><th>X</th></tr>
+<tr><td>Y</td><td>Z</td></tr>
+</table>
+<br>
+<!-- Links. -->
+<a href="#">Link 1</a>
+<a href="#">Link 2</a>
+<a href="#">Link 3</a>
+<br>
+<!-- Images. -->
+<img alt="Cake" src="resources/cake.png">
+<img alt="Cake" src="resources/cake.png">
+<img alt="Cake" src="resources/cake.png">
+<img alt="Cake" src="resources/cake.png">
+<br>
+<!-- Inputs. -->
+<input type="submit" value="Submit">
+<input type="submit" value="Submit">
+<input type="submit" value="Submit">
+<input type="submit" value="Submit">
+<input type="submit" value="Submit">
+<br>
+<!-- Headings. -->
+<h1>Heading 1</h1>
+<h2>Heading 2</h2>
+<h3>Heading 3</h3>
+<h4>Heading 4</h4>
+<h5 class="offscreen">Heading 5</h5>
+<h6 class="offscreen">Heading 6</h6>
+</div>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+    description("This tests that search predicate based element count results are accurate.");
+    
+    if (window.accessibilityController) {
+        document.getElementById("container").focus();
+        var containerElement = accessibilityController.focusedElement;
+        var elementCount = 0;
+        var startElement = accessibilityController.accessibleElementById("start");
+        
+        // Tables.
+        elementCount = containerElement.uiElementCountForSearchPredicate(startElement, true, "AXTableSearchKey", "", false);
+        shouldBe("elementCount", "2");
+        
+        // Links.
+        elementCount = containerElement.uiElementCountForSearchPredicate(startElement, true, "AXLinkSearchKey", "", false);
+        shouldBe("elementCount", "3");
+        
+        // Images.
+        elementCount = containerElement.uiElementCountForSearchPredicate(startElement, true, "AXGraphicSearchKey", "", false);
+        shouldBe("elementCount", "4");
+        
+        // Inputs.
+        elementCount = containerElement.uiElementCountForSearchPredicate(startElement, true, "AXButtonSearchKey", "", false);
+        shouldBe("elementCount", "5");
+        
+        // Headings.
+        elementCount = containerElement.uiElementCountForSearchPredicate(startElement, true, "AXHeadingSearchKey", "", false);
+        shouldBe("elementCount", "6");
+        
+        // Onscreen
+        elementCount = containerElement.uiElementCountForSearchPredicate(startElement, true, "AXHeadingSearchKey", "", false);
+        shouldBe("elementCount", "6");
+        
+        // Offscreen
+        elementCount = containerElement.uiElementCountForSearchPredicate(startElement, true, "AXHeadingSearchKey", "", true);
+        shouldBe("elementCount", "4");
+        
+        // Hide superfluous text.
+        document.getElementById("container").style.display = "none";
+    }
+</script>
+
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
index 33f16a5..08d6907 100644 (file)
@@ -1,3 +1,25 @@
+2013-12-02  Samuel White  <samuel_white@apple.com>
+
+        AX: Add AXUIElementCountForSearchPredicate parameterized attribute.
+        https://bugs.webkit.org/show_bug.cgi?id=124561
+
+        Reviewed by Chris Fleizach.
+
+        Added ability to fetch the number of elements that match a specific criteria. This will enable VoiceOver
+        to interface with WebKit much more dynamically. We can now get an idea of how many interesting elements
+        exist on a page, and then fetch them in chunks as needed.
+
+        Test: platform/mac/accessibility/search-predicate-element-count.html
+
+        * accessibility/AccessibilityObject.cpp:
+        (WebCore::AccessibilityObject::isAccessibilityTextSearchMatch):
+        * accessibility/AccessibilityObject.h:
+        (WebCore::AccessibilitySearchCriteria::AccessibilitySearchCriteria):
+        * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+        (accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute):
+        (-[WebAccessibilityObjectWrapper accessibilityParameterizedAttributeNames]):
+        (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):
+
 2013-12-02  Bem Jones-Bey  <bjonesbe@adobe.com>
 
         [css shapes] Layout support for new circle shape syntax
index bd0235f..825d097 100644 (file)
@@ -263,7 +263,7 @@ bool AccessibilityObject::isAccessibilityTextSearchMatch(AccessibilityObject* ax
     if (!axObject || !criteria)
         return false;
     
-    return axObject->accessibilityObjectContainsText(criteria->searchText);
+    return axObject->accessibilityObjectContainsText(&criteria->searchText);
 }
 
 bool AccessibilityObject::accessibilityObjectContainsText(String* text) const
index 342772d..7b7379d 100644 (file)
@@ -339,16 +339,16 @@ struct AccessibilitySearchCriteria {
     AccessibilityObject* startObject;
     AccessibilitySearchDirection searchDirection;
     Vector<AccessibilitySearchKey> searchKeys;
-    String* searchText;
+    String searchText;
     unsigned resultsLimit;
     bool visibleOnly;
     
-    AccessibilitySearchCriteria(AccessibilityObject* o, AccessibilitySearchDirection d, String* t, unsigned l, bool v)
-    : startObject(o)
-    , searchDirection(d)
-    , searchText(t)
-    , resultsLimit(l)
-    , visibleOnly(v)
+    AccessibilitySearchCriteria(AccessibilityObject* startObject, AccessibilitySearchDirection searchDirection, String searchText, unsigned resultsLimit, bool visibleOnly)
+    : startObject(startObject)
+    , searchDirection(searchDirection)
+    , searchText(searchText)
+    , resultsLimit(resultsLimit)
+    , visibleOnly(visibleOnly)
     { }
 };
 
index 18994ca..74d21f6 100644 (file)
@@ -190,6 +190,10 @@ using namespace HTMLNames;
 #endif
 
 // Search
+#ifndef NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute
+#define NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute @"AXUIElementCountForSearchPredicate"
+#endif
+
 #ifndef NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute
 #define NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute @"AXUIElementsForSearchPredicate"
 #endif
@@ -536,6 +540,52 @@ static AccessibilitySearchKey accessibilitySearchKeyForString(const String& valu
     return searchKey ? searchKey : AnyTypeSearchKey;
 }
 
+static AccessibilitySearchCriteria accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(const NSDictionary *parameterizedAttribute)
+{
+    NSString *directionParameter = [parameterizedAttribute objectForKey:@"AXDirection"];
+    NSNumber *resultsLimitParameter = [parameterizedAttribute objectForKey:@"AXResultsLimit"];
+    NSString *searchTextParameter = [parameterizedAttribute objectForKey:@"AXSearchText"];
+    WebAccessibilityObjectWrapper *startElementParameter = [parameterizedAttribute objectForKey:@"AXStartElement"];
+    NSNumber *visibleOnlyParameter = [parameterizedAttribute objectForKey:@"AXVisibleOnly"];
+    id searchKeyParameter = [parameterizedAttribute objectForKey:@"AXSearchKey"];
+    
+    AccessibilitySearchDirection direction = SearchDirectionNext;
+    if ([directionParameter isKindOfClass:[NSString class]])
+        direction = [directionParameter isEqualToString:@"AXDirectionNext"] ? SearchDirectionNext : SearchDirectionPrevious;
+    
+    unsigned resultsLimit = 0;
+    if ([resultsLimitParameter isKindOfClass:[NSNumber class]])
+        resultsLimit = [resultsLimitParameter unsignedIntValue];
+    
+    String searchText;
+    if ([searchTextParameter isKindOfClass:[NSString class]])
+        searchText = searchTextParameter;
+    
+    AccessibilityObject *startElement = nullptr;
+    if ([startElementParameter isKindOfClass:[WebAccessibilityObjectWrapper class]])
+        startElement = [startElementParameter accessibilityObject];
+    
+    BOOL visibleOnly = NO;
+    if ([visibleOnlyParameter isKindOfClass:[NSNumber class]])
+        visibleOnly = [visibleOnlyParameter boolValue];
+    
+    AccessibilitySearchCriteria criteria = AccessibilitySearchCriteria(startElement, direction, searchText, resultsLimit, visibleOnly);
+    
+    if ([searchKeyParameter isKindOfClass:[NSString class]])
+        criteria.searchKeys.append(accessibilitySearchKeyForString(searchKeyParameter));
+    else if ([searchKeyParameter isKindOfClass:[NSArray class]]) {
+        size_t searchKeyCount = static_cast<size_t>([searchKeyParameter count]);
+        criteria.searchKeys.reserveInitialCapacity(searchKeyCount);
+        for (size_t i = 0; i < searchKeyCount; ++i) {
+            NSString *searchKey = [searchKeyParameter objectAtIndex:i];
+            if ([searchKey isKindOfClass:[NSString class]])
+                criteria.searchKeys.uncheckedAppend(accessibilitySearchKeyForString(searchKey));
+        }
+    }
+    
+    return criteria;
+}
+
 #pragma mark Text Marker helpers
 
 static id textMarkerForVisiblePosition(AXObjectCache* cache, const VisiblePosition& visiblePos)
@@ -2865,6 +2915,7 @@ static NSString* roleValueToNSString(AccessibilityRole value)
                       @"AXLengthForTextMarkerRange",
                       NSAccessibilityBoundsForRangeParameterizedAttribute,
                       NSAccessibilityStringForRangeParameterizedAttribute,
+                      NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute,
                       NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute,
                       NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute,
                       NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute,
@@ -3254,45 +3305,17 @@ static RenderObject* rendererForView(NSView* view)
     }
     
     // dispatch
+    if ([attribute isEqualToString:NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute]) {
+        AccessibilitySearchCriteria criteria = accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(dictionary);
+        AccessibilityObject::AccessibilityChildrenVector results;
+        m_object->findMatchingObjects(&criteria, results);
+        return @(results.size());
+    }
+    
     if ([attribute isEqualToString:NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute]) {
-        AccessibilityObject* startObject = 0;
-        if ([[dictionary objectForKey:@"AXStartElement"] isKindOfClass:[WebAccessibilityObjectWrapper self]])
-            startObject = [(WebAccessibilityObjectWrapper*)[dictionary objectForKey:@"AXStartElement"] accessibilityObject];
-        
-        AccessibilitySearchDirection searchDirection = SearchDirectionNext;
-        if ([[dictionary objectForKey:@"AXDirection"] isKindOfClass:[NSString self]])
-            searchDirection = ([(NSString*)[dictionary objectForKey:@"AXDirection"] isEqualToString:@"AXDirectionNext"]) ? SearchDirectionNext : SearchDirectionPrevious;
-
-        String searchText;
-        if ([[dictionary objectForKey:@"AXSearchText"] isKindOfClass:[NSString self]])
-            searchText = (CFStringRef)[dictionary objectForKey:@"AXSearchText"];
-        
-        unsigned resultsLimit = 0;
-        if ([[dictionary objectForKey:@"AXResultsLimit"] isKindOfClass:[NSNumber self]])
-            resultsLimit = [(NSNumber*)[dictionary objectForKey:@"AXResultsLimit"] unsignedIntValue];
-        
-        BOOL visibleOnly = NO;
-        if ([[dictionary objectForKey:@"AXVisibleOnly"] isKindOfClass:[NSNumber self]])
-            visibleOnly = [(NSNumber*)[dictionary objectForKey:@"AXVisibleOnly"] boolValue];
-        
-        AccessibilitySearchCriteria criteria = AccessibilitySearchCriteria(startObject, searchDirection, &searchText, resultsLimit, visibleOnly);
-                
-        id searchKeyEntry = [dictionary objectForKey:@"AXSearchKey"];
-        if ([searchKeyEntry isKindOfClass:[NSString class]])
-            criteria.searchKeys.append(accessibilitySearchKeyForString((CFStringRef)searchKeyEntry));
-        else if ([searchKeyEntry isKindOfClass:[NSArray class]]) {
-            size_t length = static_cast<size_t>([(NSArray *)searchKeyEntry count]);
-            criteria.searchKeys.reserveInitialCapacity(length);
-            for (size_t i = 0; i < length; ++i) {
-                id searchKey = [(NSArray *)searchKeyEntry objectAtIndex:i];
-                if ([searchKey isKindOfClass:[NSString class]])
-                    criteria.searchKeys.append(accessibilitySearchKeyForString((CFStringRef)searchKey));
-            }
-        }
-        
+        AccessibilitySearchCriteria criteria = accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(dictionary);
         AccessibilityObject::AccessibilityChildrenVector results;
         m_object->findMatchingObjects(&criteria, results);
-        
         return convertToNSArray(results);
     }
     
index cfc3cbe..e729f52 100644 (file)
@@ -1,3 +1,38 @@
+2013-12-02  Samuel White  <samuel_white@apple.com>
+
+        AX: Add AXUIElementCountForSearchPredicate parameterized attribute.
+        https://bugs.webkit.org/show_bug.cgi?id=124561
+
+        Reviewed by Chris Fleizach.
+
+        Added function to verify that NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute works as it should.
+
+        * DumpRenderTree/AccessibilityUIElement.cpp:
+        (uiElementCountForSearchPredicateCallback):
+        (uiElementForSearchPredicateCallback):
+        (AccessibilityUIElement::getJSClass):
+        * DumpRenderTree/AccessibilityUIElement.h:
+        * DumpRenderTree/atk/AccessibilityUIElementAtk.cpp:
+        (AccessibilityUIElement::uiElementCountForSearchPredicate):
+        * DumpRenderTree/ios/AccessibilityUIElementIOS.mm:
+        (AccessibilityUIElement::uiElementCountForSearchPredicate):
+        * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+        (searchPredicateParameterizedAttributeForSearchCriteria):
+        (AccessibilityUIElement::uiElementCountForSearchPredicate):
+        (AccessibilityUIElement::uiElementForSearchPredicate):
+        * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+        (AccessibilityUIElement::uiElementCountForSearchPredicate):
+        * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp:
+        (WTR::AccessibilityUIElement::uiElementCountForSearchPredicate):
+        * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
+        * WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl:
+        * WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp:
+        (WTR::AccessibilityUIElement::uiElementCountForSearchPredicate):
+        * WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm:
+        (WTR::searchPredicateParameterizedAttributeForSearchCriteria):
+        (WTR::AccessibilityUIElement::uiElementCountForSearchPredicate):
+        (WTR::AccessibilityUIElement::uiElementForSearchPredicate):
+
 2013-12-02  Dániel Bátyai  <Batyai.Daniel@stud.u-szeged.hu>
 
         Instead of a large 'if' block, each failure class should write it's own result in test_result_writer.py
index 66bd100..327b988 100644 (file)
@@ -202,32 +202,52 @@ static JSValueRef attributedStringRangeIsMisspelledCallback(JSContextRef context
     return JSValueMakeBoolean(context, toAXElement(thisObject)->attributedStringRangeIsMisspelled(location, length));
 }
 
-static JSValueRef uiElementForSearchPredicateCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+static JSValueRef uiElementCountForSearchPredicateCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 {
-    AccessibilityUIElement* startElement = 0;
+    AccessibilityUIElement* startElement = nullptr;
     bool isDirectionNext = true;
+    JSValueRef searchKey = nullptr;
+    JSRetainPtr<JSStringRef> searchText = nullptr;
     bool visibleOnly = false;
-    JSValueRef searchKey = 0;
-    JSStringRef searchText = 0;
     if (argumentCount == 5) {
-        JSObjectRef startElementObject = JSValueToObject(context, arguments[0], exception);
-        if (startElementObject)
-            startElement = toAXElement(startElementObject);
-        isDirectionNext = JSValueToBoolean(context, arguments[1]);      
+        if (JSValueIsObject(context, arguments[0]))
+            startElement = toAXElement(JSValueToObject(context, arguments[0], exception));
+        
+        isDirectionNext = JSValueToBoolean(context, arguments[1]);
         
         searchKey = arguments[2];
         
         if (JSValueIsString(context, arguments[3]))
-            searchText = JSValueToStringCopy(context, arguments[3], exception);
+            searchText.adopt(JSValueToStringCopy(context, arguments[3], exception));
         
         visibleOnly = JSValueToBoolean(context, arguments[4]);
     }
-    JSObjectRef resultObject = AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->uiElementForSearchPredicate(context, startElement, isDirectionNext, searchKey, searchText, visibleOnly));
+    
+    return JSValueMakeNumber(context, toAXElement(thisObject)->uiElementCountForSearchPredicate(context, startElement, isDirectionNext, searchKey, searchText.get(), visibleOnly));
+}
 
-    if (searchText)
-        JSStringRelease(searchText);
+static JSValueRef uiElementForSearchPredicateCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    AccessibilityUIElement* startElement = nullptr;
+    bool isDirectionNext = true;
+    JSValueRef searchKey = nullptr;
+    JSRetainPtr<JSStringRef> searchText = nullptr;
+    bool visibleOnly = false;
+    if (argumentCount == 5) {
+        if (JSValueIsObject(context, arguments[0]))
+            startElement = toAXElement(JSValueToObject(context, arguments[0], exception));
+        
+        isDirectionNext = JSValueToBoolean(context, arguments[1]);
+        
+        searchKey = arguments[2];
+        
+        if (JSValueIsString(context, arguments[3]))
+            searchText.adopt(JSValueToStringCopy(context, arguments[3], exception));
+        
+        visibleOnly = JSValueToBoolean(context, arguments[4]);
+    }
     
-    return resultObject;
+    return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->uiElementForSearchPredicate(context, startElement, isDirectionNext, searchKey, searchText.get(), visibleOnly));
 }
 
 static JSValueRef indexOfChildCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
@@ -1390,6 +1410,7 @@ JSClassRef AccessibilityUIElement::getJSClass()
         { "stringForRange", stringForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "attributedStringForRange", attributedStringForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "attributedStringRangeIsMisspelled", attributedStringRangeIsMisspelledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+        { "uiElementCountForSearchPredicate", uiElementCountForSearchPredicateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeReadOnly },
         { "uiElementForSearchPredicate", uiElementForSearchPredicateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "childAtIndex", childAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "linkedUIElementAtIndex", linkedUIElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
index 10e42fd..ab46f65 100644 (file)
@@ -203,6 +203,7 @@ public:
     JSStringRef stringForRange(unsigned location, unsigned length);
     JSStringRef attributedStringForRange(unsigned location, unsigned length);
     bool attributedStringRangeIsMisspelled(unsigned location, unsigned length);
+    unsigned uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly);
     AccessibilityUIElement uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly);
 #if PLATFORM(IOS)
     void elementsForRange(unsigned location, unsigned length, Vector<AccessibilityUIElement>& elements);
index 74563af..b8795ef 100644 (file)
@@ -1092,6 +1092,12 @@ bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location
     return false;
 }
 
+unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+{
+    // FIXME: implement
+    return 0;
+}
+
 AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
 {
     // FIXME: implement
index e66aa32..b135595 100644 (file)
@@ -797,6 +797,12 @@ void AccessibilityUIElement::removeSelection()
     // FIXME: implement
 }
 
+unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+{
+    // FIXME: implement
+    return 0;
+}
+
 AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
 {
     // FIXME: implement
index 09d1564..7fd0ca8 100644 (file)
@@ -195,6 +195,56 @@ static JSStringRef descriptionOfElements(Vector<AccessibilityUIElement>& element
     return [allElementString createJSStringRef];
 }
 
+static NSDictionary *searchPredicateParameterizedAttributeForSearchCriteria(JSContextRef context, AccessibilityUIElement *startElement, bool isDirectionNext, unsigned resultsLimit, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+{
+    NSMutableDictionary *parameterizedAttribute = [NSMutableDictionary dictionary];
+    
+    if (startElement && startElement->platformUIElement())
+        [parameterizedAttribute setObject:(id)startElement->platformUIElement() forKey:@"AXStartElement"];
+    
+    [parameterizedAttribute setObject:(isDirectionNext) ? @"AXDirectionNext" : @"AXDirectionPrevious" forKey:@"AXDirection"];
+    
+    [parameterizedAttribute setObject:@(resultsLimit) forKey:@"AXResultsLimit"];
+    
+    if (searchKey) {
+        id searchKeyParameter = nil;
+        if (JSValueIsString(context, searchKey)) {
+            JSRetainPtr<JSStringRef> searchKeyString(Adopt, JSValueToStringCopy(context, searchKey, nullptr));
+            if (searchKeyString)
+                searchKeyParameter = [NSString stringWithJSStringRef:searchKeyString.get()];
+        }
+        else if (JSValueIsObject(context, searchKey)) {
+            JSObjectRef searchKeyArray = JSValueToObject(context, searchKey, nullptr);
+            unsigned searchKeyArrayLength = 0;
+            
+            JSRetainPtr<JSStringRef> lengthPropertyString(Adopt, JSStringCreateWithUTF8CString("length"));
+            JSValueRef searchKeyArrayLengthValue = JSObjectGetProperty(context, searchKeyArray, lengthPropertyString.get(), nullptr);
+            if (searchKeyArrayLengthValue && JSValueIsNumber(context, searchKeyArrayLengthValue))
+                searchKeyArrayLength = static_cast<unsigned>(JSValueToNumber(context, searchKeyArrayLengthValue, nullptr));
+            
+            for (unsigned i = 0; i < searchKeyArrayLength; ++i) {
+                JSValueRef searchKeyValue = JSObjectGetPropertyAtIndex(context, searchKeyArray, i, nullptr);
+                JSStringRef searchKeyString = JSValueToStringCopy(context, searchKeyValue, nullptr);
+                if (searchKeyString) {
+                    if (!searchKeyParameter)
+                        searchKeyParameter = [NSMutableArray array];
+                    [searchKeyParameter addObject:[NSString stringWithJSStringRef:searchKeyString]];
+                    JSStringRelease(searchKeyString);
+                }
+            }
+        }
+        if (searchKeyParameter)
+            [parameterizedAttribute setObject:searchKeyParameter forKey:@"AXSearchKey"];
+    }
+    
+    if (searchText && JSStringGetLength(searchText))
+        [parameterizedAttribute setObject:[NSString stringWithJSStringRef:searchText] forKey:@"AXSearchText"];
+    
+    [parameterizedAttribute setObject:@(visibleOnly) forKey:@"AXVisibleOnly"];
+    
+    return parameterizedAttribute;
+}
+
 void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elementVector)
 {
     BEGIN_AX_OBJC_EXCEPTIONS
@@ -960,60 +1010,25 @@ bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location
     return false;
 }
 
-AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement *startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
 {
     BEGIN_AX_OBJC_EXCEPTIONS
-    NSMutableDictionary* parameter = [NSMutableDictionary dictionary];
-    [parameter setObject:(isDirectionNext) ? @"AXDirectionNext" : @"AXDirectionPrevious" forKey:@"AXDirection"];
-    if (visibleOnly)
-        [parameter setObject:[NSNumber numberWithBool:YES] forKey:@"AXVisibleOnly"];
-    [parameter setObject:[NSNumber numberWithInt:1] forKey:@"AXResultsLimit"];
-    if (startElement && startElement->platformUIElement())
-        [parameter setObject:(id)startElement->platformUIElement() forKey:@"AXStartElement"];
-    if (searchKey) {
-        if (JSValueIsString(context, searchKey)) {
-            NSString *searchKeyParameter = nil;
-            JSStringRef singleSearchKey = JSValueToStringCopy(context, searchKey, 0);
-            if (singleSearchKey) {
-                searchKeyParameter = [NSString stringWithJSStringRef:singleSearchKey];
-                JSStringRelease(singleSearchKey);
-                if (searchKeyParameter)
-                    [parameter setObject:searchKeyParameter forKey:@"AXSearchKey"];
-            }
-        }
-        else if (JSValueIsObject(context, searchKey)) {
-            NSMutableArray *searchKeyParameter = nil;
-            JSObjectRef array = const_cast<JSObjectRef>(searchKey);
-            unsigned arrayLength = 0;
-            JSRetainPtr<JSStringRef> arrayLengthString(Adopt, JSStringCreateWithUTF8CString("length"));
-            JSValueRef arrayLengthValue = JSObjectGetProperty(context, array, arrayLengthString.get(), 0);
-            if (arrayLengthValue && JSValueIsNumber(context, arrayLengthValue))
-                arrayLength = static_cast<unsigned>(JSValueToNumber(context, arrayLengthValue, 0));
-            
-            for (unsigned i = 0; i < arrayLength; ++i) {
-                JSValueRef exception = 0;
-                JSValueRef value = JSObjectGetPropertyAtIndex(context, array, i, &exception);
-                if (exception)
-                    break;
-                JSStringRef singleSearchKey = JSValueToStringCopy(context, value, &exception);
-                if (exception)
-                    break;
-                if (singleSearchKey) {
-                    if (!searchKeyParameter)
-                        searchKeyParameter = [NSMutableArray array];
-                    [searchKeyParameter addObject:[NSString stringWithJSStringRef:singleSearchKey]];
-                    JSStringRelease(singleSearchKey);
-                }
-            }
-            if (searchKeyParameter)
-                [parameter setObject:searchKeyParameter forKey:@"AXSearchKey"];
-        }
-    }
-    if (searchText && JSStringGetLength(searchText))
-        [parameter setObject:[NSString stringWithJSStringRef:searchText] forKey:@"AXSearchText"];
+    NSDictionary *parameterizedAttribute = searchPredicateParameterizedAttributeForSearchCriteria(context, startElement, isDirectionNext, UINT_MAX, searchKey, searchText, visibleOnly);
+    id value = [m_element accessibilityAttributeValue:@"AXUIElementCountForSearchPredicate" forParameter:parameterizedAttribute];
+    if ([value isKindOfClass:[NSNumber class]])
+        return [value unsignedIntValue];
+    END_AX_OBJC_EXCEPTIONS
     
-    id uiElement = [[m_element accessibilityAttributeValue:@"AXUIElementsForSearchPredicate" forParameter:parameter] lastObject];
-    return AccessibilityUIElement(uiElement);
+    return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement *startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+{
+    BEGIN_AX_OBJC_EXCEPTIONS
+    NSDictionary *parameterizedAttribute = searchPredicateParameterizedAttributeForSearchCriteria(context, startElement, isDirectionNext, 1, searchKey, searchText, visibleOnly);
+    id value = [m_element accessibilityAttributeValue:@"AXUIElementsForSearchPredicate" forParameter:parameterizedAttribute];
+    if ([value isKindOfClass:[NSArray class]])
+        return AccessibilityUIElement([value lastObject]);
     END_AX_OBJC_EXCEPTIONS
     
     return nullptr;
index 6a651eb..eac59e0 100644 (file)
@@ -592,6 +592,11 @@ bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned, unsigne
     return false;
 }
 
+unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+{
+    return 0;
+}
+
 AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
 {
     return 0;
index e4d6e22..2bd9ecf 100644 (file)
@@ -162,6 +162,7 @@ void AccessibilityUIElement::setSelectedTextRange(unsigned, unsigned) { }
 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned, unsigned) { return 0; }
 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned, unsigned) { return 0; }
 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned, unsigned) { return false; }
+unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement*, bool, JSValueRef, JSStringRef, bool) { return 0; }
 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement*, bool, JSValueRef, JSStringRef, bool) { return 0; }
 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned, unsigned) { return 0; }
 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const { return 0; }
index 237b6bb..90f5cb1 100644 (file)
@@ -199,6 +199,7 @@ public:
     JSRetainPtr<JSStringRef> stringForRange(unsigned location, unsigned length);
     JSRetainPtr<JSStringRef> attributedStringForRange(unsigned location, unsigned length);
     bool attributedStringRangeIsMisspelled(unsigned location, unsigned length);
+    unsigned uiElementCountForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly);
     PassRefPtr<AccessibilityUIElement> uiElementForSearchPredicate(JSContextRef, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly);
     
     // Table-specific
index 0837a7f..7cde586 100644 (file)
@@ -145,6 +145,7 @@ interface AccessibilityUIElement {
     DOMString stringForRange(unsigned long location, unsigned long length);
     DOMString attributedStringForRange(unsigned long location, unsigned long length);
     boolean attributedStringRangeIsMisspelled(unsigned long location, unsigned long length);
+    [PassContext] unsigned int uiElementCountForSearchPredicate(AccessibilityUIElement startElement, boolean isDirectionNext, object searchKey, DOMString searchText, boolean visibleOnly);
     [PassContext] AccessibilityUIElement uiElementForSearchPredicate(AccessibilityUIElement startElement, boolean isDirectionNext, object searchKey, DOMString searchText, boolean visibleOnly);
     void setSelectedTextRange(unsigned long location, unsigned long length);
 
index 59bceec..ffe9c0e 100644 (file)
@@ -1157,6 +1157,12 @@ bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location
     return false;
 }
 
+unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+{
+    // FIXME: implement
+    return 0;
+}
+
 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
 {
     // FIXME: implement
index fd94d32..24abd8f 100644 (file)
@@ -210,6 +210,56 @@ static JSStringRef descriptionOfElements(Vector<RefPtr<AccessibilityUIElement> >
     return [allElementString createJSStringRef];
 }
 
+static NSDictionary *searchPredicateParameterizedAttributeForSearchCriteria(JSContextRef context, AccessibilityUIElement *startElement, bool isDirectionNext, unsigned resultsLimit, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+{
+    NSMutableDictionary *parameterizedAttribute = [NSMutableDictionary dictionary];
+    
+    if (startElement && startElement->platformUIElement())
+        [parameterizedAttribute setObject:(id)startElement->platformUIElement() forKey:@"AXStartElement"];
+    
+    [parameterizedAttribute setObject:(isDirectionNext) ? @"AXDirectionNext" : @"AXDirectionPrevious" forKey:@"AXDirection"];
+    
+    [parameterizedAttribute setObject:@(resultsLimit) forKey:@"AXResultsLimit"];
+    
+    if (searchKey) {
+        id searchKeyParameter = nil;
+        if (JSValueIsString(context, searchKey)) {
+            JSRetainPtr<JSStringRef> searchKeyString(Adopt, JSValueToStringCopy(context, searchKey, nullptr));
+            if (searchKeyString)
+                searchKeyParameter = [NSString stringWithJSStringRef:searchKeyString.get()];
+        }
+        else if (JSValueIsObject(context, searchKey)) {
+            JSObjectRef searchKeyArray = JSValueToObject(context, searchKey, nullptr);
+            unsigned searchKeyArrayLength = 0;
+            
+            JSRetainPtr<JSStringRef> lengthPropertyString(Adopt, JSStringCreateWithUTF8CString("length"));
+            JSValueRef searchKeyArrayLengthValue = JSObjectGetProperty(context, searchKeyArray, lengthPropertyString.get(), nullptr);
+            if (searchKeyArrayLengthValue && JSValueIsNumber(context, searchKeyArrayLengthValue))
+                searchKeyArrayLength = static_cast<unsigned>(JSValueToNumber(context, searchKeyArrayLengthValue, nullptr));
+            
+            for (unsigned i = 0; i < searchKeyArrayLength; ++i) {
+                JSValueRef searchKeyValue = JSObjectGetPropertyAtIndex(context, searchKeyArray, i, nullptr);
+                JSStringRef searchKeyString = JSValueToStringCopy(context, searchKeyValue, nullptr);
+                if (searchKeyString) {
+                    if (!searchKeyParameter)
+                        searchKeyParameter = [NSMutableArray array];
+                    [searchKeyParameter addObject:[NSString stringWithJSStringRef:searchKeyString]];
+                    JSStringRelease(searchKeyString);
+                }
+            }
+        }
+        if (searchKeyParameter)
+            [parameterizedAttribute setObject:searchKeyParameter forKey:@"AXSearchKey"];
+    }
+    
+    if (searchText && JSStringGetLength(searchText))
+        [parameterizedAttribute setObject:[NSString stringWithJSStringRef:searchText] forKey:@"AXSearchText"];
+    
+    [parameterizedAttribute setObject:@(visibleOnly) forKey:@"AXVisibleOnly"];
+    
+    return parameterizedAttribute;
+}
+
 void AccessibilityUIElement::getLinkedUIElements(Vector<RefPtr<AccessibilityUIElement> >& elementVector)
 {
     BEGIN_AX_OBJC_EXCEPTIONS
@@ -995,60 +1045,25 @@ bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location
     return false;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement *startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
 {
     BEGIN_AX_OBJC_EXCEPTIONS
-    NSMutableDictionary* parameter = [NSMutableDictionary dictionary];
-    [parameter setObject:(isDirectionNext) ? @"AXDirectionNext" : @"AXDirectionPrevious" forKey:@"AXDirection"];
-    if (visibleOnly)
-        [parameter setObject:[NSNumber numberWithBool:YES] forKey:@"AXVisibleOnly"];
-    [parameter setObject:[NSNumber numberWithInt:1] forKey:@"AXResultsLimit"];
-    if (startElement && startElement->platformUIElement())
-        [parameter setObject:(id)startElement->platformUIElement() forKey:@"AXStartElement"];
-    if (searchKey) {
-        if (JSValueIsString(context, searchKey)) {
-            NSString *searchKeyParameter = nil;
-            JSStringRef singleSearchKey = JSValueToStringCopy(context, searchKey, 0);
-            if (singleSearchKey) {
-                searchKeyParameter = [NSString stringWithJSStringRef:singleSearchKey];
-                JSStringRelease(singleSearchKey);
-                if (searchKeyParameter)
-                    [parameter setObject:searchKeyParameter forKey:@"AXSearchKey"];
-            }
-        }
-        else if (JSValueIsObject(context, searchKey)) {
-            NSMutableArray *searchKeyParameter = nil;
-            JSObjectRef array = const_cast<JSObjectRef>(searchKey);
-            unsigned arrayLength = 0;
-            JSRetainPtr<JSStringRef> arrayLengthString(Adopt, JSStringCreateWithUTF8CString("length"));
-            JSValueRef arrayLengthValue = JSObjectGetProperty(context, array, arrayLengthString.get(), 0);
-            if (arrayLengthValue && JSValueIsNumber(context, arrayLengthValue))
-                arrayLength = static_cast<unsigned>(JSValueToNumber(context, arrayLengthValue, 0));
-            
-            for (unsigned i = 0; i < arrayLength; ++i) {
-                JSValueRef exception = 0;
-                JSValueRef value = JSObjectGetPropertyAtIndex(context, array, i, &exception);
-                if (exception)
-                    break;
-                JSStringRef singleSearchKey = JSValueToStringCopy(context, value, &exception);
-                if (exception)
-                    break;
-                if (singleSearchKey) {
-                    if (!searchKeyParameter)
-                        searchKeyParameter = [NSMutableArray array];
-                    [searchKeyParameter addObject:[NSString stringWithJSStringRef:singleSearchKey]];
-                    JSStringRelease(singleSearchKey);
-                }
-            }
-            if (searchKeyParameter)
-                [parameter setObject:searchKeyParameter forKey:@"AXSearchKey"];
-        }
-    }
-    if (searchText && JSStringGetLength(searchText))
-        [parameter setObject:[NSString stringWithJSStringRef:searchText] forKey:@"AXSearchText"];
+    NSDictionary *parameterizedAttribute = searchPredicateParameterizedAttributeForSearchCriteria(context, startElement, isDirectionNext, UINT_MAX, searchKey, searchText, visibleOnly);
+    id value = [m_element accessibilityAttributeValue:@"AXUIElementCountForSearchPredicate" forParameter:parameterizedAttribute];
+    if ([value isKindOfClass:[NSNumber class]])
+        return [value unsignedIntValue];
+    END_AX_OBJC_EXCEPTIONS
     
-    id uiElement = [[m_element accessibilityAttributeValue:@"AXUIElementsForSearchPredicate" forParameter:parameter] lastObject];
-    return AccessibilityUIElement::create(uiElement);
+    return 0;
+}
+
+PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement *startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+{
+    BEGIN_AX_OBJC_EXCEPTIONS
+    NSDictionary *parameterizedAttribute = searchPredicateParameterizedAttributeForSearchCriteria(context, startElement, isDirectionNext, 1, searchKey, searchText, visibleOnly);
+    id value = [m_element accessibilityAttributeValue:@"AXUIElementsForSearchPredicate" forParameter:parameterizedAttribute];
+    if ([value isKindOfClass:[NSArray class]])
+        return AccessibilityUIElement::create([value lastObject]);
     END_AX_OBJC_EXCEPTIONS
     
     return nullptr;