Changeset 192275 in webkit
- Timestamp:
- Nov 10, 2015 3:18:52 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r192270 r192275 1 2015-11-10 Zalan Bujtas <zalan@apple.com> 2 3 Continuations with anonymous wrappers inside misplaces child renderers. 4 https://bugs.webkit.org/show_bug.cgi?id=150908 5 6 When a child is appended to an inline container and the beforeChild is not a direct child, but 7 it is inside a generated subtree, we need to special case the inline split to form continuation. 8 9 RenderInline::splitInlines() assumes that beforeChild is always a direct child of the current 10 inline container. However when beforeChild type requires wrapper content (such as table cells), the DOM and the 11 render tree get out of sync. In such cases, we need to ensure that both the beforeChild and its siblings end up 12 in the correct generated block. 13 14 Reviewed by Darin Adler and David Hyatt. 15 16 * fast/inline/continuation-with-anon-wrappers-expected.txt: Added. 17 * fast/inline/continuation-with-anon-wrappers.html: Added. 18 1 19 2015-11-10 Geoffrey Garen <ggaren@apple.com> 2 20 -
trunk/Source/WebCore/ChangeLog
r192270 r192275 1 2015-11-10 Zalan Bujtas <zalan@apple.com> 2 3 Continuations with anonymous wrappers inside misplaces child renderers. 4 https://bugs.webkit.org/show_bug.cgi?id=150908 5 6 When a child is appended to an inline container and the beforeChild is not a direct child, but 7 it is inside a generated subtree, we need to special case the inline split to form continuation. 8 9 RenderInline::splitInlines() assumes that beforeChild is always a direct child of the current 10 inline container. However when beforeChild type requires wrapper content (such as table cells), the DOM and the 11 render tree get out of sync. In such cases, we need to ensure that both the beforeChild and its siblings end up 12 in the correct generated block. 13 14 Reviewed by Darin Adler and David Hyatt. 15 16 Test: fast/inline/continuation-with-anon-wrappers.html 17 18 * rendering/RenderInline.cpp: 19 (WebCore::RenderInline::splitInlines): 20 (WebCore::RenderInline::addChildToContinuation): 21 1 22 2015-11-10 Geoffrey Garen <ggaren@apple.com> 2 23 -
trunk/Source/WebCore/rendering/RenderInline.cpp
r191011 r192275 413 413 // Create a clone of this inline. 414 414 RenderPtr<RenderInline> cloneInline = clone(); 415 cloneInline->setContinuation(oldCont);416 417 415 #if ENABLE(FULLSCREEN_API) 418 416 // If we're splitting the inline containing the fullscreened element, … … 425 423 beforeChild = document().fullScreenRenderer(); 426 424 #endif 427 428 425 // Now take all of the children from beforeChild to the end and remove 429 426 // them from |this| and place them in the clone. 430 RenderObject* renderer = beforeChild; 431 while (renderer) { 432 RenderObject* tmp = renderer; 433 renderer = tmp->nextSibling(); 434 removeChildInternal(*tmp, NotifyChildren); 435 cloneInline->addChildIgnoringContinuation(tmp); 436 tmp->setNeedsLayoutAndPrefWidthsRecalc(); 437 } 438 427 for (RenderObject* rendererToMove = beforeChild; rendererToMove;) { 428 RenderObject* nextSibling = rendererToMove->nextSibling(); 429 // When anonymous wrapper is present, we might need to move the whole subtree instead. 430 if (rendererToMove->parent() != this) { 431 auto* anonymousParent = rendererToMove->parent(); 432 while (anonymousParent && anonymousParent->parent() != this) { 433 ASSERT(anonymousParent->isAnonymous()); 434 anonymousParent = anonymousParent->parent(); 435 } 436 if (!anonymousParent) { 437 ASSERT_NOT_REACHED(); 438 break; 439 } 440 // If beforeChild is the first child in the subtree, we could just move the whole subtree. 441 if (!rendererToMove->previousSibling()) { 442 // Reparent the whole anonymous wrapper tree. 443 rendererToMove = anonymousParent; 444 // Skip to the next sibling that is not in this subtree. 445 nextSibling = anonymousParent->nextSibling(); 446 } else if (!rendererToMove->nextSibling()) { 447 // This is the last renderer in the subtree. We need to jump out of the wrapper subtree, so that 448 // the siblings are getting reparented too. 449 nextSibling = anonymousParent->nextSibling(); 450 } 451 // Otherwise just move the renderer to the inline clone. Should the renderer need an anon 452 // wrapper, the addChild() will generate one for it. 453 // FIXME: When the anonymous wrapper has multiple children, we end up traversing up to the topmost wrapper 454 // every time, which is a bit wasteful. 455 } 456 rendererToMove->parent()->removeChildInternal(*rendererToMove, NotifyChildren); 457 cloneInline->addChildIgnoringContinuation(rendererToMove); 458 rendererToMove->setNeedsLayoutAndPrefWidthsRecalc(); 459 rendererToMove = nextSibling; 460 } 461 cloneInline->setContinuation(oldCont); 439 462 // Hook |clone| up as the continuation of the middle block. 440 463 middleBlock->setContinuation(cloneInline.get()); … … 469 492 // Now we need to take all of the children starting from the first child 470 493 // *after* currentChild and append them all to the clone. 471 renderer = currentChild->nextSibling(); 472 while (renderer) { 473 RenderObject* tmp = renderer; 474 renderer = tmp->nextSibling(); 475 currentInline.removeChildInternal(*tmp, NotifyChildren); 476 cloneInline->addChildIgnoringContinuation(tmp); 477 tmp->setNeedsLayoutAndPrefWidthsRecalc(); 494 for (auto* current = currentChild->nextSibling(); current;) { 495 auto* next = current->nextSibling(); 496 currentInline.removeChildInternal(*current, NotifyChildren); 497 cloneInline->addChildIgnoringContinuation(current); 498 current->setNeedsLayoutAndPrefWidthsRecalc(); 499 current = next; 478 500 } 479 501 } … … 493 515 // Now take all the children after currentChild and remove them from the fromBlock 494 516 // and put them in the toBlock. 495 renderer = currentChild->nextSibling(); 496 while (renderer) { 497 RenderObject* tmp = renderer; 498 renderer = tmp->nextSibling(); 499 fromBlock->removeChildInternal(*tmp, NotifyChildren); 500 toBlock->insertChildInternal(tmp, nullptr, NotifyChildren); 517 for (auto* current = currentChild->nextSibling(); current;) { 518 auto* next = current->nextSibling(); 519 fromBlock->removeChildInternal(*current, NotifyChildren); 520 toBlock->insertChildInternal(current, nullptr, NotifyChildren); 521 current = next; 501 522 } 502 523 } … … 570 591 { 571 592 RenderBoxModelObject* flow = continuationBefore(beforeChild); 572 ASSERT(!beforeChild || is<RenderBlock>(*beforeChild->parent()) || is<RenderInline>(*beforeChild->parent())); 573 RenderBoxModelObject* beforeChildParent = nullptr; 574 if (beforeChild) 575 beforeChildParent = downcast<RenderBoxModelObject>(beforeChild->parent()); 576 else { 577 if (RenderBoxModelObject* continuation = nextContinuation(flow)) 578 beforeChildParent = continuation; 579 else 580 beforeChildParent = flow; 593 // It may or may not be the direct parent of the beforeChild. 594 RenderBoxModelObject* beforeChildAncestor = nullptr; 595 // In case of anonymous wrappers, the parent of the beforeChild is mostly irrelevant. What we need is 596 // the topmost wrapper. 597 if (beforeChild && !is<RenderBlock>(beforeChild->parent()) && beforeChild->parent()->isAnonymous()) { 598 RenderElement* anonymousParent = beforeChild->parent(); 599 while (anonymousParent && anonymousParent->parent() && anonymousParent->parent()->isAnonymous()) 600 anonymousParent = anonymousParent->parent(); 601 ASSERT(anonymousParent && anonymousParent->parent()); 602 beforeChildAncestor = downcast<RenderBoxModelObject>(anonymousParent->parent()); 603 } else { 604 ASSERT(!beforeChild || is<RenderBlock>(*beforeChild->parent()) || is<RenderInline>(*beforeChild->parent())); 605 if (beforeChild) 606 beforeChildAncestor = downcast<RenderBoxModelObject>(beforeChild->parent()); 607 else { 608 if (RenderBoxModelObject* continuation = nextContinuation(flow)) 609 beforeChildAncestor = continuation; 610 else 611 beforeChildAncestor = flow; 612 } 581 613 } 582 614 583 615 if (newChild->isFloatingOrOutOfFlowPositioned()) 584 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); 585 616 return beforeChildAncestor->addChildIgnoringContinuation(newChild, beforeChild); 617 618 if (flow == beforeChildAncestor) 619 return flow->addChildIgnoringContinuation(newChild, beforeChild); 586 620 // A continuation always consists of two potential candidates: an inline or an anonymous 587 621 // block box holding block children. 588 622 bool childInline = newChildIsInline(*newChild, *this); 589 bool bcpInline = beforeChildParent->isInline(); 590 bool flowInline = flow->isInline(); 591 592 if (flow == beforeChildParent) 593 return flow->addChildIgnoringContinuation(newChild, beforeChild); 594 else { 595 // The goal here is to match up if we can, so that we can coalesce and create the 596 // minimal # of continuations needed for the inline. 597 if (childInline == bcpInline) 598 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); 599 else if (flowInline == childInline) 600 return flow->addChildIgnoringContinuation(newChild); // Just treat like an append. 601 else 602 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); 603 } 623 // The goal here is to match up if we can, so that we can coalesce and create the 624 // minimal # of continuations needed for the inline. 625 if (childInline == beforeChildAncestor->isInline()) 626 return beforeChildAncestor->addChildIgnoringContinuation(newChild, beforeChild); 627 if (flow->isInline() == childInline) 628 return flow->addChildIgnoringContinuation(newChild); // Just treat like an append. 629 return beforeChildAncestor->addChildIgnoringContinuation(newChild, beforeChild); 604 630 } 605 631
Note: See TracChangeset
for help on using the changeset viewer.