/src/mozilla-central/layout/xul/nsSprocketLayout.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 "nsBoxLayoutState.h" |
15 | | #include "nsSprocketLayout.h" |
16 | | #include "nsPresContext.h" |
17 | | #include "nsCOMPtr.h" |
18 | | #include "nsIContent.h" |
19 | | #include "nsIPresShell.h" |
20 | | #include "nsContainerFrame.h" |
21 | | #include "nsBoxFrame.h" |
22 | | #include "StackArena.h" |
23 | | #include "mozilla/Likely.h" |
24 | | #include <algorithm> |
25 | | |
26 | | nsBoxLayout* nsSprocketLayout::gInstance = nullptr; |
27 | | |
28 | | nsresult |
29 | | NS_NewSprocketLayout(nsCOMPtr<nsBoxLayout>& aNewLayout) |
30 | 0 | { |
31 | 0 | if (!nsSprocketLayout::gInstance) { |
32 | 0 | nsSprocketLayout::gInstance = new nsSprocketLayout(); |
33 | 0 | NS_IF_ADDREF(nsSprocketLayout::gInstance); |
34 | 0 | } |
35 | 0 | // we have not instance variables so just return our static one. |
36 | 0 | aNewLayout = nsSprocketLayout::gInstance; |
37 | 0 | return NS_OK; |
38 | 0 | } |
39 | | |
40 | | /*static*/ void |
41 | | nsSprocketLayout::Shutdown() |
42 | 0 | { |
43 | 0 | NS_IF_RELEASE(gInstance); |
44 | 0 | } |
45 | | |
46 | | nsSprocketLayout::nsSprocketLayout() |
47 | 0 | { |
48 | 0 | } |
49 | | |
50 | | bool |
51 | | nsSprocketLayout::IsXULHorizontal(nsIFrame* aBox) |
52 | 0 | { |
53 | 0 | return (aBox->GetStateBits() & NS_STATE_IS_HORIZONTAL) != 0; |
54 | 0 | } |
55 | | |
56 | | void |
57 | | nsSprocketLayout::GetFrameState(nsIFrame* aBox, nsFrameState& aState) |
58 | 0 | { |
59 | 0 | aState = aBox->GetStateBits(); |
60 | 0 | } |
61 | | |
62 | | static uint8_t |
63 | | GetFrameDirection(nsIFrame* aBox) |
64 | 0 | { |
65 | 0 | return aBox->StyleVisibility()->mDirection; |
66 | 0 | } |
67 | | |
68 | | static void |
69 | | HandleBoxPack(nsIFrame* aBox, const nsFrameState& aFrameState, nscoord& aX, nscoord& aY, |
70 | | const nsRect& aOriginalRect, const nsRect& aClientRect) |
71 | 0 | { |
72 | 0 | // In the normal direction we lay out our kids in the positive direction (e.g., |x| will get |
73 | 0 | // bigger for a horizontal box, and |y| will get bigger for a vertical box). In the reverse |
74 | 0 | // direction, the opposite is true. We'll be laying out each child at a smaller |x| or |
75 | 0 | // |y|. |
76 | 0 | uint8_t frameDirection = GetFrameDirection(aBox); |
77 | 0 |
|
78 | 0 | if (aFrameState & NS_STATE_IS_HORIZONTAL) { |
79 | 0 | if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) { |
80 | 0 | // The normal direction. |x| increases as we move through our children. |
81 | 0 | aX = aClientRect.x; |
82 | 0 | } |
83 | 0 | else { |
84 | 0 | // The reverse direction. |x| decreases as we move through our children. |
85 | 0 | aX = aClientRect.x + aOriginalRect.width; |
86 | 0 | } |
87 | 0 | // |y| is always in the normal direction in horizontal boxes |
88 | 0 | aY = aClientRect.y; |
89 | 0 | } |
90 | 0 | else { |
91 | 0 | // take direction property into account for |x| in vertical boxes |
92 | 0 | if (frameDirection == NS_STYLE_DIRECTION_LTR) { |
93 | 0 | // The normal direction. |x| increases as we move through our children. |
94 | 0 | aX = aClientRect.x; |
95 | 0 | } |
96 | 0 | else { |
97 | 0 | // The reverse direction. |x| decreases as we move through our children. |
98 | 0 | aX = aClientRect.x + aOriginalRect.width; |
99 | 0 | } |
100 | 0 | if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) { |
101 | 0 | // The normal direction. |y| increases as we move through our children. |
102 | 0 | aY = aClientRect.y; |
103 | 0 | } |
104 | 0 | else { |
105 | 0 | // The reverse direction. |y| decreases as we move through our children. |
106 | 0 | aY = aClientRect.y + aOriginalRect.height; |
107 | 0 | } |
108 | 0 | } |
109 | 0 |
|
110 | 0 | // Get our pack/alignment information. |
111 | 0 | nsIFrame::Halignment halign = aBox->GetXULHAlign(); |
112 | 0 | nsIFrame::Valignment valign = aBox->GetXULVAlign(); |
113 | 0 |
|
114 | 0 | // The following code handles box PACKING. Packing comes into play in the case where the computed size for |
115 | 0 | // all of our children (now stored in our client rect) is smaller than the size available for |
116 | 0 | // the box (stored in |aOriginalRect|). |
117 | 0 | // |
118 | 0 | // Here we adjust our |x| and |y| variables accordingly so that we start at the beginning, |
119 | 0 | // middle, or end of the box. |
120 | 0 | // |
121 | 0 | // XXXdwh JUSTIFY needs to be implemented! |
122 | 0 | if (aFrameState & NS_STATE_IS_HORIZONTAL) { |
123 | 0 | switch(halign) { |
124 | 0 | case nsBoxFrame::hAlign_Left: |
125 | 0 | break; // Nothing to do. The default initialized us properly. |
126 | 0 |
|
127 | 0 | case nsBoxFrame::hAlign_Center: |
128 | 0 | if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) |
129 | 0 | aX += (aOriginalRect.width - aClientRect.width)/2; |
130 | 0 | else |
131 | 0 | aX -= (aOriginalRect.width - aClientRect.width)/2; |
132 | 0 | break; |
133 | 0 |
|
134 | 0 | case nsBoxFrame::hAlign_Right: |
135 | 0 | if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) |
136 | 0 | aX += (aOriginalRect.width - aClientRect.width); |
137 | 0 | else |
138 | 0 | aX -= (aOriginalRect.width - aClientRect.width); |
139 | 0 | break; // Nothing to do for the reverse dir. The default initialized us properly. |
140 | 0 | } |
141 | 0 | } else { |
142 | 0 | switch(valign) { |
143 | 0 | case nsBoxFrame::vAlign_Top: |
144 | 0 | case nsBoxFrame::vAlign_BaseLine: // This value is technically impossible to specify for pack. |
145 | 0 | break; // Don't do anything. We were initialized correctly. |
146 | 0 |
|
147 | 0 | case nsBoxFrame::vAlign_Middle: |
148 | 0 | if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) |
149 | 0 | aY += (aOriginalRect.height - aClientRect.height)/2; |
150 | 0 | else |
151 | 0 | aY -= (aOriginalRect.height - aClientRect.height)/2; |
152 | 0 | break; |
153 | 0 |
|
154 | 0 | case nsBoxFrame::vAlign_Bottom: |
155 | 0 | if (aFrameState & NS_STATE_IS_DIRECTION_NORMAL) |
156 | 0 | aY += (aOriginalRect.height - aClientRect.height); |
157 | 0 | else |
158 | 0 | aY -= (aOriginalRect.height - aClientRect.height); |
159 | 0 | break; |
160 | 0 | } |
161 | 0 | } |
162 | 0 | } |
163 | | |
164 | | NS_IMETHODIMP |
165 | | nsSprocketLayout::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aState) |
166 | 0 | { |
167 | 0 | // See if we are collapsed. If we are, then simply iterate over all our |
168 | 0 | // children and give them a rect of 0 width and height. |
169 | 0 | if (aBox->IsXULCollapsed()) { |
170 | 0 | nsIFrame* child = nsBox::GetChildXULBox(aBox); |
171 | 0 | while(child) |
172 | 0 | { |
173 | 0 | nsBoxFrame::LayoutChildAt(aState, child, nsRect(0,0,0,0)); |
174 | 0 | child = nsBox::GetNextXULBox(child); |
175 | 0 | } |
176 | 0 | return NS_OK; |
177 | 0 | } |
178 | 0 |
|
179 | 0 | nsBoxLayoutState::AutoReflowDepth depth(aState); |
180 | 0 | mozilla::AutoStackArena arena; |
181 | 0 |
|
182 | 0 | // ----- figure out our size ---------- |
183 | 0 | const nsSize originalSize = aBox->GetSize(); |
184 | 0 |
|
185 | 0 | // -- make sure we remove our border and padding ---- |
186 | 0 | nsRect clientRect; |
187 | 0 | aBox->GetXULClientRect(clientRect); |
188 | 0 |
|
189 | 0 | // |originalClientRect| represents the rect of the entire box (excluding borders |
190 | 0 | // and padding). We store it here because we're going to use |clientRect| to hold |
191 | 0 | // the required size for all our kids. As an example, consider an hbox with a |
192 | 0 | // specified width of 300. If the kids total only 150 pixels of width, then |
193 | 0 | // we have 150 pixels left over. |clientRect| is going to hold a width of 150 and |
194 | 0 | // is going to be adjusted based off the value of the PACK property. If flexible |
195 | 0 | // objects are in the box, then the two rects will match. |
196 | 0 | nsRect originalClientRect(clientRect); |
197 | 0 |
|
198 | 0 | // The frame state contains cached knowledge about our box, such as our orientation |
199 | 0 | // and direction. |
200 | 0 | nsFrameState frameState = nsFrameState(0); |
201 | 0 | GetFrameState(aBox, frameState); |
202 | 0 |
|
203 | 0 | // Build a list of our children's desired sizes and computed sizes |
204 | 0 | nsBoxSize* boxSizes = nullptr; |
205 | 0 | nsComputedBoxSize* computedBoxSizes = nullptr; |
206 | 0 |
|
207 | 0 | nscoord min = 0; |
208 | 0 | nscoord max = 0; |
209 | 0 | int32_t flexes = 0; |
210 | 0 | PopulateBoxSizes(aBox, aState, boxSizes, min, max, flexes); |
211 | 0 |
|
212 | 0 | // The |size| variable will hold the total size of children along the axis of |
213 | 0 | // the box. Continuing with the example begun in the comment above, size would |
214 | 0 | // be 150 pixels. |
215 | 0 | nscoord size = clientRect.width; |
216 | 0 | if (!IsXULHorizontal(aBox)) |
217 | 0 | size = clientRect.height; |
218 | 0 | ComputeChildSizes(aBox, aState, size, boxSizes, computedBoxSizes); |
219 | 0 |
|
220 | 0 | // After the call to ComputeChildSizes, the |size| variable contains the |
221 | 0 | // total required size of all the children. We adjust our clientRect in the |
222 | 0 | // appropriate dimension to match this size. In our example, we now assign |
223 | 0 | // 150 pixels into the clientRect.width. |
224 | 0 | // |
225 | 0 | // The variables |min| and |max| hold the minimum required size box must be |
226 | 0 | // in the OPPOSITE orientation, e.g., for a horizontal box, |min| is the minimum |
227 | 0 | // height we require to enclose our children, and |max| is the maximum height |
228 | 0 | // required to enclose our children. |
229 | 0 | if (IsXULHorizontal(aBox)) { |
230 | 0 | clientRect.width = size; |
231 | 0 | if (clientRect.height < min) |
232 | 0 | clientRect.height = min; |
233 | 0 |
|
234 | 0 | if (frameState & NS_STATE_AUTO_STRETCH) { |
235 | 0 | if (clientRect.height > max) |
236 | 0 | clientRect.height = max; |
237 | 0 | } |
238 | 0 | } else { |
239 | 0 | clientRect.height = size; |
240 | 0 | if (clientRect.width < min) |
241 | 0 | clientRect.width = min; |
242 | 0 |
|
243 | 0 | if (frameState & NS_STATE_AUTO_STRETCH) { |
244 | 0 | if (clientRect.width > max) |
245 | 0 | clientRect.width = max; |
246 | 0 | } |
247 | 0 | } |
248 | 0 |
|
249 | 0 | // With the sizes computed, now it's time to lay out our children. |
250 | 0 | bool finished; |
251 | 0 | nscoord passes = 0; |
252 | 0 |
|
253 | 0 | // We flow children at their preferred locations (along with the appropriate computed flex). |
254 | 0 | // After we flow a child, it is possible that the child will change its size. If/when this happens, |
255 | 0 | // we have to do another pass. Typically only 2 passes are required, but the code is prepared to |
256 | 0 | // do as many passes as are necessary to achieve equilibrium. |
257 | 0 | nscoord x = 0; |
258 | 0 | nscoord y = 0; |
259 | 0 | nscoord origX = 0; |
260 | 0 | nscoord origY = 0; |
261 | 0 |
|
262 | 0 | // |childResized| lets us know if a child changed its size after we attempted to lay it out at |
263 | 0 | // the specified size. If this happens, we usually have to do another pass. |
264 | 0 | bool childResized = false; |
265 | 0 |
|
266 | 0 | // |passes| stores our number of passes. If for any reason we end up doing more than, say, 10 |
267 | 0 | // passes, we assert to indicate that something is seriously screwed up. |
268 | 0 | passes = 0; |
269 | 0 | do |
270 | 0 | { |
271 | | #ifdef DEBUG_REFLOW |
272 | | if (passes > 0) { |
273 | | AddIndents(); |
274 | | printf("ChildResized doing pass: %d\n", passes); |
275 | | } |
276 | | #endif |
277 | |
|
278 | 0 | // Always assume that we're done. This will change if, for example, children don't stay |
279 | 0 | // the same size after being flowed. |
280 | 0 | finished = true; |
281 | 0 |
|
282 | 0 | // Handle box packing. |
283 | 0 | HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect); |
284 | 0 |
|
285 | 0 | // Now that packing is taken care of we set up a few additional |
286 | 0 | // tracking variables. |
287 | 0 | origX = x; |
288 | 0 | origY = y; |
289 | 0 |
|
290 | 0 | // Now we iterate over our box children and our box size lists in |
291 | 0 | // parallel. For each child, we look at its sizes and figure out |
292 | 0 | // where to place it. |
293 | 0 | nsComputedBoxSize* childComputedBoxSize = computedBoxSizes; |
294 | 0 | nsBoxSize* childBoxSize = boxSizes; |
295 | 0 |
|
296 | 0 | nsIFrame* child = nsBox::GetChildXULBox(aBox); |
297 | 0 |
|
298 | 0 | int32_t count = 0; |
299 | 0 | while (child || (childBoxSize && childBoxSize->bogus)) |
300 | 0 | { |
301 | 0 | // If for some reason, our lists are not the same length, we guard |
302 | 0 | // by bailing out of the loop. |
303 | 0 | if (childBoxSize == nullptr) { |
304 | 0 | MOZ_ASSERT_UNREACHABLE("Lists not the same length."); |
305 | 0 | break; |
306 | 0 | } |
307 | 0 |
|
308 | 0 | nscoord width = clientRect.width; |
309 | 0 | nscoord height = clientRect.height; |
310 | 0 |
|
311 | 0 | if (!childBoxSize->bogus) { |
312 | 0 | // We have a valid box size entry. This entry already contains information about our |
313 | 0 | // sizes along the axis of the box (e.g., widths in a horizontal box). If our default |
314 | 0 | // ALIGN is not stretch, however, then we also need to know the child's size along the |
315 | 0 | // opposite axis. |
316 | 0 | if (!(frameState & NS_STATE_AUTO_STRETCH)) { |
317 | 0 | nsSize prefSize = child->GetXULPrefSize(aState); |
318 | 0 | nsSize minSize = child->GetXULMinSize(aState); |
319 | 0 | nsSize maxSize = child->GetXULMaxSize(aState); |
320 | 0 | prefSize = nsBox::BoundsCheck(minSize, prefSize, maxSize); |
321 | 0 |
|
322 | 0 | AddMargin(child, prefSize); |
323 | 0 | width = std::min(prefSize.width, originalClientRect.width); |
324 | 0 | height = std::min(prefSize.height, originalClientRect.height); |
325 | 0 | } |
326 | 0 | } |
327 | 0 |
|
328 | 0 | // Obtain the computed size along the axis of the box for this child from the computedBoxSize entry. |
329 | 0 | // We store the result in |width| for horizontal boxes and |height| for vertical boxes. |
330 | 0 | if (frameState & NS_STATE_IS_HORIZONTAL) |
331 | 0 | width = childComputedBoxSize->size; |
332 | 0 | else |
333 | 0 | height = childComputedBoxSize->size; |
334 | 0 |
|
335 | 0 | // Adjust our x/y for the left/right spacing. |
336 | 0 | if (frameState & NS_STATE_IS_HORIZONTAL) { |
337 | 0 | if (frameState & NS_STATE_IS_DIRECTION_NORMAL) |
338 | 0 | x += (childBoxSize->left); |
339 | 0 | else |
340 | 0 | x -= (childBoxSize->right); |
341 | 0 | } else { |
342 | 0 | if (frameState & NS_STATE_IS_DIRECTION_NORMAL) |
343 | 0 | y += (childBoxSize->left); |
344 | 0 | else |
345 | 0 | y -= (childBoxSize->right); |
346 | 0 | } |
347 | 0 |
|
348 | 0 | // Now we build a child rect. |
349 | 0 | nscoord rectX = x; |
350 | 0 | nscoord rectY = y; |
351 | 0 | if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) { |
352 | 0 | if (frameState & NS_STATE_IS_HORIZONTAL) |
353 | 0 | rectX -= width; |
354 | 0 | else |
355 | 0 | rectY -= height; |
356 | 0 | } |
357 | 0 |
|
358 | 0 | // We now create an accurate child rect based off our computed size information. |
359 | 0 | nsRect childRect(rectX, rectY, width, height); |
360 | 0 |
|
361 | 0 | // Sanity check against our clientRect. It is possible that a child specified |
362 | 0 | // a size that is too large to fit. If that happens, then we have to grow |
363 | 0 | // our client rect. Remember, clientRect is not the total rect of the enclosing |
364 | 0 | // box. It currently holds our perception of how big the children needed to |
365 | 0 | // be. |
366 | 0 | if (childRect.width > clientRect.width) |
367 | 0 | clientRect.width = childRect.width; |
368 | 0 |
|
369 | 0 | if (childRect.height > clientRect.height) |
370 | 0 | clientRect.height = childRect.height; |
371 | 0 |
|
372 | 0 | // Either |nextX| or |nextY| is updated by this function call, according |
373 | 0 | // to our axis. |
374 | 0 | nscoord nextX = x; |
375 | 0 | nscoord nextY = y; |
376 | 0 |
|
377 | 0 | ComputeChildsNextPosition(aBox, x, y, nextX, nextY, childRect); |
378 | 0 |
|
379 | 0 | // Now we further update our nextX/Y along our axis. |
380 | 0 | // We also set childRect.y/x along the opposite axis appropriately for a |
381 | 0 | // stretch alignment. (Non-stretch alignment is handled below.) |
382 | 0 | if (frameState & NS_STATE_IS_HORIZONTAL) { |
383 | 0 | if (frameState & NS_STATE_IS_DIRECTION_NORMAL) |
384 | 0 | nextX += (childBoxSize->right); |
385 | 0 | else |
386 | 0 | nextX -= (childBoxSize->left); |
387 | 0 | childRect.y = originalClientRect.y; |
388 | 0 | } |
389 | 0 | else { |
390 | 0 | if (frameState & NS_STATE_IS_DIRECTION_NORMAL) |
391 | 0 | nextY += (childBoxSize->right); |
392 | 0 | else |
393 | 0 | nextY -= (childBoxSize->left); |
394 | 0 | if (GetFrameDirection(aBox) == NS_STYLE_DIRECTION_LTR) { |
395 | 0 | childRect.x = originalClientRect.x; |
396 | 0 | } else { |
397 | 0 | // keep the right edge of the box the same |
398 | 0 | childRect.x = clientRect.x + originalClientRect.width - childRect.width; |
399 | 0 | } |
400 | 0 | } |
401 | 0 |
|
402 | 0 | // If we encounter a completely bogus box size, we just leave this child completely |
403 | 0 | // alone and continue through the loop to the next child. |
404 | 0 | if (childBoxSize->bogus) |
405 | 0 | { |
406 | 0 | childComputedBoxSize = childComputedBoxSize->next; |
407 | 0 | childBoxSize = childBoxSize->next; |
408 | 0 | count++; |
409 | 0 | x = nextX; |
410 | 0 | y = nextY; |
411 | 0 | continue; |
412 | 0 | } |
413 | 0 | |
414 | 0 | nsMargin margin(0,0,0,0); |
415 | 0 |
|
416 | 0 | bool layout = true; |
417 | 0 |
|
418 | 0 | // Deflate the rect of our child by its margin. |
419 | 0 | child->GetXULMargin(margin); |
420 | 0 | childRect.Deflate(margin); |
421 | 0 | if (childRect.width < 0) |
422 | 0 | childRect.width = 0; |
423 | 0 | if (childRect.height < 0) |
424 | 0 | childRect.height = 0; |
425 | 0 |
|
426 | 0 | // Now we're trying to figure out if we have to lay out this child, i.e., to call |
427 | 0 | // the child's XULLayout method. |
428 | 0 | if (passes > 0) { |
429 | 0 | layout = false; |
430 | 0 | } else { |
431 | 0 | // Always perform layout if we are dirty or have dirty children |
432 | 0 | if (!NS_SUBTREE_DIRTY(child)) |
433 | 0 | layout = false; |
434 | 0 | } |
435 | 0 |
|
436 | 0 | nsRect oldRect(child->GetRect()); |
437 | 0 |
|
438 | 0 | // Non-stretch alignment will be handled in AlignChildren(), so don't |
439 | 0 | // change child out-of-axis positions yet. |
440 | 0 | if (!(frameState & NS_STATE_AUTO_STRETCH)) { |
441 | 0 | if (frameState & NS_STATE_IS_HORIZONTAL) { |
442 | 0 | childRect.y = oldRect.y; |
443 | 0 | } else { |
444 | 0 | childRect.x = oldRect.x; |
445 | 0 | } |
446 | 0 | } |
447 | 0 |
|
448 | 0 | // We computed a childRect. Now we want to set the bounds of the child to be that rect. |
449 | 0 | // If our old rect is different, then we know our size changed and we cache that fact |
450 | 0 | // in the |sizeChanged| variable. |
451 | 0 |
|
452 | 0 | child->SetXULBounds(aState, childRect); |
453 | 0 | bool sizeChanged = (childRect.width != oldRect.width || |
454 | 0 | childRect.height != oldRect.height); |
455 | 0 |
|
456 | 0 | if (sizeChanged) { |
457 | 0 | // Our size is different. Sanity check against our maximum allowed size to ensure |
458 | 0 | // we didn't exceed it. |
459 | 0 | nsSize minSize = child->GetXULMinSize(aState); |
460 | 0 | nsSize maxSize = child->GetXULMaxSize(aState); |
461 | 0 | maxSize = nsBox::BoundsCheckMinMax(minSize, maxSize); |
462 | 0 |
|
463 | 0 | // make sure the size is in our max size. |
464 | 0 | if (childRect.width > maxSize.width) |
465 | 0 | childRect.width = maxSize.width; |
466 | 0 |
|
467 | 0 | if (childRect.height > maxSize.height) |
468 | 0 | childRect.height = maxSize.height; |
469 | 0 |
|
470 | 0 | // set it again |
471 | 0 | child->SetXULBounds(aState, childRect); |
472 | 0 | } |
473 | 0 |
|
474 | 0 | // If we already determined that layout was required or if our size has changed, then |
475 | 0 | // we make sure to call layout on the child, since its children may need to be shifted |
476 | 0 | // around as a result of the size change. |
477 | 0 | if (layout || sizeChanged) |
478 | 0 | child->XULLayout(aState); |
479 | 0 |
|
480 | 0 | // If the child was a block or inline (e.g., HTML) it may have changed its rect *during* layout. |
481 | 0 | // We have to check for this. |
482 | 0 | nsRect newChildRect(child->GetRect()); |
483 | 0 |
|
484 | 0 | if (!newChildRect.IsEqualInterior(childRect)) { |
485 | | #ifdef DEBUG_GROW |
486 | | printf(" GREW from (%d,%d) -> (%d,%d)\n", childRect.width, childRect.height, newChildRect.width, newChildRect.height); |
487 | | #endif |
488 | | newChildRect.Inflate(margin); |
489 | 0 | childRect.Inflate(margin); |
490 | 0 |
|
491 | 0 | // The child changed size during layout. The ChildResized method handles this |
492 | 0 | // scenario. |
493 | 0 | ChildResized(aBox, |
494 | 0 | aState, |
495 | 0 | child, |
496 | 0 | childBoxSize, |
497 | 0 | childComputedBoxSize, |
498 | 0 | boxSizes, |
499 | 0 | computedBoxSizes, |
500 | 0 | childRect, |
501 | 0 | newChildRect, |
502 | 0 | clientRect, |
503 | 0 | flexes, |
504 | 0 | finished); |
505 | 0 |
|
506 | 0 | // We note that a child changed size, which means that another pass will be required. |
507 | 0 | childResized = true; |
508 | 0 |
|
509 | 0 | // Now that a child resized, it's entirely possible that OUR rect is too small. Now we |
510 | 0 | // ensure that |originalClientRect| is grown to accommodate the size of |clientRect|. |
511 | 0 | if (clientRect.width > originalClientRect.width) |
512 | 0 | originalClientRect.width = clientRect.width; |
513 | 0 |
|
514 | 0 | if (clientRect.height > originalClientRect.height) |
515 | 0 | originalClientRect.height = clientRect.height; |
516 | 0 |
|
517 | 0 | if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) { |
518 | 0 | // Our childRect had its XMost() or YMost() (depending on our layout |
519 | 0 | // direction), positioned at a certain point. Ensure that the |
520 | 0 | // newChildRect satisfies the same constraint. Note that this is |
521 | 0 | // just equivalent to adjusting the x/y by the difference in |
522 | 0 | // width/height between childRect and newChildRect. So we don't need |
523 | 0 | // to reaccount for the left and right of the box layout state again. |
524 | 0 | if (frameState & NS_STATE_IS_HORIZONTAL) |
525 | 0 | newChildRect.x = childRect.XMost() - newChildRect.width; |
526 | 0 | else |
527 | 0 | newChildRect.y = childRect.YMost() - newChildRect.height; |
528 | 0 | } |
529 | 0 |
|
530 | 0 | if (!(frameState & NS_STATE_IS_HORIZONTAL)) { |
531 | 0 | if (GetFrameDirection(aBox) != NS_STYLE_DIRECTION_LTR) { |
532 | 0 | // keep the right edge the same |
533 | 0 | newChildRect.x = childRect.XMost() - newChildRect.width; |
534 | 0 | } |
535 | 0 | } |
536 | 0 |
|
537 | 0 | // If the child resized then recompute its position. |
538 | 0 | ComputeChildsNextPosition(aBox, x, y, nextX, nextY, newChildRect); |
539 | 0 |
|
540 | 0 | if (newChildRect.width >= margin.left + margin.right && newChildRect.height >= margin.top + margin.bottom) |
541 | 0 | newChildRect.Deflate(margin); |
542 | 0 |
|
543 | 0 | if (childRect.width >= margin.left + margin.right && childRect.height >= margin.top + margin.bottom) |
544 | 0 | childRect.Deflate(margin); |
545 | 0 |
|
546 | 0 | child->SetXULBounds(aState, newChildRect); |
547 | 0 |
|
548 | 0 | // If we are the first box that changed size, then we don't need to do a second pass |
549 | 0 | if (count == 0) |
550 | 0 | finished = true; |
551 | 0 | } |
552 | 0 |
|
553 | 0 | // Now update our x/y finally. |
554 | 0 | x = nextX; |
555 | 0 | y = nextY; |
556 | 0 |
|
557 | 0 | // Move to the next child. |
558 | 0 | childComputedBoxSize = childComputedBoxSize->next; |
559 | 0 | childBoxSize = childBoxSize->next; |
560 | 0 |
|
561 | 0 | child = nsBox::GetNextXULBox(child); |
562 | 0 | count++; |
563 | 0 | } |
564 | 0 |
|
565 | 0 | // Sanity-checking code to ensure we don't do an infinite # of passes. |
566 | 0 | passes++; |
567 | 0 | NS_ASSERTION(passes < 10, "A Box's child is constantly growing!!!!!"); |
568 | 0 | if (passes >= 10) |
569 | 0 | break; |
570 | 0 | } while (false == finished); |
571 | 0 |
|
572 | 0 | // Get rid of our size lists. |
573 | 0 | while(boxSizes) |
574 | 0 | { |
575 | 0 | nsBoxSize* toDelete = boxSizes; |
576 | 0 | boxSizes = boxSizes->next; |
577 | 0 | delete toDelete; |
578 | 0 | } |
579 | 0 |
|
580 | 0 | while(computedBoxSizes) |
581 | 0 | { |
582 | 0 | nsComputedBoxSize* toDelete = computedBoxSizes; |
583 | 0 | computedBoxSizes = computedBoxSizes->next; |
584 | 0 | delete toDelete; |
585 | 0 | } |
586 | 0 |
|
587 | 0 | if (childResized) { |
588 | 0 | // See if one of our children forced us to get bigger |
589 | 0 | nsRect tmpClientRect(originalClientRect); |
590 | 0 | nsMargin bp(0,0,0,0); |
591 | 0 | aBox->GetXULBorderAndPadding(bp); |
592 | 0 | tmpClientRect.Inflate(bp); |
593 | 0 |
|
594 | 0 | if (tmpClientRect.width > originalSize.width || tmpClientRect.height > originalSize.height) |
595 | 0 | { |
596 | 0 | // if it did reset our bounds. |
597 | 0 | nsRect bounds(aBox->GetRect()); |
598 | 0 | if (tmpClientRect.width > originalSize.width) |
599 | 0 | bounds.width = tmpClientRect.width; |
600 | 0 |
|
601 | 0 | if (tmpClientRect.height > originalSize.height) |
602 | 0 | bounds.height = tmpClientRect.height; |
603 | 0 |
|
604 | 0 | aBox->SetXULBounds(aState, bounds); |
605 | 0 | } |
606 | 0 | } |
607 | 0 |
|
608 | 0 | // Because our size grew, we now have to readjust because of box packing. Repack |
609 | 0 | // in order to update our x and y to the correct values. |
610 | 0 | HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect); |
611 | 0 |
|
612 | 0 | // Compare against our original x and y and only worry about adjusting the children if |
613 | 0 | // we really did have to change the positions because of packing (typically for 'center' |
614 | 0 | // or 'end' pack values). |
615 | 0 | if (x != origX || y != origY) { |
616 | 0 | nsIFrame* child = nsBox::GetChildXULBox(aBox); |
617 | 0 |
|
618 | 0 | // reposition all our children |
619 | 0 | while (child) |
620 | 0 | { |
621 | 0 | nsRect childRect(child->GetRect()); |
622 | 0 | childRect.x += (x - origX); |
623 | 0 | childRect.y += (y - origY); |
624 | 0 | child->SetXULBounds(aState, childRect); |
625 | 0 | child = nsBox::GetNextXULBox(child); |
626 | 0 | } |
627 | 0 | } |
628 | 0 |
|
629 | 0 | // Perform out-of-axis alignment for non-stretch alignments |
630 | 0 | if (!(frameState & NS_STATE_AUTO_STRETCH)) { |
631 | 0 | AlignChildren(aBox, aState); |
632 | 0 | } |
633 | 0 |
|
634 | 0 | // That's it! If you made it this far without having a nervous breakdown, |
635 | 0 | // congratulations! Go get yourself a beer. |
636 | 0 | return NS_OK; |
637 | 0 | } |
638 | | |
639 | | void |
640 | | nsSprocketLayout::PopulateBoxSizes(nsIFrame* aBox, nsBoxLayoutState& aState, nsBoxSize*& aBoxSizes, nscoord& aMinSize, nscoord& aMaxSize, int32_t& aFlexes) |
641 | 0 | { |
642 | 0 | // used for the equal size flag |
643 | 0 | nscoord biggestPrefWidth = 0; |
644 | 0 | nscoord biggestMinWidth = 0; |
645 | 0 | nscoord smallestMaxWidth = NS_INTRINSICSIZE; |
646 | 0 |
|
647 | 0 | nsFrameState frameState = nsFrameState(0); |
648 | 0 | GetFrameState(aBox, frameState); |
649 | 0 |
|
650 | 0 | aMinSize = 0; |
651 | 0 | aMaxSize = NS_INTRINSICSIZE; |
652 | 0 |
|
653 | 0 | bool isHorizontal; |
654 | 0 |
|
655 | 0 | if (IsXULHorizontal(aBox)) |
656 | 0 | isHorizontal = true; |
657 | 0 | else |
658 | 0 | isHorizontal = false; |
659 | 0 |
|
660 | 0 | // this is a nice little optimization |
661 | 0 | // it turns out that if we only have 1 flexable child |
662 | 0 | // then it does not matter what its preferred size is |
663 | 0 | // there is nothing to flex it relative. This is great |
664 | 0 | // because we can avoid asking for a preferred size in this |
665 | 0 | // case. Why is this good? Well you might have html inside it |
666 | 0 | // and asking html for its preferred size is rather expensive. |
667 | 0 | // so we can just optimize it out this way. |
668 | 0 |
|
669 | 0 | // set flexes |
670 | 0 | nsIFrame* child = nsBox::GetChildXULBox(aBox); |
671 | 0 |
|
672 | 0 | aFlexes = 0; |
673 | 0 | nsBoxSize* currentBox = nullptr; |
674 | 0 |
|
675 | | #if 0 |
676 | | nsBoxSize* start = aBoxSizes; |
677 | | |
678 | | while(child) |
679 | | { |
680 | | // ok if we started with a list move down the list |
681 | | // until we reach the end. Then start looking at childen. |
682 | | // This feature is used extensively for Grid. |
683 | | nscoord flex = 0; |
684 | | |
685 | | if (!start) { |
686 | | if (!currentBox) { |
687 | | aBoxSizes = new (aState) nsBoxSize(); |
688 | | currentBox = aBoxSizes; |
689 | | } else { |
690 | | currentBox->next = new (aState) nsBoxSize(); |
691 | | currentBox = currentBox->next; |
692 | | } |
693 | | |
694 | | |
695 | | flex = child->GetXULFlex(); |
696 | | |
697 | | currentBox->flex = flex; |
698 | | currentBox->collapsed = child->IsXULCollapsed(); |
699 | | } else { |
700 | | flex = start->flex; |
701 | | start = start->next; |
702 | | } |
703 | | |
704 | | if (flex > 0) |
705 | | aFlexes++; |
706 | | |
707 | | child = GetNextXULBox(child); |
708 | | } |
709 | | #endif |
710 | |
|
711 | 0 | // get pref, min, max |
712 | 0 | child = nsBox::GetChildXULBox(aBox); |
713 | 0 | currentBox = aBoxSizes; |
714 | 0 | nsBoxSize* last = nullptr; |
715 | 0 |
|
716 | 0 | nscoord maxFlex = 0; |
717 | 0 | int32_t childCount = 0; |
718 | 0 |
|
719 | 0 | while(child) |
720 | 0 | { |
721 | 0 | while (currentBox && currentBox->bogus) { |
722 | 0 | last = currentBox; |
723 | 0 | currentBox = currentBox->next; |
724 | 0 | } |
725 | 0 | ++childCount; |
726 | 0 | nsSize pref(0,0); |
727 | 0 | nsSize minSize(0,0); |
728 | 0 | nsSize maxSize(NS_INTRINSICSIZE,NS_INTRINSICSIZE); |
729 | 0 | bool collapsed = child->IsXULCollapsed(); |
730 | 0 |
|
731 | 0 | if (!collapsed) { |
732 | 0 | // only one flexible child? Cool we will just make its preferred size |
733 | 0 | // 0 then and not even have to ask for it. |
734 | 0 | //if (flexes != 1) { |
735 | 0 |
|
736 | 0 | pref = child->GetXULPrefSize(aState); |
737 | 0 | minSize = child->GetXULMinSize(aState); |
738 | 0 | maxSize = nsBox::BoundsCheckMinMax(minSize, child->GetXULMaxSize(aState)); |
739 | 0 | child->GetXULBoxAscent(aState); |
740 | 0 | //} |
741 | 0 |
|
742 | 0 | pref = nsBox::BoundsCheck(minSize, pref, maxSize); |
743 | 0 |
|
744 | 0 | AddMargin(child, pref); |
745 | 0 | AddMargin(child, minSize); |
746 | 0 | AddMargin(child, maxSize); |
747 | 0 | } |
748 | 0 |
|
749 | 0 | if (!currentBox) { |
750 | 0 | // create one. |
751 | 0 | currentBox = new (aState) nsBoxSize(); |
752 | 0 | if (!aBoxSizes) { |
753 | 0 | aBoxSizes = currentBox; |
754 | 0 | last = aBoxSizes; |
755 | 0 | } else { |
756 | 0 | last->next = currentBox; |
757 | 0 | last = currentBox; |
758 | 0 | } |
759 | 0 |
|
760 | 0 | nscoord minWidth; |
761 | 0 | nscoord maxWidth; |
762 | 0 | nscoord prefWidth; |
763 | 0 |
|
764 | 0 | // get sizes from child |
765 | 0 | if (isHorizontal) { |
766 | 0 | minWidth = minSize.width; |
767 | 0 | maxWidth = maxSize.width; |
768 | 0 | prefWidth = pref.width; |
769 | 0 | } else { |
770 | 0 | minWidth = minSize.height; |
771 | 0 | maxWidth = maxSize.height; |
772 | 0 | prefWidth = pref.height; |
773 | 0 | } |
774 | 0 |
|
775 | 0 | nscoord flex = child->GetXULFlex(); |
776 | 0 |
|
777 | 0 | // set them if you collapsed you are not flexible. |
778 | 0 | if (collapsed) { |
779 | 0 | currentBox->flex = 0; |
780 | 0 | } |
781 | 0 | else { |
782 | 0 | if (flex > maxFlex) { |
783 | 0 | maxFlex = flex; |
784 | 0 | } |
785 | 0 | currentBox->flex = flex; |
786 | 0 | } |
787 | 0 |
|
788 | 0 | // we specified all our children are equal size; |
789 | 0 | if (frameState & NS_STATE_EQUAL_SIZE) { |
790 | 0 |
|
791 | 0 | if (prefWidth > biggestPrefWidth) |
792 | 0 | biggestPrefWidth = prefWidth; |
793 | 0 |
|
794 | 0 | if (minWidth > biggestMinWidth) |
795 | 0 | biggestMinWidth = minWidth; |
796 | 0 |
|
797 | 0 | if (maxWidth < smallestMaxWidth) |
798 | 0 | smallestMaxWidth = maxWidth; |
799 | 0 | } else { // not we can set our children right now. |
800 | 0 | currentBox->pref = prefWidth; |
801 | 0 | currentBox->min = minWidth; |
802 | 0 | currentBox->max = maxWidth; |
803 | 0 | } |
804 | 0 |
|
805 | 0 | NS_ASSERTION(minWidth <= prefWidth && prefWidth <= maxWidth,"Bad min, pref, max widths!"); |
806 | 0 |
|
807 | 0 | } |
808 | 0 |
|
809 | 0 | if (!isHorizontal) { |
810 | 0 | if (minSize.width > aMinSize) |
811 | 0 | aMinSize = minSize.width; |
812 | 0 |
|
813 | 0 | if (maxSize.width < aMaxSize) |
814 | 0 | aMaxSize = maxSize.width; |
815 | 0 |
|
816 | 0 | } else { |
817 | 0 | if (minSize.height > aMinSize) |
818 | 0 | aMinSize = minSize.height; |
819 | 0 |
|
820 | 0 | if (maxSize.height < aMaxSize) |
821 | 0 | aMaxSize = maxSize.height; |
822 | 0 | } |
823 | 0 |
|
824 | 0 | currentBox->collapsed = collapsed; |
825 | 0 | aFlexes += currentBox->flex; |
826 | 0 |
|
827 | 0 | child = nsBox::GetNextXULBox(child); |
828 | 0 |
|
829 | 0 | last = currentBox; |
830 | 0 | currentBox = currentBox->next; |
831 | 0 |
|
832 | 0 | } |
833 | 0 |
|
834 | 0 | if (childCount > 0) { |
835 | 0 | nscoord maxAllowedFlex = nscoord_MAX / childCount; |
836 | 0 |
|
837 | 0 | if (MOZ_UNLIKELY(maxFlex > maxAllowedFlex)) { |
838 | 0 | // clamp all the flexes |
839 | 0 | currentBox = aBoxSizes; |
840 | 0 | while (currentBox) { |
841 | 0 | currentBox->flex = std::min(currentBox->flex, maxAllowedFlex); |
842 | 0 | currentBox = currentBox->next; |
843 | 0 | } |
844 | 0 | } |
845 | 0 | } |
846 | | #ifdef DEBUG |
847 | | else { |
848 | | NS_ASSERTION(maxFlex == 0, "How did that happen?"); |
849 | | } |
850 | | #endif |
851 | |
|
852 | 0 | // we specified all our children are equal size; |
853 | 0 | if (frameState & NS_STATE_EQUAL_SIZE) { |
854 | 0 | smallestMaxWidth = std::max(smallestMaxWidth, biggestMinWidth); |
855 | 0 | biggestPrefWidth = nsBox::BoundsCheck(biggestMinWidth, biggestPrefWidth, smallestMaxWidth); |
856 | 0 |
|
857 | 0 | currentBox = aBoxSizes; |
858 | 0 |
|
859 | 0 | while(currentBox) |
860 | 0 | { |
861 | 0 | if (!currentBox->collapsed) { |
862 | 0 | currentBox->pref = biggestPrefWidth; |
863 | 0 | currentBox->min = biggestMinWidth; |
864 | 0 | currentBox->max = smallestMaxWidth; |
865 | 0 | } else { |
866 | 0 | currentBox->pref = 0; |
867 | 0 | currentBox->min = 0; |
868 | 0 | currentBox->max = 0; |
869 | 0 | } |
870 | 0 | currentBox = currentBox->next; |
871 | 0 | } |
872 | 0 | } |
873 | 0 |
|
874 | 0 | } |
875 | | |
876 | | void |
877 | | nsSprocketLayout::ComputeChildsNextPosition(nsIFrame* aBox, |
878 | | const nscoord& aCurX, |
879 | | const nscoord& aCurY, |
880 | | nscoord& aNextX, |
881 | | nscoord& aNextY, |
882 | | const nsRect& aCurrentChildSize) |
883 | 0 | { |
884 | 0 | // Get the position along the box axis for the child. |
885 | 0 | // The out-of-axis position is not set. |
886 | 0 | nsFrameState frameState = nsFrameState(0); |
887 | 0 | GetFrameState(aBox, frameState); |
888 | 0 |
|
889 | 0 | if (IsXULHorizontal(aBox)) { |
890 | 0 | // horizontal box's children. |
891 | 0 | if (frameState & NS_STATE_IS_DIRECTION_NORMAL) |
892 | 0 | aNextX = aCurX + aCurrentChildSize.width; |
893 | 0 | else |
894 | 0 | aNextX = aCurX - aCurrentChildSize.width; |
895 | 0 |
|
896 | 0 | } else { |
897 | 0 | // vertical box's children. |
898 | 0 | if (frameState & NS_STATE_IS_DIRECTION_NORMAL) |
899 | 0 | aNextY = aCurY + aCurrentChildSize.height; |
900 | 0 | else |
901 | 0 | aNextY = aCurY - aCurrentChildSize.height; |
902 | 0 | } |
903 | 0 | } |
904 | | |
905 | | void |
906 | | nsSprocketLayout::AlignChildren(nsIFrame* aBox, |
907 | | nsBoxLayoutState& aState) |
908 | 0 | { |
909 | 0 | nsFrameState frameState = nsFrameState(0); |
910 | 0 | GetFrameState(aBox, frameState); |
911 | 0 | bool isHorizontal = (frameState & NS_STATE_IS_HORIZONTAL) != 0; |
912 | 0 | nsRect clientRect; |
913 | 0 | aBox->GetXULClientRect(clientRect); |
914 | 0 |
|
915 | 0 | MOZ_ASSERT(!(frameState & NS_STATE_AUTO_STRETCH), |
916 | 0 | "Only AlignChildren() with non-stretch alignment"); |
917 | 0 |
|
918 | 0 | // These are only calculated if needed |
919 | 0 | nsIFrame::Halignment halign; |
920 | 0 | nsIFrame::Valignment valign; |
921 | 0 | nscoord maxAscent = 0; |
922 | 0 | bool isLTR; |
923 | 0 |
|
924 | 0 | if (isHorizontal) { |
925 | 0 | valign = aBox->GetXULVAlign(); |
926 | 0 | if (valign == nsBoxFrame::vAlign_BaseLine) { |
927 | 0 | maxAscent = aBox->GetXULBoxAscent(aState); |
928 | 0 | } |
929 | 0 | } else { |
930 | 0 | isLTR = GetFrameDirection(aBox) == NS_STYLE_DIRECTION_LTR; |
931 | 0 | halign = aBox->GetXULHAlign(); |
932 | 0 | } |
933 | 0 |
|
934 | 0 | nsIFrame* child = nsBox::GetChildXULBox(aBox); |
935 | 0 | while (child) { |
936 | 0 |
|
937 | 0 | nsMargin margin; |
938 | 0 | child->GetXULMargin(margin); |
939 | 0 | nsRect childRect = child->GetRect(); |
940 | 0 |
|
941 | 0 | if (isHorizontal) { |
942 | 0 | const nscoord startAlign = clientRect.y + margin.top; |
943 | 0 | const nscoord endAlign = |
944 | 0 | clientRect.YMost() - margin.bottom - childRect.height; |
945 | 0 |
|
946 | 0 | nscoord y = 0; |
947 | 0 | switch (valign) { |
948 | 0 | case nsBoxFrame::vAlign_Top: |
949 | 0 | y = startAlign; |
950 | 0 | break; |
951 | 0 | case nsBoxFrame::vAlign_Middle: |
952 | 0 | // Should this center the border box? |
953 | 0 | // This centers the margin box, the historical behavior. |
954 | 0 | y = (startAlign + endAlign) / 2; |
955 | 0 | break; |
956 | 0 | case nsBoxFrame::vAlign_Bottom: |
957 | 0 | y = endAlign; |
958 | 0 | break; |
959 | 0 | case nsBoxFrame::vAlign_BaseLine: |
960 | 0 | // Alignments don't force the box to grow (only sizes do), |
961 | 0 | // so keep the children within the box. |
962 | 0 | y = maxAscent - child->GetXULBoxAscent(aState); |
963 | 0 | y = std::max(startAlign, y); |
964 | 0 | y = std::min(y, endAlign); |
965 | 0 | break; |
966 | 0 | } |
967 | 0 | |
968 | 0 | childRect.y = y; |
969 | 0 |
|
970 | 0 | } else { // vertical box |
971 | 0 | const nscoord leftAlign = clientRect.x + margin.left; |
972 | 0 | const nscoord rightAlign = |
973 | 0 | clientRect.XMost() - margin.right - childRect.width; |
974 | 0 |
|
975 | 0 | nscoord x = 0; |
976 | 0 | switch (halign) { |
977 | 0 | case nsBoxFrame::hAlign_Left: // start |
978 | 0 | x = isLTR ? leftAlign : rightAlign; |
979 | 0 | break; |
980 | 0 | case nsBoxFrame::hAlign_Center: |
981 | 0 | x = (leftAlign + rightAlign) / 2; |
982 | 0 | break; |
983 | 0 | case nsBoxFrame::hAlign_Right: // end |
984 | 0 | x = isLTR ? rightAlign : leftAlign; |
985 | 0 | break; |
986 | 0 | } |
987 | 0 |
|
988 | 0 | childRect.x = x; |
989 | 0 | } |
990 | 0 |
|
991 | 0 | if (childRect.TopLeft() != child->GetPosition()) { |
992 | 0 | child->SetXULBounds(aState, childRect); |
993 | 0 | } |
994 | 0 |
|
995 | 0 | child = nsBox::GetNextXULBox(child); |
996 | 0 | } |
997 | 0 | } |
998 | | |
999 | | void |
1000 | | nsSprocketLayout::ChildResized(nsIFrame* aBox, |
1001 | | nsBoxLayoutState& aState, |
1002 | | nsIFrame* aChild, |
1003 | | nsBoxSize* aChildBoxSize, |
1004 | | nsComputedBoxSize* aChildComputedSize, |
1005 | | nsBoxSize* aBoxSizes, |
1006 | | nsComputedBoxSize* aComputedBoxSizes, |
1007 | | const nsRect& aChildLayoutRect, |
1008 | | nsRect& aChildActualRect, |
1009 | | nsRect& aContainingRect, |
1010 | | int32_t aFlexes, |
1011 | | bool& aFinished) |
1012 | | |
1013 | 0 | { |
1014 | 0 | nsRect childCurrentRect(aChildLayoutRect); |
1015 | 0 |
|
1016 | 0 | bool isHorizontal = IsXULHorizontal(aBox); |
1017 | 0 | nscoord childLayoutWidth = GET_WIDTH(aChildLayoutRect,isHorizontal); |
1018 | 0 | nscoord& childActualWidth = GET_WIDTH(aChildActualRect,isHorizontal); |
1019 | 0 | nscoord& containingWidth = GET_WIDTH(aContainingRect,isHorizontal); |
1020 | 0 |
|
1021 | 0 | //nscoord childLayoutHeight = GET_HEIGHT(aChildLayoutRect,isHorizontal); |
1022 | 0 | nscoord& childActualHeight = GET_HEIGHT(aChildActualRect,isHorizontal); |
1023 | 0 | nscoord& containingHeight = GET_HEIGHT(aContainingRect,isHorizontal); |
1024 | 0 |
|
1025 | 0 | bool recompute = false; |
1026 | 0 |
|
1027 | 0 | // if we are a horizontal box see if the child will fit inside us. |
1028 | 0 | if ( childActualHeight > containingHeight) { |
1029 | 0 | // if we are a horizontal box and the child is bigger than our height |
1030 | 0 |
|
1031 | 0 | // ok if the height changed then we need to reflow everyone but us at the new height |
1032 | 0 | // so we will set the changed index to be us. And signal that we need a new pass. |
1033 | 0 |
|
1034 | 0 | nsSize min = aChild->GetXULMinSize(aState); |
1035 | 0 | nsSize max = nsBox::BoundsCheckMinMax(min, aChild->GetXULMaxSize(aState)); |
1036 | 0 | AddMargin(aChild, max); |
1037 | 0 |
|
1038 | 0 | if (isHorizontal) |
1039 | 0 | childActualHeight = max.height < childActualHeight ? max.height : childActualHeight; |
1040 | 0 | else |
1041 | 0 | childActualHeight = max.width < childActualHeight ? max.width : childActualHeight; |
1042 | 0 |
|
1043 | 0 | // only set if it changes |
1044 | 0 | if (childActualHeight > containingHeight) { |
1045 | 0 | containingHeight = childActualHeight; |
1046 | 0 |
|
1047 | 0 | // remember we do not need to clear the resized list because changing the height of a horizontal box |
1048 | 0 | // will not affect the width of any of its children because block flow left to right, top to bottom. Just trust me |
1049 | 0 | // on this one. |
1050 | 0 | aFinished = false; |
1051 | 0 |
|
1052 | 0 | // only recompute if there are flexes. |
1053 | 0 | if (aFlexes > 0) { |
1054 | 0 | // relayout everything |
1055 | 0 | recompute = true; |
1056 | 0 | InvalidateComputedSizes(aComputedBoxSizes); |
1057 | 0 | nsComputedBoxSize* node = aComputedBoxSizes; |
1058 | 0 |
|
1059 | 0 | while(node) { |
1060 | 0 | node->resized = false; |
1061 | 0 | node = node->next; |
1062 | 0 | } |
1063 | 0 |
|
1064 | 0 | } |
1065 | 0 | } |
1066 | 0 | } |
1067 | 0 |
|
1068 | 0 | if (childActualWidth > childLayoutWidth) { |
1069 | 0 | nsSize min = aChild->GetXULMinSize(aState); |
1070 | 0 | nsSize max = nsBox::BoundsCheckMinMax(min, aChild->GetXULMaxSize(aState)); |
1071 | 0 |
|
1072 | 0 | AddMargin(aChild, max); |
1073 | 0 |
|
1074 | 0 | // our width now becomes the new size |
1075 | 0 |
|
1076 | 0 | if (isHorizontal) |
1077 | 0 | childActualWidth = max.width < childActualWidth ? max.width : childActualWidth; |
1078 | 0 | else |
1079 | 0 | childActualWidth = max.height < childActualWidth ? max.height : childActualWidth; |
1080 | 0 |
|
1081 | 0 | if (childActualWidth > childLayoutWidth) { |
1082 | 0 | aChildComputedSize->size = childActualWidth; |
1083 | 0 | aChildBoxSize->min = childActualWidth; |
1084 | 0 | if (aChildBoxSize->pref < childActualWidth) |
1085 | 0 | aChildBoxSize->pref = childActualWidth; |
1086 | 0 | if (aChildBoxSize->max < childActualWidth) |
1087 | 0 | aChildBoxSize->max = childActualWidth; |
1088 | 0 |
|
1089 | 0 | // if we have flexible elements with us then reflex things. Otherwise we can skip doing it. |
1090 | 0 | if (aFlexes > 0) { |
1091 | 0 | InvalidateComputedSizes(aComputedBoxSizes); |
1092 | 0 |
|
1093 | 0 | nsComputedBoxSize* node = aComputedBoxSizes; |
1094 | 0 | aChildComputedSize->resized = true; |
1095 | 0 |
|
1096 | 0 | while(node) { |
1097 | 0 | if (node->resized) |
1098 | 0 | node->valid = true; |
1099 | 0 |
|
1100 | 0 | node = node->next; |
1101 | 0 | } |
1102 | 0 |
|
1103 | 0 | recompute = true; |
1104 | 0 | aFinished = false; |
1105 | 0 | } else { |
1106 | 0 | containingWidth += aChildComputedSize->size - childLayoutWidth; |
1107 | 0 | } |
1108 | 0 | } |
1109 | 0 | } |
1110 | 0 |
|
1111 | 0 | if (recompute) |
1112 | 0 | ComputeChildSizes(aBox, aState, containingWidth, aBoxSizes, aComputedBoxSizes); |
1113 | 0 |
|
1114 | 0 | if (!childCurrentRect.IsEqualInterior(aChildActualRect)) { |
1115 | 0 | // the childRect includes the margin |
1116 | 0 | // make sure we remove it before setting |
1117 | 0 | // the bounds. |
1118 | 0 | nsMargin margin(0,0,0,0); |
1119 | 0 | aChild->GetXULMargin(margin); |
1120 | 0 | nsRect rect(aChildActualRect); |
1121 | 0 | if (rect.width >= margin.left + margin.right && rect.height >= margin.top + margin.bottom) |
1122 | 0 | rect.Deflate(margin); |
1123 | 0 |
|
1124 | 0 | aChild->SetXULBounds(aState, rect); |
1125 | 0 | aChild->XULLayout(aState); |
1126 | 0 | } |
1127 | 0 |
|
1128 | 0 | } |
1129 | | |
1130 | | void |
1131 | | nsSprocketLayout::InvalidateComputedSizes(nsComputedBoxSize* aComputedBoxSizes) |
1132 | 0 | { |
1133 | 0 | while(aComputedBoxSizes) { |
1134 | 0 | aComputedBoxSizes->valid = false; |
1135 | 0 | aComputedBoxSizes = aComputedBoxSizes->next; |
1136 | 0 | } |
1137 | 0 | } |
1138 | | |
1139 | | void |
1140 | | nsSprocketLayout::ComputeChildSizes(nsIFrame* aBox, |
1141 | | nsBoxLayoutState& aState, |
1142 | | nscoord& aGivenSize, |
1143 | | nsBoxSize* aBoxSizes, |
1144 | | nsComputedBoxSize*& aComputedBoxSizes) |
1145 | 0 | { |
1146 | 0 |
|
1147 | 0 | //nscoord onePixel = aState.PresContext()->IntScaledPixelsToTwips(1); |
1148 | 0 |
|
1149 | 0 | int32_t sizeRemaining = aGivenSize; |
1150 | 0 | int32_t spacerConstantsRemaining = 0; |
1151 | 0 |
|
1152 | 0 | // ----- calculate the spacers constants and the size remaining ----- |
1153 | 0 |
|
1154 | 0 | if (!aComputedBoxSizes) |
1155 | 0 | aComputedBoxSizes = new (aState) nsComputedBoxSize(); |
1156 | 0 |
|
1157 | 0 | nsBoxSize* boxSizes = aBoxSizes; |
1158 | 0 | nsComputedBoxSize* computedBoxSizes = aComputedBoxSizes; |
1159 | 0 | int32_t count = 0; |
1160 | 0 | int32_t validCount = 0; |
1161 | 0 |
|
1162 | 0 | while (boxSizes) |
1163 | 0 | { |
1164 | 0 |
|
1165 | 0 | NS_ASSERTION((boxSizes->min <= boxSizes->pref && boxSizes->pref <= boxSizes->max),"bad pref, min, max size"); |
1166 | 0 |
|
1167 | 0 |
|
1168 | 0 | // ignore collapsed children |
1169 | 0 | // if (boxSizes->collapsed) |
1170 | 0 | // { |
1171 | 0 | // computedBoxSizes->valid = true; |
1172 | 0 | // computedBoxSizes->size = boxSizes->pref; |
1173 | 0 | // validCount++; |
1174 | 0 | // boxSizes->flex = 0; |
1175 | 0 | // }// else { |
1176 | 0 |
|
1177 | 0 | if (computedBoxSizes->valid) { |
1178 | 0 | sizeRemaining -= computedBoxSizes->size; |
1179 | 0 | validCount++; |
1180 | 0 | } else { |
1181 | 0 | if (boxSizes->flex == 0) |
1182 | 0 | { |
1183 | 0 | computedBoxSizes->valid = true; |
1184 | 0 | computedBoxSizes->size = boxSizes->pref; |
1185 | 0 | validCount++; |
1186 | 0 | } |
1187 | 0 |
|
1188 | 0 | spacerConstantsRemaining += boxSizes->flex; |
1189 | 0 | sizeRemaining -= boxSizes->pref; |
1190 | 0 | } |
1191 | 0 |
|
1192 | 0 | sizeRemaining -= (boxSizes->left + boxSizes->right); |
1193 | 0 |
|
1194 | 0 | //} |
1195 | 0 |
|
1196 | 0 | boxSizes = boxSizes->next; |
1197 | 0 |
|
1198 | 0 | if (boxSizes && !computedBoxSizes->next) |
1199 | 0 | computedBoxSizes->next = new (aState) nsComputedBoxSize(); |
1200 | 0 |
|
1201 | 0 | computedBoxSizes = computedBoxSizes->next; |
1202 | 0 | count++; |
1203 | 0 | } |
1204 | 0 |
|
1205 | 0 | // everything accounted for? |
1206 | 0 | if (validCount < count) |
1207 | 0 | { |
1208 | 0 | // ----- Ok we are give a size to fit into so stretch or squeeze to fit |
1209 | 0 | // ----- Make sure we look at our min and max size |
1210 | 0 | bool limit = true; |
1211 | 0 | for (int pass=1; true == limit; pass++) |
1212 | 0 | { |
1213 | 0 | limit = false; |
1214 | 0 | boxSizes = aBoxSizes; |
1215 | 0 | computedBoxSizes = aComputedBoxSizes; |
1216 | 0 |
|
1217 | 0 | while (boxSizes) { |
1218 | 0 |
|
1219 | 0 | // ignore collapsed spacers |
1220 | 0 |
|
1221 | 0 | // if (!boxSizes->collapsed) { |
1222 | 0 |
|
1223 | 0 | nscoord pref = 0; |
1224 | 0 | nscoord max = NS_INTRINSICSIZE; |
1225 | 0 | nscoord min = 0; |
1226 | 0 | nscoord flex = 0; |
1227 | 0 |
|
1228 | 0 | pref = boxSizes->pref; |
1229 | 0 | min = boxSizes->min; |
1230 | 0 | max = boxSizes->max; |
1231 | 0 | flex = boxSizes->flex; |
1232 | 0 |
|
1233 | 0 | // ----- look at our min and max limits make sure we aren't too small or too big ----- |
1234 | 0 | if (!computedBoxSizes->valid) { |
1235 | 0 | int32_t newSize = pref + int32_t(int64_t(sizeRemaining) * flex / spacerConstantsRemaining); |
1236 | 0 |
|
1237 | 0 | if (newSize<=min) { |
1238 | 0 | computedBoxSizes->size = min; |
1239 | 0 | computedBoxSizes->valid = true; |
1240 | 0 | spacerConstantsRemaining -= flex; |
1241 | 0 | sizeRemaining += pref; |
1242 | 0 | sizeRemaining -= min; |
1243 | 0 | limit = true; |
1244 | 0 | } else if (newSize>=max) { |
1245 | 0 | computedBoxSizes->size = max; |
1246 | 0 | computedBoxSizes->valid = true; |
1247 | 0 | spacerConstantsRemaining -= flex; |
1248 | 0 | sizeRemaining += pref; |
1249 | 0 | sizeRemaining -= max; |
1250 | 0 | limit = true; |
1251 | 0 | } |
1252 | 0 | } |
1253 | 0 | // } |
1254 | 0 | boxSizes = boxSizes->next; |
1255 | 0 | computedBoxSizes = computedBoxSizes->next; |
1256 | 0 | } |
1257 | 0 | } |
1258 | 0 | } |
1259 | 0 |
|
1260 | 0 | // ---- once we have removed and min and max issues just stretch us out in the remaining space |
1261 | 0 | // ---- or shrink us. Depends on the size remaining and the spacer constants |
1262 | 0 | aGivenSize = 0; |
1263 | 0 | boxSizes = aBoxSizes; |
1264 | 0 | computedBoxSizes = aComputedBoxSizes; |
1265 | 0 |
|
1266 | 0 | while (boxSizes) { |
1267 | 0 |
|
1268 | 0 | // ignore collapsed spacers |
1269 | 0 | // if (!(boxSizes && boxSizes->collapsed)) { |
1270 | 0 |
|
1271 | 0 | nscoord pref = 0; |
1272 | 0 | nscoord flex = 0; |
1273 | 0 | pref = boxSizes->pref; |
1274 | 0 | flex = boxSizes->flex; |
1275 | 0 |
|
1276 | 0 | if (!computedBoxSizes->valid) { |
1277 | 0 | computedBoxSizes->size = pref + int32_t(int64_t(sizeRemaining) * flex / spacerConstantsRemaining); |
1278 | 0 | computedBoxSizes->valid = true; |
1279 | 0 | } |
1280 | 0 |
|
1281 | 0 | aGivenSize += (boxSizes->left + boxSizes->right); |
1282 | 0 | aGivenSize += computedBoxSizes->size; |
1283 | 0 |
|
1284 | 0 | // } |
1285 | 0 |
|
1286 | 0 | boxSizes = boxSizes->next; |
1287 | 0 | computedBoxSizes = computedBoxSizes->next; |
1288 | 0 | } |
1289 | 0 | } |
1290 | | |
1291 | | |
1292 | | nsSize |
1293 | | nsSprocketLayout::GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState) |
1294 | 0 | { |
1295 | 0 | nsSize vpref (0, 0); |
1296 | 0 | bool isHorizontal = IsXULHorizontal(aBox); |
1297 | 0 |
|
1298 | 0 | nscoord biggestPref = 0; |
1299 | 0 |
|
1300 | 0 | // run through all the children and get their min, max, and preferred sizes |
1301 | 0 | // return us the size of the box |
1302 | 0 |
|
1303 | 0 | nsIFrame* child = nsBox::GetChildXULBox(aBox); |
1304 | 0 | nsFrameState frameState = nsFrameState(0); |
1305 | 0 | GetFrameState(aBox, frameState); |
1306 | 0 | bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE); |
1307 | 0 | int32_t count = 0; |
1308 | 0 |
|
1309 | 0 | while (child) |
1310 | 0 | { |
1311 | 0 | // ignore collapsed children |
1312 | 0 | if (!child->IsXULCollapsed()) |
1313 | 0 | { |
1314 | 0 | nsSize pref = child->GetXULPrefSize(aState); |
1315 | 0 | AddMargin(child, pref); |
1316 | 0 |
|
1317 | 0 | if (isEqual) { |
1318 | 0 | if (isHorizontal) |
1319 | 0 | { |
1320 | 0 | if (pref.width > biggestPref) |
1321 | 0 | biggestPref = pref.width; |
1322 | 0 | } else { |
1323 | 0 | if (pref.height > biggestPref) |
1324 | 0 | biggestPref = pref.height; |
1325 | 0 | } |
1326 | 0 | } |
1327 | 0 |
|
1328 | 0 | AddLargestSize(vpref, pref, isHorizontal); |
1329 | 0 | count++; |
1330 | 0 | } |
1331 | 0 |
|
1332 | 0 | child = nsBox::GetNextXULBox(child); |
1333 | 0 | } |
1334 | 0 |
|
1335 | 0 | if (isEqual) { |
1336 | 0 | if (isHorizontal) |
1337 | 0 | vpref.width = biggestPref*count; |
1338 | 0 | else |
1339 | 0 | vpref.height = biggestPref*count; |
1340 | 0 | } |
1341 | 0 |
|
1342 | 0 | // now add our border and padding |
1343 | 0 | AddBorderAndPadding(aBox, vpref); |
1344 | 0 |
|
1345 | 0 | return vpref; |
1346 | 0 | } |
1347 | | |
1348 | | nsSize |
1349 | | nsSprocketLayout::GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aState) |
1350 | 0 | { |
1351 | 0 | nsSize minSize (0, 0); |
1352 | 0 | bool isHorizontal = IsXULHorizontal(aBox); |
1353 | 0 |
|
1354 | 0 | nscoord biggestMin = 0; |
1355 | 0 |
|
1356 | 0 |
|
1357 | 0 | // run through all the children and get their min, max, and preferred sizes |
1358 | 0 | // return us the size of the box |
1359 | 0 |
|
1360 | 0 | nsIFrame* child = nsBox::GetChildXULBox(aBox); |
1361 | 0 | nsFrameState frameState = nsFrameState(0); |
1362 | 0 | GetFrameState(aBox, frameState); |
1363 | 0 | bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE); |
1364 | 0 | int32_t count = 0; |
1365 | 0 |
|
1366 | 0 | while (child) |
1367 | 0 | { |
1368 | 0 | // ignore collapsed children |
1369 | 0 | if (!child->IsXULCollapsed()) |
1370 | 0 | { |
1371 | 0 | nsSize min = child->GetXULMinSize(aState); |
1372 | 0 | nsSize pref(0,0); |
1373 | 0 |
|
1374 | 0 | // if the child is not flexible then |
1375 | 0 | // its min size is its pref size. |
1376 | 0 | if (child->GetXULFlex() == 0) { |
1377 | 0 | pref = child->GetXULPrefSize(aState); |
1378 | 0 | if (isHorizontal) |
1379 | 0 | min.width = pref.width; |
1380 | 0 | else |
1381 | 0 | min.height = pref.height; |
1382 | 0 | } |
1383 | 0 |
|
1384 | 0 | if (isEqual) { |
1385 | 0 | if (isHorizontal) |
1386 | 0 | { |
1387 | 0 | if (min.width > biggestMin) |
1388 | 0 | biggestMin = min.width; |
1389 | 0 | } else { |
1390 | 0 | if (min.height > biggestMin) |
1391 | 0 | biggestMin = min.height; |
1392 | 0 | } |
1393 | 0 | } |
1394 | 0 |
|
1395 | 0 | AddMargin(child, min); |
1396 | 0 | AddLargestSize(minSize, min, isHorizontal); |
1397 | 0 | count++; |
1398 | 0 | } |
1399 | 0 |
|
1400 | 0 | child = nsBox::GetNextXULBox(child); |
1401 | 0 | } |
1402 | 0 |
|
1403 | 0 |
|
1404 | 0 | if (isEqual) { |
1405 | 0 | if (isHorizontal) |
1406 | 0 | minSize.width = biggestMin*count; |
1407 | 0 | else |
1408 | 0 | minSize.height = biggestMin*count; |
1409 | 0 | } |
1410 | 0 |
|
1411 | 0 | // now add our border and padding |
1412 | 0 | AddBorderAndPadding(aBox, minSize); |
1413 | 0 |
|
1414 | 0 | return minSize; |
1415 | 0 | } |
1416 | | |
1417 | | nsSize |
1418 | | nsSprocketLayout::GetXULMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState) |
1419 | 0 | { |
1420 | 0 |
|
1421 | 0 | bool isHorizontal = IsXULHorizontal(aBox); |
1422 | 0 |
|
1423 | 0 | nscoord smallestMax = NS_INTRINSICSIZE; |
1424 | 0 | nsSize maxSize (NS_INTRINSICSIZE, NS_INTRINSICSIZE); |
1425 | 0 |
|
1426 | 0 | // run through all the children and get their min, max, and preferred sizes |
1427 | 0 | // return us the size of the box |
1428 | 0 |
|
1429 | 0 | nsIFrame* child = nsBox::GetChildXULBox(aBox); |
1430 | 0 | nsFrameState frameState = nsFrameState(0); |
1431 | 0 | GetFrameState(aBox, frameState); |
1432 | 0 | bool isEqual = !!(frameState & NS_STATE_EQUAL_SIZE); |
1433 | 0 | int32_t count = 0; |
1434 | 0 |
|
1435 | 0 | while (child) |
1436 | 0 | { |
1437 | 0 | // ignore collapsed children |
1438 | 0 | if (!child->IsXULCollapsed()) |
1439 | 0 | { |
1440 | 0 | // if completely redefined don't even ask our child for its size. |
1441 | 0 | nsSize min = child->GetXULMinSize(aState); |
1442 | 0 | nsSize max = nsBox::BoundsCheckMinMax(min, child->GetXULMaxSize(aState)); |
1443 | 0 |
|
1444 | 0 | AddMargin(child, max); |
1445 | 0 | AddSmallestSize(maxSize, max, isHorizontal); |
1446 | 0 |
|
1447 | 0 | if (isEqual) { |
1448 | 0 | if (isHorizontal) |
1449 | 0 | { |
1450 | 0 | if (max.width < smallestMax) |
1451 | 0 | smallestMax = max.width; |
1452 | 0 | } else { |
1453 | 0 | if (max.height < smallestMax) |
1454 | 0 | smallestMax = max.height; |
1455 | 0 | } |
1456 | 0 | } |
1457 | 0 | count++; |
1458 | 0 | } |
1459 | 0 |
|
1460 | 0 | child = nsBox::GetNextXULBox(child); |
1461 | 0 | } |
1462 | 0 |
|
1463 | 0 | if (isEqual) { |
1464 | 0 | if (isHorizontal) { |
1465 | 0 | if (smallestMax != NS_INTRINSICSIZE) |
1466 | 0 | maxSize.width = smallestMax*count; |
1467 | 0 | else |
1468 | 0 | maxSize.width = NS_INTRINSICSIZE; |
1469 | 0 | } else { |
1470 | 0 | if (smallestMax != NS_INTRINSICSIZE) |
1471 | 0 | maxSize.height = smallestMax*count; |
1472 | 0 | else |
1473 | 0 | maxSize.height = NS_INTRINSICSIZE; |
1474 | 0 | } |
1475 | 0 | } |
1476 | 0 |
|
1477 | 0 | // now add our border and padding |
1478 | 0 | AddBorderAndPadding(aBox, maxSize); |
1479 | 0 |
|
1480 | 0 | return maxSize; |
1481 | 0 | } |
1482 | | |
1483 | | |
1484 | | nscoord |
1485 | | nsSprocketLayout::GetAscent(nsIFrame* aBox, nsBoxLayoutState& aState) |
1486 | 0 | { |
1487 | 0 | nscoord vAscent = 0; |
1488 | 0 |
|
1489 | 0 | bool isHorizontal = IsXULHorizontal(aBox); |
1490 | 0 |
|
1491 | 0 | // run through all the children and get their min, max, and preferred sizes |
1492 | 0 | // return us the size of the box |
1493 | 0 |
|
1494 | 0 | nsIFrame* child = nsBox::GetChildXULBox(aBox); |
1495 | 0 |
|
1496 | 0 | while (child) |
1497 | 0 | { |
1498 | 0 | // ignore collapsed children |
1499 | 0 | //if (!child->IsXULCollapsed()) |
1500 | 0 | //{ |
1501 | 0 | // if completely redefined don't even ask our child for its size. |
1502 | 0 | nscoord ascent = child->GetXULBoxAscent(aState); |
1503 | 0 |
|
1504 | 0 | nsMargin margin; |
1505 | 0 | child->GetXULMargin(margin); |
1506 | 0 | ascent += margin.top; |
1507 | 0 |
|
1508 | 0 | if (isHorizontal) |
1509 | 0 | { |
1510 | 0 | if (ascent > vAscent) |
1511 | 0 | vAscent = ascent; |
1512 | 0 | } else { |
1513 | 0 | if (vAscent == 0) |
1514 | 0 | vAscent = ascent; |
1515 | 0 | } |
1516 | 0 | //} |
1517 | 0 |
|
1518 | 0 | child = nsBox::GetNextXULBox(child); |
1519 | 0 | } |
1520 | 0 |
|
1521 | 0 | nsMargin borderPadding; |
1522 | 0 | aBox->GetXULBorderAndPadding(borderPadding); |
1523 | 0 |
|
1524 | 0 | return vAscent + borderPadding.top; |
1525 | 0 | } |
1526 | | |
1527 | | void |
1528 | | nsSprocketLayout::SetLargestSize(nsSize& aSize1, const nsSize& aSize2, bool aIsHorizontal) |
1529 | 0 | { |
1530 | 0 | if (aIsHorizontal) |
1531 | 0 | { |
1532 | 0 | if (aSize1.height < aSize2.height) |
1533 | 0 | aSize1.height = aSize2.height; |
1534 | 0 | } else { |
1535 | 0 | if (aSize1.width < aSize2.width) |
1536 | 0 | aSize1.width = aSize2.width; |
1537 | 0 | } |
1538 | 0 | } |
1539 | | |
1540 | | void |
1541 | | nsSprocketLayout::SetSmallestSize(nsSize& aSize1, const nsSize& aSize2, bool aIsHorizontal) |
1542 | 0 | { |
1543 | 0 | if (aIsHorizontal) |
1544 | 0 | { |
1545 | 0 | if (aSize1.height > aSize2.height) |
1546 | 0 | aSize1.height = aSize2.height; |
1547 | 0 | } else { |
1548 | 0 | if (aSize1.width > aSize2.width) |
1549 | 0 | aSize1.width = aSize2.width; |
1550 | 0 |
|
1551 | 0 | } |
1552 | 0 | } |
1553 | | |
1554 | | void |
1555 | | nsSprocketLayout::AddLargestSize(nsSize& aSize, const nsSize& aSizeToAdd, bool aIsHorizontal) |
1556 | 0 | { |
1557 | 0 | if (aIsHorizontal) |
1558 | 0 | AddCoord(aSize.width, aSizeToAdd.width); |
1559 | 0 | else |
1560 | 0 | AddCoord(aSize.height, aSizeToAdd.height); |
1561 | 0 |
|
1562 | 0 | SetLargestSize(aSize, aSizeToAdd, aIsHorizontal); |
1563 | 0 | } |
1564 | | |
1565 | | void |
1566 | | nsSprocketLayout::AddCoord(nscoord& aCoord, nscoord aCoordToAdd) |
1567 | 0 | { |
1568 | 0 | if (aCoord != NS_INTRINSICSIZE) |
1569 | 0 | { |
1570 | 0 | if (aCoordToAdd == NS_INTRINSICSIZE) |
1571 | 0 | aCoord = aCoordToAdd; |
1572 | 0 | else |
1573 | 0 | aCoord += aCoordToAdd; |
1574 | 0 | } |
1575 | 0 | } |
1576 | | void |
1577 | | nsSprocketLayout::AddSmallestSize(nsSize& aSize, const nsSize& aSizeToAdd, bool aIsHorizontal) |
1578 | 0 | { |
1579 | 0 | if (aIsHorizontal) |
1580 | 0 | AddCoord(aSize.width, aSizeToAdd.width); |
1581 | 0 | else |
1582 | 0 | AddCoord(aSize.height, aSizeToAdd.height); |
1583 | 0 |
|
1584 | 0 | SetSmallestSize(aSize, aSizeToAdd, aIsHorizontal); |
1585 | 0 | } |
1586 | | |
1587 | | bool |
1588 | | nsSprocketLayout::GetDefaultFlex(int32_t& aFlex) |
1589 | 0 | { |
1590 | 0 | aFlex = 0; |
1591 | 0 | return true; |
1592 | 0 | } |
1593 | | |
1594 | | nsComputedBoxSize::nsComputedBoxSize() |
1595 | 0 | { |
1596 | 0 | resized = false; |
1597 | 0 | valid = false; |
1598 | 0 | size = 0; |
1599 | 0 | next = nullptr; |
1600 | 0 | } |
1601 | | |
1602 | | nsBoxSize::nsBoxSize() |
1603 | 0 | { |
1604 | 0 | pref = 0; |
1605 | 0 | min = 0; |
1606 | 0 | max = NS_INTRINSICSIZE; |
1607 | 0 | collapsed = false; |
1608 | 0 | left = 0; |
1609 | 0 | right = 0; |
1610 | 0 | flex = 0; |
1611 | 0 | next = nullptr; |
1612 | 0 | bogus = false; |
1613 | 0 | } |
1614 | | |
1615 | | |
1616 | | void* |
1617 | | nsBoxSize::operator new(size_t sz, nsBoxLayoutState& aState) CPP_THROW_NEW |
1618 | 0 | { |
1619 | 0 | return mozilla::AutoStackArena::Allocate(sz); |
1620 | 0 | } |
1621 | | |
1622 | | |
1623 | | void |
1624 | | nsBoxSize::operator delete(void* aPtr, size_t sz) |
1625 | 0 | { |
1626 | 0 | } |
1627 | | |
1628 | | |
1629 | | void* |
1630 | | nsComputedBoxSize::operator new(size_t sz, nsBoxLayoutState& aState) CPP_THROW_NEW |
1631 | 0 | { |
1632 | 0 | return mozilla::AutoStackArena::Allocate(sz); |
1633 | 0 | } |
1634 | | |
1635 | | void |
1636 | | nsComputedBoxSize::operator delete(void* aPtr, size_t sz) |
1637 | 0 | { |
1638 | 0 | } |