Bug 179068 - AX: search predicate returns containing group for plain text instead...
authord_russell@apple.com <d_russell@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Nov 2017 23:35:34 +0000 (23:35 +0000)
committerd_russell@apple.com <d_russell@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Nov 2017 23:35:34 +0000 (23:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179068

Reviewed by Darin Adler

Implement a check in AccessibilityRenderObject::hasPlainText(), AccessibilityObject::canHavePlainText(), to confirm the element is capable of providing text.

Source/WebCore:

Tests: accessibility/mac/search-predicate-plaintext.html
       accessibility/mac/search-predicate-visible-button.html
       accessibility/mac/search-predicate-visited-links.html

* accessibility/AccessibilityNodeObject.cpp:
(WebCore::AccessibilityNodeObject::text const):
(WebCore::AccessibilityNodeObject::stringValue const):
* accessibility/AccessibilityObject.h:
(WebCore::AccessibilityObject::isARIAStaticText const):
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::stringValue const):
(WebCore::AccessibilityRenderObject::canHavePlainText const):
(WebCore::AccessibilityRenderObject::hasPlainText const):
* accessibility/AccessibilityRenderObject.h:

LayoutTests:

* accessibility/mac/search-predicate-expected.txt:
* accessibility/mac/search-predicate-plaintext-expected.txt: Added.
* accessibility/mac/search-predicate-plaintext.html: Added.
* accessibility/mac/search-predicate-visible-button-expected.txt: Added.
* accessibility/mac/search-predicate-visible-button.html: Added.
* accessibility/mac/search-predicate-visited-links-expected.txt: Added.
* accessibility/mac/search-predicate-visited-links.html: Added.
* accessibility/mac/search-predicate.html:
* platform/mac-wk2/TestExpectations:

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/accessibility/mac/search-predicate-expected.txt
LayoutTests/accessibility/mac/search-predicate-plaintext-expected.txt [new file with mode: 0644]
LayoutTests/accessibility/mac/search-predicate-plaintext.html [new file with mode: 0644]
LayoutTests/accessibility/mac/search-predicate-visible-button-expected.txt [new file with mode: 0644]
LayoutTests/accessibility/mac/search-predicate-visible-button.html [new file with mode: 0644]
LayoutTests/accessibility/mac/search-predicate-visited-links-expected.txt [new file with mode: 0644]
LayoutTests/accessibility/mac/search-predicate-visited-links.html [new file with mode: 0644]
LayoutTests/accessibility/mac/search-predicate.html
LayoutTests/platform/mac-wk2/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AccessibilityNodeObject.cpp
Source/WebCore/accessibility/AccessibilityObject.h
Source/WebCore/accessibility/AccessibilityRenderObject.cpp
Source/WebCore/accessibility/AccessibilityRenderObject.h

index b5869e8..ed243a2 100644 (file)
@@ -1,3 +1,22 @@
+2017-11-09  Doug Russell  <d_russell@apple.com>
+
+        Bug 179068 - AX: search predicate returns containing group for plain text instead of text element
+        https://bugs.webkit.org/show_bug.cgi?id=179068
+
+        Reviewed by Darin Adler
+
+        Implement a check in AccessibilityRenderObject::hasPlainText(), AccessibilityObject::canHavePlainText(), to confirm the element is capable of providing text.
+
+        * accessibility/mac/search-predicate-expected.txt:
+        * accessibility/mac/search-predicate-plaintext-expected.txt: Added.
+        * accessibility/mac/search-predicate-plaintext.html: Added.
+        * accessibility/mac/search-predicate-visible-button-expected.txt: Added.
+        * accessibility/mac/search-predicate-visible-button.html: Added.
+        * accessibility/mac/search-predicate-visited-links-expected.txt: Added.
+        * accessibility/mac/search-predicate-visited-links.html: Added.
+        * accessibility/mac/search-predicate.html:
+        * platform/mac-wk2/TestExpectations:
+
 2017-11-09  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Inserting an image, selecting, underlining, and then deleting leaves the typing style with both "-webkit-text-decorations-in-effect" and "text-decoration"
index 5996b41..17b60f2 100644 (file)
@@ -116,8 +116,6 @@ PASS resultElement.role is 'AXRole: AXGroup'
 PASS resultElement.childAtIndex(0).stringValue is 'AXValue: sans-serif black bold text with underline'
 PASS resultElement.boolAttributeValue('AXVisited') is false
 PASS resultElement.childAtIndex(0).stringValue is 'AXValue: link'
-PASS resultElement.boolAttributeValue('AXVisited') is true
-PASS resultElement.childAtIndex(0).stringValue is 'AXValue: link'
 PASS resultElement.role is 'AXRole: AXStaticText'
 PASS resultElement.stringValue is 'AXValue: sans-serif black bold text with underline'
 PASS resultElement.role is 'AXRole: AXHeading'
@@ -146,9 +144,6 @@ PASS resultElement.role is 'AXRole: AXButton'
 PASS resultElement.title is 'AXTitle: test button 3'
 PASS resultElement.role is 'AXRole: AXButton'
 PASS resultElement.title is 'AXTitle: test button 2'
-PASS resultElement.role is 'AXRole: AXButton'
-PASS resultElement.title is 'AXTitle: Submit'
-PASS resultElement is undefined.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/accessibility/mac/search-predicate-plaintext-expected.txt b/LayoutTests/accessibility/mac/search-predicate-plaintext-expected.txt
new file mode 100644 (file)
index 0000000..bcc5b4a
--- /dev/null
@@ -0,0 +1,23 @@
+first blockquote level 1
+second blockquote level 1
+plain text paragraph
+
+sans-serif black bold text with underline
+
+serif blue italic text
+
+This tests the ability to search for accessible elements by key or text.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS resultElement.role is 'AXRole: AXStaticText'
+PASS resultElement.stringValue is 'AXValue: first blockquote level 1'
+PASS resultElement.role is 'AXRole: AXStaticText'
+PASS resultElement.stringValue is 'AXValue: second blockquote level 1'
+PASS resultElement.role is 'AXRole: AXStaticText'
+PASS resultElement.stringValue is 'AXValue: plain text paragraph'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/accessibility/mac/search-predicate-plaintext.html b/LayoutTests/accessibility/mac/search-predicate-plaintext.html
new file mode 100644 (file)
index 0000000..5ec1d48
--- /dev/null
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<blockquote>first blockquote level 1</blockquote>
+<blockquote>second blockquote level 1</blockquote>
+<p>plain text paragraph</p>
+<p style="color:black; font-family:sans-serif; font-weight:bold; text-decoration:underline;">sans-serif black bold text with underline</p>
+<p style="color:blue; font-family:serif; font-style:italic;">serif blue italic text</p>
+
+    
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+    description("This tests the ability to search for accessible elements by key or text.");
+    
+    if (window.accessibilityController) {
+        document.getElementById("body").focus();
+        var containerElement = accessibilityController.focusedElement;
+        var startElement;
+        var resultElement;
+        
+        // Plain text.
+        startElement = containerElement.childAtIndex(0);
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXPlainTextSearchKey", "", false);
+        shouldBe("resultElement.role", "'AXRole: AXStaticText'");
+        shouldBe("resultElement.stringValue", "'AXValue: first blockquote level 1'");
+
+        startElement = resultElement;
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXPlainTextSearchKey", "", false);
+        shouldBe("resultElement.role", "'AXRole: AXStaticText'");
+        shouldBe("resultElement.stringValue", "'AXValue: second blockquote level 1'");
+
+        startElement = resultElement;
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXPlainTextSearchKey", "", false);
+        shouldBe("resultElement.role", "'AXRole: AXStaticText'");
+        shouldBe("resultElement.stringValue", "'AXValue: plain text paragraph'");
+    }
+    
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/accessibility/mac/search-predicate-visible-button-expected.txt b/LayoutTests/accessibility/mac/search-predicate-visible-button-expected.txt
new file mode 100644 (file)
index 0000000..867ae5e
--- /dev/null
@@ -0,0 +1,62 @@
+first blockquote level 1
+second blockquote level 1
+sans-serif black bold text with underline
+
+serif blue italic text
+
+
+ checkbox
+
+
+first heading level 1
+
+second heading level 1
+
+heading level 2
+
+heading level 3
+
+heading level 4
+
+heading level 5
+
+heading level 6
+
+landmark
+
+link
+list item
+live region
+
+radio button
+first table heading level 1
+first table body level 1
+second table heading level 1
+second table body level 1
+tree item
+isVisible test start
+
+test button 1
+test test test test 
+test test test test 
+test test test test 
+test test test test 
+test test test test 
+test test test test 
+test test test test 
+test test test test 
+test test test test 
+test button 2
+test button 3
+This tests the ability to search for accessible elements by key or text.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS resultElement.role is 'AXRole: AXButton'
+PASS resultElement.title is 'AXTitle: Submit'
+PASS resultElement is undefined.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/accessibility/mac/search-predicate-visible-button.html b/LayoutTests/accessibility/mac/search-predicate-visible-button.html
new file mode 100644 (file)
index 0000000..15a26c2
--- /dev/null
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<blockquote>first blockquote level 1</blockquote>
+<blockquote>second blockquote level 1</blockquote>
+<p style="color:black; font-family:sans-serif; font-weight:bold; text-decoration:underline;">sans-serif black bold text with underline</p>
+<p style="color:blue; font-family:serif; font-style:italic;">serif blue italic text</p>
+<form>
+<input type="text" /><br />
+<input type="checkbox" value="Checkbox" /> checkbox<br />
+<input type="submit" value="Submit" />
+</form>
+<img id="image" src="resources/cake.png" alt="Test">
+<h1>first heading level 1</h1>
+<h1>second heading level 1</h1>
+<h2>heading level 2</h2>
+<h3>heading level 3</h3>
+<h4>heading level 4</h4>
+<h5>heading level 5</h5>
+<h6>heading level 6</h6>
+<p id="banner" role="banner">landmark</p>
+<a href="#image">link</a>
+<ol><li>list item</li></ol>
+<p aria-live="polite">live region</p>
+<ul role="radiogroup"><li role="radio">radio button</li></ul>
+<table>
+<thead><tr><td>first table heading level 1</td></tr></thead>
+<tbody><tr><td>first table body level 1</td></tr></tbody>
+</table>
+<table>
+<thead><tr><td>second table heading level 1</td></tr></thead>
+<tbody><tr><td>second table body level 1</td></tr></tbody>
+</table>
+<ul role="tree"><li role="treeitem">tree item</li></ul>
+
+<h1>isVisible test start</h1>
+<div id="group" style="overflow: scroll; width:100px; height:100px;">
+    <button id="button">test button 1</button><BR>
+    test test test test <br>
+    test test test test <br>
+    test test test test <br>
+    test test test test <br>
+    test test test test <br>
+    test test test test <br>
+    test test test test <br>
+    test test test test <br>
+    test test test test <br>
+    <button id="button">test button 2</button>
+</div>
+<button id="button">test button 3</button>
+
+    
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+    description("This tests the ability to search for accessible elements by key or text.");
+
+    if (window.accessibilityController) {
+        document.getElementById("body").focus();
+        var containerElement = accessibilityController.focusedElement;
+        var startElement;
+        var resultElement;
+
+        // lets scroll to the top of the page and ensure that the submit button is visible
+        startElement = accessibilityController.focusedElement.childAtIndex(0);
+        startElement.scrollToMakeVisible();
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", true);
+        shouldBe("resultElement.role", "'AXRole: AXButton'");
+        shouldBe("resultElement.title", "'AXTitle: Submit'");
+
+        // there should be no more visible buttons
+        resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", true);
+        shouldBeUndefined("resultElement");
+    }
+    
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/accessibility/mac/search-predicate-visited-links-expected.txt b/LayoutTests/accessibility/mac/search-predicate-visited-links-expected.txt
new file mode 100644 (file)
index 0000000..d9b1aa5
--- /dev/null
@@ -0,0 +1,14 @@
+link
+This tests the ability to search for accessible elements by key or text.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS resultElement.boolAttributeValue('AXVisited') is false
+PASS resultElement.childAtIndex(0).stringValue is 'AXValue: link'
+PASS resultElement.boolAttributeValue('AXVisited') is true
+PASS resultElement.childAtIndex(0).stringValue is 'AXValue: link'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/accessibility/mac/search-predicate-visited-links.html b/LayoutTests/accessibility/mac/search-predicate-visited-links.html
new file mode 100644 (file)
index 0000000..ce2010b
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+    <script src="../../resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+<a href="#image">link</a>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+    description("This tests the ability to search for accessible elements by key or text.");
+
+    if (window.accessibilityController) {
+        jsTestIsAsync = true;
+        window.testRunner.keepWebHistory();
+
+        document.getElementById("body").focus();
+        var containerElement = accessibilityController.focusedElement;
+        var startElement;
+        var resultElement;
+
+        // Unvisited link.
+        startElement = accessibilityController.focusedElement.childAtIndex(0);
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXUnvisitedLinkSearchKey", "", false);
+        shouldBe("resultElement.boolAttributeValue('AXVisited')", "false");
+        shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: link'");
+
+        // Visited link.
+        accessibilityController.focusedElement.childAtIndex(0).childAtIndex(0).press();
+        setTimeout(function() {
+
+            startElement = accessibilityController.focusedElement.childAtIndex(0);
+            resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXVisitedLinkSearchKey", "", false);
+            shouldBe("resultElement.boolAttributeValue('AXVisited')", "true");
+            shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: link'");
+
+            finishJSTest();
+        }, 50);
+    }
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index 250ff55..9e2c922 100644 (file)
@@ -61,9 +61,6 @@
     description("This tests the ability to search for accessible elements by key or text.");
     
     if (window.accessibilityController) {
-        jsTestIsAsync = true;
-        window.testRunner.keepWebHistory();
-        
         document.getElementById("body").focus();
         var containerElement = accessibilityController.focusedElement;
         var startElement;
         resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXAnyTypeSearchKey", "", false);
         shouldBe("resultElement.role", "'AXRole: AXStaticText'");
         shouldBe("resultElement.stringValue", "'AXValue: first blockquote level 1'");
-        
+
         // Same level blockquote.
         startElement = accessibilityController.focusedElement.childAtIndex(0);
         resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXBlockquoteSameLevelSearchKey", "", false);
         shouldBe("resultElement.role", "'AXRole: AXGroup'");
         shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: second blockquote level 1'");
-        
+
         // Blockquote.
         startElement = accessibilityController.focusedElement.childAtIndex(0);
         resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXBlockquoteSearchKey", "", false);
         shouldBe("resultElement.role", "'AXRole: AXGroup'");
         shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: second blockquote level 1'");
-        
+
         // Bold font.
         startElement = accessibilityController.focusedElement.childAtIndex(0);
         resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXBoldFontSearchKey", "", false);
         resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXUnvisitedLinkSearchKey", "", false);
         shouldBe("resultElement.boolAttributeValue('AXVisited')", "false");
         shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: link'");
-        
-        // Visited link.
-        accessibilityController.focusedElement.childAtIndex(14).childAtIndex(0).press();
-        setTimeout(function() {
-            
-            startElement = accessibilityController.focusedElement.childAtIndex(0);
-            resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXVisitedLinkSearchKey", "", false);
-            shouldBe("resultElement.boolAttributeValue('AXVisited')", "true");
-            shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: link'");
-        
-            // Previous text search.
-            startElement = accessibilityController.focusedElement.childAtIndex(10);
-            resultElement = containerElement.uiElementForSearchPredicate(startElement, false, "", "sans-serif black bold text with underline", false);
-            shouldBe("resultElement.role", "'AXRole: AXStaticText'");
-            shouldBe("resultElement.stringValue", "'AXValue: sans-serif black bold text with underline'");
-        
-            // Execute a search for the next heading level 2 or the next link.
-            startElement = accessibilityController.focusedElement.childAtIndex(0);
-            resultElement = containerElement.uiElementForSearchPredicate(startElement, true, ["AXHeadingLevel2SearchKey", "AXLinkSearchKey"], "", false);
-            shouldBe("resultElement.role", "'AXRole: AXHeading'");
-            shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: heading level 2'");
-        
-            // After finding the heading, execute the search again and we should find the link.
-            resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, ["AXHeadingLevel2SearchKey", "AXLinkSearchKey"], "", false);
-            shouldBe("resultElement.role", "'AXRole: AXLink'");
-            shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: link'");
-
-            // From the link, execute the search in reverse and we should land back on the heading.
-            resultElement = containerElement.uiElementForSearchPredicate(resultElement, false, ["AXHeadingLevel2SearchKey", "AXLinkSearchKey"], "", false);
-            shouldBe("resultElement.role", "'AXRole: AXHeading'");
-            shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: heading level 2'");
-               
-            // Now, we need to test isVisible. Save off the first object
-            startElement = accessibilityController.focusedElement.childAtIndex(0);
-        
-            // Scroll all the way to the bottom of the content
-            resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "", "test button 3", false);
-            shouldBe("resultElement.role", "'AXRole: AXButton'");
-            shouldBe("resultElement.title", "'AXTitle: test button 3'");
-            resultElement.scrollToMakeVisible();
-        
-            // find the start of the isVisible test section
-            resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "", "isVisible test start", false);
-            shouldBe("resultElement.role", "'AXRole: AXHeading'");
-            shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: isVisible test start'");       
-        
-            // save away the "isVisible test start" heading as the start element
-            startElement = resultElement;
-        
-            // If we don't care about visible only, then we should easily find 3 buttons
-            resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", false);
-            shouldBe("resultElement.role", "'AXRole: AXButton'");
-            shouldBe("resultElement.title", "'AXTitle: test button 1'");
-        
-            resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", false);
-            shouldBe("resultElement.role", "'AXRole: AXButton'");
-            shouldBe("resultElement.title", "'AXTitle: test button 2'");
-        
-            // save away testButton2 so we can make it visible later
-            testButton2 = resultElement;
 
-            resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", false);
-            shouldBe("resultElement.role", "'AXRole: AXButton'");
-            shouldBe("resultElement.title", "'AXTitle: test button 3'");
+        // Previous text search.
+        startElement = accessibilityController.focusedElement.childAtIndex(10);
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, false, "", "sans-serif black bold text with underline", false);
+        shouldBe("resultElement.role", "'AXRole: AXStaticText'");
+        shouldBe("resultElement.stringValue", "'AXValue: sans-serif black bold text with underline'");
+        
+        // Execute a search for the next heading level 2 or the next link.
+        startElement = accessibilityController.focusedElement.childAtIndex(0);
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, true, ["AXHeadingLevel2SearchKey", "AXLinkSearchKey"], "", false);
+        shouldBe("resultElement.role", "'AXRole: AXHeading'");
+        shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: heading level 2'");
+        
+        // After finding the heading, execute the search again and we should find the link.
+        resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, ["AXHeadingLevel2SearchKey", "AXLinkSearchKey"], "", false);
+        shouldBe("resultElement.role", "'AXRole: AXLink'");
+        shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: link'");
 
-            // if we care about visible only, then we should not find "test button 2"
-            resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", true);
-            shouldBe("resultElement.role", "'AXRole: AXButton'");
-            shouldBe("resultElement.title", "'AXTitle: test button 1'");
+        // From the link, execute the search in reverse and we should land back on the heading.
+        resultElement = containerElement.uiElementForSearchPredicate(resultElement, false, ["AXHeadingLevel2SearchKey", "AXLinkSearchKey"], "", false);
+        shouldBe("resultElement.role", "'AXRole: AXHeading'");
+        shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: heading level 2'");
+           
+        // Now, we need to test isVisible. Save off the first object
+        startElement = accessibilityController.focusedElement.childAtIndex(0);
+        
+        // Scroll all the way to the bottom of the content
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "", "test button 3", false);
+        shouldBe("resultElement.role", "'AXRole: AXButton'");
+        shouldBe("resultElement.title", "'AXTitle: test button 3'");
+        resultElement.scrollToMakeVisible();
+        
+        // find the start of the isVisible test section
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "", "isVisible test start", false);
+        shouldBe("resultElement.role", "'AXRole: AXHeading'");
+        shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: isVisible test start'");       
         
-            resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", true);
-            shouldBe("resultElement.role", "'AXRole: AXButton'");
-            shouldBe("resultElement.title", "'AXTitle: test button 3'");
+        // save away the "isVisible test start" heading as the start element
+        startElement = resultElement;
+        
+        // If we don't care about visible only, then we should easily find 3 buttons
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", false);
+        shouldBe("resultElement.role", "'AXRole: AXButton'");
+        shouldBe("resultElement.title", "'AXTitle: test button 1'");
         
-            // now, scroll to the second button, and confirm that we don't see the first button
-            testButton2.scrollToMakeVisible();
+        resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", false);
+        shouldBe("resultElement.role", "'AXRole: AXButton'");
+        shouldBe("resultElement.title", "'AXTitle: test button 2'");
+        
+        // save away testButton2 so we can make it visible later
+        testButton2 = resultElement;
 
-            resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", true);
-            shouldBe("resultElement.role", "'AXRole: AXButton'");
-            shouldBe("resultElement.title", "'AXTitle: test button 2'");
-        
-            resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", true);
-            shouldBe("resultElement.role", "'AXRole: AXButton'");
-            shouldBe("resultElement.title", "'AXTitle: test button 3'");
-        
-            // Now since the page is scrolled to the bottom, the first visible button should be #2
-            startElement = accessibilityController.focusedElement.childAtIndex(0);
-            resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", true);
-            shouldBe("resultElement.role", "'AXRole: AXButton'");
-            shouldBe("resultElement.title", "'AXTitle: test button 2'");
-        
-            // lets scroll to the top of the page and ensure that the submit button is visible
-            startElement.scrollToMakeVisible();
-            resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", true);
-            shouldBe("resultElement.role", "'AXRole: AXButton'");
-            shouldBe("resultElement.title", "'AXTitle: Submit'");
-        
-            // there should be no more visible buttons
-            resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", true);
-            shouldBeUndefined("resultElement");
-        
-            finishJSTest();
-        }, 50);
+        resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", false);
+        shouldBe("resultElement.role", "'AXRole: AXButton'");
+        shouldBe("resultElement.title", "'AXTitle: test button 3'");
+
+        // if we care about visible only, then we should not find "test button 2"
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", true);
+        shouldBe("resultElement.role", "'AXRole: AXButton'");
+        shouldBe("resultElement.title", "'AXTitle: test button 1'");
+
+        resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", true);
+        shouldBe("resultElement.role", "'AXRole: AXButton'");
+        shouldBe("resultElement.title", "'AXTitle: test button 3'");
+
+        // now, scroll to the second button, and confirm that we don't see the first button
+        testButton2.scrollToMakeVisible();
+
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", true);
+        shouldBe("resultElement.role", "'AXRole: AXButton'");
+        shouldBe("resultElement.title", "'AXTitle: test button 2'");
+
+        resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", true);
+        shouldBe("resultElement.role", "'AXRole: AXButton'");
+        shouldBe("resultElement.title", "'AXTitle: test button 3'");
+
+        // Now since the page is scrolled to the bottom, the first visible button should be #2
+        startElement = accessibilityController.focusedElement.childAtIndex(0);
+        resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", true);
+        shouldBe("resultElement.role", "'AXRole: AXButton'");
+        shouldBe("resultElement.title", "'AXTitle: test button 2'");
     }
     
 </script>
index 8df4968..9606cea 100644 (file)
@@ -299,6 +299,7 @@ webkit.org/b/124476 platform/mac-wk2/plugins/slow/asynchronous-plugin-initializa
 
 # uiElementForSearchPredicate() is not returning an undefined object when the search returns no results
 webkit.org/b/125996 accessibility/mac/search-when-element-starts-in-table.html [ Failure ]
+webkit.org/b/125996 accessibility/mac/search-predicate-visible-button.html [ Failure ]
 
 webkit.org/b/162999 accessibility/mac/wk1-set-selected-text-marker-range-input-element.html [ Skip ]
 
@@ -464,7 +465,7 @@ editing/mac/selection/25228.html
 
 # WebKitTestRunner needs testRunner.setCallCloseOnWebViews
 # http://webkit.org/b/46714
-accessibility/mac/search-predicate.html
+accessibility/mac/search-predicate-visited-links.html
 
 # AX tests that require hit testing do not work in WK2.
 webkit.org/b/71298 accessibility/mac/html-slider-indicator.html
index dcf634a..abba85d 100644 (file)
@@ -1,3 +1,27 @@
+2017-11-09  Doug Russell  <d_russell@apple.com>
+
+        Bug 179068 - AX: search predicate returns containing group for plain text instead of text element
+        https://bugs.webkit.org/show_bug.cgi?id=179068
+
+        Reviewed by Darin Adler
+
+        Implement a check in AccessibilityRenderObject::hasPlainText(), AccessibilityObject::canHavePlainText(), to confirm the element is capable of providing text.
+
+        Tests: accessibility/mac/search-predicate-plaintext.html
+               accessibility/mac/search-predicate-visible-button.html
+               accessibility/mac/search-predicate-visited-links.html
+
+        * accessibility/AccessibilityNodeObject.cpp:
+        (WebCore::AccessibilityNodeObject::text const):
+        (WebCore::AccessibilityNodeObject::stringValue const):
+        * accessibility/AccessibilityObject.h:
+        (WebCore::AccessibilityObject::isARIAStaticText const):
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::AccessibilityRenderObject::stringValue const):
+        (WebCore::AccessibilityRenderObject::canHavePlainText const):
+        (WebCore::AccessibilityRenderObject::hasPlainText const):
+        * accessibility/AccessibilityRenderObject.h:
+
 2017-11-09  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Inserting an image, selecting, underlining, and then deleting leaves the typing style with both "-webkit-text-decorations-in-effect" and "text-decoration"
index 7883975..ffc6e3c 100644 (file)
@@ -1834,7 +1834,7 @@ String AccessibilityNodeObject::title() const
 String AccessibilityNodeObject::text() const
 {
     // If this is a user defined static text, use the accessible name computation.                                      
-    if (ariaRoleAttribute() == AccessibilityRole::StaticText) {
+    if (isARIAStaticText()) {
         Vector<AccessibilityText> textOrder;
         alternativeText(textOrder);
         if (textOrder.size() > 0 && textOrder[0].text.length())
@@ -1863,7 +1863,7 @@ String AccessibilityNodeObject::stringValue() const
     if (!node)
         return String();
 
-    if (ariaRoleAttribute() == AccessibilityRole::StaticText) {
+    if (isARIAStaticText()) {
         String staticText = text();
         if (!staticText.length())
             staticText = textUnderElement();
index 5258600..af52fc5 100644 (file)
@@ -773,6 +773,7 @@ public:
     virtual String helpText() const { return String(); }
 
     // Methods for determining accessibility text.
+    bool isARIAStaticText() const { return ariaRoleAttribute() == AccessibilityRole::StaticText; }
     virtual String stringValue() const { return String(); }
     virtual String textUnderElement(AccessibilityTextUnderElementMode = AccessibilityTextUnderElementMode()) const { return String(); }
     virtual String text() const { return String(); }
index f1fe0ed..15352cb 100644 (file)
@@ -732,7 +732,7 @@ String AccessibilityRenderObject::stringValue() const
 
     RenderBoxModelObject* cssBox = renderBoxModelObject();
 
-    if (ariaRoleAttribute() == AccessibilityRole::StaticText) {
+    if (isARIAStaticText()) {
         String staticText = text();
         if (!staticText.length())
             staticText = textUnderElement();
@@ -780,6 +780,11 @@ String AccessibilityRenderObject::stringValue() const
     return String();
 }
 
+bool AccessibilityRenderObject::canHavePlainText() const
+{
+    return isARIAStaticText() || is<RenderText>(*m_renderer) || isTextControl();
+}
+
 HTMLLabelElement* AccessibilityRenderObject::labelElementContainer() const
 {
     if (!m_renderer)
@@ -3535,9 +3540,11 @@ bool AccessibilityRenderObject::hasPlainText() const
 {
     if (!m_renderer)
         return false;
-    
+
+    if (!canHavePlainText())
+        return false;
+
     const RenderStyle& style = m_renderer->style();
-    
     return style.fontDescription().weight() == normalWeightValue()
         && style.fontDescription().italic() == normalItalicValue()
         && style.textDecorationsInEffect() == TextDecorationNone;
index 3b06864..2f47717 100644 (file)
@@ -284,6 +284,8 @@ private:
     bool inheritsPresentationalRole() const override;
 
     bool shouldGetTextFromNode(AccessibilityTextUnderElementMode) const;
+
+    bool canHavePlainText() const;
 };
 
 } // namespace WebCore