Changeset 256507 in webkit
- Timestamp:
- Feb 13, 2020 8:22:10 AM (4 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r256505 r256507 1 2020-02-13 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][IFC] LineCandidateContent can have only one float item 4 https://bugs.webkit.org/show_bug.cgi?id=207681 5 <rdar://problem/59413044> 6 7 Reviewed by Antti Koivisto. 8 9 Floats should not be considered as inline content. They shrink the available space but we never 10 add them to the line. This patch decouples InlineContent and candidate floats. Also there can only be 11 one float box per candidate content (since there's always a soft wrap opportunity before/after the float box). 12 13 * layout/inlineformatting/LineLayoutContext.cpp: 14 (WebCore::Layout::LineCandidate::InlineContent::runs const): 15 (WebCore::Layout::LineCandidate::InlineContent::logicalWidth const): 16 (WebCore::Layout::LineCandidate::InlineContent::trailingLineBreak const): 17 (WebCore::Layout::LineCandidate::InlineContent::appendLineBreak): 18 (WebCore::Layout::LineCandidate::InlineContent::setTrailingLineBreak): 19 (WebCore::Layout::LineCandidate::InlineContent::appendInlineItem): 20 (WebCore::Layout::LineCandidate::reset): 21 (WebCore::Layout::LineCandidate::InlineContent::reset): 22 (WebCore::Layout::LineLayoutContext::layoutLine): 23 (WebCore::Layout::LineLayoutContext::nextContentForLine): 24 (WebCore::Layout::LineLayoutContext::tryAddingFloatItem): 25 (WebCore::Layout::LineLayoutContext::tryAddingInlineItems): 26 (WebCore::Layout::LineCandidateContent::appendLineBreak): Deleted. 27 (WebCore::Layout::LineCandidateContent::appendFloat): Deleted. 28 (WebCore::Layout::LineCandidateContent::hasIntrusiveFloats const): Deleted. 29 (WebCore::Layout::LineCandidateContent::inlineRuns const): Deleted. 30 (WebCore::Layout::LineCandidateContent::inlineContentLogicalWidth const): Deleted. 31 (WebCore::Layout::LineCandidateContent::floats const): Deleted. 32 (WebCore::Layout::LineCandidateContent::trailingLineBreak const): Deleted. 33 (WebCore::Layout::LineCandidateContent::setTrailingLineBreak): Deleted. 34 (WebCore::Layout::LineCandidateContent::appendInlineContent): Deleted. 35 (WebCore::Layout::LineCandidateContent::reset): Deleted. 36 (WebCore::Layout::LineLayoutContext::tryAddingFloatItems): Deleted. 37 * layout/inlineformatting/LineLayoutContext.h: 38 1 39 2020-02-13 Chris Lord <clord@igalia.com> 2 40 -
trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp
r256499 r256507 172 172 } 173 173 174 struct LineCandidateContent { 175 void appendInlineContent(const InlineItem&, InlineLayoutUnit logicalWidth); 176 void appendLineBreak(const InlineItem& inlineItem) { setTrailingLineBreak(inlineItem); } 177 void appendFloat(const InlineItem& inlineItem) { m_floats.append(&inlineItem); } 178 179 bool hasIntrusiveFloats() const { return !m_floats.isEmpty(); } 180 const LineBreaker::RunList& inlineRuns() const { return m_inlineRuns; } 181 InlineLayoutUnit inlineContentLogicalWidth() const { return m_inlineContentLogicalWidth; } 182 const LineLayoutContext::FloatList& floats() const { return m_floats; } 183 184 const InlineItem* trailingLineBreak() const { return m_trailingLineBreak; } 185 174 struct LineCandidate { 186 175 void reset(); 187 176 188 private: 189 void setTrailingLineBreak(const InlineItem& lineBreakItem) { m_trailingLineBreak = &lineBreakItem; } 190 191 InlineLayoutUnit m_inlineContentLogicalWidth { 0 }; 192 LineBreaker::RunList m_inlineRuns; 193 LineLayoutContext::FloatList m_floats; 194 const InlineItem* m_trailingLineBreak { nullptr }; 177 struct InlineContent { 178 const LineBreaker::RunList& runs() const { return m_inlineRuns; } 179 InlineLayoutUnit logicalWidth() const { return m_LogicalWidth; } 180 const InlineItem* trailingLineBreak() const { return m_trailingLineBreak; } 181 182 void appendInlineItem(const InlineItem&, InlineLayoutUnit logicalWidth); 183 void appendLineBreak(const InlineItem& inlineItem) { setTrailingLineBreak(inlineItem); } 184 void reset(); 185 186 private: 187 void setTrailingLineBreak(const InlineItem& lineBreakItem) { m_trailingLineBreak = &lineBreakItem; } 188 189 InlineLayoutUnit m_LogicalWidth { 0 }; 190 LineBreaker::RunList m_inlineRuns; 191 const InlineItem* m_trailingLineBreak { nullptr }; 192 }; 193 // Candidate content is either a collection of inline items or a float box. 194 InlineContent inlineContent; 195 const InlineItem* floatItem { nullptr }; 195 196 }; 196 197 197 inline void LineCandidate Content::appendInlineContent(const InlineItem& inlineItem, InlineLayoutUnit logicalWidth)198 { 199 m_ inlineContentLogicalWidth += logicalWidth;198 inline void LineCandidate::InlineContent::appendInlineItem(const InlineItem& inlineItem, InlineLayoutUnit logicalWidth) 199 { 200 m_LogicalWidth += logicalWidth; 200 201 m_inlineRuns.append({ inlineItem, logicalWidth }); 201 202 } 202 203 203 inline void LineCandidateContent::reset() 204 { 205 m_inlineContentLogicalWidth = 0; 204 inline void LineCandidate::reset() 205 { 206 floatItem = { }; 207 inlineContent.reset(); 208 } 209 210 inline void LineCandidate::InlineContent::reset() 211 { 212 m_LogicalWidth = 0; 206 213 m_inlineRuns.clear(); 207 m_floats.clear();208 214 m_trailingLineBreak = nullptr; 209 215 } … … 260 266 auto currentItemIndex = layoutRange.start; 261 267 unsigned committedInlineItemCount = 0; 262 auto candidateContent = LineCandidateContent{ };268 auto lineCandidate = LineCandidate { }; 263 269 while (currentItemIndex < layoutRange.end) { 264 270 // 1. Collect the set of runs that we can commit to the line as one entity e.g. <span>text_and_span_start_span_end</span>. … … 266 272 // 3. Check if the content fits the line and commit the content accordingly (full, partial or not commit at all). 267 273 // 4. Return if we are at the end of the line either by not being able to fit more content or because of an explicit line break. 268 nextContentForLine( candidateContent, currentItemIndex, layoutRange, partialLeadingContentLength, line.lineBox().logicalWidth());269 if ( candidateContent.hasIntrusiveFloats()) {270 // Add floats first because they shrink the available horizontal space for the rest of the content.271 auto result = tryAddingFloatItem s(line, candidateContent.floats());274 nextContentForLine(lineCandidate, currentItemIndex, layoutRange, partialLeadingContentLength, line.lineBox().logicalWidth()); 275 if (lineCandidate.floatItem) { 276 // Floats shrink the available horizontal space for the rest of the content, but they are not added on the line. 277 auto result = tryAddingFloatItem(line, *lineCandidate.floatItem); 272 278 committedInlineItemCount += result.committedCount; 273 279 if (result.isEndOfLine == LineBreaker::IsEndOfLine::Yes) { 274 // Floats takeup all the horizontal space.280 // This float takes up all the horizontal space. 275 281 return close(line, layoutRange, committedInlineItemCount, { }); 276 282 } 277 } 278 if (!candidateContent.inlineRuns().isEmpty()) { 279 // Now check if we can put this content on the current line. 280 auto result = tryAddingInlineItems(lineBreaker, line, candidateContent); 281 if (result.revertTo) { 282 ASSERT(!result.committedCount); 283 ASSERT(result.isEndOfLine == LineBreaker::IsEndOfLine::Yes); 284 // An earlier line wrapping opportunity turned out to be the final breaking position. 285 rebuildLineForRevert(line, *result.revertTo, layoutRange); 283 ASSERT(lineCandidate.inlineContent.runs().isEmpty()); 284 } else { 285 auto& inlineContent = lineCandidate.inlineContent; 286 if (!inlineContent.runs().isEmpty()) { 287 // Now check if we can put this content on the current line. 288 auto result = tryAddingInlineItems(lineBreaker, line, lineCandidate); 289 if (result.revertTo) { 290 ASSERT(!result.committedCount); 291 ASSERT(result.isEndOfLine == LineBreaker::IsEndOfLine::Yes); 292 // An earlier line wrapping opportunity turned out to be the final breaking position. 293 rebuildLineForRevert(line, *result.revertTo, layoutRange); 294 } 295 committedInlineItemCount += result.committedCount; 296 if (result.isEndOfLine == LineBreaker::IsEndOfLine::Yes) { 297 // We can't place any more items on the current line. 298 return close(line, layoutRange, committedInlineItemCount, result.partialContent); 299 } 300 } else if (auto* trailingLineBreak = inlineContent.trailingLineBreak()) { 301 line.append(*trailingLineBreak, 0); 302 return close(line, layoutRange, ++committedInlineItemCount, { }); 286 303 } 287 committedInlineItemCount += result.committedCount;288 if (result.isEndOfLine == LineBreaker::IsEndOfLine::Yes) {289 // We can't place any more items on the current line.290 return close(line, layoutRange, committedInlineItemCount, result.partialContent);291 }292 } else if (auto* trailingLineBreak = candidateContent.trailingLineBreak()) {293 line.append(*trailingLineBreak, 0);294 return close(line, layoutRange, ++committedInlineItemCount, { });295 304 } 296 305 currentItemIndex = layoutRange.start + committedInlineItemCount; … … 331 340 } 332 341 333 void LineLayoutContext::nextContentForLine(LineCandidate Content& candidateContent, unsigned currentInlineItemIndex, const InlineItemRange layoutRange, Optional<unsigned> partialLeadingContentLength, InlineLayoutUnit currentLogicalRight)342 void LineLayoutContext::nextContentForLine(LineCandidate& lineCandidate, unsigned currentInlineItemIndex, const InlineItemRange layoutRange, Optional<unsigned> partialLeadingContentLength, InlineLayoutUnit currentLogicalRight) 334 343 { 335 344 ASSERT(currentInlineItemIndex < layoutRange.end); 336 candidateContent.reset();345 lineCandidate.reset(); 337 346 // 1. Simply add any overflow content from the previous line to the candidate content. It's always a text content. 338 347 // 2. Find the next soft wrap position or explicit line break. … … 347 356 m_partialLeadingTextItem = downcast<InlineTextItem>(m_inlineItems[currentInlineItemIndex]).right(*partialLeadingContentLength); 348 357 auto itemWidth = inlineItemWidth(*m_partialLeadingTextItem, currentLogicalRight); 349 candidateContent.appendInlineContent(*m_partialLeadingTextItem, itemWidth);358 lineCandidate.inlineContent.appendInlineItem(*m_partialLeadingTextItem, itemWidth); 350 359 currentLogicalRight += itemWidth; 351 360 ++currentInlineItemIndex; … … 355 364 auto& inlineItem = m_inlineItems[index]; 356 365 if (inlineItem.isText() || inlineItem.isContainerStart() || inlineItem.isContainerEnd()) { 366 ASSERT(!lineCandidate.floatItem); 357 367 auto inlineItenmWidth = inlineItemWidth(inlineItem, currentLogicalRight); 358 candidateContent.appendInlineContent(inlineItem, inlineItenmWidth);368 lineCandidate.inlineContent.appendInlineItem(inlineItem, inlineItenmWidth); 359 369 currentLogicalRight += inlineItenmWidth; 360 370 continue; … … 363 373 // Floats are not part of the line context. 364 374 // FIXME: Check if their width should be added to currentLogicalRight. 365 candidateContent.appendFloat(inlineItem); 375 ASSERT(!lineCandidate.floatItem); 376 ASSERT(lineCandidate.inlineContent.runs().isEmpty()); 377 lineCandidate.floatItem = &inlineItem; 366 378 continue; 367 379 } 368 380 if (inlineItem.isLineBreak()) { 369 candidateContent.appendLineBreak(inlineItem);381 lineCandidate.inlineContent.appendLineBreak(inlineItem); 370 382 continue; 371 383 } … … 374 386 } 375 387 376 LineLayoutContext::Result LineLayoutContext::tryAddingFloatItems(LineBuilder& line, const FloatList& floats) 377 { 378 size_t committedFloatItemCount = 0; 379 for (auto& floatItem : floats) { 380 auto logicalWidth = inlineItemWidth(*floatItem, { }); 381 382 auto lineIsConsideredEmpty = line.isVisuallyEmpty() && !line.hasIntrusiveFloat(); 383 if (LineBreaker().shouldWrapFloatBox(logicalWidth, line.availableWidth() + line.trimmableTrailingWidth(), lineIsConsideredEmpty)) 384 return { LineBreaker::IsEndOfLine::Yes, committedFloatItemCount }; 385 // This float can sit on the current line. 386 ++committedFloatItemCount; 387 auto& floatBox = floatItem->layoutBox(); 388 // Shrink available space for current line and move existing inline runs. 389 line.setHasIntrusiveFloat(); 390 if (floatBox.isLeftFloatingPositioned()) 391 line.moveLogicalLeft(logicalWidth); 392 else 393 line.moveLogicalRight(logicalWidth); 394 m_floats.append(floatItem); 395 } 396 return { LineBreaker::IsEndOfLine::No, committedFloatItemCount }; 397 } 398 399 LineLayoutContext::Result LineLayoutContext::tryAddingInlineItems(LineBreaker& lineBreaker, LineBuilder& line, const LineCandidateContent& candidateContent) 388 LineLayoutContext::Result LineLayoutContext::tryAddingFloatItem(LineBuilder& line, const InlineItem& floatItem) 389 { 390 auto logicalWidth = inlineItemWidth(floatItem, { }); 391 392 auto lineIsConsideredEmpty = line.isVisuallyEmpty() && !line.hasIntrusiveFloat(); 393 if (LineBreaker().shouldWrapFloatBox(logicalWidth, line.availableWidth() + line.trimmableTrailingWidth(), lineIsConsideredEmpty)) 394 return { LineBreaker::IsEndOfLine::Yes }; 395 // This float can sit on the current line. 396 auto& floatBox = floatItem.layoutBox(); 397 // Shrink available space for current line and move existing inline runs. 398 line.setHasIntrusiveFloat(); 399 if (floatBox.isLeftFloatingPositioned()) 400 line.moveLogicalLeft(logicalWidth); 401 else 402 line.moveLogicalRight(logicalWidth); 403 m_floats.append(&floatItem); 404 return { LineBreaker::IsEndOfLine::No, 1 }; 405 } 406 407 LineLayoutContext::Result LineLayoutContext::tryAddingInlineItems(LineBreaker& lineBreaker, LineBuilder& line, const LineCandidate& lineCandidate) 400 408 { 401 409 auto shouldDisableHyphenation = [&] { … … 410 418 lineBreaker.setHyphenationDisabled(); 411 419 412 auto& candidateRuns = candidateContent.inlineRuns(); 413 auto result = lineBreaker.shouldWrapInlineContent(candidateRuns, candidateContent.inlineContentLogicalWidth(), lineStatus); 420 auto& inlineContent = lineCandidate.inlineContent; 421 auto& candidateRuns = inlineContent.runs(); 422 auto result = lineBreaker.shouldWrapInlineContent(candidateRuns, inlineContent.logicalWidth(), lineStatus); 414 423 if (result.action == LineBreaker::Result::Action::Keep) { 415 424 // This continuous content can be fully placed on the current line. … … 417 426 line.append(run.inlineItem, run.logicalWidth); 418 427 // Consume trailing line break as well. 419 if (auto* lineBreakItem = candidateContent.trailingLineBreak()) {428 if (auto* lineBreakItem = inlineContent.trailingLineBreak()) { 420 429 line.append(*lineBreakItem, 0); 421 430 return { LineBreaker::IsEndOfLine::Yes, candidateRuns.size() + 1 }; -
trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.h
r256499 r256507 34 34 namespace Layout { 35 35 36 struct LineCandidate Content;36 struct LineCandidate; 37 37 38 38 class LineLayoutContext { … … 57 57 }; 58 58 LineContent layoutLine(LineBuilder&, const InlineItemRange, Optional<unsigned> partialLeadingContentLength); 59 using FloatList = Vector<const InlineItem*>;60 59 61 60 private: 62 void nextContentForLine(LineCandidate Content&, unsigned inlineItemIndex, const InlineItemRange layoutRange, Optional<unsigned> overflowLength, InlineLayoutUnit currentLogicalRight);61 void nextContentForLine(LineCandidate&, unsigned inlineItemIndex, const InlineItemRange layoutRange, Optional<unsigned> overflowLength, InlineLayoutUnit currentLogicalRight); 63 62 struct Result { 64 63 LineBreaker::IsEndOfLine isEndOfLine { LineBreaker::IsEndOfLine::No }; … … 67 66 const InlineItem* revertTo { nullptr }; 68 67 }; 69 Result tryAddingFloatItem s(LineBuilder&, const FloatList&);70 Result tryAddingInlineItems(LineBreaker&, LineBuilder&, const LineCandidate Content&);68 Result tryAddingFloatItem(LineBuilder&, const InlineItem& floatItem); 69 Result tryAddingInlineItems(LineBreaker&, LineBuilder&, const LineCandidate&); 71 70 void rebuildLineForRevert(LineBuilder&, const InlineItem& revertTo, const InlineItemRange layoutRange); 72 71 void commitPartialContent(LineBuilder&, const LineBreaker::RunList&, const LineBreaker::Result::PartialTrailingContent&); … … 81 80 const ContainerBox& m_formattingContextRoot; 82 81 const InlineItems& m_inlineItems; 82 using FloatList = Vector<const InlineItem*>; 83 83 FloatList m_floats; 84 84 Optional<InlineTextItem> m_partialLeadingTextItem;
Note: See TracChangeset
for help on using the changeset viewer.