Title: [280282] trunk
Revision
280282
Author
[email protected]
Date
2021-07-23 20:48:01 -0700 (Fri, 23 Jul 2021)

Log Message

Add a method to WebAccessibilityObjectWrapper so that clients can retrieve the text of each line and their corresponding bounding rectangles.
https://bugs.webkit.org/show_bug.cgi?id=228251
Source/WebCore:

rdar://77184036

Reviewed by Chris Fleizach.

Test: accessibility/ios-simulator/element-line-rects-and-text.html

Accessibility clients often need to retrieve a line of text and its
corresponding bounding rectangle screen coordinates. There was not a
clear way of doing this. This patch provides lineRectsAndText as the
mechanism to retrieve the lines of text and their corresponding
rectangles for a given accessibility object. This is the iOS
implementation. MacOS implementation will be done in a separate patch.

* accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
(-[WebAccessibilityObjectWrapper stringsForSimpleRange:attributed:]):
(-[WebAccessibilityObjectWrapper arrayOfTextForTextMarkers:attributed:]):
(-[WebAccessibilityObjectWrapper lineRectsAndText]):
(-[WebAccessibilityObjectWrapper lineRectsForTextMarkerRange:]):

Tools:

Reviewed by Chris Fleizach.

* WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp:
(WTR::AccessibilityUIElement::lineRectsAndText const):
* WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
* WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl:
* WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm:
(WTR::AccessibilityUIElement::lineRectsAndText const):
* WebKitTestRunner/InjectedBundle/mac/AccessibilityCommonMac.mm:
(WTR::makeJSArray):

LayoutTests:

Reviewed by Chris Fleizach.

* accessibility/ios-simulator/element-line-rects-and-text-expected.txt: Added.
* accessibility/ios-simulator/element-line-rects-and-text.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (280281 => 280282)


--- trunk/LayoutTests/ChangeLog	2021-07-24 03:40:46 UTC (rev 280281)
+++ trunk/LayoutTests/ChangeLog	2021-07-24 03:48:01 UTC (rev 280282)
@@ -1,3 +1,13 @@
+2021-07-23  Andres Gonzalez  <[email protected]>
+
+        Add a method to WebAccessibilityObjectWrapper so that clients can retrieve the text of each line and their corresponding bounding rectangles.
+        https://bugs.webkit.org/show_bug.cgi?id=228251
+
+        Reviewed by Chris Fleizach.
+
+        * accessibility/ios-simulator/element-line-rects-and-text-expected.txt: Added.
+        * accessibility/ios-simulator/element-line-rects-and-text.html: Added.
+
 2021-07-23  Alexey Shvayka  <[email protected]>
 
         [WebIDL] Properly validate and merge descriptors in [Replaceable] setter

Added: trunk/LayoutTests/accessibility/ios-simulator/element-line-rects-and-text-expected.txt (0 => 280282)


--- trunk/LayoutTests/accessibility/ios-simulator/element-line-rects-and-text-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/accessibility/ios-simulator/element-line-rects-and-text-expected.txt	2021-07-24 03:48:01 UTC (rev 280282)
@@ -0,0 +1,21 @@
+This is some testing content. A link here. MOre text.
+z
+Another line of text.
+This tests that lineRectsAndText returns the correct values.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+text = "This is some testing content. {\n    UIAccessibilityTokenFontFamily = \"Times New Roman\";\n    UIAccessibilityTokenFontName = \"Times New Roman\";\n    UIAccessibilityTokenFontSize = 16;\n}A link here.{\n    UIAccessibilityTokenFontFamily = \"Times New Roman\";\n    UIAccessibilityTokenFontName = \"Times New Roman\";\n    UIAccessibilityTokenFontSize = 16;\n    UIAccessibilityTokenUnderline = 1;\n} MOre text.{\n    UIAccessibilityTokenFontFamily = \"Times New Roman\";\n    UIAccessibilityTokenFontName = \"Times New Roman\";\n    UIAccessibilityTokenFontSize = 16;\n}";
+width > 0: true
+height > 0: true
+text = "z{\n    UIAccessibilityTokenFontFamily = \"Times New Roman\";\n    UIAccessibilityTokenFontName = \"Times New Roman\";\n    UIAccessibilityTokenFontSize = 16;\n}";
+width > 0: true
+height > 0: true
+text = "Another line of text.{\n    UIAccessibilityTokenFontFamily = \"Times New Roman\";\n    UIAccessibilityTokenFontName = \"Times New Roman\";\n    UIAccessibilityTokenFontSize = 16;\n}";
+width > 0: true
+height > 0: true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/accessibility/ios-simulator/element-line-rects-and-text.html (0 => 280282)


--- trunk/LayoutTests/accessibility/ios-simulator/element-line-rects-and-text.html	                        (rev 0)
+++ trunk/LayoutTests/accessibility/ios-simulator/element-line-rects-and-text.html	2021-07-24 03:48:01 UTC (rev 280282)
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+
+<div id="text">
+This is some testing content.
+<a href="" link here.</a>
+MOre text.<br/>z<br/>
+Another line of text.
+</div>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+    description("This tests that lineRectsAndText returns the correct values.");
+
+    if (window.accessibilityController) {
+        let text = accessibilityController.accessibleElementById("text");
+        let lineRectsAndText = text.lineRectsAndText;
+
+        lineRectsAndText.split("|").forEach((line) => {
+            let text = line.match(/text = \".*\";/);
+            debug(text[0]);
+
+            // Cannot log rect coordinates because it would vary from device to device.
+            // Thus, get the rects width and height and make sure they are > 0.
+            let size = line.match(/NSRect: {{[\d]+, [\d]+}, {([\d]+), ([\d]+)}}/);
+            debug(`width > 0: ${size[1] > 0}`);
+            debug(`height > 0: ${size[2] > 0}`);
+        });
+    }
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (280281 => 280282)


--- trunk/Source/WebCore/ChangeLog	2021-07-24 03:40:46 UTC (rev 280281)
+++ trunk/Source/WebCore/ChangeLog	2021-07-24 03:48:01 UTC (rev 280282)
@@ -1,3 +1,26 @@
+2021-07-23  Andres Gonzalez  <[email protected]>
+
+        Add a method to WebAccessibilityObjectWrapper so that clients can retrieve the text of each line and their corresponding bounding rectangles.
+        https://bugs.webkit.org/show_bug.cgi?id=228251
+        rdar://77184036
+
+        Reviewed by Chris Fleizach.
+
+        Test: accessibility/ios-simulator/element-line-rects-and-text.html
+
+        Accessibility clients often need to retrieve a line of text and its
+        corresponding bounding rectangle screen coordinates. There was not a
+        clear way of doing this. This patch provides lineRectsAndText as the
+        mechanism to retrieve the lines of text and their corresponding
+        rectangles for a given accessibility object. This is the iOS
+        implementation. MacOS implementation will be done in a separate patch.
+
+        * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
+        (-[WebAccessibilityObjectWrapper stringsForSimpleRange:attributed:]):
+        (-[WebAccessibilityObjectWrapper arrayOfTextForTextMarkers:attributed:]):
+        (-[WebAccessibilityObjectWrapper lineRectsAndText]):
+        (-[WebAccessibilityObjectWrapper lineRectsForTextMarkerRange:]):
+
 2021-07-23  Alexey Shvayka  <[email protected]>
 
         [WebIDL] Properly validate and merge descriptors in [Replaceable] setter

Modified: trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm (280281 => 280282)


--- trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm	2021-07-24 03:40:46 UTC (rev 280281)
+++ trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm	2021-07-24 03:48:01 UTC (rev 280282)
@@ -2354,55 +2354,35 @@
     AXAttributeStringSetLanguage(attrString, node->renderer(), attrStringRange);
 }
 
-
-// This method is intended to return an array of strings and accessibility elements that 
-// represent the objects on one line of rendered web content. The array of markers sent
-// in should be ordered and contain only a start and end marker.
-- (NSArray *)arrayOfTextForTextMarkers:(NSArray *)markers attributed:(BOOL)attributed
+- (NSArray *)stringsForSimpleRange:(const SimpleRange&)range attributed:(BOOL)attributed
 {
-    if (![self _prepareAccessibilityCall])
-        return nil;
+    auto array = adoptNS([[NSMutableArray alloc] init]);
 
-    if ([markers count] != 2)
-        return nil;
-    
-    WebAccessibilityTextMarker* startMarker = [markers objectAtIndex:0];
-    WebAccessibilityTextMarker* endMarker = [markers objectAtIndex:1];
-    if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
-        return nil;
-
-    auto range = makeSimpleRange([startMarker visiblePosition], [endMarker visiblePosition]);
-    if (!range)
-        return nil;
-
-    // iterate over the range to build the AX attributed string
-    auto array = adoptNS([[NSMutableArray alloc] init]);
-    TextIterator it(*range);
+    // Iterate over the range to build the AX attributed string.
+    TextIterator it(range);
     for (; !it.atEnd(); it.advance()) {
         Node& node = it.range().start.container;
 
-        // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
-        if (it.text().length() != 0) {
+        // Non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX).
+        if (it.text().length()) {
             if (!attributed) {
                 // First check if this is represented by a link.
-                AccessibilityObject* linkObject = AccessibilityObject::anchorElementForNode(&node);
+                auto* linkObject = AccessibilityObject::anchorElementForNode(&node);
                 if ([self _addAccessibilityObject:linkObject toTextMarkerArray:array.get()])
                     continue;
 
                 // Next check if this region is represented by a heading.
-                AccessibilityObject* headingObject = AccessibilityObject::headingElementForNode(&node);
+                auto* headingObject = AccessibilityObject::headingElementForNode(&node);
                 if ([self _addAccessibilityObject:headingObject toTextMarkerArray:array.get()])
                     continue;
 
                 String listMarkerText = AccessibilityObject::listMarkerTextForNodeAndPosition(&node, makeContainerOffsetPosition(it.range().start));
-                
-                if (!listMarkerText.isEmpty()) 
+                if (!listMarkerText.isEmpty())
                     [array addObject:listMarkerText];
                 // There was not an element representation, so just return the text.
                 [array addObject:it.text().createNSString().get()];
             } else {
                 String listMarkerText = AccessibilityObject::listMarkerTextForNodeAndPosition(&node, makeContainerOffsetPosition(it.range().start));
-
                 if (!listMarkerText.isEmpty()) {
                     auto attrString = adoptNS([[NSMutableAttributedString alloc] init]);
                     AXAttributedStringAppendText(attrString.get(), &node, listMarkerText);
@@ -2414,11 +2394,10 @@
                 [array addObject:attrString.get()];
             }
         } else {
-            Node* replacedNode = it.node();
-            if (replacedNode) {
-                AccessibilityObject* obj = self.axBackingObject->axObjectCache()->getOrCreate(replacedNode->renderer());
-                if (obj && !obj->accessibilityIsIgnored())
-                    [self _addAccessibilityObject:obj toTextMarkerArray:array.get()];
+            if (Node* replacedNode = it.node()) {
+                auto* object = self.axBackingObject->axObjectCache()->getOrCreate(replacedNode->renderer());
+                if (object && !object->accessibilityIsIgnored())
+                    [self _addAccessibilityObject:object toTextMarkerArray:array.get()];
             }
         }
     }
@@ -2426,6 +2405,26 @@
     return array.autorelease();
 }
 
+// This method is intended to return an array of strings and accessibility elements that
+// represent the objects on one line of rendered web content. The array of markers sent
+// in should be ordered and contain only a start and end marker.
+- (NSArray *)arrayOfTextForTextMarkers:(NSArray *)markers attributed:(BOOL)attributed
+{
+    if (![self _prepareAccessibilityCall])
+        return nil;
+
+    if ([markers count] != 2)
+        return nil;
+
+    WebAccessibilityTextMarker* startMarker = [markers objectAtIndex:0];
+    WebAccessibilityTextMarker* endMarker = [markers objectAtIndex:1];
+    if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
+        return nil;
+
+    auto range = makeSimpleRange([startMarker visiblePosition], [endMarker visiblePosition]);
+    return range ? [self stringsForSimpleRange:*range attributed:attributed] : nil;
+}
+
 // FIXME: No reason for this to be a method instead of a function.
 - (NSRange)_convertToNSRange:(const SimpleRange&)range
 {
@@ -2851,6 +2850,68 @@
     return [self textMarkersForRange:[self rangeFromMarkers:markers withText:text]];
 }
 
+- (NSArray<NSDictionary *> *)lineRectsAndText
+{
+    if (![self _prepareAccessibilityCall])
+        return nil;
+    auto* backingObject = self.axBackingObject;
+
+    auto range = backingObject->elementRange();
+    if (!range || range->collapsed())
+        return nil;
+
+    Vector<std::pair<IntRect, RetainPtr<id>>> lines;
+    auto start = VisiblePosition { makeContainerOffsetPosition(range->start) };
+    auto rangeEnd = VisiblePosition { makeContainerOffsetPosition(range->end) };
+    while (!start.isNull() && start < rangeEnd) {
+        auto end = backingObject->nextLineEndPosition(start);
+        if (end <= start)
+            break;
+
+        auto rect = backingObject->boundsForVisiblePositionRange({start, end});
+        NSArray *content = [self stringsForSimpleRange:*makeSimpleRange(start, end) attributed:YES];
+        auto text = adoptNS([[NSMutableAttributedString alloc] init]);
+        for (id item in content) {
+            if ([item isKindOfClass:NSAttributedString.class])
+                [text appendAttributedString:item];
+        }
+        lines.append({rect, text});
+
+        start = end;
+        while (isEndOfLine(start))
+            start = start.next();
+    }
+
+    if (lines.isEmpty())
+        return nil;
+    return createNSArray(lines, [self] (const auto& line) {
+        return @{ @"rect": [NSValue valueWithRect:[self convertRectToSpace:FloatRect(line.first) space:AccessibilityConversionSpace::Screen]],
+                  @"text": line.second.get() };
+    }).autorelease();
+}
+
+- (NSArray *)lineRectsForTextMarkerRange:(NSArray *)markers
+{
+    if (![self _prepareAccessibilityCall])
+        return nil;
+
+    auto range = [self rangeForTextMarkers:markers];
+    if (!range || range->collapsed())
+        return nil;
+
+    auto rects = RenderObject::absoluteTextRects(*range);
+    if (rects.isEmpty())
+        return nil;
+
+    rects.removeAllMatching([] (const auto& rect) -> bool {
+        return rect.width() <= 1 || rect.height() <= 1;
+    });
+
+    return createNSArray(rects, [self] (const auto& rect) {
+        return [NSValue valueWithRect:[self convertRectToSpace:FloatRect(rect) space:AccessibilityConversionSpace::Screen]];
+    }).autorelease();
+}
+
 - (NSArray *)textRectsFromMarkers:(NSArray *)markers withText:(NSString *)text
 {
     if (![self _prepareAccessibilityCall])

Modified: trunk/Tools/ChangeLog (280281 => 280282)


--- trunk/Tools/ChangeLog	2021-07-24 03:40:46 UTC (rev 280281)
+++ trunk/Tools/ChangeLog	2021-07-24 03:48:01 UTC (rev 280282)
@@ -1,3 +1,19 @@
+2021-07-23  Andres Gonzalez  <[email protected]>
+
+        Add a method to WebAccessibilityObjectWrapper so that clients can retrieve the text of each line and their corresponding bounding rectangles.
+        https://bugs.webkit.org/show_bug.cgi?id=228251
+
+        Reviewed by Chris Fleizach.
+
+        * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp:
+        (WTR::AccessibilityUIElement::lineRectsAndText const):
+        * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
+        * WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl:
+        * WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm:
+        (WTR::AccessibilityUIElement::lineRectsAndText const):
+        * WebKitTestRunner/InjectedBundle/mac/AccessibilityCommonMac.mm:
+        (WTR::makeJSArray):
+
 2021-07-23  Alex Christensen  <[email protected]>
 
         Make WKContentRuleListStore respond to same selectors as _WKUserContentExtensionStore

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp (280281 => 280282)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp	2021-07-24 03:40:46 UTC (rev 280281)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp	2021-07-24 03:48:01 UTC (rev 280282)
@@ -87,6 +87,7 @@
 bool AccessibilityUIElement::isTextArea() const { return false; }
 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeMatchesTextNearMarkers(JSStringRef, AccessibilityTextMarker*, AccessibilityTextMarker*) { return nullptr; }
 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForElement() { return nullptr; }
+JSRetainPtr<JSStringRef> AccessibilityUIElement::lineRectsAndText() const { return { }; }
 bool AccessibilityUIElement::isInTableCell() const { return false; }
 bool AccessibilityUIElement::isInTable() const { return false; }
 bool AccessibilityUIElement::isInLandmark() const { return false; }

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h (280281 => 280282)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h	2021-07-24 03:40:46 UTC (rev 280281)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h	2021-07-24 03:48:01 UTC (rev 280282)
@@ -152,6 +152,8 @@
     double y();
     double width();
     double height();
+    JSRetainPtr<JSStringRef> lineRectsAndText() const;
+
     double intValue() const;
     double minValue();
     double maxValue();
@@ -413,9 +415,11 @@
 #endif
 #endif
 };
-    
+
 #ifdef __OBJC__
 inline std::optional<RefPtr<AccessibilityUIElement>> makeVectorElement(const RefPtr<AccessibilityUIElement>*, id element) { return { { AccessibilityUIElement::create(element) } }; }
+
+JSObjectRef makeJSArray(NSArray *);
 #endif
 
 template<typename T>

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl (280281 => 280282)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl	2021-07-24 03:40:46 UTC (rev 280281)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl	2021-07-24 03:48:01 UTC (rev 280282)
@@ -118,6 +118,7 @@
     readonly attribute long height;
     readonly attribute long clickPointX;
     readonly attribute long clickPointY;
+    readonly attribute DOMString lineRectsAndText;
 
     readonly attribute object children;
     readonly attribute long childrenCount;

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm (280281 => 280282)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm	2021-07-24 03:40:46 UTC (rev 280281)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm	2021-07-24 03:48:01 UTC (rev 280282)
@@ -58,6 +58,7 @@
 - (NSAttributedString *)attributedStringForElement;
 - (NSArray *)elementsForRange:(NSRange)range;
 - (NSString *)selectionRangeString;
+- (NSArray *)lineRectsAndText;
 - (CGPoint)accessibilityClickPoint;
 - (void)accessibilityModifySelection:(WebCore::TextGranularity)granularity increase:(BOOL)increase;
 - (NSRange)_accessibilitySelectedTextRange;
@@ -573,6 +574,11 @@
     return [m_element accessibilityClickPoint].y;
 }
 
+JSRetainPtr<JSStringRef> AccessibilityUIElement::lineRectsAndText() const
+{
+    return [[[m_element lineRectsAndText] componentsJoinedByString:@"|"] createJSStringRef];
+}
+
 double AccessibilityUIElement::intValue() const
 {
     return 0;

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityCommonMac.mm (280281 => 280282)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityCommonMac.mm	2021-07-24 03:40:46 UTC (rev 280281)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityCommonMac.mm	2021-07-24 03:48:01 UTC (rev 280282)
@@ -71,6 +71,13 @@
     return JSObjectMakeArray(context, count, arguments, nullptr);
 }
 
+JSObjectRef makeJSArray(NSArray *array)
+{
+    WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
+    JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+    return makeJSArray(context, array);
+}
+
 static JSObjectRef makeJSObject(JSContextRef context, NSDictionary *dictionary)
 {
     auto object = JSObjectMake(context, nullptr, nullptr);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to