Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp

Issue 2020103002: Fix sticky constraints and update sticky layer positions recursively after scroll. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix bugs with overflow scrollers in sticky position constraints, add unit tests, and test clipped b… Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) 4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com) 5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 6 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
7 * Copyright (C) 2010 Google Inc. All rights reserved. 7 * Copyright (C) 2010 Google Inc. All rights reserved.
8 * 8 *
9 * This library is free software; you can redistribute it and/or 9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public 10 * modify it under the terms of the GNU Library General Public
(...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after
628 && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight() 628 && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight()
629 || !style()->bottom().hasPercent() 629 || !style()->bottom().hasPercent()
630 || containingBlock->stretchesToViewport())) 630 || containingBlock->stretchesToViewport()))
631 offset.expand(LayoutUnit(), -valueForLength(style()->bottom(), containin gBlock->availableHeight())); 631 offset.expand(LayoutUnit(), -valueForLength(style()->bottom(), containin gBlock->availableHeight()));
632 632
633 return offset; 633 return offset;
634 } 634 }
635 635
636 void LayoutBoxModelObject::updateStickyPositionConstraints() const 636 void LayoutBoxModelObject::updateStickyPositionConstraints() const
637 { 637 {
638 // TODO(flackr): This method is reasonably complicated and should have some direct unit testing.
639 const FloatSize constrainingSize = computeStickyConstrainingRect().size(); 638 const FloatSize constrainingSize = computeStickyConstrainingRect().size();
640 639
641 PaintLayerScrollableArea* scrollableArea = layer()->ancestorOverflowLayer()- >getScrollableArea(); 640 PaintLayerScrollableArea* scrollableArea = layer()->ancestorOverflowLayer()- >getScrollableArea();
642 StickyPositionScrollingConstraints constraints; 641 StickyPositionScrollingConstraints constraints;
643 FloatSize skippedContainersOffset; 642 FloatSize skippedContainersOffset;
644 LayoutBlock* containingBlock = this->containingBlock(); 643 LayoutBlock* containingBlock = this->containingBlock();
645 // Skip anonymous containing blocks. 644 // Skip anonymous containing blocks.
646 while (containingBlock->isAnonymous()) { 645 while (containingBlock->isAnonymous()) {
647 skippedContainersOffset += toFloatSize(FloatPoint(containingBlock->frame Rect().location())); 646 skippedContainersOffset += toFloatSize(FloatPoint(containingBlock->frame Rect().location()));
648 containingBlock = containingBlock->containingBlock(); 647 containingBlock = containingBlock->containingBlock();
649 } 648 }
650 LayoutBox* scrollAncestor = layer()->ancestorOverflowLayer()->isRootLayer() ? nullptr : toLayoutBox(layer()->ancestorOverflowLayer()->layoutObject()); 649 LayoutBox* scrollAncestor = layer()->ancestorOverflowLayer()->isRootLayer() ? nullptr : toLayoutBox(layer()->ancestorOverflowLayer()->layoutObject());
651 650
652 LayoutRect containerContentRect = containingBlock->contentBoxRect(); 651 LayoutRect containerContentRect = containingBlock->layoutOverflowRect();
flackr 2016/06/09 17:13:32 When the container is the scroll ancestor, we need
653 LayoutUnit maxWidth = containingBlock->availableLogicalWidth(); 652 LayoutUnit maxWidth = containingBlock->availableLogicalWidth();
653 containerContentRect.contractEdges(
chrishtr 2016/06/06 22:18:39 Contract for padding and then margin? Is this tryi
flackr 2016/06/09 17:13:33 Done, note that we remove the padding from the con
654 minimumValueForLength(containingBlock->style()->paddingTop(), maxWidth),
655 minimumValueForLength(containingBlock->style()->paddingRight(), maxWidth ),
656 minimumValueForLength(containingBlock->style()->paddingBottom(), maxWidt h),
657 minimumValueForLength(containingBlock->style()->paddingLeft(), maxWidth) );
654 658
655 // Sticky positioned element ignore any override logical width on the contai ning block (as they don't call 659 // Sticky positioned element ignore any override logical width on the contai ning block (as they don't call
chrishtr 2016/06/06 22:18:39 Does this comment belong above line 651?
flackr 2016/06/09 17:13:33 Done.
656 // containingBlockLogicalWidthForContent). It's unclear whether this is tota lly fine. 660 // containingBlockLogicalWidthForContent). It's unclear whether this is tota lly fine.
657 // Compute the container-relative area within which the sticky element is al lowed to move. 661 // Compute the container-relative area within which the sticky element is al lowed to move.
658 containerContentRect.contractEdges( 662 containerContentRect.contractEdges(
659 minimumValueForLength(style()->marginTop(), maxWidth), 663 minimumValueForLength(style()->marginTop(), maxWidth),
660 minimumValueForLength(style()->marginRight(), maxWidth), 664 minimumValueForLength(style()->marginRight(), maxWidth),
661 minimumValueForLength(style()->marginBottom(), maxWidth), 665 minimumValueForLength(style()->marginBottom(), maxWidth),
662 minimumValueForLength(style()->marginLeft(), maxWidth)); 666 minimumValueForLength(style()->marginLeft(), maxWidth));
663 667
664 // Map to the scroll ancestor. 668 // Map to the scroll ancestor.
665 constraints.setScrollContainerRelativeContainingBlockRect(containingBlock->l ocalToAncestorQuad(FloatRect(containerContentRect), scrollAncestor).boundingBox( )); 669 FloatRect scrollContainerRelativeContainingBlockRect(containingBlock->localT oAncestorQuad(FloatRect(containerContentRect), scrollAncestor).boundingBox());
670 FloatSize scrollOffset(scrollAncestor ? toFloatSize(scrollAncestor->getScrol lableArea()->adjustedScrollOffset()) : FloatSize());
chrishtr 2016/06/06 22:18:39 Why should this rect include scroll offset?
flackr 2016/06/09 17:13:33 Because we want the container's rect with respect
chrishtr 2016/06/13 19:46:39 I see, ok. Why doesn't localToAncestorQuad handle
flackr 2016/06/15 13:45:49 offsetFromContainer is specifically removing the s
671
672 // Include scroll offset in container position if the container is not our s croll ancestor.
673 if (containingBlock != scrollAncestor)
chrishtr 2016/06/06 22:18:39 Why conditional? What if the containing block is a
flackr 2016/06/09 17:13:32 We want to compute the bounds relative to the scro
chrishtr 2016/06/13 19:46:39 Ah. Yes you are right.
674 scrollContainerRelativeContainingBlockRect.move(scrollOffset);
675 constraints.setScrollContainerRelativeContainingBlockRect(scrollContainerRel ativeContainingBlockRect);
666 676
667 FloatRect stickyBoxRect = isLayoutInline() 677 FloatRect stickyBoxRect = isLayoutInline()
668 ? FloatRect(toLayoutInline(this)->linesBoundingBox()) 678 ? FloatRect(toLayoutInline(this)->linesBoundingBox())
669 : FloatRect(toLayoutBox(this)->frameRect()); 679 : FloatRect(toLayoutBox(this)->frameRect());
670 FloatRect flippedStickyBoxRect = stickyBoxRect; 680 FloatRect flippedStickyBoxRect = stickyBoxRect;
671 containingBlock->flipForWritingMode(flippedStickyBoxRect); 681 containingBlock->flipForWritingMode(flippedStickyBoxRect);
672 FloatPoint stickyLocation = flippedStickyBoxRect.location() + skippedContain ersOffset; 682 FloatPoint stickyLocation = flippedStickyBoxRect.location() + skippedContain ersOffset;
673 683
674 // TODO(flackr): Unfortunate to call localToAncestorQuad again, but we can't just offset from the previously computed rect if there are transforms. 684 // TODO(flackr): Unfortunate to call localToAncestorQuad again, but we can't just offset from the previously computed rect if there are transforms.
675 // Map to the scroll ancestor. 685 // Map to the scroll ancestor.
676 FloatRect scrollContainerRelativeContainerFrame = containingBlock->localToAn cestorQuad(FloatRect(FloatPoint(), FloatSize(containingBlock->size())), scrollAn cestor).boundingBox(); 686 FloatRect scrollContainerRelativeContainerFrame = containingBlock->localToAn cestorQuad(FloatRect(FloatPoint(), FloatSize(containingBlock->size())), scrollAn cestor).boundingBox();
687 scrollContainerRelativeContainerFrame.move(scrollOffset);
chrishtr 2016/06/06 22:18:39 localToAncestorQuad should already be adding in th
flackr 2016/06/09 17:13:32 It does not seem to. If the container is at (0, 0)
chrishtr 2016/06/13 19:46:39 See my comment above. Curious why it is not workin
chrishtr 2016/06/15 16:13:46 Any response to this comment?
flackr 2016/06/16 07:22:51 Ah, sorry, I commented on the other location. offs
677 688
678 // If the containing block is our scroll ancestor, its location will not inc lude the scroll offset which we need to include as 689 // If the containing block is our scroll ancestor, its location will not inc lude the scroll offset which we need to include as
679 // part of the sticky box rect so we include it here. 690 // part of the sticky box rect so we include it here.
680 if (containingBlock->hasOverflowClip()) { 691 if (containingBlock == scrollAncestor)
681 FloatSize scrollOffset(toFloatSize(containingBlock->layer()->getScrollab leArea()->adjustedScrollOffset()));
682 stickyLocation -= scrollOffset; 692 stickyLocation -= scrollOffset;
683 }
684 693
685 constraints.setScrollContainerRelativeStickyBoxRect(FloatRect(scrollContaine rRelativeContainerFrame.location() + toFloatSize(stickyLocation), flippedStickyB oxRect.size())); 694 constraints.setScrollContainerRelativeStickyBoxRect(FloatRect(scrollContaine rRelativeContainerFrame.location() + toFloatSize(stickyLocation), flippedStickyB oxRect.size()));
686 695
687 // We skip the right or top sticky offset if there is not enough space to ho nor both the left/right or top/bottom offsets. 696 // We skip the right or top sticky offset if there is not enough space to ho nor both the left/right or top/bottom offsets.
688 LayoutUnit horizontalOffsets = minimumValueForLength(style()->right(), Layou tUnit(constrainingSize.width())) + 697 LayoutUnit horizontalOffsets = minimumValueForLength(style()->right(), Layou tUnit(constrainingSize.width())) +
689 minimumValueForLength(style()->left(), LayoutUnit(constrainingSize.width ())); 698 minimumValueForLength(style()->left(), LayoutUnit(constrainingSize.width ()));
690 bool skipRight = false; 699 bool skipRight = false;
691 bool skipLeft = false; 700 bool skipLeft = false;
692 if (!style()->left().isAuto() && !style()->right().isAuto()) { 701 if (!style()->left().isAuto() && !style()->right().isAuto()) {
693 if (horizontalOffsets > containerContentRect.width() 702 if (horizontalOffsets > containerContentRect.width()
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
731 scrollableArea->stickyConstraintsMap().set(layer(), constraints); 740 scrollableArea->stickyConstraintsMap().set(layer(), constraints);
732 } 741 }
733 742
734 FloatRect LayoutBoxModelObject::computeStickyConstrainingRect() const 743 FloatRect LayoutBoxModelObject::computeStickyConstrainingRect() const
735 { 744 {
736 if (layer()->ancestorOverflowLayer()->isRootLayer()) 745 if (layer()->ancestorOverflowLayer()->isRootLayer())
737 return view()->frameView()->visibleContentRect(); 746 return view()->frameView()->visibleContentRect();
738 747
739 LayoutBox* enclosingClippingBox = toLayoutBox(layer()->ancestorOverflowLayer ()->layoutObject()); 748 LayoutBox* enclosingClippingBox = toLayoutBox(layer()->ancestorOverflowLayer ()->layoutObject());
740 FloatRect constrainingRect; 749 FloatRect constrainingRect;
741 constrainingRect = FloatRect(enclosingClippingBox->overflowClipRect(LayoutPo int())); 750 constrainingRect = FloatRect(enclosingClippingBox->overflowClipRect(LayoutPo int(DoublePoint(enclosingClippingBox->getScrollableArea()->adjustedScrollOffset( )))));
742 constrainingRect.move(enclosingClippingBox->paddingLeft(), enclosingClipping Box->paddingTop()); 751 constrainingRect.move(enclosingClippingBox->paddingLeft(), enclosingClipping Box->paddingTop());
743 constrainingRect.contract(FloatSize(enclosingClippingBox->paddingLeft() + en closingClippingBox->paddingRight(), 752 constrainingRect.contract(FloatSize(enclosingClippingBox->paddingLeft() + en closingClippingBox->paddingRight(),
744 enclosingClippingBox->paddingTop() + enclosingClippingBox->paddingBottom ())); 753 enclosingClippingBox->paddingTop() + enclosingClippingBox->paddingBottom ()));
745 return constrainingRect; 754 return constrainingRect;
746 } 755 }
747 756
748 LayoutSize LayoutBoxModelObject::stickyPositionOffset() const 757 LayoutSize LayoutBoxModelObject::stickyPositionOffset() const
749 { 758 {
750 const PaintLayer* ancestorOverflowLayer = layer()->ancestorOverflowLayer(); 759 const PaintLayer* ancestorOverflowLayer = layer()->ancestorOverflowLayer();
751 // TODO: Force compositing input update if we ask for offset before composit ing inputs have been computed? 760 // TODO: Force compositing input update if we ask for offset before composit ing inputs have been computed?
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after
1129 if (rootElementStyle->hasBackground()) 1138 if (rootElementStyle->hasBackground())
1130 return false; 1139 return false;
1131 1140
1132 if (node() != document().firstBodyElement()) 1141 if (node() != document().firstBodyElement())
1133 return false; 1142 return false;
1134 1143
1135 return true; 1144 return true;
1136 } 1145 }
1137 1146
1138 } // namespace blink 1147 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698