Index: Source/core/layout/LayoutBoxModelObject.cpp |
diff --git a/Source/core/layout/LayoutBoxModelObject.cpp b/Source/core/layout/LayoutBoxModelObject.cpp |
index 1d7a2fb5b029473ab51240726de94e6fc2b0a991..66564d918698d9b315c89078945f1dca1b6b9e6d 100644 |
--- a/Source/core/layout/LayoutBoxModelObject.cpp |
+++ b/Source/core/layout/LayoutBoxModelObject.cpp |
@@ -569,6 +569,131 @@ LayoutSize LayoutBoxModelObject::relativePositionOffset() const |
return offset; |
} |
+void LayoutBoxModelObject::computeStickyPositionConstraints(StickyPositionViewportConstraints& constraints, const LayoutRect& constrainingRect) const |
+{ |
+ LayoutBlock* containingBlock = this->containingBlock(); |
+ |
+ LayoutRect containerContentRect = containingBlock->contentBoxRect(); |
+ LayoutUnit maxWidth = containingBlock->availableLogicalWidth(); |
+ |
+ // Sticky positioned element ignore any override logical width on the containing block (as they don't call |
+ // containingBlockLogicalWidthForContent). It's unclear whether this is totally fine. |
+ // Compute the container-relative area within which the sticky element is allowed to move. |
+ containerContentRect.contractEdges( |
+ minimumValueForLength(style()->marginTop(), maxWidth), |
+ minimumValueForLength(style()->marginRight(), maxWidth), |
+ minimumValueForLength(style()->marginBottom(), maxWidth), |
+ minimumValueForLength(style()->marginLeft(), maxWidth)); |
+ |
+ // Map to the view to avoid including page scale factor. |
+ constraints.setAbsoluteContainingBlockRect(LayoutRect(containingBlock->localToContainerQuad(FloatRect(containerContentRect), view()).boundingBox())); |
+ |
+ LayoutRect stickyBoxRect = frameRectForStickyPositioning(); |
+ LayoutRect flippedStickyBoxRect = stickyBoxRect; |
+ containingBlock->flipForWritingMode(flippedStickyBoxRect); |
+ LayoutPoint stickyLocation = flippedStickyBoxRect.location(); |
+ |
+ // FIXME: sucks to call localToAbsolute again, but we can't just offset from the previously computed rect if there are transforms. |
+ // Map to the view to avoid including page scale factor. |
+ LayoutRect absContainerFrame = LayoutRect(containingBlock->localToContainerQuad(FloatRect(FloatPoint(), FloatSize(containingBlock->size())), view()).boundingBox()); |
+ |
+ if (containingBlock->hasOverflowClip()) { |
+ LayoutSize scrollOffset(containingBlock->layer()->scrollableArea()->adjustedScrollOffset()); |
+ stickyLocation -= scrollOffset; |
+ } |
+ |
+ // We can't call localToAbsolute on |this| because that will recur. FIXME: For now, assume that |this| is not transformed. |
+ 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
|
+ constraints.setAbsoluteStickyBoxRect(absoluteStickyBoxRect); |
+ |
+ LayoutUnit horizontalOffsets = constraints.rightOffset() + constraints.leftOffset(); |
+ bool skipRight = false; |
+ bool skipLeft = false; |
+ if (!style()->left().isAuto() && !style()->right().isAuto()) { |
+ if (horizontalOffsets > containerContentRect.width() |
+ || horizontalOffsets + containerContentRect.width() > constrainingRect.width()) { |
+ skipRight = style()->isLeftToRightDirection(); |
+ skipLeft = !skipRight; |
+ } |
+ } |
+ |
+ if (!style()->left().isAuto() && !skipLeft) { |
+ constraints.setLeftOffset(minimumValueForLength(style()->left(), constrainingRect.width())); |
+ constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft); |
+ } |
+ |
+ if (!style()->right().isAuto() && !skipRight) { |
+ constraints.setRightOffset(minimumValueForLength(style()->right(), constrainingRect.width())); |
+ constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeRight); |
+ } |
+ |
+ bool skipBottom = false; |
+ // FIXME(ostap): Exclude top or bottom edge offset depending on the writing mode when related |
+ // sections are fixed in spec: http://lists.w3.org/Archives/Public/www-style/2014May/0286.html |
+ LayoutUnit verticalOffsets = constraints.topOffset() + constraints.bottomOffset(); |
+ if (!style()->top().isAuto() && !style()->bottom().isAuto()) { |
+ if (verticalOffsets > containerContentRect.height() |
+ || verticalOffsets + containerContentRect.height() > constrainingRect.height()) { |
+ skipBottom = true; |
+ } |
+ } |
+ |
+ if (!style()->top().isAuto()) { |
+ constraints.setTopOffset(minimumValueForLength(style()->top(), constrainingRect.height())); |
+ constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop); |
+ } |
+ |
+ if (!style()->bottom().isAuto() && !skipBottom) { |
+ constraints.setBottomOffset(minimumValueForLength(style()->bottom(), constrainingRect.height())); |
+ constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeBottom); |
+ } |
+} |
+ |
+static inline LayoutBox* findScrollAncestor(const Node* startNode) |
+{ |
+ ASSERT(startNode->layoutObject()); |
+ LayoutBox* curBox = startNode->layoutObject()->containingBlock(); |
+ |
+ // Scrolling propagates along the containing block chain. |
+ while (curBox && !curBox->isLayoutView()) { |
+ if (curBox->hasOverflowClip()) |
+ return curBox; |
+ curBox = curBox->containingBlock(); |
+ } |
+ |
+ return nullptr; |
+} |
+ |
+LayoutRect LayoutBoxModelObject::computeStickyConstrainingRect() const |
+{ |
+ LayoutRect constrainingRect; |
+ |
+ ASSERT(hasLayer()); |
+ LayoutBox* enclosingClippingBox = findScrollAncestor(node()); |
+ if (enclosingClippingBox) { |
+ LayoutRect clipRect = enclosingClippingBox->overflowClipRect(LayoutPoint()); |
+ clipRect.move(enclosingClippingBox->paddingLeft(), enclosingClippingBox->paddingTop()); |
+ clipRect.contract(LayoutSize(enclosingClippingBox->paddingLeft() + enclosingClippingBox->paddingRight(), |
+ enclosingClippingBox->paddingTop() + enclosingClippingBox->paddingBottom())); |
+ 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
|
+ } else { |
+ LayoutRect viewportRect(view()->frameView()->visibleContentRect()); |
+ constrainingRect = viewportRect; |
+ } |
+ |
+ return constrainingRect; |
+} |
+ |
+LayoutSize LayoutBoxModelObject::stickyPositionOffset() const |
+{ |
+ LayoutRect constrainingRect = computeStickyConstrainingRect(); |
+ StickyPositionViewportConstraints constraints; |
+ computeStickyPositionConstraints(constraints, constrainingRect); |
+ |
+ // The sticky offset is physical, so we can just return the delta computed in absolute coords (though it may be wrong with transforms). |
+ return LayoutSize(constraints.computeStickyOffset(constrainingRect)); |
+} |
+ |
LayoutPoint LayoutBoxModelObject::adjustedPositionRelativeToOffsetParent(const LayoutPoint& startPoint) const |
{ |
// If the element is the HTML body element or doesn't have a parent |
@@ -591,7 +716,7 @@ LayoutPoint LayoutBoxModelObject::adjustedPositionRelativeToOffsetParent(const L |
referencePoint.move(-toLayoutBox(offsetParent)->borderLeft(), -toLayoutBox(offsetParent)->borderTop()); |
if (!isOutOfFlowPositioned() || flowThreadContainingBlock()) { |
if (isInFlowPositioned()) |
- referencePoint.move(relativePositionOffset()); |
+ referencePoint.move(offsetForInFlowPosition()); |
LayoutObject* current; |
for (current = parent(); current != offsetParent && current->parent(); current = current->parent()) { |
@@ -613,7 +738,13 @@ LayoutPoint LayoutBoxModelObject::adjustedPositionRelativeToOffsetParent(const L |
LayoutSize LayoutBoxModelObject::offsetForInFlowPosition() const |
{ |
- return isRelPositioned() ? relativePositionOffset() : LayoutSize(); |
+ if (isRelPositioned()) |
+ return relativePositionOffset(); |
+ |
+ if (isStickyPositioned()) |
+ return stickyPositionOffset(); |
+ |
+ return LayoutSize(); |
} |
LayoutUnit LayoutBoxModelObject::offsetLeft() const |
@@ -935,7 +1066,7 @@ const LayoutObject* LayoutBoxModelObject::pushMappingToContainer(const LayoutBox |
return nullptr; |
bool isInline = isLayoutInline(); |
- bool isFixedPos = !isInline && style()->position() == FixedPosition; |
+ bool isViewportConstrained = !isInline && (style()->hasViewportConstrainedPosition()); |
bool hasTransform = !isInline && hasLayer() && layer()->transform(); |
LayoutSize adjustmentForSkippedAncestor; |
@@ -953,10 +1084,10 @@ const LayoutObject* LayoutBoxModelObject::pushMappingToContainer(const LayoutBox |
TransformationMatrix t; |
getTransformFromContainer(container, containerOffset, t); |
t.translateRight(adjustmentForSkippedAncestor.width().toFloat(), adjustmentForSkippedAncestor.height().toFloat()); |
- geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform); |
+ geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isViewportConstrained, hasTransform); |
} else { |
containerOffset += adjustmentForSkippedAncestor; |
- geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform); |
+ geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint, isViewportConstrained, hasTransform); |
} |
return ancestorSkipped ? ancestorToStopAt : container; |