Changeset 254661 in webkit
- Timestamp:
- Jan 15, 2020 6:23:39 PM (4 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r254660 r254661 1 2020-01-15 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][IFC] LineBreaker::shouldWrapInlineContent should take the candidate content width 4 https://bugs.webkit.org/show_bug.cgi?id=206305 5 <rdar://problem/58613977> 6 7 Reviewed by Antti Koivisto. 8 9 We already have the width information of the candidate runs. Let's not loop through the runs just to re-collect the logical width. 10 ~3% progression on PerformanceTests/Layout/line-layout-simple.html. 11 12 * layout/inlineformatting/InlineLineBreaker.cpp: 13 (WebCore::Layout::LineBreaker::shouldWrapInlineContent): 14 (WebCore::Layout::LineBreaker::tryWrappingInlineContent const): 15 (WebCore::Layout::ContinuousContent::ContinuousContent): 16 * layout/inlineformatting/InlineLineBreaker.h: 17 * layout/inlineformatting/LineLayoutContext.cpp: 18 (WebCore::Layout::LineCandidateContent::inlineContentLogicalWidth const): 19 (WebCore::Layout::LineCandidateContent::append): 20 (WebCore::Layout::LineCandidateContent::reset): 21 (WebCore::Layout::LineLayoutContext::tryAddingInlineItems): 22 1 23 2020-01-15 Commit Queue <commit-queue@webkit.org> 2 24 -
trunk/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp
r254629 r254661 51 51 } 52 52 53 static inline Optional<size_t> lastWrapOpportunityIndex(const LineBreaker::RunList& runList) 54 { 55 // <span style="white-space: pre">no_wrap</span><span>yes wrap</span><span style="white-space: pre">no_wrap</span>. 56 // [container start][no_wrap][container end][container start][yes] <- continuous content 57 // [ ] <- continuous content 58 // [wrap][container end][container start][no_wrap][container end] <- continuous content 59 // Return #0 as the index where the second continuous content can wrap at. 60 ASSERT(!runList.isEmpty()); 61 auto lastItemIndex = runList.size() - 1; 62 return isWrappingAllowed(runList[lastItemIndex].inlineItem.style()) ? makeOptional(lastItemIndex) : WTF::nullopt; 63 } 64 53 65 struct ContinuousContent { 54 ContinuousContent(const LineBreaker::RunList& );66 ContinuousContent(const LineBreaker::RunList&, InlineLayoutUnit contentLogicalWidth); 55 67 56 68 const LineBreaker::RunList& runs() const { return m_runs; } … … 65 77 bool hasTrailingCollapsibleContent() const { return !!m_trailingCollapsibleContent.width; } 66 78 bool isTrailingContentFullyCollapsible() const { return m_trailingCollapsibleContent.isFullyCollapsible; } 67 Optional<size_t> lastWrapOpportunityIndex() const;68 79 69 80 Optional<size_t> firstTextRunIndex() const; … … 105 116 } 106 117 107 LineBreaker::Result LineBreaker::shouldWrapInlineContent(const RunList& candidateRuns, const LineStatus& lineStatus) 108 { 109 auto candidateContent = ContinuousContent { candidateRuns }; 118 LineBreaker::Result LineBreaker::shouldWrapInlineContent(const RunList& candidateRuns, InlineLayoutUnit candidateContentLogicalWidth, const LineStatus& lineStatus) 119 { 120 auto inlineContentWrapping = [&] { 121 if (candidateContentLogicalWidth <= lineStatus.availableWidth) 122 return Result { Result::Action::Keep }; 123 #if USE_FLOAT_AS_INLINE_LAYOUT_UNIT 124 // Preferred width computation sums up floats while line breaker substracts them. This can lead to epsilon-scale differences. 125 if (WTF::areEssentiallyEqual(candidateContentLogicalWidth, lineStatus.availableWidth)) 126 return Result { Result::Action::Keep }; 127 #endif 128 return tryWrappingInlineContent(candidateRuns, candidateContentLogicalWidth, lineStatus); 129 }; 130 131 auto result = inlineContentWrapping(); 132 if (result.action == Result::Action::Keep) { 133 // If this is not the end of the line, hold on to the last eligible line wrap opportunity so that we could revert back 134 // to this position if no other line breaking opportunity exists in this content. 135 if (auto lastLineWrapOpportunityIndex = lastWrapOpportunityIndex(candidateRuns)) { 136 auto isEligibleLineWrapOpportunity = [&] (auto& candidateItem) { 137 // Just check for leading collapsible whitespace for now. 138 if (!lineStatus.lineIsEmpty || !candidateItem.isText() || !downcast<InlineTextItem>(candidateItem).isWhitespace()) 139 return true; 140 return shouldKeepBeginningOfLineWhitespace(candidateItem.style()); 141 }; 142 auto& inlineItem = candidateRuns[*lastLineWrapOpportunityIndex].inlineItem; 143 if (isEligibleLineWrapOpportunity(inlineItem)) 144 m_lastWrapOpportunity = &inlineItem; 145 } 146 } 147 return result; 148 } 149 150 LineBreaker::Result LineBreaker::tryWrappingInlineContent(const RunList& candidateRuns, InlineLayoutUnit candidateContentLogicalWidth, const LineStatus& lineStatus) const 151 { 152 auto candidateContent = ContinuousContent { candidateRuns, candidateContentLogicalWidth }; 110 153 ASSERT(!candidateContent.isEmpty()); 111 auto result = tryWrappingInlineContent(candidateContent, lineStatus); 112 // If this is not the end of the line, hold on to the last eligible line wrap opportunity so that we could revert back 113 // to this position if no other line breaking opportunity exists in this content. 114 if (result.isEndOfLine == IsEndOfLine::Yes) 115 return result; 116 if (auto lastLineWrapOpportunityIndex = candidateContent.lastWrapOpportunityIndex()) { 117 auto isEligibleLineWrapOpportunity = [&] (auto& candidateItem) { 118 // Just check for leading collapsible whitespace for now. 119 if (!lineStatus.lineIsEmpty || !candidateItem.isText() || !downcast<InlineTextItem>(candidateItem).isWhitespace()) 120 return true; 121 return shouldKeepBeginningOfLineWhitespace(candidateItem.style()); 122 }; 123 auto& inlineItem = candidateContent.runs()[*lastLineWrapOpportunityIndex].inlineItem; 124 if (isEligibleLineWrapOpportunity(inlineItem)) 125 m_lastWrapOpportunity = &inlineItem; 126 } 127 return result; 128 } 129 130 LineBreaker::Result LineBreaker::tryWrappingInlineContent(const ContinuousContent& candidateContent, const LineStatus& lineStatus) const 131 { 132 if (candidateContent.width() <= lineStatus.availableWidth) 133 return { Result::Action::Keep }; 134 135 #if USE_FLOAT_AS_INLINE_LAYOUT_UNIT 136 // Preferred width computation sums up floats while line breaker substracts them. This can lead to epsilon-scale differences. 137 if (WTF::areEssentiallyEqual(candidateContent.width(), lineStatus.availableWidth)) 138 return { Result::Action::Keep }; 139 #endif 140 154 155 ASSERT(candidateContent.width() > lineStatus.availableWidth); 141 156 if (candidateContent.hasTrailingCollapsibleContent()) { 142 157 ASSERT(candidateContent.hasTextContentOnly()); … … 341 356 } 342 357 343 ContinuousContent::ContinuousContent(const LineBreaker::RunList& runs )358 ContinuousContent::ContinuousContent(const LineBreaker::RunList& runs, InlineLayoutUnit contentLogicalWidth) 344 359 : m_runs(runs) 360 , m_width(contentLogicalWidth) 345 361 { 346 362 // Figure out the trailing collapsible state. … … 373 389 } 374 390 } 375 // The trailing whitespace loop above is mostly about inspecting the last entry, so while it376 // looks like we are looping through the m_runs twice, it's really just one full loop in addition to checking the last run.377 for (auto& run : m_runs) {378 // Line break is not considered an inline content.379 ASSERT(!run.inlineItem.isLineBreak());380 m_width += run.logicalWidth;381 }382 391 } 383 392 … … 440 449 } 441 450 442 Optional<size_t> ContinuousContent::lastWrapOpportunityIndex() const443 {444 // <span style="white-space: pre">no_wrap</span><span>yes wrap</span><span style="white-space: pre">no_wrap</span>.445 // [container start][no_wrap][container end][container start][yes] <- continuous content446 // [ ] <- continuous content447 // [wrap][container end][container start][no_wrap][container end] <- continuous content448 // Return #0 as the index where the second continuous content can wrap at.449 auto lastItemIndex = m_runs.size() - 1;450 return isWrappingAllowed(m_runs[lastItemIndex].inlineItem.style()) ? makeOptional(lastItemIndex) : WTF::nullopt;451 }452 453 451 void ContinuousContent::TrailingCollapsibleContent::reset() 454 452 { -
trunk/Source/WebCore/layout/inlineformatting/InlineLineBreaker.h
r254032 r254661 80 80 bool lineIsEmpty { true }; 81 81 }; 82 Result shouldWrapInlineContent(const RunList& candidateRuns, const LineStatus&);82 Result shouldWrapInlineContent(const RunList& candidateRuns, InlineLayoutUnit candidateContentLogicalWidth, const LineStatus&); 83 83 bool shouldWrapFloatBox(InlineLayoutUnit floatLogicalWidth, InlineLayoutUnit availableWidth, bool lineIsEmpty); 84 84 … … 96 96 // see https://drafts.csswg.org/css-text-3/#line-break-details 97 97 Optional<WrappedTextContent> wrapTextContent(const RunList&, const LineStatus&) const; 98 Result tryWrappingInlineContent(const ContinuousContent&, const LineStatus&) const;98 Result tryWrappingInlineContent(const RunList&, InlineLayoutUnit candidateContentLogicalWidth, const LineStatus&) const; 99 99 Optional<PartialRun> tryBreakingTextRun(const Run& overflowRun, InlineLayoutUnit availableWidth) const; 100 100 -
trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp
r254630 r254661 182 182 bool hasIntrusiveFloats() const { return !m_floats.isEmpty(); } 183 183 const LineBreaker::RunList& inlineRuns() const { return m_inlineRuns; } 184 InlineLayoutUnit inlineContentLogicalWidth() const { return m_inlineContentLogicalWidth; } 184 185 const LineLayoutContext::FloatList& floats() const { return m_floats; } 185 186 … … 191 192 void setTrailingLineBreak(const InlineItem& lineBreakItem) { m_trailingLineBreak = &lineBreakItem; } 192 193 194 InlineLayoutUnit m_inlineContentLogicalWidth { 0 }; 193 195 LineBreaker::RunList m_inlineRuns; 194 196 LineLayoutContext::FloatList m_floats; … … 203 205 if (inlineItem.isFloat()) 204 206 return m_floats.append(makeWeakPtr(inlineItem)); 207 m_inlineContentLogicalWidth += *logicalWidth; 205 208 m_inlineRuns.append({ inlineItem, *logicalWidth }); 206 209 } … … 208 211 void LineCandidateContent::reset() 209 212 { 213 m_inlineContentLogicalWidth = 0; 210 214 m_inlineRuns.clear(); 211 215 m_floats.clear(); … … 411 415 412 416 auto& candidateRuns = candidateContent.inlineRuns(); 413 auto result = lineBreaker.shouldWrapInlineContent(candidateRuns, lineStatus);417 auto result = lineBreaker.shouldWrapInlineContent(candidateRuns, candidateContent.inlineContentLogicalWidth(), lineStatus); 414 418 if (result.action == LineBreaker::Result::Action::Keep) { 415 419 // This continuous content can be fully placed on the current line.
Note: See TracChangeset
for help on using the changeset viewer.