⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 287809 in webkit


Ignore:
Timestamp:
Jan 8, 2022, 6:27:39 AM (5 years ago)
Author:
Alan Bujtas
Message:

[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):

Location:
trunk/Source/WebCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r287808 r287809  
     12022-01-08  Alan Bujtas  <zalan@apple.com>
     2
     3        [LFC][IFC] Implement TextUtil::breakWord for the complex font codepath using ubrk_next
     4        https://bugs.webkit.org/show_bug.cgi?id=234998
     5
     6        Reviewed by Antti Koivisto.
     7
     8        In order to use ubrk_preceding/ubrk_following with arbitrary position (binary search) inside a cluster with surrogate pairs we have to
     9        implement some additional surrogate boundary checks (it would move the index to the beginning/end of the surrogate when it falls right
     10        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
     11        the boundary.
     12        This new breakWord implementation simply iterates over the clusters by calling ubrk_next until the content overflows.
     13
     14        * layout/formattingContexts/inline/text/TextUtil.cpp:
     15        (WebCore::Layout::TextUtil::breakWord):
     16
    1172022-01-07  Jean-Yves Avenard  <jya@apple.com>
    218
  • trunk/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp

    r287591 r287809  
    154154    ASSERT(length);
    155155    auto text = inlineTextBox.content();
    156     auto contentUsesSimpleFontCodePath = inlineTextBox.canUseSimpleFontCodePath();
    157 
    158     auto graphemeClustersIterator = std::optional<NonSharedCharacterBreakIterator> { };
    159     if (!contentUsesSimpleFontCodePath)
    160         graphemeClustersIterator.emplace(text);
    161 
    162     auto userPerceivedCharacterBoundaryAlignedIndex = [&] (auto index) -> size_t {
    163         if (text.is8Bit())
    164             return index;
    165         if (contentUsesSimpleFontCodePath) {
    166             auto alignedStartIndex = index;
    167             U16_SET_CP_START(text, startPosition, alignedStartIndex);
    168             ASSERT(alignedStartIndex >= startPosition);
    169             return alignedStartIndex;
    170         }
    171         ASSERT(graphemeClustersIterator.has_value());
    172         if (ubrk_isBoundary(*graphemeClustersIterator, index))
    173             return index;
    174         auto boundaryIndex = ubrk_preceding(*graphemeClustersIterator, index);
    175         return boundaryIndex == UBRK_DONE ? startPosition : boundaryIndex;
    176     };
    177 
    178     auto nextUserPerceivedCharacterIndex = [&] (auto index) -> size_t {
    179         if (text.is8Bit())
    180             return index + 1;
    181         if (contentUsesSimpleFontCodePath) {
    182             U16_FWD_1(text, index, length);
    183             return index;
    184         }
    185         ASSERT(graphemeClustersIterator.has_value());
    186         auto nextPosition = ubrk_following(*graphemeClustersIterator, index);
    187         return nextPosition == UBRK_DONE ? startPosition + length - 1 : nextPosition;
    188     };
    189 
    190     auto left = startPosition;
    191     auto right = left + length - 1;
    192     if (contentUsesSimpleFontCodePath) {
    193         // Pathological case of (extremely)long string and narrow lines.
    194         // Adjust the range so that we can pick a reasonable midpoint.
    195         auto averageCharacterWidth = InlineLayoutUnit { textWidth / length };
    196         size_t startOffset = 2 * availableWidth / averageCharacterWidth;
    197         right = userPerceivedCharacterBoundaryAlignedIndex(std::min(left + startOffset, right));
    198     }
    199     // Preserve the left width for the final split position so that we don't need to remeasure the left side again.
    200     auto leftSideWidth = InlineLayoutUnit { 0 };
    201     while (left < right) {
    202         auto middle = userPerceivedCharacterBoundaryAlignedIndex((left + right) / 2);
    203         ASSERT(middle >= left && middle < right);
    204         auto endOfMiddleCharacter = nextUserPerceivedCharacterIndex(middle);
    205         auto width = TextUtil::width(inlineTextBox, fontCascade, startPosition, endOfMiddleCharacter, contentLogicalLeft);
    206         if (width < availableWidth) {
    207             left = endOfMiddleCharacter;
    208             leftSideWidth = width;
    209         } else if (width > availableWidth)
    210             right = middle;
    211         else {
    212             right = endOfMiddleCharacter;
    213             leftSideWidth = width;
    214             break;
    215         }
    216     }
    217     RELEASE_ASSERT(right >= startPosition);
    218     return { right - startPosition, leftSideWidth };
     156
     157    if (inlineTextBox.canUseSimpleFontCodePath()) {
     158
     159        auto findBreakingPositionInSimpleText = [&] {
     160            auto userPerceivedCharacterBoundaryAlignedIndex = [&] (auto index) -> size_t {
     161                if (text.is8Bit())
     162                    return index;
     163                auto alignedStartIndex = index;
     164                U16_SET_CP_START(text, startPosition, alignedStartIndex);
     165                ASSERT(alignedStartIndex >= startPosition);
     166                return alignedStartIndex;
     167            };
     168
     169            auto nextUserPerceivedCharacterIndex = [&] (auto index) -> size_t {
     170                if (text.is8Bit())
     171                    return index + 1;
     172                U16_FWD_1(text, index, length);
     173                return index;
     174            };
     175
     176            auto left = startPosition;
     177            auto right = left + length - 1;
     178            // Pathological case of (extremely)long string and narrow lines.
     179            // Adjust the range so that we can pick a reasonable midpoint.
     180            auto averageCharacterWidth = InlineLayoutUnit { textWidth / length };
     181            size_t startOffset = 2 * availableWidth / averageCharacterWidth;
     182            right = userPerceivedCharacterBoundaryAlignedIndex(std::min(left + startOffset, right));
     183            // Preserve the left width for the final split position so that we don't need to remeasure the left side again.
     184            auto leftSideWidth = InlineLayoutUnit { 0 };
     185            while (left < right) {
     186                auto middle = userPerceivedCharacterBoundaryAlignedIndex((left + right) / 2);
     187                ASSERT(middle >= left && middle < right);
     188                auto endOfMiddleCharacter = nextUserPerceivedCharacterIndex(middle);
     189                auto width = TextUtil::width(inlineTextBox, fontCascade, startPosition, endOfMiddleCharacter, contentLogicalLeft);
     190                if (width < availableWidth) {
     191                    left = endOfMiddleCharacter;
     192                    leftSideWidth = width;
     193                } else if (width > availableWidth)
     194                    right = middle;
     195                else {
     196                    right = endOfMiddleCharacter;
     197                    leftSideWidth = width;
     198                    break;
     199                }
     200            }
     201            RELEASE_ASSERT(right >= startPosition);
     202            return TextUtil::WordBreakLeft { right - startPosition, leftSideWidth };
     203        };
     204        return findBreakingPositionInSimpleText();
     205    }
     206
     207    auto graphemeClusterIterator = NonSharedCharacterBreakIterator { StringView { text }.substring(startPosition, length) };
     208    auto leftSide = TextUtil::WordBreakLeft { };
     209    for (auto clusterStartPosition = ubrk_next(graphemeClusterIterator); clusterStartPosition != UBRK_DONE; clusterStartPosition = ubrk_next(graphemeClusterIterator)) {
     210        auto width = TextUtil::width(inlineTextBox, fontCascade, startPosition, startPosition + clusterStartPosition, contentLogicalLeft);
     211        if (width > availableWidth)
     212            return leftSide;
     213        leftSide = { static_cast<size_t>(clusterStartPosition), width };
     214    }
     215    // This content is not supposed to fit availableWidth.
     216    ASSERT_NOT_REACHED();
     217    return { };
    219218}
    220219
Note: See TracChangeset for help on using the changeset viewer.