|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* rendering object for css3 multi-column layout */ |
|
7 |
|
8 #include "mozilla/Attributes.h" |
|
9 #include "nsContainerFrame.h" |
|
10 |
|
11 class nsColumnSetFrame : public nsContainerFrame { |
|
12 public: |
|
13 NS_DECL_FRAMEARENA_HELPERS |
|
14 |
|
15 nsColumnSetFrame(nsStyleContext* aContext); |
|
16 |
|
17 virtual nsresult SetInitialChildList(ChildListID aListID, |
|
18 nsFrameList& aChildList) MOZ_OVERRIDE; |
|
19 |
|
20 virtual nsresult Reflow(nsPresContext* aPresContext, |
|
21 nsHTMLReflowMetrics& aDesiredSize, |
|
22 const nsHTMLReflowState& aReflowState, |
|
23 nsReflowStatus& aStatus) MOZ_OVERRIDE; |
|
24 |
|
25 virtual nsresult AppendFrames(ChildListID aListID, |
|
26 nsFrameList& aFrameList) MOZ_OVERRIDE; |
|
27 virtual nsresult InsertFrames(ChildListID aListID, |
|
28 nsIFrame* aPrevFrame, |
|
29 nsFrameList& aFrameList) MOZ_OVERRIDE; |
|
30 virtual nsresult RemoveFrame(ChildListID aListID, |
|
31 nsIFrame* aOldFrame) MOZ_OVERRIDE; |
|
32 |
|
33 virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; |
|
34 virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; |
|
35 |
|
36 /** |
|
37 * Retrieve the available height for content of this frame. The available content |
|
38 * height is the available height for the frame, minus borders and padding. |
|
39 */ |
|
40 virtual nscoord GetAvailableContentHeight(const nsHTMLReflowState& aReflowState); |
|
41 |
|
42 virtual nsIFrame* GetContentInsertionFrame() MOZ_OVERRIDE { |
|
43 nsIFrame* frame = GetFirstPrincipalChild(); |
|
44 |
|
45 // if no children return nullptr |
|
46 if (!frame) |
|
47 return nullptr; |
|
48 |
|
49 return frame->GetContentInsertionFrame(); |
|
50 } |
|
51 |
|
52 virtual nsresult StealFrame(nsIFrame* aChild, bool aForceNormal) MOZ_OVERRIDE |
|
53 { // nsColumnSetFrame keeps overflow containers in main child list |
|
54 return nsContainerFrame::StealFrame(aChild, true); |
|
55 } |
|
56 |
|
57 virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE |
|
58 { |
|
59 return nsContainerFrame::IsFrameOfType(aFlags & |
|
60 ~(nsIFrame::eCanContainOverflowContainers)); |
|
61 } |
|
62 |
|
63 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, |
|
64 const nsRect& aDirtyRect, |
|
65 const nsDisplayListSet& aLists) MOZ_OVERRIDE; |
|
66 |
|
67 virtual nsIAtom* GetType() const MOZ_OVERRIDE; |
|
68 |
|
69 virtual void PaintColumnRule(nsRenderingContext* aCtx, |
|
70 const nsRect& aDirtyRect, |
|
71 const nsPoint& aPt); |
|
72 |
|
73 #ifdef DEBUG_FRAME_DUMP |
|
74 virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE { |
|
75 return MakeFrameName(NS_LITERAL_STRING("ColumnSet"), aResult); |
|
76 } |
|
77 #endif |
|
78 |
|
79 protected: |
|
80 nscoord mLastBalanceHeight; |
|
81 nsReflowStatus mLastFrameStatus; |
|
82 |
|
83 /** |
|
84 * These are the parameters that control the layout of columns. |
|
85 */ |
|
86 struct ReflowConfig { |
|
87 // The number of columns that we want to balance across. If we're not |
|
88 // balancing, this will be set to INT32_MAX. |
|
89 int32_t mBalanceColCount; |
|
90 |
|
91 // The width of each individual column. |
|
92 nscoord mColWidth; |
|
93 |
|
94 // The amount of width that is expected to be left over after all the |
|
95 // columns and column gaps are laid out. |
|
96 nscoord mExpectedWidthLeftOver; |
|
97 |
|
98 // The width of each column gap. |
|
99 nscoord mColGap; |
|
100 |
|
101 // The maximum height of any individual column during a reflow iteration. |
|
102 // This parameter is set during each iteration of the binary search for |
|
103 // the best column height. |
|
104 nscoord mColMaxHeight; |
|
105 |
|
106 // A boolean controlling whether or not we are balancing. This should be |
|
107 // equivalent to mBalanceColCount == INT32_MAX. |
|
108 bool mIsBalancing; |
|
109 |
|
110 // The last known column height that was 'feasible'. A column height is |
|
111 // feasible if all child content fits within the specified height. |
|
112 nscoord mKnownFeasibleHeight; |
|
113 |
|
114 // The last known height that was 'infeasible'. A column height is |
|
115 // infeasible if not all child content fits within the specified height. |
|
116 nscoord mKnownInfeasibleHeight; |
|
117 |
|
118 // Height of the column set frame |
|
119 nscoord mComputedHeight; |
|
120 |
|
121 // The height "consumed" by previous-in-flows. |
|
122 // The computed height should be equal to the height of the element (i.e. |
|
123 // the computed height itself) plus the consumed height. |
|
124 nscoord mConsumedHeight; |
|
125 }; |
|
126 |
|
127 /** |
|
128 * Some data that is better calculated during reflow |
|
129 */ |
|
130 struct ColumnBalanceData { |
|
131 // The maximum "content height" of any column |
|
132 nscoord mMaxHeight; |
|
133 // The sum of the "content heights" for all columns |
|
134 nscoord mSumHeight; |
|
135 // The "content height" of the last column |
|
136 nscoord mLastHeight; |
|
137 // The maximum "content height" of all columns that overflowed |
|
138 // their available height |
|
139 nscoord mMaxOverflowingHeight; |
|
140 // This flag determines whether the last reflow of children exceeded the |
|
141 // computed height of the column set frame. If so, we set the height to |
|
142 // this maximum allowable height, and continue reflow without balancing. |
|
143 bool mHasExcessHeight; |
|
144 |
|
145 void Reset() { |
|
146 mMaxHeight = mSumHeight = mLastHeight = mMaxOverflowingHeight = 0; |
|
147 mHasExcessHeight = false; |
|
148 } |
|
149 }; |
|
150 |
|
151 /** |
|
152 * Similar to nsBlockFrame::DrainOverflowLines. Locate any columns not |
|
153 * handled by our prev-in-flow, and any columns sitting on our own |
|
154 * overflow list, and put them in our primary child list for reflowing. |
|
155 */ |
|
156 void DrainOverflowColumns(); |
|
157 |
|
158 bool ReflowColumns(nsHTMLReflowMetrics& aDesiredSize, |
|
159 const nsHTMLReflowState& aReflowState, |
|
160 nsReflowStatus& aReflowStatus, |
|
161 ReflowConfig& aConfig, |
|
162 bool aLastColumnUnbounded, |
|
163 nsCollapsingMargin* aCarriedOutBottomMargin, |
|
164 ColumnBalanceData& aColData); |
|
165 |
|
166 /** |
|
167 * The basic reflow strategy is to call this function repeatedly to |
|
168 * obtain specific parameters that determine the layout of the |
|
169 * columns. This function will compute those parameters from the CSS |
|
170 * style. This function will also be responsible for implementing |
|
171 * the state machine that controls column balancing. |
|
172 */ |
|
173 ReflowConfig ChooseColumnStrategy(const nsHTMLReflowState& aReflowState, |
|
174 bool aForceAuto, nscoord aFeasibleHeight, |
|
175 nscoord aInfeasibleHeight); |
|
176 |
|
177 /** |
|
178 * Perform the binary search for the best balance height for this column set. |
|
179 * |
|
180 * @param aReflowState The input parameters for the current reflow iteration. |
|
181 * @param aPresContext The presentation context in which the current reflow |
|
182 * iteration is occurring. |
|
183 * @param aConfig The ReflowConfig object associated with this column set |
|
184 * frame, generated by ChooseColumnStrategy(). |
|
185 * @param aColData A data structure used to keep track of data needed between |
|
186 * successive iterations of the balancing process. |
|
187 * @param aDesiredSize The final output size of the column set frame (output |
|
188 * of reflow procedure). |
|
189 * @param aOutMargin The bottom margin of the column set frame that may be |
|
190 * carried out from reflow (and thus collapsed). |
|
191 * @param aUnboundedLastColumn A boolean value indicating that the last column |
|
192 * can be of any height. Used during the first iteration of the |
|
193 * balancing procedure to measure the height of all content in |
|
194 * descendant frames of the column set. |
|
195 * @param aRunWasFeasible An input/output parameter indicating whether or not |
|
196 * the last iteration of the balancing loop was a feasible height to |
|
197 * fit all content from descendant frames. |
|
198 * @param aStatus A final reflow status of the column set frame, passed in as |
|
199 * an output parameter. |
|
200 */ |
|
201 void FindBestBalanceHeight(const nsHTMLReflowState& aReflowState, |
|
202 nsPresContext* aPresContext, |
|
203 ReflowConfig& aConfig, |
|
204 ColumnBalanceData& aColData, |
|
205 nsHTMLReflowMetrics& aDesiredSize, |
|
206 nsCollapsingMargin& aOutMargin, |
|
207 bool& aUnboundedLastColumn, |
|
208 bool& aRunWasFeasible, |
|
209 nsReflowStatus& aStatus); |
|
210 /** |
|
211 * Reflow column children. Returns true iff the content that was reflowed |
|
212 * fit into the mColMaxHeight. |
|
213 */ |
|
214 bool ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, |
|
215 const nsHTMLReflowState& aReflowState, |
|
216 nsReflowStatus& aStatus, |
|
217 const ReflowConfig& aConfig, |
|
218 bool aLastColumnUnbounded, |
|
219 nsCollapsingMargin* aCarriedOutBottomMargin, |
|
220 ColumnBalanceData& aColData); |
|
221 }; |