#include "SkMatrix.h"
#include "SkRandom.h"
#include "SkString.h"
+#include "SkPaint.h"
class MathBench : public SkBenchmark {
enum {
#undef MAKEREC
+static bool SkScalarIsNaN_new(SkScalar x) {
+ float y = x * 0;
+ return y == y;
+}
+
+static bool isFinite(const SkRect& r) {
+ // x * 0 will be NaN iff x is infinity or NaN.
+ // a + b will be NaN iff either a or b is NaN.
+ float value = r.fLeft * 0 + r.fTop * 0 + r.fRight * 0 + r.fBottom * 0;
+
+ // value is either NaN or it is finite (zero).
+ // value==value will be true iff value is not NaN
+ return value == value;
+}
+
class IsFiniteBench : public SkBenchmark {
enum {
N = SkBENCHLOOP(1000),
for (int i = 0; i < N; ++i) {
fData[i] = rand.nextSScalar1();
}
-
- fProc = gRec[index].fProc;
- fName = gRec[index].fName;
+
+ if (index < 0) {
+ fProc = NULL;
+ fName = "isfinite_rect";
+ } else {
+ fProc = gRec[index].fProc;
+ fName = gRec[index].fName;
+ }
}
protected:
virtual void onDraw(SkCanvas* canvas) {
IsFiniteProc proc = fProc;
const float* data = fData;
-
- for (int j = 0; j < NN; ++j) {
- for (int i = 0; i < N - 4; ++i) {
- proc(&data[i]);
+ // do this so the compiler won't throw away the function call
+ int counter = 0;
+
+ if (proc) {
+ for (int j = 0; j < NN; ++j) {
+ for (int i = 0; i < N - 4; ++i) {
+ counter += proc(&data[i]);
+ }
}
+ } else {
+ for (int j = 0; j < NN; ++j) {
+ for (int i = 0; i < N - 4; ++i) {
+ const SkRect* r = reinterpret_cast<const SkRect*>(&data[i]);
+ counter += r->isFinite();
+ }
+ }
+ }
+
+ SkPaint paint;
+ if (paint.getAlpha() == 0) {
+ SkDebugf("%d\n", counter);
}
}
static SkBenchmark* M3(void* p) { return new QMul64Bench(p); }
static SkBenchmark* M4(void* p) { return new QMul32Bench(p); }
+static SkBenchmark* M5neg1(void* p) { return new IsFiniteBench(p, -1); }
static SkBenchmark* M50(void* p) { return new IsFiniteBench(p, 0); }
static SkBenchmark* M51(void* p) { return new IsFiniteBench(p, 1); }
static SkBenchmark* M52(void* p) { return new IsFiniteBench(p, 2); }
static BenchRegistry gReg3(M3);
static BenchRegistry gReg4(M4);
+static BenchRegistry gReg5neg1(M5neg1);
static BenchRegistry gReg50(M50);
static BenchRegistry gReg51(M51);
static BenchRegistry gReg52(M52);
return r;
}
- /** Return true if the rectangle's width or height are <= 0
- */
- bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
- bool hasValidCoordinates() const;
+ /**
+ * Return true if the rectangle's width or height are <= 0
+ */
+ bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
+
+ /**
+ * Returns true iff all values in the rect are finite. If any are
+ * infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
+ * returns false.
+ */
+ bool isFinite() const {
+#ifdef SK_SCALAR_IS_FLOAT
+ // x * 0 will be NaN iff x is infinity or NaN.
+ // a + b will be NaN iff either a or b is NaN.
+ float value = fLeft * 0 + fTop * 0 + fRight * 0 + fBottom * 0;
+
+ // value is either NaN or it is finite (zero).
+ // value==value will be true iff value is not NaN
+ return value == value;
+#else
+ // use bit-or for speed, since we don't care about short-circuting the
+ // tests, and we expect the common case will be that we need to check all.
+ int isNaN = (SK_FixedNaN == fLeft) | (SK_FixedNaN == fTop) |
+ (SK_FixedNaN == fRight) | (SK_FixedNaN == fBottom);
+ return !isNaN;
+#endif
+ }
+
SkScalar left() const { return fLeft; }
SkScalar top() const { return fTop; }
SkScalar right() const { return fRight; }
*/
bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
- if (!rect.hasValidCoordinates())
+ if (!rect.isFinite())
return true;
if (fMCRec->fRasterClip->isEmpty()) {
/////////////////////////////////////////////////////////////////////////////
-bool SkRect::hasValidCoordinates() const {
- return SkScalarIsFinite(fLeft) &&
- SkScalarIsFinite(fTop) &&
- SkScalarIsFinite(fRight) &&
- SkScalarIsFinite(fBottom);
-}
-
void SkRect::sort() {
if (fLeft > fRight) {
SkTSwap<SkScalar>(fLeft, fRight);
SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
SkRect rect;
rect.set(l, t, r, b);
- REPORTER_ASSERT(reporter, !rect.hasValidCoordinates());
+ REPORTER_ASSERT(reporter, !rect.isFinite());
}
-// Tests that hasValidCoordinates() will reject any rect with +/-inf values
+// Tests that isFinite() will reject any rect with +/-inf values
// as one of its coordinates.
static void TestInfRect(skiatest::Reporter* reporter) {
#ifdef SK_SCALAR_IS_FLOAT
SkScalar big = SkIntToScalar(100);
SkRect rect = SkRect::MakeXYWH(small, small, big, big);
- REPORTER_ASSERT(reporter, rect.hasValidCoordinates());
+ REPORTER_ASSERT(reporter, rect.isFinite());
check_invalid(reporter, small, small, big, invalid);
check_invalid(reporter, small, small, invalid, big);