зеркало из https://github.com/mozilla/gecko-dev.git
Bug 367673, Handle width-computation arithmetic with nscoord_MAX. r=roc sr=roc a1.9=roc
This commit is contained in:
Родитель
d839a460f6
Коммит
5e31bd00b0
|
@ -121,6 +121,103 @@ inline nscoord NSCoordDivide(nscoord aCoord, PRInt32 aVal) {
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a + b, capping the sum to nscoord_MAX.
|
||||
*
|
||||
* This function assumes that neither argument is nscoord_MIN.
|
||||
*
|
||||
* Note: If/when we start using floats for nscoords, this function won't be as
|
||||
* necessary. Normal float addition correctly handles adding with infinity,
|
||||
* assuming we aren't adding nscoord_MIN. (-infinity)
|
||||
*/
|
||||
inline nscoord
|
||||
NSCoordSaturatingAdd(nscoord a, nscoord b)
|
||||
{
|
||||
VERIFY_COORD(a);
|
||||
VERIFY_COORD(b);
|
||||
NS_ASSERTION(a != nscoord_MIN && b != nscoord_MIN,
|
||||
"NSCoordSaturatingAdd got nscoord_MIN as argument");
|
||||
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
// Float math correctly handles a+b, given that neither is -infinity.
|
||||
return a + b;
|
||||
#else
|
||||
if (a == nscoord_MAX || b == nscoord_MAX) {
|
||||
// infinity + anything = anything + infinity = infinity
|
||||
return nscoord_MAX;
|
||||
} else {
|
||||
// a + b = a + b
|
||||
NS_ASSERTION(a < nscoord_MAX && b < nscoord_MAX,
|
||||
"Doing nscoord addition with values > nscoord_MAX");
|
||||
NS_ASSERTION((PRInt64)a + (PRInt64)b < (PRInt64)nscoord_MAX,
|
||||
"nscoord addition will reach or pass nscoord_MAX");
|
||||
NS_ASSERTION((PRInt64)a + (PRInt64)b > (PRInt64)nscoord_MIN,
|
||||
"nscoord addition will reach or pass nscoord_MIN");
|
||||
|
||||
// Cap the result, just in case we're dealing with numbers near nscoord_MAX
|
||||
return PR_MIN(nscoord_MAX, a + b);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a - b, gracefully handling cases involving nscoord_MAX.
|
||||
* This function assumes that neither argument is nscoord_MIN.
|
||||
*
|
||||
* The behavior is as follows:
|
||||
*
|
||||
* a) infinity - infinity -> infMinusInfResult
|
||||
* b) N - infinity -> 0 (unexpected -- triggers NOTREACHED)
|
||||
* c) infinity - N -> infinity
|
||||
* d) N1 - N2 -> N1 - N2
|
||||
*
|
||||
* Note: For float nscoords, cases (c) and (d) are handled by normal float
|
||||
* math. We still need to explicitly specify the behavior for cases (a)
|
||||
* and (b), though. (Under normal float math, those cases would return NaN
|
||||
* and -infinity, respectively.)
|
||||
*/
|
||||
inline nscoord
|
||||
NSCoordSaturatingSubtract(nscoord a, nscoord b,
|
||||
nscoord infMinusInfResult)
|
||||
{
|
||||
VERIFY_COORD(a);
|
||||
VERIFY_COORD(b);
|
||||
NS_ASSERTION(a != nscoord_MIN && b != nscoord_MIN,
|
||||
"NSCoordSaturatingSubtract got nscoord_MIN as argument");
|
||||
|
||||
if (b == nscoord_MAX) {
|
||||
if (a == nscoord_MAX) {
|
||||
// case (a)
|
||||
return infMinusInfResult;
|
||||
} else {
|
||||
// case (b)
|
||||
NS_NOTREACHED("Attempted to subtract [n - nscoord_MAX]");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
// case (c) and (d) for floats. (float math handles both)
|
||||
return a - b;
|
||||
#else
|
||||
if (a == nscoord_MAX) {
|
||||
// case (c) for integers
|
||||
return nscoord_MAX;
|
||||
} else {
|
||||
// case (d) for integers
|
||||
NS_ASSERTION(a < nscoord_MAX && b < nscoord_MAX,
|
||||
"Doing nscoord subtraction with values > nscoord_MAX");
|
||||
NS_ASSERTION((PRInt64)a - (PRInt64)b < (PRInt64)nscoord_MAX,
|
||||
"nscoord subtraction will reach or pass nscoord_MAX");
|
||||
NS_ASSERTION((PRInt64)a - (PRInt64)b > (PRInt64)nscoord_MIN,
|
||||
"nscoord subtraction will reach or pass nscoord_MIN");
|
||||
|
||||
// Cap the result, in case we're dealing with numbers near nscoord_MAX
|
||||
return PR_MIN(nscoord_MAX, a - b);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an nscoord to a PRInt32. This *does not* do rounding because
|
||||
* coords are never fractional. They can be out of range, so this does
|
||||
|
|
|
@ -1508,7 +1508,7 @@ nsLayoutUtils::IntrinsicForContainer(nsIRenderingContext *aRenderingContext,
|
|||
|
||||
if (boxSizing == NS_STYLE_BOX_SIZING_PADDING) {
|
||||
min += coordOutsideWidth;
|
||||
result += coordOutsideWidth;
|
||||
result = NSCoordSaturatingAdd(result, coordOutsideWidth);
|
||||
pctTotal += pctOutsideWidth;
|
||||
|
||||
coordOutsideWidth = 0;
|
||||
|
@ -1519,7 +1519,7 @@ nsLayoutUtils::IntrinsicForContainer(nsIRenderingContext *aRenderingContext,
|
|||
|
||||
if (boxSizing == NS_STYLE_BOX_SIZING_BORDER) {
|
||||
min += coordOutsideWidth;
|
||||
result += coordOutsideWidth;
|
||||
result = NSCoordSaturatingAdd(result, coordOutsideWidth);
|
||||
pctTotal += pctOutsideWidth;
|
||||
|
||||
coordOutsideWidth = 0;
|
||||
|
@ -1530,7 +1530,7 @@ nsLayoutUtils::IntrinsicForContainer(nsIRenderingContext *aRenderingContext,
|
|||
pctOutsideWidth += offsets.hPctMargin;
|
||||
|
||||
min += coordOutsideWidth;
|
||||
result += coordOutsideWidth;
|
||||
result = NSCoordSaturatingAdd(result, coordOutsideWidth);
|
||||
pctTotal += pctOutsideWidth;
|
||||
|
||||
nscoord w;
|
||||
|
|
|
@ -2790,8 +2790,9 @@ nsFrame::AddInlinePrefWidth(nsIRenderingContext *aRenderingContext,
|
|||
{
|
||||
aData->trailingWhitespace = 0;
|
||||
aData->skipWhitespace = PR_FALSE;
|
||||
aData->currentLine += nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
|
||||
this, nsLayoutUtils::PREF_WIDTH);
|
||||
nscoord myPref = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
|
||||
this, nsLayoutUtils::PREF_WIDTH);
|
||||
aData->currentLine = NSCoordSaturatingAdd(aData->currentLine, myPref);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -219,7 +219,7 @@ GetWidthInfo(nsIRenderingContext *aRenderingContext,
|
|||
// XXX Should we ignore percentage padding?
|
||||
nscoord add = offsets.hPadding + offsets.hBorder;
|
||||
minCoord += add;
|
||||
prefCoord += add;
|
||||
prefCoord = NSCoordSaturatingAdd(prefCoord, add);
|
||||
}
|
||||
|
||||
return CellWidthInfo(minCoord, prefCoord, prefPercent, hasSpecifiedWidth);
|
||||
|
@ -490,8 +490,10 @@ BasicTableLayoutStrategy::ComputeColumnIntrinsicWidths(nsIRenderingContext* aRen
|
|||
NSToCoordRound(float(minWithinPref) * minRatio);
|
||||
nscoord allocatedMinOutsidePref =
|
||||
NSToCoordRound(float(minOutsidePref) * coordRatio);
|
||||
nscoord allocatedPref =
|
||||
NSToCoordRound(float(info.prefCoord) * coordRatio);
|
||||
nscoord allocatedPref =
|
||||
(info.prefCoord == nscoord_MAX ?
|
||||
nscoord_MAX :
|
||||
NSToCoordRound(float(info.prefCoord) * coordRatio));
|
||||
nscoord spanMin = scolFrame->GetMinCoord() +
|
||||
allocatedMinWithinPref + allocatedMinOutsidePref;
|
||||
nscoord spanPref = scolFrame->GetPrefCoord() + allocatedPref;
|
||||
|
@ -503,7 +505,9 @@ BasicTableLayoutStrategy::ComputeColumnIntrinsicWidths(nsIRenderingContext* aRen
|
|||
// passed from the totals.
|
||||
minWithinPref -= allocatedMinWithinPref;
|
||||
minOutsidePref -= allocatedMinOutsidePref;
|
||||
info.prefCoord -= allocatedPref;
|
||||
info.prefCoord = NSCoordSaturatingSubtract(info.prefCoord,
|
||||
allocatedPref,
|
||||
nscoord_MAX);
|
||||
info.prefPercent -= allocatedPct;
|
||||
totalSPref -= scolFrame->GetPrefCoord();
|
||||
totalSMin -= scolFrame->GetMinCoord();
|
||||
|
@ -521,7 +525,8 @@ BasicTableLayoutStrategy::ComputeColumnIntrinsicWidths(nsIRenderingContext* aRen
|
|||
NS_ASSERTION(totalSPref == 0 && totalSMin == 0 &&
|
||||
totalSNonPctPref == 0 && nonPctCount == 0 &&
|
||||
minOutsidePref == 0 && minWithinPref == 0 &&
|
||||
info.prefCoord == 0 &&
|
||||
(info.prefCoord == 0 ||
|
||||
info.prefCoord == nscoord_MAX) &&
|
||||
(info.prefPercent == 0.0f || !spanHasNonPct),
|
||||
"didn't subtract all that we added");
|
||||
} while ((item = item->next));
|
||||
|
@ -593,7 +598,7 @@ BasicTableLayoutStrategy::ComputeIntrinsicWidths(nsIRenderingContext* aRendering
|
|||
add += spacing;
|
||||
}
|
||||
min += colFrame->GetMinCoord();
|
||||
pref += colFrame->GetPrefCoord();
|
||||
pref = NSCoordSaturatingAdd(pref, colFrame->GetPrefCoord());
|
||||
|
||||
// Percentages are of the table, so we have to reverse them for
|
||||
// intrinsic widths.
|
||||
|
@ -640,8 +645,8 @@ BasicTableLayoutStrategy::ComputeIntrinsicWidths(nsIRenderingContext* aRendering
|
|||
// border-spacing isn't part of the basis for percentages
|
||||
if (colCount > 0) {
|
||||
min += add;
|
||||
pref += add;
|
||||
pref_pct_expand += add;
|
||||
pref = NSCoordSaturatingAdd(pref, add);
|
||||
pref_pct_expand = NSCoordSaturatingAdd(pref_pct_expand, add);
|
||||
}
|
||||
|
||||
mMinWidth = min;
|
||||
|
@ -749,6 +754,7 @@ BasicTableLayoutStrategy::ComputeColumnWidths(const nsHTMLReflowState& aReflowSt
|
|||
total_flex_pref = 0,
|
||||
total_fixed_pref = 0;
|
||||
float total_pct = 0.0f; // 0.0f to 1.0f
|
||||
PRInt32 numInfiniteWidthCols = 0;
|
||||
|
||||
PRInt32 col;
|
||||
for (col = 0; col < colCount; ++col) {
|
||||
|
@ -769,19 +775,26 @@ BasicTableLayoutStrategy::ComputeColumnWidths(const nsHTMLReflowState& aReflowSt
|
|||
guess_pref += val;
|
||||
} else {
|
||||
nscoord pref_width = colFrame->GetPrefCoord();
|
||||
guess_pref += pref_width;
|
||||
if (pref_width == nscoord_MAX) {
|
||||
numInfiniteWidthCols++;
|
||||
}
|
||||
guess_pref = NSCoordSaturatingAdd(guess_pref, pref_width);
|
||||
guess_min_pct += min_width;
|
||||
if (colFrame->GetHasSpecifiedCoord()) {
|
||||
// we'll add on the rest of guess_min_spec outside the
|
||||
// loop
|
||||
guess_min_spec += pref_width - min_width;
|
||||
total_fixed_pref += pref_width;
|
||||
nscoord delta = NSCoordSaturatingSubtract(pref_width,
|
||||
min_width, 0);
|
||||
guess_min_spec = NSCoordSaturatingAdd(guess_min_spec, delta);
|
||||
total_fixed_pref = NSCoordSaturatingAdd(total_fixed_pref,
|
||||
pref_width);
|
||||
} else {
|
||||
total_flex_pref += pref_width;
|
||||
total_flex_pref = NSCoordSaturatingAdd(total_flex_pref,
|
||||
pref_width);
|
||||
}
|
||||
}
|
||||
}
|
||||
guess_min_spec += guess_min_pct;
|
||||
guess_min_spec = NSCoordSaturatingAdd(guess_min_spec, guess_min_pct);
|
||||
|
||||
// Determine what we're flexing:
|
||||
enum Loop2Type {
|
||||
|
@ -812,13 +825,18 @@ BasicTableLayoutStrategy::ComputeColumnWidths(const nsHTMLReflowState& aReflowSt
|
|||
} else if (width < guess_min_spec) {
|
||||
l2t = FLEX_FIXED_SMALL;
|
||||
space = width - guess_min_pct;
|
||||
basis.c = guess_min_spec - guess_min_pct;
|
||||
basis.c = NSCoordSaturatingSubtract(guess_min_spec, guess_min_pct,
|
||||
nscoord_MAX);
|
||||
} else {
|
||||
l2t = FLEX_FLEX_SMALL;
|
||||
space = width - guess_min_spec;
|
||||
basis.c = guess_pref - guess_min_spec;
|
||||
basis.c = NSCoordSaturatingSubtract(guess_pref, guess_min_spec,
|
||||
nscoord_MAX);
|
||||
}
|
||||
} else {
|
||||
// Note: Shouldn't have to check for nscoord_MAX in this case, because
|
||||
// width should be much less than nscoord_MAX, and being here means
|
||||
// guess_pref is no larger than width.
|
||||
space = width - guess_pref;
|
||||
if (total_flex_pref > 0) {
|
||||
l2t = FLEX_FLEX_LARGE;
|
||||
|
@ -903,11 +921,30 @@ BasicTableLayoutStrategy::ComputeColumnWidths(const nsHTMLReflowState& aReflowSt
|
|||
NS_ASSERTION(col_width == colFrame->GetPrefCoord(),
|
||||
"wrong width assigned");
|
||||
nscoord col_min = colFrame->GetMinCoord();
|
||||
nscoord pref_minus_min = col_width - col_min;
|
||||
nscoord pref_minus_min =
|
||||
NSCoordSaturatingSubtract(col_width, col_min, 0);
|
||||
col_width = col_width_before_adjust = col_min;
|
||||
if (pref_minus_min != 0) {
|
||||
float c = float(space) / float(basis.c);
|
||||
basis.c -= pref_minus_min;
|
||||
// If we have infinite-width cols, then the standard
|
||||
// adjustment to col_width using 'c' won't work,
|
||||
// because basis.c and pref_minus_min are both
|
||||
// nscoord_MAX and will cancel each other out in the
|
||||
// col_width adjustment (making us assign all the
|
||||
// space to the first inf-width col). To correct for
|
||||
// this, we'll also divide by numInfiniteWidthCols to
|
||||
// spread the space equally among the inf-width cols.
|
||||
if (numInfiniteWidthCols) {
|
||||
if (colFrame->GetPrefCoord() == nscoord_MAX) {
|
||||
c = c / float(numInfiniteWidthCols);
|
||||
numInfiniteWidthCols--;
|
||||
} else {
|
||||
c = 0.0f;
|
||||
}
|
||||
}
|
||||
basis.c = NSCoordSaturatingSubtract(basis.c,
|
||||
pref_minus_min,
|
||||
nscoord_MAX);
|
||||
col_width += NSToCoordRound(
|
||||
float(pref_minus_min) * c);
|
||||
}
|
||||
|
@ -971,7 +1008,7 @@ BasicTableLayoutStrategy::ComputeColumnWidths(const nsHTMLReflowState& aReflowSt
|
|||
NS_ASSERTION(space == 0 &&
|
||||
((l2t == FLEX_PCT_LARGE)
|
||||
? (-0.001f < basis.f && basis.f < 0.001f)
|
||||
: (basis.c == 0)),
|
||||
: (basis.c == 0 || basis.c == nscoord_MAX)),
|
||||
"didn't subtract all that we added");
|
||||
#ifdef DEBUG_TABLE_STRATEGY
|
||||
printf("ComputeColumnWidths final\n");
|
||||
|
|
Загрузка…
Ссылка в новой задаче