diff --git a/Source/WebCore/accessibility/AXTextMarker.h b/Source/WebCore/accessibility/AXTextMarker.h index 253467e90250..f006f66ac189 100644 --- a/Source/WebCore/accessibility/AXTextMarker.h +++ b/Source/WebCore/accessibility/AXTextMarker.h @@ -151,7 +151,7 @@ class AXTextMarkerRange { AXTextMarkerRange(AXID treeID, AXID objectID, unsigned offset, unsigned length); AXTextMarkerRange() = default; - operator bool() const { return !m_start.isNull() && !m_end.isNull(); } + operator bool() const { return m_start && m_end; } operator VisiblePositionRange() const; std::optional simpleRange() const; diff --git a/Source/WebCore/accessibility/AccessibilityObject.cpp b/Source/WebCore/accessibility/AccessibilityObject.cpp index eaca77bf5158..ec9bca2c0402 100644 --- a/Source/WebCore/accessibility/AccessibilityObject.cpp +++ b/Source/WebCore/accessibility/AccessibilityObject.cpp @@ -2846,7 +2846,12 @@ std::optional AccessibilityObject::textContent() const if (!hasTextContent()) return std::nullopt; - if (auto range = simpleRange()) + std::optional range; + if (isTextControl()) + range = rangeForPlainTextRange({ 0, text().length() }); + else + range = simpleRange(); + if (range) return stringForRange(*range); return std::nullopt; } diff --git a/Source/WebCore/accessibility/cocoa/AccessibilityObjectCocoa.mm b/Source/WebCore/accessibility/cocoa/AccessibilityObjectCocoa.mm index d05094864cda..9d9703580678 100644 --- a/Source/WebCore/accessibility/cocoa/AccessibilityObjectCocoa.mm +++ b/Source/WebCore/accessibility/cocoa/AccessibilityObjectCocoa.mm @@ -217,7 +217,19 @@ static bool isDescriptiveText(AccessibilityTextSource textSource) { if (range.location == NSNotFound) return { }; - return { visiblePositionForIndex(range.location), visiblePositionForIndex(range.location + range.length) }; + + if (!isTextControl()) + return { visiblePositionForIndex(range.location), visiblePositionForIndex(range.location + range.length) }; + + if (range.location + range.length > text().length()) + return { }; + + if (auto* cache = axObjectCache()) { + auto start = cache->characterOffsetForIndex(range.location, this); + auto end = cache->characterOffsetForIndex(range.location + range.length, this); + return cache->rangeForUnorderedCharacterOffsets(start, end); + } + return { }; } // NSAttributedString support. diff --git a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h index 09ca37dafda7..3781a373df53 100644 --- a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h +++ b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h @@ -473,7 +473,6 @@ class AXIsolatedObject final : public AXCoreObject { unsigned textLength() const override; #if PLATFORM(COCOA) RetainPtr attributedStringForTextMarkerRange(AXTextMarkerRange&&, SpellCheck) const override; - NSAttributedString *cachedAttributedStringForTextMarkerRange(const AXTextMarkerRange&, SpellCheck) const; #endif AXObjectCache* axObjectCache() const override; Element* actionElement() const override; diff --git a/Source/WebCore/accessibility/isolatedtree/mac/AXIsolatedObjectMac.mm b/Source/WebCore/accessibility/isolatedtree/mac/AXIsolatedObjectMac.mm index 6a2225b61c1e..30368a19b0b6 100644 --- a/Source/WebCore/accessibility/isolatedtree/mac/AXIsolatedObjectMac.mm +++ b/Source/WebCore/accessibility/isolatedtree/mac/AXIsolatedObjectMac.mm @@ -41,7 +41,12 @@ RetainPtr attributedText; if (object->hasAttributedText()) { - if (auto range = object->simpleRange()) { + std::optional range; + if (isTextControl()) + range = rangeForPlainTextRange({ 0, object->text().length() }); + else + range = object->simpleRange(); + if (range) { if ((attributedText = object->attributedStringForRange(*range, SpellCheck::Yes))) setProperty(AXPropertyName::AttributedText, attributedText); } @@ -163,29 +168,25 @@ RetainPtr AXIsolatedObject::attributedStringForTextMarkerRange(AXTextMarkerRange&& markerRange, SpellCheck spellCheck) const { - if (NSAttributedString *cachedString = cachedAttributedStringForTextMarkerRange(markerRange, spellCheck)) - return cachedString; - - return Accessibility::retrieveValueFromMainThread>([markerRange = WTFMove(markerRange), &spellCheck, this] () mutable -> RetainPtr { - if (RefPtr axObject = associatedAXObject()) - return axObject->attributedStringForTextMarkerRange(WTFMove(markerRange), spellCheck); - return { }; - }); -} + if (!markerRange) + return nil; -NSAttributedString *AXIsolatedObject::cachedAttributedStringForTextMarkerRange(const AXTextMarkerRange& markerRange, SpellCheck spellCheck) const -{ // At the moment we are only handling ranges that are contained in a single object, and for which we cached the AttributeString. // FIXME: Extend to cases where the range expands multiple objects. + auto attributedText = propertyValue>(AXPropertyName::AttributedText); + if (!attributedText) { + return Accessibility::retrieveValueFromMainThread>([markerRange = WTFMove(markerRange), &spellCheck, this] () mutable -> RetainPtr { + if (RefPtr axObject = associatedAXObject()) + return axObject->attributedStringForTextMarkerRange(WTFMove(markerRange), spellCheck); + return { }; + }); + } + auto nsRange = markerRange.nsRange(); if (!nsRange) return nil; - auto attributedText = propertyValue>(AXPropertyName::AttributedText); - if (!attributedText) - return nil; - if (!attributedStringContainsRange(attributedText.get(), *nsRange)) return nil; diff --git a/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm b/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm index 158857184274..66824f0a1593 100644 --- a/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm +++ b/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm @@ -2804,16 +2804,12 @@ - (NSString*)accessibilityActionDescription:(NSString*)action // The CFAttributedStringType representation of the text associated with this accessibility // object that is specified by the given range. -- (NSAttributedString *)doAXAttributedStringForRange:(NSRange)range +- (NSAttributedString *)attributedStringForNSRange:(const NSRange&)range { - return Accessibility::retrieveAutoreleasedValueFromMainThread([&range, protectedSelf = retainPtr(self)] () -> RetainPtr { - auto* backingObject = protectedSelf.get().axBackingObject; - if (!backingObject) - return nil; - - auto webRange = backingObject->rangeForPlainTextRange(range); - return [protectedSelf attributedStringForTextMarkerRange:textMarkerRangeFromRange(backingObject->axObjectCache(), webRange) spellCheck:AXCoreObject::SpellCheck::Yes]; - }); + auto* backingObject = self.axBackingObject; + if (!backingObject) + return nil; + return backingObject->attributedStringForTextMarkerRange(backingObject->textMarkerRangeForNSRange(range), AXCoreObject::SpellCheck::Yes).autorelease(); } - (NSInteger)_indexForTextMarker:(AXTextMarkerRef)markerRef @@ -2857,9 +2853,9 @@ - (AXTextMarkerRef)_textMarkerForIndex:(NSInteger)textIndex // The RTF representation of the text associated with this accessibility object that is // specified by the given range. -- (NSData *)doAXRTFForRange:(NSRange)range +- (NSData *)rtfForNSRange:(const NSRange&)range { - NSAttributedString *attrString = [self doAXAttributedStringForRange:range]; + NSAttributedString *attrString = [self attributedStringForNSRange:range]; return [attrString RTFFromRange:NSMakeRange(0, attrString.length) documentAttributes:@{ }]; } @@ -3395,6 +3391,7 @@ - (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)paramete auto* cache = backingObject->axObjectCache(); if (!cache) return String(); + auto start = cache->characterOffsetForIndex(range.location, backingObject); auto end = cache->characterOffsetForIndex(range.location + range.length, backingObject); auto range = cache->rangeForUnorderedCharacterOffsets(start, end); @@ -3630,11 +3627,11 @@ - (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)paramete return [NSValue valueWithRect:rect]; } - if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute]) - return rangeSet ? [self doAXRTFForRange:range] : nil; + if ([attribute isEqualToString:(NSString *)kAXRTFForRangeParameterizedAttribute]) + return rangeSet ? [self rtfForNSRange:range] : nil; if ([attribute isEqualToString:(NSString *)kAXAttributedStringForRangeParameterizedAttribute]) - return rangeSet ? [self doAXAttributedStringForRange:range] : nil; + return rangeSet ? [self attributedStringForNSRange:range] : nil; if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) { PlainTextRange textRange = backingObject->doAXStyleRangeForIndex([number intValue]);