2 * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
6 #include "ComplexLayouter.h"
17 #include <AutoDeleter.h>
19 #include "LayoutOptimizer.h"
20 #include "SimpleLayouter.h"
23 //#define TRACE_COMPLEX_LAYOUTER 1
24 #if TRACE_COMPLEX_LAYOUTER
25 # define TRACE(format...) printf(format);
26 # define TRACE_ONLY(x) x
28 # define TRACE(format...)
29 # define TRACE_ONLY(x)
36 class ComplexLayouter::MyLayoutInfo
: public LayoutInfo
{
38 MyLayoutInfo(int32 elementCount
, int32 spacing
)
39 : fCount(elementCount
),
42 // We also store the location of the virtual elementCountth element.
43 // Thus fLocation[i + 1] - fLocation[i] is the size of the ith element
44 // (not considering spacing).
45 fLocations
= new(nothrow
) int32
[elementCount
+ 1];
53 void InitFromSizes(int32
* sizes
)
56 for (int32 i
= 0; i
< fCount
; i
++)
57 fLocations
[i
+ 1] = fLocations
[i
] + sizes
[i
] + fSpacing
;
60 virtual float ElementLocation(int32 element
)
62 if (element
< 0 || element
>= fCount
)
65 return fLocations
[element
];
68 virtual float ElementSize(int32 element
)
70 if (element
< 0 || element
>= fCount
)
73 return fLocations
[element
+ 1] - fLocations
[element
] - 1
77 virtual float ElementRangeSize(int32 position
, int32 length
)
79 if (position
< 0 || length
< 0 || position
+ length
> fCount
)
82 return fLocations
[position
+ length
] - fLocations
[position
] - 1
88 printf("ComplexLayouter::MyLayoutInfo(): %" B_PRId32
" elements:\n",
90 for (int32 i
= 0; i
< fCount
+ 1; i
++) {
91 printf(" %2" B_PRId32
": location: %4" B_PRId32
"\n", i
,
104 struct ComplexLayouter::Constraint
{
105 Constraint(int32 start
, int32 end
, int32 min
, int32 max
)
117 void Restrict(int32 newMin
, int32 newMax
)
128 bool IsSatisfied(int32
* sumValues
) const
130 int32 value
= sumValues
[end
] - sumValues
[start
- 1];
131 return (value
>= min
&& value
<= max
);
144 struct ComplexLayouter::SumItem
{
153 struct ComplexLayouter::SumItemBackup
{
159 // #pragma mark - ComplexLayouter
163 ComplexLayouter::ComplexLayouter(int32 elementCount
, float spacing
)
164 : fElementCount(elementCount
),
165 fSpacing((int32
)spacing
),
166 fConstraints(new(nothrow
) Constraint
*[elementCount
]),
167 fWeights(new(nothrow
) float[elementCount
]),
168 fSums(new(nothrow
) SumItem
[elementCount
+ 1]),
169 fSumBackups(new(nothrow
) SumItemBackup
[elementCount
+ 1]),
170 fOptimizer(new(nothrow
) LayoutOptimizer(elementCount
)),
171 fUnlimited(B_SIZE_UNLIMITED
/ (elementCount
== 0 ? 1 : elementCount
)),
173 fOptimizerConstraintsAdded(false)
176 memset(fConstraints
, 0, sizeof(Constraint
*) * fElementCount
);
179 for (int32 i
= 0; i
< fElementCount
; i
++)
186 ComplexLayouter::~ComplexLayouter()
188 for (int32 i
= 0; i
< fElementCount
; i
++) {
189 Constraint
* constraint
= fConstraints
[i
];
190 fConstraints
[i
] = NULL
;
191 while (constraint
!= NULL
) {
192 Constraint
* next
= constraint
->next
;
198 delete[] fConstraints
;
201 delete[] fSumBackups
;
208 ComplexLayouter::InitCheck() const
210 if (!fConstraints
|| !fWeights
|| !fSums
|| !fSumBackups
|| !fOptimizer
)
212 return fOptimizer
->InitCheck();
218 ComplexLayouter::AddConstraints(int32 element
, int32 length
,
219 float _min
, float _max
, float _preferred
)
221 if (element
< 0 || length
<= 0 || element
+ length
> fElementCount
)
224 TRACE("%p->ComplexLayouter::AddConstraints(%ld, %ld, %ld, %ld, %ld)\n",
225 this, element
, length
, (int32
)_min
, (int32
)_max
, (int32
)_preferred
);
227 int32 spacing
= fSpacing
* (length
- 1);
228 int32 min
= (int32
)_min
+ 1 - spacing
;
229 int32 max
= (int32
)_max
+ 1 - spacing
;
233 if (max
> fUnlimited
)
236 int32 end
= element
+ length
- 1;
237 Constraint
** slot
= fConstraints
+ end
;
238 while (*slot
!= NULL
&& (*slot
)->start
> element
)
239 slot
= &(*slot
)->next
;
241 if (*slot
!= NULL
&& (*slot
)->start
== element
) {
242 // previous constraint exists -- use stricter values
243 (*slot
)->Restrict(min
, max
);
245 // no previous constraint -- create new one
246 Constraint
* constraint
= new(nothrow
) Constraint(element
, end
, min
,
250 constraint
->next
= *slot
;
254 fMinMaxValid
= false;
260 ComplexLayouter::SetWeight(int32 element
, float weight
)
262 if (element
< 0 || element
>= fElementCount
)
265 fWeights
[element
] = max_c(weight
, 0);
271 ComplexLayouter::MinSize()
280 ComplexLayouter::MaxSize()
289 ComplexLayouter::PreferredSize()
297 ComplexLayouter::CreateLayoutInfo()
299 MyLayoutInfo
* layoutInfo
= new(nothrow
) MyLayoutInfo(fElementCount
,
301 if (layoutInfo
&& !layoutInfo
->fLocations
) {
312 ComplexLayouter::Layout(LayoutInfo
* _layoutInfo
, float _size
)
314 TRACE("%p->ComplexLayouter::Layout(%ld)\n", this, (int32
)_size
);
316 if (fElementCount
== 0)
321 MyLayoutInfo
* layoutInfo
= (MyLayoutInfo
*)_layoutInfo
;
323 int32 min
= fSums
[fElementCount
].min
;
324 int32 max
= fSums
[fElementCount
].max
;
326 int32 size
= (int32
)_size
+ 1 - (fElementCount
- 1) * fSpacing
;
332 SumItem sums
[fElementCount
+ 1];
333 memcpy(sums
, fSums
, (fElementCount
+ 1) * sizeof(SumItem
));
335 sums
[fElementCount
].min
= size
;
336 sums
[fElementCount
].max
= size
;
337 sums
[fElementCount
].minDirty
= (size
!= min
);
338 sums
[fElementCount
].maxDirty
= (size
!= max
);
340 // propagate the size
341 _PropagateChangesBack(sums
, fElementCount
- 1, NULL
);
342 _PropagateChanges(sums
, fElementCount
- 1, NULL
);
344 #if TRACE_COMPLEX_LAYOUTER
345 TRACE("Layout(%ld)\n", size
);
346 for (int32 i
= 0; i
< fElementCount
; i
++) {
347 SumItem
& sum
= sums
[i
+ 1];
348 TRACE("[%ld] minc = %4ld, maxc = %4ld\n", i
+ 1, sum
.min
, sum
.max
);
352 int32 sizes
[fElementCount
];
353 if (!_Layout(size
, sums
, sizes
)) {
356 layoutInfo
->InitFromSizes(sizes
);
362 ComplexLayouter::CloneLayouter()
364 ComplexLayouter
* layouter
365 = new(nothrow
) ComplexLayouter(fElementCount
, fSpacing
);
366 ObjectDeleter
<ComplexLayouter
> layouterDeleter(layouter
);
367 if (!layouter
|| layouter
->InitCheck() != B_OK
368 || !layouter
->fOptimizer
->AddConstraintsFrom(fOptimizer
)) {
372 // clone the constraints
373 for (int32 i
= 0; i
< fElementCount
; i
++) {
374 Constraint
* constraint
= fConstraints
[i
];
375 Constraint
** end
= layouter
->fConstraints
+ i
;
377 *end
= new(nothrow
) Constraint(constraint
->start
, constraint
->end
,
378 constraint
->min
, constraint
->max
);
383 constraint
= constraint
->next
;
387 // copy the other stuff
388 memcpy(layouter
->fWeights
, fWeights
, fElementCount
* sizeof(float));
389 memcpy(layouter
->fSums
, fSums
, (fElementCount
+ 1) * sizeof(SumItem
));
390 memcpy(layouter
->fSumBackups
, fSumBackups
,
391 (fElementCount
+ 1) * sizeof(SumItemBackup
));
392 layouter
->fMin
= fMin
;
393 layouter
->fMax
= fMax
;
394 layouter
->fMinMaxValid
= fMinMaxValid
;
396 return layouterDeleter
.Detach();
402 ComplexLayouter::_Layout(int32 size
, SumItem
* sums
, int32
* sizes
)
404 // prepare the desired solution
405 SimpleLayouter::DistributeSize(size
, fWeights
, sizes
, fElementCount
);
406 if (_SatisfiesConstraints(sizes
)) {
407 // The desired solution already satisfies all constraints.
411 double realSizes
[fElementCount
];
412 for (int32 i
= 0; i
< fElementCount
; i
++)
413 realSizes
[i
] = sizes
[i
];
415 if (!_AddOptimizerConstraints())
419 // prepare a feasible solution (the minimum)
420 double values
[fElementCount
];
421 for (int32 i
= 0; i
< fElementCount
; i
++)
422 values
[i
] = sums
[i
+ 1].min
- sums
[i
].min
;
424 #if TRACE_COMPLEX_LAYOUTER
425 TRACE("feasible solution vs. desired solution:\n");
426 for (int32 i
= 0; i
< fElementCount
; i
++)
427 TRACE("%8.4f %8.4f\n", values
[i
], realSizes
[i
]);
431 TRACE_ONLY(bigtime_t time
= system_time();)
432 if (!fOptimizer
->Solve(realSizes
, size
, values
))
434 TRACE_ONLY(time
= system_time() - time
;)
436 // compute integer solution
437 // The basic strategy is to floor() the sums. This guarantees that the
438 // difference between two rounded sums remains in the range of floor()
439 // and ceil() of their real value difference. Since the constraints have
440 // integer values, the integer solution will therefore satisfy all
441 // constraints the real solution satisfied.
442 TRACE("computed solution in %lld us:\n", time
);
445 double previousSum
= 0;
446 for (int32 i
= 0; i
< fElementCount
; i
++) {
447 realSum
+= values
[i
];
448 double roundedRealSum
= floor(realSum
);
449 if (fuzzy_equals(realSum
, roundedRealSum
+ 1))
450 realSum
= roundedRealSum
+ 1;
451 sizes
[i
] = int32(roundedRealSum
- previousSum
);
452 previousSum
= roundedRealSum
;
454 TRACE("x[%ld] = %8.4f %4ld\n", i
, values
[i
], sizes
[i
]);
457 return _SatisfiesConstraints(sizes
);
461 // _AddOptimizerConstraints
463 ComplexLayouter::_AddOptimizerConstraints()
465 if (fOptimizerConstraintsAdded
)
468 fOptimizer
->RemoveAllConstraints();
471 for (int32 i
= 0; i
< fElementCount
; i
++) {
472 SumItem
& sum
= fSums
[i
+ 1];
474 Constraint
* constraint
= fConstraints
[i
];
475 while (constraint
!= NULL
) {
476 SumItem
& base
= fSums
[constraint
->start
];
477 int32 sumMin
= base
.min
+ constraint
->min
;
478 int32 baseMax
= sum
.max
- constraint
->min
;
479 bool minRedundant
= (sumMin
< sum
.min
&& baseMax
> base
.max
);
481 int32 sumMax
= base
.max
+ constraint
->effectiveMax
;
482 int32 baseMin
= sum
.min
- constraint
->effectiveMax
;
483 bool maxRedundant
= (sumMax
> sum
.max
&& baseMin
< base
.min
);
485 if (!minRedundant
|| !maxRedundant
) {
487 if (constraint
->min
== constraint
->effectiveMax
) {
488 // min and max equal -- add an equality constraint
489 success
= fOptimizer
->AddConstraint(constraint
->start
- 1,
490 constraint
->end
, constraint
->min
, true);
492 // min and max not equal -- add them individually,
495 success
|= fOptimizer
->AddConstraint(
496 constraint
->start
- 1, constraint
->end
,
497 constraint
->min
, false);
500 success
|= fOptimizer
->AddConstraint(constraint
->end
,
501 constraint
->start
- 1,
502 -constraint
->effectiveMax
, false);
510 constraint
= constraint
->next
;
514 fOptimizerConstraintsAdded
= true;
519 // _SatisfiesConstraints
521 ComplexLayouter::_SatisfiesConstraints(int32
* sizes
) const
523 int32 sumValues
[fElementCount
+ 1];
525 for (int32 i
= 0; i
< fElementCount
; i
++)
526 sumValues
[i
+ 1] = sumValues
[i
] + sizes
[i
];
528 return _SatisfiesConstraintsSums(sumValues
);
532 // _SatisfiesConstraintsSums
534 ComplexLayouter::_SatisfiesConstraintsSums(int32
* sumValues
) const
536 for (int32 i
= 0; i
< fElementCount
; i
++) {
537 Constraint
* constraint
= fConstraints
[i
];
539 if (!constraint
->IsSatisfied(sumValues
))
542 constraint
= constraint
->next
;
552 ComplexLayouter::_ValidateLayout()
554 // The general idea for computing the min and max for the given constraints
555 // is that we rewrite the problem a little. Instead of considering the
556 // x_1, ... x_n (n = fElementCount) and the constraints of the form
557 // x_i + ... + x_{i+j} >= min[i,j] and
558 // x_i + ... + x_{i+j} >= max[i,j], with i >= 1, j >= 0, i + j <= n
559 // and min[i,j], max[i,j] >= 0
562 // c[i] = \sum_{k=1}^i x_k, for all i, 1 <= i <= n
563 // and thus the constraints read:
564 // c[i+j] - c[i-1] >= min[i,j]
565 // c[i+j] - c[i-1] <= max[i,j]
567 // Let minc[i] and maxc[i] the limits imposed by the given constraints, i.e.
568 // minc[i] <= c[i] <= maxc[i] for any tuple of (c[i])_i satisfying the
569 // constraints (minc[i] and maxc[i] are unique), then we gain:
570 // minc[i+j] >= c[i-1] + min[i,j]
571 // maxc[i+j] <= c[i-1] + min[i,j]
572 // minc[i-1] >= minc[i+j] - max[i,j]
573 // maxc[i-1] >= maxc[i+j] - min[i,j]
574 // We can compute the minc[i] and maxc[i] in an iterative process,
575 // propagating the first to kinds of constraints forward and the other two
576 // backwards. First we start considering all min constraints only. They
577 // can't contradict each other and are usually to be enforced over max
578 // constraints. Afterwards we add the max constraints one by one. For each
579 // one of them we propagate resulting changes back and forth. In case of
580 // a conflict, we relax the max constraint as much as necessary to yield
581 // a consistent set of constraints. After all constraints have been
582 // incorporated, the resulting minc[n] and maxc[n] are the min and max
583 // limits we wanted to compute.
592 for (int32 i
= 0; i
< fElementCount
; i
++) {
593 SumItem
& sum
= fSums
[i
+ 1];
595 sum
.max
= maxSum
+= fUnlimited
;
596 sum
.minDirty
= false;
597 sum
.maxDirty
= false;
600 // apply min constraints forward:
601 // minc[i+j] >= minc[i-1] + min[i,j]
602 for (int32 i
= 0; i
< fElementCount
; i
++) {
603 SumItem
& sum
= fSums
[i
+ 1];
605 Constraint
* constraint
= fConstraints
[i
];
606 while (constraint
!= NULL
) {
607 int32 minSum
= fSums
[constraint
->start
].min
+ constraint
->min
;
608 if (minSum
> sum
.min
) {
611 TRACE("min constraint is redundant: x%ld + ... + x%ld >= %ld\n",
612 constraint
->start
, constraint
->end
, constraint
->min
);
615 constraint
= constraint
->next
;
619 // apply min constraints backwards:
620 // maxc[i-1] <= maxc[i+j] - min[i,j]
621 for (int32 i
= fElementCount
- 1; i
>= 0; i
--) {
622 SumItem
& sum
= fSums
[i
+ 1];
624 Constraint
* constraint
= fConstraints
[i
];
625 while (constraint
!= NULL
) {
626 SumItem
& base
= fSums
[constraint
->start
];
627 int32 baseMax
= sum
.max
- constraint
->min
;
628 if (baseMax
< base
.max
)
631 constraint
= constraint
->next
;
635 // apply max constraints
636 for (int32 i
= 0; i
< fElementCount
; i
++) {
637 Constraint
* constraint
= fConstraints
[i
];
638 while (constraint
!= NULL
) {
639 _ApplyMaxConstraint(constraint
, i
);
641 constraint
= constraint
->next
;
645 #if TRACE_COMPLEX_LAYOUTER
646 for (int32 i
= 0; i
< fElementCount
; i
++) {
647 SumItem
& sum
= fSums
[i
+ 1];
648 TRACE("[%ld] minc = %4ld, maxc = %4ld\n", i
+ 1, sum
.min
, sum
.max
);
652 if (fElementCount
== 0) {
654 fMax
= B_SIZE_UNLIMITED
;
656 int32 spacing
= (fElementCount
- 1) * fSpacing
;
657 fMin
= fSums
[fElementCount
].min
+ spacing
- 1;
658 fMax
= fSums
[fElementCount
].max
+ spacing
- 1;
659 if (fMax
>= fUnlimited
)
660 fMax
= B_SIZE_UNLIMITED
;
663 fOptimizerConstraintsAdded
= false;
668 // _ApplyMaxConstraint
670 ComplexLayouter::_ApplyMaxConstraint(Constraint
* currentConstraint
, int32 index
)
672 SumItem
& sum
= fSums
[index
+ 1];
673 SumItem
& base
= fSums
[currentConstraint
->start
];
676 // c[i+j] <= c[i-1] + max[i,j]
678 // This has the following direct consequences (let k = i + j):
679 // (1) maxc[k] <= maxc[i-1] + max[i,j]
680 // (2) minc[i-1] >= minc[k] - max[i,j]
682 // If maxc[k] or minc[i-i] changed, those changes have to be propagated
685 // apply (1) maxc[k] <= maxc[i-1] + max[i,j]
686 int32 max
= currentConstraint
->effectiveMax
;
687 int32 sumMax
= base
.max
+ max
;
689 // enforce maxc[i+j] >= minc[i+j]
690 if (sumMax
< sum
.min
) {
692 max
= sumMax
- base
.max
;
695 // apply (2) minc[i-1] >= minc[k] - max[i,j]
696 // and check minc[i-1] <= maxc[i-1]
697 int32 baseMin
= sum
.min
- max
;
698 if (baseMin
> base
.max
) {
700 max
= sum
.min
- baseMin
;
701 sumMax
= base
.max
+ max
;
704 if (currentConstraint
->effectiveMax
!= max
) {
705 TRACE("relaxing conflicting max constraint (1): "
706 "x%ld + ... + x%ld <= %ld -> %ld\n", currentConstraint
->start
,
707 currentConstraint
->end
, currentConstraint
->effectiveMax
, max
);
709 currentConstraint
->effectiveMax
= max
;
711 if (baseMin
<= base
.min
&& sumMax
>= sum
.max
) {
712 TRACE("max constraint is redundant: x%ld + ... + x%ld <= %ld\n",
713 currentConstraint
->start
, currentConstraint
->end
,
714 currentConstraint
->effectiveMax
);
718 // backup old values, in case we detect a conflict later
719 _BackupValues(index
);
724 int32 changedIndex
= currentConstraint
->start
;
726 if (baseMin
> base
.min
) {
728 base
.minDirty
= true;
731 if (sumMax
< sum
.max
) {
732 changedIndex
= index
;
737 // propagate the changes
738 _PropagateChangesBack(fSums
, changedIndex
, currentConstraint
);
739 _PropagateChanges(fSums
, index
, currentConstraint
);
741 // check the new constraint again -- if it doesn't hold, it
742 // conflicts with the other constraints
745 // check (1) maxc[k] <= maxc[i-1] + max[i,j]
746 max
= currentConstraint
->effectiveMax
;
747 sumMax
= base
.max
+ max
;
748 if (sumMax
< sum
.max
)
749 diff
= sum
.max
- sumMax
;
751 // check (2) minc[i-1] >= minc[k] - max[i,j]
752 baseMin
= sum
.min
- max
;
753 if (baseMin
> base
.min
)
754 diff
= max_c(diff
, baseMin
- base
.min
);
756 // clear the dirty flags
757 for (int32 i
= 0; i
<= changedIndex
; i
++) {
758 SumItem
& sum
= fSums
[i
+ 1];
759 sum
.minDirty
= false;
760 sum
.maxDirty
= false;
763 // if we've got a conflict, we relax the constraint and try again
766 TRACE("relaxing conflicting max constraint (2): "
767 "x%ld + ... + x%ld <= %ld -> %ld\n", currentConstraint
->start
,
768 currentConstraint
->end
, currentConstraint
->effectiveMax
, max
);
769 currentConstraint
->effectiveMax
= max
;
771 _RestoreValues(index
);
773 sumMax
= base
.max
+ max
;
774 baseMin
= sum
.min
- max
;
776 if (baseMin
<= base
.min
&& sumMax
>= sum
.max
)
784 /*! Propagate changes forward using min and max constraints. Max constraints
785 Beyond \a toIndex or at \a to toIndex after (and including)
786 \a lastMaxConstraint will be ignored. To have all constraints be
787 considered pass \c fElementCount and \c NULL.
790 ComplexLayouter::_PropagateChanges(SumItem
* sums
, int32 toIndex
,
791 Constraint
* lastMaxConstraint
)
793 for (int32 i
= 0; i
< fElementCount
; i
++) {
794 SumItem
& sum
= sums
[i
+ 1];
796 bool ignoreMaxConstraints
= (i
> toIndex
);
798 Constraint
* constraint
= fConstraints
[i
];
799 while (constraint
!= NULL
) {
800 SumItem
& base
= sums
[constraint
->start
];
802 if (constraint
== lastMaxConstraint
)
803 ignoreMaxConstraints
= true;
805 // minc[k] >= minc[i-1] + min[i,j]
807 int32 sumMin
= base
.min
+ constraint
->min
;
808 if (sumMin
> sum
.min
) {
814 // maxc[k] <= maxc[i-1] + max[i,j]
815 if (base
.maxDirty
&& !ignoreMaxConstraints
) {
816 int32 sumMax
= base
.max
+ constraint
->effectiveMax
;
817 if (sumMax
< sum
.max
) {
823 constraint
= constraint
->next
;
826 if (sum
.minDirty
|| sum
.maxDirty
) {
827 if (sum
.min
> sum
.max
) {
828 // TODO: Can this actually happen?
829 TRACE("adjusted max in propagation phase: index: "
830 "%ld: %ld -> %ld\n", i
, sum
.max
, sum
.min
);
839 // _PropagateChangesBack
841 ComplexLayouter::_PropagateChangesBack(SumItem
* sums
, int32 changedIndex
,
842 Constraint
* lastMaxConstraint
)
844 for (int32 i
= changedIndex
; i
>= 0; i
--) {
845 SumItem
& sum
= sums
[i
+ 1];
847 bool ignoreMaxConstraints
= false;
849 Constraint
* constraint
= fConstraints
[i
];
850 while (constraint
!= NULL
) {
851 SumItem
& base
= sums
[constraint
->start
];
853 if (constraint
== lastMaxConstraint
)
854 ignoreMaxConstraints
= true;
856 // minc[i-1] >= minc[k] - max[i,j]
857 if (sum
.minDirty
&& !ignoreMaxConstraints
) {
858 int32 baseMin
= sum
.min
- constraint
->effectiveMax
;
859 if (baseMin
> base
.min
) {
860 if (baseMin
> base
.max
) {
861 TRACE("min above max in back propagation phase: index: "
862 "(%ld -> %ld), min: %ld, max: %ld\n", i
,
863 constraint
->start
, baseMin
, base
.max
);
866 base
.minDirty
= true;
870 // maxc[i-1] <= maxc[k] - min[i,j]
872 int32 baseMax
= sum
.max
- constraint
->min
;
873 if (baseMax
< base
.max
) {
874 if (baseMax
< base
.min
) {
875 TRACE("max below min in back propagation phase: index: "
876 "(%ld -> %ld), max: %ld, min: %ld\n", i
,
877 constraint
->start
, baseMax
, base
.min
);
880 base
.maxDirty
= true;
884 constraint
= constraint
->next
;
892 ComplexLayouter::_BackupValues(int32 maxIndex
)
894 for (int32 i
= 0; i
<= maxIndex
; i
++) {
895 SumItem
& sum
= fSums
[i
+ 1];
896 fSumBackups
[i
+ 1].min
= sum
.min
;
897 fSumBackups
[i
+ 1].max
= sum
.max
;
904 ComplexLayouter::_RestoreValues(int32 maxIndex
)
906 for (int32 i
= 0; i
<= maxIndex
; i
++) {
907 SumItem
& sum
= fSums
[i
+ 1];
908 sum
.min
= fSumBackups
[i
+ 1].min
;
909 sum
.max
= fSumBackups
[i
+ 1].max
;