Changeset 286784 in webkit
- Timestamp:
- Dec 9, 2021, 9:26:58 AM (5 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
-
ChangeLog (modified) (1 diff)
-
layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp (modified) (4 diffs)
-
layout/formattingContexts/inline/InlineDisplayContentBuilder.h (modified) (2 diffs)
-
layout/formattingContexts/inline/display/InlineDisplayBox.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r286782 r286784 1 2021-12-09 Alan Bujtas <zalan@apple.com> 2 3 [LFC][IFC] Refactor bidi inline box boundary handling 4 https://bugs.webkit.org/show_bug.cgi?id=233880 5 6 Reviewed by Antti Koivisto. 7 8 This patch remove some code complexity by introducing more suitable data types to handle 9 content ranges for inline boxes. 10 11 1. The final output of the InlineDisplayContentBuilder is a list of display boxes. 12 It's a simple "one box right after the other" type of setup with continuous geometry (ie next box starts where 13 the previous ends +-horizontal margins) unless the content is embedded in an inline box (e.g. <span>embedded content</span>) 14 Inline box type of display boxes enclose all their descendant content. 15 Normally when the logical order == visual order (unidirectional content), the 16 descendant content ends right before the "inline box end" mark (</span>). 17 It makes it easy to compute the right edge/enclosing width for the inline box type of display boxes. 18 2. However the visual order of the bidi content makes the "let's use the inline box end mark" logic unusable as 19 we may see the "inline box end" mark even before we come across any descendant content 20 (there are other types of confusions with random ordering). 21 3. Working with a list when the content comes in a nested flavor may introduce some complexity (e.g. need to keep content ranges around). 22 23 This patch introduces a very simple DisplayBoxNode type which keeps track of the display boxes in a tree fashion. 24 The display boxes are still stored in a list, while this newly introduced DisplayBoxNode tree helps traversing 25 the nested content. 26 It helps finding out the insertion point at unexpected bidi boundaries (e.g. when nested content from other inline boxes 27 show up in a logically unrelated inline box) and it is also very valuable when computing visual geometries for those enclosing display boxes. 28 29 * layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp: 30 (WebCore::Layout::DisplayBoxNode::DisplayBoxNode): 31 (WebCore::Layout::DisplayBoxNode::appendChild): 32 (WebCore::Layout::AncestorStack::unwind): 33 (WebCore::Layout::AncestorStack::push): 34 (WebCore::Layout::InlineDisplayContentBuilder::ensureDisplayBoxForContainer): 35 (WebCore::Layout::InlineDisplayContentBuilder::adjustVisualGeometryForChildNode): 36 (WebCore::Layout::InlineDisplayContentBuilder::insertInlineBoxDisplayBoxForBidiBoundary): Deleted. 37 (WebCore::Layout::InlineDisplayContentBuilder::adjustInlineBoxDisplayBoxForBidiBoundary): Deleted. 38 (WebCore::Layout::InlineDisplayContentBuilder::processBidiContent): Deleted. 39 (WebCore::Layout::InlineDisplayContentBuilder::processOverflownRunsForEllipsis): Deleted. 40 (WebCore::Layout::InlineDisplayContentBuilder::collectInkOverflowForInlineBoxes): Deleted. 41 (WebCore::Layout::InlineDisplayContentBuilder::computeIsFirstIsLastBoxForInlineContent): Deleted. 42 * layout/formattingContexts/inline/InlineDisplayContentBuilder.h: 43 * layout/formattingContexts/inline/display/InlineDisplayBox.h: 44 (WebCore::InlineDisplay::Box::setLogicalLeft): 45 (WebCore::InlineDisplay::Box::setLogicalRight): 46 (WebCore::InlineDisplay::Box::setLogicalRect): 47 (WebCore::InlineDisplay::Box::setHasContent): 48 1 49 2021-12-09 Alan Bujtas <zalan@apple.com> 2 50 -
trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp
r286782 r286784 267 267 } 268 268 269 void InlineDisplayContentBuilder::insertInlineBoxDisplayBoxForBidiBoundary(const InlineLevelBox& inlineBox, const InlineRect& inlineBoxRect, bool isFirstInlineBoxFragment, size_t insertionPoint, DisplayBoxes& boxes)270 {271 ASSERT(inlineBox.isInlineBox());272 273 auto isFirstLastBox = OptionSet<InlineDisplay::Box::PositionWithinInlineLevelBox> { };274 if (inlineBox.isFirstBox() && isFirstInlineBoxFragment)275 isFirstLastBox.add({ InlineDisplay::Box::PositionWithinInlineLevelBox::First });276 if (inlineBox.isLastBox())277 isFirstLastBox.add({ InlineDisplay::Box::PositionWithinInlineLevelBox::Last });278 279 // FIXME: Compute ink overflow.280 boxes.insert(insertionPoint, { m_lineIndex281 , InlineDisplay::Box::Type::NonRootInlineBox282 , inlineBox.layoutBox()283 , UBIDI_DEFAULT_LTR284 , inlineBoxRect285 , inlineBoxRect286 , { }287 , { }288 , true289 , isFirstLastBox });290 }291 292 void InlineDisplayContentBuilder::adjustInlineBoxDisplayBoxForBidiBoundary(InlineDisplay::Box& displayBox, const InlineRect& inlineBoxRect)293 {294 UNUSED_PARAM(displayBox);295 UNUSED_PARAM(inlineBoxRect);296 }297 298 269 void InlineDisplayContentBuilder::processNonBidiContent(const LineBuilder::LineContent& lineContent, const LineBox& lineBox, const InlineLayoutPoint& lineBoxLogicalTopLeft, DisplayBoxes& boxes) 299 270 { … … 350 321 } 351 322 323 struct DisplayBoxNode { 324 WTF_MAKE_STRUCT_FAST_ALLOCATED; 325 DisplayBoxNode() = default; 326 DisplayBoxNode(size_t index, DisplayBoxNode* parent) 327 : index(index) 328 , parent(parent) 329 { 330 } 331 332 void appendChild(size_t childIndex) { children.append(makeUnique<DisplayBoxNode>(childIndex, this)); } 333 334 size_t index { 0 }; 335 DisplayBoxNode* parent { nullptr }; 336 Vector<std::unique_ptr<DisplayBoxNode>> children; 337 }; 338 339 struct AncestorStack { 340 DisplayBoxNode* unwind(const ContainerBox& containerBox) 341 { 342 // Unwind the stack all the way to container box. 343 if (!m_set.contains(&containerBox)) 344 return nullptr; 345 while (m_set.last() != &containerBox) { 346 m_stack.removeLast(); 347 m_set.removeLast(); 348 } 349 // Root is always a common ancestor. 350 ASSERT(!m_stack.isEmpty()); 351 return m_stack.last(); 352 } 353 354 void push(DisplayBoxNode& displayBoxNode, const ContainerBox& containerBox) 355 { 356 m_stack.append(&displayBoxNode); 357 ASSERT(!m_set.contains(&containerBox)); 358 m_set.add(&containerBox); 359 } 360 361 private: 362 Vector<DisplayBoxNode*> m_stack; 363 ListHashSet<const ContainerBox*> m_set; 364 }; 365 366 DisplayBoxNode& InlineDisplayContentBuilder::ensureDisplayBoxForContainer(const ContainerBox& containerBox, AncestorStack& ancestorStack, DisplayBoxes& boxes) 367 { 368 ASSERT(containerBox.isInlineBox() || &containerBox == &root()); 369 if (auto* lowestCommonAncestor = ancestorStack.unwind(containerBox)) 370 return *lowestCommonAncestor; 371 auto& enclosingDisplayBoxNodeForContainer = ensureDisplayBoxForContainer(containerBox.parent(), ancestorStack, boxes); 372 boxes.append({ m_lineIndex, InlineDisplay::Box::Type::NonRootInlineBox, containerBox, UBIDI_DEFAULT_LTR, { }, { }, { }, { }, true, { } }); 373 374 enclosingDisplayBoxNodeForContainer.appendChild(boxes.size() - 1); 375 auto& displayBoxNodeForContainer = *enclosingDisplayBoxNodeForContainer.children.last(); 376 ancestorStack.push(displayBoxNodeForContainer, containerBox); 377 return displayBoxNodeForContainer; 378 } 379 380 void InlineDisplayContentBuilder::adjustVisualGeometryForChildNode(const DisplayBoxNode& displayBoxNode, InlineLayoutUnit& contentRightInVisualOrder, InlineLayoutUnit lineBoxLogicalTop, DisplayBoxes& boxes, const LineBox& lineBox) 381 { 382 // Non-inline box display boxes just need a horizontal adjustment while 383 // inline box type of display boxes need 384 // 1. horizontal adjustment and margin/border/padding start offsetting on the first box 385 // 2. right edge computation including descendant content width and margin/border/padding end offsetting on the last box 386 ASSERT(displayBoxNode.index); 387 auto& displayBox = boxes[displayBoxNode.index]; 388 auto& layoutBox = displayBox.layoutBox(); 389 390 if (!displayBox.isNonRootInlineBox()) { 391 displayBox.setLogicalLeft(contentRightInVisualOrder); 392 contentRightInVisualOrder += displayBox.logicalWidth(); 393 if (displayBox.isAtomicInlineLevelBox() || displayBox.isGenericInlineLevelBox()) 394 contentRightInVisualOrder += formattingState().boxGeometry(layoutBox).marginEnd(); 395 return; 396 } 397 398 auto& boxGeometry = formattingState().boxGeometry(layoutBox); 399 auto beforeInlineBoxContent = [&] { 400 auto logicalRect = lineBox.logicalBorderBoxForInlineBox(layoutBox, boxGeometry); 401 auto visualRect = InlineRect { lineBoxLogicalTop + logicalRect.top(), contentRightInVisualOrder, { }, logicalRect.height() }; 402 // FIXME: Add support for ink overflow. 403 if (!displayBox.isFirstForLayoutBox()) 404 return displayBox.setLogicalRect(visualRect, visualRect); 405 406 contentRightInVisualOrder += boxGeometry.marginStart(); 407 auto visualRectWithMarginStart = InlineRect { visualRect.top(), contentRightInVisualOrder, visualRect.width(), visualRect.height() }; 408 displayBox.setLogicalRect(visualRectWithMarginStart, visualRectWithMarginStart); 409 contentRightInVisualOrder += boxGeometry.borderAndPaddingStart(); 410 }; 411 beforeInlineBoxContent(); 412 413 for (auto& childDisplayBoxNode : displayBoxNode.children) 414 adjustVisualGeometryForChildNode(*childDisplayBoxNode, contentRightInVisualOrder, lineBoxLogicalTop, boxes, lineBox); 415 416 auto afterInlineBoxContent = [&] { 417 if (!displayBox.isLastForLayoutBox()) 418 return displayBox.setLogicalRight(contentRightInVisualOrder); 419 420 contentRightInVisualOrder += boxGeometry.borderAndPaddingEnd(); 421 displayBox.setLogicalRight(contentRightInVisualOrder); 422 contentRightInVisualOrder += boxGeometry.marginEnd(); 423 }; 424 afterInlineBoxContent(); 425 426 setInlineBoxGeometry(layoutBox, displayBox.logicalRect(), displayBox.isFirstForLayoutBox()); 427 if (lineBox.inlineLevelBoxForLayoutBox(layoutBox).hasContent()) 428 displayBox.setHasContent(); 429 } 430 352 431 void InlineDisplayContentBuilder::processBidiContent(const LineBuilder::LineContent& lineContent, const LineBox& lineBox, const InlineLayoutPoint& lineBoxLogicalTopLeft, DisplayBoxes& boxes) 353 432 { 354 433 ASSERT(lineContent.visualOrderList.size() == lineContent.runs.size()); 355 434 356 Vector<Range<size_t>> inlineBoxRangeList; 357 auto needsNonRootInlineBoxDisplayBox = false; 358 auto createDisplayBoxesInVisualOrderForContentRuns = [&] { 435 AncestorStack ancestorStack; 436 DisplayBoxNode rootDisplayBoxNode = { }; 437 ancestorStack.push(rootDisplayBoxNode, root()); 438 439 auto contentStartInVisualOrder = InlineLayoutUnit { }; 440 auto createDisplayBoxesInVisualOrder = [&] { 359 441 auto rootInlineBoxRect = lineBox.logicalRectForRootInlineBox(); 360 auto contentRightInVisualOrder = InlineLayoutUnit { };361 442 // First visual run's initial content position depends on the block's inline direction. 362 443 if (!root().style().isLeftToRightDirection()) { 363 444 // FIXME: This needs the block end position instead of the lineLogicalWidth. 364 content RightInVisualOrder += lineContent.lineLogicalWidth - rootInlineBoxRect.width();445 contentStartInVisualOrder += lineContent.lineLogicalWidth - rootInlineBoxRect.width(); 365 446 } 366 447 // Adjust the content start position with the (text)alignment offset (root inline box has the alignment offset and not the individual runs). 367 contentRightInVisualOrder += rootInlineBoxRect.left(); 368 448 contentStartInVisualOrder += rootInlineBoxRect.left(); 449 450 auto contentRightInVisualOrder = contentStartInVisualOrder; 369 451 auto& runs = lineContent.runs; 370 452 for (size_t i = 0; i < runs.size(); ++i) { 371 453 auto visualIndex = lineContent.visualOrderList[i]; 372 454 auto& lineRun = runs[visualIndex]; 373 374 auto isContentRun = !lineRun.isInlineBoxStart() && !lineRun.isLineSpanningInlineBoxStart() && !lineRun.isInlineBoxEnd(); 455 auto& layoutBox = lineRun.layoutBox(); 456 457 auto isContentRun = !lineRun.isInlineBoxStart() && !lineRun.isLineSpanningInlineBoxStart() && !lineRun.isInlineBoxEnd() && !lineRun.isWordBreakOpportunity(); 375 458 if (!isContentRun) { 376 needsNonRootInlineBoxDisplayBox = true;459 // FIXME: Add support for inline boxes with no content. 377 460 continue; 378 461 } … … 384 467 }; 385 468 469 auto& parentDisplayBoxNode = ensureDisplayBoxForContainer(layoutBox.parent(), ancestorStack, boxes); 386 470 if (lineRun.isText()) { 387 471 auto visualRect = visualRectRelativeToRoot(lineBox.logicalRectForTextRun(lineRun)); 388 472 appendTextDisplayBox(lineRun, visualRect, boxes); 389 473 contentRightInVisualOrder += visualRect.width(); 390 continue; 391 } 392 if (lineRun.isSoftLineBreak()) { 474 } else if (lineRun.isSoftLineBreak()) { 393 475 ASSERT(!visualRectRelativeToRoot(lineBox.logicalRectForTextRun(lineRun)).width()); 394 476 appendSoftLineBreakDisplayBox(lineRun, visualRectRelativeToRoot(lineBox.logicalRectForTextRun(lineRun)), boxes); 395 continue; 396 } 397 if (lineRun.isHardLineBreak()) { 398 ASSERT(!visualRectRelativeToRoot(lineBox.logicalRectForLineBreakBox(lineRun.layoutBox())).width()); 399 appendHardLineBreakDisplayBox(lineRun, visualRectRelativeToRoot(lineBox.logicalRectForLineBreakBox(lineRun.layoutBox())), boxes); 400 continue; 401 } 402 if (lineRun.isBox()) { 403 auto& layoutBox = lineRun.layoutBox(); 477 } else if (lineRun.isHardLineBreak()) { 478 ASSERT(!visualRectRelativeToRoot(lineBox.logicalRectForLineBreakBox(layoutBox)).width()); 479 appendHardLineBreakDisplayBox(lineRun, visualRectRelativeToRoot(lineBox.logicalRectForLineBreakBox(layoutBox)), boxes); 480 } else if (lineRun.isBox()) { 404 481 auto& boxGeometry = formattingState().boxGeometry(layoutBox); 405 482 auto visualRect = visualRectRelativeToRoot(lineBox.logicalBorderBoxForAtomicInlineLevelBox(layoutBox, boxGeometry)); … … 407 484 appendAtomicInlineLevelDisplayBox(lineRun, visualRect, boxes); 408 485 contentRightInVisualOrder += boxGeometry.marginStart() + visualRect.width() + boxGeometry.marginEnd(); 409 continue;410 486 } 411 ASSERT(lineRun.isWordBreakOpportunity()); 412 } 413 }; 414 createDisplayBoxesInVisualOrderForContentRuns(); 415 416 auto needsDisplayBoxHorizontalAdjustment = false; 417 auto createDisplayBoxesInVisualOrderForInlineBoxes = [&] { 418 // Visual order could introduce gaps and/or inject runs outside from the current inline box content. 419 // In such cases, we need to "close" and "open" display boxes for these inline box fragments 420 // to accommodate the current content. 421 // We do it by finding the lowest common ancestor of the last and the current content display boxes and 422 // traverse both ancestor chains and close/open the parent (inline) boxes. 423 // (open here means to create a new display box, while close means to simply pop it out of parentBoxStack). 424 // <div>a<span id=first>b‮g</span>f<span id=second>e‭c</span>d</div> 425 // produces the following output (note the #8238; #8237; RTL/LTR control characters): 426 // abcdefg 427 // with the following, fragmented inline boxes: 428 // a[first open]b[first close][second open]c[second close]d[second open]e[second close]f[first open]g[first close] 429 HashMap<const Box*, size_t> inlineBoxDisplayBoxMap; 430 ListHashSet<const Box*> parentBoxStack; 431 parentBoxStack.add(&root()); 432 433 ASSERT(boxes[0].isRootInlineBox()); 434 for (size_t index = 1; index < boxes.size(); ++index) { 435 auto& parentBox = boxes[index].layoutBox().parent(); 436 ASSERT(parentBox.isInlineBox() || &parentBox == &root()); 437 438 auto runParentIsCurrentInlineBox = &parentBox == parentBoxStack.last(); 439 if (runParentIsCurrentInlineBox) { 440 // We've got the correct inline box as parent. Nothing to do here. 441 continue; 487 parentDisplayBoxNode.appendChild(boxes.size() - 1); 488 } 489 }; 490 createDisplayBoxesInVisualOrder(); 491 492 if (!rootDisplayBoxNode.children.isEmpty()) { 493 auto computeIsFirstIsLastBox = [&] { 494 HashMap<const Box*, size_t> lastDisplayBoxIndexes; 495 ASSERT(boxes[0].isRootInlineBox()); 496 for (size_t index = 1; index < boxes.size(); ++index) { 497 auto& displayBox = boxes[index]; 498 if (!displayBox.isNonRootInlineBox()) 499 continue; 500 auto& layoutBox = displayBox.layoutBox(); 501 auto isFirstBoxOnCurrentLine = lastDisplayBoxIndexes.set(&layoutBox, index).isNewEntry; 502 if (lineBox.inlineLevelBoxForLayoutBox(layoutBox).isFirstBox() && isFirstBoxOnCurrentLine) 503 displayBox.setIsFirstForLayoutBox(true); 442 504 } 443 auto parentBoxStackEnd = parentBoxStack.end(); 444 Vector<const Box*> inlineBoxNeedingDisplayBoxList; 445 for (auto* ancestor = &parentBox; ancestor; ancestor = &ancestor->parent()) { 446 ASSERT(ancestor == &root() || ancestor->isInlineBox()); 447 auto parentBoxIterator = parentBoxStack.find(ancestor); 448 if (parentBoxIterator != parentBoxStackEnd) { 449 // This is the lowest common ancestor. 450 // Let's traverse both ancestor chains and create/close display boxes as needed. 451 Vector<const Box*> inlineBoxFragmentsToClose; 452 for (auto it = ++parentBoxIterator; it != parentBoxStackEnd; ++it) 453 inlineBoxFragmentsToClose.append(*it); 454 455 for (auto* inlineBox : makeReversedRange(inlineBoxFragmentsToClose)) { 456 ASSERT(inlineBox->isInlineBox()); 457 ASSERT(inlineBoxDisplayBoxMap.contains(inlineBox)); 458 inlineBoxRangeList.append({ inlineBoxDisplayBoxMap.get(inlineBox), index }); 459 parentBoxStack.remove(inlineBox); 460 } 461 462 // Insert new display boxes for inline box fragments on bidi boundary. 463 for (auto* inlineBox : makeReversedRange(inlineBoxNeedingDisplayBoxList)) { 464 ASSERT(inlineBox->isInlineBox()); 465 parentBoxStack.add(inlineBox); 466 467 auto createAndInsertDisplayBoxForInlineBoxFragment = [&] { 468 // Make sure that the "previous" display box for this particular inline box is not tracked as the "last box". 469 auto lastDisplayBoxForInlineBoxIndex = inlineBoxDisplayBoxMap.take(inlineBox); 470 auto isFirstFragment = !lastDisplayBoxForInlineBoxIndex; 471 if (!isFirstFragment) 472 boxes[lastDisplayBoxForInlineBoxIndex].setIsLastForLayoutBox(false); 473 inlineBoxDisplayBoxMap.set(inlineBox, index); 474 475 auto& boxGeometry = formattingState().boxGeometry(*inlineBox); 476 auto visualRect = lineBox.logicalBorderBoxForInlineBox(*inlineBox, boxGeometry); 477 // Use the current content left as the starting point for this display box. 478 visualRect.setLeft(boxes[index].logicalLeft()); 479 visualRect.moveVertically(lineBoxLogicalTopLeft.y()); 480 // Visual width is not yet known. 481 visualRect.setWidth({ }); 482 insertInlineBoxDisplayBoxForBidiBoundary(lineBox.inlineLevelBoxForLayoutBox(*inlineBox), visualRect, isFirstFragment, index, boxes); 483 ++index; 484 // Need to push the rest of the content when this inline box has margin/border/padding. 485 needsDisplayBoxHorizontalAdjustment = needsDisplayBoxHorizontalAdjustment 486 || boxGeometry.horizontalBorder() 487 || boxGeometry.horizontalPadding().value_or(0) 488 || boxGeometry.marginStart() 489 || boxGeometry.marginEnd(); 490 }; 491 createAndInsertDisplayBoxForInlineBoxFragment(); 492 } 493 break; 494 } 495 // root may not be the lowest but always a common ancestor. 496 ASSERT(ancestor != &root()); 497 inlineBoxNeedingDisplayBoxList.append(ancestor); 505 for (auto index : lastDisplayBoxIndexes.values()) { 506 if (lineBox.inlineLevelBoxForLayoutBox(boxes[index].layoutBox()).isLastBox()) 507 boxes[index].setIsLastForLayoutBox(true); 498 508 } 499 } 500 // "Close" the remaining inline boxes on the stack (excluding the root). 501 while (parentBoxStack.size() > 1) { 502 auto* parentInlineBox = parentBoxStack.takeLast(); 503 ASSERT(inlineBoxDisplayBoxMap.contains(parentInlineBox)); 504 inlineBoxRangeList.append({ inlineBoxDisplayBoxMap.get(parentInlineBox), boxes.size() }); 505 } 506 }; 507 if (needsNonRootInlineBoxDisplayBox) 508 createDisplayBoxesInVisualOrderForInlineBoxes(); 509 510 auto adjustVisualGeometryWithInlineBoxes = [&] { 511 size_t currentInlineBox = 0; 512 auto accumulatedOffset = InlineLayoutUnit { }; 513 514 ASSERT(boxes[0].isRootInlineBox()); 515 for (size_t index = 1; index < boxes.size(); ++index) { 516 auto& displayBox = boxes[index]; 517 displayBox.moveHorizontally(accumulatedOffset); 518 519 while (currentInlineBox < inlineBoxRangeList.size() && index == inlineBoxRangeList[currentInlineBox].end() - 1) { 520 // We are at the end of the inline box content. 521 // Let's compute the inline box width and offset the rest of the content with padding/border/margin end. 522 auto inlineBoxRange = inlineBoxRangeList[currentInlineBox++]; 523 auto& inlineBoxDisplayBox = boxes[inlineBoxRange.begin()]; 524 ASSERT(inlineBoxDisplayBox.isNonRootInlineBox()); 525 526 auto& boxGeometry = formattingState().boxGeometry(inlineBoxDisplayBox.layoutBox()); 527 auto contentRight = displayBox.logicalRight(); 528 if (inlineBoxDisplayBox.isLastForLayoutBox()) { 529 accumulatedOffset += boxGeometry.borderAndPaddingEnd() + boxGeometry.marginEnd(); 530 inlineBoxDisplayBox.setLogicalRight(contentRight + boxGeometry.borderAndPaddingEnd()); 531 } else 532 inlineBoxDisplayBox.setLogicalRight(contentRight); 533 } 534 if (displayBox.isNonRootInlineBox() && displayBox.isFirstForLayoutBox()) { 535 auto& layoutBox = displayBox.layoutBox(); 536 auto& boxGeometry = formattingState().boxGeometry(layoutBox); 537 538 displayBox.moveHorizontally(boxGeometry.marginStart()); 539 accumulatedOffset += boxGeometry.marginStart() + boxGeometry.borderAndPaddingStart(); 540 } 541 } 542 }; 543 if (needsDisplayBoxHorizontalAdjustment) 509 }; 510 computeIsFirstIsLastBox(); 511 512 auto adjustVisualGeometryWithInlineBoxes = [&] { 513 auto contentRightInVisualOrder = lineBoxLogicalTopLeft.x() + contentStartInVisualOrder; 514 for (auto& childDisplayBoxNode : rootDisplayBoxNode.children) 515 adjustVisualGeometryForChildNode(*childDisplayBoxNode, contentRightInVisualOrder, lineBoxLogicalTopLeft.y(), boxes, lineBox); 516 }; 544 517 adjustVisualGeometryWithInlineBoxes(); 545 546 auto computeInlineBoxGeometry = [&] { 547 ASSERT(!inlineBoxRangeList.isEmpty()); 548 for (auto& inlineBoxRange : inlineBoxRangeList) { 549 auto& inlineBoxDisplayBox = boxes[inlineBoxRange.begin()]; 550 setInlineBoxGeometry(inlineBoxDisplayBox.layoutBox(), inlineBoxDisplayBox.logicalRect(), inlineBoxDisplayBox.isFirstForLayoutBox()); 551 } 552 }; 553 if (needsNonRootInlineBoxDisplayBox) 554 computeInlineBoxGeometry(); 518 } 555 519 } 556 520 -
trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.h
r286782 r286784 34 34 namespace Layout { 35 35 36 struct AncestorStack; 36 37 class ContainerBox; 38 struct DisplayBoxNode; 37 39 class InlineFormattingState; 38 40 class LineBox; … … 58 60 void appendInlineBoxDisplayBox(const Line::Run&, const InlineLevelBox&, const InlineRect&, bool linehasContent, DisplayBoxes&); 59 61 void appendSpanningInlineBoxDisplayBox(const Line::Run&, const InlineLevelBox&, const InlineRect&, DisplayBoxes&); 60 void insertInlineBoxDisplayBoxForBidiBoundary(const InlineLevelBox&, const InlineRect&, bool isFirstInlineBoxFragment, size_t insertionPoint, DisplayBoxes&);61 void adjustInlineBoxDisplayBoxForBidiBoundary(InlineDisplay::Box&, const InlineRect&);62 62 63 63 void setInlineBoxGeometry(const Box&, const InlineRect&, bool isFirstInlineBoxFragment); 64 void adjustVisualGeometryForChildNode(const DisplayBoxNode&, InlineLayoutUnit& accumulatedOffset, InlineLayoutUnit lineBoxLogicalTop, DisplayBoxes&, const LineBox&); 65 DisplayBoxNode& ensureDisplayBoxForContainer(const ContainerBox&, AncestorStack&, DisplayBoxes&); 64 66 65 67 const ContainerBox& root() const { return m_formattingContextRoot; } -
trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayBox.h
r286541 r286784 119 119 void adjustInkOverflow(const Layout::InlineRect& childBorderBox) { return m_inkOverflow.expandToContain(childBorderBox); } 120 120 void truncate(Layout::InlineLayoutUnit truncatedwidth = 0.f); 121 void setLogicalRight(Layout::InlineLayoutUnit right) { m_logicalRect.setRight(right); } 121 void setLogicalLeft(Layout::InlineLayoutUnit left) 122 { 123 auto offset = left - logicalLeft(); 124 m_logicalRect.setLeft(left); 125 m_inkOverflow.setLeft(m_inkOverflow.left() + offset); 126 } 127 void setLogicalRight(Layout::InlineLayoutUnit right) 128 { 129 auto offset = right - logicalRight(); 130 m_logicalRect.setRight(right); 131 m_inkOverflow.setRight(m_inkOverflow.right() + offset); 132 } 133 void setLogicalRect(const Layout::InlineRect& rect, const Layout::InlineRect& inkOverflow) 134 { 135 m_logicalRect = rect; 136 m_inkOverflow = inkOverflow; 137 } 138 void setHasContent() { m_hasContent = true; } 122 139 123 140 std::optional<Text>& text() { return m_text; }
Note:
See TracChangeset
for help on using the changeset viewer.