Coverage Report

Created: 2018-09-25 14:53

/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
}