vfs: check userland buffers before reading them.
[haiku.git] / src / kits / interface / layouter / ComplexLayouter.cpp
blobc694bda059d4a8b5f797234dcd811c0997d9cd77
1 /*
2 * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
6 #include "ComplexLayouter.h"
8 #include <math.h>
9 #include <stdio.h>
10 #include <string.h>
12 #include <new>
14 #include <OS.h>
15 #include <Size.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
27 #else
28 # define TRACE(format...)
29 # define TRACE_ONLY(x)
30 #endif
32 using std::nothrow;
35 // MyLayoutInfo
36 class ComplexLayouter::MyLayoutInfo : public LayoutInfo {
37 public:
38 MyLayoutInfo(int32 elementCount, int32 spacing)
39 : fCount(elementCount),
40 fSpacing(spacing)
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];
48 ~MyLayoutInfo()
50 delete[] fLocations;
53 void InitFromSizes(int32* sizes)
55 fLocations[0] = 0;
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)
63 return 0;
65 return fLocations[element];
68 virtual float ElementSize(int32 element)
70 if (element < 0 || element >= fCount)
71 return -1;
73 return fLocations[element + 1] - fLocations[element] - 1
74 - fSpacing;
77 virtual float ElementRangeSize(int32 position, int32 length)
79 if (position < 0 || length < 0 || position + length > fCount)
80 return -1;
82 return fLocations[position + length] - fLocations[position] - 1
83 - fSpacing;
86 void Dump()
88 printf("ComplexLayouter::MyLayoutInfo(): %" B_PRId32 " elements:\n",
89 fCount);
90 for (int32 i = 0; i < fCount + 1; i++) {
91 printf(" %2" B_PRId32 ": location: %4" B_PRId32 "\n", i,
92 fLocations[i]);
96 public:
97 int32 fCount;
98 int32 fSpacing;
99 int32* fLocations;
103 // Constraint
104 struct ComplexLayouter::Constraint {
105 Constraint(int32 start, int32 end, int32 min, int32 max)
106 : start(start),
107 end(end),
108 min(min),
109 max(max),
110 next(NULL)
112 if (min > max)
113 max = min;
114 effectiveMax = max;
117 void Restrict(int32 newMin, int32 newMax)
119 if (newMin > min)
120 min = newMin;
121 if (newMax < max)
122 max = newMax;
123 if (min > max)
124 max = min;
125 effectiveMax = max;
128 bool IsSatisfied(int32* sumValues) const
130 int32 value = sumValues[end] - sumValues[start - 1];
131 return (value >= min && value <= max);
134 int32 start;
135 int32 end;
136 int32 min;
137 int32 max;
138 int32 effectiveMax;
139 Constraint* next;
143 // SumItem
144 struct ComplexLayouter::SumItem {
145 int32 min;
146 int32 max;
147 bool minDirty;
148 bool maxDirty;
152 // SumItemBackup
153 struct ComplexLayouter::SumItemBackup {
154 int32 min;
155 int32 max;
159 // #pragma mark - ComplexLayouter
162 // constructor
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)),
172 fMinMaxValid(false),
173 fOptimizerConstraintsAdded(false)
175 if (fConstraints)
176 memset(fConstraints, 0, sizeof(Constraint*) * fElementCount);
178 if (fWeights) {
179 for (int32 i = 0; i < fElementCount; i++)
180 fWeights[i] = 1.0f;
185 // destructor
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;
193 delete constraint;
194 constraint = next;
198 delete[] fConstraints;
199 delete[] fWeights;
200 delete[] fSums;
201 delete[] fSumBackups;
202 delete fOptimizer;
206 // InitCheck
207 status_t
208 ComplexLayouter::InitCheck() const
210 if (!fConstraints || !fWeights || !fSums || !fSumBackups || !fOptimizer)
211 return B_NO_MEMORY;
212 return fOptimizer->InitCheck();
216 // AddConstraints
217 void
218 ComplexLayouter::AddConstraints(int32 element, int32 length,
219 float _min, float _max, float _preferred)
221 if (element < 0 || length <= 0 || element + length > fElementCount)
222 return;
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;
231 if (min < 0)
232 min = 0;
233 if (max > fUnlimited)
234 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);
244 } else {
245 // no previous constraint -- create new one
246 Constraint* constraint = new(nothrow) Constraint(element, end, min,
247 max);
248 if (!constraint)
249 return;
250 constraint->next = *slot;
251 *slot = constraint;
254 fMinMaxValid = false;
258 // SetWeight
259 void
260 ComplexLayouter::SetWeight(int32 element, float weight)
262 if (element < 0 || element >= fElementCount)
263 return;
265 fWeights[element] = max_c(weight, 0);
269 // MinSize
270 float
271 ComplexLayouter::MinSize()
273 _ValidateLayout();
274 return fMin;
278 // MaxSize
279 float
280 ComplexLayouter::MaxSize()
282 _ValidateLayout();
283 return fMax;
287 // PreferredSize
288 float
289 ComplexLayouter::PreferredSize()
291 return fMin;
295 // CreateLayoutInfo
296 LayoutInfo*
297 ComplexLayouter::CreateLayoutInfo()
299 MyLayoutInfo* layoutInfo = new(nothrow) MyLayoutInfo(fElementCount,
300 fSpacing);
301 if (layoutInfo && !layoutInfo->fLocations) {
302 delete layoutInfo;
303 return NULL;
306 return layoutInfo;
310 // Layout
311 void
312 ComplexLayouter::Layout(LayoutInfo* _layoutInfo, float _size)
314 TRACE("%p->ComplexLayouter::Layout(%ld)\n", this, (int32)_size);
316 if (fElementCount == 0)
317 return;
319 _ValidateLayout();
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;
327 if (size < min)
328 size = min;
329 if (size > max)
330 size = max;
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);
350 #endif
352 int32 sizes[fElementCount];
353 if (!_Layout(size, sums, sizes)) {
356 layoutInfo->InitFromSizes(sizes);
360 // CloneLayouter
361 Layouter*
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)) {
369 return NULL;
372 // clone the constraints
373 for (int32 i = 0; i < fElementCount; i++) {
374 Constraint* constraint = fConstraints[i];
375 Constraint** end = layouter->fConstraints + i;
376 while (constraint) {
377 *end = new(nothrow) Constraint(constraint->start, constraint->end,
378 constraint->min, constraint->max);
379 if (!*end)
380 return NULL;
382 end = &(*end)->next;
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();
400 // _Layout
401 bool
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.
408 return true;
411 double realSizes[fElementCount];
412 for (int32 i = 0; i < fElementCount; i++)
413 realSizes[i] = sizes[i];
415 if (!_AddOptimizerConstraints())
416 return false;
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]);
428 #endif
430 // solve
431 TRACE_ONLY(bigtime_t time = system_time();)
432 if (!fOptimizer->Solve(realSizes, size, values))
433 return false;
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);
444 double realSum = 0;
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
462 bool
463 ComplexLayouter::_AddOptimizerConstraints()
465 if (fOptimizerConstraintsAdded)
466 return true;
468 fOptimizer->RemoveAllConstraints();
470 // add constraints
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) {
486 bool success = true;
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);
491 } else {
492 // min and max not equal -- add them individually,
493 // unless redundant
494 if (!minRedundant) {
495 success |= fOptimizer->AddConstraint(
496 constraint->start - 1, constraint->end,
497 constraint->min, false);
499 if (!maxRedundant) {
500 success |= fOptimizer->AddConstraint(constraint->end,
501 constraint->start - 1,
502 -constraint->effectiveMax, false);
506 if (!success)
507 return false;
510 constraint = constraint->next;
514 fOptimizerConstraintsAdded = true;
515 return true;
519 // _SatisfiesConstraints
520 bool
521 ComplexLayouter::_SatisfiesConstraints(int32* sizes) const
523 int32 sumValues[fElementCount + 1];
524 sumValues[0] = 0;
525 for (int32 i = 0; i < fElementCount; i++)
526 sumValues[i + 1] = sumValues[i] + sizes[i];
528 return _SatisfiesConstraintsSums(sumValues);
532 // _SatisfiesConstraintsSums
533 bool
534 ComplexLayouter::_SatisfiesConstraintsSums(int32* sumValues) const
536 for (int32 i = 0; i < fElementCount; i++) {
537 Constraint* constraint = fConstraints[i];
538 while (constraint) {
539 if (!constraint->IsSatisfied(sumValues))
540 return false;
542 constraint = constraint->next;
546 return true;
550 // _ValidateLayout
551 void
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
560 // we define
561 // c[0] = 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.
585 if (fMinMaxValid)
586 return;
588 fSums[0].min = 0;
589 fSums[0].max = 0;
591 int32 maxSum = 0;
592 for (int32 i = 0; i < fElementCount; i++) {
593 SumItem& sum = fSums[i + 1];
594 sum.min = 0;
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) {
609 sum.min = minSum;
610 } else {
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)
629 base.max = baseMax;
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);
650 #endif
652 if (fElementCount == 0) {
653 fMin = -1;
654 fMax = B_SIZE_UNLIMITED;
655 } else {
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;
664 fMinMaxValid = true;
668 // _ApplyMaxConstraint
669 void
670 ComplexLayouter::_ApplyMaxConstraint(Constraint* currentConstraint, int32 index)
672 SumItem& sum = fSums[index + 1];
673 SumItem& base = fSums[currentConstraint->start];
675 // We want to apply:
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
683 // back.
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) {
691 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) {
699 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);
715 return;
718 // backup old values, in case we detect a conflict later
719 _BackupValues(index);
721 int32 diff;
722 do {
723 // apply the changes
724 int32 changedIndex = currentConstraint->start;
726 if (baseMin > base.min) {
727 base.min = baseMin;
728 base.minDirty = true;
731 if (sumMax < sum.max) {
732 changedIndex = index;
733 sum.max = sumMax;
734 sum.maxDirty = true;
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
743 diff = 0;
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
764 if (diff > 0) {
765 max += diff;
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)
777 return;
779 } while (diff > 0);
783 // _PropagateChanges
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.
789 void
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]
806 if (base.minDirty) {
807 int32 sumMin = base.min + constraint->min;
808 if (sumMin > sum.min) {
809 sum.min = sumMin;
810 sum.minDirty = true;
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) {
818 sum.max = sumMax;
819 sum.maxDirty = true;
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);
831 sum.max = sum.min;
832 sum.maxDirty = true;
839 // _PropagateChangesBack
840 void
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);
865 base.min = baseMin;
866 base.minDirty = true;
870 // maxc[i-1] <= maxc[k] - min[i,j]
871 if (sum.maxDirty) {
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);
879 base.max = baseMax;
880 base.maxDirty = true;
884 constraint = constraint->next;
890 // _BackupValues
891 void
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;
902 // _RestoreValues
903 void
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;