Diff
Modified: trunk/LayoutTests/ChangeLog (286115 => 286116)
--- trunk/LayoutTests/ChangeLog 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/LayoutTests/ChangeLog 2021-11-22 20:34:19 UTC (rev 286116)
@@ -1,3 +1,17 @@
+2021-11-22 Chris Fleizach <[email protected]>
+
+ AX: WebKit: need a method to get visible text and frame of an element on screen
+ https://bugs.webkit.org/show_bug.cgi?id=233336
+
+ Reviewed by Andres Gonzalez.
+
+ * accessibility/ios-simulator/visible-character-range-expected.txt: Added.
+ * accessibility/visible-character-range-expected.txt: Added.
+ * accessibility/visible-character-range.html: Added.
+ * platform/ios/TestExpectations:
+ * platform/mac-wk1/TestExpectations:
+ * platform/win/TestExpectations:
+
2021-11-22 Antti Koivisto <[email protected]>
[LFC][Integration] Remove dirOverride
Added: trunk/LayoutTests/accessibility/visible-character-range.html (0 => 286116)
--- trunk/LayoutTests/accessibility/visible-character-range.html (rev 0)
+++ trunk/LayoutTests/accessibility/visible-character-range.html 2021-11-22 20:34:19 UTC (rev 286116)
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body id="body">
+
+<div id="group">
+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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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
+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 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 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 test
+</div>
+
+<script>
+
+ description("This tests that visibleCharacterRange returns expected visible ranges while modifying obscured content.");
+
+ if (window.accessibilityController) {
+ var text = accessibilityController.accessibleElementById("group").childAtIndex(0);
+ debug("Visible range: " + text.stringDescriptionOfAttributeValue("AXVisibleCharacterRange"));
+
+ testRunner.setViewSize(500, 200);
+ debug("Visible range (500, 200): " + text.stringDescriptionOfAttributeValue("AXVisibleCharacterRange"));
+
+ document.body.scrollTop = 200;
+ testRunner.setViewSize(200, 500);
+ debug("Visible range, offset: 200 (200, 500): " + text.stringDescriptionOfAttributeValue("AXVisibleCharacterRange"));
+
+ document.getElementById("group").style.visibility = "hidden";
+ }
+
+</script>
+
+</body>
+</html>
Modified: trunk/LayoutTests/platform/ios/TestExpectations (286115 => 286116)
--- trunk/LayoutTests/platform/ios/TestExpectations 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/LayoutTests/platform/ios/TestExpectations 2021-11-22 20:34:19 UTC (rev 286116)
@@ -2118,7 +2118,7 @@
fast/dom/linkify-phone-numbers.html [ Pass ]
accessibility/video-element-url-attribute.html [ Pass ]
-
+accessibility/visible-character-range.html [ Pass ]
accessibility/ancestor-computation.html [ Pass ]
# Enable "aria-current" tests for iOS.
Added: trunk/LayoutTests/platform/ios/accessibility/visible-character-range-expected.txt (0 => 286116)
--- trunk/LayoutTests/platform/ios/accessibility/visible-character-range-expected.txt (rev 0)
+++ trunk/LayoutTests/platform/ios/accessibility/visible-character-range-expected.txt 2021-11-22 20:34:19 UTC (rev 286116)
@@ -0,0 +1,12 @@
+This tests that visibleCharacterRange returns expected visible ranges while modifying obscured content.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Visible range: {0, 3900}
+Visible range (500, 200): {0, 270}
+Visible range, offset: 200 (200, 500): {0, 735}
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/platform/mac/accessibility/visible-character-range-expected.txt (0 => 286116)
--- trunk/LayoutTests/platform/mac/accessibility/visible-character-range-expected.txt (rev 0)
+++ trunk/LayoutTests/platform/mac/accessibility/visible-character-range-expected.txt 2021-11-22 20:34:19 UTC (rev 286116)
@@ -0,0 +1,12 @@
+This tests that visibleCharacterRange returns expected visible ranges while modifying obscured content.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Visible range: NSRange: {0, 4205}
+Visible range (500, 200): NSRange: {0, 360}
+Visible range, offset: 200 (200, 500): NSRange: {0, 690}
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (286115 => 286116)
--- trunk/LayoutTests/platform/mac-wk1/TestExpectations 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations 2021-11-22 20:34:19 UTC (rev 286116)
@@ -601,6 +601,9 @@
editing/spelling/spellcheck-async.html [ Failure ]
editing/spelling/spelling-unified-emulation.html [ Failure ]
+# Skip due to lack of DumpRenderTree `AccessibilityUIElement::stringDescriptionOfAttributeValue` implementation.
+accessibility/visible-character-range.html [ Skip ]
+
# <rdar://problem/26050923> The result is probably still a pass, but we don't have a way
# to have platform specific results that are different between WK1 and WK2.
accessibility/mac/document-attributes.html [ Failure ]
Modified: trunk/LayoutTests/platform/win/TestExpectations (286115 => 286116)
--- trunk/LayoutTests/platform/win/TestExpectations 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/LayoutTests/platform/win/TestExpectations 2021-11-22 20:34:19 UTC (rev 286116)
@@ -278,6 +278,7 @@
accessibility/listbox-clear-selection.html [ Skip ]
accessibility/embedded-image-description.html [ Skip ]
accessibility/img-no-alt-not-ignored-with-title.html [ Skip ]
+accessibility/visible-character-range.html [ Skip ]
# Need to implement AccessibilityUIElement::hasDocumentRoleAncestor(), AccessibilityUIElement::hasWebApplicationAncestor(),
# AccessibilityUIElement::isInDescriptionListDetail(), AccessibilityUIElement::isInDescriptionListTerm(), and
Modified: trunk/Source/WebCore/ChangeLog (286115 => 286116)
--- trunk/Source/WebCore/ChangeLog 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/Source/WebCore/ChangeLog 2021-11-22 20:34:19 UTC (rev 286116)
@@ -1,3 +1,51 @@
+2021-11-22 Chris Fleizach <[email protected]>
+
+ AX: WebKit: need a method to get visible text and frame of an element on screen
+ https://bugs.webkit.org/show_bug.cgi?id=233336
+
+ Reviewed by Andres Gonzalez.
+
+ Implement visibleCharacterRange for static text elements so that Books can determine the visible
+ content on a page.
+
+ Test: accessibility/visible-character-range.html
+
+ * accessibility/AccessibilityObject.cpp:
+ (WebCore::AccessibilityObject::visibleCharacterRange const):
+ (WebCore::AccessibilityObject::unobscuredContentRect const):
+ * accessibility/AccessibilityObject.h:
+ * accessibility/AccessibilityObjectInterface.h:
+ * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
+ (-[WebAccessibilityObjectWrapper accessibilityVisibleContentRect]):
+ (accessibleElementsForObjects):
+ (-[WebAccessibilityObjectWrapper accessibilityFindMatchingObjects:]):
+ (-[WebAccessibilityObjectWrapper positionForTextMarker:]):
+ (-[WebAccessibilityObjectWrapper textMarkerForPosition:]):
+ (-[WebAccessibilityObjectWrapper stringForRange:]):
+ (-[WebAccessibilityObjectWrapper frameForRange:]):
+ (-[WebAccessibilityObjectWrapper accessibilityMathRadicand]):
+ (-[WebAccessibilityObjectWrapper _convertToNSRange:]): Deleted.
+ (-[WebAccessibilityObjectWrapper _convertToDOMRange:]): Deleted.
+ * accessibility/isolatedtree/AXIsolatedObject.cpp:
+ (WebCore::AXIsolatedObject::visibleCharacterRange const):
+ (WebCore::AXIsolatedObject::unobscuredContentRect const):
+ * accessibility/isolatedtree/AXIsolatedObject.h:
+ * accessibility/mac/WebAccessibilityObjectWrapperBase.h:
+ * accessibility/mac/WebAccessibilityObjectWrapperBase.mm:
+ (makeNSArray):
+ (-[WebAccessibilityObjectWrapperBase accessibilityVisibleCharacterRange]):
+ (makeNSRange):
+ (makeDOMRange):
+ (-[WebAccessibilityObjectWrapperBase baseUpdateBackingStore]):
+ (-[WebAccessibilityObjectWrapperBase lineRectsAndText]):
+ (convertToNSArray): Deleted.
+ * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+ (-[WebAccessibilityObjectWrapper childrenVectorArray]):
+ (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):
+ (-[WebAccessibilityObjectWrapper _indexForTextMarker:]):
+ (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):
+ (-[WebAccessibilityObjectWrapper _convertToNSRange:]): Deleted.
+
2021-11-20 Simon Fraser <[email protected]>
Clarify the behavior of ScrollAnimator::scroll()
Modified: trunk/Source/WebCore/accessibility/AccessibilityObject.cpp (286115 => 286116)
--- trunk/Source/WebCore/accessibility/AccessibilityObject.cpp 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/Source/WebCore/accessibility/AccessibilityObject.cpp 2021-11-22 20:34:19 UTC (rev 286116)
@@ -704,6 +704,52 @@
return AXObjectCache::rangeForNodeContents(*node);
}
+std::optional<SimpleRange> AccessibilityObject::visibleCharacterRange() const
+{
+ auto range = elementRange();
+ if (!range)
+ return std::nullopt;
+
+ auto contentRect = unobscuredContentRect();
+ auto elementRect = snappedIntRect(this->elementRect());
+ if (!contentRect.intersects(elementRect))
+ return std::nullopt;
+
+ std::optional<BoundaryPoint> startBoundary = range->start;
+ std::optional<BoundaryPoint> endBoundary = range->end;
+
+ // Origin isn't contained in visible rect, start moving forward by line.
+ while (!contentRect.contains(elementRect.location())) {
+ auto nextLinePosition = nextLineEndPosition(VisiblePosition(makeContainerOffsetPosition(*startBoundary)));
+ std::optional<BoundaryPoint> testStartBoundary = makeBoundaryPoint(nextLinePosition);
+ if (!testStartBoundary || !contains(*range, *testStartBoundary))
+ break;
+
+ startBoundary = testStartBoundary;
+ elementRect = boundsForRange(SimpleRange(*startBoundary, range->end));
+ if (elementRect.isEmpty())
+ break;
+ }
+
+ // End isn't contained in visible rect, start moving backwards by line.
+ while (!contentRect.contains(elementRect.location() + elementRect.size())) {
+ auto previousLinePosition = previousLineStartPosition(VisiblePosition(makeContainerOffsetPosition(*endBoundary)));
+ std::optional<BoundaryPoint> testEndBoundary = makeBoundaryPoint(previousLinePosition);
+ if (!testEndBoundary || !contains(*range, *testEndBoundary))
+ break;
+
+ endBoundary = testEndBoundary;
+ elementRect = boundsForRange({ *startBoundary, *endBoundary });
+ if (elementRect.isEmpty())
+ break;
+ }
+
+ if (!startBoundary || !endBoundary)
+ return std::nullopt;
+
+ return {{ *startBoundary, *endBoundary }};
+}
+
std::optional<SimpleRange> AccessibilityObject::findTextRange(const Vector<String>& searchStrings, const SimpleRange& start, AccessibilitySearchTextDirection direction) const
{
std::optional<SimpleRange> found;
@@ -3182,6 +3228,14 @@
scrollParent->scrollToMakeVisibleWithSubFocus(newSubfocus);
}
+FloatRect AccessibilityObject::unobscuredContentRect() const
+{
+ auto document = this->document();
+ if (!document || !document->view())
+ return { };
+ return FloatRect(snappedIntRect(document->view()->unobscuredContentRect()));
+}
+
void AccessibilityObject::scrollToGlobalPoint(const IntPoint& globalPoint) const
{
// Search up the parent chain and create a vector of all scrollable parent objects
Modified: trunk/Source/WebCore/accessibility/AccessibilityObject.h (286115 => 286116)
--- trunk/Source/WebCore/accessibility/AccessibilityObject.h 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/Source/WebCore/accessibility/AccessibilityObject.h 2021-11-22 20:34:19 UTC (rev 286116)
@@ -808,7 +808,7 @@
void ariaElementsFromAttribute(AccessibilityChildrenVector&, const QualifiedName&) const;
void ariaElementsReferencedByAttribute(AccessibilityChildrenVector&, const QualifiedName&) const;
virtual bool exposesTitleUIElement() const { return true; }
-
+ FloatRect unobscuredContentRect() const override;
AccessibilityObject* radioGroupAncestor() const;
bool allowsTextRanges() const;
@@ -821,6 +821,7 @@
std::optional<SimpleRange> rangeOfStringClosestToRangeInDirection(const SimpleRange&, AccessibilitySearchDirection, const Vector<String>&) const;
std::optional<SimpleRange> selectionRange() const;
std::optional<SimpleRange> findTextRange(const Vector<String>& searchStrings, const SimpleRange& start, AccessibilitySearchTextDirection) const;
+ std::optional<SimpleRange> visibleCharacterRange() const override;
protected: // FIXME: Make the data members private.
bool childrenInitialized() const { return m_childrenInitialized; }
Modified: trunk/Source/WebCore/accessibility/AccessibilityObjectInterface.h (286115 => 286116)
--- trunk/Source/WebCore/accessibility/AccessibilityObjectInterface.h 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/Source/WebCore/accessibility/AccessibilityObjectInterface.h 2021-11-22 20:34:19 UTC (rev 286116)
@@ -988,6 +988,7 @@
virtual void setIsExpanded(bool) = 0;
virtual FloatRect relativeFrame() const = 0;
virtual FloatRect convertFrameToSpace(const FloatRect&, AccessibilityConversionSpace) const = 0;
+ virtual FloatRect unobscuredContentRect() const = 0;
virtual bool supportsCheckedState() const = 0;
// In a multi-select list, many items can be selected but only one is active at a time.
@@ -997,6 +998,7 @@
virtual bool hasItalicFont() const = 0;
virtual bool hasMisspelling() const = 0;
virtual std::optional<SimpleRange> misspellingRange(const SimpleRange& start, AccessibilitySearchDirection) const = 0;
+ virtual std::optional<SimpleRange> visibleCharacterRange() const = 0;
virtual bool hasPlainText() const = 0;
virtual bool hasSameFont(const AXCoreObject&) const = 0;
virtual bool hasSameFontColor(const AXCoreObject&) const = 0;
Modified: trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm (286115 => 286116)
--- trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm 2021-11-22 20:34:19 UTC (rev 286116)
@@ -52,6 +52,7 @@
#import "SVGElementInlines.h"
#import "SVGNames.h"
#import "SelectionGeometry.h"
+#import "SimpleRange.h"
#import "TextIterator.h"
#import "WAKScrollView.h"
#import "WAKWindow.h"
@@ -1694,12 +1695,7 @@
{
if (![self _prepareAccessibilityCall])
return CGRectZero;
-
- auto document = self.axBackingObject->document();
- if (!document || !document->view())
- return CGRectZero;
- auto rect = FloatRect(snappedIntRect(document->view()->unobscuredContentRect()));
- return [self convertRectToSpace:rect space:AccessibilityConversionSpace::Screen];
+ return [self convertRectToSpace:self.axBackingObject->unobscuredContentRect() space:AccessibilityConversionSpace::Screen];
}
// The "center point" is where VoiceOver will "press" an object. This may not be the actual
@@ -1915,7 +1911,7 @@
});
}
- return convertToNSArray(accessibleElements);
+ return makeNSArray(accessibleElements);
}
- (NSArray *)accessibilityDetailsElements
@@ -2104,7 +2100,7 @@
AccessibilitySearchCriteria criteria = accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(parameters);
AccessibilityObject::AccessibilityChildrenVector results;
self.axBackingObject->findMatchingObjects(&criteria, results);
- return convertToNSArray(results);
+ return makeNSArray(results);
}
- (void)accessibilityModifySelection:(TextGranularity)granularity increase:(BOOL)increase
@@ -2209,48 +2205,7 @@
return range ? [self contentForSimpleRange:*range attributed:attributed] : nil;
}
-// FIXME: No reason for this to be a method instead of a function.
-- (NSRange)_convertToNSRange:(const SimpleRange&)range
-{
- auto& document = range.start.document();
- auto* frame = document.frame();
- if (!frame)
- return NSMakeRange(NSNotFound, 0);
- auto* rootEditableElement = frame->selection().selection().rootEditableElement();
- auto* scope = rootEditableElement ? rootEditableElement : document.documentElement();
- if (!scope)
- return NSMakeRange(NSNotFound, 0);
-
- // Mouse events may cause TSM to attempt to create an NSRange for a portion of the view
- // that is not inside the current editable region. These checks ensure we don't produce
- // potentially invalid data when responding to such requests.
- if (!scope->contains(range.start.container.ptr()) || !scope->contains(range.end.container.ptr()))
- return NSMakeRange(NSNotFound, 0);
-
- return NSMakeRange(characterCount({ { *scope, 0 }, range.start }), characterCount(range));
-}
-
-- (std::optional<SimpleRange>)_convertToDOMRange:(NSRange)range
-{
- if (range.location == NSNotFound)
- return std::nullopt;
-
- // our critical assumption is that we are only called by input methods that
- // concentrate on a given area containing the selection
- // We have to do this because of text fields and textareas. The DOM for those is not
- // directly in the document DOM, so serialization is problematic. Our solution is
- // to use the root editable element of the selection start as the positional base.
- // That fits with AppKit's idea of an input context.
- auto document = self.axBackingObject->document();
- auto selectionRoot = document->frame()->selection().selection().rootEditableElement();
- auto scope = selectionRoot ? selectionRoot : document->documentElement();
- if (!scope)
- return std::nullopt;
-
- return resolveCharacterRange(makeRangeSelectingNodeContents(*scope), range);
-}
-
// This method is intended to take a text marker representing a VisiblePosition and convert it
// into a normalized location within the document.
- (NSInteger)positionForTextMarker:(WebAccessibilityTextMarker *)marker
@@ -2267,7 +2222,7 @@
auto range = cache->rangeForUnorderedCharacterOffsets(characterOffset, characterOffset);
if (!range)
return NSNotFound;
- return [self _convertToNSRange:*range].location;
+ return makeNSRange(range).location;
}
return NSNotFound;
}
@@ -2346,7 +2301,7 @@
if (![self _prepareAccessibilityCall])
return nil;
- auto range = [self _convertToDOMRange:NSMakeRange(position, 0)];
+ auto range = makeDOMRange(self.axBackingObject->document(), NSMakeRange(position, 0));
if (!range)
return nil;
@@ -2414,7 +2369,7 @@
{
if (![self _prepareAccessibilityCall])
return nil;
- auto webRange = [self _convertToDOMRange:range];
+ auto webRange = makeDOMRange(self.axBackingObject->document(), range);
if (!webRange)
return nil;
return self.axBackingObject->stringForRange(*webRange);
@@ -2600,6 +2555,17 @@
return [self previousMarkerForCharacterOffset:start];
}
+- (CGRect)frameForRange:(NSRange)range
+{
+ if (![self _prepareAccessibilityCall])
+ return CGRectZero;
+ auto webRange = makeDOMRange(self.axBackingObject->document(), range);
+ if (!webRange)
+ return CGRectZero;
+ auto rect = self.axBackingObject->boundsForRange(*webRange);
+ return [self convertRectToSpace:rect space:AccessibilityConversionSpace::Screen];
+}
+
// This method is intended to return the bounds of a text marker range in screen coordinates.
- (CGRect)frameForTextMarkers:(NSArray *)array
{
@@ -2931,7 +2897,7 @@
return nil;
auto radicand = self.axBackingObject->mathRadicand();
- return radicand ? convertToNSArray(*radicand) : nil;
+ return radicand ? makeNSArray(*radicand) : nil;
}
- (WebAccessibilityObjectWrapper *)accessibilityMathNumeratorObject
Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp (286115 => 286116)
--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp 2021-11-22 20:34:19 UTC (rev 286116)
@@ -992,6 +992,13 @@
tree->applyPendingChanges();
}
+std::optional<SimpleRange> AXIsolatedObject::visibleCharacterRange() const
+{
+ ASSERT(isMainThread());
+ auto* axObject = associatedAXObject();
+ return axObject ? axObject->visibleCharacterRange() : std::nullopt;
+}
+
std::optional<SimpleRange> AXIsolatedObject::rangeForPlainTextRange(const PlainTextRange& axRange) const
{
ASSERT(isMainThread());
@@ -1470,6 +1477,15 @@
object->setSelectedVisiblePositionRange(visiblePositionRange);
}
+FloatRect AXIsolatedObject::unobscuredContentRect() const
+{
+ return Accessibility::retrieveValueFromMainThread<FloatRect>([this] () -> FloatRect {
+ if (auto* object = associatedAXObject())
+ return object->unobscuredContentRect();
+ return { };
+ });
+}
+
std::optional<SimpleRange> AXIsolatedObject::elementRange() const
{
ASSERT(isMainThread());
Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h (286115 => 286116)
--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h 2021-11-22 20:34:19 UTC (rev 286116)
@@ -441,9 +441,11 @@
AXCoreObject* accessibilityObjectForPosition(const VisiblePosition&) const override;
int lineForPosition(const VisiblePosition&) const override;
PlainTextRange plainTextRangeForVisiblePositionRange(const VisiblePositionRange&) const override;
+ std::optional<SimpleRange> visibleCharacterRange() const override;
int index(const VisiblePosition&) const override;
void lineBreaks(Vector<int>&) const override;
-
+ FloatRect unobscuredContentRect() const override;
+
// Attribute setters.
void setARIAGrabbed(bool) override;
void setIsExpanded(bool) override;
Modified: trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperBase.h (286115 => 286116)
--- trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperBase.h 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperBase.h 2021-11-22 20:34:19 UTC (rev 286116)
@@ -34,6 +34,7 @@
namespace WebCore {
struct AccessibilitySearchCriteria;
+class Document;
class IntRect;
class FloatPoint;
class HTMLTextFormControlElement;
@@ -111,11 +112,15 @@
- (NSArray *)accessibilityMathPostscriptPairs;
- (NSArray *)accessibilityMathPrescriptPairs;
+- (NSRange)accessibilityVisibleCharacterRange;
+
- (NSDictionary<NSString *, id> *)baseAccessibilityResolvedEditingStyles;
extern WebCore::AccessibilitySearchCriteria accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(const NSDictionary *);
-extern NSArray *convertToNSArray(const WebCore::AXCoreObject::AccessibilityChildrenVector&);
+extern NSArray *makeNSArray(const WebCore::AXCoreObject::AccessibilityChildrenVector&);
+extern NSRange makeNSRange(std::optional<WebCore::SimpleRange>);
+extern std::optional<WebCore::SimpleRange> makeDOMRange(WebCore::Document*, NSRange);
#if PLATFORM(IOS_FAMILY)
- (id)_accessibilityWebDocumentView;
Modified: trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperBase.mm (286115 => 286116)
--- trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperBase.mm 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperBase.mm 2021-11-22 20:34:19 UTC (rev 286116)
@@ -261,7 +261,7 @@
}).autorelease();
}
-NSArray *convertToNSArray(const WebCore::AXCoreObject::AccessibilityChildrenVector& children)
+NSArray *makeNSArray(const WebCore::AXCoreObject::AccessibilityChildrenVector& children)
{
return createNSArray(children, [] (const auto& child) -> id {
auto wrapper = child->wrapper();
@@ -462,6 +462,27 @@
return convertedPath.autorelease();
}
+// Determine the visible range by checking intersection of unobscuredContentRect and a range of text by
+// advancing forward by line from top and backwards by line from the bottom, until we have a visible range.
+- (NSRange)accessibilityVisibleCharacterRange
+{
+ return Accessibility::retrieveValueFromMainThread<NSRange>([protectedSelf = retainPtr(self)] () -> NSRange {
+ auto backingObject = protectedSelf.get().baseUpdateBackingStore;
+ if (!backingObject)
+ return NSMakeRange(NSNotFound, 0);
+
+ auto elementRange = makeNSRange(backingObject->elementRange());
+ if (elementRange.location == NSNotFound)
+ return elementRange;
+
+ auto visibleRange = makeNSRange(backingObject->visibleCharacterRange());
+ if (visibleRange.location == NSNotFound)
+ return visibleRange;
+
+ return NSMakeRange(visibleRange.location - elementRange.location, visibleRange.length);
+ });
+}
+
- (id)_accessibilityWebDocumentView
{
ASSERT_NOT_REACHED();
@@ -623,6 +644,49 @@
AXAttributeStringSetLanguage(attrString, node->renderer(), attrStringRange);
}
+NSRange makeNSRange(std::optional<SimpleRange> range)
+{
+ if (!range)
+ return NSMakeRange(NSNotFound, 0);
+
+ auto& document = range->start.document();
+ auto* frame = document.frame();
+ if (!frame)
+ return NSMakeRange(NSNotFound, 0);
+
+ auto* rootEditableElement = frame->selection().selection().rootEditableElement();
+ auto* scope = rootEditableElement ? rootEditableElement : document.documentElement();
+ if (!scope)
+ return NSMakeRange(NSNotFound, 0);
+
+ // Mouse events may cause TSM to attempt to create an NSRange for a portion of the view
+ // that is not inside the current editable region. These checks ensure we don't produce
+ // potentially invalid data when responding to such requests.
+ if (!scope->contains(range->start.container.ptr()) || !scope->contains(range->end.container.ptr()))
+ return NSMakeRange(NSNotFound, 0);
+
+ return NSMakeRange(characterCount({ { *scope, 0 }, range->start }), characterCount(*range));
+}
+
+std::optional<SimpleRange> makeDOMRange(Document* document, NSRange range)
+{
+ if (range.location == NSNotFound)
+ return std::nullopt;
+
+ // our critical assumption is that we are only called by input methods that
+ // concentrate on a given area containing the selection
+ // We have to do this because of text fields and textareas. The DOM for those is not
+ // directly in the document DOM, so serialization is problematic. Our solution is
+ // to use the root editable element of the selection start as the positional base.
+ // That fits with AppKit's idea of an input context.
+ auto selectionRoot = document->frame()->selection().selection().rootEditableElement();
+ auto scope = selectionRoot ? selectionRoot : document->documentElement();
+ if (!scope)
+ return std::nullopt;
+
+ return resolveCharacterRange(makeRangeSelectingNodeContents(*scope), range);
+}
+
// Returns an array of strings and AXObject wrappers corresponding to the text
// runs and replacement nodes included in the given range.
- (NSArray *)contentForSimpleRange:(const SimpleRange&)range attributed:(BOOL)attributed
@@ -676,18 +740,26 @@
return array.autorelease();
}
-- (NSArray<NSDictionary *> *)lineRectsAndText
+- (WebCore::AXCoreObject*)baseUpdateBackingStore
{
#if PLATFORM(MAC)
auto* backingObject = self.updateObjectBackingStore;
if (!backingObject)
- return nil;
+ return nullptr;
#else
if (![self _prepareAccessibilityCall])
- return nil;
+ return nullptr;
auto* backingObject = self.axBackingObject;
#endif
+ return backingObject;
+}
+- (NSArray<NSDictionary *> *)lineRectsAndText
+{
+ auto backingObject = self.baseUpdateBackingStore;
+ if (!backingObject)
+ return nil;
+
auto range = backingObject->elementRange();
if (!range)
return nil;
Modified: trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm (286115 => 286116)
--- trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm 2021-11-22 20:34:19 UTC (rev 286116)
@@ -1795,7 +1795,7 @@
- (NSArray<WebAccessibilityObjectWrapper *> *)childrenVectorArray
{
- return convertToNSArray(self.axBackingObject->children());
+ return makeNSArray(self.axBackingObject->children());
}
- (NSValue *)position
@@ -2203,7 +2203,7 @@
if (backingObject->isTreeItem()) {
AccessibilityObject::AccessibilityChildrenVector contentCopy;
backingObject->ariaTreeItemContent(contentCopy);
- return convertToNSArray(contentCopy);
+ return makeNSArray(contentCopy);
}
return self.childrenVectorArray;
@@ -2213,7 +2213,7 @@
if (backingObject->canHaveSelectedChildren()) {
AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
backingObject->selectedChildren(selectedChildrenCopy);
- return convertToNSArray(selectedChildrenCopy);
+ return makeNSArray(selectedChildrenCopy);
}
return nil;
}
@@ -2222,7 +2222,7 @@
if (backingObject->isListBox()) {
AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
backingObject->visibleChildren(visibleChildrenCopy);
- return convertToNSArray(visibleChildrenCopy);
+ return makeNSArray(visibleChildrenCopy);
}
if (backingObject->isList())
@@ -2234,7 +2234,7 @@
if (backingObject->isWebArea()) {
if ([attributeName isEqualToString:@"AXLinkUIElements"])
- return convertToNSArray(backingObject->documentLinks());
+ return makeNSArray(backingObject->documentLinks());
if ([attributeName isEqualToString:@"AXLoaded"])
return [NSNumber numberWithBool:backingObject->isLoaded()];
@@ -2267,10 +2267,6 @@
PlainTextRange textRange = backingObject->selectedTextRange();
return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
}
- // TODO: Get actual visible range. <rdar://problem/4712101>
- if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
- return backingObject->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, backingObject->textLength())];
-
if ([attributeName isEqualToString:NSAccessibilityInsertionPointLineNumberAttribute]) {
int lineNumber = backingObject->insertionPointLineNumber();
return lineNumber >= 0 ? @(lineNumber) : nil;
@@ -2277,6 +2273,15 @@
}
}
+ if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
+ if (backingObject->isPasswordField())
+ return nil;
+ // TODO: Get actual visible range. <rdar://problem/4712101>
+ if (backingObject->isTextControl())
+ return [NSValue valueWithRange:NSMakeRange(0, backingObject->textLength())];
+ return [NSValue valueWithRange:[self accessibilityVisibleCharacterRange]];
+ }
+
if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
URL url = ""
if (url.isNull())
@@ -2380,7 +2385,7 @@
if ([attributeName isEqualToString:NSAccessibilityImageOverlayElementsAttribute]) {
auto imageOverlayElements = backingObject->imageOverlayElements();
- return imageOverlayElements ? convertToNSArray(*imageOverlayElements) : nil;
+ return imageOverlayElements ? makeNSArray(*imageOverlayElements) : nil;
}
if ([attributeName isEqualToString:NSAccessibilityEmbeddedImageDescriptionAttribute])
@@ -2404,29 +2409,29 @@
if (backingObject->isTabList()) {
AccessibilityObject::AccessibilityChildrenVector tabsChildren;
backingObject->tabChildren(tabsChildren);
- return convertToNSArray(tabsChildren);
+ return makeNSArray(tabsChildren);
}
}
if ([attributeName isEqualToString:NSAccessibilityContentsAttribute])
- return convertToNSArray(backingObject->contents());
+ return makeNSArray(backingObject->contents());
if (backingObject->isTable() && backingObject->isExposable()) {
if ([attributeName isEqualToString:NSAccessibilityRowsAttribute])
- return convertToNSArray(backingObject->rows());
+ return makeNSArray(backingObject->rows());
if ([attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute])
- return convertToNSArray(backingObject->visibleRows());
+ return makeNSArray(backingObject->visibleRows());
// TODO: distinguish between visible and non-visible columns
if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute]
|| [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute])
- return convertToNSArray(backingObject->columns());
+ return makeNSArray(backingObject->columns());
if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
backingObject->selectedChildren(selectedChildrenCopy);
- return convertToNSArray(selectedChildrenCopy);
+ return makeNSArray(selectedChildrenCopy);
}
// HTML tables don't support these attributes.
@@ -2435,7 +2440,7 @@
return nil;
if ([attributeName isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute])
- return convertToNSArray(backingObject->columnHeaders());
+ return makeNSArray(backingObject->columnHeaders());
if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
auto* headerContainer = backingObject->headerContainer();
@@ -2443,10 +2448,10 @@
}
if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute])
- return convertToNSArray(backingObject->rowHeaders());
+ return makeNSArray(backingObject->rowHeaders());
if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute])
- return convertToNSArray(backingObject->cells());
+ return makeNSArray(backingObject->cells());
if ([attributeName isEqualToString:NSAccessibilityColumnCountAttribute])
return @(backingObject->columnCount());
@@ -2468,7 +2473,7 @@
// rows attribute for a column is the list of all the elements in that column at each row
if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]
|| [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute])
- return convertToNSArray(backingObject->children());
+ return makeNSArray(backingObject->children());
if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
auto* header = backingObject->columnHeader();
@@ -2488,10 +2493,10 @@
}
if ([attributeName isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute])
- return convertToNSArray(backingObject->columnHeaders());
+ return makeNSArray(backingObject->columnHeaders());
if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute])
- return convertToNSArray(backingObject->rowHeaders());
+ return makeNSArray(backingObject->rowHeaders());
if ([attributeName isEqualToString:NSAccessibilityARIAColumnIndexAttribute])
return @(backingObject->axColumnIndex());
@@ -2504,12 +2509,12 @@
if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
backingObject->selectedChildren(selectedChildrenCopy);
- return convertToNSArray(selectedChildrenCopy);
+ return makeNSArray(selectedChildrenCopy);
}
if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) {
AccessibilityObject::AccessibilityChildrenVector rowsCopy;
backingObject->ariaTreeRows(rowsCopy);
- return convertToNSArray(rowsCopy);
+ return makeNSArray(rowsCopy);
}
// TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
@@ -2544,7 +2549,7 @@
// The rows that are considered inside this row.
if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
if (backingObject->isTreeItem() || backingObject->isARIATreeGridRow())
- return convertToNSArray(backingObject->disclosedRows());
+ return makeNSArray(backingObject->disclosedRows());
}
// The row that contains this row. It should be the same as the first parent that is a treeitem.
@@ -2612,7 +2617,7 @@
if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
backingObject->linkedUIElements(linkedUIElements);
- return convertToNSArray(linkedUIElements);
+ return makeNSArray(linkedUIElements);
}
if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
@@ -2685,7 +2690,7 @@
if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) {
AccessibilityObject::AccessibilityChildrenVector ariaOwns;
backingObject->ariaOwnsElements(ariaOwns);
- return convertToNSArray(ariaOwns);
+ return makeNSArray(ariaOwns);
}
if ([attributeName isEqualToString:NSAccessibilityARIAPosInSetAttribute])
@@ -2751,7 +2756,7 @@
if ([attributeName isEqualToString:NSAccessibilityMathRootRadicandAttribute]) {
auto radicand = backingObject->mathRadicand();
- return radicand ? convertToNSArray(*radicand) : nil;
+ return radicand ? makeNSArray(*radicand) : nil;
}
if ([attributeName isEqualToString:NSAccessibilityMathFractionNumeratorAttribute])
@@ -2845,7 +2850,7 @@
if ([attributeName isEqualToString:@"AXDetailsElements"]) {
AccessibilityObject::AccessibilityChildrenVector details;
backingObject->ariaDetailsElements(details);
- return convertToNSArray(details);
+ return makeNSArray(details);
}
if ([attributeName isEqualToString:NSAccessibilityBrailleLabelAttribute])
@@ -2860,7 +2865,7 @@
if ([attributeName isEqualToString:@"AXErrorMessageElements"]) {
AccessibilityObject::AccessibilityChildrenVector errorMessages;
backingObject->ariaErrorMessageElements(errorMessages);
- return convertToNSArray(errorMessages);
+ return makeNSArray(errorMessages);
}
// Multi-selectable
@@ -2878,7 +2883,7 @@
if ([attributeName isEqualToString:NSAccessibilityAriaControlsAttribute]) {
AccessibilityObject::AccessibilityChildrenVector ariaControls;
backingObject->ariaControlsElements(ariaControls);
- return convertToNSArray(ariaControls);
+ return makeNSArray(ariaControls);
}
if ([attributeName isEqualToString:NSAccessibilityFocusableAncestorAttribute]) {
@@ -3428,22 +3433,6 @@
});
}
-// FIXME: No reason for this to be a method instead of a function; can get document from range.
-- (NSRange)_convertToNSRange:(const SimpleRange&)range
-{
- ASSERT(isMainThread());
-
- auto document = self.axBackingObject->document();
- if (!document)
- return NSMakeRange(NSNotFound, 0);
-
- auto documentElement = document->documentElement();
- if (!documentElement)
- return NSMakeRange(NSNotFound, 0);
-
- return characterRange(makeBoundaryPointBeforeNodeContents(*documentElement), range);
-}
-
- (NSInteger)_indexForTextMarker:(AXTextMarkerRef)marker
{
if (!marker)
@@ -3460,7 +3449,7 @@
if (!range)
return NSNotFound;
- return [protectedSelf _convertToNSRange:*range].location;
+ return makeNSRange(range).location;
}
return NSNotFound;
@@ -3835,8 +3824,8 @@
AccessibilityObject::AccessibilityChildrenVector results;
backingObject->findMatchingObjects(&criteria, results);
if (widgetChildren)
- return [widgetChildren arrayByAddingObjectsFromArray:convertToNSArray(results)];
- return convertToNSArray(results);
+ return [widgetChildren arrayByAddingObjectsFromArray:makeNSArray(results)];
+ return makeNSArray(results);
}
// TextMarker attributes.
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm (286115 => 286116)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm 2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm 2021-11-22 20:34:19 UTC (rev 286116)
@@ -108,6 +108,7 @@
- (id)_accessibilityListAncestor;
- (id)_accessibilityPhotoDescription;
- (NSArray *)accessibilityImageOverlayElements;
+- (NSRange)accessibilityVisibleCharacterRange;
// TextMarker related
- (NSArray *)textMarkerRange;
@@ -394,6 +395,9 @@
JSRetainPtr<JSStringRef> AccessibilityUIElement::stringDescriptionOfAttributeValue(JSStringRef attribute)
{
+ if (JSStringIsEqualToUTF8CString(attribute, "AXVisibleCharacterRange"))
+ return [NSStringFromRange([m_element accessibilityVisibleCharacterRange]) createJSStringRef];
+
return createJSString();
}