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 
14 /*
15  * The nsGridRowGroupLayout implements the <rows> or <columns> tag in a grid.
16  */
17 
18 #include "nsGridRowGroupLayout.h"
19 #include "nsCOMPtr.h"
20 #include "nsIScrollableFrame.h"
21 #include "nsBox.h"
22 #include "nsBoxLayoutState.h"
23 #include "nsGridLayout2.h"
24 #include "nsGridRow.h"
25 #include "mozilla/ReflowInput.h"
26 
NS_NewGridRowGroupLayout()27 already_AddRefed<nsBoxLayout> NS_NewGridRowGroupLayout()
28 {
29   RefPtr<nsBoxLayout> layout = new nsGridRowGroupLayout();
30   return layout.forget();
31 }
32 
nsGridRowGroupLayout()33 nsGridRowGroupLayout::nsGridRowGroupLayout():nsGridRowLayout(), mRowCount(0)
34 {
35 }
36 
~nsGridRowGroupLayout()37 nsGridRowGroupLayout::~nsGridRowGroupLayout()
38 {
39 }
40 
41 void
ChildAddedOrRemoved(nsIFrame * aBox,nsBoxLayoutState & aState)42 nsGridRowGroupLayout::ChildAddedOrRemoved(nsIFrame* aBox, nsBoxLayoutState& aState)
43 {
44   int32_t index = 0;
45   nsGrid* grid = GetGrid(aBox, &index);
46   bool isHorizontal = IsXULHorizontal(aBox);
47 
48   if (grid)
49     grid->RowAddedOrRemoved(aState, index, isHorizontal);
50 }
51 
52 void
AddWidth(nsSize & aSize,nscoord aSize2,bool aIsHorizontal)53 nsGridRowGroupLayout::AddWidth(nsSize& aSize, nscoord aSize2, bool aIsHorizontal)
54 {
55   nscoord& size = GET_WIDTH(aSize, aIsHorizontal);
56 
57   if (size == NS_INTRINSICSIZE || aSize2 == NS_INTRINSICSIZE)
58     size = NS_INTRINSICSIZE;
59   else
60     size += aSize2;
61 }
62 
63 nsSize
GetXULPrefSize(nsIFrame * aBox,nsBoxLayoutState & aState)64 nsGridRowGroupLayout::GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState)
65 {
66   nsSize vpref = nsGridRowLayout::GetXULPrefSize(aBox, aState);
67 
68 
69  /* It is possible that we could have some extra columns. This is when less columns in XUL were
70   * defined that needed. And example might be a grid with 3 defined columns but a row with 4 cells in
71   * it. We would need an extra column to make the grid work. But because that extra column does not
72   * have a box associated with it we must add its size in manually. Remember we could have extra rows
73   * as well.
74   */
75 
76   int32_t index = 0;
77   nsGrid* grid = GetGrid(aBox, &index);
78 
79   if (grid)
80   {
81     // make sure we add in extra columns sizes as well
82     bool isHorizontal = IsXULHorizontal(aBox);
83     int32_t extraColumns = grid->GetExtraColumnCount(isHorizontal);
84     int32_t start = grid->GetColumnCount(isHorizontal) - grid->GetExtraColumnCount(isHorizontal);
85     for (int32_t i=0; i < extraColumns; i++)
86     {
87       nscoord pref =
88         grid->GetPrefRowHeight(aState, i+start, !isHorizontal); // GetPrefColumnWidth
89 
90       AddWidth(vpref, pref, isHorizontal);
91     }
92   }
93 
94   return vpref;
95 }
96 
97 nsSize
GetXULMaxSize(nsIFrame * aBox,nsBoxLayoutState & aState)98 nsGridRowGroupLayout::GetXULMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState)
99 {
100  nsSize maxSize = nsGridRowLayout::GetXULMaxSize(aBox, aState);
101 
102   int32_t index = 0;
103   nsGrid* grid = GetGrid(aBox, &index);
104 
105   if (grid)
106   {
107     // make sure we add in extra columns sizes as well
108     bool isHorizontal = IsXULHorizontal(aBox);
109     int32_t extraColumns = grid->GetExtraColumnCount(isHorizontal);
110     int32_t start = grid->GetColumnCount(isHorizontal) - grid->GetExtraColumnCount(isHorizontal);
111     for (int32_t i=0; i < extraColumns; i++)
112     {
113       nscoord max =
114         grid->GetMaxRowHeight(aState, i+start, !isHorizontal); // GetMaxColumnWidth
115 
116       AddWidth(maxSize, max, isHorizontal);
117     }
118   }
119 
120   return maxSize;
121 }
122 
123 nsSize
GetXULMinSize(nsIFrame * aBox,nsBoxLayoutState & aState)124 nsGridRowGroupLayout::GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aState)
125 {
126   nsSize minSize = nsGridRowLayout::GetXULMinSize(aBox, aState);
127 
128   int32_t index = 0;
129   nsGrid* grid = GetGrid(aBox, &index);
130 
131   if (grid)
132   {
133     // make sure we add in extra columns sizes as well
134     bool isHorizontal = IsXULHorizontal(aBox);
135     int32_t extraColumns = grid->GetExtraColumnCount(isHorizontal);
136     int32_t start = grid->GetColumnCount(isHorizontal) - grid->GetExtraColumnCount(isHorizontal);
137     for (int32_t i=0; i < extraColumns; i++)
138     {
139       nscoord min =
140         grid->GetMinRowHeight(aState, i+start, !isHorizontal); // GetMinColumnWidth
141       AddWidth(minSize, min, isHorizontal);
142     }
143   }
144 
145   return minSize;
146 }
147 
148 /*
149  * Run down through our children dirtying them recursively.
150  */
151 void
DirtyRows(nsIFrame * aBox,nsBoxLayoutState & aState)152 nsGridRowGroupLayout::DirtyRows(nsIFrame* aBox, nsBoxLayoutState& aState)
153 {
154   if (aBox) {
155     // mark us dirty
156     // XXXldb We probably don't want to walk up the ancestor chain
157     // calling MarkIntrinsicISizesDirty for every row group.
158     aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange,
159                                          NS_FRAME_IS_DIRTY);
160     nsIFrame* child = nsBox::GetChildXULBox(aBox);
161 
162     while(child) {
163 
164       // walk into scrollframes
165       nsIFrame* deepChild = nsGrid::GetScrolledBox(child);
166 
167       // walk into other monuments
168       nsIGridPart* monument = nsGrid::GetPartFromBox(deepChild);
169       if (monument)
170         monument->DirtyRows(deepChild, aState);
171 
172       child = nsBox::GetNextXULBox(child);
173     }
174   }
175 }
176 
177 
178 void
CountRowsColumns(nsIFrame * aBox,int32_t & aRowCount,int32_t & aComputedColumnCount)179 nsGridRowGroupLayout::CountRowsColumns(nsIFrame* aBox, int32_t& aRowCount, int32_t& aComputedColumnCount)
180 {
181   if (aBox) {
182     int32_t startCount = aRowCount;
183 
184     nsIFrame* child = nsBox::GetChildXULBox(aBox);
185 
186     while(child) {
187 
188       // first see if it is a scrollframe. If so walk down into it and get the scrolled child
189       nsIFrame* deepChild = nsGrid::GetScrolledBox(child);
190 
191       nsIGridPart* monument = nsGrid::GetPartFromBox(deepChild);
192       if (monument) {
193         monument->CountRowsColumns(deepChild, aRowCount, aComputedColumnCount);
194         child = nsBox::GetNextXULBox(child);
195         deepChild = child;
196         continue;
197       }
198 
199       child = nsBox::GetNextXULBox(child);
200 
201       // if not a monument. Then count it. It will be a bogus row
202       aRowCount++;
203     }
204 
205     mRowCount = aRowCount - startCount;
206   }
207 }
208 
209 
210 /**
211  * Fill out the given row structure recursively
212  */
213 int32_t
BuildRows(nsIFrame * aBox,nsGridRow * aRows)214 nsGridRowGroupLayout::BuildRows(nsIFrame* aBox, nsGridRow* aRows)
215 {
216   int32_t rowCount = 0;
217 
218   if (aBox) {
219     nsIFrame* child = nsBox::GetChildXULBox(aBox);
220 
221     while(child) {
222 
223       // first see if it is a scrollframe. If so walk down into it and get the scrolled child
224       nsIFrame* deepChild = nsGrid::GetScrolledBox(child);
225 
226       nsIGridPart* monument = nsGrid::GetPartFromBox(deepChild);
227       if (monument) {
228         rowCount += monument->BuildRows(deepChild, &aRows[rowCount]);
229         child = nsBox::GetNextXULBox(child);
230         deepChild = child;
231         continue;
232       }
233 
234       aRows[rowCount].Init(child, true);
235 
236       child = nsBox::GetNextXULBox(child);
237 
238       // if not a monument. Then count it. It will be a bogus row
239       rowCount++;
240     }
241   }
242 
243   return rowCount;
244 }
245 
246 nsMargin
GetTotalMargin(nsIFrame * aBox,bool aIsHorizontal)247 nsGridRowGroupLayout::GetTotalMargin(nsIFrame* aBox, bool aIsHorizontal)
248 {
249   // group have border and padding added to the total margin
250 
251   nsMargin margin = nsGridRowLayout::GetTotalMargin(aBox, aIsHorizontal);
252 
253   // make sure we have the scrollframe on the outside if it has one.
254   // that's where the border is.
255   aBox = nsGrid::GetScrollBox(aBox);
256 
257   // add our border/padding to it
258   nsMargin borderPadding(0,0,0,0);
259   aBox->GetXULBorderAndPadding(borderPadding);
260   margin += borderPadding;
261 
262   return margin;
263 }
264 
265 
266