// Copyright 2016 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_STICKY_POSITION_SCROLLING_CONSTRAINTS_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_STICKY_POSITION_SCROLLING_CONSTRAINTS_H_ #include <optional> #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h" #include "third_party/blink/renderer/platform/geometry/layout_unit.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/member.h" namespace blink { class LayoutBoxModelObject; class PaintLayer; // Encapsulates the constraint information for a position: sticky element and // does calculation of the sticky offset for a given overflow clip rectangle. // // To avoid slowing down scrolling we cannot make the offset calculation a // layout-inducing event. Instead constraint information is cached during layout // and used as the scroll position changes to determine the current offset. In // most cases the only information that is needed is the sticky element's layout // rectangle and its containing block rectangle (both respective to the nearest // ancestor scroller which the element is sticking to), and the set of sticky // edge constraints (i.e. the distance from each edge the element should stick). // // For a given (non-cached) overflow clip rectangle, calculating the current // offset in most cases just requires sliding the (cached) sticky element // rectangle until it satisfies the (cached) sticky edge constraints for the // overflow clip rectangle, whilst not letting the sticky element rectangle // escape its (cached) containing block rect. For example, consider the // following situation (where positions are relative to the scroll container): // // +---------------------+ <-- Containing Block (150x70 at 10,0) // | +-----------------+ | // | | top: 50px; |<-- Sticky Box (130x10 at 20,0) // | +-----------------+ | // | | // +-------------------------+ <-- Overflow Clip Rectangle (170x60 at 0,50) // | | | | // | | | | // | +---------------------+ | // | | // | | // | | // +-------------------------+ // // Here the cached sticky box would be moved downwards to try and be at position // (20,100) - 50 pixels down from the top of the clip rectangle. However doing // so would take it outside the cached containing block rectangle, so the final // sticky position would be capped to (20,20). // // Unfortunately this approach breaks down in the presence of nested sticky // elements, as the cached locations would be moved by ancestor sticky elements. // Consider: // // +------------------------+ <-- Outer sticky (top: 10px, 150x50 at 0,0) // | +------------------+ | // | | | <-- Inner sticky (top: 25px, 100x20 at 20,0) // | +------------------+ | // | | // +------------------------+ // // Assume the overflow clip rectangle is centered perfectly over the outer // sticky. We would then want to move the outer sticky element down by 10 // pixels, and the inner sticky element down by only 15 pixels - because it is // already being shifted by its ancestor. To correctly handle such situations we // apply more complicated logic which is explained in the implementation of // |ComputeStickyOffset|. struct CORE_EXPORT StickyPositionScrollingConstraints final : public GarbageCollected<StickyPositionScrollingConstraints> { … }; } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_STICKY_POSITION_SCROLLING_CONSTRAINTS_H_