Changeset 267434 in webkit
- Timestamp:
- Sep 22, 2020, 1:07:19 PM (6 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
-
ChangeLog (modified) (1 diff)
-
layout/inlineformatting/InlineFormattingContext.cpp (modified) (3 diffs)
-
layout/inlineformatting/InlineFormattingState.h (modified) (6 diffs)
-
layout/inlineformatting/InlineLineBox.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r267432 r267434 1 2020-09-22 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][IFC] Add support for multiline inline box geometry. 4 https://bugs.webkit.org/show_bug.cgi?id=216835 5 6 Reviewed by Antti Koivisto. 7 8 This patch computes the geometry for inline boxes spanning multiple lines (e.g. <span>first line<br>next line</span). 9 However this is not the getBoundingClientRect() type of geometry where we provide geometry for each fragments. This is more like the 10 element.offset* geometry where we compute the enclosing rectangle for all the fragments. 11 12 * layout/inlineformatting/InlineFormattingContext.cpp: 13 (WebCore::Layout::InlineFormattingContext::layoutInFlowContent): Decouple the run construction and inline box geometry update logic, 14 where we loop through the runs and create "line runs" when needed and then we loop through the inline boxes on the current line and 15 update the box geometries. 16 17 (WebCore::Layout::InlineFormattingContext::computeGeometryForLineContent): 18 * layout/inlineformatting/InlineFormattingState.h: 19 (WebCore::Layout::InlineFormattingState::lineBoxes const): 20 (WebCore::Layout::InlineFormattingState::addLineBox): 21 (WebCore::Layout::InlineFormattingState::clearLineAndRuns): 22 (WebCore::Layout::InlineFormattingState::shrinkToFit): 23 * layout/inlineformatting/InlineLineBox.h: 24 (WebCore::Layout::LineBox::containsInlineLevelBox const): 25 1 26 2020-09-22 Chris Dumez <cdumez@apple.com> 2 27 -
trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
r267325 r267434 114 114 } 115 115 } else if (layoutBox->isInlineBox()) { 116 // Text wrapper boxes (anonymous inline level boxes) and <br>s don't generate display boxes (only displayruns).116 // Text wrapper boxes (anonymous inline level boxes) and <br>s don't have box geometries (they only generate runs). 117 117 if (!layoutBox->isInlineTextBox() && !layoutBox->isLineBreakBox()) { 118 118 // Inline boxes (<span>) can't get sized/positioned yet. At this point we can only compute their margins, borders and padding. … … 397 397 auto& formattingState = this->formattingState(); 398 398 auto geometry = this->geometry(); 399 const auto lineBox = geometry.lineBoxForLineContent(lineContent); 399 400 formattingState.addLineBox(geometry.lineBoxForLineContent(lineContent)); 401 const auto& lineBox = formattingState.lineBoxes().last(); 402 400 403 auto lineRectAndLineBoxOffset = geometry.computedLineLogicalRect(lineBox, root().style(), lineContent); 401 404 auto lineLogicalRect = lineRectAndLineBoxOffset.logicalRect; 402 405 auto lineBoxVerticalOffset = lineRectAndLineBoxOffset.lineBoxVerticalOffset; 403 auto lineIndex = formattingState.lines().size(); 404 405 auto constructLineGeometry = [&] { 406 auto lineBoxLogicalRect = InlineRect { lineLogicalRect.top() + lineBoxVerticalOffset, lineLogicalRect.left(), lineBox.logicalWidth(), lineBox.logicalHeight() }; 407 formattingState.addLine({ lineLogicalRect, lineBoxLogicalRect, lineBoxVerticalOffset + lineBox.alignmentBaseline(), lineBox.horizontalAlignmentOffset().valueOr(InlineLayoutUnit { }) }); 408 }; 409 constructLineGeometry(); 410 411 if (!lineContent.floats.isEmpty()) { 406 407 auto updateFloatGeometry = [&] { 408 if (lineContent.floats.isEmpty()) 409 return; 412 410 auto floatingContext = FloatingContext { root(), *this, formattingState.floatingState() }; 413 411 // Move floats to their final position. … … 422 420 floatingContext.append(floatBox); 423 421 } 424 } 425 426 for (auto& lineRun : lineContent.runs) { 427 auto& layoutBox = lineRun.layoutBox(); 428 // Inline level containers (<span>) don't generate display runs and neither do completely collapsed runs. 429 auto initiatesInlineRun = lineRun.isText() || lineRun.isLineBreak() || lineRun.isBox(); 430 if (initiatesInlineRun) { 431 auto logicalRect = lineRun.isBox() ? lineBox.inlineBoxForLayoutBox(layoutBox).logicalRect() : lineBox.logicalRectForTextRun(lineRun); 432 formattingState.addLineRun({ lineIndex, layoutBox, logicalRect, lineRun.expansion(), lineRun.textContent() }); 433 } 434 435 // FIXME: Since <br> and <wbr> runs have associated DOM elements, we might need to construct a display box here. 436 auto needsBoxGeometry = lineRun.isBox() || lineRun.isContainerStart(); 437 if (needsBoxGeometry) { 422 }; 423 updateFloatGeometry(); 424 425 auto constructLineRuns = [&] { 426 auto lineIndex = formattingState.lines().size(); 427 // Create the inline runs on the current line. This is mostly text and atomic inline runs. 428 for (auto& lineRun : lineContent.runs) { 429 if (lineRun.isText() || lineRun.isLineBreak()) 430 formattingState.addLineRun({ lineIndex, lineRun.layoutBox(), lineBox.logicalRectForTextRun(lineRun), lineRun.expansion(), lineRun.textContent() }); 431 else if (lineRun.isBox()) 432 formattingState.addLineRun({ lineIndex, lineRun.layoutBox(), lineBox.inlineBoxForLayoutBox(lineRun.layoutBox()).logicalRect(), lineRun.expansion(), { } }); 433 } 434 }; 435 constructLineRuns(); 436 437 auto updateBoxGeometry = [&] { 438 // Grab the inline boxes (even those that don't have associated layout boxes on the current line due to line wrapping) 439 // and update their geometries. 440 for (auto& inlineBox : lineBox.inlineBoxList()) { 441 auto& layoutBox = inlineBox->layoutBox(); 442 if (&layoutBox == &root()) { 443 // Ignore root inline box. 444 continue; 445 } 438 446 auto& boxGeometry = formattingState.boxGeometry(layoutBox); 439 auto & inlineBox = lineBox.inlineBoxForLayoutBox(layoutBox);440 auto topLeft = inlineBox.logicalRect().topLeft(); 441 topLeft.move({ }, lineBoxVerticalOffset);447 auto logicalTopLeft = inlineBox->logicalRect().topLeft(); 448 449 logicalTopLeft.move({ }, lineBoxVerticalOffset); 442 450 if (layoutBox.isInFlowPositioned()) 443 topLeft += geometry.inFlowPositionedPositionOffset(layoutBox, horizontalConstraints); 444 boxGeometry.setLogicalTopLeft(toLayoutPoint(topLeft)); 445 if (lineRun.isContainerStart()) { 446 auto marginBoxWidth = inlineBox.logicalWidth(); 447 auto contentBoxWidth = marginBoxWidth - (boxGeometry.marginStart() + boxGeometry.borderLeft() + boxGeometry.paddingLeft().valueOr(0)); 448 // FIXME: Fix it for multiline. 451 logicalTopLeft += geometry.inFlowPositionedPositionOffset(layoutBox, horizontalConstraints); 452 453 if (layoutBox.isAtomicInlineLevelBox()) { 454 // Atomic inline boxes are all set. Their margin/border/content box geometries are already computed. We just have to position them here. 455 boxGeometry.setLogicalTopLeft(toLayoutPoint(logicalTopLeft)); 456 continue; 457 } 458 auto marginBoxWidth = inlineBox->logicalWidth(); 459 auto contentBoxWidth = marginBoxWidth - (boxGeometry.marginStart() + boxGeometry.borderLeft() + boxGeometry.paddingLeft().valueOr(0)); 460 // Non-atomic inline level boxes may or may not be wrapped and have geometries on multiple lines. 461 int previousLineIndex = formattingState.lineBoxes().size() - 2; 462 auto isSpanningInlineBox = previousLineIndex > 0 && formattingState.lineBoxes()[previousLineIndex].containsInlineLevelBox(layoutBox); 463 if (!isSpanningInlineBox) { 464 // This box showed up on this line the first time. 465 boxGeometry.setLogicalTopLeft(toLayoutPoint(logicalTopLeft)); 449 466 boxGeometry.setContentBoxWidth(toLayoutUnit(contentBoxWidth)); 450 boxGeometry.setContentBoxHeight(toLayoutUnit(inlineBox.logicalHeight())); 451 } 452 } 453 } 467 boxGeometry.setContentBoxHeight(toLayoutUnit(inlineBox->logicalHeight())); 468 continue; 469 } 470 // This is a just a simple box geometry for the line spanning inline box. getBoundingClientRect looks into each line boxes (will turn into fragmented boxes). 471 boxGeometry.setLogicalLeft(std::min(boxGeometry.logicalLeft(), toLayoutUnit(logicalTopLeft.x()))); 472 boxGeometry.setContentBoxWidth(std::max(toLayoutUnit(contentBoxWidth), boxGeometry.contentBoxWidth())); 473 boxGeometry.setContentBoxHeight(boxGeometry.contentBoxHeight() + toLayoutUnit(inlineBox->logicalHeight())); 474 } 475 }; 476 updateBoxGeometry(); 477 478 auto constructLineGeometry = [&] { 479 auto lineBoxLogicalRect = InlineRect { lineLogicalRect.top() + lineBoxVerticalOffset, lineLogicalRect.left(), lineBox.logicalWidth(), lineBox.logicalHeight() }; 480 formattingState.addLine({ lineLogicalRect, lineBoxLogicalRect, lineBoxVerticalOffset + lineBox.alignmentBaseline(), lineBox.horizontalAlignmentOffset().valueOr(InlineLayoutUnit { }) }); 481 }; 482 constructLineGeometry(); 454 483 return lineLogicalRect; 455 484 } -
trunk/Source/WebCore/layout/inlineformatting/InlineFormattingState.h
r267325 r267434 30 30 #include "FormattingState.h" 31 31 #include "InlineItem.h" 32 #include "InlineLineBox.h" 32 33 #include "InlineLineGeometry.h" 33 34 #include "InlineLineRun.h" … … 39 40 using InlineItems = Vector<InlineItem>; 40 41 using InlineLines = Vector<InlineLineGeometry>; 42 using InlineLineBoxes = Vector<LineBox>; 41 43 using InlineLineRuns = Vector<LineRun>; 42 44 … … 56 58 void addLine(const InlineLineGeometry& line) { m_lines.append(line); } 57 59 60 const InlineLineBoxes& lineBoxes() const { return m_lineBoxes; } 61 void addLineBox(LineBox&& lineBox) { m_lineBoxes.append(WTFMove(lineBox)); } 62 58 63 const InlineLineRuns& lineRuns() const { return m_lineRuns; } 59 64 InlineLineRuns& lineRuns() { return m_lineRuns; } … … 67 72 InlineItems m_inlineItems; 68 73 InlineLines m_lines; 74 InlineLineBoxes m_lineBoxes; 69 75 InlineLineRuns m_lineRuns; 70 76 }; … … 73 79 { 74 80 m_lines.clear(); 81 m_lineBoxes.clear(); 75 82 m_lineRuns.clear(); 76 83 } … … 79 86 { 80 87 m_lines.shrinkToFit(); 88 m_lineBoxes.shrinkToFit(); 81 89 m_lineRuns.shrinkToFit(); 82 90 } -
trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h
r267234 r267434 112 112 const InlineBox& inlineBoxForLayoutBox(const Box& layoutBox) const { return *m_inlineBoxRectMap.get(&layoutBox); } 113 113 InlineRect logicalRectForTextRun(const Line::Run&) const; 114 115 using InlineBoxMap = HashMap<const Box*, InlineBox*>;116 114 auto inlineBoxList() const { return m_inlineBoxRectMap.values(); } 115 bool containsInlineLevelBox(const Box& layoutBox) const { return m_inlineBoxRectMap.contains(&layoutBox); } 117 116 118 117 InlineLayoutUnit alignmentBaseline() const { return m_rootInlineBox->logicalTop() + m_rootInlineBox->baseline(); } … … 141 140 InlineBoxList m_nonRootInlineBoxList; 142 141 143 InlineBoxMapm_inlineBoxRectMap;142 HashMap<const Box*, InlineBox*> m_inlineBoxRectMap; 144 143 }; 145 144
Note:
See TracChangeset
for help on using the changeset viewer.