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

Side by Side Diff: 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: Fix style errors and remaining layout tests. Created 5 years, 3 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 551 matching lines...) Expand 10 before | Expand all | Expand 10 after
562 562
563 else if (!style()->bottom().isAuto() 563 else if (!style()->bottom().isAuto()
564 && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight() 564 && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight()
565 || !style()->bottom().hasPercent() 565 || !style()->bottom().hasPercent()
566 || containingBlock->stretchesToViewport())) 566 || containingBlock->stretchesToViewport()))
567 offset.expand(0, -valueForLength(style()->bottom(), containingBlock->ava ilableHeight())); 567 offset.expand(0, -valueForLength(style()->bottom(), containingBlock->ava ilableHeight()));
568 568
569 return offset; 569 return offset;
570 } 570 }
571 571
572 void LayoutBoxModelObject::computeStickyPositionConstraints(StickyPositionViewpo rtConstraints& constraints, const LayoutRect& constrainingRect) const
573 {
574 LayoutBlock* containingBlock = this->containingBlock();
575
576 LayoutRect containerContentRect = containingBlock->contentBoxRect();
577 LayoutUnit maxWidth = containingBlock->availableLogicalWidth();
578
579 // Sticky positioned element ignore any override logical width on the contai ning block (as they don't call
580 // containingBlockLogicalWidthForContent). It's unclear whether this is tota lly fine.
581 // Compute the container-relative area within which the sticky element is al lowed to move.
582 containerContentRect.contractEdges(
583 minimumValueForLength(style()->marginTop(), maxWidth),
584 minimumValueForLength(style()->marginRight(), maxWidth),
585 minimumValueForLength(style()->marginBottom(), maxWidth),
586 minimumValueForLength(style()->marginLeft(), maxWidth));
587
588 // Map to the view to avoid including page scale factor.
589 constraints.setAbsoluteContainingBlockRect(LayoutRect(containingBlock->local ToContainerQuad(FloatRect(containerContentRect), view()).boundingBox()));
590
591 LayoutRect stickyBoxRect = frameRectForStickyPositioning();
592 LayoutRect flippedStickyBoxRect = stickyBoxRect;
593 containingBlock->flipForWritingMode(flippedStickyBoxRect);
594 LayoutPoint stickyLocation = flippedStickyBoxRect.location();
595
596 // FIXME: sucks to call localToAbsolute again, but we can't just offset from the previously computed rect if there are transforms.
597 // Map to the view to avoid including page scale factor.
598 LayoutRect absContainerFrame = LayoutRect(containingBlock->localToContainerQ uad(FloatRect(FloatPoint(), FloatSize(containingBlock->size())), view()).boundin gBox());
599
600 if (containingBlock->hasOverflowClip()) {
601 LayoutSize scrollOffset(containingBlock->layer()->scrollableArea()->adju stedScrollOffset());
602 stickyLocation -= scrollOffset;
603 }
604
605 // We can't call localToAbsolute on |this| because that will recur. FIXME: F or now, assume that |this| is not transformed.
606 LayoutRect absoluteStickyBoxRect(LayoutPoint(absContainerFrame.location()) + stickyLocation, flippedStickyBoxRect.size());
chrishtr 2015/09/17 01:18:56 This is bad for performance. Do we really need to
flackr 2015/10/07 20:38:11 We need to save this rect because sticky objects o
607 constraints.setAbsoluteStickyBoxRect(absoluteStickyBoxRect);
608
609 LayoutUnit horizontalOffsets = constraints.rightOffset() + constraints.leftO ffset();
610 bool skipRight = false;
611 bool skipLeft = false;
612 if (!style()->left().isAuto() && !style()->right().isAuto()) {
613 if (horizontalOffsets > containerContentRect.width()
614 || horizontalOffsets + containerContentRect.width() > constrainingRe ct.width()) {
615 skipRight = style()->isLeftToRightDirection();
616 skipLeft = !skipRight;
617 }
618 }
619
620 if (!style()->left().isAuto() && !skipLeft) {
621 constraints.setLeftOffset(minimumValueForLength(style()->left(), constra iningRect.width()));
622 constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft);
623 }
624
625 if (!style()->right().isAuto() && !skipRight) {
626 constraints.setRightOffset(minimumValueForLength(style()->right(), const rainingRect.width()));
627 constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeRight);
628 }
629
630 bool skipBottom = false;
631 // FIXME(ostap): Exclude top or bottom edge offset depending on the writing mode when related
632 // sections are fixed in spec: http://lists.w3.org/Archives/Public/www-style /2014May/0286.html
633 LayoutUnit verticalOffsets = constraints.topOffset() + constraints.bottomOff set();
634 if (!style()->top().isAuto() && !style()->bottom().isAuto()) {
635 if (verticalOffsets > containerContentRect.height()
636 || verticalOffsets + containerContentRect.height() > constrainingRec t.height()) {
637 skipBottom = true;
638 }
639 }
640
641 if (!style()->top().isAuto()) {
642 constraints.setTopOffset(minimumValueForLength(style()->top(), constrain ingRect.height()));
643 constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop);
644 }
645
646 if (!style()->bottom().isAuto() && !skipBottom) {
647 constraints.setBottomOffset(minimumValueForLength(style()->bottom(), con strainingRect.height()));
648 constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeBottom);
649 }
650 }
651
652 static inline LayoutBox* findScrollAncestor(const Node* startNode)
653 {
654 ASSERT(startNode->layoutObject());
655 LayoutBox* curBox = startNode->layoutObject()->containingBlock();
656
657 // Scrolling propagates along the containing block chain.
658 while (curBox && !curBox->isLayoutView()) {
659 if (curBox->hasOverflowClip())
660 return curBox;
661 curBox = curBox->containingBlock();
662 }
663
664 return nullptr;
665 }
666
667 LayoutRect LayoutBoxModelObject::computeStickyConstrainingRect() const
668 {
669 LayoutRect constrainingRect;
670
671 ASSERT(hasLayer());
672 LayoutBox* enclosingClippingBox = findScrollAncestor(node());
673 if (enclosingClippingBox) {
674 LayoutRect clipRect = enclosingClippingBox->overflowClipRect(LayoutPoint ());
675 clipRect.move(enclosingClippingBox->paddingLeft(), enclosingClippingBox- >paddingTop());
676 clipRect.contract(LayoutSize(enclosingClippingBox->paddingLeft() + enclo singClippingBox->paddingRight(),
677 enclosingClippingBox->paddingTop() + enclosingClippingBox->paddingBo ttom()));
678 constrainingRect = LayoutRect(enclosingClippingBox->localToContainerQuad (FloatRect(clipRect), view()).boundingBox());
chrishtr 2015/09/17 01:18:56 Does clippedOverflowRectForPaintInvalidation do th
flackr 2015/10/07 20:38:11 Unless I'm not understanding / using this correctl
679 } else {
680 LayoutRect viewportRect(view()->frameView()->visibleContentRect());
681 constrainingRect = viewportRect;
682 }
683
684 return constrainingRect;
685 }
686
687 LayoutSize LayoutBoxModelObject::stickyPositionOffset() const
688 {
689 LayoutRect constrainingRect = computeStickyConstrainingRect();
690 StickyPositionViewportConstraints constraints;
691 computeStickyPositionConstraints(constraints, constrainingRect);
692
693 // The sticky offset is physical, so we can just return the delta computed i n absolute coords (though it may be wrong with transforms).
694 return LayoutSize(constraints.computeStickyOffset(constrainingRect));
695 }
696
572 LayoutPoint LayoutBoxModelObject::adjustedPositionRelativeToOffsetParent(const L ayoutPoint& startPoint) const 697 LayoutPoint LayoutBoxModelObject::adjustedPositionRelativeToOffsetParent(const L ayoutPoint& startPoint) const
573 { 698 {
574 // If the element is the HTML body element or doesn't have a parent 699 // If the element is the HTML body element or doesn't have a parent
575 // return 0 and stop this algorithm. 700 // return 0 and stop this algorithm.
576 if (isBody() || !parent()) 701 if (isBody() || !parent())
577 return LayoutPoint(); 702 return LayoutPoint();
578 703
579 LayoutPoint referencePoint = startPoint; 704 LayoutPoint referencePoint = startPoint;
580 referencePoint.move(parent()->columnOffset(referencePoint)); 705 referencePoint.move(parent()->columnOffset(referencePoint));
581 706
582 // If the offsetParent of the element is null, or is the HTML body element, 707 // If the offsetParent of the element is null, or is the HTML body element,
583 // return the distance between the canvas origin and the left border edge 708 // return the distance between the canvas origin and the left border edge
584 // of the element and stop this algorithm. 709 // of the element and stop this algorithm.
585 Element* element = offsetParent(); 710 Element* element = offsetParent();
586 if (!element) 711 if (!element)
587 return referencePoint; 712 return referencePoint;
588 713
589 if (const LayoutBoxModelObject* offsetParent = element->layoutBoxModelObject ()) { 714 if (const LayoutBoxModelObject* offsetParent = element->layoutBoxModelObject ()) {
590 if (offsetParent->isBox() && !offsetParent->isBody()) 715 if (offsetParent->isBox() && !offsetParent->isBody())
591 referencePoint.move(-toLayoutBox(offsetParent)->borderLeft(), -toLay outBox(offsetParent)->borderTop()); 716 referencePoint.move(-toLayoutBox(offsetParent)->borderLeft(), -toLay outBox(offsetParent)->borderTop());
592 if (!isOutOfFlowPositioned() || flowThreadContainingBlock()) { 717 if (!isOutOfFlowPositioned() || flowThreadContainingBlock()) {
593 if (isInFlowPositioned()) 718 if (isInFlowPositioned())
594 referencePoint.move(relativePositionOffset()); 719 referencePoint.move(offsetForInFlowPosition());
595 720
596 LayoutObject* current; 721 LayoutObject* current;
597 for (current = parent(); current != offsetParent && current->parent( ); current = current->parent()) { 722 for (current = parent(); current != offsetParent && current->parent( ); current = current->parent()) {
598 // FIXME: What are we supposed to do inside SVG content? 723 // FIXME: What are we supposed to do inside SVG content?
599 if (!isOutOfFlowPositioned()) { 724 if (!isOutOfFlowPositioned()) {
600 if (current->isBox() && !current->isTableRow()) 725 if (current->isBox() && !current->isTableRow())
601 referencePoint.moveBy(toLayoutBox(current)->topLeftLocat ion()); 726 referencePoint.moveBy(toLayoutBox(current)->topLeftLocat ion());
602 referencePoint.move(current->parent()->columnOffset(referenc ePoint)); 727 referencePoint.move(current->parent()->columnOffset(referenc ePoint));
603 } 728 }
604 } 729 }
605 730
606 if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent ->isPositioned()) 731 if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent ->isPositioned())
607 referencePoint.moveBy(toLayoutBox(offsetParent)->topLeftLocation ()); 732 referencePoint.moveBy(toLayoutBox(offsetParent)->topLeftLocation ());
608 } 733 }
609 } 734 }
610 735
611 return referencePoint; 736 return referencePoint;
612 } 737 }
613 738
614 LayoutSize LayoutBoxModelObject::offsetForInFlowPosition() const 739 LayoutSize LayoutBoxModelObject::offsetForInFlowPosition() const
615 { 740 {
616 return isRelPositioned() ? relativePositionOffset() : LayoutSize(); 741 if (isRelPositioned())
742 return relativePositionOffset();
743
744 if (isStickyPositioned())
745 return stickyPositionOffset();
746
747 return LayoutSize();
617 } 748 }
618 749
619 LayoutUnit LayoutBoxModelObject::offsetLeft() const 750 LayoutUnit LayoutBoxModelObject::offsetLeft() const
620 { 751 {
621 // Note that LayoutInline and LayoutBox override this to pass a different 752 // Note that LayoutInline and LayoutBox override this to pass a different
622 // startPoint to adjustedPositionRelativeToOffsetParent. 753 // startPoint to adjustedPositionRelativeToOffsetParent.
623 return adjustedPositionRelativeToOffsetParent(LayoutPoint()).x(); 754 return adjustedPositionRelativeToOffsetParent(LayoutPoint()).x();
624 } 755 }
625 756
626 LayoutUnit LayoutBoxModelObject::offsetTop() const 757 LayoutUnit LayoutBoxModelObject::offsetTop() const
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
928 const LayoutObject* LayoutBoxModelObject::pushMappingToContainer(const LayoutBox ModelObject* ancestorToStopAt, LayoutGeometryMap& geometryMap) const 1059 const LayoutObject* LayoutBoxModelObject::pushMappingToContainer(const LayoutBox ModelObject* ancestorToStopAt, LayoutGeometryMap& geometryMap) const
929 { 1060 {
930 ASSERT(ancestorToStopAt != this); 1061 ASSERT(ancestorToStopAt != this);
931 1062
932 bool ancestorSkipped; 1063 bool ancestorSkipped;
933 LayoutObject* container = this->container(ancestorToStopAt, &ancestorSkipped ); 1064 LayoutObject* container = this->container(ancestorToStopAt, &ancestorSkipped );
934 if (!container) 1065 if (!container)
935 return nullptr; 1066 return nullptr;
936 1067
937 bool isInline = isLayoutInline(); 1068 bool isInline = isLayoutInline();
938 bool isFixedPos = !isInline && style()->position() == FixedPosition; 1069 bool isViewportConstrained = !isInline && (style()->hasViewportConstrainedPo sition());
939 bool hasTransform = !isInline && hasLayer() && layer()->transform(); 1070 bool hasTransform = !isInline && hasLayer() && layer()->transform();
940 1071
941 LayoutSize adjustmentForSkippedAncestor; 1072 LayoutSize adjustmentForSkippedAncestor;
942 if (ancestorSkipped) { 1073 if (ancestorSkipped) {
943 // There can't be a transform between paintInvalidationContainer and anc estorToStopAt, because transforms create containers, so it should be safe 1074 // There can't be a transform between paintInvalidationContainer and anc estorToStopAt, because transforms create containers, so it should be safe
944 // to just subtract the delta between the ancestor and ancestorToStopAt. 1075 // to just subtract the delta between the ancestor and ancestorToStopAt.
945 adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorCont ainer(container); 1076 adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorCont ainer(container);
946 } 1077 }
947 1078
948 bool offsetDependsOnPoint = false; 1079 bool offsetDependsOnPoint = false;
949 LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), & offsetDependsOnPoint); 1080 LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), & offsetDependsOnPoint);
950 1081
951 bool preserve3D = container->style()->preserves3D() || style()->preserves3D( ); 1082 bool preserve3D = container->style()->preserves3D() || style()->preserves3D( );
952 if (shouldUseTransformFromContainer(container)) { 1083 if (shouldUseTransformFromContainer(container)) {
953 TransformationMatrix t; 1084 TransformationMatrix t;
954 getTransformFromContainer(container, containerOffset, t); 1085 getTransformFromContainer(container, containerOffset, t);
955 t.translateRight(adjustmentForSkippedAncestor.width().toFloat(), adjustm entForSkippedAncestor.height().toFloat()); 1086 t.translateRight(adjustmentForSkippedAncestor.width().toFloat(), adjustm entForSkippedAncestor.height().toFloat());
956 geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform); 1087 geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isViewportCo nstrained, hasTransform);
957 } else { 1088 } else {
958 containerOffset += adjustmentForSkippedAncestor; 1089 containerOffset += adjustmentForSkippedAncestor;
959 geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint , isFixedPos, hasTransform); 1090 geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint , isViewportConstrained, hasTransform);
960 } 1091 }
961 1092
962 return ancestorSkipped ? ancestorToStopAt : container; 1093 return ancestorSkipped ? ancestorToStopAt : container;
963 } 1094 }
964 1095
965 void LayoutBoxModelObject::moveChildTo(LayoutBoxModelObject* toBoxModelObject, L ayoutObject* child, LayoutObject* beforeChild, bool fullRemoveInsert) 1096 void LayoutBoxModelObject::moveChildTo(LayoutBoxModelObject* toBoxModelObject, L ayoutObject* child, LayoutObject* beforeChild, bool fullRemoveInsert)
966 { 1097 {
967 // We assume that callers have cleared their positioned objects list for chi ld moves (!fullRemoveInsert) so the 1098 // We assume that callers have cleared their positioned objects list for chi ld moves (!fullRemoveInsert) so the
968 // positioned layoutObject maps don't become stale. It would be too slow to do the map lookup on each call. 1099 // positioned layoutObject maps don't become stale. It would be too slow to do the map lookup on each call.
969 ASSERT(!fullRemoveInsert || !isLayoutBlock() || !toLayoutBlock(this)->hasPos itionedObjects()); 1100 ASSERT(!fullRemoveInsert || !isLayoutBlock() || !toLayoutBlock(this)->hasPos itionedObjects());
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1017 if (rootElementStyle->hasBackground()) 1148 if (rootElementStyle->hasBackground())
1018 return false; 1149 return false;
1019 1150
1020 if (node() != document().firstBodyElement()) 1151 if (node() != document().firstBodyElement())
1021 return false; 1152 return false;
1022 1153
1023 return true; 1154 return true;
1024 } 1155 }
1025 1156
1026 } // namespace blink 1157 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698