Chromium Code Reviews| 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() || !o->layer()->ancestorOverflowLayer()) | |
|
flackr
2017/02/02 18:18:11
Are all of these checks necessary? If we have a st
smcgruer
2017/02/02 20:21:27
I can switch them to DCHECKS, if that makes more s
flackr
2017/02/02 23:31:15
No need to DCHECK if it will crash on failure tryi
smcgruer
2017/02/07 19:05:26
Did some digging. ancestorOverflowLayer() can be n
| |
| 60 return nullptr; | |
| 61 | |
| 62 PaintLayerScrollableArea* scrollableArea = | |
| 63 o->layer()->ancestorOverflowLayer()->getScrollableArea(); | |
| 64 if (!scrollableArea) | |
|
flackr
2017/02/02 18:18:11
scrollableArea should never be null afaik.
smcgruer
2017/02/02 20:21:27
Replaced with DCHECK then.
smcgruer
2017/02/07 19:05:26
Per advice above, removed since it'll just crash a
| |
| 65 return nullptr; | |
| 66 | |
| 67 auto it = scrollableArea->stickyConstraintsMap().find(o->layer()); | |
| 68 if (it == scrollableArea->stickyConstraintsMap().end()) | |
| 69 return nullptr; | |
| 70 | |
| 71 return &it->value; | |
| 72 } | |
| 73 } // namespace | |
| 74 | |
| 49 class FloatStateForStyleChange { | 75 class FloatStateForStyleChange { |
| 50 public: | 76 public: |
| 51 static void setWasFloating(LayoutBoxModelObject* boxModelObject, | 77 static void setWasFloating(LayoutBoxModelObject* boxModelObject, |
| 52 bool wasFloating) { | 78 bool wasFloating) { |
| 53 s_wasFloating = wasFloating; | 79 s_wasFloating = wasFloating; |
| 54 s_boxModelObject = boxModelObject; | 80 s_boxModelObject = boxModelObject; |
| 55 } | 81 } |
| 56 | 82 |
| 57 static bool wasFloating(LayoutBoxModelObject* boxModelObject) { | 83 static bool wasFloating(LayoutBoxModelObject* boxModelObject) { |
| 58 ASSERT(boxModelObject == s_boxModelObject); | 84 ASSERT(boxModelObject == s_boxModelObject); |
| (...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 641 } | 667 } |
| 642 | 668 |
| 643 void LayoutBoxModelObject::updateFromStyle() { | 669 void LayoutBoxModelObject::updateFromStyle() { |
| 644 const ComputedStyle& styleToUse = styleRef(); | 670 const ComputedStyle& styleToUse = styleRef(); |
| 645 setHasBoxDecorationBackground(styleToUse.hasBoxDecorationBackground()); | 671 setHasBoxDecorationBackground(styleToUse.hasBoxDecorationBackground()); |
| 646 setInline(styleToUse.isDisplayInlineType()); | 672 setInline(styleToUse.isDisplayInlineType()); |
| 647 setPositionState(styleToUse.position()); | 673 setPositionState(styleToUse.position()); |
| 648 setHorizontalWritingMode(styleToUse.isHorizontalWritingMode()); | 674 setHorizontalWritingMode(styleToUse.isHorizontalWritingMode()); |
| 649 } | 675 } |
| 650 | 676 |
| 651 static inline bool isOutOfFlowPositionedWithImplicitHeight( | |
| 652 const LayoutBoxModelObject* child) { | |
| 653 return child->isOutOfFlowPositioned() && | |
| 654 !child->style()->logicalTop().isAuto() && | |
| 655 !child->style()->logicalBottom().isAuto(); | |
| 656 } | |
| 657 | |
| 658 LayoutBlock* LayoutBoxModelObject::containingBlockForAutoHeightDetection( | 677 LayoutBlock* LayoutBoxModelObject::containingBlockForAutoHeightDetection( |
| 659 Length logicalHeight) const { | 678 Length logicalHeight) const { |
| 660 // For percentage heights: The percentage is calculated with respect to the | 679 // For percentage heights: The percentage is calculated with respect to the |
| 661 // height of the generated box's containing block. If the height of the | 680 // height of the generated box's containing block. If the height of the |
| 662 // containing block is not specified explicitly (i.e., it depends on content | 681 // containing block is not specified explicitly (i.e., it depends on content |
| 663 // height), and this element is not absolutely positioned, the used height is | 682 // height), and this element is not absolutely positioned, the used height is |
| 664 // calculated as if 'auto' was specified. | 683 // calculated as if 'auto' was specified. |
| 665 if (!logicalHeight.isPercentOrCalc() || isOutOfFlowPositioned()) | 684 if (!logicalHeight.isPercentOrCalc() || isOutOfFlowPositioned()) |
| 666 return nullptr; | 685 return nullptr; |
| 667 | 686 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 780 FloatSize skippedContainersOffset; | 799 FloatSize skippedContainersOffset; |
| 781 LayoutBlock* containingBlock = this->containingBlock(); | 800 LayoutBlock* containingBlock = this->containingBlock(); |
| 782 // The location container for boxes is not always the containing block. | 801 // The location container for boxes is not always the containing block. |
| 783 LayoutBox* locationContainer = isLayoutInline() | 802 LayoutBox* locationContainer = isLayoutInline() |
| 784 ? containingBlock | 803 ? containingBlock |
| 785 : toLayoutBox(this)->locationContainer(); | 804 : toLayoutBox(this)->locationContainer(); |
| 786 // Skip anonymous containing blocks. | 805 // Skip anonymous containing blocks. |
| 787 while (containingBlock->isAnonymous()) { | 806 while (containingBlock->isAnonymous()) { |
| 788 containingBlock = containingBlock->containingBlock(); | 807 containingBlock = containingBlock->containingBlock(); |
| 789 } | 808 } |
| 790 MapCoordinatesFlags flags = 0; | 809 MapCoordinatesFlags flags = IgnoreStickyOffset; |
| 791 skippedContainersOffset = | 810 skippedContainersOffset = |
| 792 toFloatSize(locationContainer | 811 toFloatSize(locationContainer |
| 793 ->localToAncestorQuadWithoutTransforms( | 812 ->localToAncestorQuadWithoutTransforms( |
| 794 FloatQuad(), containingBlock, flags) | 813 FloatQuad(), containingBlock, flags) |
| 795 .boundingBox() | 814 .boundingBox() |
| 796 .location()); | 815 .location()); |
| 797 LayoutBox* scrollAncestor = | 816 LayoutBox* scrollAncestor = |
| 798 layer()->ancestorOverflowLayer()->isRootLayer() | 817 layer()->ancestorOverflowLayer()->isRootLayer() |
| 799 ? nullptr | 818 ? nullptr |
| 800 : toLayoutBox(layer()->ancestorOverflowLayer()->layoutObject()); | 819 : toLayoutBox(layer()->ancestorOverflowLayer()->layoutObject()); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 878 // the container is our scroll ancestor, we also need to remove the border | 897 // the container is our scroll ancestor, we also need to remove the border |
| 879 // box because we want the position from within the scroller border. | 898 // box because we want the position from within the scroller border. |
| 880 FloatSize containerBorderOffset(containingBlock->borderLeft(), | 899 FloatSize containerBorderOffset(containingBlock->borderLeft(), |
| 881 containingBlock->borderTop()); | 900 containingBlock->borderTop()); |
| 882 stickyLocation -= containerBorderOffset; | 901 stickyLocation -= containerBorderOffset; |
| 883 constraints.setScrollContainerRelativeStickyBoxRect( | 902 constraints.setScrollContainerRelativeStickyBoxRect( |
| 884 FloatRect(scrollContainerRelativePaddingBoxRect.location() + | 903 FloatRect(scrollContainerRelativePaddingBoxRect.location() + |
| 885 toFloatSize(stickyLocation), | 904 toFloatSize(stickyLocation), |
| 886 flippedStickyBoxRect.size())); | 905 flippedStickyBoxRect.size())); |
| 887 | 906 |
| 907 // To correctly compute the offsets, the constraints need to know about any | |
| 908 // nested position:sticky between themselves and their containingBlock, and | |
| 909 // between the containingBlock and their scrollAncestor. | |
| 910 // | |
| 911 // The respective search ranges are [container, containingBlock) and | |
| 912 // [containingBlock, scrollAncestor). | |
| 913 | |
| 914 // TODO(smcgruer): Fold these into the walks to find the containingBlock and | |
| 915 // scrollAncestor. | |
| 916 LayoutObject* maybeStickyAncestor = locationContainer; | |
| 917 while (maybeStickyAncestor && maybeStickyAncestor != containingBlock) { | |
| 918 if (maybeStickyAncestor->isStickyPositioned()) { | |
| 919 constraints.setNearestStickyElementShiftingStickyBox( | |
| 920 toLayoutBoxModelObject(maybeStickyAncestor)); | |
| 921 break; | |
| 922 } | |
| 923 maybeStickyAncestor = | |
| 924 maybeStickyAncestor->isLayoutInline() | |
| 925 ? maybeStickyAncestor->containingBlock() | |
| 926 : toLayoutBox(maybeStickyAncestor)->locationContainer(); | |
| 927 } | |
| 928 | |
| 929 // NOTE(smcgruer): We cannot use |scrollAncestor| here as it disregards the | |
| 930 // root ancestorOverflowLayer(), which we should include for the purposes of | |
| 931 // finding the nearest sticky element that shifts the containing block rect. | |
| 932 LayoutObject* ancestorOverflowLayer = | |
| 933 layer()->ancestorOverflowLayer()->layoutObject(); | |
| 934 maybeStickyAncestor = containingBlock; | |
| 935 while (maybeStickyAncestor && maybeStickyAncestor != ancestorOverflowLayer) { | |
| 936 if (maybeStickyAncestor->isStickyPositioned()) { | |
| 937 constraints.setNearestStickyElementShiftingContainingBlock( | |
| 938 toLayoutBoxModelObject(maybeStickyAncestor)); | |
| 939 break; | |
| 940 } | |
| 941 maybeStickyAncestor = | |
| 942 maybeStickyAncestor->isLayoutInline() | |
| 943 ? maybeStickyAncestor->containingBlock() | |
| 944 : toLayoutBox(maybeStickyAncestor)->locationContainer(); | |
| 945 } | |
| 946 | |
| 888 // We skip the right or top sticky offset if there is not enough space to | 947 // We skip the right or top sticky offset if there is not enough space to |
| 889 // honor both the left/right or top/bottom offsets. | 948 // honor both the left/right or top/bottom offsets. |
| 890 LayoutUnit horizontalOffsets = | 949 LayoutUnit horizontalOffsets = |
| 891 minimumValueForLength(style()->right(), | 950 minimumValueForLength(style()->right(), |
| 892 LayoutUnit(constrainingSize.width())) + | 951 LayoutUnit(constrainingSize.width())) + |
| 893 minimumValueForLength(style()->left(), | 952 minimumValueForLength(style()->left(), |
| 894 LayoutUnit(constrainingSize.width())); | 953 LayoutUnit(constrainingSize.width())); |
| 895 bool skipRight = false; | 954 bool skipRight = false; |
| 896 bool skipLeft = false; | 955 bool skipLeft = false; |
| 897 if (!style()->left().isAuto() && !style()->right().isAuto()) { | 956 if (!style()->left().isAuto() && !style()->right().isAuto()) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 966 -enclosingClippingBox->borderTop() + enclosingClippingBox->paddingTop()); | 1025 -enclosingClippingBox->borderTop() + enclosingClippingBox->paddingTop()); |
| 967 constrainingRect.contract( | 1026 constrainingRect.contract( |
| 968 FloatSize(enclosingClippingBox->paddingLeft() + | 1027 FloatSize(enclosingClippingBox->paddingLeft() + |
| 969 enclosingClippingBox->paddingRight(), | 1028 enclosingClippingBox->paddingRight(), |
| 970 enclosingClippingBox->paddingTop() + | 1029 enclosingClippingBox->paddingTop() + |
| 971 enclosingClippingBox->paddingBottom())); | 1030 enclosingClippingBox->paddingBottom())); |
| 972 return constrainingRect; | 1031 return constrainingRect; |
| 973 } | 1032 } |
| 974 | 1033 |
| 975 LayoutSize LayoutBoxModelObject::stickyPositionOffset() const { | 1034 LayoutSize LayoutBoxModelObject::stickyPositionOffset() const { |
| 976 const PaintLayer* ancestorOverflowLayer = layer()->ancestorOverflowLayer(); | 1035 StickyPositionScrollingConstraints* constraints = |
| 977 // TODO: Force compositing input update if we ask for offset before | 1036 stickyConstraintsForLayoutObject(this); |
| 978 // compositing inputs have been computed? | 1037 if (!constraints) |
| 979 if (!ancestorOverflowLayer) | |
| 980 return LayoutSize(); | 1038 return LayoutSize(); |
| 981 FloatRect constrainingRect = computeStickyConstrainingRect(); | 1039 |
| 982 PaintLayerScrollableArea* scrollableArea = | 1040 StickyPositionScrollingConstraints* toContainingBlockConstraints = |
| 983 ancestorOverflowLayer->getScrollableArea(); | 1041 stickyConstraintsForLayoutObject( |
| 1042 constraints->nearestStickyElementShiftingStickyBox()); | |
| 1043 | |
| 1044 StickyPositionScrollingConstraints* toViewportConstraints = | |
| 1045 stickyConstraintsForLayoutObject( | |
| 1046 constraints->nearestStickyElementShiftingContainingBlock()); | |
| 984 | 1047 |
| 985 // The sticky offset is physical, so we can just return the delta computed in | 1048 // The sticky offset is physical, so we can just return the delta computed in |
| 986 // absolute coords (though it may be wrong with transforms). | 1049 // absolute coords (though it may be wrong with transforms). |
| 987 // TODO: Force compositing input update if we ask for offset with stale | 1050 FloatRect constrainingRect = computeStickyConstrainingRect(); |
| 988 // compositing inputs. | 1051 return LayoutSize(constraints->computeStickyOffset( |
| 989 if (!scrollableArea->stickyConstraintsMap().contains(layer())) | 1052 constrainingRect, toContainingBlockConstraints, toViewportConstraints)); |
| 990 return LayoutSize(); | |
| 991 return LayoutSize( | |
| 992 scrollableArea->stickyConstraintsMap().get(layer()).computeStickyOffset( | |
| 993 constrainingRect)); | |
| 994 } | 1053 } |
| 995 | 1054 |
| 996 LayoutPoint LayoutBoxModelObject::adjustedPositionRelativeTo( | 1055 LayoutPoint LayoutBoxModelObject::adjustedPositionRelativeTo( |
| 997 const LayoutPoint& startPoint, | 1056 const LayoutPoint& startPoint, |
| 998 const Element* offsetParent) const { | 1057 const Element* offsetParent) const { |
| 999 // If the element is the HTML body element or doesn't have a parent | 1058 // If the element is the HTML body element or doesn't have a parent |
| 1000 // return 0 and stop this algorithm. | 1059 // return 0 and stop this algorithm. |
| 1001 if (isBody() || !parent()) | 1060 if (isBody() || !parent()) |
| 1002 return LayoutPoint(); | 1061 return LayoutPoint(); |
| 1003 | 1062 |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1352 if (rootElementStyle->hasBackground()) | 1411 if (rootElementStyle->hasBackground()) |
| 1353 return false; | 1412 return false; |
| 1354 | 1413 |
| 1355 if (node() != document().firstBodyElement()) | 1414 if (node() != document().firstBodyElement()) |
| 1356 return false; | 1415 return false; |
| 1357 | 1416 |
| 1358 return true; | 1417 return true; |
| 1359 } | 1418 } |
| 1360 | 1419 |
| 1361 } // namespace blink | 1420 } // namespace blink |
| OLD | NEW |