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