Changeset 287809 in webkit
- Timestamp:
- Jan 8, 2022, 6:27:39 AM (5 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 2 edited
-
ChangeLog (modified) (1 diff)
-
layout/formattingContexts/inline/text/TextUtil.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r287808 r287809 1 2022-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 1 17 2022-01-07 Jean-Yves Avenard <jya@apple.com> 2 18 -
trunk/Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp
r287591 r287809 154 154 ASSERT(length); 155 155 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 { }; 219 218 } 220 219
Note:
See TracChangeset
for help on using the changeset viewer.