<!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>[281920] 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/281920">281920</a></dd>
<dt>Author</dt> <dd>andresg_22@apple.com</dd>
<dt>Date</dt> <dd>2021-09-02 05:45:25 -0700 (Thu, 02 Sep 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Braille display is blank in contenteditable elements when the field is followed by another element.
https://bugs.webkit.org/show_bug.cgi?id=229713
rdar://82095237

Reviewed by Chris Fleizach.

Source/WebCore:

Test: accessibility/mac/range-for-line-index.html

We were making the length of line ranges in text fields 1 more than the
number of characters in the line even when no line break character
existed, like in the case of a single line text field.
Clients like VoiceOver expect the length of the line ranges in text
fields to match the number of charaters in the line including the line
break if one exists.

* accessibility/AccessibilityRenderObject.cpp:
(WebCore::isHardLineBreak): Helper function used in doAXRangeForLine.
Determines whether the given VisiblePosition corresponds to a hard line
break.
(WebCore::AccessibilityRenderObject::doAXRangeForLine const):
Returns a PlainTextRange whose length matches the number of characters
in the given line, accounting for line break characters.

LayoutTests:

* accessibility/mac/range-for-line-index-expected.txt: Added.
* accessibility/mac/range-for-line-index.html: Added.
* platform/mac/accessibility/content-editable-as-textarea-expected.txt:
* platform/win/accessibility/content-editable-as-textarea-expected.txt:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsplatformmacaccessibilitycontenteditableastextareaexpectedtxt">trunk/LayoutTests/platform/mac/accessibility/content-editable-as-textarea-expected.txt</a></li>
<li><a href="#trunkLayoutTestsplatformwinaccessibilitycontenteditableastextareaexpectedtxt">trunk/LayoutTests/platform/win/accessibility/content-editable-as-textarea-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreaccessibilityAccessibilityRenderObjectcpp">trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsaccessibilitymacrangeforlineindexexpectedtxt">trunk/LayoutTests/accessibility/mac/range-for-line-index-expected.txt</a></li>
<li><a href="#trunkLayoutTestsaccessibilitymacrangeforlineindexhtml">trunk/LayoutTests/accessibility/mac/range-for-line-index.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (281919 => 281920)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2021-09-02 11:45:38 UTC (rev 281919)
+++ trunk/LayoutTests/ChangeLog 2021-09-02 12:45:25 UTC (rev 281920)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2021-09-02  Andres Gonzalez  <andresg_22@apple.com>
+
+        Braille display is blank in contenteditable elements when the field is followed by another element.
+        https://bugs.webkit.org/show_bug.cgi?id=229713
+        rdar://82095237
+
+        Reviewed by Chris Fleizach.
+
+        * accessibility/mac/range-for-line-index-expected.txt: Added.
+        * accessibility/mac/range-for-line-index.html: Added.
+        * platform/mac/accessibility/content-editable-as-textarea-expected.txt:
+        * platform/win/accessibility/content-editable-as-textarea-expected.txt:
+
</ins><span class="cx"> 2021-09-02  Philippe Normand  <pnormand@igalia.com>
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, GLib gardening
</span></span></pre></div>
<a id="trunkLayoutTestsaccessibilitymacrangeforlineindexexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/accessibility/mac/range-for-line-index-expected.txt (0 => 281920)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/accessibility/mac/range-for-line-index-expected.txt                            (rev 0)
+++ trunk/LayoutTests/accessibility/mac/range-for-line-index-expected.txt       2021-09-02 12:45:25 UTC (rev 281920)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS contenteditable.rangeForLine(0) is '{0, 15}'
+PASS multilineContenteditable.rangeForLine(0) is '{0, 16}'
+PASS multilineContenteditable.rangeForLine(1) is '{15, 1}'
+PASS multilineContenteditable.rangeForLine(0) is '{0, 16}'
+PASS multilineContenteditable.rangeForLine(1) is '{16, 6}'
+PASS multilineContenteditable.rangeForLine(2) is '{22, 5}'
+PASS textarea.rangeForLine(0) is '{0, 15}'
+PASS multilineTextarea.rangeForLine(0) is '{0, 16}'
+PASS multilineTextarea.rangeForLine(1) is '{16, 6}'
+PASS multilineTextarea.rangeForLine(2) is '{22, 5}'
+PASS textfield.rangeForLine(0) is '{0, 21}'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+this is a test.
+this is a test.
+this is a test.
+hello
+world
+
</ins></span></pre></div>
<a id="trunkLayoutTestsaccessibilitymacrangeforlineindexhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/accessibility/mac/range-for-line-index.html (0 => 281920)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/accessibility/mac/range-for-line-index.html                            (rev 0)
+++ trunk/LayoutTests/accessibility/mac/range-for-line-index.html       2021-09-02 12:45:25 UTC (rev 281920)
</span><span class="lines">@@ -0,0 +1,53 @@
</span><ins>+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+</head>
+<body>
+
+<div id="contenteditable1" contenteditable="true">this is a test.</div>
+<div id="contenteditable2" contenteditable="true">this is a test.<br></div>
+<div id="contenteditable3" contenteditable="true">this is a test.<br>hello<br>
+    <a href="#">world</a>
+</div>
+
+<textarea id="textarea1">this is a test.</textarea>
+<textarea id="textarea2">this is a test.
+hello
+world</textarea>
+
+<input type="text" id="textfield" value="this is a text field."></input>
+
+<script>
+    if (window.accessibilityController) {
+        description("");
+
+        // contenteditable
+        var contenteditable = accessibilityController.accessibleElementById("contenteditable1");
+        shouldBe("contenteditable.rangeForLine(0)", "'{0, 15}'");
+
+        var multilineContenteditable = accessibilityController.accessibleElementById("contenteditable2");
+        shouldBe("multilineContenteditable.rangeForLine(0)", "'{0, 16}'");
+        shouldBe("multilineContenteditable.rangeForLine(1)", "'{15, 1}'");
+
+        multilineContenteditable = accessibilityController.accessibleElementById("contenteditable3");
+        shouldBe("multilineContenteditable.rangeForLine(0)", "'{0, 16}'");
+        shouldBe("multilineContenteditable.rangeForLine(1)", "'{16, 6}'");
+        shouldBe("multilineContenteditable.rangeForLine(2)", "'{22, 5}'");
+
+        // textarea
+        var textarea = accessibilityController.accessibleElementById("textarea1");
+        shouldBe("textarea.rangeForLine(0)", "'{0, 15}'");
+
+        var multilineTextarea = accessibilityController.accessibleElementById("textarea2");
+        shouldBe("multilineTextarea.rangeForLine(0)", "'{0, 16}'");
+        shouldBe("multilineTextarea.rangeForLine(1)", "'{16, 6}'");
+        shouldBe("multilineTextarea.rangeForLine(2)", "'{22, 5}'");
+
+        // input text field
+        var textfield = accessibilityController.accessibleElementById("textfield");
+        shouldBe("textfield.rangeForLine(0)", "'{0, 21}'");
+    }
+</script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformmacaccessibilitycontenteditableastextareaexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac/accessibility/content-editable-as-textarea-expected.txt (281919 => 281920)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac/accessibility/content-editable-as-textarea-expected.txt   2021-09-02 11:45:38 UTC (rev 281919)
+++ trunk/LayoutTests/platform/mac/accessibility/content-editable-as-textarea-expected.txt      2021-09-02 12:45:25 UTC (rev 281920)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> Line for index(0): 0
</span><span class="cx"> Line for index(7): 1
</span><span class="cx"> Range for line(0): {0, 6}
</span><del>-Range for line(1): {6, 6}
</del><ins>+Range for line(1): {6, 5}
</ins><span class="cx"> Bounds for range: {{-1.000000, -1.000000}, {32.000000, 36.000000}}
</span><span class="cx"> Selected text range: {0, 3}
</span><span class="cx"> Selected text: hel
</span></span></pre></div>
<a id="trunkLayoutTestsplatformwinaccessibilitycontenteditableastextareaexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/win/accessibility/content-editable-as-textarea-expected.txt (281919 => 281920)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/win/accessibility/content-editable-as-textarea-expected.txt   2021-09-02 11:45:38 UTC (rev 281919)
+++ trunk/LayoutTests/platform/win/accessibility/content-editable-as-textarea-expected.txt      2021-09-02 12:45:25 UTC (rev 281920)
</span><span class="lines">@@ -34,7 +34,7 @@
</span><span class="cx"> Line for index(0): 0
</span><span class="cx"> Line for index(7): 1
</span><span class="cx"> Range for line(0): {0, 6}
</span><del>-Range for line(1): {6, 6}
</del><ins>+Range for line(1): {6, 5}
</ins><span class="cx"> Bounds for range: {{-1.000000, -1.000000}, {31.000000, 36.000000}}
</span><span class="cx"> Selected text range: {0, 3}
</span><span class="cx"> Selected text: hel
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (281919 => 281920)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-09-02 11:45:38 UTC (rev 281919)
+++ trunk/Source/WebCore/ChangeLog      2021-09-02 12:45:25 UTC (rev 281920)
</span><span class="lines">@@ -1,3 +1,28 @@
</span><ins>+2021-09-02  Andres Gonzalez  <andresg_22@apple.com>
+
+        Braille display is blank in contenteditable elements when the field is followed by another element.
+        https://bugs.webkit.org/show_bug.cgi?id=229713
+        rdar://82095237
+
+        Reviewed by Chris Fleizach.
+
+        Test: accessibility/mac/range-for-line-index.html
+
+        We were making the length of line ranges in text fields 1 more than the
+        number of characters in the line even when no line break character
+        existed, like in the case of a single line text field.
+        Clients like VoiceOver expect the length of the line ranges in text
+        fields to match the number of charaters in the line including the line
+        break if one exists.
+
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::isHardLineBreak): Helper function used in doAXRangeForLine.
+        Determines whether the given VisiblePosition corresponds to a hard line
+        break.
+        (WebCore::AccessibilityRenderObject::doAXRangeForLine const):
+        Returns a PlainTextRange whose length matches the number of characters
+        in the given line, accounting for line break characters.
+
</ins><span class="cx"> 2021-09-02  Rob Buis  <rbuis@igalia.com>
</span><span class="cx"> 
</span><span class="cx">         Absolutely positioned and negative z-index div with canvas child gets drawn with wrong stacking order
</span></span></pre></div>
<a id="trunkSourceWebCoreaccessibilityAccessibilityRenderObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp (281919 => 281920)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp 2021-09-02 11:45:38 UTC (rev 281919)
+++ trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp    2021-09-02 12:45:25 UTC (rev 281920)
</span><span class="lines">@@ -51,6 +51,7 @@
</span><span class="cx"> #include "GeometryUtilities.h"
</span><span class="cx"> #include "HTMLAreaElement.h"
</span><span class="cx"> #include "HTMLAudioElement.h"
</span><ins>+#include "HTMLBRElement.h"
</ins><span class="cx"> #include "HTMLDetailsElement.h"
</span><span class="cx"> #include "HTMLFormElement.h"
</span><span class="cx"> #include "HTMLFrameElementBase.h"
</span><span class="lines">@@ -2443,38 +2444,59 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static bool isHardLineBreak(const VisiblePosition& position)
+{
+    if (!isEndOfLine(position))
+        return false;
+
+    auto next = position.next();
+
+    auto lineBreakRange = makeSimpleRange(position, next);
+    if (!lineBreakRange)
+        return false;
+
+    TextIterator it(*lineBreakRange);
+    if (it.atEnd())
+        return false;
+
+    if (is<HTMLBRElement>(it.node()))
+        return true;
+
+    if (it.node() != position.deepEquivalent().anchorNode())
+        return false;
+
+    return it.text().length() == 1 && it.text()[0] == '\n';
+}
+
</ins><span class="cx"> // Given a line number, the range of characters of the text associated with this accessibility
</span><span class="cx"> // object that contains the line number.
</span><span class="cx"> PlainTextRange AccessibilityRenderObject::doAXRangeForLine(unsigned lineNumber) const
</span><span class="cx"> {
</span><span class="cx">     if (!isTextControl())
</span><del>-        return PlainTextRange();
-    
-    // iterate to the specified line
-    VisiblePosition visiblePos = visiblePositionForIndex(0);
-    VisiblePosition savedVisiblePos;
-    for (unsigned lineCount = lineNumber; lineCount; lineCount -= 1) {
-        savedVisiblePos = visiblePos;
-        visiblePos = nextLinePosition(visiblePos, 0);
-        if (visiblePos.isNull() || visiblePos == savedVisiblePos)
-            return PlainTextRange();
</del><ins>+        return { };
+
+    // Iterate to the specified line.
+    auto lineStart = visiblePositionForIndex(0);
+    for (unsigned lineCount = lineNumber; lineCount; --lineCount) {
+        auto nextLineStart = nextLinePosition(lineStart, 0);
+        if (nextLineStart.isNull() || nextLineStart == lineStart)
+            return { };
+        lineStart = nextLineStart;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Get the end of the line based on the starting position.
</span><del>-    VisiblePosition endPosition = endOfLine(visiblePos);
</del><ins>+    auto lineEnd = endOfLine(lineStart);
</ins><span class="cx"> 
</span><del>-    int index1 = indexForVisiblePosition(visiblePos);
-    int index2 = indexForVisiblePosition(endPosition);
-    
-    // add one to the end index for a line break not caused by soft line wrap (to match AppKit)
-    if (endPosition.affinity() == Affinity::Downstream && endPosition.next().isNotNull())
-        index2 += 1;
-    
-    // return nil rather than an zero-length range (to match AppKit)
-    if (index1 == index2)
-        return PlainTextRange();
-    
-    return PlainTextRange(index1, index2 - index1);
</del><ins>+    int index1 = indexForVisiblePosition(lineStart);
+    int index2 = indexForVisiblePosition(lineEnd);
+
+    if (isHardLineBreak(lineEnd))
+        ++index2;
+
+    if (index1 < 0 || index2 < 0 || index2 <= index1)
+        return { };
+
+    return { static_cast<unsigned>(index1), static_cast<unsigned>(index2 - index1) };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // The composed character range in the text associated with this accessibility object that
</span></span></pre>
</div>
</div>

</body>
</html>