| OLD | NEW |
| 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 28 matching lines...) Expand all Loading... |
| 39 #include "core/paint/ObjectPaintInvalidator.h" | 39 #include "core/paint/ObjectPaintInvalidator.h" |
| 40 #include "core/paint/PaintLayer.h" | 40 #include "core/paint/PaintLayer.h" |
| 41 #include "core/style/ShadowList.h" | 41 #include "core/style/ShadowList.h" |
| 42 #include "platform/LengthFunctions.h" | 42 #include "platform/LengthFunctions.h" |
| 43 #include "platform/geometry/TransformState.h" | 43 #include "platform/geometry/TransformState.h" |
| 44 #include "platform/scroll/MainThreadScrollingReason.h" | 44 #include "platform/scroll/MainThreadScrollingReason.h" |
| 45 #include "wtf/PtrUtil.h" | 45 #include "wtf/PtrUtil.h" |
| 46 | 46 |
| 47 namespace blink { | 47 namespace blink { |
| 48 | 48 |
| 49 namespace { |
| 50 inline bool isOutOfFlowPositionedWithImplicitHeight( |
| 51 const LayoutBoxModelObject* child) { |
| 52 return child->isOutOfFlowPositioned() && |
| 53 !child->style()->logicalTop().isAuto() && |
| 54 !child->style()->logicalBottom().isAuto(); |
| 55 } |
| 56 |
| 57 StickyPositionScrollingConstraints* stickyConstraintsForLayoutObject( |
| 58 const LayoutBoxModelObject* o) { |
| 59 if (!o || !o->layer()->ancestorOverflowLayer()) |
| 60 return nullptr; |
| 61 |
| 62 PaintLayerScrollableArea* scrollableArea = |
| 63 o->layer()->ancestorOverflowLayer()->getScrollableArea(); |
| 64 auto it = scrollableArea->stickyConstraintsMap().find(o->layer()); |
| 65 if (it == scrollableArea->stickyConstraintsMap().end()) |
| 66 return nullptr; |
| 67 |
| 68 return &it->value; |
| 69 } |
| 70 } // namespace |
| 71 |
| 49 class FloatStateForStyleChange { | 72 class FloatStateForStyleChange { |
| 50 public: | 73 public: |
| 51 static void setWasFloating(LayoutBoxModelObject* boxModelObject, | 74 static void setWasFloating(LayoutBoxModelObject* boxModelObject, |
| 52 bool wasFloating) { | 75 bool wasFloating) { |
| 53 s_wasFloating = wasFloating; | 76 s_wasFloating = wasFloating; |
| 54 s_boxModelObject = boxModelObject; | 77 s_boxModelObject = boxModelObject; |
| 55 } | 78 } |
| 56 | 79 |
| 57 static bool wasFloating(LayoutBoxModelObject* boxModelObject) { | 80 static bool wasFloating(LayoutBoxModelObject* boxModelObject) { |
| 58 ASSERT(boxModelObject == s_boxModelObject); | 81 ASSERT(boxModelObject == s_boxModelObject); |
| (...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 655 } | 678 } |
| 656 | 679 |
| 657 void LayoutBoxModelObject::updateFromStyle() { | 680 void LayoutBoxModelObject::updateFromStyle() { |
| 658 const ComputedStyle& styleToUse = styleRef(); | 681 const ComputedStyle& styleToUse = styleRef(); |
| 659 setHasBoxDecorationBackground(styleToUse.hasBoxDecorationBackground()); | 682 setHasBoxDecorationBackground(styleToUse.hasBoxDecorationBackground()); |
| 660 setInline(styleToUse.isDisplayInlineType()); | 683 setInline(styleToUse.isDisplayInlineType()); |
| 661 setPositionState(styleToUse.position()); | 684 setPositionState(styleToUse.position()); |
| 662 setHorizontalWritingMode(styleToUse.isHorizontalWritingMode()); | 685 setHorizontalWritingMode(styleToUse.isHorizontalWritingMode()); |
| 663 } | 686 } |
| 664 | 687 |
| 665 static inline bool isOutOfFlowPositionedWithImplicitHeight( | |
| 666 const LayoutBoxModelObject* child) { | |
| 667 return child->isOutOfFlowPositioned() && | |
| 668 !child->style()->logicalTop().isAuto() && | |
| 669 !child->style()->logicalBottom().isAuto(); | |
| 670 } | |
| 671 | |
| 672 LayoutBlock* LayoutBoxModelObject::containingBlockForAutoHeightDetection( | 688 LayoutBlock* LayoutBoxModelObject::containingBlockForAutoHeightDetection( |
| 673 Length logicalHeight) const { | 689 Length logicalHeight) const { |
| 674 // For percentage heights: The percentage is calculated with respect to the | 690 // For percentage heights: The percentage is calculated with respect to the |
| 675 // height of the generated box's containing block. If the height of the | 691 // height of the generated box's containing block. If the height of the |
| 676 // containing block is not specified explicitly (i.e., it depends on content | 692 // containing block is not specified explicitly (i.e., it depends on content |
| 677 // height), and this element is not absolutely positioned, the used height is | 693 // height), and this element is not absolutely positioned, the used height is |
| 678 // calculated as if 'auto' was specified. | 694 // calculated as if 'auto' was specified. |
| 679 if (!logicalHeight.isPercentOrCalc() || isOutOfFlowPositioned()) | 695 if (!logicalHeight.isPercentOrCalc() || isOutOfFlowPositioned()) |
| 680 return nullptr; | 696 return nullptr; |
| 681 | 697 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 778 (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight() || | 794 (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight() || |
| 779 !style()->bottom().isPercentOrCalc() || | 795 !style()->bottom().isPercentOrCalc() || |
| 780 containingBlock->stretchesToViewport())) | 796 containingBlock->stretchesToViewport())) |
| 781 offset.expand( | 797 offset.expand( |
| 782 LayoutUnit(), | 798 LayoutUnit(), |
| 783 -valueForLength(style()->bottom(), containingBlock->availableHeight())); | 799 -valueForLength(style()->bottom(), containingBlock->availableHeight())); |
| 784 | 800 |
| 785 return offset; | 801 return offset; |
| 786 } | 802 } |
| 787 | 803 |
| 804 // Inclusive of |from|, exclusive of |to|. |
| 805 static LayoutBoxModelObject* findFirstStickyBetween(LayoutObject* from, |
| 806 LayoutObject* to) { |
| 807 LayoutObject* maybeStickyAncestor = from; |
| 808 while (maybeStickyAncestor && maybeStickyAncestor != to) { |
| 809 if (maybeStickyAncestor->isStickyPositioned()) { |
| 810 return toLayoutBoxModelObject(maybeStickyAncestor); |
| 811 } |
| 812 maybeStickyAncestor = |
| 813 maybeStickyAncestor->isLayoutInline() |
| 814 ? maybeStickyAncestor->containingBlock() |
| 815 : toLayoutBox(maybeStickyAncestor)->locationContainer(); |
| 816 } |
| 817 |
| 818 return nullptr; |
| 819 } |
| 820 |
| 788 void LayoutBoxModelObject::updateStickyPositionConstraints() const { | 821 void LayoutBoxModelObject::updateStickyPositionConstraints() const { |
| 789 const FloatSize constrainingSize = computeStickyConstrainingRect().size(); | 822 const FloatSize constrainingSize = computeStickyConstrainingRect().size(); |
| 790 | 823 |
| 791 PaintLayerScrollableArea* scrollableArea = | 824 PaintLayerScrollableArea* scrollableArea = |
| 792 layer()->ancestorOverflowLayer()->getScrollableArea(); | 825 layer()->ancestorOverflowLayer()->getScrollableArea(); |
| 793 StickyPositionScrollingConstraints constraints; | 826 StickyPositionScrollingConstraints constraints; |
| 794 FloatSize skippedContainersOffset; | 827 FloatSize skippedContainersOffset; |
| 795 LayoutBlock* containingBlock = this->containingBlock(); | 828 LayoutBlock* containingBlock = this->containingBlock(); |
| 796 // The location container for boxes is not always the containing block. | 829 // The location container for boxes is not always the containing block. |
| 797 LayoutBox* locationContainer = isLayoutInline() | 830 LayoutObject* locationContainer = |
| 798 ? containingBlock | 831 isLayoutInline() ? container() : toLayoutBox(this)->locationContainer(); |
| 799 : toLayoutBox(this)->locationContainer(); | |
| 800 // Skip anonymous containing blocks. | 832 // Skip anonymous containing blocks. |
| 801 while (containingBlock->isAnonymous()) { | 833 while (containingBlock->isAnonymous()) { |
| 802 containingBlock = containingBlock->containingBlock(); | 834 containingBlock = containingBlock->containingBlock(); |
| 803 } | 835 } |
| 804 MapCoordinatesFlags flags = 0; | 836 MapCoordinatesFlags flags = IgnoreStickyOffset; |
| 805 skippedContainersOffset = | 837 skippedContainersOffset = |
| 806 toFloatSize(locationContainer | 838 toFloatSize(locationContainer |
| 807 ->localToAncestorQuadWithoutTransforms( | 839 ->localToAncestorQuadWithoutTransforms( |
| 808 FloatQuad(), containingBlock, flags) | 840 FloatQuad(), containingBlock, flags) |
| 809 .boundingBox() | 841 .boundingBox() |
| 810 .location()); | 842 .location()); |
| 811 LayoutBox* scrollAncestor = | 843 LayoutBox* scrollAncestor = |
| 812 layer()->ancestorOverflowLayer()->isRootLayer() | 844 layer()->ancestorOverflowLayer()->isRootLayer() |
| 813 ? nullptr | 845 ? nullptr |
| 814 : toLayoutBox(layer()->ancestorOverflowLayer()->layoutObject()); | 846 : toLayoutBox(layer()->ancestorOverflowLayer()->layoutObject()); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 874 minimumValueForLength(containingBlock->style()->paddingLeft(), | 906 minimumValueForLength(containingBlock->style()->paddingLeft(), |
| 875 maxContainerWidth) + | 907 maxContainerWidth) + |
| 876 minimumValueForLength(style()->marginLeft(), maxWidth)); | 908 minimumValueForLength(style()->marginLeft(), maxWidth)); |
| 877 | 909 |
| 878 constraints.setScrollContainerRelativeContainingBlockRect( | 910 constraints.setScrollContainerRelativeContainingBlockRect( |
| 879 FloatRect(scrollContainerRelativeContainingBlockRect)); | 911 FloatRect(scrollContainerRelativeContainingBlockRect)); |
| 880 | 912 |
| 881 FloatRect stickyBoxRect = | 913 FloatRect stickyBoxRect = |
| 882 isLayoutInline() ? FloatRect(toLayoutInline(this)->linesBoundingBox()) | 914 isLayoutInline() ? FloatRect(toLayoutInline(this)->linesBoundingBox()) |
| 883 : FloatRect(toLayoutBox(this)->frameRect()); | 915 : FloatRect(toLayoutBox(this)->frameRect()); |
| 916 |
| 917 // If we have an anonymous container, then |skippedContainersOffset| above can |
| 918 // incorrectly exclude the scrollOffset if our non-anonymous containing block |
| 919 // is the direct child of the scrollAncestor. Add it back here. |
| 920 // TODO(smcgruer): I think this is not quite the right conditional check. |
| 921 // TODO(smcgruer): Refactor into the code above. |
| 922 if (locationContainer != scrollAncestor && |
| 923 containingBlock == scrollAncestor) { |
| 924 ScrollOffset scrollOffset( |
| 925 scrollAncestor |
| 926 ? toFloatSize(scrollAncestor->getScrollableArea()->scrollPosition()) |
| 927 : FloatSize()); |
| 928 stickyBoxRect.move(scrollOffset); |
| 929 } |
| 930 |
| 884 FloatRect flippedStickyBoxRect = stickyBoxRect; | 931 FloatRect flippedStickyBoxRect = stickyBoxRect; |
| 885 containingBlock->flipForWritingMode(flippedStickyBoxRect); | 932 containingBlock->flipForWritingMode(flippedStickyBoxRect); |
| 886 FloatPoint stickyLocation = | 933 FloatPoint stickyLocation = |
| 887 flippedStickyBoxRect.location() + skippedContainersOffset; | 934 flippedStickyBoxRect.location() + skippedContainersOffset; |
| 888 | 935 |
| 889 // The scrollContainerRelativePaddingBoxRect's position is the padding box so | 936 // The scrollContainerRelativePaddingBoxRect's position is the padding box so |
| 890 // we need to remove the border when finding the position of the sticky box | 937 // we need to remove the border when finding the position of the sticky box |
| 891 // within the scroll ancestor if the container is not our scroll ancestor. If | 938 // within the scroll ancestor if the container is not our scroll ancestor. If |
| 892 // the container is our scroll ancestor, we also need to remove the border | 939 // the container is our scroll ancestor, we also need to remove the border |
| 893 // box because we want the position from within the scroller border. | 940 // box because we want the position from within the scroller border. |
| 894 FloatSize containerBorderOffset(containingBlock->borderLeft(), | 941 FloatSize containerBorderOffset(containingBlock->borderLeft(), |
| 895 containingBlock->borderTop()); | 942 containingBlock->borderTop()); |
| 896 stickyLocation -= containerBorderOffset; | 943 stickyLocation -= containerBorderOffset; |
| 897 constraints.setScrollContainerRelativeStickyBoxRect( | 944 constraints.setScrollContainerRelativeStickyBoxRect( |
| 898 FloatRect(scrollContainerRelativePaddingBoxRect.location() + | 945 FloatRect(scrollContainerRelativePaddingBoxRect.location() + |
| 899 toFloatSize(stickyLocation), | 946 toFloatSize(stickyLocation), |
| 900 flippedStickyBoxRect.size())); | 947 flippedStickyBoxRect.size())); |
| 901 | 948 |
| 949 // To correctly compute the offsets, the constraints need to know about any |
| 950 // nested position:sticky elements between themselves and their |
| 951 // containingBlock, and between the containingBlock and their scrollAncestor. |
| 952 // |
| 953 // The respective search ranges are [container, containingBlock) and |
| 954 // [containingBlock, scrollAncestor). |
| 955 constraints.setNearestStickyElementShiftingStickyBox( |
| 956 findFirstStickyBetween(locationContainer, containingBlock)); |
| 957 // We cannot use |scrollAncestor| here as it disregards the root |
| 958 // ancestorOverflowLayer(), which we should include. |
| 959 LayoutObject* ancestorOverflowLayer = |
| 960 layer()->ancestorOverflowLayer()->layoutObject(); |
| 961 constraints.setNearestStickyElementShiftingContainingBlock( |
| 962 findFirstStickyBetween(containingBlock, ancestorOverflowLayer)); |
| 963 |
| 902 // We skip the right or top sticky offset if there is not enough space to | 964 // We skip the right or top sticky offset if there is not enough space to |
| 903 // honor both the left/right or top/bottom offsets. | 965 // honor both the left/right or top/bottom offsets. |
| 904 LayoutUnit horizontalOffsets = | 966 LayoutUnit horizontalOffsets = |
| 905 minimumValueForLength(style()->right(), | 967 minimumValueForLength(style()->right(), |
| 906 LayoutUnit(constrainingSize.width())) + | 968 LayoutUnit(constrainingSize.width())) + |
| 907 minimumValueForLength(style()->left(), | 969 minimumValueForLength(style()->left(), |
| 908 LayoutUnit(constrainingSize.width())); | 970 LayoutUnit(constrainingSize.width())); |
| 909 bool skipRight = false; | 971 bool skipRight = false; |
| 910 bool skipLeft = false; | 972 bool skipLeft = false; |
| 911 if (!style()->left().isAuto() && !style()->right().isAuto()) { | 973 if (!style()->left().isAuto() && !style()->right().isAuto()) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 980 -enclosingClippingBox->borderTop() + enclosingClippingBox->paddingTop()); | 1042 -enclosingClippingBox->borderTop() + enclosingClippingBox->paddingTop()); |
| 981 constrainingRect.contract( | 1043 constrainingRect.contract( |
| 982 FloatSize(enclosingClippingBox->paddingLeft() + | 1044 FloatSize(enclosingClippingBox->paddingLeft() + |
| 983 enclosingClippingBox->paddingRight(), | 1045 enclosingClippingBox->paddingRight(), |
| 984 enclosingClippingBox->paddingTop() + | 1046 enclosingClippingBox->paddingTop() + |
| 985 enclosingClippingBox->paddingBottom())); | 1047 enclosingClippingBox->paddingBottom())); |
| 986 return constrainingRect; | 1048 return constrainingRect; |
| 987 } | 1049 } |
| 988 | 1050 |
| 989 LayoutSize LayoutBoxModelObject::stickyPositionOffset() const { | 1051 LayoutSize LayoutBoxModelObject::stickyPositionOffset() const { |
| 990 const PaintLayer* ancestorOverflowLayer = layer()->ancestorOverflowLayer(); | 1052 StickyPositionScrollingConstraints* constraints = |
| 991 // TODO: Force compositing input update if we ask for offset before | 1053 stickyConstraintsForLayoutObject(this); |
| 992 // compositing inputs have been computed? | 1054 if (!constraints) |
| 993 if (!ancestorOverflowLayer) | |
| 994 return LayoutSize(); | 1055 return LayoutSize(); |
| 995 FloatRect constrainingRect = computeStickyConstrainingRect(); | 1056 |
| 996 PaintLayerScrollableArea* scrollableArea = | 1057 StickyPositionScrollingConstraints* toContainingBlockConstraints = |
| 997 ancestorOverflowLayer->getScrollableArea(); | 1058 stickyConstraintsForLayoutObject( |
| 1059 constraints->nearestStickyElementShiftingStickyBox()); |
| 1060 |
| 1061 StickyPositionScrollingConstraints* toViewportConstraints = |
| 1062 stickyConstraintsForLayoutObject( |
| 1063 constraints->nearestStickyElementShiftingContainingBlock()); |
| 998 | 1064 |
| 999 // The sticky offset is physical, so we can just return the delta computed in | 1065 // The sticky offset is physical, so we can just return the delta computed in |
| 1000 // absolute coords (though it may be wrong with transforms). | 1066 // absolute coords (though it may be wrong with transforms). |
| 1001 // TODO: Force compositing input update if we ask for offset with stale | 1067 FloatRect constrainingRect = computeStickyConstrainingRect(); |
| 1002 // compositing inputs. | 1068 return LayoutSize(constraints->computeStickyOffset( |
| 1003 if (!scrollableArea->stickyConstraintsMap().contains(layer())) | 1069 constrainingRect, toContainingBlockConstraints, toViewportConstraints)); |
| 1004 return LayoutSize(); | |
| 1005 return LayoutSize( | |
| 1006 scrollableArea->stickyConstraintsMap().get(layer()).computeStickyOffset( | |
| 1007 constrainingRect)); | |
| 1008 } | 1070 } |
| 1009 | 1071 |
| 1010 LayoutPoint LayoutBoxModelObject::adjustedPositionRelativeTo( | 1072 LayoutPoint LayoutBoxModelObject::adjustedPositionRelativeTo( |
| 1011 const LayoutPoint& startPoint, | 1073 const LayoutPoint& startPoint, |
| 1012 const Element* offsetParent) const { | 1074 const Element* offsetParent) const { |
| 1013 // If the element is the HTML body element or doesn't have a parent | 1075 // If the element is the HTML body element or doesn't have a parent |
| 1014 // return 0 and stop this algorithm. | 1076 // return 0 and stop this algorithm. |
| 1015 if (isBody() || !parent()) | 1077 if (isBody() || !parent()) |
| 1016 return LayoutPoint(); | 1078 return LayoutPoint(); |
| 1017 | 1079 |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1367 if (rootElementStyle->hasBackground()) | 1429 if (rootElementStyle->hasBackground()) |
| 1368 return false; | 1430 return false; |
| 1369 | 1431 |
| 1370 if (node() != document().firstBodyElement()) | 1432 if (node() != document().firstBodyElement()) |
| 1371 return false; | 1433 return false; |
| 1372 | 1434 |
| 1373 return true; | 1435 return true; |
| 1374 } | 1436 } |
| 1375 | 1437 |
| 1376 } // namespace blink | 1438 } // namespace blink |
| OLD | NEW |