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