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);