Changeset 286784 in webkit
- Timestamp:
- Dec 9, 2021, 9:26:58 AM (3 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r286782 r286784 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 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 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 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 contenttInVisualOrder += 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 377 460 continue; 378 461 } … … 384 467 }; 385 468 469 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 36 37 class ContainerBox; 38 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 65 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.