Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
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/. */
6 //
7 // Eric Vaughan
8 // Netscape Communications
9 //
10 // See documentation in associated header file
11 //
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>
23 already_AddRefed<nsBoxLayout> NS_NewGridRowLeafLayout()
24 {
25 nsRefPtr<nsBoxLayout> layout = new nsGridRowLeafLayout();
26 return layout.forget();
27 }
29 nsGridRowLeafLayout::nsGridRowLeafLayout():nsGridRowLayout()
30 {
31 }
33 nsGridRowLeafLayout::~nsGridRowLeafLayout()
34 {
35 }
37 nsSize
38 nsGridRowLeafLayout::GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState)
39 {
40 int32_t index = 0;
41 nsGrid* grid = GetGrid(aBox, &index);
42 bool isHorizontal = IsHorizontal(aBox);
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 if (!grid) {
47 return nsGridRowLayout::GetPrefSize(aBox, aState);
48 }
49 else {
50 return grid->GetPrefRowSize(aState, index, isHorizontal);
51 //AddBorderAndPadding(aBox, pref);
52 }
53 }
55 nsSize
56 nsGridRowLeafLayout::GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aState)
57 {
58 int32_t index = 0;
59 nsGrid* grid = GetGrid(aBox, &index);
60 bool isHorizontal = IsHorizontal(aBox);
62 if (!grid)
63 return nsGridRowLayout::GetMinSize(aBox, aState);
64 else {
65 nsSize minSize = grid->GetMinRowSize(aState, index, isHorizontal);
66 AddBorderAndPadding(aBox, minSize);
67 return minSize;
68 }
69 }
71 nsSize
72 nsGridRowLeafLayout::GetMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState)
73 {
74 int32_t index = 0;
75 nsGrid* grid = GetGrid(aBox, &index);
76 bool isHorizontal = IsHorizontal(aBox);
78 if (!grid)
79 return nsGridRowLayout::GetMaxSize(aBox, aState);
80 else {
81 nsSize maxSize;
82 maxSize = grid->GetMaxRowSize(aState, index, isHorizontal);
83 AddBorderAndPadding(aBox, maxSize);
84 return maxSize;
85 }
86 }
88 /** If a child is added or removed or changes size
89 */
90 void
91 nsGridRowLeafLayout::ChildAddedOrRemoved(nsIFrame* aBox, nsBoxLayoutState& aState)
92 {
93 int32_t index = 0;
94 nsGrid* grid = GetGrid(aBox, &index);
95 bool isHorizontal = IsHorizontal(aBox);
97 if (grid)
98 grid->CellAddedOrRemoved(aState, index, isHorizontal);
99 }
101 void
102 nsGridRowLeafLayout::PopulateBoxSizes(nsIFrame* aBox, nsBoxLayoutState& aState, nsBoxSize*& aBoxSizes, nscoord& aMinSize, nscoord& aMaxSize, int32_t& aFlexes)
103 {
104 int32_t index = 0;
105 nsGrid* grid = GetGrid(aBox, &index);
106 bool isHorizontal = IsHorizontal(aBox);
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 if (grid) {
112 nsGridRow* column;
113 int32_t count = grid->GetColumnCount(isHorizontal);
114 nsBoxSize* start = nullptr;
115 nsBoxSize* last = nullptr;
116 nsBoxSize* current = nullptr;
117 nsIFrame* child = aBox->GetChildBox();
118 for (int i=0; i < count; i++)
119 {
120 column = grid->GetColumnAt(i,isHorizontal);
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 grid->GetPrefRowHeight(aState, i, !isHorizontal); // GetPrefColumnWidth
126 nscoord min =
127 grid->GetMinRowHeight(aState, i, !isHorizontal); // GetMinColumnWidth
128 nscoord max =
129 grid->GetMaxRowHeight(aState, i, !isHorizontal); // GetMaxColumnWidth
130 nscoord flex =
131 grid->GetRowFlex(aState, i, !isHorizontal); // GetColumnFlex
132 nscoord left = 0;
133 nscoord right = 0;
134 grid->GetRowOffsets(aState, i, left, right, !isHorizontal); // GetColumnOffsets
135 nsIFrame* box = column->GetBox();
136 bool collapsed = false;
137 nscoord topMargin = column->mTopMargin;
138 nscoord bottomMargin = column->mBottomMargin;
140 if (box)
141 collapsed = box->IsCollapsed();
143 pref = pref - (left + right);
144 if (pref < 0)
145 pref = 0;
147 // if this is the first or last column. Take into account that
148 // our row could have a border that could affect our left or right
149 // padding from our columns. If the row has padding subtract it.
150 // would should always be able to garentee that our margin is smaller
151 // or equal to our left or right
152 int32_t firstIndex = 0;
153 int32_t lastIndex = 0;
154 nsGridRow* firstRow = nullptr;
155 nsGridRow* lastRow = nullptr;
156 grid->GetFirstAndLastRow(aState, firstIndex, lastIndex, firstRow, lastRow, !isHorizontal);
158 if (i == firstIndex || i == lastIndex) {
159 nsMargin offset = GetTotalMargin(aBox, isHorizontal);
161 nsMargin border(0,0,0,0);
162 // can't call GetBorderPadding we will get into recursion
163 aBox->GetBorder(border);
164 offset += border;
165 aBox->GetPadding(border);
166 offset += border;
168 // subtract from out left and right
169 if (i == firstIndex)
170 {
171 if (isHorizontal)
172 left -= offset.left;
173 else
174 left -= offset.top;
175 }
177 if (i == lastIndex)
178 {
179 if (isHorizontal)
180 right -= offset.right;
181 else
182 right -= offset.bottom;
183 }
184 }
186 // initialize the box size here
187 max = std::max(min, max);
188 pref = nsBox::BoundsCheck(min, pref, max);
190 current = new (aState) nsBoxSize();
191 current->pref = pref;
192 current->min = min;
193 current->max = max;
194 current->flex = flex;
195 current->bogus = column->mIsBogus;
196 current->left = left + topMargin;
197 current->right = right + bottomMargin;
198 current->collapsed = collapsed;
200 if (!start) {
201 start = current;
202 last = start;
203 } else {
204 last->next = current;
205 last = current;
206 }
208 if (child && !column->mIsBogus)
209 child = child->GetNextBox();
211 }
212 aBoxSizes = start;
213 }
215 nsSprocketLayout::PopulateBoxSizes(aBox, aState, aBoxSizes, aMinSize, aMaxSize, aFlexes);
216 }
218 void
219 nsGridRowLeafLayout::ComputeChildSizes(nsIFrame* aBox,
220 nsBoxLayoutState& aState,
221 nscoord& aGivenSize,
222 nsBoxSize* aBoxSizes,
223 nsComputedBoxSize*& aComputedBoxSizes)
224 {
225 // see if we are in a scrollable frame. If we are then there could be scrollbars present
226 // if so we need to subtract them out to make sure our columns line up.
227 if (aBox) {
228 bool isHorizontal = aBox->IsHorizontal();
230 // go up the parent chain looking for scrollframes
231 nscoord diff = 0;
232 nsIFrame* parentBox;
233 (void)GetParentGridPart(aBox, &parentBox);
234 while (parentBox) {
235 nsIFrame* scrollbox = nsGrid::GetScrollBox(parentBox);
236 nsIScrollableFrame *scrollable = do_QueryFrame(scrollbox);
237 if (scrollable) {
238 // Don't call GetActualScrollbarSizes here because it's not safe
239 // to call that while we're reflowing the contents of the scrollframe,
240 // which we are here.
241 nsMargin scrollbarSizes = scrollable->GetDesiredScrollbarSizes(&aState);
242 uint32_t visible = scrollable->GetScrollbarVisibility();
244 if (isHorizontal && (visible & nsIScrollableFrame::VERTICAL)) {
245 diff += scrollbarSizes.left + scrollbarSizes.right;
246 } else if (!isHorizontal && (visible & nsIScrollableFrame::HORIZONTAL)) {
247 diff += scrollbarSizes.top + scrollbarSizes.bottom;
248 }
249 }
251 (void)GetParentGridPart(parentBox, &parentBox);
252 }
254 if (diff > 0) {
255 aGivenSize += diff;
257 nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes);
259 aGivenSize -= diff;
261 nsComputedBoxSize* s = aComputedBoxSizes;
262 nsComputedBoxSize* last = aComputedBoxSizes;
263 while(s)
264 {
265 last = s;
266 s = s->next;
267 }
269 if (last)
270 last->size -= diff;
272 return;
273 }
274 }
276 nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes);
278 }
280 NS_IMETHODIMP
281 nsGridRowLeafLayout::Layout(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
282 {
283 return nsGridRowLayout::Layout(aBox, aBoxLayoutState);
284 }
286 void
287 nsGridRowLeafLayout::DirtyRows(nsIFrame* aBox, nsBoxLayoutState& aState)
288 {
289 if (aBox) {
290 // mark us dirty
291 // XXXldb We probably don't want to walk up the ancestor chain
292 // calling MarkIntrinsicWidthsDirty for every row.
293 aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange,
294 NS_FRAME_IS_DIRTY);
295 }
296 }
298 void
299 nsGridRowLeafLayout::CountRowsColumns(nsIFrame* aBox, int32_t& aRowCount, int32_t& aComputedColumnCount)
300 {
301 if (aBox) {
302 nsIFrame* child = aBox->GetChildBox();
304 // count the children
305 int32_t columnCount = 0;
306 while(child) {
307 child = child->GetNextBox();
308 columnCount++;
309 }
311 // if our count is greater than the current column count
312 if (columnCount > aComputedColumnCount)
313 aComputedColumnCount = columnCount;
315 aRowCount++;
316 }
317 }
319 int32_t
320 nsGridRowLeafLayout::BuildRows(nsIFrame* aBox, nsGridRow* aRows)
321 {
322 if (aBox) {
323 aRows[0].Init(aBox, false);
324 return 1;
325 }
327 return 0;
328 }