AX: Implement relevant simulated key presses for custom ARIA widgets for increment/decrement
https://bugs.webkit.org/show_bug.cgi?id=213744

Reviewed by Darin Adler.

Source/WebCore:

In order to allow custom ARIA widgets to work, we can post keyboard events for specific ax actions
that are not handled natively.

Spec: https://github.com/WICG/aom/blob/gh-pages/explainer.md#user-action-events-from-assistive-technology

Test: accessibility/keyevents-posted-for-increment-actions.html
      accessibility/keyevents-for-increment-actions-with-node-removal.html

* accessibility/AccessibilityNodeObject.cpp:
(WebCore::AccessibilityNodeObject::postKeyboardKeysForValueChange):
(WebCore::AccessibilityNodeObject::setNodeValue):
(WebCore::AccessibilityNodeObject::changeValueByStep):
(WebCore::AccessibilityNodeObject::changeValueByPercent):
* accessibility/AccessibilityNodeObject.h:
* accessibility/AccessibilityObject.h:
* accessibility/AccessibilityObjectInterface.h:
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::setValue):
* accessibility/AccessibilityRenderObject.h:
* accessibility/AccessibilityScrollbar.cpp:
(WebCore::AccessibilityScrollbar::setValue):
* accessibility/AccessibilityScrollbar.h:
* accessibility/AccessibilitySlider.cpp:
(WebCore::AccessibilitySlider::setValue):
* accessibility/AccessibilitySlider.h:
* accessibility/isolatedtree/AXIsolatedObject.cpp:
(WebCore::AXIsolatedObject::setValue):
* accessibility/isolatedtree/AXIsolatedObject.h:

LayoutTests:

* accessibility/keyevents-posted-for-increment-actions-expected.txt: Added.
* accessibility/keyevents-posted-for-increment-actions.html: Added.
* accessibility/keyevents-for-increment-actions-with-node-removal-expected.txt: Added.
* accessibility/keyevents-for-increment-actions-with-node-removal.htmk: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@263823 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 891554f..241ab06 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,15 @@
+2020-07-01  Chris Fleizach  <cfleizach@apple.com>
+
+        AX: Implement relevant simulated key presses for custom ARIA widgets for increment/decrement
+        https://bugs.webkit.org/show_bug.cgi?id=213744
+
+        Reviewed by Darin Adler.
+
+        * accessibility/keyevents-posted-for-increment-actions-expected.txt: Added.
+        * accessibility/keyevents-posted-for-increment-actions.html: Added.
+        * accessibility/keyevents-for-increment-actions-with-node-removal-expected.txt: Added.
+        * accessibility/keyevents-for-increment-actions-with-node-removal.htmk: Added.
+
 2020-07-01  Chris Dumez  <cdumez@apple.com>
 
         [ iOS Debug and Mojave Debug ] http/tests/storage/storage-map-leaking.html is flaky timing out.
diff --git a/LayoutTests/accessibility/keyevents-for-increment-actions-with-node-removal-expected.txt b/LayoutTests/accessibility/keyevents-for-increment-actions-with-node-removal-expected.txt
new file mode 100644
index 0000000..db3c94f
--- /dev/null
+++ b/LayoutTests/accessibility/keyevents-for-increment-actions-with-node-removal-expected.txt
@@ -0,0 +1,10 @@
+This test makes sure if a keydown event removes the node, bad things don't happen.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Keycode received: identifier: right key name: ArrowRight
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/accessibility/keyevents-for-increment-actions-with-node-removal.html b/LayoutTests/accessibility/keyevents-for-increment-actions-with-node-removal.html
new file mode 100644
index 0000000..182fc9ef
--- /dev/null
+++ b/LayoutTests/accessibility/keyevents-for-increment-actions-with-node-removal.html
@@ -0,0 +1,47 @@
+<html>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<div id="slider"
+           role="slider"
+           tabindex="0"
+           aria-valuemin="0"
+           aria-valuenow="0"
+           aria-valuemax="255"
+           aria-labelledby="idRed"></div>
+
+<p id="description"></p>
+<div id="console"></div>
+     
+<script>
+    function handleKeyUp(event) {
+        debug("Key up should NOT be reached");
+    }
+
+    function handleKeyDown(event) {
+        debug("Keycode received: identifier: " + event.keyIdentifier + " key name: " + event.key);
+        document.getElementById("body").removeChild(document.getElementById("slider"));
+        event.preventDefault();
+        event.stopPropagation();
+        finishJSTest();
+    }
+
+    if (window.accessibilityController) {
+        jsTestIsAsync = true;
+        description("This test makes sure if a keydown event removes the node, bad things don't happen.");
+
+        document.getElementById("slider").addEventListener('keydown', handleKeyDown);
+        document.getElementById("slider").addEventListener('keyup', handleKeyUp);
+
+        // Get the parent element.
+        var axSlider = accessibilityController.accessibleElementById("slider");
+        axSlider.increment();
+    }
+ </script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/accessibility/keyevents-posted-for-increment-actions-expected.txt b/LayoutTests/accessibility/keyevents-posted-for-increment-actions-expected.txt
new file mode 100644
index 0000000..653a0d5
--- /dev/null
+++ b/LayoutTests/accessibility/keyevents-posted-for-increment-actions-expected.txt
@@ -0,0 +1,23 @@
+This test verifies that the increment/decrement actions post keyboard events that are correct for LTR and orientation.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Increment/Decrement - LTR
+Horizontal orientation
+Keycode received: identifier: right key name: ArrowRight
+Keycode received: identifier: left key name: ArrowLeft
+Vertical orientation
+Keycode received: identifier: up key name: ArrowUp
+Keycode received: identifier: down key name: ArrowDown
+Increment/Decrement - RTL
+Horizontal orientation
+Keycode received: identifier: left key name: ArrowLeft
+Keycode received: identifier: right key name: ArrowRight
+Vertical orientation
+Keycode received: identifier: up key name: ArrowUp
+Keycode received: identifier: down key name: ArrowDown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/accessibility/keyevents-posted-for-increment-actions.html b/LayoutTests/accessibility/keyevents-posted-for-increment-actions.html
new file mode 100644
index 0000000..3916c4c
--- /dev/null
+++ b/LayoutTests/accessibility/keyevents-posted-for-increment-actions.html
@@ -0,0 +1,63 @@
+<html>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<div id="slider"
+           role="slider"
+           tabindex="0"
+           aria-valuemin="0"
+           aria-valuenow="0"
+           aria-valuemax="255"
+           aria-labelledby="idRed"></div>
+
+<p id="description"></p>
+<div id="console"></div>
+     
+<script>
+    var keyCount = 0;
+    function handleKeyDown(event) {
+        debug("Keycode received: identifier: " + event.keyIdentifier + " key name: " + event.key);
+        event.preventDefault();
+        event.stopPropagation();
+        keyCount++;
+        if (keyCount == 4) {
+            finishJSTest();
+        }
+     }
+
+    if (window.accessibilityController) {
+        jsTestIsAsync = true;
+        description("This test verifies that the increment/decrement actions post keyboard events that are correct for LTR and orientation.");
+
+        document.getElementById("slider").addEventListener('keydown', handleKeyDown);
+
+        // Get the parent element.
+        var axSlider = accessibilityController.accessibleElementById("slider");
+        
+        debug("Increment/Decrement - LTR");    
+        incrementDecrement();
+
+        debug("Increment/Decrement - RTL");
+        window.internals.setUserInterfaceLayoutDirection("RTL");
+        incrementDecrement();
+
+        function incrementDecrement() {
+            debug("Horizontal orientation");
+            document.getElementById("slider").setAttribute("aria-orientation", "horizontal");
+            axSlider.increment();
+            axSlider.decrement();
+
+            debug("Vertical orientation");
+            document.getElementById("slider").setAttribute("aria-orientation", "vertical");
+            axSlider.increment();
+            axSlider.decrement();
+        }
+    }
+ </script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/platform/win/TestExpectations b/LayoutTests/platform/win/TestExpectations
index e260b7c..c106922 100644
--- a/LayoutTests/platform/win/TestExpectations
+++ b/LayoutTests/platform/win/TestExpectations
@@ -1381,6 +1381,10 @@
 accessibility/menu-list-sends-change-notification.html [ Skip ]
 accessibility/multiselect-list-reports-active-option.html [ Skip ]
 
+# increment/decrement not implemented in test runner
+accessibility/keyevents-for-increment-actions-with-node-removal.html [ Skip ]
+accessibility/keyevents-posted-for-increment-actions.html [ Skip ]
+
 webkit.org/b/140796 accessibility/alt-tag-on-image-with-nonimage-role.html [ Skip ]
 webkit.org/b/140798 accessibility/aria-controls-with-tabs.html [ Skip ]
 
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 8f91c32..f8b2c58 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,39 @@
+2020-07-01  Chris Fleizach  <cfleizach@apple.com>
+
+        AX: Implement relevant simulated key presses for custom ARIA widgets for increment/decrement
+        https://bugs.webkit.org/show_bug.cgi?id=213744
+
+        Reviewed by Darin Adler.
+
+        In order to allow custom ARIA widgets to work, we can post keyboard events for specific ax actions
+        that are not handled natively.
+
+        Spec: https://github.com/WICG/aom/blob/gh-pages/explainer.md#user-action-events-from-assistive-technology
+
+        Test: accessibility/keyevents-posted-for-increment-actions.html
+              accessibility/keyevents-for-increment-actions-with-node-removal.html
+
+        * accessibility/AccessibilityNodeObject.cpp:
+        (WebCore::AccessibilityNodeObject::postKeyboardKeysForValueChange):
+        (WebCore::AccessibilityNodeObject::setNodeValue):
+        (WebCore::AccessibilityNodeObject::changeValueByStep):
+        (WebCore::AccessibilityNodeObject::changeValueByPercent):
+        * accessibility/AccessibilityNodeObject.h:
+        * accessibility/AccessibilityObject.h:
+        * accessibility/AccessibilityObjectInterface.h:
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::AccessibilityRenderObject::setValue):
+        * accessibility/AccessibilityRenderObject.h:
+        * accessibility/AccessibilityScrollbar.cpp:
+        (WebCore::AccessibilityScrollbar::setValue):
+        * accessibility/AccessibilityScrollbar.h:
+        * accessibility/AccessibilitySlider.cpp:
+        (WebCore::AccessibilitySlider::setValue):
+        * accessibility/AccessibilitySlider.h:
+        * accessibility/isolatedtree/AXIsolatedObject.cpp:
+        (WebCore::AXIsolatedObject::setValue):
+        * accessibility/isolatedtree/AXIsolatedObject.h:
+
 2020-07-01  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Fix the WebKit build after <rdar://problem/64288191>
diff --git a/Source/WebCore/accessibility/AccessibilityNodeObject.cpp b/Source/WebCore/accessibility/AccessibilityNodeObject.cpp
index 2319a61..29e22bb 100644
--- a/Source/WebCore/accessibility/AccessibilityNodeObject.cpp
+++ b/Source/WebCore/accessibility/AccessibilityNodeObject.cpp
@@ -57,6 +57,7 @@
 #include "HTMLSelectElement.h"
 #include "HTMLTextAreaElement.h"
 #include "HTMLTextFormControlElement.h"
+#include "KeyboardEvent.h"
 #include "LabelableElement.h"
 #include "LocalizedStrings.h"
 #include "MathMLElement.h"
@@ -1094,18 +1095,45 @@
     alterSliderValue(false);
 }
 
+// Fire a keyboard event if we were not able to set this value natively.
+void AccessibilityNodeObject::postKeyboardKeysForValueChange(bool increase)
+{
+    // In case the keyboard event causes this element to be removed.
+    Ref<AccessibilityObject> protectedThis(*this);
+
+    auto keyInit = KeyboardEvent::Init();
+    bool vertical = orientation() == AccessibilityOrientation::Vertical;
+    bool isLTR = page()->userInterfaceLayoutDirection() == UserInterfaceLayoutDirection::LTR;
+    
+    keyInit.key = increase ? vertical ? "ArrowUp"_s : isLTR ? "ArrowRight"_s : "ArrowLeft"_s : vertical ? "ArrowDown"_s : isLTR ? "ArrowLeft"_s : "ArrowRight"_s;
+    keyInit.keyIdentifier = increase ? vertical ? "up"_s : isLTR ? "right"_s : "left"_s : vertical ? "down"_s : isLTR ? "left"_s : "right"_s;
+
+    if (auto* node = this->node())
+        node->dispatchEvent(KeyboardEvent::create(eventNames().keydownEvent, keyInit));
+
+    // Ensure node is still valid and wasn't removed after the keydown.
+    if (auto* node = this->node())
+        node->dispatchEvent(KeyboardEvent::create(eventNames().keyupEvent, keyInit));
+}
+
+void AccessibilityNodeObject::setNodeValue(bool increase, float value)
+{
+    bool didSet = setValue(String::number(value));
+    
+    if (didSet) {
+        if (auto* cache = axObjectCache())
+            cache->postNotification(this, document(), AXObjectCache::AXValueChanged);
+    } else
+        postKeyboardKeysForValueChange(increase);
+}
+
 void AccessibilityNodeObject::changeValueByStep(bool increase)
 {
     float step = stepValueForRange();
     float value = valueForRange();
 
     value += increase ? step : -step;
-
-    setValue(String::number(value));
-
-    auto objectCache = axObjectCache();
-    if (objectCache)
-        objectCache->postNotification(node(), AXObjectCache::AXValueChanged);
+    setNodeValue(increase, value);
 }
 
 void AccessibilityNodeObject::changeValueByPercent(float percentChange)
@@ -1119,11 +1147,7 @@
         step = std::abs(percentChange) * (1 / percentChange);
 
     value += step;
-    setValue(String::number(value));
-
-    auto objectCache = axObjectCache();
-    if (objectCache)
-        objectCache->postNotification(node(), AXObjectCache::AXValueChanged);
+    setNodeValue(percentChange > 0, value);
 }
 
 bool AccessibilityNodeObject::isGenericFocusableElement() const
diff --git a/Source/WebCore/accessibility/AccessibilityNodeObject.h b/Source/WebCore/accessibility/AccessibilityNodeObject.h
index 4e23cba..cb5f61b 100644
--- a/Source/WebCore/accessibility/AccessibilityNodeObject.h
+++ b/Source/WebCore/accessibility/AccessibilityNodeObject.h
@@ -189,7 +189,8 @@
     bool computeAccessibilityIsIgnored() const override;
     bool usesAltTagForTextComputation() const;
     bool roleIgnoresTitle() const;
-    
+    void postKeyboardKeysForValueChange(bool increase);
+    void setNodeValue(bool increase, float value);
     Node* m_node;
 };
 
diff --git a/Source/WebCore/accessibility/AccessibilityObject.h b/Source/WebCore/accessibility/AccessibilityObject.h
index c6e61ce..9538fe4 100644
--- a/Source/WebCore/accessibility/AccessibilityObject.h
+++ b/Source/WebCore/accessibility/AccessibilityObject.h
@@ -463,11 +463,11 @@
     void setFocused(bool) override { }
     void setSelectedText(const String&) override { }
     void setSelectedTextRange(const PlainTextRange&) override { }
-    void setValue(const String&) override { }
+    bool setValue(const String&) override { return false; }
     bool replaceTextInRange(const String&, const PlainTextRange&) override;
     bool insertText(const String&) override;
 
-    void setValue(float) override { }
+    bool setValue(float) override { return false; }
     void setSelected(bool) override { }
     void setSelectedRows(AccessibilityChildrenVector&) override { }
 
diff --git a/Source/WebCore/accessibility/AccessibilityObjectInterface.h b/Source/WebCore/accessibility/AccessibilityObjectInterface.h
index 61a11bb..bea4a7f 100644
--- a/Source/WebCore/accessibility/AccessibilityObjectInterface.h
+++ b/Source/WebCore/accessibility/AccessibilityObjectInterface.h
@@ -896,11 +896,11 @@
     virtual void setFocused(bool) = 0;
     virtual void setSelectedText(const String&) = 0;
     virtual void setSelectedTextRange(const PlainTextRange&) = 0;
-    virtual void setValue(const String&) = 0;
+    virtual bool setValue(const String&) = 0;
     virtual bool replaceTextInRange(const String&, const PlainTextRange&) = 0;
     virtual bool insertText(const String&) = 0;
 
-    virtual void setValue(float) = 0;
+    virtual bool setValue(float) = 0;
     virtual void setSelected(bool) = 0;
     virtual void setSelectedRows(AccessibilityChildrenVector&) = 0;
 
diff --git a/Source/WebCore/accessibility/AccessibilityRenderObject.cpp b/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
index 7370685..3c5ea03 100644
--- a/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
+++ b/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
@@ -1663,8 +1663,15 @@
     } else {
         auto node = this->node();
         ASSERT(node);
+        auto elementRange = this->elementRange();
         VisiblePosition start = visiblePositionForIndexUsingCharacterIterator(*node, range.start);
+        if (!elementRange->contains(start))
+            start = VisiblePosition(elementRange->startPosition());
+        
         VisiblePosition end = visiblePositionForIndexUsingCharacterIterator(*node, range.start + range.length);
+        if (!elementRange->contains(end))
+            end = VisiblePosition(elementRange->endPosition());
+        
         m_renderer->frame().selection().setSelection(VisibleSelection(start, end), FrameSelection::defaultSetSelectionOptions(UserTriggered));
     }
     
@@ -1860,10 +1867,10 @@
         selectedRow->setSelected(true);
 }
     
-void AccessibilityRenderObject::setValue(const String& string)
+bool AccessibilityRenderObject::setValue(const String& string)
 {
     if (!m_renderer || !is<Element>(m_renderer->node()))
-        return;
+        return false;
     
     Element& element = downcast<Element>(*m_renderer->node());
     RenderObject& renderer = *m_renderer;
@@ -1875,14 +1882,20 @@
         if (element.shouldUseInputMethod()) {
             editor.clearText();
             editor.insertText(string, nullptr);
-            return;
+            return true;
         }
     }
     // FIXME: Do we want to do anything here for ARIA textboxes?
-    if (renderer.isTextField() && is<HTMLInputElement>(element))
+    if (renderer.isTextField() && is<HTMLInputElement>(element)) {
         downcast<HTMLInputElement>(element).setValue(string);
-    else if (renderer.isTextArea() && is<HTMLTextAreaElement>(element))
+        return true;
+    }
+    if (renderer.isTextArea() && is<HTMLTextAreaElement>(element)) {
         downcast<HTMLTextAreaElement>(element).setValue(string);
+        return true;
+    }
+    
+    return false;
 }
 
 bool AccessibilityRenderObject::supportsARIAOwns() const
diff --git a/Source/WebCore/accessibility/AccessibilityRenderObject.h b/Source/WebCore/accessibility/AccessibilityRenderObject.h
index 78185e7..9923576 100644
--- a/Source/WebCore/accessibility/AccessibilityRenderObject.h
+++ b/Source/WebCore/accessibility/AccessibilityRenderObject.h
@@ -146,7 +146,7 @@
     
     void setFocused(bool) override;
     void setSelectedTextRange(const PlainTextRange&) override;
-    void setValue(const String&) override;
+    bool setValue(const String&) override;
     void setSelectedRows(AccessibilityChildrenVector&) override;
     AccessibilityOrientation orientation() const override;
 
diff --git a/Source/WebCore/accessibility/AccessibilityScrollbar.cpp b/Source/WebCore/accessibility/AccessibilityScrollbar.cpp
index c08916a..7547f6f 100644
--- a/Source/WebCore/accessibility/AccessibilityScrollbar.cpp
+++ b/Source/WebCore/accessibility/AccessibilityScrollbar.cpp
@@ -92,13 +92,14 @@
     return m_scrollbar->currentPos() / m_scrollbar->maximum();
 }
 
-void AccessibilityScrollbar::setValue(float value)
+bool AccessibilityScrollbar::setValue(float value)
 {
     if (!m_scrollbar)
-        return;
+        return false;
     
     float newValue = value * m_scrollbar->maximum();
     m_scrollbar->scrollableArea().scrollToOffsetWithoutAnimation(m_scrollbar->orientation(), newValue);
+    return true;
 }
     
 } // namespace WebCore
diff --git a/Source/WebCore/accessibility/AccessibilityScrollbar.h b/Source/WebCore/accessibility/AccessibilityScrollbar.h
index 4b0d2e3..fb21ea5 100644
--- a/Source/WebCore/accessibility/AccessibilityScrollbar.h
+++ b/Source/WebCore/accessibility/AccessibilityScrollbar.h
@@ -55,7 +55,7 @@
     bool isEnabled() const override;
     
     // Assumes float [0..1]
-    void setValue(float) override;
+    bool setValue(float) override;
     float valueForRange() const override;
 
     RefPtr<Scrollbar> m_scrollbar;
diff --git a/Source/WebCore/accessibility/AccessibilitySlider.cpp b/Source/WebCore/accessibility/AccessibilitySlider.cpp
index cc6cb81..a1a1479 100644
--- a/Source/WebCore/accessibility/AccessibilitySlider.cpp
+++ b/Source/WebCore/accessibility/AccessibilitySlider.cpp
@@ -126,14 +126,15 @@
     return static_cast<float>(inputElement()->minimum());
 }
 
-void AccessibilitySlider::setValue(const String& value)
+bool AccessibilitySlider::setValue(const String& value)
 {
     HTMLInputElement* input = inputElement();
     
     if (input->value() == value)
-        return;
+        return true;
 
     input->setValue(value, DispatchChangeEvent);
+    return true;
 }
 
 HTMLInputElement* AccessibilitySlider::inputElement() const
diff --git a/Source/WebCore/accessibility/AccessibilitySlider.h b/Source/WebCore/accessibility/AccessibilitySlider.h
index 91c7092..aba9120 100644
--- a/Source/WebCore/accessibility/AccessibilitySlider.h
+++ b/Source/WebCore/accessibility/AccessibilitySlider.h
@@ -57,7 +57,7 @@
     bool canSetValueAttribute() const override { return true; }
     const AtomString& getAttribute(const QualifiedName&) const override;
     
-    void setValue(const String&) override;
+    bool setValue(const String&) override;
     float valueForRange() const override;
     float maxValueForRange() const override;
     float minValueForRange() const override;
diff --git a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp
index 8395be2..061e9a6 100644
--- a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp
+++ b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp
@@ -629,10 +629,22 @@
         object->setIsExpanded(value);
     });
 }
-void AXIsolatedObject::setValue(float value)
+
+bool AXIsolatedObject::setValue(float value)
 {
-    performFunctionOnMainThread([&value](AXCoreObject* object) {
-        object->setValue(value);
+    return Accessibility::retrieveValueFromMainThread<bool>([&value, this] () -> bool {
+        if (auto* axObject = associatedAXObject())
+            return axObject->setValue(value);
+        return false;
+    });
+}
+
+bool AXIsolatedObject::setValue(const String& value)
+{
+    return Accessibility::retrieveValueFromMainThread<bool>([&value, this] () -> bool {
+        if (auto* axObject = associatedAXObject())
+            return axObject->setValue(value);
+        return false;
     });
 }
 
@@ -671,13 +683,6 @@
     });
 }
 
-void AXIsolatedObject::setValue(const String& value)
-{
-    performFunctionOnMainThread([&value](AXCoreObject* object) {
-        object->setValue(value);
-    });
-}
-
 #if PLATFORM(COCOA) && !PLATFORM(IOS_FAMILY)
 void AXIsolatedObject::setCaretBrowsingEnabled(bool value)
 {
diff --git a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h
index 2e6b7ef..2a199fe 100644
--- a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h
+++ b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h
@@ -703,13 +703,13 @@
     // Attribute setters.
     void setARIAGrabbed(bool) override;
     void setIsExpanded(bool) override;
-    void setValue(float) override;
+    bool setValue(float) override;
     void setSelected(bool) override;
     void setSelectedRows(AccessibilityChildrenVector&) override;
     void setFocused(bool) override;
     void setSelectedText(const String&) override;
     void setSelectedTextRange(const PlainTextRange&) override;
-    void setValue(const String&) override;
+    bool setValue(const String&) override;
 #if PLATFORM(COCOA) && !PLATFORM(IOS_FAMILY)
     void setCaretBrowsingEnabled(bool) override;
 #endif