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