1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /** 8 * compute sticky positioning, both during reflow and when the scrolling 9 * container scrolls 10 */ 11 12 #ifndef StickyScrollContainer_h 13 #define StickyScrollContainer_h 14 15 #include "nsPoint.h" 16 #include "nsRectAbsolute.h" 17 #include "nsTArray.h" 18 #include "nsIScrollPositionListener.h" 19 20 struct nsRect; 21 class nsIFrame; 22 class nsIScrollableFrame; 23 24 namespace mozilla { 25 26 class StickyScrollContainer final : public nsIScrollPositionListener { 27 public: 28 /** 29 * Find (and create if necessary) the StickyScrollContainer associated with 30 * the scroll container of the given frame, if a scroll container exists. 31 */ 32 static StickyScrollContainer* GetStickyScrollContainerForFrame( 33 nsIFrame* aFrame); 34 35 /** 36 * Find the StickyScrollContainer associated with the given scroll frame, 37 * if it exists. 38 */ 39 static StickyScrollContainer* GetStickyScrollContainerForScrollFrame( 40 nsIFrame* aScrollFrame); 41 42 /** 43 * aFrame may have moved into or out of a scroll frame's frame subtree. 44 */ 45 static void NotifyReparentedFrameAcrossScrollFrameBoundary( 46 nsIFrame* aFrame, nsIFrame* aOldParent); 47 AddFrame(nsIFrame * aFrame)48 void AddFrame(nsIFrame* aFrame) { mFrames.AppendElement(aFrame); } RemoveFrame(nsIFrame * aFrame)49 void RemoveFrame(nsIFrame* aFrame) { mFrames.RemoveElement(aFrame); } 50 ScrollFrame()51 nsIScrollableFrame* ScrollFrame() const { return mScrollFrame; } 52 53 // Compute the offsets for a sticky position element 54 static void ComputeStickyOffsets(nsIFrame* aFrame); 55 56 /** 57 * Compute the position of a sticky positioned frame, based on information 58 * stored in its properties along with our scroll frame and scroll position. 59 */ 60 nsPoint ComputePosition(nsIFrame* aFrame) const; 61 62 /** 63 * Compute where a frame should not scroll with the page, represented by the 64 * difference of two rectangles. 65 */ 66 void GetScrollRanges(nsIFrame* aFrame, nsRectAbsolute* aOuter, 67 nsRectAbsolute* aInner) const; 68 69 /** 70 * Compute and set the position of a frame and its following continuations. 71 */ 72 void PositionContinuations(nsIFrame* aFrame); 73 74 /** 75 * Compute and set the position of all sticky frames, given the current 76 * scroll position of the scroll frame. If not in reflow, aSubtreeRoot should 77 * be null; otherwise, overflow-area updates will be limited to not affect 78 * aSubtreeRoot or its ancestors. 79 */ 80 void UpdatePositions(nsPoint aScrollPosition, nsIFrame* aSubtreeRoot); 81 82 // nsIScrollPositionListener 83 virtual void ScrollPositionWillChange(nscoord aX, nscoord aY) override; 84 virtual void ScrollPositionDidChange(nscoord aX, nscoord aY) override; 85 86 ~StickyScrollContainer(); 87 GetFrames()88 const nsTArray<nsIFrame*>& GetFrames() const { return mFrames; } 89 90 /** 91 * Returns true if the frame is "stuck" in the y direction, ie it's acting 92 * like fixed position. aFrame should be in GetFrames(). 93 */ 94 bool IsStuckInYDirection(nsIFrame* aFrame) const; 95 96 private: 97 explicit StickyScrollContainer(nsIScrollableFrame* aScrollFrame); 98 99 /** 100 * Compute two rectangles that determine sticky positioning: |aStick|, based 101 * on the scroll container, and |aContain|, based on the containing block. 102 * Sticky positioning keeps the frame position (its upper-left corner) always 103 * within |aContain| and secondarily within |aStick|. 104 */ 105 void ComputeStickyLimits(nsIFrame* aFrame, nsRect* aStick, 106 nsRect* aContain) const; 107 108 nsIScrollableFrame* const mScrollFrame; 109 nsTArray<nsIFrame*> mFrames; 110 nsPoint mScrollPosition; 111 }; 112 113 } // namespace mozilla 114 115 #endif /* StickyScrollContainer_h */ 116