Title: [281341] trunk/Source/WebCore
Revision
281341
Author
[email protected]
Date
2021-08-20 15:00:16 -0700 (Fri, 20 Aug 2021)

Log Message

[LFC][IFC] Make mid-word breaking surrogate pair aware
https://bugs.webkit.org/show_bug.cgi?id=229026

Reviewed by Antti Koivisto.

Surrogate pairs represent one "character" (U16_IS_LEAD + U16_IS_TAIL).
We should never break them half even when CSS tells us to break the word at arbitrary position.
This is in preparation for removing the U16_IS_SURROGATE check in canUseForCharacter.

* layout/formattingContexts/inline/InlineContentBreaker.cpp:
(WebCore::Layout::InlineContentBreaker::tryBreakingTextRun const):
* layout/formattingContexts/inline/text/TextUtil.cpp:
(WebCore::Layout::TextUtil::midWorkdBreak):
(WebCore::Layout::TextUtil::split): Deleted.
* layout/formattingContexts/inline/text/TextUtil.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (281340 => 281341)


--- trunk/Source/WebCore/ChangeLog	2021-08-20 21:57:40 UTC (rev 281340)
+++ trunk/Source/WebCore/ChangeLog	2021-08-20 22:00:16 UTC (rev 281341)
@@ -1,5 +1,23 @@
 2021-08-20  Alan Bujtas  <[email protected]>
 
+        [LFC][IFC] Make mid-word breaking surrogate pair aware
+        https://bugs.webkit.org/show_bug.cgi?id=229026
+
+        Reviewed by Antti Koivisto.
+
+        Surrogate pairs represent one "character" (U16_IS_LEAD + U16_IS_TAIL).
+        We should never break them half even when CSS tells us to break the word at arbitrary position. 
+        This is in preparation for removing the U16_IS_SURROGATE check in canUseForCharacter.
+
+        * layout/formattingContexts/inline/InlineContentBreaker.cpp:
+        (WebCore::Layout::InlineContentBreaker::tryBreakingTextRun const):
+        * layout/formattingContexts/inline/text/TextUtil.cpp:
+        (WebCore::Layout::TextUtil::midWorkdBreak):
+        (WebCore::Layout::TextUtil::split): Deleted.
+        * layout/formattingContexts/inline/text/TextUtil.h:
+
+2021-08-20  Alan Bujtas  <[email protected]>
+
         [LFC][Integration] Use the logical width when passing in the constraint for the inline content
         https://bugs.webkit.org/show_bug.cgi?id=228942
 

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.cpp (281340 => 281341)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.cpp	2021-08-20 21:57:40 UTC (rev 281340)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineContentBreaker.cpp	2021-08-20 22:00:16 UTC (rev 281341)
@@ -459,7 +459,7 @@
                 auto availableWidthExcludingHyphen = *availableWidth - hyphenWidth;
                 if (availableWidthExcludingHyphen <= 0 || !enoughWidthForHyphenation(availableWidthExcludingHyphen, fontCascade.pixelSize()))
                     return { };
-                leftSideLength = TextUtil::split(inlineTextItem, overflowingRun.logicalWidth, availableWidthExcludingHyphen, logicalLeft).length;
+                leftSideLength = TextUtil::midWorkdBreak(inlineTextItem, overflowingRun.logicalWidth, availableWidthExcludingHyphen, logicalLeft).length;
             }
             if (leftSideLength < limitBefore)
                 return { };
@@ -493,8 +493,8 @@
                 // Fast path for cases when there's no room at all. The content is breakable but we don't have space for it.
                 return { };
             }
-            auto splitData = TextUtil::split(inlineTextItem, overflowingRun.logicalWidth, *availableWidth, logicalLeft);
-            return { splitData.length, splitData.logicalWidth };
+            auto midWorkdBreak = TextUtil::midWorkdBreak(inlineTextItem, overflowingRun.logicalWidth, *availableWidth, logicalLeft);
+            return { midWorkdBreak.length, midWorkdBreak.logicalWidth };
         };
         // With arbitrary breaking there's always a valid breaking position (even if it is before the first position).
         return tryBreakingAtArbitraryPosition();

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp (281340 => 281341)


--- trunk/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp	2021-08-20 21:57:40 UTC (rev 281340)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp	2021-08-20 22:00:16 UTC (rev 281341)
@@ -84,7 +84,7 @@
     return std::isnan(width) ? 0.0f : std::isinf(width) ? maxInlineLayoutUnit() : width;
 }
 
-TextUtil::SplitData TextUtil::split(const InlineTextItem& inlineTextItem, InlineLayoutUnit textWidth, InlineLayoutUnit availableWidth, InlineLayoutUnit contentLogicalLeft)
+TextUtil::MidWorkdBreak TextUtil::midWorkdBreak(const InlineTextItem& inlineTextItem, InlineLayoutUnit textWidth, InlineLayoutUnit availableWidth, InlineLayoutUnit contentLogicalLeft)
 {
     ASSERT(availableWidth >= 0);
     auto startPosition = inlineTextItem.start();
@@ -91,23 +91,42 @@
     auto length = inlineTextItem.length();
     ASSERT(length);
 
+    auto text = inlineTextItem.inlineTextBox().content();
+    auto surrogatePairAwareIndex = [&] (auto index) {
+        // We should never break in the middle of a surrogate pair. They are considered one joint entity.
+        RELEASE_ASSERT(index < text.length());
+        if (!U16_IS_LEAD(text[index]))
+            return index;
+        RELEASE_ASSERT(index + 1 < text.length());
+        ASSERT(U16_IS_TRAIL(text[index + 1]));
+        return ++index;
+    };
+
     auto left = startPosition;
     // Pathological case of (extremely)long string and narrow lines.
     // Adjust the range so that we can pick a reasonable midpoint.
-    InlineLayoutUnit averageCharacterWidth = textWidth / length;
+    auto averageCharacterWidth = InlineLayoutUnit { textWidth / length };
     unsigned offset = toLayoutUnit(2 * availableWidth / averageCharacterWidth).toUnsigned();
-    auto right = std::min<unsigned>(left + offset, (startPosition + length - 1));
+    auto right = surrogatePairAwareIndex(std::min<unsigned>(left + offset, (startPosition + length - 1)));
     // Preserve the left width for the final split position so that we don't need to remeasure the left side again.
-    InlineLayoutUnit leftSideWidth = 0;
+    auto leftSideWidth = InlineLayoutUnit { 0 };
     while (left < right) {
-        auto middle = (left + right) / 2;
+        auto middle = surrogatePairAwareIndex((left + right) / 2);
         auto width = TextUtil::width(inlineTextItem, startPosition, middle + 1, contentLogicalLeft);
         if (width < availableWidth) {
             left = middle + 1;
             leftSideWidth = width;
-        } else if (width > availableWidth)
-            right = middle;
-        else {
+        } else if (width > availableWidth) {
+            auto surrogatePairAwareStart = [&] (auto index) {
+                if (!U16_IS_TRAIL(text[middle]))
+                    return index;
+                RELEASE_ASSERT(index);
+                ASSERT(U16_IS_LEAD(text[index - 1]));
+                return --index;
+            };
+            // When the substring does not fit, the right side is supposed to be the start of the surrogate pair if applicable. 
+            right = surrogatePairAwareStart(middle);
+        } else {
             right = middle + 1;
             leftSideWidth = width;
             break;

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.h (281340 => 281341)


--- trunk/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.h	2021-08-20 21:57:40 UTC (rev 281340)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.h	2021-08-20 22:00:16 UTC (rev 281341)
@@ -46,12 +46,12 @@
     static InlineLayoutUnit width(const InlineTextItem&, unsigned from, unsigned to, InlineLayoutUnit contentLogicalLeft);
     static InlineLayoutUnit width(const InlineTextBox&, unsigned from, unsigned to, InlineLayoutUnit contentLogicalLeft);
 
-    struct SplitData {
-        unsigned start { 0 };
-        unsigned length { 0 };
+    struct MidWorkdBreak {
+        size_t start { 0 };
+        size_t length { 0 };
         InlineLayoutUnit logicalWidth { 0 };
     };
-    static SplitData split(const InlineTextItem&, InlineLayoutUnit textWidth, InlineLayoutUnit availableWidth, InlineLayoutUnit contentLogicalLeft);
+    static MidWorkdBreak midWorkdBreak(const InlineTextItem&, InlineLayoutUnit textWidth, InlineLayoutUnit availableWidth, InlineLayoutUnit contentLogicalLeft);
 
     static unsigned findNextBreakablePosition(LazyLineBreakIterator&, unsigned startPosition, const RenderStyle&);
     static LineBreakIteratorMode lineBreakIteratorMode(LineBreak);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to