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);