Changeset 268864 in webkit
- Timestamp:
- Oct 22, 2020, 7:43:57 AM (6 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 6 edited
-
ChangeLog (modified) (1 diff)
-
layout/inlineformatting/InlineFormattingContext.h (modified) (1 diff)
-
layout/inlineformatting/InlineFormattingContextGeometry.cpp (modified) (7 diffs)
-
layout/inlineformatting/InlineFormattingContextQuirks.cpp (modified) (1 diff)
-
layout/inlineformatting/InlineLine.cpp (modified) (1 diff)
-
layout/inlineformatting/InlineLineBox.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r268862 r268864 1 2020-10-22 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][IFC] Handle line box sizing quirks at the line box level 4 https://bugs.webkit.org/show_bug.cgi?id=218060 5 6 Reviewed by Antti Koivisto. 7 8 In this patch the line box vertical sizing behavior (mostly quirk) is moved from the inline box to the line box level. 9 10 1. Inline boxes (root and other inline boxes (<span>)) are always sized to their initial height (see layout bounds) regardless of 11 whether they have content or not. 12 2. They are set to empty initially and we change them to non-empty as they gain (non-inline-level-box) content 13 (e.g. <div>root inline box gains content</div>). 14 3. Use this empty flag as input to the line box vertical sizing logic (only non-empty inline boxes contribute to the line box height). 15 16 Note that in standard mode the root inline box starts with an imaginary strut which makes it non-empty even when it has no content. 17 This is most visible with simple block containers like this: 18 <div style="border: 1px solid green"><img></div> 19 In quirks mode the border hugs the image (root inline box does not contribute to the height of the line box), while in standard mode 20 (assume 1. the image is taller than the default font with line spacing, 2. font has 4px descent), 21 there's a 4px gap between the border and the image. 22 23 4. While computing the final line rect (InlineFormattingContext::Geometry::computedLineLogicalRect), just rely on the line box height 24 computation (no need to check whether the line has content). 25 5. Treat <br> as visually non-empty run as it may contribute to the line box visually. 26 6. Add <br> quirk behavior so that it only contributes to the line box height when the line is empty. 27 28 * layout/inlineformatting/InlineFormattingContext.h: 29 * layout/inlineformatting/InlineFormattingContextGeometry.cpp: 30 (WebCore::Layout::LineBoxBuilder::constructInlineLevelBoxes): 31 (WebCore::Layout::LineBoxBuilder::alignInlineLevelBoxesVerticallyAndComputeLineBoxHeight): 32 (WebCore::Layout::InlineFormattingContext::Geometry::computedLineLogicalRect const): 33 * layout/inlineformatting/InlineFormattingContextQuirks.cpp: 34 (WebCore::Layout::InlineFormattingContext::Quirks::shouldInlineLevelBoxStretchLineBox const): 35 * layout/inlineformatting/InlineLine.cpp: 36 (WebCore::Layout::Line::isRunVisuallyNonEmpty const): 37 * layout/inlineformatting/InlineLineBox.h: 38 (WebCore::Layout::LineBox::InlineLevelBox::verticalAlign const): 39 1 40 2020-10-22 Antti Koivisto <antti@apple.com> 2 41 -
trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h
r268660 r268864 51 51 InlineLayoutUnit initialLineHeight() const; 52 52 bool hasSoftWrapOpportunityAtImage() const; 53 bool shouldInlineLevelBoxStretchLineBox(const LineBox&, const LineBox::InlineLevelBox&) const; 53 54 54 55 private: -
trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextGeometry.cpp
r268823 r268864 214 214 if (isInitiallyConsideredNonEmpty) 215 215 rootInlineBox->setIsNonEmpty(); 216 if (lineHasImaginaryStrut) 217 setVerticalGeometryForInlineBox(*rootInlineBox); 216 setVerticalGeometryForInlineBox(*rootInlineBox); 218 217 lineBox.addRootInlineBox(WTFMove(rootInlineBox)); 219 218 }; … … 252 251 }; 253 252 createWrappedInlineBoxes(); 254 255 auto stretchRootInlineBoxIfNeededQuirk = [&] (const auto& layoutBox) {256 auto& parentInlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent());257 if (!isRootInlineBox(parentInlineBox) || !parentInlineBox.isEmpty())258 return;259 setVerticalGeometryForInlineBox(parentInlineBox);260 parentInlineBox.setIsNonEmpty();261 };262 253 263 254 for (auto& run : runs) { … … 293 284 } else if (run.isText() || run.isSoftLineBreak()) { 294 285 // FIXME: Adjust non-empty inline box height when glyphs from the non-primary font stretch the box. 295 stretchRootInlineBoxIfNeededQuirk(layoutBox);286 lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent()).setIsNonEmpty(); 296 287 } else if (run.isHardLineBreak()) { 297 288 auto lineBreakBox = LineBox::InlineLevelBox::createLineBreakBox(layoutBox, logicalLeft); 298 289 setVerticalGeometryForInlineBox(*lineBreakBox); 290 lineBreakBox->setIsNonEmpty(); 299 291 lineBox.addInlineLevelBox(WTFMove(lineBreakBox)); 300 stretchRootInlineBoxIfNeededQuirk(layoutBox);301 292 } else if (run.isWordBreakOpportunity()) 302 293 lineBox.addInlineLevelBox(LineBox::InlineLevelBox::createGenericInlineLevelBox(layoutBox, logicalLeft)); … … 315 306 InlineLayoutUnit top { 0 }; 316 307 InlineLayoutUnit bottom { 0 }; 308 const LineBox::InlineLevelBox* inlineLevelBox { nullptr }; 317 309 }; 318 310 HashMap<LineBox::InlineLevelBox*, AbsoluteTopAndBottom> absoluteLogicalTopAndBottomMap; 319 311 auto& rootInlineBox = lineBox.rootInlineBox(); 320 absoluteLogicalTopAndBottomMap.add(&rootInlineBox, AbsoluteTopAndBottom { { }, rootInlineBox.layoutBounds().height() });312 absoluteLogicalTopAndBottomMap.add(&rootInlineBox, AbsoluteTopAndBottom { { }, rootInlineBox.layoutBounds().height(), &rootInlineBox }); 321 313 322 314 auto alignInlineBoxRelativeInlineLevelBoxes = [&] { … … 352 344 auto parentAbsoluteLogicalTop = absoluteLogicalTopAndBottomMap.get(&parentInlineBox).top; 353 345 auto absoluteLogicalTop = parentAbsoluteLogicalTop + logicalTop; 354 absoluteLogicalTopAndBottomMap.add(inlineLevelBox.get(), AbsoluteTopAndBottom { absoluteLogicalTop, absoluteLogicalTop + inlineLevelBox->layoutBounds().height() });346 absoluteLogicalTopAndBottomMap.add(inlineLevelBox.get(), AbsoluteTopAndBottom { absoluteLogicalTop, absoluteLogicalTop + inlineLevelBox->layoutBounds().height(), inlineLevelBox.get() }); 355 347 } 356 348 }; … … 358 350 359 351 auto lineBoxLogicalHeight = InlineLayoutUnit { }; 360 auto minimumInlineBoxRelativeLogicalTop = InlineLayoutUnit { };361 352 auto inlineBoxRelativeLogicalHeight = InlineLayoutUnit { }; 353 auto quirks = formattingContext().quirks(); 354 auto maximumBaselineAlignedAscent = rootInlineBox.isEmpty() ? InlineLayoutUnit() : rootInlineBox.layoutBounds().ascent; 362 355 auto computeLineBoxLogicalHeight = [&] { 363 356 // FIXME: Add support for layout bounds based line box height. 364 auto minimumLogicalTop = InlineLayoutUnit{ };365 auto maximum logicalBottom = InlineLayoutUnit{ };357 auto minimumLogicalTop = Optional<InlineLayoutUnit> { }; 358 auto maximumLogicalBottom = Optional<InlineLayoutUnit> { }; 366 359 for (auto absoluteLogicalTopAndBottom : absoluteLogicalTopAndBottomMap.values()) { 367 minimumLogicalTop = std::min(minimumLogicalTop, absoluteLogicalTopAndBottom.top); 368 maximumlogicalBottom = std::max(maximumlogicalBottom, absoluteLogicalTopAndBottom.bottom); 369 } 370 minimumInlineBoxRelativeLogicalTop = minimumLogicalTop; 371 inlineBoxRelativeLogicalHeight = maximumlogicalBottom - minimumLogicalTop; 360 auto& inlineLevelBox = *absoluteLogicalTopAndBottom.inlineLevelBox; 361 if (!quirks.shouldInlineLevelBoxStretchLineBox(lineBox, inlineLevelBox)) 362 continue; 363 minimumLogicalTop = std::min(minimumLogicalTop.valueOr(absoluteLogicalTopAndBottom.top), absoluteLogicalTopAndBottom.top); 364 maximumLogicalBottom = std::max(maximumLogicalBottom.valueOr(absoluteLogicalTopAndBottom.bottom), absoluteLogicalTopAndBottom.bottom); 365 if (inlineLevelBox.verticalAlign() == VerticalAlign::Baseline) 366 maximumBaselineAlignedAscent = std::max(maximumBaselineAlignedAscent, inlineLevelBox.layoutBounds().ascent); 367 } 368 inlineBoxRelativeLogicalHeight = maximumLogicalBottom.valueOr(InlineLayoutUnit()) - minimumLogicalTop.valueOr(InlineLayoutUnit()); 372 369 lineBoxLogicalHeight = inlineBoxRelativeLogicalHeight; 373 370 // Now stretch the line box with the line box relative inline level boxes. 374 for (auto* lineBoxRelativeInlineLevelBox : lineBoxRelativeInlineLevelBoxes) 371 for (auto* lineBoxRelativeInlineLevelBox : lineBoxRelativeInlineLevelBoxes) { 372 if (!quirks.shouldInlineLevelBoxStretchLineBox(lineBox, *lineBoxRelativeInlineLevelBox)) 373 continue; 375 374 lineBoxLogicalHeight = std::max(lineBoxLogicalHeight, lineBoxRelativeInlineLevelBox->layoutBounds().height()); 375 } 376 376 }; 377 377 computeLineBoxLogicalHeight(); 378 378 379 379 auto adjustRootInlineBoxVerticalPosition = [&] { 380 if (minimumInlineBoxRelativeLogicalTop >= 0)381 return;382 rootInlineBox.setLogicalTop( -minimumInlineBoxRelativeLogicalTop);380 // FIXME: Add support for cases when the stretching inline boxes are not baseline aligned. 381 auto logicalTop = maximumBaselineAlignedAscent - rootInlineBox.layoutBounds().ascent; 382 rootInlineBox.setLogicalTop(logicalTop); 383 383 }; 384 384 adjustRootInlineBoxVerticalPosition(); … … 418 418 InlineRect InlineFormattingContext::Geometry::computedLineLogicalRect(const LineBox& lineBox, const LineBuilder::LineContent& lineContent) const 419 419 { 420 auto isConsideredEmpty = lineContent.runs.isEmpty() || lineBox.isLineVisuallyEmpty(); 421 return { lineContent.logicalTopLeft, lineContent.lineLogicalWidth, isConsideredEmpty ? InlineLayoutUnit() : lineBox.logicalHeight()}; 420 return { lineContent.logicalTopLeft, lineContent.lineLogicalWidth, lineBox.logicalHeight() }; 422 421 } 423 422 -
trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextQuirks.cpp
r268660 r268864 41 41 } 42 42 43 bool InlineFormattingContext::Quirks::shouldInlineLevelBoxStretchLineBox(const LineBox& lineBox, const LineBox::InlineLevelBox& inlineLevelBox) const 44 { 45 if (inlineLevelBox.isEmpty()) 46 return false; 47 if (layoutState().inNoQuirksMode()) 48 return true; 49 if (!inlineLevelBox.isLineBreakBox()) 50 return true; 51 // <br> in non-standard mode stretches the line box only when the line is empty. 52 // e.g. <div><span><br></span></div> will stretch but <div>this will not stretch to 200px<span style="font-size: 200px;"><br></span></div> 53 return lineBox.isLineVisuallyEmpty(); 54 } 55 43 56 bool InlineFormattingContext::Quirks::hasSoftWrapOpportunityAtImage() const 44 57 { -
trunk/Source/WebCore/layout/inlineformatting/InlineLine.cpp
r268485 r268864 354 354 355 355 if (run.isLineBreak()) 356 return true;356 return false; 357 357 358 358 // Note that this does not check whether the inline container has content. It simply checks if the container itself is considered non-empty. -
trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h
r268825 r268864 81 81 82 82 const FontMetrics& fontMetrics() const { return layoutBox().style().fontMetrics(); } 83 VerticalAlign verticalAlign() const { return layoutBox().style().verticalAlign(); } 83 84 const Box& layoutBox() const { return *m_layoutBox; } 84 85
Note:
See TracChangeset
for help on using the changeset viewer.