IsolatedObject support for multiple parameterized attributes.
authorandresg_22@apple.com <andresg_22@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 Dec 2019 20:33:20 +0000 (20:33 +0000)
committerandresg_22@apple.com <andresg_22@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 Dec 2019 20:33:20 +0000 (20:33 +0000)
https://bugs.webkit.org/show_bug.cgi?id=205508

Reviewed by Chris Fleizach.

- AXObjectCache now keeps the PageIdentifier so that it is possible to
retrieve it on the secondary thread without querying the Document.
- isIncrementor is exposed on AXCoreObject for spin button support.
- Several parameterized attributes implementation related to
TextMarkers are now dispatch to the main thread.

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::AXObjectCache):
(WebCore::AXObjectCache::setIsolatedTreeFocusedObject):
(WebCore::AXObjectCache::isolatedTreeRootObject):
(WebCore::AXObjectCache::remove):
* accessibility/AXObjectCache.h:
* accessibility/AccessibilityObject.h:
* accessibility/AccessibilityObjectInterface.h:
* accessibility/AccessibilitySpinButton.h:
* accessibility/isolatedtree/AXIsolatedTreeNode.cpp:
(WebCore::AXIsolatedObject::AXIsolatedObject):
(WebCore::AXIsolatedObject::initializeAttributeData):
(WebCore::AXIsolatedObject::updateBackingStore):
(WebCore::AXIsolatedObject::findTextRanges const):
(WebCore::AXIsolatedObject::performTextOperation):
(WebCore::AXIsolatedObject::axObjectCache const):
(WebCore::AXIsolatedObject::widget const):
(WebCore::AXIsolatedObject::document const):
(WebCore::AXIsolatedObject::documentFrameView const):
(WebCore::AXIsolatedObject::isLoaded const): Implemented in header.
(WebCore::AXIsolatedObject::supportsPath const): Implemented in header.
* accessibility/isolatedtree/AXIsolatedTreeNode.h:
* accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
(-[WebAccessibilityObjectWrapper subrole]):
(-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):

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

Source/WebCore/ChangeLog
Source/WebCore/accessibility/AXObjectCache.cpp
Source/WebCore/accessibility/AXObjectCache.h
Source/WebCore/accessibility/AccessibilityObject.h
Source/WebCore/accessibility/AccessibilityObjectInterface.h
Source/WebCore/accessibility/AccessibilitySpinButton.h
Source/WebCore/accessibility/isolatedtree/AXIsolatedTreeNode.cpp
Source/WebCore/accessibility/isolatedtree/AXIsolatedTreeNode.h
Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm

index 57f4de4..eab4aaa 100644 (file)
@@ -1,3 +1,42 @@
+2019-12-20  Andres Gonzalez  <andresg_22@apple.com>
+
+        IsolatedObject support for multiple parameterized attributes.
+        https://bugs.webkit.org/show_bug.cgi?id=205508
+
+        Reviewed by Chris Fleizach.
+
+        - AXObjectCache now keeps the PageIdentifier so that it is possible to
+        retrieve it on the secondary thread without querying the Document.
+        - isIncrementor is exposed on AXCoreObject for spin button support.
+        - Several parameterized attributes implementation related to
+        TextMarkers are now dispatch to the main thread.
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::AXObjectCache):
+        (WebCore::AXObjectCache::setIsolatedTreeFocusedObject):
+        (WebCore::AXObjectCache::isolatedTreeRootObject):
+        (WebCore::AXObjectCache::remove):
+        * accessibility/AXObjectCache.h:
+        * accessibility/AccessibilityObject.h:
+        * accessibility/AccessibilityObjectInterface.h:
+        * accessibility/AccessibilitySpinButton.h:
+        * accessibility/isolatedtree/AXIsolatedTreeNode.cpp:
+        (WebCore::AXIsolatedObject::AXIsolatedObject):
+        (WebCore::AXIsolatedObject::initializeAttributeData):
+        (WebCore::AXIsolatedObject::updateBackingStore):
+        (WebCore::AXIsolatedObject::findTextRanges const):
+        (WebCore::AXIsolatedObject::performTextOperation):
+        (WebCore::AXIsolatedObject::axObjectCache const):
+        (WebCore::AXIsolatedObject::widget const):
+        (WebCore::AXIsolatedObject::document const):
+        (WebCore::AXIsolatedObject::documentFrameView const):
+        (WebCore::AXIsolatedObject::isLoaded const): Implemented in header.
+        (WebCore::AXIsolatedObject::supportsPath const): Implemented in header.
+        * accessibility/isolatedtree/AXIsolatedTreeNode.h:
+        * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+        (-[WebAccessibilityObjectWrapper subrole]):
+        (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:forParameter:]):
+
 2019-12-20  Daniel Bates  <dabates@apple.com>
 
         Share code for computing the absolute positioned line boxes for a range
index f86f373..b09ff8f 100644 (file)
@@ -214,6 +214,7 @@ void AXObjectCache::setEnhancedUserInterfaceAccessibility(bool flag)
 
 AXObjectCache::AXObjectCache(Document& document)
     : m_document(document)
+    , m_pageID(document.pageID())
     , m_notificationPostTimer(*this, &AXObjectCache::notificationPostTimerFired)
     , m_passwordNotificationPostTimer(*this, &AXObjectCache::passwordNotificationPostTimerFired)
     , m_liveRegionChangedPostTimer(*this, &AXObjectCache::liveRegionChangedNotificationPostTimerFired)
@@ -401,12 +402,12 @@ AXCoreObject* AXObjectCache::isolatedTreeFocusedObject(Document& document)
 void AXObjectCache::setIsolatedTreeFocusedObject(Node* focusedNode)
 {
     ASSERT(isMainThread());
-    auto* focus = getOrCreate(focusedNode);
-    auto pageID = m_document.pageID();
-    if (!pageID)
+    if (!m_pageID)
         return;
 
-    if (auto tree = AXIsolatedTree::treeForPageID(*pageID))
+    auto* focus = getOrCreate(focusedNode);
+
+    if (auto tree = AXIsolatedTree::treeForPageID(*m_pageID))
         tree->setFocusedNodeID(focus ? focus->objectID() : InvalidAXID);
 }
 #endif
@@ -735,14 +736,12 @@ AXCoreObject* AXObjectCache::rootObject()
 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
 AXCoreObject* AXObjectCache::isolatedTreeRootObject()
 {
-    ASSERT(isMainThread());
-    auto pageID = m_document.pageID();
-    if (!pageID)
+    if (!m_pageID)
         return nullptr;
 
-    auto tree = AXIsolatedTree::treeForPageID(*pageID);
-    if (!tree) {
-        tree = generateIsolatedTree(*pageID, m_document);
+    auto tree = AXIsolatedTree::treeForPageID(*m_pageID);
+    if (!tree && isMainThread()) {
+        tree = generateIsolatedTree(*m_pageID, m_document);
         // Now that we have created our tree, initialize the secondary thread,
         // so future requests come in on the other thread.
         _AXUIElementUseSecondaryAXThread(true);
@@ -845,8 +844,8 @@ void AXObjectCache::remove(AXID axID)
 
     m_idsInUse.remove(axID);
 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
-    if (auto pageID = m_document.pageID()) {
-        if (auto tree = AXIsolatedTree::treeForPageID(*pageID))
+    if (m_pageID) {
+        if (auto tree = AXIsolatedTree::treeForPageID(*m_pageID))
             tree->removeNode(axID);
     }
 #endif
index 802a755..e604ecb 100644 (file)
@@ -25,9 +25,6 @@
 
 #pragma once
 
-#if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
-#include "AXIsolatedTree.h"
-#endif
 #include "AXTextStateChangeIntent.h"
 #include "AccessibilityObject.h"
 #include "Range.h"
@@ -48,6 +45,7 @@ namespace WebCore {
 
 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
 class AXIsolatedObject;
+class AXIsolatedTree;
 #endif
 class Document;
 class HTMLAreaElement;
@@ -453,6 +451,7 @@ private:
     void handleModalChange(Node*);
 
     Document& m_document;
+    const Optional<PageIdentifier> m_pageID; // constant for object's lifetime.
     HashMap<AXID, RefPtr<AccessibilityObject>> m_objects;
     HashMap<RenderObject*, AXID> m_renderObjectMapping;
     HashMap<Widget*, AXID> m_widgetObjectMapping;
index fe44e44..8a73ae6 100644 (file)
@@ -167,6 +167,7 @@ public:
     AXCoreObject* incrementButton() override { return nullptr; }
     AXCoreObject* decrementButton() override { return nullptr; }
     bool isSpinButtonPart() const override { return false; }
+    bool isIncrementor() const override { return false; }
     bool isMockObject() const override { return false; }
     virtual bool isMediaControlLabel() const { return false; }
     bool isMediaObject() const override { return false; }
index adb0d94..c503131 100644 (file)
@@ -543,6 +543,7 @@ public:
     virtual AXCoreObject* incrementButton() = 0;
     virtual AXCoreObject* decrementButton() = 0;
     virtual bool isSpinButtonPart() const = 0;
+    virtual bool isIncrementor() const = 0;
 
     virtual bool isMockObject() const = 0;
     virtual bool isMediaObject() const = 0;
index 99d0bd4..662df95 100644 (file)
@@ -58,7 +58,7 @@ public:
     static Ref<AccessibilitySpinButtonPart> create();
     virtual ~AccessibilitySpinButtonPart() = default;
     
-    bool isIncrementor() const { return m_isIncrementor; }
+    bool isIncrementor() const override { return m_isIncrementor; }
     void setIsIncrementor(bool value) { m_isIncrementor = value; }
     
 private:
index 0b576ae..a5493cc 100644 (file)
@@ -28,8 +28,6 @@
 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
 #include "AXIsolatedTreeNode.h"
 
-#include "AccessibilityObject.h"
-
 namespace WebCore {
 
 AXIsolatedObject::AXIsolatedObject(AXCoreObject& object, bool isRoot)
@@ -37,9 +35,7 @@ AXIsolatedObject::AXIsolatedObject(AXCoreObject& object, bool isRoot)
 {
     ASSERT(isMainThread());
     initializeAttributeData(object, isRoot);
-#if !ASSERT_DISABLED
     m_initialized = true;
-#endif
 }
 
 Ref<AXIsolatedObject> AXIsolatedObject::create(AXCoreObject& object, bool isRoot)
@@ -160,6 +156,7 @@ void AXIsolatedObject::initializeAttributeData(AXCoreObject& object, bool isRoot
     setProperty(AXPropertyName::SupportsCurrent, object.supportsCurrent());
     setProperty(AXPropertyName::KeyShortcutsValue, object.keyShortcutsValue());
     setProperty(AXPropertyName::SupportsSetSize, object.supportsSetSize());
+    setProperty(AXPropertyName::SupportsPath, object.supportsPath());
     setProperty(AXPropertyName::SupportsPosInSet, object.supportsPosInSet());
     setProperty(AXPropertyName::SetSize, object.setSize());
     setProperty(AXPropertyName::PosInSet, object.posInSet());
@@ -270,8 +267,10 @@ void AXIsolatedObject::initializeAttributeData(AXCoreObject& object, bool isRoot
     }
     setProperty(AXPropertyName::AccessibilityText, isolatedTexts);
 
+    // Spin button support.
     setObjectProperty(AXPropertyName::DecrementButton, object.decrementButton());
     setObjectProperty(AXPropertyName::IncrementButton, object.incrementButton());
+    setProperty(AXPropertyName::IsIncrementor, object.isIncrementor());
 
     Vector<String> classList;
     object.classList(classList);
@@ -688,7 +687,9 @@ void AXIsolatedObject::fillChildrenVectorForProperty(AXPropertyName propertyName
 
 void AXIsolatedObject::updateBackingStore()
 {
-    ASSERT(!isMainThread());
+    // This method can be called on either the main or the AX threads.
+    // It can be called in the main thread from [WebAccessibilityObjectWrapper accessibilityFocusedUIElement].
+    // Update the IsolatedTree only if it is called on the AX thread.
     if (!isMainThread()) {
         if (auto tree = this->tree())
             tree->applyPendingChanges();
@@ -697,15 +698,15 @@ void AXIsolatedObject::updateBackingStore()
 
 Vector<RefPtr<Range>> AXIsolatedObject::findTextRanges(AccessibilitySearchTextCriteria const& criteria) const
 {
-    return Accessibility::retrieveValueFromMainThread<Vector<RefPtr<Range>>>([&criteria, axID = objectID(), this] () -> Vector<RefPtr<Range>> {
-        return axObjectCache()->objectFromAXID(axID)->findTextRanges(criteria);
+    return Accessibility::retrieveValueFromMainThread<Vector<RefPtr<Range>>>([&criteria, this] () -> Vector<RefPtr<Range>> {
+        return associatedAXObject()->findTextRanges(criteria);
     });
 }
 
 Vector<String> AXIsolatedObject::performTextOperation(AccessibilityTextOperation const& textOperation)
 {
-    return Accessibility::retrieveValueFromMainThread<Vector<String>>([&textOperation, axID = objectID(), this] () -> Vector<String> {
-        return axObjectCache()->objectFromAXID(axID)->performTextOperation(textOperation);
+    return Accessibility::retrieveValueFromMainThread<Vector<String>>([&textOperation, this] () -> Vector<String> {
+        return associatedAXObject()->performTextOperation(textOperation);
     });
 }
 
@@ -943,12 +944,6 @@ bool AXIsolatedObject::isIndeterminate() const
     return false;
 }
 
-bool AXIsolatedObject::isLoaded() const
-{
-    ASSERT_NOT_REACHED();
-    return false;
-}
-
 bool AXIsolatedObject::isOnScreen() const
 {
     ASSERT_NOT_REACHED();
@@ -1359,6 +1354,7 @@ void AXIsolatedObject::elementsFromAttribute(Vector<Element*>&, const QualifiedN
 
 AXObjectCache* AXIsolatedObject::axObjectCache() const
 {
+    ASSERT(isMainThread());
     return tree()->axObjectCache();
 }
 
@@ -1380,12 +1376,6 @@ Path AXIsolatedObject::elementPath() const
     return Path();
 }
 
-bool AXIsolatedObject::supportsPath() const
-{
-    ASSERT_NOT_REACHED();
-    return false;
-}
-
 TextIteratorBehavior AXIsolatedObject::textIteratorBehaviorForTextRange() const
 {
     ASSERT_NOT_REACHED();
@@ -1394,8 +1384,7 @@ TextIteratorBehavior AXIsolatedObject::textIteratorBehaviorForTextRange() const
 
 Widget* AXIsolatedObject::widget() const
 {
-    ASSERT_NOT_REACHED();
-    return nullptr;
+    return associatedAXObject()->widget();
 }
 
 Widget* AXIsolatedObject::widgetForAttachmentView() const
@@ -1412,14 +1401,12 @@ Page* AXIsolatedObject::page() const
 
 Document* AXIsolatedObject::document() const
 {
-    ASSERT_NOT_REACHED();
-    return nullptr;
+    return associatedAXObject()->document();
 }
 
 FrameView* AXIsolatedObject::documentFrameView() const
 {
-    ASSERT_NOT_REACHED();
-    return nullptr;
+    return associatedAXObject()->documentFrameView();
 }
 
 Frame* AXIsolatedObject::frame() const
index 2ced3b7..8573b04 100644 (file)
@@ -27,7 +27,7 @@
 
 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
 
-#include "AXIsolatedTree.h"
+#include "AXObjectCache.h"
 #include "AccessibilityObjectInterface.h"
 #include "IntPoint.h"
 #include "LayoutRect.h"
@@ -72,7 +72,8 @@ private:
     AXIsolatedObject() = default;
     AXIsolatedObject(AXCoreObject&, bool isRoot);
     void initializeAttributeData(AXCoreObject&, bool isRoot);
-    
+    AXCoreObject* associatedAXObject() const { return axObjectCache()->objectFromAXID(objectID()); }
+
     enum class AXPropertyName : uint8_t {
         None = 0,
         AccessKey,
@@ -152,6 +153,7 @@ private:
         IsGroup,
         IsImage,
         IsImageMapLink,
+        IsIncrementor,
         IsIndeterminate,
         IsInlineText,
         IsInputImage,
@@ -272,9 +274,10 @@ private:
         SupportsExpanded,
         SupportsExpandedTextValue,
         SupportsLiveRegion,
-        SupportsRangeValue,
+        SupportsPath,
         SupportsPosInSet,
         SupportsPressAction,
+        SupportsRangeValue,
         SupportsRequiredAttribute,
         SupportsSetSize,
         TabChildren,
@@ -522,8 +525,10 @@ private:
     bool liveRegionAtomic() const override { return boolAttributeValue(AXPropertyName::LiveRegionAtomic); }
     bool isBusy() const override { return boolAttributeValue(AXPropertyName::IsBusy); }
     bool isInlineText() const override { return boolAttributeValue(AXPropertyName::IsInlineText); }
+    // Spin button support.
     AXCoreObject* incrementButton() override { return objectAttributeValue(AXPropertyName::IncrementButton); }
     AXCoreObject* decrementButton() override { return objectAttributeValue(AXPropertyName::DecrementButton); }
+    bool isIncrementor() const override { return boolAttributeValue(AXPropertyName::IsIncrementor); }
 
     // Parameterized attribute retrieval.
     Vector<RefPtr<Range>> findTextRanges(AccessibilitySearchTextCriteria const&) const override;
@@ -652,7 +657,7 @@ private:
     bool isKeyboardFocusable() const override;
     bool isHovered() const override;
     bool isIndeterminate() const override;
-    bool isLoaded() const override;
+    bool isLoaded() const override { return boolAttributeValue(AXPropertyName::IsLoaded); }
     bool isOnScreen() const override;
     bool isOffScreen() const override;
     bool isPressed() const override;
@@ -727,7 +732,7 @@ private:
     Element* anchorElement() const override;
     Element* actionElement() const override;
     Path elementPath() const override;
-    bool supportsPath() const override;
+    bool supportsPath() const override { return boolAttributeValue(AXPropertyName::SupportsPath); }
     TextIteratorBehavior textIteratorBehaviorForTextRange() const override;
     Widget* widget() const override;
     Widget* widgetForAttachmentView() const override;
index 6f28617..b399e67 100644 (file)
@@ -2075,10 +2075,9 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN
     if (role == AccessibilityRole::Footer)
         return @"AXFooter";
 
-    if (is<AccessibilitySpinButtonPart>(*m_object)) {
-        if (downcast<AccessibilitySpinButtonPart>(*m_object).isIncrementor())
+    if (m_object->roleValue() == AccessibilityRole::SpinButtonPart) {
+        if (m_object->isIncrementor())
             return NSAccessibilityIncrementArrowSubrole;
-        
         return NSAccessibilityDecrementArrowSubrole;
     }
     
@@ -3863,10 +3862,6 @@ ALLOW_DEPRECATED_IMPLEMENTATIONS_END
     if (![self updateObjectBackingStore])
         return nil;
     
-    AXObjectCache* cache = m_object->axObjectCache();
-    if (!cache)
-        return nil;
-    
     // common parameter type check/casting.  Nil checks in handlers catch wrong type case.
     // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
     // a parameter of the wrong type.
@@ -3960,16 +3955,29 @@ ALLOW_DEPRECATED_IMPLEMENTATIONS_END
     }
 
     if ([attribute isEqualToString:NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute]) {
-        IntRect webCoreRect = [self screenToContents:enclosingIntRect(rect)];
-        CharacterOffset characterOffset = cache->characterOffsetForBounds(webCoreRect, false);
-        return [self textMarkerForCharacterOffset:characterOffset];
+        return Accessibility::retrieveValueFromMainThread<id>([&rect, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            IntRect webCoreRect = [protectedSelf screenToContents:enclosingIntRect(rect)];
+            CharacterOffset characterOffset = cache->characterOffsetForBounds(webCoreRect, false);
+            return [protectedSelf textMarkerForCharacterOffset:characterOffset];
+        });
     }
+
     if ([attribute isEqualToString:NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute]) {
-        IntRect webCoreRect = [self screenToContents:enclosingIntRect(rect)];
-        CharacterOffset characterOffset = cache->characterOffsetForBounds(webCoreRect, true);
-        return [self textMarkerForCharacterOffset:characterOffset];
+        return Accessibility::retrieveValueFromMainThread<id>([&rect, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            IntRect webCoreRect = [protectedSelf screenToContents:enclosingIntRect(rect)];
+            CharacterOffset characterOffset = cache->characterOffsetForBounds(webCoreRect, true);
+            return [protectedSelf textMarkerForCharacterOffset:characterOffset];
+        });
     }
-    
+
     if ([attribute isEqualToString:NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute]) {
         VisiblePosition visiblePosition = [self visiblePositionForTextMarker:textMarker];
         VisiblePositionRange visiblePositionRange = m_object->lineRangeForPosition(visiblePosition);
@@ -4024,45 +4032,66 @@ ALLOW_DEPRECATED_IMPLEMENTATIONS_END
         RefPtr<Range> range = [self rangeForTextMarkerRange:textMarkerRange];
         return m_object->stringForRange(range);
     }
-    
+
     if ([attribute isEqualToString:@"AXTextMarkerForPosition"]) {
         IntPoint webCorePoint = IntPoint(point);
         if (!pointSet)
             return nil;
-        CharacterOffset characterOffset = cache->characterOffsetForPoint(webCorePoint, m_object);
-        return [self textMarkerForCharacterOffset:characterOffset];
+
+        return Accessibility::retrieveValueFromMainThread<id>([&webCorePoint, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            CharacterOffset characterOffset = cache->characterOffsetForPoint(webCorePoint, protectedSelf->m_object);
+            return [protectedSelf textMarkerForCharacterOffset:characterOffset];
+        });
     }
-    
+
     if ([attribute isEqualToString:@"AXBoundsForTextMarkerRange"]) {
         RefPtr<Range> range = [self rangeForTextMarkerRange:textMarkerRange];
         auto bounds = FloatRect(m_object->boundsForRange(range));
         NSRect rect = [self convertRectToSpace:bounds space:AccessibilityConversionSpace::Screen];
         return [NSValue valueWithRect:rect];
     }
-    
+
     if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
-        CharacterOffset start = cache->characterOffsetForIndex(range.location, m_object);
-        CharacterOffset end = cache->characterOffsetForIndex(range.location+range.length, m_object);
-        if (start.isNull() || end.isNull())
-            return nil;
-        RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(start, end);
-        auto bounds = FloatRect(m_object->boundsForRange(range));
-        NSRect rect = [self convertRectToSpace:bounds space:AccessibilityConversionSpace::Screen];
+        NSRect rect = Accessibility::retrieveValueFromMainThread<NSRect>([&range, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> NSRect {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return CGRectZero;
+
+            CharacterOffset start = cache->characterOffsetForIndex(range.location, protectedSelf->m_object);
+            CharacterOffset end = cache->characterOffsetForIndex(range.location+range.length, protectedSelf->m_object);
+            if (start.isNull() || end.isNull())
+                return CGRectZero;
+
+            RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(start, end);
+            auto bounds = FloatRect(protectedSelf->m_object->boundsForRange(range));
+            return [protectedSelf convertRectToSpace:bounds space:AccessibilityConversionSpace::Screen];
+        });
         return [NSValue valueWithRect:rect];
     }
-    
+
     if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
         if (m_object->isTextControl()) {
             PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
             return m_object->doAXStringForRange(plainTextRange);
         }
-        
-        CharacterOffset start = cache->characterOffsetForIndex(range.location, m_object);
-        CharacterOffset end = cache->characterOffsetForIndex(range.location + range.length, m_object);
-        if (start.isNull() || end.isNull())
-            return nil;
-        RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(start, end);
-        return m_object->stringForRange(range);
+
+        return Accessibility::retrieveValueFromMainThread<NSString *>([&range, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> NSString * {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            CharacterOffset start = cache->characterOffsetForIndex(range.location, protectedSelf->m_object);
+            CharacterOffset end = cache->characterOffsetForIndex(range.location + range.length, protectedSelf->m_object);
+            if (start.isNull() || end.isNull())
+                return nil;
+
+            RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(start, end);
+            return protectedSelf->m_object->stringForRange(range);
+        });
     }
 
     if ([attribute isEqualToString:@"AXAttributedStringForTextMarkerRange"])
@@ -4088,18 +4117,24 @@ ALLOW_DEPRECATED_IMPLEMENTATIONS_END
     if ([attribute isEqualToString:@"AXTextMarkerRangeForUnorderedTextMarkers"]) {
         if ([array count] < 2)
             return nil;
-        
+
         id textMarker1 = [array objectAtIndex:0];
         id textMarker2 = [array objectAtIndex:1];
         if (!AXObjectIsTextMarker(textMarker1) || !AXObjectIsTextMarker(textMarker2))
             return nil;
-        
-        CharacterOffset characterOffset1 = [self characterOffsetForTextMarker:textMarker1];
-        CharacterOffset characterOffset2 = [self characterOffsetForTextMarker:textMarker2];
-        RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(characterOffset1, characterOffset2);
-        return [self textMarkerRangeFromRange:range];
+
+        return Accessibility::retrieveValueFromMainThread<id>([textMarker1, textMarker2, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            CharacterOffset characterOffset1 = [protectedSelf characterOffsetForTextMarker:textMarker1];
+            CharacterOffset characterOffset2 = [protectedSelf characterOffsetForTextMarker:textMarker2];
+            RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(characterOffset1, characterOffset2);
+            return [protectedSelf textMarkerRangeFromRange:range];
+        });
     }
-    
+
     if ([attribute isEqualToString:@"AXNextTextMarkerForTextMarker"]) {
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
         return [self nextTextMarkerForCharacterOffset:characterOffset];
@@ -4109,19 +4144,31 @@ ALLOW_DEPRECATED_IMPLEMENTATIONS_END
         CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
         return [self previousTextMarkerForCharacterOffset:characterOffset];
     }
-    
+
     if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) {
-        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
-        RefPtr<Range> range = cache->leftWordRange(characterOffset);
-        return [self textMarkerRangeFromRange:range];
+        return Accessibility::retrieveValueFromMainThread<id>([textMarker, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            CharacterOffset characterOffset = [protectedSelf characterOffsetForTextMarker:textMarker];
+            RefPtr<Range> range = cache->leftWordRange(characterOffset);
+            return [protectedSelf textMarkerRangeFromRange:range];
+        });
     }
-    
+
     if ([attribute isEqualToString:@"AXRightWordTextMarkerRangeForTextMarker"]) {
-        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
-        RefPtr<Range> range = cache->rightWordRange(characterOffset);
-        return [self textMarkerRangeFromRange:range];
+        return Accessibility::retrieveValueFromMainThread<id>([textMarker, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            CharacterOffset characterOffset = [protectedSelf characterOffsetForTextMarker:textMarker];
+            RefPtr<Range> range = cache->rightWordRange(characterOffset);
+            return [protectedSelf textMarkerRangeFromRange:range];
+        });
     }
-    
+
     if ([attribute isEqualToString:@"AXLeftLineTextMarkerRangeForTextMarker"]) {
         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
         VisiblePositionRange vpRange = m_object->leftLineVisiblePositionRange(visiblePos);
@@ -4133,31 +4180,55 @@ ALLOW_DEPRECATED_IMPLEMENTATIONS_END
         VisiblePositionRange vpRange = m_object->rightLineVisiblePositionRange(visiblePos);
         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
     }
-    
+
     if ([attribute isEqualToString:@"AXSentenceTextMarkerRangeForTextMarker"]) {
-        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
-        RefPtr<Range> range = cache->sentenceForCharacterOffset(characterOffset);
-        return [self textMarkerRangeFromRange:range];
+        return Accessibility::retrieveValueFromMainThread<id>([textMarker, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            CharacterOffset characterOffset = [protectedSelf characterOffsetForTextMarker:textMarker];
+            RefPtr<Range> range = cache->sentenceForCharacterOffset(characterOffset);
+            return [protectedSelf textMarkerRangeFromRange:range];
+        });
     }
-    
+
     if ([attribute isEqualToString:@"AXParagraphTextMarkerRangeForTextMarker"]) {
-        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
-        RefPtr<Range> range = cache->paragraphForCharacterOffset(characterOffset);
-        return [self textMarkerRangeFromRange:range];
+        return Accessibility::retrieveValueFromMainThread<id>([textMarker, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            CharacterOffset characterOffset = [protectedSelf characterOffsetForTextMarker:textMarker];
+            RefPtr<Range> range = cache->paragraphForCharacterOffset(characterOffset);
+            return [protectedSelf textMarkerRangeFromRange:range];
+        });
     }
-    
+
     if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"]) {
-        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
-        CharacterOffset nextEnd = cache->nextWordEndCharacterOffset(characterOffset);
-        return [self textMarkerForCharacterOffset:nextEnd];
+        return Accessibility::retrieveValueFromMainThread<id>([textMarker, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            CharacterOffset characterOffset = [protectedSelf characterOffsetForTextMarker:textMarker];
+            CharacterOffset nextEnd = cache->nextWordEndCharacterOffset(characterOffset);
+            return [protectedSelf textMarkerForCharacterOffset:nextEnd];
+        });
     }
-    
+
     if ([attribute isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) {
-        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
-        CharacterOffset previousStart = cache->previousWordStartCharacterOffset(characterOffset);
-        return [self textMarkerForCharacterOffset:previousStart];
+        return Accessibility::retrieveValueFromMainThread<id>([textMarker, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            CharacterOffset characterOffset = [protectedSelf characterOffsetForTextMarker:textMarker];
+            CharacterOffset previousStart = cache->previousWordStartCharacterOffset(characterOffset);
+            return [protectedSelf textMarkerForCharacterOffset:previousStart];
+        });
     }
-    
+
     if ([attribute isEqualToString:@"AXNextLineEndTextMarkerForTextMarker"]) {
         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
         return [self textMarkerForVisiblePosition:m_object->nextLineEndPosition(visiblePos)];
@@ -4169,29 +4240,53 @@ ALLOW_DEPRECATED_IMPLEMENTATIONS_END
     }
     
     if ([attribute isEqualToString:@"AXNextSentenceEndTextMarkerForTextMarker"]) {
-        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
-        CharacterOffset nextEnd = cache->nextSentenceEndCharacterOffset(characterOffset);
-        return [self textMarkerForCharacterOffset:nextEnd];
+        return Accessibility::retrieveValueFromMainThread<id>([textMarker, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+            
+            CharacterOffset characterOffset = [protectedSelf characterOffsetForTextMarker:textMarker];
+            CharacterOffset nextEnd = cache->nextSentenceEndCharacterOffset(characterOffset);
+            return [protectedSelf textMarkerForCharacterOffset:nextEnd];
+        });
     }
-    
+
     if ([attribute isEqualToString:@"AXPreviousSentenceStartTextMarkerForTextMarker"]) {
-        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
-        CharacterOffset previousStart = cache->previousSentenceStartCharacterOffset(characterOffset);
-        return [self textMarkerForCharacterOffset:previousStart];
+        return Accessibility::retrieveValueFromMainThread<id>([textMarker, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            CharacterOffset characterOffset = [protectedSelf characterOffsetForTextMarker:textMarker];
+            CharacterOffset previousStart = cache->previousSentenceStartCharacterOffset(characterOffset);
+            return [protectedSelf textMarkerForCharacterOffset:previousStart];
+        });
     }
-    
+
     if ([attribute isEqualToString:@"AXNextParagraphEndTextMarkerForTextMarker"]) {
-        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
-        CharacterOffset nextEnd = cache->nextParagraphEndCharacterOffset(characterOffset);
-        return [self textMarkerForCharacterOffset:nextEnd];
+        return Accessibility::retrieveValueFromMainThread<id>([textMarker, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            CharacterOffset characterOffset = [protectedSelf characterOffsetForTextMarker:textMarker];
+            CharacterOffset nextEnd = cache->nextParagraphEndCharacterOffset(characterOffset);
+            return [protectedSelf textMarkerForCharacterOffset:nextEnd];
+        });
     }
-    
+
     if ([attribute isEqualToString:@"AXPreviousParagraphStartTextMarkerForTextMarker"]) {
-        CharacterOffset characterOffset = [self characterOffsetForTextMarker:textMarker];
-        CharacterOffset previousStart = cache->previousParagraphStartCharacterOffset(characterOffset);
-        return [self textMarkerForCharacterOffset:previousStart];
+        return Accessibility::retrieveValueFromMainThread<id>([textMarker, protectedSelf = RetainPtr<WebAccessibilityObjectWrapper>(self)] () -> id {
+            auto* cache = protectedSelf->m_object->axObjectCache();
+            if (!cache)
+                return nil;
+
+            CharacterOffset characterOffset = [protectedSelf characterOffsetForTextMarker:textMarker];
+            CharacterOffset previousStart = cache->previousParagraphStartCharacterOffset(characterOffset);
+            return [protectedSelf textMarkerForCharacterOffset:previousStart];
+        });
     }
-    
+
     if ([attribute isEqualToString:@"AXStyleTextMarkerRangeForTextMarker"]) {
         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
         VisiblePositionRange vpRange = m_object->styleRangeForPosition(visiblePos);