Changeset 252940 in webkit
- Timestamp:
- Nov 29, 2019 6:20:54 AM (4 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r252938 r252940 1 2019-11-29 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][IFC] Move and rename LineLayoutContext::UncommittedContent 4 https://bugs.webkit.org/show_bug.cgi?id=204693 5 <rdar://problem/57523727> 6 7 Reviewed by Antti Koivisto. 8 9 LineBreaker::Content represents the amount of content we commit to line breaking at a time. 10 Normally it holds only one InlineItem e.g [text][ ][content] <- we submit 3 entries to line breaking, but 11 with (mostly)inline containers, it can hold a long list of InlineItems e.g 12 <span>1</span>2<span>3</span>4<span>5</span>6 13 [container start][1][container end][2][container start][3][container end][4][container start][5][container end][6] 14 <- this is one entry to submit. 15 This patch is also in preparation for fixing trailing trimmable content handling. 16 17 * layout/inlineformatting/InlineLineBreaker.cpp: 18 (WebCore::Layout::LineBreaker::breakingContextForInlineContent): 19 (WebCore::Layout::LineBreaker::wordBreakingBehavior const): 20 (WebCore::Layout::LineBreaker::tryBreakingTextRun const): 21 (WebCore::Layout::LineBreaker::Content::isAtContentBoundary): 22 (WebCore::Layout::LineBreaker::Content::append): 23 (WebCore::Layout::LineBreaker::Content::reset): 24 (WebCore::Layout::LineBreaker::Content::trim): 25 * layout/inlineformatting/InlineLineBreaker.h: 26 (WebCore::Layout::LineBreaker::Content::runs): 27 (WebCore::Layout::LineBreaker::Content::runs const): 28 (WebCore::Layout::LineBreaker::Content::isEmpty const): 29 (WebCore::Layout::LineBreaker::Content::size const): 30 (WebCore::Layout::LineBreaker::Content::width const): 31 * layout/inlineformatting/LineLayoutContext.cpp: 32 (WebCore::Layout::LineLayoutContext::placeInlineItem): 33 (WebCore::Layout::LineLayoutContext::processUncommittedContent): 34 (WebCore::Layout::LineLayoutContext::UncommittedContent::add): Deleted. 35 (WebCore::Layout::LineLayoutContext::UncommittedContent::reset): Deleted. 36 (WebCore::Layout::LineLayoutContext::shouldProcessUncommittedContent const): Deleted. 37 (WebCore::Layout::LineLayoutContext::UncommittedContent::trim): Deleted. 38 * layout/inlineformatting/LineLayoutContext.h: 39 (WebCore::Layout::LineLayoutContext::UncommittedContent::runs): Deleted. 40 (WebCore::Layout::LineLayoutContext::UncommittedContent::runs const): Deleted. 41 (WebCore::Layout::LineLayoutContext::UncommittedContent::isEmpty const): Deleted. 42 (WebCore::Layout::LineLayoutContext::UncommittedContent::size const): Deleted. 43 (WebCore::Layout::LineLayoutContext::UncommittedContent::width const): Deleted. 44 1 45 2019-11-29 Philippe Normand <pnormand@igalia.com> 2 46 -
trunk/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp
r252865 r252940 49 49 } 50 50 51 LineBreaker::BreakingContext LineBreaker::breakingContextForInlineContent(const LineLayoutContext::RunList& runs, LayoutUnit logicalWidth, LayoutUnit availableWidth, bool lineIsEmpty)52 { 53 if ( logicalWidth<= availableWidth)51 LineBreaker::BreakingContext LineBreaker::breakingContextForInlineContent(const Content& content, LayoutUnit availableWidth, bool lineIsEmpty) 52 { 53 if (content.width() <= availableWidth) 54 54 return { BreakingContext::ContentBreak::Keep, { } }; 55 55 56 auto isTextContent = [](auto& runs) { 56 auto& runs = content.runs(); 57 auto isTextContent = [&] { 57 58 // <span>text</span> is considered a text run even with the [container start][container end] inline items. 58 59 for (auto& run : runs) { … … 65 66 return false; 66 67 }; 67 if (isTextContent( runs)) {68 if (isTextContent()) { 68 69 if (auto trailingPartialContent = wordBreakingBehavior(runs, availableWidth)) 69 70 return { BreakingContext::ContentBreak::Split, trailingPartialContent }; … … 89 90 } 90 91 91 Optional<LineBreaker::BreakingContext::TrailingPartialContent> LineBreaker::wordBreakingBehavior(const LineLayoutContext::RunList& runs, LayoutUnit availableWidth) const92 Optional<LineBreaker::BreakingContext::TrailingPartialContent> LineBreaker::wordBreakingBehavior(const Content::RunList& runs, LayoutUnit availableWidth) const 92 93 { 93 94 // Check where the overflow occurs and use the corresponding style to figure out the breaking behaviour. … … 122 123 } 123 124 124 Optional<LineBreaker::SplitLengthAndWidth> LineBreaker::tryBreakingTextRun(const LineLayoutContext::RunoverflowRun, LayoutUnit availableWidth) const125 Optional<LineBreaker::SplitLengthAndWidth> LineBreaker::tryBreakingTextRun(const Content::Run& overflowRun, LayoutUnit availableWidth) const 125 126 { 126 127 ASSERT(overflowRun.inlineItem.isText()); … … 138 139 } 139 140 141 bool LineBreaker::Content::isAtContentBoundary(const InlineItem& inlineItem, const Content& content) 142 { 143 // https://drafts.csswg.org/css-text-3/#line-break-details 144 // Figure out if the new incoming content puts the uncommitted content on commit boundary. 145 // e.g. <span>continuous</span> <- uncomitted content -> 146 // [inline container start][text content][inline container end] 147 // An incoming <img> box would enable us to commit the "<span>continuous</span>" content 148 // while additional text content would not. 149 ASSERT(!inlineItem.isFloat() && !inlineItem.isForcedLineBreak()); 150 if (content.isEmpty()) { 151 // Can't decide it yet. 152 return false; 153 } 154 155 auto* lastUncomittedContent = &content.runs().last().inlineItem; 156 if (inlineItem.isText()) { 157 // any content' ' -> whitespace is always a commit boundary. 158 if (downcast<InlineTextItem>(inlineItem).isWhitespace()) 159 return true; 160 // <span>text -> the inline container start and the text content form an unbreakable continuous content. 161 if (lastUncomittedContent->isContainerStart()) 162 return false; 163 // </span>text -> need to check what's before the </span>. 164 // text</span>text -> continuous content 165 // <img></span>text -> commit bounday 166 if (lastUncomittedContent->isContainerEnd()) { 167 auto& runs = content.runs(); 168 // text</span><span></span></span>text -> check all the way back until we hit either a box or some text 169 for (auto i = content.size(); i--;) { 170 auto& previousInlineItem = runs[i].inlineItem; 171 if (previousInlineItem.isContainerStart() || previousInlineItem.isContainerEnd()) 172 continue; 173 ASSERT(previousInlineItem.isText() || previousInlineItem.isBox()); 174 lastUncomittedContent = &previousInlineItem; 175 break; 176 } 177 // Did not find any content (e.g. <span></span>text) 178 if (lastUncomittedContent->isContainerEnd()) 179 return false; 180 } 181 // texttext -> continuous content. 182 // ' 'text -> commit boundary. 183 if (lastUncomittedContent->isText()) 184 return downcast<InlineTextItem>(*lastUncomittedContent).isWhitespace(); 185 // <img>text -> the inline box is on a commit boundary. 186 if (lastUncomittedContent->isBox()) 187 return true; 188 ASSERT_NOT_REACHED(); 189 } 190 191 if (inlineItem.isBox()) { 192 // <span><img> -> the inline container start and the content form an unbreakable continuous content. 193 if (lastUncomittedContent->isContainerStart()) 194 return false; 195 // </span><img> -> ok to commit the </span>. 196 if (lastUncomittedContent->isContainerEnd()) 197 return true; 198 // <img>text and <img><img> -> these combinations are ok to commit. 199 if (lastUncomittedContent->isText() || lastUncomittedContent->isBox()) 200 return true; 201 ASSERT_NOT_REACHED(); 202 } 203 204 if (inlineItem.isContainerStart() || inlineItem.isContainerEnd()) { 205 // <span><span> or </span><span> -> can't commit the previous content yet. 206 if (lastUncomittedContent->isContainerStart() || lastUncomittedContent->isContainerEnd()) 207 return false; 208 // ' '<span> -> let's commit the whitespace 209 // text<span> -> but not yet the non-whitespace; we need to know what comes next (e.g. text<span>text or text<span><img>). 210 if (lastUncomittedContent->isText()) 211 return downcast<InlineTextItem>(*lastUncomittedContent).isWhitespace(); 212 // <img><span> -> it's ok to commit the inline box content. 213 // <img></span> -> the inline box and the closing inline container form an unbreakable continuous content. 214 if (lastUncomittedContent->isBox()) 215 return inlineItem.isContainerStart(); 216 ASSERT_NOT_REACHED(); 217 } 218 219 ASSERT_NOT_REACHED(); 220 return true; 221 } 222 223 void LineBreaker::Content::append(const InlineItem& inlineItem, LayoutUnit logicalWidth) 224 { 225 m_continousRuns.append({ inlineItem, logicalWidth }); 226 m_width += logicalWidth; 227 } 228 229 void LineBreaker::Content::reset() 230 { 231 m_continousRuns.clear(); 232 m_width = 0; 233 } 234 235 void LineBreaker::Content::trim(unsigned newSize) 236 { 237 for (auto i = m_continousRuns.size(); i--;) 238 m_width -= m_continousRuns[i].logicalWidth; 239 m_continousRuns.shrink(newSize); 240 } 241 140 242 } 141 243 } -
trunk/Source/WebCore/layout/inlineformatting/InlineLineBreaker.h
r252863 r252940 29 29 30 30 #include "LayoutUnit.h" 31 #include "LineLayoutContext.h"32 31 33 32 namespace WebCore { … … 49 48 Optional<TrailingPartialContent> trailingPartialContent; 50 49 }; 51 BreakingContext breakingContextForInlineContent(const LineLayoutContext::RunList&, LayoutUnit logicalWidth, LayoutUnit availableWidth, bool lineIsEmpty); 50 51 // This struct represents the amount of content committed to line breaking at a time e.g. 52 // text content <span>span1</span>between<span>span2</span> 53 // [text][ ][content][ ][container start][span1][container end][between][container start][span2][container end] 54 // -> content chunks -> 55 // [text] 56 // [ ] 57 // [content] 58 // [container start][span1][container end][between][container start][span2][container end] 59 // see https://drafts.csswg.org/css-text-3/#line-break-details 60 struct Content { 61 void append(const InlineItem&, LayoutUnit logicalWidth); 62 void reset(); 63 void trim(unsigned newSize); 64 65 static bool isAtContentBoundary(const InlineItem&, const Content&); 66 67 struct Run { 68 const InlineItem& inlineItem; 69 LayoutUnit logicalWidth; 70 }; 71 using RunList = Vector<Run, 30>; 72 73 RunList& runs() { return m_continousRuns; } 74 const RunList& runs() const { return m_continousRuns; } 75 bool isEmpty() const { return m_continousRuns.isEmpty(); } 76 unsigned size() const { return m_continousRuns.size(); } 77 LayoutUnit width() const { return m_width; } 78 79 private: 80 RunList m_continousRuns; 81 LayoutUnit m_width; 82 }; 83 84 BreakingContext breakingContextForInlineContent(const Content&, LayoutUnit availableWidth, bool lineIsEmpty); 52 85 bool shouldWrapFloatBox(LayoutUnit floatLogicalWidth, LayoutUnit availableWidth, bool lineIsEmpty); 53 86 54 87 private: 55 88 56 Optional<BreakingContext::TrailingPartialContent> wordBreakingBehavior(const LineLayoutContext::RunList&, LayoutUnit availableWidth) const;89 Optional<BreakingContext::TrailingPartialContent> wordBreakingBehavior(const Content::RunList&, LayoutUnit availableWidth) const; 57 90 58 91 struct SplitLengthAndWidth { … … 60 93 LayoutUnit leftLogicalWidth; 61 94 }; 62 Optional<SplitLengthAndWidth> tryBreakingTextRun(const LineLayoutContext::RunoverflowRun, LayoutUnit availableWidth) const;95 Optional<SplitLengthAndWidth> tryBreakingTextRun(const Content::Run& overflowRun, LayoutUnit availableWidth) const; 63 96 }; 64 97 -
trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp
r252921 r252940 68 68 } 69 69 70 void LineLayoutContext::UncommittedContent::add(const InlineItem& inlineItem, LayoutUnit logicalWidth)71 {72 m_uncommittedRuns.append({ inlineItem, logicalWidth });73 m_width += logicalWidth;74 }75 76 void LineLayoutContext::UncommittedContent::reset()77 {78 m_uncommittedRuns.clear();79 m_width = 0;80 }81 82 70 LineLayoutContext::LineLayoutContext(const InlineFormattingContext& inlineFormattingContext, const InlineItems& inlineItems) 83 71 : m_inlineFormattingContext(inlineFormattingContext) … … 193 181 // When the uncommitted content fits(or the line is empty), add the line break to this line as well. 194 182 if (isEndOfLine == IsEndOfLine::No) { 195 m_uncommittedContent.a dd(inlineItem, itemLogicalWidth);183 m_uncommittedContent.append(inlineItem, itemLogicalWidth); 196 184 commitPendingContent(line); 197 185 } … … 200 188 // 201 189 auto isEndOfLine = IsEndOfLine::No; 202 if (!m_uncommittedContent.isEmpty() && shouldProcessUncommittedContent(inlineItem)) 190 // Can we commit the pending content already? 191 if (LineBreaker::Content::isAtContentBoundary(inlineItem, m_uncommittedContent)) 203 192 isEndOfLine = processUncommittedContent(line); 204 193 // The current item might fit as well. 205 194 if (isEndOfLine == IsEndOfLine::No) 206 m_uncommittedContent.a dd(inlineItem, itemLogicalWidth);195 m_uncommittedContent.append(inlineItem, itemLogicalWidth); 207 196 return isEndOfLine; 208 197 } … … 212 201 // Check if the pending content fits. 213 202 auto lineIsConsideredEmpty = line.isVisuallyEmpty() && !line.hasIntrusiveFloat(); 214 auto breakingContext = LineBreaker().breakingContextForInlineContent(m_uncommittedContent .runs(), m_uncommittedContent.width(), line.availableWidth(), lineIsConsideredEmpty);203 auto breakingContext = LineBreaker().breakingContextForInlineContent(m_uncommittedContent, line.availableWidth(), lineIsConsideredEmpty); 215 204 // The uncommitted content can fully, partially fit the current line (commit/partial commit) or not at all (reset). 216 205 if (breakingContext.contentBreak == LineBreaker::BreakingContext::ContentBreak::Keep) … … 230 219 // Keep the non-overflow part of the uncommitted runs and add the trailing partial content. 231 220 m_uncommittedContent.trim(overflowInlineTextItemIndex); 232 m_uncommittedContent.a dd(*m_trailingPartialTextItem, breakingContext.trailingPartialContent->logicalWidth);221 m_uncommittedContent.append(*m_trailingPartialTextItem, breakingContext.trailingPartialContent->logicalWidth); 233 222 commitPendingContent(line); 234 223 } else if (breakingContext.contentBreak == LineBreaker::BreakingContext::ContentBreak::Wrap) … … 239 228 } 240 229 241 bool LineLayoutContext::shouldProcessUncommittedContent(const InlineItem& inlineItem) const242 {243 // https://drafts.csswg.org/css-text-3/#line-break-details244 // Figure out if the new incoming content puts the uncommitted content on commit boundary.245 // e.g. <span>continuous</span> <- uncomitted content ->246 // [inline container start][text content][inline container end]247 // An incoming <img> box would enable us to commit the "<span>continuous</span>" content248 // while additional text content would not.249 ASSERT(!inlineItem.isFloat() && !inlineItem.isForcedLineBreak());250 ASSERT(!m_uncommittedContent.isEmpty());251 252 auto* lastUncomittedContent = &m_uncommittedContent.runs().last().inlineItem;253 if (inlineItem.isText()) {254 // any content' ' -> whitespace is always a commit boundary.255 if (downcast<InlineTextItem>(inlineItem).isWhitespace())256 return true;257 // <span>text -> the inline container start and the text content form an unbreakable continuous content.258 if (lastUncomittedContent->isContainerStart())259 return false;260 // </span>text -> need to check what's before the </span>.261 // text</span>text -> continuous content262 // <img></span>text -> commit bounday263 if (lastUncomittedContent->isContainerEnd()) {264 auto& runs = m_uncommittedContent.runs();265 // text</span><span></span></span>text -> check all the way back until we hit either a box or some text266 for (auto i = m_uncommittedContent.size(); i--;) {267 auto& previousInlineItem = runs[i].inlineItem;268 if (previousInlineItem.isContainerStart() || previousInlineItem.isContainerEnd())269 continue;270 ASSERT(previousInlineItem.isText() || previousInlineItem.isBox());271 lastUncomittedContent = &previousInlineItem;272 break;273 }274 // Did not find any content (e.g. <span></span>text)275 if (lastUncomittedContent->isContainerEnd())276 return false;277 }278 // texttext -> continuous content.279 // ' 'text -> commit boundary.280 if (lastUncomittedContent->isText())281 return downcast<InlineTextItem>(*lastUncomittedContent).isWhitespace();282 // <img>text -> the inline box is on a commit boundary.283 if (lastUncomittedContent->isBox())284 return true;285 ASSERT_NOT_REACHED();286 }287 288 if (inlineItem.isBox()) {289 // <span><img> -> the inline container start and the content form an unbreakable continuous content.290 if (lastUncomittedContent->isContainerStart())291 return false;292 // </span><img> -> ok to commit the </span>.293 if (lastUncomittedContent->isContainerEnd())294 return true;295 // <img>text and <img><img> -> these combinations are ok to commit.296 if (lastUncomittedContent->isText() || lastUncomittedContent->isBox())297 return true;298 ASSERT_NOT_REACHED();299 }300 301 if (inlineItem.isContainerStart() || inlineItem.isContainerEnd()) {302 // <span><span> or </span><span> -> can't commit the previous content yet.303 if (lastUncomittedContent->isContainerStart() || lastUncomittedContent->isContainerEnd())304 return false;305 // ' '<span> -> let's commit the whitespace306 // text<span> -> but not yet the non-whitespace; we need to know what comes next (e.g. text<span>text or text<span><img>).307 if (lastUncomittedContent->isText())308 return downcast<InlineTextItem>(*lastUncomittedContent).isWhitespace();309 // <img><span> -> it's ok to commit the inline box content.310 // <img></span> -> the inline box and the closing inline container form an unbreakable continuous content.311 if (lastUncomittedContent->isBox())312 return inlineItem.isContainerStart();313 ASSERT_NOT_REACHED();314 }315 316 ASSERT_NOT_REACHED();317 return true;318 }319 320 void LineLayoutContext::UncommittedContent::trim(unsigned newSize)321 {322 for (auto i = m_uncommittedRuns.size(); i--;)323 m_width -= m_uncommittedRuns[i].logicalWidth;324 m_uncommittedRuns.shrink(newSize);325 }326 327 328 230 } 329 231 } -
trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.h
r252865 r252940 28 28 #if ENABLE(LAYOUT_FORMATTING_CONTEXT) 29 29 30 #include "InlineLineBreaker.h" 30 31 #include "InlineLineBuilder.h" 31 32 … … 50 51 LineContent layoutLine(LineBuilder&, unsigned leadingInlineItemIndex, Optional<PartialContent> leadingPartialContent); 51 52 52 struct Run {53 const InlineItem& inlineItem;54 LayoutUnit logicalWidth;55 };56 57 using RunList = Vector<Run, 30>;58 59 53 private: 60 54 const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; } … … 65 59 bool shouldProcessUncommittedContent(const InlineItem&) const; 66 60 IsEndOfLine processUncommittedContent(LineBuilder&); 67 68 struct UncommittedContent {69 void add(const InlineItem&, LayoutUnit logicalWidth);70 void reset();71 void trim(unsigned newSize);72 73 RunList& runs() { return m_uncommittedRuns; }74 const RunList& runs() const { return m_uncommittedRuns; }75 bool isEmpty() const { return m_uncommittedRuns.isEmpty(); }76 unsigned size() const { return m_uncommittedRuns.size(); }77 LayoutUnit width() const { return m_width; }78 79 private:80 RunList m_uncommittedRuns;81 LayoutUnit m_width;82 };83 61 84 62 const InlineFormattingContext& m_inlineFormattingContext; 85 63 const InlineItems& m_inlineItems; 86 UncommittedContent m_uncommittedContent;64 LineBreaker::Content m_uncommittedContent; 87 65 unsigned m_committedInlineItemCount { 0 }; 88 66 Vector<WeakPtr<InlineItem>> m_floats;
Note: See TracChangeset
for help on using the changeset viewer.