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

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

Issue 1308273010: Adapt and reland old position sticky implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Move compositor plumbing into a separate review. Created 5 years, 2 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 565 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 576
577 else if (!style()->bottom().isAuto() 577 else if (!style()->bottom().isAuto()
578 && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight() 578 && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight()
579 || !style()->bottom().hasPercent() 579 || !style()->bottom().hasPercent()
580 || containingBlock->stretchesToViewport())) 580 || containingBlock->stretchesToViewport()))
581 offset.expand(0, -valueForLength(style()->bottom(), containingBlock->ava ilableHeight())); 581 offset.expand(0, -valueForLength(style()->bottom(), containingBlock->ava ilableHeight()));
582 582
583 return offset; 583 return offset;
584 } 584 }
585 585
586 void LayoutBoxModelObject::computeStickyPositionConstraints(StickyPositionViewpo rtConstraints& constraints, const LayoutRect& constrainingRect) const
587 {
588 LayoutBlock* containingBlock = this->containingBlock();
589
590 LayoutRect containerContentRect = containingBlock->contentBoxRect();
591 LayoutUnit maxWidth = containingBlock->availableLogicalWidth();
592
593 // Sticky positioned element ignore any override logical width on the contai ning block (as they don't call
594 // containingBlockLogicalWidthForContent). It's unclear whether this is tota lly fine.
595 // Compute the container-relative area within which the sticky element is al lowed to move.
596 containerContentRect.contractEdges(
597 minimumValueForLength(style()->marginTop(), maxWidth),
598 minimumValueForLength(style()->marginRight(), maxWidth),
599 minimumValueForLength(style()->marginBottom(), maxWidth),
600 minimumValueForLength(style()->marginLeft(), maxWidth));
601
602 // Map to the view to avoid including page scale factor.
603 constraints.setAbsoluteContainingBlockRect(LayoutRect(containingBlock->local ToContainerQuad(FloatRect(containerContentRect), view()).boundingBox()));
604
605 LayoutRect stickyBoxRect = frameRectForStickyPositioning();
606 LayoutRect flippedStickyBoxRect = stickyBoxRect;
607 containingBlock->flipForWritingMode(flippedStickyBoxRect);
608 LayoutPoint stickyLocation = flippedStickyBoxRect.location();
609
610 // FIXME: sucks to call localToAbsolute again, but we can't just offset from the previously computed rect if there are transforms.
611 // Map to the view to avoid including page scale factor.
612 LayoutRect absContainerFrame = LayoutRect(containingBlock->localToContainerQ uad(FloatRect(FloatPoint(), FloatSize(containingBlock->size())), view()).boundin gBox());
613
614 if (containingBlock->hasOverflowClip()) {
615 LayoutSize scrollOffset(containingBlock->layer()->scrollableArea()->adju stedScrollOffset());
616 stickyLocation -= scrollOffset;
617 }
618
619 // We can't call localToAbsolute on |this| because that will recur. FIXME: F or now, assume that |this| is not transformed.
620 LayoutRect absoluteStickyBoxRect(LayoutPoint(absContainerFrame.location()) + stickyLocation, flippedStickyBoxRect.size());
621 constraints.setAbsoluteStickyBoxRect(absoluteStickyBoxRect);
622
623 LayoutUnit horizontalOffsets = constraints.rightOffset() + constraints.leftO ffset();
chrishtr 2015/10/06 17:08:33 You're reading leftOffset() here and then setting
flackr 2015/10/07 20:38:12 This is strange, I had lifted this from the old st
624 bool skipRight = false;
625 bool skipLeft = false;
626 if (!style()->left().isAuto() && !style()->right().isAuto()) {
627 if (horizontalOffsets > containerContentRect.width()
628 || horizontalOffsets + containerContentRect.width() > constrainingRe ct.width()) {
629 skipRight = style()->isLeftToRightDirection();
630 skipLeft = !skipRight;
631 }
632 }
633
634 if (!style()->left().isAuto() && !skipLeft) {
635 constraints.setLeftOffset(minimumValueForLength(style()->left(), constra iningRect.width()));
636 constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft);
637 }
638
639 if (!style()->right().isAuto() && !skipRight) {
640 constraints.setRightOffset(minimumValueForLength(style()->right(), const rainingRect.width()));
641 constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeRight);
642 }
643
644 bool skipBottom = false;
645 // FIXME(ostap): Exclude top or bottom edge offset depending on the writing mode when related
646 // sections are fixed in spec: http://lists.w3.org/Archives/Public/www-style /2014May/0286.html
647 LayoutUnit verticalOffsets = constraints.topOffset() + constraints.bottomOff set();
648 if (!style()->top().isAuto() && !style()->bottom().isAuto()) {
649 if (verticalOffsets > containerContentRect.height()
650 || verticalOffsets + containerContentRect.height() > constrainingRec t.height()) {
651 skipBottom = true;
652 }
653 }
654
655 if (!style()->top().isAuto()) {
656 constraints.setTopOffset(minimumValueForLength(style()->top(), constrain ingRect.height()));
657 constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop);
658 }
659
660 if (!style()->bottom().isAuto() && !skipBottom) {
661 constraints.setBottomOffset(minimumValueForLength(style()->bottom(), con strainingRect.height()));
662 constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeBottom);
663 }
664 }
665
666 static inline LayoutBox* findScrollAncestor(const Node* startNode)
667 {
668 ASSERT(startNode->layoutObject());
669 LayoutBox* curBox = startNode->layoutObject()->containingBlock();
670
671 // Scrolling propagates along the containing block chain.
672 while (curBox && !curBox->isLayoutView()) {
673 if (curBox->hasOverflowClip())
674 return curBox;
675 curBox = curBox->containingBlock();
676 }
677
678 return nullptr;
679 }
680
681 LayoutRect LayoutBoxModelObject::computeStickyConstrainingRect() const
chrishtr 2015/10/06 17:08:33 Is this part of implementing the 6-step algorithm
flackr 2015/10/07 20:38:12 No, this rectangle is the "viewport" used to deter
682 {
683 LayoutRect constrainingRect;
684
685 ASSERT(hasLayer());
686 LayoutBox* enclosingClippingBox = findScrollAncestor(node());
687 if (enclosingClippingBox) {
688 LayoutRect clipRect = enclosingClippingBox->overflowClipRect(LayoutPoint ());
689 clipRect.move(enclosingClippingBox->paddingLeft(), enclosingClippingBox- >paddingTop());
690 clipRect.contract(LayoutSize(enclosingClippingBox->paddingLeft() + enclo singClippingBox->paddingRight(),
691 enclosingClippingBox->paddingTop() + enclosingClippingBox->paddingBo ttom()));
692 constrainingRect = LayoutRect(enclosingClippingBox->localToContainerQuad (FloatRect(clipRect), view()).boundingBox());
693 } else {
694 constrainingRect = LayoutRect(view()->frameView()->visibleContentRect()) ;
695 }
696
697 return constrainingRect;
698 }
699
700 LayoutSize LayoutBoxModelObject::stickyPositionOffset() const
701 {
702 LayoutRect constrainingRect = computeStickyConstrainingRect();
703 StickyPositionViewportConstraints constraints;
704 computeStickyPositionConstraints(constraints, constrainingRect);
705
706 // The sticky offset is physical, so we can just return the delta computed i n absolute coords (though it may be wrong with transforms).
707 return LayoutSize(constraints.computeStickyOffset(constrainingRect));
708 }
709
586 LayoutPoint LayoutBoxModelObject::adjustedPositionRelativeToOffsetParent(const L ayoutPoint& startPoint) const 710 LayoutPoint LayoutBoxModelObject::adjustedPositionRelativeToOffsetParent(const L ayoutPoint& startPoint) const
587 { 711 {
588 // If the element is the HTML body element or doesn't have a parent 712 // If the element is the HTML body element or doesn't have a parent
589 // return 0 and stop this algorithm. 713 // return 0 and stop this algorithm.
590 if (isBody() || !parent()) 714 if (isBody() || !parent())
591 return LayoutPoint(); 715 return LayoutPoint();
592 716
593 LayoutPoint referencePoint = startPoint; 717 LayoutPoint referencePoint = startPoint;
594 referencePoint.move(parent()->columnOffset(referencePoint)); 718 referencePoint.move(parent()->columnOffset(referencePoint));
595 719
596 // If the offsetParent of the element is null, or is the HTML body element, 720 // If the offsetParent of the element is null, or is the HTML body element,
597 // return the distance between the canvas origin and the left border edge 721 // return the distance between the canvas origin and the left border edge
598 // of the element and stop this algorithm. 722 // of the element and stop this algorithm.
599 Element* element = offsetParent(); 723 Element* element = offsetParent();
600 if (!element) 724 if (!element)
601 return referencePoint; 725 return referencePoint;
602 726
603 if (const LayoutBoxModelObject* offsetParent = element->layoutBoxModelObject ()) { 727 if (const LayoutBoxModelObject* offsetParent = element->layoutBoxModelObject ()) {
604 if (offsetParent->isBox() && !offsetParent->isBody()) 728 if (offsetParent->isBox() && !offsetParent->isBody())
605 referencePoint.move(-toLayoutBox(offsetParent)->borderLeft(), -toLay outBox(offsetParent)->borderTop()); 729 referencePoint.move(-toLayoutBox(offsetParent)->borderLeft(), -toLay outBox(offsetParent)->borderTop());
606 if (!isOutOfFlowPositioned() || flowThreadContainingBlock()) { 730 if (!isOutOfFlowPositioned() || flowThreadContainingBlock()) {
607 if (isInFlowPositioned()) 731 if (isInFlowPositioned())
608 referencePoint.move(relativePositionOffset()); 732 referencePoint.move(offsetForInFlowPosition());
609 733
610 LayoutObject* current; 734 LayoutObject* current;
611 for (current = parent(); current != offsetParent && current->parent( ); current = current->parent()) { 735 for (current = parent(); current != offsetParent && current->parent( ); current = current->parent()) {
612 // FIXME: What are we supposed to do inside SVG content? 736 // FIXME: What are we supposed to do inside SVG content?
613 if (!isOutOfFlowPositioned()) { 737 if (!isOutOfFlowPositioned()) {
614 if (current->isBox() && !current->isTableRow()) 738 if (current->isBox() && !current->isTableRow())
615 referencePoint.moveBy(toLayoutBox(current)->topLeftLocat ion()); 739 referencePoint.moveBy(toLayoutBox(current)->topLeftLocat ion());
616 referencePoint.move(current->parent()->columnOffset(referenc ePoint)); 740 referencePoint.move(current->parent()->columnOffset(referenc ePoint));
617 } 741 }
618 } 742 }
619 743
620 if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent ->isPositioned()) 744 if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent ->isPositioned())
621 referencePoint.moveBy(toLayoutBox(offsetParent)->topLeftLocation ()); 745 referencePoint.moveBy(toLayoutBox(offsetParent)->topLeftLocation ());
622 } 746 }
623 } 747 }
624 748
625 return referencePoint; 749 return referencePoint;
626 } 750 }
627 751
628 LayoutSize LayoutBoxModelObject::offsetForInFlowPosition() const 752 LayoutSize LayoutBoxModelObject::offsetForInFlowPosition() const
629 { 753 {
630 return isRelPositioned() ? relativePositionOffset() : LayoutSize(); 754 if (isRelPositioned())
755 return relativePositionOffset();
756
757 if (isStickyPositioned())
758 return stickyPositionOffset();
759
760 return LayoutSize();
631 } 761 }
632 762
633 LayoutUnit LayoutBoxModelObject::offsetLeft() const 763 LayoutUnit LayoutBoxModelObject::offsetLeft() const
634 { 764 {
635 // Note that LayoutInline and LayoutBox override this to pass a different 765 // Note that LayoutInline and LayoutBox override this to pass a different
636 // startPoint to adjustedPositionRelativeToOffsetParent. 766 // startPoint to adjustedPositionRelativeToOffsetParent.
637 return adjustedPositionRelativeToOffsetParent(LayoutPoint()).x(); 767 return adjustedPositionRelativeToOffsetParent(LayoutPoint()).x();
638 } 768 }
639 769
640 LayoutUnit LayoutBoxModelObject::offsetTop() const 770 LayoutUnit LayoutBoxModelObject::offsetTop() const
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
942 const LayoutObject* LayoutBoxModelObject::pushMappingToContainer(const LayoutBox ModelObject* ancestorToStopAt, LayoutGeometryMap& geometryMap) const 1072 const LayoutObject* LayoutBoxModelObject::pushMappingToContainer(const LayoutBox ModelObject* ancestorToStopAt, LayoutGeometryMap& geometryMap) const
943 { 1073 {
944 ASSERT(ancestorToStopAt != this); 1074 ASSERT(ancestorToStopAt != this);
945 1075
946 bool ancestorSkipped; 1076 bool ancestorSkipped;
947 LayoutObject* container = this->container(ancestorToStopAt, &ancestorSkipped ); 1077 LayoutObject* container = this->container(ancestorToStopAt, &ancestorSkipped );
948 if (!container) 1078 if (!container)
949 return nullptr; 1079 return nullptr;
950 1080
951 bool isInline = isLayoutInline(); 1081 bool isInline = isLayoutInline();
952 bool isFixedPos = !isInline && style()->position() == FixedPosition; 1082 bool isViewportConstrained = !isInline && (style()->hasViewportConstrainedPo sition());
953 bool hasTransform = !isInline && hasLayer() && layer()->transform(); 1083 bool hasTransform = !isInline && hasLayer() && layer()->transform();
954 1084
955 LayoutSize adjustmentForSkippedAncestor; 1085 LayoutSize adjustmentForSkippedAncestor;
956 if (ancestorSkipped) { 1086 if (ancestorSkipped) {
957 // There can't be a transform between paintInvalidationContainer and anc estorToStopAt, because transforms create containers, so it should be safe 1087 // There can't be a transform between paintInvalidationContainer and anc estorToStopAt, because transforms create containers, so it should be safe
958 // to just subtract the delta between the ancestor and ancestorToStopAt. 1088 // to just subtract the delta between the ancestor and ancestorToStopAt.
959 adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorCont ainer(container); 1089 adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorCont ainer(container);
960 } 1090 }
961 1091
962 bool offsetDependsOnPoint = false; 1092 bool offsetDependsOnPoint = false;
963 LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), & offsetDependsOnPoint); 1093 LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), & offsetDependsOnPoint);
964 1094
965 bool preserve3D = container->style()->preserves3D() || style()->preserves3D( ); 1095 bool preserve3D = container->style()->preserves3D() || style()->preserves3D( );
966 if (shouldUseTransformFromContainer(container)) { 1096 if (shouldUseTransformFromContainer(container)) {
967 TransformationMatrix t; 1097 TransformationMatrix t;
968 getTransformFromContainer(container, containerOffset, t); 1098 getTransformFromContainer(container, containerOffset, t);
969 t.translateRight(adjustmentForSkippedAncestor.width().toFloat(), adjustm entForSkippedAncestor.height().toFloat()); 1099 t.translateRight(adjustmentForSkippedAncestor.width().toFloat(), adjustm entForSkippedAncestor.height().toFloat());
970 geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform); 1100 geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isViewportCo nstrained, hasTransform);
971 } else { 1101 } else {
972 containerOffset += adjustmentForSkippedAncestor; 1102 containerOffset += adjustmentForSkippedAncestor;
973 geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint , isFixedPos, hasTransform); 1103 geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint , isViewportConstrained, hasTransform);
974 } 1104 }
975 1105
976 return ancestorSkipped ? ancestorToStopAt : container; 1106 return ancestorSkipped ? ancestorToStopAt : container;
977 } 1107 }
978 1108
979 void LayoutBoxModelObject::moveChildTo(LayoutBoxModelObject* toBoxModelObject, L ayoutObject* child, LayoutObject* beforeChild, bool fullRemoveInsert) 1109 void LayoutBoxModelObject::moveChildTo(LayoutBoxModelObject* toBoxModelObject, L ayoutObject* child, LayoutObject* beforeChild, bool fullRemoveInsert)
980 { 1110 {
981 // We assume that callers have cleared their positioned objects list for chi ld moves (!fullRemoveInsert) so the 1111 // We assume that callers have cleared their positioned objects list for chi ld moves (!fullRemoveInsert) so the
982 // positioned layoutObject maps don't become stale. It would be too slow to do the map lookup on each call. 1112 // positioned layoutObject maps don't become stale. It would be too slow to do the map lookup on each call.
983 ASSERT(!fullRemoveInsert || !isLayoutBlock() || !toLayoutBlock(this)->hasPos itionedObjects()); 1113 ASSERT(!fullRemoveInsert || !isLayoutBlock() || !toLayoutBlock(this)->hasPos itionedObjects());
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1031 if (rootElementStyle->hasBackground()) 1161 if (rootElementStyle->hasBackground())
1032 return false; 1162 return false;
1033 1163
1034 if (node() != document().firstBodyElement()) 1164 if (node() != document().firstBodyElement())
1035 return false; 1165 return false;
1036 1166
1037 return true; 1167 return true;
1038 } 1168 }
1039 1169
1040 } // namespace blink 1170 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698