<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[286116] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/286116">286116</a></dd>
<dt>Author</dt> <dd>cfleizach@apple.com</dd>
<dt>Date</dt> <dd>2021-11-22 12:34:19 -0800 (Mon, 22 Nov 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>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.

Source/WebCore:

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.

LayoutTests:

* 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:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsplatformiosTestExpectations">trunk/LayoutTests/platform/ios/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsplatformmacwk1TestExpectations">trunk/LayoutTests/platform/mac-wk1/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsplatformwinTestExpectations">trunk/LayoutTests/platform/win/TestExpectations</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreaccessibilityAccessibilityObjectcpp">trunk/Source/WebCore/accessibility/AccessibilityObject.cpp</a></li>
<li><a href="#trunkSourceWebCoreaccessibilityAccessibilityObjecth">trunk/Source/WebCore/accessibility/AccessibilityObject.h</a></li>
<li><a href="#trunkSourceWebCoreaccessibilityAccessibilityObjectInterfaceh">trunk/Source/WebCore/accessibility/AccessibilityObjectInterface.h</a></li>
<li><a href="#trunkSourceWebCoreaccessibilityiosWebAccessibilityObjectWrapperIOSmm">trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm</a></li>
<li><a href="#trunkSourceWebCoreaccessibilityisolatedtreeAXIsolatedObjectcpp">trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp</a></li>
<li><a href="#trunkSourceWebCoreaccessibilityisolatedtreeAXIsolatedObjecth">trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h</a></li>
<li><a href="#trunkSourceWebCoreaccessibilitymacWebAccessibilityObjectWrapperBaseh">trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperBase.h</a></li>
<li><a href="#trunkSourceWebCoreaccessibilitymacWebAccessibilityObjectWrapperBasemm">trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperBase.mm</a></li>
<li><a href="#trunkSourceWebCoreaccessibilitymacWebAccessibilityObjectWrapperMacmm">trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm</a></li>
<li><a href="#trunkToolsWebKitTestRunnerInjectedBundleiosAccessibilityUIElementIOSmm">trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsaccessibilityvisiblecharacterrangehtml">trunk/LayoutTests/accessibility/visible-character-range.html</a></li>
<li><a href="#trunkLayoutTestsplatformiosaccessibilityvisiblecharacterrangeexpectedtxt">trunk/LayoutTests/platform/ios/accessibility/visible-character-range-expected.txt</a></li>
<li><a href="#trunkLayoutTestsplatformmacaccessibilityvisiblecharacterrangeexpectedtxt">trunk/LayoutTests/platform/mac/accessibility/visible-character-range-expected.txt</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2021-11-22 20:01:09 UTC (rev 286115)
+++ trunk/LayoutTests/ChangeLog 2021-11-22 20:34:19 UTC (rev 286116)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2021-11-22  Chris Fleizach  <cfleizach@apple.com>
+
+        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:
+
</ins><span class="cx"> 2021-11-22  Antti Koivisto  <antti@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [LFC][Integration] Remove dirOverride
</span></span></pre></div>
<a id="trunkLayoutTestsaccessibilityvisiblecharacterrangehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/accessibility/visible-character-range.html (0 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,73 @@
</span><ins>+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test.js"></script>
+</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>
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformiosTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/ios/TestExpectations (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -2118,7 +2118,7 @@
</span><span class="cx"> fast/dom/linkify-phone-numbers.html [ Pass ]
</span><span class="cx"> 
</span><span class="cx"> accessibility/video-element-url-attribute.html [ Pass ]
</span><del>-
</del><ins>+accessibility/visible-character-range.html [ Pass ]
</ins><span class="cx"> accessibility/ancestor-computation.html [ Pass ]
</span><span class="cx"> 
</span><span class="cx"> # Enable "aria-current" tests for iOS.
</span></span></pre></div>
<a id="trunkLayoutTestsplatformiosaccessibilityvisiblecharacterrangeexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/platform/ios/accessibility/visible-character-range-expected.txt (0 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+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
+
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformmacaccessibilityvisiblecharacterrangeexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/platform/mac/accessibility/visible-character-range-expected.txt (0 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+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
+
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformmacwk1TestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -601,6 +601,9 @@
</span><span class="cx"> editing/spelling/spellcheck-async.html [ Failure ]
</span><span class="cx"> editing/spelling/spelling-unified-emulation.html [ Failure ]
</span><span class="cx"> 
</span><ins>+# Skip due to lack of DumpRenderTree `AccessibilityUIElement::stringDescriptionOfAttributeValue` implementation.
+accessibility/visible-character-range.html [ Skip ]
+
</ins><span class="cx"> # <rdar://problem/26050923> The result is probably still a pass, but we don't have a way
</span><span class="cx"> # to have platform specific results that are different between WK1 and WK2.
</span><span class="cx"> accessibility/mac/document-attributes.html [ Failure ]
</span></span></pre></div>
<a id="trunkLayoutTestsplatformwinTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/win/TestExpectations (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -278,6 +278,7 @@
</span><span class="cx"> accessibility/listbox-clear-selection.html [ Skip ]
</span><span class="cx"> accessibility/embedded-image-description.html [ Skip ]
</span><span class="cx"> accessibility/img-no-alt-not-ignored-with-title.html [ Skip ]
</span><ins>+accessibility/visible-character-range.html [ Skip ]
</ins><span class="cx"> 
</span><span class="cx"> # Need to implement AccessibilityUIElement::hasDocumentRoleAncestor(), AccessibilityUIElement::hasWebApplicationAncestor(),
</span><span class="cx"> # AccessibilityUIElement::isInDescriptionListDetail(), AccessibilityUIElement::isInDescriptionListTerm(), and
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,3 +1,51 @@
</span><ins>+2021-11-22  Chris Fleizach  <cfleizach@apple.com>
+
+        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.
+
</ins><span class="cx"> 2021-11-20  Simon Fraser  <simon.fraser@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Clarify the behavior of ScrollAnimator::scroll()
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilityAccessibilityObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/AccessibilityObject.cpp (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -704,6 +704,52 @@
</span><span class="cx">     return AXObjectCache::rangeForNodeContents(*node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+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 }};
+}
+
</ins><span class="cx"> std::optional<SimpleRange> AccessibilityObject::findTextRange(const Vector<String>& searchStrings, const SimpleRange& start, AccessibilitySearchTextDirection direction) const
</span><span class="cx"> {
</span><span class="cx">     std::optional<SimpleRange> found;
</span><span class="lines">@@ -3182,6 +3228,14 @@
</span><span class="cx">         scrollParent->scrollToMakeVisibleWithSubFocus(newSubfocus);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+FloatRect AccessibilityObject::unobscuredContentRect() const
+{
+    auto document = this->document();
+    if (!document || !document->view())
+        return { };
+    return FloatRect(snappedIntRect(document->view()->unobscuredContentRect()));
+}
+
</ins><span class="cx"> void AccessibilityObject::scrollToGlobalPoint(const IntPoint& globalPoint) const
</span><span class="cx"> {
</span><span class="cx">     // Search up the parent chain and create a vector of all scrollable parent objects
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilityAccessibilityObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/AccessibilityObject.h (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -808,7 +808,7 @@
</span><span class="cx">     void ariaElementsFromAttribute(AccessibilityChildrenVector&, const QualifiedName&) const;
</span><span class="cx">     void ariaElementsReferencedByAttribute(AccessibilityChildrenVector&, const QualifiedName&) const;
</span><span class="cx">     virtual bool exposesTitleUIElement() const { return true; }
</span><del>-
</del><ins>+    FloatRect unobscuredContentRect() const override;
</ins><span class="cx">     AccessibilityObject* radioGroupAncestor() const;
</span><span class="cx"> 
</span><span class="cx">     bool allowsTextRanges() const;
</span><span class="lines">@@ -821,6 +821,7 @@
</span><span class="cx">     std::optional<SimpleRange> rangeOfStringClosestToRangeInDirection(const SimpleRange&, AccessibilitySearchDirection, const Vector<String>&) const;
</span><span class="cx">     std::optional<SimpleRange> selectionRange() const;
</span><span class="cx">     std::optional<SimpleRange> findTextRange(const Vector<String>& searchStrings, const SimpleRange& start, AccessibilitySearchTextDirection) const;
</span><ins>+    std::optional<SimpleRange> visibleCharacterRange() const override;
</ins><span class="cx"> 
</span><span class="cx"> protected: // FIXME: Make the data members private.
</span><span class="cx">     bool childrenInitialized() const { return m_childrenInitialized; }
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilityAccessibilityObjectInterfaceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/AccessibilityObjectInterface.h (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -988,6 +988,7 @@
</span><span class="cx">     virtual void setIsExpanded(bool) = 0;
</span><span class="cx">     virtual FloatRect relativeFrame() const = 0;
</span><span class="cx">     virtual FloatRect convertFrameToSpace(const FloatRect&, AccessibilityConversionSpace) const = 0;
</span><ins>+    virtual FloatRect unobscuredContentRect() const = 0;
</ins><span class="cx">     virtual bool supportsCheckedState() const = 0;
</span><span class="cx">     
</span><span class="cx">     // In a multi-select list, many items can be selected but only one is active at a time.
</span><span class="lines">@@ -997,6 +998,7 @@
</span><span class="cx">     virtual bool hasItalicFont() const = 0;
</span><span class="cx">     virtual bool hasMisspelling() const = 0;
</span><span class="cx">     virtual std::optional<SimpleRange> misspellingRange(const SimpleRange& start, AccessibilitySearchDirection) const = 0;
</span><ins>+    virtual std::optional<SimpleRange> visibleCharacterRange() const = 0;
</ins><span class="cx">     virtual bool hasPlainText() const = 0;
</span><span class="cx">     virtual bool hasSameFont(const AXCoreObject&) const = 0;
</span><span class="cx">     virtual bool hasSameFontColor(const AXCoreObject&) const = 0;
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilityiosWebAccessibilityObjectWrapperIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -52,6 +52,7 @@
</span><span class="cx"> #import "SVGElementInlines.h"
</span><span class="cx"> #import "SVGNames.h"
</span><span class="cx"> #import "SelectionGeometry.h"
</span><ins>+#import "SimpleRange.h"
</ins><span class="cx"> #import "TextIterator.h"
</span><span class="cx"> #import "WAKScrollView.h"
</span><span class="cx"> #import "WAKWindow.h"
</span><span class="lines">@@ -1694,12 +1695,7 @@
</span><span class="cx"> {
</span><span class="cx">     if (![self _prepareAccessibilityCall])
</span><span class="cx">         return CGRectZero;
</span><del>-    
-    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];
</del><ins>+    return [self convertRectToSpace:self.axBackingObject->unobscuredContentRect() space:AccessibilityConversionSpace::Screen];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // The "center point" is where VoiceOver will "press" an object. This may not be the actual
</span><span class="lines">@@ -1915,7 +1911,7 @@
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return convertToNSArray(accessibleElements);
</del><ins>+    return makeNSArray(accessibleElements);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (NSArray *)accessibilityDetailsElements
</span><span class="lines">@@ -2104,7 +2100,7 @@
</span><span class="cx">     AccessibilitySearchCriteria criteria = accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(parameters);
</span><span class="cx">     AccessibilityObject::AccessibilityChildrenVector results;
</span><span class="cx">     self.axBackingObject->findMatchingObjects(&criteria, results);
</span><del>-    return convertToNSArray(results);
</del><ins>+    return makeNSArray(results);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)accessibilityModifySelection:(TextGranularity)granularity increase:(BOOL)increase
</span><span class="lines">@@ -2209,48 +2205,7 @@
</span><span class="cx">     return range ? [self contentForSimpleRange:*range attributed:attributed] : nil;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// 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);
</del><span class="cx"> 
</span><del>-    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);
-}
-
</del><span class="cx"> // This method is intended to take a text marker representing a VisiblePosition and convert it
</span><span class="cx"> // into a normalized location within the document.
</span><span class="cx"> - (NSInteger)positionForTextMarker:(WebAccessibilityTextMarker *)marker
</span><span class="lines">@@ -2267,7 +2222,7 @@
</span><span class="cx">         auto range = cache->rangeForUnorderedCharacterOffsets(characterOffset, characterOffset);
</span><span class="cx">         if (!range)
</span><span class="cx">             return NSNotFound;
</span><del>-        return [self _convertToNSRange:*range].location;
</del><ins>+        return makeNSRange(range).location;
</ins><span class="cx">     }
</span><span class="cx">     return NSNotFound;
</span><span class="cx"> }
</span><span class="lines">@@ -2346,7 +2301,7 @@
</span><span class="cx">     if (![self _prepareAccessibilityCall])
</span><span class="cx">         return nil;
</span><span class="cx"> 
</span><del>-    auto range = [self _convertToDOMRange:NSMakeRange(position, 0)];
</del><ins>+    auto range = makeDOMRange(self.axBackingObject->document(), NSMakeRange(position, 0));
</ins><span class="cx">     if (!range)
</span><span class="cx">         return nil;
</span><span class="cx"> 
</span><span class="lines">@@ -2414,7 +2369,7 @@
</span><span class="cx"> {
</span><span class="cx">     if (![self _prepareAccessibilityCall])
</span><span class="cx">         return nil;
</span><del>-    auto webRange = [self _convertToDOMRange:range];
</del><ins>+    auto webRange = makeDOMRange(self.axBackingObject->document(), range);
</ins><span class="cx">     if (!webRange)
</span><span class="cx">         return nil;
</span><span class="cx">     return self.axBackingObject->stringForRange(*webRange);
</span><span class="lines">@@ -2600,6 +2555,17 @@
</span><span class="cx">     return [self previousMarkerForCharacterOffset:start];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (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];
+}
+
</ins><span class="cx"> // This method is intended to return the bounds of a text marker range in screen coordinates.
</span><span class="cx"> - (CGRect)frameForTextMarkers:(NSArray *)array
</span><span class="cx"> {
</span><span class="lines">@@ -2931,7 +2897,7 @@
</span><span class="cx">         return nil;
</span><span class="cx"> 
</span><span class="cx">     auto radicand = self.axBackingObject->mathRadicand();
</span><del>-    return radicand ? convertToNSArray(*radicand) : nil;
</del><ins>+    return radicand ? makeNSArray(*radicand) : nil;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (WebAccessibilityObjectWrapper *)accessibilityMathNumeratorObject
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilityisolatedtreeAXIsolatedObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -992,6 +992,13 @@
</span><span class="cx">         tree->applyPendingChanges();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+std::optional<SimpleRange> AXIsolatedObject::visibleCharacterRange() const
+{
+    ASSERT(isMainThread());
+    auto* axObject = associatedAXObject();
+    return axObject ? axObject->visibleCharacterRange() : std::nullopt;
+}
+
</ins><span class="cx"> std::optional<SimpleRange> AXIsolatedObject::rangeForPlainTextRange(const PlainTextRange& axRange) const
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="lines">@@ -1470,6 +1477,15 @@
</span><span class="cx">         object->setSelectedVisiblePositionRange(visiblePositionRange);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+FloatRect AXIsolatedObject::unobscuredContentRect() const
+{
+    return Accessibility::retrieveValueFromMainThread<FloatRect>([this] () -> FloatRect {
+        if (auto* object = associatedAXObject())
+            return object->unobscuredContentRect();
+        return { };
+    });
+}
+
</ins><span class="cx"> std::optional<SimpleRange> AXIsolatedObject::elementRange() const
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isMainThread());
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilityisolatedtreeAXIsolatedObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -441,9 +441,11 @@
</span><span class="cx">     AXCoreObject* accessibilityObjectForPosition(const VisiblePosition&) const override;
</span><span class="cx">     int lineForPosition(const VisiblePosition&) const override;
</span><span class="cx">     PlainTextRange plainTextRangeForVisiblePositionRange(const VisiblePositionRange&) const override;
</span><ins>+    std::optional<SimpleRange> visibleCharacterRange() const override;
</ins><span class="cx">     int index(const VisiblePosition&) const override;
</span><span class="cx">     void lineBreaks(Vector<int>&) const override;
</span><del>-
</del><ins>+    FloatRect unobscuredContentRect() const override;
+    
</ins><span class="cx">     // Attribute setters.
</span><span class="cx">     void setARIAGrabbed(bool) override;
</span><span class="cx">     void setIsExpanded(bool) override;
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilitymacWebAccessibilityObjectWrapperBaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperBase.h (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> struct AccessibilitySearchCriteria;
</span><ins>+class Document;
</ins><span class="cx"> class IntRect;
</span><span class="cx"> class FloatPoint;
</span><span class="cx"> class HTMLTextFormControlElement;
</span><span class="lines">@@ -111,11 +112,15 @@
</span><span class="cx"> - (NSArray *)accessibilityMathPostscriptPairs;
</span><span class="cx"> - (NSArray *)accessibilityMathPrescriptPairs;
</span><span class="cx"> 
</span><ins>+- (NSRange)accessibilityVisibleCharacterRange;
+
</ins><span class="cx"> - (NSDictionary<NSString *, id> *)baseAccessibilityResolvedEditingStyles;
</span><span class="cx"> 
</span><span class="cx"> extern WebCore::AccessibilitySearchCriteria accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(const NSDictionary *);
</span><span class="cx"> 
</span><del>-extern NSArray *convertToNSArray(const WebCore::AXCoreObject::AccessibilityChildrenVector&);
</del><ins>+extern NSArray *makeNSArray(const WebCore::AXCoreObject::AccessibilityChildrenVector&);
+extern NSRange makeNSRange(std::optional<WebCore::SimpleRange>);
+extern std::optional<WebCore::SimpleRange> makeDOMRange(WebCore::Document*, NSRange);
</ins><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS_FAMILY)
</span><span class="cx"> - (id)_accessibilityWebDocumentView;
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilitymacWebAccessibilityObjectWrapperBasemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperBase.mm (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -261,7 +261,7 @@
</span><span class="cx">     }).autorelease();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-NSArray *convertToNSArray(const WebCore::AXCoreObject::AccessibilityChildrenVector& children)
</del><ins>+NSArray *makeNSArray(const WebCore::AXCoreObject::AccessibilityChildrenVector& children)
</ins><span class="cx"> {
</span><span class="cx">     return createNSArray(children, [] (const auto& child) -> id {
</span><span class="cx">         auto wrapper = child->wrapper();
</span><span class="lines">@@ -462,6 +462,27 @@
</span><span class="cx">     return convertedPath.autorelease();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// 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);
+    });
+}
+
</ins><span class="cx"> - (id)_accessibilityWebDocumentView
</span><span class="cx"> {
</span><span class="cx">     ASSERT_NOT_REACHED();
</span><span class="lines">@@ -623,6 +644,49 @@
</span><span class="cx">     AXAttributeStringSetLanguage(attrString, node->renderer(), attrStringRange);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+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);
+}
+
</ins><span class="cx"> // Returns an array of strings and AXObject wrappers corresponding to the text
</span><span class="cx"> // runs and replacement nodes included in the given range.
</span><span class="cx"> - (NSArray *)contentForSimpleRange:(const SimpleRange&)range attributed:(BOOL)attributed
</span><span class="lines">@@ -676,18 +740,26 @@
</span><span class="cx">     return array.autorelease();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (NSArray<NSDictionary *> *)lineRectsAndText
</del><ins>+- (WebCore::AXCoreObject*)baseUpdateBackingStore
</ins><span class="cx"> {
</span><span class="cx"> #if PLATFORM(MAC)
</span><span class="cx">     auto* backingObject = self.updateObjectBackingStore;
</span><span class="cx">     if (!backingObject)
</span><del>-        return nil;
</del><ins>+        return nullptr;
</ins><span class="cx"> #else
</span><span class="cx">     if (![self _prepareAccessibilityCall])
</span><del>-        return nil;
</del><ins>+        return nullptr;
</ins><span class="cx">     auto* backingObject = self.axBackingObject;
</span><span class="cx"> #endif
</span><ins>+    return backingObject;
+}
</ins><span class="cx"> 
</span><ins>+- (NSArray<NSDictionary *> *)lineRectsAndText
+{
+    auto backingObject = self.baseUpdateBackingStore;
+    if (!backingObject)
+        return nil;
+    
</ins><span class="cx">     auto range = backingObject->elementRange();
</span><span class="cx">     if (!range)
</span><span class="cx">         return nil;
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilitymacWebAccessibilityObjectWrapperMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1795,7 +1795,7 @@
</span><span class="cx"> 
</span><span class="cx"> - (NSArray<WebAccessibilityObjectWrapper *> *)childrenVectorArray
</span><span class="cx"> {
</span><del>-    return convertToNSArray(self.axBackingObject->children());
</del><ins>+    return makeNSArray(self.axBackingObject->children());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (NSValue *)position
</span><span class="lines">@@ -2203,7 +2203,7 @@
</span><span class="cx">         if (backingObject->isTreeItem()) {
</span><span class="cx">             AccessibilityObject::AccessibilityChildrenVector contentCopy;
</span><span class="cx">             backingObject->ariaTreeItemContent(contentCopy);
</span><del>-            return convertToNSArray(contentCopy);
</del><ins>+            return makeNSArray(contentCopy);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         return self.childrenVectorArray;
</span><span class="lines">@@ -2213,7 +2213,7 @@
</span><span class="cx">         if (backingObject->canHaveSelectedChildren()) {
</span><span class="cx">             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
</span><span class="cx">             backingObject->selectedChildren(selectedChildrenCopy);
</span><del>-            return convertToNSArray(selectedChildrenCopy);
</del><ins>+            return makeNSArray(selectedChildrenCopy);
</ins><span class="cx">         }
</span><span class="cx">         return nil;
</span><span class="cx">     }
</span><span class="lines">@@ -2222,7 +2222,7 @@
</span><span class="cx">         if (backingObject->isListBox()) {
</span><span class="cx">             AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
</span><span class="cx">             backingObject->visibleChildren(visibleChildrenCopy);
</span><del>-            return convertToNSArray(visibleChildrenCopy);
</del><ins>+            return makeNSArray(visibleChildrenCopy);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (backingObject->isList())
</span><span class="lines">@@ -2234,7 +2234,7 @@
</span><span class="cx"> 
</span><span class="cx">     if (backingObject->isWebArea()) {
</span><span class="cx">         if ([attributeName isEqualToString:@"AXLinkUIElements"])
</span><del>-            return convertToNSArray(backingObject->documentLinks());
</del><ins>+            return makeNSArray(backingObject->documentLinks());
</ins><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:@"AXLoaded"])
</span><span class="cx">             return [NSNumber numberWithBool:backingObject->isLoaded()];
</span><span class="lines">@@ -2267,10 +2267,6 @@
</span><span class="cx">             PlainTextRange textRange = backingObject->selectedTextRange();
</span><span class="cx">             return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
</span><span class="cx">         }
</span><del>-        // TODO: Get actual visible range. <rdar://problem/4712101>
-        if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
-            return backingObject->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, backingObject->textLength())];
-
</del><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityInsertionPointLineNumberAttribute]) {
</span><span class="cx">             int lineNumber = backingObject->insertionPointLineNumber();
</span><span class="cx">             return lineNumber >= 0 ? @(lineNumber) : nil;
</span><span class="lines">@@ -2277,6 +2273,15 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    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]];
+    }
+
</ins><span class="cx">     if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
</span><span class="cx">         URL url = backingObject->url();
</span><span class="cx">         if (url.isNull())
</span><span class="lines">@@ -2380,7 +2385,7 @@
</span><span class="cx"> 
</span><span class="cx">     if ([attributeName isEqualToString:NSAccessibilityImageOverlayElementsAttribute]) {
</span><span class="cx">         auto imageOverlayElements = backingObject->imageOverlayElements();
</span><del>-        return imageOverlayElements ? convertToNSArray(*imageOverlayElements) : nil;
</del><ins>+        return imageOverlayElements ? makeNSArray(*imageOverlayElements) : nil;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if ([attributeName isEqualToString:NSAccessibilityEmbeddedImageDescriptionAttribute])
</span><span class="lines">@@ -2404,29 +2409,29 @@
</span><span class="cx">         if (backingObject->isTabList()) {
</span><span class="cx">             AccessibilityObject::AccessibilityChildrenVector tabsChildren;
</span><span class="cx">             backingObject->tabChildren(tabsChildren);
</span><del>-            return convertToNSArray(tabsChildren);
</del><ins>+            return makeNSArray(tabsChildren);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if ([attributeName isEqualToString:NSAccessibilityContentsAttribute])
</span><del>-        return convertToNSArray(backingObject->contents());
</del><ins>+        return makeNSArray(backingObject->contents());
</ins><span class="cx"> 
</span><span class="cx">     if (backingObject->isTable() && backingObject->isExposable()) {
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute])
</span><del>-            return convertToNSArray(backingObject->rows());
</del><ins>+            return makeNSArray(backingObject->rows());
</ins><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute])
</span><del>-            return convertToNSArray(backingObject->visibleRows());
</del><ins>+            return makeNSArray(backingObject->visibleRows());
</ins><span class="cx"> 
</span><span class="cx">         // TODO: distinguish between visible and non-visible columns
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute]
</span><span class="cx">             || [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute])
</span><del>-            return convertToNSArray(backingObject->columns());
</del><ins>+            return makeNSArray(backingObject->columns());
</ins><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
</span><span class="cx">             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
</span><span class="cx">             backingObject->selectedChildren(selectedChildrenCopy);
</span><del>-            return convertToNSArray(selectedChildrenCopy);
</del><ins>+            return makeNSArray(selectedChildrenCopy);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // HTML tables don't support these attributes.
</span><span class="lines">@@ -2435,7 +2440,7 @@
</span><span class="cx">             return nil;
</span><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute])
</span><del>-            return convertToNSArray(backingObject->columnHeaders());
</del><ins>+            return makeNSArray(backingObject->columnHeaders());
</ins><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
</span><span class="cx">             auto* headerContainer = backingObject->headerContainer();
</span><span class="lines">@@ -2443,10 +2448,10 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute])
</span><del>-            return convertToNSArray(backingObject->rowHeaders());
</del><ins>+            return makeNSArray(backingObject->rowHeaders());
</ins><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute])
</span><del>-            return convertToNSArray(backingObject->cells());
</del><ins>+            return makeNSArray(backingObject->cells());
</ins><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityColumnCountAttribute])
</span><span class="cx">             return @(backingObject->columnCount());
</span><span class="lines">@@ -2468,7 +2473,7 @@
</span><span class="cx">         // rows attribute for a column is the list of all the elements in that column at each row
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]
</span><span class="cx">             || [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute])
</span><del>-            return convertToNSArray(backingObject->children());
</del><ins>+            return makeNSArray(backingObject->children());
</ins><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
</span><span class="cx">             auto* header = backingObject->columnHeader();
</span><span class="lines">@@ -2488,10 +2493,10 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute])
</span><del>-            return convertToNSArray(backingObject->columnHeaders());
</del><ins>+            return makeNSArray(backingObject->columnHeaders());
</ins><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute])
</span><del>-            return convertToNSArray(backingObject->rowHeaders());
</del><ins>+            return makeNSArray(backingObject->rowHeaders());
</ins><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityARIAColumnIndexAttribute])
</span><span class="cx">             return @(backingObject->axColumnIndex());
</span><span class="lines">@@ -2504,12 +2509,12 @@
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
</span><span class="cx">             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
</span><span class="cx">             backingObject->selectedChildren(selectedChildrenCopy);
</span><del>-            return convertToNSArray(selectedChildrenCopy);
</del><ins>+            return makeNSArray(selectedChildrenCopy);
</ins><span class="cx">         }
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) {
</span><span class="cx">             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
</span><span class="cx">             backingObject->ariaTreeRows(rowsCopy);
</span><del>-            return convertToNSArray(rowsCopy);
</del><ins>+            return makeNSArray(rowsCopy);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
</span><span class="lines">@@ -2544,7 +2549,7 @@
</span><span class="cx">     // The rows that are considered inside this row.
</span><span class="cx">     if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
</span><span class="cx">         if (backingObject->isTreeItem() || backingObject->isARIATreeGridRow())
</span><del>-            return convertToNSArray(backingObject->disclosedRows());
</del><ins>+            return makeNSArray(backingObject->disclosedRows());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // The row that contains this row. It should be the same as the first parent that is a treeitem.
</span><span class="lines">@@ -2612,7 +2617,7 @@
</span><span class="cx">     if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
</span><span class="cx">         AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
</span><span class="cx">         backingObject->linkedUIElements(linkedUIElements);
</span><del>-        return convertToNSArray(linkedUIElements);
</del><ins>+        return makeNSArray(linkedUIElements);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
</span><span class="lines">@@ -2685,7 +2690,7 @@
</span><span class="cx">     if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) {
</span><span class="cx">         AccessibilityObject::AccessibilityChildrenVector ariaOwns;
</span><span class="cx">         backingObject->ariaOwnsElements(ariaOwns);
</span><del>-        return convertToNSArray(ariaOwns);
</del><ins>+        return makeNSArray(ariaOwns);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if ([attributeName isEqualToString:NSAccessibilityARIAPosInSetAttribute])
</span><span class="lines">@@ -2751,7 +2756,7 @@
</span><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityMathRootRadicandAttribute]) {
</span><span class="cx">             auto radicand = backingObject->mathRadicand();
</span><del>-            return radicand ? convertToNSArray(*radicand) : nil;
</del><ins>+            return radicand ? makeNSArray(*radicand) : nil;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if ([attributeName isEqualToString:NSAccessibilityMathFractionNumeratorAttribute])
</span><span class="lines">@@ -2845,7 +2850,7 @@
</span><span class="cx">     if ([attributeName isEqualToString:@"AXDetailsElements"]) {
</span><span class="cx">         AccessibilityObject::AccessibilityChildrenVector details;
</span><span class="cx">         backingObject->ariaDetailsElements(details);
</span><del>-        return convertToNSArray(details);
</del><ins>+        return makeNSArray(details);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if ([attributeName isEqualToString:NSAccessibilityBrailleLabelAttribute])
</span><span class="lines">@@ -2860,7 +2865,7 @@
</span><span class="cx">     if ([attributeName isEqualToString:@"AXErrorMessageElements"]) {
</span><span class="cx">         AccessibilityObject::AccessibilityChildrenVector errorMessages;
</span><span class="cx">         backingObject->ariaErrorMessageElements(errorMessages);
</span><del>-        return convertToNSArray(errorMessages);
</del><ins>+        return makeNSArray(errorMessages);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Multi-selectable
</span><span class="lines">@@ -2878,7 +2883,7 @@
</span><span class="cx">     if ([attributeName isEqualToString:NSAccessibilityAriaControlsAttribute]) {
</span><span class="cx">         AccessibilityObject::AccessibilityChildrenVector ariaControls;
</span><span class="cx">         backingObject->ariaControlsElements(ariaControls);
</span><del>-        return convertToNSArray(ariaControls);
</del><ins>+        return makeNSArray(ariaControls);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if ([attributeName isEqualToString:NSAccessibilityFocusableAncestorAttribute]) {
</span><span class="lines">@@ -3428,22 +3433,6 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// 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);
-}
-
</del><span class="cx"> - (NSInteger)_indexForTextMarker:(AXTextMarkerRef)marker
</span><span class="cx"> {
</span><span class="cx">     if (!marker)
</span><span class="lines">@@ -3460,7 +3449,7 @@
</span><span class="cx">             if (!range)
</span><span class="cx">                 return NSNotFound;
</span><span class="cx"> 
</span><del>-            return [protectedSelf _convertToNSRange:*range].location;
</del><ins>+            return makeNSRange(range).location;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         return NSNotFound;
</span><span class="lines">@@ -3835,8 +3824,8 @@
</span><span class="cx">         AccessibilityObject::AccessibilityChildrenVector results;
</span><span class="cx">         backingObject->findMatchingObjects(&criteria, results);
</span><span class="cx">         if (widgetChildren)
</span><del>-            return [widgetChildren arrayByAddingObjectsFromArray:convertToNSArray(results)];
-        return convertToNSArray(results);
</del><ins>+            return [widgetChildren arrayByAddingObjectsFromArray:makeNSArray(results)];
+        return makeNSArray(results);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // TextMarker attributes.
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerInjectedBundleiosAccessibilityUIElementIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm (286115 => 286116)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -108,6 +108,7 @@
</span><span class="cx"> - (id)_accessibilityListAncestor;
</span><span class="cx"> - (id)_accessibilityPhotoDescription;
</span><span class="cx"> - (NSArray *)accessibilityImageOverlayElements;
</span><ins>+- (NSRange)accessibilityVisibleCharacterRange;
</ins><span class="cx"> 
</span><span class="cx"> // TextMarker related
</span><span class="cx"> - (NSArray *)textMarkerRange;
</span><span class="lines">@@ -394,6 +395,9 @@
</span><span class="cx"> 
</span><span class="cx"> JSRetainPtr<JSStringRef> AccessibilityUIElement::stringDescriptionOfAttributeValue(JSStringRef attribute)
</span><span class="cx"> {
</span><ins>+    if (JSStringIsEqualToUTF8CString(attribute, "AXVisibleCharacterRange"))
+        return [NSStringFromRange([m_element accessibilityVisibleCharacterRange]) createJSStringRef];
+
</ins><span class="cx">     return createJSString();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>