/src/mozilla-central/layout/xul/grid/nsGridRowLeafLayout.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | // Eric Vaughan |
9 | | // Netscape Communications |
10 | | // |
11 | | // See documentation in associated header file |
12 | | // |
13 | | |
14 | | #include "nsGridRowLeafLayout.h" |
15 | | #include "nsGridRowGroupLayout.h" |
16 | | #include "nsGridRow.h" |
17 | | #include "nsBoxLayoutState.h" |
18 | | #include "nsBox.h" |
19 | | #include "nsIScrollableFrame.h" |
20 | | #include "nsBoxFrame.h" |
21 | | #include "nsGridLayout2.h" |
22 | | #include <algorithm> |
23 | | |
24 | | already_AddRefed<nsBoxLayout> NS_NewGridRowLeafLayout() |
25 | 0 | { |
26 | 0 | RefPtr<nsBoxLayout> layout = new nsGridRowLeafLayout(); |
27 | 0 | return layout.forget(); |
28 | 0 | } |
29 | | |
30 | | nsGridRowLeafLayout::nsGridRowLeafLayout():nsGridRowLayout() |
31 | 0 | { |
32 | 0 | } |
33 | | |
34 | | nsGridRowLeafLayout::~nsGridRowLeafLayout() |
35 | | { |
36 | | } |
37 | | |
38 | | nsSize |
39 | | nsGridRowLeafLayout::GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState) |
40 | 0 | { |
41 | 0 | int32_t index = 0; |
42 | 0 | nsGrid* grid = GetGrid(aBox, &index); |
43 | 0 | bool isHorizontal = IsXULHorizontal(aBox); |
44 | 0 |
|
45 | 0 | // If we are not in a grid. Then we just work like a box. But if we are in a grid |
46 | 0 | // ask the grid for our size. |
47 | 0 | if (!grid) { |
48 | 0 | return nsGridRowLayout::GetXULPrefSize(aBox, aState); |
49 | 0 | } |
50 | 0 | else { |
51 | 0 | return grid->GetPrefRowSize(aState, index, isHorizontal); |
52 | 0 | //AddBorderAndPadding(aBox, pref); |
53 | 0 | } |
54 | 0 | } |
55 | | |
56 | | nsSize |
57 | | nsGridRowLeafLayout::GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aState) |
58 | 0 | { |
59 | 0 | int32_t index = 0; |
60 | 0 | nsGrid* grid = GetGrid(aBox, &index); |
61 | 0 | bool isHorizontal = IsXULHorizontal(aBox); |
62 | 0 |
|
63 | 0 | if (!grid) |
64 | 0 | return nsGridRowLayout::GetXULMinSize(aBox, aState); |
65 | 0 | else { |
66 | 0 | nsSize minSize = grid->GetMinRowSize(aState, index, isHorizontal); |
67 | 0 | AddBorderAndPadding(aBox, minSize); |
68 | 0 | return minSize; |
69 | 0 | } |
70 | 0 | } |
71 | | |
72 | | nsSize |
73 | | nsGridRowLeafLayout::GetXULMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState) |
74 | 0 | { |
75 | 0 | int32_t index = 0; |
76 | 0 | nsGrid* grid = GetGrid(aBox, &index); |
77 | 0 | bool isHorizontal = IsXULHorizontal(aBox); |
78 | 0 |
|
79 | 0 | if (!grid) |
80 | 0 | return nsGridRowLayout::GetXULMaxSize(aBox, aState); |
81 | 0 | else { |
82 | 0 | nsSize maxSize; |
83 | 0 | maxSize = grid->GetMaxRowSize(aState, index, isHorizontal); |
84 | 0 | AddBorderAndPadding(aBox, maxSize); |
85 | 0 | return maxSize; |
86 | 0 | } |
87 | 0 | } |
88 | | |
89 | | /** If a child is added or removed or changes size |
90 | | */ |
91 | | void |
92 | | nsGridRowLeafLayout::ChildAddedOrRemoved(nsIFrame* aBox, nsBoxLayoutState& aState) |
93 | 0 | { |
94 | 0 | int32_t index = 0; |
95 | 0 | nsGrid* grid = GetGrid(aBox, &index); |
96 | 0 | bool isHorizontal = IsXULHorizontal(aBox); |
97 | 0 |
|
98 | 0 | if (grid) |
99 | 0 | grid->CellAddedOrRemoved(aState, index, isHorizontal); |
100 | 0 | } |
101 | | |
102 | | void |
103 | | nsGridRowLeafLayout::PopulateBoxSizes(nsIFrame* aBox, nsBoxLayoutState& aState, nsBoxSize*& aBoxSizes, nscoord& aMinSize, nscoord& aMaxSize, int32_t& aFlexes) |
104 | 0 | { |
105 | 0 | int32_t index = 0; |
106 | 0 | nsGrid* grid = GetGrid(aBox, &index); |
107 | 0 | bool isHorizontal = IsXULHorizontal(aBox); |
108 | 0 |
|
109 | 0 | // Our base class SprocketLayout is giving us a chance to change the box sizes before layout |
110 | 0 | // If we are a row lets change the sizes to match our columns. If we are a column then do the opposite |
111 | 0 | // and make them match or rows. |
112 | 0 | if (grid) { |
113 | 0 | nsGridRow* column; |
114 | 0 | int32_t count = grid->GetColumnCount(isHorizontal); |
115 | 0 | nsBoxSize* start = nullptr; |
116 | 0 | nsBoxSize* last = nullptr; |
117 | 0 | nsBoxSize* current = nullptr; |
118 | 0 | nsIFrame* child = nsBox::GetChildXULBox(aBox); |
119 | 0 | for (int i=0; i < count; i++) |
120 | 0 | { |
121 | 0 | column = grid->GetColumnAt(i,isHorizontal); |
122 | 0 |
|
123 | 0 | // make sure the value was computed before we use it. |
124 | 0 | // !isHorizontal is passed in to invert the behavior of these methods. |
125 | 0 | nscoord pref = |
126 | 0 | grid->GetPrefRowHeight(aState, i, !isHorizontal); // GetPrefColumnWidth |
127 | 0 | nscoord min = |
128 | 0 | grid->GetMinRowHeight(aState, i, !isHorizontal); // GetMinColumnWidth |
129 | 0 | nscoord max = |
130 | 0 | grid->GetMaxRowHeight(aState, i, !isHorizontal); // GetMaxColumnWidth |
131 | 0 | nscoord flex = grid->GetRowFlex(i, !isHorizontal); // GetColumnFlex |
132 | 0 | nscoord left = 0; |
133 | 0 | nscoord right = 0; |
134 | 0 | grid->GetRowOffsets(i, left, right, !isHorizontal); // GetColumnOffsets |
135 | 0 | nsIFrame* box = column->GetBox(); |
136 | 0 | bool collapsed = false; |
137 | 0 | nscoord topMargin = column->mTopMargin; |
138 | 0 | nscoord bottomMargin = column->mBottomMargin; |
139 | 0 |
|
140 | 0 | if (box) |
141 | 0 | collapsed = box->IsXULCollapsed(); |
142 | 0 |
|
143 | 0 | pref = pref - (left + right); |
144 | 0 | if (pref < 0) |
145 | 0 | pref = 0; |
146 | 0 |
|
147 | 0 | // if this is the first or last column. Take into account that |
148 | 0 | // our row could have a border that could affect our left or right |
149 | 0 | // padding from our columns. If the row has padding subtract it. |
150 | 0 | // would should always be able to garentee that our margin is smaller |
151 | 0 | // or equal to our left or right |
152 | 0 | int32_t firstIndex = 0; |
153 | 0 | int32_t lastIndex = 0; |
154 | 0 | nsGridRow* firstRow = nullptr; |
155 | 0 | nsGridRow* lastRow = nullptr; |
156 | 0 | grid->GetFirstAndLastRow(firstIndex, lastIndex, firstRow, lastRow, !isHorizontal); |
157 | 0 |
|
158 | 0 | if (i == firstIndex || i == lastIndex) { |
159 | 0 | nsMargin offset = GetTotalMargin(aBox, isHorizontal); |
160 | 0 |
|
161 | 0 | nsMargin border(0,0,0,0); |
162 | 0 | // can't call GetBorderPadding we will get into recursion |
163 | 0 | aBox->GetXULBorder(border); |
164 | 0 | offset += border; |
165 | 0 | aBox->GetXULPadding(border); |
166 | 0 | offset += border; |
167 | 0 |
|
168 | 0 | // subtract from out left and right |
169 | 0 | if (i == firstIndex) |
170 | 0 | { |
171 | 0 | if (isHorizontal) |
172 | 0 | left -= offset.left; |
173 | 0 | else |
174 | 0 | left -= offset.top; |
175 | 0 | } |
176 | 0 |
|
177 | 0 | if (i == lastIndex) |
178 | 0 | { |
179 | 0 | if (isHorizontal) |
180 | 0 | right -= offset.right; |
181 | 0 | else |
182 | 0 | right -= offset.bottom; |
183 | 0 | } |
184 | 0 | } |
185 | 0 |
|
186 | 0 | // initialize the box size here |
187 | 0 | max = std::max(min, max); |
188 | 0 | pref = nsBox::BoundsCheck(min, pref, max); |
189 | 0 |
|
190 | 0 | current = new (aState) nsBoxSize(); |
191 | 0 | current->pref = pref; |
192 | 0 | current->min = min; |
193 | 0 | current->max = max; |
194 | 0 | current->flex = flex; |
195 | 0 | current->bogus = column->mIsBogus; |
196 | 0 | current->left = left + topMargin; |
197 | 0 | current->right = right + bottomMargin; |
198 | 0 | current->collapsed = collapsed; |
199 | 0 |
|
200 | 0 | if (!start) { |
201 | 0 | start = current; |
202 | 0 | last = start; |
203 | 0 | } else { |
204 | 0 | last->next = current; |
205 | 0 | last = current; |
206 | 0 | } |
207 | 0 |
|
208 | 0 | if (child && !column->mIsBogus) |
209 | 0 | child = nsBox::GetNextXULBox(child); |
210 | 0 |
|
211 | 0 | } |
212 | 0 | aBoxSizes = start; |
213 | 0 | } |
214 | 0 |
|
215 | 0 | nsSprocketLayout::PopulateBoxSizes(aBox, aState, aBoxSizes, aMinSize, aMaxSize, aFlexes); |
216 | 0 | } |
217 | | |
218 | | void |
219 | | nsGridRowLeafLayout::ComputeChildSizes(nsIFrame* aBox, |
220 | | nsBoxLayoutState& aState, |
221 | | nscoord& aGivenSize, |
222 | | nsBoxSize* aBoxSizes, |
223 | | nsComputedBoxSize*& aComputedBoxSizes) |
224 | 0 | { |
225 | 0 | // see if we are in a scrollable frame. If we are then there could be scrollbars present |
226 | 0 | // if so we need to subtract them out to make sure our columns line up. |
227 | 0 | if (aBox) { |
228 | 0 | bool isHorizontal = aBox->IsXULHorizontal(); |
229 | 0 |
|
230 | 0 | // go up the parent chain looking for scrollframes |
231 | 0 | nscoord diff = 0; |
232 | 0 | nsIFrame* parentBox; |
233 | 0 | (void)GetParentGridPart(aBox, &parentBox); |
234 | 0 | while (parentBox) { |
235 | 0 | nsIFrame* scrollbox = nsGrid::GetScrollBox(parentBox); |
236 | 0 | nsIScrollableFrame *scrollable = do_QueryFrame(scrollbox); |
237 | 0 | if (scrollable) { |
238 | 0 | // Don't call GetActualScrollbarSizes here because it's not safe |
239 | 0 | // to call that while we're reflowing the contents of the scrollframe, |
240 | 0 | // which we are here. |
241 | 0 | nsMargin scrollbarSizes = scrollable->GetDesiredScrollbarSizes(&aState); |
242 | 0 | uint32_t visible = scrollable->GetScrollbarVisibility(); |
243 | 0 |
|
244 | 0 | if (isHorizontal && (visible & nsIScrollableFrame::VERTICAL)) { |
245 | 0 | diff += scrollbarSizes.left + scrollbarSizes.right; |
246 | 0 | } else if (!isHorizontal && (visible & nsIScrollableFrame::HORIZONTAL)) { |
247 | 0 | diff += scrollbarSizes.top + scrollbarSizes.bottom; |
248 | 0 | } |
249 | 0 | } |
250 | 0 |
|
251 | 0 | (void)GetParentGridPart(parentBox, &parentBox); |
252 | 0 | } |
253 | 0 |
|
254 | 0 | if (diff > 0) { |
255 | 0 | aGivenSize += diff; |
256 | 0 |
|
257 | 0 | nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes); |
258 | 0 |
|
259 | 0 | aGivenSize -= diff; |
260 | 0 |
|
261 | 0 | nsComputedBoxSize* s = aComputedBoxSizes; |
262 | 0 | nsComputedBoxSize* last = aComputedBoxSizes; |
263 | 0 | while(s) |
264 | 0 | { |
265 | 0 | last = s; |
266 | 0 | s = s->next; |
267 | 0 | } |
268 | 0 |
|
269 | 0 | if (last) |
270 | 0 | last->size -= diff; |
271 | 0 |
|
272 | 0 | return; |
273 | 0 | } |
274 | 0 | } |
275 | 0 |
|
276 | 0 | nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes); |
277 | 0 |
|
278 | 0 | } |
279 | | |
280 | | NS_IMETHODIMP |
281 | | nsGridRowLeafLayout::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) |
282 | 0 | { |
283 | 0 | return nsGridRowLayout::XULLayout(aBox, aBoxLayoutState); |
284 | 0 | } |
285 | | |
286 | | void |
287 | | nsGridRowLeafLayout::DirtyRows(nsIFrame* aBox, nsBoxLayoutState& aState) |
288 | 0 | { |
289 | 0 | if (aBox) { |
290 | 0 | // mark us dirty |
291 | 0 | // XXXldb We probably don't want to walk up the ancestor chain |
292 | 0 | // calling MarkIntrinsicISizesDirty for every row. |
293 | 0 | aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange, |
294 | 0 | NS_FRAME_IS_DIRTY); |
295 | 0 | } |
296 | 0 | } |
297 | | |
298 | | void |
299 | | nsGridRowLeafLayout::CountRowsColumns(nsIFrame* aBox, int32_t& aRowCount, int32_t& aComputedColumnCount) |
300 | 0 | { |
301 | 0 | if (aBox) { |
302 | 0 | nsIFrame* child = nsBox::GetChildXULBox(aBox); |
303 | 0 |
|
304 | 0 | // count the children |
305 | 0 | int32_t columnCount = 0; |
306 | 0 | while(child) { |
307 | 0 | child = nsBox::GetNextXULBox(child); |
308 | 0 | columnCount++; |
309 | 0 | } |
310 | 0 |
|
311 | 0 | // if our count is greater than the current column count |
312 | 0 | if (columnCount > aComputedColumnCount) |
313 | 0 | aComputedColumnCount = columnCount; |
314 | 0 |
|
315 | 0 | aRowCount++; |
316 | 0 | } |
317 | 0 | } |
318 | | |
319 | | int32_t |
320 | | nsGridRowLeafLayout::BuildRows(nsIFrame* aBox, nsGridRow* aRows) |
321 | 0 | { |
322 | 0 | if (aBox) { |
323 | 0 | aRows[0].Init(aBox, false); |
324 | 0 | return 1; |
325 | 0 | } |
326 | 0 | |
327 | 0 | return 0; |
328 | 0 | } |
329 | | |