Source/WebCore/ChangeLog

 12021-02-03 Zalan Bujtas <zalan@apple.com>
 2
 3 [LFC][IFC] Add support for "word separator" when the whitespace content has multiple characters
 4 https://bugs.webkit.org/show_bug.cgi?id=221355
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Keep track of word separator characters in whitespace content even when the whitespace content has multiple characters.
 9 This fixes cases when "word-spacing" has a non-zero value in "space and tab preserve" content (e.g <pre style="word-spacing: 200px">This content has spaces and tabs</pre>)
 10 (On trunk we fail to adjust the run position with the word-spacing value because the whitespace content is not marked as a word separator.)
 11
 12 * layout/inlineformatting/InlineTextItem.cpp:
 13 (WebCore::Layout::moveToNextNonWhitespacePosition):
 14 (WebCore::Layout::InlineTextItem::createAndAppendTextItems):
 15 * layout/inlineformatting/InlineTextItem.h:
 16 (WebCore::Layout::InlineTextItem::createNonWhitespaceItem):
 17
1182021-02-03 Zalan Bujtas <zalan@apple.com>
219
320 [LFC][IFC] Move away from using RenderStyle::preserveNewline

Source/WebCore/layout/inlineformatting/InlineTextItem.cpp

@@namespace Layout {
3838
3939static_assert(sizeof(InlineItem) == sizeof(InlineTextItem), "");
4040
41 static size_t moveToNextNonWhitespacePosition(const StringView& textContent, size_t startPosition, bool preserveNewline)
 41struct WhitespaceContent {
 42 size_t length { 0 };
 43 bool isWordSeparator { true };
 44};
 45static Optional<WhitespaceContent> moveToNextNonWhitespacePosition(const StringView& textContent, size_t startPosition, bool preserveNewline, bool preserveTab)
4246{
 47 auto hasWordSeparatorCharacter = false;
4348 auto isWhitespaceCharacter = [&](auto character) {
44  return character == space || character == tabCharacter || (character == newlineCharacter && !preserveNewline);
 49 // white space processing in CSS affects only the document white space characters: spaces (U+0020), tabs (U+0009), and segment breaks.
 50 auto isTreatedAsSpaceCharacter = character == space || (character == newlineCharacter && !preserveNewline) || (character == tabCharacter && !preserveTab);
 51 hasWordSeparatorCharacter = hasWordSeparatorCharacter || isTreatedAsSpaceCharacter;
 52 return isTreatedAsSpaceCharacter || character == tabCharacter;
4553 };
46 
4754 auto nextNonWhiteSpacePosition = startPosition;
4855 while (nextNonWhiteSpacePosition < textContent.length() && isWhitespaceCharacter(textContent[nextNonWhiteSpacePosition]))
4956 ++nextNonWhiteSpacePosition;
50  return nextNonWhiteSpacePosition - startPosition;
 57 return nextNonWhiteSpacePosition == startPosition ? WTF::nullopt : makeOptional(WhitespaceContent { nextNonWhiteSpacePosition - startPosition, hasWordSeparatorCharacter });
5158}
5259
5360static unsigned moveToNextBreakablePosition(unsigned startPosition, LazyLineBreakIterator& lineBreakIterator, const RenderStyle& style)

@@void InlineTextItem::createAndAppendTextItems(InlineItems& inlineContent, const
95102 continue;
96103 }
97104
98  if (auto length = moveToNextNonWhitespacePosition(text, currentPosition, shouldPreseveNewline)) {
 105 if (auto whitespaceContent = moveToNextNonWhitespacePosition(text, currentPosition, shouldPreseveNewline, !whitespaceContentIsTreatedAsSingleSpace)) {
 106 ASSERT(whitespaceContent->length);
99107 auto appendWhitespaceItem = [&] (auto startPosition, auto itemLength) {
100108 auto simpleSingleWhitespaceContent = inlineTextBox.canUseSimplifiedContentMeasuring() && (itemLength == 1 || whitespaceContentIsTreatedAsSingleSpace);
101109 auto width = simpleSingleWhitespaceContent ? makeOptional(InlineLayoutUnit { font.spaceWidth() }) : inlineItemWidth(startPosition, itemLength);
102  auto isWordSeparator = [&] {
103  if (whitespaceContentIsTreatedAsSingleSpace)
104  return true;
105  if (itemLength != 1) {
106  // FIXME: Add support for cases where the whitespace content contains different type of characters (e.g "\t \t \t").
107  return false;
108  }
109  auto whitespaceCharacter = text[startPosition];
110  return whitespaceCharacter == space
111  || whitespaceCharacter == noBreakSpace
112  || whitespaceCharacter == ethiopicWordspace
113  || whitespaceCharacter == aegeanWordSeparatorLine
114  || whitespaceCharacter == aegeanWordSeparatorDot
115  || whitespaceCharacter == ugariticWordDivider;
116  }();
117  inlineContent.append(InlineTextItem::createWhitespaceItem(inlineTextBox, startPosition, itemLength, isWordSeparator, width));
 110 inlineContent.append(InlineTextItem::createWhitespaceItem(inlineTextBox, startPosition, itemLength, whitespaceContent->isWordSeparator, width));
118111 };
119112 if (style.whiteSpace() == WhiteSpace::BreakSpaces) {
120113 // https://www.w3.org/TR/css-text-3/#white-space-phase-1
121114 // For break-spaces, a soft wrap opportunity exists after every space and every tab.
122115 // FIXME: if this turns out to be a perf hit with too many individual whitespace inline items, we should transition this logic to line breaking.
123  for (size_t i = 0; i < length; ++i)
 116 for (size_t i = 0; i < whitespaceContent->length; ++i)
124117 appendWhitespaceItem(currentPosition + i, 1);
125118 } else
126  appendWhitespaceItem(currentPosition, length);
127  currentPosition += length;
 119 appendWhitespaceItem(currentPosition, whitespaceContent->length);
 120 currentPosition += whitespaceContent->length;
128121 continue;
129122 }
130123

Source/WebCore/layout/inlineformatting/InlineTextItem.h

@@inline InlineTextItem InlineTextItem::createWhitespaceItem(const InlineTextBox&
7474
7575inline InlineTextItem InlineTextItem::createNonWhitespaceItem(const InlineTextBox& inlineTextBox, unsigned start, unsigned length, bool hasTrailingSoftHyphen, Optional<InlineLayoutUnit> width)
7676{
 77 // FIXME: Use the following list of non-whitespace characters to set the "isWordSeparator" bit: noBreakSpace, ethiopicWordspace, aegeanWordSeparatorLine aegeanWordSeparatorDot ugariticWordDivider.
7778 return { inlineTextBox, start, length, hasTrailingSoftHyphen, false, width, TextItemType::NonWhitespace };
7879}
7980