<!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>[287809] trunk/Source/WebCore</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/287809">287809</a></dd>
<dt>Author</dt> <dd>zalan@apple.com</dd>
<dt>Date</dt> <dd>2022-01-08 06:27:39 -0800 (Sat, 08 Jan 2022)</dd>
</dl>

<h3>Log Message</h3>
<pre>[LFC][IFC] Implement TextUtil::breakWord for the complex font codepath using ubrk_next
https://bugs.webkit.org/show_bug.cgi?id=234998

Reviewed by Antti Koivisto.

In order to use ubrk_preceding/ubrk_following with arbitrary position (binary search) inside a cluster with surrogate pairs we have to
implement some additional surrogate boundary checks (it would move the index to the beginning/end of the surrogate when it falls right
in the middle of it). In addition to that, ICU would still need to scan the content from the start to find the right index for
the boundary.
This new breakWord implementation simply iterates over the clusters by calling ubrk_next until the content overflows.

* layout/formattingContexts/inline/text/TextUtil.cpp:
(WebCore::Layout::TextUtil::breakWord):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorelayoutformattingContextsinlinetextTextUtilcpp">trunk/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (287808 => 287809)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2022-01-08 06:23:50 UTC (rev 287808)
+++ trunk/Source/WebCore/ChangeLog      2022-01-08 14:27:39 UTC (rev 287809)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2022-01-08  Alan Bujtas  <zalan@apple.com>
+
+        [LFC][IFC] Implement TextUtil::breakWord for the complex font codepath using ubrk_next
+        https://bugs.webkit.org/show_bug.cgi?id=234998
+
+        Reviewed by Antti Koivisto.
+
+        In order to use ubrk_preceding/ubrk_following with arbitrary position (binary search) inside a cluster with surrogate pairs we have to
+        implement some additional surrogate boundary checks (it would move the index to the beginning/end of the surrogate when it falls right
+        in the middle of it). In addition to that, ICU would still need to scan the content from the start to find the right index for
+        the boundary.
+        This new breakWord implementation simply iterates over the clusters by calling ubrk_next until the content overflows.
+
+        * layout/formattingContexts/inline/text/TextUtil.cpp:
+        (WebCore::Layout::TextUtil::breakWord):
+
</ins><span class="cx"> 2022-01-07  Jean-Yves Avenard  <jya@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Remove IPC::SharedBufferDataReference and use IPC::SharedBufferCopy instead
</span></span></pre></div>
<a id="trunkSourceWebCorelayoutformattingContextsinlinetextTextUtilcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp (287808 => 287809)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp  2022-01-08 06:23:50 UTC (rev 287808)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp     2022-01-08 14:27:39 UTC (rev 287809)
</span><span class="lines">@@ -153,69 +153,68 @@
</span><span class="cx">     ASSERT(availableWidth >= 0);
</span><span class="cx">     ASSERT(length);
</span><span class="cx">     auto text = inlineTextBox.content();
</span><del>-    auto contentUsesSimpleFontCodePath = inlineTextBox.canUseSimpleFontCodePath();
</del><span class="cx"> 
</span><del>-    auto graphemeClustersIterator = std::optional<NonSharedCharacterBreakIterator> { };
-    if (!contentUsesSimpleFontCodePath)
-        graphemeClustersIterator.emplace(text);
</del><ins>+    if (inlineTextBox.canUseSimpleFontCodePath()) {
</ins><span class="cx"> 
</span><del>-    auto userPerceivedCharacterBoundaryAlignedIndex = [&] (auto index) -> size_t {
-        if (text.is8Bit())
-            return index;
-        if (contentUsesSimpleFontCodePath) {
-            auto alignedStartIndex = index;
-            U16_SET_CP_START(text, startPosition, alignedStartIndex);
-            ASSERT(alignedStartIndex >= startPosition);
-            return alignedStartIndex;
-        }
-        ASSERT(graphemeClustersIterator.has_value());
-        if (ubrk_isBoundary(*graphemeClustersIterator, index))
-            return index;
-        auto boundaryIndex = ubrk_preceding(*graphemeClustersIterator, index);
-        return boundaryIndex == UBRK_DONE ? startPosition : boundaryIndex;
-    };
</del><ins>+        auto findBreakingPositionInSimpleText = [&] {
+            auto userPerceivedCharacterBoundaryAlignedIndex = [&] (auto index) -> size_t {
+                if (text.is8Bit())
+                    return index;
+                auto alignedStartIndex = index;
+                U16_SET_CP_START(text, startPosition, alignedStartIndex);
+                ASSERT(alignedStartIndex >= startPosition);
+                return alignedStartIndex;
+            };
</ins><span class="cx"> 
</span><del>-    auto nextUserPerceivedCharacterIndex = [&] (auto index) -> size_t {
-        if (text.is8Bit())
-            return index + 1;
-        if (contentUsesSimpleFontCodePath) {
-            U16_FWD_1(text, index, length);
-            return index;
-        }
-        ASSERT(graphemeClustersIterator.has_value());
-        auto nextPosition = ubrk_following(*graphemeClustersIterator, index);
-        return nextPosition == UBRK_DONE ? startPosition + length - 1 : nextPosition;
-    };
</del><ins>+            auto nextUserPerceivedCharacterIndex = [&] (auto index) -> size_t {
+                if (text.is8Bit())
+                    return index + 1;
+                U16_FWD_1(text, index, length);
+                return index;
+            };
</ins><span class="cx"> 
</span><del>-    auto left = startPosition;
-    auto right = left + length - 1;
-    if (contentUsesSimpleFontCodePath) {
-        // Pathological case of (extremely)long string and narrow lines.
-        // Adjust the range so that we can pick a reasonable midpoint.
-        auto averageCharacterWidth = InlineLayoutUnit { textWidth / length };
-        size_t startOffset = 2 * availableWidth / averageCharacterWidth;
-        right = userPerceivedCharacterBoundaryAlignedIndex(std::min(left + startOffset, right));
</del><ins>+            auto left = startPosition;
+            auto right = left + length - 1;
+            // Pathological case of (extremely)long string and narrow lines.
+            // Adjust the range so that we can pick a reasonable midpoint.
+            auto averageCharacterWidth = InlineLayoutUnit { textWidth / length };
+            size_t startOffset = 2 * availableWidth / averageCharacterWidth;
+            right = userPerceivedCharacterBoundaryAlignedIndex(std::min(left + startOffset, right));
+            // Preserve the left width for the final split position so that we don't need to remeasure the left side again.
+            auto leftSideWidth = InlineLayoutUnit { 0 };
+            while (left < right) {
+                auto middle = userPerceivedCharacterBoundaryAlignedIndex((left + right) / 2);
+                ASSERT(middle >= left && middle < right);
+                auto endOfMiddleCharacter = nextUserPerceivedCharacterIndex(middle);
+                auto width = TextUtil::width(inlineTextBox, fontCascade, startPosition, endOfMiddleCharacter, contentLogicalLeft);
+                if (width < availableWidth) {
+                    left = endOfMiddleCharacter;
+                    leftSideWidth = width;
+                } else if (width > availableWidth)
+                    right = middle;
+                else {
+                    right = endOfMiddleCharacter;
+                    leftSideWidth = width;
+                    break;
+                }
+            }
+            RELEASE_ASSERT(right >= startPosition);
+            return TextUtil::WordBreakLeft { right - startPosition, leftSideWidth };
+        };
+        return findBreakingPositionInSimpleText();
</ins><span class="cx">     }
</span><del>-    // Preserve the left width for the final split position so that we don't need to remeasure the left side again.
-    auto leftSideWidth = InlineLayoutUnit { 0 };
-    while (left < right) {
-        auto middle = userPerceivedCharacterBoundaryAlignedIndex((left + right) / 2);
-        ASSERT(middle >= left && middle < right);
-        auto endOfMiddleCharacter = nextUserPerceivedCharacterIndex(middle);
-        auto width = TextUtil::width(inlineTextBox, fontCascade, startPosition, endOfMiddleCharacter, contentLogicalLeft);
-        if (width < availableWidth) {
-            left = endOfMiddleCharacter;
-            leftSideWidth = width;
-        } else if (width > availableWidth)
-            right = middle;
-        else {
-            right = endOfMiddleCharacter;
-            leftSideWidth = width;
-            break;
-        }
</del><ins>+
+    auto graphemeClusterIterator = NonSharedCharacterBreakIterator { StringView { text }.substring(startPosition, length) };
+    auto leftSide = TextUtil::WordBreakLeft { };
+    for (auto clusterStartPosition = ubrk_next(graphemeClusterIterator); clusterStartPosition != UBRK_DONE; clusterStartPosition = ubrk_next(graphemeClusterIterator)) {
+        auto width = TextUtil::width(inlineTextBox, fontCascade, startPosition, startPosition + clusterStartPosition, contentLogicalLeft);
+        if (width > availableWidth)
+            return leftSide;
+        leftSide = { static_cast<size_t>(clusterStartPosition), width };
</ins><span class="cx">     }
</span><del>-    RELEASE_ASSERT(right >= startPosition);
-    return { right - startPosition, leftSideWidth };
</del><ins>+    // This content is not supposed to fit availableWidth.
+    ASSERT_NOT_REACHED();
+    return { };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> unsigned TextUtil::findNextBreakablePosition(LazyLineBreakIterator& lineBreakIterator, unsigned startPosition, const RenderStyle& style)
</span></span></pre>
</div>
</div>

</body>
</html>