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  * code for managing absolutely positioned children of a rendering
9  * object that is a containing block for them
10  */
11 
12 #ifndef nsAbsoluteContainingBlock_h___
13 #define nsAbsoluteContainingBlock_h___
14 
15 #include "nsFrameList.h"
16 #include "nsIFrame.h"
17 #include "mozilla/TypedEnumBits.h"
18 
19 class nsContainerFrame;
20 class nsPresContext;
21 
22 /**
23  * This class contains the logic for being an absolute containing block.  This
24  * class is used within viewport frames (for frames representing content with
25  * fixed position) and blocks (for frames representing absolutely positioned
26  * content), since each set of frames is absolutely positioned with respect to
27  * its parent.
28  *
29  * There is no principal child list, just a named child list which contains
30  * the absolutely positioned frames (kAbsoluteList or kFixedList).
31  *
32  * All functions include as the first argument the frame that is delegating
33  * the request.
34  */
35 class nsAbsoluteContainingBlock {
36   using ReflowInput = mozilla::ReflowInput;
37 
38  public:
39   typedef nsIFrame::ChildListID ChildListID;
40 
nsAbsoluteContainingBlock(ChildListID aChildListID)41   explicit nsAbsoluteContainingBlock(ChildListID aChildListID)
42 #ifdef DEBUG
43       : mChildListID(aChildListID)
44 #endif
45   {
46     MOZ_ASSERT(mChildListID == nsIFrame::kAbsoluteList ||
47                    mChildListID == nsIFrame::kFixedList,
48                "should either represent position:fixed or absolute content");
49   }
50 
GetChildList()51   const nsFrameList& GetChildList() const { return mAbsoluteFrames; }
AppendChildList(nsTArray<nsIFrame::ChildList> * aLists,ChildListID aListID)52   void AppendChildList(nsTArray<nsIFrame::ChildList>* aLists,
53                        ChildListID aListID) const {
54     NS_ASSERTION(aListID == mChildListID, "wrong list ID");
55     GetChildList().AppendIfNonempty(aLists, aListID);
56   }
57 
58   void SetInitialChildList(nsIFrame* aDelegatingFrame, ChildListID aListID,
59                            nsFrameList& aChildList);
60   void AppendFrames(nsIFrame* aDelegatingFrame, ChildListID aListID,
61                     nsFrameList& aFrameList);
62   void InsertFrames(nsIFrame* aDelegatingFrame, ChildListID aListID,
63                     nsIFrame* aPrevFrame, nsFrameList& aFrameList);
64   void RemoveFrame(nsIFrame* aDelegatingFrame, ChildListID aListID,
65                    nsIFrame* aOldFrame);
66 
67   enum class AbsPosReflowFlags {
68     ConstrainHeight = 0x1,
69     CBWidthChanged = 0x2,
70     CBHeightChanged = 0x4,
71     CBWidthAndHeightChanged = CBWidthChanged | CBHeightChanged,
72     IsGridContainerCB = 0x8,
73   };
74 
75   /**
76    * Called by the delegating frame after it has done its reflow first. This
77    * function will reflow any absolutely positioned child frames that need to
78    * be reflowed, e.g., because the absolutely positioned child frame has
79    * 'auto' for an offset, or a percentage based width or height.
80    *
81    * @param aOverflowAreas, if non-null, is unioned with (in the local
82    * coordinate space) the overflow areas of the absolutely positioned
83    * children.
84    *
85    * @param aReflowStatus is assumed to be already-initialized, e.g. with the
86    * status of the delegating frame's main reflow. This function merges in the
87    * statuses of the absolutely positioned children's reflows.
88    *
89    * @param aFlags zero or more AbsPosReflowFlags
90    */
91   void Reflow(nsContainerFrame* aDelegatingFrame, nsPresContext* aPresContext,
92               const ReflowInput& aReflowInput, nsReflowStatus& aReflowStatus,
93               const nsRect& aContainingBlock, AbsPosReflowFlags aFlags,
94               mozilla::OverflowAreas* aOverflowAreas);
95 
96   using PostDestroyData = nsIFrame::PostDestroyData;
97   void DestroyFrames(nsIFrame* aDelegatingFrame, nsIFrame* aDestructRoot,
98                      PostDestroyData& aPostDestroyData);
99 
HasAbsoluteFrames()100   bool HasAbsoluteFrames() const { return mAbsoluteFrames.NotEmpty(); }
101 
102   /**
103    * Mark our size-dependent absolute frames with NS_FRAME_HAS_DIRTY_CHILDREN
104    * so that we'll make sure to reflow them.
105    */
106   void MarkSizeDependentFramesDirty();
107 
108   /**
109    * Mark all our absolute frames with NS_FRAME_IS_DIRTY.
110    */
111   void MarkAllFramesDirty();
112 
113  protected:
114   /**
115    * Returns true if the position of aFrame depends on the position of
116    * its placeholder or if the position or size of aFrame depends on a
117    * containing block dimension that changed.
118    */
119   bool FrameDependsOnContainer(nsIFrame* aFrame, bool aCBWidthChanged,
120                                bool aCBHeightChanged);
121 
122   /**
123    * After an abspos child's size is known, this method can be used to
124    * resolve size-dependent values in the ComputedLogicalOffsets on its
125    * reflow input. (This may involve resolving the inline dimension of
126    * aLogicalCBSize, too; hence, that variable is an in/outparam.)
127    *
128    * aKidSize, aMargin, aOffsets, and aLogicalCBSize are all expected to be
129    * represented in terms of the absolute containing block's writing-mode.
130    */
131   void ResolveSizeDependentOffsets(nsPresContext* aPresContext,
132                                    ReflowInput& aKidReflowInput,
133                                    const mozilla::LogicalSize& aKidSize,
134                                    const mozilla::LogicalMargin& aMargin,
135                                    mozilla::LogicalMargin* aOffsets,
136                                    mozilla::LogicalSize* aLogicalCBSize);
137 
138   /**
139    * For frames that have intrinsic block sizes, since we want to use the
140    * frame's actual instrinsic block-size, we don't compute margins in
141    * InitAbsoluteConstraints because the block-size isn't computed yet. This
142    * method computes the margins for them after layout.
143    * aMargin and aOffsets are both outparams (though we only touch aOffsets if
144    * the position is overconstrained)
145    */
146   void ResolveAutoMarginsAfterLayout(ReflowInput& aKidReflowInput,
147                                      const mozilla::LogicalSize* aLogicalCBSize,
148                                      const mozilla::LogicalSize& aKidSize,
149                                      mozilla::LogicalMargin& aMargin,
150                                      mozilla::LogicalMargin& aOffsets);
151 
152   void ReflowAbsoluteFrame(nsIFrame* aDelegatingFrame,
153                            nsPresContext* aPresContext,
154                            const ReflowInput& aReflowInput,
155                            const nsRect& aContainingBlockRect,
156                            AbsPosReflowFlags aFlags, nsIFrame* aKidFrame,
157                            nsReflowStatus& aStatus,
158                            mozilla::OverflowAreas* aOverflowAreas);
159 
160   /**
161    * Mark our absolute frames dirty.
162    * @param aMarkAllDirty if true, all will be marked with NS_FRAME_IS_DIRTY.
163    * Otherwise, the size-dependant ones will be marked with
164    * NS_FRAME_HAS_DIRTY_CHILDREN.
165    */
166   void DoMarkFramesDirty(bool aMarkAllDirty);
167 
168  protected:
169   nsFrameList mAbsoluteFrames;  // additional named child list
170 
171 #ifdef DEBUG
172   ChildListID const mChildListID;  // kFixedList or kAbsoluteList
173 #endif
174 };
175 
176 namespace mozilla {
177 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(
178     nsAbsoluteContainingBlock::AbsPosReflowFlags)
179 }
180 #endif /* nsnsAbsoluteContainingBlock_h___ */
181