path ops -- use standard max, min, double-is-nan

fix a comment or two as well
Review URL: https://codereview.chromium.org/13934009

git-svn-id: http://skia.googlecode.com/svn/trunk@8822 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
caryclark@google.com 2013-04-23 11:56:44 +00:00
parent c7e08bd6d0
commit 3b97af5add
10 changed files with 75 additions and 79 deletions

View File

@ -77,6 +77,8 @@ static inline float sk_float_copysign(float x, float y) {
#define sk_float_isinf(x) isinf(x)
#endif
#define sk_double_isnan(a) sk_float_isnan(a)
#ifdef SK_USE_FLOATBITS
#define sk_float_floor2int(x) SkFloatToIntFloor(x)
#define sk_float_round2int(x) SkFloatToIntRound(x)

View File

@ -314,6 +314,14 @@ static inline int32_t SkMin32(int32_t a, int32_t b) {
return a;
}
template <typename T> const T& SkTMin(const T& a, const T& b) {
return (a < b) ? a : b;
}
template <typename T> const T& SkTMax(const T& a, const T& b) {
return (b < a) ? a : b;
}
static inline int32_t SkSign32(int32_t a) {
return (a >> 31) | ((unsigned) -a >> 31);
}

View File

@ -141,12 +141,12 @@ static void intersect(const SkDCubic& cubic1, double t1s, double t1e, const SkDC
#if 1
double c1Bottom = tIdx == 0 ? 0 :
(t1Start + (t1 - t1Start) * locals[0][tIdx - 1] + to1) / 2;
double c1Min = SkTMax<double>(c1Bottom, to1 - offset);
double c1Min = SkTMax(c1Bottom, to1 - offset);
double c1Top = tIdx == tCount - 1 ? 1 :
(t1Start + (t1 - t1Start) * locals[0][tIdx + 1] + to1) / 2;
double c1Max = SkTMin<double>(c1Top, to1 + offset);
double c2Min = SkTMax<double>(0., to2 - offset);
double c2Max = SkTMin<double>(1., to2 + offset);
double c1Max = SkTMin(c1Top, to1 + offset);
double c2Min = SkTMax(0., to2 - offset);
double c2Max = SkTMin(1., to2 + offset);
#if ONE_OFF_DEBUG
SkDebugf("%.*s %s 1 contains1=%d/%d contains2=%d/%d\n", i.depth()*2, tab,
__FUNCTION__,
@ -172,8 +172,8 @@ static void intersect(const SkDCubic& cubic1, double t1s, double t1e, const SkDC
i.used(), i.used() > 0 ? i[0][i.used() - 1] : -1);
#endif
if (tCount > 1) {
c1Min = SkTMax<double>(0., to1 - offset);
c1Max = SkTMin<double>(1., to1 + offset);
c1Min = SkTMax(0., to1 - offset);
c1Max = SkTMin(1., to1 + offset);
double c2Bottom = tIdx == 0 ? to2 :
(t2Start + (t2 - t2Start) * locals[1][tIdx - 1] + to2) / 2;
double c2Top = tIdx == tCount - 1 ? to2 :
@ -187,8 +187,8 @@ static void intersect(const SkDCubic& cubic1, double t1s, double t1e, const SkDC
if (c2Top == to2) {
c2Top = 1;
}
c2Min = SkTMax<double>(c2Bottom, to2 - offset);
c2Max = SkTMin<double>(c2Top, to2 + offset);
c2Min = SkTMax(c2Bottom, to2 - offset);
c2Max = SkTMin(c2Top, to2 + offset);
#if ONE_OFF_DEBUG
SkDebugf("%.*s %s 2 contains1=%d/%d contains2=%d/%d\n", i.depth()*2, tab,
__FUNCTION__,
@ -213,8 +213,8 @@ static void intersect(const SkDCubic& cubic1, double t1s, double t1e, const SkDC
SkDebugf("%.*s %s 2 i.used=%d t=%1.9g\n", i.depth()*2, tab, __FUNCTION__,
i.used(), i.used() > 0 ? i[0][i.used() - 1] : -1);
#endif
c1Min = SkTMax<double>(c1Bottom, to1 - offset);
c1Max = SkTMin<double>(c1Top, to1 + offset);
c1Min = SkTMax(c1Bottom, to1 - offset);
c1Max = SkTMin(c1Top, to1 + offset);
#if ONE_OFF_DEBUG
SkDebugf("%.*s %s 3 contains1=%d/%d contains2=%d/%d\n", i.depth()*2, tab,
__FUNCTION__,
@ -243,10 +243,10 @@ static void intersect(const SkDCubic& cubic1, double t1s, double t1e, const SkDC
#else
double c1Bottom = tIdx == 0 ? 0 :
(t1Start + (t1 - t1Start) * locals.fT[0][tIdx - 1] + to1) / 2;
double c1Min = SkTMax<double>(c1Bottom, to1 - offset);
double c1Min = SkTMax(c1Bottom, to1 - offset);
double c1Top = tIdx == tCount - 1 ? 1 :
(t1Start + (t1 - t1Start) * locals.fT[0][tIdx + 1] + to1) / 2;
double c1Max = SkTMin<double>(c1Top, to1 + offset);
double c1Max = SkTMin(c1Top, to1 + offset);
double c2Bottom = tIdx == 0 ? to2 :
(t2Start + (t2 - t2Start) * locals.fT[1][tIdx - 1] + to2) / 2;
double c2Top = tIdx == tCount - 1 ? to2 :
@ -260,8 +260,8 @@ static void intersect(const SkDCubic& cubic1, double t1s, double t1e, const SkDC
if (c2Top == to2) {
c2Top = 1;
}
double c2Min = SkTMax<double>(c2Bottom, to2 - offset);
double c2Max = SkTMin<double>(c2Top, to2 + offset);
double c2Min = SkTMax(c2Bottom, to2 - offset);
double c2Max = SkTMin(c2Top, to2 + offset);
#if ONE_OFF_DEBUG
SkDebugf("%s contains1=%d/%d contains2=%d/%d\n", __FUNCTION__,
c1Min <= 0.210357794 && 0.210357794 <= c1Max
@ -351,13 +351,13 @@ static void intersectEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cub
while (tLast + 1 < tVals.count() && roughly_equal(tVals[tLast + 1], tVals[tIdx])) {
++tLast;
}
double tMin2 = SkTMax<double>(tVals[tIdx] - LINE_FRACTION, 0.0);
double tMax2 = SkTMin<double>(tVals[tLast] + LINE_FRACTION, 1.0);
double tMin2 = SkTMax(tVals[tIdx] - LINE_FRACTION, 0.0);
double tMax2 = SkTMin(tVals[tLast] + LINE_FRACTION, 1.0);
int lastUsed = i.used();
intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i);
if (lastUsed == i.used()) {
tMin2 = SkTMax<double>(tVals[tIdx] - (1.0 / SkDCubic::gPrecisionUnit), 0.0);
tMax2 = SkTMin<double>(tVals[tLast] + (1.0 / SkDCubic::gPrecisionUnit), 1.0);
tMin2 = SkTMax(tVals[tIdx] - (1.0 / SkDCubic::gPrecisionUnit), 0.0);
tMax2 = SkTMin(tVals[tLast] + (1.0 / SkDCubic::gPrecisionUnit), 1.0);
intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i);
}
tIdx = tLast + 1;

View File

@ -109,16 +109,16 @@ int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) {
if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) {
return fUsed = 0;
}
fT[0][0] = SkTMax<double>(SkTMin<double>(at0, 1.0), 0.0);
fT[0][1] = SkTMax<double>(SkTMin<double>(at1, 1.0), 0.0);
fT[0][0] = SkTMax(SkTMin(at0, 1.0), 0.0);
fT[0][1] = SkTMax(SkTMin(at1, 1.0), 0.0);
}
double bDenom = b0 - b1;
if (approximately_zero(bDenom)) {
fT[1][0] = fT[1][1] = 0;
} else {
int bIn = aDenom * bDenom < 0;
fT[1][bIn] = SkTMax<double>(SkTMin<double>((b0 - a0) / bDenom, 1.0), 0.0);
fT[1][!bIn] = SkTMax<double>(SkTMin<double>((b0 - a1) / bDenom, 1.0), 0.0);
fT[1][bIn] = SkTMax(SkTMin((b0 - a0) / bDenom, 1.0), 0.0);
fT[1][!bIn] = SkTMax(SkTMin((b0 - a1) / bDenom, 1.0), 0.0);
}
bool second = fabs(fT[0][0] - fT[0][1]) > FLT_EPSILON;
SkASSERT((fabs(fT[1][0] - fT[1][1]) <= FLT_EPSILON) ^ second);
@ -189,11 +189,11 @@ int SkIntersections::horizontal(const SkDLine& line, double left, double right,
if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) {
return fUsed = 0;
}
fT[0][0] = SkTMax<double>(SkTMin<double>(at0, 1.0), 0.0);
fT[0][1] = SkTMax<double>(SkTMin<double>(at1, 1.0), 0.0);
fT[0][0] = SkTMax(SkTMin(at0, 1.0), 0.0);
fT[0][1] = SkTMax(SkTMin(at1, 1.0), 0.0);
int bIn = (a0 - a1) * (b0 - b1) < 0;
fT[1][bIn] = SkTMax<double>(SkTMin<double>((b0 - a0) / (b0 - b1), 1.0), 0.0);
fT[1][!bIn] = SkTMax<double>(SkTMin<double>((b0 - a1) / (b0 - b1), 1.0), 0.0);
fT[1][bIn] = SkTMax(SkTMin((b0 - a0) / (b0 - b1), 1.0), 0.0);
fT[1][!bIn] = SkTMax(SkTMin((b0 - a1) / (b0 - b1), 1.0), 0.0);
bool second = fabs(fT[0][0] - fT[0][1]) > FLT_EPSILON;
SkASSERT((fabs(fT[1][0] - fT[1][1]) <= FLT_EPSILON) ^ second);
return computePoints(line, 1 + second);
@ -250,11 +250,11 @@ int SkIntersections::vertical(const SkDLine& line, double top, double bottom,
if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) {
return fUsed = 0;
}
fT[0][0] = SkTMax<double>(SkTMin<double>(at0, 1.0), 0.0);
fT[0][1] = SkTMax<double>(SkTMin<double>(at1, 1.0), 0.0);
fT[0][0] = SkTMax(SkTMin(at0, 1.0), 0.0);
fT[0][1] = SkTMax(SkTMin(at1, 1.0), 0.0);
int bIn = (a0 - a1) * (b0 - b1) < 0;
fT[1][bIn] = SkTMax<double>(SkTMin<double>((b0 - a0) / (b0 - b1), 1.0), 0.0);
fT[1][!bIn] = SkTMax<double>(SkTMin<double>((b0 - a1) / (b0 - b1), 1.0), 0.0);
fT[1][bIn] = SkTMax(SkTMin((b0 - a0) / (b0 - b1), 1.0), 0.0);
fT[1][!bIn] = SkTMax(SkTMin((b0 - a1) / (b0 - b1), 1.0), 0.0);
bool second = fabs(fT[0][0] - fT[0][1]) > FLT_EPSILON;
SkASSERT((fabs(fT[1][0] - fT[1][1]) <= FLT_EPSILON) ^ second);
return computePoints(line, 1 + second);

View File

@ -243,7 +243,7 @@ static void relaxed_is_linear(const SkDQuad& q1, const SkDQuad& q2, SkIntersecti
double m1 = flat_measure(q1);
double m2 = flat_measure(q2);
#if DEBUG_FLAT_QUADS
double min = SkTMin<double>(m1, m2);
double min = SkTMin(m1, m2);
if (min > 5) {
SkDebugf("%s maybe not flat enough.. %1.9g\n", __FUNCTION__, min);
}

View File

@ -17,7 +17,9 @@ struct SkPathOpsBounds : public SkRect {
a.fTop <= b.fBottom && b.fTop <= a.fBottom;
}
// FIXME: add() is generically useful and could be added directly to SkRect
// Note that add(), unlike SkRect::join() or SkRect::growToInclude()
// does not treat the bounds of horizontal and vertical lines as
// empty rectangles.
void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
if (left < fLeft) fLeft = left;
if (top < fTop) fTop = top;

View File

@ -96,8 +96,8 @@ struct SkDPoint {
// return approximately_equal(a.fY, fY) && approximately_equal(a.fX, fX);
// because that will not take the magnitude of the values
bool approximatelyEqual(const SkDPoint& a) const {
double denom = SkTMax<double>(fabs(fX), SkTMax<double>(fabs(fY),
SkTMax<double>(fabs(a.fX), fabs(a.fY))));
double denom = SkTMax(fabs(fX), SkTMax(fabs(fY),
SkTMax(fabs(a.fX), fabs(a.fY))));
if (denom == 0) {
return true;
}
@ -107,8 +107,8 @@ struct SkDPoint {
}
bool approximatelyEqual(const SkPoint& a) const {
double denom = SkTMax<double>(fabs(fX), SkTMax<double>(fabs(fY),
SkScalarToDouble(SkTMax<SkScalar>(fabsf(a.fX), fabsf(a.fY)))));
double denom = SkTMax(fabs(fX), SkTMax(fabs(fY),
SkScalarToDouble(SkTMax(fabsf(a.fX), fabsf(a.fY)))));
if (denom == 0) {
return true;
}
@ -118,8 +118,8 @@ struct SkDPoint {
}
bool approximatelyEqualHalf(const SkDPoint& a) const {
double denom = SkTMax<double>(fabs(fX), SkTMax<double>(fabs(fY),
SkTMax<double>(fabs(a.fX), fabs(a.fY))));
double denom = SkTMax(fabs(fX), SkTMax(fabs(fY),
SkTMax(fabs(a.fX), fabs(a.fY))));
if (denom == 0) {
return true;
}

View File

@ -26,7 +26,7 @@ double SkDQuad::nearestT(const SkDPoint& pt) const {
int roots = SkDCubic::RootsValidT(a, b, c, d, ts);
double d0 = pt.distanceSquared(fPts[0]);
double d2 = pt.distanceSquared(fPts[2]);
double distMin = SkTMin<double>(d0, d2);
double distMin = SkTMin(d0, d2);
int bestIndex = -1;
for (int index = 0; index < roots; ++index) {
SkDPoint onQuad = xyAtT(ts[index]);

View File

@ -15,22 +15,6 @@
#include "SkPathOpsDebug.h"
#include "SkScalar.h"
// FIXME: move these into SkTypes.h
template <typename T> inline T SkTMax(T a, T b) {
if (a < b)
a = b;
return a;
}
template <typename T> inline T SkTMin(T a, T b) {
if (a > b)
a = b;
return a;
}
// FIXME: move this into SkFloatingPoint.h
#define sk_double_isnan(a) sk_float_isnan(a)
enum SkPathOpsMask {
kWinding_PathOpsMask = -1,
kNo_PathOpsMask = 0,

View File

@ -43,30 +43,30 @@ static void PathOpsDRectTest(skiatest::Reporter* reporter) {
for (index = 0; index < lineTests_count; ++index) {
const SkDLine& line = lineTests[index];
rect.setBounds(line);
REPORTER_ASSERT(reporter, rect.fLeft == SkTMin<double>(line[0].fX, line[1].fX));
REPORTER_ASSERT(reporter, rect.fTop == SkTMin<double>(line[0].fY, line[1].fY));
REPORTER_ASSERT(reporter, rect.fRight == SkTMax<double>(line[0].fX, line[1].fX));
REPORTER_ASSERT(reporter, rect.fBottom == SkTMax<double>(line[0].fY, line[1].fY));
REPORTER_ASSERT(reporter, rect.fLeft == SkTMin(line[0].fX, line[1].fX));
REPORTER_ASSERT(reporter, rect.fTop == SkTMin(line[0].fY, line[1].fY));
REPORTER_ASSERT(reporter, rect.fRight == SkTMax(line[0].fX, line[1].fX));
REPORTER_ASSERT(reporter, rect.fBottom == SkTMax(line[0].fY, line[1].fY));
rect2.set(line[0]);
rect2.add(line[1]);
REPORTER_ASSERT(reporter, rect2.fLeft == SkTMin<double>(line[0].fX, line[1].fX));
REPORTER_ASSERT(reporter, rect2.fTop == SkTMin<double>(line[0].fY, line[1].fY));
REPORTER_ASSERT(reporter, rect2.fRight == SkTMax<double>(line[0].fX, line[1].fX));
REPORTER_ASSERT(reporter, rect2.fBottom == SkTMax<double>(line[0].fY, line[1].fY));
REPORTER_ASSERT(reporter, rect2.fLeft == SkTMin(line[0].fX, line[1].fX));
REPORTER_ASSERT(reporter, rect2.fTop == SkTMin(line[0].fY, line[1].fY));
REPORTER_ASSERT(reporter, rect2.fRight == SkTMax(line[0].fX, line[1].fX));
REPORTER_ASSERT(reporter, rect2.fBottom == SkTMax(line[0].fY, line[1].fY));
REPORTER_ASSERT(reporter, rect.contains(line[0]));
REPORTER_ASSERT(reporter, rect.intersects(&rect2));
}
for (index = 0; index < quadTests_count; ++index) {
const SkDQuad& quad = quadTests[index];
rect.setRawBounds(quad);
REPORTER_ASSERT(reporter, rect.fLeft == SkTMin<double>(quad[0].fX,
SkTMin<double>(quad[1].fX, quad[2].fX)));
REPORTER_ASSERT(reporter, rect.fTop == SkTMin<double>(quad[0].fY,
SkTMin<double>(quad[1].fY, quad[2].fY)));
REPORTER_ASSERT(reporter, rect.fRight == SkTMax<double>(quad[0].fX,
SkTMax<double>(quad[1].fX, quad[2].fX)));
REPORTER_ASSERT(reporter, rect.fBottom == SkTMax<double>(quad[0].fY,
SkTMax<double>(quad[1].fY, quad[2].fY)));
REPORTER_ASSERT(reporter, rect.fLeft == SkTMin(quad[0].fX,
SkTMin(quad[1].fX, quad[2].fX)));
REPORTER_ASSERT(reporter, rect.fTop == SkTMin(quad[0].fY,
SkTMin(quad[1].fY, quad[2].fY)));
REPORTER_ASSERT(reporter, rect.fRight == SkTMax(quad[0].fX,
SkTMax(quad[1].fX, quad[2].fX)));
REPORTER_ASSERT(reporter, rect.fBottom == SkTMax(quad[0].fY,
SkTMax(quad[1].fY, quad[2].fY)));
rect2.setBounds(quad);
REPORTER_ASSERT(reporter, rect.intersects(&rect2));
// FIXME: add a recursive box subdivision method to verify that tight bounds is correct
@ -78,14 +78,14 @@ static void PathOpsDRectTest(skiatest::Reporter* reporter) {
for (index = 0; index < cubicTests_count; ++index) {
const SkDCubic& cubic = cubicTests[index];
rect.setRawBounds(cubic);
REPORTER_ASSERT(reporter, rect.fLeft == SkTMin<double>(cubic[0].fX,
SkTMin<double>(cubic[1].fX, SkTMin<double>(cubic[2].fX, cubic[3].fX))));
REPORTER_ASSERT(reporter, rect.fTop == SkTMin<double>(cubic[0].fY,
SkTMin<double>(cubic[1].fY, SkTMin<double>(cubic[2].fY, cubic[3].fY))));
REPORTER_ASSERT(reporter, rect.fRight == SkTMax<double>(cubic[0].fX,
SkTMax<double>(cubic[1].fX, SkTMax<double>(cubic[2].fX, cubic[3].fX))));
REPORTER_ASSERT(reporter, rect.fBottom == SkTMax<double>(cubic[0].fY,
SkTMax<double>(cubic[1].fY, SkTMax<double>(cubic[2].fY, cubic[3].fY))));
REPORTER_ASSERT(reporter, rect.fLeft == SkTMin(cubic[0].fX,
SkTMin(cubic[1].fX, SkTMin(cubic[2].fX, cubic[3].fX))));
REPORTER_ASSERT(reporter, rect.fTop == SkTMin(cubic[0].fY,
SkTMin(cubic[1].fY, SkTMin(cubic[2].fY, cubic[3].fY))));
REPORTER_ASSERT(reporter, rect.fRight == SkTMax(cubic[0].fX,
SkTMax(cubic[1].fX, SkTMax(cubic[2].fX, cubic[3].fX))));
REPORTER_ASSERT(reporter, rect.fBottom == SkTMax(cubic[0].fY,
SkTMax(cubic[1].fY, SkTMax(cubic[2].fY, cubic[3].fY))));
rect2.setBounds(cubic);
REPORTER_ASSERT(reporter, rect.intersects(&rect2));
// FIXME: add a recursive box subdivision method to verify that tight bounds is correct