Changeset 268642 in webkit
- Timestamp:
- Oct 17, 2020 6:30:15 AM (4 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r268641 r268642 1 2020-10-17 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][IFC] Introduce layout bounds based vertical alignment 4 https://bugs.webkit.org/show_bug.cgi?id=217832 5 6 Reviewed by Antti Koivisto. 7 8 This patch introduces the layout bounds concept on the inline boxes. 9 It help with implementing https://www.w3.org/TR/css-inline-3/#line-layout (2.2. Layout Within Line Boxes) 10 where layout bounds are used extensively (essentially the layout bound drives the inline box's aligned vertical 11 position within the line box -as opposed to its logical height. Though they may match in many cases.) 12 13 With this patch nested inline boxes are positioned relative to their parent inline boxes and 14 LineBox::logicalRectForInlineLevelBox/logicalRectForTextRun resolves them to be relative to the line box (which then used for 15 generating display inline runs with relative to the line coordinates). 16 17 * layout/inlineformatting/InlineFormattingContext.cpp: 18 (WebCore::Layout::InlineFormattingContext::computeGeometryForLineContent): 19 * layout/inlineformatting/InlineFormattingContextGeometry.cpp: 20 (WebCore::Layout::LineBoxBuilder::build): 21 (WebCore::Layout::LineBoxBuilder::setVerticalGeometryForInlineBox const): 22 (WebCore::Layout::LineBoxBuilder::constructInlineLevelBoxes): 23 (WebCore::Layout::LineBoxBuilder::alignInlineLevelBoxesVerticallyAndComputeLineBoxHeight): 24 (WebCore::Layout::InlineFormattingContext::Geometry::computedLineLogicalRect const): 25 (WebCore::Layout::LineBoxBuilder::adjustInlineBoxesLogicalHeight): Deleted. 26 * layout/inlineformatting/InlineLineBox.cpp: 27 (WebCore::Layout::LineBox::logicalRectForTextRun const): 28 (WebCore::Layout::LineBox::logicalRectForInlineLevelBox const): 29 * layout/inlineformatting/InlineLineBox.h: 30 (WebCore::Layout::LineBox::InlineLevelBox::LayoutBounds::height const): 31 (WebCore::Layout::LineBox::InlineLevelBox::setLayoutBounds): 32 (WebCore::Layout::LineBox::InlineLevelBox::layoutBounds const): 33 (WebCore::Layout::LineBox::InlineLevelBox::lineSpacing const): Deleted. 34 (WebCore::Layout::LineBox::InlineLevelBox::setLineSpacing): Deleted. 35 1 36 2020-10-17 Antti Koivisto <antti@apple.com> 2 37 -
trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
r268315 r268642 442 442 formattingState.addLineRun({ lineIndex, lineRun.layoutBox(), lineBox.logicalRectForTextRun(lineRun), lineRun.expansion(), lineRun.textContent() }); 443 443 else if (lineRun.isBox()) 444 formattingState.addLineRun({ lineIndex, lineRun.layoutBox(), lineBox. inlineLevelBoxForLayoutBox(lineRun.layoutBox()).logicalRect(), lineRun.expansion(), { } });444 formattingState.addLineRun({ lineIndex, lineRun.layoutBox(), lineBox.logicalRectForInlineLevelBox(lineRun.layoutBox()), lineRun.expansion(), { } }); 445 445 } 446 446 }; -
trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextGeometry.cpp
r268485 r268642 48 48 void setVerticalGeometryForInlineBox(LineBox::InlineLevelBox&) const; 49 49 void constructInlineLevelBoxes(LineBox&, const Line::RunList&); 50 void adjustInlineBoxesLogicalHeight(LineBox&);51 50 void alignInlineLevelBoxesVerticallyAndComputeLineBoxHeight(LineBox&); 52 51 … … 161 160 lineBox.setHorizontalAlignmentOffset(*horizontalAlignmentOffset); 162 161 constructInlineLevelBoxes(lineBox, runs); 163 adjustInlineBoxesLogicalHeight(lineBox);164 162 alignInlineLevelBoxesVerticallyAndComputeLineBoxHeight(lineBox); 165 163 return lineBox; … … 170 168 ASSERT(inlineLevelBox.isInlineBox() || inlineLevelBox.isLineBreakBox()); 171 169 auto& fontMetrics = inlineLevelBox.fontMetrics(); 172 InlineLayoutUnit logicalHeight = fontMetrics.height(); 173 InlineLayoutUnit baseline = fontMetrics.ascent(); 174 170 InlineLayoutUnit ascent = fontMetrics.ascent(); 171 InlineLayoutUnit descent = fontMetrics.descent(); 172 auto logicalHeight = ascent + descent; 173 174 // FIXME: Adjust layout bounds with fallback font when applicable. 175 auto& style = inlineLevelBox.layoutBox().style(); 176 auto lineHeight = style.lineHeight(); 177 if (lineHeight.isNegative()) { 178 // If line-height computes to normal and either text-edge is leading or this is the root inline box, 179 // the font’s line gap metric may also be incorporated into A and D by adding half to each side as half-leading. 180 auto lineSpacing = &inlineLevelBox.layoutBox() == &rootBox() ? fontMetrics.lineSpacing() - logicalHeight : InlineLayoutUnit(); 181 ascent += lineSpacing / 2; 182 descent += lineSpacing / 2; 183 } else { 184 InlineLayoutUnit lineHeight = style.computedLineHeight(); 185 InlineLayoutUnit halfLeading = (lineHeight - (ascent + descent)) / 2; 186 ascent += halfLeading; 187 descent += halfLeading; 188 } 189 // We need this to match legacy layout integral positioning. 190 ascent = floorf(ascent); 191 descent = ceil(descent); 192 193 inlineLevelBox.setLayoutBounds(LineBox::InlineLevelBox::LayoutBounds { ascent, descent }); 194 inlineLevelBox.setBaseline(ascent); 195 inlineLevelBox.setDescent(descent); 175 196 inlineLevelBox.setLogicalHeight(logicalHeight); 176 inlineLevelBox.setBaseline(baseline);177 inlineLevelBox.setDescent(logicalHeight - baseline);178 if (auto lineSpacing = fontMetrics.lineSpacing() - logicalHeight)179 inlineLevelBox.setLineSpacing(lineSpacing);180 inlineLevelBox.setIsNonEmpty();181 197 } 182 198 … … 187 203 auto createRootInlineBox = [&] { 188 204 auto rootInlineBox = LineBox::InlineLevelBox::createRootInlineBox(rootBox(), horizontalAligmentOffset, lineBox.logicalWidth()); 205 setVerticalGeometryForInlineBox(*rootInlineBox); 189 206 190 207 auto lineHasImaginaryStrut = !layoutState().inQuirksMode(); 191 208 auto isInitiallyConsideredNonEmpty = !lineBox.isLineVisuallyEmpty() && lineHasImaginaryStrut; 192 209 if (isInitiallyConsideredNonEmpty) 193 setVerticalGeometryForInlineBox(*rootInlineBox);210 rootInlineBox->setIsNonEmpty(); 194 211 lineBox.addRootInlineBox(WTFMove(rootInlineBox)); 195 212 }; … … 244 261 auto atomicInlineLevelBox = LineBox::InlineLevelBox::createAtomicInlineLevelBox(layoutBox, logicalLeft, { run.logicalWidth(), logicalHeight }); 245 262 atomicInlineLevelBox->setBaseline(baseline); 263 atomicInlineLevelBox->setLayoutBounds(LineBox::InlineLevelBox::LayoutBounds { baseline, { } }); 246 264 if (logicalHeight) 247 265 atomicInlineLevelBox->setIsNonEmpty(); … … 250 268 auto initialLogicalWidth = lineBox.logicalWidth() - run.logicalLeft(); 251 269 ASSERT(initialLogicalWidth >= 0); 252 lineBox.addInlineLevelBox(LineBox::InlineLevelBox::createInlineBox(layoutBox, logicalLeft, initialLogicalWidth)); 270 auto inlineBox = LineBox::InlineLevelBox::createInlineBox(layoutBox, logicalLeft, initialLogicalWidth); 271 setVerticalGeometryForInlineBox(*inlineBox); 272 lineBox.addInlineLevelBox(WTFMove(inlineBox)); 253 273 } else if (run.isContainerEnd()) { 254 274 // Adjust the logical width when the inline level container closes on this line. … … 257 277 inlineBox.setLogicalWidth(run.logicalRight() - inlineBox.logicalLeft()); 258 278 } else if (run.isText() || run.isSoftLineBreak()) { 259 auto& parentBox = layoutBox.parent();260 auto& parentInlineBox = &parentBox == &rootBox() ? lineBox.rootInlineBox() : lineBox.inlineLevelBoxForLayoutBox(parentBox);261 279 // FIXME: Adjust non-empty inline box height when glyphs from the non-primary font stretch the box. 262 if (parentInlineBox.isEmpty()) 263 setVerticalGeometryForInlineBox(parentInlineBox); 280 // FIXME: Add quirk inline box stretching. 264 281 } else if (run.isHardLineBreak()) { 265 282 auto lineBreakBox = LineBox::InlineLevelBox::createLineBreakBox(layoutBox, logicalLeft); … … 273 290 } 274 291 275 void LineBoxBuilder::adjustInlineBoxesLogicalHeight(LineBox& lineBox) 276 { 277 // By traversing the inline box list backwards, it's guaranteed that descendant inline boxes are sized first. 278 for (auto& inlineLevelBox : WTF::makeReversedRange(lineBox.nonRootInlineLevelBoxes())) { 279 if (inlineLevelBox->isEmpty()) 280 continue; 281 282 auto& layoutBox = inlineLevelBox->layoutBox(); 283 auto& parentInlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent()); 284 ASSERT(parentInlineBox.isInlineBox()); 285 switch (layoutBox.style().verticalAlign()) { 286 case VerticalAlign::Top: 287 case VerticalAlign::Bottom: 288 // top and bottom alignments only stretch the line box. They don't stretch any of the inline boxes, not even the root inline box. 289 break; 290 case VerticalAlign::TextTop: { 291 auto parentTextLogicalTop = parentInlineBox.baseline() - parentInlineBox.fontMetrics().ascent(); 292 parentInlineBox.setLogicalHeight(std::max(parentInlineBox.logicalHeight(), parentTextLogicalTop + inlineLevelBox->logicalHeight())); 293 break; 294 } 295 case VerticalAlign::Baseline: { 296 auto baselineOverflow = std::max(0.0f, inlineLevelBox->baseline() - parentInlineBox.baseline()); 297 if (baselineOverflow) { 298 parentInlineBox.setBaseline(parentInlineBox.baseline() + baselineOverflow); 299 parentInlineBox.setLogicalHeight(parentInlineBox.logicalHeight() + baselineOverflow); 292 void LineBoxBuilder::alignInlineLevelBoxesVerticallyAndComputeLineBoxHeight(LineBox& lineBox) 293 { 294 // This function (partially) implements: 295 // 2.2. Layout Within Line Boxes 296 // https://www.w3.org/TR/css-inline-3/#line-layout 297 Vector<LineBox::InlineLevelBox*> lineBoxRelativeInlineLevelBoxes; 298 struct AbsoluteTopAndBottom { 299 InlineLayoutUnit top { 0 }; 300 InlineLayoutUnit bottom { 0 }; 301 }; 302 HashMap<LineBox::InlineLevelBox*, AbsoluteTopAndBottom> absoluteLogicalTopAndBottomMap; 303 auto& rootInlineBox = lineBox.rootInlineBox(); 304 absoluteLogicalTopAndBottomMap.add(&rootInlineBox, AbsoluteTopAndBottom { { }, rootInlineBox.layoutBounds().height() }); 305 306 auto alignInlineBoxRelativeInlineLevelBoxes = [&] { 307 // FIXME: Add proper support for cases when the inline box with line box relative alignment has a child inline box 308 // with non-line box relative alignment. 309 for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) { 310 auto& layoutBox = inlineLevelBox->layoutBox(); 311 auto verticalAlignment = layoutBox.style().verticalAlign(); 312 if (inlineLevelBox->hasLineBoxRelativeAlignment()) { 313 lineBoxRelativeInlineLevelBoxes.append(inlineLevelBox.get()); 314 continue; 300 315 } 301 auto parentInlineBoxBelowBaseline = parentInlineBox.logicalHeight() - parentInlineBox.baseline(); 302 auto inlineBoxBelowBaseline = inlineLevelBox->logicalHeight() - inlineLevelBox->baseline(); 303 auto belowBaselineOverflow = std::max(0.0f, inlineBoxBelowBaseline - parentInlineBoxBelowBaseline); 304 if (belowBaselineOverflow) 305 parentInlineBox.setLogicalHeight(parentInlineBox.logicalHeight() + belowBaselineOverflow); 306 break; 307 } 308 case VerticalAlign::TextBottom: { 309 auto parentTextLogicalBottom = parentInlineBox.baseline() + parentInlineBox.descent().valueOr(InlineLayoutUnit { }); 310 auto overflow = std::max(0.0f, inlineLevelBox->logicalHeight() - parentTextLogicalBottom); 311 if (overflow) { 312 // TextBottom pushes the baseline downward the same way 'bottom' does. 313 parentInlineBox.setLogicalHeight(parentInlineBox.logicalHeight() + overflow); 314 parentInlineBox.setBaseline(parentInlineBox.baseline() + overflow); 316 auto& parentInlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent()); 317 auto logicalTop = InlineLayoutUnit { }; 318 switch (verticalAlignment) { 319 case VerticalAlign::Baseline: 320 logicalTop = parentInlineBox.baseline() - inlineLevelBox->baseline(); 321 break; 322 case VerticalAlign::TextTop: 323 logicalTop = { }; 324 break; 325 case VerticalAlign::TextBottom: 326 logicalTop = parentInlineBox.layoutBounds().height() - inlineLevelBox->layoutBounds().height(); 327 break; 328 case VerticalAlign::Middle: 329 logicalTop = parentInlineBox.baseline() - (inlineLevelBox->layoutBounds().height() / 2 + parentInlineBox.fontMetrics().xHeight() / 2); 330 break; 331 default: 332 ASSERT_NOT_IMPLEMENTED_YET(); 333 break; 315 334 } 316 break; 317 } 318 case VerticalAlign::Middle: { 319 auto logicalTop = parentInlineBox.baseline() - (inlineLevelBox->logicalHeight() / 2 + parentInlineBox.fontMetrics().xHeight() / 2); 320 if (logicalTop < 0) { 321 auto overflow = -logicalTop; 322 // Child inline box with middle alignment pushes the baseline down when overflows. 323 parentInlineBox.setBaseline(parentInlineBox.baseline() + overflow); 324 parentInlineBox.setLogicalHeight(parentInlineBox.logicalHeight() + overflow); 335 inlineLevelBox->setLogicalTop(logicalTop); 336 auto parentAbsoluteLogicalTop = absoluteLogicalTopAndBottomMap.get(&parentInlineBox).top; 337 auto absoluteLogicalTop = parentAbsoluteLogicalTop + logicalTop; 338 absoluteLogicalTopAndBottomMap.add(inlineLevelBox.get(), AbsoluteTopAndBottom { absoluteLogicalTop, absoluteLogicalTop + inlineLevelBox->layoutBounds().height() }); 339 } 340 }; 341 alignInlineBoxRelativeInlineLevelBoxes(); 342 343 auto lineBoxLogicalHeight = InlineLayoutUnit { }; 344 auto minimumInlineBoxRelativeLogicalTop = InlineLayoutUnit { }; 345 auto inlineBoxRelativeLogicalHeight = InlineLayoutUnit { }; 346 auto computeLineBoxLogicalHeight = [&] { 347 // FIXME: Add support for layout bounds based line box height. 348 auto minimumLogicalTop = InlineLayoutUnit { }; 349 auto maximumlogicalBottom = InlineLayoutUnit { }; 350 for (auto absoluteLogicalTopAndBottom : absoluteLogicalTopAndBottomMap.values()) { 351 minimumLogicalTop = std::min(minimumLogicalTop, absoluteLogicalTopAndBottom.top); 352 maximumlogicalBottom = std::max(maximumlogicalBottom, absoluteLogicalTopAndBottom.bottom); 353 } 354 minimumInlineBoxRelativeLogicalTop = minimumLogicalTop; 355 inlineBoxRelativeLogicalHeight = maximumlogicalBottom - minimumLogicalTop; 356 lineBoxLogicalHeight = inlineBoxRelativeLogicalHeight; 357 // Now stretch the line box with the line box relative inline level boxes. 358 for (auto* lineBoxRelativeInlineLevelBox : lineBoxRelativeInlineLevelBoxes) 359 lineBoxLogicalHeight = std::max(lineBoxLogicalHeight, lineBoxRelativeInlineLevelBox->layoutBounds().height()); 360 }; 361 computeLineBoxLogicalHeight(); 362 363 auto adjustRootInlineBoxVerticalPosition = [&] { 364 if (minimumInlineBoxRelativeLogicalTop >= 0) 365 return; 366 rootInlineBox.setLogicalTop(-minimumInlineBoxRelativeLogicalTop); 367 }; 368 adjustRootInlineBoxVerticalPosition(); 369 370 auto alignLineBoxRelativeInlineLevelBoxes = [&] { 371 for (auto* inlineLevelBox : lineBoxRelativeInlineLevelBoxes) { 372 auto& layoutBox = inlineLevelBox->layoutBox(); 373 auto verticalAlignment = layoutBox.style().verticalAlign(); 374 auto logicalTop = InlineLayoutUnit { }; 375 auto rootInlineBoxOffset = InlineLayoutUnit { }; 376 switch (verticalAlignment) { 377 case VerticalAlign::Top: 325 378 logicalTop = { }; 379 break; 380 case VerticalAlign::Bottom: 381 logicalTop = lineBoxLogicalHeight - inlineLevelBox->layoutBounds().height(); 382 rootInlineBoxOffset = inlineLevelBox->layoutBounds().height() - inlineBoxRelativeLogicalHeight; 383 break; 384 default: 385 ASSERT_NOT_IMPLEMENTED_YET(); 386 break; 326 387 } 327 auto logicalBottom = logicalTop + inlineLevelBox->logicalHeight(); 328 parentInlineBox.setLogicalHeight(std::max(parentInlineBox.logicalHeight(), logicalBottom)); 329 break; 330 } 331 default: 332 ASSERT_NOT_IMPLEMENTED_YET(); 333 break; 334 } 335 } 336 } 337 338 void LineBoxBuilder::alignInlineLevelBoxesVerticallyAndComputeLineBoxHeight(LineBox& lineBox) 339 { 340 // Inline boxes are in the coordinate system of the line box (and not in the coordinate system of their parents). 341 // Starting with the root inline box, position the ancestors first so that the descendant line boxes see absolute vertical positions. 342 auto& rootInlineBox = lineBox.rootInlineBox(); 343 auto contentLogicalHeight = InlineLayoutUnit { }; 344 auto alignRootInlineBox = [&] { 345 contentLogicalHeight = rootInlineBox.logicalHeight(); 346 for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) { 347 auto verticalAlign = inlineLevelBox->layoutBox().style().verticalAlign(); 348 if (verticalAlign == VerticalAlign::Bottom) { 349 // bottom align always pushes the root inline box downwards. 350 auto overflow = std::max(0.0f, inlineLevelBox->logicalBottom() - rootInlineBox.logicalBottom()); 351 rootInlineBox.setLogicalTop(rootInlineBox.logicalTop() + overflow); 352 contentLogicalHeight += overflow; 353 } else if (verticalAlign == VerticalAlign::Top) 354 contentLogicalHeight = std::max(contentLogicalHeight, inlineLevelBox->logicalHeight()); 355 } 356 }; 357 alignRootInlineBox(); 358 359 for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) { 360 auto inlineLevelBoxLogicalTop = InlineLayoutUnit { }; 361 auto& layoutBox = inlineLevelBox->layoutBox(); 362 auto& parentInlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent()); 363 ASSERT(parentInlineBox.isInlineBox()); 364 switch (layoutBox.style().verticalAlign()) { 365 case VerticalAlign::Baseline: 366 inlineLevelBoxLogicalTop = parentInlineBox.logicalTop() + parentInlineBox.baseline() - inlineLevelBox->baseline(); 367 break; 368 case VerticalAlign::TextTop: 369 inlineLevelBoxLogicalTop = parentInlineBox.logicalTop() + parentInlineBox.baseline() - parentInlineBox.fontMetrics().ascent(); 370 break; 371 case VerticalAlign::TextBottom: { 372 auto parentTextLogicalBottom = parentInlineBox.logicalTop() + parentInlineBox.baseline() + parentInlineBox.fontMetrics().descent(); 373 inlineLevelBoxLogicalTop = parentTextLogicalBottom - inlineLevelBox->logicalHeight(); 374 break; 375 } 376 case VerticalAlign::Top: 377 inlineLevelBoxLogicalTop = InlineLayoutUnit { }; 378 break; 379 case VerticalAlign::Bottom: 380 inlineLevelBoxLogicalTop = contentLogicalHeight - inlineLevelBox->logicalHeight(); 381 break; 382 case VerticalAlign::Middle: 383 inlineLevelBoxLogicalTop = parentInlineBox.logicalTop() + parentInlineBox.baseline() - (inlineLevelBox->logicalHeight() / 2 + parentInlineBox.fontMetrics().xHeight() / 2); 384 break; 385 default: 386 ASSERT_NOT_IMPLEMENTED_YET(); 387 break; 388 } 389 inlineLevelBox->setLogicalTop(inlineLevelBoxLogicalTop); 390 } 391 if (!lineBox.isLineVisuallyEmpty()) 392 lineBox.setLogicalHeight(contentLogicalHeight); 388 inlineLevelBox->setLogicalTop(logicalTop); 389 if (rootInlineBoxOffset > 0) 390 rootInlineBox.setLogicalTop(rootInlineBox.logicalTop() + rootInlineBoxOffset); 391 } 392 }; 393 alignLineBoxRelativeInlineLevelBoxes(); 394 lineBox.setLogicalHeight(lineBoxLogicalHeight); 393 395 } 394 396 … … 398 400 } 399 401 400 InlineFormattingContext::Geometry::LineRectAndLineBoxOffset InlineFormattingContext::Geometry::computedLineLogicalRect(const LineBox& lineBox, const RenderStyle& rootStyle, const LineBuilder::LineContent& lineContent) const 401 { 402 // Compute the line height and the line box vertical offset. 403 // The line height is either the line-height value (negative value means line height is not set) or the font metrics's line spacing/line box height. 404 // The line box is then positioned using the half leading centering. 405 // ___________________________________________ line 406 // | ^ | 407 // | | line spacing | 408 // | v | 409 // | -------------------------------------------|--------- LineBox 410 // || ^ | | 411 // || | line box height | | 412 // ||----v--------------------------------------|-------- | alignment baseline 413 // | -------------------------------------------|--------- 414 // | ^ | ^ 415 // | | line spacing | | 416 // |____________________v_______________________| scrollable overflow 417 // 402 InlineFormattingContext::Geometry::LineRectAndLineBoxOffset InlineFormattingContext::Geometry::computedLineLogicalRect(const LineBox& lineBox, const RenderStyle&, const LineBuilder::LineContent& lineContent) const 403 { 418 404 if (lineContent.runs.isEmpty() || lineBox.isLineVisuallyEmpty()) 419 405 return { { }, { lineContent.logicalTopLeft, lineContent.lineLogicalWidth, { } } }; 420 406 421 407 auto lineBoxLogicalHeight = lineBox.logicalHeight(); 422 auto lineLogicalHeight = InlineLayoutUnit { }; 423 if (rootStyle.lineHeight().isNegative()) { 424 // Negative line height value means the line height is driven by the content. 425 auto usedLineSpacing = [&] { 426 auto logicalTopWithLineSpacing = InlineLayoutUnit { }; 427 auto logicalBottomWithLineSpacing = lineBoxLogicalHeight; 428 for (auto& inlineLevelBox : lineBox.inlineLevelBoxList()) { 429 if (auto lineSpacing = inlineLevelBox->lineSpacing()) { 430 // FIXME: check if line spacing is distributed evenly. 431 logicalTopWithLineSpacing = std::min(logicalTopWithLineSpacing, inlineLevelBox->logicalTop() - *lineSpacing / 2); 432 logicalBottomWithLineSpacing = std::max(logicalBottomWithLineSpacing, inlineLevelBox->logicalBottom() + *lineSpacing / 2); 433 } 434 } 435 return -logicalTopWithLineSpacing + (logicalBottomWithLineSpacing - lineBoxLogicalHeight); 436 }; 437 lineLogicalHeight = lineBox.logicalHeight() + usedLineSpacing(); 438 } else 439 lineLogicalHeight = rootStyle.computedLineHeight(); 440 408 auto lineLogicalHeight = lineBox.logicalHeight(); 441 409 auto logicalRect = InlineRect { lineContent.logicalTopLeft, lineContent.lineLogicalWidth, lineLogicalHeight}; 442 410 // Inline tree height is all integer based. -
trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.cpp
r268399 r268642 40 40 } 41 41 42 bool LineBox::InlineLevelBox::hasLineBoxRelativeAlignment() const 43 { 44 auto verticalAlignment = layoutBox().style().verticalAlign(); 45 return verticalAlignment == VerticalAlign::Top || verticalAlignment == VerticalAlign::Bottom; 46 } 47 42 48 LineBox::LineBox(InlineLayoutUnit contentLogicalWidth, IsLineVisuallyEmpty isLineVisuallyEmpty) 43 49 : m_logicalSize(contentLogicalWidth, { }) … … 61 67 { 62 68 ASSERT(run.isText() || run.isLineBreak()); 63 auto& parentInlineBox = inlineLevelBoxForLayoutBox(run.layoutBox().parent()); 64 ASSERT(parentInlineBox.isInlineBox()); 65 auto& fontMetrics = parentInlineBox.fontMetrics(); 66 auto runlogicalTop = parentInlineBox.logicalTop() + parentInlineBox.baseline() - fontMetrics.ascent(); 69 auto* parentInlineBox = &inlineLevelBoxForLayoutBox(run.layoutBox().parent()); 70 ASSERT(parentInlineBox->isInlineBox()); 71 auto& fontMetrics = parentInlineBox->fontMetrics(); 72 auto runlogicalTop = parentInlineBox->logicalTop() + parentInlineBox->baseline() - fontMetrics.ascent(); 73 74 while (parentInlineBox != m_rootInlineBox.get() && !parentInlineBox->hasLineBoxRelativeAlignment()) { 75 parentInlineBox = &inlineLevelBoxForLayoutBox(parentInlineBox->layoutBox().parent()); 76 ASSERT(parentInlineBox->isInlineBox()); 77 runlogicalTop += parentInlineBox->logicalTop(); 78 } 67 79 InlineLayoutUnit logicalHeight = fontMetrics.height(); 68 80 return { runlogicalTop, m_horizontalAlignmentOffset.valueOr(InlineLayoutUnit { }) + run.logicalLeft(), run.logicalWidth(), logicalHeight }; 81 } 82 83 InlineRect LineBox::logicalRectForInlineLevelBox(const Box& layoutBox) const 84 { 85 auto* inlineBox = &inlineLevelBoxForLayoutBox(layoutBox); 86 auto inlineBoxLogicalRect = inlineBox->logicalRect(); 87 auto inlineBoxAbsolutelogicalTop = inlineBox->logicalTop(); 88 89 while (inlineBox != m_rootInlineBox.get() && !inlineBox->hasLineBoxRelativeAlignment()) { 90 inlineBox = &inlineLevelBoxForLayoutBox(inlineBox->layoutBox().parent()); 91 ASSERT(inlineBox->isInlineBox()); 92 inlineBoxAbsolutelogicalTop += inlineBox->logicalTop(); 93 } 94 return { inlineBoxAbsolutelogicalTop, m_horizontalAlignmentOffset.valueOr(InlineLayoutUnit { }) + inlineBoxLogicalRect.left(), inlineBoxLogicalRect.width(), inlineBoxLogicalRect.height() }; 69 95 } 70 96 -
trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h
r268399 r268642 80 80 void setIsNonEmpty() { m_isEmpty = false; } 81 81 82 Optional<InlineLayoutUnit> lineSpacing() const { return m_lineSpacing; }83 82 const FontMetrics& fontMetrics() const { return layoutBox().style().fontMetrics(); } 84 83 const Box& layoutBox() const { return *m_layoutBox; } … … 86 85 bool isInlineBox() const { return m_type == Type::InlineBox || m_type == Type::RootInlineBox; } 87 86 bool isLineBreakBox() const { return m_type == Type::LineBreakBox; } 87 bool hasLineBoxRelativeAlignment() const; 88 88 89 89 enum class Type { … … 105 105 void setBaseline(InlineLayoutUnit baseline) { m_baseline = baseline; } 106 106 void setDescent(InlineLayoutUnit descent) { m_descent = descent; } 107 void setLineSpacing(InlineLayoutUnit lineSpacing) { m_lineSpacing = lineSpacing; } 107 108 // See https://www.w3.org/TR/css-inline-3/#layout-bounds 109 struct LayoutBounds { 110 InlineLayoutUnit height() const { return ascent + descent; } 111 112 InlineLayoutUnit ascent { 0 }; 113 InlineLayoutUnit descent { 0 }; 114 }; 115 void setLayoutBounds(const LayoutBounds& layoutBounds) { m_layoutBounds = layoutBounds; } 116 LayoutBounds layoutBounds() const { return m_layoutBounds; } 108 117 109 118 private: 110 119 WeakPtr<const Box> m_layoutBox; 111 120 InlineRect m_logicalRect; 121 LayoutBounds m_layoutBounds; 112 122 InlineLayoutUnit m_baseline { 0 }; 113 123 Optional<InlineLayoutUnit> m_descent; 114 Optional<InlineLayoutUnit> m_lineSpacing;115 124 bool m_isEmpty { true }; 116 125 Type m_type { Type::InlineBox }; … … 128 137 129 138 const InlineLevelBox& inlineLevelBoxForLayoutBox(const Box& layoutBox) const { return *m_inlineLevelBoxRectMap.get(&layoutBox); } 139 130 140 InlineRect logicalRectForTextRun(const Line::Run&) const; 141 InlineRect logicalRectForInlineLevelBox(const Box&) const; 142 131 143 auto inlineLevelBoxList() const { return m_inlineLevelBoxRectMap.values(); } 132 144 bool containsInlineLevelBox(const Box& layoutBox) const { return m_inlineLevelBoxRectMap.contains(&layoutBox); }
Note: See TracChangeset
for help on using the changeset viewer.