Changeset 250487 in webkit
- Timestamp:
- Sep 28, 2019, 6:59:27 PM (6 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r250485 r250487 1 2019-09-28 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][IFC] Move horizontal alignment to Line 4 https://bugs.webkit.org/show_bug.cgi?id=202351 5 <rdar://problem/55810139> 6 7 Reviewed by Antti Koivisto. 8 9 Line should be able to finalize the run placement including horizontal alignment. 10 11 * layout/Verification.cpp: 12 (WebCore::Layout::outputMismatchingSimpleLineInformationIfNeeded): 13 * layout/inlineformatting/InlineFormattingContextLineLayout.cpp: 14 (WebCore::Layout::LineInput::LineInput): 15 (WebCore::Layout::LineLayout::LineLayout): 16 (WebCore::Layout::InlineFormattingContext::InlineLayout::layout): 17 (WebCore::Layout::InlineFormattingContext::InlineLayout::computedIntrinsicWidth const): 18 * layout/inlineformatting/InlineLine.cpp: 19 (WebCore::Layout::Line::Line): 20 (WebCore::Layout::Line::isVisuallyEmpty const): 21 (WebCore::Layout::Line::close): 22 (WebCore::Layout::Line::verticalAlignContent): 23 (WebCore::Layout::Line::horizontalAlignContent): 24 (WebCore::Layout::Line::appendInlineContainerStart): 25 (WebCore::Layout::Line::appendTextContent): 26 (WebCore::Layout::Line::appendNonReplacedInlineBox): 27 (WebCore::Layout::Line::appendHardLineBreak): 28 (WebCore::Layout::Line::inlineItemContentHeight const): 29 * layout/inlineformatting/InlineLine.h: 30 1 31 2019-09-28 Wenson Hsieh <wenson_hsieh@apple.com> 2 32 -
trunk/Source/WebCore/layout/Verification.cpp
r250429 r250487 100 100 continue; 101 101 102 stream << "Mismatching: simple run(" << simpleRun.start << ", " << simpleRun.end << ") (" << simpleRun.logicalLeft << ", " << simpleRun.logicalRight << ") layout run(" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->end() << ") (" << inlineRun.logicalLeft() << ", " << inlineRun.logicalRight() << ")"; 102 stream << "Mismatching: simple run(" << simpleRun.start << ", " << simpleRun.end << ") (" << simpleRun.logicalLeft << ", " << simpleRun.logicalRight << ")"; 103 stream << " inline run"; 104 if (inlineRun.textContext()) 105 stream << " (" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->end() << ")"; 106 stream << " (" << inlineRun.logicalLeft() << ", " << inlineRun.logicalTop() << ") (" << inlineRun.logicalWidth() << "x" << inlineRun.logicalHeight() << ")"; 103 107 stream.nextLine(); 104 108 mismatched = true; -
trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h
r250439 r250487 69 69 LineContent placeInlineItems(const LineInput&) const; 70 70 void setupDisplayBoxes(const LineContent&); 71 void alignRuns(TextAlignMode, InlineRuns&, unsigned firstRunIndex, LayoutUnit availableWidth) const;72 71 73 72 private: -
trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp
r250484 r250487 82 82 83 83 struct LineInput { 84 LineInput(const Line::InitialConstraints& initialLineConstraints, Line::SkipVerticalAligment, IndexAndRange firstToProcess, const InlineItems&); 84 LineInput(const Line::InitialConstraints&, TextAlignMode, IndexAndRange firstToProcess, const InlineItems&); 85 LineInput(const Line::InitialConstraints&, IndexAndRange firstToProcess, const InlineItems&); 85 86 86 87 Line::InitialConstraints initialConstraints; 88 TextAlignMode horizontalAlignment; 87 89 // FIXME Alternatively we could just have a second pass with vertical positioning (preferred width computation opts out) 88 Line::Skip VerticalAligment skipVerticalAligment;90 Line::SkipAlignment skipAlignment { Line::SkipAlignment::No }; 89 91 IndexAndRange firstInlineItem; 90 92 const InlineItems& inlineItems; … … 92 94 }; 93 95 94 LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, Line::SkipVerticalAligment skipVerticalAligment, IndexAndRange firstToProcess, const InlineItems& inlineItems)96 LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, TextAlignMode horizontalAlignment, IndexAndRange firstToProcess, const InlineItems& inlineItems) 95 97 : initialConstraints(initialLineConstraints) 96 , skipVerticalAligment(skipVerticalAligment) 98 , horizontalAlignment(horizontalAlignment) 99 , firstInlineItem(firstToProcess) 100 , inlineItems(inlineItems) 101 { 102 } 103 104 LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, IndexAndRange firstToProcess, const InlineItems& inlineItems) 105 : initialConstraints(initialLineConstraints) 106 , skipAlignment(Line::SkipAlignment::Yes) 97 107 , firstInlineItem(firstToProcess) 98 108 , inlineItems(inlineItems) … … 165 175 : m_inlineFormattingContext(inlineFormattingContext) 166 176 , m_lineInput(lineInput) 167 , m_line(inlineFormattingContext, lineInput.initialConstraints, lineInput. skipVerticalAligment)177 , m_line(inlineFormattingContext, lineInput.initialConstraints, lineInput.horizontalAlignment, lineInput.skipAlignment) 168 178 , m_lineHasIntrusiveFloat(lineInput.initialConstraints.lineIsConstrainedByFloat) 169 179 { … … 282 292 IndexAndRange currentInlineItem; 283 293 while (currentInlineItem.index < inlineItems.size()) { 284 auto lineInput = LineInput { initialConstraintsForLine(lineLogicalTop), Line::SkipVerticalAligment::No, currentInlineItem, inlineItems };294 auto lineInput = LineInput { initialConstraintsForLine(lineLogicalTop), formattingRoot().style().textAlign(), currentInlineItem, inlineItems }; 285 295 auto lineLayout = LineLayout { formattingContext(), lineInput }; 286 296 … … 350 360 // Only the horiztonal available width is constrained when computing intrinsic width. 351 361 auto initialLineConstraints = Line::InitialConstraints { { }, widthConstraint(), false, { } }; 352 auto lineInput = LineInput { initialLineConstraints, Line::SkipVerticalAligment::Yes,currentInlineItem, inlineItems };362 auto lineInput = LineInput { initialLineConstraints, currentInlineItem, inlineItems }; 353 363 354 364 auto lineContent = LineLayout(formattingContext, lineInput).layout(); … … 381 391 } 382 392 383 auto& inlineDisplayRuns = formattingState.inlineRuns();384 auto previousLineLastRunIndex = Optional<unsigned> { inlineDisplayRuns.isEmpty() ? Optional<unsigned>() : inlineDisplayRuns.size() - 1 };385 // 9.4.2 Inline formatting contexts386 // A line box is always tall enough for all of the boxes it contains.387 388 393 // Add final display runs to state. 389 394 for (auto& lineRun : lineContent.runList) { … … 394 399 } 395 400 401 // Compute box final geometry. 396 402 auto geometry = formattingContext.geometry(); 397 403 auto& lineRuns = lineContent.runList; … … 457 463 ASSERT_NOT_REACHED(); 458 464 } 459 // FIXME linebox needs to be ajusted after content alignment.460 465 formattingState.addLineBox(lineContent.lineBox); 461 alignRuns(formattingRoot().style().textAlign(), inlineDisplayRuns, previousLineLastRunIndex.valueOr(-1) + 1, widthConstraint() - lineContent.lineBox.logicalWidth());462 }463 464 static Optional<LayoutUnit> horizontalAdjustmentForAlignment(TextAlignMode align, LayoutUnit remainingWidth)465 {466 switch (align) {467 case TextAlignMode::Left:468 case TextAlignMode::WebKitLeft:469 case TextAlignMode::Start:470 return { };471 case TextAlignMode::Right:472 case TextAlignMode::WebKitRight:473 case TextAlignMode::End:474 return std::max(remainingWidth, 0_lu);475 case TextAlignMode::Center:476 case TextAlignMode::WebKitCenter:477 return std::max(remainingWidth / 2, 0_lu);478 case TextAlignMode::Justify:479 ASSERT_NOT_REACHED();480 break;481 }482 ASSERT_NOT_REACHED();483 return { };484 }485 486 void InlineFormattingContext::InlineLayout::alignRuns(TextAlignMode textAlign, InlineRuns& inlineDisplayRuns, unsigned firstRunIndex, LayoutUnit availableWidth) const487 {488 auto adjustment = horizontalAdjustmentForAlignment(textAlign, availableWidth);489 if (!adjustment)490 return;491 492 for (unsigned index = firstRunIndex; index < inlineDisplayRuns.size(); ++index)493 inlineDisplayRuns[index].moveHorizontally(*adjustment);494 466 } 495 467 -
trunk/Source/WebCore/layout/inlineformatting/InlineLine.cpp
r250484 r250487 58 58 } 59 59 60 Line::Line(const InlineFormattingContext& inlineFormattingContext, const InitialConstraints& initialConstraints, SkipVerticalAligment skipVerticalAligment)60 Line::Line(const InlineFormattingContext& inlineFormattingContext, const InitialConstraints& initialConstraints, Optional<TextAlignMode> horizontalAlignment, SkipAlignment skipAlignment) 61 61 : m_inlineFormattingContext(inlineFormattingContext) 62 62 , m_initialStrut(initialConstraints.heightAndBaseline ? initialConstraints.heightAndBaseline->strut : WTF::nullopt) 63 63 , m_lineLogicalWidth(initialConstraints.availableLogicalWidth) 64 , m_skipVerticalAligment(skipVerticalAligment == SkipVerticalAligment::Yes) 65 { 66 ASSERT(m_skipVerticalAligment || initialConstraints.heightAndBaseline); 64 , m_horizontalAlignment(horizontalAlignment) 65 , m_skipAlignment(skipAlignment == SkipAlignment::Yes) 66 { 67 ASSERT(m_skipAlignment || initialConstraints.heightAndBaseline); 67 68 auto initialLineHeight = initialConstraints.heightAndBaseline ? initialConstraints.heightAndBaseline->height : LayoutUnit(); 68 69 auto initialBaselineOffset = initialConstraints.heightAndBaseline ? initialConstraints.heightAndBaseline->baselineOffset : LayoutUnit(); … … 97 98 if (!boxGeometry.width()) 98 99 continue; 99 if (m_skip VerticalAligment || boxGeometry.height())100 if (m_skipAlignment || boxGeometry.height()) 100 101 return false; 101 102 continue; … … 110 111 { 111 112 removeTrailingTrimmableContent(); 112 if (!m_skipVerticalAligment) { 113 if (isVisuallyEmpty()) { 114 m_lineBox.baseline().reset(); 115 m_lineBox.setBaselineOffset({ }); 116 m_lineBox.setLogicalHeight({ }); 117 } 118 119 // Remove descent when all content is baseline aligned but none of them have descent. 120 if (formattingContext().quirks().lineDescentNeedsCollapsing(m_runList)) { 121 m_lineBox.shrinkVertically(m_lineBox.baseline().descent()); 122 m_lineBox.baseline().setDescent({ }); 123 } 124 125 auto& layoutState = this->layoutState(); 126 auto& formattingContext = this->formattingContext(); 127 for (auto& run : m_runList) { 128 LayoutUnit logicalTop; 129 auto& layoutBox = run->layoutBox(); 130 auto verticalAlign = layoutBox.style().verticalAlign(); 131 auto ascent = layoutBox.style().fontMetrics().ascent(); 132 133 switch (verticalAlign) { 134 case VerticalAlign::Baseline: 135 if (run->isLineBreak() || run->isText()) 136 logicalTop = baselineOffset() - ascent; 137 else if (run->isContainerStart()) { 138 auto& boxGeometry = formattingContext.geometryForBox(layoutBox); 139 logicalTop = baselineOffset() - ascent - boxGeometry.borderTop() - boxGeometry.paddingTop().valueOr(0); 140 } else if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) { 141 auto& formattingState = downcast<InlineFormattingState>(layoutState.establishedFormattingState(downcast<Container>(layoutBox))); 142 // Spec makes us generate at least one line -even if it is empty. 143 ASSERT(!formattingState.lineBoxes().isEmpty()); 144 auto inlineBlockBaseline = formattingState.lineBoxes().last().baseline(); 145 logicalTop = baselineOffset() - inlineBlockBaseline.ascent(); 146 } else 147 logicalTop = baselineOffset() - run->logicalRect().height(); 148 break; 149 case VerticalAlign::Top: 150 logicalTop = { }; 151 break; 152 case VerticalAlign::Bottom: 153 logicalTop = logicalBottom() - run->logicalRect().height(); 154 break; 155 default: 156 ASSERT_NOT_IMPLEMENTED_YET(); 157 break; 158 } 159 run->adjustLogicalTop(logicalTop); 160 // Convert runs from relative to the line top/left to the formatting root's border box top/left. 161 run->moveVertically(this->logicalTop()); 162 run->moveHorizontally(this->logicalLeft()); 163 } 164 } 165 166 // Let's join text runs together when possible. 167 // FIXME: Check if we can do it as part of the loop above. 113 // Join text runs together when possible. 168 114 unsigned index = 1; 169 115 while (index < m_runList.size()) { … … 185 131 m_runList.remove(index); 186 132 } 133 134 if (!m_skipAlignment) { 135 alignContentVertically(); 136 alignContentHorizontally(); 137 } 138 187 139 return WTFMove(m_runList); 140 } 141 142 void Line::alignContentVertically() 143 { 144 ASSERT(!m_skipAlignment); 145 146 if (isVisuallyEmpty()) { 147 m_lineBox.baseline().reset(); 148 m_lineBox.setBaselineOffset({ }); 149 m_lineBox.setLogicalHeight({ }); 150 } 151 152 // Remove descent when all content is baseline aligned but none of them have descent. 153 if (formattingContext().quirks().lineDescentNeedsCollapsing(m_runList)) { 154 m_lineBox.shrinkVertically(m_lineBox.baseline().descent()); 155 m_lineBox.baseline().setDescent({ }); 156 } 157 158 auto& layoutState = this->layoutState(); 159 auto& formattingContext = this->formattingContext(); 160 for (auto& run : m_runList) { 161 LayoutUnit logicalTop; 162 auto& layoutBox = run->layoutBox(); 163 auto verticalAlign = layoutBox.style().verticalAlign(); 164 auto ascent = layoutBox.style().fontMetrics().ascent(); 165 166 switch (verticalAlign) { 167 case VerticalAlign::Baseline: 168 if (run->isLineBreak() || run->isText()) 169 logicalTop = baselineOffset() - ascent; 170 else if (run->isContainerStart()) { 171 auto& boxGeometry = formattingContext.geometryForBox(layoutBox); 172 logicalTop = baselineOffset() - ascent - boxGeometry.borderTop() - boxGeometry.paddingTop().valueOr(0); 173 } else if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) { 174 auto& formattingState = downcast<InlineFormattingState>(layoutState.establishedFormattingState(downcast<Container>(layoutBox))); 175 // Spec makes us generate at least one line -even if it is empty. 176 ASSERT(!formattingState.lineBoxes().isEmpty()); 177 auto inlineBlockBaseline = formattingState.lineBoxes().last().baseline(); 178 logicalTop = baselineOffset() - inlineBlockBaseline.ascent(); 179 } else 180 logicalTop = baselineOffset() - run->logicalRect().height(); 181 break; 182 case VerticalAlign::Top: 183 logicalTop = { }; 184 break; 185 case VerticalAlign::Bottom: 186 logicalTop = logicalBottom() - run->logicalRect().height(); 187 break; 188 default: 189 ASSERT_NOT_IMPLEMENTED_YET(); 190 break; 191 } 192 run->adjustLogicalTop(logicalTop); 193 // Convert runs from relative to the line top/left to the formatting root's border box top/left. 194 run->moveVertically(this->logicalTop()); 195 run->moveHorizontally(this->logicalLeft()); 196 } 197 } 198 199 void Line::alignContentHorizontally() 200 { 201 ASSERT(!m_skipAlignment); 202 203 auto adjustmentForAlignment = [&]() -> Optional<LayoutUnit> { 204 switch (*m_horizontalAlignment) { 205 case TextAlignMode::Left: 206 case TextAlignMode::WebKitLeft: 207 case TextAlignMode::Start: 208 return { }; 209 case TextAlignMode::Right: 210 case TextAlignMode::WebKitRight: 211 case TextAlignMode::End: 212 return std::max(availableWidth(), 0_lu); 213 case TextAlignMode::Center: 214 case TextAlignMode::WebKitCenter: 215 return std::max(availableWidth() / 2, 0_lu); 216 case TextAlignMode::Justify: 217 ASSERT_NOT_REACHED(); 218 break; 219 } 220 ASSERT_NOT_REACHED(); 221 return { }; 222 }; 223 224 auto adjustment = adjustmentForAlignment(); 225 if (!adjustment) 226 return; 227 228 for (auto& run : m_runList) 229 run->moveHorizontally(*adjustment); 230 // FIXME: Find out if m_lineBox needs adjustmnent as well. 188 231 } 189 232 … … 252 295 logicalRect.setWidth(logicalWidth); 253 296 254 if (!m_skip VerticalAligment) {297 if (!m_skipAlignment) { 255 298 auto logicalHeight = inlineItemContentHeight(inlineItem); 256 299 adjustBaselineAndLineHeight(inlineItem, logicalHeight); … … 299 342 logicalRect.setLeft(contentLogicalWidth()); 300 343 logicalRect.setWidth(logicalWidth); 301 if (!m_skip VerticalAligment) {344 if (!m_skipAlignment) { 302 345 auto runHeight = inlineItemContentHeight(inlineItem); 303 346 logicalRect.setHeight(runHeight); … … 326 369 logicalRect.setLeft(contentLogicalWidth() + horizontalMargin.start); 327 370 logicalRect.setWidth(logicalWidth); 328 if (!m_skip VerticalAligment) {371 if (!m_skipAlignment) { 329 372 adjustBaselineAndLineHeight(inlineItem, boxGeometry.marginBoxHeight()); 330 373 logicalRect.setHeight(inlineItemContentHeight(inlineItem)); … … 347 390 logicalRect.setLeft(contentLogicalWidth()); 348 391 logicalRect.setWidth({ }); 349 if (!m_skip VerticalAligment) {392 if (!m_skipAlignment) { 350 393 adjustBaselineAndLineHeight(inlineItem, { }); 351 394 logicalRect.setHeight(logicalHeight()); … … 427 470 LayoutUnit Line::inlineItemContentHeight(const InlineItem& inlineItem) const 428 471 { 429 ASSERT(!m_skip VerticalAligment);472 ASSERT(!m_skipAlignment); 430 473 auto& fontMetrics = inlineItem.style().fontMetrics(); 431 474 if (inlineItem.isLineBreak() || is<InlineTextItem>(inlineItem)) -
trunk/Source/WebCore/layout/inlineformatting/InlineLine.h
r250484 r250487 52 52 Optional<HeightAndBaseline> heightAndBaseline; 53 53 }; 54 enum class Skip VerticalAligment { No, Yes };55 Line(const InlineFormattingContext&, const InitialConstraints&, SkipVerticalAligment);54 enum class SkipAlignment { No, Yes }; 55 Line(const InlineFormattingContext&, const InitialConstraints&, Optional<TextAlignMode>, SkipAlignment); 56 56 57 57 void append(const InlineItem&, LayoutUnit logicalWidth); … … 126 126 127 127 void removeTrailingTrimmableContent(); 128 void alignContentHorizontally(); 129 void alignContentVertically(); 128 130 129 131 void adjustBaselineAndLineHeight(const InlineItem&, LayoutUnit runHeight); … … 140 142 Optional<LineBox::Baseline> m_initialStrut; 141 143 LayoutUnit m_lineLogicalWidth; 142 bool m_skipVerticalAligment { false }; 144 Optional<TextAlignMode> m_horizontalAlignment; 145 bool m_skipAlignment { false }; 143 146 LineBox m_lineBox; 144 147 };
Note:
See TracChangeset
for help on using the changeset viewer.