Initial import of Cobalt 2.8885 2016-07-27
diff --git a/src/third_party/skia/tests/AAClipTest.cpp b/src/third_party/skia/tests/AAClipTest.cpp
new file mode 100644
index 0000000..64e3784
--- /dev/null
+++ b/src/third_party/skia/tests/AAClipTest.cpp
@@ -0,0 +1,433 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkAAClip.h"
+#include "SkCanvas.h"
+#include "SkMask.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "Test.h"
+
+static bool operator==(const SkMask& a, const SkMask& b) {
+ if (a.fFormat != b.fFormat || a.fBounds != b.fBounds) {
+ return false;
+ }
+ if (!a.fImage && !b.fImage) {
+ return true;
+ }
+ if (!a.fImage || !b.fImage) {
+ return false;
+ }
+
+ size_t wbytes = a.fBounds.width();
+ switch (a.fFormat) {
+ case SkMask::kBW_Format:
+ wbytes = (wbytes + 7) >> 3;
+ break;
+ case SkMask::kA8_Format:
+ case SkMask::k3D_Format:
+ break;
+ case SkMask::kLCD16_Format:
+ wbytes <<= 1;
+ break;
+ case SkMask::kLCD32_Format:
+ case SkMask::kARGB32_Format:
+ wbytes <<= 2;
+ break;
+ default:
+ SkDEBUGFAIL("unknown mask format");
+ return false;
+ }
+
+ const int h = a.fBounds.height();
+ const char* aptr = (const char*)a.fImage;
+ const char* bptr = (const char*)b.fImage;
+ for (int y = 0; y < h; ++y) {
+ if (memcmp(aptr, bptr, wbytes)) {
+ return false;
+ }
+ aptr += wbytes;
+ bptr += wbytes;
+ }
+ return true;
+}
+
+static void copyToMask(const SkRegion& rgn, SkMask* mask) {
+ mask->fFormat = SkMask::kA8_Format;
+
+ if (rgn.isEmpty()) {
+ mask->fBounds.setEmpty();
+ mask->fRowBytes = 0;
+ mask->fImage = NULL;
+ return;
+ }
+
+ mask->fBounds = rgn.getBounds();
+ mask->fRowBytes = mask->fBounds.width();
+ mask->fImage = SkMask::AllocImage(mask->computeImageSize());
+ sk_bzero(mask->fImage, mask->computeImageSize());
+
+ SkImageInfo info = SkImageInfo::Make(mask->fBounds.width(),
+ mask->fBounds.height(),
+ kAlpha_8_SkColorType,
+ kPremul_SkAlphaType);
+ SkBitmap bitmap;
+ bitmap.installPixels(info, mask->fImage, mask->fRowBytes);
+
+ // canvas expects its coordinate system to always be 0,0 in the top/left
+ // so we translate the rgn to match that before drawing into the mask.
+ //
+ SkRegion tmpRgn(rgn);
+ tmpRgn.translate(-rgn.getBounds().fLeft, -rgn.getBounds().fTop);
+
+ SkCanvas canvas(bitmap);
+ canvas.clipRegion(tmpRgn);
+ canvas.drawColor(SK_ColorBLACK);
+}
+
+static SkIRect rand_rect(SkRandom& rand, int n) {
+ int x = rand.nextS() % n;
+ int y = rand.nextS() % n;
+ int w = rand.nextU() % n;
+ int h = rand.nextU() % n;
+ return SkIRect::MakeXYWH(x, y, w, h);
+}
+
+static void make_rand_rgn(SkRegion* rgn, SkRandom& rand) {
+ int count = rand.nextU() % 20;
+ for (int i = 0; i < count; ++i) {
+ rgn->op(rand_rect(rand, 100), SkRegion::kXOR_Op);
+ }
+}
+
+static bool operator==(const SkRegion& rgn, const SkAAClip& aaclip) {
+ SkMask mask0, mask1;
+
+ copyToMask(rgn, &mask0);
+ aaclip.copyToMask(&mask1);
+ bool eq = (mask0 == mask1);
+
+ SkMask::FreeImage(mask0.fImage);
+ SkMask::FreeImage(mask1.fImage);
+ return eq;
+}
+
+static bool equalsAAClip(const SkRegion& rgn) {
+ SkAAClip aaclip;
+ aaclip.setRegion(rgn);
+ return rgn == aaclip;
+}
+
+static void setRgnToPath(SkRegion* rgn, const SkPath& path) {
+ SkIRect ir;
+ path.getBounds().round(&ir);
+ rgn->setPath(path, SkRegion(ir));
+}
+
+// aaclip.setRegion should create idential masks to the region
+static void test_rgn(skiatest::Reporter* reporter) {
+ SkRandom rand;
+ for (int i = 0; i < 1000; i++) {
+ SkRegion rgn;
+ make_rand_rgn(&rgn, rand);
+ REPORTER_ASSERT(reporter, equalsAAClip(rgn));
+ }
+
+ {
+ SkRegion rgn;
+ SkPath path;
+ path.addCircle(0, 0, SkIntToScalar(30));
+ setRgnToPath(&rgn, path);
+ REPORTER_ASSERT(reporter, equalsAAClip(rgn));
+
+ path.reset();
+ path.moveTo(0, 0);
+ path.lineTo(SkIntToScalar(100), 0);
+ path.lineTo(SkIntToScalar(100 - 20), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
+ setRgnToPath(&rgn, path);
+ REPORTER_ASSERT(reporter, equalsAAClip(rgn));
+ }
+}
+
+static const SkRegion::Op gRgnOps[] = {
+ SkRegion::kDifference_Op,
+ SkRegion::kIntersect_Op,
+ SkRegion::kUnion_Op,
+ SkRegion::kXOR_Op,
+ SkRegion::kReverseDifference_Op,
+ SkRegion::kReplace_Op
+};
+
+static const char* gRgnOpNames[] = {
+ "DIFF", "INTERSECT", "UNION", "XOR", "REVERSE_DIFF", "REPLACE"
+};
+
+static void imoveTo(SkPath& path, int x, int y) {
+ path.moveTo(SkIntToScalar(x), SkIntToScalar(y));
+}
+
+static void icubicTo(SkPath& path, int x0, int y0, int x1, int y1, int x2, int y2) {
+ path.cubicTo(SkIntToScalar(x0), SkIntToScalar(y0),
+ SkIntToScalar(x1), SkIntToScalar(y1),
+ SkIntToScalar(x2), SkIntToScalar(y2));
+}
+
+static void test_path_bounds(skiatest::Reporter* reporter) {
+ SkPath path;
+ SkAAClip clip;
+ const int height = 40;
+ const SkScalar sheight = SkIntToScalar(height);
+
+ path.addOval(SkRect::MakeWH(sheight, sheight));
+ REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
+ clip.setPath(path, NULL, true);
+ REPORTER_ASSERT(reporter, height == clip.getBounds().height());
+
+ // this is the trimmed height of this cubic (with aa). The critical thing
+ // for this test is that it is less than height, which represents just
+ // the bounds of the path's control-points.
+ //
+ // This used to fail until we tracked the MinY in the BuilderBlitter.
+ //
+ const int teardrop_height = 12;
+ path.reset();
+ imoveTo(path, 0, 20);
+ icubicTo(path, 40, 40, 40, 0, 0, 20);
+ REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
+ clip.setPath(path, NULL, true);
+ REPORTER_ASSERT(reporter, teardrop_height == clip.getBounds().height());
+}
+
+static void test_empty(skiatest::Reporter* reporter) {
+ SkAAClip clip0, clip1;
+
+ REPORTER_ASSERT(reporter, clip0.isEmpty());
+ REPORTER_ASSERT(reporter, clip0.getBounds().isEmpty());
+ REPORTER_ASSERT(reporter, clip1 == clip0);
+
+ clip0.translate(10, 10); // should have no effect on empty
+ REPORTER_ASSERT(reporter, clip0.isEmpty());
+ REPORTER_ASSERT(reporter, clip0.getBounds().isEmpty());
+ REPORTER_ASSERT(reporter, clip1 == clip0);
+
+ SkIRect r = { 10, 10, 40, 50 };
+ clip0.setRect(r);
+ REPORTER_ASSERT(reporter, !clip0.isEmpty());
+ REPORTER_ASSERT(reporter, !clip0.getBounds().isEmpty());
+ REPORTER_ASSERT(reporter, clip0 != clip1);
+ REPORTER_ASSERT(reporter, clip0.getBounds() == r);
+
+ clip0.setEmpty();
+ REPORTER_ASSERT(reporter, clip0.isEmpty());
+ REPORTER_ASSERT(reporter, clip0.getBounds().isEmpty());
+ REPORTER_ASSERT(reporter, clip1 == clip0);
+
+ SkMask mask;
+ mask.fImage = NULL;
+ clip0.copyToMask(&mask);
+ REPORTER_ASSERT(reporter, NULL == mask.fImage);
+ REPORTER_ASSERT(reporter, mask.fBounds.isEmpty());
+}
+
+static void rand_irect(SkIRect* r, int N, SkRandom& rand) {
+ r->setXYWH(0, 0, rand.nextU() % N, rand.nextU() % N);
+ int dx = rand.nextU() % (2*N);
+ int dy = rand.nextU() % (2*N);
+ // use int dx,dy to make the subtract be signed
+ r->offset(N - dx, N - dy);
+}
+
+static void test_irect(skiatest::Reporter* reporter) {
+ SkRandom rand;
+
+ for (int i = 0; i < 10000; i++) {
+ SkAAClip clip0, clip1;
+ SkRegion rgn0, rgn1;
+ SkIRect r0, r1;
+
+ rand_irect(&r0, 10, rand);
+ rand_irect(&r1, 10, rand);
+ clip0.setRect(r0);
+ clip1.setRect(r1);
+ rgn0.setRect(r0);
+ rgn1.setRect(r1);
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gRgnOps); ++j) {
+ SkRegion::Op op = gRgnOps[j];
+ SkAAClip clip2;
+ SkRegion rgn2;
+ bool nonEmptyAA = clip2.op(clip0, clip1, op);
+ bool nonEmptyBW = rgn2.op(rgn0, rgn1, op);
+ if (nonEmptyAA != nonEmptyBW || clip2.getBounds() != rgn2.getBounds()) {
+ SkDebugf("[%d %d %d %d] %s [%d %d %d %d] = BW:[%d %d %d %d] AA:[%d %d %d %d]\n",
+ r0.fLeft, r0.fTop, r0.right(), r0.bottom(),
+ gRgnOpNames[j],
+ r1.fLeft, r1.fTop, r1.right(), r1.bottom(),
+ rgn2.getBounds().fLeft, rgn2.getBounds().fTop,
+ rgn2.getBounds().right(), rgn2.getBounds().bottom(),
+ clip2.getBounds().fLeft, clip2.getBounds().fTop,
+ clip2.getBounds().right(), clip2.getBounds().bottom());
+ }
+ REPORTER_ASSERT(reporter, nonEmptyAA == nonEmptyBW);
+ REPORTER_ASSERT(reporter, clip2.getBounds() == rgn2.getBounds());
+
+ SkMask maskBW, maskAA;
+ copyToMask(rgn2, &maskBW);
+ clip2.copyToMask(&maskAA);
+ SkAutoMaskFreeImage freeBW(maskBW.fImage);
+ SkAutoMaskFreeImage freeAA(maskAA.fImage);
+ REPORTER_ASSERT(reporter, maskBW == maskAA);
+ }
+ }
+}
+
+static void test_path_with_hole(skiatest::Reporter* reporter) {
+ static const uint8_t gExpectedImage[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ };
+ SkMask expected;
+ expected.fBounds.set(0, 0, 4, 6);
+ expected.fRowBytes = 4;
+ expected.fFormat = SkMask::kA8_Format;
+ expected.fImage = (uint8_t*)gExpectedImage;
+
+ SkPath path;
+ path.addRect(SkRect::MakeXYWH(0, 0,
+ SkIntToScalar(4), SkIntToScalar(2)));
+ path.addRect(SkRect::MakeXYWH(0, SkIntToScalar(4),
+ SkIntToScalar(4), SkIntToScalar(2)));
+
+ for (int i = 0; i < 2; ++i) {
+ SkAAClip clip;
+ clip.setPath(path, NULL, 1 == i);
+
+ SkMask mask;
+ clip.copyToMask(&mask);
+ SkAutoMaskFreeImage freeM(mask.fImage);
+
+ REPORTER_ASSERT(reporter, expected == mask);
+ }
+}
+
+static void test_really_a_rect(skiatest::Reporter* reporter) {
+ SkRRect rrect;
+ rrect.setRectXY(SkRect::MakeWH(100, 100), 5, 5);
+
+ SkPath path;
+ path.addRRect(rrect);
+
+ SkAAClip clip;
+ clip.setPath(path);
+
+ REPORTER_ASSERT(reporter, clip.getBounds() == SkIRect::MakeWH(100, 100));
+ REPORTER_ASSERT(reporter, !clip.isRect());
+
+ // This rect should intersect the clip, but slice-out all of the "soft" parts,
+ // leaving just a rect.
+ const SkIRect ir = SkIRect::MakeLTRB(10, -10, 50, 90);
+
+ clip.op(ir, SkRegion::kIntersect_Op);
+
+ REPORTER_ASSERT(reporter, clip.getBounds() == SkIRect::MakeLTRB(10, 0, 50, 90));
+ // the clip recognized that that it is just a rect!
+ REPORTER_ASSERT(reporter, clip.isRect());
+}
+
+#include "SkRasterClip.h"
+
+static void copyToMask(const SkRasterClip& rc, SkMask* mask) {
+ if (rc.isAA()) {
+ rc.aaRgn().copyToMask(mask);
+ } else {
+ copyToMask(rc.bwRgn(), mask);
+ }
+}
+
+static bool operator==(const SkRasterClip& a, const SkRasterClip& b) {
+ if (a.isEmpty()) {
+ return b.isEmpty();
+ }
+ if (b.isEmpty()) {
+ return false;
+ }
+
+ SkMask ma, mb;
+ copyToMask(a, &ma);
+ copyToMask(b, &mb);
+ SkAutoMaskFreeImage aCleanUp(ma.fImage);
+ SkAutoMaskFreeImage bCleanUp(mb.fImage);
+
+ return ma == mb;
+}
+
+static void did_dx_affect(skiatest::Reporter* reporter, const SkScalar dx[],
+ size_t count, bool changed) {
+ const SkISize baseSize = SkISize::Make(10, 10);
+ SkIRect ir = { 0, 0, 10, 10 };
+
+ for (size_t i = 0; i < count; ++i) {
+ SkRect r;
+ r.set(ir);
+
+ SkRasterClip rc0(ir);
+ SkRasterClip rc1(ir);
+ SkRasterClip rc2(ir);
+
+ rc0.op(r, baseSize, SkRegion::kIntersect_Op, false);
+ r.offset(dx[i], 0);
+ rc1.op(r, baseSize, SkRegion::kIntersect_Op, true);
+ r.offset(-2*dx[i], 0);
+ rc2.op(r, baseSize, SkRegion::kIntersect_Op, true);
+
+ REPORTER_ASSERT(reporter, changed != (rc0 == rc1));
+ REPORTER_ASSERT(reporter, changed != (rc0 == rc2));
+ }
+}
+
+static void test_nearly_integral(skiatest::Reporter* reporter) {
+ // All of these should generate equivalent rasterclips
+
+ static const SkScalar gSafeX[] = {
+ 0, SK_Scalar1/1000, SK_Scalar1/100, SK_Scalar1/10,
+ };
+ did_dx_affect(reporter, gSafeX, SK_ARRAY_COUNT(gSafeX), false);
+
+ static const SkScalar gUnsafeX[] = {
+ SK_Scalar1/4, SK_Scalar1/3,
+ };
+ did_dx_affect(reporter, gUnsafeX, SK_ARRAY_COUNT(gUnsafeX), true);
+}
+
+static void test_regressions() {
+ // these should not assert in the debug build
+ // bug was introduced in rev. 3209
+ {
+ SkAAClip clip;
+ SkRect r;
+ r.fLeft = 129.892181f;
+ r.fTop = 10.3999996f;
+ r.fRight = 130.892181f;
+ r.fBottom = 20.3999996f;
+ clip.setRect(r, true);
+ }
+}
+
+DEF_TEST(AAClip, reporter) {
+ test_empty(reporter);
+ test_path_bounds(reporter);
+ test_irect(reporter);
+ test_rgn(reporter);
+ test_path_with_hole(reporter);
+ test_regressions();
+ test_nearly_integral(reporter);
+ test_really_a_rect(reporter);
+}
diff --git a/src/third_party/skia/tests/ARGBImageEncoderTest.cpp b/src/third_party/skia/tests/ARGBImageEncoderTest.cpp
new file mode 100644
index 0000000..4d16f4c
--- /dev/null
+++ b/src/third_party/skia/tests/ARGBImageEncoderTest.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkImageEncoder.h"
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkStream.h"
+#include "Test.h"
+
+static SkColorType gColorTypes[] = {
+ kRGB_565_SkColorType,
+ kN32_SkColorType,
+};
+
+DEF_TEST(ARGBImageEncoder, reporter) {
+ // Bytes we expect to get:
+ const int kWidth = 3;
+ const int kHeight = 5;
+ const unsigned char comparisonBuffer[] = {
+ // kHeight rows, each with kWidth pixels, premultiplied ARGB for each pixel
+ 0xff,0xff,0x00,0x00, 0xff,0xff,0x00,0x00, 0xff,0xff,0x00,0x00, // red
+ 0xff,0x00,0xff,0x00, 0xff,0x00,0xff,0x00, 0xff,0x00,0xff,0x00, // green
+ 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, // blue
+ 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, // blue
+ 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, // blue
+ };
+
+ SkAutoTDelete<SkImageEncoder> enc(CreateARGBImageEncoder());
+ for (size_t ctIndex = 0; ctIndex < SK_ARRAY_COUNT(gColorTypes); ++ctIndex) {
+ // A bitmap that should generate the above bytes:
+ SkBitmap bitmap;
+ {
+ bitmap.allocPixels(SkImageInfo::Make(kWidth, kHeight, gColorTypes[ctIndex],
+ kOpaque_SkAlphaType));
+ bitmap.eraseColor(SK_ColorBLUE);
+ // Change rows [0,1] from blue to [red,green].
+ SkCanvas canvas(bitmap);
+ SkPaint paint;
+ paint.setColor(SK_ColorRED);
+ canvas.drawIRect(SkIRect::MakeLTRB(0, 0, kWidth, 1), paint);
+ paint.setColor(SK_ColorGREEN);
+ canvas.drawIRect(SkIRect::MakeLTRB(0, 1, kWidth, 2), paint);
+ }
+
+ // Transform the bitmap.
+ int bufferSize = bitmap.width() * bitmap.height() * 4;
+ SkAutoMalloc pixelBufferManager(bufferSize);
+ char *pixelBuffer = static_cast<char *>(pixelBufferManager.get());
+ SkMemoryWStream out(pixelBuffer, bufferSize);
+ REPORTER_ASSERT(reporter, enc->encodeStream(&out, bitmap, SkImageEncoder::kDefaultQuality));
+
+ // Confirm we got the expected results.
+ REPORTER_ASSERT(reporter, bufferSize == sizeof(comparisonBuffer));
+ REPORTER_ASSERT(reporter, memcmp(pixelBuffer, comparisonBuffer, bufferSize) == 0);
+ }
+}
diff --git a/src/third_party/skia/tests/AnnotationTest.cpp b/src/third_party/skia/tests/AnnotationTest.cpp
new file mode 100644
index 0000000..274d53e
--- /dev/null
+++ b/src/third_party/skia/tests/AnnotationTest.cpp
@@ -0,0 +1,95 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkAnnotation.h"
+#include "SkCanvas.h"
+#include "SkData.h"
+#include "SkPDFDevice.h"
+#include "SkPDFDocument.h"
+#include "Test.h"
+
+/** Returns true if data (may contain null characters) contains needle (null
+ * terminated). */
+static bool ContainsString(const char* data, size_t dataSize, const char* needle) {
+ size_t nSize = strlen(needle);
+ for (size_t i = 0; i < dataSize - nSize; i++) {
+ if (strncmp(&data[i], needle, nSize) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+DEF_TEST(Annotation_NoDraw, reporter) {
+ SkBitmap bm;
+ bm.allocN32Pixels(10, 10);
+ bm.eraseColor(SK_ColorTRANSPARENT);
+
+ SkCanvas canvas(bm);
+ SkRect r = SkRect::MakeWH(SkIntToScalar(10), SkIntToScalar(10));
+
+ SkAutoDataUnref data(SkData::NewWithCString("http://www.gooogle.com"));
+
+ REPORTER_ASSERT(reporter, 0 == *bm.getAddr32(0, 0));
+ SkAnnotateRectWithURL(&canvas, r, data.get());
+ REPORTER_ASSERT(reporter, 0 == *bm.getAddr32(0, 0));
+}
+
+struct testCase {
+ SkPDFDocument::Flags flags;
+ bool expectAnnotations;
+};
+
+DEF_TEST(Annotation_PdfLink, reporter) {
+ SkISize size = SkISize::Make(612, 792);
+ SkMatrix initialTransform;
+ initialTransform.reset();
+ SkPDFDevice device(size, size, initialTransform);
+ SkCanvas canvas(&device);
+
+ SkRect r = SkRect::MakeXYWH(SkIntToScalar(72), SkIntToScalar(72),
+ SkIntToScalar(288), SkIntToScalar(72));
+ SkAutoDataUnref data(SkData::NewWithCString("http://www.gooogle.com"));
+ SkAnnotateRectWithURL(&canvas, r, data.get());
+
+ testCase tests[] = {{(SkPDFDocument::Flags)0, true},
+ {SkPDFDocument::kNoLinks_Flags, false}};
+ for (size_t testNum = 0; testNum < SK_ARRAY_COUNT(tests); testNum++) {
+ SkPDFDocument doc(tests[testNum].flags);
+ doc.appendPage(&device);
+ SkDynamicMemoryWStream outStream;
+ doc.emitPDF(&outStream);
+ SkAutoDataUnref out(outStream.copyToData());
+ const char* rawOutput = (const char*)out->data();
+
+ REPORTER_ASSERT(reporter,
+ ContainsString(rawOutput, out->size(), "/Annots ")
+ == tests[testNum].expectAnnotations);
+ }
+}
+
+DEF_TEST(Annotation_NamedDestination, reporter) {
+ SkISize size = SkISize::Make(612, 792);
+ SkMatrix initialTransform;
+ initialTransform.reset();
+ SkPDFDevice device(size, size, initialTransform);
+ SkCanvas canvas(&device);
+
+ SkPoint p = SkPoint::Make(SkIntToScalar(72), SkIntToScalar(72));
+ SkAutoDataUnref data(SkData::NewWithCString("example"));
+ SkAnnotateNamedDestination(&canvas, p, data.get());
+
+ SkPDFDocument doc;
+ doc.appendPage(&device);
+ SkDynamicMemoryWStream outStream;
+ doc.emitPDF(&outStream);
+ SkAutoDataUnref out(outStream.copyToData());
+ const char* rawOutput = (const char*)out->data();
+
+ REPORTER_ASSERT(reporter,
+ ContainsString(rawOutput, out->size(), "/example "));
+}
diff --git a/src/third_party/skia/tests/AsADashTest.cpp b/src/third_party/skia/tests/AsADashTest.cpp
new file mode 100644
index 0000000..47f1971
--- /dev/null
+++ b/src/third_party/skia/tests/AsADashTest.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+
+#include "SkPathEffect.h"
+#include "SkDashPathEffect.h"
+#include "SkCornerPathEffect.h"
+
+DEF_TEST(AsADashTest_noneDash, reporter) {
+ SkAutoTUnref<SkCornerPathEffect> pe(SkCornerPathEffect::Create(1.0));
+ SkPathEffect::DashInfo info;
+
+ SkPathEffect::DashType dashType = pe->asADash(&info);
+ REPORTER_ASSERT(reporter, SkPathEffect::kNone_DashType == dashType);
+}
+
+DEF_TEST(AsADashTest_nullInfo, reporter) {
+ SkScalar inIntervals[] = { 4.0, 2.0, 1.0, 3.0 };
+ const SkScalar phase = 2.0;
+ SkAutoTUnref<SkDashPathEffect> pe(SkDashPathEffect::Create(inIntervals, 4, phase));
+
+ SkPathEffect::DashType dashType = pe->asADash(NULL);
+ REPORTER_ASSERT(reporter, SkPathEffect::kDash_DashType == dashType);
+}
+
+DEF_TEST(AsADashTest_usingDash, reporter) {
+ SkScalar inIntervals[] = { 4.0, 2.0, 1.0, 3.0 };
+ SkScalar totalIntSum = 10.0;
+ const SkScalar phase = 2.0;
+
+ SkAutoTUnref<SkDashPathEffect> pe(SkDashPathEffect::Create(inIntervals, 4, phase));
+
+ SkPathEffect::DashInfo info;
+
+ SkPathEffect::DashType dashType = pe->asADash(&info);
+ REPORTER_ASSERT(reporter, SkPathEffect::kDash_DashType == dashType);
+ REPORTER_ASSERT(reporter, 4 == info.fCount);
+ REPORTER_ASSERT(reporter, SkScalarMod(phase, totalIntSum) == info.fPhase);
+
+ // Since it is a kDash_DashType, allocate space for the intervals and recall asADash
+ SkAutoTArray<SkScalar> intervals(info.fCount);
+ info.fIntervals = intervals.get();
+ pe->asADash(&info);
+ REPORTER_ASSERT(reporter, inIntervals[0] == info.fIntervals[0]);
+ REPORTER_ASSERT(reporter, inIntervals[1] == info.fIntervals[1]);
+ REPORTER_ASSERT(reporter, inIntervals[2] == info.fIntervals[2]);
+ REPORTER_ASSERT(reporter, inIntervals[3] == info.fIntervals[3]);
+
+ // Make sure nothing else has changed on us
+ REPORTER_ASSERT(reporter, 4 == info.fCount);
+ REPORTER_ASSERT(reporter, SkScalarMod(phase, totalIntSum) == info.fPhase);
+}
diff --git a/src/third_party/skia/tests/AtomicTest.cpp b/src/third_party/skia/tests/AtomicTest.cpp
new file mode 100644
index 0000000..8b5ac9b
--- /dev/null
+++ b/src/third_party/skia/tests/AtomicTest.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkThread.h"
+#include "SkThreadUtils.h"
+#include "SkTypes.h"
+#include "Test.h"
+
+struct AddInfo {
+ int32_t valueToAdd;
+ int timesToAdd;
+ unsigned int processorAffinity;
+};
+
+static int32_t base = 0;
+
+static AddInfo gAdds[] = {
+ { 3, 100, 23 },
+ { 2, 200, 2 },
+ { 7, 150, 17 },
+};
+
+static void addABunchOfTimes(void* data) {
+ AddInfo* addInfo = static_cast<AddInfo*>(data);
+ for (int i = 0; i < addInfo->timesToAdd; i++) {
+ sk_atomic_add(&base, addInfo->valueToAdd);
+ }
+}
+
+DEF_TEST(Atomic, reporter) {
+ int32_t total = base;
+ SkThread* threads[SK_ARRAY_COUNT(gAdds)];
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gAdds); i++) {
+ total += gAdds[i].valueToAdd * gAdds[i].timesToAdd;
+ }
+ // Start the threads
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gAdds); i++) {
+ threads[i] = new SkThread(addABunchOfTimes, &gAdds[i]);
+ threads[i]->setProcessorAffinity(gAdds[i].processorAffinity);
+ threads[i]->start();
+ }
+
+ // Now end the threads
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gAdds); i++) {
+ threads[i]->join();
+ delete threads[i];
+ }
+ REPORTER_ASSERT(reporter, total == base);
+ // Ensure that the returned value from sk_atomic_add is correct.
+ int32_t valueToModify = 3;
+ const int32_t originalValue = valueToModify;
+ REPORTER_ASSERT(reporter, originalValue == sk_atomic_add(&valueToModify, 7));
+}
diff --git a/src/third_party/skia/tests/BBoxHierarchyTest.cpp b/src/third_party/skia/tests/BBoxHierarchyTest.cpp
new file mode 100644
index 0000000..71b9699
--- /dev/null
+++ b/src/third_party/skia/tests/BBoxHierarchyTest.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "SkRandom.h"
+#include "SkRTree.h"
+#include "SkTSort.h"
+
+static const size_t RTREE_MIN_CHILDREN = 6;
+static const size_t RTREE_MAX_CHILDREN = 11;
+
+static const int NUM_RECTS = 200;
+static const size_t NUM_ITERATIONS = 100;
+static const size_t NUM_QUERIES = 50;
+
+static const SkScalar MAX_SIZE = 1000.0f;
+
+struct DataRect {
+ SkRect rect;
+ void* data;
+};
+
+static SkRect random_rect(SkRandom& rand) {
+ SkRect rect = {0,0,0,0};
+ while (rect.isEmpty()) {
+ rect.fLeft = rand.nextRangeF(0, MAX_SIZE);
+ rect.fRight = rand.nextRangeF(0, MAX_SIZE);
+ rect.fTop = rand.nextRangeF(0, MAX_SIZE);
+ rect.fBottom = rand.nextRangeF(0, MAX_SIZE);
+ rect.sort();
+ }
+ return rect;
+}
+
+static void random_data_rects(SkRandom& rand, DataRect out[], int n) {
+ for (int i = 0; i < n; ++i) {
+ out[i].rect = random_rect(rand);
+ out[i].data = reinterpret_cast<void*>(i);
+ }
+}
+
+static bool verify_query(SkRect query, DataRect rects[],
+ SkTDArray<void*>& found) {
+ // TODO(mtklein): no need to do this after everything's SkRects
+ query.roundOut();
+
+ SkTDArray<void*> expected;
+ // manually intersect with every rectangle
+ for (int i = 0; i < NUM_RECTS; ++i) {
+ if (SkRect::Intersects(query, rects[i].rect)) {
+ expected.push(rects[i].data);
+ }
+ }
+
+ if (expected.count() != found.count()) {
+ return false;
+ }
+
+ if (0 == expected.count()) {
+ return true;
+ }
+
+ // Just cast to long since sorting by the value of the void*'s was being problematic...
+ SkTQSort(reinterpret_cast<long*>(expected.begin()),
+ reinterpret_cast<long*>(expected.end() - 1));
+ SkTQSort(reinterpret_cast<long*>(found.begin()),
+ reinterpret_cast<long*>(found.end() - 1));
+ return found == expected;
+}
+
+static void run_queries(skiatest::Reporter* reporter, SkRandom& rand, DataRect rects[],
+ SkBBoxHierarchy& tree) {
+ for (size_t i = 0; i < NUM_QUERIES; ++i) {
+ SkTDArray<void*> hits;
+ SkRect query = random_rect(rand);
+ tree.search(query, &hits);
+ REPORTER_ASSERT(reporter, verify_query(query, rects, hits));
+ }
+}
+
+static void tree_test_main(SkBBoxHierarchy* tree, int minChildren, int maxChildren,
+ skiatest::Reporter* reporter) {
+ DataRect rects[NUM_RECTS];
+ SkRandom rand;
+ REPORTER_ASSERT(reporter, tree);
+
+ int expectedDepthMin = -1;
+ int expectedDepthMax = -1;
+
+ int tmp = NUM_RECTS;
+ if (maxChildren > 0) {
+ while (tmp > 0) {
+ tmp -= static_cast<int>(pow(static_cast<double>(maxChildren),
+ static_cast<double>(expectedDepthMin + 1)));
+ ++expectedDepthMin;
+ }
+ }
+
+ tmp = NUM_RECTS;
+ if (minChildren > 0) {
+ while (tmp > 0) {
+ tmp -= static_cast<int>(pow(static_cast<double>(minChildren),
+ static_cast<double>(expectedDepthMax + 1)));
+ ++expectedDepthMax;
+ }
+ }
+
+ for (size_t i = 0; i < NUM_ITERATIONS; ++i) {
+ random_data_rects(rand, rects, NUM_RECTS);
+
+ // First try bulk-loaded inserts
+ for (int i = 0; i < NUM_RECTS; ++i) {
+ tree->insert(rects[i].data, rects[i].rect, true);
+ }
+ tree->flushDeferredInserts();
+ run_queries(reporter, rand, rects, *tree);
+ REPORTER_ASSERT(reporter, NUM_RECTS == tree->getCount());
+ REPORTER_ASSERT(reporter,
+ ((expectedDepthMin <= 0) || (expectedDepthMin <= tree->getDepth())) &&
+ ((expectedDepthMax <= 0) || (expectedDepthMax >= tree->getDepth())));
+ tree->clear();
+ REPORTER_ASSERT(reporter, 0 == tree->getCount());
+
+ // Then try immediate inserts
+ tree->insert(rects[0].data, rects[0].rect);
+ tree->flushDeferredInserts();
+ for (int i = 1; i < NUM_RECTS; ++i) {
+ tree->insert(rects[i].data, rects[i].rect);
+ }
+ run_queries(reporter, rand, rects, *tree);
+ REPORTER_ASSERT(reporter, NUM_RECTS == tree->getCount());
+ REPORTER_ASSERT(reporter,
+ ((expectedDepthMin <= 0) || (expectedDepthMin <= tree->getDepth())) &&
+ ((expectedDepthMax <= 0) || (expectedDepthMax >= tree->getDepth())));
+ tree->clear();
+ REPORTER_ASSERT(reporter, 0 == tree->getCount());
+
+ // And for good measure try immediate inserts, but in reversed order
+ tree->insert(rects[NUM_RECTS - 1].data, rects[NUM_RECTS - 1].rect);
+ tree->flushDeferredInserts();
+ for (int i = NUM_RECTS - 2; i >= 0; --i) {
+ tree->insert(rects[i].data, rects[i].rect);
+ }
+ run_queries(reporter, rand, rects, *tree);
+ REPORTER_ASSERT(reporter, NUM_RECTS == tree->getCount());
+ REPORTER_ASSERT(reporter,
+ ((expectedDepthMin < 0) || (expectedDepthMin <= tree->getDepth())) &&
+ ((expectedDepthMax < 0) || (expectedDepthMax >= tree->getDepth())));
+ tree->clear();
+ REPORTER_ASSERT(reporter, 0 == tree->getCount());
+ }
+}
+
+DEF_TEST(BBoxHierarchy, reporter) {
+ // RTree
+ {
+ SkRTree* rtree = SkRTree::Create(RTREE_MIN_CHILDREN, RTREE_MAX_CHILDREN);
+ SkAutoUnref au(rtree);
+ tree_test_main(rtree, RTREE_MIN_CHILDREN, RTREE_MAX_CHILDREN, reporter);
+
+ // Rtree that orders input rectangles on deferred insert.
+ SkRTree* unsortedRtree = SkRTree::Create(RTREE_MIN_CHILDREN, RTREE_MAX_CHILDREN, 1, false);
+ SkAutoUnref auo(unsortedRtree);
+ tree_test_main(unsortedRtree, RTREE_MIN_CHILDREN, RTREE_MAX_CHILDREN, reporter);
+ }
+}
diff --git a/src/third_party/skia/tests/BitSetTest.cpp b/src/third_party/skia/tests/BitSetTest.cpp
new file mode 100644
index 0000000..da02376
--- /dev/null
+++ b/src/third_party/skia/tests/BitSetTest.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitSet.h"
+#include "Test.h"
+
+DEF_TEST(BitSet, reporter) {
+ SkBitSet set0(65536);
+ REPORTER_ASSERT(reporter, set0.isBitSet(0) == false);
+ REPORTER_ASSERT(reporter, set0.isBitSet(32767) == false);
+ REPORTER_ASSERT(reporter, set0.isBitSet(65535) == false);
+
+ SkBitSet set1(65536);
+ REPORTER_ASSERT(reporter, set0 == set1);
+
+ set0.setBit(22, true);
+ REPORTER_ASSERT(reporter, set0.isBitSet(22) == true);
+ set0.setBit(24, true);
+ REPORTER_ASSERT(reporter, set0.isBitSet(24) == true);
+ set0.setBit(35, true); // on a different DWORD
+ REPORTER_ASSERT(reporter, set0.isBitSet(35) == true);
+ set0.setBit(22, false);
+ REPORTER_ASSERT(reporter, set0.isBitSet(22) == false);
+ REPORTER_ASSERT(reporter, set0.isBitSet(24) == true);
+ REPORTER_ASSERT(reporter, set0.isBitSet(35) == true);
+
+ SkTDArray<unsigned int> data;
+ set0.exportTo(&data);
+ REPORTER_ASSERT(reporter, data.count() == 2);
+ REPORTER_ASSERT(reporter, data[0] == 24);
+ REPORTER_ASSERT(reporter, data[1] == 35);
+
+ set1.setBit(12345, true);
+ set1.orBits(set0);
+ REPORTER_ASSERT(reporter, set0.isBitSet(12345) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(12345) == true);
+ REPORTER_ASSERT(reporter, set1.isBitSet(22) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(24) == true);
+ REPORTER_ASSERT(reporter, set0.isBitSet(35) == true);
+ REPORTER_ASSERT(reporter, set1 != set0);
+
+ set1.clearAll();
+ REPORTER_ASSERT(reporter, set0.isBitSet(12345) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(12345) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(22) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(24) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(35) == false);
+
+ set1.orBits(set0);
+ REPORTER_ASSERT(reporter, set1 == set0);
+
+ SkBitSet set2(1);
+ SkBitSet set3(1);
+ SkBitSet set4(4);
+ SkBitSet set5(33);
+
+ REPORTER_ASSERT(reporter, set2 == set3);
+ REPORTER_ASSERT(reporter, set2 != set4);
+ REPORTER_ASSERT(reporter, set2 != set5);
+
+ set2.setBit(0, true);
+ REPORTER_ASSERT(reporter, set2 != set5);
+ set5.setBit(0, true);
+ REPORTER_ASSERT(reporter, set2 != set5);
+ REPORTER_ASSERT(reporter, set2 != set3);
+ set3.setBit(0, true);
+ REPORTER_ASSERT(reporter, set2 == set3);
+ set3.clearAll();
+ set3 = set2;
+ set2 = set2;
+ REPORTER_ASSERT(reporter, set2 == set3);
+}
diff --git a/src/third_party/skia/tests/BitmapCopyTest.cpp b/src/third_party/skia/tests/BitmapCopyTest.cpp
new file mode 100644
index 0000000..3923846
--- /dev/null
+++ b/src/third_party/skia/tests/BitmapCopyTest.cpp
@@ -0,0 +1,639 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkRect.h"
+#include "Test.h"
+
+static const char* boolStr(bool value) {
+ return value ? "true" : "false";
+}
+
+// these are in the same order as the SkColorType enum
+static const char* gColorTypeName[] = {
+ "None", "A8", "565", "4444", "RGBA", "BGRA", "Index8"
+};
+
+static void report_opaqueness(skiatest::Reporter* reporter, const SkBitmap& src,
+ const SkBitmap& dst) {
+ ERRORF(reporter, "src %s opaque:%d, dst %s opaque:%d",
+ gColorTypeName[src.colorType()], src.isOpaque(),
+ gColorTypeName[dst.colorType()], dst.isOpaque());
+}
+
+static bool canHaveAlpha(SkColorType ct) {
+ return kRGB_565_SkColorType != ct;
+}
+
+// copyTo() should preserve isOpaque when it makes sense
+static void test_isOpaque(skiatest::Reporter* reporter,
+ const SkBitmap& srcOpaque, const SkBitmap& srcPremul,
+ SkColorType dstColorType) {
+ SkBitmap dst;
+
+ if (canHaveAlpha(srcPremul.colorType()) && canHaveAlpha(dstColorType)) {
+ REPORTER_ASSERT(reporter, srcPremul.copyTo(&dst, dstColorType));
+ REPORTER_ASSERT(reporter, dst.colorType() == dstColorType);
+ if (srcPremul.isOpaque() != dst.isOpaque()) {
+ report_opaqueness(reporter, srcPremul, dst);
+ }
+ }
+
+ REPORTER_ASSERT(reporter, srcOpaque.copyTo(&dst, dstColorType));
+ REPORTER_ASSERT(reporter, dst.colorType() == dstColorType);
+ if (srcOpaque.isOpaque() != dst.isOpaque()) {
+ report_opaqueness(reporter, srcOpaque, dst);
+ }
+}
+
+static void init_src(const SkBitmap& bitmap) {
+ SkAutoLockPixels lock(bitmap);
+ if (bitmap.getPixels()) {
+ if (bitmap.getColorTable()) {
+ sk_bzero(bitmap.getPixels(), bitmap.getSize());
+ } else {
+ bitmap.eraseColor(SK_ColorWHITE);
+ }
+ }
+}
+
+static SkColorTable* init_ctable(SkAlphaType alphaType) {
+ static const SkColor colors[] = {
+ SK_ColorBLACK, SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE
+ };
+ return new SkColorTable(colors, SK_ARRAY_COUNT(colors), alphaType);
+}
+
+struct Pair {
+ SkColorType fColorType;
+ const char* fValid;
+};
+
+// Utility functions for copyPixelsTo()/copyPixelsFrom() tests.
+// getPixel()
+// setPixel()
+// getSkConfigName()
+// struct Coordinates
+// reportCopyVerification()
+// writeCoordPixels()
+
+// Utility function to read the value of a given pixel in bm. All
+// values converted to uint32_t for simplification of comparisons.
+static uint32_t getPixel(int x, int y, const SkBitmap& bm) {
+ uint32_t val = 0;
+ uint16_t val16;
+ uint8_t val8;
+ SkAutoLockPixels lock(bm);
+ const void* rawAddr = bm.getAddr(x,y);
+
+ switch (bm.bytesPerPixel()) {
+ case 4:
+ memcpy(&val, rawAddr, sizeof(uint32_t));
+ break;
+ case 2:
+ memcpy(&val16, rawAddr, sizeof(uint16_t));
+ val = val16;
+ break;
+ case 1:
+ memcpy(&val8, rawAddr, sizeof(uint8_t));
+ val = val8;
+ break;
+ default:
+ break;
+ }
+ return val;
+}
+
+// Utility function to set value of any pixel in bm.
+// bm.getConfig() specifies what format 'val' must be
+// converted to, but at present uint32_t can handle all formats.
+static void setPixel(int x, int y, uint32_t val, SkBitmap& bm) {
+ uint16_t val16;
+ uint8_t val8;
+ SkAutoLockPixels lock(bm);
+ void* rawAddr = bm.getAddr(x,y);
+
+ switch (bm.bytesPerPixel()) {
+ case 4:
+ memcpy(rawAddr, &val, sizeof(uint32_t));
+ break;
+ case 2:
+ val16 = val & 0xFFFF;
+ memcpy(rawAddr, &val16, sizeof(uint16_t));
+ break;
+ case 1:
+ val8 = val & 0xFF;
+ memcpy(rawAddr, &val8, sizeof(uint8_t));
+ break;
+ default:
+ // Ignore.
+ break;
+ }
+}
+
+// Helper struct to contain pixel locations, while avoiding need for STL.
+struct Coordinates {
+
+ const int length;
+ SkIPoint* const data;
+
+ explicit Coordinates(int _length): length(_length)
+ , data(new SkIPoint[length]) { }
+
+ ~Coordinates(){
+ delete [] data;
+ }
+
+ SkIPoint* operator[](int i) const {
+ // Use with care, no bounds checking.
+ return data + i;
+ }
+};
+
+// A function to verify that two bitmaps contain the same pixel values
+// at all coordinates indicated by coords. Simplifies verification of
+// copied bitmaps.
+static void reportCopyVerification(const SkBitmap& bm1, const SkBitmap& bm2,
+ Coordinates& coords,
+ const char* msg,
+ skiatest::Reporter* reporter){
+ bool success = true;
+
+ // Confirm all pixels in the list match.
+ for (int i = 0; i < coords.length; ++i) {
+ success = success &&
+ (getPixel(coords[i]->fX, coords[i]->fY, bm1) ==
+ getPixel(coords[i]->fX, coords[i]->fY, bm2));
+ }
+
+ if (!success) {
+ ERRORF(reporter, "%s [colortype = %s]", msg,
+ gColorTypeName[bm1.colorType()]);
+ }
+}
+
+// Writes unique pixel values at locations specified by coords.
+static void writeCoordPixels(SkBitmap& bm, const Coordinates& coords) {
+ for (int i = 0; i < coords.length; ++i)
+ setPixel(coords[i]->fX, coords[i]->fY, i, bm);
+}
+
+static const Pair gPairs[] = {
+ { kUnknown_SkColorType, "000000" },
+ { kAlpha_8_SkColorType, "010101" },
+ { kIndex_8_SkColorType, "011111" },
+ { kRGB_565_SkColorType, "010101" },
+ { kARGB_4444_SkColorType, "010111" },
+ { kN32_SkColorType, "010111" },
+};
+
+static const int W = 20;
+static const int H = 33;
+
+static void setup_src_bitmaps(SkBitmap* srcOpaque, SkBitmap* srcPremul,
+ SkColorType ct) {
+ SkColorTable* ctOpaque = NULL;
+ SkColorTable* ctPremul = NULL;
+ if (kIndex_8_SkColorType == ct) {
+ ctOpaque = init_ctable(kOpaque_SkAlphaType);
+ ctPremul = init_ctable(kPremul_SkAlphaType);
+ }
+
+ srcOpaque->allocPixels(SkImageInfo::Make(W, H, ct, kOpaque_SkAlphaType),
+ NULL, ctOpaque);
+ srcPremul->allocPixels(SkImageInfo::Make(W, H, ct, kPremul_SkAlphaType),
+ NULL, ctPremul);
+ SkSafeUnref(ctOpaque);
+ SkSafeUnref(ctPremul);
+ init_src(*srcOpaque);
+ init_src(*srcPremul);
+}
+
+DEF_TEST(BitmapCopy_extractSubset, reporter) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
+ SkBitmap srcOpaque, srcPremul;
+ setup_src_bitmaps(&srcOpaque, &srcPremul, gPairs[i].fColorType);
+
+ SkBitmap bitmap(srcOpaque);
+ SkBitmap subset;
+ SkIRect r;
+ // Extract a subset which has the same width as the original. This
+ // catches a bug where we cloned the genID incorrectly.
+ r.set(0, 1, W, 3);
+ bitmap.setIsVolatile(true);
+ // Relies on old behavior of extractSubset failing if colortype is unknown
+ if (kUnknown_SkColorType != bitmap.colorType() && bitmap.extractSubset(&subset, r)) {
+ REPORTER_ASSERT(reporter, subset.width() == W);
+ REPORTER_ASSERT(reporter, subset.height() == 2);
+ REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType());
+ REPORTER_ASSERT(reporter, subset.isVolatile() == true);
+
+ // Test copying an extracted subset.
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) {
+ SkBitmap copy;
+ bool success = subset.copyTo(©, gPairs[j].fColorType);
+ if (!success) {
+ // Skip checking that success matches fValid, which is redundant
+ // with the code below.
+ REPORTER_ASSERT(reporter, gPairs[i].fColorType != gPairs[j].fColorType);
+ continue;
+ }
+
+ // When performing a copy of an extracted subset, the gen id should
+ // change.
+ REPORTER_ASSERT(reporter, copy.getGenerationID() != subset.getGenerationID());
+
+ REPORTER_ASSERT(reporter, copy.width() == W);
+ REPORTER_ASSERT(reporter, copy.height() == 2);
+
+ if (gPairs[i].fColorType == gPairs[j].fColorType) {
+ SkAutoLockPixels alp0(subset);
+ SkAutoLockPixels alp1(copy);
+ // they should both have, or both not-have, a colortable
+ bool hasCT = subset.getColorTable() != NULL;
+ REPORTER_ASSERT(reporter, (copy.getColorTable() != NULL) == hasCT);
+ }
+ }
+ }
+
+ bitmap = srcPremul;
+ bitmap.setIsVolatile(false);
+ if (bitmap.extractSubset(&subset, r)) {
+ REPORTER_ASSERT(reporter, subset.alphaType() == bitmap.alphaType());
+ REPORTER_ASSERT(reporter, subset.isVolatile() == false);
+ }
+ }
+}
+
+DEF_TEST(BitmapCopy, reporter) {
+ static const bool isExtracted[] = {
+ false, true
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
+ SkBitmap srcOpaque, srcPremul;
+ setup_src_bitmaps(&srcOpaque, &srcPremul, gPairs[i].fColorType);
+
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) {
+ SkBitmap dst;
+
+ bool success = srcPremul.copyTo(&dst, gPairs[j].fColorType);
+ bool expected = gPairs[i].fValid[j] != '0';
+ if (success != expected) {
+ ERRORF(reporter, "SkBitmap::copyTo from %s to %s. expected %s "
+ "returned %s", gColorTypeName[i], gColorTypeName[j],
+ boolStr(expected), boolStr(success));
+ }
+
+ bool canSucceed = srcPremul.canCopyTo(gPairs[j].fColorType);
+ if (success != canSucceed) {
+ ERRORF(reporter, "SkBitmap::copyTo from %s to %s. returned %s "
+ "canCopyTo %s", gColorTypeName[i], gColorTypeName[j],
+ boolStr(success), boolStr(canSucceed));
+ }
+
+ if (success) {
+ REPORTER_ASSERT(reporter, srcPremul.width() == dst.width());
+ REPORTER_ASSERT(reporter, srcPremul.height() == dst.height());
+ REPORTER_ASSERT(reporter, dst.colorType() == gPairs[j].fColorType);
+ test_isOpaque(reporter, srcOpaque, srcPremul, dst.colorType());
+ if (srcPremul.colorType() == dst.colorType()) {
+ SkAutoLockPixels srcLock(srcPremul);
+ SkAutoLockPixels dstLock(dst);
+ REPORTER_ASSERT(reporter, srcPremul.readyToDraw());
+ REPORTER_ASSERT(reporter, dst.readyToDraw());
+ const char* srcP = (const char*)srcPremul.getAddr(0, 0);
+ const char* dstP = (const char*)dst.getAddr(0, 0);
+ REPORTER_ASSERT(reporter, srcP != dstP);
+ REPORTER_ASSERT(reporter, !memcmp(srcP, dstP,
+ srcPremul.getSize()));
+ REPORTER_ASSERT(reporter, srcPremul.getGenerationID() == dst.getGenerationID());
+ } else {
+ REPORTER_ASSERT(reporter, srcPremul.getGenerationID() != dst.getGenerationID());
+ }
+ } else {
+ // dst should be unchanged from its initial state
+ REPORTER_ASSERT(reporter, dst.colorType() == kUnknown_SkColorType);
+ REPORTER_ASSERT(reporter, dst.width() == 0);
+ REPORTER_ASSERT(reporter, dst.height() == 0);
+ }
+ } // for (size_t j = ...
+
+ // Tests for getSafeSize(), getSafeSize64(), copyPixelsTo(),
+ // copyPixelsFrom().
+ //
+ for (size_t copyCase = 0; copyCase < SK_ARRAY_COUNT(isExtracted);
+ ++copyCase) {
+ // Test copying to/from external buffer.
+ // Note: the tests below have hard-coded values ---
+ // Please take care if modifying.
+
+ // Tests for getSafeSize64().
+ // Test with a very large configuration without pixel buffer
+ // attached.
+ SkBitmap tstSafeSize;
+ tstSafeSize.setInfo(SkImageInfo::Make(100000000U, 100000000U,
+ gPairs[i].fColorType, kPremul_SkAlphaType));
+ int64_t safeSize = tstSafeSize.computeSafeSize64();
+ if (safeSize < 0) {
+ ERRORF(reporter, "getSafeSize64() negative: %s",
+ gColorTypeName[tstSafeSize.colorType()]);
+ }
+ bool sizeFail = false;
+ // Compare against hand-computed values.
+ switch (gPairs[i].fColorType) {
+ case kUnknown_SkColorType:
+ break;
+
+ case kAlpha_8_SkColorType:
+ case kIndex_8_SkColorType:
+ if (safeSize != 0x2386F26FC10000LL) {
+ sizeFail = true;
+ }
+ break;
+
+ case kRGB_565_SkColorType:
+ case kARGB_4444_SkColorType:
+ if (safeSize != 0x470DE4DF820000LL) {
+ sizeFail = true;
+ }
+ break;
+
+ case kN32_SkColorType:
+ if (safeSize != 0x8E1BC9BF040000LL) {
+ sizeFail = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (sizeFail) {
+ ERRORF(reporter, "computeSafeSize64() wrong size: %s",
+ gColorTypeName[tstSafeSize.colorType()]);
+ }
+
+ int subW = 2;
+ int subH = 2;
+
+ // Create bitmap to act as source for copies and subsets.
+ SkBitmap src, subset;
+ SkColorTable* ct = NULL;
+ if (kIndex_8_SkColorType == src.colorType()) {
+ ct = init_ctable(kPremul_SkAlphaType);
+ }
+
+ int localSubW;
+ if (isExtracted[copyCase]) { // A larger image to extract from.
+ localSubW = 2 * subW + 1;
+ } else { // Tests expect a 2x2 bitmap, so make smaller.
+ localSubW = subW;
+ }
+ // could fail if we pass kIndex_8 for the colortype
+ if (src.tryAllocPixels(SkImageInfo::Make(localSubW, subH, gPairs[i].fColorType,
+ kPremul_SkAlphaType))) {
+ // failure is fine, as we will notice later on
+ }
+ SkSafeUnref(ct);
+
+ // Either copy src or extract into 'subset', which is used
+ // for subsequent calls to copyPixelsTo/From.
+ bool srcReady = false;
+ // Test relies on older behavior that extractSubset will fail on
+ // kUnknown_SkColorType
+ if (kUnknown_SkColorType != src.colorType() &&
+ isExtracted[copyCase]) {
+ // The extractedSubset() test case allows us to test copy-
+ // ing when src and dst mave possibly different strides.
+ SkIRect r;
+ r.set(1, 0, 1 + subW, subH); // 2x2 extracted bitmap
+
+ srcReady = src.extractSubset(&subset, r);
+ } else {
+ srcReady = src.copyTo(&subset);
+ }
+
+ // Not all configurations will generate a valid 'subset'.
+ if (srcReady) {
+
+ // Allocate our target buffer 'buf' for all copies.
+ // To simplify verifying correctness of copies attach
+ // buf to a SkBitmap, but copies are done using the
+ // raw buffer pointer.
+ const size_t bufSize = subH *
+ SkColorTypeMinRowBytes(src.colorType(), subW) * 2;
+ SkAutoMalloc autoBuf (bufSize);
+ uint8_t* buf = static_cast<uint8_t*>(autoBuf.get());
+
+ SkBitmap bufBm; // Attach buf to this bitmap.
+ bool successExpected;
+
+ // Set up values for each pixel being copied.
+ Coordinates coords(subW * subH);
+ for (int x = 0; x < subW; ++x)
+ for (int y = 0; y < subH; ++y)
+ {
+ int index = y * subW + x;
+ SkASSERT(index < coords.length);
+ coords[index]->fX = x;
+ coords[index]->fY = y;
+ }
+
+ writeCoordPixels(subset, coords);
+
+ // Test #1 ////////////////////////////////////////////
+
+ const SkImageInfo info = SkImageInfo::Make(subW, subH,
+ gPairs[i].fColorType,
+ kPremul_SkAlphaType);
+ // Before/after comparisons easier if we attach buf
+ // to an appropriately configured SkBitmap.
+ memset(buf, 0xFF, bufSize);
+ // Config with stride greater than src but that fits in buf.
+ bufBm.installPixels(info, buf, info.minRowBytes() * 2);
+ successExpected = false;
+ // Then attempt to copy with a stride that is too large
+ // to fit in the buffer.
+ REPORTER_ASSERT(reporter,
+ subset.copyPixelsTo(buf, bufSize, bufBm.rowBytes() * 3)
+ == successExpected);
+
+ if (successExpected)
+ reportCopyVerification(subset, bufBm, coords,
+ "copyPixelsTo(buf, bufSize, 1.5*maxRowBytes)",
+ reporter);
+
+ // Test #2 ////////////////////////////////////////////
+ // This test should always succeed, but in the case
+ // of extracted bitmaps only because we handle the
+ // issue of getSafeSize(). Without getSafeSize()
+ // buffer overrun/read would occur.
+ memset(buf, 0xFF, bufSize);
+ bufBm.installPixels(info, buf, subset.rowBytes());
+ successExpected = subset.getSafeSize() <= bufSize;
+ REPORTER_ASSERT(reporter,
+ subset.copyPixelsTo(buf, bufSize) ==
+ successExpected);
+ if (successExpected)
+ reportCopyVerification(subset, bufBm, coords,
+ "copyPixelsTo(buf, bufSize)", reporter);
+
+ // Test #3 ////////////////////////////////////////////
+ // Copy with different stride between src and dst.
+ memset(buf, 0xFF, bufSize);
+ bufBm.installPixels(info, buf, subset.rowBytes()+1);
+ successExpected = true; // Should always work.
+ REPORTER_ASSERT(reporter,
+ subset.copyPixelsTo(buf, bufSize,
+ subset.rowBytes()+1) == successExpected);
+ if (successExpected)
+ reportCopyVerification(subset, bufBm, coords,
+ "copyPixelsTo(buf, bufSize, rowBytes+1)", reporter);
+
+ // Test #4 ////////////////////////////////////////////
+ // Test copy with stride too small.
+ memset(buf, 0xFF, bufSize);
+ bufBm.installPixels(info, buf, info.minRowBytes());
+ successExpected = false;
+ // Request copy with stride too small.
+ REPORTER_ASSERT(reporter,
+ subset.copyPixelsTo(buf, bufSize, bufBm.rowBytes()-1)
+ == successExpected);
+ if (successExpected)
+ reportCopyVerification(subset, bufBm, coords,
+ "copyPixelsTo(buf, bufSize, rowBytes()-1)", reporter);
+
+#if 0 // copyPixelsFrom is gone
+ // Test #5 ////////////////////////////////////////////
+ // Tests the case where the source stride is too small
+ // for the source configuration.
+ memset(buf, 0xFF, bufSize);
+ bufBm.installPixels(info, buf, info.minRowBytes());
+ writeCoordPixels(bufBm, coords);
+ REPORTER_ASSERT(reporter,
+ subset.copyPixelsFrom(buf, bufSize, 1) == false);
+
+ // Test #6 ///////////////////////////////////////////
+ // Tests basic copy from an external buffer to the bitmap.
+ // If the bitmap is "extracted", this also tests the case
+ // where the source stride is different from the dest.
+ // stride.
+ // We've made the buffer large enough to always succeed.
+ bufBm.installPixels(info, buf, info.minRowBytes());
+ writeCoordPixels(bufBm, coords);
+ REPORTER_ASSERT(reporter,
+ subset.copyPixelsFrom(buf, bufSize, bufBm.rowBytes()) ==
+ true);
+ reportCopyVerification(bufBm, subset, coords,
+ "copyPixelsFrom(buf, bufSize)",
+ reporter);
+
+ // Test #7 ////////////////////////////////////////////
+ // Tests the case where the source buffer is too small
+ // for the transfer.
+ REPORTER_ASSERT(reporter,
+ subset.copyPixelsFrom(buf, 1, subset.rowBytes()) ==
+ false);
+
+#endif
+ }
+ } // for (size_t copyCase ...
+ }
+}
+
+#include "SkColorPriv.h"
+#include "SkUtils.h"
+
+/**
+ * Construct 4x4 pixels where we can look at a color and determine where it should be in the grid.
+ * alpha = 0xFF, blue = 0x80, red = x, green = y
+ */
+static void fill_4x4_pixels(SkPMColor colors[16]) {
+ for (int y = 0; y < 4; ++y) {
+ for (int x = 0; x < 4; ++x) {
+ colors[y*4+x] = SkPackARGB32(0xFF, x, y, 0x80);
+ }
+ }
+}
+
+static bool check_4x4_pixel(SkPMColor color, unsigned x, unsigned y) {
+ SkASSERT(x < 4 && y < 4);
+ return 0xFF == SkGetPackedA32(color) &&
+ x == SkGetPackedR32(color) &&
+ y == SkGetPackedG32(color) &&
+ 0x80 == SkGetPackedB32(color);
+}
+
+/**
+ * Fill with all zeros, which will never match any value from fill_4x4_pixels
+ */
+static void clear_4x4_pixels(SkPMColor colors[16]) {
+ sk_memset32(colors, 0, 16);
+}
+
+// Much of readPixels is exercised by copyTo testing, since readPixels is the backend for that
+// method. Here we explicitly test subset copies.
+//
+DEF_TEST(BitmapReadPixels, reporter) {
+ const int W = 4;
+ const int H = 4;
+ const size_t rowBytes = W * sizeof(SkPMColor);
+ const SkImageInfo srcInfo = SkImageInfo::MakeN32Premul(W, H);
+ SkPMColor srcPixels[16];
+ fill_4x4_pixels(srcPixels);
+ SkBitmap srcBM;
+ srcBM.installPixels(srcInfo, srcPixels, rowBytes);
+
+ SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(W, H);
+ SkPMColor dstPixels[16];
+
+ const struct {
+ bool fExpectedSuccess;
+ SkIPoint fRequestedSrcLoc;
+ SkISize fRequestedDstSize;
+ // If fExpectedSuccess, check these, otherwise ignore
+ SkIPoint fExpectedDstLoc;
+ SkIRect fExpectedSrcR;
+ } gRec[] = {
+ { true, { 0, 0 }, { 4, 4 }, { 0, 0 }, { 0, 0, 4, 4 } },
+ { true, { 1, 1 }, { 2, 2 }, { 0, 0 }, { 1, 1, 3, 3 } },
+ { true, { 2, 2 }, { 4, 4 }, { 0, 0 }, { 2, 2, 4, 4 } },
+ { true, {-1,-1 }, { 2, 2 }, { 1, 1 }, { 0, 0, 1, 1 } },
+ { false, {-1,-1 }, { 1, 1 }, { 0, 0 }, { 0, 0, 0, 0 } },
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
+ clear_4x4_pixels(dstPixels);
+
+ dstInfo = dstInfo.makeWH(gRec[i].fRequestedDstSize.width(),
+ gRec[i].fRequestedDstSize.height());
+ bool success = srcBM.readPixels(dstInfo, dstPixels, rowBytes,
+ gRec[i].fRequestedSrcLoc.x(), gRec[i].fRequestedSrcLoc.y());
+
+ REPORTER_ASSERT(reporter, gRec[i].fExpectedSuccess == success);
+ if (success) {
+ const SkIRect srcR = gRec[i].fExpectedSrcR;
+ const int dstX = gRec[i].fExpectedDstLoc.x();
+ const int dstY = gRec[i].fExpectedDstLoc.y();
+ // Walk the dst pixels, and check if we got what we expected
+ for (int y = 0; y < H; ++y) {
+ for (int x = 0; x < W; ++x) {
+ SkPMColor dstC = dstPixels[y*4+x];
+ // get into src coordinates
+ int sx = x - dstX + srcR.x();
+ int sy = y - dstY + srcR.y();
+ if (srcR.contains(sx, sy)) {
+ REPORTER_ASSERT(reporter, check_4x4_pixel(dstC, sx, sy));
+ } else {
+ REPORTER_ASSERT(reporter, 0 == dstC);
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/third_party/skia/tests/BitmapGetColorTest.cpp b/src/third_party/skia/tests/BitmapGetColorTest.cpp
new file mode 100644
index 0000000..bf3ba67
--- /dev/null
+++ b/src/third_party/skia/tests/BitmapGetColorTest.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkRandom.h"
+#include "SkRect.h"
+#include "Test.h"
+
+DEF_TEST(GetColor, reporter) {
+ static const struct Rec {
+ SkColorType fColorType;
+ SkColor fInColor;
+ SkColor fOutColor;
+ } gRec[] = {
+ // todo: add some tests that involve alpha, so we exercise the
+ // unpremultiply aspect of getColor()
+ { kAlpha_8_SkColorType, 0xFF000000, 0xFF000000 },
+ { kAlpha_8_SkColorType, 0, 0 },
+ { kRGB_565_SkColorType, 0xFF00FF00, 0xFF00FF00 },
+ { kRGB_565_SkColorType, 0xFFFF00FF, 0xFFFF00FF },
+ { kN32_SkColorType, 0xFFFFFFFF, 0xFFFFFFFF },
+ { kN32_SkColorType, 0, 0 },
+ { kN32_SkColorType, 0xFF224466, 0xFF224466 },
+ };
+
+ // specify an area that doesn't touch (0,0) and may extend beyond the
+ // bitmap bounds (to test that we catch that in eraseArea
+ const SkColor initColor = 0xFF0000FF;
+ const SkIRect area = { 1, 1, 3, 3 };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
+ SkImageInfo info = SkImageInfo::Make(2, 2, gRec[i].fColorType,
+ kPremul_SkAlphaType);
+ SkBitmap bm;
+ uint32_t storage[4];
+ bm.installPixels(info, storage, info.minRowBytes());
+
+ bm.eraseColor(initColor);
+ bm.eraseArea(area, gRec[i].fInColor);
+
+ SkColor c = bm.getColor(1, 1);
+ REPORTER_ASSERT(reporter, c == gRec[i].fOutColor);
+ }
+}
diff --git a/src/third_party/skia/tests/BitmapHasherTest.cpp b/src/third_party/skia/tests/BitmapHasherTest.cpp
new file mode 100644
index 0000000..3b51706
--- /dev/null
+++ b/src/third_party/skia/tests/BitmapHasherTest.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmapHasher.h"
+
+#include "SkBitmap.h"
+#include "SkColor.h"
+#include "Test.h"
+
+// Word size that is large enough to hold results of any checksum type.
+typedef uint64_t checksum_result;
+
+// Fill in bitmap with test data.
+static void CreateTestBitmap(SkBitmap* bitmap, int width, int height,
+ SkColor color, skiatest::Reporter* reporter) {
+ bitmap->allocN32Pixels(width, height, kOpaque_SkAlphaType);
+ bitmap->eraseColor(color);
+}
+
+DEF_TEST(BitmapHasher, reporter) {
+ // Test SkBitmapHasher
+ SkBitmap bitmap;
+ uint64_t digest;
+ // initial test case
+ CreateTestBitmap(&bitmap, 333, 555, SK_ColorBLUE, reporter);
+ REPORTER_ASSERT(reporter, SkBitmapHasher::ComputeDigest(bitmap, &digest));
+ REPORTER_ASSERT(reporter, digest == 0xfb2903562766ef87ULL);
+ // same pixel data but different dimensions should yield a different checksum
+ CreateTestBitmap(&bitmap, 555, 333, SK_ColorBLUE, reporter);
+ REPORTER_ASSERT(reporter, SkBitmapHasher::ComputeDigest(bitmap, &digest));
+ REPORTER_ASSERT(reporter, digest == 0xfe04023fb97d0f61ULL);
+ // same dimensions but different color should yield a different checksum
+ CreateTestBitmap(&bitmap, 555, 333, SK_ColorGREEN, reporter);
+ REPORTER_ASSERT(reporter, SkBitmapHasher::ComputeDigest(bitmap, &digest));
+ REPORTER_ASSERT(reporter, digest == 0x2423c51cad6d1edcULL);
+}
diff --git a/src/third_party/skia/tests/BitmapHeapTest.cpp b/src/third_party/skia/tests/BitmapHeapTest.cpp
new file mode 100644
index 0000000..dc9905e
--- /dev/null
+++ b/src/third_party/skia/tests/BitmapHeapTest.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkBitmapHeap.h"
+#include "SkColor.h"
+#include "SkFlattenable.h"
+#include "SkWriteBuffer.h"
+#include "SkPictureFlat.h"
+#include "SkRefCnt.h"
+#include "SkShader.h"
+#include "Test.h"
+
+struct SkShaderTraits {
+ static void Flatten(SkWriteBuffer& buffer, const SkShader& shader) {
+ buffer.writeFlattenable(&shader);
+ }
+};
+typedef SkFlatDictionary<SkShader, SkShaderTraits> FlatDictionary;
+
+class SkBitmapHeapTester {
+
+public:
+ static int32_t GetRefCount(const SkBitmapHeapEntry* entry) {
+ return entry->fRefCount;
+ }
+};
+
+DEF_TEST(BitmapHeap, reporter) {
+ // Create a bitmap shader.
+ SkBitmap bm;
+ bm.allocN32Pixels(2, 2);
+ bm.eraseColor(SK_ColorRED);
+ uint32_t* pixel = bm.getAddr32(1,0);
+ *pixel = SK_ColorBLUE;
+
+ SkShader* bitmapShader = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ SkAutoTUnref<SkShader> aur(bitmapShader);
+
+ // Flatten, storing it in the bitmap heap.
+ SkBitmapHeap heap(1, 1);
+ SkChunkFlatController controller(1024);
+ controller.setBitmapStorage(&heap);
+ FlatDictionary dictionary(&controller);
+
+ // Dictionary and heap start off empty.
+ REPORTER_ASSERT(reporter, heap.count() == 0);
+ REPORTER_ASSERT(reporter, dictionary.count() == 0);
+
+ heap.deferAddingOwners();
+ int index = dictionary.find(*bitmapShader);
+ heap.endAddingOwnersDeferral(true);
+
+ // The dictionary and heap should now each have one entry.
+ REPORTER_ASSERT(reporter, 1 == index);
+ REPORTER_ASSERT(reporter, heap.count() == 1);
+ REPORTER_ASSERT(reporter, dictionary.count() == 1);
+
+ // The bitmap entry's refcount should be 1, then 0 after release.
+ SkBitmapHeapEntry* entry = heap.getEntry(0);
+ REPORTER_ASSERT(reporter, SkBitmapHeapTester::GetRefCount(entry) == 1);
+
+ entry->releaseRef();
+ REPORTER_ASSERT(reporter, SkBitmapHeapTester::GetRefCount(entry) == 0);
+
+ // Now clear out the heap, after which it should be empty.
+ heap.freeMemoryIfPossible(~0U);
+ REPORTER_ASSERT(reporter, heap.count() == 0);
+
+ // Now attempt to flatten the shader again.
+ heap.deferAddingOwners();
+ index = dictionary.find(*bitmapShader);
+ heap.endAddingOwnersDeferral(false);
+
+ // The dictionary should report the same index since the new entry is identical.
+ // The bitmap heap should contain the bitmap, but with no references.
+ REPORTER_ASSERT(reporter, 1 == index);
+ REPORTER_ASSERT(reporter, heap.count() == 1);
+ REPORTER_ASSERT(reporter, SkBitmapHeapTester::GetRefCount(heap.getEntry(0)) == 0);
+}
diff --git a/src/third_party/skia/tests/BitmapTest.cpp b/src/third_party/skia/tests/BitmapTest.cpp
new file mode 100644
index 0000000..ef69531
--- /dev/null
+++ b/src/third_party/skia/tests/BitmapTest.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+
+#include "Test.h"
+
+static void test_allocpixels(skiatest::Reporter* reporter) {
+ const int width = 10;
+ const int height = 10;
+ const SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
+ const size_t explicitRowBytes = info.minRowBytes() + 24;
+
+ SkBitmap bm;
+ bm.setInfo(info);
+ REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
+ bm.allocPixels();
+ REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
+ bm.reset();
+ bm.allocPixels(info);
+ REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
+
+ bm.setInfo(info, explicitRowBytes);
+ REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes());
+ bm.allocPixels();
+ REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes());
+ bm.reset();
+ bm.allocPixels(info, explicitRowBytes);
+ REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes());
+
+ bm.reset();
+ bm.setInfo(info, 0);
+ REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
+ bm.reset();
+ bm.allocPixels(info, 0);
+ REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes());
+
+ bm.reset();
+ bool success = bm.setInfo(info, info.minRowBytes() - 1); // invalid for 32bit
+ REPORTER_ASSERT(reporter, !success);
+ REPORTER_ASSERT(reporter, bm.isNull());
+}
+
+static void test_bigwidth(skiatest::Reporter* reporter) {
+ SkBitmap bm;
+ int width = 1 << 29; // *4 will be the high-bit of 32bit int
+
+ SkImageInfo info = SkImageInfo::MakeA8(width, 1);
+ REPORTER_ASSERT(reporter, bm.setInfo(info));
+ REPORTER_ASSERT(reporter, bm.setInfo(info.makeColorType(kRGB_565_SkColorType)));
+
+ // for a 4-byte config, this width will compute a rowbytes of 0x80000000,
+ // which does not fit in a int32_t. setConfig should detect this, and fail.
+
+ // TODO: perhaps skia can relax this, and only require that rowBytes fit
+ // in a uint32_t (or larger), but for now this is the constraint.
+
+ REPORTER_ASSERT(reporter, !bm.setInfo(info.makeColorType(kN32_SkColorType)));
+}
+
+/**
+ * This test contains basic sanity checks concerning bitmaps.
+ */
+DEF_TEST(Bitmap, reporter) {
+ // Zero-sized bitmaps are allowed
+ for (int width = 0; width < 2; ++width) {
+ for (int height = 0; height < 2; ++height) {
+ SkBitmap bm;
+ bool setConf = bm.setInfo(SkImageInfo::MakeN32Premul(width, height));
+ REPORTER_ASSERT(reporter, setConf);
+ if (setConf) {
+ bm.allocPixels();
+ }
+ REPORTER_ASSERT(reporter, SkToBool(width & height) != bm.empty());
+ }
+ }
+
+ test_bigwidth(reporter);
+ test_allocpixels(reporter);
+}
diff --git a/src/third_party/skia/tests/BlendTest.cpp b/src/third_party/skia/tests/BlendTest.cpp
new file mode 100644
index 0000000..a0a84d7
--- /dev/null
+++ b/src/third_party/skia/tests/BlendTest.cpp
@@ -0,0 +1,258 @@
+#include "Test.h"
+#include "SkColor.h"
+
+#define ASSERT(x) REPORTER_ASSERT(r, x)
+
+static uint8_t double_to_u8(double d) {
+ SkASSERT(d >= 0);
+ SkASSERT(d < 256);
+ return uint8_t(d);
+}
+
+// All algorithms we're testing have this interface.
+// We want a single channel blend, src over dst, assuming src is premultiplied by srcAlpha.
+typedef uint8_t(*Blend)(uint8_t dst, uint8_t src, uint8_t srcAlpha);
+
+// This is our golden algorithm.
+static uint8_t blend_double_round(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
+ SkASSERT(src <= srcAlpha);
+ return double_to_u8(0.5 + src + dst * (255.0 - srcAlpha) / 255.0);
+}
+
+static uint8_t abs_diff(uint8_t a, uint8_t b) {
+ const int diff = a - b;
+ return diff > 0 ? diff : -diff;
+}
+
+static void test(skiatest::Reporter* r, int maxDiff, Blend algorithm,
+ uint8_t dst, uint8_t src, uint8_t alpha) {
+ const uint8_t golden = blend_double_round(dst, src, alpha);
+ const uint8_t blend = algorithm(dst, src, alpha);
+ if (abs_diff(blend, golden) > maxDiff) {
+ SkDebugf("dst %02x, src %02x, alpha %02x, |%02x - %02x| > %d\n",
+ dst, src, alpha, blend, golden, maxDiff);
+ ASSERT(abs_diff(blend, golden) <= maxDiff);
+ }
+}
+
+// Exhaustively compare an algorithm against our golden, for a given alpha.
+static void test_alpha(skiatest::Reporter* r, uint8_t alpha, int maxDiff, Blend algorithm) {
+ SkASSERT(maxDiff >= 0);
+
+ for (unsigned src = 0; src <= alpha; src++) {
+ for (unsigned dst = 0; dst < 256; dst++) {
+ test(r, maxDiff, algorithm, dst, src, alpha);
+ }
+ }
+}
+
+// Exhaustively compare an algorithm against our golden, for a given dst.
+static void test_dst(skiatest::Reporter* r, uint8_t dst, int maxDiff, Blend algorithm) {
+ SkASSERT(maxDiff >= 0);
+
+ for (unsigned alpha = 0; alpha < 256; alpha++) {
+ for (unsigned src = 0; src <= alpha; src++) {
+ test(r, maxDiff, algorithm, dst, src, alpha);
+ }
+ }
+}
+
+static uint8_t blend_double_trunc(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
+ return double_to_u8(src + dst * (255.0 - srcAlpha) / 255.0);
+}
+
+static uint8_t blend_float_trunc(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
+ return double_to_u8(src + dst * (255.0f - srcAlpha) / 255.0f);
+}
+
+static uint8_t blend_float_round(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
+ return double_to_u8(0.5f + src + dst * (255.0f - srcAlpha) / 255.0f);
+}
+
+static uint8_t blend_255_trunc(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
+ const uint16_t invAlpha = 255 - srcAlpha;
+ const uint16_t product = dst * invAlpha;
+ return src + (product >> 8);
+}
+
+static uint8_t blend_255_round(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
+ const uint16_t invAlpha = 255 - srcAlpha;
+ const uint16_t product = dst * invAlpha + 128;
+ return src + (product >> 8);
+}
+
+static uint8_t blend_256_trunc(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
+ const uint16_t invAlpha = 256 - (srcAlpha + (srcAlpha >> 7));
+ const uint16_t product = dst * invAlpha;
+ return src + (product >> 8);
+}
+
+static uint8_t blend_256_round(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
+ const uint16_t invAlpha = 256 - (srcAlpha + (srcAlpha >> 7));
+ const uint16_t product = dst * invAlpha + 128;
+ return src + (product >> 8);
+}
+
+static uint8_t blend_256_round_alt(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
+ const uint8_t invAlpha8 = 255 - srcAlpha;
+ const uint16_t invAlpha = invAlpha8 + (invAlpha8 >> 7);
+ const uint16_t product = dst * invAlpha + 128;
+ return src + (product >> 8);
+}
+
+static uint8_t blend_256_plus1_trunc(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
+ const uint16_t invAlpha = 256 - (srcAlpha + 1);
+ const uint16_t product = dst * invAlpha;
+ return src + (product >> 8);
+}
+
+static uint8_t blend_256_plus1_round(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
+ const uint16_t invAlpha = 256 - (srcAlpha + 1);
+ const uint16_t product = dst * invAlpha + 128;
+ return src + (product >> 8);
+}
+
+static uint8_t blend_perfect(uint8_t dst, uint8_t src, uint8_t srcAlpha) {
+ const uint8_t invAlpha = 255 - srcAlpha;
+ const uint16_t product = dst * invAlpha + 128;
+ return src + ((product + (product >> 8)) >> 8);
+}
+
+
+// We want 0 diff whenever src is fully transparent.
+DEF_TEST(Blend_alpha_0x00, r) {
+ const uint8_t alpha = 0x00;
+
+ // GOOD
+ test_alpha(r, alpha, 0, blend_256_round);
+ test_alpha(r, alpha, 0, blend_256_round_alt);
+ test_alpha(r, alpha, 0, blend_256_trunc);
+ test_alpha(r, alpha, 0, blend_double_trunc);
+ test_alpha(r, alpha, 0, blend_float_round);
+ test_alpha(r, alpha, 0, blend_float_trunc);
+ test_alpha(r, alpha, 0, blend_perfect);
+
+ // BAD
+ test_alpha(r, alpha, 1, blend_255_round);
+ test_alpha(r, alpha, 1, blend_255_trunc);
+ test_alpha(r, alpha, 1, blend_256_plus1_round);
+ test_alpha(r, alpha, 1, blend_256_plus1_trunc);
+}
+
+// We want 0 diff whenever dst is 0.
+DEF_TEST(Blend_dst_0x00, r) {
+ const uint8_t dst = 0x00;
+
+ // GOOD
+ test_dst(r, dst, 0, blend_255_round);
+ test_dst(r, dst, 0, blend_255_trunc);
+ test_dst(r, dst, 0, blend_256_plus1_round);
+ test_dst(r, dst, 0, blend_256_plus1_trunc);
+ test_dst(r, dst, 0, blend_256_round);
+ test_dst(r, dst, 0, blend_256_round_alt);
+ test_dst(r, dst, 0, blend_256_trunc);
+ test_dst(r, dst, 0, blend_double_trunc);
+ test_dst(r, dst, 0, blend_float_round);
+ test_dst(r, dst, 0, blend_float_trunc);
+ test_dst(r, dst, 0, blend_perfect);
+
+ // BAD
+}
+
+// We want 0 diff whenever src is fully opaque.
+DEF_TEST(Blend_alpha_0xFF, r) {
+ const uint8_t alpha = 0xFF;
+
+ // GOOD
+ test_alpha(r, alpha, 0, blend_255_round);
+ test_alpha(r, alpha, 0, blend_255_trunc);
+ test_alpha(r, alpha, 0, blend_256_plus1_round);
+ test_alpha(r, alpha, 0, blend_256_plus1_trunc);
+ test_alpha(r, alpha, 0, blend_256_round);
+ test_alpha(r, alpha, 0, blend_256_round_alt);
+ test_alpha(r, alpha, 0, blend_256_trunc);
+ test_alpha(r, alpha, 0, blend_double_trunc);
+ test_alpha(r, alpha, 0, blend_float_round);
+ test_alpha(r, alpha, 0, blend_float_trunc);
+ test_alpha(r, alpha, 0, blend_perfect);
+
+ // BAD
+}
+
+// We want 0 diff whenever dst is 0xFF.
+DEF_TEST(Blend_dst_0xFF, r) {
+ const uint8_t dst = 0xFF;
+
+ // GOOD
+ test_dst(r, dst, 0, blend_256_round);
+ test_dst(r, dst, 0, blend_256_round_alt);
+ test_dst(r, dst, 0, blend_double_trunc);
+ test_dst(r, dst, 0, blend_float_round);
+ test_dst(r, dst, 0, blend_float_trunc);
+ test_dst(r, dst, 0, blend_perfect);
+
+ // BAD
+ test_dst(r, dst, 1, blend_255_round);
+ test_dst(r, dst, 1, blend_255_trunc);
+ test_dst(r, dst, 1, blend_256_plus1_round);
+ test_dst(r, dst, 1, blend_256_plus1_trunc);
+ test_dst(r, dst, 1, blend_256_trunc);
+}
+
+// We'd like diff <= 1 everywhere.
+DEF_TEST(Blend_alpha_Exhaustive, r) {
+ for (unsigned alpha = 0; alpha < 256; alpha++) {
+ // PERFECT
+ test_alpha(r, alpha, 0, blend_float_round);
+ test_alpha(r, alpha, 0, blend_perfect);
+
+ // GOOD
+ test_alpha(r, alpha, 1, blend_255_round);
+ test_alpha(r, alpha, 1, blend_256_plus1_round);
+ test_alpha(r, alpha, 1, blend_256_round);
+ test_alpha(r, alpha, 1, blend_256_round_alt);
+ test_alpha(r, alpha, 1, blend_256_trunc);
+ test_alpha(r, alpha, 1, blend_double_trunc);
+ test_alpha(r, alpha, 1, blend_float_trunc);
+
+ // BAD
+ test_alpha(r, alpha, 2, blend_255_trunc);
+ test_alpha(r, alpha, 2, blend_256_plus1_trunc);
+ }
+}
+
+// We'd like diff <= 1 everywhere.
+DEF_TEST(Blend_dst_Exhaustive, r) {
+ for (unsigned dst = 0; dst < 256; dst++) {
+ // PERFECT
+ test_dst(r, dst, 0, blend_float_round);
+ test_dst(r, dst, 0, blend_perfect);
+
+ // GOOD
+ test_dst(r, dst, 1, blend_255_round);
+ test_dst(r, dst, 1, blend_256_plus1_round);
+ test_dst(r, dst, 1, blend_256_round);
+ test_dst(r, dst, 1, blend_256_round_alt);
+ test_dst(r, dst, 1, blend_256_trunc);
+ test_dst(r, dst, 1, blend_double_trunc);
+ test_dst(r, dst, 1, blend_float_trunc);
+
+ // BAD
+ test_dst(r, dst, 2, blend_255_trunc);
+ test_dst(r, dst, 2, blend_256_plus1_trunc);
+ }
+}
+// Overall summary:
+// PERFECT
+// blend_double_round
+// blend_float_round
+// blend_perfect
+// GOOD ENOUGH
+// blend_double_trunc
+// blend_float_trunc
+// blend_256_round
+// blend_256_round_alt
+// NOT GOOD ENOUGH
+// all others
+//
+// Algorithms that make sense to use in Skia: blend_256_round, blend_256_round_alt, blend_perfect
diff --git a/src/third_party/skia/tests/BlitRowTest.cpp b/src/third_party/skia/tests/BlitRowTest.cpp
new file mode 100644
index 0000000..4689a30
--- /dev/null
+++ b/src/third_party/skia/tests/BlitRowTest.cpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkGradientShader.h"
+#include "SkRect.h"
+#include "Test.h"
+
+// these are in the same order as the SkColorType enum
+static const char* gColorTypeName[] = {
+ "None", "A8", "565", "4444", "RGBA", "BGRA", "Index8"
+};
+
+/** Returns -1 on success, else the x coord of the first bad pixel, return its
+ value in bad
+ */
+typedef int (*Proc)(const void*, int width, uint32_t expected, uint32_t* bad);
+
+static int proc_32(const void* ptr, int w, uint32_t expected, uint32_t* bad) {
+ const SkPMColor* addr = static_cast<const SkPMColor*>(ptr);
+ for (int x = 0; x < w; x++) {
+ if (addr[x] != expected) {
+ *bad = addr[x];
+ return x;
+ }
+ }
+ return -1;
+}
+
+static int proc_16(const void* ptr, int w, uint32_t expected, uint32_t* bad) {
+ const uint16_t* addr = static_cast<const uint16_t*>(ptr);
+ for (int x = 0; x < w; x++) {
+ if (addr[x] != expected) {
+ *bad = addr[x];
+ return x;
+ }
+ }
+ return -1;
+}
+
+static int proc_8(const void* ptr, int w, uint32_t expected, uint32_t* bad) {
+ const SkPMColor* addr = static_cast<const SkPMColor*>(ptr);
+ for (int x = 0; x < w; x++) {
+ if (SkGetPackedA32(addr[x]) != expected) {
+ *bad = SkGetPackedA32(addr[x]);
+ return x;
+ }
+ }
+ return -1;
+}
+
+static int proc_bad(const void*, int, uint32_t, uint32_t* bad) {
+ *bad = 0;
+ return 0;
+}
+
+static Proc find_proc(const SkBitmap& bm, SkPMColor expect32, uint16_t expect16,
+ uint8_t expect8, uint32_t* expect) {
+ switch (bm.colorType()) {
+ case kN32_SkColorType:
+ *expect = expect32;
+ return proc_32;
+ case kARGB_4444_SkColorType:
+ case kRGB_565_SkColorType:
+ *expect = expect16;
+ return proc_16;
+ case kAlpha_8_SkColorType:
+ *expect = expect8;
+ return proc_8;
+ default:
+ *expect = 0;
+ return proc_bad;
+ }
+}
+
+static bool check_color(const SkBitmap& bm, SkPMColor expect32,
+ uint16_t expect16, uint8_t expect8,
+ skiatest::Reporter* reporter) {
+ uint32_t expect;
+ Proc proc = find_proc(bm, expect32, expect16, expect8, &expect);
+ for (int y = 0; y < bm.height(); y++) {
+ uint32_t bad;
+ int x = proc(bm.getAddr(0, y), bm.width(), expect, &bad);
+ if (x >= 0) {
+ ERRORF(reporter, "BlitRow colortype=%s [%d %d] expected %x got %x",
+ gColorTypeName[bm.colorType()], x, y, expect, bad);
+ return false;
+ }
+ }
+ return true;
+}
+
+// Make sure our blits always map src==0 to a noop, and src==FF to full opaque
+static void test_00_FF(skiatest::Reporter* reporter) {
+ static const int W = 256;
+
+ static const SkColorType gDstColorType[] = {
+ kN32_SkColorType,
+ kRGB_565_SkColorType,
+ };
+
+ static const struct {
+ SkColor fSrc;
+ SkColor fDst;
+ SkPMColor fResult32;
+ uint16_t fResult16;
+ uint8_t fResult8;
+ } gSrcRec[] = {
+ { 0, 0, 0, 0, 0 },
+ { 0, 0xFFFFFFFF, SkPackARGB32(0xFF, 0xFF, 0xFF, 0xFF), 0xFFFF, 0xFF },
+ { 0xFFFFFFFF, 0, SkPackARGB32(0xFF, 0xFF, 0xFF, 0xFF), 0xFFFF, 0xFF },
+ { 0xFFFFFFFF, 0xFFFFFFFF, SkPackARGB32(0xFF, 0xFF, 0xFF, 0xFF), 0xFFFF, 0xFF },
+ };
+
+ SkPaint paint;
+
+ SkBitmap srcBM;
+ srcBM.allocN32Pixels(W, 1);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gDstColorType); i++) {
+ SkImageInfo info = SkImageInfo::Make(W, 1, gDstColorType[i],
+ kPremul_SkAlphaType);
+ SkBitmap dstBM;
+ dstBM.allocPixels(info);
+
+ SkCanvas canvas(dstBM);
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gSrcRec); j++) {
+ srcBM.eraseColor(gSrcRec[j].fSrc);
+ dstBM.eraseColor(gSrcRec[j].fDst);
+
+ for (int k = 0; k < 4; k++) {
+ bool dither = (k & 1) != 0;
+ bool blend = (k & 2) != 0;
+ if (gSrcRec[j].fSrc != 0 && blend) {
+ // can't make a numerical promise about blending anything
+ // but 0
+ // continue;
+ }
+ paint.setDither(dither);
+ paint.setAlpha(blend ? 0x80 : 0xFF);
+ canvas.drawBitmap(srcBM, 0, 0, &paint);
+ if (!check_color(dstBM, gSrcRec[j].fResult32, gSrcRec[j].fResult16,
+ gSrcRec[j].fResult8, reporter)) {
+ SkDebugf("--- src index %d dither %d blend %d\n", j, dither, blend);
+ }
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct Mesh {
+ SkPoint fPts[4];
+
+ Mesh(const SkBitmap& bm, SkPaint* paint) {
+ const SkScalar w = SkIntToScalar(bm.width());
+ const SkScalar h = SkIntToScalar(bm.height());
+ fPts[0].set(0, 0);
+ fPts[1].set(w, 0);
+ fPts[2].set(w, h);
+ fPts[3].set(0, h);
+ SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+ paint->setShader(s)->unref();
+
+ }
+
+ void draw(SkCanvas* canvas, SkPaint* paint) {
+ canvas->drawVertices(SkCanvas::kTriangleFan_VertexMode, 4, fPts, fPts,
+ NULL, NULL, NULL, 0, *paint);
+ }
+};
+
+#include "SkImageEncoder.h"
+static void save_bm(const SkBitmap& bm, const char name[]) {
+ SkImageEncoder::EncodeFile(name, bm, SkImageEncoder::kPNG_Type, 100);
+}
+
+static bool gOnce;
+
+// Make sure our blits are invariant with the width of the blit (i.e. that
+// special case for 8 at a time have the same results as narrower blits)
+static void test_diagonal(skiatest::Reporter* reporter) {
+ static const int W = 64;
+ static const int H = W;
+
+ static const SkColorType gDstColorType[] = {
+ kN32_SkColorType,
+ kRGB_565_SkColorType,
+ };
+
+ static const SkColor gDstBG[] = { 0, 0xFFFFFFFF };
+
+ SkPaint paint;
+
+ SkBitmap srcBM;
+ srcBM.allocN32Pixels(W, H);
+ SkRect srcR = {
+ 0, 0, SkIntToScalar(srcBM.width()), SkIntToScalar(srcBM.height()) };
+
+ // cons up a mesh to draw the bitmap with
+ Mesh mesh(srcBM, &paint);
+
+ SkImageInfo info = SkImageInfo::Make(W, H, kUnknown_SkColorType,
+ kPremul_SkAlphaType);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gDstColorType); i++) {
+ info = info.makeColorType(gDstColorType[i]);
+
+ SkBitmap dstBM0, dstBM1;
+ dstBM0.allocPixels(info);
+ dstBM1.allocPixels(info);
+
+ SkCanvas canvas0(dstBM0);
+ SkCanvas canvas1(dstBM1);
+ SkColor bgColor;
+
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gDstBG); j++) {
+ bgColor = gDstBG[j];
+
+ for (int c = 0; c <= 0xFF; c++) {
+ srcBM.eraseARGB(0xFF, c, c, c);
+
+ for (int k = 0; k < 4; k++) {
+ bool dither = (k & 1) != 0;
+ uint8_t alpha = (k & 2) ? 0x80 : 0xFF;
+ paint.setDither(dither);
+ paint.setAlpha(alpha);
+
+ dstBM0.eraseColor(bgColor);
+ dstBM1.eraseColor(bgColor);
+
+ canvas0.drawRect(srcR, paint);
+ mesh.draw(&canvas1, &paint);
+
+ if (!gOnce && false) {
+ save_bm(dstBM0, "drawBitmap.png");
+ save_bm(dstBM1, "drawMesh.png");
+ gOnce = true;
+ }
+
+ if (memcmp(dstBM0.getPixels(), dstBM1.getPixels(), dstBM0.getSize())) {
+ ERRORF(reporter, "Diagonal colortype=%s bg=0x%x dither=%d"
+ " alpha=0x%x src=0x%x",
+ gColorTypeName[gDstColorType[i]], bgColor, dither,
+ alpha, c);
+ }
+ }
+ }
+ }
+ }
+}
+
+DEF_TEST(BlitRow, reporter) {
+ test_00_FF(reporter);
+ test_diagonal(reporter);
+}
diff --git a/src/third_party/skia/tests/BlurTest.cpp b/src/third_party/skia/tests/BlurTest.cpp
new file mode 100644
index 0000000..143d777
--- /dev/null
+++ b/src/third_party/skia/tests/BlurTest.cpp
@@ -0,0 +1,573 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBlurMask.h"
+#include "SkBlurMaskFilter.h"
+#include "SkBlurDrawLooper.h"
+#include "SkLayerDrawLooper.h"
+#include "SkEmbossMaskFilter.h"
+#include "SkCanvas.h"
+#include "SkMath.h"
+#include "SkPaint.h"
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#include "SkGpuDevice.h"
+#endif
+
+#define WRITE_CSV 0
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define ILLEGAL_MODE ((SkXfermode::Mode)-1)
+
+static const int outset = 100;
+static const SkColor bgColor = SK_ColorWHITE;
+static const int strokeWidth = 4;
+
+static void create(SkBitmap* bm, const SkIRect& bound) {
+ bm->allocN32Pixels(bound.width(), bound.height());
+}
+
+static void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(bgColor);
+}
+
+
+struct BlurTest {
+ void (*addPath)(SkPath*);
+ int viewLen;
+ SkIRect views[9];
+};
+
+//Path Draw Procs
+//Beware that paths themselves my draw differently depending on the clip.
+static void draw50x50Rect(SkPath* path) {
+ path->addRect(0, 0, SkIntToScalar(50), SkIntToScalar(50));
+}
+
+//Tests
+static BlurTest tests[] = {
+ { draw50x50Rect, 3, {
+ //inner half of blur
+ { 0, 0, 50, 50 },
+ //blur, but no path.
+ { 50 + strokeWidth/2, 50 + strokeWidth/2, 100, 100 },
+ //just an edge
+ { 40, strokeWidth, 60, 50 - strokeWidth },
+ }},
+};
+
+/** Assumes that the ref draw was completely inside ref canvas --
+ implies that everything outside is "bgColor".
+ Checks that all overlap is the same and that all non-overlap on the
+ ref is "bgColor".
+ */
+static bool compare(const SkBitmap& ref, const SkIRect& iref,
+ const SkBitmap& test, const SkIRect& itest)
+{
+ const int xOff = itest.fLeft - iref.fLeft;
+ const int yOff = itest.fTop - iref.fTop;
+
+ SkAutoLockPixels alpRef(ref);
+ SkAutoLockPixels alpTest(test);
+
+ for (int y = 0; y < test.height(); ++y) {
+ for (int x = 0; x < test.width(); ++x) {
+ SkColor testColor = test.getColor(x, y);
+ int refX = x + xOff;
+ int refY = y + yOff;
+ SkColor refColor;
+ if (refX >= 0 && refX < ref.width() &&
+ refY >= 0 && refY < ref.height())
+ {
+ refColor = ref.getColor(refX, refY);
+ } else {
+ refColor = bgColor;
+ }
+ if (refColor != testColor) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static void test_blur_drawing(skiatest::Reporter* reporter) {
+
+ SkPaint paint;
+ paint.setColor(SK_ColorGRAY);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(strokeWidth));
+
+ SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5));
+ for (int style = 0; style <= kLastEnum_SkBlurStyle; ++style) {
+ SkBlurStyle blurStyle = static_cast<SkBlurStyle>(style);
+
+ const uint32_t flagPermutations = SkBlurMaskFilter::kAll_BlurFlag;
+ for (uint32_t flags = 0; flags < flagPermutations; ++flags) {
+ SkMaskFilter* filter;
+ filter = SkBlurMaskFilter::Create(blurStyle, sigma, flags);
+
+ paint.setMaskFilter(filter);
+ filter->unref();
+
+ for (size_t test = 0; test < SK_ARRAY_COUNT(tests); ++test) {
+ SkPath path;
+ tests[test].addPath(&path);
+ SkPath strokedPath;
+ paint.getFillPath(path, &strokedPath);
+ SkRect refBound = strokedPath.getBounds();
+ SkIRect iref;
+ refBound.roundOut(&iref);
+ iref.inset(-outset, -outset);
+ SkBitmap refBitmap;
+ create(&refBitmap, iref);
+
+ SkCanvas refCanvas(refBitmap);
+ refCanvas.translate(SkIntToScalar(-iref.fLeft),
+ SkIntToScalar(-iref.fTop));
+ drawBG(&refCanvas);
+ refCanvas.drawPath(path, paint);
+
+ for (int view = 0; view < tests[test].viewLen; ++view) {
+ SkIRect itest = tests[test].views[view];
+ SkBitmap testBitmap;
+ create(&testBitmap, itest);
+
+ SkCanvas testCanvas(testBitmap);
+ testCanvas.translate(SkIntToScalar(-itest.fLeft),
+ SkIntToScalar(-itest.fTop));
+ drawBG(&testCanvas);
+ testCanvas.drawPath(path, paint);
+
+ REPORTER_ASSERT(reporter,
+ compare(refBitmap, iref, testBitmap, itest));
+ }
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// Use SkBlurMask::BlurGroundTruth to blur a 'width' x 'height' solid
+// white rect. Return the right half of the middle row in 'result'.
+static void ground_truth_2d(int width, int height,
+ SkScalar sigma,
+ int* result, int resultCount) {
+ SkMask src, dst;
+
+ src.fBounds.set(0, 0, width, height);
+ src.fFormat = SkMask::kA8_Format;
+ src.fRowBytes = src.fBounds.width();
+ src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
+
+ memset(src.fImage, 0xff, src.computeTotalImageSize());
+
+ dst.fImage = NULL;
+ SkBlurMask::BlurGroundTruth(sigma, &dst, src, kNormal_SkBlurStyle);
+
+ int midX = dst.fBounds.centerX();
+ int midY = dst.fBounds.centerY();
+ uint8_t* bytes = dst.getAddr8(midX, midY);
+ int i;
+ for (i = 0; i < dst.fBounds.width()-(midX-dst.fBounds.fLeft); ++i) {
+ if (i < resultCount) {
+ result[i] = bytes[i];
+ }
+ }
+ for ( ; i < resultCount; ++i) {
+ result[i] = 0;
+ }
+
+ SkMask::FreeImage(src.fImage);
+ SkMask::FreeImage(dst.fImage);
+}
+
+// Implement a step function that is 255 between min and max; 0 elsewhere.
+static int step(int x, SkScalar min, SkScalar max) {
+ if (min < x && x < max) {
+ return 255;
+ }
+ return 0;
+}
+
+// Implement a Gaussian function with 0 mean and std.dev. of 'sigma'.
+static float gaussian(int x, SkScalar sigma) {
+ float k = SK_Scalar1/(sigma * sqrtf(2.0f*SK_ScalarPI));
+ float exponent = -(x * x) / (2 * sigma * sigma);
+ return k * expf(exponent);
+}
+
+// Perform a brute force convolution of a step function with a Gaussian.
+// Return the right half in 'result'
+static void brute_force_1d(SkScalar stepMin, SkScalar stepMax,
+ SkScalar gaussianSigma,
+ int* result, int resultCount) {
+
+ int gaussianRange = SkScalarCeilToInt(10 * gaussianSigma);
+
+ for (int i = 0; i < resultCount; ++i) {
+ SkScalar sum = 0.0f;
+ for (int j = -gaussianRange; j < gaussianRange; ++j) {
+ sum += gaussian(j, gaussianSigma) * step(i-j, stepMin, stepMax);
+ }
+
+ result[i] = SkClampMax(SkClampPos(int(sum + 0.5f)), 255);
+ }
+}
+
+static void blur_path(SkCanvas* canvas, const SkPath& path,
+ SkScalar gaussianSigma) {
+
+ SkScalar midX = path.getBounds().centerX();
+ SkScalar midY = path.getBounds().centerY();
+
+ canvas->translate(-midX, -midY);
+
+ SkPaint blurPaint;
+ blurPaint.setColor(SK_ColorWHITE);
+ SkMaskFilter* filter = SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
+ gaussianSigma,
+ SkBlurMaskFilter::kHighQuality_BlurFlag);
+ blurPaint.setMaskFilter(filter)->unref();
+
+ canvas->drawColor(SK_ColorBLACK);
+ canvas->drawPath(path, blurPaint);
+}
+
+// Readback the blurred draw results from the canvas
+static void readback(SkCanvas* canvas, int* result, int resultCount) {
+ SkBitmap readback;
+ readback.allocN32Pixels(resultCount, 30);
+
+ SkIRect readBackRect = { 0, 0, resultCount, 30 };
+
+ canvas->readPixels(readBackRect, &readback);
+
+ readback.lockPixels();
+ SkPMColor* pixels = (SkPMColor*) readback.getAddr32(0, 15);
+
+ for (int i = 0; i < resultCount; ++i) {
+ result[i] = SkColorGetR(pixels[i]);
+ }
+}
+
+// Draw a blurred version of the provided path.
+// Return the right half of the middle row in 'result'.
+static void cpu_blur_path(const SkPath& path, SkScalar gaussianSigma,
+ int* result, int resultCount) {
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(resultCount, 30);
+ SkCanvas canvas(bitmap);
+
+ blur_path(&canvas, path, gaussianSigma);
+ readback(&canvas, result, resultCount);
+}
+
+#if SK_SUPPORT_GPU
+#if 0
+// temporary disable; see below for explanation
+static bool gpu_blur_path(GrContextFactory* factory, const SkPath& path,
+ SkScalar gaussianSigma,
+ int* result, int resultCount) {
+
+ GrContext* grContext = factory->get(GrContextFactory::kNative_GLContextType);
+ if (NULL == grContext) {
+ return false;
+ }
+
+ GrTextureDesc desc;
+ desc.fConfig = kSkia8888_GrPixelConfig;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ desc.fWidth = resultCount;
+ desc.fHeight = 30;
+ desc.fSampleCnt = 0;
+
+ SkAutoTUnref<GrTexture> texture(grContext->createUncachedTexture(desc, NULL, 0));
+ SkAutoTUnref<SkGpuDevice> device(SkNEW_ARGS(SkGpuDevice, (grContext, texture.get())));
+ SkCanvas canvas(device.get());
+
+ blur_path(&canvas, path, gaussianSigma);
+ readback(&canvas, result, resultCount);
+ return true;
+}
+#endif
+#endif
+
+#if WRITE_CSV
+static void write_as_csv(const char* label, SkScalar scale, int* data, int count) {
+ SkDebugf("%s_%.2f,", label, scale);
+ for (int i = 0; i < count-1; ++i) {
+ SkDebugf("%d,", data[i]);
+ }
+ SkDebugf("%d\n", data[count-1]);
+}
+#endif
+
+static bool match(int* first, int* second, int count, int tol) {
+ int delta;
+ for (int i = 0; i < count; ++i) {
+ delta = first[i] - second[i];
+ if (delta > tol || delta < -tol) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Test out the normal blur style with a wide range of sigmas
+static void test_sigma_range(skiatest::Reporter* reporter, GrContextFactory* factory) {
+
+ static const int kSize = 100;
+
+ // The geometry is offset a smidge to trigger:
+ // https://code.google.com/p/chromium/issues/detail?id=282418
+ SkPath rectPath;
+ rectPath.addRect(0.3f, 0.3f, 100.3f, 100.3f);
+
+ SkPoint polyPts[] = {
+ { 0.3f, 0.3f },
+ { 100.3f, 0.3f },
+ { 100.3f, 100.3f },
+ { 0.3f, 100.3f },
+ { 2.3f, 50.3f } // a little divet to throw off the rect special case
+ };
+ SkPath polyPath;
+ polyPath.addPoly(polyPts, SK_ARRAY_COUNT(polyPts), true);
+
+ int rectSpecialCaseResult[kSize];
+ int generalCaseResult[kSize];
+ int groundTruthResult[kSize];
+ int bruteForce1DResult[kSize];
+
+ SkScalar sigma = 10.0f;
+
+ for (int i = 0; i < 4; ++i, sigma /= 10) {
+
+ cpu_blur_path(rectPath, sigma, rectSpecialCaseResult, kSize);
+ cpu_blur_path(polyPath, sigma, generalCaseResult, kSize);
+
+ ground_truth_2d(100, 100, sigma, groundTruthResult, kSize);
+ brute_force_1d(-50.0f, 50.0f, sigma, bruteForce1DResult, kSize);
+
+ REPORTER_ASSERT(reporter, match(rectSpecialCaseResult, bruteForce1DResult, kSize, 5));
+ REPORTER_ASSERT(reporter, match(generalCaseResult, bruteForce1DResult, kSize, 15));
+#if SK_SUPPORT_GPU
+#if 0
+ int gpuResult[kSize];
+ bool haveGPUResult = gpu_blur_path(factory, rectPath, sigma, gpuResult, kSize);
+ // Disabling this test for now -- I don't think it's a legit comparison.
+ // Will continue to investigate this.
+ if (haveGPUResult) {
+ // 1 works everywhere but: Ubuntu13 & Nexus4
+ REPORTER_ASSERT(reporter, match(gpuResult, bruteForce1DResult, kSize, 10));
+ }
+#endif
+#endif
+ REPORTER_ASSERT(reporter, match(groundTruthResult, bruteForce1DResult, kSize, 1));
+
+#if WRITE_CSV
+ write_as_csv("RectSpecialCase", sigma, rectSpecialCaseResult, kSize);
+ write_as_csv("GeneralCase", sigma, generalCaseResult, kSize);
+#if SK_SUPPORT_GPU
+ write_as_csv("GPU", sigma, gpuResult, kSize);
+#endif
+ write_as_csv("GroundTruth2D", sigma, groundTruthResult, kSize);
+ write_as_csv("BruteForce1D", sigma, bruteForce1DResult, kSize);
+#endif
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+static SkBlurQuality blurMaskFilterFlags_as_quality(uint32_t blurMaskFilterFlags) {
+ return (blurMaskFilterFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
+ kHigh_SkBlurQuality : kLow_SkBlurQuality;
+}
+
+static uint32_t blurMaskFilterFlags_to_blurDrawLooperFlags(uint32_t bmf) {
+ const struct {
+ uint32_t fBlurMaskFilterFlag;
+ uint32_t fBlurDrawLooperFlag;
+ } pairs[] = {
+ { SkBlurMaskFilter::kIgnoreTransform_BlurFlag, SkBlurDrawLooper::kIgnoreTransform_BlurFlag },
+ { SkBlurMaskFilter::kHighQuality_BlurFlag, SkBlurDrawLooper::kHighQuality_BlurFlag },
+ };
+
+ uint32_t bdl = 0;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(pairs); ++i) {
+ if (bmf & pairs[i].fBlurMaskFilterFlag) {
+ bdl |= pairs[i].fBlurDrawLooperFlag;
+ }
+ }
+ return bdl;
+}
+
+static void test_blurDrawLooper(skiatest::Reporter* reporter, SkScalar sigma,
+ SkBlurStyle style, uint32_t blurMaskFilterFlags) {
+ if (kNormal_SkBlurStyle != style) {
+ return; // blurdrawlooper only supports normal
+ }
+
+ const SkColor color = 0xFF335577;
+ const SkScalar dx = 10;
+ const SkScalar dy = -5;
+ const SkBlurQuality quality = blurMaskFilterFlags_as_quality(blurMaskFilterFlags);
+ uint32_t flags = blurMaskFilterFlags_to_blurDrawLooperFlags(blurMaskFilterFlags);
+
+ SkAutoTUnref<SkDrawLooper> lp(SkBlurDrawLooper::Create(color, sigma, dx, dy, flags));
+
+ const bool expectSuccess = sigma > 0 &&
+ 0 == (flags & SkBlurDrawLooper::kIgnoreTransform_BlurFlag);
+
+ if (NULL == lp.get()) {
+ REPORTER_ASSERT(reporter, sigma <= 0);
+ } else {
+ SkDrawLooper::BlurShadowRec rec;
+ bool success = lp->asABlurShadow(&rec);
+ REPORTER_ASSERT(reporter, success == expectSuccess);
+ if (success) {
+ REPORTER_ASSERT(reporter, rec.fSigma == sigma);
+ REPORTER_ASSERT(reporter, rec.fOffset.x() == dx);
+ REPORTER_ASSERT(reporter, rec.fOffset.y() == dy);
+ REPORTER_ASSERT(reporter, rec.fColor == color);
+ REPORTER_ASSERT(reporter, rec.fStyle == style);
+ REPORTER_ASSERT(reporter, rec.fQuality == quality);
+ }
+ }
+}
+
+static void test_delete_looper(skiatest::Reporter* reporter, SkDrawLooper* lp, SkScalar sigma,
+ SkBlurStyle style, SkBlurQuality quality, bool expectSuccess) {
+ SkDrawLooper::BlurShadowRec rec;
+ bool success = lp->asABlurShadow(&rec);
+ REPORTER_ASSERT(reporter, success == expectSuccess);
+ if (success != expectSuccess) {
+ lp->asABlurShadow(&rec);
+ }
+ if (success) {
+ REPORTER_ASSERT(reporter, rec.fSigma == sigma);
+ REPORTER_ASSERT(reporter, rec.fStyle == style);
+ REPORTER_ASSERT(reporter, rec.fQuality == quality);
+ }
+ lp->unref();
+}
+
+static void make_noop_layer(SkLayerDrawLooper::Builder* builder) {
+ SkLayerDrawLooper::LayerInfo info;
+
+ info.fPaintBits = 0;
+ info.fColorMode = SkXfermode::kDst_Mode;
+ builder->addLayer(info);
+}
+
+static void make_blur_layer(SkLayerDrawLooper::Builder* builder, SkMaskFilter* mf) {
+ SkLayerDrawLooper::LayerInfo info;
+
+ info.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit;
+ info.fColorMode = SkXfermode::kSrc_Mode;
+ SkPaint* paint = builder->addLayer(info);
+ paint->setMaskFilter(mf);
+}
+
+static void test_layerDrawLooper(skiatest::Reporter* reporter, SkMaskFilter* mf, SkScalar sigma,
+ SkBlurStyle style, SkBlurQuality quality, bool expectSuccess) {
+
+ SkLayerDrawLooper::LayerInfo info;
+ SkLayerDrawLooper::Builder builder;
+
+ // 1 layer is too few
+ make_noop_layer(&builder);
+ test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, false);
+
+ // 2 layers is good, but need blur
+ make_noop_layer(&builder);
+ make_noop_layer(&builder);
+ test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, false);
+
+ // 2 layers is just right
+ make_noop_layer(&builder);
+ make_blur_layer(&builder, mf);
+ test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, expectSuccess);
+
+ // 3 layers is too many
+ make_noop_layer(&builder);
+ make_blur_layer(&builder, mf);
+ make_noop_layer(&builder);
+ test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, false);
+}
+
+static void test_asABlur(skiatest::Reporter* reporter) {
+ const SkBlurStyle styles[] = {
+ kNormal_SkBlurStyle, kSolid_SkBlurStyle, kOuter_SkBlurStyle, kInner_SkBlurStyle
+ };
+ const SkScalar sigmas[] = {
+ // values <= 0 should not success for a blur
+ -1, 0, 0.5f, 2
+ };
+
+ // Test asABlur for SkBlurMaskFilter
+ //
+ for (size_t i = 0; i < SK_ARRAY_COUNT(styles); ++i) {
+ const SkBlurStyle style = (SkBlurStyle)styles[i];
+ for (size_t j = 0; j < SK_ARRAY_COUNT(sigmas); ++j) {
+ const SkScalar sigma = sigmas[j];
+ for (int flags = 0; flags <= SkBlurMaskFilter::kAll_BlurFlag; ++flags) {
+ const SkBlurQuality quality = blurMaskFilterFlags_as_quality(flags);
+
+ SkAutoTUnref<SkMaskFilter> mf(SkBlurMaskFilter::Create(style, sigma, flags));
+ if (NULL == mf.get()) {
+ REPORTER_ASSERT(reporter, sigma <= 0);
+ } else {
+ REPORTER_ASSERT(reporter, sigma > 0);
+ SkMaskFilter::BlurRec rec;
+ bool success = mf->asABlur(&rec);
+ if (flags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
+ REPORTER_ASSERT(reporter, !success);
+ } else {
+ REPORTER_ASSERT(reporter, success);
+ REPORTER_ASSERT(reporter, rec.fSigma == sigma);
+ REPORTER_ASSERT(reporter, rec.fStyle == style);
+ REPORTER_ASSERT(reporter, rec.fQuality == quality);
+ }
+ test_layerDrawLooper(reporter, mf, sigma, style, quality, success);
+ }
+ test_blurDrawLooper(reporter, sigma, style, flags);
+ }
+ }
+ }
+
+ // Test asABlur for SkEmbossMaskFilter -- should never succeed
+ //
+ {
+ SkEmbossMaskFilter::Light light = {
+ { 1, 1, 1 }, 0, 127, 127
+ };
+ for (size_t j = 0; j < SK_ARRAY_COUNT(sigmas); ++j) {
+ const SkScalar sigma = sigmas[j];
+ SkAutoTUnref<SkMaskFilter> mf(SkEmbossMaskFilter::Create(sigma, light));
+ if (mf.get()) {
+ SkMaskFilter::BlurRec rec;
+ bool success = mf->asABlur(&rec);
+ REPORTER_ASSERT(reporter, !success);
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+DEF_GPUTEST(Blur, reporter, factory) {
+ test_blur_drawing(reporter);
+ test_sigma_range(reporter, factory);
+ test_asABlur(reporter);
+}
diff --git a/src/third_party/skia/tests/CachedDecodingPixelRefTest.cpp b/src/third_party/skia/tests/CachedDecodingPixelRefTest.cpp
new file mode 100644
index 0000000..b3eb532
--- /dev/null
+++ b/src/third_party/skia/tests/CachedDecodingPixelRefTest.cpp
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkCachingPixelRef.h"
+#include "SkCanvas.h"
+#include "SkData.h"
+#include "SkDecodingImageGenerator.h"
+#include "SkDiscardableMemoryPool.h"
+#include "SkImageDecoder.h"
+#include "SkImageGeneratorPriv.h"
+#include "SkResourceCache.h"
+#include "SkStream.h"
+#include "SkUtils.h"
+
+#include "Test.h"
+
+/**
+ * Fill this bitmap with some color.
+ */
+static void make_test_image(SkBitmap* bm) {
+ const int W = 50, H = 50;
+ bm->allocN32Pixels(W, H);
+ bm->eraseColor(SK_ColorBLACK);
+ SkCanvas canvas(*bm);
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ canvas.drawRectCoords(0, 0, SkIntToScalar(W/2),
+ SkIntToScalar(H/2), paint);
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRectCoords(SkIntToScalar(W/2), SkIntToScalar(H/2),
+ SkIntToScalar(W), SkIntToScalar(H), paint);
+}
+
+/**
+ * encode this bitmap into some data via SkImageEncoder
+ */
+static SkData* create_data_from_bitmap(const SkBitmap& bm,
+ SkImageEncoder::Type type) {
+ SkDynamicMemoryWStream stream;
+ if (SkImageEncoder::EncodeStream(&stream, bm, type, 100)) {
+ return stream.copyToData();
+ }
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static void compare_bitmaps(skiatest::Reporter* reporter,
+ const SkBitmap& b1, const SkBitmap& b2,
+ bool pixelPerfect = true) {
+ REPORTER_ASSERT(reporter, b1.empty() == b2.empty());
+ REPORTER_ASSERT(reporter, b1.width() == b2.width());
+ REPORTER_ASSERT(reporter, b1.height() == b2.height());
+ REPORTER_ASSERT(reporter, b1.isNull() == b2.isNull());
+ SkAutoLockPixels autoLockPixels1(b1);
+ SkAutoLockPixels autoLockPixels2(b2);
+ REPORTER_ASSERT(reporter, b1.isNull() == b2.isNull());
+ if (b1.isNull() || b1.empty()) {
+ return;
+ }
+ REPORTER_ASSERT(reporter, b1.getPixels());
+ REPORTER_ASSERT(reporter, b2.getPixels());
+ if ((!(b1.getPixels())) || (!(b2.getPixels()))) {
+ return;
+ }
+ if ((b1.width() != b2.width()) ||
+ (b1.height() != b2.height())) {
+ return;
+ }
+ if (!pixelPerfect) {
+ return;
+ }
+
+ int pixelErrors = 0;
+ for (int y = 0; y < b2.height(); ++y) {
+ for (int x = 0; x < b2.width(); ++x) {
+ if (b1.getColor(x, y) != b2.getColor(x, y)) {
+ ++pixelErrors;
+ }
+ }
+ }
+ REPORTER_ASSERT(reporter, 0 == pixelErrors);
+}
+
+typedef bool (*InstallEncoded)(SkData* encoded, SkBitmap* dst);
+
+/**
+ This function tests three differently encoded images against the
+ original bitmap */
+static void test_three_encodings(skiatest::Reporter* reporter,
+ InstallEncoded install) {
+ SkBitmap original;
+ make_test_image(&original);
+ REPORTER_ASSERT(reporter, !original.empty());
+ REPORTER_ASSERT(reporter, !original.isNull());
+ if (original.empty() || original.isNull()) {
+ return;
+ }
+ static const SkImageEncoder::Type types[] = {
+ SkImageEncoder::kPNG_Type,
+ SkImageEncoder::kJPEG_Type,
+ SkImageEncoder::kWEBP_Type
+ };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(types); i++) {
+ SkImageEncoder::Type type = types[i];
+ SkAutoDataUnref encoded(create_data_from_bitmap(original, type));
+ REPORTER_ASSERT(reporter, encoded.get() != NULL);
+ if (NULL == encoded.get()) {
+ continue;
+ }
+ SkBitmap lazy;
+ bool installSuccess = install(encoded.get(), &lazy);
+ REPORTER_ASSERT(reporter, installSuccess);
+ if (!installSuccess) {
+ continue;
+ }
+ REPORTER_ASSERT(reporter, NULL == lazy.getPixels());
+ {
+ SkAutoLockPixels autoLockPixels(lazy); // now pixels are good.
+ REPORTER_ASSERT(reporter, lazy.getPixels());
+ if (NULL == lazy.getPixels()) {
+ continue;
+ }
+ }
+ // pixels should be gone!
+ REPORTER_ASSERT(reporter, NULL == lazy.getPixels());
+ {
+ SkAutoLockPixels autoLockPixels(lazy); // now pixels are good.
+ REPORTER_ASSERT(reporter, lazy.getPixels());
+ if (NULL == lazy.getPixels()) {
+ continue;
+ }
+ }
+ bool comparePixels = (SkImageEncoder::kPNG_Type == type);
+ compare_bitmaps(reporter, original, lazy, comparePixels);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+static bool install_skCachingPixelRef(SkData* encoded, SkBitmap* dst) {
+ return SkCachingPixelRef::Install(
+ SkDecodingImageGenerator::Create(
+ encoded, SkDecodingImageGenerator::Options()), dst);
+}
+static bool install_skDiscardablePixelRef(SkData* encoded, SkBitmap* dst) {
+ // Use system-default discardable memory.
+ return SkInstallDiscardablePixelRef(
+ SkDecodingImageGenerator::Create(
+ encoded, SkDecodingImageGenerator::Options()), dst);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * This checks to see that a SkCachingPixelRef and a
+ * SkDiscardablePixelRef works as advertised with a
+ * SkDecodingImageGenerator.
+ */
+DEF_TEST(DecodingImageGenerator, reporter) {
+ test_three_encodings(reporter, install_skCachingPixelRef);
+ test_three_encodings(reporter, install_skDiscardablePixelRef);
+}
+
+class TestImageGenerator : public SkImageGenerator {
+public:
+ enum TestType {
+ kFailGetInfo_TestType,
+ kFailGetPixels_TestType,
+ kSucceedGetPixels_TestType,
+ kLast_TestType = kSucceedGetPixels_TestType
+ };
+ static int Width() { return 10; }
+ static int Height() { return 10; }
+ static uint32_t Color() { return 0xff123456; }
+ TestImageGenerator(TestType type, skiatest::Reporter* reporter)
+ : fType(type), fReporter(reporter) {
+ SkASSERT((fType <= kLast_TestType) && (fType >= 0));
+ }
+ virtual ~TestImageGenerator() { }
+
+protected:
+ virtual bool onGetInfo(SkImageInfo* info) SK_OVERRIDE {
+ REPORTER_ASSERT(fReporter, info);
+ if ((NULL == info) || (kFailGetInfo_TestType == fType)) {
+ return false;
+ }
+ *info = SkImageInfo::MakeN32(TestImageGenerator::Width(),
+ TestImageGenerator::Height(),
+ kOpaque_SkAlphaType);
+ return true;
+ }
+
+ virtual bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
+ SkPMColor ctable[], int* ctableCount) SK_OVERRIDE {
+ REPORTER_ASSERT(fReporter, pixels != NULL);
+ size_t minRowBytes = static_cast<size_t>(info.width() * info.bytesPerPixel());
+ REPORTER_ASSERT(fReporter, rowBytes >= minRowBytes);
+ if ((NULL == pixels)
+ || (fType != kSucceedGetPixels_TestType)
+ || (info.colorType() != kN32_SkColorType)) {
+ return false;
+ }
+ char* bytePtr = static_cast<char*>(pixels);
+ for (int y = 0; y < info.height(); ++y) {
+ sk_memset32(reinterpret_cast<SkColor*>(bytePtr),
+ TestImageGenerator::Color(), info.width());
+ bytePtr += rowBytes;
+ }
+ return true;
+ }
+
+private:
+ const TestType fType;
+ skiatest::Reporter* const fReporter;
+};
+
+static void check_test_image_generator_bitmap(skiatest::Reporter* reporter,
+ const SkBitmap& bm) {
+ REPORTER_ASSERT(reporter, TestImageGenerator::Width() == bm.width());
+ REPORTER_ASSERT(reporter, TestImageGenerator::Height() == bm.height());
+ SkAutoLockPixels autoLockPixels(bm);
+ REPORTER_ASSERT(reporter, bm.getPixels());
+ if (NULL == bm.getPixels()) {
+ return;
+ }
+ int errors = 0;
+ for (int y = 0; y < bm.height(); ++y) {
+ for (int x = 0; x < bm.width(); ++x) {
+ if (TestImageGenerator::Color() != *bm.getAddr32(x, y)) {
+ ++errors;
+ }
+ }
+ }
+ REPORTER_ASSERT(reporter, 0 == errors);
+}
+
+enum PixelRefType {
+ kSkCaching_PixelRefType,
+ kSkDiscardable_PixelRefType,
+ kLast_PixelRefType = kSkDiscardable_PixelRefType
+};
+
+static void check_pixelref(TestImageGenerator::TestType type,
+ skiatest::Reporter* reporter,
+ PixelRefType pixelRefType,
+ SkDiscardableMemory::Factory* factory) {
+ SkASSERT((pixelRefType >= 0) && (pixelRefType <= kLast_PixelRefType));
+ SkAutoTDelete<SkImageGenerator> gen(SkNEW_ARGS(TestImageGenerator,
+ (type, reporter)));
+ REPORTER_ASSERT(reporter, gen.get() != NULL);
+ SkBitmap lazy;
+ bool success;
+ if (kSkCaching_PixelRefType == pixelRefType) {
+ // Ignore factory; use global cache.
+ success = SkCachingPixelRef::Install(gen.detach(), &lazy);
+ } else {
+ success = SkInstallDiscardablePixelRef(gen.detach(), &lazy, factory);
+ }
+ REPORTER_ASSERT(reporter, success
+ == (TestImageGenerator::kFailGetInfo_TestType != type));
+ if (TestImageGenerator::kSucceedGetPixels_TestType == type) {
+ check_test_image_generator_bitmap(reporter, lazy);
+ } else if (TestImageGenerator::kFailGetPixels_TestType == type) {
+ SkAutoLockPixels autoLockPixels(lazy);
+ REPORTER_ASSERT(reporter, NULL == lazy.getPixels());
+ }
+}
+
+// new/lock/delete is an odd pattern for a pixelref, but it needs to not assert
+static void test_newlockdelete(skiatest::Reporter* reporter) {
+ SkBitmap bm;
+ SkImageGenerator* ig = new TestImageGenerator(
+ TestImageGenerator::kSucceedGetPixels_TestType, reporter);
+ SkInstallDiscardablePixelRef(ig, &bm);
+ bm.pixelRef()->lockPixels();
+}
+
+/**
+ * This tests the basic functionality of SkDiscardablePixelRef with a
+ * basic SkImageGenerator implementation and several
+ * SkDiscardableMemory::Factory choices.
+ */
+DEF_TEST(DiscardableAndCachingPixelRef, reporter) {
+ test_newlockdelete(reporter);
+
+ check_pixelref(TestImageGenerator::kFailGetInfo_TestType,
+ reporter, kSkCaching_PixelRefType, NULL);
+ check_pixelref(TestImageGenerator::kFailGetPixels_TestType,
+ reporter, kSkCaching_PixelRefType, NULL);
+ check_pixelref(TestImageGenerator::kSucceedGetPixels_TestType,
+ reporter, kSkCaching_PixelRefType, NULL);
+
+ check_pixelref(TestImageGenerator::kFailGetInfo_TestType,
+ reporter, kSkDiscardable_PixelRefType, NULL);
+ check_pixelref(TestImageGenerator::kFailGetPixels_TestType,
+ reporter, kSkDiscardable_PixelRefType, NULL);
+ check_pixelref(TestImageGenerator::kSucceedGetPixels_TestType,
+ reporter, kSkDiscardable_PixelRefType, NULL);
+
+ SkAutoTUnref<SkDiscardableMemoryPool> pool(
+ SkDiscardableMemoryPool::Create(1, NULL));
+ REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed());
+ check_pixelref(TestImageGenerator::kFailGetPixels_TestType,
+ reporter, kSkDiscardable_PixelRefType, pool);
+ REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed());
+ check_pixelref(TestImageGenerator::kSucceedGetPixels_TestType,
+ reporter, kSkDiscardable_PixelRefType, pool);
+ REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed());
+
+ SkDiscardableMemoryPool* globalPool = SkGetGlobalDiscardableMemoryPool();
+ // Only acts differently from NULL on a platform that has a
+ // default discardable memory implementation that differs from the
+ // global DM pool.
+ check_pixelref(TestImageGenerator::kFailGetPixels_TestType,
+ reporter, kSkDiscardable_PixelRefType, globalPool);
+ check_pixelref(TestImageGenerator::kSucceedGetPixels_TestType,
+ reporter, kSkDiscardable_PixelRefType, globalPool);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+DEF_TEST(Image_NewFromGenerator, r) {
+ TestImageGenerator::TestType testTypes[] = {
+ TestImageGenerator::kFailGetInfo_TestType,
+ TestImageGenerator::kFailGetPixels_TestType,
+ TestImageGenerator::kSucceedGetPixels_TestType,
+ };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(testTypes); ++i) {
+ TestImageGenerator::TestType test = testTypes[i];
+ SkImageGenerator* gen = SkNEW_ARGS(TestImageGenerator, (test, r));
+ SkAutoTUnref<SkImage> image(SkImage::NewFromGenerator(gen));
+ if (TestImageGenerator::kFailGetInfo_TestType == test) {
+ REPORTER_ASSERT(r, NULL == image.get());
+ continue;
+ }
+ if (NULL == image.get()) {
+ ERRORF(r, "SkImage::NewFromGenerator unexpecedly failed ["
+ SK_SIZE_T_SPECIFIER "]", i);
+ continue;
+ }
+ REPORTER_ASSERT(r, TestImageGenerator::Width() == image->width());
+ REPORTER_ASSERT(r, TestImageGenerator::Height() == image->height());
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(TestImageGenerator::Width(), TestImageGenerator::Height());
+ SkCanvas canvas(bitmap);
+ const SkColor kDefaultColor = 0xffabcdef;
+ canvas.clear(kDefaultColor);
+ canvas.drawImage(image, 0, 0, NULL);
+ if (TestImageGenerator::kSucceedGetPixels_TestType == test) {
+ REPORTER_ASSERT(
+ r, TestImageGenerator::Color() == *bitmap.getAddr32(0, 0));
+ } else {
+ REPORTER_ASSERT(r, kDefaultColor == bitmap.getColor(0,0));
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/CanvasStateHelpers.cpp b/src/third_party/skia/tests/CanvasStateHelpers.cpp
new file mode 100644
index 0000000..96972b8
--- /dev/null
+++ b/src/third_party/skia/tests/CanvasStateHelpers.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "CanvasStateHelpers.h"
+#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
+#include "SkCanvas.h"
+#include "SkCanvasStateUtils.h"
+#include "SkPaint.h"
+#include "SkRect.h"
+#include "SkRegion.h"
+
+void complex_layers_draw(SkCanvas* canvas, float left, float top,
+ float right, float bottom, int32_t spacer) {
+ SkPaint bluePaint;
+ bluePaint.setColor(SK_ColorBLUE);
+ bluePaint.setStyle(SkPaint::kFill_Style);
+
+ SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
+ canvas->drawRect(rect, bluePaint);
+ canvas->translate(0, rect.height() + spacer);
+ canvas->drawRect(rect, bluePaint);
+}
+
+extern "C" bool complex_layers_draw_from_canvas_state(SkCanvasState* state,
+ float left, float top, float right, float bottom, int32_t spacer) {
+ SkCanvas* canvas = SkCanvasStateUtils::CreateFromCanvasState(state);
+ if (!canvas) {
+ return false;
+ }
+ complex_layers_draw(canvas, left, top, right, bottom, spacer);
+ canvas->unref();
+ return true;
+}
+
+void complex_clips_draw(SkCanvas* canvas, int32_t left, int32_t top,
+ int32_t right, int32_t bottom, int32_t clipOp, const SkRegion& localRegion) {
+ canvas->save();
+ SkRect clipRect = SkRect::MakeLTRB(SkIntToScalar(left), SkIntToScalar(top),
+ SkIntToScalar(right), SkIntToScalar(bottom));
+ canvas->clipRect(clipRect, (SkRegion::Op) clipOp);
+ canvas->drawColor(SK_ColorBLUE);
+ canvas->restore();
+
+ canvas->clipRegion(localRegion, (SkRegion::Op) clipOp);
+ canvas->drawColor(SK_ColorBLUE);
+}
+
+extern "C" bool complex_clips_draw_from_canvas_state(SkCanvasState* state,
+ int32_t left, int32_t top, int32_t right, int32_t bottom, int32_t clipOp,
+ int32_t regionRects, int32_t* rectCoords) {
+ SkCanvas* canvas = SkCanvasStateUtils::CreateFromCanvasState(state);
+ if (!canvas) {
+ return false;
+ }
+
+ SkRegion localRegion;
+ for (int32_t i = 0; i < regionRects; ++i) {
+ localRegion.op(rectCoords[0], rectCoords[1], rectCoords[2], rectCoords[3],
+ SkRegion::kUnion_Op);
+ rectCoords += 4;
+ }
+
+ complex_clips_draw(canvas, left, top, right, bottom, clipOp, localRegion);
+ canvas->unref();
+ return true;
+}
+#endif // SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
diff --git a/src/third_party/skia/tests/CanvasStateHelpers.h b/src/third_party/skia/tests/CanvasStateHelpers.h
new file mode 100644
index 0000000..aa3c178
--- /dev/null
+++ b/src/third_party/skia/tests/CanvasStateHelpers.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef CanvasStateHelpers_DEFINED
+#define CanvasStateHelpers_DEFINED
+
+#include "SkTypes.h"
+
+#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
+class SkCanvas;
+class SkCanvasState;
+class SkRegion;
+
+/*
+ * Helper function to perform drawing to an SkCanvas. Used by both
+ * test_complex_layers and complex_layers_draw_from_canvas_state.
+ */
+void complex_layers_draw(SkCanvas* canvas, float left, float top,
+ float right, float bottom, int32_t spacer);
+
+/*
+ * Create an SkCanvas from state and draw to it. Return true on success.
+ *
+ * Used by test_complex_layers test in CanvasStateTest. Marked as extern
+ * so it can be called from a separate library.
+ */
+extern "C" bool complex_layers_draw_from_canvas_state(SkCanvasState* state,
+ float left, float top, float right, float bottom, int32_t spacer);
+
+/*
+ * Helper function to perform drawing to an SkCanvas. Used both by test_complex_clips
+ * and complex_clips_draw_from_canvas_state.
+ */
+void complex_clips_draw(SkCanvas* canvas, int32_t left, int32_t top,
+ int32_t right, int32_t bottom, int32_t clipOp, const SkRegion& localRegion);
+
+/*
+ * Create an SkCanvas from state and draw to it. Return true on success.
+ *
+ * Used by test_complex_clips test in CanvasStateTest. Marked as extern
+ * so it can be called from a separate library.
+ */
+extern "C" bool complex_clips_draw_from_canvas_state(SkCanvasState* state,
+ int32_t left, int32_t top, int32_t right, int32_t bottom, int32_t clipOp,
+ int32_t regionRects, int32_t* rectCoords);
+
+#endif // SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
+#endif // CanvasStateHelpers_DEFINED
diff --git a/src/third_party/skia/tests/CanvasStateTest.cpp b/src/third_party/skia/tests/CanvasStateTest.cpp
new file mode 100644
index 0000000..8364a4b
--- /dev/null
+++ b/src/third_party/skia/tests/CanvasStateTest.cpp
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "CanvasStateHelpers.h"
+#include "SkCanvas.h"
+#include "SkCanvasStateUtils.h"
+#include "SkCommandLineFlags.h"
+#include "SkDrawFilter.h"
+#include "SkError.h"
+#include "SkPaint.h"
+#include "SkRRect.h"
+#include "SkRect.h"
+#include "Test.h"
+
+// dlopen and the library flag are only used for tests which require this flag.
+#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
+#include <dlfcn.h>
+
+DEFINE_string(library, "", "Support library to use for CanvasState test. If empty (the default), "
+ "the test will be run without crossing a library boundary. Otherwise, "
+ "it is expected to be a full path to a shared library file, which will"
+ " be dynamically loaded. Functions from the library will be called to "
+ "test SkCanvasState. Instructions for generating the library are in "
+ "gyp/canvas_state_lib.gyp");
+
+
+// This class calls dlopen on the library passed in to the command line flag library, and handles
+// calling dlclose when it goes out of scope.
+class OpenLibResult {
+public:
+ // If the flag library was passed to this run of the test, attempt to open it using dlopen and
+ // report whether it succeeded.
+ OpenLibResult(skiatest::Reporter* reporter) {
+ if (FLAGS_library.count() == 1) {
+ fHandle = dlopen(FLAGS_library[0], RTLD_LAZY | RTLD_LOCAL);
+ REPORTER_ASSERT_MESSAGE(reporter, fHandle != NULL, "Failed to open library!");
+ } else {
+ fHandle = NULL;
+ }
+ }
+
+ // Automatically call dlclose when going out of scope.
+ ~OpenLibResult() {
+ if (fHandle) {
+ dlclose(fHandle);
+ }
+ }
+
+ // Pointer to the shared library object.
+ void* handle() { return fHandle; }
+
+private:
+ void* fHandle;
+};
+
+DEF_TEST(CanvasState_test_complex_layers, reporter) {
+ const int WIDTH = 400;
+ const int HEIGHT = 400;
+ const int SPACER = 10;
+
+ SkRect rect = SkRect::MakeXYWH(SkIntToScalar(SPACER), SkIntToScalar(SPACER),
+ SkIntToScalar(WIDTH-(2*SPACER)),
+ SkIntToScalar((HEIGHT-(2*SPACER)) / 7));
+
+ const SkColorType colorTypes[] = {
+ kRGB_565_SkColorType, kN32_SkColorType
+ };
+
+ const int layerAlpha[] = { 255, 255, 0 };
+ const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
+ SkCanvas::kARGB_ClipLayer_SaveFlag,
+ SkCanvas::kARGB_NoClipLayer_SaveFlag
+ };
+ REPORTER_ASSERT(reporter, sizeof(layerAlpha) == sizeof(flags));
+
+ bool (*drawFn)(SkCanvasState* state, float l, float t,
+ float r, float b, int32_t s);
+
+ OpenLibResult openLibResult(reporter);
+ if (openLibResult.handle() != NULL) {
+ *(void**) (&drawFn) = dlsym(openLibResult.handle(),
+ "complex_layers_draw_from_canvas_state");
+ } else {
+ drawFn = complex_layers_draw_from_canvas_state;
+ }
+
+ REPORTER_ASSERT(reporter, drawFn);
+ if (!drawFn) {
+ return;
+ }
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(colorTypes); ++i) {
+ SkBitmap bitmaps[2];
+ for (int j = 0; j < 2; ++j) {
+ bitmaps[j].allocPixels(SkImageInfo::Make(WIDTH, HEIGHT,
+ colorTypes[i],
+ kPremul_SkAlphaType));
+
+ SkCanvas canvas(bitmaps[j]);
+
+ canvas.drawColor(SK_ColorRED);
+
+ for (size_t k = 0; k < SK_ARRAY_COUNT(layerAlpha); ++k) {
+ // draw a rect within the layer's bounds and again outside the layer's bounds
+ canvas.saveLayerAlpha(&rect, layerAlpha[k], flags[k]);
+
+ if (j) {
+ // Capture from the first Skia.
+ SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
+ REPORTER_ASSERT(reporter, state);
+
+ // And draw to it in the second Skia.
+ bool success = complex_layers_draw_from_canvas_state(state,
+ rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, SPACER);
+ REPORTER_ASSERT(reporter, success);
+
+ // And release it in the *first* Skia.
+ SkCanvasStateUtils::ReleaseCanvasState(state);
+ } else {
+ // Draw in the first Skia.
+ complex_layers_draw(&canvas, rect.fLeft, rect.fTop,
+ rect.fRight, rect.fBottom, SPACER);
+ }
+
+ canvas.restore();
+
+ // translate the canvas for the next iteration
+ canvas.translate(0, 2*(rect.height() + SPACER));
+ }
+ }
+
+ // now we memcmp the two bitmaps
+ REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
+ REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
+ bitmaps[1].getPixels(),
+ bitmaps[0].getSize()));
+ }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
+DEF_TEST(CanvasState_test_complex_clips, reporter) {
+ const int WIDTH = 400;
+ const int HEIGHT = 400;
+ const int SPACER = 10;
+
+ SkIRect layerRect = SkIRect::MakeWH(WIDTH, HEIGHT / 4);
+ layerRect.inset(2*SPACER, 2*SPACER);
+
+ SkIRect clipRect = layerRect;
+ clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER);
+ clipRect.outset(SPACER, SPACER);
+
+ SkIRect regionBounds = clipRect;
+ regionBounds.offset(clipRect.width() + (2*SPACER), 0);
+
+ SkIRect regionInterior = regionBounds;
+ regionInterior.inset(SPACER*3, SPACER*3);
+
+ SkRegion clipRegion;
+ clipRegion.setRect(regionBounds);
+ clipRegion.op(regionInterior, SkRegion::kDifference_Op);
+
+
+ const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op,
+ SkRegion::kIntersect_Op,
+ SkRegion::kReplace_Op,
+ };
+ const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
+ SkCanvas::kARGB_ClipLayer_SaveFlag,
+ SkCanvas::kARGB_NoClipLayer_SaveFlag,
+ };
+ REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags));
+
+ bool (*drawFn)(SkCanvasState* state, int32_t l, int32_t t,
+ int32_t r, int32_t b, int32_t clipOp,
+ int32_t regionRects, int32_t* rectCoords);
+
+ OpenLibResult openLibResult(reporter);
+ if (openLibResult.handle() != NULL) {
+ *(void**) (&drawFn) = dlsym(openLibResult.handle(),
+ "complex_clips_draw_from_canvas_state");
+ } else {
+ drawFn = complex_clips_draw_from_canvas_state;
+ }
+
+ REPORTER_ASSERT(reporter, drawFn);
+ if (!drawFn) {
+ return;
+ }
+
+ SkBitmap bitmaps[2];
+ for (int i = 0; i < 2; ++i) {
+ bitmaps[i].allocN32Pixels(WIDTH, HEIGHT);
+
+ SkCanvas canvas(bitmaps[i]);
+
+ canvas.drawColor(SK_ColorRED);
+
+ SkRegion localRegion = clipRegion;
+
+ for (size_t j = 0; j < SK_ARRAY_COUNT(flags); ++j) {
+ SkRect layerBounds = SkRect::Make(layerRect);
+ canvas.saveLayerAlpha(&layerBounds, 128, flags[j]);
+
+ if (i) {
+ SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
+ REPORTER_ASSERT(reporter, state);
+
+ SkRegion::Iterator iter(localRegion);
+ SkTDArray<int32_t> rectCoords;
+ for (; !iter.done(); iter.next()) {
+ const SkIRect& rect = iter.rect();
+ *rectCoords.append() = rect.fLeft;
+ *rectCoords.append() = rect.fTop;
+ *rectCoords.append() = rect.fRight;
+ *rectCoords.append() = rect.fBottom;
+ }
+ bool success = drawFn(state, clipRect.fLeft, clipRect.fTop,
+ clipRect.fRight, clipRect.fBottom, clipOps[j],
+ rectCoords.count() / 4, rectCoords.begin());
+ REPORTER_ASSERT(reporter, success);
+
+ SkCanvasStateUtils::ReleaseCanvasState(state);
+ } else {
+ complex_clips_draw(&canvas, clipRect.fLeft, clipRect.fTop,
+ clipRect.fRight, clipRect.fBottom, clipOps[j],
+ localRegion);
+ }
+
+ canvas.restore();
+
+ // translate the canvas and region for the next iteration
+ canvas.translate(0, SkIntToScalar(2*(layerRect.height() + (SPACER))));
+ localRegion.translate(0, 2*(layerRect.height() + SPACER));
+ }
+ }
+
+ // now we memcmp the two bitmaps
+ REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
+ REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
+ bitmaps[1].getPixels(),
+ bitmaps[0].getSize()));
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TestDrawFilter : public SkDrawFilter {
+public:
+ virtual bool filter(SkPaint*, Type) SK_OVERRIDE { return true; }
+};
+
+DEF_TEST(CanvasState_test_draw_filters, reporter) {
+ TestDrawFilter drawFilter;
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(10, 10);
+ SkCanvas canvas(bitmap);
+
+ canvas.setDrawFilter(&drawFilter);
+
+ SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
+ REPORTER_ASSERT(reporter, state);
+ SkCanvas* tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
+ REPORTER_ASSERT(reporter, tmpCanvas);
+
+ REPORTER_ASSERT(reporter, canvas.getDrawFilter());
+ REPORTER_ASSERT(reporter, NULL == tmpCanvas->getDrawFilter());
+
+ tmpCanvas->unref();
+ SkCanvasStateUtils::ReleaseCanvasState(state);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// we need this function to prevent SkError from printing to stdout
+static void error_callback(SkError code, void* ctx) {}
+
+DEF_TEST(CanvasState_test_soft_clips, reporter) {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(10, 10);
+ SkCanvas canvas(bitmap);
+
+ SkRRect roundRect;
+ roundRect.setOval(SkRect::MakeWH(5, 5));
+
+ canvas.clipRRect(roundRect, SkRegion::kIntersect_Op, true);
+
+ SkSetErrorCallback(error_callback, NULL);
+
+ SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
+ REPORTER_ASSERT(reporter, !state);
+
+ REPORTER_ASSERT(reporter, kInvalidOperation_SkError == SkGetLastError());
+ SkClearLastError();
+}
+
+#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
+DEF_TEST(CanvasState_test_saveLayer_clip, reporter) {
+ const int WIDTH = 100;
+ const int HEIGHT = 100;
+ const int LAYER_WIDTH = 50;
+ const int LAYER_HEIGHT = 50;
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(WIDTH, HEIGHT);
+ SkCanvas canvas(bitmap);
+
+ SkRect bounds = SkRect::MakeWH(SkIntToScalar(LAYER_WIDTH), SkIntToScalar(LAYER_HEIGHT));
+ canvas.clipRect(SkRect::MakeWH(SkIntToScalar(WIDTH), SkIntToScalar(HEIGHT)));
+
+ // Check that saveLayer without the kClipToLayer_SaveFlag leaves the
+ // clip stack unchanged.
+ canvas.saveLayer(&bounds, NULL, SkCanvas::kARGB_NoClipLayer_SaveFlag);
+ SkRect clipStackBounds;
+ SkClipStack::BoundsType boundsType;
+ canvas.getClipStack()->getBounds(&clipStackBounds, &boundsType);
+ REPORTER_ASSERT(reporter, clipStackBounds.width() == WIDTH);
+ REPORTER_ASSERT(reporter, clipStackBounds.height() == HEIGHT);
+ canvas.restore();
+
+ // Check that saveLayer with the kClipToLayer_SaveFlag sets the clip
+ // stack to the layer bounds.
+ canvas.saveLayer(&bounds, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
+ canvas.getClipStack()->getBounds(&clipStackBounds, &boundsType);
+ REPORTER_ASSERT(reporter, clipStackBounds.width() == LAYER_WIDTH);
+ REPORTER_ASSERT(reporter, clipStackBounds.height() == LAYER_HEIGHT);
+
+ canvas.restore();
+}
+#endif
diff --git a/src/third_party/skia/tests/CanvasTest.cpp b/src/third_party/skia/tests/CanvasTest.cpp
new file mode 100644
index 0000000..216a408
--- /dev/null
+++ b/src/third_party/skia/tests/CanvasTest.cpp
@@ -0,0 +1,922 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Description:
+ * This test defines a series of elementatry test steps that perform
+ * a single or a small group of canvas API calls. Each test step is
+ * used in several test cases that verify that different types of SkCanvas
+ * flavors and derivatives pass it and yield consistent behavior. The
+ * test cases analyse results that are queryable through the API. They do
+ * not look at rendering results.
+ *
+ * Adding test stepss:
+ * The general pattern for creating a new test step is to write a test
+ * function of the form:
+ *
+ * static void MyTestStepFunction(SkCanvas* canvas,
+ * skiatest::Reporter* reporter,
+ * CanvasTestStep* testStep)
+ * {
+ * canvas->someCanvasAPImethod();
+ * (...)
+ * REPORTER_ASSERT_MESSAGE(reporter, (...), \
+ * testStep->assertMessage());
+ * }
+ *
+ * The definition of the test step function should be followed by an
+ * invocation of the TEST_STEP macro, which generates a class and
+ * instance for the test step:
+ *
+ * TEST_STEP(MyTestStep, MyTestStepFunction)
+ *
+ * There are also short hand macros for defining simple test steps
+ * in a single line of code. A simple test step is a one that is made
+ * of a single canvas API call.
+ *
+ * SIMPLE_TEST_STEP(MytestStep, someCanvasAPIMethod());
+ *
+ * There is another macro called SIMPLE_TEST_STEP_WITH_ASSERT that
+ * works the same way as SIMPLE_TEST_STEP, and additionally verifies
+ * that the invoked method returns a non-zero value.
+ */
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkDeferredCanvas.h"
+#include "SkDevice.h"
+#include "SkMatrix.h"
+#include "SkNWayCanvas.h"
+#include "SkPDFDevice.h"
+#include "SkPDFDocument.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkPicture.h"
+#include "SkPictureRecord.h"
+#include "SkPictureRecorder.h"
+#include "SkProxyCanvas.h"
+#include "SkRect.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkStream.h"
+#include "SkSurface.h"
+#include "SkTDArray.h"
+#include "Test.h"
+
+static bool equal_clips(const SkCanvas& a, const SkCanvas& b) {
+ if (a.isClipEmpty()) {
+ return b.isClipEmpty();
+ }
+ if (!a.isClipRect()) {
+ // this is liberally true, since we don't expose a way to know this exactly (for non-rects)
+ return !b.isClipRect();
+ }
+ SkIRect ar, br;
+ a.getClipDeviceBounds(&ar);
+ b.getClipDeviceBounds(&br);
+ return ar == br;
+}
+
+class Canvas2CanvasClipVisitor : public SkCanvas::ClipVisitor {
+public:
+ Canvas2CanvasClipVisitor(SkCanvas* target) : fTarget(target) {}
+
+ virtual void clipRect(const SkRect& r, SkRegion::Op op, bool aa) SK_OVERRIDE {
+ fTarget->clipRect(r, op, aa);
+ }
+ virtual void clipRRect(const SkRRect& r, SkRegion::Op op, bool aa) SK_OVERRIDE {
+ fTarget->clipRRect(r, op, aa);
+ }
+ virtual void clipPath(const SkPath& p, SkRegion::Op op, bool aa) SK_OVERRIDE {
+ fTarget->clipPath(p, op, aa);
+ }
+
+private:
+ SkCanvas* fTarget;
+};
+
+static void test_clipVisitor(skiatest::Reporter* reporter, SkCanvas* canvas) {
+ SkISize size = canvas->getDeviceSize();
+
+ SkBitmap bm;
+ bm.setInfo(SkImageInfo::MakeN32Premul(size.width(), size.height()));
+ SkCanvas c(bm);
+
+ Canvas2CanvasClipVisitor visitor(&c);
+ canvas->replayClips(&visitor);
+
+ REPORTER_ASSERT(reporter, equal_clips(c, *canvas));
+}
+
+static const int kWidth = 2;
+static const int kHeight = 2;
+
+// Format strings that describe the test context. The %s token is where
+// the name of the test step is inserted. The context is required for
+// disambiguating the error in the case of failures that are reported in
+// functions that are called multiple times in different contexts (test
+// cases and test steps).
+static const char* const kDefaultAssertMessageFormat = "%s";
+static const char* const kCanvasDrawAssertMessageFormat =
+ "Drawing test step %s with SkCanvas";
+static const char* const kPictureDrawAssertMessageFormat =
+ "Drawing test step %s with SkPicture";
+static const char* const kPictureSecondDrawAssertMessageFormat =
+ "Duplicate draw of test step %s with SkPicture";
+static const char* const kDeferredDrawAssertMessageFormat =
+ "Drawing test step %s with SkDeferredCanvas";
+static const char* const kProxyDrawAssertMessageFormat =
+ "Drawing test step %s with SkProxyCanvas";
+static const char* const kNWayDrawAssertMessageFormat =
+ "Drawing test step %s with SkNWayCanvas";
+static const char* const kDeferredPreFlushAssertMessageFormat =
+ "test step %s, SkDeferredCanvas state consistency before flush";
+static const char* const kDeferredPostFlushPlaybackAssertMessageFormat =
+ "test step %s, SkDeferredCanvas playback canvas state consistency after flush";
+static const char* const kDeferredPostSilentFlushPlaybackAssertMessageFormat =
+ "test step %s, SkDeferredCanvas playback canvas state consistency after silent flush";
+static const char* const kPictureResourceReuseMessageFormat =
+ "test step %s, SkPicture duplicate flattened object test";
+static const char* const kProxyStateAssertMessageFormat =
+ "test step %s, SkProxyCanvas state consistency";
+static const char* const kProxyIndirectStateAssertMessageFormat =
+ "test step %s, SkProxyCanvas indirect canvas state consistency";
+static const char* const kNWayStateAssertMessageFormat =
+ "test step %s, SkNWayCanvas state consistency";
+static const char* const kNWayIndirect1StateAssertMessageFormat =
+ "test step %s, SkNWayCanvas indirect canvas 1 state consistency";
+static const char* const kNWayIndirect2StateAssertMessageFormat =
+ "test step %s, SkNWayCanvas indirect canvas 2 state consistency";
+static const char* const kPdfAssertMessageFormat =
+ "PDF sanity check failed %s";
+
+static void createBitmap(SkBitmap* bm, SkColor color) {
+ bm->allocN32Pixels(kWidth, kHeight);
+ bm->eraseColor(color);
+}
+
+static SkSurface* createSurface(SkColor color) {
+ SkSurface* surface = SkSurface::NewRasterPMColor(kWidth, kHeight);
+ surface->getCanvas()->clear(color);
+ return surface;
+}
+
+class CanvasTestStep;
+static SkTDArray<CanvasTestStep*>& testStepArray() {
+ static SkTDArray<CanvasTestStep*> theTests;
+ return theTests;
+}
+
+class CanvasTestStep {
+public:
+ CanvasTestStep(bool fEnablePdfTesting = true) {
+ *testStepArray().append() = this;
+ fAssertMessageFormat = kDefaultAssertMessageFormat;
+ this->fEnablePdfTesting = fEnablePdfTesting;
+ }
+ virtual ~CanvasTestStep() { }
+
+ virtual void draw(SkCanvas*, skiatest::Reporter*) = 0;
+ virtual const char* name() const = 0;
+
+ const char* assertMessage() {
+ fAssertMessage.printf(fAssertMessageFormat, name());
+ return fAssertMessage.c_str();
+ }
+
+ void setAssertMessageFormat(const char* format) {
+ fAssertMessageFormat = format;
+ }
+
+ bool enablePdfTesting() { return fEnablePdfTesting; }
+
+private:
+ SkString fAssertMessage;
+ const char* fAssertMessageFormat;
+ bool fEnablePdfTesting;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Constants used by test steps
+
+const SkRect kTestRect =
+ SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
+ SkIntToScalar(2), SkIntToScalar(1));
+static SkMatrix testMatrix() {
+ SkMatrix matrix;
+ matrix.reset();
+ matrix.setScale(SkIntToScalar(2), SkIntToScalar(3));
+ return matrix;
+}
+const SkMatrix kTestMatrix = testMatrix();
+static SkPath test_path() {
+ SkPath path;
+ path.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
+ SkIntToScalar(2), SkIntToScalar(1)));
+ return path;
+}
+const SkPath kTestPath = test_path();
+static SkPath test_nearly_zero_length_path() {
+ SkPath path;
+ SkPoint pt1 = { 0, 0 };
+ SkPoint pt2 = { 0, SK_ScalarNearlyZero };
+ SkPoint pt3 = { SkIntToScalar(1), 0 };
+ SkPoint pt4 = { SkIntToScalar(1), SK_ScalarNearlyZero/2 };
+ path.moveTo(pt1);
+ path.lineTo(pt2);
+ path.lineTo(pt3);
+ path.lineTo(pt4);
+ return path;
+}
+const SkPath kNearlyZeroLengthPath = test_nearly_zero_length_path();
+static SkRegion testRegion() {
+ SkRegion region;
+ SkIRect rect = SkIRect::MakeXYWH(0, 0, 2, 1);
+ region.setRect(rect);
+ return region;
+}
+const SkIRect kTestIRect = SkIRect::MakeXYWH(0, 0, 2, 1);
+const SkRegion kTestRegion = testRegion();
+const SkColor kTestColor = 0x01020304;
+const SkPaint kTestPaint;
+const SkPoint kTestPoints[3] = {
+ {SkIntToScalar(0), SkIntToScalar(0)},
+ {SkIntToScalar(2), SkIntToScalar(1)},
+ {SkIntToScalar(0), SkIntToScalar(2)}
+};
+const size_t kTestPointCount = 3;
+static SkBitmap testBitmap() {
+ SkBitmap bitmap;
+ createBitmap(&bitmap, 0x05060708);
+ return bitmap;
+}
+SkBitmap kTestBitmap; // cannot be created during static init
+SkString kTestText("Hello World");
+SkPoint kTestPoints2[] = {
+ { SkIntToScalar(0), SkIntToScalar(1) },
+ { SkIntToScalar(1), SkIntToScalar(1) },
+ { SkIntToScalar(2), SkIntToScalar(1) },
+ { SkIntToScalar(3), SkIntToScalar(1) },
+ { SkIntToScalar(4), SkIntToScalar(1) },
+ { SkIntToScalar(5), SkIntToScalar(1) },
+ { SkIntToScalar(6), SkIntToScalar(1) },
+ { SkIntToScalar(7), SkIntToScalar(1) },
+ { SkIntToScalar(8), SkIntToScalar(1) },
+ { SkIntToScalar(9), SkIntToScalar(1) },
+ { SkIntToScalar(10), SkIntToScalar(1) },
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Macros for defining test steps
+
+#define TEST_STEP(NAME, FUNCTION) \
+class NAME##_TestStep : public CanvasTestStep{ \
+public: \
+ virtual void draw(SkCanvas* canvas, skiatest::Reporter* reporter) { \
+ FUNCTION (canvas, reporter, this); \
+ } \
+ virtual const char* name() const {return #NAME ;} \
+}; \
+static NAME##_TestStep NAME##_TestStepInstance;
+
+#define TEST_STEP_NO_PDF(NAME, FUNCTION) \
+class NAME##_TestStep : public CanvasTestStep{ \
+public: \
+ NAME##_TestStep() : CanvasTestStep(false) {} \
+ virtual void draw(SkCanvas* canvas, skiatest::Reporter* reporter) { \
+ FUNCTION (canvas, reporter, this); \
+ } \
+ virtual const char* name() const {return #NAME ;} \
+}; \
+static NAME##_TestStep NAME##_TestStepInstance;
+
+#define SIMPLE_TEST_STEP(NAME, CALL) \
+static void NAME##TestStep(SkCanvas* canvas, skiatest::Reporter*, \
+ CanvasTestStep*) { \
+ canvas-> CALL ; \
+} \
+TEST_STEP(NAME, NAME##TestStep )
+
+#define SIMPLE_TEST_STEP_WITH_ASSERT(NAME, CALL) \
+static void NAME##TestStep(SkCanvas* canvas, skiatest::Reporter* reporter, \
+ CanvasTestStep* testStep) { \
+ REPORTER_ASSERT_MESSAGE(reporter, canvas-> CALL , \
+ testStep->assertMessage()); \
+} \
+TEST_STEP(NAME, NAME##TestStep )
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Basic test steps for most virtual methods in SkCanvas that draw or affect
+// the state of the canvas.
+
+SIMPLE_TEST_STEP(Translate, translate(SkIntToScalar(1), SkIntToScalar(2)));
+SIMPLE_TEST_STEP(Scale, scale(SkIntToScalar(1), SkIntToScalar(2)));
+SIMPLE_TEST_STEP(Rotate, rotate(SkIntToScalar(1)));
+SIMPLE_TEST_STEP(Skew, skew(SkIntToScalar(1), SkIntToScalar(2)));
+SIMPLE_TEST_STEP(Concat, concat(kTestMatrix));
+SIMPLE_TEST_STEP(SetMatrix, setMatrix(kTestMatrix));
+SIMPLE_TEST_STEP(ClipRect, clipRect(kTestRect));
+SIMPLE_TEST_STEP(ClipPath, clipPath(kTestPath));
+SIMPLE_TEST_STEP(ClipRegion,
+ clipRegion(kTestRegion, SkRegion::kReplace_Op));
+SIMPLE_TEST_STEP(Clear, clear(kTestColor));
+SIMPLE_TEST_STEP(DrawPaint, drawPaint(kTestPaint));
+SIMPLE_TEST_STEP(DrawPointsPoints, drawPoints(SkCanvas::kPoints_PointMode,
+ kTestPointCount, kTestPoints, kTestPaint));
+SIMPLE_TEST_STEP(DrawPointsLiness, drawPoints(SkCanvas::kLines_PointMode,
+ kTestPointCount, kTestPoints, kTestPaint));
+SIMPLE_TEST_STEP(DrawPointsPolygon, drawPoints(SkCanvas::kPolygon_PointMode,
+ kTestPointCount, kTestPoints, kTestPaint));
+SIMPLE_TEST_STEP(DrawRect, drawRect(kTestRect, kTestPaint));
+SIMPLE_TEST_STEP(DrawPath, drawPath(kTestPath, kTestPaint));
+SIMPLE_TEST_STEP(DrawBitmap, drawBitmap(kTestBitmap, 0, 0));
+SIMPLE_TEST_STEP(DrawBitmapPaint, drawBitmap(kTestBitmap, 0, 0, &kTestPaint));
+SIMPLE_TEST_STEP(DrawBitmapRect, drawBitmapRect(kTestBitmap, NULL, kTestRect,
+ NULL));
+SIMPLE_TEST_STEP(DrawBitmapRectSrcRect, drawBitmapRect(kTestBitmap,
+ &kTestIRect, kTestRect, NULL));
+SIMPLE_TEST_STEP(DrawBitmapRectPaint, drawBitmapRect(kTestBitmap, NULL,
+ kTestRect, &kTestPaint));
+SIMPLE_TEST_STEP(DrawBitmapMatrix, drawBitmapMatrix(kTestBitmap, kTestMatrix,
+ NULL));
+SIMPLE_TEST_STEP(DrawBitmapMatrixPaint, drawBitmapMatrix(kTestBitmap,
+ kTestMatrix, &kTestPaint));
+SIMPLE_TEST_STEP(DrawBitmapNine, drawBitmapNine(kTestBitmap, kTestIRect,
+ kTestRect, NULL));
+SIMPLE_TEST_STEP(DrawBitmapNinePaint, drawBitmapNine(kTestBitmap, kTestIRect,
+ kTestRect, &kTestPaint));
+SIMPLE_TEST_STEP(DrawSprite, drawSprite(kTestBitmap, 0, 0, NULL));
+SIMPLE_TEST_STEP(DrawSpritePaint, drawSprite(kTestBitmap, 0, 0, &kTestPaint));
+SIMPLE_TEST_STEP(DrawText, drawText(kTestText.c_str(), kTestText.size(),
+ 0, 1, kTestPaint));
+SIMPLE_TEST_STEP(DrawPosText, drawPosText(kTestText.c_str(),
+ kTestText.size(), kTestPoints2, kTestPaint));
+SIMPLE_TEST_STEP(DrawTextOnPath, drawTextOnPath(kTestText.c_str(),
+ kTestText.size(), kTestPath, NULL, kTestPaint));
+SIMPLE_TEST_STEP(DrawTextOnPathMatrix, drawTextOnPath(kTestText.c_str(),
+ kTestText.size(), kTestPath, &kTestMatrix, kTestPaint));
+SIMPLE_TEST_STEP(DrawData, drawData(kTestText.c_str(), kTestText.size()));
+SIMPLE_TEST_STEP(BeginGroup, beginCommentGroup(kTestText.c_str()));
+SIMPLE_TEST_STEP(AddComment, addComment(kTestText.c_str(), kTestText.c_str()));
+SIMPLE_TEST_STEP(EndGroup, endCommentGroup());
+
+///////////////////////////////////////////////////////////////////////////////
+// Complex test steps
+
+static void SaveMatrixClipStep(SkCanvas* canvas,
+ skiatest::Reporter* reporter,
+ CanvasTestStep* testStep) {
+ int saveCount = canvas->getSaveCount();
+ canvas->save();
+ canvas->translate(SkIntToScalar(1), SkIntToScalar(2));
+ canvas->clipRegion(kTestRegion);
+ canvas->restore();
+ REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
+ testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, canvas->getTotalMatrix().isIdentity(),
+ testStep->assertMessage());
+// REPORTER_ASSERT_MESSAGE(reporter, canvas->getTotalClip() != kTestRegion, testStep->assertMessage());
+}
+TEST_STEP(SaveMatrixClip, SaveMatrixClipStep);
+
+static void SaveLayerStep(SkCanvas* canvas,
+ skiatest::Reporter* reporter,
+ CanvasTestStep* testStep) {
+ int saveCount = canvas->getSaveCount();
+ canvas->saveLayer(NULL, NULL);
+ canvas->restore();
+ REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
+ testStep->assertMessage());
+}
+TEST_STEP(SaveLayer, SaveLayerStep);
+
+static void BoundedSaveLayerStep(SkCanvas* canvas,
+ skiatest::Reporter* reporter,
+ CanvasTestStep* testStep) {
+ int saveCount = canvas->getSaveCount();
+ canvas->saveLayer(&kTestRect, NULL);
+ canvas->restore();
+ REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
+ testStep->assertMessage());
+}
+TEST_STEP(BoundedSaveLayer, BoundedSaveLayerStep);
+
+static void PaintSaveLayerStep(SkCanvas* canvas,
+ skiatest::Reporter* reporter,
+ CanvasTestStep* testStep) {
+ int saveCount = canvas->getSaveCount();
+ canvas->saveLayer(NULL, &kTestPaint);
+ canvas->restore();
+ REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
+ testStep->assertMessage());
+}
+TEST_STEP(PaintSaveLayer, PaintSaveLayerStep);
+
+static void TwoClipOpsStep(SkCanvas* canvas,
+ skiatest::Reporter*,
+ CanvasTestStep*) {
+ // This test exercises a functionality in SkPicture that leads to the
+ // recording of restore offset placeholders. This test will trigger an
+ // assertion at playback time if the placeholders are not properly
+ // filled when the recording ends.
+ canvas->clipRect(kTestRect);
+ canvas->clipRegion(kTestRegion);
+}
+TEST_STEP(TwoClipOps, TwoClipOpsStep);
+
+// exercise fix for http://code.google.com/p/skia/issues/detail?id=560
+// ('SkPathStroker::lineTo() fails for line with length SK_ScalarNearlyZero')
+static void DrawNearlyZeroLengthPathTestStep(SkCanvas* canvas,
+ skiatest::Reporter*,
+ CanvasTestStep*) {
+ SkPaint paint;
+ paint.setStrokeWidth(SkIntToScalar(1));
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawPath(kNearlyZeroLengthPath, paint);
+}
+TEST_STEP(DrawNearlyZeroLengthPath, DrawNearlyZeroLengthPathTestStep);
+
+static void DrawVerticesShaderTestStep(SkCanvas* canvas,
+ skiatest::Reporter*,
+ CanvasTestStep*) {
+ SkPoint pts[4];
+ pts[0].set(0, 0);
+ pts[1].set(SkIntToScalar(kWidth), 0);
+ pts[2].set(SkIntToScalar(kWidth), SkIntToScalar(kHeight));
+ pts[3].set(0, SkIntToScalar(kHeight));
+ SkPaint paint;
+ SkShader* shader = SkShader::CreateBitmapShader(kTestBitmap,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ paint.setShader(shader)->unref();
+ canvas->drawVertices(SkCanvas::kTriangleFan_VertexMode, 4, pts, pts,
+ NULL, NULL, NULL, 0, paint);
+}
+// NYI: issue 240.
+TEST_STEP_NO_PDF(DrawVerticesShader, DrawVerticesShaderTestStep);
+
+static void DrawPictureTestStep(SkCanvas* canvas,
+ skiatest::Reporter*,
+ CanvasTestStep*) {
+ SkPictureRecorder recorder;
+ SkCanvas* testCanvas = recorder.beginRecording(SkIntToScalar(kWidth), SkIntToScalar(kHeight),
+ NULL, 0);
+ testCanvas->scale(SkIntToScalar(2), SkIntToScalar(1));
+ testCanvas->clipRect(kTestRect);
+ testCanvas->drawRect(kTestRect, kTestPaint);
+ SkAutoTUnref<SkPicture> testPicture(recorder.endRecording());
+
+ canvas->drawPicture(testPicture);
+}
+TEST_STEP(DrawPicture, DrawPictureTestStep);
+
+static void SaveRestoreTestStep(SkCanvas* canvas,
+ skiatest::Reporter* reporter,
+ CanvasTestStep* testStep) {
+ int baseSaveCount = canvas->getSaveCount();
+ int n = canvas->save();
+ REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount == n, testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 1 == canvas->getSaveCount(),
+ testStep->assertMessage());
+ canvas->save();
+ canvas->save();
+ REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 3 == canvas->getSaveCount(),
+ testStep->assertMessage());
+ canvas->restoreToCount(baseSaveCount + 1);
+ REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 1 == canvas->getSaveCount(),
+ testStep->assertMessage());
+
+ // should this pin to 1, or be a no-op, or crash?
+ canvas->restoreToCount(0);
+ REPORTER_ASSERT_MESSAGE(reporter, 1 == canvas->getSaveCount(),
+ testStep->assertMessage());
+}
+TEST_STEP(SaveRestore, SaveRestoreTestStep);
+
+static void DrawLayerTestStep(SkCanvas* canvas,
+ skiatest::Reporter* reporter,
+ CanvasTestStep* testStep) {
+ REPORTER_ASSERT_MESSAGE(reporter, !canvas->isDrawingToLayer(),
+ testStep->assertMessage());
+ canvas->save();
+ REPORTER_ASSERT_MESSAGE(reporter, !canvas->isDrawingToLayer(),
+ testStep->assertMessage());
+ canvas->restore();
+
+ const SkRect* bounds = NULL; // null means include entire bounds
+ const SkPaint* paint = NULL;
+
+ canvas->saveLayer(bounds, paint);
+ REPORTER_ASSERT_MESSAGE(reporter, canvas->isDrawingToLayer(),
+ testStep->assertMessage());
+ canvas->restore();
+ REPORTER_ASSERT_MESSAGE(reporter, !canvas->isDrawingToLayer(),
+ testStep->assertMessage());
+
+ canvas->saveLayer(bounds, paint);
+ canvas->saveLayer(bounds, paint);
+ REPORTER_ASSERT_MESSAGE(reporter, canvas->isDrawingToLayer(),
+ testStep->assertMessage());
+ canvas->restore();
+ REPORTER_ASSERT_MESSAGE(reporter, canvas->isDrawingToLayer(),
+ testStep->assertMessage());
+ canvas->restore();
+ // now layer count should be 0
+ REPORTER_ASSERT_MESSAGE(reporter, !canvas->isDrawingToLayer(),
+ testStep->assertMessage());
+}
+TEST_STEP(DrawLayer, DrawLayerTestStep);
+
+static void NestedSaveRestoreWithSolidPaintTestStep(SkCanvas* canvas,
+ skiatest::Reporter*,
+ CanvasTestStep*) {
+ // This test step challenges the TestDeferredCanvasStateConsistency
+ // test cases because the opaque paint can trigger an optimization
+ // that discards previously recorded commands. The challenge is to maintain
+ // correct clip and matrix stack state.
+ canvas->resetMatrix();
+ canvas->rotate(SkIntToScalar(30));
+ canvas->save();
+ canvas->translate(SkIntToScalar(2), SkIntToScalar(1));
+ canvas->save();
+ canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
+ SkPaint paint;
+ paint.setColor(0xFFFFFFFF);
+ canvas->drawPaint(paint);
+ canvas->restore();
+ canvas->restore();
+}
+TEST_STEP(NestedSaveRestoreWithSolidPaint, \
+ NestedSaveRestoreWithSolidPaintTestStep);
+
+static void NestedSaveRestoreWithFlushTestStep(SkCanvas* canvas,
+ skiatest::Reporter*,
+ CanvasTestStep*) {
+ // This test step challenges the TestDeferredCanvasStateConsistency
+ // test case because the canvas flush on a deferred canvas will
+ // reset the recording session. The challenge is to maintain correct
+ // clip and matrix stack state on the playback canvas.
+ canvas->resetMatrix();
+ canvas->rotate(SkIntToScalar(30));
+ canvas->save();
+ canvas->translate(SkIntToScalar(2), SkIntToScalar(1));
+ canvas->save();
+ canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
+ canvas->drawRect(kTestRect,kTestPaint);
+ canvas->flush();
+ canvas->restore();
+ canvas->restore();
+}
+TEST_STEP(NestedSaveRestoreWithFlush, \
+ NestedSaveRestoreWithFlushTestStep);
+
+static void AssertCanvasStatesEqual(skiatest::Reporter* reporter,
+ const SkCanvas* canvas1,
+ const SkCanvas* canvas2,
+ CanvasTestStep* testStep) {
+ REPORTER_ASSERT_MESSAGE(reporter, canvas1->getDeviceSize() ==
+ canvas2->getDeviceSize(), testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, canvas1->getSaveCount() ==
+ canvas2->getSaveCount(), testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, canvas1->isDrawingToLayer() ==
+ canvas2->isDrawingToLayer(), testStep->assertMessage());
+
+ SkRect bounds1, bounds2;
+ REPORTER_ASSERT_MESSAGE(reporter,
+ canvas1->getClipBounds(&bounds1) == canvas2->getClipBounds(&bounds2),
+ testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, bounds1 == bounds2,
+ testStep->assertMessage());
+
+ REPORTER_ASSERT_MESSAGE(reporter, canvas1->getDrawFilter() ==
+ canvas2->getDrawFilter(), testStep->assertMessage());
+ SkIRect deviceBounds1, deviceBounds2;
+ REPORTER_ASSERT_MESSAGE(reporter,
+ canvas1->getClipDeviceBounds(&deviceBounds1) ==
+ canvas2->getClipDeviceBounds(&deviceBounds2),
+ testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, deviceBounds1 == deviceBounds2, testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, canvas1->getTotalMatrix() ==
+ canvas2->getTotalMatrix(), testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, equal_clips(*canvas1, *canvas2), testStep->assertMessage());
+
+ // The following test code is commented out because the test fails when
+ // the canvas is an SkPictureRecord or SkDeferredCanvas
+ // Issue: http://code.google.com/p/skia/issues/detail?id=498
+ // Also, creating a LayerIter on an SkProxyCanvas crashes
+ // Issue: http://code.google.com/p/skia/issues/detail?id=499
+ /*
+ SkCanvas::LayerIter layerIter1(const_cast<SkCanvas*>(canvas1), false);
+ SkCanvas::LayerIter layerIter2(const_cast<SkCanvas*>(canvas2), false);
+ while (!layerIter1.done() && !layerIter2.done()) {
+ REPORTER_ASSERT_MESSAGE(reporter, layerIter1.matrix() ==
+ layerIter2.matrix(), testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, layerIter1.clip() ==
+ layerIter2.clip(), testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, layerIter1.paint() ==
+ layerIter2.paint(), testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, layerIter1.x() ==
+ layerIter2.x(), testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, layerIter1.y() ==
+ layerIter2.y(), testStep->assertMessage());
+ layerIter1.next();
+ layerIter2.next();
+ }
+ REPORTER_ASSERT_MESSAGE(reporter, layerIter1.done(),
+ testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter, layerIter2.done(),
+ testStep->assertMessage());
+ */
+}
+
+// The following class groups static functions that need to access
+// the privates members of SkPictureRecord
+class SkPictureTester {
+private:
+ static int EQ(const SkFlatData* a, const SkFlatData* b) {
+ return *a == *b;
+ }
+
+ static void AssertFlattenedObjectsEqual(
+ SkPictureRecord* referenceRecord,
+ SkPictureRecord* testRecord,
+ skiatest::Reporter* reporter,
+ CanvasTestStep* testStep) {
+
+ REPORTER_ASSERT_MESSAGE(reporter,
+ referenceRecord->fBitmapHeap->count() ==
+ testRecord->fBitmapHeap->count(), testStep->assertMessage());
+ REPORTER_ASSERT_MESSAGE(reporter,
+ referenceRecord->fPaints.count() ==
+ testRecord->fPaints.count(), testStep->assertMessage());
+ for (int i = 0; i < referenceRecord->fPaints.count(); ++i) {
+ REPORTER_ASSERT_MESSAGE(reporter,
+ EQ(referenceRecord->fPaints[i], testRecord->fPaints[i]),
+ testStep->assertMessage());
+ }
+ REPORTER_ASSERT_MESSAGE(reporter,
+ !referenceRecord->fPathHeap == !testRecord->fPathHeap,
+ testStep->assertMessage());
+ // The following tests are commented out because they currently
+ // fail. Issue: http://code.google.com/p/skia/issues/detail?id=507
+ /*
+ if (referenceRecord->fPathHeap) {
+ REPORTER_ASSERT_MESSAGE(reporter,
+ referenceRecord->fPathHeap->count() ==
+ testRecord->fPathHeap->count(),
+ testStep->assertMessage());
+ for (int i = 0; i < referenceRecord->fPathHeap->count(); ++i) {
+ REPORTER_ASSERT_MESSAGE(reporter,
+ (*referenceRecord->fPathHeap)[i] ==
+ (*testRecord->fPathHeap)[i], testStep->assertMessage());
+ }
+ }
+ */
+
+ }
+
+public:
+
+ static void TestPictureFlattenedObjectReuse(skiatest::Reporter* reporter,
+ CanvasTestStep* testStep,
+ uint32_t recordFlags) {
+ // Verify that when a test step is executed twice, no extra resources
+ // are flattened during the second execution
+ testStep->setAssertMessageFormat(kPictureDrawAssertMessageFormat);
+ SkPictureRecorder referenceRecorder;
+ SkCanvas* referenceCanvas =
+ referenceRecorder.DEPRECATED_beginRecording(SkIntToScalar(kWidth),
+ SkIntToScalar(kHeight),
+ NULL, recordFlags);
+ testStep->draw(referenceCanvas, reporter);
+
+ SkPictureRecorder testRecorder;
+ SkCanvas* testCanvas =
+ testRecorder.DEPRECATED_beginRecording(SkIntToScalar(kWidth),
+ SkIntToScalar(kHeight),
+ NULL, recordFlags);
+ testStep->draw(testCanvas, reporter);
+ testStep->setAssertMessageFormat(kPictureSecondDrawAssertMessageFormat);
+ testStep->draw(testCanvas, reporter);
+
+ SkPictureRecord* referenceRecord = static_cast<SkPictureRecord*>(referenceCanvas);
+ SkPictureRecord* testRecord = static_cast<SkPictureRecord*>(testCanvas);
+ testStep->setAssertMessageFormat(kPictureResourceReuseMessageFormat);
+ AssertFlattenedObjectsEqual(referenceRecord, testRecord,
+ reporter, testStep);
+ }
+};
+
+static void TestPdfDevice(skiatest::Reporter* reporter,
+ CanvasTestStep* testStep) {
+ SkISize pageSize = SkISize::Make(kWidth, kHeight);
+ SkPDFDevice device(pageSize, pageSize, SkMatrix::I());
+ SkCanvas canvas(&device);
+ testStep->setAssertMessageFormat(kPdfAssertMessageFormat);
+ testStep->draw(&canvas, reporter);
+ SkPDFDocument doc;
+ doc.appendPage(&device);
+ SkDynamicMemoryWStream stream;
+ doc.emitPDF(&stream);
+}
+
+// The following class groups static functions that need to access
+// the privates members of SkDeferredCanvas
+class SkDeferredCanvasTester {
+public:
+ static void TestDeferredCanvasStateConsistency(
+ skiatest::Reporter* reporter,
+ CanvasTestStep* testStep,
+ const SkCanvas& referenceCanvas, bool silent) {
+
+ SkAutoTUnref<SkSurface> surface(createSurface(0xFFFFFFFF));
+ SkAutoTUnref<SkDeferredCanvas> deferredCanvas(SkDeferredCanvas::Create(surface.get()));
+
+ testStep->setAssertMessageFormat(kDeferredDrawAssertMessageFormat);
+ testStep->draw(deferredCanvas, reporter);
+ testStep->setAssertMessageFormat(kDeferredPreFlushAssertMessageFormat);
+ AssertCanvasStatesEqual(reporter, deferredCanvas, &referenceCanvas,
+ testStep);
+
+ if (silent) {
+ deferredCanvas->silentFlush();
+ } else {
+ deferredCanvas->flush();
+ }
+
+ testStep->setAssertMessageFormat(
+ silent ? kDeferredPostSilentFlushPlaybackAssertMessageFormat :
+ kDeferredPostFlushPlaybackAssertMessageFormat);
+ AssertCanvasStatesEqual(reporter,
+ deferredCanvas->immediateCanvas(),
+ &referenceCanvas, testStep);
+
+ // Verified that deferred canvas state is not affected by flushing
+ // pending draw operations
+
+ // The following test code is commented out because it currently fails.
+ // Issue: http://code.google.com/p/skia/issues/detail?id=496
+ /*
+ testStep->setAssertMessageFormat(kDeferredPostFlushAssertMessageFormat);
+ AssertCanvasStatesEqual(reporter, &deferredCanvas, &referenceCanvas,
+ testStep);
+ */
+ }
+};
+
+// unused
+static void TestProxyCanvasStateConsistency(
+ skiatest::Reporter* reporter,
+ CanvasTestStep* testStep,
+ const SkCanvas& referenceCanvas) {
+
+ SkBitmap indirectStore;
+ createBitmap(&indirectStore, 0xFFFFFFFF);
+ SkCanvas indirectCanvas(indirectStore);
+ SkProxyCanvas proxyCanvas(&indirectCanvas);
+ testStep->setAssertMessageFormat(kProxyDrawAssertMessageFormat);
+ testStep->draw(&proxyCanvas, reporter);
+ // Verify that the SkProxyCanvas reports consitent state
+ testStep->setAssertMessageFormat(kProxyStateAssertMessageFormat);
+ AssertCanvasStatesEqual(reporter, &proxyCanvas, &referenceCanvas,
+ testStep);
+ // Verify that the indirect canvas reports consitent state
+ testStep->setAssertMessageFormat(kProxyIndirectStateAssertMessageFormat);
+ AssertCanvasStatesEqual(reporter, &indirectCanvas, &referenceCanvas,
+ testStep);
+}
+
+// unused
+static void TestNWayCanvasStateConsistency(
+ skiatest::Reporter* reporter,
+ CanvasTestStep* testStep,
+ const SkCanvas& referenceCanvas) {
+
+ SkBitmap indirectStore1;
+ createBitmap(&indirectStore1, 0xFFFFFFFF);
+ SkCanvas indirectCanvas1(indirectStore1);
+
+ SkBitmap indirectStore2;
+ createBitmap(&indirectStore2, 0xFFFFFFFF);
+ SkCanvas indirectCanvas2(indirectStore2);
+
+ SkISize canvasSize = referenceCanvas.getDeviceSize();
+ SkNWayCanvas nWayCanvas(canvasSize.width(), canvasSize.height());
+ nWayCanvas.addCanvas(&indirectCanvas1);
+ nWayCanvas.addCanvas(&indirectCanvas2);
+
+ testStep->setAssertMessageFormat(kNWayDrawAssertMessageFormat);
+ testStep->draw(&nWayCanvas, reporter);
+ // Verify that the SkProxyCanvas reports consitent state
+ testStep->setAssertMessageFormat(kNWayStateAssertMessageFormat);
+ AssertCanvasStatesEqual(reporter, &nWayCanvas, &referenceCanvas,
+ testStep);
+ // Verify that the indirect canvases report consitent state
+ testStep->setAssertMessageFormat(kNWayIndirect1StateAssertMessageFormat);
+ AssertCanvasStatesEqual(reporter, &indirectCanvas1, &referenceCanvas,
+ testStep);
+ testStep->setAssertMessageFormat(kNWayIndirect2StateAssertMessageFormat);
+ AssertCanvasStatesEqual(reporter, &indirectCanvas2, &referenceCanvas,
+ testStep);
+}
+
+/*
+ * This sub-test verifies that the test step passes when executed
+ * with SkCanvas and with classes derrived from SkCanvas. It also verifies
+ * that the all canvas derivatives report the same state as an SkCanvas
+ * after having executed the test step.
+ */
+static void TestOverrideStateConsistency(skiatest::Reporter* reporter,
+ CanvasTestStep* testStep) {
+ SkBitmap referenceStore;
+ createBitmap(&referenceStore, 0xFFFFFFFF);
+ SkCanvas referenceCanvas(referenceStore);
+ testStep->setAssertMessageFormat(kCanvasDrawAssertMessageFormat);
+ testStep->draw(&referenceCanvas, reporter);
+
+ SkDeferredCanvasTester::TestDeferredCanvasStateConsistency(reporter, testStep, referenceCanvas, false);
+
+ SkDeferredCanvasTester::TestDeferredCanvasStateConsistency(reporter, testStep, referenceCanvas, true);
+
+ // The following test code is disabled because SkProxyCanvas is
+ // missing a lot of virtual overrides on get* methods, which are used
+ // to verify canvas state.
+ // Issue: http://code.google.com/p/skia/issues/detail?id=500
+
+ if (false) { // avoid bit rot, suppress warning
+ TestProxyCanvasStateConsistency(reporter, testStep, referenceCanvas);
+ }
+
+ // The following test code is disabled because SkNWayCanvas does not
+ // report correct clipping and device bounds information
+ // Issue: http://code.google.com/p/skia/issues/detail?id=501
+
+ if (false) { // avoid bit rot, suppress warning
+ TestNWayCanvasStateConsistency(reporter, testStep, referenceCanvas);
+ }
+
+ if (false) { // avoid bit rot, suppress warning
+ test_clipVisitor(reporter, &referenceCanvas);
+ }
+}
+
+static void test_newraster(skiatest::Reporter* reporter) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
+ SkCanvas* canvas = SkCanvas::NewRaster(info);
+ REPORTER_ASSERT(reporter, canvas);
+
+ SkImageInfo info2;
+ size_t rowBytes;
+ const SkPMColor* addr = (const SkPMColor*)canvas->peekPixels(&info2, &rowBytes);
+ REPORTER_ASSERT(reporter, addr);
+ REPORTER_ASSERT(reporter, info == info2);
+ for (int y = 0; y < info.height(); ++y) {
+ for (int x = 0; x < info.width(); ++x) {
+ REPORTER_ASSERT(reporter, 0 == addr[x]);
+ }
+ addr = (const SkPMColor*)((const char*)addr + rowBytes);
+ }
+ SkDELETE(canvas);
+
+ // now try a deliberately bad info
+ info = info.makeWH(-1, info.height());
+ REPORTER_ASSERT(reporter, NULL == SkCanvas::NewRaster(info));
+
+ // too big
+ info = info.makeWH(1 << 30, 1 << 30);
+ REPORTER_ASSERT(reporter, NULL == SkCanvas::NewRaster(info));
+
+ // not a valid pixel type
+ info = SkImageInfo::Make(10, 10, kUnknown_SkColorType, info.alphaType());
+ REPORTER_ASSERT(reporter, NULL == SkCanvas::NewRaster(info));
+
+ // We should succeed with a zero-sized valid info
+ info = SkImageInfo::MakeN32Premul(0, 0);
+ canvas = SkCanvas::NewRaster(info);
+ REPORTER_ASSERT(reporter, canvas);
+ SkDELETE(canvas);
+}
+
+DEF_TEST(Canvas, reporter) {
+ // Init global here because bitmap pixels cannot be alocated during
+ // static initialization
+ kTestBitmap = testBitmap();
+
+ for (int testStep = 0; testStep < testStepArray().count(); testStep++) {
+ TestOverrideStateConsistency(reporter, testStepArray()[testStep]);
+ SkPictureTester::TestPictureFlattenedObjectReuse(reporter,
+ testStepArray()[testStep], 0);
+ if (testStepArray()[testStep]->enablePdfTesting()) {
+ TestPdfDevice(reporter, testStepArray()[testStep]);
+ }
+ }
+
+ // Explicitly call reset(), so we don't leak the pixels (since kTestBitmap is a global)
+ kTestBitmap.reset();
+
+ test_newraster(reporter);
+}
diff --git a/src/third_party/skia/tests/ChecksumTest.cpp b/src/third_party/skia/tests/ChecksumTest.cpp
new file mode 100644
index 0000000..6248678
--- /dev/null
+++ b/src/third_party/skia/tests/ChecksumTest.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkChecksum.h"
+#include "SkRandom.h"
+#include "Test.h"
+
+
+// Murmur3 has an optional third seed argument, so we wrap it to fit a uniform type.
+static uint32_t murmur_noseed(const uint32_t* d, size_t l) { return SkChecksum::Murmur3(d, l); }
+
+#define ASSERT(x) REPORTER_ASSERT(r, x)
+
+DEF_TEST(Checksum, r) {
+ // Algorithms to test. They're currently all uint32_t(const uint32_t*, size_t).
+ typedef uint32_t(*algorithmProc)(const uint32_t*, size_t);
+ const algorithmProc kAlgorithms[] = { &SkChecksum::Compute, &murmur_noseed };
+
+ // Put 128 random bytes into two identical buffers. Any multiple of 4 will do.
+ const size_t kBytes = SkAlign4(128);
+ SkRandom rand;
+ uint32_t data[kBytes/4], tweaked[kBytes/4];
+ for (size_t i = 0; i < SK_ARRAY_COUNT(tweaked); ++i) {
+ data[i] = tweaked[i] = rand.nextU();
+ }
+
+ // Test each algorithm.
+ for (size_t i = 0; i < SK_ARRAY_COUNT(kAlgorithms); ++i) {
+ const algorithmProc algorithm = kAlgorithms[i];
+
+ // Hash of NULL is always 0.
+ ASSERT(algorithm(NULL, 0) == 0);
+
+ const uint32_t hash = algorithm(data, kBytes);
+ // Should be deterministic.
+ ASSERT(hash == algorithm(data, kBytes));
+
+ // Changing any single element should change the hash.
+ for (size_t j = 0; j < SK_ARRAY_COUNT(tweaked); ++j) {
+ const uint32_t saved = tweaked[j];
+ tweaked[j] = rand.nextU();
+ const uint32_t tweakedHash = algorithm(tweaked, kBytes);
+ ASSERT(tweakedHash != hash);
+ ASSERT(tweakedHash == algorithm(tweaked, kBytes));
+ tweaked[j] = saved;
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/ClampRangeTest.cpp b/src/third_party/skia/tests/ClampRangeTest.cpp
new file mode 100644
index 0000000..bf7c95f
--- /dev/null
+++ b/src/third_party/skia/tests/ClampRangeTest.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRandom.h"
+#include "Test.h"
+#include "gradients/SkClampRange.h"
+
+static skiatest::Reporter* gReporter;
+#define R_ASSERT(cond) if (!(cond)) { \
+ SkDebugf("%d: %s\n", __LINE__, #cond); \
+ REPORTER_ASSERT(gReporter, cond); \
+}
+
+// Arbitrary sentinel values outside [0, 0xFFFF].
+static const int kV0 = -42, kV1 = -53, kRamp = -64;
+
+static void check_value(int64_t bigfx, int expected) {
+ if (bigfx < 0) {
+ R_ASSERT(expected == kV0);
+ } else if (bigfx > 0xFFFF) {
+ R_ASSERT(expected == kV1);
+ } else if (bigfx == 0xFFFF) {
+ // Either one is fine (and we do see both).
+ R_ASSERT(expected == kV1 || expected == kRamp);
+ } else {
+ R_ASSERT(expected == kRamp);
+ }
+}
+
+static void slow_check(const SkClampRange& range,
+ const SkFixed fx, SkFixed dx, int count) {
+ SkASSERT(range.fCount0 + range.fCount1 + range.fCount2 == count);
+
+ // If dx is large, fx will overflow if updated naively. So we use more bits.
+ int64_t bigfx = fx;
+
+ for (int i = 0; i < range.fCount0; i++) {
+ check_value(bigfx, range.fV0);
+ bigfx += dx;
+ }
+
+ for (int i = 0; i < range.fCount1; i++) {
+ check_value(bigfx, kRamp);
+ bigfx += dx;
+ }
+
+ for (int i = 0; i < range.fCount2; i++) {
+ check_value(bigfx, range.fV1);
+ bigfx += dx;
+ }
+}
+
+
+static void test_range(SkFixed fx, SkFixed dx, int count) {
+ SkClampRange range;
+ range.init(fx, dx, count, kV0, kV1);
+ slow_check(range, fx, dx, count);
+}
+
+#define ff(x) SkIntToFixed(x)
+
+DEF_TEST(ClampRange, reporter) {
+ gReporter = reporter;
+
+ test_range(0, 0, 20);
+ test_range(0xFFFF, 0, 20);
+ test_range(-ff(2), 0, 20);
+ test_range( ff(2), 0, 20);
+
+ test_range(-10, 1, 20);
+ test_range(10, -1, 20);
+ test_range(-10, 3, 20);
+ test_range(10, -3, 20);
+
+ test_range(ff(1), ff(16384), 100);
+ test_range(ff(-1), ff(-16384), 100);
+ test_range(ff(1)/2, ff(16384), 100);
+ // TODO(reed): skia:2481, fix whatever bug this is, then uncomment
+ //test_range(ff(1)/2, ff(-16384), 100);
+
+ SkRandom rand;
+
+ // test non-overflow cases
+ for (int i = 0; i < 1000000; i++) {
+ SkFixed fx = rand.nextS() >> 1;
+ SkFixed sx = rand.nextS() >> 1;
+ int count = rand.nextU() % 1000 + 1;
+ SkFixed dx = (sx - fx) / count;
+ test_range(fx, dx, count);
+ }
+
+ // TODO(reed): skia:2481, fix whatever bug this is, then uncomment
+ /*
+ // test overflow cases
+ for (int i = 0; i < 100000; i++) {
+ SkFixed fx = rand.nextS();
+ SkFixed dx = rand.nextS();
+ int count = rand.nextU() % 1000 + 1;
+ test_range(fx, dx, count);
+ }
+ */
+}
diff --git a/src/third_party/skia/tests/ClipCacheTest.cpp b/src/third_party/skia/tests/ClipCacheTest.cpp
new file mode 100644
index 0000000..d9f3b57
--- /dev/null
+++ b/src/third_party/skia/tests/ClipCacheTest.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+// This is a GR test
+#if SK_SUPPORT_GPU
+#include "../../src/gpu/GrClipMaskManager.h"
+#include "GrContextFactory.h"
+#include "SkGpuDevice.h"
+
+static const int X_SIZE = 12;
+static const int Y_SIZE = 12;
+
+////////////////////////////////////////////////////////////////////////////////
+// note: this is unused
+static GrTexture* createTexture(GrContext* context) {
+ unsigned char textureData[X_SIZE][Y_SIZE][4];
+
+ memset(textureData, 0, 4* X_SIZE * Y_SIZE);
+
+ GrTextureDesc desc;
+
+ // let Skia know we will be using this texture as a render target
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ desc.fConfig = kSkia8888_GrPixelConfig;
+ desc.fWidth = X_SIZE;
+ desc.fHeight = Y_SIZE;
+
+ // We are initializing the texture with zeros here
+ GrTexture* texture = context->createUncachedTexture(desc, textureData, 0);
+ if (!texture) {
+ return NULL;
+ }
+
+ return texture;
+}
+
+// Ensure that the 'getConservativeBounds' calls are returning bounds clamped
+// to the render target
+static void test_clip_bounds(skiatest::Reporter* reporter, GrContext* context) {
+
+ static const int kXSize = 100;
+ static const int kYSize = 100;
+
+ GrTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ desc.fConfig = kAlpha_8_GrPixelConfig;
+ desc.fWidth = kXSize;
+ desc.fHeight = kYSize;
+
+ GrTexture* texture = context->createUncachedTexture(desc, NULL, 0);
+ if (!texture) {
+ return;
+ }
+
+ SkAutoTUnref<GrTexture> au(texture);
+
+ SkIRect intScreen = SkIRect::MakeWH(kXSize, kYSize);
+ SkRect screen;
+
+ screen = SkRect::MakeWH(SkIntToScalar(kXSize),
+ SkIntToScalar(kYSize));
+
+ SkRect clipRect(screen);
+ clipRect.outset(10, 10);
+
+ // create a clip stack that will (trivially) reduce to a single rect that
+ // is larger than the screen
+ SkClipStack stack;
+ stack.clipDevRect(clipRect, SkRegion::kReplace_Op, false);
+
+ bool isIntersectionOfRects = true;
+ SkRect devStackBounds;
+
+ stack.getConservativeBounds(0, 0, kXSize, kYSize,
+ &devStackBounds,
+ &isIntersectionOfRects);
+
+ // make sure that the SkClipStack is behaving itself
+ REPORTER_ASSERT(reporter, screen == devStackBounds);
+ REPORTER_ASSERT(reporter, isIntersectionOfRects);
+
+ // wrap the SkClipStack in a GrClipData
+ GrClipData clipData;
+ clipData.fClipStack = &stack;
+
+ SkIRect devGrClipDataBound;
+ clipData.getConservativeBounds(texture,
+ &devGrClipDataBound,
+ &isIntersectionOfRects);
+
+ // make sure that GrClipData is behaving itself
+ REPORTER_ASSERT(reporter, intScreen == devGrClipDataBound);
+ REPORTER_ASSERT(reporter, isIntersectionOfRects);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// verify that the top state of the stack matches the passed in state
+static void check_state(skiatest::Reporter* reporter,
+ const GrClipMaskCache& cache,
+ const SkClipStack& clip,
+ GrTexture* mask,
+ const SkIRect& bound) {
+ REPORTER_ASSERT(reporter, clip.getTopmostGenID() == cache.getLastClipGenID());
+
+ REPORTER_ASSERT(reporter, mask == cache.getLastMask());
+
+ SkIRect cacheBound;
+ cache.getLastBound(&cacheBound);
+ REPORTER_ASSERT(reporter, bound == cacheBound);
+}
+
+static void check_empty_state(skiatest::Reporter* reporter,
+ const GrClipMaskCache& cache) {
+ REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID == cache.getLastClipGenID());
+ REPORTER_ASSERT(reporter, NULL == cache.getLastMask());
+
+ SkIRect emptyBound;
+ emptyBound.setEmpty();
+
+ SkIRect cacheBound;
+ cache.getLastBound(&cacheBound);
+ REPORTER_ASSERT(reporter, emptyBound == cacheBound);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// basic test of the cache's base functionality:
+// push, pop, set, canReuse & getters
+static void test_cache(skiatest::Reporter* reporter, GrContext* context) {
+
+ if (false) { // avoid bit rot, suppress warning
+ createTexture(context);
+ }
+ GrClipMaskCache cache;
+
+ cache.setContext(context);
+
+ // check initial state
+ check_empty_state(reporter, cache);
+
+ // set the current state
+ SkIRect bound1;
+ bound1.set(0, 0, 100, 100);
+
+ SkClipStack clip1(bound1);
+
+ GrTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ desc.fWidth = X_SIZE;
+ desc.fHeight = Y_SIZE;
+ desc.fConfig = kSkia8888_GrPixelConfig;
+
+ cache.acquireMask(clip1.getTopmostGenID(), desc, bound1);
+
+ GrTexture* texture1 = cache.getLastMask();
+ REPORTER_ASSERT(reporter, texture1);
+ if (NULL == texture1) {
+ return;
+ }
+
+ // check that the set took
+ check_state(reporter, cache, clip1, texture1, bound1);
+
+ // push the state
+ cache.push();
+
+ // verify that the pushed state is initially empty
+ check_empty_state(reporter, cache);
+
+ // modify the new state
+ SkIRect bound2;
+ bound2.set(-10, -10, 10, 10);
+
+ SkClipStack clip2(bound2);
+
+ cache.acquireMask(clip2.getTopmostGenID(), desc, bound2);
+
+ GrTexture* texture2 = cache.getLastMask();
+ REPORTER_ASSERT(reporter, texture2);
+ if (NULL == texture2) {
+ return;
+ }
+
+ // check that the changes took
+ check_state(reporter, cache, clip2, texture2, bound2);
+
+ // check to make sure canReuse works
+ REPORTER_ASSERT(reporter, cache.canReuse(clip2.getTopmostGenID(), bound2));
+ REPORTER_ASSERT(reporter, !cache.canReuse(clip1.getTopmostGenID(), bound1));
+
+ // pop the state
+ cache.pop();
+
+ // verify that the old state is restored
+ check_state(reporter, cache, clip1, texture1, bound1);
+
+ // manually clear the state
+ cache.reset();
+
+ // verify it is now empty
+ check_empty_state(reporter, cache);
+
+ // pop again - so there is no state
+ cache.pop();
+
+#if !defined(SK_DEBUG)
+ // verify that the getters don't crash
+ // only do in release since it generates asserts in debug
+ check_empty_state(reporter, cache);
+#endif
+}
+
+DEF_GPUTEST(ClipCache, reporter, factory) {
+ for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
+ GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type);
+ if (!GrContextFactory::IsRenderingGLContext(glType)) {
+ continue;
+ }
+ GrContext* context = factory->get(glType);
+ if (NULL == context) {
+ continue;
+ }
+
+ test_cache(reporter, context);
+ test_clip_bounds(reporter, context);
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/ClipCubicTest.cpp b/src/third_party/skia/tests/ClipCubicTest.cpp
new file mode 100644
index 0000000..31b38f2
--- /dev/null
+++ b/src/third_party/skia/tests/ClipCubicTest.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkCubicClipper.h"
+#include "SkGeometry.h"
+#include "SkPaint.h"
+#include "Test.h"
+
+// Currently the supersampler blitter uses int16_t for its index into an array
+// the width of the clip. Test that we don't crash/assert if we try to draw
+// with a device/clip that is larger.
+static void test_giantClip() {
+ SkBitmap bm;
+ bm.allocN32Pixels(64919, 1);
+ SkCanvas canvas(bm);
+ canvas.clear(SK_ColorTRANSPARENT);
+
+ SkPath path;
+ path.moveTo(0, 0); path.lineTo(1, 0); path.lineTo(33, 1);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ canvas.drawPath(path, paint);
+}
+
+static void PrintCurve(const char *name, const SkPoint crv[4]) {
+ SkDebugf("%s: %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g\n",
+ name,
+ (float)crv[0].fX, (float)crv[0].fY,
+ (float)crv[1].fX, (float)crv[1].fY,
+ (float)crv[2].fX, (float)crv[2].fY,
+ (float)crv[3].fX, (float)crv[3].fY);
+
+}
+
+
+static bool CurvesAreEqual(const SkPoint c0[4],
+ const SkPoint c1[4],
+ float tol) {
+ for (int i = 0; i < 4; i++) {
+ if (SkScalarAbs(c0[i].fX - c1[i].fX) > tol ||
+ SkScalarAbs(c0[i].fY - c1[i].fY) > tol
+ ) {
+ PrintCurve("c0", c0);
+ PrintCurve("c1", c1);
+ return false;
+ }
+ }
+ return true;
+}
+
+
+static SkPoint* SetCurve(float x0, float y0,
+ float x1, float y1,
+ float x2, float y2,
+ float x3, float y3,
+ SkPoint crv[4]) {
+ crv[0].fX = x0; crv[0].fY = y0;
+ crv[1].fX = x1; crv[1].fY = y1;
+ crv[2].fX = x2; crv[2].fY = y2;
+ crv[3].fX = x3; crv[3].fY = y3;
+ return crv;
+}
+
+
+DEF_TEST(ClipCubic, reporter) {
+ static SkPoint crv[4] = {
+ { SkIntToScalar(0), SkIntToScalar(0) },
+ { SkIntToScalar(2), SkIntToScalar(3) },
+ { SkIntToScalar(1), SkIntToScalar(10) },
+ { SkIntToScalar(4), SkIntToScalar(12) }
+ };
+
+ SkCubicClipper clipper;
+ SkPoint clipped[4], shouldbe[4];
+ SkIRect clipRect;
+ bool success;
+ const float tol = 1e-4f;
+
+ // Test no clip, with plenty of room.
+ clipRect.set(-2, -2, 6, 14);
+ clipper.setClip(clipRect);
+ success = clipper.clipCubic(crv, clipped);
+ REPORTER_ASSERT(reporter, success == true);
+ REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
+ 0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
+
+ // Test no clip, touching first point.
+ clipRect.set(-2, 0, 6, 14);
+ clipper.setClip(clipRect);
+ success = clipper.clipCubic(crv, clipped);
+ REPORTER_ASSERT(reporter, success == true);
+ REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
+ 0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
+
+ // Test no clip, touching last point.
+ clipRect.set(-2, -2, 6, 12);
+ clipper.setClip(clipRect);
+ success = clipper.clipCubic(crv, clipped);
+ REPORTER_ASSERT(reporter, success == true);
+ REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
+ 0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
+
+ // Test all clip.
+ clipRect.set(-2, 14, 6, 20);
+ clipper.setClip(clipRect);
+ success = clipper.clipCubic(crv, clipped);
+ REPORTER_ASSERT(reporter, success == false);
+
+ // Test clip at 1.
+ clipRect.set(-2, 1, 6, 14);
+ clipper.setClip(clipRect);
+ success = clipper.clipCubic(crv, clipped);
+ REPORTER_ASSERT(reporter, success == true);
+ REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
+ 0.5126125216f, 1,
+ 1.841195941f, 4.337081432f,
+ 1.297019958f, 10.19801331f,
+ 4, 12,
+ shouldbe), tol));
+
+ // Test clip at 2.
+ clipRect.set(-2, 2, 6, 14);
+ clipper.setClip(clipRect);
+ success = clipper.clipCubic(crv, clipped);
+ REPORTER_ASSERT(reporter, success == true);
+ REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
+ 00.8412352204f, 2,
+ 1.767683744f, 5.400758266f,
+ 1.55052948f, 10.36701965f,
+ 4, 12,
+ shouldbe), tol));
+
+ // Test clip at 11.
+ clipRect.set(-2, -2, 6, 11);
+ clipper.setClip(clipRect);
+ success = clipper.clipCubic(crv, clipped);
+ REPORTER_ASSERT(reporter, success == true);
+ REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
+ 0, 0,
+ 1.742904663f, 2.614356995f,
+ 1.207521796f, 8.266430855f,
+ 3.026495695f, 11,
+ shouldbe), tol));
+
+ // Test clip at 10.
+ clipRect.set(-2, -2, 6, 10);
+ clipper.setClip(clipRect);
+ success = clipper.clipCubic(crv, clipped);
+ REPORTER_ASSERT(reporter, success == true);
+ REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
+ 0, 0,
+ 1.551193237f, 2.326789856f,
+ 1.297736168f, 7.059780121f,
+ 2.505550385f, 10,
+ shouldbe), tol));
+
+ test_giantClip();
+}
diff --git a/src/third_party/skia/tests/ClipStackTest.cpp b/src/third_party/skia/tests/ClipStackTest.cpp
new file mode 100644
index 0000000..662e680
--- /dev/null
+++ b/src/third_party/skia/tests/ClipStackTest.cpp
@@ -0,0 +1,1221 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#if SK_SUPPORT_GPU
+ #include "GrReducedClip.h"
+#endif
+#include "SkClipStack.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkRect.h"
+#include "SkRegion.h"
+
+static void test_assign_and_comparison(skiatest::Reporter* reporter) {
+ SkClipStack s;
+ bool doAA = false;
+
+ REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
+
+ // Build up a clip stack with a path, an empty clip, and a rect.
+ s.save();
+ REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
+
+ SkPath p;
+ p.moveTo(5, 6);
+ p.lineTo(7, 8);
+ p.lineTo(5, 9);
+ p.close();
+ s.clipDevPath(p, SkRegion::kIntersect_Op, doAA);
+
+ s.save();
+ REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
+
+ SkRect r = SkRect::MakeLTRB(1, 2, 3, 4);
+ s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
+ r = SkRect::MakeLTRB(10, 11, 12, 13);
+ s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
+
+ s.save();
+ REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
+
+ r = SkRect::MakeLTRB(14, 15, 16, 17);
+ s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
+
+ // Test that assignment works.
+ SkClipStack copy = s;
+ REPORTER_ASSERT(reporter, s == copy);
+
+ // Test that different save levels triggers not equal.
+ s.restore();
+ REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
+ REPORTER_ASSERT(reporter, s != copy);
+
+ // Test that an equal, but not copied version is equal.
+ s.save();
+ REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
+ r = SkRect::MakeLTRB(14, 15, 16, 17);
+ s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
+ REPORTER_ASSERT(reporter, s == copy);
+
+ // Test that a different op on one level triggers not equal.
+ s.restore();
+ REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
+ s.save();
+ REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
+ r = SkRect::MakeLTRB(14, 15, 16, 17);
+ s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
+ REPORTER_ASSERT(reporter, s != copy);
+
+ // Test that version constructed with rect-path rather than a rect is still considered equal.
+ s.restore();
+ s.save();
+ SkPath rp;
+ rp.addRect(r);
+ s.clipDevPath(rp, SkRegion::kUnion_Op, doAA);
+ REPORTER_ASSERT(reporter, s == copy);
+
+ // Test that different rects triggers not equal.
+ s.restore();
+ REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
+ s.save();
+ REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
+
+ r = SkRect::MakeLTRB(24, 25, 26, 27);
+ s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
+ REPORTER_ASSERT(reporter, s != copy);
+
+ // Sanity check
+ s.restore();
+ REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
+
+ copy.restore();
+ REPORTER_ASSERT(reporter, 2 == copy.getSaveCount());
+ REPORTER_ASSERT(reporter, s == copy);
+ s.restore();
+ REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
+ copy.restore();
+ REPORTER_ASSERT(reporter, 1 == copy.getSaveCount());
+ REPORTER_ASSERT(reporter, s == copy);
+
+ // Test that different paths triggers not equal.
+ s.restore();
+ REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
+ s.save();
+ REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
+
+ p.addRect(r);
+ s.clipDevPath(p, SkRegion::kIntersect_Op, doAA);
+ REPORTER_ASSERT(reporter, s != copy);
+}
+
+static void assert_count(skiatest::Reporter* reporter, const SkClipStack& stack,
+ int count) {
+ SkClipStack::B2TIter iter(stack);
+ int counter = 0;
+ while (iter.next()) {
+ counter += 1;
+ }
+ REPORTER_ASSERT(reporter, count == counter);
+}
+
+// Exercise the SkClipStack's bottom to top and bidirectional iterators
+// (including the skipToTopmost functionality)
+static void test_iterators(skiatest::Reporter* reporter) {
+ SkClipStack stack;
+
+ static const SkRect gRects[] = {
+ { 0, 0, 40, 40 },
+ { 60, 0, 100, 40 },
+ { 0, 60, 40, 100 },
+ { 60, 60, 100, 100 }
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) {
+ // the union op will prevent these from being fused together
+ stack.clipDevRect(gRects[i], SkRegion::kUnion_Op, false);
+ }
+
+ assert_count(reporter, stack, 4);
+
+ // bottom to top iteration
+ {
+ const SkClipStack::Element* element = NULL;
+
+ SkClipStack::B2TIter iter(stack);
+ int i;
+
+ for (i = 0, element = iter.next(); element; ++i, element = iter.next()) {
+ REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
+ REPORTER_ASSERT(reporter, element->getRect() == gRects[i]);
+ }
+
+ SkASSERT(i == 4);
+ }
+
+ // top to bottom iteration
+ {
+ const SkClipStack::Element* element = NULL;
+
+ SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
+ int i;
+
+ for (i = 3, element = iter.prev(); element; --i, element = iter.prev()) {
+ REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
+ REPORTER_ASSERT(reporter, element->getRect() == gRects[i]);
+ }
+
+ SkASSERT(i == -1);
+ }
+
+ // skipToTopmost
+ {
+ const SkClipStack::Element* element = NULL;
+
+ SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
+
+ element = iter.skipToTopmost(SkRegion::kUnion_Op);
+ REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
+ REPORTER_ASSERT(reporter, element->getRect() == gRects[3]);
+ }
+}
+
+// Exercise the SkClipStack's getConservativeBounds computation
+static void test_bounds(skiatest::Reporter* reporter, SkClipStack::Element::Type primType) {
+ static const int gNumCases = 20;
+ static const SkRect gAnswerRectsBW[gNumCases] = {
+ // A op B
+ { 40, 40, 50, 50 },
+ { 10, 10, 50, 50 },
+ { 10, 10, 80, 80 },
+ { 10, 10, 80, 80 },
+ { 40, 40, 80, 80 },
+
+ // invA op B
+ { 40, 40, 80, 80 },
+ { 0, 0, 100, 100 },
+ { 0, 0, 100, 100 },
+ { 0, 0, 100, 100 },
+ { 40, 40, 50, 50 },
+
+ // A op invB
+ { 10, 10, 50, 50 },
+ { 40, 40, 50, 50 },
+ { 0, 0, 100, 100 },
+ { 0, 0, 100, 100 },
+ { 0, 0, 100, 100 },
+
+ // invA op invB
+ { 0, 0, 100, 100 },
+ { 40, 40, 80, 80 },
+ { 0, 0, 100, 100 },
+ { 10, 10, 80, 80 },
+ { 10, 10, 50, 50 },
+ };
+
+ static const SkRegion::Op gOps[] = {
+ SkRegion::kIntersect_Op,
+ SkRegion::kDifference_Op,
+ SkRegion::kUnion_Op,
+ SkRegion::kXOR_Op,
+ SkRegion::kReverseDifference_Op
+ };
+
+ SkRect rectA, rectB;
+
+ rectA.iset(10, 10, 50, 50);
+ rectB.iset(40, 40, 80, 80);
+
+ SkRRect rrectA, rrectB;
+ rrectA.setOval(rectA);
+ rrectB.setRectXY(rectB, SkIntToScalar(1), SkIntToScalar(2));
+
+ SkPath pathA, pathB;
+
+ pathA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5));
+ pathB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5));
+
+ SkClipStack stack;
+ SkRect devClipBound;
+ bool isIntersectionOfRects = false;
+
+ int testCase = 0;
+ int numBitTests = SkClipStack::Element::kPath_Type == primType ? 4 : 1;
+ for (int invBits = 0; invBits < numBitTests; ++invBits) {
+ for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) {
+
+ stack.save();
+ bool doInvA = SkToBool(invBits & 1);
+ bool doInvB = SkToBool(invBits & 2);
+
+ pathA.setFillType(doInvA ? SkPath::kInverseEvenOdd_FillType :
+ SkPath::kEvenOdd_FillType);
+ pathB.setFillType(doInvB ? SkPath::kInverseEvenOdd_FillType :
+ SkPath::kEvenOdd_FillType);
+
+ switch (primType) {
+ case SkClipStack::Element::kEmpty_Type:
+ SkDEBUGFAIL("Don't call this with kEmpty.");
+ break;
+ case SkClipStack::Element::kRect_Type:
+ stack.clipDevRect(rectA, SkRegion::kIntersect_Op, false);
+ stack.clipDevRect(rectB, gOps[op], false);
+ break;
+ case SkClipStack::Element::kRRect_Type:
+ stack.clipDevRRect(rrectA, SkRegion::kIntersect_Op, false);
+ stack.clipDevRRect(rrectB, gOps[op], false);
+ break;
+ case SkClipStack::Element::kPath_Type:
+ stack.clipDevPath(pathA, SkRegion::kIntersect_Op, false);
+ stack.clipDevPath(pathB, gOps[op], false);
+ break;
+ }
+
+ REPORTER_ASSERT(reporter, !stack.isWideOpen());
+ REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID != stack.getTopmostGenID());
+
+ stack.getConservativeBounds(0, 0, 100, 100, &devClipBound,
+ &isIntersectionOfRects);
+
+ if (SkClipStack::Element::kRect_Type == primType) {
+ REPORTER_ASSERT(reporter, isIntersectionOfRects ==
+ (gOps[op] == SkRegion::kIntersect_Op));
+ } else {
+ REPORTER_ASSERT(reporter, !isIntersectionOfRects);
+ }
+
+ SkASSERT(testCase < gNumCases);
+ REPORTER_ASSERT(reporter, devClipBound == gAnswerRectsBW[testCase]);
+ ++testCase;
+
+ stack.restore();
+ }
+ }
+}
+
+// Test out 'isWideOpen' entry point
+static void test_isWideOpen(skiatest::Reporter* reporter) {
+ {
+ // Empty stack is wide open. Wide open stack means that gen id is wide open.
+ SkClipStack stack;
+ REPORTER_ASSERT(reporter, stack.isWideOpen());
+ REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
+ }
+
+ SkRect rectA, rectB;
+
+ rectA.iset(10, 10, 40, 40);
+ rectB.iset(50, 50, 80, 80);
+
+ // Stack should initially be wide open
+ {
+ SkClipStack stack;
+
+ REPORTER_ASSERT(reporter, stack.isWideOpen());
+ REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
+ }
+
+ // Test out case where the user specifies a union that includes everything
+ {
+ SkClipStack stack;
+
+ SkPath clipA, clipB;
+
+ clipA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5));
+ clipA.setFillType(SkPath::kInverseEvenOdd_FillType);
+
+ clipB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5));
+ clipB.setFillType(SkPath::kInverseEvenOdd_FillType);
+
+ stack.clipDevPath(clipA, SkRegion::kReplace_Op, false);
+ stack.clipDevPath(clipB, SkRegion::kUnion_Op, false);
+
+ REPORTER_ASSERT(reporter, stack.isWideOpen());
+ REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
+ }
+
+ // Test out union w/ a wide open clip
+ {
+ SkClipStack stack;
+
+ stack.clipDevRect(rectA, SkRegion::kUnion_Op, false);
+
+ REPORTER_ASSERT(reporter, stack.isWideOpen());
+ REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
+ }
+
+ // Test out empty difference from a wide open clip
+ {
+ SkClipStack stack;
+
+ SkRect emptyRect;
+ emptyRect.setEmpty();
+
+ stack.clipDevRect(emptyRect, SkRegion::kDifference_Op, false);
+
+ REPORTER_ASSERT(reporter, stack.isWideOpen());
+ REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
+ }
+
+ // Test out return to wide open
+ {
+ SkClipStack stack;
+
+ stack.save();
+
+ stack.clipDevRect(rectA, SkRegion::kReplace_Op, false);
+
+ REPORTER_ASSERT(reporter, !stack.isWideOpen());
+ REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID != stack.getTopmostGenID());
+
+ stack.restore();
+
+ REPORTER_ASSERT(reporter, stack.isWideOpen());
+ REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
+ }
+}
+
+static int count(const SkClipStack& stack) {
+
+ SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
+
+ const SkClipStack::Element* element = NULL;
+ int count = 0;
+
+ for (element = iter.prev(); element; element = iter.prev(), ++count) {
+ ;
+ }
+
+ return count;
+}
+
+static void test_rect_inverse_fill(skiatest::Reporter* reporter) {
+ // non-intersecting rectangles
+ SkRect rect = SkRect::MakeLTRB(0, 0, 10, 10);
+
+ SkPath path;
+ path.addRect(rect);
+ path.toggleInverseFillType();
+ SkClipStack stack;
+ stack.clipDevPath(path, SkRegion::kIntersect_Op, false);
+
+ SkRect bounds;
+ SkClipStack::BoundsType boundsType;
+ stack.getBounds(&bounds, &boundsType);
+ REPORTER_ASSERT(reporter, SkClipStack::kInsideOut_BoundsType == boundsType);
+ REPORTER_ASSERT(reporter, bounds == rect);
+}
+
+static void test_rect_replace(skiatest::Reporter* reporter) {
+ SkRect rect = SkRect::MakeWH(100, 100);
+ SkRect rect2 = SkRect::MakeXYWH(50, 50, 100, 100);
+
+ SkRect bound;
+ SkClipStack::BoundsType type;
+ bool isIntersectionOfRects;
+
+ // Adding a new rect with the replace operator should not increase
+ // the stack depth. BW replacing BW.
+ {
+ SkClipStack stack;
+ REPORTER_ASSERT(reporter, 0 == count(stack));
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, false);
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, false);
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+ }
+
+ // Adding a new rect with the replace operator should not increase
+ // the stack depth. AA replacing AA.
+ {
+ SkClipStack stack;
+ REPORTER_ASSERT(reporter, 0 == count(stack));
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, true);
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, true);
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+ }
+
+ // Adding a new rect with the replace operator should not increase
+ // the stack depth. BW replacing AA replacing BW.
+ {
+ SkClipStack stack;
+ REPORTER_ASSERT(reporter, 0 == count(stack));
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, false);
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, true);
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, false);
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+ }
+
+ // Make sure replace clip rects don't collapse too much.
+ {
+ SkClipStack stack;
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, false);
+ stack.clipDevRect(rect2, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+
+ stack.save();
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, false);
+ REPORTER_ASSERT(reporter, 2 == count(stack));
+ stack.getBounds(&bound, &type, &isIntersectionOfRects);
+ REPORTER_ASSERT(reporter, bound == rect);
+ stack.restore();
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+
+ stack.save();
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, false);
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, false);
+ REPORTER_ASSERT(reporter, 2 == count(stack));
+ stack.restore();
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+
+ stack.save();
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, false);
+ stack.clipDevRect(rect2, SkRegion::kIntersect_Op, false);
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, false);
+ REPORTER_ASSERT(reporter, 2 == count(stack));
+ stack.restore();
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+ }
+}
+
+// Simplified path-based version of test_rect_replace.
+static void test_path_replace(skiatest::Reporter* reporter) {
+ SkRect rect = SkRect::MakeWH(100, 100);
+ SkPath path;
+ path.addCircle(50, 50, 50);
+
+ // Replace operation doesn't grow the stack.
+ {
+ SkClipStack stack;
+ REPORTER_ASSERT(reporter, 0 == count(stack));
+ stack.clipDevPath(path, SkRegion::kReplace_Op, false);
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+ stack.clipDevPath(path, SkRegion::kReplace_Op, false);
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+ }
+
+ // Replacing rect with path.
+ {
+ SkClipStack stack;
+ stack.clipDevRect(rect, SkRegion::kReplace_Op, true);
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+ stack.clipDevPath(path, SkRegion::kReplace_Op, true);
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+ }
+}
+
+// Test out SkClipStack's merging of rect clips. In particular exercise
+// merging of aa vs. bw rects.
+static void test_rect_merging(skiatest::Reporter* reporter) {
+
+ SkRect overlapLeft = SkRect::MakeLTRB(10, 10, 50, 50);
+ SkRect overlapRight = SkRect::MakeLTRB(40, 40, 80, 80);
+
+ SkRect nestedParent = SkRect::MakeLTRB(10, 10, 90, 90);
+ SkRect nestedChild = SkRect::MakeLTRB(40, 40, 60, 60);
+
+ SkRect bound;
+ SkClipStack::BoundsType type;
+ bool isIntersectionOfRects;
+
+ // all bw overlapping - should merge
+ {
+ SkClipStack stack;
+
+ stack.clipDevRect(overlapLeft, SkRegion::kReplace_Op, false);
+
+ stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false);
+
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+
+ stack.getBounds(&bound, &type, &isIntersectionOfRects);
+
+ REPORTER_ASSERT(reporter, isIntersectionOfRects);
+ }
+
+ // all aa overlapping - should merge
+ {
+ SkClipStack stack;
+
+ stack.clipDevRect(overlapLeft, SkRegion::kReplace_Op, true);
+
+ stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, true);
+
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+
+ stack.getBounds(&bound, &type, &isIntersectionOfRects);
+
+ REPORTER_ASSERT(reporter, isIntersectionOfRects);
+ }
+
+ // mixed overlapping - should _not_ merge
+ {
+ SkClipStack stack;
+
+ stack.clipDevRect(overlapLeft, SkRegion::kReplace_Op, true);
+
+ stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false);
+
+ REPORTER_ASSERT(reporter, 2 == count(stack));
+
+ stack.getBounds(&bound, &type, &isIntersectionOfRects);
+
+ REPORTER_ASSERT(reporter, !isIntersectionOfRects);
+ }
+
+ // mixed nested (bw inside aa) - should merge
+ {
+ SkClipStack stack;
+
+ stack.clipDevRect(nestedParent, SkRegion::kReplace_Op, true);
+
+ stack.clipDevRect(nestedChild, SkRegion::kIntersect_Op, false);
+
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+
+ stack.getBounds(&bound, &type, &isIntersectionOfRects);
+
+ REPORTER_ASSERT(reporter, isIntersectionOfRects);
+ }
+
+ // mixed nested (aa inside bw) - should merge
+ {
+ SkClipStack stack;
+
+ stack.clipDevRect(nestedParent, SkRegion::kReplace_Op, false);
+
+ stack.clipDevRect(nestedChild, SkRegion::kIntersect_Op, true);
+
+ REPORTER_ASSERT(reporter, 1 == count(stack));
+
+ stack.getBounds(&bound, &type, &isIntersectionOfRects);
+
+ REPORTER_ASSERT(reporter, isIntersectionOfRects);
+ }
+
+ // reverse nested (aa inside bw) - should _not_ merge
+ {
+ SkClipStack stack;
+
+ stack.clipDevRect(nestedChild, SkRegion::kReplace_Op, false);
+
+ stack.clipDevRect(nestedParent, SkRegion::kIntersect_Op, true);
+
+ REPORTER_ASSERT(reporter, 2 == count(stack));
+
+ stack.getBounds(&bound, &type, &isIntersectionOfRects);
+
+ REPORTER_ASSERT(reporter, !isIntersectionOfRects);
+ }
+}
+
+static void test_quickContains(skiatest::Reporter* reporter) {
+ SkRect testRect = SkRect::MakeLTRB(10, 10, 40, 40);
+ SkRect insideRect = SkRect::MakeLTRB(20, 20, 30, 30);
+ SkRect intersectingRect = SkRect::MakeLTRB(25, 25, 50, 50);
+ SkRect outsideRect = SkRect::MakeLTRB(0, 0, 50, 50);
+ SkRect nonIntersectingRect = SkRect::MakeLTRB(100, 100, 110, 110);
+
+ SkPath insideCircle;
+ insideCircle.addCircle(25, 25, 5);
+ SkPath intersectingCircle;
+ intersectingCircle.addCircle(25, 40, 10);
+ SkPath outsideCircle;
+ outsideCircle.addCircle(25, 25, 50);
+ SkPath nonIntersectingCircle;
+ nonIntersectingCircle.addCircle(100, 100, 5);
+
+ {
+ SkClipStack stack;
+ stack.clipDevRect(outsideRect, SkRegion::kDifference_Op, false);
+ // return false because quickContains currently does not care for kDifference_Op
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ // Replace Op tests
+ {
+ SkClipStack stack;
+ stack.clipDevRect(outsideRect, SkRegion::kReplace_Op, false);
+ REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ stack.clipDevRect(insideRect, SkRegion::kIntersect_Op, false);
+ stack.save(); // To prevent in-place substitution by replace OP
+ stack.clipDevRect(outsideRect, SkRegion::kReplace_Op, false);
+ REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
+ stack.restore();
+ }
+
+ {
+ SkClipStack stack;
+ stack.clipDevRect(outsideRect, SkRegion::kIntersect_Op, false);
+ stack.save(); // To prevent in-place substitution by replace OP
+ stack.clipDevRect(insideRect, SkRegion::kReplace_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ stack.restore();
+ }
+
+ // Verify proper traversal of multi-element clip
+ {
+ SkClipStack stack;
+ stack.clipDevRect(insideRect, SkRegion::kIntersect_Op, false);
+ // Use a path for second clip to prevent in-place intersection
+ stack.clipDevPath(outsideCircle, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ // Intersect Op tests with rectangles
+ {
+ SkClipStack stack;
+ stack.clipDevRect(outsideRect, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ stack.clipDevRect(insideRect, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ stack.clipDevRect(intersectingRect, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ stack.clipDevRect(nonIntersectingRect, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ // Intersect Op tests with circle paths
+ {
+ SkClipStack stack;
+ stack.clipDevPath(outsideCircle, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ stack.clipDevPath(insideCircle, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ stack.clipDevPath(intersectingCircle, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ stack.clipDevPath(nonIntersectingCircle, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ // Intersect Op tests with inverse filled rectangles
+ {
+ SkClipStack stack;
+ SkPath path;
+ path.addRect(outsideRect);
+ path.toggleInverseFillType();
+ stack.clipDevPath(path, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ SkPath path;
+ path.addRect(insideRect);
+ path.toggleInverseFillType();
+ stack.clipDevPath(path, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ SkPath path;
+ path.addRect(intersectingRect);
+ path.toggleInverseFillType();
+ stack.clipDevPath(path, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ SkPath path;
+ path.addRect(nonIntersectingRect);
+ path.toggleInverseFillType();
+ stack.clipDevPath(path, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
+ }
+
+ // Intersect Op tests with inverse filled circles
+ {
+ SkClipStack stack;
+ SkPath path = outsideCircle;
+ path.toggleInverseFillType();
+ stack.clipDevPath(path, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ SkPath path = insideCircle;
+ path.toggleInverseFillType();
+ stack.clipDevPath(path, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ SkPath path = intersectingCircle;
+ path.toggleInverseFillType();
+ stack.clipDevPath(path, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
+ }
+
+ {
+ SkClipStack stack;
+ SkPath path = nonIntersectingCircle;
+ path.toggleInverseFillType();
+ stack.clipDevPath(path, SkRegion::kIntersect_Op, false);
+ REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if SK_SUPPORT_GPU
+// Functions that add a shape to the clip stack. The shape is computed from a rectangle.
+// AA is always disabled since the clip stack reducer can cause changes in aa rasterization of the
+// stack. A fractional edge repeated in different elements may be rasterized fewer times using the
+// reduced stack.
+typedef void (*AddElementFunc) (const SkRect& rect,
+ bool invert,
+ SkRegion::Op op,
+ SkClipStack* stack);
+
+static void add_round_rect(const SkRect& rect, bool invert, SkRegion::Op op, SkClipStack* stack) {
+ SkScalar rx = rect.width() / 10;
+ SkScalar ry = rect.height() / 20;
+ if (invert) {
+ SkPath path;
+ path.addRoundRect(rect, rx, ry);
+ path.setFillType(SkPath::kInverseWinding_FillType);
+ stack->clipDevPath(path, op, false);
+ } else {
+ SkRRect rrect;
+ rrect.setRectXY(rect, rx, ry);
+ stack->clipDevRRect(rrect, op, false);
+ }
+};
+
+static void add_rect(const SkRect& rect, bool invert, SkRegion::Op op, SkClipStack* stack) {
+ if (invert) {
+ SkPath path;
+ path.addRect(rect);
+ path.setFillType(SkPath::kInverseWinding_FillType);
+ stack->clipDevPath(path, op, false);
+ } else {
+ stack->clipDevRect(rect, op, false);
+ }
+};
+
+static void add_oval(const SkRect& rect, bool invert, SkRegion::Op op, SkClipStack* stack) {
+ SkPath path;
+ path.addOval(rect);
+ if (invert) {
+ path.setFillType(SkPath::kInverseWinding_FillType);
+ }
+ stack->clipDevPath(path, op, false);
+};
+
+static void add_elem_to_stack(const SkClipStack::Element& element, SkClipStack* stack) {
+ switch (element.getType()) {
+ case SkClipStack::Element::kRect_Type:
+ stack->clipDevRect(element.getRect(), element.getOp(), element.isAA());
+ break;
+ case SkClipStack::Element::kRRect_Type:
+ stack->clipDevRRect(element.getRRect(), element.getOp(), element.isAA());
+ break;
+ case SkClipStack::Element::kPath_Type:
+ stack->clipDevPath(element.getPath(), element.getOp(), element.isAA());
+ break;
+ case SkClipStack::Element::kEmpty_Type:
+ SkDEBUGFAIL("Why did the reducer produce an explicit empty.");
+ stack->clipEmpty();
+ break;
+ }
+}
+
+static void add_elem_to_region(const SkClipStack::Element& element,
+ const SkIRect& bounds,
+ SkRegion* region) {
+ SkRegion elemRegion;
+ SkRegion boundsRgn(bounds);
+ SkPath path;
+
+ switch (element.getType()) {
+ case SkClipStack::Element::kEmpty_Type:
+ elemRegion.setEmpty();
+ break;
+ default:
+ element.asPath(&path);
+ elemRegion.setPath(path, boundsRgn);
+ break;
+ }
+ region->op(elemRegion, element.getOp());
+}
+
+static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
+ // We construct random clip stacks, reduce them, and then rasterize both versions to verify that
+ // they are equal.
+
+ // All the clip elements will be contained within these bounds.
+ static const SkRect kBounds = SkRect::MakeWH(100, 100);
+
+ enum {
+ kNumTests = 200,
+ kMinElemsPerTest = 1,
+ kMaxElemsPerTest = 50,
+ };
+
+ // min/max size of a clip element as a fraction of kBounds.
+ static const SkScalar kMinElemSizeFrac = SK_Scalar1 / 5;
+ static const SkScalar kMaxElemSizeFrac = SK_Scalar1;
+
+ static const SkRegion::Op kOps[] = {
+ SkRegion::kDifference_Op,
+ SkRegion::kIntersect_Op,
+ SkRegion::kUnion_Op,
+ SkRegion::kXOR_Op,
+ SkRegion::kReverseDifference_Op,
+ SkRegion::kReplace_Op,
+ };
+
+ // Replace operations short-circuit the optimizer. We want to make sure that we test this code
+ // path a little bit but we don't want it to prevent us from testing many longer traversals in
+ // the optimizer.
+ static const int kReplaceDiv = 4 * kMaxElemsPerTest;
+
+ // We want to test inverse fills. However, they are quite rare in practice so don't over do it.
+ static const SkScalar kFractionInverted = SK_Scalar1 / kMaxElemsPerTest;
+
+ static const AddElementFunc kElementFuncs[] = {
+ add_rect,
+ add_round_rect,
+ add_oval,
+ };
+
+ SkRandom r;
+
+ for (int i = 0; i < kNumTests; ++i) {
+ // Randomly generate a clip stack.
+ SkClipStack stack;
+ int numElems = r.nextRangeU(kMinElemsPerTest, kMaxElemsPerTest);
+ for (int e = 0; e < numElems; ++e) {
+ SkRegion::Op op = kOps[r.nextULessThan(SK_ARRAY_COUNT(kOps))];
+ if (op == SkRegion::kReplace_Op) {
+ if (r.nextU() % kReplaceDiv) {
+ --e;
+ continue;
+ }
+ }
+
+ // saves can change the clip stack behavior when an element is added.
+ bool doSave = r.nextBool();
+
+ SkSize size = SkSize::Make(
+ SkScalarFloorToScalar(SkScalarMul(kBounds.width(), r.nextRangeScalar(kMinElemSizeFrac, kMaxElemSizeFrac))),
+ SkScalarFloorToScalar(SkScalarMul(kBounds.height(), r.nextRangeScalar(kMinElemSizeFrac, kMaxElemSizeFrac))));
+
+ SkPoint xy = {SkScalarFloorToScalar(r.nextRangeScalar(kBounds.fLeft, kBounds.fRight - size.fWidth)),
+ SkScalarFloorToScalar(r.nextRangeScalar(kBounds.fTop, kBounds.fBottom - size.fHeight))};
+
+ SkRect rect = SkRect::MakeXYWH(xy.fX, xy.fY, size.fWidth, size.fHeight);
+
+ bool invert = r.nextBiasedBool(kFractionInverted);
+
+ kElementFuncs[r.nextULessThan(SK_ARRAY_COUNT(kElementFuncs))](rect, invert, op, &stack);
+ if (doSave) {
+ stack.save();
+ }
+ }
+
+ SkRect inflatedBounds = kBounds;
+ inflatedBounds.outset(kBounds.width() / 2, kBounds.height() / 2);
+ SkIRect inflatedIBounds;
+ inflatedBounds.roundOut(&inflatedIBounds);
+
+ typedef GrReducedClip::ElementList ElementList;
+ // Get the reduced version of the stack.
+ ElementList reducedClips;
+ int32_t reducedGenID;
+ GrReducedClip::InitialState initial;
+ SkIRect tBounds(inflatedIBounds);
+ SkIRect* tightBounds = r.nextBool() ? &tBounds : NULL;
+ GrReducedClip::ReduceClipStack(stack,
+ inflatedIBounds,
+ &reducedClips,
+ &reducedGenID,
+ &initial,
+ tightBounds);
+
+ REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID != reducedGenID);
+
+ // Build a new clip stack based on the reduced clip elements
+ SkClipStack reducedStack;
+ if (GrReducedClip::kAllOut_InitialState == initial) {
+ // whether the result is bounded or not, the whole plane should start outside the clip.
+ reducedStack.clipEmpty();
+ }
+ for (ElementList::Iter iter = reducedClips.headIter(); iter.get(); iter.next()) {
+ add_elem_to_stack(*iter.get(), &reducedStack);
+ }
+
+ // GrReducedClipStack assumes that the final result is clipped to the returned bounds
+ if (tightBounds) {
+ reducedStack.clipDevRect(*tightBounds, SkRegion::kIntersect_Op);
+ }
+
+ // convert both the original stack and reduced stack to SkRegions and see if they're equal
+ SkRegion region;
+ SkRegion reducedRegion;
+
+ region.setRect(inflatedIBounds);
+ const SkClipStack::Element* element;
+ SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
+ while ((element = iter.next())) {
+ add_elem_to_region(*element, inflatedIBounds, ®ion);
+ }
+
+ reducedRegion.setRect(inflatedIBounds);
+ iter.reset(reducedStack, SkClipStack::Iter::kBottom_IterStart);
+ while ((element = iter.next())) {
+ add_elem_to_region(*element, inflatedIBounds, &reducedRegion);
+ }
+ SkString testCase;
+ testCase.printf("Iteration %d", i);
+ REPORTER_ASSERT_MESSAGE(reporter, region == reducedRegion, testCase.c_str());
+ }
+}
+
+#if defined(WIN32)
+ #define SUPPRESS_VISIBILITY_WARNING
+#else
+ #define SUPPRESS_VISIBILITY_WARNING __attribute__((visibility("hidden")))
+#endif
+
+static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) {
+ {
+ SkClipStack stack;
+ stack.clipDevRect(SkRect::MakeXYWH(0, 0, 100, 100), SkRegion::kReplace_Op, true);
+ stack.clipDevRect(SkRect::MakeXYWH(0, 0, SkScalar(50.3), SkScalar(50.3)), SkRegion::kReplace_Op, true);
+ SkIRect inflatedIBounds = SkIRect::MakeXYWH(0, 0, 100, 100);
+
+ GrReducedClip::ElementList reducedClips;
+ int32_t reducedGenID;
+ GrReducedClip::InitialState initial;
+ SkIRect tightBounds;
+
+ GrReducedClip::ReduceClipStack(stack,
+ inflatedIBounds,
+ &reducedClips,
+ &reducedGenID,
+ &initial,
+ &tightBounds);
+
+ REPORTER_ASSERT(reporter, reducedClips.count() == 1);
+ // Clips will be cached based on the generation id. Make sure the gen id is valid.
+ REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID != reducedGenID);
+ }
+ {
+ SkClipStack stack;
+
+ // Create a clip with following 25.3, 25.3 boxes which are 25 apart:
+ // A B
+ // C D
+
+ stack.clipDevRect(SkRect::MakeXYWH(0, 0, SkScalar(25.3), SkScalar(25.3)), SkRegion::kReplace_Op, true);
+ int32_t genIDA = stack.getTopmostGenID();
+ stack.clipDevRect(SkRect::MakeXYWH(50, 0, SkScalar(25.3), SkScalar(25.3)), SkRegion::kUnion_Op, true);
+ int32_t genIDB = stack.getTopmostGenID();
+ stack.clipDevRect(SkRect::MakeXYWH(0, 50, SkScalar(25.3), SkScalar(25.3)), SkRegion::kUnion_Op, true);
+ int32_t genIDC = stack.getTopmostGenID();
+ stack.clipDevRect(SkRect::MakeXYWH(50, 50, SkScalar(25.3), SkScalar(25.3)), SkRegion::kUnion_Op, true);
+ int32_t genIDD = stack.getTopmostGenID();
+
+
+#define XYWH SkIRect::MakeXYWH
+
+ SkIRect unused;
+ unused.setEmpty();
+ SkIRect stackBounds = XYWH(0, 0, 76, 76);
+
+ // The base test is to test each rect in two ways:
+ // 1) The box dimensions. (Should reduce to "all in", no elements).
+ // 2) A bit over the box dimensions.
+ // In the case 2, test that the generation id is what is expected.
+ // The rects are of fractional size so that case 2 never gets optimized to an empty element
+ // list.
+
+ // Not passing in tighter bounds is tested for consistency.
+ static const struct SUPPRESS_VISIBILITY_WARNING {
+ SkIRect testBounds;
+ int reducedClipCount;
+ int32_t reducedGenID;
+ GrReducedClip::InitialState initialState;
+ SkIRect tighterBounds; // If this is empty, the query will not pass tighter bounds
+ // parameter.
+ } testCases[] = {
+ // Rect A.
+ { XYWH(0, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, XYWH(0, 0, 25, 25) },
+ { XYWH(0, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, unused },
+ { XYWH(0, 0, 27, 27), 1, genIDA, GrReducedClip::kAllOut_InitialState, XYWH(0, 0, 27, 27)},
+ { XYWH(0, 0, 27, 27), 1, genIDA, GrReducedClip::kAllOut_InitialState, unused },
+
+ // Rect B.
+ { XYWH(50, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, XYWH(50, 0, 25, 25) },
+ { XYWH(50, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, unused },
+ { XYWH(50, 0, 27, 27), 1, genIDB, GrReducedClip::kAllOut_InitialState, XYWH(50, 0, 26, 27) },
+ { XYWH(50, 0, 27, 27), 1, genIDB, GrReducedClip::kAllOut_InitialState, unused },
+
+ // Rect C.
+ { XYWH(0, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, XYWH(0, 50, 25, 25) },
+ { XYWH(0, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, unused },
+ { XYWH(0, 50, 27, 27), 1, genIDC, GrReducedClip::kAllOut_InitialState, XYWH(0, 50, 27, 26) },
+ { XYWH(0, 50, 27, 27), 1, genIDC, GrReducedClip::kAllOut_InitialState, unused },
+
+ // Rect D.
+ { XYWH(50, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, unused },
+ { XYWH(50, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip::kAllIn_InitialState, XYWH(50, 50, 25, 25)},
+ { XYWH(50, 50, 27, 27), 1, genIDD, GrReducedClip::kAllOut_InitialState, unused },
+ { XYWH(50, 50, 27, 27), 1, genIDD, GrReducedClip::kAllOut_InitialState, XYWH(50, 50, 26, 26)},
+
+ // Other tests:
+ { XYWH(0, 0, 100, 100), 4, genIDD, GrReducedClip::kAllOut_InitialState, unused },
+ { XYWH(0, 0, 100, 100), 4, genIDD, GrReducedClip::kAllOut_InitialState, stackBounds },
+
+ // Rect in the middle, touches none.
+ { XYWH(26, 26, 24, 24), 0, SkClipStack::kEmptyGenID, GrReducedClip::kAllOut_InitialState, unused },
+ { XYWH(26, 26, 24, 24), 0, SkClipStack::kEmptyGenID, GrReducedClip::kAllOut_InitialState, XYWH(26, 26, 24, 24) },
+
+ // Rect in the middle, touches all the rects. GenID is the last rect.
+ { XYWH(24, 24, 27, 27), 4, genIDD, GrReducedClip::kAllOut_InitialState, unused },
+ { XYWH(24, 24, 27, 27), 4, genIDD, GrReducedClip::kAllOut_InitialState, XYWH(24, 24, 27, 27) },
+ };
+
+#undef XYWH
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(testCases); ++i) {
+ GrReducedClip::ElementList reducedClips;
+ int32_t reducedGenID;
+ GrReducedClip::InitialState initial;
+ SkIRect tightBounds;
+
+ GrReducedClip::ReduceClipStack(stack,
+ testCases[i].testBounds,
+ &reducedClips,
+ &reducedGenID,
+ &initial,
+ testCases[i].tighterBounds.isEmpty() ? NULL : &tightBounds);
+
+ REPORTER_ASSERT(reporter, reducedClips.count() == testCases[i].reducedClipCount);
+ SkASSERT(reducedClips.count() == testCases[i].reducedClipCount);
+ REPORTER_ASSERT(reporter, reducedGenID == testCases[i].reducedGenID);
+ SkASSERT(reducedGenID == testCases[i].reducedGenID);
+ REPORTER_ASSERT(reporter, initial == testCases[i].initialState);
+ SkASSERT(initial == testCases[i].initialState);
+ if (!testCases[i].tighterBounds.isEmpty()) {
+ REPORTER_ASSERT(reporter, tightBounds == testCases[i].tighterBounds);
+ SkASSERT(tightBounds == testCases[i].tighterBounds);
+ }
+ }
+ }
+}
+
+static void test_reduced_clip_stack_no_aa_crash(skiatest::Reporter* reporter) {
+ SkClipStack stack;
+ stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 100, 100), SkRegion::kReplace_Op);
+ stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 50, 50), SkRegion::kReplace_Op);
+ SkIRect inflatedIBounds = SkIRect::MakeXYWH(0, 0, 100, 100);
+
+ GrReducedClip::ElementList reducedClips;
+ int32_t reducedGenID;
+ GrReducedClip::InitialState initial;
+ SkIRect tightBounds;
+
+ // At the time, this would crash.
+ GrReducedClip::ReduceClipStack(stack,
+ inflatedIBounds,
+ &reducedClips,
+ &reducedGenID,
+ &initial,
+ &tightBounds);
+
+ REPORTER_ASSERT(reporter, 0 == reducedClips.count());
+}
+
+#endif
+
+DEF_TEST(ClipStack, reporter) {
+ SkClipStack stack;
+
+ REPORTER_ASSERT(reporter, 0 == stack.getSaveCount());
+ assert_count(reporter, stack, 0);
+
+ static const SkIRect gRects[] = {
+ { 0, 0, 100, 100 },
+ { 25, 25, 125, 125 },
+ { 0, 0, 1000, 1000 },
+ { 0, 0, 75, 75 }
+ };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) {
+ stack.clipDevRect(gRects[i], SkRegion::kIntersect_Op);
+ }
+
+ // all of the above rects should have been intersected, leaving only 1 rect
+ SkClipStack::B2TIter iter(stack);
+ const SkClipStack::Element* element = iter.next();
+ SkRect answer;
+ answer.iset(25, 25, 75, 75);
+
+ REPORTER_ASSERT(reporter, element);
+ REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
+ REPORTER_ASSERT(reporter, SkRegion::kIntersect_Op == element->getOp());
+ REPORTER_ASSERT(reporter, element->getRect() == answer);
+ // now check that we only had one in our iterator
+ REPORTER_ASSERT(reporter, !iter.next());
+
+ stack.reset();
+ REPORTER_ASSERT(reporter, 0 == stack.getSaveCount());
+ assert_count(reporter, stack, 0);
+
+ test_assign_and_comparison(reporter);
+ test_iterators(reporter);
+ test_bounds(reporter, SkClipStack::Element::kRect_Type);
+ test_bounds(reporter, SkClipStack::Element::kRRect_Type);
+ test_bounds(reporter, SkClipStack::Element::kPath_Type);
+ test_isWideOpen(reporter);
+ test_rect_merging(reporter);
+ test_rect_replace(reporter);
+ test_rect_inverse_fill(reporter);
+ test_path_replace(reporter);
+ test_quickContains(reporter);
+#if SK_SUPPORT_GPU
+ test_reduced_clip_stack(reporter);
+ test_reduced_clip_stack_genid(reporter);
+ test_reduced_clip_stack_no_aa_crash(reporter);
+#endif
+}
diff --git a/src/third_party/skia/tests/ClipperTest.cpp b/src/third_party/skia/tests/ClipperTest.cpp
new file mode 100644
index 0000000..00b6229
--- /dev/null
+++ b/src/third_party/skia/tests/ClipperTest.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkEdgeClipper.h"
+#include "SkLineClipper.h"
+#include "SkPath.h"
+#include "Test.h"
+
+static void test_hairclipping(skiatest::Reporter* reporter) {
+ SkBitmap bm;
+ bm.allocN32Pixels(4, 4);
+ bm.eraseColor(SK_ColorWHITE);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkCanvas canvas(bm);
+ canvas.clipRect(SkRect::MakeWH(SkIntToScalar(4), SkIntToScalar(2)));
+ canvas.drawLine(1.5f, 1.5f,
+ 3.5f, 3.5f, paint);
+
+ /**
+ * We had a bug where we misinterpreted the bottom of the clip, and
+ * would draw another pixel (to the right in this case) on the same
+ * last scanline. i.e. we would draw to [2,1], even though this hairline
+ * should just draw to [1,1], [2,2], [3,3] modulo the clip.
+ *
+ * The result of this entire draw should be that we only draw to [1,1]
+ *
+ * Fixed in rev. 3366
+ */
+ for (int y = 0; y < 4; ++y) {
+ for (int x = 0; x < 4; ++x) {
+ bool nonWhite = (1 == y) && (1 == x);
+ SkPMColor c = *bm.getAddr32(x, y);
+ if (nonWhite) {
+ REPORTER_ASSERT(reporter, 0xFFFFFFFF != c);
+ } else {
+ REPORTER_ASSERT(reporter, 0xFFFFFFFF == c);
+ }
+ }
+ }
+}
+
+static void test_edgeclipper() {
+ SkEdgeClipper clipper;
+
+ const SkPoint pts[] = {
+ { 3.0995476e+010f, 42.929779f },
+ { -3.0995163e+010f, 51.050385f },
+ { -3.0995157e+010f, 51.050392f },
+ { -3.0995134e+010f, 51.050400f },
+ };
+
+ const SkRect clip = { 0, 0, SkIntToScalar(300), SkIntToScalar(200) };
+
+ // this should not assert, even though our choppers do a poor numerical
+ // job when computing their t values.
+ // http://code.google.com/p/skia/issues/detail?id=444
+ clipper.clipCubic(pts, clip);
+}
+
+static void test_intersectline(skiatest::Reporter* reporter) {
+ static const SkScalar L = 0;
+ static const SkScalar T = 0;
+ static const SkScalar R = SkIntToScalar(100);
+ static const SkScalar B = SkIntToScalar(100);
+ static const SkScalar CX = SkScalarHalf(L + R);
+ static const SkScalar CY = SkScalarHalf(T + B);
+ static const SkRect gR = { L, T, R, B };
+
+ size_t i;
+ SkPoint dst[2];
+
+ static const SkPoint gEmpty[] = {
+ // sides
+ { L, CY }, { L - 10, CY },
+ { R, CY }, { R + 10, CY },
+ { CX, T }, { CX, T - 10 },
+ { CX, B }, { CX, B + 10 },
+ // corners
+ { L, T }, { L - 10, T - 10 },
+ { L, B }, { L - 10, B + 10 },
+ { R, T }, { R + 10, T - 10 },
+ { R, B }, { R + 10, B + 10 },
+ };
+ for (i = 0; i < SK_ARRAY_COUNT(gEmpty); i += 2) {
+ bool valid = SkLineClipper::IntersectLine(&gEmpty[i], gR, dst);
+ if (valid) {
+ SkDebugf("----- [%d] %g %g -> %g %g\n", i/2, dst[0].fX, dst[0].fY, dst[1].fX, dst[1].fY);
+ }
+ REPORTER_ASSERT(reporter, !valid);
+ }
+
+ static const SkPoint gFull[] = {
+ // diagonals, chords
+ { L, T }, { R, B },
+ { L, B }, { R, T },
+ { CX, T }, { CX, B },
+ { L, CY }, { R, CY },
+ { CX, T }, { R, CY },
+ { CX, T }, { L, CY },
+ { L, CY }, { CX, B },
+ { R, CY }, { CX, B },
+ // edges
+ { L, T }, { L, B },
+ { R, T }, { R, B },
+ { L, T }, { R, T },
+ { L, B }, { R, B },
+ };
+ for (i = 0; i < SK_ARRAY_COUNT(gFull); i += 2) {
+ bool valid = SkLineClipper::IntersectLine(&gFull[i], gR, dst);
+ if (!valid || memcmp(&gFull[i], dst, sizeof(dst))) {
+ SkDebugf("++++ [%d] %g %g -> %g %g\n", i/2, dst[0].fX, dst[0].fY, dst[1].fX, dst[1].fY);
+ }
+ REPORTER_ASSERT(reporter, valid && !memcmp(&gFull[i], dst, sizeof(dst)));
+ }
+
+ static const SkPoint gPartial[] = {
+ { L - 10, CY }, { CX, CY }, { L, CY }, { CX, CY },
+ { CX, T - 10 }, { CX, CY }, { CX, T }, { CX, CY },
+ { R + 10, CY }, { CX, CY }, { R, CY }, { CX, CY },
+ { CX, B + 10 }, { CX, CY }, { CX, B }, { CX, CY },
+ // extended edges
+ { L, T - 10 }, { L, B + 10 }, { L, T }, { L, B },
+ { R, T - 10 }, { R, B + 10 }, { R, T }, { R, B },
+ { L - 10, T }, { R + 10, T }, { L, T }, { R, T },
+ { L - 10, B }, { R + 10, B }, { L, B }, { R, B },
+ };
+ for (i = 0; i < SK_ARRAY_COUNT(gPartial); i += 4) {
+ bool valid = SkLineClipper::IntersectLine(&gPartial[i], gR, dst);
+ if (!valid || memcmp(&gPartial[i+2], dst, sizeof(dst))) {
+ SkDebugf("++++ [%d] %g %g -> %g %g\n", i/2, dst[0].fX, dst[0].fY, dst[1].fX, dst[1].fY);
+ }
+ REPORTER_ASSERT(reporter, valid &&
+ !memcmp(&gPartial[i+2], dst, sizeof(dst)));
+ }
+
+}
+
+DEF_TEST(Clipper, reporter) {
+ test_intersectline(reporter);
+ test_edgeclipper();
+ test_hairclipping(reporter);
+}
diff --git a/src/third_party/skia/tests/ColorFilterTest.cpp b/src/third_party/skia/tests/ColorFilterTest.cpp
new file mode 100644
index 0000000..f3f6a0a
--- /dev/null
+++ b/src/third_party/skia/tests/ColorFilterTest.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkColor.h"
+#include "SkColorFilter.h"
+#include "SkColorPriv.h"
+#include "SkLumaColorFilter.h"
+#include "SkReadBuffer.h"
+#include "SkWriteBuffer.h"
+#include "SkRandom.h"
+#include "SkXfermode.h"
+#include "Test.h"
+
+static SkColorFilter* reincarnate_colorfilter(SkFlattenable* obj) {
+ SkWriteBuffer wb;
+ wb.writeFlattenable(obj);
+
+ size_t size = wb.bytesWritten();
+ SkAutoSMalloc<1024> storage(size);
+ // make a copy into storage
+ wb.writeToMemory(storage.get());
+
+ SkReadBuffer rb(storage.get(), size);
+ return rb.readColorFilter();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define ILLEGAL_MODE ((SkXfermode::Mode)-1)
+
+DEF_TEST(ColorFilter, reporter) {
+ SkRandom rand;
+
+ for (int mode = 0; mode <= SkXfermode::kLastMode; mode++) {
+ SkColor color = rand.nextU();
+
+ // ensure we always get a filter, by avoiding the possibility of a
+ // special case that would return NULL (if color's alpha is 0 or 0xFF)
+ color = SkColorSetA(color, 0x7F);
+
+ SkColorFilter* cf = SkColorFilter::CreateModeFilter(color,
+ (SkXfermode::Mode)mode);
+
+ // allow for no filter if we're in Dst mode (its a no op)
+ if (SkXfermode::kDst_Mode == mode && NULL == cf) {
+ continue;
+ }
+
+ SkAutoUnref aur(cf);
+ REPORTER_ASSERT(reporter, cf);
+
+ SkColor c = ~color;
+ SkXfermode::Mode m = ILLEGAL_MODE;
+
+ SkColor expectedColor = color;
+ SkXfermode::Mode expectedMode = (SkXfermode::Mode)mode;
+
+// SkDebugf("--- mc [%d %x] ", mode, color);
+
+ REPORTER_ASSERT(reporter, cf->asColorMode(&c, &m));
+ // handle special-case folding by the factory
+ if (SkXfermode::kClear_Mode == mode) {
+ if (c != expectedColor) {
+ expectedColor = 0;
+ }
+ if (m != expectedMode) {
+ expectedMode = SkXfermode::kSrc_Mode;
+ }
+ }
+
+// SkDebugf("--- got [%d %x] expected [%d %x]\n", m, c, expectedMode, expectedColor);
+
+ REPORTER_ASSERT(reporter, c == expectedColor);
+ REPORTER_ASSERT(reporter, m == expectedMode);
+
+ {
+ SkColorFilter* cf2 = reincarnate_colorfilter(cf);
+ SkAutoUnref aur2(cf2);
+ REPORTER_ASSERT(reporter, cf2);
+
+ SkColor c2 = ~color;
+ SkXfermode::Mode m2 = ILLEGAL_MODE;
+ REPORTER_ASSERT(reporter, cf2->asColorMode(&c2, &m2));
+ REPORTER_ASSERT(reporter, c2 == expectedColor);
+ REPORTER_ASSERT(reporter, m2 == expectedMode);
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+DEF_TEST(LumaColorFilter, reporter) {
+ SkPMColor in, out;
+ SkAutoTUnref<SkColorFilter> lf(SkLumaColorFilter::Create());
+
+ // Applying luma to white produces black with the same transparency.
+ for (unsigned i = 0; i < 256; ++i) {
+ in = SkPackARGB32(i, i, i, i);
+ lf->filterSpan(&in, 1, &out);
+ REPORTER_ASSERT(reporter, SkGetPackedA32(out) == i);
+ REPORTER_ASSERT(reporter, SkGetPackedR32(out) == 0);
+ REPORTER_ASSERT(reporter, SkGetPackedG32(out) == 0);
+ REPORTER_ASSERT(reporter, SkGetPackedB32(out) == 0);
+ }
+
+ // Applying luma to black yields transparent black (luminance(black) == 0)
+ for (unsigned i = 0; i < 256; ++i) {
+ in = SkPackARGB32(i, 0, 0, 0);
+ lf->filterSpan(&in, 1, &out);
+ REPORTER_ASSERT(reporter, out == SK_ColorTRANSPARENT);
+ }
+
+ // For general colors, a luma filter generates black with an attenuated alpha channel.
+ for (unsigned i = 1; i < 256; ++i) {
+ in = SkPackARGB32(i, i, i / 2, i / 3);
+ lf->filterSpan(&in, 1, &out);
+ REPORTER_ASSERT(reporter, out != in);
+ REPORTER_ASSERT(reporter, SkGetPackedA32(out) <= i);
+ REPORTER_ASSERT(reporter, SkGetPackedR32(out) == 0);
+ REPORTER_ASSERT(reporter, SkGetPackedG32(out) == 0);
+ REPORTER_ASSERT(reporter, SkGetPackedB32(out) == 0);
+ }
+}
diff --git a/src/third_party/skia/tests/ColorPrivTest.cpp b/src/third_party/skia/tests/ColorPrivTest.cpp
new file mode 100644
index 0000000..02885d0
--- /dev/null
+++ b/src/third_party/skia/tests/ColorPrivTest.cpp
@@ -0,0 +1,43 @@
+#include "Test.h"
+
+#include "SkColorPriv.h"
+
+#define ASSERT(expr) REPORTER_ASSERT(r, expr)
+
+DEF_TEST(Splay, r) {
+ const SkPMColor color = 0xA1B2C3D4;
+
+ uint32_t ag, rb;
+ SkSplay(color, &ag, &rb);
+ ASSERT(ag == 0x00A100C3);
+ ASSERT(rb == 0x00B200D4);
+ ASSERT(SkUnsplay(ag << 8, rb << 8) == color);
+
+ const uint64_t agrb = SkSplay(color);
+ ASSERT(agrb == 0x00A100C300B200D4ULL);
+ ASSERT(SkUnsplay(agrb<<8) == color);
+}
+
+DEF_TEST(FourByteInterp, r) {
+ const SkPMColor src = 0xAB998877, dst = 0x66334455;
+ for (unsigned scale = 0; scale <= 256; scale++) {
+ ASSERT(SkFourByteInterp256(src, dst, scale) == SkFastFourByteInterp256(src, dst, scale));
+ }
+
+ for (unsigned scale = 0; scale < 256; scale++) {
+ // SkFourByteInterp and SkFastFourByteInterp convert from [0, 255] to [0, 256] differently.
+ // In particular, slow may end up a little too high (weirdly, fast is more accurate).
+ const SkPMColor slow = SkFourByteInterp(src, dst, scale);
+ const SkPMColor fast = SkFastFourByteInterp(src, dst, scale);
+
+ const int deltaA = SkGetPackedA32(slow) - SkGetPackedA32(fast);
+ const int deltaR = SkGetPackedR32(slow) - SkGetPackedR32(fast);
+ const int deltaG = SkGetPackedG32(slow) - SkGetPackedG32(fast);
+ const int deltaB = SkGetPackedB32(slow) - SkGetPackedB32(fast);
+
+ ASSERT(deltaA == 0 || deltaA == 1);
+ ASSERT(deltaR == 0 || deltaR == 1);
+ ASSERT(deltaG == 0 || deltaG == 1);
+ ASSERT(deltaB == 0 || deltaB == 1);
+ }
+}
diff --git a/src/third_party/skia/tests/ColorTest.cpp b/src/third_party/skia/tests/ColorTest.cpp
new file mode 100644
index 0000000..5a6f0fb
--- /dev/null
+++ b/src/third_party/skia/tests/ColorTest.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkColor.h"
+#include "SkColorPriv.h"
+#include "SkMathPriv.h"
+#include "SkRandom.h"
+#include "SkUnPreMultiply.h"
+#include "Test.h"
+
+#define GetPackedR16As32(packed) (SkGetPackedR16(dc) << (8 - SK_R16_BITS))
+#define GetPackedG16As32(packed) (SkGetPackedG16(dc) << (8 - SK_G16_BITS))
+#define GetPackedB16As32(packed) (SkGetPackedB16(dc) << (8 - SK_B16_BITS))
+
+static inline void test_premul(skiatest::Reporter* reporter) {
+ for (int a = 0; a <= 255; a++) {
+ for (int x = 0; x <= 255; x++) {
+ SkColor c0 = SkColorSetARGB(a, x, x, x);
+ SkPMColor p0 = SkPreMultiplyColor(c0);
+
+ SkColor c1 = SkUnPreMultiply::PMColorToColor(p0);
+ SkPMColor p1 = SkPreMultiplyColor(c1);
+
+ // we can't promise that c0 == c1, since c0 -> p0 is a many to one
+ // function, however, we can promise that p0 -> c1 -> p1 : p0 == p1
+ REPORTER_ASSERT(reporter, p0 == p1);
+
+ {
+ int ax = SkMulDiv255Ceiling(x, a);
+ REPORTER_ASSERT(reporter, ax <= a);
+ }
+ }
+ }
+}
+
+/**
+ This test fails: SkFourByteInterp does *not* preserve opaque destinations.
+ SkAlpha255To256 implemented as (alpha + 1) is faster than
+ (alpha + (alpha >> 7)), but inaccurate, and Skia intends to phase it out.
+*/
+/*
+static void test_interp(skiatest::Reporter* reporter) {
+ SkRandom r;
+
+ U8CPU a0 = 0;
+ U8CPU a255 = 255;
+ for (int i = 0; i < 200; i++) {
+ SkColor colorSrc = r.nextU();
+ SkColor colorDst = r.nextU();
+ SkPMColor src = SkPreMultiplyColor(colorSrc);
+ SkPMColor dst = SkPreMultiplyColor(colorDst);
+
+ REPORTER_ASSERT(reporter, SkFourByteInterp(src, dst, a0) == dst);
+ REPORTER_ASSERT(reporter, SkFourByteInterp(src, dst, a255) == src);
+ }
+}
+*/
+
+static inline void test_fast_interp(skiatest::Reporter* reporter) {
+ SkRandom r;
+
+ U8CPU a0 = 0;
+ U8CPU a255 = 255;
+ for (int i = 0; i < 200; i++) {
+ SkColor colorSrc = r.nextU();
+ SkColor colorDst = r.nextU();
+ SkPMColor src = SkPreMultiplyColor(colorSrc);
+ SkPMColor dst = SkPreMultiplyColor(colorDst);
+
+ REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a0) == dst);
+ REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a255) == src);
+ }
+}
+
+DEF_TEST(Color, reporter) {
+ test_premul(reporter);
+ //test_interp(reporter);
+ test_fast_interp(reporter);
+ //test_565blend();
+}
diff --git a/src/third_party/skia/tests/DashPathEffectTest.cpp b/src/third_party/skia/tests/DashPathEffectTest.cpp
new file mode 100644
index 0000000..1e53058
--- /dev/null
+++ b/src/third_party/skia/tests/DashPathEffectTest.cpp
@@ -0,0 +1,21 @@
+#include "Test.h"
+
+#include "SkDashPathEffect.h"
+#include "SkWriteBuffer.h"
+
+// crbug.com/348821 was rooted in SkDashPathEffect refusing to flatten and unflatten itself when
+// fInitialDashLength < 0 (a signal the effect is nonsense). Here we test that it flattens.
+
+DEF_TEST(DashPathEffectTest_crbug_348821, r) {
+ SkScalar intervals[] = { 1.76934361e+36f, 2.80259693e-45f }; // Values from bug.
+ const int count = 2;
+ SkScalar phase = SK_ScalarInfinity; // Used to force the bad fInitialDashLength = -1 path.
+ SkAutoTUnref<SkDashPathEffect> dash(SkDashPathEffect::Create(intervals, count, phase));
+
+ // NULL -> refuses to work with flattening framework.
+ REPORTER_ASSERT(r, dash->getFactory() != NULL);
+
+ SkWriteBuffer buffer;
+ buffer.writeFlattenable(dash);
+ REPORTER_ASSERT(r, buffer.bytesWritten() > 12); // We'd write 12 if broken, >=40 if not.
+}
diff --git a/src/third_party/skia/tests/DataRefTest.cpp b/src/third_party/skia/tests/DataRefTest.cpp
new file mode 100644
index 0000000..6a58c16
--- /dev/null
+++ b/src/third_party/skia/tests/DataRefTest.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkData.h"
+#include "SkDataTable.h"
+#include "SkOSFile.h"
+#include "SkReadBuffer.h"
+#include "SkWriteBuffer.h"
+#include "SkStream.h"
+#include "Test.h"
+
+static void test_is_equal(skiatest::Reporter* reporter,
+ const SkDataTable* a, const SkDataTable* b) {
+ REPORTER_ASSERT(reporter, a->count() == b->count());
+ for (int i = 0; i < a->count(); ++i) {
+ size_t sizea, sizeb;
+ const void* mema = a->at(i, &sizea);
+ const void* memb = b->at(i, &sizeb);
+ REPORTER_ASSERT(reporter, sizea == sizeb);
+ REPORTER_ASSERT(reporter, !memcmp(mema, memb, sizea));
+ }
+}
+
+static void test_datatable_is_empty(skiatest::Reporter* reporter,
+ SkDataTable* table) {
+ REPORTER_ASSERT(reporter, table->isEmpty());
+ REPORTER_ASSERT(reporter, 0 == table->count());
+}
+
+static void test_emptytable(skiatest::Reporter* reporter) {
+ SkAutoTUnref<SkDataTable> table0(SkDataTable::NewEmpty());
+ SkAutoTUnref<SkDataTable> table1(SkDataTable::NewCopyArrays(NULL, NULL, 0));
+ SkAutoTUnref<SkDataTable> table2(SkDataTable::NewCopyArray(NULL, 0, 0));
+ SkAutoTUnref<SkDataTable> table3(SkDataTable::NewArrayProc(NULL, 0, 0,
+ NULL, NULL));
+
+ test_datatable_is_empty(reporter, table0);
+ test_datatable_is_empty(reporter, table1);
+ test_datatable_is_empty(reporter, table2);
+ test_datatable_is_empty(reporter, table3);
+
+ test_is_equal(reporter, table0, table1);
+ test_is_equal(reporter, table0, table2);
+ test_is_equal(reporter, table0, table3);
+}
+
+static void test_simpletable(skiatest::Reporter* reporter) {
+ const int idata[] = { 1, 4, 9, 16, 25, 63 };
+ int icount = SK_ARRAY_COUNT(idata);
+ SkAutoTUnref<SkDataTable> itable(SkDataTable::NewCopyArray(idata,
+ sizeof(idata[0]),
+ icount));
+ REPORTER_ASSERT(reporter, itable->count() == icount);
+ for (int i = 0; i < icount; ++i) {
+ size_t size;
+ REPORTER_ASSERT(reporter, sizeof(int) == itable->atSize(i));
+ REPORTER_ASSERT(reporter, *itable->atT<int>(i, &size) == idata[i]);
+ REPORTER_ASSERT(reporter, sizeof(int) == size);
+ }
+}
+
+static void test_vartable(skiatest::Reporter* reporter) {
+ const char* str[] = {
+ "", "a", "be", "see", "deigh", "ef", "ggggggggggggggggggggggggggg"
+ };
+ int count = SK_ARRAY_COUNT(str);
+ size_t sizes[SK_ARRAY_COUNT(str)];
+ for (int i = 0; i < count; ++i) {
+ sizes[i] = strlen(str[i]) + 1;
+ }
+
+ SkAutoTUnref<SkDataTable> table(SkDataTable::NewCopyArrays(
+ (const void*const*)str, sizes, count));
+
+ REPORTER_ASSERT(reporter, table->count() == count);
+ for (int i = 0; i < count; ++i) {
+ size_t size;
+ REPORTER_ASSERT(reporter, table->atSize(i) == sizes[i]);
+ REPORTER_ASSERT(reporter, !strcmp(table->atT<const char>(i, &size),
+ str[i]));
+ REPORTER_ASSERT(reporter, size == sizes[i]);
+
+ const char* s = table->atStr(i);
+ REPORTER_ASSERT(reporter, strlen(s) == strlen(str[i]));
+ }
+}
+
+static void test_tablebuilder(skiatest::Reporter* reporter) {
+ const char* str[] = {
+ "", "a", "be", "see", "deigh", "ef", "ggggggggggggggggggggggggggg"
+ };
+ int count = SK_ARRAY_COUNT(str);
+
+ SkDataTableBuilder builder(16);
+
+ for (int i = 0; i < count; ++i) {
+ builder.append(str[i], strlen(str[i]) + 1);
+ }
+ SkAutoTUnref<SkDataTable> table(builder.detachDataTable());
+
+ REPORTER_ASSERT(reporter, table->count() == count);
+ for (int i = 0; i < count; ++i) {
+ size_t size;
+ REPORTER_ASSERT(reporter, table->atSize(i) == strlen(str[i]) + 1);
+ REPORTER_ASSERT(reporter, !strcmp(table->atT<const char>(i, &size),
+ str[i]));
+ REPORTER_ASSERT(reporter, size == strlen(str[i]) + 1);
+
+ const char* s = table->atStr(i);
+ REPORTER_ASSERT(reporter, strlen(s) == strlen(str[i]));
+ }
+}
+
+static void test_globaltable(skiatest::Reporter* reporter) {
+ static const int gData[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+ };
+ int count = SK_ARRAY_COUNT(gData);
+
+ SkAutoTUnref<SkDataTable> table(SkDataTable::NewArrayProc(gData,
+ sizeof(gData[0]), count, NULL, NULL));
+
+ REPORTER_ASSERT(reporter, table->count() == count);
+ for (int i = 0; i < count; ++i) {
+ size_t size;
+ REPORTER_ASSERT(reporter, table->atSize(i) == sizeof(int));
+ REPORTER_ASSERT(reporter, *table->atT<const char>(i, &size) == i);
+ REPORTER_ASSERT(reporter, sizeof(int) == size);
+ }
+}
+
+DEF_TEST(DataTable, reporter) {
+ test_emptytable(reporter);
+ test_simpletable(reporter);
+ test_vartable(reporter);
+ test_tablebuilder(reporter);
+ test_globaltable(reporter);
+}
+
+static void* gGlobal;
+
+static void delete_int_proc(const void* ptr, size_t len, void* context) {
+ int* data = (int*)ptr;
+ SkASSERT(context == gGlobal);
+ delete[] data;
+}
+
+static void assert_len(skiatest::Reporter* reporter, SkData* ref, size_t len) {
+ REPORTER_ASSERT(reporter, ref->size() == len);
+}
+
+static void assert_data(skiatest::Reporter* reporter, SkData* ref,
+ const void* data, size_t len) {
+ REPORTER_ASSERT(reporter, ref->size() == len);
+ REPORTER_ASSERT(reporter, !memcmp(ref->data(), data, len));
+}
+
+static void test_cstring(skiatest::Reporter* reporter) {
+ const char str[] = "Hello world";
+ size_t len = strlen(str);
+
+ SkAutoTUnref<SkData> r0(SkData::NewWithCopy(str, len + 1));
+ SkAutoTUnref<SkData> r1(SkData::NewWithCString(str));
+
+ REPORTER_ASSERT(reporter, r0->equals(r1));
+
+ SkAutoTUnref<SkData> r2(SkData::NewWithCString(NULL));
+ REPORTER_ASSERT(reporter, 1 == r2->size());
+ REPORTER_ASSERT(reporter, 0 == *r2->bytes());
+}
+
+static void test_files(skiatest::Reporter* reporter) {
+ SkString tmpDir = skiatest::Test::GetTmpDir();
+ if (tmpDir.isEmpty()) {
+ return;
+ }
+
+ SkString path = SkOSPath::Join(tmpDir.c_str(), "data_test");
+
+ const char s[] = "abcdefghijklmnopqrstuvwxyz";
+ {
+ SkFILEWStream writer(path.c_str());
+ if (!writer.isValid()) {
+ ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str());
+ return;
+ }
+ writer.write(s, 26);
+ }
+
+ SkFILE* file = sk_fopen(path.c_str(), kRead_SkFILE_Flag);
+ SkAutoTUnref<SkData> r1(SkData::NewFromFILE(file));
+ REPORTER_ASSERT(reporter, r1.get() != NULL);
+ REPORTER_ASSERT(reporter, r1->size() == 26);
+ REPORTER_ASSERT(reporter, strncmp(static_cast<const char*>(r1->data()), s, 26) == 0);
+
+ int fd = sk_fileno(file);
+ SkAutoTUnref<SkData> r2(SkData::NewFromFD(fd));
+ REPORTER_ASSERT(reporter, r2.get() != NULL);
+ REPORTER_ASSERT(reporter, r2->size() == 26);
+ REPORTER_ASSERT(reporter, strncmp(static_cast<const char*>(r2->data()), s, 26) == 0);
+}
+
+DEF_TEST(Data, reporter) {
+ const char* str = "We the people, in order to form a more perfect union.";
+ const int N = 10;
+
+ SkAutoTUnref<SkData> r0(SkData::NewEmpty());
+ SkAutoTUnref<SkData> r1(SkData::NewWithCopy(str, strlen(str)));
+ SkAutoTUnref<SkData> r2(SkData::NewWithProc(new int[N], N*sizeof(int),
+ delete_int_proc, gGlobal));
+ SkAutoTUnref<SkData> r3(SkData::NewSubset(r1, 7, 6));
+
+ assert_len(reporter, r0, 0);
+ assert_len(reporter, r1, strlen(str));
+ assert_len(reporter, r2, N * sizeof(int));
+ assert_len(reporter, r3, 6);
+
+ assert_data(reporter, r1, str, strlen(str));
+ assert_data(reporter, r3, "people", 6);
+
+ SkData* tmp = SkData::NewSubset(r1, strlen(str), 10);
+ assert_len(reporter, tmp, 0);
+ tmp->unref();
+ tmp = SkData::NewSubset(r1, 0, 0);
+ assert_len(reporter, tmp, 0);
+ tmp->unref();
+
+ test_cstring(reporter);
+ test_files(reporter);
+}
diff --git a/src/third_party/skia/tests/DeferredCanvasTest.cpp b/src/third_party/skia/tests/DeferredCanvasTest.cpp
new file mode 100644
index 0000000..d234c8c
--- /dev/null
+++ b/src/third_party/skia/tests/DeferredCanvasTest.cpp
@@ -0,0 +1,916 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "../src/image/SkImagePriv.h"
+#include "../src/image/SkSurface_Base.h"
+#include "SkBitmap.h"
+#include "SkBitmapDevice.h"
+#include "SkBitmapProcShader.h"
+#include "SkDeferredCanvas.h"
+#include "SkGradientShader.h"
+#include "SkShader.h"
+#include "SkSurface.h"
+#include "Test.h"
+#include "sk_tool_utils.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#else
+class GrContextFactory;
+#endif
+
+static const int gWidth = 2;
+static const int gHeight = 2;
+
+static void create(SkBitmap* bm, SkColor color) {
+ bm->allocN32Pixels(gWidth, gHeight);
+ bm->eraseColor(color);
+}
+
+static SkSurface* createSurface(SkColor color) {
+ SkSurface* surface = SkSurface::NewRasterPMColor(gWidth, gHeight);
+ surface->getCanvas()->clear(color);
+ return surface;
+}
+
+static SkPMColor read_pixel(SkSurface* surface, int x, int y) {
+ SkPMColor pixel = 0;
+ SkBitmap bitmap;
+ bitmap.installPixels(SkImageInfo::MakeN32Premul(1, 1), &pixel, 4);
+ SkCanvas canvas(bitmap);
+
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ surface->draw(&canvas, -SkIntToScalar(x), -SkIntToScalar(y), &paint);
+ return pixel;
+}
+
+class MockSurface : public SkSurface_Base {
+public:
+ MockSurface(int width, int height) : SkSurface_Base(width, height, NULL) {
+ clearCounts();
+ fBitmap.allocN32Pixels(width, height);
+ }
+
+ virtual SkCanvas* onNewCanvas() SK_OVERRIDE {
+ return SkNEW_ARGS(SkCanvas, (fBitmap));
+ }
+
+ virtual SkSurface* onNewSurface(const SkImageInfo&) SK_OVERRIDE {
+ return NULL;
+ }
+
+ virtual SkImage* onNewImageSnapshot() SK_OVERRIDE {
+ return SkNewImageFromBitmap(fBitmap, true);
+ }
+
+ virtual void onCopyOnWrite(ContentChangeMode mode) SK_OVERRIDE {
+ if (mode == SkSurface::kDiscard_ContentChangeMode) {
+ fDiscardCount++;
+ } else {
+ fRetainCount++;
+ }
+ }
+
+ void clearCounts() {
+ fDiscardCount = 0;
+ fRetainCount = 0;
+ }
+
+ int fDiscardCount, fRetainCount;
+ SkBitmap fBitmap;
+};
+
+static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter) {
+ SkAutoTUnref<MockSurface> surface(SkNEW_ARGS(MockSurface, (10, 10)));
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+
+ SkBitmap srcBitmap;
+ srcBitmap.allocPixels(SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType));
+ srcBitmap.eraseColor(SK_ColorGREEN);
+ // Tests below depend on this bitmap being recognized as opaque
+
+ // Preliminary sanity check: no copy on write if no active snapshot
+ surface->clearCounts();
+ canvas->clear(SK_ColorWHITE);
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->flush();
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ // Case 1: Discard notification happens upon flushing
+ // with an Image attached.
+ surface->clearCounts();
+ SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->clear(SK_ColorWHITE);
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->flush();
+ REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ // Case 2: Opaque writePixels
+ surface->clearCounts();
+ SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ // Case 3: writePixels that partially covers the canvas
+ surface->clearCounts();
+ SkAutoTUnref<SkImage> image3(canvas->newImageSnapshot());
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ // Case 4: unpremultiplied opaque writePixels that entirely
+ // covers the canvas
+ surface->clearCounts();
+ SkAutoTUnref<SkImage> image4(canvas->newImageSnapshot());
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->writePixels(srcBitmap, 0, 0);
+ REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->flush();
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ // Case 5: unpremultiplied opaque writePixels that partially
+ // covers the canvas
+ surface->clearCounts();
+ SkAutoTUnref<SkImage> image5(canvas->newImageSnapshot());
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->writePixels(srcBitmap, 5, 0);
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->flush();
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ // Case 6: unpremultiplied opaque writePixels that entirely
+ // covers the canvas, preceded by clear
+ surface->clearCounts();
+ SkAutoTUnref<SkImage> image6(canvas->newImageSnapshot());
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->clear(SK_ColorWHITE);
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->writePixels(srcBitmap, 0, 0);
+ REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->flush();
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ // Case 7: unpremultiplied opaque writePixels that partially
+ // covers the canvas, preceeded by a clear
+ surface->clearCounts();
+ SkAutoTUnref<SkImage> image7(canvas->newImageSnapshot());
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->clear(SK_ColorWHITE);
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->writePixels(srcBitmap, 5, 0);
+ REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount); // because of the clear
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->flush();
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ // Case 8: unpremultiplied opaque writePixels that partially
+ // covers the canvas, preceeded by a drawREct that partially
+ // covers the canvas
+ surface->clearCounts();
+ SkAutoTUnref<SkImage> image8(canvas->newImageSnapshot());
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ SkPaint paint;
+ canvas->drawRect(SkRect::MakeLTRB(0, 0, 5, 5), paint);
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->writePixels(srcBitmap, 5, 0);
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
+
+ surface->clearCounts();
+ canvas->flush();
+ REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
+ REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+}
+
+static void TestDeferredCanvasFlush(skiatest::Reporter* reporter) {
+ SkAutoTUnref<SkSurface> surface(createSurface(0xFFFFFFFF));
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+
+ canvas->clear(0x00000000);
+
+ // verify that clear was deferred
+ REPORTER_ASSERT(reporter, 0xFFFFFFFF == read_pixel(surface, 0, 0));
+
+ canvas->flush();
+
+ // verify that clear was executed
+ REPORTER_ASSERT(reporter, 0 == read_pixel(surface, 0, 0));
+}
+
+static void TestDeferredCanvasFreshFrame(skiatest::Reporter* reporter) {
+ SkRect fullRect;
+ fullRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth),
+ SkIntToScalar(gHeight));
+ SkRect partialRect;
+ partialRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0),
+ SkIntToScalar(1), SkIntToScalar(1));
+
+ SkAutoTUnref<SkSurface> surface(createSurface(0xFFFFFFFF));
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+
+ // verify that frame is intially fresh
+ REPORTER_ASSERT(reporter, canvas->isFreshFrame());
+ // no clearing op since last call to isFreshFrame -> not fresh
+ REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
+
+ // Verify that clear triggers a fresh frame
+ canvas->clear(0x00000000);
+ REPORTER_ASSERT(reporter, canvas->isFreshFrame());
+
+ // Verify that clear with saved state triggers a fresh frame
+ canvas->save();
+ canvas->clear(0x00000000);
+ canvas->restore();
+ REPORTER_ASSERT(reporter, canvas->isFreshFrame());
+
+ // Verify that clear within a layer does NOT trigger a fresh frame
+ canvas->saveLayer(NULL, NULL);
+ canvas->clear(0x00000000);
+ canvas->restore();
+ REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
+
+ // Verify that a clear with clipping triggers a fresh frame
+ // (clear is not affected by clipping)
+ canvas->save();
+ canvas->clipRect(partialRect, SkRegion::kIntersect_Op, false);
+ canvas->clear(0x00000000);
+ canvas->restore();
+ REPORTER_ASSERT(reporter, canvas->isFreshFrame());
+
+ // Verify that full frame rects with different forms of opaque paint
+ // trigger frames to be marked as fresh
+ {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setAlpha(255);
+ canvas->drawRect(fullRect, paint);
+ REPORTER_ASSERT(reporter, canvas->isFreshFrame());
+ }
+ {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setAlpha(255);
+ paint.setXfermodeMode(SkXfermode::kSrcIn_Mode);
+ canvas->drawRect(fullRect, paint);
+ REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
+ }
+ {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ SkBitmap bmp;
+ create(&bmp, 0xFFFFFFFF);
+ bmp.setAlphaType(kOpaque_SkAlphaType);
+ SkShader* shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ paint.setShader(shader)->unref();
+ canvas->drawRect(fullRect, paint);
+ REPORTER_ASSERT(reporter, canvas->isFreshFrame());
+ }
+
+ // Verify that full frame rects with different forms of non-opaque paint
+ // do not trigger frames to be marked as fresh
+ {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setAlpha(254);
+ canvas->drawRect(fullRect, paint);
+ REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
+ }
+ {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ // Defining a cone that partially overlaps the canvas
+ const SkPoint pt1 = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0));
+ const SkScalar r1 = SkIntToScalar(1);
+ const SkPoint pt2 = SkPoint::Make(SkIntToScalar(10), SkIntToScalar(0));
+ const SkScalar r2 = SkIntToScalar(5);
+ const SkColor colors[2] = {SK_ColorWHITE, SK_ColorWHITE};
+ const SkScalar pos[2] = {0, SK_Scalar1};
+ SkShader* shader = SkGradientShader::CreateTwoPointConical(
+ pt1, r1, pt2, r2, colors, pos, 2, SkShader::kClamp_TileMode);
+ paint.setShader(shader)->unref();
+ canvas->drawRect(fullRect, paint);
+ REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
+ }
+ {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ SkBitmap bmp;
+ create(&bmp, 0xFFFFFFFF);
+ bmp.setAlphaType(kPremul_SkAlphaType);
+ SkShader* shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ paint.setShader(shader)->unref();
+ canvas->drawRect(fullRect, paint);
+ REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
+ }
+
+ // Verify that incomplete coverage does not trigger a fresh frame
+ {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setAlpha(255);
+ canvas->drawRect(partialRect, paint);
+ REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
+ }
+
+ // Verify that incomplete coverage due to clipping does not trigger a fresh
+ // frame
+ {
+ canvas->save();
+ canvas->clipRect(partialRect, SkRegion::kIntersect_Op, false);
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setAlpha(255);
+ canvas->drawRect(fullRect, paint);
+ canvas->restore();
+ REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
+ }
+ {
+ canvas->save();
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setAlpha(255);
+ SkPath path;
+ path.addCircle(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(2));
+ canvas->clipPath(path, SkRegion::kIntersect_Op, false);
+ canvas->drawRect(fullRect, paint);
+ canvas->restore();
+ REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
+ }
+
+ // Verify that stroked rect does not trigger a fresh frame
+ {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setAlpha(255);
+ canvas->drawRect(fullRect, paint);
+ REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
+ }
+
+ // Verify kSrcMode triggers a fresh frame even with transparent color
+ {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setAlpha(100);
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas->drawRect(fullRect, paint);
+ REPORTER_ASSERT(reporter, canvas->isFreshFrame());
+ }
+}
+
+class MockDevice : public SkBitmapDevice {
+public:
+ MockDevice(const SkBitmap& bm) : SkBitmapDevice(bm) {
+ fDrawBitmapCallCount = 0;
+ }
+ virtual void drawBitmap(const SkDraw&, const SkBitmap&,
+ const SkMatrix&, const SkPaint&) SK_OVERRIDE {
+ fDrawBitmapCallCount++;
+ }
+
+ int fDrawBitmapCallCount;
+};
+
+class NotificationCounter : public SkDeferredCanvas::NotificationClient {
+public:
+ NotificationCounter() {
+ fPrepareForDrawCount = fStorageAllocatedChangedCount =
+ fFlushedDrawCommandsCount = fSkippedPendingDrawCommandsCount = 0;
+ }
+
+ virtual void prepareForDraw() SK_OVERRIDE {
+ fPrepareForDrawCount++;
+ }
+ virtual void storageAllocatedForRecordingChanged(size_t) SK_OVERRIDE {
+ fStorageAllocatedChangedCount++;
+ }
+ virtual void flushedDrawCommands() SK_OVERRIDE {
+ fFlushedDrawCommandsCount++;
+ }
+ virtual void skippedPendingDrawCommands() SK_OVERRIDE {
+ fSkippedPendingDrawCommandsCount++;
+ }
+
+ int fPrepareForDrawCount;
+ int fStorageAllocatedChangedCount;
+ int fFlushedDrawCommandsCount;
+ int fSkippedPendingDrawCommandsCount;
+
+private:
+ typedef SkDeferredCanvas::NotificationClient INHERITED;
+};
+
+// Verifies that the deferred canvas triggers a flush when its memory
+// limit is exceeded
+static void TestDeferredCanvasMemoryLimit(skiatest::Reporter* reporter) {
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(100, 100));
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+
+ NotificationCounter notificationCounter;
+ canvas->setNotificationClient(¬ificationCounter);
+
+ canvas->setMaxRecordingStorage(160000);
+
+ SkBitmap sourceImage;
+ // 100 by 100 image, takes 40,000 bytes in memory
+ sourceImage.allocN32Pixels(100, 100);
+ sourceImage.eraseColor(SK_ColorGREEN);
+
+ for (int i = 0; i < 5; i++) {
+ sourceImage.notifyPixelsChanged(); // to force re-serialization
+ canvas->drawBitmap(sourceImage, 0, 0, NULL);
+ }
+
+ REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
+}
+
+static void TestDeferredCanvasSilentFlush(skiatest::Reporter* reporter) {
+ SkAutoTUnref<SkSurface> surface(createSurface(0));
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+
+ NotificationCounter notificationCounter;
+ canvas->setNotificationClient(¬ificationCounter);
+
+ canvas->silentFlush(); // will skip the initial clear that was recorded in createSurface
+
+ REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
+ REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
+}
+
+static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(100, 100));
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+
+ NotificationCounter notificationCounter;
+ canvas->setNotificationClient(¬ificationCounter);
+
+ const int imageCount = 2;
+ SkBitmap sourceImages[imageCount];
+ for (int i = 0; i < imageCount; i++) {
+ sourceImages[i].allocN32Pixels(100, 100);
+ sourceImages[i].eraseColor(SK_ColorGREEN);
+ }
+
+ size_t bitmapSize = sourceImages[0].getSize();
+
+ canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
+ REPORTER_ASSERT(reporter, 1 == notificationCounter.fStorageAllocatedChangedCount);
+ // stored bitmap + drawBitmap command
+ REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > bitmapSize);
+
+ // verify that nothing can be freed at this point
+ REPORTER_ASSERT(reporter, 0 == canvas->freeMemoryIfPossible(~0U));
+
+ // verify that flush leaves image in cache
+ REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
+ REPORTER_ASSERT(reporter, 0 == notificationCounter.fPrepareForDrawCount);
+ canvas->flush();
+ REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
+ REPORTER_ASSERT(reporter, 1 == notificationCounter.fPrepareForDrawCount);
+ REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() >= bitmapSize);
+
+ // verify that after a flush, cached image can be freed
+ REPORTER_ASSERT(reporter, canvas->freeMemoryIfPossible(~0U) >= bitmapSize);
+
+ // Verify that caching works for avoiding multiple copies of the same bitmap
+ canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
+ REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
+ canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
+ REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
+ REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
+ REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < 2 * bitmapSize);
+
+ // Verify partial eviction based on bytesToFree
+ canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
+ REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
+ canvas->flush();
+ REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
+ REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2 * bitmapSize);
+ size_t bytesFreed = canvas->freeMemoryIfPossible(1);
+ REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
+ REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
+ REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
+
+ // Verifiy that partial purge works, image zero is in cache but not reffed by
+ // a pending draw, while image 1 is locked-in.
+ canvas->freeMemoryIfPossible(~0U);
+ REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
+ canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
+ canvas->flush();
+ canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
+ bytesFreed = canvas->freeMemoryIfPossible(~0U);
+ // only one bitmap should have been freed.
+ REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
+ REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
+ // Clear for next test
+ canvas->flush();
+ canvas->freeMemoryIfPossible(~0U);
+ REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < bitmapSize);
+
+ // Verify the image cache is sensitive to genID bumps
+ canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
+ sourceImages[1].notifyPixelsChanged();
+ canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
+ REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2*bitmapSize);
+
+ // Verify that nothing in this test caused commands to be skipped
+ REPORTER_ASSERT(reporter, 0 == notificationCounter.fSkippedPendingDrawCommandsCount);
+}
+
+static void TestDeferredCanvasSkip(skiatest::Reporter* reporter) {
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(100, 100));
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+
+ NotificationCounter notificationCounter;
+ canvas->setNotificationClient(¬ificationCounter);
+ canvas->clear(0x0);
+ REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
+ REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
+ canvas->flush();
+ REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
+ REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
+
+}
+
+static void TestDeferredCanvasBitmapShaderNoLeak(skiatest::Reporter* reporter) {
+ // This is a regression test for crbug.com/155875
+ // This test covers a code path that inserts bitmaps into the bitmap heap through the
+ // flattening of SkBitmapProcShaders. The refcount in the bitmap heap is maintained through
+ // the flattening and unflattening of the shader.
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(100, 100));
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+ // test will fail if nbIterations is not in sync with
+ // BITMAPS_TO_KEEP in SkGPipeWrite.cpp
+ const int nbIterations = 5;
+ size_t bytesAllocated = 0;
+ for(int pass = 0; pass < 2; ++pass) {
+ for(int i = 0; i < nbIterations; ++i) {
+ SkPaint paint;
+ SkBitmap paintPattern;
+ paintPattern.allocN32Pixels(10, 10);
+ paintPattern.eraseColor(SK_ColorGREEN);
+ paint.setShader(SkNEW_ARGS(SkBitmapProcShader,
+ (paintPattern, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)))->unref();
+ canvas->drawPaint(paint);
+ canvas->flush();
+
+ // In the first pass, memory allocation should be monotonically increasing as
+ // the bitmap heap slots fill up. In the second pass memory allocation should be
+ // stable as bitmap heap slots get recycled.
+ size_t newBytesAllocated = canvas->storageAllocatedForRecording();
+ if (pass == 0) {
+ REPORTER_ASSERT(reporter, newBytesAllocated > bytesAllocated);
+ bytesAllocated = newBytesAllocated;
+ } else {
+ REPORTER_ASSERT(reporter, newBytesAllocated == bytesAllocated);
+ }
+ }
+ }
+ // All cached resources should be evictable since last canvas call was flush()
+ canvas->freeMemoryIfPossible(~0U);
+ REPORTER_ASSERT(reporter, 0 == canvas->storageAllocatedForRecording());
+}
+
+static void TestDeferredCanvasBitmapSizeThreshold(skiatest::Reporter* reporter) {
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(100, 100));
+
+ SkBitmap sourceImage;
+ // 100 by 100 image, takes 40,000 bytes in memory
+ sourceImage.allocN32Pixels(100, 100);
+ sourceImage.eraseColor(SK_ColorGREEN);
+
+ // 1 under : should not store the image
+ {
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+ canvas->setBitmapSizeThreshold(39999);
+ canvas->drawBitmap(sourceImage, 0, 0, NULL);
+ size_t newBytesAllocated = canvas->storageAllocatedForRecording();
+ REPORTER_ASSERT(reporter, newBytesAllocated == 0);
+ }
+
+ // exact value : should store the image
+ {
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+ canvas->setBitmapSizeThreshold(40000);
+ canvas->drawBitmap(sourceImage, 0, 0, NULL);
+ size_t newBytesAllocated = canvas->storageAllocatedForRecording();
+ REPORTER_ASSERT(reporter, newBytesAllocated > 0);
+ }
+
+ // 1 over : should still store the image
+ {
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+ canvas->setBitmapSizeThreshold(40001);
+ canvas->drawBitmap(sourceImage, 0, 0, NULL);
+ size_t newBytesAllocated = canvas->storageAllocatedForRecording();
+ REPORTER_ASSERT(reporter, newBytesAllocated > 0);
+ }
+}
+
+
+typedef const void* PixelPtr;
+// Returns an opaque pointer which, either points to a GrTexture or RAM pixel
+// buffer. Used to test pointer equality do determine whether a surface points
+// to the same pixel data storage as before.
+static PixelPtr get_surface_ptr(SkSurface* surface, bool useGpu) {
+#if SK_SUPPORT_GPU
+ if (useGpu) {
+ return surface->getCanvas()->internal_private_accessTopLayerRenderTarget()->asTexture();
+ } else
+#endif
+ {
+ return surface->peekPixels(NULL, NULL);
+ }
+}
+
+static void TestDeferredCanvasSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
+ SkImageInfo imageSpec = SkImageInfo::MakeN32Premul(10, 10);
+ bool useGpu = SkToBool(factory);
+ int cnt;
+#if SK_SUPPORT_GPU
+ if (useGpu) {
+ cnt = GrContextFactory::kGLContextTypeCnt;
+ } else {
+ cnt = 1;
+ }
+#else
+ SkASSERT(!useGpu);
+ cnt = 1;
+#endif
+ for (int i = 0; i < cnt; ++i) {
+ SkSurface* surface;
+#if SK_SUPPORT_GPU
+ if (useGpu) {
+ GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
+ if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
+ continue;
+ }
+ GrContext* context = factory->get(glCtxType);
+ if (NULL == context) {
+ return;
+ }
+
+ surface = SkSurface::NewRenderTarget(context, imageSpec, 0, NULL);
+ } else
+#endif
+ {
+ surface = SkSurface::NewRaster(imageSpec);
+ }
+ SkASSERT(surface);
+ SkAutoTUnref<SkSurface> aur(surface);
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface));
+
+ SkImage* image1 = canvas->newImageSnapshot();
+ SkAutoTUnref<SkImage> aur_i1(image1);
+ PixelPtr pixels1 = get_surface_ptr(surface, useGpu);
+ // The following clear would normally trigger a copy on write, but
+ // it won't because rendering is deferred.
+ canvas->clear(SK_ColorBLACK);
+ // Obtaining a snapshot directly from the surface (as opposed to the
+ // SkDeferredCanvas) will not trigger a flush of deferred draw operations
+ // and will therefore return the same image as the previous snapshot.
+ SkImage* image2 = surface->newImageSnapshot();
+ SkAutoTUnref<SkImage> aur_i2(image2);
+ // Images identical because of deferral
+ REPORTER_ASSERT(reporter, image1->uniqueID() == image2->uniqueID());
+ // Now we obtain a snpshot via the deferred canvas, which triggers a flush.
+ // Because there is a pending clear, this will generate a different image.
+ SkImage* image3 = canvas->newImageSnapshot();
+ SkAutoTUnref<SkImage> aur_i3(image3);
+ REPORTER_ASSERT(reporter, image1->uniqueID() != image3->uniqueID());
+ // Verify that backing store is now a different buffer because of copy on
+ // write
+ PixelPtr pixels2 = get_surface_ptr(surface, useGpu);
+ REPORTER_ASSERT(reporter, pixels1 != pixels2);
+ // Verify copy-on write with a draw operation that gets deferred by
+ // the in order draw buffer.
+ SkPaint paint;
+ canvas->drawPaint(paint);
+ SkImage* image4 = canvas->newImageSnapshot(); // implicit flush
+ SkAutoTUnref<SkImage> aur_i4(image4);
+ REPORTER_ASSERT(reporter, image4->uniqueID() != image3->uniqueID());
+ PixelPtr pixels3 = get_surface_ptr(surface, useGpu);
+ REPORTER_ASSERT(reporter, pixels2 != pixels3);
+ // Verify that a direct canvas flush with a pending draw does not trigger
+ // a copy on write when the surface is not sharing its buffer with an
+ // SkImage.
+ canvas->clear(SK_ColorWHITE);
+ canvas->flush();
+ PixelPtr pixels4 = get_surface_ptr(surface, useGpu);
+ canvas->drawPaint(paint);
+ canvas->flush();
+ PixelPtr pixels5 = get_surface_ptr(surface, useGpu);
+ REPORTER_ASSERT(reporter, pixels4 == pixels5);
+ }
+}
+
+static void TestDeferredCanvasSetSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
+ SkImageInfo imageSpec = SkImageInfo::MakeN32Premul(10, 10);
+ SkSurface* surface;
+ SkSurface* alternateSurface;
+ bool useGpu = SkToBool(factory);
+ int cnt;
+#if SK_SUPPORT_GPU
+ if (useGpu) {
+ cnt = GrContextFactory::kGLContextTypeCnt;
+ } else {
+ cnt = 1;
+ }
+#else
+ SkASSERT(!useGpu);
+ cnt = 1;
+#endif
+
+ for (int i = 0; i < cnt; ++i) {
+#if SK_SUPPORT_GPU
+ if (useGpu) {
+ GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
+ if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
+ continue;
+ }
+ GrContext* context = factory->get(glCtxType);
+ if (NULL == context) {
+ continue;
+ }
+ surface = SkSurface::NewRenderTarget(context, imageSpec, 0, NULL);
+ alternateSurface = SkSurface::NewRenderTarget(context, imageSpec, 0, NULL);
+ } else
+#endif
+ {
+ surface = SkSurface::NewRaster(imageSpec);
+ alternateSurface = SkSurface::NewRaster(imageSpec);
+ }
+ SkASSERT(surface);
+ SkASSERT(alternateSurface);
+ SkAutoTUnref<SkSurface> aur1(surface);
+ SkAutoTUnref<SkSurface> aur2(alternateSurface);
+ PixelPtr pixels1 = get_surface_ptr(surface, useGpu);
+ PixelPtr pixels2 = get_surface_ptr(alternateSurface, useGpu);
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface));
+ SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
+ canvas->setSurface(alternateSurface);
+ SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
+ REPORTER_ASSERT(reporter, image1->uniqueID() != image2->uniqueID());
+ // Verify that none of the above operations triggered a surface copy on write.
+ REPORTER_ASSERT(reporter, get_surface_ptr(surface, useGpu) == pixels1);
+ REPORTER_ASSERT(reporter, get_surface_ptr(alternateSurface, useGpu) == pixels2);
+ // Verify that a flushed draw command will trigger a copy on write on alternateSurface.
+ canvas->clear(SK_ColorWHITE);
+ canvas->flush();
+ REPORTER_ASSERT(reporter, get_surface_ptr(surface, useGpu) == pixels1);
+ REPORTER_ASSERT(reporter, get_surface_ptr(alternateSurface, useGpu) != pixels2);
+ }
+}
+
+static void TestDeferredCanvasCreateCompatibleDevice(skiatest::Reporter* reporter) {
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(100, 100));
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+
+ NotificationCounter notificationCounter;
+ canvas->setNotificationClient(¬ificationCounter);
+
+ SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
+ SkAutoTUnref<SkSurface> secondarySurface(canvas->newSurface(info));
+
+ SkRect rect = SkRect::MakeWH(5, 5);
+ SkPaint paint;
+ // After spawning a compatible canvas:
+ // 1) Verify that secondary canvas is usable and does not report to the notification client.
+ surface->getCanvas()->drawRect(rect, paint);
+ REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 0);
+ // 2) Verify that original canvas is usable and still reports to the notification client.
+ canvas->drawRect(rect, paint);
+ REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 1);
+}
+
+static void TestDeferredCanvasGetCanvasSize(skiatest::Reporter* reporter) {
+ SkRect rect;
+ rect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth), SkIntToScalar(gHeight));
+ SkRect clip;
+ clip.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(1), SkIntToScalar(1));
+
+ SkPaint paint;
+ SkISize size = SkISize::Make(gWidth, gHeight);
+
+ SkAutoTUnref<SkSurface> surface(createSurface(0xFFFFFFFF));
+ SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
+ SkSurface* newSurface = SkSurface::NewRasterPMColor(4, 4);
+ SkAutoTUnref<SkSurface> aur(newSurface);
+
+ for (int i = 0; i < 2; ++i) {
+ if (i == 1) {
+ canvas->setSurface(newSurface);
+ size = SkISize::Make(4, 4);
+ }
+
+ // verify that canvas size is correctly initialized or set
+ REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
+
+ // Verify that clear, clip and draw the canvas will not change its size
+ canvas->clear(0x00000000);
+ canvas->clipRect(clip, SkRegion::kIntersect_Op, false);
+ canvas->drawRect(rect, paint);
+ REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
+
+ // Verify that flush the canvas will not change its size
+ canvas->flush();
+ REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
+
+ // Verify that clear canvas with saved state will not change its size
+ canvas->save();
+ canvas->clear(0xFFFFFFFF);
+ REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
+
+ // Verify that restore canvas state will not change its size
+ canvas->restore();
+ REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
+
+ // Verify that clear within a layer will not change canvas size
+ canvas->saveLayer(&clip, &paint);
+ canvas->clear(0x00000000);
+ REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
+
+ // Verify that restore from a layer will not change canvas size
+ canvas->restore();
+ REPORTER_ASSERT(reporter, size == canvas->getCanvasSize());
+ }
+}
+
+DEF_TEST(DeferredCanvas_CPU, reporter) {
+ TestDeferredCanvasFlush(reporter);
+ TestDeferredCanvasSilentFlush(reporter);
+ TestDeferredCanvasFreshFrame(reporter);
+ TestDeferredCanvasMemoryLimit(reporter);
+ TestDeferredCanvasBitmapCaching(reporter);
+ TestDeferredCanvasSkip(reporter);
+ TestDeferredCanvasBitmapShaderNoLeak(reporter);
+ TestDeferredCanvasBitmapSizeThreshold(reporter);
+ TestDeferredCanvasCreateCompatibleDevice(reporter);
+ TestDeferredCanvasWritePixelsToSurface(reporter);
+ TestDeferredCanvasGetCanvasSize(reporter);
+ TestDeferredCanvasSurface(reporter, NULL);
+ TestDeferredCanvasSetSurface(reporter, NULL);
+}
+
+DEF_GPUTEST(DeferredCanvas_GPU, reporter, factory) {
+ if (factory != NULL) {
+ TestDeferredCanvasSurface(reporter, factory);
+ TestDeferredCanvasSetSurface(reporter, factory);
+ }
+}
diff --git a/src/third_party/skia/tests/DequeTest.cpp b/src/third_party/skia/tests/DequeTest.cpp
new file mode 100644
index 0000000..04b1f40
--- /dev/null
+++ b/src/third_party/skia/tests/DequeTest.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkDeque.h"
+#include "Test.h"
+
+static void assert_count(skiatest::Reporter* reporter, const SkDeque& deq, int count) {
+ if (0 == count) {
+ REPORTER_ASSERT(reporter, deq.empty());
+ REPORTER_ASSERT(reporter, 0 == deq.count());
+ REPORTER_ASSERT(reporter, sizeof(int) == deq.elemSize());
+ REPORTER_ASSERT(reporter, NULL == deq.front());
+ REPORTER_ASSERT(reporter, NULL == deq.back());
+ } else {
+ REPORTER_ASSERT(reporter, !deq.empty());
+ REPORTER_ASSERT(reporter, count == deq.count());
+ REPORTER_ASSERT(reporter, sizeof(int) == deq.elemSize());
+ REPORTER_ASSERT(reporter, deq.front());
+ REPORTER_ASSERT(reporter, deq.back());
+ if (1 == count) {
+ REPORTER_ASSERT(reporter, deq.back() == deq.front());
+ } else {
+ REPORTER_ASSERT(reporter, deq.back() != deq.front());
+ }
+ }
+}
+
+static void assert_iter(skiatest::Reporter* reporter, const SkDeque& deq,
+ int max, int min) {
+ // test forward iteration
+ SkDeque::Iter iter(deq, SkDeque::Iter::kFront_IterStart);
+ void* ptr;
+
+ int value = max;
+ while ((ptr = iter.next())) {
+ REPORTER_ASSERT(reporter, value == *(int*)ptr);
+ value -= 1;
+ }
+ REPORTER_ASSERT(reporter, value+1 == min);
+
+ // test reverse iteration
+ iter.reset(deq, SkDeque::Iter::kBack_IterStart);
+
+ value = min;
+ while ((ptr = iter.prev())) {
+ REPORTER_ASSERT(reporter, value == *(int*)ptr);
+ value += 1;
+ }
+ REPORTER_ASSERT(reporter, value-1 == max);
+
+ // test mixed iteration
+ iter.reset(deq, SkDeque::Iter::kFront_IterStart);
+
+ value = max;
+ // forward iteration half-way
+ for (int i = 0; i < deq.count()/2 && (ptr = iter.next()); i++) {
+ REPORTER_ASSERT(reporter, value == *(int*)ptr);
+ value -= 1;
+ }
+ // then back down w/ reverse iteration
+ while ((ptr = iter.prev())) {
+ REPORTER_ASSERT(reporter, value == *(int*)ptr);
+ value += 1;
+ }
+ REPORTER_ASSERT(reporter, value-1 == max);
+}
+
+// This helper is intended to only give the unit test access to SkDeque's
+// private numBlocksAllocated method
+class DequeUnitTestHelper {
+public:
+ int fNumBlocksAllocated;
+
+ DequeUnitTestHelper(const SkDeque& deq) {
+ fNumBlocksAllocated = deq.numBlocksAllocated();
+ }
+};
+
+static void assert_blocks(skiatest::Reporter* reporter,
+ const SkDeque& deq,
+ int allocCount) {
+ DequeUnitTestHelper helper(deq);
+
+ if (0 == deq.count()) {
+ REPORTER_ASSERT(reporter, 1 == helper.fNumBlocksAllocated);
+ } else {
+ int expected = (deq.count() + allocCount - 1) / allocCount;
+ // A block isn't freed in the deque when it first becomes empty so
+ // sometimes an extra block lingers around
+ REPORTER_ASSERT(reporter,
+ expected == helper.fNumBlocksAllocated ||
+ expected+1 == helper.fNumBlocksAllocated);
+ }
+}
+
+static void TestSub(skiatest::Reporter* reporter, int allocCount) {
+ SkDeque deq(sizeof(int), allocCount);
+ int i;
+
+ // test pushing on the front
+
+ assert_count(reporter, deq, 0);
+ for (i = 1; i <= 10; i++) {
+ *(int*)deq.push_front() = i;
+ }
+ assert_count(reporter, deq, 10);
+ assert_iter(reporter, deq, 10, 1);
+ assert_blocks(reporter, deq, allocCount);
+
+ for (i = 0; i < 5; i++) {
+ deq.pop_front();
+ }
+ assert_count(reporter, deq, 5);
+ assert_iter(reporter, deq, 5, 1);
+ assert_blocks(reporter, deq, allocCount);
+
+ for (i = 0; i < 5; i++) {
+ deq.pop_front();
+ }
+ assert_count(reporter, deq, 0);
+ assert_blocks(reporter, deq, allocCount);
+
+ // now test pushing on the back
+
+ for (i = 10; i >= 1; --i) {
+ *(int*)deq.push_back() = i;
+ }
+ assert_count(reporter, deq, 10);
+ assert_iter(reporter, deq, 10, 1);
+ assert_blocks(reporter, deq, allocCount);
+
+ for (i = 0; i < 5; i++) {
+ deq.pop_back();
+ }
+ assert_count(reporter, deq, 5);
+ assert_iter(reporter, deq, 10, 6);
+ assert_blocks(reporter, deq, allocCount);
+
+ for (i = 0; i < 5; i++) {
+ deq.pop_back();
+ }
+ assert_count(reporter, deq, 0);
+ assert_blocks(reporter, deq, allocCount);
+
+ // now test pushing/popping on both ends
+
+ *(int*)deq.push_front() = 5;
+ *(int*)deq.push_back() = 4;
+ *(int*)deq.push_front() = 6;
+ *(int*)deq.push_back() = 3;
+ *(int*)deq.push_front() = 7;
+ *(int*)deq.push_back() = 2;
+ *(int*)deq.push_front() = 8;
+ *(int*)deq.push_back() = 1;
+ assert_count(reporter, deq, 8);
+ assert_iter(reporter, deq, 8, 1);
+ assert_blocks(reporter, deq, allocCount);
+}
+
+DEF_TEST(Deque, reporter) {
+ // test it once with the default allocation count
+ TestSub(reporter, 1);
+ // test it again with a generous allocation count
+ TestSub(reporter, 10);
+}
diff --git a/src/third_party/skia/tests/DeviceLooperTest.cpp b/src/third_party/skia/tests/DeviceLooperTest.cpp
new file mode 100644
index 0000000..5735043
--- /dev/null
+++ b/src/third_party/skia/tests/DeviceLooperTest.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkDeviceLooper.h"
+#include "SkRasterClip.h"
+#include "Test.h"
+
+static void make_bm(SkBitmap* bm, int w, int h) {
+ bm->allocPixels(SkImageInfo::Make(w, h, kAlpha_8_SkColorType,
+ kPremul_SkAlphaType));
+}
+
+static bool equal(const SkRasterClip& a, const SkRasterClip& b) {
+ if (a.isBW()) {
+ return b.isBW() && a.bwRgn() == b.bwRgn();
+ } else {
+ return a.isAA() && a.aaRgn() == b.aaRgn();
+ }
+}
+
+static const struct {
+ SkISize fDevSize;
+ SkIRect fRCBounds;
+ SkIRect fRect;
+} gRec[] = {
+ { { 4000, 10 }, { 0, 0, 4000, 10 }, { 0, 0, 4000, 4000 } },
+ { { 10, 4000 }, { 0, 0, 10, 4000 }, { 0, 0, 4000, 4000 } },
+ // very large devce, small rect
+ { { 32000, 10 }, { 0, 0, 32000, 10 }, { 0, 0, 4000, 4000 } },
+ { { 10, 32000 }, { 0, 0, 10, 32000 }, { 0, 0, 4000, 4000 } },
+ // very large device, small clip
+ { { 32000, 10 }, { 0, 0, 4000, 10 }, { 0, 0, 32000, 32000 } },
+ { { 10, 32000 }, { 0, 0, 10, 4000 }, { 0, 0, 32000, 32000 } },
+};
+
+static void test_simple(skiatest::Reporter* reporter) {
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
+ SkBitmap bitmap;
+ make_bm(&bitmap, gRec[i].fDevSize.width(), gRec[i].fDevSize.height());
+
+ SkRasterClip rc(gRec[i].fRCBounds);
+
+ for (int aa = 0; aa <= 1; ++aa) {
+ SkDeviceLooper looper(bitmap, rc, gRec[i].fRect, SkToBool(aa));
+
+ bool valid = looper.next();
+ REPORTER_ASSERT(reporter, valid);
+ if (valid) {
+ REPORTER_ASSERT(reporter, looper.getBitmap().width() == bitmap.width());
+ REPORTER_ASSERT(reporter, looper.getBitmap().height() == bitmap.height());
+ REPORTER_ASSERT(reporter, equal(looper.getRC(), rc));
+
+ REPORTER_ASSERT(reporter, !looper.next());
+ }
+ }
+ // test that a rect that doesn't intersect returns no loops
+ {
+ SkIRect r = rc.getBounds();
+ r.offset(r.width(), 0);
+ SkDeviceLooper looper(bitmap, rc, r, false);
+ REPORTER_ASSERT(reporter, !looper.next());
+ }
+ }
+}
+
+// mask-bits are interpreted as the areas where the clip is visible
+// [ 0x01 0x02 ]
+// [ 0x04 0x08 ]
+//
+static void make_rgn(SkRegion* rgn, int w, int h, unsigned mask) {
+ SkASSERT(SkAlign2(w));
+ SkASSERT(SkAlign2(h));
+ w >>= 1;
+ h >>= 1;
+ const SkIRect baseR = SkIRect::MakeWH(w, h);
+
+ int bit = 1;
+ for (int y = 0; y <= 1; ++y) {
+ for (int x = 0; x <= 1; ++x) {
+ if (mask & bit) {
+ SkIRect r = baseR;
+ r.offset(x * w, y * h);
+ rgn->op(r, SkRegion::kUnion_Op);
+ }
+ bit <<= 1;
+ }
+ }
+}
+
+static void test_complex(skiatest::Reporter* reporter) {
+ // choose size values that will result in 4 quadrants, given fAA setting
+ const int BW_SIZE = 17 * 1000;
+ const int AA_SIZE = 7 * 1000;
+
+ struct {
+ SkISize fSize;
+ bool fAA;
+ } const gRec[] = {
+ { { BW_SIZE, BW_SIZE }, false },
+ { { AA_SIZE, AA_SIZE }, true },
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
+ const int w = gRec[i].fSize.width();
+ const int h = gRec[i].fSize.height();
+
+ SkBitmap bitmap;
+ make_bm(&bitmap, w, h);
+
+ const SkIRect rect = SkIRect::MakeWH(w, h);
+
+ // mask-bits are interpreted as the areas where the clip is visible
+ // [ 0x01 0x02 ]
+ // [ 0x04 0x08 ]
+ //
+ for (int mask = 0; mask <= 15; ++mask) {
+ SkRegion rgn;
+ make_rgn(&rgn, w, h, mask);
+
+ SkRasterClip rc;
+ rc.op(rgn, SkRegion::kReplace_Op);
+
+ SkDeviceLooper looper(bitmap, rc, rect, gRec[i].fAA);
+ while (looper.next()) {
+ REPORTER_ASSERT(reporter, !looper.getRC().isEmpty());
+ }
+ }
+ }
+}
+
+DEF_TEST(DeviceLooper, reporter) {
+ test_simple(reporter);
+ test_complex(reporter);
+}
diff --git a/src/third_party/skia/tests/DiscardableMemoryPoolTest.cpp b/src/third_party/skia/tests/DiscardableMemoryPoolTest.cpp
new file mode 100644
index 0000000..e0145bc
--- /dev/null
+++ b/src/third_party/skia/tests/DiscardableMemoryPoolTest.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkDiscardableMemoryPool.h"
+
+#include "Test.h"
+
+DEF_TEST(DiscardableMemoryPool, reporter) {
+ SkAutoTUnref<SkDiscardableMemoryPool> pool(
+ SkDiscardableMemoryPool::Create(1, NULL));
+ pool->setRAMBudget(3);
+ REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed());
+
+ SkAutoTDelete<SkDiscardableMemory> dm1(pool->create(100));
+ REPORTER_ASSERT(reporter, dm1->data() != NULL);
+ REPORTER_ASSERT(reporter, 100 == pool->getRAMUsed());
+ dm1->unlock();
+ REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed());
+ REPORTER_ASSERT(reporter, !dm1->lock());
+
+
+ SkAutoTDelete<SkDiscardableMemory> dm2(pool->create(200));
+ REPORTER_ASSERT(reporter, 200 == pool->getRAMUsed());
+ pool->setRAMBudget(400);
+ dm2->unlock();
+ REPORTER_ASSERT(reporter, 200 == pool->getRAMUsed());
+ REPORTER_ASSERT(reporter, dm2->lock());
+ dm2->unlock();
+ pool->dumpPool();
+ REPORTER_ASSERT(reporter, !dm2->lock());
+ REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed());
+}
diff --git a/src/third_party/skia/tests/DiscardableMemoryTest.cpp b/src/third_party/skia/tests/DiscardableMemoryTest.cpp
new file mode 100644
index 0000000..da36ffd
--- /dev/null
+++ b/src/third_party/skia/tests/DiscardableMemoryTest.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkDiscardableMemory.h"
+
+#include "Test.h"
+
+DEF_TEST(DiscardableMemory, reporter) {
+ const char testString[] = "HELLO, WORLD!";
+ const size_t len = sizeof(testString);
+ SkAutoTDelete<SkDiscardableMemory> dm(SkDiscardableMemory::Create(len));
+ REPORTER_ASSERT(reporter, dm.get() != NULL);
+ if (NULL == dm.get()) {
+ return;
+ }
+ void* ptr = dm->data();
+ REPORTER_ASSERT(reporter, ptr != NULL);
+ memcpy(ptr, testString, sizeof(testString));
+ dm->unlock();
+ bool success = dm->lock();
+ REPORTER_ASSERT(reporter, success);
+ if (!success) {
+ return;
+ }
+ ptr = dm->data();
+ REPORTER_ASSERT(reporter, 0 == memcmp(ptr, testString, len));
+ dm->unlock();
+}
diff --git a/src/third_party/skia/tests/DocumentTest.cpp b/src/third_party/skia/tests/DocumentTest.cpp
new file mode 100644
index 0000000..97aefcb
--- /dev/null
+++ b/src/third_party/skia/tests/DocumentTest.cpp
@@ -0,0 +1,105 @@
+#include "Test.h"
+
+#include "SkCanvas.h"
+#include "SkDocument.h"
+#include "SkOSFile.h"
+#include "SkStream.h"
+
+static void test_empty(skiatest::Reporter* reporter) {
+ SkDynamicMemoryWStream stream;
+
+ SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(&stream));
+
+ doc->close();
+
+ REPORTER_ASSERT(reporter, stream.bytesWritten() == 0);
+}
+
+static void test_abort(skiatest::Reporter* reporter) {
+ SkDynamicMemoryWStream stream;
+ SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(&stream));
+
+ SkCanvas* canvas = doc->beginPage(100, 100);
+ canvas->drawColor(SK_ColorRED);
+ doc->endPage();
+
+ doc->abort();
+
+ REPORTER_ASSERT(reporter, stream.bytesWritten() == 0);
+}
+
+static void test_abortWithFile(skiatest::Reporter* reporter) {
+ SkString tmpDir = skiatest::Test::GetTmpDir();
+
+ if (tmpDir.isEmpty()) {
+ return; // TODO(edisonn): unfortunatelly this pattern is used in other
+ // tests, but if GetTmpDir() starts returning and empty dir
+ // allways, then all these tests will be disabled.
+ }
+
+ SkString path = SkOSPath::Join(tmpDir.c_str(), "aborted.pdf");
+
+ // Make sure doc's destructor is called to flush.
+ {
+ SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(path.c_str()));
+
+ SkCanvas* canvas = doc->beginPage(100, 100);
+ canvas->drawColor(SK_ColorRED);
+ doc->endPage();
+
+ doc->abort();
+ }
+
+ FILE* file = fopen(path.c_str(), "r");
+ // The created file should be empty.
+ char buffer[100];
+ REPORTER_ASSERT(reporter, fread(buffer, 1, 1, file) == 0);
+ fclose(file);
+}
+
+static void test_file(skiatest::Reporter* reporter) {
+ SkString tmpDir = skiatest::Test::GetTmpDir();
+ if (tmpDir.isEmpty()) {
+ return; // TODO(edisonn): unfortunatelly this pattern is used in other
+ // tests, but if GetTmpDir() starts returning and empty dir
+ // allways, then all these tests will be disabled.
+ }
+
+ SkString path = SkOSPath::Join(tmpDir.c_str(), "file.pdf");
+
+ SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(path.c_str()));
+
+ SkCanvas* canvas = doc->beginPage(100, 100);
+
+ canvas->drawColor(SK_ColorRED);
+ doc->endPage();
+ doc->close();
+
+ FILE* file = fopen(path.c_str(), "r");
+ REPORTER_ASSERT(reporter, file != NULL);
+ char header[100];
+ REPORTER_ASSERT(reporter, fread(header, 4, 1, file) != 0);
+ REPORTER_ASSERT(reporter, strncmp(header, "%PDF", 4) == 0);
+ fclose(file);
+}
+
+static void test_close(skiatest::Reporter* reporter) {
+ SkDynamicMemoryWStream stream;
+ SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(&stream));
+
+ SkCanvas* canvas = doc->beginPage(100, 100);
+ canvas->drawColor(SK_ColorRED);
+ doc->endPage();
+
+ doc->close();
+
+ REPORTER_ASSERT(reporter, stream.bytesWritten() != 0);
+}
+
+DEF_TEST(document_tests, reporter) {
+ test_empty(reporter);
+ test_abort(reporter);
+ test_abortWithFile(reporter);
+ test_file(reporter);
+ test_close(reporter);
+}
diff --git a/src/third_party/skia/tests/DrawBitmapRectTest.cpp b/src/third_party/skia/tests/DrawBitmapRectTest.cpp
new file mode 100644
index 0000000..71ad2cf
--- /dev/null
+++ b/src/third_party/skia/tests/DrawBitmapRectTest.cpp
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkData.h"
+#include "SkDiscardableMemoryPool.h"
+#include "SkImageGeneratorPriv.h"
+#include "SkMatrixUtils.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+#include "SkShader.h"
+#include "SkSurface.h"
+#include "Test.h"
+
+// A BitmapFactory that always fails when asked to return pixels.
+class FailureImageGenerator : public SkImageGenerator {
+public:
+ FailureImageGenerator() { }
+ virtual ~FailureImageGenerator() { }
+
+protected:
+ virtual bool onGetInfo(SkImageInfo* info) SK_OVERRIDE {
+ *info = SkImageInfo::MakeN32Premul(100, 100);
+ return true;
+ }
+ // default onGetPixels() returns false, which is what we want.
+};
+
+// crbug.com/295895
+// Crashing in skia when a pixelref fails in lockPixels
+//
+static void test_faulty_pixelref(skiatest::Reporter* reporter) {
+ // need a cache, but don't expect to use it, so the budget is not critical
+ SkAutoTUnref<SkDiscardableMemoryPool> pool(
+ SkDiscardableMemoryPool::Create(10 * 1000, NULL));
+ SkBitmap bm;
+ bool installSuccess = SkInstallDiscardablePixelRef(SkNEW(FailureImageGenerator), &bm, pool);
+ REPORTER_ASSERT(reporter, installSuccess);
+ // now our bitmap has a pixelref, but we know it will fail to lock
+
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(200, 200));
+ SkCanvas* canvas = surface->getCanvas();
+
+ const SkPaint::FilterLevel levels[] = {
+ SkPaint::kNone_FilterLevel,
+ SkPaint::kLow_FilterLevel,
+ SkPaint::kMedium_FilterLevel,
+ SkPaint::kHigh_FilterLevel,
+ };
+
+ SkPaint paint;
+ canvas->scale(2, 2); // need a scale, otherwise we may ignore filtering
+ for (size_t i = 0; i < SK_ARRAY_COUNT(levels); ++i) {
+ paint.setFilterLevel(levels[i]);
+ canvas->drawBitmap(bm, 0, 0, &paint);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void rand_matrix(SkMatrix* mat, SkRandom& rand, unsigned mask) {
+ mat->setIdentity();
+ if (mask & SkMatrix::kTranslate_Mask) {
+ mat->postTranslate(rand.nextSScalar1(), rand.nextSScalar1());
+ }
+ if (mask & SkMatrix::kScale_Mask) {
+ mat->postScale(rand.nextSScalar1(), rand.nextSScalar1());
+ }
+ if (mask & SkMatrix::kAffine_Mask) {
+ mat->postRotate(rand.nextSScalar1() * 360);
+ }
+ if (mask & SkMatrix::kPerspective_Mask) {
+ mat->setPerspX(rand.nextSScalar1());
+ mat->setPerspY(rand.nextSScalar1());
+ }
+}
+
+static void rand_size(SkISize* size, SkRandom& rand) {
+ size->set(rand.nextU() & 0xFFFF, rand.nextU() & 0xFFFF);
+}
+
+static bool treat_as_sprite(const SkMatrix& mat, const SkISize& size,
+ unsigned bits) {
+ return SkTreatAsSprite(mat, size.width(), size.height(), bits);
+}
+
+static void test_treatAsSprite(skiatest::Reporter* reporter) {
+ const unsigned bilerBits = kSkSubPixelBitsForBilerp;
+
+ SkMatrix mat;
+ SkISize size;
+ SkRandom rand;
+
+ // assert: translate-only no-filter can always be treated as sprite
+ for (int i = 0; i < 1000; ++i) {
+ rand_matrix(&mat, rand, SkMatrix::kTranslate_Mask);
+ for (int j = 0; j < 1000; ++j) {
+ rand_size(&size, rand);
+ REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, 0));
+ }
+ }
+
+ // assert: rotate/perspect is never treated as sprite
+ for (int i = 0; i < 1000; ++i) {
+ rand_matrix(&mat, rand, SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask);
+ for (int j = 0; j < 1000; ++j) {
+ rand_size(&size, rand);
+ REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, 0));
+ REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits));
+ }
+ }
+
+ size.set(500, 600);
+
+ const SkScalar tooMuchSubpixel = 100.1f;
+ mat.setTranslate(tooMuchSubpixel, 0);
+ REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits));
+ mat.setTranslate(0, tooMuchSubpixel);
+ REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits));
+
+ const SkScalar tinySubPixel = 100.02f;
+ mat.setTranslate(tinySubPixel, 0);
+ REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, bilerBits));
+ mat.setTranslate(0, tinySubPixel);
+ REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, bilerBits));
+
+ const SkScalar twoThirds = SK_Scalar1 * 2 / 3;
+ const SkScalar bigScale = SkScalarDiv(size.width() + twoThirds, size.width());
+ mat.setScale(bigScale, bigScale);
+ REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, false));
+ REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits));
+
+ const SkScalar oneThird = SK_Scalar1 / 3;
+ const SkScalar smallScale = SkScalarDiv(size.width() + oneThird, size.width());
+ mat.setScale(smallScale, smallScale);
+ REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, false));
+ REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits));
+
+ const SkScalar oneFortyth = SK_Scalar1 / 40;
+ const SkScalar tinyScale = SkScalarDiv(size.width() + oneFortyth, size.width());
+ mat.setScale(tinyScale, tinyScale);
+ REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, false));
+ REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, bilerBits));
+}
+
+static void assert_ifDrawnTo(skiatest::Reporter* reporter,
+ const SkBitmap& bm, bool shouldBeDrawn) {
+ for (int y = 0; y < bm.height(); ++y) {
+ for (int x = 0; x < bm.width(); ++x) {
+ if (shouldBeDrawn) {
+ if (SK_ColorTRANSPARENT == *bm.getAddr32(x, y)) {
+ REPORTER_ASSERT(reporter, false);
+ return;
+ }
+ } else {
+ // should not be drawn
+ if (SK_ColorTRANSPARENT != *bm.getAddr32(x, y)) {
+ REPORTER_ASSERT(reporter, false);
+ return;
+ }
+ }
+ }
+ }
+}
+
+static void test_wacky_bitmapshader(skiatest::Reporter* reporter,
+ int width, int height, bool shouldBeDrawn) {
+ SkBitmap dev;
+ dev.allocN32Pixels(0x56F, 0x4f6);
+ dev.eraseColor(SK_ColorTRANSPARENT); // necessary, so we know if we draw to it
+
+ SkMatrix matrix;
+
+ SkCanvas c(dev);
+ matrix.setAll(-119.34097f,
+ -43.436558f,
+ 93489.945f,
+ 43.436558f,
+ -119.34097f,
+ 123.98426f,
+ 0, 0, SK_Scalar1);
+ c.concat(matrix);
+
+ SkBitmap bm;
+ if (bm.tryAllocN32Pixels(width, height)) {
+ // allow this to fail silently, to test the code downstream
+ }
+ bm.eraseColor(SK_ColorRED);
+
+ matrix.setAll(0.0078740157f,
+ 0,
+ SkIntToScalar(249),
+ 0,
+ 0.0078740157f,
+ SkIntToScalar(239),
+ 0, 0, SK_Scalar1);
+ SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode, &matrix);
+
+ SkPaint paint;
+ paint.setShader(s)->unref();
+
+ SkRect r = SkRect::MakeXYWH(681, 239, 695, 253);
+ c.drawRect(r, paint);
+
+ assert_ifDrawnTo(reporter, dev, shouldBeDrawn);
+}
+
+/*
+ * Original bug was asserting that the matrix-proc had generated a (Y) value
+ * that was out of range. This led (in the release build) to the sampler-proc
+ * reading memory out-of-bounds of the original bitmap.
+ *
+ * We were numerically overflowing our 16bit coordinates that we communicate
+ * between these two procs. The fixes was in two parts:
+ *
+ * 1. Just don't draw bitmaps larger than 64K-1 in width or height, since we
+ * can't represent those coordinates in our transport format (yet).
+ * 2. Perform an unsigned shift during the calculation, so we don't get
+ * sign-extension bleed when packing the two values (X,Y) into our 32bit
+ * slot.
+ *
+ * This tests exercises the original setup, plus 3 more to ensure that we can,
+ * in fact, handle bitmaps at 64K-1 (assuming we don't exceed the total
+ * memory allocation limit).
+ */
+static void test_giantrepeat_crbug118018(skiatest::Reporter* reporter) {
+ static const struct {
+ int fWidth;
+ int fHeight;
+ bool fExpectedToDraw;
+ } gTests[] = {
+ { 0x1b294, 0x7f, false }, // crbug 118018 (width exceeds 64K)
+ { 0xFFFF, 0x7f, true }, // should draw, test max width
+ { 0x7f, 0xFFFF, true }, // should draw, test max height
+ { 0xFFFF, 0xFFFF, false }, // allocation fails (too much RAM)
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); ++i) {
+ test_wacky_bitmapshader(reporter,
+ gTests[i].fWidth, gTests[i].fHeight,
+ gTests[i].fExpectedToDraw);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_nan_antihair() {
+ SkBitmap bm;
+ bm.allocN32Pixels(20, 20);
+
+ SkCanvas canvas(bm);
+
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(10, SK_ScalarNaN);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ // before our fix to SkScan_Antihair.cpp to check for integral NaN (0x800...)
+ // this would trigger an assert/crash.
+ //
+ // see rev. 3558
+ canvas.drawPath(path, paint);
+}
+
+static bool check_for_all_zeros(const SkBitmap& bm) {
+ SkAutoLockPixels alp(bm);
+
+ size_t count = bm.width() * bm.bytesPerPixel();
+ for (int y = 0; y < bm.height(); y++) {
+ const uint8_t* ptr = reinterpret_cast<const uint8_t*>(bm.getAddr(0, y));
+ for (size_t i = 0; i < count; i++) {
+ if (ptr[i]) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static const int gWidth = 256;
+static const int gHeight = 256;
+
+static void create(SkBitmap* bm, SkColor color) {
+ bm->allocN32Pixels(gWidth, gHeight);
+ bm->eraseColor(color);
+}
+
+DEF_TEST(DrawBitmapRect, reporter) {
+ SkBitmap src, dst;
+
+ create(&src, 0xFFFFFFFF);
+ create(&dst, 0);
+
+ SkCanvas canvas(dst);
+
+ SkIRect srcR = { gWidth, 0, gWidth + 16, 16 };
+ SkRect dstR = { 0, 0, SkIntToScalar(16), SkIntToScalar(16) };
+
+ canvas.drawBitmapRect(src, &srcR, dstR, NULL);
+
+ // ensure that we draw nothing if srcR does not intersect the bitmap
+ REPORTER_ASSERT(reporter, check_for_all_zeros(dst));
+
+ test_nan_antihair();
+ test_giantrepeat_crbug118018(reporter);
+
+ test_treatAsSprite(reporter);
+ test_faulty_pixelref(reporter);
+}
diff --git a/src/third_party/skia/tests/DrawPathTest.cpp b/src/third_party/skia/tests/DrawPathTest.cpp
new file mode 100644
index 0000000..2af4224
--- /dev/null
+++ b/src/third_party/skia/tests/DrawPathTest.cpp
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkDashPathEffect.h"
+#include "SkSurface.h"
+#include "Test.h"
+
+// test that we can draw an aa-rect at coordinates > 32K (bigger than fixedpoint)
+static void test_big_aa_rect(skiatest::Reporter* reporter) {
+ SkBitmap output;
+ SkPMColor pixel[1];
+ output.installPixels(SkImageInfo::MakeN32Premul(1, 1), pixel, 4);
+
+ SkSurface* surf = SkSurface::NewRasterPMColor(300, 33300);
+ SkCanvas* canvas = surf->getCanvas();
+
+ SkRect r = { 0, 33000, 300, 33300 };
+ int x = SkScalarRoundToInt(r.left());
+ int y = SkScalarRoundToInt(r.top());
+
+ // check that the pixel in question starts as transparent (by the surface)
+ if (canvas->readPixels(&output, x, y)) {
+ REPORTER_ASSERT(reporter, 0 == pixel[0]);
+ } else {
+ REPORTER_ASSERT_MESSAGE(reporter, false, "readPixels failed");
+ }
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorWHITE);
+
+ canvas->drawRect(r, paint);
+
+ // Now check that it is BLACK
+ if (canvas->readPixels(&output, x, y)) {
+ // don't know what swizzling PMColor did, but white should always
+ // appear the same.
+ REPORTER_ASSERT(reporter, 0xFFFFFFFF == pixel[0]);
+ } else {
+ REPORTER_ASSERT_MESSAGE(reporter, false, "readPixels failed");
+ }
+ surf->unref();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void moveToH(SkPath* path, const uint32_t raw[]) {
+ const float* fptr = (const float*)raw;
+ path->moveTo(fptr[0], fptr[1]);
+}
+
+static void cubicToH(SkPath* path, const uint32_t raw[]) {
+ const float* fptr = (const float*)raw;
+ path->cubicTo(fptr[0], fptr[1], fptr[2], fptr[3], fptr[4], fptr[5]);
+}
+
+// This used to assert, because we performed a cast (int)(pt[0].fX * scale) to
+// arrive at an int (SkFDot6) rather than calling sk_float_round2int. The assert
+// was that the initial line-segment produced by the cubic was not monotonically
+// going down (i.e. the initial DY was negative). By rounding the floats, we get
+// the more proper result.
+//
+// http://code.google.com/p/chromium/issues/detail?id=131181
+//
+
+// we're not calling this test anymore; is that for a reason?
+
+static void test_crbug131181() {
+ /*
+ fX = 18.8943768,
+ fY = 129.121277
+ }, {
+ fX = 18.8937435,
+ fY = 129.121689
+ }, {
+ fX = 18.8950119,
+ fY = 129.120422
+ }, {
+ fX = 18.5030727,
+ fY = 129.13121
+ */
+ uint32_t data[] = {
+ 0x419727af, 0x43011f0c, 0x41972663, 0x43011f27,
+ 0x419728fc, 0x43011ed4, 0x4194064b, 0x43012197
+ };
+
+ SkPath path;
+ moveToH(&path, &data[0]);
+ cubicToH(&path, &data[2]);
+
+ SkAutoTUnref<SkCanvas> canvas(SkCanvas::NewRasterN32(640, 480));
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ canvas->drawPath(path, paint);
+}
+
+// This used to assert in debug builds (and crash writing bad memory in release)
+// because we overflowed an intermediate value (B coefficient) setting up our
+// stepper for the quadratic. Now we bias that value by 1/2 so we don't overflow
+static void test_crbug_140803() {
+ SkBitmap bm;
+ bm.allocN32Pixels(2700, 30*1024);
+ SkCanvas canvas(bm);
+
+ SkPath path;
+ path.moveTo(2762, 20);
+ path.quadTo(11, 21702, 10, 21706);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ canvas.drawPath(path, paint);
+}
+
+// Need to exercise drawing an inverse-path whose bounds intersect the clip,
+// but whose edges do not (since its a quad which draws only in the bottom half
+// of its bounds).
+// In the debug build, we used to assert in this case, until it was fixed.
+//
+static void test_inversepathwithclip() {
+ SkPath path;
+
+ path.moveTo(0, SkIntToScalar(20));
+ path.quadTo(SkIntToScalar(10), SkIntToScalar(10),
+ SkIntToScalar(20), SkIntToScalar(20));
+ path.toggleInverseFillType();
+
+ SkPaint paint;
+
+ SkAutoTUnref<SkCanvas> canvas(SkCanvas::NewRasterN32(640, 480));
+ canvas.get()->save();
+ canvas.get()->clipRect(SkRect::MakeWH(SkIntToScalar(19), SkIntToScalar(11)));
+
+ paint.setAntiAlias(false);
+ canvas.get()->drawPath(path, paint);
+ paint.setAntiAlias(true);
+ canvas.get()->drawPath(path, paint);
+
+ canvas.get()->restore();
+
+ // Now do the test again, with the path flipped, so we only draw in the
+ // top half of our bounds, and have the clip intersect our bounds at the
+ // bottom.
+ path.reset(); // preserves our filltype
+ path.moveTo(0, SkIntToScalar(10));
+ path.quadTo(SkIntToScalar(10), SkIntToScalar(20),
+ SkIntToScalar(20), SkIntToScalar(10));
+ canvas.get()->clipRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(19),
+ SkIntToScalar(19), SkIntToScalar(11)));
+
+ paint.setAntiAlias(false);
+ canvas.get()->drawPath(path, paint);
+ paint.setAntiAlias(true);
+ canvas.get()->drawPath(path, paint);
+}
+
+static void test_bug533() {
+ /*
+ http://code.google.com/p/skia/issues/detail?id=533
+ This particular test/bug only applies to the float case, where the
+ coordinates are very large.
+ */
+ SkPath path;
+ path.moveTo(64, 3);
+ path.quadTo(-329936, -100000000, 1153, 330003);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkAutoTUnref<SkCanvas> canvas(SkCanvas::NewRasterN32(640, 480));
+ canvas.get()->drawPath(path, paint);
+}
+
+static void test_crbug_140642() {
+ /*
+ * We used to see this construct, and due to rounding as we accumulated
+ * our length, the loop where we apply the phase would run off the end of
+ * the array, since it relied on just -= each interval value, which did not
+ * behave as "expected". Now the code explicitly checks for walking off the
+ * end of that array.
+
+ * A different (better) fix might be to rewrite dashing to do all of its
+ * length/phase/measure math using double, but this may need to be
+ * coordinated with SkPathMeasure, to be consistent between the two.
+
+ <path stroke="mintcream" stroke-dasharray="27734 35660 2157846850 247"
+ stroke-dashoffset="-248.135982067">
+ */
+
+ const SkScalar vals[] = { 27734, 35660, 2157846850.0f, 247 };
+ SkAutoTUnref<SkDashPathEffect> dontAssert(SkDashPathEffect::Create(vals, 4, -248.135982067f));
+}
+
+static void test_crbug_124652() {
+ /*
+ http://code.google.com/p/chromium/issues/detail?id=124652
+ This particular test/bug only applies to the float case, where
+ large values can "swamp" small ones.
+ */
+ SkScalar intervals[2] = {837099584, 33450};
+ SkAutoTUnref<SkDashPathEffect> dash(SkDashPathEffect::Create(intervals, 2, -10));
+}
+
+static void test_bigcubic() {
+ SkPath path;
+ path.moveTo(64, 3);
+ path.cubicTo(-329936, -100000000, -329936, 100000000, 1153, 330003);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkAutoTUnref<SkCanvas> canvas(SkCanvas::NewRasterN32(640, 480));
+ canvas.get()->drawPath(path, paint);
+}
+
+// we used to assert if the bounds of the device (clip) was larger than 32K
+// even when the path itself was smaller. We just draw and hope in the debug
+// version to not assert.
+static void test_giantaa() {
+ const int W = 400;
+ const int H = 400;
+ SkAutoTUnref<SkCanvas> canvas(SkCanvas::NewRasterN32(33000, 10));
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkPath path;
+ path.addOval(SkRect::MakeXYWH(-10, -10, 20 + W, 20 + H));
+ canvas.get()->drawPath(path, paint);
+}
+
+// Extremely large path_length/dash_length ratios may cause infinite looping
+// in SkDashPathEffect::filterPath() due to single precision rounding.
+// The test is quite expensive, but it should get much faster after the fix
+// for http://crbug.com/165432 goes in.
+static void test_infinite_dash(skiatest::Reporter* reporter) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(5000000, 0);
+
+ SkScalar intervals[] = { 0.2f, 0.2f };
+ SkAutoTUnref<SkDashPathEffect> dash(SkDashPathEffect::Create(intervals, 2, 0));
+
+ SkPath filteredPath;
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setPathEffect(dash);
+
+ paint.getFillPath(path, &filteredPath);
+ // If we reach this, we passed.
+ REPORTER_ASSERT(reporter, true);
+}
+
+// http://crbug.com/165432
+// Limit extreme dash path effects to avoid exhausting the system memory.
+static void test_crbug_165432(skiatest::Reporter* reporter) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(10000000, 0);
+
+ SkScalar intervals[] = { 0.5f, 0.5f };
+ SkAutoTUnref<SkDashPathEffect> dash(SkDashPathEffect::Create(intervals, 2, 0));
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setPathEffect(dash);
+
+ SkPath filteredPath;
+ SkStrokeRec rec(paint);
+ REPORTER_ASSERT(reporter, !dash->filterPath(&filteredPath, path, &rec, NULL));
+ REPORTER_ASSERT(reporter, filteredPath.isEmpty());
+}
+
+DEF_TEST(DrawPath, reporter) {
+ test_giantaa();
+ test_bug533();
+ test_bigcubic();
+ test_crbug_124652();
+ test_crbug_140642();
+ test_crbug_140803();
+ test_inversepathwithclip();
+ // why?
+ if (false) test_crbug131181();
+ test_infinite_dash(reporter);
+ test_crbug_165432(reporter);
+ test_big_aa_rect(reporter);
+}
diff --git a/src/third_party/skia/tests/DrawTextTest.cpp b/src/third_party/skia/tests/DrawTextTest.cpp
new file mode 100644
index 0000000..3a96c4f
--- /dev/null
+++ b/src/third_party/skia/tests/DrawTextTest.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColor.h"
+#include "SkPaint.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+#include "SkTypes.h"
+#include "Test.h"
+
+static const SkColor bgColor = SK_ColorWHITE;
+
+static void create(SkBitmap* bm, SkIRect bound) {
+ bm->allocN32Pixels(bound.width(), bound.height());
+}
+
+static void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(bgColor);
+}
+
+/** Assumes that the ref draw was completely inside ref canvas --
+ implies that everything outside is "bgColor".
+ Checks that all overlap is the same and that all non-overlap on the
+ ref is "bgColor".
+ */
+static bool compare(const SkBitmap& ref, const SkIRect& iref,
+ const SkBitmap& test, const SkIRect& itest)
+{
+ const int xOff = itest.fLeft - iref.fLeft;
+ const int yOff = itest.fTop - iref.fTop;
+
+ SkAutoLockPixels alpRef(ref);
+ SkAutoLockPixels alpTest(test);
+
+ for (int y = 0; y < test.height(); ++y) {
+ for (int x = 0; x < test.width(); ++x) {
+ SkColor testColor = test.getColor(x, y);
+ int refX = x + xOff;
+ int refY = y + yOff;
+ SkColor refColor;
+ if (refX >= 0 && refX < ref.width() &&
+ refY >= 0 && refY < ref.height())
+ {
+ refColor = ref.getColor(refX, refY);
+ } else {
+ refColor = bgColor;
+ }
+ if (refColor != testColor) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+DEF_TEST(DrawText, reporter) {
+ SkPaint paint;
+ paint.setColor(SK_ColorGRAY);
+ paint.setTextSize(SkIntToScalar(20));
+
+ SkIRect drawTextRect = SkIRect::MakeWH(64, 64);
+ SkBitmap drawTextBitmap;
+ create(&drawTextBitmap, drawTextRect);
+ SkCanvas drawTextCanvas(drawTextBitmap);
+
+ SkIRect drawPosTextRect = SkIRect::MakeWH(64, 64);
+ SkBitmap drawPosTextBitmap;
+ create(&drawPosTextBitmap, drawPosTextRect);
+ SkCanvas drawPosTextCanvas(drawPosTextBitmap);
+
+ for (float offsetY = 0.0f; offsetY < 1.0f; offsetY += (1.0f / 16.0f)) {
+ for (float offsetX = 0.0f; offsetX < 1.0f; offsetX += (1.0f / 16.0f)) {
+ SkPoint point = SkPoint::Make(25.0f + offsetX,
+ 25.0f + offsetY);
+
+ for (int align = 0; align < SkPaint::kAlignCount; ++align) {
+ paint.setTextAlign(static_cast<SkPaint::Align>(align));
+
+ for (unsigned int flags = 0; flags < (1 << 3); ++flags) {
+ static const unsigned int antiAliasFlag = 1;
+ static const unsigned int subpixelFlag = 1 << 1;
+ static const unsigned int lcdFlag = 1 << 2;
+
+ paint.setAntiAlias(SkToBool(flags & antiAliasFlag));
+ paint.setSubpixelText(SkToBool(flags & subpixelFlag));
+ paint.setLCDRenderText(SkToBool(flags & lcdFlag));
+
+ // Test: drawText and drawPosText draw the same.
+ drawBG(&drawTextCanvas);
+ drawTextCanvas.drawText("A", 1, point.fX, point.fY, paint);
+
+ drawBG(&drawPosTextCanvas);
+ drawPosTextCanvas.drawPosText("A", 1, &point, paint);
+
+ REPORTER_ASSERT(reporter,
+ compare(drawTextBitmap, drawTextRect,
+ drawPosTextBitmap, drawPosTextRect));
+ }
+ }
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/DynamicHashTest.cpp b/src/third_party/skia/tests/DynamicHashTest.cpp
new file mode 100644
index 0000000..4a5bb85
--- /dev/null
+++ b/src/third_party/skia/tests/DynamicHashTest.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTDynamicHash.h"
+#include "Test.h"
+
+namespace {
+
+struct Entry {
+ int key;
+ double value;
+
+ static const int& GetKey(const Entry& entry) { return entry.key; }
+ static uint32_t Hash(const int& key) { return key; }
+};
+
+
+class Hash : public SkTDynamicHash<Entry, int> {
+public:
+ Hash() : INHERITED() {}
+
+ // Promote protected methods to public for this test.
+ int capacity() const { return this->INHERITED::capacity(); }
+ int countCollisions(const int& key) const { return this->INHERITED::countCollisions(key); }
+
+private:
+ typedef SkTDynamicHash<Entry, int> INHERITED;
+};
+
+} // namespace
+
+#define ASSERT(x) REPORTER_ASSERT(reporter, x)
+
+DEF_TEST(DynamicHash_growth, reporter) {
+ Entry a = { 1, 2.0 };
+ Entry b = { 2, 3.0 };
+ Entry c = { 3, 4.0 };
+ Entry d = { 4, 5.0 };
+ Entry e = { 5, 6.0 };
+
+ Hash hash;
+ ASSERT(hash.capacity() == 0);
+
+ hash.add(&a);
+ ASSERT(hash.capacity() == 4);
+
+ hash.add(&b);
+ ASSERT(hash.capacity() == 4);
+
+ hash.add(&c);
+ ASSERT(hash.capacity() == 4);
+
+ hash.add(&d);
+ ASSERT(hash.capacity() == 8);
+
+ hash.add(&e);
+ ASSERT(hash.capacity() == 8);
+
+ ASSERT(hash.count() == 5);
+}
+
+DEF_TEST(DynamicHash_add, reporter) {
+ Hash hash;
+ Entry a = { 1, 2.0 };
+ Entry b = { 2, 3.0 };
+
+ ASSERT(hash.count() == 0);
+ hash.add(&a);
+ ASSERT(hash.count() == 1);
+ hash.add(&b);
+ ASSERT(hash.count() == 2);
+}
+
+DEF_TEST(DynamicHash_lookup, reporter) {
+ Hash hash;
+
+ // These collide.
+ Entry a = { 1, 2.0 };
+ Entry b = { 5, 3.0 };
+
+ // Before we insert anything, nothing can collide.
+ ASSERT(hash.countCollisions(1) == 0);
+ ASSERT(hash.countCollisions(5) == 0);
+ ASSERT(hash.countCollisions(9) == 0);
+
+ // First is easy.
+ hash.add(&a);
+ ASSERT(hash.countCollisions(1) == 0);
+ ASSERT(hash.countCollisions(5) == 1);
+ ASSERT(hash.countCollisions(9) == 1);
+
+ // Second is one step away.
+ hash.add(&b);
+ ASSERT(hash.countCollisions(1) == 0);
+ ASSERT(hash.countCollisions(5) == 1);
+ ASSERT(hash.countCollisions(9) == 2);
+
+ // We can find our data right?
+ ASSERT(hash.find(1) != NULL);
+ ASSERT(hash.find(1)->value == 2.0);
+ ASSERT(hash.find(5) != NULL);
+ ASSERT(hash.find(5)->value == 3.0);
+
+ // These aren't in the hash.
+ ASSERT(hash.find(2) == NULL);
+ ASSERT(hash.find(9) == NULL);
+}
+
+DEF_TEST(DynamicHash_remove, reporter) {
+ Hash hash;
+
+ // These collide.
+ Entry a = { 1, 2.0 };
+ Entry b = { 5, 3.0 };
+ Entry c = { 9, 4.0 };
+
+ hash.add(&a);
+ hash.add(&b);
+ hash.remove(1);
+ // a should be marked deleted, and b should still be findable.
+
+ ASSERT(hash.find(1) == NULL);
+ ASSERT(hash.find(5) != NULL);
+ ASSERT(hash.find(5)->value == 3.0);
+
+ // This will go in the same slot as 'a' did before.
+ ASSERT(hash.countCollisions(9) == 0);
+ hash.add(&c);
+ ASSERT(hash.find(9) != NULL);
+ ASSERT(hash.find(9)->value == 4.0);
+ ASSERT(hash.find(5) != NULL);
+ ASSERT(hash.find(5)->value == 3.0);
+}
+
+template<typename T> static void TestIter(skiatest::Reporter* reporter) {
+ Hash hash;
+
+ int count = 0;
+ // this should fall out of loop immediately
+ for (T iter(&hash); !iter.done(); ++iter) {
+ ++count;
+ }
+ ASSERT(0 == count);
+
+ // These collide.
+ Entry a = { 1, 2.0 };
+ Entry b = { 5, 3.0 };
+ Entry c = { 9, 4.0 };
+
+ hash.add(&a);
+ hash.add(&b);
+ hash.add(&c);
+
+ // should see all 3 unique keys when iterating over hash
+ count = 0;
+ int keys[3] = {0, 0, 0};
+ for (T iter(&hash); !iter.done(); ++iter) {
+ int key = (*iter).key;
+ keys[count] = key;
+ ASSERT(hash.find(key) != NULL);
+ ++count;
+ }
+ ASSERT(3 == count);
+ ASSERT(keys[0] != keys[1]);
+ ASSERT(keys[0] != keys[2]);
+ ASSERT(keys[1] != keys[2]);
+
+ // should see 2 unique keys when iterating over hash that aren't 1
+ hash.remove(1);
+ count = 0;
+ memset(keys, 0, sizeof(keys));
+ for (T iter(&hash); !iter.done(); ++iter) {
+ int key = (*iter).key;
+ keys[count] = key;
+ ASSERT(key != 1);
+ ASSERT(hash.find(key) != NULL);
+ ++count;
+ }
+ ASSERT(2 == count);
+ ASSERT(keys[0] != keys[1]);
+}
+
+DEF_TEST(DynamicHash_iterator, reporter) {
+ TestIter<Hash::Iter>(reporter);
+ TestIter<Hash::ConstIter>(reporter);
+}
+
+static void TestResetOrRewind(skiatest::Reporter* reporter, bool testReset) {
+ Hash hash;
+ Entry a = { 1, 2.0 };
+ Entry b = { 2, 3.0 };
+
+ ASSERT(hash.capacity() == 0);
+ hash.add(&a);
+ hash.add(&b);
+ ASSERT(hash.count() == 2);
+ ASSERT(hash.capacity() == 4);
+
+ if (testReset) {
+ hash.reset();
+ ASSERT(hash.capacity() == 0);
+ } else {
+ hash.rewind();
+ ASSERT(hash.capacity() == 4);
+ }
+ ASSERT(hash.count() == 0);
+
+ // make sure things still work
+ hash.add(&a);
+ hash.add(&b);
+ ASSERT(hash.count() == 2);
+ ASSERT(hash.capacity() == 4);
+
+ ASSERT(hash.find(1) != NULL);
+ ASSERT(hash.find(2) != NULL);
+}
+
+DEF_TEST(DynamicHash_reset, reporter) {
+ TestResetOrRewind(reporter, true);
+}
+
+DEF_TEST(DynamicHash_rewind, reporter) {
+ TestResetOrRewind(reporter, false);
+}
diff --git a/src/third_party/skia/tests/EmptyPathTest.cpp b/src/third_party/skia/tests/EmptyPathTest.cpp
new file mode 100644
index 0000000..c4f011a
--- /dev/null
+++ b/src/third_party/skia/tests/EmptyPathTest.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkPath.h"
+#include "Test.h"
+
+#define DIMENSION 32
+
+static void drawAndTest(skiatest::Reporter* reporter, const SkPath& path,
+ const SkPaint& paint, bool shouldDraw) {
+ SkBitmap bm;
+ bm.allocN32Pixels(DIMENSION, DIMENSION);
+ SkASSERT(DIMENSION*4 == bm.rowBytes()); // ensure no padding on each row
+ bm.eraseColor(SK_ColorTRANSPARENT);
+
+ SkCanvas canvas(bm);
+ SkPaint p(paint);
+ p.setColor(SK_ColorWHITE);
+
+ canvas.drawPath(path, p);
+
+ size_t count = DIMENSION * DIMENSION;
+ const SkPMColor* ptr = bm.getAddr32(0, 0);
+
+ SkPMColor andValue = ~0U;
+ SkPMColor orValue = 0;
+ for (size_t i = 0; i < count; ++i) {
+ SkPMColor c = ptr[i];
+ andValue &= c;
+ orValue |= c;
+ }
+
+ // success means we drew everywhere or nowhere (depending on shouldDraw)
+ bool success = shouldDraw ? (~0U == andValue) : (0 == orValue);
+
+ if (!success) {
+ const char* str;
+ if (shouldDraw) {
+ str = "Path expected to draw everywhere, but didn't. ";
+ } else {
+ str = "Path expected to draw nowhere, but did. ";
+ }
+ ERRORF(reporter, "%s style[%d] cap[%d] join[%d] antialias[%d]"
+ " filltype[%d] ptcount[%d]", str, paint.getStyle(),
+ paint.getStrokeCap(), paint.getStrokeJoin(),
+ paint.isAntiAlias(), path.getFillType(), path.countPoints());
+// uncomment this if you want to step in to see the failure
+// canvas.drawPath(path, p);
+ }
+}
+
+static void iter_paint(skiatest::Reporter* reporter, const SkPath& path, bool shouldDraw) {
+ static const SkPaint::Cap gCaps[] = {
+ SkPaint::kButt_Cap,
+ SkPaint::kRound_Cap,
+ SkPaint::kSquare_Cap
+ };
+ static const SkPaint::Join gJoins[] = {
+ SkPaint::kMiter_Join,
+ SkPaint::kRound_Join,
+ SkPaint::kBevel_Join
+ };
+ static const SkPaint::Style gStyles[] = {
+ SkPaint::kFill_Style,
+ SkPaint::kStroke_Style,
+ SkPaint::kStrokeAndFill_Style
+ };
+ for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+ for (size_t join = 0; join < SK_ARRAY_COUNT(gJoins); ++join) {
+ for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ SkPaint paint;
+ paint.setStrokeWidth(SkIntToScalar(10));
+
+ paint.setStrokeCap(gCaps[cap]);
+ paint.setStrokeJoin(gJoins[join]);
+ paint.setStyle(gStyles[style]);
+
+ paint.setAntiAlias(false);
+ drawAndTest(reporter, path, paint, shouldDraw);
+ paint.setAntiAlias(true);
+ drawAndTest(reporter, path, paint, shouldDraw);
+ }
+ }
+ }
+}
+
+#define CX (SkIntToScalar(DIMENSION) / 2)
+#define CY (SkIntToScalar(DIMENSION) / 2)
+
+static void make_empty(SkPath*) {}
+static void make_M(SkPath* path) { path->moveTo(CX, CY); }
+static void make_MM(SkPath* path) { path->moveTo(CX, CY); path->moveTo(CX, CY); }
+static void make_MZM(SkPath* path) { path->moveTo(CX, CY); path->close(); path->moveTo(CX, CY); }
+static void make_L(SkPath* path) { path->moveTo(CX, CY); path->lineTo(CX, CY); }
+static void make_Q(SkPath* path) { path->moveTo(CX, CY); path->quadTo(CX, CY, CX, CY); }
+static void make_C(SkPath* path) { path->moveTo(CX, CY); path->cubicTo(CX, CY, CX, CY, CX, CY); }
+
+/* Two invariants are tested: How does an empty/degenerate path draw?
+ * - if the path is drawn inverse, it should draw everywhere
+ * - if the path is drawn non-inverse, it should draw nowhere
+ *
+ * Things to iterate on:
+ * - path (empty, degenerate line/quad/cubic w/ and w/o close
+ * - paint style
+ * - path filltype
+ * - path stroke variants (e.g. caps, joins, width)
+ */
+static void test_emptydrawing(skiatest::Reporter* reporter) {
+ static void (*gMakeProc[])(SkPath*) = {
+ make_empty, make_M, make_MM, make_MZM, make_L, make_Q, make_C
+ };
+ static SkPath::FillType gFills[] = {
+ SkPath::kWinding_FillType,
+ SkPath::kEvenOdd_FillType,
+ SkPath::kInverseWinding_FillType,
+ SkPath::kInverseEvenOdd_FillType
+ };
+ for (int doClose = 0; doClose < 2; ++doClose) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProc); ++i) {
+ SkPath path;
+ gMakeProc[i](&path);
+ if (doClose) {
+ path.close();
+ }
+ for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ path.setFillType(gFills[fill]);
+ bool shouldDraw = path.isInverseFillType();
+ iter_paint(reporter, path, shouldDraw);
+ }
+ }
+ }
+}
+
+DEF_TEST(EmptyPath, reporter) {
+ test_emptydrawing(reporter);
+}
diff --git a/src/third_party/skia/tests/ErrorTest.cpp b/src/third_party/skia/tests/ErrorTest.cpp
new file mode 100644
index 0000000..4802d53
--- /dev/null
+++ b/src/third_party/skia/tests/ErrorTest.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkError.h"
+#include "SkPath.h"
+#include "SkRect.h"
+#include "Test.h"
+
+typedef struct {
+ skiatest::Reporter *fReporter;
+ unsigned int *fIntPointer;
+} ErrorContext;
+
+#define CHECK(errcode) \
+ REPORTER_ASSERT( reporter, (err = SkGetLastError()) == errcode); \
+ if (err != kNoError_SkError) \
+ { \
+ SkClearLastError(); \
+ }
+
+static void cb(SkError err, void *context) {
+ ErrorContext *context_ptr = static_cast<ErrorContext *>(context);
+ REPORTER_ASSERT( context_ptr->fReporter, (*(context_ptr->fIntPointer) == 0xdeadbeef) );
+}
+
+DEF_TEST(Error, reporter) {
+ // Some previous user of this thread may have left an error laying around.
+ SkClearLastError();
+
+ SkError err;
+
+ unsigned int test_value = 0xdeadbeef;
+ ErrorContext context;
+ context.fReporter = reporter;
+ context.fIntPointer = &test_value;
+
+ SkSetErrorCallback(cb, &context);
+
+ CHECK(kNoError_SkError);
+
+ SkRect r = SkRect::MakeWH(50, 100);
+ CHECK(kNoError_SkError);
+
+ SkPath path;
+ path.addRect(r);
+ CHECK(kNoError_SkError);
+
+ path.addRoundRect(r, 10, 10);
+ CHECK(kNoError_SkError);
+
+ // should trigger the default error callback, which just prints to the screen.
+ path.addRoundRect(r, -10, -10);
+ CHECK(kInvalidArgument_SkError);
+ CHECK(kNoError_SkError);
+
+ // should trigger *our* callback.
+ path.addRoundRect(r, -10, -10);
+ CHECK(kInvalidArgument_SkError);
+ CHECK(kNoError_SkError);
+}
diff --git a/src/third_party/skia/tests/FillPathTest.cpp b/src/third_party/skia/tests/FillPathTest.cpp
new file mode 100644
index 0000000..cc8d329
--- /dev/null
+++ b/src/third_party/skia/tests/FillPathTest.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBlitter.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkScan.h"
+#include "Test.h"
+
+struct FakeBlitter : public SkBlitter {
+ FakeBlitter()
+ : m_blitCount(0)
+ {}
+
+ virtual void blitH(int x, int y, int width) {
+ m_blitCount++;
+ }
+
+ int m_blitCount;
+};
+
+// http://code.google.com/p/skia/issues/detail?id=87
+// Lines which is not clipped by boundary based clipping,
+// but skipped after tessellation, should be cleared by the blitter.
+DEF_TEST(FillPathInverse, reporter) {
+ FakeBlitter blitter;
+ SkIRect clip;
+ SkPath path;
+ int height = 100;
+ int width = 200;
+ int expected_lines = 5;
+ clip.set(0, height - expected_lines, width, height);
+ path.moveTo(0.0f, 0.0f);
+ path.quadTo(SkIntToScalar(width/2), SkIntToScalar(height),
+ SkIntToScalar(width), 0.0f);
+ path.close();
+ path.setFillType(SkPath::kInverseWinding_FillType);
+ SkScan::FillPath(path, clip, &blitter);
+
+ REPORTER_ASSERT(reporter, blitter.m_blitCount == expected_lines);
+}
diff --git a/src/third_party/skia/tests/FitsInTest.cpp b/src/third_party/skia/tests/FitsInTest.cpp
new file mode 100644
index 0000000..6a46b67
--- /dev/null
+++ b/src/third_party/skia/tests/FitsInTest.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTFitsIn.h"
+#include "SkTypes.h"
+#include "Test.h"
+
+#include <limits>
+
+#define TEST(S, s, D, expected) REPORTER_ASSERT(reporter, (SkTFitsIn<D>((S)(s)) == (expected)))
+
+DEF_TEST(FitsIn, reporter) {
+ TEST(int32_t, 1, int8_t, true);
+ TEST(int32_t, -1, int8_t, true);
+ TEST(int32_t, (int32_t)(std::numeric_limits<int8_t>::max)(), int8_t, true);
+ TEST(int32_t, ((int32_t)(std::numeric_limits<int8_t>::max)())+1, int8_t, false);
+ TEST(int32_t, (int32_t)(std::numeric_limits<int8_t>::min)(), int8_t, true);
+ TEST(int32_t, (int32_t)((std::numeric_limits<int8_t>::min)())-1, int8_t, false);
+
+ TEST(int32_t, 1, uint8_t, true);
+ TEST(int32_t, -1, uint8_t, false);
+ TEST(int32_t, (int32_t)(std::numeric_limits<uint8_t>::max)(), uint8_t, true);
+ TEST(int32_t, ((int32_t)(std::numeric_limits<uint8_t>::max)())+1, uint8_t, false);
+ TEST(int32_t, 0, uint8_t, true);
+ TEST(int32_t, -1, uint8_t, false);
+ TEST(int32_t, -127, uint8_t, false);
+ TEST(int32_t, -128, uint8_t, false);
+
+ TEST(int32_t, 1000, int8_t, false);
+ TEST(int32_t, 1000, uint8_t, false);
+
+ TEST(int32_t, 1, int32_t, true);
+ TEST(int32_t, -1, int32_t, true);
+ TEST(int32_t, 1, uint32_t, true);
+ TEST(int32_t, -1, uint32_t, false);
+
+ TEST(int32_t, 1, int64_t, true);
+ TEST(int32_t, -1, int64_t, true);
+ TEST(int32_t, 1, uint64_t, true);
+ TEST(int32_t, -1, uint64_t, false);
+
+ TEST(uint32_t, 1, int8_t, true);
+ TEST(uint32_t, 1, uint8_t, true);
+ TEST(uint32_t, 1, int32_t, true);
+ TEST(uint32_t, 1, uint32_t, true);
+ TEST(uint32_t, 1, int64_t, true);
+ TEST(uint32_t, 1, uint64_t, true);
+
+ TEST(uint32_t, (std::numeric_limits<uint32_t>::max)(), int8_t, false);
+ TEST(uint32_t, (std::numeric_limits<uint32_t>::max)(), uint8_t, false);
+ TEST(uint32_t, (std::numeric_limits<uint32_t>::max)(), int32_t, false);
+ TEST(uint32_t, (std::numeric_limits<uint32_t>::max)(), uint32_t, true);
+ TEST(uint32_t, (std::numeric_limits<uint32_t>::max)(), int64_t, true);
+ TEST(uint32_t, (std::numeric_limits<uint32_t>::max)(), uint64_t, true);
+
+ TEST(uint64_t, 1, int8_t, true);
+ TEST(uint64_t, 1, uint8_t, true);
+ TEST(uint64_t, 1, int32_t, true);
+ TEST(uint64_t, 1, uint32_t, true);
+ TEST(uint64_t, 1, int64_t, true);
+ TEST(uint64_t, 1, uint64_t, true);
+
+ // Uncommenting the following should cause compile failures.
+ //TEST(float, 1, uint64_t, true);
+}
diff --git a/src/third_party/skia/tests/FlatDataTest.cpp b/src/third_party/skia/tests/FlatDataTest.cpp
new file mode 100644
index 0000000..2be92b6
--- /dev/null
+++ b/src/third_party/skia/tests/FlatDataTest.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColor.h"
+#include "SkColorFilter.h"
+#include "SkGradientShader.h"
+#include "SkPaint.h"
+#include "SkPictureFlat.h"
+#include "SkShader.h"
+#include "SkXfermode.h"
+#include "Test.h"
+
+struct SkFlattenableTraits {
+ static void Flatten(SkWriteBuffer& buffer, const SkFlattenable& flattenable) {
+ buffer.writeFlattenable(&flattenable);
+ }
+};
+
+class Controller : public SkChunkFlatController {
+public:
+ Controller() : INHERITED(1024) {
+ this->INHERITED::setNamedFactorySet(SkNEW(SkNamedFactorySet))->unref();
+ }
+private:
+ typedef SkChunkFlatController INHERITED;
+};
+
+/**
+ * Verify that two SkFlatData objects that created from the same object are
+ * identical when using an SkNamedFactorySet.
+ * @param reporter Object to report failures.
+ * @param obj Flattenable object to be flattened.
+ * @param flattenProc Function that flattens objects with the same type as obj.
+ */
+template <typename Traits, typename T>
+static void testCreate(skiatest::Reporter* reporter, const T& obj) {
+ Controller controller;
+ // No need to delete data because that will be taken care of by the controller.
+ SkFlatData* data1 = SkFlatData::Create<Traits>(&controller, obj, 0);
+ SkFlatData* data2 = SkFlatData::Create<Traits>(&controller, obj, 1);
+ REPORTER_ASSERT(reporter, *data1 == *data2);
+}
+
+DEF_TEST(FlatData, reporter) {
+ // Test flattening SkShader
+ SkPoint points[2];
+ points[0].set(0, 0);
+ points[1].set(SkIntToScalar(20), SkIntToScalar(20));
+ SkColor colors[2];
+ colors[0] = SK_ColorRED;
+ colors[1] = SK_ColorBLUE;
+
+ SkAutoTUnref<SkShader> shader(SkGradientShader::CreateLinear(points, colors, NULL, 2,
+ SkShader::kRepeat_TileMode));
+ testCreate<SkFlattenableTraits>(reporter, *shader);
+
+ // Test SkColorFilter
+ SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateLightingFilter(SK_ColorBLUE, SK_ColorRED));
+ testCreate<SkFlattenableTraits>(reporter, *cf);
+
+ // Test SkXfermode
+ SkAutoTUnref<SkXfermode> xfer(SkXfermode::Create(SkXfermode::kDstOver_Mode));
+ testCreate<SkFlattenableTraits>(reporter, *xfer);
+}
diff --git a/src/third_party/skia/tests/FlateTest.cpp b/src/third_party/skia/tests/FlateTest.cpp
new file mode 100644
index 0000000..75c6f3f
--- /dev/null
+++ b/src/third_party/skia/tests/FlateTest.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkData.h"
+#include "SkFlate.h"
+#include "SkStream.h"
+#include "Test.h"
+
+// A memory stream that reports zero size with the standard call, like
+// an unseekable file stream would.
+class SkZeroSizeMemStream : public SkMemoryStream {
+public:
+ virtual size_t read(void* buffer, size_t size) {
+ if (buffer == NULL && size == 0)
+ return 0;
+ if (buffer == NULL && size == kGetSizeKey)
+ size = 0;
+ return SkMemoryStream::read(buffer, size);
+ }
+
+ static const size_t kGetSizeKey = 0xDEADBEEF;
+};
+
+// Returns a deterministic data of the given size that should be
+// very compressible.
+static SkData* new_test_data(size_t dataSize) {
+ SkAutoTMalloc<uint8_t> testBuffer(dataSize);
+ for (size_t i = 0; i < dataSize; ++i) {
+ testBuffer[i] = i % 64;
+ }
+ return SkData::NewFromMalloc(testBuffer.detach(), dataSize);
+}
+
+static void TestFlate(skiatest::Reporter* reporter, SkMemoryStream* testStream,
+ size_t dataSize) {
+ SkASSERT(testStream != NULL);
+
+ SkAutoDataUnref testData(new_test_data(dataSize));
+ SkASSERT(testData->size() == dataSize);
+
+ testStream->setMemory(testData->data(), dataSize, /*copyData=*/ true);
+ SkDynamicMemoryWStream compressed;
+ bool deflateSuccess = SkFlate::Deflate(testStream, &compressed);
+ REPORTER_ASSERT(reporter, deflateSuccess);
+
+ // Check that the input data wasn't changed.
+ size_t inputSize = testStream->getLength();
+ if (inputSize == 0) {
+ inputSize = testStream->read(NULL, SkZeroSizeMemStream::kGetSizeKey);
+ }
+ REPORTER_ASSERT(reporter, dataSize == inputSize);
+ if (dataSize == inputSize) {
+ REPORTER_ASSERT(reporter, memcmp(testData->data(),
+ testStream->getMemoryBase(),
+ dataSize) == 0);
+ }
+
+ size_t compressedSize = compressed.getOffset();
+
+ SkAutoDataUnref compressedData(compressed.copyToData());
+ testStream->setData(compressedData.get());
+
+ SkDynamicMemoryWStream uncompressed;
+ bool inflateSuccess = SkFlate::Inflate(testStream, &uncompressed);
+ REPORTER_ASSERT(reporter, inflateSuccess);
+
+ // Check that the input data wasn't changed.
+ inputSize = testStream->getLength();
+ if (inputSize == 0) {
+ inputSize = testStream->read(NULL, SkZeroSizeMemStream::kGetSizeKey);
+ }
+ REPORTER_ASSERT(reporter, compressedSize == inputSize);
+ if (compressedData->size() == inputSize) {
+ REPORTER_ASSERT(reporter, memcmp(testStream->getMemoryBase(),
+ compressedData->data(),
+ compressedData->size()) == 0);
+ }
+
+ // Check that the uncompressed data matches the source data.
+ SkAutoDataUnref uncompressedData(uncompressed.copyToData());
+ REPORTER_ASSERT(reporter, dataSize == uncompressedData->size());
+ if (dataSize == uncompressedData->size()) {
+ REPORTER_ASSERT(reporter, memcmp(testData->data(),
+ uncompressedData->data(),
+ dataSize) == 0);
+ }
+
+ if (compressedSize < 1) { return; }
+
+ double compressionRatio = static_cast<double>(dataSize) / compressedSize;
+ // Assert that some compression took place.
+ REPORTER_ASSERT(reporter, compressionRatio > 1.2);
+
+ if (reporter->verbose()) {
+ SkDebugf("Flate Test: \t input size: " SK_SIZE_T_SPECIFIER
+ "\tcompressed size: " SK_SIZE_T_SPECIFIER
+ "\tratio: %.4g\n",
+ dataSize, compressedSize, compressionRatio);
+ }
+}
+
+DEF_TEST(Flate, reporter) {
+#ifdef SK_HAS_ZLIB
+ REPORTER_ASSERT(reporter, SkFlate::HaveFlate());
+#endif
+ if (SkFlate::HaveFlate()) {
+ SkMemoryStream memStream;
+ TestFlate(reporter, &memStream, 512);
+ TestFlate(reporter, &memStream, 10240);
+
+ SkZeroSizeMemStream fileStream;
+ TestFlate(reporter, &fileStream, 512);
+ TestFlate(reporter, &fileStream, 10240);
+ }
+}
diff --git a/src/third_party/skia/tests/FloatingPointTextureTest.cpp b/src/third_party/skia/tests/FloatingPointTextureTest.cpp
new file mode 100644
index 0000000..d367659
--- /dev/null
+++ b/src/third_party/skia/tests/FloatingPointTextureTest.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * This is a straightforward test of floating point textures, which are
+ * supported on some platforms. As of right now, this test only supports
+ * 32 bit floating point textures, and indeed floating point test values
+ * have been selected to require 32 bits of precision and full IEEE conformance
+ */
+#if SK_SUPPORT_GPU
+#include <float.h>
+#include "Test.h"
+#include "GrContext.h"
+#include "GrTexture.h"
+#include "GrContextFactory.h"
+#include "SkGpuDevice.h"
+
+static const int DEV_W = 100, DEV_H = 100;
+static const int FP_CONTROL_ARRAY_SIZE = DEV_W * DEV_H * sizeof(float);
+static const float kMaxIntegerRepresentableInSPFloatingPoint = 16777216; // 2 ^ 24
+
+static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
+
+DEF_GPUTEST(FloatingPointTextureTest, reporter, factory) {
+ float controlPixelData[FP_CONTROL_ARRAY_SIZE];
+ float readBuffer[FP_CONTROL_ARRAY_SIZE];
+ for (int i = 0; i < FP_CONTROL_ARRAY_SIZE; i += 4) {
+ controlPixelData[i] = FLT_MIN;
+ controlPixelData[i + 1] = FLT_MAX;
+ controlPixelData[i + 2] = FLT_EPSILON;
+ controlPixelData[i + 3] = kMaxIntegerRepresentableInSPFloatingPoint;
+ }
+
+ for (int origin = 0; origin < 2; ++origin) {
+ int glCtxTypeCnt = 1;
+ glCtxTypeCnt = GrContextFactory::kGLContextTypeCnt;
+ for (int glCtxType = 0; glCtxType < glCtxTypeCnt; ++glCtxType) {
+ GrTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ desc.fWidth = DEV_W;
+ desc.fHeight = DEV_H;
+ desc.fConfig = kRGBA_float_GrPixelConfig;
+ desc.fOrigin = 0 == origin ?
+ kTopLeft_GrSurfaceOrigin : kBottomLeft_GrSurfaceOrigin;
+
+ GrContext* context = NULL;
+ GrContextFactory::GLContextType type =
+ static_cast<GrContextFactory::GLContextType>(glCtxType);
+ if (!GrContextFactory::IsRenderingGLContext(type)) {
+ continue;
+ }
+ context = factory->get(type);
+ if (NULL == context){
+ continue;
+ }
+
+ SkAutoTUnref<GrTexture> fpTexture(context->createUncachedTexture(desc,
+ NULL,
+ 0));
+
+ // Floating point textures are NOT supported everywhere
+ if (NULL == fpTexture) {
+ continue;
+ }
+
+ // write square
+ context->writeTexturePixels(fpTexture, 0, 0, DEV_W, DEV_H, desc.fConfig,
+ controlPixelData, 0);
+ context->readTexturePixels(fpTexture, 0, 0, DEV_W, DEV_H, desc.fConfig, readBuffer, 0);
+ for (int j = 0; j < FP_CONTROL_ARRAY_SIZE; ++j) {
+ REPORTER_ASSERT(reporter, readBuffer[j] == controlPixelData[j]);
+ }
+ }
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/FontConfigParser.cpp b/src/third_party/skia/tests/FontConfigParser.cpp
new file mode 100644
index 0000000..86b2b1d
--- /dev/null
+++ b/src/third_party/skia/tests/FontConfigParser.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Resources.h"
+#include "SkFontConfigParser_android.h"
+#include "Test.h"
+
+int CountFallbacks(SkTDArray<FontFamily*> fontFamilies) {
+ int countOfFallbackFonts = 0;
+ for (int i = 0; i < fontFamilies.count(); i++) {
+ if (fontFamilies[i]->fIsFallbackFont) {
+ countOfFallbackFonts++;
+ }
+ }
+ return countOfFallbackFonts;
+}
+
+void ValidateLoadedFonts(SkTDArray<FontFamily*> fontFamilies,
+ skiatest::Reporter* reporter) {
+ REPORTER_ASSERT(reporter, fontFamilies[0]->fNames.count() == 5);
+ REPORTER_ASSERT(reporter, !strcmp(fontFamilies[0]->fNames[0].c_str(), "sans-serif"));
+ REPORTER_ASSERT(reporter,
+ !strcmp(fontFamilies[0]->fFonts[0].fFileName.c_str(),
+ "Roboto-Regular.ttf"));
+ REPORTER_ASSERT(reporter, !fontFamilies[0]->fIsFallbackFont);
+}
+
+void DumpLoadedFonts(SkTDArray<FontFamily*> fontFamilies) {
+#if SK_DEBUG_FONTS
+ for (int i = 0; i < fontFamilies.count(); ++i) {
+ SkDebugf("Family %d:\n", i);
+ switch(fontFamilies[i]->fVariant) {
+ case SkPaintOptionsAndroid::kElegant_Variant: SkDebugf(" elegant"); break;
+ case SkPaintOptionsAndroid::kCompact_Variant: SkDebugf(" compact"); break;
+ default: break;
+ }
+ if (!fontFamilies[i]->fLanguage.getTag().isEmpty()) {
+ SkDebugf(" language: %s", fontFamilies[i]->fLanguage.getTag().c_str());
+ }
+ for (int j = 0; j < fontFamilies[i]->fNames.count(); ++j) {
+ SkDebugf(" name %s\n", fontFamilies[i]->fNames[j].c_str());
+ }
+ for (int j = 0; j < fontFamilies[i]->fFonts.count(); ++j) {
+ const FontFileInfo& ffi = fontFamilies[i]->fFonts[j];
+ SkDebugf(" file (%d %s %d) %s\n",
+ ffi.fWeight,
+ ffi.fPaintOptions.getLanguage().getTag().isEmpty() ? "" :
+ ffi.fPaintOptions.getLanguage().getTag().c_str(),
+ ffi.fPaintOptions.getFontVariant(),
+ ffi.fFileName.c_str());
+ }
+ }
+#endif // SK_DEBUG_FONTS
+}
+
+DEF_TEST(FontConfigParserAndroid, reporter) {
+
+ bool resourcesMissing = false;
+
+ SkTDArray<FontFamily*> preV17FontFamilies;
+ SkFontConfigParser::GetTestFontFamilies(preV17FontFamilies,
+ GetResourcePath("android_fonts/pre_v17/system_fonts.xml").c_str(),
+ GetResourcePath("android_fonts/pre_v17/fallback_fonts.xml").c_str());
+
+ if (preV17FontFamilies.count() > 0) {
+ REPORTER_ASSERT(reporter, preV17FontFamilies.count() == 14);
+ REPORTER_ASSERT(reporter, CountFallbacks(preV17FontFamilies) == 10);
+
+ DumpLoadedFonts(preV17FontFamilies);
+ ValidateLoadedFonts(preV17FontFamilies, reporter);
+ } else {
+ resourcesMissing = true;
+ }
+
+
+ SkTDArray<FontFamily*> v17FontFamilies;
+ SkFontConfigParser::GetTestFontFamilies(v17FontFamilies,
+ GetResourcePath("android_fonts/v17/system_fonts.xml").c_str(),
+ GetResourcePath("android_fonts/v17/fallback_fonts.xml").c_str());
+
+ if (v17FontFamilies.count() > 0) {
+ REPORTER_ASSERT(reporter, v17FontFamilies.count() == 41);
+ REPORTER_ASSERT(reporter, CountFallbacks(v17FontFamilies) == 31);
+
+ DumpLoadedFonts(v17FontFamilies);
+ ValidateLoadedFonts(v17FontFamilies, reporter);
+ } else {
+ resourcesMissing = true;
+ }
+
+
+ SkTDArray<FontFamily*> v22FontFamilies;
+ SkFontConfigParser::GetTestFontFamilies(v22FontFamilies,
+ GetResourcePath("android_fonts/v22/fonts.xml").c_str(),
+ NULL);
+
+ if (v22FontFamilies.count() > 0) {
+ REPORTER_ASSERT(reporter, v22FontFamilies.count() == 53);
+ REPORTER_ASSERT(reporter, CountFallbacks(v22FontFamilies) == 42);
+
+ DumpLoadedFonts(v22FontFamilies);
+ ValidateLoadedFonts(v22FontFamilies, reporter);
+ } else {
+ resourcesMissing = true;
+ }
+
+ if (resourcesMissing) {
+ SkDebugf("---- Resource files missing for FontConfigParser test\n");
+ }
+}
+
diff --git a/src/third_party/skia/tests/FontHostStreamTest.cpp b/src/third_party/skia/tests/FontHostStreamTest.cpp
new file mode 100644
index 0000000..a2254fd
--- /dev/null
+++ b/src/third_party/skia/tests/FontHostStreamTest.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColor.h"
+#include "SkFontDescriptor.h"
+#include "SkFontHost.h"
+#include "SkGraphics.h"
+#include "SkPaint.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+#include "SkStream.h"
+#include "SkTypeface.h"
+#include "SkTypes.h"
+#include "Test.h"
+
+static const SkColor bgColor = SK_ColorWHITE;
+
+static void create(SkBitmap* bm, SkIRect bound) {
+ bm->allocN32Pixels(bound.width(), bound.height());
+}
+
+static void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(bgColor);
+}
+
+/** Assumes that the ref draw was completely inside ref canvas --
+ implies that everything outside is "bgColor".
+ Checks that all overlap is the same and that all non-overlap on the
+ ref is "bgColor".
+ */
+static bool compare(const SkBitmap& ref, const SkIRect& iref,
+ const SkBitmap& test, const SkIRect& itest)
+{
+ const int xOff = itest.fLeft - iref.fLeft;
+ const int yOff = itest.fTop - iref.fTop;
+
+ SkAutoLockPixels alpRef(ref);
+ SkAutoLockPixels alpTest(test);
+
+ for (int y = 0; y < test.height(); ++y) {
+ for (int x = 0; x < test.width(); ++x) {
+ SkColor testColor = test.getColor(x, y);
+ int refX = x + xOff;
+ int refY = y + yOff;
+ SkColor refColor;
+ if (refX >= 0 && refX < ref.width() &&
+ refY >= 0 && refY < ref.height())
+ {
+ refColor = ref.getColor(refX, refY);
+ } else {
+ refColor = bgColor;
+ }
+ if (refColor != testColor) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+DEF_TEST(FontHostStream, reporter) {
+ {
+ SkPaint paint;
+ paint.setColor(SK_ColorGRAY);
+ paint.setTextSize(SkIntToScalar(30));
+
+ SkTypeface* fTypeface = SkTypeface::CreateFromName("Georgia",
+ SkTypeface::kNormal);
+ SkSafeUnref(paint.setTypeface(fTypeface));
+
+ SkIRect origRect = SkIRect::MakeWH(64, 64);
+ SkBitmap origBitmap;
+ create(&origBitmap, origRect);
+ SkCanvas origCanvas(origBitmap);
+
+ SkIRect streamRect = SkIRect::MakeWH(64, 64);
+ SkBitmap streamBitmap;
+ create(&streamBitmap, streamRect);
+ SkCanvas streamCanvas(streamBitmap);
+
+ SkPoint point = SkPoint::Make(24, 32);
+
+ // Test: origTypeface and streamTypeface from orig data draw the same
+ drawBG(&origCanvas);
+ origCanvas.drawText("A", 1, point.fX, point.fY, paint);
+
+ SkTypeface* origTypeface = paint.getTypeface();
+ SkAutoTUnref<SkTypeface> aur;
+ if (NULL == origTypeface) {
+ origTypeface = aur.reset(SkTypeface::RefDefault());
+ }
+
+ int ttcIndex;
+ SkAutoTUnref<SkStream> fontData(origTypeface->openStream(&ttcIndex));
+ SkTypeface* streamTypeface = SkTypeface::CreateFromStream(fontData);
+
+ SkFontDescriptor desc;
+ bool isLocalStream = false;
+ streamTypeface->getFontDescriptor(&desc, &isLocalStream);
+ REPORTER_ASSERT(reporter, isLocalStream);
+
+ SkSafeUnref(paint.setTypeface(streamTypeface));
+ drawBG(&streamCanvas);
+ streamCanvas.drawPosText("A", 1, &point, paint);
+
+ REPORTER_ASSERT(reporter,
+ compare(origBitmap, origRect, streamBitmap, streamRect));
+ }
+ //Make sure the typeface is deleted and removed.
+ SkGraphics::PurgeFontCache();
+}
diff --git a/src/third_party/skia/tests/FontHostTest.cpp b/src/third_party/skia/tests/FontHostTest.cpp
new file mode 100644
index 0000000..249fe7b
--- /dev/null
+++ b/src/third_party/skia/tests/FontHostTest.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Resources.h"
+#include "SkEndian.h"
+#include "SkFontStream.h"
+#include "SkOSFile.h"
+#include "SkPaint.h"
+#include "SkStream.h"
+#include "SkTypeface.h"
+#include "Test.h"
+
+//#define DUMP_TABLES
+//#define DUMP_TTC_TABLES
+
+#define kFontTableTag_head SkSetFourByteTag('h', 'e', 'a', 'd')
+#define kFontTableTag_hhea SkSetFourByteTag('h', 'h', 'e', 'a')
+#define kFontTableTag_maxp SkSetFourByteTag('m', 'a', 'x', 'p')
+
+static const struct TagSize {
+ SkFontTableTag fTag;
+ size_t fSize;
+} gKnownTableSizes[] = {
+ { kFontTableTag_head, 54 },
+ { kFontTableTag_hhea, 36 },
+};
+
+// Test that getUnitsPerEm() agrees with a direct lookup in the 'head' table
+// (if that table is available).
+static void test_unitsPerEm(skiatest::Reporter* reporter, SkTypeface* face) {
+ int nativeUPEM = face->getUnitsPerEm();
+
+ int tableUPEM = -1;
+ size_t size = face->getTableSize(kFontTableTag_head);
+ if (size) {
+ // unitsPerEm is at offset 18 into the 'head' table.
+ uint16_t rawUPEM;
+ face->getTableData(kFontTableTag_head, 18, sizeof(rawUPEM), &rawUPEM);
+ tableUPEM = SkEndian_SwapBE16(rawUPEM);
+ }
+
+ if (tableUPEM >= 0) {
+ REPORTER_ASSERT(reporter, tableUPEM == nativeUPEM);
+ }
+}
+
+// Test that countGlyphs() agrees with a direct lookup in the 'maxp' table
+// (if that table is available).
+static void test_countGlyphs(skiatest::Reporter* reporter, SkTypeface* face) {
+ int nativeGlyphs = face->countGlyphs();
+
+ int tableGlyphs = -1;
+ size_t size = face->getTableSize(kFontTableTag_maxp);
+ if (size) {
+ // glyphs is at offset 4 into the 'maxp' table.
+ uint16_t rawGlyphs;
+ face->getTableData(kFontTableTag_maxp, 4, sizeof(rawGlyphs), &rawGlyphs);
+ tableGlyphs = SkEndian_SwapBE16(rawGlyphs);
+ }
+
+ if (tableGlyphs >= 0) {
+ REPORTER_ASSERT(reporter, tableGlyphs == nativeGlyphs);
+ }
+}
+
+// The following three are all the same code points in various encodings.
+// a中Яיו𝄞a𠮟
+static uint8_t utf8Chars[] = { 0x61, 0xE4,0xB8,0xAD, 0xD0,0xAF, 0xD7,0x99, 0xD7,0x95, 0xF0,0x9D,0x84,0x9E, 0x61, 0xF0,0xA0,0xAE,0x9F };
+static uint16_t utf16Chars[] = { 0x0061, 0x4E2D, 0x042F, 0x05D9, 0x05D5, 0xD834,0xDD1E, 0x0061, 0xD842,0xDF9F };
+static uint32_t utf32Chars[] = { 0x00000061, 0x00004E2D, 0x0000042F, 0x000005D9, 0x000005D5, 0x0001D11E, 0x00000061, 0x00020B9F };
+
+struct CharsToGlyphs_TestData {
+ const void* chars;
+ int charCount;
+ size_t charsByteLength;
+ SkTypeface::Encoding typefaceEncoding;
+ const char* name;
+} static charsToGlyphs_TestData[] = {
+ { utf8Chars, 8, sizeof(utf8Chars), SkTypeface::kUTF8_Encoding, "Simple UTF-8" },
+ { utf16Chars, 8, sizeof(utf16Chars), SkTypeface::kUTF16_Encoding, "Simple UTF-16" },
+ { utf32Chars, 8, sizeof(utf32Chars), SkTypeface::kUTF32_Encoding, "Simple UTF-32" },
+};
+
+// Test that SkPaint::textToGlyphs agrees with SkTypeface::charsToGlyphs.
+static void test_charsToGlyphs(skiatest::Reporter* reporter, SkTypeface* face) {
+ uint16_t paintGlyphIds[256];
+ uint16_t faceGlyphIds[256];
+
+ for (size_t testIndex = 0; testIndex < SK_ARRAY_COUNT(charsToGlyphs_TestData); ++testIndex) {
+ CharsToGlyphs_TestData& test = charsToGlyphs_TestData[testIndex];
+
+ SkPaint paint;
+ paint.setTypeface(face);
+ paint.setTextEncoding((SkPaint::TextEncoding)test.typefaceEncoding);
+ paint.textToGlyphs(test.chars, test.charsByteLength, paintGlyphIds);
+
+ face->charsToGlyphs(test.chars, test.typefaceEncoding, faceGlyphIds, test.charCount);
+
+ for (int i = 0; i < test.charCount; ++i) {
+ SkString name;
+ face->getFamilyName(&name);
+ SkString a;
+ a.appendf("%s, paintGlyphIds[%d] = %d, faceGlyphIds[%d] = %d, face = %s",
+ test.name, i, (int)paintGlyphIds[i], i, (int)faceGlyphIds[i], name.c_str());
+ REPORTER_ASSERT_MESSAGE(reporter, paintGlyphIds[i] == faceGlyphIds[i], a.c_str());
+ }
+ }
+}
+
+static void test_fontstream(skiatest::Reporter* reporter,
+ SkStream* stream, int ttcIndex) {
+ int n = SkFontStream::GetTableTags(stream, ttcIndex, NULL);
+ SkAutoTArray<SkFontTableTag> array(n);
+
+ int n2 = SkFontStream::GetTableTags(stream, ttcIndex, array.get());
+ REPORTER_ASSERT(reporter, n == n2);
+
+ for (int i = 0; i < n; ++i) {
+#ifdef DUMP_TTC_TABLES
+ SkString str;
+ SkFontTableTag t = array[i];
+ str.appendUnichar((t >> 24) & 0xFF);
+ str.appendUnichar((t >> 16) & 0xFF);
+ str.appendUnichar((t >> 8) & 0xFF);
+ str.appendUnichar((t >> 0) & 0xFF);
+ SkDebugf("[%d:%d] '%s'\n", ttcIndex, i, str.c_str());
+#endif
+ size_t size = SkFontStream::GetTableSize(stream, ttcIndex, array[i]);
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gKnownTableSizes); ++j) {
+ if (gKnownTableSizes[j].fTag == array[i]) {
+ REPORTER_ASSERT(reporter, gKnownTableSizes[j].fSize == size);
+ }
+ }
+ }
+}
+
+static void test_fontstream(skiatest::Reporter* reporter, SkStream* stream) {
+ int count = SkFontStream::CountTTCEntries(stream);
+#ifdef DUMP_TTC_TABLES
+ SkDebugf("CountTTCEntries %d\n", count);
+#endif
+ for (int i = 0; i < count; ++i) {
+ test_fontstream(reporter, stream, i);
+ }
+}
+
+static void test_fontstream(skiatest::Reporter* reporter) {
+ // This test cannot run if there is no resource path.
+ SkString resourcePath = GetResourcePath();
+ if (resourcePath.isEmpty()) {
+ SkDebugf("Could not run fontstream test because resourcePath not specified.");
+ return;
+ }
+ SkString filename = SkOSPath::Join(resourcePath.c_str(), "test.ttc");
+
+ SkFILEStream stream(filename.c_str());
+ if (stream.isValid()) {
+ test_fontstream(reporter, &stream);
+ } else {
+ SkDebugf("Could not run fontstream test because test.ttc not found.");
+ }
+}
+
+static void test_tables(skiatest::Reporter* reporter, SkTypeface* face) {
+ if (false) { // avoid bit rot, suppress warning
+ SkFontID fontID = face->uniqueID();
+ REPORTER_ASSERT(reporter, fontID);
+ }
+
+ int count = face->countTables();
+
+ SkAutoTMalloc<SkFontTableTag> storage(count);
+ SkFontTableTag* tags = storage.get();
+
+ int count2 = face->getTableTags(tags);
+ REPORTER_ASSERT(reporter, count2 == count);
+
+ for (int i = 0; i < count; ++i) {
+ size_t size = face->getTableSize(tags[i]);
+ REPORTER_ASSERT(reporter, size > 0);
+
+#ifdef DUMP_TABLES
+ char name[5];
+ name[0] = (tags[i] >> 24) & 0xFF;
+ name[1] = (tags[i] >> 16) & 0xFF;
+ name[2] = (tags[i] >> 8) & 0xFF;
+ name[3] = (tags[i] >> 0) & 0xFF;
+ name[4] = 0;
+ SkDebugf("%s %d\n", name, size);
+#endif
+
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gKnownTableSizes); ++j) {
+ if (gKnownTableSizes[j].fTag == tags[i]) {
+ REPORTER_ASSERT(reporter, gKnownTableSizes[j].fSize == size);
+ }
+ }
+
+ // do we get the same size from GetTableData and GetTableSize
+ {
+ SkAutoMalloc data(size);
+ size_t size2 = face->getTableData(tags[i], 0, size, data.get());
+ REPORTER_ASSERT(reporter, size2 == size);
+ }
+ }
+}
+
+static void test_tables(skiatest::Reporter* reporter) {
+ static const char* const gNames[] = {
+ NULL, // default font
+ "Helvetica", "Arial",
+ "Times", "Times New Roman",
+ "Courier", "Courier New",
+ "Terminal", "MS Sans Serif",
+ "Hiragino Mincho ProN", "MS PGothic",
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) {
+ SkAutoTUnref<SkTypeface> face(SkTypeface::CreateFromName(gNames[i], SkTypeface::kNormal));
+ if (face) {
+#ifdef DUMP_TABLES
+ SkDebugf("%s\n", gNames[i]);
+#endif
+ test_tables(reporter, face);
+ test_unitsPerEm(reporter, face);
+ test_countGlyphs(reporter, face);
+ test_charsToGlyphs(reporter, face);
+ }
+ }
+}
+
+/*
+ * Verifies that the advance values returned by generateAdvance and
+ * generateMetrics match.
+ */
+static void test_advances(skiatest::Reporter* reporter) {
+ static const char* const faces[] = {
+ NULL, // default font
+ "Arial", "Times", "Times New Roman", "Helvetica", "Courier",
+ "Courier New", "Verdana", "monospace",
+ };
+
+ static const struct {
+ SkPaint::Hinting hinting;
+ unsigned flags;
+ } settings[] = {
+ { SkPaint::kNo_Hinting, 0 },
+ { SkPaint::kNo_Hinting, SkPaint::kLinearText_Flag },
+ { SkPaint::kNo_Hinting, SkPaint::kSubpixelText_Flag },
+ { SkPaint::kSlight_Hinting, 0 },
+ { SkPaint::kSlight_Hinting, SkPaint::kLinearText_Flag },
+ { SkPaint::kSlight_Hinting, SkPaint::kSubpixelText_Flag },
+ { SkPaint::kNormal_Hinting, 0 },
+ { SkPaint::kNormal_Hinting, SkPaint::kLinearText_Flag },
+ { SkPaint::kNormal_Hinting, SkPaint::kSubpixelText_Flag },
+ };
+
+ static const struct {
+ SkScalar fScaleX;
+ SkScalar fSkewX;
+ } gScaleRec[] = {
+ { SK_Scalar1, 0 },
+ { SK_Scalar1/2, 0 },
+ // these two exercise obliquing (skew)
+ { SK_Scalar1, -SK_Scalar1/4 },
+ { SK_Scalar1/2, -SK_Scalar1/4 },
+ };
+
+ SkPaint paint;
+ char txt[] = "long.text.with.lots.of.dots.";
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(faces); i++) {
+ SkAutoTUnref<SkTypeface> face(SkTypeface::CreateFromName(faces[i], SkTypeface::kNormal));
+ paint.setTypeface(face);
+
+ for (size_t j = 0; j < SK_ARRAY_COUNT(settings); j++) {
+ paint.setHinting(settings[j].hinting);
+ paint.setLinearText((settings[j].flags & SkPaint::kLinearText_Flag) != 0);
+ paint.setSubpixelText((settings[j].flags & SkPaint::kSubpixelText_Flag) != 0);
+
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gScaleRec); ++k) {
+ paint.setTextScaleX(gScaleRec[k].fScaleX);
+ paint.setTextSkewX(gScaleRec[k].fSkewX);
+
+ SkRect bounds;
+
+ // For no hinting and light hinting this should take the
+ // optimized generateAdvance path.
+ SkScalar width1 = paint.measureText(txt, strlen(txt));
+
+ // Requesting the bounds forces a generateMetrics call.
+ SkScalar width2 = paint.measureText(txt, strlen(txt), &bounds);
+
+ // SkDebugf("Font: %s, generateAdvance: %f, generateMetrics: %f\n",
+ // faces[i], SkScalarToFloat(width1), SkScalarToFloat(width2));
+
+ REPORTER_ASSERT(reporter, width1 == width2);
+ }
+ }
+ }
+}
+
+DEF_TEST(FontHost, reporter) {
+ test_tables(reporter);
+ test_fontstream(reporter);
+ test_advances(reporter);
+}
+
+// need tests for SkStrSearch
diff --git a/src/third_party/skia/tests/FontMgrTest.cpp b/src/third_party/skia/tests/FontMgrTest.cpp
new file mode 100644
index 0000000..a1dc9dc
--- /dev/null
+++ b/src/third_party/skia/tests/FontMgrTest.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCommandLineFlags.h"
+#include "SkFontMgr.h"
+#include "SkTypeface.h"
+#include "Test.h"
+
+#include "SkFont.h"
+#include "SkPaint.h"
+static void test_font(skiatest::Reporter* reporter) {
+ uint32_t flags = 0;
+ SkAutoTUnref<SkFont> font(SkFont::Create(NULL, 24, SkFont::kA8_MaskType, flags));
+
+ REPORTER_ASSERT(reporter, font->getTypeface());
+ REPORTER_ASSERT(reporter, 24 == font->getSize());
+ REPORTER_ASSERT(reporter, 1 == font->getScaleX());
+ REPORTER_ASSERT(reporter, 0 == font->getSkewX());
+ REPORTER_ASSERT(reporter, SkFont::kA8_MaskType == font->getMaskType());
+
+ uint16_t glyphs[5];
+ sk_bzero(glyphs, sizeof(glyphs));
+
+ int count = font->textToGlyphs("Hello", 5, kUTF8_SkTextEncoding, glyphs, SK_ARRAY_COUNT(glyphs));
+
+ REPORTER_ASSERT(reporter, 5 == count);
+ for (int i = 0; i < count; ++i) {
+ REPORTER_ASSERT(reporter, 0 != glyphs[i]);
+ }
+ REPORTER_ASSERT(reporter, glyphs[0] != glyphs[1]); // 'h' != 'e'
+ REPORTER_ASSERT(reporter, glyphs[2] == glyphs[3]); // 'l' == 'l'
+
+ SkAutoTUnref<SkFont> newFont(font->cloneWithSize(36));
+ REPORTER_ASSERT(reporter, newFont.get());
+ REPORTER_ASSERT(reporter, font->getTypeface() == newFont->getTypeface());
+ REPORTER_ASSERT(reporter, 36 == newFont->getSize()); // double check we haven't changed
+ REPORTER_ASSERT(reporter, 24 == font->getSize()); // double check we haven't changed
+
+ SkPaint paint;
+ paint.setTextSize(18);
+ font.reset(SkFont::Testing_CreateFromPaint(paint));
+ REPORTER_ASSERT(reporter, font.get());
+ REPORTER_ASSERT(reporter, font->getSize() == paint.getTextSize());
+ REPORTER_ASSERT(reporter, SkFont::kBW_MaskType == font->getMaskType());
+}
+
+/*
+ * If the font backend is going to "alias" some font names to other fonts
+ * (e.g. sans -> Arial) then we want to at least get the same typeface back
+ * if we request the alias name multiple times.
+ */
+static void test_alias_names(skiatest::Reporter* reporter) {
+ const char* inNames[] = {
+ "sans", "sans-serif", "serif", "monospace", "times", "helvetica"
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(inNames); ++i) {
+ SkAutoTUnref<SkTypeface> first(SkTypeface::CreateFromName(inNames[i],
+ SkTypeface::kNormal));
+ if (NULL == first.get()) {
+ continue;
+ }
+ for (int j = 0; j < 10; ++j) {
+ SkAutoTUnref<SkTypeface> face(SkTypeface::CreateFromName(inNames[i],
+ SkTypeface::kNormal));
+ #if 0
+ SkString name;
+ face->getFamilyName(&name);
+ printf("request %s, received %s, first id %x received %x\n",
+ inNames[i], name.c_str(), first->uniqueID(), face->uniqueID());
+ #endif
+ REPORTER_ASSERT(reporter, first->uniqueID() == face->uniqueID());
+ }
+ }
+}
+
+static void test_fontiter(skiatest::Reporter* reporter, bool verbose) {
+ SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
+ int count = fm->countFamilies();
+
+ for (int i = 0; i < count; ++i) {
+ SkString fname;
+ fm->getFamilyName(i, &fname);
+
+ SkAutoTUnref<SkFontStyleSet> fnset(fm->matchFamily(fname.c_str()));
+ SkAutoTUnref<SkFontStyleSet> set(fm->createStyleSet(i));
+ REPORTER_ASSERT(reporter, fnset->count() == set->count());
+
+ if (verbose) {
+ SkDebugf("[%2d] %s\n", i, fname.c_str());
+ }
+
+ for (int j = 0; j < set->count(); ++j) {
+ SkString sname;
+ SkFontStyle fs;
+ set->getStyle(j, &fs, &sname);
+// REPORTER_ASSERT(reporter, sname.size() > 0);
+
+ SkAutoTUnref<SkTypeface> face(set->createTypeface(j));
+// REPORTER_ASSERT(reporter, face.get());
+
+ if (verbose) {
+ SkDebugf("\t[%d] %s [%3d %d %d]\n", j, sname.c_str(),
+ fs.weight(), fs.width(), fs.isItalic());
+ }
+ }
+ }
+}
+
+DEFINE_bool(verboseFontMgr, false, "run verbose fontmgr tests.");
+
+DEF_TEST(FontMgr, reporter) {
+ test_fontiter(reporter, FLAGS_verboseFontMgr);
+ test_alias_names(reporter);
+ test_font(reporter);
+}
diff --git a/src/third_party/skia/tests/FontNamesTest.cpp b/src/third_party/skia/tests/FontNamesTest.cpp
new file mode 100644
index 0000000..5c314e4
--- /dev/null
+++ b/src/third_party/skia/tests/FontNamesTest.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCommandLineFlags.h"
+#include "SkFontMgr.h"
+#include "SkOTTable_name.h"
+#include "SkTypeface.h"
+#include "Test.h"
+
+#include <stddef.h>
+
+template <size_t R, size_t D> struct Format0NameTable {
+ SkOTTableName header;
+ SkOTTableName::Record nameRecord[R];
+ char data[D];
+};
+
+template <size_t R, size_t L, size_t D> struct Format1NameTable {
+ SkOTTableName header;
+ SkOTTableName::Record nameRecord[R];
+ struct {
+ SkOTTableName::Format1Ext header;
+ SkOTTableName::Format1Ext::LangTagRecord langTagRecord[L];
+ } format1ext;
+ char data[D];
+};
+
+typedef Format0NameTable<1, 9> SimpleFormat0NameTable;
+SimpleFormat0NameTable simpleFormat0NameTable = {
+ /*header*/ {
+ /*format*/ SkOTTableName::format_0,
+ /*count*/ SkTEndianSwap16<1>::value,
+ /*stringOffset*/ SkTEndianSwap16<offsetof(SimpleFormat0NameTable, data)>::value,
+ },
+ /*nameRecord[]*/ {
+ /*Record*/ {
+ /*platformID*/ { SkOTTableName::Record::PlatformID::Windows },
+ /*encodingID*/ { SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2 },
+ /*languageID*/ { SkOTTableName::Record::LanguageID::Windows::English_UnitedStates },
+ /*nameID*/ { SkOTTableName::Record::NameID::Predefined::FontFamilyName },
+ /*length*/ SkTEndianSwap16<8>::value,
+ /*offset*/ SkTEndianSwap16<0>::value,
+ }
+ },
+ /*data*/ "\x0" "T" "\x0" "e" "\x0" "s" "\x0" "t",
+};
+
+typedef Format1NameTable<1, 1, 19> SimpleFormat1NameTable;
+SimpleFormat1NameTable simpleFormat1NameTable = {
+ /*header*/ {
+ /*format*/ SkOTTableName::format_1,
+ /*count*/ SkTEndianSwap16<1>::value,
+ /*stringOffset*/ SkTEndianSwap16<offsetof(SimpleFormat1NameTable, data)>::value,
+ },
+ /*nameRecord[]*/ {
+ /*Record*/ {
+ /*platformID*/ { SkOTTableName::Record::PlatformID::Windows },
+ /*encodingID*/ { SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2 },
+ /*languageID*/ { SkTEndianSwap16<0x8000 + 0>::value },
+ /*nameID*/ { SkOTTableName::Record::NameID::Predefined::FontFamilyName },
+ /*length*/ SkTEndianSwap16<8>::value,
+ /*offset*/ SkTEndianSwap16<0>::value,
+ }
+ },
+ /*format1ext*/ {
+ /*header*/ {
+ /*langTagCount*/ SkTEndianSwap16<1>::value,
+ },
+ /*langTagRecord[]*/ {
+ /*LangTagRecord*/ {
+ /*length*/ SkTEndianSwap16<10>::value,
+ /*offset*/ SkTEndianSwap16<8>::value,
+ },
+ },
+ },
+ /*data*/ "\x0" "T" "\x0" "e" "\x0" "s" "\x0" "t"
+ "\x0" "e" "\x0" "n" "\x0" "-" "\x0" "U" "\x0" "S",
+};
+
+struct FontNamesTest {
+ SkOTTableName* data;
+ SkOTTableName::Record::NameID nameID;
+ size_t nameCount;
+ struct {
+ const char* name;
+ const char* language;
+ } names[10];
+
+} test[] = {
+ {
+ (SkOTTableName*)&simpleFormat0NameTable,
+ { SkOTTableName::Record::NameID::Predefined::FontFamilyName },
+ 1,
+ {
+ { "Test", "en-US" },
+ },
+ },
+ {
+ (SkOTTableName*)&simpleFormat1NameTable,
+ { SkOTTableName::Record::NameID::Predefined::FontFamilyName },
+ 1,
+ {
+ { "Test", "en-US" },
+ },
+ },
+};
+
+static void test_synthetic(skiatest::Reporter* reporter, bool verbose) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(test); ++i) {
+ SkOTTableName::Iterator iter(*test[i].data, test[i].nameID.predefined.value);
+ SkOTTableName::Iterator::Record record;
+ size_t nameIndex = 0;
+ while (nameIndex < test[i].nameCount && iter.next(record)) {
+ REPORTER_ASSERT_MESSAGE(reporter,
+ strcmp(test[i].names[nameIndex].name, record.name.c_str()) == 0,
+ "Name did not match."
+ );
+
+ REPORTER_ASSERT_MESSAGE(reporter,
+ strcmp(test[i].names[nameIndex].language, record.language.c_str()) == 0,
+ "Language did not match."
+ );
+
+ //printf("%s <%s>\n", record.name.c_str(), record.language.c_str());
+
+ ++nameIndex;
+ }
+
+ REPORTER_ASSERT_MESSAGE(reporter, nameIndex == test[i].nameCount,
+ "Fewer names than expected.");
+
+ REPORTER_ASSERT_MESSAGE(reporter, !iter.next(record),
+ "More names than expected.");
+ }
+}
+
+#define MAX_FAMILIES 1000
+static void test_systemfonts(skiatest::Reporter* reporter, bool verbose) {
+ static const SkFontTableTag nameTag = SkSetFourByteTag('n','a','m','e');
+
+ SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
+ int count = SkMin32(fm->countFamilies(), MAX_FAMILIES);
+ for (int i = 0; i < count; ++i) {
+ SkAutoTUnref<SkFontStyleSet> set(fm->createStyleSet(i));
+ for (int j = 0; j < set->count(); ++j) {
+ SkString sname;
+ SkFontStyle fs;
+ set->getStyle(j, &fs, &sname);
+
+ SkAutoTUnref<SkTypeface> typeface(set->createTypeface(j));
+
+ SkString familyName;
+ typeface->getFamilyName(&familyName);
+ if (verbose) {
+ SkDebugf("[%s]\n", familyName.c_str());
+ }
+
+ SkAutoTUnref<SkTypeface::LocalizedStrings> familyNamesIter(
+ typeface->createFamilyNameIterator());
+ SkTypeface::LocalizedString familyNameLocalized;
+ while (familyNamesIter->next(&familyNameLocalized)) {
+ if (verbose) {
+ SkDebugf("(%s) <%s>\n", familyNameLocalized.fString.c_str(),
+ familyNameLocalized.fLanguage.c_str());
+ }
+ }
+
+ size_t nameTableSize = typeface->getTableSize(nameTag);
+ if (0 == nameTableSize) {
+ continue;
+ }
+ SkAutoTMalloc<uint8_t> nameTableData(nameTableSize);
+ size_t copied = typeface->getTableData(nameTag, 0, nameTableSize, nameTableData.get());
+ if (copied != nameTableSize) {
+ continue;
+ }
+
+ SkOTTableName::Iterator::Record record;
+ SkOTTableName::Iterator familyNameIter(*((SkOTTableName*)nameTableData.get()),
+ SkOTTableName::Record::NameID::Predefined::FontFamilyName);
+ while (familyNameIter.next(record)) {
+ REPORTER_ASSERT_MESSAGE(reporter,
+ SkOTTableName::Record::NameID::Predefined::FontFamilyName == record.type,
+ "Requested family name, got something else."
+ );
+ if (verbose) {
+ SkDebugf("{%s} <%s>\n", record.name.c_str(), record.language.c_str());
+ }
+ }
+
+ SkOTTableName::Iterator styleNameIter(*((SkOTTableName*)nameTableData.get()),
+ SkOTTableName::Record::NameID::Predefined::FontSubfamilyName);
+ while (styleNameIter.next(record)) {
+ REPORTER_ASSERT_MESSAGE(reporter,
+ SkOTTableName::Record::NameID::Predefined::FontSubfamilyName == record.type,
+ "Requested subfamily name, got something else."
+ );
+ if (verbose) {
+ SkDebugf("{{%s}} <%s>\n", record.name.c_str(), record.language.c_str());
+ }
+ }
+
+ if (verbose) {
+ SkDebugf("\n");
+ }
+ }
+ }
+}
+
+DEFINE_bool(verboseFontNames, false, "verbose FontNames test.");
+
+DEF_TEST(FontNames, reporter) {
+ test_synthetic(reporter, FLAGS_verboseFontNames);
+ test_systemfonts(reporter, FLAGS_verboseFontNames);
+}
diff --git a/src/third_party/skia/tests/FontObjTest.cpp b/src/third_party/skia/tests/FontObjTest.cpp
new file mode 100644
index 0000000..c2d8f5d
--- /dev/null
+++ b/src/third_party/skia/tests/FontObjTest.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkFont.h"
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include "Test.h"
+
+static bool is_use_nonlinear_metrics(const SkPaint& paint) {
+ return !paint.isSubpixelText() && !paint.isLinearText();
+}
+
+static bool is_enable_auto_hints(const SkPaint& paint) {
+ return paint.isAutohinted();
+}
+
+static bool is_enable_bytecode_hints(const SkPaint& paint) {
+ return paint.getHinting() >= SkPaint::kFull_Hinting;
+}
+
+static void test_cachedfont(skiatest::Reporter* reporter, const SkPaint& paint) {
+ SkAutoTUnref<SkFont> font(SkFont::Testing_CreateFromPaint(paint));
+
+ // Currently SkFont resolves null into the default, so only test if paint's is not null
+ if (paint.getTypeface()) {
+ REPORTER_ASSERT(reporter, font->getTypeface() == paint.getTypeface());
+ }
+ REPORTER_ASSERT(reporter, font->getSize() == paint.getTextSize());
+ REPORTER_ASSERT(reporter, font->getScaleX() == paint.getTextScaleX());
+ REPORTER_ASSERT(reporter, font->getSkewX() == paint.getTextSkewX());
+
+ REPORTER_ASSERT(reporter, font->isVertical() == paint.isVerticalText());
+ REPORTER_ASSERT(reporter, font->isEmbolden() == paint.isFakeBoldText());
+
+ REPORTER_ASSERT(reporter, font->isUseNonLinearMetrics() == is_use_nonlinear_metrics(paint));
+ REPORTER_ASSERT(reporter, font->isEnableAutoHints() == is_enable_auto_hints(paint));
+ REPORTER_ASSERT(reporter, font->isEnableByteCodeHints() == is_enable_bytecode_hints(paint));
+}
+
+static void test_cachedfont(skiatest::Reporter* reporter) {
+ static const char* const faces[] = {
+ NULL, // default font
+ "Arial", "Times", "Times New Roman", "Helvetica", "Courier",
+ "Courier New", "Verdana", "monospace",
+ };
+
+ static const struct {
+ SkPaint::Hinting hinting;
+ unsigned flags;
+ } settings[] = {
+ { SkPaint::kNo_Hinting, 0 },
+ { SkPaint::kNo_Hinting, SkPaint::kLinearText_Flag },
+ { SkPaint::kNo_Hinting, SkPaint::kSubpixelText_Flag },
+ { SkPaint::kSlight_Hinting, 0 },
+ { SkPaint::kSlight_Hinting, SkPaint::kLinearText_Flag },
+ { SkPaint::kSlight_Hinting, SkPaint::kSubpixelText_Flag },
+ { SkPaint::kNormal_Hinting, 0 },
+ { SkPaint::kNormal_Hinting, SkPaint::kLinearText_Flag },
+ { SkPaint::kNormal_Hinting, SkPaint::kSubpixelText_Flag },
+ };
+
+ static const struct {
+ SkScalar fScaleX;
+ SkScalar fSkewX;
+ } gScaleRec[] = {
+ { SK_Scalar1, 0 },
+ { SK_Scalar1/2, 0 },
+ // these two exercise obliquing (skew)
+ { SK_Scalar1, -SK_Scalar1/4 },
+ { SK_Scalar1/2, -SK_Scalar1/4 },
+ };
+
+ SkPaint paint;
+ char txt[] = "long.text.with.lots.of.dots.";
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(faces); i++) {
+ SkAutoTUnref<SkTypeface> face(SkTypeface::CreateFromName(faces[i], SkTypeface::kNormal));
+ paint.setTypeface(face);
+
+ for (size_t j = 0; j < SK_ARRAY_COUNT(settings); j++) {
+ paint.setHinting(settings[j].hinting);
+ paint.setLinearText((settings[j].flags & SkPaint::kLinearText_Flag) != 0);
+ paint.setSubpixelText((settings[j].flags & SkPaint::kSubpixelText_Flag) != 0);
+
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gScaleRec); ++k) {
+ paint.setTextScaleX(gScaleRec[k].fScaleX);
+ paint.setTextSkewX(gScaleRec[k].fSkewX);
+
+ test_cachedfont(reporter, paint);
+
+ SkRect bounds;
+
+ // For no hinting and light hinting this should take the
+ // optimized generateAdvance path.
+ SkScalar width1 = paint.measureText(txt, strlen(txt));
+
+ // Requesting the bounds forces a generateMetrics call.
+ SkScalar width2 = paint.measureText(txt, strlen(txt), &bounds);
+
+ REPORTER_ASSERT(reporter, width1 == width2);
+
+ SkAutoTUnref<SkFont> font(SkFont::Testing_CreateFromPaint(paint));
+ SkScalar font_width1 = font->measureText(txt, strlen(txt), kUTF8_SkTextEncoding);
+ // measureText not yet implemented...
+ REPORTER_ASSERT(reporter, font_width1 == -1);
+// REPORTER_ASSERT(reporter, width1 == font_width1);
+ }
+ }
+ }
+}
+
+DEF_TEST(FontObj, reporter) {
+ test_cachedfont(reporter);
+}
+
+// need tests for SkStrSearch
diff --git a/src/third_party/skia/tests/FrontBufferedStreamTest.cpp b/src/third_party/skia/tests/FrontBufferedStreamTest.cpp
new file mode 100644
index 0000000..cb11b12
--- /dev/null
+++ b/src/third_party/skia/tests/FrontBufferedStreamTest.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkFrontBufferedStream.h"
+#include "SkRefCnt.h"
+#include "SkStream.h"
+#include "SkTypes.h"
+#include "Test.h"
+
+static void test_read(skiatest::Reporter* reporter, SkStream* bufferedStream,
+ const void* expectations, size_t bytesToRead) {
+ // output for reading bufferedStream.
+ SkAutoMalloc storage(bytesToRead);
+
+ const size_t bytesRead = bufferedStream->read(storage.get(), bytesToRead);
+ REPORTER_ASSERT(reporter, bytesRead == bytesToRead || bufferedStream->isAtEnd());
+ REPORTER_ASSERT(reporter, memcmp(storage.get(), expectations, bytesRead) == 0);
+}
+
+static void test_rewind(skiatest::Reporter* reporter,
+ SkStream* bufferedStream, bool shouldSucceed) {
+ const bool success = bufferedStream->rewind();
+ REPORTER_ASSERT(reporter, success == shouldSucceed);
+}
+
+// Test that hasLength() returns the correct value, based on the stream
+// being wrapped. A length can only be known if the wrapped stream has a
+// length and it has a position (so its initial position can be taken into
+// account when computing the length).
+static void test_hasLength(skiatest::Reporter* reporter,
+ const SkStream& bufferedStream,
+ const SkStream& streamBeingBuffered) {
+ if (streamBeingBuffered.hasLength() && streamBeingBuffered.hasPosition()) {
+ REPORTER_ASSERT(reporter, bufferedStream.hasLength());
+ } else {
+ REPORTER_ASSERT(reporter, !bufferedStream.hasLength());
+ }
+}
+
+// All tests will buffer this string, and compare output to the original.
+// The string is long to ensure that all of our lengths being tested are
+// smaller than the string length.
+const char gAbcs[] = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx";
+
+// Tests reading the stream across boundaries of what has been buffered so far and what
+// the total buffer size is.
+static void test_incremental_buffering(skiatest::Reporter* reporter, size_t bufferSize) {
+ SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
+
+ SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize));
+ test_hasLength(reporter, *bufferedStream.get(), memStream);
+
+ // First, test reading less than the max buffer size.
+ test_read(reporter, bufferedStream, gAbcs, bufferSize / 2);
+
+ // Now test rewinding back to the beginning and reading less than what was
+ // already buffered.
+ test_rewind(reporter, bufferedStream, true);
+ test_read(reporter, bufferedStream, gAbcs, bufferSize / 4);
+
+ // Now test reading part of what was buffered, and buffering new data.
+ test_read(reporter, bufferedStream, gAbcs + bufferedStream->getPosition(), bufferSize / 2);
+
+ // Now test reading what was buffered, buffering new data, and
+ // reading directly from the stream.
+ test_rewind(reporter, bufferedStream, true);
+ test_read(reporter, bufferedStream, gAbcs, bufferSize << 1);
+
+ // We have reached the end of the buffer, so rewinding will fail.
+ // This test assumes that the stream is larger than the buffer; otherwise the
+ // result of rewind should be true.
+ test_rewind(reporter, bufferedStream, false);
+}
+
+static void test_perfectly_sized_buffer(skiatest::Reporter* reporter, size_t bufferSize) {
+ SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
+ SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize));
+ test_hasLength(reporter, *bufferedStream.get(), memStream);
+
+ // Read exactly the amount that fits in the buffer.
+ test_read(reporter, bufferedStream, gAbcs, bufferSize);
+
+ // Rewinding should succeed.
+ test_rewind(reporter, bufferedStream, true);
+
+ // Once again reading buffered info should succeed
+ test_read(reporter, bufferedStream, gAbcs, bufferSize);
+
+ // Read past the size of the buffer. At this point, we cannot return.
+ test_read(reporter, bufferedStream, gAbcs + bufferedStream->getPosition(), 1);
+ test_rewind(reporter, bufferedStream, false);
+}
+
+static void test_skipping(skiatest::Reporter* reporter, size_t bufferSize) {
+ SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
+ SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize));
+ test_hasLength(reporter, *bufferedStream.get(), memStream);
+
+ // Skip half the buffer.
+ bufferedStream->skip(bufferSize / 2);
+
+ // Rewind, then read part of the buffer, which should have been read.
+ test_rewind(reporter, bufferedStream, true);
+ test_read(reporter, bufferedStream, gAbcs, bufferSize / 4);
+
+ // Now skip beyond the buffered piece, but still within the total buffer.
+ bufferedStream->skip(bufferSize / 2);
+
+ // Test that reading will still work.
+ test_read(reporter, bufferedStream, gAbcs + bufferedStream->getPosition(), bufferSize / 4);
+
+ test_rewind(reporter, bufferedStream, true);
+ test_read(reporter, bufferedStream, gAbcs, bufferSize);
+}
+
+// A custom class whose isAtEnd behaves the way Android's stream does - since it is an adaptor to a
+// Java InputStream, it does not know that it is at the end until it has attempted to read beyond
+// the end and failed. Used by test_read_beyond_buffer.
+class AndroidLikeMemoryStream : public SkMemoryStream {
+public:
+ AndroidLikeMemoryStream(void* data, size_t size, bool ownMemory)
+ : INHERITED(data, size, ownMemory)
+ , fIsAtEnd(false) {}
+
+ size_t read(void* dst, size_t requested) SK_OVERRIDE {
+ size_t bytesRead = this->INHERITED::read(dst, requested);
+ if (bytesRead < requested) {
+ fIsAtEnd = true;
+ }
+ return bytesRead;
+ }
+
+ bool isAtEnd() const SK_OVERRIDE {
+ return fIsAtEnd;
+ }
+
+private:
+ bool fIsAtEnd;
+ typedef SkMemoryStream INHERITED;
+};
+
+// This test ensures that buffering the exact length of the stream and attempting to read beyond it
+// does not invalidate the buffer.
+static void test_read_beyond_buffer(skiatest::Reporter* reporter, size_t bufferSize) {
+ // Use a stream that behaves like Android's stream.
+ AndroidLikeMemoryStream memStream((void*)gAbcs, bufferSize, false);
+
+ // Create a buffer that matches the length of the stream.
+ SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize));
+ test_hasLength(reporter, *bufferedStream.get(), memStream);
+
+ // Attempt to read one more than the bufferSize
+ test_read(reporter, bufferedStream.get(), gAbcs, bufferSize + 1);
+ test_rewind(reporter, bufferedStream.get(), true);
+
+ // Ensure that the initial read did not invalidate the buffer.
+ test_read(reporter, bufferedStream, gAbcs, bufferSize);
+}
+
+// Dummy stream that optionally has a length and/or position. Tests that FrontBufferedStream's
+// length depends on the stream it's buffering having a length and position.
+class LengthOptionalStream : public SkStream {
+public:
+ LengthOptionalStream(bool hasLength, bool hasPosition)
+ : fHasLength(hasLength)
+ , fHasPosition(hasPosition)
+ {}
+
+ virtual bool hasLength() const SK_OVERRIDE {
+ return fHasLength;
+ }
+
+ virtual bool hasPosition() const SK_OVERRIDE {
+ return fHasPosition;
+ }
+
+ virtual size_t read(void*, size_t) SK_OVERRIDE {
+ return 0;
+ }
+
+ virtual bool isAtEnd() const SK_OVERRIDE {
+ return true;
+ }
+
+private:
+ const bool fHasLength;
+ const bool fHasPosition;
+};
+
+// Test all possible combinations of the wrapped stream having a length and a position.
+static void test_length_combos(skiatest::Reporter* reporter, size_t bufferSize) {
+ for (int hasLen = 0; hasLen <= 1; hasLen++) {
+ for (int hasPos = 0; hasPos <= 1; hasPos++) {
+ LengthOptionalStream stream(SkToBool(hasLen), SkToBool(hasPos));
+ SkAutoTUnref<SkStream> buffered(SkFrontBufferedStream::Create(&stream, bufferSize));
+ test_hasLength(reporter, *buffered.get(), stream);
+ }
+ }
+}
+
+// Test using a stream with an initial offset.
+static void test_initial_offset(skiatest::Reporter* reporter, size_t bufferSize) {
+ SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
+
+ // Skip a few characters into the memStream, so that bufferedStream represents an offset into
+ // the stream it wraps.
+ const size_t arbitraryOffset = 17;
+ memStream.skip(arbitraryOffset);
+ SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize));
+
+ // Since SkMemoryStream has a length and a position, bufferedStream must also.
+ REPORTER_ASSERT(reporter, bufferedStream->hasLength());
+
+ const size_t amountToRead = 10;
+ const size_t bufferedLength = bufferedStream->getLength();
+ size_t currentPosition = bufferedStream->getPosition();
+ REPORTER_ASSERT(reporter, 0 == currentPosition);
+
+ // Read the stream in chunks. After each read, the position must match currentPosition,
+ // which sums the amount attempted to read, unless the end of the stream has been reached.
+ // Importantly, the end should not have been reached until currentPosition == bufferedLength.
+ while (currentPosition < bufferedLength) {
+ REPORTER_ASSERT(reporter, !bufferedStream->isAtEnd());
+ test_read(reporter, bufferedStream, gAbcs + arbitraryOffset + currentPosition,
+ amountToRead);
+ currentPosition = SkTMin(currentPosition + amountToRead, bufferedLength);
+ REPORTER_ASSERT(reporter, bufferedStream->getPosition() == currentPosition);
+ }
+ REPORTER_ASSERT(reporter, bufferedStream->isAtEnd());
+ REPORTER_ASSERT(reporter, bufferedLength == currentPosition);
+}
+
+static void test_buffers(skiatest::Reporter* reporter, size_t bufferSize) {
+ test_incremental_buffering(reporter, bufferSize);
+ test_perfectly_sized_buffer(reporter, bufferSize);
+ test_skipping(reporter, bufferSize);
+ test_read_beyond_buffer(reporter, bufferSize);
+ test_length_combos(reporter, bufferSize);
+ test_initial_offset(reporter, bufferSize);
+}
+
+DEF_TEST(FrontBufferedStream, reporter) {
+ // Test 6 and 64, which are used by Android, as well as another arbitrary length.
+ test_buffers(reporter, 6);
+ test_buffers(reporter, 15);
+ test_buffers(reporter, 64);
+}
diff --git a/src/third_party/skia/tests/GLInterfaceValidationTest.cpp b/src/third_party/skia/tests/GLInterfaceValidationTest.cpp
new file mode 100755
index 0000000..797ba72
--- /dev/null
+++ b/src/third_party/skia/tests/GLInterfaceValidationTest.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+
+// This is a GPU-backend specific test
+#if SK_SUPPORT_GPU
+
+#include "GrContextFactory.h"
+
+DEF_GPUTEST(GLInterfaceValidation, reporter, factory) {
+ for (int i = 0; i <= GrContextFactory::kLastGLContextType; ++i) {
+ GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType)i;
+ // this forces the factory to make the context if it hasn't yet
+ factory->get(glCtxType);
+ SkGLContextHelper* glCtxHelper = factory->getGLContext(glCtxType);
+
+ // We're supposed to fail the NVPR context type when we the native context that does not
+ // support the NVPR extension.
+ if (GrContextFactory::kNVPR_GLContextType == glCtxType &&
+ factory->getGLContext(GrContextFactory::kNative_GLContextType) &&
+ !factory->getGLContext(GrContextFactory::kNative_GLContextType)->hasExtension("GL_NV_path_rendering")) {
+ REPORTER_ASSERT(reporter, NULL == glCtxHelper);
+ continue;
+ }
+
+ REPORTER_ASSERT(reporter, glCtxHelper);
+ if (glCtxHelper) {
+ const GrGLInterface* interface = glCtxHelper->gl();
+ REPORTER_ASSERT(reporter, interface->validate());
+ }
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GLProgramsTest.cpp b/src/third_party/skia/tests/GLProgramsTest.cpp
new file mode 100644
index 0000000..a16173b
--- /dev/null
+++ b/src/third_party/skia/tests/GLProgramsTest.cpp
@@ -0,0 +1,395 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// This is a GPU-backend specific test. It relies on static intializers to work
+
+#include "SkTypes.h"
+
+#if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+
+#include "GrBackendProcessorFactory.h"
+#include "GrContextFactory.h"
+#include "GrOptDrawState.h"
+#include "effects/GrConfigConversionEffect.h"
+#include "gl/GrGLPathRendering.h"
+#include "gl/GrGpuGL.h"
+#include "SkChecksum.h"
+#include "SkRandom.h"
+#include "Test.h"
+
+static void get_stage_stats(const GrFragmentStage stage, bool* readsDst,
+ bool* readsFragPosition, bool* requiresVertexShader) {
+ if (stage.getFragmentProcessor()->willReadDstColor()) {
+ *readsDst = true;
+ }
+ if (stage.getProcessor()->willReadFragmentPosition()) {
+ *readsFragPosition = true;
+ }
+}
+
+bool GrGLProgramDesc::setRandom(SkRandom* random,
+ GrGpuGL* gpu,
+ const GrRenderTarget* dstRenderTarget,
+ const GrTexture* dstCopyTexture,
+ const GrGeometryStage* geometryProcessor,
+ const GrFragmentStage* stages[],
+ int numColorStages,
+ int numCoverageStages,
+ int currAttribIndex,
+ GrGpu::DrawType drawType) {
+ bool isPathRendering = GrGpu::IsPathRenderingDrawType(drawType);
+ bool useLocalCoords = !isPathRendering &&
+ random->nextBool() &&
+ currAttribIndex < GrDrawState::kMaxVertexAttribCnt;
+
+ int numStages = numColorStages + numCoverageStages;
+ fKey.reset();
+
+ GR_STATIC_ASSERT(0 == kEffectKeyOffsetsAndLengthOffset % sizeof(uint32_t));
+
+ // Make room for everything up to and including the array of offsets to effect keys.
+ fKey.push_back_n(kEffectKeyOffsetsAndLengthOffset + 2 * sizeof(uint16_t) * (numStages +
+ (geometryProcessor ? 1 : 0)));
+
+ bool dstRead = false;
+ bool fragPos = false;
+ bool vertexShader = SkToBool(geometryProcessor);
+ int offset = 0;
+ if (geometryProcessor) {
+ const GrGeometryStage* stage = geometryProcessor;
+ uint16_t* offsetAndSize = reinterpret_cast<uint16_t*>(fKey.begin() +
+ kEffectKeyOffsetsAndLengthOffset +
+ offset * 2 * sizeof(uint16_t));
+ uint32_t effectKeyOffset = fKey.count();
+ if (effectKeyOffset > SK_MaxU16) {
+ fKey.reset();
+ return false;
+ }
+ GrProcessorKeyBuilder b(&fKey);
+ uint16_t effectKeySize;
+ if (!GetProcessorKey(*stage, gpu->glCaps(), useLocalCoords, &b, &effectKeySize)) {
+ fKey.reset();
+ return false;
+ }
+ vertexShader = true;
+ fragPos = stage->getProcessor()->willReadFragmentPosition();
+ offsetAndSize[0] = effectKeyOffset;
+ offsetAndSize[1] = effectKeySize;
+ offset++;
+ }
+
+ for (int s = 0; s < numStages; ++s, ++offset) {
+ const GrFragmentStage* stage = stages[s];
+ uint16_t* offsetAndSize = reinterpret_cast<uint16_t*>(fKey.begin() +
+ kEffectKeyOffsetsAndLengthOffset +
+ offset * 2 * sizeof(uint16_t));
+ uint32_t effectKeyOffset = fKey.count();
+ if (effectKeyOffset > SK_MaxU16) {
+ fKey.reset();
+ return false;
+ }
+ GrProcessorKeyBuilder b(&fKey);
+ uint16_t effectKeySize;
+ if (!GetProcessorKey(*stages[s], gpu->glCaps(), useLocalCoords, &b, &effectKeySize)) {
+ fKey.reset();
+ return false;
+ }
+ get_stage_stats(*stage, &dstRead, &fragPos, &vertexShader);
+ offsetAndSize[0] = effectKeyOffset;
+ offsetAndSize[1] = effectKeySize;
+ }
+
+ KeyHeader* header = this->header();
+ memset(header, 0, kHeaderSize);
+ header->fEmitsPointSize = random->nextBool();
+
+ header->fPositionAttributeIndex = 0;
+
+ // if the effects have used up all off the available attributes,
+ // don't try to use color or coverage attributes as input
+ do {
+ header->fColorInput = static_cast<GrGLProgramDesc::ColorInput>(
+ random->nextULessThan(kColorInputCnt));
+ } while ((GrDrawState::kMaxVertexAttribCnt <= currAttribIndex || isPathRendering) &&
+ kAttribute_ColorInput == header->fColorInput);
+ header->fColorAttributeIndex = (header->fColorInput == kAttribute_ColorInput) ?
+ currAttribIndex++ :
+ -1;
+
+ do {
+ header->fCoverageInput = static_cast<GrGLProgramDesc::ColorInput>(
+ random->nextULessThan(kColorInputCnt));
+ } while ((GrDrawState::kMaxVertexAttribCnt <= currAttribIndex || isPathRendering) &&
+ kAttribute_ColorInput == header->fCoverageInput);
+ header->fCoverageAttributeIndex = (header->fCoverageInput == kAttribute_ColorInput) ?
+ currAttribIndex++ :
+ -1;
+ bool useGS = random->nextBool();
+#if GR_GL_EXPERIMENTAL_GS
+ header->fExperimentalGS = gpu->caps()->geometryShaderSupport() && useGS;
+#else
+ (void) useGS;
+#endif
+
+ header->fLocalCoordAttributeIndex = useLocalCoords ? currAttribIndex++ : -1;
+
+ header->fColorEffectCnt = numColorStages;
+ header->fCoverageEffectCnt = numCoverageStages;
+
+ if (dstRead) {
+ header->fDstReadKey = SkToU8(GrGLFragmentShaderBuilder::KeyForDstRead(dstCopyTexture,
+ gpu->glCaps()));
+ } else {
+ header->fDstReadKey = 0;
+ }
+ if (fragPos) {
+ header->fFragPosKey = SkToU8(GrGLFragmentShaderBuilder::KeyForFragmentPosition(dstRenderTarget,
+ gpu->glCaps()));
+ } else {
+ header->fFragPosKey = 0;
+ }
+
+ header->fUseFragShaderOnly = isPathRendering && gpu->glPathRendering()->texturingMode() ==
+ GrGLPathRendering::FixedFunction_TexturingMode;
+ header->fHasGeometryProcessor = vertexShader;
+
+ GrOptDrawState::PrimaryOutputType primaryOutput;
+ GrOptDrawState::SecondaryOutputType secondaryOutput;
+ if (!dstRead) {
+ primaryOutput = GrOptDrawState::kModulate_PrimaryOutputType;
+ } else {
+ primaryOutput = static_cast<GrOptDrawState::PrimaryOutputType>(
+ random->nextULessThan(GrOptDrawState::kPrimaryOutputTypeCnt));
+ }
+
+ if (GrOptDrawState::kCombineWithDst_PrimaryOutputType == primaryOutput ||
+ !gpu->caps()->dualSourceBlendingSupport()) {
+ secondaryOutput = GrOptDrawState::kNone_SecondaryOutputType;
+ } else {
+ secondaryOutput = static_cast<GrOptDrawState::SecondaryOutputType>(
+ random->nextULessThan(GrOptDrawState::kSecondaryOutputTypeCnt));
+ }
+
+ header->fPrimaryOutputType = primaryOutput;
+ header->fSecondaryOutputType = secondaryOutput;
+
+ this->finalize();
+ return true;
+}
+
+// TODO clean this up, we have to do this to test geometry processors but there has got to be
+// a better way. In the mean time, we actually fill out these generic vertex attribs below with
+// the correct vertex attribs from the GP. We have to ensure, however, we don't try to add more
+// than two attributes.
+GrVertexAttrib genericVertexAttribs[] = {
+ { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
+ { kVec2f_GrVertexAttribType, 0, kGeometryProcessor_GrVertexAttribBinding },
+ { kVec2f_GrVertexAttribType, 0, kGeometryProcessor_GrVertexAttribBinding }
+};
+
+/*
+ * convert sl type to vertexattrib type, not a complete implementation, only use for debugging
+ */
+GrVertexAttribType convert_sltype_to_attribtype(GrSLType type) {
+ switch (type) {
+ case kFloat_GrSLType:
+ return kFloat_GrVertexAttribType;
+ case kVec2f_GrSLType:
+ return kVec2f_GrVertexAttribType;
+ case kVec3f_GrSLType:
+ return kVec3f_GrVertexAttribType;
+ case kVec4f_GrSLType:
+ return kVec4f_GrVertexAttribType;
+ default:
+ SkFAIL("Type isn't convertible");
+ return kFloat_GrVertexAttribType;
+ }
+}
+// TODO end test hack
+
+
+bool GrGpuGL::programUnitTest(int maxStages) {
+
+ GrTextureDesc dummyDesc;
+ dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit;
+ dummyDesc.fConfig = kSkia8888_GrPixelConfig;
+ dummyDesc.fWidth = 34;
+ dummyDesc.fHeight = 18;
+ SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
+ dummyDesc.fFlags = kNone_GrTextureFlags;
+ dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
+ dummyDesc.fWidth = 16;
+ dummyDesc.fHeight = 22;
+ SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
+
+ if (!dummyTexture1 || ! dummyTexture2) {
+ return false;
+ }
+
+ static const int NUM_TESTS = 512;
+
+ SkRandom random;
+ for (int t = 0; t < NUM_TESTS; ++t) {
+
+#if 0
+ GrPrintf("\nTest Program %d\n-------------\n", t);
+ static const int stop = -1;
+ if (t == stop) {
+ int breakpointhere = 9;
+ }
+#endif
+
+ GrGLProgramDesc pdesc;
+
+ int currAttribIndex = 1; // we need to always leave room for position
+ int currTextureCoordSet = 0;
+ GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
+
+ int numStages = random.nextULessThan(maxStages + 1);
+ int numColorStages = random.nextULessThan(numStages + 1);
+ int numCoverageStages = numStages - numColorStages;
+
+ SkAutoSTMalloc<8, const GrFragmentStage*> stages(numStages);
+
+ bool usePathRendering = this->glCaps().pathRenderingSupport() && random.nextBool();
+
+ GrGpu::DrawType drawType = usePathRendering ? GrGpu::kDrawPath_DrawType :
+ GrGpu::kDrawPoints_DrawType;
+
+ SkAutoTDelete<GrGeometryStage> geometryProcessor;
+ bool hasGeometryProcessor = usePathRendering ? false : random.nextBool();
+ if (hasGeometryProcessor) {
+ while (true) {
+ SkAutoTUnref<const GrGeometryProcessor> effect(
+ GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(&random, this->getContext(), *this->caps(),
+ dummyTextures));
+ SkASSERT(effect);
+ // Only geometryProcessor can use vertex shader
+ GrGeometryStage* stage = SkNEW_ARGS(GrGeometryStage, (effect.get()));
+ geometryProcessor.reset(stage);
+
+ // we have to set dummy vertex attribs
+ const GrGeometryProcessor::VertexAttribArray& v = effect->getVertexAttribs();
+ int numVertexAttribs = v.count();
+
+ SkASSERT(GrGeometryProcessor::kMaxVertexAttribs == 2 &&
+ GrGeometryProcessor::kMaxVertexAttribs >= numVertexAttribs);
+ size_t runningStride = GrVertexAttribTypeSize(genericVertexAttribs[0].fType);
+ for (int i = 0; i < numVertexAttribs; i++) {
+ genericVertexAttribs[i + 1].fOffset = runningStride;
+ genericVertexAttribs[i + 1].fType =
+ convert_sltype_to_attribtype(v[i].getType());
+ runningStride += GrVertexAttribTypeSize(genericVertexAttribs[i + 1].fType);
+ }
+
+ // update the vertex attributes with the ds
+ GrDrawState* ds = this->drawState();
+ ds->setVertexAttribs<genericVertexAttribs>(numVertexAttribs + 1, runningStride);
+ currAttribIndex = numVertexAttribs + 1;
+ break;
+ }
+ }
+ for (int s = 0; s < numStages;) {
+ SkAutoTUnref<const GrFragmentProcessor> effect(
+ GrProcessorTestFactory<GrFragmentProcessor>::CreateStage(
+ &random,
+ this->getContext(),
+ *this->caps(),
+ dummyTextures));
+ SkASSERT(effect);
+
+ // If adding this effect would exceed the max texture coord set count then generate a
+ // new random effect.
+ if (usePathRendering && this->glPathRendering()->texturingMode() ==
+ GrGLPathRendering::FixedFunction_TexturingMode) {;
+ int numTransforms = effect->numTransforms();
+ if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) {
+ continue;
+ }
+ currTextureCoordSet += numTransforms;
+ }
+ GrFragmentStage* stage = SkNEW_ARGS(GrFragmentStage, (effect.get()));
+
+ stages[s] = stage;
+ ++s;
+ }
+ const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1];
+ if (!pdesc.setRandom(&random,
+ this,
+ dummyTextures[0]->asRenderTarget(),
+ dstTexture,
+ geometryProcessor.get(),
+ stages.get(),
+ numColorStages,
+ numCoverageStages,
+ currAttribIndex,
+ drawType)) {
+ return false;
+ }
+
+ SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this,
+ pdesc,
+ geometryProcessor.get(),
+ stages,
+ stages + numColorStages));
+ for (int s = 0; s < numStages; ++s) {
+ SkDELETE(stages[s]);
+ }
+ if (NULL == program.get()) {
+ return false;
+ }
+
+ // We have to reset the drawstate because we might have added a gp
+ this->drawState()->reset();
+ }
+ return true;
+}
+
+DEF_GPUTEST(GLPrograms, reporter, factory) {
+ for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
+ GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
+ if (context) {
+ GrGpuGL* gpu = static_cast<GrGpuGL*>(context->getGpu());
+ int maxStages = 6;
+#if SK_ANGLE
+ // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
+ if (type == GrContextFactory::kANGLE_GLContextType) {
+ maxStages = 3;
+ }
+#endif
+ REPORTER_ASSERT(reporter, gpu->programUnitTest(maxStages));
+ }
+ }
+}
+
+// This is evil evil evil. The linker may throw away whole translation units as dead code if it
+// thinks none of the functions are called. It will do this even if there are static initializers
+// in the unit that could pass pointers to functions from the unit out to other translation units!
+// We force some of the effects that would otherwise be discarded to link here.
+
+#include "SkAlphaThresholdFilter.h"
+#include "SkColorMatrixFilter.h"
+#include "SkLightingImageFilter.h"
+#include "SkMagnifierImageFilter.h"
+
+void forceLinking();
+
+void forceLinking() {
+ SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0);
+ SkAlphaThresholdFilter::Create(SkRegion(), .5f, .5f);
+ SkAutoTUnref<SkImageFilter> mag(SkMagnifierImageFilter::Create(
+ SkRect::MakeWH(SK_Scalar1, SK_Scalar1), SK_Scalar1));
+ GrConfigConversionEffect::Create(NULL,
+ false,
+ GrConfigConversionEffect::kNone_PMConversion,
+ SkMatrix::I());
+ SkScalar matrix[20];
+ SkAutoTUnref<SkColorMatrixFilter> cmf(SkColorMatrixFilter::Create(matrix));
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GeometryTest.cpp b/src/third_party/skia/tests/GeometryTest.cpp
new file mode 100644
index 0000000..5151b70
--- /dev/null
+++ b/src/third_party/skia/tests/GeometryTest.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkGeometry.h"
+#include "Test.h"
+
+static bool nearly_equal(const SkPoint& a, const SkPoint& b) {
+ return SkScalarNearlyEqual(a.fX, b.fX) && SkScalarNearlyEqual(a.fY, b.fY);
+}
+
+static void testChopCubic(skiatest::Reporter* reporter) {
+ /*
+ Inspired by this test, which used to assert that the tValues had dups
+
+ <path stroke="#202020" d="M0,0 C0,0 1,1 2190,5130 C2190,5070 2220,5010 2205,4980" />
+ */
+ const SkPoint src[] = {
+ { SkIntToScalar(2190), SkIntToScalar(5130) },
+ { SkIntToScalar(2190), SkIntToScalar(5070) },
+ { SkIntToScalar(2220), SkIntToScalar(5010) },
+ { SkIntToScalar(2205), SkIntToScalar(4980) },
+ };
+ SkPoint dst[13];
+ SkScalar tValues[3];
+ // make sure we don't assert internally
+ int count = SkChopCubicAtMaxCurvature(src, dst, tValues);
+ if (false) { // avoid bit rot, suppress warning
+ REPORTER_ASSERT(reporter, count);
+ }
+}
+
+DEF_TEST(Geometry, reporter) {
+ SkPoint pts[3], dst[5];
+
+ pts[0].set(0, 0);
+ pts[1].set(100, 50);
+ pts[2].set(0, 100);
+
+ int count = SkChopQuadAtMaxCurvature(pts, dst);
+ REPORTER_ASSERT(reporter, count == 1 || count == 2);
+
+ pts[0].set(0, 0);
+ pts[1].set(SkIntToScalar(3), 0);
+ pts[2].set(SkIntToScalar(3), SkIntToScalar(3));
+ SkConvertQuadToCubic(pts, dst);
+ const SkPoint cubic[] = {
+ { 0, 0, },
+ { SkIntToScalar(2), 0, },
+ { SkIntToScalar(3), SkIntToScalar(1), },
+ { SkIntToScalar(3), SkIntToScalar(3) },
+ };
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter, nearly_equal(cubic[i], dst[i]));
+ }
+
+ testChopCubic(reporter);
+}
diff --git a/src/third_party/skia/tests/GifTest.cpp b/src/third_party/skia/tests/GifTest.cpp
new file mode 100644
index 0000000..e2e0384
--- /dev/null
+++ b/src/third_party/skia/tests/GifTest.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// This tests out GIF decoder (SkImageDecoder_libgif.cpp)
+// It is not used on these platforms:
+#if (!defined(SK_BUILD_FOR_WIN32)) && \
+ (!defined(SK_BUILD_FOR_IOS)) && \
+ (!defined(SK_BUILD_FOR_MAC))
+
+#include "SkBitmap.h"
+#include "SkData.h"
+#include "SkForceLinking.h"
+#include "SkImage.h"
+#include "SkImageDecoder.h"
+#include "SkStream.h"
+#include "Test.h"
+
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
+static unsigned char gGIFData[] = {
+ 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x03, 0x00, 0x03, 0x00, 0xe3, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x80, 0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x04,
+ 0x07, 0x50, 0x1c, 0x43, 0x40, 0x41, 0x23, 0x44, 0x00, 0x3b
+};
+
+static unsigned char gGIFDataNoColormap[] = {
+ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x21, 0xf9, 0x04, 0x01, 0x0a, 0x00, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x4c, 0x01, 0x00, 0x3b
+};
+
+static unsigned char gInterlacedGIF[] = {
+ 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x09, 0x00, 0x09, 0x00, 0xe3, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x80,
+ 0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x09, 0x00, 0x40, 0x04, 0x1b, 0x50, 0x1c, 0x23, 0xe9, 0x44,
+ 0x23, 0x60, 0x9d, 0x09, 0x28, 0x1e, 0xf8, 0x6d, 0x64, 0x56, 0x9d, 0x53, 0xa8,
+ 0x7e, 0xa8, 0x65, 0x94, 0x5c, 0xb0, 0x8a, 0x45, 0x04, 0x00, 0x3b
+};
+
+static void test_gif_data_no_colormap(skiatest::Reporter* r,
+ void* data,
+ size_t size) {
+ SkBitmap bm;
+ bool imageDecodeSuccess = SkImageDecoder::DecodeMemory(
+ data, size, &bm);
+ REPORTER_ASSERT(r, imageDecodeSuccess);
+ REPORTER_ASSERT(r, bm.width() == 1);
+ REPORTER_ASSERT(r, bm.height() == 1);
+ REPORTER_ASSERT(r, !(bm.empty()));
+ if (!(bm.empty())) {
+ REPORTER_ASSERT(r, bm.getColor(0, 0) == 0x00000000);
+ }
+}
+static void test_gif_data(skiatest::Reporter* r, void* data, size_t size) {
+ SkBitmap bm;
+ bool imageDecodeSuccess = SkImageDecoder::DecodeMemory(
+ data, size, &bm);
+ REPORTER_ASSERT(r, imageDecodeSuccess);
+ REPORTER_ASSERT(r, bm.width() == 3);
+ REPORTER_ASSERT(r, bm.height() == 3);
+ REPORTER_ASSERT(r, !(bm.empty()));
+ if (!(bm.empty())) {
+ REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
+ REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
+ REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
+ REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080);
+ REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000);
+ REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00);
+ REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff);
+ REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff);
+ REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff);
+ }
+}
+static void test_interlaced_gif_data(skiatest::Reporter* r,
+ void* data,
+ size_t size) {
+ SkBitmap bm;
+ bool imageDecodeSuccess = SkImageDecoder::DecodeMemory(
+ data, size, &bm);
+ REPORTER_ASSERT(r, imageDecodeSuccess);
+ REPORTER_ASSERT(r, bm.width() == 9);
+ REPORTER_ASSERT(r, bm.height() == 9);
+ REPORTER_ASSERT(r, !(bm.empty()));
+ if (!(bm.empty())) {
+ REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
+ REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
+ REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
+
+ REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff);
+ REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff);
+ REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff);
+
+ REPORTER_ASSERT(r, bm.getColor(0, 4) == 0xff808080);
+ REPORTER_ASSERT(r, bm.getColor(1, 4) == 0xff000000);
+ REPORTER_ASSERT(r, bm.getColor(2, 4) == 0xff00ff00);
+
+ REPORTER_ASSERT(r, bm.getColor(0, 6) == 0xffff0000);
+ REPORTER_ASSERT(r, bm.getColor(1, 6) == 0xffffff00);
+ REPORTER_ASSERT(r, bm.getColor(2, 6) == 0xff00ffff);
+
+ REPORTER_ASSERT(r, bm.getColor(0, 8) == 0xffffffff);
+ REPORTER_ASSERT(r, bm.getColor(1, 8) == 0xffff00ff);
+ REPORTER_ASSERT(r, bm.getColor(2, 8) == 0xff0000ff);
+ }
+}
+
+static void test_gif_data_short(skiatest::Reporter* r,
+ void* data,
+ size_t size) {
+ SkBitmap bm;
+ bool imageDecodeSuccess = SkImageDecoder::DecodeMemory(
+ data, size, &bm);
+ REPORTER_ASSERT(r, imageDecodeSuccess);
+ REPORTER_ASSERT(r, bm.width() == 3);
+ REPORTER_ASSERT(r, bm.height() == 3);
+ REPORTER_ASSERT(r, !(bm.empty()));
+ if (!(bm.empty())) {
+ REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
+ REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
+ REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
+ REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080);
+ REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000);
+ REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00);
+ }
+}
+
+/**
+ This test will test the ability of the SkImageDecoder to deal with
+ GIF files which have been mangled somehow. We want to display as
+ much of the GIF as possible.
+*/
+DEF_TEST(Gif, reporter) {
+ // test perfectly good images.
+ test_gif_data(reporter, static_cast<void *>(gGIFData), sizeof(gGIFData));
+ test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF),
+ sizeof(gInterlacedGIF));
+
+ unsigned char badData[sizeof(gGIFData)];
+
+ /* If you set the environment variable
+ skia_images_gif_suppressDecoderWarnings to 'false', you will
+ see warnings on stderr. This is a feature. */
+
+ memcpy(badData, gGIFData, sizeof(gGIFData));
+ badData[6] = 0x01; // image too wide
+ test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
+ // "libgif warning [image too wide, expanding output to size]"
+
+ memcpy(badData, gGIFData, sizeof(gGIFData));
+ badData[8] = 0x01; // image too tall
+ test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
+ // "libgif warning [image too tall, expanding output to size]"
+
+ memcpy(badData, gGIFData, sizeof(gGIFData));
+ badData[62] = 0x01; // image shifted right
+ test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
+ // "libgif warning [shifting image left to fit]"
+
+ memcpy(badData, gGIFData, sizeof(gGIFData));
+ badData[64] = 0x01; // image shifted down
+ test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
+ // "libgif warning [shifting image up to fit]"
+
+ memcpy(badData, gGIFData, sizeof(gGIFData));
+ badData[62] = 0xff; // image shifted left
+ badData[63] = 0xff; // 2's complement -1 short
+ test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
+ // "libgif warning [shifting image left to fit]"
+
+ memcpy(badData, gGIFData, sizeof(gGIFData));
+ badData[64] = 0xff; // image shifted up
+ badData[65] = 0xff; // 2's complement -1 short
+ test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
+ // "libgif warning [shifting image up to fit]"
+
+ test_gif_data_no_colormap(reporter, static_cast<void *>(gGIFDataNoColormap),
+ sizeof(gGIFDataNoColormap));
+ // "libgif warning [missing colormap]"
+
+ // test short Gif. 80 is missing a few bytes.
+ test_gif_data_short(reporter, static_cast<void *>(gGIFData), 80);
+ // "libgif warning [DGifGetLine]"
+
+ test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF),
+ 100); // 100 is missing a few bytes
+ // "libgif warning [interlace DGifGetLine]"
+}
+
+#endif // !(SK_BUILD_FOR_WIN32||SK_BUILD_FOR_IOS||SK_BUILD_FOR_MAC)
diff --git a/src/third_party/skia/tests/GpuColorFilterTest.cpp b/src/third_party/skia/tests/GpuColorFilterTest.cpp
new file mode 100644
index 0000000..202756b
--- /dev/null
+++ b/src/third_party/skia/tests/GpuColorFilterTest.cpp
@@ -0,0 +1,124 @@
+
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#if SK_SUPPORT_GPU
+
+#include "GrContext.h"
+#include "GrContextFactory.h"
+#include "GrProcessor.h"
+#include "SkColorFilter.h"
+#include "SkGr.h"
+#include "Test.h"
+
+static GrColor filterColor(const GrColor& color, uint32_t flags) {
+ uint32_t mask = 0;
+ if (flags & kR_GrColorComponentFlag) {
+ mask = 0xFF << GrColor_SHIFT_R;
+ }
+ if (flags & kG_GrColorComponentFlag) {
+ mask |= 0xFF << GrColor_SHIFT_G;
+ }
+ if (flags & kB_GrColorComponentFlag) {
+ mask |= 0xFF << GrColor_SHIFT_B;
+ }
+ if (flags & kA_GrColorComponentFlag) {
+ mask |= 0xFF << GrColor_SHIFT_A;
+ }
+ return color & mask;
+}
+
+static void test_getConstantColorComponents(skiatest::Reporter* reporter, GrContext* grContext) {
+ struct GetConstantComponentTestCase {
+ // "Shape drawn with"
+ uint32_t inputComponents; // "rgb of", "red of", "alpha of", ...
+ GrColor inputColor; // "[color]"
+
+ SkColor filterColor; // "with filter color [color]"
+ SkXfermode::Mode filterMode; // "in mode [mode]"
+
+ // "produces"
+ uint32_t outputComponents; // "rgb of", "red of", "alpha of", ...
+ GrColor outputColor; // "[color]"
+ };
+
+ // Shorthands.
+ enum {
+ kR = kR_GrColorComponentFlag,
+ kG = kG_GrColorComponentFlag,
+ kB = kB_GrColorComponentFlag,
+ kA = kA_GrColorComponentFlag,
+ kRGB = kRGB_GrColorComponentFlags,
+ kRGBA = kRGBA_GrColorComponentFlags
+ };
+
+ // Note: below, SkColors are non-premultiplied, where as GrColors are premultiplied.
+
+ const SkColor c1 = SkColorSetARGB(200, 200, 200, 200);
+ const SkColor c2 = SkColorSetARGB(60, 60, 60, 60);
+ const GrColor gr_c1 = SkColor2GrColor(c1);
+ const GrColor gr_c2 = SkColor2GrColor(c2);
+
+ const GrColor gr_black = GrColorPackRGBA(0, 0, 0, 0);
+ const GrColor gr_white = GrColorPackRGBA(255, 255, 255, 255);
+ const GrColor gr_whiteTrans = GrColorPackRGBA(128, 128, 128, 128);
+
+ GetConstantComponentTestCase filterTests[] = {
+ // A color filtered with Clear produces black.
+ { kRGBA, gr_white, SK_ColorBLACK, SkXfermode::kClear_Mode, kRGBA, gr_black },
+ { kRGBA, gr_c1, SK_ColorWHITE, SkXfermode::kClear_Mode, kRGBA, gr_black },
+ { kR, gr_white, c1, SkXfermode::kClear_Mode, kRGBA, gr_black },
+
+ // A color filtered with a color in mode Src, produces the filter color.
+ { kRGBA, gr_c2, c1, SkXfermode::kSrc_Mode, kRGBA, gr_c1 },
+ { kA, gr_c1, c1, SkXfermode::kSrc_Mode, kRGBA, gr_c1 },
+
+ // A color filtered with SrcOver produces a color.
+ { kRGBA, gr_whiteTrans, SkColorSetARGB(128, 200, 200, 200), SkXfermode::kSrcOver_Mode, kRGBA, GrColorPackRGBA(164, 164, 164, 192)},
+ // An unknown color with known alpha filtered with SrcOver produces an unknown color with known alpha.
+ { kA , gr_whiteTrans, SkColorSetARGB(128, 200, 200, 200), SkXfermode::kSrcOver_Mode, kA , GrColorPackRGBA(0, 0, 0, 192)},
+ // A color with unknown alpha filtered with SrcOver produces a color with unknown alpha.
+ { kRGB , gr_whiteTrans, SkColorSetARGB(128, 200, 200, 200), SkXfermode::kSrcOver_Mode, kRGB, GrColorPackRGBA(164, 164, 164, 0)},
+
+ // A color filtered with DstOver produces a color.
+ { kRGBA, gr_whiteTrans, SkColorSetARGB(128, 200, 200, 200), SkXfermode::kDstOver_Mode, kRGBA, GrColorPackRGBA(178, 178, 178, 192)},
+ // An unknown color with known alpha filtered with DstOver produces an unknown color with known alpha.
+ { kA , gr_whiteTrans, SkColorSetARGB(128, 200, 200, 200), SkXfermode::kDstOver_Mode, kA , GrColorPackRGBA(0, 0, 0, 192)},
+ // A color with unknown alpha filtered with DstOver produces an unknown color.
+ { kRGB , gr_whiteTrans, SkColorSetARGB(128, 200, 200, 200), SkXfermode::kDstOver_Mode, 0 , gr_black},
+
+ // An unknown color with known alpha and red component filtered with Multiply produces an unknown color with known red and alpha.
+ { kR|kA , gr_whiteTrans, SkColorSetARGB(128, 200, 200, 200), SkXfermode::kModulate_Mode, kR|kA, GrColorPackRGBA(50, 0, 0, 64) }
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(filterTests); ++i) {
+ const GetConstantComponentTestCase& test = filterTests[i];
+ SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(test.filterColor, test.filterMode));
+ SkAutoTUnref<GrFragmentProcessor> effect(cf->asFragmentProcessor(grContext));
+ GrColor color = test.inputColor;
+ uint32_t components = test.inputComponents;
+ effect->getConstantColorComponents(&color, &components);
+
+ REPORTER_ASSERT(reporter, filterColor(color, components) == test.outputColor);
+ REPORTER_ASSERT(reporter, test.outputComponents == components);
+ }
+}
+
+DEF_GPUTEST(GpuColorFilter, reporter, factory) {
+ for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
+ GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type);
+
+ GrContext* grContext = factory->get(glType);
+ if (NULL == grContext) {
+ continue;
+ }
+
+ test_getConstantColorComponents(reporter, grContext);
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GpuDrawPathTest.cpp b/src/third_party/skia/tests/GpuDrawPathTest.cpp
new file mode 100644
index 0000000..3e47a05
--- /dev/null
+++ b/src/third_party/skia/tests/GpuDrawPathTest.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#if SK_SUPPORT_GPU
+
+#include "GrContext.h"
+#include "GrContextFactory.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColor.h"
+#include "SkPaint.h"
+#include "SkRRect.h"
+#include "SkRect.h"
+#include "SkSurface.h"
+#include "Test.h"
+
+static void test_drawPathEmpty(skiatest::Reporter*, SkCanvas* canvas) {
+ // Filling an empty path should not crash.
+ SkPaint paint;
+ canvas->drawRect(SkRect(), paint);
+ canvas->drawPath(SkPath(), paint);
+ canvas->drawOval(SkRect(), paint);
+ canvas->drawRect(SkRect(), paint);
+ canvas->drawRRect(SkRRect(), paint);
+
+ // Stroking an empty path should not crash.
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(SK_ColorGRAY);
+ paint.setStrokeWidth(SkIntToScalar(20));
+ paint.setStrokeJoin(SkPaint::kRound_Join);
+ canvas->drawRect(SkRect(), paint);
+ canvas->drawPath(SkPath(), paint);
+ canvas->drawOval(SkRect(), paint);
+ canvas->drawRect(SkRect(), paint);
+ canvas->drawRRect(SkRRect(), paint);
+}
+
+
+DEF_GPUTEST(GpuDrawPath, reporter, factory) {
+ return;
+
+ for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
+ GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type);
+
+ GrContext* grContext = factory->get(glType);
+ if (NULL == grContext) {
+ continue;
+ }
+ static const int sampleCounts[] = { 0, 4, 16 };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(sampleCounts); ++i) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(255, 255);
+
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(grContext, info,
+ sampleCounts[i], NULL));
+ test_drawPathEmpty(reporter, surface->getCanvas());
+ }
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GpuLayerCacheTest.cpp b/src/third_party/skia/tests/GpuLayerCacheTest.cpp
new file mode 100644
index 0000000..c9b88f5
--- /dev/null
+++ b/src/third_party/skia/tests/GpuLayerCacheTest.cpp
@@ -0,0 +1,214 @@
+/*
+* Copyright 2014 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#if SK_SUPPORT_GPU
+
+#include "GrContext.h"
+#include "GrContextFactory.h"
+#include "GrLayerCache.h"
+#include "SkPictureRecorder.h"
+#include "Test.h"
+
+class TestingAccess {
+public:
+ static int NumLayers(GrLayerCache* cache) {
+ return cache->numLayers();
+ }
+ static void Purge(GrLayerCache* cache, uint32_t pictureID) {
+ cache->purge(pictureID);
+ }
+};
+
+// Add several layers to the cache
+static void create_layers(skiatest::Reporter* reporter,
+ GrLayerCache* cache,
+ const SkPicture& picture,
+ int numToAdd,
+ int idOffset) {
+
+ for (int i = 0; i < numToAdd; ++i) {
+ GrCachedLayer* layer = cache->findLayerOrCreate(picture.uniqueID(),
+ idOffset+i+1, idOffset+i+2,
+ SkIPoint::Make(0, 0),
+ SkMatrix::I(),
+ NULL);
+ REPORTER_ASSERT(reporter, layer);
+ GrCachedLayer* temp = cache->findLayer(picture.uniqueID(), idOffset+i+1, idOffset+i+2,
+ SkIPoint::Make(0, 0), SkMatrix::I());
+ REPORTER_ASSERT(reporter, temp == layer);
+
+ REPORTER_ASSERT(reporter, TestingAccess::NumLayers(cache) == idOffset + i + 1);
+
+ REPORTER_ASSERT(reporter, picture.uniqueID() == layer->pictureID());
+ REPORTER_ASSERT(reporter, layer->start() == idOffset + i + 1);
+ REPORTER_ASSERT(reporter, layer->stop() == idOffset + i + 2);
+ REPORTER_ASSERT(reporter, layer->ctm() == SkMatrix::I());
+ REPORTER_ASSERT(reporter, NULL == layer->texture());
+ REPORTER_ASSERT(reporter, NULL == layer->paint());
+ REPORTER_ASSERT(reporter, !layer->isAtlased());
+ }
+
+ cache->trackPicture(&picture);
+}
+
+static void lock_layer(skiatest::Reporter* reporter,
+ GrLayerCache* cache,
+ GrCachedLayer* layer) {
+ // Make the layer 512x512 (so it can be atlased)
+ GrTextureDesc desc;
+ desc.fWidth = 512;
+ desc.fHeight = 512;
+ desc.fConfig = kSkia8888_GrPixelConfig;
+
+ bool needsRerendering = cache->lock(layer, desc, false);
+ REPORTER_ASSERT(reporter, needsRerendering);
+
+ needsRerendering = cache->lock(layer, desc, false);
+ REPORTER_ASSERT(reporter, !needsRerendering);
+
+ REPORTER_ASSERT(reporter, layer->texture());
+ REPORTER_ASSERT(reporter, layer->locked());
+}
+
+// This test case exercises the public API of the GrLayerCache class.
+// In particular it checks its interaction with the resource cache (w.r.t.
+// locking & unlocking textures).
+// TODO: need to add checks on VRAM usage!
+DEF_GPUTEST(GpuLayerCache, reporter, factory) {
+ static const int kInitialNumLayers = 5;
+
+ for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
+ GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
+
+ if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
+ continue;
+ }
+
+ GrContext* context = factory->get(glCtxType);
+
+ if (NULL == context) {
+ continue;
+ }
+
+ SkPictureRecorder recorder;
+ recorder.beginRecording(1, 1);
+ SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
+
+ GrLayerCache cache(context);
+
+ create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
+
+ for (int i = 0; i < kInitialNumLayers; ++i) {
+ GrCachedLayer* layer = cache.findLayer(picture->uniqueID(), i+1, i+2,
+ SkIPoint::Make(0, 0), SkMatrix::I());
+ REPORTER_ASSERT(reporter, layer);
+
+ lock_layer(reporter, &cache, layer);
+
+ // The first 4 layers should be in the atlas (and thus have non-empty
+ // rects)
+ if (i < 4) {
+ REPORTER_ASSERT(reporter, layer->isAtlased());
+ } else {
+ // The 5th layer couldn't fit in the atlas
+ REPORTER_ASSERT(reporter, !layer->isAtlased());
+ }
+ }
+
+ // Unlock the textures
+ for (int i = 0; i < kInitialNumLayers; ++i) {
+ GrCachedLayer* layer = cache.findLayer(picture->uniqueID(), i+1, i+2,
+ SkIPoint::Make(0, 0), SkMatrix::I());
+ REPORTER_ASSERT(reporter, layer);
+ cache.unlock(layer);
+ }
+
+ for (int i = 0; i < kInitialNumLayers; ++i) {
+ GrCachedLayer* layer = cache.findLayer(picture->uniqueID(), i+1, i+2,
+ SkIPoint::Make(0, 0), SkMatrix::I());
+ REPORTER_ASSERT(reporter, layer);
+
+ REPORTER_ASSERT(reporter, !layer->locked());
+ // The first 4 layers should still be in the atlas.
+ if (i < 4) {
+ REPORTER_ASSERT(reporter, layer->texture());
+ REPORTER_ASSERT(reporter, layer->isAtlased());
+ } else {
+ // The final layer should be unlocked.
+ REPORTER_ASSERT(reporter, NULL == layer->texture());
+ REPORTER_ASSERT(reporter, !layer->isAtlased());
+ }
+ }
+
+ {
+ // Add an additional layer. Since all the layers are unlocked this
+ // will force out the first atlased layer
+ create_layers(reporter, &cache, *picture, 1, kInitialNumLayers);
+ GrCachedLayer* layer = cache.findLayer(picture->uniqueID(),
+ kInitialNumLayers+1, kInitialNumLayers+2,
+ SkIPoint::Make(0, 0), SkMatrix::I());
+ REPORTER_ASSERT(reporter, layer);
+
+ lock_layer(reporter, &cache, layer);
+ cache.unlock(layer);
+ }
+
+ for (int i = 0; i < kInitialNumLayers+1; ++i) {
+ GrCachedLayer* layer = cache.findLayer(picture->uniqueID(), i+1, i+2,
+ SkIPoint::Make(0, 0), SkMatrix::I());
+ // 3 old layers plus the new one should be in the atlas.
+ if (1 == i || 2 == i || 3 == i || 5 == i) {
+ REPORTER_ASSERT(reporter, layer);
+ REPORTER_ASSERT(reporter, !layer->locked());
+ REPORTER_ASSERT(reporter, layer->texture());
+ REPORTER_ASSERT(reporter, layer->isAtlased());
+ } else if (4 == i) {
+ // The one that was never atlased should still be around
+ REPORTER_ASSERT(reporter, layer);
+
+ REPORTER_ASSERT(reporter, NULL == layer->texture());
+ REPORTER_ASSERT(reporter, !layer->isAtlased());
+ } else {
+ // The one bumped out of the atlas (i.e., 0) should be gone
+ REPORTER_ASSERT(reporter, NULL == layer);
+ }
+ }
+
+ //--------------------------------------------------------------------
+ // Free them all SkGpuDevice-style. This will not free up the
+ // atlas' texture but will eliminate all the layers.
+ TestingAccess::Purge(&cache, picture->uniqueID());
+
+ REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
+ // TODO: add VRAM/resource cache check here
+
+ //--------------------------------------------------------------------
+ // Test out the GrContext-style purge. This should remove all the layers
+ // and the atlas.
+ // Re-create the layers
+ create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
+
+ // Free them again GrContext-style. This should free up everything.
+ cache.freeAll();
+
+ REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
+ // TODO: add VRAM/resource cache check here
+
+ //--------------------------------------------------------------------
+ // Test out the MessageBus-style purge. This will not free the atlas
+ // but should eliminate the free-floating layers.
+ create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
+
+ picture.reset(NULL);
+ cache.processDeletedPictures();
+
+ REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
+ // TODO: add VRAM/resource cache check here
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GpuRectanizerTest.cpp b/src/third_party/skia/tests/GpuRectanizerTest.cpp
new file mode 100644
index 0000000..2ee641e
--- /dev/null
+++ b/src/third_party/skia/tests/GpuRectanizerTest.cpp
@@ -0,0 +1,74 @@
+/*
+* Copyright 2014 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#if SK_SUPPORT_GPU
+
+#include "GrRectanizer_pow2.h"
+#include "GrRectanizer_skyline.h"
+#include "SkRandom.h"
+#include "SkSize.h"
+#include "SkTDArray.h"
+#include "Test.h"
+
+static const int kWidth = 1024;
+static const int kHeight = 1024;
+
+// Basic test of a GrRectanizer-derived class' functionality
+static void test_rectanizer_basic(skiatest::Reporter* reporter, GrRectanizer* rectanizer) {
+ REPORTER_ASSERT(reporter, kWidth == rectanizer->width());
+ REPORTER_ASSERT(reporter, kHeight == rectanizer->height());
+
+ SkIPoint16 loc;
+
+ REPORTER_ASSERT(reporter, rectanizer->addRect(50, 50, &loc));
+ REPORTER_ASSERT(reporter, rectanizer->percentFull() > 0.0f);
+ rectanizer->reset();
+ REPORTER_ASSERT(reporter, rectanizer->percentFull() == 0.0f);
+}
+
+static void test_rectanizer_inserts(skiatest::Reporter*,
+ GrRectanizer* rectanizer,
+ const SkTDArray<SkISize>& rects) {
+ int i;
+ for (i = 0; i < rects.count(); ++i) {
+ SkIPoint16 loc;
+ if (!rectanizer->addRect(rects[i].fWidth, rects[i].fHeight, &loc)) {
+ break;
+ }
+ }
+
+ //SkDebugf("\n***%d %f\n", i, rectanizer->percentFull());
+}
+
+static void test_skyline(skiatest::Reporter* reporter, const SkTDArray<SkISize>& rects) {
+ GrRectanizerSkyline skylineRectanizer(kWidth, kHeight);
+
+ test_rectanizer_basic(reporter, &skylineRectanizer);
+ test_rectanizer_inserts(reporter, &skylineRectanizer, rects);
+}
+
+static void test_pow2(skiatest::Reporter* reporter, const SkTDArray<SkISize>& rects) {
+ GrRectanizerPow2 pow2Rectanizer(kWidth, kHeight);
+
+ test_rectanizer_basic(reporter, &pow2Rectanizer);
+ test_rectanizer_inserts(reporter, &pow2Rectanizer, rects);
+}
+
+DEF_GPUTEST(GpuRectanizer, reporter, factory) {
+ SkTDArray<SkISize> rects;
+ SkRandom rand;
+
+ for (int i = 0; i < 50; i++) {
+ rects.push(SkISize::Make(rand.nextRangeU(1, kWidth / 2),
+ rand.nextRangeU(1, kHeight / 2)));
+ }
+
+ test_skyline(reporter, rects);
+ test_pow2(reporter, rects);
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GrAllocatorTest.cpp b/src/third_party/skia/tests/GrAllocatorTest.cpp
new file mode 100644
index 0000000..c02a7ca
--- /dev/null
+++ b/src/third_party/skia/tests/GrAllocatorTest.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+// This is a GPU-backend specific test
+#if SK_SUPPORT_GPU
+#include "GrAllocator.h"
+
+namespace {
+struct C {
+ C() : fID(-1) { ++gInstCnt; }
+ C(int id) : fID(id) { ++gInstCnt; }
+ ~C() { --gInstCnt; }
+ int fID;
+
+ static int gInstCnt;
+};
+
+int C::gInstCnt = 0;
+}
+
+static void check_allocator_helper(GrTAllocator<C>* allocator, int cnt, int popCnt,
+ skiatest::Reporter* reporter);
+
+// Adds cnt items to the allocator, tests the cnts and iterators, pops popCnt items and checks
+// again. Finally it resets the allocator and checks again.
+static void check_allocator(GrTAllocator<C>* allocator, int cnt, int popCnt,
+ skiatest::Reporter* reporter) {
+ SkASSERT(allocator);
+ SkASSERT(allocator->empty());
+ for (int i = 0; i < cnt; ++i) {
+ // Try both variations of push_back().
+ if (i % 1) {
+ allocator->push_back(C(i));
+ } else {
+ allocator->push_back() = C(i);
+ }
+ }
+ check_allocator_helper(allocator, cnt, popCnt, reporter);
+ allocator->reset();
+ check_allocator_helper(allocator, 0, 0, reporter);
+}
+
+// Checks that the allocator has the correct count, etc and that the element IDs are correct.
+// Then pops popCnt items and checks again.
+static void check_allocator_helper(GrTAllocator<C>* allocator, int cnt, int popCnt,
+ skiatest::Reporter* reporter) {
+ REPORTER_ASSERT(reporter, (0 == cnt) == allocator->empty());
+ REPORTER_ASSERT(reporter, cnt == allocator->count());
+ REPORTER_ASSERT(reporter, cnt == C::gInstCnt);
+
+ GrTAllocator<C>::Iter iter(allocator);
+ for (int i = 0; i < cnt; ++i) {
+ REPORTER_ASSERT(reporter, iter.next() && i == iter.get()->fID);
+ }
+ REPORTER_ASSERT(reporter, !iter.next());
+ if (cnt > 0) {
+ REPORTER_ASSERT(reporter, cnt-1 == allocator->back().fID);
+ }
+
+ if (popCnt > 0) {
+ for (int i = 0; i < popCnt; ++i) {
+ allocator->pop_back();
+ }
+ check_allocator_helper(allocator, cnt - popCnt, 0, reporter);
+ }
+}
+
+DEF_TEST(GrAllocator, reporter) {
+
+ // Test combinations of allocators with and without stack storage and with different block
+ // sizes.
+ SkTArray<GrTAllocator<C>*> allocators;
+ GrTAllocator<C> a1(1);
+ allocators.push_back(&a1);
+ GrTAllocator<C> a2(2);
+ allocators.push_back(&a2);
+ GrTAllocator<C> a5(5);
+ allocators.push_back(&a5);
+
+ GrSTAllocator<1, C> sa1;
+ allocators.push_back(&a1);
+ GrSTAllocator<3, C> sa3;
+ allocators.push_back(&sa3);
+ GrSTAllocator<4, C> sa4;
+ allocators.push_back(&sa4);
+
+ for (int i = 0; i < allocators.count(); ++i) {
+ check_allocator(allocators[i], 0, 0, reporter);
+ check_allocator(allocators[i], 1, 1, reporter);
+ check_allocator(allocators[i], 2, 2, reporter);
+ check_allocator(allocators[i], 10, 1, reporter);
+ check_allocator(allocators[i], 10, 5, reporter);
+ check_allocator(allocators[i], 10, 10, reporter);
+ check_allocator(allocators[i], 100, 10, reporter);
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GrBinHashKeyTest.cpp b/src/third_party/skia/tests/GrBinHashKeyTest.cpp
new file mode 100644
index 0000000..605fd9f
--- /dev/null
+++ b/src/third_party/skia/tests/GrBinHashKeyTest.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// This is a GPU-backend specific test
+#if SK_SUPPORT_GPU
+
+#include "GrMurmur3HashKey.h"
+#include "GrBinHashKey.h"
+
+#include "Test.h"
+
+template<typename KeyType> static void TestHash(skiatest::Reporter* reporter) {
+ const char* testStringA_ = "abcdABCD";
+ const char* testStringB_ = "abcdBBCD";
+ const uint32_t* testStringA = reinterpret_cast<const uint32_t*>(testStringA_);
+ const uint32_t* testStringB = reinterpret_cast<const uint32_t*>(testStringB_);
+
+ KeyType keyA;
+ keyA.setKeyData(testStringA);
+ // test copy constructor and comparison
+ KeyType keyA2(keyA);
+ REPORTER_ASSERT(reporter, keyA == keyA2);
+ REPORTER_ASSERT(reporter, keyA.getHash() == keyA2.getHash());
+ // test re-init
+ keyA2.setKeyData(testStringA);
+ REPORTER_ASSERT(reporter, keyA == keyA2);
+ REPORTER_ASSERT(reporter, keyA.getHash() == keyA2.getHash());
+ // test sorting
+ KeyType keyB;
+ keyB.setKeyData(testStringB);
+ REPORTER_ASSERT(reporter, keyA.getHash() != keyB.getHash());
+}
+
+
+DEF_TEST(GrBinHashKey, reporter) {
+ enum {
+ kDataLenUsedForKey = 8
+ };
+
+ TestHash<GrBinHashKey<kDataLenUsedForKey> >(reporter);
+ TestHash<GrMurmur3HashKey<kDataLenUsedForKey> >(reporter);
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GrContextFactoryTest.cpp b/src/third_party/skia/tests/GrContextFactoryTest.cpp
new file mode 100644
index 0000000..1d884ac
--- /dev/null
+++ b/src/third_party/skia/tests/GrContextFactoryTest.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#if SK_SUPPORT_GPU
+
+#include "GrContextFactory.h"
+#include "Test.h"
+
+DEF_GPUTEST(GrContextFactory, reporter, factory) {
+ // Reset in case some other test has been using it first.
+ factory->destroyContexts();
+
+ // Before we ask for a context, we expect the GL context to not be there.
+ REPORTER_ASSERT(reporter,
+ NULL == factory->getGLContext(GrContextFactory::kNull_GLContextType));
+
+ // After we ask for a context, we expect that the GL context to be there.
+ factory->get(GrContextFactory::kNull_GLContextType);
+ REPORTER_ASSERT(reporter,
+ factory->getGLContext(GrContextFactory::kNull_GLContextType) != NULL);
+
+ // If we did not ask for a context with the particular GL context, we would
+ // expect the particular GL context to not be there.
+ REPORTER_ASSERT(reporter,
+ NULL == factory->getGLContext(GrContextFactory::kDebug_GLContextType));
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GrDrawTargetTest.cpp b/src/third_party/skia/tests/GrDrawTargetTest.cpp
new file mode 100644
index 0000000..c032d88
--- /dev/null
+++ b/src/third_party/skia/tests/GrDrawTargetTest.cpp
@@ -0,0 +1,36 @@
+
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#if SK_SUPPORT_GPU
+
+#include "GrContext.h"
+#include "GrContextFactory.h"
+#include "GrDrawTargetCaps.h"
+#include "GrGpu.h"
+#include "Test.h"
+
+static void test_print(skiatest::Reporter*, const GrDrawTargetCaps* caps) {
+ // This used to assert.
+ SkString result = caps->dump();
+ SkASSERT(!result.isEmpty());
+}
+
+DEF_GPUTEST(GrDrawTarget, reporter, factory) {
+ for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
+ GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type);
+
+ GrContext* grContext = factory->get(glType);
+ if (NULL == grContext) {
+ continue;
+ }
+
+ test_print(reporter, grContext->getGpu()->caps());
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GrGLSLPrettyPrintTest.cpp b/src/third_party/skia/tests/GrGLSLPrettyPrintTest.cpp
new file mode 100644
index 0000000..9977488
--- /dev/null
+++ b/src/third_party/skia/tests/GrGLSLPrettyPrintTest.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#if SK_SUPPORT_GPU
+#include "Test.h"
+#include "gl/GrGLSLPrettyPrint.h"
+
+#define ASSERT(x) REPORTER_ASSERT(r, x)
+
+const SkString input1("#this is not a realshader\nvec4 some stuff;outside of a function;"
+ "int i(int b, int c) { { some stuff;} fake block; //comments\n return i;}"
+ "void main()"
+ "{nowin a function;{indenting;{abit more;dreadedfor((;;)(;)((;;);)){doingstuff"
+ ";for(;;;){and more stufff;mixed garbage\n\n\t\t\t\t\n/*using this"
+ " comment\n is"
+ " dangerous\ndo so at your own\n risk*/;\n\n\t\t\t\n"
+ "//a comment\n}}a; little ; love; for ; leading; spaces;} "
+ "an struct = { int a; int b; };"
+ "int[5] arr = int[5](1,2,3,4,5);} some code at the bottom; for(;;) {} }");
+
+const SkString output1(
+ " 1\t#this is not a realshader\n"
+ " 2\tvec4 some stuff;\n"
+ " 3\toutside of a function;\n"
+ " 4\tint i(int b, int c) \n"
+ " 5\t{\n"
+ " 6\t\t{\n"
+ " 7\t\t\tsome stuff;\n"
+ " 8\t\t}\n"
+ " 9\t\tfake block;\n"
+ " 10\t\t//comments\n"
+ " 11\t\treturn i;\n"
+ " 12\t}\n"
+ " 13\tvoid main()\n"
+ " 14\t{\n"
+ " 15\t\tnowin a function;\n"
+ " 16\t\t{\n"
+ " 17\t\t\tindenting;\n"
+ " 18\t\t\t{\n"
+ " 19\t\t\t\tabit more;\n"
+ " 20\t\t\t\tdreadedfor((;;)(;)((;;);))\n"
+ " 21\t\t\t\t{\n"
+ " 22\t\t\t\t\tdoingstuff;\n"
+ " 23\t\t\t\t\tfor(;;;)\n"
+ " 24\t\t\t\t\t{\n"
+ " 25\t\t\t\t\t\tand more stufff;\n"
+ " 26\t\t\t\t\t\tmixed garbage/*using this comment\n"
+ " 27\t\t\t\t\t\t is dangerous\n"
+ " 28\t\t\t\t\t\tdo so at your own\n"
+ " 29\t\t\t\t\t\t risk*/;\n"
+ " 30\t\t\t\t\t\t//a comment\n"
+ " 31\t\t\t\t\t}\n"
+ " 32\t\t\t\t}\n"
+ " 33\t\t\t\ta;\n"
+ " 34\t\t\t\tlittle ;\n"
+ " 35\t\t\t\tlove;\n"
+ " 36\t\t\t\tfor ;\n"
+ " 37\t\t\t\tleading;\n"
+ " 38\t\t\t\tspaces;\n"
+ " 39\t\t\t}\n"
+ " 40\t\t\tan struct = \n"
+ " 41\t\t\t{\n"
+ " 42\t\t\t\tint a;\n"
+ " 43\t\t\t\tint b;\n"
+ " 44\t\t\t}\n"
+ " 45\t\t\t;\n"
+ " 46\t\t\tint[5] arr = int[5](1,2,3,4,5);\n"
+ " 47\t\t}\n"
+ " 48\t\tsome code at the bottom;\n"
+ " 49\t\tfor(;;) \n"
+ " 50\t\t{\n"
+ " 51\t\t}\n"
+ " 52\t}\n"
+ " 53\t");
+
+const SkString input2("{;;{{{{;;;{{{{{{{{{{{###\n##\n#####(((((((((((((unbalanced verything;;;"
+ "}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}"
+ ";;;;;;/////");
+
+DEF_TEST(GrGLSLPrettyPrint, r) {
+ SkString test = GrGLSLPrettyPrint::PrettyPrintGLSL(input1, true);
+ ASSERT(output1 == test);
+
+ // Just test we don't crash with garbage input
+ ASSERT(GrGLSLPrettyPrint::PrettyPrintGLSL(input2, true).c_str() != NULL);
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GrMemoryPoolTest.cpp b/src/third_party/skia/tests/GrMemoryPoolTest.cpp
new file mode 100644
index 0000000..0848d97
--- /dev/null
+++ b/src/third_party/skia/tests/GrMemoryPoolTest.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+// This is a GPU-backend specific test
+#if SK_SUPPORT_GPU
+#include "GrMemoryPool.h"
+#include "SkInstCnt.h"
+#include "SkRandom.h"
+#include "SkTDArray.h"
+#include "SkTemplates.h"
+
+// A is the top of an inheritance tree of classes that overload op new and
+// and delete to use a GrMemoryPool. The objects have values of different types
+// that can be set and checked.
+class A {
+public:
+ A() {};
+ virtual void setValues(int v) {
+ fChar = static_cast<char>(v);
+ }
+ virtual bool checkValues(int v) {
+ return fChar == static_cast<char>(v);
+ }
+ virtual ~A() {};
+
+ void* operator new(size_t size) {
+ if (!gPool.get()) {
+ return ::operator new(size);
+ } else {
+ return gPool->allocate(size);
+ }
+ }
+
+ void operator delete(void* p) {
+ if (!gPool.get()) {
+ ::operator delete(p);
+ } else {
+ return gPool->release(p);
+ }
+ }
+
+ SK_DECLARE_INST_COUNT_ROOT(A);
+
+ static A* Create(SkRandom* r);
+
+ static void SetAllocator(size_t preallocSize, size_t minAllocSize) {
+#if SK_ENABLE_INST_COUNT
+ SkASSERT(0 == GetInstanceCount());
+#endif
+ GrMemoryPool* pool = new GrMemoryPool(preallocSize, minAllocSize);
+ gPool.reset(pool);
+ }
+
+ static void ResetAllocator() {
+#if SK_ENABLE_INST_COUNT
+ SkASSERT(0 == GetInstanceCount());
+#endif
+ gPool.reset(NULL);
+ }
+
+private:
+ static SkAutoTDelete<GrMemoryPool> gPool;
+ char fChar;
+};
+
+SkAutoTDelete<GrMemoryPool> A::gPool;
+
+class B : public A {
+public:
+ B() {};
+ virtual void setValues(int v) {
+ fDouble = static_cast<double>(v);
+ this->INHERITED::setValues(v);
+ }
+ virtual bool checkValues(int v) {
+ return fDouble == static_cast<double>(v) &&
+ this->INHERITED::checkValues(v);
+ }
+ virtual ~B() {};
+
+private:
+ double fDouble;
+
+ typedef A INHERITED;
+};
+
+class C : public A {
+public:
+ C() {};
+ virtual void setValues(int v) {
+ fInt64 = static_cast<int64_t>(v);
+ this->INHERITED::setValues(v);
+ }
+ virtual bool checkValues(int v) {
+ return fInt64 == static_cast<int64_t>(v) &&
+ this->INHERITED::checkValues(v);
+ }
+ virtual ~C() {};
+
+private:
+ int64_t fInt64;
+
+ typedef A INHERITED;
+};
+
+// D derives from C and owns a dynamically created B
+class D : public C {
+public:
+ D() {
+ fB = new B();
+ }
+ virtual void setValues(int v) {
+ fVoidStar = reinterpret_cast<void*>(v);
+ this->INHERITED::setValues(v);
+ fB->setValues(v);
+ }
+ virtual bool checkValues(int v) {
+ return fVoidStar == reinterpret_cast<void*>(v) &&
+ fB->checkValues(v) &&
+ this->INHERITED::checkValues(v);
+ }
+ virtual ~D() {
+ delete fB;
+ }
+private:
+ void* fVoidStar;
+ B* fB;
+
+ typedef C INHERITED;
+};
+
+class E : public A {
+public:
+ E() {}
+ virtual void setValues(int v) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fIntArray); ++i) {
+ fIntArray[i] = v;
+ }
+ this->INHERITED::setValues(v);
+ }
+ virtual bool checkValues(int v) {
+ bool ok = true;
+ for (size_t i = 0; ok && i < SK_ARRAY_COUNT(fIntArray); ++i) {
+ if (fIntArray[i] != v) {
+ ok = false;
+ }
+ }
+ return ok && this->INHERITED::checkValues(v);
+ }
+ virtual ~E() {}
+private:
+ int fIntArray[20];
+
+ typedef A INHERITED;
+};
+
+A* A::Create(SkRandom* r) {
+ switch (r->nextRangeU(0, 4)) {
+ case 0:
+ return new A;
+ case 1:
+ return new B;
+ case 2:
+ return new C;
+ case 3:
+ return new D;
+ case 4:
+ return new E;
+ default:
+ // suppress warning
+ return NULL;
+ }
+}
+
+struct Rec {
+ A* fInstance;
+ int fValue;
+};
+
+DEF_TEST(GrMemoryPool, reporter) {
+ // prealloc and min alloc sizes for the pool
+ static const size_t gSizes[][2] = {
+ {0, 0},
+ {10 * sizeof(A), 20 * sizeof(A)},
+ {100 * sizeof(A), 100 * sizeof(A)},
+ {500 * sizeof(A), 500 * sizeof(A)},
+ {10000 * sizeof(A), 0},
+ {1, 100 * sizeof(A)},
+ };
+ // different percentages of creation vs deletion
+ static const float gCreateFraction[] = {1.f, .95f, 0.75f, .5f};
+ // number of create/destroys per test
+ static const int kNumIters = 20000;
+ // check that all the values stored in A objects are correct after this
+ // number of iterations
+ static const int kCheckPeriod = 500;
+
+ SkRandom r;
+ for (size_t s = 0; s < SK_ARRAY_COUNT(gSizes); ++s) {
+ A::SetAllocator(gSizes[s][0], gSizes[s][1]);
+ for (size_t c = 0; c < SK_ARRAY_COUNT(gCreateFraction); ++c) {
+ SkTDArray<Rec> instanceRecs;
+ for (int i = 0; i < kNumIters; ++i) {
+ float createOrDestroy = r.nextUScalar1();
+ if (createOrDestroy < gCreateFraction[c] ||
+ 0 == instanceRecs.count()) {
+ Rec* rec = instanceRecs.append();
+ rec->fInstance = A::Create(&r);
+ rec->fValue = static_cast<int>(r.nextU());
+ rec->fInstance->setValues(rec->fValue);
+ } else {
+ int d = r.nextRangeU(0, instanceRecs.count() - 1);
+ Rec& rec = instanceRecs[d];
+ REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
+ delete rec.fInstance;
+ instanceRecs.removeShuffle(d);
+ }
+ if (0 == i % kCheckPeriod) {
+ for (int r = 0; r < instanceRecs.count(); ++r) {
+ Rec& rec = instanceRecs[r];
+ REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
+ }
+ }
+ }
+ for (int i = 0; i < instanceRecs.count(); ++i) {
+ Rec& rec = instanceRecs[i];
+ REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
+ delete rec.fInstance;
+ }
+#if SK_ENABLE_INST_COUNT
+ REPORTER_ASSERT(reporter, !A::GetInstanceCount());
+#endif
+ }
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GrOrderedSetTest.cpp b/src/third_party/skia/tests/GrOrderedSetTest.cpp
new file mode 100644
index 0000000..7b3db9d
--- /dev/null
+++ b/src/third_party/skia/tests/GrOrderedSetTest.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRandom.h"
+#include "Test.h"
+// This is a GPU-backend specific test
+#if SK_SUPPORT_GPU
+#include "GrOrderedSet.h"
+
+typedef GrOrderedSet<int> Set;
+typedef GrOrderedSet<const char*, GrStrLess> Set2;
+
+DEF_TEST(GrOrderedSet, reporter) {
+ Set set;
+
+ REPORTER_ASSERT(reporter, set.empty());
+
+ SkRandom r;
+
+ int count[1000] = {0};
+ // add 10K ints
+ for (int i = 0; i < 10000; ++i) {
+ int x = r.nextU() % 1000;
+ Set::Iter xi = set.insert(x);
+ REPORTER_ASSERT(reporter, *xi == x);
+ REPORTER_ASSERT(reporter, !set.empty());
+ count[x] = 1;
+ }
+ set.insert(0);
+ count[0] = 1;
+ set.insert(999);
+ count[999] = 1;
+ int totalCount = 0;
+ for (int i = 0; i < 1000; ++i) {
+ totalCount += count[i];
+ }
+ REPORTER_ASSERT(reporter, *set.begin() == 0);
+ REPORTER_ASSERT(reporter, *set.last() == 999);
+ REPORTER_ASSERT(reporter, --(++set.begin()) == set.begin());
+ REPORTER_ASSERT(reporter, --set.end() == set.last());
+ REPORTER_ASSERT(reporter, set.count() == totalCount);
+
+ int c = 0;
+ // check that we iterate through the correct number of
+ // elements and they are properly sorted.
+ for (Set::Iter a = set.begin(); set.end() != a; ++a) {
+ Set::Iter b = a;
+ ++b;
+ ++c;
+ REPORTER_ASSERT(reporter, b == set.end() || *a <= *b);
+ }
+ REPORTER_ASSERT(reporter, c == set.count());
+
+ // check that the set finds all ints and only ints added to set
+ for (int i = 0; i < 1000; ++i) {
+ bool existsFind = set.find(i) != set.end();
+ bool existsCount = 0 != count[i];
+ REPORTER_ASSERT(reporter, existsFind == existsCount);
+ }
+ // remove all the ints between 100 and 200.
+ for (int i = 100; i < 200; ++i) {
+ set.remove(set.find(i));
+ if (1 == count[i]) {
+ count[i] = 0;
+ --totalCount;
+ }
+ REPORTER_ASSERT(reporter, set.count() == totalCount);
+ REPORTER_ASSERT(reporter, set.find(i) == set.end());
+ }
+ // remove the 0 entry. (tests removing begin())
+ REPORTER_ASSERT(reporter, *set.begin() == 0);
+ REPORTER_ASSERT(reporter, *(--set.end()) == 999);
+ set.remove(set.find(0));
+ count[0] = 0;
+ --totalCount;
+ REPORTER_ASSERT(reporter, set.count() == totalCount);
+ REPORTER_ASSERT(reporter, set.find(0) == set.end());
+ REPORTER_ASSERT(reporter, 0 < *set.begin());
+
+ // remove all the 999 entries (tests removing last()).
+ set.remove(set.find(999));
+ count[999] = 0;
+ --totalCount;
+ REPORTER_ASSERT(reporter, set.count() == totalCount);
+ REPORTER_ASSERT(reporter, set.find(999) == set.end());
+ REPORTER_ASSERT(reporter, 999 > *(--set.end()));
+ REPORTER_ASSERT(reporter, set.last() == --set.end());
+
+ // Make sure iteration still goes through correct number of entries
+ // and is still sorted correctly.
+ c = 0;
+ for (Set::Iter a = set.begin(); set.end() != a; ++a) {
+ Set::Iter b = a;
+ ++b;
+ ++c;
+ REPORTER_ASSERT(reporter, b == set.end() || *a <= *b);
+ }
+ REPORTER_ASSERT(reporter, c == set.count());
+
+ // repeat check that the set finds all ints and only ints added to set
+ for (int i = 0; i < 1000; ++i) {
+ bool existsFind = set.find(i) != set.end();
+ bool existsCount = 0 != count[i];
+ REPORTER_ASSERT(reporter, existsFind == existsCount);
+ }
+
+ // remove all entries
+ while (!set.empty()) {
+ set.remove(set.begin());
+ }
+
+ // test reset on empty set.
+ set.reset();
+ REPORTER_ASSERT(reporter, set.empty());
+
+
+ // test using c strings
+ const char* char1 = "dog";
+ const char* char2 = "cat";
+ const char* char3 = "dog";
+
+ Set2 set2;
+
+ set2.insert("ape");
+ set2.insert(char1);
+ set2.insert(char2);
+ set2.insert(char3);
+ set2.insert("ant");
+ set2.insert("cat");
+
+ REPORTER_ASSERT(reporter, set2.count() == 4);
+ REPORTER_ASSERT(reporter, set2.find("dog") == set2.last());
+ REPORTER_ASSERT(reporter, set2.find("cat") != set2.end());
+ REPORTER_ASSERT(reporter, set2.find("ant") == set2.begin());
+ REPORTER_ASSERT(reporter, set2.find("bug") == set2.end());
+
+ set2.remove(set2.find("ant"));
+ REPORTER_ASSERT(reporter, set2.find("ant") == set2.end());
+ REPORTER_ASSERT(reporter, set2.count() == 3);
+
+ set2.reset();
+ REPORTER_ASSERT(reporter, set2.empty());
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GrRedBlackTreeTest.cpp b/src/third_party/skia/tests/GrRedBlackTreeTest.cpp
new file mode 100644
index 0000000..c517cf2
--- /dev/null
+++ b/src/third_party/skia/tests/GrRedBlackTreeTest.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// This is a GPU-backend specific test
+#if SK_SUPPORT_GPU
+
+#include "GrRedBlackTree.h"
+#include "SkRandom.h"
+#include "Test.h"
+
+typedef GrRedBlackTree<int> Tree;
+
+DEF_TEST(GrRedBlackTree, reporter) {
+ Tree tree;
+
+ SkRandom r;
+
+ int count[100] = {0};
+ // add 10K ints
+ for (int i = 0; i < 10000; ++i) {
+ int x = r.nextU() % 100;
+ Tree::Iter xi = tree.insert(x);
+ REPORTER_ASSERT(reporter, *xi == x);
+ ++count[x];
+ }
+
+ tree.insert(0);
+ ++count[0];
+ tree.insert(99);
+ ++count[99];
+ REPORTER_ASSERT(reporter, *tree.begin() == 0);
+ REPORTER_ASSERT(reporter, *tree.last() == 99);
+ REPORTER_ASSERT(reporter, --(++tree.begin()) == tree.begin());
+ REPORTER_ASSERT(reporter, --tree.end() == tree.last());
+ REPORTER_ASSERT(reporter, tree.count() == 10002);
+
+ int c = 0;
+ // check that we iterate through the correct number of
+ // elements and they are properly sorted.
+ for (Tree::Iter a = tree.begin(); tree.end() != a; ++a) {
+ Tree::Iter b = a;
+ ++b;
+ ++c;
+ REPORTER_ASSERT(reporter, b == tree.end() || *a <= *b);
+ }
+ REPORTER_ASSERT(reporter, c == tree.count());
+
+ // check that the tree reports the correct number of each int
+ // and that we can iterate through them correctly both forward
+ // and backward.
+ for (int i = 0; i < 100; ++i) {
+ int c;
+ c = tree.countOf(i);
+ REPORTER_ASSERT(reporter, c == count[i]);
+ c = 0;
+ Tree::Iter iter = tree.findFirst(i);
+ while (iter != tree.end() && *iter == i) {
+ ++c;
+ ++iter;
+ }
+ REPORTER_ASSERT(reporter, count[i] == c);
+ c = 0;
+ iter = tree.findLast(i);
+ if (iter != tree.end()) {
+ do {
+ if (*iter == i) {
+ ++c;
+ } else {
+ break;
+ }
+ if (iter != tree.begin()) {
+ --iter;
+ } else {
+ break;
+ }
+ } while (true);
+ }
+ REPORTER_ASSERT(reporter, c == count[i]);
+ }
+ // remove all the ints between 25 and 74. Randomly chose to remove
+ // the first, last, or any entry for each.
+ for (int i = 25; i < 75; ++i) {
+ while (0 != tree.countOf(i)) {
+ --count[i];
+ int x = r.nextU() % 3;
+ Tree::Iter iter;
+ switch (x) {
+ case 0:
+ iter = tree.findFirst(i);
+ break;
+ case 1:
+ iter = tree.findLast(i);
+ break;
+ case 2:
+ default:
+ iter = tree.find(i);
+ break;
+ }
+ tree.remove(iter);
+ }
+ REPORTER_ASSERT(reporter, 0 == count[i]);
+ REPORTER_ASSERT(reporter, tree.findFirst(i) == tree.end());
+ REPORTER_ASSERT(reporter, tree.findLast(i) == tree.end());
+ REPORTER_ASSERT(reporter, tree.find(i) == tree.end());
+ }
+ // remove all of the 0 entries. (tests removing begin())
+ REPORTER_ASSERT(reporter, *tree.begin() == 0);
+ REPORTER_ASSERT(reporter, *(--tree.end()) == 99);
+ while (0 != tree.countOf(0)) {
+ --count[0];
+ tree.remove(tree.find(0));
+ }
+ REPORTER_ASSERT(reporter, 0 == count[0]);
+ REPORTER_ASSERT(reporter, tree.findFirst(0) == tree.end());
+ REPORTER_ASSERT(reporter, tree.findLast(0) == tree.end());
+ REPORTER_ASSERT(reporter, tree.find(0) == tree.end());
+ REPORTER_ASSERT(reporter, 0 < *tree.begin());
+
+ // remove all the 99 entries (tests removing last()).
+ while (0 != tree.countOf(99)) {
+ --count[99];
+ tree.remove(tree.find(99));
+ }
+ REPORTER_ASSERT(reporter, 0 == count[99]);
+ REPORTER_ASSERT(reporter, tree.findFirst(99) == tree.end());
+ REPORTER_ASSERT(reporter, tree.findLast(99) == tree.end());
+ REPORTER_ASSERT(reporter, tree.find(99) == tree.end());
+ REPORTER_ASSERT(reporter, 99 > *(--tree.end()));
+ REPORTER_ASSERT(reporter, tree.last() == --tree.end());
+
+ // Make sure iteration still goes through correct number of entries
+ // and is still sorted correctly.
+ c = 0;
+ for (Tree::Iter a = tree.begin(); tree.end() != a; ++a) {
+ Tree::Iter b = a;
+ ++b;
+ ++c;
+ REPORTER_ASSERT(reporter, b == tree.end() || *a <= *b);
+ }
+ REPORTER_ASSERT(reporter, c == tree.count());
+
+ // repeat check that correct number of each entry is in the tree
+ // and iterates correctly both forward and backward.
+ for (int i = 0; i < 100; ++i) {
+ REPORTER_ASSERT(reporter, tree.countOf(i) == count[i]);
+ int c = 0;
+ Tree::Iter iter = tree.findFirst(i);
+ while (iter != tree.end() && *iter == i) {
+ ++c;
+ ++iter;
+ }
+ REPORTER_ASSERT(reporter, count[i] == c);
+ c = 0;
+ iter = tree.findLast(i);
+ if (iter != tree.end()) {
+ do {
+ if (*iter == i) {
+ ++c;
+ } else {
+ break;
+ }
+ if (iter != tree.begin()) {
+ --iter;
+ } else {
+ break;
+ }
+ } while (true);
+ }
+ REPORTER_ASSERT(reporter, count[i] == c);
+ }
+
+ // remove all entries
+ while (!tree.empty()) {
+ tree.remove(tree.begin());
+ }
+
+ // test reset on empty tree.
+ tree.reset();
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GrSurfaceTest.cpp b/src/third_party/skia/tests/GrSurfaceTest.cpp
new file mode 100644
index 0000000..a2ed629
--- /dev/null
+++ b/src/third_party/skia/tests/GrSurfaceTest.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#if SK_SUPPORT_GPU
+
+#include "GrContext.h"
+#include "GrContextFactory.h"
+#include "GrRenderTarget.h"
+#include "GrTexture.h"
+#include "SkTypes.h"
+#include "Test.h"
+
+DEF_GPUTEST(GrSurface, reporter, factory) {
+ GrContext* context = factory->get(GrContextFactory::kNull_GLContextType);
+ if (context) {
+ GrTextureDesc desc;
+ desc.fConfig = kSkia8888_GrPixelConfig;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ desc.fWidth = 256;
+ desc.fHeight = 256;
+ desc.fSampleCnt = 0;
+ GrSurface* texRT1 = context->createUncachedTexture(desc, NULL, 0);
+ GrSurface* texRT2 = context->createUncachedTexture(desc, NULL, 0);
+ desc.fFlags = kNone_GrTextureFlags;
+ GrSurface* tex1 = context->createUncachedTexture(desc, NULL, 0);
+
+ REPORTER_ASSERT(reporter, texRT1->isSameAs(texRT1));
+ REPORTER_ASSERT(reporter, texRT1->isSameAs(texRT1->asRenderTarget()));
+ REPORTER_ASSERT(reporter, texRT1->asRenderTarget()->isSameAs(texRT1));
+ REPORTER_ASSERT(reporter, !texRT2->isSameAs(texRT1));
+ REPORTER_ASSERT(reporter, !texRT2->asRenderTarget()->isSameAs(texRT1));
+ REPORTER_ASSERT(reporter, !texRT2->isSameAs(texRT1->asRenderTarget()));
+ REPORTER_ASSERT(reporter, !texRT2->isSameAs(tex1));
+ REPORTER_ASSERT(reporter, !texRT2->asRenderTarget()->isSameAs(tex1));
+
+ GrBackendTextureDesc backendDesc;
+ backendDesc.fConfig = kSkia8888_GrPixelConfig;
+ backendDesc.fFlags = kRenderTarget_GrBackendTextureFlag;
+ backendDesc.fWidth = 256;
+ backendDesc.fHeight = 256;
+ backendDesc.fSampleCnt = 0;
+ backendDesc.fTextureHandle = 5;
+ GrSurface* externalTexRT = context->wrapBackendTexture(backendDesc);
+ REPORTER_ASSERT(reporter, externalTexRT->isSameAs(externalTexRT));
+ REPORTER_ASSERT(reporter, externalTexRT->isSameAs(externalTexRT->asRenderTarget()));
+ REPORTER_ASSERT(reporter, externalTexRT->asRenderTarget()->isSameAs(externalTexRT));
+ REPORTER_ASSERT(reporter, !externalTexRT->isSameAs(texRT1));
+ REPORTER_ASSERT(reporter, !externalTexRT->asRenderTarget()->isSameAs(texRT1));
+
+ texRT1->unref();
+ texRT2->unref();
+ tex1->unref();
+ externalTexRT->unref();
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GrTBSearchTest.cpp b/src/third_party/skia/tests/GrTBSearchTest.cpp
new file mode 100644
index 0000000..d057807
--- /dev/null
+++ b/src/third_party/skia/tests/GrTBSearchTest.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// This is a GPU-backend specific test
+#if SK_SUPPORT_GPU
+
+#include "Test.h"
+
+// If we aren't inheriting these as #defines from elsewhere,
+// clang demands they be declared before we #include the template
+// that relies on them.
+static bool LT(const int& elem, int value) {
+ return elem < value;
+}
+static bool EQ(const int& elem, int value) {
+ return elem == value;
+}
+
+#include "GrTBSearch.h"
+
+DEF_TEST(GrTBSearch, reporter) {
+ const int array[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99
+ };
+
+ for (int n = 0; n < static_cast<int>(SK_ARRAY_COUNT(array)); ++n) {
+ for (int i = 0; i < n; i++) {
+ int index = GrTBSearch<int, int>(array, n, array[i]);
+ REPORTER_ASSERT(reporter, index == (int) i);
+ index = GrTBSearch<int, int>(array, n, -array[i]);
+ REPORTER_ASSERT(reporter, index < 0);
+ }
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/GradientTest.cpp b/src/third_party/skia/tests/GradientTest.cpp
new file mode 100644
index 0000000..e6fd7b9
--- /dev/null
+++ b/src/third_party/skia/tests/GradientTest.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkColorShader.h"
+#include "SkGradientShader.h"
+#include "SkShader.h"
+#include "SkTemplates.h"
+#include "Test.h"
+
+struct GradRec {
+ int fColorCount;
+ const SkColor* fColors;
+ const SkScalar* fPos;
+ const SkPoint* fPoint; // 2
+ const SkScalar* fRadius; // 2
+ SkShader::TileMode fTileMode;
+
+ void gradCheck(skiatest::Reporter* reporter, SkShader* shader,
+ SkShader::GradientInfo* info,
+ SkShader::GradientType gt) const {
+ SkAutoTMalloc<SkColor> colorStorage(fColorCount);
+ SkAutoTMalloc<SkScalar> posStorage(fColorCount);
+
+ info->fColorCount = fColorCount;
+ info->fColors = colorStorage;
+ info->fColorOffsets = posStorage.get();
+ REPORTER_ASSERT(reporter, shader->asAGradient(info) == gt);
+
+ REPORTER_ASSERT(reporter, info->fColorCount == fColorCount);
+ REPORTER_ASSERT(reporter,
+ !memcmp(info->fColors, fColors, fColorCount * sizeof(SkColor)));
+ REPORTER_ASSERT(reporter,
+ !memcmp(info->fColorOffsets, fPos, fColorCount * sizeof(SkScalar)));
+ REPORTER_ASSERT(reporter, fTileMode == info->fTileMode);
+ }
+};
+
+
+static void none_gradproc(skiatest::Reporter* reporter, const GradRec&) {
+ SkAutoTUnref<SkShader> s(SkShader::CreateEmptyShader());
+ REPORTER_ASSERT(reporter, SkShader::kNone_GradientType == s->asAGradient(NULL));
+}
+
+static void color_gradproc(skiatest::Reporter* reporter, const GradRec& rec) {
+ SkAutoTUnref<SkShader> s(new SkColorShader(rec.fColors[0]));
+ REPORTER_ASSERT(reporter, SkShader::kColor_GradientType == s->asAGradient(NULL));
+
+ SkShader::GradientInfo info;
+ info.fColors = NULL;
+ info.fColorCount = 0;
+ s->asAGradient(&info);
+ REPORTER_ASSERT(reporter, 1 == info.fColorCount);
+}
+
+static void linear_gradproc(skiatest::Reporter* reporter, const GradRec& rec) {
+ SkAutoTUnref<SkShader> s(SkGradientShader::CreateLinear(rec.fPoint,
+ rec.fColors,
+ rec.fPos,
+ rec.fColorCount,
+ rec.fTileMode));
+
+ SkShader::GradientInfo info;
+ rec.gradCheck(reporter, s, &info, SkShader::kLinear_GradientType);
+ REPORTER_ASSERT(reporter, !memcmp(info.fPoint, rec.fPoint, 2 * sizeof(SkPoint)));
+}
+
+static void radial_gradproc(skiatest::Reporter* reporter, const GradRec& rec) {
+ SkAutoTUnref<SkShader> s(SkGradientShader::CreateRadial(rec.fPoint[0],
+ rec.fRadius[0],
+ rec.fColors,
+ rec.fPos,
+ rec.fColorCount,
+ rec.fTileMode));
+
+ SkShader::GradientInfo info;
+ rec.gradCheck(reporter, s, &info, SkShader::kRadial_GradientType);
+ REPORTER_ASSERT(reporter, info.fPoint[0] == rec.fPoint[0]);
+ REPORTER_ASSERT(reporter, info.fRadius[0] == rec.fRadius[0]);
+}
+
+static void radial2_gradproc(skiatest::Reporter* reporter, const GradRec& rec) {
+ SkAutoTUnref<SkShader> s(SkGradientShader::CreateTwoPointRadial(rec.fPoint[0],
+ rec.fRadius[0],
+ rec.fPoint[1],
+ rec.fRadius[1],
+ rec.fColors,
+ rec.fPos,
+ rec.fColorCount,
+ rec.fTileMode));
+
+ SkShader::GradientInfo info;
+ rec.gradCheck(reporter, s, &info, SkShader::kRadial2_GradientType);
+ REPORTER_ASSERT(reporter, !memcmp(info.fPoint, rec.fPoint, 2 * sizeof(SkPoint)));
+ REPORTER_ASSERT(reporter, !memcmp(info.fRadius, rec.fRadius, 2 * sizeof(SkScalar)));
+}
+
+static void sweep_gradproc(skiatest::Reporter* reporter, const GradRec& rec) {
+ SkAutoTUnref<SkShader> s(SkGradientShader::CreateSweep(rec.fPoint[0].fX,
+ rec.fPoint[0].fY,
+ rec.fColors,
+ rec.fPos,
+ rec.fColorCount));
+
+ SkShader::GradientInfo info;
+ rec.gradCheck(reporter, s, &info, SkShader::kSweep_GradientType);
+ REPORTER_ASSERT(reporter, info.fPoint[0] == rec.fPoint[0]);
+}
+
+static void conical_gradproc(skiatest::Reporter* reporter, const GradRec& rec) {
+ SkAutoTUnref<SkShader> s(SkGradientShader::CreateTwoPointConical(rec.fPoint[0],
+ rec.fRadius[0],
+ rec.fPoint[1],
+ rec.fRadius[1],
+ rec.fColors,
+ rec.fPos,
+ rec.fColorCount,
+ rec.fTileMode));
+
+ SkShader::GradientInfo info;
+ rec.gradCheck(reporter, s, &info, SkShader::kConical_GradientType);
+ REPORTER_ASSERT(reporter, !memcmp(info.fPoint, rec.fPoint, 2 * sizeof(SkPoint)));
+ REPORTER_ASSERT(reporter, !memcmp(info.fRadius, rec.fRadius, 2 * sizeof(SkScalar)));
+}
+
+// Ensure that repeated color gradients behave like drawing a single color
+static void TestConstantGradient(skiatest::Reporter*) {
+ const SkPoint pts[] = {
+ { 0, 0 },
+ { SkIntToScalar(10), 0 }
+ };
+ SkColor colors[] = { SK_ColorBLUE, SK_ColorBLUE };
+ const SkScalar pos[] = { 0, SK_Scalar1 };
+ SkAutoTUnref<SkShader> s(SkGradientShader::CreateLinear(pts,
+ colors,
+ pos,
+ 2,
+ SkShader::kClamp_TileMode));
+ SkBitmap outBitmap;
+ outBitmap.allocN32Pixels(10, 1);
+ SkPaint paint;
+ paint.setShader(s.get());
+ SkCanvas canvas(outBitmap);
+ canvas.drawPaint(paint);
+ SkAutoLockPixels alp(outBitmap);
+ for (int i = 0; i < 10; i++) {
+ // The following is commented out because it currently fails
+ // Related bug: https://code.google.com/p/skia/issues/detail?id=1098
+
+ // REPORTER_ASSERT(reporter, SK_ColorBLUE == outBitmap.getColor(i, 0));
+ }
+}
+
+typedef void (*GradProc)(skiatest::Reporter* reporter, const GradRec&);
+
+static void TestGradientShaders(skiatest::Reporter* reporter) {
+ static const SkColor gColors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
+ static const SkScalar gPos[] = { 0, SK_ScalarHalf, SK_Scalar1 };
+ static const SkPoint gPts[] = {
+ { 0, 0 },
+ { SkIntToScalar(10), SkIntToScalar(20) }
+ };
+ static const SkScalar gRad[] = { SkIntToScalar(1), SkIntToScalar(2) };
+
+ GradRec rec;
+ rec.fColorCount = SK_ARRAY_COUNT(gColors);
+ rec.fColors = gColors;
+ rec.fPos = gPos;
+ rec.fPoint = gPts;
+ rec.fRadius = gRad;
+ rec.fTileMode = SkShader::kClamp_TileMode;
+
+ static const GradProc gProcs[] = {
+ none_gradproc,
+ color_gradproc,
+ linear_gradproc,
+ radial_gradproc,
+ radial2_gradproc,
+ sweep_gradproc,
+ conical_gradproc,
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gProcs); ++i) {
+ gProcs[i](reporter, rec);
+ }
+}
+
+DEF_TEST(Gradient, reporter) {
+ TestGradientShaders(reporter);
+ TestConstantGradient(reporter);
+}
diff --git a/src/third_party/skia/tests/ImageCacheTest.cpp b/src/third_party/skia/tests/ImageCacheTest.cpp
new file mode 100644
index 0000000..9f893bb
--- /dev/null
+++ b/src/third_party/skia/tests/ImageCacheTest.cpp
@@ -0,0 +1,116 @@
+ /*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkDiscardableMemory.h"
+#include "SkResourceCache.h"
+#include "Test.h"
+
+namespace {
+static void* gGlobalAddress;
+struct TestingKey : public SkResourceCache::Key {
+ void* fPtr;
+ intptr_t fValue;
+
+ TestingKey(intptr_t value) : fPtr(&gGlobalAddress), fValue(value) {
+ this->init(sizeof(fPtr) + sizeof(fValue));
+ }
+};
+struct TestingRec : public SkResourceCache::Rec {
+ TestingRec(const TestingKey& key, uint32_t value) : fKey(key), fValue(value) {}
+
+ TestingKey fKey;
+ intptr_t fValue;
+
+ virtual const Key& getKey() const SK_OVERRIDE { return fKey; }
+ virtual size_t bytesUsed() const SK_OVERRIDE { return sizeof(fKey) + sizeof(fValue); }
+
+ static bool Visitor(const SkResourceCache::Rec& baseRec, void* context) {
+ const TestingRec& rec = static_cast<const TestingRec&>(baseRec);
+ intptr_t* result = (intptr_t*)context;
+
+ *result = rec.fValue;
+ return true;
+ }
+};
+}
+
+static const int COUNT = 10;
+static const int DIM = 256;
+
+static void test_cache(skiatest::Reporter* reporter, SkResourceCache& cache, bool testPurge) {
+ for (int i = 0; i < COUNT; ++i) {
+ TestingKey key(i);
+ intptr_t value = -1;
+
+ REPORTER_ASSERT(reporter, !cache.find(key, TestingRec::Visitor, &value));
+ REPORTER_ASSERT(reporter, -1 == value);
+
+ cache.add(SkNEW_ARGS(TestingRec, (key, i)));
+
+ REPORTER_ASSERT(reporter, cache.find(key, TestingRec::Visitor, &value));
+ REPORTER_ASSERT(reporter, i == value);
+ }
+
+ if (testPurge) {
+ // stress test, should trigger purges
+ for (size_t i = 0; i < COUNT * 100; ++i) {
+ TestingKey key(i);
+ cache.add(SkNEW_ARGS(TestingRec, (key, i)));
+ }
+ }
+
+ // test the originals after all that purging
+ for (int i = 0; i < COUNT; ++i) {
+ intptr_t value;
+ (void)cache.find(TestingKey(i), TestingRec::Visitor, &value);
+ }
+
+ cache.setTotalByteLimit(0);
+}
+
+#include "SkDiscardableMemoryPool.h"
+
+static SkDiscardableMemoryPool* gPool;
+static SkDiscardableMemory* pool_factory(size_t bytes) {
+ SkASSERT(gPool);
+ return gPool->create(bytes);
+}
+
+DEF_TEST(ImageCache, reporter) {
+ static const size_t defLimit = DIM * DIM * 4 * COUNT + 1024; // 1K slop
+
+ {
+ SkResourceCache cache(defLimit);
+ test_cache(reporter, cache, true);
+ }
+ {
+ SkAutoTUnref<SkDiscardableMemoryPool> pool(
+ SkDiscardableMemoryPool::Create(defLimit, NULL));
+ gPool = pool.get();
+ SkResourceCache cache(pool_factory);
+ test_cache(reporter, cache, true);
+ }
+ {
+ SkResourceCache cache(SkDiscardableMemory::Create);
+ test_cache(reporter, cache, false);
+ }
+}
+
+DEF_TEST(ImageCache_doubleAdd, r) {
+ // Adding the same key twice should be safe.
+ SkResourceCache cache(4096);
+
+ TestingKey key(1);
+
+ cache.add(SkNEW_ARGS(TestingRec, (key, 2)));
+ cache.add(SkNEW_ARGS(TestingRec, (key, 3)));
+
+ // Lookup can return either value.
+ intptr_t value = -1;
+ REPORTER_ASSERT(r, cache.find(key, TestingRec::Visitor, &value));
+ REPORTER_ASSERT(r, 2 == value || 3 == value);
+}
diff --git a/src/third_party/skia/tests/ImageDecodingTest.cpp b/src/third_party/skia/tests/ImageDecodingTest.cpp
new file mode 100644
index 0000000..30665a6
--- /dev/null
+++ b/src/third_party/skia/tests/ImageDecodingTest.cpp
@@ -0,0 +1,819 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Resources.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColor.h"
+#include "SkColorPriv.h"
+#include "SkData.h"
+#include "SkDecodingImageGenerator.h"
+#include "SkDiscardableMemoryPool.h"
+#include "SkForceLinking.h"
+#include "SkGradientShader.h"
+#include "SkImageDecoder.h"
+#include "SkImageEncoder.h"
+#include "SkImageGeneratorPriv.h"
+#include "SkImagePriv.h"
+#include "SkOSFile.h"
+#include "SkPoint.h"
+#include "SkShader.h"
+#include "SkStream.h"
+#include "SkString.h"
+#include "Test.h"
+
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
+/**
+ * Interprets c as an unpremultiplied color, and returns the
+ * premultiplied equivalent.
+ */
+static SkPMColor premultiply_unpmcolor(SkPMColor c) {
+ U8CPU a = SkGetPackedA32(c);
+ U8CPU r = SkGetPackedR32(c);
+ U8CPU g = SkGetPackedG32(c);
+ U8CPU b = SkGetPackedB32(c);
+ return SkPreMultiplyARGB(a, r, g, b);
+}
+
+/**
+ * Return true if this stream format should be skipped, due
+ * to do being an opaque format or not a valid format.
+ */
+static bool skip_image_format(SkImageDecoder::Format format) {
+ switch (format) {
+ case SkImageDecoder::kPNG_Format:
+ case SkImageDecoder::kWEBP_Format:
+ return false;
+ // Skip unknown since it will not be decoded anyway.
+ case SkImageDecoder::kUnknown_Format:
+ // Technically ICO and BMP supports alpha channels, but our image
+ // decoders do not, so skip them as well.
+ case SkImageDecoder::kICO_Format:
+ case SkImageDecoder::kBMP_Format:
+ // KTX and ASTC are texture formats so it's not particularly clear how to
+ // decode the alpha from them.
+ case SkImageDecoder::kKTX_Format:
+ case SkImageDecoder::kASTC_Format:
+ // The rest of these are opaque.
+ case SkImageDecoder::kPKM_Format:
+ case SkImageDecoder::kWBMP_Format:
+ case SkImageDecoder::kGIF_Format:
+ case SkImageDecoder::kJPEG_Format:
+ return true;
+ }
+ SkASSERT(false);
+ return true;
+}
+
+/**
+ * Test decoding an image in premultiplied mode and unpremultiplied mode and compare
+ * them.
+ */
+static void compare_unpremul(skiatest::Reporter* reporter, const SkString& filename) {
+ // Decode a resource:
+ SkBitmap bm8888;
+ SkBitmap bm8888Unpremul;
+
+ SkFILEStream stream(filename.c_str());
+
+ SkImageDecoder::Format format = SkImageDecoder::GetStreamFormat(&stream);
+ if (skip_image_format(format)) {
+ return;
+ }
+
+ SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
+ if (NULL == decoder.get()) {
+ SkDebugf("couldn't decode %s\n", filename.c_str());
+ return;
+ }
+
+ bool success = decoder->decode(&stream, &bm8888, kN32_SkColorType,
+ SkImageDecoder::kDecodePixels_Mode);
+ if (!success) {
+ return;
+ }
+
+ success = stream.rewind();
+ REPORTER_ASSERT(reporter, success);
+ if (!success) {
+ return;
+ }
+
+ decoder->setRequireUnpremultipliedColors(true);
+ success = decoder->decode(&stream, &bm8888Unpremul, kN32_SkColorType,
+ SkImageDecoder::kDecodePixels_Mode);
+ if (!success) {
+ return;
+ }
+
+ bool dimensionsMatch = bm8888.width() == bm8888Unpremul.width()
+ && bm8888.height() == bm8888Unpremul.height();
+ REPORTER_ASSERT(reporter, dimensionsMatch);
+ if (!dimensionsMatch) {
+ return;
+ }
+
+ // Only do the comparison if the two bitmaps are both 8888.
+ if (bm8888.colorType() != kN32_SkColorType || bm8888Unpremul.colorType() != kN32_SkColorType) {
+ return;
+ }
+
+ // Now compare the two bitmaps.
+ for (int i = 0; i < bm8888.width(); ++i) {
+ for (int j = 0; j < bm8888.height(); ++j) {
+ // "c0" is the color of the premultiplied bitmap at (i, j).
+ const SkPMColor c0 = *bm8888.getAddr32(i, j);
+ // "c1" is the result of premultiplying the color of the unpremultiplied
+ // bitmap at (i, j).
+ const SkPMColor c1 = premultiply_unpmcolor(*bm8888Unpremul.getAddr32(i, j));
+ // Compute the difference for each component.
+ int da = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1));
+ int dr = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1));
+ int dg = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1));
+ int db = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1));
+
+ // Alpha component must be exactly the same.
+ REPORTER_ASSERT(reporter, 0 == da);
+
+ // Color components may not match exactly due to rounding error.
+ REPORTER_ASSERT(reporter, dr <= 1);
+ REPORTER_ASSERT(reporter, dg <= 1);
+ REPORTER_ASSERT(reporter, db <= 1);
+ }
+ }
+}
+
+static void test_unpremul(skiatest::Reporter* reporter) {
+ // This test cannot run if there is no resource path.
+ SkString resourcePath = GetResourcePath();
+ if (resourcePath.isEmpty()) {
+ SkDebugf("Could not run unpremul test because resourcePath not specified.");
+ return;
+ }
+ SkOSFile::Iter iter(resourcePath.c_str());
+ SkString basename;
+ if (iter.next(&basename)) {
+ do {
+ SkString filename = SkOSPath::Join(resourcePath.c_str(), basename.c_str());
+ // SkDebugf("about to decode \"%s\"\n", filename.c_str());
+ compare_unpremul(reporter, filename);
+ } while (iter.next(&basename));
+ } else {
+ SkDebugf("Failed to find any files :(\n");
+ }
+}
+
+#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
+// Test that the alpha type is what we expect.
+static void test_alphaType(skiatest::Reporter* reporter, const SkString& filename,
+ bool requireUnpremul) {
+ SkBitmap bm;
+ SkFILEStream stream(filename.c_str());
+
+ SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
+ if (NULL == decoder.get()) {
+ return;
+ }
+
+ decoder->setRequireUnpremultipliedColors(requireUnpremul);
+
+ // Decode just the bounds. This should always succeed.
+ bool success = decoder->decode(&stream, &bm, kN32_SkColorType,
+ SkImageDecoder::kDecodeBounds_Mode);
+ REPORTER_ASSERT(reporter, success);
+ if (!success) {
+ return;
+ }
+
+ // Keep track of the alpha type for testing later. If the full decode
+ // succeeds, the alpha type should be the same, unless the full decode
+ // determined that the alpha type should actually be opaque, which may
+ // not be known when only decoding the bounds.
+ const SkAlphaType boundsAlphaType = bm.alphaType();
+
+ // rewind should always succeed on SkFILEStream.
+ success = stream.rewind();
+ REPORTER_ASSERT(reporter, success);
+ if (!success) {
+ return;
+ }
+
+ success = decoder->decode(&stream, &bm, kN32_SkColorType, SkImageDecoder::kDecodePixels_Mode);
+
+ if (!success) {
+ // When the decoder is set to require unpremul, if it does not support
+ // unpremul it will fail. This is the only reason the decode should
+ // fail (since we know the files we are using to test can be decoded).
+ REPORTER_ASSERT(reporter, requireUnpremul);
+ return;
+ }
+
+ // The bounds decode should return with either the requested
+ // premul/unpremul or opaque, if that value could be determined when only
+ // decoding the bounds.
+ if (requireUnpremul) {
+ REPORTER_ASSERT(reporter, kUnpremul_SkAlphaType == boundsAlphaType
+ || kOpaque_SkAlphaType == boundsAlphaType);
+ } else {
+ REPORTER_ASSERT(reporter, kPremul_SkAlphaType == boundsAlphaType
+ || kOpaque_SkAlphaType == boundsAlphaType);
+ }
+
+ // When decoding the full image, the alpha type should match the one
+ // returned by the bounds decode, unless the full decode determined that
+ // the alpha type is actually opaque.
+ REPORTER_ASSERT(reporter, bm.alphaType() == boundsAlphaType
+ || bm.alphaType() == kOpaque_SkAlphaType);
+}
+
+DEF_TEST(ImageDecoding_alphaType, reporter) {
+ SkString resourcePath = GetResourcePath();
+ if (resourcePath.isEmpty()) {
+ SkDebugf("Could not run alphaType test because resourcePath not specified.");
+ return;
+ }
+
+ SkOSFile::Iter iter(resourcePath.c_str());
+ SkString basename;
+ if (iter.next(&basename)) {
+ do {
+ SkString filename = SkOSPath::Join(resourcePath.c_str(), basename.c_str());
+ for (int truth = 0; truth <= 1; ++truth) {
+ test_alphaType(reporter, filename, SkToBool(truth));
+ }
+ } while (iter.next(&basename));
+ } else {
+ SkDebugf("Failed to find any files :(\n");
+ }
+
+}
+
+// Using known images, test that decoding into unpremul and premul behave as expected.
+DEF_TEST(ImageDecoding_unpremul, reporter) {
+ SkString resourcePath = GetResourcePath();
+ if (resourcePath.isEmpty()) {
+ SkDebugf("Could not run unpremul test because resourcePath not specified.");
+ return;
+ }
+ const char* root = "half-transparent-white-pixel";
+ const char* suffixes[] = { ".png", ".webp" };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(suffixes); ++i) {
+ SkString basename = SkStringPrintf("%s%s", root, suffixes[i]);
+ SkString fullName = SkOSPath::Join(resourcePath.c_str(), basename.c_str());
+
+ SkBitmap bm;
+ SkFILEStream stream(fullName.c_str());
+
+ if (!stream.isValid()) {
+ SkDebugf("file %s missing from resource directoy %s\n",
+ basename.c_str(), resourcePath.c_str());
+ continue;
+ }
+
+ // This should never fail since we know the images we're decoding.
+ SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
+ REPORTER_ASSERT(reporter, decoder.get());
+ if (NULL == decoder.get()) {
+ continue;
+ }
+
+ // Test unpremultiplied. We know what color this should result in.
+ decoder->setRequireUnpremultipliedColors(true);
+ bool success = decoder->decode(&stream, &bm, kN32_SkColorType,
+ SkImageDecoder::kDecodePixels_Mode);
+ REPORTER_ASSERT(reporter, success);
+ if (!success) {
+ continue;
+ }
+
+ REPORTER_ASSERT(reporter, bm.width() == 1 && bm.height() == 1);
+ {
+ SkAutoLockPixels alp(bm);
+ REPORTER_ASSERT(reporter, bm.getAddr32(0, 0)[0] == 0x7fffffff);
+ }
+
+ success = stream.rewind();
+ REPORTER_ASSERT(reporter, success);
+ if (!success) {
+ continue;
+ }
+
+ // Test premultiplied. Once again, we know which color this should
+ // result in.
+ decoder->setRequireUnpremultipliedColors(false);
+ success = decoder->decode(&stream, &bm, kN32_SkColorType,
+ SkImageDecoder::kDecodePixels_Mode);
+ REPORTER_ASSERT(reporter, success);
+ if (!success) {
+ continue;
+ }
+
+ REPORTER_ASSERT(reporter, bm.width() == 1 && bm.height() == 1);
+ {
+ SkAutoLockPixels alp(bm);
+ REPORTER_ASSERT(reporter, bm.getAddr32(0, 0)[0] == 0x7f7f7f7f);
+ }
+ }
+}
+#endif // SK_BUILD_FOR_UNIX/ANDROID skbug.com/2388
+
+#ifdef SK_DEBUG
+// Create a stream containing a bitmap encoded to Type type.
+static SkMemoryStream* create_image_stream(SkImageEncoder::Type type) {
+ SkBitmap bm;
+ const int size = 50;
+ bm.allocN32Pixels(size, size);
+ SkCanvas canvas(bm);
+ SkPoint points[2] = {
+ { SkIntToScalar(0), SkIntToScalar(0) },
+ { SkIntToScalar(size), SkIntToScalar(size) }
+ };
+ SkColor colors[2] = { SK_ColorWHITE, SK_ColorBLUE };
+ SkShader* shader = SkGradientShader::CreateLinear(points, colors, NULL,
+ SK_ARRAY_COUNT(colors),
+ SkShader::kClamp_TileMode);
+ SkPaint paint;
+ paint.setShader(shader)->unref();
+ canvas.drawPaint(paint);
+ // Now encode it to a stream.
+ SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(bm, type, 100));
+ if (NULL == data.get()) {
+ return NULL;
+ }
+ return SkNEW_ARGS(SkMemoryStream, (data.get()));
+}
+
+// For every format that supports tile based decoding, ensure that
+// calling decodeSubset will not fail if the caller has unreffed the
+// stream provided in buildTileIndex.
+// Only runs in debug mode since we are testing for a crash.
+static void test_stream_life() {
+ const SkImageEncoder::Type gTypes[] = {
+#ifdef SK_BUILD_FOR_ANDROID
+ SkImageEncoder::kJPEG_Type,
+ SkImageEncoder::kPNG_Type,
+#endif
+ SkImageEncoder::kWEBP_Type,
+ };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gTypes); ++i) {
+ // SkDebugf("encoding to %i\n", i);
+ SkAutoTUnref<SkMemoryStream> stream(create_image_stream(gTypes[i]));
+ if (NULL == stream.get()) {
+ SkDebugf("no stream\n");
+ continue;
+ }
+ SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
+ if (NULL == decoder.get()) {
+ SkDebugf("no decoder\n");
+ continue;
+ }
+ int width, height;
+ if (!decoder->buildTileIndex(stream.get(), &width, &height)) {
+ SkDebugf("could not build a tile index\n");
+ continue;
+ }
+ // Now unref the stream to make sure it survives
+ stream.reset(NULL);
+ SkBitmap bm;
+ decoder->decodeSubset(&bm, SkIRect::MakeWH(width, height), kN32_SkColorType);
+ }
+}
+
+// Test inside SkScaledBitmapSampler.cpp
+extern void test_row_proc_choice();
+
+#endif // SK_DEBUG
+
+DEF_TEST(ImageDecoding, reporter) {
+ test_unpremul(reporter);
+#ifdef SK_DEBUG
+ test_stream_life();
+ test_row_proc_choice();
+#endif
+}
+
+// expected output for 8x8 bitmap
+static const int kExpectedWidth = 8;
+static const int kExpectedHeight = 8;
+static const SkColor kExpectedPixels[] = {
+ 0xffbba570, 0xff395f5d, 0xffe25c39, 0xff197666,
+ 0xff3cba27, 0xffdefcb0, 0xffc13874, 0xfffa0093,
+ 0xffbda60e, 0xffc01db6, 0xff2bd688, 0xff9362d4,
+ 0xffc641b2, 0xffa5cede, 0xff606eba, 0xff8f4bf3,
+ 0xff3bf742, 0xff8f02a8, 0xff5509df, 0xffc7027e,
+ 0xff24aa8a, 0xff886c96, 0xff625481, 0xff403689,
+ 0xffc52152, 0xff78ccd6, 0xffdcb4ab, 0xff09d27d,
+ 0xffca00f3, 0xff605d47, 0xff446fb2, 0xff576e46,
+ 0xff273df9, 0xffb41a83, 0xfff812c3, 0xffccab67,
+ 0xff034218, 0xff7db9a7, 0xff821048, 0xfffe4ab4,
+ 0xff6fac98, 0xff941d27, 0xff5fe411, 0xfffbb283,
+ 0xffd86e99, 0xff169162, 0xff71128c, 0xff39cab4,
+ 0xffa7fe63, 0xff4c956b, 0xffbc22e0, 0xffb272e4,
+ 0xff129f4a, 0xffe34513, 0xff3d3742, 0xffbd190a,
+ 0xffb07222, 0xff2e23f8, 0xfff089d9, 0xffb35738,
+ 0xffa86022, 0xff3340fe, 0xff95fe71, 0xff6a71df
+};
+SK_COMPILE_ASSERT((kExpectedWidth * kExpectedHeight)
+ == SK_ARRAY_COUNT(kExpectedPixels), array_size_mismatch);
+
+DEF_TEST(WebP, reporter) {
+ const unsigned char encodedWebP[] = {
+ 0x52, 0x49, 0x46, 0x46, 0x2c, 0x01, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50,
+ 0x56, 0x50, 0x38, 0x4c, 0x20, 0x01, 0x00, 0x00, 0x2f, 0x07, 0xc0, 0x01,
+ 0x00, 0xff, 0x01, 0x45, 0x03, 0x00, 0xe2, 0xd5, 0xae, 0x60, 0x2b, 0xad,
+ 0xd9, 0x68, 0x76, 0xb6, 0x8d, 0x6a, 0x1d, 0xc0, 0xe6, 0x19, 0xd6, 0x16,
+ 0xb7, 0xb4, 0xef, 0xcf, 0xc3, 0x15, 0x6c, 0xb3, 0xbd, 0x77, 0x0d, 0x85,
+ 0x6d, 0x1b, 0xa9, 0xb1, 0x2b, 0xdc, 0x3d, 0x83, 0xdb, 0x00, 0x00, 0xc8,
+ 0x26, 0xe5, 0x01, 0x99, 0x8a, 0xd5, 0xdd, 0xfc, 0x82, 0xcd, 0xcd, 0x9a,
+ 0x8c, 0x13, 0xcc, 0x1b, 0xba, 0xf5, 0x05, 0xdb, 0xee, 0x6a, 0xdb, 0x38,
+ 0x60, 0xfe, 0x43, 0x2c, 0xd4, 0x6a, 0x99, 0x4d, 0xc6, 0xc0, 0xd3, 0x28,
+ 0x1b, 0xc1, 0xb1, 0x17, 0x4e, 0x43, 0x0e, 0x3d, 0x27, 0xe9, 0xe4, 0x84,
+ 0x4f, 0x24, 0x62, 0x69, 0x85, 0x43, 0x8d, 0xc2, 0x04, 0x00, 0x07, 0x59,
+ 0x60, 0xfd, 0x8b, 0x4d, 0x60, 0x32, 0x72, 0xcf, 0x88, 0x0c, 0x2f, 0x2f,
+ 0xad, 0x62, 0xbd, 0x27, 0x09, 0x16, 0x70, 0x78, 0x6c, 0xd9, 0x82, 0xef,
+ 0x1a, 0xa2, 0xcc, 0xf0, 0xf1, 0x6f, 0xd8, 0x78, 0x2e, 0x39, 0xa1, 0xcf,
+ 0x14, 0x4b, 0x89, 0xb4, 0x1b, 0x48, 0x15, 0x7c, 0x48, 0x6f, 0x8c, 0x20,
+ 0xb7, 0x00, 0xcf, 0xfc, 0xdb, 0xd0, 0xe9, 0xe7, 0x42, 0x09, 0xa4, 0x03,
+ 0x40, 0xac, 0xda, 0x40, 0x01, 0x00, 0x5f, 0xa1, 0x3d, 0x64, 0xe1, 0xf4,
+ 0x03, 0x45, 0x29, 0xe0, 0xe2, 0x4a, 0xc3, 0xa2, 0xe8, 0xe0, 0x25, 0x12,
+ 0x74, 0xc6, 0xe8, 0xfb, 0x93, 0x4f, 0x9f, 0x5e, 0xc0, 0xa6, 0x91, 0x1b,
+ 0xa4, 0x24, 0x82, 0xc3, 0x61, 0x07, 0x4c, 0x49, 0x4f, 0x53, 0xae, 0x5f,
+ 0x5d, 0x39, 0x36, 0xc0, 0x5b, 0x57, 0x54, 0x60, 0x10, 0x00, 0x00, 0xd1,
+ 0x68, 0xb6, 0x6d, 0xdb, 0x36, 0x22, 0xfa, 0x1f, 0x35, 0x75, 0x22, 0xec,
+ 0x31, 0xbc, 0x5d, 0x8f, 0x87, 0x53, 0xa2, 0x05, 0x8c, 0x2f, 0xcd, 0xa8,
+ 0xa7, 0xf3, 0xa3, 0xbd, 0x83, 0x8b, 0x2a, 0xc8, 0x58, 0xf5, 0xac, 0x80,
+ 0xe3, 0xfe, 0x66, 0xa4, 0x7c, 0x1b, 0x6c, 0xd1, 0xa9, 0xd8, 0x14, 0xd0,
+ 0xc5, 0xb5, 0x39, 0x71, 0x97, 0x19, 0x19, 0x1b
+ };
+ SkAutoDataUnref encoded(SkData::NewWithCopy(encodedWebP,
+ sizeof(encodedWebP)));
+ SkBitmap bm;
+
+ bool success = SkInstallDiscardablePixelRef(
+ SkDecodingImageGenerator::Create(encoded,
+ SkDecodingImageGenerator::Options()), &bm);
+
+ REPORTER_ASSERT(reporter, success);
+ if (!success) {
+ return;
+ }
+ SkAutoLockPixels alp(bm);
+
+ bool rightSize = ((kExpectedWidth == bm.width())
+ && (kExpectedHeight == bm.height()));
+ REPORTER_ASSERT(reporter, rightSize);
+ if (rightSize) {
+ bool error = false;
+ const SkColor* correctPixel = kExpectedPixels;
+ for (int y = 0; y < bm.height(); ++y) {
+ for (int x = 0; x < bm.width(); ++x) {
+ error |= (*correctPixel != bm.getColor(x, y));
+ ++correctPixel;
+ }
+ }
+ REPORTER_ASSERT(reporter, !error);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// example of how Android will do this inside their BitmapFactory
+static SkPixelRef* install_pixel_ref(SkBitmap* bitmap,
+ SkStreamRewindable* stream,
+ int sampleSize, bool ditherImage) {
+ SkASSERT(bitmap != NULL);
+ SkASSERT(stream != NULL);
+ SkASSERT(stream->rewind());
+ SkASSERT(stream->unique());
+ SkColorType colorType = bitmap->colorType();
+ SkDecodingImageGenerator::Options opts(sampleSize, ditherImage, colorType);
+ if (SkInstallDiscardablePixelRef(
+ SkDecodingImageGenerator::Create(stream, opts), bitmap)) {
+ return bitmap->pixelRef();
+ }
+ return NULL;
+}
+/**
+ * A test for the SkDecodingImageGenerator::Create and
+ * SkInstallDiscardablePixelRef functions.
+ */
+DEF_TEST(ImprovedBitmapFactory, reporter) {
+ SkString pngFilename = GetResourcePath("randPixels.png");
+ SkAutoTUnref<SkStreamRewindable> stream(SkStream::NewFromFile(pngFilename.c_str()));
+ if (sk_exists(pngFilename.c_str())) {
+ SkBitmap bm;
+ SkAssertResult(bm.setInfo(SkImageInfo::MakeN32Premul(1, 1)));
+ REPORTER_ASSERT(reporter,
+ install_pixel_ref(&bm, stream.detach(), 1, true));
+ SkAutoLockPixels alp(bm);
+ REPORTER_ASSERT(reporter, bm.getPixels());
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
+static inline bool check_rounding(int value, int dividend, int divisor) {
+ // returns true if the value is greater than floor(dividend/divisor)
+ // and less than SkNextPow2(ceil(dividend - divisor))
+ return (((divisor * value) > (dividend - divisor))
+ && value <= SkNextPow2(((dividend - 1) / divisor) + 1));
+}
+#endif // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX
+
+
+#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
+ #define kBackwards_SkColorType kRGBA_8888_SkColorType
+#elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
+ #define kBackwards_SkColorType kBGRA_8888_SkColorType
+#else
+ #error "SK_*32_SHFIT values must correspond to BGRA or RGBA byte order"
+#endif
+
+static inline const char* SkColorType_to_string(SkColorType colorType) {
+ switch(colorType) {
+ case kAlpha_8_SkColorType: return "Alpha_8";
+ case kRGB_565_SkColorType: return "RGB_565";
+ case kARGB_4444_SkColorType: return "ARGB_4444";
+ case kN32_SkColorType: return "N32";
+ case kBackwards_SkColorType: return "Backwards";
+ case kIndex_8_SkColorType: return "Index_8";
+ default: return "ERROR";
+ }
+}
+
+static inline const char* options_colorType(
+ const SkDecodingImageGenerator::Options& opts) {
+ if (opts.fUseRequestedColorType) {
+ return SkColorType_to_string(opts.fRequestedColorType);
+ } else {
+ return "(none)";
+ }
+}
+
+static inline const char* yn(bool value) {
+ if (value) {
+ return "yes";
+ } else {
+ return "no";
+ }
+}
+
+/**
+ * Given either a SkStream or a SkData, try to decode the encoded
+ * image using the specified options and report errors.
+ */
+static void test_options(skiatest::Reporter* reporter,
+ const SkDecodingImageGenerator::Options& opts,
+ SkStreamRewindable* encodedStream,
+ SkData* encodedData,
+ bool useData,
+ const SkString& path) {
+ SkBitmap bm;
+ bool success = false;
+ if (useData) {
+ if (NULL == encodedData) {
+ return;
+ }
+ success = SkInstallDiscardablePixelRef(
+ SkDecodingImageGenerator::Create(encodedData, opts), &bm);
+ } else {
+ if (NULL == encodedStream) {
+ return;
+ }
+ success = SkInstallDiscardablePixelRef(
+ SkDecodingImageGenerator::Create(encodedStream->duplicate(), opts), &bm);
+ }
+ if (!success) {
+ if (opts.fUseRequestedColorType
+ && (kARGB_4444_SkColorType == opts.fRequestedColorType)) {
+ return; // Ignore known conversion inabilities.
+ }
+ // If we get here, it's a failure and we will need more
+ // information about why it failed.
+ ERRORF(reporter, "Bounds decode failed [sampleSize=%d dither=%s "
+ "colorType=%s %s]", opts.fSampleSize, yn(opts.fDitherImage),
+ options_colorType(opts), path.c_str());
+ return;
+ }
+ #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
+ // Android is the only system that use Skia's image decoders in
+ // production. For now, we'll only verify that samplesize works
+ // on systems where it already is known to work.
+ REPORTER_ASSERT(reporter, check_rounding(bm.height(), kExpectedHeight,
+ opts.fSampleSize));
+ REPORTER_ASSERT(reporter, check_rounding(bm.width(), kExpectedWidth,
+ opts.fSampleSize));
+ // The ImageDecoder API doesn't guarantee that SampleSize does
+ // anything at all, but the decoders that this test excercises all
+ // produce an output size in the following range:
+ // (((sample_size * out_size) > (in_size - sample_size))
+ // && out_size <= SkNextPow2(((in_size - 1) / sample_size) + 1));
+ #endif // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX
+ SkAutoLockPixels alp(bm);
+ if (bm.getPixels() == NULL) {
+ ERRORF(reporter, "Pixel decode failed [sampleSize=%d dither=%s "
+ "colorType=%s %s]", opts.fSampleSize, yn(opts.fDitherImage),
+ options_colorType(opts), path.c_str());
+ return;
+ }
+
+ SkColorType requestedColorType = opts.fRequestedColorType;
+ REPORTER_ASSERT(reporter,
+ (!opts.fUseRequestedColorType)
+ || (bm.colorType() == requestedColorType));
+
+ // Condition under which we should check the decoding results:
+ if ((kN32_SkColorType == bm.colorType())
+ && (!path.endsWith(".jpg")) // lossy
+ && (opts.fSampleSize == 1)) { // scaled
+ const SkColor* correctPixels = kExpectedPixels;
+ SkASSERT(bm.height() == kExpectedHeight);
+ SkASSERT(bm.width() == kExpectedWidth);
+ int pixelErrors = 0;
+ for (int y = 0; y < bm.height(); ++y) {
+ for (int x = 0; x < bm.width(); ++x) {
+ if (*correctPixels != bm.getColor(x, y)) {
+ ++pixelErrors;
+ }
+ ++correctPixels;
+ }
+ }
+ if (pixelErrors != 0) {
+ ERRORF(reporter, "Pixel-level mismatch (%d of %d) "
+ "[sampleSize=%d dither=%s colorType=%s %s]",
+ pixelErrors, kExpectedHeight * kExpectedWidth,
+ opts.fSampleSize, yn(opts.fDitherImage),
+ options_colorType(opts), path.c_str());
+ }
+ }
+}
+
+/**
+ * SkDecodingImageGenerator has an Options struct which lets the
+ * client of the generator set sample size, dithering, and bitmap
+ * config. This test loops through many possible options and tries
+ * them on a set of 5 small encoded images (each in a different
+ * format). We test both SkData and SkStreamRewindable decoding.
+ */
+DEF_TEST(ImageDecoderOptions, reporter) {
+ const char* files[] = {
+ "randPixels.bmp",
+ "randPixels.jpg",
+ "randPixels.png",
+ "randPixels.webp",
+ #if !defined(SK_BUILD_FOR_WIN)
+ // TODO(halcanary): Find out why this fails sometimes.
+ "randPixels.gif",
+ #endif
+ };
+
+ SkString resourceDir = GetResourcePath();
+ if (!sk_exists(resourceDir.c_str())) {
+ return;
+ }
+
+ int scaleList[] = {1, 2, 3, 4};
+ bool ditherList[] = {true, false};
+ SkColorType colorList[] = {
+ kAlpha_8_SkColorType,
+ kRGB_565_SkColorType,
+ kARGB_4444_SkColorType, // Most decoders will fail on 4444.
+ kN32_SkColorType
+ // Note that indexed color is left out of the list. Lazy
+ // decoding doesn't do indexed color.
+ };
+ const bool useDataList[] = {true, false};
+
+ for (size_t fidx = 0; fidx < SK_ARRAY_COUNT(files); ++fidx) {
+ SkString path = SkOSPath::Join(resourceDir.c_str(), files[fidx]);
+ if (!sk_exists(path.c_str())) {
+ continue;
+ }
+
+ SkAutoDataUnref encodedData(SkData::NewFromFileName(path.c_str()));
+ REPORTER_ASSERT(reporter, encodedData.get() != NULL);
+ SkAutoTUnref<SkStreamRewindable> encodedStream(
+ SkStream::NewFromFile(path.c_str()));
+ REPORTER_ASSERT(reporter, encodedStream.get() != NULL);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(scaleList); ++i) {
+ for (size_t j = 0; j < SK_ARRAY_COUNT(ditherList); ++j) {
+ for (size_t m = 0; m < SK_ARRAY_COUNT(useDataList); ++m) {
+ for (size_t k = 0; k < SK_ARRAY_COUNT(colorList); ++k) {
+ SkDecodingImageGenerator::Options opts(scaleList[i],
+ ditherList[j],
+ colorList[k]);
+ test_options(reporter, opts, encodedStream, encodedData,
+ useDataList[m], path);
+
+ }
+ SkDecodingImageGenerator::Options options(scaleList[i],
+ ditherList[j]);
+ test_options(reporter, options, encodedStream, encodedData,
+ useDataList[m], path);
+ }
+ }
+ }
+ }
+}
+
+DEF_TEST(DiscardablePixelRef_SecondLockColorTableCheck, r) {
+ SkString resourceDir = GetResourcePath();
+ SkString path = SkOSPath::Join(resourceDir.c_str(), "randPixels.gif");
+ if (!sk_exists(path.c_str())) {
+ return;
+ }
+ SkAutoDataUnref encoded(SkData::NewFromFileName(path.c_str()));
+ SkBitmap bitmap;
+ if (!SkInstallDiscardablePixelRef(
+ SkDecodingImageGenerator::Create(
+ encoded, SkDecodingImageGenerator::Options()), &bitmap)) {
+ #ifndef SK_BUILD_FOR_WIN
+ ERRORF(r, "SkInstallDiscardablePixelRef [randPixels.gif] failed.");
+ #endif
+ return;
+ }
+ if (kIndex_8_SkColorType != bitmap.colorType()) {
+ return;
+ }
+ {
+ SkAutoLockPixels alp(bitmap);
+ REPORTER_ASSERT(r, bitmap.getColorTable() && "first pass");
+ }
+ {
+ SkAutoLockPixels alp(bitmap);
+ REPORTER_ASSERT(r, bitmap.getColorTable() && "second pass");
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+namespace {
+class SingleAllocator : public SkBitmap::Allocator {
+public:
+ SingleAllocator(void* p, size_t s) : fPixels(p), fSize(s) { }
+ ~SingleAllocator() {}
+ // If the pixels in fPixels are big enough, use them.
+ virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE {
+ SkASSERT(bm);
+ if (bm->info().getSafeSize(bm->rowBytes()) <= fSize) {
+ bm->setPixels(fPixels, ct);
+ fPixels = NULL;
+ fSize = 0;
+ return true;
+ }
+ return bm->tryAllocPixels(NULL, ct);
+ }
+ bool ready() { return fPixels != NULL; }
+private:
+ void* fPixels;
+ size_t fSize;
+};
+} // namespace
+
+/* This tests for a bug in libjpeg where INT32 is typedefed to long
+ and memory can be written to outside of the array. */
+DEF_TEST(ImageDecoding_JpegOverwrite, r) {
+ SkString resourceDir = GetResourcePath();
+ SkString path = SkOSPath::Join(resourceDir.c_str(), "randPixels.jpg");
+ SkAutoTUnref<SkStreamAsset> stream(
+ SkStream::NewFromFile(path.c_str()));
+ if (!stream.get()) {
+ SkDebugf("\nPath '%s' missing.\n", path.c_str());
+ return;
+ }
+ SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
+ if (NULL == decoder.get()) {
+ ERRORF(r, "\nSkImageDecoder::Factory failed.\n");
+ return;
+ }
+ SkAssertResult(stream->rewind());
+
+ static const uint16_t sentinal = 0xBEEF;
+ static const int pixelCount = 16;
+ SkAutoTMalloc<uint16_t> pixels(pixelCount + 1);
+ // pixels.get() should be 4-byte aligned.
+ // This is necessary to reproduce the bug.
+
+ pixels[pixelCount] = sentinal; // This value should not be changed.
+
+ SkAutoTUnref<SingleAllocator> allocator(
+ SkNEW_ARGS(SingleAllocator,
+ ((void*)pixels.get(), sizeof(uint16_t) * pixelCount)));
+ decoder->setAllocator(allocator);
+ decoder->setSampleSize(2);
+ SkBitmap bitmap;
+ bool success = decoder->decode(stream, &bitmap, kRGB_565_SkColorType,
+ SkImageDecoder::kDecodePixels_Mode);
+ REPORTER_ASSERT(r, success);
+ REPORTER_ASSERT(r, !allocator->ready()); // Decoder used correct memory
+ REPORTER_ASSERT(r, sentinal == pixels[pixelCount]);
+}
diff --git a/src/third_party/skia/tests/ImageFilterTest.cpp b/src/third_party/skia/tests/ImageFilterTest.cpp
new file mode 100644
index 0000000..d0fa93f
--- /dev/null
+++ b/src/third_party/skia/tests/ImageFilterTest.cpp
@@ -0,0 +1,1094 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkBitmapDevice.h"
+#include "SkBitmapSource.h"
+#include "SkBlurImageFilter.h"
+#include "SkCanvas.h"
+#include "SkColorFilterImageFilter.h"
+#include "SkColorMatrixFilter.h"
+#include "SkDeviceImageFilterProxy.h"
+#include "SkDisplacementMapEffect.h"
+#include "SkDropShadowImageFilter.h"
+#include "SkFlattenableSerialization.h"
+#include "SkGradientShader.h"
+#include "SkLightingImageFilter.h"
+#include "SkMatrixConvolutionImageFilter.h"
+#include "SkMatrixImageFilter.h"
+#include "SkMergeImageFilter.h"
+#include "SkMorphologyImageFilter.h"
+#include "SkOffsetImageFilter.h"
+#include "SkPicture.h"
+#include "SkPictureImageFilter.h"
+#include "SkPictureRecorder.h"
+#include "SkReadBuffer.h"
+#include "SkRect.h"
+#include "SkTileImageFilter.h"
+#include "SkXfermodeImageFilter.h"
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#include "SkGpuDevice.h"
+#endif
+
+static const int kBitmapSize = 4;
+
+namespace {
+
+class MatrixTestImageFilter : public SkImageFilter {
+public:
+ MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
+ : SkImageFilter(0, NULL), fReporter(reporter), fExpectedMatrix(expectedMatrix) {
+ }
+
+ virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context& ctx,
+ SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE {
+ REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
+ return true;
+ }
+
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
+
+protected:
+#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
+ explicit MatrixTestImageFilter(SkReadBuffer& buffer) : SkImageFilter(0, NULL) {
+ fReporter = static_cast<skiatest::Reporter*>(buffer.readFunctionPtr());
+ buffer.readMatrix(&fExpectedMatrix);
+ }
+#endif
+
+ virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
+ this->INHERITED::flatten(buffer);
+ buffer.writeFunctionPtr(fReporter);
+ buffer.writeMatrix(fExpectedMatrix);
+ }
+
+private:
+ skiatest::Reporter* fReporter;
+ SkMatrix fExpectedMatrix;
+
+ typedef SkImageFilter INHERITED;
+};
+
+}
+
+SkFlattenable* MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
+ SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
+ skiatest::Reporter* reporter = (skiatest::Reporter*)buffer.readFunctionPtr();
+ SkMatrix matrix;
+ buffer.readMatrix(&matrix);
+ return SkNEW_ARGS(MatrixTestImageFilter, (reporter, matrix));
+}
+
+static void make_small_bitmap(SkBitmap& bitmap) {
+ bitmap.allocN32Pixels(kBitmapSize, kBitmapSize);
+ SkCanvas canvas(bitmap);
+ canvas.clear(0x00000000);
+ SkPaint darkPaint;
+ darkPaint.setColor(0xFF804020);
+ SkPaint lightPaint;
+ lightPaint.setColor(0xFF244484);
+ const int i = kBitmapSize / 4;
+ for (int y = 0; y < kBitmapSize; y += i) {
+ for (int x = 0; x < kBitmapSize; x += i) {
+ canvas.save();
+ canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
+ canvas.drawRect(SkRect::MakeXYWH(0, 0,
+ SkIntToScalar(i),
+ SkIntToScalar(i)), darkPaint);
+ canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
+ 0,
+ SkIntToScalar(i),
+ SkIntToScalar(i)), lightPaint);
+ canvas.drawRect(SkRect::MakeXYWH(0,
+ SkIntToScalar(i),
+ SkIntToScalar(i),
+ SkIntToScalar(i)), lightPaint);
+ canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
+ SkIntToScalar(i),
+ SkIntToScalar(i),
+ SkIntToScalar(i)), darkPaint);
+ canvas.restore();
+ }
+ }
+}
+
+static SkImageFilter* make_scale(float amount, SkImageFilter* input = NULL) {
+ SkScalar s = amount;
+ SkScalar matrix[20] = { s, 0, 0, 0, 0,
+ 0, s, 0, 0, 0,
+ 0, 0, s, 0, 0,
+ 0, 0, 0, s, 0 };
+ SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
+ return SkColorFilterImageFilter::Create(filter, input);
+}
+
+static SkImageFilter* make_grayscale(SkImageFilter* input = NULL, const SkImageFilter::CropRect* cropRect = NULL) {
+ SkScalar matrix[20];
+ memset(matrix, 0, 20 * sizeof(SkScalar));
+ matrix[0] = matrix[5] = matrix[10] = 0.2126f;
+ matrix[1] = matrix[6] = matrix[11] = 0.7152f;
+ matrix[2] = matrix[7] = matrix[12] = 0.0722f;
+ matrix[18] = 1.0f;
+ SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
+ return SkColorFilterImageFilter::Create(filter, input, cropRect);
+}
+
+DEF_TEST(ImageFilter, reporter) {
+ {
+ // Check that two non-clipping color matrices concatenate into a single filter.
+ SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f));
+ SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness));
+ REPORTER_ASSERT(reporter, NULL == quarterBrightness->getInput(0));
+ }
+
+ {
+ // Check that a clipping color matrix followed by a grayscale does not concatenate into a single filter.
+ SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f));
+ SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness));
+ REPORTER_ASSERT(reporter, halfBrightness->getInput(0));
+ }
+
+ {
+ // Check that a color filter image filter without a crop rect can be
+ // expressed as a color filter.
+ SkAutoTUnref<SkImageFilter> gray(make_grayscale());
+ REPORTER_ASSERT(reporter, true == gray->asColorFilter(NULL));
+ }
+
+ {
+ // Check that a color filter image filter with a crop rect cannot
+ // be expressed as a color filter.
+ SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
+ SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(NULL, &cropRect));
+ REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(NULL));
+ }
+
+ {
+ // Check that two non-commutative matrices are concatenated in
+ // the correct order.
+ SkScalar blueToRedMatrix[20] = { 0 };
+ blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
+ SkScalar redToGreenMatrix[20] = { 0 };
+ redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
+ SkAutoTUnref<SkColorFilter> blueToRed(SkColorMatrixFilter::Create(blueToRedMatrix));
+ SkAutoTUnref<SkImageFilter> filter1(SkColorFilterImageFilter::Create(blueToRed.get()));
+ SkAutoTUnref<SkColorFilter> redToGreen(SkColorMatrixFilter::Create(redToGreenMatrix));
+ SkAutoTUnref<SkImageFilter> filter2(SkColorFilterImageFilter::Create(redToGreen.get(), filter1.get()));
+
+ SkBitmap result;
+ result.allocN32Pixels(kBitmapSize, kBitmapSize);
+
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ paint.setImageFilter(filter2.get());
+ SkCanvas canvas(result);
+ canvas.clear(0x0);
+ SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
+ canvas.drawRect(rect, paint);
+ uint32_t pixel = *result.getAddr32(0, 0);
+ // The result here should be green, since we have effectively shifted blue to green.
+ REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
+ }
+
+ {
+ // Tests pass by not asserting
+ SkBitmap bitmap, result;
+ make_small_bitmap(bitmap);
+ result.allocN32Pixels(kBitmapSize, kBitmapSize);
+
+ {
+ // This tests for :
+ // 1 ) location at (0,0,1)
+ SkPoint3 location(0, 0, SK_Scalar1);
+ // 2 ) location and target at same value
+ SkPoint3 target(location.fX, location.fY, location.fZ);
+ // 3 ) large negative specular exponent value
+ SkScalar specularExponent = -1000;
+
+ SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
+ SkPaint paint;
+ paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(
+ location, target, specularExponent, 180,
+ 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
+ bmSrc))->unref();
+ SkCanvas canvas(result);
+ SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
+ SkIntToScalar(kBitmapSize));
+ canvas.drawRect(r, paint);
+ }
+ }
+}
+
+static void test_crop_rects(SkBaseDevice* device, skiatest::Reporter* reporter) {
+ // Check that all filters offset to their absolute crop rect,
+ // unaffected by the input crop rect.
+ // Tests pass by not asserting.
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(100, 100);
+ bitmap.eraseARGB(0, 0, 0, 0);
+ SkDeviceImageFilterProxy proxy(device);
+
+ SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
+ SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
+ SkAutoTUnref<SkImageFilter> input(make_grayscale(NULL, &inputCropRect));
+
+ SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
+ SkPoint3 location(0, 0, SK_Scalar1);
+ SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ SkScalar kernel[9] = {
+ SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
+ SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
+ SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
+ };
+ SkISize kernelSize = SkISize::Make(3, 3);
+ SkScalar gain = SK_Scalar1, bias = 0;
+
+ SkImageFilter* filters[] = {
+ SkColorFilterImageFilter::Create(cf.get(), input.get(), &cropRect),
+ SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType,
+ SkDisplacementMapEffect::kB_ChannelSelectorType,
+ 40.0f, input.get(), input.get(), &cropRect),
+ SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
+ SkDropShadowImageFilter::Create(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN, input.get(), &cropRect),
+ SkLightingImageFilter::CreatePointLitDiffuse(location, SK_ColorGREEN, 0, 0, input.get(), &cropRect),
+ SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input.get(), &cropRect),
+ SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input.get(), &cropRect),
+ SkMergeImageFilter::Create(input.get(), input.get(), SkXfermode::kSrcOver_Mode, &cropRect),
+ SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
+ SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
+ SkDilateImageFilter::Create(3, 2, input.get(), &cropRect),
+ SkErodeImageFilter::Create(2, 3, input.get(), &cropRect),
+ SkTileImageFilter::Create(inputCropRect.rect(), cropRect.rect(), input.get()),
+ SkXfermodeImageFilter::Create(SkXfermode::Create(SkXfermode::kSrcOver_Mode), input.get(), input.get(), &cropRect),
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
+ SkImageFilter* filter = filters[i];
+ SkBitmap result;
+ SkIPoint offset;
+ SkString str;
+ str.printf("filter %d", static_cast<int>(i));
+ SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
+ REPORTER_ASSERT_MESSAGE(reporter, filter->filterImage(&proxy, bitmap, ctx,
+ &result, &offset), str.c_str());
+ REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str());
+ }
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
+ SkSafeUnref(filters[i]);
+ }
+}
+
+static SkBitmap make_gradient_circle(int width, int height) {
+ SkBitmap bitmap;
+ SkScalar x = SkIntToScalar(width / 2);
+ SkScalar y = SkIntToScalar(height / 2);
+ SkScalar radius = SkMinScalar(x, y) * 0.8f;
+ bitmap.allocN32Pixels(width, height);
+ SkCanvas canvas(bitmap);
+ canvas.clear(0x00000000);
+ SkColor colors[2];
+ colors[0] = SK_ColorWHITE;
+ colors[1] = SK_ColorBLACK;
+ SkAutoTUnref<SkShader> shader(
+ SkGradientShader::CreateRadial(SkPoint::Make(x, y), radius, colors, NULL, 2,
+ SkShader::kClamp_TileMode)
+ );
+ SkPaint paint;
+ paint.setShader(shader);
+ canvas.drawCircle(x, y, radius, paint);
+ return bitmap;
+}
+
+static void test_negative_blur_sigma(SkBaseDevice* device, skiatest::Reporter* reporter) {
+ // Check that SkBlurImageFilter will accept a negative sigma, either in
+ // the given arguments or after CTM application.
+ int width = 32, height = 32;
+ SkDeviceImageFilterProxy proxy(device);
+ SkScalar five = SkIntToScalar(5);
+
+ SkAutoTUnref<SkBlurImageFilter> positiveFilter(
+ SkBlurImageFilter::Create(five, five)
+ );
+
+ SkAutoTUnref<SkBlurImageFilter> negativeFilter(
+ SkBlurImageFilter::Create(-five, five)
+ );
+
+ SkBitmap gradient = make_gradient_circle(width, height);
+ SkBitmap positiveResult1, negativeResult1;
+ SkBitmap positiveResult2, negativeResult2;
+ SkIPoint offset;
+ SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
+ positiveFilter->filterImage(&proxy, gradient, ctx, &positiveResult1, &offset);
+ negativeFilter->filterImage(&proxy, gradient, ctx, &negativeResult1, &offset);
+ SkMatrix negativeScale;
+ negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
+ SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeLargest(), NULL);
+ positiveFilter->filterImage(&proxy, gradient, negativeCTX, &negativeResult2, &offset);
+ negativeFilter->filterImage(&proxy, gradient, negativeCTX, &positiveResult2, &offset);
+ SkAutoLockPixels lockP1(positiveResult1);
+ SkAutoLockPixels lockP2(positiveResult2);
+ SkAutoLockPixels lockN1(negativeResult1);
+ SkAutoLockPixels lockN2(negativeResult2);
+ for (int y = 0; y < height; y++) {
+ int diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult1.getAddr32(0, y), positiveResult1.rowBytes());
+ REPORTER_ASSERT(reporter, !diffs);
+ if (diffs) {
+ break;
+ }
+ diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult2.getAddr32(0, y), positiveResult1.rowBytes());
+ REPORTER_ASSERT(reporter, !diffs);
+ if (diffs) {
+ break;
+ }
+ diffs = memcmp(positiveResult1.getAddr32(0, y), positiveResult2.getAddr32(0, y), positiveResult1.rowBytes());
+ REPORTER_ASSERT(reporter, !diffs);
+ if (diffs) {
+ break;
+ }
+ }
+}
+
+DEF_TEST(TestNegativeBlurSigma, reporter) {
+ SkBitmap temp;
+ temp.allocN32Pixels(100, 100);
+ SkBitmapDevice device(temp);
+ test_negative_blur_sigma(&device, reporter);
+}
+
+DEF_TEST(ImageFilterDrawTiled, reporter) {
+ // Check that all filters when drawn tiled (with subsequent clip rects) exactly
+ // match the same filters drawn with a single full-canvas bitmap draw.
+ // Tests pass by not asserting.
+
+ SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
+ SkPoint3 location(0, 0, SK_Scalar1);
+ SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ SkScalar kernel[9] = {
+ SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
+ SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
+ SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
+ };
+ SkISize kernelSize = SkISize::Make(3, 3);
+ SkScalar gain = SK_Scalar1, bias = 0;
+ SkScalar five = SkIntToScalar(5);
+
+ SkAutoTUnref<SkImageFilter> gradient_source(SkBitmapSource::Create(make_gradient_circle(64, 64)));
+ SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(five, five));
+ SkMatrix matrix;
+
+ matrix.setTranslate(SK_Scalar1, SK_Scalar1);
+ matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
+
+ SkRTreeFactory factory;
+ SkPictureRecorder recorder;
+ SkCanvas* recordingCanvas = recorder.beginRecording(64, 64, &factory, 0);
+
+ SkPaint greenPaint;
+ greenPaint.setColor(SK_ColorGREEN);
+ recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+ SkAutoTUnref<SkImageFilter> pictureFilter(SkPictureImageFilter::Create(picture.get()));
+
+ struct {
+ const char* fName;
+ SkImageFilter* fFilter;
+ } filters[] = {
+ { "color filter", SkColorFilterImageFilter::Create(cf.get()) },
+ { "displacement map", SkDisplacementMapEffect::Create(
+ SkDisplacementMapEffect::kR_ChannelSelectorType,
+ SkDisplacementMapEffect::kB_ChannelSelectorType,
+ 20.0f, gradient_source.get()) },
+ { "blur", SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1) },
+ { "drop shadow", SkDropShadowImageFilter::Create(
+ SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN) },
+ { "diffuse lighting", SkLightingImageFilter::CreatePointLitDiffuse(
+ location, SK_ColorGREEN, 0, 0) },
+ { "specular lighting",
+ SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0) },
+ { "matrix convolution",
+ SkMatrixConvolutionImageFilter::Create(
+ kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
+ SkMatrixConvolutionImageFilter::kRepeat_TileMode, false) },
+ { "merge", SkMergeImageFilter::Create(NULL, NULL, SkXfermode::kSrcOver_Mode) },
+ { "offset", SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1) },
+ { "dilate", SkDilateImageFilter::Create(3, 2) },
+ { "erode", SkErodeImageFilter::Create(2, 3) },
+ { "tile", SkTileImageFilter::Create(SkRect::MakeXYWH(0, 0, 50, 50),
+ SkRect::MakeXYWH(0, 0, 100, 100), NULL) },
+ { "matrix", SkMatrixImageFilter::Create(matrix, SkPaint::kLow_FilterLevel) },
+ { "blur and offset", SkOffsetImageFilter::Create(five, five, blur.get()) },
+ { "picture and blur", SkBlurImageFilter::Create(five, five, pictureFilter.get()) },
+ };
+
+ SkBitmap untiledResult, tiledResult;
+ int width = 64, height = 64;
+ untiledResult.allocN32Pixels(width, height);
+ tiledResult.allocN32Pixels(width, height);
+ SkCanvas tiledCanvas(tiledResult);
+ SkCanvas untiledCanvas(untiledResult);
+ int tileSize = 8;
+
+ for (int scale = 1; scale <= 2; ++scale) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
+ tiledCanvas.clear(0);
+ untiledCanvas.clear(0);
+ SkPaint paint;
+ paint.setImageFilter(filters[i].fFilter);
+ paint.setTextSize(SkIntToScalar(height));
+ paint.setColor(SK_ColorWHITE);
+ SkString str;
+ const char* text = "ABC";
+ SkScalar ypos = SkIntToScalar(height);
+ untiledCanvas.save();
+ untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
+ untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
+ untiledCanvas.restore();
+ for (int y = 0; y < height; y += tileSize) {
+ for (int x = 0; x < width; x += tileSize) {
+ tiledCanvas.save();
+ tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
+ tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
+ tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
+ tiledCanvas.restore();
+ }
+ }
+ untiledCanvas.flush();
+ tiledCanvas.flush();
+ for (int y = 0; y < height; y++) {
+ int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
+ REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters[i].fName);
+ if (diffs) {
+ break;
+ }
+ }
+ }
+ }
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
+ SkSafeUnref(filters[i].fFilter);
+ }
+}
+
+static void draw_saveLayer_picture(int width, int height, int tileSize,
+ SkBBHFactory* factory, SkBitmap* result) {
+
+ SkMatrix matrix;
+ matrix.setTranslate(SkIntToScalar(50), 0);
+
+ SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode));
+ SkAutoTUnref<SkImageFilter> cfif(SkColorFilterImageFilter::Create(cf.get()));
+ SkAutoTUnref<SkImageFilter> imageFilter(SkMatrixImageFilter::Create(matrix, SkPaint::kNone_FilterLevel, cfif.get()));
+
+ SkPaint paint;
+ paint.setImageFilter(imageFilter.get());
+ SkPictureRecorder recorder;
+ SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
+ SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
+ SkIntToScalar(height),
+ factory, 0);
+ recordingCanvas->translate(-55, 0);
+ recordingCanvas->saveLayer(&bounds, &paint);
+ recordingCanvas->restore();
+ SkAutoTUnref<SkPicture> picture1(recorder.endRecording());
+
+ result->allocN32Pixels(width, height);
+ SkCanvas canvas(*result);
+ canvas.clear(0);
+ canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
+ canvas.drawPicture(picture1.get());
+}
+
+DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
+ // Check that matrix filter when drawn tiled with BBH exactly
+ // matches the same thing drawn without BBH.
+ // Tests pass by not asserting.
+
+ const int width = 200, height = 200;
+ const int tileSize = 100;
+ SkBitmap result1, result2;
+ SkRTreeFactory factory;
+
+ draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
+ draw_saveLayer_picture(width, height, tileSize, NULL, &result2);
+
+ for (int y = 0; y < height; y++) {
+ int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
+ REPORTER_ASSERT(reporter, !diffs);
+ if (diffs) {
+ break;
+ }
+ }
+}
+
+static SkImageFilter* makeBlur(SkImageFilter* input = NULL) {
+ return SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input);
+}
+
+static SkImageFilter* makeDropShadow(SkImageFilter* input = NULL) {
+ return SkDropShadowImageFilter::Create(
+ SkIntToScalar(100), SkIntToScalar(100),
+ SkIntToScalar(10), SkIntToScalar(10),
+ SK_ColorBLUE, input);
+}
+
+DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
+ SkAutoTUnref<SkImageFilter> filter1(makeBlur());
+ SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get()));
+
+ SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
+ SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
+ filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
+
+ REPORTER_ASSERT(reporter, bounds == expectedBounds);
+}
+
+DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
+ SkAutoTUnref<SkImageFilter> filter1(makeDropShadow());
+ SkAutoTUnref<SkImageFilter> filter2(makeBlur(filter1.get()));
+
+ SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
+ SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
+ filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
+
+ REPORTER_ASSERT(reporter, bounds == expectedBounds);
+}
+
+DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
+ SkAutoTUnref<SkImageFilter> filter1(SkDilateImageFilter::Create(2, 2));
+ SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get()));
+
+ SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
+ SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
+ filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
+
+ REPORTER_ASSERT(reporter, bounds == expectedBounds);
+}
+
+static void draw_blurred_rect(SkCanvas* canvas) {
+ SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(SkIntToScalar(8), 0));
+ SkPaint filterPaint;
+ filterPaint.setColor(SK_ColorWHITE);
+ filterPaint.setImageFilter(filter);
+ canvas->saveLayer(NULL, &filterPaint);
+ SkPaint whitePaint;
+ whitePaint.setColor(SK_ColorWHITE);
+ canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
+ canvas->restore();
+}
+
+static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
+ canvas->save();
+ canvas->clipRect(clipRect);
+ canvas->drawPicture(picture);
+ canvas->restore();
+}
+
+DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
+ // Check that the blur filter when recorded with RTree acceleration,
+ // and drawn tiled (with subsequent clip rects) exactly
+ // matches the same filter drawn with without RTree acceleration.
+ // This tests that the "bleed" from the blur into the otherwise-blank
+ // tiles is correctly rendered.
+ // Tests pass by not asserting.
+
+ int width = 16, height = 8;
+ SkBitmap result1, result2;
+ result1.allocN32Pixels(width, height);
+ result2.allocN32Pixels(width, height);
+ SkCanvas canvas1(result1);
+ SkCanvas canvas2(result2);
+ int tileSize = 8;
+
+ canvas1.clear(0);
+ canvas2.clear(0);
+
+ SkRTreeFactory factory;
+
+ SkPictureRecorder recorder1, recorder2;
+ // The only difference between these two pictures is that one has RTree aceleration.
+ SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
+ SkIntToScalar(height),
+ NULL, 0);
+ SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
+ SkIntToScalar(height),
+ &factory, 0);
+ draw_blurred_rect(recordingCanvas1);
+ draw_blurred_rect(recordingCanvas2);
+ SkAutoTUnref<SkPicture> picture1(recorder1.endRecording());
+ SkAutoTUnref<SkPicture> picture2(recorder2.endRecording());
+ for (int y = 0; y < height; y += tileSize) {
+ for (int x = 0; x < width; x += tileSize) {
+ SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
+ draw_picture_clipped(&canvas1, tileRect, picture1);
+ draw_picture_clipped(&canvas2, tileRect, picture2);
+ }
+ }
+ for (int y = 0; y < height; y++) {
+ int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
+ REPORTER_ASSERT(reporter, !diffs);
+ if (diffs) {
+ break;
+ }
+ }
+}
+
+DEF_TEST(ImageFilterMatrixConvolution, reporter) {
+ // Check that a 1x3 filter does not cause a spurious assert.
+ SkScalar kernel[3] = {
+ SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
+ };
+ SkISize kernelSize = SkISize::Make(1, 3);
+ SkScalar gain = SK_Scalar1, bias = 0;
+ SkIPoint kernelOffset = SkIPoint::Make(0, 0);
+
+ SkAutoTUnref<SkImageFilter> filter(
+ SkMatrixConvolutionImageFilter::Create(
+ kernelSize, kernel, gain, bias, kernelOffset,
+ SkMatrixConvolutionImageFilter::kRepeat_TileMode, false));
+
+ SkBitmap result;
+ int width = 16, height = 16;
+ result.allocN32Pixels(width, height);
+ SkCanvas canvas(result);
+ canvas.clear(0);
+
+ SkPaint paint;
+ paint.setImageFilter(filter);
+ SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
+ canvas.drawRect(rect, paint);
+}
+
+DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
+ // Check that a filter with borders outside the target bounds
+ // does not crash.
+ SkScalar kernel[3] = {
+ 0, 0, 0,
+ };
+ SkISize kernelSize = SkISize::Make(3, 1);
+ SkScalar gain = SK_Scalar1, bias = 0;
+ SkIPoint kernelOffset = SkIPoint::Make(2, 0);
+
+ SkAutoTUnref<SkImageFilter> filter(
+ SkMatrixConvolutionImageFilter::Create(
+ kernelSize, kernel, gain, bias, kernelOffset,
+ SkMatrixConvolutionImageFilter::kClamp_TileMode, true));
+
+ SkBitmap result;
+
+ int width = 10, height = 10;
+ result.allocN32Pixels(width, height);
+ SkCanvas canvas(result);
+ canvas.clear(0);
+
+ SkPaint filterPaint;
+ filterPaint.setImageFilter(filter);
+ SkRect bounds = SkRect::MakeWH(1, 10);
+ SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
+ SkPaint rectPaint;
+ canvas.saveLayer(&bounds, &filterPaint);
+ canvas.drawRect(rect, rectPaint);
+ canvas.restore();
+}
+
+DEF_TEST(ImageFilterCropRect, reporter) {
+ SkBitmap temp;
+ temp.allocN32Pixels(100, 100);
+ SkBitmapDevice device(temp);
+ test_crop_rects(&device, reporter);
+}
+
+DEF_TEST(ImageFilterMatrix, reporter) {
+ SkBitmap temp;
+ temp.allocN32Pixels(100, 100);
+ SkBitmapDevice device(temp);
+ SkCanvas canvas(&device);
+ canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
+
+ SkMatrix expectedMatrix = canvas.getTotalMatrix();
+
+ SkRTreeFactory factory;
+ SkPictureRecorder recorder;
+ SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
+
+ SkPaint paint;
+ SkAutoTUnref<MatrixTestImageFilter> imageFilter(
+ new MatrixTestImageFilter(reporter, expectedMatrix));
+ paint.setImageFilter(imageFilter.get());
+ recordingCanvas->saveLayer(NULL, &paint);
+ SkPaint solidPaint;
+ solidPaint.setColor(0xFFFFFFFF);
+ recordingCanvas->save();
+ recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
+ recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
+ recordingCanvas->restore(); // scale
+ recordingCanvas->restore(); // saveLayer
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ canvas.drawPicture(picture);
+}
+
+DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
+ SkRTreeFactory factory;
+ SkPictureRecorder recorder;
+ SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
+
+ // Create an SkPicture which simply draws a green 1x1 rectangle.
+ SkPaint greenPaint;
+ greenPaint.setColor(SK_ColorGREEN);
+ recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ // Wrap that SkPicture in an SkPictureImageFilter.
+ SkAutoTUnref<SkImageFilter> imageFilter(
+ SkPictureImageFilter::Create(picture.get()));
+
+ // Check that SkPictureImageFilter successfully serializes its contained
+ // SkPicture when not in cross-process mode.
+ SkPaint paint;
+ paint.setImageFilter(imageFilter.get());
+ SkPictureRecorder outerRecorder;
+ SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
+ SkPaint redPaintWithFilter;
+ redPaintWithFilter.setColor(SK_ColorRED);
+ redPaintWithFilter.setImageFilter(imageFilter.get());
+ outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
+ SkAutoTUnref<SkPicture> outerPicture(outerRecorder.endRecording());
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(1, 1);
+ SkBitmapDevice device(bitmap);
+ SkCanvas canvas(&device);
+
+ // The result here should be green, since the filter replaces the primitive's red interior.
+ canvas.clear(0x0);
+ canvas.drawPicture(outerPicture);
+ uint32_t pixel = *bitmap.getAddr32(0, 0);
+ REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
+
+ // Check that, for now, SkPictureImageFilter does not serialize or
+ // deserialize its contained picture when the filter is serialized
+ // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
+ SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
+ SkAutoTUnref<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
+ data->data(), data->size(), SkImageFilter::GetFlattenableType()));
+ SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
+
+ redPaintWithFilter.setImageFilter(unflattenedFilter);
+ SkPictureRecorder crossProcessRecorder;
+ SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
+ crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
+ SkAutoTUnref<SkPicture> crossProcessPicture(crossProcessRecorder.endRecording());
+
+ canvas.clear(0x0);
+ canvas.drawPicture(crossProcessPicture);
+ pixel = *bitmap.getAddr32(0, 0);
+ // The result here should not be green, since the filter draws nothing.
+ REPORTER_ASSERT(reporter, pixel != SK_ColorGREEN);
+}
+
+DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
+ SkRTreeFactory factory;
+ SkPictureRecorder recorder;
+ SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
+
+ // Create an SkPicture which simply draws a green 1x1 rectangle.
+ SkPaint greenPaint;
+ greenPaint.setColor(SK_ColorGREEN);
+ recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ SkAutoTUnref<SkImageFilter> imageFilter(
+ SkPictureImageFilter::Create(picture.get()));
+
+ SkBitmap result;
+ SkIPoint offset;
+ SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), NULL);
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(2, 2);
+ SkBitmapDevice device(bitmap);
+ SkDeviceImageFilterProxy proxy(&device);
+ REPORTER_ASSERT(reporter, !imageFilter->filterImage(&proxy, bitmap, ctx, &result, &offset));
+}
+
+DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
+ // Even when there's an empty saveLayer()/restore(), ensure that an image
+ // filter or color filter which affects transparent black still draws.
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(10, 10);
+ SkBitmapDevice device(bitmap);
+ SkCanvas canvas(&device);
+
+ SkRTreeFactory factory;
+ SkPictureRecorder recorder;
+
+ SkAutoTUnref<SkColorFilter> green(
+ SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
+ SkAutoTUnref<SkColorFilterImageFilter> imageFilter(
+ SkColorFilterImageFilter::Create(green.get()));
+ SkPaint imageFilterPaint;
+ imageFilterPaint.setImageFilter(imageFilter.get());
+ SkPaint colorFilterPaint;
+ colorFilterPaint.setColorFilter(green.get());
+
+ SkRect bounds = SkRect::MakeWH(10, 10);
+
+ SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
+ recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
+ recordingCanvas->restore();
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ canvas.clear(0);
+ canvas.drawPicture(picture);
+ uint32_t pixel = *bitmap.getAddr32(0, 0);
+ REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
+
+ recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
+ recordingCanvas->saveLayer(NULL, &imageFilterPaint);
+ recordingCanvas->restore();
+ SkAutoTUnref<SkPicture> picture2(recorder.endRecording());
+
+ canvas.clear(0);
+ canvas.drawPicture(picture2);
+ pixel = *bitmap.getAddr32(0, 0);
+ REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
+
+ recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
+ recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
+ recordingCanvas->restore();
+ SkAutoTUnref<SkPicture> picture3(recorder.endRecording());
+
+ canvas.clear(0);
+ canvas.drawPicture(picture3);
+ pixel = *bitmap.getAddr32(0, 0);
+ REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
+}
+
+static void test_huge_blur(SkBaseDevice* device, skiatest::Reporter* reporter) {
+ SkCanvas canvas(device);
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(100, 100);
+ bitmap.eraseARGB(0, 0, 0, 0);
+
+ // Check that a blur with an insane radius does not crash or assert.
+ SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30)));
+
+ SkPaint paint;
+ paint.setImageFilter(blur);
+ canvas.drawSprite(bitmap, 0, 0, &paint);
+}
+
+DEF_TEST(HugeBlurImageFilter, reporter) {
+ SkBitmap temp;
+ temp.allocN32Pixels(100, 100);
+ SkBitmapDevice device(temp);
+ test_huge_blur(&device, reporter);
+}
+
+DEF_TEST(MatrixConvolutionSanityTest, reporter) {
+ SkScalar kernel[1] = { 0 };
+ SkScalar gain = SK_Scalar1, bias = 0;
+ SkIPoint kernelOffset = SkIPoint::Make(1, 1);
+
+ // Check that an enormous (non-allocatable) kernel gives a NULL filter.
+ SkAutoTUnref<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Create(
+ SkISize::Make(1<<30, 1<<30),
+ kernel,
+ gain,
+ bias,
+ kernelOffset,
+ SkMatrixConvolutionImageFilter::kRepeat_TileMode,
+ false));
+
+ REPORTER_ASSERT(reporter, NULL == conv.get());
+
+ // Check that a NULL kernel gives a NULL filter.
+ conv.reset(SkMatrixConvolutionImageFilter::Create(
+ SkISize::Make(1, 1),
+ NULL,
+ gain,
+ bias,
+ kernelOffset,
+ SkMatrixConvolutionImageFilter::kRepeat_TileMode,
+ false));
+
+ REPORTER_ASSERT(reporter, NULL == conv.get());
+
+ // Check that a kernel width < 1 gives a NULL filter.
+ conv.reset(SkMatrixConvolutionImageFilter::Create(
+ SkISize::Make(0, 1),
+ kernel,
+ gain,
+ bias,
+ kernelOffset,
+ SkMatrixConvolutionImageFilter::kRepeat_TileMode,
+ false));
+
+ REPORTER_ASSERT(reporter, NULL == conv.get());
+
+ // Check that kernel height < 1 gives a NULL filter.
+ conv.reset(SkMatrixConvolutionImageFilter::Create(
+ SkISize::Make(1, -1),
+ kernel,
+ gain,
+ bias,
+ kernelOffset,
+ SkMatrixConvolutionImageFilter::kRepeat_TileMode,
+ false));
+
+ REPORTER_ASSERT(reporter, NULL == conv.get());
+}
+
+static void test_xfermode_cropped_input(SkBaseDevice* device, skiatest::Reporter* reporter) {
+ SkCanvas canvas(device);
+ canvas.clear(0);
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(1, 1);
+ bitmap.eraseARGB(255, 255, 255, 255);
+
+ SkAutoTUnref<SkColorFilter> green(
+ SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrcIn_Mode));
+ SkAutoTUnref<SkColorFilterImageFilter> greenFilter(
+ SkColorFilterImageFilter::Create(green.get()));
+ SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
+ SkAutoTUnref<SkColorFilterImageFilter> croppedOut(
+ SkColorFilterImageFilter::Create(green.get(), NULL, &cropRect));
+
+ // Check that an xfermode image filter whose input has been cropped out still draws the other
+ // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
+ SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrcOver_Mode);
+ SkAutoTUnref<SkImageFilter> xfermodeNoFg(
+ SkXfermodeImageFilter::Create(mode, greenFilter, croppedOut));
+ SkAutoTUnref<SkImageFilter> xfermodeNoBg(
+ SkXfermodeImageFilter::Create(mode, croppedOut, greenFilter));
+ SkAutoTUnref<SkImageFilter> xfermodeNoFgNoBg(
+ SkXfermodeImageFilter::Create(mode, croppedOut, croppedOut));
+
+ SkPaint paint;
+ paint.setImageFilter(xfermodeNoFg);
+ canvas.drawSprite(bitmap, 0, 0, &paint);
+
+ uint32_t pixel;
+ SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
+ canvas.readPixels(info, &pixel, 4, 0, 0);
+ REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
+
+ paint.setImageFilter(xfermodeNoBg);
+ canvas.drawSprite(bitmap, 0, 0, &paint);
+ canvas.readPixels(info, &pixel, 4, 0, 0);
+ REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
+
+ paint.setImageFilter(xfermodeNoFgNoBg);
+ canvas.drawSprite(bitmap, 0, 0, &paint);
+ canvas.readPixels(info, &pixel, 4, 0, 0);
+ REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
+}
+
+DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
+ SkBitmap temp;
+ temp.allocN32Pixels(50, 50);
+ SkBitmapDevice device(temp);
+ SkCanvas canvas(&device);
+ canvas.clear(0x0);
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(10, 10);
+ bitmap.eraseColor(SK_ColorGREEN);
+
+ SkMatrix matrix;
+ matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
+ matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
+ SkAutoTUnref<SkImageFilter> matrixFilter(
+ SkMatrixImageFilter::Create(matrix, SkPaint::kLow_FilterLevel));
+
+ // Test that saveLayer() with a filter nested inside another saveLayer() applies the
+ // correct offset to the filter matrix.
+ SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
+ canvas.saveLayer(&bounds1, NULL);
+ SkPaint filterPaint;
+ filterPaint.setImageFilter(matrixFilter);
+ SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
+ canvas.saveLayer(&bounds2, &filterPaint);
+ SkPaint greenPaint;
+ greenPaint.setColor(SK_ColorGREEN);
+ canvas.drawRect(bounds2, greenPaint);
+ canvas.restore();
+ canvas.restore();
+ SkPaint strokePaint;
+ strokePaint.setStyle(SkPaint::kStroke_Style);
+ strokePaint.setColor(SK_ColorRED);
+
+ SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
+ uint32_t pixel;
+ canvas.readPixels(info, &pixel, 4, 25, 25);
+ REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
+
+ // Test that drawSprite() with a filter nested inside a saveLayer() applies the
+ // correct offset to the filter matrix.
+ canvas.clear(0x0);
+ canvas.readPixels(info, &pixel, 4, 25, 25);
+ canvas.saveLayer(&bounds1, NULL);
+ canvas.drawSprite(bitmap, 20, 20, &filterPaint);
+ canvas.restore();
+
+ canvas.readPixels(info, &pixel, 4, 25, 25);
+ REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
+}
+
+DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
+ SkBitmap temp;
+ temp.allocN32Pixels(100, 100);
+ SkBitmapDevice device(temp);
+ test_xfermode_cropped_input(&device, reporter);
+}
+
+#if SK_SUPPORT_GPU
+const SkSurfaceProps gProps = SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType);
+
+DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
+ GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
+ SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
+ SkImageInfo::MakeN32Premul(100, 100),
+ gProps,
+ 0));
+ test_crop_rects(device, reporter);
+}
+
+DEF_GPUTEST(HugeBlurImageFilterGPU, reporter, factory) {
+ GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
+ SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
+ SkImageInfo::MakeN32Premul(100, 100),
+ gProps,
+ 0));
+ test_huge_blur(device, reporter);
+}
+
+DEF_GPUTEST(XfermodeImageFilterCroppedInputGPU, reporter, factory) {
+ GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
+ SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
+ SkImageInfo::MakeN32Premul(1, 1),
+ gProps,
+ 0));
+ test_xfermode_cropped_input(device, reporter);
+}
+
+DEF_GPUTEST(TestNegativeBlurSigmaGPU, reporter, factory) {
+ GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
+ SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
+ SkImageInfo::MakeN32Premul(1, 1),
+ gProps,
+ 0));
+ test_negative_blur_sigma(device, reporter);
+}
+#endif
diff --git a/src/third_party/skia/tests/ImageGeneratorTest.cpp b/src/third_party/skia/tests/ImageGeneratorTest.cpp
new file mode 100644
index 0000000..1f960ea
--- /dev/null
+++ b/src/third_party/skia/tests/ImageGeneratorTest.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkImageGenerator.h"
+#include "Test.h"
+
+DEF_TEST(ImageGenerator, reporter) {
+ SkImageGenerator ig;
+ SkISize sizes[3];
+ sizes[0] = SkISize::Make(200, 200);
+ sizes[1] = SkISize::Make(100, 100);
+ sizes[2] = SkISize::Make( 50, 50);
+ void* planes[3] = { NULL };
+ size_t rowBytes[3] = { 0 };
+ SkYUVColorSpace colorSpace;
+
+ // Check that the YUV decoding API does not cause any crashes
+ ig.getYUV8Planes(sizes, NULL, NULL, &colorSpace);
+ ig.getYUV8Planes(sizes, NULL, NULL, NULL);
+ ig.getYUV8Planes(sizes, planes, NULL, NULL);
+ ig.getYUV8Planes(sizes, NULL, rowBytes, NULL);
+ ig.getYUV8Planes(sizes, planes, rowBytes, NULL);
+ ig.getYUV8Planes(sizes, planes, rowBytes, &colorSpace);
+
+ int dummy;
+ planes[0] = planes[1] = planes[2] = &dummy;
+ rowBytes[0] = rowBytes[1] = rowBytes[2] = 250;
+
+ ig.getYUV8Planes(sizes, planes, rowBytes, &colorSpace);
+}
diff --git a/src/third_party/skia/tests/ImageIsOpaqueTest.cpp b/src/third_party/skia/tests/ImageIsOpaqueTest.cpp
new file mode 100644
index 0000000..3fe5b3d
--- /dev/null
+++ b/src/third_party/skia/tests/ImageIsOpaqueTest.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypes.h"
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#endif
+#include "SkImage.h"
+#include "SkSurface.h"
+
+#include "Test.h"
+
+static void check_isopaque(skiatest::Reporter* reporter, SkSurface* surface, bool expectedOpaque) {
+ SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
+ REPORTER_ASSERT(reporter, image->isOpaque() == expectedOpaque);
+}
+
+DEF_TEST(ImageIsOpaqueTest, reporter) {
+ SkImageInfo infoTransparent = SkImageInfo::MakeN32Premul(5, 5);
+ SkAutoTUnref<SkSurface> surfaceTransparent(SkSurface::NewRaster(infoTransparent));
+ check_isopaque(reporter, surfaceTransparent, false);
+
+ SkImageInfo infoOpaque = SkImageInfo::MakeN32(5, 5, kOpaque_SkAlphaType);
+ SkAutoTUnref<SkSurface> surfaceOpaque(SkSurface::NewRaster(infoOpaque));
+ check_isopaque(reporter, surfaceOpaque, true);
+}
+
+#if SK_SUPPORT_GPU
+
+DEF_GPUTEST(ImageIsOpaqueTest_GPU, reporter, factory) {
+ for (int i = 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
+ GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
+
+ if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
+ continue;
+ }
+
+ GrContext* context = factory->get(glCtxType);
+
+ if (NULL == context) {
+ continue;
+ }
+
+ SkImageInfo infoTransparent = SkImageInfo::MakeN32Premul(5, 5);
+ SkAutoTUnref<SkSurface> surfaceTransparent(SkSurface::NewRenderTarget(context, infoTransparent));
+ check_isopaque(reporter, surfaceTransparent, false);
+
+ SkImageInfo infoOpaque = SkImageInfo::MakeN32(5, 5, kOpaque_SkAlphaType);
+ SkAutoTUnref<SkSurface> surfaceOpaque(SkSurface::NewRenderTarget(context, infoOpaque));
+#if 0
+ // this is failing right now : TODO fix me
+ check_isopaque(reporter, surfaceOpaque, true);
+#endif
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/ImageNewShaderTest.cpp b/src/third_party/skia/tests/ImageNewShaderTest.cpp
new file mode 100644
index 0000000..dfc5a24
--- /dev/null
+++ b/src/third_party/skia/tests/ImageNewShaderTest.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypes.h"
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#endif
+#include "SkCanvas.h"
+#include "SkImage.h"
+#include "SkShader.h"
+#include "SkSurface.h"
+
+#include "Test.h"
+
+void testBitmapEquality(skiatest::Reporter* reporter, SkBitmap& bm1, SkBitmap& bm2) {
+ SkAutoLockPixels lockBm1(bm1);
+ SkAutoLockPixels lockBm2(bm2);
+
+ REPORTER_ASSERT(reporter, bm1.getSize() == bm2.getSize());
+ REPORTER_ASSERT(reporter, 0 == memcmp(bm1.getPixels(), bm2.getPixels(), bm1.getSize()));
+}
+
+void paintSource(SkSurface* sourceSurface) {
+ SkCanvas* sourceCanvas = sourceSurface->getCanvas();
+ sourceCanvas->clear(0xFFDEDEDE);
+
+ SkPaint paintColor;
+ paintColor.setColor(0xFFFF0000);
+ paintColor.setStyle(SkPaint::kFill_Style);
+
+ SkRect rect = SkRect::MakeXYWH(
+ SkIntToScalar(1),
+ SkIntToScalar(0),
+ SkIntToScalar(1),
+ SkIntToScalar(sourceSurface->height()));
+
+ sourceCanvas->drawRect(rect, paintColor);
+}
+
+void runShaderTest(skiatest::Reporter* reporter, SkSurface* sourceSurface, SkSurface* destinationSurface, SkImageInfo& info) {
+ paintSource(sourceSurface);
+
+ SkAutoTUnref<SkImage> sourceImage(sourceSurface->newImageSnapshot());
+ SkAutoTUnref<SkShader> sourceShader(sourceImage->newShader(
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode));
+
+ SkPaint paint;
+ paint.setShader(sourceShader);
+
+ SkCanvas* destinationCanvas = destinationSurface->getCanvas();
+ destinationCanvas->clear(SK_ColorTRANSPARENT);
+ destinationCanvas->drawPaint(paint);
+
+ SkIRect rect = SkIRect::MakeWH(info.width(), info.height());
+
+ SkBitmap bmOrig;
+ sourceSurface->getCanvas()->readPixels(rect, &bmOrig);
+
+
+ SkBitmap bm;
+ destinationCanvas->readPixels(rect, &bm);
+
+ testBitmapEquality(reporter, bmOrig, bm);
+
+
+
+ // Test with a translated shader
+ SkMatrix matrix;
+ matrix.setTranslate(SkIntToScalar(-1), SkIntToScalar(0));
+
+ SkAutoTUnref<SkShader> sourceShaderTranslated(sourceImage->newShader(
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode,
+ &matrix));
+
+ destinationCanvas->clear(SK_ColorTRANSPARENT);
+
+ SkPaint paintTranslated;
+ paintTranslated.setShader(sourceShaderTranslated);
+
+ destinationCanvas->drawPaint(paintTranslated);
+
+ SkBitmap bmt;
+ destinationCanvas->readPixels(rect, &bmt);
+
+ // Test correctness
+ {
+ SkAutoLockPixels lockBm(bmt);
+ for (int y = 0; y < info.height(); y++) {
+ REPORTER_ASSERT(reporter, 0xFFFF0000 == bmt.getColor(0, y));
+
+ for (int x = 1; x < info.width(); x++) {
+ REPORTER_ASSERT(reporter, 0xFFDEDEDE == bmt.getColor(x, y));
+ }
+ }
+ }
+}
+
+DEF_TEST(ImageNewShader, reporter) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(5, 5);
+
+ SkAutoTUnref<SkSurface> sourceSurface(SkSurface::NewRaster(info));
+ SkAutoTUnref<SkSurface> destinationSurface(SkSurface::NewRaster(info));
+
+ runShaderTest(reporter, sourceSurface.get(), destinationSurface.get(), info);
+}
+
+#if SK_SUPPORT_GPU
+
+void gpuToGpu(skiatest::Reporter* reporter, GrContext* context) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(5, 5);
+
+ SkAutoTUnref<SkSurface> sourceSurface(SkSurface::NewRenderTarget(context, info));
+ SkAutoTUnref<SkSurface> destinationSurface(SkSurface::NewRenderTarget(context, info));
+
+ runShaderTest(reporter, sourceSurface.get(), destinationSurface.get(), info);
+}
+
+void gpuToRaster(skiatest::Reporter* reporter, GrContext* context) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(5, 5);
+
+ SkAutoTUnref<SkSurface> sourceSurface(SkSurface::NewRenderTarget(context, info));
+ SkAutoTUnref<SkSurface> destinationSurface(SkSurface::NewRaster(info));
+
+ runShaderTest(reporter, sourceSurface.get(), destinationSurface.get(), info);
+}
+
+void rasterToGpu(skiatest::Reporter* reporter, GrContext* context) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(5, 5);
+
+ SkAutoTUnref<SkSurface> sourceSurface(SkSurface::NewRaster(info));
+ SkAutoTUnref<SkSurface> destinationSurface(SkSurface::NewRenderTarget(context, info));
+
+ runShaderTest(reporter, sourceSurface.get(), destinationSurface.get(), info);
+}
+
+DEF_GPUTEST(ImageNewShader_GPU, reporter, factory) {
+ for (int i = 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
+ GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
+
+ if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
+ continue;
+ }
+
+ GrContext* context = factory->get(glCtxType);
+
+ if (NULL == context) {
+ continue;
+ }
+
+ // GPU -> GPU
+ gpuToGpu(reporter, context);
+
+ // GPU -> RASTER
+ gpuToRaster(reporter, context);
+
+ // RASTER -> GPU
+ rasterToGpu(reporter, context);
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/InfRectTest.cpp b/src/third_party/skia/tests/InfRectTest.cpp
new file mode 100644
index 0000000..3da0e5e
--- /dev/null
+++ b/src/third_party/skia/tests/InfRectTest.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRandom.h"
+#include "SkRect.h"
+#include "Test.h"
+
+static float make_zero() {
+ return sk_float_sin(0);
+}
+
+struct RectCenter {
+ SkIRect fRect;
+ SkIPoint fCenter;
+};
+
+static void test_center(skiatest::Reporter* reporter) {
+ static const RectCenter gData[] = {
+ { { 0, 0, 0, 0 }, { 0, 0 } },
+ { { 0, 0, 1, 1 }, { 0, 0 } },
+ { { -1, -1, 0, 0 }, { -1, -1 } },
+ { { 0, 0, 10, 7 }, { 5, 3 } },
+ { { 0, 0, 11, 6 }, { 5, 3 } },
+ };
+ for (size_t index = 0; index < SK_ARRAY_COUNT(gData); ++index) {
+ REPORTER_ASSERT(reporter,
+ gData[index].fRect.centerX() == gData[index].fCenter.x());
+ REPORTER_ASSERT(reporter,
+ gData[index].fRect.centerY() == gData[index].fCenter.y());
+ }
+
+ SkRandom rand;
+ for (int i = 0; i < 10000; ++i) {
+ SkIRect r;
+
+ r.set(rand.nextS() >> 2, rand.nextS() >> 2,
+ rand.nextS() >> 2, rand.nextS() >> 2);
+ int cx = r.centerX();
+ int cy = r.centerY();
+ REPORTER_ASSERT(reporter, ((r.left() + r.right()) >> 1) == cx);
+ REPORTER_ASSERT(reporter, ((r.top() + r.bottom()) >> 1) == cy);
+ }
+}
+
+static void check_invalid(skiatest::Reporter* reporter,
+ SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
+ SkRect rect;
+ rect.set(l, t, r, b);
+ REPORTER_ASSERT(reporter, !rect.isFinite());
+}
+
+// Tests that isFinite() will reject any rect with +/-inf values
+// as one of its coordinates.
+DEF_TEST(InfRect, reporter) {
+ float inf = 1 / make_zero(); // infinity
+ float nan = inf * 0;
+ SkASSERT(!(nan == nan));
+ SkScalar small = SkIntToScalar(10);
+ SkScalar big = SkIntToScalar(100);
+
+ REPORTER_ASSERT(reporter, SkRect::MakeEmpty().isFinite());
+
+ SkRect rect = SkRect::MakeXYWH(small, small, big, big);
+ REPORTER_ASSERT(reporter, rect.isFinite());
+
+ const SkScalar invalid[] = { nan, inf, -inf };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(invalid); ++i) {
+ check_invalid(reporter, small, small, big, invalid[i]);
+ check_invalid(reporter, small, small, invalid[i], big);
+ check_invalid(reporter, small, invalid[i], big, big);
+ check_invalid(reporter, invalid[i], small, big, big);
+ }
+
+ test_center(reporter);
+}
+
+// need tests for SkStrSearch
diff --git a/src/third_party/skia/tests/InterpolatorTest.cpp b/src/third_party/skia/tests/InterpolatorTest.cpp
new file mode 100644
index 0000000..3cfd19f
--- /dev/null
+++ b/src/third_party/skia/tests/InterpolatorTest.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkInterpolator.h"
+
+#include "Test.h"
+
+static SkScalar* iset(SkScalar array[3], int a, int b, int c) {
+ array[0] = SkIntToScalar(a);
+ array[1] = SkIntToScalar(b);
+ array[2] = SkIntToScalar(c);
+ return array;
+}
+
+DEF_TEST(Interpolator, reporter) {
+ SkInterpolator inter(3, 2);
+ SkScalar v1[3], v2[3], v[3];
+ SkInterpolator::Result result;
+
+ inter.setKeyFrame(0, 100, iset(v1, 10, 20, 30), 0);
+ inter.setKeyFrame(1, 200, iset(v2, 110, 220, 330));
+
+ result = inter.timeToValues(0, v);
+ REPORTER_ASSERT(reporter, result == SkInterpolator::kFreezeStart_Result);
+ REPORTER_ASSERT(reporter, memcmp(v, v1, sizeof(v)) == 0);
+
+ result = inter.timeToValues(99, v);
+ REPORTER_ASSERT(reporter, result == SkInterpolator::kFreezeStart_Result);
+ REPORTER_ASSERT(reporter, memcmp(v, v1, sizeof(v)) == 0);
+
+ result = inter.timeToValues(100, v);
+ REPORTER_ASSERT(reporter, result == SkInterpolator::kNormal_Result);
+ REPORTER_ASSERT(reporter, memcmp(v, v1, sizeof(v)) == 0);
+
+ result = inter.timeToValues(200, v);
+ REPORTER_ASSERT(reporter, result == SkInterpolator::kNormal_Result);
+ REPORTER_ASSERT(reporter, memcmp(v, v2, sizeof(v)) == 0);
+
+ result = inter.timeToValues(201, v);
+ REPORTER_ASSERT(reporter, result == SkInterpolator::kFreezeEnd_Result);
+ REPORTER_ASSERT(reporter, memcmp(v, v2, sizeof(v)) == 0);
+
+ result = inter.timeToValues(150, v);
+ REPORTER_ASSERT(reporter, result == SkInterpolator::kNormal_Result);
+
+// Found failing when we re-enabled this test:
+#if 0
+ SkScalar vv[3];
+ REPORTER_ASSERT(reporter, memcmp(v, iset(vv, 60, 120, 180), sizeof(v)) == 0);
+#endif
+
+ result = inter.timeToValues(125, v);
+ REPORTER_ASSERT(reporter, result == SkInterpolator::kNormal_Result);
+ result = inter.timeToValues(175, v);
+ REPORTER_ASSERT(reporter, result == SkInterpolator::kNormal_Result);
+
+}
diff --git a/src/third_party/skia/tests/JpegTest.cpp b/src/third_party/skia/tests/JpegTest.cpp
new file mode 100644
index 0000000..f8784a2
--- /dev/null
+++ b/src/third_party/skia/tests/JpegTest.cpp
@@ -0,0 +1,454 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkData.h"
+#include "SkForceLinking.h"
+#include "SkImage.h"
+#include "SkImageDecoder.h"
+#include "SkStream.h"
+#include "Test.h"
+
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
+#define JPEG_TEST_WRITE_TO_FILE_FOR_DEBUGGING 0 // do not do this for
+ // normal unit testing.
+static unsigned char goodJpegImage[] = {
+0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46,
+0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x8F,
+0x00, 0x8F, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43,
+0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05,
+0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07,
+0x0C, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B,
+0x0B, 0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11,
+0x0F, 0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13,
+0x14, 0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18,
+0x1A, 0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17,
+0x22, 0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F,
+0x1E, 0xFF, 0xDB, 0x00, 0x43, 0x01, 0x05, 0x05,
+0x05, 0x07, 0x06, 0x07, 0x0E, 0x08, 0x08, 0x0E,
+0x1E, 0x14, 0x11, 0x14, 0x1E, 0x1E, 0x1E, 0x1E,
+0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
+0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
+0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
+0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
+0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
+0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0xFF, 0xC0,
+0x00, 0x11, 0x08, 0x00, 0x80, 0x00, 0x80, 0x03,
+0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11,
+0x01, 0xFF, 0xC4, 0x00, 0x18, 0x00, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
+0x08, 0x06, 0x05, 0xFF, 0xC4, 0x00, 0x4C, 0x10,
+0x00, 0x00, 0x01, 0x07, 0x08, 0x05, 0x08, 0x05,
+0x0A, 0x03, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x11,
+0x05, 0x08, 0x12, 0x13, 0x14, 0x15, 0x38, 0xB4,
+0x16, 0x17, 0x21, 0x31, 0x84, 0x18, 0x22, 0x23,
+0x24, 0x58, 0xA5, 0xA6, 0xD2, 0x32, 0x51, 0x56,
+0x61, 0xD3, 0x28, 0x33, 0x41, 0x48, 0x67, 0x85,
+0x86, 0xC3, 0xE4, 0xF0, 0x25, 0x49, 0x55, 0x09,
+0x34, 0x35, 0x36, 0x53, 0x68, 0x72, 0x81, 0xA7,
+0xE2, 0xFF, 0xC4, 0x00, 0x14, 0x01, 0x01, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+0xC4, 0x00, 0x14, 0x11, 0x01, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xDA, 0x00,
+0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11,
+0x00, 0x3F, 0x00, 0xD9, 0x62, 0x10, 0x80, 0x40,
+0x65, 0xED, 0x62, 0x75, 0xC8, 0x7D, 0xFF, 0x00,
+0x92, 0x30, 0x33, 0x01, 0x97, 0xB5, 0x89, 0xD7,
+0x21, 0xF7, 0xFE, 0x48, 0xC0, 0x0C, 0xC2, 0x10,
+0x80, 0x40, 0x66, 0x64, 0xB8, 0x62, 0x64, 0x78,
+0xDC, 0xEA, 0x70, 0xCC, 0x06, 0x66, 0x4B, 0x86,
+0x26, 0x47, 0x8D, 0xCE, 0xA7, 0x00, 0xCC, 0x21,
+0x08, 0x04, 0x31, 0x9F, 0xF2, 0xC5, 0xFD, 0xFF,
+0x00, 0x5A, 0x1B, 0x30, 0x63, 0x3F, 0xE5, 0x8B,
+0xFB, 0xFE, 0xB4, 0x03, 0x66, 0x01, 0x99, 0x92,
+0xE1, 0x89, 0x91, 0xE3, 0x73, 0xA9, 0xC3, 0x30,
+0x19, 0x99, 0x2E, 0x18, 0x99, 0x1E, 0x37, 0x3A,
+0x9C, 0x03, 0x30, 0x84, 0x33, 0x33, 0x92, 0x55,
+0x7E, 0xCF, 0x29, 0xD8, 0x49, 0x0D, 0xAE, 0xBD,
+0xAE, 0xAB, 0xC6, 0xBB, 0xAA, 0x68, 0x92, 0x92,
+0x6A, 0xBA, 0xB4, 0xE9, 0x11, 0x7A, 0x7C, 0xD8,
+0xC6, 0x84, 0x77, 0x12, 0x11, 0x87, 0xBC, 0x07,
+0x67, 0xAC, 0x47, 0xED, 0xD9, 0xD3, 0xC6, 0xAA,
+0x5E, 0x51, 0x6B, 0x11, 0xFB, 0x76, 0x74, 0xF1,
+0xAA, 0x97, 0x94, 0x33, 0x08, 0x00, 0xCE, 0xB1,
+0x1F, 0xB7, 0x67, 0x4F, 0x1A, 0xA9, 0x79, 0x41,
+0x9B, 0xC4, 0x6C, 0xDE, 0xC2, 0xCB, 0xF6, 0x75,
+0x92, 0x84, 0xA0, 0xE5, 0xEC, 0x12, 0xB2, 0x9D,
+0xEF, 0x76, 0xC9, 0xBA, 0x50, 0xAA, 0x92, 0xF1,
+0xA6, 0xAA, 0x69, 0x12, 0xF4, 0xA4, 0x36, 0x8A,
+0x2A, 0xB3, 0x60, 0x77, 0x3A, 0x34, 0xA3, 0x02,
+0x6D, 0x1A, 0xC8, 0x0C, 0xBD, 0xAC, 0x4E, 0xB9,
+0x0F, 0xBF, 0xF2, 0x46, 0x00, 0xB5, 0x88, 0xFD,
+0xBB, 0x3A, 0x78, 0xD5, 0x4B, 0xCA, 0x2D, 0x62,
+0x3F, 0x6E, 0xCE, 0x9E, 0x35, 0x52, 0xF2, 0x86,
+0x61, 0x00, 0x19, 0xD6, 0x23, 0xF6, 0xEC, 0xE9,
+0xE3, 0x55, 0x2F, 0x28, 0x33, 0x9A, 0xE3, 0x66,
+0xF6, 0x24, 0x97, 0x12, 0xCE, 0xC9, 0xEC, 0xCB,
+0x97, 0xD2, 0x49, 0x25, 0x15, 0xAA, 0xCF, 0x29,
+0x69, 0x42, 0xAA, 0xA5, 0x7C, 0x56, 0x92, 0x94,
+0xEE, 0x88, 0xF3, 0x4A, 0x71, 0xB4, 0x4E, 0x29,
+0xC6, 0xED, 0xDF, 0x46, 0x3B, 0x8A, 0x35, 0x90,
+0x19, 0x99, 0x2E, 0x18, 0x99, 0x1E, 0x37, 0x3A,
+0x9C, 0x01, 0x9B, 0xE4, 0x79, 0x73, 0x93, 0x59,
+0x69, 0xD9, 0x36, 0x65, 0x99, 0x62, 0x34, 0x1E,
+0x56, 0x95, 0xAD, 0x96, 0x75, 0x7B, 0xD6, 0x4F,
+0x94, 0x6F, 0x1A, 0xA3, 0x0C, 0x3C, 0xEE, 0x71,
+0xE6, 0x51, 0x45, 0x56, 0x6D, 0x22, 0xED, 0x29,
+0x29, 0x53, 0xFA, 0x4A, 0x41, 0xE2, 0xFC, 0xBB,
+0x3F, 0x77, 0x28, 0x66, 0x7B, 0x58, 0x9D, 0x72,
+0x1F, 0x7F, 0xE4, 0x8C, 0x0C, 0xC0, 0x31, 0x9F,
+0xCB, 0xB3, 0xF7, 0x72, 0x8F, 0x19, 0xB6, 0x76,
+0x8F, 0x61, 0x8B, 0x99, 0xDA, 0xDA, 0x16, 0x99,
+0xB7, 0xB0, 0x49, 0x2A, 0x74, 0x2D, 0x0C, 0x9D,
+0xD4, 0xAA, 0x92, 0x85, 0x39, 0x40, 0xD2, 0x9B,
+0xD7, 0x0C, 0x3C, 0xA7, 0x16, 0x27, 0x1C, 0x6A,
+0x5D, 0x91, 0xDF, 0x43, 0x70, 0xDC, 0xA2, 0x01,
+0x8C, 0xF5, 0xC1, 0xFE, 0xF1, 0x3F, 0xF3, 0x4F,
+0xFE, 0x07, 0xB5, 0x35, 0xC6, 0x31, 0xEC, 0x4A,
+0xCE, 0x25, 0x9D, 0x94, 0x19, 0x97, 0xD1, 0xA3,
+0x72, 0x4A, 0x5B, 0x55, 0x9E, 0x4D, 0xD1, 0x75,
+0x55, 0xBA, 0x88, 0x2D, 0x25, 0x21, 0xDD, 0x29,
+0xE7, 0x10, 0xE3, 0xA9, 0x1C, 0x43, 0x8E, 0xDB,
+0xBA, 0x94, 0x37, 0x10, 0x6B, 0x21, 0x00, 0x19,
+0xD5, 0xDB, 0xF6, 0xED, 0x17, 0xE0, 0xA5, 0x2F,
+0x30, 0x33, 0x9A, 0xE3, 0x18, 0xF6, 0x25, 0x67,
+0x12, 0xCE, 0xCA, 0x0C, 0xCB, 0xE8, 0xD1, 0xB9,
+0x25, 0x2D, 0xAA, 0xCF, 0x26, 0xE8, 0xBA, 0xAA,
+0xDD, 0x44, 0x16, 0x92, 0x90, 0xEE, 0x94, 0xF3,
+0x88, 0x71, 0xD4, 0x8E, 0x21, 0xC7, 0x6D, 0xDD,
+0x4A, 0x1B, 0x88, 0x35, 0x90, 0x19, 0x99, 0x2E,
+0x18, 0x99, 0x1E, 0x37, 0x3A, 0x9C, 0x03, 0x30,
+0x80, 0x04, 0xDB, 0x99, 0x69, 0x09, 0x8B, 0x7E,
+0xCF, 0x8D, 0x99, 0x66, 0x54, 0x6C, 0x12, 0x4A,
+0x9D, 0xC7, 0x67, 0x57, 0xAD, 0x3D, 0x25, 0x0A,
+0x6A, 0xA9, 0x4F, 0x3B, 0x9C, 0x79, 0x4A, 0x71,
+0x62, 0x71, 0xC7, 0x17, 0x69, 0x4B, 0xBF, 0xD4,
+0x1F, 0xC0, 0x43, 0x8C, 0x79, 0xAE, 0xB5, 0x84,
+0x79, 0x57, 0x7E, 0x9A, 0xC8, 0x57, 0xAD, 0xDD,
+0x5B, 0x64, 0xEB, 0x69, 0xD0, 0xD5, 0xD6, 0x50,
+0xA7, 0xF3, 0x47, 0x9B, 0x18, 0xD0, 0x33, 0x7C,
+0x61, 0x0D, 0x9F, 0x48, 0xEC, 0xC0, 0x03, 0x12,
+0xFB, 0x5E, 0xC3, 0x68, 0xCC, 0x2A, 0x34, 0xCC,
+0xCB, 0x83, 0xB7, 0xC9, 0x2B, 0x94, 0xEC, 0xEB,
+0x1A, 0x5E, 0xAA, 0x8E, 0x9D, 0x03, 0xCE, 0x30,
+0xEE, 0x69, 0xE8, 0xC8, 0x71, 0x20, 0x71, 0xA7,
+0x13, 0x69, 0x09, 0xBB, 0xD4, 0x03, 0xD9, 0xE4,
+0xB8, 0xE2, 0x7D, 0x86, 0xEF, 0x65, 0xDF, 0x8C,
+0x2E, 0x4B, 0x8E, 0x27, 0xD8, 0x6E, 0xF6, 0x5D,
+0xF8, 0xC2, 0xD6, 0x23, 0xF6, 0xEC, 0xE9, 0xE3,
+0x55, 0x2F, 0x28, 0xB5, 0x88, 0xFD, 0xBB, 0x3A,
+0x78, 0xD5, 0x4B, 0xCA, 0x02, 0xE4, 0xB8, 0xE2,
+0x7D, 0x86, 0xEF, 0x65, 0xDF, 0x8C, 0x0C, 0xE6,
+0xB8, 0xE1, 0x1D, 0x3B, 0x68, 0xE2, 0x59, 0xD6,
+0x99, 0xA6, 0x65, 0x2D, 0xF2, 0xB2, 0xE5, 0xAA,
+0xD0, 0xB1, 0x78, 0x2D, 0x23, 0xA7, 0x41, 0x69,
+0x29, 0x86, 0xF3, 0x4C, 0x48, 0x43, 0x49, 0x03,
+0x4D, 0x34, 0x9B, 0x08, 0x4D, 0xDE, 0xB0, 0x99,
+0xAC, 0x47, 0xED, 0xD9, 0xD3, 0xC6, 0xAA, 0x5E,
+0x50, 0x67, 0x35, 0xC6, 0xCD, 0xEC, 0x49, 0x2E,
+0x25, 0x9D, 0x93, 0xD9, 0x97, 0x2F, 0xA4, 0x92,
+0x4A, 0x2B, 0x55, 0x9E, 0x52, 0xD2, 0x85, 0x55,
+0x4A, 0xF8, 0xAD, 0x25, 0x29, 0xDD, 0x11, 0xE6,
+0x94, 0xE3, 0x68, 0x9C, 0x53, 0x8D, 0xDB, 0xBE,
+0x8C, 0x77, 0x14, 0x04, 0xF1, 0x1C, 0x23, 0xA7,
+0x92, 0x5F, 0xB3, 0xAC, 0x66, 0x64, 0xF6, 0x52,
+0xA6, 0x49, 0x97, 0xAF, 0x7B, 0xC9, 0x5E, 0xF0,
+0x5A, 0x3A, 0xBE, 0xA1, 0x54, 0xD3, 0xD1, 0x73,
+0x8A, 0x90, 0xA7, 0x1B, 0x44, 0xE2, 0x94, 0xBC,
+0xD2, 0x92, 0x3F, 0x4C, 0x48, 0x13, 0x39, 0x2E,
+0x38, 0x9F, 0x61, 0xBB, 0xD9, 0x77, 0xE3, 0x01,
+0x97, 0xF4, 0xF7, 0x1B, 0xB6, 0x51, 0xE7, 0xBB,
+0x76, 0xD5, 0xB5, 0x74, 0xB7, 0x15, 0xCD, 0x7A,
+0x59, 0x15, 0x34, 0x89, 0x02, 0xCD, 0xBA, 0xB9,
+0x02, 0x34, 0x47, 0xF3, 0xD1, 0x18, 0x5A, 0xBA,
+0x14, 0x8C, 0x2E, 0xD2, 0x16, 0x95, 0x28, 0x12,
+0x10, 0x29, 0x46, 0xCC, 0x00, 0x33, 0xC9, 0x71,
+0xC4, 0xFB, 0x0D, 0xDE, 0xCB, 0xBF, 0x18, 0x5C,
+0x97, 0x1C, 0x4F, 0xB0, 0xDD, 0xEC, 0xBB, 0xF1,
+0x83, 0x30, 0x80, 0x0C, 0xF2, 0x5C, 0x71, 0x3E,
+0xC3, 0x77, 0xB2, 0xEF, 0xC6, 0x17, 0x25, 0xC7,
+0x13, 0xEC, 0x37, 0x7B, 0x2E, 0xFC, 0x60, 0xCC,
+0x20, 0x03, 0x3C, 0x97, 0x1C, 0x4F, 0xB0, 0xDD,
+0xEC, 0xBB, 0xF1, 0x81, 0x9C, 0xD7, 0x1C, 0x23,
+0xA7, 0x6D, 0x1C, 0x4B, 0x3A, 0xD3, 0x34, 0xCC,
+0xA5, 0xBE, 0x56, 0x5C, 0xB5, 0x5A, 0x16, 0x2F,
+0x05, 0xA4, 0x74, 0xE8, 0x2D, 0x25, 0x30, 0xDE,
+0x69, 0x89, 0x08, 0x69, 0x20, 0x69, 0xA6, 0x93,
+0x61, 0x09, 0xBB, 0xD6, 0x35, 0x90, 0x19, 0x99,
+0x2E, 0x18, 0x99, 0x1E, 0x37, 0x3A, 0x9C, 0x07,
+0x8D, 0x36, 0xE6, 0xA6, 0x42, 0x6D, 0x1F, 0xB3,
+0xE3, 0x69, 0x99, 0x95, 0xEB, 0x7C, 0x92, 0xB9,
+0x71, 0xD9, 0xD6, 0x2A, 0x8F, 0x47, 0x4E, 0x82,
+0xAA, 0x53, 0x0E, 0xE6, 0x9E, 0x42, 0x1C, 0x48,
+0x1C, 0x69, 0xC4, 0xDA, 0x42, 0x6E, 0xF5, 0x07,
+0xF1, 0x08, 0x00, 0xCB, 0x40, 0xF7, 0x1B, 0xBD,
+0x67, 0xB4, 0xEC, 0x53, 0x14, 0xE9, 0x74, 0xAB,
+0x47, 0x2C, 0x96, 0xB5, 0xBD, 0x22, 0x40, 0xA5,
+0xFD, 0xE1, 0x01, 0x12, 0x99, 0xCC, 0x4A, 0x67,
+0xFC, 0xC9, 0xB0, 0xA5, 0xF4, 0x62, 0x58, 0x44,
+0x84, 0x06, 0x73, 0x5C, 0x6C, 0xDE, 0xC4, 0x92,
+0xE2, 0x59, 0xD9, 0x3D, 0x99, 0x72, 0xFA, 0x49,
+0x24, 0xA2, 0xB5, 0x59, 0xE5, 0x2D, 0x28, 0x55,
+0x54, 0xAF, 0x8A, 0xD2, 0x52, 0x9D, 0xD1, 0x1E,
+0x69, 0x4E, 0x36, 0x89, 0xC5, 0x38, 0xDD, 0xBB,
+0xE8, 0xC7, 0x71, 0x42, 0x63, 0xA5, 0xC4, 0xEB,
+0xEF, 0xFB, 0x83, 0x24, 0x78, 0xA6, 0x4B, 0x86,
+0x26, 0x47, 0x8D, 0xCE, 0xA7, 0x01, 0x6B, 0x11,
+0xFB, 0x76, 0x74, 0xF1, 0xAA, 0x97, 0x94, 0x5A,
+0xC4, 0x7E, 0xDD, 0x9D, 0x3C, 0x6A, 0xA5, 0xE5,
+0x0C, 0xC2, 0x00, 0x33, 0xAC, 0x47, 0xED, 0xD9,
+0xD3, 0xC6, 0xAA, 0x5E, 0x50, 0x67, 0x35, 0xC6,
+0xCD, 0xEC, 0x49, 0x2E, 0x25, 0x9D, 0x93, 0xD9,
+0x97, 0x2F, 0xA4, 0x92, 0x4A, 0x2B, 0x55, 0x9E,
+0x52, 0xD2, 0x85, 0x55, 0x4A, 0xF8, 0xAD, 0x25,
+0x29, 0xDD, 0x11, 0xE6, 0x94, 0xE3, 0x68, 0x9C,
+0x53, 0x8D, 0xDB, 0xBE, 0x8C, 0x77, 0x14, 0x6B,
+0x20, 0x33, 0x32, 0x5C, 0x31, 0x32, 0x3C, 0x6E,
+0x75, 0x38, 0x0C, 0xCD, 0x3E, 0x76, 0x89, 0xBB,
+0x97, 0xF4, 0x3B, 0x4D, 0x5D, 0xD6, 0x86, 0xD4,
+0x5B, 0xAC, 0x9F, 0xC6, 0x90, 0x2F, 0xDA, 0xA9,
+0x59, 0xE9, 0xFC, 0xD1, 0x09, 0x42, 0x8C, 0x0C,
+0xDF, 0xBE, 0x9E, 0xCD, 0xC5, 0x1A, 0x67, 0x58,
+0x8F, 0xDB, 0xB3, 0xA7, 0x8D, 0x54, 0xBC, 0xA3,
+0x8C, 0xFE, 0xD0, 0x76, 0x16, 0xFF, 0x00, 0x76,
+0x0A, 0xAD, 0xAD, 0xE9, 0x66, 0xD1, 0x5A, 0x7D,
+0x52, 0xCF, 0x4E, 0xD5, 0x6A, 0x4E, 0xAC, 0x8B,
+0xD3, 0xA4, 0x4A, 0x14, 0x61, 0x1D, 0xC7, 0x47,
+0x76, 0xCD, 0xE2, 0x7D, 0xAA, 0xAF, 0xD9, 0xDA,
+0xBB, 0x09, 0x5D, 0xB5, 0xD7, 0xB5, 0xEB, 0x77,
+0x54, 0xF5, 0x4D, 0x12, 0x52, 0x43, 0x59, 0x58,
+0x9D, 0x1A, 0x2F, 0x4F, 0x9D, 0x08, 0x53, 0x8E,
+0xE2, 0xC6, 0x10, 0xF7, 0x80, 0xEC, 0xF5, 0x88,
+0xFD, 0xBB, 0x3A, 0x78, 0xD5, 0x4B, 0xCA, 0x2D,
+0x62, 0x3F, 0x6E, 0xCE, 0x9E, 0x35, 0x52, 0xF2,
+0x8C, 0x67, 0xCA, 0x8D, 0xFB, 0x7B, 0x73, 0xDD,
+0x2A, 0x5F, 0x04, 0x5C, 0xA8, 0xDF, 0xB7, 0xB7,
+0x3D, 0xD2, 0xA5, 0xF0, 0x40, 0x6C, 0xCD, 0x62,
+0x3F, 0x6E, 0xCE, 0x9E, 0x35, 0x52, 0xF2, 0x8B,
+0x58, 0x8F, 0xDB, 0xB3, 0xA7, 0x8D, 0x54, 0xBC,
+0xA3, 0x33, 0x3B, 0x27, 0xA5, 0x3B, 0x17, 0x95,
+0x78, 0x68, 0x54, 0xBB, 0x7A, 0xDD, 0xD5, 0x56,
+0xBE, 0xA9, 0x25, 0xA1, 0xAB, 0xAC, 0xA7, 0x43,
+0xE7, 0x4C, 0x36, 0x31, 0xA0, 0x7E, 0xE8, 0xC2,
+0x1B, 0x7E, 0x81, 0xD9, 0xFC, 0xBB, 0x3F, 0x77,
+0x28, 0x06, 0x6D, 0x62, 0x3F, 0x6E, 0xCE, 0x9E,
+0x35, 0x52, 0xF2, 0x83, 0x39, 0xAE, 0x36, 0x6F,
+0x62, 0x49, 0x71, 0x2C, 0xEC, 0x9E, 0xCC, 0xB9,
+0x7D, 0x24, 0x92, 0x51, 0x5A, 0xAC, 0xF2, 0x96,
+0x94, 0x2A, 0xAA, 0x57, 0xC5, 0x69, 0x29, 0x4E,
+0xE8, 0x8F, 0x34, 0xA7, 0x1B, 0x44, 0xE2, 0x9C,
+0x6E, 0xDD, 0xF4, 0x63, 0xB8, 0xA3, 0xC5, 0xF9,
+0x76, 0x7E, 0xEE, 0x51, 0xC6, 0x39, 0x2E, 0x56,
+0x3A, 0xB0, 0x92, 0x35, 0x69, 0xFE, 0x53, 0xE9,
+0xAC, 0x1F, 0xE1, 0x7F, 0xEB, 0xA4, 0xAC, 0xF9,
+0xFE, 0x93, 0xE7, 0x2B, 0x3D, 0x2F, 0xFA, 0xD9,
+0x00, 0x1B, 0xFC, 0x42, 0x10, 0x0C, 0x9A, 0xD4,
+0xBE, 0x39, 0x09, 0xCF, 0xBF, 0x67, 0xD5, 0x28,
+0x4A, 0x08, 0x6D, 0xF2, 0xB2, 0xE5, 0xC3, 0x76,
+0xC9, 0xB4, 0x8F, 0x47, 0x6B, 0xA0, 0xAA, 0x42,
+0x25, 0xE9, 0x48, 0x8C, 0xF3, 0x4C, 0xA0, 0x6A,
+0x42, 0x1D, 0xCE, 0x84, 0x61, 0x02, 0x6D, 0xDC,
+0x64, 0xE4, 0xA7, 0x5B, 0xAB, 0x57, 0x61, 0x24,
+0x31, 0x5A, 0x05, 0x7A, 0xDD, 0xD5, 0xDD, 0x6E,
+0xF7, 0xA9, 0xAC, 0xAC, 0x4E, 0x91, 0x2F, 0xA1,
+0x52, 0x74, 0x21, 0x4E, 0x1B, 0xCB, 0x18, 0x47,
+0xDC, 0x34, 0xCC, 0xF6, 0xB0, 0xC4, 0xD7, 0x70,
+0x59, 0xD4, 0x02, 0x99, 0x2E, 0x18, 0x99, 0x1E,
+0x37, 0x3A, 0x9C, 0x00, 0xCF, 0x2E, 0x7F, 0xB2,
+0xEE, 0xFF, 0x00, 0xFD, 0x38, 0xB9, 0x73, 0xFD,
+0x97, 0x77, 0xFF, 0x00, 0xE9, 0xC6, 0xCC, 0x10,
+0x0C, 0x67, 0xCB, 0x9F, 0xEC, 0xBB, 0xBF, 0xFF,
+0x00, 0x4E, 0x38, 0xC7, 0x25, 0x3A, 0xDD, 0x5A,
+0xBB, 0x09, 0x21, 0x8A, 0xD0, 0x2B, 0xD6, 0xEE,
+0xAE, 0xEB, 0x77, 0xBD, 0x4D, 0x65, 0x62, 0x74,
+0x89, 0x7D, 0x0A, 0x93, 0xA1, 0x0A, 0x70, 0xDE,
+0x58, 0xC2, 0x3E, 0xE1, 0xBF, 0xC0, 0xCC, 0xC9,
+0x70, 0xC4, 0xC8, 0xF1, 0xB9, 0xD4, 0xE0, 0x33,
+0x33, 0xED, 0x9D, 0x6E, 0xB2, 0x9D, 0x84, 0xAE,
+0xC5, 0x68, 0x15, 0xD5, 0x78, 0xD4, 0xF5, 0xBB,
+0xDE, 0xBA, 0xAE, 0xAD, 0x3A, 0x34, 0xBE, 0x85,
+0x49, 0xB1, 0x8D, 0x08, 0x6F, 0x24, 0x23, 0x1F,
+0x70, 0x9F, 0x6C, 0xEB, 0x75, 0x94, 0xEC, 0x25,
+0x76, 0x2B, 0x40, 0xAE, 0xAB, 0xC6, 0xA7, 0xAD,
+0xDE, 0xF5, 0xD5, 0x75, 0x69, 0xD1, 0xA5, 0xF4,
+0x2A, 0x4D, 0x8C, 0x68, 0x43, 0x79, 0x21, 0x18,
+0xFB, 0x86, 0x99, 0x9E, 0xD6, 0x18, 0x9A, 0xEE,
+0x0B, 0x3A, 0x80, 0x53, 0xDA, 0xC3, 0x13, 0x5D,
+0xC1, 0x67, 0x50, 0x00, 0xCC, 0xCE, 0x4A, 0x75,
+0xBA, 0xB5, 0x76, 0x12, 0x43, 0x15, 0xA0, 0x57,
+0xAD, 0xDD, 0x5D, 0xD6, 0xEF, 0x7A, 0x9A, 0xCA,
+0xC4, 0xE9, 0x12, 0xFA, 0x15, 0x27, 0x42, 0x14,
+0xE1, 0xBC, 0xB1, 0x84, 0x7D, 0xC3, 0xB3, 0xE5,
+0xCF, 0xF6, 0x5D, 0xDF, 0xFF, 0x00, 0xA7, 0x0C,
+0xD3, 0x25, 0xC3, 0x13, 0x23, 0xC6, 0xE7, 0x53,
+0x86, 0x60, 0x18, 0x01, 0x92, 0x9D, 0x6D, 0xC0,
+0xF3, 0xDB, 0x76, 0xD7, 0x40, 0xAD, 0x3A, 0x55,
+0x60, 0xEA, 0x97, 0xBD, 0x0B, 0x2D, 0x95, 0x01,
+0x51, 0x7A, 0x75, 0x25, 0xA7, 0x4A, 0x31, 0xDC,
+0x6C, 0x37, 0x6D, 0xDE, 0x3B, 0x3E, 0x5C, 0xFF,
+0x00, 0x65, 0xDD, 0xFF, 0x00, 0xFA, 0x70, 0xCC,
+0xE9, 0x71, 0x3A, 0xFB, 0xFE, 0xE0, 0xC9, 0x1E,
+0x19, 0x80, 0x63, 0x3E, 0x5C, 0xFF, 0x00, 0x65,
+0xDD, 0xFF, 0x00, 0xFA, 0x71, 0xC6, 0x39, 0x29,
+0xD6, 0xEA, 0xD5, 0xD8, 0x49, 0x0C, 0x56, 0x81,
+0x5E, 0xB7, 0x75, 0x77, 0x5B, 0xBD, 0xEA, 0x6B,
+0x2B, 0x13, 0xA4, 0x4B, 0xE8, 0x54, 0x9D, 0x08,
+0x53, 0x86, 0xF2, 0xC6, 0x11, 0xF7, 0x0D, 0xFE,
+0x06, 0x66, 0x4B, 0x86, 0x26, 0x47, 0x8D, 0xCE,
+0xA7, 0x00, 0xCC, 0x21, 0x08, 0x00, 0xCC, 0xF6,
+0xB0, 0xC4, 0xD7, 0x70, 0x59, 0xD4, 0x02, 0x99,
+0x2E, 0x18, 0x99, 0x1E, 0x37, 0x3A, 0x9C, 0x53,
+0xDA, 0xC3, 0x13, 0x5D, 0xC1, 0x67, 0x50, 0x0A,
+0x64, 0xB8, 0x62, 0x64, 0x78, 0xDC, 0xEA, 0x70,
+0x0C, 0xC2, 0x10, 0x80, 0x40, 0x66, 0x64, 0xB8,
+0x62, 0x64, 0x78, 0xDC, 0xEA, 0x70, 0xCC, 0x06,
+0x66, 0x4B, 0x86, 0x26, 0x47, 0x8D, 0xCE, 0xA7,
+0x01, 0x4F, 0x6B, 0x0C, 0x4D, 0x77, 0x05, 0x9D,
+0x40, 0x29, 0xED, 0x61, 0x89, 0xAE, 0xE0, 0xB3,
+0xA8, 0x05, 0x3D, 0xAC, 0x31, 0x35, 0xDC, 0x16,
+0x75, 0x00, 0xA7, 0xB5, 0x86, 0x26, 0xBB, 0x82,
+0xCE, 0xA0, 0x01, 0x4C, 0x97, 0x0C, 0x4C, 0x8F,
+0x1B, 0x9D, 0x4E, 0x19, 0x86, 0x4D, 0x9A, 0xE3,
+0xFB, 0x74, 0xEC, 0x5B, 0x89, 0x67, 0x59, 0x96,
+0x99, 0xAB, 0xB0, 0x4A, 0xCA, 0x76, 0xAB, 0x42,
+0xBD, 0xDE, 0xB4, 0x92, 0x85, 0x35, 0xA4, 0xA7,
+0x9B, 0xCE, 0x31, 0x19, 0x4D, 0x2C, 0x4D, 0x38,
+0xD2, 0xEC, 0x29, 0x77, 0xFA, 0xC2, 0x67, 0x2A,
+0x37, 0x13, 0xED, 0xCF, 0x74, 0xAE, 0xFC, 0x10,
+0x03, 0x33, 0x80, 0xFA, 0xCE, 0xFE, 0x13, 0xFC,
+0xB0, 0xCD, 0x32, 0x5C, 0x31, 0x32, 0x3C, 0x6E,
+0x75, 0x38, 0x00, 0x79, 0x2D, 0x4C, 0x84, 0xDA,
+0x33, 0x13, 0x91, 0x69, 0x99, 0x95, 0xEB, 0x7C,
+0x92, 0xB9, 0xA2, 0xF6, 0x75, 0x8A, 0xA3, 0xD1,
+0xD3, 0xA0, 0x79, 0xA6, 0x1D, 0xCD, 0x3C, 0x84,
+0x38, 0x90, 0x38, 0xD3, 0x89, 0xB4, 0x84, 0xDD,
+0xEA, 0x0F, 0xF3, 0x25, 0xC3, 0x13, 0x23, 0xC6,
+0xE7, 0x53, 0x80, 0x66, 0x03, 0x33, 0x25, 0xC3,
+0x13, 0x23, 0xC6, 0xE7, 0x53, 0x86, 0x60, 0x33,
+0x32, 0x5C, 0x31, 0x32, 0x3C, 0x6E, 0x75, 0x38,
+0x06, 0x61, 0x08, 0x40, 0x06, 0x67, 0xB5, 0x86,
+0x26, 0xBB, 0x82, 0xCE, 0xA0, 0x14, 0xC9, 0x70,
+0xC4, 0xC8, 0xF1, 0xB9, 0xD4, 0xE2, 0x9E, 0xD6,
+0x18, 0x9A, 0xEE, 0x0B, 0x3A, 0x80, 0x53, 0x25,
+0xC3, 0x13, 0x23, 0xC6, 0xE7, 0x53, 0x80, 0x66,
+0x10, 0x84, 0x02, 0x03, 0x33, 0x25, 0xC3, 0x13,
+0x23, 0xC6, 0xE7, 0x53, 0x86, 0x60, 0x33, 0x32,
+0x5C, 0x31, 0x32, 0x3C, 0x6E, 0x75, 0x38, 0x0A,
+0x7B, 0x58, 0x62, 0x6B, 0xB8, 0x2C, 0xEA, 0x01,
+0x4F, 0x6B, 0x0C, 0x4D, 0x77, 0x05, 0x9D, 0x40,
+0x29, 0xED, 0x61, 0x89, 0xAE, 0xE0, 0xB3, 0xA8,
+0x05, 0x3D, 0xAC, 0x31, 0x35, 0xDC, 0x16, 0x75,
+0x00, 0x06, 0x61, 0x08, 0x40, 0x31, 0x9C, 0xEB,
+0x65, 0x86, 0xEE, 0x5F, 0xD7, 0x2C, 0x93, 0xA6,
+0x36, 0x66, 0x4D, 0x95, 0xB8, 0xFF, 0x00, 0x82,
+0xDD, 0x88, 0x0F, 0xB5, 0x5A, 0xAA, 0x4E, 0xF9,
+0xF8, 0x11, 0x21, 0x94, 0x52, 0x12, 0x9E, 0xF3,
+0xA3, 0xBB, 0x61, 0x07, 0xB5, 0x35, 0xC6, 0x31,
+0xEC, 0x4A, 0xCE, 0x25, 0x9D, 0x94, 0x19, 0x97,
+0xD1, 0xA3, 0x72, 0x4A, 0x5B, 0x55, 0x9E, 0x4D,
+0xD1, 0x75, 0x55, 0xBA, 0x88, 0x2D, 0x25, 0x21,
+0xDD, 0x29, 0xE7, 0x10, 0xE3, 0xA9, 0x1C, 0x43,
+0x8E, 0xDB, 0xBA, 0x94, 0x37, 0x10, 0x78, 0xB3,
+0x80, 0xFA, 0xCE, 0xFE, 0x13, 0xFC, 0xB0, 0xCD,
+0x32, 0x5C, 0x31, 0x32, 0x3C, 0x6E, 0x75, 0x38,
+0x0B, 0x57, 0x6F, 0xDB, 0xB4, 0x5F, 0x82, 0x94,
+0xBC, 0xC0, 0xCE, 0x6B, 0x8C, 0x63, 0xD8, 0x95,
+0x9C, 0x4B, 0x3B, 0x28, 0x33, 0x2F, 0xA3, 0x46,
+0xE4, 0x94, 0xB6, 0xAB, 0x3C, 0x9B, 0xA2, 0xEA,
+0xAB, 0x75, 0x10, 0x5A, 0x4A, 0x43, 0xBA, 0x53,
+0xCE, 0x21, 0xC7, 0x52, 0x38, 0x87, 0x1D, 0xB7,
+0x75, 0x28, 0x6E, 0x20, 0xD6, 0x40, 0x66, 0x64,
+0xB8, 0x62, 0x64, 0x78, 0xDC, 0xEA, 0x70, 0x16,
+0xB1, 0x1F, 0xB7, 0x67, 0x4F, 0x1A, 0xA9, 0x79,
+0x45, 0xAC, 0x47, 0xED, 0xD9, 0xD3, 0xC6, 0xAA,
+0x5E, 0x50, 0xCC, 0x20, 0x19, 0x36, 0x74, 0x6D,
+0x9B, 0xD8, 0x95, 0x9C, 0x4B, 0x45, 0x27, 0xB4,
+0xCE, 0x5F, 0x46, 0xE4, 0x94, 0xB6, 0x5B, 0x44,
+0xA5, 0xA5, 0x0A, 0xAB, 0x75, 0x10, 0x5A, 0x44,
+0x53, 0x7A, 0x23, 0x0D, 0x21, 0xC7, 0x52, 0x38,
+0x86, 0x9B, 0xB3, 0x75, 0x28, 0xEE, 0x20, 0xA6,
+0xB8, 0xD9, 0xBD, 0x89, 0x25, 0xC4, 0xB3, 0xB2,
+0x7B, 0x32, 0xE5, 0xF4, 0x92, 0x49, 0x45, 0x6A,
+0xB3, 0xCA, 0x5A, 0x50, 0xAA, 0xA9, 0x5F, 0x15,
+0xA4, 0xA5, 0x3B, 0xA2, 0x3C, 0xD2, 0x9C, 0x6D,
+0x13, 0x8A, 0x71, 0xBB, 0x77, 0xD1, 0x8E, 0xE2,
+0x84, 0xC9, 0xED, 0x61, 0x89, 0xAE, 0xE0, 0xB3,
+0xA8, 0x05, 0x32, 0x5C, 0x31, 0x32, 0x3C, 0x6E,
+0x75, 0x38, 0x0B, 0x58, 0x8F, 0xDB, 0xB3, 0xA7,
+0x8D, 0x54, 0xBC, 0xA2, 0xD6, 0x23, 0xF6, 0xEC,
+0xE9, 0xE3, 0x55, 0x2F, 0x28, 0x66, 0x10, 0x01,
+0x9D, 0x62, 0x3F, 0x6E, 0xCE, 0x9E, 0x35, 0x52,
+0xF2, 0x8F, 0x6A, 0x6B, 0x8C, 0xB4, 0xBA, 0xC5,
+0xB8, 0x96, 0x75, 0x99, 0x69, 0x94, 0x6C, 0x12,
+0xB2, 0x9D, 0xAA, 0xD0, 0xAF, 0x5A, 0x62, 0x4A,
+0x14, 0xD6, 0x92, 0x9E, 0x6F, 0x38, 0xC2, 0x94,
+0xD2, 0xC4, 0xD3, 0x8D, 0x2E, 0xC2, 0x97, 0x7F,
+0xAC, 0x26, 0x08, 0x00, 0xCC, 0xF6, 0xB0, 0xC4,
+0xD7, 0x70, 0x59, 0xD4, 0x02, 0x9E, 0xD6, 0x18,
+0x9A, 0xEE, 0x0B, 0x3A, 0x80, 0x53, 0xDA, 0xC3,
+0x13, 0x5D, 0xC1, 0x67, 0x50, 0x0A, 0x7B, 0x58,
+0x62, 0x6B, 0xB8, 0x2C, 0xEA, 0x00, 0x0C, 0xC2,
+0x10, 0x80, 0x63, 0x39, 0xC0, 0x7D, 0x67, 0x7F,
+0x09, 0xFE, 0x58, 0x66, 0x99, 0x2E, 0x18, 0x99,
+0x1E, 0x37, 0x3A, 0x9C, 0x0C, 0xCE, 0x03, 0xEB,
+0x3B, 0xF8, 0x4F, 0xF2, 0xC3, 0x34, 0xC9, 0x70,
+0xC4, 0xC8, 0xF1, 0xB9, 0xD4, 0xE0, 0x19, 0x80,
+0xCC, 0xC9, 0x70, 0xC4, 0xC8, 0xF1, 0xB9, 0xD4,
+0xE1, 0x98, 0x0C, 0xCC, 0x97, 0x0C, 0x4C, 0x8F,
+0x1B, 0x9D, 0x4E, 0x03, 0xFF, 0xD9};
+static const int goodJpegImageWidth = 128;
+static const int goodJpegImageHeight = 128;
+
+// https://code.google.com/p/android/issues/detail?id=42382
+// https://code.google.com/p/android/issues/detail?id=9064
+// https://code.google.com/p/skia/issues/detail?id=1649
+
+/**
+ This test will test the ability of the SkImageDecoder to deal with
+ Jpeg files which have been mangled somehow. We want to display as
+ much of the jpeg as possible.
+*/
+DEF_TEST(Jpeg, reporter) {
+ size_t len = sizeof(goodJpegImage) / 2;
+ // I am explicitly not putting the entire image into the
+ // DecodeMemory. This simulates a network error.
+
+ SkBitmap bm8888;
+ bool imageDecodeSuccess = SkImageDecoder::DecodeMemory(
+ static_cast<void *>(goodJpegImage), len, &bm8888);
+ REPORTER_ASSERT(reporter, imageDecodeSuccess);
+ REPORTER_ASSERT(reporter, bm8888.width() == goodJpegImageWidth);
+ REPORTER_ASSERT(reporter, bm8888.height() == goodJpegImageHeight);
+ REPORTER_ASSERT(reporter, !(bm8888.empty()));
+
+ // Pick a few pixels and verify that their colors match the colors
+ // we expect (given the original image).
+ REPORTER_ASSERT(reporter, bm8888.getColor(7, 9) == 0xffffffff);
+ REPORTER_ASSERT(reporter, bm8888.getColor(28, 3) == 0xff000000);
+ REPORTER_ASSERT(reporter, bm8888.getColor(27, 34) == 0xffffffff);
+ REPORTER_ASSERT(reporter, bm8888.getColor(71, 18) == 0xff000000);
+
+#ifdef SK_BUILD_FOR_IOS // the iOS jpeg decoder fills to gray
+ REPORTER_ASSERT(reporter, bm8888.getColor(127, 127) == 0xff808080
+ || bm8888.getColor(127, 127) == SK_ColorWHITE);
+#else
+ // This is the fill color
+ REPORTER_ASSERT(reporter, bm8888.getColor(127, 127) == SK_ColorWHITE);
+#endif
+
+ #if JPEG_TEST_WRITE_TO_FILE_FOR_DEBUGGING
+ // Check to see that the resulting bitmap is nice
+ bool writeSuccess = (!(bm8888.empty())) && SkImageEncoder::EncodeFile(
+ "HalfOfAJpeg.png", bm8888, SkImageEncoder::kPNG_Type, 100);
+ SkASSERT(writeSuccess);
+ #endif
+}
diff --git a/src/third_party/skia/tests/KtxTest.cpp b/src/third_party/skia/tests/KtxTest.cpp
new file mode 100644
index 0000000..1a61f3a
--- /dev/null
+++ b/src/third_party/skia/tests/KtxTest.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Resources.h"
+#include "SkBitmap.h"
+#include "SkData.h"
+#include "SkDecodingImageGenerator.h"
+#include "SkForceLinking.h"
+#include "SkImageDecoder.h"
+#include "SkOSFile.h"
+#include "SkRandom.h"
+#include "SkStream.h"
+#include "Test.h"
+
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
+/**
+ * First, make sure that writing an 8-bit RGBA KTX file and then
+ * reading it produces the same bitmap.
+ */
+DEF_TEST(KtxReadWrite, reporter) {
+
+ // Random number generator with explicit seed for reproducibility
+ SkRandom rand(0x1005cbad);
+
+ SkBitmap bm8888;
+ bm8888.allocN32Pixels(128, 128);
+
+ uint8_t *pixels = reinterpret_cast<uint8_t*>(bm8888.getPixels());
+ REPORTER_ASSERT(reporter, pixels);
+
+ if (NULL == pixels) {
+ return;
+ }
+
+ uint8_t *row = pixels;
+ for (int y = 0; y < bm8888.height(); ++y) {
+ for (int x = 0; x < bm8888.width(); ++x) {
+ uint8_t a = rand.nextRangeU(0, 255);
+ uint8_t r = rand.nextRangeU(0, 255);
+ uint8_t g = rand.nextRangeU(0, 255);
+ uint8_t b = rand.nextRangeU(0, 255);
+
+ SkPMColor &pixel = *(reinterpret_cast<SkPMColor*>(row + x*sizeof(SkPMColor)));
+ pixel = SkPreMultiplyARGB(a, r, g, b);
+ }
+ row += bm8888.rowBytes();
+ }
+ REPORTER_ASSERT(reporter, !(bm8888.empty()));
+
+ SkAutoDataUnref encodedData(SkImageEncoder::EncodeData(bm8888, SkImageEncoder::kKTX_Type, 0));
+ REPORTER_ASSERT(reporter, encodedData);
+
+ SkAutoTUnref<SkMemoryStream> stream(SkNEW_ARGS(SkMemoryStream, (encodedData)));
+ REPORTER_ASSERT(reporter, stream);
+
+ SkBitmap decodedBitmap;
+ bool imageDecodeSuccess = SkImageDecoder::DecodeStream(stream, &decodedBitmap);
+ REPORTER_ASSERT(reporter, imageDecodeSuccess);
+
+ REPORTER_ASSERT(reporter, decodedBitmap.colorType() == bm8888.colorType());
+ REPORTER_ASSERT(reporter, decodedBitmap.alphaType() == bm8888.alphaType());
+ REPORTER_ASSERT(reporter, decodedBitmap.width() == bm8888.width());
+ REPORTER_ASSERT(reporter, decodedBitmap.height() == bm8888.height());
+ REPORTER_ASSERT(reporter, !(decodedBitmap.empty()));
+
+ uint8_t *decodedPixels = reinterpret_cast<uint8_t*>(decodedBitmap.getPixels());
+ REPORTER_ASSERT(reporter, decodedPixels);
+ REPORTER_ASSERT(reporter, decodedBitmap.getSize() == bm8888.getSize());
+
+ if (NULL == decodedPixels) {
+ return;
+ }
+
+ REPORTER_ASSERT(reporter, memcmp(decodedPixels, pixels, decodedBitmap.getSize()) == 0);
+}
+
+/**
+ * Next test is to see whether or not reading an unpremultiplied KTX file accurately
+ * creates a premultiplied buffer...
+ */
+DEF_TEST(KtxReadUnpremul, reporter) {
+
+ static const uint8_t kHalfWhiteKTX[] = {
+ 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, // First twelve bytes is magic
+ 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A, // KTX identifier string
+ 0x01, 0x02, 0x03, 0x04, // Then magic endian specifier
+ 0x01, 0x14, 0x00, 0x00, // uint32_t fGLType;
+ 0x01, 0x00, 0x00, 0x00, // uint32_t fGLTypeSize;
+ 0x08, 0x19, 0x00, 0x00, // uint32_t fGLFormat;
+ 0x58, 0x80, 0x00, 0x00, // uint32_t fGLInternalFormat;
+ 0x08, 0x19, 0x00, 0x00, // uint32_t fGLBaseInternalFormat;
+ 0x02, 0x00, 0x00, 0x00, // uint32_t fPixelWidth;
+ 0x02, 0x00, 0x00, 0x00, // uint32_t fPixelHeight;
+ 0x00, 0x00, 0x00, 0x00, // uint32_t fPixelDepth;
+ 0x00, 0x00, 0x00, 0x00, // uint32_t fNumberOfArrayElements;
+ 0x01, 0x00, 0x00, 0x00, // uint32_t fNumberOfFaces;
+ 0x01, 0x00, 0x00, 0x00, // uint32_t fNumberOfMipmapLevels;
+ 0x00, 0x00, 0x00, 0x00, // uint32_t fBytesOfKeyValueData;
+ 0x10, 0x00, 0x00, 0x00, // image size: 2x2 image of RGBA = 4 * 4 = 16 bytes
+ 0xFF, 0xFF, 0xFF, 0x80, // Pixel 1
+ 0xFF, 0xFF, 0xFF, 0x80, // Pixel 2
+ 0xFF, 0xFF, 0xFF, 0x80, // Pixel 3
+ 0xFF, 0xFF, 0xFF, 0x80};// Pixel 4
+
+ SkAutoTUnref<SkMemoryStream> stream(
+ SkNEW_ARGS(SkMemoryStream, (kHalfWhiteKTX, sizeof(kHalfWhiteKTX))));
+ REPORTER_ASSERT(reporter, stream);
+
+ SkBitmap decodedBitmap;
+ bool imageDecodeSuccess = SkImageDecoder::DecodeStream(stream, &decodedBitmap);
+ REPORTER_ASSERT(reporter, imageDecodeSuccess);
+
+ REPORTER_ASSERT(reporter, decodedBitmap.colorType() == kN32_SkColorType);
+ REPORTER_ASSERT(reporter, decodedBitmap.alphaType() == kPremul_SkAlphaType);
+ REPORTER_ASSERT(reporter, decodedBitmap.width() == 2);
+ REPORTER_ASSERT(reporter, decodedBitmap.height() == 2);
+ REPORTER_ASSERT(reporter, !(decodedBitmap.empty()));
+
+ uint8_t *decodedPixels = reinterpret_cast<uint8_t*>(decodedBitmap.getPixels());
+ REPORTER_ASSERT(reporter, decodedPixels);
+
+ uint8_t *row = decodedPixels;
+ for (int j = 0; j < decodedBitmap.height(); ++j) {
+ for (int i = 0; i < decodedBitmap.width(); ++i) {
+ SkPMColor pixel = *(reinterpret_cast<SkPMColor*>(row + i*sizeof(SkPMColor)));
+ REPORTER_ASSERT(reporter, SkPreMultiplyARGB(0x80, 0xFF, 0xFF, 0xFF) == pixel);
+ }
+ row += decodedBitmap.rowBytes();
+ }
+}
+
+/**
+ * Finally, make sure that if we get ETC1 data from a PKM file that we can then
+ * accurately write it out into a KTX file (i.e. transferring the ETC1 data from
+ * the PKM to the KTX should produce an identical KTX to the one we have on file)
+ */
+DEF_TEST(KtxReexportPKM, reporter) {
+ SkString pkmFilename = GetResourcePath("mandrill_128.pkm");
+
+ // Load PKM file into a bitmap
+ SkBitmap etcBitmap;
+ SkAutoTUnref<SkData> fileData(SkData::NewFromFileName(pkmFilename.c_str()));
+ REPORTER_ASSERT(reporter, fileData);
+ if (NULL == fileData) {
+ return;
+ }
+
+ bool installDiscardablePixelRefSuccess =
+ SkInstallDiscardablePixelRef(
+ SkDecodingImageGenerator::Create(
+ fileData, SkDecodingImageGenerator::Options()), &etcBitmap);
+ REPORTER_ASSERT(reporter, installDiscardablePixelRefSuccess);
+
+ // Write the bitmap out to a KTX file.
+ SkData *ktxDataPtr = SkImageEncoder::EncodeData(etcBitmap, SkImageEncoder::kKTX_Type, 0);
+ SkAutoDataUnref newKtxData(ktxDataPtr);
+ REPORTER_ASSERT(reporter, ktxDataPtr);
+
+ // See is this data is identical to data in existing ktx file.
+ SkString ktxFilename = GetResourcePath("mandrill_128.ktx");
+ SkAutoDataUnref oldKtxData(SkData::NewFromFileName(ktxFilename.c_str()));
+ REPORTER_ASSERT(reporter, oldKtxData->equals(newKtxData));
+}
diff --git a/src/third_party/skia/tests/LListTest.cpp b/src/third_party/skia/tests/LListTest.cpp
new file mode 100644
index 0000000..8fb0117
--- /dev/null
+++ b/src/third_party/skia/tests/LListTest.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRandom.h"
+#include "SkTInternalLList.h"
+#include "SkTLList.h"
+#include "Test.h"
+
+class ListElement {
+public:
+ ListElement(int id) : fID(id) {
+ }
+ bool operator== (const ListElement& other) { return fID == other.fID; }
+
+#if SK_ENABLE_INST_COUNT
+ // Make the instance count available publicly.
+ static int InstanceCount() { return GetInstanceCount(); }
+#endif
+
+ int fID;
+
+private:
+ SK_DECLARE_INST_COUNT_ROOT(ListElement);
+ SK_DECLARE_INTERNAL_LLIST_INTERFACE(ListElement);
+};
+
+static void check_list(const SkTInternalLList<ListElement>& list,
+ skiatest::Reporter* reporter,
+ bool empty,
+ int numElements,
+ bool in0, bool in1, bool in2, bool in3,
+ ListElement elements[4]) {
+
+ REPORTER_ASSERT(reporter, empty == list.isEmpty());
+#ifdef SK_DEBUG
+ list.validate();
+ REPORTER_ASSERT(reporter, numElements == list.countEntries());
+ REPORTER_ASSERT(reporter, in0 == list.isInList(&elements[0]));
+ REPORTER_ASSERT(reporter, in1 == list.isInList(&elements[1]));
+ REPORTER_ASSERT(reporter, in2 == list.isInList(&elements[2]));
+ REPORTER_ASSERT(reporter, in3 == list.isInList(&elements[3]));
+#endif
+}
+
+static void TestTInternalLList(skiatest::Reporter* reporter) {
+ SkTInternalLList<ListElement> list;
+ ListElement elements[4] = {
+ ListElement(0),
+ ListElement(1),
+ ListElement(2),
+ ListElement(3),
+ };
+
+ // list should be empty to start with
+ check_list(list, reporter, true, 0, false, false, false, false, elements);
+
+ list.addToHead(&elements[0]);
+
+ check_list(list, reporter, false, 1, true, false, false, false, elements);
+
+ list.addToHead(&elements[1]);
+ list.addToHead(&elements[2]);
+ list.addToHead(&elements[3]);
+
+ check_list(list, reporter, false, 4, true, true, true, true, elements);
+
+ // test out iterators
+ typedef SkTInternalLList<ListElement>::Iter Iter;
+ Iter iter;
+
+ ListElement* cur = iter.init(list, Iter::kHead_IterStart);
+ for (int i = 0; cur; ++i, cur = iter.next()) {
+ REPORTER_ASSERT(reporter, cur->fID == 3-i);
+ }
+
+ cur = iter.init(list, Iter::kTail_IterStart);
+ for (int i = 0; cur; ++i, cur = iter.prev()) {
+ REPORTER_ASSERT(reporter, cur->fID == i);
+ }
+
+ // remove middle, frontmost then backmost
+ list.remove(&elements[1]);
+ list.remove(&elements[3]);
+ list.remove(&elements[0]);
+
+ check_list(list, reporter, false, 1, false, false, true, false, elements);
+
+ // remove last element
+ list.remove(&elements[2]);
+
+ // list should be empty again
+ check_list(list, reporter, true, 0, false, false, false, false, elements);
+
+ // test out methods that add to the middle of the list.
+ list.addAfter(&elements[1], NULL);
+ check_list(list, reporter, false, 1, false, true, false, false, elements);
+
+ list.remove(&elements[1]);
+
+ list.addBefore(&elements[1], NULL);
+ check_list(list, reporter, false, 1, false, true, false, false, elements);
+
+ list.addBefore(&elements[0], &elements[1]);
+ check_list(list, reporter, false, 2, true, true, false, false, elements);
+
+ list.addAfter(&elements[3], &elements[1]);
+ check_list(list, reporter, false, 3, true, true, false, true, elements);
+
+ list.addBefore(&elements[2], &elements[3]);
+ check_list(list, reporter, false, 4, true, true, true, true, elements);
+
+ cur = iter.init(list, Iter::kHead_IterStart);
+ for (int i = 0; cur; ++i, cur = iter.next()) {
+ REPORTER_ASSERT(reporter, cur->fID == i);
+ }
+}
+
+static void TestTLList(skiatest::Reporter* reporter) {
+ typedef SkTLList<ListElement> ElList;
+ typedef ElList::Iter Iter;
+ SkRandom random;
+
+ for (int i = 1; i <= 16; i *= 2) {
+
+ ElList list1(i);
+ ElList list2(i);
+ Iter iter1;
+ Iter iter2;
+ Iter iter3;
+ Iter iter4;
+
+#if SK_ENABLE_INST_COUNT
+ SkASSERT(0 == ListElement::InstanceCount());
+#endif
+
+ REPORTER_ASSERT(reporter, list1.isEmpty());
+ REPORTER_ASSERT(reporter, NULL == iter1.init(list1, Iter::kHead_IterStart));
+ REPORTER_ASSERT(reporter, NULL == iter1.init(list1, Iter::kTail_IterStart));
+ // Try popping an empty list
+ list1.popHead();
+ list1.popTail();
+ REPORTER_ASSERT(reporter, list1.isEmpty());
+ REPORTER_ASSERT(reporter, list1 == list2);
+
+ // Create two identical lists, one by appending to head and the other to the tail.
+ list1.addToHead(ListElement(1));
+ list2.addToTail(ListElement(1));
+#if SK_ENABLE_INST_COUNT
+ SkASSERT(2 == ListElement::InstanceCount());
+#endif
+ iter1.init(list1, Iter::kHead_IterStart);
+ iter2.init(list1, Iter::kTail_IterStart);
+ REPORTER_ASSERT(reporter, iter1.get()->fID == iter2.get()->fID);
+ iter3.init(list2, Iter::kHead_IterStart);
+ iter4.init(list2, Iter::kTail_IterStart);
+ REPORTER_ASSERT(reporter, iter3.get()->fID == iter1.get()->fID);
+ REPORTER_ASSERT(reporter, iter4.get()->fID == iter1.get()->fID);
+ REPORTER_ASSERT(reporter, list1 == list2);
+
+ list2.reset();
+
+ // use both before/after in-place construction on an empty list
+ SkNEW_INSERT_IN_LLIST_BEFORE(&list2, list2.headIter(), ListElement, (1));
+ REPORTER_ASSERT(reporter, list2 == list1);
+ list2.reset();
+
+ SkNEW_INSERT_IN_LLIST_AFTER(&list2, list2.tailIter(), ListElement, (1));
+ REPORTER_ASSERT(reporter, list2 == list1);
+
+ // add an element to the second list, check that iters are still valid
+ iter3.init(list2, Iter::kHead_IterStart);
+ iter4.init(list2, Iter::kTail_IterStart);
+ list2.addToHead(ListElement(2));
+
+#if SK_ENABLE_INST_COUNT
+ SkASSERT(3 == ListElement::InstanceCount());
+#endif
+
+ REPORTER_ASSERT(reporter, iter3.get()->fID == iter1.get()->fID);
+ REPORTER_ASSERT(reporter, iter4.get()->fID == iter1.get()->fID);
+ REPORTER_ASSERT(reporter, 1 == Iter(list2, Iter::kTail_IterStart).get()->fID);
+ REPORTER_ASSERT(reporter, 2 == Iter(list2, Iter::kHead_IterStart).get()->fID);
+ REPORTER_ASSERT(reporter, list1 != list2);
+ list1.addToHead(ListElement(2));
+ REPORTER_ASSERT(reporter, list1 == list2);
+#if SK_ENABLE_INST_COUNT
+ SkASSERT(4 == ListElement::InstanceCount());
+#endif
+ REPORTER_ASSERT(reporter, !list1.isEmpty());
+
+ list1.reset();
+ list2.reset();
+#if SK_ENABLE_INST_COUNT
+ SkASSERT(0 == ListElement::InstanceCount());
+#endif
+ REPORTER_ASSERT(reporter, list1.isEmpty() && list2.isEmpty());
+
+ // randomly perform insertions and deletions on a list and perform tests
+ int count = 0;
+ for (int j = 0; j < 100; ++j) {
+ if (list1.isEmpty() || random.nextBiasedBool(3 * SK_Scalar1 / 4)) {
+ int id = j;
+ // Choose one of three ways to insert a new element: at the head, at the tail,
+ // before a random element, after a random element
+ int numValidMethods = 0 == count ? 2 : 4;
+ int insertionMethod = random.nextULessThan(numValidMethods);
+ switch (insertionMethod) {
+ case 0:
+ list1.addToHead(ListElement(id));
+ break;
+ case 1:
+ list1.addToTail(ListElement(id));
+ break;
+ case 2: // fallthru to share code that picks random element.
+ case 3: {
+ int n = random.nextULessThan(list1.count());
+ Iter iter = list1.headIter();
+ // remember the elements before/after the insertion point.
+ while (n--) {
+ iter.next();
+ }
+ Iter prev(iter);
+ Iter next(iter);
+ next.next();
+ prev.prev();
+
+ SkASSERT(iter.get());
+ // insert either before or after the iterator, then check that the
+ // surrounding sequence is correct.
+ if (2 == insertionMethod) {
+ SkNEW_INSERT_IN_LLIST_BEFORE(&list1, iter, ListElement, (id));
+ Iter newItem(iter);
+ newItem.prev();
+ REPORTER_ASSERT(reporter, newItem.get()->fID == id);
+
+ if (next.get()) {
+ REPORTER_ASSERT(reporter, next.prev()->fID == iter.get()->fID);
+ }
+ if (prev.get()) {
+ REPORTER_ASSERT(reporter, prev.next()->fID == id);
+ }
+ } else {
+ SkNEW_INSERT_IN_LLIST_AFTER(&list1, iter, ListElement, (id));
+ Iter newItem(iter);
+ newItem.next();
+ REPORTER_ASSERT(reporter, newItem.get()->fID == id);
+
+ if (next.get()) {
+ REPORTER_ASSERT(reporter, next.prev()->fID == id);
+ }
+ if (prev.get()) {
+ REPORTER_ASSERT(reporter, prev.next()->fID == iter.get()->fID);
+ }
+ }
+ }
+ }
+ ++count;
+ } else {
+ // walk to a random place either forward or backwards and remove.
+ int n = random.nextULessThan(list1.count());
+ Iter::IterStart start;
+ ListElement* (Iter::*incrFunc)();
+
+ if (random.nextBool()) {
+ start = Iter::kHead_IterStart;
+ incrFunc = &Iter::next;
+ } else {
+ start = Iter::kTail_IterStart;
+ incrFunc = &Iter::prev;
+ }
+
+ // find the element
+ Iter iter(list1, start);
+ while (n--) {
+ REPORTER_ASSERT(reporter, iter.get());
+ (iter.*incrFunc)();
+ }
+ REPORTER_ASSERT(reporter, iter.get());
+
+ // remember the prev and next elements from the element to be removed
+ Iter prev = iter;
+ Iter next = iter;
+ prev.prev();
+ next.next();
+ list1.remove(iter.get());
+
+ // make sure the remembered next/prev iters still work
+ Iter pn = prev; pn.next();
+ Iter np = next; np.prev();
+ // pn should match next unless the target node was the head, in which case prev
+ // walked off the list.
+ REPORTER_ASSERT(reporter, pn.get() == next.get() || NULL == prev.get());
+ // Similarly, np should match prev unless next originally walked off the tail.
+ REPORTER_ASSERT(reporter, np.get() == prev.get() || NULL == next.get());
+ --count;
+ }
+ REPORTER_ASSERT(reporter, count == list1.count());
+#if SK_ENABLE_INST_COUNT
+ SkASSERT(count == ListElement::InstanceCount());
+#endif
+ }
+ list1.reset();
+#if SK_ENABLE_INST_COUNT
+ SkASSERT(0 == ListElement::InstanceCount());
+#endif
+ }
+}
+
+DEF_TEST(LList, reporter) {
+ TestTInternalLList(reporter);
+ TestTLList(reporter);
+}
diff --git a/src/third_party/skia/tests/LayerDrawLooperTest.cpp b/src/third_party/skia/tests/LayerDrawLooperTest.cpp
new file mode 100644
index 0000000..bc76a02
--- /dev/null
+++ b/src/third_party/skia/tests/LayerDrawLooperTest.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkBitmapDevice.h"
+#include "SkCanvas.h"
+#include "SkDraw.h"
+#include "SkLayerDrawLooper.h"
+#include "SkMatrix.h"
+#include "SkPaint.h"
+#include "SkRect.h"
+#include "SkRefCnt.h"
+#include "SkScalar.h"
+#include "SkSmallAllocator.h"
+#include "SkXfermode.h"
+#include "Test.h"
+
+static SkBitmap make_bm(int w, int h) {
+ SkBitmap bm;
+ bm.allocN32Pixels(w, h);
+ return bm;
+}
+
+class FakeDevice : public SkBitmapDevice {
+public:
+ FakeDevice() : SkBitmapDevice(make_bm(100, 100)) { }
+
+ virtual void drawRect(const SkDraw& draw, const SkRect& r,
+ const SkPaint& paint) SK_OVERRIDE {
+ fLastMatrix = *draw.fMatrix;
+ this->INHERITED::drawRect(draw, r, paint);
+ }
+
+ SkMatrix fLastMatrix;
+
+private:
+ typedef SkBitmapDevice INHERITED;
+};
+
+static void test_frontToBack(skiatest::Reporter* reporter) {
+ SkLayerDrawLooper::Builder looperBuilder;
+ SkLayerDrawLooper::LayerInfo layerInfo;
+
+ // Add the front layer, with the defaults.
+ (void)looperBuilder.addLayer(layerInfo);
+
+ // Add the back layer, with some layer info set.
+ layerInfo.fOffset.set(10.0f, 20.0f);
+ layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
+ SkPaint* layerPaint = looperBuilder.addLayer(layerInfo);
+ layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode);
+
+ FakeDevice device;
+ SkCanvas canvas(&device);
+ SkPaint paint;
+ SkAutoTUnref<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
+ SkSmallAllocator<1, 32> allocator;
+ void* buffer = allocator.reserveT<SkDrawLooper::Context>(looper->contextSize());
+ SkDrawLooper::Context* context = looper->createContext(&canvas, buffer);
+
+ // The back layer should come first.
+ REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
+ REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode));
+ canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
+ REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
+ REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
+ paint.reset();
+
+ // Then the front layer.
+ REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
+ REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode));
+ canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
+ REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
+ REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
+
+ // Only two layers were added, so that should be the end.
+ REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
+}
+
+static void test_backToFront(skiatest::Reporter* reporter) {
+ SkLayerDrawLooper::Builder looperBuilder;
+ SkLayerDrawLooper::LayerInfo layerInfo;
+
+ // Add the back layer, with the defaults.
+ (void)looperBuilder.addLayerOnTop(layerInfo);
+
+ // Add the front layer, with some layer info set.
+ layerInfo.fOffset.set(10.0f, 20.0f);
+ layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
+ SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo);
+ layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode);
+
+ FakeDevice device;
+ SkCanvas canvas(&device);
+ SkPaint paint;
+ SkAutoTUnref<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
+ SkSmallAllocator<1, 32> allocator;
+ void* buffer = allocator.reserveT<SkDrawLooper::Context>(looper->contextSize());
+ SkDrawLooper::Context* context = looper->createContext(&canvas, buffer);
+
+ // The back layer should come first.
+ REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
+ REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode));
+ canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
+ REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
+ REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
+ paint.reset();
+
+ // Then the front layer.
+ REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
+ REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode));
+ canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
+ REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
+ REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
+
+ // Only two layers were added, so that should be the end.
+ REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
+}
+
+static void test_mixed(skiatest::Reporter* reporter) {
+ SkLayerDrawLooper::Builder looperBuilder;
+ SkLayerDrawLooper::LayerInfo layerInfo;
+
+ // Add the back layer, with the defaults.
+ (void)looperBuilder.addLayer(layerInfo);
+
+ // Add the front layer, with some layer info set.
+ layerInfo.fOffset.set(10.0f, 20.0f);
+ layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
+ SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo);
+ layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode);
+
+ FakeDevice device;
+ SkCanvas canvas(&device);
+ SkPaint paint;
+ SkAutoTUnref<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
+ SkSmallAllocator<1, 32> allocator;
+ void* buffer = allocator.reserveT<SkDrawLooper::Context>(looper->contextSize());
+ SkDrawLooper::Context* context = looper->createContext(&canvas, buffer);
+
+ // The back layer should come first.
+ REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
+ REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode));
+ canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
+ REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
+ REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
+ paint.reset();
+
+ // Then the front layer.
+ REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
+ REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode));
+ canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
+ REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
+ REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
+
+ // Only two layers were added, so that should be the end.
+ REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
+}
+
+DEF_TEST(LayerDrawLooper, reporter) {
+ test_frontToBack(reporter);
+ test_backToFront(reporter);
+ test_mixed(reporter);
+}
diff --git a/src/third_party/skia/tests/LayerRasterizerTest.cpp b/src/third_party/skia/tests/LayerRasterizerTest.cpp
new file mode 100644
index 0000000..4b236ac
--- /dev/null
+++ b/src/third_party/skia/tests/LayerRasterizerTest.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkDeque.h"
+#include "SkLayerRasterizer.h"
+#include "SkPaint.h"
+#include "SkRasterizer.h"
+#include "Test.h"
+
+class SkReadBuffer;
+
+// Dummy class to place on a paint just to ensure the paint's destructor
+// is called.
+// ONLY to be used by LayerRasterizer_destructor, since other tests may
+// be run in a separate thread, and this class is not threadsafe.
+class DummyRasterizer : public SkRasterizer {
+public:
+ DummyRasterizer()
+ : INHERITED()
+ {
+ // Not threadsafe. Only used in one thread.
+ gCount++;
+ }
+
+ ~DummyRasterizer() {
+ // Not threadsafe. Only used in one thread.
+ gCount--;
+ }
+
+ static int GetCount() { return gCount; }
+
+ SK_DECLARE_NOT_FLATTENABLE_PROCS(DummyRasterizer)
+
+private:
+ static int gCount;
+
+ typedef SkRasterizer INHERITED;
+};
+
+int DummyRasterizer::gCount;
+
+// Check to make sure that the SkPaint in the layer has its destructor called.
+DEF_TEST(LayerRasterizer_destructor, reporter) {
+ {
+ SkPaint paint;
+ paint.setRasterizer(SkNEW(DummyRasterizer))->unref();
+ REPORTER_ASSERT(reporter, DummyRasterizer::GetCount() == 1);
+
+ SkLayerRasterizer::Builder builder;
+ builder.addLayer(paint);
+ }
+ REPORTER_ASSERT(reporter, DummyRasterizer::GetCount() == 0);
+}
+
+class LayerRasterizerTester {
+public:
+ static int CountLayers(const SkLayerRasterizer& layerRasterizer) {
+ return layerRasterizer.fLayers->count();
+ }
+
+ static const SkDeque& GetLayers(const SkLayerRasterizer& layerRasterizer) {
+ return *layerRasterizer.fLayers;
+ }
+};
+
+// MUST stay in sync with definition of SkLayerRasterizer_Rec in SkLayerRasterizer.cpp.
+struct SkLayerRasterizer_Rec {
+ SkPaint fPaint;
+ SkVector fOffset;
+};
+
+static bool equals(const SkLayerRasterizer_Rec& rec1, const SkLayerRasterizer_Rec& rec2) {
+ return rec1.fPaint == rec2.fPaint && rec1.fOffset == rec2.fOffset;
+}
+
+DEF_TEST(LayerRasterizer_copy, reporter) {
+ SkLayerRasterizer::Builder builder;
+ REPORTER_ASSERT(reporter, NULL == builder.snapshotRasterizer());
+ SkPaint paint;
+ // Create a bunch of paints with different flags.
+ for (uint32_t flags = 0x01; flags < SkPaint::kAllFlags; flags <<= 1) {
+ paint.setFlags(flags);
+ builder.addLayer(paint, static_cast<SkScalar>(flags), static_cast<SkScalar>(flags));
+ }
+
+ // Create a layer rasterizer with all the existing layers.
+ SkAutoTUnref<SkLayerRasterizer> firstCopy(builder.snapshotRasterizer());
+
+ // Add one more layer.
+ paint.setFlags(SkPaint::kAllFlags);
+ builder.addLayer(paint);
+
+ SkAutoTUnref<SkLayerRasterizer> oneLarger(builder.snapshotRasterizer());
+ SkAutoTUnref<SkLayerRasterizer> detached(builder.detachRasterizer());
+
+ // Check the counts for consistency.
+ const int largerCount = LayerRasterizerTester::CountLayers(*oneLarger.get());
+ const int smallerCount = LayerRasterizerTester::CountLayers(*firstCopy.get());
+ REPORTER_ASSERT(reporter, largerCount == LayerRasterizerTester::CountLayers(*detached.get()));
+ REPORTER_ASSERT(reporter, smallerCount == largerCount - 1);
+
+ const SkLayerRasterizer_Rec* recFirstCopy = NULL;
+ const SkLayerRasterizer_Rec* recOneLarger = NULL;
+ const SkLayerRasterizer_Rec* recDetached = NULL;
+
+ const SkDeque& layersFirstCopy = LayerRasterizerTester::GetLayers(*firstCopy.get());
+ const SkDeque& layersOneLarger = LayerRasterizerTester::GetLayers(*oneLarger.get());
+ const SkDeque& layersDetached = LayerRasterizerTester::GetLayers(*detached.get());
+
+ // Ensure that our version of SkLayerRasterizer_Rec is the same as the one in
+ // SkLayerRasterizer.cpp - or at least the same size. If the order were switched, we
+ // would fail the test elsewhere.
+ REPORTER_ASSERT(reporter, layersFirstCopy.elemSize() == sizeof(SkLayerRasterizer_Rec));
+ REPORTER_ASSERT(reporter, layersOneLarger.elemSize() == sizeof(SkLayerRasterizer_Rec));
+ REPORTER_ASSERT(reporter, layersDetached.elemSize() == sizeof(SkLayerRasterizer_Rec));
+
+ SkDeque::F2BIter iterFirstCopy(layersFirstCopy);
+ SkDeque::F2BIter iterOneLarger(layersOneLarger);
+ SkDeque::F2BIter iterDetached(layersDetached);
+
+ for (int i = 0; i < largerCount; ++i) {
+ recFirstCopy = static_cast<const SkLayerRasterizer_Rec*>(iterFirstCopy.next());
+ recOneLarger = static_cast<const SkLayerRasterizer_Rec*>(iterOneLarger.next());
+ recDetached = static_cast<const SkLayerRasterizer_Rec*>(iterDetached.next());
+
+ REPORTER_ASSERT(reporter, equals(*recOneLarger, *recDetached));
+ if (smallerCount == i) {
+ REPORTER_ASSERT(reporter, recFirstCopy == NULL);
+ } else {
+ REPORTER_ASSERT(reporter, equals(*recFirstCopy, *recOneLarger));
+ }
+ }
+}
+
+DEF_TEST(LayerRasterizer_detachEmpty, reporter) {
+ SkLayerRasterizer::Builder builder;
+ REPORTER_ASSERT(reporter, NULL == builder.detachRasterizer());
+}
diff --git a/src/third_party/skia/tests/MD5Test.cpp b/src/third_party/skia/tests/MD5Test.cpp
new file mode 100644
index 0000000..efad26d
--- /dev/null
+++ b/src/third_party/skia/tests/MD5Test.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkMD5.h"
+#include "Test.h"
+
+static bool digests_equal(const SkMD5::Digest& expectedDigest, const SkMD5::Digest& computedDigest) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(expectedDigest.data); ++i) {
+ if (expectedDigest.data[i] != computedDigest.data[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void md5_test(const char* string, const SkMD5::Digest& expectedDigest, skiatest::Reporter* reporter) {
+ size_t len = strlen(string);
+
+ // All at once
+ {
+ SkMD5 context;
+ context.update(reinterpret_cast<const uint8_t*>(string), len);
+ SkMD5::Digest digest;
+ context.finish(digest);
+
+ REPORTER_ASSERT(reporter, digests_equal(expectedDigest, digest));
+ }
+
+ // One byte at a time.
+ {
+ SkMD5 context;
+ const uint8_t* data = reinterpret_cast<const uint8_t*>(string);
+ const uint8_t* end = reinterpret_cast<const uint8_t*>(string + len);
+ for (; data < end; ++data) {
+ context.update(data, 1);
+ }
+ SkMD5::Digest digest;
+ context.finish(digest);
+
+ REPORTER_ASSERT(reporter, digests_equal(expectedDigest, digest));
+ }
+}
+
+static struct MD5Test {
+ const char* message;
+ SkMD5::Digest digest;
+} md5_tests[] = {
+ // Reference tests from RFC1321 Section A.5 ( http://www.ietf.org/rfc/rfc1321.txt )
+ { "", {{ 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e }} },
+ { "a", {{ 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 }} },
+ { "abc", {{ 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 }} },
+ { "message digest", {{ 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 }} },
+ { "abcdefghijklmnopqrstuvwxyz", {{ 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b }} },
+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", {{ 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f }} },
+ { "12345678901234567890123456789012345678901234567890123456789012345678901234567890", {{ 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a }} },
+};
+
+DEF_TEST(MD5, reporter) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(md5_tests); ++i) {
+ md5_test(md5_tests[i].message, md5_tests[i].digest, reporter);
+ }
+}
diff --git a/src/third_party/skia/tests/MallocPixelRefTest.cpp b/src/third_party/skia/tests/MallocPixelRefTest.cpp
new file mode 100644
index 0000000..e267d6f
--- /dev/null
+++ b/src/third_party/skia/tests/MallocPixelRefTest.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkData.h"
+#include "SkMallocPixelRef.h"
+#include "Test.h"
+
+static void delete_uint8_proc(void* ptr, void*) {
+ delete[] static_cast<uint8_t*>(ptr);
+}
+
+static void set_to_one_proc(void*, void* context) {
+ *(static_cast<int*>(context)) = 1;
+}
+
+/**
+ * This test contains basic sanity checks concerning SkMallocPixelRef.
+ */
+DEF_TEST(MallocPixelRef, reporter) {
+ REPORTER_ASSERT(reporter, true);
+ SkImageInfo info = SkImageInfo::MakeN32Premul(10, 13);
+ {
+ SkAutoTUnref<SkMallocPixelRef> pr(
+ SkMallocPixelRef::NewAllocate(info, info.minRowBytes() - 1, NULL));
+ // rowbytes too small.
+ REPORTER_ASSERT(reporter, NULL == pr.get());
+ }
+ {
+ size_t rowBytes = info.minRowBytes() - 1;
+ size_t size = info.getSafeSize(rowBytes);
+ SkAutoDataUnref data(SkData::NewUninitialized(size));
+ SkAutoTUnref<SkMallocPixelRef> pr(
+ SkMallocPixelRef::NewWithData(info, rowBytes, NULL, data));
+ // rowbytes too small.
+ REPORTER_ASSERT(reporter, NULL == pr.get());
+ }
+ {
+ size_t rowBytes = info.minRowBytes() + 2;
+ size_t size = info.getSafeSize(rowBytes) - 1;
+ SkAutoDataUnref data(SkData::NewUninitialized(size));
+ SkAutoTUnref<SkMallocPixelRef> pr(
+ SkMallocPixelRef::NewWithData(info, rowBytes, NULL, data));
+ // data too small.
+ REPORTER_ASSERT(reporter, NULL == pr.get());
+ }
+ size_t rowBytes = info.minRowBytes() + 7;
+ size_t size = info.getSafeSize(rowBytes) + 9;
+ {
+ SkAutoMalloc memory(size);
+ SkAutoTUnref<SkMallocPixelRef> pr(
+ SkMallocPixelRef::NewDirect(info, memory.get(), rowBytes, NULL));
+ REPORTER_ASSERT(reporter, pr.get() != NULL);
+ REPORTER_ASSERT(reporter, memory.get() == pr->pixels());
+ }
+ {
+ SkAutoTUnref<SkMallocPixelRef> pr(
+ SkMallocPixelRef::NewAllocate(info, rowBytes, NULL));
+ REPORTER_ASSERT(reporter, pr.get() != NULL);
+ REPORTER_ASSERT(reporter, pr->pixels());
+ }
+ {
+ void* addr = static_cast<void*>(new uint8_t[size]);
+ SkAutoTUnref<SkMallocPixelRef> pr(
+ SkMallocPixelRef::NewWithProc(info, rowBytes, NULL, addr,
+ delete_uint8_proc, NULL));
+ REPORTER_ASSERT(reporter, pr.get() != NULL);
+ REPORTER_ASSERT(reporter, addr == pr->pixels());
+ }
+ {
+ int x = 0;
+ SkAutoMalloc memory(size);
+ SkAutoTUnref<SkMallocPixelRef> pr(
+ SkMallocPixelRef::NewWithProc(info, rowBytes, NULL,
+ memory.get(), set_to_one_proc,
+ static_cast<void*>(&x)));
+ REPORTER_ASSERT(reporter, pr.get() != NULL);
+ REPORTER_ASSERT(reporter, memory.get() == pr->pixels());
+ REPORTER_ASSERT(reporter, 0 == x);
+ pr.reset(NULL);
+ // make sure that set_to_one_proc was called.
+ REPORTER_ASSERT(reporter, 1 == x);
+ }
+ {
+ void* addr = static_cast<void*>(new uint8_t[size]);
+ REPORTER_ASSERT(reporter, addr != NULL);
+ SkAutoTUnref<SkMallocPixelRef> pr(
+ SkMallocPixelRef::NewWithProc(info, rowBytes, NULL, addr,
+ delete_uint8_proc, NULL));
+ REPORTER_ASSERT(reporter, addr == pr->pixels());
+ }
+ {
+ SkAutoDataUnref data(SkData::NewUninitialized(size));
+ SkData* dataPtr = data.get();
+ REPORTER_ASSERT(reporter, dataPtr->unique());
+ SkAutoTUnref<SkMallocPixelRef> pr(
+ SkMallocPixelRef::NewWithData(info, rowBytes, NULL, data.get()));
+ REPORTER_ASSERT(reporter, !(dataPtr->unique()));
+ data.reset(NULL);
+ REPORTER_ASSERT(reporter, dataPtr->unique());
+ REPORTER_ASSERT(reporter, dataPtr->data() == pr->pixels());
+ }
+}
diff --git a/src/third_party/skia/tests/MathTest.cpp b/src/third_party/skia/tests/MathTest.cpp
new file mode 100644
index 0000000..2053936
--- /dev/null
+++ b/src/third_party/skia/tests/MathTest.cpp
@@ -0,0 +1,603 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkColorPriv.h"
+#include "SkEndian.h"
+#include "SkFloatBits.h"
+#include "SkFloatingPoint.h"
+#include "SkMathPriv.h"
+#include "SkPoint.h"
+#include "SkRandom.h"
+#include "Test.h"
+
+static void test_clz(skiatest::Reporter* reporter) {
+ REPORTER_ASSERT(reporter, 32 == SkCLZ(0));
+ REPORTER_ASSERT(reporter, 31 == SkCLZ(1));
+ REPORTER_ASSERT(reporter, 1 == SkCLZ(1 << 30));
+ REPORTER_ASSERT(reporter, 0 == SkCLZ(~0U));
+
+ SkRandom rand;
+ for (int i = 0; i < 1000; ++i) {
+ uint32_t mask = rand.nextU();
+ // need to get some zeros for testing, but in some obscure way so the
+ // compiler won't "see" that, and work-around calling the functions.
+ mask >>= (mask & 31);
+ int intri = SkCLZ(mask);
+ int porta = SkCLZ_portable(mask);
+ REPORTER_ASSERT(reporter, intri == porta);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static float sk_fsel(float pred, float result_ge, float result_lt) {
+ return pred >= 0 ? result_ge : result_lt;
+}
+
+static float fast_floor(float x) {
+// float big = sk_fsel(x, 0x1.0p+23, -0x1.0p+23);
+ float big = sk_fsel(x, (float)(1 << 23), -(float)(1 << 23));
+ return (float)(x + big) - big;
+}
+
+static float std_floor(float x) {
+ return sk_float_floor(x);
+}
+
+static void test_floor_value(skiatest::Reporter* reporter, float value) {
+ float fast = fast_floor(value);
+ float std = std_floor(value);
+ REPORTER_ASSERT(reporter, std == fast);
+// SkDebugf("value[%1.9f] std[%g] fast[%g] equal[%d]\n",
+// value, std, fast, std == fast);
+}
+
+static void test_floor(skiatest::Reporter* reporter) {
+ static const float gVals[] = {
+ 0, 1, 1.1f, 1.01f, 1.001f, 1.0001f, 1.00001f, 1.000001f, 1.0000001f
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gVals); ++i) {
+ test_floor_value(reporter, gVals[i]);
+// test_floor_value(reporter, -gVals[i]);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// test that SkMul16ShiftRound and SkMulDiv255Round return the same result
+static void test_muldivround(skiatest::Reporter* reporter) {
+#if 0
+ // this "complete" test is too slow, so we test a random sampling of it
+
+ for (int a = 0; a <= 32767; ++a) {
+ for (int b = 0; b <= 32767; ++b) {
+ unsigned prod0 = SkMul16ShiftRound(a, b, 8);
+ unsigned prod1 = SkMulDiv255Round(a, b);
+ SkASSERT(prod0 == prod1);
+ }
+ }
+#endif
+
+ SkRandom rand;
+ for (int i = 0; i < 10000; ++i) {
+ unsigned a = rand.nextU() & 0x7FFF;
+ unsigned b = rand.nextU() & 0x7FFF;
+
+ unsigned prod0 = SkMul16ShiftRound(a, b, 8);
+ unsigned prod1 = SkMulDiv255Round(a, b);
+
+ REPORTER_ASSERT(reporter, prod0 == prod1);
+ }
+}
+
+static float float_blend(int src, int dst, float unit) {
+ return dst + (src - dst) * unit;
+}
+
+static int blend31(int src, int dst, int a31) {
+ return dst + ((src - dst) * a31 * 2114 >> 16);
+ // return dst + ((src - dst) * a31 * 33 >> 10);
+}
+
+static int blend31_slow(int src, int dst, int a31) {
+ int prod = src * a31 + (31 - a31) * dst + 16;
+ prod = (prod + (prod >> 5)) >> 5;
+ return prod;
+}
+
+static int blend31_round(int src, int dst, int a31) {
+ int prod = (src - dst) * a31 + 16;
+ prod = (prod + (prod >> 5)) >> 5;
+ return dst + prod;
+}
+
+static int blend31_old(int src, int dst, int a31) {
+ a31 += a31 >> 4;
+ return dst + ((src - dst) * a31 >> 5);
+}
+
+// suppress unused code warning
+static int (*blend_functions[])(int, int, int) = {
+ blend31,
+ blend31_slow,
+ blend31_round,
+ blend31_old
+};
+
+static void test_blend31() {
+ int failed = 0;
+ int death = 0;
+ if (false) { // avoid bit rot, suppress warning
+ failed = (*blend_functions[0])(0,0,0);
+ }
+ for (int src = 0; src <= 255; src++) {
+ for (int dst = 0; dst <= 255; dst++) {
+ for (int a = 0; a <= 31; a++) {
+// int r0 = blend31(src, dst, a);
+// int r0 = blend31_round(src, dst, a);
+// int r0 = blend31_old(src, dst, a);
+ int r0 = blend31_slow(src, dst, a);
+
+ float f = float_blend(src, dst, a / 31.f);
+ int r1 = (int)f;
+ int r2 = SkScalarRoundToInt(f);
+
+ if (r0 != r1 && r0 != r2) {
+ SkDebugf("src:%d dst:%d a:%d result:%d float:%g\n",
+ src, dst, a, r0, f);
+ failed += 1;
+ }
+ if (r0 > 255) {
+ death += 1;
+ SkDebugf("death src:%d dst:%d a:%d result:%d float:%g\n",
+ src, dst, a, r0, f);
+ }
+ }
+ }
+ }
+ SkDebugf("---- failed %d death %d\n", failed, death);
+}
+
+static void test_blend(skiatest::Reporter* reporter) {
+ for (int src = 0; src <= 255; src++) {
+ for (int dst = 0; dst <= 255; dst++) {
+ for (int a = 0; a <= 255; a++) {
+ int r0 = SkAlphaBlend255(src, dst, a);
+ float f1 = float_blend(src, dst, a / 255.f);
+ int r1 = SkScalarRoundToInt(f1);
+
+ if (r0 != r1) {
+ float diff = sk_float_abs(f1 - r1);
+ diff = sk_float_abs(diff - 0.5f);
+ if (diff > (1 / 255.f)) {
+#ifdef SK_DEBUG
+ SkDebugf("src:%d dst:%d a:%d result:%d float:%g\n",
+ src, dst, a, r0, f1);
+#endif
+ REPORTER_ASSERT(reporter, false);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void check_length(skiatest::Reporter* reporter,
+ const SkPoint& p, SkScalar targetLen) {
+ float x = SkScalarToFloat(p.fX);
+ float y = SkScalarToFloat(p.fY);
+ float len = sk_float_sqrt(x*x + y*y);
+
+ len /= SkScalarToFloat(targetLen);
+
+ REPORTER_ASSERT(reporter, len > 0.999f && len < 1.001f);
+}
+
+static float nextFloat(SkRandom& rand) {
+ SkFloatIntUnion data;
+ data.fSignBitInt = rand.nextU();
+ return data.fFloat;
+}
+
+/* returns true if a == b as resulting from (int)x. Since it is undefined
+ what to do if the float exceeds 2^32-1, we check for that explicitly.
+ */
+static bool equal_float_native_skia(float x, uint32_t ni, uint32_t si) {
+ if (!(x == x)) { // NAN
+ return ((int32_t)si) == SK_MaxS32 || ((int32_t)si) == SK_MinS32;
+ }
+ // for out of range, C is undefined, but skia always should return NaN32
+ if (x > SK_MaxS32) {
+ return ((int32_t)si) == SK_MaxS32;
+ }
+ if (x < -SK_MaxS32) {
+ return ((int32_t)si) == SK_MinS32;
+ }
+ return si == ni;
+}
+
+static void assert_float_equal(skiatest::Reporter* reporter, const char op[],
+ float x, uint32_t ni, uint32_t si) {
+ if (!equal_float_native_skia(x, ni, si)) {
+ ERRORF(reporter, "%s float %g bits %x native %x skia %x\n",
+ op, x, SkFloat2Bits(x), ni, si);
+ }
+}
+
+static void test_float_cast(skiatest::Reporter* reporter, float x) {
+ int ix = (int)x;
+ int iix = SkFloatToIntCast(x);
+ assert_float_equal(reporter, "cast", x, ix, iix);
+}
+
+static void test_float_floor(skiatest::Reporter* reporter, float x) {
+ int ix = (int)floor(x);
+ int iix = SkFloatToIntFloor(x);
+ assert_float_equal(reporter, "floor", x, ix, iix);
+}
+
+static void test_float_round(skiatest::Reporter* reporter, float x) {
+ double xx = x + 0.5; // need intermediate double to avoid temp loss
+ int ix = (int)floor(xx);
+ int iix = SkFloatToIntRound(x);
+ assert_float_equal(reporter, "round", x, ix, iix);
+}
+
+static void test_float_ceil(skiatest::Reporter* reporter, float x) {
+ int ix = (int)ceil(x);
+ int iix = SkFloatToIntCeil(x);
+ assert_float_equal(reporter, "ceil", x, ix, iix);
+}
+
+static void test_float_conversions(skiatest::Reporter* reporter, float x) {
+ test_float_cast(reporter, x);
+ test_float_floor(reporter, x);
+ test_float_round(reporter, x);
+ test_float_ceil(reporter, x);
+}
+
+static void test_int2float(skiatest::Reporter* reporter, int ival) {
+ float x0 = (float)ival;
+ float x1 = SkIntToFloatCast(ival);
+ REPORTER_ASSERT(reporter, x0 == x1);
+}
+
+static void unittest_fastfloat(skiatest::Reporter* reporter) {
+ SkRandom rand;
+ size_t i;
+
+ static const float gFloats[] = {
+ 0.f, 1.f, 0.5f, 0.499999f, 0.5000001f, 1.f/3,
+ 0.000000001f, 1000000000.f, // doesn't overflow
+ 0.0000000001f, 10000000000.f // does overflow
+ };
+ for (i = 0; i < SK_ARRAY_COUNT(gFloats); i++) {
+ test_float_conversions(reporter, gFloats[i]);
+ test_float_conversions(reporter, -gFloats[i]);
+ }
+
+ for (int outer = 0; outer < 100; outer++) {
+ rand.setSeed(outer);
+ for (i = 0; i < 100000; i++) {
+ float x = nextFloat(rand);
+ test_float_conversions(reporter, x);
+ }
+
+ test_int2float(reporter, 0);
+ test_int2float(reporter, 1);
+ test_int2float(reporter, -1);
+ for (i = 0; i < 100000; i++) {
+ // for now only test ints that are 24bits or less, since we don't
+ // round (down) large ints the same as IEEE...
+ int ival = rand.nextU() & 0xFFFFFF;
+ test_int2float(reporter, ival);
+ test_int2float(reporter, -ival);
+ }
+ }
+}
+
+static float make_zero() {
+ return sk_float_sin(0);
+}
+
+static void unittest_isfinite(skiatest::Reporter* reporter) {
+ float nan = sk_float_asin(2);
+ float inf = 1.0f / make_zero();
+ float big = 3.40282e+038f;
+
+ REPORTER_ASSERT(reporter, !SkScalarIsNaN(inf));
+ REPORTER_ASSERT(reporter, !SkScalarIsNaN(-inf));
+ REPORTER_ASSERT(reporter, !SkScalarIsFinite(inf));
+ REPORTER_ASSERT(reporter, !SkScalarIsFinite(-inf));
+
+ REPORTER_ASSERT(reporter, SkScalarIsNaN(nan));
+ REPORTER_ASSERT(reporter, !SkScalarIsNaN(big));
+ REPORTER_ASSERT(reporter, !SkScalarIsNaN(-big));
+ REPORTER_ASSERT(reporter, !SkScalarIsNaN(0));
+
+ REPORTER_ASSERT(reporter, !SkScalarIsFinite(nan));
+ REPORTER_ASSERT(reporter, SkScalarIsFinite(big));
+ REPORTER_ASSERT(reporter, SkScalarIsFinite(-big));
+ REPORTER_ASSERT(reporter, SkScalarIsFinite(0));
+}
+
+static void test_muldiv255(skiatest::Reporter* reporter) {
+ for (int a = 0; a <= 255; a++) {
+ for (int b = 0; b <= 255; b++) {
+ int ab = a * b;
+ float s = ab / 255.0f;
+ int round = (int)floorf(s + 0.5f);
+ int trunc = (int)floorf(s);
+
+ int iround = SkMulDiv255Round(a, b);
+ int itrunc = SkMulDiv255Trunc(a, b);
+
+ REPORTER_ASSERT(reporter, iround == round);
+ REPORTER_ASSERT(reporter, itrunc == trunc);
+
+ REPORTER_ASSERT(reporter, itrunc <= iround);
+ REPORTER_ASSERT(reporter, iround <= a);
+ REPORTER_ASSERT(reporter, iround <= b);
+ }
+ }
+}
+
+static void test_muldiv255ceiling(skiatest::Reporter* reporter) {
+ for (int c = 0; c <= 255; c++) {
+ for (int a = 0; a <= 255; a++) {
+ int product = (c * a + 255);
+ int expected_ceiling = (product + (product >> 8)) >> 8;
+ int webkit_ceiling = (c * a + 254) / 255;
+ REPORTER_ASSERT(reporter, expected_ceiling == webkit_ceiling);
+ int skia_ceiling = SkMulDiv255Ceiling(c, a);
+ REPORTER_ASSERT(reporter, skia_ceiling == webkit_ceiling);
+ }
+ }
+}
+
+static void test_copysign(skiatest::Reporter* reporter) {
+ static const int32_t gTriples[] = {
+ // x, y, expected result
+ 0, 0, 0,
+ 0, 1, 0,
+ 0, -1, 0,
+ 1, 0, 1,
+ 1, 1, 1,
+ 1, -1, -1,
+ -1, 0, 1,
+ -1, 1, 1,
+ -1, -1, -1,
+ };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gTriples); i += 3) {
+ REPORTER_ASSERT(reporter,
+ SkCopySign32(gTriples[i], gTriples[i+1]) == gTriples[i+2]);
+ float x = (float)gTriples[i];
+ float y = (float)gTriples[i+1];
+ float expected = (float)gTriples[i+2];
+ REPORTER_ASSERT(reporter, sk_float_copysign(x, y) == expected);
+ }
+
+ SkRandom rand;
+ for (int j = 0; j < 1000; j++) {
+ int ix = rand.nextS();
+ REPORTER_ASSERT(reporter, SkCopySign32(ix, ix) == ix);
+ REPORTER_ASSERT(reporter, SkCopySign32(ix, -ix) == -ix);
+ REPORTER_ASSERT(reporter, SkCopySign32(-ix, ix) == ix);
+ REPORTER_ASSERT(reporter, SkCopySign32(-ix, -ix) == -ix);
+
+ SkScalar sx = rand.nextSScalar1();
+ REPORTER_ASSERT(reporter, SkScalarCopySign(sx, sx) == sx);
+ REPORTER_ASSERT(reporter, SkScalarCopySign(sx, -sx) == -sx);
+ REPORTER_ASSERT(reporter, SkScalarCopySign(-sx, sx) == sx);
+ REPORTER_ASSERT(reporter, SkScalarCopySign(-sx, -sx) == -sx);
+ }
+}
+
+DEF_TEST(Math, reporter) {
+ int i;
+ SkRandom rand;
+
+ // these should assert
+#if 0
+ SkToS8(128);
+ SkToS8(-129);
+ SkToU8(256);
+ SkToU8(-5);
+
+ SkToS16(32768);
+ SkToS16(-32769);
+ SkToU16(65536);
+ SkToU16(-5);
+
+ if (sizeof(size_t) > 4) {
+ SkToS32(4*1024*1024);
+ SkToS32(-4*1024*1024);
+ SkToU32(5*1024*1024);
+ SkToU32(-5);
+ }
+#endif
+
+ test_muldiv255(reporter);
+ test_muldiv255ceiling(reporter);
+ test_copysign(reporter);
+
+ {
+ SkScalar x = SK_ScalarNaN;
+ REPORTER_ASSERT(reporter, SkScalarIsNaN(x));
+ }
+
+ for (i = 0; i < 1000; i++) {
+ int value = rand.nextS16();
+ int max = rand.nextU16();
+
+ int clamp = SkClampMax(value, max);
+ int clamp2 = value < 0 ? 0 : (value > max ? max : value);
+ REPORTER_ASSERT(reporter, clamp == clamp2);
+ }
+
+ for (i = 0; i < 10000; i++) {
+ SkPoint p;
+
+ // These random values are being treated as 32-bit-patterns, not as
+ // ints; calling SkIntToScalar() here produces crashes.
+ p.setLength((SkScalar) rand.nextS(),
+ (SkScalar) rand.nextS(),
+ SK_Scalar1);
+ check_length(reporter, p, SK_Scalar1);
+ p.setLength((SkScalar) (rand.nextS() >> 13),
+ (SkScalar) (rand.nextS() >> 13),
+ SK_Scalar1);
+ check_length(reporter, p, SK_Scalar1);
+ }
+
+ {
+ SkFixed result = SkFixedDiv(100, 100);
+ REPORTER_ASSERT(reporter, result == SK_Fixed1);
+ result = SkFixedDiv(1, SK_Fixed1);
+ REPORTER_ASSERT(reporter, result == 1);
+ }
+
+ unittest_fastfloat(reporter);
+ unittest_isfinite(reporter);
+
+ for (i = 0; i < 10000; i++) {
+ SkFixed numer = rand.nextS();
+ SkFixed denom = rand.nextS();
+ SkFixed result = SkFixedDiv(numer, denom);
+ int64_t check = ((int64_t)numer << 16) / denom;
+
+ (void)SkCLZ(numer);
+ (void)SkCLZ(denom);
+
+ REPORTER_ASSERT(reporter, result != (SkFixed)SK_NaN32);
+ if (check > SK_MaxS32) {
+ check = SK_MaxS32;
+ } else if (check < -SK_MaxS32) {
+ check = SK_MinS32;
+ }
+ REPORTER_ASSERT(reporter, result == (int32_t)check);
+ }
+
+ test_blend(reporter);
+
+ if (false) test_floor(reporter);
+
+ // disable for now
+ if (false) test_blend31(); // avoid bit rot, suppress warning
+
+ test_muldivround(reporter);
+ test_clz(reporter);
+}
+
+template <typename T> struct PairRec {
+ T fYin;
+ T fYang;
+};
+
+DEF_TEST(TestEndian, reporter) {
+ static const PairRec<uint16_t> g16[] = {
+ { 0x0, 0x0 },
+ { 0xFFFF, 0xFFFF },
+ { 0x1122, 0x2211 },
+ };
+ static const PairRec<uint32_t> g32[] = {
+ { 0x0, 0x0 },
+ { 0xFFFFFFFF, 0xFFFFFFFF },
+ { 0x11223344, 0x44332211 },
+ };
+ static const PairRec<uint64_t> g64[] = {
+ { 0x0, 0x0 },
+ { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL },
+ { 0x1122334455667788ULL, 0x8877665544332211ULL },
+ };
+
+ REPORTER_ASSERT(reporter, 0x1122 == SkTEndianSwap16<0x2211>::value);
+ REPORTER_ASSERT(reporter, 0x11223344 == SkTEndianSwap32<0x44332211>::value);
+ REPORTER_ASSERT(reporter, 0x1122334455667788ULL == SkTEndianSwap64<0x8877665544332211ULL>::value);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(g16); ++i) {
+ REPORTER_ASSERT(reporter, g16[i].fYang == SkEndianSwap16(g16[i].fYin));
+ }
+ for (size_t i = 0; i < SK_ARRAY_COUNT(g32); ++i) {
+ REPORTER_ASSERT(reporter, g32[i].fYang == SkEndianSwap32(g32[i].fYin));
+ }
+ for (size_t i = 0; i < SK_ARRAY_COUNT(g64); ++i) {
+ REPORTER_ASSERT(reporter, g64[i].fYang == SkEndianSwap64(g64[i].fYin));
+ }
+}
+
+template <typename T>
+static void test_divmod(skiatest::Reporter* r) {
+ const struct {
+ T numer;
+ T denom;
+ } kEdgeCases[] = {
+ {(T)17, (T)17},
+ {(T)17, (T)4},
+ {(T)0, (T)17},
+ // For unsigned T these negatives are just some large numbers. Doesn't hurt to test them.
+ {(T)-17, (T)-17},
+ {(T)-17, (T)4},
+ {(T)17, (T)-4},
+ {(T)-17, (T)-4},
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(kEdgeCases); i++) {
+ const T numer = kEdgeCases[i].numer;
+ const T denom = kEdgeCases[i].denom;
+ T div, mod;
+ SkTDivMod(numer, denom, &div, &mod);
+ REPORTER_ASSERT(r, numer/denom == div);
+ REPORTER_ASSERT(r, numer%denom == mod);
+ }
+
+ SkRandom rand;
+ for (size_t i = 0; i < 10000; i++) {
+ const T numer = (T)rand.nextS();
+ T denom = 0;
+ while (0 == denom) {
+ denom = (T)rand.nextS();
+ }
+ T div, mod;
+ SkTDivMod(numer, denom, &div, &mod);
+ REPORTER_ASSERT(r, numer/denom == div);
+ REPORTER_ASSERT(r, numer%denom == mod);
+ }
+}
+
+DEF_TEST(divmod_u8, r) {
+ test_divmod<uint8_t>(r);
+}
+
+DEF_TEST(divmod_u16, r) {
+ test_divmod<uint16_t>(r);
+}
+
+DEF_TEST(divmod_u32, r) {
+ test_divmod<uint32_t>(r);
+}
+
+DEF_TEST(divmod_u64, r) {
+ test_divmod<uint64_t>(r);
+}
+
+DEF_TEST(divmod_s8, r) {
+ test_divmod<int8_t>(r);
+}
+
+DEF_TEST(divmod_s16, r) {
+ test_divmod<int16_t>(r);
+}
+
+DEF_TEST(divmod_s32, r) {
+ test_divmod<int32_t>(r);
+}
+
+DEF_TEST(divmod_s64, r) {
+ test_divmod<int64_t>(r);
+}
diff --git a/src/third_party/skia/tests/Matrix44Test.cpp b/src/third_party/skia/tests/Matrix44Test.cpp
new file mode 100644
index 0000000..0bd4a8b
--- /dev/null
+++ b/src/third_party/skia/tests/Matrix44Test.cpp
@@ -0,0 +1,659 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkMatrix44.h"
+#include "Test.h"
+
+static bool nearly_equal_double(double a, double b) {
+ const double tolerance = 1e-7;
+ double diff = a - b;
+ if (diff < 0)
+ diff = -diff;
+ return diff <= tolerance;
+}
+
+static bool nearly_equal_mscalar(SkMScalar a, SkMScalar b) {
+ const SkMScalar tolerance = SK_MScalar1 / 200000;
+
+ return SkTAbs<SkMScalar>(a - b) <= tolerance;
+}
+
+static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
+ const SkScalar tolerance = SK_Scalar1 / 200000;
+ return SkScalarAbs(a - b) <= tolerance;
+}
+
+template <typename T> void assert16(skiatest::Reporter* reporter, const T data[],
+ T m0, T m1, T m2, T m3,
+ T m4, T m5, T m6, T m7,
+ T m8, T m9, T m10, T m11,
+ T m12, T m13, T m14, T m15) {
+ REPORTER_ASSERT(reporter, data[0] == m0);
+ REPORTER_ASSERT(reporter, data[1] == m1);
+ REPORTER_ASSERT(reporter, data[2] == m2);
+ REPORTER_ASSERT(reporter, data[3] == m3);
+
+ REPORTER_ASSERT(reporter, data[4] == m4);
+ REPORTER_ASSERT(reporter, data[5] == m5);
+ REPORTER_ASSERT(reporter, data[6] == m6);
+ REPORTER_ASSERT(reporter, data[7] == m7);
+
+ REPORTER_ASSERT(reporter, data[8] == m8);
+ REPORTER_ASSERT(reporter, data[9] == m9);
+ REPORTER_ASSERT(reporter, data[10] == m10);
+ REPORTER_ASSERT(reporter, data[11] == m11);
+
+ REPORTER_ASSERT(reporter, data[12] == m12);
+ REPORTER_ASSERT(reporter, data[13] == m13);
+ REPORTER_ASSERT(reporter, data[14] == m14);
+ REPORTER_ASSERT(reporter, data[15] == m15);
+}
+
+static bool nearly_equal(const SkMatrix44& a, const SkMatrix44& b) {
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ if (!nearly_equal_mscalar(a.get(i, j), b.get(i, j))) {
+ SkDebugf("not equal %g %g\n", a.get(i, j), b.get(i, j));
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool is_identity(const SkMatrix44& m) {
+ SkMatrix44 identity(SkMatrix44::kIdentity_Constructor);
+ return nearly_equal(m, identity);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static bool bits_isonly(int value, int mask) {
+ return 0 == (value & ~mask);
+}
+
+static void test_constructor(skiatest::Reporter* reporter) {
+ // Allocate a matrix on the heap
+ SkMatrix44* placeholderMatrix = new SkMatrix44(SkMatrix44::kUninitialized_Constructor);
+ SkAutoTDelete<SkMatrix44> deleteMe(placeholderMatrix);
+
+ for (int row = 0; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ placeholderMatrix->setDouble(row, col, row * col);
+ }
+ }
+
+ // Use placement-new syntax to trigger the constructor on top of the heap
+ // address we already initialized. This allows us to check that the
+ // constructor did avoid initializing the matrix contents.
+ SkMatrix44* testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kUninitialized_Constructor);
+ REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
+ REPORTER_ASSERT(reporter, !testMatrix->isIdentity());
+ for (int row = 0; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ REPORTER_ASSERT(reporter, nearly_equal_double(row * col, testMatrix->getDouble(row, col)));
+ }
+ }
+
+ // Verify that kIdentity_Constructor really does initialize to an identity matrix.
+ testMatrix = 0;
+ testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kIdentity_Constructor);
+ REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
+ REPORTER_ASSERT(reporter, testMatrix->isIdentity());
+ REPORTER_ASSERT(reporter, *testMatrix == SkMatrix44::I());
+}
+
+static void test_translate(skiatest::Reporter* reporter) {
+ SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
+
+ mat.setTranslate(0, 0, 0);
+ REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
+ mat.setTranslate(1, 2, 3);
+ REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kTranslate_Mask));
+ REPORTER_ASSERT(reporter, mat.invert(&inverse));
+ REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kTranslate_Mask));
+
+ SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 c(SkMatrix44::kUninitialized_Constructor);
+ a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
+ b.setTranslate(10, 11, 12);
+
+ c.setConcat(a, b);
+ mat = a;
+ mat.preTranslate(10, 11, 12);
+ REPORTER_ASSERT(reporter, mat == c);
+
+ c.setConcat(b, a);
+ mat = a;
+ mat.postTranslate(10, 11, 12);
+ REPORTER_ASSERT(reporter, mat == c);
+}
+
+static void test_scale(skiatest::Reporter* reporter) {
+ SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
+
+ mat.setScale(1, 1, 1);
+ REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
+ mat.setScale(1, 2, 3);
+ REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kScale_Mask));
+ REPORTER_ASSERT(reporter, mat.invert(&inverse));
+ REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kScale_Mask));
+
+ SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 c(SkMatrix44::kUninitialized_Constructor);
+ a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
+ b.setScale(10, 11, 12);
+
+ c.setConcat(a, b);
+ mat = a;
+ mat.preScale(10, 11, 12);
+ REPORTER_ASSERT(reporter, mat == c);
+
+ c.setConcat(b, a);
+ mat = a;
+ mat.postScale(10, 11, 12);
+ REPORTER_ASSERT(reporter, mat == c);
+}
+
+static void make_i(SkMatrix44* mat) { mat->setIdentity(); }
+static void make_t(SkMatrix44* mat) { mat->setTranslate(1, 2, 3); }
+static void make_s(SkMatrix44* mat) { mat->setScale(1, 2, 3); }
+static void make_st(SkMatrix44* mat) {
+ mat->setScale(1, 2, 3);
+ mat->postTranslate(1, 2, 3);
+}
+static void make_a(SkMatrix44* mat) {
+ mat->setRotateDegreesAbout(1, 2, 3, 45);
+}
+static void make_p(SkMatrix44* mat) {
+ SkMScalar data[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ };
+ mat->setRowMajor(data);
+}
+
+typedef void (*Make44Proc)(SkMatrix44*);
+
+static const Make44Proc gMakeProcs[] = {
+ make_i, make_t, make_s, make_st, make_a, make_p
+};
+
+static void test_map2(skiatest::Reporter* reporter, const SkMatrix44& mat) {
+ SkMScalar src2[] = { 1, 2 };
+ SkMScalar src4[] = { src2[0], src2[1], 0, 1 };
+ SkMScalar dstA[4], dstB[4];
+
+ for (int i = 0; i < 4; ++i) {
+ dstA[i] = 123456789;
+ dstB[i] = 987654321;
+ }
+
+ mat.map2(src2, 1, dstA);
+ mat.mapMScalars(src4, dstB);
+
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter, dstA[i] == dstB[i]);
+ }
+}
+
+static void test_map2(skiatest::Reporter* reporter) {
+ SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProcs); ++i) {
+ gMakeProcs[i](&mat);
+ test_map2(reporter, mat);
+ }
+}
+
+static void test_gettype(skiatest::Reporter* reporter) {
+ SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
+
+ REPORTER_ASSERT(reporter, matrix.isIdentity());
+ REPORTER_ASSERT(reporter, SkMatrix44::kIdentity_Mask == matrix.getType());
+
+ int expectedMask;
+
+ matrix.set(1, 1, 0);
+ expectedMask = SkMatrix44::kScale_Mask;
+ REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
+
+ matrix.set(0, 3, 1); // translate-x
+ expectedMask |= SkMatrix44::kTranslate_Mask;
+ REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
+
+ matrix.set(2, 0, 1);
+ expectedMask |= SkMatrix44::kAffine_Mask;
+ REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
+
+ matrix.set(3, 2, 1);
+ REPORTER_ASSERT(reporter, matrix.getType() & SkMatrix44::kPerspective_Mask);
+
+ // ensure that negative zero is treated as zero
+ SkMScalar dx = 0;
+ SkMScalar dy = 0;
+ SkMScalar dz = 0;
+ matrix.setTranslate(-dx, -dy, -dz);
+ REPORTER_ASSERT(reporter, matrix.isIdentity());
+ matrix.preTranslate(-dx, -dy, -dz);
+ REPORTER_ASSERT(reporter, matrix.isIdentity());
+ matrix.postTranslate(-dx, -dy, -dz);
+ REPORTER_ASSERT(reporter, matrix.isIdentity());
+}
+
+static void test_common_angles(skiatest::Reporter* reporter) {
+ SkMatrix44 rot(SkMatrix44::kUninitialized_Constructor);
+ // Test precision of rotation in common cases
+ int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
+ for (int i = 0; i < 9; ++i) {
+ rot.setRotateDegreesAbout(0, 0, -1, SkIntToScalar(common_angles[i]));
+
+ SkMatrix rot3x3 = rot;
+ REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
+ }
+}
+
+static void test_concat(skiatest::Reporter* reporter) {
+ int i;
+ SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 c(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 d(SkMatrix44::kUninitialized_Constructor);
+
+ a.setTranslate(10, 10, 10);
+ b.setScale(2, 2, 2);
+
+ SkScalar src[8] = {
+ 0, 0, 0, 1,
+ 1, 1, 1, 1
+ };
+ SkScalar dst[8];
+
+ c.setConcat(a, b);
+
+ d = a;
+ d.preConcat(b);
+ REPORTER_ASSERT(reporter, d == c);
+
+ c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
+ for (i = 0; i < 3; ++i) {
+ REPORTER_ASSERT(reporter, 10 == dst[i]);
+ REPORTER_ASSERT(reporter, 12 == dst[i + 4]);
+ }
+
+ c.setConcat(b, a);
+
+ d = a;
+ d.postConcat(b);
+ REPORTER_ASSERT(reporter, d == c);
+
+ c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
+ for (i = 0; i < 3; ++i) {
+ REPORTER_ASSERT(reporter, 20 == dst[i]);
+ REPORTER_ASSERT(reporter, 22 == dst[i + 4]);
+ }
+}
+
+static void test_determinant(skiatest::Reporter* reporter) {
+ SkMatrix44 a(SkMatrix44::kIdentity_Constructor);
+ REPORTER_ASSERT(reporter, nearly_equal_double(1, a.determinant()));
+ a.set(1, 1, 2);
+ REPORTER_ASSERT(reporter, nearly_equal_double(2, a.determinant()));
+ SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
+ REPORTER_ASSERT(reporter, a.invert(&b));
+ REPORTER_ASSERT(reporter, nearly_equal_double(0.5, b.determinant()));
+ SkMatrix44 c = b = a;
+ c.set(0, 1, 4);
+ b.set(1, 0, 4);
+ REPORTER_ASSERT(reporter,
+ nearly_equal_double(a.determinant(),
+ b.determinant()));
+ SkMatrix44 d = a;
+ d.set(0, 0, 8);
+ REPORTER_ASSERT(reporter, nearly_equal_double(16, d.determinant()));
+
+ SkMatrix44 e = a;
+ e.postConcat(d);
+ REPORTER_ASSERT(reporter, nearly_equal_double(32, e.determinant()));
+ e.set(0, 0, 0);
+ REPORTER_ASSERT(reporter, nearly_equal_double(0, e.determinant()));
+}
+
+static void test_invert(skiatest::Reporter* reporter) {
+ SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
+ double inverseData[16];
+
+ SkMatrix44 identity(SkMatrix44::kIdentity_Constructor);
+ identity.invert(&inverse);
+ inverse.asRowMajord(inverseData);
+ assert16<double>(reporter, inverseData,
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
+
+ SkMatrix44 translation(SkMatrix44::kUninitialized_Constructor);
+ translation.setTranslate(2, 3, 4);
+ translation.invert(&inverse);
+ inverse.asRowMajord(inverseData);
+ assert16<double>(reporter, inverseData,
+ 1, 0, 0, -2,
+ 0, 1, 0, -3,
+ 0, 0, 1, -4,
+ 0, 0, 0, 1);
+
+ SkMatrix44 scale(SkMatrix44::kUninitialized_Constructor);
+ scale.setScale(2, 4, 8);
+ scale.invert(&inverse);
+ inverse.asRowMajord(inverseData);
+ assert16<double>(reporter, inverseData,
+ 0.5, 0, 0, 0,
+ 0, 0.25, 0, 0,
+ 0, 0, 0.125, 0,
+ 0, 0, 0, 1);
+
+ SkMatrix44 scaleTranslation(SkMatrix44::kUninitialized_Constructor);
+ scaleTranslation.setScale(10, 100, 1000);
+ scaleTranslation.preTranslate(2, 3, 4);
+ scaleTranslation.invert(&inverse);
+ inverse.asRowMajord(inverseData);
+ assert16<double>(reporter, inverseData,
+ 0.1, 0, 0, -2,
+ 0, 0.01, 0, -3,
+ 0, 0, 0.001, -4,
+ 0, 0, 0, 1);
+
+ SkMatrix44 rotation(SkMatrix44::kUninitialized_Constructor);
+ rotation.setRotateDegreesAbout(0, 0, 1, 90);
+ rotation.invert(&inverse);
+ SkMatrix44 expected(SkMatrix44::kUninitialized_Constructor);
+ double expectedInverseRotation[16] =
+ {0, 1, 0, 0,
+ -1, 0, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1};
+ expected.setRowMajord(expectedInverseRotation);
+ REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
+
+ SkMatrix44 affine(SkMatrix44::kUninitialized_Constructor);
+ affine.setRotateDegreesAbout(0, 0, 1, 90);
+ affine.preScale(10, 20, 100);
+ affine.preTranslate(2, 3, 4);
+ affine.invert(&inverse);
+ double expectedInverseAffine[16] =
+ {0, 0.1, 0, -2,
+ -0.05, 0, 0, -3,
+ 0, 0, 0.01, -4,
+ 0, 0, 0, 1};
+ expected.setRowMajord(expectedInverseAffine);
+ REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
+
+ SkMatrix44 perspective(SkMatrix44::kIdentity_Constructor);
+ perspective.setDouble(3, 2, 1.0);
+ perspective.invert(&inverse);
+ double expectedInversePerspective[16] =
+ {1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, -1, 1};
+ expected.setRowMajord(expectedInversePerspective);
+ REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
+
+ SkMatrix44 affineAndPerspective(SkMatrix44::kIdentity_Constructor);
+ affineAndPerspective.setDouble(3, 2, 1.0);
+ affineAndPerspective.preScale(10, 20, 100);
+ affineAndPerspective.preTranslate(2, 3, 4);
+ affineAndPerspective.invert(&inverse);
+ double expectedInverseAffineAndPerspective[16] =
+ {0.1, 0, 2, -2,
+ 0, 0.05, 3, -3,
+ 0, 0, 4.01, -4,
+ 0, 0, -1, 1};
+ expected.setRowMajord(expectedInverseAffineAndPerspective);
+ REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
+}
+
+static void test_transpose(skiatest::Reporter* reporter) {
+ SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
+
+ int i = 0;
+ for (int row = 0; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ a.setDouble(row, col, i);
+ b.setDouble(col, row, i++);
+ }
+ }
+
+ a.transpose();
+ REPORTER_ASSERT(reporter, nearly_equal(a, b));
+}
+
+static void test_get_set_double(skiatest::Reporter* reporter) {
+ SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
+ for (int row = 0; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ a.setDouble(row, col, 3.141592653589793);
+ REPORTER_ASSERT(reporter,
+ nearly_equal_double(3.141592653589793,
+ a.getDouble(row, col)));
+ a.setDouble(row, col, 0);
+ REPORTER_ASSERT(reporter,
+ nearly_equal_double(0, a.getDouble(row, col)));
+ }
+ }
+}
+
+static void test_set_row_col_major(skiatest::Reporter* reporter) {
+ SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
+
+ for (int row = 0; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ a.setDouble(row, col, row * 4 + col);
+ }
+ }
+
+ double bufferd[16];
+ float bufferf[16];
+ a.asColMajord(bufferd);
+ b.setColMajord(bufferd);
+ REPORTER_ASSERT(reporter, nearly_equal(a, b));
+ b.setRowMajord(bufferd);
+ b.transpose();
+ REPORTER_ASSERT(reporter, nearly_equal(a, b));
+ a.asColMajorf(bufferf);
+ b.setColMajorf(bufferf);
+ REPORTER_ASSERT(reporter, nearly_equal(a, b));
+ b.setRowMajorf(bufferf);
+ b.transpose();
+ REPORTER_ASSERT(reporter, nearly_equal(a, b));
+}
+
+static void test_3x3_conversion(skiatest::Reporter* reporter) {
+ SkMScalar values4x4[16] = { 1, 2, 3, 4,
+ 5, 6, 7, 8,
+ 9, 10, 11, 12,
+ 13, 14, 15, 16 };
+ SkScalar values3x3[9] = { 1, 2, 4,
+ 5, 6, 8,
+ 13, 14, 16 };
+ SkMScalar values4x4flattened[16] = { 1, 2, 0, 4,
+ 5, 6, 0, 8,
+ 0, 0, 1, 0,
+ 13, 14, 0, 16 };
+ SkMatrix44 a44(SkMatrix44::kUninitialized_Constructor);
+ a44.setRowMajor(values4x4);
+
+ SkMatrix a33 = a44;
+ SkMatrix expected33;
+ for (int i = 0; i < 9; i++) expected33[i] = values3x3[i];
+ REPORTER_ASSERT(reporter, expected33 == a33);
+
+ SkMatrix44 a44flattened = a33;
+ SkMatrix44 expected44flattened(SkMatrix44::kUninitialized_Constructor);
+ expected44flattened.setRowMajor(values4x4flattened);
+ REPORTER_ASSERT(reporter, nearly_equal(a44flattened, expected44flattened));
+
+ // Test that a point with a Z value of 0 is transformed the same way.
+ SkScalar vec4[4] = { 2, 4, 0, 8 };
+ SkScalar vec3[3] = { 2, 4, 8 };
+
+ SkScalar vec4transformed[4];
+ SkScalar vec3transformed[3];
+ SkScalar vec4transformed2[4];
+ a44.mapScalars(vec4, vec4transformed);
+ a33.mapHomogeneousPoints(vec3transformed, vec3, 1);
+ a44flattened.mapScalars(vec4, vec4transformed2);
+ REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec3transformed[0]));
+ REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec3transformed[1]));
+ REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec3transformed[2]));
+ REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec4transformed2[0]));
+ REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec4transformed2[1]));
+ REPORTER_ASSERT(reporter, !nearly_equal_scalar(vec4transformed[2], vec4transformed2[2]));
+ REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec4transformed2[3]));
+}
+
+static void test_has_perspective(skiatest::Reporter* reporter) {
+ SkMatrix44 transform(SkMatrix44::kIdentity_Constructor);
+
+ transform.set(3, 2, -0.1);
+ REPORTER_ASSERT(reporter, transform.hasPerspective());
+
+ transform.reset();
+ REPORTER_ASSERT(reporter, !transform.hasPerspective());
+
+ transform.set(3, 0, -1.0);
+ REPORTER_ASSERT(reporter, transform.hasPerspective());
+
+ transform.reset();
+ transform.set(3, 1, -1.0);
+ REPORTER_ASSERT(reporter, transform.hasPerspective());
+
+ transform.reset();
+ transform.set(3, 2, -0.3);
+ REPORTER_ASSERT(reporter, transform.hasPerspective());
+
+ transform.reset();
+ transform.set(3, 3, 0.5);
+ REPORTER_ASSERT(reporter, transform.hasPerspective());
+
+ transform.reset();
+ transform.set(3, 3, 0.0);
+ REPORTER_ASSERT(reporter, transform.hasPerspective());
+}
+
+DEF_TEST(Matrix44, reporter) {
+ SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 iden1(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 iden2(SkMatrix44::kUninitialized_Constructor);
+ SkMatrix44 rot(SkMatrix44::kUninitialized_Constructor);
+
+ mat.setTranslate(1, 1, 1);
+ mat.invert(&inverse);
+ iden1.setConcat(mat, inverse);
+ REPORTER_ASSERT(reporter, is_identity(iden1));
+
+ mat.setScale(2, 2, 2);
+ mat.invert(&inverse);
+ iden1.setConcat(mat, inverse);
+ REPORTER_ASSERT(reporter, is_identity(iden1));
+
+ mat.setScale(SK_MScalar1/2, SK_MScalar1/2, SK_MScalar1/2);
+ mat.invert(&inverse);
+ iden1.setConcat(mat, inverse);
+ REPORTER_ASSERT(reporter, is_identity(iden1));
+
+ mat.setScale(3, 3, 3);
+ rot.setRotateDegreesAbout(0, 0, -1, 90);
+ mat.postConcat(rot);
+ REPORTER_ASSERT(reporter, mat.invert(NULL));
+ mat.invert(&inverse);
+ iden1.setConcat(mat, inverse);
+ REPORTER_ASSERT(reporter, is_identity(iden1));
+ iden2.setConcat(inverse, mat);
+ REPORTER_ASSERT(reporter, is_identity(iden2));
+
+ // test tiny-valued matrix inverse
+ mat.reset();
+ mat.setScale(1.0e-12, 1.0e-12, 1.0e-12);
+ rot.setRotateDegreesAbout(0, 0, -1, 90);
+ mat.postConcat(rot);
+ mat.postTranslate(1.0e-12, 1.0e-12, 1.0e-12);
+ REPORTER_ASSERT(reporter, mat.invert(NULL));
+ mat.invert(&inverse);
+ iden1.setConcat(mat, inverse);
+ REPORTER_ASSERT(reporter, is_identity(iden1));
+
+ // test mixed-valued matrix inverse
+ mat.reset();
+ mat.setScale(1.0e-10, 3.0, 1.0e+10);
+ rot.setRotateDegreesAbout(0, 0, -1, 90);
+ mat.postConcat(rot);
+ mat.postTranslate(1.0e+10, 3.0, 1.0e-10);
+ REPORTER_ASSERT(reporter, mat.invert(NULL));
+ mat.invert(&inverse);
+ iden1.setConcat(mat, inverse);
+ REPORTER_ASSERT(reporter, is_identity(iden1));
+
+ // test degenerate matrix
+ mat.reset();
+ mat.set3x3(1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0);
+ REPORTER_ASSERT(reporter, !mat.invert(NULL));
+
+ // test rol/col Major getters
+ {
+ mat.setTranslate(2, 3, 4);
+ float dataf[16];
+ double datad[16];
+
+ mat.asColMajorf(dataf);
+ assert16<float>(reporter, dataf,
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 2, 3, 4, 1);
+ mat.asColMajord(datad);
+ assert16<double>(reporter, datad, 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 2, 3, 4, 1);
+ mat.asRowMajorf(dataf);
+ assert16<float>(reporter, dataf, 1, 0, 0, 2,
+ 0, 1, 0, 3,
+ 0, 0, 1, 4,
+ 0, 0, 0, 1);
+ mat.asRowMajord(datad);
+ assert16<double>(reporter, datad, 1, 0, 0, 2,
+ 0, 1, 0, 3,
+ 0, 0, 1, 4,
+ 0, 0, 0, 1);
+ }
+
+ test_concat(reporter);
+
+ if (false) { // avoid bit rot, suppress warning (working on making this pass)
+ test_common_angles(reporter);
+ }
+
+ test_constructor(reporter);
+ test_gettype(reporter);
+ test_determinant(reporter);
+ test_invert(reporter);
+ test_transpose(reporter);
+ test_get_set_double(reporter);
+ test_set_row_col_major(reporter);
+ test_translate(reporter);
+ test_scale(reporter);
+ test_map2(reporter);
+ test_3x3_conversion(reporter);
+ test_has_perspective(reporter);
+}
diff --git a/src/third_party/skia/tests/MatrixClipCollapseTest.cpp b/src/third_party/skia/tests/MatrixClipCollapseTest.cpp
new file mode 100644
index 0000000..c994027
--- /dev/null
+++ b/src/third_party/skia/tests/MatrixClipCollapseTest.cpp
@@ -0,0 +1,730 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "SkCanvas.h"
+#include "SkDebugCanvas.h"
+#include "SkPicture.h"
+#include "SkPictureFlat.h"
+#include "SkPictureRecord.h"
+
+// This test exercises the Matrix/Clip State collapsing system. It generates
+// example skps and the compares the actual stored operations to the expected
+// operations. The test works by emitting canvas operations at three levels:
+// overall structure, bodies that draw something and model/clip state changes.
+//
+// Structure methods only directly emit save and restores but call the
+// ModelClip and Body helper methods to fill in the structure. Since they only
+// emit saves and restores the operations emitted by the structure methods will
+// be completely removed by the matrix/clip collapse. Note: every save in
+// a structure method is followed by a call to a ModelClip helper.
+//
+// Body methods only directly emit draw ops and saveLayer/restore pairs but call
+// the ModelClip helper methods. Since the body methods emit the ops that cannot
+// be collapsed (i.e., draw ops, saveLayer/restore) they also generate the
+// expected result information. Note: every saveLayer in a body method is
+// followed by a call to a ModelClip helper.
+//
+// The ModelClip methods output matrix and clip ops in various orders and
+// combinations. They contribute to the expected result by outputting the
+// expected matrix & clip ops. Note that, currently, the entire clip stack
+// is output for each MC state so the clip operations accumulate down the
+// save/restore stack.
+
+// TODOs:
+// check on clip offsets
+// - not sure if this is possible. The desire is to verify that the clip
+// operations' offsets point to the correct follow-on operations. This
+// could be difficult since there is no good way to communicate the
+// offset stored in the SkPicture to the debugger's clip objects
+// add comparison of rendered before & after images?
+// - not sure if this would be useful since it somewhat duplicates the
+// correctness test of running render_pictures in record mode and
+// rendering before and after images. Additionally the matrix/clip collapse
+// is sure to cause some small differences so an automated test might
+// yield too many false positives.
+// run the matrix/clip collapse system on the 10K skp set
+// - this should give us warm fuzzies that the matrix clip collapse
+// system is ready for prime time
+// bench the recording times with/without matrix/clip collapsing
+
+#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
+
+// Enable/disable debugging helper code
+//#define TEST_COLLAPSE_MATRIX_CLIP_STATE 1
+
+// Extract the command ops from the input SkPicture
+static void gets_ops(SkPicture& input, SkTDArray<DrawType>* ops) {
+ SkDebugCanvas debugCanvas(input.width(), input.height());
+ debugCanvas.setBounds(input.width(), input.height());
+ input.draw(&debugCanvas);
+
+ ops->setCount(debugCanvas.getSize());
+ for (int i = 0; i < debugCanvas.getSize(); ++i) {
+ (*ops)[i] = debugCanvas.getDrawCommandAt(i)->getType();
+ }
+}
+
+enum ClipType {
+ kNone_ClipType,
+ kRect_ClipType,
+ kRRect_ClipType,
+ kPath_ClipType,
+ kRegion_ClipType,
+
+ kLast_ClipType = kRRect_ClipType
+};
+
+static const int kClipTypeCount = kLast_ClipType + 1;
+
+enum MatType {
+ kNone_MatType,
+ kTranslate_MatType,
+ kScale_MatType,
+ kSkew_MatType,
+ kRotate_MatType,
+ kConcat_MatType,
+ kSetMatrix_MatType,
+
+ kLast_MatType = kScale_MatType
+};
+
+static const int kMatTypeCount = kLast_MatType + 1;
+
+// TODO: implement the rest of the draw ops
+enum DrawOpType {
+ kNone_DrawOpType,
+#if 0
+ kBitmap_DrawOpType,
+ kBitmapMatrix_DrawOpType,
+ kBitmapNone_DrawOpType,
+ kBitmapRectToRect_DrawOpType,
+#endif
+ kClear_DrawOpType,
+#if 0
+ kData_DrawOpType,
+#endif
+ kOval_DrawOpType,
+#if 0
+ kPaint_DrawOpType,
+ kPath_DrawOpType,
+ kPicture_DrawOpType,
+ kPoints_DrawOpType,
+ kPosText_DrawOpType,
+ kPosTextTopBottom_DrawOpType,
+ kPosTextH_DrawOpType,
+ kPosTextHTopBottom_DrawOpType,
+#endif
+ kRect_DrawOpType,
+ kRRect_DrawOpType,
+#if 0
+ kSprite_DrawOpType,
+ kText_DrawOpType,
+ kTextOnPath_DrawOpType,
+ kTextTopBottom_DrawOpType,
+ kDrawVertices_DrawOpType,
+#endif
+
+ kLastNonSaveLayer_DrawOpType = kRect_DrawOpType,
+
+ // saveLayer's have to handled apart from the other draw operations
+ // since they also alter the save/restore structure.
+ kSaveLayer_DrawOpType,
+};
+
+static const int kNonSaveLayerDrawOpTypeCount = kLastNonSaveLayer_DrawOpType + 1;
+
+typedef void (*PFEmitMC)(SkCanvas* canvas, MatType mat, ClipType clip,
+ DrawOpType draw, SkTDArray<DrawType>* expected,
+ int accumulatedClips);
+typedef void (*PFEmitBody)(SkCanvas* canvas, PFEmitMC emitMC, MatType mat,
+ ClipType clip, DrawOpType draw,
+ SkTDArray<DrawType>* expected, int accumulatedClips);
+typedef void (*PFEmitStruct)(SkCanvas* canvas, PFEmitMC emitMC, MatType mat,
+ ClipType clip, PFEmitBody emitBody, DrawOpType draw,
+ SkTDArray<DrawType>* expected);
+
+//////////////////////////////////////////////////////////////////////////////
+
+// TODO: expand the testing to include the different ops & AA types!
+static void emit_clip(SkCanvas* canvas, ClipType clip) {
+ switch (clip) {
+ case kNone_ClipType:
+ break;
+ case kRect_ClipType: {
+ SkRect r = SkRect::MakeLTRB(10, 10, 90, 90);
+ canvas->clipRect(r, SkRegion::kIntersect_Op, true);
+ break;
+ }
+ case kRRect_ClipType: {
+ SkRect r = SkRect::MakeLTRB(10, 10, 90, 90);
+ SkRRect rr;
+ rr.setRectXY(r, 10, 10);
+ canvas->clipRRect(rr, SkRegion::kIntersect_Op, true);
+ break;
+ }
+ case kPath_ClipType: {
+ SkPath p;
+ p.moveTo(5.0f, 5.0f);
+ p.lineTo(50.0f, 50.0f);
+ p.lineTo(100.0f, 5.0f);
+ p.close();
+ canvas->clipPath(p, SkRegion::kIntersect_Op, true);
+ break;
+ }
+ case kRegion_ClipType: {
+ SkIRect rects[2] = {
+ { 1, 1, 55, 55 },
+ { 45, 45, 99, 99 },
+ };
+ SkRegion r;
+ r.setRects(rects, 2);
+ canvas->clipRegion(r, SkRegion::kIntersect_Op);
+ break;
+ }
+ default:
+ SkASSERT(0);
+ }
+}
+
+static void add_clip(ClipType clip, MatType mat, SkTDArray<DrawType>* expected) {
+ if (NULL == expected) {
+ // expected is NULL if this clip will be fused into later clips
+ return;
+ }
+
+ switch (clip) {
+ case kNone_ClipType:
+ break;
+ case kRect_ClipType:
+ *expected->append() = CONCAT;
+ *expected->append() = CLIP_RECT;
+ break;
+ case kRRect_ClipType:
+ *expected->append() = CONCAT;
+ *expected->append() = CLIP_RRECT;
+ break;
+ case kPath_ClipType:
+ *expected->append() = CONCAT;
+ *expected->append() = CLIP_PATH;
+ break;
+ case kRegion_ClipType:
+ *expected->append() = CONCAT;
+ *expected->append() = CLIP_REGION;
+ break;
+ default:
+ SkASSERT(0);
+ }
+}
+
+static void emit_mat(SkCanvas* canvas, MatType mat) {
+ switch (mat) {
+ case kNone_MatType:
+ break;
+ case kTranslate_MatType:
+ canvas->translate(5.0f, 5.0f);
+ break;
+ case kScale_MatType:
+ canvas->scale(1.1f, 1.1f);
+ break;
+ case kSkew_MatType:
+ canvas->skew(1.1f, 1.1f);
+ break;
+ case kRotate_MatType:
+ canvas->rotate(1.0f);
+ break;
+ case kConcat_MatType: {
+ SkMatrix m;
+ m.setTranslate(1.0f, 1.0f);
+ canvas->concat(m);
+ break;
+ }
+ case kSetMatrix_MatType: {
+ SkMatrix m;
+ m.setTranslate(1.0f, 1.0f);
+ canvas->setMatrix(m);
+ break;
+ }
+ default:
+ SkASSERT(0);
+ }
+}
+
+static void add_mat(MatType mat, SkTDArray<DrawType>* expected) {
+ if (NULL == expected) {
+ // expected is NULL if this matrix call will be fused into later ones
+ return;
+ }
+
+ switch (mat) {
+ case kNone_MatType:
+ break;
+ case kTranslate_MatType: // fall thru
+ case kScale_MatType: // fall thru
+ case kSkew_MatType: // fall thru
+ case kRotate_MatType: // fall thru
+ case kConcat_MatType: // fall thru
+ case kSetMatrix_MatType:
+ // TODO: this system currently converts a setMatrix to concat. If we wanted to
+ // really preserve the setMatrix semantics we should keep it a setMatrix. I'm
+ // not sure if this is a good idea though since this would keep things like pinch
+ // zoom from working.
+ *expected->append() = CONCAT;
+ break;
+ default:
+ SkASSERT(0);
+ }
+}
+
+static void emit_draw(SkCanvas* canvas, DrawOpType draw, SkTDArray<DrawType>* expected) {
+ switch (draw) {
+ case kNone_DrawOpType:
+ break;
+ case kClear_DrawOpType:
+ canvas->clear(SK_ColorRED);
+ *expected->append() = DRAW_CLEAR;
+ break;
+ case kOval_DrawOpType: {
+ SkRect r = SkRect::MakeLTRB(10, 10, 90, 90);
+ SkPaint p;
+ canvas->drawOval(r, p);
+ *expected->append() = DRAW_OVAL;
+ break;
+ }
+ case kRect_DrawOpType: {
+ SkRect r = SkRect::MakeLTRB(10, 10, 90, 90);
+ SkPaint p;
+ canvas->drawRect(r, p);
+ *expected->append() = DRAW_RECT;
+ break;
+ }
+ case kRRect_DrawOpType: {
+ SkRect r = SkRect::MakeLTRB(10.0f, 10.0f, 90.0f, 90.0f);
+ SkRRect rr;
+ rr.setRectXY(r, 5.0f, 5.0f);
+ SkPaint p;
+ canvas->drawRRect(rr, p);
+ *expected->append() = DRAW_RRECT;
+ break;
+ }
+ default:
+ SkASSERT(0);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Emit:
+// clip
+// matrix
+// Simple case - the clip isn't effect by the matrix
+static void emit_clip_and_mat(SkCanvas* canvas, MatType mat, ClipType clip,
+ DrawOpType draw, SkTDArray<DrawType>* expected,
+ int accumulatedClips) {
+ emit_clip(canvas, clip);
+ emit_mat(canvas, mat);
+
+ if (kNone_DrawOpType == draw) {
+ return;
+ }
+
+ for (int i = 0; i < accumulatedClips; ++i) {
+ add_clip(clip, mat, expected);
+ }
+ add_mat(mat, expected);
+}
+
+// Emit:
+// matrix
+// clip
+// Emitting the matrix first is more challenging since the matrix has to be
+// pushed across (i.e., applied to) the clip.
+static void emit_mat_and_clip(SkCanvas* canvas, MatType mat, ClipType clip,
+ DrawOpType draw, SkTDArray<DrawType>* expected,
+ int accumulatedClips) {
+ emit_mat(canvas, mat);
+ emit_clip(canvas, clip);
+
+ if (kNone_DrawOpType == draw) {
+ return;
+ }
+
+ // the matrix & clip order will be reversed once collapsed!
+ for (int i = 0; i < accumulatedClips; ++i) {
+ add_clip(clip, mat, expected);
+ }
+ add_mat(mat, expected);
+}
+
+// Emit:
+// matrix
+// clip
+// matrix
+// clip
+// This tests that the matrices and clips coalesce when collapsed
+static void emit_double_mat_and_clip(SkCanvas* canvas, MatType mat, ClipType clip,
+ DrawOpType draw, SkTDArray<DrawType>* expected,
+ int accumulatedClips) {
+ emit_mat(canvas, mat);
+ emit_clip(canvas, clip);
+ emit_mat(canvas, mat);
+ emit_clip(canvas, clip);
+
+ if (kNone_DrawOpType == draw) {
+ return;
+ }
+
+ for (int i = 0; i < accumulatedClips; ++i) {
+ add_clip(clip, mat, expected);
+ add_clip(clip, mat, expected);
+ }
+ add_mat(mat, expected);
+}
+
+// Emit:
+// matrix
+// clip
+// clip
+// This tests accumulation of clips in same transform state. It also tests pushing
+// of the matrix across both the clips.
+static void emit_mat_clip_clip(SkCanvas* canvas, MatType mat, ClipType clip,
+ DrawOpType draw, SkTDArray<DrawType>* expected,
+ int accumulatedClips) {
+ emit_mat(canvas, mat);
+ emit_clip(canvas, clip);
+ emit_clip(canvas, clip);
+
+ if (kNone_DrawOpType == draw) {
+ return;
+ }
+
+ for (int i = 0; i < accumulatedClips; ++i) {
+ add_clip(clip, mat, expected);
+ add_clip(clip, mat, expected);
+ }
+ add_mat(mat, expected);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Emit:
+// matrix & clip calls
+// draw op
+static void emit_body0(SkCanvas* canvas, PFEmitMC emitMC, MatType mat,
+ ClipType clip, DrawOpType draw,
+ SkTDArray<DrawType>* expected, int accumulatedClips) {
+ bool needsSaveRestore = kNone_DrawOpType != draw &&
+ (kNone_MatType != mat || kNone_ClipType != clip);
+
+ if (needsSaveRestore) {
+ *expected->append() = SAVE;
+ }
+ (*emitMC)(canvas, mat, clip, draw, expected, accumulatedClips+1);
+ emit_draw(canvas, draw, expected);
+ if (needsSaveRestore) {
+ *expected->append() = RESTORE;
+ }
+}
+
+// Emit:
+// matrix & clip calls
+// draw op
+// matrix & clip calls
+// draw op
+static void emit_body1(SkCanvas* canvas, PFEmitMC emitMC, MatType mat,
+ ClipType clip, DrawOpType draw,
+ SkTDArray<DrawType>* expected, int accumulatedClips) {
+ bool needsSaveRestore = kNone_DrawOpType != draw &&
+ (kNone_MatType != mat || kNone_ClipType != clip);
+
+ if (needsSaveRestore) {
+ *expected->append() = SAVE;
+ }
+ (*emitMC)(canvas, mat, clip, draw, expected, accumulatedClips+1);
+ emit_draw(canvas, draw, expected);
+ if (needsSaveRestore) {
+ *expected->append() = RESTORE;
+ *expected->append() = SAVE;
+ }
+ (*emitMC)(canvas, mat, clip, draw, expected, accumulatedClips+2);
+ emit_draw(canvas, draw, expected);
+ if (needsSaveRestore) {
+ *expected->append() = RESTORE;
+ }
+}
+
+// Emit:
+// matrix & clip calls
+// SaveLayer
+// matrix & clip calls
+// draw op
+// Restore
+static void emit_body2(SkCanvas* canvas, PFEmitMC emitMC, MatType mat,
+ ClipType clip, DrawOpType draw,
+ SkTDArray<DrawType>* expected, int accumulatedClips) {
+ bool needsSaveRestore = kNone_DrawOpType != draw &&
+ (kNone_MatType != mat || kNone_ClipType != clip);
+
+ if (kNone_MatType != mat || kNone_ClipType != clip) {
+ *expected->append() = SAVE;
+ }
+ (*emitMC)(canvas, mat, clip, kSaveLayer_DrawOpType, expected, accumulatedClips+1);
+ *expected->append() = SAVE_LAYER;
+ // TODO: widen testing to exercise saveLayer's parameters
+ canvas->saveLayer(NULL, NULL);
+ if (needsSaveRestore) {
+ *expected->append() = SAVE;
+ }
+ (*emitMC)(canvas, mat, clip, draw, expected, 1);
+ emit_draw(canvas, draw, expected);
+ if (needsSaveRestore) {
+ *expected->append() = RESTORE;
+ }
+ canvas->restore();
+ *expected->append() = RESTORE;
+ if (kNone_MatType != mat || kNone_ClipType != clip) {
+ *expected->append() = RESTORE;
+ }
+}
+
+// Emit:
+// matrix & clip calls
+// SaveLayer
+// matrix & clip calls
+// SaveLayer
+// matrix & clip calls
+// draw op
+// Restore
+// matrix & clip calls (will be ignored)
+// Restore
+static void emit_body3(SkCanvas* canvas, PFEmitMC emitMC, MatType mat,
+ ClipType clip, DrawOpType draw,
+ SkTDArray<DrawType>* expected, int accumulatedClips) {
+ bool needsSaveRestore = kNone_DrawOpType != draw &&
+ (kNone_MatType != mat || kNone_ClipType != clip);
+
+ if (kNone_MatType != mat || kNone_ClipType != clip) {
+ *expected->append() = SAVE;
+ }
+ (*emitMC)(canvas, mat, clip, kSaveLayer_DrawOpType, expected, accumulatedClips+1);
+ *expected->append() = SAVE_LAYER;
+ // TODO: widen testing to exercise saveLayer's parameters
+ canvas->saveLayer(NULL, NULL);
+ (*emitMC)(canvas, mat, clip, kSaveLayer_DrawOpType, expected, 1);
+ if (kNone_MatType != mat || kNone_ClipType != clip) {
+ *expected->append() = SAVE;
+ }
+ *expected->append() = SAVE_LAYER;
+ // TODO: widen testing to exercise saveLayer's parameters
+ canvas->saveLayer(NULL, NULL);
+ if (needsSaveRestore) {
+ *expected->append() = SAVE;
+ }
+ (*emitMC)(canvas, mat, clip, draw, expected, 1);
+ emit_draw(canvas, draw, expected);
+ if (needsSaveRestore) {
+ *expected->append() = RESTORE;
+ }
+ canvas->restore(); // for saveLayer
+ *expected->append() = RESTORE; // for saveLayer
+ if (kNone_MatType != mat || kNone_ClipType != clip) {
+ *expected->append() = RESTORE;
+ }
+ canvas->restore();
+ // required to match forced SAVE_LAYER
+ *expected->append() = RESTORE;
+ if (kNone_MatType != mat || kNone_ClipType != clip) {
+ *expected->append() = RESTORE;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Emit:
+// Save
+// some body
+// Restore
+// Note: the outer save/restore are provided by beginRecording/endRecording
+static void emit_struct0(SkCanvas* canvas,
+ PFEmitMC emitMC, MatType mat, ClipType clip,
+ PFEmitBody emitBody, DrawOpType draw,
+ SkTDArray<DrawType>* expected) {
+ (*emitBody)(canvas, emitMC, mat, clip, draw, expected, 0);
+}
+
+// Emit:
+// Save
+// matrix & clip calls
+// Save
+// some body
+// Restore
+// matrix & clip calls (will be ignored)
+// Restore
+// Note: the outer save/restore are provided by beginRecording/endRecording
+static void emit_struct1(SkCanvas* canvas,
+ PFEmitMC emitMC, MatType mat, ClipType clip,
+ PFEmitBody emitBody, DrawOpType draw,
+ SkTDArray<DrawType>* expected) {
+ (*emitMC)(canvas, mat, clip, draw, NULL, 0); // these get fused into later ops
+ canvas->save();
+ (*emitBody)(canvas, emitMC, mat, clip, draw, expected, 1);
+ canvas->restore();
+ (*emitMC)(canvas, mat, clip, draw, NULL, 0); // these will get removed
+}
+
+// Emit:
+// Save
+// matrix & clip calls
+// Save
+// some body
+// Restore
+// Save
+// some body
+// Restore
+// matrix & clip calls (will be ignored)
+// Restore
+// Note: the outer save/restore are provided by beginRecording/endRecording
+static void emit_struct2(SkCanvas* canvas,
+ PFEmitMC emitMC, MatType mat, ClipType clip,
+ PFEmitBody emitBody, DrawOpType draw,
+ SkTDArray<DrawType>* expected) {
+ (*emitMC)(canvas, mat, clip, draw, NULL, 1); // these will get fused into later ops
+ canvas->save();
+ (*emitBody)(canvas, emitMC, mat, clip, draw, expected, 1);
+ canvas->restore();
+ canvas->save();
+ (*emitBody)(canvas, emitMC, mat, clip, draw, expected, 1);
+ canvas->restore();
+ (*emitMC)(canvas, mat, clip, draw, NULL, 1); // these will get removed
+}
+
+// Emit:
+// Save
+// matrix & clip calls
+// Save
+// some body
+// Restore
+// Save
+// matrix & clip calls
+// Save
+// some body
+// Restore
+// Restore
+// matrix & clip calls (will be ignored)
+// Restore
+// Note: the outer save/restore are provided by beginRecording/endRecording
+static void emit_struct3(SkCanvas* canvas,
+ PFEmitMC emitMC, MatType mat, ClipType clip,
+ PFEmitBody emitBody, DrawOpType draw,
+ SkTDArray<DrawType>* expected) {
+ (*emitMC)(canvas, mat, clip, draw, NULL, 0); // these will get fused into later ops
+ canvas->save();
+ (*emitBody)(canvas, emitMC, mat, clip, draw, expected, 1);
+ canvas->restore();
+ canvas->save();
+ (*emitMC)(canvas, mat, clip, draw, NULL, 1); // these will get fused into later ops
+ canvas->save();
+ (*emitBody)(canvas, emitMC, mat, clip, draw, expected, 2);
+ canvas->restore();
+ canvas->restore();
+ (*emitMC)(canvas, mat, clip, draw, NULL, 0); // these will get removed
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
+static void print(const SkTDArray<DrawType>& expected, const SkTDArray<DrawType>& actual) {
+ SkDebugf("\n\nexpected %d --- actual %d\n", expected.count(), actual.count());
+ int max = SkMax32(expected.count(), actual.count());
+
+ for (int i = 0; i < max; ++i) {
+ if (i < expected.count()) {
+ SkDebugf("%16s, ", SkDrawCommand::GetCommandString(expected[i]));
+ } else {
+ SkDebugf("%16s, ", " ");
+ }
+
+ if (i < actual.count()) {
+ SkDebugf("%s\n", SkDrawCommand::GetCommandString(actual[i]));
+ } else {
+ SkDebugf("\n");
+ }
+ }
+ SkDebugf("\n\n");
+ SkASSERT(0);
+}
+#endif
+
+static void test_collapse(skiatest::Reporter* reporter) {
+ PFEmitStruct gStructure[] = { emit_struct0, emit_struct1, emit_struct2, emit_struct3 };
+ PFEmitBody gBody[] = { emit_body0, emit_body1, emit_body2, emit_body3 };
+ PFEmitMC gMCs[] = { emit_clip_and_mat, emit_mat_and_clip,
+ emit_double_mat_and_clip, emit_mat_clip_clip };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gStructure); ++i) {
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gBody); ++j) {
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gMCs); ++k) {
+ for (int l = 0; l < kMatTypeCount; ++l) {
+ for (int m = 0; m < kClipTypeCount; ++m) {
+ for (int n = 0; n < kNonSaveLayerDrawOpTypeCount; ++n) {
+#ifdef TEST_COLLAPSE_MATRIX_CLIP_STATE
+ static int testID = -1;
+ ++testID;
+ if (testID < -1) {
+ continue;
+ }
+ SkDebugf("test: %d\n", testID);
+#endif
+
+ SkTDArray<DrawType> expected, actual;
+
+ SkPicture picture;
+
+ // Note: beginRecording/endRecording add a save/restore pair
+ SkCanvas* canvas = picture.beginRecording(100, 100);
+ (*gStructure[i])(canvas,
+ gMCs[k],
+ (MatType) l,
+ (ClipType) m,
+ gBody[j],
+ (DrawOpType) n,
+ &expected);
+ picture.endRecording();
+
+ gets_ops(picture, &actual);
+
+ REPORTER_ASSERT(reporter, expected.count() == actual.count());
+
+ if (expected.count() != actual.count()) {
+#ifdef TEST_COLLAPSE_MATRIX_CLIP_STATE
+ print(expected, actual);
+#endif
+ continue;
+ }
+
+ for (int i = 0; i < expected.count(); ++i) {
+ REPORTER_ASSERT(reporter, expected[i] == actual[i]);
+#ifdef TEST_COLLAPSE_MATRIX_CLIP_STATE
+ if (expected[i] != actual[i]) {
+ print(expected, actual);
+ }
+#endif
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+DEF_TEST(MatrixClipCollapse, reporter) {
+ test_collapse(reporter);
+}
+
+#endif
diff --git a/src/third_party/skia/tests/MatrixTest.cpp b/src/third_party/skia/tests/MatrixTest.cpp
new file mode 100644
index 0000000..fc7ac42
--- /dev/null
+++ b/src/third_party/skia/tests/MatrixTest.cpp
@@ -0,0 +1,865 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkMath.h"
+#include "SkMatrix.h"
+#include "SkMatrixUtils.h"
+#include "SkRandom.h"
+#include "Test.h"
+
+static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
+ const SkScalar tolerance = SK_Scalar1 / 200000;
+ return SkScalarAbs(a - b) <= tolerance;
+}
+
+static bool nearly_equal(const SkMatrix& a, const SkMatrix& b) {
+ for (int i = 0; i < 9; i++) {
+ if (!nearly_equal_scalar(a[i], b[i])) {
+ SkDebugf("not equal %g %g\n", (float)a[i], (float)b[i]);
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool are_equal(skiatest::Reporter* reporter,
+ const SkMatrix& a,
+ const SkMatrix& b) {
+ bool equal = a == b;
+ bool cheapEqual = a.cheapEqualTo(b);
+ if (equal != cheapEqual) {
+ if (equal) {
+ bool foundZeroSignDiff = false;
+ for (int i = 0; i < 9; ++i) {
+ float aVal = a.get(i);
+ float bVal = b.get(i);
+ int aValI = *SkTCast<int*>(&aVal);
+ int bValI = *SkTCast<int*>(&bVal);
+ if (0 == aVal && 0 == bVal && aValI != bValI) {
+ foundZeroSignDiff = true;
+ } else {
+ REPORTER_ASSERT(reporter, aVal == bVal && aValI == aValI);
+ }
+ }
+ REPORTER_ASSERT(reporter, foundZeroSignDiff);
+ } else {
+ bool foundNaN = false;
+ for (int i = 0; i < 9; ++i) {
+ float aVal = a.get(i);
+ float bVal = b.get(i);
+ int aValI = *SkTCast<int*>(&aVal);
+ int bValI = *SkTCast<int*>(&bVal);
+ if (sk_float_isnan(aVal) && aValI == bValI) {
+ foundNaN = true;
+ } else {
+ REPORTER_ASSERT(reporter, aVal == bVal && aValI == bValI);
+ }
+ }
+ REPORTER_ASSERT(reporter, foundNaN);
+ }
+ }
+ return equal;
+}
+
+static bool is_identity(const SkMatrix& m) {
+ SkMatrix identity;
+ identity.reset();
+ return nearly_equal(m, identity);
+}
+
+static void test_matrix_recttorect(skiatest::Reporter* reporter) {
+ SkRect src, dst;
+ SkMatrix matrix;
+
+ src.set(0, 0, SK_Scalar1*10, SK_Scalar1*10);
+ dst = src;
+ matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
+ REPORTER_ASSERT(reporter, SkMatrix::kIdentity_Mask == matrix.getType());
+ REPORTER_ASSERT(reporter, matrix.rectStaysRect());
+
+ dst.offset(SK_Scalar1, SK_Scalar1);
+ matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
+ REPORTER_ASSERT(reporter, SkMatrix::kTranslate_Mask == matrix.getType());
+ REPORTER_ASSERT(reporter, matrix.rectStaysRect());
+
+ dst.fRight += SK_Scalar1;
+ matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
+ REPORTER_ASSERT(reporter,
+ (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask) == matrix.getType());
+ REPORTER_ASSERT(reporter, matrix.rectStaysRect());
+
+ dst = src;
+ dst.fRight = src.fRight * 2;
+ matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
+ REPORTER_ASSERT(reporter, SkMatrix::kScale_Mask == matrix.getType());
+ REPORTER_ASSERT(reporter, matrix.rectStaysRect());
+}
+
+static void test_flatten(skiatest::Reporter* reporter, const SkMatrix& m) {
+ // add 100 in case we have a bug, I don't want to kill my stack in the test
+ static const size_t kBufferSize = SkMatrix::kMaxFlattenSize + 100;
+ char buffer[kBufferSize];
+ size_t size1 = m.writeToMemory(NULL);
+ size_t size2 = m.writeToMemory(buffer);
+ REPORTER_ASSERT(reporter, size1 == size2);
+ REPORTER_ASSERT(reporter, size1 <= SkMatrix::kMaxFlattenSize);
+
+ SkMatrix m2;
+ size_t size3 = m2.readFromMemory(buffer, kBufferSize);
+ REPORTER_ASSERT(reporter, size1 == size3);
+ REPORTER_ASSERT(reporter, are_equal(reporter, m, m2));
+
+ char buffer2[kBufferSize];
+ size3 = m2.writeToMemory(buffer2);
+ REPORTER_ASSERT(reporter, size1 == size3);
+ REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
+}
+
+static void test_matrix_min_max_scale(skiatest::Reporter* reporter) {
+ SkScalar scales[2];
+ bool success;
+
+ SkMatrix identity;
+ identity.reset();
+ REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMinScale());
+ REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMaxScale());
+ success = identity.getMinMaxScales(scales);
+ REPORTER_ASSERT(reporter, success && SK_Scalar1 == scales[0] && SK_Scalar1 == scales[1]);
+
+ SkMatrix scale;
+ scale.setScale(SK_Scalar1 * 2, SK_Scalar1 * 4);
+ REPORTER_ASSERT(reporter, SK_Scalar1 * 2 == scale.getMinScale());
+ REPORTER_ASSERT(reporter, SK_Scalar1 * 4 == scale.getMaxScale());
+ success = scale.getMinMaxScales(scales);
+ REPORTER_ASSERT(reporter, success && SK_Scalar1 * 2 == scales[0] && SK_Scalar1 * 4 == scales[1]);
+
+ SkMatrix rot90Scale;
+ rot90Scale.setRotate(90 * SK_Scalar1);
+ rot90Scale.postScale(SK_Scalar1 / 4, SK_Scalar1 / 2);
+ REPORTER_ASSERT(reporter, SK_Scalar1 / 4 == rot90Scale.getMinScale());
+ REPORTER_ASSERT(reporter, SK_Scalar1 / 2 == rot90Scale.getMaxScale());
+ success = rot90Scale.getMinMaxScales(scales);
+ REPORTER_ASSERT(reporter, success && SK_Scalar1 / 4 == scales[0] && SK_Scalar1 / 2 == scales[1]);
+
+ SkMatrix rotate;
+ rotate.setRotate(128 * SK_Scalar1);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SK_Scalar1, rotate.getMinScale(), SK_ScalarNearlyZero));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SK_Scalar1, rotate.getMaxScale(), SK_ScalarNearlyZero));
+ success = rotate.getMinMaxScales(scales);
+ REPORTER_ASSERT(reporter, success);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SK_Scalar1, scales[0], SK_ScalarNearlyZero));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SK_Scalar1, scales[1], SK_ScalarNearlyZero));
+
+ SkMatrix translate;
+ translate.setTranslate(10 * SK_Scalar1, -5 * SK_Scalar1);
+ REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMinScale());
+ REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMaxScale());
+ success = translate.getMinMaxScales(scales);
+ REPORTER_ASSERT(reporter, success && SK_Scalar1 == scales[0] && SK_Scalar1 == scales[1]);
+
+ SkMatrix perspX;
+ perspX.reset();
+ perspX.setPerspX(SkScalarToPersp(SK_Scalar1 / 1000));
+ REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMinScale());
+ REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMaxScale());
+ // Verify that getMinMaxScales() doesn't update the scales array on failure.
+ scales[0] = -5;
+ scales[1] = -5;
+ success = perspX.getMinMaxScales(scales);
+ REPORTER_ASSERT(reporter, !success && -5 * SK_Scalar1 == scales[0] && -5 * SK_Scalar1 == scales[1]);
+
+ SkMatrix perspY;
+ perspY.reset();
+ perspY.setPerspY(SkScalarToPersp(-SK_Scalar1 / 500));
+ REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMinScale());
+ REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMaxScale());
+ scales[0] = -5;
+ scales[1] = -5;
+ success = perspY.getMinMaxScales(scales);
+ REPORTER_ASSERT(reporter, !success && -5 * SK_Scalar1 == scales[0] && -5 * SK_Scalar1 == scales[1]);
+
+ SkMatrix baseMats[] = {scale, rot90Scale, rotate,
+ translate, perspX, perspY};
+ SkMatrix mats[2*SK_ARRAY_COUNT(baseMats)];
+ for (size_t i = 0; i < SK_ARRAY_COUNT(baseMats); ++i) {
+ mats[i] = baseMats[i];
+ bool invertable = mats[i].invert(&mats[i + SK_ARRAY_COUNT(baseMats)]);
+ REPORTER_ASSERT(reporter, invertable);
+ }
+ SkRandom rand;
+ for (int m = 0; m < 1000; ++m) {
+ SkMatrix mat;
+ mat.reset();
+ for (int i = 0; i < 4; ++i) {
+ int x = rand.nextU() % SK_ARRAY_COUNT(mats);
+ mat.postConcat(mats[x]);
+ }
+
+ SkScalar minScale = mat.getMinScale();
+ SkScalar maxScale = mat.getMaxScale();
+ REPORTER_ASSERT(reporter, (minScale < 0) == (maxScale < 0));
+ REPORTER_ASSERT(reporter, (maxScale < 0) == mat.hasPerspective());
+
+ SkScalar scales[2];
+ bool success = mat.getMinMaxScales(scales);
+ REPORTER_ASSERT(reporter, success == !mat.hasPerspective());
+ REPORTER_ASSERT(reporter, !success || (scales[0] == minScale && scales[1] == maxScale));
+
+ if (mat.hasPerspective()) {
+ m -= 1; // try another non-persp matrix
+ continue;
+ }
+
+ // test a bunch of vectors. All should be scaled by between minScale and maxScale
+ // (modulo some error) and we should find a vector that is scaled by almost each.
+ static const SkScalar gVectorScaleTol = (105 * SK_Scalar1) / 100;
+ static const SkScalar gCloseScaleTol = (97 * SK_Scalar1) / 100;
+ SkScalar max = 0, min = SK_ScalarMax;
+ SkVector vectors[1000];
+ for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
+ vectors[i].fX = rand.nextSScalar1();
+ vectors[i].fY = rand.nextSScalar1();
+ if (!vectors[i].normalize()) {
+ i -= 1;
+ continue;
+ }
+ }
+ mat.mapVectors(vectors, SK_ARRAY_COUNT(vectors));
+ for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
+ SkScalar d = vectors[i].length();
+ REPORTER_ASSERT(reporter, SkScalarDiv(d, maxScale) < gVectorScaleTol);
+ REPORTER_ASSERT(reporter, SkScalarDiv(minScale, d) < gVectorScaleTol);
+ if (max < d) {
+ max = d;
+ }
+ if (min > d) {
+ min = d;
+ }
+ }
+ REPORTER_ASSERT(reporter, SkScalarDiv(max, maxScale) >= gCloseScaleTol);
+ REPORTER_ASSERT(reporter, SkScalarDiv(minScale, min) >= gCloseScaleTol);
+ }
+}
+
+static void test_matrix_preserve_shape(skiatest::Reporter* reporter) {
+ SkMatrix mat;
+
+ // identity
+ mat.setIdentity();
+ REPORTER_ASSERT(reporter, mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+
+ // translation only
+ mat.reset();
+ mat.setTranslate(SkIntToScalar(100), SkIntToScalar(100));
+ REPORTER_ASSERT(reporter, mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+
+ // scale with same size
+ mat.reset();
+ mat.setScale(SkIntToScalar(15), SkIntToScalar(15));
+ REPORTER_ASSERT(reporter, mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+
+ // scale with one negative
+ mat.reset();
+ mat.setScale(SkIntToScalar(-15), SkIntToScalar(15));
+ REPORTER_ASSERT(reporter, mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+
+ // scale with different size
+ mat.reset();
+ mat.setScale(SkIntToScalar(15), SkIntToScalar(20));
+ REPORTER_ASSERT(reporter, !mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+
+ // scale with same size at a pivot point
+ mat.reset();
+ mat.setScale(SkIntToScalar(15), SkIntToScalar(15),
+ SkIntToScalar(2), SkIntToScalar(2));
+ REPORTER_ASSERT(reporter, mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+
+ // scale with different size at a pivot point
+ mat.reset();
+ mat.setScale(SkIntToScalar(15), SkIntToScalar(20),
+ SkIntToScalar(2), SkIntToScalar(2));
+ REPORTER_ASSERT(reporter, !mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+
+ // skew with same size
+ mat.reset();
+ mat.setSkew(SkIntToScalar(15), SkIntToScalar(15));
+ REPORTER_ASSERT(reporter, !mat.isSimilarity());
+ REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
+
+ // skew with different size
+ mat.reset();
+ mat.setSkew(SkIntToScalar(15), SkIntToScalar(20));
+ REPORTER_ASSERT(reporter, !mat.isSimilarity());
+ REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
+
+ // skew with same size at a pivot point
+ mat.reset();
+ mat.setSkew(SkIntToScalar(15), SkIntToScalar(15),
+ SkIntToScalar(2), SkIntToScalar(2));
+ REPORTER_ASSERT(reporter, !mat.isSimilarity());
+ REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
+
+ // skew with different size at a pivot point
+ mat.reset();
+ mat.setSkew(SkIntToScalar(15), SkIntToScalar(20),
+ SkIntToScalar(2), SkIntToScalar(2));
+ REPORTER_ASSERT(reporter, !mat.isSimilarity());
+ REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
+
+ // perspective x
+ mat.reset();
+ mat.setPerspX(SkScalarToPersp(SK_Scalar1 / 2));
+ REPORTER_ASSERT(reporter, !mat.isSimilarity());
+ REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
+
+ // perspective y
+ mat.reset();
+ mat.setPerspY(SkScalarToPersp(SK_Scalar1 / 2));
+ REPORTER_ASSERT(reporter, !mat.isSimilarity());
+ REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
+
+ // rotate
+ for (int angle = 0; angle < 360; ++angle) {
+ mat.reset();
+ mat.setRotate(SkIntToScalar(angle));
+ REPORTER_ASSERT(reporter, mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+ }
+
+ // see if there are any accumulated precision issues
+ mat.reset();
+ for (int i = 1; i < 360; i++) {
+ mat.postRotate(SkIntToScalar(1));
+ }
+ REPORTER_ASSERT(reporter, mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+
+ // rotate + translate
+ mat.reset();
+ mat.setRotate(SkIntToScalar(30));
+ mat.postTranslate(SkIntToScalar(10), SkIntToScalar(20));
+ REPORTER_ASSERT(reporter, mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+
+ // rotate + uniform scale
+ mat.reset();
+ mat.setRotate(SkIntToScalar(30));
+ mat.postScale(SkIntToScalar(2), SkIntToScalar(2));
+ REPORTER_ASSERT(reporter, mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+
+ // rotate + non-uniform scale
+ mat.reset();
+ mat.setRotate(SkIntToScalar(30));
+ mat.postScale(SkIntToScalar(3), SkIntToScalar(2));
+ REPORTER_ASSERT(reporter, !mat.isSimilarity());
+ REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
+
+ // non-uniform scale + rotate
+ mat.reset();
+ mat.setScale(SkIntToScalar(3), SkIntToScalar(2));
+ mat.postRotate(SkIntToScalar(30));
+ REPORTER_ASSERT(reporter, !mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+
+ // all zero
+ mat.setAll(0, 0, 0, 0, 0, 0, 0, 0, 0);
+ REPORTER_ASSERT(reporter, !mat.isSimilarity());
+ REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
+
+ // all zero except perspective
+ mat.reset();
+ mat.setAll(0, 0, 0, 0, 0, 0, 0, 0, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !mat.isSimilarity());
+ REPORTER_ASSERT(reporter, !mat.preservesRightAngles());
+
+ // scales zero, only skews (rotation)
+ mat.setAll(0, SK_Scalar1, 0,
+ -SK_Scalar1, 0, 0,
+ 0, 0, SkMatrix::I()[8]);
+ REPORTER_ASSERT(reporter, mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+
+ // scales zero, only skews (reflection)
+ mat.setAll(0, SK_Scalar1, 0,
+ SK_Scalar1, 0, 0,
+ 0, 0, SkMatrix::I()[8]);
+ REPORTER_ASSERT(reporter, mat.isSimilarity());
+ REPORTER_ASSERT(reporter, mat.preservesRightAngles());
+}
+
+// For test_matrix_decomposition, below.
+static bool scalar_nearly_equal_relative(SkScalar a, SkScalar b,
+ SkScalar tolerance = SK_ScalarNearlyZero) {
+ // from Bruce Dawson
+ // absolute check
+ SkScalar diff = SkScalarAbs(a - b);
+ if (diff < tolerance) {
+ return true;
+ }
+
+ // relative check
+ a = SkScalarAbs(a);
+ b = SkScalarAbs(b);
+ SkScalar largest = (b > a) ? b : a;
+
+ if (diff <= largest*tolerance) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool check_matrix_recomposition(const SkMatrix& mat,
+ const SkPoint& rotation1,
+ const SkPoint& scale,
+ const SkPoint& rotation2) {
+ SkScalar c1 = rotation1.fX;
+ SkScalar s1 = rotation1.fY;
+ SkScalar scaleX = scale.fX;
+ SkScalar scaleY = scale.fY;
+ SkScalar c2 = rotation2.fX;
+ SkScalar s2 = rotation2.fY;
+
+ // We do a relative check here because large scale factors cause problems with an absolute check
+ bool result = scalar_nearly_equal_relative(mat[SkMatrix::kMScaleX],
+ scaleX*c1*c2 - scaleY*s1*s2) &&
+ scalar_nearly_equal_relative(mat[SkMatrix::kMSkewX],
+ -scaleX*s1*c2 - scaleY*c1*s2) &&
+ scalar_nearly_equal_relative(mat[SkMatrix::kMSkewY],
+ scaleX*c1*s2 + scaleY*s1*c2) &&
+ scalar_nearly_equal_relative(mat[SkMatrix::kMScaleY],
+ -scaleX*s1*s2 + scaleY*c1*c2);
+ return result;
+}
+
+static void test_matrix_decomposition(skiatest::Reporter* reporter) {
+ SkMatrix mat;
+ SkPoint rotation1, scale, rotation2;
+
+ const float kRotation0 = 15.5f;
+ const float kRotation1 = -50.f;
+ const float kScale0 = 5000.f;
+ const float kScale1 = 0.001f;
+
+ // identity
+ mat.reset();
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+ // make sure it doesn't crash if we pass in NULLs
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, NULL, NULL, NULL));
+
+ // rotation only
+ mat.setRotate(kRotation0);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // uniform scale only
+ mat.setScale(kScale0, kScale0);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // anisotropic scale only
+ mat.setScale(kScale1, kScale0);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // rotation then uniform scale
+ mat.setRotate(kRotation1);
+ mat.postScale(kScale0, kScale0);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // uniform scale then rotation
+ mat.setScale(kScale0, kScale0);
+ mat.postRotate(kRotation1);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // rotation then uniform scale+reflection
+ mat.setRotate(kRotation0);
+ mat.postScale(kScale1, -kScale1);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // uniform scale+reflection, then rotate
+ mat.setScale(kScale0, -kScale0);
+ mat.postRotate(kRotation1);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // rotation then anisotropic scale
+ mat.setRotate(kRotation1);
+ mat.postScale(kScale1, kScale0);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // rotation then anisotropic scale
+ mat.setRotate(90);
+ mat.postScale(kScale1, kScale0);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // anisotropic scale then rotation
+ mat.setScale(kScale1, kScale0);
+ mat.postRotate(kRotation0);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // anisotropic scale then rotation
+ mat.setScale(kScale1, kScale0);
+ mat.postRotate(90);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // rotation, uniform scale, then different rotation
+ mat.setRotate(kRotation1);
+ mat.postScale(kScale0, kScale0);
+ mat.postRotate(kRotation0);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // rotation, anisotropic scale, then different rotation
+ mat.setRotate(kRotation0);
+ mat.postScale(kScale1, kScale0);
+ mat.postRotate(kRotation1);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // rotation, anisotropic scale + reflection, then different rotation
+ mat.setRotate(kRotation0);
+ mat.postScale(-kScale1, kScale0);
+ mat.postRotate(kRotation1);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // try some random matrices
+ SkRandom rand;
+ for (int m = 0; m < 1000; ++m) {
+ SkScalar rot0 = rand.nextRangeF(-180, 180);
+ SkScalar sx = rand.nextRangeF(-3000.f, 3000.f);
+ SkScalar sy = rand.nextRangeF(-3000.f, 3000.f);
+ SkScalar rot1 = rand.nextRangeF(-180, 180);
+ mat.setRotate(rot0);
+ mat.postScale(sx, sy);
+ mat.postRotate(rot1);
+
+ if (SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2)) {
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+ } else {
+ // if the matrix is degenerate, the basis vectors should be near-parallel or near-zero
+ SkScalar perpdot = mat[SkMatrix::kMScaleX]*mat[SkMatrix::kMScaleY] -
+ mat[SkMatrix::kMSkewX]*mat[SkMatrix::kMSkewY];
+ REPORTER_ASSERT(reporter, SkScalarNearlyZero(perpdot));
+ }
+ }
+
+ // translation shouldn't affect this
+ mat.postTranslate(-1000.f, 1000.f);
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // perspective shouldn't affect this
+ mat[SkMatrix::kMPersp0] = 12.f;
+ mat[SkMatrix::kMPersp1] = 4.f;
+ mat[SkMatrix::kMPersp2] = 1872.f;
+ REPORTER_ASSERT(reporter, SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ REPORTER_ASSERT(reporter, check_matrix_recomposition(mat, rotation1, scale, rotation2));
+
+ // degenerate matrices
+ // mostly zero entries
+ mat.reset();
+ mat[SkMatrix::kMScaleX] = 0.f;
+ REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ mat.reset();
+ mat[SkMatrix::kMScaleY] = 0.f;
+ REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+ mat.reset();
+ // linearly dependent entries
+ mat[SkMatrix::kMScaleX] = 1.f;
+ mat[SkMatrix::kMSkewX] = 2.f;
+ mat[SkMatrix::kMSkewY] = 4.f;
+ mat[SkMatrix::kMScaleY] = 8.f;
+ REPORTER_ASSERT(reporter, !SkDecomposeUpper2x2(mat, &rotation1, &scale, &rotation2));
+}
+
+// For test_matrix_homogeneous, below.
+static bool scalar_array_nearly_equal_relative(const SkScalar a[], const SkScalar b[], int count) {
+ for (int i = 0; i < count; ++i) {
+ if (!scalar_nearly_equal_relative(a[i], b[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// For test_matrix_homogeneous, below.
+// Maps a single triple in src using m and compares results to those in dst
+static bool naive_homogeneous_mapping(const SkMatrix& m, const SkScalar src[3],
+ const SkScalar dst[3]) {
+ SkScalar res[3];
+ SkScalar ms[9] = {m[0], m[1], m[2],
+ m[3], m[4], m[5],
+ m[6], m[7], m[8]};
+ res[0] = src[0] * ms[0] + src[1] * ms[1] + src[2] * ms[2];
+ res[1] = src[0] * ms[3] + src[1] * ms[4] + src[2] * ms[5];
+ res[2] = src[0] * ms[6] + src[1] * ms[7] + src[2] * ms[8];
+ return scalar_array_nearly_equal_relative(res, dst, 3);
+}
+
+static void test_matrix_homogeneous(skiatest::Reporter* reporter) {
+ SkMatrix mat;
+
+ const float kRotation0 = 15.5f;
+ const float kRotation1 = -50.f;
+ const float kScale0 = 5000.f;
+
+ const int kTripleCount = 1000;
+ const int kMatrixCount = 1000;
+ SkRandom rand;
+
+ SkScalar randTriples[3*kTripleCount];
+ for (int i = 0; i < 3*kTripleCount; ++i) {
+ randTriples[i] = rand.nextRangeF(-3000.f, 3000.f);
+ }
+
+ SkMatrix mats[kMatrixCount];
+ for (int i = 0; i < kMatrixCount; ++i) {
+ for (int j = 0; j < 9; ++j) {
+ mats[i].set(j, rand.nextRangeF(-3000.f, 3000.f));
+ }
+ }
+
+ // identity
+ {
+ mat.reset();
+ SkScalar dst[3*kTripleCount];
+ mat.mapHomogeneousPoints(dst, randTriples, kTripleCount);
+ REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(randTriples, dst, kTripleCount*3));
+ }
+
+ // zero matrix
+ {
+ mat.setAll(0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
+ SkScalar dst[3*kTripleCount];
+ mat.mapHomogeneousPoints(dst, randTriples, kTripleCount);
+ SkScalar zeros[3] = {0.f, 0.f, 0.f};
+ for (int i = 0; i < kTripleCount; ++i) {
+ REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(&dst[i*3], zeros, 3));
+ }
+ }
+
+ // zero point
+ {
+ SkScalar zeros[3] = {0.f, 0.f, 0.f};
+ for (int i = 0; i < kMatrixCount; ++i) {
+ SkScalar dst[3];
+ mats[i].mapHomogeneousPoints(dst, zeros, 1);
+ REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(dst, zeros, 3));
+ }
+ }
+
+ // doesn't crash with null dst, src, count == 0
+ {
+ mats[0].mapHomogeneousPoints(NULL, NULL, 0);
+ }
+
+ // uniform scale of point
+ {
+ mat.setScale(kScale0, kScale0);
+ SkScalar dst[3];
+ SkScalar src[3] = {randTriples[0], randTriples[1], 1.f};
+ SkPoint pnt;
+ pnt.set(src[0], src[1]);
+ mat.mapHomogeneousPoints(dst, src, 1);
+ mat.mapPoints(&pnt, &pnt, 1);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1));
+ }
+
+ // rotation of point
+ {
+ mat.setRotate(kRotation0);
+ SkScalar dst[3];
+ SkScalar src[3] = {randTriples[0], randTriples[1], 1.f};
+ SkPoint pnt;
+ pnt.set(src[0], src[1]);
+ mat.mapHomogeneousPoints(dst, src, 1);
+ mat.mapPoints(&pnt, &pnt, 1);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1));
+ }
+
+ // rotation, scale, rotation of point
+ {
+ mat.setRotate(kRotation1);
+ mat.postScale(kScale0, kScale0);
+ mat.postRotate(kRotation0);
+ SkScalar dst[3];
+ SkScalar src[3] = {randTriples[0], randTriples[1], 1.f};
+ SkPoint pnt;
+ pnt.set(src[0], src[1]);
+ mat.mapHomogeneousPoints(dst, src, 1);
+ mat.mapPoints(&pnt, &pnt, 1);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1));
+ }
+
+ // compare with naive approach
+ {
+ for (int i = 0; i < kMatrixCount; ++i) {
+ for (int j = 0; j < kTripleCount; ++j) {
+ SkScalar dst[3];
+ mats[i].mapHomogeneousPoints(dst, &randTriples[j*3], 1);
+ REPORTER_ASSERT(reporter, naive_homogeneous_mapping(mats[i], &randTriples[j*3], dst));
+ }
+ }
+ }
+
+}
+
+DEF_TEST(Matrix, reporter) {
+ SkMatrix mat, inverse, iden1, iden2;
+
+ mat.reset();
+ mat.setTranslate(SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, mat.invert(&inverse));
+ iden1.setConcat(mat, inverse);
+ REPORTER_ASSERT(reporter, is_identity(iden1));
+
+ mat.setScale(SkIntToScalar(2), SkIntToScalar(4));
+ REPORTER_ASSERT(reporter, mat.invert(&inverse));
+ iden1.setConcat(mat, inverse);
+ REPORTER_ASSERT(reporter, is_identity(iden1));
+ test_flatten(reporter, mat);
+
+ mat.setScale(SK_Scalar1/2, SkIntToScalar(2));
+ REPORTER_ASSERT(reporter, mat.invert(&inverse));
+ iden1.setConcat(mat, inverse);
+ REPORTER_ASSERT(reporter, is_identity(iden1));
+ test_flatten(reporter, mat);
+
+ mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20), 0);
+ mat.postRotate(SkIntToScalar(25));
+ REPORTER_ASSERT(reporter, mat.invert(NULL));
+ REPORTER_ASSERT(reporter, mat.invert(&inverse));
+ iden1.setConcat(mat, inverse);
+ REPORTER_ASSERT(reporter, is_identity(iden1));
+ iden2.setConcat(inverse, mat);
+ REPORTER_ASSERT(reporter, is_identity(iden2));
+ test_flatten(reporter, mat);
+ test_flatten(reporter, iden2);
+
+ mat.setScale(0, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !mat.invert(NULL));
+ REPORTER_ASSERT(reporter, !mat.invert(&inverse));
+ mat.setScale(SK_Scalar1, 0);
+ REPORTER_ASSERT(reporter, !mat.invert(NULL));
+ REPORTER_ASSERT(reporter, !mat.invert(&inverse));
+
+ // rectStaysRect test
+ {
+ static const struct {
+ SkScalar m00, m01, m10, m11;
+ bool mStaysRect;
+ }
+ gRectStaysRectSamples[] = {
+ { 0, 0, 0, 0, false },
+ { 0, 0, 0, SK_Scalar1, false },
+ { 0, 0, SK_Scalar1, 0, false },
+ { 0, 0, SK_Scalar1, SK_Scalar1, false },
+ { 0, SK_Scalar1, 0, 0, false },
+ { 0, SK_Scalar1, 0, SK_Scalar1, false },
+ { 0, SK_Scalar1, SK_Scalar1, 0, true },
+ { 0, SK_Scalar1, SK_Scalar1, SK_Scalar1, false },
+ { SK_Scalar1, 0, 0, 0, false },
+ { SK_Scalar1, 0, 0, SK_Scalar1, true },
+ { SK_Scalar1, 0, SK_Scalar1, 0, false },
+ { SK_Scalar1, 0, SK_Scalar1, SK_Scalar1, false },
+ { SK_Scalar1, SK_Scalar1, 0, 0, false },
+ { SK_Scalar1, SK_Scalar1, 0, SK_Scalar1, false },
+ { SK_Scalar1, SK_Scalar1, SK_Scalar1, 0, false },
+ { SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, false }
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRectStaysRectSamples); i++) {
+ SkMatrix m;
+
+ m.reset();
+ m.set(SkMatrix::kMScaleX, gRectStaysRectSamples[i].m00);
+ m.set(SkMatrix::kMSkewX, gRectStaysRectSamples[i].m01);
+ m.set(SkMatrix::kMSkewY, gRectStaysRectSamples[i].m10);
+ m.set(SkMatrix::kMScaleY, gRectStaysRectSamples[i].m11);
+ REPORTER_ASSERT(reporter,
+ m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
+ }
+ }
+
+ mat.reset();
+ mat.set(SkMatrix::kMScaleX, SkIntToScalar(1));
+ mat.set(SkMatrix::kMSkewX, SkIntToScalar(2));
+ mat.set(SkMatrix::kMTransX, SkIntToScalar(3));
+ mat.set(SkMatrix::kMSkewY, SkIntToScalar(4));
+ mat.set(SkMatrix::kMScaleY, SkIntToScalar(5));
+ mat.set(SkMatrix::kMTransY, SkIntToScalar(6));
+ SkScalar affine[6];
+ REPORTER_ASSERT(reporter, mat.asAffine(affine));
+
+ #define affineEqual(e) affine[SkMatrix::kA##e] == mat.get(SkMatrix::kM##e)
+ REPORTER_ASSERT(reporter, affineEqual(ScaleX));
+ REPORTER_ASSERT(reporter, affineEqual(SkewY));
+ REPORTER_ASSERT(reporter, affineEqual(SkewX));
+ REPORTER_ASSERT(reporter, affineEqual(ScaleY));
+ REPORTER_ASSERT(reporter, affineEqual(TransX));
+ REPORTER_ASSERT(reporter, affineEqual(TransY));
+ #undef affineEqual
+
+ mat.set(SkMatrix::kMPersp1, SkScalarToPersp(SK_Scalar1 / 2));
+ REPORTER_ASSERT(reporter, !mat.asAffine(affine));
+
+ SkMatrix mat2;
+ mat2.reset();
+ mat.reset();
+ SkScalar zero = 0;
+ mat.set(SkMatrix::kMSkewX, -zero);
+ REPORTER_ASSERT(reporter, are_equal(reporter, mat, mat2));
+
+ mat2.reset();
+ mat.reset();
+ mat.set(SkMatrix::kMSkewX, SK_ScalarNaN);
+ mat2.set(SkMatrix::kMSkewX, SK_ScalarNaN);
+ REPORTER_ASSERT(reporter, !are_equal(reporter, mat, mat2));
+
+ test_matrix_min_max_scale(reporter);
+ test_matrix_preserve_shape(reporter);
+ test_matrix_recttorect(reporter);
+ test_matrix_decomposition(reporter);
+ test_matrix_homogeneous(reporter);
+}
+
+DEF_TEST(Matrix_Concat, r) {
+ SkMatrix a;
+ a.setTranslate(10, 20);
+
+ SkMatrix b;
+ b.setScale(3, 5);
+
+ SkMatrix expected;
+ expected.setConcat(a,b);
+
+ REPORTER_ASSERT(r, expected == SkMatrix::Concat(a, b));
+}
diff --git a/src/third_party/skia/tests/MemoryTest.cpp b/src/third_party/skia/tests/MemoryTest.cpp
new file mode 100644
index 0000000..c7eff30
--- /dev/null
+++ b/src/third_party/skia/tests/MemoryTest.cpp
@@ -0,0 +1,11 @@
+#include "Test.h"
+
+DEF_TEST(memory_calloc, reporter) {
+ const size_t kNum = 200;
+ char* zeros = (char*)sk_calloc_throw(kNum*sizeof(char));
+
+ for (size_t i = 0; i < kNum; i++) {
+ REPORTER_ASSERT(reporter, 0 == zeros[i]);
+ }
+ sk_free(zeros);
+}
diff --git a/src/third_party/skia/tests/MemsetTest.cpp b/src/third_party/skia/tests/MemsetTest.cpp
new file mode 100644
index 0000000..ee6aaea
--- /dev/null
+++ b/src/third_party/skia/tests/MemsetTest.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkChunkAlloc.h"
+#include "SkUtils.h"
+#include "Test.h"
+
+static void test_chunkalloc(skiatest::Reporter* reporter) {
+ size_t min = 256;
+ SkChunkAlloc alloc(min);
+
+ REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity());
+ REPORTER_ASSERT(reporter, 0 == alloc.totalUsed());
+ REPORTER_ASSERT(reporter, 0 == alloc.blockCount());
+ REPORTER_ASSERT(reporter, !alloc.contains(NULL));
+ REPORTER_ASSERT(reporter, !alloc.contains(reporter));
+
+ alloc.reset();
+ REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity());
+ REPORTER_ASSERT(reporter, 0 == alloc.totalUsed());
+ REPORTER_ASSERT(reporter, 0 == alloc.blockCount());
+
+ size_t size = min >> 1;
+ void* ptr = alloc.allocThrow(size);
+ REPORTER_ASSERT(reporter, alloc.totalCapacity() >= size);
+ REPORTER_ASSERT(reporter, alloc.totalUsed() == size);
+ REPORTER_ASSERT(reporter, alloc.blockCount() > 0);
+ REPORTER_ASSERT(reporter, alloc.contains(ptr));
+
+ alloc.reset();
+ REPORTER_ASSERT(reporter, !alloc.contains(ptr));
+ REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity());
+ REPORTER_ASSERT(reporter, 0 == alloc.totalUsed());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void set_zero(void* dst, size_t bytes) {
+ char* ptr = (char*)dst;
+ for (size_t i = 0; i < bytes; ++i) {
+ ptr[i] = 0;
+ }
+}
+
+#define MAX_ALIGNMENT 64
+#define MAX_COUNT ((MAX_ALIGNMENT) * 32)
+#define PAD 32
+#define TOTAL (PAD + MAX_ALIGNMENT + MAX_COUNT + PAD)
+
+#define VALUE16 0x1234
+#define VALUE32 0x12345678
+
+static bool compare16(const uint16_t base[], uint16_t value, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (base[i] != value) {
+ SkDebugf("[%d] expected %x found %x\n", i, value, base[i]);
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool compare32(const uint32_t base[], uint32_t value, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (base[i] != value) {
+ SkDebugf("[%d] expected %x found %x\n", i, value, base[i]);
+ return false;
+ }
+ }
+ return true;
+}
+
+static void test_16(skiatest::Reporter* reporter) {
+ uint16_t buffer[TOTAL];
+
+ for (int count = 0; count < MAX_COUNT; ++count) {
+ for (int alignment = 0; alignment < MAX_ALIGNMENT; ++alignment) {
+ set_zero(buffer, sizeof(buffer));
+
+ uint16_t* base = &buffer[PAD + alignment];
+ sk_memset16(base, VALUE16, count);
+
+ REPORTER_ASSERT(reporter,
+ compare16(buffer, 0, PAD + alignment) &&
+ compare16(base, VALUE16, count) &&
+ compare16(base + count, 0, TOTAL - count - PAD - alignment));
+ }
+ }
+}
+
+static void test_32(skiatest::Reporter* reporter) {
+ uint32_t buffer[TOTAL];
+
+ for (int count = 0; count < MAX_COUNT; ++count) {
+ for (int alignment = 0; alignment < MAX_ALIGNMENT; ++alignment) {
+ set_zero(buffer, sizeof(buffer));
+
+ uint32_t* base = &buffer[PAD + alignment];
+ sk_memset32(base, VALUE32, count);
+
+ REPORTER_ASSERT(reporter,
+ compare32(buffer, 0, PAD + alignment) &&
+ compare32(base, VALUE32, count) &&
+ compare32(base + count, 0, TOTAL - count - PAD - alignment));
+ }
+ }
+}
+
+/**
+ * Test sk_memset16 and sk_memset32.
+ * For performance considerations, implementations may take different paths
+ * depending on the alignment of the dst, and/or the size of the count.
+ */
+DEF_TEST(Memset, reporter) {
+ test_16(reporter);
+ test_32(reporter);
+
+ test_chunkalloc(reporter);
+}
diff --git a/src/third_party/skia/tests/MessageBusTest.cpp b/src/third_party/skia/tests/MessageBusTest.cpp
new file mode 100644
index 0000000..f7a02b2
--- /dev/null
+++ b/src/third_party/skia/tests/MessageBusTest.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkMessageBus.h"
+#include "Test.h"
+
+struct TestMessage {
+ int x;
+ float y;
+};
+DECLARE_SKMESSAGEBUS_MESSAGE(TestMessage)
+
+DEF_TEST(MessageBus, r) {
+ // Register two inboxes to receive all TestMessages.
+ SkMessageBus<TestMessage>::Inbox inbox1, inbox2;
+
+ // Send two messages.
+ const TestMessage m1 = { 5, 4.2f };
+ const TestMessage m2 = { 6, 4.3f };
+ SkMessageBus<TestMessage>::Post(m1);
+ SkMessageBus<TestMessage>::Post(m2);
+
+ // Make sure we got two.
+ SkTDArray<TestMessage> messages;
+ inbox1.poll(&messages);
+ REPORTER_ASSERT(r, 2 == messages.count());
+ REPORTER_ASSERT(r, 5 == messages[0].x);
+ REPORTER_ASSERT(r, 6 == messages[1].x);
+
+ // Send another; check we get just that one.
+ const TestMessage m3 = { 1, 0.3f };
+ SkMessageBus<TestMessage>::Post(m3);
+ inbox1.poll(&messages);
+ REPORTER_ASSERT(r, 1 == messages.count());
+ REPORTER_ASSERT(r, 1 == messages[0].x);
+
+ // Nothing was sent since the last read.
+ inbox1.poll(&messages);
+ REPORTER_ASSERT(r, 0 == messages.count());
+
+ // Over all this time, inbox2 should have piled up 3 messages.
+ inbox2.poll(&messages);
+ REPORTER_ASSERT(r, 3 == messages.count());
+ REPORTER_ASSERT(r, 5 == messages[0].x);
+ REPORTER_ASSERT(r, 6 == messages[1].x);
+ REPORTER_ASSERT(r, 1 == messages[2].x);
+}
+
+// Multithreaded tests tbd.
diff --git a/src/third_party/skia/tests/MetaDataTest.cpp b/src/third_party/skia/tests/MetaDataTest.cpp
new file mode 100644
index 0000000..eb7eae9
--- /dev/null
+++ b/src/third_party/skia/tests/MetaDataTest.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkMetaData.h"
+#include "Test.h"
+
+static void test_ptrs(skiatest::Reporter* reporter) {
+ SkRefCnt ref;
+ REPORTER_ASSERT(reporter, 1 == ref.getRefCnt());
+
+ {
+ SkMetaData md0, md1;
+ const char name[] = "refcnt";
+
+ md0.setRefCnt(name, &ref);
+ REPORTER_ASSERT(reporter, md0.findRefCnt(name));
+ REPORTER_ASSERT(reporter, md0.hasRefCnt(name, &ref));
+ REPORTER_ASSERT(reporter, 2 == ref.getRefCnt());
+
+ md1 = md0;
+ REPORTER_ASSERT(reporter, md1.findRefCnt(name));
+ REPORTER_ASSERT(reporter, md1.hasRefCnt(name, &ref));
+ REPORTER_ASSERT(reporter, 3 == ref.getRefCnt());
+
+ REPORTER_ASSERT(reporter, md0.removeRefCnt(name));
+ REPORTER_ASSERT(reporter, !md0.findRefCnt(name));
+ REPORTER_ASSERT(reporter, !md0.hasRefCnt(name, &ref));
+ REPORTER_ASSERT(reporter, 2 == ref.getRefCnt());
+ }
+ REPORTER_ASSERT(reporter, 1 == ref.getRefCnt());
+}
+
+DEF_TEST(MetaData, reporter) {
+ SkMetaData m1;
+
+ REPORTER_ASSERT(reporter, !m1.findS32("int"));
+ REPORTER_ASSERT(reporter, !m1.findScalar("scalar"));
+ REPORTER_ASSERT(reporter, !m1.findString("hello"));
+ REPORTER_ASSERT(reporter, !m1.removeS32("int"));
+ REPORTER_ASSERT(reporter, !m1.removeScalar("scalar"));
+ REPORTER_ASSERT(reporter, !m1.removeString("hello"));
+ REPORTER_ASSERT(reporter, !m1.removeString("true"));
+ REPORTER_ASSERT(reporter, !m1.removeString("false"));
+
+ m1.setS32("int", 12345);
+ m1.setScalar("scalar", SK_Scalar1 * 42);
+ m1.setString("hello", "world");
+ m1.setPtr("ptr", &m1);
+ m1.setBool("true", true);
+ m1.setBool("false", false);
+
+ int32_t n;
+ SkScalar s;
+
+ m1.setScalar("scalar", SK_Scalar1/2);
+
+ REPORTER_ASSERT(reporter, m1.findS32("int", &n) && n == 12345);
+ REPORTER_ASSERT(reporter, m1.findScalar("scalar", &s) && s == SK_Scalar1/2);
+ REPORTER_ASSERT(reporter, !strcmp(m1.findString("hello"), "world"));
+ REPORTER_ASSERT(reporter, m1.hasBool("true", true));
+ REPORTER_ASSERT(reporter, m1.hasBool("false", false));
+
+ SkMetaData::Iter iter(m1);
+ const char* name;
+
+ static const struct {
+ const char* fName;
+ SkMetaData::Type fType;
+ int fCount;
+ } gElems[] = {
+ { "int", SkMetaData::kS32_Type, 1 },
+ { "scalar", SkMetaData::kScalar_Type, 1 },
+ { "ptr", SkMetaData::kPtr_Type, 1 },
+ { "hello", SkMetaData::kString_Type, sizeof("world") },
+ { "true", SkMetaData::kBool_Type, 1 },
+ { "false", SkMetaData::kBool_Type, 1 }
+ };
+
+ int loop = 0;
+ int count;
+ SkMetaData::Type t;
+ while ((name = iter.next(&t, &count)) != NULL)
+ {
+ int match = 0;
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(gElems); i++)
+ {
+ if (!strcmp(name, gElems[i].fName))
+ {
+ match += 1;
+ REPORTER_ASSERT(reporter, gElems[i].fType == t);
+ REPORTER_ASSERT(reporter, gElems[i].fCount == count);
+ }
+ }
+ REPORTER_ASSERT(reporter, match == 1);
+ loop += 1;
+ }
+ REPORTER_ASSERT(reporter, loop == SK_ARRAY_COUNT(gElems));
+
+ REPORTER_ASSERT(reporter, m1.removeS32("int"));
+ REPORTER_ASSERT(reporter, m1.removeScalar("scalar"));
+ REPORTER_ASSERT(reporter, m1.removeString("hello"));
+ REPORTER_ASSERT(reporter, m1.removeBool("true"));
+ REPORTER_ASSERT(reporter, m1.removeBool("false"));
+
+ REPORTER_ASSERT(reporter, !m1.findS32("int"));
+ REPORTER_ASSERT(reporter, !m1.findScalar("scalar"));
+ REPORTER_ASSERT(reporter, !m1.findString("hello"));
+ REPORTER_ASSERT(reporter, !m1.findBool("true"));
+ REPORTER_ASSERT(reporter, !m1.findBool("false"));
+
+ test_ptrs(reporter);
+}
diff --git a/src/third_party/skia/tests/MiniDataTest.cpp b/src/third_party/skia/tests/MiniDataTest.cpp
new file mode 100644
index 0000000..cb656b3
--- /dev/null
+++ b/src/third_party/skia/tests/MiniDataTest.cpp
@@ -0,0 +1,16 @@
+#include "SkMiniData.h"
+#include "Test.h"
+
+DEF_TEST(MiniData, r) {
+ static const char* s = "abcdefghijklmnopqrstuvwxyz";
+
+ for (size_t len = 0; len <= 26; len++) {
+ SkMiniData md(s, len);
+ REPORTER_ASSERT(r, md.len() == len);
+ REPORTER_ASSERT(r, 0 == memcmp(md.data(), s, len));
+
+ SkMiniData copy(md);
+ REPORTER_ASSERT(r, copy.len() == len);
+ REPORTER_ASSERT(r, 0 == memcmp(copy.data(), s, len));
+ }
+}
diff --git a/src/third_party/skia/tests/MipMapTest.cpp b/src/third_party/skia/tests/MipMapTest.cpp
new file mode 100644
index 0000000..33f4672
--- /dev/null
+++ b/src/third_party/skia/tests/MipMapTest.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkMipMap.h"
+#include "SkRandom.h"
+#include "Test.h"
+
+static void make_bitmap(SkBitmap* bm, SkRandom& rand) {
+ // for now, Build needs a min size of 2, otherwise it will return NULL.
+ // should fix that to support 1 X N, where N > 1 to return non-null.
+ int w = 2 + rand.nextU() % 1000;
+ int h = 2 + rand.nextU() % 1000;
+ bm->allocN32Pixels(w, h);
+ bm->eraseColor(SK_ColorWHITE);
+}
+
+DEF_TEST(MipMap, reporter) {
+ SkBitmap bm;
+ SkRandom rand;
+
+ for (int i = 0; i < 500; ++i) {
+ make_bitmap(&bm, rand);
+ SkAutoTUnref<SkMipMap> mm(SkMipMap::Build(bm));
+
+ REPORTER_ASSERT(reporter, !mm->extractLevel(SK_Scalar1, NULL));
+ REPORTER_ASSERT(reporter, !mm->extractLevel(SK_Scalar1 * 2, NULL));
+
+ SkMipMap::Level prevLevel;
+ sk_bzero(&prevLevel, sizeof(prevLevel));
+
+ SkScalar scale = SK_Scalar1;
+ for (int j = 0; j < 30; ++j) {
+ scale = scale * 2 / 3;
+
+ SkMipMap::Level level;
+ if (mm->extractLevel(scale, &level)) {
+ REPORTER_ASSERT(reporter, level.fPixels);
+ REPORTER_ASSERT(reporter, level.fWidth > 0);
+ REPORTER_ASSERT(reporter, level.fHeight > 0);
+ REPORTER_ASSERT(reporter, level.fRowBytes >= level.fWidth * 4);
+
+ if (prevLevel.fPixels) {
+ REPORTER_ASSERT(reporter, level.fWidth <= prevLevel.fWidth);
+ REPORTER_ASSERT(reporter, level.fHeight <= prevLevel.fHeight);
+ }
+ prevLevel = level;
+ }
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/NameAllocatorTest.cpp b/src/third_party/skia/tests/NameAllocatorTest.cpp
new file mode 100644
index 0000000..86efdb2
--- /dev/null
+++ b/src/third_party/skia/tests/NameAllocatorTest.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#if SK_SUPPORT_GPU
+
+#include "gl/GrGLNameAllocator.h"
+#include "Test.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+class NameLeakTest {
+ static const GrGLuint kFirstName = 101;
+ static const GrGLuint kRange = 1013;
+
+public:
+ NameLeakTest(skiatest::Reporter* reporter)
+ : fReporter(reporter),
+ fAllocator(kFirstName, kFirstName + kRange),
+ fAllocatedCount(0),
+ fRandomName(kFirstName + 4 * kRange / 7) {
+ memset(fAllocatedNames, 0, sizeof(fAllocatedNames));
+ }
+
+ bool run() {
+ if (!this->allocateAllRemaining()) {
+ return false;
+ }
+
+ for (GrGLuint freeCount = 1; freeCount <= kRange; ++freeCount) {
+ if (!this->freeRandomNames(freeCount)) {
+ return false;
+ }
+ if (!this->allocateAllRemaining()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+private:
+ bool isAllocated(GrGLuint name) const {
+ return fAllocatedNames[name - kFirstName];
+ }
+
+ void setAllocated(GrGLuint name, bool allocated) {
+ fAllocatedNames[name - kFirstName] = allocated;
+ }
+
+ bool allocateAllRemaining() {
+ for (; fAllocatedCount < kRange; ++fAllocatedCount) {
+ GrGLuint name = fAllocator.allocateName();
+ if (0 == name) {
+ ERRORF(fReporter,
+ "Name allocate failed, but there should still be %u free names",
+ kRange - fAllocatedCount);
+ return false;
+ }
+ if (name < kFirstName || name >= kFirstName + kRange) {
+ ERRORF(fReporter,
+ "Name allocate returned name %u outside its bounds [%u, %u)",
+ name, kFirstName, kFirstName + kRange);
+ return false;
+ }
+ if (this->isAllocated(name)) {
+ ERRORF(fReporter, "Name allocate returned name that is already allocated");
+ return false;
+ }
+
+ this->setAllocated(name, true);
+ }
+
+ // Ensure it returns 0 once all the names are allocated.
+ GrGLuint name = fAllocator.allocateName();
+ if (0 != name) {
+ ERRORF(fReporter,
+ "Name allocate did not fail when all names were already in use");
+ return false;
+ }
+
+ // Ensure every unique name is allocated.
+ for (GrGLuint i = 0; i < kRange; ++i) {
+ if (!this->isAllocated(kFirstName + i)) {
+ ERRORF(fReporter, "Not all unique names are allocated after allocateAllRemaining()");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool freeRandomNames(GrGLuint count) {
+ // The values a and c make up an LCG (pseudo-random generator). These
+ // values must satisfy the Hull-Dobell Theorem (with m=kRange):
+ // http://en.wikipedia.org/wiki/Linear_congruential_generator
+ // We use our own generator to guarantee it hits each unique value
+ // within kRange exactly once before repeating.
+ const GrGLuint seed = (count + fRandomName) / 2;
+ const GrGLuint a = seed * kRange + 1;
+ const GrGLuint c = (seed * 743) % kRange;
+
+ for (GrGLuint i = 0; i < count; ++i) {
+ fRandomName = (a * fRandomName + c) % kRange;
+ const GrGLuint name = kFirstName + fRandomName;
+ if (!this->isAllocated(name)) {
+ ERRORF(fReporter, "Test bug: Should not free a not-allocated name at this point (%u)", i);
+ return false;
+ }
+
+ fAllocator.free(name);
+ this->setAllocated(name, false);
+ --fAllocatedCount;
+ }
+
+ return true;
+ }
+
+ skiatest::Reporter* fReporter;
+ GrGLNameAllocator fAllocator;
+ bool fAllocatedNames[kRange];
+ GrGLuint fAllocatedCount;
+ GrGLuint fRandomName;
+};
+
+DEF_GPUTEST(NameAllocator, reporter, factory) {
+ // Ensure no names are leaked or double-allocated during heavy usage.
+ {
+ NameLeakTest nameLeakTest(reporter);
+ nameLeakTest.run();
+ }
+
+ static const GrGLuint range = 32;
+ GrGLNameAllocator allocator(1, 1 + range);
+ for (GrGLuint i = 1; i <= range; ++i) {
+ allocator.allocateName();
+ }
+ REPORTER_ASSERT(reporter, 0 == allocator.allocateName());
+
+ // Test freeing names out of range.
+ allocator.free(allocator.firstName() - 1);
+ allocator.free(allocator.endName());
+ REPORTER_ASSERT(reporter, 0 == allocator.allocateName());
+
+ // Test freeing not-allocated names.
+ for (GrGLuint i = 1; i <= range/2; i += 2) {
+ allocator.free(i);
+ }
+ for (GrGLuint i = 1; i <= range/2; i += 2) {
+ // None of these names will be allocated.
+ allocator.free(i);
+ }
+ for (GrGLuint i = 1; i <= range/2; ++i) {
+ // Every other name will not be be allocated.
+ allocator.free(i);
+ }
+ for (GrGLuint i = 1; i <= range/2; ++i) {
+ if (0 == allocator.allocateName()) {
+ ERRORF(reporter, "Name allocate failed when there should be free names");
+ break;
+ }
+ }
+ REPORTER_ASSERT(reporter, 0 == allocator.allocateName());
+}
+
+#endif
diff --git a/src/third_party/skia/tests/OSPathTest.cpp b/src/third_party/skia/tests/OSPathTest.cpp
new file mode 100644
index 0000000..facc6ad
--- /dev/null
+++ b/src/third_party/skia/tests/OSPathTest.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkOSFile.h"
+#include "SkString.h"
+#include "Test.h"
+
+/**
+ * Test SkOSPath::Join, SkOSPath::Basename, and SkOSPath::Dirname.
+ * Will use SkOSPath::Join to append filename to dir, test that it works correctly,
+ * and tests using SkOSPath::Basename on the result.
+ * @param reporter Reporter for test conditions.
+ * @param dir String representing the path to a folder. May or may not
+ * end with SkPATH_SEPARATOR.
+ * @param filename String representing the basename of a file. Must NOT
+ * contain SkPATH_SEPARATOR.
+ */
+static void test_dir_with_file(skiatest::Reporter* reporter, SkString dir,
+ SkString filename) {
+ // If filename contains SkPATH_SEPARATOR, the tests will fail.
+ SkASSERT(!filename.contains(SkPATH_SEPARATOR));
+
+ // Tests for SkOSPath::Join and SkOSPath::Basename
+
+ // fullName should be "dir<SkPATH_SEPARATOR>file"
+ SkString fullName = SkOSPath::Join(dir.c_str(), filename.c_str());
+
+ // fullName should be the combined size of dir and file, plus one if
+ // dir did not include the final path separator.
+ size_t expectedSize = dir.size() + filename.size();
+ if (!dir.endsWith(SkPATH_SEPARATOR) && !dir.isEmpty()) {
+ expectedSize++;
+ }
+ REPORTER_ASSERT(reporter, fullName.size() == expectedSize);
+
+ SkString basename = SkOSPath::Basename(fullName.c_str());
+ SkString dirname = SkOSPath::Dirname(fullName.c_str());
+
+ // basename should be the same as filename
+ REPORTER_ASSERT(reporter, basename.equals(filename));
+
+ // dirname should be the same as dir with any trailing seperators removed.
+ // Except when the the string is just "/".
+ SkString strippedDir = dir;
+ while (strippedDir.size() > 2 && strippedDir[strippedDir.size() - 1] == SkPATH_SEPARATOR) {
+ strippedDir.remove(strippedDir.size() - 1, 1);
+ }
+ if (!dirname.equals(strippedDir)) {
+ SkDebugf("OOUCH %s %s %s\n", dir.c_str(), strippedDir.c_str(), dirname.c_str());
+ }
+ REPORTER_ASSERT(reporter, dirname.equals(strippedDir));
+
+ // basename will not contain a path separator
+ REPORTER_ASSERT(reporter, !basename.contains(SkPATH_SEPARATOR));
+
+ // Now take the basename of filename, which should be the same as filename.
+ basename = SkOSPath::Basename(filename.c_str());
+ REPORTER_ASSERT(reporter, basename.equals(filename));
+}
+
+DEF_TEST(OSPath, reporter) {
+ SkString dir("dir");
+ SkString filename("file");
+ test_dir_with_file(reporter, dir, filename);
+
+ // Now make sure this works with a path separator at the end of dir.
+ dir.appendUnichar(SkPATH_SEPARATOR);
+ test_dir_with_file(reporter, dir, filename);
+
+ // Test using no filename.
+ test_dir_with_file(reporter, dir, SkString());
+
+ // Testing using no directory.
+ test_dir_with_file(reporter, SkString(), filename);
+
+ // Test with a sub directory.
+ dir.append("subDir");
+ test_dir_with_file(reporter, dir, filename);
+
+ // Basename of a directory with a path separator at the end is empty.
+ dir.appendUnichar(SkPATH_SEPARATOR);
+ SkString baseOfDir = SkOSPath::Basename(dir.c_str());
+ REPORTER_ASSERT(reporter, baseOfDir.size() == 0);
+
+ // Basename of NULL is an empty string.
+ SkString empty = SkOSPath::Basename(NULL);
+ REPORTER_ASSERT(reporter, empty.size() == 0);
+
+ // File in root dir
+ dir.printf("%c", SkPATH_SEPARATOR);
+ filename.set("file");
+ test_dir_with_file(reporter, dir, filename);
+
+ // Just the root dir
+ filename.reset();
+ test_dir_with_file(reporter, dir, filename);
+
+ // Test that NULL can be used for the directory and filename.
+ SkString emptyPath = SkOSPath::Join(NULL, NULL);
+ REPORTER_ASSERT(reporter, emptyPath.isEmpty());
+}
diff --git a/src/third_party/skia/tests/ObjectPoolTest.cpp b/src/third_party/skia/tests/ObjectPoolTest.cpp
new file mode 100644
index 0000000..404448e
--- /dev/null
+++ b/src/third_party/skia/tests/ObjectPoolTest.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTObjectPool.h"
+#include "SkTObjectPool.h"
+#include "Test.h"
+
+class PoolEntry {
+public:
+private:
+ SK_DECLARE_INTERNAL_SLIST_INTERFACE(PoolEntry);
+};
+
+static const int kNumItemsPerBlock = 3;
+typedef SkTObjectPool<PoolEntry, kNumItemsPerBlock> ObjectPoolType;
+
+static bool verifyPool(skiatest::Reporter* reporter,
+ const ObjectPoolType& pool,
+ const char* stage,
+ int available, int blocks) {
+ if (available != pool.available()) {
+ ERRORF(reporter, "%s - Pool available is %d not %d",
+ stage, pool.available(), available);
+ return false;
+ }
+ if (blocks != pool.blocks()) {
+ ERRORF(reporter, "%s - Pool blocks is %d not %d",
+ stage, pool.blocks(), blocks);
+ return false;
+ }
+ return true;
+}
+
+static const int kNumToAcquire = kNumItemsPerBlock * 5;
+static void testObjectPool(skiatest::Reporter* reporter) {
+ ObjectPoolType pool;
+ SkTInternalSList<PoolEntry> used;
+ verifyPool(reporter, pool, "empty", 0, 0);
+ for (int index = 0; index < kNumToAcquire; ++index) {
+ used.push(pool.acquire());
+ int blocks = (index / kNumItemsPerBlock) + 1;
+ int available = (blocks * kNumItemsPerBlock) - (index + 1);
+ if (!verifyPool(reporter, pool, "acquire", available, blocks)) {
+ return;
+ }
+ }
+ int available = pool.available();
+ int blocks = pool.blocks();
+ for (int index = 0; index < kNumToAcquire / 2; ++index) {
+ pool.release(used.pop());
+ ++available;
+ if (!verifyPool(reporter, pool, "release", available, blocks)) {
+ return;
+ }
+ }
+ available += used.getCount();
+ pool.releaseAll(&used);
+ REPORTER_ASSERT(reporter, used.isEmpty());
+ verifyPool(reporter, pool, "releaseAll", available, blocks);
+}
+
+DEF_TEST(ObjectPool, reporter) {
+ testObjectPool(reporter);
+}
diff --git a/src/third_party/skia/tests/OnceTest.cpp b/src/third_party/skia/tests/OnceTest.cpp
new file mode 100644
index 0000000..192abaa
--- /dev/null
+++ b/src/third_party/skia/tests/OnceTest.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkOnce.h"
+#include "SkTaskGroup.h"
+#include "Test.h"
+
+static void add_five(int* x) {
+ *x += 5;
+}
+
+DEF_TEST(SkOnce_Singlethreaded, r) {
+ int x = 0;
+
+ SK_DECLARE_STATIC_ONCE(once);
+ // No matter how many times we do this, x will be 5.
+ SkOnce(&once, add_five, &x);
+ SkOnce(&once, add_five, &x);
+ SkOnce(&once, add_five, &x);
+ SkOnce(&once, add_five, &x);
+ SkOnce(&once, add_five, &x);
+
+ REPORTER_ASSERT(r, 5 == x);
+}
+
+static void add_six(int* x) {
+ *x += 6;
+}
+
+class Racer : public SkRunnable {
+public:
+ SkOnceFlag* once;
+ int* ptr;
+
+ virtual void run() SK_OVERRIDE {
+ SkOnce(once, add_six, ptr);
+ }
+};
+
+DEF_TEST(SkOnce_Multithreaded, r) {
+ const int kTasks = 16;
+
+ // Make a bunch of tasks that will race to be the first to add six to x.
+ Racer racers[kTasks];
+ SK_DECLARE_STATIC_ONCE(once);
+ int x = 0;
+ for (int i = 0; i < kTasks; i++) {
+ racers[i].once = &once;
+ racers[i].ptr = &x;
+ }
+
+ // Let them race.
+ SkTaskGroup tg;
+ for (int i = 0; i < kTasks; i++) {
+ tg.add(&racers[i]);
+ }
+ tg.wait();
+
+ // Only one should have done the +=.
+ REPORTER_ASSERT(r, 6 == x);
+}
+
+static int gX = 0;
+static void inc_gX() { gX++; }
+
+DEF_TEST(SkOnce_NoArg, r) {
+ SK_DECLARE_STATIC_ONCE(once);
+ SkOnce(&once, inc_gX);
+ SkOnce(&once, inc_gX);
+ SkOnce(&once, inc_gX);
+ REPORTER_ASSERT(r, 1 == gX);
+}
diff --git a/src/third_party/skia/tests/PDFJpegEmbedTest.cpp b/src/third_party/skia/tests/PDFJpegEmbedTest.cpp
new file mode 100644
index 0000000..c1d0ea8
--- /dev/null
+++ b/src/third_party/skia/tests/PDFJpegEmbedTest.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkDocument.h"
+#include "SkCanvas.h"
+#include "SkImageGenerator.h"
+#include "SkData.h"
+#include "SkStream.h"
+#include "SkDecodingImageGenerator.h"
+
+#include "Resources.h"
+#include "Test.h"
+
+// Returned bitmap is lazy. Only lazy bitmaps hold onto the original data.
+static SkBitmap bitmap_from_data(SkData* data) {
+ SkASSERT(data);
+ SkBitmap bm;
+ SkInstallDiscardablePixelRef(
+ SkDecodingImageGenerator::Create(
+ data, SkDecodingImageGenerator::Options()), &bm);
+ return bm;
+}
+
+static bool is_subset_of(SkData* smaller, SkData* larger) {
+ SkASSERT(smaller && larger);
+ if (smaller->size() > larger->size()) {
+ return false;
+ }
+ size_t size = smaller->size();
+ size_t size_diff = larger->size() - size;
+ for (size_t i = 0; i <= size_diff; ++i) {
+ if (0 == memcmp(larger->bytes() + i, smaller->bytes(), size)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+static SkData* load_resource(
+ skiatest::Reporter* r, const char* test, const char* filename) {
+ SkString path(GetResourcePath(filename));
+ SkData* data = SkData::NewFromFileName(path.c_str());
+ if (!data && r->verbose()) {
+ SkDebugf("\n%s: Resource '%s' can not be found.\n",
+ test, filename);
+ }
+ return data; // May return NULL.
+}
+
+/**
+ * Test that for Jpeg files that use the JFIF colorspace, they are
+ * directly embedded into the PDF (without re-encoding) when that
+ * makes sense.
+ */
+DEF_TEST(PDFJpegEmbedTest, r) {
+ const char test[] = "PDFJpegEmbedTest";
+ SkAutoTUnref<SkData> mandrillData(
+ load_resource(r, test, "mandrill_512_q075.jpg"));
+ SkAutoTUnref<SkData> cmykData(load_resource(r, test, "CMYK.jpg"));
+ if (!mandrillData || !cmykData) {
+ return;
+ }
+
+ SkDynamicMemoryWStream pdf;
+ SkAutoTUnref<SkDocument> document(SkDocument::CreatePDF(&pdf));
+ SkCanvas* canvas = document->beginPage(642, 1028);
+
+ canvas->clear(SK_ColorLTGRAY);
+
+ SkBitmap bm1(bitmap_from_data(mandrillData));
+ canvas->drawBitmap(bm1, 65.0, 0.0, NULL);
+ SkBitmap bm2(bitmap_from_data(cmykData));
+ canvas->drawBitmap(bm2, 0.0, 512.0, NULL);
+
+ canvas->flush();
+ document->endPage();
+ document->close();
+ SkAutoTUnref<SkData> pdfData(pdf.copyToData());
+ SkASSERT(pdfData);
+ pdf.reset();
+
+ REPORTER_ASSERT(r, is_subset_of(mandrillData, pdfData));
+
+ // This JPEG uses a nonstandard colorspace - it can not be
+ // embedded into the PDF directly.
+ REPORTER_ASSERT(r, !is_subset_of(cmykData, pdfData));
+
+ // The following is for debugging purposes only.
+ const char* outputPath = getenv("SKIA_TESTS_PDF_JPEG_EMBED_OUTPUT_PATH");
+ if (outputPath) {
+ SkFILEWStream output(outputPath);
+ if (output.isValid()) {
+ output.write(pdfData->data(), pdfData->size());
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/PDFPrimitivesTest.cpp b/src/third_party/skia/tests/PDFPrimitivesTest.cpp
new file mode 100644
index 0000000..05677cd
--- /dev/null
+++ b/src/third_party/skia/tests/PDFPrimitivesTest.cpp
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2010 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkData.h"
+#include "SkFlate.h"
+#include "SkImageEncoder.h"
+#include "SkMatrix.h"
+#include "SkPDFCatalog.h"
+#include "SkPDFDevice.h"
+#include "SkPDFStream.h"
+#include "SkPDFTypes.h"
+#include "SkReadBuffer.h"
+#include "SkScalar.h"
+#include "SkStream.h"
+#include "SkTypes.h"
+#include "Test.h"
+
+class SkPDFTestDict : public SkPDFDict {
+public:
+ virtual void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
+ SkTSet<SkPDFObject*>* newResourceObjects) {
+ for (int i = 0; i < fResources.count(); i++) {
+ newResourceObjects->add(fResources[i]);
+ fResources[i]->ref();
+ }
+ }
+
+ void addResource(SkPDFObject* object) {
+ fResources.append(1, &object);
+ }
+
+private:
+ SkTDArray<SkPDFObject*> fResources;
+};
+
+#define DUMMY_TEXT "DCT compessed stream."
+
+static SkData* encode_to_dct_data(size_t* pixelRefOffset, const SkBitmap& bitmap) {
+ *pixelRefOffset = 0;
+ return SkData::NewWithProc(DUMMY_TEXT, sizeof(DUMMY_TEXT) - 1, NULL, NULL);
+}
+
+static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
+ const void* buffer, size_t len) {
+ SkAutoDataUnref data(stream.copyToData());
+ if (offset + len > data->size()) {
+ return false;
+ }
+ return memcmp(data->bytes() + offset, buffer, len) == 0;
+}
+
+static bool stream_contains(const SkDynamicMemoryWStream& stream,
+ const char* buffer) {
+ SkAutoDataUnref data(stream.copyToData());
+ int len = strlen(buffer); // our buffer does not have EOSs.
+
+ for (int offset = 0 ; offset < (int)data->size() - len; offset++) {
+ if (memcmp(data->bytes() + offset, buffer, len) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj,
+ const char* expectedData, size_t expectedSize,
+ bool indirect, bool compression) {
+ SkPDFDocument::Flags docFlags = (SkPDFDocument::Flags) 0;
+ if (!compression) {
+ docFlags = SkTBitOr(docFlags, SkPDFDocument::kFavorSpeedOverSize_Flags);
+ }
+ SkPDFCatalog catalog(docFlags);
+ size_t directSize = obj->getOutputSize(&catalog, false);
+ REPORTER_ASSERT(reporter, directSize == expectedSize);
+
+ SkDynamicMemoryWStream buffer;
+ obj->emit(&buffer, &catalog, false);
+ REPORTER_ASSERT(reporter, directSize == buffer.getOffset());
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedData,
+ directSize));
+
+ if (indirect) {
+ // Indirect output.
+ static char header[] = "1 0 obj\n";
+ static size_t headerLen = strlen(header);
+ static char footer[] = "\nendobj\n";
+ static size_t footerLen = strlen(footer);
+
+ catalog.addObject(obj, false);
+
+ size_t indirectSize = obj->getOutputSize(&catalog, true);
+ REPORTER_ASSERT(reporter,
+ indirectSize == directSize + headerLen + footerLen);
+
+ buffer.reset();
+ obj->emit(&buffer, &catalog, true);
+ REPORTER_ASSERT(reporter, indirectSize == buffer.getOffset());
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, header, headerLen));
+ REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen, expectedData,
+ directSize));
+ REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen + directSize,
+ footer, footerLen));
+ }
+}
+
+static void SimpleCheckObjectOutput(skiatest::Reporter* reporter,
+ SkPDFObject* obj,
+ const char* expectedResult) {
+ CheckObjectOutput(reporter, obj, expectedResult,
+ strlen(expectedResult), true, false);
+}
+
+static void TestPDFStream(skiatest::Reporter* reporter) {
+ char streamBytes[] = "Test\nFoo\tBar";
+ SkAutoTUnref<SkMemoryStream> streamData(new SkMemoryStream(
+ streamBytes, strlen(streamBytes), true));
+ SkAutoTUnref<SkPDFStream> stream(new SkPDFStream(streamData.get()));
+ SimpleCheckObjectOutput(
+ reporter, stream.get(),
+ "<</Length 12\n>> stream\nTest\nFoo\tBar\nendstream");
+ stream->insert("Attribute", new SkPDFInt(42))->unref();
+ SimpleCheckObjectOutput(reporter, stream.get(),
+ "<</Length 12\n/Attribute 42\n>> stream\n"
+ "Test\nFoo\tBar\nendstream");
+
+ if (SkFlate::HaveFlate()) {
+ char streamBytes2[] = "This is a longer string, so that compression "
+ "can do something with it. With shorter strings, "
+ "the short circuit logic cuts in and we end up "
+ "with an uncompressed string.";
+ SkAutoDataUnref streamData2(SkData::NewWithCopy(streamBytes2,
+ strlen(streamBytes2)));
+ SkAutoTUnref<SkPDFStream> stream(new SkPDFStream(streamData2.get()));
+
+ SkDynamicMemoryWStream compressedByteStream;
+ SkFlate::Deflate(streamData2.get(), &compressedByteStream);
+ SkAutoDataUnref compressedData(compressedByteStream.copyToData());
+
+ // Check first without compression.
+ SkDynamicMemoryWStream expectedResult1;
+ expectedResult1.writeText("<</Length 167\n>> stream\n");
+ expectedResult1.writeText(streamBytes2);
+ expectedResult1.writeText("\nendstream");
+ SkAutoDataUnref expectedResultData1(expectedResult1.copyToData());
+ CheckObjectOutput(reporter, stream.get(),
+ (const char*) expectedResultData1->data(),
+ expectedResultData1->size(), true, false);
+
+ // Then again with compression.
+ SkDynamicMemoryWStream expectedResult2;
+ expectedResult2.writeText("<</Filter /FlateDecode\n/Length 116\n"
+ ">> stream\n");
+ expectedResult2.write(compressedData->data(), compressedData->size());
+ expectedResult2.writeText("\nendstream");
+ SkAutoDataUnref expectedResultData2(expectedResult2.copyToData());
+ CheckObjectOutput(reporter, stream.get(),
+ (const char*) expectedResultData2->data(),
+ expectedResultData2->size(), true, true);
+ }
+}
+
+static void TestCatalog(skiatest::Reporter* reporter) {
+ SkPDFCatalog catalog((SkPDFDocument::Flags)0);
+ SkAutoTUnref<SkPDFInt> int1(new SkPDFInt(1));
+ SkAutoTUnref<SkPDFInt> int2(new SkPDFInt(2));
+ SkAutoTUnref<SkPDFInt> int3(new SkPDFInt(3));
+ int1.get()->ref();
+ SkAutoTUnref<SkPDFInt> int1Again(int1.get());
+
+ catalog.addObject(int1.get(), false);
+ catalog.addObject(int2.get(), false);
+ catalog.addObject(int3.get(), false);
+
+ REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int1.get()) == 3);
+ REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int2.get()) == 3);
+ REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int3.get()) == 3);
+
+ SkDynamicMemoryWStream buffer;
+ catalog.emitObjectNumber(&buffer, int1.get());
+ catalog.emitObjectNumber(&buffer, int2.get());
+ catalog.emitObjectNumber(&buffer, int3.get());
+ catalog.emitObjectNumber(&buffer, int1Again.get());
+ char expectedResult[] = "1 02 03 01 0";
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
+ strlen(expectedResult)));
+}
+
+static void TestObjectRef(skiatest::Reporter* reporter) {
+ SkAutoTUnref<SkPDFInt> int1(new SkPDFInt(1));
+ SkAutoTUnref<SkPDFInt> int2(new SkPDFInt(2));
+ SkAutoTUnref<SkPDFObjRef> int2ref(new SkPDFObjRef(int2.get()));
+
+ SkPDFCatalog catalog((SkPDFDocument::Flags)0);
+ catalog.addObject(int1.get(), false);
+ catalog.addObject(int2.get(), false);
+ REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int1.get()) == 3);
+ REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int2.get()) == 3);
+
+ char expectedResult[] = "2 0 R";
+ SkDynamicMemoryWStream buffer;
+ int2ref->emitObject(&buffer, &catalog, false);
+ REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult));
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
+ buffer.getOffset()));
+}
+
+static void TestSubstitute(skiatest::Reporter* reporter) {
+ SkAutoTUnref<SkPDFTestDict> proxy(new SkPDFTestDict());
+ SkAutoTUnref<SkPDFTestDict> stub(new SkPDFTestDict());
+ SkAutoTUnref<SkPDFInt> int33(new SkPDFInt(33));
+ SkAutoTUnref<SkPDFDict> stubResource(new SkPDFDict());
+ SkAutoTUnref<SkPDFInt> int44(new SkPDFInt(44));
+
+ stub->insert("Value", int33.get());
+ stubResource->insert("InnerValue", int44.get());
+ stub->addResource(stubResource.get());
+
+ SkPDFCatalog catalog((SkPDFDocument::Flags)0);
+ catalog.addObject(proxy.get(), false);
+ catalog.setSubstitute(proxy.get(), stub.get());
+
+ SkDynamicMemoryWStream buffer;
+ proxy->emit(&buffer, &catalog, false);
+ catalog.emitSubstituteResources(&buffer, false);
+
+ char objectResult[] = "2 0 obj\n<</Value 33\n>>\nendobj\n";
+ REPORTER_ASSERT(
+ reporter,
+ catalog.setFileOffset(proxy.get(), 0) == strlen(objectResult));
+
+ char expectedResult[] =
+ "<</Value 33\n>>1 0 obj\n<</InnerValue 44\n>>\nendobj\n";
+ REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult));
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
+ buffer.getOffset()));
+}
+
+// Create a bitmap that would be very eficiently compressed in a ZIP.
+static void setup_bitmap(SkBitmap* bitmap, int width, int height) {
+ bitmap->allocN32Pixels(width, height);
+ bitmap->eraseColor(SK_ColorWHITE);
+}
+
+static void TestImage(skiatest::Reporter* reporter, const SkBitmap& bitmap,
+ const char* expected, bool useDCTEncoder) {
+ SkISize pageSize = SkISize::Make(bitmap.width(), bitmap.height());
+ SkAutoTUnref<SkPDFDevice> dev(new SkPDFDevice(pageSize, pageSize, SkMatrix::I()));
+
+ if (useDCTEncoder) {
+ dev->setDCTEncoder(encode_to_dct_data);
+ }
+
+ SkCanvas c(dev);
+ c.drawBitmap(bitmap, 0, 0, NULL);
+
+ SkPDFDocument doc;
+ doc.appendPage(dev);
+
+ SkDynamicMemoryWStream stream;
+ doc.emitPDF(&stream);
+
+ REPORTER_ASSERT(reporter, stream_contains(stream, expected));
+}
+
+static void TestUncompressed(skiatest::Reporter* reporter) {
+ SkBitmap bitmap;
+ setup_bitmap(&bitmap, 1, 1);
+ TestImage(reporter, bitmap,
+ "/Subtype /Image\n"
+ "/Width 1\n"
+ "/Height 1\n"
+ "/ColorSpace /DeviceRGB\n"
+ "/BitsPerComponent 8\n"
+ "/Length 3\n"
+ ">> stream",
+ true);
+}
+
+static void TestFlateDecode(skiatest::Reporter* reporter) {
+ if (!SkFlate::HaveFlate()) {
+ return;
+ }
+ SkBitmap bitmap;
+ setup_bitmap(&bitmap, 10, 10);
+ TestImage(reporter, bitmap,
+ "/Subtype /Image\n"
+ "/Width 10\n"
+ "/Height 10\n"
+ "/ColorSpace /DeviceRGB\n"
+ "/BitsPerComponent 8\n"
+ "/Filter /FlateDecode\n"
+ "/Length 13\n"
+ ">> stream",
+ false);
+}
+
+static void TestDCTDecode(skiatest::Reporter* reporter) {
+ SkBitmap bitmap;
+ setup_bitmap(&bitmap, 32, 32);
+ TestImage(reporter, bitmap,
+ "/Subtype /Image\n"
+ "/Width 32\n"
+ "/Height 32\n"
+ "/ColorSpace /DeviceRGB\n"
+ "/BitsPerComponent 8\n"
+ "/Filter /DCTDecode\n"
+ "/ColorTransform 0\n"
+ "/Length 21\n"
+ ">> stream",
+ true);
+}
+
+static void TestImages(skiatest::Reporter* reporter) {
+ TestUncompressed(reporter);
+ TestFlateDecode(reporter);
+ TestDCTDecode(reporter);
+}
+
+// This test used to assert without the fix submitted for
+// http://code.google.com/p/skia/issues/detail?id=1083.
+// SKP files might have invalid glyph ids. This test ensures they are ignored,
+// and there is no assert on input data in Debug mode.
+static void test_issue1083() {
+ SkISize pageSize = SkISize::Make(100, 100);
+ SkAutoTUnref<SkPDFDevice> dev(new SkPDFDevice(pageSize, pageSize, SkMatrix::I()));
+
+ SkCanvas c(dev);
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ uint16_t glyphID = 65000;
+ c.drawText(&glyphID, 2, 0, 0, paint);
+
+ SkPDFDocument doc;
+ doc.appendPage(dev);
+
+ SkDynamicMemoryWStream stream;
+ doc.emitPDF(&stream);
+}
+
+DEF_TEST(PDFPrimitives, reporter) {
+ SkAutoTUnref<SkPDFInt> int42(new SkPDFInt(42));
+ SimpleCheckObjectOutput(reporter, int42.get(), "42");
+
+ SkAutoTUnref<SkPDFScalar> realHalf(new SkPDFScalar(SK_ScalarHalf));
+ SimpleCheckObjectOutput(reporter, realHalf.get(), "0.5");
+
+ SkAutoTUnref<SkPDFScalar> bigScalar(new SkPDFScalar(110999.75f));
+#if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
+ SimpleCheckObjectOutput(reporter, bigScalar.get(), "111000");
+#else
+ SimpleCheckObjectOutput(reporter, bigScalar.get(), "110999.75");
+
+ SkAutoTUnref<SkPDFScalar> biggerScalar(new SkPDFScalar(50000000.1));
+ SimpleCheckObjectOutput(reporter, biggerScalar.get(), "50000000");
+
+ SkAutoTUnref<SkPDFScalar> smallestScalar(new SkPDFScalar(1.0/65536));
+ SimpleCheckObjectOutput(reporter, smallestScalar.get(), "0.00001526");
+#endif
+
+ SkAutoTUnref<SkPDFString> stringSimple(
+ new SkPDFString("test ) string ( foo"));
+ SimpleCheckObjectOutput(reporter, stringSimple.get(),
+ "(test \\) string \\( foo)");
+ SkAutoTUnref<SkPDFString> stringComplex(
+ new SkPDFString("\ttest ) string ( foo"));
+ SimpleCheckObjectOutput(reporter, stringComplex.get(),
+ "<0974657374202920737472696E67202820666F6F>");
+
+ SkAutoTUnref<SkPDFName> name(new SkPDFName("Test name\twith#tab"));
+ const char expectedResult[] = "/Test#20name#09with#23tab";
+ CheckObjectOutput(reporter, name.get(), expectedResult,
+ strlen(expectedResult), false, false);
+
+ SkAutoTUnref<SkPDFName> escapedName(new SkPDFName("A#/%()<>[]{}B"));
+ const char escapedNameExpected[] = "/A#23#2F#25#28#29#3C#3E#5B#5D#7B#7DB";
+ CheckObjectOutput(reporter, escapedName.get(), escapedNameExpected,
+ strlen(escapedNameExpected), false, false);
+
+ // Test that we correctly handle characters with the high-bit set.
+ const unsigned char highBitCString[] = {0xDE, 0xAD, 'b', 'e', 0xEF, 0};
+ SkAutoTUnref<SkPDFName> highBitName(
+ new SkPDFName((const char*)highBitCString));
+ const char highBitExpectedResult[] = "/#DE#ADbe#EF";
+ CheckObjectOutput(reporter, highBitName.get(), highBitExpectedResult,
+ strlen(highBitExpectedResult), false, false);
+
+ SkAutoTUnref<SkPDFArray> array(new SkPDFArray);
+ SimpleCheckObjectOutput(reporter, array.get(), "[]");
+ array->append(int42.get());
+ SimpleCheckObjectOutput(reporter, array.get(), "[42]");
+ array->append(realHalf.get());
+ SimpleCheckObjectOutput(reporter, array.get(), "[42 0.5]");
+ SkAutoTUnref<SkPDFInt> int0(new SkPDFInt(0));
+ array->append(int0.get());
+ SimpleCheckObjectOutput(reporter, array.get(), "[42 0.5 0]");
+ SkAutoTUnref<SkPDFInt> int1(new SkPDFInt(1));
+ array->setAt(0, int1.get());
+ SimpleCheckObjectOutput(reporter, array.get(), "[1 0.5 0]");
+
+ SkAutoTUnref<SkPDFDict> dict(new SkPDFDict);
+ SimpleCheckObjectOutput(reporter, dict.get(), "<<>>");
+ SkAutoTUnref<SkPDFName> n1(new SkPDFName("n1"));
+ dict->insert(n1.get(), int42.get());
+ SimpleCheckObjectOutput(reporter, dict.get(), "<</n1 42\n>>");
+ SkAutoTUnref<SkPDFName> n2(new SkPDFName("n2"));
+ SkAutoTUnref<SkPDFName> n3(new SkPDFName("n3"));
+ dict->insert(n2.get(), realHalf.get());
+ dict->insert(n3.get(), array.get());
+ SimpleCheckObjectOutput(reporter, dict.get(),
+ "<</n1 42\n/n2 0.5\n/n3 [1 0.5 0]\n>>");
+
+ TestPDFStream(reporter);
+
+ TestCatalog(reporter);
+
+ TestObjectRef(reporter);
+
+ TestSubstitute(reporter);
+
+ test_issue1083();
+
+ TestImages(reporter);
+}
+
+namespace {
+
+class DummyImageFilter : public SkImageFilter {
+public:
+ DummyImageFilter(bool visited = false) : SkImageFilter(0, NULL), fVisited(visited) {}
+ virtual ~DummyImageFilter() SK_OVERRIDE {}
+ virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
+ SkBitmap* result, SkIPoint* offset) const {
+ fVisited = true;
+ offset->fX = offset->fY = 0;
+ *result = src;
+ return true;
+ }
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(DummyImageFilter)
+#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
+ explicit DummyImageFilter(SkReadBuffer& buffer) : SkImageFilter(0, NULL) {
+ fVisited = buffer.readBool();
+ }
+#endif
+ bool visited() const { return fVisited; }
+
+private:
+ mutable bool fVisited;
+};
+
+SkFlattenable* DummyImageFilter::CreateProc(SkReadBuffer& buffer) {
+ SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
+ bool visited = buffer.readBool();
+ return SkNEW_ARGS(DummyImageFilter, (visited));
+}
+
+};
+
+// Check that PDF rendering of image filters successfully falls back to
+// CPU rasterization.
+DEF_TEST(PDFImageFilter, reporter) {
+ SkISize pageSize = SkISize::Make(100, 100);
+ SkAutoTUnref<SkPDFDevice> device(new SkPDFDevice(pageSize, pageSize, SkMatrix::I()));
+ SkCanvas canvas(device.get());
+ SkAutoTUnref<DummyImageFilter> filter(new DummyImageFilter());
+
+ // Filter just created; should be unvisited.
+ REPORTER_ASSERT(reporter, !filter->visited());
+ SkPaint paint;
+ paint.setImageFilter(filter.get());
+ canvas.drawRect(SkRect::MakeWH(100, 100), paint);
+
+ // Filter was used in rendering; should be visited.
+ REPORTER_ASSERT(reporter, filter->visited());
+}
diff --git a/src/third_party/skia/tests/PackBitsTest.cpp b/src/third_party/skia/tests/PackBitsTest.cpp
new file mode 100644
index 0000000..fdbd9bd
--- /dev/null
+++ b/src/third_party/skia/tests/PackBitsTest.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPackBits.h"
+#include "Test.h"
+
+#include "SkRandom.h"
+static SkRandom gRand;
+static const uint8_t gTest80[] = { 0, 0, 1, 1 };
+static const uint8_t gTest81[] = { 1, 2, 3, 4, 5, 6 };
+static const uint8_t gTest82[] = { 0, 0, 0, 1, 2, 3, 3, 3 };
+static const uint8_t gTest83[] = { 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 0, 0, 1 };
+static const uint8_t gTest84[] = { 1, 0, 3, 0, 0, 0, 2, 1, 1, 2 };
+
+static void rand_fill(uint8_t buffer[], int count) {
+ for (int i = 0; i < count; i++)
+ buffer[i] = (uint8_t)((gRand.nextU() >> 8) & 0x3);
+}
+
+static void test_pack8(skiatest::Reporter* reporter) {
+ static const struct {
+ const uint8_t* fSrc;
+ int fCount;
+ } gTests[] = {
+ { gTest80, SK_ARRAY_COUNT(gTest80) },
+ { gTest81, SK_ARRAY_COUNT(gTest81) },
+ { gTest82, SK_ARRAY_COUNT(gTest82) },
+ { gTest83, SK_ARRAY_COUNT(gTest83) },
+ { gTest84, SK_ARRAY_COUNT(gTest84) }
+ };
+
+ for (size_t i = 4; i < SK_ARRAY_COUNT(gTests); i++) {
+ uint8_t dst[100];
+ size_t maxSize = SkPackBits::ComputeMaxSize8(gTests[i].fCount);
+ size_t dstSize = SkPackBits::Pack8(gTests[i].fSrc,
+ gTests[i].fCount, dst, maxSize - 1);
+ REPORTER_ASSERT(reporter, dstSize == 0);
+ dstSize = SkPackBits::Pack8(gTests[i].fSrc,
+ gTests[i].fCount, dst, sizeof(dst));
+ REPORTER_ASSERT(reporter, dstSize <= maxSize);
+ uint8_t src[100];
+ int srcCount = SkPackBits::Unpack8(dst, dstSize, src, gTests[i].fCount - 1);
+ REPORTER_ASSERT(reporter, srcCount == 0);
+ srcCount = SkPackBits::Unpack8(dst, dstSize, src, sizeof(src));
+ bool match = gTests[i].fCount == srcCount &&
+ memcmp(gTests[i].fSrc, src,
+ gTests[i].fCount * sizeof(uint8_t)) == 0;
+ REPORTER_ASSERT(reporter, match);
+ }
+
+ for (size_t size = 1; size <= 512; size += 1) {
+ for (int n = 100; n; n--) {
+ uint8_t src[600], src2[600];
+ uint8_t dst[600];
+ rand_fill(src, size);
+
+ size_t dstSize = SkPackBits::Pack8(src, size, dst, sizeof(dst));
+ size_t maxSize = SkPackBits::ComputeMaxSize8(size);
+ REPORTER_ASSERT(reporter, maxSize >= dstSize);
+
+ size_t srcCount = SkPackBits::Unpack8(dst, dstSize, src2, size);
+ REPORTER_ASSERT(reporter, size == srcCount);
+ bool match = memcmp(src, src2, size * sizeof(uint8_t)) == 0;
+ REPORTER_ASSERT(reporter, match);
+ }
+ }
+}
+
+DEF_TEST(PackBits, reporter) {
+ test_pack8(reporter);
+}
diff --git a/src/third_party/skia/tests/PaintTest.cpp b/src/third_party/skia/tests/PaintTest.cpp
new file mode 100644
index 0000000..57d0283
--- /dev/null
+++ b/src/third_party/skia/tests/PaintTest.cpp
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBlurMask.h"
+#include "SkBlurMaskFilter.h"
+#include "SkLayerDrawLooper.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkReadBuffer.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+#include "SkWriteBuffer.h"
+#include "SkXfermode.h"
+#include "Test.h"
+
+static size_t uni_to_utf8(const SkUnichar src[], void* dst, int count) {
+ char* u8 = (char*)dst;
+ for (int i = 0; i < count; ++i) {
+ int n = SkUTF8_FromUnichar(src[i], u8);
+ u8 += n;
+ }
+ return u8 - (char*)dst;
+}
+
+static size_t uni_to_utf16(const SkUnichar src[], void* dst, int count) {
+ uint16_t* u16 = (uint16_t*)dst;
+ for (int i = 0; i < count; ++i) {
+ int n = SkUTF16_FromUnichar(src[i], u16);
+ u16 += n;
+ }
+ return (char*)u16 - (char*)dst;
+}
+
+static size_t uni_to_utf32(const SkUnichar src[], void* dst, int count) {
+ SkUnichar* u32 = (SkUnichar*)dst;
+ if (src != u32) {
+ memcpy(u32, src, count * sizeof(SkUnichar));
+ }
+ return count * sizeof(SkUnichar);
+}
+
+static SkTypeface::Encoding paint2encoding(const SkPaint& paint) {
+ SkPaint::TextEncoding enc = paint.getTextEncoding();
+ SkASSERT(SkPaint::kGlyphID_TextEncoding != enc);
+ return (SkTypeface::Encoding)enc;
+}
+
+static int find_first_zero(const uint16_t glyphs[], int count) {
+ for (int i = 0; i < count; ++i) {
+ if (0 == glyphs[i]) {
+ return i;
+ }
+ }
+ return count;
+}
+
+DEF_TEST(Paint_cmap, reporter) {
+ // need to implement charsToGlyphs on other backends (e.g. linux, win)
+ // before we can run this tests everywhere
+ return;
+
+ static const int NGLYPHS = 64;
+
+ SkUnichar src[NGLYPHS];
+ SkUnichar dst[NGLYPHS]; // used for utf8, utf16, utf32 storage
+
+ static const struct {
+ size_t (*fSeedTextProc)(const SkUnichar[], void* dst, int count);
+ SkPaint::TextEncoding fEncoding;
+ } gRec[] = {
+ { uni_to_utf8, SkPaint::kUTF8_TextEncoding },
+ { uni_to_utf16, SkPaint::kUTF16_TextEncoding },
+ { uni_to_utf32, SkPaint::kUTF32_TextEncoding },
+ };
+
+ SkRandom rand;
+ SkPaint paint;
+ paint.setTypeface(SkTypeface::RefDefault())->unref();
+ SkTypeface* face = paint.getTypeface();
+
+ for (int i = 0; i < 1000; ++i) {
+ // generate some random text
+ for (int j = 0; j < NGLYPHS; ++j) {
+ src[j] = ' ' + j;
+ }
+ // inject some random chars, to sometimes abort early
+ src[rand.nextU() & 63] = rand.nextU() & 0xFFF;
+
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gRec); ++k) {
+ paint.setTextEncoding(gRec[k].fEncoding);
+
+ size_t len = gRec[k].fSeedTextProc(src, dst, NGLYPHS);
+
+ uint16_t glyphs0[NGLYPHS], glyphs1[NGLYPHS];
+
+ bool contains = paint.containsText(dst, len);
+ int nglyphs = paint.textToGlyphs(dst, len, glyphs0);
+ int first = face->charsToGlyphs(dst, paint2encoding(paint), glyphs1, NGLYPHS);
+ int index = find_first_zero(glyphs1, NGLYPHS);
+
+ REPORTER_ASSERT(reporter, NGLYPHS == nglyphs);
+ REPORTER_ASSERT(reporter, index == first);
+ REPORTER_ASSERT(reporter, 0 == memcmp(glyphs0, glyphs1, NGLYPHS * sizeof(uint16_t)));
+ if (contains) {
+ REPORTER_ASSERT(reporter, NGLYPHS == first);
+ } else {
+ REPORTER_ASSERT(reporter, NGLYPHS > first);
+ }
+ }
+ }
+}
+
+// temparary api for bicubic, just be sure we can set/clear it
+DEF_TEST(Paint_filterlevel, reporter) {
+ SkPaint p0, p1;
+
+ REPORTER_ASSERT(reporter,
+ SkPaint::kNone_FilterLevel == p0.getFilterLevel());
+
+ static const SkPaint::FilterLevel gLevels[] = {
+ SkPaint::kNone_FilterLevel,
+ SkPaint::kLow_FilterLevel,
+ SkPaint::kMedium_FilterLevel,
+ SkPaint::kHigh_FilterLevel
+ };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gLevels); ++i) {
+ p0.setFilterLevel(gLevels[i]);
+ REPORTER_ASSERT(reporter, gLevels[i] == p0.getFilterLevel());
+ p1 = p0;
+ REPORTER_ASSERT(reporter, gLevels[i] == p1.getFilterLevel());
+
+ p0.reset();
+ REPORTER_ASSERT(reporter,
+ SkPaint::kNone_FilterLevel == p0.getFilterLevel());
+ }
+}
+
+DEF_TEST(Paint_copy, reporter) {
+ SkPaint paint;
+ // set a few member variables
+ paint.setStyle(SkPaint::kStrokeAndFill_Style);
+ paint.setTextAlign(SkPaint::kLeft_Align);
+ paint.setStrokeWidth(SkIntToScalar(2));
+ // set a few pointers
+ SkLayerDrawLooper::Builder looperBuilder;
+ SkLayerDrawLooper* looper = looperBuilder.detachLooper();
+ paint.setLooper(looper)->unref();
+ SkMaskFilter* mask = SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
+ SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(1)));
+ paint.setMaskFilter(mask)->unref();
+
+ // copy the paint using the copy constructor and check they are the same
+ SkPaint copiedPaint = paint;
+ REPORTER_ASSERT(reporter, paint == copiedPaint);
+
+#ifdef SK_BUILD_FOR_ANDROID
+ // the copy constructor should preserve the Generation ID
+ uint32_t paintGenID = paint.getGenerationID();
+ uint32_t copiedPaintGenID = copiedPaint.getGenerationID();
+ REPORTER_ASSERT(reporter, paintGenID == copiedPaintGenID);
+ REPORTER_ASSERT(reporter, paint == copiedPaint);
+#endif
+
+ // copy the paint using the equal operator and check they are the same
+ copiedPaint = paint;
+ REPORTER_ASSERT(reporter, paint == copiedPaint);
+
+#ifdef SK_BUILD_FOR_ANDROID
+ // the equals operator should increment the Generation ID
+ REPORTER_ASSERT(reporter, paint.getGenerationID() == paintGenID);
+ REPORTER_ASSERT(reporter, copiedPaint.getGenerationID() != copiedPaintGenID);
+ copiedPaintGenID = copiedPaint.getGenerationID(); // reset to the new value
+ REPORTER_ASSERT(reporter, paint == copiedPaint); // operator== ignores fGenerationID
+#endif
+
+ // clean the paint and check they are back to their initial states
+ SkPaint cleanPaint;
+ paint.reset();
+ copiedPaint.reset();
+ REPORTER_ASSERT(reporter, cleanPaint == paint);
+ REPORTER_ASSERT(reporter, cleanPaint == copiedPaint);
+
+#ifdef SK_BUILD_FOR_ANDROID
+ // the reset function should increment the Generation ID
+ REPORTER_ASSERT(reporter, paint.getGenerationID() != paintGenID);
+ REPORTER_ASSERT(reporter, copiedPaint.getGenerationID() != copiedPaintGenID);
+ // operator== ignores fGenerationID
+ REPORTER_ASSERT(reporter, cleanPaint == paint);
+ REPORTER_ASSERT(reporter, cleanPaint == copiedPaint);
+#endif
+}
+
+// found and fixed for webkit: mishandling when we hit recursion limit on
+// mostly degenerate cubic flatness test
+DEF_TEST(Paint_regression_cubic, reporter) {
+ SkPath path, stroke;
+ SkPaint paint;
+
+ path.moveTo(460.2881309415525f,
+ 303.250847066498f);
+ path.cubicTo(463.36378422175284f,
+ 302.1169735073363f,
+ 456.32239330810046f,
+ 304.720354932878f,
+ 453.15255460013304f,
+ 305.788586869862f);
+
+ SkRect fillR, strokeR;
+ fillR = path.getBounds();
+
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(2));
+ paint.getFillPath(path, &stroke);
+ strokeR = stroke.getBounds();
+
+ SkRect maxR = fillR;
+ SkScalar miter = SkMaxScalar(SK_Scalar1, paint.getStrokeMiter());
+ SkScalar inset = paint.getStrokeJoin() == SkPaint::kMiter_Join ?
+ SkScalarMul(paint.getStrokeWidth(), miter) :
+ paint.getStrokeWidth();
+ maxR.inset(-inset, -inset);
+
+ // test that our stroke didn't explode
+ REPORTER_ASSERT(reporter, maxR.contains(strokeR));
+}
+
+DEF_TEST(Paint_flattening, reporter) {
+ const SkPaint::FilterLevel levels[] = {
+ SkPaint::kNone_FilterLevel,
+ SkPaint::kLow_FilterLevel,
+ SkPaint::kMedium_FilterLevel,
+ SkPaint::kHigh_FilterLevel,
+ };
+ const SkPaint::Hinting hinting[] = {
+ SkPaint::kNo_Hinting,
+ SkPaint::kSlight_Hinting,
+ SkPaint::kNormal_Hinting,
+ SkPaint::kFull_Hinting,
+ };
+ const SkPaint::Align align[] = {
+ SkPaint::kLeft_Align,
+ SkPaint::kCenter_Align,
+ SkPaint::kRight_Align
+ };
+ const SkPaint::Cap caps[] = {
+ SkPaint::kButt_Cap,
+ SkPaint::kRound_Cap,
+ SkPaint::kSquare_Cap,
+ };
+ const SkPaint::Join joins[] = {
+ SkPaint::kMiter_Join,
+ SkPaint::kRound_Join,
+ SkPaint::kBevel_Join,
+ };
+ const SkPaint::TextEncoding encodings[] = {
+ SkPaint::kUTF8_TextEncoding,
+ SkPaint::kUTF16_TextEncoding,
+ SkPaint::kUTF32_TextEncoding,
+ SkPaint::kGlyphID_TextEncoding,
+ };
+ const SkPaint::Style styles[] = {
+ SkPaint::kFill_Style,
+ SkPaint::kStroke_Style,
+ SkPaint::kStrokeAndFill_Style,
+ };
+
+#define FOR_SETUP(index, array, setter) \
+ for (size_t index = 0; index < SK_ARRAY_COUNT(array); ++index) { \
+ paint.setter(array[index]); \
+
+ SkPaint paint;
+ paint.setFlags(0x1234);
+
+ FOR_SETUP(i, levels, setFilterLevel)
+ FOR_SETUP(j, hinting, setHinting)
+ FOR_SETUP(k, align, setTextAlign)
+ FOR_SETUP(l, caps, setStrokeCap)
+ FOR_SETUP(m, joins, setStrokeJoin)
+ FOR_SETUP(n, encodings, setTextEncoding)
+ FOR_SETUP(p, styles, setStyle)
+
+ SkWriteBuffer writer;
+ paint.flatten(writer);
+
+ const uint32_t* written = writer.getWriter32()->contiguousArray();
+ SkReadBuffer reader(written, writer.bytesWritten());
+
+ SkPaint paint2;
+ paint2.unflatten(reader);
+ REPORTER_ASSERT(reporter, paint2 == paint);
+
+ }}}}}}}
+#undef FOR_SETUP
+
+}
+
+// found and fixed for android: not initializing rect for string's of length 0
+DEF_TEST(Paint_regression_measureText, reporter) {
+
+ SkPaint paint;
+ paint.setTextSize(12.0f);
+
+ SkRect r;
+ r.setLTRB(SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN);
+
+ // test that the rect was reset
+ paint.measureText("", 0, &r);
+ REPORTER_ASSERT(reporter, r.isEmpty());
+}
+
+#define ASSERT(expr) REPORTER_ASSERT(r, expr)
+
+DEF_TEST(Paint_FlatteningTraits, r) {
+ SkPaint paint;
+ paint.setColor(0x00AABBCC);
+ paint.setTextScaleX(1.0f); // Default value, ignored.
+ paint.setTextSize(19);
+ paint.setXfermode(SkXfermode::Create(SkXfermode::kModulate_Mode))->unref();
+ paint.setLooper(NULL); // Default value, ignored.
+
+ SkWriteBuffer writer;
+ SkPaint::FlatteningTraits::Flatten(writer, paint);
+
+ // BEGIN white box asserts: if the impl changes, these asserts may change
+ const size_t expectedBytesWritten = sizeof(void*) == 8 ? 32 : 28;
+ ASSERT(expectedBytesWritten == writer.bytesWritten());
+
+ const uint32_t* written = writer.getWriter32()->contiguousArray();
+ SkASSERT(written != NULL);
+ ASSERT(*written == ((1<<0) | (1<<1) | (1<<8))); // Dirty bits for our 3.
+ // END white box asserts
+
+ SkReadBuffer reader(written, writer.bytesWritten());
+ SkPaint other;
+ SkPaint::FlatteningTraits::Unflatten(reader, &other);
+ ASSERT(reader.offset() == writer.bytesWritten());
+
+ // No matter the encoding, these must always hold.
+ ASSERT(other.getColor() == paint.getColor());
+ ASSERT(other.getTextScaleX() == paint.getTextScaleX());
+ ASSERT(other.getTextSize() == paint.getTextSize());
+ ASSERT(other.getLooper() == paint.getLooper());
+
+ // We have to be a little looser and compare just the modes. Pointers might not be the same.
+ SkXfermode::Mode otherMode, paintMode;
+ ASSERT(other.getXfermode()->asMode(&otherMode));
+ ASSERT(paint.getXfermode()->asMode(&paintMode));
+ ASSERT(otherMode == paintMode);
+}
diff --git a/src/third_party/skia/tests/ParsePathTest.cpp b/src/third_party/skia/tests/ParsePathTest.cpp
new file mode 100644
index 0000000..ff43d14
--- /dev/null
+++ b/src/third_party/skia/tests/ParsePathTest.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkParsePath.h"
+#include "Test.h"
+
+static void test_to_from(skiatest::Reporter* reporter, const SkPath& path) {
+ SkString str, str2;
+ SkParsePath::ToSVGString(path, &str);
+
+ SkPath path2;
+ bool success = SkParsePath::FromSVGString(str.c_str(), &path2);
+ REPORTER_ASSERT(reporter, success);
+
+ SkParsePath::ToSVGString(path2, &str2);
+ REPORTER_ASSERT(reporter, str == str2);
+#if 0 // closed paths are not equal, the iter explicitly gives the closing
+ // edge, even if it is not in the path.
+ REPORTER_ASSERT(reporter, path == path2);
+ if (path != path2) {
+ SkDebugf("str1=%s\nstr2=%s\n", str.c_str(), str2.c_str());
+ }
+#endif
+}
+
+static struct {
+ const char* fStr;
+ const SkRect fBounds;
+} gRec[] = {
+ { "", { 0, 0, 0, 0 } },
+ { "M0,0L10,10", { 0, 0, SkIntToScalar(10), SkIntToScalar(10) } },
+ { "M-5.5,-0.5 Q 0 0 6,6.50",
+ { -5.5f, -0.5f,
+ 6, 6.5f } }
+};
+
+DEF_TEST(ParsePath, reporter) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
+ SkPath path;
+ bool success = SkParsePath::FromSVGString(gRec[i].fStr, &path);
+ REPORTER_ASSERT(reporter, success);
+ const SkRect& expectedBounds = gRec[i].fBounds;
+ const SkRect& pathBounds = path.getBounds();
+ REPORTER_ASSERT(reporter, expectedBounds == pathBounds);
+
+ test_to_from(reporter, path);
+ }
+
+ SkRect r;
+ r.set(0, 0, 10, 10.5f);
+ SkPath p;
+ p.addRect(r);
+ test_to_from(reporter, p);
+ p.addOval(r);
+ test_to_from(reporter, p);
+ p.addRoundRect(r, 4, 4.5f);
+ test_to_from(reporter, p);
+}
diff --git a/src/third_party/skia/tests/PathCoverageTest.cpp b/src/third_party/skia/tests/PathCoverageTest.cpp
new file mode 100644
index 0000000..0e4a153
--- /dev/null
+++ b/src/third_party/skia/tests/PathCoverageTest.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkMath.h"
+#include "SkPoint.h"
+#include "SkScalar.h"
+#include "Test.h"
+
+/*
+ Duplicates lots of code from gpu/src/GrPathUtils.cpp
+ It'd be nice not to do so, but that code's set up currently to only have
+ a single implementation.
+*/
+
+// Sk uses 6, Gr (implicitly) used 10, both apparently arbitrarily.
+#define MAX_COEFF_SHIFT 6
+static const uint32_t MAX_POINTS_PER_CURVE = 1 << MAX_COEFF_SHIFT;
+
+// max + 0.5 min has error [0.0, 0.12]
+// max + 0.375 min has error [-.03, 0.07]
+// 0.96043387 max + 0.397824735 min has error [-.06, +.05]
+// For determining the maximum possible number of points to use in
+// drawing a quadratic, we want to err on the high side.
+static inline int cheap_distance(SkScalar dx, SkScalar dy) {
+ int idx = SkAbs32(SkScalarRoundToInt(dx));
+ int idy = SkAbs32(SkScalarRoundToInt(dy));
+ if (idx > idy) {
+ idx += idy >> 1;
+ } else {
+ idx = idy + (idx >> 1);
+ }
+ return idx;
+}
+
+static inline int estimate_distance(const SkPoint points[]) {
+ return cheap_distance(points[1].fX * 2 - points[2].fX - points[0].fX,
+ points[1].fY * 2 - points[2].fY - points[0].fY);
+}
+
+static inline SkScalar compute_distance(const SkPoint points[]) {
+ return points[1].distanceToLineSegmentBetween(points[0], points[2]);
+}
+
+static inline uint32_t estimate_pointCount(int distance) {
+ // Includes -2 bias because this estimator runs 4x high?
+ int shift = 30 - SkCLZ(distance);
+ // Clamp to zero if above subtraction went negative.
+ shift &= ~(shift>>31);
+ if (shift > MAX_COEFF_SHIFT) {
+ shift = MAX_COEFF_SHIFT;
+ }
+ return 1 << shift;
+}
+
+static inline uint32_t compute_pointCount(SkScalar d, SkScalar tol) {
+ if (d < tol) {
+ return 1;
+ } else {
+ int temp = SkScalarCeilToInt(SkScalarSqrt(SkScalarDiv(d, tol)));
+ uint32_t count = SkMin32(SkNextPow2(temp), MAX_POINTS_PER_CURVE);
+ return count;
+ }
+}
+
+static uint32_t quadraticPointCount_EE(const SkPoint points[]) {
+ int distance = estimate_distance(points);
+ return estimate_pointCount(distance);
+}
+
+static uint32_t quadraticPointCount_EC(const SkPoint points[], SkScalar tol) {
+ int distance = estimate_distance(points);
+ return compute_pointCount(SkIntToScalar(distance), tol);
+}
+
+static uint32_t quadraticPointCount_CE(const SkPoint points[]) {
+ SkScalar distance = compute_distance(points);
+ return estimate_pointCount(SkScalarRoundToInt(distance));
+}
+
+static uint32_t quadraticPointCount_CC(const SkPoint points[], SkScalar tol) {
+ SkScalar distance = compute_distance(points);
+ return compute_pointCount(distance, tol);
+}
+
+// Curve from samplecode/SampleSlides.cpp
+static const int gXY[] = {
+ 4, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4
+};
+
+static const int gSawtooth[] = {
+ 0, 0, 10, 10, 20, 20, 30, 10, 40, 0, 50, -10, 60, -20, 70, -10, 80, 0
+};
+
+static const int gOvalish[] = {
+ 0, 0, 5, 15, 20, 20, 35, 15, 40, 0
+};
+
+static const int gSharpSawtooth[] = {
+ 0, 0, 1, 10, 2, 0, 3, -10, 4, 0
+};
+
+// Curve crosses back over itself around 0,10
+static const int gRibbon[] = {
+ -4, 0, 4, 20, 0, 25, -4, 20, 4, 0
+};
+
+static bool one_d_pe(const int* array, const unsigned int count,
+ skiatest::Reporter* reporter) {
+ SkPoint path [3];
+ path[1] = SkPoint::Make(SkIntToScalar(array[0]), SkIntToScalar(array[1]));
+ path[2] = SkPoint::Make(SkIntToScalar(array[2]), SkIntToScalar(array[3]));
+ int numErrors = 0;
+ for (unsigned i = 4; i < count; i += 2) {
+ path[0] = path[1];
+ path[1] = path[2];
+ path[2] = SkPoint::Make(SkIntToScalar(array[i]),
+ SkIntToScalar(array[i+1]));
+ uint32_t computedCount =
+ quadraticPointCount_CC(path, SkIntToScalar(1));
+ uint32_t estimatedCount =
+ quadraticPointCount_EE(path);
+
+ if (false) { // avoid bit rot, suppress warning
+ computedCount =
+ quadraticPointCount_EC(path, SkIntToScalar(1));
+ estimatedCount =
+ quadraticPointCount_CE(path);
+ }
+ // Allow estimated to be high by a factor of two, but no less than
+ // the computed value.
+ bool isAccurate = (estimatedCount >= computedCount) &&
+ (estimatedCount <= 2 * computedCount);
+
+ if (!isAccurate) {
+ ERRORF(reporter, "Curve from %.2f %.2f through %.2f %.2f to "
+ "%.2f %.2f computes %d, estimates %d\n",
+ path[0].fX, path[0].fY, path[1].fX, path[1].fY,
+ path[2].fX, path[2].fY, computedCount, estimatedCount);
+ numErrors++;
+ }
+ }
+
+ return (numErrors == 0);
+}
+
+
+
+static void TestQuadPointCount(skiatest::Reporter* reporter) {
+ one_d_pe(gXY, SK_ARRAY_COUNT(gXY), reporter);
+ one_d_pe(gSawtooth, SK_ARRAY_COUNT(gSawtooth), reporter);
+ one_d_pe(gOvalish, SK_ARRAY_COUNT(gOvalish), reporter);
+ one_d_pe(gSharpSawtooth, SK_ARRAY_COUNT(gSharpSawtooth), reporter);
+ one_d_pe(gRibbon, SK_ARRAY_COUNT(gRibbon), reporter);
+}
+
+DEF_TEST(PathCoverage, reporter) {
+ TestQuadPointCount(reporter);
+
+}
diff --git a/src/third_party/skia/tests/PathMeasureTest.cpp b/src/third_party/skia/tests/PathMeasureTest.cpp
new file mode 100644
index 0000000..578f4eb
--- /dev/null
+++ b/src/third_party/skia/tests/PathMeasureTest.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPathMeasure.h"
+#include "Test.h"
+
+static void test_small_segment3() {
+ SkPath path;
+ const SkPoint pts[] = {
+ { 0, 0 },
+ { 100000000000.0f, 100000000000.0f }, { 0, 0 }, { 10, 10 },
+ { 10, 10 }, { 0, 0 }, { 10, 10 }
+ };
+
+ path.moveTo(pts[0]);
+ for (size_t i = 1; i < SK_ARRAY_COUNT(pts); i += 3) {
+ path.cubicTo(pts[i], pts[i + 1], pts[i + 2]);
+ }
+
+ SkPathMeasure meas(path, false);
+ meas.getLength();
+}
+
+static void test_small_segment2() {
+ SkPath path;
+ const SkPoint pts[] = {
+ { 0, 0 },
+ { 100000000000.0f, 100000000000.0f }, { 0, 0 },
+ { 10, 10 }, { 0, 0 },
+ };
+
+ path.moveTo(pts[0]);
+ for (size_t i = 1; i < SK_ARRAY_COUNT(pts); i += 2) {
+ path.quadTo(pts[i], pts[i + 1]);
+ }
+ SkPathMeasure meas(path, false);
+ meas.getLength();
+}
+
+static void test_small_segment() {
+ SkPath path;
+ const SkPoint pts[] = {
+ { 100000, 100000},
+ // big jump between these points, makes a big segment
+ { 1.0005f, 0.9999f },
+ // tiny (non-zero) jump between these points
+ { SK_Scalar1, SK_Scalar1 },
+ };
+
+ path.moveTo(pts[0]);
+ for (size_t i = 1; i < SK_ARRAY_COUNT(pts); ++i) {
+ path.lineTo(pts[i]);
+ }
+ SkPathMeasure meas(path, false);
+
+ /* this would assert (before a fix) because we added a segment with
+ the same length as the prev segment, due to the follow (bad) pattern
+
+ d = distance(pts[0], pts[1]);
+ distance += d;
+ seg->fDistance = distance;
+
+ SkASSERT(d > 0); // TRUE
+ SkASSERT(seg->fDistance > prevSeg->fDistance); // FALSE
+
+ This 2nd assert failes because (distance += d) didn't affect distance
+ because distance >>> d.
+ */
+ meas.getLength();
+}
+
+DEF_TEST(PathMeasure, reporter) {
+ SkPath path;
+
+ path.moveTo(0, 0);
+ path.lineTo(SK_Scalar1, 0);
+ path.lineTo(SK_Scalar1, SK_Scalar1);
+ path.lineTo(0, SK_Scalar1);
+
+ SkPathMeasure meas(path, true);
+ SkScalar length = meas.getLength();
+ SkASSERT(length == SK_Scalar1*4);
+
+ path.reset();
+ path.moveTo(0, 0);
+ path.lineTo(SK_Scalar1*3, SK_Scalar1*4);
+ meas.setPath(&path, false);
+ length = meas.getLength();
+ REPORTER_ASSERT(reporter, length == SK_Scalar1*5);
+
+ path.reset();
+ path.addCircle(0, 0, SK_Scalar1);
+ meas.setPath(&path, true);
+ length = meas.getLength();
+// SkDebugf("circle arc-length = %g\n", length);
+
+ // Test the behavior following a close not followed by a move.
+ path.reset();
+ path.lineTo(SK_Scalar1, 0);
+ path.lineTo(SK_Scalar1, SK_Scalar1);
+ path.lineTo(0, SK_Scalar1);
+ path.close();
+ path.lineTo(-SK_Scalar1, 0);
+ meas.setPath(&path, false);
+ length = meas.getLength();
+ REPORTER_ASSERT(reporter, length == SK_Scalar1 * 4);
+ meas.nextContour();
+ length = meas.getLength();
+ REPORTER_ASSERT(reporter, length == SK_Scalar1);
+ SkPoint position;
+ SkVector tangent;
+ REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent));
+ REPORTER_ASSERT(reporter,
+ SkScalarNearlyEqual(position.fX,
+ -SK_ScalarHalf,
+ 0.0001f));
+ REPORTER_ASSERT(reporter, position.fY == 0);
+ REPORTER_ASSERT(reporter, tangent.fX == -SK_Scalar1);
+ REPORTER_ASSERT(reporter, tangent.fY == 0);
+
+ // Test degenerate paths
+ path.reset();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(SK_Scalar1, 0);
+ path.quadTo(SK_Scalar1, 0, SK_Scalar1, 0);
+ path.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1 * 2);
+ path.cubicTo(SK_Scalar1, SK_Scalar1 * 2,
+ SK_Scalar1, SK_Scalar1 * 2,
+ SK_Scalar1, SK_Scalar1 * 2);
+ path.cubicTo(SK_Scalar1*2, SK_Scalar1 * 2,
+ SK_Scalar1*3, SK_Scalar1 * 2,
+ SK_Scalar1*4, SK_Scalar1 * 2);
+ meas.setPath(&path, false);
+ length = meas.getLength();
+ REPORTER_ASSERT(reporter, length == SK_Scalar1 * 6);
+ REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent));
+ REPORTER_ASSERT(reporter,
+ SkScalarNearlyEqual(position.fX,
+ SK_ScalarHalf,
+ 0.0001f));
+ REPORTER_ASSERT(reporter, position.fY == 0);
+ REPORTER_ASSERT(reporter, tangent.fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, tangent.fY == 0);
+ REPORTER_ASSERT(reporter, meas.getPosTan(2.5f, &position, &tangent));
+ REPORTER_ASSERT(reporter,
+ SkScalarNearlyEqual(position.fX, SK_Scalar1, 0.0001f));
+ REPORTER_ASSERT(reporter,
+ SkScalarNearlyEqual(position.fY, 1.5f));
+ REPORTER_ASSERT(reporter, tangent.fX == 0);
+ REPORTER_ASSERT(reporter, tangent.fY == SK_Scalar1);
+ REPORTER_ASSERT(reporter, meas.getPosTan(4.5f, &position, &tangent));
+ REPORTER_ASSERT(reporter,
+ SkScalarNearlyEqual(position.fX,
+ 2.5f,
+ 0.0001f));
+ REPORTER_ASSERT(reporter,
+ SkScalarNearlyEqual(position.fY,
+ 2.0f,
+ 0.0001f));
+ REPORTER_ASSERT(reporter, tangent.fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, tangent.fY == 0);
+
+ path.reset();
+ path.moveTo(0, 0);
+ path.lineTo(SK_Scalar1, 0);
+ path.moveTo(SK_Scalar1, SK_Scalar1);
+ path.moveTo(SK_Scalar1 * 2, SK_Scalar1 * 2);
+ path.lineTo(SK_Scalar1, SK_Scalar1 * 2);
+ meas.setPath(&path, false);
+ length = meas.getLength();
+ REPORTER_ASSERT(reporter, length == SK_Scalar1);
+ REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent));
+ REPORTER_ASSERT(reporter,
+ SkScalarNearlyEqual(position.fX,
+ SK_ScalarHalf,
+ 0.0001f));
+ REPORTER_ASSERT(reporter, position.fY == 0);
+ REPORTER_ASSERT(reporter, tangent.fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, tangent.fY == 0);
+ meas.nextContour();
+ length = meas.getLength();
+ REPORTER_ASSERT(reporter, length == SK_Scalar1);
+ REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent));
+ REPORTER_ASSERT(reporter,
+ SkScalarNearlyEqual(position.fX,
+ 1.5f,
+ 0.0001f));
+ REPORTER_ASSERT(reporter,
+ SkScalarNearlyEqual(position.fY,
+ 2.0f,
+ 0.0001f));
+ REPORTER_ASSERT(reporter, tangent.fX == -SK_Scalar1);
+ REPORTER_ASSERT(reporter, tangent.fY == 0);
+
+ test_small_segment();
+ test_small_segment2();
+ test_small_segment3();
+}
diff --git a/src/third_party/skia/tests/PathOpsAngleIdeas.cpp b/src/third_party/skia/tests/PathOpsAngleIdeas.cpp
new file mode 100755
index 0000000..901cab2
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsAngleIdeas.cpp
@@ -0,0 +1,860 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkIntersections.h"
+#include "SkOpSegment.h"
+#include "SkPathOpsTriangle.h"
+#include "SkRandom.h"
+#include "SkTArray.h"
+#include "SkTSort.h"
+#include "Test.h"
+
+static bool gPathOpsAngleIdeasVerbose = false;
+static bool gPathOpsAngleIdeasEnableBruteCheck = false;
+
+class PathOpsAngleTester {
+public:
+ static int ConvexHullOverlaps(const SkOpAngle& lh, const SkOpAngle& rh) {
+ return lh.convexHullOverlaps(rh);
+ }
+
+ static int EndsIntersect(const SkOpAngle& lh, const SkOpAngle& rh) {
+ return lh.endsIntersect(rh);
+ }
+};
+
+struct TRange {
+ double tMin1;
+ double tMin2;
+ double t1;
+ double t2;
+ double tMin;
+ double a1;
+ double a2;
+ bool ccw;
+};
+
+static double testArc(skiatest::Reporter* reporter, const SkDQuad& quad, const SkDQuad& arcRef,
+ int octant) {
+ SkDQuad arc = arcRef;
+ SkDVector offset = {quad[0].fX, quad[0].fY};
+ arc[0] += offset;
+ arc[1] += offset;
+ arc[2] += offset;
+ SkIntersections i;
+ i.intersect(arc, quad);
+ if (i.used() == 0) {
+ return -1;
+ }
+ int smallest = -1;
+ double t = 2;
+ for (int idx = 0; idx < i.used(); ++idx) {
+ if (i[0][idx] > 1 || i[0][idx] < 0) {
+ i.reset();
+ i.intersect(arc, quad);
+ }
+ if (i[1][idx] > 1 || i[1][idx] < 0) {
+ i.reset();
+ i.intersect(arc, quad);
+ }
+ if (t > i[1][idx]) {
+ smallest = idx;
+ t = i[1][idx];
+ }
+ }
+ REPORTER_ASSERT(reporter, smallest >= 0);
+ REPORTER_ASSERT(reporter, t >= 0 && t <= 1);
+ return i[1][smallest];
+}
+
+static void orderQuads(skiatest::Reporter* reporter, const SkDQuad& quad, double radius,
+ SkTArray<double, false>* tArray) {
+ double r = radius;
+ double s = r * SK_ScalarTanPIOver8;
+ double m = r * SK_ScalarRoot2Over2;
+ // construct circle from quads
+ const SkDQuad circle[8] = {{{{ r, 0}, { r, -s}, { m, -m}}},
+ {{{ m, -m}, { s, -r}, { 0, -r}}},
+ {{{ 0, -r}, {-s, -r}, {-m, -m}}},
+ {{{-m, -m}, {-r, -s}, {-r, 0}}},
+ {{{-r, 0}, {-r, s}, {-m, m}}},
+ {{{-m, m}, {-s, r}, { 0, r}}},
+ {{{ 0, r}, { s, r}, { m, m}}},
+ {{{ m, m}, { r, s}, { r, 0}}}};
+ for (int octant = 0; octant < 8; ++octant) {
+ double t = testArc(reporter, quad, circle[octant], octant);
+ if (t < 0) {
+ continue;
+ }
+ for (int index = 0; index < tArray->count(); ++index) {
+ double matchT = (*tArray)[index];
+ if (approximately_equal(t, matchT)) {
+ goto next;
+ }
+ }
+ tArray->push_back(t);
+next: ;
+ }
+}
+
+static double quadAngle(skiatest::Reporter* reporter, const SkDQuad& quad, double t) {
+ const SkDVector& pt = quad.ptAtT(t) - quad[0];
+ double angle = (atan2(pt.fY, pt.fX) + SK_ScalarPI) * 8 / (SK_ScalarPI * 2);
+ REPORTER_ASSERT(reporter, angle >= 0 && angle <= 8);
+ return angle;
+}
+
+static bool angleDirection(double a1, double a2) {
+ double delta = a1 - a2;
+ return (delta < 4 && delta > 0) || delta < -4;
+}
+
+static void setQuadHullSweep(const SkDQuad& quad, SkDVector sweep[2]) {
+ sweep[0] = quad[1] - quad[0];
+ sweep[1] = quad[2] - quad[0];
+}
+
+static double distEndRatio(double dist, const SkDQuad& quad) {
+ SkDVector v[] = {quad[2] - quad[0], quad[1] - quad[0], quad[2] - quad[1]};
+ double longest = SkTMax(v[0].length(), SkTMax(v[1].length(), v[2].length()));
+ return longest / dist;
+}
+
+static bool checkParallel(skiatest::Reporter* reporter, const SkDQuad& quad1, const SkDQuad& quad2) {
+ SkDVector sweep[2], tweep[2];
+ setQuadHullSweep(quad1, sweep);
+ setQuadHullSweep(quad2, tweep);
+ // if the ctrl tangents are not nearly parallel, use them
+ // solve for opposite direction displacement scale factor == m
+ // initial dir = v1.cross(v2) == v2.x * v1.y - v2.y * v1.x
+ // displacement of q1[1] : dq1 = { -m * v1.y, m * v1.x } + q1[1]
+ // straight angle when : v2.x * (dq1.y - q1[0].y) == v2.y * (dq1.x - q1[0].x)
+ // v2.x * (m * v1.x + v1.y) == v2.y * (-m * v1.y + v1.x)
+ // - m * (v2.x * v1.x + v2.y * v1.y) == v2.x * v1.y - v2.y * v1.x
+ // m = (v2.y * v1.x - v2.x * v1.y) / (v2.x * v1.x + v2.y * v1.y)
+ // m = v1.cross(v2) / v1.dot(v2)
+ double s0dt0 = sweep[0].dot(tweep[0]);
+ REPORTER_ASSERT(reporter, s0dt0 != 0);
+ double s0xt0 = sweep[0].crossCheck(tweep[0]);
+ double m = s0xt0 / s0dt0;
+ double sDist = sweep[0].length() * m;
+ double tDist = tweep[0].length() * m;
+ bool useS = fabs(sDist) < fabs(tDist);
+ double mFactor = fabs(useS ? distEndRatio(sDist, quad1) : distEndRatio(tDist, quad2));
+ if (mFactor < 5000) { // empirically found limit
+ return s0xt0 < 0;
+ }
+ SkDVector m0 = quad1.ptAtT(0.5) - quad1[0];
+ SkDVector m1 = quad2.ptAtT(0.5) - quad2[0];
+ return m0.crossCheck(m1) < 0;
+}
+
+/* returns
+ -1 if overlaps
+ 0 if no overlap cw
+ 1 if no overlap ccw
+*/
+static int quadHullsOverlap(skiatest::Reporter* reporter, const SkDQuad& quad1,
+ const SkDQuad& quad2) {
+ SkDVector sweep[2], tweep[2];
+ setQuadHullSweep(quad1, sweep);
+ setQuadHullSweep(quad2, tweep);
+ double s0xs1 = sweep[0].crossCheck(sweep[1]);
+ double s0xt0 = sweep[0].crossCheck(tweep[0]);
+ double s1xt0 = sweep[1].crossCheck(tweep[0]);
+ bool tBetweenS = s0xs1 > 0 ? s0xt0 > 0 && s1xt0 < 0 : s0xt0 < 0 && s1xt0 > 0;
+ double s0xt1 = sweep[0].crossCheck(tweep[1]);
+ double s1xt1 = sweep[1].crossCheck(tweep[1]);
+ tBetweenS |= s0xs1 > 0 ? s0xt1 > 0 && s1xt1 < 0 : s0xt1 < 0 && s1xt1 > 0;
+ double t0xt1 = tweep[0].crossCheck(tweep[1]);
+ if (tBetweenS) {
+ return -1;
+ }
+ if ((s0xt0 == 0 && s1xt1 == 0) || (s1xt0 == 0 && s0xt1 == 0)) { // s0 to s1 equals t0 to t1
+ return -1;
+ }
+ bool sBetweenT = t0xt1 > 0 ? s0xt0 < 0 && s0xt1 > 0 : s0xt0 > 0 && s0xt1 < 0;
+ sBetweenT |= t0xt1 > 0 ? s1xt0 < 0 && s1xt1 > 0 : s1xt0 > 0 && s1xt1 < 0;
+ if (sBetweenT) {
+ return -1;
+ }
+ // if all of the sweeps are in the same half plane, then the order of any pair is enough
+ if (s0xt0 >= 0 && s0xt1 >= 0 && s1xt0 >= 0 && s1xt1 >= 0) {
+ return 0;
+ }
+ if (s0xt0 <= 0 && s0xt1 <= 0 && s1xt0 <= 0 && s1xt1 <= 0) {
+ return 1;
+ }
+ // if the outside sweeps are greater than 180 degress:
+ // first assume the inital tangents are the ordering
+ // if the midpoint direction matches the inital order, that is enough
+ SkDVector m0 = quad1.ptAtT(0.5) - quad1[0];
+ SkDVector m1 = quad2.ptAtT(0.5) - quad2[0];
+ double m0xm1 = m0.crossCheck(m1);
+ if (s0xt0 > 0 && m0xm1 > 0) {
+ return 0;
+ }
+ if (s0xt0 < 0 && m0xm1 < 0) {
+ return 1;
+ }
+ REPORTER_ASSERT(reporter, s0xt0 != 0);
+ return checkParallel(reporter, quad1, quad2);
+}
+
+static double radianSweep(double start, double end) {
+ double sweep = end - start;
+ if (sweep > SK_ScalarPI) {
+ sweep -= 2 * SK_ScalarPI;
+ } else if (sweep < -SK_ScalarPI) {
+ sweep += 2 * SK_ScalarPI;
+ }
+ return sweep;
+}
+
+static bool radianBetween(double start, double test, double end) {
+ double startToEnd = radianSweep(start, end);
+ double startToTest = radianSweep(start, test);
+ double testToEnd = radianSweep(test, end);
+ return (startToTest <= 0 && testToEnd <= 0 && startToTest >= startToEnd) ||
+ (startToTest >= 0 && testToEnd >= 0 && startToTest <= startToEnd);
+}
+
+static bool orderTRange(skiatest::Reporter* reporter, const SkDQuad& quad1, const SkDQuad& quad2,
+ double r, TRange* result) {
+ SkTArray<double, false> t1Array, t2Array;
+ orderQuads(reporter, quad1, r, &t1Array);
+ orderQuads(reporter,quad2, r, &t2Array);
+ if (!t1Array.count() || !t2Array.count()) {
+ return false;
+ }
+ SkTQSort<double>(t1Array.begin(), t1Array.end() - 1);
+ SkTQSort<double>(t2Array.begin(), t2Array.end() - 1);
+ double t1 = result->tMin1 = t1Array[0];
+ double t2 = result->tMin2 = t2Array[0];
+ double a1 = quadAngle(reporter,quad1, t1);
+ double a2 = quadAngle(reporter,quad2, t2);
+ if (approximately_equal(a1, a2)) {
+ return false;
+ }
+ bool refCCW = angleDirection(a1, a2);
+ result->t1 = t1;
+ result->t2 = t2;
+ result->tMin = SkTMin(t1, t2);
+ result->a1 = a1;
+ result->a2 = a2;
+ result->ccw = refCCW;
+ return true;
+}
+
+static bool equalPoints(const SkDPoint& pt1, const SkDPoint& pt2, double max) {
+ return approximately_zero_when_compared_to(pt1.fX - pt2.fX, max)
+ && approximately_zero_when_compared_to(pt1.fY - pt2.fY, max);
+}
+
+static double maxDist(const SkDQuad& quad) {
+ SkDRect bounds;
+ bounds.setBounds(quad);
+ SkDVector corner[4] = {
+ { bounds.fLeft - quad[0].fX, bounds.fTop - quad[0].fY },
+ { bounds.fRight - quad[0].fX, bounds.fTop - quad[0].fY },
+ { bounds.fLeft - quad[0].fX, bounds.fBottom - quad[0].fY },
+ { bounds.fRight - quad[0].fX, bounds.fBottom - quad[0].fY }
+ };
+ double max = 0;
+ for (unsigned index = 0; index < SK_ARRAY_COUNT(corner); ++index) {
+ max = SkTMax(max, corner[index].length());
+ }
+ return max;
+}
+
+static double maxQuad(const SkDQuad& quad) {
+ double max = 0;
+ for (int index = 0; index < 2; ++index) {
+ max = SkTMax(max, fabs(quad[index].fX));
+ max = SkTMax(max, fabs(quad[index].fY));
+ }
+ return max;
+}
+
+static bool bruteMinT(skiatest::Reporter* reporter, const SkDQuad& quad1, const SkDQuad& quad2,
+ TRange* lowerRange, TRange* upperRange) {
+ double maxRadius = SkTMin(maxDist(quad1), maxDist(quad2));
+ double maxQuads = SkTMax(maxQuad(quad1), maxQuad(quad2));
+ double r = maxRadius / 2;
+ double rStep = r / 2;
+ SkDPoint best1 = {SK_ScalarInfinity, SK_ScalarInfinity};
+ SkDPoint best2 = {SK_ScalarInfinity, SK_ScalarInfinity};
+ int bestCCW = -1;
+ double bestR = maxRadius;
+ upperRange->tMin = 0;
+ lowerRange->tMin = 1;
+ do {
+ do { // find upper bounds of single result
+ TRange tRange;
+ bool stepUp = orderTRange(reporter, quad1, quad2, r, &tRange);
+ if (stepUp) {
+ SkDPoint pt1 = quad1.ptAtT(tRange.t1);
+ if (equalPoints(pt1, best1, maxQuads)) {
+ break;
+ }
+ best1 = pt1;
+ SkDPoint pt2 = quad2.ptAtT(tRange.t2);
+ if (equalPoints(pt2, best2, maxQuads)) {
+ break;
+ }
+ best2 = pt2;
+ if (gPathOpsAngleIdeasVerbose) {
+ SkDebugf("u bestCCW=%d ccw=%d bestMin=%1.9g:%1.9g r=%1.9g tMin=%1.9g\n",
+ bestCCW, tRange.ccw, lowerRange->tMin, upperRange->tMin, r,
+ tRange.tMin);
+ }
+ if (bestCCW >= 0 && bestCCW != (int) tRange.ccw) {
+ if (tRange.tMin < upperRange->tMin) {
+ upperRange->tMin = 0;
+ } else {
+ stepUp = false;
+ }
+ }
+ if (upperRange->tMin < tRange.tMin) {
+ bestCCW = tRange.ccw;
+ bestR = r;
+ *upperRange = tRange;
+ }
+ if (lowerRange->tMin > tRange.tMin) {
+ *lowerRange = tRange;
+ }
+ }
+ r += stepUp ? rStep : -rStep;
+ rStep /= 2;
+ } while (rStep > FLT_EPSILON);
+ if (bestCCW < 0) {
+ REPORTER_ASSERT(reporter, bestR < maxRadius);
+ return false;
+ }
+ double lastHighR = bestR;
+ r = bestR / 2;
+ rStep = r / 2;
+ do { // find lower bounds of single result
+ TRange tRange;
+ bool success = orderTRange(reporter, quad1, quad2, r, &tRange);
+ if (success) {
+ if (gPathOpsAngleIdeasVerbose) {
+ SkDebugf("l bestCCW=%d ccw=%d bestMin=%1.9g:%1.9g r=%1.9g tMin=%1.9g\n",
+ bestCCW, tRange.ccw, lowerRange->tMin, upperRange->tMin, r,
+ tRange.tMin);
+ }
+ if (bestCCW != (int) tRange.ccw || upperRange->tMin < tRange.tMin) {
+ bestCCW = tRange.ccw;
+ *upperRange = tRange;
+ bestR = lastHighR;
+ break; // need to establish a new upper bounds
+ }
+ SkDPoint pt1 = quad1.ptAtT(tRange.t1);
+ SkDPoint pt2 = quad2.ptAtT(tRange.t2);
+ if (equalPoints(pt1, best1, maxQuads)) {
+ goto breakOut;
+ }
+ best1 = pt1;
+ if (equalPoints(pt2, best2, maxQuads)) {
+ goto breakOut;
+ }
+ best2 = pt2;
+ if (equalPoints(pt1, pt2, maxQuads)) {
+ success = false;
+ } else {
+ if (upperRange->tMin < tRange.tMin) {
+ *upperRange = tRange;
+ }
+ if (lowerRange->tMin > tRange.tMin) {
+ *lowerRange = tRange;
+ }
+ }
+ lastHighR = SkTMin(r, lastHighR);
+ }
+ r += success ? -rStep : rStep;
+ rStep /= 2;
+ } while (rStep > FLT_EPSILON);
+ } while (rStep > FLT_EPSILON);
+breakOut:
+ if (gPathOpsAngleIdeasVerbose) {
+ SkDebugf("l a2-a1==%1.9g\n", lowerRange->a2 - lowerRange->a1);
+ }
+ return true;
+}
+
+static void bruteForce(skiatest::Reporter* reporter, const SkDQuad& quad1, const SkDQuad& quad2,
+ bool ccw) {
+ if (!gPathOpsAngleIdeasEnableBruteCheck) {
+ return;
+ }
+ TRange lowerRange, upperRange;
+ bool result = bruteMinT(reporter, quad1, quad2, &lowerRange, &upperRange);
+ REPORTER_ASSERT(reporter, result);
+ double angle = fabs(lowerRange.a2 - lowerRange.a1);
+ REPORTER_ASSERT(reporter, angle > 3.998 || ccw == upperRange.ccw);
+}
+
+static bool bruteForceCheck(skiatest::Reporter* reporter, const SkDQuad& quad1,
+ const SkDQuad& quad2, bool ccw) {
+ TRange lowerRange, upperRange;
+ bool result = bruteMinT(reporter, quad1, quad2, &lowerRange, &upperRange);
+ REPORTER_ASSERT(reporter, result);
+ return ccw == upperRange.ccw;
+}
+
+class PathOpsSegmentTester {
+public:
+ static void ConstructQuad(SkOpSegment* segment, SkPoint shortQuad[3]) {
+ segment->debugConstructQuad(shortQuad);
+ }
+};
+
+static void makeSegment(const SkDQuad& quad, SkPoint shortQuad[3], SkOpSegment* result) {
+ shortQuad[0] = quad[0].asSkPoint();
+ shortQuad[1] = quad[1].asSkPoint();
+ shortQuad[2] = quad[2].asSkPoint();
+ PathOpsSegmentTester::ConstructQuad(result, shortQuad);
+}
+
+static void testQuadAngles(skiatest::Reporter* reporter, const SkDQuad& quad1, const SkDQuad& quad2,
+ int testNo) {
+ SkPoint shortQuads[2][3];
+ SkOpSegment seg[2];
+ makeSegment(quad1, shortQuads[0], &seg[0]);
+ makeSegment(quad2, shortQuads[1], &seg[1]);
+ int realOverlap = PathOpsAngleTester::ConvexHullOverlaps(*seg[0].debugLastAngle(),
+ *seg[1].debugLastAngle());
+ const SkDPoint& origin = quad1[0];
+ REPORTER_ASSERT(reporter, origin == quad2[0]);
+ double a1s = atan2(origin.fY - quad1[1].fY, quad1[1].fX - origin.fX);
+ double a1e = atan2(origin.fY - quad1[2].fY, quad1[2].fX - origin.fX);
+ double a2s = atan2(origin.fY - quad2[1].fY, quad2[1].fX - origin.fX);
+ double a2e = atan2(origin.fY - quad2[2].fY, quad2[2].fX - origin.fX);
+ bool oldSchoolOverlap = radianBetween(a1s, a2s, a1e)
+ || radianBetween(a1s, a2e, a1e) || radianBetween(a2s, a1s, a2e)
+ || radianBetween(a2s, a1e, a2e);
+ int overlap = quadHullsOverlap(reporter, quad1, quad2);
+ bool realMatchesOverlap = realOverlap == overlap || SK_ScalarPI - fabs(a2s - a1s) < 0.002;
+ if (realOverlap != overlap) {
+ SkDebugf("\nSK_ScalarPI - fabs(a2s - a1s) = %1.9g\n", SK_ScalarPI - fabs(a2s - a1s));
+ }
+ if (!realMatchesOverlap) {
+ DumpQ(quad1, quad2, testNo);
+ }
+ REPORTER_ASSERT(reporter, realMatchesOverlap);
+ if (oldSchoolOverlap != (overlap < 0)) {
+ overlap = quadHullsOverlap(reporter, quad1, quad2); // set a breakpoint and debug if assert fires
+ REPORTER_ASSERT(reporter, oldSchoolOverlap == (overlap < 0));
+ }
+ SkDVector v1s = quad1[1] - quad1[0];
+ SkDVector v1e = quad1[2] - quad1[0];
+ SkDVector v2s = quad2[1] - quad2[0];
+ SkDVector v2e = quad2[2] - quad2[0];
+ double vDir[2] = { v1s.cross(v1e), v2s.cross(v2e) };
+ bool ray1In2 = v1s.cross(v2s) * vDir[1] <= 0 && v1s.cross(v2e) * vDir[1] >= 0;
+ bool ray2In1 = v2s.cross(v1s) * vDir[0] <= 0 && v2s.cross(v1e) * vDir[0] >= 0;
+ if (overlap >= 0) {
+ // verify that hulls really don't overlap
+ REPORTER_ASSERT(reporter, !ray1In2);
+ REPORTER_ASSERT(reporter, !ray2In1);
+ bool ctrl1In2 = v1e.cross(v2s) * vDir[1] <= 0 && v1e.cross(v2e) * vDir[1] >= 0;
+ REPORTER_ASSERT(reporter, !ctrl1In2);
+ bool ctrl2In1 = v2e.cross(v1s) * vDir[0] <= 0 && v2e.cross(v1e) * vDir[0] >= 0;
+ REPORTER_ASSERT(reporter, !ctrl2In1);
+ // check answer against reference
+ bruteForce(reporter, quad1, quad2, overlap > 0);
+ }
+ // continue end point rays and see if they intersect the opposite curve
+ SkDLine rays[] = {{{origin, quad2[2]}}, {{origin, quad1[2]}}};
+ const SkDQuad* quads[] = {&quad1, &quad2};
+ SkDVector midSpokes[2];
+ SkIntersections intersect[2];
+ double minX, minY, maxX, maxY;
+ minX = minY = SK_ScalarInfinity;
+ maxX = maxY = -SK_ScalarInfinity;
+ double maxWidth = 0;
+ bool useIntersect = false;
+ double smallestTs[] = {1, 1};
+ for (unsigned index = 0; index < SK_ARRAY_COUNT(quads); ++index) {
+ const SkDQuad& q = *quads[index];
+ midSpokes[index] = q.ptAtT(0.5) - origin;
+ minX = SkTMin(SkTMin(SkTMin(minX, origin.fX), q[1].fX), q[2].fX);
+ minY = SkTMin(SkTMin(SkTMin(minY, origin.fY), q[1].fY), q[2].fY);
+ maxX = SkTMax(SkTMax(SkTMax(maxX, origin.fX), q[1].fX), q[2].fX);
+ maxY = SkTMax(SkTMax(SkTMax(maxY, origin.fY), q[1].fY), q[2].fY);
+ maxWidth = SkTMax(maxWidth, SkTMax(maxX - minX, maxY - minY));
+ intersect[index].intersectRay(q, rays[index]);
+ const SkIntersections& i = intersect[index];
+ REPORTER_ASSERT(reporter, i.used() >= 1);
+ bool foundZero = false;
+ double smallT = 1;
+ for (int idx2 = 0; idx2 < i.used(); ++idx2) {
+ double t = i[0][idx2];
+ if (t == 0) {
+ foundZero = true;
+ continue;
+ }
+ if (smallT > t) {
+ smallT = t;
+ }
+ }
+ REPORTER_ASSERT(reporter, foundZero == true);
+ if (smallT == 1) {
+ continue;
+ }
+ SkDVector ray = q.ptAtT(smallT) - origin;
+ SkDVector end = rays[index][1] - origin;
+ if (ray.fX * end.fX < 0 || ray.fY * end.fY < 0) {
+ continue;
+ }
+ double rayDist = ray.length();
+ double endDist = end.length();
+ double delta = fabs(rayDist - endDist) / maxWidth;
+ if (delta > 1e-4) {
+ useIntersect ^= true;
+ }
+ smallestTs[index] = smallT;
+ }
+ bool firstInside;
+ if (useIntersect) {
+ int sIndex = (int) (smallestTs[1] < 1);
+ REPORTER_ASSERT(reporter, smallestTs[sIndex ^ 1] == 1);
+ double t = smallestTs[sIndex];
+ const SkDQuad& q = *quads[sIndex];
+ SkDVector ray = q.ptAtT(t) - origin;
+ SkDVector end = rays[sIndex][1] - origin;
+ double rayDist = ray.length();
+ double endDist = end.length();
+ SkDVector mid = q.ptAtT(t / 2) - origin;
+ double midXray = mid.crossCheck(ray);
+ if (gPathOpsAngleIdeasVerbose) {
+ SkDebugf("rayDist>endDist:%d sIndex==0:%d vDir[sIndex]<0:%d midXray<0:%d\n",
+ rayDist > endDist, sIndex == 0, vDir[sIndex] < 0, midXray < 0);
+ }
+ SkASSERT(SkScalarSignAsInt(SkDoubleToScalar(midXray))
+ == SkScalarSignAsInt(SkDoubleToScalar(vDir[sIndex])));
+ firstInside = (rayDist > endDist) ^ (sIndex == 0) ^ (vDir[sIndex] < 0);
+ } else if (overlap >= 0) {
+ return; // answer has already been determined
+ } else {
+ firstInside = checkParallel(reporter, quad1, quad2);
+ }
+ if (overlap < 0) {
+ SkDEBUGCODE(int realEnds =)
+ PathOpsAngleTester::EndsIntersect(*seg[0].debugLastAngle(),
+ *seg[1].debugLastAngle());
+ SkASSERT(realEnds == (firstInside ? 1 : 0));
+ }
+ bruteForce(reporter, quad1, quad2, firstInside);
+}
+
+DEF_TEST(PathOpsAngleOverlapHullsOne, reporter) {
+// gPathOpsAngleIdeasVerbose = true;
+ const SkDQuad quads[] = {
+{{{939.4808349609375, 914.355224609375}, {-357.7921142578125, 590.842529296875}, {736.8936767578125, -350.717529296875}}},
+{{{939.4808349609375, 914.355224609375}, {-182.85418701171875, 634.4552001953125}, {-509.62615966796875, 576.1182861328125}}}
+ };
+ for (int index = 0; index < (int) SK_ARRAY_COUNT(quads); index += 2) {
+ testQuadAngles(reporter, quads[index], quads[index + 1], 0);
+ }
+}
+
+DEF_TEST(PathOpsAngleOverlapHulls, reporter) {
+ if (!gPathOpsAngleIdeasVerbose) { // takes a while to run -- so exclude it by default
+ return;
+ }
+ SkRandom ran;
+ for (int index = 0; index < 100000; ++index) {
+ if (index % 1000 == 999) SkDebugf(".");
+ SkDPoint origin = {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)};
+ SkDQuad quad1 = {{origin, {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
+ {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)}}};
+ if (quad1[0] == quad1[2]) {
+ continue;
+ }
+ SkDQuad quad2 = {{origin, {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
+ {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)}}};
+ if (quad2[0] == quad2[2]) {
+ continue;
+ }
+ SkIntersections i;
+ i.intersect(quad1, quad2);
+ REPORTER_ASSERT(reporter, i.used() >= 1);
+ if (i.used() > 1) {
+ continue;
+ }
+ testQuadAngles(reporter, quad1, quad2, index);
+ }
+}
+
+DEF_TEST(PathOpsAngleBruteT, reporter) {
+ if (!gPathOpsAngleIdeasVerbose) { // takes a while to run -- so exclude it by default
+ return;
+ }
+ SkRandom ran;
+ double smaller = SK_Scalar1;
+ SkDQuad small[2];
+ SkDEBUGCODE(int smallIndex);
+ for (int index = 0; index < 100000; ++index) {
+ SkDPoint origin = {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)};
+ SkDQuad quad1 = {{origin, {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
+ {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)}}};
+ if (quad1[0] == quad1[2]) {
+ continue;
+ }
+ SkDQuad quad2 = {{origin, {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
+ {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)}}};
+ if (quad2[0] == quad2[2]) {
+ continue;
+ }
+ SkIntersections i;
+ i.intersect(quad1, quad2);
+ REPORTER_ASSERT(reporter, i.used() >= 1);
+ if (i.used() > 1) {
+ continue;
+ }
+ TRange lowerRange, upperRange;
+ bool result = bruteMinT(reporter, quad1, quad2, &lowerRange, &upperRange);
+ REPORTER_ASSERT(reporter, result);
+ double min = SkTMin(upperRange.t1, upperRange.t2);
+ if (smaller > min) {
+ small[0] = quad1;
+ small[1] = quad2;
+ SkDEBUGCODE(smallIndex = index);
+ smaller = min;
+ }
+ }
+#ifdef SK_DEBUG
+ DumpQ(small[0], small[1], smallIndex);
+#endif
+}
+
+DEF_TEST(PathOpsAngleBruteTOne, reporter) {
+// gPathOpsAngleIdeasVerbose = true;
+ const SkDQuad quads[] = {
+{{{-770.8492431640625, 948.2369384765625}, {-853.37066650390625, 972.0301513671875}, {-200.62042236328125, -26.7174072265625}}},
+{{{-770.8492431640625, 948.2369384765625}, {513.602783203125, 578.8681640625}, {960.641357421875, -813.69757080078125}}},
+{{{563.8267822265625, -107.4566650390625}, {-44.67724609375, -136.57452392578125}, {492.3856201171875, -268.79644775390625}}},
+{{{563.8267822265625, -107.4566650390625}, {708.049072265625, -100.77789306640625}, {-48.88226318359375, 967.9022216796875}}},
+{{{598.857421875, 846.345458984375}, {-644.095703125, -316.12921142578125}, {-97.64599609375, 20.6158447265625}}},
+{{{598.857421875, 846.345458984375}, {715.7142333984375, 955.3599853515625}, {-919.9478759765625, 691.611328125}}},
+ };
+ TRange lowerRange, upperRange;
+ bruteMinT(reporter, quads[0], quads[1], &lowerRange, &upperRange);
+ bruteMinT(reporter, quads[2], quads[3], &lowerRange, &upperRange);
+ bruteMinT(reporter, quads[4], quads[5], &lowerRange, &upperRange);
+}
+
+/*
+The sorting problem happens when the inital tangents are not a true indicator of the curve direction
+Nearly always, the initial tangents do give the right answer,
+so the trick is to figure out when the initial tangent cannot be trusted.
+If the convex hulls of both curves are in the same half plane, and not overlapping, sorting the
+hulls is enough.
+If the hulls overlap, and have the same general direction, then intersect the shorter end point ray
+with the opposing curve, and see on which side of the shorter curve the opposing intersection lies.
+Otherwise, if the control vector is extremely short, likely the point on curve must be computed
+If moving the control point slightly can change the sign of the cross product, either answer could
+be "right".
+We need to determine how short is extremely short. Move the control point a set percentage of
+the largest length to determine how stable the curve is vis-a-vis the initial tangent.
+*/
+
+static const SkDQuad extremeTests[][2] = {
+ {
+ {{{-708.0077926931004,-154.61669472244046},
+ {-707.9234268635319,-154.30459999551294},
+ {505.58447265625,-504.9130859375}}},
+ {{{-708.0077926931004,-154.61669472244046},
+ {-711.127526325141,-163.9446090624656},
+ {-32.39227294921875,-906.3277587890625}}},
+ }, {
+ {{{-708.0077926931004,-154.61669472244046},
+ {-708.2875337527566,-154.36676458635623},
+ {505.58447265625,-504.9130859375}}},
+ {{{-708.0077926931004,-154.61669472244046},
+ {-708.4111557216864,-154.5366642875255},
+ {-32.39227294921875,-906.3277587890625}}},
+ }, {
+ {{{-609.0230951752058,-267.5435593490574},
+ {-594.1120809906336,-136.08492475411555},
+ {505.58447265625,-504.9130859375}}},
+ {{{-609.0230951752058,-267.5435593490574},
+ {-693.7467719138988,-341.3259237831895},
+ {-32.39227294921875,-906.3277587890625}}}
+ }, {
+ {{{-708.0077926931004,-154.61669472244046},
+ {-707.9994640658723,-154.58588461064852},
+ {505.58447265625,-504.9130859375}}},
+ {{{-708.0077926931004,-154.61669472244046},
+ {-708.0239418990758,-154.6403553507124},
+ {-32.39227294921875,-906.3277587890625}}}
+ }, {
+ {{{-708.0077926931004,-154.61669472244046},
+ {-707.9993222215099,-154.55999389855003},
+ {68.88981098017803,296.9273945411635}}},
+ {{{-708.0077926931004,-154.61669472244046},
+ {-708.0509091919608,-154.64675214697067},
+ {-777.4871194247767,-995.1470120113145}}}
+ }, {
+ {{{-708.0077926931004,-154.61669472244046},
+ {-708.0060491116379,-154.60889321524968},
+ {229.97088707895057,-430.0569357467175}}},
+ {{{-708.0077926931004,-154.61669472244046},
+ {-708.013911296257,-154.6219143988058},
+ {138.13162892614037,-573.3689311737394}}}
+ }, {
+ {{{-543.2570545751013,-237.29243831075053},
+ {-452.4119186056987,-143.47223056267802},
+ {229.97088707895057,-430.0569357467175}}},
+ {{{-543.2570545751013,-237.29243831075053},
+ {-660.5330371214436,-362.0016148388},
+ {138.13162892614037,-573.3689311737394}}},
+ },
+};
+
+static double endCtrlRatio(const SkDQuad quad) {
+ SkDVector longEdge = quad[2] - quad[0];
+ double longLen = longEdge.length();
+ SkDVector shortEdge = quad[1] - quad[0];
+ double shortLen = shortEdge.length();
+ return longLen / shortLen;
+}
+
+static void computeMV(const SkDQuad& quad, const SkDVector& v, double m, SkDVector mV[2]) {
+ SkDPoint mPta = {quad[1].fX - m * v.fY, quad[1].fY + m * v.fX};
+ SkDPoint mPtb = {quad[1].fX + m * v.fY, quad[1].fY - m * v.fX};
+ mV[0] = mPta - quad[0];
+ mV[1] = mPtb - quad[0];
+}
+
+static double mDistance(skiatest::Reporter* reporter, bool agrees, const SkDQuad& q1,
+ const SkDQuad& q2) {
+ if (1 && agrees) {
+ return SK_ScalarMax;
+ }
+ // how close is the angle from inflecting in the opposite direction?
+ SkDVector v1 = q1[1] - q1[0];
+ SkDVector v2 = q2[1] - q2[0];
+ double dir = v1.crossCheck(v2);
+ REPORTER_ASSERT(reporter, dir != 0);
+ // solve for opposite direction displacement scale factor == m
+ // initial dir = v1.cross(v2) == v2.x * v1.y - v2.y * v1.x
+ // displacement of q1[1] : dq1 = { -m * v1.y, m * v1.x } + q1[1]
+ // straight angle when : v2.x * (dq1.y - q1[0].y) == v2.y * (dq1.x - q1[0].x)
+ // v2.x * (m * v1.x + v1.y) == v2.y * (-m * v1.y + v1.x)
+ // - m * (v2.x * v1.x + v2.y * v1.y) == v2.x * v1.y - v2.y * v1.x
+ // m = (v2.y * v1.x - v2.x * v1.y) / (v2.x * v1.x + v2.y * v1.y)
+ // m = v1.cross(v2) / v1.dot(v2)
+ double div = v1.dot(v2);
+ REPORTER_ASSERT(reporter, div != 0);
+ double m = dir / div;
+ SkDVector mV1[2], mV2[2];
+ computeMV(q1, v1, m, mV1);
+ computeMV(q2, v2, m, mV2);
+ double dist1 = v1.length() * m;
+ double dist2 = v2.length() * m;
+ if (gPathOpsAngleIdeasVerbose) {
+ SkDebugf("%c r1=%1.9g r2=%1.9g m=%1.9g dist1=%1.9g dist2=%1.9g "
+ " dir%c 1a=%1.9g 1b=%1.9g 2a=%1.9g 2b=%1.9g\n", agrees ? 'T' : 'F',
+ endCtrlRatio(q1), endCtrlRatio(q2), m, dist1, dist2, dir > 0 ? '+' : '-',
+ mV1[0].crossCheck(v2), mV1[1].crossCheck(v2),
+ mV2[0].crossCheck(v1), mV2[1].crossCheck(v1));
+ }
+ if (1) {
+ bool use1 = fabs(dist1) < fabs(dist2);
+ if (gPathOpsAngleIdeasVerbose) {
+ SkDebugf("%c dist=%1.9g r=%1.9g\n", agrees ? 'T' : 'F', use1 ? dist1 : dist2,
+ use1 ? distEndRatio(dist1, q1) : distEndRatio(dist2, q2));
+ }
+ return fabs(use1 ? distEndRatio(dist1, q1) : distEndRatio(dist2, q2));
+ }
+ return SK_ScalarMax;
+}
+
+static void midPointAgrees(skiatest::Reporter* reporter, const SkDQuad& q1, const SkDQuad& q2,
+ bool ccw) {
+ SkDPoint mid1 = q1.ptAtT(0.5);
+ SkDVector m1 = mid1 - q1[0];
+ SkDPoint mid2 = q2.ptAtT(0.5);
+ SkDVector m2 = mid2 - q2[0];
+ REPORTER_ASSERT(reporter, ccw ? m1.crossCheck(m2) < 0 : m1.crossCheck(m2) > 0);
+}
+
+DEF_TEST(PathOpsAngleExtreme, reporter) {
+ if (!gPathOpsAngleIdeasVerbose) { // takes a while to run -- so exclude it by default
+ return;
+ }
+ double maxR = SK_ScalarMax;
+ for (int index = 0; index < (int) SK_ARRAY_COUNT(extremeTests); ++index) {
+ const SkDQuad& quad1 = extremeTests[index][0];
+ const SkDQuad& quad2 = extremeTests[index][1];
+ if (gPathOpsAngleIdeasVerbose) {
+ SkDebugf("%s %d\n", __FUNCTION__, index);
+ }
+ REPORTER_ASSERT(reporter, quad1[0] == quad2[0]);
+ SkIntersections i;
+ i.intersect(quad1, quad2);
+ REPORTER_ASSERT(reporter, i.used() == 1);
+ REPORTER_ASSERT(reporter, i.pt(0) == quad1[0]);
+ int overlap = quadHullsOverlap(reporter, quad1, quad2);
+ REPORTER_ASSERT(reporter, overlap >= 0);
+ SkDVector sweep[2], tweep[2];
+ setQuadHullSweep(quad1, sweep);
+ setQuadHullSweep(quad2, tweep);
+ double s0xt0 = sweep[0].crossCheck(tweep[0]);
+ REPORTER_ASSERT(reporter, s0xt0 != 0);
+ bool ccw = s0xt0 < 0;
+ bool agrees = bruteForceCheck(reporter, quad1, quad2, ccw);
+ maxR = SkTMin(maxR, mDistance(reporter, agrees, quad1, quad2));
+ if (agrees) {
+ continue;
+ }
+ midPointAgrees(reporter, quad1, quad2, !ccw);
+ SkDQuad q1 = quad1;
+ SkDQuad q2 = quad2;
+ double loFail = 1;
+ double hiPass = 2;
+ // double vectors until t passes
+ do {
+ q1[1].fX = quad1[0].fX * (1 - hiPass) + quad1[1].fX * hiPass;
+ q1[1].fY = quad1[0].fY * (1 - hiPass) + quad1[1].fY * hiPass;
+ q2[1].fX = quad2[0].fX * (1 - hiPass) + quad2[1].fX * hiPass;
+ q2[1].fY = quad2[0].fY * (1 - hiPass) + quad2[1].fY * hiPass;
+ agrees = bruteForceCheck(reporter, q1, q2, ccw);
+ maxR = SkTMin(maxR, mDistance(reporter, agrees, q1, q2));
+ if (agrees) {
+ break;
+ }
+ midPointAgrees(reporter, quad1, quad2, !ccw);
+ loFail = hiPass;
+ hiPass *= 2;
+ } while (true);
+ // binary search to find minimum pass
+ double midTest = (loFail + hiPass) / 2;
+ double step = (hiPass - loFail) / 4;
+ while (step > FLT_EPSILON) {
+ q1[1].fX = quad1[0].fX * (1 - midTest) + quad1[1].fX * midTest;
+ q1[1].fY = quad1[0].fY * (1 - midTest) + quad1[1].fY * midTest;
+ q2[1].fX = quad2[0].fX * (1 - midTest) + quad2[1].fX * midTest;
+ q2[1].fY = quad2[0].fY * (1 - midTest) + quad2[1].fY * midTest;
+ agrees = bruteForceCheck(reporter, q1, q2, ccw);
+ maxR = SkTMin(maxR, mDistance(reporter, agrees, q1, q2));
+ if (!agrees) {
+ midPointAgrees(reporter, quad1, quad2, !ccw);
+ }
+ midTest += agrees ? -step : step;
+ step /= 2;
+ }
+#ifdef SK_DEBUG
+// DumpQ(q1, q2, 999);
+#endif
+ }
+ if (gPathOpsAngleIdeasVerbose) {
+ SkDebugf("maxR=%1.9g\n", maxR);
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsAngleTest.cpp b/src/third_party/skia/tests/PathOpsAngleTest.cpp
new file mode 100644
index 0000000..faf6158
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsAngleTest.cpp
@@ -0,0 +1,485 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkIntersections.h"
+#include "SkOpSegment.h"
+#include "SkPathOpsTriangle.h"
+#include "SkRandom.h"
+#include "SkTArray.h"
+#include "SkTSort.h"
+#include "Test.h"
+
+static bool gDisableAngleTests = true;
+
+static float next(float f)
+{
+ int fBits = SkFloatAs2sCompliment(f);
+ ++fBits;
+ float fNext = Sk2sComplimentAsFloat(fBits);
+ return fNext;
+}
+
+static float prev(float f)
+{
+ int fBits = SkFloatAs2sCompliment(f);
+ --fBits;
+ float fNext = Sk2sComplimentAsFloat(fBits);
+ return fNext;
+}
+
+DEF_TEST(PathOpsAngleFindCrossEpsilon, reporter) {
+ if (gDisableAngleTests) {
+ return;
+ }
+ SkRandom ran;
+ int maxEpsilon = 0;
+ for (int index = 0; index < 10000000; ++index) {
+ SkDLine line = {{{0, 0}, {ran.nextRangeF(0.0001f, 1000), ran.nextRangeF(0.0001f, 1000)}}};
+ for (int inner = 0; inner < 10; ++inner) {
+ float t = ran.nextRangeF(0.0001f, 1);
+ SkDPoint dPt = line.ptAtT(t);
+ SkPoint pt = dPt.asSkPoint();
+ float xs[3] = { prev(pt.fX), pt.fX, next(pt.fX) };
+ float ys[3] = { prev(pt.fY), pt.fY, next(pt.fY) };
+ for (int xIdx = 0; xIdx < 3; ++xIdx) {
+ for (int yIdx = 0; yIdx < 3; ++yIdx) {
+ SkPoint test = { xs[xIdx], ys[yIdx] };
+ float p1 = SkDoubleToScalar(line[1].fX * test.fY);
+ float p2 = SkDoubleToScalar(line[1].fY * test.fX);
+ int p1Bits = SkFloatAs2sCompliment(p1);
+ int p2Bits = SkFloatAs2sCompliment(p2);
+ int epsilon = abs(p1Bits - p2Bits);
+ if (maxEpsilon < epsilon) {
+ SkDebugf("line={{0, 0}, {%1.7g, %1.7g}} t=%1.7g pt={%1.7g, %1.7g}"
+ " epsilon=%d\n",
+ line[1].fX, line[1].fY, t, test.fX, test.fY, epsilon);
+ maxEpsilon = epsilon;
+ }
+ }
+ }
+ }
+ }
+}
+
+DEF_TEST(PathOpsAngleFindQuadEpsilon, reporter) {
+ if (gDisableAngleTests) {
+ return;
+ }
+ SkRandom ran;
+ int maxEpsilon = 0;
+ double maxAngle = 0;
+ for (int index = 0; index < 100000; ++index) {
+ SkDLine line = {{{0, 0}, {ran.nextRangeF(0.0001f, 1000), ran.nextRangeF(0.0001f, 1000)}}};
+ float t = ran.nextRangeF(0.0001f, 1);
+ SkDPoint dPt = line.ptAtT(t);
+ float t2 = ran.nextRangeF(0.0001f, 1);
+ SkDPoint qPt = line.ptAtT(t2);
+ float t3 = ran.nextRangeF(0.0001f, 1);
+ SkDPoint qPt2 = line.ptAtT(t3);
+ qPt.fX += qPt2.fY;
+ qPt.fY -= qPt2.fX;
+ SkDQuad quad = {{line[0], dPt, qPt}};
+ // binary search for maximum movement of quad[1] towards test that still has 1 intersection
+ double moveT = 0.5f;
+ double deltaT = moveT / 2;
+ SkDPoint last;
+ do {
+ last = quad[1];
+ quad[1].fX = dPt.fX - line[1].fY * moveT;
+ quad[1].fY = dPt.fY + line[1].fX * moveT;
+ SkIntersections i;
+ i.intersect(quad, line);
+ REPORTER_ASSERT(reporter, i.used() > 0);
+ if (i.used() == 1) {
+ moveT += deltaT;
+ } else {
+ moveT -= deltaT;
+ }
+ deltaT /= 2;
+ } while (last.asSkPoint() != quad[1].asSkPoint());
+ float p1 = SkDoubleToScalar(line[1].fX * last.fY);
+ float p2 = SkDoubleToScalar(line[1].fY * last.fX);
+ int p1Bits = SkFloatAs2sCompliment(p1);
+ int p2Bits = SkFloatAs2sCompliment(p2);
+ int epsilon = abs(p1Bits - p2Bits);
+ if (maxEpsilon < epsilon) {
+ SkDebugf("line={{0, 0}, {%1.7g, %1.7g}} t=%1.7g/%1.7g/%1.7g moveT=%1.7g"
+ " pt={%1.7g, %1.7g} epsilon=%d\n",
+ line[1].fX, line[1].fY, t, t2, t3, moveT, last.fX, last.fY, epsilon);
+ maxEpsilon = epsilon;
+ }
+ double a1 = atan2(line[1].fY, line[1].fX);
+ double a2 = atan2(last.fY, last.fX);
+ double angle = fabs(a1 - a2);
+ if (maxAngle < angle) {
+ SkDebugf("line={{0, 0}, {%1.7g, %1.7g}} t=%1.7g/%1.7g/%1.7g moveT=%1.7g"
+ " pt={%1.7g, %1.7g} angle=%1.7g\n",
+ line[1].fX, line[1].fY, t, t2, t3, moveT, last.fX, last.fY, angle);
+ maxAngle = angle;
+ }
+ }
+}
+
+static int find_slop(double x, double y, double rx, double ry) {
+ int slopBits = 0;
+ bool less1, less2;
+ double absX = fabs(x);
+ double absY = fabs(y);
+ double length = absX < absY ? absX / 2 + absY : absX + absY / 2;
+ int exponent;
+ (void) frexp(length, &exponent);
+ double epsilon = ldexp(FLT_EPSILON, exponent);
+ do {
+ // get the length as the larger plus half the smaller (both same signs)
+ // find the ulps of the length
+ // compute the offsets from there
+ double xSlop = epsilon * slopBits;
+ double ySlop = x * y < 0 ? -xSlop : xSlop; // OPTIMIZATION: use copysign / _copysign ?
+ double x1 = x - xSlop;
+ double y1 = y + ySlop;
+ double x_ry1 = x1 * ry;
+ double rx_y1 = rx * y1;
+ less1 = x_ry1 < rx_y1;
+ double x2 = x + xSlop;
+ double y2 = y - ySlop;
+ double x_ry2 = x2 * ry;
+ double rx_y2 = rx * y2;
+ less2 = x_ry2 < rx_y2;
+ } while (less1 == less2 && ++slopBits);
+ return slopBits;
+}
+
+// from http://stackoverflow.com/questions/1427422/cheap-algorithm-to-find-measure-of-angle-between-vectors
+static double diamond_angle(double y, double x)
+{
+ if (y >= 0)
+ return (x >= 0 ? y/(x+y) : 1-x/(-x+y));
+ else
+ return (x < 0 ? 2-y/(-x-y) : 3+x/(x-y));
+}
+
+static const double slopTests[][4] = {
+ // x y rx ry
+ {-0.058554756452593892, -0.18804585843827226, -0.018568569646021160, -0.059615294434479438},
+ {-0.0013717412948608398, 0.0041152238845825195, -0.00045837944195925573, 0.0013753175735478074},
+ {-2.1033774145221198, -1.4046019261273715e-008, -0.70062688352066704, -1.2706324683777995e-008},
+};
+
+DEF_TEST(PathOpsAngleFindSlop, reporter) {
+ if (gDisableAngleTests) {
+ return;
+ }
+ for (int index = 0; index < (int) SK_ARRAY_COUNT(slopTests); ++index) {
+ const double* slopTest = slopTests[index];
+ double x = slopTest[0];
+ double y = slopTest[1];
+ double rx = slopTest[2];
+ double ry = slopTest[3];
+ SkDebugf("%s xy %d=%d\n", __FUNCTION__, index, find_slop(x, y, rx, ry));
+ SkDebugf("%s rxy %d=%d\n", __FUNCTION__, index, find_slop(rx, ry, x, y));
+ double angle = diamond_angle(y, x);
+ double rAngle = diamond_angle(ry, rx);
+ double diff = fabs(angle - rAngle);
+ SkDebugf("%s diamond xy=%1.9g rxy=%1.9g diff=%1.9g factor=%d\n", __FUNCTION__,
+ angle, rAngle, diff, (int) (diff / FLT_EPSILON));
+ }
+}
+
+class PathOpsAngleTester {
+public:
+ static int After(const SkOpAngle& lh, const SkOpAngle& rh) {
+ return lh.after(&rh);
+ }
+
+ static int ConvexHullOverlaps(const SkOpAngle& lh, const SkOpAngle& rh) {
+ return lh.convexHullOverlaps(rh);
+ }
+
+ static int Orderable(const SkOpAngle& lh, const SkOpAngle& rh) {
+ return lh.orderable(rh);
+ }
+
+ static int EndsIntersect(const SkOpAngle& lh, const SkOpAngle& rh) {
+ return lh.endsIntersect(rh);
+ }
+
+ static void SetNext(SkOpAngle& lh, SkOpAngle& rh) {
+ lh.fNext = &rh;
+ }
+};
+
+class PathOpsSegmentTester {
+public:
+ static void ConstructCubic(SkOpSegment* segment, SkPoint shortCubic[4]) {
+ segment->debugConstructCubic(shortCubic);
+ }
+
+ static void ConstructLine(SkOpSegment* segment, SkPoint shortLine[2]) {
+ segment->debugConstructLine(shortLine);
+ }
+
+ static void ConstructQuad(SkOpSegment* segment, SkPoint shortQuad[3]) {
+ segment->debugConstructQuad(shortQuad);
+ }
+
+ static void DebugReset(SkOpSegment* segment) {
+ segment->debugReset();
+ }
+};
+
+struct CircleData {
+ const SkDCubic fPts;
+ const int fPtCount;
+ SkPoint fShortPts[4];
+};
+
+static CircleData circleDataSet[] = {
+ { {{{313.0155029296875, 207.90290832519531}, {320.05078125, 227.58743286132812}}}, 2, {} },
+ { {{{313.0155029296875, 207.90290832519531}, {313.98246891063195, 219.33615203830394},
+ {320.05078125, 227.58743286132812}}}, 3, {} },
+};
+
+static const int circleDataSetSize = (int) SK_ARRAY_COUNT(circleDataSet);
+
+DEF_TEST(PathOpsAngleCircle, reporter) {
+ SkOpSegment segment[2];
+ for (int index = 0; index < circleDataSetSize; ++index) {
+ CircleData& data = circleDataSet[index];
+ for (int idx2 = 0; idx2 < data.fPtCount; ++idx2) {
+ data.fShortPts[idx2] = data.fPts.fPts[idx2].asSkPoint();
+ }
+ switch (data.fPtCount) {
+ case 2:
+ PathOpsSegmentTester::ConstructLine(&segment[index], data.fShortPts);
+ break;
+ case 3:
+ PathOpsSegmentTester::ConstructQuad(&segment[index], data.fShortPts);
+ break;
+ case 4:
+ PathOpsSegmentTester::ConstructCubic(&segment[index], data.fShortPts);
+ break;
+ }
+ }
+ PathOpsAngleTester::Orderable(*segment[0].debugLastAngle(), *segment[1].debugLastAngle());
+}
+
+struct IntersectData {
+ const SkDCubic fPts;
+ const int fPtCount;
+ double fTStart;
+ double fTEnd;
+ SkPoint fShortPts[4];
+};
+
+static IntersectData intersectDataSet1[] = {
+ { {{{322.935669,231.030273}, {312.832214,220.393295}, {312.832214,203.454178}}}, 3,
+ 0.865309956, 0.154740299, {} },
+ { {{{322.12738,233.397751}, {295.718353,159.505829}}}, 2,
+ 0.345028807, 0.0786326511, {} },
+ { {{{322.935669,231.030273}, {312.832214,220.393295}, {312.832214,203.454178}}}, 3,
+ 0.865309956, 1, {} },
+ { {{{322.12738,233.397751}, {295.718353,159.505829}}}, 2,
+ 0.345028807, 1, {} },
+};
+
+static IntersectData intersectDataSet2[] = {
+ { {{{364.390686,157.898193}, {375.281769,136.674606}, {396.039917,136.674606}}}, 3,
+ 0.578520747, 1, {} },
+ { {{{364.390686,157.898193}, {375.281769,136.674606}, {396.039917,136.674606}}}, 3,
+ 0.578520747, 0.536512973, {} },
+ { {{{366.608826,151.196014}, {378.803101,136.674606}, {398.164948,136.674606}}}, 3,
+ 0.490456543, 1, {} },
+};
+
+static IntersectData intersectDataSet3[] = {
+ { {{{2.000000,0.000000}, {1.33333333,0.66666667}}}, 2, 1, 0, {} },
+ { {{{1.33333333,0.66666667}, {0.000000,2.000000}}}, 2, 0, 0.25, {} },
+ { {{{2.000000,2.000000}, {1.33333333,0.66666667}}}, 2, 1, 0, {} },
+};
+
+static IntersectData intersectDataSet4[] = {
+ { {{{1.3333333,0.6666667}, {0.000,2.000}}}, 2, 0.250000006, 0, {} },
+ { {{{1.000,0.000}, {1.000,1.000}}}, 2, 1, 0, {} },
+ { {{{1.000,1.000}, {0.000,0.000}}}, 2, 0, 1, {} },
+};
+
+static IntersectData intersectDataSet5[] = {
+ { {{{0.000,0.000}, {1.000,0.000}, {1.000,1.000}}}, 3, 1, 0.666666667, {} },
+ { {{{0.000,0.000}, {2.000,1.000}, {0.000,2.000}}}, 3, 0.5, 1, {} },
+ { {{{0.000,0.000}, {2.000,1.000}, {0.000,2.000}}}, 3, 0.5, 0, {} },
+};
+
+static IntersectData intersectDataSet6[] = { // pathops_visualizer.htm:3658
+ { {{{0.000,1.000}, {3.000,4.000}, {1.000,0.000}, {3.000,0.000}}}, 4, 0.0925339054, 0, {} }, // pathops_visualizer.htm:3616
+ { {{{0.000,1.000}, {0.000,3.000}, {1.000,0.000}, {4.000,3.000}}}, 4, 0.453872386, 0, {} }, // pathops_visualizer.htm:3616
+ { {{{0.000,1.000}, {3.000,4.000}, {1.000,0.000}, {3.000,0.000}}}, 4, 0.0925339054, 0.417096368, {} }, // pathops_visualizer.htm:3616
+};
+
+static IntersectData intersectDataSet7[] = { // pathops_visualizer.htm:3748
+ { {{{2.000,1.000}, {0.000,1.000}}}, 2, 0.5, 0, {} }, // pathops_visualizer.htm:3706
+ { {{{2.000,0.000}, {0.000,2.000}}}, 2, 0.5, 1, {} }, // pathops_visualizer.htm:3706
+ { {{{0.000,1.000}, {0.000,2.000}, {2.000,0.000}, {2.000,1.000}}}, 4, 0.5, 1, {} }, // pathops_visualizer.htm:3706
+}; //
+
+static IntersectData intersectDataSet8[] = { // pathops_visualizer.htm:4194
+ { {{{0.000,1.000}, {2.000,3.000}, {5.000,1.000}, {4.000,3.000}}}, 4, 0.311007457, 0.285714286, {} }, // pathops_visualizer.htm:4152
+ { {{{1.000,5.000}, {3.000,4.000}, {1.000,0.000}, {3.000,2.000}}}, 4, 0.589885081, 0.999982974, {} }, // pathops_visualizer.htm:4152
+ { {{{1.000,5.000}, {3.000,4.000}, {1.000,0.000}, {3.000,2.000}}}, 4, 0.589885081, 0.576935809, {} }, // pathops_visualizer.htm:4152
+}; //
+
+static IntersectData intersectDataSet9[] = { // pathops_visualizer.htm:4142
+ { {{{0.000,1.000}, {2.000,3.000}, {5.000,1.000}, {4.000,3.000}}}, 4, 0.476627072, 0.311007457, {} }, // pathops_visualizer.htm:4100
+ { {{{1.000,5.000}, {3.000,4.000}, {1.000,0.000}, {3.000,2.000}}}, 4, 0.999982974, 1, {} }, // pathops_visualizer.htm:4100
+ { {{{0.000,1.000}, {2.000,3.000}, {5.000,1.000}, {4.000,3.000}}}, 4, 0.476627072, 1, {} }, // pathops_visualizer.htm:4100
+}; //
+
+static IntersectData intersectDataSet10[] = { // pathops_visualizer.htm:4186
+ { {{{0.000,1.000}, {1.000,6.000}, {1.000,0.000}, {1.000,0.000}}}, 4, 0.788195121, 0.726275769, {} }, // pathops_visualizer.htm:4144
+ { {{{0.000,1.000}, {0.000,1.000}, {1.000,0.000}, {6.000,1.000}}}, 4, 0.473378977, 1, {} }, // pathops_visualizer.htm:4144
+ { {{{0.000,1.000}, {1.000,6.000}, {1.000,0.000}, {1.000,0.000}}}, 4, 0.788195121, 1, {} }, // pathops_visualizer.htm:4144
+}; //
+
+static IntersectData intersectDataSet11[] = { // pathops_visualizer.htm:4704
+ { {{{979.305,561.000}, {1036.695,291.000}}}, 2, 0.888888874, 0.11111108, {} }, // pathops_visualizer.htm:4662
+ { {{{1006.695,291.000}, {1023.264,291.000}, {1033.840,304.431}, {1030.318,321.000}}}, 4, 1, 0, {} }, // pathops_visualizer.htm:4662
+ { {{{979.305,561.000}, {1036.695,291.000}}}, 2, 0.888888874, 1, {} }, // pathops_visualizer.htm:4662
+}; //
+
+static IntersectData intersectDataSet12[] = { // pathops_visualizer.htm:5481
+ { {{{67.000,912.000}, {67.000,913.000}}}, 2, 1, 0, {} }, // pathops_visualizer.htm:5439
+ { {{{67.000,913.000}, {67.000,917.389}, {67.224,921.726}, {67.662,926.000}}}, 4, 0, 1, {} }, // pathops_visualizer.htm:5439
+ { {{{194.000,1041.000}, {123.860,1041.000}, {67.000,983.692}, {67.000,913.000}}}, 4, 1, 0, {} }, // pathops_visualizer.htm:5439
+}; //
+
+static IntersectData intersectDataSet13[] = { // pathops_visualizer.htm:5735
+ { {{{6.000,0.000}, {0.000,4.000}}}, 2, 0.625, 0.25, {} }, // pathops_visualizer.htm:5693
+ { {{{0.000,1.000}, {0.000,6.000}, {4.000,0.000}, {6.000,1.000}}}, 4, 0.5, 0.833333333, {} }, // pathops_visualizer.htm:5693
+ { {{{0.000,1.000}, {0.000,6.000}, {4.000,0.000}, {6.000,1.000}}}, 4, 0.5, 0.379043969, {} }, // pathops_visualizer.htm:5693
+}; //
+
+static IntersectData intersectDataSet14[] = { // pathops_visualizer.htm:5875
+ { {{{0.000,1.000}, {4.000,6.000}, {2.000,1.000}, {2.000,0.000}}}, 4, 0.0756502183, 0.0594570973, {} }, // pathops_visualizer.htm:5833
+ { {{{1.000,2.000}, {0.000,2.000}, {1.000,0.000}, {6.000,4.000}}}, 4, 0.0756502184, 0, {} }, // pathops_visualizer.htm:5833
+ { {{{0.000,1.000}, {4.000,6.000}, {2.000,1.000}, {2.000,0.000}}}, 4, 0.0756502183, 0.531917258, {} }, // pathops_visualizer.htm:5833
+}; //
+
+static IntersectData intersectDataSet15[] = { // pathops_visualizer.htm:6580
+ { {{{490.435,879.407}, {405.593,909.436}}}, 2, 0.500554405, 1, {} }, // pathops_visualizer.htm:6538
+ { {{{447.967,894.438}, {448.007,894.424}, {448.014,894.422}}}, 3, 0, 1, {} }, // pathops_visualizer.htm:6538
+ { {{{490.435,879.407}, {405.593,909.436}}}, 2, 0.500554405, 0.500000273, {} }, // pathops_visualizer.htm:6538
+}; //
+
+static IntersectData intersectDataSet16[] = { // pathops_visualizer.htm:7419
+ { {{{1.000,4.000}, {4.000,5.000}, {3.000,2.000}, {6.000,3.000}}}, 4, 0.5, 0, {} }, // pathops_visualizer.htm:7377
+ { {{{2.000,3.000}, {3.000,6.000}, {4.000,1.000}, {5.000,4.000}}}, 4, 0.5, 0.112701665, {} }, // pathops_visualizer.htm:7377
+ { {{{5.000,4.000}, {2.000,3.000}}}, 2, 0.5, 0, {} }, // pathops_visualizer.htm:7377
+}; //
+
+#define I(x) intersectDataSet##x
+
+static IntersectData* intersectDataSets[] = {
+ I(1), I(2), I(3), I(4), I(5), I(6), I(7), I(8), I(9), I(10),
+ I(11), I(12), I(13), I(14), I(15), I(16),
+};
+
+#undef I
+#define I(x) (int) SK_ARRAY_COUNT(intersectDataSet##x)
+
+static const int intersectDataSetSizes[] = {
+ I(1), I(2), I(3), I(4), I(5), I(6), I(7), I(8), I(9), I(10),
+ I(11), I(12), I(13), I(14), I(15), I(16),
+};
+
+#undef I
+
+static const int intersectDataSetsSize = (int) SK_ARRAY_COUNT(intersectDataSetSizes);
+
+DEF_TEST(PathOpsAngleAfter, reporter) {
+ for (int index = intersectDataSetsSize - 1; index >= 0; --index) {
+ IntersectData* dataArray = intersectDataSets[index];
+ const int dataSize = intersectDataSetSizes[index];
+ SkOpSegment segment[3];
+ for (int index2 = 0; index2 < dataSize - 2; ++index2) {
+ for (int temp = 0; temp < (int) SK_ARRAY_COUNT(segment); ++temp) {
+ PathOpsSegmentTester::DebugReset(&segment[temp]);
+ }
+ for (int index3 = 0; index3 < (int) SK_ARRAY_COUNT(segment); ++index3) {
+ IntersectData& data = dataArray[index2 + index3];
+ SkPoint temp[4];
+ for (int idx2 = 0; idx2 < data.fPtCount; ++idx2) {
+ temp[idx2] = data.fPts.fPts[idx2].asSkPoint();
+ }
+ switch (data.fPtCount) {
+ case 2: {
+ SkDLine seg = SkDLine::SubDivide(temp, data.fTStart,
+ data.fTStart < data.fTEnd ? 1 : 0);
+ data.fShortPts[0] = seg[0].asSkPoint();
+ data.fShortPts[1] = seg[1].asSkPoint();
+ PathOpsSegmentTester::ConstructLine(&segment[index3], data.fShortPts);
+ } break;
+ case 3: {
+ SkDQuad seg = SkDQuad::SubDivide(temp, data.fTStart, data.fTEnd);
+ data.fShortPts[0] = seg[0].asSkPoint();
+ data.fShortPts[1] = seg[1].asSkPoint();
+ data.fShortPts[2] = seg[2].asSkPoint();
+ PathOpsSegmentTester::ConstructQuad(&segment[index3], data.fShortPts);
+ } break;
+ case 4: {
+ SkDCubic seg = SkDCubic::SubDivide(temp, data.fTStart, data.fTEnd);
+ data.fShortPts[0] = seg[0].asSkPoint();
+ data.fShortPts[1] = seg[1].asSkPoint();
+ data.fShortPts[2] = seg[2].asSkPoint();
+ data.fShortPts[3] = seg[3].asSkPoint();
+ PathOpsSegmentTester::ConstructCubic(&segment[index3], data.fShortPts);
+ } break;
+ }
+ }
+ SkOpAngle& angle1 = *const_cast<SkOpAngle*>(segment[0].debugLastAngle());
+ SkOpAngle& angle2 = *const_cast<SkOpAngle*>(segment[1].debugLastAngle());
+ SkOpAngle& angle3 = *const_cast<SkOpAngle*>(segment[2].debugLastAngle());
+ PathOpsAngleTester::SetNext(angle1, angle3);
+ // These data sets are seeded when the set itself fails, so likely the dataset does not
+ // match the expected result. The tests above return 1 when first added, but
+ // return 0 after the bug is fixed.
+ SkDEBUGCODE(int result =) PathOpsAngleTester::After(angle2, angle1);
+ SkASSERT(result == 0 || result == 1);
+ }
+ }
+}
+
+void SkOpSegment::debugConstruct() {
+ addStartSpan(1);
+ addEndSpan(1);
+ debugAddAngle(0, 1);
+}
+
+void SkOpSegment::debugAddAngle(int start, int end) {
+ SkASSERT(start != end);
+ SkOpAngle& angle = fAngles.push_back();
+ angle.set(this, start, end);
+}
+
+void SkOpSegment::debugConstructCubic(SkPoint shortQuad[4]) {
+ addCubic(shortQuad, false, false);
+ addT(NULL, shortQuad[0], 0);
+ addT(NULL, shortQuad[3], 1);
+ debugConstruct();
+}
+
+void SkOpSegment::debugConstructLine(SkPoint shortQuad[2]) {
+ addLine(shortQuad, false, false);
+ addT(NULL, shortQuad[0], 0);
+ addT(NULL, shortQuad[1], 1);
+ debugConstruct();
+}
+
+void SkOpSegment::debugConstructQuad(SkPoint shortQuad[3]) {
+ addQuad(shortQuad, false, false);
+ addT(NULL, shortQuad[0], 0);
+ addT(NULL, shortQuad[2], 1);
+ debugConstruct();
+}
diff --git a/src/third_party/skia/tests/PathOpsBattles.cpp b/src/third_party/skia/tests/PathOpsBattles.cpp
new file mode 100644
index 0000000..15fffd5
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsBattles.cpp
@@ -0,0 +1,11183 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsTestCommon.h"
+
+#define TEST(name) { name, #name }
+
+static void issue414409(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1, path2;
+
+ // one fill 1
+ path1.moveTo(9.53595e-07f, -60);
+ path1.lineTo(5.08228e-15f, -83);
+ path1.cubicTo(32.8673f, -83, 62.6386f, -63.6055f, 75.9208f, -33.5416f);
+ path1.cubicTo(89.2029f, -3.47759f, 83.4937f, 31.5921f, 61.3615f, 55.8907f);
+ path1.lineTo(46.9383f, 68.4529f);
+ path1.lineTo(33.9313f, 49.484f);
+ path1.cubicTo(37.7451f, 46.8689f, 41.2438f, 43.8216f, 44.3577f, 40.4029f);
+ path1.lineTo(44.3577f, 40.4029f);
+ path1.cubicTo(60.3569f, 22.8376f, 64.4841f, -2.51392f, 54.8825f, -24.2469f);
+ path1.cubicTo(45.2809f, -45.9799f, 23.7595f, -60, 9.53595e-07f, -60);
+ path1.close();
+
+ // two fill 0
+ path2.moveTo(46.9383f, 68.4529f);
+ path2.cubicTo(17.5117f, 88.6307f, -21.518f, 87.7442f, -49.9981f, 66.251f);
+ path2.cubicTo(-78.4781f, 44.7578f, -90.035f, 7.46781f, -78.7014f, -26.3644f);
+ path2.cubicTo(-67.3679f, -60.1967f, -35.6801f, -83, -1.48383e-06f, -83);
+ path2.lineTo(4.22689e-14f, -60);
+ path2.cubicTo(-25.7929f, -60, -48.6997f, -43.5157f, -56.8926f, -19.0586f);
+ path2.cubicTo(-65.0855f, 5.39842f, -56.7312f, 32.355f, -36.1432f, 47.8923f);
+ path2.cubicTo(-15.5552f, 63.4296f, 12.6591f, 64.0704f, 33.9313f, 49.484f);
+ path2.lineTo(46.9383f, 68.4529f);
+ path2.close();
+ testPathOp(reporter, path1, path2, kUnion_PathOp, filename);
+}
+
+static void issue414409b(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1, path2;
+ // one fill=0 op=2
+path1.setFillType((SkPath::FillType) 0);
+path1.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path1.cubicTo(SkBits2Float(0x41f12edc), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4267b362), SkBits2Float(0xc2854e1f), SkBits2Float(0x42911faa), SkBits2Float(0xc2212f3b));
+path1.cubicTo(SkBits2Float(0x42ae65a2), SkBits2Float(0xc15f08de), SkBits2Float(0x42acc913), SkBits2Float(0x41923f59), SkBits2Float(0x428ce9f0), SkBits2Float(0x422f7dc4));
+path1.lineTo(SkBits2Float(0x424bbb16), SkBits2Float(0x41fdb8ed));
+path1.cubicTo(SkBits2Float(0x4279cf6e), SkBits2Float(0x41537137), SkBits2Float(0x427c23ea), SkBits2Float(0xc1213ad2), SkBits2Float(0x4251d142), SkBits2Float(0xc1e909ae));
+path1.cubicTo(SkBits2Float(0x42277e9a), SkBits2Float(0xc240baf8), SkBits2Float(0x41ae5968), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path1.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path1.close();
+
+path2.setFillType((SkPath::FillType) 1);
+path2.moveTo(SkBits2Float(0x428ce9ef), SkBits2Float(0x422f7dc6));
+path2.cubicTo(SkBits2Float(0x4286af43), SkBits2Float(0x42437fa7), SkBits2Float(0x427ed0d6), SkBits2Float(0x42561f5a), SkBits2Float(0x426e69d2), SkBits2Float(0x42670c39));
+path2.lineTo(SkBits2Float(0x422c58d6), SkBits2Float(0x422705c1));
+path2.cubicTo(SkBits2Float(0x42383446), SkBits2Float(0x421ac98f), SkBits2Float(0x4242b98a), SkBits2Float(0x420d5308), SkBits2Float(0x424bbb17), SkBits2Float(0x41fdb8ee));
+path2.lineTo(SkBits2Float(0x428ce9ef), SkBits2Float(0x422f7dc6));
+path2.close();
+// SkOpSegment.cpp:3488: failed assertion "other->fTs[min].fWindSum == oppWinding"
+ testPathOp(reporter, path1, path2, kUnion_PathOp, filename);
+}
+
+static void issue414409c(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1, path2;
+path1.setFillType((SkPath::FillType) 1);
+path1.moveTo(SkBits2Float(0x36961ef0), SkBits2Float(0xc2700000));
+path1.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path1.cubicTo(SkBits2Float(0x3df86648), SkBits2Float(0xc2a60000), SkBits2Float(0x3e786777), SkBits2Float(0xc2a5ffdc), SkBits2Float(0x3eba4dc2), SkBits2Float(0xc2a5ff96));
+path1.lineTo(SkBits2Float(0x3eba4dc3), SkBits2Float(0xc2a5ff97));
+path1.cubicTo(SkBits2Float(0x3ec08370), SkBits2Float(0xc2a5ff8f), SkBits2Float(0x3ec6b964), SkBits2Float(0xc2a5ff88), SkBits2Float(0x3eccef58), SkBits2Float(0xc2a5ff80));
+path1.lineTo(SkBits2Float(0x3e942522), SkBits2Float(0xc26fff49));
+path1.cubicTo(SkBits2Float(0x3e8fa7da), SkBits2Float(0xc26fff56), SkBits2Float(0x3e8b2acd), SkBits2Float(0xc26fff61), SkBits2Float(0x3e86adc0), SkBits2Float(0xc26fff6b));
+path1.lineTo(SkBits2Float(0x3e86ad6a), SkBits2Float(0xc26fff69));
+path1.cubicTo(SkBits2Float(0x3e3391e9), SkBits2Float(0xc26fffce), SkBits2Float(0x3db3931e), SkBits2Float(0xc2700000), SkBits2Float(0x36961ef0), SkBits2Float(0xc2700000));
+path1.close();
+
+path2.setFillType((SkPath::FillType) 0);
+path2.moveTo(SkBits2Float(0x3eccef1a), SkBits2Float(0xc2a5ff81));
+path2.cubicTo(SkBits2Float(0x3f18c8a9), SkBits2Float(0xc2a5ff04), SkBits2Float(0x3f4b19b0), SkBits2Float(0xc2a5fe2d), SkBits2Float(0x3f7d6a37), SkBits2Float(0xc2a5fcfa));
+path2.lineTo(SkBits2Float(0x3f3730f2), SkBits2Float(0xc26ffba1));
+path2.cubicTo(SkBits2Float(0x3f12d1c8), SkBits2Float(0xc26ffd5d), SkBits2Float(0x3edce4b4), SkBits2Float(0xc26ffe95), SkBits2Float(0x3e942577), SkBits2Float(0xc26fff49));
+path2.lineTo(SkBits2Float(0x3eccef1a), SkBits2Float(0xc2a5ff81));
+path2.close();
+
+testPathOp(reporter, path1, path2, kUnion_PathOp, filename);
+}
+
+// fails to draw correctly
+static void battleOp1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ea4d9f5), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f24d9a9), SkBits2Float(0xc2a5ff0a), SkBits2Float(0x3f774519), SkBits2Float(0xc2a5fd1f));
+path.lineTo(SkBits2Float(0x3f32bfc3), SkBits2Float(0xc26ffbd7));
+path.cubicTo(SkBits2Float(0x3eee5669), SkBits2Float(0xc26ffe9e), SkBits2Float(0x3e6e56cc), SkBits2Float(0xc2700000), SkBits2Float(0x357ffb40), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f774503), SkBits2Float(0xc2a5fd1f));
+path.cubicTo(SkBits2Float(0x3f7f82ff), SkBits2Float(0xc2a5fcee), SkBits2Float(0x3f83e06d), SkBits2Float(0xc2a5fcbb), SkBits2Float(0x3f87ff59), SkBits2Float(0xc2a5fc85));
+path.lineTo(SkBits2Float(0x3f449f80), SkBits2Float(0xc26ffaf7));
+path.cubicTo(SkBits2Float(0x3f3eaa52), SkBits2Float(0xc26ffb47), SkBits2Float(0x3f38b4f5), SkBits2Float(0xc26ffb92), SkBits2Float(0x3f32bf98), SkBits2Float(0xc26ffbd9));
+path.lineTo(SkBits2Float(0x3f774503), SkBits2Float(0xc2a5fd1f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ea4d9e6), SkBits2Float(0xc2a60000), SkBits2Float(0x3f24d99a), SkBits2Float(0xc2a5ff0a), SkBits2Float(0x3f774503), SkBits2Float(0xc2a5fd1f));
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f87ff64), SkBits2Float(0xc2a5fc85));
+path.cubicTo(SkBits2Float(0x3fcac720), SkBits2Float(0xc2a5f91a), SkBits2Float(0x4006c62a), SkBits2Float(0xc2a5f329), SkBits2Float(0x40282667), SkBits2Float(0xc2a5eab4));
+path.lineTo(SkBits2Float(0x3ff31bb9), SkBits2Float(0xc26fe136));
+path.cubicTo(SkBits2Float(0x3fc2da88), SkBits2Float(0xc26fed71), SkBits2Float(0x3f9295ff), SkBits2Float(0xc26ff607), SkBits2Float(0x3f449f66), SkBits2Float(0xc26ffaf9));
+path.lineTo(SkBits2Float(0x3f87ff64), SkBits2Float(0xc2a5fc85));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f19f03c), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f99ef95), SkBits2Float(0xc2a5fca7), SkBits2Float(0x3fe6e2fa), SkBits2Float(0xc2a5f5f7));
+path.lineTo(SkBits2Float(0x3fa6e80c), SkBits2Float(0xc26ff17d));
+path.cubicTo(SkBits2Float(0x3f5e8ed4), SkBits2Float(0xc26ffb2a), SkBits2Float(0x3ede8fc6), SkBits2Float(0xc2700000), SkBits2Float(0x35d9fd64), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3fe6e322), SkBits2Float(0xc2a5f5f7));
+path.cubicTo(SkBits2Float(0x3fee94fb), SkBits2Float(0xc2a5f54c), SkBits2Float(0x3ff646db), SkBits2Float(0xc2a5f497), SkBits2Float(0x3ffdf8ad), SkBits2Float(0xc2a5f3db));
+path.lineTo(SkBits2Float(0x3fb79813), SkBits2Float(0xc26fee71));
+path.cubicTo(SkBits2Float(0x3fb20800), SkBits2Float(0xc26fef82), SkBits2Float(0x3fac77ff), SkBits2Float(0xc26ff085), SkBits2Float(0x3fa6e7f4), SkBits2Float(0xc26ff17d));
+path.lineTo(SkBits2Float(0x3fe6e322), SkBits2Float(0xc2a5f5f7));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f19f03c), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f99ef95), SkBits2Float(0xc2a5fca7), SkBits2Float(0x3fe6e322), SkBits2Float(0xc2a5f5f7));
+path.cubicTo(SkBits2Float(0x3fee94fb), SkBits2Float(0xc2a5f54c), SkBits2Float(0x3ff646db), SkBits2Float(0xc2a5f497), SkBits2Float(0x3ffdf8ad), SkBits2Float(0xc2a5f3db));
+path.lineTo(SkBits2Float(0x3fb79813), SkBits2Float(0xc26fee71));
+path.cubicTo(SkBits2Float(0x3fb20808), SkBits2Float(0xc26fef82), SkBits2Float(0x3fac780f), SkBits2Float(0xc26ff085), SkBits2Float(0x3fa6e80c), SkBits2Float(0xc26ff17d));
+path.lineTo(SkBits2Float(0x3fa6e7f4), SkBits2Float(0xc26ff17d));
+path.cubicTo(SkBits2Float(0x3f5e8eb4), SkBits2Float(0xc26ffb2a), SkBits2Float(0x3ede8fa6), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ffdf8c6), SkBits2Float(0xc2a5f3db));
+path.cubicTo(SkBits2Float(0x403d5556), SkBits2Float(0xc2a5e7ed), SkBits2Float(0x407ba65a), SkBits2Float(0xc2a5d338), SkBits2Float(0x409cf3fe), SkBits2Float(0xc2a5b5bc));
+path.lineTo(SkBits2Float(0x4062eb8a), SkBits2Float(0xc26f94a1));
+path.cubicTo(SkBits2Float(0x4035ea63), SkBits2Float(0xc26fbf44), SkBits2Float(0x4008de16), SkBits2Float(0xc26fdd35), SkBits2Float(0x3fb79810), SkBits2Float(0xc26fee74));
+path.lineTo(SkBits2Float(0x3ffdf8c6), SkBits2Float(0xc2a5f3db));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3fe06a9b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40606368), SkBits2Float(0xc2a5e38e), SkBits2Float(0x40a82f8a), SkBits2Float(0xc2a5aab6));
+path.lineTo(SkBits2Float(0x40732902), SkBits2Float(0xc26f84b2));
+path.cubicTo(SkBits2Float(0x4022355b), SkBits2Float(0xc26fd6e1), SkBits2Float(0x3fa23a8f), SkBits2Float(0xc2700000), SkBits2Float(0xb5600574), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40a82f91), SkBits2Float(0xc2a5aab7));
+path.cubicTo(SkBits2Float(0x40adc8dc), SkBits2Float(0xc2a5a508), SkBits2Float(0x40b361d8), SkBits2Float(0xc2a59f10), SkBits2Float(0x40b8fa82), SkBits2Float(0xc2a598d0));
+path.lineTo(SkBits2Float(0x4085b825), SkBits2Float(0xc26f6ad0));
+path.cubicTo(SkBits2Float(0x4081ac7b), SkBits2Float(0xc26f73dc), SkBits2Float(0x407b412c), SkBits2Float(0xc26f7c7c), SkBits2Float(0x407328f8), SkBits2Float(0xc26f84b3));
+path.lineTo(SkBits2Float(0x40a82f91), SkBits2Float(0xc2a5aab7));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp6(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3fe06a9b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40606368), SkBits2Float(0xc2a5e38e), SkBits2Float(0x40a82f91), SkBits2Float(0xc2a5aab7));
+path.cubicTo(SkBits2Float(0x40adc8dc), SkBits2Float(0xc2a5a508), SkBits2Float(0x40b361d8), SkBits2Float(0xc2a59f10), SkBits2Float(0x40b8fa82), SkBits2Float(0xc2a598d0));
+path.lineTo(SkBits2Float(0x4085b825), SkBits2Float(0xc26f6ad0));
+path.cubicTo(SkBits2Float(0x4081ac7d), SkBits2Float(0xc26f73dc), SkBits2Float(0x407b4133), SkBits2Float(0xc26f7c7c), SkBits2Float(0x40732902), SkBits2Float(0xc26f84b2));
+path.cubicTo(SkBits2Float(0x4022355b), SkBits2Float(0xc26fd6e1), SkBits2Float(0x3fa23a8f), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+path.moveTo(SkBits2Float(0x408fea52), SkBits2Float(0xc28dc28a));
+path.lineTo(SkBits2Float(0x407328f8), SkBits2Float(0xc26f84b3));
+path.lineTo(SkBits2Float(0x40732903), SkBits2Float(0xc26f84b3));
+path.lineTo(SkBits2Float(0x408fea52), SkBits2Float(0xc28dc28a));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40b8fa77), SkBits2Float(0xc2a598d0));
+path.cubicTo(SkBits2Float(0x4109d7e9), SkBits2Float(0xc2a5337c), SkBits2Float(0x4137014a), SkBits2Float(0xc2a483b2), SkBits2Float(0x4163cbb6), SkBits2Float(0xc2a38a24));
+path.lineTo(SkBits2Float(0x4124abf0), SkBits2Float(0xc26c715c));
+path.cubicTo(SkBits2Float(0x41044af8), SkBits2Float(0xc26dda2b), SkBits2Float(0x40c74ab0), SkBits2Float(0xc26ed852), SkBits2Float(0x4085b82e), SkBits2Float(0xc26f6ad1));
+path.lineTo(SkBits2Float(0x40b8fa77), SkBits2Float(0xc2a598d0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp7(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3de5c884), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3e65c882), SkBits2Float(0xc2a5ffe2), SkBits2Float(0x3eac5645), SkBits2Float(0xc2a5ffa7));
+path.lineTo(SkBits2Float(0x3e79297e), SkBits2Float(0xc26fff7f));
+path.cubicTo(SkBits2Float(0x3e261bbd), SkBits2Float(0xc26fffd7), SkBits2Float(0x3da61bbf), SkBits2Float(0xc2700000), SkBits2Float(0xb3244c00), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3eac564d), SkBits2Float(0xc2a5ffa7));
+path.cubicTo(SkBits2Float(0x3eb21458), SkBits2Float(0xc2a5ffa1), SkBits2Float(0x3eb7d2fc), SkBits2Float(0xc2a5ff9b), SkBits2Float(0x3ebd91a0), SkBits2Float(0xc2a5ff94));
+path.lineTo(SkBits2Float(0x3e8909ff), SkBits2Float(0xc26fff64));
+path.cubicTo(SkBits2Float(0x3e84e2cf), SkBits2Float(0xc26fff6d), SkBits2Float(0x3e80bc02), SkBits2Float(0xc26fff76), SkBits2Float(0x3e792a69), SkBits2Float(0xc26fff7f));
+path.lineTo(SkBits2Float(0x3eac564d), SkBits2Float(0xc2a5ffa7));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp8(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3de5c884), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3e65c882), SkBits2Float(0xc2a5ffe2), SkBits2Float(0x3eac564d), SkBits2Float(0xc2a5ffa7));
+path.cubicTo(SkBits2Float(0x3eb21458), SkBits2Float(0xc2a5ffa1), SkBits2Float(0x3eb7d2fc), SkBits2Float(0xc2a5ff9b), SkBits2Float(0x3ebd91a0), SkBits2Float(0xc2a5ff94));
+path.lineTo(SkBits2Float(0x3e8909ff), SkBits2Float(0xc26fff64));
+path.lineTo(SkBits2Float(0x3e792a69), SkBits2Float(0xc26fff7f));
+path.cubicTo(SkBits2Float(0x3e261bbd), SkBits2Float(0xc26fffd7), SkBits2Float(0x3da61bbf), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ebd921a), SkBits2Float(0xc2a5ff94));
+path.cubicTo(SkBits2Float(0x3f0d545f), SkBits2Float(0xc2a5ff29), SkBits2Float(0x3f3bdfbd), SkBits2Float(0xc2a5fe71), SkBits2Float(0x3f6a6ab6), SkBits2Float(0xc2a5fd69));
+path.lineTo(SkBits2Float(0x3f297558), SkBits2Float(0xc26ffc43));
+path.cubicTo(SkBits2Float(0x3f07d00d), SkBits2Float(0xc26ffdc0), SkBits2Float(0x3ecc550f), SkBits2Float(0xc26ffecc), SkBits2Float(0x3e8909b7), SkBits2Float(0xc26fff65));
+path.lineTo(SkBits2Float(0x3ebd921a), SkBits2Float(0xc2a5ff94));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp9(skiatest::Reporter* reporter, const char* filename) { // crashes
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ecc43bf), SkBits2Float(0xc2a60000), SkBits2Float(0x3f4c4385), SkBits2Float(0xc2a5fe87), SkBits2Float(0x3f993163), SkBits2Float(0xc2a5fb95));
+path.lineTo(SkBits2Float(0x3f5d7bc4), SkBits2Float(0xc26ff99d));
+path.cubicTo(SkBits2Float(0x3f13a919), SkBits2Float(0xc26ffdde), SkBits2Float(0x3e93a998), SkBits2Float(0xc26fffff), SkBits2Float(0x367b7ed0), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f993156), SkBits2Float(0xc2a5fb95));
+path.cubicTo(SkBits2Float(0x3f9e4c7a), SkBits2Float(0xc2a5fb49), SkBits2Float(0x3fa36794), SkBits2Float(0xc2a5fafa), SkBits2Float(0x3fa882aa), SkBits2Float(0xc2a5faa7));
+path.lineTo(SkBits2Float(0x3f73a149), SkBits2Float(0xc26ff845));
+path.cubicTo(SkBits2Float(0x3f6c3f64), SkBits2Float(0xc26ff8bf), SkBits2Float(0x3f64dd9d), SkBits2Float(0xc26ff931), SkBits2Float(0x3f5d7bcf), SkBits2Float(0xc26ff99f));
+path.lineTo(SkBits2Float(0x3f993156), SkBits2Float(0xc2a5fb95));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp10(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ddcd524), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3e5cd462), SkBits2Float(0xc2a5ffe3), SkBits2Float(0x3ea59eff), SkBits2Float(0xc2a5ffac));
+path.lineTo(SkBits2Float(0x3e6f74a3), SkBits2Float(0xc26fff89));
+path.cubicTo(SkBits2Float(0x3e1fa33e), SkBits2Float(0xc26fffd9), SkBits2Float(0x3d9fa303), SkBits2Float(0xc2700000), SkBits2Float(0xb580e440), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ea59f9c), SkBits2Float(0xc2a5ffad));
+path.cubicTo(SkBits2Float(0x3eab24c0), SkBits2Float(0xc2a5ffa7), SkBits2Float(0x3eb0aa54), SkBits2Float(0xc2a5ffa1), SkBits2Float(0x3eb62fe9), SkBits2Float(0xc2a5ff9b));
+path.lineTo(SkBits2Float(0x3e83b355), SkBits2Float(0xc26fff6f));
+path.cubicTo(SkBits2Float(0x3e7f6bdb), SkBits2Float(0xc26fff79), SkBits2Float(0x3e777021), SkBits2Float(0xc26fff81), SkBits2Float(0x3e6f7465), SkBits2Float(0xc26fff8a));
+path.lineTo(SkBits2Float(0x3ea59f9c), SkBits2Float(0xc2a5ffad));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp11(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ddcd524), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3e5cd462), SkBits2Float(0xc2a5ffe3), SkBits2Float(0x3ea59f9c), SkBits2Float(0xc2a5ffad));
+path.lineTo(SkBits2Float(0x3eb62fe9), SkBits2Float(0xc2a5ff9b));
+path.lineTo(SkBits2Float(0x3e83b355), SkBits2Float(0xc26fff6f));
+path.cubicTo(SkBits2Float(0x3e7f6bf0), SkBits2Float(0xc26fff79), SkBits2Float(0x3e77704b), SkBits2Float(0xc26fff81), SkBits2Float(0x3e6f74a3), SkBits2Float(0xc26fff89));
+path.cubicTo(SkBits2Float(0x3e1fa33e), SkBits2Float(0xc26fffd9), SkBits2Float(0x3d9fa303), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+path.moveTo(SkBits2Float(0x3e7ee007), SkBits2Float(0xc27f7413));
+path.lineTo(SkBits2Float(0x3e6f7465), SkBits2Float(0xc26fff8a));
+path.lineTo(SkBits2Float(0x3e6f74a4), SkBits2Float(0xc26fff8a));
+path.lineTo(SkBits2Float(0x3e7ee007), SkBits2Float(0xc27f7413));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3eb62f8c), SkBits2Float(0xc2a5ff9c));
+path.cubicTo(SkBits2Float(0x3f07d31d), SkBits2Float(0xc2a5ff3a), SkBits2Float(0x3f348e3e), SkBits2Float(0xc2a5fe8f), SkBits2Float(0x3f614904), SkBits2Float(0xc2a5fd9c));
+path.lineTo(SkBits2Float(0x3f22db6c), SkBits2Float(0xc26ffc8c));
+path.cubicTo(SkBits2Float(0x3f0285bf), SkBits2Float(0xc26ffdeb), SkBits2Float(0x3ec45fa5), SkBits2Float(0xc26ffee1), SkBits2Float(0x3e83b387), SkBits2Float(0xc26fff6f));
+path.lineTo(SkBits2Float(0x3eb62f8c), SkBits2Float(0xc2a5ff9c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp12(skiatest::Reporter* reporter, const char* filename) { // crashed
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ecc43bf), SkBits2Float(0xc2a60000), SkBits2Float(0x3f4c4385), SkBits2Float(0xc2a5fe87), SkBits2Float(0x3f993163), SkBits2Float(0xc2a5fb95));
+path.lineTo(SkBits2Float(0x3f5d7bc4), SkBits2Float(0xc26ff99d));
+path.cubicTo(SkBits2Float(0x3f13a919), SkBits2Float(0xc26ffdde), SkBits2Float(0x3e93a998), SkBits2Float(0xc26fffff), SkBits2Float(0x367b7ed0), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f993156), SkBits2Float(0xc2a5fb95));
+path.cubicTo(SkBits2Float(0x3f9e4c7a), SkBits2Float(0xc2a5fb49), SkBits2Float(0x3fa36794), SkBits2Float(0xc2a5fafa), SkBits2Float(0x3fa882aa), SkBits2Float(0xc2a5faa7));
+path.lineTo(SkBits2Float(0x3f73a149), SkBits2Float(0xc26ff845));
+path.cubicTo(SkBits2Float(0x3f6c3f64), SkBits2Float(0xc26ff8bf), SkBits2Float(0x3f64dd9d), SkBits2Float(0xc26ff931), SkBits2Float(0x3f5d7bcf), SkBits2Float(0xc26ff99f));
+path.lineTo(SkBits2Float(0x3f993156), SkBits2Float(0xc2a5fb95));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// ../../third_party/tcmalloc/chromium/src/free_list.h:118] Memory corruption detected.
+
+static void battleOp13(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ddcd524), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3e5cd462), SkBits2Float(0xc2a5ffe3), SkBits2Float(0x3ea59eff), SkBits2Float(0xc2a5ffac));
+path.lineTo(SkBits2Float(0x3e6f74a3), SkBits2Float(0xc26fff89));
+path.cubicTo(SkBits2Float(0x3e1fa33e), SkBits2Float(0xc26fffd9), SkBits2Float(0x3d9fa303), SkBits2Float(0xc2700000), SkBits2Float(0xb580e440), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ea59f9c), SkBits2Float(0xc2a5ffad));
+path.cubicTo(SkBits2Float(0x3eab24c0), SkBits2Float(0xc2a5ffa7), SkBits2Float(0x3eb0aa54), SkBits2Float(0xc2a5ffa1), SkBits2Float(0x3eb62fe9), SkBits2Float(0xc2a5ff9b));
+path.lineTo(SkBits2Float(0x3e83b355), SkBits2Float(0xc26fff6f));
+path.cubicTo(SkBits2Float(0x3e7f6bdb), SkBits2Float(0xc26fff79), SkBits2Float(0x3e777021), SkBits2Float(0xc26fff81), SkBits2Float(0x3e6f7465), SkBits2Float(0xc26fff8a));
+path.lineTo(SkBits2Float(0x3ea59f9c), SkBits2Float(0xc2a5ffad));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp14(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ddcd524), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3e5cd462), SkBits2Float(0xc2a5ffe3), SkBits2Float(0x3ea59f9c), SkBits2Float(0xc2a5ffad));
+path.lineTo(SkBits2Float(0x3eb62fe9), SkBits2Float(0xc2a5ff9b));
+path.lineTo(SkBits2Float(0x3e83b355), SkBits2Float(0xc26fff6f));
+path.cubicTo(SkBits2Float(0x3e7f6bf0), SkBits2Float(0xc26fff79), SkBits2Float(0x3e77704b), SkBits2Float(0xc26fff81), SkBits2Float(0x3e6f74a3), SkBits2Float(0xc26fff89));
+path.cubicTo(SkBits2Float(0x3e1fa33e), SkBits2Float(0xc26fffd9), SkBits2Float(0x3d9fa303), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+path.moveTo(SkBits2Float(0x3e7ee007), SkBits2Float(0xc27f7413));
+path.lineTo(SkBits2Float(0x3e6f7465), SkBits2Float(0xc26fff8a));
+path.lineTo(SkBits2Float(0x3e6f74a4), SkBits2Float(0xc26fff8a));
+path.lineTo(SkBits2Float(0x3e7ee007), SkBits2Float(0xc27f7413));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3eb62f8c), SkBits2Float(0xc2a5ff9c));
+path.cubicTo(SkBits2Float(0x3f07d31d), SkBits2Float(0xc2a5ff3a), SkBits2Float(0x3f348e3e), SkBits2Float(0xc2a5fe8f), SkBits2Float(0x3f614904), SkBits2Float(0xc2a5fd9c));
+path.lineTo(SkBits2Float(0x3f22db6c), SkBits2Float(0xc26ffc8c));
+path.cubicTo(SkBits2Float(0x3f0285bf), SkBits2Float(0xc26ffdeb), SkBits2Float(0x3ec45fa5), SkBits2Float(0xc26ffee1), SkBits2Float(0x3e83b387), SkBits2Float(0xc26fff6f));
+path.lineTo(SkBits2Float(0x3eb62f8c), SkBits2Float(0xc2a5ff9c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp15(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f19f03c), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f99ef95), SkBits2Float(0xc2a5fca7), SkBits2Float(0x3fe6e2fa), SkBits2Float(0xc2a5f5f7));
+path.lineTo(SkBits2Float(0x3fa6e80c), SkBits2Float(0xc26ff17d));
+path.cubicTo(SkBits2Float(0x3f5e8ed4), SkBits2Float(0xc26ffb2a), SkBits2Float(0x3ede8fc6), SkBits2Float(0xc2700000), SkBits2Float(0x35d9fd64), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3fe6e322), SkBits2Float(0xc2a5f5f7));
+path.cubicTo(SkBits2Float(0x3fee94fb), SkBits2Float(0xc2a5f54c), SkBits2Float(0x3ff646db), SkBits2Float(0xc2a5f497), SkBits2Float(0x3ffdf8ad), SkBits2Float(0xc2a5f3db));
+path.lineTo(SkBits2Float(0x3fb79813), SkBits2Float(0xc26fee71));
+path.cubicTo(SkBits2Float(0x3fb20800), SkBits2Float(0xc26fef82), SkBits2Float(0x3fac77ff), SkBits2Float(0xc26ff085), SkBits2Float(0x3fa6e7f4), SkBits2Float(0xc26ff17d));
+path.lineTo(SkBits2Float(0x3fe6e322), SkBits2Float(0xc2a5f5f7));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp16(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f19f03c), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f99ef95), SkBits2Float(0xc2a5fca7), SkBits2Float(0x3fe6e322), SkBits2Float(0xc2a5f5f7));
+path.cubicTo(SkBits2Float(0x3fee94fb), SkBits2Float(0xc2a5f54c), SkBits2Float(0x3ff646db), SkBits2Float(0xc2a5f497), SkBits2Float(0x3ffdf8ad), SkBits2Float(0xc2a5f3db));
+path.lineTo(SkBits2Float(0x3fb79813), SkBits2Float(0xc26fee71));
+path.cubicTo(SkBits2Float(0x3fb20808), SkBits2Float(0xc26fef82), SkBits2Float(0x3fac780f), SkBits2Float(0xc26ff085), SkBits2Float(0x3fa6e80c), SkBits2Float(0xc26ff17d));
+path.lineTo(SkBits2Float(0x3fa6e7f4), SkBits2Float(0xc26ff17d));
+path.cubicTo(SkBits2Float(0x3f5e8eb4), SkBits2Float(0xc26ffb2a), SkBits2Float(0x3ede8fa6), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ffdf8c6), SkBits2Float(0xc2a5f3db));
+path.cubicTo(SkBits2Float(0x403d5556), SkBits2Float(0xc2a5e7ed), SkBits2Float(0x407ba65a), SkBits2Float(0xc2a5d338), SkBits2Float(0x409cf3fe), SkBits2Float(0xc2a5b5bc));
+path.lineTo(SkBits2Float(0x4062eb8a), SkBits2Float(0xc26f94a1));
+path.cubicTo(SkBits2Float(0x4035ea63), SkBits2Float(0xc26fbf44), SkBits2Float(0x4008de16), SkBits2Float(0xc26fdd35), SkBits2Float(0x3fb79810), SkBits2Float(0xc26fee74));
+path.lineTo(SkBits2Float(0x3ffdf8c6), SkBits2Float(0xc2a5f3db));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp17(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f9860dc), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40185ea2), SkBits2Float(0xc2a5f2e2), SkBits2Float(0x40647d09), SkBits2Float(0xc2a5d8aa));
+path.lineTo(SkBits2Float(0x40252c2a), SkBits2Float(0xc26fc723));
+path.cubicTo(SkBits2Float(0x3fdc4b47), SkBits2Float(0xc26fed09), SkBits2Float(0x3f5c4ea6), SkBits2Float(0xc26ffffe), SkBits2Float(0x3664fea3), SkBits2Float(0xc26ffffe));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40647d17), SkBits2Float(0xc2a5d8ab));
+path.cubicTo(SkBits2Float(0x406c19ae), SkBits2Float(0xc2a5d60b), SkBits2Float(0x4073b608), SkBits2Float(0xc2a5d34a), SkBits2Float(0x407b5230), SkBits2Float(0xc2a5d069));
+path.lineTo(SkBits2Float(0x4035ad90), SkBits2Float(0xc26fbb32));
+path.cubicTo(SkBits2Float(0x40302d3b), SkBits2Float(0xc26fbf5d), SkBits2Float(0x402aacbf), SkBits2Float(0xc26fc358), SkBits2Float(0x40252c21), SkBits2Float(0xc26fc722));
+path.lineTo(SkBits2Float(0x40647d17), SkBits2Float(0xc2a5d8ab));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp18(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3664fea3), SkBits2Float(0xc26ffffe));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f9860dc), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40185ea2), SkBits2Float(0xc2a5f2e2), SkBits2Float(0x40647d17), SkBits2Float(0xc2a5d8ab));
+path.cubicTo(SkBits2Float(0x406c19ae), SkBits2Float(0xc2a5d60b), SkBits2Float(0x4073b608), SkBits2Float(0xc2a5d34a), SkBits2Float(0x407b5230), SkBits2Float(0xc2a5d069));
+path.lineTo(SkBits2Float(0x4035ad90), SkBits2Float(0xc26fbb32));
+path.cubicTo(SkBits2Float(0x40302d3b), SkBits2Float(0xc26fbf5d), SkBits2Float(0x402aacbf), SkBits2Float(0xc26fc358), SkBits2Float(0x40252c2a), SkBits2Float(0xc26fc723));
+path.cubicTo(SkBits2Float(0x3fdc4b47), SkBits2Float(0xc26fed09), SkBits2Float(0x3f5c4ea6), SkBits2Float(0xc26ffffe), SkBits2Float(0x3664fea3), SkBits2Float(0xc26ffffe));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x407b523a), SkBits2Float(0xc2a5d069));
+path.cubicTo(SkBits2Float(0x40bb53e8), SkBits2Float(0xc2a5a1ad), SkBits2Float(0x40f8dfd1), SkBits2Float(0xc2a5508e), SkBits2Float(0x411b1813), SkBits2Float(0xc2a4dd32));
+path.lineTo(SkBits2Float(0x40e03b7c), SkBits2Float(0xc26e5b8f));
+path.cubicTo(SkBits2Float(0x40b3e8bb), SkBits2Float(0xc26f0259), SkBits2Float(0x40876aeb), SkBits2Float(0xc26f77a1), SkBits2Float(0x4035ad92), SkBits2Float(0xc26fbb33));
+path.lineTo(SkBits2Float(0x407b523a), SkBits2Float(0xc2a5d069));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp19(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40272e66), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40a7227d), SkBits2Float(0xc2a5c0db), SkBits2Float(0x40fa5a70), SkBits2Float(0xc2a542ca));
+path.lineTo(SkBits2Float(0x40b4fa6e), SkBits2Float(0xc26eee73));
+path.cubicTo(SkBits2Float(0x4071a3f5), SkBits2Float(0xc26fa4b8), SkBits2Float(0x3ff1b53c), SkBits2Float(0xc2700000), SkBits2Float(0x359dfd46), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40fa5a6d), SkBits2Float(0xc2a542cb));
+path.cubicTo(SkBits2Float(0x4101563b), SkBits2Float(0xc2a5362f), SkBits2Float(0x41057ec0), SkBits2Float(0xc2a528f4), SkBits2Float(0x4109a6c0), SkBits2Float(0xc2a51b18));
+path.lineTo(SkBits2Float(0x40c70391), SkBits2Float(0xc26eb50e));
+path.cubicTo(SkBits2Float(0x40c10142), SkBits2Float(0xc26ec918), SkBits2Float(0x40bafe32), SkBits2Float(0xc26edc3a), SkBits2Float(0x40b4fa70), SkBits2Float(0xc26eee73));
+path.lineTo(SkBits2Float(0x40fa5a6d), SkBits2Float(0xc2a542cb));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp20(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40272e63), SkBits2Float(0xc2a60000), SkBits2Float(0x40a7227a), SkBits2Float(0xc2a5c0db), SkBits2Float(0x40fa5a6c), SkBits2Float(0xc2a542ca));
+path.lineTo(SkBits2Float(0x40fa5a6d), SkBits2Float(0xc2a542cb));
+path.cubicTo(SkBits2Float(0x4101563b), SkBits2Float(0xc2a5362f), SkBits2Float(0x41057ec0), SkBits2Float(0xc2a528f4), SkBits2Float(0x4109a6c0), SkBits2Float(0xc2a51b18));
+path.lineTo(SkBits2Float(0x40c70391), SkBits2Float(0xc26eb50e));
+path.cubicTo(SkBits2Float(0x40c10142), SkBits2Float(0xc26ec918), SkBits2Float(0x40bafe32), SkBits2Float(0xc26edc3a), SkBits2Float(0x40b4fa6e), SkBits2Float(0xc26eee73));
+path.cubicTo(SkBits2Float(0x4071a3f5), SkBits2Float(0xc26fa4b8), SkBits2Float(0x3ff1b53c), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4109a6bc), SkBits2Float(0xc2a51b19));
+path.cubicTo(SkBits2Float(0x414d093d), SkBits2Float(0xc2a43a61), SkBits2Float(0x4187e474), SkBits2Float(0xc2a2b4fa), SkBits2Float(0x41a8a805), SkBits2Float(0xc2a08e4d));
+path.lineTo(SkBits2Float(0x4173d72c), SkBits2Float(0xc2682105));
+path.cubicTo(SkBits2Float(0x41447890), SkBits2Float(0xc26b3d2d), SkBits2Float(0x4114380c), SkBits2Float(0xc26d702b), SkBits2Float(0x40c70392), SkBits2Float(0xc26eb510));
+path.lineTo(SkBits2Float(0x4109a6bc), SkBits2Float(0xc2a51b19));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp21(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x404ef9c5), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40cee321), SkBits2Float(0xc2a59f3a), SkBits2Float(0x411ad5ab), SkBits2Float(0xc2a4de2c));
+path.lineTo(SkBits2Float(0x40dfdb77), SkBits2Float(0xc26e5cf8));
+path.cubicTo(SkBits2Float(0x40958e99), SkBits2Float(0xc26f7414), SkBits2Float(0x40159f04), SkBits2Float(0xc26ffffe), SkBits2Float(0x36ae7f52), SkBits2Float(0xc26ffffe));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x411ad5aa), SkBits2Float(0xc2a4de2c));
+path.cubicTo(SkBits2Float(0x411ff8ea), SkBits2Float(0xc2a4cadf), SkBits2Float(0x41251b3e), SkBits2Float(0xc2a4b69c), SkBits2Float(0x412a3c98), SkBits2Float(0xc2a4a163));
+path.lineTo(SkBits2Float(0x40f6200f), SkBits2Float(0xc26e0518));
+path.cubicTo(SkBits2Float(0x40eeb53e), SkBits2Float(0xc26e23c6), SkBits2Float(0x40e74902), SkBits2Float(0xc26e4112), SkBits2Float(0x40dfdb73), SkBits2Float(0xc26e5cf8));
+path.lineTo(SkBits2Float(0x411ad5aa), SkBits2Float(0xc2a4de2c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end fail 1
+
+static void battleOp22(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x407fb41a), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40ff895b), SkBits2Float(0xc2a56c4b), SkBits2Float(0x413f077c), SkBits2Float(0xc2a44609));
+path.lineTo(SkBits2Float(0x410a17ee), SkBits2Float(0xc26d8104));
+path.cubicTo(SkBits2Float(0x40b8b9ab), SkBits2Float(0xc26f2a74), SkBits2Float(0x4038d88b), SkBits2Float(0xc2700000), SkBits2Float(0x337fa8c0), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x413f0780), SkBits2Float(0xc2a44609));
+path.cubicTo(SkBits2Float(0x41455a4a), SkBits2Float(0xc2a4289f), SkBits2Float(0x414bab5a), SkBits2Float(0xc2a409bf), SkBits2Float(0x4151fa92), SkBits2Float(0xc2a3e96b));
+path.lineTo(SkBits2Float(0x4117cabb), SkBits2Float(0xc26cfb1d));
+path.cubicTo(SkBits2Float(0x41133b1d), SkBits2Float(0xc26d29dc), SkBits2Float(0x410eaa27), SkBits2Float(0xc26d567f), SkBits2Float(0x410a17f1), SkBits2Float(0xc26d8105));
+path.lineTo(SkBits2Float(0x413f0780), SkBits2Float(0xc2a44609));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp23(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x407fb41a), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40ff895b), SkBits2Float(0xc2a56c4b), SkBits2Float(0x413f0780), SkBits2Float(0xc2a44609));
+path.cubicTo(SkBits2Float(0x41455a4a), SkBits2Float(0xc2a4289f), SkBits2Float(0x414bab5a), SkBits2Float(0xc2a409bf), SkBits2Float(0x4151fa92), SkBits2Float(0xc2a3e96b));
+path.lineTo(SkBits2Float(0x4117cabb), SkBits2Float(0xc26cfb1d));
+path.cubicTo(SkBits2Float(0x41133b1d), SkBits2Float(0xc26d29dc), SkBits2Float(0x410eaa27), SkBits2Float(0xc26d567f), SkBits2Float(0x410a17ee), SkBits2Float(0xc26d8104));
+path.cubicTo(SkBits2Float(0x40b8b9ab), SkBits2Float(0xc26f2a74), SkBits2Float(0x4038d88b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4151fa93), SkBits2Float(0xc2a3e96b));
+path.cubicTo(SkBits2Float(0x419c2b7d), SkBits2Float(0xc2a1dce5), SkBits2Float(0x41ce36f8), SkBits2Float(0xc29e52a6), SkBits2Float(0x41fe1a0a), SkBits2Float(0xc2995d2e));
+path.lineTo(SkBits2Float(0x41b7b024), SkBits2Float(0xc25dbb29));
+path.cubicTo(SkBits2Float(0x41951228), SkBits2Float(0xc264e68b), SkBits2Float(0x4161c9b2), SkBits2Float(0xc26a04c8), SkBits2Float(0x4117cabf), SkBits2Float(0xc26cfb1e));
+path.lineTo(SkBits2Float(0x4151fa93), SkBits2Float(0xc2a3e96b));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp24(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x409bc7b0), SkBits2Float(0xc2a5ffff), SkBits2Float(0x411ba103), SkBits2Float(0xc2a524b6), SkBits2Float(0x4168515c), SkBits2Float(0xc2a370af));
+path.lineTo(SkBits2Float(0x4127f0cc), SkBits2Float(0xc26c4c8f));
+path.cubicTo(SkBits2Float(0x40e1017a), SkBits2Float(0xc26ec2f6), SkBits2Float(0x40613965), SkBits2Float(0xc26fffff), SkBits2Float(0x3655fea5), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4168515e), SkBits2Float(0xc2a370b0));
+path.cubicTo(SkBits2Float(0x416ffb5b), SkBits2Float(0xc2a3451c), SkBits2Float(0x4177a23d), SkBits2Float(0xc2a31761), SkBits2Float(0x417f45ca), SkBits2Float(0xc2a2e77f));
+path.lineTo(SkBits2Float(0x413888ce), SkBits2Float(0xc26b8638));
+path.cubicTo(SkBits2Float(0x41330328), SkBits2Float(0xc26bcb72), SkBits2Float(0x412d7b1a), SkBits2Float(0xc26c0d90), SkBits2Float(0x4127f0cb), SkBits2Float(0xc26c4c90));
+path.lineTo(SkBits2Float(0x4168515e), SkBits2Float(0xc2a370b0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp25(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3655fea5), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x409bc7b0), SkBits2Float(0xc2a5ffff), SkBits2Float(0x411ba103), SkBits2Float(0xc2a524b6), SkBits2Float(0x4168515e), SkBits2Float(0xc2a370b0));
+path.cubicTo(SkBits2Float(0x416ffb5b), SkBits2Float(0xc2a3451c), SkBits2Float(0x4177a23d), SkBits2Float(0xc2a31761), SkBits2Float(0x417f45ca), SkBits2Float(0xc2a2e77f));
+path.lineTo(SkBits2Float(0x413888ce), SkBits2Float(0xc26b8638));
+path.cubicTo(SkBits2Float(0x41330328), SkBits2Float(0xc26bcb72), SkBits2Float(0x412d7b1a), SkBits2Float(0xc26c0d90), SkBits2Float(0x4127f0cc), SkBits2Float(0xc26c4c8f));
+path.cubicTo(SkBits2Float(0x40e1017a), SkBits2Float(0xc26ec2f6), SkBits2Float(0x40613965), SkBits2Float(0xc26fffff), SkBits2Float(0x3655fea5), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x417f45c8), SkBits2Float(0xc2a2e780));
+path.cubicTo(SkBits2Float(0x41bda27d), SkBits2Float(0xc29fde49), SkBits2Float(0x41f99531), SkBits2Float(0xc29aa2c4), SkBits2Float(0x4218d569), SkBits2Float(0xc2935d77));
+path.lineTo(SkBits2Float(0x41dcf6db), SkBits2Float(0xc2550ed7));
+path.cubicTo(SkBits2Float(0x41b46bda), SkBits2Float(0xc25f91e2), SkBits2Float(0x418915db), SkBits2Float(0xc2672288), SkBits2Float(0x413888d2), SkBits2Float(0xc26b8639));
+path.lineTo(SkBits2Float(0x417f45c8), SkBits2Float(0xc2a2e780));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp26(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40b98c15), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41394aaf), SkBits2Float(0xc2a4c8e8), SkBits2Float(0x418a04fa), SkBits2Float(0xc2a25fd2));
+path.lineTo(SkBits2Float(0x41478bd6), SkBits2Float(0xc26ac20e));
+path.cubicTo(SkBits2Float(0x4105f224), SkBits2Float(0xc26e3e3c), SkBits2Float(0x40862167), SkBits2Float(0xc2700000), SkBits2Float(0xb4d00ae8), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x418a04fd), SkBits2Float(0xc2a25fd2));
+path.cubicTo(SkBits2Float(0x418e8d81), SkBits2Float(0xc2a2222a), SkBits2Float(0x41931368), SkBits2Float(0xc2a1e17a), SkBits2Float(0x41979681), SkBits2Float(0xc2a19dc3));
+path.lineTo(SkBits2Float(0x415b29c8), SkBits2Float(0xc269a97e));
+path.cubicTo(SkBits2Float(0x4154a3c3), SkBits2Float(0xc26a0b66), SkBits2Float(0x414e19b0), SkBits2Float(0xc26a68ed), SkBits2Float(0x41478bd5), SkBits2Float(0xc26ac20f));
+path.lineTo(SkBits2Float(0x418a04fd), SkBits2Float(0xc2a25fd2));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp27(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40b98c15), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41394aaf), SkBits2Float(0xc2a4c8e8), SkBits2Float(0x418a04fd), SkBits2Float(0xc2a25fd2));
+path.cubicTo(SkBits2Float(0x418e8d81), SkBits2Float(0xc2a2222a), SkBits2Float(0x41931368), SkBits2Float(0xc2a1e17a), SkBits2Float(0x41979681), SkBits2Float(0xc2a19dc3));
+path.lineTo(SkBits2Float(0x415b29c8), SkBits2Float(0xc269a97e));
+path.cubicTo(SkBits2Float(0x4154a3c3), SkBits2Float(0xc26a0b66), SkBits2Float(0x414e19b0), SkBits2Float(0xc26a68ed), SkBits2Float(0x41478bd6), SkBits2Float(0xc26ac20e));
+path.cubicTo(SkBits2Float(0x4105f224), SkBits2Float(0xc26e3e3c), SkBits2Float(0x40862167), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41979680), SkBits2Float(0xc2a19dc4));
+path.cubicTo(SkBits2Float(0x41e0e1b2), SkBits2Float(0xc29d51d4), SkBits2Float(0x42135c08), SkBits2Float(0xc295f036), SkBits2Float(0x42330e86), SkBits2Float(0xc28bc9b7));
+path.lineTo(SkBits2Float(0x42017048), SkBits2Float(0xc24a1a63));
+path.cubicTo(SkBits2Float(0x41d50cc4), SkBits2Float(0xc258c742), SkBits2Float(0x41a290a5), SkBits2Float(0xc263733c), SkBits2Float(0x415b29c7), SkBits2Float(0xc269a980));
+path.lineTo(SkBits2Float(0x41979680), SkBits2Float(0xc2a19dc4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp28(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40dd1e63), SkBits2Float(0xc2a5ffff), SkBits2Float(0x415caf98), SkBits2Float(0xc2a44632), SkBits2Float(0x41a3e96c), SkBits2Float(0xc2a0dcda));
+path.lineTo(SkBits2Float(0x416cfb1c), SkBits2Float(0xc2689294));
+path.cubicTo(SkBits2Float(0x411f8831), SkBits2Float(0xc26d8140), SkBits2Float(0x409fd849), SkBits2Float(0xc2700000), SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41a3e96b), SkBits2Float(0xc2a0dcda));
+path.cubicTo(SkBits2Float(0x41a94306), SkBits2Float(0xc2a085a1), SkBits2Float(0x41ae9839), SkBits2Float(0xc2a02a23), SkBits2Float(0x41b3e8b2), SkBits2Float(0xc29fca67));
+path.lineTo(SkBits2Float(0x41820dff), SkBits2Float(0xc26705ca));
+path.cubicTo(SkBits2Float(0x417c6d0a), SkBits2Float(0xc2679035), SkBits2Float(0x4174b742), SkBits2Float(0xc268147b), SkBits2Float(0x416cfb1d), SkBits2Float(0xc2689296));
+path.lineTo(SkBits2Float(0x41a3e96b), SkBits2Float(0xc2a0dcda));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp29(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40dd1e62), SkBits2Float(0xc2a60000), SkBits2Float(0x415caf97), SkBits2Float(0xc2a44632), SkBits2Float(0x41a3e96b), SkBits2Float(0xc2a0dcda));
+path.lineTo(SkBits2Float(0x416cfb1d), SkBits2Float(0xc2689296));
+path.cubicTo(SkBits2Float(0x4174b742), SkBits2Float(0xc268147b), SkBits2Float(0x417c6d0a), SkBits2Float(0xc2679035), SkBits2Float(0x41820dff), SkBits2Float(0xc26705ca));
+path.lineTo(SkBits2Float(0x41b3e8b2), SkBits2Float(0xc29fca67));
+path.cubicTo(SkBits2Float(0x41ae9839), SkBits2Float(0xc2a02a23), SkBits2Float(0x41a94307), SkBits2Float(0xc2a085a1), SkBits2Float(0x41a3e96c), SkBits2Float(0xc2a0dcda));
+path.lineTo(SkBits2Float(0x416cfb1c), SkBits2Float(0xc2689294));
+path.cubicTo(SkBits2Float(0x411f8831), SkBits2Float(0xc26d8140), SkBits2Float(0x409fd849), SkBits2Float(0xc2700000), SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41b3e8b1), SkBits2Float(0xc29fca67));
+path.cubicTo(SkBits2Float(0x4205291f), SkBits2Float(0xc299b5bb), SkBits2Float(0x422d73c0), SkBits2Float(0xc28f4fcf), SkBits2Float(0x425064bf), SkBits2Float(0xc2813989));
+path.lineTo(SkBits2Float(0x4216a55b), SkBits2Float(0xc23ad4b9));
+path.cubicTo(SkBits2Float(0x41fac62f), SkBits2Float(0xc24f329e), SkBits2Float(0x41c0857c), SkBits2Float(0xc25e3b2e), SkBits2Float(0x41820dfe), SkBits2Float(0xc26705cb));
+path.lineTo(SkBits2Float(0x41b3e8b1), SkBits2Float(0xc29fca67));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp30(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41028186), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4182264a), SkBits2Float(0xc2a39869), SkBits2Float(0x41c098e8), SkBits2Float(0xc29edd15));
+path.lineTo(SkBits2Float(0x418b3a1a), SkBits2Float(0xc265aeac));
+path.cubicTo(SkBits2Float(0x413c2b06), SkBits2Float(0xc26c85fe), SkBits2Float(0x40bcaeed), SkBits2Float(0xc2700000), SkBits2Float(0x337fa8c0), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41c098e9), SkBits2Float(0xc29edd15));
+path.cubicTo(SkBits2Float(0x41c6d4b6), SkBits2Float(0xc29e642a), SkBits2Float(0x41cd0950), SkBits2Float(0xc29de562), SkBits2Float(0x41d33633), SkBits2Float(0xc29d60c8));
+path.lineTo(SkBits2Float(0x4198aee4), SkBits2Float(0xc26388d7));
+path.cubicTo(SkBits2Float(0x41943815), SkBits2Float(0xc264488f), SkBits2Float(0x418fbbb2), SkBits2Float(0xc264ffdc), SkBits2Float(0x418b3a19), SkBits2Float(0xc265aeae));
+path.lineTo(SkBits2Float(0x41c098e9), SkBits2Float(0xc29edd15));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp31(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41028186), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4182264a), SkBits2Float(0xc2a39869), SkBits2Float(0x41c098e9), SkBits2Float(0xc29edd15));
+path.cubicTo(SkBits2Float(0x41c6d4b6), SkBits2Float(0xc29e642a), SkBits2Float(0x41cd0950), SkBits2Float(0xc29de562), SkBits2Float(0x41d33633), SkBits2Float(0xc29d60c8));
+path.lineTo(SkBits2Float(0x4198aee4), SkBits2Float(0xc26388d7));
+path.cubicTo(SkBits2Float(0x41943816), SkBits2Float(0xc264488f), SkBits2Float(0x418fbbb2), SkBits2Float(0xc264ffda), SkBits2Float(0x418b3a1a), SkBits2Float(0xc265aeac));
+path.cubicTo(SkBits2Float(0x413c2b06), SkBits2Float(0xc26c85fe), SkBits2Float(0x40bcaeed), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41d33633), SkBits2Float(0xc29d60c8));
+path.cubicTo(SkBits2Float(0x421be102), SkBits2Float(0xc294f1be), SkBits2Float(0x4249615f), SkBits2Float(0xc2869cbc), SkBits2Float(0x426e4d45), SkBits2Float(0xc26729aa));
+path.lineTo(SkBits2Float(0x422c4432), SkBits2Float(0xc2271b0a));
+path.cubicTo(SkBits2Float(0x42119380), SkBits2Float(0xc2429ec2), SkBits2Float(0x41e15dfd), SkBits2Float(0xc257575a), SkBits2Float(0x4198aee4), SkBits2Float(0xc26388d8));
+path.lineTo(SkBits2Float(0x41d33633), SkBits2Float(0xc29d60c8));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp32(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4118c001), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41982d6e), SkBits2Float(0xc2a2b4b2), SkBits2Float(0x41e01284), SkBits2Float(0xc29c4333));
+path.lineTo(SkBits2Float(0x41a1fae3), SkBits2Float(0xc261ebf5));
+path.cubicTo(SkBits2Float(0x415c0406), SkBits2Float(0xc26b3cc7), SkBits2Float(0x40dcd7ee), SkBits2Float(0xc2700000), SkBits2Float(0x35f7fd46), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41e01286), SkBits2Float(0xc29c4334));
+path.cubicTo(SkBits2Float(0x41e73e86), SkBits2Float(0xc29b9ea8), SkBits2Float(0x41ee5f11), SkBits2Float(0xc29af239), SkBits2Float(0x41f57356), SkBits2Float(0xc29a3dfa));
+path.lineTo(SkBits2Float(0x41b16f25), SkBits2Float(0xc25f0029));
+path.cubicTo(SkBits2Float(0x41ac5112), SkBits2Float(0xc26004c3), SkBits2Float(0x41a72a20), SkBits2Float(0xc260fe11), SkBits2Float(0x41a1fae3), SkBits2Float(0xc261ebf7));
+path.lineTo(SkBits2Float(0x41e01286), SkBits2Float(0xc29c4334));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp33(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4118c001), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41982d6e), SkBits2Float(0xc2a2b4b2), SkBits2Float(0x41e01286), SkBits2Float(0xc29c4334));
+path.cubicTo(SkBits2Float(0x41e73e86), SkBits2Float(0xc29b9ea8), SkBits2Float(0x41ee5f11), SkBits2Float(0xc29af239), SkBits2Float(0x41f57356), SkBits2Float(0xc29a3dfa));
+path.lineTo(SkBits2Float(0x41b16f25), SkBits2Float(0xc25f0029));
+path.cubicTo(SkBits2Float(0x41ac5112), SkBits2Float(0xc26004c3), SkBits2Float(0x41a72a20), SkBits2Float(0xc260fe11), SkBits2Float(0x41a1fae3), SkBits2Float(0xc261ebf7));
+path.lineTo(SkBits2Float(0x41a1fae3), SkBits2Float(0xc261ebf5));
+path.cubicTo(SkBits2Float(0x415c0406), SkBits2Float(0xc26b3cc7), SkBits2Float(0x40dcd7ee), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41f57359), SkBits2Float(0xc29a3dfa));
+path.cubicTo(SkBits2Float(0x42347528), SkBits2Float(0xc28ec218), SkBits2Float(0x42669614), SkBits2Float(0xc276cf04), SkBits2Float(0x4285b481), SkBits2Float(0xc244c364));
+path.lineTo(SkBits2Float(0x42414f00), SkBits2Float(0xc20e3d0e));
+path.cubicTo(SkBits2Float(0x4226b05a), SkBits2Float(0xc2326a79), SkBits2Float(0x4202738a), SkBits2Float(0xc24e65b9), SkBits2Float(0x41b16f25), SkBits2Float(0xc25f0028));
+path.lineTo(SkBits2Float(0x41f57359), SkBits2Float(0xc29a3dfa));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp34(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41360dec), SkBits2Float(0xc2a60000), SkBits2Float(0x41b5150e), SkBits2Float(0xc2a1522b), SkBits2Float(0x42044925), SkBits2Float(0xc29840e5));
+path.lineTo(SkBits2Float(0x41bf41a8), SkBits2Float(0xc25c2022));
+path.cubicTo(SkBits2Float(0x4182e721), SkBits2Float(0xc2693c30), SkBits2Float(0x41039b08), SkBits2Float(0xc2700000), SkBits2Float(0x3673fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42044925), SkBits2Float(0xc29840e4));
+path.cubicTo(SkBits2Float(0x4208721a), SkBits2Float(0xc2975992), SkBits2Float(0x420c9178), SkBits2Float(0xc296675c), SkBits2Float(0x4210a695), SkBits2Float(0xc2956a6a));
+path.lineTo(SkBits2Float(0x41d1222e), SkBits2Float(0xc25805ce));
+path.cubicTo(SkBits2Float(0x41cb3b2f), SkBits2Float(0xc2597382), SkBits2Float(0x41c5455b), SkBits2Float(0xc25ad1b2), SkBits2Float(0x41bf41a9), SkBits2Float(0xc25c2023));
+path.lineTo(SkBits2Float(0x42044925), SkBits2Float(0xc29840e4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp35(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3673fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41360dec), SkBits2Float(0xc2a60000), SkBits2Float(0x41b5150e), SkBits2Float(0xc2a1522b), SkBits2Float(0x42044925), SkBits2Float(0xc29840e5));
+path.lineTo(SkBits2Float(0x4210a695), SkBits2Float(0xc2956a6a));
+path.lineTo(SkBits2Float(0x41d1222e), SkBits2Float(0xc25805ce));
+path.cubicTo(SkBits2Float(0x41cb3b2f), SkBits2Float(0xc2597382), SkBits2Float(0x41c5455b), SkBits2Float(0xc25ad1b2), SkBits2Float(0x41bf41a9), SkBits2Float(0xc25c2023));
+path.lineTo(SkBits2Float(0x41bf41a8), SkBits2Float(0xc25c2022));
+path.cubicTo(SkBits2Float(0x4182e721), SkBits2Float(0xc2693c30), SkBits2Float(0x41039b08), SkBits2Float(0xc2700000), SkBits2Float(0x3673fea3), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4210a693), SkBits2Float(0xc2956a6a));
+path.cubicTo(SkBits2Float(0x42536b4d), SkBits2Float(0xc2854182), SkBits2Float(0x4284b863), SkBits2Float(0xc254c33a), SkBits2Float(0x42950c68), SkBits2Float(0xc2122882));
+path.lineTo(SkBits2Float(0x42577de3), SkBits2Float(0xc1d35027));
+path.cubicTo(SkBits2Float(0x423fe27d), SkBits2Float(0xc219cde7), SkBits2Float(0x4218d548), SkBits2Float(0xc240a8bd), SkBits2Float(0x41d1222f), SkBits2Float(0xc25805ce));
+path.lineTo(SkBits2Float(0x4210a693), SkBits2Float(0xc2956a6a));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp36(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x414e6589), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41ccf9e5), SkBits2Float(0xc29ffc89), SkBits2Float(0x4214a0bb), SkBits2Float(0xc2946fc8));
+path.lineTo(SkBits2Float(0x41d6e236), SkBits2Float(0xc2569b72));
+path.cubicTo(SkBits2Float(0x41942cf0), SkBits2Float(0xc2674e45), SkBits2Float(0x411533d1), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4214a0bb), SkBits2Float(0xc2946fc9));
+path.cubicTo(SkBits2Float(0x421938a6), SkBits2Float(0xc293496b), SkBits2Float(0x421dc2c1), SkBits2Float(0xc2921574), SkBits2Float(0x42223e19), SkBits2Float(0xc290d421));
+path.lineTo(SkBits2Float(0x41ea914d), SkBits2Float(0xc251640c));
+path.cubicTo(SkBits2Float(0x41e4167f), SkBits2Float(0xc253349e), SkBits2Float(0x41dd8659), SkBits2Float(0xc254f1de), SkBits2Float(0x41d6e239), SkBits2Float(0xc2569b73));
+path.lineTo(SkBits2Float(0x4214a0bb), SkBits2Float(0xc2946fc9));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp37(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x414e6589), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41ccf9e5), SkBits2Float(0xc29ffc89), SkBits2Float(0x4214a0bb), SkBits2Float(0xc2946fc9));
+path.cubicTo(SkBits2Float(0x421938a6), SkBits2Float(0xc293496b), SkBits2Float(0x421dc2c1), SkBits2Float(0xc2921574), SkBits2Float(0x42223e19), SkBits2Float(0xc290d421));
+path.lineTo(SkBits2Float(0x41ea914d), SkBits2Float(0xc251640c));
+path.cubicTo(SkBits2Float(0x41e4167f), SkBits2Float(0xc253349e), SkBits2Float(0x41dd8659), SkBits2Float(0xc254f1de), SkBits2Float(0x41d6e239), SkBits2Float(0xc2569b73));
+path.lineTo(SkBits2Float(0x41d6e236), SkBits2Float(0xc2569b72));
+path.cubicTo(SkBits2Float(0x41942cf0), SkBits2Float(0xc2674e45), SkBits2Float(0x411533d1), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42223e19), SkBits2Float(0xc290d422));
+path.cubicTo(SkBits2Float(0x426bbc38), SkBits2Float(0xc2787e1d), SkBits2Float(0x42916a94), SkBits2Float(0xc234ee59), SkBits2Float(0x429e2fac), SkBits2Float(0xc1c951fc));
+path.lineTo(SkBits2Float(0x4264b3f7), SkBits2Float(0xc191885f));
+path.cubicTo(SkBits2Float(0x42523d91), SkBits2Float(0xc202cb25), SkBits2Float(0x422a6939), SkBits2Float(0xc233a21b), SkBits2Float(0x41ea914d), SkBits2Float(0xc251640d));
+path.lineTo(SkBits2Float(0x42223e19), SkBits2Float(0xc290d422));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp38(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x416c96cf), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41ea70fe), SkBits2Float(0xc29e1973), SkBits2Float(0x422836c6), SkBits2Float(0xc28f1d8a));
+path.lineTo(SkBits2Float(0x41f3336d), SkBits2Float(0xc24ee9f1));
+path.cubicTo(SkBits2Float(0x41a979c6), SkBits2Float(0xc26493d6), SkBits2Float(0x412b073c), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x422836c5), SkBits2Float(0xc28f1d8b));
+path.cubicTo(SkBits2Float(0x422d4896), SkBits2Float(0xc28da02f), SkBits2Float(0x423245ea), SkBits2Float(0xc28c11a8), SkBits2Float(0x42372d65), SkBits2Float(0xc28a7261));
+path.lineTo(SkBits2Float(0x42046ad7), SkBits2Float(0xc24829ff));
+path.cubicTo(SkBits2Float(0x4200df44), SkBits2Float(0xc24a8267), SkBits2Float(0x41fa87ca), SkBits2Float(0xc24cc296), SkBits2Float(0x41f3336d), SkBits2Float(0xc24ee9f1));
+path.lineTo(SkBits2Float(0x422836c5), SkBits2Float(0xc28f1d8b));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp39(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x416c96cf), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41ea70fe), SkBits2Float(0xc29e1973), SkBits2Float(0x422836c5), SkBits2Float(0xc28f1d8b));
+path.cubicTo(SkBits2Float(0x422d4896), SkBits2Float(0xc28da02f), SkBits2Float(0x423245ea), SkBits2Float(0xc28c11a8), SkBits2Float(0x42372d65), SkBits2Float(0xc28a7261));
+path.lineTo(SkBits2Float(0x42046ad7), SkBits2Float(0xc24829ff));
+path.cubicTo(SkBits2Float(0x4200df44), SkBits2Float(0xc24a8267), SkBits2Float(0x41fa87ca), SkBits2Float(0xc24cc296), SkBits2Float(0x41f3336d), SkBits2Float(0xc24ee9f1));
+path.cubicTo(SkBits2Float(0x41a979c6), SkBits2Float(0xc26493d6), SkBits2Float(0x412b073c), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42372d65), SkBits2Float(0xc28a7262));
+path.cubicTo(SkBits2Float(0x4283f2b3), SkBits2Float(0xc25f7e9c), SkBits2Float(0x429ea5c2), SkBits2Float(0xc2098801), SkBits2Float(0x42a4b292), SkBits2Float(0xc12607b1));
+path.lineTo(SkBits2Float(0x426e1def), SkBits2Float(0xc0f00b21));
+path.cubicTo(SkBits2Float(0x42655eb1), SkBits2Float(0xc1c6d725), SkBits2Float(0x423ec4ad), SkBits2Float(0xc2218ff6), SkBits2Float(0x42046ad7), SkBits2Float(0xc2482a00));
+path.lineTo(SkBits2Float(0x42372d65), SkBits2Float(0xc28a7262));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp40(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4184d4a8), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42034ddf), SkBits2Float(0xc29c0a4c), SkBits2Float(0x423a47b2), SkBits2Float(0xc289686d));
+path.lineTo(SkBits2Float(0x4206a908), SkBits2Float(0xc246a97c));
+path.cubicTo(SkBits2Float(0x41bdd65f), SkBits2Float(0xc26199af), SkBits2Float(0x41400b5c), SkBits2Float(0xc2700000), SkBits2Float(0xb560056c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423a47b2), SkBits2Float(0xc289686d));
+path.cubicTo(SkBits2Float(0x423fbcc3), SkBits2Float(0xc2878eef), SkBits2Float(0x4245154e), SkBits2Float(0xc285a0be), SkBits2Float(0x424a4f85), SkBits2Float(0xc2839e81));
+path.lineTo(SkBits2Float(0x42123fa7), SkBits2Float(0xc23e4af2));
+path.cubicTo(SkBits2Float(0x420e7846), SkBits2Float(0xc241326c), SkBits2Float(0x420a9af5), SkBits2Float(0xc243fcec), SkBits2Float(0x4206a907), SkBits2Float(0xc246a97c));
+path.lineTo(SkBits2Float(0x423a47b2), SkBits2Float(0xc289686d));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end fail 1
+
+static void battleOp41(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4196c4f9), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42148669), SkBits2Float(0xc2992c23), SkBits2Float(0x424f6452), SkBits2Float(0xc281a081));
+path.lineTo(SkBits2Float(0x4215ebfd), SkBits2Float(0xc23b6999));
+path.cubicTo(SkBits2Float(0x41d6bc2a), SkBits2Float(0xc25d7441), SkBits2Float(0x4159fada), SkBits2Float(0xc2700000), SkBits2Float(0xb560056c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x424f6452), SkBits2Float(0xc281a081));
+path.cubicTo(SkBits2Float(0x42553921), SkBits2Float(0xc27e96d1), SkBits2Float(0x425ae53b), SkBits2Float(0xc279ba9d), SkBits2Float(0x42606622), SkBits2Float(0xc274ae80));
+path.lineTo(SkBits2Float(0x42223753), SkBits2Float(0xc230e0d8));
+path.cubicTo(SkBits2Float(0x421e3cd8), SkBits2Float(0xc23486e8), SkBits2Float(0x421a2322), SkBits2Float(0xc2380a55), SkBits2Float(0x4215ebfe), SkBits2Float(0xc23b6999));
+path.lineTo(SkBits2Float(0x424f6452), SkBits2Float(0xc281a081));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp42(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4196c4f9), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42148669), SkBits2Float(0xc2992c23), SkBits2Float(0x424f6452), SkBits2Float(0xc281a081));
+path.cubicTo(SkBits2Float(0x42553921), SkBits2Float(0xc27e96d1), SkBits2Float(0x425ae53b), SkBits2Float(0xc279ba9d), SkBits2Float(0x42606622), SkBits2Float(0xc274ae80));
+path.lineTo(SkBits2Float(0x42223753), SkBits2Float(0xc230e0d8));
+path.cubicTo(SkBits2Float(0x421e3cd8), SkBits2Float(0xc23486e8), SkBits2Float(0x421a2322), SkBits2Float(0xc2380a55), SkBits2Float(0x4215ebfd), SkBits2Float(0xc23b6999));
+path.cubicTo(SkBits2Float(0x41d6bc2a), SkBits2Float(0xc25d7441), SkBits2Float(0x4159fada), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42606622), SkBits2Float(0xc274ae80));
+path.cubicTo(SkBits2Float(0x429deeac), SkBits2Float(0xc220cc44), SkBits2Float(0x42b0742c), SkBits2Float(0xc1039d5c), SkBits2Float(0x42a03731), SkBits2Float(0x41adc1b3));
+path.lineTo(SkBits2Float(0x4267a314), SkBits2Float(0x417b36e3));
+path.cubicTo(SkBits2Float(0x427f1d2c), SkBits2Float(0xc0be4950), SkBits2Float(0x426455fc), SkBits2Float(0xc1e87a9a), SkBits2Float(0x42223754), SkBits2Float(0xc230e0d7));
+path.lineTo(SkBits2Float(0x42606622), SkBits2Float(0xc274ae80));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp43(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41aa5d9e), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42271b56), SkBits2Float(0xc295a109), SkBits2Float(0x4264d340), SkBits2Float(0xc2708c1d));
+path.lineTo(SkBits2Float(0x42256a74), SkBits2Float(0xc22de3bf));
+path.cubicTo(SkBits2Float(0x41f199ac), SkBits2Float(0xc25854c9), SkBits2Float(0x41764fdb), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4264d342), SkBits2Float(0xc2708c1d));
+path.cubicTo(SkBits2Float(0x426aec59), SkBits2Float(0xc26abf16), SkBits2Float(0x4270cc6c), SkBits2Float(0xc264b73d), SkBits2Float(0x42767031), SkBits2Float(0xc25e77e8));
+path.lineTo(SkBits2Float(0x423225ec), SkBits2Float(0xc220d20e));
+path.cubicTo(SkBits2Float(0x422e123c), SkBits2Float(0xc2255633), SkBits2Float(0x4229d2f5), SkBits2Float(0xc229b23c), SkBits2Float(0x42256a74), SkBits2Float(0xc22de3c0));
+path.lineTo(SkBits2Float(0x4264d342), SkBits2Float(0xc2708c1d));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp44(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41aa5d9e), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42271b56), SkBits2Float(0xc295a109), SkBits2Float(0x4264d340), SkBits2Float(0xc2708c1d));
+path.lineTo(SkBits2Float(0x4264d342), SkBits2Float(0xc2708c1d));
+path.cubicTo(SkBits2Float(0x426aec59), SkBits2Float(0xc26abf16), SkBits2Float(0x4270cc6c), SkBits2Float(0xc264b73d), SkBits2Float(0x42767031), SkBits2Float(0xc25e77e8));
+path.lineTo(SkBits2Float(0x423225ec), SkBits2Float(0xc220d20e));
+path.cubicTo(SkBits2Float(0x422e123c), SkBits2Float(0xc2255633), SkBits2Float(0x4229d2f5), SkBits2Float(0xc229b23c), SkBits2Float(0x42256a74), SkBits2Float(0xc22de3c0));
+path.lineTo(SkBits2Float(0x42256a74), SkBits2Float(0xc22de3bf));
+path.cubicTo(SkBits2Float(0x41f199ac), SkBits2Float(0xc25854c9), SkBits2Float(0x41764fdb), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42767032), SkBits2Float(0xc25e77e8));
+path.cubicTo(SkBits2Float(0x42aa697a), SkBits2Float(0xc1ebd370), SkBits2Float(0x42b37ad4), SkBits2Float(0x410b48c2), SkBits2Float(0x4291d766), SkBits2Float(0x421e927b));
+path.lineTo(SkBits2Float(0x4252dae4), SkBits2Float(0x41e542d2));
+path.cubicTo(SkBits2Float(0x4281be95), SkBits2Float(0x40c95ff9), SkBits2Float(0x427660fe), SkBits2Float(0xc1aa7a03), SkBits2Float(0x423225ed), SkBits2Float(0xc220d20e));
+path.lineTo(SkBits2Float(0x42767032), SkBits2Float(0xc25e77e8));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp45(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41bfbd07), SkBits2Float(0xc2a5ffff), SkBits2Float(0x423b0ef1), SkBits2Float(0xc2914772), SkBits2Float(0x427a1b1d), SkBits2Float(0xc25a5641));
+path.lineTo(SkBits2Float(0x4234ccaa), SkBits2Float(0xc21dd57d));
+path.cubicTo(SkBits2Float(0x42073912), SkBits2Float(0xc2520ac5), SkBits2Float(0x418a9b2a), SkBits2Float(0xc26fffff), SkBits2Float(0x3697ff52), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x427a1b1e), SkBits2Float(0xc25a5642));
+path.cubicTo(SkBits2Float(0x4280286a), SkBits2Float(0xc253393c), SkBits2Float(0x42831c11), SkBits2Float(0xc24bd939), SkBits2Float(0x4285e673), SkBits2Float(0xc2443b5f));
+path.lineTo(SkBits2Float(0x42419733), SkBits2Float(0xc20ddaba));
+path.cubicTo(SkBits2Float(0x423d8e5d), SkBits2Float(0xc2135c44), SkBits2Float(0x423949dc), SkBits2Float(0xc218b118), SkBits2Float(0x4234ccac), SkBits2Float(0xc21dd57e));
+path.lineTo(SkBits2Float(0x427a1b1e), SkBits2Float(0xc25a5642));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp46(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return;
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3697ff52), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41bfbd07), SkBits2Float(0xc2a5ffff), SkBits2Float(0x423b0ef1), SkBits2Float(0xc2914772), SkBits2Float(0x427a1b1e), SkBits2Float(0xc25a5642));
+path.cubicTo(SkBits2Float(0x4280286a), SkBits2Float(0xc253393c), SkBits2Float(0x42831c11), SkBits2Float(0xc24bd939), SkBits2Float(0x4285e673), SkBits2Float(0xc2443b5f));
+path.lineTo(SkBits2Float(0x42419733), SkBits2Float(0xc20ddaba));
+path.cubicTo(SkBits2Float(0x423d8e5d), SkBits2Float(0xc2135c44), SkBits2Float(0x423949dc), SkBits2Float(0xc218b118), SkBits2Float(0x4234ccac), SkBits2Float(0xc21dd57e));
+path.lineTo(SkBits2Float(0x4234ccaa), SkBits2Float(0xc21dd57d));
+path.cubicTo(SkBits2Float(0x42073912), SkBits2Float(0xc2520ac5), SkBits2Float(0x418a9b2a), SkBits2Float(0xc26fffff), SkBits2Float(0x3697ff52), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4285e672), SkBits2Float(0xc2443b5f));
+path.cubicTo(SkBits2Float(0x42b50145), SkBits2Float(0xc1875361), SkBits2Float(0x42afc74e), SkBits2Float(0x41db6d5e), SkBits2Float(0x4272e616), SkBits2Float(0x426253de));
+path.lineTo(SkBits2Float(0x422f96e8), SkBits2Float(0x42239c3e));
+path.cubicTo(SkBits2Float(0x427e233c), SkBits2Float(0x419e9f42), SkBits2Float(0x4282d8d3), SkBits2Float(0xc143a6d1), SkBits2Float(0x42419734), SkBits2Float(0xc20ddabb));
+path.lineTo(SkBits2Float(0x4285e672), SkBits2Float(0xc2443b5f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp47(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41d59904), SkBits2Float(0xc2a5ffff), SkBits2Float(0x424f13ae), SkBits2Float(0xc28c4fb7), SkBits2Float(0x4286bb70), SkBits2Float(0xc241f0ca));
+path.lineTo(SkBits2Float(0x4242cb24), SkBits2Float(0xc20c32b1));
+path.cubicTo(SkBits2Float(0x4215b1b4), SkBits2Float(0xc24adc20), SkBits2Float(0x419a6875), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4286bb71), SkBits2Float(0xc241f0ca));
+path.cubicTo(SkBits2Float(0x4289cb2b), SkBits2Float(0xc2396eee), SkBits2Float(0x428ca6e5), SkBits2Float(0xc230a410), SkBits2Float(0x428f4c27), SkBits2Float(0xc22797c0));
+path.lineTo(SkBits2Float(0x424f2d54), SkBits2Float(0xc1f24d85));
+path.cubicTo(SkBits2Float(0x424b5a2a), SkBits2Float(0xc1ff6268), SkBits2Float(0x42473840), SkBits2Float(0xc2060c56), SkBits2Float(0x4242cb25), SkBits2Float(0xc20c32b2));
+path.lineTo(SkBits2Float(0x4286bb71), SkBits2Float(0xc241f0ca));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp48(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41d59904), SkBits2Float(0xc2a5ffff), SkBits2Float(0x424f13ae), SkBits2Float(0xc28c4fb7), SkBits2Float(0x4286bb71), SkBits2Float(0xc241f0ca));
+path.cubicTo(SkBits2Float(0x4289cb2b), SkBits2Float(0xc2396eee), SkBits2Float(0x428ca6e5), SkBits2Float(0xc230a410), SkBits2Float(0x428f4c27), SkBits2Float(0xc22797c0));
+path.lineTo(SkBits2Float(0x424f2d54), SkBits2Float(0xc1f24d85));
+path.cubicTo(SkBits2Float(0x424b5a2a), SkBits2Float(0xc1ff6268), SkBits2Float(0x42473840), SkBits2Float(0xc2060c56), SkBits2Float(0x4242cb24), SkBits2Float(0xc20c32b1));
+path.cubicTo(SkBits2Float(0x4215b1b4), SkBits2Float(0xc24adc20), SkBits2Float(0x419a6875), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x428f4c27), SkBits2Float(0xc22797c0));
+path.cubicTo(SkBits2Float(0x42bc6513), SkBits2Float(0xc055a915), SkBits2Float(0x42a45eb2), SkBits2Float(0x42389acf), SkBits2Float(0x4231df29), SkBits2Float(0x428c2a69));
+path.lineTo(SkBits2Float(0x420094fc), SkBits2Float(0x424aa62f));
+path.cubicTo(SkBits2Float(0x426da4ad), SkBits2Float(0x42057300), SkBits2Float(0x42883065), SkBits2Float(0xc01a7416), SkBits2Float(0x424f2d56), SkBits2Float(0xc1f24d87));
+path.lineTo(SkBits2Float(0x428f4c27), SkBits2Float(0xc22797c0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp49(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41eed329), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4265a038), SkBits2Float(0xc285ef96), SkBits2Float(0x42905111), SkBits2Float(0xc2240eac));
+path.lineTo(SkBits2Float(0x4250a68d), SkBits2Float(0xc1ed30fa));
+path.cubicTo(SkBits2Float(0x4225fe9e), SkBits2Float(0xc241a46c), SkBits2Float(0x41aca4fc), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42905111), SkBits2Float(0xc2240ead));
+path.cubicTo(SkBits2Float(0x429332f8), SkBits2Float(0xc219ea36), SkBits2Float(0x4295cfef), SkBits2Float(0xc20f79c4), SkBits2Float(0x4298252c), SkBits2Float(0xc204c875));
+path.lineTo(SkBits2Float(0x425bf80f), SkBits2Float(0xc1bff9b9));
+path.cubicTo(SkBits2Float(0x42589896), SkBits2Float(0xc1cf6f48), SkBits2Float(0x4254d168), SkBits2Float(0xc1de8710), SkBits2Float(0x4250a68e), SkBits2Float(0xc1ed30fc));
+path.lineTo(SkBits2Float(0x42905111), SkBits2Float(0xc2240ead));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp50(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41eed328), SkBits2Float(0xc2a60000), SkBits2Float(0x4265a038), SkBits2Float(0xc285ef96), SkBits2Float(0x42905111), SkBits2Float(0xc2240ead));
+path.lineTo(SkBits2Float(0x42905111), SkBits2Float(0xc2240eac));
+path.cubicTo(SkBits2Float(0x429332f8), SkBits2Float(0xc219ea35), SkBits2Float(0x4295cfef), SkBits2Float(0xc20f79c4), SkBits2Float(0x4298252c), SkBits2Float(0xc204c875));
+path.lineTo(SkBits2Float(0x425bf80f), SkBits2Float(0xc1bff9b9));
+path.cubicTo(SkBits2Float(0x42589896), SkBits2Float(0xc1cf6f48), SkBits2Float(0x4254d168), SkBits2Float(0xc1de8710), SkBits2Float(0x4250a68d), SkBits2Float(0xc1ed30fa));
+path.cubicTo(SkBits2Float(0x4225fe9e), SkBits2Float(0xc241a46c), SkBits2Float(0x41aca4fc), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4298252d), SkBits2Float(0xc204c875));
+path.cubicTo(SkBits2Float(0x42ab560c), SkBits2Float(0xc1334da0), SkBits2Float(0x42aa8ee6), SkBits2Float(0x415dbf57), SkBits2Float(0x4296030d), SkBits2Float(0x420e292a));
+path.cubicTo(SkBits2Float(0x42817734), SkBits2Float(0x4264e27f), SkBits2Float(0x42365290), SkBits2Float(0x4292cae0), SkBits2Float(0x41b3e39e), SkBits2Float(0x429fcac3));
+path.lineTo(SkBits2Float(0x41820a52), SkBits2Float(0x4267064e));
+path.cubicTo(SkBits2Float(0x4203cca7), SkBits2Float(0x42543ae9), SkBits2Float(0x423b2de4), SkBits2Float(0x42257578), SkBits2Float(0x4258e27d), SkBits2Float(0x41cd88a1));
+path.cubicTo(SkBits2Float(0x42769717), SkBits2Float(0x41204ca2), SkBits2Float(0x4277b705), SkBits2Float(0xc1019de9), SkBits2Float(0x425bf810), SkBits2Float(0xc1bff9bb));
+path.lineTo(SkBits2Float(0x4298252d), SkBits2Float(0xc204c875));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp51(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42044d64), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427bf9ef), SkBits2Float(0xc27d72ab), SkBits2Float(0x42984d42), SkBits2Float(0xc2041029));
+path.lineTo(SkBits2Float(0x425c3202), SkBits2Float(0xc1beef44));
+path.cubicTo(SkBits2Float(0x423626cb), SkBits2Float(0xc2373722), SkBits2Float(0x41bf47cb), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42984d42), SkBits2Float(0xc2041029));
+path.cubicTo(SkBits2Float(0x429adc06), SkBits2Float(0xc1f08771), SkBits2Float(0x429d127e), SkBits2Float(0xc1d85b80), SkBits2Float(0x429eedcc), SkBits2Float(0xc1bfbbc5));
+path.lineTo(SkBits2Float(0x4265c6d6), SkBits2Float(0xc18a9a3f));
+path.cubicTo(SkBits2Float(0x426317a7), SkBits2Float(0xc19c6729), SkBits2Float(0x425fe4aa), SkBits2Float(0xc1ade05f), SkBits2Float(0x425c3203), SkBits2Float(0xc1beef45));
+path.lineTo(SkBits2Float(0x42984d42), SkBits2Float(0xc2041029));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp52(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42044d64), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427bf9ef), SkBits2Float(0xc27d72ab), SkBits2Float(0x42984d42), SkBits2Float(0xc2041029));
+path.cubicTo(SkBits2Float(0x429adc06), SkBits2Float(0xc1f08771), SkBits2Float(0x429d127e), SkBits2Float(0xc1d85b80), SkBits2Float(0x429eedcc), SkBits2Float(0xc1bfbbc5));
+path.lineTo(SkBits2Float(0x4265c6d6), SkBits2Float(0xc18a9a3f));
+path.cubicTo(SkBits2Float(0x426317a7), SkBits2Float(0xc19c6729), SkBits2Float(0x425fe4aa), SkBits2Float(0xc1ade05f), SkBits2Float(0x425c3202), SkBits2Float(0xc1beef44));
+path.cubicTo(SkBits2Float(0x423626cb), SkBits2Float(0xc2373722), SkBits2Float(0x41bf47cb), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429eedcc), SkBits2Float(0xc1bfbbc6));
+path.cubicTo(SkBits2Float(0x42ae408c), SkBits2Float(0x3fb7daeb), SkBits2Float(0x42a45c89), SkBits2Float(0x41e7c57e), SkBits2Float(0x42845101), SkBits2Float(0x42487bac));
+path.cubicTo(SkBits2Float(0x42488af1), SkBits2Float(0x428e8a4c), SkBits2Float(0x41c7bd0e), SkBits2Float(0x42a6f806), SkBits2Float(0xbfc7d871), SkBits2Float(0x42a5f87b));
+path.lineTo(SkBits2Float(0xbf90777c), SkBits2Float(0x426ff521));
+path.cubicTo(SkBits2Float(0x419063a9), SkBits2Float(0x42716698), SkBits2Float(0x4210f87e), SkBits2Float(0x424e1511), SkBits2Float(0x423f4d05), SkBits2Float(0x4210ed75));
+path.cubicTo(SkBits2Float(0x426da18c), SkBits2Float(0x41a78bb1), SkBits2Float(0x427bee4d), SkBits2Float(0x3f84e856), SkBits2Float(0x4265c6d8), SkBits2Float(0xc18a9a40));
+path.lineTo(SkBits2Float(0x429eedcc), SkBits2Float(0xc1bfbbc6));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp53(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x421216db), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4289817d), SkBits2Float(0xc26c814f), SkBits2Float(0x429ecb3a), SkBits2Float(0xc1c183ed));
+path.lineTo(SkBits2Float(0x426594dc), SkBits2Float(0xc18be3fc));
+path.cubicTo(SkBits2Float(0x4246cdba), SkBits2Float(0xc22af7b1), SkBits2Float(0x41d336a3), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429ecb3a), SkBits2Float(0xc1c183e9));
+path.cubicTo(SkBits2Float(0x42a0d9cb), SkBits2Float(0xc1a68281), SkBits2Float(0x42a27999), SkBits2Float(0xc18b01ce), SkBits2Float(0x42a3a81d), SkBits2Float(0xc15e595d));
+path.lineTo(SkBits2Float(0x426c9cb2), SkBits2Float(0xc120bbfa));
+path.cubicTo(SkBits2Float(0x426ae754), SkBits2Float(0xc148f95c), SkBits2Float(0x42688e2a), SkBits2Float(0xc170bcb0), SkBits2Float(0x426594dd), SkBits2Float(0xc18be3fd));
+path.lineTo(SkBits2Float(0x429ecb3a), SkBits2Float(0xc1c183e9));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp54(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return;
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x421216db), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4289817d), SkBits2Float(0xc26c814f), SkBits2Float(0x429ecb3a), SkBits2Float(0xc1c183ed));
+path.lineTo(SkBits2Float(0x42a3a81d), SkBits2Float(0xc15e595d));
+path.lineTo(SkBits2Float(0x426c9cb2), SkBits2Float(0xc120bbfa));
+path.cubicTo(SkBits2Float(0x426ae754), SkBits2Float(0xc148f95c), SkBits2Float(0x42688e2a), SkBits2Float(0xc170bcb0), SkBits2Float(0x426594dd), SkBits2Float(0xc18be3fd));
+path.lineTo(SkBits2Float(0x426594dc), SkBits2Float(0xc18be3fc));
+path.cubicTo(SkBits2Float(0x4246cdba), SkBits2Float(0xc22af7b1), SkBits2Float(0x41d336a3), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a3a81d), SkBits2Float(0xc15e595e));
+path.cubicTo(SkBits2Float(0x42ad725e), SkBits2Float(0x416ed313), SkBits2Float(0x42982fa2), SkBits2Float(0x4230cc44), SkBits2Float(0x42575fca), SkBits2Float(0x427ca963));
+path.cubicTo(SkBits2Float(0x41fcc0a1), SkBits2Float(0x42a44341), SkBits2Float(0x3f80ed4e), SkBits2Float(0x42affc4e), SkBits2Float(0xc1d56b7f), SkBits2Float(0x429d3115));
+path.lineTo(SkBits2Float(0xc19a478e), SkBits2Float(0x426343e2));
+path.cubicTo(SkBits2Float(0x3f3a6666), SkBits2Float(0x427e6fe0), SkBits2Float(0x41b6b66f), SkBits2Float(0x426d7d04), SkBits2Float(0x421bb135), SkBits2Float(0x4236a5a5));
+path.cubicTo(SkBits2Float(0x425c0733), SkBits2Float(0x41ff9c8c), SkBits2Float(0x427ac435), SkBits2Float(0x412ca4f2), SkBits2Float(0x426c9cb3), SkBits2Float(0xc120bbf8));
+path.lineTo(SkBits2Float(0x42a3a81d), SkBits2Float(0xc15e595e));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp55(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4220aa02), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42952310), SkBits2Float(0xc258f48d), SkBits2Float(0x42a35f68), SkBits2Float(0xc16b5614));
+path.lineTo(SkBits2Float(0x426c3395), SkBits2Float(0xc12a1f61));
+path.cubicTo(SkBits2Float(0x42579ea8), SkBits2Float(0xc21cd5ce), SkBits2Float(0x41e84916), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a35f69), SkBits2Float(0xc16b5613));
+path.cubicTo(SkBits2Float(0x42a4bd24), SkBits2Float(0xc12ea3c2), SkBits2Float(0x42a59325), SkBits2Float(0xc0e282d6), SkBits2Float(0x42a5dfdf), SkBits2Float(0xc04e84a0));
+path.lineTo(SkBits2Float(0x426fd18d), SkBits2Float(0xc0154a48));
+path.cubicTo(SkBits2Float(0x426f62a1), SkBits2Float(0xc0a3be33), SkBits2Float(0x426e2d39), SkBits2Float(0xc0fc7dbb), SkBits2Float(0x426c3397), SkBits2Float(0xc12a1f63));
+path.lineTo(SkBits2Float(0x42a35f69), SkBits2Float(0xc16b5613));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp56(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4220aa02), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42952310), SkBits2Float(0xc258f48d), SkBits2Float(0x42a35f69), SkBits2Float(0xc16b5613));
+path.cubicTo(SkBits2Float(0x42a4bd24), SkBits2Float(0xc12ea3c2), SkBits2Float(0x42a59325), SkBits2Float(0xc0e282d6), SkBits2Float(0x42a5dfdf), SkBits2Float(0xc04e84a0));
+path.lineTo(SkBits2Float(0x426fd18d), SkBits2Float(0xc0154a48));
+path.cubicTo(SkBits2Float(0x426f62a1), SkBits2Float(0xc0a3be33), SkBits2Float(0x426e2d39), SkBits2Float(0xc0fc7dbb), SkBits2Float(0x426c3397), SkBits2Float(0xc12a1f63));
+path.lineTo(SkBits2Float(0x426c3395), SkBits2Float(0xc12a1f61));
+path.cubicTo(SkBits2Float(0x42579ea8), SkBits2Float(0xc21cd5ce), SkBits2Float(0x41e84916), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a5dfdf), SkBits2Float(0xc04e84a0));
+path.cubicTo(SkBits2Float(0x42a85e4f), SkBits2Float(0x41e6959e), SkBits2Float(0x4285b4e3), SkBits2Float(0x426ae44f), SkBits2Float(0x4219b105), SkBits2Float(0x42932450));
+path.cubicTo(SkBits2Float(0x411fe111), SkBits2Float(0x42b0d679), SkBits2Float(0xc1c3966b), SkBits2Float(0x42ab1d42), SkBits2Float(0xc2482755), SkBits2Float(0x428470e8));
+path.lineTo(SkBits2Float(0xc210b07c), SkBits2Float(0x423f7b24));
+path.cubicTo(SkBits2Float(0xc18d6382), SkBits2Float(0x427764e8), SkBits2Float(0x40e72680), SkBits2Float(0x427fab4e), SkBits2Float(0x41de345e), SkBits2Float(0x4254bc3b));
+path.cubicTo(SkBits2Float(0x42414f8e), SkBits2Float(0x4229cd28), SkBits2Float(0x42736c9d), SkBits2Float(0x41a6b008), SkBits2Float(0x426fd18e), SkBits2Float(0xc0154a3f));
+path.lineTo(SkBits2Float(0x42a5dfdf), SkBits2Float(0xc04e84a0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp57(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x422b8e0b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x429d6dbc), SkBits2Float(0xc2494bad), SkBits2Float(0x42a54cb6), SkBits2Float(0xc0f3b760));
+path.lineTo(SkBits2Float(0x426efcca), SkBits2Float(0xc0b02e2c));
+path.cubicTo(SkBits2Float(0x42639b94), SkBits2Float(0xc21183d2), SkBits2Float(0x41f807f9), SkBits2Float(0xc2700000), SkBits2Float(0xb630015b), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a54cb7), SkBits2Float(0xc0f3b757));
+path.cubicTo(SkBits2Float(0x42a60d08), SkBits2Float(0xc0628d9e), SkBits2Float(0x42a632b1), SkBits2Float(0x3f0efcd8), SkBits2Float(0x42a5bd61), SkBits2Float(0x4094a90a));
+path.lineTo(SkBits2Float(0x426f9faf), SkBits2Float(0x4056ee3d));
+path.cubicTo(SkBits2Float(0x42704949), SkBits2Float(0x3ecebaba), SkBits2Float(0x427012d8), SkBits2Float(0xc023c5fe), SkBits2Float(0x426efccb), SkBits2Float(0xc0b02e2d));
+path.lineTo(SkBits2Float(0x42a54cb7), SkBits2Float(0xc0f3b757));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp58(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb630015b), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x422b8e0b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x429d6dbc), SkBits2Float(0xc2494bad), SkBits2Float(0x42a54cb7), SkBits2Float(0xc0f3b757));
+path.cubicTo(SkBits2Float(0x42a60d08), SkBits2Float(0xc0628d9e), SkBits2Float(0x42a632b1), SkBits2Float(0x3f0efcd8), SkBits2Float(0x42a5bd61), SkBits2Float(0x4094a90a));
+path.lineTo(SkBits2Float(0x426f9faf), SkBits2Float(0x4056ee3d));
+path.cubicTo(SkBits2Float(0x42704949), SkBits2Float(0x3ecebaba), SkBits2Float(0x427012d8), SkBits2Float(0xc023c5fe), SkBits2Float(0x426efcca), SkBits2Float(0xc0b02e2c));
+path.cubicTo(SkBits2Float(0x42639b94), SkBits2Float(0xc21183d2), SkBits2Float(0x41f807f9), SkBits2Float(0xc2700000), SkBits2Float(0xb630015b), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a5bd62), SkBits2Float(0x4094a90c));
+path.cubicTo(SkBits2Float(0x42a1e9d4), SkBits2Float(0x421b17cd), SkBits2Float(0x426944f3), SkBits2Float(0x428879ea), SkBits2Float(0x41ceac14), SkBits2Float(0x429dc116));
+path.cubicTo(SkBits2Float(0xc0d4c6f5), SkBits2Float(0x42b30843), SkBits2Float(0xc2295516), SkBits2Float(0x429e4e8b), SkBits2Float(0xc2802142), SkBits2Float(0x4253148e));
+path.lineTo(SkBits2Float(0xc2393f81), SkBits2Float(0x42189693));
+path.cubicTo(SkBits2Float(0xc1f4d162), SkBits2Float(0x4264e09b), SkBits2Float(0xc099d099), SkBits2Float(0x42816bc3), SkBits2Float(0x419566d0), SkBits2Float(0x42641418));
+path.cubicTo(SkBits2Float(0x4228a0e3), SkBits2Float(0x424550a9), SkBits2Float(0x426a177b), SkBits2Float(0x41e03b19), SkBits2Float(0x426f9fb0), SkBits2Float(0x4056ee3a));
+path.lineTo(SkBits2Float(0x42a5bd62), SkBits2Float(0x4094a90c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp59(skiatest::Reporter* reporter, const char* filename) { // hung
+ if (!FLAGS_runFail) {
+ return;
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x423693bc), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42a57249), SkBits2Float(0xc2389374), SkBits2Float(0x42a5ff3a), SkBits2Float(0xbf002494));
+path.lineTo(SkBits2Float(0x426ffee2), SkBits2Float(0xbeb944c3));
+path.cubicTo(SkBits2Float(0x426f331d), SkBits2Float(0xc2056daf), SkBits2Float(0x4203fbc4), SkBits2Float(0xc2700000), SkBits2Float(0xb560056c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a5ff3a), SkBits2Float(0xbf0024e6));
+path.cubicTo(SkBits2Float(0x42a60c9b), SkBits2Float(0x40752b0d), SkBits2Float(0x42a56c5d), SkBits2Float(0x410284fd), SkBits2Float(0x42a41ffb), SkBits2Float(0x414709fb));
+path.lineTo(SkBits2Float(0x426d49ff), SkBits2Float(0x410fe233));
+path.cubicTo(SkBits2Float(0x426f2a8e), SkBits2Float(0x40bcb3f0), SkBits2Float(0x42701239), SkBits2Float(0x40313ae3), SkBits2Float(0x426ffee3), SkBits2Float(0xbeb944c6));
+path.lineTo(SkBits2Float(0x42a5ff3a), SkBits2Float(0xbf0024e6));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp60(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e9334c2), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f13342a), SkBits2Float(0xc2a5ff3c), SkBits2Float(0x3f5ccd0d), SkBits2Float(0xc2a5fdb4));
+path.lineTo(SkBits2Float(0x3f1f9d85), SkBits2Float(0xc26ffcaf));
+path.cubicTo(SkBits2Float(0x3ed4d324), SkBits2Float(0xc26ffee7), SkBits2Float(0x3e54d404), SkBits2Float(0xc2700000), SkBits2Float(0x36b23f68), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f5ccd1a), SkBits2Float(0xc2a5fdb5));
+path.cubicTo(SkBits2Float(0x3f642956), SkBits2Float(0xc2a5fd8c), SkBits2Float(0x3f6b855d), SkBits2Float(0xc2a5fd63), SkBits2Float(0x3f72e163), SkBits2Float(0xc2a5fd38));
+path.lineTo(SkBits2Float(0x3f2f9381), SkBits2Float(0xc26ffbfc));
+path.cubicTo(SkBits2Float(0x3f2a4188), SkBits2Float(0xc26ffc3b), SkBits2Float(0x3f24ef95), SkBits2Float(0xc26ffc76), SkBits2Float(0x3f1f9da0), SkBits2Float(0xc26ffcb0));
+path.lineTo(SkBits2Float(0x3f5ccd1a), SkBits2Float(0xc2a5fdb5));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp61(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36b23f68), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e9334c2), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f13342a), SkBits2Float(0xc2a5ff3c), SkBits2Float(0x3f5ccd1a), SkBits2Float(0xc2a5fdb5));
+path.cubicTo(SkBits2Float(0x3f642956), SkBits2Float(0xc2a5fd8c), SkBits2Float(0x3f6b855d), SkBits2Float(0xc2a5fd63), SkBits2Float(0x3f72e163), SkBits2Float(0xc2a5fd38));
+path.lineTo(SkBits2Float(0x3f2f9381), SkBits2Float(0xc26ffbfc));
+path.cubicTo(SkBits2Float(0x3f2a4188), SkBits2Float(0xc26ffc3b), SkBits2Float(0x3f24ef95), SkBits2Float(0xc26ffc76), SkBits2Float(0x3f1f9d85), SkBits2Float(0xc26ffcaf));
+path.cubicTo(SkBits2Float(0x3ed4d324), SkBits2Float(0xc26ffee7), SkBits2Float(0x3e54d404), SkBits2Float(0xc2700000), SkBits2Float(0x36b23f68), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f72e162), SkBits2Float(0xc2a5fd39));
+path.cubicTo(SkBits2Float(0x3fb51288), SkBits2Float(0xc2a5fa80), SkBits2Float(0x3ff0b297), SkBits2Float(0xc2a5f5c4), SkBits2Float(0x401627a5), SkBits2Float(0xc2a5ef06));
+path.lineTo(SkBits2Float(0x3fd9177b), SkBits2Float(0xc26fe773));
+path.cubicTo(SkBits2Float(0x3fadff90), SkBits2Float(0xc26ff134), SkBits2Float(0x3f82e54e), SkBits2Float(0xc26ff80c), SkBits2Float(0x3f2f9393), SkBits2Float(0xc26ffbfc));
+path.lineTo(SkBits2Float(0x3f72e162), SkBits2Float(0xc2a5fd39));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp62(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f614848), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3fe14683), SkBits2Float(0xc2a5f8d5), SkBits2Float(0x4028ee0f), SkBits2Float(0xc2a5ea81));
+path.lineTo(SkBits2Float(0x3ff43c76), SkBits2Float(0xc26fe0ec));
+path.cubicTo(SkBits2Float(0x3fa2d98a), SkBits2Float(0xc26ff5a4), SkBits2Float(0x3f22dad5), SkBits2Float(0xc2700000), SkBits2Float(0xb5420574), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4028ee15), SkBits2Float(0xc2a5ea81));
+path.cubicTo(SkBits2Float(0x402e8f25), SkBits2Float(0xc2a5e912), SkBits2Float(0x40343026), SkBits2Float(0xc2a5e791), SkBits2Float(0x4039d111), SkBits2Float(0xc2a5e5fd));
+path.lineTo(SkBits2Float(0x4006533c), SkBits2Float(0xc26fda66));
+path.cubicTo(SkBits2Float(0x4002419e), SkBits2Float(0xc26fdcaf), SkBits2Float(0x3ffc5fdb), SkBits2Float(0xc26fdedc), SkBits2Float(0x3ff43c61), SkBits2Float(0xc26fe0ed));
+path.lineTo(SkBits2Float(0x4028ee15), SkBits2Float(0xc2a5ea81));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp63(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return;
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f614848), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3fe14683), SkBits2Float(0xc2a5f8d5), SkBits2Float(0x4028ee15), SkBits2Float(0xc2a5ea81));
+path.cubicTo(SkBits2Float(0x402e8f25), SkBits2Float(0xc2a5e912), SkBits2Float(0x40343026), SkBits2Float(0xc2a5e791), SkBits2Float(0x4039d111), SkBits2Float(0xc2a5e5fd));
+path.lineTo(SkBits2Float(0x4006533c), SkBits2Float(0xc26fda66));
+path.cubicTo(SkBits2Float(0x400241a2), SkBits2Float(0xc26fdcaf), SkBits2Float(0x3ffc5fea), SkBits2Float(0xc26fdedc), SkBits2Float(0x3ff43c76), SkBits2Float(0xc26fe0ec));
+path.cubicTo(SkBits2Float(0x3fa2d98a), SkBits2Float(0xc26ff5a4), SkBits2Float(0x3f22dad5), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+path.moveTo(SkBits2Float(0x40186abb), SkBits2Float(0xc295b297));
+path.lineTo(SkBits2Float(0x3ff43c61), SkBits2Float(0xc26fe0ed));
+path.lineTo(SkBits2Float(0x3ff43c77), SkBits2Float(0xc26fe0ed));
+path.lineTo(SkBits2Float(0x40186abb), SkBits2Float(0xc295b297));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4039d102), SkBits2Float(0xc2a5e5fe));
+path.cubicTo(SkBits2Float(0x408a83ff), SkBits2Float(0xc2a5cc72), SkBits2Float(0x40b8130f), SkBits2Float(0xc2a5a01a), SkBits2Float(0x40e58a06), SkBits2Float(0xc2a56100));
+path.lineTo(SkBits2Float(0x40a5ee90), SkBits2Float(0xc26f1a20));
+path.cubicTo(SkBits2Float(0x408510de), SkBits2Float(0xc26f755e), SkBits2Float(0x40484386), SkBits2Float(0xc26fb57a), SkBits2Float(0x40065347), SkBits2Float(0xc26fda68));
+path.lineTo(SkBits2Float(0x4039d102), SkBits2Float(0xc2a5e5fe));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp64(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3faf587e), SkBits2Float(0xc2a5ffff), SkBits2Float(0x402f5505), SkBits2Float(0xc2a5eea1), SkBits2Float(0x408372de), SkBits2Float(0xc2a5cbeb));
+path.lineTo(SkBits2Float(0x403e0bd0), SkBits2Float(0xc26fb4b6));
+path.cubicTo(SkBits2Float(0x3ffd7de6), SkBits2Float(0xc26fe6e6), SkBits2Float(0x3f7d82fb), SkBits2Float(0xc2700000), SkBits2Float(0x363f7eb2), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x408372d6), SkBits2Float(0xc2a5cbec));
+path.cubicTo(SkBits2Float(0x4087d39d), SkBits2Float(0xc2a5c874), SkBits2Float(0x408c3440), SkBits2Float(0xc2a5c4cf), SkBits2Float(0x409094bd), SkBits2Float(0xc2a5c0fe));
+path.lineTo(SkBits2Float(0x40510866), SkBits2Float(0xc26fa4e7));
+path.cubicTo(SkBits2Float(0x404ab468), SkBits2Float(0xc26faa6c), SkBits2Float(0x40446037), SkBits2Float(0xc26fafb2), SkBits2Float(0x403e0bd2), SkBits2Float(0xc26fb4b7));
+path.lineTo(SkBits2Float(0x408372d6), SkBits2Float(0xc2a5cbec));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp65(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x363f7eb2), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3faf5872), SkBits2Float(0xc2a60000), SkBits2Float(0x402f54f9), SkBits2Float(0xc2a5eea1), SkBits2Float(0x408372d5), SkBits2Float(0xc2a5cbeb));
+path.lineTo(SkBits2Float(0x408372d6), SkBits2Float(0xc2a5cbec));
+path.cubicTo(SkBits2Float(0x4087d39d), SkBits2Float(0xc2a5c874), SkBits2Float(0x408c3440), SkBits2Float(0xc2a5c4cf), SkBits2Float(0x409094bd), SkBits2Float(0xc2a5c0fe));
+path.lineTo(SkBits2Float(0x40510866), SkBits2Float(0xc26fa4e7));
+path.cubicTo(SkBits2Float(0x404ab468), SkBits2Float(0xc26faa6c), SkBits2Float(0x40446037), SkBits2Float(0xc26fafb2), SkBits2Float(0x403e0bd0), SkBits2Float(0xc26fb4b6));
+path.cubicTo(SkBits2Float(0x3ffd7de6), SkBits2Float(0xc26fe6e6), SkBits2Float(0x3f7d82fb), SkBits2Float(0xc2700000), SkBits2Float(0x363f7eb2), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x409094be), SkBits2Float(0xc2a5c0fe));
+path.cubicTo(SkBits2Float(0x40d784bb), SkBits2Float(0xc2a5831d), SkBits2Float(0x410f22d3), SkBits2Float(0xc2a517ba), SkBits2Float(0x413255ec), SkBits2Float(0xc2a47f15));
+path.lineTo(SkBits2Float(0x4100ead4), SkBits2Float(0xc26dd37e));
+path.cubicTo(SkBits2Float(0x40cef193), SkBits2Float(0xc26eb02f), SkBits2Float(0x409bcbdf), SkBits2Float(0xc26f4b72), SkBits2Float(0x40510859), SkBits2Float(0xc26fa4e8));
+path.lineTo(SkBits2Float(0x409094be), SkBits2Float(0xc2a5c0fe));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp66(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4037e518), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40b7d534), SkBits2Float(0xc2a5b39a), SkBits2Float(0x4109a47d), SkBits2Float(0xc2a51b1f));
+path.lineTo(SkBits2Float(0x40c70051), SkBits2Float(0xc26eb519));
+path.cubicTo(SkBits2Float(0x4084e427), SkBits2Float(0xc26f918c), SkBits2Float(0x4004efa4), SkBits2Float(0xc26fffff), SkBits2Float(0x3543fa8c), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4109a47c), SkBits2Float(0xc2a51b20));
+path.cubicTo(SkBits2Float(0x410e36d1), SkBits2Float(0xc2a50be2), SkBits2Float(0x4112c883), SkBits2Float(0xc2a4fbe1), SkBits2Float(0x41175985), SkBits2Float(0xc2a4eb1d));
+path.lineTo(SkBits2Float(0x40dad196), SkBits2Float(0xc26e6faf));
+path.cubicTo(SkBits2Float(0x40d4377d), SkBits2Float(0xc26e87ed), SkBits2Float(0x40cd9c5c), SkBits2Float(0xc26e9f10), SkBits2Float(0x40c7004e), SkBits2Float(0xc26eb51a));
+path.lineTo(SkBits2Float(0x4109a47c), SkBits2Float(0xc2a51b20));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp67(skiatest::Reporter* reporter, const char* filename) { // crashed
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4037e518), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40b7d534), SkBits2Float(0xc2a5b39a), SkBits2Float(0x4109a47c), SkBits2Float(0xc2a51b20));
+path.cubicTo(SkBits2Float(0x410e36d1), SkBits2Float(0xc2a50be2), SkBits2Float(0x4112c883), SkBits2Float(0xc2a4fbe1), SkBits2Float(0x41175985), SkBits2Float(0xc2a4eb1d));
+path.lineTo(SkBits2Float(0x40dad196), SkBits2Float(0xc26e6faf));
+path.cubicTo(SkBits2Float(0x40d4377e), SkBits2Float(0xc26e87ed), SkBits2Float(0x40cd9c5f), SkBits2Float(0xc26e9f10), SkBits2Float(0x40c70052), SkBits2Float(0xc26eb51a));
+path.lineTo(SkBits2Float(0x40c70051), SkBits2Float(0xc26eb519));
+path.cubicTo(SkBits2Float(0x4084e427), SkBits2Float(0xc26f918c), SkBits2Float(0x4004efa4), SkBits2Float(0xc26fffff), SkBits2Float(0x00000000), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4117597f), SkBits2Float(0xc2a4eb1d));
+path.cubicTo(SkBits2Float(0x41616445), SkBits2Float(0xc2a3db51), SkBits2Float(0x41954b2d), SkBits2Float(0xc2a2048b), SkBits2Float(0x41b914a4), SkBits2Float(0xc29f6bcb));
+path.lineTo(SkBits2Float(0x4185cb10), SkBits2Float(0xc2667d00));
+path.cubicTo(SkBits2Float(0x4157d8a2), SkBits2Float(0xc26a3e17), SkBits2Float(0x4122ef07), SkBits2Float(0xc26ce6b9), SkBits2Float(0x40dad195), SkBits2Float(0xc26e6faf));
+path.lineTo(SkBits2Float(0x4117597f), SkBits2Float(0xc2a4eb1d));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp68(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e1b2207), SkBits2Float(0xc2a60000), SkBits2Float(0x3e9b2105), SkBits2Float(0xc2a5ffca), SkBits2Float(0x3ee8b0c0), SkBits2Float(0xc2a5ff5d));
+path.lineTo(SkBits2Float(0x3ea83563), SkBits2Float(0xc26fff14));
+path.cubicTo(SkBits2Float(0x3e60486a), SkBits2Float(0xc26fffb2), SkBits2Float(0x3de049e3), SkBits2Float(0xc2700000), SkBits2Float(0x36b67768), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ee8b040), SkBits2Float(0xc2a5ff5d));
+path.cubicTo(SkBits2Float(0x3ef0720a), SkBits2Float(0xc2a5ff52), SkBits2Float(0x3ef83386), SkBits2Float(0xc2a5ff47), SkBits2Float(0x3efff501), SkBits2Float(0xc2a5ff3b));
+path.lineTo(SkBits2Float(0x3eb90778), SkBits2Float(0xc26ffee3));
+path.cubicTo(SkBits2Float(0x3eb36c27), SkBits2Float(0xc26ffef6), SkBits2Float(0x3eadd0dd), SkBits2Float(0xc26fff07), SkBits2Float(0x3ea83592), SkBits2Float(0xc26fff16));
+path.lineTo(SkBits2Float(0x3ee8b040), SkBits2Float(0xc2a5ff5d));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp69(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36b67768), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e1b21b2), SkBits2Float(0xc2a60000), SkBits2Float(0x3e9b20b0), SkBits2Float(0xc2a5ffca), SkBits2Float(0x3ee8b040), SkBits2Float(0xc2a5ff5d));
+path.cubicTo(SkBits2Float(0x3ef0720a), SkBits2Float(0xc2a5ff52), SkBits2Float(0x3ef83386), SkBits2Float(0xc2a5ff47), SkBits2Float(0x3efff501), SkBits2Float(0xc2a5ff3b));
+path.lineTo(SkBits2Float(0x3eb90778), SkBits2Float(0xc26ffee3));
+path.lineTo(SkBits2Float(0x3ea83592), SkBits2Float(0xc26fff16));
+path.lineTo(SkBits2Float(0x3ea83563), SkBits2Float(0xc26fff14));
+path.cubicTo(SkBits2Float(0x3e60486a), SkBits2Float(0xc26fffb2), SkBits2Float(0x3de049e3), SkBits2Float(0xc2700000), SkBits2Float(0x36b67768), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3efff501), SkBits2Float(0xc2a5ff3b));
+path.cubicTo(SkBits2Float(0x3f3ed289), SkBits2Float(0xc2a5fe79), SkBits2Float(0x3f7daa5c), SkBits2Float(0xc2a5fd28), SkBits2Float(0x3f9e4099), SkBits2Float(0xc2a5fb49));
+path.lineTo(SkBits2Float(0x3f64cc5f), SkBits2Float(0xc26ff92f));
+path.cubicTo(SkBits2Float(0x3f375f8f), SkBits2Float(0xc26ffbe5), SkBits2Float(0x3f09f1cf), SkBits2Float(0xc26ffdcc), SkBits2Float(0x3eb9075f), SkBits2Float(0xc26ffee4));
+path.lineTo(SkBits2Float(0x3efff501), SkBits2Float(0xc2a5ff3b));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp70(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f0938d2), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f893841), SkBits2Float(0xc2a5fd56), SkBits2Float(0x3fcdd137), SkBits2Float(0xc2a5f805));
+path.lineTo(SkBits2Float(0x3f94c89b), SkBits2Float(0xc26ff478));
+path.cubicTo(SkBits2Float(0x3f4663c1), SkBits2Float(0xc26ffc29), SkBits2Float(0x3ec6647d), SkBits2Float(0xc2700000), SkBits2Float(0x360ebeb2), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3fcdd13c), SkBits2Float(0xc2a5f806));
+path.cubicTo(SkBits2Float(0x3fd4ad55), SkBits2Float(0xc2a5f77d), SkBits2Float(0x3fdb895f), SkBits2Float(0xc2a5f6ef), SkBits2Float(0x3fe26560), SkBits2Float(0xc2a5f659));
+path.lineTo(SkBits2Float(0x3fa3a8ea), SkBits2Float(0xc26ff20c));
+path.cubicTo(SkBits2Float(0x3f9eb37e), SkBits2Float(0xc26ff2e6), SkBits2Float(0x3f99be11), SkBits2Float(0xc26ff3b4), SkBits2Float(0x3f94c89e), SkBits2Float(0xc26ff479));
+path.lineTo(SkBits2Float(0x3fcdd13c), SkBits2Float(0xc2a5f806));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp71(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x360ebeb2), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f0938d2), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f893841), SkBits2Float(0xc2a5fd56), SkBits2Float(0x3fcdd13c), SkBits2Float(0xc2a5f806));
+path.cubicTo(SkBits2Float(0x3fd4ad55), SkBits2Float(0xc2a5f77d), SkBits2Float(0x3fdb895f), SkBits2Float(0xc2a5f6ef), SkBits2Float(0x3fe26560), SkBits2Float(0xc2a5f659));
+path.lineTo(SkBits2Float(0x3fa3a8ea), SkBits2Float(0xc26ff20c));
+path.cubicTo(SkBits2Float(0x3f9eb37e), SkBits2Float(0xc26ff2e6), SkBits2Float(0x3f99be11), SkBits2Float(0xc26ff3b4), SkBits2Float(0x3f94c89b), SkBits2Float(0xc26ff478));
+path.cubicTo(SkBits2Float(0x3f4663c1), SkBits2Float(0xc26ffc29), SkBits2Float(0x3ec6647d), SkBits2Float(0xc2700000), SkBits2Float(0x360ebeb2), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3fe26566), SkBits2Float(0xc2a5f65a));
+path.cubicTo(SkBits2Float(0x4028c729), SkBits2Float(0xc2a5ecdf), SkBits2Float(0x406055f2), SkBits2Float(0xc2a5dc6a), SkBits2Float(0x408beceb), SkBits2Float(0xc2a5c4fb));
+path.lineTo(SkBits2Float(0x404a4d47), SkBits2Float(0xc26faaae));
+path.cubicTo(SkBits2Float(0x40222b9c), SkBits2Float(0xc26fcc90), SkBits2Float(0x3ff40427), SkBits2Float(0xc26fe45b), SkBits2Float(0x3fa3a8ee), SkBits2Float(0xc26ff20e));
+path.lineTo(SkBits2Float(0x3fe26566), SkBits2Float(0xc2a5f65a));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp72(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f73aa4a), SkBits2Float(0xc2a60000), SkBits2Float(0x3ff3a7f0), SkBits2Float(0xc2a5f79e), SkBits2Float(0x4036b54b), SkBits2Float(0xc2a5e6db));
+path.lineTo(SkBits2Float(0x40041412), SkBits2Float(0xc26fdba5));
+path.cubicTo(SkBits2Float(0x3fb0230c), SkBits2Float(0xc26ff3e0), SkBits2Float(0x3f3024c1), SkBits2Float(0xc26fffff), SkBits2Float(0x359dfd4a), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4036b55d), SkBits2Float(0xc2a5e6db));
+path.cubicTo(SkBits2Float(0x403ccbdf), SkBits2Float(0xc2a5e52d), SkBits2Float(0x4042e24c), SkBits2Float(0xc2a5e36a), SkBits2Float(0x4048f89e), SkBits2Float(0xc2a5e192));
+path.lineTo(SkBits2Float(0x401147bc), SkBits2Float(0xc26fd403));
+path.cubicTo(SkBits2Float(0x400ce144), SkBits2Float(0xc26fd6ae), SkBits2Float(0x40087ab2), SkBits2Float(0xc26fd939), SkBits2Float(0x4004140f), SkBits2Float(0xc26fdba5));
+path.lineTo(SkBits2Float(0x4036b55d), SkBits2Float(0xc2a5e6db));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end fail 1
+
+static void battleOp73(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40447e19), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40c46ab2), SkBits2Float(0xc2a5a8c7), SkBits2Float(0x4113078c), SkBits2Float(0xc2a4fabe));
+path.lineTo(SkBits2Float(0x40d4929e), SkBits2Float(0xc26e8647));
+path.cubicTo(SkBits2Float(0x408dfcf1), SkBits2Float(0xc26f81e6), SkBits2Float(0x400e0af8), SkBits2Float(0xc2700000), SkBits2Float(0x3655fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4113078b), SkBits2Float(0xc2a4fabe));
+path.cubicTo(SkBits2Float(0x4117e908), SkBits2Float(0xc2a4e957), SkBits2Float(0x411cc9c0), SkBits2Float(0xc2a4d714), SkBits2Float(0x4121a9a1), SkBits2Float(0xc2a4c3f3));
+path.lineTo(SkBits2Float(0x40e9baad), SkBits2Float(0xc26e370e));
+path.cubicTo(SkBits2Float(0x40e2ae85), SkBits2Float(0xc26e52b6), SkBits2Float(0x40dba120), SkBits2Float(0xc26e6d20), SkBits2Float(0x40d4929a), SkBits2Float(0xc26e8647));
+path.lineTo(SkBits2Float(0x4113078b), SkBits2Float(0xc2a4fabe));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end fail 1
+
+static void battleOp74(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x406db78d), SkBits2Float(0xc2a60000), SkBits2Float(0x40ed953d), SkBits2Float(0xc2a58058), SkBits2Float(0x4131afb7), SkBits2Float(0xc2a481e4));
+path.lineTo(SkBits2Float(0x410072b2), SkBits2Float(0xc26dd78e));
+path.cubicTo(SkBits2Float(0x40abbf2e), SkBits2Float(0xc26f4770), SkBits2Float(0x402bd807), SkBits2Float(0xc2700000), SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4131afba), SkBits2Float(0xc2a481e4));
+path.cubicTo(SkBits2Float(0x413792dd), SkBits2Float(0xc2a46874), SkBits2Float(0x413d74a2), SkBits2Float(0xc2a44dc1), SkBits2Float(0x414354e9), SkBits2Float(0xc2a431ca));
+path.lineTo(SkBits2Float(0x410d3424), SkBits2Float(0xc26d63c0));
+path.cubicTo(SkBits2Float(0x4108f4b6), SkBits2Float(0xc26d8c2e), SkBits2Float(0x4104b435), SkBits2Float(0xc26db2c8), SkBits2Float(0x410072b4), SkBits2Float(0xc26dd78e));
+path.lineTo(SkBits2Float(0x4131afba), SkBits2Float(0xc2a481e4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp75(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x406db78d), SkBits2Float(0xc2a60000), SkBits2Float(0x40ed953d), SkBits2Float(0xc2a58058), SkBits2Float(0x4131afba), SkBits2Float(0xc2a481e4));
+path.cubicTo(SkBits2Float(0x413792dd), SkBits2Float(0xc2a46874), SkBits2Float(0x413d74a2), SkBits2Float(0xc2a44dc1), SkBits2Float(0x414354e9), SkBits2Float(0xc2a431ca));
+path.lineTo(SkBits2Float(0x410d3424), SkBits2Float(0xc26d63c0));
+path.cubicTo(SkBits2Float(0x4108f4b6), SkBits2Float(0xc26d8c2e), SkBits2Float(0x4104b435), SkBits2Float(0xc26db2c8), SkBits2Float(0x410072b2), SkBits2Float(0xc26dd78e));
+path.cubicTo(SkBits2Float(0x40abbf2e), SkBits2Float(0xc26f4770), SkBits2Float(0x402bd807), SkBits2Float(0xc2700000), SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x414354ed), SkBits2Float(0xc2a431cb));
+path.cubicTo(SkBits2Float(0x419152e5), SkBits2Float(0xc2a26c3a), SkBits2Float(0x41c0119b), SkBits2Float(0xc29f5c06), SkBits2Float(0x41ed1335), SkBits2Float(0xc29b0f0a));
+path.lineTo(SkBits2Float(0x41ab612b), SkBits2Float(0xc2602e6b));
+path.cubicTo(SkBits2Float(0x418ad84d), SkBits2Float(0xc2666635), SkBits2Float(0x41521b54), SkBits2Float(0xc26ad3fe), SkBits2Float(0x410d3426), SkBits2Float(0xc26d63c0));
+path.lineTo(SkBits2Float(0x414354ed), SkBits2Float(0xc2a431cb));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp76(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40932e58), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41130dbc), SkBits2Float(0xc2a53c41), SkBits2Float(0x415ba178), SkBits2Float(0xc2a3b6ca));
+path.lineTo(SkBits2Float(0x411ec4eb), SkBits2Float(0xc26cb1eb));
+path.cubicTo(SkBits2Float(0x40d49b93), SkBits2Float(0xc26ee4ff), SkBits2Float(0x4054cab9), SkBits2Float(0xc26fffff), SkBits2Float(0x35f7fd46), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x415ba178), SkBits2Float(0xc2a3b6cb));
+path.cubicTo(SkBits2Float(0x4162e261), SkBits2Float(0xc2a38fde), SkBits2Float(0x416a20aa), SkBits2Float(0xc2a36704), SkBits2Float(0x41715c23), SkBits2Float(0xc2a33c3e));
+path.lineTo(SkBits2Float(0x412e7a25), SkBits2Float(0xc26c00bd));
+path.cubicTo(SkBits2Float(0x41293fb6), SkBits2Float(0xc26c3e94), SkBits2Float(0x41240342), SkBits2Float(0xc26c79a4), SkBits2Float(0x411ec4e8), SkBits2Float(0xc26cb1eb));
+path.lineTo(SkBits2Float(0x415ba178), SkBits2Float(0xc2a3b6cb));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end fail 1
+
+static void battleOp77(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40d0158a), SkBits2Float(0xc2a60000), SkBits2Float(0x414fb944), SkBits2Float(0xc2a478c0), SkBits2Float(0x419a74b5), SkBits2Float(0xc2a1724b));
+path.lineTo(SkBits2Float(0x415f4f4c), SkBits2Float(0xc2696aa5));
+path.cubicTo(SkBits2Float(0x41162967), SkBits2Float(0xc26dca57), SkBits2Float(0x40966c1f), SkBits2Float(0xc2700000), SkBits2Float(0x3655fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x419a74b6), SkBits2Float(0xc2a1724b));
+path.cubicTo(SkBits2Float(0x419f8274), SkBits2Float(0xc2a124ef), SkBits2Float(0x41a48c82), SkBits2Float(0xc2a0d3c9), SkBits2Float(0x41a9929f), SkBits2Float(0xc2a07edb));
+path.lineTo(SkBits2Float(0x41752a58), SkBits2Float(0xc2680ab0));
+path.cubicTo(SkBits2Float(0x416de6e6), SkBits2Float(0xc268857b), SkBits2Float(0x41669dc0), SkBits2Float(0xc268facf), SkBits2Float(0x415f4f4b), SkBits2Float(0xc2696aa6));
+path.lineTo(SkBits2Float(0x419a74b6), SkBits2Float(0xc2a1724b));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp78(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3655fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40d0158a), SkBits2Float(0xc2a60000), SkBits2Float(0x414fb944), SkBits2Float(0xc2a478c0), SkBits2Float(0x419a74b6), SkBits2Float(0xc2a1724b));
+path.cubicTo(SkBits2Float(0x419f8274), SkBits2Float(0xc2a124ef), SkBits2Float(0x41a48c82), SkBits2Float(0xc2a0d3c9), SkBits2Float(0x41a9929f), SkBits2Float(0xc2a07edb));
+path.lineTo(SkBits2Float(0x41752a58), SkBits2Float(0xc2680ab0));
+path.cubicTo(SkBits2Float(0x416de6e6), SkBits2Float(0xc268857b), SkBits2Float(0x41669dc0), SkBits2Float(0xc268facf), SkBits2Float(0x415f4f4c), SkBits2Float(0xc2696aa5));
+path.cubicTo(SkBits2Float(0x41162967), SkBits2Float(0xc26dca57), SkBits2Float(0x40966c1f), SkBits2Float(0xc2700000), SkBits2Float(0x3655fea3), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41a9929f), SkBits2Float(0xc2a07edc));
+path.cubicTo(SkBits2Float(0x41fb3aee), SkBits2Float(0xc29b1a71), SkBits2Float(0x422402f4), SkBits2Float(0xc291ddaf), SkBits2Float(0x4245eaa6), SkBits2Float(0xc2854763));
+path.lineTo(SkBits2Float(0x420f1280), SkBits2Float(0xc240b13c));
+path.cubicTo(SkBits2Float(0x41ed200b), SkBits2Float(0xc252e3f9), SkBits2Float(0x41b59cbb), SkBits2Float(0xc2603ee8), SkBits2Float(0x41752a58), SkBits2Float(0xc2680aaf));
+path.lineTo(SkBits2Float(0x41a9929f), SkBits2Float(0xc2a07edc));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp79(skiatest::Reporter* reporter, const char* filename) { //crashed
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4110a0cc), SkBits2Float(0xc2a60000), SkBits2Float(0x4190247a), SkBits2Float(0xc2a30bfe), SkBits2Float(0x41d4a5dc), SkBits2Float(0xc29d41d4));
+path.lineTo(SkBits2Float(0x4199b8a9), SkBits2Float(0xc2635c16));
+path.cubicTo(SkBits2Float(0x4150660f), SkBits2Float(0xc26bbaf8), SkBits2Float(0x40d119d0), SkBits2Float(0xc2700000), SkBits2Float(0x3673fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41d4a5d9), SkBits2Float(0xc29d41d4));
+path.cubicTo(SkBits2Float(0x41db7bbd), SkBits2Float(0xc29cadef), SkBits2Float(0x41e247df), SkBits2Float(0xc29c12ec), SkBits2Float(0x41e9098d), SkBits2Float(0xc29b70d9));
+path.lineTo(SkBits2Float(0x41a875f1), SkBits2Float(0xc260bbd5));
+path.cubicTo(SkBits2Float(0x41a39393), SkBits2Float(0xc261a627), SkBits2Float(0x419ea9a6), SkBits2Float(0xc2628645), SkBits2Float(0x4199b8ab), SkBits2Float(0xc2635c17));
+path.lineTo(SkBits2Float(0x41d4a5d9), SkBits2Float(0xc29d41d4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp80(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e15a675), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3e95a67a), SkBits2Float(0xc2a5ffcd), SkBits2Float(0x3ee07980), SkBits2Float(0xc2a5ff68));
+path.lineTo(SkBits2Float(0x3ea245bb), SkBits2Float(0xc26fff25));
+path.cubicTo(SkBits2Float(0x3e585de0), SkBits2Float(0xc26fffb9), SkBits2Float(0x3dd85f11), SkBits2Float(0xc2700000), SkBits2Float(0x3691e768), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ee07a10), SkBits2Float(0xc2a5ff68));
+path.cubicTo(SkBits2Float(0x3ee7f565), SkBits2Float(0xc2a5ff5d), SkBits2Float(0x3eef70d9), SkBits2Float(0xc2a5ff52), SkBits2Float(0x3ef6ec4d), SkBits2Float(0xc2a5ff47));
+path.lineTo(SkBits2Float(0x3eb27fdb), SkBits2Float(0xc26ffef6));
+path.cubicTo(SkBits2Float(0x3ead1768), SkBits2Float(0xc26fff07), SkBits2Float(0x3ea7aebe), SkBits2Float(0xc26fff17), SkBits2Float(0x3ea24612), SkBits2Float(0xc26fff26));
+path.lineTo(SkBits2Float(0x3ee07a10), SkBits2Float(0xc2a5ff68));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp81(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3691e768), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e15a675), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3e95a67a), SkBits2Float(0xc2a5ffcd), SkBits2Float(0x3ee07a10), SkBits2Float(0xc2a5ff68));
+path.lineTo(SkBits2Float(0x3ef6ec4d), SkBits2Float(0xc2a5ff47));
+path.lineTo(SkBits2Float(0x3eb27fdb), SkBits2Float(0xc26ffef6));
+path.cubicTo(SkBits2Float(0x3ead1768), SkBits2Float(0xc26fff07), SkBits2Float(0x3ea7aebe), SkBits2Float(0xc26fff17), SkBits2Float(0x3ea245bb), SkBits2Float(0xc26fff25));
+path.cubicTo(SkBits2Float(0x3e585de0), SkBits2Float(0xc26fffb9), SkBits2Float(0x3dd85f11), SkBits2Float(0xc2700000), SkBits2Float(0x3691e768), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ef6ec9b), SkBits2Float(0xc2a5ff48));
+path.cubicTo(SkBits2Float(0x3f3816c9), SkBits2Float(0xc2a5fe94), SkBits2Float(0x3f74b6e1), SkBits2Float(0xc2a5fd5b), SkBits2Float(0x3f98ab0b), SkBits2Float(0xc2a5fb9d));
+path.lineTo(SkBits2Float(0x3f5cb973), SkBits2Float(0xc26ff9a8));
+path.cubicTo(SkBits2Float(0x3f30e6e7), SkBits2Float(0xc26ffc2e), SkBits2Float(0x3f05138e), SkBits2Float(0xc26ffdf2), SkBits2Float(0x3eb27fc6), SkBits2Float(0xc26ffef7));
+path.lineTo(SkBits2Float(0x3ef6ec9b), SkBits2Float(0xc2a5ff48));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp82(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3eff98a5), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f7f97b3), SkBits2Float(0xc2a5fdb1), SkBits2Float(0x3fbfaf38), SkBits2Float(0xc2a5f914));
+path.lineTo(SkBits2Float(0x3f8a9112), SkBits2Float(0xc26ff600));
+path.cubicTo(SkBits2Float(0x3f38c3e7), SkBits2Float(0xc26ffcab), SkBits2Float(0x3eb8c475), SkBits2Float(0xc2700000), SkBits2Float(0x35877d28), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3fbfaf15), SkBits2Float(0xc2a5f915));
+path.cubicTo(SkBits2Float(0x3fc612b4), SkBits2Float(0xc2a5f8a0), SkBits2Float(0x3fcc7634), SkBits2Float(0xc2a5f824), SkBits2Float(0x3fd2d9ad), SkBits2Float(0xc2a5f7a2));
+path.lineTo(SkBits2Float(0x3f986bef), SkBits2Float(0xc26ff3e6));
+path.cubicTo(SkBits2Float(0x3f93cdb9), SkBits2Float(0xc26ff4a2), SkBits2Float(0x3f8f2f70), SkBits2Float(0xc26ff556), SkBits2Float(0x3f8a9121), SkBits2Float(0xc26ff601));
+path.lineTo(SkBits2Float(0x3fbfaf15), SkBits2Float(0xc2a5f915));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp83(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3eff9875), SkBits2Float(0xc2a60000), SkBits2Float(0x3f7f9783), SkBits2Float(0xc2a5fdb1), SkBits2Float(0x3fbfaf14), SkBits2Float(0xc2a5f914));
+path.lineTo(SkBits2Float(0x3fbfaf15), SkBits2Float(0xc2a5f915));
+path.cubicTo(SkBits2Float(0x3fc612b4), SkBits2Float(0xc2a5f8a0), SkBits2Float(0x3fcc7634), SkBits2Float(0xc2a5f824), SkBits2Float(0x3fd2d9ad), SkBits2Float(0xc2a5f7a2));
+path.lineTo(SkBits2Float(0x3f986bef), SkBits2Float(0xc26ff3e6));
+path.cubicTo(SkBits2Float(0x3f93cdb9), SkBits2Float(0xc26ff4a2), SkBits2Float(0x3f8f2f70), SkBits2Float(0xc26ff556), SkBits2Float(0x3f8a9112), SkBits2Float(0xc26ff600));
+path.cubicTo(SkBits2Float(0x3f38c3e7), SkBits2Float(0xc26ffcab), SkBits2Float(0x3eb8c475), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3fd2d994), SkBits2Float(0xc2a5f7a1));
+path.cubicTo(SkBits2Float(0x401d305c), SkBits2Float(0xc2a5ef69), SkBits2Float(0x4050ef71), SkBits2Float(0xc2a5e123), SkBits2Float(0x408252dc), SkBits2Float(0xc2a5ccd0));
+path.lineTo(SkBits2Float(0x403c6b7d), SkBits2Float(0xc26fb5fe));
+path.cubicTo(SkBits2Float(0x401709a2), SkBits2Float(0xc26fd362), SkBits2Float(0x3fe342dd), SkBits2Float(0xc26fe805), SkBits2Float(0x3f986be0), SkBits2Float(0xc26ff3e7));
+path.lineTo(SkBits2Float(0x3fd2d994), SkBits2Float(0xc2a5f7a1));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp84(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f541e8b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3fd41d19), SkBits2Float(0xc2a5f9a6), SkBits2Float(0x401f1022), SkBits2Float(0xc2a5ecf2));
+path.lineTo(SkBits2Float(0x3fe5f882), SkBits2Float(0xc26fe473));
+path.cubicTo(SkBits2Float(0x3f9955cf), SkBits2Float(0xc26ff6d2), SkBits2Float(0x3f1956dc), SkBits2Float(0xc2700000), SkBits2Float(0xb5bb02d8), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x401f1027), SkBits2Float(0xc2a5ecf2));
+path.cubicTo(SkBits2Float(0x40245d21), SkBits2Float(0xc2a5ebac), SkBits2Float(0x4029aa04), SkBits2Float(0xc2a5ea57), SkBits2Float(0x402ef6d6), SkBits2Float(0xc2a5e8f1));
+path.lineTo(SkBits2Float(0x3ffcf5ba), SkBits2Float(0xc26fdeaa));
+path.cubicTo(SkBits2Float(0x3ff54c2d), SkBits2Float(0xc26fe0b0), SkBits2Float(0x3feda268), SkBits2Float(0xc26fe29e), SkBits2Float(0x3fe5f88e), SkBits2Float(0xc26fe474));
+path.lineTo(SkBits2Float(0x401f1027), SkBits2Float(0xc2a5ecf2));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp85(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return;
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f541e8b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3fd41d19), SkBits2Float(0xc2a5f9a6), SkBits2Float(0x401f1027), SkBits2Float(0xc2a5ecf2));
+path.cubicTo(SkBits2Float(0x40245d21), SkBits2Float(0xc2a5ebac), SkBits2Float(0x4029aa04), SkBits2Float(0xc2a5ea57), SkBits2Float(0x402ef6d6), SkBits2Float(0xc2a5e8f1));
+path.lineTo(SkBits2Float(0x3ffcf5ba), SkBits2Float(0xc26fdeaa));
+path.cubicTo(SkBits2Float(0x3ff54c2d), SkBits2Float(0xc26fe0b0), SkBits2Float(0x3feda268), SkBits2Float(0xc26fe29e), SkBits2Float(0x3fe5f882), SkBits2Float(0xc26fe473));
+path.cubicTo(SkBits2Float(0x3f9955cf), SkBits2Float(0xc26ff6d2), SkBits2Float(0x3f1956dc), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x402ef6c3), SkBits2Float(0xc2a5e8f1));
+path.cubicTo(SkBits2Float(0x40826d68), SkBits2Float(0xc2a5d24c), SkBits2Float(0x40ad550a), SkBits2Float(0xc2a5aafb), SkBits2Float(0x40d82890), SkBits2Float(0xc2a57308));
+path.lineTo(SkBits2Float(0x409c425c), SkBits2Float(0xc26f3430));
+path.cubicTo(SkBits2Float(0x407a99d8), SkBits2Float(0xc26f8515), SkBits2Float(0x403c91e6), SkBits2Float(0xc26fbded), SkBits2Float(0x3ffcf5ca), SkBits2Float(0xc26fdeaa));
+path.lineTo(SkBits2Float(0x402ef6c3), SkBits2Float(0xc2a5e8f1));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp86(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40155bee), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40955364), SkBits2Float(0xc2a5cd99), SkBits2Float(0x40dfbd5f), SkBits2Float(0xc2a568f2));
+path.lineTo(SkBits2Float(0x40a1bd53), SkBits2Float(0xc26f259d));
+path.cubicTo(SkBits2Float(0x4057e483), SkBits2Float(0xc26fb724), SkBits2Float(0x3fd7f0d9), SkBits2Float(0xc2700000), SkBits2Float(0x3619fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40dfbd5e), SkBits2Float(0xc2a568f3));
+path.cubicTo(SkBits2Float(0x40e72e1b), SkBits2Float(0xc2a55ee2), SkBits2Float(0x40ee9e1c), SkBits2Float(0xc2a55452), SkBits2Float(0x40f60d62), SkBits2Float(0xc2a54941));
+path.lineTo(SkBits2Float(0x40b1de84), SkBits2Float(0xc26ef7c9));
+path.cubicTo(SkBits2Float(0x40ac7ea0), SkBits2Float(0xc26f07cb), SkBits2Float(0x40a71e37), SkBits2Float(0xc26f1712), SkBits2Float(0x40a1bd4f), SkBits2Float(0xc26f259f));
+path.lineTo(SkBits2Float(0x40dfbd5e), SkBits2Float(0xc2a568f3));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp87(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3619fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40155bee), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40955364), SkBits2Float(0xc2a5cd99), SkBits2Float(0x40dfbd5e), SkBits2Float(0xc2a568f3));
+path.cubicTo(SkBits2Float(0x40e72e1b), SkBits2Float(0xc2a55ee2), SkBits2Float(0x40ee9e1c), SkBits2Float(0xc2a55452), SkBits2Float(0x40f60d62), SkBits2Float(0xc2a54941));
+path.lineTo(SkBits2Float(0x40b1de84), SkBits2Float(0xc26ef7c9));
+path.cubicTo(SkBits2Float(0x40ac7ea2), SkBits2Float(0xc26f07cb), SkBits2Float(0x40a71e3a), SkBits2Float(0xc26f1712), SkBits2Float(0x40a1bd54), SkBits2Float(0xc26f259f));
+path.lineTo(SkBits2Float(0x40a1bd53), SkBits2Float(0xc26f259d));
+path.cubicTo(SkBits2Float(0x4057e483), SkBits2Float(0xc26fb724), SkBits2Float(0x3fd7f0d9), SkBits2Float(0xc2700000), SkBits2Float(0x3619fea3), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40f60d69), SkBits2Float(0xc2a54941));
+path.cubicTo(SkBits2Float(0x41374a21), SkBits2Float(0xc2a495d5), SkBits2Float(0x41731962), SkBits2Float(0xc2a35eca), SkBits2Float(0x419704b1), SkBits2Float(0xc2a1a64c));
+path.lineTo(SkBits2Float(0x415a56f5), SkBits2Float(0xc269b5d4));
+path.cubicTo(SkBits2Float(0x412fbbfb), SkBits2Float(0xc26c32af), SkBits2Float(0x41047f9a), SkBits2Float(0xc26df463), SkBits2Float(0x40b1de7e), SkBits2Float(0xc26ef7cb));
+path.lineTo(SkBits2Float(0x40f60d69), SkBits2Float(0xc2a54941));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp88(skiatest::Reporter* reporter, const char* filename) { // crashed
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4059d383), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40d9b918), SkBits2Float(0xc2a594d0), SkBits2Float(0x4122e820), SkBits2Float(0xc2a4bf0c));
+path.lineTo(SkBits2Float(0x40eb871c), SkBits2Float(0xc26e2ff8));
+path.cubicTo(SkBits2Float(0x409d63e0), SkBits2Float(0xc26f6508), SkBits2Float(0x401d76fa), SkBits2Float(0xc2700000), SkBits2Float(0x35f7fd4a), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4122e81e), SkBits2Float(0xc2a4bf0c));
+path.cubicTo(SkBits2Float(0x41284f3c), SkBits2Float(0xc2a4a9ac), SkBits2Float(0x412db549), SkBits2Float(0xc2a4933e), SkBits2Float(0x41331a33), SkBits2Float(0xc2a47bbf));
+path.lineTo(SkBits2Float(0x410178be), SkBits2Float(0xc26dceac));
+path.cubicTo(SkBits2Float(0x40fb24f7), SkBits2Float(0xc26df0a4), SkBits2Float(0x40f356d1), SkBits2Float(0xc26e1114), SkBits2Float(0x40eb871f), SkBits2Float(0xc26e2ff8));
+path.lineTo(SkBits2Float(0x4122e81e), SkBits2Float(0xc2a4bf0c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp89(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3dd41fb8), SkBits2Float(0xc2a5fffe), SkBits2Float(0x3e541e5b), SkBits2Float(0xc2a5ffe5), SkBits2Float(0x3e9f1657), SkBits2Float(0xc2a5ffb2));
+path.lineTo(SkBits2Float(0x3e66012b), SkBits2Float(0xc26fff92));
+path.cubicTo(SkBits2Float(0x3e1955e2), SkBits2Float(0xc26fffdc), SkBits2Float(0x3d99560b), SkBits2Float(0xc2700000), SkBits2Float(0x350f7780), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3e9f1626), SkBits2Float(0xc2a5ffb4));
+path.cubicTo(SkBits2Float(0x3ea463a8), SkBits2Float(0xc2a5ffae), SkBits2Float(0x3ea9b10b), SkBits2Float(0xc2a5ffa8), SkBits2Float(0x3eaefe6d), SkBits2Float(0xc2a5ffa3));
+path.lineTo(SkBits2Float(0x3e7d0144), SkBits2Float(0xc26fff7b));
+path.cubicTo(SkBits2Float(0x3e75568f), SkBits2Float(0xc26fff84), SkBits2Float(0x3e6dac12), SkBits2Float(0xc26fff8c), SkBits2Float(0x3e660197), SkBits2Float(0xc26fff93));
+path.lineTo(SkBits2Float(0x3e9f1626), SkBits2Float(0xc2a5ffb4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp90(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3dd41f74), SkBits2Float(0xc2a5fffe), SkBits2Float(0x3e541e17), SkBits2Float(0xc2a5ffe5), SkBits2Float(0x3e9f1624), SkBits2Float(0xc2a5ffb2));
+path.lineTo(SkBits2Float(0x3e9f1626), SkBits2Float(0xc2a5ffb4));
+path.cubicTo(SkBits2Float(0x3ea463a8), SkBits2Float(0xc2a5ffae), SkBits2Float(0x3ea9b10b), SkBits2Float(0xc2a5ffa8), SkBits2Float(0x3eaefe6d), SkBits2Float(0xc2a5ffa3));
+path.lineTo(SkBits2Float(0x3e7d0144), SkBits2Float(0xc26fff7b));
+path.cubicTo(SkBits2Float(0x3e75568f), SkBits2Float(0xc26fff84), SkBits2Float(0x3e6dac12), SkBits2Float(0xc26fff8c), SkBits2Float(0x3e66012b), SkBits2Float(0xc26fff92));
+path.cubicTo(SkBits2Float(0x3e1955e2), SkBits2Float(0xc26fffdc), SkBits2Float(0x3d99560b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3eaefebc), SkBits2Float(0xc2a5ffa4));
+path.cubicTo(SkBits2Float(0x3f0276b7), SkBits2Float(0xc2a5ff4a), SkBits2Float(0x3f2d6dea), SkBits2Float(0xc2a5feac), SkBits2Float(0x3f5864cc), SkBits2Float(0xc2a5fdcd));
+path.lineTo(SkBits2Float(0x3f1c6df6), SkBits2Float(0xc26ffcd0));
+path.cubicTo(SkBits2Float(0x3efabdec), SkBits2Float(0xc26ffe15), SkBits2Float(0x3ebc9f78), SkBits2Float(0xc26ffef9), SkBits2Float(0x3e7d0190), SkBits2Float(0xc26fff7c));
+path.lineTo(SkBits2Float(0x3eaefebc), SkBits2Float(0xc2a5ffa4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp91(skiatest::Reporter* reporter, const char* filename) { // crashed
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ec1e1ad), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f41e136), SkBits2Float(0xc2a5feac), SkBits2Float(0x3f9167c6), SkBits2Float(0xc2a5fc05));
+path.lineTo(SkBits2Float(0x3f523979), SkBits2Float(0xc26ffa3f));
+path.cubicTo(SkBits2Float(0x3f0c2737), SkBits2Float(0xc26ffe17), SkBits2Float(0x3e8c2756), SkBits2Float(0xc2700000), SkBits2Float(0xb5b74260), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f9167c1), SkBits2Float(0xc2a5fc05));
+path.cubicTo(SkBits2Float(0x3f96406f), SkBits2Float(0xc2a5fbc1), SkBits2Float(0x3f9b1917), SkBits2Float(0xc2a5fb79), SkBits2Float(0x3f9ff1bc), SkBits2Float(0xc2a5fb2f));
+path.lineTo(SkBits2Float(0x3f673ed7), SkBits2Float(0xc26ff909));
+path.cubicTo(SkBits2Float(0x3f603cf4), SkBits2Float(0xc26ff977), SkBits2Float(0x3f593b3c), SkBits2Float(0xc26ff9dd), SkBits2Float(0x3f52397f), SkBits2Float(0xc26ffa3f));
+path.lineTo(SkBits2Float(0x3f9167c1), SkBits2Float(0xc2a5fc05));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp92(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e2c5962), SkBits2Float(0xc2a60000), SkBits2Float(0x3eac58ef), SkBits2Float(0xc2a5ffbd), SkBits2Float(0x3f014269), SkBits2Float(0xc2a5ff37));
+path.lineTo(SkBits2Float(0x3ebae1ca), SkBits2Float(0xc26ffedd));
+path.cubicTo(SkBits2Float(0x3e792d51), SkBits2Float(0xc26fff9f), SkBits2Float(0x3df92dfa), SkBits2Float(0xc2700000), SkBits2Float(0x36163ed0), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f014292), SkBits2Float(0xc2a5ff37));
+path.cubicTo(SkBits2Float(0x3f0591a2), SkBits2Float(0xc2a5ff28), SkBits2Float(0x3f09e09b), SkBits2Float(0xc2a5ff1a), SkBits2Float(0x3f0e2f92), SkBits2Float(0xc2a5ff0b));
+path.lineTo(SkBits2Float(0x3ecd91e5), SkBits2Float(0xc26ffea0));
+path.cubicTo(SkBits2Float(0x3ec75718), SkBits2Float(0xc26ffeb6), SkBits2Float(0x3ec11c70), SkBits2Float(0xc26ffeca), SkBits2Float(0x3ebae1c7), SkBits2Float(0xc26ffedd));
+path.lineTo(SkBits2Float(0x3f014292), SkBits2Float(0xc2a5ff37));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp93(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36163ed0), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.quadTo(SkBits2Float(0x3e81430a), SkBits2Float(0xc2a60000), SkBits2Float(0x3f014292), SkBits2Float(0xc2a5ff37));
+path.cubicTo(SkBits2Float(0x3f0591a2), SkBits2Float(0xc2a5ff28), SkBits2Float(0x3f09e09b), SkBits2Float(0xc2a5ff1a), SkBits2Float(0x3f0e2f92), SkBits2Float(0xc2a5ff0b));
+path.lineTo(SkBits2Float(0x3ecd91e5), SkBits2Float(0xc26ffea0));
+path.cubicTo(SkBits2Float(0x3ec75719), SkBits2Float(0xc26ffeb6), SkBits2Float(0x3ec11c72), SkBits2Float(0xc26ffeca), SkBits2Float(0x3ebae1ca), SkBits2Float(0xc26ffedd));
+path.quadTo(SkBits2Float(0x3e3ae230), SkBits2Float(0xc2700000), SkBits2Float(0x36163ed0), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f0e2f94), SkBits2Float(0xc2a5ff0c));
+path.cubicTo(SkBits2Float(0x3f5401b9), SkBits2Float(0xc2a5fe1c), SkBits2Float(0x3f8ce9a3), SkBits2Float(0xc2a5fc7d), SkBits2Float(0x3fafd1bd), SkBits2Float(0xc2a5fa2d));
+path.lineTo(SkBits2Float(0x3f7e3238), SkBits2Float(0xc26ff796));
+path.cubicTo(SkBits2Float(0x3f4bbaca), SkBits2Float(0xc26ffaee), SkBits2Float(0x3f194226), SkBits2Float(0xc26ffd46), SkBits2Float(0x3ecd9202), SkBits2Float(0xc26ffea0));
+path.lineTo(SkBits2Float(0x3f0e2f94), SkBits2Float(0xc2a5ff0c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp94(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f167e4a), SkBits2Float(0xc2a60000), SkBits2Float(0x3f967d97), SkBits2Float(0xc2a5fcce), SkBits2Float(0x3fe1b83b), SkBits2Float(0xc2a5f668));
+path.lineTo(SkBits2Float(0x3fa32ba2), SkBits2Float(0xc26ff222));
+path.cubicTo(SkBits2Float(0x3f599370), SkBits2Float(0xc26ffb61), SkBits2Float(0x3ed9943c), SkBits2Float(0xc2700000), SkBits2Float(0x3437e940), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3fe1b817), SkBits2Float(0xc2a5f668));
+path.cubicTo(SkBits2Float(0x3fe93dd6), SkBits2Float(0xc2a5f5c4), SkBits2Float(0x3ff0c3a7), SkBits2Float(0xc2a5f518), SkBits2Float(0x3ff8496b), SkBits2Float(0xc2a5f464));
+path.lineTo(SkBits2Float(0x3fb37c11), SkBits2Float(0xc26fef38));
+path.cubicTo(SkBits2Float(0x3fae0bf9), SkBits2Float(0xc26ff03c), SkBits2Float(0x3fa89bd2), SkBits2Float(0xc26ff134), SkBits2Float(0x3fa32ba2), SkBits2Float(0xc26ff222));
+path.lineTo(SkBits2Float(0x3fe1b817), SkBits2Float(0xc2a5f668));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp95(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f167e32), SkBits2Float(0xc2a60000), SkBits2Float(0x3f967d7f), SkBits2Float(0xc2a5fcce), SkBits2Float(0x3fe1b817), SkBits2Float(0xc2a5f668));
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ff8497f), SkBits2Float(0xc2a5f465));
+path.cubicTo(SkBits2Float(0x40391895), SkBits2Float(0xc2a5e8fe), SkBits2Float(0x407604f1), SkBits2Float(0xc2a5d533), SkBits2Float(0x40997177), SkBits2Float(0xc2a5b905));
+path.lineTo(SkBits2Float(0x405dd87f), SkBits2Float(0xc26f9962));
+path.cubicTo(SkBits2Float(0x4031d867), SkBits2Float(0xc26fc221), SkBits2Float(0x4005cdec), SkBits2Float(0xc26fdebf), SkBits2Float(0x3fb37c22), SkBits2Float(0xc26fef39));
+path.lineTo(SkBits2Float(0x3ff8497f), SkBits2Float(0xc2a5f465));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp96(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3fa966bb), SkBits2Float(0xc2a5ffff), SkBits2Float(0x402963a4), SkBits2Float(0xc2a5efcb), SkBits2Float(0x407dfe39), SkBits2Float(0xc2a5cf64));
+path.lineTo(SkBits2Float(0x40379c05), SkBits2Float(0xc26fb9ba));
+path.cubicTo(SkBits2Float(0x3ff4e689), SkBits2Float(0xc26fe893), SkBits2Float(0x3f74eb1f), SkBits2Float(0xc2700000), SkBits2Float(0x363f7e94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x407dfe3a), SkBits2Float(0xc2a5cf65));
+path.cubicTo(SkBits2Float(0x40833a01), SkBits2Float(0xc2a5cc27), SkBits2Float(0x408774bf), SkBits2Float(0xc2a5c8c0), SkBits2Float(0x408baf5a), SkBits2Float(0xc2a5c52f));
+path.lineTo(SkBits2Float(0x4049f448), SkBits2Float(0xc26faaf9));
+path.cubicTo(SkBits2Float(0x4043d713), SkBits2Float(0xc26fb022), SkBits2Float(0x403db99f), SkBits2Float(0xc26fb50d), SkBits2Float(0x40379bfe), SkBits2Float(0xc26fb9bc));
+path.lineTo(SkBits2Float(0x407dfe3a), SkBits2Float(0xc2a5cf65));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp97(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x363f7e94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3fa966bb), SkBits2Float(0xc2a5ffff), SkBits2Float(0x402963a4), SkBits2Float(0xc2a5efcb), SkBits2Float(0x407dfe3a), SkBits2Float(0xc2a5cf65));
+path.cubicTo(SkBits2Float(0x40833a01), SkBits2Float(0xc2a5cc27), SkBits2Float(0x408774bf), SkBits2Float(0xc2a5c8c0), SkBits2Float(0x408baf5a), SkBits2Float(0xc2a5c52f));
+path.lineTo(SkBits2Float(0x4049f448), SkBits2Float(0xc26faaf9));
+path.cubicTo(SkBits2Float(0x4043d716), SkBits2Float(0xc26fb022), SkBits2Float(0x403db9a5), SkBits2Float(0xc26fb50d), SkBits2Float(0x40379c07), SkBits2Float(0xc26fb9bc));
+path.lineTo(SkBits2Float(0x40379c05), SkBits2Float(0xc26fb9ba));
+path.cubicTo(SkBits2Float(0x3ff4e689), SkBits2Float(0xc26fe893), SkBits2Float(0x3f74eb1f), SkBits2Float(0xc2700000), SkBits2Float(0x363f7e94), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x408baf5c), SkBits2Float(0xc2a5c530));
+path.cubicTo(SkBits2Float(0x40d03963), SkBits2Float(0xc2a58b6e), SkBits2Float(0x410a4c7d), SkBits2Float(0xc2a52732), SkBits2Float(0x412c535f), SkBits2Float(0xc2a498b2));
+path.lineTo(SkBits2Float(0x40f9253d), SkBits2Float(0xc26df886));
+path.cubicTo(SkBits2Float(0x40c7f32d), SkBits2Float(0xc26ec68d), SkBits2Float(0x409685fb), SkBits2Float(0xc26f577a), SkBits2Float(0x4049f441), SkBits2Float(0xc26faafa));
+path.lineTo(SkBits2Float(0x408baf5c), SkBits2Float(0xc2a5c530));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp98(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40155bee), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40955364), SkBits2Float(0xc2a5cd99), SkBits2Float(0x40dfbd5f), SkBits2Float(0xc2a568f2));
+path.lineTo(SkBits2Float(0x40a1bd53), SkBits2Float(0xc26f259d));
+path.cubicTo(SkBits2Float(0x4057e483), SkBits2Float(0xc26fb724), SkBits2Float(0x3fd7f0d9), SkBits2Float(0xc2700000), SkBits2Float(0x3619fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40dfbd5e), SkBits2Float(0xc2a568f3));
+path.cubicTo(SkBits2Float(0x40e72e1b), SkBits2Float(0xc2a55ee2), SkBits2Float(0x40ee9e1c), SkBits2Float(0xc2a55452), SkBits2Float(0x40f60d62), SkBits2Float(0xc2a54941));
+path.lineTo(SkBits2Float(0x40b1de84), SkBits2Float(0xc26ef7c9));
+path.cubicTo(SkBits2Float(0x40ac7ea0), SkBits2Float(0xc26f07cb), SkBits2Float(0x40a71e37), SkBits2Float(0xc26f1712), SkBits2Float(0x40a1bd4f), SkBits2Float(0xc26f259f));
+path.lineTo(SkBits2Float(0x40dfbd5e), SkBits2Float(0xc2a568f3));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp99(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3619fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40155bee), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40955364), SkBits2Float(0xc2a5cd99), SkBits2Float(0x40dfbd5e), SkBits2Float(0xc2a568f3));
+path.cubicTo(SkBits2Float(0x40e72e1b), SkBits2Float(0xc2a55ee2), SkBits2Float(0x40ee9e1c), SkBits2Float(0xc2a55452), SkBits2Float(0x40f60d62), SkBits2Float(0xc2a54941));
+path.lineTo(SkBits2Float(0x40b1de84), SkBits2Float(0xc26ef7c9));
+path.cubicTo(SkBits2Float(0x40ac7ea2), SkBits2Float(0xc26f07cb), SkBits2Float(0x40a71e3a), SkBits2Float(0xc26f1712), SkBits2Float(0x40a1bd54), SkBits2Float(0xc26f259f));
+path.lineTo(SkBits2Float(0x40a1bd53), SkBits2Float(0xc26f259d));
+path.cubicTo(SkBits2Float(0x4057e483), SkBits2Float(0xc26fb724), SkBits2Float(0x3fd7f0d9), SkBits2Float(0xc2700000), SkBits2Float(0x3619fea3), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40f60d69), SkBits2Float(0xc2a54941));
+path.cubicTo(SkBits2Float(0x41374a21), SkBits2Float(0xc2a495d5), SkBits2Float(0x41731962), SkBits2Float(0xc2a35eca), SkBits2Float(0x419704b1), SkBits2Float(0xc2a1a64c));
+path.lineTo(SkBits2Float(0x415a56f5), SkBits2Float(0xc269b5d4));
+path.cubicTo(SkBits2Float(0x412fbbfb), SkBits2Float(0xc26c32af), SkBits2Float(0x41047f9a), SkBits2Float(0xc26df463), SkBits2Float(0x40b1de7e), SkBits2Float(0xc26ef7cb));
+path.lineTo(SkBits2Float(0x40f60d69), SkBits2Float(0xc2a54941));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp100(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x403cde0b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40bcccc9), SkBits2Float(0xc2a5af6a), SkBits2Float(0x410d5936), SkBits2Float(0xc2a50e98));
+path.lineTo(SkBits2Float(0x40cc5bf6), SkBits2Float(0xc26ea2fc));
+path.cubicTo(SkBits2Float(0x40887b5e), SkBits2Float(0xc26f8b7f), SkBits2Float(0x400887d8), SkBits2Float(0xc2700000), SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x410d5935), SkBits2Float(0xc2a50e99));
+path.cubicTo(SkBits2Float(0x41120ace), SkBits2Float(0xc2a4fe85), SkBits2Float(0x4116bbb5), SkBits2Float(0xc2a4eda4), SkBits2Float(0x411b6bdd), SkBits2Float(0xc2a4dbf6));
+path.lineTo(SkBits2Float(0x40e0b4a3), SkBits2Float(0xc26e59c7));
+path.cubicTo(SkBits2Float(0x40d9ed7a), SkBits2Float(0xc26e7357), SkBits2Float(0x40d32536), SkBits2Float(0xc26e8bbe), SkBits2Float(0x40cc5bf1), SkBits2Float(0xc26ea2fc));
+path.lineTo(SkBits2Float(0x410d5935), SkBits2Float(0xc2a50e99));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end fail 1
+
+static void battleOp101(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x406db78d), SkBits2Float(0xc2a60000), SkBits2Float(0x40ed953d), SkBits2Float(0xc2a58058), SkBits2Float(0x4131afb7), SkBits2Float(0xc2a481e4));
+path.lineTo(SkBits2Float(0x410072b2), SkBits2Float(0xc26dd78e));
+path.cubicTo(SkBits2Float(0x40abbf2e), SkBits2Float(0xc26f4770), SkBits2Float(0x402bd807), SkBits2Float(0xc2700000), SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4131afba), SkBits2Float(0xc2a481e4));
+path.cubicTo(SkBits2Float(0x413792dd), SkBits2Float(0xc2a46874), SkBits2Float(0x413d74a2), SkBits2Float(0xc2a44dc1), SkBits2Float(0x414354e9), SkBits2Float(0xc2a431ca));
+path.lineTo(SkBits2Float(0x410d3424), SkBits2Float(0xc26d63c0));
+path.cubicTo(SkBits2Float(0x4108f4b6), SkBits2Float(0xc26d8c2e), SkBits2Float(0x4104b435), SkBits2Float(0xc26db2c8), SkBits2Float(0x410072b4), SkBits2Float(0xc26dd78e));
+path.lineTo(SkBits2Float(0x4131afba), SkBits2Float(0xc2a481e4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp102(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x406db78d), SkBits2Float(0xc2a60000), SkBits2Float(0x40ed953d), SkBits2Float(0xc2a58058), SkBits2Float(0x4131afba), SkBits2Float(0xc2a481e4));
+path.cubicTo(SkBits2Float(0x413792dd), SkBits2Float(0xc2a46874), SkBits2Float(0x413d74a2), SkBits2Float(0xc2a44dc1), SkBits2Float(0x414354e9), SkBits2Float(0xc2a431ca));
+path.lineTo(SkBits2Float(0x410d3424), SkBits2Float(0xc26d63c0));
+path.cubicTo(SkBits2Float(0x4108f4b6), SkBits2Float(0xc26d8c2e), SkBits2Float(0x4104b435), SkBits2Float(0xc26db2c8), SkBits2Float(0x410072b2), SkBits2Float(0xc26dd78e));
+path.cubicTo(SkBits2Float(0x40abbf2e), SkBits2Float(0xc26f4770), SkBits2Float(0x402bd807), SkBits2Float(0xc2700000), SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x414354ed), SkBits2Float(0xc2a431cb));
+path.cubicTo(SkBits2Float(0x419152e5), SkBits2Float(0xc2a26c3a), SkBits2Float(0x41c0119b), SkBits2Float(0xc29f5c06), SkBits2Float(0x41ed1335), SkBits2Float(0xc29b0f0a));
+path.lineTo(SkBits2Float(0x41ab612b), SkBits2Float(0xc2602e6b));
+path.cubicTo(SkBits2Float(0x418ad84d), SkBits2Float(0xc2666635), SkBits2Float(0x41521b54), SkBits2Float(0xc26ad3fe), SkBits2Float(0x410d3426), SkBits2Float(0xc26d63c0));
+path.lineTo(SkBits2Float(0x414354ed), SkBits2Float(0xc2a431cb));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp103(skiatest::Reporter* reporter, const char* filename) { //crash
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x408e2d73), SkBits2Float(0xc2a5ffff), SkBits2Float(0x410e100a), SkBits2Float(0xc2a54957), SkBits2Float(0x41543cd2), SkBits2Float(0xc2a3ddc8));
+path.lineTo(SkBits2Float(0x41196cba), SkBits2Float(0xc26cea49));
+path.cubicTo(SkBits2Float(0x40cd643f), SkBits2Float(0xc26ef7e9), SkBits2Float(0x404d8eb8), SkBits2Float(0xc26fffff), SkBits2Float(0xb5ac02ba), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41543cce), SkBits2Float(0xc2a3ddc8));
+path.cubicTo(SkBits2Float(0x415b4057), SkBits2Float(0xc2a3b973), SkBits2Float(0x41624181), SkBits2Float(0xc2a39350), SkBits2Float(0x41694022), SkBits2Float(0xc2a36b60));
+path.lineTo(SkBits2Float(0x41289d63), SkBits2Float(0xc26c44e1));
+path.cubicTo(SkBits2Float(0x41238ef8), SkBits2Float(0xc26c7e9e), SkBits2Float(0x411e7eb5), SkBits2Float(0xc26cb5c1), SkBits2Float(0x41196cbd), SkBits2Float(0xc26cea4a));
+path.lineTo(SkBits2Float(0x41543cce), SkBits2Float(0xc2a3ddc8));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp104(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3dd41fb8), SkBits2Float(0xc2a5fffe), SkBits2Float(0x3e541e5b), SkBits2Float(0xc2a5ffe5), SkBits2Float(0x3e9f1657), SkBits2Float(0xc2a5ffb2));
+path.lineTo(SkBits2Float(0x3e66012b), SkBits2Float(0xc26fff92));
+path.cubicTo(SkBits2Float(0x3e1955e2), SkBits2Float(0xc26fffdc), SkBits2Float(0x3d99560b), SkBits2Float(0xc2700000), SkBits2Float(0x350f7780), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3e9f1626), SkBits2Float(0xc2a5ffb4));
+path.cubicTo(SkBits2Float(0x3ea463a8), SkBits2Float(0xc2a5ffae), SkBits2Float(0x3ea9b10b), SkBits2Float(0xc2a5ffa8), SkBits2Float(0x3eaefe6d), SkBits2Float(0xc2a5ffa3));
+path.lineTo(SkBits2Float(0x3e7d0144), SkBits2Float(0xc26fff7b));
+path.cubicTo(SkBits2Float(0x3e75568f), SkBits2Float(0xc26fff84), SkBits2Float(0x3e6dac12), SkBits2Float(0xc26fff8c), SkBits2Float(0x3e660197), SkBits2Float(0xc26fff93));
+path.lineTo(SkBits2Float(0x3e9f1626), SkBits2Float(0xc2a5ffb4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp105(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3dd41f74), SkBits2Float(0xc2a5fffe), SkBits2Float(0x3e541e17), SkBits2Float(0xc2a5ffe5), SkBits2Float(0x3e9f1624), SkBits2Float(0xc2a5ffb2));
+path.lineTo(SkBits2Float(0x3e9f1626), SkBits2Float(0xc2a5ffb4));
+path.cubicTo(SkBits2Float(0x3ea463a8), SkBits2Float(0xc2a5ffae), SkBits2Float(0x3ea9b10b), SkBits2Float(0xc2a5ffa8), SkBits2Float(0x3eaefe6d), SkBits2Float(0xc2a5ffa3));
+path.lineTo(SkBits2Float(0x3e7d0144), SkBits2Float(0xc26fff7b));
+path.cubicTo(SkBits2Float(0x3e75568f), SkBits2Float(0xc26fff84), SkBits2Float(0x3e6dac12), SkBits2Float(0xc26fff8c), SkBits2Float(0x3e66012b), SkBits2Float(0xc26fff92));
+path.cubicTo(SkBits2Float(0x3e1955e2), SkBits2Float(0xc26fffdc), SkBits2Float(0x3d99560b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3eaefebc), SkBits2Float(0xc2a5ffa4));
+path.cubicTo(SkBits2Float(0x3f0276b7), SkBits2Float(0xc2a5ff4a), SkBits2Float(0x3f2d6dea), SkBits2Float(0xc2a5feac), SkBits2Float(0x3f5864cc), SkBits2Float(0xc2a5fdcd));
+path.lineTo(SkBits2Float(0x3f1c6df6), SkBits2Float(0xc26ffcd0));
+path.cubicTo(SkBits2Float(0x3efabdec), SkBits2Float(0xc26ffe15), SkBits2Float(0x3ebc9f78), SkBits2Float(0xc26ffef9), SkBits2Float(0x3e7d0190), SkBits2Float(0xc26fff7c));
+path.lineTo(SkBits2Float(0x3eaefebc), SkBits2Float(0xc2a5ffa4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp106(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ee221f0), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f622166), SkBits2Float(0xc2a5fe31), SkBits2Float(0x3fa9974d), SkBits2Float(0xc2a5fa95));
+path.lineTo(SkBits2Float(0x3f753159), SkBits2Float(0xc26ff82c));
+path.cubicTo(SkBits2Float(0x3f237814), SkBits2Float(0xc26ffd64), SkBits2Float(0x3ea3787a), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa50), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3fa99777), SkBits2Float(0xc2a5fa96));
+path.cubicTo(SkBits2Float(0x3faf3e7a), SkBits2Float(0xc2a5fa39), SkBits2Float(0x3fb4e596), SkBits2Float(0xc2a5f9d8), SkBits2Float(0x3fba8cad), SkBits2Float(0xc2a5f972));
+path.lineTo(SkBits2Float(0x3f86dad5), SkBits2Float(0xc26ff687));
+path.cubicTo(SkBits2Float(0x3f82c4d9), SkBits2Float(0xc26ff71a), SkBits2Float(0x3f7d5da4), SkBits2Float(0xc26ff7a6), SkBits2Float(0x3f753191), SkBits2Float(0xc26ff82c));
+path.lineTo(SkBits2Float(0x3fa99777), SkBits2Float(0xc2a5fa96));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp107(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ee221f0), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f622166), SkBits2Float(0xc2a5fe31), SkBits2Float(0x3fa99777), SkBits2Float(0xc2a5fa96));
+path.cubicTo(SkBits2Float(0x3faf3e7a), SkBits2Float(0xc2a5fa39), SkBits2Float(0x3fb4e596), SkBits2Float(0xc2a5f9d8), SkBits2Float(0x3fba8cad), SkBits2Float(0xc2a5f972));
+path.lineTo(SkBits2Float(0x3f86dad5), SkBits2Float(0xc26ff687));
+path.cubicTo(SkBits2Float(0x3f82c4d9), SkBits2Float(0xc26ff71a), SkBits2Float(0x3f7d5da4), SkBits2Float(0xc26ff7a6), SkBits2Float(0x3f753159), SkBits2Float(0xc26ff82c));
+path.cubicTo(SkBits2Float(0x3f237814), SkBits2Float(0xc26ffd64), SkBits2Float(0x3ea3787a), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3fba8c96), SkBits2Float(0xc2a5f973));
+path.cubicTo(SkBits2Float(0x400b1301), SkBits2Float(0xc2a5f303), SkBits2Float(0x4038dc7e), SkBits2Float(0xc2a5e7d6), SkBits2Float(0x40669fe4), SkBits2Float(0xc2a5d7ed));
+path.lineTo(SkBits2Float(0x4026b765), SkBits2Float(0xc26fc611));
+path.cubicTo(SkBits2Float(0x4005a27d), SkBits2Float(0xc26fdd13), SkBits2Float(0x3fc9123c), SkBits2Float(0xc26fed3b), SkBits2Float(0x3f86daf1), SkBits2Float(0xc26ff689));
+path.lineTo(SkBits2Float(0x3fba8c96), SkBits2Float(0xc2a5f973));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp108(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f587304), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3fd8713e), SkBits2Float(0xc2a5f962), SkBits2Float(0x40224ed5), SkBits2Float(0xc2a5ec27));
+path.lineTo(SkBits2Float(0x3feaa996), SkBits2Float(0xc26fe350));
+path.cubicTo(SkBits2Float(0x3f9c76e4), SkBits2Float(0xc26ff671), SkBits2Float(0x3f1c780b), SkBits2Float(0xc2700000), SkBits2Float(0xb5510538), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40224ee4), SkBits2Float(0xc2a5ec28));
+path.cubicTo(SkBits2Float(0x4027b77a), SkBits2Float(0xc2a5ead6), SkBits2Float(0x402d1ffd), SkBits2Float(0xc2a5e972), SkBits2Float(0x4032886f), SkBits2Float(0xc2a5e7fe));
+path.lineTo(SkBits2Float(0x40010f64), SkBits2Float(0xc26fdd4a));
+path.cubicTo(SkBits2Float(0x3ffa4d23), SkBits2Float(0xc26fdf64), SkBits2Float(0x3ff27b6d), SkBits2Float(0xc26fe166), SkBits2Float(0x3feaa9a1), SkBits2Float(0xc26fe350));
+path.lineTo(SkBits2Float(0x40224ee4), SkBits2Float(0xc2a5ec28));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp109(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f587304), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3fd8713e), SkBits2Float(0xc2a5f962), SkBits2Float(0x40224ee4), SkBits2Float(0xc2a5ec28));
+path.cubicTo(SkBits2Float(0x4027b77a), SkBits2Float(0xc2a5ead6), SkBits2Float(0x402d1ffd), SkBits2Float(0xc2a5e972), SkBits2Float(0x4032886f), SkBits2Float(0xc2a5e7fe));
+path.lineTo(SkBits2Float(0x40010f64), SkBits2Float(0xc26fdd4a));
+path.cubicTo(SkBits2Float(0x3ffa4d23), SkBits2Float(0xc26fdf64), SkBits2Float(0x3ff27b6d), SkBits2Float(0xc26fe166), SkBits2Float(0x3feaa996), SkBits2Float(0xc26fe350));
+path.cubicTo(SkBits2Float(0x3f9c76e4), SkBits2Float(0xc26ff671), SkBits2Float(0x3f1c780b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4032887d), SkBits2Float(0xc2a5e7fe));
+path.cubicTo(SkBits2Float(0x4085166b), SkBits2Float(0xc2a5d069), SkBits2Float(0x40b0dd8e), SkBits2Float(0xc2a5a77a), SkBits2Float(0x40dc8f53), SkBits2Float(0xc2a56d38));
+path.lineTo(SkBits2Float(0x409f70d9), SkBits2Float(0xc26f2bca));
+path.cubicTo(SkBits2Float(0x407fb58c), SkBits2Float(0xc26f8005), SkBits2Float(0x40406a74), SkBits2Float(0xc26fbb35), SkBits2Float(0x40010f5f), SkBits2Float(0xc26fdd4b));
+path.lineTo(SkBits2Float(0x4032887d), SkBits2Float(0xc2a5e7fe));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp110(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x400cf1ae), SkBits2Float(0xc2a5ffff), SkBits2Float(0x408cea87), SkBits2Float(0xc2a5d31f), SkBits2Float(0x40d32a40), SkBits2Float(0xc2a57979));
+path.lineTo(SkBits2Float(0x4098a645), SkBits2Float(0xc26f3d83));
+path.cubicTo(SkBits2Float(0x404bbc01), SkBits2Float(0xc26fbf1e), SkBits2Float(0x3fcbc669), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff59), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40d32a46), SkBits2Float(0xc2a5797a));
+path.cubicTo(SkBits2Float(0x40da306e), SkBits2Float(0xc2a57083), SkBits2Float(0x40e135fe), SkBits2Float(0xc2a5671a), SkBits2Float(0x40e83aef), SkBits2Float(0xc2a55d3f));
+path.lineTo(SkBits2Float(0x40a7e090), SkBits2Float(0xc26f14b1));
+path.cubicTo(SkBits2Float(0x40a2cd8d), SkBits2Float(0xc26f22f4), SkBits2Float(0x409dba1d), SkBits2Float(0xc26f308e), SkBits2Float(0x4098a641), SkBits2Float(0xc26f3d84));
+path.lineTo(SkBits2Float(0x40d32a46), SkBits2Float(0xc2a5797a));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp111(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3697ff59), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x400cf1ae), SkBits2Float(0xc2a5ffff), SkBits2Float(0x408cea87), SkBits2Float(0xc2a5d31f), SkBits2Float(0x40d32a46), SkBits2Float(0xc2a5797a));
+path.cubicTo(SkBits2Float(0x40da306e), SkBits2Float(0xc2a57083), SkBits2Float(0x40e135fe), SkBits2Float(0xc2a5671a), SkBits2Float(0x40e83aef), SkBits2Float(0xc2a55d3f));
+path.lineTo(SkBits2Float(0x40a7e090), SkBits2Float(0xc26f14b1));
+path.cubicTo(SkBits2Float(0x40a2cd8f), SkBits2Float(0xc26f22f4), SkBits2Float(0x409dba20), SkBits2Float(0xc26f308e), SkBits2Float(0x4098a645), SkBits2Float(0xc26f3d83));
+path.cubicTo(SkBits2Float(0x404bbc01), SkBits2Float(0xc26fbf1e), SkBits2Float(0x3fcbc669), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff59), SkBits2Float(0xc26fffff));
+path.close();
+path.moveTo(SkBits2Float(0x40b5a39a), SkBits2Float(0xc28e5650));
+path.lineTo(SkBits2Float(0x4098a641), SkBits2Float(0xc26f3d84));
+path.lineTo(SkBits2Float(0x4098a646), SkBits2Float(0xc26f3d84));
+path.lineTo(SkBits2Float(0x40b5a39a), SkBits2Float(0xc28e5650));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40e83ae9), SkBits2Float(0xc2a55d3f));
+path.cubicTo(SkBits2Float(0x412d0232), SkBits2Float(0xc2a4bd73), SkBits2Float(0x4165854a), SkBits2Float(0xc2a3a860), SkBits2Float(0x418ea651), SkBits2Float(0xc2a21fbf));
+path.lineTo(SkBits2Float(0x414e3d91), SkBits2Float(0xc26a656a));
+path.cubicTo(SkBits2Float(0x4125eb27), SkBits2Float(0xc26c9d13), SkBits2Float(0x40fa2207), SkBits2Float(0xc26e2daa), SkBits2Float(0x40a7e094), SkBits2Float(0xc26f14b2));
+path.lineTo(SkBits2Float(0x40e83ae9), SkBits2Float(0xc2a55d3f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp112(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4035711d), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40b561d9), SkBits2Float(0xc2a5b5a1), SkBits2Float(0x4107d050), SkBits2Float(0xc2a5212f));
+path.lineTo(SkBits2Float(0x40c45b76), SkBits2Float(0xc26ebddb));
+path.cubicTo(SkBits2Float(0x40831ea4), SkBits2Float(0xc26f947a), SkBits2Float(0x400329ad), SkBits2Float(0xc26fffff), SkBits2Float(0x35bbfd46), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4107d054), SkBits2Float(0xc2a5212f));
+path.cubicTo(SkBits2Float(0x410c5332), SkBits2Float(0xc2a51258), SkBits2Float(0x4110d578), SkBits2Float(0xc2a502c3), SkBits2Float(0x41155714), SkBits2Float(0xc2a4f271));
+path.lineTo(SkBits2Float(0x40d7e9e2), SkBits2Float(0xc26e7a46));
+path.cubicTo(SkBits2Float(0x40d16605), SkBits2Float(0xc26e91e0), SkBits2Float(0x40cae131), SkBits2Float(0xc26ea866), SkBits2Float(0x40c45b7a), SkBits2Float(0xc26ebddc));
+path.lineTo(SkBits2Float(0x4107d054), SkBits2Float(0xc2a5212f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp113(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4035711d), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40b561d9), SkBits2Float(0xc2a5b5a1), SkBits2Float(0x4107d054), SkBits2Float(0xc2a5212f));
+path.cubicTo(SkBits2Float(0x410c5332), SkBits2Float(0xc2a51258), SkBits2Float(0x4110d578), SkBits2Float(0xc2a502c3), SkBits2Float(0x41155714), SkBits2Float(0xc2a4f271));
+path.lineTo(SkBits2Float(0x40d7e9e2), SkBits2Float(0xc26e7a46));
+path.cubicTo(SkBits2Float(0x40d16605), SkBits2Float(0xc26e91e0), SkBits2Float(0x40cae131), SkBits2Float(0xc26ea866), SkBits2Float(0x40c45b76), SkBits2Float(0xc26ebddb));
+path.cubicTo(SkBits2Float(0x40831ea4), SkBits2Float(0xc26f947a), SkBits2Float(0x400329ad), SkBits2Float(0xc26fffff), SkBits2Float(0x00000000), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4115571a), SkBits2Float(0xc2a4f271));
+path.cubicTo(SkBits2Float(0x415e6818), SkBits2Float(0xc2a3e9d4), SkBits2Float(0x41935478), SkBits2Float(0xc2a21f7a), SkBits2Float(0x41b6ad74), SkBits2Float(0xc29f981d));
+path.lineTo(SkBits2Float(0x41840e5b), SkBits2Float(0xc266bd14));
+path.cubicTo(SkBits2Float(0x415501d6), SkBits2Float(0xc26a6507), SkBits2Float(0x4120c6a0), SkBits2Float(0xc26cfbb4), SkBits2Float(0x40d7e9e6), SkBits2Float(0xc26e7a47));
+path.lineTo(SkBits2Float(0x4115571a), SkBits2Float(0xc2a4f271));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp114(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x405f6414), SkBits2Float(0xc2a60000), SkBits2Float(0x40df4798), SkBits2Float(0xc2a58f44), SkBits2Float(0x41270b42), SkBits2Float(0xc2a4ae78));
+path.lineTo(SkBits2Float(0x40f1826b), SkBits2Float(0xc26e1801));
+path.cubicTo(SkBits2Float(0x40a16831), SkBits2Float(0xc26f5d03), SkBits2Float(0x40217cc8), SkBits2Float(0xc2700000), SkBits2Float(0x3507fa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41270b46), SkBits2Float(0xc2a4ae78));
+path.cubicTo(SkBits2Float(0x412c952a), SkBits2Float(0xc2a497ff), SkBits2Float(0x41321de3), SkBits2Float(0xc2a48068), SkBits2Float(0x4137a563), SkBits2Float(0xc2a467b4));
+path.lineTo(SkBits2Float(0x4104c195), SkBits2Float(0xc26db1b1));
+path.cubicTo(SkBits2Float(0x4100c256), SkBits2Float(0xc26dd569), SkBits2Float(0x40f98465), SkBits2Float(0xc26df784), SkBits2Float(0x40f18273), SkBits2Float(0xc26e1801));
+path.lineTo(SkBits2Float(0x41270b46), SkBits2Float(0xc2a4ae78));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp115(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x405f6414), SkBits2Float(0xc2a60000), SkBits2Float(0x40df4798), SkBits2Float(0xc2a58f44), SkBits2Float(0x41270b46), SkBits2Float(0xc2a4ae78));
+path.cubicTo(SkBits2Float(0x412c952a), SkBits2Float(0xc2a497ff), SkBits2Float(0x41321de3), SkBits2Float(0xc2a48068), SkBits2Float(0x4137a563), SkBits2Float(0xc2a467b4));
+path.lineTo(SkBits2Float(0x4104c195), SkBits2Float(0xc26db1b1));
+path.cubicTo(SkBits2Float(0x4100c256), SkBits2Float(0xc26dd569), SkBits2Float(0x40f98465), SkBits2Float(0xc26df784), SkBits2Float(0x40f1826b), SkBits2Float(0xc26e1801));
+path.cubicTo(SkBits2Float(0x40a16831), SkBits2Float(0xc26f5d03), SkBits2Float(0x40217cc8), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4137a563), SkBits2Float(0xc2a467b4));
+path.cubicTo(SkBits2Float(0x4188a9bf), SkBits2Float(0xc2a2d700), SkBits2Float(0x41b4bec4), SkBits2Float(0xc2a021d5), SkBits2Float(0x41df619b), SkBits2Float(0xc29c5308));
+path.lineTo(SkBits2Float(0x41a17afe), SkBits2Float(0xc26202d7));
+path.cubicTo(SkBits2Float(0x4182a8c1), SkBits2Float(0xc2678433), SkBits2Float(0x414595cf), SkBits2Float(0xc26b6e5e), SkBits2Float(0x4104c197), SkBits2Float(0xc26db1b2));
+path.lineTo(SkBits2Float(0x4137a563), SkBits2Float(0xc2a467b4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp116(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40894a00), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41092f84), SkBits2Float(0xc2a555af), SkBits2Float(0x414d01d5), SkBits2Float(0xc2a40295));
+path.lineTo(SkBits2Float(0x411432a9), SkBits2Float(0xc26d1f80));
+path.cubicTo(SkBits2Float(0x40c65728), SkBits2Float(0xc26f09c3), SkBits2Float(0x40467d64), SkBits2Float(0xc2700000), SkBits2Float(0xb5600574), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x414d01d1), SkBits2Float(0xc2a40296));
+path.cubicTo(SkBits2Float(0x4153c92e), SkBits2Float(0xc2a3e0b1), SkBits2Float(0x415a8e6d), SkBits2Float(0xc2a3bd1e), SkBits2Float(0x41615162), SkBits2Float(0xc2a397de));
+path.lineTo(SkBits2Float(0x4122e164), SkBits2Float(0xc26c8535));
+path.cubicTo(SkBits2Float(0x411dfe19), SkBits2Float(0xc26cbb11), SkBits2Float(0x41191928), SkBits2Float(0xc26cee7f), SkBits2Float(0x411432ab), SkBits2Float(0xc26d1f80));
+path.lineTo(SkBits2Float(0x414d01d1), SkBits2Float(0xc2a40296));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp117(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x408949fd), SkBits2Float(0xc2a60000), SkBits2Float(0x41092f81), SkBits2Float(0xc2a555af), SkBits2Float(0x414d01d0), SkBits2Float(0xc2a40295));
+path.lineTo(SkBits2Float(0x414d01d1), SkBits2Float(0xc2a40296));
+path.cubicTo(SkBits2Float(0x4153c92e), SkBits2Float(0xc2a3e0b1), SkBits2Float(0x415a8e6d), SkBits2Float(0xc2a3bd1e), SkBits2Float(0x41615162), SkBits2Float(0xc2a397de));
+path.lineTo(SkBits2Float(0x4122e164), SkBits2Float(0xc26c8535));
+path.cubicTo(SkBits2Float(0x411dfe19), SkBits2Float(0xc26cbb11), SkBits2Float(0x41191928), SkBits2Float(0xc26cee7f), SkBits2Float(0x411432a9), SkBits2Float(0xc26d1f80));
+path.cubicTo(SkBits2Float(0x40c65728), SkBits2Float(0xc26f09c3), SkBits2Float(0x40467d64), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41615164), SkBits2Float(0xc2a397de));
+path.cubicTo(SkBits2Float(0x41a78432), SkBits2Float(0xc2a13b6d), SkBits2Float(0x41dcf7f2), SkBits2Float(0xc29d27e8), SkBits2Float(0x4207e0f5), SkBits2Float(0xc29775db));
+path.lineTo(SkBits2Float(0x41c47380), SkBits2Float(0xc25afa96));
+path.cubicTo(SkBits2Float(0x419fbc7e), SkBits2Float(0xc263369d), SkBits2Float(0x41723143), SkBits2Float(0xc2691b52), SkBits2Float(0x4122e168), SkBits2Float(0xc26c8537));
+path.lineTo(SkBits2Float(0x41615164), SkBits2Float(0xc2a397de));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp118(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40a2e582), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4122b94f), SkBits2Float(0xc2a51039), SkBits2Float(0x4172cca0), SkBits2Float(0xc2a333b4));
+path.lineTo(SkBits2Float(0x412f847d), SkBits2Float(0xc26bf464));
+path.cubicTo(SkBits2Float(0x40eb4376), SkBits2Float(0xc26ea556), SkBits2Float(0x406b836d), SkBits2Float(0xc2700000), SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4172cc9b), SkBits2Float(0xc2a333b4));
+path.cubicTo(SkBits2Float(0x417acd1a), SkBits2Float(0xc2a30415), SkBits2Float(0x41816508), SkBits2Float(0xc2a2d21d), SkBits2Float(0x4185619b), SkBits2Float(0xc2a29dcb));
+path.lineTo(SkBits2Float(0x4140d724), SkBits2Float(0xc26b1ba8));
+path.cubicTo(SkBits2Float(0x413b139d), SkBits2Float(0xc26b674c), SkBits2Float(0x41354d54), SkBits2Float(0xc26baf8b), SkBits2Float(0x412f847c), SkBits2Float(0xc26bf463));
+path.lineTo(SkBits2Float(0x4172cc9b), SkBits2Float(0xc2a333b4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp119(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40a2e57f), SkBits2Float(0xc2a60000), SkBits2Float(0x4122b94c), SkBits2Float(0xc2a51039), SkBits2Float(0x4172cc9b), SkBits2Float(0xc2a333b4));
+path.lineTo(SkBits2Float(0x4172cca0), SkBits2Float(0xc2a333b4));
+path.cubicTo(SkBits2Float(0x417acd1d), SkBits2Float(0xc2a30415), SkBits2Float(0x41816509), SkBits2Float(0xc2a2d21d), SkBits2Float(0x4185619b), SkBits2Float(0xc2a29dcb));
+path.lineTo(SkBits2Float(0x4140d724), SkBits2Float(0xc26b1ba8));
+path.cubicTo(SkBits2Float(0x413b139d), SkBits2Float(0xc26b674c), SkBits2Float(0x41354d54), SkBits2Float(0xc26baf8b), SkBits2Float(0x412f847c), SkBits2Float(0xc26bf463));
+path.lineTo(SkBits2Float(0x412f847d), SkBits2Float(0xc26bf464));
+path.cubicTo(SkBits2Float(0x40eb4376), SkBits2Float(0xc26ea556), SkBits2Float(0x406b836d), SkBits2Float(0xc2700000), SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4185619b), SkBits2Float(0xc2a29dcc));
+path.cubicTo(SkBits2Float(0x41c61a92), SkBits2Float(0xc29f4c69), SkBits2Float(0x42023dd6), SkBits2Float(0xc299958f), SkBits2Float(0x421f3a98), SkBits2Float(0xc291a994));
+path.lineTo(SkBits2Float(0x41e635e1), SkBits2Float(0xc25298a5));
+path.cubicTo(SkBits2Float(0x41bc4d11), SkBits2Float(0xc25e0caa), SkBits2Float(0x418f3524), SkBits2Float(0xc2664fa2), SkBits2Float(0x4140d729), SkBits2Float(0xc26b1ba9));
+path.lineTo(SkBits2Float(0x4185619b), SkBits2Float(0xc2a29dcc));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp120(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40c39389), SkBits2Float(0xc2a60000), SkBits2Float(0x414346f4), SkBits2Float(0xc2a4a65f), SkBits2Float(0x419158cf), SkBits2Float(0xc2a1f965));
+path.lineTo(SkBits2Float(0x415223e0), SkBits2Float(0xc26a2df8));
+path.cubicTo(SkBits2Float(0x410d2a0c), SkBits2Float(0xc26e0c4b), SkBits2Float(0x408d616c), SkBits2Float(0xc2700000), SkBits2Float(0x35bbfd46), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x419158d0), SkBits2Float(0xc2a1f965));
+path.cubicTo(SkBits2Float(0x41961cea), SkBits2Float(0xc2a1b4f6), SkBits2Float(0x419addf6), SkBits2Float(0xc2a16d2c), SkBits2Float(0x419f9bbb), SkBits2Float(0xc2a12207));
+path.lineTo(SkBits2Float(0x4166c251), SkBits2Float(0xc268f69a));
+path.cubicTo(SkBits2Float(0x415fe778), SkBits2Float(0xc269633e), SkBits2Float(0x415907e2), SkBits2Float(0xc269cb09), SkBits2Float(0x415223e0), SkBits2Float(0xc26a2df8));
+path.lineTo(SkBits2Float(0x419158d0), SkBits2Float(0xc2a1f965));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp121(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40c39389), SkBits2Float(0xc2a60000), SkBits2Float(0x414346f4), SkBits2Float(0xc2a4a65f), SkBits2Float(0x419158d0), SkBits2Float(0xc2a1f965));
+path.cubicTo(SkBits2Float(0x41961cea), SkBits2Float(0xc2a1b4f6), SkBits2Float(0x419addf6), SkBits2Float(0xc2a16d2c), SkBits2Float(0x419f9bbb), SkBits2Float(0xc2a12207));
+path.lineTo(SkBits2Float(0x4166c251), SkBits2Float(0xc268f69a));
+path.cubicTo(SkBits2Float(0x415fe778), SkBits2Float(0xc269633e), SkBits2Float(0x415907e2), SkBits2Float(0xc269cb09), SkBits2Float(0x415223e0), SkBits2Float(0xc26a2df8));
+path.cubicTo(SkBits2Float(0x410d2a0c), SkBits2Float(0xc26e0c4b), SkBits2Float(0x408d616c), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x419f9bbc), SkBits2Float(0xc2a12208));
+path.cubicTo(SkBits2Float(0x41eca53e), SkBits2Float(0xc29c5d1a), SkBits2Float(0x421ad1be), SkBits2Float(0xc2942e2b), SkBits2Float(0x423b8fe1), SkBits2Float(0xc288f8a3));
+path.lineTo(SkBits2Float(0x42079647), SkBits2Float(0xc24607dc));
+path.cubicTo(SkBits2Float(0x41dfd5cc), SkBits2Float(0xc2563c94), SkBits2Float(0x41ab11aa), SkBits2Float(0xc2621167), SkBits2Float(0x4166c24e), SkBits2Float(0xc268f69b));
+path.lineTo(SkBits2Float(0x419f9bbc), SkBits2Float(0xc2a12208));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp122(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x410a1653), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4189aa2f), SkBits2Float(0xc2a34ed0), SkBits2Float(0x41cb63be), SkBits2Float(0xc29e054b));
+path.lineTo(SkBits2Float(0x41930758), SkBits2Float(0xc26476b2));
+path.cubicTo(SkBits2Float(0x41470896), SkBits2Float(0xc26c1b98), SkBits2Float(0x40c7a4f2), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41cb63c3), SkBits2Float(0xc29e054c));
+path.cubicTo(SkBits2Float(0x41d1f2f3), SkBits2Float(0xc29d7e37), SkBits2Float(0x41d879a0), SkBits2Float(0xc29cf09c), SkBits2Float(0x41def72d), SkBits2Float(0xc29c5c87));
+path.lineTo(SkBits2Float(0x41a12e10), SkBits2Float(0xc2621091));
+path.cubicTo(SkBits2Float(0x419c7cee), SkBits2Float(0xc262e6aa), SkBits2Float(0x4197c536), SkBits2Float(0xc263b366), SkBits2Float(0x41930757), SkBits2Float(0xc26476b3));
+path.lineTo(SkBits2Float(0x41cb63c3), SkBits2Float(0xc29e054c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp123(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x410a1653), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4189aa2f), SkBits2Float(0xc2a34ed0), SkBits2Float(0x41cb63be), SkBits2Float(0xc29e054b));
+path.lineTo(SkBits2Float(0x41cb63c3), SkBits2Float(0xc29e054c));
+path.cubicTo(SkBits2Float(0x41d1f2f3), SkBits2Float(0xc29d7e37), SkBits2Float(0x41d879a0), SkBits2Float(0xc29cf09c), SkBits2Float(0x41def72d), SkBits2Float(0xc29c5c87));
+path.lineTo(SkBits2Float(0x41a12e10), SkBits2Float(0xc2621091));
+path.cubicTo(SkBits2Float(0x419c7cee), SkBits2Float(0xc262e6aa), SkBits2Float(0x4197c536), SkBits2Float(0xc263b366), SkBits2Float(0x41930757), SkBits2Float(0xc26476b3));
+path.lineTo(SkBits2Float(0x41930758), SkBits2Float(0xc26476b2));
+path.cubicTo(SkBits2Float(0x41470896), SkBits2Float(0xc26c1b98), SkBits2Float(0x40c7a4f2), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea3), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41def730), SkBits2Float(0xc29c5c87));
+path.cubicTo(SkBits2Float(0x422459f2), SkBits2Float(0xc292f017), SkBits2Float(0x42539427), SkBits2Float(0xc282f764), SkBits2Float(0x4278c050), SkBits2Float(0xc25be110));
+path.lineTo(SkBits2Float(0x4233d1f5), SkBits2Float(0xc21ef2e3));
+path.cubicTo(SkBits2Float(0x4218f2cf), SkBits2Float(0xc23d5956), SkBits2Float(0x41ed9dce), SkBits2Float(0xc25470b6), SkBits2Float(0x41a12e11), SkBits2Float(0xc2621092));
+path.lineTo(SkBits2Float(0x41def730), SkBits2Float(0xc29c5c87));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp124(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x411fc00b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x419f1845), SkBits2Float(0xc2a265a5), SkBits2Float(0x41e9da2b), SkBits2Float(0xc29b5d43));
+path.lineTo(SkBits2Float(0x41a90cc1), SkBits2Float(0xc2609f84));
+path.cubicTo(SkBits2Float(0x41660440), SkBits2Float(0xc26aca7c), SkBits2Float(0x40e6f6cd), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa8c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41e9da2e), SkBits2Float(0xc29b5d44));
+path.cubicTo(SkBits2Float(0x41f14eda), SkBits2Float(0xc29aa9b5), SkBits2Float(0x41f8b671), SkBits2Float(0xc299ed94), SkBits2Float(0x42000805), SkBits2Float(0xc29928f7));
+path.lineTo(SkBits2Float(0x41b91b05), SkBits2Float(0xc25d6faa));
+path.cubicTo(SkBits2Float(0x41b3cad4), SkBits2Float(0xc25e8bec), SkBits2Float(0x41ae7086), SkBits2Float(0xc25f9beb), SkBits2Float(0x41a90cc3), SkBits2Float(0xc2609f85));
+path.lineTo(SkBits2Float(0x41e9da2e), SkBits2Float(0xc29b5d44));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp125(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x411fc00b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x419f1845), SkBits2Float(0xc2a265a5), SkBits2Float(0x41e9da2e), SkBits2Float(0xc29b5d44));
+path.cubicTo(SkBits2Float(0x41f14eda), SkBits2Float(0xc29aa9b5), SkBits2Float(0x41f8b671), SkBits2Float(0xc299ed94), SkBits2Float(0x42000805), SkBits2Float(0xc29928f7));
+path.lineTo(SkBits2Float(0x41b91b05), SkBits2Float(0xc25d6faa));
+path.cubicTo(SkBits2Float(0x41b3cad4), SkBits2Float(0xc25e8bec), SkBits2Float(0x41ae7086), SkBits2Float(0xc25f9beb), SkBits2Float(0x41a90cc1), SkBits2Float(0xc2609f84));
+path.cubicTo(SkBits2Float(0x41660440), SkBits2Float(0xc26aca7c), SkBits2Float(0x40e6f6cd), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42000806), SkBits2Float(0xc29928f8));
+path.cubicTo(SkBits2Float(0x423c0231), SkBits2Float(0xc28ca034), SkBits2Float(0x426f4e95), SkBits2Float(0xc26f2095), SkBits2Float(0x4289c821), SkBits2Float(0xc2392c12));
+path.lineTo(SkBits2Float(0x424733db), SkBits2Float(0xc205dc02));
+path.cubicTo(SkBits2Float(0x422cfe35), SkBits2Float(0xc22cdcf5), SkBits2Float(0x4207e8ea), SkBits2Float(0xc24b507f), SkBits2Float(0x41b91b06), SkBits2Float(0xc25d6faa));
+path.lineTo(SkBits2Float(0x42000806), SkBits2Float(0xc29928f8));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp126(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41379cd4), SkBits2Float(0xc2a60000), SkBits2Float(0x41b69d77), SkBits2Float(0xc2a13d93), SkBits2Float(0x42055871), SkBits2Float(0xc29805ae));
+path.lineTo(SkBits2Float(0x41c0c9e6), SkBits2Float(0xc25bca86));
+path.cubicTo(SkBits2Float(0x418402cc), SkBits2Float(0xc2691e6b), SkBits2Float(0x4104bb66), SkBits2Float(0xc26fffff), SkBits2Float(0x3673fea5), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42055872), SkBits2Float(0xc29805ae));
+path.cubicTo(SkBits2Float(0x420988d2), SkBits2Float(0xc2971a85), SkBits2Float(0x420daf5c), SkBits2Float(0xc296244f), SkBits2Float(0x4211cb64), SkBits2Float(0xc2952332));
+path.lineTo(SkBits2Float(0x41d2c988), SkBits2Float(0xc2579ed7));
+path.cubicTo(SkBits2Float(0x41ccd887), SkBits2Float(0xc2591291), SkBits2Float(0x41c6d852), SkBits2Float(0xc25a7689), SkBits2Float(0x41c0c9e6), SkBits2Float(0xc25bca86));
+path.lineTo(SkBits2Float(0x42055872), SkBits2Float(0xc29805ae));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp127(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3673fea5), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41379cd4), SkBits2Float(0xc2a60000), SkBits2Float(0x41b69d77), SkBits2Float(0xc2a13d93), SkBits2Float(0x42055872), SkBits2Float(0xc29805ae));
+path.cubicTo(SkBits2Float(0x420988d2), SkBits2Float(0xc2971a85), SkBits2Float(0x420daf5c), SkBits2Float(0xc296244f), SkBits2Float(0x4211cb64), SkBits2Float(0xc2952332));
+path.lineTo(SkBits2Float(0x41d2c988), SkBits2Float(0xc2579ed7));
+path.cubicTo(SkBits2Float(0x41ccd887), SkBits2Float(0xc2591291), SkBits2Float(0x41c6d852), SkBits2Float(0xc25a7689), SkBits2Float(0x41c0c9e6), SkBits2Float(0xc25bca86));
+path.cubicTo(SkBits2Float(0x418402cc), SkBits2Float(0xc2691e6b), SkBits2Float(0x4104bb66), SkBits2Float(0xc26fffff), SkBits2Float(0x3673fea5), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4211cb65), SkBits2Float(0xc2952332));
+path.cubicTo(SkBits2Float(0x42550406), SkBits2Float(0xc284b578), SkBits2Float(0x42859569), SkBits2Float(0xc252d13a), SkBits2Float(0x4295bbf4), SkBits2Float(0xc20f53bf));
+path.lineTo(SkBits2Float(0x42587bb2), SkBits2Float(0xc1cf3850));
+path.cubicTo(SkBits2Float(0x4241220a), SkBits2Float(0xc21865e8), SkBits2Float(0x4219fcbd), SkBits2Float(0xc23fde48), SkBits2Float(0x41d2c988), SkBits2Float(0xc2579ed8));
+path.lineTo(SkBits2Float(0x4211cb65), SkBits2Float(0xc2952332));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp128(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4151cd59), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41d04f3f), SkBits2Float(0xc29fc954), SkBits2Float(0x4216e058), SkBits2Float(0xc293de54));
+path.lineTo(SkBits2Float(0x41da226b), SkBits2Float(0xc255c926));
+path.cubicTo(SkBits2Float(0x419695d1), SkBits2Float(0xc267043d), SkBits2Float(0x4117aa0a), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4216e057), SkBits2Float(0xc293de54));
+path.cubicTo(SkBits2Float(0x421b86ea), SkBits2Float(0xc292aea0), SkBits2Float(0x42201eff), SkBits2Float(0xc29170ed), SkBits2Float(0x4224a79b), SkBits2Float(0xc290257e));
+path.lineTo(SkBits2Float(0x41ee0e15), SkBits2Float(0xc2506790));
+path.cubicTo(SkBits2Float(0x41e78019), SkBits2Float(0xc25246bf), SkBits2Float(0x41e0dbbc), SkBits2Float(0xc2541212), SkBits2Float(0x41da226b), SkBits2Float(0xc255c927));
+path.lineTo(SkBits2Float(0x4216e057), SkBits2Float(0xc293de54));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp129(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4151cd58), SkBits2Float(0xc2a60000), SkBits2Float(0x41d04f3d), SkBits2Float(0xc29fc954), SkBits2Float(0x4216e057), SkBits2Float(0xc293de54));
+path.lineTo(SkBits2Float(0x4216e058), SkBits2Float(0xc293de54));
+path.cubicTo(SkBits2Float(0x421b86eb), SkBits2Float(0xc292aea0), SkBits2Float(0x42201eff), SkBits2Float(0xc29170ed), SkBits2Float(0x4224a79b), SkBits2Float(0xc290257e));
+path.lineTo(SkBits2Float(0x41ee0e15), SkBits2Float(0xc2506790));
+path.cubicTo(SkBits2Float(0x41e78019), SkBits2Float(0xc25246bf), SkBits2Float(0x41e0dbbc), SkBits2Float(0xc2541212), SkBits2Float(0x41da226b), SkBits2Float(0xc255c927));
+path.lineTo(SkBits2Float(0x41da226b), SkBits2Float(0xc255c926));
+path.cubicTo(SkBits2Float(0x419695d1), SkBits2Float(0xc267043d), SkBits2Float(0x4117aa0a), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4224a79b), SkBits2Float(0xc290257f));
+path.cubicTo(SkBits2Float(0x426f06c3), SkBits2Float(0xc275d105), SkBits2Float(0x42930d85), SkBits2Float(0xc2303df6), SkBits2Float(0x429f3103), SkBits2Float(0xc1bc373f));
+path.lineTo(SkBits2Float(0x42662806), SkBits2Float(0xc1880f44));
+path.cubicTo(SkBits2Float(0x42549b44), SkBits2Float(0xc1fececc), SkBits2Float(0x422cca4c), SkBits2Float(0xc231b2de), SkBits2Float(0x41ee0e18), SkBits2Float(0xc2506792));
+path.lineTo(SkBits2Float(0x4224a79b), SkBits2Float(0xc290257f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp130(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x417054a2), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41ee1405), SkBits2Float(0xc29dd904), SkBits2Float(0x422a9595), SkBits2Float(0xc28e6989));
+path.lineTo(SkBits2Float(0x41f6a0c0), SkBits2Float(0xc24de5b0));
+path.cubicTo(SkBits2Float(0x41ac1ad0), SkBits2Float(0xc26436ad), SkBits2Float(0x412dbba0), SkBits2Float(0xc2700000), SkBits2Float(0xb630015b), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x422a9596), SkBits2Float(0xc28e6989));
+path.cubicTo(SkBits2Float(0x422fb535), SkBits2Float(0xc28ce0c4), SkBits2Float(0x4234bf65), SkBits2Float(0xc28b465e), SkBits2Float(0x4239b2bc), SkBits2Float(0xc2899acc));
+path.lineTo(SkBits2Float(0x42063d5a), SkBits2Float(0xc246f24e));
+path.cubicTo(SkBits2Float(0x4202a934), SkBits2Float(0xc2495c7c), SkBits2Float(0x41fe0912), SkBits2Float(0xc24badd5), SkBits2Float(0x41f6a0c0), SkBits2Float(0xc24de5b1));
+path.lineTo(SkBits2Float(0x422a9596), SkBits2Float(0xc28e6989));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp131(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb630015b), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x417054a2), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41ee1405), SkBits2Float(0xc29dd904), SkBits2Float(0x422a9596), SkBits2Float(0xc28e6989));
+path.cubicTo(SkBits2Float(0x422fb535), SkBits2Float(0xc28ce0c4), SkBits2Float(0x4234bf65), SkBits2Float(0xc28b465e), SkBits2Float(0x4239b2bc), SkBits2Float(0xc2899acc));
+path.lineTo(SkBits2Float(0x42063d5a), SkBits2Float(0xc246f24e));
+path.cubicTo(SkBits2Float(0x4202a934), SkBits2Float(0xc2495c7c), SkBits2Float(0x41fe0912), SkBits2Float(0xc24badd5), SkBits2Float(0x41f6a0c0), SkBits2Float(0xc24de5b0));
+path.cubicTo(SkBits2Float(0x41ac1ad0), SkBits2Float(0xc26436ad), SkBits2Float(0x412dbba0), SkBits2Float(0xc2700000), SkBits2Float(0xb630015b), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4239b2bd), SkBits2Float(0xc2899acc));
+path.cubicTo(SkBits2Float(0x42859c2b), SkBits2Float(0xc25c33ca), SkBits2Float(0x42a01474), SkBits2Float(0xc203e23a), SkBits2Float(0x42a51fce), SkBits2Float(0xc1083bae));
+path.lineTo(SkBits2Float(0x426ebbdb), SkBits2Float(0xc0c4f6ab));
+path.cubicTo(SkBits2Float(0x426770d9), SkBits2Float(0xc1beacda), SkBits2Float(0x42412bce), SkBits2Float(0xc21f2eb0), SkBits2Float(0x42063d5a), SkBits2Float(0xc246f24e));
+path.lineTo(SkBits2Float(0x4239b2bd), SkBits2Float(0xc2899acc));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp132(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4187e175), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42063ec3), SkBits2Float(0xc29b93fb), SkBits2Float(0x423df6fd), SkBits2Float(0xc2882410));
+path.lineTo(SkBits2Float(0x420952ef), SkBits2Float(0xc244d488));
+path.cubicTo(SkBits2Float(0x41c216e4), SkBits2Float(0xc260eea0), SkBits2Float(0x4144743c), SkBits2Float(0xc26fffff), SkBits2Float(0x357ffa94), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423df6fe), SkBits2Float(0xc2882411));
+path.cubicTo(SkBits2Float(0x42437e7a), SkBits2Float(0xc286364a), SkBits2Float(0x4248e78f), SkBits2Float(0xc2843312), SkBits2Float(0x424e304d), SkBits2Float(0xc2821b20));
+path.lineTo(SkBits2Float(0x42150d53), SkBits2Float(0xc23c1ae0));
+path.cubicTo(SkBits2Float(0x42113b72), SkBits2Float(0xc23f21be), SkBits2Float(0x420d522e), SkBits2Float(0xc2420aa4), SkBits2Float(0x420952ef), SkBits2Float(0xc244d48a));
+path.lineTo(SkBits2Float(0x423df6fe), SkBits2Float(0xc2882411));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp133(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4187e175), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42063ec3), SkBits2Float(0xc29b93fb), SkBits2Float(0x423df6fe), SkBits2Float(0xc2882411));
+path.cubicTo(SkBits2Float(0x42437e7a), SkBits2Float(0xc286364a), SkBits2Float(0x4248e78f), SkBits2Float(0xc2843312), SkBits2Float(0x424e304d), SkBits2Float(0xc2821b20));
+path.lineTo(SkBits2Float(0x42150d53), SkBits2Float(0xc23c1ae0));
+path.cubicTo(SkBits2Float(0x42113b72), SkBits2Float(0xc23f21be), SkBits2Float(0x420d522e), SkBits2Float(0xc2420aa4), SkBits2Float(0x420952ef), SkBits2Float(0xc244d48a));
+path.lineTo(SkBits2Float(0x420952ef), SkBits2Float(0xc244d488));
+path.cubicTo(SkBits2Float(0x41c216e4), SkBits2Float(0xc260eea0), SkBits2Float(0x4144743c), SkBits2Float(0xc26fffff), SkBits2Float(0x00000000), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x424e304d), SkBits2Float(0xc2821b20));
+path.cubicTo(SkBits2Float(0x4292cbf1), SkBits2Float(0xc23ef41d), SkBits2Float(0x42aa31a6), SkBits2Float(0xc1a4e14c), SkBits2Float(0x42a56158), SkBits2Float(0x40e54b3a));
+path.lineTo(SkBits2Float(0x426f1a9e), SkBits2Float(0x40a5c12f));
+path.cubicTo(SkBits2Float(0x42761044), SkBits2Float(0xc16e617c), SkBits2Float(0x42543c73), SkBits2Float(0xc20a09ea), SkBits2Float(0x42150d54), SkBits2Float(0xc23c1ae1));
+path.lineTo(SkBits2Float(0x424e304d), SkBits2Float(0xc2821b20));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp134(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x419c5b1f), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4219d929), SkBits2Float(0xc29834b3), SkBits2Float(0x4255ae76), SkBits2Float(0xc27e184c));
+path.lineTo(SkBits2Float(0x421a77f2), SkBits2Float(0xc237aede));
+path.cubicTo(SkBits2Float(0x41de6e66), SkBits2Float(0xc25c0e82), SkBits2Float(0x41620e8a), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4255ae76), SkBits2Float(0xc27e184c));
+path.cubicTo(SkBits2Float(0x425b9ab5), SkBits2Float(0xc2791d33), SkBits2Float(0x426159ea), SkBits2Float(0xc273ed7b), SkBits2Float(0x4266e960), SkBits2Float(0xc26e8b92));
+path.lineTo(SkBits2Float(0x4226ec90), SkBits2Float(0xc22c713c));
+path.cubicTo(SkBits2Float(0x4222e78d), SkBits2Float(0xc2305550), SkBits2Float(0x421ec008), SkBits2Float(0xc234151d), SkBits2Float(0x421a77f3), SkBits2Float(0xc237aedd));
+path.lineTo(SkBits2Float(0x4255ae76), SkBits2Float(0xc27e184c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp135(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x419c5b1f), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4219d929), SkBits2Float(0xc29834b3), SkBits2Float(0x4255ae76), SkBits2Float(0xc27e184c));
+path.cubicTo(SkBits2Float(0x425b9ab5), SkBits2Float(0xc2791d33), SkBits2Float(0x426159ea), SkBits2Float(0xc273ed7b), SkBits2Float(0x4266e960), SkBits2Float(0xc26e8b92));
+path.lineTo(SkBits2Float(0x4226ec90), SkBits2Float(0xc22c713c));
+path.cubicTo(SkBits2Float(0x4222e78d), SkBits2Float(0xc2305550), SkBits2Float(0x421ec008), SkBits2Float(0xc234151d), SkBits2Float(0x421a77f2), SkBits2Float(0xc237aede));
+path.cubicTo(SkBits2Float(0x41de6e66), SkBits2Float(0xc25c0e82), SkBits2Float(0x41620e8a), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4266e961), SkBits2Float(0xc26e8b93));
+path.cubicTo(SkBits2Float(0x42a1bfce), SkBits2Float(0xc214ebcf), SkBits2Float(0x42b1ee5a), SkBits2Float(0xc05d1412), SkBits2Float(0x429cf75a), SkBits2Float(0x41d80f2c));
+path.lineTo(SkBits2Float(0x4262f06b), SkBits2Float(0x419c2ffb));
+path.cubicTo(SkBits2Float(0x42809ff9), SkBits2Float(0xc01fd0e5), SkBits2Float(0x4269dab8), SkBits2Float(0xc1d74ec6), SkBits2Float(0x4226ec91), SkBits2Float(0xc22c713d));
+path.lineTo(SkBits2Float(0x4266e961), SkBits2Float(0xc26e8b93));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp136(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41ae0130), SkBits2Float(0xc2a5ffff), SkBits2Float(0x422a8737), SkBits2Float(0xc294ec91), SkBits2Float(0x42689b67), SkBits2Float(0xc26ce46c));
+path.lineTo(SkBits2Float(0x42282651), SkBits2Float(0xc22b3f58));
+path.cubicTo(SkBits2Float(0x41f68bfb), SkBits2Float(0xc2574fdc), SkBits2Float(0x417b92b3), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42689b68), SkBits2Float(0xc26ce46d));
+path.cubicTo(SkBits2Float(0x426ebcd2), SkBits2Float(0xc266df67), SkBits2Float(0x4274a1d2), SkBits2Float(0xc2609e09), SkBits2Float(0x427a4701), SkBits2Float(0xc25a23f2));
+path.lineTo(SkBits2Float(0x4234ec64), SkBits2Float(0xc21db11e));
+path.cubicTo(SkBits2Float(0x4230d7ae), SkBits2Float(0xc2225fbc), SkBits2Float(0x422c94d6), SkBits2Float(0xc226e55a), SkBits2Float(0x42282652), SkBits2Float(0xc22b3f58));
+path.lineTo(SkBits2Float(0x42689b68), SkBits2Float(0xc26ce46d));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp137(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41ae0130), SkBits2Float(0xc2a5ffff), SkBits2Float(0x422a8737), SkBits2Float(0xc294ec91), SkBits2Float(0x42689b68), SkBits2Float(0xc26ce46d));
+path.cubicTo(SkBits2Float(0x426ebcd2), SkBits2Float(0xc266df67), SkBits2Float(0x4274a1d2), SkBits2Float(0xc2609e09), SkBits2Float(0x427a4701), SkBits2Float(0xc25a23f2));
+path.lineTo(SkBits2Float(0x4234ec64), SkBits2Float(0xc21db11e));
+path.cubicTo(SkBits2Float(0x4230d7ae), SkBits2Float(0xc2225fbc), SkBits2Float(0x422c94d6), SkBits2Float(0xc226e55a), SkBits2Float(0x42282651), SkBits2Float(0xc22b3f58));
+path.cubicTo(SkBits2Float(0x41f68bfb), SkBits2Float(0xc2574fdc), SkBits2Float(0x417b92b3), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x427a4702), SkBits2Float(0xc25a23f2));
+path.cubicTo(SkBits2Float(0x42ac7185), SkBits2Float(0xc1db2f83), SkBits2Float(0x42b35ed0), SkBits2Float(0x413e447a), SkBits2Float(0x428e4a3d), SkBits2Float(0x422afde8));
+path.lineTo(SkBits2Float(0x424db871), SkBits2Float(0x41f73799));
+path.cubicTo(SkBits2Float(0x4281aa54), SkBits2Float(0x41098afa), SkBits2Float(0x427950da), SkBits2Float(0xc19e728d), SkBits2Float(0x4234ec66), SkBits2Float(0xc21db120));
+path.lineTo(SkBits2Float(0x427a4702), SkBits2Float(0xc25a23f2));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp138(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41c2602d), SkBits2Float(0xc2a5ffff), SkBits2Float(0x423d7ece), SkBits2Float(0xc290b51a), SkBits2Float(0x427c92bc), SkBits2Float(0xc2577a5f));
+path.lineTo(SkBits2Float(0x42369543), SkBits2Float(0xc21bc469));
+path.cubicTo(SkBits2Float(0x4208fc10), SkBits2Float(0xc2513731), SkBits2Float(0x418c8338), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x427c92be), SkBits2Float(0xc2577a5f));
+path.cubicTo(SkBits2Float(0x42816448), SkBits2Float(0xc25032db), SkBits2Float(0x42845689), SkBits2Float(0xc248a77c), SkBits2Float(0x42871e08), SkBits2Float(0xc240ddaa));
+path.lineTo(SkBits2Float(0x424359af), SkBits2Float(0xc20b6bce));
+path.cubicTo(SkBits2Float(0x423f5505), SkBits2Float(0xc2110d1f), SkBits2Float(0x423b1287), SkBits2Float(0xc216814b), SkBits2Float(0x42369543), SkBits2Float(0xc21bc46a));
+path.lineTo(SkBits2Float(0x427c92be), SkBits2Float(0xc2577a5f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp139(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41c2602d), SkBits2Float(0xc2a5ffff), SkBits2Float(0x423d7ece), SkBits2Float(0xc290b51a), SkBits2Float(0x427c92bc), SkBits2Float(0xc2577a5f));
+path.lineTo(SkBits2Float(0x427c92be), SkBits2Float(0xc2577a5f));
+path.cubicTo(SkBits2Float(0x42816448), SkBits2Float(0xc25032db), SkBits2Float(0x42845689), SkBits2Float(0xc248a77c), SkBits2Float(0x42871e08), SkBits2Float(0xc240ddaa));
+path.lineTo(SkBits2Float(0x424359af), SkBits2Float(0xc20b6bce));
+path.cubicTo(SkBits2Float(0x423f5505), SkBits2Float(0xc2110d1f), SkBits2Float(0x423b1287), SkBits2Float(0xc216814a), SkBits2Float(0x42369543), SkBits2Float(0xc21bc469));
+path.lineTo(SkBits2Float(0x42369543), SkBits2Float(0xc21bc46a));
+path.cubicTo(SkBits2Float(0x4208fc10), SkBits2Float(0xc2513732), SkBits2Float(0x418c8337), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42871e08), SkBits2Float(0xc240ddaa));
+path.cubicTo(SkBits2Float(0x42b615a2), SkBits2Float(0xc174ff4e), SkBits2Float(0x42aecf41), SkBits2Float(0x41edcc49), SkBits2Float(0x426bc7a7), SkBits2Float(0x4269bc09));
+path.lineTo(SkBits2Float(0x422a717e), SkBits2Float(0x4228f6f7));
+path.cubicTo(SkBits2Float(0x427cbca0), SkBits2Float(0x41abe6f4), SkBits2Float(0x4283a09b), SkBits2Float(0xc1311b44), SkBits2Float(0x424359af), SkBits2Float(0xc20b6bcd));
+path.lineTo(SkBits2Float(0x42871e08), SkBits2Float(0xc240ddaa));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp140(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41d9e52a), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4252f644), SkBits2Float(0xc28b460f), SkBits2Float(0x42887c98), SkBits2Float(0xc23cf83b));
+path.lineTo(SkBits2Float(0x42455485), SkBits2Float(0xc2089ac5));
+path.cubicTo(SkBits2Float(0x421880ae), SkBits2Float(0xc2495c0a), SkBits2Float(0x419d83bb), SkBits2Float(0xc2700000), SkBits2Float(0xb560056c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42887c98), SkBits2Float(0xc23cf83b));
+path.cubicTo(SkBits2Float(0x428b8706), SkBits2Float(0xc2342f4a), SkBits2Float(0x428e5ab7), SkBits2Float(0xc22b1c84), SkBits2Float(0x4290f525), SkBits2Float(0xc221c800));
+path.lineTo(SkBits2Float(0x425193c7), SkBits2Float(0xc1e9e68d));
+path.cubicTo(SkBits2Float(0x424dd044), SkBits2Float(0xc1f763d3), SkBits2Float(0x4249b9f6), SkBits2Float(0xc2024108), SkBits2Float(0x42455485), SkBits2Float(0xc2089ac6));
+path.lineTo(SkBits2Float(0x42887c98), SkBits2Float(0xc23cf83b));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp141(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41d9e52a), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4252f644), SkBits2Float(0xc28b460f), SkBits2Float(0x42887c98), SkBits2Float(0xc23cf83b));
+path.cubicTo(SkBits2Float(0x428b8706), SkBits2Float(0xc2342f4a), SkBits2Float(0x428e5ab7), SkBits2Float(0xc22b1c84), SkBits2Float(0x4290f525), SkBits2Float(0xc221c800));
+path.lineTo(SkBits2Float(0x425193c7), SkBits2Float(0xc1e9e68d));
+path.cubicTo(SkBits2Float(0x424dd044), SkBits2Float(0xc1f763d3), SkBits2Float(0x4249b9f6), SkBits2Float(0xc2024107), SkBits2Float(0x42455485), SkBits2Float(0xc2089ac5));
+path.lineTo(SkBits2Float(0x42455485), SkBits2Float(0xc2089ac6));
+path.cubicTo(SkBits2Float(0x421880ae), SkBits2Float(0xc2495c0b), SkBits2Float(0x419d83ba), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4290f526), SkBits2Float(0xc221c800));
+path.cubicTo(SkBits2Float(0x42bd6cdd), SkBits2Float(0xbf1a1474), SkBits2Float(0x42a13baa), SkBits2Float(0x4246de93), SkBits2Float(0x4223add7), SkBits2Float(0x42906c8a));
+path.lineTo(SkBits2Float(0x41eca4f8), SkBits2Float(0x4250ce48));
+path.cubicTo(SkBits2Float(0x42691bac), SkBits2Float(0x420fc2d7), SkBits2Float(0x4288ef16), SkBits2Float(0xbedec420), SkBits2Float(0x425193c9), SkBits2Float(0xc1e9e690));
+path.lineTo(SkBits2Float(0x4290f526), SkBits2Float(0xc221c800));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp142(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f6a97d), SkBits2Float(0xc2a60000), SkBits2Float(0x426c7f9e), SkBits2Float(0xc283d12f), SkBits2Float(0x4292f07c), SkBits2Float(0xc21a76e5));
+path.lineTo(SkBits2Float(0x42547147), SkBits2Float(0xc1df5274));
+path.cubicTo(SkBits2Float(0x422af677), SkBits2Float(0xc23e9438), SkBits2Float(0x41b24f58), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4292f07c), SkBits2Float(0xc21a76e5));
+path.cubicTo(SkBits2Float(0x4295bcf6), SkBits2Float(0xc20fd099), SkBits2Float(0x42983ed1), SkBits2Float(0xc204de6d), SkBits2Float(0x429a7333), SkBits2Float(0xc1f3598c));
+path.lineTo(SkBits2Float(0x425f4d1c), SkBits2Float(0xc1afea60));
+path.cubicTo(SkBits2Float(0x425c1d22), SkBits2Float(0xc1c0197b), SkBits2Float(0x42587d28), SkBits2Float(0xc1cfecd2), SkBits2Float(0x42547148), SkBits2Float(0xc1df5275));
+path.lineTo(SkBits2Float(0x4292f07c), SkBits2Float(0xc21a76e5));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp143(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f6a97d), SkBits2Float(0xc2a60000), SkBits2Float(0x426c7f9e), SkBits2Float(0xc283d12f), SkBits2Float(0x4292f07c), SkBits2Float(0xc21a76e5));
+path.cubicTo(SkBits2Float(0x4295bcf6), SkBits2Float(0xc20fd099), SkBits2Float(0x42983ed1), SkBits2Float(0xc204de6d), SkBits2Float(0x429a7333), SkBits2Float(0xc1f3598c));
+path.lineTo(SkBits2Float(0x425f4d1c), SkBits2Float(0xc1afea60));
+path.cubicTo(SkBits2Float(0x425c1d22), SkBits2Float(0xc1c0197b), SkBits2Float(0x42587d28), SkBits2Float(0xc1cfecd2), SkBits2Float(0x42547147), SkBits2Float(0xc1df5274));
+path.cubicTo(SkBits2Float(0x422af677), SkBits2Float(0xc23e9438), SkBits2Float(0x41b24f58), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429a7334), SkBits2Float(0xc1f3598d));
+path.cubicTo(SkBits2Float(0x42ac9a56), SkBits2Float(0xc0ec08d5), SkBits2Float(0x42a93a4b), SkBits2Float(0x4194209c), SkBits2Float(0x42913f11), SkBits2Float(0x4220bdeb));
+path.cubicTo(SkBits2Float(0x427287b0), SkBits2Float(0x42776b87), SkBits2Float(0x421e5dc6), SkBits2Float(0x429a1372), SkBits2Float(0x4173f4a4), SkBits2Float(0x42a32ccd));
+path.lineTo(SkBits2Float(0x41305a7f), SkBits2Float(0x426bea6b));
+path.cubicTo(SkBits2Float(0x41e4f69e), SkBits2Float(0x425ec2af), SkBits2Float(0x422f52ad), SkBits2Float(0x4232db9e), SkBits2Float(0x4251feaa), SkBits2Float(0x41e865df));
+path.cubicTo(SkBits2Float(0x4274aaa7), SkBits2Float(0x41562902), SkBits2Float(0x42798bdd), SkBits2Float(0xc0aaa09a), SkBits2Float(0x425f4d1d), SkBits2Float(0xc1afea60));
+path.lineTo(SkBits2Float(0x429a7334), SkBits2Float(0xc1f3598d));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp144(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42079c39), SkBits2Float(0xc2a60000), SkBits2Float(0x4280cb64), SkBits2Float(0xc279860f), SkBits2Float(0x429a0d79), SkBits2Float(0xc1f758df));
+path.lineTo(SkBits2Float(0x425eba08), SkBits2Float(0xc1b2ce1f));
+path.cubicTo(SkBits2Float(0x423a357b), SkBits2Float(0xc23460ea), SkBits2Float(0x41c41023), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429a0d79), SkBits2Float(0xc1f758de));
+path.cubicTo(SkBits2Float(0x429c811b), SkBits2Float(0xc1deea6e), SkBits2Float(0x429e9731), SkBits2Float(0xc1c5ec3a), SkBits2Float(0x42a04ce7), SkBits2Float(0xc1ac8024));
+path.lineTo(SkBits2Float(0x4267c277), SkBits2Float(0xc17965fc));
+path.cubicTo(SkBits2Float(0x426549a1), SkBits2Float(0xc18f13a3), SkBits2Float(0x42624575), SkBits2Float(0xc1a124d8), SkBits2Float(0x425eba09), SkBits2Float(0xc1b2ce1e));
+path.lineTo(SkBits2Float(0x429a0d79), SkBits2Float(0xc1f758de));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp145(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42079c39), SkBits2Float(0xc2a60000), SkBits2Float(0x4280cb64), SkBits2Float(0xc279860f), SkBits2Float(0x429a0d79), SkBits2Float(0xc1f758df));
+path.lineTo(SkBits2Float(0x42a04ce7), SkBits2Float(0xc1ac8024));
+path.lineTo(SkBits2Float(0x4267c277), SkBits2Float(0xc17965fc));
+path.cubicTo(SkBits2Float(0x426549a1), SkBits2Float(0xc18f13a3), SkBits2Float(0x42624575), SkBits2Float(0xc1a124d8), SkBits2Float(0x425eba09), SkBits2Float(0xc1b2ce1e));
+path.lineTo(SkBits2Float(0x425eba08), SkBits2Float(0xc1b2ce1f));
+path.cubicTo(SkBits2Float(0x423a357b), SkBits2Float(0xc23460ea), SkBits2Float(0x41c41023), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a04ce8), SkBits2Float(0xc1ac8024));
+path.cubicTo(SkBits2Float(0x42ae6ca1), SkBits2Float(0x4095ff41), SkBits2Float(0x42a1f1fa), SkBits2Float(0x4202ed54), SkBits2Float(0x427dc9de), SkBits2Float(0x42560b98));
+path.cubicTo(SkBits2Float(0x4237afc7), SkBits2Float(0x429494ee), SkBits2Float(0x419aa752), SkBits2Float(0x42aa57e8), SkBits2Float(0xc0f777b3), SkBits2Float(0x42a54724));
+path.lineTo(SkBits2Float(0xc0b2e472), SkBits2Float(0x426ef4bb));
+path.cubicTo(SkBits2Float(0x415f9870), SkBits2Float(0x42764794), SkBits2Float(0x4204c916), SkBits2Float(0x4256d126), SkBits2Float(0x4237762a), SkBits2Float(0x421abb46));
+path.cubicTo(SkBits2Float(0x426a233f), SkBits2Float(0x41bd4acb), SkBits2Float(0x427c2e04), SkBits2Float(0x4058dcfe), SkBits2Float(0x4267c279), SkBits2Float(0xc17965fc));
+path.lineTo(SkBits2Float(0x42a04ce8), SkBits2Float(0xc1ac8024));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp146(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x421472e7), SkBits2Float(0xc2a5ffff), SkBits2Float(0x428b6da4), SkBits2Float(0xc26973d7), SkBits2Float(0x429fb179), SkBits2Float(0xc1b54986));
+path.lineTo(SkBits2Float(0x4266e1be), SkBits2Float(0xc1830d0f));
+path.cubicTo(SkBits2Float(0x42499544), SkBits2Float(0xc228c2c8), SkBits2Float(0x41d69ff6), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429fb179), SkBits2Float(0xc1b54988));
+path.cubicTo(SkBits2Float(0x42a1a632), SkBits2Float(0xc199b837), SkBits2Float(0x42a3282f), SkBits2Float(0xc17b594e), SkBits2Float(0x42a43501), SkBits2Float(0xc142a7ba));
+path.lineTo(SkBits2Float(0x426d6865), SkBits2Float(0xc10cb6f0));
+path.cubicTo(SkBits2Float(0x426be3bc), SkBits2Float(0xc135b2ae), SkBits2Float(0x4269b5af), SkBits2Float(0xc15e3ec8), SkBits2Float(0x4266e1be), SkBits2Float(0xc1830d0f));
+path.lineTo(SkBits2Float(0x429fb179), SkBits2Float(0xc1b54988));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp147(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x421472e7), SkBits2Float(0xc2a60000), SkBits2Float(0x428b6da4), SkBits2Float(0xc26973d8), SkBits2Float(0x429fb179), SkBits2Float(0xc1b54988));
+path.lineTo(SkBits2Float(0x429fb179), SkBits2Float(0xc1b54986));
+path.cubicTo(SkBits2Float(0x42a1a632), SkBits2Float(0xc199b836), SkBits2Float(0x42a3282f), SkBits2Float(0xc17b594d), SkBits2Float(0x42a43501), SkBits2Float(0xc142a7ba));
+path.lineTo(SkBits2Float(0x426d6865), SkBits2Float(0xc10cb6f0));
+path.cubicTo(SkBits2Float(0x426be3bc), SkBits2Float(0xc135b2ae), SkBits2Float(0x4269b5af), SkBits2Float(0xc15e3ec8), SkBits2Float(0x4266e1be), SkBits2Float(0xc1830d0f));
+path.cubicTo(SkBits2Float(0x42499544), SkBits2Float(0xc228c2c8), SkBits2Float(0x41d69ff6), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a43502), SkBits2Float(0xc142a7bb));
+path.cubicTo(SkBits2Float(0x42ace9b0), SkBits2Float(0x4189ae79), SkBits2Float(0x429590d6), SkBits2Float(0x423ab1c1), SkBits2Float(0x424df762), SkBits2Float(0x428231a6));
+path.cubicTo(SkBits2Float(0x41e19a31), SkBits2Float(0x42a70a69), SkBits2Float(0xc04a3289), SkBits2Float(0x42b03133), SkBits2Float(0xc1f5f36e), SkBits2Float(0x429a3139));
+path.lineTo(SkBits2Float(0xc1b1cbb9), SkBits2Float(0x425eedb9));
+path.cubicTo(SkBits2Float(0xc0122aac), SkBits2Float(0x427ebc5a), SkBits2Float(0x41a31606), SkBits2Float(0x42718130), SkBits2Float(0x4214e430), SkBits2Float(0x423c3b73));
+path.cubicTo(SkBits2Float(0x42583d5c), SkBits2Float(0x4206f5b6), SkBits2Float(0x4279fe97), SkBits2Float(0x41470ec8), SkBits2Float(0x426d6866), SkBits2Float(0xc10cb6eb));
+path.lineTo(SkBits2Float(0x42a43502), SkBits2Float(0xc142a7bb));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp148(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return;
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42216831), SkBits2Float(0xc2a60000), SkBits2Float(0x4295b6bc), SkBits2Float(0xc257ea44), SkBits2Float(0x42a38b53), SkBits2Float(0xc1639572));
+path.lineTo(SkBits2Float(0x426c7311), SkBits2Float(0xc12484b9));
+path.cubicTo(SkBits2Float(0x42587424), SkBits2Float(0xc21c154e), SkBits2Float(0x41e95c08), SkBits2Float(0xc2700000), SkBits2Float(0xb560056c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a38b52), SkBits2Float(0xc1639578));
+path.cubicTo(SkBits2Float(0x42a4def8), SkBits2Float(0xc1269090), SkBits2Float(0x42a5a99a), SkBits2Float(0xc0d1c16f), SkBits2Float(0x42a5e9be), SkBits2Float(0xc02be63c));
+path.lineTo(SkBits2Float(0x426fdfd2), SkBits2Float(0xbff8877d));
+path.cubicTo(SkBits2Float(0x426f8319), SkBits2Float(0xc097a16e), SkBits2Float(0x426e5e22), SkBits2Float(0xc0f0d105), SkBits2Float(0x426c7311), SkBits2Float(0xc12484ba));
+path.lineTo(SkBits2Float(0x42a38b52), SkBits2Float(0xc1639578));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp149(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42216831), SkBits2Float(0xc2a60000), SkBits2Float(0x4295b6bc), SkBits2Float(0xc257ea44), SkBits2Float(0x42a38b52), SkBits2Float(0xc1639578));
+path.lineTo(SkBits2Float(0x426c7311), SkBits2Float(0xc12484ba));
+path.cubicTo(SkBits2Float(0x42587424), SkBits2Float(0xc21c154e), SkBits2Float(0x41e95c08), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a5e9be), SkBits2Float(0xc02be63f));
+path.cubicTo(SkBits2Float(0x42a7ff8e), SkBits2Float(0x41ec1faa), SkBits2Float(0x42849fff), SkBits2Float(0x426da4e1), SkBits2Float(0x4216595b), SkBits2Float(0x429400af));
+path.cubicTo(SkBits2Float(0x410dcade), SkBits2Float(0x42b12eec), SkBits2Float(0xc1cdb135), SkBits2Float(0x42aa7b1c), SkBits2Float(0xc24c6646), SkBits2Float(0x4282cf52));
+path.lineTo(SkBits2Float(0xc213c238), SkBits2Float(0x423d1f66));
+path.cubicTo(SkBits2Float(0xc194b176), SkBits2Float(0x42767a79), SkBits2Float(0x40cd0045), SkBits2Float(0x42801597), SkBits2Float(0x41d95f44), SkBits2Float(0x4255fad4));
+path.cubicTo(SkBits2Float(0x423fbf3c), SkBits2Float(0x422bca7a), SkBits2Float(0x4272e39a), SkBits2Float(0x41aab11f), SkBits2Float(0x426fdfd3), SkBits2Float(0xbff88758));
+path.lineTo(SkBits2Float(0x42a5e9be), SkBits2Float(0xc02be63f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp150(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x422dab0f), SkBits2Float(0xc2a5ffff), SkBits2Float(0x429efeec), SkBits2Float(0xc2462810), SkBits2Float(0x42a58789), SkBits2Float(0xc0c7d837));
+path.lineTo(SkBits2Float(0x426f51d5), SkBits2Float(0xc0907750));
+path.cubicTo(SkBits2Float(0x4265df9a), SkBits2Float(0xc20f3ee4), SkBits2Float(0x41fb162c), SkBits2Float(0xc26ffffe), SkBits2Float(0x3637fea5), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a58789), SkBits2Float(0xc0c7d840));
+path.cubicTo(SkBits2Float(0x42a626ff), SkBits2Float(0xc0078454), SkBits2Float(0x42a62824), SkBits2Float(0x4001c6d5), SkBits2Float(0x42a58af5), SkBits2Float(0x40c4fc3c));
+path.lineTo(SkBits2Float(0x426f56ca), SkBits2Float(0x408e6626));
+path.cubicTo(SkBits2Float(0x42703a0b), SkBits2Float(0x3fbba106), SkBits2Float(0x42703864), SkBits2Float(0xbfc3ed93), SkBits2Float(0x426f51d4), SkBits2Float(0xc090774f));
+path.lineTo(SkBits2Float(0x42a58789), SkBits2Float(0xc0c7d840));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp151(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x422dab0f), SkBits2Float(0xc2a60000), SkBits2Float(0x429efeec), SkBits2Float(0xc2462811), SkBits2Float(0x42a58789), SkBits2Float(0xc0c7d840));
+path.lineTo(SkBits2Float(0x42a58789), SkBits2Float(0xc0c7d837));
+path.cubicTo(SkBits2Float(0x42a626ff), SkBits2Float(0xc0078448), SkBits2Float(0x42a62824), SkBits2Float(0x4001c6db), SkBits2Float(0x42a58af5), SkBits2Float(0x40c4fc3c));
+path.lineTo(SkBits2Float(0x426f56ca), SkBits2Float(0x408e6626));
+path.cubicTo(SkBits2Float(0x42703a0b), SkBits2Float(0x3fbba106), SkBits2Float(0x42703864), SkBits2Float(0xbfc3ed93), SkBits2Float(0x426f51d4), SkBits2Float(0xc090774f));
+path.lineTo(SkBits2Float(0x426f51d5), SkBits2Float(0xc0907750));
+path.cubicTo(SkBits2Float(0x4265df9a), SkBits2Float(0xc20f3ee4), SkBits2Float(0x41fb162c), SkBits2Float(0xc26ffffe), SkBits2Float(0x3637fea5), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a58af6), SkBits2Float(0x40c4fc3d));
+path.cubicTo(SkBits2Float(0x42a06986), SkBits2Float(0x422298c3), SkBits2Float(0x42621341), SkBits2Float(0x428bdf10), SkBits2Float(0x41ba9762), SkBits2Float(0x429f4f99));
+path.cubicTo(SkBits2Float(0xc11def80), SkBits2Float(0x42b2c022), SkBits2Float(0xc236745f), SkBits2Float(0x429afb1c), SkBits2Float(0xc284c1e2), SkBits2Float(0x4247504a));
+path.lineTo(SkBits2Float(0xc23ff038), SkBits2Float(0x42101509));
+path.cubicTo(SkBits2Float(0xc203e517), SkBits2Float(0x4260119e), SkBits2Float(0xc0e45731), SkBits2Float(0x428137a0), SkBits2Float(0x4186e2a5), SkBits2Float(0x42665443));
+path.cubicTo(SkBits2Float(0x42236d8c), SkBits2Float(0x424a3945), SkBits2Float(0x4267ebda), SkBits2Float(0x41eb1462), SkBits2Float(0x426f56cb), SkBits2Float(0x408e661a));
+path.lineTo(SkBits2Float(0x42a58af6), SkBits2Float(0x40c4fc3d));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp152(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41b12ed4), SkBits2Float(0xc2a60000), SkBits2Float(0x422d822c), SkBits2Float(0xc2944bde), SkBits2Float(0x426bdb91), SkBits2Float(0xc269a7f3));
+path.cubicTo(SkBits2Float(0x42951a7b), SkBits2Float(0xc22ab829), SkBits2Float(0x42a66879), SkBits2Float(0xc1aaf2b1), SkBits2Float(0x42a5fe21), SkBits2Float(0x3f4744a4));
+path.lineTo(SkBits2Float(0x426ffd4c), SkBits2Float(0x3f100c99));
+path.cubicTo(SkBits2Float(0x4270970c), SkBits2Float(0xc177275d), SkBits2Float(0x4257923d), SkBits2Float(0xc1f6d2bd), SkBits2Float(0x422a7fe2), SkBits2Float(0xc228e872));
+path.cubicTo(SkBits2Float(0x41fadb0b), SkBits2Float(0xc2566785), SkBits2Float(0x41801584), SkBits2Float(0xc2700000), SkBits2Float(0xb560056c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a5fe22), SkBits2Float(0x3f4744a1));
+path.cubicTo(SkBits2Float(0x42a5e921), SkBits2Float(0x40a4df91), SkBits2Float(0x42a52322), SkBits2Float(0x411841f7), SkBits2Float(0x42a3adfe), SkBits2Float(0x415d43d0));
+path.lineTo(SkBits2Float(0x426ca531), SkBits2Float(0x411ff355));
+path.cubicTo(SkBits2Float(0x426ec0ad), SkBits2Float(0x40dc21ae), SkBits2Float(0x426fdeef), SkBits2Float(0x406e5efe), SkBits2Float(0x426ffd4d), SkBits2Float(0x3f100c9b));
+path.lineTo(SkBits2Float(0x42a5fe22), SkBits2Float(0x3f4744a1));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp153(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41b12ed4), SkBits2Float(0xc2a60000), SkBits2Float(0x422d822c), SkBits2Float(0xc2944bde), SkBits2Float(0x426bdb91), SkBits2Float(0xc269a7f3));
+path.cubicTo(SkBits2Float(0x42951a7b), SkBits2Float(0xc22ab829), SkBits2Float(0x42a66879), SkBits2Float(0xc1aaf2b1), SkBits2Float(0x42a5fe21), SkBits2Float(0x3f4744a0));
+path.lineTo(SkBits2Float(0x426ffd4c), SkBits2Float(0x3f100c99));
+path.cubicTo(SkBits2Float(0x4270970c), SkBits2Float(0xc177275d), SkBits2Float(0x4257923d), SkBits2Float(0xc1f6d2bd), SkBits2Float(0x422a7fe2), SkBits2Float(0xc228e872));
+path.cubicTo(SkBits2Float(0x41fadb0b), SkBits2Float(0xc2566785), SkBits2Float(0x41801584), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a3adfe), SkBits2Float(0x415d43d0));
+path.cubicTo(SkBits2Float(0x42977493), SkBits2Float(0x42480062), SkBits2Float(0x423a617c), SkBits2Float(0x429bbd03), SkBits2Float(0x4123044a), SkBits2Float(0x42a4be9a));
+path.cubicTo(SkBits2Float(0xc1d1beaf), SkBits2Float(0x42adc030), SkBits2Float(0xc2750d30), SkBits2Float(0x4285e3a3), SkBits2Float(0xc2980208), SkBits2Float(0x42056911));
+path.lineTo(SkBits2Float(0xc25bc541), SkBits2Float(0x41c0e1ed));
+path.cubicTo(SkBits2Float(0xc231254e), SkBits2Float(0x42419328), SkBits2Float(0xc1979f72), SkBits2Float(0x427b34be), SkBits2Float(0x40ebafde), SkBits2Float(0x426e2f5c));
+path.cubicTo(SkBits2Float(0x4206bbb1), SkBits2Float(0x426129fa), SkBits2Float(0x425af8c2), SkBits2Float(0x42109457), SkBits2Float(0x426ca533), SkBits2Float(0x411ff35b));
+path.lineTo(SkBits2Float(0x42a3adfe), SkBits2Float(0x415d43d0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp154(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41bb5603), SkBits2Float(0xc2a60000), SkBits2Float(0x4236fa4e), SkBits2Float(0xc2923760), SkBits2Float(0x4275e892), SkBits2Float(0xc25f0dc8));
+path.cubicTo(SkBits2Float(0x429a6b6b), SkBits2Float(0xc219acd0), SkBits2Float(0x42a9c473), SkBits2Float(0xc173c3a6), SkBits2Float(0x42a5369d), SkBits2Float(0x410121d8));
+path.lineTo(SkBits2Float(0x426edcd8), SkBits2Float(0x40bab276));
+path.cubicTo(SkBits2Float(0x42757264), SkBits2Float(0xc1303715), SkBits2Float(0x425f41dd), SkBits2Float(0xc1de2e4a), SkBits2Float(0x4231c3e2), SkBits2Float(0xc2213e66));
+path.cubicTo(SkBits2Float(0x420445e8), SkBits2Float(0xc25365a8), SkBits2Float(0x41876c72), SkBits2Float(0xc2700000), SkBits2Float(0xb560056c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a5369e), SkBits2Float(0x410121d6));
+path.cubicTo(SkBits2Float(0x42a450b5), SkBits2Float(0x414aab85), SkBits2Float(0x42a2a6cd), SkBits2Float(0x4189bd6e), SkBits2Float(0x42a03d57), SkBits2Float(0x41ad66e6));
+path.lineTo(SkBits2Float(0x4267abf7), SkBits2Float(0x417ab39f));
+path.cubicTo(SkBits2Float(0x426b28ae), SkBits2Float(0x41472463), SkBits2Float(0x426d9071), SkBits2Float(0x41128229), SkBits2Float(0x426edcd8), SkBits2Float(0x40bab277));
+path.lineTo(SkBits2Float(0x42a5369e), SkBits2Float(0x410121d6));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp155(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41bb5603), SkBits2Float(0xc2a60000), SkBits2Float(0x4236fa4e), SkBits2Float(0xc2923760), SkBits2Float(0x4275e892), SkBits2Float(0xc25f0dc8));
+path.cubicTo(SkBits2Float(0x429a6b6b), SkBits2Float(0xc219acd0), SkBits2Float(0x42a9c473), SkBits2Float(0xc173c3a8), SkBits2Float(0x42a5369d), SkBits2Float(0x410121d5));
+path.lineTo(SkBits2Float(0x42a5369e), SkBits2Float(0x410121d6));
+path.cubicTo(SkBits2Float(0x42a450b5), SkBits2Float(0x414aab85), SkBits2Float(0x42a2a6cd), SkBits2Float(0x4189bd6e), SkBits2Float(0x42a03d57), SkBits2Float(0x41ad66e6));
+path.lineTo(SkBits2Float(0x4267abf7), SkBits2Float(0x417ab39f));
+path.cubicTo(SkBits2Float(0x426b28ae), SkBits2Float(0x41472463), SkBits2Float(0x426d9071), SkBits2Float(0x41128229), SkBits2Float(0x426edcd8), SkBits2Float(0x40bab276));
+path.cubicTo(SkBits2Float(0x42757264), SkBits2Float(0xc1303715), SkBits2Float(0x425f41dd), SkBits2Float(0xc1de2e4a), SkBits2Float(0x4231c3e2), SkBits2Float(0xc2213e66));
+path.cubicTo(SkBits2Float(0x420445e8), SkBits2Float(0xc25365a8), SkBits2Float(0x41876c72), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a03d58), SkBits2Float(0x41ad66e7));
+path.cubicTo(SkBits2Float(0x428bedd4), SkBits2Float(0x426cda0a), SkBits2Float(0x420c6f35), SkBits2Float(0x42a955c4), SkBits2Float(0xc06f4c79), SkBits2Float(0x42a5d4d6));
+path.cubicTo(SkBits2Float(0xc22a58c2), SkBits2Float(0x42a253e8), SkBits2Float(0xc2960525), SkBits2Float(0x4252b394), SkBits2Float(0xc2a37db3), SkBits2Float(0x41660422));
+path.lineTo(SkBits2Float(0xc26c5f63), SkBits2Float(0x412646cf));
+path.cubicTo(SkBits2Float(0xc258e58a), SkBits2Float(0x4218507a), SkBits2Float(0xc1f648da), SkBits2Float(0x426ab0dc), SkBits2Float(0xc02cfcc3), SkBits2Float(0x426fc1a0));
+path.cubicTo(SkBits2Float(0x41cb09aa), SkBits2Float(0x4274d265), SkBits2Float(0x424a4e9e), SkBits2Float(0x422b37da), SkBits2Float(0x4267abf8), SkBits2Float(0x417ab398));
+path.lineTo(SkBits2Float(0x42a03d58), SkBits2Float(0x41ad66e7));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp156(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41c3ae1a), SkBits2Float(0xc2a60000), SkBits2Float(0x423eb2d3), SkBits2Float(0xc2906c00), SkBits2Float(0x427dc7c2), SkBits2Float(0xc2560e13));
+path.cubicTo(SkBits2Float(0x429e6e58), SkBits2Float(0xc20b4426), SkBits2Float(0x42abdf2b), SkBits2Float(0xc121d7a7), SkBits2Float(0x42a39f93), SkBits2Float(0x415fea21));
+path.lineTo(SkBits2Float(0x426c905a), SkBits2Float(0x4121ddae));
+path.cubicTo(SkBits2Float(0x42787d42), SkBits2Float(0xc0e9fd34), SkBits2Float(0x42650e94), SkBits2Float(0xc1c95949), SkBits2Float(0x423774a6), SkBits2Float(0xc21abd13));
+path.cubicTo(SkBits2Float(0x4209dab9), SkBits2Float(0xc250cd81), SkBits2Float(0x418d749b), SkBits2Float(0xc2700000), SkBits2Float(0xb560056c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a39f93), SkBits2Float(0x415fea20));
+path.cubicTo(SkBits2Float(0x42a1ffad), SkBits2Float(0x4195f252), SkBits2Float(0x429f8ce1), SkBits2Float(0x41bb4c45), SkBits2Float(0x429c4e4c), SkBits2Float(0x41df969a));
+path.lineTo(SkBits2Float(0x4261fbff), SkBits2Float(0x41a1a14e));
+path.cubicTo(SkBits2Float(0x4266acd9), SkBits2Float(0x41876566), SkBits2Float(0x426a370e), SkBits2Float(0x4158ca4c), SkBits2Float(0x426c905b), SkBits2Float(0x4121ddaf));
+path.lineTo(SkBits2Float(0x42a39f93), SkBits2Float(0x415fea20));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp157(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41c3ae1a), SkBits2Float(0xc2a60000), SkBits2Float(0x423eb2d3), SkBits2Float(0xc2906c00), SkBits2Float(0x427dc7c2), SkBits2Float(0xc2560e13));
+path.cubicTo(SkBits2Float(0x429e6e58), SkBits2Float(0xc20b4426), SkBits2Float(0x42abdf2b), SkBits2Float(0xc121d7a8), SkBits2Float(0x42a39f93), SkBits2Float(0x415fea20));
+path.lineTo(SkBits2Float(0x42a39f93), SkBits2Float(0x415fea21));
+path.cubicTo(SkBits2Float(0x42a1ffad), SkBits2Float(0x4195f252), SkBits2Float(0x429f8ce1), SkBits2Float(0x41bb4c45), SkBits2Float(0x429c4e4c), SkBits2Float(0x41df969a));
+path.lineTo(SkBits2Float(0x4261fbff), SkBits2Float(0x41a1a14e));
+path.cubicTo(SkBits2Float(0x4266acd9), SkBits2Float(0x41876566), SkBits2Float(0x426a370e), SkBits2Float(0x4158ca4c), SkBits2Float(0x426c905b), SkBits2Float(0x4121ddaf));
+path.lineTo(SkBits2Float(0x426c905a), SkBits2Float(0x4121ddae));
+path.cubicTo(SkBits2Float(0x42787d42), SkBits2Float(0xc0e9fd34), SkBits2Float(0x42650e94), SkBits2Float(0xc1c95949), SkBits2Float(0x423774a6), SkBits2Float(0xc21abd13));
+path.cubicTo(SkBits2Float(0x4209dab9), SkBits2Float(0xc250cd81), SkBits2Float(0x418d749b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429c4e4c), SkBits2Float(0x41df969b));
+path.cubicTo(SkBits2Float(0x4280e391), SkBits2Float(0x4284903f), SkBits2Float(0x41c7a851), SkBits2Float(0x42b2072e), SkBits2Float(0xc1713833), SkBits2Float(0x42a33d14));
+path.cubicTo(SkBits2Float(0xc25c7040), SkBits2Float(0x429472fb), SkBits2Float(0xc2a7bda2), SkBits2Float(0x421b8b2e), SkBits2Float(0xc2a5f5d6), SkBits2Float(0xbfe85110));
+path.lineTo(SkBits2Float(0xc26ff14f), SkBits2Float(0xbfa7f00b));
+path.cubicTo(SkBits2Float(0xc272844c), SkBits2Float(0x41e0e1f3), SkBits2Float(0xc21f5a65), SkBits2Float(0x4256a019), SkBits2Float(0xc12e6015), SkBits2Float(0x426c01f9));
+path.cubicTo(SkBits2Float(0x419054b7), SkBits2Float(0x4280b1ec), SkBits2Float(0x423a5877), SkBits2Float(0x423fa872), SkBits2Float(0x4261fc02), SkBits2Float(0x41a1a142));
+path.lineTo(SkBits2Float(0x429c4e4c), SkBits2Float(0x41df969b));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp158(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41cb677f), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4245cb36), SkBits2Float(0xc28eb15b), SkBits2Float(0x42825fc2), SkBits2Float(0xc24d8299));
+path.cubicTo(SkBits2Float(0x42a1d9e8), SkBits2Float(0xc1fb44f8), SkBits2Float(0x42ad4967), SkBits2Float(0xc0aa7cf8), SkBits2Float(0x42a1679f), SkBits2Float(0x419b26cf));
+path.lineTo(SkBits2Float(0x42695b36), SkBits2Float(0x416050ca));
+path.cubicTo(SkBits2Float(0x427a88f8), SkBits2Float(0xc0767d2a), SkBits2Float(0x426a0074), SkBits2Float(0xc1b5a3f9), SkBits2Float(0x423c7e1d), SkBits2Float(0xc2148fc2));
+path.cubicTo(SkBits2Float(0x420efbc6), SkBits2Float(0xc24e4d87), SkBits2Float(0x41930a0e), SkBits2Float(0xc2700000), SkBits2Float(0xb560056c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a1679f), SkBits2Float(0x419b26d0));
+path.cubicTo(SkBits2Float(0x429f113c), SkBits2Float(0x41c20ede), SkBits2Float(0x429bdafe), SkBits2Float(0x41e80a2e), SkBits2Float(0x4297ceee), SkBits2Float(0x42065107));
+path.lineTo(SkBits2Float(0x425b7b5f), SkBits2Float(0x41c2314a));
+path.cubicTo(SkBits2Float(0x4261554b), SkBits2Float(0x41a7bd56), SkBits2Float(0x4265fa14), SkBits2Float(0x418c4870), SkBits2Float(0x42695b37), SkBits2Float(0x416050cb));
+path.lineTo(SkBits2Float(0x42a1679f), SkBits2Float(0x419b26d0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp159(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41cb677f), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4245cb36), SkBits2Float(0xc28eb15b), SkBits2Float(0x42825fc2), SkBits2Float(0xc24d8299));
+path.cubicTo(SkBits2Float(0x42a1d9e8), SkBits2Float(0xc1fb44f8), SkBits2Float(0x42ad4967), SkBits2Float(0xc0aa7cf8), SkBits2Float(0x42a1679f), SkBits2Float(0x419b26d0));
+path.cubicTo(SkBits2Float(0x429f113c), SkBits2Float(0x41c20ede), SkBits2Float(0x429bdafe), SkBits2Float(0x41e80a2e), SkBits2Float(0x4297ceee), SkBits2Float(0x42065107));
+path.lineTo(SkBits2Float(0x425b7b5f), SkBits2Float(0x41c2314a));
+path.cubicTo(SkBits2Float(0x4261554b), SkBits2Float(0x41a7bd56), SkBits2Float(0x4265fa14), SkBits2Float(0x418c4870), SkBits2Float(0x42695b36), SkBits2Float(0x416050ca));
+path.cubicTo(SkBits2Float(0x427a88f8), SkBits2Float(0xc0767d2a), SkBits2Float(0x426a0074), SkBits2Float(0xc1b5a3f9), SkBits2Float(0x423c7e1d), SkBits2Float(0xc2148fc2));
+path.cubicTo(SkBits2Float(0x420efbc6), SkBits2Float(0xc24e4d87), SkBits2Float(0x41930a0e), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4297ceef), SkBits2Float(0x42065107));
+path.cubicTo(SkBits2Float(0x426afc81), SkBits2Float(0x4290b9e3), SkBits2Float(0x4171c53f), SkBits2Float(0x42b7f2c1), SkBits2Float(0xc1ca446b), SkBits2Float(0x429e1c54));
+path.cubicTo(SkBits2Float(0xc2835add), SkBits2Float(0x428445e8), SkBits2Float(0xc2b3ab9e), SkBits2Float(0x41c6c009), SkBits2Float(0xc2a29b10), SkBits2Float(0xc18596e4));
+path.lineTo(SkBits2Float(0xc26b17b4), SkBits2Float(0xc141242b));
+path.cubicTo(SkBits2Float(0xc281e1de), SkBits2Float(0x418faccb), SkBits2Float(0xc23de932), SkBits2Float(0x423f3d09), SkBits2Float(0xc19237aa), SkBits2Float(0x42649810));
+path.cubicTo(SkBits2Float(0x412ec628), SkBits2Float(0x4284f98c), SkBits2Float(0x4229deab), SkBits2Float(0x42513e23), SkBits2Float(0x425b7b62), SkBits2Float(0x41c23147));
+path.lineTo(SkBits2Float(0x4297ceef), SkBits2Float(0x42065107));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp160(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41d3ccce), SkBits2Float(0xc2a5ffff), SkBits2Float(0x424d7252), SkBits2Float(0xc28cbd55), SkBits2Float(0x4285fbcc), SkBits2Float(0xc244010c));
+path.cubicTo(SkBits2Float(0x42a53e6e), SkBits2Float(0xc1dd0edd), SkBits2Float(0x42ae3d82), SkBits2Float(0xbdb630d0), SkBits2Float(0x429e3366), SkBits2Float(0x41c92323));
+path.lineTo(SkBits2Float(0x4264b95a), SkBits2Float(0x41916681));
+path.cubicTo(SkBits2Float(0x427be9e4), SkBits2Float(0xbd83b620), SkBits2Float(0x426ee823), SkBits2Float(0xc19fcd11), SkBits2Float(0x4241b610), SkBits2Float(0xc20db091));
+path.cubicTo(SkBits2Float(0x421483fd), SkBits2Float(0xc24b7a9a), SkBits2Float(0x41991bc1), SkBits2Float(0xc26fffff), SkBits2Float(0xb630015b), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429e3367), SkBits2Float(0x41c92322));
+path.cubicTo(SkBits2Float(0x429b0cbc), SkBits2Float(0x41f0ca9b), SkBits2Float(0x4296f94f), SkBits2Float(0x420b9629), SkBits2Float(0x429206e2), SkBits2Float(0x421de34f));
+path.lineTo(SkBits2Float(0x42531f8a), SkBits2Float(0x41e4458f));
+path.cubicTo(SkBits2Float(0x425a4685), SkBits2Float(0x41c9cfd9), SkBits2Float(0x42602b18), SkBits2Float(0x41ae10ed), SkBits2Float(0x4264b95a), SkBits2Float(0x41916682));
+path.lineTo(SkBits2Float(0x429e3367), SkBits2Float(0x41c92322));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp161(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb630015b), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41d3ccce), SkBits2Float(0xc2a5ffff), SkBits2Float(0x424d7252), SkBits2Float(0xc28cbd55), SkBits2Float(0x4285fbcc), SkBits2Float(0xc244010c));
+path.cubicTo(SkBits2Float(0x42a53e6e), SkBits2Float(0xc1dd0edd), SkBits2Float(0x42ae3d82), SkBits2Float(0xbdb630d0), SkBits2Float(0x429e3367), SkBits2Float(0x41c92322));
+path.cubicTo(SkBits2Float(0x429b0cbc), SkBits2Float(0x41f0ca9b), SkBits2Float(0x4296f94f), SkBits2Float(0x420b9629), SkBits2Float(0x429206e2), SkBits2Float(0x421de34f));
+path.lineTo(SkBits2Float(0x42531f8a), SkBits2Float(0x41e4458f));
+path.cubicTo(SkBits2Float(0x425a4685), SkBits2Float(0x41c9cfd9), SkBits2Float(0x42602b18), SkBits2Float(0x41ae10ed), SkBits2Float(0x4264b95a), SkBits2Float(0x41916681));
+path.cubicTo(SkBits2Float(0x427be9e4), SkBits2Float(0xbd83b620), SkBits2Float(0x426ee823), SkBits2Float(0xc19fcd11), SkBits2Float(0x4241b610), SkBits2Float(0xc20db091));
+path.cubicTo(SkBits2Float(0x421483fd), SkBits2Float(0xc24b7a9a), SkBits2Float(0x41991bc1), SkBits2Float(0xc26fffff), SkBits2Float(0xb630015b), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429206e2), SkBits2Float(0x421de34f));
+path.cubicTo(SkBits2Float(0x424fd7be), SkBits2Float(0x429cd433), SkBits2Float(0x40819da9), SkBits2Float(0x42bbf605), SkBits2Float(0xc20f7b98), SkBits2Float(0x4295b271));
+path.cubicTo(SkBits2Float(0xc2979573), SkBits2Float(0x425eddba), SkBits2Float(0xc2bb57fe), SkBits2Float(0x4109ef62), SkBits2Float(0xc2990315), SkBits2Float(0xc200bcbb));
+path.lineTo(SkBits2Float(0xc25d38e3), SkBits2Float(0xc1ba2048));
+path.cubicTo(SkBits2Float(0xc2876de1), SkBits2Float(0x40c76c9c), SkBits2Float(0xc25b2842), SkBits2Float(0x42211baa), SkBits2Float(0xc1cf71e5), SkBits2Float(0x42586df1));
+path.cubicTo(SkBits2Float(0x403b65b7), SkBits2Float(0x4287e01c), SkBits2Float(0x42163f6f), SkBits2Float(0x4262bd95), SkBits2Float(0x42531f8c), SkBits2Float(0x41e4458b));
+path.lineTo(SkBits2Float(0x429206e2), SkBits2Float(0x421de34f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp162(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41da3d7f), SkBits2Float(0xc2a60000), SkBits2Float(0x425345ee), SkBits2Float(0xc28b3082), SkBits2Float(0x4288a01b), SkBits2Float(0xc23c9177));
+path.cubicTo(SkBits2Float(0x42a79d3f), SkBits2Float(0xc1c583d9), SkBits2Float(0x42ae8eeb), SkBits2Float(0x407c6461), SkBits2Float(0x429b333a), SkBits2Float(0x41eb9731));
+path.lineTo(SkBits2Float(0x426062bb), SkBits2Float(0x41aa4e75));
+path.cubicTo(SkBits2Float(0x427c5f9a), SkBits2Float(0x403673d5), SkBits2Float(0x4272557b), SkBits2Float(0xc18ec82c), SkBits2Float(0x424587e0), SkBits2Float(0xc208507b));
+path.cubicTo(SkBits2Float(0x4218ba46), SkBits2Float(0xc2493ce1), SkBits2Float(0x419dc399), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429b3339), SkBits2Float(0x41eb9733));
+path.cubicTo(SkBits2Float(0x429766b3), SkBits2Float(0x4209d0f3), SkBits2Float(0x4292a485), SkBits2Float(0x421d0e17), SkBits2Float(0x428cfdb5), SkBits2Float(0x422f3e33));
+path.lineTo(SkBits2Float(0x424bd7ac), SkBits2Float(0x41fd5d06));
+path.cubicTo(SkBits2Float(0x42540374), SkBits2Float(0x41e3114e), SkBits2Float(0x425ae4ae), SkBits2Float(0x41c7409b), SkBits2Float(0x426062bc), SkBits2Float(0x41aa4e76));
+path.lineTo(SkBits2Float(0x429b3339), SkBits2Float(0x41eb9733));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp163(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41da3d7f), SkBits2Float(0xc2a60000), SkBits2Float(0x425345ee), SkBits2Float(0xc28b3082), SkBits2Float(0x4288a01b), SkBits2Float(0xc23c9177));
+path.cubicTo(SkBits2Float(0x42a79d3f), SkBits2Float(0xc1c583d9), SkBits2Float(0x42ae8eeb), SkBits2Float(0x407c6461), SkBits2Float(0x429b3339), SkBits2Float(0x41eb9733));
+path.cubicTo(SkBits2Float(0x429766b3), SkBits2Float(0x4209d0f3), SkBits2Float(0x4292a485), SkBits2Float(0x421d0e17), SkBits2Float(0x428cfdb5), SkBits2Float(0x422f3e33));
+path.lineTo(SkBits2Float(0x424bd7ac), SkBits2Float(0x41fd5d06));
+path.cubicTo(SkBits2Float(0x42540374), SkBits2Float(0x41e3114e), SkBits2Float(0x425ae4ae), SkBits2Float(0x41c7409b), SkBits2Float(0x426062bb), SkBits2Float(0x41aa4e75));
+path.cubicTo(SkBits2Float(0x427c5f9a), SkBits2Float(0x403673d5), SkBits2Float(0x4272557b), SkBits2Float(0xc18ec82c), SkBits2Float(0x424587e0), SkBits2Float(0xc208507b));
+path.cubicTo(SkBits2Float(0x4218ba46), SkBits2Float(0xc2493ce1), SkBits2Float(0x419dc399), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x428cfdb5), SkBits2Float(0x422f3e36));
+path.cubicTo(SkBits2Float(0x42397b9c), SkBits2Float(0x42a54202), SkBits2Float(0xc0931849), SkBits2Float(0x42bd474f), SkBits2Float(0xc22e0fe8), SkBits2Float(0x428d5ab7));
+path.cubicTo(SkBits2Float(0xc2a4de63), SkBits2Float(0x423adc3f), SkBits2Float(0xc2bd50df), SkBits2Float(0xc08673c0), SkBits2Float(0xc28db7cd), SkBits2Float(0xc22ce1b4));
+path.lineTo(SkBits2Float(0xc24ce4bb), SkBits2Float(0xc1f9f306));
+path.cubicTo(SkBits2Float(0xc288db72), SkBits2Float(0xc0426216), SkBits2Float(0xc26e5ec8), SkBits2Float(0x42071590), SkBits2Float(0xc1fba9c9), SkBits2Float(0x424c5fa5));
+path.cubicTo(SkBits2Float(0xc054b001), SkBits2Float(0x4288d4dc), SkBits2Float(0x420615fc), SkBits2Float(0x426eee67), SkBits2Float(0x424bd7af), SkBits2Float(0x41fd5d01));
+path.lineTo(SkBits2Float(0x428cfdb5), SkBits2Float(0x422f3e36));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp164(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41e183ec), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4259cec4), SkBits2Float(0xc2896274), SkBits2Float(0x428b79bc), SkBits2Float(0xc2340753));
+path.cubicTo(SkBits2Float(0x42aa0c16), SkBits2Float(0xc1aa937d), SkBits2Float(0x42ae7c71), SkBits2Float(0x41080a55), SkBits2Float(0x42974339), SkBits2Float(0x4208c1d5));
+path.lineTo(SkBits2Float(0x425ab161), SkBits2Float(0x41c5b8a2));
+path.cubicTo(SkBits2Float(0x427c44e4), SkBits2Float(0x40c4af5a), SkBits2Float(0x4275d9f7), SkBits2Float(0xc1769dba), SkBits2Float(0x4249a6c2), SkBits2Float(0xc2022424));
+path.cubicTo(SkBits2Float(0x421d738b), SkBits2Float(0xc246a0db), SkBits2Float(0x41a305f1), SkBits2Float(0xc2700000), SkBits2Float(0x3725ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42974339), SkBits2Float(0x4208c1d6));
+path.cubicTo(SkBits2Float(0x4292b5f8), SkBits2Float(0x421ce537), SkBits2Float(0x428d2a3f), SkBits2Float(0x42301305), SkBits2Float(0x4286b52e), SkBits2Float(0x4242022c));
+path.lineTo(SkBits2Float(0x4242c218), SkBits2Float(0x420c3f43));
+path.cubicTo(SkBits2Float(0x424c1813), SkBits2Float(0x41fe90b7), SkBits2Float(0x42541cae), SkBits2Float(0x41e2d634), SkBits2Float(0x425ab162), SkBits2Float(0x41c5b8a3));
+path.lineTo(SkBits2Float(0x42974339), SkBits2Float(0x4208c1d6));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp165(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3725ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41e183ec), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4259cec4), SkBits2Float(0xc2896274), SkBits2Float(0x428b79bc), SkBits2Float(0xc2340753));
+path.cubicTo(SkBits2Float(0x42aa0c16), SkBits2Float(0xc1aa937d), SkBits2Float(0x42ae7c71), SkBits2Float(0x41080a55), SkBits2Float(0x42974339), SkBits2Float(0x4208c1d6));
+path.cubicTo(SkBits2Float(0x4292b5f8), SkBits2Float(0x421ce537), SkBits2Float(0x428d2a3f), SkBits2Float(0x42301305), SkBits2Float(0x4286b52e), SkBits2Float(0x4242022c));
+path.lineTo(SkBits2Float(0x4242c218), SkBits2Float(0x420c3f43));
+path.cubicTo(SkBits2Float(0x424c1813), SkBits2Float(0x41fe90b7), SkBits2Float(0x42541cae), SkBits2Float(0x41e2d634), SkBits2Float(0x425ab161), SkBits2Float(0x41c5b8a2));
+path.cubicTo(SkBits2Float(0x427c44e4), SkBits2Float(0x40c4af5a), SkBits2Float(0x4275d9f7), SkBits2Float(0xc1769dba), SkBits2Float(0x4249a6c2), SkBits2Float(0xc2022424));
+path.cubicTo(SkBits2Float(0x421d738b), SkBits2Float(0xc246a0db), SkBits2Float(0x41a305f1), SkBits2Float(0xc2700000), SkBits2Float(0x3725ffa9), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4286b52e), SkBits2Float(0x4242022d));
+path.cubicTo(SkBits2Float(0x4245f9c6), SkBits2Float(0x42929b97), SkBits2Float(0x419b96e9), SkBits2Float(0x42ac9135), SkBits2Float(0xc12da222), SkBits2Float(0x42a4933a));
+path.cubicTo(SkBits2Float(0xc2249c85), SkBits2Float(0x429c9540), SkBits2Float(0xc2859c99), SkBits2Float(0x4267dd85), SkBits2Float(0xc29b4028), SkBits2Float(0x41eb0f05));
+path.cubicTo(SkBits2Float(0xc2b0e3b8), SkBits2Float(0x3f4c608a), SkBits2Float(0xc2a55c16), SkBits2Float(0xc1fb5a07), SkBits2Float(0xc27a7a78), SkBits2Float(0xc259e8d8));
+path.lineTo(SkBits2Float(0xc2351199), SkBits2Float(0xc21d8664));
+path.cubicTo(SkBits2Float(0xc26f12eb), SkBits2Float(0xc1b5b32d), SkBits2Float(0xc27fbe43), SkBits2Float(0x3f13bb74), SkBits2Float(0xc2607541), SkBits2Float(0x41a9ebcd));
+path.cubicTo(SkBits2Float(0xc2412c3e), SkBits2Float(0x42279ce1), SkBits2Float(0xc1edfdc7), SkBits2Float(0x4262625e), SkBits2Float(0xc0fb089d), SkBits2Float(0x426df06d));
+path.cubicTo(SkBits2Float(0x4160f2f1), SkBits2Float(0x42797e7c), SkBits2Float(0x420f1d6a), SkBits2Float(0x4253f671), SkBits2Float(0x4242c21c), SkBits2Float(0x420c3f41));
+path.lineTo(SkBits2Float(0x4286b52e), SkBits2Float(0x4242022d));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp166(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41e5cd16), SkBits2Float(0xc2a60000), SkBits2Float(0x425da203), SkBits2Float(0xc2884b73), SkBits2Float(0x428d165b), SkBits2Float(0xc22eeec9));
+path.cubicTo(SkBits2Float(0x42ab5bb4), SkBits2Float(0xc19a8d5b), SkBits2Float(0x42ae3add), SkBits2Float(0x4132f7c2), SkBits2Float(0x4294adf4), SkBits2Float(0x4213a75b));
+path.lineTo(SkBits2Float(0x4256f554), SkBits2Float(0x41d579ab));
+path.cubicTo(SkBits2Float(0x427be612), SkBits2Float(0x41015fcf), SkBits2Float(0x4277bf2e), SkBits2Float(0xc15f72f6), SkBits2Float(0x424bfb4d), SkBits2Float(0xc1fcea38));
+path.cubicTo(SkBits2Float(0x4220376c), SkBits2Float(0xc2450d7a), SkBits2Float(0x41a61f08), SkBits2Float(0xc2700000), SkBits2Float(0xb7060057), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4294adf4), SkBits2Float(0x4213a75b));
+path.cubicTo(SkBits2Float(0x428facea), SkBits2Float(0x4227cf1b), SkBits2Float(0x4289a8e5), SkBits2Float(0x423ae500), SkBits2Float(0x4282b9a7), SkBits2Float(0x424c9dab));
+path.lineTo(SkBits2Float(0x423d0015), SkBits2Float(0x4213ea45));
+path.cubicTo(SkBits2Float(0x424706b3), SkBits2Float(0x42071ac0), SkBits2Float(0x424fb93a), SkBits2Float(0x41f29d8f), SkBits2Float(0x4256f555), SkBits2Float(0x41d579ac));
+path.lineTo(SkBits2Float(0x4294adf4), SkBits2Float(0x4213a75b));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp167(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb7060057), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41e5cd16), SkBits2Float(0xc2a60000), SkBits2Float(0x425da203), SkBits2Float(0xc2884b73), SkBits2Float(0x428d165b), SkBits2Float(0xc22eeec9));
+path.cubicTo(SkBits2Float(0x42ab5bb4), SkBits2Float(0xc19a8d5b), SkBits2Float(0x42ae3add), SkBits2Float(0x4132f7c2), SkBits2Float(0x4294adf4), SkBits2Float(0x4213a75b));
+path.cubicTo(SkBits2Float(0x428facea), SkBits2Float(0x4227cf1b), SkBits2Float(0x4289a8e5), SkBits2Float(0x423ae500), SkBits2Float(0x4282b9a7), SkBits2Float(0x424c9dab));
+path.lineTo(SkBits2Float(0x423d0015), SkBits2Float(0x4213ea45));
+path.cubicTo(SkBits2Float(0x424706b3), SkBits2Float(0x42071ac0), SkBits2Float(0x424fb93a), SkBits2Float(0x41f29d8f), SkBits2Float(0x4256f554), SkBits2Float(0x41d579ab));
+path.cubicTo(SkBits2Float(0x427be612), SkBits2Float(0x41015fcf), SkBits2Float(0x4277bf2e), SkBits2Float(0xc15f72f6), SkBits2Float(0x424bfb4d), SkBits2Float(0xc1fcea38));
+path.cubicTo(SkBits2Float(0x4220376c), SkBits2Float(0xc2450d7a), SkBits2Float(0x41a61f08), SkBits2Float(0xc2700000), SkBits2Float(0xb7060057), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4282b9a8), SkBits2Float(0x424c9dac));
+path.cubicTo(SkBits2Float(0x4238a98e), SkBits2Float(0x42975dcd), SkBits2Float(0x416d9db4), SkBits2Float(0x42aecc7f), SkBits2Float(0xc17bb856), SkBits2Float(0x42a2fd9a));
+path.cubicTo(SkBits2Float(0xc2394396), SkBits2Float(0x42972eb6), SkBits2Float(0xc28e09e8), SkBits2Float(0x42543e5a), SkBits2Float(0xc29f69c3), SkBits2Float(0x41b9307a));
+path.cubicTo(SkBits2Float(0xc2b0c99f), SkBits2Float(0xc0d86efe), SkBits2Float(0xc29f345f), SkBits2Float(0xc21c161b), SkBits2Float(0xc263c1d4), SkBits2Float(0xc2718f13));
+path.lineTo(SkBits2Float(0xc224a4cd), SkBits2Float(0xc22e9eef));
+path.cubicTo(SkBits2Float(0xc2662cd7), SkBits2Float(0xc1e1aab7), SkBits2Float(0xc27f98a3), SkBits2Float(0xc09c754c), SkBits2Float(0xc26679fe), SkBits2Float(0x4185df20));
+path.cubicTo(SkBits2Float(0xc24d5b58), SkBits2Float(0x42196dcb), SkBits2Float(0xc205ecef), SkBits2Float(0x425a93a6), SkBits2Float(0xc135f72f), SkBits2Float(0x426ba619));
+path.cubicTo(SkBits2Float(0x412bc560), SkBits2Float(0x427cb88a), SkBits2Float(0x42057da8), SkBits2Float(0x425ad7c5), SkBits2Float(0x423d0018), SkBits2Float(0x4213ea45));
+path.lineTo(SkBits2Float(0x4282b9a8), SkBits2Float(0x424c9dac));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp168(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41ea54b9), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4261a7de), SkBits2Float(0xc2871f16), SkBits2Float(0x428ebc81), SkBits2Float(0xc2297f4d));
+path.cubicTo(SkBits2Float(0x42aca513), SkBits2Float(0xc18980da), SkBits2Float(0x42adc9a4), SkBits2Float(0x41604127), SkBits2Float(0x4291be57), SkBits2Float(0x421eee87));
+path.lineTo(SkBits2Float(0x4252b6a9), SkBits2Float(0x41e5c7e9));
+path.cubicTo(SkBits2Float(0x427b4260), SkBits2Float(0x41221c9f), SkBits2Float(0x42799b62), SkBits2Float(0xc146ccc2), SkBits2Float(0x424e5da6), SkBits2Float(0xc1f50e65));
+path.cubicTo(SkBits2Float(0x42231fea), SkBits2Float(0xc2435b34), SkBits2Float(0x41a9655c), SkBits2Float(0xc26ffffe), SkBits2Float(0x3725ffa9), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4291be57), SkBits2Float(0x421eee8a));
+path.cubicTo(SkBits2Float(0x428c4169), SkBits2Float(0x42330feb), SkBits2Float(0x4285bd57), SkBits2Float(0x4246005c), SkBits2Float(0x427c99ac), SkBits2Float(0x4257723d));
+path.lineTo(SkBits2Float(0x42369a46), SkBits2Float(0x421bbe89));
+path.cubicTo(SkBits2Float(0x42415bc7), SkBits2Float(0x420f2230), SkBits2Float(0x424ac771), SkBits2Float(0x4201714b), SkBits2Float(0x4252b6a9), SkBits2Float(0x41e5c7e9));
+path.lineTo(SkBits2Float(0x4291be57), SkBits2Float(0x421eee8a));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp169(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3725ffa9), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41ea54b9), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4261a7de), SkBits2Float(0xc2871f16), SkBits2Float(0x428ebc81), SkBits2Float(0xc2297f4d));
+path.cubicTo(SkBits2Float(0x42aca513), SkBits2Float(0xc18980da), SkBits2Float(0x42adc9a4), SkBits2Float(0x41604127), SkBits2Float(0x4291be57), SkBits2Float(0x421eee8a));
+path.cubicTo(SkBits2Float(0x428c4169), SkBits2Float(0x42330feb), SkBits2Float(0x4285bd57), SkBits2Float(0x4246005c), SkBits2Float(0x427c99ac), SkBits2Float(0x4257723d));
+path.lineTo(SkBits2Float(0x42369a46), SkBits2Float(0x421bbe89));
+path.cubicTo(SkBits2Float(0x42415bc7), SkBits2Float(0x420f2230), SkBits2Float(0x424ac771), SkBits2Float(0x4201714b), SkBits2Float(0x4252b6a9), SkBits2Float(0x41e5c7e9));
+path.cubicTo(SkBits2Float(0x427b4260), SkBits2Float(0x41221c9f), SkBits2Float(0x42799b62), SkBits2Float(0xc146ccc2), SkBits2Float(0x424e5da6), SkBits2Float(0xc1f50e65));
+path.cubicTo(SkBits2Float(0x42231fea), SkBits2Float(0xc2435b34), SkBits2Float(0x41a9655c), SkBits2Float(0xc26ffffe), SkBits2Float(0x3725ffa9), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x427c99ad), SkBits2Float(0x4257723e));
+path.cubicTo(SkBits2Float(0x422a2459), SkBits2Float(0x429c0ff6), SkBits2Float(0x411ef0c1), SkBits2Float(0x42b0a109), SkBits2Float(0xc1a68a7f), SkBits2Float(0x42a0b1a2));
+path.cubicTo(SkBits2Float(0xc24e46af), SkBits2Float(0x4290c23b), SkBits2Float(0xc296269a), SkBits2Float(0x423e3c04), SkBits2Float(0xc2a2b82b), SkBits2Float(0x41835b51));
+path.cubicTo(SkBits2Float(0xc2af49bc), SkBits2Float(0xc16b82d9), SkBits2Float(0xc2973524), SkBits2Float(0xc23adb29), SkBits2Float(0xc24965c6), SkBits2Float(0xc283f801));
+path.lineTo(SkBits2Float(0xc21196ae), SkBits2Float(0xc23ecc58));
+path.cubicTo(SkBits2Float(0xc25a9cfe), SkBits2Float(0xc20713a1), SkBits2Float(0xc27d6da1), SkBits2Float(0xc12a3fcc), SkBits2Float(0xc26b41bb), SkBits2Float(0x413de9a9));
+path.cubicTo(SkBits2Float(0xc25915d3), SkBits2Float(0x420984c8), SkBits2Float(0xc2151d75), SkBits2Float(0x42514a1b), SkBits2Float(0xc170c819), SkBits2Float(0x4268540a));
+path.cubicTo(SkBits2Float(0x40e5cb46), SkBits2Float(0x427f5dfa), SkBits2Float(0x41f5fd0c), SkBits2Float(0x4261a1d8), SkBits2Float(0x42369a4a), SkBits2Float(0x421bbe87));
+path.lineTo(SkBits2Float(0x427c99ad), SkBits2Float(0x4257723e));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp170(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41ef3488), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4265f5fc), SkBits2Float(0xc285d5a4), SkBits2Float(0x429072a6), SkBits2Float(0xc2239841));
+path.cubicTo(SkBits2Float(0x42adea4e), SkBits2Float(0xc16e14e5), SkBits2Float(0x42ad1da2), SkBits2Float(0x41886b20), SkBits2Float(0x428e5adb), SkBits2Float(0x422ac68e));
+path.lineTo(SkBits2Float(0x424dd078), SkBits2Float(0x41f6e790));
+path.cubicTo(SkBits2Float(0x427a49b4), SkBits2Float(0x41453b4b), SkBits2Float(0x427b719d), SkBits2Float(0xc12c1b6e), SkBits2Float(0x4250d71f), SkBits2Float(0xc1ec85c5));
+path.cubicTo(SkBits2Float(0x42263ca0), SkBits2Float(0xc2417eea), SkBits2Float(0x41aceb63), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x428e5adb), SkBits2Float(0x422ac690));
+path.cubicTo(SkBits2Float(0x42885732), SkBits2Float(0x423ed443), SkBits2Float(0x428148a8), SkBits2Float(0x42518e43), SkBits2Float(0x42729aa0), SkBits2Float(0x4262a4bd));
+path.lineTo(SkBits2Float(0x422f605c), SkBits2Float(0x4223d6b5));
+path.cubicTo(SkBits2Float(0x423aea98), SkBits2Float(0x42177c70), SkBits2Float(0x42451e76), SkBits2Float(0x4209f2e4), SkBits2Float(0x424dd078), SkBits2Float(0x41f6e792));
+path.lineTo(SkBits2Float(0x428e5adb), SkBits2Float(0x422ac690));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp171(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41ef3488), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4265f5fc), SkBits2Float(0xc285d5a4), SkBits2Float(0x429072a6), SkBits2Float(0xc2239841));
+path.cubicTo(SkBits2Float(0x42adea4e), SkBits2Float(0xc16e14e5), SkBits2Float(0x42ad1da2), SkBits2Float(0x41886b20), SkBits2Float(0x428e5adb), SkBits2Float(0x422ac690));
+path.cubicTo(SkBits2Float(0x42885732), SkBits2Float(0x423ed443), SkBits2Float(0x428148a8), SkBits2Float(0x42518e43), SkBits2Float(0x42729aa0), SkBits2Float(0x4262a4bd));
+path.lineTo(SkBits2Float(0x422f605c), SkBits2Float(0x4223d6b5));
+path.cubicTo(SkBits2Float(0x423aea98), SkBits2Float(0x42177c70), SkBits2Float(0x42451e76), SkBits2Float(0x4209f2e4), SkBits2Float(0x424dd078), SkBits2Float(0x41f6e790));
+path.cubicTo(SkBits2Float(0x427a49b4), SkBits2Float(0x41453b4b), SkBits2Float(0x427b719d), SkBits2Float(0xc12c1b6e), SkBits2Float(0x4250d71f), SkBits2Float(0xc1ec85c5));
+path.cubicTo(SkBits2Float(0x42263ca0), SkBits2Float(0xc2417eea), SkBits2Float(0x41aceb63), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42729aa1), SkBits2Float(0x4262a4be));
+path.cubicTo(SkBits2Float(0x421a0aa1), SkBits2Float(0x42a0b8ab), SkBits2Float(0x4092ff14), SkBits2Float(0x42b1fc82), SkBits2Float(0xc1d17709), SkBits2Float(0x429d861f));
+path.cubicTo(SkBits2Float(0xc263d6eb), SkBits2Float(0x42890fbc), SkBits2Float(0xc29dea71), SkBits2Float(0x42253dbf), SkBits2Float(0xc2a5016a), SkBits2Float(0x4111261a));
+path.cubicTo(SkBits2Float(0xc2ac1862), SkBits2Float(0xc1b95567), SkBits2Float(0xc28cface), SkBits2Float(0xc25a1117), SkBits2Float(0xc22aafa6), SkBits2Float(0xc28e61ba));
+path.lineTo(SkBits2Float(0xc1f6c679), SkBits2Float(0xc24dda63));
+path.cubicTo(SkBits2Float(0xc24bd376), SkBits2Float(0xc21da377), SkBits2Float(0xc278cff1), SkBits2Float(0xc185f9db), SkBits2Float(0xc26e8fe1), SkBits2Float(0x40d1da84));
+path.cubicTo(SkBits2Float(0xc2644fd1), SkBits2Float(0x41eee71d), SkBits2Float(0xc224b3fc), SkBits2Float(0x4246293b), SkBits2Float(0xc1976b90), SkBits2Float(0x4263becd));
+path.cubicTo(SkBits2Float(0x405486c0), SkBits2Float(0x4280aa2f), SkBits2Float(0x41deb5f2), SkBits2Float(0x42685e3e), SkBits2Float(0x422f605e), SkBits2Float(0x4223d6b6));
+path.lineTo(SkBits2Float(0x42729aa1), SkBits2Float(0x4262a4be));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp172(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f30c96), SkBits2Float(0xc2a60000), SkBits2Float(0x426956a5), SkBits2Float(0xc284cd4a), SkBits2Float(0x4291c05e), SkBits2Float(0xc21ee718));
+path.cubicTo(SkBits2Float(0x42aed56a), SkBits2Float(0xc150ce71), SkBits2Float(0x42ac7181), SkBits2Float(0x419b8107), SkBits2Float(0x428b8516), SkBits2Float(0x4233e422));
+path.lineTo(SkBits2Float(0x4249b729), SkBits2Float(0x42020ab3));
+path.cubicTo(SkBits2Float(0x427950d3), SkBits2Float(0x4160d339), SkBits2Float(0x427cc584), SkBits2Float(0xc116f1c4), SkBits2Float(0x4252b998), SkBits2Float(0xc1e5bd26));
+path.cubicTo(SkBits2Float(0x4228adad), SkBits2Float(0xc24000b5), SkBits2Float(0x41afb2be), SkBits2Float(0xc2700000), SkBits2Float(0xb560056c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x428b8516), SkBits2Float(0x4233e422));
+path.cubicTo(SkBits2Float(0x4285165c), SkBits2Float(0x4247d8d0), SkBits2Float(0x427b34bd), SkBits2Float(0x425a5d74), SkBits2Float(0x426a6401), SkBits2Float(0x426b20b1));
+path.lineTo(SkBits2Float(0x42297063), SkBits2Float(0x4229f8c9));
+path.cubicTo(SkBits2Float(0x42359840), SkBits2Float(0x421ddab1), SkBits2Float(0x42406a5a), SkBits2Float(0x421077b9), SkBits2Float(0x4249b72b), SkBits2Float(0x42020ab4));
+path.lineTo(SkBits2Float(0x428b8516), SkBits2Float(0x4233e422));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp173(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f30c96), SkBits2Float(0xc2a60000), SkBits2Float(0x426956a5), SkBits2Float(0xc284cd4a), SkBits2Float(0x4291c05e), SkBits2Float(0xc21ee718));
+path.cubicTo(SkBits2Float(0x42aed56a), SkBits2Float(0xc150ce71), SkBits2Float(0x42ac7181), SkBits2Float(0x419b8107), SkBits2Float(0x428b8516), SkBits2Float(0x4233e422));
+path.cubicTo(SkBits2Float(0x4285165c), SkBits2Float(0x4247d8d0), SkBits2Float(0x427b34bd), SkBits2Float(0x425a5d74), SkBits2Float(0x426a6401), SkBits2Float(0x426b20b1));
+path.lineTo(SkBits2Float(0x42297063), SkBits2Float(0x4229f8c9));
+path.cubicTo(SkBits2Float(0x42359840), SkBits2Float(0x421ddab1), SkBits2Float(0x42406a5a), SkBits2Float(0x421077b9), SkBits2Float(0x4249b72b), SkBits2Float(0x42020ab4));
+path.lineTo(SkBits2Float(0x4249b729), SkBits2Float(0x42020ab3));
+path.cubicTo(SkBits2Float(0x427950d3), SkBits2Float(0x4160d339), SkBits2Float(0x427cc584), SkBits2Float(0xc116f1c4), SkBits2Float(0x4252b998), SkBits2Float(0xc1e5bd26));
+path.cubicTo(SkBits2Float(0x4228adad), SkBits2Float(0xc24000b5), SkBits2Float(0x41afb2be), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x426a6401), SkBits2Float(0x426b20b0));
+path.cubicTo(SkBits2Float(0x420d0644), SkBits2Float(0x42a419c2), SkBits2Float(0x3eb79d8f), SkBits2Float(0x42b29b69), SkBits2Float(0xc1f292a7), SkBits2Float(0x429a86c6));
+path.cubicTo(SkBits2Float(0xc27401e4), SkBits2Float(0x42827223), SkBits2Float(0xc2a34d81), SkBits2Float(0x4210aea0), SkBits2Float(0xc2a5dfaf), SkBits2Float(0x404f3106));
+path.cubicTo(SkBits2Float(0xc2a871dd), SkBits2Float(0xc1ed90fa), SkBits2Float(0xc283ccf3), SkBits2Float(0xc27113da), SkBits2Float(0xc21101fe), SkBits2Float(0xc2955440));
+path.lineTo(SkBits2Float(0xc1d1a65c), SkBits2Float(0xc257e5c3));
+path.cubicTo(SkBits2Float(0xc23e8e16), SkBits2Float(0xc22e45d9), SkBits2Float(0xc27388d2), SkBits2Float(0xc1abbc0d), SkBits2Float(0xc26fd138), SkBits2Float(0x4015c6fe));
+path.cubicTo(SkBits2Float(0xc26c199f), SkBits2Float(0x41d12dcc), SkBits2Float(0xc2306400), SkBits2Float(0x423c98a5), SkBits2Float(0xc1af5a7e), SkBits2Float(0x425f695f));
+path.cubicTo(SkBits2Float(0x3e84bf70), SkBits2Float(0x42811d0c), SkBits2Float(0x41cbe40c), SkBits2Float(0x426d40fa), SkBits2Float(0x42297064), SkBits2Float(0x4229f8cc));
+path.lineTo(SkBits2Float(0x426a6401), SkBits2Float(0x426b20b0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp174(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f67553), SkBits2Float(0xc2a5ffff), SkBits2Float(0x426c5214), SkBits2Float(0xc283df7d), SkBits2Float(0x4292df93), SkBits2Float(0xc21ab724));
+path.cubicTo(SkBits2Float(0x42af961c), SkBits2Float(0xc136bd38), SkBits2Float(0x42abbe10), SkBits2Float(0x41ac5dd5), SkBits2Float(0x4288e395), SkBits2Float(0x423bcd53));
+path.lineTo(SkBits2Float(0x4245e96c), SkBits2Float(0x4207c2b1));
+path.cubicTo(SkBits2Float(0x42784d66), SkBits2Float(0x41793464), SkBits2Float(0x427ddc1f), SkBits2Float(0xc10419c2), SkBits2Float(0x425458d8), SkBits2Float(0xc1dfaf58));
+path.cubicTo(SkBits2Float(0x422ad590), SkBits2Float(0xc23ea8e8), SkBits2Float(0x41b229a4), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4288e396), SkBits2Float(0x423bcd52));
+path.cubicTo(SkBits2Float(0x42821571), SkBits2Float(0x424fa4b8), SkBits2Float(0x427470be), SkBits2Float(0x4261f24c), SkBits2Float(0x4262dfb6), SkBits2Float(0x4272637b));
+path.lineTo(SkBits2Float(0x42240156), SkBits2Float(0x422f387f));
+path.cubicTo(SkBits2Float(0x4230b436), SkBits2Float(0x422355b8), SkBits2Float(0x423c12ab), SkBits2Float(0x42161a8d), SkBits2Float(0x4245e96e), SkBits2Float(0x4207c2b2));
+path.lineTo(SkBits2Float(0x4288e396), SkBits2Float(0x423bcd52));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp175(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f67553), SkBits2Float(0xc2a5ffff), SkBits2Float(0x426c5214), SkBits2Float(0xc283df7d), SkBits2Float(0x4292df93), SkBits2Float(0xc21ab724));
+path.cubicTo(SkBits2Float(0x42af961c), SkBits2Float(0xc136bd38), SkBits2Float(0x42abbe10), SkBits2Float(0x41ac5dd5), SkBits2Float(0x4288e396), SkBits2Float(0x423bcd52));
+path.cubicTo(SkBits2Float(0x42821571), SkBits2Float(0x424fa4b8), SkBits2Float(0x427470be), SkBits2Float(0x4261f24c), SkBits2Float(0x4262dfb6), SkBits2Float(0x4272637b));
+path.lineTo(SkBits2Float(0x42240156), SkBits2Float(0x422f387f));
+path.cubicTo(SkBits2Float(0x4230b436), SkBits2Float(0x422355b8), SkBits2Float(0x423c12ab), SkBits2Float(0x42161a8d), SkBits2Float(0x4245e96e), SkBits2Float(0x4207c2b2));
+path.lineTo(SkBits2Float(0x4245e96c), SkBits2Float(0x4207c2b1));
+path.cubicTo(SkBits2Float(0x42784d66), SkBits2Float(0x41793464), SkBits2Float(0x427ddc1f), SkBits2Float(0xc10419c2), SkBits2Float(0x425458d8), SkBits2Float(0xc1dfaf58));
+path.cubicTo(SkBits2Float(0x422ad590), SkBits2Float(0xc23ea8e8), SkBits2Float(0x41b229a4), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4262dfb7), SkBits2Float(0x4272637c));
+path.cubicTo(SkBits2Float(0x4201435c), SkBits2Float(0x42a6e035), SkBits2Float(0xc05a052a), SkBits2Float(0x42b2d330), SkBits2Float(0xc207a774), SkBits2Float(0x429782c3));
+path.cubicTo(SkBits2Float(0xc280d74a), SkBits2Float(0x427864aa), SkBits2Float(0xc2a78489), SkBits2Float(0x41fbcc10), SkBits2Float(0xc2a5f467), SkBits2Float(0xbff86670));
+path.cubicTo(SkBits2Float(0xc2a46445), SkBits2Float(0xc20d6c6d), SkBits2Float(0xc275c9b5), SkBits2Float(0xc2821580), SkBits2Float(0xc1f2ade6), SkBits2Float(0xc29a8413));
+path.lineTo(SkBits2Float(0xc1af6e4e), SkBits2Float(0xc25f6582));
+path.cubicTo(SkBits2Float(0xc231ad90), SkBits2Float(0xc23c12bd), SkBits2Float(0xc26dacb3), SkBits2Float(0xc1cc77b7), SkBits2Float(0xc26fef30), SkBits2Float(0xbfb390a5));
+path.cubicTo(SkBits2Float(0xc27231ae), SkBits2Float(0x41b605a0), SkBits2Float(0xc23a46a0), SkBits2Float(0x42338faf), SkBits2Float(0xc1c42047), SkBits2Float(0x425b0d36));
+path.cubicTo(SkBits2Float(0xc01d9a6d), SkBits2Float(0x4281455e), SkBits2Float(0x41bae2f1), SkBits2Float(0x42714420), SkBits2Float(0x42240157), SkBits2Float(0x422f387f));
+path.lineTo(SkBits2Float(0x4262dfb7), SkBits2Float(0x4272637c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp176(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f9cdf3), SkBits2Float(0xc2a5ffff), SkBits2Float(0x426f3c43), SkBits2Float(0xc282f30b), SkBits2Float(0x4293f176), SkBits2Float(0xc2169536));
+path.cubicTo(SkBits2Float(0x42b044ca), SkBits2Float(0xc11d115b), SkBits2Float(0x42aaf59e), SkBits2Float(0x41bcd986), SkBits2Float(0x428633ff), SkBits2Float(0x42436703));
+path.lineTo(SkBits2Float(0x42420751), SkBits2Float(0x420d4138));
+path.cubicTo(SkBits2Float(0x42772b98), SkBits2Float(0x41888496), SkBits2Float(0x427ed8af), SkBits2Float(0xc0e315f7), SkBits2Float(0x4255e4d4), SkBits2Float(0xc1d9b5cc));
+path.cubicTo(SkBits2Float(0x422cf0fb), SkBits2Float(0xc23d530d), SkBits2Float(0x41b494e9), SkBits2Float(0xc2700000), SkBits2Float(0x3743ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x428633ff), SkBits2Float(0x42436705));
+path.cubicTo(SkBits2Float(0x427e0fd0), SkBits2Float(0x42571b29), SkBits2Float(0x426d975d), SkBits2Float(0x42692b9b), SkBits2Float(0x425b4ae0), SkBits2Float(0x427944c1));
+path.lineTo(SkBits2Float(0x421e8652), SkBits2Float(0x423431b3));
+path.cubicTo(SkBits2Float(0x422bc0b3), SkBits2Float(0x42288e8e), SkBits2Float(0x4237a8bb), SkBits2Float(0x421b7f95), SkBits2Float(0x42420752), SkBits2Float(0x420d4138));
+path.lineTo(SkBits2Float(0x428633ff), SkBits2Float(0x42436705));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp177(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3743ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f9cdf3), SkBits2Float(0xc2a5ffff), SkBits2Float(0x426f3c43), SkBits2Float(0xc282f30b), SkBits2Float(0x4293f176), SkBits2Float(0xc2169536));
+path.cubicTo(SkBits2Float(0x42b044ca), SkBits2Float(0xc11d115b), SkBits2Float(0x42aaf59e), SkBits2Float(0x41bcd986), SkBits2Float(0x428633ff), SkBits2Float(0x42436705));
+path.cubicTo(SkBits2Float(0x427e0fd0), SkBits2Float(0x42571b29), SkBits2Float(0x426d975d), SkBits2Float(0x42692b9b), SkBits2Float(0x425b4ae0), SkBits2Float(0x427944c1));
+path.lineTo(SkBits2Float(0x421e8652), SkBits2Float(0x423431b3));
+path.cubicTo(SkBits2Float(0x422bc0b3), SkBits2Float(0x42288e8e), SkBits2Float(0x4237a8bb), SkBits2Float(0x421b7f95), SkBits2Float(0x42420751), SkBits2Float(0x420d4138));
+path.cubicTo(SkBits2Float(0x42772b98), SkBits2Float(0x41888496), SkBits2Float(0x427ed8af), SkBits2Float(0xc0e315f7), SkBits2Float(0x4255e4d4), SkBits2Float(0xc1d9b5cc));
+path.cubicTo(SkBits2Float(0x422cf0fb), SkBits2Float(0xc23d530d), SkBits2Float(0x41b494e9), SkBits2Float(0xc2700000), SkBits2Float(0x3743ffa9), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x425b4ae0), SkBits2Float(0x427944c0));
+path.cubicTo(SkBits2Float(0x41eb12b8), SkBits2Float(0x42a964d5), SkBits2Float(0xc0e3546a), SkBits2Float(0x42b2bc1c), SkBits2Float(0xc2157060), SkBits2Float(0x42943ba4));
+path.cubicTo(SkBits2Float(0xc2873b19), SkBits2Float(0x426b7658), SkBits2Float(0xc2ab209f), SkBits2Float(0x41d60b1d), SkBits2Float(0xc2a5685b), SkBits2Float(0xc0e02f3c));
+path.cubicTo(SkBits2Float(0xc29fb018), SkBits2Float(0xc223115c), SkBits2Float(0xc263001e), SkBits2Float(0xc28acd07), SkBits2Float(0xc1c2e1a0), SkBits2Float(0xc29eb07c));
+path.lineTo(SkBits2Float(0xc18ce0d1), SkBits2Float(0xc2656e32));
+path.cubicTo(SkBits2Float(0xc22418c2), SkBits2Float(0xc248ad0a), SkBits2Float(0xc266dfbc), SkBits2Float(0xc1ebc2b6), SkBits2Float(0xc26f24bb), SkBits2Float(0xc0a20f94));
+path.cubicTo(SkBits2Float(0xc27769ba), SkBits2Float(0x419abaee), SkBits2Float(0xc24383ac), SkBits2Float(0x422a36b0), SkBits2Float(0xc1d80e5c), SkBits2Float(0x4256500a));
+path.cubicTo(SkBits2Float(0xc0a45587), SkBits2Float(0x428134b2), SkBits2Float(0x41a9eeb8), SkBits2Float(0x4274e820), SkBits2Float(0x421e8655), SkBits2Float(0x423431b1));
+path.lineTo(SkBits2Float(0x425b4ae0), SkBits2Float(0x427944c0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp178(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41fc5f30), SkBits2Float(0xc2a5fffe), SkBits2Float(0x427176a0), SkBits2Float(0xc2823b95), SkBits2Float(0x4294be35), SkBits2Float(0xc21365c9));
+path.cubicTo(SkBits2Float(0x42b0c118), SkBits2Float(0xc1095198), SkBits2Float(0x42aa4b8f), SkBits2Float(0x41c9721a), SkBits2Float(0x42841312), SkBits2Float(0x42491ec0));
+path.lineTo(SkBits2Float(0x423ef37b), SkBits2Float(0x42116356));
+path.cubicTo(SkBits2Float(0x427635bc), SkBits2Float(0x41919f96), SkBits2Float(0x427f8c66), SkBits2Float(0xc0c68887), SkBits2Float(0x42570cd6), SkBits2Float(0xc1d51ae4));
+path.cubicTo(SkBits2Float(0x422e8d45), SkBits2Float(0xc23c49d3), SkBits2Float(0x41b66ffd), SkBits2Float(0xc2700000), SkBits2Float(0xb7060057), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42841313), SkBits2Float(0x42491ebf));
+path.cubicTo(SkBits2Float(0x42793d8e), SkBits2Float(0x425cb36e), SkBits2Float(0x4268336d), SkBits2Float(0x426e9032), SkBits2Float(0x4255582b), SkBits2Float(0x427e60c5));
+path.lineTo(SkBits2Float(0x421a3990), SkBits2Float(0x4237e342));
+path.cubicTo(SkBits2Float(0x4227db27), SkBits2Float(0x422c7494), SkBits2Float(0x42342c7f), SkBits2Float(0x421f8af7), SkBits2Float(0x423ef37c), SkBits2Float(0x42116357));
+path.lineTo(SkBits2Float(0x42841313), SkBits2Float(0x42491ebf));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp179(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb7060057), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41fc5f30), SkBits2Float(0xc2a5fffe), SkBits2Float(0x427176a0), SkBits2Float(0xc2823b95), SkBits2Float(0x4294be35), SkBits2Float(0xc21365c9));
+path.cubicTo(SkBits2Float(0x42b0c118), SkBits2Float(0xc1095198), SkBits2Float(0x42aa4b8f), SkBits2Float(0x41c9721a), SkBits2Float(0x42841313), SkBits2Float(0x42491ebf));
+path.cubicTo(SkBits2Float(0x42793d8e), SkBits2Float(0x425cb36e), SkBits2Float(0x4268336d), SkBits2Float(0x426e9032), SkBits2Float(0x4255582b), SkBits2Float(0x427e60c5));
+path.lineTo(SkBits2Float(0x421a3990), SkBits2Float(0x4237e342));
+path.cubicTo(SkBits2Float(0x4227db27), SkBits2Float(0x422c7494), SkBits2Float(0x42342c7f), SkBits2Float(0x421f8af7), SkBits2Float(0x423ef37b), SkBits2Float(0x42116356));
+path.cubicTo(SkBits2Float(0x427635bc), SkBits2Float(0x41919f96), SkBits2Float(0x427f8c66), SkBits2Float(0xc0c68887), SkBits2Float(0x42570cd6), SkBits2Float(0xc1d51ae4));
+path.cubicTo(SkBits2Float(0x422e8d45), SkBits2Float(0xc23c49d3), SkBits2Float(0x41b66ffd), SkBits2Float(0xc2700000), SkBits2Float(0xb7060057), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4255582a), SkBits2Float(0x427e60c6));
+path.cubicTo(SkBits2Float(0x41d8da26), SkBits2Float(0x42ab2f9f), SkBits2Float(0xc11f0392), SkBits2Float(0x42b2763a), SkBits2Float(0xc21fc8f1), SkBits2Float(0x4291829a));
+path.cubicTo(SkBits2Float(0xc28be87e), SkBits2Float(0x42611df4), SkBits2Float(0xc2ad8941), SkBits2Float(0x41b88f93), SkBits2Float(0xc2a49219), SkBits2Float(0xc12de56c));
+path.cubicTo(SkBits2Float(0xc29b9af2), SkBits2Float(0xc2333a80), SkBits2Float(0xc253c58e), SkBits2Float(0xc2910614), SkBits2Float(0xc19d7dc6), SkBits2Float(0xc2a14359));
+path.lineTo(SkBits2Float(0xc163b2c9), SkBits2Float(0xc26926c4));
+path.cubicTo(SkBits2Float(0xc2191685), SkBits2Float(0xc251ac40), SkBits2Float(0xc260f8ae), SkBits2Float(0xc201900e), SkBits2Float(0xc26deef7), SkBits2Float(0xc0fb6a70));
+path.cubicTo(SkBits2Float(0xc27ae541), SkBits2Float(0x41856ae3), SkBits2Float(0xc24a46d8), SkBits2Float(0x4222bc35), SkBits2Float(0xc1e7039a), SkBits2Float(0x42526049));
+path.cubicTo(SkBits2Float(0xc0e5e60c), SkBits2Float(0x4281022e), SkBits2Float(0x419cc2c4), SkBits2Float(0x42777f70), SkBits2Float(0x421a3996), SkBits2Float(0x4237e33e));
+path.lineTo(SkBits2Float(0x4255582a), SkBits2Float(0x427e60c6));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp180(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41fed5d1), SkBits2Float(0xc2a60000), SkBits2Float(0x4273981d), SkBits2Float(0xc28189e8), SkBits2Float(0x42957e40), SkBits2Float(0xc210547e));
+path.cubicTo(SkBits2Float(0x42b13073), SkBits2Float(0xc0eca961), SkBits2Float(0x42a99b35), SkBits2Float(0x41d57c6c), SkBits2Float(0x4281fa62), SkBits2Float(0x424e82d3));
+path.lineTo(SkBits2Float(0x423beb8b), SkBits2Float(0x421548fc));
+path.cubicTo(SkBits2Float(0x427536c2), SkBits2Float(0x419a53c7), SkBits2Float(0x428016af), SkBits2Float(0xc0ab14a9), SkBits2Float(0x4258227d), SkBits2Float(0xc1d0ab83));
+path.cubicTo(SkBits2Float(0x4230179a), SkBits2Float(0xc23b48ee), SkBits2Float(0x41b837da), SkBits2Float(0xc2700002), SkBits2Float(0xb7060057), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4281fa62), SkBits2Float(0x424e82d5));
+path.cubicTo(SkBits2Float(0x4274817d), SkBits2Float(0x4261f5b7), SkBits2Float(0x4262ebfa), SkBits2Float(0x42739d02), SkBits2Float(0x424f88b8), SkBits2Float(0x428191ef));
+path.lineTo(SkBits2Float(0x4216064f), SkBits2Float(0x423b5489));
+path.cubicTo(SkBits2Float(0x42240a35), SkBits2Float(0x42301b25), SkBits2Float(0x4230c051), SkBits2Float(0x4223582f), SkBits2Float(0x423beb8c), SkBits2Float(0x421548fc));
+path.lineTo(SkBits2Float(0x4281fa62), SkBits2Float(0x424e82d5));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp181(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb7060057), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41fed5d1), SkBits2Float(0xc2a60000), SkBits2Float(0x4273981d), SkBits2Float(0xc28189e8), SkBits2Float(0x42957e40), SkBits2Float(0xc210547e));
+path.cubicTo(SkBits2Float(0x42b13073), SkBits2Float(0xc0eca961), SkBits2Float(0x42a99b35), SkBits2Float(0x41d57c6c), SkBits2Float(0x4281fa62), SkBits2Float(0x424e82d5));
+path.cubicTo(SkBits2Float(0x4274817d), SkBits2Float(0x4261f5b7), SkBits2Float(0x4262ebfa), SkBits2Float(0x42739d02), SkBits2Float(0x424f88b8), SkBits2Float(0x428191ef));
+path.lineTo(SkBits2Float(0x4216064f), SkBits2Float(0x423b5489));
+path.cubicTo(SkBits2Float(0x42240a35), SkBits2Float(0x42301b25), SkBits2Float(0x4230c051), SkBits2Float(0x4223582f), SkBits2Float(0x423beb8b), SkBits2Float(0x421548fc));
+path.cubicTo(SkBits2Float(0x427536c2), SkBits2Float(0x419a53c7), SkBits2Float(0x428016af), SkBits2Float(0xc0ab14a9), SkBits2Float(0x4258227d), SkBits2Float(0xc1d0ab83));
+path.cubicTo(SkBits2Float(0x4230179a), SkBits2Float(0xc23b48ee), SkBits2Float(0x41b837da), SkBits2Float(0xc2700002), SkBits2Float(0xb7060057), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x424f88ba), SkBits2Float(0x428191f0));
+path.cubicTo(SkBits2Float(0x41c732b7), SkBits2Float(0x42acca52), SkBits2Float(0xc14a7268), SkBits2Float(0x42b208b4), SkBits2Float(0xc22982dc), SkBits2Float(0x428ebb75));
+path.cubicTo(SkBits2Float(0xc2903490), SkBits2Float(0x4256dc6c), SkBits2Float(0xc2af8c6f), SkBits2Float(0x419be833), SkBits2Float(0xc2a36e37), SkBits2Float(0xc168c0a6));
+path.cubicTo(SkBits2Float(0xc2974fff), SkBits2Float(0xc242546a), SkBits2Float(0xc2448acf), SkBits2Float(0xc29698ac), SkBits2Float(0xc17253d7), SkBits2Float(0xc2a33682));
+path.lineTo(SkBits2Float(0xc12f2d38), SkBits2Float(0xc26bf872));
+path.cubicTo(SkBits2Float(0xc20e1427), SkBits2Float(0xc259bacc), SkBits2Float(0xc25ac3d7), SkBits2Float(0xc20c7ab2), SkBits2Float(0xc26c48f7), SkBits2Float(0xc1284130));
+path.cubicTo(SkBits2Float(0xc27dce17), SkBits2Float(0x41616864), SkBits2Float(0xc2507d50), SkBits2Float(0x421b5239), SkBits2Float(0xc1f51386), SkBits2Float(0x424e5c1e));
+path.cubicTo(SkBits2Float(0xc11258cd), SkBits2Float(0x4280b301), SkBits2Float(0x418fffac), SkBits2Float(0x4279d13a), SkBits2Float(0x42160652), SkBits2Float(0x423b5488));
+path.lineTo(SkBits2Float(0x424f88ba), SkBits2Float(0x428191f0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp182(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x420048ef), SkBits2Float(0xc2a60000), SkBits2Float(0x4275172d), SkBits2Float(0xc2810bd2), SkBits2Float(0x429602e3), SkBits2Float(0xc20e29dc));
+path.cubicTo(SkBits2Float(0x42b17a30), SkBits2Float(0xc0d1e0a1), SkBits2Float(0x42a9174e), SkBits2Float(0x41ddef9e), SkBits2Float(0x4280787d), SkBits2Float(0x4252400e));
+path.lineTo(SkBits2Float(0x4239bd9f), SkBits2Float(0x4217fcf6));
+path.cubicTo(SkBits2Float(0x4274780f), SkBits2Float(0x41a06f8c), SkBits2Float(0x42804bfe), SkBits2Float(0xc097b7f0), SkBits2Float(0x4258e240), SkBits2Float(0xc1cd899e));
+path.cubicTo(SkBits2Float(0x42312c84), SkBits2Float(0xc23a929f), SkBits2Float(0x41b978e3), SkBits2Float(0xc2700000), SkBits2Float(0x36d3ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4280787d), SkBits2Float(0x42524010));
+path.cubicTo(SkBits2Float(0x42711c0e), SkBits2Float(0x42659909), SkBits2Float(0x425f24ad), SkBits2Float(0x42771864), SkBits2Float(0x424b624a), SkBits2Float(0x4283347a));
+path.lineTo(SkBits2Float(0x42130648), SkBits2Float(0x423db1a5));
+path.cubicTo(SkBits2Float(0x42214ef3), SkBits2Float(0x42329f82), SkBits2Float(0x422e4bcd), SkBits2Float(0x4225f96c), SkBits2Float(0x4239bd9f), SkBits2Float(0x4217fcf7));
+path.lineTo(SkBits2Float(0x4280787d), SkBits2Float(0x42524010));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp183(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36d3ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x420048ef), SkBits2Float(0xc2a60000), SkBits2Float(0x4275172d), SkBits2Float(0xc2810bd2), SkBits2Float(0x429602e3), SkBits2Float(0xc20e29dc));
+path.cubicTo(SkBits2Float(0x42b17a30), SkBits2Float(0xc0d1e0a1), SkBits2Float(0x42a9174e), SkBits2Float(0x41ddef9e), SkBits2Float(0x4280787d), SkBits2Float(0x42524010));
+path.cubicTo(SkBits2Float(0x42711c0e), SkBits2Float(0x42659909), SkBits2Float(0x425f24ad), SkBits2Float(0x42771864), SkBits2Float(0x424b624a), SkBits2Float(0x4283347a));
+path.lineTo(SkBits2Float(0x42130648), SkBits2Float(0x423db1a5));
+path.cubicTo(SkBits2Float(0x42214ef3), SkBits2Float(0x42329f82), SkBits2Float(0x422e4bcd), SkBits2Float(0x4225f96c), SkBits2Float(0x4239bd9f), SkBits2Float(0x4217fcf6));
+path.cubicTo(SkBits2Float(0x4274780f), SkBits2Float(0x41a06f8c), SkBits2Float(0x42804bfe), SkBits2Float(0xc097b7f0), SkBits2Float(0x4258e240), SkBits2Float(0xc1cd899e));
+path.cubicTo(SkBits2Float(0x42312c84), SkBits2Float(0xc23a929f), SkBits2Float(0x41b978e3), SkBits2Float(0xc2700000), SkBits2Float(0x36d3ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x424b624a), SkBits2Float(0x42833479));
+path.cubicTo(SkBits2Float(0x41baac2f), SkBits2Float(0x42adda12), SkBits2Float(0xc168f6a7), SkBits2Float(0x42b1a2b3), SkBits2Float(0xc2303c92), SkBits2Float(0x428cae5c));
+path.cubicTo(SkBits2Float(0xc2931dbe), SkBits2Float(0x424f7409), SkBits2Float(0xc2b0c9d8), SkBits2Float(0x41878abe), SkBits2Float(0xc2a26e7f), SkBits2Float(0xc188ef9a));
+path.cubicTo(SkBits2Float(0xc2941327), SkBits2Float(0xc24cb4f5), SkBits2Float(0xc2397a7c), SkBits2Float(0xc29a4742), SkBits2Float(0xc13ec328), SkBits2Float(0xc2a44746));
+path.lineTo(SkBits2Float(0xc109e67a), SkBits2Float(0xc26d82d0));
+path.cubicTo(SkBits2Float(0xc20614b0), SkBits2Float(0xc25f0d94), SkBits2Float(0xc2561585), SkBits2Float(0xc213fb18), SkBits2Float(0xc26ad744), SkBits2Float(0xc145fabb));
+path.cubicTo(SkBits2Float(0xc27f9901), SkBits2Float(0x4143f6e8), SkBits2Float(0xc254b2af), SkBits2Float(0x4215f75b), SkBits2Float(0xc1feccbb), SkBits2Float(0x424b64f3));
+path.cubicTo(SkBits2Float(0xc128682f), SkBits2Float(0x42806945), SkBits2Float(0x4186f1ba), SkBits2Float(0x427b5a1e), SkBits2Float(0x4213064f), SkBits2Float(0x423db1a2));
+path.lineTo(SkBits2Float(0x424b624a), SkBits2Float(0x42833479));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp184(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42011b87), SkBits2Float(0xc2a5fffe), SkBits2Float(0x427681ab), SkBits2Float(0xc280937a), SkBits2Float(0x42967eb3), SkBits2Float(0xc20c1a94));
+path.cubicTo(SkBits2Float(0x42b1bc91), SkBits2Float(0xc0b87191), SkBits2Float(0x42a89454), SkBits2Float(0x41e5ed6f), SkBits2Float(0x427e0902), SkBits2Float(0x4255c0a2));
+path.lineTo(SkBits2Float(0x4237a3d0), SkBits2Float(0x421a8517));
+path.cubicTo(SkBits2Float(0x4273bab4), SkBits2Float(0x41a63674), SkBits2Float(0x42807bfc), SkBits2Float(0xc0855530), SkBits2Float(0x42599545), SkBits2Float(0xc1ca8f4f));
+path.cubicTo(SkBits2Float(0x42323293), SkBits2Float(0xc239e4a8), SkBits2Float(0x41baa959), SkBits2Float(0xc2700002), SkBits2Float(0xb5600574), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x427e0901), SkBits2Float(0x4255c0a4));
+path.cubicTo(SkBits2Float(0x426dd77c), SkBits2Float(0x4268ff65), SkBits2Float(0x425b838b), SkBits2Float(0x427a571f), SkBits2Float(0x42476779), SkBits2Float(0x4284b92f));
+path.lineTo(SkBits2Float(0x421025c9), SkBits2Float(0x423fe3a3));
+path.cubicTo(SkBits2Float(0x421eaf4b), SkBits2Float(0x4234f80b), SkBits2Float(0x422bef10), SkBits2Float(0x42286e9a), SkBits2Float(0x4237a3d2), SkBits2Float(0x421a8517));
+path.lineTo(SkBits2Float(0x427e0901), SkBits2Float(0x4255c0a4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp185(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42011b87), SkBits2Float(0xc2a5fffe), SkBits2Float(0x427681ab), SkBits2Float(0xc280937a), SkBits2Float(0x42967eb3), SkBits2Float(0xc20c1a94));
+path.cubicTo(SkBits2Float(0x42b1bc91), SkBits2Float(0xc0b87191), SkBits2Float(0x42a89454), SkBits2Float(0x41e5ed6f), SkBits2Float(0x427e0902), SkBits2Float(0x4255c0a2));
+path.lineTo(SkBits2Float(0x427e0901), SkBits2Float(0x4255c0a4));
+path.cubicTo(SkBits2Float(0x426dd77c), SkBits2Float(0x4268ff65), SkBits2Float(0x425b838b), SkBits2Float(0x427a571f), SkBits2Float(0x42476779), SkBits2Float(0x4284b92f));
+path.lineTo(SkBits2Float(0x421025c9), SkBits2Float(0x423fe3a3));
+path.cubicTo(SkBits2Float(0x421eaf4b), SkBits2Float(0x4234f80b), SkBits2Float(0x422bef10), SkBits2Float(0x42286e9a), SkBits2Float(0x4237a3d2), SkBits2Float(0x421a8517));
+path.lineTo(SkBits2Float(0x4237a3d0), SkBits2Float(0x421a8517));
+path.cubicTo(SkBits2Float(0x4273bab4), SkBits2Float(0x41a63674), SkBits2Float(0x42807bfc), SkBits2Float(0xc0855530), SkBits2Float(0x42599545), SkBits2Float(0xc1ca8f4f));
+path.cubicTo(SkBits2Float(0x42323293), SkBits2Float(0xc239e4a8), SkBits2Float(0x41baa959), SkBits2Float(0xc2700002), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42476779), SkBits2Float(0x4284b92f));
+path.cubicTo(SkBits2Float(0x41aeb99d), SkBits2Float(0x42aece6d), SkBits2Float(0xc182ebc7), SkBits2Float(0x42b12f04), SkBits2Float(0xc236847b), SkBits2Float(0x428aaa1d));
+path.cubicTo(SkBits2Float(0xc295c989), SkBits2Float(0x42484a6d), SkBits2Float(0xc2b1d401), SkBits2Float(0x41683386), SkBits2Float(0xc2a15607), SkBits2Float(0xc19c4a77));
+path.cubicTo(SkBits2Float(0xc290d80f), SkBits2Float(0xc2565754), SkBits2Float(0xc22ebdc1), SkBits2Float(0xc29d94aa), SkBits2Float(0xc10da15c), SkBits2Float(0xc2a50da2));
+path.lineTo(SkBits2Float(0xc0ccc448), SkBits2Float(0xc26ea197));
+path.cubicTo(SkBits2Float(0xc1fca350), SkBits2Float(0xc263d3da), SkBits2Float(0xc25169ba), SkBits2Float(0xc21af203), SkBits2Float(0xc26941c7), SkBits2Float(0xc161f664));
+path.cubicTo(SkBits2Float(0xc2808cea), SkBits2Float(0x4127db45), SkBits2Float(0xc2588f4e), SkBits2Float(0x4210c9da), SkBits2Float(0xc203f0b6), SkBits2Float(0x42487a91));
+path.cubicTo(SkBits2Float(0xc13d487f), SkBits2Float(0x428015a4), SkBits2Float(0x417c9d5c), SkBits2Float(0x427cbb65), SkBits2Float(0x421025ca), SkBits2Float(0x423fe3a2));
+path.lineTo(SkBits2Float(0x42476779), SkBits2Float(0x4284b92f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp186(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4201bd60), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427797bb), SkBits2Float(0xc2803682), SkBits2Float(0x4296dc8c), SkBits2Float(0xc20a848f));
+path.cubicTo(SkBits2Float(0x42b1ed3b), SkBits2Float(0xc0a4e0c3), SkBits2Float(0x42a82bcd), SkBits2Float(0x41ec0db8), SkBits2Float(0x427bc56e), SkBits2Float(0x42586a20));
+path.lineTo(SkBits2Float(0x423600d6), SkBits2Float(0x421c71bc));
+path.cubicTo(SkBits2Float(0x42732394), SkBits2Float(0x41aaa425), SkBits2Float(0x42809f29), SkBits2Float(0xc06e60a8), SkBits2Float(0x425a1cf3), SkBits2Float(0xc1c84447));
+path.cubicTo(SkBits2Float(0x4232fb94), SkBits2Float(0xc2395e3c), SkBits2Float(0x41bb9357), SkBits2Float(0xc2700002), SkBits2Float(0xb69400ae), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x427bc56c), SkBits2Float(0x42586a22));
+path.cubicTo(SkBits2Float(0x426b4cc6), SkBits2Float(0x426b93ad), SkBits2Float(0x4258b1e1), SkBits2Float(0x427ccbca), SkBits2Float(0x42445140), SkBits2Float(0x4285de6e));
+path.lineTo(SkBits2Float(0x420dea8b), SkBits2Float(0x42418b9b));
+path.cubicTo(SkBits2Float(0x421ca599), SkBits2Float(0x4236be7f), SkBits2Float(0x422a18a8), SkBits2Float(0x422a4be8), SkBits2Float(0x423600d6), SkBits2Float(0x421c71bc));
+path.lineTo(SkBits2Float(0x427bc56c), SkBits2Float(0x42586a22));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp187(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb69400ae), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4201bd60), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427797bb), SkBits2Float(0xc2803682), SkBits2Float(0x4296dc8c), SkBits2Float(0xc20a848f));
+path.cubicTo(SkBits2Float(0x42b1ed3b), SkBits2Float(0xc0a4e0c3), SkBits2Float(0x42a82bcd), SkBits2Float(0x41ec0db8), SkBits2Float(0x427bc56e), SkBits2Float(0x42586a20));
+path.lineTo(SkBits2Float(0x423600d6), SkBits2Float(0x421c71bc));
+path.cubicTo(SkBits2Float(0x42732394), SkBits2Float(0x41aaa425), SkBits2Float(0x42809f29), SkBits2Float(0xc06e60a8), SkBits2Float(0x425a1cf3), SkBits2Float(0xc1c84447));
+path.cubicTo(SkBits2Float(0x4232fb94), SkBits2Float(0xc2395e3c), SkBits2Float(0x41bb9357), SkBits2Float(0xc2700002), SkBits2Float(0xb69400ae), SkBits2Float(0xc2700000));
+path.close();
+path.moveTo(SkBits2Float(0x423600d6), SkBits2Float(0x421c71bc));
+path.lineTo(SkBits2Float(0x427bc56c), SkBits2Float(0x42586a22));
+path.cubicTo(SkBits2Float(0x426b4cc6), SkBits2Float(0x426b93ad), SkBits2Float(0x4258b1e1), SkBits2Float(0x427ccbca), SkBits2Float(0x42445140), SkBits2Float(0x4285de6e));
+path.lineTo(SkBits2Float(0x420dea8b), SkBits2Float(0x42418b9b));
+path.cubicTo(SkBits2Float(0x421ca599), SkBits2Float(0x4236be7f), SkBits2Float(0x422a18a8), SkBits2Float(0x422a4be8), SkBits2Float(0x423600d6), SkBits2Float(0x421c71bc));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42445140), SkBits2Float(0x4285de6e));
+path.cubicTo(SkBits2Float(0x41a5801a), SkBits2Float(0x42af8153), SkBits2Float(0xc18dfe3b), SkBits2Float(0x42b0c99d), SkBits2Float(0xc23b472e), SkBits2Float(0x42891183));
+path.cubicTo(SkBits2Float(0xc297c79f), SkBits2Float(0x4242b2d1), SkBits2Float(0xc2b28961), SkBits2Float(0x414a2ba6), SkBits2Float(0xc2a0659f), SkBits2Float(0xc1ab0f22));
+path.cubicTo(SkBits2Float(0xc28e41db), SkBits2Float(0xc25d9a0f), SkBits2Float(0xc2265613), SkBits2Float(0xc29ffd9f), SkBits2Float(0xc0cf8787), SkBits2Float(0xc2a57e12));
+path.lineTo(SkBits2Float(0xc09605ca), SkBits2Float(0xc26f4428));
+path.cubicTo(SkBits2Float(0xc1f07c7d), SkBits2Float(0xc2674fd1), SkBits2Float(0xc24dac50), SkBits2Float(0xc22031a9), SkBits2Float(0xc267e62b), SkBits2Float(0xc1775074));
+path.cubicTo(SkBits2Float(0xc2811003), SkBits2Float(0x411225be), SkBits2Float(0xc25b70c1), SkBits2Float(0x420cbef2), SkBits2Float(0xc20761ad), SkBits2Float(0x42462bd0));
+path.cubicTo(SkBits2Float(0xc14d4a68), SkBits2Float(0x427f98ac), SkBits2Float(0x416f472e), SkBits2Float(0x427dbe0b), SkBits2Float(0x420dea8f), SkBits2Float(0x42418b9b));
+path.lineTo(SkBits2Float(0x42445140), SkBits2Float(0x4285de6e));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp188(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42025498), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42789b1b), SkBits2Float(0xc27fbe84), SkBits2Float(0x42973334), SkBits2Float(0xc2090897));
+path.cubicTo(SkBits2Float(0x42b218da), SkBits2Float(0xc092954a), SkBits2Float(0x42a7c71a), SkBits2Float(0x41f1c3b5), SkBits2Float(0x4279a1de), SkBits2Float(0x425ae0d9));
+path.lineTo(SkBits2Float(0x42347503), SkBits2Float(0x421e39ac));
+path.cubicTo(SkBits2Float(0x427291fe), SkBits2Float(0x41aec4fe), SkBits2Float(0x4280beb1), SkBits2Float(0xc053ed89), SkBits2Float(0x425a9a3a), SkBits2Float(0xc1c61ef1));
+path.cubicTo(SkBits2Float(0x4233b713), SkBits2Float(0xc238e018), SkBits2Float(0x41bc6df5), SkBits2Float(0xc2700002), SkBits2Float(0xb7240057), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4279a1de), SkBits2Float(0x425ae0d9));
+path.cubicTo(SkBits2Float(0x4268e6ce), SkBits2Float(0x426df5b7), SkBits2Float(0x425609c8), SkBits2Float(0x427f0f64), SkBits2Float(0x42416967), SkBits2Float(0x4286ec0f));
+path.lineTo(SkBits2Float(0x420bd0d2), SkBits2Float(0x42431170));
+path.cubicTo(SkBits2Float(0x421ab9f8), SkBits2Float(0x4238617e), SkBits2Float(0x42285cd4), SkBits2Float(0x422c04e7), SkBits2Float(0x42347505), SkBits2Float(0x421e39ac));
+path.lineTo(SkBits2Float(0x4279a1de), SkBits2Float(0x425ae0d9));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp189(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb7240057), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42025498), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42789b1b), SkBits2Float(0xc27fbe84), SkBits2Float(0x42973334), SkBits2Float(0xc2090897));
+path.cubicTo(SkBits2Float(0x42b218da), SkBits2Float(0xc092954a), SkBits2Float(0x42a7c71a), SkBits2Float(0x41f1c3b5), SkBits2Float(0x4279a1de), SkBits2Float(0x425ae0d9));
+path.cubicTo(SkBits2Float(0x4268e6ce), SkBits2Float(0x426df5b7), SkBits2Float(0x425609c8), SkBits2Float(0x427f0f64), SkBits2Float(0x42416967), SkBits2Float(0x4286ec0f));
+path.lineTo(SkBits2Float(0x420bd0d2), SkBits2Float(0x42431170));
+path.cubicTo(SkBits2Float(0x421ab9f8), SkBits2Float(0x4238617e), SkBits2Float(0x42285cd4), SkBits2Float(0x422c04e7), SkBits2Float(0x42347505), SkBits2Float(0x421e39ac));
+path.lineTo(SkBits2Float(0x42347503), SkBits2Float(0x421e39ac));
+path.cubicTo(SkBits2Float(0x427291fe), SkBits2Float(0x41aec4fe), SkBits2Float(0x4280beb1), SkBits2Float(0xc053ed89), SkBits2Float(0x425a9a3a), SkBits2Float(0xc1c61ef1));
+path.cubicTo(SkBits2Float(0x4233b713), SkBits2Float(0xc238e018), SkBits2Float(0x41bc6df5), SkBits2Float(0xc2700002), SkBits2Float(0xb7240057), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42416967), SkBits2Float(0x4286ec0f));
+path.cubicTo(SkBits2Float(0x419cd99a), SkBits2Float(0x42b02173), SkBits2Float(0xc19850b8), SkBits2Float(0x42b06117), SkBits2Float(0xc23fac11), SkBits2Float(0x42878a96));
+path.cubicTo(SkBits2Float(0xc29997e3), SkBits2Float(0x423d682a), SkBits2Float(0xc2b3208c), SkBits2Float(0x412e025f), SkBits2Float(0xc29f71a3), SkBits2Float(0xc1b8c415));
+path.cubicTo(SkBits2Float(0xc28bc2ba), SkBits2Float(0xc26444ae), SkBits2Float(0xc21e5e96), SkBits2Float(0xc2a223df), SkBits2Float(0xc088ac52), SkBits2Float(0xc2a5c7b3));
+path.lineTo(SkBits2Float(0xc0459a01), SkBits2Float(0xc26fae99));
+path.cubicTo(SkBits2Float(0xc1e4f7d0), SkBits2Float(0xc26a6b5c), SkBits2Float(0xc24a1045), SkBits2Float(0xc225035c), SkBits2Float(0xc266856e), SkBits2Float(0xc18590cd));
+path.cubicTo(SkBits2Float(0xc2817d4a), SkBits2Float(0x40fb9475), SkBits2Float(0xc25e0ffd), SkBits2Float(0x4208ebae), SkBits2Float(0xc20a8edd), SkBits2Float(0x4243f69e));
+path.cubicTo(SkBits2Float(0xc15c36ee), SkBits2Float(0x427f018f), SkBits2Float(0x4162c57c), SkBits2Float(0x427ea58e), SkBits2Float(0x420bd0d7), SkBits2Float(0x4243116e));
+path.lineTo(SkBits2Float(0x42416967), SkBits2Float(0x4286ec0f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp190(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4202b56e), SkBits2Float(0xc2a60000), SkBits2Float(0x427940ff), SkBits2Float(0xc27f4e67), SkBits2Float(0x42976a2d), SkBits2Float(0xc20814ff));
+path.cubicTo(SkBits2Float(0x42b233da), SkBits2Float(0xc086dcb5), SkBits2Float(0x42a78518), SkBits2Float(0x41f56a27), SkBits2Float(0x42784037), SkBits2Float(0x425c71a4));
+path.lineTo(SkBits2Float(0x4233755d), SkBits2Float(0x421f5b67));
+path.cubicTo(SkBits2Float(0x4272328d), SkBits2Float(0x41b16880), SkBits2Float(0x4280d235), SkBits2Float(0xc042fb32), SkBits2Float(0x425ae9b3), SkBits2Float(0xc1c4bebc));
+path.cubicTo(SkBits2Float(0x42342efc), SkBits2Float(0xc2388f09), SkBits2Float(0x41bcf9fa), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42784038), SkBits2Float(0x425c71a4));
+path.cubicTo(SkBits2Float(0x42675aa4), SkBits2Float(0x426f78d5), SkBits2Float(0x4254535c), SkBits2Float(0x42803f48), SkBits2Float(0x423f8a54), SkBits2Float(0x4287967e));
+path.lineTo(SkBits2Float(0x420a7682), SkBits2Float(0x424407da));
+path.cubicTo(SkBits2Float(0x42197d0c), SkBits2Float(0x42396aed), SkBits2Float(0x42273e74), SkBits2Float(0x422d1cc3), SkBits2Float(0x4233755f), SkBits2Float(0x421f5b68));
+path.lineTo(SkBits2Float(0x42784038), SkBits2Float(0x425c71a4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp191(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4202b56e), SkBits2Float(0xc2a60000), SkBits2Float(0x427940ff), SkBits2Float(0xc27f4e67), SkBits2Float(0x42976a2d), SkBits2Float(0xc20814ff));
+path.cubicTo(SkBits2Float(0x42b233da), SkBits2Float(0xc086dcb5), SkBits2Float(0x42a78518), SkBits2Float(0x41f56a27), SkBits2Float(0x42784038), SkBits2Float(0x425c71a4));
+path.cubicTo(SkBits2Float(0x42675aa4), SkBits2Float(0x426f78d5), SkBits2Float(0x4254535c), SkBits2Float(0x42803f48), SkBits2Float(0x423f8a54), SkBits2Float(0x4287967e));
+path.lineTo(SkBits2Float(0x420a7682), SkBits2Float(0x424407da));
+path.cubicTo(SkBits2Float(0x42197d0c), SkBits2Float(0x42396aed), SkBits2Float(0x42273e74), SkBits2Float(0x422d1cc3), SkBits2Float(0x4233755f), SkBits2Float(0x421f5b68));
+path.lineTo(SkBits2Float(0x4233755d), SkBits2Float(0x421f5b67));
+path.cubicTo(SkBits2Float(0x4272328d), SkBits2Float(0x41b16880), SkBits2Float(0x4280d235), SkBits2Float(0xc042fb32), SkBits2Float(0x425ae9b3), SkBits2Float(0xc1c4bebc));
+path.cubicTo(SkBits2Float(0x42342efc), SkBits2Float(0xc2388f09), SkBits2Float(0x41bcf9fa), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423f8a55), SkBits2Float(0x4287967f));
+path.cubicTo(SkBits2Float(0x41974ba2), SkBits2Float(0x42b0846d), SkBits2Float(0xc19ee9a3), SkBits2Float(0x42b01937), SkBits2Float(0xc2427547), SkBits2Float(0x42868bae));
+path.cubicTo(SkBits2Float(0xc29abade), SkBits2Float(0x4239fc4c), SkBits2Float(0xc2b3780d), SkBits2Float(0x411bee16), SkBits2Float(0xc29ecbab), SkBits2Float(0xc1c17e4f));
+path.cubicTo(SkBits2Float(0xc28a1f48), SkBits2Float(0xc26879d6), SkBits2Float(0xc2193674), SkBits2Float(0xc2a376c5), SkBits2Float(0xc0368c8c), SkBits2Float(0xc2a5e6e5));
+path.lineTo(SkBits2Float(0xc003f6b5), SkBits2Float(0xc26fdbb6));
+path.cubicTo(SkBits2Float(0xc1dd8323), SkBits2Float(0xc26c555a), SkBits2Float(0xc247b1d3), SkBits2Float(0xc2280e0b), SkBits2Float(0xc2659575), SkBits2Float(0xc18bdff2));
+path.cubicTo(SkBits2Float(0xc281bc8c), SkBits2Float(0x40e170d0), SkBits2Float(0xc25fb4ae), SkBits2Float(0x42067283), SkBits2Float(0xc20c926e), SkBits2Float(0x42428613));
+path.cubicTo(SkBits2Float(0xc165c0b5), SkBits2Float(0x427e99a3), SkBits2Float(0x415abda1), SkBits2Float(0x427f34a6), SkBits2Float(0x420a7686), SkBits2Float(0x424407d8));
+path.lineTo(SkBits2Float(0x423f8a55), SkBits2Float(0x4287967f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp192(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4202fa25), SkBits2Float(0xc2a60000), SkBits2Float(0x4279b699), SkBits2Float(0xc27efea4), SkBits2Float(0x429790ee), SkBits2Float(0xc20767f9));
+path.cubicTo(SkBits2Float(0x42b24690), SkBits2Float(0xc07d14fa), SkBits2Float(0x42a75587), SkBits2Float(0x41f80076), SkBits2Float(0x427743d2), SkBits2Float(0x425d8c9b));
+path.lineTo(SkBits2Float(0x4232bee9), SkBits2Float(0x422027f2));
+path.cubicTo(SkBits2Float(0x4271edc7), SkBits2Float(0x41b34741), SkBits2Float(0x4280dfbb), SkBits2Float(0xc036f37a), SkBits2Float(0x425b21bb), SkBits2Float(0xc1c3c49a));
+path.cubicTo(SkBits2Float(0x423483ff), SkBits2Float(0xc2385562), SkBits2Float(0x41bd5d54), SkBits2Float(0xc2700000), SkBits2Float(0x36d3ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x427743d4), SkBits2Float(0x425d8c98));
+path.cubicTo(SkBits2Float(0x4266401a), SkBits2Float(0x427089e5), SkBits2Float(0x42531ae2), SkBits2Float(0x4280c0a0), SkBits2Float(0x423e3514), SkBits2Float(0x42880e64));
+path.lineTo(SkBits2Float(0x42097fd1), SkBits2Float(0x4244b531));
+path.cubicTo(SkBits2Float(0x42189b26), SkBits2Float(0x423a25ea), SkBits2Float(0x42267233), SkBits2Float(0x422de224), SkBits2Float(0x4232beea), SkBits2Float(0x422027f3));
+path.lineTo(SkBits2Float(0x427743d4), SkBits2Float(0x425d8c98));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp193(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e15a675), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3e95a67a), SkBits2Float(0xc2a5ffcd), SkBits2Float(0x3ee07980), SkBits2Float(0xc2a5ff68));
+path.lineTo(SkBits2Float(0x3ea245bb), SkBits2Float(0xc26fff25));
+path.cubicTo(SkBits2Float(0x3e585de0), SkBits2Float(0xc26fffb9), SkBits2Float(0x3dd85f11), SkBits2Float(0xc2700000), SkBits2Float(0x3691e768), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ee07a10), SkBits2Float(0xc2a5ff68));
+path.cubicTo(SkBits2Float(0x3ee7f565), SkBits2Float(0xc2a5ff5d), SkBits2Float(0x3eef70d9), SkBits2Float(0xc2a5ff52), SkBits2Float(0x3ef6ec4d), SkBits2Float(0xc2a5ff47));
+path.lineTo(SkBits2Float(0x3eb27fdb), SkBits2Float(0xc26ffef6));
+path.cubicTo(SkBits2Float(0x3ead1768), SkBits2Float(0xc26fff07), SkBits2Float(0x3ea7aebe), SkBits2Float(0xc26fff17), SkBits2Float(0x3ea24612), SkBits2Float(0xc26fff26));
+path.lineTo(SkBits2Float(0x3ee07a10), SkBits2Float(0xc2a5ff68));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp194(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3691e768), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e15a675), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3e95a67a), SkBits2Float(0xc2a5ffcd), SkBits2Float(0x3ee07a10), SkBits2Float(0xc2a5ff68));
+path.lineTo(SkBits2Float(0x3ef6ec4d), SkBits2Float(0xc2a5ff47));
+path.lineTo(SkBits2Float(0x3eb27fdb), SkBits2Float(0xc26ffef6));
+path.cubicTo(SkBits2Float(0x3ead1768), SkBits2Float(0xc26fff07), SkBits2Float(0x3ea7aebe), SkBits2Float(0xc26fff17), SkBits2Float(0x3ea245bb), SkBits2Float(0xc26fff25));
+path.cubicTo(SkBits2Float(0x3e585de0), SkBits2Float(0xc26fffb9), SkBits2Float(0x3dd85f11), SkBits2Float(0xc2700000), SkBits2Float(0x3691e768), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ef6ec9b), SkBits2Float(0xc2a5ff48));
+path.cubicTo(SkBits2Float(0x3f3816c9), SkBits2Float(0xc2a5fe94), SkBits2Float(0x3f74b6e1), SkBits2Float(0xc2a5fd5b), SkBits2Float(0x3f98ab0b), SkBits2Float(0xc2a5fb9d));
+path.lineTo(SkBits2Float(0x3f5cb973), SkBits2Float(0xc26ff9a8));
+path.cubicTo(SkBits2Float(0x3f30e6e7), SkBits2Float(0xc26ffc2e), SkBits2Float(0x3f05138e), SkBits2Float(0xc26ffdf2), SkBits2Float(0x3eb27fc6), SkBits2Float(0xc26ffef7));
+path.lineTo(SkBits2Float(0x3ef6ec9b), SkBits2Float(0xc2a5ff48));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp195(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f0607d9), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3f860760), SkBits2Float(0xc2a5fd76), SkBits2Float(0x3fc90825), SkBits2Float(0xc2a5f863));
+path.lineTo(SkBits2Float(0x3f9152f7), SkBits2Float(0xc26ff500));
+path.cubicTo(SkBits2Float(0x3f41c6b2), SkBits2Float(0xc26ffc55), SkBits2Float(0x3ec1c794), SkBits2Float(0xc26fffff), SkBits2Float(0x36a51f4a), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3fc9081a), SkBits2Float(0xc2a5f864));
+path.cubicTo(SkBits2Float(0x3fcfbb75), SkBits2Float(0xc2a5f7e2), SkBits2Float(0x3fd66eab), SkBits2Float(0xc2a5f75a), SkBits2Float(0x3fdd21d8), SkBits2Float(0xc2a5f6cb));
+path.lineTo(SkBits2Float(0x3f9fdac0), SkBits2Float(0xc26ff2b1));
+path.cubicTo(SkBits2Float(0x3f9b02da), SkBits2Float(0xc26ff37f), SkBits2Float(0x3f962add), SkBits2Float(0xc26ff444), SkBits2Float(0x3f9152da), SkBits2Float(0xc26ff500));
+path.lineTo(SkBits2Float(0x3fc9081a), SkBits2Float(0xc2a5f864));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp196(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36a51f4a), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3f0607d1), SkBits2Float(0xc2a60000), SkBits2Float(0x3f860758), SkBits2Float(0xc2a5fd76), SkBits2Float(0x3fc9081a), SkBits2Float(0xc2a5f864));
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3fdd21ce), SkBits2Float(0xc2a5f6cb));
+path.cubicTo(SkBits2Float(0x4024daa1), SkBits2Float(0xc2a5edc0), SkBits2Float(0x405b1f05), SkBits2Float(0xc2a5de0d), SkBits2Float(0x4088aca3), SkBits2Float(0xc2a5c7b3));
+path.lineTo(SkBits2Float(0x40459a01), SkBits2Float(0xc26fae99));
+path.cubicTo(SkBits2Float(0x401e66a3), SkBits2Float(0xc26fceed), SkBits2Float(0x3fee57cd), SkBits2Float(0xc26fe5a0), SkBits2Float(0x3f9fdaba), SkBits2Float(0xc26ff2b3));
+path.lineTo(SkBits2Float(0x3fdd21ce), SkBits2Float(0xc2a5f6cb));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp197(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3fa0bd52), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4020babd), SkBits2Float(0xc2a5f168), SkBits2Float(0x40710446), SkBits2Float(0xc2a5d43c));
+path.lineTo(SkBits2Float(0x402e3a94), SkBits2Float(0xc26fc0ba));
+path.cubicTo(SkBits2Float(0x3fe86158), SkBits2Float(0xc26feae9), SkBits2Float(0x3f686554), SkBits2Float(0xc2700000), SkBits2Float(0x369bbf59), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4071043c), SkBits2Float(0xc2a5d43c));
+path.cubicTo(SkBits2Float(0x40790b78), SkBits2Float(0xc2a5d151), SkBits2Float(0x40808943), SkBits2Float(0xc2a5ce41), SkBits2Float(0x40848cac), SkBits2Float(0xc2a5cb0c));
+path.lineTo(SkBits2Float(0x403fa34c), SkBits2Float(0xc26fb371));
+path.cubicTo(SkBits2Float(0x4039d5dd), SkBits2Float(0xc26fb815), SkBits2Float(0x40340849), SkBits2Float(0xc26fbc83), SkBits2Float(0x402e3a8d), SkBits2Float(0xc26fc0bb));
+path.lineTo(SkBits2Float(0x4071043c), SkBits2Float(0xc2a5d43c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp198(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x369bbf59), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3fa0bd4b), SkBits2Float(0xc2a60000), SkBits2Float(0x4020bab6), SkBits2Float(0xc2a5f168), SkBits2Float(0x4071043c), SkBits2Float(0xc2a5d43c));
+path.lineTo(SkBits2Float(0x40710446), SkBits2Float(0xc2a5d43c));
+path.cubicTo(SkBits2Float(0x40790b7f), SkBits2Float(0xc2a5d151), SkBits2Float(0x40808945), SkBits2Float(0xc2a5ce41), SkBits2Float(0x40848cac), SkBits2Float(0xc2a5cb0c));
+path.lineTo(SkBits2Float(0x403fa34c), SkBits2Float(0xc26fb371));
+path.quadTo(SkBits2Float(0x4036ef2a), SkBits2Float(0xc26fba67), SkBits2Float(0x402e3a95), SkBits2Float(0xc26fc0bb));
+path.lineTo(SkBits2Float(0x402e3a94), SkBits2Float(0xc26fc0ba));
+path.cubicTo(SkBits2Float(0x3fe86158), SkBits2Float(0xc26feae9), SkBits2Float(0x3f686554), SkBits2Float(0xc2700000), SkBits2Float(0x369bbf59), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40848cae), SkBits2Float(0xc2a5cb0c));
+path.cubicTo(SkBits2Float(0x40c597bc), SkBits2Float(0xc2a5970c), SkBits2Float(0x41033f43), SkBits2Float(0xc2a53cca), SkBits2Float(0x41238fb3), SkBits2Float(0xc2a4bc74));
+path.lineTo(SkBits2Float(0x40ec7963), SkBits2Float(0xc26e2c38));
+path.cubicTo(SkBits2Float(0x40bdc13f), SkBits2Float(0xc26ee5c4), SkBits2Float(0x408ed689), SkBits2Float(0xc26f6843), SkBits2Float(0x403fa341), SkBits2Float(0xc26fb372));
+path.lineTo(SkBits2Float(0x40848cae), SkBits2Float(0xc2a5cb0c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp199(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ffdfad4), SkBits2Float(0xc2a60000), SkBits2Float(0x407df074), SkBits2Float(0xc2a5db92), SkBits2Float(0x40be4d32), SkBits2Float(0xc2a592c7));
+path.lineTo(SkBits2Float(0x40899143), SkBits2Float(0xc26f6217));
+path.cubicTo(SkBits2Float(0x40379219), SkBits2Float(0xc26fcb54), SkBits2Float(0x3fb799b8), SkBits2Float(0xc26fffff), SkBits2Float(0x3673fea3), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40be4d37), SkBits2Float(0xc2a592c7));
+path.cubicTo(SkBits2Float(0x40c4a257), SkBits2Float(0xc2a58b80), SkBits2Float(0x40caf70c), SkBits2Float(0xc2a583db), SkBits2Float(0x40d14b4e), SkBits2Float(0xc2a57bda));
+path.lineTo(SkBits2Float(0x40974c04), SkBits2Float(0xc26f40f2));
+path.cubicTo(SkBits2Float(0x4092b8c1), SkBits2Float(0xc26f4c86), SkBits2Float(0x408e252c), SkBits2Float(0xc26f5792), SkBits2Float(0x4089914a), SkBits2Float(0xc26f6219));
+path.lineTo(SkBits2Float(0x40be4d37), SkBits2Float(0xc2a592c7));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp200(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3673fea3), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3ffdfad4), SkBits2Float(0xc2a60000), SkBits2Float(0x407df074), SkBits2Float(0xc2a5db92), SkBits2Float(0x40be4d37), SkBits2Float(0xc2a592c7));
+path.cubicTo(SkBits2Float(0x40c4a257), SkBits2Float(0xc2a58b80), SkBits2Float(0x40caf70c), SkBits2Float(0xc2a583db), SkBits2Float(0x40d14b4e), SkBits2Float(0xc2a57bda));
+path.lineTo(SkBits2Float(0x40974c04), SkBits2Float(0xc26f40f2));
+path.cubicTo(SkBits2Float(0x4092b8c1), SkBits2Float(0xc26f4c86), SkBits2Float(0x408e252c), SkBits2Float(0xc26f5792), SkBits2Float(0x4089914a), SkBits2Float(0xc26f6219));
+path.lineTo(SkBits2Float(0x40899143), SkBits2Float(0xc26f6217));
+path.cubicTo(SkBits2Float(0x40379219), SkBits2Float(0xc26fcb54), SkBits2Float(0x3fb799b8), SkBits2Float(0xc26fffff), SkBits2Float(0x3673fea3), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x40d14b4a), SkBits2Float(0xc2a57bdb));
+path.cubicTo(SkBits2Float(0x411bf161), SkBits2Float(0xc2a4fa1a), SkBits2Float(0x414ef5ad), SkBits2Float(0xc2a4190e), SkBits2Float(0x4180b83e), SkBits2Float(0xc2a2d9dc));
+path.lineTo(SkBits2Float(0x413a19cf), SkBits2Float(0xc26b727f));
+path.cubicTo(SkBits2Float(0x41159c04), SkBits2Float(0xc26d3fff), SkBits2Float(0x40e175a8), SkBits2Float(0xc26e855c), SkBits2Float(0x40974c02), SkBits2Float(0xc26f40f4));
+path.lineTo(SkBits2Float(0x40d14b4a), SkBits2Float(0xc2a57bdb));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp201(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4059d383), SkBits2Float(0xc2a5ffff), SkBits2Float(0x40d9b918), SkBits2Float(0xc2a594d0), SkBits2Float(0x4122e820), SkBits2Float(0xc2a4bf0c));
+path.lineTo(SkBits2Float(0x40eb871c), SkBits2Float(0xc26e2ff8));
+path.cubicTo(SkBits2Float(0x409d63e0), SkBits2Float(0xc26f6508), SkBits2Float(0x401d76fa), SkBits2Float(0xc2700000), SkBits2Float(0x35f7fd4a), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4122e81e), SkBits2Float(0xc2a4bf0c));
+path.cubicTo(SkBits2Float(0x41284f3c), SkBits2Float(0xc2a4a9ac), SkBits2Float(0x412db549), SkBits2Float(0xc2a4933e), SkBits2Float(0x41331a33), SkBits2Float(0xc2a47bbf));
+path.lineTo(SkBits2Float(0x410178be), SkBits2Float(0xc26dceac));
+path.cubicTo(SkBits2Float(0x40fb24f7), SkBits2Float(0xc26df0a4), SkBits2Float(0x40f356d1), SkBits2Float(0xc26e1114), SkBits2Float(0x40eb871f), SkBits2Float(0xc26e2ff8));
+path.lineTo(SkBits2Float(0x4122e81e), SkBits2Float(0xc2a4bf0c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp202(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4059d380), SkBits2Float(0xc2a60000), SkBits2Float(0x40d9b915), SkBits2Float(0xc2a594d0), SkBits2Float(0x4122e81e), SkBits2Float(0xc2a4bf0c));
+path.lineTo(SkBits2Float(0x4122e820), SkBits2Float(0xc2a4bf0c));
+path.cubicTo(SkBits2Float(0x41284f3d), SkBits2Float(0xc2a4a9ac), SkBits2Float(0x412db54a), SkBits2Float(0xc2a4933e), SkBits2Float(0x41331a33), SkBits2Float(0xc2a47bbf));
+path.lineTo(SkBits2Float(0x410178be), SkBits2Float(0xc26dceac));
+path.cubicTo(SkBits2Float(0x40fb24f7), SkBits2Float(0xc26df0a4), SkBits2Float(0x40f356d1), SkBits2Float(0xc26e1114), SkBits2Float(0x40eb871f), SkBits2Float(0xc26e2ff8));
+path.lineTo(SkBits2Float(0x40eb871c), SkBits2Float(0xc26e2ff8));
+path.cubicTo(SkBits2Float(0x409d63e0), SkBits2Float(0xc26f6508), SkBits2Float(0x401d76fa), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41331a39), SkBits2Float(0xc2a47bc0));
+path.cubicTo(SkBits2Float(0x41854b40), SkBits2Float(0xc2a2feb5), SkBits2Float(0x41b05576), SkBits2Float(0xc2a06b6c), SkBits2Float(0x41da0834), SkBits2Float(0xc29ccbb1));
+path.lineTo(SkBits2Float(0x419d9d10), SkBits2Float(0xc262b148));
+path.cubicTo(SkBits2Float(0x417ef0c0), SkBits2Float(0xc267ee96), SkBits2Float(0x4140b6cf), SkBits2Float(0xc26ba7c4), SkBits2Float(0x410178c0), SkBits2Float(0xc26dcead));
+path.lineTo(SkBits2Float(0x41331a39), SkBits2Float(0xc2a47bc0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp203(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4087af55), SkBits2Float(0xc2a5ffff), SkBits2Float(0x410795c5), SkBits2Float(0xc2a559a4), SkBits2Float(0x414aa20a), SkBits2Float(0xc2a40e63));
+path.lineTo(SkBits2Float(0x41127b4b), SkBits2Float(0xc26d308f));
+path.cubicTo(SkBits2Float(0x40c406cd), SkBits2Float(0xc26f0f7b), SkBits2Float(0x40442bc2), SkBits2Float(0xc26fffff), SkBits2Float(0x36b5ff52), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x414aa206), SkBits2Float(0xc2a40e63));
+path.cubicTo(SkBits2Float(0x4151559c), SkBits2Float(0xc2a3ed46), SkBits2Float(0x41580726), SkBits2Float(0xc2a3ca86), SkBits2Float(0x415eb67b), SkBits2Float(0xc2a3a622));
+path.lineTo(SkBits2Float(0x4120ff4d), SkBits2Float(0xc26c99d6));
+path.cubicTo(SkBits2Float(0x411c2a2f), SkBits2Float(0xc26cce74), SkBits2Float(0x41175378), SkBits2Float(0xc26d00b1), SkBits2Float(0x41127b46), SkBits2Float(0xc26d308f));
+path.lineTo(SkBits2Float(0x414aa206), SkBits2Float(0xc2a40e63));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp204(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36b5ff52), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4087af52), SkBits2Float(0xc2a60000), SkBits2Float(0x410795c2), SkBits2Float(0xc2a559a4), SkBits2Float(0x414aa206), SkBits2Float(0xc2a40e63));
+path.lineTo(SkBits2Float(0x414aa20a), SkBits2Float(0xc2a40e63));
+path.cubicTo(SkBits2Float(0x4151559f), SkBits2Float(0xc2a3ed46), SkBits2Float(0x41580727), SkBits2Float(0xc2a3ca86), SkBits2Float(0x415eb67b), SkBits2Float(0xc2a3a622));
+path.lineTo(SkBits2Float(0x4120ff4d), SkBits2Float(0xc26c99d6));
+path.cubicTo(SkBits2Float(0x411c2a31), SkBits2Float(0xc26cce74), SkBits2Float(0x4117537b), SkBits2Float(0xc26d00b1), SkBits2Float(0x41127b4b), SkBits2Float(0xc26d308f));
+path.lineTo(SkBits2Float(0x41127b46), SkBits2Float(0xc26d308f));
+path.cubicTo(SkBits2Float(0x40c406c6), SkBits2Float(0xc26f0f7b), SkBits2Float(0x40442bbb), SkBits2Float(0xc26fffff), SkBits2Float(0x36b5ff52), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x415eb680), SkBits2Float(0xc2a3a623));
+path.cubicTo(SkBits2Float(0x41a59721), SkBits2Float(0xc2a157ad), SkBits2Float(0x41da77ab), SkBits2Float(0xc29d5c25), SkBits2Float(0x420662d7), SkBits2Float(0xc297cafd));
+path.lineTo(SkBits2Float(0x41c24b0d), SkBits2Float(0xc25b75ac));
+path.cubicTo(SkBits2Float(0x419deda5), SkBits2Float(0xc2638226), SkBits2Float(0x416f6860), SkBits2Float(0xc269442a), SkBits2Float(0x4120ff4a), SkBits2Float(0xc26c99d9));
+path.lineTo(SkBits2Float(0x415eb680), SkBits2Float(0xc2a3a623));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp205(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40a2e582), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4122b94f), SkBits2Float(0xc2a51039), SkBits2Float(0x4172cca0), SkBits2Float(0xc2a333b4));
+path.lineTo(SkBits2Float(0x412f847d), SkBits2Float(0xc26bf464));
+path.cubicTo(SkBits2Float(0x40eb4376), SkBits2Float(0xc26ea556), SkBits2Float(0x406b836d), SkBits2Float(0xc2700000), SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4172cc9b), SkBits2Float(0xc2a333b4));
+path.cubicTo(SkBits2Float(0x417acd1a), SkBits2Float(0xc2a30415), SkBits2Float(0x41816508), SkBits2Float(0xc2a2d21d), SkBits2Float(0x4185619b), SkBits2Float(0xc2a29dcb));
+path.lineTo(SkBits2Float(0x4140d724), SkBits2Float(0xc26b1ba8));
+path.cubicTo(SkBits2Float(0x413b139d), SkBits2Float(0xc26b674c), SkBits2Float(0x41354d54), SkBits2Float(0xc26baf8b), SkBits2Float(0x412f847c), SkBits2Float(0xc26bf463));
+path.lineTo(SkBits2Float(0x4172cc9b), SkBits2Float(0xc2a333b4));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp206(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40a2e57f), SkBits2Float(0xc2a60000), SkBits2Float(0x4122b94c), SkBits2Float(0xc2a51039), SkBits2Float(0x4172cc9b), SkBits2Float(0xc2a333b4));
+path.lineTo(SkBits2Float(0x4172cca0), SkBits2Float(0xc2a333b4));
+path.cubicTo(SkBits2Float(0x417acd1d), SkBits2Float(0xc2a30415), SkBits2Float(0x41816509), SkBits2Float(0xc2a2d21d), SkBits2Float(0x4185619b), SkBits2Float(0xc2a29dcb));
+path.lineTo(SkBits2Float(0x4140d724), SkBits2Float(0xc26b1ba8));
+path.cubicTo(SkBits2Float(0x413b139d), SkBits2Float(0xc26b674c), SkBits2Float(0x41354d54), SkBits2Float(0xc26baf8b), SkBits2Float(0x412f847c), SkBits2Float(0xc26bf463));
+path.lineTo(SkBits2Float(0x412f847d), SkBits2Float(0xc26bf464));
+path.cubicTo(SkBits2Float(0x40eb4376), SkBits2Float(0xc26ea556), SkBits2Float(0x406b836d), SkBits2Float(0xc2700000), SkBits2Float(0x36b5ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4185619b), SkBits2Float(0xc2a29dcc));
+path.cubicTo(SkBits2Float(0x41c61a92), SkBits2Float(0xc29f4c69), SkBits2Float(0x42023dd6), SkBits2Float(0xc299958f), SkBits2Float(0x421f3a98), SkBits2Float(0xc291a994));
+path.lineTo(SkBits2Float(0x41e635e1), SkBits2Float(0xc25298a5));
+path.cubicTo(SkBits2Float(0x41bc4d11), SkBits2Float(0xc25e0caa), SkBits2Float(0x418f3524), SkBits2Float(0xc2664fa2), SkBits2Float(0x4140d729), SkBits2Float(0xc26b1ba9));
+path.lineTo(SkBits2Float(0x4185619b), SkBits2Float(0xc2a29dcc));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp207(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40c39389), SkBits2Float(0xc2a60000), SkBits2Float(0x414346f4), SkBits2Float(0xc2a4a65f), SkBits2Float(0x419158cf), SkBits2Float(0xc2a1f965));
+path.lineTo(SkBits2Float(0x415223e0), SkBits2Float(0xc26a2df8));
+path.cubicTo(SkBits2Float(0x410d2a0c), SkBits2Float(0xc26e0c4b), SkBits2Float(0x408d616c), SkBits2Float(0xc2700000), SkBits2Float(0x35bbfd46), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x419158d0), SkBits2Float(0xc2a1f965));
+path.cubicTo(SkBits2Float(0x41961cea), SkBits2Float(0xc2a1b4f6), SkBits2Float(0x419addf6), SkBits2Float(0xc2a16d2c), SkBits2Float(0x419f9bbb), SkBits2Float(0xc2a12207));
+path.lineTo(SkBits2Float(0x4166c251), SkBits2Float(0xc268f69a));
+path.cubicTo(SkBits2Float(0x415fe778), SkBits2Float(0xc269633e), SkBits2Float(0x415907e2), SkBits2Float(0xc269cb09), SkBits2Float(0x415223e0), SkBits2Float(0xc26a2df8));
+path.lineTo(SkBits2Float(0x419158d0), SkBits2Float(0xc2a1f965));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp208(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40c39389), SkBits2Float(0xc2a60000), SkBits2Float(0x414346f4), SkBits2Float(0xc2a4a65f), SkBits2Float(0x419158d0), SkBits2Float(0xc2a1f965));
+path.cubicTo(SkBits2Float(0x41961cea), SkBits2Float(0xc2a1b4f6), SkBits2Float(0x419addf6), SkBits2Float(0xc2a16d2c), SkBits2Float(0x419f9bbb), SkBits2Float(0xc2a12207));
+path.lineTo(SkBits2Float(0x4166c251), SkBits2Float(0xc268f69a));
+path.cubicTo(SkBits2Float(0x415fe778), SkBits2Float(0xc269633e), SkBits2Float(0x415907e2), SkBits2Float(0xc269cb09), SkBits2Float(0x415223e0), SkBits2Float(0xc26a2df8));
+path.cubicTo(SkBits2Float(0x410d2a0c), SkBits2Float(0xc26e0c4b), SkBits2Float(0x408d616c), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x419f9bbc), SkBits2Float(0xc2a12208));
+path.cubicTo(SkBits2Float(0x41eca53e), SkBits2Float(0xc29c5d1a), SkBits2Float(0x421ad1be), SkBits2Float(0xc2942e2b), SkBits2Float(0x423b8fe1), SkBits2Float(0xc288f8a3));
+path.lineTo(SkBits2Float(0x42079647), SkBits2Float(0xc24607dc));
+path.cubicTo(SkBits2Float(0x41dfd5cc), SkBits2Float(0xc2563c94), SkBits2Float(0x41ab11aa), SkBits2Float(0xc2621167), SkBits2Float(0x4166c24e), SkBits2Float(0xc268f69b));
+path.lineTo(SkBits2Float(0x419f9bbc), SkBits2Float(0xc2a12208));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp209(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40e86425), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4167e385), SkBits2Float(0xc2a41801), SkBits2Float(0x41ac0ecd), SkBits2Float(0xc2a05484));
+path.lineTo(SkBits2Float(0x4178c21d), SkBits2Float(0xc267cd79));
+path.cubicTo(SkBits2Float(0x4127a168), SkBits2Float(0xc26d3e79), SkBits2Float(0x40a7fe68), SkBits2Float(0xc2700000), SkBits2Float(0x3673fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41ac0ecb), SkBits2Float(0xc2a05485));
+path.cubicTo(SkBits2Float(0x41b1a941), SkBits2Float(0xc29ff44e), SkBits2Float(0x41b73ea0), SkBits2Float(0xc29f8f65), SkBits2Float(0x41bcce84), SkBits2Float(0xc29f25d1));
+path.lineTo(SkBits2Float(0x41887c9d), SkBits2Float(0xc26617d6));
+path.cubicTo(SkBits2Float(0x4184774a), SkBits2Float(0xc266b07c), SkBits2Float(0x41806e06), SkBits2Float(0xc2674260), SkBits2Float(0x4178c21e), SkBits2Float(0xc267cd7a));
+path.lineTo(SkBits2Float(0x41ac0ecb), SkBits2Float(0xc2a05485));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp210(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3673fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x40e86421), SkBits2Float(0xc2a60000), SkBits2Float(0x4167e381), SkBits2Float(0xc2a41801), SkBits2Float(0x41ac0eca), SkBits2Float(0xc2a05484));
+path.lineTo(SkBits2Float(0x41ac0ecd), SkBits2Float(0xc2a05484));
+path.lineTo(SkBits2Float(0x4178c21e), SkBits2Float(0xc267cd7a));
+path.lineTo(SkBits2Float(0x41ac0ecb), SkBits2Float(0xc2a05485));
+path.cubicTo(SkBits2Float(0x41b1a941), SkBits2Float(0xc29ff44e), SkBits2Float(0x41b73ea0), SkBits2Float(0xc29f8f65), SkBits2Float(0x41bcce84), SkBits2Float(0xc29f25d1));
+path.lineTo(SkBits2Float(0x41887c9d), SkBits2Float(0xc26617d6));
+path.cubicTo(SkBits2Float(0x4184774a), SkBits2Float(0xc266b07c), SkBits2Float(0x41806e06), SkBits2Float(0xc2674260), SkBits2Float(0x4178c21d), SkBits2Float(0xc267cd79));
+path.cubicTo(SkBits2Float(0x4127a168), SkBits2Float(0xc26d3e79), SkBits2Float(0x40a7fe68), SkBits2Float(0xc2700000), SkBits2Float(0x3673fea3), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41bcce83), SkBits2Float(0xc29f25d2));
+path.cubicTo(SkBits2Float(0x420ba3b4), SkBits2Float(0xc2987080), SkBits2Float(0x42357f09), SkBits2Float(0xc28cfcb1), SkBits2Float(0x42592f07), SkBits2Float(0xc27b1ba7));
+path.lineTo(SkBits2Float(0x421d0012), SkBits2Float(0xc235861c));
+path.cubicTo(SkBits2Float(0x420333bc), SkBits2Float(0xc24bd636), SkBits2Float(0x41c9e36e), SkBits2Float(0xc25c64f6), SkBits2Float(0x41887c9c), SkBits2Float(0xc26617d7));
+path.lineTo(SkBits2Float(0x41bcce83), SkBits2Float(0xc29f25d2));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp211(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x411e5541), SkBits2Float(0xc2a5ffff), SkBits2Float(0x419db1ee), SkBits2Float(0xc2a275ef), SkBits2Float(0x41e7e0a3), SkBits2Float(0xc29b8c98));
+path.lineTo(SkBits2Float(0x41a79f51), SkBits2Float(0xc260e3f1));
+path.cubicTo(SkBits2Float(0x4163fe32), SkBits2Float(0xc26ae208), SkBits2Float(0x40e4ea54), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41e7e0a8), SkBits2Float(0xc29b8c98));
+path.cubicTo(SkBits2Float(0x41ef46bb), SkBits2Float(0xc29adc20), SkBits2Float(0x41f6a013), SkBits2Float(0xc29a2338), SkBits2Float(0x41fdebc8), SkBits2Float(0xc29961f8));
+path.lineTo(SkBits2Float(0x41b78eb0), SkBits2Float(0xc25dc215));
+path.cubicTo(SkBits2Float(0x41b2488a), SkBits2Float(0xc25ed97a), SkBits2Float(0x41acf889), SkBits2Float(0xc25fe4cd), SkBits2Float(0x41a79f51), SkBits2Float(0xc260e3f1));
+path.lineTo(SkBits2Float(0x41e7e0a8), SkBits2Float(0xc29b8c98));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp212(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea3), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x411e5541), SkBits2Float(0xc2a5ffff), SkBits2Float(0x419db1ee), SkBits2Float(0xc2a275ef), SkBits2Float(0x41e7e0a8), SkBits2Float(0xc29b8c98));
+path.cubicTo(SkBits2Float(0x41ef46bb), SkBits2Float(0xc29adc20), SkBits2Float(0x41f6a013), SkBits2Float(0xc29a2338), SkBits2Float(0x41fdebc8), SkBits2Float(0xc29961f8));
+path.lineTo(SkBits2Float(0x41b78eb0), SkBits2Float(0xc25dc215));
+path.cubicTo(SkBits2Float(0x41b2488a), SkBits2Float(0xc25ed97a), SkBits2Float(0x41acf889), SkBits2Float(0xc25fe4cd), SkBits2Float(0x41a79f51), SkBits2Float(0xc260e3f1));
+path.cubicTo(SkBits2Float(0x4163fe32), SkBits2Float(0xc26ae208), SkBits2Float(0x40e4ea54), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea3), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x41fdebc9), SkBits2Float(0xc29961f9));
+path.cubicTo(SkBits2Float(0x423a7ccd), SkBits2Float(0xc28d1085), SkBits2Float(0x426d8f8d), SkBits2Float(0xc270b4b0), SkBits2Float(0x4288fa0c), SkBits2Float(0xc23b8bbf));
+path.lineTo(SkBits2Float(0x424609e8), SkBits2Float(0xc207934a));
+path.cubicTo(SkBits2Float(0x422bbb0d), SkBits2Float(0xc22e0114), SkBits2Float(0x4206cf6b), SkBits2Float(0xc24bf2e1), SkBits2Float(0x41b78eaf), SkBits2Float(0xc25dc216));
+path.lineTo(SkBits2Float(0x41fdebc9), SkBits2Float(0xc29961f9));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp213(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4151cd59), SkBits2Float(0xc2a5ffff), SkBits2Float(0x41d04f3f), SkBits2Float(0xc29fc954), SkBits2Float(0x4216e058), SkBits2Float(0xc293de54));
+path.lineTo(SkBits2Float(0x41da226b), SkBits2Float(0xc255c926));
+path.cubicTo(SkBits2Float(0x419695d1), SkBits2Float(0xc267043d), SkBits2Float(0x4117aa0a), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4216e057), SkBits2Float(0xc293de54));
+path.cubicTo(SkBits2Float(0x421b86ea), SkBits2Float(0xc292aea0), SkBits2Float(0x42201eff), SkBits2Float(0xc29170ed), SkBits2Float(0x4224a79b), SkBits2Float(0xc290257e));
+path.lineTo(SkBits2Float(0x41ee0e15), SkBits2Float(0xc2506790));
+path.cubicTo(SkBits2Float(0x41e78019), SkBits2Float(0xc25246bf), SkBits2Float(0x41e0dbbc), SkBits2Float(0xc2541212), SkBits2Float(0x41da226b), SkBits2Float(0xc255c927));
+path.lineTo(SkBits2Float(0x4216e057), SkBits2Float(0xc293de54));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp214(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4151cd58), SkBits2Float(0xc2a60000), SkBits2Float(0x41d04f3d), SkBits2Float(0xc29fc954), SkBits2Float(0x4216e057), SkBits2Float(0xc293de54));
+path.lineTo(SkBits2Float(0x4216e058), SkBits2Float(0xc293de54));
+path.cubicTo(SkBits2Float(0x421b86eb), SkBits2Float(0xc292aea0), SkBits2Float(0x42201eff), SkBits2Float(0xc29170ed), SkBits2Float(0x4224a79b), SkBits2Float(0xc290257e));
+path.lineTo(SkBits2Float(0x41ee0e15), SkBits2Float(0xc2506790));
+path.cubicTo(SkBits2Float(0x41e78019), SkBits2Float(0xc25246bf), SkBits2Float(0x41e0dbbc), SkBits2Float(0xc2541212), SkBits2Float(0x41da226b), SkBits2Float(0xc255c927));
+path.lineTo(SkBits2Float(0x41da226b), SkBits2Float(0xc255c926));
+path.cubicTo(SkBits2Float(0x419695d1), SkBits2Float(0xc267043d), SkBits2Float(0x4117aa0a), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4224a79b), SkBits2Float(0xc290257f));
+path.cubicTo(SkBits2Float(0x426f06c3), SkBits2Float(0xc275d105), SkBits2Float(0x42930d85), SkBits2Float(0xc2303df6), SkBits2Float(0x429f3103), SkBits2Float(0xc1bc373f));
+path.lineTo(SkBits2Float(0x42662806), SkBits2Float(0xc1880f44));
+path.cubicTo(SkBits2Float(0x42549b44), SkBits2Float(0xc1fececc), SkBits2Float(0x422cca4c), SkBits2Float(0xc231b2de), SkBits2Float(0x41ee0e18), SkBits2Float(0xc2506792));
+path.lineTo(SkBits2Float(0x4224a79b), SkBits2Float(0xc290257f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp215(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41741cf0), SkBits2Float(0xc2a60000), SkBits2Float(0x41f1c060), SkBits2Float(0xc29d96da), SkBits2Float(0x422cf7a2), SkBits2Float(0xc28db11c));
+path.lineTo(SkBits2Float(0x41fa12be), SkBits2Float(0xc24cdb0d));
+path.cubicTo(SkBits2Float(0x41aec295), SkBits2Float(0xc263d704), SkBits2Float(0x413077a0), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x422cf7a1), SkBits2Float(0xc28db11c));
+path.cubicTo(SkBits2Float(0x423224e7), SkBits2Float(0xc28c1ca8), SkBits2Float(0x42373bc3), SkBits2Float(0xc28a7620), SkBits2Float(0x423c3abd), SkBits2Float(0xc288bdfd));
+path.lineTo(SkBits2Float(0x420811ca), SkBits2Float(0xc245b313));
+path.cubicTo(SkBits2Float(0x4204753a), SkBits2Float(0xc2482f6b), SkBits2Float(0x4200c767), SkBits2Float(0xc24a924f), SkBits2Float(0x41fa12c1), SkBits2Float(0xc24cdb0e));
+path.lineTo(SkBits2Float(0x422cf7a1), SkBits2Float(0xc28db11c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp216(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41741cef), SkBits2Float(0xc2a60000), SkBits2Float(0x41f1c05e), SkBits2Float(0xc29d96da), SkBits2Float(0x422cf7a1), SkBits2Float(0xc28db11c));
+path.lineTo(SkBits2Float(0x422cf7a2), SkBits2Float(0xc28db11c));
+path.cubicTo(SkBits2Float(0x423224e8), SkBits2Float(0xc28c1ca8), SkBits2Float(0x42373bc3), SkBits2Float(0xc28a7620), SkBits2Float(0x423c3abd), SkBits2Float(0xc288bdfd));
+path.lineTo(SkBits2Float(0x420811ca), SkBits2Float(0xc245b313));
+path.cubicTo(SkBits2Float(0x4204753a), SkBits2Float(0xc2482f6b), SkBits2Float(0x4200c767), SkBits2Float(0xc24a924f), SkBits2Float(0x41fa12c1), SkBits2Float(0xc24cdb0e));
+path.lineTo(SkBits2Float(0x41fa12be), SkBits2Float(0xc24cdb0d));
+path.cubicTo(SkBits2Float(0x41aec295), SkBits2Float(0xc263d704), SkBits2Float(0x413077a0), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423c3abe), SkBits2Float(0xc288bdfe));
+path.cubicTo(SkBits2Float(0x42874551), SkBits2Float(0xc258d4f5), SkBits2Float(0x42a17ace), SkBits2Float(0xc1fc3ce7), SkBits2Float(0x42a57844), SkBits2Float(0xc0d41d22));
+path.lineTo(SkBits2Float(0x426f3bc1), SkBits2Float(0xc09955d3));
+path.cubicTo(SkBits2Float(0x426976f3), SkBits2Float(0xc1b65735), SkBits2Float(0x4243927c), SkBits2Float(0xc21cbef5), SkBits2Float(0x420811ca), SkBits2Float(0xc245b314));
+path.lineTo(SkBits2Float(0x423c3abe), SkBits2Float(0xc288bdfe));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp217(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4188e880), SkBits2Float(0xc2a60000), SkBits2Float(0x42073c1a), SkBits2Float(0xc29b6b86), SkBits2Float(0x423f3295), SkBits2Float(0xc287b573));
+path.lineTo(SkBits2Float(0x420a3712), SkBits2Float(0xc2443499));
+path.cubicTo(SkBits2Float(0x41c3852b), SkBits2Float(0xc260b421), SkBits2Float(0x4145f08c), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423f3294), SkBits2Float(0xc287b572));
+path.cubicTo(SkBits2Float(0x4244c015), SkBits2Float(0xc285c0c3), SkBits2Float(0x424a2e84), SkBits2Float(0xc283b664), SkBits2Float(0x424f7bec), SkBits2Float(0xc281970f));
+path.lineTo(SkBits2Float(0x4215fd0e), SkBits2Float(0xc23b5bf1));
+path.cubicTo(SkBits2Float(0x421227cb), SkBits2Float(0xc23e6d7a), SkBits2Float(0x420e3aa9), SkBits2Float(0xc24160b8), SkBits2Float(0x420a3713), SkBits2Float(0xc2443498));
+path.lineTo(SkBits2Float(0x423f3294), SkBits2Float(0xc287b572));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp218(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4188e880), SkBits2Float(0xc2a60000), SkBits2Float(0x42073c1a), SkBits2Float(0xc29b6b86), SkBits2Float(0x423f3295), SkBits2Float(0xc287b573));
+path.lineTo(SkBits2Float(0x424f7bec), SkBits2Float(0xc281970f));
+path.lineTo(SkBits2Float(0x4215fd0e), SkBits2Float(0xc23b5bf1));
+path.cubicTo(SkBits2Float(0x421227cb), SkBits2Float(0xc23e6d7a), SkBits2Float(0x420e3aa9), SkBits2Float(0xc24160b8), SkBits2Float(0x420a3713), SkBits2Float(0xc2443498));
+path.lineTo(SkBits2Float(0x420a3712), SkBits2Float(0xc2443499));
+path.cubicTo(SkBits2Float(0x41c3852b), SkBits2Float(0xc260b421), SkBits2Float(0x4145f08c), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x424f7bed), SkBits2Float(0xc281970f));
+path.cubicTo(SkBits2Float(0x42939bdb), SkBits2Float(0xc23cf22a), SkBits2Float(0x42aabb70), SkBits2Float(0xc19e30f8), SkBits2Float(0x42a530dd), SkBits2Float(0x4102f5b1));
+path.lineTo(SkBits2Float(0x426ed486), SkBits2Float(0x40bd56e4));
+path.cubicTo(SkBits2Float(0x4276d778), SkBits2Float(0xc164b5d6), SkBits2Float(0x4255690c), SkBits2Float(0xc2089663), SkBits2Float(0x4215fd0d), SkBits2Float(0xc23b5bf2));
+path.lineTo(SkBits2Float(0x424f7bed), SkBits2Float(0xc281970f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp219(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4198fc97), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4216a3e3), SkBits2Float(0xc298caff), SkBits2Float(0x4251e7a7), SkBits2Float(0xc2809c9b));
+path.lineTo(SkBits2Float(0x4217bd0d), SkBits2Float(0xc239f1d8));
+path.cubicTo(SkBits2Float(0x41d9cb04), SkBits2Float(0xc25ce7ce), SkBits2Float(0x415d2f7f), SkBits2Float(0xc26fffff), SkBits2Float(0xb630015b), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4251e7a7), SkBits2Float(0xc2809c9c));
+path.cubicTo(SkBits2Float(0x4257c623), SkBits2Float(0xc27c6f1e), SkBits2Float(0x425d7a38), SkBits2Float(0xc27771f7), SkBits2Float(0x42630157), SkBits2Float(0xc27243fd));
+path.lineTo(SkBits2Float(0x422419a4), SkBits2Float(0xc22f21bb));
+path.cubicTo(SkBits2Float(0x42201aab), SkBits2Float(0xc232e046), SkBits2Float(0x421bfb30), SkBits2Float(0xc2367b84), SkBits2Float(0x4217bd0d), SkBits2Float(0xc239f1d8));
+path.lineTo(SkBits2Float(0x4251e7a7), SkBits2Float(0xc2809c9c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp220(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb630015b), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4198fc97), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4216a3e3), SkBits2Float(0xc298caff), SkBits2Float(0x4251e7a7), SkBits2Float(0xc2809c9c));
+path.cubicTo(SkBits2Float(0x4257c623), SkBits2Float(0xc27c6f1e), SkBits2Float(0x425d7a38), SkBits2Float(0xc27771f7), SkBits2Float(0x42630157), SkBits2Float(0xc27243fd));
+path.lineTo(SkBits2Float(0x422419a4), SkBits2Float(0xc22f21bb));
+path.cubicTo(SkBits2Float(0x42201aab), SkBits2Float(0xc232e046), SkBits2Float(0x421bfb30), SkBits2Float(0xc2367b84), SkBits2Float(0x4217bd0d), SkBits2Float(0xc239f1d8));
+path.cubicTo(SkBits2Float(0x41d9cb04), SkBits2Float(0xc25ce7ce), SkBits2Float(0x415d2f7f), SkBits2Float(0xc26fffff), SkBits2Float(0xb630015b), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42630157), SkBits2Float(0xc27243ff));
+path.cubicTo(SkBits2Float(0x429f78af), SkBits2Float(0xc21c1e80), SkBits2Float(0x42b11918), SkBits2Float(0xc0cad7ee), SkBits2Float(0x429f0274), SkBits2Float(0x41bea8f4));
+path.lineTo(SkBits2Float(0x4265e4b4), SkBits2Float(0x4189d394));
+path.cubicTo(SkBits2Float(0x428005cc), SkBits2Float(0xc092a249), SkBits2Float(0x42668fa3), SkBits2Float(0xc1e1b6e5), SkBits2Float(0x422419a4), SkBits2Float(0xc22f21bb));
+path.lineTo(SkBits2Float(0x42630157), SkBits2Float(0xc27243ff));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp221(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41ae0130), SkBits2Float(0xc2a5ffff), SkBits2Float(0x422a8737), SkBits2Float(0xc294ec91), SkBits2Float(0x42689b67), SkBits2Float(0xc26ce46c));
+path.lineTo(SkBits2Float(0x42282651), SkBits2Float(0xc22b3f58));
+path.cubicTo(SkBits2Float(0x41f68bfb), SkBits2Float(0xc2574fdc), SkBits2Float(0x417b92b3), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42689b68), SkBits2Float(0xc26ce46d));
+path.cubicTo(SkBits2Float(0x426ebcd2), SkBits2Float(0xc266df67), SkBits2Float(0x4274a1d2), SkBits2Float(0xc2609e09), SkBits2Float(0x427a4701), SkBits2Float(0xc25a23f2));
+path.lineTo(SkBits2Float(0x4234ec64), SkBits2Float(0xc21db11e));
+path.cubicTo(SkBits2Float(0x4230d7ae), SkBits2Float(0xc2225fbc), SkBits2Float(0x422c94d6), SkBits2Float(0xc226e55a), SkBits2Float(0x42282652), SkBits2Float(0xc22b3f58));
+path.lineTo(SkBits2Float(0x42689b68), SkBits2Float(0xc26ce46d));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp222(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41ae0130), SkBits2Float(0xc2a5ffff), SkBits2Float(0x422a8737), SkBits2Float(0xc294ec91), SkBits2Float(0x42689b68), SkBits2Float(0xc26ce46d));
+path.cubicTo(SkBits2Float(0x426ebcd2), SkBits2Float(0xc266df67), SkBits2Float(0x4274a1d2), SkBits2Float(0xc2609e09), SkBits2Float(0x427a4701), SkBits2Float(0xc25a23f2));
+path.lineTo(SkBits2Float(0x4234ec64), SkBits2Float(0xc21db11e));
+path.cubicTo(SkBits2Float(0x4230d7ae), SkBits2Float(0xc2225fbc), SkBits2Float(0x422c94d6), SkBits2Float(0xc226e55a), SkBits2Float(0x42282651), SkBits2Float(0xc22b3f58));
+path.cubicTo(SkBits2Float(0x41f68bfb), SkBits2Float(0xc2574fdc), SkBits2Float(0x417b92b3), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x427a4702), SkBits2Float(0xc25a23f2));
+path.cubicTo(SkBits2Float(0x42ac7185), SkBits2Float(0xc1db2f83), SkBits2Float(0x42b35ed0), SkBits2Float(0x413e447a), SkBits2Float(0x428e4a3d), SkBits2Float(0x422afde8));
+path.lineTo(SkBits2Float(0x424db871), SkBits2Float(0x41f73799));
+path.cubicTo(SkBits2Float(0x4281aa54), SkBits2Float(0x41098afa), SkBits2Float(0x427950da), SkBits2Float(0xc19e728d), SkBits2Float(0x4234ec66), SkBits2Float(0xc21db120));
+path.lineTo(SkBits2Float(0x427a4702), SkBits2Float(0xc25a23f2));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp223(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41c50a2c), SkBits2Float(0xc2a60000), SkBits2Float(0x423ff37f), SkBits2Float(0xc2901f4e), SkBits2Float(0x427f077c), SkBits2Float(0xc25490c6));
+path.lineTo(SkBits2Float(0x42385bc5), SkBits2Float(0xc219a96d));
+path.cubicTo(SkBits2Float(0x420ac287), SkBits2Float(0xc2505e9c), SkBits2Float(0x418e7039), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x427f077b), SkBits2Float(0xc25490c6));
+path.cubicTo(SkBits2Float(0x42829e52), SkBits2Float(0xc24d1e28), SkBits2Float(0x42858ec1), SkBits2Float(0xc24566d6), SkBits2Float(0x428852e3), SkBits2Float(0xc23d7081));
+path.lineTo(SkBits2Float(0x42451839), SkBits2Float(0xc208f1b7));
+path.cubicTo(SkBits2Float(0x4241186a), SkBits2Float(0xc20eb335), SkBits2Float(0x423cd88e), SkBits2Float(0xc2144725), SkBits2Float(0x42385bc4), SkBits2Float(0xc219a96c));
+path.lineTo(SkBits2Float(0x427f077b), SkBits2Float(0xc25490c6));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp224(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41c50a2c), SkBits2Float(0xc2a60000), SkBits2Float(0x423ff37f), SkBits2Float(0xc2901f4e), SkBits2Float(0x427f077c), SkBits2Float(0xc25490c6));
+path.lineTo(SkBits2Float(0x428852e3), SkBits2Float(0xc23d7081));
+path.lineTo(SkBits2Float(0x42451839), SkBits2Float(0xc208f1b7));
+path.cubicTo(SkBits2Float(0x4241186a), SkBits2Float(0xc20eb335), SkBits2Float(0x423cd88e), SkBits2Float(0xc2144725), SkBits2Float(0x42385bc4), SkBits2Float(0xc219a96c));
+path.lineTo(SkBits2Float(0x42385bc5), SkBits2Float(0xc219a96d));
+path.cubicTo(SkBits2Float(0x420ac287), SkBits2Float(0xc2505e9c), SkBits2Float(0x418e7039), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x428852e3), SkBits2Float(0xc23d7081));
+path.cubicTo(SkBits2Float(0x42b71f8a), SkBits2Float(0xc15aea65), SkBits2Float(0x42adb77f), SkBits2Float(0x42002593), SkBits2Float(0x42645e8b), SkBits2Float(0x4270faee));
+path.lineTo(SkBits2Float(0x42251616), SkBits2Float(0x422e33d9));
+path.cubicTo(SkBits2Float(0x427b2825), SkBits2Float(0x41b945be), SkBits2Float(0x428460d4), SkBits2Float(0xc11e4099), SkBits2Float(0x4245183a), SkBits2Float(0xc208f1b8));
+path.lineTo(SkBits2Float(0x428852e3), SkBits2Float(0xc23d7081));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp225(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41d8749b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4251a993), SkBits2Float(0xc28b9f9f), SkBits2Float(0x4287e789), SkBits2Float(0xc23ea40d));
+path.lineTo(SkBits2Float(0x42447d05), SkBits2Float(0xc209d00a));
+path.cubicTo(SkBits2Float(0x4217902d), SkBits2Float(0xc249dd89), SkBits2Float(0x419c7951), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4287e78a), SkBits2Float(0xc23ea40e));
+path.cubicTo(SkBits2Float(0x428af3dc), SkBits2Float(0xc235f2f3), SkBits2Float(0x428dca5e), SkBits2Float(0xc22cf844), SkBits2Float(0x4290688d), SkBits2Float(0xc223bbef));
+path.lineTo(SkBits2Float(0x4250c881), SkBits2Float(0xc1ecb95a));
+path.cubicTo(SkBits2Float(0x424cff91), SkBits2Float(0xc1fa13ac), SkBits2Float(0x4248e532), SkBits2Float(0xc2038788), SkBits2Float(0x42447d06), SkBits2Float(0xc209d00a));
+path.lineTo(SkBits2Float(0x4287e78a), SkBits2Float(0xc23ea40e));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp226(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41d8749b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4251a993), SkBits2Float(0xc28b9f9f), SkBits2Float(0x4287e78a), SkBits2Float(0xc23ea40e));
+path.cubicTo(SkBits2Float(0x428af3dc), SkBits2Float(0xc235f2f3), SkBits2Float(0x428dca5e), SkBits2Float(0xc22cf844), SkBits2Float(0x4290688d), SkBits2Float(0xc223bbef));
+path.lineTo(SkBits2Float(0x4250c881), SkBits2Float(0xc1ecb95a));
+path.cubicTo(SkBits2Float(0x424cff91), SkBits2Float(0xc1fa13ac), SkBits2Float(0x4248e532), SkBits2Float(0xc2038788), SkBits2Float(0x42447d05), SkBits2Float(0xc209d00a));
+path.cubicTo(SkBits2Float(0x4217902d), SkBits2Float(0xc249dd89), SkBits2Float(0x419c7951), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4290688d), SkBits2Float(0xc223bbef));
+path.cubicTo(SkBits2Float(0x42bd187d), SkBits2Float(0xbfc2a74a), SkBits2Float(0x42a250ed), SkBits2Float(0x42421cbf), SkBits2Float(0x42287a28), SkBits2Float(0x428f09b7));
+path.lineTo(SkBits2Float(0x41f394da), SkBits2Float(0x424ecd48));
+path.cubicTo(SkBits2Float(0x426aac8a), SkBits2Float(0x420c527b), SkBits2Float(0x4288b219), SkBits2Float(0xbf8cb68f), SkBits2Float(0x4250c882), SkBits2Float(0xc1ecb95c));
+path.lineTo(SkBits2Float(0x4290688d), SkBits2Float(0xc223bbef));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp227(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f1efaa), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42685cb5), SkBits2Float(0xc2851a3e), SkBits2Float(0x429160d2), SkBits2Float(0xc22043b6));
+path.lineTo(SkBits2Float(0x42522f73), SkBits2Float(0xc1e7b52d));
+path.cubicTo(SkBits2Float(0x4227f8ff), SkBits2Float(0xc2406ff8), SkBits2Float(0x41aee4c7), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429160d2), SkBits2Float(0xc22043b7));
+path.cubicTo(SkBits2Float(0x42943aa0), SkBits2Float(0xc215eba6), SkBits2Float(0x4296cd42), SkBits2Float(0xc20b4794), SkBits2Float(0x429915e6), SkBits2Float(0xc200631e));
+path.lineTo(SkBits2Float(0x425d5418), SkBits2Float(0xc1b99eb9));
+path.cubicTo(SkBits2Float(0x425a06d4), SkBits2Float(0xc1c95e3a), SkBits2Float(0x42564e98), SkBits2Float(0xc1d8c0a6), SkBits2Float(0x42522f74), SkBits2Float(0xc1e7b52e));
+path.lineTo(SkBits2Float(0x429160d2), SkBits2Float(0xc22043b7));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp228(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f1efa9), SkBits2Float(0xc2a60000), SkBits2Float(0x42685cb5), SkBits2Float(0xc2851a3e), SkBits2Float(0x429160d2), SkBits2Float(0xc22043b7));
+path.lineTo(SkBits2Float(0x429160d2), SkBits2Float(0xc22043b6));
+path.cubicTo(SkBits2Float(0x42943aa0), SkBits2Float(0xc215eba5), SkBits2Float(0x4296cd42), SkBits2Float(0xc20b4794), SkBits2Float(0x429915e6), SkBits2Float(0xc200631e));
+path.lineTo(SkBits2Float(0x425d5418), SkBits2Float(0xc1b99eb9));
+path.cubicTo(SkBits2Float(0x425a06d4), SkBits2Float(0xc1c95e3a), SkBits2Float(0x42564e98), SkBits2Float(0xc1d8c0a6), SkBits2Float(0x42522f74), SkBits2Float(0xc1e7b52e));
+path.lineTo(SkBits2Float(0x42522f73), SkBits2Float(0xc1e7b52d));
+path.cubicTo(SkBits2Float(0x4227f8ff), SkBits2Float(0xc2406ff8), SkBits2Float(0x41aee4c7), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429915e6), SkBits2Float(0xc200631e));
+path.cubicTo(SkBits2Float(0x42abe101), SkBits2Float(0xc11b0235), SkBits2Float(0x42aa16bb), SkBits2Float(0x417b685c), SkBits2Float(0x42942fff), SkBits2Float(0x42159e77));
+path.cubicTo(SkBits2Float(0x427c9284), SkBits2Float(0x426c62d8), SkBits2Float(0x422cf27d), SkBits2Float(0x4295ccdb), SkBits2Float(0x419d039e), SkBits2Float(0x42a14aca));
+path.lineTo(SkBits2Float(0x4163022c), SkBits2Float(0x42693188));
+path.cubicTo(SkBits2Float(0x41fa0b56), SkBits2Float(0x42589424), SkBits2Float(0x4236951c), SkBits2Float(0x422ae1ad), SkBits2Float(0x42563f3c), SkBits2Float(0x41d85112));
+path.cubicTo(SkBits2Float(0x4275e95c), SkBits2Float(0x4135bd94), SkBits2Float(0x42787fea), SkBits2Float(0xc0e01be1), SkBits2Float(0x425d5419), SkBits2Float(0xc1b99eba));
+path.lineTo(SkBits2Float(0x429915e6), SkBits2Float(0xc200631e));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp229(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4206c976), SkBits2Float(0xc2a60000), SkBits2Float(0x42801937), SkBits2Float(0xc27a823c), SkBits2Float(0x4299a0d7), SkBits2Float(0xc1fb88d1));
+path.lineTo(SkBits2Float(0x425e1cfa), SkBits2Float(0xc1b5d505));
+path.cubicTo(SkBits2Float(0x423933e1), SkBits2Float(0xc2351735), SkBits2Float(0x41c2df6b), SkBits2Float(0xc2700000), SkBits2Float(0xb560056c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4299a0d8), SkBits2Float(0xc1fb88d0));
+path.cubicTo(SkBits2Float(0x429c1b73), SkBits2Float(0xc1e34f53), SkBits2Float(0x429e39d2), SkBits2Float(0xc1ca8528), SkBits2Float(0x429ff920), SkBits2Float(0xc1b14b8c));
+path.lineTo(SkBits2Float(0x42674955), SkBits2Float(0xc1802a45));
+path.cubicTo(SkBits2Float(0x4264c2a3), SkBits2Float(0xc192666d), SkBits2Float(0x4261b27b), SkBits2Float(0xc1a45204), SkBits2Float(0x425e1cfb), SkBits2Float(0xc1b5d506));
+path.lineTo(SkBits2Float(0x4299a0d8), SkBits2Float(0xc1fb88d0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp230(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4206c976), SkBits2Float(0xc2a60000), SkBits2Float(0x42801937), SkBits2Float(0xc27a823c), SkBits2Float(0x4299a0d8), SkBits2Float(0xc1fb88d0));
+path.cubicTo(SkBits2Float(0x429c1b73), SkBits2Float(0xc1e34f53), SkBits2Float(0x429e39d2), SkBits2Float(0xc1ca8528), SkBits2Float(0x429ff920), SkBits2Float(0xc1b14b8c));
+path.lineTo(SkBits2Float(0x42674955), SkBits2Float(0xc1802a45));
+path.cubicTo(SkBits2Float(0x4264c2a3), SkBits2Float(0xc192666d), SkBits2Float(0x4261b27b), SkBits2Float(0xc1a45204), SkBits2Float(0x425e1cfa), SkBits2Float(0xc1b5d505));
+path.cubicTo(SkBits2Float(0x423933e1), SkBits2Float(0xc2351735), SkBits2Float(0x41c2df6b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429ff91f), SkBits2Float(0xc1b14b8a));
+path.cubicTo(SkBits2Float(0x42ae673b), SkBits2Float(0x40783c41), SkBits2Float(0x42a293c2), SkBits2Float(0x41fe6960), SkBits2Float(0x4280464e), SkBits2Float(0x4252ba7b));
+path.cubicTo(SkBits2Float(0x423bf1b3), SkBits2Float(0x42932023), SkBits2Float(0x41a5f32c), SkBits2Float(0x42a99309), SkBits2Float(0xc0c67989), SkBits2Float(0x42a5892f));
+path.lineTo(SkBits2Float(0xc08f79c7), SkBits2Float(0x426f5437));
+path.cubicTo(SkBits2Float(0x416fed74), SkBits2Float(0x42752af2), SkBits2Float(0x4207dcfc), SkBits2Float(0x4254b62d), SkBits2Float(0x42397512), SkBits2Float(0x42185575));
+path.cubicTo(SkBits2Float(0x426b0d26), SkBits2Float(0x41b7e97d), SkBits2Float(0x427c2639), SkBits2Float(0x40337286), SkBits2Float(0x42674956), SkBits2Float(0xc1802a46));
+path.lineTo(SkBits2Float(0x429ff91f), SkBits2Float(0xc1b14b8a));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp231(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x421472e7), SkBits2Float(0xc2a5ffff), SkBits2Float(0x428b6da4), SkBits2Float(0xc26973d7), SkBits2Float(0x429fb179), SkBits2Float(0xc1b54986));
+path.lineTo(SkBits2Float(0x4266e1be), SkBits2Float(0xc1830d0f));
+path.cubicTo(SkBits2Float(0x42499544), SkBits2Float(0xc228c2c8), SkBits2Float(0x41d69ff6), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429fb179), SkBits2Float(0xc1b54988));
+path.cubicTo(SkBits2Float(0x42a1a632), SkBits2Float(0xc199b837), SkBits2Float(0x42a3282f), SkBits2Float(0xc17b594e), SkBits2Float(0x42a43501), SkBits2Float(0xc142a7ba));
+path.lineTo(SkBits2Float(0x426d6865), SkBits2Float(0xc10cb6f0));
+path.cubicTo(SkBits2Float(0x426be3bc), SkBits2Float(0xc135b2ae), SkBits2Float(0x4269b5af), SkBits2Float(0xc15e3ec8), SkBits2Float(0x4266e1be), SkBits2Float(0xc1830d0f));
+path.lineTo(SkBits2Float(0x429fb179), SkBits2Float(0xc1b54988));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp232(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x421472e7), SkBits2Float(0xc2a60000), SkBits2Float(0x428b6da4), SkBits2Float(0xc26973d8), SkBits2Float(0x429fb179), SkBits2Float(0xc1b54988));
+path.lineTo(SkBits2Float(0x429fb179), SkBits2Float(0xc1b54986));
+path.cubicTo(SkBits2Float(0x42a1a632), SkBits2Float(0xc199b836), SkBits2Float(0x42a3282f), SkBits2Float(0xc17b594d), SkBits2Float(0x42a43501), SkBits2Float(0xc142a7ba));
+path.lineTo(SkBits2Float(0x426d6865), SkBits2Float(0xc10cb6f0));
+path.cubicTo(SkBits2Float(0x426be3bc), SkBits2Float(0xc135b2ae), SkBits2Float(0x4269b5af), SkBits2Float(0xc15e3ec8), SkBits2Float(0x4266e1be), SkBits2Float(0xc1830d0f));
+path.cubicTo(SkBits2Float(0x42499544), SkBits2Float(0xc228c2c8), SkBits2Float(0x41d69ff6), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a43502), SkBits2Float(0xc142a7bb));
+path.cubicTo(SkBits2Float(0x42ace9b0), SkBits2Float(0x4189ae79), SkBits2Float(0x429590d6), SkBits2Float(0x423ab1c1), SkBits2Float(0x424df762), SkBits2Float(0x428231a6));
+path.cubicTo(SkBits2Float(0x41e19a31), SkBits2Float(0x42a70a69), SkBits2Float(0xc04a3289), SkBits2Float(0x42b03133), SkBits2Float(0xc1f5f36e), SkBits2Float(0x429a3139));
+path.lineTo(SkBits2Float(0xc1b1cbb9), SkBits2Float(0x425eedb9));
+path.cubicTo(SkBits2Float(0xc0122aac), SkBits2Float(0x427ebc5a), SkBits2Float(0x41a31606), SkBits2Float(0x42718130), SkBits2Float(0x4214e430), SkBits2Float(0x423c3b73));
+path.cubicTo(SkBits2Float(0x42583d5c), SkBits2Float(0x4206f5b6), SkBits2Float(0x4279fe97), SkBits2Float(0x41470ec8), SkBits2Float(0x426d6866), SkBits2Float(0xc10cb6eb));
+path.lineTo(SkBits2Float(0x42a43502), SkBits2Float(0xc142a7bb));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp233(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4220aa02), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42952310), SkBits2Float(0xc258f48d), SkBits2Float(0x42a35f68), SkBits2Float(0xc16b5614));
+path.lineTo(SkBits2Float(0x426c3395), SkBits2Float(0xc12a1f61));
+path.cubicTo(SkBits2Float(0x42579ea8), SkBits2Float(0xc21cd5ce), SkBits2Float(0x41e84916), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a35f69), SkBits2Float(0xc16b5613));
+path.cubicTo(SkBits2Float(0x42a4bd24), SkBits2Float(0xc12ea3c2), SkBits2Float(0x42a59325), SkBits2Float(0xc0e282d6), SkBits2Float(0x42a5dfdf), SkBits2Float(0xc04e84a0));
+path.lineTo(SkBits2Float(0x426fd18d), SkBits2Float(0xc0154a48));
+path.cubicTo(SkBits2Float(0x426f62a1), SkBits2Float(0xc0a3be33), SkBits2Float(0x426e2d39), SkBits2Float(0xc0fc7dbb), SkBits2Float(0x426c3397), SkBits2Float(0xc12a1f63));
+path.lineTo(SkBits2Float(0x42a35f69), SkBits2Float(0xc16b5613));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp234(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4220aa02), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42952310), SkBits2Float(0xc258f48d), SkBits2Float(0x42a35f69), SkBits2Float(0xc16b5613));
+path.cubicTo(SkBits2Float(0x42a4bd24), SkBits2Float(0xc12ea3c2), SkBits2Float(0x42a59325), SkBits2Float(0xc0e282d6), SkBits2Float(0x42a5dfdf), SkBits2Float(0xc04e84a0));
+path.lineTo(SkBits2Float(0x426fd18d), SkBits2Float(0xc0154a48));
+path.cubicTo(SkBits2Float(0x426f62a1), SkBits2Float(0xc0a3be33), SkBits2Float(0x426e2d39), SkBits2Float(0xc0fc7dbb), SkBits2Float(0x426c3397), SkBits2Float(0xc12a1f63));
+path.lineTo(SkBits2Float(0x426c3395), SkBits2Float(0xc12a1f61));
+path.cubicTo(SkBits2Float(0x42579ea8), SkBits2Float(0xc21cd5ce), SkBits2Float(0x41e84916), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a5dfdf), SkBits2Float(0xc04e84a0));
+path.cubicTo(SkBits2Float(0x42a85e4f), SkBits2Float(0x41e6959e), SkBits2Float(0x4285b4e3), SkBits2Float(0x426ae44f), SkBits2Float(0x4219b105), SkBits2Float(0x42932450));
+path.cubicTo(SkBits2Float(0x411fe111), SkBits2Float(0x42b0d679), SkBits2Float(0xc1c3966b), SkBits2Float(0x42ab1d42), SkBits2Float(0xc2482755), SkBits2Float(0x428470e8));
+path.lineTo(SkBits2Float(0xc210b07c), SkBits2Float(0x423f7b24));
+path.cubicTo(SkBits2Float(0xc18d6382), SkBits2Float(0x427764e8), SkBits2Float(0x40e72680), SkBits2Float(0x427fab4e), SkBits2Float(0x41de345e), SkBits2Float(0x4254bc3b));
+path.cubicTo(SkBits2Float(0x42414f8e), SkBits2Float(0x4229cd28), SkBits2Float(0x42736c9d), SkBits2Float(0x41a6b008), SkBits2Float(0x426fd18e), SkBits2Float(0xc0154a3f));
+path.lineTo(SkBits2Float(0x42a5dfdf), SkBits2Float(0xc04e84a0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp235(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x422e5e2d), SkBits2Float(0xc2a5ffff), SkBits2Float(0x429f82f2), SkBits2Float(0xc2451c35), SkBits2Float(0x42a59867), SkBits2Float(0xc0b956c5));
+path.lineTo(SkBits2Float(0x426f6a3b), SkBits2Float(0xc085fae3));
+path.cubicTo(SkBits2Float(0x42669e7e), SkBits2Float(0xc20e7d42), SkBits2Float(0x41fc1920), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a59868), SkBits2Float(0xc0b956ca));
+path.cubicTo(SkBits2Float(0x42a62cd8), SkBits2Float(0xbfd2dd07), SkBits2Float(0x42a621be), SkBits2Float(0x4020d557), SkBits2Float(0x42a57734), SkBits2Float(0x40d4ef9c));
+path.lineTo(SkBits2Float(0x426f3a3b), SkBits2Float(0x4099edfc));
+path.cubicTo(SkBits2Float(0x427030cb), SkBits2Float(0x3fe887ba), SkBits2Float(0x427040d6), SkBits2Float(0xbf986e77), SkBits2Float(0x426f6a3b), SkBits2Float(0xc085fae4));
+path.lineTo(SkBits2Float(0x42a59868), SkBits2Float(0xc0b956ca));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp236(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x422e5e2d), SkBits2Float(0xc2a5ffff), SkBits2Float(0x429f82f2), SkBits2Float(0xc2451c35), SkBits2Float(0x42a59868), SkBits2Float(0xc0b956ca));
+path.cubicTo(SkBits2Float(0x42a62cd8), SkBits2Float(0xbfd2dd07), SkBits2Float(0x42a621be), SkBits2Float(0x4020d557), SkBits2Float(0x42a57734), SkBits2Float(0x40d4ef9c));
+path.lineTo(SkBits2Float(0x426f3a3b), SkBits2Float(0x4099edfc));
+path.cubicTo(SkBits2Float(0x427030cb), SkBits2Float(0x3fe887bb), SkBits2Float(0x427040d6), SkBits2Float(0xbf986e74), SkBits2Float(0x426f6a3b), SkBits2Float(0xc085fae3));
+path.lineTo(SkBits2Float(0x426f6a3b), SkBits2Float(0xc085fae4));
+path.cubicTo(SkBits2Float(0x42669e7e), SkBits2Float(0xc20e7d42), SkBits2Float(0x41fc1920), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a57735), SkBits2Float(0x40d4ef9d));
+path.cubicTo(SkBits2Float(0x429fe5e1), SkBits2Float(0x4225104d), SkBits2Float(0x425fa7d9), SkBits2Float(0x428cf91a), SkBits2Float(0x41b3ea58), SkBits2Float(0x429fca49));
+path.cubicTo(SkBits2Float(0xc12ef606), SkBits2Float(0x42b29b77), SkBits2Float(0xc23abc07), SkBits2Float(0x4299d29d), SkBits2Float(0xc2863a28), SkBits2Float(0x42435615));
+path.lineTo(SkBits2Float(0xc242103b), SkBits2Float(0x420d34fa));
+path.cubicTo(SkBits2Float(0xc206fd22), SkBits2Float(0x425e64f1), SkBits2Float(0xc0fcf4a4), SkBits2Float(0x42811d1e), SkBits2Float(0x41820f34), SkBits2Float(0x426705a2));
+path.cubicTo(SkBits2Float(0x4221adc8), SkBits2Float(0x424bd107), SkBits2Float(0x42672d88), SkBits2Float(0x41eea576), SkBits2Float(0x426f3a3c), SkBits2Float(0x4099edfe));
+path.lineTo(SkBits2Float(0x42a57735), SkBits2Float(0x40d4ef9d));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp237(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41b25a1b), SkBits2Float(0xc2a60000), SkBits2Float(0x422e9a51), SkBits2Float(0xc294100b), SkBits2Float(0x426d0a79), SkBits2Float(0xc26874a1));
+path.cubicTo(SkBits2Float(0x4295bd51), SkBits2Float(0xc228c92e), SkBits2Float(0x42a6d6d5), SkBits2Float(0xc1a5596e), SkBits2Float(0x42a5f7e5), SkBits2Float(0x3fcf7f4c));
+path.lineTo(SkBits2Float(0x426ff448), SkBits2Float(0x3f95ff69));
+path.cubicTo(SkBits2Float(0x4271369b), SkBits2Float(0xc16f0f30), SkBits2Float(0x42587daa), SkBits2Float(0xc1f4071e), SkBits2Float(0x422b5ada), SkBits2Float(0xc2280a4b));
+path.cubicTo(SkBits2Float(0x41fc7014), SkBits2Float(0xc2561107), SkBits2Float(0x4180eddd), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a5f7e5), SkBits2Float(0x3fcf7f2e));
+path.cubicTo(SkBits2Float(0x42a5cbdf), SkBits2Float(0x40c0b7f8), SkBits2Float(0x42a4eca2), SkBits2Float(0x41268f7d), SkBits2Float(0x42a35c4c), SkBits2Float(0x416be04e));
+path.lineTo(SkBits2Float(0x426c2f14), SkBits2Float(0x412a834e));
+path.cubicTo(SkBits2Float(0x426e71e2), SkBits2Float(0x40f0cf74), SkBits2Float(0x426fb4a3), SkBits2Float(0x408b5090), SkBits2Float(0x426ff449), SkBits2Float(0x3f95ff6b));
+path.lineTo(SkBits2Float(0x42a5f7e5), SkBits2Float(0x3fcf7f2e));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp238(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41b25a1b), SkBits2Float(0xc2a60000), SkBits2Float(0x422e9a51), SkBits2Float(0xc294100b), SkBits2Float(0x426d0a79), SkBits2Float(0xc26874a1));
+path.cubicTo(SkBits2Float(0x4295bd51), SkBits2Float(0xc228c92e), SkBits2Float(0x42a6d6d5), SkBits2Float(0xc1a5596f), SkBits2Float(0x42a5f7e5), SkBits2Float(0x3fcf7f2e));
+path.lineTo(SkBits2Float(0x426c2f14), SkBits2Float(0x412a834e));
+path.cubicTo(SkBits2Float(0x426e71e2), SkBits2Float(0x40f0cf74), SkBits2Float(0x426fb4a3), SkBits2Float(0x408b5090), SkBits2Float(0x426ff449), SkBits2Float(0x3f95ff6b));
+path.lineTo(SkBits2Float(0x426ff448), SkBits2Float(0x3f95ff69));
+path.cubicTo(SkBits2Float(0x4271369b), SkBits2Float(0xc16f0f30), SkBits2Float(0x42587daa), SkBits2Float(0xc1f4071e), SkBits2Float(0x422b5ada), SkBits2Float(0xc2280a4b));
+path.cubicTo(SkBits2Float(0x41fc7014), SkBits2Float(0xc2561107), SkBits2Float(0x4180eddd), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a35c4c), SkBits2Float(0x416be04e));
+path.cubicTo(SkBits2Float(0x42963d3f), SkBits2Float(0x424c5e0d), SkBits2Float(0x42354f77), SkBits2Float(0x429d76d6), SkBits2Float(0x41096c90), SkBits2Float(0x42a51bdb));
+path.cubicTo(SkBits2Float(0xc1e1325f), SkBits2Float(0x42acc0e0), SkBits2Float(0xc27bf938), SkBits2Float(0x4282ec23), SkBits2Float(0xc299cad8), SkBits2Float(0x41f9ecd8));
+path.lineTo(SkBits2Float(0xc25e59b3), SkBits2Float(0x41b4ab36));
+path.cubicTo(SkBits2Float(0xc2362649), SkBits2Float(0x423d4911), SkBits2Float(0xc1a2caf7), SkBits2Float(0x4279c398), SkBits2Float(0x40c6af7d), SkBits2Float(0x426eb62b));
+path.cubicTo(SkBits2Float(0x4203115b), SkBits2Float(0x4263a8be), SkBits2Float(0x425936a2), SkBits2Float(0x4213bc4a), SkBits2Float(0x426c2f16), SkBits2Float(0x412a8350));
+path.lineTo(SkBits2Float(0x42a35c4c), SkBits2Float(0x416be04e));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp239(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41ba3f99), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4235f79d), SkBits2Float(0xc29271cf), SkBits2Float(0x4274db3f), SkBits2Float(0xc260354d));
+path.cubicTo(SkBits2Float(0x4299df70), SkBits2Float(0xc21b86fd), SkBits2Float(0x42a97305), SkBits2Float(0xc17e5d7a), SkBits2Float(0x42a55ba0), SkBits2Float(0x40e961b4));
+path.lineTo(SkBits2Float(0x426f1259), SkBits2Float(0x40a8b5ae));
+path.cubicTo(SkBits2Float(0x4274fca8), SkBits2Float(0xc137e0e1), SkBits2Float(0x425e777b), SkBits2Float(0xc1e0dbdb), SkBits2Float(0x42310131), SkBits2Float(0xc2221408));
+path.cubicTo(SkBits2Float(0x42038ae6), SkBits2Float(0xc253ba22), SkBits2Float(0x4186a32c), SkBits2Float(0xc2700000), SkBits2Float(0xb560056c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a55ba0), SkBits2Float(0x40e961b9));
+path.cubicTo(SkBits2Float(0x42a48d09), SkBits2Float(0x413de0a1), SkBits2Float(0x42a2fc74), SkBits2Float(0x41833376), SkBits2Float(0x42a0adff), SkBits2Float(0x41a6c250));
+path.lineTo(SkBits2Float(0x42684ed9), SkBits2Float(0x417118ef));
+path.cubicTo(SkBits2Float(0x426ba483), SkBits2Float(0x413db02f), SkBits2Float(0x426de7aa), SkBits2Float(0x410942c3), SkBits2Float(0x426f1258), SkBits2Float(0x40a8b5ad));
+path.lineTo(SkBits2Float(0x42a55ba0), SkBits2Float(0x40e961b9));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp240(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41ba3f99), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4235f79d), SkBits2Float(0xc29271cf), SkBits2Float(0x4274db3f), SkBits2Float(0xc260354d));
+path.cubicTo(SkBits2Float(0x4299df70), SkBits2Float(0xc21b86fd), SkBits2Float(0x42a97305), SkBits2Float(0xc17e5d7a), SkBits2Float(0x42a55ba0), SkBits2Float(0x40e961b9));
+path.cubicTo(SkBits2Float(0x42a48d09), SkBits2Float(0x413de0a1), SkBits2Float(0x42a2fc74), SkBits2Float(0x41833376), SkBits2Float(0x42a0adff), SkBits2Float(0x41a6c250));
+path.lineTo(SkBits2Float(0x42684ed9), SkBits2Float(0x417118ef));
+path.cubicTo(SkBits2Float(0x426ba483), SkBits2Float(0x413db02f), SkBits2Float(0x426de7aa), SkBits2Float(0x410942c3), SkBits2Float(0x426f1259), SkBits2Float(0x40a8b5ae));
+path.cubicTo(SkBits2Float(0x4274fca8), SkBits2Float(0xc137e0e1), SkBits2Float(0x425e777b), SkBits2Float(0xc1e0dbdb), SkBits2Float(0x42310131), SkBits2Float(0xc2221408));
+path.cubicTo(SkBits2Float(0x42038ae6), SkBits2Float(0xc253ba22), SkBits2Float(0x4186a32c), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a0ae00), SkBits2Float(0x41a6c250));
+path.cubicTo(SkBits2Float(0x428d4422), SkBits2Float(0x4269069e), SkBits2Float(0x42118d33), SkBits2Float(0x42a8086f), SkBits2Float(0xc00fe376), SkBits2Float(0x42a5f066));
+path.cubicTo(SkBits2Float(0xc22389a2), SkBits2Float(0x42a3d85e), SkBits2Float(0xc2935e5d), SkBits2Float(0x42596224), SkBits2Float(0xc2a2b39d), SkBits2Float(0x4183b53a));
+path.lineTo(SkBits2Float(0xc26b3b33), SkBits2Float(0x413e6bca));
+path.cubicTo(SkBits2Float(0xc2551027), SkBits2Float(0x421d2508), SkBits2Float(0xc1ec70a3), SkBits2Float(0x426ce27d), SkBits2Float(0xbfd007ff), SkBits2Float(0x426fe979));
+path.cubicTo(SkBits2Float(0x41d26fa4), SkBits2Float(0x4272f076), SkBits2Float(0x424c3d84), SkBits2Float(0x422873d5), SkBits2Float(0x42684eda), SkBits2Float(0x417118ee));
+path.lineTo(SkBits2Float(0x42a0ae00), SkBits2Float(0x41a6c250));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp241(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41c2abe0), SkBits2Float(0xc2a5ffff), SkBits2Float(0x423dc4ab), SkBits2Float(0xc290a493), SkBits2Float(0x427cd8fd), SkBits2Float(0xc25727eb));
+path.cubicTo(SkBits2Float(0x429df6a6), SkBits2Float(0xc20d06b1), SkBits2Float(0x42aba628), SkBits2Float(0xc12bcbe5), SkBits2Float(0x42a3dc46), SkBits2Float(0x4154872f));
+path.lineTo(SkBits2Float(0x426ce81c), SkBits2Float(0x4119a283));
+path.cubicTo(SkBits2Float(0x42782ad8), SkBits2Float(0xc0f86165), SkBits2Float(0x42646188), SkBits2Float(0xc1cbe4ab), SkBits2Float(0x4236c80c), SkBits2Float(0xc21b88d1));
+path.cubicTo(SkBits2Float(0x42092e8f), SkBits2Float(0xc2511f4c), SkBits2Float(0x418cb9f2), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a3dc46), SkBits2Float(0x41548735));
+path.cubicTo(SkBits2Float(0x42a2537f), SkBits2Float(0x41901e3f), SkBits2Float(0x429ff996), SkBits2Float(0x41b55e92), SkBits2Float(0x429cd549), SkBits2Float(0x41d999a0));
+path.lineTo(SkBits2Float(0x4262bf29), SkBits2Float(0x419d4d21));
+path.cubicTo(SkBits2Float(0x42674a02), SkBits2Float(0x41831c46), SkBits2Float(0x426ab03e), SkBits2Float(0x41505d16), SkBits2Float(0x426ce81d), SkBits2Float(0x4119a283));
+path.lineTo(SkBits2Float(0x42a3dc46), SkBits2Float(0x41548735));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp242(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41c2abe0), SkBits2Float(0xc2a5ffff), SkBits2Float(0x423dc4ab), SkBits2Float(0xc290a493), SkBits2Float(0x427cd8fd), SkBits2Float(0xc25727eb));
+path.cubicTo(SkBits2Float(0x429df6a6), SkBits2Float(0xc20d06b1), SkBits2Float(0x42aba628), SkBits2Float(0xc12bcbe5), SkBits2Float(0x42a3dc46), SkBits2Float(0x41548735));
+path.cubicTo(SkBits2Float(0x42a2537f), SkBits2Float(0x41901e3f), SkBits2Float(0x429ff996), SkBits2Float(0x41b55e92), SkBits2Float(0x429cd549), SkBits2Float(0x41d999a0));
+path.lineTo(SkBits2Float(0x4262bf29), SkBits2Float(0x419d4d21));
+path.cubicTo(SkBits2Float(0x42674a02), SkBits2Float(0x41831c46), SkBits2Float(0x426ab03e), SkBits2Float(0x41505d16), SkBits2Float(0x426ce81c), SkBits2Float(0x4119a283));
+path.cubicTo(SkBits2Float(0x42782ad8), SkBits2Float(0xc0f86165), SkBits2Float(0x42646188), SkBits2Float(0xc1cbe4ab), SkBits2Float(0x4236c80c), SkBits2Float(0xc21b88d1));
+path.cubicTo(SkBits2Float(0x42092e8f), SkBits2Float(0xc2511f4c), SkBits2Float(0x418cb9f2), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429cd549), SkBits2Float(0x41d999a0));
+path.cubicTo(SkBits2Float(0x42824b9e), SkBits2Float(0x4282e841), SkBits2Float(0x41d1b597), SkBits2Float(0x42b119ff), SkBits2Float(0xc15b80c3), SkBits2Float(0x42a3b776));
+path.cubicTo(SkBits2Float(0xc2569b2d), SkBits2Float(0x429654ee), SkBits2Float(0xc2a5db0b), SkBits2Float(0x42228c64), SkBits2Float(0xc2a5ffee), SkBits2Float(0x3e172efd));
+path.lineTo(SkBits2Float(0xc26fffe7), SkBits2Float(0x3dda91a4));
+path.cubicTo(SkBits2Float(0xc26fca99), SkBits2Float(0x41eb0285), SkBits2Float(0xc21b2317), SkBits2Float(0x425958e5), SkBits2Float(0xc11ead4d), SkBits2Float(0x426cb2ed));
+path.cubicTo(SkBits2Float(0x419798e1), SkBits2Float(0x4280067a), SkBits2Float(0x423c6102), SkBits2Float(0x423d4379), SkBits2Float(0x4262bf29), SkBits2Float(0x419d4d1f));
+path.lineTo(SkBits2Float(0x429cd549), SkBits2Float(0x41d999a0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp243(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41caf078), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42455e40), SkBits2Float(0xc28ecc78), SkBits2Float(0x42822b31), SkBits2Float(0xc24e07b4));
+path.cubicTo(SkBits2Float(0x42a1a743), SkBits2Float(0xc1fcecee), SkBits2Float(0x42ad3753), SkBits2Float(0xc0b3be45), SkBits2Float(0x42a18eed), SkBits2Float(0x419892cb));
+path.lineTo(SkBits2Float(0x42699409), SkBits2Float(0x415c9689));
+path.cubicTo(SkBits2Float(0x427a6ed6), SkBits2Float(0xc081ef5b), SkBits2Float(0x4269b739), SkBits2Float(0xc1b6d67a), SkBits2Float(0x423c321c), SkBits2Float(0xc214effc));
+path.cubicTo(SkBits2Float(0x420eacff), SkBits2Float(0xc24e74bc), SkBits2Float(0x4192b3ff), SkBits2Float(0xc2700000), SkBits2Float(0xb630015b), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42a18eed), SkBits2Float(0x419892ca));
+path.cubicTo(SkBits2Float(0x429f43c9), SkBits2Float(0x41bf6e44), SkBits2Float(0x429c198b), SkBits2Float(0x41e561a5), SkBits2Float(0x42981a0b), SkBits2Float(0x4204fb6e));
+path.lineTo(SkBits2Float(0x425be7f8), SkBits2Float(0x41c0436a));
+path.cubicTo(SkBits2Float(0x4261afba), SkBits2Float(0x41a5d162), SkBits2Float(0x42664329), SkBits2Float(0x418a6237), SkBits2Float(0x4269940a), SkBits2Float(0x415c968a));
+path.lineTo(SkBits2Float(0x42a18eed), SkBits2Float(0x419892ca));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp244(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb630015b), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41caf078), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42455e40), SkBits2Float(0xc28ecc78), SkBits2Float(0x42822b31), SkBits2Float(0xc24e07b4));
+path.cubicTo(SkBits2Float(0x42a1a743), SkBits2Float(0xc1fcecee), SkBits2Float(0x42ad3753), SkBits2Float(0xc0b3be48), SkBits2Float(0x42a18eed), SkBits2Float(0x419892ca));
+path.lineTo(SkBits2Float(0x42a18eed), SkBits2Float(0x419892cb));
+path.cubicTo(SkBits2Float(0x429f43c9), SkBits2Float(0x41bf6e45), SkBits2Float(0x429c198b), SkBits2Float(0x41e561a5), SkBits2Float(0x42981a0b), SkBits2Float(0x4204fb6e));
+path.lineTo(SkBits2Float(0x425be7f8), SkBits2Float(0x41c0436a));
+path.cubicTo(SkBits2Float(0x4261afba), SkBits2Float(0x41a5d162), SkBits2Float(0x42664329), SkBits2Float(0x418a6237), SkBits2Float(0x4269940a), SkBits2Float(0x415c968a));
+path.lineTo(SkBits2Float(0x42699409), SkBits2Float(0x415c9689));
+path.cubicTo(SkBits2Float(0x427a6ed6), SkBits2Float(0xc081ef5b), SkBits2Float(0x4269b739), SkBits2Float(0xc1b6d67a), SkBits2Float(0x423c321c), SkBits2Float(0xc214effc));
+path.cubicTo(SkBits2Float(0x420eacff), SkBits2Float(0xc24e74bc), SkBits2Float(0x4192b3ff), SkBits2Float(0xc2700000), SkBits2Float(0xb630015b), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42981a0b), SkBits2Float(0x4204fb6e));
+path.cubicTo(SkBits2Float(0x426c6b55), SkBits2Float(0x42900555), SkBits2Float(0x417b6a9f), SkBits2Float(0x42b7a6c3), SkBits2Float(0xc1c57072), SkBits2Float(0x429e7dd7));
+path.cubicTo(SkBits2Float(0xc282258c), SkBits2Float(0x428554eb), SkBits2Float(0xc2b314c4), SkBits2Float(0x41cdbc89), SkBits2Float(0xc2a2f571), SkBits2Float(0xc17d09b6));
+path.lineTo(SkBits2Float(0xc26b9a61), SkBits2Float(0xc136eb32));
+path.cubicTo(SkBits2Float(0xc28174d0), SkBits2Float(0x4194b9b3), SkBits2Float(0xc23c29fc), SkBits2Float(0x4240c4dc), SkBits2Float(0xc18eba2f), SkBits2Float(0x4265250a));
+path.cubicTo(SkBits2Float(0x4135bf41), SkBits2Float(0x4284c29d), SkBits2Float(0x422ae7d8), SkBits2Float(0x42503918), SkBits2Float(0x425be7f9), SkBits2Float(0x41c04367));
+path.lineTo(SkBits2Float(0x42981a0b), SkBits2Float(0x4204fb6e));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp245(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41d28773), SkBits2Float(0xc2a5ffff), SkBits2Float(0x424c4acf), SkBits2Float(0xc28d0a47), SkBits2Float(0x428572fc), SkBits2Float(0xc24574fc));
+path.cubicTo(SkBits2Float(0x42a4c090), SkBits2Float(0xc1e1aad9), SkBits2Float(0x42ae2294), SkBits2Float(0xbf62367e), SkBits2Float(0x429ebce0), SkBits2Float(0x41c23fec));
+path.lineTo(SkBits2Float(0x4265801d), SkBits2Float(0x418c6be6));
+path.cubicTo(SkBits2Float(0x427bc2fb), SkBits2Float(0xbf238720), SkBits2Float(0x426e322e), SkBits2Float(0xc1a32211), SkBits2Float(0x4240f046), SkBits2Float(0xc20ebd71));
+path.cubicTo(SkBits2Float(0x4213ae61), SkBits2Float(0xc24be9da), SkBits2Float(0x41983095), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429ebce1), SkBits2Float(0x41c23fee));
+path.cubicTo(SkBits2Float(0x429bb658), SkBits2Float(0x41e9cedc), SkBits2Float(0x4297c4ea), SkBits2Float(0x4208130e), SkBits2Float(0x4292f5c0), SkBits2Float(0x421a62d5));
+path.lineTo(SkBits2Float(0x425478e6), SkBits2Float(0x41df3573));
+path.cubicTo(SkBits2Float(0x425b6ce6), SkBits2Float(0x41c4bbf1), SkBits2Float(0x42612050), SkBits2Float(0x41a90494), SkBits2Float(0x4265801e), SkBits2Float(0x418c6be6));
+path.lineTo(SkBits2Float(0x429ebce1), SkBits2Float(0x41c23fee));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp246(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41d28773), SkBits2Float(0xc2a5ffff), SkBits2Float(0x424c4acf), SkBits2Float(0xc28d0a47), SkBits2Float(0x428572fc), SkBits2Float(0xc24574fc));
+path.cubicTo(SkBits2Float(0x42a4c090), SkBits2Float(0xc1e1aad9), SkBits2Float(0x42ae2294), SkBits2Float(0xbf62367e), SkBits2Float(0x429ebce1), SkBits2Float(0x41c23fee));
+path.cubicTo(SkBits2Float(0x429bb658), SkBits2Float(0x41e9cedc), SkBits2Float(0x4297c4ea), SkBits2Float(0x4208130e), SkBits2Float(0x4292f5c0), SkBits2Float(0x421a62d5));
+path.lineTo(SkBits2Float(0x425478e6), SkBits2Float(0x41df3573));
+path.cubicTo(SkBits2Float(0x425b6ce6), SkBits2Float(0x41c4bbf1), SkBits2Float(0x42612050), SkBits2Float(0x41a90494), SkBits2Float(0x4265801d), SkBits2Float(0x418c6be6));
+path.cubicTo(SkBits2Float(0x427bc2fb), SkBits2Float(0xbf238720), SkBits2Float(0x426e322e), SkBits2Float(0xc1a32211), SkBits2Float(0x4240f046), SkBits2Float(0xc20ebd71));
+path.cubicTo(SkBits2Float(0x4213ae61), SkBits2Float(0xc24be9da), SkBits2Float(0x41983095), SkBits2Float(0xc2700000), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4292f5c1), SkBits2Float(0x421a62d6));
+path.cubicTo(SkBits2Float(0x42541a09), SkBits2Float(0x429b1363), SkBits2Float(0x40b7c75d), SkBits2Float(0x42bb84d6), SkBits2Float(0xc2093cef), SkBits2Float(0x42972755));
+path.cubicTo(SkBits2Float(0xc294b966), SkBits2Float(0x426593a9), SkBits2Float(0xc2ba8c7c), SkBits2Float(0x4131f51c), SkBits2Float(0xc29ad8fe), SkBits2Float(0xc1ef45cd));
+path.lineTo(SkBits2Float(0xc25fe048), SkBits2Float(0xc1acf7d7));
+path.cubicTo(SkBits2Float(0xc286dac7), SkBits2Float(0x4100a4f0), SkBits2Float(0xc25705ec), SkBits2Float(0x4225f597), SkBits2Float(0xc1c66aa8), SkBits2Float(0x425a891e));
+path.cubicTo(SkBits2Float(0x4084da24), SkBits2Float(0x42878e54), SkBits2Float(0x4219539e), SkBits2Float(0x426034bf), SkBits2Float(0x425478e7), SkBits2Float(0x41df3571));
+path.lineTo(SkBits2Float(0x4292f5c1), SkBits2Float(0x421a62d6));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp247(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41d91350), SkBits2Float(0xc2a5ffff), SkBits2Float(0x425238e3), SkBits2Float(0xc28b791f), SkBits2Float(0x428827e4), SkBits2Float(0xc23dec02));
+path.cubicTo(SkBits2Float(0x42a73357), SkBits2Float(0xc1c9cb8b), SkBits2Float(0x42ae86ff), SkBits2Float(0x404daf5b), SkBits2Float(0x429bc6e8), SkBits2Float(0x41e56ae9));
+path.lineTo(SkBits2Float(0x42613841), SkBits2Float(0x41a5d816));
+path.cubicTo(SkBits2Float(0x427c5425), SkBits2Float(0x4014b024), SkBits2Float(0x4271bc5c), SkBits2Float(0xc191e03e), SkBits2Float(0x4244da12), SkBits2Float(0xc2094aff));
+path.cubicTo(SkBits2Float(0x4217f7c8), SkBits2Float(0xc249a5df), SkBits2Float(0x419cec09), SkBits2Float(0xc2700000), SkBits2Float(0xb630015b), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x429bc6e9), SkBits2Float(0x41e56aeb));
+path.cubicTo(SkBits2Float(0x429818bd), SkBits2Float(0x4206b36a), SkBits2Float(0x42937671), SkBits2Float(0x4219f01e), SkBits2Float(0x428df070), SkBits2Float(0x422c2771));
+path.lineTo(SkBits2Float(0x424d369d), SkBits2Float(0x41f8e5bf));
+path.cubicTo(SkBits2Float(0x425532f6), SkBits2Float(0x41de8f99), SkBits2Float(0x425be616), SkBits2Float(0x41c2bf8b), SkBits2Float(0x42613843), SkBits2Float(0x41a5d816));
+path.lineTo(SkBits2Float(0x429bc6e9), SkBits2Float(0x41e56aeb));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp248(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb630015b), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41d91350), SkBits2Float(0xc2a5ffff), SkBits2Float(0x425238e3), SkBits2Float(0xc28b791f), SkBits2Float(0x428827e4), SkBits2Float(0xc23dec02));
+path.cubicTo(SkBits2Float(0x42a73357), SkBits2Float(0xc1c9cb8b), SkBits2Float(0x42ae86ff), SkBits2Float(0x404daf5b), SkBits2Float(0x429bc6e9), SkBits2Float(0x41e56aeb));
+path.cubicTo(SkBits2Float(0x429818bd), SkBits2Float(0x4206b36a), SkBits2Float(0x42937671), SkBits2Float(0x4219f01e), SkBits2Float(0x428df070), SkBits2Float(0x422c2771));
+path.lineTo(SkBits2Float(0x424d369d), SkBits2Float(0x41f8e5bf));
+path.cubicTo(SkBits2Float(0x425532f6), SkBits2Float(0x41de8f99), SkBits2Float(0x425be616), SkBits2Float(0x41c2bf8b), SkBits2Float(0x42613843), SkBits2Float(0x41a5d816));
+path.lineTo(SkBits2Float(0x42613841), SkBits2Float(0x41a5d816));
+path.cubicTo(SkBits2Float(0x427c5425), SkBits2Float(0x4014b024), SkBits2Float(0x4271bc5c), SkBits2Float(0xc191e03e), SkBits2Float(0x4244da12), SkBits2Float(0xc2094aff));
+path.cubicTo(SkBits2Float(0x4217f7c8), SkBits2Float(0xc249a5df), SkBits2Float(0x419cec09), SkBits2Float(0xc2700000), SkBits2Float(0xb630015b), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x428df071), SkBits2Float(0x422c2771));
+path.cubicTo(SkBits2Float(0x423d9ebb), SkBits2Float(0x42a3ca6a), SkBits2Float(0xc041a78f), SkBits2Float(0x42bd279e), SkBits2Float(0xc228abe7), SkBits2Float(0x428efaad));
+path.cubicTo(SkBits2Float(0xc2a29eac), SkBits2Float(0x42419b78), SkBits2Float(0xc2bd3710), SkBits2Float(0xbfef63d4), SkBits2Float(0xc2900003), SkBits2Float(0xc2252a98));
+path.lineTo(SkBits2Float(0xc250315d), SkBits2Float(0xc1eecb7c));
+path.cubicTo(SkBits2Float(0xc288c864), SkBits2Float(0xbfad0c79), SkBits2Float(0xc26b1d6b), SkBits2Float(0x420bf56b), SkBits2Float(0xc1f3dd5d), SkBits2Float(0x424eb80d));
+path.cubicTo(SkBits2Float(0xc00bff34), SkBits2Float(0x4288bd57), SkBits2Float(0x4209134e), SkBits2Float(0x426ccea7), SkBits2Float(0x424d369e), SkBits2Float(0x41f8e5bd));
+path.lineTo(SkBits2Float(0x428df071), SkBits2Float(0x422c2771));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp249(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41df6bc7), SkBits2Float(0xc2a60000), SkBits2Float(0x4257ee8b), SkBits2Float(0xc289e8f6), SkBits2Float(0x428aab73), SkBits2Float(0xc2368066));
+path.cubicTo(SkBits2Float(0x42a95fa1), SkBits2Float(0xc1b25dc1), SkBits2Float(0x42ae8dc1), SkBits2Float(0x40e61789), SkBits2Float(0x42987459), SkBits2Float(0x42035b41));
+path.lineTo(SkBits2Float(0x425c6a87), SkBits2Float(0x41bde9b7));
+path.cubicTo(SkBits2Float(0x427c5dea), SkBits2Float(0x40a654db), SkBits2Float(0x4274e0a0), SkBits2Float(0xc180f082), SkBits2Float(0x42487c82), SkBits2Float(0xc203edca));
+path.cubicTo(SkBits2Float(0x421c1865), SkBits2Float(0xc2476353), SkBits2Float(0x41a18256), SkBits2Float(0xc2700000), SkBits2Float(0xb69400ae), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42987459), SkBits2Float(0x42035b41));
+path.cubicTo(SkBits2Float(0x42941f1a), SkBits2Float(0x421778e1), SkBits2Float(0x428ecdc9), SkBits2Float(0x422aae55), SkBits2Float(0x42889449), SkBits2Float(0x423cb3b9));
+path.lineTo(SkBits2Float(0x424576c5), SkBits2Float(0x4208693e));
+path.cubicTo(SkBits2Float(0x424e76a2), SkBits2Float(0x41f6c488), SkBits2Float(0x425626ce), SkBits2Float(0x41dafef6), SkBits2Float(0x425c6a88), SkBits2Float(0x41bde9b8));
+path.lineTo(SkBits2Float(0x42987459), SkBits2Float(0x42035b41));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp250(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb69400ae), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41df6bc7), SkBits2Float(0xc2a60000), SkBits2Float(0x4257ee8b), SkBits2Float(0xc289e8f6), SkBits2Float(0x428aab73), SkBits2Float(0xc2368066));
+path.cubicTo(SkBits2Float(0x42a95fa1), SkBits2Float(0xc1b25dc1), SkBits2Float(0x42ae8dc1), SkBits2Float(0x40e61789), SkBits2Float(0x42987459), SkBits2Float(0x42035b41));
+path.cubicTo(SkBits2Float(0x42941f1a), SkBits2Float(0x421778e1), SkBits2Float(0x428ecdc9), SkBits2Float(0x422aae55), SkBits2Float(0x42889449), SkBits2Float(0x423cb3b9));
+path.lineTo(SkBits2Float(0x424576c5), SkBits2Float(0x4208693e));
+path.cubicTo(SkBits2Float(0x424e76a2), SkBits2Float(0x41f6c488), SkBits2Float(0x425626ce), SkBits2Float(0x41dafef6), SkBits2Float(0x425c6a87), SkBits2Float(0x41bde9b7));
+path.cubicTo(SkBits2Float(0x427c5dea), SkBits2Float(0x40a654db), SkBits2Float(0x4274e0a0), SkBits2Float(0xc180f082), SkBits2Float(0x42487c82), SkBits2Float(0xc203edca));
+path.cubicTo(SkBits2Float(0x421c1865), SkBits2Float(0xc2476353), SkBits2Float(0x41a18256), SkBits2Float(0xc2700000), SkBits2Float(0xb69400ae), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42889449), SkBits2Float(0x423cb3b8));
+path.cubicTo(SkBits2Float(0x424c5291), SkBits2Float(0x42902c61), SkBits2Float(0x41ad609d), SkBits2Float(0x42ab4d26), SkBits2Float(0xc1072a9c), SkBits2Float(0x42a52356));
+path.cubicTo(SkBits2Float(0xc21a459c), SkBits2Float(0x429ef985), SkBits2Float(0xc2813d9b), SkBits2Float(0x4270fef6), SkBits2Float(0xc298db30), SkBits2Float(0x420179e4));
+path.cubicTo(SkBits2Float(0xc2b078c6), SkBits2Float(0x408fa686), SkBits2Float(0xc2a7d9d7), SkBits2Float(0xc1dcde62), SkBits2Float(0xc2825c7e), SkBits2Float(0xc24d8ae0));
+path.lineTo(SkBits2Float(0xc23c7965), SkBits2Float(0xc21495bd));
+path.cubicTo(SkBits2Float(0xc272ad07), SkBits2Float(0xc19fa9fe), SkBits2Float(0xc27f23bc), SkBits2Float(0x404faf9e), SkBits2Float(0xc25cff22), SkBits2Float(0x41bb31a8));
+path.cubicTo(SkBits2Float(0xc23ada86), SkBits2Float(0x422e36b1), SkBits2Float(0xc1df0b0c), SkBits2Float(0x4265d7b2), SkBits2Float(0xc0c36b6f), SkBits2Float(0x426ec0e0));
+path.cubicTo(SkBits2Float(0x417aaa9e), SkBits2Float(0x4277aa0e), SkBits2Float(0x4213b3f9), SkBits2Float(0x42507175), SkBits2Float(0x424576c8), SkBits2Float(0x4208693c));
+path.lineTo(SkBits2Float(0x42889449), SkBits2Float(0x423cb3b8));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp251(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41e529f0), SkBits2Float(0xc2a5ffff), SkBits2Float(0x425d10b2), SkBits2Float(0xc2887541), SkBits2Float(0x428cd9cf), SkBits2Float(0xc22fb184));
+path.cubicTo(SkBits2Float(0x42ab2b45), SkBits2Float(0xc19cf10c), SkBits2Float(0x42ae472d), SkBits2Float(0x412c96c0), SkBits2Float(0x42951360), SkBits2Float(0x42120c0d));
+path.lineTo(SkBits2Float(0x425787f7), SkBits2Float(0x41d32707));
+path.cubicTo(SkBits2Float(0x427bf7e0), SkBits2Float(0x40f986c2), SkBits2Float(0x4277792b), SkBits2Float(0xc162e746), SkBits2Float(0x424ba3c8), SkBits2Float(0xc1fe03ba));
+path.cubicTo(SkBits2Float(0x421fce66), SkBits2Float(0xc24549e8), SkBits2Float(0x41a5a922), SkBits2Float(0xc2700000), SkBits2Float(0x3725ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42951360), SkBits2Float(0x42120c0f));
+path.cubicTo(SkBits2Float(0x429023a5), SkBits2Float(0x422633cd), SkBits2Float(0x428a3193), SkBits2Float(0x42394df4), SkBits2Float(0x42835484), SkBits2Float(0x424b0f7e));
+path.lineTo(SkBits2Float(0x423ddffa), SkBits2Float(0x4212ca6e));
+path.cubicTo(SkBits2Float(0x4247cc4f), SkBits2Float(0x4205f480), SkBits2Float(0x425064e4), SkBits2Float(0x41f04ae6), SkBits2Float(0x425787f8), SkBits2Float(0x41d32708));
+path.lineTo(SkBits2Float(0x42951360), SkBits2Float(0x42120c0f));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp252(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3725ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41e529f0), SkBits2Float(0xc2a5ffff), SkBits2Float(0x425d10b2), SkBits2Float(0xc2887541), SkBits2Float(0x428cd9cf), SkBits2Float(0xc22fb184));
+path.cubicTo(SkBits2Float(0x42ab2b45), SkBits2Float(0xc19cf10c), SkBits2Float(0x42ae472d), SkBits2Float(0x412c96c0), SkBits2Float(0x42951360), SkBits2Float(0x42120c0f));
+path.cubicTo(SkBits2Float(0x429023a5), SkBits2Float(0x422633cd), SkBits2Float(0x428a3193), SkBits2Float(0x42394df4), SkBits2Float(0x42835484), SkBits2Float(0x424b0f7e));
+path.lineTo(SkBits2Float(0x423ddffa), SkBits2Float(0x4212ca6e));
+path.cubicTo(SkBits2Float(0x4247cc4f), SkBits2Float(0x4205f480), SkBits2Float(0x425064e4), SkBits2Float(0x41f04ae6), SkBits2Float(0x425787f7), SkBits2Float(0x41d32707));
+path.cubicTo(SkBits2Float(0x427bf7e0), SkBits2Float(0x40f986c2), SkBits2Float(0x4277792b), SkBits2Float(0xc162e746), SkBits2Float(0x424ba3c8), SkBits2Float(0xc1fe03ba));
+path.cubicTo(SkBits2Float(0x421fce66), SkBits2Float(0xc24549e8), SkBits2Float(0x41a5a922), SkBits2Float(0xc2700000), SkBits2Float(0x3725ffa9), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42835484), SkBits2Float(0x424b0f7e));
+path.cubicTo(SkBits2Float(0x423aab34), SkBits2Float(0x4296ad9b), SkBits2Float(0x41789cf4), SkBits2Float(0x42ae7f70), SkBits2Float(0xc1702bd2), SkBits2Float(0x42a3434e));
+path.cubicTo(SkBits2Float(0xc2363d27), SkBits2Float(0x4298072c), SkBits2Float(0xc28cd4c4), SkBits2Float(0x42573cf7), SkBits2Float(0xc29edb8e), SkBits2Float(0x41c0adb0));
+path.cubicTo(SkBits2Float(0xc2b0e257), SkBits2Float(0xc0b47a14), SkBits2Float(0xc2a03550), SkBits2Float(0xc217a35b), SkBits2Float(0xc2674746), SkBits2Float(0xc26e3089));
+path.lineTo(SkBits2Float(0xc2273070), SkBits2Float(0xc22c2f6e));
+path.cubicTo(SkBits2Float(0xc267a050), SkBits2Float(0xc1db3c5e), SkBits2Float(0xc27fbc5f), SkBits2Float(0xc0827737), SkBits2Float(0xc265ac62), SkBits2Float(0x418b490c));
+path.cubicTo(SkBits2Float(0xc24b9c64), SkBits2Float(0x421b97f2), SkBits2Float(0xc203bd1c), SkBits2Float(0x425bcc95), SkBits2Float(0xc12d9e08), SkBits2Float(0x426c0adc));
+path.cubicTo(SkBits2Float(0x4133b85e), SkBits2Float(0x427c4921), SkBits2Float(0x4206f0f2), SkBits2Float(0x4259d90a), SkBits2Float(0x423ddff7), SkBits2Float(0x4212ca73));
+path.lineTo(SkBits2Float(0x42835484), SkBits2Float(0x424b0f7e));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp253(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41ea9e19), SkBits2Float(0xc2a60000), SkBits2Float(0x4261e8db), SkBits2Float(0xc2870be6), SkBits2Float(0x428ed6bc), SkBits2Float(0xc22926d7));
+path.cubicTo(SkBits2Float(0x42acb90a), SkBits2Float(0xc1886bc1), SkBits2Float(0x42adc0f7), SkBits2Float(0x41631db6), SkBits2Float(0x42918cff), SkBits2Float(0x421fa302));
+path.lineTo(SkBits2Float(0x42526f53), SkBits2Float(0x41e6ccd4));
+path.cubicTo(SkBits2Float(0x427b35d6), SkBits2Float(0x41242e26), SkBits2Float(0x4279b842), SkBits2Float(0xc1453c2f), SkBits2Float(0x424e8393), SkBits2Float(0xc1f48e84));
+path.cubicTo(SkBits2Float(0x42234ee4), SkBits2Float(0xc2433f78), SkBits2Float(0x41a99a66), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42918d00), SkBits2Float(0x421fa301));
+path.cubicTo(SkBits2Float(0x428c0830), SkBits2Float(0x4233c399), SkBits2Float(0x42857bfe), SkBits2Float(0x4246b13f), SkBits2Float(0x427c06a0), SkBits2Float(0x42581e30));
+path.lineTo(SkBits2Float(0x42362ff8), SkBits2Float(0x421c3ad6));
+path.cubicTo(SkBits2Float(0x4240fd4a), SkBits2Float(0x420fa210), SkBits2Float(0x424a74b5), SkBits2Float(0x4201f32f), SkBits2Float(0x42526f54), SkBits2Float(0x41e6ccd5));
+path.lineTo(SkBits2Float(0x42918d00), SkBits2Float(0x421fa301));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp254(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41ea9e19), SkBits2Float(0xc2a60000), SkBits2Float(0x4261e8db), SkBits2Float(0xc2870be6), SkBits2Float(0x428ed6bc), SkBits2Float(0xc22926d7));
+path.cubicTo(SkBits2Float(0x42acb90a), SkBits2Float(0xc1886bc1), SkBits2Float(0x42adc0f7), SkBits2Float(0x41631db6), SkBits2Float(0x42918d00), SkBits2Float(0x421fa301));
+path.cubicTo(SkBits2Float(0x428c0830), SkBits2Float(0x4233c399), SkBits2Float(0x42857bfe), SkBits2Float(0x4246b13f), SkBits2Float(0x427c06a0), SkBits2Float(0x42581e30));
+path.lineTo(SkBits2Float(0x42362ff8), SkBits2Float(0x421c3ad6));
+path.cubicTo(SkBits2Float(0x4240fd4a), SkBits2Float(0x420fa210), SkBits2Float(0x424a74b5), SkBits2Float(0x4201f32f), SkBits2Float(0x42526f53), SkBits2Float(0x41e6ccd4));
+path.cubicTo(SkBits2Float(0x427b35d6), SkBits2Float(0x41242e26), SkBits2Float(0x4279b842), SkBits2Float(0xc1453c2f), SkBits2Float(0x424e8393), SkBits2Float(0xc1f48e84));
+path.cubicTo(SkBits2Float(0x42234ee4), SkBits2Float(0xc2433f78), SkBits2Float(0x41a99a66), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x427c069f), SkBits2Float(0x42581e31));
+path.cubicTo(SkBits2Float(0x4229355f), SkBits2Float(0x429c5901), SkBits2Float(0x4119ef9b), SkBits2Float(0x42b0b9f6), SkBits2Float(0xc1a91754), SkBits2Float(0x42a086fc));
+path.cubicTo(SkBits2Float(0xc24f933a), SkBits2Float(0x42905402), SkBits2Float(0xc296a2af), SkBits2Float(0x423cccf9), SkBits2Float(0xc2a2e3f0), SkBits2Float(0x417fd713));
+path.cubicTo(SkBits2Float(0xc2af2532), SkBits2Float(0xc17385be), SkBits2Float(0xc296a6d5), SkBits2Float(0xc23cbfbd), SkBits2Float(0xc247a7c9), SkBits2Float(0xc284a101));
+path.lineTo(SkBits2Float(0xc210544b), SkBits2Float(0xc23fc0ab));
+path.cubicTo(SkBits2Float(0xc259cf4c), SkBits2Float(0xc20871e9), SkBits2Float(0xc27d38da), SkBits2Float(0xc1300a36), SkBits2Float(0xc26b810f), SkBits2Float(0x4138f1f1));
+path.cubicTo(SkBits2Float(0xc259c944), SkBits2Float(0x42087b85), SkBits2Float(0xc2160de3), SkBits2Float(0x4250aad1), SkBits2Float(0xc174780b), SkBits2Float(0x42681670));
+path.cubicTo(SkBits2Float(0x40de8efd), SkBits2Float(0x427f820e), SkBits2Float(0x41f4a392), SkBits2Float(0x42620b79), SkBits2Float(0x42362ffc), SkBits2Float(0x421c3ad2));
+path.lineTo(SkBits2Float(0x427c069f), SkBits2Float(0x42581e31));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp255(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41eeb164), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42658277), SkBits2Float(0xc285f892), SkBits2Float(0x42904565), SkBits2Float(0xc22437b5));
+path.cubicTo(SkBits2Float(0x42adc98d), SkBits2Float(0xc171f916), SkBits2Float(0x42ad3226), SkBits2Float(0x4185deb6), SkBits2Float(0x428eb8d5), SkBits2Float(0x42298bae));
+path.lineTo(SkBits2Float(0x424e5857), SkBits2Float(0x41f5204e));
+path.cubicTo(SkBits2Float(0x427a675d), SkBits2Float(0x41418c03), SkBits2Float(0x427b4242), SkBits2Float(0xc12eeb9a), SkBits2Float(0x425095b0), SkBits2Float(0xc1ed6c50));
+path.cubicTo(SkBits2Float(0x4225e91e), SkBits2Float(0xc241b169), SkBits2Float(0x41ac8c92), SkBits2Float(0xc2700000), SkBits2Float(0xb69400ae), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x428eb8d5), SkBits2Float(0x42298bad));
+path.cubicTo(SkBits2Float(0x4288c365), SkBits2Float(0x423d9c15), SkBits2Float(0x4281c36f), SkBits2Float(0x42505c7e), SkBits2Float(0x4273ad50), SkBits2Float(0x42617d52));
+path.lineTo(SkBits2Float(0x423026ec), SkBits2Float(0x42230126));
+path.cubicTo(SkBits2Float(0x423b9c18), SkBits2Float(0x42169f65), SkBits2Float(0x4245bae4), SkBits2Float(0x42091136), SkBits2Float(0x424e5858), SkBits2Float(0x41f5204d));
+path.lineTo(SkBits2Float(0x428eb8d5), SkBits2Float(0x42298bad));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp256(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb69400ae), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41eeb164), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42658277), SkBits2Float(0xc285f892), SkBits2Float(0x42904565), SkBits2Float(0xc22437b5));
+path.cubicTo(SkBits2Float(0x42adc98d), SkBits2Float(0xc171f917), SkBits2Float(0x42ad3226), SkBits2Float(0x4185deb4), SkBits2Float(0x428eb8d5), SkBits2Float(0x42298bad));
+path.lineTo(SkBits2Float(0x428eb8d5), SkBits2Float(0x42298bae));
+path.cubicTo(SkBits2Float(0x4288c365), SkBits2Float(0x423d9c16), SkBits2Float(0x4281c36f), SkBits2Float(0x42505c7e), SkBits2Float(0x4273ad50), SkBits2Float(0x42617d52));
+path.lineTo(SkBits2Float(0x423026ec), SkBits2Float(0x42230126));
+path.cubicTo(SkBits2Float(0x423b9c18), SkBits2Float(0x42169f65), SkBits2Float(0x4245bae4), SkBits2Float(0x42091136), SkBits2Float(0x424e5858), SkBits2Float(0x41f5204d));
+path.cubicTo(SkBits2Float(0x427a675e), SkBits2Float(0x41418c02), SkBits2Float(0x427b4242), SkBits2Float(0xc12eeb9b), SkBits2Float(0x425095b0), SkBits2Float(0xc1ed6c50));
+path.cubicTo(SkBits2Float(0x4225e91e), SkBits2Float(0xc241b169), SkBits2Float(0x41ac8c92), SkBits2Float(0xc2700000), SkBits2Float(0xb69400ae), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4273ad4f), SkBits2Float(0x42617d52));
+path.cubicTo(SkBits2Float(0x421bc173), SkBits2Float(0x42a0404f), SkBits2Float(0x40a50405), SkBits2Float(0x42b1dfaa), SkBits2Float(0xc1cd0022), SkBits2Float(0x429de3fd));
+path.cubicTo(SkBits2Float(0xc261a0a2), SkBits2Float(0x4289e850), SkBits2Float(0xc29d25ee), SkBits2Float(0x4227ed4e), SkBits2Float(0xc2a4d3d8), SkBits2Float(0x411d8f80));
+path.cubicTo(SkBits2Float(0xc2ac81c3), SkBits2Float(0xc1b24b1c), SkBits2Float(0xc28e216c), SkBits2Float(0xc256e38c), SkBits2Float(0xc22e0453), SkBits2Float(0xc28d5ec3));
+path.lineTo(SkBits2Float(0xc1fb9743), SkBits2Float(0xc24c63fd));
+path.cubicTo(SkBits2Float(0xc24d7d6b), SkBits2Float(0xc21b575f), SkBits2Float(0xc279684a), SkBits2Float(0xc180e302), SkBits2Float(0xc26e4dff), SkBits2Float(0x40e3cc4e));
+path.cubicTo(SkBits2Float(0xc26333b4), SkBits2Float(0x41f2c929), SkBits2Float(0xc2231aa4), SkBits2Float(0x42476256), SkBits2Float(0xc1943166), SkBits2Float(0x4264467e));
+path.cubicTo(SkBits2Float(0x406e93d1), SkBits2Float(0x42809553), SkBits2Float(0x41e1305a), SkBits2Float(0x4267b03c), SkBits2Float(0x423026ed), SkBits2Float(0x42230127));
+path.lineTo(SkBits2Float(0x4273ad4f), SkBits2Float(0x42617d52));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp257(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f2d268), SkBits2Float(0xc2a5ffff), SkBits2Float(0x426923a2), SkBits2Float(0xc284dd06), SkBits2Float(0x4291aced), SkBits2Float(0xc21f2e53));
+path.cubicTo(SkBits2Float(0x42aec809), SkBits2Float(0xc1528a66), SkBits2Float(0x42ac7c90), SkBits2Float(0x419a60b1), SkBits2Float(0x428bb0fe), SkBits2Float(0x42335ba0));
+path.lineTo(SkBits2Float(0x4249f6a4), SkBits2Float(0x4201a806));
+path.cubicTo(SkBits2Float(0x427960d2), SkBits2Float(0x415f325f), SkBits2Float(0x427cb22e), SkBits2Float(0xc11832b1), SkBits2Float(0x42529d7e), SkBits2Float(0xc1e62422));
+path.cubicTo(SkBits2Float(0x422888ce), SkBits2Float(0xc2401775), SkBits2Float(0x41af88b3), SkBits2Float(0xc2700000), SkBits2Float(0x36d3ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x428bb0ff), SkBits2Float(0x42335ba2));
+path.cubicTo(SkBits2Float(0x4285489d), SkBits2Float(0x42475206), SkBits2Float(0x427ba631), SkBits2Float(0x4259da14), SkBits2Float(0x426ae250), SkBits2Float(0x426aa282));
+path.lineTo(SkBits2Float(0x4229cbb3), SkBits2Float(0x42299d92));
+path.cubicTo(SkBits2Float(0x4235ea43), SkBits2Float(0x421d7bb7), SkBits2Float(0x4240b302), SkBits2Float(0x42101649), SkBits2Float(0x4249f6a5), SkBits2Float(0x4201a807));
+path.lineTo(SkBits2Float(0x428bb0ff), SkBits2Float(0x42335ba2));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp258(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36d3ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f2d268), SkBits2Float(0xc2a5ffff), SkBits2Float(0x426923a2), SkBits2Float(0xc284dd06), SkBits2Float(0x4291aced), SkBits2Float(0xc21f2e53));
+path.cubicTo(SkBits2Float(0x42aec809), SkBits2Float(0xc1528a66), SkBits2Float(0x42ac7c90), SkBits2Float(0x419a60b1), SkBits2Float(0x428bb0ff), SkBits2Float(0x42335ba2));
+path.cubicTo(SkBits2Float(0x4285489d), SkBits2Float(0x42475206), SkBits2Float(0x427ba631), SkBits2Float(0x4259da14), SkBits2Float(0x426ae250), SkBits2Float(0x426aa282));
+path.lineTo(SkBits2Float(0x4229cbb3), SkBits2Float(0x42299d92));
+path.cubicTo(SkBits2Float(0x4235ea43), SkBits2Float(0x421d7bb7), SkBits2Float(0x4240b302), SkBits2Float(0x42101649), SkBits2Float(0x4249f6a4), SkBits2Float(0x4201a806));
+path.cubicTo(SkBits2Float(0x427960d2), SkBits2Float(0x415f325f), SkBits2Float(0x427cb22e), SkBits2Float(0xc11832b1), SkBits2Float(0x42529d7e), SkBits2Float(0xc1e62422));
+path.cubicTo(SkBits2Float(0x422888ce), SkBits2Float(0xc2401775), SkBits2Float(0x41af88b3), SkBits2Float(0xc2700000), SkBits2Float(0x36d3ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x426ae251), SkBits2Float(0x426aa281));
+path.cubicTo(SkBits2Float(0x420dcd2c), SkBits2Float(0x42a3e87c), SkBits2Float(0x3f1c0197), SkBits2Float(0x42b294d6), SkBits2Float(0xc1f0a2ab), SkBits2Float(0x429ab731));
+path.cubicTo(SkBits2Float(0xc27312b1), SkBits2Float(0x4282d98e), SkBits2Float(0xc2a300b1), SkBits2Float(0x4211eaa7), SkBits2Float(0xc2a5d865), SkBits2Float(0x40654aaf));
+path.cubicTo(SkBits2Float(0xc2a8b018), SkBits2Float(0xc1ea82a2), SkBits2Float(0xc2845e8a), SkBits2Float(0xc26fc272), SkBits2Float(0xc2128ebb), SkBits2Float(0xc294f34d));
+path.lineTo(SkBits2Float(0xc1d3e3ef), SkBits2Float(0xc2575999));
+path.cubicTo(SkBits2Float(0xc23f6093), SkBits2Float(0xc22d51f6), SkBits2Float(0xc273e2d0), SkBits2Float(0xc1a9868a), SkBits2Float(0xc26fc6b5), SkBits2Float(0x4025c090));
+path.cubicTo(SkBits2Float(0xc26baa9a), SkBits2Float(0x41d2f6ae), SkBits2Float(0xc22fb71e), SkBits2Float(0x423d2e2a), SkBits2Float(0xc1adf403), SkBits2Float(0x425faf61));
+path.cubicTo(SkBits2Float(0x3ee18e9e), SkBits2Float(0x4281184d), SkBits2Float(0x41cd03a3), SkBits2Float(0x426cf9bf), SkBits2Float(0x4229cbb7), SkBits2Float(0x42299d90));
+path.lineTo(SkBits2Float(0x426ae251), SkBits2Float(0x426aa281));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp259(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f70d18), SkBits2Float(0xc2a60000), SkBits2Float(0x426cd682), SkBits2Float(0xc283b5d2), SkBits2Float(0x429310ae), SkBits2Float(0xc219fc22));
+path.cubicTo(SkBits2Float(0x42afb61c), SkBits2Float(0xc132327f), SkBits2Float(0x42ab9c4e), SkBits2Float(0x41af4ab2), SkBits2Float(0x42886baa), SkBits2Float(0x423d2918));
+path.lineTo(SkBits2Float(0x42453c0d), SkBits2Float(0x4208be17));
+path.cubicTo(SkBits2Float(0x42781c98), SkBits2Float(0x417d6f0f), SkBits2Float(0x427e0a5e), SkBits2Float(0xc100d142), SkBits2Float(0x42549fd3), SkBits2Float(0xc1dea0fa));
+path.cubicTo(SkBits2Float(0x422b3547), SkBits2Float(0xc23e6ca9), SkBits2Float(0x41b29756), SkBits2Float(0xc26fffff), SkBits2Float(0xb630015b), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42886bab), SkBits2Float(0x423d2917));
+path.cubicTo(SkBits2Float(0x42818ce6), SkBits2Float(0x4250fab6), SkBits2Float(0x42733ded), SkBits2Float(0x42633df9), SkBits2Float(0x42618b96), SkBits2Float(0x4273a01b));
+path.lineTo(SkBits2Float(0x42230b75), SkBits2Float(0x42301d61));
+path.cubicTo(SkBits2Float(0x422fd668), SkBits2Float(0x4224457a), SkBits2Float(0x423b4d41), SkBits2Float(0x421711c6), SkBits2Float(0x42453c0e), SkBits2Float(0x4208be17));
+path.lineTo(SkBits2Float(0x42886bab), SkBits2Float(0x423d2917));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp260(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb630015b), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f70d18), SkBits2Float(0xc2a60000), SkBits2Float(0x426cd682), SkBits2Float(0xc283b5d2), SkBits2Float(0x429310ae), SkBits2Float(0xc219fc22));
+path.cubicTo(SkBits2Float(0x42afb61c), SkBits2Float(0xc132327f), SkBits2Float(0x42ab9c4e), SkBits2Float(0x41af4ab2), SkBits2Float(0x42886bab), SkBits2Float(0x423d2917));
+path.cubicTo(SkBits2Float(0x42818ce6), SkBits2Float(0x4250fab6), SkBits2Float(0x42733ded), SkBits2Float(0x42633df9), SkBits2Float(0x42618b96), SkBits2Float(0x4273a01b));
+path.lineTo(SkBits2Float(0x42230b75), SkBits2Float(0x42301d61));
+path.cubicTo(SkBits2Float(0x422fd668), SkBits2Float(0x4224457a), SkBits2Float(0x423b4d41), SkBits2Float(0x421711c6), SkBits2Float(0x42453c0d), SkBits2Float(0x4208be17));
+path.cubicTo(SkBits2Float(0x42781c98), SkBits2Float(0x417d6f0f), SkBits2Float(0x427e0a5e), SkBits2Float(0xc100d142), SkBits2Float(0x42549fd3), SkBits2Float(0xc1dea0fa));
+path.cubicTo(SkBits2Float(0x422b3547), SkBits2Float(0xc23e6ca9), SkBits2Float(0x41b29756), SkBits2Float(0xc26fffff), SkBits2Float(0xb630015b), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42618b95), SkBits2Float(0x4273a01c));
+path.cubicTo(SkBits2Float(0x41fe659e), SkBits2Float(0x42a75638), SkBits2Float(0xc081f8cf), SkBits2Float(0x42b2d4b3), SkBits2Float(0xc20a1eaa), SkBits2Float(0x4296f3e7));
+path.cubicTo(SkBits2Float(0xc281ff1e), SkBits2Float(0x42762634), SkBits2Float(0xc2a8320c), SkBits2Float(0x41f52b39), SkBits2Float(0xc2a5e71e), SkBits2Float(0xc035be80));
+path.cubicTo(SkBits2Float(0xc2a39c30), SkBits2Float(0xc2114d6a), SkBits2Float(0xc2728d06), SkBits2Float(0xc283ad37), SkBits2Float(0xc1ea4cbe), SkBits2Float(0xc29b5279));
+path.lineTo(SkBits2Float(0xc1a95f99), SkBits2Float(0xc2608fe9));
+path.cubicTo(SkBits2Float(0xc22f5688), SkBits2Float(0xc23e6034), SkBits2Float(0xc26c8b72), SkBits2Float(0xc1d2135a), SkBits2Float(0xc26fdc03), SkBits2Float(0xc003615b));
+path.cubicTo(SkBits2Float(0xc2732c96), SkBits2Float(0x41b13b02), SkBits2Float(0xc23bf25c), SkBits2Float(0x4231f06e), SkBits2Float(0xc1c7b0f0), SkBits2Float(0x425a3eb1));
+path.cubicTo(SkBits2Float(0xc03be91a), SkBits2Float(0x4281467b), SkBits2Float(0x41b7e6c5), SkBits2Float(0x4271eec4), SkBits2Float(0x42230b77), SkBits2Float(0x42301d61));
+path.lineTo(SkBits2Float(0x42618b95), SkBits2Float(0x4273a01c));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp261(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f9750b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x426eeefa), SkBits2Float(0xc2830bb8), SkBits2Float(0x4293d569), SkBits2Float(0xc2170343));
+path.cubicTo(SkBits2Float(0x42b03354), SkBits2Float(0xc11fbc55), SkBits2Float(0x42ab0b89), SkBits2Float(0x41bb247a), SkBits2Float(0x42867c8e), SkBits2Float(0x42429f12));
+path.lineTo(SkBits2Float(0x42427039), SkBits2Float(0x420cb0ae));
+path.cubicTo(SkBits2Float(0x42774b4a), SkBits2Float(0x418748a6), SkBits2Float(0x427ebf70), SkBits2Float(0xc0e6f16a), SkBits2Float(0x4255bc46), SkBits2Float(0xc1da54e8));
+path.cubicTo(SkBits2Float(0x422cb91b), SkBits2Float(0xc23d76ba), SkBits2Float(0x41b454a4), SkBits2Float(0xc2700000), SkBits2Float(0x3725ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42867c8e), SkBits2Float(0x42429f13));
+path.cubicTo(SkBits2Float(0x427eb473), SkBits2Float(0x4256572c), SkBits2Float(0x426e4fbb), SkBits2Float(0x42686e49), SkBits2Float(0x425c16a2), SkBits2Float(0x427890ea));
+path.lineTo(SkBits2Float(0x421f199c), SkBits2Float(0x4233afb3));
+path.cubicTo(SkBits2Float(0x422c45f9), SkBits2Float(0x422805b5), SkBits2Float(0x42381fbf), SkBits2Float(0x421af1ea), SkBits2Float(0x4242703a), SkBits2Float(0x420cb0af));
+path.lineTo(SkBits2Float(0x42867c8e), SkBits2Float(0x42429f13));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp262(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3725ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41f9750b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x426eeefa), SkBits2Float(0xc2830bb8), SkBits2Float(0x4293d569), SkBits2Float(0xc2170343));
+path.cubicTo(SkBits2Float(0x42b03354), SkBits2Float(0xc11fbc55), SkBits2Float(0x42ab0b89), SkBits2Float(0x41bb247a), SkBits2Float(0x42867c8e), SkBits2Float(0x42429f13));
+path.cubicTo(SkBits2Float(0x427eb473), SkBits2Float(0x4256572c), SkBits2Float(0x426e4fbb), SkBits2Float(0x42686e49), SkBits2Float(0x425c16a2), SkBits2Float(0x427890ea));
+path.lineTo(SkBits2Float(0x421f199c), SkBits2Float(0x4233afb3));
+path.cubicTo(SkBits2Float(0x422c45f9), SkBits2Float(0x422805b5), SkBits2Float(0x42381fbf), SkBits2Float(0x421af1ea), SkBits2Float(0x42427039), SkBits2Float(0x420cb0ae));
+path.cubicTo(SkBits2Float(0x42774b4a), SkBits2Float(0x418748a6), SkBits2Float(0x427ebf70), SkBits2Float(0xc0e6f16a), SkBits2Float(0x4255bc46), SkBits2Float(0xc1da54e8));
+path.cubicTo(SkBits2Float(0x422cb91b), SkBits2Float(0xc23d76ba), SkBits2Float(0x41b454a4), SkBits2Float(0xc2700000), SkBits2Float(0x3725ffa9), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x425c16a1), SkBits2Float(0x427890eb));
+path.cubicTo(SkBits2Float(0x41ed85e5), SkBits2Float(0x42a9245e), SkBits2Float(0xc0d70d9a), SkBits2Float(0x42b2c211), SkBits2Float(0xc2140612), SkBits2Float(0x42949665));
+path.cubicTo(SkBits2Float(0xc2869539), SkBits2Float(0x426cd56f), SkBits2Float(0xc2aac701), SkBits2Float(0x41d9ff9c), SkBits2Float(0xc2a57e3b), SkBits2Float(0xc0cf6824));
+path.cubicTo(SkBits2Float(0xc2a03574), SkBits2Float(0xc220d9d7), SkBits2Float(0xc26501e3), SkBits2Float(0xc289ed78), SkBits2Float(0xc1c7e516), SkBits2Float(0xc29e4c97));
+path.lineTo(SkBits2Float(0xc190809e), SkBits2Float(0xc264ddc3));
+path.cubicTo(SkBits2Float(0xc2258c2b), SkBits2Float(0xc24769d4), SkBits2Float(0xc267a08f), SkBits2Float(0xc1e88e39), SkBits2Float(0xc26f4461), SkBits2Float(0xc095eec9));
+path.cubicTo(SkBits2Float(0xc276e835), SkBits2Float(0x419d96da), SkBits2Float(0xc24293e3), SkBits2Float(0x422b3483), SkBits2Float(0xc1d60298), SkBits2Float(0x4256d347));
+path.cubicTo(SkBits2Float(0xc09b75b0), SkBits2Float(0x42813905), SkBits2Float(0x41abb417), SkBits2Float(0x42748af0), SkBits2Float(0x421f199e), SkBits2Float(0x4233afb2));
+path.lineTo(SkBits2Float(0x425c16a1), SkBits2Float(0x427890eb));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp263(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41fc38da), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4271556b), SkBits2Float(0xc2824656), SkBits2Float(0x4294b266), SkBits2Float(0xc213956f));
+path.cubicTo(SkBits2Float(0x42b0ba15), SkBits2Float(0xc10a78c9), SkBits2Float(0x42aa55de), SkBits2Float(0x41c8b65d), SkBits2Float(0x42843343), SkBits2Float(0x4248ca15));
+path.lineTo(SkBits2Float(0x423f2206), SkBits2Float(0x42112621));
+path.cubicTo(SkBits2Float(0x427644a6), SkBits2Float(0x419117e2), SkBits2Float(0x427f8241), SkBits2Float(0xc0c83353), SkBits2Float(0x4256fbc4), SkBits2Float(0xc1d55fc8));
+path.cubicTo(SkBits2Float(0x422e7546), SkBits2Float(0xc23c595d), SkBits2Float(0x41b6544b), SkBits2Float(0xc2700002), SkBits2Float(0x357ffa8c), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42843344), SkBits2Float(0x4248ca14));
+path.cubicTo(SkBits2Float(0x4279865a), SkBits2Float(0x425c60b2), SkBits2Float(0x426884b7), SkBits2Float(0x426e4097), SkBits2Float(0x4255b1c1), SkBits2Float(0x427e1584));
+path.lineTo(SkBits2Float(0x421a7a55), SkBits2Float(0x4237acdc));
+path.cubicTo(SkBits2Float(0x422815ec), SkBits2Float(0x422c3b08), SkBits2Float(0x42346121), SkBits2Float(0x421f4f28), SkBits2Float(0x423f2207), SkBits2Float(0x42112621));
+path.lineTo(SkBits2Float(0x42843344), SkBits2Float(0x4248ca14));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp264(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41fc38da), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4271556b), SkBits2Float(0xc2824656), SkBits2Float(0x4294b266), SkBits2Float(0xc213956f));
+path.cubicTo(SkBits2Float(0x42b0ba15), SkBits2Float(0xc10a78c9), SkBits2Float(0x42aa55de), SkBits2Float(0x41c8b65d), SkBits2Float(0x42843344), SkBits2Float(0x4248ca14));
+path.cubicTo(SkBits2Float(0x4279865a), SkBits2Float(0x425c60b2), SkBits2Float(0x426884b7), SkBits2Float(0x426e4097), SkBits2Float(0x4255b1c1), SkBits2Float(0x427e1584));
+path.lineTo(SkBits2Float(0x421a7a55), SkBits2Float(0x4237acdc));
+path.cubicTo(SkBits2Float(0x422815ec), SkBits2Float(0x422c3b08), SkBits2Float(0x42346121), SkBits2Float(0x421f4f28), SkBits2Float(0x423f2206), SkBits2Float(0x42112621));
+path.cubicTo(SkBits2Float(0x427644a6), SkBits2Float(0x419117e2), SkBits2Float(0x427f8241), SkBits2Float(0xc0c83353), SkBits2Float(0x4256fbc4), SkBits2Float(0xc1d55fc8));
+path.cubicTo(SkBits2Float(0x422e7546), SkBits2Float(0xc23c595d), SkBits2Float(0x41b6544b), SkBits2Float(0xc2700002), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4255b1c2), SkBits2Float(0x427e1586));
+path.cubicTo(SkBits2Float(0x41d9eb88), SkBits2Float(0x42ab15b8), SkBits2Float(0xc11c5ee2), SkBits2Float(0x42b27b8c), SkBits2Float(0xc21f2fec), SkBits2Float(0x4291ac82));
+path.cubicTo(SkBits2Float(0xc28ba40f), SkBits2Float(0x4261baf0), SkBits2Float(0xc2ad6782), SkBits2Float(0x41ba4aab), SkBits2Float(0xc2a4a120), SkBits2Float(0xc12a4d95));
+path.cubicTo(SkBits2Float(0xc29bdabd), SkBits2Float(0xc2324c20), SkBits2Float(0xc254adab), SkBits2Float(0xc290ac19), SkBits2Float(0xc19fafc0), SkBits2Float(0xc2a120ca));
+path.lineTo(SkBits2Float(0xc166df50), SkBits2Float(0xc268f4ce));
+path.cubicTo(SkBits2Float(0xc219be54), SkBits2Float(0xc2512a28), SkBits2Float(0xc26154eb), SkBits2Float(0xc200e3bb), SkBits2Float(0xc26e04b2), SkBits2Float(0xc0f6387e));
+path.cubicTo(SkBits2Float(0xc27ab479), SkBits2Float(0x4186ab35), SkBits2Float(0xc249e3ea), SkBits2Float(0x42232db1), SkBits2Float(0xc1e62664), SkBits2Float(0x42529ce0));
+path.cubicTo(SkBits2Float(0xc0e213c9), SkBits2Float(0x42810608), SkBits2Float(0x419d8860), SkBits2Float(0x427759fd), SkBits2Float(0x421a7a58), SkBits2Float(0x4237acda));
+path.lineTo(SkBits2Float(0x4255b1c2), SkBits2Float(0x427e1586));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp265(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41fe7454), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427343e8), SkBits2Float(0xc281a57b), SkBits2Float(0x429560d9), SkBits2Float(0xc210ce12));
+path.cubicTo(SkBits2Float(0x42b11fbd), SkBits2Float(0xc0f2896e), SkBits2Float(0x42a9b750), SkBits2Float(0x41d3a0ba), SkBits2Float(0x42824e39), SkBits2Float(0x424daf12));
+path.lineTo(SkBits2Float(0x423c64bf), SkBits2Float(0x4214afea));
+path.cubicTo(SkBits2Float(0x42755f66), SkBits2Float(0x4198fbec), SkBits2Float(0x42800a9d), SkBits2Float(0xc0af53e2), SkBits2Float(0x4257f7fc), SkBits2Float(0xc1d15b49));
+path.cubicTo(SkBits2Float(0x422fdabc), SkBits2Float(0xc23b70cc), SkBits2Float(0x41b7f168), SkBits2Float(0xc2700002), SkBits2Float(0xb5600574), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42824e38), SkBits2Float(0x424daf15));
+path.cubicTo(SkBits2Float(0x42753e9a), SkBits2Float(0x4261276c), SkBits2Float(0x4263be9a), SkBits2Float(0x4272d73c), SkBits2Float(0x4250704b), SkBits2Float(0x428134df));
+path.lineTo(SkBits2Float(0x4216adb6), SkBits2Float(0x423acdfc));
+path.cubicTo(SkBits2Float(0x4224a276), SkBits2Float(0x422f8c2c), SkBits2Float(0x42314905), SkBits2Float(0x4222c30f), SkBits2Float(0x423c64c0), SkBits2Float(0x4214afec));
+path.lineTo(SkBits2Float(0x42824e38), SkBits2Float(0x424daf15));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp266(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x41fe7454), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427343e8), SkBits2Float(0xc281a57b), SkBits2Float(0x429560d9), SkBits2Float(0xc210ce12));
+path.cubicTo(SkBits2Float(0x42b11fbd), SkBits2Float(0xc0f2896e), SkBits2Float(0x42a9b750), SkBits2Float(0x41d3a0ba), SkBits2Float(0x42824e39), SkBits2Float(0x424daf12));
+path.lineTo(SkBits2Float(0x42824e38), SkBits2Float(0x424daf15));
+path.cubicTo(SkBits2Float(0x42753e9a), SkBits2Float(0x4261276c), SkBits2Float(0x4263be9a), SkBits2Float(0x4272d73c), SkBits2Float(0x4250704b), SkBits2Float(0x428134df));
+path.lineTo(SkBits2Float(0x4216adb6), SkBits2Float(0x423acdfc));
+path.cubicTo(SkBits2Float(0x4224a276), SkBits2Float(0x422f8c2c), SkBits2Float(0x42314905), SkBits2Float(0x4222c30f), SkBits2Float(0x423c64c0), SkBits2Float(0x4214afec));
+path.lineTo(SkBits2Float(0x423c64bf), SkBits2Float(0x4214afea));
+path.cubicTo(SkBits2Float(0x42755f66), SkBits2Float(0x4198fbec), SkBits2Float(0x42800a9d), SkBits2Float(0xc0af53e2), SkBits2Float(0x4257f7fc), SkBits2Float(0xc1d15b49));
+path.cubicTo(SkBits2Float(0x422fdabc), SkBits2Float(0xc23b70cc), SkBits2Float(0x41b7f168), SkBits2Float(0xc2700002), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4250704d), SkBits2Float(0x428134e0));
+path.cubicTo(SkBits2Float(0x41c9effb), SkBits2Float(0x42ac8cba), SkBits2Float(0xc143bd6b), SkBits2Float(0x42b21c58), SkBits2Float(0xc2280561), SkBits2Float(0x428f2c0c));
+path.cubicTo(SkBits2Float(0xc28f8db2), SkBits2Float(0x42587782), SkBits2Float(0xc2af41ba), SkBits2Float(0x41a05b8a), SkBits2Float(0xc2a3a0d2), SkBits2Float(0xc15fb01a));
+path.cubicTo(SkBits2Float(0xc297ffea), SkBits2Float(0xc24005d3), SkBits2Float(0xc246ef26), SkBits2Float(0xc295c2d5), SkBits2Float(0xc17d9b57), SkBits2Float(0xc2a2f1e8));
+path.lineTo(SkBits2Float(0xc1375488), SkBits2Float(0xc26b9543));
+path.cubicTo(SkBits2Float(0xc20fcecd), SkBits2Float(0xc25885a3), SkBits2Float(0xc25bc22e), SkBits2Float(0xc20acfc5), SkBits2Float(0xc26c9222), SkBits2Float(0xc121b3b7));
+path.cubicTo(SkBits2Float(0xc27d6216), SkBits2Float(0x4167d7a5), SkBits2Float(0xc24f8c13), SkBits2Float(0x421c7b68), SkBits2Float(0xc1f2ebf9), SkBits2Float(0x424efee8));
+path.cubicTo(SkBits2Float(0xc10d7f99), SkBits2Float(0x4280c134), SkBits2Float(0x4191fa9e), SkBits2Float(0x4279782f), SkBits2Float(0x4216adb8), SkBits2Float(0x423acdfc));
+path.lineTo(SkBits2Float(0x4250704d), SkBits2Float(0x428134e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp267(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42003b3a), SkBits2Float(0xc2a60000), SkBits2Float(0x4274ff8d), SkBits2Float(0xc28113a0), SkBits2Float(0x4295fac2), SkBits2Float(0xc20e4c24));
+path.cubicTo(SkBits2Float(0x42b175be), SkBits2Float(0xc0d38840), SkBits2Float(0x42a91fa3), SkBits2Float(0x41dd6a3d), SkBits2Float(0x42809081), SkBits2Float(0x4252054f));
+path.lineTo(SkBits2Float(0x4239e059), SkBits2Float(0x4217d27c));
+path.cubicTo(SkBits2Float(0x4274841b), SkBits2Float(0x41a00f1c), SkBits2Float(0x428048c8), SkBits2Float(0xc098ea38), SkBits2Float(0x4258d681), SkBits2Float(0xc1cdbb32));
+path.cubicTo(SkBits2Float(0x42311b71), SkBits2Float(0xc23a9deb), SkBits2Float(0x41b96511), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42809082), SkBits2Float(0x4252054e));
+path.cubicTo(SkBits2Float(0x4271521d), SkBits2Float(0x42655feb), SkBits2Float(0x425f60c7), SkBits2Float(0x4276e1ca), SkBits2Float(0x424ba43f), SkBits2Float(0x42831ae1));
+path.lineTo(SkBits2Float(0x421335f7), SkBits2Float(0x423d8ca7));
+path.cubicTo(SkBits2Float(0x42217a65), SkBits2Float(0x4232780c), SkBits2Float(0x422e72e3), SkBits2Float(0x4225d023), SkBits2Float(0x4239e05a), SkBits2Float(0x4217d27c));
+path.lineTo(SkBits2Float(0x42809082), SkBits2Float(0x4252054e));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp268(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42003b3a), SkBits2Float(0xc2a60000), SkBits2Float(0x4274ff8d), SkBits2Float(0xc28113a0), SkBits2Float(0x4295fac2), SkBits2Float(0xc20e4c24));
+path.cubicTo(SkBits2Float(0x42b175be), SkBits2Float(0xc0d38840), SkBits2Float(0x42a91fa3), SkBits2Float(0x41dd6a3d), SkBits2Float(0x42809082), SkBits2Float(0x4252054e));
+path.cubicTo(SkBits2Float(0x4271521d), SkBits2Float(0x42655feb), SkBits2Float(0x425f60c7), SkBits2Float(0x4276e1ca), SkBits2Float(0x424ba43f), SkBits2Float(0x42831ae1));
+path.lineTo(SkBits2Float(0x421335f7), SkBits2Float(0x423d8ca7));
+path.cubicTo(SkBits2Float(0x42217a65), SkBits2Float(0x4232780c), SkBits2Float(0x422e72e3), SkBits2Float(0x4225d023), SkBits2Float(0x4239e059), SkBits2Float(0x4217d27c));
+path.cubicTo(SkBits2Float(0x4274841b), SkBits2Float(0x41a00f1c), SkBits2Float(0x428048c8), SkBits2Float(0xc098ea38), SkBits2Float(0x4258d681), SkBits2Float(0xc1cdbb32));
+path.cubicTo(SkBits2Float(0x42311b71), SkBits2Float(0xc23a9deb), SkBits2Float(0x41b96511), SkBits2Float(0xc2700000), SkBits2Float(0x3697ff52), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x424ba440), SkBits2Float(0x42831ae2));
+path.cubicTo(SkBits2Float(0x41bb72ba), SkBits2Float(0x42adc9b8), SkBits2Float(0xc16714ca), SkBits2Float(0x42b1a998), SkBits2Float(0xc22fd30d), SkBits2Float(0x428ccf5c));
+path.cubicTo(SkBits2Float(0xc292f074), SkBits2Float(0x424fea41), SkBits2Float(0xc2b0b757), SkBits2Float(0x4188cdbd), SkBits2Float(0xc2a27f7d), SkBits2Float(0xc187abb1));
+path.cubicTo(SkBits2Float(0xc29447a3), SkBits2Float(0xc24c1290), SkBits2Float(0xc23a2b5e), SkBits2Float(0xc29a0e93), SkBits2Float(0xc141f42b), SkBits2Float(0xc2a43853));
+path.lineTo(SkBits2Float(0xc10c3538), SkBits2Float(0xc26d6d31));
+path.cubicTo(SkBits2Float(0xc2069491), SkBits2Float(0xc25ebb9d), SkBits2Float(0xc2566164), SkBits2Float(0xc21385b2), SkBits2Float(0xc26aefd1), SkBits2Float(0xc1442672));
+path.cubicTo(SkBits2Float(0xc27f7e3e), SkBits2Float(0x4145c9dc), SkBits2Float(0xc2547130), SkBits2Float(0x42164ccc), SkBits2Float(0xc1fe3427), SkBits2Float(0x424b94a6));
+path.cubicTo(SkBits2Float(0xc1270bd9), SkBits2Float(0x42806e40), SkBits2Float(0x41878138), SkBits2Float(0x427b4278), SkBits2Float(0x421335f8), SkBits2Float(0x423d8ca8));
+path.lineTo(SkBits2Float(0x424ba440), SkBits2Float(0x42831ae2));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp269(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42011047), SkBits2Float(0xc2a60000), SkBits2Float(0x42766e56), SkBits2Float(0xc28099ef), SkBits2Float(0x42967824), SkBits2Float(0xc20c36c8));
+path.cubicTo(SkBits2Float(0x42b1b91c), SkBits2Float(0xc0b9cd9b), SkBits2Float(0x42a89b7a), SkBits2Float(0x41e5804f), SkBits2Float(0x427e310b), SkBits2Float(0x42559106));
+path.lineTo(SkBits2Float(0x4237c0bf), SkBits2Float(0x421a62ac));
+path.cubicTo(SkBits2Float(0x4273c506), SkBits2Float(0x41a5e791), SkBits2Float(0x4280797a), SkBits2Float(0xc08650bf), SkBits2Float(0x42598bc5), SkBits2Float(0xc1cab811));
+path.cubicTo(SkBits2Float(0x42322494), SkBits2Float(0xc239edfa), SkBits2Float(0x41ba9913), SkBits2Float(0xc2700002), SkBits2Float(0xb7060057), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x427e3109), SkBits2Float(0x42559108));
+path.cubicTo(SkBits2Float(0x426e0477), SkBits2Float(0x4268d13b), SkBits2Float(0x425bb575), SkBits2Float(0x427a2b1d), SkBits2Float(0x42479e2a), SkBits2Float(0x4284a4a0));
+path.lineTo(SkBits2Float(0x42104d52), SkBits2Float(0x423fc5ea));
+path.cubicTo(SkBits2Float(0x421ed35e), SkBits2Float(0x4234d83a), SkBits2Float(0x422c0f91), SkBits2Float(0x42284d3a), SkBits2Float(0x4237c0bf), SkBits2Float(0x421a62ad));
+path.lineTo(SkBits2Float(0x427e3109), SkBits2Float(0x42559108));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp270(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb7060057), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42011047), SkBits2Float(0xc2a60000), SkBits2Float(0x42766e56), SkBits2Float(0xc28099ef), SkBits2Float(0x42967824), SkBits2Float(0xc20c36c8));
+path.cubicTo(SkBits2Float(0x42b1b91c), SkBits2Float(0xc0b9cd9b), SkBits2Float(0x42a89b7a), SkBits2Float(0x41e5804f), SkBits2Float(0x427e310b), SkBits2Float(0x42559106));
+path.lineTo(SkBits2Float(0x4237c0bf), SkBits2Float(0x421a62ad));
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42479e29), SkBits2Float(0x4284a4a0));
+path.cubicTo(SkBits2Float(0x41af5d68), SkBits2Float(0x42aec1b4), SkBits2Float(0xc1822698), SkBits2Float(0x42b135a9), SkBits2Float(0xc2362f3e), SkBits2Float(0x428ac623));
+path.cubicTo(SkBits2Float(0xc295a599), SkBits2Float(0x4248ad36), SkBits2Float(0xc2b1c6ab), SkBits2Float(0x416a48a9), SkBits2Float(0xc2a165f3), SkBits2Float(0xc19b42cf));
+path.cubicTo(SkBits2Float(0xc291053c), SkBits2Float(0xc255d4f6), SkBits2Float(0xc22f520a), SkBits2Float(0xc29d68ba), SkBits2Float(0xc110422a), SkBits2Float(0xc2a50486));
+path.lineTo(SkBits2Float(0xc0d09136), SkBits2Float(0xc26e946c));
+path.cubicTo(SkBits2Float(0xc1fd79b9), SkBits2Float(0xc2639452), SkBits2Float(0xc251ab0b), SkBits2Float(0xc21a93c1), SkBits2Float(0xc26958c8), SkBits2Float(0xc1607927));
+path.cubicTo(SkBits2Float(0xc2808342), SkBits2Float(0x41295cae), SkBits2Float(0xc2585b55), SkBits2Float(0x42111142), SkBits2Float(0xc203b318), SkBits2Float(0x4248a313));
+path.cubicTo(SkBits2Float(0xc13c2b63), SkBits2Float(0x42801a73), SkBits2Float(0x417d8a30), SkBits2Float(0x427ca903), SkBits2Float(0x42104d56), SkBits2Float(0x423fc5e8));
+path.lineTo(SkBits2Float(0x42479e29), SkBits2Float(0x4284a4a0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp271(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4201b43a), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4277880a), SkBits2Float(0xc2803bc7), SkBits2Float(0x4296d747), SkBits2Float(0xc20a9b85));
+path.cubicTo(SkBits2Float(0x42b1ea89), SkBits2Float(0xc0a5fbe3), SkBits2Float(0x42a831cc), SkBits2Float(0x41ebb52f), SkBits2Float(0x427be65b), SkBits2Float(0x425843c9));
+path.lineTo(SkBits2Float(0x423618a6), SkBits2Float(0x421c5604));
+path.cubicTo(SkBits2Float(0x42732c40), SkBits2Float(0x41aa6424), SkBits2Float(0x42809d37), SkBits2Float(0xc06ffa1c), SkBits2Float(0x425a1555), SkBits2Float(0xc1c8657d));
+path.cubicTo(SkBits2Float(0x4232f03c), SkBits2Float(0xc23965db), SkBits2Float(0x41bb8620), SkBits2Float(0xc2700002), SkBits2Float(0xb5600574), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x427be65e), SkBits2Float(0x425843c9));
+path.cubicTo(SkBits2Float(0x426b71bd), SkBits2Float(0x426b6e8c), SkBits2Float(0x4258dad9), SkBits2Float(0x427ca87a), SkBits2Float(0x42447e14), SkBits2Float(0x4285cdfb));
+path.lineTo(SkBits2Float(0x420e0af4), SkBits2Float(0x424173d3));
+path.cubicTo(SkBits2Float(0x421cc338), SkBits2Float(0x4236a4f9), SkBits2Float(0x422a3361), SkBits2Float(0x422a3113), SkBits2Float(0x423618a6), SkBits2Float(0x421c5605));
+path.lineTo(SkBits2Float(0x427be65e), SkBits2Float(0x425843c9));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp272(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4201b43a), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4277880a), SkBits2Float(0xc2803bc7), SkBits2Float(0x4296d747), SkBits2Float(0xc20a9b85));
+path.cubicTo(SkBits2Float(0x42b1ea89), SkBits2Float(0xc0a5fbe3), SkBits2Float(0x42a831cc), SkBits2Float(0x41ebb52f), SkBits2Float(0x427be65b), SkBits2Float(0x425843c9));
+path.lineTo(SkBits2Float(0x427be65e), SkBits2Float(0x425843c9));
+path.cubicTo(SkBits2Float(0x426b71bd), SkBits2Float(0x426b6e8c), SkBits2Float(0x4258dad9), SkBits2Float(0x427ca87a), SkBits2Float(0x42447e14), SkBits2Float(0x4285cdfb));
+path.lineTo(SkBits2Float(0x420e0af4), SkBits2Float(0x424173d3));
+path.cubicTo(SkBits2Float(0x421cc338), SkBits2Float(0x4236a4f9), SkBits2Float(0x422a3361), SkBits2Float(0x422a3113), SkBits2Float(0x423618a6), SkBits2Float(0x421c5605));
+path.lineTo(SkBits2Float(0x423618a6), SkBits2Float(0x421c5604));
+path.cubicTo(SkBits2Float(0x42732c40), SkBits2Float(0x41aa6424), SkBits2Float(0x42809d37), SkBits2Float(0xc06ffa1c), SkBits2Float(0x425a1555), SkBits2Float(0xc1c8657d));
+path.cubicTo(SkBits2Float(0x4232f03c), SkBits2Float(0xc23965db), SkBits2Float(0x41bb8620), SkBits2Float(0xc2700002), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42447e16), SkBits2Float(0x4285cdfb));
+path.cubicTo(SkBits2Float(0x41a605d7), SkBits2Float(0x42af776a), SkBits2Float(0xc18d5e26), SkBits2Float(0x42b0cfa2), SkBits2Float(0xc23b02ad), SkBits2Float(0x428928e1));
+path.cubicTo(SkBits2Float(0xc297ab24), SkBits2Float(0x42430442), SkBits2Float(0xc2b27fa9), SkBits2Float(0x414bdf0d), SkBits2Float(0xc2a073c8), SkBits2Float(0xc1aa3a13));
+path.cubicTo(SkBits2Float(0xc28e67e7), SkBits2Float(0xc25d31d4), SkBits2Float(0xc226d0a4), SkBits2Float(0xc29fdb7e), SkBits2Float(0xc0d3d11a), SkBits2Float(0xc2a578a5));
+path.lineTo(SkBits2Float(0xc0991eb2), SkBits2Float(0xc26f3c4f));
+path.cubicTo(SkBits2Float(0xc1f12d9c), SkBits2Float(0xc2671e82), SkBits2Float(0xc24de350), SkBits2Float(0xc21fe656), SkBits2Float(0xc267faa7), SkBits2Float(0xc1761c74));
+path.cubicTo(SkBits2Float(0xc28108ff), SkBits2Float(0x4113607a), SkBits2Float(0xc25b4798), SkBits2Float(0x420cf9d1), SkBits2Float(0xc207302c), SkBits2Float(0x42464d9a));
+path.cubicTo(SkBits2Float(0xc14c6303), SkBits2Float(0x427fa162), SkBits2Float(0x4170087f), SkBits2Float(0x427dafb7), SkBits2Float(0x420e0af6), SkBits2Float(0x424173d2));
+path.lineTo(SkBits2Float(0x42447e16), SkBits2Float(0x4285cdfb));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp273(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42023f77), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427876e4), SkBits2Float(0xc27fd6f4), SkBits2Float(0x42972728), SkBits2Float(0xc2093dbb));
+path.cubicTo(SkBits2Float(0x42b212de), SkBits2Float(0xc0952410), SkBits2Float(0x42a7d55b), SkBits2Float(0x41f0f791), SkBits2Float(0x4279eebf), SkBits2Float(0x425a890b));
+path.lineTo(SkBits2Float(0x4234ac95), SkBits2Float(0x421dfa35));
+path.cubicTo(SkBits2Float(0x4272a697), SkBits2Float(0x41ae3171), SkBits2Float(0x4280ba5e), SkBits2Float(0xc057a00f), SkBits2Float(0x425a88d0), SkBits2Float(0xc1c66bc2));
+path.cubicTo(SkBits2Float(0x42339ce5), SkBits2Float(0xc238f1c1), SkBits2Float(0x41bc4f6b), SkBits2Float(0xc2700002), SkBits2Float(0xb630015d), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4279eebd), SkBits2Float(0x425a890e));
+path.cubicTo(SkBits2Float(0x42693cf3), SkBits2Float(0x426da0dc), SkBits2Float(0x42566929), SkBits2Float(0x427ebed8), SkBits2Float(0x4241d1ac), SkBits2Float(0x4286c6a2));
+path.lineTo(SkBits2Float(0x420c1c33), SkBits2Float(0x4242db53));
+path.cubicTo(SkBits2Float(0x421afee9), SkBits2Float(0x42382742), SkBits2Float(0x42289b18), SkBits2Float(0x422bc78f), SkBits2Float(0x4234ac94), SkBits2Float(0x421dfa34));
+path.lineTo(SkBits2Float(0x4279eebd), SkBits2Float(0x425a890e));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp274(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb630015d), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42023f77), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427876e4), SkBits2Float(0xc27fd6f4), SkBits2Float(0x42972728), SkBits2Float(0xc2093dbb));
+path.cubicTo(SkBits2Float(0x42b212de), SkBits2Float(0xc0952410), SkBits2Float(0x42a7d55b), SkBits2Float(0x41f0f791), SkBits2Float(0x4279eebf), SkBits2Float(0x425a890b));
+path.lineTo(SkBits2Float(0x4234ac95), SkBits2Float(0x421dfa35));
+path.cubicTo(SkBits2Float(0x4272a697), SkBits2Float(0x41ae3171), SkBits2Float(0x4280ba5e), SkBits2Float(0xc057a00f), SkBits2Float(0x425a88d0), SkBits2Float(0xc1c66bc2));
+path.cubicTo(SkBits2Float(0x42339ce5), SkBits2Float(0xc238f1c1), SkBits2Float(0x41bc4f6b), SkBits2Float(0xc2700002), SkBits2Float(0xb630015d), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4241d1ad), SkBits2Float(0x4286c6a2));
+path.cubicTo(SkBits2Float(0x419e0f8e), SkBits2Float(0x42b00b7b), SkBits2Float(0xc196dfc4), SkBits2Float(0x42b07042), SkBits2Float(0xc23f0fa7), SkBits2Float(0x4287c1be));
+path.cubicTo(SkBits2Float(0xc29957b6), SkBits2Float(0x423e2672), SkBits2Float(0xc2b30c7a), SkBits2Float(0x4131f351), SkBits2Float(0xc29f94d8), SkBits2Float(0xc1b6db1d));
+path.cubicTo(SkBits2Float(0xc28c1d38), SkBits2Float(0xc26357ee), SkBits2Float(0xc21f7d48), SkBits2Float(0xc2a1d87d), SkBits2Float(0xc09294c7), SkBits2Float(0xc2a5bf3c));
+path.lineTo(SkBits2Float(0xc053ec94), SkBits2Float(0xc26fa25d));
+path.cubicTo(SkBits2Float(0xc1e69644), SkBits2Float(0xc269fe64), SkBits2Float(0xc24a931a), SkBits2Float(0xc224583b), SkBits2Float(0xc266b858), SkBits2Float(0xc1842f59));
+path.cubicTo(SkBits2Float(0xc2816ecb), SkBits2Float(0x4100a388), SkBits2Float(0xc25db33b), SkBits2Float(0x42097539), SkBits2Float(0xc20a1dd2), SkBits2Float(0x4244465c));
+path.cubicTo(SkBits2Float(0xc15a2194), SkBits2Float(0x427f177f), SkBits2Float(0x41648588), SkBits2Float(0x427e85cc), SkBits2Float(0x420c1c35), SkBits2Float(0x4242db52));
+path.lineTo(SkBits2Float(0x4241d1ad), SkBits2Float(0x4286c6a2));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp275(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4202aab9), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42792ea4), SkBits2Float(0xc27f5acc), SkBits2Float(0x4297641b), SkBits2Float(0xc2082fee));
+path.cubicTo(SkBits2Float(0x42b230e5), SkBits2Float(0xc0882884), SkBits2Float(0x42a78c73), SkBits2Float(0x41f502e3), SkBits2Float(0x4278676f), SkBits2Float(0x425c4571));
+path.lineTo(SkBits2Float(0x423391b8), SkBits2Float(0x421f3b73));
+path.cubicTo(SkBits2Float(0x42723d33), SkBits2Float(0x41b11ddb), SkBits2Float(0x4280d014), SkBits2Float(0xc044db05), SkBits2Float(0x425ae0f2), SkBits2Float(0xc1c4e5b3));
+path.cubicTo(SkBits2Float(0x423421be), SkBits2Float(0xc2389802), SkBits2Float(0x41bcea83), SkBits2Float(0xc2700000), SkBits2Float(0x3725ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42786771), SkBits2Float(0x425c4570));
+path.cubicTo(SkBits2Float(0x42678692), SkBits2Float(0x426f4e2b), SkBits2Float(0x425483f6), SkBits2Float(0x42802b0f), SkBits2Float(0x423fbf6b), SkBits2Float(0x428783bc));
+path.lineTo(SkBits2Float(0x420a9ce1), SkBits2Float(0x4243ecb9));
+path.cubicTo(SkBits2Float(0x4219a02a), SkBits2Float(0x42394dac), SkBits2Float(0x42275e32), SkBits2Float(0x422cfde6), SkBits2Float(0x423391b8), SkBits2Float(0x421f3b72));
+path.lineTo(SkBits2Float(0x42786771), SkBits2Float(0x425c4570));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp276(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3725ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4202aab9), SkBits2Float(0xc2a5ffff), SkBits2Float(0x42792ea4), SkBits2Float(0xc27f5acc), SkBits2Float(0x4297641b), SkBits2Float(0xc2082fee));
+path.cubicTo(SkBits2Float(0x42b230e5), SkBits2Float(0xc0882884), SkBits2Float(0x42a78c73), SkBits2Float(0x41f502e3), SkBits2Float(0x4278676f), SkBits2Float(0x425c4571));
+path.cubicTo(SkBits2Float(0x42678690), SkBits2Float(0x426f4e2b), SkBits2Float(0x425483f5), SkBits2Float(0x42802b0f), SkBits2Float(0x423fbf6b), SkBits2Float(0x428783bc));
+path.lineTo(SkBits2Float(0x420a9ce1), SkBits2Float(0x4243ecb9));
+path.cubicTo(SkBits2Float(0x4219a02a), SkBits2Float(0x42394dac), SkBits2Float(0x42275e32), SkBits2Float(0x422cfde7), SkBits2Float(0x423391b8), SkBits2Float(0x421f3b73));
+path.lineTo(SkBits2Float(0x423391b8), SkBits2Float(0x421f3b72));
+path.cubicTo(SkBits2Float(0x42723d33), SkBits2Float(0x41b11dd9), SkBits2Float(0x4280d014), SkBits2Float(0xc044db09), SkBits2Float(0x425ae0f2), SkBits2Float(0xc1c4e5b3));
+path.cubicTo(SkBits2Float(0x423421be), SkBits2Float(0xc2389802), SkBits2Float(0x41bcea83), SkBits2Float(0xc2700000), SkBits2Float(0x3725ffa9), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423fbf6b), SkBits2Float(0x428783bc));
+path.cubicTo(SkBits2Float(0x4197e908), SkBits2Float(0x42b0799e), SkBits2Float(0xc19e2f01), SkBits2Float(0x42b0215b), SkBits2Float(0xc24226b0), SkBits2Float(0x4286a80b));
+path.cubicTo(SkBits2Float(0xc29a9aef), SkBits2Float(0x423a5d79), SkBits2Float(0xc2b36ebb), SkBits2Float(0x411dee4a), SkBits2Float(0xc29ede64), SkBits2Float(0xc1c087c1));
+path.cubicTo(SkBits2Float(0xc28a4e0d), SkBits2Float(0xc2680353), SkBits2Float(0xc219c8f7), SkBits2Float(0xc2a351d0), SkBits2Float(0xc0409740), SkBits2Float(0xc2a5e40e));
+path.lineTo(SkBits2Float(0xc00b391c), SkBits2Float(0xc26fd79b));
+path.cubicTo(SkBits2Float(0xc1de5701), SkBits2Float(0xc26c1feb), SkBits2Float(0xc247f576), SkBits2Float(0xc227b85e), SkBits2Float(0xc265b08d), SkBits2Float(0xc18b2dac));
+path.cubicTo(SkBits2Float(0xc281b5d1), SkBits2Float(0x40e45588), SkBits2Float(0xc25f8687), SkBits2Float(0x4206b8c8), SkBits2Float(0xc20c59a1), SkBits2Float(0x4242af19));
+path.cubicTo(SkBits2Float(0xc164b2eb), SkBits2Float(0x427ea56a), SkBits2Float(0x415ba119), SkBits2Float(0x427f2508), SkBits2Float(0x420a9ce0), SkBits2Float(0x4243ecba));
+path.lineTo(SkBits2Float(0x423fbf6b), SkBits2Float(0x428783bc));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp277(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4202f62b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4279afc7), SkBits2Float(0xc27f0340), SkBits2Float(0x42978eaf), SkBits2Float(0xc20771fd));
+path.cubicTo(SkBits2Float(0x42b2457b), SkBits2Float(0xc07e0b91), SkBits2Float(0x42a7584a), SkBits2Float(0x41f7da1e), SkBits2Float(0x42775276), SkBits2Float(0x425d7c3f));
+path.lineTo(SkBits2Float(0x4232c97e), SkBits2Float(0x42201c22));
+path.cubicTo(SkBits2Float(0x4271f1c7), SkBits2Float(0x41b32b8d), SkBits2Float(0x4280def3), SkBits2Float(0xc037a5cf), SkBits2Float(0x425b1e7c), SkBits2Float(0xc1c3d316));
+path.cubicTo(SkBits2Float(0x42347f10), SkBits2Float(0xc23858b9), SkBits2Float(0x41bd578b), SkBits2Float(0xc26fffff), SkBits2Float(0xb7240057), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42775277), SkBits2Float(0x425d7c41));
+path.cubicTo(SkBits2Float(0x4266507b), SkBits2Float(0x42707a20), SkBits2Float(0x42532cff), SkBits2Float(0x4280b928), SkBits2Float(0x423e48db), SkBits2Float(0x42880779));
+path.lineTo(SkBits2Float(0x42098e1c), SkBits2Float(0x4244ab32));
+path.cubicTo(SkBits2Float(0x4218a83e), SkBits2Float(0x423a1b21), SkBits2Float(0x42267e0b), SkBits2Float(0x422dd6be), SkBits2Float(0x4232c97e), SkBits2Float(0x42201c22));
+path.lineTo(SkBits2Float(0x42775277), SkBits2Float(0x425d7c41));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp278(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb7240057), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x4202f62b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x4279afc7), SkBits2Float(0xc27f0340), SkBits2Float(0x42978eaf), SkBits2Float(0xc20771fd));
+path.cubicTo(SkBits2Float(0x42b2457b), SkBits2Float(0xc07e0b91), SkBits2Float(0x42a7584a), SkBits2Float(0x41f7da1e), SkBits2Float(0x42775276), SkBits2Float(0x425d7c3f));
+path.lineTo(SkBits2Float(0x42775277), SkBits2Float(0x425d7c41));
+path.cubicTo(SkBits2Float(0x4266507b), SkBits2Float(0x42707a20), SkBits2Float(0x42532cff), SkBits2Float(0x4280b928), SkBits2Float(0x423e48db), SkBits2Float(0x42880779));
+path.lineTo(SkBits2Float(0x42098e1c), SkBits2Float(0x4244ab32));
+path.cubicTo(SkBits2Float(0x4218a83e), SkBits2Float(0x423a1b21), SkBits2Float(0x42267e0b), SkBits2Float(0x422dd6be), SkBits2Float(0x4232c97e), SkBits2Float(0x42201c22));
+path.cubicTo(SkBits2Float(0x4271f1c7), SkBits2Float(0x41b32b8d), SkBits2Float(0x4280def3), SkBits2Float(0xc037a5cf), SkBits2Float(0x425b1e7c), SkBits2Float(0xc1c3d316));
+path.cubicTo(SkBits2Float(0x42347f10), SkBits2Float(0xc23858b9), SkBits2Float(0x41bd578b), SkBits2Float(0xc26fffff), SkBits2Float(0xb7240057), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423e48db), SkBits2Float(0x4288077a));
+path.cubicTo(SkBits2Float(0x41939344), SkBits2Float(0x42b0c509), SkBits2Float(0xc1a3515b), SkBits2Float(0x42afe6ff), SkBits2Float(0xc2444efb), SkBits2Float(0x4285df44));
+path.cubicTo(SkBits2Float(0xc29b7aa2), SkBits2Float(0x4237af14), SkBits2Float(0xc2b3ae7d), SkBits2Float(0x410fd2d1), SkBits2Float(0xc29e5879), SkBits2Float(0xc1c74e5b));
+path.cubicTo(SkBits2Float(0xc2890275), SkBits2Float(0xc26b4310), SkBits2Float(0xc215bdd9), SkBits2Float(0xc2a45375), SkBits2Float(0xbff3abc7), SkBits2Float(0xc2a5f4d2));
+path.lineTo(SkBits2Float(0xbfb025f0), SkBits2Float(0xc26fefd6));
+path.cubicTo(SkBits2Float(0xc1d87e6f), SkBits2Float(0xc26d946b), SkBits2Float(0xc246160c), SkBits2Float(0xc22a11a0), SkBits2Float(0xc264eef0), SkBits2Float(0xc190139e));
+path.cubicTo(SkBits2Float(0xc281e3ea), SkBits2Float(0x40cff015), SkBits2Float(0xc260c9f8), SkBits2Float(0x4204c898), SkBits2Float(0xc20de8e2), SkBits2Float(0x42418cd3));
+path.cubicTo(SkBits2Float(0xc16c1f36), SkBits2Float(0x427e510e), SkBits2Float(0x41555c9e), SkBits2Float(0x427f9213), SkBits2Float(0x42098e1b), SkBits2Float(0x4244ab33));
+path.lineTo(SkBits2Float(0x423e48db), SkBits2Float(0x4288077a));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp279(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x420331e6), SkBits2Float(0xc2a60000), SkBits2Float(0x427a15f4), SkBits2Float(0xc27ebdd3), SkBits2Float(0x4297b03a), SkBits2Float(0xc206db86));
+path.cubicTo(SkBits2Float(0x42b2557a), SkBits2Float(0xc06f9378), SkBits2Float(0x42a72e7e), SkBits2Float(0x41fa194a), SkBits2Float(0x4276762d), SkBits2Float(0x425e7148));
+path.lineTo(SkBits2Float(0x42322a40), SkBits2Float(0x4220cd43));
+path.cubicTo(SkBits2Float(0x4271b558), SkBits2Float(0x41b4cb56), SkBits2Float(0x4280ea83), SkBits2Float(0xc02d3004), SkBits2Float(0x425b4efa), SkBits2Float(0xc1c2f986));
+path.cubicTo(SkBits2Float(0x4234c8ee), SkBits2Float(0xc2382686), SkBits2Float(0x41bdadf1), SkBits2Float(0xc26fffff), SkBits2Float(0x3707ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4276762e), SkBits2Float(0x425e7147));
+path.cubicTo(SkBits2Float(0x42655a01), SkBits2Float(0x42716669), SkBits2Float(0x42521c84), SkBits2Float(0x428128fd), SkBits2Float(0x423d1f69), SkBits2Float(0x42886f05));
+path.lineTo(SkBits2Float(0x4208b718), SkBits2Float(0x424540e7));
+path.cubicTo(SkBits2Float(0x4217e344), SkBits2Float(0x423abccf), SkBits2Float(0x4225cbdd), SkBits2Float(0x422e818f), SkBits2Float(0x42322a41), SkBits2Float(0x4220cd43));
+path.lineTo(SkBits2Float(0x4276762e), SkBits2Float(0x425e7147));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp280(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3707ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x420331e6), SkBits2Float(0xc2a60000), SkBits2Float(0x427a15f4), SkBits2Float(0xc27ebdd3), SkBits2Float(0x4297b03a), SkBits2Float(0xc206db86));
+path.cubicTo(SkBits2Float(0x42b2557a), SkBits2Float(0xc06f937f), SkBits2Float(0x42a72e7e), SkBits2Float(0x41fa1948), SkBits2Float(0x4276762e), SkBits2Float(0x425e7147));
+path.lineTo(SkBits2Float(0x4276762d), SkBits2Float(0x425e7148));
+path.cubicTo(SkBits2Float(0x42655a00), SkBits2Float(0x4271666a), SkBits2Float(0x42521c84), SkBits2Float(0x428128fd), SkBits2Float(0x423d1f69), SkBits2Float(0x42886f05));
+path.lineTo(SkBits2Float(0x4208b718), SkBits2Float(0x424540e7));
+path.cubicTo(SkBits2Float(0x4217e344), SkBits2Float(0x423abccf), SkBits2Float(0x4225cbdd), SkBits2Float(0x422e818f), SkBits2Float(0x42322a41), SkBits2Float(0x4220cd43));
+path.lineTo(SkBits2Float(0x42322a40), SkBits2Float(0x4220cd43));
+path.cubicTo(SkBits2Float(0x4271b558), SkBits2Float(0x41b4cb56), SkBits2Float(0x4280ea83), SkBits2Float(0xc02d3004), SkBits2Float(0x425b4efa), SkBits2Float(0xc1c2f986));
+path.cubicTo(SkBits2Float(0x4234c8ee), SkBits2Float(0xc2382686), SkBits2Float(0x41bdadf1), SkBits2Float(0xc26fffff), SkBits2Float(0x3707ffa9), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423d1f69), SkBits2Float(0x42886f06));
+path.cubicTo(SkBits2Float(0x4190236c), SkBits2Float(0x42b0ff8c), SkBits2Float(0xc1a760b7), SkBits2Float(0x42afb726), SkBits2Float(0xc24601c7), SkBits2Float(0x42853ece));
+path.cubicTo(SkBits2Float(0xc29c2998), SkBits2Float(0x42358ced), SkBits2Float(0xc2b3ddd5), SkBits2Float(0x4104a433), SkBits2Float(0xc29deb35), SkBits2Float(0xc1cca70e));
+path.cubicTo(SkBits2Float(0xc287f895), SkBits2Float(0xc26dd020), SkBits2Float(0xc21285d2), SkBits2Float(0xc2a51ade), SkBits2Float(0xbf83a2cf), SkBits2Float(0xc2a5fcbd));
+path.lineTo(SkBits2Float(0xbf3e53cf), SkBits2Float(0xc26ffb48));
+path.cubicTo(SkBits2Float(0xc1d3d71b), SkBits2Float(0xc26eb4b2), SkBits2Float(0xc24495a7), SkBits2Float(0xc22be9b4), SkBits2Float(0xc26450f5), SkBits2Float(0xc193f109));
+path.cubicTo(SkBits2Float(0xc2820621), SkBits2Float(0x40bfc558), SkBits2Float(0xc261c6ea), SkBits2Float(0x42033dc6), SkBits2Float(0xc20f2333), SkBits2Float(0x4240a4d2));
+path.cubicTo(SkBits2Float(0xc171fde8), SkBits2Float(0x427e0bde), SkBits2Float(0x4150649d), SkBits2Float(0x427fe6ab), SkBits2Float(0x4208b71a), SkBits2Float(0x424540e8));
+path.lineTo(SkBits2Float(0x423d1f69), SkBits2Float(0x42886f06));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp281(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42035955), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427a595d), SkBits2Float(0xc27e8fe6), SkBits2Float(0x4297c647), SkBits2Float(0xc206781b));
+path.cubicTo(SkBits2Float(0x42b25fdf), SkBits2Float(0xc0660504), SkBits2Float(0x42a712a2), SkBits2Float(0x41fb94c7), SkBits2Float(0x4275e43b), SkBits2Float(0x425f1290));
+path.lineTo(SkBits2Float(0x4231c0be), SkBits2Float(0x422141dc));
+path.cubicTo(SkBits2Float(0x42718d10), SkBits2Float(0x41b5ddaf), SkBits2Float(0x4280f208), SkBits2Float(0xc026476c), SkBits2Float(0x425b6edc), SkBits2Float(0xc1c269cb));
+path.cubicTo(SkBits2Float(0x4234f9ab), SkBits2Float(0xc2380553), SkBits2Float(0x41bde6f3), SkBits2Float(0xc26fffff), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x4275e43b), SkBits2Float(0x425f1292));
+path.cubicTo(SkBits2Float(0x4264b6c3), SkBits2Float(0x427201df), SkBits2Float(0x4251681e), SkBits2Float(0x42817283), SkBits2Float(0x423c5a8f), SkBits2Float(0x4288b309));
+path.lineTo(SkBits2Float(0x420828ca), SkBits2Float(0x4245a33c));
+path.cubicTo(SkBits2Float(0x421760db), SkBits2Float(0x423b2719), SkBits2Float(0x422555d9), SkBits2Float(0x422ef1ee), SkBits2Float(0x4231c0be), SkBits2Float(0x422141da));
+path.lineTo(SkBits2Float(0x4275e43b), SkBits2Float(0x425f1292));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp282(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42035955), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427a595d), SkBits2Float(0xc27e8fe6), SkBits2Float(0x4297c647), SkBits2Float(0xc206781b));
+path.cubicTo(SkBits2Float(0x42b25fdf), SkBits2Float(0xc0660504), SkBits2Float(0x42a712a2), SkBits2Float(0x41fb94c7), SkBits2Float(0x4275e43b), SkBits2Float(0x425f1290));
+path.lineTo(SkBits2Float(0x4275e43b), SkBits2Float(0x425f1292));
+path.cubicTo(SkBits2Float(0x4264b6c3), SkBits2Float(0x427201df), SkBits2Float(0x4251681e), SkBits2Float(0x42817283), SkBits2Float(0x423c5a8f), SkBits2Float(0x4288b309));
+path.lineTo(SkBits2Float(0x420828ca), SkBits2Float(0x4245a33c));
+path.cubicTo(SkBits2Float(0x421760db), SkBits2Float(0x423b2719), SkBits2Float(0x422555d9), SkBits2Float(0x422ef1f0), SkBits2Float(0x4231c0be), SkBits2Float(0x422141dc));
+path.cubicTo(SkBits2Float(0x42718d10), SkBits2Float(0x41b5ddaf), SkBits2Float(0x4280f208), SkBits2Float(0xc026476c), SkBits2Float(0x425b6edc), SkBits2Float(0xc1c269cb));
+path.cubicTo(SkBits2Float(0x4234f9ab), SkBits2Float(0xc2380553), SkBits2Float(0x41bde6f3), SkBits2Float(0xc26fffff), SkBits2Float(0x3637fea5), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423c5a8f), SkBits2Float(0x4288b30a));
+path.cubicTo(SkBits2Float(0x418dddd4), SkBits2Float(0x42b12599), SkBits2Float(0xc1aa0e7c), SkBits2Float(0x42af96c0), SkBits2Float(0xc2471fb7), SkBits2Float(0x4284d41e));
+path.cubicTo(SkBits2Float(0xc29c9c18), SkBits2Float(0x423422f8), SkBits2Float(0xc2b3fb95), SkBits2Float(0x40fa8096), SkBits2Float(0xc29da17e), SkBits2Float(0xc1d02ca0));
+path.cubicTo(SkBits2Float(0xc2874768), SkBits2Float(0xc26f7cb1), SkBits2Float(0xc2106396), SkBits2Float(0xc2a59c4c), SkBits2Float(0xbee6b152), SkBits2Float(0xc2a5ff5f));
+path.lineTo(SkBits2Float(0xbea6c49b), SkBits2Float(0xc26fff18));
+path.cubicTo(SkBits2Float(0xc1d0c156), SkBits2Float(0xc26f6fd8), SkBits2Float(0xc2439580), SkBits2Float(0xc22d1f86), SkBits2Float(0xc263e663), SkBits2Float(0xc1967cc0));
+path.cubicTo(SkBits2Float(0xc2821ba4), SkBits2Float(0x40b51622), SkBits2Float(0xc2626c73), SkBits2Float(0x4202381f), SkBits2Float(0xc20ff1e5), SkBits2Float(0x42400a93));
+path.cubicTo(SkBits2Float(0xc175dd55), SkBits2Float(0x427ddd08), SkBits2Float(0x414d1bd1), SkBits2Float(0x42800ed7), SkBits2Float(0x420828d0), SkBits2Float(0x4245a338));
+path.lineTo(SkBits2Float(0x423c5a8f), SkBits2Float(0x4288b30a));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp283(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return; // draws wrong
+ }
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42036bf7), SkBits2Float(0xc2a60000), SkBits2Float(0x427a7934), SkBits2Float(0xc27e7a35), SkBits2Float(0x4297d0ad), SkBits2Float(0xc2064926));
+path.cubicTo(SkBits2Float(0x42b264c0), SkBits2Float(0xc061818a), SkBits2Float(0x42a70569), SkBits2Float(0x41fc47ee), SkBits2Float(0x42759f2d), SkBits2Float(0x425f5e99));
+path.lineTo(SkBits2Float(0x42318ed2), SkBits2Float(0x422178d2));
+path.cubicTo(SkBits2Float(0x427179f2), SkBits2Float(0x41b65f2f), SkBits2Float(0x4280f58f), SkBits2Float(0xc0230424), SkBits2Float(0x425b7de6), SkBits2Float(0xc1c225e6));
+path.cubicTo(SkBits2Float(0x423510af), SkBits2Float(0xc237f5a4), SkBits2Float(0x41be01e5), SkBits2Float(0xc26fffff), SkBits2Float(0x3707ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42759f2b), SkBits2Float(0x425f5e9b));
+path.cubicTo(SkBits2Float(0x42646988), SkBits2Float(0x42724b20), SkBits2Float(0x425112cb), SkBits2Float(0x42819524), SkBits2Float(0x423bfd7a), SkBits2Float(0x4288d30e));
+path.lineTo(SkBits2Float(0x4207e580), SkBits2Float(0x4245d187));
+path.cubicTo(SkBits2Float(0x4217232e), SkBits2Float(0x423b592c), SkBits2Float(0x42251e07), SkBits2Float(0x422f26e4), SkBits2Float(0x42318ed3), SkBits2Float(0x422178d2));
+path.lineTo(SkBits2Float(0x42759f2b), SkBits2Float(0x425f5e9b));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp284(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3707ffa9), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42036bf7), SkBits2Float(0xc2a60000), SkBits2Float(0x427a7934), SkBits2Float(0xc27e7a35), SkBits2Float(0x4297d0ad), SkBits2Float(0xc2064926));
+path.cubicTo(SkBits2Float(0x42b264c0), SkBits2Float(0xc061818a), SkBits2Float(0x42a70569), SkBits2Float(0x41fc47ee), SkBits2Float(0x42759f2d), SkBits2Float(0x425f5e99));
+path.lineTo(SkBits2Float(0x42318ed3), SkBits2Float(0x422178d2));
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bfd7a), SkBits2Float(0x4288d30e));
+path.cubicTo(SkBits2Float(0x418ccafd), SkBits2Float(0x42b13768), SkBits2Float(0xc1ab522b), SkBits2Float(0x42af873b), SkBits2Float(0xc247a66c), SkBits2Float(0x4284a188));
+path.cubicTo(SkBits2Float(0xc29cd1e0), SkBits2Float(0x423377ac), SkBits2Float(0xc2b40936), SkBits2Float(0x40f384e7), SkBits2Float(0xc29d7e41), SkBits2Float(0xc1d1d5b9));
+path.cubicTo(SkBits2Float(0xc286f34a), SkBits2Float(0xc2704657), SkBits2Float(0xc20f6108), SkBits2Float(0xc2a5d8cf), SkBits2Float(0xbe35f437), SkBits2Float(0xc2a5ffe6));
+path.lineTo(SkBits2Float(0xbe038989), SkBits2Float(0xc26fffdc));
+path.cubicTo(SkBits2Float(0xc1cf4b80), SkBits2Float(0xc26fc755), SkBits2Float(0xc2431bdf), SkBits2Float(0xc22db14d), SkBits2Float(0xc263b36c), SkBits2Float(0xc197b016));
+path.cubicTo(SkBits2Float(0xc282257d), SkBits2Float(0x40b009af), SkBits2Float(0xc262ba31), SkBits2Float(0x4201bc49), SkBits2Float(0xc2105343), SkBits2Float(0x423fc16f));
+path.cubicTo(SkBits2Float(0xc177b158), SkBits2Float(0x427dc695), SkBits2Float(0x414b8e67), SkBits2Float(0x42801bb6), SkBits2Float(0x4207e581), SkBits2Float(0x4245d188));
+path.lineTo(SkBits2Float(0x423bfd7a), SkBits2Float(0x4288d30e));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp285(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x420374f9), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427a8897), SkBits2Float(0xc27e6fb3), SkBits2Float(0x4297d5b1), SkBits2Float(0xc2063270));
+path.cubicTo(SkBits2Float(0x42b26718), SkBits2Float(0xc05f52ba), SkBits2Float(0x42a6ff00), SkBits2Float(0x41fc9e87), SkBits2Float(0x42757dbf), SkBits2Float(0x425f8353));
+path.lineTo(SkBits2Float(0x423176ab), SkBits2Float(0x4221935e));
+path.cubicTo(SkBits2Float(0x427170b0), SkBits2Float(0x41b69dc5), SkBits2Float(0x4280f73f), SkBits2Float(0xc0217057), SkBits2Float(0x425b8525), SkBits2Float(0xc1c20512));
+path.cubicTo(SkBits2Float(0x42351bcc), SkBits2Float(0xc237ee0d), SkBits2Float(0x41be0ee4), SkBits2Float(0xc26fffff), SkBits2Float(0xb630015b), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757dc1), SkBits2Float(0x425f8353));
+path.cubicTo(SkBits2Float(0x4264442b), SkBits2Float(0x42726e80), SkBits2Float(0x4250e985), SkBits2Float(0x4281a5dc), SkBits2Float(0x423bd072), SkBits2Float(0x4288e283));
+path.lineTo(SkBits2Float(0x4207c4f4), SkBits2Float(0x4245e7df));
+path.cubicTo(SkBits2Float(0x42170559), SkBits2Float(0x423b7158), SkBits2Float(0x42250305), SkBits2Float(0x422f4076), SkBits2Float(0x423176ac), SkBits2Float(0x4221935e));
+path.lineTo(SkBits2Float(0x42757dc1), SkBits2Float(0x425f8353));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp286(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb630015b), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x420374f9), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427a8897), SkBits2Float(0xc27e6fb3), SkBits2Float(0x4297d5b1), SkBits2Float(0xc2063270));
+path.cubicTo(SkBits2Float(0x42b26718), SkBits2Float(0xc05f52c1), SkBits2Float(0x42a6ff01), SkBits2Float(0x41fc9e87), SkBits2Float(0x42757dc1), SkBits2Float(0x425f8353));
+path.cubicTo(SkBits2Float(0x4264442b), SkBits2Float(0x42726e80), SkBits2Float(0x4250e985), SkBits2Float(0x4281a5dc), SkBits2Float(0x423bd072), SkBits2Float(0x4288e283));
+path.lineTo(SkBits2Float(0x4207c4f4), SkBits2Float(0x4245e7df));
+path.cubicTo(SkBits2Float(0x42170559), SkBits2Float(0x423b7158), SkBits2Float(0x42250305), SkBits2Float(0x422f4076), SkBits2Float(0x423176ab), SkBits2Float(0x4221935e));
+path.cubicTo(SkBits2Float(0x427170b0), SkBits2Float(0x41b69dc5), SkBits2Float(0x4280f73f), SkBits2Float(0xc0217057), SkBits2Float(0x425b8525), SkBits2Float(0xc1c20512));
+path.cubicTo(SkBits2Float(0x42351bcc), SkBits2Float(0xc237ee0d), SkBits2Float(0x41be0ee4), SkBits2Float(0xc26fffff), SkBits2Float(0xb630015b), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bd073), SkBits2Float(0x4288e283));
+path.cubicTo(SkBits2Float(0x418c461b), SkBits2Float(0x42b13ffc), SkBits2Float(0xc1abee9c), SkBits2Float(0x42af7fac), SkBits2Float(0xc247e775), SkBits2Float(0x42848907));
+path.cubicTo(SkBits2Float(0xc29cebcd), SkBits2Float(0x423324c4), SkBits2Float(0xc2b40fb2), SkBits2Float(0x40f02474), SkBits2Float(0xc29d6d1c), SkBits2Float(0xc1d2a316));
+path.cubicTo(SkBits2Float(0xc286ca87), SkBits2Float(0xc270a7a6), SkBits2Float(0xc20ee3ea), SkBits2Float(0xc2a5f5e9), SkBits2Float(0xbd3ba09e), SkBits2Float(0xc2a5fffd));
+path.lineTo(SkBits2Float(0xbd0796d7), SkBits2Float(0xc26ffffe));
+path.cubicTo(SkBits2Float(0xc1ce9695), SkBits2Float(0xc26ff16b), SkBits2Float(0xc242e0ee), SkBits2Float(0xc22df7a5), SkBits2Float(0xc2639aa3), SkBits2Float(0xc198448c));
+path.cubicTo(SkBits2Float(0xc2822a2c), SkBits2Float(0x40ad98d0), SkBits2Float(0xc262dfac), SkBits2Float(0x4201805e), SkBits2Float(0xc2108243), SkBits2Float(0x423f9e03));
+path.cubicTo(SkBits2Float(0xc178936c), SkBits2Float(0x427dbba8), SkBits2Float(0x414ace5d), SkBits2Float(0x428021e8), SkBits2Float(0x4207c4fa), SkBits2Float(0x4245e7dc));
+path.lineTo(SkBits2Float(0x423bd073), SkBits2Float(0x4288e283));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp287(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x420377c9), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8d67), SkBits2Float(0xc27e6c6d), SkBits2Float(0x4297d744), SkBits2Float(0xc2062b59));
+path.cubicTo(SkBits2Float(0x42b267d3), SkBits2Float(0xc05ea43d), SkBits2Float(0x42a6fd01), SkBits2Float(0x41fcb991), SkBits2Float(0x42757351), SkBits2Float(0x425f8ecb));
+path.lineTo(SkBits2Float(0x42316f1e), SkBits2Float(0x42219ba8));
+path.cubicTo(SkBits2Float(0x42716dc9), SkBits2Float(0x41b6b154), SkBits2Float(0x4280f7c8), SkBits2Float(0xc020f212), SkBits2Float(0x425b876b), SkBits2Float(0xc1c1fad0));
+path.cubicTo(SkBits2Float(0x42351f48), SkBits2Float(0xc237ebae), SkBits2Float(0x41be12f9), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757350), SkBits2Float(0x425f8ecb));
+path.cubicTo(SkBits2Float(0x42643881), SkBits2Float(0x4272798e), SkBits2Float(0x4250dca0), SkBits2Float(0x4281ab15), SkBits2Float(0x423bc262), SkBits2Float(0x4288e756));
+path.lineTo(SkBits2Float(0x4207bac8), SkBits2Float(0x4245eed9));
+path.cubicTo(SkBits2Float(0x4216fc05), SkBits2Float(0x423b78e5), SkBits2Float(0x4224fa94), SkBits2Float(0x422f4874), SkBits2Float(0x42316f1f), SkBits2Float(0x42219baa));
+path.lineTo(SkBits2Float(0x42757350), SkBits2Float(0x425f8ecb));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp288(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x420377c9), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8d67), SkBits2Float(0xc27e6c6d), SkBits2Float(0x4297d744), SkBits2Float(0xc2062b59));
+path.cubicTo(SkBits2Float(0x42b267d3), SkBits2Float(0xc05ea43d), SkBits2Float(0x42a6fd01), SkBits2Float(0x41fcb991), SkBits2Float(0x42757351), SkBits2Float(0x425f8ecb));
+path.lineTo(SkBits2Float(0x423bc262), SkBits2Float(0x4288e756));
+path.lineTo(SkBits2Float(0x4207bac8), SkBits2Float(0x4245eed9));
+path.cubicTo(SkBits2Float(0x4216fc05), SkBits2Float(0x423b78e5), SkBits2Float(0x4224fa94), SkBits2Float(0x422f4874), SkBits2Float(0x42316f1f), SkBits2Float(0x42219baa));
+path.lineTo(SkBits2Float(0x42316f1e), SkBits2Float(0x42219ba8));
+path.cubicTo(SkBits2Float(0x42716dc9), SkBits2Float(0x41b6b154), SkBits2Float(0x4280f7c8), SkBits2Float(0xc020f212), SkBits2Float(0x425b876b), SkBits2Float(0xc1c1fad0));
+path.cubicTo(SkBits2Float(0x42351f48), SkBits2Float(0xc237ebae), SkBits2Float(0x41be12f9), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc261), SkBits2Float(0x4288e756));
+path.cubicTo(SkBits2Float(0x418c1c95), SkBits2Float(0x42b142a6), SkBits2Float(0xc1ac1f7e), SkBits2Float(0x42af7d4d), SkBits2Float(0xc247fbc6), SkBits2Float(0x4284815d));
+path.cubicTo(SkBits2Float(0xc29cf3e6), SkBits2Float(0x42330ad8), SkBits2Float(0xc2b411b5), SkBits2Float(0x40ef163d), SkBits2Float(0xc29d67bc), SkBits2Float(0xc1d2e345));
+path.cubicTo(SkBits2Float(0xc286bdc4), SkBits2Float(0xc270c60d), SkBits2Float(0xc20ebcc7), SkBits2Float(0xc2a5feff), SkBits2Float(0xbb958372), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0xbb591ee2), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce5e0c), SkBits2Float(0xc26ffe8b), SkBits2Float(0xc242ce80), SkBits2Float(0xc22e0d9d), SkBits2Float(0xc26392e3), SkBits2Float(0xc19872ed));
+path.cubicTo(SkBits2Float(0xc2822ba3), SkBits2Float(0x40acd588), SkBits2Float(0xc262eb66), SkBits2Float(0x42016da1), SkBits2Float(0xc21090f8), SkBits2Float(0x423f92f0));
+path.cubicTo(SkBits2Float(0xc178da2a), SkBits2Float(0x427db83e), SkBits2Float(0x414a923f), SkBits2Float(0x428023d8), SkBits2Float(0x4207baca), SkBits2Float(0x4245eed8));
+path.lineTo(SkBits2Float(0x423bc261), SkBits2Float(0x4288e756));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp289(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp290(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp291(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp292(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp293(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp294(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp295(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp296(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp297(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp298(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp299(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp300(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp301(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp302(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp303(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp304(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp305(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp306(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp307(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp308(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp309(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp310(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp311(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp312(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp313(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp314(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp315(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp316(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp317(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp318(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp319(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp320(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp321(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp322(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp323(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp324(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp325(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp326(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp327(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp328(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp329(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp330(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp331(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp332(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp333(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp334(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp335(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp336(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp337(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp338(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp339(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp340(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp341(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp342(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp343(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp344(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp345(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp346(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp347(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3d570205), SkBits2Float(0xc2a60000), SkBits2Float(0x3dd7026d), SkBits2Float(0xc2a5fffa), SkBits2Float(0x3e2141e6), SkBits2Float(0xc2a5ffed));
+path.lineTo(SkBits2Float(0x3de92565), SkBits2Float(0xc26fffe4));
+path.cubicTo(SkBits2Float(0x3d9b6fac), SkBits2Float(0xc26ffff9), SkBits2Float(0x3d1b715b), SkBits2Float(0xc2700002), SkBits2Float(0x365677c0), SkBits2Float(0xc2700002));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3e214267), SkBits2Float(0xc2a5ffec));
+path.cubicTo(SkBits2Float(0x3e26a1f2), SkBits2Float(0xc2a5ffeb), SkBits2Float(0x3e2c025b), SkBits2Float(0xc2a5ffe9), SkBits2Float(0x3e3162c6), SkBits2Float(0xc2a5ffe7));
+path.lineTo(SkBits2Float(0x3e003af5), SkBits2Float(0xc26fffde));
+path.cubicTo(SkBits2Float(0x3df8b0d2), SkBits2Float(0xc26fffe0), SkBits2Float(0x3df0ead2), SkBits2Float(0xc26fffe2), SkBits2Float(0x3de924d4), SkBits2Float(0xc26fffe4));
+path.lineTo(SkBits2Float(0x3e214267), SkBits2Float(0xc2a5ffec));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp348(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x365677c0), SkBits2Float(0xc2700002));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3d570205), SkBits2Float(0xc2a60000), SkBits2Float(0x3dd7026d), SkBits2Float(0xc2a5fffa), SkBits2Float(0x3e2141e6), SkBits2Float(0xc2a5ffed));
+path.lineTo(SkBits2Float(0x3e0492ca), SkBits2Float(0xc28878a2));
+path.lineTo(SkBits2Float(0x3e214267), SkBits2Float(0xc2a5ffec));
+path.cubicTo(SkBits2Float(0x3e26a1f2), SkBits2Float(0xc2a5ffeb), SkBits2Float(0x3e2c025b), SkBits2Float(0xc2a5ffe9), SkBits2Float(0x3e3162c6), SkBits2Float(0xc2a5ffe7));
+path.lineTo(SkBits2Float(0x3e003af5), SkBits2Float(0xc26fffde));
+path.lineTo(SkBits2Float(0x3de92565), SkBits2Float(0xc26fffe4));
+path.lineTo(SkBits2Float(0x3de924d4), SkBits2Float(0xc26fffe4));
+path.cubicTo(SkBits2Float(0x3d9b6f4b), SkBits2Float(0xc26ffff9), SkBits2Float(0x3d1b70fa), SkBits2Float(0xc2700002), SkBits2Float(0x365677c0), SkBits2Float(0xc2700002));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3e3162a4), SkBits2Float(0xc2a5ffe8));
+path.cubicTo(SkBits2Float(0x3e843f51), SkBits2Float(0xc2a5ffd1), SkBits2Float(0x3eafcce9), SkBits2Float(0xc2a5ffa8), SkBits2Float(0x3edb5a6f), SkBits2Float(0xc2a5ff6f));
+path.lineTo(SkBits2Float(0x3e9e9160), SkBits2Float(0xc26fff2e));
+path.cubicTo(SkBits2Float(0x3e7e2aec), SkBits2Float(0xc26fff82), SkBits2Float(0x3e3f3306), SkBits2Float(0xc26fffbd), SkBits2Float(0x3e003b0e), SkBits2Float(0xc26fffdf));
+path.lineTo(SkBits2Float(0x3e3162a4), SkBits2Float(0xc2a5ffe8));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp349(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e678fda), SkBits2Float(0xc2a60000), SkBits2Float(0x3ee78f7d), SkBits2Float(0xc2a5ff87), SkBits2Float(0x3f2dab18), SkBits2Float(0xc2a5fe96));
+path.lineTo(SkBits2Float(0x3efb15d4), SkBits2Float(0xc26ffdf3));
+path.cubicTo(SkBits2Float(0x3ea764ab), SkBits2Float(0xc26fff52), SkBits2Float(0x3e2764f3), SkBits2Float(0xc2700000), SkBits2Float(0x35c73da0), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f2daad3), SkBits2Float(0xc2a5fe95));
+path.cubicTo(SkBits2Float(0x3f3374d8), SkBits2Float(0xc2a5fe7b), SkBits2Float(0x3f393eae), SkBits2Float(0xc2a5fe62), SkBits2Float(0x3f3f0885), SkBits2Float(0xc2a5fe46));
+path.lineTo(SkBits2Float(0x3f0a18b8), SkBits2Float(0xc26ffd84));
+path.cubicTo(SkBits2Float(0x3f05e964), SkBits2Float(0xc26ffdad), SkBits2Float(0x3f01ba2f), SkBits2Float(0xc26ffdd1), SkBits2Float(0x3efb15f0), SkBits2Float(0xc26ffdf5));
+path.lineTo(SkBits2Float(0x3f2daad3), SkBits2Float(0xc2a5fe95));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp350(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e678fda), SkBits2Float(0xc2a60000), SkBits2Float(0x3ee78f7d), SkBits2Float(0xc2a5ff87), SkBits2Float(0x3f2dab18), SkBits2Float(0xc2a5fe96));
+path.cubicTo(SkBits2Float(0x3f3374d8), SkBits2Float(0xc2a5fe7b), SkBits2Float(0x3f393eae), SkBits2Float(0xc2a5fe62), SkBits2Float(0x3f3f0885), SkBits2Float(0xc2a5fe46));
+path.lineTo(SkBits2Float(0x3f0a18b8), SkBits2Float(0xc26ffd84));
+path.cubicTo(SkBits2Float(0x3f05e964), SkBits2Float(0xc26ffdad), SkBits2Float(0x3f01ba2f), SkBits2Float(0xc26ffdd1), SkBits2Float(0x3efb15f0), SkBits2Float(0xc26ffdf5));
+path.lineTo(SkBits2Float(0x3efb15d4), SkBits2Float(0xc26ffdf3));
+path.cubicTo(SkBits2Float(0x3ea764ab), SkBits2Float(0xc26fff52), SkBits2Float(0x3e2764f3), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f3f0899), SkBits2Float(0xc2a5fe48));
+path.cubicTo(SkBits2Float(0x3f8e6b81), SkBits2Float(0xc2a5fc98), SkBits2Float(0x3fbd51fb), SkBits2Float(0xc2a5f9aa), SkBits2Float(0x3fec36d3), SkBits2Float(0xc2a5f57e));
+path.lineTo(SkBits2Float(0x3faac1d7), SkBits2Float(0xc26ff0d0));
+path.cubicTo(SkBits2Float(0x3f88dbac), SkBits2Float(0xc26ff6d7), SkBits2Float(0x3f4de8bb), SkBits2Float(0xc26ffb13), SkBits2Float(0x3f0a18e7), SkBits2Float(0xc26ffd83));
+path.lineTo(SkBits2Float(0x3f3f0899), SkBits2Float(0xc2a5fe48));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp351(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x403f62fc), SkBits2Float(0xc2a60000), SkBits2Float(0x40bf510b), SkBits2Float(0xc2a5ad41), SkBits2Float(0x410f39cc), SkBits2Float(0xc2a50821));
+path.lineTo(SkBits2Float(0x40cf12cc), SkBits2Float(0xc26e99a0));
+path.cubicTo(SkBits2Float(0x408a4d18), SkBits2Float(0xc26f885f), SkBits2Float(0x400a5a13), SkBits2Float(0xc2700000), SkBits2Float(0x36a6ff52), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x410f39cd), SkBits2Float(0xc2a50820));
+path.cubicTo(SkBits2Float(0x4113fb3b), SkBits2Float(0xc2a4f79d), SkBits2Float(0x4118bbf1), SkBits2Float(0xc2a4e648), SkBits2Float(0x411d7be1), SkBits2Float(0xc2a4d421));
+path.lineTo(SkBits2Float(0x40e3b008), SkBits2Float(0xc26e4e75));
+path.cubicTo(SkBits2Float(0x40dcd206), SkBits2Float(0xc26e68b4), SkBits2Float(0x40d5f2eb), SkBits2Float(0xc26e81c3), SkBits2Float(0x40cf12c6), SkBits2Float(0xc26e99a1));
+path.lineTo(SkBits2Float(0x410f39cd), SkBits2Float(0xc2a50820));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp352(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e0b17a8), SkBits2Float(0xc2a60000), SkBits2Float(0x3e8b179e), SkBits2Float(0xc2a5ffd4), SkBits2Float(0x3ed0a337), SkBits2Float(0xc2a5ff7c));
+path.lineTo(SkBits2Float(0x3ed0a338), SkBits2Float(0xc2a5ff7d));
+path.cubicTo(SkBits2Float(0x3ed797a0), SkBits2Float(0xc2a5ff73), SkBits2Float(0x3ede8c36), SkBits2Float(0xc2a5ff6a), SkBits2Float(0x3ee580cb), SkBits2Float(0xc2a5ff60));
+path.lineTo(SkBits2Float(0x3ea5e78a), SkBits2Float(0xc26fff1b));
+path.cubicTo(SkBits2Float(0x3ea0e0bb), SkBits2Float(0xc26fff29), SkBits2Float(0x3e9bd9a1), SkBits2Float(0xc26fff36), SkBits2Float(0x3e96d286), SkBits2Float(0xc26fff43));
+path.lineTo(SkBits2Float(0x3e96d285), SkBits2Float(0xc26fff42));
+path.cubicTo(SkBits2Float(0x3e491945), SkBits2Float(0xc26fffc2), SkBits2Float(0x3dc91958), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ee58048), SkBits2Float(0xc2a5ff61));
+path.cubicTo(SkBits2Float(0x3f2b1987), SkBits2Float(0xc2a5fec4), SkBits2Float(0x3f637253), SkBits2Float(0xc2a5fdb6), SkBits2Float(0x3f8de535), SkBits2Float(0xc2a5fc35));
+path.lineTo(SkBits2Float(0x3f4d269a), SkBits2Float(0xc26ffa85));
+path.cubicTo(SkBits2Float(0x3f246b51), SkBits2Float(0xc26ffcb3), SkBits2Float(0x3ef75f30), SkBits2Float(0xc26ffe3a), SkBits2Float(0x3ea5e737), SkBits2Float(0xc26fff1c));
+path.lineTo(SkBits2Float(0x3ee58048), SkBits2Float(0xc2a5ff61));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp1390(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0xb7240057), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x420377ff), SkBits2Float(0xc2a5ffff), SkBits2Float(0x427a8dc0), SkBits2Float(0xc27e6c2f), SkBits2Float(0x4297d760), SkBits2Float(0xc2062ad2));
+path.cubicTo(SkBits2Float(0x42b267e1), SkBits2Float(0xc05e974f), SkBits2Float(0x42a6fcda), SkBits2Float(0x41fcbb92), SkBits2Float(0x42757289), SkBits2Float(0x425f8fa5));
+path.cubicTo(SkBits2Float(0x426437a0), SkBits2Float(0x42727a5f), SkBits2Float(0x4250dbaa), SkBits2Float(0x4281ab79), SkBits2Float(0x423bc155), SkBits2Float(0x4288e7b2));
+path.lineTo(SkBits2Float(0x4207ba06), SkBits2Float(0x4245ef5e));
+path.cubicTo(SkBits2Float(0x4216fb52), SkBits2Float(0x423b7973), SkBits2Float(0x4224f9f2), SkBits2Float(0x422f490a), SkBits2Float(0x42316e8e), SkBits2Float(0x42219c46));
+path.cubicTo(SkBits2Float(0x42716d91), SkBits2Float(0x41b6b2c9), SkBits2Float(0x4280f7d1), SkBits2Float(0xc020e8c8), SkBits2Float(0x425b8794), SkBits2Float(0xc1c1fa0e));
+path.cubicTo(SkBits2Float(0x42351f87), SkBits2Float(0xc237eb83), SkBits2Float(0x41be1342), SkBits2Float(0xc2700002), SkBits2Float(0xb7240057), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc156), SkBits2Float(0x4288e7b2));
+path.cubicTo(SkBits2Float(0x418c1984), SkBits2Float(0x42b142da), SkBits2Float(0xc1ac2314), SkBits2Float(0x42af7d21), SkBits2Float(0xc247fd43), SkBits2Float(0x428480ce));
+path.cubicTo(SkBits2Float(0xc29cf47f), SkBits2Float(0x423308f3), SkBits2Float(0xc2b411dd), SkBits2Float(0x40ef0242), SkBits2Float(0xc29d6757), SkBits2Float(0xc1d2e807));
+path.cubicTo(SkBits2Float(0xc286bcd2), SkBits2Float(0xc270c84c), SkBits2Float(0xc20eb9e2), SkBits2Float(0xc2a5ffaa), SkBits2Float(0xbac6f0ca), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0xba901698), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce59d7), SkBits2Float(0xc26fff83), SkBits2Float(0xc242cd21), SkBits2Float(0xc22e0f3f), SkBits2Float(0xc263924f), SkBits2Float(0xc1987661));
+path.cubicTo(SkBits2Float(0xc2822bbf), SkBits2Float(0x40acc6fd), SkBits2Float(0xc262ec43), SkBits2Float(0x42016c3b), SkBits2Float(0xc2109210), SkBits2Float(0x423f921c));
+path.cubicTo(SkBits2Float(0xc178df72), SkBits2Float(0x427db7fc), SkBits2Float(0x414a8dba), SkBits2Float(0x428023fd), SkBits2Float(0x4207ba05), SkBits2Float(0x4245ef60));
+path.lineTo(SkBits2Float(0x423bc156), SkBits2Float(0x4288e7b2));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp1391(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp1392(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp1393(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3c436965), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3cc36072), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3d128619), SkBits2Float(0xc2a5fffe));
+path.lineTo(SkBits2Float(0x3cd3db06), SkBits2Float(0xc26fffff));
+path.cubicTo(SkBits2Float(0x3c8d3d03), SkBits2Float(0xc2700000), SkBits2Float(0x3c0d4407), SkBits2Float(0xc2700000), SkBits2Float(0x36606a00), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3d12888d), SkBits2Float(0xc2a5ffff));
+path.cubicTo(SkBits2Float(0x3d176d55), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3d1c4dcb), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3d212e40), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x3ce90a84), SkBits2Float(0xc26ffffe));
+path.cubicTo(SkBits2Float(0x3ce1ffb6), SkBits2Float(0xc26ffffe), SkBits2Float(0x3cdaedb6), SkBits2Float(0xc26fffff), SkBits2Float(0x3cd3dbb7), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x3d12888d), SkBits2Float(0xc2a5ffff));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp1394(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x36606a00), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3c436965), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3cc36072), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3d128619), SkBits2Float(0xc2a5fffe));
+path.lineTo(SkBits2Float(0x3d12888d), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x3d212e40), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x3ce90a84), SkBits2Float(0xc26ffffe));
+path.cubicTo(SkBits2Float(0x3ce1ffb6), SkBits2Float(0xc26ffffe), SkBits2Float(0x3cdaedb6), SkBits2Float(0xc26fffff), SkBits2Float(0x3cd3db06), SkBits2Float(0xc26fffff));
+path.cubicTo(SkBits2Float(0x3c8d3d03), SkBits2Float(0xc2700000), SkBits2Float(0x3c0d4407), SkBits2Float(0xc2700000), SkBits2Float(0x36606a00), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3d212fd0), SkBits2Float(0xc2a5ffff));
+path.cubicTo(SkBits2Float(0x3d705530), SkBits2Float(0xc2a5fffe), SkBits2Float(0x3d9fbf82), SkBits2Float(0xc2a5fffc), SkBits2Float(0x3dc7546b), SkBits2Float(0xc2a5fffa));
+path.lineTo(SkBits2Float(0x3d901696), SkBits2Float(0xc26ffff5));
+path.cubicTo(SkBits2Float(0x3d66f230), SkBits2Float(0xc26ffff9), SkBits2Float(0x3d2dbab1), SkBits2Float(0xc26ffffc), SkBits2Float(0x3ce90664), SkBits2Float(0xc26ffffe));
+path.lineTo(SkBits2Float(0x3d212fd0), SkBits2Float(0xc2a5ffff));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp1395(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e06023f), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3e860192), SkBits2Float(0xc2a5ffd6), SkBits2Float(0x3ec901db), SkBits2Float(0xc2a5ff85));
+path.lineTo(SkBits2Float(0x3e914e16), SkBits2Float(0xc26fff50));
+path.cubicTo(SkBits2Float(0x3e41bddf), SkBits2Float(0xc26fffc5), SkBits2Float(0x3dc1be4c), SkBits2Float(0xc26fffff), SkBits2Float(0x35c55da0), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ec9015b), SkBits2Float(0xc2a5ff86));
+path.cubicTo(SkBits2Float(0x3ecfb4f0), SkBits2Float(0xc2a5ff7d), SkBits2Float(0x3ed66842), SkBits2Float(0xc2a5ff75), SkBits2Float(0x3edd1b92), SkBits2Float(0xc2a5ff6c));
+path.lineTo(SkBits2Float(0x3e9fd5de), SkBits2Float(0xc26fff2b));
+path.cubicTo(SkBits2Float(0x3e9afe3a), SkBits2Float(0xc26fff39), SkBits2Float(0x3e96263d), SkBits2Float(0xc26fff45), SkBits2Float(0x3e914e41), SkBits2Float(0xc26fff51));
+path.lineTo(SkBits2Float(0x3ec9015b), SkBits2Float(0xc2a5ff86));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp1396(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e0601e9), SkBits2Float(0xc2a60000), SkBits2Float(0x3e86013c), SkBits2Float(0xc2a5ffd6), SkBits2Float(0x3ec9015a), SkBits2Float(0xc2a5ff85));
+path.lineTo(SkBits2Float(0x3ec9015b), SkBits2Float(0xc2a5ff86));
+path.cubicTo(SkBits2Float(0x3ecfb4f0), SkBits2Float(0xc2a5ff7d), SkBits2Float(0x3ed66842), SkBits2Float(0xc2a5ff75), SkBits2Float(0x3edd1b92), SkBits2Float(0xc2a5ff6c));
+path.lineTo(SkBits2Float(0x3e9fd5de), SkBits2Float(0xc26fff2b));
+path.cubicTo(SkBits2Float(0x3e9afe3a), SkBits2Float(0xc26fff39), SkBits2Float(0x3e96263d), SkBits2Float(0xc26fff45), SkBits2Float(0x3e914e16), SkBits2Float(0xc26fff50));
+path.cubicTo(SkBits2Float(0x3e41bddf), SkBits2Float(0xc26fffc5), SkBits2Float(0x3dc1be4c), SkBits2Float(0xc26fffff), SkBits2Float(0x00000000), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3edd1b0d), SkBits2Float(0xc2a5ff6d));
+path.cubicTo(SkBits2Float(0x3f24d70e), SkBits2Float(0xc2a5fedc), SkBits2Float(0x3f5b204e), SkBits2Float(0xc2a5fde1), SkBits2Float(0x3f88b475), SkBits2Float(0xc2a5fc7b));
+path.lineTo(SkBits2Float(0x3f45a57e), SkBits2Float(0xc26ffaea));
+path.cubicTo(SkBits2Float(0x3f1e67a6), SkBits2Float(0xc26ffcf1), SkBits2Float(0x3eee52e7), SkBits2Float(0xc26ffe5c), SkBits2Float(0x3e9fd606), SkBits2Float(0xc26fff2d));
+path.lineTo(SkBits2Float(0x3edd1b0d), SkBits2Float(0xc2a5ff6d));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp2193(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e3881bc), SkBits2Float(0xc2a60000), SkBits2Float(0x3eb88238), SkBits2Float(0xc2a5ffb3), SkBits2Float(0x3f0a6190), SkBits2Float(0xc2a5ff19));
+path.lineTo(SkBits2Float(0x3ec8119b), SkBits2Float(0xc26ffeb2));
+path.cubicTo(SkBits2Float(0x3e856151), SkBits2Float(0xc26fff91), SkBits2Float(0x3e0561b2), SkBits2Float(0xc2700000), SkBits2Float(0x3629eed0), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f0a6183), SkBits2Float(0xc2a5ff19));
+path.cubicTo(SkBits2Float(0x3f0efe46), SkBits2Float(0xc2a5ff0a), SkBits2Float(0x3f139b44), SkBits2Float(0xc2a5fef9), SkBits2Float(0x3f183842), SkBits2Float(0xc2a5fee9));
+path.lineTo(SkBits2Float(0x3edc1349), SkBits2Float(0xc26ffe6c));
+path.cubicTo(SkBits2Float(0x3ed567f5), SkBits2Float(0xc26ffe84), SkBits2Float(0x3ecebccf), SkBits2Float(0xc26ffe9c), SkBits2Float(0x3ec811a8), SkBits2Float(0xc26ffeb2));
+path.lineTo(SkBits2Float(0x3f0a6183), SkBits2Float(0xc2a5ff19));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp2194(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3629eed0), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e3881ab), SkBits2Float(0xc2a60000), SkBits2Float(0x3eb88227), SkBits2Float(0xc2a5ffb3), SkBits2Float(0x3f0a6183), SkBits2Float(0xc2a5ff19));
+path.lineTo(SkBits2Float(0x3f0a6190), SkBits2Float(0xc2a5ff19));
+path.cubicTo(SkBits2Float(0x3f0efe4f), SkBits2Float(0xc2a5ff0a), SkBits2Float(0x3f139b48), SkBits2Float(0xc2a5fef9), SkBits2Float(0x3f183842), SkBits2Float(0xc2a5fee9));
+path.lineTo(SkBits2Float(0x3edc1349), SkBits2Float(0xc26ffe6c));
+path.cubicTo(SkBits2Float(0x3ed567f5), SkBits2Float(0xc26ffe84), SkBits2Float(0x3ecebccf), SkBits2Float(0xc26ffe9c), SkBits2Float(0x3ec811a8), SkBits2Float(0xc26ffeb2));
+path.lineTo(SkBits2Float(0x3ec8119b), SkBits2Float(0xc26ffeb2));
+path.cubicTo(SkBits2Float(0x3e856151), SkBits2Float(0xc26fff91), SkBits2Float(0x3e0561b2), SkBits2Float(0xc2700000), SkBits2Float(0x3629eed0), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f183800), SkBits2Float(0xc2a5fee9));
+path.cubicTo(SkBits2Float(0x3f62f7a2), SkBits2Float(0xc2a5fdd7), SkBits2Float(0x3f96db12), SkBits2Float(0xc2a5fbfa), SkBits2Float(0x3fbc3981), SkBits2Float(0xc2a5f954));
+path.lineTo(SkBits2Float(0x3f8810cc), SkBits2Float(0xc26ff65b));
+path.cubicTo(SkBits2Float(0x3f5a1a86), SkBits2Float(0xc26ffa2f), SkBits2Float(0x3f241256), SkBits2Float(0xc26ffcdf), SkBits2Float(0x3edc1312), SkBits2Float(0xc26ffe6c));
+path.lineTo(SkBits2Float(0x3f183800), SkBits2Float(0xc2a5fee9));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp3368(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp3369(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp3370(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp3371(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3c85f8a2), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3d05fda5), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3d48fefa), SkBits2Float(0xc2a5fffd));
+path.lineTo(SkBits2Float(0x3d114e3a), SkBits2Float(0xc26ffffd));
+path.cubicTo(SkBits2Float(0x3cc1c2c0), SkBits2Float(0xc26fffff), SkBits2Float(0x3c41c57e), SkBits2Float(0xc26fffff), SkBits2Float(0x35afaa00), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3d49018c), SkBits2Float(0xc2a5fffe));
+path.cubicTo(SkBits2Float(0x3d4fb7df), SkBits2Float(0xc2a5fffd), SkBits2Float(0x3d5667bf), SkBits2Float(0xc2a5fffd), SkBits2Float(0x3d5d179f), SkBits2Float(0xc2a5fffd));
+path.lineTo(SkBits2Float(0x3d1fd60d), SkBits2Float(0xc26ffffd));
+path.cubicTo(SkBits2Float(0x3d1afde4), SkBits2Float(0xc26fffff), SkBits2Float(0x3d162864), SkBits2Float(0xc26fffff), SkBits2Float(0x3d1152e4), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x3d49018c), SkBits2Float(0xc2a5fffe));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp3372(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3c85f8a2), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3d05fda5), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3d48fefa), SkBits2Float(0xc2a5fffd));
+path.lineTo(SkBits2Float(0x3d49018c), SkBits2Float(0xc2a5fffe));
+path.cubicTo(SkBits2Float(0x3d4fb7df), SkBits2Float(0xc2a5fffd), SkBits2Float(0x3d5667bf), SkBits2Float(0xc2a5fffd), SkBits2Float(0x3d5d179f), SkBits2Float(0xc2a5fffd));
+path.lineTo(SkBits2Float(0x3d1fd60d), SkBits2Float(0xc26ffffd));
+path.cubicTo(SkBits2Float(0x3d1afde4), SkBits2Float(0xc26fffff), SkBits2Float(0x3d162864), SkBits2Float(0xc26fffff), SkBits2Float(0x3d1152e4), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x3d114e3a), SkBits2Float(0xc26ffffd));
+path.cubicTo(SkBits2Float(0x3cc1c2c0), SkBits2Float(0xc26fffff), SkBits2Float(0x3c41c57e), SkBits2Float(0xc26fffff), SkBits2Float(0x00000000), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3d5d1b4e), SkBits2Float(0xc2a5fffe));
+path.cubicTo(SkBits2Float(0x3da4d661), SkBits2Float(0xc2a5fffc), SkBits2Float(0x3ddb1fb1), SkBits2Float(0xc2a5fff8), SkBits2Float(0x3e08b47e), SkBits2Float(0xc2a5fff2));
+path.lineTo(SkBits2Float(0x3dc5a6e0), SkBits2Float(0xc26fffec));
+path.cubicTo(SkBits2Float(0x3d9e671d), SkBits2Float(0xc26ffff6), SkBits2Float(0x3d6e51bc), SkBits2Float(0xc26ffffb), SkBits2Float(0x3d1fd53d), SkBits2Float(0xc26ffffe));
+path.lineTo(SkBits2Float(0x3d5d1b4e), SkBits2Float(0xc2a5fffe));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp4290(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp4291(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp4292(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp4293(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x357ffa94), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.cubicTo(SkBits2Float(0x42643732), SkBits2Float(0x42727ac8), SkBits2Float(0x4250db30), SkBits2Float(0x4281abaa), SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42757226), SkBits2Float(0x425f9012));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp4294(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x42037818), SkBits2Float(0xc2a60000), SkBits2Float(0x427a8dee), SkBits2Float(0xc27e6c10), SkBits2Float(0x4297d76f), SkBits2Float(0xc2062a8f));
+path.cubicTo(SkBits2Float(0x42b267e8), SkBits2Float(0xc05e90e8), SkBits2Float(0x42a6fcc7), SkBits2Float(0x41fcbc94), SkBits2Float(0x42757227), SkBits2Float(0x425f9011));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.lineTo(SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.cubicTo(SkBits2Float(0x4216fafb), SkBits2Float(0x423b79ba), SkBits2Float(0x4224f9a4), SkBits2Float(0x422f4956), SkBits2Float(0x42316e48), SkBits2Float(0x42219c94));
+path.lineTo(SkBits2Float(0x42316e47), SkBits2Float(0x42219c94));
+path.cubicTo(SkBits2Float(0x42716d77), SkBits2Float(0x41b6b381), SkBits2Float(0x4280f7d6), SkBits2Float(0xc020e418), SkBits2Float(0x425b87ab), SkBits2Float(0xc1c1f9ac));
+path.cubicTo(SkBits2Float(0x42351faa), SkBits2Float(0xc237eb6b), SkBits2Float(0x41be136b), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.cubicTo(SkBits2Float(0x418c17fd), SkBits2Float(0x42b142f1), SkBits2Float(0xc1ac24e4), SkBits2Float(0x42af7d09), SkBits2Float(0xc247fe03), SkBits2Float(0x42848083));
+path.cubicTo(SkBits2Float(0xc29cf4c9), SkBits2Float(0x423307fa), SkBits2Float(0xc2b411ee), SkBits2Float(0x40eef84a), SkBits2Float(0xc29d6723), SkBits2Float(0xc1d2ea61));
+path.cubicTo(SkBits2Float(0xc286bc59), SkBits2Float(0xc270c968), SkBits2Float(0xc20eb871), SkBits2Float(0xc2a5ffff), SkBits2Float(0xb5c727ee), SkBits2Float(0xc2a5ffff));
+path.lineTo(SkBits2Float(0x293e5cb4), SkBits2Float(0xc2700000));
+path.cubicTo(SkBits2Float(0xc1ce57c4), SkBits2Float(0xc2700000), SkBits2Float(0xc242cc76), SkBits2Float(0xc22e100c), SkBits2Float(0xc2639208), SkBits2Float(0xc1987810));
+path.cubicTo(SkBits2Float(0xc2822bcd), SkBits2Float(0x40acbfe2), SkBits2Float(0xc262ecb3), SkBits2Float(0x42016b8c), SkBits2Float(0xc210929c), SkBits2Float(0x423f91b4));
+path.cubicTo(SkBits2Float(0xc178e211), SkBits2Float(0x427db7dc), SkBits2Float(0x414a8b85), SkBits2Float(0x4280240f), SkBits2Float(0x4207b9a6), SkBits2Float(0x4245efa0));
+path.lineTo(SkBits2Float(0x423bc0d1), SkBits2Float(0x4288e7e0));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp4295(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e3881bc), SkBits2Float(0xc2a60000), SkBits2Float(0x3eb88238), SkBits2Float(0xc2a5ffb3), SkBits2Float(0x3f0a6190), SkBits2Float(0xc2a5ff19));
+path.lineTo(SkBits2Float(0x3ec8119b), SkBits2Float(0xc26ffeb2));
+path.cubicTo(SkBits2Float(0x3e856151), SkBits2Float(0xc26fff91), SkBits2Float(0x3e0561b2), SkBits2Float(0xc2700000), SkBits2Float(0x3629eed0), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f0a6183), SkBits2Float(0xc2a5ff19));
+path.cubicTo(SkBits2Float(0x3f0efe46), SkBits2Float(0xc2a5ff0a), SkBits2Float(0x3f139b44), SkBits2Float(0xc2a5fef9), SkBits2Float(0x3f183842), SkBits2Float(0xc2a5fee9));
+path.lineTo(SkBits2Float(0x3edc1349), SkBits2Float(0xc26ffe6c));
+path.cubicTo(SkBits2Float(0x3ed567f5), SkBits2Float(0xc26ffe84), SkBits2Float(0x3ecebccf), SkBits2Float(0xc26ffe9c), SkBits2Float(0x3ec811a8), SkBits2Float(0xc26ffeb2));
+path.lineTo(SkBits2Float(0x3f0a6183), SkBits2Float(0xc2a5ff19));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp4296(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x3629eed0), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e3881ab), SkBits2Float(0xc2a60000), SkBits2Float(0x3eb88227), SkBits2Float(0xc2a5ffb3), SkBits2Float(0x3f0a6183), SkBits2Float(0xc2a5ff19));
+path.lineTo(SkBits2Float(0x3f0a6190), SkBits2Float(0xc2a5ff19));
+path.cubicTo(SkBits2Float(0x3f0efe4f), SkBits2Float(0xc2a5ff0a), SkBits2Float(0x3f139b48), SkBits2Float(0xc2a5fef9), SkBits2Float(0x3f183842), SkBits2Float(0xc2a5fee9));
+path.lineTo(SkBits2Float(0x3edc1349), SkBits2Float(0xc26ffe6c));
+path.cubicTo(SkBits2Float(0x3ed567f5), SkBits2Float(0xc26ffe84), SkBits2Float(0x3ecebccf), SkBits2Float(0xc26ffe9c), SkBits2Float(0x3ec811a8), SkBits2Float(0xc26ffeb2));
+path.lineTo(SkBits2Float(0x3ec8119b), SkBits2Float(0xc26ffeb2));
+path.cubicTo(SkBits2Float(0x3e856151), SkBits2Float(0xc26fff91), SkBits2Float(0x3e0561b2), SkBits2Float(0xc2700000), SkBits2Float(0x3629eed0), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3f183800), SkBits2Float(0xc2a5fee9));
+path.cubicTo(SkBits2Float(0x3f62f7a2), SkBits2Float(0xc2a5fdd7), SkBits2Float(0x3f96db12), SkBits2Float(0xc2a5fbfa), SkBits2Float(0x3fbc3981), SkBits2Float(0xc2a5f954));
+path.lineTo(SkBits2Float(0x3f8810cc), SkBits2Float(0xc26ff65b));
+path.cubicTo(SkBits2Float(0x3f5a1a86), SkBits2Float(0xc26ffa2f), SkBits2Float(0x3f241256), SkBits2Float(0xc26ffcdf), SkBits2Float(0x3edc1312), SkBits2Float(0xc26ffe6c));
+path.lineTo(SkBits2Float(0x3f183800), SkBits2Float(0xc2a5fee9));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp5193(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e0b17ea), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3e8b17df), SkBits2Float(0xc2a5ffd4), SkBits2Float(0x3ed0a399), SkBits2Float(0xc2a5ff7c));
+path.lineTo(SkBits2Float(0x3e96d285), SkBits2Float(0xc26fff42));
+path.cubicTo(SkBits2Float(0x3e491945), SkBits2Float(0xc26fffc2), SkBits2Float(0x3dc91958), SkBits2Float(0xc2700000), SkBits2Float(0x340ae940), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ed0a338), SkBits2Float(0xc2a5ff7d));
+path.cubicTo(SkBits2Float(0x3ed797a0), SkBits2Float(0xc2a5ff73), SkBits2Float(0x3ede8c36), SkBits2Float(0xc2a5ff6a), SkBits2Float(0x3ee580cb), SkBits2Float(0xc2a5ff60));
+path.lineTo(SkBits2Float(0x3ea5e78a), SkBits2Float(0xc26fff1b));
+path.cubicTo(SkBits2Float(0x3ea0e0aa), SkBits2Float(0xc26fff29), SkBits2Float(0x3e9bd97e), SkBits2Float(0xc26fff36), SkBits2Float(0x3e96d252), SkBits2Float(0xc26fff43));
+path.lineTo(SkBits2Float(0x3ed0a338), SkBits2Float(0xc2a5ff7d));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+// op end success 1
+
+static void battleOp5194(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e0b17a8), SkBits2Float(0xc2a60000), SkBits2Float(0x3e8b179e), SkBits2Float(0xc2a5ffd4), SkBits2Float(0x3ed0a337), SkBits2Float(0xc2a5ff7c));
+path.lineTo(SkBits2Float(0x3ed0a338), SkBits2Float(0xc2a5ff7d));
+path.cubicTo(SkBits2Float(0x3ed797a0), SkBits2Float(0xc2a5ff73), SkBits2Float(0x3ede8c36), SkBits2Float(0xc2a5ff6a), SkBits2Float(0x3ee580cb), SkBits2Float(0xc2a5ff60));
+path.lineTo(SkBits2Float(0x3ea5e78a), SkBits2Float(0xc26fff1b));
+path.cubicTo(SkBits2Float(0x3ea0e0bb), SkBits2Float(0xc26fff29), SkBits2Float(0x3e9bd9a1), SkBits2Float(0xc26fff36), SkBits2Float(0x3e96d286), SkBits2Float(0xc26fff43));
+path.lineTo(SkBits2Float(0x3e96d285), SkBits2Float(0xc26fff42));
+path.cubicTo(SkBits2Float(0x3e491945), SkBits2Float(0xc26fffc2), SkBits2Float(0x3dc91958), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ee58048), SkBits2Float(0xc2a5ff61));
+path.cubicTo(SkBits2Float(0x3f2b1987), SkBits2Float(0xc2a5fec4), SkBits2Float(0x3f637253), SkBits2Float(0xc2a5fdb6), SkBits2Float(0x3f8de535), SkBits2Float(0xc2a5fc35));
+path.lineTo(SkBits2Float(0x3f4d269a), SkBits2Float(0xc26ffa85));
+path.cubicTo(SkBits2Float(0x3f246b51), SkBits2Float(0xc26ffcb3), SkBits2Float(0x3ef75f30), SkBits2Float(0xc26ffe3a), SkBits2Float(0x3ea5e737), SkBits2Float(0xc26fff1c));
+path.lineTo(SkBits2Float(0x3ee58048), SkBits2Float(0xc2a5ff61));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp402(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3e0b17a8), SkBits2Float(0xc2a60000), SkBits2Float(0x3e8b179e), SkBits2Float(0xc2a5ffd4), SkBits2Float(0x3ed0a337), SkBits2Float(0xc2a5ff7c));
+path.lineTo(SkBits2Float(0x3ed0a338), SkBits2Float(0xc2a5ff7d));
+path.cubicTo(SkBits2Float(0x3ed797a0), SkBits2Float(0xc2a5ff73), SkBits2Float(0x3ede8c36), SkBits2Float(0xc2a5ff6a), SkBits2Float(0x3ee580cb), SkBits2Float(0xc2a5ff60));
+path.lineTo(SkBits2Float(0x3ea5e78a), SkBits2Float(0xc26fff1b));
+path.cubicTo(SkBits2Float(0x3ea0e0bb), SkBits2Float(0xc26fff29), SkBits2Float(0x3e9bd9a1), SkBits2Float(0xc26fff36), SkBits2Float(0x3e96d286), SkBits2Float(0xc26fff43));
+path.lineTo(SkBits2Float(0x3e96d285), SkBits2Float(0xc26fff42));
+path.cubicTo(SkBits2Float(0x3e491945), SkBits2Float(0xc26fffc2), SkBits2Float(0x3dc91958), SkBits2Float(0xc2700000), SkBits2Float(0x00000000), SkBits2Float(0xc2700000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3ee58048), SkBits2Float(0xc2a5ff61));
+path.cubicTo(SkBits2Float(0x3f2b1987), SkBits2Float(0xc2a5fec4), SkBits2Float(0x3f637253), SkBits2Float(0xc2a5fdb6), SkBits2Float(0x3f8de535), SkBits2Float(0xc2a5fc35));
+path.lineTo(SkBits2Float(0x3f4d269a), SkBits2Float(0xc26ffa85));
+path.cubicTo(SkBits2Float(0x3f246b51), SkBits2Float(0xc26ffcb3), SkBits2Float(0x3ef75f30), SkBits2Float(0xc26ffe3a), SkBits2Float(0x3ea5e737), SkBits2Float(0xc26fff1c));
+path.lineTo(SkBits2Float(0x3ee58048), SkBits2Float(0xc2a5ff61));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp6000(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3c9b2383), SkBits2Float(0xc2a60000), SkBits2Float(0x3d1b200b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3d68ae54), SkBits2Float(0xc2a5fffd));
+path.lineTo(SkBits2Float(0x3d283599), SkBits2Float(0xc26ffffc));
+path.cubicTo(SkBits2Float(0x3ce049ca), SkBits2Float(0xc26ffffe), SkBits2Float(0x3c604794), SkBits2Float(0xc26fffff), SkBits2Float(0xb58d9000), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x27b71bcd), SkBits2Float(0xc2a60000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3d68b08b), SkBits2Float(0xc2a5fffd));
+path.cubicTo(SkBits2Float(0x3d707589), SkBits2Float(0xc2a5fffd), SkBits2Float(0x3d783329), SkBits2Float(0xc2a5fffd), SkBits2Float(0x3d7ff0c9), SkBits2Float(0xc2a5fffd));
+path.lineTo(SkBits2Float(0x3d3907c2), SkBits2Float(0xc26ffffc));
+path.cubicTo(SkBits2Float(0x3d336bee), SkBits2Float(0xc26ffffd), SkBits2Float(0x3d2dd36e), SkBits2Float(0xc26ffffd), SkBits2Float(0x3d283aee), SkBits2Float(0xc26ffffd));
+path.lineTo(SkBits2Float(0x3d68b08b), SkBits2Float(0xc2a5fffd));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void battleOp6001(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 1);
+path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0xc26fffff));
+path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0xc2a60000));
+path.cubicTo(SkBits2Float(0x3c9b2383), SkBits2Float(0xc2a60000), SkBits2Float(0x3d1b200b), SkBits2Float(0xc2a5ffff), SkBits2Float(0x3d68ae54), SkBits2Float(0xc2a5fffd));
+path.lineTo(SkBits2Float(0x3d7ff0c9), SkBits2Float(0xc2a5fffd));
+path.lineTo(SkBits2Float(0x3d3907c2), SkBits2Float(0xc26ffffc));
+path.cubicTo(SkBits2Float(0x3d336bee), SkBits2Float(0xc26ffffd), SkBits2Float(0x3d2dd36e), SkBits2Float(0xc26ffffd), SkBits2Float(0x3d283aee), SkBits2Float(0xc26ffffd));
+path.lineTo(SkBits2Float(0x3d283599), SkBits2Float(0xc26ffffc));
+path.cubicTo(SkBits2Float(0x3ce049ca), SkBits2Float(0xc26ffffe), SkBits2Float(0x3c604794), SkBits2Float(0xc26fffff), SkBits2Float(0x00000000), SkBits2Float(0xc26fffff));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x3d7ff566), SkBits2Float(0xc2a5fffd));
+path.cubicTo(SkBits2Float(0x3dbed1a5), SkBits2Float(0xc2a5fffa), SkBits2Float(0x3dfda9cc), SkBits2Float(0xc2a5fff4), SkBits2Float(0x3e1e40f8), SkBits2Float(0xc2a5ffed));
+path.lineTo(SkBits2Float(0x3de4ce81), SkBits2Float(0xc26fffe5));
+path.cubicTo(SkBits2Float(0x3db75eff), SkBits2Float(0xc26ffff0), SkBits2Float(0x3d89f101), SkBits2Float(0xc26ffff8), SkBits2Float(0x3d390604), SkBits2Float(0xc26ffffc));
+path.lineTo(SkBits2Float(0x3d7ff566), SkBits2Float(0xc2a5fffd));
+path.close();
+
+ SkPath path2(path);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = battleOp6001;
+static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
+
+static struct TestDesc tests[] = {
+ TEST(battleOp1),
+ TEST(battleOp2),
+ TEST(battleOp3),
+ TEST(battleOp4),
+ TEST(battleOp5),
+ TEST(battleOp6),
+ TEST(battleOp7),
+ TEST(battleOp8),
+ TEST(battleOp9),
+ TEST(battleOp10),
+
+ TEST(battleOp11),
+ TEST(battleOp12),
+ TEST(battleOp13),
+ TEST(battleOp14),
+ TEST(battleOp15),
+ TEST(battleOp16),
+ TEST(battleOp17),
+ TEST(battleOp18),
+ TEST(battleOp19),
+ TEST(battleOp20),
+
+ TEST(battleOp21),
+ TEST(battleOp22),
+ TEST(battleOp23),
+ TEST(battleOp24),
+ TEST(battleOp25),
+ TEST(battleOp26),
+ TEST(battleOp27),
+ TEST(battleOp28),
+ TEST(battleOp29),
+ TEST(battleOp30),
+
+ TEST(battleOp31),
+ TEST(battleOp32),
+ TEST(battleOp33),
+ TEST(battleOp34),
+ TEST(battleOp35),
+ TEST(battleOp36),
+ TEST(battleOp37),
+ TEST(battleOp38),
+ TEST(battleOp39),
+ TEST(battleOp40),
+
+ TEST(battleOp41),
+ TEST(battleOp42),
+ TEST(battleOp43),
+ TEST(battleOp44),
+ TEST(battleOp45),
+ TEST(battleOp46), // draws wrong : dropped an outer cubic incorrectly
+ // if assembly rewrite was done, the error would be hidden
+ TEST(battleOp47),
+ TEST(battleOp48),
+ TEST(battleOp49),
+ TEST(battleOp50),
+
+ TEST(battleOp51),
+ TEST(battleOp52),
+ TEST(battleOp53),
+ TEST(battleOp54), // draws wrong
+ TEST(battleOp55),
+ TEST(battleOp56),
+ TEST(battleOp57),
+ TEST(battleOp58),
+ TEST(battleOp59), // draws wrong
+ TEST(battleOp60),
+
+ TEST(battleOp61),
+ TEST(battleOp62),
+ TEST(battleOp63), // draws wrong
+ TEST(battleOp64),
+ TEST(battleOp65),
+ TEST(battleOp66),
+ TEST(battleOp67),
+ TEST(battleOp68),
+ TEST(battleOp69),
+ TEST(battleOp70),
+
+ TEST(battleOp71),
+ TEST(battleOp72),
+ TEST(battleOp73),
+ TEST(battleOp74),
+ TEST(battleOp75),
+ TEST(battleOp76),
+ TEST(battleOp77),
+ TEST(battleOp78),
+ TEST(battleOp79),
+ TEST(battleOp80),
+
+ TEST(battleOp81),
+ TEST(battleOp82),
+ TEST(battleOp83),
+ TEST(battleOp84),
+ TEST(battleOp85), // draws wrong
+ TEST(battleOp86),
+ TEST(battleOp87),
+ TEST(battleOp88),
+ TEST(battleOp89),
+ TEST(battleOp90),
+
+ TEST(battleOp91),
+ TEST(battleOp92),
+ TEST(battleOp93),
+ TEST(battleOp94),
+ TEST(battleOp95),
+ TEST(battleOp96),
+ TEST(battleOp97),
+ TEST(battleOp98),
+ TEST(battleOp99),
+ TEST(battleOp100),
+
+ TEST(battleOp101),
+ TEST(battleOp102),
+ TEST(battleOp103),
+ TEST(battleOp104),
+ TEST(battleOp105),
+ TEST(battleOp106),
+ TEST(battleOp107),
+ TEST(battleOp108),
+ TEST(battleOp109),
+ TEST(battleOp110),
+
+ TEST(battleOp111),
+ TEST(battleOp112),
+ TEST(battleOp113),
+ TEST(battleOp114),
+ TEST(battleOp115),
+ TEST(battleOp116),
+ TEST(battleOp117),
+ TEST(battleOp118),
+ TEST(battleOp119),
+ TEST(battleOp120),
+
+ TEST(battleOp121),
+ TEST(battleOp122),
+ TEST(battleOp123),
+ TEST(battleOp124),
+ TEST(battleOp125),
+ TEST(battleOp126),
+ TEST(battleOp127),
+ TEST(battleOp128),
+ TEST(battleOp129),
+ TEST(battleOp130),
+
+ TEST(battleOp131),
+ TEST(battleOp132),
+ TEST(battleOp133),
+ TEST(battleOp134),
+ TEST(battleOp135),
+ TEST(battleOp136),
+ TEST(battleOp137),
+ TEST(battleOp138),
+ TEST(battleOp139),
+ TEST(battleOp140),
+
+ TEST(battleOp141),
+ TEST(battleOp142),
+ TEST(battleOp143),
+ TEST(battleOp144),
+ TEST(battleOp145),
+ TEST(battleOp146),
+ TEST(battleOp147),
+ TEST(battleOp148), // draws wrong
+ TEST(battleOp149),
+ TEST(battleOp150),
+
+ TEST(battleOp151),
+ TEST(battleOp152),
+ TEST(battleOp153),
+ TEST(battleOp154),
+ TEST(battleOp155),
+ TEST(battleOp156),
+ TEST(battleOp157),
+ TEST(battleOp158),
+ TEST(battleOp159),
+ TEST(battleOp160),
+
+ TEST(battleOp161),
+ TEST(battleOp162),
+ TEST(battleOp163),
+ TEST(battleOp164),
+ TEST(battleOp165),
+ TEST(battleOp166),
+ TEST(battleOp167),
+ TEST(battleOp168),
+ TEST(battleOp169),
+ TEST(battleOp170),
+
+ TEST(battleOp171),
+ TEST(battleOp172),
+ TEST(battleOp173),
+ TEST(battleOp174),
+ TEST(battleOp175),
+ TEST(battleOp176),
+ TEST(battleOp177),
+ TEST(battleOp178),
+ TEST(battleOp179),
+ TEST(battleOp180),
+
+ TEST(battleOp181),
+ TEST(battleOp182),
+ TEST(battleOp183),
+ TEST(battleOp184),
+ TEST(battleOp185),
+ TEST(battleOp186),
+ TEST(battleOp187),
+ TEST(battleOp188),
+ TEST(battleOp189),
+ TEST(battleOp190),
+
+ TEST(battleOp191),
+ TEST(battleOp192),
+ TEST(battleOp193),
+ TEST(battleOp194),
+ TEST(battleOp195),
+ TEST(battleOp196),
+ TEST(battleOp197),
+ TEST(battleOp198),
+ TEST(battleOp199),
+ TEST(battleOp200),
+
+ TEST(battleOp201),
+ TEST(battleOp202),
+ TEST(battleOp203),
+ TEST(battleOp204),
+ TEST(battleOp205),
+ TEST(battleOp206),
+ TEST(battleOp207),
+ TEST(battleOp208),
+ TEST(battleOp209),
+ TEST(battleOp210),
+
+ TEST(battleOp211),
+ TEST(battleOp212),
+ TEST(battleOp213),
+ TEST(battleOp214),
+ TEST(battleOp215),
+ TEST(battleOp216),
+ TEST(battleOp217),
+ TEST(battleOp218),
+ TEST(battleOp219),
+ TEST(battleOp220),
+
+ TEST(battleOp221),
+ TEST(battleOp222),
+ TEST(battleOp223),
+ TEST(battleOp224),
+ TEST(battleOp225),
+ TEST(battleOp226),
+ TEST(battleOp227),
+ TEST(battleOp228),
+ TEST(battleOp229),
+ TEST(battleOp230),
+
+ TEST(battleOp231),
+ TEST(battleOp232),
+ TEST(battleOp233),
+ TEST(battleOp234),
+ TEST(battleOp235),
+ TEST(battleOp236),
+ TEST(battleOp237),
+ TEST(battleOp238),
+ TEST(battleOp239),
+ TEST(battleOp240),
+
+ TEST(battleOp241),
+ TEST(battleOp242),
+ TEST(battleOp243),
+ TEST(battleOp244),
+ TEST(battleOp245),
+ TEST(battleOp246),
+ TEST(battleOp247),
+ TEST(battleOp248),
+ TEST(battleOp249),
+ TEST(battleOp250),
+
+ TEST(battleOp251),
+ TEST(battleOp252),
+ TEST(battleOp253),
+ TEST(battleOp254),
+ TEST(battleOp255),
+ TEST(battleOp256),
+ TEST(battleOp257),
+ TEST(battleOp258),
+ TEST(battleOp259),
+ TEST(battleOp260),
+
+ TEST(battleOp261),
+ TEST(battleOp262),
+ TEST(battleOp263),
+ TEST(battleOp264),
+ TEST(battleOp265),
+ TEST(battleOp266),
+ TEST(battleOp267),
+ TEST(battleOp268),
+ TEST(battleOp269),
+ TEST(battleOp270),
+
+ TEST(battleOp271),
+ TEST(battleOp272),
+ TEST(battleOp273),
+ TEST(battleOp274),
+ TEST(battleOp275),
+ TEST(battleOp276),
+ TEST(battleOp277),
+ TEST(battleOp278),
+ TEST(battleOp279),
+ TEST(battleOp280),
+
+ TEST(battleOp281),
+ TEST(battleOp282),
+ TEST(battleOp283),
+ TEST(battleOp284),
+ TEST(battleOp285),
+ TEST(battleOp286),
+ TEST(battleOp287),
+ TEST(battleOp288),
+ TEST(battleOp289),
+ TEST(battleOp290),
+
+ TEST(battleOp291),
+ TEST(battleOp292),
+ TEST(battleOp293),
+ TEST(battleOp294),
+ TEST(battleOp295),
+ TEST(battleOp296),
+ TEST(battleOp297),
+ TEST(battleOp298),
+ TEST(battleOp299),
+ TEST(battleOp300),
+
+ TEST(battleOp301),
+ TEST(battleOp302),
+ TEST(battleOp303),
+ TEST(battleOp304),
+ TEST(battleOp305),
+ TEST(battleOp306),
+ TEST(battleOp307),
+ TEST(battleOp308),
+ TEST(battleOp309),
+ TEST(battleOp310),
+
+ TEST(battleOp311),
+ TEST(battleOp312),
+ TEST(battleOp313),
+ TEST(battleOp314),
+ TEST(battleOp315),
+ TEST(battleOp316),
+ TEST(battleOp317),
+ TEST(battleOp318),
+ TEST(battleOp319),
+ TEST(battleOp320),
+
+ TEST(battleOp321),
+ TEST(battleOp322),
+ TEST(battleOp323),
+ TEST(battleOp324),
+ TEST(battleOp325),
+ TEST(battleOp326),
+ TEST(battleOp327),
+ TEST(battleOp328),
+ TEST(battleOp329),
+ TEST(battleOp330),
+
+ TEST(battleOp331),
+ TEST(battleOp332),
+ TEST(battleOp333),
+ TEST(battleOp334),
+ TEST(battleOp335),
+ TEST(battleOp336),
+ TEST(battleOp337),
+ TEST(battleOp338),
+ TEST(battleOp339),
+ TEST(battleOp340),
+
+ TEST(battleOp341),
+ TEST(battleOp342),
+ TEST(battleOp343),
+ TEST(battleOp344),
+ TEST(battleOp345),
+ TEST(battleOp346),
+ TEST(battleOp347),
+ TEST(battleOp348),
+ TEST(battleOp349),
+ TEST(battleOp350),
+
+ TEST(battleOp351),
+ TEST(battleOp352),
+
+ TEST(battleOp402),
+
+ TEST(battleOp1390),
+ TEST(battleOp1391),
+ TEST(battleOp1392),
+ TEST(battleOp1393),
+ TEST(battleOp1394),
+ TEST(battleOp1395),
+ TEST(battleOp1396),
+
+ TEST(battleOp2193),
+ TEST(battleOp2194),
+
+ TEST(battleOp3368),
+ TEST(battleOp3369),
+ TEST(battleOp3370),
+ TEST(battleOp3371),
+ TEST(battleOp3372),
+
+ TEST(battleOp4290),
+ TEST(battleOp4291),
+ TEST(battleOp4292),
+ TEST(battleOp4293),
+ TEST(battleOp4294),
+ TEST(battleOp4295),
+ TEST(battleOp4296),
+
+ TEST(battleOp5193),
+ TEST(battleOp5194),
+
+ TEST(battleOp6000),
+ TEST(battleOp6001),
+
+ TEST(issue414409c),
+ TEST(issue414409b),
+ TEST(issue414409),
+};
+
+
+static const size_t testCount = SK_ARRAY_COUNT(tests);
+
+static bool runReverse = false;
+
+DEF_TEST(PathOpsBattle, reporter) {
+#if DEBUG_SHOW_TEST_NAME
+ strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
+#endif
+ RunTestSet(reporter, tests, testCount, firstTest, stopTest, runReverse);
+}
diff --git a/src/third_party/skia/tests/PathOpsBoundsTest.cpp b/src/third_party/skia/tests/PathOpsBoundsTest.cpp
new file mode 100644
index 0000000..8683051
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsBoundsTest.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkPathOpsBounds.h"
+#include "Test.h"
+
+static const SkRect sectTests[][2] = {
+ {{2, 0, 4, 1}, {4, 0, 6, 1}},
+ {{2, 0, 4, 1}, {3, 0, 5, 1}},
+ {{2, 0, 4, 1}, {3, 0, 5, 0}},
+ {{2, 0, 4, 1}, {3, 1, 5, 2}},
+ {{2, 1, 4, 2}, {1, 0, 5, 3}},
+ {{2, 1, 5, 3}, {3, 1, 4, 2}},
+ {{2, 0, 4, 1}, {3, 0, 3, 0}}, // intersecting an empty bounds is OK
+ {{2, 0, 4, 1}, {4, 1, 5, 2}}, // touching just on a corner is OK
+};
+
+static const size_t sectTestsCount = SK_ARRAY_COUNT(sectTests);
+
+static const SkRect noSectTests[][2] = {
+ {{2, 0, 4, 1}, {5, 0, 6, 1}},
+ {{2, 0, 4, 1}, {3, 2, 5, 2}},
+};
+
+static const size_t noSectTestsCount = SK_ARRAY_COUNT(noSectTests);
+
+static const SkRect reallyEmpty[] = {
+ {0, 0, 0, 0},
+ {1, 1, 1, 0},
+ {1, 1, 0, 1},
+ {1, 1, 0, 0},
+ {1, 2, 3, SK_ScalarNaN},
+};
+
+static const size_t emptyTestsCount = SK_ARRAY_COUNT(reallyEmpty);
+
+static const SkRect notReallyEmpty[] = {
+ {0, 0, 1, 0},
+ {0, 0, 0, 1},
+ {0, 0, 1, 1},
+};
+
+static const size_t notEmptyTestsCount = SK_ARRAY_COUNT(notReallyEmpty);
+
+DEF_TEST(PathOpsBounds, reporter) {
+ for (size_t index = 0; index < sectTestsCount; ++index) {
+ const SkPathOpsBounds& bounds1 = static_cast<const SkPathOpsBounds&>(sectTests[index][0]);
+ SkASSERT(ValidBounds(bounds1));
+ const SkPathOpsBounds& bounds2 = static_cast<const SkPathOpsBounds&>(sectTests[index][1]);
+ SkASSERT(ValidBounds(bounds2));
+ bool touches = SkPathOpsBounds::Intersects(bounds1, bounds2);
+ REPORTER_ASSERT(reporter, touches);
+ }
+ for (size_t index = 0; index < noSectTestsCount; ++index) {
+ const SkPathOpsBounds& bounds1 = static_cast<const SkPathOpsBounds&>(noSectTests[index][0]);
+ SkASSERT(ValidBounds(bounds1));
+ const SkPathOpsBounds& bounds2 = static_cast<const SkPathOpsBounds&>(noSectTests[index][1]);
+ SkASSERT(ValidBounds(bounds2));
+ bool touches = SkPathOpsBounds::Intersects(bounds1, bounds2);
+ REPORTER_ASSERT(reporter, !touches);
+ }
+ SkPathOpsBounds bounds;
+ bounds.setEmpty();
+ bounds.add(1, 2, 3, 4);
+ SkPathOpsBounds expected;
+ expected.set(0, 0, 3, 4);
+ REPORTER_ASSERT(reporter, bounds == expected);
+ bounds.setEmpty();
+ SkPathOpsBounds ordinal;
+ ordinal.set(1, 2, 3, 4);
+ bounds.add(ordinal);
+ REPORTER_ASSERT(reporter, bounds == expected);
+ SkPoint topLeft = {0, 0};
+ bounds.setPointBounds(topLeft);
+ SkPoint botRight = {3, 4};
+ bounds.add(botRight);
+ REPORTER_ASSERT(reporter, bounds == expected);
+ for (size_t index = 0; index < emptyTestsCount; ++index) {
+ const SkPathOpsBounds& bounds = static_cast<const SkPathOpsBounds&>(reallyEmpty[index]);
+ // SkASSERT(ValidBounds(bounds)); // don't check because test may contain nan
+ bool empty = bounds.isReallyEmpty();
+ REPORTER_ASSERT(reporter, empty);
+ }
+ for (size_t index = 0; index < notEmptyTestsCount; ++index) {
+ const SkPathOpsBounds& bounds = static_cast<const SkPathOpsBounds&>(notReallyEmpty[index]);
+ SkASSERT(ValidBounds(bounds));
+ bool empty = bounds.isReallyEmpty();
+ REPORTER_ASSERT(reporter, !empty);
+ }
+ const SkPoint curvePts[] = {{0, 0}, {1, 2}, {3, 4}, {5, 6}};
+ bounds.setLineBounds(curvePts);
+ expected.set(0, 0, 1, 2);
+ REPORTER_ASSERT(reporter, bounds == expected);
+ (bounds.*SetCurveBounds[1])(curvePts);
+ REPORTER_ASSERT(reporter, bounds == expected);
+ bounds.setQuadBounds(curvePts);
+ expected.set(0, 0, 3, 4);
+ REPORTER_ASSERT(reporter, bounds == expected);
+ (bounds.*SetCurveBounds[2])(curvePts);
+ REPORTER_ASSERT(reporter, bounds == expected);
+ bounds.setCubicBounds(curvePts);
+ expected.set(0, 0, 5, 6);
+ REPORTER_ASSERT(reporter, bounds == expected);
+ (bounds.*SetCurveBounds[3])(curvePts);
+ REPORTER_ASSERT(reporter, bounds == expected);
+}
diff --git a/src/third_party/skia/tests/PathOpsCubicIntersectionTest.cpp b/src/third_party/skia/tests/PathOpsCubicIntersectionTest.cpp
new file mode 100644
index 0000000..443e1ae
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsCubicIntersectionTest.cpp
@@ -0,0 +1,652 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsCubicIntersectionTestData.h"
+#include "PathOpsTestCommon.h"
+#include "SkIntersections.h"
+#include "SkPathOpsRect.h"
+#include "SkReduceOrder.h"
+#include "Test.h"
+
+const int firstCubicIntersectionTest = 9;
+
+static void standardTestCases(skiatest::Reporter* reporter) {
+ for (size_t index = firstCubicIntersectionTest; index < tests_count; ++index) {
+ int iIndex = static_cast<int>(index);
+ const SkDCubic& cubic1 = tests[index][0];
+ const SkDCubic& cubic2 = tests[index][1];
+ SkReduceOrder reduce1, reduce2;
+ int order1 = reduce1.reduce(cubic1, SkReduceOrder::kNo_Quadratics);
+ int order2 = reduce2.reduce(cubic2, SkReduceOrder::kNo_Quadratics);
+ const bool showSkipped = false;
+ if (order1 < 4) {
+ if (showSkipped) {
+ SkDebugf("%s [%d] cubic1 order=%d\n", __FUNCTION__, iIndex, order1);
+ }
+ continue;
+ }
+ if (order2 < 4) {
+ if (showSkipped) {
+ SkDebugf("%s [%d] cubic2 order=%d\n", __FUNCTION__, iIndex, order2);
+ }
+ continue;
+ }
+ SkIntersections tIntersections;
+ tIntersections.intersect(cubic1, cubic2);
+ if (!tIntersections.used()) {
+ if (showSkipped) {
+ SkDebugf("%s [%d] no intersection\n", __FUNCTION__, iIndex);
+ }
+ continue;
+ }
+ if (tIntersections.isCoincident(0)) {
+ if (showSkipped) {
+ SkDebugf("%s [%d] coincident\n", __FUNCTION__, iIndex);
+ }
+ continue;
+ }
+ for (int pt = 0; pt < tIntersections.used(); ++pt) {
+ double tt1 = tIntersections[0][pt];
+ SkDPoint xy1 = cubic1.ptAtT(tt1);
+ double tt2 = tIntersections[1][pt];
+ SkDPoint xy2 = cubic2.ptAtT(tt2);
+ if (!xy1.approximatelyEqual(xy2)) {
+ SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
+ __FUNCTION__, (int)index, pt, tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY);
+ }
+ REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
+ }
+ reporter->bumpTestCount();
+ }
+}
+
+static const SkDCubic testSet[] = {
+// FIXME: uncommenting these two will cause this to fail
+// this results in two curves very nearly but not exactly coincident
+#if 0
+{{{67.426548091427676, 37.993772624988935}, {23.483695892376684, 90.476863174921306},
+ {35.597065061143162, 79.872482633158796}, {75.38634169631932, 18.244890038969412}}},
+{{{67.4265481, 37.9937726}, {23.4836959, 90.4768632}, {35.5970651, 79.8724826},
+ {75.3863417, 18.24489}}},
+#endif
+
+{{{0, 0}, {0, 1}, {1, 1}, {1, 0}}},
+{{{1, 0}, {0, 0}, {0, 1}, {1, 1}}},
+
+{{{0, 1}, {4, 5}, {1, 0}, {5, 3}}},
+{{{0, 1}, {3, 5}, {1, 0}, {5, 4}}},
+
+{{{0, 1}, {1, 6}, {1, 0}, {1, 0}}},
+{{{0, 1}, {0, 1}, {1, 0}, {6, 1}}},
+
+{{{0, 1}, {3, 4}, {1, 0}, {5, 1}}},
+{{{0, 1}, {1, 5}, {1, 0}, {4, 3}}},
+
+{{{0, 1}, {1, 2}, {1, 0}, {6, 1}}},
+{{{0, 1}, {1, 6}, {1, 0}, {2, 1}}},
+
+{{{0, 1}, {0, 5}, {1, 0}, {4, 0}}},
+{{{0, 1}, {0, 4}, {1, 0}, {5, 0}}},
+
+{{{0, 1}, {3, 4}, {1, 0}, {3, 0}}},
+{{{0, 1}, {0, 3}, {1, 0}, {4, 3}}},
+
+{{{0, 0}, {1, 2}, {3, 4}, {4, 4}}},
+{{{0, 0}, {1, 2}, {3, 4}, {4, 4}}},
+{{{4, 4}, {3, 4}, {1, 2}, {0, 0}}},
+
+{{{0, 1}, {2, 3}, {1, 0}, {1, 0}}},
+{{{0, 1}, {0, 1}, {1, 0}, {3, 2}}},
+
+{{{0, 2}, {0, 1}, {1, 0}, {1, 0}}},
+{{{0, 1}, {0, 1}, {2, 0}, {1, 0}}},
+
+{{{0, 1}, {0, 2}, {1, 0}, {1, 0}}},
+{{{0, 1}, {0, 1}, {1, 0}, {2, 0}}},
+
+{{{0, 1}, {1, 6}, {1, 0}, {2, 0}}},
+{{{0, 1}, {0, 2}, {1, 0}, {6, 1}}},
+
+{{{0, 1}, {5, 6}, {1, 0}, {1, 0}}},
+{{{0, 1}, {0, 1}, {1, 0}, {6, 5}}},
+
+{{{95.837747722788592, 45.025976907939643}, {16.564570095652982, 0.72959763963222402},
+ {63.209855865319199, 68.047528419665767}, {57.640240647662544, 59.524565264361243}}},
+{{{51.593891741518817, 38.53849970667553}, {62.34752929878772, 74.924924725166022},
+ {74.810149322641152, 34.17966562983564}, {29.368398119401373, 94.66719277886078}}},
+
+{{{39.765160968417838, 33.060396198677083}, {5.1922921581157908, 66.854301452103215},
+ {31.619281802149157, 25.269248720849514}, {81.541621071073038, 70.025341524754353}}},
+{{{46.078911165743556, 48.259962651999651}, {20.24450549867214, 49.403916182650214},
+ {0.26325131778756683, 24.46489805563581}, {15.915006546264051, 83.515023059917155}}},
+
+{{{65.454505973241524, 93.881892270353575}, {45.867360264932437, 92.723972719499827},
+ {2.1464054482739447, 74.636369140183717}, {33.774068594804994, 40.770872887582925}}},
+{{{72.963387832494163, 95.659300729473728}, {11.809496633619768, 82.209921247423594},
+ {13.456139067865974, 57.329313623406605}, {36.060621606214262, 70.867335643091849}}},
+
+{{{32.484981432782945, 75.082940782924624}, {42.467313093350882, 48.131159948246157},
+ {3.5963115764764657, 43.208665839959245}, {79.442476890721579, 89.709102357602262}}},
+{{{18.98573861410177, 93.308887208490106}, {40.405250173250792, 91.039661826118675},
+ {8.0467721950480584, 42.100282172719147}, {40.883324221187891, 26.030185504830527}}},
+
+{{{7.5374809128872498, 82.441702896003477}, {22.444346930107265, 22.138854312775123},
+ {66.76091829629658, 50.753805856571446}, {78.193478508942519, 97.7932997968948}}},
+{{{97.700573130371311, 53.53260215070685}, {87.72443481149358, 84.575876772671876},
+ {19.215031396232092, 47.032676472809484}, {11.989686410869325, 10.659507480757082}}},
+
+{{{26.192053931854691, 9.8504326817814416}, {10.174241480498686, 98.476562741434464},
+ {21.177712558385782, 33.814968789841501}, {75.329030899018534, 55.02231980442177}}},
+{{{56.222082700683771, 24.54395039218662}, {95.589995289030483, 81.050822735322086},
+ {28.180450866082897, 28.837706255185282}, {60.128952916771617, 87.311672180570511}}},
+
+{{{42.449716172390481, 52.379709366885805}, {27.896043159019225, 48.797373636065686},
+ {92.770268299044233, 89.899302036454571}, {12.102066544863426, 99.43241951960718}}},
+{{{45.77532924980639, 45.958701495993274}, {37.458701356062065, 68.393691335056758},
+ {37.569326692060258, 27.673713456687381}, {60.674866037757539, 62.47349659096146}}},
+
+{{{67.426548091427676, 37.993772624988935}, {23.483695892376684, 90.476863174921306},
+ {35.597065061143162, 79.872482633158796}, {75.38634169631932, 18.244890038969412}}},
+{{{61.336508189019057, 82.693132843213675}, {44.639380902349664, 54.074825790745592},
+ {16.815615499771951, 20.049704667203923}, {41.866884958868326, 56.735503699973002}}},
+
+{{{18.1312339, 31.6473732}, {95.5711034, 63.5350219}, {92.3283165, 62.0158945},
+ {18.5656052, 32.1268808}}},
+{{{97.402018, 35.7169972}, {33.1127443, 25.8935163}, {1.13970027, 54.9424981},
+ {56.4860195, 60.529264}}},
+};
+
+const int testSetCount = (int) SK_ARRAY_COUNT(testSet);
+
+static const SkDCubic newTestSet[] = {
+{{{980.9000244140625, 1474.3280029296875}, {980.9000244140625, 1474.3280029296875}, {978.89300537109375, 1471.95703125}, {981.791015625, 1469.487060546875}}},
+{{{981.791015625, 1469.487060546875}, {981.791015625, 1469.4859619140625}, {983.3580322265625, 1472.72900390625}, {980.9000244140625, 1474.3280029296875}}},
+
+{{{275,532}, {277.209137,532}, {279,530.209106}, {279,528}}},
+{{{278,529}, {278,530.65686}, {276.65686,532}, {275,532}}},
+
+#if 0 // FIXME: asserts coincidence, not working yet
+{{{195, 785}, {124.30755615234375, 785}, {67, 841.85986328125}, {67, 912}}},
+{{{67, 913}, {67, 842.30755615234375}, {123.85984039306641, 785}, {194, 785}}},
+#endif
+
+{{{149,710.001465}, {149.000809,712.209961}, {150.791367,714}, {153,714}}},
+{{{154,715}, {151.238571,715}, {149,712.761414}, {149,710}}},
+
+{{{1,2}, {1,2}, {2,0}, {6,0}}},
+{{{0,2}, {0,6}, {2,1}, {2,1}}},
+
+{{{0,1}, {2,3}, {5,1}, {4,3}}},
+{{{1,5}, {3,4}, {1,0}, {3,2}}},
+
+{{{399,657}, {399,661.970581}, {403.029449,666}, {408,666}}},
+{{{406,666}, {402.686279,666}, {400,663.313721}, {400,660}}},
+
+{{{0,5}, {3,5}, {3,0}, {3,2}}},
+{{{0,3}, {2,3}, {5,0}, {5,3}}},
+
+{{{132, 11419}, {130.89543151855469, 11419}, {130, 11418.1044921875}, {130, 11417}}},
+
+{{{3, 4}, {1, 5}, {4, 3}, {6, 4}}},
+{{{3, 4}, {4, 6}, {4, 3}, {5, 1}}},
+
+{{{130.04275512695312, 11417.413085937500 },
+ {130.23312377929687, 11418.319335937500 },
+ {131.03707885742187, 11419.000000000000 },
+ {132.00000000000000, 11419.000000000000 }}},
+
+{{{132.00000000000000, 11419.000000000000 },
+ {130.89543151855469, 11419.000000000000 },
+ {130.00000000000000, 11418.104492187500 },
+ {130.00000000000000, 11417.000000000000 }}},
+
+{{{1.0516976506771041, 2.9684399028541346 },
+ {1.0604363140895228, 2.9633503074444141 },
+ {1.0692548215065762, 2.9580354426587459 },
+ {1.0781560339512140, 2.9525043684031349 }}},
+
+{{{1.0523038101345104, 2.9523755204833737 },
+ {1.0607035288264237, 2.9580853881628375 },
+ {1.0690530472271964, 2.9633896794787749 },
+ {1.0773566568712512, 2.9682969775000219 }}},
+
+{{{1.0386522625066592, 2.9759024812329078 },
+ {1.0559713690392631, 2.9661782500838885 },
+ {1.0736041309019990, 2.9555348259177858 },
+ {1.0915734362784633, 2.9440446879826569 }}},
+
+{{{1.0396670794879301, 2.9435062123457261 },
+ {1.0565690546812769, 2.9557413250983462 },
+ {1.0732616463413533, 2.9663369676594282 },
+ {1.0897791867435489, 2.9753618045797472 }}},
+
+{{{0.8685656183311091, 3.0409266475785208 },
+ {0.99189542936395292, 3.0212163698184424 },
+ {1.1302108367493320, 2.9265646471747306 },
+ {1.2952305904872474, 2.7940808546473788 }}},
+
+{{{0.85437872843682727, 2.7536036928549055 },
+ {1.0045584590592620, 2.9493041024831705 },
+ {1.1336998329885613, 3.0248027987251747 },
+ {1.2593809752247314, 3.0152560315809107 }}},
+
+{{{0, 1}, {1, 6}, {1, 0}, {6, 2}}},
+{{{0, 1}, {2, 6}, {1, 0}, {6, 1}}},
+
+{{{134,11414}, {131.990234375,11414}, {130.32666015625,11415.482421875}, {130.04275512695312,11417.4130859375}}},
+{{{132,11419}, {130.89543151855469,11419}, {130,11418.1044921875}, {130,11417}}},
+
+{{{132,11419}, {130.89543151855469,11419}, {130,11418.1044921875}, {130,11417}}},
+{{{130.04275512695312,11417.4130859375}, {130.23312377929687,11418.3193359375}, {131.03707885742187,11419}, {132,11419}}},
+
+{{{0, 1}, {2, 3}, {5, 1}, {4, 3}}},
+{{{1, 5}, {3, 4}, {1, 0}, {3, 2}}},
+
+{{{3, 5}, {1, 6}, {5, 0}, {3, 1}}},
+{{{0, 5}, {1, 3}, {5, 3}, {6, 1}}},
+
+{{{0, 1}, {1, 5}, {1, 0}, {1, 0}}},
+{{{0, 1}, {0, 1}, {1, 0}, {5, 1}}},
+
+{{{1, 3}, {5, 6}, {5, 3}, {5, 4}}},
+{{{3, 5}, {4, 5}, {3, 1}, {6, 5}}},
+
+{{{0, 5}, {0, 5}, {5, 4}, {6, 4}}},
+{{{4, 5}, {4, 6}, {5, 0}, {5, 0}}},
+
+{{{0, 4}, {1, 3}, {5, 4}, {4, 2}}},
+{{{4, 5}, {2, 4}, {4, 0}, {3, 1}}},
+
+{{{0, 2}, {1, 5}, {3, 2}, {4, 1}}},
+{{{2, 3}, {1, 4}, {2, 0}, {5, 1}}},
+
+{{{0, 2}, {2, 3}, {5, 1}, {3, 2}}},
+{{{1, 5}, {2, 3}, {2, 0}, {3, 2}}},
+
+{{{2, 6}, {4, 5}, {1, 0}, {6, 1}}},
+{{{0, 1}, {1, 6}, {6, 2}, {5, 4}}},
+
+{{{0, 1}, {1, 2}, {6, 5}, {5, 4}}},
+{{{5, 6}, {4, 5}, {1, 0}, {2, 1}}},
+
+{{{2.5119999999999996, 1.5710000000000002}, {2.6399999999999983, 1.6599999999999997},
+ {2.8000000000000007, 1.8000000000000003}, {3, 2}}},
+{{{2.4181876227114887, 1.9849772580462195}, {2.8269904869227211, 2.009330650246834},
+ {3.2004679292461624, 1.9942047174679169}, {3.4986199496818058, 2.0035994597094731}}},
+
+{{{2, 3}, {1, 4}, {1, 0}, {6, 0}}},
+{{{0, 1}, {0, 6}, {3, 2}, {4, 1}}},
+
+{{{0, 2}, {1, 5}, {1, 0}, {6, 1}}},
+{{{0, 1}, {1, 6}, {2, 0}, {5, 1}}},
+
+{{{0, 1}, {1, 5}, {2, 1}, {4, 0}}},
+{{{1, 2}, {0, 4}, {1, 0}, {5, 1}}},
+
+{{{0, 1}, {3, 5}, {2, 1}, {3, 1}}},
+{{{1, 2}, {1, 3}, {1, 0}, {5, 3}}},
+
+{{{0, 1}, {2, 5}, {6, 0}, {5, 3}}},
+{{{0, 6}, {3, 5}, {1, 0}, {5, 2}}},
+
+{{{0, 1}, {3, 6}, {1, 0}, {5, 2}}},
+{{{0, 1}, {2, 5}, {1, 0}, {6, 3}}},
+
+{{{1, 2}, {5, 6}, {1, 0}, {1, 0}}},
+{{{0, 1}, {0, 1}, {2, 1}, {6, 5}}},
+
+{{{0, 6}, {1, 2}, {1, 0}, {1, 0}}},
+{{{0, 1}, {0, 1}, {6, 0}, {2, 1}}},
+
+{{{0, 2}, {0, 1}, {3, 0}, {1, 0}}},
+{{{0, 3}, {0, 1}, {2, 0}, {1, 0}}},
+};
+
+const int newTestSetCount = (int) SK_ARRAY_COUNT(newTestSet);
+
+static void oneOff(skiatest::Reporter* reporter, const SkDCubic& cubic1, const SkDCubic& cubic2,
+ bool coin) {
+ SkASSERT(ValidCubic(cubic1));
+ SkASSERT(ValidCubic(cubic2));
+#if ONE_OFF_DEBUG
+ SkDebugf("computed quadratics given\n");
+ SkDebugf(" {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n",
+ cubic1[0].fX, cubic1[0].fY, cubic1[1].fX, cubic1[1].fY,
+ cubic1[2].fX, cubic1[2].fY, cubic1[3].fX, cubic1[3].fY);
+ SkDebugf(" {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n",
+ cubic2[0].fX, cubic2[0].fY, cubic2[1].fX, cubic2[1].fY,
+ cubic2[2].fX, cubic2[2].fY, cubic2[3].fX, cubic2[3].fY);
+#endif
+ SkTArray<SkDQuad, true> quads1;
+ CubicToQuads(cubic1, cubic1.calcPrecision(), quads1);
+#if ONE_OFF_DEBUG
+ SkDebugf("computed quadratics set 1\n");
+ for (int index = 0; index < quads1.count(); ++index) {
+ const SkDQuad& q = quads1[index];
+ SkDebugf(" {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].fX, q[0].fY,
+ q[1].fX, q[1].fY, q[2].fX, q[2].fY);
+ }
+#endif
+ SkTArray<SkDQuad, true> quads2;
+ CubicToQuads(cubic2, cubic2.calcPrecision(), quads2);
+#if ONE_OFF_DEBUG
+ SkDebugf("computed quadratics set 2\n");
+ for (int index = 0; index < quads2.count(); ++index) {
+ const SkDQuad& q = quads2[index];
+ SkDebugf(" {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].fX, q[0].fY,
+ q[1].fX, q[1].fY, q[2].fX, q[2].fY);
+ }
+#endif
+ SkIntersections intersections;
+ intersections.intersect(cubic1, cubic2);
+ REPORTER_ASSERT(reporter, !coin || intersections.used() == 2);
+ double tt1, tt2;
+ SkDPoint xy1, xy2;
+ for (int pt3 = 0; pt3 < intersections.used(); ++pt3) {
+ tt1 = intersections[0][pt3];
+ xy1 = cubic1.ptAtT(tt1);
+ tt2 = intersections[1][pt3];
+ xy2 = cubic2.ptAtT(tt2);
+ const SkDPoint& iPt = intersections.pt(pt3);
+#if ONE_OFF_DEBUG
+ SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g) (%1.9g, %1.9g) t2=%1.9g\n",
+ __FUNCTION__, tt1, xy1.fX, xy1.fY, iPt.fX,
+ iPt.fY, xy2.fX, xy2.fY, tt2);
+#endif
+ REPORTER_ASSERT(reporter, xy1.approximatelyEqual(iPt));
+ REPORTER_ASSERT(reporter, xy2.approximatelyEqual(iPt));
+ REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
+ }
+ reporter->bumpTestCount();
+}
+
+static void oneOff(skiatest::Reporter* reporter, int outer, int inner) {
+ const SkDCubic& cubic1 = testSet[outer];
+ const SkDCubic& cubic2 = testSet[inner];
+ oneOff(reporter, cubic1, cubic2, false);
+}
+
+static void newOneOff(skiatest::Reporter* reporter, int outer, int inner) {
+ const SkDCubic& cubic1 = newTestSet[outer];
+ const SkDCubic& cubic2 = newTestSet[inner];
+ oneOff(reporter, cubic1, cubic2, false);
+}
+
+static void oneOffTests(skiatest::Reporter* reporter) {
+ for (int outer = 0; outer < testSetCount - 1; ++outer) {
+ for (int inner = outer + 1; inner < testSetCount; ++inner) {
+ oneOff(reporter, outer, inner);
+ }
+ }
+ for (int outer = 0; outer < newTestSetCount - 1; ++outer) {
+ for (int inner = outer + 1; inner < newTestSetCount; ++inner) {
+ newOneOff(reporter, outer, inner);
+ }
+ }
+}
+
+#define DEBUG_CRASH 0
+
+static void CubicIntersection_RandTest(skiatest::Reporter* reporter) {
+ srand(0);
+ const int tests = 10000000;
+#if !defined(SK_BUILD_FOR_WIN) && !defined(SK_BUILD_FOR_ANDROID)
+ unsigned seed = 0;
+#endif
+ for (int test = 0; test < tests; ++test) {
+ SkDCubic cubic1, cubic2;
+ for (int i = 0; i < 4; ++i) {
+ cubic1[i].fX = static_cast<double>(SK_RAND(seed)) / RAND_MAX * 100;
+ cubic1[i].fY = static_cast<double>(SK_RAND(seed)) / RAND_MAX * 100;
+ cubic2[i].fX = static_cast<double>(SK_RAND(seed)) / RAND_MAX * 100;
+ cubic2[i].fY = static_cast<double>(SK_RAND(seed)) / RAND_MAX * 100;
+ }
+ #if DEBUG_CRASH
+ char str[1024];
+ snprintf(str, sizeof(str),
+ "{{{%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}}},\n"
+ "{{{%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}}},\n",
+ cubic1[0].fX, cubic1[0].fY, cubic1[1].fX, cubic1[1].fY, cubic1[2].fX, cubic1[2].fY,
+ cubic1[3].fX, cubic1[3].fY,
+ cubic2[0].fX, cubic2[0].fY, cubic2[1].fX, cubic2[1].fY, cubic2[2].fX, cubic2[2].fY,
+ cubic2[3].fX, cubic2[3].fY);
+ #endif
+ SkDRect rect1, rect2;
+ rect1.setBounds(cubic1);
+ rect2.setBounds(cubic2);
+ bool boundsIntersect = rect1.fLeft <= rect2.fRight && rect2.fLeft <= rect2.fRight
+ && rect1.fTop <= rect2.fBottom && rect2.fTop <= rect1.fBottom;
+ if (test == -1) {
+ SkDebugf("ready...\n");
+ }
+ SkIntersections intersections2;
+ int newIntersects = intersections2.intersect(cubic1, cubic2);
+ if (!boundsIntersect && newIntersects) {
+ #if DEBUG_CRASH
+ SkDebugf("%s %d unexpected intersection boundsIntersect=%d "
+ " newIntersects=%d\n%s %s\n", __FUNCTION__, test, boundsIntersect,
+ newIntersects, __FUNCTION__, str);
+ #endif
+ REPORTER_ASSERT(reporter, 0);
+ }
+ for (int pt = 0; pt < intersections2.used(); ++pt) {
+ double tt1 = intersections2[0][pt];
+ SkDPoint xy1 = cubic1.ptAtT(tt1);
+ double tt2 = intersections2[1][pt];
+ SkDPoint xy2 = cubic2.ptAtT(tt2);
+ REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
+ }
+ reporter->bumpTestCount();
+ }
+}
+
+static void intersectionFinder(int index0, int index1, double t1Seed, double t2Seed,
+ double t1Step, double t2Step) {
+ const SkDCubic& cubic1 = newTestSet[index0];
+ const SkDCubic& cubic2 = newTestSet[index1];
+ SkDPoint t1[3], t2[3];
+ bool toggle = true;
+ do {
+ t1[0] = cubic1.ptAtT(t1Seed - t1Step);
+ t1[1] = cubic1.ptAtT(t1Seed);
+ t1[2] = cubic1.ptAtT(t1Seed + t1Step);
+ t2[0] = cubic2.ptAtT(t2Seed - t2Step);
+ t2[1] = cubic2.ptAtT(t2Seed);
+ t2[2] = cubic2.ptAtT(t2Seed + t2Step);
+ double dist[3][3];
+ dist[1][1] = t1[1].distance(t2[1]);
+ int best_i = 1, best_j = 1;
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ if (i == 1 && j == 1) {
+ continue;
+ }
+ dist[i][j] = t1[i].distance(t2[j]);
+ if (dist[best_i][best_j] > dist[i][j]) {
+ best_i = i;
+ best_j = j;
+ }
+ }
+ }
+ if (best_i == 0) {
+ t1Seed -= t1Step;
+ } else if (best_i == 2) {
+ t1Seed += t1Step;
+ }
+ if (best_j == 0) {
+ t2Seed -= t2Step;
+ } else if (best_j == 2) {
+ t2Seed += t2Step;
+ }
+ if (best_i == 1 && best_j == 1) {
+ if ((toggle ^= true)) {
+ t1Step /= 2;
+ } else {
+ t2Step /= 2;
+ }
+ }
+ } while (!t1[1].approximatelyEqual(t2[1]));
+ t1Step = t2Step = 0.1;
+ double t10 = t1Seed - t1Step * 2;
+ double t12 = t1Seed + t1Step * 2;
+ double t20 = t2Seed - t2Step * 2;
+ double t22 = t2Seed + t2Step * 2;
+ SkDPoint test;
+ while (!approximately_zero(t1Step)) {
+ test = cubic1.ptAtT(t10);
+ t10 += t1[1].approximatelyEqual(test) ? -t1Step : t1Step;
+ t1Step /= 2;
+ }
+ t1Step = 0.1;
+ while (!approximately_zero(t1Step)) {
+ test = cubic1.ptAtT(t12);
+ t12 -= t1[1].approximatelyEqual(test) ? -t1Step : t1Step;
+ t1Step /= 2;
+ }
+ while (!approximately_zero(t2Step)) {
+ test = cubic2.ptAtT(t20);
+ t20 += t2[1].approximatelyEqual(test) ? -t2Step : t2Step;
+ t2Step /= 2;
+ }
+ t2Step = 0.1;
+ while (!approximately_zero(t2Step)) {
+ test = cubic2.ptAtT(t22);
+ t22 -= t2[1].approximatelyEqual(test) ? -t2Step : t2Step;
+ t2Step /= 2;
+ }
+#if ONE_OFF_DEBUG
+ SkDebugf("%s t1=(%1.9g<%1.9g<%1.9g) t2=(%1.9g<%1.9g<%1.9g)\n", __FUNCTION__,
+ t10, t1Seed, t12, t20, t2Seed, t22);
+ SkDPoint p10 = cubic1.ptAtT(t10);
+ SkDPoint p1Seed = cubic1.ptAtT(t1Seed);
+ SkDPoint p12 = cubic1.ptAtT(t12);
+ SkDebugf("%s p1=(%1.9g,%1.9g)<(%1.9g,%1.9g)<(%1.9g,%1.9g)\n", __FUNCTION__,
+ p10.fX, p10.fY, p1Seed.fX, p1Seed.fY, p12.fX, p12.fY);
+ SkDPoint p20 = cubic2.ptAtT(t20);
+ SkDPoint p2Seed = cubic2.ptAtT(t2Seed);
+ SkDPoint p22 = cubic2.ptAtT(t22);
+ SkDebugf("%s p2=(%1.9g,%1.9g)<(%1.9g,%1.9g)<(%1.9g,%1.9g)\n", __FUNCTION__,
+ p20.fX, p20.fY, p2Seed.fX, p2Seed.fY, p22.fX, p22.fY);
+#endif
+}
+
+static void CubicIntersection_IntersectionFinder() {
+// double t1Seed = 0.87;
+// double t2Seed = 0.87;
+ double t1Step = 0.000001;
+ double t2Step = 0.000001;
+ intersectionFinder(0, 1, 0.855895664, 0.864850875, t1Step, t2Step);
+ intersectionFinder(0, 1, 0.865207906, 0.865207887, t1Step, t2Step);
+ intersectionFinder(0, 1, 0.865213351, 0.865208087, t1Step, t2Step);
+}
+
+static const SkDCubic selfSet[] = {
+ {{{2, 3}, {0, 4}, {3, 2}, {5, 3}}},
+ {{{3, 6}, {2, 3}, {4, 0}, {3, 2}}},
+ {{{0, 2}, {2, 3}, {5, 1}, {3, 2}}},
+ {{{0, 2}, {3, 5}, {5, 0}, {4, 2}}},
+ {{{3.34, 8.98}, {1.95, 10.27}, {3.76, 7.65}, {4.96, 10.64}}},
+ {{{3.13, 2.74}, {1.08, 4.62}, {3.71, 0.94}, {2.01, 3.81}}},
+ {{{6.71, 3.14}, {7.99, 2.75}, {8.27, 1.96}, {6.35, 3.57}}},
+ {{{12.81, 7.27}, {7.22, 6.98}, {12.49, 8.97}, {11.42, 6.18}}},
+};
+
+int selfSetCount = (int) SK_ARRAY_COUNT(selfSet);
+
+static void selfOneOff(skiatest::Reporter* reporter, int index) {
+ const SkDCubic& cubic = selfSet[index];
+#if ONE_OFF_DEBUG
+ int idx2;
+ double max[3];
+ int ts = cubic.findMaxCurvature(max);
+ for (idx2 = 0; idx2 < ts; ++idx2) {
+ SkDebugf("%s max[%d]=%1.9g (%1.9g, %1.9g)\n", __FUNCTION__, idx2,
+ max[idx2], cubic.ptAtT(max[idx2]).fX, cubic.ptAtT(max[idx2]).fY);
+ }
+ SkTArray<double, true> ts1;
+ SkTArray<SkDQuad, true> quads1;
+ cubic.toQuadraticTs(cubic.calcPrecision(), &ts1);
+ for (idx2 = 0; idx2 < ts1.count(); ++idx2) {
+ SkDebugf("%s t[%d]=%1.9g\n", __FUNCTION__, idx2, ts1[idx2]);
+ }
+ CubicToQuads(cubic, cubic.calcPrecision(), quads1);
+ for (idx2 = 0; idx2 < quads1.count(); ++idx2) {
+ const SkDQuad& q = quads1[idx2];
+ SkDebugf(" {{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}},\n",
+ q[0].fX, q[0].fY, q[1].fX, q[1].fY, q[2].fX, q[2].fY);
+ }
+ SkDebugf("\n");
+#endif
+ SkIntersections i;
+ int result = i.intersect(cubic);
+ REPORTER_ASSERT(reporter, result == 1);
+ REPORTER_ASSERT(reporter, i.used() == 1);
+ REPORTER_ASSERT(reporter, !approximately_equal(i[0][0], i[1][0]));
+ SkDPoint pt1 = cubic.ptAtT(i[0][0]);
+ SkDPoint pt2 = cubic.ptAtT(i[1][0]);
+ REPORTER_ASSERT(reporter, pt1.approximatelyEqual(pt2));
+ reporter->bumpTestCount();
+}
+
+static void cubicIntersectionSelfTest(skiatest::Reporter* reporter) {
+ int firstFail = 0;
+ for (int index = firstFail; index < selfSetCount; ++index) {
+ selfOneOff(reporter, index);
+ }
+}
+
+static const SkDCubic coinSet[] = {
+ {{{297.04998779296875, 43.928997039794922}, {297.04998779296875, 43.928997039794922},
+ {300.69699096679688, 45.391998291015625}, {306.92498779296875, 43.08599853515625}}},
+ {{{297.04998779296875, 43.928997039794922}, {297.04998779296875, 43.928997039794922},
+ {300.69699096679688, 45.391998291015625}, {306.92498779296875, 43.08599853515625}}},
+
+ {{{2, 3}, {0, 4}, {3, 2}, {5, 3}}},
+ {{{2, 3}, {0, 4}, {3, 2}, {5, 3}}},
+
+ {{{317, 711}, {322.52285766601562, 711}, {327, 715.4771728515625}, {327, 721}}},
+ {{{324.07107543945312, 713.928955078125}, {324.4051513671875, 714.26300048828125},
+ {324.71566772460937, 714.62060546875}, {325, 714.9990234375}}},
+
+ {{{2, 3}, {0, 4}, {3, 2}, {5, 3}}},
+ {{{2, 3}, {0, 4}, {3, 2}, {5, 3}}},
+};
+
+static int coinSetCount = (int) SK_ARRAY_COUNT(coinSet);
+
+static void coinOneOff(skiatest::Reporter* reporter, int index) {
+ const SkDCubic& cubic1 = coinSet[index];
+ const SkDCubic& cubic2 = coinSet[index + 1];
+ oneOff(reporter, cubic1, cubic2, true);
+}
+
+static void cubicIntersectionCoinTest(skiatest::Reporter* reporter) {
+ int firstFail = 0;
+ for (int index = firstFail; index < coinSetCount; index += 2) {
+ coinOneOff(reporter, index);
+ }
+}
+
+DEF_TEST(PathOpsCubicCoinOneOff, reporter) {
+ coinOneOff(reporter, 0);
+}
+
+DEF_TEST(PathOpsCubicIntersectionOneOff, reporter) {
+ newOneOff(reporter, 0, 1);
+}
+
+DEF_TEST(PathOpsCubicSelfOneOff, reporter) {
+ selfOneOff(reporter, 0);
+}
+
+DEF_TEST(PathOpsCubicIntersection, reporter) {
+ oneOffTests(reporter);
+ cubicIntersectionSelfTest(reporter);
+ cubicIntersectionCoinTest(reporter);
+ standardTestCases(reporter);
+ if (false) CubicIntersection_IntersectionFinder();
+ if (false) CubicIntersection_RandTest(reporter);
+}
diff --git a/src/third_party/skia/tests/PathOpsCubicIntersectionTestData.cpp b/src/third_party/skia/tests/PathOpsCubicIntersectionTestData.cpp
new file mode 100644
index 0000000..31056d2
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsCubicIntersectionTestData.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "PathOpsCubicIntersectionTestData.h"
+
+#include <limits>
+
+static const double D = FLT_EPSILON / 2;
+static const double G = FLT_EPSILON / 3;
+static const double N = -FLT_EPSILON / 2;
+static const double M = -FLT_EPSILON / 3;
+
+const SkDCubic pointDegenerates[] = {
+ {{{0, 0}, {0, 0}, {0, 0}, {0, 0}}},
+ {{{1, 1}, {1, 1}, {1, 1}, {1, 1}}},
+ {{{1 + FLT_EPSILON_HALF, 1}, {1, 1 + FLT_EPSILON_HALF}, {1, 1}, {1, 1}}},
+ {{{1 + D, 1}, {1 - D, 1}, {1, 1}, {1, 1}}},
+ {{{0, 0}, {0, 0}, {1, 0}, {0, 0}}},
+ {{{0, 0}, {1, 0}, {0, 0}, {0, 0}}},
+ {{{0, 0}, {0, 0}, {0, 1}, {0, 0}}},
+ {{{0, 0}, {0, 1}, {0, 0}, {0, 0}}},
+ {{{0, 0}, {0, 0}, {1, 1}, {0, 0}}},
+ {{{0, 0}, {1, 1}, {0, 0}, {0, 0}}},
+ {{{0, 0}, {1, 1}, {2, 2}, {0, 0}}},
+ {{{1, 1}, {2, 2}, {2, 2}, {1, 1}}},
+ {{{0, 0}, {0, D}, {1, 0}, {0, 0}}},
+ {{{0, 0}, {1, 0}, {0, D}, {0, 0}}},
+ {{{0, 0}, {D, 0}, {0, 1}, {0, 0}}},
+ {{{0, 0}, {0, 1}, {D, 0}, {0, 0}}},
+ {{{1, 1}, {2, 2}, {2, 2+D}, {1, 1}}},
+ {{{0, 0}, {0, N}, {1, 0}, {0, 0}}},
+ {{{0, 0}, {1, 0}, {0, N}, {0, 0}}},
+ {{{0, 0}, {N, 0}, {0, 1}, {0, 0}}},
+ {{{0, 0}, {0, 1}, {N, 0}, {0, 0}}},
+ {{{0, 0}, {1, 1}, {N, 0}, {0, 0}}},
+ {{{0, 0}, {D, 0}, {1, 1}, {0, 0}}},
+ {{{0, 0}, {1, 1}, {D, 0}, {0, 0}}},
+ {{{0, 0}, {N, 0}, {1, 1}, {0, 0}}},
+ {{{1, 1}, {2, 2}, {2, 2+N}, {1, 1}}},
+};
+
+const size_t pointDegenerates_count = SK_ARRAY_COUNT(pointDegenerates);
+
+const SkDCubic notPointDegenerates[] = {
+ {{{1 + FLT_EPSILON * 2, 1}, {1, FLT_EPSILON * 2}, {1, 1}, {1, 1}}},
+ {{{1 + FLT_EPSILON * 2, 1}, {1 - FLT_EPSILON * 2, 1}, {1, 1}, {1, 1}}}
+};
+
+const size_t notPointDegenerates_count =
+ SK_ARRAY_COUNT(notPointDegenerates);
+
+// from http://www.truetex.com/bezint.htm
+const SkDCubic tests[][2] = {
+ { // intersects in one place (data gives bezier clip fits
+ {{{0, 45},
+ {6.0094158284751593, 51.610357411322688},
+ {12.741093228940867, 55.981703949474607},
+ {20.021417396476362, 58.652245509710262}}},
+ {{{2.2070737699246674, 52.703494107327209},
+ {31.591482272629477, 23.811002295222025},
+ {76.824588616426425, 44.049473790502674},
+ {119.25488947221436, 55.599248272955073}}}
+ }, { // intersects in three places
+ {{{0, 45}, {50, 100}, {150, 0}, {200, 55}}},
+ {{{0, 55}, {50, 0}, {150, 100}, {200, 45}}}
+ }, { // intersects in one place, cross over is nearly parallel
+ {{{0, 0}, {0, 100}, {200, 0}, {200, 100}}},
+ {{{0, 100}, {0, 0}, {200, 100}, {200, 0}}}
+ }, { // intersects in two places
+ {{{0, 0}, {0, 100}, {200, 100}, {200, 0}}},
+ {{{0, 100}, {0, 0}, {200, 0}, {200, 100}}}
+ }, {
+ {{{150, 100}, {150 + 0.1, 150}, {150, 200}, {150, 250}}},
+ {{{250, 150}, {200, 150 + 0.1}, {150, 150}, {100, 150}}}
+ }, { // single intersection around 168,185
+ {{{200, 100}, {150, 100}, {150, 150}, {200, 150}}},
+ {{{250, 150}, {250, 100}, {100, 100}, {100, 150}}}
+ }, {
+ {{{1.0, 1.5}, {15.5, 0.5}, {-8.0, 3.5}, {5.0, 1.5}}},
+ {{{4.0, 0.5}, {5.0, 15.0}, {2.0, -8.5}, {4.0, 4.5}}}
+ }, {
+ {{{664.00168, 0}, {726.11545, 124.22757}, {736.89069, 267.89743},
+ {694.0017, 400.0002}}},
+ {{{850.66843, 115.55563}, {728.515, 115.55563}, {725.21347, 275.15309},
+ {694.0017, 400.0002}}}
+ }, {
+ {{{1, 1}, {12.5, 6.5}, {-4, 6.5}, {7.5, 1}}},
+ {{{1, 6.5}, {12.5, 1}, {-4, 1}, {.5, 6}}}
+ }, {
+ {{{315.748, 312.84}, {312.644, 318.134}, {305.836, 319.909}, {300.542, 316.804}}},
+ {{{317.122, 309.05}, {316.112, 315.102}, {310.385, 319.19}, {304.332, 318.179}}}
+ }, {
+ {{{1046.604051, 172.937967}, {1046.604051, 178.9763059}, {1041.76745, 183.9279165}, {1035.703842, 184.0432409}}},
+ {{{1046.452235, 174.7640504}, {1045.544872, 180.1973817}, {1040.837966, 184.0469882}, {1035.505925, 184.0469882}}}
+ }, {
+ {{{125.79356, 199.57382}, {51.16556, 128.93575}, {87.494, 16.67848}, {167.29361, 16.67848}}},
+ {{{167.29361, 55.81876}, {100.36128, 55.81876}, {68.64099, 145.4755}, {125.7942, 199.57309}}}
+ }, {
+ {{{104.11546583642826, 370.21352558595504}, {122.96968232592344, 404.54489231839295},
+ {169.90881005384728, 425.00067000000007}, {221.33045999999999, 425.00067000000001}}},
+ {{{116.32365976159625, 381.71048540582598}, {103.86096590870899, 381.71048540581626},
+ {91.394188003200725, 377.17917781762833}, {82.622283093355179, 368.11683661930334}}}
+ }
+};
+
+const size_t tests_count = SK_ARRAY_COUNT(tests);
+
+const SkDCubic lines[] = {
+ {{{0, 0}, {0, 0}, {0, 0}, {1, 0}}}, // 0: horizontal
+ {{{1, 0}, {0, 0}, {0, 0}, {0, 0}}},
+ {{{1, 0}, {2, 0}, {3, 0}, {4, 0}}},
+ {{{0, 0}, {0, 0}, {0, 0}, {0, 1}}}, // 5: vertical
+ {{{0, 1}, {0, 0}, {0, 0}, {0, 0}}},
+ {{{0, 1}, {0, 2}, {0, 3}, {0, 4}}},
+ {{{0, 0}, {0, 0}, {0, 0}, {1, 1}}}, // 10: 3 coincident
+ {{{1, 1}, {0, 0}, {0, 0}, {0, 0}}},
+ {{{0, 0}, {0, 0}, {1, 1}, {2, 2}}}, // 14: 2 coincident
+ {{{0, 0}, {1, 1}, {0, 0}, {2, 2}}},
+ {{{1, 1}, {0, 0}, {0, 0}, {2, 2}}}, // 17:
+ {{{1, 1}, {0, 0}, {2, 2}, {0, 0}}},
+ {{{1, 1}, {2, 2}, {0, 0}, {0, 0}}},
+ {{{1, 1}, {2, 2}, {3, 3}, {2, 2}}}, // middle-last coincident
+ {{{1, 1}, {2, 2}, {3, 3}, {3, 3}}}, // middle-last coincident
+ {{{1, 1}, {1, 1}, {2, 2}, {2, 2}}}, // 2 pairs coincident
+ {{{1, 1}, {2, 2}, {1, 1}, {2, 2}}},
+ {{{1, 1}, {1, 1}, {3, 3}, {3, 3}}}, // first-middle middle-last coincident
+ {{{1, 1}, {2, 2}, {3, 3}, {4, 4}}}, // no coincident
+ {{{1, 1}, {3, 3}, {2, 2}, {4, 4}}},
+ {{{1, 1}, {2, 2}, {4, 4}, {3, 3}}},
+ {{{1, 1}, {3, 3}, {4, 4}, {2, 2}}},
+ {{{1, 1}, {4, 4}, {2, 2}, {3, 3}}},
+ {{{1, 1}, {4, 4}, {3, 3}, {2, 2}}},
+ {{{2, 2}, {1, 1}, {3, 3}, {4, 4}}},
+ {{{2, 2}, {1, 1}, {4, 4}, {3, 3}}},
+ {{{2, 2}, {3, 3}, {1, 1}, {4, 4}}},
+ {{{2, 2}, {3, 3}, {4, 4}, {1, 1}}},
+ {{{2, 2}, {4, 4}, {1, 1}, {3, 3}}},
+ {{{2, 2}, {4, 4}, {3, 3}, {1, 1}}},
+};
+
+const size_t lines_count = SK_ARRAY_COUNT(lines);
+
+// 'not a line' tries to fool the line detection code
+const SkDCubic notLines[] = {
+ {{{0, 0}, {0, 0}, {0, 1}, {1, 0}}},
+ {{{0, 0}, {0, 1}, {0, 0}, {1, 0}}},
+ {{{0, 0}, {0, 1}, {1, 0}, {0, 0}}},
+ {{{0, 1}, {0, 0}, {0, 0}, {1, 0}}},
+ {{{0, 1}, {0, 0}, {1, 0}, {0, 0}}},
+ {{{0, 1}, {1, 0}, {0, 0}, {0, 0}}},
+};
+
+const size_t notLines_count = SK_ARRAY_COUNT(notLines);
+
+static const double E = FLT_EPSILON * 2;
+static const double F = FLT_EPSILON * 3;
+
+const SkDCubic modEpsilonLines[] = {
+ {{{0, E}, {0, 0}, {0, 0}, {1, 0}}}, // horizontal
+ {{{0, 0}, {0, E}, {1, 0}, {0, 0}}},
+ {{{0, 0}, {1, 0}, {0, E}, {0, 0}}},
+ {{{1, 0}, {0, 0}, {0, 0}, {0, E}}},
+ {{{1, E}, {2, 0}, {3, 0}, {4, 0}}},
+ {{{E, 0}, {0, 0}, {0, 0}, {0, 1}}}, // vertical
+ {{{0, 0}, {E, 0}, {0, 1}, {0, 0}}},
+ {{{0, 0}, {0, 1}, {E, 0}, {0, 0}}},
+ {{{0, 1}, {0, 0}, {0, 0}, {E, 0}}},
+ {{{E, 1}, {0, 2}, {0, 3}, {0, 4}}},
+ {{{E, 0}, {0, 0}, {0, 0}, {1, 1}}}, // 3 coincident
+ {{{0, 0}, {E, 0}, {1, 1}, {0, 0}}},
+ {{{0, 0}, {1, 1}, {E, 0}, {0, 0}}},
+ {{{1, 1}, {0, 0}, {0, 0}, {E, 0}}},
+ {{{0, E}, {0, 0}, {1, 1}, {2, 2}}}, // 2 coincident
+ {{{0, 0}, {1, 1}, {0, E}, {2, 2}}},
+ {{{0, 0}, {1, 1}, {2, 2}, {0, E}}},
+ {{{1, 1}, {0, E}, {0, 0}, {2, 2}}},
+ {{{1, 1}, {0, E}, {2, 2}, {0, 0}}},
+ {{{1, 1}, {2, 2}, {E, 0}, {0, 0}}},
+ {{{1, 1}, {2, 2+E}, {3, 3}, {2, 2}}}, // middle-last coincident
+ {{{1, 1}, {2+E, 2}, {3, 3}, {3, 3}}}, // middle-last coincident
+ {{{1, 1}, {1, 1}, {2, 2}, {2+E, 2}}}, // 2 pairs coincident
+ {{{1, 1}, {2, 2}, {1, 1}, {2+E, 2}}},
+ {{{1, 1}, {2, 2}, {2, 2+E}, {1, 1}}},
+ {{{1, 1}, {1, 1+E}, {3, 3}, {3, 3}}}, // first-middle middle-last coincident
+ {{{1, 1}, {2+E, 2}, {3, 3}, {4, 4}}}, // no coincident
+ {{{1, 1}, {3, 3}, {2, 2}, {4, 4+F}}}, // INVESTIGATE: why the epsilon is bigger
+ {{{1, 1+F}, {2, 2}, {4, 4}, {3, 3}}}, // INVESTIGATE: why the epsilon is bigger
+ {{{1, 1}, {3, 3}, {4, 4+E}, {2, 2}}},
+ {{{1, 1}, {4, 4}, {2, 2}, {3, 3+E}}},
+ {{{1, 1}, {4, 4}, {3, 3}, {2+E, 2}}},
+ {{{2, 2}, {1, 1}, {3+E, 3}, {4, 4}}},
+ {{{2, 2}, {1+E, 1}, {4, 4}, {3, 3}}},
+ {{{2, 2+E}, {3, 3}, {1, 1}, {4, 4}}},
+ {{{2+E, 2}, {3, 3}, {4, 4}, {1, 1}}},
+ {{{2, 2}, {4+E, 4}, {1, 1}, {3, 3}}},
+ {{{2, 2}, {4, 4}, {3, 3}, {1, 1+E}}},
+};
+
+const size_t modEpsilonLines_count = SK_ARRAY_COUNT(modEpsilonLines);
+
+const SkDCubic lessEpsilonLines[] = {
+ {{{0, D}, {0, 0}, {0, 0}, {1, 0}}}, // horizontal
+ {{{1, 0}, {0, 0}, {0, 0}, {0, D}}},
+ {{{1, D}, {2, 0}, {3, 0}, {4, 0}}},
+ {{{D, 0}, {0, 0}, {0, 0}, {0, 1}}}, // vertical
+ {{{0, 1}, {0, 0}, {0, 0}, {D, 0}}},
+ {{{D, 1}, {0, 2}, {0, 3}, {0, 4}}},
+ {{{D, 0}, {0, 0}, {0, 0}, {1, 1}}}, // 3 coincident
+ {{{1, 1}, {0, 0}, {0, 0}, {D, 0}}},
+ {{{0, D}, {0, 0}, {1, 1}, {2, 2}}}, // 2 coincident
+ {{{0, 0}, {1, 1}, {0, D}, {2, 2}}},
+ {{{0, 0}, {1, 1}, {2, 2}, {1, 1+D}}},
+ {{{1, 1}, {0, D}, {0, 0}, {2, 2}}},
+ {{{1, 1}, {0, D}, {2, 2}, {0, 0}}},
+ {{{1, 1}, {2, 2}, {D, 0}, {0, 0}}},
+ {{{1, 1}, {2, 2+D}, {3, 3}, {2, 2}}}, // middle-last coincident
+ {{{1, 1}, {2+D, 2}, {3, 3}, {3, 3}}}, // middle-last coincident
+ {{{1, 1}, {1, 1}, {2, 2}, {2+D, 2}}}, // 2 pairs coincident
+ {{{1, 1}, {2, 2}, {1, 1}, {2+D, 2}}},
+ {{{1, 1}, {1, 1+D}, {3, 3}, {3, 3}}}, // first-middle middle-last coincident
+ {{{1, 1}, {2+D/2, 2}, {3, 3}, {4, 4}}}, // no coincident (FIXME: N as opposed to N/2 failed)
+ {{{1, 1}, {3, 3}, {2, 2}, {4, 4+D}}},
+ {{{1, 1+D}, {2, 2}, {4, 4}, {3, 3}}},
+ {{{1, 1}, {3, 3}, {4, 4+D}, {2, 2}}},
+ {{{1, 1}, {4, 4}, {2, 2}, {3, 3+D}}},
+ {{{1, 1}, {4, 4}, {3, 3}, {2+G, 2}}}, // INVESTIGATE: why the epsilon is smaller
+ {{{2, 2}, {1, 1}, {3+D, 3}, {4, 4}}},
+ {{{2, 2}, {1+D, 1}, {4, 4}, {3, 3}}},
+ {{{2, 2+D}, {3, 3}, {1, 1}, {4, 4}}},
+ {{{2+G, 2}, {3, 3}, {4, 4}, {1, 1}}}, // INVESTIGATE: why the epsilon is smaller
+ {{{2, 2}, {4+D, 4}, {1, 1}, {3, 3}}},
+ {{{2, 2}, {4, 4}, {3, 3}, {1, 1+D}}},
+};
+
+const size_t lessEpsilonLines_count = SK_ARRAY_COUNT(lessEpsilonLines);
+
+const SkDCubic negEpsilonLines[] = {
+ {{{0, N}, {0, 0}, {0, 0}, {1, 0}}}, // horizontal
+ {{{1, 0}, {0, 0}, {0, 0}, {0, N}}},
+ {{{1, N}, {2, 0}, {3, 0}, {4, 0}}},
+ {{{N, 0}, {0, 0}, {0, 0}, {0, 1}}}, // vertical
+ {{{0, 1}, {0, 0}, {0, 0}, {N, 0}}},
+ {{{N, 1}, {0, 2}, {0, 3}, {0, 4}}},
+ {{{N, 0}, {0, 0}, {0, 0}, {1, 1}}}, // 3 coincident
+ {{{1, 1}, {0, 0}, {0, 0}, {N, 0}}},
+ {{{0, N}, {0, 0}, {1, 1}, {2, 2}}}, // 2 coincident
+ {{{0, 0}, {1, 1}, {0, N}, {2, 2}}},
+ {{{0, 0}, {1, 1}, {2, 2}, {1, 1+N}}},
+ {{{1, 1}, {0, N}, {0, 0}, {2, 2}}},
+ {{{1, 1}, {0, N}, {2, 2}, {0, 0}}},
+ {{{1, 1}, {2, 2}, {N, 0}, {0, 0}}},
+ {{{1, 1}, {2, 2+N}, {3, 3}, {2, 2}}}, // middle-last coincident
+ {{{1, 1}, {2+N, 2}, {3, 3}, {3, 3}}}, // middle-last coincident
+ {{{1, 1}, {1, 1}, {2, 2}, {2+N, 2}}}, // 2 pairs coincident
+ {{{1, 1}, {2, 2}, {1, 1}, {2+N, 2}}},
+ {{{1, 1}, {1, 1+N}, {3, 3}, {3, 3}}}, // first-middle middle-last coincident
+ {{{1, 1}, {2+N/2, 2}, {3, 3}, {4, 4}}}, // no coincident (FIXME: N as opposed to N/2 failed)
+ {{{1, 1}, {3, 3}, {2, 2}, {4, 4+N}}},
+ {{{1, 1+N}, {2, 2}, {4, 4}, {3, 3}}},
+ {{{1, 1}, {3, 3}, {4, 4+N}, {2, 2}}},
+ {{{1, 1}, {4, 4}, {2, 2}, {3, 3+N}}},
+ {{{1, 1}, {4, 4}, {3, 3}, {2+M, 2}}}, // INVESTIGATE: why the epsilon is smaller
+ {{{2, 2}, {1, 1}, {3+N, 3}, {4, 4}}},
+ {{{2, 2}, {1+N, 1}, {4, 4}, {3, 3}}},
+ {{{2, 2+N}, {3, 3}, {1, 1}, {4, 4}}},
+ {{{2+M, 2}, {3, 3}, {4, 4}, {1, 1}}}, // INVESTIGATE: why the epsilon is smaller
+ {{{2, 2}, {4+N, 4}, {1, 1}, {3, 3}}},
+ {{{2, 2}, {4, 4}, {3, 3}, {1, 1+N}}},
+};
+
+const size_t negEpsilonLines_count = SK_ARRAY_COUNT(negEpsilonLines);
diff --git a/src/third_party/skia/tests/PathOpsCubicIntersectionTestData.h b/src/third_party/skia/tests/PathOpsCubicIntersectionTestData.h
new file mode 100644
index 0000000..e37d571
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsCubicIntersectionTestData.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkPathOpsCubic.h"
+
+extern const SkDCubic pointDegenerates[];
+extern const SkDCubic notPointDegenerates[];
+extern const SkDCubic tests[][2];
+extern SkDCubic hexTests[][2];
+
+extern const SkDCubic lines[];
+extern const SkDCubic notLines[];
+extern const SkDCubic modEpsilonLines[];
+extern const SkDCubic lessEpsilonLines[];
+extern const SkDCubic negEpsilonLines[];
+
+extern const size_t pointDegenerates_count;
+extern const size_t notPointDegenerates_count;
+extern const size_t tests_count;
+extern const size_t hexTests_count;
+extern const size_t lines_count;
+extern const size_t notLines_count;
+extern const size_t modEpsilonLines_count;
+extern const size_t lessEpsilonLines_count;
+extern const size_t negEpsilonLines_count;
diff --git a/src/third_party/skia/tests/PathOpsCubicLineIntersectionIdeas.cpp b/src/third_party/skia/tests/PathOpsCubicLineIntersectionIdeas.cpp
new file mode 100644
index 0000000..6aec8b1
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsCubicLineIntersectionIdeas.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkIntersections.h"
+#include "SkPathOpsCubic.h"
+#include "SkPathOpsLine.h"
+#include "SkPathOpsQuad.h"
+#include "SkRandom.h"
+#include "SkReduceOrder.h"
+#include "Test.h"
+
+static bool gPathOpsCubicLineIntersectionIdeasVerbose = false;
+
+static struct CubicLineFailures {
+ SkDCubic c;
+ double t;
+ SkDPoint p;
+} cubicLineFailures[] = {
+ {{{{-164.3726806640625, 36.826904296875}, {-189.045166015625, -953.2220458984375},
+ {926.505859375, -897.36175537109375}, {-139.33489990234375, 204.40771484375}}},
+ 0.37329583, {107.54935269006289, -632.13736293162208}},
+ {{{{784.056884765625, -554.8350830078125}, {67.5489501953125, 509.0224609375},
+ {-447.713134765625, 751.375}, {415.7784423828125, 172.22265625}}},
+ 0.660005242, {-32.973148967736151, 478.01341797403569}},
+ {{{{-580.6834716796875, -127.044921875}, {-872.8983154296875, -945.54302978515625},
+ {260.8092041015625, -909.34991455078125}, {-976.2125244140625, -18.46551513671875}}},
+ 0.578826774, {-390.17910153915489, -687.21144412296007}},
+};
+
+int cubicLineFailuresCount = (int) SK_ARRAY_COUNT(cubicLineFailures);
+
+double measuredSteps[] = {
+ 9.15910731e-007, 8.6600277e-007, 7.4122059e-007, 6.92087618e-007, 8.35290245e-007,
+ 3.29763199e-007, 5.07547773e-007, 4.41294224e-007, 0, 0,
+ 3.76879167e-006, 1.06126249e-006, 2.36873967e-006, 1.62421134e-005, 3.09103599e-005,
+ 4.38917976e-005, 0.000112348938, 0.000243149242, 0.000433174114, 0.00170880232,
+ 0.00272619724, 0.00518844604, 0.000352621078, 0.00175960064, 0.027875185,
+ 0.0351329803, 0.103964925,
+};
+
+/* last output : errors=3121
+ 9.1796875e-007 8.59375e-007 7.5e-007 6.875e-007 8.4375e-007
+ 3.125e-007 5e-007 4.375e-007 0 0
+ 3.75e-006 1.09375e-006 2.1875e-006 1.640625e-005 3.0859375e-005
+ 4.38964844e-005 0.000112304687 0.000243164063 0.000433181763 0.00170898437
+ 0.00272619247 0.00518844604 0.000352621078 0.00175960064 0.027875185
+ 0.0351329803 0.103964925
+*/
+
+static double binary_search(const SkDCubic& cubic, double step, const SkDPoint& pt, double t,
+ int* iters) {
+ double firstStep = step;
+ do {
+ *iters += 1;
+ SkDPoint cubicAtT = cubic.ptAtT(t);
+ if (cubicAtT.approximatelyEqual(pt)) {
+ break;
+ }
+ double calcX = cubicAtT.fX - pt.fX;
+ double calcY = cubicAtT.fY - pt.fY;
+ double calcDist = calcX * calcX + calcY * calcY;
+ if (step == 0) {
+ SkDebugf("binary search failed: step=%1.9g cubic=", firstStep);
+ cubic.dump();
+ SkDebugf(" t=%1.9g ", t);
+ pt.dump();
+ SkDebugf("\n");
+ return -1;
+ }
+ double lastStep = step;
+ step /= 2;
+ SkDPoint lessPt = cubic.ptAtT(t - lastStep);
+ double lessX = lessPt.fX - pt.fX;
+ double lessY = lessPt.fY - pt.fY;
+ double lessDist = lessX * lessX + lessY * lessY;
+ // use larger x/y difference to choose step
+ if (calcDist > lessDist) {
+ t -= step;
+ t = SkTMax(0., t);
+ } else {
+ SkDPoint morePt = cubic.ptAtT(t + lastStep);
+ double moreX = morePt.fX - pt.fX;
+ double moreY = morePt.fY - pt.fY;
+ double moreDist = moreX * moreX + moreY * moreY;
+ if (calcDist <= moreDist) {
+ continue;
+ }
+ t += step;
+ t = SkTMin(1., t);
+ }
+ } while (true);
+ return t;
+}
+
+#if 0
+static bool r2check(double A, double B, double C, double D, double* R2MinusQ3Ptr) {
+ if (approximately_zero(A)
+ && approximately_zero_when_compared_to(A, B)
+ && approximately_zero_when_compared_to(A, C)
+ && approximately_zero_when_compared_to(A, D)) { // we're just a quadratic
+ return false;
+ }
+ if (approximately_zero_when_compared_to(D, A)
+ && approximately_zero_when_compared_to(D, B)
+ && approximately_zero_when_compared_to(D, C)) { // 0 is one root
+ return false;
+ }
+ if (approximately_zero(A + B + C + D)) { // 1 is one root
+ return false;
+ }
+ double a, b, c;
+ {
+ double invA = 1 / A;
+ a = B * invA;
+ b = C * invA;
+ c = D * invA;
+ }
+ double a2 = a * a;
+ double Q = (a2 - b * 3) / 9;
+ double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
+ double R2 = R * R;
+ double Q3 = Q * Q * Q;
+ double R2MinusQ3 = R2 - Q3;
+ *R2MinusQ3Ptr = R2MinusQ3;
+ return true;
+}
+#endif
+
+/* What is the relationship between the accuracy of the root in range and the magnitude of all
+ roots? To find out, create a bunch of cubics, and measure */
+
+DEF_TEST(PathOpsCubicLineRoots, reporter) {
+ if (!gPathOpsCubicLineIntersectionIdeasVerbose) { // slow; exclude it by default
+ return;
+ }
+ SkRandom ran;
+ double worstStep[256] = {0};
+ int errors = 0;
+ int iters = 0;
+ double smallestR2 = 0;
+ double largestR2 = 0;
+ for (int index = 0; index < 1000000000; ++index) {
+ SkDPoint origin = {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)};
+ SkDCubic cubic = {{origin,
+ {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
+ {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
+ {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)}
+ }};
+ // construct a line at a known intersection
+ double t = ran.nextRangeF(0, 1);
+ SkDPoint pt = cubic.ptAtT(t);
+ // skip answers with no intersections (although note the bug!) or two, or more
+ // see if the line / cubic has a fun range of roots
+ double A, B, C, D;
+ SkDCubic::Coefficients(&cubic[0].fY, &A, &B, &C, &D);
+ D -= pt.fY;
+ double allRoots[3] = {0}, validRoots[3] = {0};
+ int realRoots = SkDCubic::RootsReal(A, B, C, D, allRoots);
+ int valid = SkDQuad::AddValidTs(allRoots, realRoots, validRoots);
+ if (valid != 1) {
+ continue;
+ }
+ if (realRoots == 1) {
+ continue;
+ }
+ t = validRoots[0];
+ SkDPoint calcPt = cubic.ptAtT(t);
+ if (calcPt.approximatelyEqual(pt)) {
+ continue;
+ }
+#if 0
+ double R2MinusQ3;
+ if (r2check(A, B, C, D, &R2MinusQ3)) {
+ smallestR2 = SkTMin(smallestR2, R2MinusQ3);
+ largestR2 = SkTMax(largestR2, R2MinusQ3);
+ }
+#endif
+ double largest = SkTMax(fabs(allRoots[0]), fabs(allRoots[1]));
+ if (realRoots == 3) {
+ largest = SkTMax(largest, fabs(allRoots[2]));
+ }
+ int largeBits;
+ if (largest <= 1) {
+#if 0
+ SkDebugf("realRoots=%d (%1.9g, %1.9g, %1.9g) valid=%d (%1.9g, %1.9g, %1.9g)\n",
+ realRoots, allRoots[0], allRoots[1], allRoots[2], valid, validRoots[0],
+ validRoots[1], validRoots[2]);
+#endif
+ double smallest = SkTMin(allRoots[0], allRoots[1]);
+ if (realRoots == 3) {
+ smallest = SkTMin(smallest, allRoots[2]);
+ }
+ SK_ALWAYSBREAK(smallest < 0);
+ SK_ALWAYSBREAK(smallest >= -1);
+ largeBits = 0;
+ } else {
+ frexp(largest, &largeBits);
+ SK_ALWAYSBREAK(largeBits >= 0);
+ SK_ALWAYSBREAK(largeBits < 256);
+ }
+ double step = 1e-6;
+ if (largeBits > 21) {
+ step = 1e-1;
+ } else if (largeBits > 18) {
+ step = 1e-2;
+ } else if (largeBits > 15) {
+ step = 1e-3;
+ } else if (largeBits > 12) {
+ step = 1e-4;
+ } else if (largeBits > 9) {
+ step = 1e-5;
+ }
+ double diff;
+ do {
+ double newT = binary_search(cubic, step, pt, t, &iters);
+ if (newT >= 0) {
+ diff = fabs(t - newT);
+ break;
+ }
+ step *= 1.5;
+ SK_ALWAYSBREAK(step < 1);
+ } while (true);
+ worstStep[largeBits] = SkTMax(worstStep[largeBits], diff);
+#if 0
+ {
+ cubic.dump();
+ SkDebugf("\n");
+ SkDLine line = {{{pt.fX - 1, pt.fY}, {pt.fX + 1, pt.fY}}};
+ line.dump();
+ SkDebugf("\n");
+ }
+#endif
+ ++errors;
+ }
+ SkDebugf("errors=%d avgIter=%1.9g", errors, (double) iters / errors);
+ SkDebugf(" steps: ");
+ int worstLimit = SK_ARRAY_COUNT(worstStep);
+ while (worstStep[--worstLimit] == 0) ;
+ for (int idx2 = 0; idx2 <= worstLimit; ++idx2) {
+ SkDebugf("%1.9g ", worstStep[idx2]);
+ }
+ SkDebugf("\n");
+ SkDebugf("smallestR2=%1.9g largestR2=%1.9g\n", smallestR2, largestR2);
+}
+
+static double testOneFailure(const CubicLineFailures& failure) {
+ const SkDCubic& cubic = failure.c;
+ const SkDPoint& pt = failure.p;
+ double A, B, C, D;
+ SkDCubic::Coefficients(&cubic[0].fY, &A, &B, &C, &D);
+ D -= pt.fY;
+ double allRoots[3] = {0}, validRoots[3] = {0};
+ int realRoots = SkDCubic::RootsReal(A, B, C, D, allRoots);
+ int valid = SkDQuad::AddValidTs(allRoots, realRoots, validRoots);
+ SK_ALWAYSBREAK(valid == 1);
+ SK_ALWAYSBREAK(realRoots != 1);
+ double t = validRoots[0];
+ SkDPoint calcPt = cubic.ptAtT(t);
+ SK_ALWAYSBREAK(!calcPt.approximatelyEqual(pt));
+ int iters = 0;
+ double newT = binary_search(cubic, 0.1, pt, t, &iters);
+ return newT;
+}
+
+DEF_TEST(PathOpsCubicLineFailures, reporter) {
+ return; // disable for now
+ for (int index = 0; index < cubicLineFailuresCount; ++index) {
+ const CubicLineFailures& failure = cubicLineFailures[index];
+ double newT = testOneFailure(failure);
+ SK_ALWAYSBREAK(newT >= 0);
+ }
+}
+
+DEF_TEST(PathOpsCubicLineOneFailure, reporter) {
+ return; // disable for now
+ const CubicLineFailures& failure = cubicLineFailures[1];
+ double newT = testOneFailure(failure);
+ SK_ALWAYSBREAK(newT >= 0);
+}
diff --git a/src/third_party/skia/tests/PathOpsCubicLineIntersectionTest.cpp b/src/third_party/skia/tests/PathOpsCubicLineIntersectionTest.cpp
new file mode 100644
index 0000000..234a538
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsCubicLineIntersectionTest.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkIntersections.h"
+#include "SkPathOpsCubic.h"
+#include "SkPathOpsLine.h"
+#include "SkReduceOrder.h"
+#include "Test.h"
+
+struct lineCubic {
+ SkDCubic cubic;
+ SkDLine line;
+};
+
+static lineCubic failLineCubicTests[] = {
+ {{{{37.5273438,-1.44140625}, {37.8736992,-1.69921875}, {38.1640625,-2.140625},
+ {38.3984375,-2.765625}}},
+ {{{40.625,-5.7890625}, {37.7109375,1.3515625}}}},
+};
+
+static const size_t failLineCubicTests_count = SK_ARRAY_COUNT(failLineCubicTests);
+
+static void testFail(skiatest::Reporter* reporter, int iIndex) {
+ const SkDCubic& cubic = failLineCubicTests[iIndex].cubic;
+ SkASSERT(ValidCubic(cubic));
+ const SkDLine& line = failLineCubicTests[iIndex].line;
+ SkASSERT(ValidLine(line));
+ SkReduceOrder reduce1;
+ SkReduceOrder reduce2;
+ int order1 = reduce1.reduce(cubic, SkReduceOrder::kNo_Quadratics);
+ int order2 = reduce2.reduce(line);
+ if (order1 < 4) {
+ SkDebugf("[%d] cubic order=%d\n", iIndex, order1);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ if (order2 < 2) {
+ SkDebugf("[%d] line order=%d\n", iIndex, order2);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ if (order1 == 4 && order2 == 2) {
+ SkIntersections i;
+ int roots = i.intersect(cubic, line);
+ REPORTER_ASSERT(reporter, roots == 0);
+ }
+}
+
+static lineCubic lineCubicTests[] = {
+ {{{{-634.60540771484375, -481.262939453125}, {266.2696533203125, -752.70867919921875},
+ {-751.8370361328125, -317.37921142578125}, {-969.7427978515625, 824.7255859375}}},
+ {{{-287.9506133720805678, -557.1376476615772617},
+ {-285.9506133720805678, -557.1376476615772617}}}},
+
+ {{{{36.7184372,0.888650894}, {36.7184372,0.888650894}, {35.1233864,0.554015458},
+ {34.5114098,-0.115255356}}}, {{{35.4531212,0}, {31.9375,0}}}},
+
+ {{{{421, 378}, {421, 380.209137f}, {418.761414f, 382}, {416, 382}}},
+ {{{320, 378}, {421, 378.000031f}}}},
+
+ {{{{416, 383}, {418.761414f, 383}, {421, 380.761414f}, {421, 378}}},
+ {{{320, 378}, {421, 378.000031f}}}},
+
+ {{{{154,715}, {151.238571,715}, {149,712.761414}, {149,710}}},
+ {{{149,675}, {149,710.001465}}}},
+
+ {{{{0,1}, {1,6}, {4,1}, {4,3}}},
+ {{{6,1}, {1,4}}}},
+
+ {{{{0,1}, {2,6}, {4,1}, {5,4}}},
+ {{{6,2}, {1,4}}}},
+
+ {{{{0,4}, {3,4}, {6,2}, {5,2}}},
+ {{{4,3}, {2,6}}}},
+#if 0
+ {{{{258, 122}, {260.761414, 122}, { 263, 124.238579}, {263, 127}}},
+ {{{259.82843, 125.17157}, {261.535522, 123.46447}}}},
+#endif
+ {{{{1006.6951293945312,291}, {1023.263671875,291}, {1033.8402099609375,304.43145751953125},
+ {1030.318359375,321}}},
+ {{{979.30487060546875,561}, {1036.695068359375,291}}}},
+ {{{{259.30487060546875,561}, {242.73631286621094,561}, {232.15980529785156,547.56854248046875},
+ {235.68154907226562,531}}},
+ {{{286.69512939453125,291}, {229.30485534667969,561}}}},
+ {{{{1, 2}, {2, 6}, {2, 0}, {1, 0}}}, {{{1, 0}, {1, 2}}}},
+ {{{{0, 0}, {0, 1}, {0, 1}, {1, 1}}}, {{{0, 1}, {1, 0}}}},
+};
+
+static const size_t lineCubicTests_count = SK_ARRAY_COUNT(lineCubicTests);
+
+static int doIntersect(SkIntersections& intersections, const SkDCubic& cubic, const SkDLine& line) {
+ int result;
+ bool flipped = false;
+ if (line[0].fX == line[1].fX) {
+ double top = line[0].fY;
+ double bottom = line[1].fY;
+ flipped = top > bottom;
+ if (flipped) {
+ SkTSwap<double>(top, bottom);
+ }
+ result = intersections.vertical(cubic, top, bottom, line[0].fX, flipped);
+ } else if (line[0].fY == line[1].fY) {
+ double left = line[0].fX;
+ double right = line[1].fX;
+ flipped = left > right;
+ if (flipped) {
+ SkTSwap<double>(left, right);
+ }
+ result = intersections.horizontal(cubic, left, right, line[0].fY, flipped);
+ } else {
+ intersections.intersect(cubic, line);
+ result = intersections.used();
+ }
+ return result;
+}
+
+static void testOne(skiatest::Reporter* reporter, int iIndex) {
+ const SkDCubic& cubic = lineCubicTests[iIndex].cubic;
+ SkASSERT(ValidCubic(cubic));
+ const SkDLine& line = lineCubicTests[iIndex].line;
+ SkASSERT(ValidLine(line));
+ SkReduceOrder reduce1;
+ SkReduceOrder reduce2;
+ int order1 = reduce1.reduce(cubic, SkReduceOrder::kNo_Quadratics);
+ int order2 = reduce2.reduce(line);
+ if (order1 < 4) {
+ SkDebugf("[%d] cubic order=%d\n", iIndex, order1);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ if (order2 < 2) {
+ SkDebugf("[%d] line order=%d\n", iIndex, order2);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ if (order1 == 4 && order2 == 2) {
+ SkIntersections i;
+ int roots = doIntersect(i, cubic, line);
+ for (int pt = 0; pt < roots; ++pt) {
+ double tt1 = i[0][pt];
+ SkDPoint xy1 = cubic.ptAtT(tt1);
+ double tt2 = i[1][pt];
+ SkDPoint xy2 = line.ptAtT(tt2);
+ if (!xy1.approximatelyEqual(xy2)) {
+ SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
+ __FUNCTION__, iIndex, pt, tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY);
+ }
+ REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
+ }
+#if ONE_OFF_DEBUG
+ double cubicT = i[0][0];
+ SkDPoint prev = cubic.ptAtT(cubicT * 2 - 1);
+ SkDPoint sect = cubic.ptAtT(cubicT);
+ double left[3] = { line.isLeft(prev), line.isLeft(sect), line.isLeft(cubic[3]) };
+ SkDebugf("cubic=(%1.9g, %1.9g, %1.9g)\n", left[0], left[1], left[2]);
+ SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", prev.fX, prev.fY, sect.fX, sect.fY);
+ SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", sect.fX, sect.fY, cubic[3].fX, cubic[3].fY);
+ SkDPoint prevL = line.ptAtT(i[1][0] - 0.0000007);
+ SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", prevL.fX, prevL.fY, i.pt(0).fX, i.pt(0).fY);
+ SkDPoint nextL = line.ptAtT(i[1][0] + 0.0000007);
+ SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", i.pt(0).fX, i.pt(0).fY, nextL.fX, nextL.fY);
+ SkDebugf("prevD=%1.9g dist=%1.9g nextD=%1.9g\n", prev.distance(nextL),
+ sect.distance(i.pt(0)), cubic[3].distance(prevL));
+#endif
+ }
+}
+
+DEF_TEST(PathOpsFailCubicLineIntersection, reporter) {
+ for (size_t index = 0; index < failLineCubicTests_count; ++index) {
+ int iIndex = static_cast<int>(index);
+ testFail(reporter, iIndex);
+ reporter->bumpTestCount();
+ }
+}
+
+DEF_TEST(PathOpsCubicLineIntersection, reporter) {
+ for (size_t index = 0; index < lineCubicTests_count; ++index) {
+ int iIndex = static_cast<int>(index);
+ testOne(reporter, iIndex);
+ reporter->bumpTestCount();
+ }
+}
+
+DEF_TEST(PathOpsCubicLineIntersectionOneOff, reporter) {
+ int iIndex = 0;
+ testOne(reporter, iIndex);
+ const SkDCubic& cubic = lineCubicTests[iIndex].cubic;
+ const SkDLine& line = lineCubicTests[iIndex].line;
+ SkIntersections i;
+ i.intersect(cubic, line);
+ SkASSERT(i.used() == 1);
+}
diff --git a/src/third_party/skia/tests/PathOpsCubicQuadIntersectionTest.cpp b/src/third_party/skia/tests/PathOpsCubicQuadIntersectionTest.cpp
new file mode 100644
index 0000000..967dfc7
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsCubicQuadIntersectionTest.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkIntersections.h"
+#include "SkPathOpsCubic.h"
+#include "SkPathOpsQuad.h"
+#include "SkRandom.h"
+#include "SkReduceOrder.h"
+#include "Test.h"
+
+static struct quadCubic {
+ SkDCubic cubic;
+ SkDQuad quad;
+ int answerCount;
+ SkDPoint answers[2];
+} quadCubicTests[] = {
+#if 0 // FIXME : this should not fail (root problem behind skpcarrot_is24 )
+ {{{{1020.08099,672.161987}, {1020.08002,630.73999}, {986.502014,597.161987}, {945.080994,597.161987}}},
+ {{{1020,672}, {1020,640.93396}, {998.03302,618.96698}}}, 1,
+ {{1019.421, 662.449}}},
+#endif
+
+ {{{{778, 14089}, {778, 14091.208984375}, {776.20916748046875, 14093}, {774, 14093}}},
+ {{{778, 14089}, {777.99957275390625, 14090.65625}, {776.82843017578125, 14091.828125}}}, 2,
+ {{778, 14089}, {776.82855609581270,14091.828250841330}}},
+
+ {{{{1110, 817}, {1110.55225f, 817}, {1111, 817.447693f}, {1111, 818}}},
+ {{{1110.70715f, 817.292908f}, {1110.41406f, 817.000122f}, {1110, 817}}}, 2,
+ {{1110, 817}, {1110.70715f, 817.292908f}}},
+
+ {{{{1110, 817}, {1110.55225f, 817}, {1111, 817.447693f}, {1111, 818}}},
+ {{{1111, 818}, {1110.99988f, 817.585876f}, {1110.70715f, 817.292908f}}}, 2,
+ {{1110.70715f, 817.292908f}, {1111, 818}}},
+
+ {{{{55, 207}, {52.238574981689453, 207}, {50, 204.76142883300781}, {50, 202}}},
+ {{{55, 207}, {52.929431915283203, 206.99949645996094},
+ {51.464466094970703, 205.53553771972656}}}, 2,
+ {{55, 207}, {51.464466094970703, 205.53553771972656}}},
+
+ {{{{49, 47}, {49, 74.614250183105469}, {26.614250183105469, 97}, {-1, 97}}},
+ {{{-8.659739592076221e-015, 96.991401672363281}, {20.065492630004883, 96.645187377929688},
+ {34.355339050292969, 82.355339050292969}}}, 2,
+ {{34.355339050292969,82.355339050292969}, {34.28654835573549, 82.424006509351585}}},
+
+ {{{{10,234}, {10,229.58172607421875}, {13.581720352172852,226}, {18,226}}},
+ {{{18,226}, {14.686291694641113,226}, {12.342399597167969,228.3424072265625}}}, 1,
+ {{18,226}, {0,0}}},
+
+ {{{{10,234}, {10,229.58172607421875}, {13.581720352172852,226}, {18,226}}},
+ {{{12.342399597167969,228.3424072265625}, {10,230.68629455566406}, {10,234}}}, 1,
+ {{10,234}, {0,0}}},
+};
+
+static const int quadCubicTests_count = (int) SK_ARRAY_COUNT(quadCubicTests);
+
+static void cubicQuadIntersection(skiatest::Reporter* reporter, int index) {
+ int iIndex = static_cast<int>(index);
+ const SkDCubic& cubic = quadCubicTests[index].cubic;
+ SkASSERT(ValidCubic(cubic));
+ const SkDQuad& quad = quadCubicTests[index].quad;
+ SkASSERT(ValidQuad(quad));
+ SkReduceOrder reduce1;
+ SkReduceOrder reduce2;
+ int order1 = reduce1.reduce(cubic, SkReduceOrder::kNo_Quadratics);
+ int order2 = reduce2.reduce(quad);
+ if (order1 != 4) {
+ SkDebugf("[%d] cubic order=%d\n", iIndex, order1);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ if (order2 != 3) {
+ SkDebugf("[%d] quad order=%d\n", iIndex, order2);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ SkIntersections i;
+ int roots = i.intersect(cubic, quad);
+ SkASSERT(roots == quadCubicTests[index].answerCount);
+ for (int pt = 0; pt < roots; ++pt) {
+ double tt1 = i[0][pt];
+ SkDPoint xy1 = cubic.ptAtT(tt1);
+ double tt2 = i[1][pt];
+ SkDPoint xy2 = quad.ptAtT(tt2);
+ if (!xy1.approximatelyEqual(xy2)) {
+ SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
+ __FUNCTION__, iIndex, pt, tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY);
+ }
+ REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2));
+ bool found = false;
+ for (int idx2 = 0; idx2 < quadCubicTests[index].answerCount; ++idx2) {
+ found |= quadCubicTests[index].answers[idx2].approximatelyEqual(xy1);
+ }
+ if (!found) {
+ SkDebugf("%s [%d,%d] xy1=(%g,%g) != \n",
+ __FUNCTION__, iIndex, pt, xy1.fX, xy1.fY);
+ }
+ REPORTER_ASSERT(reporter, found);
+ }
+ reporter->bumpTestCount();
+}
+
+DEF_TEST(PathOpsCubicQuadIntersection, reporter) {
+ for (int index = 0; index < quadCubicTests_count; ++index) {
+ cubicQuadIntersection(reporter, index);
+ reporter->bumpTestCount();
+ }
+}
+
+DEF_TEST(PathOpsCubicQuadIntersectionOneOff, reporter) {
+ cubicQuadIntersection(reporter, 0);
+}
+
+static bool gPathOpCubicQuadSlopVerbose = false;
+static const int kCubicToQuadSubdivisionDepth = 8; // slots reserved for cubic to quads subdivision
+
+// determine that slop required after quad/quad finds a candidate intersection
+// use the cross of the tangents plus the distance from 1 or 0 as knobs
+DEF_TEST(PathOpsCubicQuadSlop, reporter) {
+ // create a random non-selfintersecting cubic
+ // break it into quadratics
+ // offset the quadratic, measuring the slop required to find the intersection
+ if (!gPathOpCubicQuadSlopVerbose) { // takes a while to run -- so exclude it by default
+ return;
+ }
+ int results[101];
+ sk_bzero(results, sizeof(results));
+ double minCross[101];
+ sk_bzero(minCross, sizeof(minCross));
+ double maxCross[101];
+ sk_bzero(maxCross, sizeof(maxCross));
+ double sumCross[101];
+ sk_bzero(sumCross, sizeof(sumCross));
+ int foundOne = 0;
+ int slopCount = 1;
+ SkRandom ran;
+ for (int index = 0; index < 10000000; ++index) {
+ if (index % 1000 == 999) SkDebugf(".");
+ SkDCubic cubic = {{
+ {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
+ {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
+ {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)},
+ {ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)}
+ }};
+ SkIntersections i;
+ if (i.intersect(cubic)) {
+ continue;
+ }
+ SkSTArray<kCubicToQuadSubdivisionDepth, double, true> ts;
+ cubic.toQuadraticTs(cubic.calcPrecision(), &ts);
+ double tStart = 0;
+ int tsCount = ts.count();
+ for (int i1 = 0; i1 <= tsCount; ++i1) {
+ const double tEnd = i1 < tsCount ? ts[i1] : 1;
+ SkDCubic part = cubic.subDivide(tStart, tEnd);
+ SkDQuad quad = part.toQuad();
+ SkReduceOrder reducer;
+ int order = reducer.reduce(quad);
+ if (order != 3) {
+ continue;
+ }
+ for (int i2 = 0; i2 < 100; ++i2) {
+ SkDPoint endDisplacement = {ran.nextRangeF(-100, 100), ran.nextRangeF(-100, 100)};
+ SkDQuad nearby = {{
+ {quad[0].fX + endDisplacement.fX, quad[0].fY + endDisplacement.fY},
+ {quad[1].fX + ran.nextRangeF(-100, 100), quad[1].fY + ran.nextRangeF(-100, 100)},
+ {quad[2].fX - endDisplacement.fX, quad[2].fY - endDisplacement.fY}
+ }};
+ order = reducer.reduce(nearby);
+ if (order != 3) {
+ continue;
+ }
+ SkIntersections locals;
+ locals.allowNear(false);
+ locals.intersect(quad, nearby);
+ if (locals.used() != 1) {
+ continue;
+ }
+ // brute force find actual intersection
+ SkDLine cubicLine = {{ {0, 0}, {cubic[0].fX, cubic[0].fY } }};
+ SkIntersections liner;
+ int i3;
+ int found = -1;
+ int foundErr = true;
+ for (i3 = 1; i3 <= 1000; ++i3) {
+ cubicLine[0] = cubicLine[1];
+ cubicLine[1] = cubic.ptAtT(i3 / 1000.);
+ liner.reset();
+ liner.allowNear(false);
+ liner.intersect(nearby, cubicLine);
+ if (liner.used() == 0) {
+ continue;
+ }
+ if (liner.used() > 1) {
+ foundErr = true;
+ break;
+ }
+ if (found > 0) {
+ foundErr = true;
+ break;
+ }
+ foundErr = false;
+ found = i3;
+ }
+ if (foundErr) {
+ continue;
+ }
+ SkDVector dist = liner.pt(0) - locals.pt(0);
+ SkDVector qV = nearby.dxdyAtT(locals[0][0]);
+ double cubicT = (found - 1 + liner[1][0]) / 1000.;
+ SkDVector cV = cubic.dxdyAtT(cubicT);
+ double qxc = qV.crossCheck(cV);
+ double qvLen = qV.length();
+ double cvLen = cV.length();
+ double maxLen = SkTMax(qvLen, cvLen);
+ qxc /= maxLen;
+ double quadT = tStart + (tEnd - tStart) * locals[0][0];
+ double diffT = fabs(cubicT - quadT);
+ int diffIdx = (int) (diffT * 100);
+ results[diffIdx]++;
+ double absQxc = fabs(qxc);
+ if (sumCross[diffIdx] == 0) {
+ minCross[diffIdx] = maxCross[diffIdx] = sumCross[diffIdx] = absQxc;
+ } else {
+ minCross[diffIdx] = SkTMin(minCross[diffIdx], absQxc);
+ maxCross[diffIdx] = SkTMax(maxCross[diffIdx], absQxc);
+ sumCross[diffIdx] += absQxc;
+ }
+ if (diffIdx >= 20) {
+#if 01
+ SkDebugf("cubic={{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}"
+ " quad={{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}"
+ " {{{%1.9g,%1.9g}, {%1.9g,%1.9g}}}"
+ " qT=%1.9g cT=%1.9g dist=%1.9g cross=%1.9g\n",
+ cubic[0].fX, cubic[0].fY, cubic[1].fX, cubic[1].fY,
+ cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY,
+ nearby[0].fX, nearby[0].fY, nearby[1].fX, nearby[1].fY,
+ nearby[2].fX, nearby[2].fY,
+ liner.pt(0).fX, liner.pt(0).fY,
+ locals.pt(0).fX, locals.pt(0).fY, quadT, cubicT, dist.length(), qxc);
+#else
+ SkDebugf("qT=%1.9g cT=%1.9g dist=%1.9g cross=%1.9g\n",
+ quadT, cubicT, dist.length(), qxc);
+ SkDebugf("<div id=\"slop%d\">\n", ++slopCount);
+ SkDebugf("{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}\n"
+ "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}\n"
+ "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}}}\n",
+ cubic[0].fX, cubic[0].fY, cubic[1].fX, cubic[1].fY,
+ cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY,
+ nearby[0].fX, nearby[0].fY, nearby[1].fX, nearby[1].fY,
+ nearby[2].fX, nearby[2].fY,
+ liner.pt(0).fX, liner.pt(0).fY,
+ locals.pt(0).fX, locals.pt(0).fY);
+ SkDebugf("</div>\n\n");
+#endif
+ }
+ ++foundOne;
+ }
+ tStart = tEnd;
+ }
+ if (++foundOne >= 100000) {
+ break;
+ }
+ }
+#if 01
+ SkDebugf("slopCount=%d\n", slopCount);
+ int max = 100;
+ while (results[max] == 0) {
+ --max;
+ }
+ for (int i = 0; i <= max; ++i) {
+ if (i > 0 && i % 10 == 0) {
+ SkDebugf("\n");
+ }
+ SkDebugf("%d ", results[i]);
+ }
+ SkDebugf("min\n");
+ for (int i = 0; i <= max; ++i) {
+ if (i > 0 && i % 10 == 0) {
+ SkDebugf("\n");
+ }
+ SkDebugf("%1.9g ", minCross[i]);
+ }
+ SkDebugf("max\n");
+ for (int i = 0; i <= max; ++i) {
+ if (i > 0 && i % 10 == 0) {
+ SkDebugf("\n");
+ }
+ SkDebugf("%1.9g ", maxCross[i]);
+ }
+ SkDebugf("avg\n");
+ for (int i = 0; i <= max; ++i) {
+ if (i > 0 && i % 10 == 0) {
+ SkDebugf("\n");
+ }
+ SkDebugf("%1.9g ", sumCross[i] / results[i]);
+ }
+#else
+ for (int i = 1; i < slopCount; ++i) {
+ SkDebugf(" slop%d,\n", i);
+ }
+#endif
+ SkDebugf("\n");
+}
diff --git a/src/third_party/skia/tests/PathOpsCubicReduceOrderTest.cpp b/src/third_party/skia/tests/PathOpsCubicReduceOrderTest.cpp
new file mode 100644
index 0000000..dc779b8
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsCubicReduceOrderTest.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsCubicIntersectionTestData.h"
+#include "PathOpsQuadIntersectionTestData.h"
+#include "PathOpsTestCommon.h"
+#include "SkIntersections.h"
+#include "SkPathOpsRect.h"
+#include "SkReduceOrder.h"
+#include "Test.h"
+
+#if 0 // disable test until stroke reduction is supported
+static bool controls_inside(const SkDCubic& cubic) {
+ return between(cubic[0].fX, cubic[1].fX, cubic[3].fX)
+ && between(cubic[0].fX, cubic[2].fX, cubic[3].fX)
+ && between(cubic[0].fY, cubic[1].fY, cubic[3].fY)
+ && between(cubic[0].fY, cubic[2].fY, cubic[3].fY);
+}
+
+static bool tiny(const SkDCubic& cubic) {
+ int index, minX, maxX, minY, maxY;
+ minX = maxX = minY = maxY = 0;
+ for (index = 1; index < 4; ++index) {
+ if (cubic[minX].fX > cubic[index].fX) {
+ minX = index;
+ }
+ if (cubic[minY].fY > cubic[index].fY) {
+ minY = index;
+ }
+ if (cubic[maxX].fX < cubic[index].fX) {
+ maxX = index;
+ }
+ if (cubic[maxY].fY < cubic[index].fY) {
+ maxY = index;
+ }
+ }
+ return approximately_equal(cubic[maxX].fX, cubic[minX].fX)
+ && approximately_equal(cubic[maxY].fY, cubic[minY].fY);
+}
+
+static void find_tight_bounds(const SkDCubic& cubic, SkDRect& bounds) {
+ SkDCubicPair cubicPair = cubic.chopAt(0.5);
+ if (!tiny(cubicPair.first()) && !controls_inside(cubicPair.first())) {
+ find_tight_bounds(cubicPair.first(), bounds);
+ } else {
+ bounds.add(cubicPair.first()[0]);
+ bounds.add(cubicPair.first()[3]);
+ }
+ if (!tiny(cubicPair.second()) && !controls_inside(cubicPair.second())) {
+ find_tight_bounds(cubicPair.second(), bounds);
+ } else {
+ bounds.add(cubicPair.second()[0]);
+ bounds.add(cubicPair.second()[3]);
+ }
+}
+#endif
+
+DEF_TEST(PathOpsReduceOrderCubic, reporter) {
+ size_t index;
+ SkReduceOrder reducer;
+ int order;
+ enum {
+ RunAll,
+ RunPointDegenerates,
+ RunNotPointDegenerates,
+ RunLines,
+ RunNotLines,
+ RunModEpsilonLines,
+ RunLessEpsilonLines,
+ RunNegEpsilonLines,
+ RunQuadraticLines,
+ RunQuadraticPoints,
+ RunQuadraticModLines,
+ RunComputedLines,
+ RunNone
+ } run = RunAll;
+ int firstTestIndex = 0;
+#if 0
+ run = RunComputedLines;
+ firstTestIndex = 18;
+#endif
+ int firstPointDegeneratesTest = run == RunAll ? 0 : run == RunPointDegenerates
+ ? firstTestIndex : SK_MaxS32;
+ int firstNotPointDegeneratesTest = run == RunAll ? 0 : run == RunNotPointDegenerates
+ ? firstTestIndex : SK_MaxS32;
+ int firstLinesTest = run == RunAll ? 0 : run == RunLines ? firstTestIndex : SK_MaxS32;
+ int firstNotLinesTest = run == RunAll ? 0 : run == RunNotLines ? firstTestIndex : SK_MaxS32;
+ int firstModEpsilonTest = run == RunAll ? 0 : run == RunModEpsilonLines
+ ? firstTestIndex : SK_MaxS32;
+ int firstLessEpsilonTest = run == RunAll ? 0 : run == RunLessEpsilonLines
+ ? firstTestIndex : SK_MaxS32;
+ int firstNegEpsilonTest = run == RunAll ? 0 : run == RunNegEpsilonLines
+ ? firstTestIndex : SK_MaxS32;
+ int firstQuadraticPointTest = run == RunAll ? 0 : run == RunQuadraticPoints
+ ? firstTestIndex : SK_MaxS32;
+ int firstQuadraticLineTest = run == RunAll ? 0 : run == RunQuadraticLines
+ ? firstTestIndex : SK_MaxS32;
+ int firstQuadraticModLineTest = run == RunAll ? 0 : run == RunQuadraticModLines
+ ? firstTestIndex : SK_MaxS32;
+#if 0
+ int firstComputedLinesTest = run == RunAll ? 0 : run == RunComputedLines
+ ? firstTestIndex : SK_MaxS32;
+#endif
+ for (index = firstPointDegeneratesTest; index < pointDegenerates_count; ++index) {
+ const SkDCubic& cubic = pointDegenerates[index];
+ SkASSERT(ValidCubic(cubic));
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
+ if (order != 1) {
+ SkDebugf("[%d] pointDegenerates order=%d\n", static_cast<int>(index), order);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ for (index = firstNotPointDegeneratesTest; index < notPointDegenerates_count; ++index) {
+ const SkDCubic& cubic = notPointDegenerates[index];
+ SkASSERT(ValidCubic(cubic));
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
+ if (order == 1) {
+ SkDebugf("[%d] notPointDegenerates order=%d\n", static_cast<int>(index), order);
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ for (index = firstLinesTest; index < lines_count; ++index) {
+ const SkDCubic& cubic = lines[index];
+ SkASSERT(ValidCubic(cubic));
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
+ if (order != 2) {
+ SkDebugf("[%d] lines order=%d\n", static_cast<int>(index), order);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ for (index = firstNotLinesTest; index < notLines_count; ++index) {
+ const SkDCubic& cubic = notLines[index];
+ SkASSERT(ValidCubic(cubic));
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
+ if (order == 2) {
+ SkDebugf("[%d] notLines order=%d\n", static_cast<int>(index), order);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ for (index = firstModEpsilonTest; index < modEpsilonLines_count; ++index) {
+ const SkDCubic& cubic = modEpsilonLines[index];
+ SkASSERT(ValidCubic(cubic));
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
+ if (order == 2) {
+ SkDebugf("[%d] line mod by epsilon order=%d\n", static_cast<int>(index), order);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ for (index = firstLessEpsilonTest; index < lessEpsilonLines_count; ++index) {
+ const SkDCubic& cubic = lessEpsilonLines[index];
+ SkASSERT(ValidCubic(cubic));
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
+ if (order != 2) {
+ SkDebugf("[%d] line less by epsilon/2 order=%d\n", static_cast<int>(index), order);
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ for (index = firstNegEpsilonTest; index < negEpsilonLines_count; ++index) {
+ const SkDCubic& cubic = negEpsilonLines[index];
+ SkASSERT(ValidCubic(cubic));
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
+ if (order != 2) {
+ SkDebugf("[%d] line neg by epsilon/2 order=%d\n", static_cast<int>(index), order);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ for (index = firstQuadraticPointTest; index < quadraticPoints_count; ++index) {
+ const SkDQuad& quad = quadraticPoints[index];
+ SkASSERT(ValidQuad(quad));
+ SkDCubic cubic = quad.toCubic();
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
+ if (order != 1) {
+ SkDebugf("[%d] point quad order=%d\n", static_cast<int>(index), order);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ for (index = firstQuadraticLineTest; index < quadraticLines_count; ++index) {
+ const SkDQuad& quad = quadraticLines[index];
+ SkASSERT(ValidQuad(quad));
+ SkDCubic cubic = quad.toCubic();
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
+ if (order != 2) {
+ SkDebugf("[%d] line quad order=%d\n", static_cast<int>(index), order);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ for (index = firstQuadraticModLineTest; index < quadraticModEpsilonLines_count; ++index) {
+ const SkDQuad& quad = quadraticModEpsilonLines[index];
+ SkASSERT(ValidQuad(quad));
+ SkDCubic cubic = quad.toCubic();
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
+ if (order != 3) {
+ SkDebugf("[%d] line mod quad order=%d\n", static_cast<int>(index), order);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+
+#if 0 // disable test until stroke reduction is supported
+// test if computed line end points are valid
+ for (index = firstComputedLinesTest; index < lines_count; ++index) {
+ const SkDCubic& cubic = lines[index];
+ SkASSERT(ValidCubic(cubic));
+ bool controlsInside = controls_inside(cubic);
+ order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics,
+ SkReduceOrder::kStroke_Style);
+ if (order == 2 && reducer.fLine[0] == reducer.fLine[1]) {
+ SkDebugf("[%d] line computed ends match order=%d\n", static_cast<int>(index), order);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ if (controlsInside) {
+ if ( (reducer.fLine[0].fX != cubic[0].fX && reducer.fLine[0].fX != cubic[3].fX)
+ || (reducer.fLine[0].fY != cubic[0].fY && reducer.fLine[0].fY != cubic[3].fY)
+ || (reducer.fLine[1].fX != cubic[0].fX && reducer.fLine[1].fX != cubic[3].fX)
+ || (reducer.fLine[1].fY != cubic[0].fY && reducer.fLine[1].fY != cubic[3].fY)) {
+ SkDebugf("[%d] line computed ends order=%d\n", static_cast<int>(index), order);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ } else {
+ // binary search for extrema, compare against actual results
+ // while a control point is outside of bounding box formed by end points, split
+ SkDRect bounds = {DBL_MAX, DBL_MAX, -DBL_MAX, -DBL_MAX};
+ find_tight_bounds(cubic, bounds);
+ if ( (!AlmostEqualUlps(reducer.fLine[0].fX, bounds.fLeft)
+ && !AlmostEqualUlps(reducer.fLine[0].fX, bounds.fRight))
+ || (!AlmostEqualUlps(reducer.fLine[0].fY, bounds.fTop)
+ && !AlmostEqualUlps(reducer.fLine[0].fY, bounds.fBottom))
+ || (!AlmostEqualUlps(reducer.fLine[1].fX, bounds.fLeft)
+ && !AlmostEqualUlps(reducer.fLine[1].fX, bounds.fRight))
+ || (!AlmostEqualUlps(reducer.fLine[1].fY, bounds.fTop)
+ && !AlmostEqualUlps(reducer.fLine[1].fY, bounds.fBottom))) {
+ SkDebugf("[%d] line computed tight bounds order=%d\n", static_cast<int>(index), order);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ }
+#endif
+}
diff --git a/src/third_party/skia/tests/PathOpsCubicToQuadsTest.cpp b/src/third_party/skia/tests/PathOpsCubicToQuadsTest.cpp
new file mode 100644
index 0000000..ab22a83
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsCubicToQuadsTest.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsCubicIntersectionTestData.h"
+#include "PathOpsQuadIntersectionTestData.h"
+#include "PathOpsTestCommon.h"
+#include "SkGeometry.h"
+#include "SkIntersections.h"
+#include "SkPathOpsRect.h"
+#include "SkReduceOrder.h"
+#include "Test.h"
+
+static void test(skiatest::Reporter* reporter, const SkDCubic* cubics, const char* name,
+ int firstTest, size_t testCount) {
+ for (size_t index = firstTest; index < testCount; ++index) {
+ const SkDCubic& cubic = cubics[index];
+ SkASSERT(ValidCubic(cubic));
+ double precision = cubic.calcPrecision();
+ SkTArray<SkDQuad, true> quads;
+ CubicToQuads(cubic, precision, quads);
+ if (quads.count() != 1 && quads.count() != 2) {
+ SkDebugf("%s [%d] cubic to quadratics failed count=%d\n", name, static_cast<int>(index),
+ quads.count());
+ }
+ REPORTER_ASSERT(reporter, quads.count() == 1);
+ }
+}
+
+static void test(skiatest::Reporter* reporter, const SkDQuad* quadTests, const char* name,
+ int firstTest, size_t testCount) {
+ for (size_t index = firstTest; index < testCount; ++index) {
+ const SkDQuad& quad = quadTests[index];
+ SkASSERT(ValidQuad(quad));
+ SkDCubic cubic = quad.toCubic();
+ double precision = cubic.calcPrecision();
+ SkTArray<SkDQuad, true> quads;
+ CubicToQuads(cubic, precision, quads);
+ if (quads.count() != 1 && quads.count() != 2) {
+ SkDebugf("%s [%d] cubic to quadratics failed count=%d\n", name, static_cast<int>(index),
+ quads.count());
+ }
+ REPORTER_ASSERT(reporter, quads.count() <= 2);
+ }
+}
+
+static void testC(skiatest::Reporter* reporter, const SkDCubic* cubics, const char* name,
+ int firstTest, size_t testCount) {
+ // test if computed line end points are valid
+ for (size_t index = firstTest; index < testCount; ++index) {
+ const SkDCubic& cubic = cubics[index];
+ SkASSERT(ValidCubic(cubic));
+ double precision = cubic.calcPrecision();
+ SkTArray<SkDQuad, true> quads;
+ CubicToQuads(cubic, precision, quads);
+ if (!AlmostEqualUlps(cubic[0].fX, quads[0][0].fX)
+ || !AlmostEqualUlps(cubic[0].fY, quads[0][0].fY)) {
+ SkDebugf("[%d] unmatched start\n", static_cast<int>(index));
+ REPORTER_ASSERT(reporter, 0);
+ }
+ int last = quads.count() - 1;
+ if (!AlmostEqualUlps(cubic[3].fX, quads[last][2].fX)
+ || !AlmostEqualUlps(cubic[3].fY, quads[last][2].fY)) {
+ SkDebugf("[%d] unmatched end\n", static_cast<int>(index));
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+}
+
+static void testC(skiatest::Reporter* reporter, const SkDCubic(* cubics)[2], const char* name,
+ int firstTest, size_t testCount) {
+ for (size_t index = firstTest; index < testCount; ++index) {
+ for (int idx2 = 0; idx2 < 2; ++idx2) {
+ const SkDCubic& cubic = cubics[index][idx2];
+ SkASSERT(ValidCubic(cubic));
+ double precision = cubic.calcPrecision();
+ SkTArray<SkDQuad, true> quads;
+ CubicToQuads(cubic, precision, quads);
+ if (!AlmostEqualUlps(cubic[0].fX, quads[0][0].fX)
+ || !AlmostEqualUlps(cubic[0].fY, quads[0][0].fY)) {
+ SkDebugf("[%d][%d] unmatched start\n", static_cast<int>(index), idx2);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ int last = quads.count() - 1;
+ if (!AlmostEqualUlps(cubic[3].fX, quads[last][2].fX)
+ || !AlmostEqualUlps(cubic[3].fY, quads[last][2].fY)) {
+ SkDebugf("[%d][%d] unmatched end\n", static_cast<int>(index), idx2);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ }
+}
+
+DEF_TEST(CubicToQuads, reporter) {
+ enum {
+ RunAll,
+ RunPointDegenerates,
+ RunNotPointDegenerates,
+ RunLines,
+ RunNotLines,
+ RunModEpsilonLines,
+ RunLessEpsilonLines,
+ RunNegEpsilonLines,
+ RunQuadraticLines,
+ RunQuadraticModLines,
+ RunComputedLines,
+ RunComputedTests,
+ RunNone
+ } run = RunAll;
+ int firstTestIndex = 0;
+#if 0
+ run = RunComputedLines;
+ firstTestIndex = 18;
+#endif
+ int firstPointDegeneratesTest = run == RunAll ? 0 : run == RunPointDegenerates
+ ? firstTestIndex : SK_MaxS32;
+ int firstNotPointDegeneratesTest = run == RunAll ? 0 : run == RunNotPointDegenerates
+ ? firstTestIndex : SK_MaxS32;
+ int firstLinesTest = run == RunAll ? 0 : run == RunLines ? firstTestIndex : SK_MaxS32;
+ int firstNotLinesTest = run == RunAll ? 0 : run == RunNotLines ? firstTestIndex : SK_MaxS32;
+ int firstModEpsilonTest = run == RunAll ? 0 : run == RunModEpsilonLines
+ ? firstTestIndex : SK_MaxS32;
+ int firstLessEpsilonTest = run == RunAll ? 0 : run == RunLessEpsilonLines
+ ? firstTestIndex : SK_MaxS32;
+ int firstNegEpsilonTest = run == RunAll ? 0 : run == RunNegEpsilonLines
+ ? firstTestIndex : SK_MaxS32;
+ int firstQuadraticLineTest = run == RunAll ? 0 : run == RunQuadraticLines
+ ? firstTestIndex : SK_MaxS32;
+ int firstQuadraticModLineTest = run == RunAll ? 0 : run == RunQuadraticModLines
+ ? firstTestIndex : SK_MaxS32;
+ int firstComputedLinesTest = run == RunAll ? 0 : run == RunComputedLines
+ ? firstTestIndex : SK_MaxS32;
+ int firstComputedCubicsTest = run == RunAll ? 0 : run == RunComputedTests
+ ? firstTestIndex : SK_MaxS32;
+
+ test(reporter, pointDegenerates, "pointDegenerates", firstPointDegeneratesTest,
+ pointDegenerates_count);
+ testC(reporter, notPointDegenerates, "notPointDegenerates", firstNotPointDegeneratesTest,
+ notPointDegenerates_count);
+ test(reporter, lines, "lines", firstLinesTest, lines_count);
+ testC(reporter, notLines, "notLines", firstNotLinesTest, notLines_count);
+ testC(reporter, modEpsilonLines, "modEpsilonLines", firstModEpsilonTest, modEpsilonLines_count);
+ test(reporter, lessEpsilonLines, "lessEpsilonLines", firstLessEpsilonTest,
+ lessEpsilonLines_count);
+ test(reporter, negEpsilonLines, "negEpsilonLines", firstNegEpsilonTest, negEpsilonLines_count);
+ test(reporter, quadraticLines, "quadraticLines", firstQuadraticLineTest, quadraticLines_count);
+ test(reporter, quadraticModEpsilonLines, "quadraticModEpsilonLines", firstQuadraticModLineTest,
+ quadraticModEpsilonLines_count);
+ testC(reporter, lines, "computed lines", firstComputedLinesTest, lines_count);
+ testC(reporter, tests, "computed tests", firstComputedCubicsTest, tests_count);
+}
+
+static SkDCubic locals[] = {
+ {{{0, 1}, {1.9274705288631189e-19, 1.0000000000000002},
+ {0.0017190297609673323, 0.99828097023903239},
+ {0.0053709083094631276, 0.99505672974365911}}},
+ {{{14.5975863, 41.632436}, {16.3518929, 26.2639684}, {18.5165519, 7.68775139},
+ {8.03767257, 89.1628526}}},
+ {{{69.7292014, 38.6877352}, {24.7648688, 23.1501713}, {84.9283191, 90.2588441},
+ {80.392774, 61.3533852}}},
+ {{{60.776536520932126, 71.249307306133829}, {87.107894191103014, 22.377669868235323},
+ {1.4974754310666936, 68.069569937917208}, {45.261946574441133, 17.536076632112298}}},
+};
+
+static size_t localsCount = SK_ARRAY_COUNT(locals);
+
+#define DEBUG_CRASH 0
+#define TEST_AVERAGE_END_POINTS 0 // must take const off to test
+extern const bool AVERAGE_END_POINTS;
+
+static void oneOff(skiatest::Reporter* reporter, size_t x) {
+ const SkDCubic& cubic = locals[x];
+ SkASSERT(ValidCubic(cubic));
+ const SkPoint skcubic[4] = {
+ {static_cast<float>(cubic[0].fX), static_cast<float>(cubic[0].fY)},
+ {static_cast<float>(cubic[1].fX), static_cast<float>(cubic[1].fY)},
+ {static_cast<float>(cubic[2].fX), static_cast<float>(cubic[2].fY)},
+ {static_cast<float>(cubic[3].fX), static_cast<float>(cubic[3].fY)}};
+ SkScalar skinflect[2];
+ int skin = SkFindCubicInflections(skcubic, skinflect);
+ if (false) SkDebugf("%s %d %1.9g\n", __FUNCTION__, skin, skinflect[0]);
+ SkTArray<SkDQuad, true> quads;
+ double precision = cubic.calcPrecision();
+ CubicToQuads(cubic, precision, quads);
+ if (false) SkDebugf("%s quads=%d\n", __FUNCTION__, quads.count());
+}
+
+DEF_TEST(CubicsToQuadratics_OneOff_Loop, reporter) {
+ for (size_t x = 0; x < localsCount; ++x) {
+ oneOff(reporter, x);
+ }
+}
+
+DEF_TEST(CubicsToQuadratics_OneOff_Single, reporter) {
+ oneOff(reporter, 0);
+}
diff --git a/src/third_party/skia/tests/PathOpsDCubicTest.cpp b/src/third_party/skia/tests/PathOpsDCubicTest.cpp
new file mode 100644
index 0000000..422236d
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsDCubicTest.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkPathOpsCubic.h"
+#include "Test.h"
+
+static const SkDCubic tests[] = {
+ {{{2, 0}, {3, 1}, {2, 2}, {1, 1}}},
+ {{{3, 1}, {2, 2}, {1, 1}, {2, 0}}},
+ {{{3, 0}, {2, 1}, {3, 2}, {1, 1}}},
+};
+
+static const size_t tests_count = SK_ARRAY_COUNT(tests);
+
+DEF_TEST(PathOpsDCubic, reporter) {
+ for (size_t index = 0; index < tests_count; ++index) {
+ const SkDCubic& cubic = tests[index];
+ SkASSERT(ValidCubic(cubic));
+ bool result = cubic.clockwise();
+ if (!result) {
+ SkDebugf("%s [%d] expected clockwise\n", __FUNCTION__, index);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsDLineTest.cpp b/src/third_party/skia/tests/PathOpsDLineTest.cpp
new file mode 100644
index 0000000..dd86dd3
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsDLineTest.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkPathOpsLine.h"
+#include "Test.h"
+
+static const SkDLine tests[] = {
+ {{{2, 1}, {2, 1}}},
+ {{{2, 1}, {1, 1}}},
+ {{{2, 1}, {2, 2}}},
+ {{{1, 1}, {2, 2}}},
+ {{{3, 0}, {2, 1}}},
+ {{{3, 2}, {1, 1}}},
+};
+
+static const SkDPoint left[] = {
+ {2, 1},
+ {1, 0},
+ {1, 1},
+ {1, 2},
+ {2, 0},
+ {2, 1}
+};
+
+static const size_t tests_count = SK_ARRAY_COUNT(tests);
+
+DEF_TEST(PathOpsLineUtilities, reporter) {
+ for (size_t index = 0; index < tests_count; ++index) {
+ const SkDLine& line = tests[index];
+ SkASSERT(ValidLine(line));
+ SkDLine line2;
+ SkPoint pts[2] = {line[0].asSkPoint(), line[1].asSkPoint()};
+ line2.set(pts);
+ REPORTER_ASSERT(reporter, line[0] == line2[0] && line[1] == line2[1]);
+ const SkDPoint& pt = left[index];
+ SkASSERT(ValidPoint(pt));
+ double result = line.isLeft(pt);
+ if ((result <= 0 && index >= 1) || (result < 0 && index == 0)) {
+ SkDebugf("%s [%d] expected left\n", __FUNCTION__, index);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ line2 = line.subDivide(1, 0);
+ REPORTER_ASSERT(reporter, line[0] == line2[1] && line[1] == line2[0]);
+ line2 = SkDLine::SubDivide(pts, 1, 0);
+ REPORTER_ASSERT(reporter, line[0] == line2[1] && line[1] == line2[0]);
+ SkDPoint mid = line.ptAtT(.5);
+ REPORTER_ASSERT(reporter, approximately_equal((line[0].fX + line[1].fX) / 2, mid.fX));
+ REPORTER_ASSERT(reporter, approximately_equal((line[0].fY + line[1].fY) / 2, mid.fY));
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsDPointTest.cpp b/src/third_party/skia/tests/PathOpsDPointTest.cpp
new file mode 100644
index 0000000..186d691
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsDPointTest.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkPathOpsPoint.h"
+#include "Test.h"
+
+static const SkDPoint tests[] = {
+ {0, 0},
+ {1, 0},
+ {0, 1},
+ {2, 1},
+ {1, 2},
+ {1, 1},
+ {2, 2}
+};
+
+static const size_t tests_count = SK_ARRAY_COUNT(tests);
+
+DEF_TEST(PathOpsDPoint, reporter) {
+ for (size_t index = 0; index < tests_count; ++index) {
+ const SkDPoint& pt = tests[index];
+ SkASSERT(ValidPoint(pt));
+ SkDPoint p = pt;
+ REPORTER_ASSERT(reporter, p == pt);
+ REPORTER_ASSERT(reporter, !(pt != pt));
+ SkDVector v = p - pt;
+ p += v;
+ REPORTER_ASSERT(reporter, p == pt);
+ p -= v;
+ REPORTER_ASSERT(reporter, p == pt);
+ REPORTER_ASSERT(reporter, p.approximatelyEqual(pt));
+ SkPoint sPt = pt.asSkPoint();
+ p.set(sPt);
+ REPORTER_ASSERT(reporter, p == pt);
+ REPORTER_ASSERT(reporter, p.approximatelyEqual(sPt));
+ REPORTER_ASSERT(reporter, p.roughlyEqual(pt));
+ REPORTER_ASSERT(reporter, p.moreRoughlyEqual(pt));
+ p.fX = p.fY = 0;
+ REPORTER_ASSERT(reporter, p.fX == 0 && p.fY == 0);
+ REPORTER_ASSERT(reporter, p.approximatelyZero());
+ REPORTER_ASSERT(reporter, pt.distanceSquared(p) == pt.fX * pt.fX + pt.fY * pt.fY);
+ REPORTER_ASSERT(reporter, approximately_equal(pt.distance(p),
+ sqrt(pt.fX * pt.fX + pt.fY * pt.fY)));
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsDQuadTest.cpp b/src/third_party/skia/tests/PathOpsDQuadTest.cpp
new file mode 100644
index 0000000..bd29ff1
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsDQuadTest.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkPath.h"
+#include "SkPathOpsQuad.h"
+#include "SkRRect.h"
+#include "Test.h"
+
+static const SkDQuad tests[] = {
+ {{{1, 1}, {2, 1}, {0, 2}}},
+ {{{0, 0}, {1, 1}, {3, 1}}},
+ {{{2, 0}, {1, 1}, {2, 2}}},
+ {{{4, 0}, {0, 1}, {4, 2}}},
+ {{{0, 0}, {0, 1}, {1, 1}}},
+};
+
+static const SkDPoint inPoint[]= {
+ {1, 1.2},
+ {1, 0.8},
+ {1.8, 1},
+ {1.5, 1},
+ {0.4999, 0.5}, // was 0.5, 0.5; points on the hull are considered outside
+};
+
+static const SkDPoint outPoint[]= {
+ {1, 1.6},
+ {1, 1.5},
+ {2.2, 1},
+ {1.5, 1.5},
+ {1.1, 0.5},
+};
+
+static const size_t tests_count = SK_ARRAY_COUNT(tests);
+
+DEF_TEST(PathOpsDQuad, reporter) {
+ for (size_t index = 0; index < tests_count; ++index) {
+ const SkDQuad& quad = tests[index];
+ SkASSERT(ValidQuad(quad));
+ bool result = quad.pointInHull(inPoint[index]);
+ if (!result) {
+ SkDebugf("%s [%d] expected in hull\n", __FUNCTION__, index);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ result = quad.pointInHull(outPoint[index]);
+ if (result) {
+ SkDebugf("%s [%d] expected outside hull\n", __FUNCTION__, index);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+}
+
+DEF_TEST(PathOpsRRect, reporter) {
+ SkPath path;
+ SkRRect rRect;
+ SkRect rect = {135, 143, 250, 177};
+ SkVector radii[4] = {{8, 8}, {8, 8}, {0, 0}, {0, 0}};
+ rRect.setRectRadii(rect, radii);
+ path.addRRect(rRect);
+}
diff --git a/src/third_party/skia/tests/PathOpsDRectTest.cpp b/src/third_party/skia/tests/PathOpsDRectTest.cpp
new file mode 100644
index 0000000..874e82b
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsDRectTest.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkPathOpsCubic.h"
+#include "SkPathOpsLine.h"
+#include "SkPathOpsQuad.h"
+#include "SkPathOpsRect.h"
+#include "Test.h"
+
+static const SkDLine lineTests[] = {
+ {{{2, 1}, {2, 1}}},
+ {{{2, 1}, {1, 1}}},
+ {{{2, 1}, {2, 2}}},
+ {{{1, 1}, {2, 2}}},
+ {{{3, 0}, {2, 1}}},
+ {{{3, 2}, {1, 1}}},
+};
+
+static const SkDQuad quadTests[] = {
+ {{{1, 1}, {2, 1}, {0, 2}}},
+ {{{0, 0}, {1, 1}, {3, 1}}},
+ {{{2, 0}, {1, 1}, {2, 2}}},
+ {{{4, 0}, {0, 1}, {4, 2}}},
+ {{{0, 0}, {0, 1}, {1, 1}}},
+};
+
+static const SkDCubic cubicTests[] = {
+ {{{2, 0}, {3, 1}, {2, 2}, {1, 1}}},
+ {{{3, 1}, {2, 2}, {1, 1}, {2, 0}}},
+ {{{3, 0}, {2, 1}, {3, 2}, {1, 1}}},
+};
+
+static const size_t lineTests_count = SK_ARRAY_COUNT(lineTests);
+static const size_t quadTests_count = SK_ARRAY_COUNT(quadTests);
+static const size_t cubicTests_count = SK_ARRAY_COUNT(cubicTests);
+
+DEF_TEST(PathOpsDRect, reporter) {
+ size_t index;
+ SkDRect rect, rect2;
+ for (index = 0; index < lineTests_count; ++index) {
+ const SkDLine& line = lineTests[index];
+ SkASSERT(ValidLine(line));
+ rect.setBounds(line);
+ 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(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];
+ SkASSERT(ValidQuad(quad));
+ rect.setRawBounds(quad);
+ 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
+ SkDPoint leftTop = {rect2.fLeft, rect2.fTop};
+ REPORTER_ASSERT(reporter, rect.contains(leftTop));
+ SkDPoint rightBottom = {rect2.fRight, rect2.fBottom};
+ REPORTER_ASSERT(reporter, rect.contains(rightBottom));
+ }
+ for (index = 0; index < cubicTests_count; ++index) {
+ const SkDCubic& cubic = cubicTests[index];
+ SkASSERT(ValidCubic(cubic));
+ rect.setRawBounds(cubic);
+ 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
+ SkDPoint leftTop = {rect2.fLeft, rect2.fTop};
+ REPORTER_ASSERT(reporter, rect.contains(leftTop));
+ SkDPoint rightBottom = {rect2.fRight, rect2.fBottom};
+ REPORTER_ASSERT(reporter, rect.contains(rightBottom));
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsDTriangleTest.cpp b/src/third_party/skia/tests/PathOpsDTriangleTest.cpp
new file mode 100644
index 0000000..b5e2d41
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsDTriangleTest.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkPathOpsTriangle.h"
+#include "Test.h"
+
+static const SkDTriangle tests[] = {
+ {{{2, 0}, {3, 1}, {2, 2}}},
+ {{{3, 1}, {2, 2}, {1, 1}}},
+ {{{3, 0}, {2, 1}, {3, 2}}},
+};
+
+static const SkDPoint inPoint[] = {
+ {2.5, 1},
+ {2, 1.5},
+ {2.5, 1},
+};
+
+static const SkDPoint outPoint[] = {
+ {3, 0},
+ {2.5, 2},
+ {2.5, 2},
+};
+
+static const size_t tests_count = SK_ARRAY_COUNT(tests);
+
+DEF_TEST(PathOpsTriangleUtilities, reporter) {
+ for (size_t index = 0; index < tests_count; ++index) {
+ const SkDTriangle& triangle = tests[index];
+ SkASSERT(ValidTriangle(triangle));
+ bool result = triangle.contains(inPoint[index]);
+ if (!result) {
+ SkDebugf("%s [%d] expected point in triangle\n", __FUNCTION__, index);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ result = triangle.contains(outPoint[index]);
+ if (result) {
+ SkDebugf("%s [%d] expected point outside triangle\n", __FUNCTION__, index);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+}
+
+static const SkDTriangle oneOff[] = {
+ {{{271.03291625750461, 5.0402503630087025e-05}, {275.21652430019037, 3.6997300650817753},
+ {279.25839233398438, 7.7416000366210938}}},
+
+ {{{271.03291625750461, 5.0402503617874572e-05}, {275.21652430019037, 3.6997300650817877},
+ {279.25839233398438, 7.7416000366210938}}}
+};
+
+static const size_t oneOff_count = SK_ARRAY_COUNT(oneOff);
+
+DEF_TEST(PathOpsTriangleOneOff, reporter) {
+ for (size_t index = 0; index < oneOff_count; ++index) {
+ const SkDTriangle& triangle = oneOff[index];
+ SkASSERT(ValidTriangle(triangle));
+ for (int inner = 0; inner < 3; ++inner) {
+ bool result = triangle.contains(triangle.fPts[inner]);
+ if (result) {
+ SkDebugf("%s [%d][%d] point on triangle is not in\n", __FUNCTION__, index, inner);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsDVectorTest.cpp b/src/third_party/skia/tests/PathOpsDVectorTest.cpp
new file mode 100644
index 0000000..ab291b2
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsDVectorTest.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkPathOpsPoint.h"
+#include "Test.h"
+
+static const SkDPoint tests[] = {
+ {0, 0},
+ {1, 0},
+ {0, 1},
+ {2, 1},
+ {1, 2},
+ {1, 1},
+ {2, 2}
+};
+
+static const size_t tests_count = SK_ARRAY_COUNT(tests);
+
+DEF_TEST(PathOpsDVector, reporter) {
+ for (size_t index = 0; index < tests_count - 1; ++index) {
+ SkDVector v1 = tests[index + 1] - tests[index];
+ SkASSERT(ValidVector(v1));
+ SkDVector v2 = tests[index] - tests[index + 1];
+ SkASSERT(ValidVector(v2));
+ v1 += v2;
+ REPORTER_ASSERT(reporter, v1.fX == 0 && v1.fY == 0);
+ SkDPoint p = tests[index + 1] + v2;
+ REPORTER_ASSERT(reporter, p == tests[index]);
+ v2 -= v2;
+ REPORTER_ASSERT(reporter, v2.fX == 0 && v2.fY == 0);
+ v1 = tests[index + 1] - tests[index];
+ v1 /= 2;
+ v1 *= 2;
+ v1 -= tests[index + 1] - tests[index];
+ REPORTER_ASSERT(reporter, v1.fX == 0 && v1.fY == 0);
+ SkVector sv = v1.asSkVector();
+ REPORTER_ASSERT(reporter, sv.fX == 0 && sv.fY == 0);
+ v1 = tests[index + 1] - tests[index];
+ double lenSq = v1.lengthSquared();
+ double v1Dot = v1.dot(v1);
+ REPORTER_ASSERT(reporter, lenSq == v1Dot);
+ REPORTER_ASSERT(reporter, approximately_equal(sqrt(lenSq), v1.length()));
+ double v1Cross = v1.cross(v1);
+ REPORTER_ASSERT(reporter, v1Cross == 0);
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsDebug.cpp b/src/third_party/skia/tests/PathOpsDebug.cpp
new file mode 100755
index 0000000..8ac38aa
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsDebug.cpp
@@ -0,0 +1,875 @@
+#include "SkOpContour.h"
+#include "SkIntersectionHelper.h"
+#include "SkOpSegment.h"
+#include "SkString.h"
+
+inline void DebugDumpDouble(double x) {
+ if (x == floor(x)) {
+ SkDebugf("%.0f", x);
+ } else {
+ SkDebugf("%1.19g", x);
+ }
+}
+
+inline void DebugDumpFloat(float x) {
+ if (x == floorf(x)) {
+ SkDebugf("%.0f", x);
+ } else {
+ SkDebugf("%1.9gf", x);
+ }
+}
+
+
+#if DEBUG_SHOW_TEST_NAME
+
+static void output_scalar(SkScalar num) {
+ if (num == (int) num) {
+ SkDebugf("%d", (int) num);
+ } else {
+ SkString str;
+ str.printf("%1.9g", num);
+ int width = (int) str.size();
+ const char* cStr = str.c_str();
+ while (cStr[width - 1] == '0') {
+ --width;
+ }
+ str.resize(width);
+ SkDebugf("%sf", str.c_str());
+ }
+}
+
+static void output_points(const SkPoint* pts, int count) {
+ for (int index = 0; index < count; ++index) {
+ output_scalar(pts[index].fX);
+ SkDebugf(", ");
+ output_scalar(pts[index].fY);
+ if (index + 1 < count) {
+ SkDebugf(", ");
+ }
+ }
+ SkDebugf(");\n");
+}
+
+static void showPathContours(SkPath::RawIter& iter, const char* pathName) {
+ uint8_t verb;
+ SkPoint pts[4];
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ SkDebugf(" %s.moveTo(", pathName);
+ output_points(&pts[0], 1);
+ continue;
+ case SkPath::kLine_Verb:
+ SkDebugf(" %s.lineTo(", pathName);
+ output_points(&pts[1], 1);
+ break;
+ case SkPath::kQuad_Verb:
+ SkDebugf(" %s.quadTo(", pathName);
+ output_points(&pts[1], 2);
+ break;
+ case SkPath::kCubic_Verb:
+ SkDebugf(" %s.cubicTo(", pathName);
+ output_points(&pts[1], 3);
+ break;
+ case SkPath::kClose_Verb:
+ SkDebugf(" %s.close();\n", pathName);
+ break;
+ default:
+ SkDEBUGFAIL("bad verb");
+ return;
+ }
+ }
+}
+
+static const char* gFillTypeStr[] = {
+ "kWinding_FillType",
+ "kEvenOdd_FillType",
+ "kInverseWinding_FillType",
+ "kInverseEvenOdd_FillType"
+};
+
+void SkPathOpsDebug::ShowOnePath(const SkPath& path, const char* name, bool includeDeclaration) {
+ SkPath::RawIter iter(path);
+#define SUPPORT_RECT_CONTOUR_DETECTION 0
+#if SUPPORT_RECT_CONTOUR_DETECTION
+ int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0;
+ if (rectCount > 0) {
+ SkTDArray<SkRect> rects;
+ SkTDArray<SkPath::Direction> directions;
+ rects.setCount(rectCount);
+ directions.setCount(rectCount);
+ path.rectContours(rects.begin(), directions.begin());
+ for (int contour = 0; contour < rectCount; ++contour) {
+ const SkRect& rect = rects[contour];
+ SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop,
+ rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction
+ ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction");
+ }
+ return;
+ }
+#endif
+ SkPath::FillType fillType = path.getFillType();
+ SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInverseEvenOdd_FillType);
+ if (includeDeclaration) {
+ SkDebugf(" SkPath %s;\n", name);
+ }
+ SkDebugf(" %s.setFillType(SkPath::%s);\n", name, gFillTypeStr[fillType]);
+ iter.setPath(path);
+ showPathContours(iter, name);
+}
+
+static void show_function_header(const char* functionName) {
+ SkDebugf("\nstatic void %s(skiatest::Reporter* reporter, const char* filename) {\n", functionName);
+ if (strcmp("skphealth_com76", functionName) == 0) {
+ SkDebugf("found it\n");
+ }
+}
+
+static const char* gOpStrs[] = {
+ "kDifference_PathOp",
+ "kIntersect_PathOp",
+ "kUnion_PathOp",
+ "kXor_PathOp",
+ "kReverseDifference_PathOp",
+};
+
+static void show_op(SkPathOp op, const char* pathOne, const char* pathTwo) {
+ SkDebugf(" testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathTwo, gOpStrs[op]);
+ SkDebugf("}\n");
+}
+
+SK_DECLARE_STATIC_MUTEX(gTestMutex);
+
+void SkPathOpsDebug::ShowPath(const SkPath& a, const SkPath& b, SkPathOp shapeOp,
+ const char* testName) {
+ SkAutoMutexAcquire ac(gTestMutex);
+ show_function_header(testName);
+ ShowOnePath(a, "path", true);
+ ShowOnePath(b, "pathB", true);
+ show_op(shapeOp, "path", "pathB");
+}
+#endif
+
+// if not defined by PathOpsDebug.cpp ...
+#if !defined SK_DEBUG && FORCE_RELEASE
+bool SkPathOpsDebug::ValidWind(int wind) {
+ return wind > SK_MinS32 + 0xFFFF && wind < SK_MaxS32 - 0xFFFF;
+}
+
+void SkPathOpsDebug::WindingPrintf(int wind) {
+ if (wind == SK_MinS32) {
+ SkDebugf("?");
+ } else {
+ SkDebugf("%d", wind);
+ }
+}
+#endif
+
+void SkOpAngle::dump() const {
+ dumpOne(true);
+ SkDebugf("\n");
+}
+
+void SkOpAngle::dumpOne(bool functionHeader) const {
+// fSegment->debugValidate();
+ const SkOpSpan& mSpan = fSegment->span(SkMin32(fStart, fEnd));
+ if (functionHeader) {
+ SkDebugf("%s ", __FUNCTION__);
+ }
+ SkDebugf("[%d", fSegment->debugID());
+ SkDebugf("/%d", debugID());
+ SkDebugf("] next=");
+ if (fNext) {
+ SkDebugf("%d", fNext->fSegment->debugID());
+ SkDebugf("/%d", fNext->debugID());
+ } else {
+ SkDebugf("?");
+ }
+ SkDebugf(" sect=%d/%d ", fSectorStart, fSectorEnd);
+ SkDebugf(" s=%1.9g [%d] e=%1.9g [%d]", fSegment->span(fStart).fT, fStart,
+ fSegment->span(fEnd).fT, fEnd);
+ SkDebugf(" sgn=%d windVal=%d", sign(), mSpan.fWindValue);
+
+ SkDebugf(" windSum=");
+ SkPathOpsDebug::WindingPrintf(mSpan.fWindSum);
+ if (mSpan.fOppValue != 0 || mSpan.fOppSum != SK_MinS32) {
+ SkDebugf(" oppVal=%d", mSpan.fOppValue);
+ SkDebugf(" oppSum=");
+ SkPathOpsDebug::WindingPrintf(mSpan.fOppSum);
+ }
+ if (mSpan.fDone) {
+ SkDebugf(" done");
+ }
+ if (unorderable()) {
+ SkDebugf(" unorderable");
+ }
+ if (small()) {
+ SkDebugf(" small");
+ }
+ if (mSpan.fTiny) {
+ SkDebugf(" tiny");
+ }
+ if (fSegment->operand()) {
+ SkDebugf(" operand");
+ }
+ if (fStop) {
+ SkDebugf(" stop");
+ }
+}
+
+void SkOpAngle::dumpTo(const SkOpSegment* segment, const SkOpAngle* to) const {
+ const SkOpAngle* first = this;
+ const SkOpAngle* next = this;
+ const char* indent = "";
+ do {
+ SkDebugf("%s", indent);
+ next->dumpOne(false);
+ if (segment == next->fSegment) {
+ if (this == fNext) {
+ SkDebugf(" << from");
+ }
+ if (to == fNext) {
+ SkDebugf(" << to");
+ }
+ }
+ SkDebugf("\n");
+ indent = " ";
+ next = next->fNext;
+ } while (next && next != first);
+}
+
+void SkOpAngle::dumpLoop() const {
+ const SkOpAngle* first = this;
+ const SkOpAngle* next = this;
+ do {
+ next->dumpOne(false);
+ SkDebugf("\n");
+ next = next->fNext;
+ } while (next && next != first);
+}
+
+void SkOpAngle::dumpPartials() const {
+ const SkOpAngle* first = this;
+ const SkOpAngle* next = this;
+ do {
+ next->fCurvePart.dumpNumber();
+ next = next->fNext;
+ } while (next && next != first);
+}
+
+void SkOpAngleSet::dump() const {
+ // FIXME: unimplemented
+/* This requires access to the internal SkChunkAlloc data
+ Defer implementing this until it is needed for debugging
+*/
+ SkASSERT(0);
+}
+
+void SkOpContour::dump() const {
+ int segmentCount = fSegments.count();
+ SkDebugf("((SkOpContour*) 0x%p) [%d]\n", this, debugID());
+ for (int test = 0; test < segmentCount; ++test) {
+ SkDebugf(" [%d] ((SkOpSegment*) 0x%p) [%d]\n", test, &fSegments[test],
+ fSegments[test].debugID());
+ }
+}
+
+void SkOpContour::dumpAngles() const {
+ int segmentCount = fSegments.count();
+ SkDebugf("((SkOpContour*) 0x%p) [%d]\n", this, debugID());
+ for (int test = 0; test < segmentCount; ++test) {
+ SkDebugf(" [%d] ", test);
+ fSegments[test].dumpAngles();
+ }
+}
+
+void SkOpContour::dumpCoincidence(const SkCoincidence& coin) const {
+ int thisIndex = coin.fSegments[0];
+ const SkOpSegment& s1 = fSegments[thisIndex];
+ int otherIndex = coin.fSegments[1];
+ const SkOpSegment& s2 = coin.fOther->fSegments[otherIndex];
+ SkDebugf("((SkOpSegment*) 0x%p) [%d] ((SkOpSegment*) 0x%p) [%d]\n", &s1, s1.debugID(),
+ &s2, s2.debugID());
+ for (int index = 0; index < 2; ++index) {
+ SkDebugf(" {%1.9gf, %1.9gf}", coin.fPts[0][index].fX, coin.fPts[0][index].fY);
+ if (coin.fNearly[index]) {
+ SkDebugf(" {%1.9gf, %1.9gf}", coin.fPts[1][index].fX, coin.fPts[1][index].fY);
+ }
+ SkDebugf(" seg1t=%1.9g seg2t=%1.9g\n", coin.fTs[0][index], coin.fTs[1][index]);
+ }
+}
+
+void SkOpContour::dumpCoincidences() const {
+ int count = fCoincidences.count();
+ if (count > 0) {
+ SkDebugf("fCoincidences count=%d\n", count);
+ for (int test = 0; test < count; ++test) {
+ dumpCoincidence(fCoincidences[test]);
+ }
+ }
+ count = fPartialCoincidences.count();
+ if (count == 0) {
+ return;
+ }
+ SkDebugf("fPartialCoincidences count=%d\n", count);
+ for (int test = 0; test < count; ++test) {
+ dumpCoincidence(fPartialCoincidences[test]);
+ }
+}
+
+void SkOpContour::dumpPt(int index) const {
+ int segmentCount = fSegments.count();
+ for (int test = 0; test < segmentCount; ++test) {
+ const SkOpSegment& segment = fSegments[test];
+ if (segment.debugID() == index) {
+ fSegments[test].dumpPts();
+ }
+ }
+}
+
+void SkOpContour::dumpPts() const {
+ int segmentCount = fSegments.count();
+ SkDebugf("((SkOpContour*) 0x%p) [%d]\n", this, debugID());
+ for (int test = 0; test < segmentCount; ++test) {
+ SkDebugf(" [%d] ", test);
+ fSegments[test].dumpPts();
+ }
+}
+
+void SkOpContour::dumpSpan(int index) const {
+ int segmentCount = fSegments.count();
+ for (int test = 0; test < segmentCount; ++test) {
+ const SkOpSegment& segment = fSegments[test];
+ if (segment.debugID() == index) {
+ fSegments[test].dumpSpans();
+ }
+ }
+}
+
+void SkOpContour::dumpSpans() const {
+ int segmentCount = fSegments.count();
+ SkDebugf("((SkOpContour*) 0x%p) [%d]\n", this, debugID());
+ for (int test = 0; test < segmentCount; ++test) {
+ SkDebugf(" [%d] ", test);
+ fSegments[test].dumpSpans();
+ }
+}
+
+void SkDCubic::dump() const {
+ SkDebugf("{{");
+ int index = 0;
+ do {
+ fPts[index].dump();
+ SkDebugf(", ");
+ } while (++index < 3);
+ fPts[index].dump();
+ SkDebugf("}}\n");
+}
+
+void SkDCubic::dumpNumber() const {
+ SkDebugf("{{");
+ int index = 0;
+ bool dumpedOne = false;
+ do {
+ if (!(fPts[index].fX == fPts[index].fX && fPts[index].fY == fPts[index].fY)) {
+ continue;
+ }
+ if (dumpedOne) {
+ SkDebugf(", ");
+ }
+ fPts[index].dump();
+ dumpedOne = true;
+ } while (++index < 3);
+ if (fPts[index].fX == fPts[index].fX && fPts[index].fY == fPts[index].fY) {
+ if (dumpedOne) {
+ SkDebugf(", ");
+ }
+ fPts[index].dump();
+ }
+ SkDebugf("}}\n");
+}
+
+void SkDLine::dump() const {
+ SkDebugf("{{");
+ fPts[0].dump();
+ SkDebugf(", ");
+ fPts[1].dump();
+ SkDebugf("}}\n");
+}
+
+void SkDPoint::dump() const {
+ SkDebugf("{");
+ DebugDumpDouble(fX);
+ SkDebugf(", ");
+ DebugDumpDouble(fY);
+ SkDebugf("}");
+}
+
+void SkDPoint::Dump(const SkPoint& pt) {
+ SkDebugf("{");
+ DebugDumpFloat(pt.fX);
+ SkDebugf(", ");
+ DebugDumpFloat(pt.fY);
+ SkDebugf("}");
+}
+
+
+void SkDQuad::dumpComma(const char* comma) const {
+ SkDebugf("{{");
+ int index = 0;
+ do {
+ fPts[index].dump();
+ SkDebugf(", ");
+ } while (++index < 2);
+ fPts[index].dump();
+ SkDebugf("}}%s\n", comma ? comma : "");
+}
+
+void SkDQuad::dump() const {
+ dumpComma("");
+}
+
+void SkIntersectionHelper::dump() const {
+ SkDPoint::Dump(pts()[0]);
+ SkDPoint::Dump(pts()[1]);
+ if (verb() >= SkPath::kQuad_Verb) {
+ SkDPoint::Dump(pts()[2]);
+ }
+ if (verb() >= SkPath::kCubic_Verb) {
+ SkDPoint::Dump(pts()[3]);
+ }
+}
+
+const SkTDArray<SkOpSpan>& SkOpSegment::debugSpans() const {
+ return fTs;
+}
+
+void SkOpSegment::dumpAngles() const {
+ SkDebugf("((SkOpSegment*) 0x%p) [%d]\n", this, debugID());
+ const SkOpAngle* fromAngle = NULL;
+ const SkOpAngle* toAngle = NULL;
+ for (int index = 0; index < count(); ++index) {
+ const SkOpAngle* fAngle = fTs[index].fFromAngle;
+ const SkOpAngle* tAngle = fTs[index].fToAngle;
+ if (fromAngle == fAngle && toAngle == tAngle) {
+ continue;
+ }
+ if (fAngle) {
+ SkDebugf(" [%d] from=%d ", index, fAngle->debugID());
+ fAngle->dumpTo(this, tAngle);
+ }
+ if (tAngle) {
+ SkDebugf(" [%d] to=%d ", index, tAngle->debugID());
+ tAngle->dumpTo(this, fAngle);
+ }
+ fromAngle = fAngle;
+ toAngle = tAngle;
+ }
+}
+
+void SkOpSegment::dumpContour(int firstID, int lastID) const {
+ if (debugID() < 0) {
+ return;
+ }
+ const SkOpSegment* test = this - (debugID() - 1);
+ test += (firstID - 1);
+ const SkOpSegment* last = test + (lastID - firstID);
+ while (test <= last) {
+ test->dumpSpans();
+ ++test;
+ }
+}
+
+void SkOpSegment::dumpPts() const {
+ int last = SkPathOpsVerbToPoints(fVerb);
+ SkDebugf("((SkOpSegment*) 0x%p) [%d] {{", this, debugID());
+ int index = 0;
+ do {
+ SkDPoint::Dump(fPts[index]);
+ SkDebugf(", ");
+ } while (++index < last);
+ SkDPoint::Dump(fPts[index]);
+ SkDebugf("}}\n");
+}
+
+void SkOpSegment::dumpDPts() const {
+ int count = SkPathOpsVerbToPoints(fVerb);
+ SkDebugf("((SkOpSegment*) 0x%p) [%d] {{", this, debugID());
+ int index = 0;
+ do {
+ SkDPoint dPt = {fPts[index].fX, fPts[index].fY};
+ dPt.dump();
+ if (index != count) {
+ SkDebugf(", ");
+ }
+ } while (++index <= count);
+ SkDebugf("}}\n");
+}
+
+void SkOpSegment::dumpSpans() const {
+ int count = this->count();
+ SkDebugf("((SkOpSegment*) 0x%p) [%d]\n", this, debugID());
+ for (int index = 0; index < count; ++index) {
+ const SkOpSpan& span = this->span(index);
+ SkDebugf(" [%d] ", index);
+ span.dumpOne();
+ }
+}
+
+void SkPathOpsDebug::DumpCoincidence(const SkTArray<SkOpContour, true>& contours) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index].dumpCoincidences();
+ }
+}
+
+void SkPathOpsDebug::DumpCoincidence(const SkTArray<SkOpContour* , true>& contours) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index]->dumpCoincidences();
+ }
+}
+
+void SkPathOpsDebug::DumpContours(const SkTArray<SkOpContour, true>& contours) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index].dump();
+ }
+}
+
+void SkPathOpsDebug::DumpContours(const SkTArray<SkOpContour* , true>& contours) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index]->dump();
+ }
+}
+
+void SkPathOpsDebug::DumpContourAngles(const SkTArray<SkOpContour, true>& contours) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index].dumpAngles();
+ }
+}
+
+void SkPathOpsDebug::DumpContourAngles(const SkTArray<SkOpContour* , true>& contours) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index]->dumpAngles();
+ }
+}
+
+void SkPathOpsDebug::DumpContourPts(const SkTArray<SkOpContour, true>& contours) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index].dumpPts();
+ }
+}
+
+void SkPathOpsDebug::DumpContourPts(const SkTArray<SkOpContour* , true>& contours) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index]->dumpPts();
+ }
+}
+
+void SkPathOpsDebug::DumpContourPt(const SkTArray<SkOpContour, true>& contours, int segmentID) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index].dumpPt(segmentID);
+ }
+}
+
+void SkPathOpsDebug::DumpContourPt(const SkTArray<SkOpContour* , true>& contours, int segmentID) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index]->dumpPt(segmentID);
+ }
+}
+
+void SkPathOpsDebug::DumpContourSpans(const SkTArray<SkOpContour, true>& contours) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index].dumpSpans();
+ }
+}
+
+void SkPathOpsDebug::DumpContourSpans(const SkTArray<SkOpContour* , true>& contours) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index]->dumpSpans();
+ }
+}
+
+void SkPathOpsDebug::DumpContourSpan(const SkTArray<SkOpContour, true>& contours, int segmentID) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index].dumpSpan(segmentID);
+ }
+}
+
+void SkPathOpsDebug::DumpContourSpan(const SkTArray<SkOpContour* , true>& contours, int segmentID) {
+ int count = contours.count();
+ for (int index = 0; index < count; ++index) {
+ contours[index]->dumpSpan(segmentID);
+ }
+}
+
+void SkPathOpsDebug::DumpSpans(const SkTDArray<SkOpSpan *>& spans) {
+ int count = spans.count();
+ for (int index = 0; index < count; ++index) {
+ const SkOpSpan* span = spans[index];
+ const SkOpSpan& oSpan = span->fOther->span(span->fOtherIndex);
+ const SkOpSegment* segment = oSpan.fOther;
+ SkDebugf("((SkOpSegment*) 0x%p) [%d] ", segment, segment->debugID());
+ SkDebugf("spanIndex:%d ", oSpan.fOtherIndex);
+ span->dumpOne();
+ }
+}
+
+// this does not require that other T index is initialized or correct
+const SkOpSegment* SkOpSpan::debugToSegment(ptrdiff_t* spanIndex) const {
+ if (!fOther) {
+ return NULL;
+ }
+ int oppCount = fOther->count();
+ for (int index = 0; index < oppCount; ++index) {
+ const SkOpSpan& otherSpan = fOther->span(index);
+ double otherTestT = otherSpan.fT;
+ if (otherTestT < fOtherT) {
+ continue;
+ }
+ SkASSERT(otherTestT == fOtherT);
+ const SkOpSegment* candidate = otherSpan.fOther;
+ const SkOpSpan* first = candidate->debugSpans().begin();
+ const SkOpSpan* last = candidate->debugSpans().end() - 1;
+ if (first <= this && this <= last) {
+ if (spanIndex) {
+ *spanIndex = this - first;
+ }
+ return candidate;
+ }
+ }
+ SkASSERT(0);
+ return NULL;
+}
+
+void SkOpSpan::dumpOne() const {
+ SkDebugf("t=");
+ DebugDumpDouble(fT);
+ SkDebugf(" pt=");
+ SkDPoint::Dump(fPt);
+ if (fOther) {
+ SkDebugf(" other.fID=%d", fOther->debugID());
+ SkDebugf(" [%d] otherT=", fOtherIndex);
+ DebugDumpDouble(fOtherT);
+ } else {
+ SkDebugf(" other.fID=? [?] otherT=?");
+ }
+ if (fWindSum != SK_MinS32) {
+ SkDebugf(" windSum=%d", fWindSum);
+ }
+ if (fOppSum != SK_MinS32 && (SkPathOpsDebug::ValidWind(fOppSum) || fOppValue != 0)) {
+ SkDebugf(" oppSum=%d", fOppSum);
+ }
+ SkDebugf(" windValue=%d", fWindValue);
+ if (SkPathOpsDebug::ValidWind(fOppSum) || fOppValue != 0) {
+ SkDebugf(" oppValue=%d", fOppValue);
+ }
+ if (fFromAngle && fFromAngle->debugID()) {
+ SkDebugf(" from=%d", fFromAngle->debugID());
+ }
+ if (fToAngle && fToAngle->debugID()) {
+ SkDebugf(" to=%d", fToAngle->debugID());
+ }
+ if (fChased) {
+ SkDebugf(" chased");
+ }
+ if (fCoincident) {
+ SkDebugf(" coincident");
+ }
+ if (fDone) {
+ SkDebugf(" done");
+ }
+ if (fLoop) {
+ SkDebugf(" loop");
+ }
+ if (fMultiple) {
+ SkDebugf(" multiple");
+ }
+ if (fNear) {
+ SkDebugf(" near");
+ }
+ if (fSmall) {
+ SkDebugf(" small");
+ }
+ if (fTiny) {
+ SkDebugf(" tiny");
+ }
+ SkDebugf("\n");
+}
+
+void SkOpSpan::dump() const {
+ ptrdiff_t spanIndex;
+ const SkOpSegment* segment = debugToSegment(&spanIndex);
+ if (segment) {
+ SkDebugf("((SkOpSegment*) 0x%p) [%d]\n", segment, segment->debugID());
+ SkDebugf(" [%d] ", spanIndex);
+ } else {
+ SkDebugf("((SkOpSegment*) ?) [?]\n");
+ SkDebugf(" [?] ");
+ }
+ dumpOne();
+}
+
+void Dump(const SkTArray<class SkOpContour, true>& contours) {
+ SkPathOpsDebug::DumpContours(contours);
+}
+
+void Dump(const SkTArray<class SkOpContour* , true>& contours) {
+ SkPathOpsDebug::DumpContours(contours);
+}
+
+void Dump(const SkTArray<class SkOpContour, true>* contours) {
+ SkPathOpsDebug::DumpContours(*contours);
+}
+
+void Dump(const SkTArray<class SkOpContour* , true>* contours) {
+ SkPathOpsDebug::DumpContours(*contours);
+}
+
+void Dump(const SkTDArray<SkOpSpan *>& chase) {
+ SkPathOpsDebug::DumpSpans(chase);
+}
+
+void Dump(const SkTDArray<SkOpSpan *>* chase) {
+ SkPathOpsDebug::DumpSpans(*chase);
+}
+
+void DumpAngles(const SkTArray<class SkOpContour, true>& contours) {
+ SkPathOpsDebug::DumpContourAngles(contours);
+}
+
+void DumpAngles(const SkTArray<class SkOpContour* , true>& contours) {
+ SkPathOpsDebug::DumpContourAngles(contours);
+}
+
+void DumpAngles(const SkTArray<class SkOpContour, true>* contours) {
+ SkPathOpsDebug::DumpContourAngles(*contours);
+}
+
+void DumpAngles(const SkTArray<class SkOpContour* , true>* contours) {
+ SkPathOpsDebug::DumpContourAngles(*contours);
+}
+
+void DumpCoin(const SkTArray<class SkOpContour, true>& contours) {
+ SkPathOpsDebug::DumpCoincidence(contours);
+}
+
+void DumpCoin(const SkTArray<class SkOpContour* , true>& contours) {
+ SkPathOpsDebug::DumpCoincidence(contours);
+}
+
+void DumpCoin(const SkTArray<class SkOpContour, true>* contours) {
+ SkPathOpsDebug::DumpCoincidence(*contours);
+}
+
+void DumpCoin(const SkTArray<class SkOpContour* , true>* contours) {
+ SkPathOpsDebug::DumpCoincidence(*contours);
+}
+
+void DumpSpans(const SkTArray<class SkOpContour, true>& contours) {
+ SkPathOpsDebug::DumpContourSpans(contours);
+}
+
+void DumpSpans(const SkTArray<class SkOpContour* , true>& contours) {
+ SkPathOpsDebug::DumpContourSpans(contours);
+}
+
+void DumpSpans(const SkTArray<class SkOpContour, true>* contours) {
+ SkPathOpsDebug::DumpContourSpans(*contours);
+}
+
+void DumpSpans(const SkTArray<class SkOpContour* , true>* contours) {
+ SkPathOpsDebug::DumpContourSpans(*contours);
+}
+
+void DumpSpan(const SkTArray<class SkOpContour, true>& contours, int segmentID) {
+ SkPathOpsDebug::DumpContourSpan(contours, segmentID);
+}
+
+void DumpSpan(const SkTArray<class SkOpContour* , true>& contours, int segmentID) {
+ SkPathOpsDebug::DumpContourSpan(contours, segmentID);
+}
+
+void DumpSpan(const SkTArray<class SkOpContour, true>* contours, int segmentID) {
+ SkPathOpsDebug::DumpContourSpan(*contours, segmentID);
+}
+
+void DumpSpan(const SkTArray<class SkOpContour* , true>* contours, int segmentID) {
+ SkPathOpsDebug::DumpContourSpan(*contours, segmentID);
+}
+
+void DumpPts(const SkTArray<class SkOpContour, true>& contours) {
+ SkPathOpsDebug::DumpContourPts(contours);
+}
+
+void DumpPts(const SkTArray<class SkOpContour* , true>& contours) {
+ SkPathOpsDebug::DumpContourPts(contours);
+}
+
+void DumpPts(const SkTArray<class SkOpContour, true>* contours) {
+ SkPathOpsDebug::DumpContourPts(*contours);
+}
+
+void DumpPts(const SkTArray<class SkOpContour* , true>* contours) {
+ SkPathOpsDebug::DumpContourPts(*contours);
+}
+
+void DumpPt(const SkTArray<class SkOpContour, true>& contours, int segmentID) {
+ SkPathOpsDebug::DumpContourPt(contours, segmentID);
+}
+
+void DumpPt(const SkTArray<class SkOpContour* , true>& contours, int segmentID) {
+ SkPathOpsDebug::DumpContourPt(contours, segmentID);
+}
+
+void DumpPt(const SkTArray<class SkOpContour, true>* contours, int segmentID) {
+ SkPathOpsDebug::DumpContourPt(*contours, segmentID);
+}
+
+void DumpPt(const SkTArray<class SkOpContour* , true>* contours, int segmentID) {
+ SkPathOpsDebug::DumpContourPt(*contours, segmentID);
+}
+
+static void dumpTestCase(const SkDQuad& quad1, const SkDQuad& quad2, int testNo) {
+ SkDebugf("<div id=\"quad%d\">\n", testNo);
+ quad1.dumpComma(",");
+ quad2.dump();
+ SkDebugf("</div>\n\n");
+}
+
+static void dumpTestTrailer() {
+ SkDebugf("</div>\n\n<script type=\"text/javascript\">\n\n");
+ SkDebugf(" var testDivs = [\n");
+}
+
+static void dumpTestList(int testNo, double min) {
+ SkDebugf(" quad%d,", testNo);
+ if (min > 0) {
+ SkDebugf(" // %1.9g", min);
+ }
+ SkDebugf("\n");
+}
+
+void DumpQ(const SkDQuad& quad1, const SkDQuad& quad2, int testNo) {
+ SkDebugf("\n");
+ dumpTestCase(quad1, quad2, testNo);
+ dumpTestTrailer();
+ dumpTestList(testNo, 0);
+ SkDebugf("\n");
+}
+
+void DumpT(const SkDQuad& quad, double t) {
+ SkDLine line = {{quad.ptAtT(t), quad[0]}};
+ line.dump();
+}
diff --git a/src/third_party/skia/tests/PathOpsExtendedTest.cpp b/src/third_party/skia/tests/PathOpsExtendedTest.cpp
new file mode 100644
index 0000000..d808ed7
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsExtendedTest.cpp
@@ -0,0 +1,630 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "PathOpsExtendedTest.h"
+#include "PathOpsThreadedCommon.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkForceLinking.h"
+#include "SkMatrix.h"
+#include "SkPaint.h"
+#include "SkRTConf.h"
+#include "SkStream.h"
+#include "SkTaskGroup.h"
+#include "SkThread.h"
+
+#ifdef SK_BUILD_FOR_MAC
+#include <sys/sysctl.h>
+#endif
+
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
+DEFINE_bool2(runFail, f, false, "run tests known to fail.");
+
+static const char marker[] =
+ "</div>\n"
+ "\n"
+ "<script type=\"text/javascript\">\n"
+ "\n"
+ "var testDivs = [\n";
+
+static const char* opStrs[] = {
+ "kDifference_PathOp",
+ "kIntersect_PathOp",
+ "kUnion_PathOp",
+ "kXor_PathOp",
+ "kReverseDifference_PathOp",
+};
+
+static const char* opSuffixes[] = {
+ "d",
+ "i",
+ "u",
+ "o",
+};
+
+static bool gShowPath = false;
+static bool gComparePathsAssert = true;
+static bool gPathStrAssert = true;
+
+#if DEBUG_SHOW_TEST_NAME
+static void showPathData(const SkPath& path) {
+ SkPath::RawIter iter(path);
+ uint8_t verb;
+ SkPoint pts[4];
+ SkPoint firstPt = {0, 0}, lastPt = {0, 0};
+ bool firstPtSet = false;
+ bool lastPtSet = true;
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ if (firstPtSet && lastPtSet && firstPt != lastPt) {
+ SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", lastPt.fX, lastPt.fY,
+ firstPt.fX, firstPt.fY);
+ lastPtSet = false;
+ }
+ firstPt = pts[0];
+ firstPtSet = true;
+ continue;
+ case SkPath::kLine_Verb:
+ SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", pts[0].fX, pts[0].fY,
+ pts[1].fX, pts[1].fY);
+ lastPt = pts[1];
+ lastPtSet = true;
+ break;
+ case SkPath::kQuad_Verb:
+ SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n",
+ pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
+ lastPt = pts[2];
+ lastPtSet = true;
+ break;
+ case SkPath::kCubic_Verb:
+ SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n",
+ pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
+ pts[3].fX, pts[3].fY);
+ lastPt = pts[3];
+ lastPtSet = true;
+ break;
+ case SkPath::kClose_Verb:
+ if (firstPtSet && lastPtSet && firstPt != lastPt) {
+ SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", lastPt.fX, lastPt.fY,
+ firstPt.fX, firstPt.fY);
+ }
+ firstPtSet = lastPtSet = false;
+ break;
+ default:
+ SkDEBUGFAIL("bad verb");
+ return;
+ }
+ }
+ if (firstPtSet && lastPtSet && firstPt != lastPt) {
+ SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", lastPt.fX, lastPt.fY,
+ firstPt.fX, firstPt.fY);
+ }
+}
+#endif
+
+void showOp(const SkPathOp op) {
+ switch (op) {
+ case kDifference_PathOp:
+ SkDebugf("op difference\n");
+ break;
+ case kIntersect_PathOp:
+ SkDebugf("op intersect\n");
+ break;
+ case kUnion_PathOp:
+ SkDebugf("op union\n");
+ break;
+ case kXOR_PathOp:
+ SkDebugf("op xor\n");
+ break;
+ case kReverseDifference_PathOp:
+ SkDebugf("op reverse difference\n");
+ break;
+ default:
+ SkASSERT(0);
+ }
+}
+
+#if DEBUG_SHOW_TEST_NAME
+static char hexorator(int x) {
+ if (x < 10) {
+ return x + '0';
+ }
+ x -= 10;
+ SkASSERT(x < 26);
+ return x + 'A';
+}
+#endif
+
+void ShowTestName(PathOpsThreadState* state, int a, int b, int c, int d) {
+#if DEBUG_SHOW_TEST_NAME
+ state->fSerialNo[0] = hexorator(state->fA);
+ state->fSerialNo[1] = hexorator(state->fB);
+ state->fSerialNo[2] = hexorator(state->fC);
+ state->fSerialNo[3] = hexorator(state->fD);
+ state->fSerialNo[4] = hexorator(a);
+ state->fSerialNo[5] = hexorator(b);
+ state->fSerialNo[6] = hexorator(c);
+ state->fSerialNo[7] = hexorator(d);
+ state->fSerialNo[8] = '\0';
+ SkDebugf("%s\n", state->fSerialNo);
+ if (strcmp(state->fSerialNo, state->fKey) == 0) {
+ SkDebugf("%s\n", state->fPathStr);
+ }
+#endif
+}
+
+const int bitWidth = 64;
+const int bitHeight = 64;
+
+static void scaleMatrix(const SkPath& one, const SkPath& two, SkMatrix& scale) {
+ SkRect larger = one.getBounds();
+ larger.join(two.getBounds());
+ SkScalar largerWidth = larger.width();
+ if (largerWidth < 4) {
+ largerWidth = 4;
+ }
+ SkScalar largerHeight = larger.height();
+ if (largerHeight < 4) {
+ largerHeight = 4;
+ }
+ SkScalar hScale = (bitWidth - 2) / largerWidth;
+ SkScalar vScale = (bitHeight - 2) / largerHeight;
+ scale.reset();
+ scale.preScale(hScale, vScale);
+}
+
+static int pathsDrawTheSame(SkBitmap& bits, const SkPath& scaledOne, const SkPath& scaledTwo,
+ int& error2x2) {
+ if (bits.width() == 0) {
+ bits.allocN32Pixels(bitWidth * 2, bitHeight);
+ }
+ SkCanvas canvas(bits);
+ canvas.drawColor(SK_ColorWHITE);
+ SkPaint paint;
+ canvas.save();
+ const SkRect& bounds1 = scaledOne.getBounds();
+ canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
+ canvas.drawPath(scaledOne, paint);
+ canvas.restore();
+ canvas.save();
+ canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
+ canvas.drawPath(scaledTwo, paint);
+ canvas.restore();
+ int errors2 = 0;
+ int errors = 0;
+ for (int y = 0; y < bitHeight - 1; ++y) {
+ uint32_t* addr1 = bits.getAddr32(0, y);
+ uint32_t* addr2 = bits.getAddr32(0, y + 1);
+ uint32_t* addr3 = bits.getAddr32(bitWidth, y);
+ uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1);
+ for (int x = 0; x < bitWidth - 1; ++x) {
+ // count 2x2 blocks
+ bool err = addr1[x] != addr3[x];
+ if (err) {
+ errors2 += addr1[x + 1] != addr3[x + 1]
+ && addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1];
+ errors++;
+ }
+ }
+ }
+ error2x2 = errors2;
+ return errors;
+}
+
+static int pathsDrawTheSame(const SkPath& one, const SkPath& two, SkBitmap& bits, SkPath& scaledOne,
+ SkPath& scaledTwo, int& error2x2) {
+ SkMatrix scale;
+ scaleMatrix(one, two, scale);
+ one.transform(scale, &scaledOne);
+ two.transform(scale, &scaledTwo);
+ return pathsDrawTheSame(bits, scaledOne, scaledTwo, error2x2);
+}
+
+bool drawAsciiPaths(const SkPath& one, const SkPath& two, bool drawPaths) {
+ if (!drawPaths) {
+ return true;
+ }
+ const SkRect& bounds1 = one.getBounds();
+ const SkRect& bounds2 = two.getBounds();
+ SkRect larger = bounds1;
+ larger.join(bounds2);
+ SkBitmap bits;
+ char out[256];
+ int bitWidth = SkScalarCeilToInt(larger.width()) + 2;
+ if (bitWidth * 2 + 1 >= (int) sizeof(out)) {
+ return false;
+ }
+ int bitHeight = SkScalarCeilToInt(larger.height()) + 2;
+ if (bitHeight >= (int) sizeof(out)) {
+ return false;
+ }
+ bits.allocN32Pixels(bitWidth * 2, bitHeight);
+ SkCanvas canvas(bits);
+ canvas.drawColor(SK_ColorWHITE);
+ SkPaint paint;
+ canvas.save();
+ canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
+ canvas.drawPath(one, paint);
+ canvas.restore();
+ canvas.save();
+ canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
+ canvas.drawPath(two, paint);
+ canvas.restore();
+ for (int y = 0; y < bitHeight; ++y) {
+ uint32_t* addr1 = bits.getAddr32(0, y);
+ int x;
+ char* outPtr = out;
+ for (x = 0; x < bitWidth; ++x) {
+ *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
+ }
+ *outPtr++ = '|';
+ for (x = bitWidth; x < bitWidth * 2; ++x) {
+ *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
+ }
+ *outPtr++ = '\0';
+ SkDebugf("%s\n", out);
+ }
+ return true;
+}
+
+static int comparePaths(skiatest::Reporter* reporter, const char* filename, const SkPath& one,
+ const SkPath& two, SkBitmap& bitmap) {
+ int errors2x2;
+ SkPath scaledOne, scaledTwo;
+ (void) pathsDrawTheSame(one, two, bitmap, scaledOne, scaledTwo, errors2x2);
+ if (errors2x2 == 0) {
+ return 0;
+ }
+ const int MAX_ERRORS = 9;
+ REPORTER_ASSERT(reporter, errors2x2 <= MAX_ERRORS || !gComparePathsAssert);
+ return errors2x2 > MAX_ERRORS ? errors2x2 : 0;
+}
+
+const int gTestFirst = 4;
+static int gTestNo = gTestFirst;
+static SkTDArray<SkPathOp> gTestOp;
+
+static void showPathOpPath(const char* testName, const SkPath& one, const SkPath& two,
+ const SkPath& a, const SkPath& b, const SkPath& scaledOne, const SkPath& scaledTwo,
+ const SkPathOp shapeOp, const SkMatrix& scale) {
+ SkASSERT((unsigned) shapeOp < SK_ARRAY_COUNT(opStrs));
+ SkString defaultTestName;
+ if (!testName) {
+ defaultTestName.printf("xOp%d%s", gTestNo, opSuffixes[shapeOp]);
+ testName = defaultTestName.c_str();
+ }
+ SkDebugf("static void %s(skiatest::Reporter* reporter, const char* filename) {\n", testName);
+ *gTestOp.append() = shapeOp;
+ ++gTestNo;
+ SkDebugf(" SkPath path, pathB;\n");
+#if DEBUG_SHOW_TEST_NAME
+ SkPathOpsDebug::ShowOnePath(a, "path", false);
+ SkPathOpsDebug::ShowOnePath(b, "pathB", false);
+#endif
+ SkDebugf(" testPathOp(reporter, path, pathB, %s, filename);\n", opStrs[shapeOp]);
+ SkDebugf("}\n");
+ drawAsciiPaths(scaledOne, scaledTwo, true);
+}
+
+void ShowTestArray() {
+ for (int x = gTestFirst; x < gTestNo; ++x) {
+ SkDebugf(" TEST(xOp%d%s),\n", x, opSuffixes[gTestOp[x - gTestFirst]]);
+ }
+}
+
+SK_DECLARE_STATIC_MUTEX(compareDebugOut3);
+SK_DECLARE_STATIC_MUTEX(compareDebugOut4);
+static int comparePaths(skiatest::Reporter* reporter, const char* testName, const SkPath& one,
+ const SkPath& scaledOne, const SkPath& two, const SkPath& scaledTwo, SkBitmap& bitmap,
+ const SkPath& a, const SkPath& b, const SkPathOp shapeOp, const SkMatrix& scale) {
+ int errors2x2;
+ (void) pathsDrawTheSame(bitmap, scaledOne, scaledTwo, errors2x2);
+ if (errors2x2 == 0) {
+ if (gShowPath) {
+ showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
+ }
+ return 0;
+ }
+ const int MAX_ERRORS = 8;
+ if (errors2x2 > MAX_ERRORS && gComparePathsAssert) {
+ SkAutoMutexAcquire autoM(compareDebugOut3);
+ SkDebugf("\n*** this test fails ***\n");
+ showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
+ REPORTER_ASSERT(reporter, 0);
+ } else if (gShowPath || errors2x2 == MAX_ERRORS || errors2x2 == MAX_ERRORS - 1) {
+ SkAutoMutexAcquire autoM(compareDebugOut4);
+ showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
+ }
+ return errors2x2 > MAX_ERRORS ? errors2x2 : 0;
+}
+
+// Default values for when reporter->verbose() is false.
+static int testNumber = 55;
+static const char* testName = "pathOpTest";
+
+static void writeTestName(const char* nameSuffix, SkMemoryWStream& outFile) {
+ outFile.writeText(testName);
+ outFile.writeDecAsText(testNumber);
+ ++testNumber;
+ if (nameSuffix) {
+ outFile.writeText(nameSuffix);
+ }
+}
+
+static void outputToStream(const char* pathStr, const char* pathPrefix, const char* nameSuffix,
+ const char* testFunction, bool twoPaths, SkMemoryWStream& outFile) {
+#if 0
+ outFile.writeText("<div id=\"");
+ writeTestName(nameSuffix, outFile);
+ outFile.writeText("\">\n");
+ if (pathPrefix) {
+ outFile.writeText(pathPrefix);
+ }
+ outFile.writeText(pathStr);
+ outFile.writeText("</div>\n\n");
+
+ outFile.writeText(marker);
+ outFile.writeText(" ");
+ writeTestName(nameSuffix, outFile);
+ outFile.writeText(",\n\n\n");
+#endif
+ outFile.writeText("static void ");
+ writeTestName(nameSuffix, outFile);
+ outFile.writeText("(skiatest::Reporter* reporter) {\n SkPath path");
+ if (twoPaths) {
+ outFile.writeText(", pathB");
+ }
+ outFile.writeText(";\n");
+ if (pathPrefix) {
+ outFile.writeText(pathPrefix);
+ }
+ outFile.writeText(pathStr);
+ outFile.writeText(" ");
+ outFile.writeText(testFunction);
+ outFile.writeText("\n}\n\n");
+#if 0
+ outFile.writeText("static void (*firstTest)() = ");
+ writeTestName(nameSuffix, outFile);
+ outFile.writeText(";\n\n");
+
+ outFile.writeText("static struct {\n");
+ outFile.writeText(" void (*fun)();\n");
+ outFile.writeText(" const char* str;\n");
+ outFile.writeText("} tests[] = {\n");
+ outFile.writeText(" TEST(");
+ writeTestName(nameSuffix, outFile);
+ outFile.writeText("),\n");
+#endif
+ outFile.flush();
+}
+
+SK_DECLARE_STATIC_MUTEX(simplifyDebugOut);
+bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& state,
+ const char* pathStr) {
+ SkPath::FillType fillType = useXor ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
+ path.setFillType(fillType);
+#if DEBUG_SHOW_TEST_NAME
+ if (gShowPath) {
+ SkPathOpsDebug::ShowOnePath(path, "path", false);
+ }
+#endif
+ if (!Simplify(path, &out)) {
+ SkDebugf("%s did not expect failure\n", __FUNCTION__);
+ REPORTER_ASSERT(state.fReporter, 0);
+ return false;
+ }
+ if (!state.fReporter->verbose()) {
+ return true;
+ }
+ int result = comparePaths(state.fReporter, NULL, path, out, *state.fBitmap);
+ if (result && gPathStrAssert) {
+ SkAutoMutexAcquire autoM(simplifyDebugOut);
+ char temp[8192];
+ sk_bzero(temp, sizeof(temp));
+ SkMemoryWStream stream(temp, sizeof(temp));
+ const char* pathPrefix = NULL;
+ const char* nameSuffix = NULL;
+ if (fillType == SkPath::kEvenOdd_FillType) {
+ pathPrefix = " path.setFillType(SkPath::kEvenOdd_FillType);\n";
+ nameSuffix = "x";
+ }
+ const char testFunction[] = "testSimplify(reporter, path);";
+ outputToStream(pathStr, pathPrefix, nameSuffix, testFunction, false, stream);
+ SkDebugf(temp);
+ REPORTER_ASSERT(state.fReporter, 0);
+ }
+ state.fReporter->bumpTestCount();
+ return result == 0;
+}
+
+bool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename) {
+#if DEBUG_SHOW_TEST_NAME
+ showPathData(path);
+#endif
+ SkPath out;
+ if (!Simplify(path, &out)) {
+ SkDebugf("%s did not expect failure\n", __FUNCTION__);
+ REPORTER_ASSERT(reporter, 0);
+ return false;
+ }
+ SkBitmap bitmap;
+ int result = comparePaths(reporter, filename, path, out, bitmap);
+ if (result && gPathStrAssert) {
+ REPORTER_ASSERT(reporter, 0);
+ }
+ reporter->bumpTestCount();
+ return result == 0;
+}
+
+#if DEBUG_SHOW_TEST_NAME
+static void showName(const SkPath& a, const SkPath& b, const SkPathOp shapeOp) {
+ SkDebugf("\n");
+ showPathData(a);
+ showOp(shapeOp);
+ showPathData(b);
+}
+#endif
+
+static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
+ const SkPathOp shapeOp, const char* testName, bool threaded) {
+#if DEBUG_SHOW_TEST_NAME
+ showName(a, b, shapeOp);
+#endif
+ SkPath out;
+ if (!Op(a, b, shapeOp, &out) ) {
+ SkDebugf("%s did not expect failure\n", __FUNCTION__);
+ REPORTER_ASSERT(reporter, 0);
+ return false;
+ }
+ if (threaded && !reporter->verbose()) {
+ return true;
+ }
+ SkPath pathOut, scaledPathOut;
+ SkRegion rgnA, rgnB, openClip, rgnOut;
+ openClip.setRect(-16000, -16000, 16000, 16000);
+ rgnA.setPath(a, openClip);
+ rgnB.setPath(b, openClip);
+ rgnOut.op(rgnA, rgnB, (SkRegion::Op) shapeOp);
+ rgnOut.getBoundaryPath(&pathOut);
+
+ SkMatrix scale;
+ scaleMatrix(a, b, scale);
+ SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
+ SkPath scaledA, scaledB;
+ scaledA.addPath(a, scale);
+ scaledA.setFillType(a.getFillType());
+ scaledB.addPath(b, scale);
+ scaledB.setFillType(b.getFillType());
+ scaledRgnA.setPath(scaledA, openClip);
+ scaledRgnB.setPath(scaledB, openClip);
+ scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) shapeOp);
+ scaledRgnOut.getBoundaryPath(&scaledPathOut);
+ SkBitmap bitmap;
+ SkPath scaledOut;
+ scaledOut.addPath(out, scale);
+ scaledOut.setFillType(out.getFillType());
+ int result = comparePaths(reporter, testName, pathOut, scaledPathOut, out, scaledOut, bitmap,
+ a, b, shapeOp, scale);
+ if (result && gPathStrAssert) {
+ REPORTER_ASSERT(reporter, 0);
+ }
+ reporter->bumpTestCount();
+ return result == 0;
+}
+
+bool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
+ const SkPathOp shapeOp, const char* testName) {
+ return innerPathOp(reporter, a, b, shapeOp, testName, false);
+}
+
+bool testPathFailOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
+ const SkPathOp shapeOp, const char* testName) {
+#if DEBUG_SHOW_TEST_NAME
+ showName(a, b, shapeOp);
+#endif
+ SkPath out;
+ if (Op(a, b, shapeOp, &out) ) {
+ SkDebugf("%s test is expected to fail\n", __FUNCTION__);
+ REPORTER_ASSERT(reporter, 0);
+ return false;
+ }
+ return true;
+}
+
+bool testThreadedPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
+ const SkPathOp shapeOp, const char* testName) {
+ return innerPathOp(reporter, a, b, shapeOp, testName, true);
+}
+
+SK_DECLARE_STATIC_MUTEX(gMutex);
+
+void initializeTests(skiatest::Reporter* reporter, const char* test) {
+#if 0 // doesn't work yet
+ SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true);
+ SK_CONF_SET("images.png.suppressDecoderWarnings", true);
+#endif
+ if (reporter->verbose()) {
+ SkAutoMutexAcquire lock(gMutex);
+ testName = test;
+ size_t testNameSize = strlen(test);
+ SkFILEStream inFile("../../experimental/Intersection/op.htm");
+ if (inFile.isValid()) {
+ SkTDArray<char> inData;
+ inData.setCount((int) inFile.getLength());
+ size_t inLen = inData.count();
+ inFile.read(inData.begin(), inLen);
+ inFile.setPath(NULL);
+ char* insert = strstr(inData.begin(), marker);
+ if (insert) {
+ insert += sizeof(marker) - 1;
+ const char* numLoc = insert + 4 /* indent spaces */ + testNameSize - 1;
+ testNumber = atoi(numLoc) + 1;
+ }
+ }
+ }
+}
+
+void outputProgress(char* ramStr, const char* pathStr, SkPath::FillType pathFillType) {
+ const char testFunction[] = "testSimplify(path);";
+ const char* pathPrefix = NULL;
+ const char* nameSuffix = NULL;
+ if (pathFillType == SkPath::kEvenOdd_FillType) {
+ pathPrefix = " path.setFillType(SkPath::kEvenOdd_FillType);\n";
+ nameSuffix = "x";
+ }
+ SkMemoryWStream rRamStream(ramStr, PATH_STR_SIZE);
+ outputToStream(pathStr, pathPrefix, nameSuffix, testFunction, false, rRamStream);
+}
+
+void outputProgress(char* ramStr, const char* pathStr, SkPathOp op) {
+ const char testFunction[] = "testOp(path);";
+ SkASSERT((size_t) op < SK_ARRAY_COUNT(opSuffixes));
+ const char* nameSuffix = opSuffixes[op];
+ SkMemoryWStream rRamStream(ramStr, PATH_STR_SIZE);
+ outputToStream(pathStr, NULL, nameSuffix, testFunction, true, rRamStream);
+}
+
+void RunTestSet(skiatest::Reporter* reporter, TestDesc tests[], size_t count,
+ void (*firstTest)(skiatest::Reporter* , const char* filename),
+ void (*stopTest)(skiatest::Reporter* , const char* filename), bool reverse) {
+ size_t index;
+ if (firstTest) {
+ index = count - 1;
+ while (index > 0 && tests[index].fun != firstTest) {
+ --index;
+ }
+#if DEBUG_SHOW_TEST_NAME
+ SkDebugf("<div id=\"%s\">\n", tests[index].str);
+ SkDebugf(" %s [%s]\n", __FUNCTION__, tests[index].str);
+#endif
+ (*tests[index].fun)(reporter, tests[index].str);
+ if (tests[index].fun == stopTest) {
+ return;
+ }
+ }
+ index = reverse ? count - 1 : 0;
+ size_t last = reverse ? 0 : count - 1;
+ do {
+ if (tests[index].fun != firstTest) {
+ #if DEBUG_SHOW_TEST_NAME
+ SkDebugf("<div id=\"%s\">\n", tests[index].str);
+ SkDebugf(" %s [%s]\n", __FUNCTION__, tests[index].str);
+ #endif
+ (*tests[index].fun)(reporter, tests[index].str);
+ }
+ if (tests[index].fun == stopTest) {
+ SkDebugf("lastTest\n");
+ break;
+ }
+ if (index == last) {
+ break;
+ }
+ index += reverse ? -1 : 1;
+ } while (true);
+}
diff --git a/src/third_party/skia/tests/PathOpsExtendedTest.h b/src/third_party/skia/tests/PathOpsExtendedTest.h
new file mode 100644
index 0000000..49ac804
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsExtendedTest.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef PathOpsExtendedTest_DEFINED
+#define PathOpsExtendedTest_DEFINED
+
+#include "SkBitmap.h"
+#include "SkCommandLineFlags.h"
+#include "SkPath.h"
+#include "SkPathOpsTypes.h"
+#include "SkStream.h"
+#include "SkThread.h"
+#include "SkThreadUtils.h"
+#include "Test.h"
+
+DECLARE_bool(runFail);
+
+struct PathOpsThreadState;
+
+struct TestDesc {
+ void (*fun)(skiatest::Reporter*, const char* filename);
+ const char* str;
+};
+
+//extern int comparePaths(const SkPath& one, const SkPath& two);
+extern int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap);
+extern bool drawAsciiPaths(const SkPath& one, const SkPath& two, bool drawPaths);
+extern void showOp(const SkPathOp op);
+extern bool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
+ const SkPathOp , const char* testName);
+extern bool testPathFailOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
+ const SkPathOp , const char* testName);
+extern bool testThreadedPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
+ const SkPathOp , const char* testName);
+extern bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& state,
+ const char* pathStr);
+extern bool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename);
+
+void initializeTests(skiatest::Reporter* reporter, const char* testName);
+void outputProgress(char* ramStr, const char* pathStr, SkPath::FillType );
+void outputProgress(char* ramStr, const char* pathStr, SkPathOp op);
+
+void RunTestSet(skiatest::Reporter* reporter, TestDesc tests[], size_t count,
+ void (*firstTest)(skiatest::Reporter* , const char* filename),
+ void (*stopTest)(skiatest::Reporter* , const char* filename), bool reverse);
+void ShowTestArray();
+void ShowTestName(PathOpsThreadState* data, int a, int b, int c, int d);
+void ShowFunctionHeader(const char* name);
+void ShowPath(const SkPath& path, const char* pathName);
+void ShowOp(SkPathOp op, const char* pathOne, const char* pathTwo);
+
+#endif
diff --git a/src/third_party/skia/tests/PathOpsInverseTest.cpp b/src/third_party/skia/tests/PathOpsInverseTest.cpp
new file mode 100644
index 0000000..23dbd1f
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsInverseTest.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+
+DEF_TEST(PathOpsInverse, reporter) {
+ SkPath one, two;
+ for (int op = kDifference_PathOp; op <= kReverseDifference_PathOp; ++op) {
+ for (int oneFill = SkPath::kWinding_FillType; oneFill <= SkPath::kInverseEvenOdd_FillType;
+ ++oneFill) {
+ for (int oneDir = SkPath::kCW_Direction; oneDir != SkPath::kCCW_Direction; ++oneDir) {
+ one.reset();
+ one.setFillType((SkPath::FillType) oneFill);
+ one.addRect(0, 0, 6, 6, (SkPath::Direction) oneDir);
+ for (int twoFill = SkPath::kWinding_FillType;
+ twoFill <= SkPath::kInverseEvenOdd_FillType; ++twoFill) {
+ for (int twoDir = SkPath::kCW_Direction; twoDir != SkPath::kCCW_Direction;
+ ++twoDir) {
+ two.reset();
+ two.setFillType((SkPath::FillType) twoFill);
+ two.addRect(3, 3, 9, 9, (SkPath::Direction) twoDir);
+ testPathOp(reporter, one, two, (SkPathOp) op, "inverseTest");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsLineIntersectionTest.cpp b/src/third_party/skia/tests/PathOpsLineIntersectionTest.cpp
new file mode 100644
index 0000000..105187b
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsLineIntersectionTest.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkIntersections.h"
+#include "SkPathOpsLine.h"
+#include "Test.h"
+
+// FIXME: add tests for intersecting, non-intersecting, degenerate, coincident
+static const SkDLine tests[][2] = {
+#if 0
+ // these do intersect at a pair of points, but not close enough for check results liking
+ {{{{365.848175,5081.15186}, {368,5103}}}, {{{367.967712,5102.61084}, {368.278717,5105.71045}}}},
+#endif
+ {{{{30,20}, {30,50}}}, {{{24,30}, {36,30}}}},
+ {{{{323,193}, {-317,193}}}, {{{0,994}, {0,0}}}},
+ {{{{90,230}, {160,60}}}, {{{60,120}, {260,120}}}},
+ {{{{90,230}, {160,60}}}, {{{181.176468,120}, {135.294128,120}}}},
+ {{{{181.1764678955078125f, 120}, {186.3661956787109375f, 134.7042236328125f}}},
+ {{{175.8309783935546875f, 141.5211334228515625f}, {187.8782806396484375f, 133.7258148193359375f}}}},
+#if 0 // FIXME: these fail because one line is too short and appears quasi-coincident
+ {{{{158.000000, 926.000000}, {1108.00000, 926.000000}}},
+ {{{1108.00000, 926.000000}, {1108.00000, 925.999634}}}},
+ {{{{1108,926}, {1108,925.9996337890625}}}, {{{158,926}, {1108,926}}}},
+#endif
+ {{{{192, 4}, {243, 4}}}, {{{246, 4}, {189, 4}}}},
+ {{{{246, 4}, {189, 4}}}, {{{192, 4}, {243, 4}}}},
+ {{{{5, 0}, {0, 5}}}, {{{5, 4}, {1, 4}}}},
+ {{{{0, 0}, {1, 0}}}, {{{1, 0}, {0, 0}}}},
+ {{{{0, 0}, {0, 0}}}, {{{0, 0}, {1, 0}}}},
+ {{{{0, 1}, {0, 1}}}, {{{0, 0}, {0, 2}}}},
+ {{{{0, 0}, {1, 0}}}, {{{0, 0}, {2, 0}}}},
+ {{{{1, 1}, {2, 2}}}, {{{0, 0}, {3, 3}}}},
+ {{{{166.86950047022856, 112.69654129527828}, {166.86948801592692, 112.69655741235339}}},
+ {{{166.86960700313026, 112.6965477747386}, {166.86925794355412, 112.69656471103423}}}}
+};
+
+static const size_t tests_count = SK_ARRAY_COUNT(tests);
+
+static const SkDLine noIntersect[][2] = {
+ {{{{(double) (2 - 1e-6f),2}, {(double) (2 - 1e-6f),4}}},
+ {{{2,1}, {2,3}}}},
+
+ {{{{0, 0}, {1, 0}}}, {{{3, 0}, {2, 0}}}},
+ {{{{0, 0}, {0, 0}}}, {{{1, 0}, {2, 0}}}},
+ {{{{0, 1}, {0, 1}}}, {{{0, 3}, {0, 2}}}},
+ {{{{0, 0}, {1, 0}}}, {{{2, 0}, {3, 0}}}},
+ {{{{1, 1}, {2, 2}}}, {{{4, 4}, {3, 3}}}},
+};
+
+static const size_t noIntersect_count = SK_ARRAY_COUNT(noIntersect);
+
+static const SkDLine coincidentTests[][2] = {
+ {{{ {-1.48383003e-006,-83}, {4.2268899e-014,-60} }},
+ {{ {9.5359502e-007,-60}, {5.08227985e-015,-83} }}},
+
+ {{{ { 10105, 2510 }, { 10123, 2509.98999f } }},
+ {{{10105, 2509.98999f}, { 10123, 2510 } }}},
+
+ {{ { { 0, 482.5 }, { -4.4408921e-016, 682.5 } } },
+ {{{0,683}, {0,482}}}},
+
+ {{{{1.77635684e-015,312}, {-1.24344979e-014,348}}},
+ {{{0,348}, {0,312}}}},
+
+ {{{{979.304871, 561}, {1036.69507, 291}}},
+ {{{985.681519, 531}, {982.159790, 547.568542}}}},
+
+ {{{{232.159805, 547.568542}, {235.681549, 531}}},
+ {{{286.695129,291}, {229.304855,561}}}},
+
+ {{{{186.3661956787109375f, 134.7042236328125f}, {187.8782806396484375f, 133.7258148193359375f}}},
+ {{{175.8309783935546875f, 141.5211334228515625f}, {187.8782806396484375f, 133.7258148193359375f}}}},
+
+ {{{{235.681549, 531.000000}, {280.318420, 321.000000}}},
+ {{{286.695129, 291.000000}, {229.304855, 561.000000}}}},
+};
+
+static const size_t coincidentTests_count = SK_ARRAY_COUNT(coincidentTests);
+
+static void check_results(skiatest::Reporter* reporter, const SkDLine& line1, const SkDLine& line2,
+ const SkIntersections& ts) {
+ for (int i = 0; i < ts.used(); ++i) {
+ SkDPoint result1 = line1.ptAtT(ts[0][i]);
+ SkDPoint result2 = line2.ptAtT(ts[1][i]);
+ if (!result1.approximatelyEqual(result2) && !ts.nearlySame(i)) {
+ REPORTER_ASSERT(reporter, ts.used() != 1);
+ result2 = line2.ptAtT(ts[1][i ^ 1]);
+ if (!result1.approximatelyEqual(result2)) {
+ SkDebugf(".");
+ }
+ REPORTER_ASSERT(reporter, result1.approximatelyEqual(result2));
+ REPORTER_ASSERT(reporter, result1.approximatelyEqual(ts.pt(i).asSkPoint()));
+ }
+ }
+}
+
+static void testOne(skiatest::Reporter* reporter, const SkDLine& line1, const SkDLine& line2) {
+ SkASSERT(ValidLine(line1));
+ SkASSERT(ValidLine(line2));
+ SkIntersections i;
+ int pts = i.intersect(line1, line2);
+ REPORTER_ASSERT(reporter, pts);
+ REPORTER_ASSERT(reporter, pts == i.used());
+ check_results(reporter, line1, line2, i);
+ if (line1[0] == line1[1] || line2[0] == line2[1]) {
+ return;
+ }
+ if (line1[0].fY == line1[1].fY) {
+ double left = SkTMin(line1[0].fX, line1[1].fX);
+ double right = SkTMax(line1[0].fX, line1[1].fX);
+ SkIntersections ts;
+ ts.horizontal(line2, left, right, line1[0].fY, line1[0].fX != left);
+ check_results(reporter, line2, line1, ts);
+ }
+ if (line2[0].fY == line2[1].fY) {
+ double left = SkTMin(line2[0].fX, line2[1].fX);
+ double right = SkTMax(line2[0].fX, line2[1].fX);
+ SkIntersections ts;
+ ts.horizontal(line1, left, right, line2[0].fY, line2[0].fX != left);
+ check_results(reporter, line1, line2, ts);
+ }
+ if (line1[0].fX == line1[1].fX) {
+ double top = SkTMin(line1[0].fY, line1[1].fY);
+ double bottom = SkTMax(line1[0].fY, line1[1].fY);
+ SkIntersections ts;
+ ts.vertical(line2, top, bottom, line1[0].fX, line1[0].fY != top);
+ check_results(reporter, line2, line1, ts);
+ }
+ if (line2[0].fX == line2[1].fX) {
+ double top = SkTMin(line2[0].fY, line2[1].fY);
+ double bottom = SkTMax(line2[0].fY, line2[1].fY);
+ SkIntersections ts;
+ ts.vertical(line1, top, bottom, line2[0].fX, line2[0].fY != top);
+ check_results(reporter, line1, line2, ts);
+ }
+ reporter->bumpTestCount();
+}
+
+static void testOneCoincident(skiatest::Reporter* reporter, const SkDLine& line1,
+ const SkDLine& line2) {
+ SkASSERT(ValidLine(line1));
+ SkASSERT(ValidLine(line2));
+ SkIntersections ts;
+ int pts = ts.intersect(line1, line2);
+ REPORTER_ASSERT(reporter, pts == 2);
+ REPORTER_ASSERT(reporter, pts == ts.used());
+ check_results(reporter, line1, line2, ts);
+ if (line1[0] == line1[1] || line2[0] == line2[1]) {
+ return;
+ }
+ if (line1[0].fY == line1[1].fY) {
+ double left = SkTMin(line1[0].fX, line1[1].fX);
+ double right = SkTMax(line1[0].fX, line1[1].fX);
+ SkIntersections ts;
+ ts.horizontal(line2, left, right, line1[0].fY, line1[0].fX != left);
+ REPORTER_ASSERT(reporter, pts == 2);
+ REPORTER_ASSERT(reporter, pts == ts.used());
+ check_results(reporter, line2, line1, ts);
+ }
+ if (line2[0].fY == line2[1].fY) {
+ double left = SkTMin(line2[0].fX, line2[1].fX);
+ double right = SkTMax(line2[0].fX, line2[1].fX);
+ SkIntersections ts;
+ ts.horizontal(line1, left, right, line2[0].fY, line2[0].fX != left);
+ REPORTER_ASSERT(reporter, pts == 2);
+ REPORTER_ASSERT(reporter, pts == ts.used());
+ check_results(reporter, line1, line2, ts);
+ }
+ if (line1[0].fX == line1[1].fX) {
+ double top = SkTMin(line1[0].fY, line1[1].fY);
+ double bottom = SkTMax(line1[0].fY, line1[1].fY);
+ SkIntersections ts;
+ ts.vertical(line2, top, bottom, line1[0].fX, line1[0].fY != top);
+ REPORTER_ASSERT(reporter, pts == 2);
+ REPORTER_ASSERT(reporter, pts == ts.used());
+ check_results(reporter, line2, line1, ts);
+ }
+ if (line2[0].fX == line2[1].fX) {
+ double top = SkTMin(line2[0].fY, line2[1].fY);
+ double bottom = SkTMax(line2[0].fY, line2[1].fY);
+ SkIntersections ts;
+ ts.vertical(line1, top, bottom, line2[0].fX, line2[0].fY != top);
+ REPORTER_ASSERT(reporter, pts == 2);
+ REPORTER_ASSERT(reporter, pts == ts.used());
+ check_results(reporter, line1, line2, ts);
+ }
+ reporter->bumpTestCount();
+}
+
+DEF_TEST(PathOpsLineIntersection, reporter) {
+ size_t index;
+ for (index = 0; index < coincidentTests_count; ++index) {
+ const SkDLine& line1 = coincidentTests[index][0];
+ const SkDLine& line2 = coincidentTests[index][1];
+ testOneCoincident(reporter, line1, line2);
+ }
+ for (index = 0; index < tests_count; ++index) {
+ const SkDLine& line1 = tests[index][0];
+ const SkDLine& line2 = tests[index][1];
+ testOne(reporter, line1, line2);
+ }
+ for (index = 0; index < noIntersect_count; ++index) {
+ const SkDLine& line1 = noIntersect[index][0];
+ const SkDLine& line2 = noIntersect[index][1];
+ SkIntersections ts;
+ int pts = ts.intersect(line1, line2);
+ REPORTER_ASSERT(reporter, !pts);
+ REPORTER_ASSERT(reporter, pts == ts.used());
+ reporter->bumpTestCount();
+ }
+}
+
+DEF_TEST(PathOpsLineIntersectionOneOff, reporter) {
+ int index = 0;
+ SkASSERT(index < (int) tests_count);
+ testOne(reporter, tests[index][0], tests[index][1]);
+ testOne(reporter, tests[1][0], tests[1][1]);
+}
+
+DEF_TEST(PathOpsLineIntersectionOneCoincident, reporter) {
+ int index = 0;
+ SkASSERT(index < (int) coincidentTests_count);
+ const SkDLine& line1 = coincidentTests[index][0];
+ const SkDLine& line2 = coincidentTests[index][1];
+ testOneCoincident(reporter, line1, line2);
+}
diff --git a/src/third_party/skia/tests/PathOpsLineParametetersTest.cpp b/src/third_party/skia/tests/PathOpsLineParametetersTest.cpp
new file mode 100644
index 0000000..aab1f7a
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsLineParametetersTest.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkLineParameters.h"
+#include "Test.h"
+
+// tests to verify that distance calculations are coded correctly
+static const SkDCubic tests[] = {
+ {{{0, 0}, {1, 1}, {2, 2}, {0, 3}}},
+ {{{0, 0}, {1, 1}, {2, 2}, {3, 0}}},
+ {{{0, 0}, {5, 0}, {-2, 4}, {3, 4}}},
+ {{{0, 2}, {1, 0}, {2, 0}, {3, 0}}},
+ {{{0, .2}, {1, 0}, {2, 0}, {3, 0}}},
+ {{{0, .02}, {1, 0}, {2, 0}, {3, 0}}},
+ {{{0, .002}, {1, 0}, {2, 0}, {3, 0}}},
+ {{{0, .0002}, {1, 0}, {2, 0}, {3, 0}}},
+ {{{0, .00002}, {1, 0}, {2, 0}, {3, 0}}},
+ {{{0, FLT_EPSILON * 2}, {1, 0}, {2, 0}, {3, 0}}},
+};
+
+static const double answers[][2] = {
+ {1, 2},
+ {1, 2},
+ {4, 4},
+ {1.1094003924, 0.5547001962},
+ {0.133038021, 0.06651901052},
+ {0.0133330370, 0.006666518523},
+ {0.001333333037, 0.0006666665185},
+ {0.000133333333, 6.666666652e-05},
+ {1.333333333e-05, 6.666666667e-06},
+ {1.5894571940104115e-07, 7.9472859700520577e-08},
+};
+
+static const size_t tests_count = SK_ARRAY_COUNT(tests);
+
+DEF_TEST(PathOpsLineParameters, reporter) {
+ for (size_t index = 0; index < tests_count; ++index) {
+ SkLineParameters lineParameters;
+ const SkDCubic& cubic = tests[index];
+ SkASSERT(ValidCubic(cubic));
+ lineParameters.cubicEndPoints(cubic, 0, 3);
+ double denormalizedDistance[2];
+ denormalizedDistance[0] = lineParameters.controlPtDistance(cubic, 1);
+ denormalizedDistance[1] = lineParameters.controlPtDistance(cubic, 2);
+ double normalSquared = lineParameters.normalSquared();
+ size_t inner;
+ for (inner = 0; inner < 2; ++inner) {
+ double distSq = denormalizedDistance[inner];
+ distSq *= distSq;
+ double answersSq = answers[index][inner];
+ answersSq *= answersSq;
+ if (AlmostEqualUlps(distSq, normalSquared * answersSq)) {
+ continue;
+ }
+ SkDebugf("%s [%d,%d] denormalizedDistance:%g != answer:%g"
+ " distSq:%g answerSq:%g normalSquared:%g\n",
+ __FUNCTION__, static_cast<int>(index), (int)inner,
+ denormalizedDistance[inner], answers[index][inner],
+ distSq, answersSq, normalSquared);
+ }
+ lineParameters.normalize();
+ double normalizedDistance[2];
+ normalizedDistance[0] = lineParameters.controlPtDistance(cubic, 1);
+ normalizedDistance[1] = lineParameters.controlPtDistance(cubic, 2);
+ for (inner = 0; inner < 2; ++inner) {
+ if (AlmostEqualUlps(fabs(normalizedDistance[inner]), answers[index][inner])) {
+ continue;
+ }
+ SkDebugf("%s [%d,%d] normalizedDistance:%1.9g != answer:%g\n",
+ __FUNCTION__, static_cast<int>(index), (int)inner,
+ normalizedDistance[inner], answers[index][inner]);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsOpCubicThreadedTest.cpp b/src/third_party/skia/tests/PathOpsOpCubicThreadedTest.cpp
new file mode 100644
index 0000000..751ccc5
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsOpCubicThreadedTest.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsThreadedCommon.h"
+
+static void testOpCubicsMain(PathOpsThreadState* data) {
+#if DEBUG_SHOW_TEST_NAME
+ strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
+#endif
+ SkASSERT(data);
+ PathOpsThreadState& state = *data;
+ char pathStr[1024]; // gdb: set print elements 400
+ bool progress = state.fReporter->verbose(); // FIXME: break out into its own parameter?
+ if (progress) {
+ sk_bzero(pathStr, sizeof(pathStr));
+ }
+ for (int a = 0 ; a < 6; ++a) {
+ for (int b = a + 1 ; b < 7; ++b) {
+ for (int c = 0 ; c < 6; ++c) {
+ for (int d = c + 1 ; d < 7; ++d) {
+ for (int e = SkPath::kWinding_FillType ; e <= SkPath::kEvenOdd_FillType; ++e) {
+ for (int f = SkPath::kWinding_FillType ; f <= SkPath::kEvenOdd_FillType; ++f) {
+ SkPath pathA, pathB;
+ if (progress) {
+ char* str = pathStr;
+ str += sprintf(str, " path.setFillType(SkPath::k%s_FillType);\n",
+ e == SkPath::kWinding_FillType ? "Winding" : e == SkPath::kEvenOdd_FillType
+ ? "EvenOdd" : "?UNDEFINED");
+ str += sprintf(str, " path.moveTo(%d,%d);\n", state.fA, state.fB);
+ str += sprintf(str, " path.cubicTo(%d,%d, %d,%d, %d,%d);\n", state.fC, state.fD,
+ b, a, d, c);
+ str += sprintf(str, " path.close();\n");
+ str += sprintf(str, " pathB.setFillType(SkPath::k%s_FillType);\n",
+ f == SkPath::kWinding_FillType ? "Winding" : f == SkPath::kEvenOdd_FillType
+ ? "EvenOdd" : "?UNDEFINED");
+ str += sprintf(str, " pathB.moveTo(%d,%d);\n", a, b);
+ str += sprintf(str, " pathB.cubicTo(%d,%d, %d,%d, %d,%d);\n", c, d,
+ state.fB, state.fA, state.fD, state.fC);
+ str += sprintf(str, " pathB.close();\n");
+ }
+ pathA.setFillType((SkPath::FillType) e);
+ pathA.moveTo(SkIntToScalar(state.fA), SkIntToScalar(state.fB));
+ pathA.cubicTo(SkIntToScalar(state.fC), SkIntToScalar(state.fD), SkIntToScalar(b),
+ SkIntToScalar(a), SkIntToScalar(d), SkIntToScalar(c));
+ pathA.close();
+ pathB.setFillType((SkPath::FillType) f);
+ pathB.moveTo(SkIntToScalar(a), SkIntToScalar(b));
+ pathB.cubicTo(SkIntToScalar(c), SkIntToScalar(d), SkIntToScalar(state.fB),
+ SkIntToScalar(state.fA), SkIntToScalar(state.fD), SkIntToScalar(state.fC));
+ pathB.close();
+ for (int op = 0 ; op <= kXOR_PathOp; ++op) {
+ if (progress) {
+ outputProgress(state.fPathStr, pathStr, (SkPathOp) op);
+ }
+ testThreadedPathOp(state.fReporter, pathA, pathB, (SkPathOp) op, "cubics");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+DEF_TEST(PathOpsOpCubicsThreaded, reporter) {
+ initializeTests(reporter, "cubicOp");
+ PathOpsThreadedTestRunner testRunner(reporter);
+ for (int a = 0; a < 6; ++a) { // outermost
+ for (int b = a + 1; b < 7; ++b) {
+ for (int c = 0 ; c < 6; ++c) {
+ for (int d = c + 1; d < 7; ++d) {
+ *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
+ (&testOpCubicsMain, a, b, c, d, &testRunner));
+ }
+ }
+ if (!reporter->allowExtendedTest()) goto finish;
+ }
+ }
+finish:
+ testRunner.render();
+ ShowTestArray();
+}
diff --git a/src/third_party/skia/tests/PathOpsOpLoopThreadedTest.cpp b/src/third_party/skia/tests/PathOpsOpLoopThreadedTest.cpp
new file mode 100755
index 0000000..c50e23b
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsOpLoopThreadedTest.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsThreadedCommon.h"
+
+static void testOpLoopsMain(PathOpsThreadState* data) {
+#if DEBUG_SHOW_TEST_NAME
+ strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
+#endif
+ SkASSERT(data);
+ PathOpsThreadState& state = *data;
+ char pathStr[1024]; // gdb: set print elements 400
+ bool progress = state.fReporter->verbose(); // FIXME: break out into its own parameter?
+ if (progress) {
+ sk_bzero(pathStr, sizeof(pathStr));
+ }
+ for (int a = 0 ; a < 6; ++a) {
+ for (int b = a + 1 ; b < 7; ++b) {
+ for (int c = 0 ; c < 6; ++c) {
+ for (int d = c + 1 ; d < 7; ++d) {
+ // define 4 points that form two lines that often cross; one line is (a, b) (c, d)
+ SkVector v = {SkIntToScalar(a - c), SkIntToScalar(b - d)};
+ SkPoint midA = { SkIntToScalar(a * state.fA + c * (6 - state.fA)) / 6,
+ SkIntToScalar(b * state.fA + d * (6 - state.fA)) / 6 };
+ SkPoint midB = { SkIntToScalar(a * state.fB + c * (6 - state.fB)) / 6,
+ SkIntToScalar(b * state.fB + d * (6 - state.fB)) / 6 };
+ SkPoint endC = { midA.fX + v.fY * state.fC / 3,
+ midA.fY + v.fX * state.fC / 3 };
+ SkPoint endD = { midB.fX - v.fY * state.fD / 3,
+ midB.fY + v.fX * state.fD / 3 };
+ SkPath pathA, pathB;
+ if (progress) {
+ char* str = pathStr;
+ str += sprintf(str, " path.moveTo(%d,%d);\n", a, b);
+ str += sprintf(str, " path.cubicTo(%d,%d, %1.9gf,%1.9gf, %1.9gf,%1.9gf);\n",
+ c, d, endC.fX, endC.fY, endD.fX, endD.fY);
+ str += sprintf(str, " path.close();\n");
+ str += sprintf(str, " pathB.moveTo(%d,%d);\n", c, d);
+ str += sprintf(str, " pathB.cubicTo(%1.9gf,%1.9gf, %1.9gf,%1.9gf, %d,%d);\n",
+ endC.fX, endC.fY, endD.fX, endD.fY, a, b);
+ str += sprintf(str, " pathB.close();\n");
+ }
+ pathA.moveTo(SkIntToScalar(a), SkIntToScalar(b));
+ pathA.cubicTo(SkIntToScalar(c), SkIntToScalar(d), endC.fX, endC.fY, endD.fX, endD.fY);
+ pathA.close();
+ pathB.moveTo(SkIntToScalar(c), SkIntToScalar(d));
+ pathB.cubicTo(endC.fX, endC.fY, endD.fX, endD.fY, SkIntToScalar(a), SkIntToScalar(b));
+ pathB.close();
+// SkDebugf("%s\n", pathStr);
+ if (progress) {
+ outputProgress(state.fPathStr, pathStr, kIntersect_PathOp);
+ }
+ testThreadedPathOp(state.fReporter, pathA, pathB, kIntersect_PathOp, "loops");
+ }
+ }
+ }
+ }
+}
+
+DEF_TEST(PathOpsOpLoopsThreaded, reporter) {
+ if (!FLAGS_runFail) {
+ return;
+ }
+ initializeTests(reporter, "cubicOp");
+ PathOpsThreadedTestRunner testRunner(reporter);
+ for (int a = 0; a < 6; ++a) { // outermost
+ for (int b = a + 1; b < 7; ++b) {
+ for (int c = 0 ; c < 6; ++c) {
+ for (int d = c + 1; d < 7; ++d) {
+ *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
+ (&testOpLoopsMain, a, b, c, d, &testRunner));
+ }
+ }
+ if (!reporter->allowExtendedTest()) goto finish;
+ }
+ }
+finish:
+ testRunner.render();
+ ShowTestArray();
+}
+
+DEF_TEST(PathOpsOpLoops, reporter) {
+ if (!FLAGS_runFail) {
+ return;
+ }
+ initializeTests(reporter, "cubicOp");
+ PathOpsThreadState state;
+ state.fReporter = reporter;
+ SkBitmap bitmap;
+ state.fBitmap = &bitmap;
+ char pathStr[PATH_STR_SIZE];
+ state.fPathStr = pathStr;
+ for (state.fA = 0; state.fA < 6; ++state.fA) { // outermost
+ for (state.fB = state.fA + 1; state.fB < 7; ++state.fB) {
+ for (state.fC = 0 ; state.fC < 6; ++state.fC) {
+ for (state.fD = state.fC + 1; state.fD < 7; ++state.fD) {
+ testOpLoopsMain(&state);
+ }
+ }
+ if (!reporter->allowExtendedTest()) goto finish;
+ }
+ }
+finish:
+ ShowTestArray();
+}
diff --git a/src/third_party/skia/tests/PathOpsOpRectThreadedTest.cpp b/src/third_party/skia/tests/PathOpsOpRectThreadedTest.cpp
new file mode 100644
index 0000000..1b6e4e8
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsOpRectThreadedTest.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsThreadedCommon.h"
+
+// four rects, of four sizes
+// for 3 smaller sizes, tall, wide
+ // top upper mid lower bottom aligned (3 bits, 5 values)
+ // same with x (3 bits, 5 values)
+// not included, square, tall, wide (2 bits)
+// cw or ccw (1 bit)
+
+static void testPathOpsRectsMain(PathOpsThreadState* data)
+{
+ SkASSERT(data);
+ PathOpsThreadState& state = *data;
+ char pathStr[1024]; // gdb: set print elements 400
+ bool progress = state.fReporter->verbose(); // FIXME: break out into its own parameter?
+ if (progress) {
+ sk_bzero(pathStr, sizeof(pathStr));
+ }
+ for (int a = 0 ; a < 6; ++a) {
+ for (int b = a + 1 ; b < 7; ++b) {
+ for (int c = 0 ; c < 6; ++c) {
+ for (int d = c + 1 ; d < 7; ++d) {
+ for (int e = SkPath::kWinding_FillType ; e <= SkPath::kEvenOdd_FillType; ++e) {
+ for (int f = SkPath::kWinding_FillType ; f <= SkPath::kEvenOdd_FillType; ++f) {
+ if (progress) {
+ char* str = pathStr;
+ str += sprintf(str, " path.setFillType(SkPath::k%s_FillType);\n",
+ e == SkPath::kWinding_FillType ? "Winding" : e == SkPath::kEvenOdd_FillType
+ ? "EvenOdd" : "?UNDEFINED");
+ str += sprintf(str, " path.addRect(%d, %d, %d, %d,"
+ " SkPath::kCW_Direction);\n", state.fA, state.fA, state.fB, state.fB);
+ str += sprintf(str, " path.addRect(%d, %d, %d, %d,"
+ " SkPath::kCW_Direction);\n", state.fC, state.fC, state.fD, state.fD);
+ str += sprintf(str, " pathB.setFillType(SkPath::k%s_FillType);\n",
+ f == SkPath::kWinding_FillType ? "Winding" : f == SkPath::kEvenOdd_FillType
+ ? "EvenOdd" : "?UNDEFINED");
+ str += sprintf(str, " pathB.addRect(%d, %d, %d, %d,"
+ " SkPath::kCW_Direction);\n", a, a, b, b);
+ str += sprintf(str, " pathB.addRect(%d, %d, %d, %d,"
+ " SkPath::kCW_Direction);\n", c, c, d, d);
+ }
+ SkPath pathA, pathB;
+ pathA.setFillType((SkPath::FillType) e);
+ pathA.addRect(SkIntToScalar(state.fA), SkIntToScalar(state.fA), SkIntToScalar(state.fB),
+ SkIntToScalar(state.fB), SkPath::kCW_Direction);
+ pathA.addRect(SkIntToScalar(state.fC), SkIntToScalar(state.fC), SkIntToScalar(state.fD),
+ SkIntToScalar(state.fD), SkPath::kCW_Direction);
+ pathA.close();
+ pathB.setFillType((SkPath::FillType) f);
+ pathB.addRect(SkIntToScalar(a), SkIntToScalar(a), SkIntToScalar(b),
+ SkIntToScalar(b), SkPath::kCW_Direction);
+ pathB.addRect(SkIntToScalar(c), SkIntToScalar(c), SkIntToScalar(d),
+ SkIntToScalar(d), SkPath::kCW_Direction);
+ pathB.close();
+ for (int op = 0 ; op <= kXOR_PathOp; ++op) {
+ if (progress) {
+ outputProgress(state.fPathStr, pathStr, (SkPathOp) op);
+ }
+ testThreadedPathOp(state.fReporter, pathA, pathB, (SkPathOp) op, "rects");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+DEF_TEST(PathOpsRectsThreaded, reporter) {
+ initializeTests(reporter, "testOp");
+ PathOpsThreadedTestRunner testRunner(reporter);
+ for (int a = 0; a < 6; ++a) { // outermost
+ for (int b = a + 1; b < 7; ++b) {
+ for (int c = 0 ; c < 6; ++c) {
+ for (int d = c + 1; d < 7; ++d) {
+ *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
+ (&testPathOpsRectsMain, a, b, c, d, &testRunner));
+ }
+ }
+ if (!reporter->allowExtendedTest()) goto finish;
+ }
+ }
+finish:
+ testRunner.render();
+}
diff --git a/src/third_party/skia/tests/PathOpsOpTest.cpp b/src/third_party/skia/tests/PathOpsOpTest.cpp
new file mode 100644
index 0000000..7ca15e1
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsOpTest.cpp
@@ -0,0 +1,5612 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsTestCommon.h"
+
+#define TEST(name) { name, #name }
+
+static void cubicOp1d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,2, 1,0, 1,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(0,1, 1,0, 2,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp2d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(0,1, 1,0, 1,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(0,1, 2,0, 1,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp3d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,3, 1,0, 1,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(0,1, 1,0, 3,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp5d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,2, 1,0, 2,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(0,2, 1,0, 2,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp6d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,6, 1,0, 3,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(0,3, 1,0, 6,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp7d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,4, 1,0, 3,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(0,3, 1,0, 4,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp8d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,5, 1,0, 4,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(0,4, 1,0, 5,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp9d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,6, 1,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(1,2, 1,0, 6,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void quadOp9d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.quadTo(1,6, 1.5f,1);
+ path.quadTo(1.5f,0.5f, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.quadTo(1,2, 1.4f,1);
+ pathB.quadTo(3,0.4f, 6,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void lineOp9d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.lineTo(1,6);
+ path.lineTo(1.5f,1);
+ path.lineTo(1.8f,0.8f);
+ path.lineTo(2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.lineTo(1,2);
+ pathB.lineTo(1.4f,1);
+ pathB.lineTo(3,0.4f);
+ pathB.lineTo(6,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp1i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,2, 1,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(1,2, 1,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp10d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,3, 1,0, 4,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(1,4, 1,0, 3,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp11d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,4, 1,0, 5,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(1,5, 1,0, 4,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp12d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,6, 1,0, 1,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(0,1, 1,0, 6,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp13d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(4,5, 1,0, 5,3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(3,5, 1,0, 5,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp14d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,2, 2,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,2);
+ pathB.cubicTo(1,2, 1,0, 2,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp15d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,6, 2,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,2);
+ pathB.cubicTo(1,2, 1,0, 6,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp16d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(0,1, 3,0, 1,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,3);
+ pathB.cubicTo(0,1, 2,0, 1,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp17d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(0,2, 4,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,4);
+ pathB.cubicTo(1,2, 2,0, 2,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp18d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,5, 2,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,2);
+ pathB.cubicTo(1,2, 1,0, 5,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp19i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(0,1, 2,1, 6,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(2,6, 2,0, 1,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp20d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,1, 6,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(1,2, 1,0, 1,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp21d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,1, 2,1, 6,5);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(5,6, 1,0, 1,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp22d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,3, 3,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,3);
+ pathB.cubicTo(1,2, 1,0, 3,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp23d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,2, 4,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,4);
+ pathB.cubicTo(1,2, 1,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp24d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,2, 2,0, 3,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,2);
+ pathB.cubicTo(2,3, 1,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void testIntersect1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath one, two;
+ one.addRect(0, 0, 6, 6, SkPath::kCW_Direction);
+ two.addRect(3, 3, 9, 9, SkPath::kCW_Direction);
+ testPathOp(reporter, one, two, kIntersect_PathOp, filename);
+}
+
+static void testUnion1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath one, two;
+ one.addRect(0, 0, 6, 6, SkPath::kCW_Direction);
+ two.addRect(3, 3, 9, 9, SkPath::kCW_Direction);
+ testPathOp(reporter, one, two, kUnion_PathOp, filename);
+}
+
+static void testDiff1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath one, two;
+ one.addRect(0, 0, 6, 6, SkPath::kCW_Direction);
+ two.addRect(3, 3, 9, 9, SkPath::kCW_Direction);
+ testPathOp(reporter, one, two, kDifference_PathOp, filename);
+}
+
+static void testXor1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath one, two;
+ one.addRect(0, 0, 6, 6, SkPath::kCW_Direction);
+ two.addRect(3, 3, 9, 9, SkPath::kCW_Direction);
+ testPathOp(reporter, one, two, kXOR_PathOp, filename);
+}
+
+static void testIntersect2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath one, two;
+ one.addRect(0, 0, 6, 6, SkPath::kCW_Direction);
+ two.addRect(0, 3, 9, 9, SkPath::kCW_Direction);
+ testPathOp(reporter, one, two, kIntersect_PathOp, filename);
+}
+
+static void testUnion2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath one, two;
+ one.addRect(0, 0, 6, 6, SkPath::kCW_Direction);
+ two.addRect(0, 3, 9, 9, SkPath::kCW_Direction);
+ testPathOp(reporter, one, two, kUnion_PathOp, filename);
+}
+
+static void testDiff2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath one, two;
+ one.addRect(0, 0, 6, 6, SkPath::kCW_Direction);
+ two.addRect(0, 3, 9, 9, SkPath::kCW_Direction);
+ testPathOp(reporter, one, two, kDifference_PathOp, filename);
+}
+
+static void testXor2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath one, two;
+ one.addRect(0, 0, 6, 6, SkPath::kCW_Direction);
+ two.addRect(0, 3, 9, 9, SkPath::kCW_Direction);
+ testPathOp(reporter, one, two, kXOR_PathOp, filename);
+}
+
+static void testOp1d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void testOp2d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void testOp3d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(1, 1, 2, 2, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void testOp1u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(0, 0, 3, 3, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void testOp4d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(2, 2, 4, 4, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void testOp5d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ path.addRect(0, 0, 3, 3, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void testOp6d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(0, 0, 3, 3, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void testOp7d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void testOp2u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ path.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addRect(0, 0, 3, 3, SkPath::kCW_Direction);
+ pathB.addRect(1, 1, 2, 2, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void testOp8d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.addRect(0, 0, 640, 480);
+ pathB.moveTo(577330, 1971.72f);
+ pathB.cubicTo(10.7082f, -116.596f, 262.057f, 45.6468f, 294.694f, 1.96237f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+static void cubicOp25i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,4, 5,0, 3,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,5);
+ pathB.cubicTo(2,3, 1,0, 4,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp26d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,4, 4,0, 3,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,4);
+ pathB.cubicTo(2,3, 1,0, 4,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp27d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,6, 1,0, 5,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(2,5, 1,0, 6,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp28u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,4, 6,0, 3,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(2,3, 1,0, 4,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp29d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,5, 6,0, 4,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(2,4, 1,0, 5,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp30d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,5, 6,0, 5,3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(3,5, 1,0, 5,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp31d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(0,3, 2,1, 4,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(0,4, 2,0, 3,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp31u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(0,3, 2,1, 4,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(0,4, 2,0, 3,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp31x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(0,3, 2,1, 4,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(0,4, 2,0, 3,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kXOR_PathOp, filename);
+}
+
+static void cubicOp32d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,2, 6,0, 3,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(1,3, 1,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp33i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,2, 6,0, 3,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(1,3, 1,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp34d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,5, 2,1, 3,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(1,3, 1,0, 5,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp35d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,5, 2,1, 4,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(0,4, 1,0, 5,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp36u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,6, 2,0, 5,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,2);
+ pathB.cubicTo(1,5, 1,0, 6,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp37d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,6, 6,1, 4,3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,6);
+ pathB.cubicTo(3,4, 1,0, 6,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+// this fails to detect a cubic/cubic intersection
+// the slight overlap is missed when the cubics are approximated by quadratics
+// and the subsequent line/cubic intersection also (correctly) misses the intersection
+// if the line/cubic was a matching line/approx.quadratic then the missing intersection
+// could have been detected
+static void cubicOp38d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,6, 3,2, 4,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,3);
+ pathB.cubicTo(1,4, 1,0, 6,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp39d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,3, 5,1, 4,3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,5);
+ pathB.cubicTo(3,4, 1,0, 3,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp40d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,5, 3,2, 4,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,3);
+ pathB.cubicTo(2,4, 1,0, 5,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp41i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,6, 4,3, 6,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3,4);
+ pathB.cubicTo(4,6, 1,0, 6,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp42d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,2, 6,5, 5,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(5,6);
+ pathB.cubicTo(4,5, 1,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp43d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(1,2, 4,0, 3,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,4);
+ pathB.cubicTo(1,3, 2,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp44d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(3,6, 4,0, 3,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,4);
+ pathB.cubicTo(2,3, 2,0, 6,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp45d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(2,4, 4,0, 3,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,4);
+ pathB.cubicTo(2,3, 2,0, 4,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp46d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(3,5, 5,0, 4,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,5);
+ pathB.cubicTo(2,4, 2,0, 5,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp47d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,6, 6,2, 5,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,6);
+ pathB.cubicTo(4,5, 1,0, 6,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp48d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(2,3, 5,1, 3,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,5);
+ pathB.cubicTo(2,3, 2,0, 3,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp49d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(1,5, 3,2, 4,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,3);
+ pathB.cubicTo(1,4, 2,0, 5,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp50d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,3);
+ path.cubicTo(1,6, 5,0, 5,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,5);
+ pathB.cubicTo(1,5, 3,0, 6,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp51d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,3);
+ path.cubicTo(1,2, 4,1, 6,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,4);
+ pathB.cubicTo(0,6, 3,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp52d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(1,2, 5,4, 4,3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(4,5);
+ pathB.cubicTo(3,4, 2,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp53d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,3);
+ path.cubicTo(1,2, 5,3, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3,5);
+ pathB.cubicTo(1,2, 3,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp54d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,4);
+ path.cubicTo(1,3, 5,4, 4,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(4,5);
+ pathB.cubicTo(2,4, 4,0, 3,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp55d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,5);
+ path.cubicTo(1,3, 3,2, 5,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,3);
+ pathB.cubicTo(0,5, 5,0, 3,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp56d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,6, 5,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,5);
+ pathB.cubicTo(1,2, 1,0, 6,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp57d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,5);
+ path.cubicTo(0,5, 5,4, 6,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(4,5);
+ pathB.cubicTo(4,6, 5,0, 5,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp58d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,5);
+ path.cubicTo(3,4, 6,5, 5,3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(5,6);
+ pathB.cubicTo(3,5, 5,0, 4,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp59d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(5,6, 4,0, 4,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,4);
+ pathB.cubicTo(1,4, 1,0, 6,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp60d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(4,6, 6,0, 5,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(2,5, 2,0, 6,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp61d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1,2);
+ path.cubicTo(0,5, 3,2, 6,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,3);
+ pathB.cubicTo(1,6, 2,1, 5,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp62d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1,3);
+ path.cubicTo(5,6, 5,3, 5,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3,5);
+ pathB.cubicTo(4,5, 3,1, 6,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp63d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2,3);
+ path.cubicTo(0,4, 3,2, 5,3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,3);
+ pathB.cubicTo(3,5, 3,2, 4,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp64d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,1);
+ path.cubicTo(0,1, 1,0, 3,0);
+ path.lineTo(0,1);
+ path.close();
+ pathB.moveTo(0,1);
+ pathB.cubicTo(0,3, 1,0, 1,0);
+ pathB.lineTo(0,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp65d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,1);
+ path.cubicTo(1,5, 1,0, 1,0);
+ path.lineTo(0,1);
+ path.close();
+ pathB.moveTo(0,1);
+ pathB.cubicTo(0,1, 1,0, 5,1);
+ pathB.lineTo(0,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void rectOp1d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,1);
+ path.cubicTo(0,1, 1,0, 3,0);
+ path.lineTo(0,1);
+ path.close();
+ pathB.moveTo(0,1);
+ pathB.cubicTo(0,3, 1,0, 1,0);
+ pathB.lineTo(0,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp66u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,6, 4,2, 5,3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,4);
+ pathB.cubicTo(3,5, 1,0, 6,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp67u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(3,5);
+ path.cubicTo(1,6, 5,0, 3,1);
+ path.lineTo(3,5);
+ path.close();
+ pathB.moveTo(0,5);
+ pathB.cubicTo(1,3, 5,3, 6,1);
+ pathB.lineTo(0,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp68u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,5);
+ path.cubicTo(4,5, 4,1, 5,0);
+ path.close();
+ pathB.moveTo(1,4);
+ pathB.cubicTo(0,5, 5,0, 5,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp69d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(1,3);
+ path.cubicTo(0,1, 3,1, 2,0);
+ path.close();
+ pathB.moveTo(1,3);
+ pathB.cubicTo(0,2, 3,1, 1,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+SkPathOp ops[] = {
+ kUnion_PathOp,
+ kXOR_PathOp,
+ kReverseDifference_PathOp,
+ kXOR_PathOp,
+ kReverseDifference_PathOp,
+};
+
+static void rRect1(skiatest::Reporter* reporter, const char* filename) {
+ SkScalar xA = 0.65f;
+ SkScalar xB = 10.65f;
+ SkScalar xC = 20.65f;
+ SkScalar xD = 30.65f;
+ SkScalar xE = 40.65f;
+ SkScalar xF = 50.65f;
+
+ SkScalar yA = 0.65f;
+ SkScalar yB = 10.65f;
+ SkScalar yC = 20.65f;
+ SkScalar yD = 30.65f;
+ SkScalar yE = 40.65f;
+ SkScalar yF = 50.65f;
+ SkPath paths[5];
+ SkRect rects[5];
+ rects[0].set(xB, yB, xE, yE);
+ paths[0].addRoundRect(rects[0], SkIntToScalar(5), SkIntToScalar(5)); // red
+ rects[1].set(xA, yA, xD, yD);
+ paths[1].addRoundRect(rects[1], SkIntToScalar(5), SkIntToScalar(5)); // green
+ rects[2].set(xC, yA, xF, yD);
+ paths[2].addRoundRect(rects[2], SkIntToScalar(5), SkIntToScalar(5)); // blue
+ rects[3].set(xA, yC, xD, yF);
+ paths[3].addRoundRect(rects[3], SkIntToScalar(5), SkIntToScalar(5)); // yellow
+ rects[4].set(xC, yC, xF, yF);
+ paths[4].addRoundRect(rects[4], SkIntToScalar(5), SkIntToScalar(5)); // cyan
+ SkPath path;
+ path.setFillType(SkPath::kInverseEvenOdd_FillType);
+ for (int index = 0; index < 5; ++index) {
+ testPathOp(reporter, path, paths[index], ops[index], filename);
+ Op(path, paths[index], ops[index], &path);
+ }
+}
+
+static void skp1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(189,7);
+ path.cubicTo(189,5.34314585f, 190.34314f,4, 192,4);
+ path.lineTo(243,4);
+ path.cubicTo(244.65686f,4, 246,5.34314585f, 246,7);
+ path.lineTo(246,21);
+ path.cubicTo(246,22.6568546f, 244.65686f,24, 243,24);
+ path.lineTo(192,24);
+ path.cubicTo(190.34314f,24, 189,22.6568546f, 189,21);
+ path.lineTo(189,7);
+ path.close();
+ path.moveTo(191,8);
+ path.cubicTo(191,6.89543009f, 191.895432f,6, 193,6);
+ path.lineTo(242,6);
+ path.cubicTo(243.104568f,6, 244,6.89543009f, 244,8);
+ path.lineTo(244,20);
+ path.cubicTo(244,21.1045704f, 243.104568f,22, 242,22);
+ path.lineTo(193,22);
+ path.cubicTo(191.895432f,22, 191,21.1045704f, 191,20);
+ path.lineTo(191,8);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(189,4);
+ pathB.lineTo(199,14);
+ pathB.lineTo(236,14);
+ pathB.lineTo(246,4);
+ pathB.lineTo(189,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skp2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(253.000000f, 11757.0000f);
+ path.lineTo(253.000000f, 222.000000f);
+ path.lineTo(823.000000f, 222.000000f);
+ path.lineTo(823.000000f, 11757.0000f);
+ path.lineTo(253.000000f, 11757.0000f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(258.000000f, 1028.00000f);
+ pathB.lineTo(258.000000f, 1027.00000f);
+ pathB.lineTo(823.000000f, 1027.00000f);
+ pathB.lineTo(823.000000f, 1028.00000f);
+ pathB.lineTo(258.000000f, 1028.00000f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skp3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(717.000000f, 507.000000f);
+ path.lineTo(717.000000f, 425.000000f);
+ path.lineTo(973.000000f, 425.000000f);
+ path.lineTo(973.000000f, 507.000000f);
+ path.quadTo(973.000000f, 508.242645f, 972.121582f, 509.121613f);
+ path.quadTo(971.242615f, 510.000000f, 970.000000f, 510.000000f);
+ path.lineTo(720.000000f, 510.000000f);
+ path.quadTo(718.757385f, 510.000000f, 717.878418f, 509.121613f);
+ path.quadTo(717.000000f, 508.242645f, 717.000000f, 507.000000f);
+ path.close();
+ path.moveTo(719.000000f, 426.000000f);
+ path.lineTo(971.000000f, 426.000000f);
+ path.lineTo(971.000000f, 506.000000f);
+ path.cubicTo(971.000000f, 507.104584f, 970.104553f, 508.000000f, 969.000000f, 508.000000f);
+ path.lineTo(721.000000f, 508.000000f);
+ path.cubicTo(719.895447f, 508.000000f, 719.000000f, 507.104584f, 719.000000f, 506.000000f);
+ path.lineTo(719.000000f, 426.000000f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(717.000000f, 510.000000f);
+ pathB.lineTo(760.000000f, 467.000000f);
+ pathB.lineTo(930.000000f, 467.000000f);
+ pathB.lineTo(973.000000f, 510.000000f);
+ pathB.lineTo(717.000000f, 510.000000f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skp4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(230.756805f, 591.756775f);
+ path.quadTo(232.514725f, 590.000000f, 235.000000f, 590.000000f);
+ path.lineTo(300.000000f, 590.000000f);
+ path.quadTo(302.485291f, 590.000000f, 304.243195f, 591.756775f);
+ path.quadTo(306.000000f, 593.514709f, 306.000000f, 596.000000f);
+ path.lineTo(306.000000f, 617.000000f);
+ path.lineTo(229.000000f, 617.000000f);
+ path.lineTo(229.000000f, 596.000000f);
+ path.quadTo(229.000000f, 593.514709f, 230.756805f, 591.756775f);
+ path.close();
+ path.moveTo(231.000000f, 597.000000f);
+ path.cubicTo(231.000000f, 594.238586f, 233.238571f, 592.000000f, 236.000000f, 592.000000f);
+ path.lineTo(299.000000f, 592.000000f);
+ path.cubicTo(301.761414f, 592.000000f, 304.000000f, 594.238586f, 304.000000f, 597.000000f);
+ path.lineTo(304.000000f, 616.000000f);
+ path.lineTo(231.000000f, 616.000000f);
+ path.lineTo(231.000000f, 597.000000f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(306.000000f, 590.000000f);
+ pathB.lineTo(292.000000f, 604.000000f);
+ pathB.lineTo(305.000000f, 617.000000f);
+ pathB.lineTo(306.000000f, 617.000000f);
+ pathB.lineTo(306.000000f, 590.000000f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skp5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(18.0000000f, 226.000000f);
+ path.quadTo(14.6862917f, 226.000000f, 12.3423996f, 228.342407f);
+ path.quadTo(10.0000000f, 230.686295f, 10.0000000f, 234.000000f);
+ path.lineTo(10.0000000f, 253.000000f);
+ path.lineTo(1247.00000f, 253.000000f);
+ path.lineTo(1247.00000f, 234.000000f);
+ path.quadTo(1247.00000f, 230.686295f, 1244.65759f, 228.342407f);
+ path.quadTo(1242.31372f, 226.000000f, 1239.00000f, 226.000000f);
+ path.lineTo(18.0000000f, 226.000000f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(18.0000000f, 226.000000f);
+ pathB.lineTo(1239.00000f, 226.000000f);
+ pathB.cubicTo(1243.41833f, 226.000000f, 1247.00000f, 229.581726f, 1247.00000f, 234.000000f);
+ pathB.lineTo(1247.00000f, 252.000000f);
+ pathB.lineTo(10.0000000f, 252.000000f);
+ pathB.lineTo(10.0000000f, 234.000000f);
+ pathB.cubicTo(10.0000000f, 229.581726f, 13.5817204f, 226.000000f, 18.0000000f, 226.000000f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp70d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,5, 4,0, 5,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,4);
+ pathB.cubicTo(0,5, 1,0, 5,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp71d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,5, 4,1, 6,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,4);
+ pathB.cubicTo(4,6, 1,0, 5,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp72i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,5, 5,2, 5,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,5);
+ pathB.cubicTo(4,5, 1,0, 5,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp73d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,4, 4,0, 6,4);
+ path.lineTo(0,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,4);
+ pathB.cubicTo(4,6, 1,0, 4,3);
+ pathB.lineTo(0,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp74d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,5, 5,1, 5,1);
+ path.lineTo(0,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,5);
+ pathB.cubicTo(1,5, 1,0, 5,1);
+ pathB.lineTo(1,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp75d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,4, 5,1, 6,4);
+ path.lineTo(0,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,5);
+ pathB.cubicTo(4,6, 1,0, 4,0);
+ pathB.lineTo(1,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp76u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,2, 2,0, 5,3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,2);
+ pathB.cubicTo(3,5, 1,0, 2,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp77i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,3, 2,0, 3,2);
+ path.lineTo(0,1);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(0,2);
+ pathB.cubicTo(2,3, 1,0, 3,1);
+ pathB.lineTo(0,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp78u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1,6);
+ path.cubicTo(1,6, 5,0, 6,1);
+ path.lineTo(1,6);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(0,5);
+ pathB.cubicTo(1,6, 6,1, 6,1);
+ pathB.lineTo(0,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp79u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,3, 1,0, 6,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(4,6, 1,0, 3,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp80i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,3, 2,1, 4,3);
+ path.lineTo(0,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(3,4, 1,0, 3,2);
+ pathB.lineTo(1,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp81d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(4,6, 4,3, 5,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3,4);
+ pathB.cubicTo(4,5, 1,0, 6,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp82i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,3, 5,2, 3,0);
+ path.lineTo(0,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,5);
+ pathB.cubicTo(0,3, 1,0, 3,2);
+ pathB.lineTo(2,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp83i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,3, 2,1, 4,1);
+ path.lineTo(0,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(1,4, 1,0, 3,0);
+ pathB.lineTo(1,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp84d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,4);
+ path.cubicTo(2,3, 6,3, 3,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3,6);
+ pathB.cubicTo(2,3, 4,0, 3,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void skpClip1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1126.17114f, 877.171204f);
+ path.quadTo(1127.34314f, 876.000000f, 1129.00000f, 876.000000f);
+ path.lineTo(1243.00000f, 876.000000f);
+ path.quadTo(1244.65686f, 876.000000f, 1245.82886f, 877.171204f);
+ path.quadTo(1247.00000f, 878.343140f, 1247.00000f, 880.000000f);
+ path.lineTo(1247.00000f, 907.000000f);
+ path.lineTo(1246.00000f, 907.000000f);
+ path.lineTo(1246.00000f, 880.000000f);
+ path.cubicTo(1246.00000f, 878.343140f, 1244.65686f, 877.000000f, 1243.00000f, 877.000000f);
+ path.lineTo(1129.00000f, 877.000000f);
+ path.cubicTo(1127.34314f, 877.000000f, 1126.00000f, 878.343140f, 1126.00000f, 880.000000f);
+ path.lineTo(1126.00000f, 907.000000f);
+ path.lineTo(1125.00000f, 907.000000f);
+ path.lineTo(1125.00000f, 880.000000f);
+ path.quadTo(1125.00000f, 878.343140f, 1126.17114f, 877.171204f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1247.00000f, 876.000000f);
+ pathB.lineTo(1231.00000f, 892.000000f);
+ pathB.lineTo(1246.00000f, 907.000000f);
+ pathB.lineTo(1247.00000f, 907.000000f);
+ pathB.lineTo(1247.00000f, 876.000000f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpClip2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(134.000000f, 11414.0000f);
+ path.cubicTo(131.990234f, 11414.0000f, 130.326660f, 11415.4824f, 130.042755f, 11417.4131f);
+ path.cubicTo(130.233124f, 11418.3193f, 131.037079f, 11419.0000f, 132.000000f, 11419.0000f);
+ path.lineTo(806.000000f, 11419.0000f);
+ path.cubicTo(806.962891f, 11419.0000f, 807.766907f, 11418.3193f, 807.957275f, 11417.4131f);
+ path.cubicTo(807.673401f, 11415.4824f, 806.009766f, 11414.0000f, 804.000000f, 11414.0000f);
+ path.lineTo(134.000000f, 11414.0000f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(132.000000f, 11415.0000f);
+ pathB.lineTo(806.000000f, 11415.0000f);
+ pathB.cubicTo(807.104553f, 11415.0000f, 808.000000f, 11415.4473f, 808.000000f, 11416.0000f);
+ pathB.lineTo(808.000000f, 11417.0000f);
+ pathB.cubicTo(808.000000f, 11418.1045f, 807.104553f, 11419.0000f, 806.000000f, 11419.0000f);
+ pathB.lineTo(132.000000f, 11419.0000f);
+ pathB.cubicTo(130.895432f, 11419.0000f, 130.000000f, 11418.1045f, 130.000000f, 11417.0000f);
+ pathB.lineTo(130.000000f, 11416.0000f);
+ pathB.cubicTo(130.000000f, 11415.4473f, 130.895432f, 11415.0000f, 132.000000f, 11415.0000f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skp96prezzi1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(157.464005f, 670.463989f);
+ path.quadTo(158.928925f, 669.000000f, 161.000000f, 669.000000f);
+ path.lineTo(248.000000f, 669.000000f);
+ path.quadTo(250.071075f, 669.000000f, 251.535995f, 670.463989f);
+ path.quadTo(253.000000f, 671.928955f, 253.000000f, 674.000000f);
+ path.lineTo(253.000000f, 706.000000f);
+ path.lineTo(251.000000f, 706.000000f);
+ path.lineTo(251.000000f, 675.000000f);
+ path.cubicTo(251.000000f, 672.790833f, 249.209137f, 671.000000f, 247.000000f, 671.000000f);
+ path.lineTo(162.000000f, 671.000000f);
+ path.cubicTo(159.790863f, 671.000000f, 158.000000f, 672.790833f, 158.000000f, 675.000000f);
+ path.lineTo(158.000000f, 706.000000f);
+ path.lineTo(156.000000f, 706.000000f);
+ path.lineTo(156.000000f, 674.000000f);
+ path.quadTo(156.000000f, 671.928955f, 157.464005f, 670.463989f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(156.000000f, 669.000000f);
+ pathB.lineTo(178.500000f, 691.500000f);
+ pathB.lineTo(230.500000f, 691.500000f);
+ pathB.lineTo(253.000000f, 669.000000f);
+ pathB.lineTo(156.000000f, 669.000000f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpancestry_com1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(161.000000f, 925.000000f);
+ path.cubicTo(159.874390f, 925.000000f, 158.835663f, 925.371948f, 158.000000f, 925.999634f);
+ path.lineTo(158.000000f, 926.000000f);
+ path.lineTo(1108.00000f, 926.000000f);
+ path.lineTo(1108.00000f, 925.999634f);
+ path.cubicTo(1107.16443f, 925.371948f, 1106.12561f, 925.000000f, 1105.00000f, 925.000000f);
+ path.lineTo(161.000000f, 925.000000f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(161.000000f, 926.000000f);
+ pathB.lineTo(1105.00000f, 926.000000f);
+ pathB.cubicTo(1107.20911f, 926.000000f, 1109.00000f, 927.790833f, 1109.00000f, 930.000000f);
+ pathB.lineTo(1109.00000f, 956.000000f);
+ pathB.cubicTo(1109.00000f, 958.209167f, 1107.20911f, 960.000000f, 1105.00000f, 960.000000f);
+ pathB.lineTo(161.000000f, 960.000000f);
+ pathB.cubicTo(158.790863f, 960.000000f, 157.000000f, 958.209167f, 157.000000f, 956.000000f);
+ pathB.lineTo(157.000000f, 930.000000f);
+ pathB.cubicTo(157.000000f, 927.790833f, 158.790863f, 926.000000f, 161.000000f, 926.000000f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpeldorado_com_ua1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(286.695129f, 291.000000f);
+ path.lineTo(229.304855f, 561.000000f);
+ path.lineTo(979.304871f, 561.000000f);
+ path.lineTo(1036.69507f, 291.000000f);
+ path.lineTo(286.695129f, 291.000000f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1006.69513f, 291.000000f);
+ pathB.cubicTo(1023.26367f, 291.000000f, 1033.84021f, 304.431458f, 1030.31836f, 321.000000f);
+ pathB.lineTo(985.681519f, 531.000000f);
+ pathB.cubicTo(982.159790f, 547.568542f, 965.873413f, 561.000000f, 949.304871f, 561.000000f);
+ pathB.lineTo(259.304871f, 561.000000f);
+ pathB.cubicTo(242.736313f, 561.000000f, 232.159805f, 547.568542f, 235.681549f, 531.000000f);
+ pathB.lineTo(280.318420f, 321.000000f);
+ pathB.cubicTo(283.840179f, 304.431458f, 300.126587f, 291.000000f, 316.695129f, 291.000000f);
+ pathB.lineTo(1006.69513f, 291.000000f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpbyte_com1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(968.000000f, 14.0000000f);
+ path.cubicTo(965.238586f, 14.0000000f, 963.000000f, 16.2385769f, 963.000000f, 19.0000000f);
+ path.lineTo(963.000000f, 32.0000000f);
+ path.cubicTo(963.000000f, 34.7614250f, 965.238586f, 37.0000000f, 968.000000f, 37.0000000f);
+ path.lineTo(1034.00000f, 37.0000000f);
+ path.cubicTo(1036.76147f, 37.0000000f, 1039.00000f, 34.7614250f, 1039.00000f, 32.0000000f);
+ path.lineTo(1039.00000f, 19.0000000f);
+ path.cubicTo(1039.00000f, 16.2385769f, 1036.76147f, 14.0000000f, 1034.00000f, 14.0000000f);
+ path.lineTo(968.000000f, 14.0000000f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(968.000000f, 14.0000000f);
+ pathB.lineTo(1034.00000f, 14.0000000f);
+ pathB.cubicTo(1036.76147f, 14.0000000f, 1039.00000f, 16.2385750f, 1039.00000f, 19.0000000f);
+ pathB.lineTo(1039.00000f, 32.0000000f);
+ pathB.cubicTo(1039.00000f, 34.2091408f, 1036.76147f, 36.0000000f, 1034.00000f, 36.0000000f);
+ pathB.lineTo(968.000000f, 36.0000000f);
+ pathB.cubicTo(965.238586f, 36.0000000f, 963.000000f, 34.2091408f, 963.000000f, 32.0000000f);
+ pathB.lineTo(963.000000f, 19.0000000f);
+ pathB.cubicTo(963.000000f, 16.2385750f, 965.238586f, 14.0000000f, 968.000000f, 14.0000000f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skphealth_com76(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(708.099182f, 7.09919119f);
+ path.lineTo(708.099182f, 7.09920025f);
+ path.quadTo(704.000000f, 11.2010098f, 704.000000f, 17.0000000f);
+ path.lineTo(704.000000f, 33.0000000f);
+ path.lineTo(705.000000f, 33.0000000f);
+ path.lineTo(705.000000f, 17.0000000f);
+ path.cubicTo(705.000000f, 13.4101496f, 706.455078f, 10.1601505f, 708.807617f, 7.80761385f);
+ path.lineTo(708.099182f, 7.09919119f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(704.000000f, 3.00000000f);
+#if 0
+ pathB.lineTo(719.500000f, 3.00000000f);
+ pathB.lineTo(705.000000f, 33.0000000f);
+ pathB.lineTo(704.000000f, 33.0000000f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+#else
+ pathB.lineTo(704.000000f, 33.0000000f);
+ pathB.lineTo(705.000000f, 33.0000000f);
+ pathB.lineTo(719.500000f, 3.00000000f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+#endif
+}
+
+static void skpahrefs_com88(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1099.82886f, 7.17117119f);
+ path.lineTo(1099.12134f, 7.87867832f);
+ path.cubicTo(1099.66418f, 8.42157173f, 1100.00000f, 9.17157173f, 1100.00000f, 10.0000000f);
+ path.lineTo(1100.00000f, 28.0000000f);
+ path.cubicTo(1100.00000f, 29.6568546f, 1098.65686f, 31.0000000f, 1097.00000f, 31.0000000f);
+ path.lineTo(1088.00000f, 31.0000000f);
+ path.lineTo(1088.00000f, 32.0000000f);
+ path.lineTo(1097.00000f, 32.0000000f);
+ path.quadTo(1098.65686f, 32.0000000f, 1099.82886f, 30.8288002f);
+ path.quadTo(1101.00000f, 29.6568546f, 1101.00000f, 28.0000000f);
+ path.lineTo(1101.00000f, 10.0000000f);
+ path.quadTo(1101.00000f, 8.34314537f, 1099.82886f, 7.17119980f);
+ path.lineTo(1099.82886f, 7.17117119f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1101.00000f, 6.00000000f);
+ pathB.lineTo(1088.00000f, 6.00000000f);
+ pathB.lineTo(1088.00000f, 19.0000000f);
+ pathB.lineTo(1101.00000f, 32.0000000f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpahrefs_com29(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1037.17114f, 7.17119980f);
+ path.quadTo(1038.34314f, 6.00000000f, 1040.00000f, 6.00000000f);
+ path.lineTo(1074.00000f, 6.00000000f);
+ path.lineTo(1074.00000f, 32.0000000f);
+ path.lineTo(1040.00000f, 32.0000000f);
+ path.quadTo(1038.34314f, 32.0000000f, 1037.17114f, 30.8288002f);
+ path.quadTo(1036.00000f, 29.6568546f, 1036.00000f, 28.0000000f);
+ path.lineTo(1036.00000f, 10.0000000f);
+ path.quadTo(1036.00000f, 8.34314537f, 1037.17114f, 7.17119980f);
+ path.close();
+ path.moveTo(1037.00000f, 10.0000000f);
+ path.cubicTo(1037.00000f, 8.34314537f, 1038.34314f, 7.00000000f, 1040.00000f, 7.00000000f);
+ path.lineTo(1073.00000f, 7.00000000f);
+ path.lineTo(1073.00000f, 31.0000000f);
+ path.lineTo(1040.00000f, 31.0000000f);
+ path.cubicTo(1038.34314f, 31.0000000f, 1037.00000f, 29.6568546f, 1037.00000f, 28.0000000f);
+ path.lineTo(1037.00000f, 10.0000000f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1036.00000f, 32.0000000f);
+ pathB.lineTo(1049.00000f, 19.0000000f);
+ pathB.lineTo(1073.00000f, 31.0000000f);
+ pathB.lineTo(1074.00000f, 32.0000000f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp85d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,6, 1,0, 6,2);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(2,6, 1,0, 6,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+// this fails because the pair of nearly coincident cubics intersect at the ends
+// but the line connected to one of the cubics at the same point does not intersect
+// the other
+static void skpkkiste_to98(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(96, 122);
+ path.cubicTo(94.6192932f, 122, 93.3692932f, 122.559647f, 92.4644699f, 123.46447f);
+ path.lineTo(94.1715698f, 125.17157f);
+ path.cubicTo(94.8954315f, 124.447708f, 95.8954315f, 124, 97, 124);
+ path.lineTo(257, 124);
+ path.cubicTo(258.104553f, 124, 259.104584f, 124.447708f, 259.82843f, 125.17157f);
+ path.lineTo(261.535522f, 123.46447f);
+ path.cubicTo(260.630707f, 122.559647f, 259.380707f, 122, 258, 122);
+ path.lineTo(96, 122);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(258, 122);
+ pathB.cubicTo(260.761414f, 122, 263, 124.238579f, 263, 127);
+ pathB.lineTo(263, 284);
+ pathB.cubicTo(263, 286.761414f, 260.761414f, 289, 258, 289);
+ pathB.lineTo(96, 289);
+ pathB.cubicTo(93.2385788f, 289, 91, 286.761414f, 91, 284);
+ pathB.lineTo(91, 127);
+ pathB.cubicTo(91, 124.238579f, 93.2385788f, 122, 96, 122);
+ pathB.lineTo(258, 122);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void issue1417(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1;
+ path1.moveTo(122.58908843994140625f, 82.2836456298828125f);
+ path1.quadTo(129.8215789794921875f, 80, 138, 80);
+ path1.quadTo(147.15692138671875f, 80, 155.1280364990234375f, 82.86279296875f);
+ path1.lineTo(161.1764678955078125f, 100);
+ path1.lineTo(161.1764678955078125f, 100);
+ path1.lineTo(115.29412078857421875f, 100);
+ path1.lineTo(115.29412078857421875f, 100);
+ path1.lineTo(122.58908843994140625f, 82.2836456298828125f);
+ path1.lineTo(122.58908843994140625f, 82.2836456298828125f);
+ path1.close();
+ path1.moveTo(98.68194580078125f, 140.343841552734375f);
+ path1.lineTo(115.29412078857421875f, 100);
+ path1.lineTo(115.29412078857421875f, 100);
+ path1.lineTo(97.9337615966796875f, 100);
+ path1.lineTo(97.9337615966796875f, 100);
+ path1.quadTo(88, 112.94264984130859375f, 88, 130);
+ path1.quadTo(88, 131.544830322265625f, 88.08148956298828125f, 133.0560302734375f);
+ path1.lineTo(98.68194580078125f, 140.343841552734375f);
+ path1.lineTo(98.68194580078125f, 140.343841552734375f);
+ path1.close();
+ path1.moveTo(136.969696044921875f, 166.6666717529296875f);
+ path1.lineTo(98.68194580078125f, 140.343841552734375f);
+ path1.lineTo(98.68194580078125f, 140.343841552734375f);
+ path1.lineTo(93.45894622802734375f, 153.02825927734375f);
+ path1.lineTo(93.45894622802734375f, 153.02825927734375f);
+ path1.quadTo(96.94116973876953125f, 159.65185546875f, 102.64466094970703125f, 165.3553466796875f);
+ path1.quadTo(110.7924652099609375f, 173.503143310546875f, 120.8179779052734375f, 177.1177825927734375f);
+ path1.lineTo(136.969696044921875f, 166.6666717529296875f);
+ path1.lineTo(136.969696044921875f, 166.6666717529296875f);
+ path1.close();
+ path1.moveTo(175.8309783935546875f, 141.5211334228515625f);
+ path1.lineTo(136.969696044921875f, 166.6666717529296875f);
+ path1.lineTo(136.969696044921875f, 166.6666717529296875f);
+ path1.lineTo(153.15728759765625f, 177.7956390380859375f);
+ path1.lineTo(153.15728759765625f, 177.7956390380859375f);
+ path1.quadTo(164.392425537109375f, 174.318267822265625f, 173.3553466796875f, 165.3553466796875f);
+ path1.quadTo(177.805816650390625f, 160.9048614501953125f, 180.90380859375f, 155.8941650390625f);
+ path1.lineTo(175.8309783935546875f, 141.5211334228515625f);
+ path1.lineTo(175.8309783935546875f, 141.5211334228515625f);
+ path1.close();
+ path1.moveTo(175.8309783935546875f, 141.5211334228515625f);
+ path1.lineTo(187.8782806396484375f, 133.7258148193359375f);
+ path1.lineTo(187.8782806396484375f, 133.7258148193359375f);
+ path1.quadTo(188, 131.8880615234375f, 188, 130);
+ path1.quadTo(188, 112.942657470703125f, 178.0662384033203125f, 100);
+ path1.lineTo(161.1764678955078125f, 100);
+ path1.lineTo(161.1764678955078125f, 100);
+ path1.lineTo(175.8309783935546875f, 141.5211334228515625f);
+ path1.lineTo(175.8309783935546875f, 141.5211334228515625f);
+ path1.close();
+
+ SkPath path2;
+ path2.moveTo(174.117645263671875f, 100);
+ path2.lineTo(161.1764678955078125f, 100);
+ path2.lineTo(161.1764678955078125f, 100);
+ path2.lineTo(155.1280364990234375f, 82.86279296875f);
+ path2.lineTo(155.1280364990234375f, 82.86279296875f);
+ path2.quadTo(153.14971923828125f, 82.15229034423828125f, 151.098419189453125f, 81.618133544921875f);
+ path2.lineTo(143.5294189453125f, 100);
+ path2.lineTo(143.5294189453125f, 100);
+ path2.lineTo(161.1764678955078125f, 100);
+ path2.lineTo(161.1764678955078125f, 100);
+ path2.lineTo(168.23529052734375f, 120);
+ path2.lineTo(168.23529052734375f, 120);
+ path2.lineTo(181.1764678955078125f, 120);
+ path2.lineTo(181.1764678955078125f, 120);
+ path2.lineTo(186.3661956787109375f, 134.7042236328125f);
+ path2.lineTo(186.3661956787109375f, 134.7042236328125f);
+ path2.lineTo(187.8782806396484375f, 133.7258148193359375f);
+ path2.lineTo(187.8782806396484375f, 133.7258148193359375f);
+ path2.quadTo(188, 131.8880615234375f, 188, 130);
+ path2.quadTo(188, 124.80947113037109375f, 187.080169677734375f, 120);
+ path2.lineTo(181.1764678955078125f, 120);
+ path2.lineTo(181.1764678955078125f, 120);
+ path2.lineTo(174.117645263671875f, 100);
+ path2.lineTo(174.117645263671875f, 100);
+ path2.close();
+ path2.moveTo(88.91983795166015625f, 120);
+ path2.lineTo(107.0588226318359375f, 120);
+ path2.lineTo(107.0588226318359375f, 120);
+ path2.lineTo(98.68194580078125f, 140.343841552734375f);
+ path2.lineTo(98.68194580078125f, 140.343841552734375f);
+ path2.lineTo(88.08148956298828125f, 133.0560302734375f);
+ path2.lineTo(88.08148956298828125f, 133.0560302734375f);
+ path2.quadTo(88, 131.544830322265625f, 88, 130);
+ path2.quadTo(88, 124.80951690673828125f, 88.91983795166015625f, 120);
+ path2.close();
+ path2.moveTo(96.67621612548828125f, 145.21490478515625f);
+ path2.lineTo(98.68194580078125f, 140.343841552734375f);
+ path2.lineTo(98.68194580078125f, 140.343841552734375f);
+ path2.lineTo(120.68767547607421875f, 155.4727783203125f);
+ path2.lineTo(120.68767547607421875f, 155.4727783203125f);
+ path2.lineTo(118.68194580078125f, 160.343841552734375f);
+ path2.lineTo(118.68194580078125f, 160.343841552734375f);
+ path2.lineTo(96.67621612548828125f, 145.21490478515625f);
+ path2.lineTo(96.67621612548828125f, 145.21490478515625f);
+ path2.close();
+ path2.moveTo(113.232177734375f, 173.5789947509765625f);
+ path2.quadTo(116.8802642822265625f, 175.69805908203125f, 120.8179779052734375f, 177.1177825927734375f);
+ path2.lineTo(132.2864990234375f, 169.6969757080078125f);
+ path2.lineTo(132.2864990234375f, 169.6969757080078125f);
+ path2.lineTo(118.68194580078125f, 160.343841552734375f);
+ path2.lineTo(118.68194580078125f, 160.343841552734375f);
+ path2.lineTo(113.232177734375f, 173.5789947509765625f);
+ path2.lineTo(113.232177734375f, 173.5789947509765625f);
+ path2.close();
+
+ testPathOp(reporter, path1, path2, kUnion_PathOp, filename);
+}
+
+static void issue1418(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1;
+ path1.moveTo(0, 0);
+ path1.lineTo(1, 0);
+ path1.lineTo(1, 0);
+ path1.lineTo(1, 1);
+ path1.lineTo(1, 1);
+ path1.lineTo(0, 1);
+ path1.lineTo(0, 1);
+ path1.lineTo(0, 0);
+ path1.lineTo(0, 0);
+ path1.close();
+
+ SkPath path2;
+ path2.moveTo(0.64644664525985717773f, -0.35355341434478759766f);
+ path2.quadTo(0.79289329051971435547f, -0.50000005960464477539f, 1.0000001192092895508f, -0.50000005960464477539f);
+ path2.quadTo(1.2071068286895751953f, -0.50000005960464477539f, 1.3535535335540771484f, -0.35355341434478759766f);
+ path2.quadTo(1.5000001192092895508f, -0.20710679888725280762f, 1.5000001192092895508f, 0);
+ path2.quadTo(1.5000001192092895508f, 0.20710679888725280762f, 1.3535535335540771484f, 0.35355341434478759766f);
+ path2.quadTo(1.2071068286895751953f, 0.50000005960464477539f, 1.0000001192092895508f, 0.50000005960464477539f);
+ path2.quadTo(0.79289329051971435547f, 0.50000005960464477539f, 0.64644664525985717773f, 0.35355341434478759766f);
+ path2.quadTo(0.50000005960464477539f, 0.20710679888725280762f, 0.50000005960464477539f, 0);
+ path2.quadTo(0.50000005960464477539f, -0.20710679888725280762f, 0.64644664525985717773f, -0.35355341434478759766f);
+ testPathOp(reporter, path1, path2, kIntersect_PathOp, filename);
+}
+
+static void cubicOp85i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 4);
+ path.cubicTo(1, 5, 4, 3, 6, 4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3, 4);
+ pathB.cubicTo(4, 6, 4, 3, 5, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void issue1418b(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1;
+ path1.moveTo(0, 0);
+ path1.lineTo(1, 0);
+ path1.lineTo(1, 1);
+ path1.lineTo(0, 1);
+ path1.lineTo(0, 0);
+ path1.close();
+ path1.setFillType(SkPath::kWinding_FillType);
+ SkPath path2;
+ path2.moveTo(0.646446645f, -0.353553414f);
+ path2.quadTo(0.792893291f, -0.50000006f, 1.00000012f, -0.50000006f);
+ path2.quadTo(1.20710683f, -0.50000006f, 1.35355353f, -0.353553414f);
+ path2.quadTo(1.50000012f, -0.207106799f, 1.50000012f, 0);
+ path2.quadTo(1.50000012f, 0.207106799f, 1.35355353f, 0.353553414f);
+ path2.quadTo(1.20710683f, 0.50000006f, 1.00000012f, 0.50000006f);
+ path2.quadTo(0.792893291f, 0.50000006f, 0.646446645f, 0.353553414f);
+ path2.quadTo(0.50000006f, 0.207106799f, 0.50000006f, 0);
+ path2.quadTo(0.50000006f, -0.207106799f, 0.646446645f, -0.353553414f);
+ path2.close();
+ path2.moveTo(1.00000012f, 0.50000006f);
+ path2.lineTo(1.00000012f, 1.00000012f);
+ path2.lineTo(0.50000006f, 1.00000012f);
+ path2.quadTo(0.50000006f, 0.792893291f, 0.646446645f, 0.646446645f);
+ path2.quadTo(0.792893291f, 0.50000006f, 1.00000012f, 0.50000006f);
+ path2.close();
+ path2.setFillType(SkPath::kEvenOdd_FillType);
+ testPathOp(reporter, path1, path2, kIntersect_PathOp, filename);
+}
+
+static void rectOp1i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(2, 2, 4, 4, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void rectOp2i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(0, 0, 3, 3, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void rectOp3x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(3, 0);
+ path.lineTo(3, 3);
+ path.lineTo(0, 3);
+ path.close();
+ path.moveTo(2, 2);
+ path.lineTo(3, 2);
+ path.lineTo(3, 3);
+ path.lineTo(2, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 1);
+ pathB.lineTo(3, 1);
+ pathB.lineTo(3, 3);
+ pathB.lineTo(1, 3);
+ pathB.close();
+ pathB.moveTo(2, 2);
+ pathB.lineTo(3, 2);
+ pathB.lineTo(3, 3);
+ pathB.lineTo(2, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kXOR_PathOp, filename);
+}
+
+// this fails to generate two interior line segments
+// an earlier pathops succeeded, but still failed to generate one interior line segment
+// (but was saved by assemble, which works around a single line missing segment)
+static void issue1435(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1;
+ path1.moveTo(160, 60);
+ path1.lineTo(220, 230);
+ path1.lineTo(60, 120);
+ path1.lineTo(260, 120);
+ path1.lineTo(90, 230);
+ path1.lineTo(160, 60);
+ path1.close();
+ path1.setFillType(SkPath::kEvenOdd_FillType);
+
+ SkPath path2;
+ path2.moveTo(142.589081f, 102.283646f);
+ path2.quadTo(149.821579f, 100, 158, 100);
+ path2.quadTo(167.156921f, 100, 175.128036f, 102.862793f);
+ path2.lineTo(181.176468f, 120);
+ path2.lineTo(135.294128f, 120);
+ path2.lineTo(142.589081f, 102.283646f);
+ path2.close();
+ path2.moveTo(118.681946f, 160.343842f);
+ path2.lineTo(135.294128f, 120);
+ path2.lineTo(117.933762f, 120);
+ path2.quadTo(108, 132.942657f, 108, 150);
+ path2.quadTo(108, 151.54483f, 108.08149f, 153.05603f);
+ path2.lineTo(118.681946f, 160.343842f);
+ path2.close();
+ path2.moveTo(156.969696f, 186.666672f);
+ path2.lineTo(118.681946f, 160.343842f);
+ path2.lineTo(113.458946f, 173.028259f);
+ path2.quadTo(116.94117f, 179.651855f, 122.644661f, 185.355347f);
+ path2.quadTo(130.792465f, 193.503143f, 140.817978f, 197.117783f);
+ path2.lineTo(156.969696f, 186.666672f);
+ path2.close();
+ path2.moveTo(195.830978f, 161.521133f);
+ path2.lineTo(156.969696f, 186.666672f);
+ path2.lineTo(173.157288f, 197.795639f);
+ path2.quadTo(184.392426f, 194.318268f, 193.355347f, 185.355347f);
+ path2.quadTo(197.805817f, 180.904861f, 200.903809f, 175.894165f);
+ path2.lineTo(195.830978f, 161.521133f);
+ path2.close();
+ path2.moveTo(195.830978f, 161.521133f);
+ path2.lineTo(207.878281f, 153.725815f);
+ path2.quadTo(208, 151.888062f, 208, 150);
+ path2.quadTo(208, 132.942657f, 198.066238f, 120);
+ path2.lineTo(181.176468f, 120);
+ path2.lineTo(195.830978f, 161.521133f);
+ path2.close();
+ path2.setFillType(SkPath::kEvenOdd_FillType);
+ testPathOp(reporter, path1, path2, kIntersect_PathOp, filename);
+}
+
+static void skpkkiste_to716(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1173, 284);
+ path.cubicTo(1173, 285.125824f, 1173.37207f, 286.164734f, 1174, 287.000488f);
+ path.lineTo(1174, 123.999496f);
+ path.cubicTo(1173.37207f, 124.835243f, 1173, 125.874168f, 1173, 127);
+ path.lineTo(1173, 284);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1340, 122);
+ pathB.cubicTo(1342.76147f, 122, 1345, 124.238579f, 1345, 127);
+ pathB.lineTo(1345, 284);
+ pathB.cubicTo(1345, 286.761414f, 1342.76147f, 289, 1340, 289);
+ pathB.lineTo(1178, 289);
+ pathB.cubicTo(1175.23853f, 289, 1173, 286.761414f, 1173, 284);
+ pathB.lineTo(1173, 127);
+ pathB.cubicTo(1173, 124.238579f, 1175.23853f, 122, 1178, 122);
+ pathB.lineTo(1340, 122);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void loopEdge1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,0);
+ path.lineTo(3,0);
+ path.lineTo(3,2);
+ path.lineTo(1,2);
+ path.lineTo(1,1);
+ path.lineTo(2,1);
+ path.lineTo(2,3);
+ path.lineTo(0,3);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(1,2);
+ pathB.lineTo(2,2);
+ pathB.lineTo(2,4);
+ pathB.lineTo(1,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void loopEdge2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,0);
+ path.lineTo(3,0);
+ path.lineTo(3,2);
+ path.lineTo(1,2);
+ path.lineTo(1,1);
+ path.lineTo(2,1);
+ path.lineTo(2,3);
+ path.lineTo(0,3);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(1 - 1e-6f,2);
+ pathB.lineTo(2 - 1e-6f,2);
+ pathB.lineTo(2 - 1e-6f,4);
+ pathB.lineTo(1 - 1e-6f,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp86i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 4);
+ path.cubicTo(3, 4, 6, 2, 5, 2);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(2, 6);
+ pathB.cubicTo(2, 5, 4, 0, 4, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp87u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,2, 2,0, 6,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,2);
+ pathB.cubicTo(4,6, 1,0, 2,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp88u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,5, 5,0, 6,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,5);
+ pathB.cubicTo(4,6, 1,0, 5,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp89u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 3);
+ path.cubicTo(1, 6, 5, 0, 6, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 5);
+ pathB.cubicTo(3, 6, 3, 0, 6, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp90u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 5);
+ path.cubicTo(1, 2, 5, 2, 4, 1);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(2, 5);
+ pathB.cubicTo(1, 4, 5, 0, 2, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp91u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 6);
+ path.cubicTo(0, 3, 6, 3, 5, 0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3, 6);
+ pathB.cubicTo(0, 5, 6, 1, 3, 0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void skpaaalgarve_org53(skiatest::Reporter* reporter, const char* filename) { // add t cancel
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(-1.24344979e-014f, 348);
+ path.lineTo(258, 348);
+ path.lineTo(258, 322);
+ path.quadTo(258, 317.857849f, 255.072006f, 314.928009f);
+ path.quadTo(252.142136f, 312, 248, 312);
+ path.lineTo(1.77635684e-015f, 312);
+ path.lineTo(-1.24344979e-014f, 348);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 312);
+ pathB.lineTo(258, 312);
+ pathB.lineTo(258, 348);
+ pathB.lineTo(0, 348);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpabcspark_ca103(skiatest::Reporter* reporter, const char* filename) { // add t cancel
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1.99840144e-015f, 494);
+ path.lineTo(97, 494);
+ path.quadTo(100.313705f, 494, 102.6576f, 491.657593f);
+ path.quadTo(105, 489.313721f, 105, 486);
+ path.lineTo(105, 425);
+ path.quadTo(105, 421.686279f, 102.6576f, 419.342407f);
+ path.quadTo(100.313705f, 417, 97, 417);
+ path.lineTo(2.22044605e-016f, 417);
+ path.lineTo(1.99840144e-015f, 494);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 417);
+ pathB.lineTo(105, 417);
+ pathB.lineTo(105, 494);
+ pathB.lineTo(0, 494);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpacesoftech_com47(skiatest::Reporter* reporter, const char* filename) { // partial coincidence
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(670.537415f, 285);
+ path.lineTo(670.387451f, 285);
+ path.lineTo(596.315186f, 314.850708f);
+ path.lineTo(626.19696f, 389);
+ path.lineTo(626.346863f, 389);
+ path.lineTo(700.419189f, 359.149261f);
+ path.lineTo(670.537415f, 285);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(663.318542f, 374.100616f);
+ pathB.quadTo(647.950989f, 380.293671f, 632.705322f, 373.806305f);
+ pathB.quadTo(617.459595f, 367.318909f, 611.266541f, 351.951355f);
+ pathB.quadTo(605.073486f, 336.58374f, 611.560913f, 321.338074f);
+ pathB.quadTo(618.048279f, 306.092407f, 633.415833f, 299.899353f);
+ pathB.quadTo(648.783447f, 293.706299f, 664.029114f, 300.193665f);
+ pathB.quadTo(679.27478f, 306.68103f, 685.467834f, 322.048645f);
+ pathB.quadTo(691.660889f, 337.416199f, 685.173523f, 352.661896f);
+ pathB.quadTo(678.686157f, 367.907562f, 663.318542f, 374.100616f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpact_com43(skiatest::Reporter* reporter, const char* filename) { // bridge op
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1.45716772e-016f, 924.336121f);
+ path.lineTo(-1.11022302e-016f, 920);
+ path.lineTo(6, 920);
+ path.lineTo(6, 926);
+ path.lineTo(1.66389287f, 926);
+ path.quadTo(1.18842196f, 925.674561f, 0.756800175f, 925.243225f);
+ path.quadTo(0.325406998f, 924.811523f, 1.45716772e-016f, 924.336121f);
+ path.close();
+ path.moveTo(1, 921);
+ path.lineTo(5, 921);
+ path.lineTo(5, 925);
+ path.cubicTo(2.79086018f, 925, 1, 923.209167f, 1, 921);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(-1, 920);
+ pathB.lineTo(0, 920);
+ pathB.lineTo(3, 927);
+ pathB.lineTo(-1, 927);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpadbox_lt8(skiatest::Reporter* reporter, const char* filename) { // zero span
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(320.097229f, 628.573669f);
+ path.lineTo(610.227173f, 85.7786865f);
+ path.lineTo(946.652588f, 265.601807f);
+ path.lineTo(656.522644f, 808.39679f);
+ path.lineTo(320.097229f, 628.573669f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(333.866608f, 623.496155f);
+ pathB.lineTo(613.368042f, 100.585754f);
+ pathB.cubicTo(613.685303f, 99.9921265f, 614.423767f, 99.7681885f, 615.017395f, 100.085449f);
+ pathB.lineTo(932.633057f, 269.854553f);
+ pathB.cubicTo(933.226685f, 270.171875f, 933.450623f, 270.910278f, 933.133301f, 271.503906f);
+ pathB.lineTo(653.631897f, 794.414307f);
+ pathB.cubicTo(653.314636f, 795.007935f, 652.576172f, 795.231934f, 651.982544f, 794.914612f);
+ pathB.lineTo(334.366943f, 625.145508f);
+ pathB.cubicTo(333.773315f, 624.828247f, 333.549286f, 624.089783f, 333.866608f, 623.496155f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpadindex_de4(skiatest::Reporter* reporter, const char* filename) { // find chase op
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 926);
+ path.lineTo(0, 0);
+ path.lineTo(1280, 0);
+ path.lineTo(1280, 926);
+ path.lineTo(0, 926);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 312);
+ pathB.lineTo(8.20486257e-015f, 178);
+ pathB.lineTo(49, 178);
+ pathB.lineTo(49, 312);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpadithya_putr4_blogspot_com551(skiatest::Reporter* reporter, const char* filename) { // calc common
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(205.605804f, 142.334625f);
+ path.lineTo(254.665359f, 85.6058044f);
+ path.lineTo(311.394196f, 134.665359f);
+ path.lineTo(262.334625f, 191.39418f);
+ path.lineTo(205.605804f, 142.334625f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(283.407959f, 110.462646f);
+ pathB.cubicTo(298.864319f, 123.829437f, 300.558258f, 147.195221f, 287.191467f, 162.651581f);
+ pathB.lineTo(286.537354f, 163.407959f);
+ pathB.cubicTo(273.170563f, 178.864334f, 249.804779f, 180.558258f, 234.348419f, 167.191467f);
+ pathB.lineTo(233.592026f, 166.537338f);
+ pathB.cubicTo(218.135666f, 153.170547f, 216.441727f, 129.804779f, 229.808517f, 114.348412f);
+ pathB.lineTo(230.462646f, 113.592026f);
+ pathB.cubicTo(243.829437f, 98.1356659f, 267.195221f, 96.4417267f, 282.651581f, 109.808517f);
+ pathB.lineTo(283.407959f, 110.462646f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpadspert_de11(skiatest::Reporter* reporter, const char* filename) { // mark and chase winding
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(-4.4408921e-016f, 682.5f);
+ path.lineTo(30.5f, 682.5f);
+ path.cubicTo(32.709137f, 682.5f, 34.5f, 680.709167f, 34.5f, 678.5f);
+ path.lineTo(34.5f, 486.5f);
+ path.cubicTo(34.5f, 484.290863f, 32.709137f, 482.5f, 30.5f, 482.5f);
+ path.lineTo(0, 482.5f);
+ path.lineTo(-4.4408921e-016f, 682.5f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 482);
+ pathB.lineTo(35, 482);
+ pathB.lineTo(35, 683);
+ pathB.lineTo(0, 683);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpaiaigames_com870(skiatest::Reporter* reporter, const char* filename) { // cubic/cubic intersect
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(324.071075f, 845.071045f);
+ path.cubicTo(324.405151f, 844.737f, 324.715668f, 844.379395f, 325, 844.000977f);
+ path.lineTo(325, 842.127197f);
+ path.cubicTo(324.571411f, 842.956238f, 324.017761f, 843.710144f, 323.363953f, 844.363953f);
+ path.lineTo(324.071075f, 845.071045f);
+ path.close();
+ path.moveTo(323.363953f, 714.636047f);
+ path.lineTo(324.071075f, 713.928955f);
+ path.cubicTo(324.405151f, 714.263f, 324.715668f, 714.620605f, 325, 714.999023f);
+ path.lineTo(325, 716.872803f);
+ path.cubicTo(324.571411f, 716.043762f, 324.017761f, 715.289856f, 323.363953f, 714.636047f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(317, 711);
+ pathB.cubicTo(322.522858f, 711, 327, 715.477173f, 327, 721);
+ pathB.lineTo(327, 838);
+ pathB.cubicTo(327, 843.522827f, 322.522858f, 848, 317, 848);
+ pathB.lineTo(155, 848);
+ pathB.cubicTo(149.477158f, 848, 145, 843.522827f, 145, 838);
+ pathB.lineTo(145, 721);
+ pathB.cubicTo(145, 715.477173f, 149.477158f, 711, 155, 711);
+ pathB.lineTo(317, 711);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp92i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(2, 6, 4, 1, 5, 4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(4, 5, 1, 0, 6, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp93d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(1, 6, 4, 1, 4, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(3, 4, 1, 0, 6, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp94u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 3);
+ path.cubicTo(2, 3, 5, 0, 5, 3);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(0, 5);
+ pathB.cubicTo(3, 5, 3, 0, 3, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void skpadbox_lt15(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(333.292084f, 624.570984f);
+ path.lineTo(614.229797f, 98.9735107f);
+ path.lineTo(933.457764f, 269.604431f);
+ path.lineTo(652.52002f, 795.201904f);
+ path.lineTo(333.292084f, 624.570984f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(613.368042f, 100.585754f);
+ pathB.cubicTo(613.685303f, 99.9921265f, 614.423767f, 99.7681885f, 615.017395f, 100.085449f);
+ pathB.lineTo(932.633057f, 269.854553f);
+ pathB.cubicTo(933.226685f, 270.171875f, 933.450623f, 270.910278f, 933.133301f, 271.503906f);
+ pathB.lineTo(653.631897f, 794.414307f);
+ pathB.cubicTo(653.314636f, 795.007935f, 652.576172f, 795.231934f, 651.982544f, 794.914612f);
+ pathB.lineTo(334.366943f, 625.145508f);
+ pathB.cubicTo(333.773315f, 624.828247f, 333.549286f, 624.089783f, 333.866608f, 623.496155f);
+ pathB.lineTo(613.368042f, 100.585754f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpadoption_org196(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(802, 367);
+ path.lineTo(802, 324);
+ path.lineTo(956, 324);
+ path.lineTo(956, 371);
+ path.quadTo(956, 373.071075f, 954.536011f, 374.536011f);
+ path.quadTo(953.071045f, 376, 951, 376);
+ path.lineTo(811, 376);
+ path.cubicTo(806.029419f, 376, 802, 371.970551f, 802, 367);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(803, 326);
+ pathB.lineTo(955, 326);
+ pathB.lineTo(955, 370);
+ pathB.cubicTo(955, 372.761414f, 952.761414f, 375, 950, 375);
+ pathB.lineTo(808, 375);
+ pathB.cubicTo(805.238586f, 375, 803, 372.761414f, 803, 370);
+ pathB.lineTo(803, 326);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpadspert_net23(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(-2.220446e-018f, 483.5f);
+ path.lineTo(0, 482.5f);
+ path.lineTo(30.5f, 482.5f);
+ path.cubicTo(32.709137f, 482.5f, 34.5f, 484.290863f, 34.5f, 486.5f);
+ path.lineTo(34.5f, 678.5f);
+ path.cubicTo(34.5f, 680.709167f, 32.709137f, 682.5f, 30.5f, 682.5f);
+ path.lineTo(-4.4408921e-016f, 682.5f);
+ path.lineTo(-4.41868766e-016f, 681.5f);
+ path.lineTo(30.5f, 681.5f);
+ path.cubicTo(32.1568565f, 681.5f, 33.5f, 680.15686f, 33.5f, 678.5f);
+ path.lineTo(33.5f, 486.5f);
+ path.cubicTo(33.5f, 484.84314f, 32.1568565f, 483.5f, 30.5f, 483.5f);
+ path.lineTo(-2.220446e-018f, 483.5f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 482);
+ pathB.lineTo(35, 482);
+ pathB.lineTo(35, 683);
+ pathB.lineTo(0, 683);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpadventistmission_org572(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1182.00037f, 926);
+ path.cubicTo(1181.08813f, 924.785583f, 1179.63586f, 924, 1178, 924);
+ path.lineTo(938, 924);
+ path.cubicTo(936.364197f, 924, 934.911865f, 924.785583f, 933.999634f, 926);
+ path.lineTo(1182.00037f, 926);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(934, 924);
+ pathB.lineTo(1182, 924);
+ pathB.lineTo(1182, 926);
+ pathB.lineTo(934, 926);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpagentxsites_com55(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(925, 27);
+ path.cubicTo(924.447693f, 27, 924, 27.4477158f, 924, 28);
+ path.lineTo(924, 55);
+ path.cubicTo(924, 55.5522842f, 924.447693f, 56, 925, 56);
+ path.lineTo(1103, 56);
+ path.cubicTo(1103.55225f, 56, 1104, 55.5522842f, 1104, 55);
+ path.lineTo(1104, 28);
+ path.cubicTo(1104, 27.4477158f, 1103.55225f, 27, 1103, 27);
+ path.lineTo(925, 27);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1103, 27);
+ pathB.cubicTo(1104.10461f, 27, 1105, 27.8954315f, 1105, 29);
+ pathB.lineTo(1105, 54);
+ pathB.cubicTo(1105, 55.1045685f, 1104.10461f, 56, 1103, 56);
+ pathB.lineTo(926, 56);
+ pathB.cubicTo(924.895447f, 56, 924, 55.1045685f, 924, 54);
+ pathB.lineTo(924, 29);
+ pathB.cubicTo(924, 27.8954315f, 924.895447f, 27, 926, 27);
+ pathB.lineTo(1103, 27);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpbakosoft_com10(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(190, 170);
+ path.cubicTo(178.9543f, 170, 170, 178.9543f, 170, 190);
+ path.cubicTo(170, 201.0457f, 178.9543f, 210, 190, 210);
+ path.lineTo(370, 210);
+ path.cubicTo(381.045685f, 210, 390, 201.0457f, 390, 190);
+ path.cubicTo(390, 178.9543f, 381.045685f, 170, 370, 170);
+ path.lineTo(190, 170);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(210, 190);
+ pathB.quadTo(210, 198.284271f, 204.142136f, 204.142136f);
+ pathB.quadTo(198.284271f, 210, 190, 210);
+ pathB.quadTo(181.715729f, 210, 175.857864f, 204.142136f);
+ pathB.quadTo(170, 198.284271f, 170, 190);
+ pathB.quadTo(170, 181.715729f, 175.857864f, 175.857864f);
+ pathB.quadTo(181.715729f, 170, 190, 170);
+ pathB.quadTo(198.284271f, 170, 204.142136f, 175.857864f);
+ pathB.quadTo(210, 181.715729f, 210, 190);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpbambootheme_com12(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(47.8780937f, 58);
+ path.lineTo(0, 58);
+ path.lineTo(-8.65973959e-015f, 96.9914017f);
+ path.quadTo(20.0654926f, 96.6451874f, 34.3553391f, 82.3553391f);
+ path.quadTo(44.9466133f, 71.764061f, 47.8780937f, 58);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(-1, -3);
+ pathB.lineTo(-1, -3);
+ pathB.cubicTo(26.6142502f, -3, 49, 19.3857498f, 49, 47);
+ pathB.lineTo(49, 47);
+ pathB.cubicTo(49, 74.6142502f, 26.6142502f, 97, -1, 97);
+ pathB.lineTo(-1, 97);
+ pathB.cubicTo(-28.6142502f, 97, -51, 74.6142502f, -51, 47);
+ pathB.lineTo(-51, 47);
+ pathB.cubicTo(-51, 19.3857498f, -28.6142502f, -3, -1, -3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpakmmos_ru100(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(693.000488f, 926);
+ path.cubicTo(692.164734f, 925.37207f, 691.125793f, 925, 690, 925);
+ path.lineTo(578, 925);
+ path.cubicTo(576.874207f, 925, 575.835266f, 925.37207f, 574.999512f, 926);
+ path.lineTo(693.000488f, 926);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(575, 925);
+ pathB.lineTo(693, 925);
+ pathB.lineTo(693, 926);
+ pathB.lineTo(575, 926);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpcarpetplanet_ru22(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(195, 785);
+ path.cubicTo(124.307556f, 785, 67, 841.859863f, 67, 912);
+ path.lineTo(67, 913);
+ path.cubicTo(67, 917.388916f, 67.2243805f, 921.725769f, 67.662384f, 926);
+ path.lineTo(322, 926);
+ path.lineTo(322, 896.048035f);
+ path.cubicTo(314.09201f, 833.437622f, 260.247131f, 785, 195, 785);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(195, 785);
+ pathB.cubicTo(265.140167f, 785, 322, 842.307556f, 322, 913);
+ pathB.cubicTo(322, 983.692444f, 265.140167f, 1041, 195, 1041);
+ pathB.lineTo(194, 1041);
+ pathB.cubicTo(123.85984f, 1041, 67, 983.692444f, 67, 913);
+ pathB.cubicTo(67, 842.307556f, 123.85984f, 785, 194, 785);
+ pathB.lineTo(195, 785);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// this fails because cubic/quad misses an intersection (failure is isolated in c/q int test)
+static void skpcarrot_is24(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return;
+ }
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(945, 597);
+ path.quadTo(913.93396f, 597, 891.96698f, 618.96698f);
+ path.quadTo(870, 640.93396f, 870, 672);
+ path.quadTo(870, 703.06604f, 891.96698f, 725.03302f);
+ path.quadTo(913.93396f, 747, 945, 747);
+ path.quadTo(976.06604f, 747, 998.03302f, 725.03302f);
+ path.quadTo(1020, 703.06604f, 1020, 672);
+ path.quadTo(1020, 640.93396f, 998.03302f, 618.96698f);
+ path.quadTo(976.06604f, 597, 945, 597);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(945.080994f, 597.161987f);
+ pathB.cubicTo(903.659973f, 597.161987f, 870.080994f, 630.73999f, 870.080994f, 672.161987f);
+ pathB.cubicTo(870.080994f, 676.096008f, 870.387024f, 679.957031f, 870.971008f, 683.726013f);
+ pathB.cubicTo(876.53302f, 719.656006f, 907.593994f, 747.161987f, 945.080994f, 747.161987f);
+ pathB.cubicTo(982.567993f, 747.161987f, 1013.62903f, 719.656006f, 1019.19104f, 683.726013f);
+ pathB.cubicTo(1019.77502f, 679.955017f, 1020.08099f, 676.094971f, 1020.08099f, 672.161987f);
+ pathB.cubicTo(1020.08002f, 630.73999f, 986.502014f, 597.161987f, 945.080994f, 597.161987f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpbangalorenest_com4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 926);
+ path.lineTo(0, 0);
+ path.lineTo(1265, 0);
+ path.lineTo(1265, 926);
+ path.lineTo(0, 926);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 290);
+ pathB.lineTo(-2.64514972e-014f, 146);
+ pathB.lineTo(30, 146);
+ pathB.lineTo(30, 290);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpbenzoteh_ru152(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(883, 23);
+ path.lineTo(883, 0);
+ path.lineTo(1122.5f, 0);
+ path.lineTo(1122.5f, 25.2136822f);
+ path.quadTo(1122.14441f, 25.9271851f, 1121.53601f, 26.5359993f);
+ path.quadTo(1120.07104f, 28, 1118, 28);
+ path.lineTo(888, 28);
+ path.quadTo(885.928955f, 28, 884.463989f, 26.5359993f);
+ path.quadTo(883, 25.0710678f, 883, 23);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(883, 0);
+ pathB.lineTo(1123, 0);
+ pathB.lineTo(1123, 23);
+ pathB.quadTo(1123, 25.0710678f, 1121.53601f, 26.5359993f);
+ pathB.quadTo(1120.07104f, 28, 1118, 28);
+ pathB.lineTo(888, 28);
+ pathB.quadTo(885.928955f, 28, 884.463989f, 26.5359993f);
+ pathB.quadTo(883, 25.0710678f, 883, 23);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpbestred_ru37(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(883, 23);
+ path.lineTo(883, 0);
+ path.lineTo(1122.5f, 0);
+ path.lineTo(1122.5f, 25.2136822f);
+ path.quadTo(1122.14441f, 25.9271851f, 1121.53601f, 26.5359993f);
+ path.quadTo(1120.07104f, 28, 1118, 28);
+ path.lineTo(888, 28);
+ path.quadTo(885.928955f, 28, 884.463989f, 26.5359993f);
+ path.quadTo(883, 25.0710678f, 883, 23);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(883, 0);
+ pathB.lineTo(1123, 0);
+ pathB.lineTo(1123, 23);
+ pathB.quadTo(1123, 25.0710678f, 1121.53601f, 26.5359993f);
+ pathB.quadTo(1120.07104f, 28, 1118, 28);
+ pathB.lineTo(888, 28);
+ pathB.quadTo(885.928955f, 28, 884.463989f, 26.5359993f);
+ pathB.quadTo(883, 25.0710678f, 883, 23);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpbingoentertainment_net189(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(896, 745.38678f);
+ path.lineTo(896, 873.38678f);
+ path.lineTo(922.567993f, 876.683716f);
+ path.lineTo(922.567993f, 748.683716f);
+ path.lineTo(896, 745.38678f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(899.200928f, 745.783997f);
+ pathB.cubicTo(897.119385f, 745.525696f, 895.432007f, 752.031982f, 895.432007f, 760.316284f);
+ pathB.lineTo(895.432007f, 858.316284f);
+ pathB.cubicTo(895.432007f, 866.600586f, 897.119385f, 873.525696f, 899.200928f, 873.783997f);
+ pathB.lineTo(918.799133f, 876.216003f);
+ pathB.cubicTo(920.880615f, 876.474304f, 922.567993f, 869.968018f, 922.567993f, 861.683716f);
+ pathB.lineTo(922.567993f, 763.683716f);
+ pathB.cubicTo(922.567993f, 755.399414f, 920.880615f, 748.474304f, 918.799133f, 748.216003f);
+ pathB.lineTo(899.200928f, 745.783997f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpcarrefour_ro62(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1104, 453);
+ path.lineTo(399, 453);
+ path.lineTo(399, 657);
+ path.cubicTo(399, 661.970581f, 403.029449f, 666, 408, 666);
+ path.lineTo(1095, 666);
+ path.cubicTo(1099.97058f, 666, 1104, 661.970581f, 1104, 657);
+ path.lineTo(1104, 453);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(400, 453);
+ pathB.lineTo(1103, 453);
+ pathB.lineTo(1103, 666);
+ pathB.lineTo(406, 666);
+ pathB.cubicTo(402.686279f, 666, 400, 663.313721f, 400, 660);
+ pathB.lineTo(400, 453);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpcaffelavazzait_com_ua21(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(883, 23);
+ path.lineTo(883, 0);
+ path.lineTo(1122.5f, 0);
+ path.lineTo(1122.5f, 25.2136822f);
+ path.quadTo(1122.14441f, 25.9271851f, 1121.53601f, 26.5359993f);
+ path.quadTo(1120.07104f, 28, 1118, 28);
+ path.lineTo(888, 28);
+ path.quadTo(885.928955f, 28, 884.463989f, 26.5359993f);
+ path.quadTo(883, 25.0710678f, 883, 23);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(883, 0);
+ pathB.lineTo(1123, 0);
+ pathB.lineTo(1123, 23);
+ pathB.quadTo(1123, 25.0710678f, 1121.53601f, 26.5359993f);
+ pathB.quadTo(1120.07104f, 28, 1118, 28);
+ pathB.lineTo(888, 28);
+ pathB.quadTo(885.928955f, 28, 884.463989f, 26.5359993f);
+ pathB.quadTo(883, 25.0710678f, 883, 23);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpcamcorder_kz21(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(883, 23);
+ path.lineTo(883, 0);
+ path.lineTo(1122.5f, 0);
+ path.lineTo(1122.5f, 25.2136822f);
+ path.quadTo(1122.14441f, 25.9271851f, 1121.53601f, 26.5359993f);
+ path.quadTo(1120.07104f, 28, 1118, 28);
+ path.lineTo(888, 28);
+ path.quadTo(885.928955f, 28, 884.463989f, 26.5359993f);
+ path.quadTo(883, 25.0710678f, 883, 23);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(883, 0);
+ pathB.lineTo(1123, 0);
+ pathB.lineTo(1123, 23);
+ pathB.quadTo(1123, 25.0710678f, 1121.53601f, 26.5359993f);
+ pathB.quadTo(1120.07104f, 28, 1118, 28);
+ pathB.lineTo(888, 28);
+ pathB.quadTo(885.928955f, 28, 884.463989f, 26.5359993f);
+ pathB.quadTo(883, 25.0710678f, 883, 23);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpcavablar_net563(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(160.000488f, 918);
+ path.cubicTo(159.164749f, 917.37207f, 158.125824f, 917, 157, 917);
+ path.lineTo(94, 917);
+ path.cubicTo(92.874176f, 917, 91.8352661f, 917.37207f, 90.9995193f, 918);
+ path.lineTo(160.000488f, 918);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(91, 917);
+ pathB.lineTo(160, 917);
+ pathB.lineTo(160, 918);
+ pathB.lineTo(91, 918);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpinsomnia_gr72(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1138, 231);
+ path.lineTo(1137, 243.625748f);
+ path.lineTo(1137, 926);
+ path.lineTo(1139, 926);
+ path.lineTo(1139, 231);
+ path.lineTo(1138, 231);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1139, 231);
+ pathB.lineTo(1138, 231);
+ pathB.lineTo(633, 6101);
+ pathB.lineTo(1139, 6607);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp95u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 2);
+ path.cubicTo(2, 3, 5, 1, 3, 2);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(1, 5);
+ pathB.cubicTo(2, 3, 2, 0, 3, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp96d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1, 6);
+ path.cubicTo(0, 3, 6, 3, 5, 0);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(3, 6);
+ pathB.cubicTo(0, 5, 6, 1, 3, 0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp97x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 2);
+ path.cubicTo(0, 6, 2, 1, 2, 1);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(1, 2, 2, 0, 6, 0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kXOR_PathOp, filename);
+}
+
+static void cubicOp98x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 3);
+ path.cubicTo(3, 6, 4, 1, 6, 3);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(3, 6, 3, 0, 6, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kXOR_PathOp, filename);
+}
+
+static void cubicOp99(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3,6);
+ path.cubicTo(0,3, 6,5, 5,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(5,6);
+ pathB.cubicTo(4,5, 6,3, 3,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp100(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,2, 2,1, 4,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(2,4, 1,0, 2,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp101(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(2, 3, 2, 1, 5, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(3, 5, 1, 0, 3, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp102(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,2, 1,0, 3,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(0,3, 1,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp103(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,5, 2,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,2);
+ pathB.cubicTo(1,2, 1,0, 5,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp104(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,6, 4,0, 6,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,4);
+ pathB.cubicTo(1,6, 1,0, 6,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp105(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,4, 6,5, 2,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(5,6);
+ pathB.cubicTo(0,2, 1,0, 4,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp106(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(4, 6, 2, 1, 2, 0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(0, 2, 1, 0, 6, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp107(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(4, 6, 2, 1, 2, 0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(0, 2, 1, 0, 6, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp108(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(4, 6, 2, 1, 2, 0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(0, 2, 1, 0, 6, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void cubicOp109(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(4,5, 6,3, 5,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3,6);
+ pathB.cubicTo(4,5, 1,0, 5,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp110(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(0, 0, 4, 4, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp111(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1,4);
+ path.cubicTo(0,5, 4,1, 3,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,4);
+ pathB.cubicTo(1,3, 4,1, 5,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void xOp1u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1, 4);
+ path.cubicTo(4, 5, 3, 2, 6, 3);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(2, 3);
+ pathB.cubicTo(3, 6, 4, 1, 5, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void xOp1i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1, 4);
+ path.cubicTo(1, 5, 6, 0, 5, 1);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(0, 6);
+ pathB.cubicTo(1, 5, 4, 1, 5, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void xOp2i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(0, 4, 3, 2, 6, 1);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(2, 3);
+ pathB.cubicTo(1, 6, 5, 1, 4, 0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void xOp3i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1,4);
+ path.cubicTo(0,5, 4,1, 3,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,4);
+ pathB.cubicTo(1,3, 4,1, 5,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void findFirst1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,6, 5,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,5);
+ pathB.cubicTo(1,2, 1,0, 6,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+// triggers addSimpleAngle with non-zero argument
+static void cubicOp112(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2,4);
+ path.cubicTo(2,3, 6,4, 1,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(4,6);
+ pathB.cubicTo(0,1, 4,2, 3,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp113(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(2,4);
+ path.cubicTo(3,5, 2.33333325f,4.33333349f, 3.83333325f,3.83333349f);
+ path.close();
+ pathB.moveTo(3,5);
+ pathB.cubicTo(2.33333325f,4.33333349f, 3.83333325f,3.83333349f, 2,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void cubicOp114(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return;
+ }
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(1, 3, -1, 2, 3.5f, 1.33333337f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 3);
+ pathB.cubicTo(-1, 2, 3.5f, 1.33333337f, 0, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void cubicOp114asQuad(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(1, 3, -1, 2, 3.5f, 1.33333337f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 3);
+ pathB.cubicTo(-1, 2, 3.5f, 1.33333337f, 0, 1);
+ pathB.close();
+ SkPath qPath, qPathB;
+ CubicPathToQuads(path, &qPath);
+ CubicPathToQuads(pathB, &qPathB);
+ testPathOp(reporter, qPath, qPathB, kIntersect_PathOp, filename);
+}
+
+static void quadOp10i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.quadTo(1, 8, 3, 5);
+ path.lineTo(8, 1);
+ path.close();
+ pathB.moveTo(0, 0);
+ pathB.quadTo(8, 1, 4, 8);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void kari1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1;
+ path1.moveTo(39.9375, -5.8359375);
+ path1.lineTo(40.625, -5.7890625);
+ path1.lineTo(37.7109375, 1.3515625);
+ path1.lineTo(37.203125, 0.9609375);
+ path1.close();
+
+ SkPath path2;
+ path2.moveTo(37.52734375f, -1.44140625f);
+ path2.cubicTo(37.8736991882324f, -1.69921875f, 38.1640625f, -2.140625f, 38.3984375f, -2.765625f);
+ path2.lineTo(38.640625f, -2.609375f);
+ path2.cubicTo(38.53125f, -1.89583337306976f, 38.0664443969727f, -0.154893040657043f, 38.0664443969727f, -0.154893040657043f);
+ path2.cubicTo(38.0664443969727f, -0.154893040657043f, 37.1809883117676f, -1.18359375f, 37.52734375, -1.44140625f);
+ path2.close();
+
+ testPathOp(reporter, path1, path2, kDifference_PathOp, filename);
+}
+
+static void issue2504(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1;
+ path1.moveTo(34.2421875, -5.976562976837158203125);
+ path1.lineTo(35.453121185302734375, 0);
+ path1.lineTo(31.9375, 0);
+ path1.close();
+
+ SkPath path2;
+ path2.moveTo(36.71843719482421875, 0.8886508941650390625);
+ path2.cubicTo(36.71843719482421875, 0.8886508941650390625,
+ 35.123386383056640625, 0.554015457630157470703125,
+ 34.511409759521484375, -0.1152553558349609375);
+ path2.cubicTo(33.899425506591796875, -0.7845261096954345703125,
+ 34.53484344482421875, -5.6777553558349609375,
+ 34.53484344482421875, -5.6777553558349609375);
+ path2.close();
+ testPathOp(reporter, path1, path2, kUnion_PathOp, filename);
+}
+
+static void issue2540(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1;
+ path1.moveTo(26.5054988861083984375, 85.73960113525390625);
+ path1.cubicTo(84.19739532470703125, 17.77140045166015625, 16.93920135498046875, 101.86199951171875, 12.631000518798828125, 105.24700164794921875);
+ path1.cubicTo(11.0819997787475585937500000, 106.46399688720703125, 11.5260000228881835937500000, 104.464996337890625, 11.5260000228881835937500000, 104.464996337890625);
+ path1.lineTo(23.1654987335205078125, 89.72879791259765625);
+ path1.cubicTo(23.1654987335205078125, 89.72879791259765625, -10.1713008880615234375, 119.9160003662109375, -17.1620006561279296875, 120.8249969482421875);
+ path1.cubicTo(-19.1149997711181640625, 121.07900238037109375, -18.0380001068115234375, 119.79299163818359375, -18.0380001068115234375, 119.79299163818359375);
+ path1.cubicTo(-18.0380001068115234375, 119.79299163818359375, 14.22100067138671875, 90.60700225830078125, 26.5054988861083984375, 85.73960113525390625);
+ path1.close();
+
+ SkPath path2;
+ path2.moveTo(-25.077999114990234375, 124.9120025634765625);
+ path2.cubicTo(-25.077999114990234375, 124.9120025634765625, -25.9509983062744140625, 125.95400238037109375, -24.368999481201171875, 125.7480010986328125);
+ path2.cubicTo(-16.06999969482421875, 124.66899871826171875, 1.2680000066757202148437500, 91.23999786376953125, 37.264003753662109375, 95.35400390625);
+ path2.cubicTo(37.264003753662109375, 95.35400390625, 11.3710002899169921875, 83.7339935302734375, -25.077999114990234375, 124.9120025634765625);
+ path2.close();
+ testPathOp(reporter, path1, path2, kUnion_PathOp, filename);
+}
+
+static void rects1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(1, 1);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(6, 0);
+ path.lineTo(6, 6);
+ path.lineTo(0, 6);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(0, 0);
+ pathB.lineTo(1, 0);
+ pathB.lineTo(1, 1);
+ pathB.lineTo(0, 1);
+ pathB.close();
+ pathB.moveTo(0, 0);
+ pathB.lineTo(2, 0);
+ pathB.lineTo(2, 2);
+ pathB.lineTo(0, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+static void rects2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(4, 0);
+ path.lineTo(4, 4);
+ path.lineTo(0, 4);
+ path.close();
+ path.moveTo(3, 3);
+ path.lineTo(4, 3);
+ path.lineTo(4, 4);
+ path.lineTo(3, 4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3, 3);
+ pathB.lineTo(6, 3);
+ pathB.lineTo(6, 6);
+ pathB.lineTo(3, 6);
+ pathB.close();
+ pathB.moveTo(3, 3);
+ pathB.lineTo(4, 3);
+ pathB.lineTo(4, 4);
+ pathB.lineTo(3, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void rects3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(0, 0, 4, 4, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void rects4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addRect(0, 0, 2, 2, SkPath::kCW_Direction);
+ pathB.addRect(0, 0, 3, 3, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void issue2753(skiatest::Reporter* reporter, const char* filename) {
+ if (!FLAGS_runFail) {
+ return;
+ }
+ SkPath path1;
+ path1.moveTo(142.701f, 110.568f);
+ path1.lineTo(142.957f, 100);
+ path1.lineTo(153.835f, 100);
+ path1.lineTo(154.592f, 108.188f);
+ path1.cubicTo(154.592f, 108.188f, 153.173f, 108.483f, 152.83f, 109.412f);
+ path1.cubicTo(152.83f, 109.412f, 142.701f, 110.568f, 142.701f, 110.568f);
+ path1.close();
+
+ SkPath path2;
+ path2.moveTo(39, 124.001f);
+ path2.cubicTo(39, 124.001f, 50.6f, 117.001f, 50.6f, 117.001f);
+ path2.cubicTo(50.6f, 117.001f, 164.601f, 85.2f, 188.201f, 117.601f);
+ path2.cubicTo(188.201f, 117.601f, 174.801f, 93, 39, 124.001f);
+ path2.close();
+
+ testPathOp(reporter, path1, path2, kUnion_PathOp, filename);
+}
+
+static void issue2808(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1, path2;
+
+ path1.moveTo(509.20300293f, 385.601989746f);
+ path1.quadTo(509.20300293f, 415.68838501f, 487.928710938f, 436.96270752f);
+ path1.quadTo(466.654388428f, 458.236999512f, 436.567993164f, 458.236999512f);
+ path1.quadTo(406.4815979f, 458.236999512f, 385.207275391f, 436.96270752f);
+ path1.quadTo(363.932983398f, 415.68838501f, 363.932983398f, 385.601989746f);
+ path1.quadTo(363.932983398f, 355.515594482f, 385.207275391f, 334.241271973f);
+ path1.quadTo(406.4815979f, 312.96697998f, 436.567993164f, 312.96697998f);
+ path1.quadTo(466.654388428f, 312.96697998f, 487.928710938f, 334.241271973f);
+ path1.quadTo(509.20300293f, 355.515594482f, 509.20300293f, 385.601989746f);
+ path1.close();
+
+ path2.moveTo(449.033996582f, 290.87298584f);
+ path2.quadTo(449.033996582f, 301.028259277f, 441.853149414f, 308.209106445f);
+ path2.quadTo(434.672271729f, 315.389984131f, 424.516998291f, 315.389984131f);
+ path2.quadTo(414.361724854f, 315.389984131f, 407.180847168f, 308.209106445f);
+ path2.quadTo(400, 301.028259277f, 400, 290.87298584f);
+ path2.quadTo(400, 280.717712402f, 407.180847168f, 273.536865234f);
+ path2.quadTo(414.361724854f, 266.355987549f, 424.516998291f, 266.355987549f);
+ path2.quadTo(434.672271729f, 266.355987549f, 441.853149414f, 273.536865234f);
+ path2.quadTo(449.033996582f, 280.717712402f, 449.033996582f, 290.87298584f);
+ path2.close();
+
+ testPathOp(reporter, path1, path2, kUnion_PathOp, filename);
+}
+
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
+static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
+
+static struct TestDesc tests[] = {
+ TEST(issue2753), // FIXME: pair of cubics miss intersection
+ TEST(cubicOp114), // FIXME: curve with inflection is ordered the wrong way
+ TEST(issue2808),
+ TEST(cubicOp114asQuad),
+ TEST(rects4),
+ TEST(rects3),
+ TEST(rects2),
+ TEST(rects1),
+ TEST(issue2540),
+ TEST(issue2504),
+ TEST(kari1),
+ TEST(quadOp10i),
+ TEST(cubicOp113),
+ // fails because a cubic/quadratic intersection is missed
+ // the internal quad/quad is far enough away from the real cubic/quad that it is rejected
+ TEST(skpcarrot_is24),
+ TEST(issue1417),
+ TEST(cubicOp112),
+ TEST(skpadspert_net23),
+ TEST(skpadspert_de11),
+ TEST(findFirst1),
+ TEST(xOp2i),
+ TEST(xOp3i),
+ TEST(xOp1u),
+ TEST(xOp1i),
+ TEST(cubicOp111),
+ TEST(cubicOp110),
+ TEST(cubicOp109),
+ TEST(cubicOp108),
+ TEST(cubicOp107),
+ TEST(cubicOp106),
+ TEST(cubicOp105),
+ TEST(cubicOp104),
+ TEST(cubicOp103),
+ TEST(cubicOp102),
+ TEST(cubicOp101),
+ TEST(cubicOp100),
+ TEST(cubicOp99),
+ TEST(issue1435),
+ TEST(cubicOp98x),
+ TEST(cubicOp97x),
+ TEST(skpcarpetplanet_ru22), // cubic/cubic intersect detects unwanted coincidence
+ TEST(cubicOp96d),
+ TEST(cubicOp95u),
+ TEST(skpadbox_lt15),
+ TEST(skpagentxsites_com55),
+ TEST(skpadventistmission_org572),
+ TEST(skpadoption_org196),
+ TEST(skpbambootheme_com12),
+ TEST(skpbakosoft_com10),
+ TEST(skpakmmos_ru100),
+ TEST(skpbangalorenest_com4),
+ TEST(skpbingoentertainment_net189),
+ TEST(skpbestred_ru37),
+ TEST(skpbenzoteh_ru152),
+ TEST(skpcamcorder_kz21),
+ TEST(skpcaffelavazzait_com_ua21),
+ TEST(skpcarrefour_ro62),
+ TEST(skpcavablar_net563),
+ TEST(skpinsomnia_gr72),
+ TEST(skpadbox_lt8),
+ TEST(skpact_com43),
+ TEST(skpacesoftech_com47),
+ TEST(skpabcspark_ca103),
+ TEST(cubicOp94u),
+ TEST(cubicOp93d),
+ TEST(cubicOp92i),
+ TEST(skpadithya_putr4_blogspot_com551),
+ TEST(skpadindex_de4),
+ TEST(skpaiaigames_com870),
+ TEST(skpaaalgarve_org53),
+ TEST(skpkkiste_to716),
+ TEST(cubicOp91u),
+ TEST(cubicOp90u),
+ TEST(cubicOp89u),
+ TEST(cubicOp88u),
+ TEST(cubicOp87u),
+ TEST(cubicOp86i),
+ TEST(loopEdge2),
+ TEST(loopEdge1),
+ TEST(rectOp3x),
+ TEST(rectOp2i),
+ TEST(rectOp1i),
+ TEST(issue1418b),
+ TEST(cubicOp85i),
+ TEST(issue1418),
+ TEST(skpkkiste_to98),
+ TEST(skpahrefs_com29),
+ TEST(cubicOp85d),
+ TEST(skpahrefs_com88),
+ TEST(skphealth_com76),
+ TEST(skpancestry_com1),
+ TEST(skpbyte_com1),
+ TEST(skpeldorado_com_ua1),
+ TEST(skp96prezzi1),
+ TEST(skpClip2),
+ TEST(skpClip1),
+ TEST(cubicOp84d),
+ TEST(cubicOp83i),
+ TEST(cubicOp82i),
+ TEST(cubicOp81d),
+ TEST(cubicOp80i),
+ TEST(cubicOp79u),
+ TEST(cubicOp78u),
+ TEST(cubicOp77i),
+ TEST(cubicOp76u),
+ TEST(cubicOp75d),
+ TEST(cubicOp74d),
+ TEST(cubicOp73d),
+ TEST(cubicOp72i),
+ TEST(cubicOp71d),
+ TEST(skp5),
+ TEST(skp4),
+ TEST(skp3),
+ TEST(skp2),
+ TEST(skp1),
+ TEST(rRect1),
+ TEST(cubicOp70d),
+ TEST(cubicOp69d),
+ TEST(cubicOp68u),
+ TEST(cubicOp67u),
+ TEST(cubicOp66u),
+ TEST(rectOp1d),
+ TEST(cubicOp65d),
+ TEST(cubicOp64d),
+ TEST(cubicOp63d),
+ TEST(cubicOp62d),
+ TEST(cubicOp61d),
+ TEST(cubicOp60d),
+ TEST(cubicOp59d),
+ TEST(cubicOp58d),
+ TEST(cubicOp57d),
+ TEST(cubicOp56d),
+ TEST(cubicOp55d),
+ TEST(cubicOp54d),
+ TEST(cubicOp53d),
+ TEST(cubicOp52d),
+ TEST(cubicOp51d),
+ TEST(cubicOp50d),
+ TEST(cubicOp49d),
+ TEST(cubicOp48d),
+ TEST(cubicOp47d),
+ TEST(cubicOp46d),
+ TEST(cubicOp45d),
+ TEST(cubicOp44d),
+ TEST(cubicOp43d),
+ TEST(cubicOp42d),
+ TEST(cubicOp41i),
+ TEST(cubicOp40d),
+ TEST(cubicOp39d),
+ TEST(cubicOp38d),
+ TEST(cubicOp37d),
+ TEST(cubicOp36u),
+ TEST(cubicOp35d),
+ TEST(cubicOp34d),
+ TEST(cubicOp33i),
+ TEST(cubicOp32d),
+ TEST(cubicOp31d),
+ TEST(cubicOp31x),
+ TEST(cubicOp31u),
+ TEST(cubicOp30d),
+ TEST(cubicOp29d),
+ TEST(cubicOp28u),
+ TEST(cubicOp27d),
+ TEST(cubicOp26d),
+ TEST(cubicOp25i),
+ TEST(testOp8d),
+ TEST(testDiff1),
+ TEST(testIntersect1),
+ TEST(testUnion1),
+ TEST(testXor1),
+ TEST(testDiff2),
+ TEST(testIntersect2),
+ TEST(testUnion2),
+ TEST(testXor2),
+ TEST(testOp1d),
+ TEST(testOp2d),
+ TEST(testOp3d),
+ TEST(testOp1u),
+ TEST(testOp4d),
+ TEST(testOp5d),
+ TEST(testOp6d),
+ TEST(testOp7d),
+ TEST(testOp2u),
+
+ TEST(cubicOp24d),
+ TEST(cubicOp23d),
+ TEST(cubicOp22d),
+ TEST(cubicOp21d),
+ TEST(cubicOp20d),
+ TEST(cubicOp19i),
+ TEST(cubicOp18d),
+ TEST(cubicOp17d),
+ TEST(cubicOp16d),
+ TEST(cubicOp15d),
+ TEST(cubicOp14d),
+ TEST(cubicOp13d),
+ TEST(cubicOp12d),
+ TEST(cubicOp11d),
+ TEST(cubicOp10d),
+ TEST(cubicOp1i),
+ TEST(cubicOp9d),
+ TEST(quadOp9d),
+ TEST(lineOp9d),
+ TEST(cubicOp8d),
+ TEST(cubicOp7d),
+ TEST(cubicOp6d),
+ TEST(cubicOp5d),
+ TEST(cubicOp3d),
+ TEST(cubicOp2d),
+ TEST(cubicOp1d),
+};
+
+static const size_t testCount = SK_ARRAY_COUNT(tests);
+
+static void cubicOp117(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(4,5, 6,0, 1,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(0,1, 1,0, 5,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp118(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(4,6, 5,1, 6,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,5);
+ pathB.cubicTo(2,6, 1,0, 6,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void loop1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,1);
+ path.cubicTo(1,5, -5.66666651f,3.33333349f, 8.83333302f,2.33333349f);
+ path.close();
+ pathB.moveTo(1,5);
+ pathB.cubicTo(-5.66666651f,3.33333349f, 8.83333302f,2.33333349f, 0,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+#include "SkPathOpsCubic.h"
+
+static void loop1asQuad(skiatest::Reporter* reporter, const char* filename) {
+ SkDCubic c1 = {{{0,1}, {1,5}, {-5.66666651f,3.33333349f}, {8.83333302f,2.33333349f}}};
+ SkDCubic c2 = {{{1,5}, {-5.66666651f,3.33333349f}, {8.83333302f,2.33333349f}, {0,1}}};
+ double c1InflectionTs[2], c2InflectionTs[2];
+ SkDEBUGCODE(int c1InfTCount =) c1.findInflections(c1InflectionTs);
+ SkASSERT(c1InfTCount == 2);
+ SkDEBUGCODE(int c2InfTCount =) c2.findInflections(c2InflectionTs);
+ SkASSERT(c2InfTCount == 1);
+ SkASSERT(c1InflectionTs[0] > c1InflectionTs[1]);
+ SkDCubicPair c1pair = c1.chopAt(c1InflectionTs[0]);
+ SkDCubicPair c1apair = c1pair.first().chopAt(c1InflectionTs[1]);
+ SkDCubicPair c2pair = c2.chopAt(c2InflectionTs[0]);
+ SkDQuad q1[2] = { c1pair.first().toQuad(), c1pair.second().toQuad() };
+ SkDQuad q1a[2] = { c1apair.first().toQuad(), c1apair.second().toQuad() };
+ SkDQuad q2[2] = { c2pair.first().toQuad(), c2pair.second().toQuad() };
+ SkPath path, pathB;
+ path.moveTo(q1a[0].fPts[0].asSkPoint());
+ path.quadTo(q1a[0].fPts[1].asSkPoint(), q1a[0].fPts[2].asSkPoint());
+ path.quadTo(q1a[1].fPts[1].asSkPoint(), q1a[1].fPts[2].asSkPoint());
+ path.quadTo(q1[1].fPts[1].asSkPoint(), q1[1].fPts[2].asSkPoint());
+ path.close();
+ pathB.moveTo(q2[0].fPts[0].asSkPoint());
+ pathB.quadTo(q2[0].fPts[1].asSkPoint(), q2[0].fPts[2].asSkPoint());
+ pathB.quadTo(q2[1].fPts[1].asSkPoint(), q2[1].fPts[2].asSkPoint());
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loop2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,1);
+ path.cubicTo(3,4, 3.f,4.f, 4.5f,1.5f);
+ path.close();
+ pathB.moveTo(3,4);
+ pathB.cubicTo(3.f,4.f, 4.5f,1.5f, 0,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loop3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,1);
+ path.cubicTo(3,5, -3.66666651f,0, 10.5f,-1.66666651f);
+ path.close();
+ pathB.moveTo(3,5);
+ pathB.cubicTo(-3.66666651f,0, 10.5f,-1.66666651f, 0,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loop4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,5);
+ path.cubicTo(1,5, 1,4, 0.833333313f,3);
+ path.close();
+ pathB.moveTo(1,5);
+ pathB.cubicTo(1,4, 0.833333313f,3, 0,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+#include "SkParsePath.h"
+
+static void issue3517(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+
+ const char str[] = "M31.35 57.75L31.35 57.75C31.9 57.7486 32.45 57.7948 33 57.7413C33.55 57.6878 34.1 57.5014 34.65 57.4291C35.2 57.3569 35.75 57.3223 36.3 57.3079C36.85 57.2935 37.4 57.3143 37.95 57.3428C38.5 57.3712 39.05 57.4112 39.6 57.4786C40.15 57.546 40.7 57.7029 41.25 57.7472C41.8 57.7916 42.35 57.7962 42.9 57.7445C43.45 57.6928 44 57.5345 44.55 57.4373C45.1 57.34 45.65 57.2115 46.2 57.1611C46.75 57.1107 47.3 57.1371 47.85 57.1349C48.4 57.1327 48.95 57.144 49.5 57.1478C50.05 57.1516 50.6 57.1553 51.15 57.1579C51.7 57.1605 52.25 57.1601 52.8 57.1634C53.35 57.1667 53.9 57.1731 54.45 57.1776C55 57.182 55.55 57.1916 56.1 57.19C56.65 57.1884 57.2 57.178 57.75 57.168C58.3 57.158 58.85 57.1355 59.4 57.1299C59.95 57.1243 60.5 57.1338 61.05 57.1345C61.6 57.1352 62.15 57.124 62.7 57.134C63.25 57.1441 63.8 57.1731 64.35 57.195C64.9 57.2169 65.45 57.2532 66 57.2655C66.55 57.2778 67.1 57.2647 67.65 57.2687C68.2 57.2728 68.75 57.267 69.3 57.2896C69.85 57.3122 70.4 57.371 70.95 57.4044C71.5 57.4377 72.05 57.4668 72.6 57.4896C73.15 57.5123 73.7 57.545 74.25 57.5408C74.8 57.5365 75.35 57.5068 75.9 57.4641C76.45 57.4213 77 57.3244 77.55 57.2842C78.1 57.244 78.65 57.2163 79.2 57.2228C79.75 57.2293 80.3 57.29 80.85 57.3232C81.4 57.3563 81.95 57.396 82.5 57.4219C83.05 57.4478 83.6 57.4637 84.15 57.4787C84.7 57.4937 85.25 57.5011 85.8 57.5121C86.35 57.523 86.9 57.5411 87.45 57.5444C88 57.5477 88.55 57.5663 89.1 57.5318C89.65 57.4972 90.2 57.3126 90.75 57.337C91.3 57.3613 91.85 57.6088 92.4 57.6776C92.95 57.7465 93.5 57.7379 94.05 57.75C94.6 57.7621 95.15 57.75 95.7 57.75L95.7 57.75L31.35 57.75Z";
+ SkParsePath::FromSVGString(str, &path);
+
+ const char strB[] = "M31.35 57.75L31.35 57.75C31.9 57.7514 32.45 57.7052 33 57.7587C33.55 57.8122 34.1 57.9986 34.65 58.0709C35.2 58.1431 35.75 58.1777 36.3 58.1921C36.85 58.2065 37.4 58.1857 37.95 58.1572C38.5 58.1288 39.05 58.0888 39.6 58.0214C40.15 57.954 40.7 57.7971 41.25 57.7528C41.8 57.7084 42.35 57.7038 42.9 57.7555C43.45 57.8072 44 57.9655 44.55 58.0627C45.1 58.16 45.65 58.2885 46.2 58.3389C46.75 58.3893 47.3 58.3629 47.85 58.3651C48.4 58.3673 48.95 58.356 49.5 58.3522C50.05 58.3484 50.6 58.3447 51.15 58.3421C51.7 58.3395 52.25 58.3399 52.8 58.3366C53.35 58.3333 53.9 58.3269 54.45 58.3224C55 58.318 55.55 58.3084 56.1 58.31C56.65 58.3116 57.2 58.322 57.75 58.332C58.3 58.342 58.85 58.3645 59.4 58.3701C59.95 58.3757 60.5 58.3662 61.05 58.3655C61.6 58.3648 62.15 58.376 62.7 58.366C63.25 58.3559 63.8 58.3269 64.35 58.305C64.9 58.2831 65.45 58.2468 66 58.2345C66.55 58.2222 67.1 58.2353 67.65 58.2313C68.2 58.2272 68.75 58.233 69.3 58.2104C69.85 58.1878 70.4 58.129 70.95 58.0956C71.5 58.0623 72.05 58.0332 72.6 58.0104C73.15 57.9877 73.7 57.955 74.25 57.9592C74.8 57.9635 75.35 57.9932 75.9 58.0359C76.45 58.0787 77 58.1756 77.55 58.2158C78.1 58.256 78.65 58.2837 79.2 58.2772C79.75 58.2707 80.3 58.21 80.85 58.1768C81.4 58.1437 81.95 58.104 82.5 58.0781C83.05 58.0522 83.6 58.0363 84.15 58.0213C84.7 58.0063 85.25 57.9989 85.8 57.9879C86.35 57.977 86.9 57.9589 87.45 57.9556C88 57.9523 88.55 57.9337 89.1 57.9682C89.65 58.0028 90.2 58.1874 90.75 58.163C91.3 58.1387 91.85 57.8912 92.4 57.8224C92.95 57.7535 93.5 57.7621 94.05 57.75C94.6 57.7379 95.15 57.75 95.7 57.75L95.7 57.75L31.35 57.75Z";
+ SkParsePath::FromSVGString(strB, &pathB);
+ testPathOp(reporter, path, pathB, kUnion_SkPathOp, filename);
+}
+
+static void cubicOp119(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,5, 2,1, 3,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(1,3, 1,0, 5,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void cubicOp120(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,4, 2,1, 4,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(0,4, 1,0, 4,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp121(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,4, 3,2, 4,3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,3);
+ pathB.cubicTo(3,4, 1,0, 4,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+// FIXME : haven't debugged this failure yet
+static void cubicOp122(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,5, 4,1, 4,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,4);
+ pathB.cubicTo(0,4, 1,0, 5,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp123(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,5, 2,0, 6,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,2);
+ pathB.cubicTo(0,6, 1,0, 5,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void loop5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,2);
+ path.cubicTo(1,2, 1,1.66666663f, 0.833333313f,1.33333325f);
+ path.close();
+ pathB.moveTo(1,2);
+ pathB.cubicTo(1,1.66666663f, 0.833333313f,1.33333325f, 0,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loop6(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,1);
+ path.cubicTo(1,3, -1.66666675f,1.66666663f, 4.16666651f,1.00000012f);
+ path.close();
+ pathB.moveTo(1,3);
+ pathB.cubicTo(-1.66666675f,1.66666663f, 4.16666651f,1.00000012f, 0,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void cubicOp124(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,5, 6,0, 3,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(0,3, 1,0, 5,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp125(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,6, 3,1, 6,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,3);
+ pathB.cubicTo(2,6, 1,0, 6,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp126(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,3, 6,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(1,2, 1,0, 3,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp127(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,5, 6,0, 3,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(0,3, 1,0, 5,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void cubicOp128(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,3, 3,2, 5,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,3);
+ pathB.cubicTo(2,5, 1,0, 3,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp129(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(5,6);
+ path.cubicTo(3,4, 2,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,2);
+ pathB.cubicTo(1,2, 6,5, 4,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp130(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(5,6);
+ path.cubicTo(4,6, 3,0, 2,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,3);
+ pathB.cubicTo(1,2, 6,5, 6,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+#include "SkGeometry.h"
+
+static void complex_to_quads(const SkPoint pts[], SkPath* path) {
+ SkScalar loopT;
+ SkDCubic::CubicType dType;
+ if (SkDCubic::ComplexBreak(pts, &loopT, &dType)) {
+ SkPoint cubicPair[7];
+ SkChopCubicAt(pts, cubicPair, loopT);
+ SkDCubic c1, c2;
+ c1.set(cubicPair);
+ c2.set(&cubicPair[3]);
+ SkDQuad q1 = c1.toQuad();
+ SkDQuad q2 = c2.toQuad();
+ path->quadTo(q1[1].asSkPoint(), q1[2].asSkPoint());
+ path->quadTo(q2[1].asSkPoint(), q2[2].asSkPoint());
+ } else {
+ path->cubicTo(pts[1], pts[2], pts[3]);
+ }
+}
+
+static void cubicOp130a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(5,6);
+ SkPoint pts[] = { {5,6}, {4,6}, {3,0}, {2,1} };
+ complex_to_quads(pts, &path);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,3);
+ SkPoint pts2[] = { {0,3}, {1,2}, {6,5}, {6,4} };
+ complex_to_quads(pts2, &path);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp131(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,4, 3,0, 6,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,3);
+ pathB.cubicTo(2,6, 1,0, 4,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void circlesOp1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addCircle(0, 1, 2, SkPath::kCCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addCircle(0, 1, 1, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void circlesOp2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addCircle(0, 1, 4, SkPath::kCCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addCircle(0, 4, 3, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void rRect1x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(20.65f, 5.65f);
+ path.conicTo(20.65f, 1.13612f, 25.1404f, 0.65f, 0.888488f);
+ path.lineTo(25.65f, 0.65f);
+ path.lineTo(26.1596f, 0.67604f);
+ path.conicTo(30.65f, 1.13612f, 30.65f, 5.65f, 0.888488f);
+ path.lineTo(30.65f, 25.65f);
+ path.conicTo(30.65f, 20.65f, 25.65f, 20.65f, 0.707107f);
+ path.lineTo(20.65f, 20.65f);
+ path.lineTo(20.65f, 5.65f);
+ path.close();
+ path.moveTo(20.65f, 20.65f);
+ path.lineTo(5.65f, 20.65f);
+ path.conicTo(0.65f, 20.65f, 0.65f, 25.65f, 0.707107f);
+ path.lineTo(0.65f, 45.65f);
+ path.conicTo(0.65f, 50.65f, 5.65f, 50.65f, 0.707107f);
+ path.lineTo(25.65f, 50.65f);
+ path.conicTo(30.65f, 50.65f, 30.65f, 45.65f, 0.707107f);
+ path.lineTo(30.65f, 25.65f);
+ path.conicTo(30.65f, 30.65f, 25.65f, 30.65f, 0.707107f);
+ path.conicTo(20.65f, 30.65f, 20.65f, 25.65f, 0.707107f);
+ path.lineTo(20.65f, 20.65f);
+ path.close();
+ SkPath path1(path);
+
+ path.reset();
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(20.65f, 45.65f);
+ path.lineTo(20.65f, 25.65f);
+ path.conicTo(20.65f, 20.65f, 25.65f, 20.65f, 0.707107f);
+ path.lineTo(45.65f, 20.65f);
+ path.conicTo(50.65f, 20.65f, 50.65f, 25.65f, 0.707107f);
+ path.lineTo(50.65f, 45.65f);
+ path.conicTo(50.65f, 50.65f, 45.65f, 50.65f, 0.707107f);
+ path.lineTo(25.65f, 50.65f);
+ path.conicTo(20.65f, 50.65f, 20.65f, 45.65f, 0.707107f);
+ path.close();
+ SkPath path2(path);
+
+ testPathOp(reporter, path1, path2, kDifference_SkPathOp, filename);
+}
+
+static void loop7(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,1);
+ path.cubicTo(3,4, -1,0, 8.5f,-2.5f);
+ path.close();
+ pathB.moveTo(3,4);
+ pathB.cubicTo(-1,0, 8.5f,-2.5f, 0,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void rects5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addRect(5, 5, 6, 6, SkPath::kCW_Direction);
+ path.addRect(5, 5, 6, 6, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.addRect(0, 0, 6, 6, SkPath::kCW_Direction);
+ pathB.addRect(5, 5, 6, 6, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void loop8(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,1);
+ path.cubicTo(1,4, -3.83333325f,0.166666627f, 6,-1);
+ path.close();
+ pathB.moveTo(1,4);
+ pathB.cubicTo(-3.83333325f,0.166666627f, 6,-1, 0,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loop9(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,1);
+ path.cubicTo(1,3, -2.5f,0, 3.33333325f,-0.666666627f);
+ path.close();
+ pathB.moveTo(1,3);
+ pathB.cubicTo(-2.5f,0, 3.33333325f,-0.666666627f, 0,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void circlesOp3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addCircle(0, 1, 2, SkPath::kCCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addCircle(3, 5, 3, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void loop10(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(5,6);
+ path.cubicTo(1,2, 1,2, -3.66666651f,13.333334f);
+ path.close();
+ pathB.moveTo(1,2);
+ pathB.cubicTo(1,2, -3.66666651f,13.333334f, 5,6);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loop11(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(0,1);
+ path.cubicTo(1,3, -1.83333349f,1.33333337f, 4,-1);
+ path.close();
+ pathB.moveTo(1,3);
+ pathB.cubicTo(-1.83333349f,1.33333337f, 4,-1, 0,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void cubicOp132(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(5,6);
+ path.cubicTo(3,4, 3,0, 3,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,3);
+ pathB.cubicTo(2,3, 6,5, 4,3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void loop12(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(1,2);
+ path.cubicTo(0,6, -3.16666675f,3.66666675f, 6.33333349f,3.33333349f);
+ path.close();
+ pathB.moveTo(0,6);
+ pathB.cubicTo(-3.16666675f,3.66666675f, 6.33333349f,3.33333349f, 1,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void cubicOp133(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(5,6);
+ path.cubicTo(5,6, 5,0, 4,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,5);
+ pathB.cubicTo(1,4, 6,5, 6,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp134(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(5,6);
+ path.cubicTo(5,6, 6,0, 3,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(1,3, 6,5, 6,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp135(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(5,6);
+ path.cubicTo(5,6, 6,0, 4,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,6);
+ pathB.cubicTo(1,4, 6,5, 6,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp136(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(5,6);
+ path.cubicTo(5,6, 5,0, 3,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,5);
+ pathB.cubicTo(1,3, 6,5, 6,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp136a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(5,6);
+ path.quadTo(5,0, 3,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,5);
+ pathB.cubicTo(1,3, 6,5, 6,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics137(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 5);
+ path.cubicTo(3, 6, 1, 0, 3, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 1);
+ pathB.cubicTo(2, 3, 5, 0, 6, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics138(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 5);
+ path.cubicTo(3, 6, 1, 0, 4, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 1);
+ pathB.cubicTo(2, 4, 5, 0, 6, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+// three curves intersect successfully nearby -- the angle only gets 2 of the 3 pts
+static void cubicOp139(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(0,4, 3,1, 5,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,3);
+ pathB.cubicTo(1,5, 2,0, 4,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp140(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(1,2, 5,4, 3,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(4,5);
+ pathB.cubicTo(2,3, 2,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp141(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(1,2, 6,4, 3,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(4,6);
+ pathB.cubicTo(2,3, 2,0, 2,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void quadRect1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(6,15);
+ path.quadTo(16,0, 8,4);
+ path.quadTo(2,7, 12,12);
+ path.close();
+ pathB.addRect(4,11, 13,16);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void quadRect2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(5,12);
+ path.quadTo(15,7, 9,4);
+ path.quadTo(1,0, 11,15);
+ path.close();
+ pathB.addRect(4,11, 13,16);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void quadRect3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(12,12);
+ path.quadTo(2,7, 8,4);
+ path.quadTo(16,0, 6,15);
+ path.close();
+ pathB.addRect(4,11, 13,16);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void quadRect4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(11,15);
+ path.quadTo(1,0, 9,4);
+ path.quadTo(15,7, 5,12);
+ path.close();
+ pathB.addRect(4,11, 13,16);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void quadRect5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(11,13);
+ path.quadTo(4,4, 8,4);
+ path.quadTo(12,4, 5,13);
+ path.close();
+ pathB.addRect(4,11, 13,16);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void quadRect6(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(5,13);
+ path.quadTo(12,4, 8,4);
+ path.quadTo(4,4, 11,13);
+ path.close();
+ pathB.addRect(4,11, 13,16);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops4i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 3);
+ path.cubicTo(0, 2, 0, 2, -1.66666663f, 2.16666675f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(0, 2, -1.66666663f, 2.16666675f, 0, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops5i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(0, 2, 0, 2, 0.166666672f, 2.66666675f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(0, 2, 0.166666672f, 2.66666675f, 1, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void cubicOp142(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(5,6);
+ path.cubicTo(2,5, 2,1, 1,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(0,1, 6,5, 5,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics6d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 5);
+ path.cubicTo(1, 5, 4, 2, 4, 0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 4);
+ pathB.cubicTo(0, 4, 5, 3, 5, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics7d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 6);
+ path.cubicTo(2, 4, 5, 1, 3, 1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 5);
+ pathB.cubicTo(1, 3, 6, 2, 4, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics8d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 5);
+ path.cubicTo(2, 4, 5, 1, 3, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 5);
+ pathB.cubicTo(2, 3, 5, 2, 4, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics9d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 4);
+ path.cubicTo(2, 6, 3, 1, 5, 1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 3);
+ pathB.cubicTo(1, 5, 4, 2, 6, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics10u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 4);
+ path.cubicTo(1, 6, 4, 1, 5, 1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(1, 5, 4, 2, 6, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_SkPathOp, filename);
+}
+
+static void cubics11i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 4);
+ path.cubicTo(2, 5, 3, 2, 5, 1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 3);
+ pathB.cubicTo(1, 5, 4, 2, 5, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void cubics12d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 4);
+ path.cubicTo(0, 4, 5, 3, 5, 1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3, 5);
+ pathB.cubicTo(1, 5, 4, 2, 4, 0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics13d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 3);
+ path.cubicTo(1, 5, 4, 2, 5, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 4);
+ pathB.cubicTo(2, 5, 3, 2, 5, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics14d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 3);
+ path.cubicTo(0, 4, 3, 1, 3, 0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 3);
+ pathB.cubicTo(0, 3, 3, 2, 4, 0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics15d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(3, 5, 4, 0, 4, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 4);
+ pathB.cubicTo(2, 4, 5, 1, 5, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics16i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(2, 5, 5, 0, 4, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 5);
+ pathB.cubicTo(2, 4, 5, 1, 5, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void cubics17d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(3, 4, 4, 1, 4, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(2, 4, 5, 1, 4, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics18d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(1, 3, 4, 0, 2, 0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 4);
+ pathB.cubicTo(0, 2, 5, 1, 3, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics19d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(2, 3, 5, 2, 4, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 5);
+ pathB.cubicTo(2, 4, 5, 1, 3, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubicOp157(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1,5);
+ path.cubicTo(1,3, 6,2, 4,2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,6);
+ pathB.cubicTo(2,4, 5,1, 3,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics20d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(0, 3, 6, 0, 3, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 6);
+ pathB.cubicTo(2, 3, 2, 1, 3, 0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void loops20i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(0, 2, 0.833333313f, 2, 1, 3.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(0.833333313f, 2, 1, 3.66666651f, 1, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops21i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(0, 2, 0.833333313f, 2, 1, 4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(0.833333313f, 2, 1, 4, 1, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops22i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 3);
+ path.cubicTo(0, 3, 0.833333313f, 3, 1, 4.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 3);
+ pathB.cubicTo(0.833333313f, 3, 1, 4.66666651f, 1, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops23i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(0, 1, 6.16666698f, 5.66666698f, -5.66666651f, 6.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 1);
+ pathB.cubicTo(6.16666698f, 5.66666698f, -5.66666651f, 6.66666651f, 1, 5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops24i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(0, 2, 0.833333313f, 2, 1, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(0.833333313f, 2, 1, 3, 1, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops25i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(0, 5, 0.833333313f, 5, 1, 7);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 5);
+ pathB.cubicTo(0.833333313f, 5, 1, 7, 1, 5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops26i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 6);
+ path.cubicTo(0, 2, 6.16666698f, 6.66666698f, -5.66666651f, 7.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(6.16666698f, 6.66666698f, -5.66666651f, 7.66666651f, 1, 6);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops27i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 3);
+ path.cubicTo(0, 3, 0.833333313f, 3, 1, 4.33333349f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 3);
+ pathB.cubicTo(0.833333313f, 3, 1, 4.33333349f, 1, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops28i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 3);
+ path.cubicTo(1, 3, 1.83333337f, 3, 2, 4.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 3);
+ pathB.cubicTo(1.83333337f, 3, 2, 4.66666651f, 2, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops29i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 4);
+ path.cubicTo(0, 4, 1.66666663f, 4, 2, 7.33333302f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 4);
+ pathB.cubicTo(1.66666663f, 4, 2, 7.33333302f, 2, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops30i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 4);
+ path.cubicTo(0, 4, 1.66666663f, 4, 2, 8);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 4);
+ pathB.cubicTo(1.66666663f, 4, 2, 8, 2, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops31i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 5);
+ path.cubicTo(1, 5, 1.83333337f, 5, 2, 6.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 5);
+ pathB.cubicTo(1.83333337f, 5, 2, 6.66666651f, 2, 5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops32i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 6);
+ path.cubicTo(1, 6, 1.83333337f, 6, 2, 8);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 6);
+ pathB.cubicTo(1.83333337f, 6, 2, 8, 2, 6);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops33i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 6);
+ path.cubicTo(1, 2, 7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f, 2, 6);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops33iMod(skiatest::Reporter* reporter, const char* filename) {
+ SkPoint pts[] = {{2, 6}, {1, 2}, {7.16666698f, 6.66666698f}, {-4.66666651f, 7.66666651f},
+ {1, 2}, {7.16666698f, 6.66666698f}, {-4.66666651f, 7.66666651f}, {2, 6}};
+ bool up = false;
+ float offset = 0.0380172729f;
+ float step = 7.62939453e-006f;
+ bool lastResult = true;
+ // for (int i = 0; i < 30; ++i) {
+ SkString name(filename);
+ // name.appendS32(i);
+ // if (i > 0) {
+ // SkDebugf("\n\n<div id=\"%s\">\n", name.c_str());
+ // }
+ pts[5].fY = 6.66666698f + offset;
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(pts[0]);
+ path.cubicTo(pts[1], pts[2], pts[3]);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(pts[4]);
+ pathB.cubicTo(pts[5], pts[6], pts[7]);
+ pathB.close();
+ bool result = testPathOp(reporter, path, pathB, kIntersect_SkPathOp, name.c_str());
+ if (lastResult != result) {
+ up = !up;
+ }
+ step /= 2;
+ offset += up ? step : -step;
+ lastResult = result;
+ // }
+}
+
+
+static void loops33iAsQuads(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 6);
+ path.cubicTo(1, 2, 7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f, 2, 6);
+ pathB.close();
+ SkPath qPath, qPathB;
+ CubicPathToQuads(path, &qPath);
+ CubicPathToQuads(pathB, &qPathB);
+ testPathOp(reporter, qPath, qPathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops34i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 4);
+ path.cubicTo(0, 4, 2.5f, 4, 3, 9);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 4);
+ pathB.cubicTo(2.5f, 4, 3, 9, 3, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops35i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 4);
+ path.cubicTo(0, 4, 2.5f, 4, 3, 10);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 4);
+ pathB.cubicTo(2.5f, 4, 3, 10, 3, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops36i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 4);
+ path.cubicTo(1, 4, 2.66666675f, 4, 3, 8);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(2.66666675f, 4, 3, 8, 3, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops37i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 4);
+ path.cubicTo(1, 4, 1.83333337f, 4, 2, 5.33333349f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(1.83333337f, 4, 2, 5.33333349f, 2, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops38i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 4);
+ path.cubicTo(2, 4, 2.83333325f, 4, 3, 6);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 4);
+ pathB.cubicTo(2.83333325f, 4, 3, 6, 3, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops39i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 5);
+ path.cubicTo(0, 5, 2.5f, 5, 3, 10);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 5);
+ pathB.cubicTo(2.5f, 5, 3, 10, 3, 5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops40i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 5);
+ path.cubicTo(0, 5, 2.5f, 5, 3, 11);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 5);
+ pathB.cubicTo(2.5f, 5, 3, 11, 3, 5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops40iAsQuads(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 5);
+ path.cubicTo(0, 5, 2.5f, 5, 3, 11);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 5);
+ pathB.cubicTo(2.5f, 5, 3, 11, 3, 5);
+ pathB.close();
+ SkPath qPath, qPathB;
+ CubicPathToQuads(path, &qPath);
+ CubicPathToQuads(pathB, &qPathB);
+ testPathOp(reporter, qPath, qPathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops44i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 5);
+ path.cubicTo(0, 1, 7.33333302f, 5.33333349f, -7, 7);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 1);
+ pathB.cubicTo(7.33333302f, 5.33333349f, -7, 7, 1, 5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops45i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 6);
+ path.cubicTo(0, 2, 7.33333302f, 6.33333302f, -7, 8);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 2);
+ pathB.cubicTo(7.33333302f, 6.33333302f, -7, 8, 1, 6);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops46i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 6);
+ path.cubicTo(1, 2, 8.33333302f, 6.33333302f, -6, 8);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(8.33333302f, 6.33333302f, -6, 8, 2, 6);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+/*
+FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
+static void loops47i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 4);
+ path.cubicTo(0, 1, 6, 5.83333302f, -4, 8);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 1);
+ pathB.cubicTo(6, 5.83333302f, -4, 8, 2, 4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops48i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 6);
+ path.cubicTo(0, 1, 9.33333302f, 6.83333302f, -8.33333302f, 9.16666603f);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 1);
+ pathB.cubicTo(9.33333302f, 6.83333302f, -8.33333302f, 9.16666603f, 2, 6);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops49i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 2);
+ path.cubicTo(1, 4, -0.166666687f, 2.66666675f, 1.66666675f, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(-0.166666687f, 2.66666675f, 1.66666675f, 2, 0, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops50i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 3);
+ path.cubicTo(1, 5, -0.166666687f, 3.66666675f, 1.66666675f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 5);
+ pathB.cubicTo(-0.166666687f, 3.66666675f, 1.66666675f, 3, 0, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops51i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(2, 4, 0.833333313f, 2.66666675f, 2.66666675f, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 4);
+ pathB.cubicTo(0.833333313f, 2.66666675f, 2.66666675f, 2, 1, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops52i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 3);
+ path.cubicTo(2, 5, 0.833333313f, 3.66666675f, 2.66666675f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 5);
+ pathB.cubicTo(0.833333313f, 3.66666675f, 2.66666675f, 3, 1, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops53i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 3);
+ path.cubicTo(3, 5, 1.83333325f, 3.66666675f, 3.66666651f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3, 5);
+ pathB.cubicTo(1.83333325f, 3.66666675f, 3.66666651f, 3, 2, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops54i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 2);
+ path.cubicTo(1, 4, 0, 3, 1.66666675f, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 4);
+ pathB.cubicTo(0, 3, 1.66666675f, 2, 0, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops55i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 3);
+ path.cubicTo(1, 5, 0, 4, 1.66666675f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 5);
+ pathB.cubicTo(0, 4, 1.66666675f, 3, 0, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops56i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 2);
+ path.cubicTo(2, 4, 0.99999994f, 3, 2.66666675f, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 4);
+ pathB.cubicTo(0.99999994f, 3, 2.66666675f, 2, 1, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops57i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 3);
+ path.cubicTo(2, 5, 0.99999994f, 4, 2.66666675f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 5);
+ pathB.cubicTo(0.99999994f, 4, 2.66666675f, 3, 1, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops58i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 3);
+ path.cubicTo(3, 5, 2, 4, 3.66666651f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3, 5);
+ pathB.cubicTo(2, 4, 3.66666651f, 3, 2, 3);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops58iAsQuads(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 3);
+ path.cubicTo(3, 5, 2, 4, 3.66666651f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3, 5);
+ pathB.cubicTo(2, 4, 3.66666651f, 3, 2, 3);
+ pathB.close();
+ SkPath qPath, qPathB;
+ CubicPathToQuads(path, &qPath);
+ CubicPathToQuads(pathB, &qPathB);
+// SkPoint from = {2.61714339f,1.90228665f};
+// SkPoint to = {2.617045833359139f,1.9013528935803314f};
+// path_edit(from, to, &qPathB);
+ testPathOp(reporter, qPath, qPathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops59i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 6);
+ path.cubicTo(1, 2, 7.33333302f, 1.66666663f, -7.5f, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(7.33333302f, 1.66666663f, -7.5f, 2, 0, 6);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops59iasQuads(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 6);
+ path.cubicTo(1, 2, 7.33333302f, 1.66666663f, -7.5f, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 2);
+ pathB.cubicTo(7.33333302f, 1.66666663f, -7.5f, 2, 0, 6);
+ pathB.close();
+ SkPath qPath, qPathB;
+ CubicPathToQuads(path, &qPath);
+ CubicPathToQuads(pathB, &qPathB);
+ SkPoint from = {2.61714339f,1.90228665f};
+ SkPoint to = {2.617045833359139f,1.9013528935803314f};
+ path_edit(from, to, &qPathB);
+ testPathOp(reporter, qPath, qPathB, kIntersect_SkPathOp, filename);
+}
+
+static void cubics41d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(1, 4, 3, 0, 3, 1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 3);
+ pathB.cubicTo(1, 3, 1, 0, 4, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+void loops61i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(1, 5, -6.33333302f, 0.666666627f, 8, -1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 5);
+ pathB.cubicTo(-6.33333302f, 0.666666627f, 8, -1, 0, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops62i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 2);
+ path.cubicTo(1, 6, -6.33333302f, 1.66666663f, 8, 0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 6);
+ pathB.cubicTo(-6.33333302f, 1.66666663f, 8, 0, 0, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops63i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(2, 4, -4, -0.833333254f, 6, -3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 4);
+ pathB.cubicTo(-4, -0.833333254f, 6, -3, 0, 1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void cubics44d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 4);
+ path.cubicTo(2, 5, 3, 1, 6, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 3);
+ pathB.cubicTo(2, 6, 4, 3, 5, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
+}
+
+static void cubics45u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 3);
+ path.cubicTo(2, 6, 4, 3, 5, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3, 4);
+ pathB.cubicTo(2, 5, 3, 1, 6, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_SkPathOp, filename);
+}
+
+static void fuzz38(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(100.34f, 303.312f);
+ path.lineTo(-1e+08, 303.312f);
+ path.lineTo(102, 310.156f);
+ path.lineTo(100.34f, 310.156f);
+ path.lineTo(100.34f, 303.312f);
+ path.close();
+ testPathOpCheck(reporter, path, pathB, kUnion_SkPathOp, filename, FLAGS_runFail);
+}
+
+static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
+static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
+
+#define TEST(name) { name, #name }
+
+static struct TestDesc tests[] = {
+ TEST(fuzz38),
+ TEST(cubics44d),
+ TEST(cubics45u),
+ TEST(loops61i),
+ TEST(loops62i),
+ TEST(loops63i),
+ TEST(loops58iAsQuads),
+ TEST(cubics41d),
+ TEST(loops59iasQuads),
+ TEST(loops59i),
+ TEST(loops44i),
+ TEST(loops45i),
+ TEST(loops46i),
+ TEST(loops47i),
+ TEST(loops48i),
+ TEST(loops49i),
+ TEST(loops50i),
+ TEST(loops51i),
+ TEST(loops52i),
+ TEST(loops53i),
+ TEST(loops54i),
+ TEST(loops55i),
+ TEST(loops56i),
+ TEST(loops57i),
+ TEST(loops58i),
+ TEST(loops33iMod),
+ TEST(loops33iAsQuads),
+ TEST(loops33i),
+ TEST(loops40i),
+ TEST(loops40iAsQuads),
+ TEST(loops39i),
+ TEST(loops38i),
+ TEST(loops37i),
+ TEST(loops36i),
+ TEST(loops35i),
+ TEST(loops34i),
+ TEST(loops32i),
+ TEST(loops31i),
+ TEST(loops30i),
+ TEST(loops29i),
+ TEST(loops28i),
+ TEST(loops27i),
+ TEST(loops26i),
+ TEST(loops25i),
+ TEST(loops24i),
+ TEST(loops23i),
+ TEST(loops22i),
+ TEST(loops21i),
+ TEST(loops20i),
+ TEST(cubics20d),
+ TEST(cubics6d),
+ TEST(cubics7d),
+ TEST(cubics8d),
+ TEST(cubics9d),
+ TEST(cubics10u),
+ TEST(cubics11i),
+ TEST(cubics12d),
+ TEST(cubics13d),
+ TEST(cubics14d),
+ TEST(cubics15d),
+ TEST(cubics16i),
+ TEST(cubics17d),
+ TEST(cubics18d),
+ TEST(cubics19d),
+ TEST(cubicOp157),
+ TEST(cubicOp142),
+ TEST(loops4i),
+ TEST(quadRect1),
+ TEST(quadRect2),
+ TEST(quadRect3),
+ TEST(quadRect4),
+ TEST(quadRect5),
+ TEST(quadRect6),
+ TEST(cubicOp141),
+ TEST(cubicOp58d),
+ TEST(cubicOp53d),
+};
+
+static const size_t subTestCount = SK_ARRAY_COUNT(subTests);
+
+static void (*firstSubTest)(skiatest::Reporter* , const char* filename) = 0;
+
+static bool runSubTests = false;
+static bool runSubTestsFirst = false;
+static bool runReverse = false;
+
+DEF_TEST(PathOpsOp, reporter) {
+#if DEBUG_SHOW_TEST_NAME
+ strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
+#endif
+ if (runSubTests && runSubTestsFirst) {
+ RunTestSet(reporter, subTests, subTestCount, firstSubTest, stopTest, runReverse);
+ }
+ RunTestSet(reporter, tests, testCount, firstTest, stopTest, runReverse);
+ if (runSubTests && !runSubTestsFirst) {
+ RunTestSet(reporter, subTests, subTestCount, firstSubTest, stopTest, runReverse);
+ }
+}
+
+static void bufferOverflow(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0,0, 300,170141183460469231731687303715884105728.f);
+ SkPath pathB;
+ pathB.addRect(0,0, 300,16);
+ testPathFailOp(reporter, path, pathB, kUnion_PathOp, filename);
+}
+
+// m 100,0 60,170 -160,-110 200,0 -170,11000000000 z
+static void fuzz433(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1, path2;
+ path1.moveTo(100,0);
+ path1.lineTo(60,170);
+ path1.lineTo(-160,-110);
+ path1.lineTo(200,0);
+ path1.lineTo(-170,11000000000.0f);
+ path1.close();
+
+ path2.moveTo(100 + 20,0 + 20);
+ path2.lineTo(60 + 20,170 + 20);
+ path2.lineTo(-160 + 20,-110 + 20);
+ path2.lineTo(200 + 20,0 + 20);
+ path2.lineTo(-170 + 20,11000000000.0f + 20);
+ path2.close();
+
+ testPathFailOp(reporter, path1, path2, kIntersect_PathOp, filename);
+}
+
+static void fuzz433b(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path1, path2;
+ path1.setFillType(SkPath::kEvenOdd_FillType);
+ path1.moveTo(140, 40);
+ path1.lineTo(200, 210);
+ path1.lineTo(40, 100);
+ path1.lineTo(240, 100);
+ path1.lineTo(70, 1.1e+10f);
+ path1.lineTo(140, 40);
+ path1.close();
+
+ path1.setFillType(SkPath::kWinding_FillType);
+ path2.moveTo(190, 60);
+ path2.lineTo(250, 230);
+ path2.lineTo(90, 120);
+ path2.lineTo(290, 120);
+ path2.lineTo(120, 1.1e+10f);
+ path2.lineTo(190, 60);
+ path2.close();
+
+ testPathFailOp(reporter, path1, path2, kUnion_PathOp, filename);
+}
+
+static void fuzz487a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x432c8000), SkBits2Float(0x42c00000));
+path.lineTo(SkBits2Float(0x4309999a), SkBits2Float(0x42c00000));
+path.cubicTo(SkBits2Float(0x4309999a), SkBits2Float(0x429a6666), SkBits2Float(0x42f9999a), SkBits2Float(0x4275999a), SkBits2Float(0x42d70001), SkBits2Float(0x42633333));
+path.lineTo(SkBits2Float(0x42e90001), SkBits2Float(0x41b8cccc));
+path.cubicTo(SkBits2Float(0x42dc6667), SkBits2Float(0x41ab3332), SkBits2Float(0x42cf3334), SkBits2Float(0x41a3ffff), SkBits2Float(0x42c20001), SkBits2Float(0x41a3ffff));
+path.lineTo(SkBits2Float(0x42c20001), SkBits2Float(0x425d999a));
+path.lineTo(SkBits2Float(0x42c20001), SkBits2Float(0x425d999a));
+path.cubicTo(SkBits2Float(0x429c6668), SkBits2Float(0x425d999a), SkBits2Float(0x4279999c), SkBits2Float(0x42886667), SkBits2Float(0x42673335), SkBits2Float(0x42ab0000));
+path.lineTo(SkBits2Float(0x41c0ccd0), SkBits2Float(0x42990000));
+path.cubicTo(SkBits2Float(0x41b33336), SkBits2Float(0x42a5999a), SkBits2Float(0x41ac0003), SkBits2Float(0x42b2cccd), SkBits2Float(0x41ac0003), SkBits2Float(0x42c00000));
+path.lineTo(SkBits2Float(0x4261999c), SkBits2Float(0x42c00000));
+path.lineTo(SkBits2Float(0x4261999c), SkBits2Float(0x42c00000));
+path.cubicTo(SkBits2Float(0x4261999c), SkBits2Float(0x434d3333), SkBits2Float(0x4364e667), SkBits2Float(0x4346b333), SkBits2Float(0x4364e667), SkBits2Float(0x43400000));
+path.lineTo(SkBits2Float(0x432c8000), SkBits2Float(0x42c00000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x432c8000), SkBits2Float(0x42c00000));
+path.lineTo(SkBits2Float(0x4309999a), SkBits2Float(0x42c00000));
+path.cubicTo(SkBits2Float(0x4309999a), SkBits2Float(0x42a20000), SkBits2Float(0x43016667), SkBits2Float(0x4287cccd), SkBits2Float(0x42ea999a), SkBits2Float(0x4273999a));
+path.lineTo(SkBits2Float(0x4306cccd), SkBits2Float(0x41f5999a));
+path.cubicTo(SkBits2Float(0x42f76667), SkBits2Float(0x41c26667), SkBits2Float(0x42dd999a), SkBits2Float(0x41a4cccd), SkBits2Float(0x42c23334), SkBits2Float(0x41a4cccd));
+path.lineTo(SkBits2Float(0x42c23334), SkBits2Float(0x425e0000));
+path.cubicTo(SkBits2Float(0x42a43334), SkBits2Float(0x425e0000), SkBits2Float(0x428a0001), SkBits2Float(0x427ecccd), SkBits2Float(0x42780002), SkBits2Float(0x4297999a));
+path.lineTo(SkBits2Float(0x41fccccd), SkBits2Float(0x42693333));
+path.cubicTo(SkBits2Float(0x41c9999a), SkBits2Float(0x428acccd), SkBits2Float(0x41ac0000), SkBits2Float(0x42a4999a), SkBits2Float(0x41ac0000), SkBits2Float(0x42c00000));
+path.lineTo(SkBits2Float(0x4261999a), SkBits2Float(0x42c00000));
+path.cubicTo(SkBits2Float(0x4261999a), SkBits2Float(0x42de0000), SkBits2Float(0x42813333), SkBits2Float(0x42f83333), SkBits2Float(0x42996666), SkBits2Float(0x4303199a));
+path.cubicTo(SkBits2Float(0x4272cccc), SkBits2Float(0x4303199a), SkBits2Float(0x423d3332), SkBits2Float(0x430de667), SkBits2Float(0x422d9999), SkBits2Float(0x431cb334));
+path.lineTo(SkBits2Float(0x7086a1dc), SkBits2Float(0x42eecccd));
+path.lineTo(SkBits2Float(0x41eb3333), SkBits2Float(0xc12ccccd));
+path.lineTo(SkBits2Float(0x42053333), SkBits2Float(0xc1cccccd));
+path.lineTo(SkBits2Float(0x42780000), SkBits2Float(0xc18f3334));
+path.cubicTo(SkBits2Float(0x43206666), SkBits2Float(0x43134ccd), SkBits2Float(0x43213333), SkBits2Float(0x430db333), SkBits2Float(0x43213333), SkBits2Float(0x43080000));
+path.lineTo(SkBits2Float(0x432c8000), SkBits2Float(0x42c00000));
+path.close();
+
+ SkPath path2(path);
+ testPathFailOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static void fuzz487b(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x432c8000), SkBits2Float(0x42c00000));
+path.lineTo(SkBits2Float(0x4309999a), SkBits2Float(0x42c00000));
+path.cubicTo(SkBits2Float(0x4309999a), SkBits2Float(0x429a6666), SkBits2Float(0x42f9999a), SkBits2Float(0x4275999a), SkBits2Float(0x42d70001), SkBits2Float(0x42633333));
+path.lineTo(SkBits2Float(0x42e90001), SkBits2Float(0x41b8cccc));
+path.cubicTo(SkBits2Float(0x42dc6667), SkBits2Float(0x41ab3332), SkBits2Float(0x42cf3334), SkBits2Float(0x41a3ffff), SkBits2Float(0x42c20001), SkBits2Float(0x41a3ffff));
+path.lineTo(SkBits2Float(0x42c20001), SkBits2Float(0x425d999a));
+path.lineTo(SkBits2Float(0x42c20001), SkBits2Float(0x425d999a));
+path.cubicTo(SkBits2Float(0x429c6668), SkBits2Float(0x425d999a), SkBits2Float(0x4279999c), SkBits2Float(0x42886667), SkBits2Float(0x42673335), SkBits2Float(0x42ab0000));
+path.lineTo(SkBits2Float(0x41c0ccd0), SkBits2Float(0x42990000));
+path.cubicTo(SkBits2Float(0x41b33336), SkBits2Float(0x42a5999a), SkBits2Float(0x41ac0003), SkBits2Float(0x42b2cccd), SkBits2Float(0x41ac0003), SkBits2Float(0x42c00000));
+path.lineTo(SkBits2Float(0x4261999c), SkBits2Float(0x42c00000));
+path.lineTo(SkBits2Float(0x4261999c), SkBits2Float(0x42c00000));
+path.cubicTo(SkBits2Float(0x4261999c), SkBits2Float(0x434d3333), SkBits2Float(0x4364e667), SkBits2Float(0x4346b333), SkBits2Float(0x4364e667), SkBits2Float(0x43400000));
+path.lineTo(SkBits2Float(0x432c8000), SkBits2Float(0x42c00000));
+path.close();
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x432c8000), SkBits2Float(0x42c00000));
+path.lineTo(SkBits2Float(0x4309999a), SkBits2Float(0x42c00000));
+path.cubicTo(SkBits2Float(0x4309999a), SkBits2Float(0x42a20000), SkBits2Float(0x43016667), SkBits2Float(0x4287cccd), SkBits2Float(0x42ea999a), SkBits2Float(0x4273999a));
+path.lineTo(SkBits2Float(0x4306cccd), SkBits2Float(0x41f5999a));
+path.cubicTo(SkBits2Float(0x42f76667), SkBits2Float(0x41c26667), SkBits2Float(0x42dd999a), SkBits2Float(0x41a4cccd), SkBits2Float(0x42c23334), SkBits2Float(0x41a4cccd));
+path.lineTo(SkBits2Float(0x42c23334), SkBits2Float(0x425e0000));
+path.cubicTo(SkBits2Float(0x42a43334), SkBits2Float(0x425e0000), SkBits2Float(0x428a0001), SkBits2Float(0x427ecccd), SkBits2Float(0x42780002), SkBits2Float(0x4297999a));
+path.lineTo(SkBits2Float(0x41fccccd), SkBits2Float(0x42693333));
+path.cubicTo(SkBits2Float(0x41c9999a), SkBits2Float(0x428acccd), SkBits2Float(0x41ac0000), SkBits2Float(0x42a4999a), SkBits2Float(0x41ac0000), SkBits2Float(0x42c00000));
+path.lineTo(SkBits2Float(0x4261999a), SkBits2Float(0x42c00000));
+path.cubicTo(SkBits2Float(0x4261999a), SkBits2Float(0x42de0000), SkBits2Float(0x42813333), SkBits2Float(0x42f83333), SkBits2Float(0x42996666), SkBits2Float(0x4303199a));
+path.cubicTo(SkBits2Float(0x4272cccc), SkBits2Float(0x4303199a), SkBits2Float(0x423d3332), SkBits2Float(0x430de667), SkBits2Float(0x422d9999), SkBits2Float(0x431cb334));
+path.lineTo(SkBits2Float(0x7086a1dc), SkBits2Float(0x42eecccd));
+path.lineTo(SkBits2Float(0x41eb3333), SkBits2Float(0xc12ccccd));
+path.lineTo(SkBits2Float(0x42053333), SkBits2Float(0xc1cccccd));
+path.lineTo(SkBits2Float(0x42780000), SkBits2Float(0xc18f3334));
+path.cubicTo(SkBits2Float(0x43206666), SkBits2Float(0x43134ccd), SkBits2Float(0x43213333), SkBits2Float(0x430db333), SkBits2Float(0x43213333), SkBits2Float(0x43080000));
+path.lineTo(SkBits2Float(0x432c8000), SkBits2Float(0x42c00000));
+path.close();
+
+ SkPath path2(path);
+ testPathFailOp(reporter, path1, path2, (SkPathOp) 2, filename);
+}
+
+static struct TestDesc failTests[] = {
+ TEST(fuzz487a),
+ TEST(fuzz487b),
+ TEST(fuzz433b),
+ TEST(fuzz433),
+ TEST(bufferOverflow),
+};
+
+static const size_t failTestCount = SK_ARRAY_COUNT(failTests);
+
+DEF_TEST(PathOpsFailOp, reporter) {
+#if DEBUG_SHOW_TEST_NAME
+ strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
+#endif
+ RunTestSet(reporter, failTests, failTestCount, 0, 0, false);
+}
diff --git a/src/third_party/skia/tests/PathOpsQuadIntersectionTest.cpp b/src/third_party/skia/tests/PathOpsQuadIntersectionTest.cpp
new file mode 100644
index 0000000..1ddbbcc
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsQuadIntersectionTest.cpp
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsQuadIntersectionTestData.h"
+#include "PathOpsTestCommon.h"
+#include "SkIntersections.h"
+#include "SkPathOpsRect.h"
+#include "SkReduceOrder.h"
+#include "Test.h"
+
+static void standardTestCases(skiatest::Reporter* reporter) {
+ bool showSkipped = false;
+ for (size_t index = 0; index < quadraticTests_count; ++index) {
+ const SkDQuad& quad1 = quadraticTests[index][0];
+ SkASSERT(ValidQuad(quad1));
+ const SkDQuad& quad2 = quadraticTests[index][1];
+ SkASSERT(ValidQuad(quad2));
+ SkReduceOrder reduce1, reduce2;
+ int order1 = reduce1.reduce(quad1);
+ int order2 = reduce2.reduce(quad2);
+ if (order1 < 3) {
+ if (showSkipped) {
+ SkDebugf("[%d] quad1 order=%d\n", static_cast<int>(index), order1);
+ }
+ }
+ if (order2 < 3) {
+ if (showSkipped) {
+ SkDebugf("[%d] quad2 order=%d\n", static_cast<int>(index), order2);
+ }
+ }
+ if (order1 == 3 && order2 == 3) {
+ SkIntersections intersections;
+ intersections.intersect(quad1, quad2);
+ if (intersections.used() > 0) {
+ for (int pt = 0; pt < intersections.used(); ++pt) {
+ double tt1 = intersections[0][pt];
+ SkDPoint xy1 = quad1.ptAtT(tt1);
+ double tt2 = intersections[1][pt];
+ SkDPoint xy2 = quad2.ptAtT(tt2);
+ if (!xy1.approximatelyEqual(xy2)) {
+ SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
+ __FUNCTION__, static_cast<int>(index), pt, tt1, xy1.fX, xy1.fY,
+ tt2, xy2.fX, xy2.fY);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ }
+ }
+ }
+}
+
+static const SkDQuad testSet[] = {
+{{{441.853149, 308.209106}, {434.672272, 315.389984}, {424.516998, 315.389984}}},
+{{{385.207275, 334.241272}, {406.481598, 312.96698}, {436.567993, 312.96698}}},
+
+{{{-708.00779269310044, -154.36998607290101}, {-707.90560262312511, -154.36998607290101}, {-707.8333433370193, -154.44224536635932}}},
+{{{-708.00779269310044, -154.61669472244046}, {-701.04513225634582, -128.85970734043804}, {505.58447265625, -504.9130859375}}},
+
+{{{164, -40}, {231.51681518554687, -40}, {279.25839233398438, 7.7416000366210938}}},
+{{{279.25839233398438, 7.7416000366210938}, {275.2164306640625, 3.6996400356292725}, {271.03286743164062, -5.3290705182007514e-015}}},
+
+{{{2.9999997378517067, 1.9737872594345709}, {2.9999997432230918, 1.9739647181863822}, {1.2414155459263587e-163, 5.2957833941332142e-315}}},
+{{{2.9999047485265304, 1.9739164225694723}, {3.0000947268526112, 1.9738379076623633}, {0.61149411077591886, 0.0028382324376270418}}},
+
+ {{{2.9999996843656502, 1.9721416019045801}, {2.9999997725237835, 1.9749798343422071},
+ {5.3039068214821359e-315, 8.9546185262775165e-307}}},
+ {{{2.9984791443874976, 1.974505741312242}, {2.9999992702127476, 1.9738772171479178},
+ {3.0015187977319759, 1.9732495027303418}}},
+
+ {{{0.647069409,2.97691634}, {0.946860918,3.17625612}, {1.46875407,2.65105457}}},
+ {{{0,1}, {0.723699095,2.82756208}, {1.08907197,2.97497449}}},
+
+ {{{131.37418,11414.9825}, {130.28798,11415.9328}, {130.042755,11417.4131}}},
+ {{{130.585787,11418.4142}, {130.021447,11417.8498}, {130,11417}}},
+
+ {{{130.73167037963867, 11418.546386718750}, {131.26360225677490, 11418.985778808592},
+ {132, 11419 }}},
+ {{{132, 11419}, {131.15012693405151, 11418.978546142578},
+ {130.58578681945801, 11418.414184570313}}},
+
+ {{{132, 11419},
+ {130.73167037963867, 11418.546386718750}, {131.26360225677490, 11418.985778808592}}},
+ {{{131.15012693405151, 11418.978546142578},
+ {130.58578681945801, 11418.414184570313}, {132, 11419}}},
+
+ {{{3.0774019473063863, 3.35198509346713}, {3.0757503498668397, 3.327320623945933},
+ {3.0744102085015879, 3.3025879417907196}}},
+ {{{3.053913680774329, 3.3310471586283938}, {3.0758730889691694, 3.3273466070370152},
+ {3.0975671980059394, 3.3235031316554351}}},
+
+ {{{3.39068129, 4.44939202}, {3.03659239, 3.81843234}, {3.06844529, 3.02100922}}},
+ {{{2.10714698, 3.44196686}, {3.12180288, 3.38575704}, {3.75968569, 3.1281838}}},
+
+ {{{2.74792918, 4.77711896}, {2.82236867, 4.23882547}, {2.82848144, 3.63729341}}},
+ {{{2.62772567, 3.64823958}, {3.46652495, 3.64258364}, {4.1425079, 3.48623815}}},
+
+ {{{1.34375, 2.03125}, {2.2734375, 2.6640625}, {3.25, 3.25}}},
+ {{{3.96875, 4.65625}, {3.3359375, 3.7265625}, {2.75, 2.75}}},
+
+ {{{0, 1}, {0.324417544, 2.27953848}, {0.664376547, 2.58940267}}},
+ {{{1, 2}, {0.62109375, 2.70703125}, {0.640625, 2.546875}}},
+
+ {{{1, 2}, {0.984375, 2.3359375}, {1.0625, 2.15625}}},
+ {{{0, 1}, {0.983539095, 2.30041152}, {1.47325103, 2.61316872}}},
+
+ {{{4.09011926, 2.20971038}, {4.74608133, 1.9335932}, {5.02469918, 2.00694987}}},
+ {{{2.79472921, 1.73568666}, {3.36246373, 1.21251209}, {5, 2}}},
+
+ {{{1.80814127, 2.41537795}, {2.23475077, 2.05922313}, {3.16529668, 1.98358763}}},
+ {{{2.16505631, 2.55782454}, {2.40541285, 2.02193091}, {2.99836023, 1.68247638}}},
+
+ {{{3, 1.875}, {3.375, 1.54296875}, {3.375, 1.421875}}},
+ {{{3.375, 1.421875}, {3.3749999999999996, 1.3007812499999998}, {3, 2}}},
+
+ {{{3.34, 8.98}, {2.83363281, 9.4265625}, {2.83796875, 9.363125}}},
+ {{{2.83796875, 9.363125}, {2.84230469, 9.2996875}, {3.17875, 9.1725}}},
+
+ {{{2.7279999999999998, 3.024}, {2.5600000000000005, 2.5600000000000005},
+ {2.1520000000000001, 1.8560000000000001}}},
+ {{{0.66666666666666652, 1.1481481481481481}, {1.3333333333333326, 1.3333333333333335},
+ {2.6666666666666665, 2.1851851851851851}}},
+
+ {{{2.728, 3.024}, {2.56, 2.56}, {2.152, 1.856}}},
+ {{{0.666666667, 1.14814815}, {1.33333333, 1.33333333}, {2.66666667, 2.18518519}}},
+
+ {{{0.875, 1.5}, {1.03125, 1.11022302e-16}, {1, 0}}},
+ {{{0.875, 0.859375}, {1.6875, 0.73046875}, {2.5, 0.625}}},
+
+ {{{1.64451042, 0.0942001592}, {1.53635465, 0.00152863961}, {1, 0}}},
+ {{{1.27672209, 0.15}, {1.32143477, 9.25185854e-17}, {1, 0}}},
+
+ {{{0, 0}, {0.51851851851851849, 1.0185185185185186}, {1.2592592592592591, 1.9259259259259258}}},
+ {{{1.2592592592592593, 1.9259259259259265}, {0.51851851851851893, 1.0185185185185195}, {0, 0}}},
+
+ {{{1.93281168, 2.58856757}, {2.38543691, 2.7096125}, {2.51967352, 2.34531784}}},
+ {{{2.51967352, 2.34531784}, {2.65263731, 2.00639194}, {3.1212119, 1.98608967}}},
+ {{{2.09544533, 2.51981963}, {2.33331524, 2.25252128}, {2.92003302, 2.39442311}}},
+
+ {{{0.924337655, 1.94072717}, {1.25185043, 1.52836494}, {1.71793901, 1.06149951}}},
+ {{{0.940798831, 1.67439357}, {1.25988251, 1.39778567}, {1.71791672, 1.06650313}}},
+
+ {{{0.924337655, 1.94072717}, {1.39158994, 1.32418496}, {2.14967426, 0.687365435}}},
+ {{{0.940798831, 1.67439357}, {1.48941875, 1.16280321}, {2.47884711, 0.60465921}}},
+
+ {{{1.7465749139282332, 1.9930452039527999}, {1.8320006564080331, 1.859481345189089},
+ {1.8731035127758437, 1.6344055934266613}}},
+ {{{1.8731035127758437, 1.6344055934266613}, {1.89928170345231, 1.5006405518943067},
+ {1.9223833226085514, 1.3495796165215643}}},
+ {{{1.74657491, 1.9930452}, {1.87407679, 1.76762853}, {1.92238332, 1.34957962}}},
+ {{{0.60797907, 1.68776977}, {1.0447864, 1.50810914}, {1.87464474, 1.63655092}}},
+ {{{1.87464474, 1.63655092}, {2.70450308, 1.76499271}, {4, 3}}},
+
+ {{{1.2071879545809394, 0.82163474041730045}, {1.1534203513372994, 0.52790870069930229},
+ {1.0880000000000001, 0.29599999999999982}}}, //t=0.63155333662549329,0.80000000000000004
+ {{{0.33333333333333326, 0.81481481481481488}, {0.63395173631977997, 0.68744136726313931},
+ {1.205684411948591, 0.81344322326274499}}},
+ {{{0.33333333333333326, 0.81481481481481488}, {0.63396444791444551, 0.68743368362444768},
+ {1.205732763658403, 0.81345617746834109}}}, //t=0.33333333333333331, 0.63396444791444551
+ {{{1.205684411948591, 0.81344322326274499}, {1.2057085875611198, 0.81344969999329253},
+ {1.205732763658403, 0.81345617746834109}}},
+
+ {{{1.20718795, 0.82163474}, {1.15342035, 0.527908701}, {1.088, 0.296}}},
+ {{{1.20568441, 0.813443223}, {1.20570859, 0.8134497}, {1.20573276, 0.813456177}}},
+
+ {{{41.5072916, 87.1234036}, {28.2747836, 80.9545395}, {23.5780771, 69.3344126}}},
+ {{{72.9633878, 95.6593007}, {42.7738746, 88.4730382}, {31.1932785, 80.2458029}}},
+
+ {{{31.1663962, 54.7302484}, {31.1662882, 54.7301074}, {31.1663969, 54.7302485}}},
+ {{{26.0404936, 45.4260361}, {27.7887523, 33.1863051}, {40.8833242, 26.0301855}}},
+
+ {{{29.9404074, 49.1672596}, {44.3131071, 45.3915253}, {58.1067559, 59.5061814}}},
+ {{{72.6510251, 64.2972928}, {53.6989659, 60.1862397}, {35.2053722, 44.8391126}}},
+
+ {{{52.14807018377202, 65.012420045148644}, {44.778669050208237, 66.315562705604378},
+ {51.619118408823567, 63.787827046262684}}},
+ {{{30.004993234763383, 93.921296668202288}, {53.384822003076991, 60.732180341802753},
+ {58.652998934338584, 43.111073088306185}}},
+
+ {{{80.897794748143198, 49.236332042718459}, {81.082078218891212, 64.066749904488631},
+ {69.972305057149981, 72.968595519850993}}},
+ {{{72.503745601281395, 32.952320736577882}, {88.030880716061645, 38.137194847810164},
+ {73.193774825517906, 67.773492479591397}}},
+
+ {{{67.426548091427676, 37.993772624988935}, {51.129513170665035, 57.542281234563646},
+ {44.594748190899189, 65.644267382683879}}},
+ {{{61.336508189019057, 82.693132843213675}, {54.825078921449354, 71.663932799212432},
+ {47.727444217558926, 61.4049645128392}}},
+
+ {{{67.4265481, 37.9937726}, {51.1295132, 57.5422812}, {44.5947482, 65.6442674}}},
+ {{{61.3365082, 82.6931328}, {54.8250789, 71.6639328}, {47.7274442, 61.4049645}}},
+
+ {{{53.774852327053594, 53.318060789841951}, {45.787877803416805, 51.393492026284981},
+ {46.703936967162392, 53.06860709822206}}},
+ {{{46.703936967162392, 53.06860709822206}, {47.619996130907957, 54.74372217015916},
+ {53.020051653535361, 48.633140968832024}}},
+
+ {{{50.934805397717923, 51.52391952648901}, {56.803308902971423, 44.246234610627596},
+ {69.776888596721406, 40.166645096692555}}},
+ {{{50.230212796400401, 38.386469101526998}, {49.855620812184917, 38.818990392153609},
+ {56.356567496227363, 47.229909093319407}}},
+
+ {{{36.148792695174222, 70.336952793070424}, {36.141613037691357, 70.711654739870085},
+ {36.154708826402597, 71.088492662905836}}},
+ {{{35.216235592661825, 70.580199617313212}, {36.244476835123969, 71.010897787304074},
+ {37.230244263238326, 71.423156953613102}}},
+
+ // this pair is nearly coincident, and causes the quartic code to produce bad
+ // data. Mathematica doesn't think they touch. Graphically, I can't tell.
+ // it may not be so bad to pretend that they don't touch, if I can detect that
+ {{{369.848602, 145.680267}, {382.360413, 121.298294}, {406.207703, 121.298294}}},
+ {{{369.850525, 145.675964}, {382.362915, 121.29287}, {406.211273, 121.29287}}},
+
+ {{{33.567436351153468, 62.336347586395924}, {35.200980274619084, 65.038561460144479},
+ {36.479571811084995, 67.632178905412445}}},
+ {{{41.349524945572696, 67.886658677862641}, {39.125562529359087, 67.429772735149214},
+ {35.600314083992416, 66.705372160552685}}},
+
+ {{{67.25299631583178, 21.109080184767524}, {43.617595267398613, 33.658034168577529},
+ {33.38371819435676, 44.214192553988745}}},
+ {{{40.476838859398541, 39.543209911285999}, {36.701186108431131, 34.8817994016458},
+ {30.102144288878023, 26.739063172945315}}},
+
+ {{{25.367434474345036, 50.4712103169743}, {17.865013304933097, 37.356741010559439},
+ {16.818988838905465, 37.682915484123129}}},
+ {{{16.818988838905465, 37.682915484123129}, {15.772964372877833, 38.009089957686811},
+ {20.624104547604965, 41.825131596683121}}},
+
+ {{{26.440225044088567, 79.695009812848298}, {26.085525979582247, 83.717928354134784},
+ {27.075079976297072, 84.820633667838905}}},
+ {{{27.075079976297072, 84.820633667838905}, {28.276546859574015, 85.988574184029034},
+ {25.649263209500006, 87.166762066617025}}},
+
+ {{{34.879150914024962, 83.862726601601125}, {35.095810134304429, 83.693473210169543},
+ {35.359284111931586, 83.488069234177502}}},
+ {{{54.503204203015471, 76.094098492518242}, {51.366889541918894, 71.609856061299155},
+ {46.53086955445437, 69.949863036494207}}},
+
+ {{{0, 0}, {1, 0}, {0, 3}}},
+ {{{1, 0}, {0, 1}, {1, 1}}},
+ {{{369.961151, 137.980698}, {383.970093, 121.298294}, {406.213287, 121.298294}}},
+ {{{353.2948, 194.351074}, {353.2948, 173.767563}, {364.167572, 160.819855}}},
+ {{{360.416077, 166.795715}, {370.126831, 147.872162}, {388.635406, 147.872162}}},
+ {{{406.236359, 121.254936}, {409.445679, 121.254936}, {412.975952, 121.789818}}},
+ {{{406.235992, 121.254936}, {425.705902, 121.254936}, {439.71994, 137.087616}}},
+
+ {{{369.8543701171875, 145.66734313964844}, {382.36788940429688, 121.28203582763672},
+ {406.21844482421875, 121.28203582763672}}},
+ {{{369.96469116210938, 137.96672058105469}, {383.97555541992188, 121.28203582763672},
+ {406.2218017578125, 121.28203582763672}}},
+
+ {{{369.962311, 137.976044}, {383.971893, 121.29287}, {406.216125, 121.29287}}},
+
+ {{{400.121704, 149.468719}, {391.949493, 161.037186}, {391.949493, 181.202423}}},
+ {{{391.946747, 181.839218}, {391.946747, 155.62442}, {406.115479, 138.855438}}},
+ {{{360.048828125, 229.2578125}, {360.048828125, 224.4140625}, {362.607421875, 221.3671875}}},
+ {{{362.607421875, 221.3671875}, {365.166015625, 218.3203125}, {369.228515625, 218.3203125}}},
+ {{{8, 8}, {10, 10}, {8, -10}}},
+ {{{8, 8}, {12, 12}, {14, 4}}},
+ {{{8, 8}, {9, 9}, {10, 8}}}
+};
+
+const size_t testSetCount = SK_ARRAY_COUNT(testSet);
+
+static void oneOffTest1(skiatest::Reporter* reporter, size_t outer, size_t inner) {
+ const SkDQuad& quad1 = testSet[outer];
+ SkASSERT(ValidQuad(quad1));
+ const SkDQuad& quad2 = testSet[inner];
+ SkASSERT(ValidQuad(quad2));
+ SkIntersections intersections2;
+ intersections2.intersect(quad1, quad2);
+ for (int pt = 0; pt < intersections2.used(); ++pt) {
+ double tt1 = intersections2[0][pt];
+ SkDPoint xy1 = quad1.ptAtT(tt1);
+ double tt2 = intersections2[1][pt];
+ SkDPoint xy2 = quad2.ptAtT(tt2);
+ if (!xy1.approximatelyEqual(xy2)) {
+ SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
+ __FUNCTION__, static_cast<int>(outer), static_cast<int>(inner),
+ tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY);
+ REPORTER_ASSERT(reporter, 0);
+ }
+#if ONE_OFF_DEBUG
+ SkDebugf("%s [%d][%d] t1=%1.9g (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
+ outer, inner, tt1, xy1.fX, xy1.fY, tt2);
+#endif
+ }
+}
+
+DEF_TEST(PathOpsQuadIntersectionOneOff, reporter) {
+ oneOffTest1(reporter, 0, 1);
+}
+
+static void oneOffTests(skiatest::Reporter* reporter) {
+ for (size_t outer = 0; outer < testSetCount - 1; ++outer) {
+ for (size_t inner = outer + 1; inner < testSetCount; ++inner) {
+ oneOffTest1(reporter, outer, inner);
+ }
+ }
+}
+
+static const SkDQuad coincidentTestSet[] = {
+#if 0
+ {{{97.9337615966796875,100}, {88,112.94264984130859375}, {88,130}}},
+ {{{88,130}, {88,124.80951690673828125}, {88.91983795166015625,120}}},
+#endif
+ {{{369.850525, 145.675964}, {382.362915, 121.29287}, {406.211273, 121.29287}}},
+ {{{369.850525, 145.675964}, {382.362915, 121.29287}, {406.211273, 121.29287}}},
+ {{{8, 8}, {10, 10}, {8, -10}}},
+ {{{8, -10}, {10, 10}, {8, 8}}},
+};
+
+static const int coincidentTestSetCount = (int) SK_ARRAY_COUNT(coincidentTestSet);
+
+static void coincidentTestOne(skiatest::Reporter* reporter, int test1, int test2) {
+ const SkDQuad& quad1 = coincidentTestSet[test1];
+ SkASSERT(ValidQuad(quad1));
+ const SkDQuad& quad2 = coincidentTestSet[test2];
+ SkASSERT(ValidQuad(quad2));
+ SkIntersections intersections2;
+ intersections2.intersect(quad1, quad2);
+ REPORTER_ASSERT(reporter, intersections2.coincidentUsed() == 2);
+ REPORTER_ASSERT(reporter, intersections2.used() == 2);
+ for (int pt = 0; pt < intersections2.coincidentUsed(); ++pt) {
+ double tt1 = intersections2[0][pt];
+ double tt2 = intersections2[1][pt];
+ SkDPoint pt1 = quad1.ptAtT(tt1);
+ SkDPoint pt2 = quad2.ptAtT(tt2);
+ REPORTER_ASSERT(reporter, pt1.approximatelyEqual(pt2));
+ }
+}
+
+static void coincidentTest(skiatest::Reporter* reporter) {
+ for (int testIndex = 0; testIndex < coincidentTestSetCount - 1; testIndex += 2) {
+ coincidentTestOne(reporter, testIndex, testIndex + 1);
+ }
+}
+
+DEF_TEST(PathOpsQuadIntersectionCoincidenceOneOff, reporter) {
+ coincidentTestOne(reporter, 0, 1);
+}
+
+static int floatSign(double x) {
+ return x < 0 ? -1 : x > 0 ? 1 : 0;
+}
+
+static const SkDQuad pointFinderTestSet[] = {
+ //>=0.633974464 0.633974846 <=
+{{{1.2071879545809394, 0.82163474041730045}, {1.1534203513372994, 0.52790870069930229},
+ {1.0880000000000001, 0.29599999999999982}}}, //t=0.63155333662549329, 0.80000000000000004
+{{{1.2071879545809394, 0.82163474041730045}, {1.2065040319428038, 0.81766753259119995},
+ {1.2058123269101506, 0.81370135061854221}}}, //t=0.63155333662549329, 0.6339049773632347
+{{{1.2058123269101506, 0.81370135061854221}, {1.152376363978022, 0.5244097415381026},
+ {1.0880000000000001, 0.29599999999999982}}}, //t=0.6339049773632347, 0.80000000000000004
+ //>=0.633974083 0.633975227 <=
+{{{0.33333333333333326, 0.81481481481481488}, {0.63395173631977997, 0.68744136726313931},
+ {1.205684411948591, 0.81344322326274499}}}, //t=0.33333333333333331, 0.63395173631977986
+{{{0.33333333333333326, 0.81481481481481488}, {0.63396444791444551, 0.68743368362444768},
+ {1.205732763658403, 0.81345617746834109}}}, //t=0.33333333333333331, 0.63396444791444551
+{{{1.205684411948591, 0.81344322326274499}, {1.2057085875611198, 0.81344969999329253},
+ {1.205732763658403, 0.81345617746834109}}}, //t=0.63395173631977986, 0.63396444791444551
+{{{1.205732763658403, 0.81345617746834109}, {1.267928895828891, 0.83008534558465619},
+ {1.3333333333333333, 0.85185185185185175}}}, //t=0.63396444791444551, 0.66666666666666663
+};
+
+static void pointFinder(const SkDQuad& q1, const SkDQuad& q2) {
+ for (int index = 0; index < 3; ++index) {
+ double t = q1.nearestT(q2[index]);
+ SkDPoint onQuad = q1.ptAtT(t);
+ SkDebugf("%s t=%1.9g (%1.9g,%1.9g) dist=%1.9g\n", __FUNCTION__, t, onQuad.fX, onQuad.fY,
+ onQuad.distance(q2[index]));
+ double left[3];
+ left[0] = ((const SkDLine&) q1[0]).isLeft(q2[index]);
+ left[1] = ((const SkDLine&) q1[1]).isLeft(q2[index]);
+ SkDLine diag = {{q1[0], q1[2]}};
+ left[2] = diag.isLeft(q2[index]);
+ SkDebugf("%s left=(%d, %d, %d) inHull=%s\n", __FUNCTION__, floatSign(left[0]),
+ floatSign(left[1]), floatSign(left[2]),
+ q1.pointInHull(q2[index]) ? "true" : "false");
+ }
+ SkDebugf("\n");
+}
+
+static void hullIntersect(const SkDQuad& q1, const SkDQuad& q2) {
+ SkDebugf("%s", __FUNCTION__);
+ SkIntersections ts;
+ for (int i1 = 0; i1 < 3; ++i1) {
+ SkDLine l1 = {{q1[i1], q1[(i1 + 1) % 3]}};
+ for (int i2 = 0; i2 < 3; ++i2) {
+ SkDLine l2 = {{q2[i2], q2[(i2 + 1) % 3]}};
+ if (ts.intersect(l1, l2)) {
+ SkDebugf(" [%d,%d]", i1, i2);
+ }
+ }
+ }
+ SkDebugf("\n");
+}
+
+static void QuadraticIntersection_PointFinder() {
+ pointFinder(pointFinderTestSet[0], pointFinderTestSet[4]);
+ pointFinder(pointFinderTestSet[4], pointFinderTestSet[0]);
+ pointFinder(pointFinderTestSet[0], pointFinderTestSet[6]);
+ pointFinder(pointFinderTestSet[6], pointFinderTestSet[0]);
+ hullIntersect(pointFinderTestSet[0], pointFinderTestSet[4]);
+ hullIntersect(pointFinderTestSet[0], pointFinderTestSet[6]);
+}
+
+static void intersectionFinder(int test1, int test2) {
+ const SkDQuad& quad1 = testSet[test1];
+ const SkDQuad& quad2 = testSet[test2];
+
+ double t1Seed = 0.5;
+ double t2Seed = 0.8;
+ double t1Step = 0.1;
+ double t2Step = 0.1;
+ SkDPoint t1[3], t2[3];
+ bool toggle = true;
+ do {
+ t1[0] = quad1.ptAtT(t1Seed - t1Step);
+ t1[1] = quad1.ptAtT(t1Seed);
+ t1[2] = quad1.ptAtT(t1Seed + t1Step);
+ t2[0] = quad2.ptAtT(t2Seed - t2Step);
+ t2[1] = quad2.ptAtT(t2Seed);
+ t2[2] = quad2.ptAtT(t2Seed + t2Step);
+ double dist[3][3];
+ dist[1][1] = t1[1].distance(t2[1]);
+ int best_i = 1, best_j = 1;
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ if (i == 1 && j == 1) {
+ continue;
+ }
+ dist[i][j] = t1[i].distance(t2[j]);
+ if (dist[best_i][best_j] > dist[i][j]) {
+ best_i = i;
+ best_j = j;
+ }
+ }
+ }
+ if (best_i == 0) {
+ t1Seed -= t1Step;
+ } else if (best_i == 2) {
+ t1Seed += t1Step;
+ }
+ if (best_j == 0) {
+ t2Seed -= t2Step;
+ } else if (best_j == 2) {
+ t2Seed += t2Step;
+ }
+ if (best_i == 1 && best_j == 1) {
+ if ((toggle ^= true)) {
+ t1Step /= 2;
+ } else {
+ t2Step /= 2;
+ }
+ }
+ } while (!t1[1].approximatelyEqual(t2[1]));
+ t1Step = t2Step = 0.1;
+ double t10 = t1Seed - t1Step * 2;
+ double t12 = t1Seed + t1Step * 2;
+ double t20 = t2Seed - t2Step * 2;
+ double t22 = t2Seed + t2Step * 2;
+ SkDPoint test;
+ while (!approximately_zero(t1Step)) {
+ test = quad1.ptAtT(t10);
+ t10 += t1[1].approximatelyEqual(test) ? -t1Step : t1Step;
+ t1Step /= 2;
+ }
+ t1Step = 0.1;
+ while (!approximately_zero(t1Step)) {
+ test = quad1.ptAtT(t12);
+ t12 -= t1[1].approximatelyEqual(test) ? -t1Step : t1Step;
+ t1Step /= 2;
+ }
+ while (!approximately_zero(t2Step)) {
+ test = quad2.ptAtT(t20);
+ t20 += t2[1].approximatelyEqual(test) ? -t2Step : t2Step;
+ t2Step /= 2;
+ }
+ t2Step = 0.1;
+ while (!approximately_zero(t2Step)) {
+ test = quad2.ptAtT(t22);
+ t22 -= t2[1].approximatelyEqual(test) ? -t2Step : t2Step;
+ t2Step /= 2;
+ }
+#if ONE_OFF_DEBUG
+ SkDebugf("%s t1=(%1.9g<%1.9g<%1.9g) t2=(%1.9g<%1.9g<%1.9g)\n", __FUNCTION__,
+ t10, t1Seed, t12, t20, t2Seed, t22);
+ SkDPoint p10 = quad1.ptAtT(t10);
+ SkDPoint p1Seed = quad1.ptAtT(t1Seed);
+ SkDPoint p12 = quad1.ptAtT(t12);
+ SkDebugf("%s p1=(%1.9g,%1.9g)<(%1.9g,%1.9g)<(%1.9g,%1.9g)\n", __FUNCTION__,
+ p10.fX, p10.fY, p1Seed.fX, p1Seed.fY, p12.fX, p12.fY);
+ SkDPoint p20 = quad2.ptAtT(t20);
+ SkDPoint p2Seed = quad2.ptAtT(t2Seed);
+ SkDPoint p22 = quad2.ptAtT(t22);
+ SkDebugf("%s p2=(%1.9g,%1.9g)<(%1.9g,%1.9g)<(%1.9g,%1.9g)\n", __FUNCTION__,
+ p20.fX, p20.fY, p2Seed.fX, p2Seed.fY, p22.fX, p22.fY);
+#endif
+}
+
+static void QuadraticIntersection_IntersectionFinder() {
+ intersectionFinder(0, 1);
+}
+
+DEF_TEST(PathOpsQuadIntersection, reporter) {
+ oneOffTests(reporter);
+ coincidentTest(reporter);
+ standardTestCases(reporter);
+ if (false) QuadraticIntersection_IntersectionFinder();
+ if (false) QuadraticIntersection_PointFinder();
+}
diff --git a/src/third_party/skia/tests/PathOpsQuadIntersectionTestData.cpp b/src/third_party/skia/tests/PathOpsQuadIntersectionTestData.cpp
new file mode 100644
index 0000000..0706efc
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsQuadIntersectionTestData.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "PathOpsQuadIntersectionTestData.h"
+
+const SkDQuad quadraticPoints[] = {
+ {{{0, 0}, {1, 0}, {0, 0}}},
+ {{{0, 0}, {0, 1}, {0, 0}}},
+ {{{0, 0}, {1, 1}, {0, 0}}},
+ {{{1, 1}, {2, 2}, {1, 1}}},
+};
+
+const size_t quadraticPoints_count = SK_ARRAY_COUNT(quadraticPoints);
+
+const SkDQuad quadraticLines[] = {
+ {{{0, 0}, {0, 0}, {1, 0}}},
+ {{{1, 0}, {0, 0}, {0, 0}}},
+ {{{1, 0}, {2, 0}, {3, 0}}},
+ {{{0, 0}, {0, 0}, {0, 1}}},
+ {{{0, 1}, {0, 0}, {0, 0}}},
+ {{{0, 1}, {0, 2}, {0, 3}}},
+ {{{0, 0}, {0, 0}, {1, 1}}},
+ {{{1, 1}, {0, 0}, {0, 0}}},
+ {{{1, 1}, {2, 2}, {3, 3}}},
+ {{{1, 1}, {3, 3}, {3, 3}}},
+ {{{1, 1}, {1, 1}, {2, 2}}},
+ {{{1, 1}, {1, 1}, {3, 3}}},
+ {{{1, 1}, {2, 2}, {4, 4}}}, // no coincident
+ {{{1, 1}, {3, 3}, {4, 4}}},
+ {{{1, 1}, {3, 3}, {2, 2}}},
+ {{{1, 1}, {4, 4}, {2, 2}}},
+ {{{1, 1}, {4, 4}, {3, 3}}},
+ {{{2, 2}, {1, 1}, {3, 3}}},
+ {{{2, 2}, {1, 1}, {4, 4}}},
+ {{{2, 2}, {3, 3}, {1, 1}}},
+ {{{2, 2}, {3, 3}, {4, 4}}},
+ {{{2, 2}, {4, 4}, {1, 1}}},
+ {{{2, 2}, {4, 4}, {3, 3}}},
+};
+
+const size_t quadraticLines_count = SK_ARRAY_COUNT(quadraticLines);
+
+static const double F = FLT_EPSILON * 3;
+static const double H = FLT_EPSILON * 4;
+static const double J = FLT_EPSILON * 5;
+static const double K = FLT_EPSILON * 8; // INVESTIGATE: why are larger multiples necessary?
+
+const SkDQuad quadraticModEpsilonLines[] = {
+ {{{0, F}, {0, 0}, {1, 0}}},
+ {{{0, 0}, {1, 0}, {0, F}}},
+ {{{1, 0}, {0, F}, {0, 0}}},
+ {{{1, H}, {2, 0}, {3, 0}}},
+// {{{F, 0}, {0, 0}, {0, 1}}}, // INVESTIGATE: even substituting K for F, quad is still linear.
+// {{{0, 0}, {0, 1}, {F, 0}}},
+// {{{0, 1}, {F, 0}, {0, 0}}},
+// {{{H, 1}, {0, 2}, {0, 3}}},
+ {{{0, F}, {0, 0}, {1, 1}}},
+ {{{0, 0}, {1, 1}, {F, 0}}},
+ {{{1, 1}, {F, 0}, {0, 0}}},
+ {{{1, 1+J}, {2, 2}, {3, 3}}},
+ {{{1, 1}, {3, 3}, {3+F, 3}}},
+ {{{1, 1}, {1+F, 1}, {2, 2}}},
+ {{{1, 1}, {2, 2}, {1, 1+F}}},
+ {{{1, 1}, {1, 1+F}, {3, 3}}},
+ {{{1+H, 1}, {2, 2}, {4, 4}}}, // no coincident
+ {{{1, 1+K}, {3, 3}, {4, 4}}},
+ {{{1, 1}, {3+F, 3}, {2, 2}}},
+ {{{1, 1}, {4, 4+F}, {2, 2}}},
+ {{{1, 1}, {4, 4}, {3+F, 3}}},
+ {{{2, 2}, {1, 1}, {3, 3+F}}},
+ {{{2+F, 2}, {1, 1}, {4, 4}}},
+ {{{2, 2+F}, {3, 3}, {1, 1}}},
+ {{{2, 2}, {3+F, 3}, {4, 4}}},
+ {{{2, 2}, {4, 4+F}, {1, 1}}},
+ {{{2, 2}, {4, 4}, {3+F, 3}}},
+};
+
+const size_t quadraticModEpsilonLines_count =
+ SK_ARRAY_COUNT(quadraticModEpsilonLines);
+
+const SkDQuad quadraticTests[][2] = {
+ { // one intersection
+ {{{0, 0},
+ {0, 1},
+ {1, 1}}},
+ {{{0, 1},
+ {0, 0},
+ {1, 0}}}
+ },
+ { // four intersections
+ {{{1, 0},
+ {2, 6},
+ {3, 0}}},
+ {{{0, 1},
+ {6, 2},
+ {0, 3}}}
+ }
+};
+
+const size_t quadraticTests_count = SK_ARRAY_COUNT(quadraticTests);
diff --git a/src/third_party/skia/tests/PathOpsQuadIntersectionTestData.h b/src/third_party/skia/tests/PathOpsQuadIntersectionTestData.h
new file mode 100644
index 0000000..3090fc9
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsQuadIntersectionTestData.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkPathOpsQuad.h"
+
+extern const SkDQuad quadraticLines[];
+extern const SkDQuad quadraticPoints[];
+extern const SkDQuad quadraticModEpsilonLines[];
+extern const SkDQuad quadraticTests[][2];
+
+extern const size_t quadraticLines_count;
+extern const size_t quadraticPoints_count;
+extern const size_t quadraticModEpsilonLines_count;
+extern const size_t quadraticTests_count;
diff --git a/src/third_party/skia/tests/PathOpsQuadLineIntersectionTest.cpp b/src/third_party/skia/tests/PathOpsQuadLineIntersectionTest.cpp
new file mode 100644
index 0000000..6a9e497
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsQuadLineIntersectionTest.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsTestCommon.h"
+#include "SkIntersections.h"
+#include "SkPathOpsLine.h"
+#include "SkPathOpsQuad.h"
+#include "SkReduceOrder.h"
+#include "Test.h"
+
+static struct lineQuad {
+ SkDQuad quad;
+ SkDLine line;
+ int result;
+ SkDPoint expected[2];
+} lineQuadTests[] = {
+ // quad line results
+ {{{{1, 1}, {2, 1}, {0, 2}}}, {{{0, 0}, {1, 1}}}, 1, {{1, 1}, {0, 0}} },
+ {{{{0, 0}, {1, 1}, {3, 1}}}, {{{0, 0}, {3, 1}}}, 2, {{0, 0}, {3, 1}} },
+ {{{{2, 0}, {1, 1}, {2, 2}}}, {{{0, 0}, {0, 2}}}, 0, {{0, 0}, {0, 0}} },
+ {{{{4, 0}, {0, 1}, {4, 2}}}, {{{3, 1}, {4, 1}}}, 0, {{0, 0}, {0, 0}} },
+ {{{{0, 0}, {0, 1}, {1, 1}}}, {{{0, 1}, {1, 0}}}, 1, {{.25, .75}, {0, 0}} },
+};
+
+static size_t lineQuadTests_count = SK_ARRAY_COUNT(lineQuadTests);
+
+static int doIntersect(SkIntersections& intersections, const SkDQuad& quad, const SkDLine& line,
+ bool& flipped) {
+ int result;
+ flipped = false;
+ if (line[0].fX == line[1].fX) {
+ double top = line[0].fY;
+ double bottom = line[1].fY;
+ flipped = top > bottom;
+ if (flipped) {
+ SkTSwap<double>(top, bottom);
+ }
+ result = intersections.vertical(quad, top, bottom, line[0].fX, flipped);
+ } else if (line[0].fY == line[1].fY) {
+ double left = line[0].fX;
+ double right = line[1].fX;
+ flipped = left > right;
+ if (flipped) {
+ SkTSwap<double>(left, right);
+ }
+ result = intersections.horizontal(quad, left, right, line[0].fY, flipped);
+ } else {
+ intersections.intersect(quad, line);
+ result = intersections.used();
+ }
+ return result;
+}
+
+static struct oneLineQuad {
+ SkDQuad quad;
+ SkDLine line;
+} oneOffs[] = {
+ {{{{97.9337616,100}, {88,112.94265}, {88,130}}},
+ {{{88.919838,120}, {107.058823,120}}}},
+ {{{{447.96701049804687, 894.4381103515625}, {448.007080078125, 894.4239501953125},
+ {448.0140380859375, 894.4215087890625}}},
+ {{{490.43548583984375, 879.40740966796875}, {405.59262084960937, 909.435546875}}}},
+ {{{{142.589081, 102.283646}, {149.821579, 100}, {158, 100}}},
+ {{{90, 230}, {160, 60}}}},
+ {{{{1101, 10}, {1101, 8.3431453704833984}, {1099.828857421875, 7.1711997985839844}}},
+ {{{1099.828857421875,7.1711711883544922}, {1099.121337890625,7.8786783218383789}}}},
+ {{{{973, 507}, {973, 508.24264526367187}, {972.12158203125, 509.12161254882812}}},
+ {{{930, 467}, {973, 510}}}},
+ {{{{369.848602, 145.680267}, {382.360413, 121.298294}, {406.207703, 121.298294}}},
+ {{{406.207703, 121.298294}, {348.781738, 123.864815}}}},
+};
+
+static size_t oneOffs_count = SK_ARRAY_COUNT(oneOffs);
+
+static void testOneOffs(skiatest::Reporter* reporter) {
+ bool flipped = false;
+ for (size_t index = 0; index < oneOffs_count; ++index) {
+ const SkDQuad& quad = oneOffs[index].quad;
+ SkASSERT(ValidQuad(quad));
+ const SkDLine& line = oneOffs[index].line;
+ SkASSERT(ValidLine(line));
+ SkIntersections intersections;
+ int result = doIntersect(intersections, quad, line, flipped);
+ for (int inner = 0; inner < result; ++inner) {
+ double quadT = intersections[0][inner];
+ SkDPoint quadXY = quad.ptAtT(quadT);
+ double lineT = intersections[1][inner];
+ SkDPoint lineXY = line.ptAtT(lineT);
+ if (!quadXY.approximatelyEqual(lineXY)) {
+ quadXY.approximatelyEqual(lineXY);
+ SkDebugf("");
+ }
+ REPORTER_ASSERT(reporter, quadXY.approximatelyEqual(lineXY));
+ }
+ }
+}
+
+DEF_TEST(PathOpsQuadLineIntersectionOneOff, reporter) {
+ testOneOffs(reporter);
+}
+
+DEF_TEST(PathOpsQuadLineIntersection, reporter) {
+ for (size_t index = 0; index < lineQuadTests_count; ++index) {
+ int iIndex = static_cast<int>(index);
+ const SkDQuad& quad = lineQuadTests[index].quad;
+ SkASSERT(ValidQuad(quad));
+ const SkDLine& line = lineQuadTests[index].line;
+ SkASSERT(ValidLine(line));
+ SkReduceOrder reducer1, reducer2;
+ int order1 = reducer1.reduce(quad);
+ int order2 = reducer2.reduce(line);
+ if (order1 < 3) {
+ SkDebugf("%s [%d] quad order=%d\n", __FUNCTION__, iIndex, order1);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ if (order2 < 2) {
+ SkDebugf("%s [%d] line order=%d\n", __FUNCTION__, iIndex, order2);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ SkIntersections intersections;
+ bool flipped = false;
+ int result = doIntersect(intersections, quad, line, flipped);
+ REPORTER_ASSERT(reporter, result == lineQuadTests[index].result);
+ if (intersections.used() <= 0) {
+ continue;
+ }
+ for (int pt = 0; pt < result; ++pt) {
+ double tt1 = intersections[0][pt];
+ REPORTER_ASSERT(reporter, tt1 >= 0 && tt1 <= 1);
+ SkDPoint t1 = quad.ptAtT(tt1);
+ double tt2 = intersections[1][pt];
+ REPORTER_ASSERT(reporter, tt2 >= 0 && tt2 <= 1);
+ SkDPoint t2 = line.ptAtT(tt2);
+ if (!t1.approximatelyEqual(t2)) {
+ SkDebugf("%s [%d,%d] x!= t1=%1.9g (%1.9g,%1.9g) t2=%1.9g (%1.9g,%1.9g)\n",
+ __FUNCTION__, iIndex, pt, tt1, t1.fX, t1.fY, tt2, t2.fX, t2.fY);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ if (!t1.approximatelyEqual(lineQuadTests[index].expected[0])
+ && (lineQuadTests[index].result == 1
+ || !t1.approximatelyEqual(lineQuadTests[index].expected[1]))) {
+ SkDebugf("%s t1=(%1.9g,%1.9g)\n", __FUNCTION__, t1.fX, t1.fY);
+ REPORTER_ASSERT(reporter, 0);
+ }
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsQuadLineIntersectionThreadedTest.cpp b/src/third_party/skia/tests/PathOpsQuadLineIntersectionThreadedTest.cpp
new file mode 100644
index 0000000..7e33b7b
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsQuadLineIntersectionThreadedTest.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsThreadedCommon.h"
+#include "SkIntersections.h"
+#include "SkPathOpsLine.h"
+#include "SkPathOpsQuad.h"
+#include "SkReduceOrder.h"
+
+static int doIntersect(SkIntersections& intersections, const SkDQuad& quad, const SkDLine& line,
+ bool& flipped) {
+ int result;
+ flipped = false;
+ if (line[0].fX == line[1].fX) {
+ double top = line[0].fY;
+ double bottom = line[1].fY;
+ flipped = top > bottom;
+ if (flipped) {
+ SkTSwap<double>(top, bottom);
+ }
+ result = intersections.vertical(quad, top, bottom, line[0].fX, flipped);
+ } else if (line[0].fY == line[1].fY) {
+ double left = line[0].fX;
+ double right = line[1].fX;
+ flipped = left > right;
+ if (flipped) {
+ SkTSwap<double>(left, right);
+ }
+ result = intersections.horizontal(quad, left, right, line[0].fY, flipped);
+ } else {
+ intersections.intersect(quad, line);
+ result = intersections.used();
+ }
+ return result;
+}
+
+static void testLineIntersect(skiatest::Reporter* reporter, const SkDQuad& quad,
+ const SkDLine& line, const double x, const double y) {
+ char pathStr[1024];
+ sk_bzero(pathStr, sizeof(pathStr));
+ char* str = pathStr;
+ str += sprintf(str, " path.moveTo(%1.9g, %1.9g);\n", quad[0].fX, quad[0].fY);
+ str += sprintf(str, " path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n", quad[1].fX,
+ quad[1].fY, quad[2].fX, quad[2].fY);
+ str += sprintf(str, " path.moveTo(%1.9g, %1.9g);\n", line[0].fX, line[0].fY);
+ str += sprintf(str, " path.lineTo(%1.9g, %1.9g);\n", line[1].fX, line[1].fY);
+
+ SkIntersections intersections;
+ bool flipped = false;
+ int result = doIntersect(intersections, quad, line, flipped);
+ bool found = false;
+ for (int index = 0; index < result; ++index) {
+ double quadT = intersections[0][index];
+ SkDPoint quadXY = quad.ptAtT(quadT);
+ double lineT = intersections[1][index];
+ SkDPoint lineXY = line.ptAtT(lineT);
+ if (quadXY.approximatelyEqual(lineXY)) {
+ found = true;
+ }
+ }
+ REPORTER_ASSERT(reporter, found);
+}
+
+// find a point on a quad by choosing a t from 0 to 1
+// create a vertical span above and below the point
+// verify that intersecting the vertical span and the quad returns t
+// verify that a vertical span starting at quad[0] intersects at t=0
+// verify that a vertical span starting at quad[2] intersects at t=1
+static void testQuadLineIntersectMain(PathOpsThreadState* data)
+{
+ PathOpsThreadState& state = *data;
+ REPORTER_ASSERT(state.fReporter, data);
+ int ax = state.fA & 0x03;
+ int ay = state.fA >> 2;
+ int bx = state.fB & 0x03;
+ int by = state.fB >> 2;
+ int cx = state.fC & 0x03;
+ int cy = state.fC >> 2;
+ SkDQuad quad = {{{(double) ax, (double) ay}, {(double) bx, (double) by},
+ {(double) cx, (double) cy}}};
+ SkReduceOrder reducer;
+ int order = reducer.reduce(quad);
+ if (order < 3) {
+ return;
+ }
+ for (int tIndex = 0; tIndex <= 4; ++tIndex) {
+ SkDPoint xy = quad.ptAtT(tIndex / 4.0);
+ for (int h = -2; h <= 2; ++h) {
+ for (int v = -2; v <= 2; ++v) {
+ if (h == v && abs(h) != 1) {
+ continue;
+ }
+ double x = xy.fX;
+ double y = xy.fY;
+ SkDLine line = {{{x - h, y - v}, {x, y}}};
+ testLineIntersect(state.fReporter, quad, line, x, y);
+ state.fReporter->bumpTestCount();
+ SkDLine line2 = {{{x, y}, {x + h, y + v}}};
+ testLineIntersect(state.fReporter, quad, line2, x, y);
+ state.fReporter->bumpTestCount();
+ SkDLine line3 = {{{x - h, y - v}, {x + h, y + v}}};
+ testLineIntersect(state.fReporter, quad, line3, x, y);
+ state.fReporter->bumpTestCount();
+ }
+ }
+ }
+}
+
+DEF_TEST(PathOpsQuadLineIntersectionThreaded, reporter) {
+ initializeTests(reporter, "testQuadLineIntersect");
+ PathOpsThreadedTestRunner testRunner(reporter);
+ for (int a = 0; a < 16; ++a) {
+ for (int b = 0 ; b < 16; ++b) {
+ for (int c = 0 ; c < 16; ++c) {
+ *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
+ (&testQuadLineIntersectMain, a, b, c, 0, &testRunner));
+ }
+ if (!reporter->allowExtendedTest()) goto finish;
+ }
+ }
+finish:
+ testRunner.render();
+}
diff --git a/src/third_party/skia/tests/PathOpsQuadParameterizationTest.cpp b/src/third_party/skia/tests/PathOpsQuadParameterizationTest.cpp
new file mode 100644
index 0000000..c7a2e87
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsQuadParameterizationTest.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkDQuadImplicit.h"
+#include "SkPathOpsQuad.h"
+#include "Test.h"
+
+static bool point_on_parameterized_curve(const SkDQuad& quad, const SkDPoint& point) {
+ SkDQuadImplicit q(quad);
+ double xx = q.x2() * point.fX * point.fX;
+ double xy = q.xy() * point.fX * point.fY;
+ double yy = q.y2() * point.fY * point.fY;
+ double x = q.x() * point.fX;
+ double y = q.y() * point.fY;
+ double c = q.c();
+ double sum = xx + xy + yy + x + y + c;
+ return approximately_zero(sum);
+}
+
+static const SkDQuad quadratics[] = {
+ {{{0, 0}, {1, 0}, {1, 1}}},
+};
+
+static const int quadratics_count = (int) SK_ARRAY_COUNT(quadratics);
+
+DEF_TEST(PathOpsQuadImplicit, reporter) {
+ // split large quadratic
+ // compare original, parts, to see if the are coincident
+ for (int index = 0; index < quadratics_count; ++index) {
+ const SkDQuad& test = quadratics[index];
+ SkDQuadPair split = test.chopAt(0.5);
+ SkDQuad midThird = test.subDivide(1.0/3, 2.0/3);
+ const SkDQuad* quads[] = {
+ &test, &midThird, &split.first(), &split.second()
+ };
+ int quadsCount = (int) SK_ARRAY_COUNT(quads);
+ for (int one = 0; one < quadsCount; ++one) {
+ for (int two = 0; two < quadsCount; ++two) {
+ for (int inner = 0; inner < 3; inner += 2) {
+ REPORTER_ASSERT(reporter, point_on_parameterized_curve(*quads[one],
+ (*quads[two])[inner]));
+ }
+ REPORTER_ASSERT(reporter, SkDQuadImplicit::Match(*quads[one], *quads[two]));
+ }
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsQuadReduceOrderTest.cpp b/src/third_party/skia/tests/PathOpsQuadReduceOrderTest.cpp
new file mode 100644
index 0000000..9a0bdcf
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsQuadReduceOrderTest.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsQuadIntersectionTestData.h"
+#include "SkIntersections.h"
+#include "SkPathOpsRect.h"
+#include "SkReduceOrder.h"
+#include "Test.h"
+
+static const SkDQuad testSet[] = {
+ {{{1, 1}, {2, 2}, {1, 1.000003}}},
+ {{{1, 0}, {2, 6}, {3, 0}}}
+};
+
+static const size_t testSetCount = SK_ARRAY_COUNT(testSet);
+
+static void oneOffTest(skiatest::Reporter* reporter) {
+ for (size_t index = 0; index < testSetCount; ++index) {
+ const SkDQuad& quad = testSet[index];
+ SkReduceOrder reducer;
+ SkDEBUGCODE(int result = ) reducer.reduce(quad);
+ SkASSERT(result == 3);
+ }
+}
+
+static void standardTestCases(skiatest::Reporter* reporter) {
+ size_t index;
+ SkReduceOrder reducer;
+ int order;
+ enum {
+ RunAll,
+ RunQuadraticLines,
+ RunQuadraticModLines,
+ RunNone
+ } run = RunAll;
+ int firstTestIndex = 0;
+#if 0
+ run = RunQuadraticLines;
+ firstTestIndex = 1;
+#endif
+ int firstQuadraticLineTest = run == RunAll ? 0 : run == RunQuadraticLines ? firstTestIndex
+ : SK_MaxS32;
+ int firstQuadraticModLineTest = run == RunAll ? 0 : run == RunQuadraticModLines ? firstTestIndex
+ : SK_MaxS32;
+
+ for (index = firstQuadraticLineTest; index < quadraticLines_count; ++index) {
+ const SkDQuad& quad = quadraticLines[index];
+ order = reducer.reduce(quad);
+ if (order != 2) {
+ SkDebugf("[%d] line quad order=%d\n", (int) index, order);
+ }
+ }
+ for (index = firstQuadraticModLineTest; index < quadraticModEpsilonLines_count; ++index) {
+ const SkDQuad& quad = quadraticModEpsilonLines[index];
+ order = reducer.reduce(quad);
+ if (order != 3) {
+ SkDebugf("[%d] line mod quad order=%d\n", (int) index, order);
+ }
+ }
+}
+
+DEF_TEST(PathOpsReduceOrderQuad, reporter) {
+ oneOffTest(reporter);
+ standardTestCases(reporter);
+}
diff --git a/src/third_party/skia/tests/PathOpsSimplifyDegenerateThreadedTest.cpp b/src/third_party/skia/tests/PathOpsSimplifyDegenerateThreadedTest.cpp
new file mode 100755
index 0000000..8e8c58b
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsSimplifyDegenerateThreadedTest.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsThreadedCommon.h"
+
+static void testSimplifyDegeneratesMain(PathOpsThreadState* data) {
+ SkASSERT(data);
+ PathOpsThreadState& state = *data;
+ char pathStr[1024];
+ bool progress = state.fReporter->verbose(); // FIXME: break out into its own parameter?
+ if (progress) {
+ sk_bzero(pathStr, sizeof(pathStr));
+ }
+ int ax = state.fA & 0x03;
+ int ay = state.fA >> 2;
+ int bx = state.fB & 0x03;
+ int by = state.fB >> 2;
+ int cx = state.fC & 0x03;
+ int cy = state.fC >> 2;
+ for (int d = 0; d < 16; ++d) {
+ int dx = d & 0x03;
+ int dy = d >> 2;
+ for (int e = d ; e < 16; ++e) {
+ int ex = e & 0x03;
+ int ey = e >> 2;
+ for (int f = d ; f < 16; ++f) {
+ int fx = f & 0x03;
+ int fy = f >> 2;
+ if (state.fD && (ex - dx) * (fy - dy)
+ != (ey - dy) * (fx - dx)) {
+ continue;
+ }
+ SkPath path, out;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(SkIntToScalar(ax), SkIntToScalar(ay));
+ path.lineTo(SkIntToScalar(bx), SkIntToScalar(by));
+ path.lineTo(SkIntToScalar(cx), SkIntToScalar(cy));
+ path.close();
+ path.moveTo(SkIntToScalar(dx), SkIntToScalar(dy));
+ path.lineTo(SkIntToScalar(ex), SkIntToScalar(ey));
+ path.lineTo(SkIntToScalar(fx), SkIntToScalar(fy));
+ path.close();
+ if (progress) {
+ char* str = pathStr;
+ str += sprintf(str, " path.moveTo(%d, %d);\n", ax, ay);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", bx, by);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", cx, cy);
+ str += sprintf(str, " path.close();\n");
+ str += sprintf(str, " path.moveTo(%d, %d);\n", dx, dy);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", ex, ey);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", fx, fy);
+ str += sprintf(str, " path.close();\n");
+ outputProgress(state.fPathStr, pathStr, SkPath::kWinding_FillType);
+ }
+ testSimplify(path, false, out, state, pathStr);
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ if (progress) {
+ outputProgress(state.fPathStr, pathStr, SkPath::kEvenOdd_FillType);
+ }
+ testSimplify(path, true, out, state, pathStr);
+ }
+ }
+ }
+}
+
+DEF_TEST(PathOpsSimplifyDegeneratesThreaded, reporter) {
+ initializeTests(reporter, "testDegenerates");
+ PathOpsThreadedTestRunner testRunner(reporter);
+ for (int a = 0; a < 16; ++a) {
+ int ax = a & 0x03;
+ int ay = a >> 2;
+ for (int b = a ; b < 16; ++b) {
+ int bx = b & 0x03;
+ int by = b >> 2;
+ for (int c = a ; c < 16; ++c) {
+ int cx = c & 0x03;
+ int cy = c >> 2;
+ bool abcIsATriangle = (bx - ax) * (cy - ay) != (by - ay) * (cx - ax);
+ *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
+ (&testSimplifyDegeneratesMain, a, b, c, abcIsATriangle,
+ &testRunner));
+ }
+ if (!reporter->allowExtendedTest()) goto finish;
+ }
+ }
+finish:
+ testRunner.render();
+}
diff --git a/src/third_party/skia/tests/PathOpsSimplifyFailTest.cpp b/src/third_party/skia/tests/PathOpsSimplifyFailTest.cpp
new file mode 100644
index 0000000..2a4b0a0
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsSimplifyFailTest.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkPath.h"
+#include "SkPathOps.h"
+#include "SkPoint.h"
+#include "Test.h"
+
+static const SkPoint nonFinitePts[] = {
+ { SK_ScalarInfinity, 0 },
+ { 0, SK_ScalarInfinity },
+ { SK_ScalarInfinity, SK_ScalarInfinity },
+ { SK_ScalarNegativeInfinity, 0},
+ { 0, SK_ScalarNegativeInfinity },
+ { SK_ScalarNegativeInfinity, SK_ScalarNegativeInfinity },
+ { SK_ScalarNegativeInfinity, SK_ScalarInfinity },
+ { SK_ScalarInfinity, SK_ScalarNegativeInfinity },
+ { SK_ScalarNaN, 0 },
+ { 0, SK_ScalarNaN },
+ { SK_ScalarNaN, SK_ScalarNaN },
+};
+
+const size_t nonFinitePtsCount = sizeof(nonFinitePts) / sizeof(nonFinitePts[0]);
+
+static const SkPoint finitePts[] = {
+ { 0, 0 },
+ { SK_ScalarMax, 0 },
+ { 0, SK_ScalarMax },
+ { SK_ScalarMax, SK_ScalarMax },
+ { SK_ScalarMin, 0 },
+ { 0, SK_ScalarMin },
+ { SK_ScalarMin, SK_ScalarMin },
+};
+
+const size_t finitePtsCount = sizeof(finitePts) / sizeof(finitePts[0]);
+
+static void failOne(skiatest::Reporter* reporter, int index) {
+ SkPath path;
+ int i = (int) (index % nonFinitePtsCount);
+ int f = (int) (index % finitePtsCount);
+ int g = (int) ((f + 1) % finitePtsCount);
+ switch (index % 13) {
+ case 0: path.lineTo(nonFinitePts[i]); break;
+ case 1: path.quadTo(nonFinitePts[i], nonFinitePts[i]); break;
+ case 2: path.quadTo(nonFinitePts[i], finitePts[f]); break;
+ case 3: path.quadTo(finitePts[f], nonFinitePts[i]); break;
+ case 4: path.cubicTo(nonFinitePts[i], finitePts[f], finitePts[f]); break;
+ case 5: path.cubicTo(finitePts[f], nonFinitePts[i], finitePts[f]); break;
+ case 6: path.cubicTo(finitePts[f], finitePts[f], nonFinitePts[i]); break;
+ case 7: path.cubicTo(nonFinitePts[i], nonFinitePts[i], finitePts[f]); break;
+ case 8: path.cubicTo(nonFinitePts[i], finitePts[f], nonFinitePts[i]); break;
+ case 9: path.cubicTo(finitePts[f], nonFinitePts[i], nonFinitePts[i]); break;
+ case 10: path.cubicTo(nonFinitePts[i], nonFinitePts[i], nonFinitePts[i]); break;
+ case 11: path.cubicTo(nonFinitePts[i], finitePts[f], finitePts[g]); break;
+ case 12: path.moveTo(nonFinitePts[i]); break;
+ }
+ SkPath result;
+ result.setFillType(SkPath::kWinding_FillType);
+ bool success = Simplify(path, &result);
+ REPORTER_ASSERT(reporter, !success);
+ REPORTER_ASSERT(reporter, result.isEmpty());
+ REPORTER_ASSERT(reporter, result.getFillType() == SkPath::kWinding_FillType);
+ reporter->bumpTestCount();
+}
+
+static void dontFailOne(skiatest::Reporter* reporter, int index) {
+ SkPath path;
+ int f = (int) (index % finitePtsCount);
+ int g = (int) ((f + 1) % finitePtsCount);
+ switch (index % 11) {
+ case 0: path.lineTo(finitePts[f]); break;
+ case 1: path.quadTo(finitePts[f], finitePts[f]); break;
+ case 2: path.quadTo(finitePts[f], finitePts[g]); break;
+ case 3: path.quadTo(finitePts[g], finitePts[f]); break;
+ case 4: path.cubicTo(finitePts[f], finitePts[f], finitePts[f]); break;
+ case 5: path.cubicTo(finitePts[f], finitePts[f], finitePts[g]); break;
+ case 6: path.cubicTo(finitePts[f], finitePts[g], finitePts[f]); break;
+ case 7: path.cubicTo(finitePts[f], finitePts[g], finitePts[g]); break;
+ case 8: path.cubicTo(finitePts[g], finitePts[f], finitePts[f]); break;
+ case 9: path.cubicTo(finitePts[g], finitePts[f], finitePts[g]); break;
+ case 10: path.moveTo(finitePts[f]); break;
+ }
+ SkPath result;
+ result.setFillType(SkPath::kWinding_FillType);
+ bool success = Simplify(path, &result);
+ // linux 32 debug fails test 13 because the quad is not treated as linear
+ // there's no error in the math that I can find -- it looks like a processor
+ // or compiler bug -- so for now, allow either to work
+ REPORTER_ASSERT(reporter, success || index == 13);
+ REPORTER_ASSERT(reporter, result.getFillType() != SkPath::kWinding_FillType);
+ reporter->bumpTestCount();
+}
+
+DEF_TEST(PathOpsSimplifyFail, reporter) {
+ for (int index = 0; index < (int) (13 * nonFinitePtsCount * finitePtsCount); ++index) {
+ failOne(reporter, index);
+ }
+ for (int index = 0; index < (int) (11 * finitePtsCount); ++index) {
+ dontFailOne(reporter, index);
+ }
+}
+
+DEF_TEST(PathOpsSimplifyFailOne, reporter) {
+ int index = 0;
+ failOne(reporter, index);
+}
+
+DEF_TEST(PathOpsSimplifyDontFailOne, reporter) {
+ int index = 13;
+ dontFailOne(reporter, index);
+}
diff --git a/src/third_party/skia/tests/PathOpsSimplifyQuadThreadedTest.cpp b/src/third_party/skia/tests/PathOpsSimplifyQuadThreadedTest.cpp
new file mode 100644
index 0000000..3c92cca
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsSimplifyQuadThreadedTest.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsThreadedCommon.h"
+
+static void testSimplifyQuadsMain(PathOpsThreadState* data)
+{
+ SkASSERT(data);
+ PathOpsThreadState& state = *data;
+ char pathStr[1024];
+ bool progress = state.fReporter->verbose(); // FIXME: break out into its own parameter?
+ if (progress) {
+ sk_bzero(pathStr, sizeof(pathStr));
+ }
+ int ax = state.fA & 0x03;
+ int ay = state.fA >> 2;
+ int bx = state.fB & 0x03;
+ int by = state.fB >> 2;
+ int cx = state.fC & 0x03;
+ int cy = state.fC >> 2;
+ int dx = state.fD & 0x03;
+ int dy = state.fD >> 2;
+ for (int e = 0 ; e < 16; ++e) {
+ int ex = e & 0x03;
+ int ey = e >> 2;
+ for (int f = e ; f < 16; ++f) {
+ int fx = f & 0x03;
+ int fy = f >> 2;
+ for (int g = f ; g < 16; ++g) {
+ int gx = g & 0x03;
+ int gy = g >> 2;
+ for (int h = g ; h < 16; ++h) {
+ int hx = h & 0x03;
+ int hy = h >> 2;
+ SkPath path, out;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(SkIntToScalar(ax), SkIntToScalar(ay));
+ path.quadTo(SkIntToScalar(bx), SkIntToScalar(by),
+ SkIntToScalar(cx), SkIntToScalar(cy));
+ path.lineTo(SkIntToScalar(dx), SkIntToScalar(dy));
+ path.close();
+ path.moveTo(SkIntToScalar(ex), SkIntToScalar(ey));
+ path.lineTo(SkIntToScalar(fx), SkIntToScalar(fy));
+ path.quadTo(SkIntToScalar(gx), SkIntToScalar(gy),
+ SkIntToScalar(hx), SkIntToScalar(hy));
+ path.close();
+ if (progress) {
+ // gdb: set print elements 400
+ char* str = pathStr;
+ str += sprintf(str, " path.moveTo(%d, %d);\n", ax, ay);
+ str += sprintf(str, " path.quadTo(%d, %d, %d, %d);\n", bx, by, cx, cy);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", dx, dy);
+ str += sprintf(str, " path.close();\n");
+ str += sprintf(str, " path.moveTo(%d, %d);\n", ex, ey);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", fx, fy);
+ str += sprintf(str, " path.quadTo(%d, %d, %d, %d);\n", gx, gy, hx, hy);
+ str += sprintf(str, " path.close();\n");
+ outputProgress(state.fPathStr, pathStr, SkPath::kWinding_FillType);
+ }
+ testSimplify(path, false, out, state, pathStr);
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ if (progress) {
+ outputProgress(state.fPathStr, pathStr, SkPath::kEvenOdd_FillType);
+ }
+ testSimplify(path, true, out, state, pathStr);
+ }
+ }
+ }
+ }
+}
+
+DEF_TEST(PathOpsSimplifyQuadsThreaded, reporter) {
+ initializeTests(reporter, "testQuads");
+ PathOpsThreadedTestRunner testRunner(reporter);
+ int a = 0;
+ for (; a < 16; ++a) {
+ for (int b = a ; b < 16; ++b) {
+ for (int c = b ; c < 16; ++c) {
+ for (int d = c; d < 16; ++d) {
+ *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
+ (&testSimplifyQuadsMain, a, b, c, d, &testRunner));
+ }
+ if (!reporter->allowExtendedTest()) goto finish;
+ }
+ }
+ }
+finish:
+ testRunner.render();
+ ShowTestArray();
+}
diff --git a/src/third_party/skia/tests/PathOpsSimplifyQuadralateralsThreadedTest.cpp b/src/third_party/skia/tests/PathOpsSimplifyQuadralateralsThreadedTest.cpp
new file mode 100755
index 0000000..f8e9a6e
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsSimplifyQuadralateralsThreadedTest.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsThreadedCommon.h"
+
+static void testSimplifyQuadralateralsMain(PathOpsThreadState* data)
+{
+ SkASSERT(data);
+ PathOpsThreadState& state = *data;
+ char pathStr[1024];
+ bool progress = state.fReporter->verbose(); // FIXME: break out into its own parameter?
+ if (progress) {
+ sk_bzero(pathStr, sizeof(pathStr));
+ }
+ int ax = state.fA & 0x03;
+ int ay = state.fA >> 2;
+ int bx = state.fB & 0x03;
+ int by = state.fB >> 2;
+ int cx = state.fC & 0x03;
+ int cy = state.fC >> 2;
+ int dx = state.fD & 0x03;
+ int dy = state.fD >> 2;
+ for (int e = 0 ; e < 16; ++e) {
+ int ex = e & 0x03;
+ int ey = e >> 2;
+ for (int f = e ; f < 16; ++f) {
+ int fx = f & 0x03;
+ int fy = f >> 2;
+ for (int g = f ; g < 16; ++g) {
+ int gx = g & 0x03;
+ int gy = g >> 2;
+ for (int h = g ; h < 16; ++h) {
+ int hx = h & 0x03;
+ int hy = h >> 2;
+ SkPath path, out;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(SkIntToScalar(ax), SkIntToScalar(ay));
+ path.lineTo(SkIntToScalar(bx), SkIntToScalar(by));
+ path.lineTo(SkIntToScalar(cx), SkIntToScalar(cy));
+ path.lineTo(SkIntToScalar(dx), SkIntToScalar(dy));
+ path.close();
+ path.moveTo(SkIntToScalar(ex), SkIntToScalar(ey));
+ path.lineTo(SkIntToScalar(fx), SkIntToScalar(fy));
+ path.lineTo(SkIntToScalar(gx), SkIntToScalar(gy));
+ path.lineTo(SkIntToScalar(hx), SkIntToScalar(hy));
+ path.close();
+ if (progress) {
+ // gdb: set print elements 400
+ char* str = pathStr;
+ str += sprintf(str, " path.moveTo(%d, %d);\n", ax, ay);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", bx, by);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", cx, cy);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", dx, dy);
+ str += sprintf(str, " path.close();\n");
+ str += sprintf(str, " path.moveTo(%d, %d);\n", ex, ey);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", fx, fy);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", gx, gy);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", hx, hy);
+ str += sprintf(str, " path.close();\n");
+ outputProgress(state.fPathStr, pathStr, SkPath::kWinding_FillType);
+ }
+ testSimplify(path, false, out, state, pathStr);
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ if (progress) {
+ outputProgress(state.fPathStr, pathStr, SkPath::kEvenOdd_FillType);
+ }
+ testSimplify(path, true, out, state, pathStr);
+ }
+ }
+ }
+ }
+}
+
+DEF_TEST(PathOpsSimplifyQuadralateralsThreaded, reporter) {
+ initializeTests(reporter, "testQuadralaterals");
+ PathOpsThreadedTestRunner testRunner(reporter);
+ for (int a = 0; a < 16; ++a) {
+ for (int b = a ; b < 16; ++b) {
+ for (int c = b ; c < 16; ++c) {
+ for (int d = c; d < 16; ++d) {
+ *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
+ (&testSimplifyQuadralateralsMain, a, b, c, d, &testRunner));
+ }
+ if (!reporter->allowExtendedTest()) goto finish;
+ }
+ }
+ }
+finish:
+ testRunner.render();
+}
diff --git a/src/third_party/skia/tests/PathOpsSimplifyRectThreadedTest.cpp b/src/third_party/skia/tests/PathOpsSimplifyRectThreadedTest.cpp
new file mode 100644
index 0000000..52a78ec
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsSimplifyRectThreadedTest.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsThreadedCommon.h"
+
+// four rects, of four sizes
+// for 3 smaller sizes, tall, wide
+ // top upper mid lower bottom aligned (3 bits, 5 values)
+ // same with x (3 bits, 5 values)
+// not included, square, tall, wide (2 bits)
+// cw or ccw (1 bit)
+
+static void testSimplify4x4RectsMain(PathOpsThreadState* data)
+{
+ SkASSERT(data);
+ PathOpsThreadState& state = *data;
+ char pathStr[1024]; // gdb: set print elements 400
+ bool progress = state.fReporter->verbose(); // FIXME: break out into its own parameter?
+ if (progress) {
+ sk_bzero(pathStr, sizeof(pathStr));
+ }
+ int aShape = state.fA & 0x03;
+ SkPath::Direction aCW = state.fA >> 2 ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
+ int bShape = state.fB & 0x03;
+ SkPath::Direction bCW = state.fB >> 2 ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
+ int cShape = state.fC & 0x03;
+ SkPath::Direction cCW = state.fC >> 2 ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
+ int dShape = state.fD & 0x03;
+ SkPath::Direction dCW = state.fD >> 2 ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
+ for (int aXAlign = 0; aXAlign < 5; ++aXAlign) {
+ for (int aYAlign = 0; aYAlign < 5; ++aYAlign) {
+ for (int bXAlign = 0; bXAlign < 5; ++bXAlign) {
+ for (int bYAlign = 0; bYAlign < 5; ++bYAlign) {
+ for (int cXAlign = 0; cXAlign < 5; ++cXAlign) {
+ for (int cYAlign = 0; cYAlign < 5; ++cYAlign) {
+ for (int dXAlign = 0; dXAlign < 5; ++dXAlign) {
+ for (int dYAlign = 0; dYAlign < 5; ++dYAlign) {
+ SkPath path, out;
+ char* str = pathStr;
+ path.setFillType(SkPath::kWinding_FillType);
+ int l, t, r, b;
+ if (aShape) {
+ switch (aShape) {
+ case 1: // square
+ l = 0; r = 60;
+ t = 0; b = 60;
+ aXAlign = 5;
+ aYAlign = 5;
+ break;
+ case 2:
+ l = aXAlign * 12;
+ r = l + 30;
+ t = 0; b = 60;
+ aYAlign = 5;
+ break;
+ case 3:
+ l = 0; r = 60;
+ t = aYAlign * 12;
+ b = l + 30;
+ aXAlign = 5;
+ break;
+ }
+ path.addRect(SkIntToScalar(l), SkIntToScalar(t), SkIntToScalar(r), SkIntToScalar(b),
+ aCW);
+ if (progress) {
+ str += sprintf(str, " path.addRect(%d, %d, %d, %d,"
+ " SkPath::kC%sW_Direction);\n", l, t, r, b, aCW ? "C" : "");
+ }
+ } else {
+ aXAlign = 5;
+ aYAlign = 5;
+ }
+ if (bShape) {
+ switch (bShape) {
+ case 1: // square
+ l = bXAlign * 10;
+ r = l + 20;
+ t = bYAlign * 10;
+ b = l + 20;
+ break;
+ case 2:
+ l = bXAlign * 10;
+ r = l + 20;
+ t = 10; b = 40;
+ bYAlign = 5;
+ break;
+ case 3:
+ l = 10; r = 40;
+ t = bYAlign * 10;
+ b = l + 20;
+ bXAlign = 5;
+ break;
+ }
+ path.addRect(SkIntToScalar(l), SkIntToScalar(t), SkIntToScalar(r), SkIntToScalar(b),
+ bCW);
+ if (progress) {
+ str += sprintf(str, " path.addRect(%d, %d, %d, %d,"
+ " SkPath::kC%sW_Direction);\n", l, t, r, b, bCW ? "C" : "");
+ }
+ } else {
+ bXAlign = 5;
+ bYAlign = 5;
+ }
+ if (cShape) {
+ switch (cShape) {
+ case 1: // square
+ l = cXAlign * 6;
+ r = l + 12;
+ t = cYAlign * 6;
+ b = l + 12;
+ break;
+ case 2:
+ l = cXAlign * 6;
+ r = l + 12;
+ t = 20; b = 30;
+ cYAlign = 5;
+ break;
+ case 3:
+ l = 20; r = 30;
+ t = cYAlign * 6;
+ b = l + 20;
+ cXAlign = 5;
+ break;
+ }
+ path.addRect(SkIntToScalar(l), SkIntToScalar(t), SkIntToScalar(r), SkIntToScalar(b),
+ cCW);
+ if (progress) {
+ str += sprintf(str, " path.addRect(%d, %d, %d, %d,"
+ " SkPath::kC%sW_Direction);\n", l, t, r, b, cCW ? "C" : "");
+ }
+ } else {
+ cXAlign = 5;
+ cYAlign = 5;
+ }
+ if (dShape) {
+ switch (dShape) {
+ case 1: // square
+ l = dXAlign * 4;
+ r = l + 9;
+ t = dYAlign * 4;
+ b = l + 9;
+ break;
+ case 2:
+ l = dXAlign * 6;
+ r = l + 9;
+ t = 32; b = 36;
+ dYAlign = 5;
+ break;
+ case 3:
+ l = 32; r = 36;
+ t = dYAlign * 6;
+ b = l + 9;
+ dXAlign = 5;
+ break;
+ }
+ path.addRect(SkIntToScalar(l), SkIntToScalar(t), SkIntToScalar(r), SkIntToScalar(b),
+ dCW);
+ if (progress) {
+ str += sprintf(str, " path.addRect(%d, %d, %d, %d,"
+ " SkPath::kC%sW_Direction);\n", l, t, r, b, dCW ? "C" : "");
+ }
+ } else {
+ dXAlign = 5;
+ dYAlign = 5;
+ }
+ path.close();
+ if (progress) {
+ outputProgress(state.fPathStr, pathStr, SkPath::kWinding_FillType);
+ }
+ testSimplify(path, false, out, state, pathStr);
+ if (progress) {
+ outputProgress(state.fPathStr, pathStr, SkPath::kEvenOdd_FillType);
+ }
+ testSimplify(path, true, out, state, pathStr);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+DEF_TEST(PathOpsSimplifyRectsThreaded, reporter) {
+ initializeTests(reporter, "testLine");
+ PathOpsThreadedTestRunner testRunner(reporter);
+ for (int a = 0; a < 8; ++a) { // outermost
+ for (int b = a ; b < 8; ++b) {
+ for (int c = b ; c < 8; ++c) {
+ for (int d = c; d < 8; ++d) {
+ *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
+ (&testSimplify4x4RectsMain, a, b, c, d, &testRunner));
+ }
+ if (!reporter->allowExtendedTest()) goto finish;
+ }
+ }
+ }
+finish:
+ testRunner.render();
+}
diff --git a/src/third_party/skia/tests/PathOpsSimplifyTest.cpp b/src/third_party/skia/tests/PathOpsSimplifyTest.cpp
new file mode 100644
index 0000000..88547a0
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsSimplifyTest.cpp
@@ -0,0 +1,5124 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+
+#define TEST(name) { name, #name }
+
+static void testLine1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2,0);
+ path.lineTo(1,1);
+ path.lineTo(0,0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine1x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(2,0);
+ path.lineTo(1,1);
+ path.lineTo(0,0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void addInnerCWTriangle(SkPath& path) {
+ path.moveTo(3,0);
+ path.lineTo(4,1);
+ path.lineTo(2,1);
+ path.close();
+}
+
+static void addInnerCCWTriangle(SkPath& path) {
+ path.moveTo(3,0);
+ path.lineTo(2,1);
+ path.lineTo(4,1);
+ path.close();
+}
+
+static void addOuterCWTriangle(SkPath& path) {
+ path.moveTo(3,0);
+ path.lineTo(6,2);
+ path.lineTo(0,2);
+ path.close();
+}
+
+static void addOuterCCWTriangle(SkPath& path) {
+ path.moveTo(3,0);
+ path.lineTo(0,2);
+ path.lineTo(6,2);
+ path.close();
+}
+
+static void testLine2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ addInnerCWTriangle(path);
+ addOuterCWTriangle(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine2x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ addInnerCWTriangle(path);
+ addOuterCWTriangle(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ addInnerCCWTriangle(path);
+ addOuterCWTriangle(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine3x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ addInnerCCWTriangle(path);
+ addOuterCWTriangle(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine3a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ addInnerCWTriangle(path);
+ addOuterCCWTriangle(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine3ax(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ addInnerCWTriangle(path);
+ addOuterCCWTriangle(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine3b(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ addInnerCCWTriangle(path);
+ addOuterCCWTriangle(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine3bx(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ addInnerCCWTriangle(path);
+ addOuterCCWTriangle(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ addOuterCCWTriangle(path);
+ addOuterCWTriangle(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine4x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ addOuterCCWTriangle(path);
+ addOuterCWTriangle(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ addOuterCWTriangle(path);
+ addOuterCWTriangle(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine5x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ addOuterCWTriangle(path);
+ addOuterCWTriangle(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine6(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0,0);
+ path.lineTo(4,0);
+ path.lineTo(2,2);
+ path.close();
+ path.moveTo(2,0);
+ path.lineTo(6,0);
+ path.lineTo(4,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine6x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,0);
+ path.lineTo(4,0);
+ path.lineTo(2,2);
+ path.close();
+ path.moveTo(2,0);
+ path.lineTo(6,0);
+ path.lineTo(4,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine7(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0,0);
+ path.lineTo(4,0);
+ path.lineTo(2,2);
+ path.close();
+ path.moveTo(6,0);
+ path.lineTo(2,0);
+ path.lineTo(4,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine7x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,0);
+ path.lineTo(4,0);
+ path.lineTo(2,2);
+ path.close();
+ path.moveTo(6,0);
+ path.lineTo(2,0);
+ path.lineTo(4,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine7a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0,0);
+ path.lineTo(4,0);
+ path.lineTo(2,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine7ax(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,0);
+ path.lineTo(4,0);
+ path.lineTo(2,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine7b(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0,0);
+ path.lineTo(4,0);
+ path.close();
+ path.moveTo(6,0);
+ path.lineTo(2,0);
+ path.lineTo(4,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine7bx(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,0);
+ path.lineTo(4,0);
+ path.close();
+ path.moveTo(6,0);
+ path.lineTo(2,0);
+ path.lineTo(4,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine8(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0,4);
+ path.lineTo(4,4);
+ path.lineTo(2,2);
+ path.close();
+ path.moveTo(2,4);
+ path.lineTo(6,4);
+ path.lineTo(4,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine8x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,4);
+ path.lineTo(4,4);
+ path.lineTo(2,2);
+ path.close();
+ path.moveTo(2,4);
+ path.lineTo(6,4);
+ path.lineTo(4,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine9(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0,4);
+ path.lineTo(4,4);
+ path.lineTo(2,2);
+ path.close();
+ path.moveTo(6,4);
+ path.lineTo(2,4);
+ path.lineTo(4,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine9x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,4);
+ path.lineTo(4,4);
+ path.lineTo(2,2);
+ path.close();
+ path.moveTo(6,4);
+ path.lineTo(2,4);
+ path.lineTo(4,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine10(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0,4);
+ path.lineTo(4,4);
+ path.lineTo(2,2);
+ path.close();
+ path.moveTo(2,1);
+ path.lineTo(3,4);
+ path.lineTo(6,1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine10x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,4);
+ path.lineTo(4,4);
+ path.lineTo(2,2);
+ path.close();
+ path.moveTo(2,1);
+ path.lineTo(3,4);
+ path.lineTo(6,1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine10a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0,4);
+ path.lineTo(8,4);
+ path.lineTo(4,0);
+ path.close();
+ path.moveTo(2,2);
+ path.lineTo(3,3);
+ path.lineTo(4,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine10ax(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,4);
+ path.lineTo(8,4);
+ path.lineTo(4,0);
+ path.close();
+ path.moveTo(2,2);
+ path.lineTo(3,3);
+ path.lineTo(4,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void addCWContainer(SkPath& path) {
+ path.moveTo(6,4);
+ path.lineTo(0,4);
+ path.lineTo(3,1);
+ path.close();
+}
+
+static void addCCWContainer(SkPath& path) {
+ path.moveTo(0,4);
+ path.lineTo(6,4);
+ path.lineTo(3,1);
+ path.close();
+}
+
+static void addCWContents(SkPath& path) {
+ path.moveTo(2,3);
+ path.lineTo(3,2);
+ path.lineTo(4,3);
+ path.close();
+}
+
+static void addCCWContents(SkPath& path) {
+ path.moveTo(3,2);
+ path.lineTo(2,3);
+ path.lineTo(4,3);
+ path.close();
+}
+
+static void testLine11(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ addCWContainer(path);
+ addCWContents(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine11x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ addCWContainer(path);
+ addCWContents(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine12(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ addCCWContainer(path);
+ addCWContents(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine12x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ addCCWContainer(path);
+ addCWContents(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine13(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ addCWContainer(path);
+ addCCWContents(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine13x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ addCWContainer(path);
+ addCCWContents(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine14(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ addCCWContainer(path);
+ addCCWContents(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine14x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ addCCWContainer(path);
+ addCCWContents(path);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine15(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine15x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine16(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 4, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine16x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 4, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine17(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine17x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine18(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 4, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine18x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 4, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine19(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 16, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine19x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 16, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine20(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 12, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine20x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 12, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine21(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 16, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine21x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 16, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine22(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine22x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine23(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine23x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine24a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2,0);
+ path.lineTo(4,4);
+ path.lineTo(0,4);
+ path.close();
+ path.moveTo(2,0);
+ path.lineTo(1,2);
+ path.lineTo(2,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine24ax(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(2,0);
+ path.lineTo(4,4);
+ path.lineTo(0,4);
+ path.close();
+ path.moveTo(2,0);
+ path.lineTo(1,2);
+ path.lineTo(2,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine24(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 18, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine24x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 18, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine25(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 6, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine25x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 6, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine26(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 18, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 12, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine26x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 18, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 12, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine27(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 18, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 8, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine27x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 18, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 8, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine28(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 6, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 0, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine28x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 6, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 0, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine29(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 18, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 12, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine29x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 18, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 12, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine30(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 4, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine30x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 4, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine31(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 4, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine31x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 4, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine32(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine32x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine33(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 16, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine33x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 16, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine34(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 6, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine34x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 6, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine35(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 0, 18, 18, SkPath::kCW_Direction);
+ path.addRect(4, 16, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine35x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 0, 18, 18, SkPath::kCW_Direction);
+ path.addRect(4, 16, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine36(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 10, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 12, 18, 18, SkPath::kCW_Direction);
+ path.addRect(4, 16, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine36x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 10, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 12, 18, 18, SkPath::kCW_Direction);
+ path.addRect(4, 16, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine37(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 20, 20, 20, SkPath::kCW_Direction);
+ path.addRect(18, 24, 30, 30, SkPath::kCW_Direction);
+ path.addRect(0, 0, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine37x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 20, 20, 20, SkPath::kCW_Direction);
+ path.addRect(18, 24, 30, 30, SkPath::kCW_Direction);
+ path.addRect(0, 0, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine38(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(10, 0, 30, 30, SkPath::kCW_Direction);
+ path.addRect(6, 12, 18, 18, SkPath::kCW_Direction);
+ path.addRect(12, 12, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine38x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(10, 0, 30, 30, SkPath::kCW_Direction);
+ path.addRect(6, 12, 18, 18, SkPath::kCW_Direction);
+ path.addRect(12, 12, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine40(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(10, 0, 30, 30, SkPath::kCW_Direction);
+ path.addRect(12, 18, 24, 24, SkPath::kCW_Direction);
+ path.addRect(4, 16, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine40x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(10, 0, 30, 30, SkPath::kCW_Direction);
+ path.addRect(12, 18, 24, 24, SkPath::kCW_Direction);
+ path.addRect(4, 16, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine41(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(18, 24, 30, 30, SkPath::kCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine41x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(18, 24, 30, 30, SkPath::kCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine42(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(8, 16, 17, 17, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine42x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(8, 16, 17, 17, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine43(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 24, 18, 18, SkPath::kCW_Direction);
+ path.addRect(0, 32, 9, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine43x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 24, 18, 18, SkPath::kCW_Direction);
+ path.addRect(0, 32, 9, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine44(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(10, 40, 30, 30, SkPath::kCW_Direction);
+ path.addRect(18, 0, 30, 30, SkPath::kCW_Direction);
+ path.addRect(18, 32, 27, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine44x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(10, 40, 30, 30, SkPath::kCW_Direction);
+ path.addRect(18, 0, 30, 30, SkPath::kCW_Direction);
+ path.addRect(18, 32, 27, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine45(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(10, 0, 30, 30, SkPath::kCW_Direction);
+ path.addRect(18, 0, 30, 30, SkPath::kCW_Direction);
+ path.addRect(24, 32, 33, 36, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine45x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(10, 0, 30, 30, SkPath::kCW_Direction);
+ path.addRect(18, 0, 30, 30, SkPath::kCW_Direction);
+ path.addRect(24, 32, 33, 36, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine46(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(10, 40, 30, 30, SkPath::kCW_Direction);
+ path.addRect(24, 0, 36, 36, SkPath::kCW_Direction);
+ path.addRect(24, 32, 33, 36, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine46x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(10, 40, 30, 30, SkPath::kCW_Direction);
+ path.addRect(24, 0, 36, 36, SkPath::kCW_Direction);
+ path.addRect(24, 32, 33, 36, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine47(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 0, 9, 9, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine47x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 0, 9, 9, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine48(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 6, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 0, 9, 9, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine48x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 6, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 0, 9, 9, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine49(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 0, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine49x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(0, 0, 9, 9, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine50(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(10, 30, 30, 30, SkPath::kCW_Direction);
+ path.addRect(24, 20, 36, 30, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine50x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(10, 30, 30, 30, SkPath::kCW_Direction);
+ path.addRect(24, 20, 36, 30, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine51(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine51x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine52(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 30, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 20, 18, 30, SkPath::kCW_Direction);
+ path.addRect(32, 0, 36, 41, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine52x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 30, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 20, 18, 30, SkPath::kCW_Direction);
+ path.addRect(32, 0, 36, 41, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine53(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(10, 30, 30, 30, SkPath::kCW_Direction);
+ path.addRect(12, 20, 24, 30, SkPath::kCW_Direction);
+ path.addRect(12, 32, 21, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine53x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(10, 30, 30, 30, SkPath::kCW_Direction);
+ path.addRect(12, 20, 24, 30, SkPath::kCW_Direction);
+ path.addRect(12, 32, 21, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine54(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 0, 18, 18, SkPath::kCW_Direction);
+ path.addRect(8, 4, 17, 17, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine54x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 0, 18, 18, SkPath::kCW_Direction);
+ path.addRect(8, 4, 17, 17, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine55(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 6, 18, 18, SkPath::kCW_Direction);
+ path.addRect(4, 4, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine55x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 6, 18, 18, SkPath::kCW_Direction);
+ path.addRect(4, 4, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine56(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 20, 20, 20, SkPath::kCW_Direction);
+ path.addRect(18, 20, 30, 30, SkPath::kCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine56x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 20, 20, 20, SkPath::kCW_Direction);
+ path.addRect(18, 20, 30, 30, SkPath::kCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine57(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(20, 0, 40, 40, SkPath::kCW_Direction);
+ path.addRect(20, 0, 30, 40, SkPath::kCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine57x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(20, 0, 40, 40, SkPath::kCW_Direction);
+ path.addRect(20, 0, 30, 40, SkPath::kCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine58(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCCW_Direction);
+ path.addRect(0, 12, 9, 9, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine58x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 0, 12, 12, SkPath::kCCW_Direction);
+ path.addRect(0, 12, 9, 9, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine59(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 6, 18, 18, SkPath::kCCW_Direction);
+ path.addRect(4, 4, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine59x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 6, 18, 18, SkPath::kCCW_Direction);
+ path.addRect(4, 4, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine60(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 12, 18, 18, SkPath::kCCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine60x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(6, 12, 18, 18, SkPath::kCCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine61(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(12, 0, 24, 24, SkPath::kCCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine61x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(12, 0, 24, 24, SkPath::kCCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine62(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine62x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine63(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(0, 10, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 6, 12, 12, SkPath::kCCW_Direction);
+ path.addRect(0, 32, 9, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine63x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(0, 10, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 6, 12, 12, SkPath::kCCW_Direction);
+ path.addRect(0, 32, 9, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine64(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(10, 40, 30, 30, SkPath::kCW_Direction);
+ path.addRect(18, 6, 30, 30, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine64x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(10, 40, 30, 30, SkPath::kCW_Direction);
+ path.addRect(18, 6, 30, 30, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine65(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(10, 0, 30, 30, SkPath::kCW_Direction);
+ path.addRect(24, 0, 36, 36, SkPath::kCW_Direction);
+ path.addRect(32, 6, 36, 41, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine65x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(10, 0, 30, 30, SkPath::kCW_Direction);
+ path.addRect(24, 0, 36, 36, SkPath::kCW_Direction);
+ path.addRect(32, 6, 36, 41, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine66(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(0, 30, 20, 20, SkPath::kCW_Direction);
+ path.addRect(12, 20, 24, 30, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine66x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(0, 30, 20, 20, SkPath::kCW_Direction);
+ path.addRect(12, 20, 24, 30, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine67(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(10, 40, 30, 30, SkPath::kCW_Direction);
+ path.addRect(24, 20, 36, 30, SkPath::kCW_Direction);
+ path.addRect(32, 0, 36, 41, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine67x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(10, 40, 30, 30, SkPath::kCW_Direction);
+ path.addRect(24, 20, 36, 30, SkPath::kCW_Direction);
+ path.addRect(32, 0, 36, 41, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCW_Direction);
+ path.addRect(1, 2, 4, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68ax(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCW_Direction);
+ path.addRect(1, 2, 4, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68b(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(1, 2, 2, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68bx(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(1, 2, 2, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68c(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 8, 8, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCW_Direction);
+ path.addRect(1, 2, 4, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68cx(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 8, 8, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCW_Direction);
+ path.addRect(1, 2, 4, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 8, 8, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(1, 2, 4, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68dx(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 8, 8, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(1, 2, 4, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68e(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(1, 2, 2, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68ex(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(1, 2, 2, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68f(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(1, 2, 2, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68fx(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(1, 2, 2, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68g(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(1, 2, 2, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68gx(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(1, 2, 2, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68h(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(1, 2, 2, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine68hx(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 8, 8, SkPath::kCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 6, 6, SkPath::kCCW_Direction);
+ path.addRect(1, 2, 2, 2, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine69(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 20, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 20, 12, 30, SkPath::kCW_Direction);
+ path.addRect(12, 32, 21, 36, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine69x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 20, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 20, 12, 30, SkPath::kCW_Direction);
+ path.addRect(12, 32, 21, 36, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine70(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 24, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 32, 21, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine70x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 24, 12, 12, SkPath::kCW_Direction);
+ path.addRect(12, 32, 21, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine71(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(12, 0, 24, 24, SkPath::kCW_Direction);
+ path.addRect(12, 32, 21, 36, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine71x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 20, 20, SkPath::kCW_Direction);
+ path.addRect(12, 0, 24, 24, SkPath::kCW_Direction);
+ path.addRect(12, 32, 21, 36, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine72(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(10, 40, 30, 30, SkPath::kCW_Direction);
+ path.addRect(6, 20, 18, 30, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine72x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(10, 40, 30, 30, SkPath::kCW_Direction);
+ path.addRect(6, 20, 18, 30, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine73(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(0, 40, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 20, 12, 30, SkPath::kCW_Direction);
+ path.addRect(0, 0, 9, 9, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine73x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(0, 40, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 20, 12, 30, SkPath::kCW_Direction);
+ path.addRect(0, 0, 9, 9, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine74(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(20, 30, 40, 40, SkPath::kCW_Direction);
+ path.addRect(24, 20, 36, 30, SkPath::kCCW_Direction);
+ path.addRect(32, 24, 36, 41, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine74x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(20, 30, 40, 40, SkPath::kCW_Direction);
+ path.addRect(24, 20, 36, 30, SkPath::kCCW_Direction);
+ path.addRect(32, 24, 36, 41, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine75(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(10, 0, 30, 30, SkPath::kCCW_Direction);
+ path.addRect(18, 0, 30, 30, SkPath::kCCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine75x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 60, 60, SkPath::kCW_Direction);
+ path.addRect(10, 0, 30, 30, SkPath::kCCW_Direction);
+ path.addRect(18, 0, 30, 30, SkPath::kCCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine76(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(36, 0, 66, 60, SkPath::kCW_Direction);
+ path.addRect(10, 20, 40, 30, SkPath::kCW_Direction);
+ path.addRect(24, 20, 36, 30, SkPath::kCCW_Direction);
+ path.addRect(32, 6, 36, 41, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine76x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(36, 0, 66, 60, SkPath::kCW_Direction);
+ path.addRect(10, 20, 40, 30, SkPath::kCW_Direction);
+ path.addRect(24, 20, 36, 30, SkPath::kCCW_Direction);
+ path.addRect(32, 6, 36, 41, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine77(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(20, 0, 40, 40, SkPath::kCW_Direction);
+ path.addRect(24, 6, 36, 36, SkPath::kCCW_Direction);
+ path.addRect(24, 32, 33, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine77x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(20, 0, 40, 40, SkPath::kCW_Direction);
+ path.addRect(24, 6, 36, 36, SkPath::kCCW_Direction);
+ path.addRect(24, 32, 33, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine78(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 30, 60, SkPath::kCW_Direction);
+ path.addRect(10, 20, 30, 30, SkPath::kCCW_Direction);
+ path.addRect(18, 20, 30, 30, SkPath::kCCW_Direction);
+ path.addRect(32, 0, 36, 41, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine78x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 30, 60, SkPath::kCW_Direction);
+ path.addRect(10, 20, 30, 30, SkPath::kCCW_Direction);
+ path.addRect(18, 20, 30, 30, SkPath::kCCW_Direction);
+ path.addRect(32, 0, 36, 41, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine79(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 36, 60, 30, SkPath::kCW_Direction);
+ path.addRect(10, 30, 40, 30, SkPath::kCW_Direction);
+ path.addRect(0, 20, 12, 30, SkPath::kCCW_Direction);
+ path.addRect(0, 32, 9, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine79x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 36, 60, 30, SkPath::kCW_Direction);
+ path.addRect(10, 30, 40, 30, SkPath::kCW_Direction);
+ path.addRect(0, 20, 12, 30, SkPath::kCCW_Direction);
+ path.addRect(0, 32, 9, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine81(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(-1, -1, 3, 3, SkPath::kCW_Direction);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(0, 0, 1, 1, SkPath::kCW_Direction);
+ path.addRect(1, 1, 2, 2, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testDegenerate1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(2, 0);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(2, 0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testDegenerate1x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(2, 0);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(2, 0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testDegenerate2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(0, 0);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testDegenerate2x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(0, 0);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testDegenerate3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(2, 0);
+ path.lineTo(1, 0);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(3, 0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testDegenerate3x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(2, 0);
+ path.lineTo(1, 0);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(3, 0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testDegenerate4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 1);
+ path.lineTo(1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testDegenerate4x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 1);
+ path.lineTo(1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testNondegenerate1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(3, 0);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(1, 1);
+ path.lineTo(2, 1);
+ path.lineTo(1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testNondegenerate1x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(3, 0);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(1, 1);
+ path.lineTo(2, 1);
+ path.lineTo(1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testNondegenerate2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.lineTo(0, 1);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(0, 2);
+ path.lineTo(0, 3);
+ path.lineTo(1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testNondegenerate2x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1, 0);
+ path.lineTo(0, 1);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(0, 2);
+ path.lineTo(0, 3);
+ path.lineTo(1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testNondegenerate3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(0, 1);
+ path.lineTo(1, 1);
+ path.lineTo(0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testNondegenerate3x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(0, 1);
+ path.lineTo(1, 1);
+ path.lineTo(0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testNondegenerate4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.lineTo(0, 1);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(0, 2);
+ path.lineTo(0, 3);
+ path.lineTo(1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testNondegenerate4x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1, 0);
+ path.lineTo(0, 1);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(0, 2);
+ path.lineTo(0, 3);
+ path.lineTo(1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(2, 2);
+ path.lineTo(3, 2);
+ path.lineTo(3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral5x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(2, 2);
+ path.lineTo(3, 2);
+ path.lineTo(3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral6(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(2, 0);
+ path.lineTo(0, 2);
+ path.lineTo(2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral6x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(2, 0);
+ path.lineTo(0, 2);
+ path.lineTo(2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testFauxQuadralateral6(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(2, 0);
+ path.lineTo(1 + 1.0f/3, 2.0f/3);
+ path.close();
+ path.moveTo(1 + 1.0f/3, 2.0f/3);
+ path.lineTo(0, 2);
+ path.lineTo(2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testFauxQuadralateral6x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(2, 0);
+ path.lineTo(1 + 1.0f/3, 2.0f/3);
+ path.close();
+ path.moveTo(1 + 1.0f/3, 2.0f/3);
+ path.lineTo(0, 2);
+ path.lineTo(2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testFauxQuadralateral6a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(3, 0);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(6, 0);
+ path.lineTo(4, 2);
+ path.close();
+ path.moveTo(4, 2);
+ path.lineTo(0, 6);
+ path.lineTo(6, 6);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testFauxQuadralateral6ax(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(3, 0);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(6, 0);
+ path.lineTo(4, 2);
+ path.close();
+ path.moveTo(4, 2);
+ path.lineTo(0, 6);
+ path.lineTo(6, 6);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testFauxQuadralateral6b(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(3, 0);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(6, 0);
+ path.lineTo(4, 2);
+ path.close();
+ path.moveTo(4, 2);
+ path.lineTo(6, 6);
+ path.lineTo(0, 6);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testFauxQuadralateral6bx(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(3, 0);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(6, 0);
+ path.lineTo(4, 2);
+ path.close();
+ path.moveTo(4, 2);
+ path.lineTo(6, 6);
+ path.lineTo(0, 6);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testFauxQuadralateral6c(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(3, 3);
+ path.lineTo(3, 0);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(6, 0);
+ path.lineTo(4, 2);
+ path.close();
+ path.moveTo(4, 2);
+ path.lineTo(0, 6);
+ path.lineTo(6, 6);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testFauxQuadralateral6cx(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(3, 3);
+ path.lineTo(3, 0);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(6, 0);
+ path.lineTo(4, 2);
+ path.close();
+ path.moveTo(4, 2);
+ path.lineTo(0, 6);
+ path.lineTo(6, 6);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testFauxQuadralateral6d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(3, 3);
+ path.lineTo(3, 0);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(6, 0);
+ path.lineTo(4, 2);
+ path.close();
+ path.moveTo(4, 2);
+ path.lineTo(6, 6);
+ path.lineTo(0, 6);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testFauxQuadralateral6dx(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(3, 3);
+ path.lineTo(3, 0);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(6, 0);
+ path.lineTo(4, 2);
+ path.close();
+ path.moveTo(4, 2);
+ path.lineTo(6, 6);
+ path.lineTo(0, 6);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral6a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(3, 0);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(6, 0);
+ path.lineTo(0, 6);
+ path.lineTo(6, 6);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral6ax(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(3, 0);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(6, 0);
+ path.lineTo(0, 6);
+ path.lineTo(6, 6);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral7(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 1);
+ path.lineTo(2, 2);
+ path.lineTo(1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral7x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 1);
+ path.lineTo(2, 2);
+ path.lineTo(1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral8(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(3, 1);
+ path.lineTo(1, 3);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(2, 1);
+ path.lineTo(0, 2);
+ path.lineTo(3, 2);
+ path.lineTo(2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral8x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(3, 1);
+ path.lineTo(1, 3);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(2, 1);
+ path.lineTo(0, 2);
+ path.lineTo(3, 2);
+ path.lineTo(2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral9(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(1, 2);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(1, 1);
+ path.lineTo(2, 1);
+ path.lineTo(1, 3);
+ path.lineTo(2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral9x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(1, 2);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(1, 1);
+ path.lineTo(2, 1);
+ path.lineTo(1, 3);
+ path.lineTo(2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine1a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 0, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine1ax(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 0, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine2ax(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 20, 20, 20, SkPath::kCW_Direction);
+ path.addRect(0, 20, 12, 30, SkPath::kCW_Direction);
+ path.addRect(12, 0, 21, 21, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine3aax(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(10, 30, 30, 30, SkPath::kCW_Direction);
+ path.addRect(18, 20, 30, 30, SkPath::kCCW_Direction);
+ path.addRect(0, 32, 9, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine4ax(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(10, 30, 30, 30, SkPath::kCW_Direction);
+ path.addRect(24, 20, 36, 30, SkPath::kCCW_Direction);
+ path.addRect(0, 32, 9, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(1, 0);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic1x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(1, 0);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(3, 0);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic2x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(3, 0);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(0, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic3x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(0, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(0, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic4x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(0, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic6(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 0, 0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic7(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(3, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(3, 0, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic8(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(0, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic9(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(3, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(1, 2, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic14(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(3, 2, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic15(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(0, 1);
+ path.quadTo(1, 1, 0, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic17x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 3, 1);
+ path.lineTo(0, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(3, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic18(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 1, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic19(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 0, 0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic20(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic21(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic22(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 1, 2, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic23(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 2, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic24(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(2, 0, 0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic25(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 1);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic26(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 1);
+ path.lineTo(0, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic27(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 1);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic28(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 2);
+ path.quadTo(1, 2, 0, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic29(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 2, 1);
+ path.lineTo(0, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic30(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 2);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic31(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 2);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic32(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 2, 3);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(3, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic33(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(2, 0, 0, 1);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 1);
+ path.quadTo(2, 1, 2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic34(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(2, 0, 0, 1);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 1);
+ path.quadTo(2, 1, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic35(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(3, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic36(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(2, 1, 2, 3);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(3, 1);
+ path.lineTo(1, 2);
+ path.quadTo(3, 2, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic37(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 2, 1, 2);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(3, 1);
+ path.quadTo(0, 2, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic38(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 2);
+ path.quadTo(2, 2, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic51(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(369.863983f, 145.645813f);
+ path.quadTo(382.380371f, 121.254936f, 406.236359f, 121.254936f);
+ path.lineTo(369.863983f, 145.645813f);
+ path.close();
+ path.moveTo(369.970581f, 137.94342f);
+ path.quadTo(383.98465f, 121.254936f, 406.235992f, 121.254936f);
+ path.lineTo(369.970581f, 137.94342f);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic53(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(303.12088f, 141.299606f);
+ path.lineTo(330.463562f, 217.659027f);
+ path.lineTo(303.12088f, 141.299606f);
+ path.close();
+ path.moveTo(371.919067f, 205.854996f);
+ path.lineTo(326.236786f, 205.854996f);
+ path.quadTo(329.104431f, 231.663818f, 351.512085f, 231.663818f);
+ path.lineTo(371.919067f, 205.854996f);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic55(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+path.moveTo(303.12088f, 141.299606f);
+path.lineTo(330.463562f, 217.659027f);
+path.lineTo(358.606506f, 141.299606f);
+path.lineTo(303.12088f, 141.299606f);
+path.close();
+path.moveTo(326.236786f, 205.854996f);
+path.quadTo(329.104431f, 231.663818f, 351.512085f, 231.663818f);
+path.lineTo(326.236786f, 205.854996f);
+path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic56(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+path.moveTo(366.608826f, 151.196014f);
+path.quadTo(378.803101f, 136.674606f, 398.164948f, 136.674606f);
+path.lineTo(354.009216f, 208.816208f);
+path.lineTo(393.291473f, 102.232819f);
+path.lineTo(359.978058f, 136.581512f);
+path.quadTo(378.315979f, 136.581512f, 388.322723f, 149.613556f);
+path.lineTo(364.390686f, 157.898193f);
+path.quadTo(375.281769f, 136.674606f, 396.039917f, 136.674606f);
+path.lineTo(350, 120);
+path.lineTo(366.608826f, 151.196014f);
+path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine80(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+path.moveTo(4, 0);
+path.lineTo(3, 7);
+path.lineTo(7, 5);
+path.lineTo(2, 2);
+path.close();
+path.moveTo(0, 6);
+path.lineTo(6, 12);
+path.lineTo(8, 3);
+path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic58(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(283.714233f, 240);
+ path.lineTo(283.714233f, 141.299606f);
+ path.lineTo(303.12088f, 141.299606f);
+ path.lineTo(330.463562f, 217.659027f);
+ path.lineTo(358.606506f, 141.299606f);
+ path.lineTo(362.874634f, 159.705902f);
+ path.lineTo(335.665344f, 233.397751f);
+ path.lineTo(322.12738f, 233.397751f);
+ path.lineTo(295.718353f, 159.505829f);
+ path.lineTo(295.718353f, 240);
+ path.lineTo(283.714233f, 240);
+ path.close();
+ path.moveTo(322.935669f, 231.030273f);
+ path.quadTo(312.832214f, 220.393295f, 312.832214f, 203.454178f);
+ path.quadTo(312.832214f, 186.981888f, 321.73526f, 176.444946f);
+ path.quadTo(330.638306f, 165.90802f, 344.509705f, 165.90802f);
+ path.quadTo(357.647522f, 165.90802f, 364.81665f, 175.244537f);
+ path.lineTo(371.919067f, 205.854996f);
+ path.lineTo(326.236786f, 205.854996f);
+ path.quadTo(329.104431f, 231.663818f, 351.512085f, 231.663818f);
+ path.lineTo(322.935669f, 231.030273f);
+ path.close();
+ path.moveTo(326.837006f, 195.984955f);
+ path.lineTo(358.78125f, 195.984955f);
+ path.quadTo(358.78125f, 175.778046f, 343.709442f, 175.778046f);
+ path.quadTo(328.570923f, 175.778046f, 326.837006f, 195.984955f);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic59x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(2, 0);
+ path.quadTo(3, 1, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic59(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(2, 0);
+ path.quadTo(3, 1, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic63(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(2, 1);
+ path.quadTo(2, 1, 2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic64(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(1, 2);
+ path.lineTo(2, 2);
+ path.quadTo(0, 3, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic65(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(2, 1);
+ path.lineTo(2, 2);
+ path.quadTo(0, 3, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic67x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 2, 1);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(2, 0);
+ path.quadTo(1, 1, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic68(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 1, 2, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic69(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 1);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(1, 1);
+ path.quadTo(3, 2, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic70x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 1, 2, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic71(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 1);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 1, 3, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic72(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 2);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic73(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 0, 3);
+ path.lineTo(0, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic74(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 3);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 1);
+ path.quadTo(3, 2, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic75(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 3);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 1);
+ path.quadTo(3, 2, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic76(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 2);
+ path.quadTo(1, 2, 2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic77(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 1);
+ path.lineTo(3, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic78(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 2);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic79(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 2);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testEight1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(2, 2);
+ path.lineTo(0, 2);
+ path.lineTo(2, 0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testEight2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(2, 0);
+ path.lineTo(0, 2);
+ path.lineTo(2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testEight3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(0, 2);
+ path.lineTo(2, 0);
+ path.lineTo(2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testEight4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(2, 2);
+ path.lineTo(2, 0);
+ path.lineTo(0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testEight5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.lineTo(1, 2);
+ path.lineTo(0, 2);
+ path.lineTo(2, 0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testEight6(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.lineTo(2, 0);
+ path.lineTo(0, 2);
+ path.lineTo(1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testEight7(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(0, 1);
+ path.lineTo(2, 1);
+ path.lineTo(2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testEight8(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(2, 2);
+ path.lineTo(2, 1);
+ path.lineTo(0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testEight9(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.lineTo(1, 2);
+ path.lineTo(2, 1);
+ path.lineTo(0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testEight10(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.lineTo(0, 1);
+ path.lineTo(2, 1);
+ path.lineTo(1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic80(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 2, 3);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(3, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic81(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(2, 0, 1, 1);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic82(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(2, 0, 1, 1);
+ path.lineTo(0, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic83(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 2, 0);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(0, 1);
+ path.lineTo(0, 2);
+ path.quadTo(2, 2, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic84(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(2, 0, 1, 1);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(2, 0);
+ path.quadTo(0, 1, 2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic85(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(3, 0, 1, 1);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(3, 0);
+ path.quadTo(0, 1, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic86(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 1, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic87(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 1);
+ path.quadTo(0, 2, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic88(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 1);
+ path.quadTo(0, 2, 2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic89x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(3, 1, 2, 2);
+ path.lineTo(0, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(2, 1);
+ path.quadTo(3, 1, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic90x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(3, 0, 2, 2);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 1);
+ path.quadTo(3, 2, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic91(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(3, 2, 2, 3);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 1);
+ path.quadTo(2, 1, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic92x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1, 0);
+ path.quadTo(3, 0, 2, 2);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(0, 1);
+ path.quadTo(3, 2, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine82(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(20, 0, 40, 40, SkPath::kCCW_Direction);
+ path.addRect(24, 20, 36, 30, SkPath::kCCW_Direction);
+ path.addRect(24, 32, 33, 36, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine82a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 6, 10, SkPath::kCW_Direction);
+ path.addRect(2, 2, 4, 4, SkPath::kCW_Direction);
+ path.addRect(2, 6, 4, 8, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine82b(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 6, 10, SkPath::kCW_Direction);
+ path.addRect(2, 2, 4, 4, SkPath::kCW_Direction);
+ path.addRect(2, 6, 4, 8, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine82c(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 6, 10, SkPath::kCW_Direction);
+ path.addRect(2, 2, 4, 4, SkPath::kCCW_Direction);
+ path.addRect(2, 6, 4, 8, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine82d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 6, 10, SkPath::kCW_Direction);
+ path.addRect(2, 2, 4, 4, SkPath::kCCW_Direction);
+ path.addRect(2, 6, 4, 8, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine82e(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 6, 10, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 4, 4, SkPath::kCW_Direction);
+ path.addRect(2, 6, 4, 8, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine82f(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 6, 10, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 4, 4, SkPath::kCW_Direction);
+ path.addRect(2, 6, 4, 8, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine82g(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 6, 10, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 4, 4, SkPath::kCCW_Direction);
+ path.addRect(2, 6, 4, 8, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine82h(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 6, 10, SkPath::kCCW_Direction);
+ path.addRect(2, 2, 4, 4, SkPath::kCCW_Direction);
+ path.addRect(2, 6, 4, 8, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine83(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+path.addRect(10, 30, 30, 40, SkPath::kCCW_Direction);
+path.addRect(0, 12, 12, 18, SkPath::kCCW_Direction);
+path.addRect(4, 13, 13, 16, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine84(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 12, 60, 30, SkPath::kCCW_Direction);
+ path.addRect(10, 20, 40, 30, SkPath::kCW_Direction);
+ path.addRect(0, 12, 12, 12, SkPath::kCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine84x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 12, 60, 30, SkPath::kCCW_Direction);
+ path.addRect(10, 20, 40, 30, SkPath::kCCW_Direction);
+ path.addRect(0, 12, 12, 12, SkPath::kCCW_Direction);
+ path.addRect(4, 12, 13, 13, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testLine85(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(36, 0, 66, 60, SkPath::kCCW_Direction);
+ path.addRect(20, 0, 40, 40, SkPath::kCCW_Direction);
+ path.addRect(12, 0, 24, 24, SkPath::kCCW_Direction);
+ path.addRect(32, 0, 36, 41, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(2, 1);
+ path.lineTo(2, 2);
+ path.lineTo(2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testCubic1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.cubicTo(0, 1, 1, 1, 1, 0);
+ path.close();
+ path.moveTo(1, 0);
+ path.cubicTo(0, 0, 0, 1, 1, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic93(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(3, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.lineTo(0, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(2, 0);
+ path.quadTo(1, 1, 2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testCubic2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0,2);
+ path.cubicTo(0,3, 2,1, 4,0);
+ path.close();
+ path.moveTo(1,2);
+ path.cubicTo(0,4, 2,0, 3,0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0,0);
+ path.quadTo(0,0, 0,1);
+ path.lineTo(1,1);
+ path.close();
+ path.moveTo(0,0);
+ path.quadTo(1,1, 0,2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(2, 2);
+ path.lineTo(0, 3);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(3, 0);
+ path.lineTo(0, 1);
+ path.lineTo(1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic94(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(8, 8);
+ path.quadTo(8, 4, 4, 4);
+ path.quadTo(4, 0, 0, 0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic95(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(8, 8);
+ path.lineTo(0, 0);
+ path.quadTo(4, 0, 4, 4);
+ path.quadTo(8, 4, 8, 8);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic96(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(8, 0);
+ path.lineTo(0, 8);
+ path.quadTo(0, 4, 4, 4);
+ path.quadTo(4, 0, 8, 0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadratic97(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 8);
+ path.lineTo(8, 0);
+ path.quadTo(4, 0, 4, 4);
+ path.quadTo(0, 4, 0, 8);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testTriangles1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 2);
+ path.lineTo(1, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testTriangles2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(1, 1);
+ path.lineTo(2, 3);
+ path.lineTo(1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+// A test this for this case:
+// contourA has two segments that are coincident
+// contourB has two segments that are coincident in the same place
+// each ends up with +2/0 pairs for winding count
+// since logic in OpSegment::addTCoincident doesn't transfer count (only increments/decrements)
+// can this be resolved to +4/0 ?
+static void testAddTCoincident1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.lineTo(2, 2);
+ path.lineTo(1, 1);
+ path.lineTo(2, 0);
+ path.lineTo(2, 2);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(2, 2);
+ path.lineTo(3, 1);
+ path.lineTo(2, 0);
+ path.lineTo(2, 2);
+ path.lineTo(3, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+// test with implicit close
+static void testAddTCoincident2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.lineTo(2, 2);
+ path.lineTo(1, 1);
+ path.lineTo(2, 0);
+ path.lineTo(2, 2);
+ path.lineTo(1, 1);
+ path.moveTo(2, 0);
+ path.lineTo(2, 2);
+ path.lineTo(3, 1);
+ path.lineTo(2, 0);
+ path.lineTo(2, 2);
+ path.lineTo(3, 1);
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.close();
+}
+
+static void testQuad3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(2, 0);
+ path.quadTo(0, 1, 2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(0, 1, 2, 2);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(2, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad6(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(0, 1, 2, 2);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(2, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad7(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(3, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(3, 0);
+ path.quadTo(0, 1, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadLineIntersect1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(3, 1, 0, 3);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(0, 1);
+ path.quadTo(3, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadLineIntersect2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(3, 1, 0, 3);
+ path.lineTo(0, 3);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(0, 1);
+ path.quadTo(3, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadLineIntersect3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(3, 1, 0, 3);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(0, 1);
+ path.quadTo(3, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void skphealth_com76(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(708.099182f, 7.09919119f);
+ path.lineTo(708.099182f, 7.09920025f);
+ path.quadTo(704.000000f, 11.2010098f, 704.000000f, 17.0000000f);
+ path.lineTo(704.000000f, 33.0000000f);
+ path.lineTo(705.000000f, 33.0000000f);
+ path.lineTo(705.000000f, 17.0000000f);
+ path.cubicTo(705.000000f, 13.4101496f, 706.455078f, 10.1601505f, 708.807617f, 7.80761385f);
+ path.lineTo(708.099182f, 7.09919119f);
+ path.close();
+ path.moveTo(704.000000f, 3.00000000f);
+ path.lineTo(704.000000f, 33.0000000f);
+ path.lineTo(705.000000f, 33.0000000f);
+ path.lineTo(719.500000f, 3.00000000f);
+ testSimplify(reporter, path, filename);
+}
+
+static void tooCloseTest(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(1, 1);
+ path.lineTo(1,-1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1,-2);
+ path.lineTo(1, 2);
+ path.lineTo(2, 0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testRect1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.addRect(0, 0, 60, 60, SkPath::kCCW_Direction);
+ path.addRect(30, 20, 50, 50, SkPath::kCCW_Direction);
+ path.addRect(24, 20, 36, 30, SkPath::kCCW_Direction);
+ path.addRect(32, 24, 36, 41, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void testRect2(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(60, 0);
+ path.lineTo(60, 60);
+ path.lineTo(0, 60);
+ path.close();
+ path.moveTo(30, 20);
+ path.lineTo(30, 50);
+ path.lineTo(50, 50);
+ path.lineTo(50, 20);
+ path.close();
+ path.moveTo(24, 20);
+ path.lineTo(24, 30);
+ path.lineTo(36, 30);
+ path.lineTo(36, 20);
+ path.close();
+ path.moveTo(32, 24);
+ path.lineTo(32, 41);
+ path.lineTo(36, 41);
+ path.lineTo(36, 24);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testTriangles3x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 1);
+ path.quadTo(2, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad8(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(3, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.lineTo(0, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(3, 0);
+ path.quadTo(1, 1, 2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testTriangles4x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(2, 0, 0, 3);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 1);
+ path.quadTo(3, 2, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad9(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 1);
+ path.quadTo(2, 1, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad10(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(2, 0);
+ path.quadTo(2, 3, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad11(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(0, 1, 1, 2);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 1);
+ path.quadTo(1, 3, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad12(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(1, 0);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+
+static void testDegenerate5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(1, 0);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(0, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(3, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(0, 1);
+ path.lineTo(3, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testDegenerates1(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 1);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(3, 2, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad13(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 1);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(3, 2, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad14(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 1);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(3, 1, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuad15(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 1);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 0, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads16(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 1);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads17(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 1);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 2, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads18(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 1);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 2, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads19(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 2, 1);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads20(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 2, 1);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads21(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 1);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(3, 0, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads22(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 2, 0);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads23(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads24(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 1);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(0, 1);
+ path.lineTo(0, 1);
+ path.quadTo(0, 2, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads25(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 1);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(3, 0, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads26(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 3, 0);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads27(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 2, 0);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(2, 0);
+ path.quadTo(3, 0, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads28(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 1);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(3, 0, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads29(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 3, 0);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(3, 0);
+ path.quadTo(3, 1, 0, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads30(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+
+ path.quadTo(0, 0, 2, 0);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(2, 0);
+ path.quadTo(3, 2, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads31(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 2, 1);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(0, 1);
+
+ path.quadTo(2, 1, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads32(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 1);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(1, 1);
+ path.lineTo(1, 1);
+ path.quadTo(3, 1, 0, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads33(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 1);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(3, 0, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads34(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 0);
+ path.quadTo(2, 0, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads35(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(1, 2);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 0);
+ path.quadTo(3, 1, 0, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads36(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(2, 0, 1, 2);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 0);
+ path.quadTo(3, 0, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads37(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1, 0);
+ path.quadTo(2, 0, 1, 2);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 0);
+ path.quadTo(3, 0, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads38(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(3, 0, 0, 2);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 0);
+ path.quadTo(2, 1, 3, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads39(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(3, 0, 0, 3);
+ path.lineTo(0, 3);
+ path.close();
+ path.moveTo(1, 1);
+ path.lineTo(0, 2);
+ path.quadTo(1, 2, 0, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+static void testQuads40(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(3, 0, 3, 3);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(2, 1);
+ path.lineTo(2, 2);
+ path.quadTo(3, 2, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads41(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 1, 0);
+ path.lineTo(2, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 1, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+
+static void testQuads54(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(2, 0, 1, 1);
+ path.lineTo(3, 1);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(1, 1);
+ path.quadTo(1, 1, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+static void testQuads53(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(2, 0, 1, 1);
+ path.lineTo(3, 1);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(1, 1);
+ path.quadTo(2, 3, 2, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+static void testQuads52(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(2, 0, 1, 1);
+ path.lineTo(3, 1);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(1, 1);
+ path.quadTo(2, 3, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+static void testQuads51(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(3, 0, 2, 1);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(3, 1);
+ path.quadTo(3, 1, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+static void testQuads50(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(3, 0, 2, 1);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(3, 1);
+ path.quadTo(1, 2, 1, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+static void testQuads49(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(3, 0, 2, 1);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(2, 2);
+ path.quadTo(2, 2, 0, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+static void testQuads48(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(3, 0, 2, 1);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(2, 2);
+ path.quadTo(3, 2, 0, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+static void testQuads47(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(3, 0, 2, 1);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(2, 2);
+ path.quadTo(0, 3, 0, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+// this fails because there is a short unorderable segment and the unordered state isn't handled
+// correctly later on.
+static void testQuads46x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(2, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 1);
+ path.quadTo(3, 2, 1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads45(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(3, 2, 3, 3);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 2);
+ path.quadTo(3, 2, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads44(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(3, 2, 3, 3);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(0, 2);
+ path.quadTo(3, 2, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads43(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(2, 3, 3, 3);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(0, 2);
+ path.lineTo(0, 2);
+ path.quadTo(2, 3, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads42(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(3, 2, 3, 3);
+ path.lineTo(3, 3);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(0, 2);
+ path.quadTo(3, 2, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads56(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 0);
+ path.quadTo(3, 1, 0, 2);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(3, 0);
+ path.lineTo(2, 1);
+ path.quadTo(2, 1, 3, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads57(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(3, 0, 3, 1);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(3, 1);
+ path.quadTo(2, 2, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads58(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(1, 0);
+ path.quadTo(3, 0, 3, 1);
+ path.lineTo(1, 3);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(3, 1);
+ path.quadTo(2, 2, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads59(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(3, 0);
+ path.quadTo(3, 1, 3, 1);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(3, 1);
+ path.quadTo(2, 2, 3, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads60(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(2, 1);
+ path.quadTo(0, 2, 3, 2);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(2, 0);
+ path.quadTo(1, 1, 2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuads61(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 2, 0);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(1, 0, 2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testQuadralateral10(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(0, 0);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 1);
+ path.lineTo(2, 2);
+ path.lineTo(1, 3);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testRect3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.addRect(0, 0, 60, 60, SkPath::kCCW_Direction);
+ path.addRect(10, 30, 40, 30, SkPath::kCCW_Direction);
+ path.addRect(24, 6, 36, 36, SkPath::kCCW_Direction);
+ path.addRect(32, 6, 36, 41, SkPath::kCCW_Direction);
+ testSimplify(reporter, path, filename);
+}
+
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
+
+static TestDesc tests[] = {
+ TEST(testRect3),
+ TEST(testQuadralateral10),
+ TEST(testQuads61),
+ TEST(testQuads60),
+ TEST(testQuads59),
+ TEST(testQuads58),
+ TEST(testQuads57),
+ TEST(testQuads56),
+ TEST(testQuads54),
+ TEST(testQuads53),
+ TEST(testQuads52),
+ TEST(testQuads51),
+ TEST(testQuads50),
+ TEST(testQuads49),
+ TEST(testQuads48),
+ TEST(testQuads47),
+ TEST(testQuads46x),
+ TEST(testQuads45),
+ TEST(testQuads44),
+ TEST(testQuads43),
+ TEST(testQuads42),
+ TEST(testQuads41),
+ TEST(testQuads36),
+ TEST(testQuads37),
+ TEST(testQuads38),
+ TEST(testQuads39),
+ TEST(testQuads40),
+ TEST(testQuads16),
+ TEST(testQuads17),
+ TEST(testQuads18),
+ TEST(testQuads19),
+ TEST(testQuads20),
+ TEST(testQuads21),
+ TEST(testQuads22),
+ TEST(testQuads23),
+ TEST(testQuads24),
+ TEST(testQuads25),
+ TEST(testQuads26),
+ TEST(testQuads27),
+ TEST(testQuads28),
+ TEST(testQuads29),
+ TEST(testQuads30),
+ TEST(testQuads31),
+ TEST(testQuads32),
+ TEST(testQuads33),
+ TEST(testQuads34),
+ TEST(testQuads35),
+ TEST(testDegenerates1),
+ TEST(testQuad13),
+ TEST(testQuad14),
+ TEST(testQuad15),
+ TEST(testQuadratic56),
+ TEST(testQuadralateral4),
+ TEST(testQuadralateral3),
+ TEST(testDegenerate5),
+ TEST(testQuad12),
+ TEST(testQuadratic51), // has unorderable angles
+ TEST(testQuad8),
+ TEST(testQuad11),
+ TEST(testQuad10),
+ TEST(testQuad9),
+ TEST(testTriangles4x),
+ TEST(testTriangles3x),
+ TEST(testRect2),
+ TEST(testRect1),
+ TEST(tooCloseTest),
+ TEST(skphealth_com76),
+ TEST(testQuadLineIntersect1),
+ TEST(testQuadLineIntersect2),
+ TEST(testQuadLineIntersect3),
+ TEST(testQuad7),
+ TEST(testQuad6),
+ TEST(testQuad5),
+ TEST(testQuad4),
+ TEST(testQuad3),
+ TEST(testQuad2),
+ TEST(testAddTCoincident2),
+ TEST(testAddTCoincident1),
+ TEST(testTriangles2),
+ TEST(testTriangles1),
+ TEST(testQuadratic97),
+ TEST(testQuadratic96),
+ TEST(testQuadratic95),
+ TEST(testQuadratic94),
+ TEST(testQuadralateral2),
+ TEST(testQuad1),
+ TEST(testCubic2),
+ TEST(testCubic1),
+ TEST(testQuadralateral1),
+ TEST(testLine85),
+ TEST(testLine84),
+ TEST(testLine84x),
+ TEST(testLine83),
+ TEST(testLine82h),
+ TEST(testLine82g),
+ TEST(testLine82f),
+ TEST(testLine82e),
+ TEST(testLine82d),
+ TEST(testLine82c),
+ TEST(testLine82b),
+ TEST(testLine82a),
+ TEST(testLine82),
+ TEST(testQuadratic93),
+ TEST(testQuadratic92x),
+ TEST(testQuadratic91),
+ TEST(testQuadratic90x),
+ TEST(testQuadratic89x),
+ TEST(testQuadratic88),
+ TEST(testQuadratic87),
+ TEST(testQuadratic86),
+ TEST(testQuadratic85),
+ TEST(testQuadratic84),
+ TEST(testQuadratic83),
+ TEST(testQuadratic82),
+ TEST(testQuadratic81),
+ TEST(testQuadratic80),
+ TEST(testEight1),
+ TEST(testEight2),
+ TEST(testEight3),
+ TEST(testEight4),
+ TEST(testEight5),
+ TEST(testEight6),
+ TEST(testEight7),
+ TEST(testEight8),
+ TEST(testEight9),
+ TEST(testEight10),
+ TEST(testQuadratic79),
+ TEST(testQuadratic78),
+ TEST(testQuadratic77),
+ TEST(testQuadratic76),
+ TEST(testQuadratic75),
+ TEST(testQuadratic74),
+ TEST(testQuadratic73),
+ TEST(testQuadratic72),
+ TEST(testQuadratic71),
+ TEST(testQuadratic70x),
+ TEST(testQuadratic69),
+ TEST(testQuadratic68),
+ TEST(testQuadratic67x),
+ TEST(testQuadratic65),
+ TEST(testQuadratic64),
+ TEST(testQuadratic63),
+ TEST(testLine1a),
+ TEST(testLine1ax),
+ TEST(testQuadratic59),
+ TEST(testQuadratic59x),
+ TEST(testQuadratic58),
+ TEST(testQuadratic55),
+ TEST(testQuadratic53),
+ TEST(testQuadratic38),
+ TEST(testQuadratic37),
+ TEST(testQuadratic36),
+ TEST(testQuadratic35),
+ TEST(testQuadratic34),
+ TEST(testQuadratic33),
+ TEST(testQuadratic32),
+ TEST(testQuadratic31),
+ TEST(testQuadratic30),
+ TEST(testQuadratic29),
+ TEST(testQuadratic28),
+ TEST(testQuadratic27),
+ TEST(testQuadratic26),
+ TEST(testQuadratic25),
+ TEST(testQuadratic24),
+ TEST(testQuadratic23),
+ TEST(testQuadratic22),
+ TEST(testQuadratic21),
+ TEST(testQuadratic20),
+ TEST(testQuadratic19),
+ TEST(testQuadratic18),
+ TEST(testQuadratic17x),
+ TEST(testQuadratic15),
+ TEST(testQuadratic14),
+ TEST(testQuadratic9),
+ TEST(testQuadratic8),
+ TEST(testQuadratic7),
+ TEST(testQuadratic6),
+ TEST(testQuadratic5),
+ TEST(testQuadratic4x),
+ TEST(testQuadratic3x),
+ TEST(testQuadratic2x),
+ TEST(testQuadratic1x),
+ TEST(testQuadratic4),
+ TEST(testQuadratic3),
+ TEST(testQuadratic2),
+ TEST(testQuadratic1),
+ TEST(testLine4ax),
+ TEST(testLine3aax),
+ TEST(testLine2ax),
+ TEST(testLine1ax),
+ TEST(testQuadralateral9x),
+ TEST(testQuadralateral8x),
+ TEST(testQuadralateral7x),
+ TEST(testQuadralateral6x),
+ TEST(testQuadralateral6ax),
+ TEST(testQuadralateral9),
+ TEST(testQuadralateral8),
+ TEST(testQuadralateral7),
+ TEST(testQuadralateral6),
+ TEST(testQuadralateral6a),
+ TEST(testFauxQuadralateral6dx),
+ TEST(testFauxQuadralateral6cx),
+ TEST(testFauxQuadralateral6bx),
+ TEST(testFauxQuadralateral6ax),
+ TEST(testFauxQuadralateral6x),
+ TEST(testFauxQuadralateral6d),
+ TEST(testFauxQuadralateral6c),
+ TEST(testFauxQuadralateral6b),
+ TEST(testFauxQuadralateral6a),
+ TEST(testFauxQuadralateral6),
+ TEST(testQuadralateral5x),
+ TEST(testQuadralateral5),
+ TEST(testNondegenerate4x),
+ TEST(testNondegenerate3x),
+ TEST(testNondegenerate2x),
+ TEST(testNondegenerate1x),
+ TEST(testNondegenerate4),
+ TEST(testNondegenerate3),
+ TEST(testNondegenerate2),
+ TEST(testNondegenerate1),
+ TEST(testDegenerate4x),
+ TEST(testDegenerate3x),
+ TEST(testDegenerate2x),
+ TEST(testDegenerate1x),
+ TEST(testDegenerate4),
+ TEST(testDegenerate3),
+ TEST(testDegenerate2),
+ TEST(testDegenerate1),
+ TEST(testLine79x),
+ TEST(testLine78x),
+ TEST(testLine77x),
+ TEST(testLine76x),
+ TEST(testLine75x),
+ TEST(testLine74x),
+ TEST(testLine73x),
+ TEST(testLine72x),
+ TEST(testLine71x),
+ TEST(testLine70x),
+ TEST(testLine69x),
+ TEST(testLine68hx),
+ TEST(testLine68gx),
+ TEST(testLine68fx),
+ TEST(testLine68ex),
+ TEST(testLine68dx),
+ TEST(testLine68cx),
+ TEST(testLine68bx),
+ TEST(testLine68ax),
+ TEST(testLine67x),
+ TEST(testLine66x),
+ TEST(testLine65x),
+ TEST(testLine64x),
+ TEST(testLine63x),
+ TEST(testLine62x),
+ TEST(testLine61x),
+ TEST(testLine60x),
+ TEST(testLine59x),
+ TEST(testLine58x),
+ TEST(testLine57x),
+ TEST(testLine56x),
+ TEST(testLine55x),
+ TEST(testLine54x),
+ TEST(testLine53x),
+ TEST(testLine52x),
+ TEST(testLine51x),
+ TEST(testLine50x),
+ TEST(testLine49x),
+ TEST(testLine48x),
+ TEST(testLine47x),
+ TEST(testLine46x),
+ TEST(testLine45x),
+ TEST(testLine44x),
+ TEST(testLine43x),
+ TEST(testLine42x),
+ TEST(testLine41x),
+ TEST(testLine40x),
+ TEST(testLine38x),
+ TEST(testLine37x),
+ TEST(testLine36x),
+ TEST(testLine35x),
+ TEST(testLine34x),
+ TEST(testLine33x),
+ TEST(testLine32x),
+ TEST(testLine31x),
+ TEST(testLine30x),
+ TEST(testLine29x),
+ TEST(testLine28x),
+ TEST(testLine27x),
+ TEST(testLine26x),
+ TEST(testLine25x),
+ TEST(testLine24ax),
+ TEST(testLine24x),
+ TEST(testLine23x),
+ TEST(testLine22x),
+ TEST(testLine21x),
+ TEST(testLine20x),
+ TEST(testLine19x),
+ TEST(testLine18x),
+ TEST(testLine17x),
+ TEST(testLine16x),
+ TEST(testLine15x),
+ TEST(testLine14x),
+ TEST(testLine13x),
+ TEST(testLine12x),
+ TEST(testLine11x),
+ TEST(testLine10ax),
+ TEST(testLine10x),
+ TEST(testLine9x),
+ TEST(testLine8x),
+ TEST(testLine7bx),
+ TEST(testLine7ax),
+ TEST(testLine7x),
+ TEST(testLine6x),
+ TEST(testLine5x),
+ TEST(testLine4x),
+ TEST(testLine3bx),
+ TEST(testLine3ax),
+ TEST(testLine3x),
+ TEST(testLine2x),
+ TEST(testLine1x),
+ TEST(testLine81),
+ TEST(testLine80),
+ TEST(testLine79),
+ TEST(testLine78),
+ TEST(testLine77),
+ TEST(testLine76),
+ TEST(testLine75),
+ TEST(testLine74),
+ TEST(testLine73),
+ TEST(testLine72),
+ TEST(testLine71),
+ TEST(testLine70),
+ TEST(testLine69),
+ TEST(testLine68h),
+ TEST(testLine68g),
+ TEST(testLine68f),
+ TEST(testLine68e),
+ TEST(testLine68d),
+ TEST(testLine68c),
+ TEST(testLine68b),
+ TEST(testLine68a),
+ TEST(testLine67),
+ TEST(testLine66),
+ TEST(testLine65),
+ TEST(testLine64),
+ TEST(testLine63),
+ TEST(testLine62),
+ TEST(testLine61),
+ TEST(testLine60),
+ TEST(testLine59),
+ TEST(testLine58),
+ TEST(testLine57),
+ TEST(testLine56),
+ TEST(testLine55),
+ TEST(testLine54),
+ TEST(testLine53),
+ TEST(testLine52),
+ TEST(testLine51),
+ TEST(testLine50),
+ TEST(testLine49),
+ TEST(testLine48),
+ TEST(testLine47),
+ TEST(testLine46),
+ TEST(testLine45),
+ TEST(testLine44),
+ TEST(testLine43),
+ TEST(testLine42),
+ TEST(testLine41),
+ TEST(testLine40),
+ TEST(testLine38),
+ TEST(testLine37),
+ TEST(testLine36),
+ TEST(testLine35),
+ TEST(testLine34),
+ TEST(testLine33),
+ TEST(testLine32),
+ TEST(testLine31),
+ TEST(testLine30),
+ TEST(testLine29),
+ TEST(testLine28),
+ TEST(testLine27),
+ TEST(testLine26),
+ TEST(testLine25),
+ TEST(testLine24a),
+ TEST(testLine24),
+ TEST(testLine23),
+ TEST(testLine22),
+ TEST(testLine21),
+ TEST(testLine20),
+ TEST(testLine19),
+ TEST(testLine18),
+ TEST(testLine17),
+ TEST(testLine16),
+ TEST(testLine15),
+ TEST(testLine14),
+ TEST(testLine13),
+ TEST(testLine12),
+ TEST(testLine11),
+ TEST(testLine10a),
+ TEST(testLine10),
+ TEST(testLine9),
+ TEST(testLine8),
+ TEST(testLine7b),
+ TEST(testLine7a),
+ TEST(testLine7),
+ TEST(testLine6),
+ TEST(testLine5),
+ TEST(testLine4),
+ TEST(testLine3b),
+ TEST(testLine3a),
+ TEST(testLine3),
+ TEST(testLine2),
+ TEST(testLine1),
+};
+
+static const size_t testCount = SK_ARRAY_COUNT(tests);
+
+static TestDesc subTests[] = {
+ TEST(testLine3),
+ TEST(testLine2),
+ TEST(testLine1),
+};
+
+static const size_t subTestCount = SK_ARRAY_COUNT(subTests);
+
+static void (*firstSubTest)(skiatest::Reporter* , const char* filename) = 0;
+
+static bool runSubTests = false;
+static bool runSubTestsFirst = false;
+static bool runReverse = false;
+static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
+
+DEF_TEST(PathOpsSimplify, reporter) {
+ if (runSubTests && runSubTestsFirst) {
+ RunTestSet(reporter, subTests, subTestCount, firstSubTest, stopTest, runReverse);
+ }
+ RunTestSet(reporter, tests, testCount, firstTest, stopTest, runReverse);
+ if (runSubTests && !runSubTestsFirst) {
+ RunTestSet(reporter, subTests, subTestCount, firstSubTest, stopTest, runReverse);
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsSimplifyTrianglesThreadedTest.cpp b/src/third_party/skia/tests/PathOpsSimplifyTrianglesThreadedTest.cpp
new file mode 100755
index 0000000..ee0ca2b
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsSimplifyTrianglesThreadedTest.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsThreadedCommon.h"
+
+static void testSimplifyTrianglesMain(PathOpsThreadState* data) {
+ SkASSERT(data);
+ PathOpsThreadState& state = *data;
+ char pathStr[1024];
+ bool progress = state.fReporter->verbose(); // FIXME: break out into its own parameter?
+ if (progress) {
+ sk_bzero(pathStr, sizeof(pathStr));
+ }
+ state.fKey = "?";
+ int ax = state.fA & 0x03;
+ int ay = state.fA >> 2;
+ int bx = state.fB & 0x03;
+ int by = state.fB >> 2;
+ int cx = state.fC & 0x03;
+ int cy = state.fC >> 2;
+ for (int d = 0; d < 15; ++d) {
+ int dx = d & 0x03;
+ int dy = d >> 2;
+ for (int e = d + 1; e < 16; ++e) {
+ int ex = e & 0x03;
+ int ey = e >> 2;
+ for (int f = d + 1; f < 16; ++f) {
+ if (e == f) {
+ continue;
+ }
+ int fx = f & 0x03;
+ int fy = f >> 2;
+ if ((ex - dx) * (fy - dy) == (ey - dy) * (fx - dx)) {
+ continue;
+ }
+ SkPath path, out;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(SkIntToScalar(ax), SkIntToScalar(ay));
+ path.lineTo(SkIntToScalar(bx), SkIntToScalar(by));
+ path.lineTo(SkIntToScalar(cx), SkIntToScalar(cy));
+ path.close();
+ path.moveTo(SkIntToScalar(dx), SkIntToScalar(dy));
+ path.lineTo(SkIntToScalar(ex), SkIntToScalar(ey));
+ path.lineTo(SkIntToScalar(fx), SkIntToScalar(fy));
+ path.close();
+ if (progress) {
+ char* str = pathStr;
+ str += sprintf(str, " path.moveTo(%d, %d);\n", ax, ay);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", bx, by);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", cx, cy);
+ str += sprintf(str, " path.close();\n");
+ str += sprintf(str, " path.moveTo(%d, %d);\n", dx, dy);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", ex, ey);
+ str += sprintf(str, " path.lineTo(%d, %d);\n", fx, fy);
+ str += sprintf(str, " path.close();\n");
+ outputProgress(state.fPathStr, pathStr, SkPath::kWinding_FillType);
+ }
+ ShowTestName(&state, d, e, f, 0);
+ testSimplify(path, false, out, state, pathStr);
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ if (progress) {
+ outputProgress(state.fPathStr, pathStr, SkPath::kEvenOdd_FillType);
+ }
+ ShowTestName(&state, d, e, f, 1);
+ testSimplify(path, true, out, state, pathStr);
+ }
+ }
+ }
+}
+
+DEF_TEST(PathOpsSimplifyTrianglesThreaded, reporter) {
+ initializeTests(reporter, "testTriangles");
+ PathOpsThreadedTestRunner testRunner(reporter);
+ for (int a = 0; a < 15; ++a) {
+ int ax = a & 0x03;
+ int ay = a >> 2;
+ for (int b = a + 1; b < 16; ++b) {
+ int bx = b & 0x03;
+ int by = b >> 2;
+ for (int c = a + 1; c < 16; ++c) {
+ if (b == c) {
+ continue;
+ }
+ int cx = c & 0x03;
+ int cy = c >> 2;
+ if ((bx - ax) * (cy - ay) == (by - ay) * (cx - ax)) {
+ continue;
+ }
+ *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
+ (&testSimplifyTrianglesMain, a, b, c, 0, &testRunner));
+ }
+ if (!reporter->allowExtendedTest()) goto finish;
+ }
+ }
+finish:
+ testRunner.render();
+}
diff --git a/src/third_party/skia/tests/PathOpsSkpClipTest.cpp b/src/third_party/skia/tests/PathOpsSkpClipTest.cpp
new file mode 100755
index 0000000..b8142cd
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsSkpClipTest.cpp
@@ -0,0 +1,1105 @@
+#include "CrashHandler.h"
+// #include "OverwriteLine.h"
+#include "Resources.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColor.h"
+#include "SkColorPriv.h"
+#include "SkCommandLineFlags.h"
+#include "SkDevice.h"
+#include "SkForceLinking.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkImageEncoder.h"
+#include "SkOSFile.h"
+#include "SkPathOpsDebug.h"
+#include "SkPicture.h"
+#include "SkRTConf.h"
+#include "SkTSort.h"
+#include "SkStream.h"
+#include "SkString.h"
+#include "SkTArray.h"
+#include "SkTDArray.h"
+#include "SkTaskGroup.h"
+#include "SkTemplates.h"
+#include "SkTime.h"
+
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
+/* add local exceptions here */
+/* TODO : add command flag interface */
+const struct SkipOverTest {
+ int directory;
+ const char* filename;
+ bool blamePathOps;
+} skipOver[] = {
+ { 2, "http___www_groupon_sg_.skp", false}, // SkAAClip::Builder::addRun SkASSERT(fBounds.contains(x, y));
+ { 6, "http___www_googleventures_com_.skp", true}, // addTCoincident SkASSERT(test->fT < 1);
+ { 7, "http___www_foxsports_nl_.skp", true}, // (no repro on mac) addT SkASSERT(this != other || fVerb == SkPath::kCubic_Verb)
+ {13, "http___www_modernqigong_com_.skp", false}, // SkAAClip::Builder::addRun SkASSERT(fBounds.contains(x, y));
+ {14, "http___www_devbridge_com_.skp", true}, // checkSmallCoincidence SkASSERT(!next->fSmall || checkMultiple);
+ {16, "http___www_1023world_net_.skp", false}, // bitmap decode assert (corrupt skp?)
+ {19, "http___www_alamdi_com_.skp", true}, // cubic/quad intersection
+ {26, "http___www_liveencounters_net_.skp", true}, // (no repro on mac) checkSmall addT:549 (line, expects cubic)
+ {28, "http___www_encros_fr_.skp", false}, // SkAAClip::Builder::addRun SkASSERT(fBounds.contains(x, y));
+ {37, "http___www_familysurvivalprotocol_wordpress_com_.skp", true}, // bumpSpan SkASSERT(span->fOppValue >= 0);
+ {39, "http___sufeinet_com_.skp", false}, // bitmap decode assert (corrupt skp?)
+ {41, "http___www_rano360_com_.skp", true}, // checkSmallCoincidence SkASSERT(!next->fSmall || checkMultiple);
+ {44, "http___www_firstunitedbank_com_.skp", true}, // addTCancel SkASSERT(oIndex > 0);
+ {46, "http___www_shinydemos_com_.skp", true}, // addSimpleAngle SkASSERT(index == count() - 2);
+ {48, "http___www_familysurvivalprotocol_com_.skp", true}, // bumpSpan SkASSERT "span->fOppValue >= 0"
+ {57, "http___www_lptemp_com_.skp", true}, // addTCoincident oPeek = &other->fTs[++oPeekIndex];
+ {71, "http___www_1milyonkahraman_org_.skp", true}, // addTCoincident SkASSERT(test->fT < 1);
+ {88, "http___www_apuntesdelechuza_wordpress_com_.skp", true}, // bumpSpan SkASSERT "span->fOppValue >= 0"
+ {89, "http___www_mobilizedconsulting_com_.skp", true}, // addTCancel SkASSERT(oIndex > 0);
+ {93, "http___www_simple_living_in_suffolk_co_uk_.skp", true}, // bumpSpan SkASSERT "span->fOppValue >= 0"
+};
+
+size_t skipOverCount = sizeof(skipOver) / sizeof(skipOver[0]);
+
+
+/* customize file in/out here */
+/* TODO : add command flag interface */
+#define CHROME_VERSION "1e5dfa4-4a995df"
+#define SUMMARY_RUN 1
+
+#ifdef SK_BUILD_FOR_WIN
+ #define DRIVE_SPEC "D:"
+ #define PATH_SLASH "\\"
+#else
+ #define DRIVE_SPEC ""
+ #define PATH_SLASH "/"
+#endif
+
+#define IN_DIR_PRE DRIVE_SPEC PATH_SLASH "skps" PATH_SLASH "slave"
+#define OUT_DIR_PRE DRIVE_SPEC PATH_SLASH "skpOut" PATH_SLASH "slave"
+#define OUT_DIR_SUM DRIVE_SPEC PATH_SLASH "skpOut" PATH_SLASH "summary"
+#define DIR_POST PATH_SLASH "All" PATH_SLASH CHROME_VERSION
+
+static const char outOpDir[] = "opClip";
+static const char outOldDir[] = "oldClip";
+static const char outStatusDir[] = "statusTest";
+
+static SkString get_in_path(int dirNo, const char* filename) {
+ SkString path;
+ SkASSERT(dirNo);
+ path.appendf("%s%d%s", IN_DIR_PRE, dirNo, DIR_POST);
+ if (!sk_exists(path.c_str())) {
+ SkDebugf("could not read %s\n", path.c_str());
+ return SkString();
+ }
+ if (filename) {
+ path.appendf("%s%s", PATH_SLASH, filename);
+ if (!sk_exists(path.c_str())) {
+ SkDebugf("could not read %s\n", path.c_str());
+ return SkString();
+ }
+ }
+ return path;
+}
+
+static void make_recursive_dir(const SkString& path) {
+ if (sk_exists(path.c_str())) {
+ return;
+ }
+ const char* pathStr = path.c_str();
+ int last = (int) path.size();
+ do {
+ while (last > 0 && pathStr[--last] != PATH_SLASH[0])
+ ;
+ SkASSERT(last > 0);
+ SkString shorter(pathStr, last);
+ if (sk_mkdir(shorter.c_str())) {
+ break;
+ }
+ } while (true);
+ do {
+ while (last < (int) path.size() && pathStr[++last] != PATH_SLASH[0])
+ ;
+ SkString shorter(pathStr, last);
+ SkAssertResult(sk_mkdir(shorter.c_str()));
+ } while (last < (int) path.size());
+}
+
+static SkString get_out_path(int dirNo, const char* dirName) {
+ SkString path;
+ SkASSERT(dirNo);
+ SkASSERT(dirName);
+ path.appendf("%s%d%s%s%s", OUT_DIR_PRE, dirNo, DIR_POST, PATH_SLASH, dirName);
+ make_recursive_dir(path);
+ return path;
+}
+
+static SkString get_sum_path(const char* dirName) {
+ SkString path;
+ SkASSERT(dirName);
+ path.appendf("%s%d%s%s", OUT_DIR_SUM, SUMMARY_RUN, PATH_SLASH, dirName);
+ SkDebugf("%s\n", path.c_str());
+ make_recursive_dir(path);
+ return path;
+}
+
+static SkString make_png_name(const char* filename) {
+ SkString pngName = SkString(filename);
+ pngName.remove(pngName.size() - 3, 3);
+ pngName.append("png");
+ return pngName;
+}
+
+////////////////////////////////////////////////////////
+
+enum TestStep {
+ kCompareBits,
+ kEncodeFiles,
+};
+
+enum {
+ kMaxLength = 256,
+ kMaxFiles = 128,
+ kSmallLimit = 1000,
+};
+
+struct TestResult {
+ void init(int dirNo) {
+ fDirNo = dirNo;
+ sk_bzero(fFilename, sizeof(fFilename));
+ fTestStep = kCompareBits;
+ fScale = 1;
+ }
+
+ void init(int dirNo, const SkString& filename) {
+ fDirNo = dirNo;
+ strcpy(fFilename, filename.c_str());
+ fTestStep = kCompareBits;
+ fScale = 1;
+ }
+
+ SkString status() {
+ SkString outStr;
+ outStr.printf("%s %d %d\n", fFilename, fPixelError, fTime);
+ return outStr;
+ }
+
+ SkString progress() {
+ SkString outStr;
+ outStr.printf("dir=%d %s ", fDirNo, fFilename);
+ if (fPixelError) {
+ outStr.appendf(" err=%d", fPixelError);
+ }
+ if (fTime) {
+ outStr.appendf(" time=%d", fTime);
+ }
+ if (fScale != 1) {
+ outStr.appendf(" scale=%d", fScale);
+ }
+ outStr.appendf("\n");
+ return outStr;
+
+ }
+
+ void test(int dirNo, const SkString& filename) {
+ init(dirNo);
+ strcpy(fFilename, filename.c_str());
+ testOne();
+ }
+
+ void testOne();
+
+ char fFilename[kMaxLength];
+ TestStep fTestStep;
+ int fDirNo;
+ int fPixelError;
+ int fTime;
+ int fScale;
+};
+
+class SortByPixel : public TestResult {
+public:
+ bool operator<(const SortByPixel& rh) const {
+ return fPixelError < rh.fPixelError;
+ }
+};
+
+class SortByTime : public TestResult {
+public:
+ bool operator<(const SortByTime& rh) const {
+ return fTime < rh.fTime;
+ }
+};
+
+class SortByName : public TestResult {
+public:
+ bool operator<(const SortByName& rh) const {
+ return strcmp(fFilename, rh.fFilename) < 0;
+ }
+};
+
+struct TestState {
+ void init(int dirNo) {
+ fResult.init(dirNo);
+ }
+
+ SkTDArray<SortByPixel> fPixelWorst;
+ SkTDArray<SortByTime> fSlowest;
+ TestResult fResult;
+};
+
+struct TestRunner {
+ ~TestRunner();
+ void render();
+ SkTDArray<class TestRunnable*> fRunnables;
+};
+
+class TestRunnable : public SkRunnable {
+public:
+ virtual void run() SK_OVERRIDE {
+ SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
+ (*fTestFun)(&fState);
+ }
+
+ TestState fState;
+ void (*fTestFun)(TestState*);
+};
+
+
+class TestRunnableDir : public TestRunnable {
+public:
+ TestRunnableDir(void (*testFun)(TestState*), int dirNo, TestRunner* runner) {
+ fState.init(dirNo);
+ fTestFun = testFun;
+ }
+
+};
+
+class TestRunnableFile : public TestRunnable {
+public:
+ TestRunnableFile(void (*testFun)(TestState*), int dirNo, const char* name, TestRunner* runner) {
+ fState.init(dirNo);
+ strcpy(fState.fResult.fFilename, name);
+ fTestFun = testFun;
+ }
+};
+
+class TestRunnableEncode : public TestRunnableFile {
+public:
+ TestRunnableEncode(void (*testFun)(TestState*), int dirNo, const char* name, TestRunner* runner)
+ : TestRunnableFile(testFun, dirNo, name, runner) {
+ fState.fResult.fTestStep = kEncodeFiles;
+ }
+};
+
+TestRunner::~TestRunner() {
+ for (int index = 0; index < fRunnables.count(); index++) {
+ SkDELETE(fRunnables[index]);
+ }
+}
+
+void TestRunner::render() {
+ SkTaskGroup tg;
+ for (int index = 0; index < fRunnables.count(); ++ index) {
+ tg.add(fRunnables[index]);
+ }
+}
+
+////////////////////////////////////////////////
+
+
+static int similarBits(const SkBitmap& gr, const SkBitmap& sk) {
+ const int kRowCount = 3;
+ const int kThreshold = 3;
+ int width = SkTMin(gr.width(), sk.width());
+ if (width < kRowCount) {
+ return true;
+ }
+ int height = SkTMin(gr.height(), sk.height());
+ if (height < kRowCount) {
+ return true;
+ }
+ int errorTotal = 0;
+ SkTArray<int, true> errorRows;
+ errorRows.push_back_n(width * kRowCount);
+ SkAutoLockPixels autoGr(gr);
+ SkAutoLockPixels autoSk(sk);
+ for (int y = 0; y < height; ++y) {
+ SkPMColor* grRow = gr.getAddr32(0, y);
+ SkPMColor* skRow = sk.getAddr32(0, y);
+ int* base = &errorRows[0];
+ int* cOut = &errorRows[y % kRowCount];
+ for (int x = 0; x < width; ++x) {
+ SkPMColor grColor = grRow[x];
+ SkPMColor skColor = skRow[x];
+ int dr = SkGetPackedR32(grColor) - SkGetPackedR32(skColor);
+ int dg = SkGetPackedG32(grColor) - SkGetPackedG32(skColor);
+ int db = SkGetPackedB32(grColor) - SkGetPackedB32(skColor);
+ int error = cOut[x] = SkTMax(SkAbs32(dr), SkTMax(SkAbs32(dg), SkAbs32(db)));
+ if (error < kThreshold || x < 2) {
+ continue;
+ }
+ if (base[x - 2] < kThreshold
+ || base[width + x - 2] < kThreshold
+ || base[width * 2 + x - 2] < kThreshold
+ || base[x - 1] < kThreshold
+ || base[width + x - 1] < kThreshold
+ || base[width * 2 + x - 1] < kThreshold
+ || base[x] < kThreshold
+ || base[width + x] < kThreshold
+ || base[width * 2 + x] < kThreshold) {
+ continue;
+ }
+ errorTotal += error;
+ }
+ }
+ return errorTotal;
+}
+
+static bool addError(TestState* data, const TestResult& testResult) {
+ if (testResult.fPixelError <= 0 && testResult.fTime <= 0) {
+ return false;
+ }
+ int worstCount = data->fPixelWorst.count();
+ int pixelError = testResult.fPixelError;
+ if (pixelError > 0) {
+ for (int index = 0; index < worstCount; ++index) {
+ if (pixelError > data->fPixelWorst[index].fPixelError) {
+ data->fPixelWorst[index] = *(SortByPixel*) &testResult;
+ return true;
+ }
+ }
+ }
+ int slowCount = data->fSlowest.count();
+ int time = testResult.fTime;
+ if (time > 0) {
+ for (int index = 0; index < slowCount; ++index) {
+ if (time > data->fSlowest[index].fTime) {
+ data->fSlowest[index] = *(SortByTime*) &testResult;
+ return true;
+ }
+ }
+ }
+ if (pixelError > 0 && worstCount < kMaxFiles) {
+ *data->fPixelWorst.append() = *(SortByPixel*) &testResult;
+ return true;
+ }
+ if (time > 0 && slowCount < kMaxFiles) {
+ *data->fSlowest.append() = *(SortByTime*) &testResult;
+ return true;
+ }
+ return false;
+}
+
+static SkMSec timePict(SkPicture* pic, SkCanvas* canvas) {
+ canvas->save();
+ SkScalar pWidth = pic->cullRect().width();
+ SkScalar pHeight = pic->cullRect().height();
+ const SkScalar maxDimension = 1000.0f;
+ const int slices = 3;
+ SkScalar xInterval = SkTMax(pWidth - maxDimension, 0.0f) / (slices - 1);
+ SkScalar yInterval = SkTMax(pHeight - maxDimension, 0.0f) / (slices - 1);
+ SkRect rect = {0, 0, SkTMin(maxDimension, pWidth), SkTMin(maxDimension, pHeight) };
+ canvas->clipRect(rect);
+ SkMSec start = SkTime::GetMSecs();
+ for (int x = 0; x < slices; ++x) {
+ for (int y = 0; y < slices; ++y) {
+ pic->playback(canvas);
+ canvas->translate(0, yInterval);
+ }
+ canvas->translate(xInterval, -yInterval * slices);
+ }
+ SkMSec end = SkTime::GetMSecs();
+ canvas->restore();
+ return end - start;
+}
+
+static void drawPict(SkPicture* pic, SkCanvas* canvas, int scale) {
+ canvas->clear(SK_ColorWHITE);
+ if (scale != 1) {
+ canvas->save();
+ canvas->scale(1.0f / scale, 1.0f / scale);
+ }
+ pic->playback(canvas);
+ if (scale != 1) {
+ canvas->restore();
+ }
+}
+
+static void writePict(const SkBitmap& bitmap, const char* outDir, const char* pngName) {
+ SkString outFile = get_sum_path(outDir);
+ outFile.appendf("%s%s", PATH_SLASH, pngName);
+ if (!SkImageEncoder::EncodeFile(outFile.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100)) {
+ SkDebugf("unable to encode gr %s (width=%d height=%d)\n", pngName,
+ bitmap.width(), bitmap.height());
+ }
+}
+
+void TestResult::testOne() {
+ SkPicture* pic = NULL;
+ {
+ #if DEBUG_SHOW_TEST_NAME
+ if (fTestStep == kCompareBits) {
+ SkString testName(fFilename);
+ const char http[] = "http";
+ if (testName.startsWith(http)) {
+ testName.remove(0, sizeof(http) - 1);
+ }
+ while (testName.startsWith("_")) {
+ testName.remove(0, 1);
+ }
+ const char dotSkp[] = ".skp";
+ if (testName.endsWith(dotSkp)) {
+ size_t len = testName.size();
+ testName.remove(len - (sizeof(dotSkp) - 1), sizeof(dotSkp) - 1);
+ }
+ testName.prepend("skp");
+ testName.append("1");
+ strncpy(DEBUG_FILENAME_STRING, testName.c_str(), DEBUG_FILENAME_STRING_LENGTH);
+ } else if (fTestStep == kEncodeFiles) {
+ strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
+ }
+ #endif
+ SkString path = get_in_path(fDirNo, fFilename);
+ SkFILEStream stream(path.c_str());
+ if (!stream.isValid()) {
+ SkDebugf("invalid stream %s\n", path.c_str());
+ goto finish;
+ }
+ pic = SkPicture::CreateFromStream(&stream, &SkImageDecoder::DecodeMemory);
+ if (!pic) {
+ SkDebugf("unable to decode %s\n", fFilename);
+ goto finish;
+ }
+ SkScalar width = pic->cullRect().width();
+ SkScalar height = pic->cullRect().height();
+ SkBitmap oldBitmap, opBitmap;
+ fScale = 1;
+ while (width / fScale > 32767 || height / fScale > 32767) {
+ ++fScale;
+ }
+ do {
+ int dimX = SkScalarCeilToInt(width / fScale);
+ int dimY = SkScalarCeilToInt(height / fScale);
+ if (oldBitmap.tryAllocN32Pixels(dimX, dimY) && opBitmap.tryAllocN32Pixels(dimX, dimY)) {
+ break;
+ }
+ SkDebugf("-%d-", fScale);
+ } while (++fScale < 256);
+ if (fScale >= 256) {
+ SkDebugf("unable to allocate bitmap for %s (w=%f h=%f)\n", fFilename,
+ width, height);
+ goto finish;
+ }
+ oldBitmap.eraseColor(SK_ColorWHITE);
+ SkCanvas oldCanvas(oldBitmap);
+ oldCanvas.setAllowSimplifyClip(false);
+ opBitmap.eraseColor(SK_ColorWHITE);
+ SkCanvas opCanvas(opBitmap);
+ opCanvas.setAllowSimplifyClip(true);
+ drawPict(pic, &oldCanvas, fScale);
+ drawPict(pic, &opCanvas, fScale);
+ if (fTestStep == kCompareBits) {
+ fPixelError = similarBits(oldBitmap, opBitmap);
+ int oldTime = timePict(pic, &oldCanvas);
+ int opTime = timePict(pic, &opCanvas);
+ fTime = SkTMax(0, oldTime - opTime);
+ } else if (fTestStep == kEncodeFiles) {
+ SkString pngStr = make_png_name(fFilename);
+ const char* pngName = pngStr.c_str();
+ writePict(oldBitmap, outOldDir, pngName);
+ writePict(opBitmap, outOpDir, pngName);
+ }
+ }
+finish:
+ if (pic) {
+ pic->unref();
+ }
+}
+
+DEFINE_string2(match, m, "PathOpsSkpClipThreaded",
+ "[~][^]substring[$] [...] of test name to run.\n"
+ "Multiple matches may be separated by spaces.\n"
+ "~ causes a matching test to always be skipped\n"
+ "^ requires the start of the test to match\n"
+ "$ requires the end of the test to match\n"
+ "^ and $ requires an exact match\n"
+ "If a test does not match any list entry,\n"
+ "it is skipped unless some list entry starts with ~");
+DEFINE_string2(dir, d, NULL, "range of directories (e.g., 1-100)");
+DEFINE_string2(skp, s, NULL, "skp to test");
+DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
+DEFINE_int32(testIndex, 0, "override local test index (PathOpsSkpClipOneOff only).");
+DEFINE_bool2(verbose, v, false, "enable verbose output.");
+
+static bool verbose() {
+ return FLAGS_verbose;
+}
+
+class Dirs {
+public:
+ Dirs() {
+ reset();
+ sk_bzero(fRun, sizeof(fRun));
+ fSet = false;
+ }
+
+ int first() const {
+ int index = 0;
+ while (++index < kMaxDir) {
+ if (fRun[index]) {
+ return index;
+ }
+ }
+ SkASSERT(0);
+ return -1;
+ }
+
+ int last() const {
+ int index = kMaxDir;
+ while (--index > 0 && !fRun[index])
+ ;
+ return index;
+ }
+
+ int next() {
+ while (++fIndex < kMaxDir) {
+ if (fRun[fIndex]) {
+ return fIndex;
+ }
+ }
+ return -1;
+ }
+
+ void reset() {
+ fIndex = -1;
+ }
+
+ void set(int start, int end) {
+ while (start < end) {
+ fRun[start++] = 1;
+ }
+ fSet = true;
+ }
+
+ void setDefault() {
+ if (!fSet) {
+ set(1, 100);
+ }
+ }
+
+private:
+ enum {
+ kMaxDir = 101
+ };
+ char fRun[kMaxDir];
+ int fIndex;
+ bool fSet;
+} gDirs;
+
+class Filenames {
+public:
+ Filenames()
+ : fIndex(-1) {
+ }
+
+ const char* next() {
+ while (fNames && ++fIndex < fNames->count()) {
+ return (*fNames)[fIndex];
+ }
+ return NULL;
+ }
+
+ void set(const SkCommandLineFlags::StringArray& names) {
+ fNames = &names;
+ }
+
+private:
+ int fIndex;
+ const SkCommandLineFlags::StringArray* fNames;
+} gNames;
+
+static bool buildTestDir(int dirNo, int firstDirNo,
+ SkTDArray<TestResult>* tests, SkTDArray<SortByName*>* sorted) {
+ SkString dirName = get_out_path(dirNo, outStatusDir);
+ if (!dirName.size()) {
+ return false;
+ }
+ SkOSFile::Iter iter(dirName.c_str(), "skp");
+ SkString filename;
+ while (iter.next(&filename)) {
+ TestResult test;
+ test.init(dirNo);
+ SkString spaceFile(filename);
+ char* spaces = spaceFile.writable_str();
+ int spaceSize = (int) spaceFile.size();
+ for (int index = 0; index < spaceSize; ++index) {
+ if (spaces[index] == '.') {
+ spaces[index] = ' ';
+ }
+ }
+ int success = sscanf(spaces, "%s %d %d skp", test.fFilename,
+ &test.fPixelError, &test.fTime);
+ if (success < 3) {
+ SkDebugf("failed to scan %s matched=%d\n", filename.c_str(), success);
+ return false;
+ }
+ *tests[dirNo - firstDirNo].append() = test;
+ }
+ if (!sorted) {
+ return true;
+ }
+ SkTDArray<TestResult>& testSet = tests[dirNo - firstDirNo];
+ int count = testSet.count();
+ for (int index = 0; index < count; ++index) {
+ *sorted[dirNo - firstDirNo].append() = (SortByName*) &testSet[index];
+ }
+ if (sorted[dirNo - firstDirNo].count()) {
+ SkTQSort<SortByName>(sorted[dirNo - firstDirNo].begin(),
+ sorted[dirNo - firstDirNo].end() - 1);
+ if (verbose()) {
+ SkDebugf("+");
+ }
+ }
+ return true;
+}
+
+static void testSkpClip(TestState* data) {
+ data->fResult.testOne();
+ SkString statName(data->fResult.fFilename);
+ SkASSERT(statName.endsWith(".skp"));
+ statName.remove(statName.size() - 4, 4);
+ statName.appendf(".%d.%d.skp", data->fResult.fPixelError, data->fResult.fTime);
+ SkString statusFile = get_out_path(data->fResult.fDirNo, outStatusDir);
+ if (!statusFile.size()) {
+ SkDebugf("failed to create %s", statusFile.c_str());
+ return;
+ }
+ statusFile.appendf("%s%s", PATH_SLASH, statName.c_str());
+ SkFILE* file = sk_fopen(statusFile.c_str(), kWrite_SkFILE_Flag);
+ if (!file) {
+ SkDebugf("failed to create %s", statusFile.c_str());
+ return;
+ }
+ sk_fclose(file);
+ if (verbose()) {
+ if (data->fResult.fPixelError || data->fResult.fTime) {
+ SkDebugf("%s", data->fResult.progress().c_str());
+ } else {
+ SkDebugf(".");
+ }
+ }
+}
+
+bool Less(const SortByName& a, const SortByName& b);
+bool Less(const SortByName& a, const SortByName& b) {
+ return a < b;
+}
+
+static bool doOneDir(TestState* state, bool threaded) {
+ int dirNo = state->fResult.fDirNo;
+ SkString dirName = get_in_path(dirNo, NULL);
+ if (!dirName.size()) {
+ return false;
+ }
+ SkTDArray<TestResult> tests[1];
+ SkTDArray<SortByName*> sorted[1];
+ if (!buildTestDir(dirNo, dirNo, tests, sorted)) {
+ return false;
+ }
+ SkOSFile::Iter iter(dirName.c_str(), "skp");
+ SkString filename;
+ while (iter.next(&filename)) {
+ for (size_t index = 0; index < skipOverCount; ++index) {
+ if (skipOver[index].directory == dirNo
+ && strcmp(filename.c_str(), skipOver[index].filename) == 0) {
+ goto checkEarlyExit;
+ }
+ }
+ {
+ SortByName name;
+ name.init(dirNo);
+ strncpy(name.fFilename, filename.c_str(), filename.size() - 4); // drop .skp
+ int count = sorted[0].count();
+ int idx = SkTSearch<SortByName, Less>(sorted[0].begin(), count, &name, sizeof(&name));
+ if (idx >= 0) {
+ SortByName* found = sorted[0][idx];
+ (void) addError(state, *found);
+ continue;
+ }
+ TestResult test;
+ test.init(dirNo, filename);
+ state->fResult = test;
+ testSkpClip(state);
+#if 0 // artificially limit to a few while debugging code
+ static int debugLimit = 0;
+ if (++debugLimit == 5) {
+ return true;
+ }
+#endif
+ }
+checkEarlyExit:
+ ;
+ }
+ return true;
+}
+
+static void initTest() {
+#if !defined SK_BUILD_FOR_WIN && !defined SK_BUILD_FOR_MAC
+ SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true);
+ SK_CONF_SET("images.png.suppressDecoderWarnings", true);
+#endif
+}
+
+static void testSkpClipEncode(TestState* data) {
+ data->fResult.testOne();
+ if (verbose()) {
+ SkDebugf("+");
+ }
+}
+
+static void encodeFound(TestState& state) {
+ if (verbose()) {
+ if (state.fPixelWorst.count()) {
+ SkTDArray<SortByPixel*> worst;
+ for (int index = 0; index < state.fPixelWorst.count(); ++index) {
+ *worst.append() = &state.fPixelWorst[index];
+ }
+ SkTQSort<SortByPixel>(worst.begin(), worst.end() - 1);
+ for (int index = 0; index < state.fPixelWorst.count(); ++index) {
+ const TestResult& result = *worst[index];
+ SkDebugf("%d %s pixelError=%d\n", result.fDirNo, result.fFilename, result.fPixelError);
+ }
+ }
+ if (state.fSlowest.count()) {
+ SkTDArray<SortByTime*> slowest;
+ for (int index = 0; index < state.fSlowest.count(); ++index) {
+ *slowest.append() = &state.fSlowest[index];
+ }
+ if (slowest.count() > 0) {
+ SkTQSort<SortByTime>(slowest.begin(), slowest.end() - 1);
+ for (int index = 0; index < slowest.count(); ++index) {
+ const TestResult& result = *slowest[index];
+ SkDebugf("%d %s time=%d\n", result.fDirNo, result.fFilename, result.fTime);
+ }
+ }
+ }
+ }
+ TestRunner testRunner;
+ for (int index = 0; index < state.fPixelWorst.count(); ++index) {
+ const TestResult& result = state.fPixelWorst[index];
+ SkString filename(result.fFilename);
+ if (!filename.endsWith(".skp")) {
+ filename.append(".skp");
+ }
+ *testRunner.fRunnables.append() = SkNEW_ARGS(TestRunnableEncode,
+ (&testSkpClipEncode, result.fDirNo, filename.c_str(), &testRunner));
+ }
+ testRunner.render();
+}
+
+class Test {
+public:
+ Test() {}
+ virtual ~Test() {}
+
+ const char* getName() { onGetName(&fName); return fName.c_str(); }
+ void run() { onRun(); }
+
+protected:
+ virtual void onGetName(SkString*) = 0;
+ virtual void onRun() = 0;
+
+private:
+ SkString fName;
+};
+
+typedef SkTRegistry<Test*(*)(void*)> TestRegistry;
+
+#define DEF_TEST(name) \
+ static void test_##name(); \
+ class name##Class : public Test { \
+ public: \
+ static Test* Factory(void*) { return SkNEW(name##Class); } \
+ protected: \
+ virtual void onGetName(SkString* name) SK_OVERRIDE { \
+ name->set(#name); \
+ } \
+ virtual void onRun() SK_OVERRIDE { test_##name(); } \
+ }; \
+ static TestRegistry gReg_##name##Class(name##Class::Factory); \
+ static void test_##name()
+
+DEF_TEST(PathOpsSkpClip) {
+ gDirs.setDefault();
+ initTest();
+ SkTArray<TestResult, true> errors;
+ TestState state;
+ state.init(0);
+ int dirNo;
+ gDirs.reset();
+ while ((dirNo = gDirs.next()) > 0) {
+ if (verbose()) {
+ SkDebugf("dirNo=%d\n", dirNo);
+ }
+ state.fResult.fDirNo = dirNo;
+ if (!doOneDir(&state, false)) {
+ break;
+ }
+ }
+ encodeFound(state);
+}
+
+static void testSkpClipMain(TestState* data) {
+ (void) doOneDir(data, true);
+}
+
+DEF_TEST(PathOpsSkpClipThreaded) {
+ gDirs.setDefault();
+ initTest();
+ TestRunner testRunner;
+ int dirNo;
+ gDirs.reset();
+ while ((dirNo = gDirs.next()) > 0) {
+ *testRunner.fRunnables.append() = SkNEW_ARGS(TestRunnableDir,
+ (&testSkpClipMain, dirNo, &testRunner));
+ }
+ testRunner.render();
+ TestState state;
+ state.init(0);
+ gDirs.reset();
+ while ((dirNo = gDirs.next()) > 0) {
+ TestState& testState = testRunner.fRunnables[dirNo - 1]->fState;
+ SkASSERT(testState.fResult.fDirNo == dirNo);
+ for (int inner = 0; inner < testState.fPixelWorst.count(); ++inner) {
+ addError(&state, testState.fPixelWorst[inner]);
+ }
+ for (int inner = 0; inner < testState.fSlowest.count(); ++inner) {
+ addError(&state, testState.fSlowest[inner]);
+ }
+ }
+ encodeFound(state);
+}
+
+static bool buildTests(SkTDArray<TestResult>* tests, SkTDArray<SortByName*>* sorted) {
+ int firstDirNo = gDirs.first();
+ int dirNo;
+ while ((dirNo = gDirs.next()) > 0) {
+ if (!buildTestDir(dirNo, firstDirNo, tests, sorted)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+DEF_TEST(PathOpsSkpClipUberThreaded) {
+ gDirs.setDefault();
+ const int firstDirNo = gDirs.next();
+ const int lastDirNo = gDirs.last();
+ initTest();
+ int dirCount = lastDirNo - firstDirNo + 1;
+ SkAutoTDeleteArray<SkTDArray<TestResult> > tests(new SkTDArray<TestResult>[dirCount]);
+ SkAutoTDeleteArray<SkTDArray<SortByName*> > sorted(new SkTDArray<SortByName*>[dirCount]);
+ if (!buildTests(tests.get(), sorted.get())) {
+ return;
+ }
+ TestRunner testRunner;
+ int dirNo;
+ gDirs.reset();
+ while ((dirNo = gDirs.next()) > 0) {
+ SkString dirName = get_in_path(dirNo, NULL);
+ if (!dirName.size()) {
+ continue;
+ }
+ SkOSFile::Iter iter(dirName.c_str(), "skp");
+ SkString filename;
+ while (iter.next(&filename)) {
+ for (size_t index = 0; index < skipOverCount; ++index) {
+ if (skipOver[index].directory == dirNo
+ && strcmp(filename.c_str(), skipOver[index].filename) == 0) {
+ goto checkEarlyExit;
+ }
+ }
+ {
+ SortByName name;
+ name.init(dirNo);
+ strncpy(name.fFilename, filename.c_str(), filename.size() - 4); // drop .skp
+ int count = sorted.get()[dirNo - firstDirNo].count();
+ if (SkTSearch<SortByName, Less>(sorted.get()[dirNo - firstDirNo].begin(),
+ count, &name, sizeof(&name)) < 0) {
+ *testRunner.fRunnables.append() = SkNEW_ARGS(TestRunnableFile,
+ (&testSkpClip, dirNo, filename.c_str(), &testRunner));
+ }
+ }
+ checkEarlyExit:
+ ;
+ }
+
+ }
+ testRunner.render();
+ SkAutoTDeleteArray<SkTDArray<TestResult> > results(new SkTDArray<TestResult>[dirCount]);
+ if (!buildTests(results.get(), NULL)) {
+ return;
+ }
+ SkTDArray<TestResult> allResults;
+ for (int dirNo = firstDirNo; dirNo <= lastDirNo; ++dirNo) {
+ SkTDArray<TestResult>& array = results.get()[dirNo - firstDirNo];
+ allResults.append(array.count(), array.begin());
+ }
+ int allCount = allResults.count();
+ SkTDArray<SortByPixel*> pixels;
+ SkTDArray<SortByTime*> times;
+ for (int index = 0; index < allCount; ++index) {
+ *pixels.append() = (SortByPixel*) &allResults[index];
+ *times.append() = (SortByTime*) &allResults[index];
+ }
+ TestState state;
+ if (pixels.count()) {
+ SkTQSort<SortByPixel>(pixels.begin(), pixels.end() - 1);
+ for (int inner = 0; inner < kMaxFiles; ++inner) {
+ *state.fPixelWorst.append() = *pixels[allCount - inner - 1];
+ }
+ }
+ if (times.count()) {
+ SkTQSort<SortByTime>(times.begin(), times.end() - 1);
+ for (int inner = 0; inner < kMaxFiles; ++inner) {
+ *state.fSlowest.append() = *times[allCount - inner - 1];
+ }
+ }
+ encodeFound(state);
+}
+
+DEF_TEST(PathOpsSkpClipOneOff) {
+ const int testIndex = FLAGS_testIndex;
+ int dirNo = gDirs.next();
+ if (dirNo < 0) {
+ dirNo = skipOver[testIndex].directory;
+ }
+ const char* skp = gNames.next();
+ if (!skp) {
+ skp = skipOver[testIndex].filename;
+ }
+ initTest();
+ SkAssertResult(get_in_path(dirNo, skp).size());
+ SkString filename(skp);
+ TestResult state;
+ state.test(dirNo, filename);
+ if (verbose()) {
+ SkDebugf("%s", state.status().c_str());
+ }
+ state.fTestStep = kEncodeFiles;
+ state.testOne();
+}
+
+DEF_TEST(PathOpsTestSkipped) {
+ for (size_t index = 0; index < skipOverCount; ++index) {
+ const SkipOverTest& skip = skipOver[index];
+ if (!skip.blamePathOps) {
+ continue;
+ }
+ int dirNo = skip.directory;
+ const char* skp = skip.filename;
+ initTest();
+ SkAssertResult(get_in_path(dirNo, skp).size());
+ SkString filename(skp);
+ TestResult state;
+ state.test(dirNo, filename);
+ if (verbose()) {
+ SkDebugf("%s", state.status().c_str());
+ }
+ state.fTestStep = kEncodeFiles;
+ state.testOne();
+ }
+}
+
+DEF_TEST(PathOpsCopyFails) {
+ FLAGS_verbose = true;
+ for (size_t index = 0; index < skipOverCount; ++index) {
+ int dirNo = skipOver[index].directory;
+ SkDebugf("mkdir -p " IN_DIR_PRE "%d" DIR_POST "\n", dirNo);
+ }
+ for (size_t index = 0; index < skipOverCount; ++index) {
+ int dirNo = skipOver[index].directory;
+ const char* filename = skipOver[index].filename;
+ SkDebugf("rsync -av cary-linux.cnc:/tera" PATH_SLASH "skps" PATH_SLASH "slave"
+ "%d" DIR_POST "/%s " IN_DIR_PRE "%d" DIR_POST "\n", dirNo, filename, dirNo);
+ }
+}
+
+template TestRegistry* TestRegistry::gHead;
+
+class Iter {
+public:
+ Iter() { this->reset(); }
+ void reset() { fReg = TestRegistry::Head(); }
+
+ Test* next() {
+ if (fReg) {
+ TestRegistry::Factory fact = fReg->factory();
+ fReg = fReg->next();
+ Test* test = fact(NULL);
+ return test;
+ }
+ return NULL;
+ }
+
+private:
+ const TestRegistry* fReg;
+};
+
+int tool_main(int argc, char** argv);
+int tool_main(int argc, char** argv) {
+ SetupCrashHandler();
+ SkCommandLineFlags::SetUsage("");
+ SkCommandLineFlags::Parse(argc, argv);
+ SkGraphics::Init();
+ SkString header("PathOps SkpClip:");
+ if (!FLAGS_match.isEmpty()) {
+ header.appendf(" --match");
+ for (int index = 0; index < FLAGS_match.count(); ++index) {
+ header.appendf(" %s", FLAGS_match[index]);
+ }
+ }
+ if (!FLAGS_dir.isEmpty()) {
+ int count = FLAGS_dir.count();
+ for (int i = 0; i < count; ++i) {
+ const char* range = FLAGS_dir[i];
+ const char* dash = strchr(range, '-');
+ if (!dash) {
+ dash = strchr(range, ',');
+ }
+ int first = atoi(range);
+ int last = dash ? atoi(dash + 1) : first;
+ if (!first || !last) {
+ SkDebugf("couldn't parse --dir %s\n", range);
+ return 1;
+ }
+ gDirs.set(first, last);
+ }
+ }
+ if (!FLAGS_skp.isEmpty()) {
+ gNames.set(FLAGS_skp);
+ }
+#ifdef SK_DEBUG
+ header.append(" SK_DEBUG");
+#else
+ header.append(" SK_RELEASE");
+#endif
+ header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8);
+ if (FLAGS_verbose) {
+ header.appendf("\n");
+ }
+ SkDebugf(header.c_str());
+ Iter iter;
+ Test* test;
+ while ((test = iter.next()) != NULL) {
+ SkAutoTDelete<Test> owned(test);
+ if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) {
+ test->run();
+ }
+ }
+ SkGraphics::Term();
+ return 0;
+}
+
+#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
+int main(int argc, char * const argv[]) {
+ return tool_main(argc, (char**) argv);
+}
+#endif
diff --git a/src/third_party/skia/tests/PathOpsSkpTest.cpp b/src/third_party/skia/tests/PathOpsSkpTest.cpp
new file mode 100755
index 0000000..32ddf61
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsSkpTest.cpp
@@ -0,0 +1,3952 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+
+#define TEST(name) { name, #name }
+
+#define TEST_NEW_FAILURES 0
+
+static void skpcheeseandburger_com225(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(555, 468);
+ path.lineTo(555, 362);
+ path.lineTo(872, 362);
+ path.lineTo(872, 468);
+ path.lineTo(555, 468);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(859.11792f, 397.320343f);
+ pathB.cubicTo(855.523071f, 399.691284f, 853.721191f, 402.40863f, 853.721191f, 405.552216f);
+ pathB.cubicTo(853.721191f, 407.911163f, 854.727478f, 410.115387f, 857.043518f, 412.252716f);
+ pathB.cubicTo(859.920532f, 414.916138f, 862.704773f, 417.086426f, 864.679382f, 418.852386f);
+ pathB.cubicTo(866.382446f, 420.371765f, 867.19104f, 422.108795f, 867.19104f, 423.506378f);
+ pathB.cubicTo(867.19104f, 424.551605f, 866.741821f, 425.539886f, 865.935242f, 426.281616f);
+ pathB.cubicTo(865.250366f, 426.910553f, 864.662415f, 427.339813f, 864.139282f, 427.4646f);
+ pathB.cubicTo(863.536377f, 427.605347f, 862.259521f, 426.491272f, 860.366821f, 424.208191f);
+ pathB.cubicTo(858.345276f, 421.770355f, 857.317017f, 419.733856f, 857.317017f, 417.98587f);
+ pathB.cubicTo(857.317017f, 417.198212f, 857.942993f, 415.930389f, 857.942993f, 415.930389f);
+ pathB.cubicTo(857.942993f, 415.930389f, 852.106018f, 421.296173f, 852.279663f, 422.549042f);
+ pathB.cubicTo(852.462402f, 423.890747f, 853.669312f, 425.703613f, 855.876465f, 428.252258f);
+ pathB.cubicTo(858.038818f, 430.754944f, 859.4953f, 431.840088f, 860.190125f, 431.594513f);
+ pathB.cubicTo(862.571045f, 430.754944f, 865.48999f, 429.237549f, 868.44397f, 427.018372f);
+ pathB.cubicTo(870.505371f, 425.470032f, 871.582581f, 423.534332f, 871.582581f, 421.001678f);
+ pathB.cubicTo(871.582581f, 417.945923f, 870.056213f, 415.171692f, 867.015381f, 412.640045f);
+ pathB.cubicTo(863.683105f, 409.872803f, 861.445923f, 408.027954f, 860.551514f, 407.140503f);
+ pathB.cubicTo(858.660767f, 405.264709f, 857.765259f, 403.50174f, 857.765259f, 402.187988f);
+ pathB.cubicTo(857.765259f, 401.141785f, 858.339355f, 400.394073f, 859.476318f, 399.925873f);
+ pathB.cubicTo(860.004395f, 399.704254f, 861.270264f, 400.515869f, 863.156006f, 402.36969f);
+ pathB.cubicTo(865.094727f, 404.28241f, 866.203796f, 405.565186f, 866.383484f, 406.130219f);
+ pathB.cubicTo(868.250244f, 404.305359f, 869.179688f, 403.397919f, 871.046509f, 401.58902f);
+ pathB.cubicTo(868.26825f, 399.296967f, 864.431824f, 394.705841f, 863.156006f, 394.600037f);
+ pathB.cubicTo(863.145996f, 394.600037f, 863.136108f, 394.59903f, 863.126099f, 394.59903f);
+ pathB.cubicTo(862.352417f, 394.598022f, 859.909607f, 396.79425f, 859.11792f, 397.320343f);
+ pathB.moveTo(832.164246f, 394.307526f);
+ pathB.cubicTo(832.451721f, 394.425323f, 832.598511f, 394.486206f, 832.886963f, 394.605011f);
+ pathB.cubicTo(834.078979f, 395.474518f, 834.674927f, 395.90979f, 835.867859f, 396.781281f);
+ pathB.cubicTo(836.502808f, 397.325348f, 836.863159f, 398.000183f, 836.863159f, 398.964539f);
+ pathB.lineTo(836.863159f, 419.740845f);
+ pathB.cubicTo(836.863159f, 420.876923f, 836.319092f, 422.17868f, 835.055298f, 423.617188f);
+ pathB.cubicTo(836.39502f, 424.512665f, 837.063843f, 424.961884f, 838.39856f, 425.864349f);
+ pathB.cubicTo(839.477661f, 426.578125f, 841.37439f, 427.27594f, 842.275879f, 427.443634f);
+ pathB.cubicTo(842.999634f, 427.574402f, 843.82019f, 427.513519f, 844.354309f, 427.216034f);
+ pathB.cubicTo(846.956787f, 425.765503f, 848.689819f, 423.588257f, 848.58606f, 423.483429f);
+ pathB.cubicTo(848.58606f, 423.483429f, 846.877991f, 423.327698f, 845.971558f, 422.807587f);
+ pathB.cubicTo(845.253784f, 422.284485f, 844.892395f, 422.022949f, 844.171631f, 421.502838f);
+ pathB.cubicTo(843.361023f, 420.915833f, 842.907837f, 420.308899f, 842.907837f, 419.350525f);
+ pathB.lineTo(842.907837f, 399.445709f);
+ pathB.cubicTo(842.907837f, 398.053101f, 843.272217f, 397.417175f, 843.812256f, 397.518005f);
+ pathB.cubicTo(844.170654f, 397.583893f, 844.711731f, 398.122986f, 845.432495f, 398.782837f);
+ pathB.cubicTo(846.116333f, 399.402771f, 846.459717f, 399.709259f, 847.14856f, 400.3302f);
+ pathB.cubicTo(844.986206f, 402.099152f, 843.988892f, 403.926025f, 843.988892f, 405.932556f);
+ pathB.cubicTo(843.988892f, 410.209229f, 848.272583f, 410.951935f, 849.576355f, 408.394348f);
+ pathB.cubicTo(849.871826f, 407.816345f, 850.421875f, 406.214081f, 850.387939f, 406.196106f);
+ pathB.cubicTo(850.387939f, 406.196106f, 849.305786f, 406.771118f, 848.495239f, 406.615387f);
+ pathB.cubicTo(846.96582f, 406.316895f, 846.153198f, 405.46637f, 846.153198f, 403.89505f);
+ pathB.cubicTo(846.153198f, 401.796661f, 848.50116f, 399.09729f, 852.279663f, 396.270142f);
+ pathB.cubicTo(851.014893f, 395.315796f, 847.723511f, 391.546265f, 846.875f, 391.546265f);
+ pathB.cubicTo(846.330933f, 391.546265f, 843.988892f, 394.403351f, 843.273193f, 394.972382f);
+ pathB.cubicTo(840.889282f, 392.886963f, 839.700317f, 391.850739f, 837.312378f, 389.786285f);
+ pathB.cubicTo(835.257935f, 391.589203f, 834.225708f, 392.491638f, 832.164246f, 394.307526f);
+ pathB.moveTo(818.860107f, 392.707275f);
+ pathB.cubicTo(819.857361f, 393.382111f, 822.302124f, 395.764038f, 824.387573f, 397.051819f);
+ pathB.cubicTo(822.57666f, 398.249756f, 820.582092f, 399.687286f, 818.860107f, 400.827332f);
+ pathB.lineTo(818.860107f, 392.707275f);
+ pathB.close();
+ pathB.moveTo(810.69812f, 391.096039f);
+ pathB.cubicTo(810.69812f, 391.096039f, 812.786499f, 394.093903f, 812.786499f, 394.965393f);
+ pathB.lineTo(812.786499f, 415.743713f);
+ pathB.cubicTo(812.786499f, 417.753265f, 811.881042f, 418.497986f, 810.974609f, 419.769806f);
+ pathB.cubicTo(813.948486f, 421.160431f, 815.437988f, 421.864197f, 818.404846f, 423.283783f);
+ pathB.cubicTo(819.948181f, 423.95462f, 822.417969f, 424.592529f, 823.937317f, 423.782928f);
+ pathB.cubicTo(827.905518f, 421.663544f, 831.53125f, 417.600525f, 832.255005f, 415.191681f);
+ pathB.cubicTo(833.882263f, 409.877808f, 823.095825f, 411.495026f, 823.119751f, 411.518982f);
+ pathB.cubicTo(823.119751f, 411.518982f, 832.000488f, 411.874359f, 830.537964f, 416.29776f);
+ pathB.cubicTo(829.888123f, 418.253418f, 827.278564f, 420.292908f, 825.385864f, 419.55719f);
+ pathB.cubicTo(821.14209f, 417.915985f, 818.861023f, 417.414856f, 818.861023f, 414.970032f);
+ pathB.lineTo(818.861023f, 403.096436f);
+ pathB.cubicTo(822.126404f, 399.132233f, 831.289673f, 395.897797f, 831.356567f, 395.657227f);
+ pathB.cubicTo(831.356567f, 395.657227f, 823.022888f, 387.594055f, 821.763062f, 387.476257f);
+ pathB.cubicTo(821.755066f, 387.47525f, 821.746094f, 387.47525f, 821.737061f, 387.47525f);
+ pathB.cubicTo(820.793701f, 387.47525f, 810.72406f, 390.967255f, 810.69812f, 391.096039f);
+ pathB.moveTo(624.254211f, 390.498077f);
+ pathB.cubicTo(625.252502f, 390.893402f, 627.708252f, 392.592468f, 629.796692f, 393.307251f);
+ pathB.cubicTo(627.978821f, 395.006317f, 625.980225f, 397.000916f, 624.254211f, 398.618134f);
+ pathB.lineTo(624.254211f, 390.498077f);
+ pathB.close();
+ pathB.moveTo(627.160217f, 384.460449f);
+ pathB.cubicTo(626.286743f, 384.51535f, 616.076233f, 390.993225f, 616.086243f, 391.141968f);
+ pathB.cubicTo(616.086243f, 391.141968f, 618.173645f, 393.561798f, 618.173645f, 394.437317f);
+ pathB.lineTo(618.173645f, 415.216614f);
+ pathB.cubicTo(618.173645f, 417.222168f, 617.265198f, 418.219482f, 616.355774f, 419.742859f);
+ pathB.cubicTo(619.331665f, 420.307892f, 620.824097f, 420.599396f, 623.802979f, 421.198364f);
+ pathB.cubicTo(625.346313f, 421.437958f, 627.818115f, 421.39801f, 629.342468f, 420.166138f);
+ pathB.cubicTo(633.340576f, 416.939667f, 636.982361f, 411.871368f, 637.714111f, 409.263855f);
+ pathB.cubicTo(639.348267f, 403.500732f, 628.508911f, 408.111816f, 628.52887f, 408.126801f);
+ pathB.cubicTo(628.52887f, 408.126801f, 637.468506f, 405.998444f, 635.985046f, 410.844147f);
+ pathB.cubicTo(635.332153f, 412.984467f, 632.705688f, 415.748718f, 630.801941f, 415.541077f);
+ pathB.cubicTo(626.537292f, 415.072876f, 624.257202f, 415.202667f, 624.257202f, 412.755859f);
+ pathB.cubicTo(624.257202f, 408.007019f, 624.255188f, 405.636078f, 624.255188f, 400.884247f);
+ pathB.cubicTo(627.525574f, 396.016602f, 636.801636f, 390.283447f, 636.801636f, 389.97995f);
+ pathB.cubicTo(636.801636f, 389.97995f, 628.360168f, 384.458435f, 627.18219f, 384.458435f);
+ pathB.cubicTo(627.174194f, 384.460449f, 627.167236f, 384.460449f, 627.160217f, 384.460449f);
+ pathB.moveTo(796.530396f, 416.438538f);
+ pathB.cubicTo(795.892517f, 416.365662f, 794.527832f, 415.589996f, 792.348572f, 414.036652f);
+ pathB.lineTo(792.348572f, 391.425476f);
+ pathB.cubicTo(792.348572f, 390.465118f, 792.530273f, 390.047852f, 792.89563f, 390.088776f);
+ pathB.cubicTo(793.075317f, 390.109741f, 793.3479f, 390.317383f, 793.804077f, 390.629852f);
+ pathB.cubicTo(795.113831f, 391.585205f, 795.768738f, 392.059387f, 797.077515f, 393.018738f);
+ pathB.cubicTo(797.983948f, 393.648651f, 798.348267f, 394.219666f, 798.348267f, 394.742767f);
+ pathB.lineTo(798.348267f, 413.253998f);
+ pathB.cubicTo(798.348267f, 415.391327f, 797.783264f, 416.451508f, 796.728088f, 416.451508f);
+ pathB.cubicTo(796.664185f, 416.4505f, 796.598267f, 416.446533f, 796.530396f, 416.438538f);
+ pathB.moveTo(795.165771f, 383.714722f);
+ pathB.cubicTo(794.022705f, 383.851471f, 783.959961f, 388.652252f, 783.880127f, 388.873871f);
+ pathB.cubicTo(783.880127f, 388.873871f, 785.054077f, 389.871155f, 785.522339f, 390.606873f);
+ pathB.cubicTo(786.000488f, 391.361603f, 786.246094f, 391.9935f, 786.246094f, 392.427765f);
+ pathB.lineTo(786.246094f, 411.987183f);
+ pathB.cubicTo(786.246094f, 413.733185f, 784.160645f, 416.428558f, 784.246521f, 416.759979f);
+ pathB.cubicTo(784.258484f, 416.79892f, 785.432495f, 417.14032f, 785.793823f, 417.350952f);
+ pathB.cubicTo(786.739258f, 417.937958f, 787.213379f, 418.228455f, 788.161804f, 418.821442f);
+ pathB.cubicTo(789.342773f, 419.554199f, 790.619568f, 419.956482f, 791.892395f, 420.098236f);
+ pathB.cubicTo(794.533813f, 420.390747f, 796.717102f, 419.337555f, 798.349304f, 416.999573f);
+ pathB.lineTo(798.349304f, 425.212463f);
+ pathB.cubicTo(797.94696f, 425.47702f, 797.750305f, 425.609772f, 797.356018f, 425.874329f);
+ pathB.cubicTo(795.259583f, 423.619202f, 792.806824f, 422.286499f, 789.985657f, 421.984009f);
+ pathB.cubicTo(785.157959f, 421.463898f, 780.409119f, 428.344086f, 780.423096f, 428.346069f);
+ pathB.cubicTo(780.423096f, 428.346069f, 783.340088f, 424.960907f, 785.889709f, 425.218445f);
+ pathB.cubicTo(789.25592f, 425.565857f, 793.166199f, 430.745972f, 793.805115f, 430.790894f);
+ pathB.cubicTo(793.940857f, 430.798889f, 795.918457f, 429.091797f, 798.454102f, 427.383728f);
+ pathB.cubicTo(801.049683f, 425.635742f, 804.230225f, 423.886749f, 806.619141f, 423.980591f);
+ pathB.cubicTo(805.621826f, 423.586243f, 805.048828f, 423.074127f, 804.804199f, 422.609924f);
+ pathB.cubicTo(804.616577f, 422.25354f, 804.616577f, 421.539764f, 804.616577f, 420.31488f);
+ pathB.cubicTo(804.623535f, 411.732605f, 804.623535f, 403.147339f, 804.623535f, 394.562073f);
+ pathB.cubicTo(804.623535f, 392.464691f, 805.970215f, 391.000183f, 805.984192f, 390.896362f);
+ pathB.cubicTo(805.984192f, 390.896362f, 796.785034f, 383.7117f, 795.219666f, 383.7117f);
+ pathB.cubicTo(795.19873f, 383.712708f, 795.181763f, 383.712708f, 795.165771f, 383.714722f);
+ pathB.moveTo(648.092285f, 387.883545f);
+ pathB.cubicTo(649.095581f, 388.312805f, 651.55835f, 390.099762f, 653.655701f, 390.884399f);
+ pathB.cubicTo(651.831848f, 392.522583f, 649.82428f, 394.447296f, 648.092285f, 396.003601f);
+ pathB.lineTo(648.092285f, 387.883545f);
+ pathB.close();
+ pathB.moveTo(651.009277f, 381.943756f);
+ pathB.cubicTo(650.147766f, 381.983704f, 639.893372f, 388.105164f, 639.899353f, 388.254913f);
+ pathB.cubicTo(639.899353f, 388.254913f, 641.987793f, 390.744659f, 641.987793f, 391.617157f);
+ pathB.lineTo(641.987793f, 412.399475f);
+ pathB.cubicTo(641.987793f, 414.409027f, 641.082336f, 415.369354f, 640.169861f, 416.864807f);
+ pathB.cubicTo(643.155762f, 417.53064f, 644.650208f, 417.87207f, 647.638062f, 418.573853f);
+ pathB.cubicTo(649.188416f, 418.865356f, 651.666138f, 418.908295f, 653.19751f, 417.725311f);
+ pathB.cubicTo(657.204651f, 414.633636f, 660.859375f, 409.690125f, 661.590088f, 407.106567f);
+ pathB.cubicTo(663.231262f, 401.397339f, 652.356934f, 405.644073f, 652.375916f, 405.663025f);
+ pathB.cubicTo(652.375916f, 405.663025f, 661.338562f, 403.835175f, 659.857056f, 408.632935f);
+ pathB.cubicTo(659.199219f, 410.748291f, 656.568726f, 413.424713f, 654.656982f, 413.151184f);
+ pathB.cubicTo(650.381348f, 412.536224f, 648.092285f, 412.591125f, 648.092285f, 410.146332f);
+ pathB.lineTo(648.092285f, 398.270721f);
+ pathB.cubicTo(651.374634f, 393.5159f, 660.66571f, 388.09021f, 660.674683f, 387.791718f);
+ pathB.cubicTo(660.674683f, 387.791718f, 652.188232f, 381.941772f, 651.022278f, 381.942749f);
+ pathB.cubicTo(651.01825f, 381.942749f, 651.013245f, 381.942749f, 651.009277f, 381.943756f);
+ pathB.moveTo(761.636353f, 385.965851f);
+ pathB.cubicTo(761.927856f, 386.056702f, 762.071594f, 386.098633f, 762.363098f, 386.189453f);
+ pathB.cubicTo(763.570007f, 386.938171f, 764.175964f, 387.311554f, 765.376892f, 388.066254f);
+ pathB.cubicTo(766.019775f, 388.546417f, 766.384155f, 389.184326f, 766.384155f, 390.147675f);
+ pathB.lineTo(766.384155f, 410.924011f);
+ pathB.cubicTo(766.384155f, 412.057037f, 765.836121f, 413.410736f, 764.559326f, 414.979034f);
+ pathB.cubicTo(765.911987f, 415.738739f, 766.579834f, 416.12207f, 767.934509f, 416.887756f);
+ pathB.cubicTo(769.029602f, 417.495728f, 770.944336f, 418.000854f, 771.85675f, 418.075714f);
+ pathB.cubicTo(772.58551f, 418.134613f, 773.413086f, 417.987854f, 773.950195f, 417.638458f);
+ pathB.cubicTo(776.583618f, 415.917419f, 778.332642f, 413.564453f, 778.237793f, 413.473633f);
+ pathB.cubicTo(778.237793f, 413.473633f, 776.507812f, 413.497559f, 775.596313f, 413.066315f);
+ pathB.cubicTo(774.866577f, 412.61908f, 774.497253f, 412.39447f, 773.771484f, 411.951233f);
+ pathB.cubicTo(772.947876f, 411.444092f, 772.493652f, 410.877075f, 772.493652f, 409.919708f);
+ pathB.lineTo(772.493652f, 390.013885f);
+ pathB.cubicTo(772.493652f, 388.618286f, 772.860046f, 387.949432f, 773.407104f, 387.995361f);
+ pathB.cubicTo(773.771484f, 388.026306f, 774.318542f, 388.509491f, 775.049316f, 389.09848f);
+ pathB.cubicTo(775.742065f, 389.646515f, 776.088501f, 389.923065f, 776.77533f, 390.470123f);
+ pathB.cubicTo(774.590088f, 392.45871f, 773.589783f, 394.385376f, 773.589783f, 396.395935f);
+ pathB.cubicTo(773.589783f, 400.673584f, 777.907349f, 401.008026f, 779.237122f, 398.292694f);
+ pathB.cubicTo(779.539551f, 397.684723f, 780.089661f, 396.027557f, 780.058716f, 396.01358f);
+ pathB.cubicTo(780.058716f, 396.01358f, 778.970581f, 396.694427f, 778.149963f, 396.618561f);
+ pathB.cubicTo(776.598633f, 396.4758f, 775.775024f, 395.709106f, 775.775024f, 394.13681f);
+ pathB.cubicTo(775.775024f, 392.042419f, 778.149963f, 389.103455f, 781.973389f, 385.892975f);
+ pathB.cubicTo(780.697571f, 385.06839f, 777.326416f, 381.676208f, 776.506775f, 381.719147f);
+ pathB.cubicTo(775.908813f, 381.747101f, 773.588806f, 384.868744f, 772.860046f, 385.506622f);
+ pathB.cubicTo(770.451172f, 383.664795f, 769.248291f, 382.749359f, 766.843384f, 380.929504f);
+ pathB.cubicTo(764.758972f, 382.934052f, 763.716736f, 383.940338f, 761.636353f, 385.965851f);
+ pathB.moveTo(672.996521f, 379.821411f);
+ pathB.cubicTo(672.123047f, 379.891266f, 669.7052f, 382.898132f, 668.887573f, 383.64682f);
+ pathB.cubicTo(665.239868f, 386.999084f, 663.41095f, 390.213562f, 663.41095f, 393.356171f);
+ pathB.cubicTo(663.41095f, 395.715118f, 664.439209f, 397.642792f, 666.785156f, 399.150208f);
+ pathB.cubicTo(669.702148f, 401.02002f, 672.547302f, 402.439575f, 674.545837f, 403.655487f);
+ pathB.cubicTo(676.261902f, 404.697693f, 677.105469f, 406.231049f, 677.105469f, 407.625671f);
+ pathB.cubicTo(677.105469f, 408.671875f, 676.651245f, 409.777954f, 675.825684f, 410.7453f);
+ pathB.cubicTo(675.12384f, 411.569885f, 674.538879f, 412.145905f, 673.997803f, 412.417419f);
+ pathB.cubicTo(673.38385f, 412.724915f, 672.080078f, 411.958221f, 670.166382f, 410.198242f);
+ pathB.cubicTo(668.113892f, 408.319458f, 667.062683f, 406.55249f, 667.062683f, 404.808502f);
+ pathB.cubicTo(667.062683f, 404.020844f, 667.701599f, 402.580322f, 667.701599f, 402.580322f);
+ pathB.cubicTo(667.701599f, 402.580322f, 661.773804f, 409.542358f, 661.951477f, 410.7453f);
+ pathB.cubicTo(662.13916f, 412.037079f, 663.368042f, 413.524536f, 665.60321f, 415.469208f);
+ pathB.cubicTo(667.791443f, 417.368927f, 669.261963f, 418.074738f, 669.983704f, 417.630493f);
+ pathB.cubicTo(672.412537f, 416.138062f, 675.369446f, 413.822021f, 678.385254f, 410.790222f);
+ pathB.cubicTo(680.485657f, 408.677856f, 681.587769f, 406.446686f, 681.587769f, 403.917023f);
+ pathB.cubicTo(681.587769f, 400.859283f, 680.007446f, 398.490356f, 676.923767f, 396.806244f);
+ pathB.cubicTo(673.540588f, 394.957428f, 671.257507f, 393.71756f, 670.351074f, 393.075653f);
+ pathB.cubicTo(668.434326f, 391.71698f, 667.518921f, 390.193604f, 667.518921f, 388.88385f);
+ pathB.cubicTo(667.518921f, 387.837646f, 668.101929f, 386.934204f, 669.25592f, 386.156525f);
+ pathB.cubicTo(669.796997f, 385.788147f, 671.085815f, 386.257355f, 672.997498f, 387.592072f);
+ pathB.cubicTo(674.966125f, 388.968689f, 676.104187f, 389.951019f, 676.284851f, 390.465118f);
+ pathB.cubicTo(678.186584f, 388.130127f, 679.136963f, 386.966125f, 681.035706f, 384.646118f);
+ pathB.cubicTo(678.244507f, 383.133728f, 674.247375f, 379.819397f, 673.044434f, 379.819397f);
+ pathB.cubicTo(673.027466f, 379.819397f, 673.011475f, 379.820404f, 672.996521f, 379.821411f);
+ pathB.moveTo(732.95459f, 384.60318f);
+ pathB.cubicTo(733.246094f, 384.680054f, 733.391846f, 384.720001f, 733.689331f, 384.794861f);
+ pathB.cubicTo(735.072937f, 385.500641f, 735.769714f, 385.856049f, 737.162354f, 386.563812f);
+ pathB.cubicTo(737.891113f, 386.938171f, 738.164612f, 387.642975f, 738.164612f, 388.6073f);
+ pathB.lineTo(738.164612f, 408.510132f);
+ pathB.cubicTo(738.164612f, 410.257141f, 737.709412f, 411.893341f, 736.064209f, 413.416718f);
+ pathB.cubicTo(737.635498f, 414.235321f, 738.419189f, 414.651611f, 739.991455f, 415.475189f);
+ pathB.cubicTo(740.997742f, 416.034241f, 742.186707f, 416.344696f, 743.098145f, 416.379639f);
+ pathB.cubicTo(743.830872f, 416.410583f, 744.476807f, 416.175964f, 745.019836f, 415.851532f);
+ pathB.cubicTo(746.476318f, 414.977051f, 748.58075f, 413.571442f, 749.225647f, 413.079285f);
+ pathB.cubicTo(751.012573f, 414.253296f, 751.907043f, 414.845276f, 753.69696f, 416.028229f);
+ pathB.cubicTo(754.703247f, 416.610229f, 755.706543f, 416.84082f, 756.528076f, 416.892761f);
+ pathB.cubicTo(757.259827f, 416.93866f, 757.996582f, 416.807892f, 758.537659f, 416.494446f);
+ pathB.cubicTo(760.814758f, 415.174713f, 762.185425f, 413.509552f, 762.552734f, 412.830719f);
+ pathB.cubicTo(761.637329f, 412.681976f, 759.633789f, 411.58786f, 759.263428f, 411.387207f);
+ pathB.cubicTo(758.607544f, 410.994873f, 758.279114f, 410.803223f, 757.621216f, 410.413879f);
+ pathB.cubicTo(756.983276f, 410.020538f, 756.616943f, 409.301788f, 756.616943f, 408.343445f);
+ pathB.lineTo(756.616943f, 388.351746f);
+ pathB.cubicTo(756.616943f, 387.387421f, 757.164978f, 386.548859f, 758.627502f, 385.067383f);
+ pathB.cubicTo(755.523804f, 383.05484f, 753.97052f, 382.057556f, 750.862854f, 380.078949f);
+ pathB.cubicTo(749.001038f, 382.112457f, 748.069641f, 383.130707f, 746.207825f, 385.174194f);
+ pathB.cubicTo(746.501343f, 385.292999f, 746.647095f, 385.353912f, 746.939575f, 385.472687f);
+ pathB.cubicTo(747.996765f, 386.183472f, 748.525879f, 386.538879f, 749.587036f, 387.257629f);
+ pathB.cubicTo(750.224915f, 387.724823f, 750.498474f, 388.351746f, 750.498474f, 389.223267f);
+ pathB.lineTo(750.498474f, 407.822327f);
+ pathB.cubicTo(750.498474f, 408.694824f, 750.339722f, 409.955658f, 749.951416f, 410.847137f);
+ pathB.cubicTo(749.550049f, 411.761566f, 749.039978f, 411.585876f, 748.487915f, 411.560913f);
+ pathB.cubicTo(747.393799f, 411.503998f, 746.385498f, 410.53067f, 745.473083f, 410.022552f);
+ pathB.cubicTo(744.760254f, 409.627228f, 744.380981f, 409.013275f, 744.380981f, 407.965088f);
+ pathB.lineTo(744.380981f, 386.840363f);
+ pathB.cubicTo(744.380981f, 385.791138f, 744.833191f, 384.763916f, 745.657776f, 383.839508f);
+ pathB.cubicTo(742.656921f, 382.101501f, 741.161499f, 381.234985f, 738.162659f, 379.525909f);
+ pathB.cubicTo(736.083191f, 381.548431f, 735.039978f, 382.562683f, 732.95459f, 384.60318f);
+ pathB.moveTo(692.546936f, 385.171204f);
+ pathB.cubicTo(693.552246f, 385.667358f, 696.018005f, 387.607025f, 698.122375f, 388.521454f);
+ pathB.cubicTo(696.293518f, 390.043854f, 694.281982f, 391.844757f, 692.546936f, 393.294281f);
+ pathB.lineTo(692.546936f, 385.171204f);
+ pathB.close();
+ pathB.moveTo(695.4729f, 379.417084f);
+ pathB.cubicTo(694.635376f, 379.426086f, 684.32605f, 384.880707f, 684.322083f, 385.025452f);
+ pathB.cubicTo(684.322083f, 385.025452f, 686.422485f, 387.645966f, 686.422485f, 388.521454f);
+ pathB.lineTo(686.422485f, 409.300781f);
+ pathB.cubicTo(686.422485f, 411.312347f, 685.51001f, 412.21579f, 684.595581f, 413.65033f);
+ pathB.cubicTo(687.592468f, 414.504852f, 689.089905f, 414.945099f, 692.088745f, 415.833557f);
+ pathB.cubicTo(693.645081f, 416.221893f, 696.128784f, 416.420563f, 697.667114f, 415.334412f);
+ pathB.cubicTo(701.67926f, 412.494293f, 705.344971f, 407.783386f, 706.077698f, 405.240753f);
+ pathB.cubicTo(707.721924f, 399.638367f, 696.822632f, 403.198273f, 696.845581f, 403.216248f);
+ pathB.cubicTo(696.845581f, 403.216248f, 705.825134f, 401.960388f, 704.337708f, 406.658325f);
+ pathB.cubicTo(703.683838f, 408.733765f, 701.044373f, 411.241455f, 699.129639f, 410.847137f);
+ pathB.cubicTo(694.843018f, 409.968628f, 692.545959f, 409.876801f, 692.545959f, 407.432983f);
+ pathB.lineTo(692.545959f, 395.563354f);
+ pathB.cubicTo(695.838318f, 391.012177f, 705.134338f, 386.160522f, 705.162292f, 385.873993f);
+ pathB.cubicTo(705.162292f, 385.873993f, 696.635925f, 379.416107f, 695.473938f, 379.417084f);
+ pathB.cubicTo(695.474915f, 379.417084f, 695.473938f, 379.417084f, 695.4729f, 379.417084f);
+ pathB.moveTo(570.463562f, 420.81601f);
+ pathB.lineTo(570.463562f, 402.922729f);
+ pathB.cubicTo(571.039551f, 402.800934f, 571.327087f, 402.743042f, 571.901123f, 402.625244f);
+ pathB.lineTo(571.901123f, 423.142029f);
+ pathB.cubicTo(570.911804f, 422.823578f, 570.463562f, 422.123779f, 570.463562f, 420.81601f);
+ pathB.moveTo(570.463562f, 384.062134f);
+ pathB.cubicTo(571.039551f, 384.149963f, 571.327087f, 384.198883f, 571.901123f, 384.290741f);
+ pathB.lineTo(571.901123f, 401.580048f);
+ pathB.cubicTo(571.327087f, 401.695862f, 571.039551f, 401.756744f, 570.463562f, 401.874542f);
+ pathB.lineTo(570.463562f, 384.062134f);
+ pathB.close();
+ pathB.moveTo(573.880676f, 376.556f);
+ pathB.cubicTo(572.483093f, 376.996246f, 561.476013f, 385.624451f, 561.482971f, 385.70929f);
+ pathB.cubicTo(561.482971f, 385.70929f, 563.637268f, 388.554413f, 563.637268f, 389.688446f);
+ pathB.lineTo(563.637268f, 398.423462f);
+ pathB.cubicTo(556.411682f, 399.838043f, 555.429382f, 404.307373f, 555.418396f, 405.679993f);
+ pathB.lineTo(555.418396f, 405.724915f);
+ pathB.cubicTo(555.42041f, 405.94455f, 555.448364f, 406.073334f, 555.477295f, 406.083313f);
+ pathB.cubicTo(555.477295f, 406.083313f, 558.070862f, 404.250458f, 563.637268f, 403.222229f);
+ pathB.lineTo(563.637268f, 404.797516f);
+ pathB.cubicTo(556.993713f, 406.233063f, 555.191772f, 412.494293f, 555.569153f, 412.614105f);
+ pathB.cubicTo(555.569153f, 412.614105f, 561.572815f, 410.21521f, 563.637268f, 409.598267f);
+ pathB.lineTo(563.637268f, 424.00354f);
+ pathB.cubicTo(563.637268f, 426.357483f, 563.36676f, 427.901855f, 562.291565f, 429.70874f);
+ pathB.cubicTo(565.448181f, 430.067139f, 567.028442f, 430.256805f, 570.192017f, 430.653137f);
+ pathB.cubicTo(571.99292f, 430.893707f, 574.782166f, 430.669098f, 576.403381f, 429.136719f);
+ pathB.cubicTo(580.960571f, 424.828125f, 586.135681f, 419.346527f, 586.135681f, 416.115082f);
+ pathB.lineTo(586.135681f, 406.511566f);
+ pathB.cubicTo(586.135681f, 405.377533f, 586.047791f, 404.608856f, 586.678711f, 403.271149f);
+ pathB.cubicTo(584.151062f, 404.98819f, 582.888245f, 405.851715f, 580.362549f, 407.587738f);
+ pathB.cubicTo(579.281433f, 408.320465f, 579.192566f, 409.2948f, 579.192566f, 410.955933f);
+ pathB.lineTo(579.192566f, 421.869202f);
+ pathB.cubicTo(579.192566f, 423.180969f, 577.746033f, 423.273804f, 577.392639f, 423.266815f);
+ pathB.cubicTo(575.636658f, 423.228882f, 574.153259f, 423.295776f, 573.071106f, 423.077148f);
+ pathB.lineTo(573.071106f, 384.663086f);
+ pathB.cubicTo(575.230408f, 385.379852f, 576.309509f, 385.742249f, 578.473816f, 386.473999f);
+ pathB.cubicTo(579.373291f, 386.996094f, 579.553955f, 387.490234f, 579.553955f, 388.013336f);
+ pathB.cubicTo(581.861023f, 384.848785f, 583.015991f, 383.267487f, 585.325073f, 380.114899f);
+ pathB.cubicTo(581.680298f, 379.229431f, 575.865295f, 376.520081f, 574.157227f, 376.521057f);
+ pathB.cubicTo(574.047424f, 376.522064f, 573.955566f, 376.533051f, 573.880676f, 376.556f);
+ pathB.moveTo(593.447083f, 375.096527f);
+ pathB.cubicTo(592.363953f, 375.804291f, 591.821899f, 376.772644f, 591.821899f, 377.908691f);
+ pathB.lineTo(591.821899f, 419.46933f);
+ pathB.cubicTo(591.821899f, 420.517517f, 591.187012f, 422.018951f, 589.921143f, 423.991577f);
+ pathB.cubicTo(591.2948f, 424.412842f, 591.982605f, 424.622467f, 593.354248f, 425.050751f);
+ pathB.cubicTo(594.53125f, 425.462036f, 595.525513f, 425.555878f, 596.427979f, 425.404144f);
+ pathB.cubicTo(597.150757f, 425.279358f, 597.785645f, 424.914978f, 598.326721f, 424.475739f);
+ pathB.cubicTo(600.935242f, 422.385315f, 602.846985f, 419.809753f, 602.759094f, 419.749847f);
+ pathB.cubicTo(602.759094f, 419.749847f, 601.582153f, 419.935516f, 600.59082f, 419.831696f);
+ pathB.cubicTo(600.0448f, 419.74585f, 599.774231f, 419.700928f, 599.233154f, 419.615082f);
+ pathB.cubicTo(598.416565f, 419.484314f, 597.965332f, 418.860382f, 597.965332f, 417.988861f);
+ pathB.lineTo(597.965332f, 396.857147f);
+ pathB.cubicTo(597.965332f, 395.376678f, 598.326721f, 394.617004f, 598.867798f, 394.528137f);
+ pathB.cubicTo(599.232178f, 394.466248f, 599.773254f, 394.731812f, 600.59082f, 395.124115f);
+ pathB.cubicTo(601.601074f, 395.589325f, 602.111206f, 395.819946f, 603.123474f, 396.288116f);
+ pathB.cubicTo(603.93811f, 396.686432f, 603.93512f, 397.38324f, 603.93512f, 398.169891f);
+ pathB.cubicTo(603.93512f, 405.971497f, 603.93512f, 413.768127f, 603.93811f, 421.569702f);
+ pathB.cubicTo(603.93811f, 425.325256f, 601.109924f, 430.634155f, 601.133911f, 430.656128f);
+ pathB.cubicTo(601.133911f, 430.656128f, 605.184937f, 427.222015f, 607.017822f, 424.414825f);
+ pathB.cubicTo(609.118164f, 421.201355f, 610.280212f, 417.987854f, 610.280212f, 415.109802f);
+ pathB.lineTo(610.280212f, 394.593048f);
+ pathB.cubicTo(610.280212f, 393.890228f, 610.823242f, 393.112579f, 611.728699f, 392.020447f);
+ pathB.cubicTo(608.827698f, 390.960266f, 604.000977f, 387.703857f, 602.759094f, 387.967407f);
+ pathB.cubicTo(602.120239f, 388.104187f, 599.957947f, 391.29071f, 597.965332f, 393.27829f);
+ pathB.lineTo(597.965332f, 374.422668f);
+ pathB.cubicTo(597.965332f, 373.461334f, 598.326721f, 372.440063f, 598.867798f, 371.567566f);
+ pathB.cubicTo(596.701538f, 372.96817f, 595.616394f, 373.677948f, 593.447083f, 375.096527f);
+ pathB.moveTo(718.054138f, 409.318756f);
+ pathB.cubicTo(717.461182f, 408.789673f, 716.867188f, 408.178711f, 716.867188f, 407.218353f);
+ pathB.lineTo(716.867188f, 387.053986f);
+ pathB.cubicTo(716.867188f, 385.305969f, 717.323425f, 385.566528f, 718.328674f, 386.013763f);
+ pathB.cubicTo(719.645386f, 386.859314f, 720.307251f, 387.284576f, 721.622009f, 388.135132f);
+ pathB.cubicTo(722.266907f, 388.4935f, 722.903809f, 388.934753f, 722.903809f, 389.721405f);
+ pathB.lineTo(722.903809f, 407.794373f);
+ pathB.cubicTo(722.903809f, 408.66687f, 722.746094f, 410.490753f, 722.259888f, 410.758301f);
+ pathB.cubicTo(722.125122f, 410.83017f, 721.950439f, 410.862122f, 721.746826f, 410.862122f);
+ pathB.cubicTo(720.655701f, 410.864105f, 718.747925f, 409.936707f, 718.054138f, 409.318756f);
+ pathB.moveTo(711.928711f, 364.782227f);
+ pathB.cubicTo(711.195923f, 365.134613f, 710.648865f, 365.834412f, 710.648865f, 366.794769f);
+ pathB.lineTo(710.648865f, 407.392059f);
+ pathB.cubicTo(710.648865f, 409.397614f, 708.519531f, 411.37323f, 708.547485f, 411.684692f);
+ pathB.cubicTo(708.550476f, 411.745605f, 711.838867f, 413.067322f, 713.849365f, 414.368073f);
+ pathB.cubicTo(717.766663f, 416.906738f, 720.162537f, 415.845551f, 722.354797f, 414.073608f);
+ pathB.cubicTo(724.059875f, 412.69397f, 726.55957f, 410.981903f, 730.675537f, 410.124359f);
+ pathB.cubicTo(729.75708f, 409.143066f, 729.213013f, 407.993042f, 729.213013f, 406.683289f);
+ pathB.cubicTo(729.213013f, 399.630402f, 729.209045f, 396.103455f, 729.209045f, 389.047546f);
+ pathB.cubicTo(729.209045f, 387.648956f, 730.577698f, 385.292023f, 730.583679f, 385.149261f);
+ pathB.cubicTo(730.583679f, 385.149261f, 720.888306f, 378.762207f, 719.609497f, 378.947906f);
+ pathB.cubicTo(719.275085f, 378.996826f, 717.872498f, 381.118164f, 716.868225f, 381.896851f);
+ pathB.lineTo(716.868225f, 365.046783f);
+ pathB.cubicTo(716.868225f, 363.740021f, 716.960083f, 363.043213f, 717.597961f, 362);
+ pathB.cubicTo(715.331848f, 363.104095f, 714.19873f, 363.657166f, 711.928711f, 364.782227f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpeverytechpro_blogspot_com100(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1074.29285f, 627.292786f);
+ path.quadTo(1074.58582f, 627, 1075, 627);
+ path.lineTo(1117, 627);
+ path.quadTo(1124.04163f, 627, 1129.02246f, 631.9776f);
+ path.quadTo(1134, 636.958374f, 1134, 644);
+ path.lineTo(1134, 645);
+ path.quadTo(1134, 652.041626f, 1129.02246f, 657.0224f);
+ path.quadTo(1124.04163f, 662, 1117, 662);
+ path.lineTo(1075, 662);
+ path.quadTo(1074.58582f, 662, 1074.29285f, 661.707214f);
+ path.quadTo(1074, 661.414185f, 1074, 661);
+ path.lineTo(1074, 628);
+ path.quadTo(1074, 627.585815f, 1074.29285f, 627.292786f);
+ path.close();
+ path.moveTo(1076, 629);
+ path.lineTo(1117, 629);
+ path.cubicTo(1125.2843f, 629, 1132, 635.715698f, 1132, 644);
+ path.lineTo(1132, 645);
+ path.cubicTo(1132, 653.284302f, 1125.2843f, 660, 1117, 660);
+ path.lineTo(1076, 660);
+ path.lineTo(1076, 629);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1074, 627);
+ pathB.lineTo(1075, 628);
+ pathB.lineTo(1116.5f, 644.5f);
+ pathB.lineTo(1134, 627);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpflite_com41(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(301.464081f, 424);
+ path.lineTo(296, 433.46405f);
+ path.lineTo(296, 433.810822f);
+ path.lineTo(303.25589f, 438);
+ path.lineTo(304.729736f, 438);
+ path.lineTo(311, 427.139557f);
+ path.lineTo(311, 426.305237f);
+ path.lineTo(307.007202f, 424);
+ path.lineTo(301.464081f, 424);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(302.849854f, 421.599762f);
+ pathB.lineTo(311.510101f, 426.599762f);
+ pathB.lineTo(304.510101f, 438.724121f);
+ pathB.lineTo(295.849854f, 433.724121f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpilkoora_com37(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(818, 157);
+ path.cubicTo(818, 148.715729f, 824.715698f, 142, 833, 142);
+ path.lineTo(909, 142);
+ path.lineTo(909, 143);
+ path.lineTo(833, 143);
+ path.cubicTo(825.268005f, 143, 819, 149.268005f, 819, 157);
+ path.lineTo(819, 926);
+ path.lineTo(818, 926);
+ path.lineTo(818, 157);
+ path.close();
+ path.moveTo(1184, 926);
+ path.lineTo(1185, 926);
+ path.lineTo(1185, 157);
+ path.cubicTo(1185, 148.715729f, 1178.2843f, 142, 1170, 142);
+ path.lineTo(1093, 142);
+ path.lineTo(1093, 143);
+ path.lineTo(1170, 143);
+ path.cubicTo(1177.73193f, 143, 1184, 149.268005f, 1184, 157);
+ path.lineTo(1184, 926);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1185, 142);
+ pathB.lineTo(1001.5f, 325.5f);
+ pathB.lineTo(1001.5f, 782.5f);
+ pathB.lineTo(1185, 966);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpmm4everfriends_com43(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(540.74231f, 215.922546f);
+ path.cubicTo(540.893127f, 215.391159f, 541.443909f, 215.090134f, 541.972473f, 215.250168f);
+ path.lineTo(581.213318f, 227.131104f);
+ path.cubicTo(581.741882f, 227.291153f, 582.048157f, 227.851654f, 581.897339f, 228.383041f);
+ path.lineTo(576.708923f, 246.663925f);
+ path.cubicTo(576.558167f, 247.195297f, 576.007324f, 247.496338f, 575.47876f, 247.336288f);
+ path.lineTo(536.237915f, 235.455353f);
+ path.cubicTo(535.709351f, 235.295319f, 535.403137f, 234.734802f, 535.553894f, 234.20343f);
+ path.lineTo(540.74231f, 215.922546f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(541.015381f, 214.960388f);
+ pathB.lineTo(582.17041f, 227.420883f);
+ pathB.lineTo(576.435852f, 247.626068f);
+ pathB.lineTo(535.280823f, 235.165573f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpmtrk_uz27(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(33, 787);
+ path.lineTo(33, 412);
+ path.lineTo(1233, 412);
+ path.lineTo(1233, 787);
+ path.quadTo(1233, 793.213196f, 1228.60803f, 797.607971f);
+ path.quadTo(1224.21326f, 802, 1218, 802);
+ path.lineTo(48, 802);
+ path.quadTo(41.7867966f, 802, 37.3919983f, 797.607971f);
+ path.quadTo(33, 793.213196f, 33, 787);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(33, 412);
+ pathB.lineTo(1233, 412);
+ pathB.lineTo(1233, 787);
+ pathB.quadTo(1233, 793.213196f, 1228.60791f, 797.608032f);
+ pathB.quadTo(1224.21313f, 802, 1218, 802);
+ pathB.lineTo(48, 802);
+ pathB.quadTo(41.7867432f, 802, 37.3919678f, 797.608032f);
+ pathB.quadTo(33, 793.213196f, 33, 787);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpfrauen_magazin_com83(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(808, 886);
+ path.cubicTo(805.581055f, 886, 803.563293f, 887.717773f, 803.100037f, 890);
+ path.lineTo(1122.90002f, 890);
+ path.cubicTo(1122.43677f, 887.717773f, 1120.41895f, 886, 1118, 886);
+ path.lineTo(808, 886);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(808, 886);
+ pathB.lineTo(1118, 886);
+ pathB.cubicTo(1120.76147f, 886, 1123, 888.238586f, 1123, 891);
+ pathB.lineTo(1123, 1521);
+ pathB.cubicTo(1123, 1523.20911f, 1120.76147f, 1525, 1118, 1525);
+ pathB.lineTo(808, 1525);
+ pathB.cubicTo(805.238586f, 1525, 803, 1523.20911f, 803, 1521);
+ pathB.lineTo(803, 891);
+ pathB.cubicTo(803, 888.238586f, 805.238586f, 886, 808, 886);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpi_gino_com16(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(184, 734);
+ path.quadTo(133.051727f, 734, 97.0258636f, 770.025879f);
+ path.quadTo(61, 806.051758f, 61, 857);
+ path.quadTo(61, 895.835083f, 81.9317017f, 926);
+ path.lineTo(286.068298f, 926);
+ path.quadTo(307, 895.835083f, 307, 857);
+ path.quadTo(307, 806.051758f, 270.974121f, 770.025879f);
+ path.quadTo(234.948273f, 734, 184, 734);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(185, 734);
+ pathB.cubicTo(252.93103f, 734, 308, 789.06897f, 308, 857);
+ pathB.cubicTo(308, 924.93103f, 252.93103f, 980, 185, 980);
+ pathB.lineTo(184, 980);
+ pathB.cubicTo(116.068977f, 980, 61, 924.93103f, 61, 857);
+ pathB.cubicTo(61, 789.06897f, 116.068977f, 734, 184, 734);
+ pathB.lineTo(185, 734);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skppchappy_com_au102(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(363, 493);
+ path.cubicTo(360.790863f, 493, 359, 494.790863f, 359, 497);
+ path.lineTo(359, 656);
+ path.cubicTo(359, 658.209106f, 360.790863f, 660, 363, 660);
+ path.lineTo(623.001709f, 660);
+ path.cubicTo(624.657776f, 659.999023f, 626, 658.65625f, 626, 657);
+ path.lineTo(626, 496);
+ path.cubicTo(626, 494.343872f, 624.657959f, 493.00116f, 623.002075f, 493);
+ path.lineTo(363, 493);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(362, 494);
+ pathB.lineTo(623, 494);
+ pathB.cubicTo(624.65686f, 494, 626, 494.895416f, 626, 496);
+ pathB.lineTo(626, 657);
+ pathB.cubicTo(626, 658.65686f, 624.65686f, 660, 623, 660);
+ pathB.lineTo(362, 660);
+ pathB.cubicTo(360.34314f, 660, 359, 658.65686f, 359, 657);
+ pathB.lineTo(359, 496);
+ pathB.cubicTo(359, 494.895416f, 360.34314f, 494, 362, 494);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpsciality_com161(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(656, 728);
+ path.cubicTo(653.790833f, 728, 652, 729.790833f, 652, 732);
+ path.lineTo(652, 789);
+ path.cubicTo(652, 791.209106f, 653.790833f, 793, 656, 793);
+ path.lineTo(769.001282f, 793);
+ path.cubicTo(770.657532f, 792.999268f, 772, 791.656433f, 772, 790);
+ path.lineTo(772, 731);
+ path.cubicTo(772, 729.34314f, 770.65686f, 728, 769, 728);
+ path.lineTo(656, 728);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(655, 729);
+ pathB.lineTo(769, 729);
+ pathB.cubicTo(770.65686f, 729, 772, 729.895447f, 772, 731);
+ pathB.lineTo(772, 790);
+ pathB.cubicTo(772, 791.65686f, 770.65686f, 793, 769, 793);
+ pathB.lineTo(655, 793);
+ pathB.cubicTo(653.34314f, 793, 652, 791.65686f, 652, 790);
+ pathB.lineTo(652, 731);
+ pathB.cubicTo(652, 729.895447f, 653.34314f, 729, 655, 729);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpsudoestenegocios_com186(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 495);
+ path.lineTo(1.23685242e-14f, 293);
+ path.lineTo(44, 293);
+ path.quadTo(45.6568527f, 293, 46.8288002f, 294.171204f);
+ path.quadTo(48, 295.34314f, 48, 297);
+ path.lineTo(48, 491);
+ path.quadTo(48, 492.65686f, 46.8288002f, 493.828796f);
+ path.quadTo(45.6568527f, 495, 44, 495);
+ path.lineTo(0, 495);
+ path.close();
+ path.moveTo(1, 294);
+ path.lineTo(44, 294);
+ path.cubicTo(45.6568565f, 294, 47, 295.34314f, 47, 297);
+ path.lineTo(47, 491);
+ path.cubicTo(47, 492.65686f, 45.6568565f, 494, 44, 494);
+ path.lineTo(1, 494);
+ path.lineTo(1, 294);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(48, 495);
+ pathB.lineTo(24, 471);
+ pathB.lineTo(24, 317);
+ pathB.lineTo(48, 293);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpthesuburbanite_com213(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(863.439026f, 692);
+ path.lineTo(863.283264f, 692);
+ path.lineTo(802, 708.420837f);
+ path.lineTo(802, 718.773621f);
+ path.lineTo(866, 701.624817f);
+ path.lineTo(866, 701.557922f);
+ path.lineTo(863.439026f, 692);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(783.256775f, 713.443054f);
+ pathB.lineTo(863.428589f, 691.96106f);
+ pathB.lineTo(866.016724f, 701.620361f);
+ pathB.lineTo(785.84491f, 723.102356f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skphostloco_com11(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(6.66133815e-16f, 648);
+ path.lineTo(25.8522835f, 648);
+ path.quadTo(27.5087376f, 647.999634f, 28.6807098f, 646.82843f);
+ path.quadTo(29.8518829f, 645.656433f, 29.8522835f, 644);
+ path.lineTo(29.8522835f, 467);
+ path.quadTo(29.8518829f, 465.343536f, 28.6807098f, 464.17157f);
+ path.quadTo(27.5087376f, 463.000397f, 25.8522835f, 463);
+ path.lineTo(2.22044605e-16f, 463);
+ path.lineTo(6.66133815e-16f, 648);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0, 463);
+ pathB.lineTo(30, 463);
+ pathB.lineTo(30, 648);
+ pathB.lineTo(0, 648);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpsergeychunkevich_com8(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 926);
+ path.lineTo(0, 0);
+ path.lineTo(1265, 0);
+ path.lineTo(1265, 926);
+ path.lineTo(0, 926);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(37, 374);
+ pathB.lineTo(37, 535);
+ pathB.cubicTo(37, 536.65686f, 35.6568565f, 538, 34, 538);
+ pathB.lineTo(1.02866934e-14f, 538);
+ pathB.lineTo(6.12303177e-17f, 371);
+ pathB.lineTo(34, 371);
+ pathB.cubicTo(35.6568565f, 371, 37, 372.34314f, 37, 374);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skptracksflow_com9(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(16, 56);
+ path.lineTo(32, 56);
+ path.lineTo(32, 72);
+ path.lineTo(16, 72);
+ path.lineTo(16, 56);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(31.65625f, 70.0555649f);
+ pathB.lineTo(31.65625f, 70.0554962f);
+ pathB.lineTo(26.9727192f, 65.3615341f);
+ pathB.cubicTo(27.6210003f, 64.4029694f, 28.0048752f, 63.2470932f, 28.0048752f, 62.0027809f);
+ pathB.cubicTo(28.0048752f, 58.6875305f, 25.3199062f, 56, 22.0046558f, 56);
+ pathB.cubicTo(18.6894073f, 56, 16.0031872f, 58.6875305f, 16.0031872f, 62.0027809f);
+ pathB.cubicTo(16.0031872f, 65.3180008f, 18.6913433f, 68.0055618f, 22.0066261f, 68.0055618f);
+ pathB.cubicTo(23.2509995f, 68.0055618f, 24.4072189f, 67.6187515f, 25.3657818f, 66.9704056f);
+ pathB.lineTo(30.0599365f, 71.65625f);
+ pathB.lineTo(30.0600014f, 71.65625f);
+ pathB.cubicTo(30.2668133f, 71.875f, 30.5524693f, 71.9992828f, 30.868f, 71.9992828f);
+ pathB.cubicTo(31.4994049f, 71.9992828f, 32.0014687f, 71.4909363f, 32.0014687f, 70.8595276f);
+ pathB.cubicTo(32.0015335f, 70.5439072f, 31.875f, 70.2623444f, 31.65625f, 70.0555649f);
+ pathB.close();
+ pathB.moveTo(18.0054054f, 62.0027809f);
+ pathB.cubicTo(18.0054054f, 59.7925949f, 19.7970943f, 58.0009079f, 22.0072823f, 58.0009079f);
+ pathB.cubicTo(24.2174377f, 58.0009079f, 26.0091248f, 59.7925949f, 26.0091248f, 62.0027809f);
+ pathB.cubicTo(26.0091248f, 64.2129364f, 24.2174377f, 66.0046234f, 22.0072803f, 66.0046234f);
+ pathB.cubicTo(19.7970943f, 66.0045929f, 18.0054054f, 64.2129059f, 18.0054054f, 62.0027809f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpautobutler_dk29(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 926);
+ path.lineTo(0, 0);
+ path.lineTo(1265, 0);
+ path.lineTo(1265, 926);
+ path.lineTo(0, 926);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(21, 162);
+ pathB.lineTo(21, 301);
+ pathB.lineTo(8.57224448e-15f, 301);
+ pathB.lineTo(6.12303177e-17f, 162);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skponlinecollege_org144(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(179, 407);
+ path.cubicTo(177.34314f, 407, 176, 408.34314f, 176, 410);
+ path.lineTo(176, 436);
+ path.cubicTo(176, 437.65686f, 177.34314f, 439, 179, 439);
+ path.lineTo(337.002289f, 439);
+ path.cubicTo(338.105835f, 438.998779f, 339, 438.103821f, 339, 437);
+ path.lineTo(339, 409);
+ path.cubicTo(339, 407.896362f, 338.10611f, 407.001526f, 337.002838f, 407);
+ path.lineTo(179, 407);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(179, 408);
+ pathB.lineTo(337, 408);
+ pathB.cubicTo(338.65686f, 408, 340, 408.895416f, 340, 410);
+ pathB.lineTo(340, 436);
+ pathB.cubicTo(340, 437.65686f, 338.65686f, 439, 337, 439);
+ pathB.lineTo(179, 439);
+ pathB.cubicTo(177.895432f, 439, 177, 437.65686f, 177, 436);
+ pathB.lineTo(177, 410);
+ pathB.cubicTo(177, 408.895416f, 177.895432f, 408, 179, 408);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpnational_com_au81(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(807, 817);
+ path.quadTo(806.585876f, 817.000122f, 806.292908f, 817.292908f);
+ path.quadTo(806.000122f, 817.585876f, 806, 818);
+ path.lineTo(806, 881);
+ path.lineTo(1111, 881);
+ path.lineTo(1111, 818);
+ path.quadTo(1110.99988f, 817.585876f, 1110.70715f, 817.292908f);
+ path.quadTo(1110.41406f, 817.000122f, 1110, 817);
+ path.lineTo(807, 817);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(807, 817);
+ pathB.lineTo(1110, 817);
+ pathB.cubicTo(1110.55225f, 817, 1111, 817.447693f, 1111, 818);
+ pathB.lineTo(1111, 880);
+ pathB.lineTo(806, 880);
+ pathB.lineTo(806, 818);
+ pathB.cubicTo(806, 817.447693f, 806.447693f, 817, 807, 817);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skprentacheat_com30(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(967, 263);
+ path.quadTo(966.585876f, 263.000092f, 966.292908f, 263.292908f);
+ path.quadTo(966.000122f, 263.585876f, 966, 264);
+ path.lineTo(966, 301);
+ path.lineTo(1214, 301);
+ path.lineTo(1214, 264);
+ path.quadTo(1213.99988f, 263.585876f, 1213.70715f, 263.292908f);
+ path.quadTo(1213.41406f, 263.000092f, 1213, 263);
+ path.lineTo(967, 263);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(967, 263);
+ pathB.lineTo(1213, 263);
+ pathB.cubicTo(1213.55225f, 263, 1214, 263.447723f, 1214, 264);
+ pathB.lineTo(1214, 300);
+ pathB.lineTo(966, 300);
+ pathB.lineTo(966, 264);
+ pathB.cubicTo(966, 263.447723f, 966.447693f, 263, 967, 263);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpbreakmystyle_com10(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(271.032867f, -5.32907052e-15f);
+ path.lineTo(56.9671326f, -5.16253706e-15f);
+ path.quadTo(52.7835083f, 3.69968891f, 48.7416f, 7.74160004f);
+ path.quadTo(1, 55.4831848f, 1, 123);
+ path.quadTo(1, 190.516815f, 48.7416f, 238.258392f);
+ path.quadTo(96.4831848f, 286, 164, 286);
+ path.quadTo(231.516815f, 286, 279.258392f, 238.258392f);
+ path.quadTo(327, 190.516815f, 327, 123);
+ path.quadTo(327, 55.4831848f, 279.258392f, 7.74160004f);
+ path.quadTo(275.216431f, 3.69964004f, 271.032867f, -5.32907052e-15f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(327, 123);
+ pathB.quadTo(327, 190.516815f, 279.258392f, 238.258392f);
+ pathB.quadTo(231.516815f, 286, 164, 286);
+ pathB.quadTo(96.4831848f, 286, 48.7416f, 238.258392f);
+ pathB.quadTo(1, 190.516815f, 1, 123);
+ pathB.quadTo(1, 55.4831848f, 48.7416f, 7.74160004f);
+ pathB.quadTo(96.4831848f, -40, 164, -40);
+ pathB.quadTo(231.516815f, -40, 279.258392f, 7.74160004f);
+ pathB.quadTo(327, 55.4831848f, 327, 123);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpsd_graphic_net104(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(475.421448f, 836.985962f);
+ path.lineTo(461.280975f, 841.990662f);
+ path.cubicTo(466.80899f, 857.609802f, 458.62854f, 874.752991f, 443.009399f, 880.281006f);
+ path.cubicTo(435.199829f, 883.044983f, 427.009247f, 882.381897f, 420.080048f, 879.075378f);
+ path.lineTo(413.620056f, 892.613037f);
+ path.quadTo(430.419983f, 900.629761f, 447.96701f, 894.43811f);
+ path.quadTo(448.00708f, 894.42395f, 448.014038f, 894.421509f);
+ path.quadTo(448.043976f, 894.410889f, 448.061066f, 894.404846f);
+ path.quadTo(465.596313f, 888.179932f, 473.613037f, 871.379944f);
+ path.quadTo(477.351227f, 863.546143f, 478, 855.549866f);
+ path.lineTo(478, 848.804321f);
+ path.quadTo(477.528076f, 842.93811f, 475.421448f, 836.985962f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(405.592621f, 909.435547f);
+ pathB.lineTo(390.578583f, 867.014099f);
+ pathB.lineTo(433, 852.000061f);
+ pathB.lineTo(490.435486f, 879.40741f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+/* this cubic/quad pair
+ c = 430,280 430,278.895416 473.876068,278 528,278
+ q = 430,280 430.009796,277.101196 458.703552,275.050262
+ only intersect at the shared point (430,280)
+ they sort backwards because the tangent from pt[0] to control pt[1]
+ c' = (0.00000000000000000, -1.1045837402343750)
+ q' = (0.0097961425781250000, -2.8988037109375000)
+ suggests that the quad is counterclockwise of the cubic, when the reverse is true
+ the angle code is fooled because the control pt[1] of both the quad and cubic
+ is far away from cubic cntl [2] and quad pt [2].
+ Maybe in angle setup, this instability can be detected to suppress sorting on the initial tangent
+ Or the error term can be passed to NearRay that is magnified by the distance from the next ctrl?
+ */
+static void skpnaoxrane_ru23(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(458.703552f, 275.050262f);
+ path.quadTo(487.41687f, 273.000702f, 528, 273);
+ path.lineTo(529, 273);
+ path.quadTo(530.242371f, 273.000305f, 531.121338f, 273.878693f);
+ path.quadTo(531.999695f, 274.75766f, 532, 276);
+ path.lineTo(532, 378);
+ path.quadTo(531.990173f, 380.898804f, 503.296448f, 382.949738f);
+ path.quadTo(474.58313f, 384.999298f, 434, 385);
+ path.lineTo(433, 385);
+ path.quadTo(431.75766f, 384.999695f, 430.878693f, 384.121307f);
+ path.quadTo(430.000305f, 383.24234f, 430, 382);
+ path.lineTo(430, 280);
+ path.quadTo(430.009796f, 277.101196f, 458.703552f, 275.050262f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(528, 278);
+ pathB.lineTo(529, 278);
+ pathB.cubicTo(530.65686f, 278, 532, 278, 532, 278);
+ pathB.lineTo(532, 378);
+ pathB.cubicTo(532, 379.104584f, 488.123932f, 380, 434, 380);
+ pathB.lineTo(433, 380);
+ pathB.cubicTo(431.34314f, 380, 430, 380, 430, 380);
+ pathB.lineTo(430, 280);
+ pathB.cubicTo(430, 278.895416f, 473.876068f, 278, 528, 278);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+/* didn't investigate thoroughly, but looks to be missorting quad and cubic
+ {{468.507751,560.724426}, {467.275146,552.856262}, {465.84668,547.288391}}
+ {{463.779907,542.671143}, {464.829529,542.672974}, {466.946289,550.755676}, {468.507751,560.724426}}
+ decision maker is case 14 leftLessThanRight
+ */
+static void skptcmevents_org23(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(465.503998f, 546);
+ path.lineTo(347, 546);
+ path.lineTo(347, 632);
+ path.lineTo(469.104248f, 632);
+ path.quadTo(470.79007f, 627.638672f, 471.833496f, 621.036255f);
+ path.quadTo(474.902588f, 601.562866f, 470.591064f, 574.024353f);
+ path.lineTo(468.507751f, 560.724426f);
+ path.quadTo(467.275146f, 552.856262f, 465.84668f, 547.288391f);
+ path.quadTo(465.670349f, 546.601501f, 465.503998f, 546);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(363.052246f, 542.495361f);
+ pathB.lineTo(463.779907f, 542.671143f);
+ pathB.cubicTo(464.829529f, 542.672974f, 466.946289f, 550.755676f, 468.507751f, 560.724426f);
+ pathB.lineTo(470.591064f, 574.024353f);
+ pathB.cubicTo(476.26178f, 610.226624f, 471.498932f, 639.557922f, 459.953003f, 639.537781f);
+ pathB.lineTo(368.727936f, 639.378601f);
+ pathB.cubicTo(351.933868f, 639.349304f, 337.053741f, 631.244324f, 335.492249f, 621.275574f);
+ pathB.lineTo(325.968597f, 560.475708f);
+ pathB.cubicTo(324.407104f, 550.506958f, 341.01001f, 542.456909f, 363.052246f, 542.495361f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpredbullskatearcade_es16(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(936.765625f, 458.965302f);
+ path.cubicTo(937.028442f, 453.863251f, 933.145813f, 449.864502f, 928.093445f, 450.033905f);
+ path.lineTo(661.882263f, 458.958862f);
+ path.lineTo(661.875366f, 458.959106f);
+ path.cubicTo(656.828369f, 459.13205f, 652.525085f, 463.399719f, 652.258545f, 468.496124f);
+ path.lineTo(652.258179f, 468.503662f);
+ path.lineTo(649.021729f, 531.322754f);
+ path.cubicTo(648.75885f, 536.424805f, 652.641479f, 540.423523f, 657.693848f, 540.25415f);
+ path.lineTo(923.905029f, 531.329163f);
+ path.cubicTo(928.955017f, 531.159851f, 933.262268f, 526.890442f, 933.528809f, 521.791565f);
+ path.lineTo(933.529175f, 521.784363f);
+ path.lineTo(936.765625f, 458.965302f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(661.882263f, 458.958862f);
+ pathB.lineTo(928.093445f, 450.033905f);
+ pathB.cubicTo(929.103882f, 450, 929.709961f, 454.108612f, 929.447144f, 459.210663f);
+ pathB.lineTo(926.210693f, 522.029724f);
+ pathB.cubicTo(926.079224f, 524.58075f, 925.153442f, 526.676208f, 924.143066f, 526.710083f);
+ pathB.lineTo(657.931885f, 535.635071f);
+ pathB.cubicTo(652.879456f, 535.804443f, 648.890259f, 533.873779f, 649.021729f, 531.322754f);
+ pathB.lineTo(652.258179f, 468.503662f);
+ pathB.cubicTo(652.520996f, 463.401611f, 656.829834f, 459.128235f, 661.882263f, 458.958862f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpfinanzasdigital_com9(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(156, 126);
+ path.quadTo(154.343552f, 126.000397f, 153.17157f, 127.17157f);
+ path.quadTo(152.000397f, 128.343552f, 152, 130);
+ path.lineTo(152, 174);
+ path.lineTo(1114, 174);
+ path.lineTo(1114, 130);
+ path.quadTo(1113.99963f, 128.343552f, 1112.82837f, 127.17157f);
+ path.quadTo(1111.65649f, 126.000397f, 1110, 126);
+ path.lineTo(156, 126);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(156, 126);
+ pathB.lineTo(1110, 126);
+ pathB.cubicTo(1111.65686f, 126, 1113, 127.790863f, 1113, 130);
+ pathB.lineTo(1113, 174);
+ pathB.lineTo(153, 174);
+ pathB.lineTo(153, 130);
+ pathB.cubicTo(153, 127.790863f, 154.34314f, 126, 156, 126);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skppartainasdemo250_org56(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(182.000015f, 645);
+ path.lineTo(182, 640);
+ path.cubicTo(174.322327f, 640, 166.644669f, 637.071045f, 160.786804f, 631.213196f);
+ path.cubicTo(149.071075f, 619.497437f, 149.071075f, 600.502563f, 160.786804f, 588.786804f);
+ path.lineTo(157.251266f, 585.251221f);
+ path.quadTo(147, 595.502502f, 147.000015f, 610);
+ path.quadTo(147, 624.482605f, 157.230255f, 634.727722f);
+ path.quadTo(157.251251f, 634.748779f, 157.251282f, 634.748779f);
+ path.quadTo(157.282852f, 634.780334f, 157.272263f, 634.769775f);
+ path.quadTo(167.517334f, 645, 182.000015f, 645);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(182, 659.497498f);
+ pathB.lineTo(206.748749f, 634.748718f);
+ pathB.lineTo(182.000015f, 610);
+ pathB.lineTo(132.502533f, 610);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpmlk_com326(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(154, 670);
+ path.cubicTo(151.238571f, 670, 149, 672.238586f, 149, 675);
+ path.lineTo(149, 710.001465f);
+ path.cubicTo(149.000809f, 712.209961f, 150.791367f, 714, 153, 714);
+ path.lineTo(189, 714);
+ path.cubicTo(191.209137f, 714, 193, 712.209167f, 193, 710);
+ path.lineTo(193, 675);
+ path.cubicTo(193, 672.238586f, 190.761429f, 670, 188, 670);
+ path.lineTo(154, 670);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(154, 671);
+ pathB.lineTo(188, 671);
+ pathB.cubicTo(190.761429f, 671, 193, 672.790833f, 193, 675);
+ pathB.lineTo(193, 710);
+ pathB.cubicTo(193, 712.761414f, 190.761429f, 715, 188, 715);
+ pathB.lineTo(154, 715);
+ pathB.cubicTo(151.238571f, 715, 149, 712.761414f, 149, 710);
+ pathB.lineTo(149, 675);
+ pathB.cubicTo(149, 672.790833f, 151.238571f, 671, 154, 671);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpcyclist_friends_gr52(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(50, 182);
+ path.lineTo(1215, 182);
+ path.lineTo(1215, 202);
+ path.quadTo(1214.99951f, 204.070572f, 1213.53552f, 205.535538f);
+ path.quadTo(1212.07056f, 206.999496f, 1210, 207);
+ path.lineTo(55, 207);
+ path.quadTo(52.9294319f, 206.999496f, 51.4644661f, 205.535538f);
+ path.quadTo(50.0004997f, 204.070572f, 50, 202);
+ path.lineTo(50, 182);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(50, 183);
+ pathB.lineTo(1215, 183);
+ pathB.lineTo(1215, 202);
+ pathB.cubicTo(1215, 204.761429f, 1212.76147f, 207, 1210, 207);
+ pathB.lineTo(55, 207);
+ pathB.cubicTo(52.238575f, 207, 50, 204.761429f, 50, 202);
+ pathB.lineTo(50, 183);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+/* cubic ends just above opp line */
+static void skpwww_fj_p_com_22(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(172, 201);
+ path.lineTo(172, 202);
+ path.lineTo(220, 202);
+ path.cubicTo(221.65686f, 202, 223, 200.65686f, 223, 199);
+ path.cubicTo(223, 200.104568f, 221.65686f, 201, 220, 201);
+ path.lineTo(172, 201);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(161, 202);
+ pathB.lineTo(161, 199);
+ pathB.lineTo(223, 199.000015f);
+ pathB.lineTo(223, 202);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// pair of lines are not quite coincident, so sorting line/cubic fails (i think)
+static void skpwww_lavoixdunord_fr_11(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(806, 57);
+ path.cubicTo(806, 55.3431473f, 807.34314f, 54, 809, 54);
+ path.lineTo(930, 54);
+ path.cubicTo(931.65686f, 54, 933, 55.3431473f, 933, 57);
+ path.lineTo(933, 91);
+ path.cubicTo(933, 92.6568527f, 931.65686f, 94, 930, 94);
+ path.lineTo(809, 94);
+ path.cubicTo(807.34314f, 94, 806, 92.6568527f, 806, 91);
+ path.lineTo(806, 57);
+ path.close();
+ path.moveTo(808, 58);
+ path.cubicTo(808, 56.8954315f, 808.895447f, 56, 810, 56);
+ path.lineTo(929, 56);
+ path.cubicTo(930.104553f, 56, 931, 56.8954315f, 931, 58);
+ path.lineTo(931, 90);
+ path.cubicTo(931, 91.1045685f, 930.104553f, 92, 929, 92);
+ path.lineTo(810, 92);
+ path.cubicTo(808.895447f, 92, 808, 91.1045685f, 808, 90);
+ path.lineTo(808, 58);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(806, 54);
+ pathB.lineTo(808, 56);
+ pathB.lineTo(935.02002f, 56.0200005f);
+ pathB.lineTo(933, 54);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// pair of curves have nearly the same initial tangent but are sorting by
+// that alone sorts them incorrectly. Need to detect that tangents are nearly
+// identical and not reliable by themselves
+static void skppptv_com_62(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(173, 5342);
+ path.quadTo(171.343536f, 5342.00049f, 170.17157f, 5343.17139f);
+ path.quadTo(169.000397f, 5344.34375f, 169, 5346);
+ path.lineTo(169, 5372);
+ path.lineTo(234, 5372);
+ path.lineTo(234, 5346);
+ path.quadTo(233.999603f, 5344.34375f, 232.82843f, 5343.17139f);
+ path.quadTo(231.656464f, 5342.00049f, 230, 5342);
+ path.lineTo(173, 5342);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(173, 5342);
+ pathB.lineTo(230, 5342);
+ pathB.cubicTo(231.65686f, 5342, 233, 5343.79102f, 233, 5346);
+ pathB.lineTo(233, 5372);
+ pathB.lineTo(169, 5372);
+ pathB.lineTo(169, 5346);
+ pathB.cubicTo(169, 5343.79102f, 170.790863f, 5342, 173, 5342);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// nearly identical to lavoixdunord -- to not-quite-coincident lines
+static void skpwww_booking_com_68(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(90, 187);
+ path.cubicTo(90, 185.34314f, 91.3431473f, 184, 93, 184);
+ path.lineTo(588, 184);
+ path.cubicTo(589.65686f, 184, 591, 185.34314f, 591, 187);
+ path.lineTo(591, 218);
+ path.cubicTo(591, 219.65686f, 589.65686f, 221, 588, 221);
+ path.lineTo(93, 221);
+ path.cubicTo(91.3431473f, 221, 90, 219.65686f, 90, 218);
+ path.lineTo(90, 187);
+ path.close();
+ path.moveTo(92, 188);
+ path.cubicTo(92, 186.895432f, 92.8954315f, 186, 94, 186);
+ path.lineTo(587, 186);
+ path.cubicTo(588.104553f, 186, 589, 186.895432f, 589, 188);
+ path.lineTo(589, 217);
+ path.cubicTo(589, 218.104568f, 588.104553f, 219, 587, 219);
+ path.lineTo(94, 219);
+ path.cubicTo(92.8954315f, 219, 92, 218.104568f, 92, 217);
+ path.lineTo(92, 188);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(90, 184);
+ pathB.lineTo(92, 186);
+ pathB.lineTo(593.02002f, 186.020004f);
+ pathB.lineTo(591, 184);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// visually looks like lavoixdunord and www_booking_com
+static void skpwww_despegar_com_mx_272(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(635, 1788);
+ path.cubicTo(635, 1786.34314f, 636.34314f, 1785, 638, 1785);
+ path.lineTo(832, 1785);
+ path.cubicTo(833.65686f, 1785, 835, 1786.34314f, 835, 1788);
+ path.lineTo(835, 1812);
+ path.cubicTo(835, 1813.65686f, 833.65686f, 1815, 832, 1815);
+ path.lineTo(638, 1815);
+ path.cubicTo(636.34314f, 1815, 635, 1813.65686f, 635, 1812);
+ path.lineTo(635, 1788);
+ path.close();
+ path.moveTo(637, 1789);
+ path.cubicTo(637, 1787.89539f, 637.895447f, 1787, 639, 1787);
+ path.lineTo(831, 1787);
+ path.cubicTo(832.104553f, 1787, 833, 1787.89539f, 833, 1789);
+ path.lineTo(833, 1811);
+ path.cubicTo(833, 1812.10461f, 832.104553f, 1813, 831, 1813);
+ path.lineTo(639, 1813);
+ path.cubicTo(637.895447f, 1813, 637, 1812.10461f, 637, 1811);
+ path.lineTo(637, 1789);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(835, 1785);
+ pathB.lineTo(833, 1787);
+ pathB.lineTo(832.97998f, 1817.02002f);
+ pathB.lineTo(835, 1815);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_joomla_org_23(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(320, 347);
+ path.cubicTo(320, 344.238586f, 322.238586f, 342, 325, 342);
+ path.lineTo(416, 342);
+ path.cubicTo(418.761414f, 342, 421, 344.238586f, 421, 347);
+ path.cubicTo(421, 344.790863f, 418.761414f, 343, 416, 343);
+ path.lineTo(325, 343);
+ path.cubicTo(322.238586f, 343, 320, 344.790863f, 320, 347);
+ path.close();
+ path.moveTo(320, 378);
+ path.cubicTo(320, 380.761414f, 322.238586f, 383, 325, 383);
+ path.lineTo(416, 383);
+ path.cubicTo(418.761414f, 383, 421, 380.761414f, 421, 378);
+ path.cubicTo(421, 380.209137f, 418.761414f, 382, 416, 382);
+ path.lineTo(325, 382);
+ path.cubicTo(322.238586f, 382, 320, 380.209137f, 320, 378);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(320, 383);
+ pathB.lineTo(320, 378);
+ pathB.lineTo(421, 378.000031f);
+ pathB.lineTo(421, 383);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_macrumors_com_131(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(136, 14089);
+ path.lineTo(136, 14056);
+ path.lineTo(778, 14056);
+ path.lineTo(778, 14089);
+ path.quadTo(777.999573f, 14090.6562f, 776.82843f, 14091.8281f);
+ path.quadTo(775.656433f, 14093, 774, 14093);
+ path.lineTo(140, 14093);
+ path.quadTo(138.343552f, 14093, 137.17157f, 14091.8281f);
+ path.quadTo(136.000397f, 14090.6562f, 136, 14089);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(136, 14057);
+ pathB.lineTo(778, 14057);
+ pathB.lineTo(778, 14089);
+ pathB.cubicTo(778, 14091.209f, 776.209167f, 14093, 774, 14093);
+ pathB.lineTo(140, 14093);
+ pathB.cubicTo(137.790863f, 14093, 136, 14091.209f, 136, 14089);
+ pathB.lineTo(136, 14057);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_leadpages_net_84(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(377.1716f, 5910.17139f);
+ path.cubicTo(376.447723f, 5910.89551f, 376, 5911.89551f, 376, 5913);
+ path.lineTo(376, 5972);
+ path.cubicTo(376, 5974.20898f, 377.790863f, 5976, 380, 5976);
+ path.cubicTo(378.34314f, 5976, 377, 5974.20898f, 377, 5972);
+ path.lineTo(377, 5913);
+ path.cubicTo(377, 5912.17139f, 377.335785f, 5911.42188f, 377.878693f, 5910.87891f);
+ path.lineTo(377.1716f, 5910.17139f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(376, 5909);
+ pathB.lineTo(378.481873f, 5909);
+ pathB.lineTo(379.999878f, 5976);
+ pathB.lineTo(376, 5976);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_briian_com_34(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(843, 216);
+ path.cubicTo(843, 213.238571f, 845.238586f, 211, 848, 211);
+ path.lineTo(1191, 211);
+ path.cubicTo(1193.76147f, 211, 1196, 213.238571f, 1196, 216);
+ path.lineTo(1196, 779);
+ path.cubicTo(1196, 781.761414f, 1193.76147f, 784, 1191, 784);
+ path.lineTo(848, 784);
+ path.cubicTo(845.238586f, 784, 843, 781.761414f, 843, 779);
+ path.lineTo(843, 216);
+ path.close();
+ path.moveTo(844, 217);
+ path.cubicTo(844, 214.238571f, 846.238586f, 212, 849, 212);
+ path.lineTo(1190, 212);
+ path.cubicTo(1192.76147f, 212, 1195, 214.238571f, 1195, 217);
+ path.lineTo(1195, 778);
+ path.cubicTo(1195, 779.65686f, 1192.76147f, 781, 1190, 781);
+ path.lineTo(849, 781);
+ path.cubicTo(846.238586f, 781, 844, 779.65686f, 844, 778);
+ path.lineTo(844, 217);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(843, 784);
+ pathB.lineTo(843, 779);
+ pathB.lineTo(1196, 779.000061f);
+ pathB.lineTo(1196, 784);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_sciality_com_100(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(162, 468);
+ path.cubicTo(159.790863f, 468, 158, 469.790863f, 158, 472);
+ path.lineTo(158, 528);
+ path.cubicTo(158, 530.209106f, 159.790863f, 532, 162, 532);
+ path.lineTo(275, 532);
+ path.cubicTo(277.209137f, 532, 279, 530.209106f, 279, 528);
+ path.lineTo(279, 472);
+ path.cubicTo(279, 469.790863f, 277.209137f, 468, 275, 468);
+ path.lineTo(162, 468);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(275, 468);
+ pathB.cubicTo(276.65686f, 468, 278, 469.34314f, 278, 471);
+ pathB.lineTo(278, 529);
+ pathB.cubicTo(278, 530.65686f, 276.65686f, 532, 275, 532);
+ pathB.lineTo(161, 532);
+ pathB.cubicTo(159.34314f, 532, 158, 530.65686f, 158, 529);
+ pathB.lineTo(158, 471);
+ pathB.cubicTo(158, 469.34314f, 159.34314f, 468, 161, 468);
+ pathB.lineTo(275, 468);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_sciality_com_101(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(162, 468);
+ path.cubicTo(159.790863f, 468, 158, 469.790863f, 158, 472);
+ path.lineTo(158, 528);
+ path.cubicTo(158, 530.209106f, 159.790863f, 532, 162, 532);
+ path.lineTo(275.009186f, 532);
+ path.cubicTo(276.661774f, 531.994995f, 278, 530.653748f, 278, 529);
+ path.lineTo(278, 471);
+ path.cubicTo(278, 469.346375f, 276.662079f, 468.005249f, 275.009705f, 468);
+ path.lineTo(162, 468);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(161, 469);
+ pathB.lineTo(275, 469);
+ pathB.cubicTo(276.65686f, 469, 278, 469.895416f, 278, 471);
+ pathB.lineTo(278, 529);
+ pathB.cubicTo(278, 530.65686f, 276.65686f, 532, 275, 532);
+ pathB.lineTo(161, 532);
+ pathB.cubicTo(159.34314f, 532, 158, 530.65686f, 158, 529);
+ pathB.lineTo(158, 471);
+ pathB.cubicTo(158, 469.895416f, 159.34314f, 469, 161, 469);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_meb_gov_tr_5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(137.34314f, 145.34314f);
+ path.quadTo(139.687088f, 143.000793f, 143, 143);
+ path.lineTo(242, 143);
+ path.quadTo(245.312912f, 143.000793f, 247.65686f, 145.34314f);
+ path.quadTo(249.999207f, 147.687088f, 250, 151);
+ path.lineTo(250, 177);
+ path.lineTo(135, 177);
+ path.lineTo(135, 151);
+ path.quadTo(135.000793f, 147.687088f, 137.34314f, 145.34314f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(135, 143);
+ pathB.lineTo(250, 143);
+ pathB.lineTo(250, 177);
+ pathB.lineTo(135, 177);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_meb_gov_tr_6(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(143, 143);
+ path.quadTo(139.687088f, 143.000793f, 137.34314f, 145.34314f);
+ path.quadTo(135.000793f, 147.687088f, 135, 151);
+ path.lineTo(135, 177);
+ path.lineTo(250, 177);
+ path.lineTo(250, 151);
+ path.quadTo(249.999207f, 147.687088f, 247.65686f, 145.34314f);
+ path.quadTo(245.312912f, 143.000793f, 242, 143);
+ path.lineTo(143, 143);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(143, 143);
+ pathB.lineTo(242, 143);
+ pathB.cubicTo(245.865997f, 143, 249, 146.581726f, 249, 151);
+ pathB.lineTo(249, 177);
+ pathB.lineTo(135, 177);
+ pathB.lineTo(135, 151);
+ pathB.cubicTo(135, 146.581726f, 138.581726f, 143, 143, 143);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpgithub_io_25(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1001.87866f, 14.8786793f);
+ path.quadTo(1002.75745f, 14.0001001f, 1004, 14);
+ path.lineTo(1105, 14);
+ path.quadTo(1106.24255f, 14.0001001f, 1107.12134f, 14.8786793f);
+ path.quadTo(1107.99988f, 15.7574596f, 1108, 17);
+ path.lineTo(1108, 41);
+ path.quadTo(1107.99988f, 42.2425423f, 1107.12134f, 43.1213188f);
+ path.quadTo(1106.24255f, 43.9999008f, 1105, 44);
+ path.lineTo(1004, 44);
+ path.quadTo(1002.75745f, 43.9999008f, 1001.87866f, 43.1213188f);
+ path.quadTo(1001.00012f, 42.2425423f, 1001, 41);
+ path.lineTo(1001, 17);
+ path.quadTo(1001.00012f, 15.7574596f, 1001.87866f, 14.8786793f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(1005, 16);
+ pathB.lineTo(1104, 16);
+ pathB.cubicTo(1105.10461f, 16, 1106, 16.8954296f, 1106, 18);
+ pathB.lineTo(1106, 40);
+ pathB.cubicTo(1106, 41.1045685f, 1105.10461f, 42, 1104, 42);
+ pathB.lineTo(1005, 42);
+ pathB.cubicTo(1003.89545f, 42, 1003, 41.1045685f, 1003, 40);
+ pathB.lineTo(1003, 18);
+ pathB.cubicTo(1003, 16.8954296f, 1003.89545f, 16, 1005, 16);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpgithub_io_26(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1001.87866f, 14.8786793f);
+ path.quadTo(1002.75745f, 14.0001001f, 1004, 14);
+ path.lineTo(1105, 14);
+ path.quadTo(1106.24255f, 14.0001001f, 1107.12134f, 14.8786793f);
+ path.quadTo(1107.99988f, 15.7574596f, 1108, 17);
+ path.lineTo(1108, 41);
+ path.quadTo(1107.99988f, 42.2425423f, 1107.12134f, 43.1213188f);
+ path.quadTo(1106.24255f, 43.9999008f, 1105, 44);
+ path.lineTo(1004, 44);
+ path.quadTo(1002.75745f, 43.9999008f, 1001.87866f, 43.1213188f);
+ path.quadTo(1001.00012f, 42.2425423f, 1001, 41);
+ path.lineTo(1001, 17);
+ path.quadTo(1001.00012f, 15.7574596f, 1001.87866f, 14.8786793f);
+ path.close();
+ path.moveTo(1003, 18);
+ path.cubicTo(1003, 16.8954296f, 1003.89545f, 16, 1005, 16);
+ path.lineTo(1104, 16);
+ path.cubicTo(1105.10461f, 16, 1106, 16.8954296f, 1106, 18);
+ path.lineTo(1106, 40);
+ path.cubicTo(1106, 41.1045685f, 1105.10461f, 42, 1104, 42);
+ path.lineTo(1005, 42);
+ path.cubicTo(1003.89545f, 42, 1003, 41.1045685f, 1003, 40);
+ path.lineTo(1003, 18);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1108, 14);
+ pathB.lineTo(1106, 16);
+ pathB.lineTo(1105.97998f, 46.0200005f);
+ pathB.lineTo(1108, 44);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpskpicture14(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 994);
+ path.lineTo(0, 0);
+ path.lineTo(512, 0);
+ path.lineTo(512, 994);
+ path.lineTo(0, 994);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(-317, 168);
+ pathB.quadTo(-317, 166.757385f, -316.121338f, 165.878662f);
+ pathB.quadTo(-315.242645f, 165, -314, 165);
+ pathB.lineTo(320, 165);
+ pathB.quadTo(321.242615f, 165, 322.121338f, 165.878662f);
+ pathB.quadTo(323, 166.757385f, 323, 168);
+ pathB.lineTo(323, 193);
+ pathB.lineTo(-317, 193);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpskpicture15(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 193);
+ path.lineTo(323, 193);
+ path.lineTo(323, 168);
+ path.quadTo(323, 166.757385f, 322.121338f, 165.878662f);
+ path.quadTo(321.242615f, 165, 320, 165);
+ path.lineTo(0, 165);
+ path.lineTo(0, 193);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kInverseWinding_FillType);
+ pathB.moveTo(-314, 165);
+ pathB.lineTo(320, 165);
+ pathB.cubicTo(321.65686f, 165, 323, 166.34314f, 323, 168);
+ pathB.lineTo(323, 192);
+ pathB.lineTo(-317, 192);
+ pathB.lineTo(-317, 168);
+ pathB.cubicTo(-317, 166.34314f, -315.65686f, 165, -314, 165);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+/* Three edges are partially coincident. Only one of the three knows about the other two.
+ Subsequently, when the angle loop is created, it misses one of the edges.
+ After coincident edges are processed, probably need a check-and-correct that makes sure the
+ coincidences are all self-consistent.
+ */
+static void skpelpais_com_18(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(183, 8507);
+ path.lineTo(552, 8506.99023f);
+ path.lineTo(552, 8508);
+ path.lineTo(183, 8508);
+ path.lineTo(183, 8507);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(183, 8508);
+ pathB.lineTo(183, 8506.99023f);
+ pathB.lineTo(552, 8507);
+ pathB.lineTo(552, 8508);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+/* this generates a pair of lines that are essentially coincident; but the next line at a right
+ angle is not treated as if it intersects at the same point.
+ There are several of options:
+ move the intersection of the right angle line to the coincident point (should 'near' do this?
+ construct another coincident pair from the right angle line to the coincident point
+ treat the intersection as simple and not coincident
+ */
+static void skpnamecheap_com_405(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(140, 1000);
+ path.lineTo(140, 842);
+ path.lineTo(141, 842);
+ path.lineTo(141.14502f, 1000);
+ path.lineTo(140, 1000);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(140, 842);
+ pathB.lineTo(141.008835f, 837.9646f);
+ pathB.lineTo(141.235291f, 1109.05884f);
+ pathB.lineTo(140, 1114);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// fails on angle insert -- haven't investigated yet
+static void skpwww_alrakoba_net_62(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(134.34314f, 9802.34277f);
+ path.quadTo(132, 9804.68652f, 132, 9808);
+ path.lineTo(132, 9822);
+ path.quadTo(132, 9825.31348f, 134.34314f, 9827.65723f);
+ path.quadTo(136.686295f, 9830, 140, 9830);
+ path.lineTo(140.028473f, 9830);
+ path.lineTo(139.877213f, 9828.90723f);
+ path.quadTo(137.692032f, 9828.5332f, 136.050247f, 9826.65723f);
+ path.quadTo(134, 9824.31348f, 134, 9821);
+ path.lineTo(134, 9809);
+ path.quadTo(134, 9806.10059f, 136.050247f, 9804.0498f);
+ path.lineTo(134.34314f, 9802.34277f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(132, 9800);
+ pathB.lineTo(135.962357f, 9800);
+ pathB.lineTo(140, 9830);
+ pathB.lineTo(132, 9830);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+/* asserts in alignSpanState looks like a coincident related bug */
+static void skpwww_cityads_ru_249(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(817.464478f, 11.4644661f);
+ path.quadTo(818.928955f, 10, 821, 10);
+ path.lineTo(998, 10);
+ path.quadTo(999.082947f, 10, 1000, 10.4003992f);
+ path.lineTo(1000, 13.3527431f);
+ path.quadTo(999.917603f, 13.2607508f, 999.82843f, 13.1715727f);
+ path.quadTo(998.65686f, 12, 997, 12);
+ path.lineTo(822, 12);
+ path.quadTo(820.34314f, 12, 819.17157f, 13.1715727f);
+ path.quadTo(818, 14.3431454f, 818, 16);
+ path.lineTo(818, 28);
+ path.quadTo(818, 29.6568546f, 819.17157f, 30.8284264f);
+ path.quadTo(820.34314f, 32, 822, 32);
+ path.lineTo(997, 32);
+ path.quadTo(998.65686f, 32, 999.82843f, 30.8284264f);
+ path.quadTo(999.917603f, 30.7392426f, 1000, 30.6472569f);
+ path.lineTo(1000, 33.5996017f);
+ path.quadTo(999.082947f, 34, 998, 34);
+ path.lineTo(821, 34);
+ path.quadTo(818.928955f, 34, 817.464478f, 32.5355339f);
+ path.quadTo(816, 31.0710678f, 816, 29);
+ path.lineTo(816, 15);
+ path.quadTo(816, 12.9289322f, 817.464478f, 11.4644661f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1003, 10);
+ pathB.lineTo(1000, 13);
+ pathB.lineTo(999.969971f, 37.0299988f);
+ pathB.lineTo(1003, 34);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// fails on angle insert
+static void skpwww_dealnews_com_315(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(966.464478f, 4261.46436f);
+ path.quadTo(965, 4262.92871f, 965, 4265);
+ path.lineTo(965, 4276);
+ path.quadTo(965, 4278.07129f, 966.464478f, 4279.53564f);
+ path.quadTo(967.928955f, 4281, 970, 4281);
+ path.lineTo(970.020325f, 4281);
+ path.lineTo(969.887512f, 4279.81641f);
+ path.quadTo(968.928284f, 4279.48145f, 968.17157f, 4278.53564f);
+ path.quadTo(967, 4277.07129f, 967, 4275);
+ path.lineTo(967, 4266);
+ path.quadTo(967, 4264.44287f, 968.035217f, 4263.31396f);
+ path.lineTo(968, 4263);
+ path.lineTo(966.464478f, 4261.46436f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(965, 4260);
+ pathB.lineTo(967.716675f, 4260);
+ pathB.lineTo(970, 4281);
+ pathB.lineTo(965, 4281);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// fails in intersections insert
+static void skpwww_inmotionhosting_com_9(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(991.633911f, 1839);
+ path.lineTo(964.265015f, 1839);
+ path.lineTo(963.734985f, 1893.73242f);
+ path.lineTo(991.3703f, 1894);
+ path.lineTo(1018.23492f, 1894);
+ path.lineTo(1018.76501f, 1839.2627f);
+ path.lineTo(991.638184f, 1839);
+ path.lineTo(991.633911f, 1839);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(964.267578f, 1838.73499f);
+ pathB.lineTo(1019.26501f, 1839.26758f);
+ pathB.lineTo(1018.73242f, 1894.26501f);
+ pathB.lineTo(963.734985f, 1893.73242f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_alucinados_net_101(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1129.53552f, 1164.46448f);
+ path.lineTo(1128, 1166);
+ path.lineTo(1128.12231f, 1166.49548f);
+ path.quadTo(1129, 1167.56592f, 1129, 1169);
+ path.lineTo(1129, 1170.05054f);
+ path.lineTo(1130.34509f, 1175.49878f);
+ path.quadTo(1131, 1174.38513f, 1131, 1173);
+ path.lineTo(1131, 1168);
+ path.quadTo(1131, 1165.92896f, 1129.53552f, 1164.46448f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1131, 1163);
+ pathB.lineTo(-43515.8555f, -177415.594f);
+ pathB.lineTo(1129.76465f, 1173.05884f);
+ pathB.lineTo(1131, 1178);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// /SkOpContour.cpp:278: failed assertion "!approximately_negative(oEndT - oStartT)
+static void skpwww_hairjobsearch_com_31(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(143.292892f, 0.707106769f);
+ path.quadTo(143, 0.414213538f, 143, 0);
+ path.lineTo(1123, 0);
+ path.quadTo(1123, 0.414213538f, 1122.70715f, 0.707106769f);
+ path.quadTo(1122.41418f, 1, 1122, 1);
+ path.lineTo(144, 1);
+ path.quadTo(143.585785f, 1, 143.292892f, 0.707106769f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(143, 1);
+ pathB.lineTo(144, 0);
+ pathB.lineTo(1122, 0);
+ pathB.lineTo(1123, 1);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// SkOpSegment::checkSmallCoincidence; line 1958 SkASSERT(span.fWindValue);
+static void skpwww_heartiste_wordpress_com_86(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(741, 9432);
+ path.lineTo(761, 9431.99023f);
+ path.lineTo(761, 9433);
+ path.lineTo(741, 9433);
+ path.lineTo(741, 9432);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(741, 9433);
+ pathB.lineTo(741, 9431.99023f);
+ pathB.lineTo(761, 9432);
+ pathB.lineTo(761, 9433);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_argus_presse_fr_41(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1000, 343);
+ path.lineTo(165, 343);
+ path.lineTo(165, 364.869873f);
+ path.lineTo(1000, 364.869873f);
+ path.lineTo(1000, 343);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(165, 343.000031f);
+ pathB.lineTo(1000, 343.000031f);
+ pathB.lineTo(1000, 364.869904f);
+ pathB.lineTo(165, 364.869904f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// SkOpSegment::checkSmallCoincidence; line 1958 SkASSERT(span.fWindValue);
+static void skpwww_320kbps_net_2231(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(838, 9125);
+ path.lineTo(862, 9124.99023f);
+ path.lineTo(862, 9126);
+ path.lineTo(838, 9126);
+ path.lineTo(838, 9125);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(838, 9126);
+ pathB.lineTo(838, 9124.99023f);
+ pathB.lineTo(862, 9125);
+ pathB.lineTo(862, 9126);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// debugValidateLoop loop sum fails
+static void skpwww_exystence_net_61(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(143, 9075);
+ path.lineTo(316, 9075);
+ path.lineTo(316, 9073.99023f);
+ path.lineTo(143, 9074);
+ path.lineTo(143, 9075);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(143, 9075);
+ pathB.lineTo(143, 9073.99023f);
+ pathB.lineTo(316, 9074);
+ pathB.lineTo(316, 9075);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// debugValidateLoop loop sum fails
+static void skpwww_trashness_com_36(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(541.5f, 4835.99512f);
+ path.lineTo(91.5f, 4836);
+ path.lineTo(91.5f, 4836.5f);
+ path.lineTo(541.5f, 4836.5f);
+ path.lineTo(541.5f, 4835.99512f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(91.5f, 4836.5f);
+ pathB.lineTo(91.5f, 4835.99512f);
+ pathB.lineTo(541.5f, 4836);
+ pathB.lineTo(541.5f, 4836.5f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// SkIntersections::lineVertical fUsed >= fMax
+static void skpwww_getgold_jp_731(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(284.878693f, 10134.8789f);
+ path.quadTo(284, 10135.7578f, 284, 10137);
+ path.lineTo(284, 10216);
+ path.quadTo(284, 10217.2422f, 284.878693f, 10218.1211f);
+ path.quadTo(285.125122f, 10218.3672f, 285.40213f, 10218.5459f);
+ path.lineTo(286, 10138);
+ path.lineTo(286, 10136);
+ path.lineTo(284.878693f, 10134.8789f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(284, 10134);
+ pathB.lineTo(286.05957f, 10129.8809f);
+ pathB.lineTo(285.399994f, 10216.2002f);
+ pathB.lineTo(284, 10219);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// SkOpContour::calcPartialCoincidentWinding SkASSERT(!approximately_negative(endT - startT));
+static void skpwww_maturesupertube_com_21(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(3.17157292f, 11831.1719f);
+ path.quadTo(4.34314585f, 11830, 6, 11830);
+ path.lineTo(1259, 11830);
+ path.quadTo(1260.65686f, 11830, 1261.82837f, 11831.1719f);
+ path.quadTo(1263, 11832.3428f, 1263, 11834);
+ path.lineTo(1263, 11848);
+ path.quadTo(1263, 11849.6572f, 1261.82837f, 11850.8281f);
+ path.quadTo(1260.65686f, 11852, 1259, 11852);
+ path.lineTo(6, 11852);
+ path.quadTo(4.34314585f, 11852, 3.17157292f, 11850.8281f);
+ path.quadTo(2, 11849.6572f, 2, 11848);
+ path.lineTo(2, 11834);
+ path.quadTo(2, 11832.3428f, 3.17157292f, 11831.1719f);
+ path.close();
+ path.moveTo(3.87867975f, 11831.8789f);
+ path.quadTo(4.7573595f, 11831, 6, 11831);
+ path.lineTo(1259, 11831);
+ path.quadTo(1260.24268f, 11831, 1261.12134f, 11831.8789f);
+ path.quadTo(1262, 11832.7578f, 1262, 11834);
+ path.lineTo(1262, 11848);
+ path.quadTo(1262, 11849.2422f, 1261.12134f, 11850.1211f);
+ path.quadTo(1260.24268f, 11851, 1259, 11851);
+ path.lineTo(6, 11851);
+ path.quadTo(4.7573595f, 11851, 3.87867975f, 11850.1211f);
+ path.quadTo(3, 11849.2422f, 3, 11848);
+ path.lineTo(3, 11834);
+ path.quadTo(3, 11832.7578f, 3.87867975f, 11831.8789f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 11830);
+ pathB.lineTo(4.5f, 11832.5f);
+ pathB.lineTo(1260.5f, 11832.5f);
+ pathB.lineTo(1263, 11830);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// can't find winding of remaining vertical edges
+static void skpwww_hubbyscook_com_22(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1000, 902.329346f);
+ path.quadTo(998, 905.250427f, 998, 909);
+ path.lineTo(998, 910);
+ path.quadTo(998, 913.749573f, 1000, 916.670654f);
+ path.lineTo(1000, 902.329346f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(998, 910);
+ pathB.lineTo(998, 909);
+ pathB.quadTo(998, 904.029419f, 1001.51471f, 900.514709f);
+ pathB.quadTo(1005.02942f, 897, 1010, 897);
+ pathB.lineTo(1011, 897);
+ pathB.quadTo(1015.14215f, 897, 1018.07104f, 900.514709f);
+ pathB.quadTo(1021, 904.029419f, 1021, 909);
+ pathB.lineTo(1021, 910);
+ pathB.quadTo(1021, 914.142151f, 1018.07104f, 917.071045f);
+ pathB.quadTo(1015.14215f, 920, 1011, 920);
+ pathB.lineTo(1010, 920);
+ pathB.quadTo(1005.02942f, 920, 1001.51471f, 917.071045f);
+ pathB.quadTo(998, 914.142151f, 998, 910);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void skpwww_gruposejaumdivulgador_com_br_4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(610.5f, 5.78626502e-14f);
+ path.lineTo(1083.5f, -6.12303177e-17f);
+ path.lineTo(1083.5f, 469);
+ path.lineTo(610.5f, 469);
+ path.lineTo(610.5f, 5.78626502e-14f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(611, 0);
+ pathB.lineTo(1084, 0);
+ pathB.lineTo(1084, 469);
+ pathB.lineTo(611, 469);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// asserts in bridgeOp simple->isClosed()
+static void skpwww_phototransferapp_com_24(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(85.6091843f, 5.92893219f);
+ path.quadTo(89.6041641f, 3, 93.7462997f, 3);
+ path.lineTo(1212.74634f, 3);
+ path.quadTo(1216.88843f, 3, 1218.75134f, 5.92893219f);
+ path.quadTo(1220.61414f, 8.85775471f, 1219.10669f, 12.9996767f);
+ path.quadTo(1220.46338f, 9.27196693f, 1218.4939f, 6.63603878f);
+ path.quadTo(1216.52441f, 4, 1212.38232f, 4);
+ path.lineTo(93.3823318f, 4);
+ path.quadTo(89.2401962f, 4, 85.3518219f, 6.63603878f);
+ path.quadTo(81.4634476f, 9.27207756f, 80.1065979f, 13);
+ path.quadTo(81.614212f, 8.85786438f, 85.6091843f, 5.92893219f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(83.7462997f, 3);
+ pathB.lineTo(1222.74634f, 3);
+ pathB.lineTo(1219.10657f, 13);
+ pathB.lineTo(80.1065979f, 13);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_phototransferapp_com_24x(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(85.6091843f, 5.92893219f);
+ path.quadTo(89.6041641f, 3, 93.7462997f, 3);
+ path.lineTo(112.74634f, 3);
+ path.quadTo(116.88843f, 3, 118.75134f, 5.92893219f);
+ path.quadTo(120.61414f, 8.85775471f, 119.10669f, 12.9996767f);
+ path.quadTo(120.46338f, 9.27196693f, 118.4939f, 6.63603878f);
+ path.quadTo(116.52441f, 4, 112.38232f, 4);
+ path.lineTo(93.3823318f, 4);
+ path.quadTo(89.2401962f, 4, 85.3518219f, 6.63603878f);
+ path.quadTo(81.4634476f, 9.27207756f, 80.1065979f, 13);
+ path.quadTo(81.614212f, 8.85786438f, 85.6091843f, 5.92893219f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(83.7462997f, 3);
+ pathB.lineTo(122.74634f, 3);
+ pathB.lineTo(119.10657f, 13);
+ pathB.lineTo(80.1065979f, 13);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_helha_be_109(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(117.686981f, 3339.08423f);
+ path.lineTo(109.533035f, 3350.72925f);
+ path.quadTo(107.120552f, 3354.17456f, 103.879379f, 3354.41821f);
+ path.quadTo(100.638504f, 3354.66187f, 98.4674301f, 3351.56177f);
+ path.quadTo(100.87973f, 3355.00635f, 104.291222f, 3355.00635f);
+ path.quadTo(107.70298f, 3355.00635f, 110.115463f, 3351.56104f);
+ path.lineTo(118, 3340.30078f);
+ path.lineTo(118, 3339.53125f);
+ path.lineTo(117.686981f, 3339.08423f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(118.269409f, 3339.91602f);
+ pathB.lineTo(117.686981f, 3339.08423f);
+ pathB.lineTo(98.4669647f, 3351.56104f);
+ pathB.lineTo(104.291214f, 3359.87891f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_cooksnaps_com_32(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(509.34021f, 176);
+ path.lineTo(505, 176);
+ path.quadTo(500.964233f, 176, 497.299988f, 176.896912f);
+ path.quadTo(493.678162f, 177.952286f, 490.183014f, 179.9702f);
+ path.lineTo(489.316986f, 180.4702f);
+ path.quadTo(485.175385f, 182.861359f, 482.115265f, 186.082397f);
+ path.quadTo(479.69455f, 188.700821f, 477.995941f, 191.618286f);
+ path.quadTo(476.316772f, 194.550476f, 475.258759f, 197.959335f);
+ path.quadTo(474, 202.218979f, 474, 207);
+ path.lineTo(474, 208);
+ path.quadTo(474, 212.03569f, 474.896851f, 215.699799f);
+ path.quadTo(475.950256f, 219.315002f, 477.962708f, 222.803986f);
+ path.lineTo(477.970215f, 222.816986f);
+ path.lineTo(478.470215f, 223.683014f);
+ path.quadTo(478.474915f, 223.691162f, 478.479645f, 223.69931f);
+ path.quadTo(480.867981f, 227.831055f, 484.082947f, 230.885254f);
+ path.quadTo(486.701447f, 233.305939f, 489.61908f, 235.004517f);
+ path.quadTo(492.550232f, 236.682983f, 495.957611f, 237.740738f);
+ path.quadTo(500.217987f, 239, 505, 239);
+ path.lineTo(509.482178f, 239);
+ path.quadTo(515.299133f, 238.212051f, 520.801941f, 235.038513f);
+ path.quadTo(520.809509f, 235.034164f, 520.817017f, 235.0298f);
+ path.lineTo(521.683044f, 234.5298f);
+ path.quadTo(521.692078f, 234.524582f, 521.701111f, 234.519348f);
+ path.quadTo(532.80603f, 228.09938f, 536.126709f, 215.70639f);
+ path.quadTo(539.450134f, 203.303314f, 533.029785f, 192.183014f);
+ path.lineTo(532.529785f, 191.316986f);
+ path.quadTo(526.109497f, 180.196686f, 513.706421f, 176.873276f);
+ path.quadTo(511.503082f, 176.282898f, 509.34021f, 176);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(478.470215f, 223.683014f);
+ pathB.lineTo(477.970215f, 222.816986f);
+ pathB.quadTo(471.549896f, 211.696686f, 474.873322f, 199.293594f);
+ pathB.quadTo(478.196686f, 186.890503f, 489.316986f, 180.4702f);
+ pathB.lineTo(490.183014f, 179.9702f);
+ pathB.quadTo(501.303345f, 173.549896f, 513.706421f, 176.873276f);
+ pathB.quadTo(526.109497f, 180.196686f, 532.529785f, 191.316986f);
+ pathB.lineTo(533.029785f, 192.183014f);
+ pathB.quadTo(539.450134f, 203.303314f, 536.126709f, 215.70639f);
+ pathB.quadTo(532.803345f, 228.109497f, 521.683044f, 234.5298f);
+ pathB.lineTo(520.817017f, 235.0298f);
+ pathB.quadTo(509.696686f, 241.450104f, 497.29361f, 238.126709f);
+ pathB.quadTo(484.890533f, 234.803314f, 478.470215f, 223.683014f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_cooksnaps_com_32a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(497.299988f, 176.896912f);
+ path.quadTo(493.678162f, 177.952286f, 490.183014f, 179.9702f);
+ path.lineTo(489.316986f, 180.4702f);
+ path.quadTo(485.175385f, 182.861359f, 482.115265f, 186.082397f);
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(474.873322f, 199.293594f);
+ pathB.quadTo(478.196686f, 186.890503f, 489.316986f, 180.4702f);
+ pathB.lineTo(490.183014f, 179.9702f);
+ pathB.quadTo(501.303345f, 173.549896f, 513.706421f, 176.873276f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// !simple->isClosed()
+static void skpwww_contextualnewsfeeds_com_346(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(460.257355f, 1202.27808f);
+ path.lineTo(460.257355f, 1204.27808f);
+ path.quadTo(461.081207f, 1204.27808f, 461.665161f, 1203.69873f);
+ path.lineTo(461.67157f, 1203.69238f);
+ path.lineTo(466.621307f, 1198.74268f);
+ path.quadTo(466.623993f, 1198.73999f, 466.626648f, 1198.7373f);
+ path.quadTo(466.914185f, 1198.44604f, 466.914185f, 1198.03552f);
+ path.quadTo(466.914215f, 1197.62122f, 466.621307f, 1197.32837f);
+ path.lineTo(465.914215f, 1196.62122f);
+ path.lineTo(460.257355f, 1202.27808f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(460.257355f, 1205.10657f);
+ pathB.lineTo(458.828979f, 1203.67822f);
+ pathB.lineTo(465.914215f, 1196.62122f);
+ pathB.lineTo(467.32843f, 1198.03552f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// line quad intersection SkIntersections::assert
+static void skpwww_pindosiya_com_99(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(899.17157f, 548.17157f);
+ path.quadTo(898, 549.34314f, 898, 551);
+ path.lineTo(898, 556);
+ path.lineTo(899.027283f, 556);
+ path.lineTo(900.02356f, 551.602844f);
+ path.quadTo(900.06073f, 551.297058f, 900.156555f, 551.015747f);
+ path.lineTo(900.5f, 549.5f);
+ path.lineTo(899.17157f, 548.17157f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(898, 547);
+ pathB.lineTo(901.086914f, 547);
+ pathB.lineTo(899, 556);
+ pathB.lineTo(898, 556);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// SkOpAngle::setSector SkASSERT(fSectorStart >= 0);
+static void skpwww_karnivool_com_au_11(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0, 1431);
+ path.lineTo(0, 775);
+ path.lineTo(1265, 775);
+ path.lineTo(1265, 1431);
+ path.lineTo(0, 1431);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(32.3243904f, 851);
+ pathB.lineTo(459.324402f, 851);
+ pathB.lineTo(427, 1081);
+ pathB.lineTo(-3.81469727e-06f, 1081);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_tunero_de_24(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1020.79303f, 2252);
+ path.quadTo(1018.72198f, 2252, 1016.86798f, 2253.46436f);
+ path.quadTo(1015.02032f, 2254.92383f, 1014.4668f, 2256.98584f);
+ path.lineTo(1014.46301f, 2257);
+ path.lineTo(1011.53705f, 2268);
+ path.quadTo(1010.98615f, 2270.07104f, 1012.06104f, 2271.53564f);
+ path.quadTo(1013.13599f, 2273, 1015.20703f, 2273);
+ path.lineTo(1083.20703f, 2273);
+ path.quadTo(1085.27808f, 2273, 1087.13208f, 2271.53564f);
+ path.quadTo(1088.97144f, 2270.08252f, 1089.52832f, 2268.03271f);
+ path.lineTo(1089.53711f, 2268);
+ path.lineTo(1092.46301f, 2257);
+ path.lineTo(1092.4679f, 2256.98145f);
+ path.quadTo(1093.00916f, 2254.92236f, 1091.93909f, 2253.46436f);
+ path.quadTo(1090.86414f, 2252, 1088.79297f, 2252);
+ path.lineTo(1020.79303f, 2252);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1011.53705f, 2268);
+ pathB.lineTo(1014.46301f, 2257);
+ pathB.quadTo(1015.01392f, 2254.92896f, 1016.86798f, 2253.46436f);
+ pathB.quadTo(1018.72198f, 2252, 1020.79303f, 2252);
+ pathB.lineTo(1088.79297f, 2252);
+ pathB.quadTo(1090.86414f, 2252, 1091.93909f, 2253.46436f);
+ pathB.quadTo(1093.01392f, 2254.92896f, 1092.46301f, 2257);
+ pathB.lineTo(1089.53711f, 2268);
+ pathB.quadTo(1088.98608f, 2270.07104f, 1087.13208f, 2271.53564f);
+ pathB.quadTo(1085.27808f, 2273, 1083.20703f, 2273);
+ pathB.lineTo(1015.20703f, 2273);
+ pathB.quadTo(1013.13599f, 2273, 1012.06104f, 2271.53564f);
+ pathB.quadTo(1010.98615f, 2270.07104f, 1011.53705f, 2268);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_docgelo_com_66(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(22.5f, 24174.5f);
+ path.lineTo(185.5f, 24174.498f);
+ path.lineTo(185.5f, 24174.75f);
+ path.lineTo(22.5f, 24174.75f);
+ path.lineTo(22.5f, 24174.5f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(22.5f, 24174.75f);
+ pathB.lineTo(22.5f, 24174.498f);
+ pathB.lineTo(185.5f, 24174.5f);
+ pathB.lineTo(185.5f, 24174.75f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_kpopexplorer_net_22(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1000, 866.329346f);
+ path.quadTo(998, 869.250427f, 998, 873);
+ path.lineTo(998, 874);
+ path.quadTo(998, 877.749573f, 1000, 880.670654f);
+ path.lineTo(1000, 866.329346f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(998, 874);
+ pathB.lineTo(998, 873);
+ pathB.quadTo(998, 868.029419f, 1001.51471f, 864.514709f);
+ pathB.quadTo(1005.02942f, 861, 1010, 861);
+ pathB.lineTo(1011, 861);
+ pathB.quadTo(1015.14215f, 861, 1018.07104f, 864.514709f);
+ pathB.quadTo(1021, 868.029419f, 1021, 873);
+ pathB.lineTo(1021, 874);
+ pathB.quadTo(1021, 878.142151f, 1018.07104f, 881.071045f);
+ pathB.quadTo(1015.14215f, 884, 1011, 884);
+ pathB.lineTo(1010, 884);
+ pathB.quadTo(1005.02942f, 884, 1001.51471f, 881.071045f);
+ pathB.quadTo(998, 878.142151f, 998, 874);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void skpwww_artblart_com_8(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(22.5f, 24527.25f);
+ path.lineTo(45, 24527.248f);
+ path.lineTo(45, 24527.5f);
+ path.lineTo(22.5f, 24527.5f);
+ path.lineTo(22.5f, 24527.25f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(22.5f, 24527.5f);
+ pathB.lineTo(22.5f, 24527.248f);
+ pathB.lineTo(45, 24527.25f);
+ pathB.lineTo(45, 24527.5f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// joinCoincidence / findT / assert
+static void skpwww_jessicaslens_wordpress_com_222(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1000, 844.329346f);
+ path.quadTo(998, 847.250427f, 998, 851);
+ path.lineTo(998, 852);
+ path.quadTo(998, 855.749573f, 1000, 858.670654f);
+ path.lineTo(1000, 844.329346f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(998, 852);
+ pathB.lineTo(998, 851);
+ pathB.quadTo(998, 846.029419f, 1001.51471f, 842.514709f);
+ pathB.quadTo(1005.02942f, 839, 1010, 839);
+ pathB.lineTo(1011, 839);
+ pathB.quadTo(1015.14215f, 839, 1018.07104f, 842.514709f);
+ pathB.quadTo(1021, 846.029419f, 1021, 851);
+ pathB.lineTo(1021, 852);
+ pathB.quadTo(1021, 856.142151f, 1018.07104f, 859.071045f);
+ pathB.quadTo(1015.14215f, 862, 1011, 862);
+ pathB.lineTo(1010, 862);
+ pathB.quadTo(1005.02942f, 862, 1001.51471f, 859.071045f);
+ pathB.quadTo(998, 856.142151f, 998, 852);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+// joinCoincidence / findT / assert
+static void skpwww_simplysaru_com_40(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1000, 866.329346f);
+ path.quadTo(998, 869.250427f, 998, 873);
+ path.lineTo(998, 874);
+ path.quadTo(998, 877.749573f, 1000, 880.670654f);
+ path.lineTo(1000, 866.329346f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(998, 874);
+ pathB.lineTo(998, 873);
+ pathB.quadTo(998, 868.029419f, 1001.51471f, 864.514709f);
+ pathB.quadTo(1005.02942f, 861, 1010, 861);
+ pathB.lineTo(1011, 861);
+ pathB.quadTo(1015.14215f, 861, 1018.07104f, 864.514709f);
+ pathB.quadTo(1021, 868.029419f, 1021, 873);
+ pathB.lineTo(1021, 874);
+ pathB.quadTo(1021, 878.142151f, 1018.07104f, 881.071045f);
+ pathB.quadTo(1015.14215f, 884, 1011, 884);
+ pathB.lineTo(1010, 884);
+ pathB.quadTo(1005.02942f, 884, 1001.51471f, 881.071045f);
+ pathB.quadTo(998, 878.142151f, 998, 874);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+// cubic-cubic intersection reduce checkLinear assert
+static void skpwww_partsdata_de_53(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(407, 119);
+ path.lineTo(407, 28);
+ path.lineTo(647, 28);
+ path.lineTo(647, 119);
+ path.lineTo(407, 119);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(471.228394f, 64.443222f);
+ pathB.cubicTo(471.193878f, 60.953373f, 470.234985f, 52.4797592f, 462.201569f, 46.6231461f);
+ pathB.cubicTo(454.168152f, 40.7665405f, 446.592804f, 41.993145f, 443.033936f, 42.8568878f);
+ pathB.cubicTo(439.475098f, 43.7206268f, 436.978638f, 45.4052658f, 436.304871f, 45.7851906f);
+ pathB.cubicTo(435.631104f, 46.1651154f, 435.156006f, 45.8026352f, 434.957306f, 45.6384506f);
+ pathB.cubicTo(434.758636f, 45.4742737f, 431.460999f, 42.0105858f, 430.916901f, 41.4664841f);
+ pathB.cubicTo(430.372803f, 40.9223785f, 429.731628f, 41.3303604f, 429.375214f, 41.6996689f);
+ pathB.cubicTo(429.375214f, 41.6996689f, 420.610016f, 50.5190887f, 419.918793f, 51.1754227f);
+ pathB.cubicTo(419.22757f, 51.8321419f, 419.331482f, 52.2465706f, 419.884308f, 52.8339005f);
+ pathB.cubicTo(420.437134f, 53.4212303f, 425.170624f, 58.0167313f, 425.619568f, 58.4660416f);
+ pathB.cubicTo(426.068512f, 58.9153557f, 426.137878f, 59.2952805f, 426.137878f, 59.8136024f);
+ pathB.cubicTo(426.137878f, 60.3319244f, 426.103394f, 103.141357f, 426.103394f, 103.970215f);
+ pathB.cubicTo(426.103394f, 104.799835f, 426.310791f, 105.525177f, 427.17453f, 105.525177f);
+ pathB.cubicTo(428.038269f, 105.525177f, 440.131409f, 105.491432f, 440.85675f, 105.491432f);
+ pathB.cubicTo(441.582489f, 105.491432f, 441.996918f, 104.903343f, 441.996918f, 104.17762f);
+ pathB.cubicTo(441.996918f, 103.452271f, 441.996918f, 89.5622559f, 441.996918f, 87.8002701f);
+ pathB.cubicTo(441.996918f, 86.0382843f, 442.342712f, 86.2453079f, 442.826141f, 86.3491974f);
+ pathB.cubicTo(443.309601f, 86.4530945f, 445.832184f, 87.040802f, 448.700195f, 87.040802f);
+ pathB.cubicTo(466.87442f, 86.6949997f, 471.815338f, 69.4876556f, 471.228394f, 64.443222f);
+ pathB.close();
+ pathB.moveTo(448.873108f, 72.4595642f);
+ pathB.cubicTo(444.636658f, 72.4595642f, 441.202545f, 69.0254517f, 441.202545f, 64.7890244f);
+ pathB.cubicTo(441.202545f, 60.5525932f, 444.636658f, 57.1184845f, 448.873108f, 57.1184845f);
+ pathB.cubicTo(453.109528f, 57.1184845f, 456.54364f, 60.552597f, 456.54364f, 64.7890244f);
+ pathB.cubicTo(456.54364f, 69.0254517f, 453.109528f, 72.4595642f, 448.873108f, 72.4595642f);
+ pathB.close();
+ pathB.moveTo(520.242859f, 82.5275803f);
+ pathB.cubicTo(519.733276f, 81.6547394f, 494.845154f, 41.3379478f, 494.263123f, 40.3923073f);
+ pathB.cubicTo(493.681122f, 39.4462852f, 493.244324f, 39.5918846f, 492.807495f, 40.3195038f);
+ pathB.cubicTo(492.515167f, 40.8071136f, 467.238037f, 81.6790085f, 466.528625f, 82.8373566f);
+ pathB.cubicTo(465.819183f, 83.9945831f, 466.497528f, 84.2975311f, 466.904358f, 84.5792542f);
+ pathB.cubicTo(466.904358f, 84.5792542f, 477.399689f, 91.2036743f, 478.235748f, 91.6981049f);
+ pathB.cubicTo(479.071838f, 92.1929092f, 479.396393f, 91.9028473f, 479.669403f, 91.5104141f);
+ pathB.cubicTo(479.942383f, 91.1175995f, 484.106384f, 84.1549606f, 484.481781f, 83.5570221f);
+ pathB.cubicTo(484.857147f, 82.9602051f, 485.198792f, 82.8741379f, 485.966583f, 82.8741379f);
+ pathB.cubicTo(486.734406f, 82.8741379f, 499.635925f, 82.8062668f, 500.830322f, 82.8062668f);
+ pathB.cubicTo(502.024658f, 82.8062668f, 502.229797f, 83.4038391f, 502.400452f, 83.6427078f);
+ pathB.cubicTo(502.571045f, 83.8815842f, 506.615631f, 90.7414703f, 506.990997f, 91.2870865f);
+ pathB.cubicTo(507.651123f, 92.2475128f, 508.017395f, 92.1333847f, 508.672241f, 91.6962051f);
+ pathB.cubicTo(509.327423f, 91.2597809f, 519.442444f, 85.0744324f, 520.243286f, 84.4920349f);
+ pathB.cubicTo(521.042908f, 83.9100189f, 520.751709f, 83.4004211f, 520.242859f, 82.5275803f);
+ pathB.close();
+ pathB.moveTo(493.720551f, 72.4811783f);
+ pathB.cubicTo(491.265442f, 72.4811783f, 489.275574f, 70.4905548f, 489.275574f, 68.0362091f);
+ pathB.cubicTo(489.275574f, 65.5811005f, 491.265808f, 63.5912399f, 493.720551f, 63.5912399f);
+ pathB.cubicTo(496.175262f, 63.5912399f, 498.165527f, 65.5814819f, 498.165527f, 68.0362091f);
+ pathB.cubicTo(498.165894f, 70.4905548f, 496.175659f, 72.4811783f, 493.720551f, 72.4811783f);
+ pathB.close();
+ pathB.moveTo(526.561707f, 42.132679f);
+ pathB.cubicTo(526.876404f, 41.786499f, 527.537292f, 41.1881752f, 528.512878f, 42.1956215f);
+ pathB.cubicTo(529.488892f, 43.2030678f, 531.691833f, 45.2486725f, 531.881042f, 45.4693451f);
+ pathB.cubicTo(532.07019f, 45.6896439f, 532.762939f, 46.2875862f, 533.517883f, 45.7525826f);
+ pathB.cubicTo(534.272827f, 45.2172012f, 539.497681f, 41.9753265f, 545.384277f, 42.132679f);
+ pathB.cubicTo(546.203247f, 42.2270889f, 546.580566f, 42.5421791f, 546.612f, 43.8324814f);
+ pathB.cubicTo(546.643494f, 45.1227837f, 546.674561f, 55.1957283f, 546.612f, 56.2657356f);
+ pathB.cubicTo(546.549072f, 57.3361206f, 546.549072f, 57.7452469f, 544.975525f, 57.8396568f);
+ pathB.cubicTo(543.401978f, 57.9340706f, 538.742798f, 59.5709305f, 538.774658f, 64.6070251f);
+ pathB.cubicTo(538.806458f, 69.6431122f, 538.806091f, 86.2631226f, 538.806091f, 86.9554901f);
+ pathB.cubicTo(538.806091f, 87.6478424f, 538.585815f, 88.4349976f, 537.484314f, 88.4349976f);
+ pathB.cubicTo(536.382446f, 88.4349976f, 524.79895f, 88.4031372f, 524.04364f, 88.4031372f);
+ pathB.cubicTo(523.287964f, 88.4031372f, 522.910706f, 88.3402023f, 522.910706f, 86.8606949f);
+ pathB.cubicTo(522.910706f, 85.3823242f, 522.910706f, 60.6094704f, 522.910706f, 60.0740852f);
+ pathB.cubicTo(522.910706f, 59.5387039f, 522.81665f, 58.9092865f, 522.470093f, 58.6260452f);
+ pathB.cubicTo(522.123901f, 58.3428116f, 517.465088f, 53.621048f, 517.181885f, 53.3378105f);
+ pathB.cubicTo(516.898621f, 53.0545731f, 516.300659f, 52.330368f, 517.213318f, 51.5121231f);
+ pathB.cubicTo(518.125977f, 50.6942635f, 526.561707f, 42.132679f, 526.561707f, 42.132679f);
+ pathB.close();
+ pathB.moveTo(550.169006f, 43.7373123f);
+ pathB.cubicTo(550.169006f, 42.6358337f, 550.767334f, 42.2263336f, 551.49115f, 42.2263336f);
+ pathB.cubicTo(552.214966f, 42.2263336f, 552.781433f, 42.2263336f, 552.938843f, 42.2263336f);
+ pathB.cubicTo(553.096191f, 42.2263336f, 553.725586f, 41.8801537f, 553.662598f, 41.124855f);
+ pathB.cubicTo(553.600098f, 40.369175f, 553.662598f, 31.4614124f, 553.662598f, 30.8005257f);
+ pathB.cubicTo(553.662598f, 30.1396389f, 553.75708f, 29.1951332f, 555.110657f, 29.1951332f);
+ pathB.cubicTo(556.463928f, 29.1951332f, 566.536865f, 29.1951332f, 567.859009f, 29.1951332f);
+ pathB.cubicTo(569.180786f, 29.1951332f, 569.463623f, 30.1711082f, 569.463623f, 30.7690544f);
+ pathB.cubicTo(569.463623f, 31.3670006f, 569.463623f, 40.2122002f, 569.463623f, 41.0619125f);
+ pathB.cubicTo(569.463623f, 41.9116249f, 569.746887f, 42.3207474f, 570.659912f, 42.3207474f);
+ pathB.cubicTo(571.572571f, 42.3207474f, 575.507568f, 42.2263336f, 576.199951f, 42.2263336f);
+ pathB.cubicTo(576.892273f, 42.2263336f, 577.742004f, 42.5725098f, 577.742004f, 43.8631973f);
+ pathB.cubicTo(577.742004f, 45.1538811f, 577.742004f, 55.8877106f, 577.742004f, 56.5800705f);
+ pathB.cubicTo(577.742004f, 57.2724266f, 577.616455f, 58.0595779f, 576.45166f, 58.0595779f);
+ pathB.cubicTo(575.286865f, 58.0595779f, 570.943115f, 58.0595779f, 570.471069f, 58.0595779f);
+ pathB.cubicTo(569.999023f, 58.0595779f, 569.479919f, 57.8389015f, 569.479919f, 59.0510979f);
+ pathB.cubicTo(569.479919f, 60.2629128f, 569.479919f, 66.2124176f, 569.479919f, 67.1880188f);
+ pathB.cubicTo(569.479919f, 68.1636047f, 570.628418f, 73.6406708f, 575.917053f, 73.6406708f);
+ pathB.cubicTo(577.018921f, 73.6406708f, 577.742737f, 73.9242859f, 577.742737f, 75.4348907f);
+ pathB.cubicTo(577.742737f, 76.945488f, 577.742737f, 87.0813751f, 577.742737f, 87.8366699f);
+ pathB.cubicTo(577.742737f, 88.5915909f, 577.648315f, 89.4416809f, 576.295044f, 89.4416809f);
+ pathB.cubicTo(574.028809f, 89.6312714f, 553.978088f, 88.0254974f, 553.631897f, 65.928421f);
+ pathB.cubicTo(553.631897f, 65.928421f, 553.631897f, 59.6964378f, 553.631897f, 58.972229f);
+ pathB.cubicTo(553.631897f, 58.2484055f, 553.034363f, 58.0436554f, 552.703735f, 58.0436554f);
+ pathB.cubicTo(552.372681f, 58.0436554f, 551.522949f, 58.0436554f, 551.208252f, 58.0436554f);
+ pathB.cubicTo(550.893921f, 58.0436554f, 550.170105f, 58.0906677f, 550.170105f, 56.6115417f);
+ pathB.cubicTo(550.170105f, 55.1324081f, 550.169006f, 43.7373123f, 550.169006f, 43.7373123f);
+ pathB.close();
+ pathB.moveTo(611.203857f, 39.5509338f);
+ pathB.cubicTo(612.084961f, 39.5509338f, 612.620422f, 40.0544662f, 612.620422f, 40.8097687f);
+ pathB.cubicTo(612.620422f, 41.5650673f, 612.620422f, 53.1486092f, 612.620422f, 53.6839905f);
+ pathB.cubicTo(612.620422f, 54.2193718f, 612.651489f, 55.2264404f, 611.612976f, 55.2264404f);
+ pathB.cubicTo(610.574463f, 55.2264404f, 604.404663f, 55.9817429f, 604.404663f, 61.899395f);
+ pathB.cubicTo(604.404663f, 65.4878235f, 604.373169f, 66.6211548f, 604.373169f, 67.5338135f);
+ pathB.cubicTo(604.373169f, 68.0684357f, 604.414124f, 74.3353043f, 599.934631f, 80.4702148f);
+ pathB.cubicTo(596.765564f, 84.8109131f, 590.664368f, 89.3942871f, 582.150208f, 89.630127f);
+ pathB.cubicTo(580.028015f, 89.630127f, 580.230469f, 88.5286484f, 580.230469f, 88.1820908f);
+ pathB.cubicTo(580.230469f, 87.5845184f, 580.198975f, 75.8436279f, 580.198975f, 75.2142105f);
+ pathB.cubicTo(580.198975f, 74.5844116f, 580.608154f, 73.8605804f, 581.58374f, 73.8605804f);
+ pathB.cubicTo(583.40979f, 73.8605804f, 588.603271f, 72.7905731f, 588.603271f, 66.9043884f);
+ pathB.cubicTo(588.603271f, 61.3958588f, 588.603271f, 61.8679237f, 588.603271f, 61.0496788f);
+ pathB.cubicTo(588.603271f, 60.2314377f, 588.666565f, 54.3137856f, 593.230591f, 48.3961296f);
+ pathB.cubicTo(597.794617f, 42.4784775f, 604.814087f, 39.5509338f, 611.203857f, 39.5509338f);
+ pathB.close();
+ pathB.moveTo(635.22937f, 81.9311447f);
+ pathB.cubicTo(635.057617f, 81.6475296f, 634.869141f, 81.3851471f, 634.664429f, 81.1439972f);
+ pathB.lineTo(635.039001f, 81.0385895f);
+ pathB.cubicTo(635.447754f, 80.9233246f, 635.729858f, 80.5509796f, 635.729858f, 80.1263123f);
+ pathB.lineTo(635.729858f, 78.6149597f);
+ pathB.cubicTo(635.729858f, 78.3309631f, 635.602417f, 78.0617523f, 635.382935f, 77.8816452f);
+ pathB.cubicTo(635.162598f, 77.7015381f, 634.873291f, 77.6295013f, 634.595764f, 77.6852341f);
+ pathB.cubicTo(633.906799f, 77.8232498f, 633.194397f, 77.9017334f, 632.478149f, 77.9191818f);
+ pathB.cubicTo(631.714844f, 77.9373779f, 630.851501f, 77.9464874f, 629.911133f, 77.9464874f);
+ pathB.lineTo(615.131226f, 77.9464874f);
+ pathB.cubicTo(614.607605f, 77.9464874f, 614.18335f, 78.3707733f, 614.18335f, 78.8944016f);
+ pathB.lineTo(614.18335f, 81.1337585f);
+ pathB.cubicTo(614.18335f, 81.6573868f, 614.607605f, 82.0816803f, 615.131226f, 82.0816803f);
+ pathB.lineTo(619.693787f, 82.0816803f);
+ pathB.cubicTo(619.680908f, 82.1423492f, 619.669128f, 82.2026367f, 619.657776f, 82.2629166f);
+ pathB.cubicTo(619.571289f, 82.728157f, 619.529602f, 83.3200302f, 619.529602f, 84.0730591f);
+ pathB.cubicTo(619.529602f, 86.3196259f, 620.260254f, 88.1236954f, 621.701477f, 89.4348602f);
+ pathB.cubicTo(623.116516f, 90.7225037f, 625.163269f, 91.3754272f, 627.784058f, 91.3754272f);
+ pathB.cubicTo(630.525024f, 91.3754272f, 632.517944f, 90.8669662f, 633.876099f, 89.8208466f);
+ pathB.cubicTo(635.291565f, 88.7314987f, 636.009705f, 87.0798492f, 636.009705f, 84.9129181f);
+ pathB.cubicTo(636.010071f, 83.7905807f, 635.747314f, 82.7873077f, 635.22937f, 81.9311447f);
+ pathB.close();
+ pathB.moveTo(631.880554f, 85.7326736f);
+ pathB.cubicTo(631.690552f, 86.0545807f, 631.436157f, 86.307869f, 631.102844f, 86.5076904f);
+ pathB.cubicTo(630.736206f, 86.7279816f, 630.277039f, 86.8906479f, 629.737854f, 86.9903717f);
+ pathB.cubicTo(629.146362f, 87.1003265f, 628.488892f, 87.1564484f, 627.783997f, 87.1564484f);
+ pathB.cubicTo(626.159668f, 87.1564484f, 624.996399f, 86.8656235f, 624.327881f, 86.293457f);
+ pathB.cubicTo(623.693604f, 85.7489777f, 623.385315f, 84.995575f, 623.385315f, 83.9896393f);
+ pathB.cubicTo(623.385315f, 83.3655396f, 623.431519f, 82.8718567f, 623.522583f, 82.5215149f);
+ pathB.cubicTo(623.563477f, 82.3645325f, 623.616943f, 82.2189331f, 623.684448f, 82.0824356f);
+ pathB.lineTo(630.008179f, 82.0824356f);
+ pathB.cubicTo(630.758911f, 82.247757f, 631.311401f, 82.5256805f, 631.650757f, 82.9101562f);
+ pathB.cubicTo(631.990112f, 83.2942505f, 632.154663f, 83.8303986f, 632.154663f, 84.549675f);
+ pathB.cubicTo(632.154663f, 85.02742f, 632.062927f, 85.4251709f, 631.880554f, 85.7326736f);
+ pathB.close();
+ pathB.moveTo(635.667664f, 69.5979919f);
+ pathB.cubicTo(635.518311f, 69.0645142f, 635.325684f, 68.5818329f, 635.093994f, 68.1620941f);
+ pathB.cubicTo(634.940796f, 67.8856812f, 634.770569f, 67.6316376f, 634.586304f, 67.4026184f);
+ pathB.lineTo(635.054565f, 67.2619476f);
+ pathB.cubicTo(635.455322f, 67.1417542f, 635.729858f, 66.7724457f, 635.729858f, 66.3538437f);
+ pathB.lineTo(635.729858f, 64.7021942f);
+ pathB.cubicTo(635.729858f, 64.4045486f, 635.590332f, 64.1243439f, 635.3526f, 63.9449997f);
+ pathB.cubicTo(635.115234f, 63.7660294f, 634.807373f, 63.7087784f, 634.521057f, 63.7906761f);
+ pathB.cubicTo(634.059998f, 63.9226265f, 633.544678f, 64.0155258f, 632.988831f, 64.0659485f);
+ pathB.cubicTo(631.578735f, 64.1941071f, 629.921387f, 64.1565704f, 628.141968f, 64.0632935f);
+ pathB.cubicTo(627.067383f, 64.0068054f, 625.948853f, 63.9779854f, 624.81665f, 63.9779854f);
+ pathB.cubicTo(624.253601f, 63.9779854f, 623.681396f, 64.0359955f, 623.116089f, 64.1512604f);
+ pathB.cubicTo(622.479126f, 64.2809448f, 621.888367f, 64.5437012f, 621.35907f, 64.9315872f);
+ pathB.cubicTo(620.807007f, 65.3365402f, 620.360352f, 65.9159088f, 620.031189f, 66.6548996f);
+ pathB.cubicTo(619.712708f, 67.3722839f, 619.557983f, 68.2625656f, 619.557983f, 69.3769379f);
+ pathB.cubicTo(619.557983f, 70.4655304f, 619.669128f, 71.5268097f, 619.887878f, 72.5323639f);
+ pathB.cubicTo(620.11499f, 73.573555f, 620.473694f, 74.5040283f, 620.954468f, 75.2983856f);
+ pathB.cubicTo(621.196411f, 75.6976471f, 621.693481f, 75.861824f, 622.124939f, 75.6847534f);
+ pathB.lineTo(623.832336f, 74.9851913f);
+ pathB.cubicTo(624.086365f, 74.8809204f, 624.282776f, 74.6716156f, 624.370728f, 74.4111328f);
+ pathB.cubicTo(624.45874f, 74.15065f, 624.429138f, 73.8651276f, 624.290405f, 73.6281509f);
+ pathB.cubicTo(624.166382f, 73.416954f, 624.051147f, 73.1644287f, 623.947205f, 72.875885f);
+ pathB.cubicTo(623.836853f, 72.5702744f, 623.741333f, 72.2407837f, 623.663574f, 71.8968811f);
+ pathB.cubicTo(623.584717f, 71.549942f, 623.522217f, 71.2018585f, 623.477417f, 70.8621292f);
+ pathB.cubicTo(623.434937f, 70.5409775f, 623.41333f, 70.2391663f, 623.41333f, 69.9646454f);
+ pathB.cubicTo(623.41333f, 68.8229752f, 623.672729f, 68.4748993f, 623.75116f, 68.3960266f);
+ pathB.cubicTo(623.853577f, 68.2940369f, 624.20166f, 68.0574341f, 625.236755f, 68.0574341f);
+ pathB.cubicTo(625.39679f, 68.0574341f, 625.566284f, 68.0616074f, 625.744446f, 68.0695648f);
+ pathB.lineTo(625.744446f, 68.7331085f);
+ pathB.cubicTo(625.744446f, 69.8065338f, 625.819153f, 70.8048782f, 625.967041f, 71.70047f);
+ pathB.cubicTo(626.12323f, 72.6483841f, 626.392456f, 73.4825516f, 626.767456f, 74.1794586f);
+ pathB.cubicTo(627.173523f, 74.9328613f, 627.730957f, 75.5292969f, 628.424438f, 75.9528198f);
+ pathB.cubicTo(629.123596f, 76.3790054f, 629.981628f, 76.5951309f, 630.975464f, 76.5951309f);
+ pathB.cubicTo(631.722046f, 76.5951309f, 632.406799f, 76.4597626f, 633.009644f, 76.1924591f);
+ pathB.cubicTo(633.611816f, 75.9262848f, 634.136536f, 75.5543213f, 634.567688f, 75.0875626f);
+ pathB.cubicTo(634.998779f, 74.6223297f, 635.333191f, 74.0672302f, 635.561096f, 73.4370575f);
+ pathB.cubicTo(635.78479f, 72.8212891f, 635.898193f, 72.1520538f, 635.898193f, 71.4479446f);
+ pathB.cubicTo(635.898193f, 70.7688599f, 635.820496f, 70.1462708f, 635.667664f, 69.5979919f);
+ pathB.close();
+ pathB.moveTo(631.656494f, 71.9905396f);
+ pathB.cubicTo(631.416077f, 72.2574692f, 631.13739f, 72.3765259f, 630.751404f, 72.3765259f);
+ pathB.cubicTo(630.390015f, 72.3765259f, 630.239502f, 72.2536774f, 630.190247f, 72.2127228f);
+ pathB.cubicTo(630.002197f, 72.0587845f, 629.853149f, 71.8483429f, 629.735596f, 71.5704193f);
+ pathB.cubicTo(629.594177f, 71.2348557f, 629.494507f, 70.8310394f, 629.439453f, 70.3714905f);
+ pathB.cubicTo(629.379211f, 69.8607559f, 629.348511f, 69.3284073f, 629.348511f, 68.7892303f);
+ pathB.cubicTo(629.348511f, 68.5765228f, 629.351929f, 68.3603973f, 629.357971f, 68.1416168f);
+ pathB.lineTo(630.581177f, 68.1416168f);
+ pathB.cubicTo(630.702515f, 68.2026672f, 630.831787f, 68.2841797f, 630.967163f, 68.3857956f);
+ pathB.cubicTo(631.149902f, 68.523056f, 631.322815f, 68.703537f, 631.480225f, 68.922699f);
+ pathB.cubicTo(631.639038f, 69.1437531f, 631.77478f, 69.4186478f, 631.884399f, 69.7390442f);
+ pathB.cubicTo(631.989807f, 70.0488281f, 632.04364f, 70.4169922f, 632.04364f, 70.8329391f);
+ pathB.cubicTo(632.042847f, 71.3228302f, 631.916565f, 71.7012329f, 631.656494f, 71.9905396f);
+ pathB.close();
+ pathB.moveTo(622.689575f, 63.4953079f);
+ pathB.lineTo(620.72998f, 63.4953079f);
+ pathB.cubicTo(620.206421f, 63.4953079f, 619.782104f, 63.0710182f, 619.782104f, 62.54739f);
+ pathB.lineTo(619.782104f, 61.3116837f);
+ pathB.lineTo(617.958679f, 61.3116837f);
+ pathB.cubicTo(617.536255f, 61.3116837f, 617.164307f, 61.0318604f, 617.047913f, 60.6257744f);
+ pathB.lineTo(616.404114f, 58.3864136f);
+ pathB.cubicTo(616.321411f, 58.1001472f, 616.378662f, 57.7922592f, 616.557678f, 57.5541458f);
+ pathB.cubicTo(616.737061f, 57.3164062f, 617.017212f, 57.1764946f, 617.31488f, 57.1764946f);
+ pathB.lineTo(619.782104f, 57.1764946f);
+ pathB.lineTo(619.782104f, 54.3171997f);
+ pathB.cubicTo(619.782104f, 53.7935715f, 620.206421f, 53.3692818f, 620.730042f, 53.3692818f);
+ pathB.lineTo(622.689575f, 53.3692818f);
+ pathB.cubicTo(623.213196f, 53.3692818f, 623.637512f, 53.7935715f, 623.637512f, 54.3171997f);
+ pathB.lineTo(623.637512f, 57.1764946f);
+ pathB.lineTo(630.443176f, 57.1764946f);
+ pathB.cubicTo(631.548828f, 57.1764946f, 631.921936f, 57.0028381f, 632.009888f, 56.9493713f);
+ pathB.cubicTo(632.057617f, 56.9205589f, 632.154724f, 56.8621674f, 632.154724f, 56.5288773f);
+ pathB.cubicTo(632.154724f, 56.139473f, 632.116821f, 55.8179398f, 632.04248f, 55.5737572f);
+ pathB.cubicTo(631.949219f, 55.268528f, 631.822205f, 54.9193192f, 631.665588f, 54.5363579f);
+ pathB.cubicTo(631.563599f, 54.288002f, 631.572327f, 54.0085602f, 631.688354f, 53.7670288f);
+ pathB.cubicTo(631.804749f, 53.5251198f, 632.017456f, 53.3438797f, 632.274536f, 53.2680435f);
+ pathB.lineTo(633.9823f, 52.7641296f);
+ pathB.cubicTo(634.430115f, 52.6325607f, 634.90332f, 52.8437576f, 635.105042f, 53.2623596f);
+ pathB.cubicTo(635.375f, 53.8235245f, 635.59491f, 54.4404297f, 635.758301f, 55.0956268f);
+ pathB.cubicTo(635.925537f, 55.7656174f, 636.010498f, 56.4928589f, 636.010498f, 57.2565002f);
+ pathB.cubicTo(636.010498f, 58.7109833f, 635.553589f, 59.7790947f, 634.653076f, 60.4316406f);
+ pathB.cubicTo(633.835938f, 61.0235176f, 632.596069f, 61.311306f, 630.863647f, 61.311306f);
+ pathB.lineTo(623.637878f, 61.311306f);
+ pathB.lineTo(623.637878f, 62.5470123f);
+ pathB.cubicTo(623.637451f, 63.071022f, 623.213196f, 63.4953079f, 622.689575f, 63.4953079f);
+ pathB.close();
+ pathB.moveTo(635.667664f, 46.2246475f);
+ pathB.cubicTo(635.518311f, 45.6911545f, 635.325684f, 45.2084808f, 635.093994f, 44.7887421f);
+ pathB.cubicTo(634.940796f, 44.5123291f, 634.770569f, 44.2582855f, 634.586304f, 44.029274f);
+ pathB.lineTo(635.054565f, 43.8886032f);
+ pathB.cubicTo(635.455322f, 43.7684059f, 635.729858f, 43.3990974f, 635.729858f, 42.9804955f);
+ pathB.lineTo(635.729858f, 41.328846f);
+ pathB.cubicTo(635.729858f, 41.0312004f, 635.590332f, 40.7509995f, 635.3526f, 40.5716515f);
+ pathB.cubicTo(635.115234f, 40.3926849f, 634.807373f, 40.3354301f, 634.521057f, 40.4173279f);
+ pathB.cubicTo(634.059998f, 40.5492783f, 633.544678f, 40.6421738f, 632.988831f, 40.6926041f);
+ pathB.cubicTo(631.578735f, 40.8207626f, 629.921387f, 40.7836075f, 628.141968f, 40.689949f);
+ pathB.cubicTo(627.067383f, 40.6334534f, 625.948853f, 40.6046371f, 624.81665f, 40.6046371f);
+ pathB.cubicTo(624.253601f, 40.6046371f, 623.681396f, 40.6626511f, 623.116089f, 40.777916f);
+ pathB.cubicTo(622.479126f, 40.9075928f, 621.888367f, 41.1703568f, 621.35907f, 41.5582428f);
+ pathB.cubicTo(620.807007f, 41.963192f, 620.360352f, 42.5425606f, 620.031189f, 43.2815552f);
+ pathB.cubicTo(619.712708f, 43.9989395f, 619.557983f, 44.8892212f, 619.557983f, 46.0035934f);
+ pathB.cubicTo(619.557983f, 47.0921783f, 619.669128f, 48.1534653f, 619.887878f, 49.1590195f);
+ pathB.cubicTo(620.11499f, 50.2002106f, 620.473694f, 51.1306839f, 620.954468f, 51.9250374f);
+ pathB.cubicTo(621.196411f, 52.3243027f, 621.693481f, 52.4880981f, 622.124939f, 52.311409f);
+ pathB.lineTo(623.832336f, 51.6118431f);
+ pathB.cubicTo(624.086365f, 51.5075722f, 624.282776f, 51.2982712f, 624.370728f, 51.0377846f);
+ pathB.cubicTo(624.45874f, 50.777298f, 624.429138f, 50.4917831f, 624.290405f, 50.2548065f);
+ pathB.cubicTo(624.166382f, 50.0436096f, 624.051147f, 49.7910843f, 623.947205f, 49.5025406f);
+ pathB.cubicTo(623.836853f, 49.1969299f, 623.741333f, 48.8674355f, 623.663574f, 48.5235291f);
+ pathB.cubicTo(623.584717f, 48.1765938f, 623.522217f, 47.8285179f, 623.477417f, 47.4887848f);
+ pathB.cubicTo(623.434937f, 47.1676331f, 623.41333f, 46.8658142f, 623.41333f, 46.5912971f);
+ pathB.cubicTo(623.41333f, 45.4496269f, 623.672729f, 45.1015511f, 623.75116f, 45.0226822f);
+ pathB.cubicTo(623.853577f, 44.9206886f, 624.20166f, 44.6840897f, 625.236755f, 44.6840897f);
+ pathB.cubicTo(625.39679f, 44.6840897f, 625.566284f, 44.6882591f, 625.744446f, 44.6962204f);
+ pathB.lineTo(625.744446f, 45.3597641f);
+ pathB.cubicTo(625.744446f, 46.4331856f, 625.819153f, 47.43153f, 625.967041f, 48.3271217f);
+ pathB.cubicTo(626.12323f, 49.2750397f, 626.392456f, 50.1092072f, 626.767456f, 50.8061142f);
+ pathB.cubicTo(627.173523f, 51.5595169f, 627.730957f, 52.1559486f, 628.424438f, 52.5794754f);
+ pathB.cubicTo(629.123596f, 53.005661f, 629.981628f, 53.2217865f, 630.975464f, 53.2217865f);
+ pathB.cubicTo(631.722046f, 53.2217865f, 632.406799f, 53.086422f, 633.009644f, 52.8191147f);
+ pathB.cubicTo(633.611816f, 52.5529366f, 634.136536f, 52.1809769f, 634.567688f, 51.7142181f);
+ pathB.cubicTo(634.998779f, 51.2489815f, 635.333191f, 50.693882f, 635.561096f, 50.0637054f);
+ pathB.cubicTo(635.78479f, 49.4479408f, 635.898193f, 48.7787094f, 635.898193f, 48.0746002f);
+ pathB.cubicTo(635.898193f, 47.3958893f, 635.820496f, 46.7733002f, 635.667664f, 46.2246475f);
+ pathB.close();
+ pathB.moveTo(631.656494f, 48.6171875f);
+ pathB.cubicTo(631.416077f, 48.8841209f, 631.13739f, 49.0031815f, 630.751404f, 49.0031815f);
+ pathB.cubicTo(630.390015f, 49.0031815f, 630.239502f, 48.8803291f, 630.190247f, 48.8393784f);
+ pathB.cubicTo(630.002197f, 48.6854401f, 629.853149f, 48.4749985f, 629.735596f, 48.1970711f);
+ pathB.cubicTo(629.594177f, 47.8615112f, 629.494507f, 47.457695f, 629.439453f, 46.9981461f);
+ pathB.cubicTo(629.379211f, 46.4874115f, 629.348511f, 45.9550591f, 629.348511f, 45.4158859f);
+ pathB.cubicTo(629.348511f, 45.2031708f, 629.351929f, 44.9870453f, 629.357971f, 44.7682648f);
+ pathB.lineTo(630.581177f, 44.7682648f);
+ pathB.cubicTo(630.702515f, 44.8293152f, 630.831787f, 44.9108353f, 630.967163f, 45.0124512f);
+ pathB.cubicTo(631.149902f, 45.1497116f, 631.322815f, 45.3301926f, 631.480225f, 45.5493507f);
+ pathB.cubicTo(631.639038f, 45.7704048f, 631.77478f, 46.0453033f, 631.884399f, 46.3656998f);
+ pathB.cubicTo(631.989807f, 46.6754761f, 632.04364f, 47.0436478f, 632.04364f, 47.4595947f);
+ pathB.cubicTo(632.042847f, 47.949852f, 631.916565f, 48.3282623f, 631.656494f, 48.6171875f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// SkOpAngle::setSector SkASSERT(fSectorStart >= 0);
+static void skpwww_seopack_blogspot_com_2153(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(999.892212f, 246);
+ path.lineTo(927.340759f, 245.505722f);
+ path.quadTo(928.068054f, 246, 929, 246);
+ path.lineTo(999.892212f, 246);
+ path.close();
+ path.moveTo(927.340759f, 245.505722f);
+ path.lineTo(926.5f, 245.5f);
+ path.lineTo(925.17157f, 246.82843f);
+ path.quadTo(926.34314f, 248, 928, 248);
+ path.lineTo(1000, 248);
+ path.lineTo(1000, 246);
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(924, 248);
+ pathB.lineTo(924, 245.472672f);
+ pathB.lineTo(1143, 247);
+ pathB.lineTo(1143, 248);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// joinCoincidence / findT / assert
+static void skpwww_lokado_de_173(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1000, 896.991394f);
+ path.quadTo(999.789917f, 896.718872f, 999.535522f, 896.464478f);
+ path.quadTo(998.071045f, 895, 996, 895);
+ path.lineTo(956, 895);
+ path.quadTo(951.857849f, 895, 948.928955f, 897.928955f);
+ path.quadTo(946, 900.857849f, 946, 905);
+ path.lineTo(946, 906);
+ path.quadTo(946, 910.142151f, 948.928955f, 913.071045f);
+ path.quadTo(951.857849f, 916, 956, 916);
+ path.lineTo(996, 916);
+ path.quadTo(998.071045f, 916, 999.535522f, 914.535522f);
+ path.quadTo(999.789917f, 914.281128f, 1000, 914.008606f);
+ path.lineTo(1000, 896.991394f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(946, 906);
+ pathB.lineTo(946, 905);
+ pathB.quadTo(946, 901.272095f, 948.928955f, 898.636047f);
+ pathB.quadTo(951.857849f, 896, 956, 896);
+ pathB.lineTo(996, 896);
+ pathB.quadTo(998.071045f, 896, 999.535522f, 897.17157f);
+ pathB.quadTo(1001, 898.34314f, 1001, 900);
+ pathB.lineTo(1001, 911);
+ pathB.quadTo(1001, 913.071045f, 999.535522f, 914.535522f);
+ pathB.quadTo(998.071045f, 916, 996, 916);
+ pathB.lineTo(956, 916);
+ pathB.quadTo(951.857849f, 916, 948.928955f, 913.071045f);
+ pathB.quadTo(946, 910.142151f, 946, 906);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+// !simple->isClosed()
+static void skpwww_wartepop_blogspot_com_br_6(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(90.9763107f, 153.309662f);
+ path.quadTo(91.9526215f, 152.333344f, 93.3333359f, 152.333344f);
+ path.lineTo(124.666664f, 152.333344f);
+ path.quadTo(126.047379f, 152.333344f, 127.023689f, 153.309662f);
+ path.quadTo(128, 154.285965f, 128, 155.666672f);
+ path.lineTo(128, 163.666672f);
+ path.lineTo(90, 163.666672f);
+ path.lineTo(90, 155.666672f);
+ path.quadTo(90, 154.285965f, 90.9763107f, 153.309662f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(90, 163.666672f);
+ pathB.lineTo(90, 155.666672f);
+ pathB.quadTo(90, 154.285965f, 90.9763107f, 153.309662f);
+ pathB.quadTo(91.9526215f, 152.333344f, 93.3333359f, 152.333344f);
+ pathB.lineTo(124.666672f, 152.333344f);
+ pathB.quadTo(125.909309f, 152.333344f, 126.787994f, 153.309662f);
+ pathB.quadTo(127.666672f, 154.285965f, 127.666672f, 155.666672f);
+ pathB.lineTo(127.666672f, 163.666672f);
+ pathB.lineTo(127.666672f, 163.666672f);
+ pathB.lineTo(127.666672f, 163.666672f);
+ pathB.lineTo(90, 163.666672f);
+ pathB.lineTo(90, 163.666672f);
+ pathB.lineTo(90, 163.666672f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void skpwww_wartepop_blogspot_com_br_6a(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(90.9763107f, 153.309662f);
+ path.quadTo(91.9526215f, 152.333344f, 93.3333359f, 152.333344f);
+ path.lineTo(124.666672f, 152.333344f);
+ path.quadTo(126.047379f, 152.333344f, 127.023689f, 153.309662f);
+ path.quadTo(128, 154.285965f, 128, 155.666672f);
+ path.lineTo(128, 163.666672f);
+ path.lineTo(90, 163.666672f);
+ path.lineTo(90, 155.666672f);
+ path.quadTo(90, 154.285965f, 90.9763107f, 153.309662f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(90, 163.666672f);
+ pathB.lineTo(90, 155.666672f);
+ pathB.quadTo(90, 154.285965f, 90.9763107f, 153.309662f);
+ pathB.quadTo(91.9526215f, 152.333344f, 93.3333359f, 152.333344f);
+ pathB.lineTo(124.666672f, 152.333344f);
+ pathB.quadTo(125.909309f, 152.333344f, 126.787994f, 153.309662f);
+ pathB.quadTo(127.666672f, 154.285965f, 127.666672f, 155.666672f);
+ pathB.lineTo(127.666672f, 163.666672f);
+ pathB.lineTo(127.666672f, 163.666672f);
+ pathB.lineTo(127.666672f, 163.666672f);
+ pathB.lineTo(90, 163.666672f);
+ pathB.lineTo(90, 163.666672f);
+ pathB.lineTo(90, 163.666672f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+// !simple->isClosed()
+static void skpwww_odia_com_br_26(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(360.740479f, 741.040771f);
+ path.quadTo(360.378967f, 741, 360, 741);
+ path.quadTo(359.159821f, 741, 358.403076f, 741.200745f);
+ path.quadTo(357.649658f, 741.415833f, 356.92746f, 741.846436f);
+ path.quadTo(356.600769f, 742.041199f, 356.310211f, 742.262268f);
+ path.quadTo(356.025513f, 742.489197f, 355.757355f, 742.757385f);
+ path.quadTo(355.16394f, 743.350769f, 354.770874f, 744.027283f);
+ path.quadTo(354.389618f, 744.71283f, 354.183258f, 745.528564f);
+ path.quadTo(354.090027f, 745.897095f, 354.040833f, 746.259277f);
+ path.quadTo(354, 746.621216f, 354, 747);
+ path.quadTo(354, 747.839844f, 354.200653f, 748.596497f);
+ path.quadTo(354.415771f, 749.35022f, 354.846466f, 750.072632f);
+ path.quadTo(355.040741f, 750.398438f, 355.261444f, 750.688721f);
+ path.quadTo(355.488861f, 750.974121f, 355.757355f, 751.242615f);
+ path.quadTo(356.352142f, 751.837402f, 357.030304f, 752.230896f);
+ path.quadTo(357.714539f, 752.610901f, 358.528564f, 752.816833f);
+ path.quadTo(358.895294f, 752.909607f, 359.25528f, 752.95874f);
+ path.quadTo(359.618896f, 753, 360, 753);
+ path.quadTo(360.842285f, 753, 361.600952f, 752.798157f);
+ path.quadTo(362.352386f, 752.583008f, 363.072601f, 752.153625f);
+ path.quadTo(363.397339f, 751.960022f, 363.686829f, 751.740051f);
+ path.quadTo(363.973297f, 751.511963f, 364.242645f, 751.242615f);
+ path.quadTo(364.837799f, 750.647461f, 365.231354f, 749.968933f);
+ path.quadTo(365.610992f, 749.285034f, 365.816803f, 748.471497f);
+ path.quadTo(365.909668f, 748.104431f, 365.958832f, 747.743713f);
+ path.quadTo(366, 747.380371f, 366, 747);
+ path.quadTo(366, 746.158997f, 365.798767f, 745.401367f);
+ path.quadTo(365.583618f, 744.648682f, 365.153595f, 743.927429f);
+ path.quadTo(364.959442f, 743.601807f, 364.738678f, 743.311462f);
+ path.quadTo(364.511108f, 743.025818f, 364.242645f, 742.757385f);
+ path.quadTo(363.649017f, 742.163757f, 362.972168f, 741.770569f);
+ path.quadTo(362.286835f, 741.389526f, 361.471497f, 741.183289f);
+ path.quadTo(361.102509f, 741.089966f, 360.740479f, 741.040771f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(355.654724f, 739.711792f);
+ pathB.lineTo(367.288269f, 742.654724f);
+ pathB.lineTo(364.345337f, 754.288269f);
+ pathB.lineTo(352.711792f, 751.345337f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_evolvehq_com_210(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(172, 972);
+ path.quadTo(170.757355f, 972, 169.878677f, 972.878662f);
+ path.quadTo(169, 973.757385f, 169, 975);
+ path.lineTo(169, 1171);
+ path.quadTo(169, 1172.24268f, 169.878677f, 1173.12134f);
+ path.quadTo(170.757355f, 1174, 172, 1174);
+ path.lineTo(308, 1174);
+ path.quadTo(309.242645f, 1174, 310.121307f, 1173.12134f);
+ path.quadTo(310.337311f, 1172.9054f, 310.5f, 1172.66772f);
+ path.lineTo(310.5f, 973.332336f);
+ path.quadTo(310.337219f, 973.094604f, 310.121307f, 972.878662f);
+ path.quadTo(309.242645f, 972, 308, 972);
+ path.lineTo(172, 972);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(170, 1171);
+ pathB.lineTo(170, 975);
+ pathB.quadTo(170, 974.17157f, 170.585785f, 973.585815f);
+ pathB.quadTo(171.17157f, 973, 172, 973);
+ pathB.lineTo(308, 973);
+ pathB.quadTo(309.242645f, 973, 310.121307f, 973.585815f);
+ pathB.quadTo(311, 974.17157f, 311, 975);
+ pathB.lineTo(311, 1171);
+ pathB.quadTo(311, 1172.24268f, 310.121307f, 1173.12134f);
+ pathB.quadTo(309.242645f, 1174, 308, 1174);
+ pathB.lineTo(172, 1174);
+ pathB.quadTo(171.17157f, 1174, 170.585785f, 1173.12134f);
+ pathB.quadTo(170, 1172.24268f, 170, 1171);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+// hangs
+static void skpwww_catingueiraonline_com_352(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(443, 8292);
+ path.lineTo(443, 8140);
+ path.lineTo(444, 8140);
+ path.lineTo(444.01001f, 8292);
+ path.lineTo(443, 8292);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(443, 8140);
+ pathB.lineTo(444.01001f, 8140);
+ pathB.lineTo(444, 8292);
+ pathB.lineTo(443, 8292);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// hangs
+static void skpwww_galaxystwo_com_4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(10105, 2510);
+ path.lineTo(10123, 2509.98999f);
+ path.lineTo(10123, 2511);
+ path.lineTo(10105, 2511);
+ path.lineTo(10105, 2510);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(10105, 2511);
+ pathB.lineTo(10105, 2509.98999f);
+ pathB.lineTo(10123, 2510);
+ pathB.lineTo(10123, 2511);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_thaienews_blogspot_com_36(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(429.994995f, 6268);
+ path.lineTo(430, 2187);
+ path.lineTo(430.5f, 2187);
+ path.lineTo(430.5f, 6268);
+ path.lineTo(429.994995f, 6268);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(430.5f, 2187);
+ pathB.lineTo(429.994995f, 2187);
+ pathB.lineTo(430, 6268);
+ pathB.lineTo(430.5f, 6268);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_fashionscandal_com_94(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(25.9107456f, 272.577423f);
+ path.quadTo(26.1548233f, 272.333344f, 26.5000019f, 272.333344f);
+ path.lineTo(131.166672f, 272.333344f);
+ path.quadTo(131.511841f, 272.333344f, 131.75592f, 272.577423f);
+ path.quadTo(132, 272.821503f, 132, 273.166687f);
+ path.lineTo(132, 417.166656f);
+ path.quadTo(132, 417.511841f, 131.75592f, 417.75592f);
+ path.quadTo(131.511841f, 418, 131.166672f, 418);
+ path.lineTo(26.5000019f, 418);
+ path.quadTo(26.1548233f, 418, 25.9107456f, 417.75592f);
+ path.quadTo(25.6666679f, 417.511841f, 25.6666679f, 417.166656f);
+ path.lineTo(25.6666679f, 273.166687f);
+ path.quadTo(25.6666679f, 272.821503f, 25.9107456f, 272.577423f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(25.833334f, 417.166656f);
+ pathB.lineTo(25.833334f, 273.166656f);
+ pathB.quadTo(25.833334f, 272.890533f, 26.0285969f, 272.695251f);
+ pathB.quadTo(26.2238579f, 272.5f, 26.5f, 272.5f);
+ pathB.lineTo(131.166672f, 272.5f);
+ pathB.quadTo(131.442825f, 272.5f, 131.638077f, 272.695251f);
+ pathB.quadTo(131.833344f, 272.890533f, 131.833344f, 273.166656f);
+ pathB.lineTo(131.833344f, 417.166656f);
+ pathB.quadTo(131.833344f, 417.511841f, 131.638077f, 417.75592f);
+ pathB.quadTo(131.442825f, 418, 131.166672f, 418);
+ pathB.lineTo(26.5f, 418);
+ pathB.quadTo(26.2238579f, 418, 26.0285969f, 417.75592f);
+ pathB.quadTo(25.833334f, 417.511841f, 25.833334f, 417.166656f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
+}
+
+static void skpwww_kenlevine_blogspot_com_28(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(276, 9506);
+ path.lineTo(276, 7531);
+ path.lineTo(277, 7531);
+ path.lineTo(277.01001f, 9506);
+ path.lineTo(276, 9506);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(276, 7531);
+ pathB.lineTo(277.01001f, 7531);
+ pathB.lineTo(277, 9506);
+ pathB.lineTo(276, 9506);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_defense_studies_blogspot_com_64(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(276, 9600);
+ path.lineTo(276, 7703);
+ path.lineTo(277, 7703);
+ path.lineTo(277.01001f, 9600);
+ path.lineTo(276, 9600);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(276, 7703);
+ pathB.lineTo(277.01001f, 7703);
+ pathB.lineTo(277, 9600);
+ pathB.lineTo(276, 9600);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_uniquefx_net_442(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(960, 306);
+ path.lineTo(960, 305);
+ path.lineTo(1000, 305);
+ path.lineTo(1000, 306.708527f);
+ path.lineTo(960, 306);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(960, 305);
+ pathB.lineTo(958.997253f, 306.002747f);
+ pathB.lineTo(1017, 307);
+ pathB.lineTo(1019, 305);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_kitcheninspirations_wordpress_com_32(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(47.1666679f, 19651.334f);
+ path.lineTo(65.8333359f, 19651.332f);
+ path.lineTo(65.8333359f, 19651.5f);
+ path.lineTo(47.1666679f, 19651.5f);
+ path.lineTo(47.1666679f, 19651.334f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(47.1666679f, 19651.5f);
+ pathB.lineTo(47.1666679f, 19651.332f);
+ pathB.lineTo(65.8333359f, 19651.334f);
+ pathB.lineTo(65.8333359f, 19651.5f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_educationalcraft_com_4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(941, 1494);
+ path.lineTo(941, 1464);
+ path.lineTo(985, 1464);
+ path.lineTo(985, 1494);
+ path.lineTo(941, 1494);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(979.211975f, 1480.45496f);
+ pathB.cubicTo(979.211975f, 1480.45496f, 976.348999f, 1479.68506f, 977.495972f, 1475.59497f);
+ pathB.cubicTo(977.497009f, 1475.59497f, 981.072021f, 1477.88501f, 979.211975f, 1480.45496f);
+ pathB.close();
+ pathB.moveTo(977.854004f, 1484.453f);
+ pathB.cubicTo(977.854004f, 1484.453f, 975.265991f, 1483.26099f, 976.713989f, 1479.35205f);
+ pathB.cubicTo(976.713989f, 1479.35303f, 979.84198f, 1482.23499f, 977.854004f, 1484.453f);
+ pathB.close();
+ pathB.moveTo(980.226013f, 1476.229f);
+ pathB.cubicTo(980.226013f, 1476.229f, 977.078003f, 1476.349f, 977.234985f, 1471.97095f);
+ pathB.cubicTo(977.234985f, 1471.97095f, 980.666992f, 1473.12903f, 980.226013f, 1476.229f);
+ pathB.close();
+ pathB.moveTo(984.546021f, 1478.31494f);
+ pathB.cubicTo(984.546021f, 1478.31494f, 983.187988f, 1481.93396f, 980.026001f, 1481.276f);
+ pathB.cubicTo(980.026978f, 1481.276f, 979.554993f, 1478.38904f, 984.546021f, 1478.31494f);
+ pathB.close();
+ pathB.moveTo(978.989014f, 1484.198f);
+ pathB.cubicTo(978.989014f, 1484.198f, 979.094971f, 1481.33496f, 983.786011f, 1481.823f);
+ pathB.cubicTo(983.786011f, 1481.823f, 982.070007f, 1485.49805f, 978.989014f, 1484.198f);
+ pathB.close();
+ pathB.moveTo(976.393005f, 1486.86804f);
+ pathB.cubicTo(976.393005f, 1486.86804f, 976.719971f, 1484.06494f, 981.679016f, 1485.37f);
+ pathB.cubicTo(981.679016f, 1485.37f, 979.169983f, 1488.40796f, 976.393005f, 1486.86804f);
+ pathB.close();
+ pathB.moveTo(969.156982f, 1490.40002f);
+ pathB.cubicTo(969.156982f, 1490.40002f, 971.478027f, 1488.23596f, 974.869995f, 1491.21399f);
+ pathB.cubicTo(974.869995f, 1491.21497f, 970.828003f, 1493.026f, 969.156982f, 1490.40002f);
+ pathB.close();
+ pathB.moveTo(972.825012f, 1483.93701f);
+ pathB.cubicTo(972.825012f, 1483.93701f, 973.971985f, 1487.98401f, 971.161987f, 1488.94604f);
+ pathB.cubicTo(971.161987f, 1488.94495f, 969.278015f, 1486.37097f, 972.825012f, 1483.93701f);
+ pathB.close();
+ pathB.moveTo(965.60199f, 1489.98499f);
+ pathB.cubicTo(965.60199f, 1489.98499f, 964.879028f, 1487.19202f, 969.864014f, 1486.75f);
+ pathB.cubicTo(969.864014f, 1486.75f, 968.749023f, 1490.672f, 965.60199f, 1489.98499f);
+ pathB.close();
+ pathB.moveTo(970.666992f, 1492.81604f);
+ pathB.cubicTo(970.666992f, 1492.81604f, 967.327026f, 1494.49695f, 964.999023f, 1491.56299f);
+ pathB.cubicTo(964.999023f, 1491.56299f, 967.304016f, 1489.43896f, 970.666992f, 1492.81604f);
+ pathB.close();
+ pathB.moveTo(968.343994f, 1481.53796f);
+ pathB.cubicTo(971.573975f, 1479.94995f, 971.687988f, 1476.78601f, 971.687988f, 1476.78601f);
+ pathB.lineTo(971.393982f, 1466.83398f);
+ pathB.lineTo(954.960999f, 1466.83398f);
+ pathB.lineTo(954.666016f, 1476.78601f);
+ pathB.cubicTo(954.666016f, 1476.78601f, 954.780029f, 1479.94995f, 958.008972f, 1481.53796f);
+ pathB.cubicTo(960.781006f, 1482.90295f, 962.166992f, 1484.77698f, 962.166992f, 1484.77698f);
+ pathB.cubicTo(962.166992f, 1484.77698f, 962.747986f, 1485.70105f, 963.177979f, 1485.70105f);
+ pathB.cubicTo(963.606995f, 1485.70105f, 964.185974f, 1484.77698f, 964.185974f, 1484.77698f);
+ pathB.cubicTo(964.185974f, 1484.77698f, 965.573975f, 1482.90295f, 968.343994f, 1481.53796f);
+ pathB.close();
+ pathB.moveTo(963.215027f, 1486.67004f);
+ pathB.cubicTo(962.744995f, 1486.67004f, 962.106995f, 1485.65405f, 962.106995f, 1485.65405f);
+ pathB.cubicTo(962.106995f, 1485.65405f, 960.585022f, 1483.59595f, 957.539001f, 1482.09705f);
+ pathB.cubicTo(953.991028f, 1480.35205f, 953.867004f, 1476.87598f, 953.867004f, 1476.87598f);
+ pathB.lineTo(954.190002f, 1465.94397f);
+ pathB.lineTo(972.23999f, 1465.94397f);
+ pathB.lineTo(972.565002f, 1476.87695f);
+ pathB.cubicTo(972.565002f, 1476.87695f, 972.440979f, 1480.35303f, 968.891968f, 1482.09802f);
+ pathB.cubicTo(965.846008f, 1483.59705f, 964.325012f, 1485.65503f, 964.325012f, 1485.65503f);
+ pathB.cubicTo(964.325012f, 1485.65503f, 963.687012f, 1486.67004f, 963.215027f, 1486.67004f);
+ pathB.close();
+ pathB.moveTo(960.68103f, 1489.98499f);
+ pathB.cubicTo(957.533997f, 1490.672f, 956.417969f, 1486.75f, 956.417969f, 1486.75f);
+ pathB.cubicTo(961.403015f, 1487.19202f, 960.68103f, 1489.98499f, 960.68103f, 1489.98499f);
+ pathB.close();
+ pathB.moveTo(963.143005f, 1489.59802f);
+ pathB.cubicTo(963.763f, 1489.59802f, 964.265015f, 1490.09998f, 964.265015f, 1490.72095f);
+ pathB.cubicTo(964.265015f, 1491.34204f, 963.763f, 1491.84399f, 963.143005f, 1491.84399f);
+ pathB.cubicTo(962.521973f, 1491.84399f, 962.02002f, 1491.34204f, 962.02002f, 1490.72095f);
+ pathB.cubicTo(962.02002f, 1490.09998f, 962.521973f, 1489.59802f, 963.143005f, 1489.59802f);
+ pathB.close();
+ pathB.moveTo(961.283997f, 1491.56299f);
+ pathB.cubicTo(958.953979f, 1494.49695f, 955.61499f, 1492.81604f, 955.61499f, 1492.81604f);
+ pathB.cubicTo(958.97699f, 1489.43896f, 961.283997f, 1491.56299f, 961.283997f, 1491.56299f);
+ pathB.close();
+ pathB.moveTo(957.127014f, 1490.40002f);
+ pathB.cubicTo(955.455017f, 1493.026f, 951.414001f, 1491.21399f, 951.414001f, 1491.21399f);
+ pathB.cubicTo(954.802979f, 1488.23596f, 957.127014f, 1490.40002f, 957.127014f, 1490.40002f);
+ pathB.close();
+ pathB.moveTo(949.890991f, 1486.86804f);
+ pathB.cubicTo(947.112976f, 1488.40796f, 944.604004f, 1485.37f, 944.604004f, 1485.37f);
+ pathB.cubicTo(949.562012f, 1484.06494f, 949.890991f, 1486.86804f, 949.890991f, 1486.86804f);
+ pathB.close();
+ pathB.moveTo(947.070984f, 1480.45496f);
+ pathB.cubicTo(945.211975f, 1477.88501f, 948.786011f, 1475.59497f, 948.786011f, 1475.59497f);
+ pathB.cubicTo(949.934021f, 1479.68506f, 947.070984f, 1480.45496f, 947.070984f, 1480.45496f);
+ pathB.close();
+ pathB.moveTo(946.054016f, 1476.229f);
+ pathB.cubicTo(945.61499f, 1473.12903f, 949.046997f, 1471.97095f, 949.046997f, 1471.97095f);
+ pathB.cubicTo(949.205994f, 1476.349f, 946.054016f, 1476.229f, 946.054016f, 1476.229f);
+ pathB.close();
+ pathB.moveTo(948.427002f, 1484.453f);
+ pathB.cubicTo(946.440002f, 1482.23499f, 949.567993f, 1479.35205f, 949.567993f, 1479.35205f);
+ pathB.cubicTo(951.015991f, 1483.26099f, 948.427002f, 1484.453f, 948.427002f, 1484.453f);
+ pathB.close();
+ pathB.moveTo(947.294006f, 1484.198f);
+ pathB.cubicTo(944.210999f, 1485.49805f, 942.495972f, 1481.823f, 942.495972f, 1481.823f);
+ pathB.cubicTo(947.187988f, 1481.33496f, 947.294006f, 1484.198f, 947.294006f, 1484.198f);
+ pathB.close();
+ pathB.moveTo(946.255005f, 1481.276f);
+ pathB.cubicTo(943.094971f, 1481.93396f, 941.736023f, 1478.31494f, 941.736023f, 1478.31494f);
+ pathB.cubicTo(946.728027f, 1478.38904f, 946.255005f, 1481.276f, 946.255005f, 1481.276f);
+ pathB.close();
+ pathB.moveTo(945.312988f, 1478.18005f);
+ pathB.cubicTo(942.052979f, 1477.80103f, 942.651001f, 1473.87805f, 942.651001f, 1473.87805f);
+ pathB.cubicTo(946.562988f, 1475.66199f, 945.312988f, 1478.18005f, 945.312988f, 1478.18005f);
+ pathB.close();
+ pathB.moveTo(945.382019f, 1474.328f);
+ pathB.cubicTo(942.924011f, 1472.729f, 944.492004f, 1469.48706f, 944.492004f, 1469.48706f);
+ pathB.cubicTo(947.388977f, 1471.95703f, 945.382019f, 1474.328f, 945.382019f, 1474.328f);
+ pathB.close();
+ pathB.moveTo(946.797974f, 1470.27405f);
+ pathB.cubicTo(944.664978f, 1467.90198f, 947.083984f, 1465.50598f, 947.083984f, 1465.50598f);
+ pathB.cubicTo(949.145996f, 1468.82605f, 946.797974f, 1470.27405f, 946.797974f, 1470.27405f);
+ pathB.close();
+ pathB.moveTo(947.392029f, 1471.64197f);
+ pathB.cubicTo(947.624023f, 1468.56299f, 951.361023f, 1468.29199f, 951.361023f, 1468.29199f);
+ pathB.cubicTo(950.554016f, 1471.98499f, 947.392029f, 1471.64197f, 947.392029f, 1471.64197f);
+ pathB.close();
+ pathB.moveTo(948.64801f, 1468.15002f);
+ pathB.cubicTo(948.638977f, 1465.22095f, 952.265991f, 1464.46399f, 952.265991f, 1464.46399f);
+ pathB.cubicTo(951.672974f, 1468.53101f, 948.64801f, 1468.15002f, 948.64801f, 1468.15002f);
+ pathB.close();
+ pathB.moveTo(951.176025f, 1486.97803f);
+ pathB.cubicTo(948.963013f, 1484.62f, 951.361023f, 1481.77698f, 951.361023f, 1481.77698f);
+ pathB.cubicTo(953.734985f, 1485.48596f, 951.176025f, 1486.97803f, 951.176025f, 1486.97803f);
+ pathB.close();
+ pathB.moveTo(947.51001f, 1488.53101f);
+ pathB.cubicTo(947.51001f, 1488.53101f, 951.596985f, 1486.32202f, 953.234009f, 1489.08997f);
+ pathB.cubicTo(953.234009f, 1489.08997f, 951.158997f, 1491.03601f, 947.51001f, 1488.53101f);
+ pathB.close();
+ pathB.moveTo(955.120972f, 1488.94495f);
+ pathB.cubicTo(952.309021f, 1487.98303f, 953.458984f, 1483.93604f, 953.458984f, 1483.93604f);
+ pathB.cubicTo(957.004028f, 1486.37097f, 955.120972f, 1488.94495f, 955.120972f, 1488.94495f);
+ pathB.close();
+ pathB.moveTo(978.770996f, 1488.53101f);
+ pathB.cubicTo(975.122986f, 1491.03601f, 973.047974f, 1489.08997f, 973.047974f, 1489.08997f);
+ pathB.cubicTo(974.684998f, 1486.32202f, 978.770996f, 1488.53101f, 978.770996f, 1488.53101f);
+ pathB.close();
+ pathB.moveTo(975.106995f, 1486.97803f);
+ pathB.cubicTo(975.106995f, 1486.97803f, 972.546997f, 1485.48706f, 974.919983f, 1481.77698f);
+ pathB.cubicTo(974.919983f, 1481.776f, 977.31897f, 1484.61902f, 975.106995f, 1486.97803f);
+ pathB.close();
+ pathB.moveTo(974.016968f, 1464.46399f);
+ pathB.cubicTo(974.016968f, 1464.46399f, 977.643982f, 1465.22095f, 977.633972f, 1468.15002f);
+ pathB.cubicTo(977.633972f, 1468.15002f, 974.611023f, 1468.53101f, 974.016968f, 1464.46399f);
+ pathB.close();
+ pathB.moveTo(974.919983f, 1468.29199f);
+ pathB.cubicTo(974.919983f, 1468.29199f, 978.658997f, 1468.56299f, 978.890015f, 1471.64197f);
+ pathB.cubicTo(978.890015f, 1471.64197f, 975.72699f, 1471.98499f, 974.919983f, 1468.29199f);
+ pathB.close();
+ pathB.moveTo(979.197998f, 1465.50598f);
+ pathB.cubicTo(979.197998f, 1465.50598f, 981.619019f, 1467.90198f, 979.481995f, 1470.27405f);
+ pathB.cubicTo(979.481995f, 1470.27405f, 977.138f, 1468.82605f, 979.197998f, 1465.50598f);
+ pathB.close();
+ pathB.moveTo(980.900024f, 1474.328f);
+ pathB.cubicTo(980.900024f, 1474.328f, 978.893005f, 1471.95703f, 981.791016f, 1469.48706f);
+ pathB.cubicTo(981.791016f, 1469.48596f, 983.358032f, 1472.729f, 980.900024f, 1474.328f);
+ pathB.close();
+ pathB.moveTo(980.968994f, 1478.18005f);
+ pathB.cubicTo(980.968994f, 1478.18005f, 979.718018f, 1475.66199f, 983.632019f, 1473.87805f);
+ pathB.cubicTo(983.632019f, 1473.87805f, 984.229004f, 1477.80103f, 980.968994f, 1478.18005f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_narayana_publishers_com_194(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1083.34314f, 445.65686f);
+ path.quadTo(1081, 443.313721f, 1081, 440);
+ path.lineTo(1257, 440);
+ path.quadTo(1257, 443.313721f, 1254.65686f, 445.65686f);
+ path.quadTo(1252.31372f, 448, 1249, 448);
+ path.lineTo(1089, 448);
+ path.quadTo(1085.68628f, 448, 1083.34314f, 445.65686f);
+ path.close();
+ path.moveTo(1083, 441);
+ path.lineTo(1255, 441);
+ path.quadTo(1255, 443.071075f, 1253.53552f, 444.535522f);
+ path.quadTo(1252.07104f, 446, 1250, 446);
+ path.lineTo(1088, 446);
+ path.quadTo(1085.92896f, 446, 1084.46448f, 444.535522f);
+ path.quadTo(1083, 443.071075f, 1083, 441);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1081, 440);
+ pathB.lineTo(1082, 440);
+ pathB.lineTo(1090.01001f, 448);
+ pathB.lineTo(1081, 448);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_cooksnaps_com_17(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(170.340179f, 176);
+ path.lineTo(166, 176);
+ path.quadTo(161.964188f, 176, 158.299957f, 176.896912f);
+ path.quadTo(154.678162f, 177.952271f, 151.183014f, 179.9702f);
+ path.lineTo(150.316986f, 180.4702f);
+ path.quadTo(146.175812f, 182.861099f, 143.115921f, 186.081696f);
+ path.quadTo(140.693939f, 188.70134f, 138.99472f, 191.620407f);
+ path.quadTo(137.316833f, 194.550888f, 136.259338f, 197.957367f);
+ path.quadTo(135, 202.217865f, 135, 207);
+ path.lineTo(135, 208);
+ path.quadTo(135, 212.035751f, 135.896912f, 215.699997f);
+ path.quadTo(136.952286f, 219.321869f, 138.9702f, 222.816986f);
+ path.lineTo(139.4702f, 223.683014f);
+ path.quadTo(141.861099f, 227.824188f, 145.081696f, 230.884079f);
+ path.quadTo(147.70134f, 233.306061f, 150.620407f, 235.00528f);
+ path.quadTo(153.550888f, 236.683167f, 156.957367f, 237.740662f);
+ path.quadTo(161.217865f, 239, 166, 239);
+ path.lineTo(170.482162f, 239);
+ path.quadTo(176.307037f, 238.210968f, 181.816986f, 235.0298f);
+ path.lineTo(182.683014f, 234.5298f);
+ path.quadTo(182.686462f, 234.527817f, 182.689896f, 234.525818f);
+ path.quadTo(193.804352f, 228.105652f, 197.126709f, 215.70639f);
+ path.quadTo(200.450104f, 203.303314f, 194.0298f, 192.183014f);
+ path.lineTo(193.5298f, 191.316986f);
+ path.quadTo(187.109497f, 180.196686f, 174.706406f, 176.873276f);
+ path.quadTo(172.503067f, 176.282898f, 170.340179f, 176);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(139.4702f, 223.683014f);
+ pathB.lineTo(138.9702f, 222.816986f);
+ pathB.quadTo(132.549896f, 211.696686f, 135.873291f, 199.293594f);
+ pathB.quadTo(139.196686f, 186.890503f, 150.316986f, 180.4702f);
+ pathB.lineTo(151.183014f, 179.9702f);
+ pathB.quadTo(162.303314f, 173.549896f, 174.706406f, 176.873276f);
+ pathB.quadTo(187.109497f, 180.196686f, 193.5298f, 191.316986f);
+ pathB.lineTo(194.0298f, 192.183014f);
+ pathB.quadTo(200.450104f, 203.303314f, 197.126709f, 215.70639f);
+ pathB.quadTo(193.803314f, 228.109497f, 182.683014f, 234.5298f);
+ pathB.lineTo(181.816986f, 235.0298f);
+ pathB.quadTo(170.696686f, 241.450104f, 158.293594f, 238.126709f);
+ pathB.quadTo(145.890503f, 234.803314f, 139.4702f, 223.683014f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_swapspacesystems_com_5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(819.050781f, 5539.72412f);
+ path.quadTo(819.651672f, 5539.1543f, 820.479858f, 5539.17578f);
+ path.lineTo(1191.35278f, 5548.8877f);
+ path.quadTo(1192.18091f, 5548.90918f, 1192.7511f, 5549.50977f);
+ path.quadTo(1193.32141f, 5550.11133f, 1193.29968f, 5550.93945f);
+ path.lineTo(1186.57214f, 5807.85107f);
+ path.quadTo(1186.55054f, 5808.6792f, 1185.94958f, 5809.24951f);
+ path.quadTo(1185.34863f, 5809.81982f, 1184.52051f, 5809.79834f);
+ path.lineTo(813.647705f, 5800.08643f);
+ path.quadTo(812.819519f, 5800.06494f, 812.249268f, 5799.46387f);
+ path.quadTo(811.679016f, 5798.86279f, 811.700684f, 5798.03467f);
+ path.lineTo(818.428162f, 5541.12305f);
+ path.quadTo(818.44989f, 5540.29492f, 819.050781f, 5539.72412f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(818.48053f, 5539.12354f);
+ pathB.lineTo(1193.35205f, 5548.93994f);
+ pathB.lineTo(1186.5199f, 5809.85059f);
+ pathB.lineTo(811.648376f, 5800.03418f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_kitcheninspirations_wordpress_com_66(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(47.1666679f, 27820.668f);
+ path.lineTo(60.8333359f, 27820.668f);
+ path.lineTo(60.8333359f, 27820.498f);
+ path.lineTo(47.1666679f, 27820.5f);
+ path.lineTo(47.1666679f, 27820.668f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(47.1666679f, 27820.668f);
+ pathB.lineTo(47.1666679f, 27820.498f);
+ pathB.lineTo(60.8333359f, 27820.5f);
+ pathB.lineTo(60.8333359f, 27820.668f);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_etiqadd_com_2464(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(630.378662f, 1293.42896f);
+ path.quadTo(631.257385f, 1292.55029f, 632.5f, 1292.55029f);
+ path.quadTo(633.742615f, 1292.55029f, 634.621338f, 1293.42896f);
+ path.lineTo(639.571045f, 1298.37866f);
+ path.quadTo(640.449768f, 1299.25732f, 640.449707f, 1300.5f);
+ path.quadTo(640.449768f, 1301.74268f, 639.571045f, 1302.62134f);
+ path.lineTo(634.621338f, 1307.57104f);
+ path.quadTo(633.742615f, 1308.44971f, 632.5f, 1308.44971f);
+ path.quadTo(631.257385f, 1308.44971f, 630.378662f, 1307.57104f);
+ path.lineTo(625.428955f, 1302.62134f);
+ path.quadTo(624.550232f, 1301.74268f, 624.550293f, 1300.5f);
+ path.quadTo(624.550232f, 1299.25732f, 625.428955f, 1298.37866f);
+ path.lineTo(630.378662f, 1293.42896f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(632.5f, 1291.30762f);
+ pathB.lineTo(641.692383f, 1300.5f);
+ pathB.lineTo(632.5f, 1309.69238f);
+ pathB.lineTo(623.307617f, 1300.5f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_narayana_verlag_de_194(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1083.34314f, 513.65686f);
+ path.quadTo(1081, 511.313721f, 1081, 508);
+ path.lineTo(1257, 508);
+ path.quadTo(1257, 511.313721f, 1254.65686f, 513.65686f);
+ path.quadTo(1252.31372f, 516, 1249, 516);
+ path.lineTo(1089, 516);
+ path.quadTo(1085.68628f, 516, 1083.34314f, 513.65686f);
+ path.close();
+ path.moveTo(1083, 509);
+ path.lineTo(1255, 509);
+ path.quadTo(1255, 511.071075f, 1253.53552f, 512.535522f);
+ path.quadTo(1252.07104f, 514, 1250, 514);
+ path.lineTo(1088, 514);
+ path.quadTo(1085.92896f, 514, 1084.46448f, 512.535522f);
+ path.quadTo(1083, 511.071075f, 1083, 509);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1081, 508);
+ pathB.lineTo(1082, 508);
+ pathB.lineTo(1090.01001f, 516);
+ pathB.lineTo(1081, 516);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_americascup_com_108(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(999.454102f, 689.17157f);
+ path.quadTo(1001.172f, 688, 1002.82886f, 688);
+ path.lineTo(1013.82886f, 688);
+ path.lineTo(1002.17114f, 713);
+ path.lineTo(991.171143f, 713);
+ path.quadTo(989.514282f, 713, 988.889038f, 711.82843f);
+ path.quadTo(988.263794f, 710.65686f, 989.036377f, 709);
+ path.lineTo(996.963623f, 692);
+ path.quadTo(997.736206f, 690.34314f, 999.454102f, 689.17157f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(998.828857f, 688);
+ pathB.lineTo(1013.82886f, 688);
+ pathB.lineTo(1002.17114f, 713);
+ pathB.lineTo(987.171143f, 713);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_vantageproduction_com_109(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(794.514709f, 759.485291f);
+ path.quadTo(791, 755.970581f, 791, 751);
+ path.lineTo(1133, 751);
+ path.quadTo(1133, 755.970581f, 1129.48523f, 759.485291f);
+ path.quadTo(1125.97058f, 763, 1121, 763);
+ path.lineTo(803, 763);
+ path.quadTo(798.029419f, 763, 794.514709f, 759.485291f);
+ path.close();
+ path.moveTo(793, 752);
+ path.lineTo(1131, 752);
+ path.quadTo(1131, 755.727905f, 1128.36401f, 758.363953f);
+ path.quadTo(1125.72791f, 761, 1122, 761);
+ path.lineTo(802, 761);
+ path.quadTo(798.272095f, 761, 795.636047f, 758.363953f);
+ path.quadTo(793, 755.727905f, 793, 752);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(791, 751);
+ pathB.lineTo(792, 751);
+ pathB.lineTo(804.01001f, 763);
+ pathB.lineTo(791, 763);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_aceinfographics_com_106(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(166.878677f, 7638.87891f);
+ path.quadTo(166, 7639.75732f, 166, 7641);
+ path.lineTo(166, 11577);
+ path.quadTo(166, 11578.2422f, 166.878677f, 11579.1211f);
+ path.quadTo(167.388f, 11579.6309f, 168.019989f, 11579.8447f);
+ path.lineTo(168.019974f, 11576.2979f);
+ path.quadTo(168, 11576.1533f, 168, 11576);
+ path.lineTo(168, 7642);
+ path.lineTo(168.000015f, 7641.99316f);
+ path.lineTo(168, 7640);
+ path.lineTo(166.878677f, 7638.87891f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(166, 7638);
+ pathB.lineTo(168.020004f, 7635.97998f);
+ pathB.lineTo(168, 11578);
+ pathB.lineTo(166, 11580);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_tcmevents_org_13(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(465.951904f, 547.960144f);
+ path.quadTo(465.66571f, 546.867371f, 465.404938f, 546);
+ path.lineTo(465.504089f, 546);
+ path.quadTo(465.670349f, 546.601257f, 465.84668f, 547.288391f);
+ path.quadTo(467.274506f, 552.852356f, 468.506836f, 560.718567f);
+ path.quadTo(467.336121f, 553.24585f, 465.951904f, 547.960144f);
+ path.close();
+ path.moveTo(470.591064f, 574.024353f);
+ path.quadTo(474.844055f, 601.176025f, 471.728271f, 620.364502f);
+ path.quadTo(470.567017f, 627.515991f, 468.635742f, 632);
+ path.lineTo(469.106812f, 632);
+ path.quadTo(470.791504f, 627.638672f, 471.833496f, 621.036255f);
+ path.quadTo(474.905701f, 601.569519f, 470.591064f, 574.024353f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(322.992462f, 541.475708f);
+ pathB.lineTo(465.531616f, 541.724426f);
+ pathB.lineTo(468.507751f, 560.724426f);
+ pathB.lineTo(325.968597f, 560.475708f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_paseoitaigara_com_br_56(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(633.147217f, 1247);
+ path.lineTo(718, 1162.14722f);
+ path.lineTo(802.852783f, 1247);
+ path.lineTo(718, 1331.85278f);
+ path.lineTo(633.147217f, 1247);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(635.268494f, 1244.87866f);
+ pathB.lineTo(715.878662f, 1164.26855f);
+ pathB.quadTo(716.757385f, 1163.38989f, 718, 1163.38989f);
+ pathB.quadTo(719.242615f, 1163.38989f, 720.121338f, 1164.26855f);
+ pathB.lineTo(800.731506f, 1244.87866f);
+ pathB.quadTo(801.610168f, 1245.75732f, 801.610168f, 1247);
+ pathB.quadTo(801.610229f, 1248.24268f, 800.731445f, 1249.12134f);
+ pathB.lineTo(720.121338f, 1329.73145f);
+ pathB.quadTo(719.242676f, 1330.61011f, 718, 1330.61011f);
+ pathB.quadTo(716.757385f, 1330.61011f, 715.878723f, 1329.73145f);
+ pathB.lineTo(635.268555f, 1249.12134f);
+ pathB.quadTo(634.389832f, 1248.24268f, 634.389832f, 1247);
+ pathB.quadTo(634.389832f, 1245.75732f, 635.268494f, 1244.87866f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_mortgagemarketguide_com_109(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(816.514709f, 781.485291f);
+ path.quadTo(813, 777.970581f, 813, 773);
+ path.lineTo(1133, 773);
+ path.quadTo(1133, 777.970581f, 1129.48523f, 781.485291f);
+ path.quadTo(1125.97058f, 785, 1121, 785);
+ path.lineTo(825, 785);
+ path.quadTo(820.029419f, 785, 816.514709f, 781.485291f);
+ path.close();
+ path.moveTo(815, 774);
+ path.lineTo(1131, 774);
+ path.quadTo(1131, 777.727905f, 1128.36401f, 780.363953f);
+ path.quadTo(1125.72791f, 783, 1122, 783);
+ path.lineTo(824, 783);
+ path.quadTo(820.272095f, 783, 817.636047f, 780.363953f);
+ path.quadTo(815, 777.727905f, 815, 774);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(813, 773);
+ pathB.lineTo(814, 773);
+ pathB.lineTo(826.01001f, 785);
+ pathB.lineTo(813, 785);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_9to5mac_com_64(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(365, 5101);
+ path.lineTo(365, 5082);
+ path.lineTo(366, 5083);
+ path.lineTo(367, 5092.96631f);
+ path.lineTo(367, 5100);
+ path.quadTo(367, 5101.50537f, 367.967712f, 5102.61084f);
+ path.lineTo(368.278717f, 5105.71045f);
+ path.quadTo(367.277618f, 5105.34863f, 366.464478f, 5104.53564f);
+ path.quadTo(365, 5103.07129f, 365, 5101);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(365, 5082);
+ pathB.lineTo(365.848175f, 5081.15186f);
+ pathB.lineTo(368, 5103);
+ pathB.lineTo(365, 5106);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+static void skpwww_googleventures_com_32(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(725.911682f, 898.767456f);
+ path.lineTo(741.232544f, 885.911682f);
+ path.lineTo(754.088318f, 901.232544f);
+ path.lineTo(738.767456f, 914.088318f);
+ path.lineTo(725.911682f, 898.767456f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(728.37677f, 870.59082f);
+ pathB.lineTo(754.088257f, 901.232605f);
+ pathB.lineTo(738.767395f, 914.088379f);
+ pathB.lineTo(713.055908f, 883.446594f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+#if TEST_NEW_FAILURES
+static void skpwww_devbridge_com_22(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(4915, 1523);
+ path.quadTo(4887.24756f, 1523, 4867.62402f, 1542.6239f);
+ path.quadTo(4848, 1562.24768f, 4848, 1590);
+ path.quadTo(4848, 1617.75232f, 4867.62402f, 1637.3761f);
+ path.quadTo(4887.24756f, 1657, 4915, 1657);
+ path.quadTo(4942.75244f, 1657, 4962.37598f, 1637.3761f);
+ path.quadTo(4982, 1617.75232f, 4982, 1590);
+ path.quadTo(4982, 1562.24768f, 4962.37598f, 1542.6239f);
+ path.quadTo(4942.75244f, 1523, 4915, 1523);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(4981.99902f, 1590);
+ pathB.quadTo(4981.99902f, 1617.75232f, 4962.375f, 1637.3761f);
+ pathB.quadTo(4942.75146f, 1657, 4914.99902f, 1657);
+ pathB.quadTo(4887.24658f, 1657, 4867.62305f, 1637.3761f);
+ pathB.quadTo(4847.99902f, 1617.75232f, 4847.99902f, 1590);
+ pathB.quadTo(4847.99902f, 1562.24768f, 4867.62305f, 1542.6239f);
+ pathB.quadTo(4887.24658f, 1523, 4914.99902f, 1523);
+ pathB.quadTo(4942.75146f, 1523, 4962.375f, 1542.6239f);
+ pathB.quadTo(4981.99902f, 1562.24768f, 4981.99902f, 1590);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// cubic/quad intersection
+static void skpwww_alamdi_com_3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(10210.8789f, 5315.87891f);
+ path.quadTo(10211.7578f, 5315, 10213, 5315);
+ path.lineTo(10230, 5315);
+ path.quadTo(10231.2422f, 5315, 10232.1211f, 5315.87891f);
+ path.quadTo(10233, 5316.75732f, 10233, 5318);
+ path.lineTo(10233, 5338);
+ path.quadTo(10233, 5339.24268f, 10232.1211f, 5340.12109f);
+ path.quadTo(10231.2422f, 5341, 10230, 5341);
+ path.lineTo(10213, 5341);
+ path.quadTo(10211.7578f, 5341, 10210.8789f, 5340.12109f);
+ path.quadTo(10210, 5339.24268f, 10210, 5338);
+ path.lineTo(10210, 5318);
+ path.quadTo(10210, 5316.75732f, 10210.8789f, 5315.87891f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(10213, 5315);
+ pathB.lineTo(10230, 5315);
+ pathB.cubicTo(10231.6572f, 5315, 10233, 5316.34326f, 10233, 5318);
+ pathB.lineTo(10233, 5338);
+ pathB.cubicTo(10233, 5339.10449f, 10231.6572f, 5340, 10230, 5340);
+ pathB.lineTo(10213, 5340);
+ pathB.cubicTo(10211.3428f, 5340, 10210, 5339.10449f, 10210, 5338);
+ pathB.lineTo(10210, 5318);
+ pathB.cubicTo(10210, 5316.34326f, 10211.3428f, 5315, 10213, 5315);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// bumpSpan failed assertion "span->fOppValue >= 0"
+static void skpwww_familysurvivalprotocol_wordpress_com_61(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(143, 14557);
+ path.lineTo(165, 14557);
+ path.lineTo(165, 14555.9902f);
+ path.lineTo(143, 14556);
+ path.lineTo(143, 14557);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(143, 14557);
+ pathB.lineTo(143, 14555.9902f);
+ pathB.lineTo(165, 14556);
+ pathB.lineTo(165, 14557);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+#endif
+
+static void skpwww_firstunitedbank_com_19(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(808.585815f, 11673.5859f);
+ path.quadTo(809.17157f, 11673, 810, 11673);
+ path.lineTo(1032, 11673);
+ path.quadTo(1038.21326f, 11673, 1042.60657f, 11677.3936f);
+ path.quadTo(1047, 11681.7871f, 1047, 11688);
+ path.quadTo(1047, 11682.2012f, 1042.60657f, 11678.1006f);
+ path.quadTo(1038.21326f, 11674, 1032, 11674);
+ path.lineTo(810, 11674);
+ path.quadTo(809.585815f, 11674, 809.292908f, 11674.293f);
+ path.quadTo(809, 11674.5859f, 809, 11675);
+ path.lineTo(809, 11701);
+ path.quadTo(809, 11701.4141f, 809.292908f, 11701.707f);
+ path.quadTo(809.585815f, 11702, 810, 11702);
+ path.lineTo(1032, 11702);
+ path.quadTo(1038.21326f, 11702, 1042.60657f, 11697.8994f);
+ path.quadTo(1047, 11693.7988f, 1047, 11688);
+ path.quadTo(1047, 11694.2129f, 1042.60657f, 11698.6064f);
+ path.quadTo(1038.21326f, 11703, 1032, 11703);
+ path.lineTo(810, 11703);
+ path.quadTo(809.17157f, 11703, 808.585815f, 11702.4141f);
+ path.quadTo(808, 11701.8281f, 808, 11701);
+ path.lineTo(808, 11675);
+ path.quadTo(808, 11674.1719f, 808.585815f, 11673.5859f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(808, 11703);
+ pathB.lineTo(809.5f, 11701.5f);
+ pathB.lineTo(1062.91907f, 11687.0811f);
+ pathB.lineTo(1047, 11703);
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// addSimpleAngle: failed assertion "index == count() - 2"
+static void skpwww_shinydemos_com_5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(205.884888f, 648.203857f);
+ path.lineTo(771.570374f, 82.5183716f);
+ path.lineTo(1110.98169f, 421.929626f);
+ path.lineTo(545.296143f, 987.615112f);
+ path.lineTo(205.884888f, 648.203857f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(771.570374f, 82.5183716f);
+ pathB.lineTo(1110.98169f, 421.929626f);
+ pathB.lineTo(545.296204f, 987.615051f);
+ pathB.lineTo(205.884949f, 648.203796f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// addTCoincident oPeek = &other->fTs[++oPeekIndex];
+static void skpwww_lptemp_com_3(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(78.6429825f, 1394.30969f);
+ path.quadTo(79.6192932f, 1393.33337f, 81.0000076f, 1393.33337f);
+ path.lineTo(341, 1393.33337f);
+ path.quadTo(342.380707f, 1393.33337f, 343.357025f, 1394.30969f);
+ path.quadTo(344.333344f, 1395.28601f, 344.333344f, 1396.66675f);
+ path.lineTo(344.333344f, 1465.66663f);
+ path.quadTo(344.333344f, 1467.04736f, 343.357025f, 1468.02368f);
+ path.quadTo(342.380707f, 1469, 341, 1469);
+ path.lineTo(81.0000076f, 1469);
+ path.quadTo(79.6192932f, 1469, 78.6429825f, 1468.02368f);
+ path.quadTo(77.6666718f, 1467.04736f, 77.6666718f, 1465.66663f);
+ path.lineTo(77.6666718f, 1396.66675f);
+ path.quadTo(77.6666718f, 1395.28601f, 78.6429825f, 1394.30969f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(81, 1393.33337f);
+ pathB.lineTo(341, 1393.33337f);
+ pathB.cubicTo(342.840942f, 1393.33337f, 344.333344f, 1394.82568f, 344.333344f, 1396.66675f);
+ pathB.lineTo(344.333344f, 1465.66675f);
+ pathB.cubicTo(344.333344f, 1467.32361f, 342.840942f, 1468.66675f, 341, 1468.66675f);
+ pathB.lineTo(81, 1468.66675f);
+ pathB.cubicTo(79.15905f, 1468.66675f, 77.6666718f, 1467.32361f, 77.6666718f, 1465.66675f);
+ pathB.lineTo(77.6666718f, 1396.66675f);
+ pathB.cubicTo(77.6666718f, 1394.82568f, 79.15905f, 1393.33337f, 81, 1393.33337f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+#if TEST_NEW_FAILURES
+// SkOpSegment.cpp:3915: failed assertion "otherEnd >= 0"
+static void skpwww_shinydemos_com_15(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1000, 310.947968f);
+ path.lineTo(771.570374f, 82.5183716f);
+ path.lineTo(205.884888f, 648.203857f);
+ path.lineTo(448.68103f, 891);
+ path.lineTo(641.911255f, 891);
+ path.lineTo(1000, 532.911316f);
+ path.lineTo(1000, 310.947968f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(771.570374f, 82.5183716f);
+ pathB.lineTo(1110.98169f, 421.929626f);
+ pathB.lineTo(545.296204f, 987.615051f);
+ pathB.lineTo(205.884949f, 648.203796f);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+
+// SkOpSegment.cpp:4398: failed assertion "!span->fDone"
+static void skpwww_lptemp_com_5(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(78.6429825f, 3150.97632f);
+ path.quadTo(79.6192932f, 3150, 81.0000076f, 3150);
+ path.lineTo(341, 3150);
+ path.quadTo(342.380707f, 3150, 343.357025f, 3150.97632f);
+ path.quadTo(344.333344f, 3151.95264f, 344.333344f, 3153.33325f);
+ path.lineTo(344.333344f, 5205.3335f);
+ path.quadTo(344.333344f, 5206.71436f, 343.357025f, 5207.69092f);
+ path.quadTo(342.380707f, 5208.66699f, 341, 5208.66699f);
+ path.lineTo(81.0000076f, 5208.66699f);
+ path.quadTo(79.6192932f, 5208.66699f, 78.6429825f, 5207.69092f);
+ path.quadTo(77.6666718f, 5206.71436f, 77.6666718f, 5205.3335f);
+ path.lineTo(77.6666718f, 3153.33325f);
+ path.quadTo(77.6666718f, 3151.95264f, 78.6429825f, 3150.97632f);
+ path.close();
+ SkPath pathB;
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(81, 3150);
+ pathB.lineTo(341, 3150);
+ pathB.cubicTo(342.840942f, 3150, 344.333344f, 3151.49268f, 344.333344f, 3153.3335f);
+ pathB.lineTo(344.333344f, 5205.3335f);
+ pathB.cubicTo(344.333344f, 5206.99023f, 342.840942f, 5208.3335f, 341, 5208.3335f);
+ pathB.lineTo(81, 5208.3335f);
+ pathB.cubicTo(79.15905f, 5208.3335f, 77.6666718f, 5206.99023f, 77.6666718f, 5205.3335f);
+ pathB.lineTo(77.6666718f, 3153.3335f);
+ pathB.cubicTo(77.6666718f, 3151.49268f, 79.15905f, 3150, 81, 3150);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
+}
+#endif
+
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
+
+static struct TestDesc tests[] = {
+ TEST(skpwww_lptemp_com_3),
+ TEST(skpwww_shinydemos_com_5),
+#if TEST_NEW_FAILURES
+ TEST(skpwww_lptemp_com_5),
+ TEST(skpwww_shinydemos_com_15),
+ TEST(skpwww_familysurvivalprotocol_wordpress_com_61),
+ TEST(skpwww_alamdi_com_3),
+ TEST(skpwww_devbridge_com_22),
+#endif
+ TEST(skpwww_firstunitedbank_com_19),
+ TEST(skpwww_googleventures_com_32),
+ TEST(skpwww_9to5mac_com_64),
+ TEST(skpwww_wartepop_blogspot_com_br_6),
+ TEST(skpwww_wartepop_blogspot_com_br_6a),
+ TEST(skpwww_cooksnaps_com_32a),
+ TEST(skpwww_argus_presse_fr_41),
+ TEST(skpwww_cooksnaps_com_17),
+ TEST(skpwww_cooksnaps_com_32),
+ TEST(skpwww_kitcheninspirations_wordpress_com_66),
+ TEST(skpwww_tcmevents_org_13),
+ TEST(skpwww_narayana_publishers_com_194),
+ TEST(skpwww_swapspacesystems_com_5),
+ TEST(skpwww_vantageproduction_com_109),
+ TEST(skpwww_americascup_com_108),
+ TEST(skpwww_narayana_verlag_de_194),
+ TEST(skpwww_etiqadd_com_2464),
+ TEST(skpwww_paseoitaigara_com_br_56),
+ TEST(skpwww_mortgagemarketguide_com_109),
+ TEST(skpwww_aceinfographics_com_106),
+ TEST(skpwww_educationalcraft_com_4),
+ TEST(skpwww_kitcheninspirations_wordpress_com_32),
+ TEST(skpwww_artblart_com_8),
+ TEST(skpwww_docgelo_com_66),
+ TEST(skpwww_uniquefx_net_442),
+ TEST(skpwww_defense_studies_blogspot_com_64),
+ TEST(skpwww_kenlevine_blogspot_com_28),
+ TEST(skpwww_fashionscandal_com_94),
+ TEST(skpwww_thaienews_blogspot_com_36),
+ TEST(skpwww_galaxystwo_com_4),
+ TEST(skpwww_catingueiraonline_com_352),
+ TEST(skpwww_evolvehq_com_210),
+ TEST(skpwww_odia_com_br_26),
+ TEST(skpwww_lokado_de_173),
+ TEST(skpwww_seopack_blogspot_com_2153),
+ TEST(skpwww_partsdata_de_53),
+ TEST(skpwww_simplysaru_com_40),
+ TEST(skpwww_jessicaslens_wordpress_com_222),
+ TEST(skpwww_kpopexplorer_net_22),
+ TEST(skpwww_tunero_de_24),
+ TEST(skpwww_karnivool_com_au_11),
+ TEST(skpwww_pindosiya_com_99),
+ TEST(skpwww_contextualnewsfeeds_com_346),
+ TEST(skpwww_helha_be_109),
+ TEST(skpwww_phototransferapp_com_24),
+ TEST(skpwww_phototransferapp_com_24x),
+ TEST(skpwww_gruposejaumdivulgador_com_br_4),
+ TEST(skpwww_hubbyscook_com_22),
+ TEST(skpwww_maturesupertube_com_21),
+ TEST(skpwww_getgold_jp_731),
+ TEST(skpwww_trashness_com_36),
+ TEST(skpwww_exystence_net_61),
+ TEST(skpwww_320kbps_net_2231),
+ TEST(skpwww_heartiste_wordpress_com_86),
+ TEST(skpwww_hairjobsearch_com_31),
+ TEST(skpwww_alucinados_net_101),
+ TEST(skpnamecheap_com_405),
+ TEST(skpelpais_com_18),
+ TEST(skpwww_cityads_ru_249),
+ TEST(skpwww_alrakoba_net_62),
+ TEST(skpwww_dealnews_com_315),
+ TEST(skpwww_inmotionhosting_com_9),
+ TEST(skpskpicture14),
+ TEST(skpskpicture15),
+ TEST(skpwww_meb_gov_tr_6),
+ TEST(skpwww_sciality_com_101),
+ TEST(skpwww_booking_com_68),
+ TEST(skpwww_despegar_com_mx_272),
+ TEST(skpwww_lavoixdunord_fr_11),
+ TEST(skppptv_com_62),
+ TEST(skppchappy_com_au102),
+ TEST(skpsciality_com161),
+ TEST(skpi_gino_com16),
+ TEST(skpnaoxrane_ru23),
+ TEST(skptcmevents_org23),
+ TEST(skpredbullskatearcade_es16),
+ TEST(skpfinanzasdigital_com9),
+ TEST(skpgithub_io_26),
+ TEST(skpgithub_io_25),
+ TEST(skpwww_meb_gov_tr_5),
+ TEST(skpwww_sciality_com_100),
+ TEST(skpwww_joomla_org_23),
+ TEST(skpwww_macrumors_com_131),
+ TEST(skpwww_briian_com_34),
+ TEST(skpwww_leadpages_net_84),
+ TEST(skpwww_fj_p_com_22),
+ TEST(skppartainasdemo250_org56),
+ TEST(skpsd_graphic_net104),
+ TEST(skpbreakmystyle_com10),
+ TEST(skpnational_com_au81),
+ TEST(skprentacheat_com30),
+ TEST(skptracksflow_com9),
+ TEST(skpautobutler_dk29),
+ TEST(skponlinecollege_org144),
+ TEST(skphostloco_com11),
+ TEST(skpsergeychunkevich_com8),
+ TEST(skpmlk_com326),
+ TEST(skpcyclist_friends_gr52),
+ TEST(skpfrauen_magazin_com83),
+ TEST(skpthesuburbanite_com213),
+ TEST(skpsudoestenegocios_com186),
+ TEST(skpmtrk_uz27),
+ TEST(skpilkoora_com37),
+ TEST(skpmm4everfriends_com43),
+ TEST(skpflite_com41),
+ TEST(skpcheeseandburger_com225),
+ TEST(skpeverytechpro_blogspot_com100),
+};
+
+static const size_t testCount = SK_ARRAY_COUNT(tests);
+
+static bool runReverse = false;
+static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
+
+DEF_TEST(PathOpsSkp, reporter) {
+#if DEBUG_SHOW_TEST_NAME
+ strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
+#endif
+ RunTestSet(reporter, tests, testCount, firstTest, stopTest, runReverse);
+}
diff --git a/src/third_party/skia/tests/PathOpsTestCommon.cpp b/src/third_party/skia/tests/PathOpsTestCommon.cpp
new file mode 100644
index 0000000..60a12ee
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsTestCommon.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "SkPathOpsBounds.h"
+#include "SkPathOpsCubic.h"
+#include "SkPathOpsLine.h"
+#include "SkPathOpsQuad.h"
+#include "SkPathOpsTriangle.h"
+
+void CubicToQuads(const SkDCubic& cubic, double precision, SkTArray<SkDQuad, true>& quads) {
+ SkTArray<double, true> ts;
+ cubic.toQuadraticTs(precision, &ts);
+ if (ts.count() <= 0) {
+ SkDQuad quad = cubic.toQuad();
+ quads.push_back(quad);
+ return;
+ }
+ double tStart = 0;
+ for (int i1 = 0; i1 <= ts.count(); ++i1) {
+ const double tEnd = i1 < ts.count() ? ts[i1] : 1;
+ SkDCubic part = cubic.subDivide(tStart, tEnd);
+ SkDQuad quad = part.toQuad();
+ quads.push_back(quad);
+ tStart = tEnd;
+ }
+}
+
+void CubicPathToQuads(const SkPath& cubicPath, SkPath* quadPath) {
+ quadPath->reset();
+ SkDCubic cubic;
+ SkTArray<SkDQuad, true> quads;
+ SkPath::RawIter iter(cubicPath);
+ uint8_t verb;
+ SkPoint pts[4];
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ quadPath->moveTo(pts[0].fX, pts[0].fY);
+ continue;
+ case SkPath::kLine_Verb:
+ quadPath->lineTo(pts[1].fX, pts[1].fY);
+ break;
+ case SkPath::kQuad_Verb:
+ quadPath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
+ break;
+ case SkPath::kCubic_Verb:
+ quads.reset();
+ cubic.set(pts);
+ CubicToQuads(cubic, cubic.calcPrecision(), quads);
+ for (int index = 0; index < quads.count(); ++index) {
+ SkPoint qPts[2] = {
+ quads[index][1].asSkPoint(),
+ quads[index][2].asSkPoint()
+ };
+ quadPath->quadTo(qPts[0].fX, qPts[0].fY, qPts[1].fX, qPts[1].fY);
+ }
+ break;
+ case SkPath::kClose_Verb:
+ quadPath->close();
+ break;
+ default:
+ SkDEBUGFAIL("bad verb");
+ return;
+ }
+ }
+}
+
+void CubicPathToSimple(const SkPath& cubicPath, SkPath* simplePath) {
+ simplePath->reset();
+ SkDCubic cubic;
+ SkPath::RawIter iter(cubicPath);
+ uint8_t verb;
+ SkPoint pts[4];
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ simplePath->moveTo(pts[0].fX, pts[0].fY);
+ continue;
+ case SkPath::kLine_Verb:
+ simplePath->lineTo(pts[1].fX, pts[1].fY);
+ break;
+ case SkPath::kQuad_Verb:
+ simplePath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
+ break;
+ case SkPath::kCubic_Verb: {
+ cubic.set(pts);
+ double tInflects[2];
+ int inflections = cubic.findInflections(tInflects);
+ if (inflections > 1 && tInflects[0] > tInflects[1]) {
+ SkTSwap(tInflects[0], tInflects[1]);
+ }
+ double lo = 0;
+ for (int index = 0; index <= inflections; ++index) {
+ double hi = index < inflections ? tInflects[index] : 1;
+ SkDCubic part = cubic.subDivide(lo, hi);
+ SkPoint cPts[3];
+ cPts[0] = part[1].asSkPoint();
+ cPts[1] = part[2].asSkPoint();
+ cPts[2] = part[3].asSkPoint();
+ simplePath->cubicTo(cPts[0].fX, cPts[0].fY, cPts[1].fX, cPts[1].fY,
+ cPts[2].fX, cPts[2].fY);
+ lo = hi;
+ }
+ break;
+ }
+ case SkPath::kClose_Verb:
+ simplePath->close();
+ break;
+ default:
+ SkDEBUGFAIL("bad verb");
+ return;
+ }
+ }
+}
+
+static bool SkDoubleIsNaN(double x) {
+ return x != x;
+}
+
+bool ValidBounds(const SkPathOpsBounds& bounds) {
+ if (SkScalarIsNaN(bounds.fLeft)) {
+ return false;
+ }
+ if (SkScalarIsNaN(bounds.fTop)) {
+ return false;
+ }
+ if (SkScalarIsNaN(bounds.fRight)) {
+ return false;
+ }
+ return !SkScalarIsNaN(bounds.fBottom);
+}
+
+bool ValidCubic(const SkDCubic& cubic) {
+ for (int index = 0; index < 4; ++index) {
+ if (!ValidPoint(cubic[index])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ValidLine(const SkDLine& line) {
+ for (int index = 0; index < 2; ++index) {
+ if (!ValidPoint(line[index])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ValidPoint(const SkDPoint& pt) {
+ if (SkDoubleIsNaN(pt.fX)) {
+ return false;
+ }
+ return !SkDoubleIsNaN(pt.fY);
+}
+
+bool ValidPoints(const SkPoint* pts, int count) {
+ for (int index = 0; index < count; ++index) {
+ if (SkScalarIsNaN(pts[index].fX)) {
+ return false;
+ }
+ if (SkScalarIsNaN(pts[index].fY)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ValidQuad(const SkDQuad& quad) {
+ for (int index = 0; index < 3; ++index) {
+ if (!ValidPoint(quad[index])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ValidTriangle(const SkDTriangle& triangle) {
+ for (int index = 0; index < 3; ++index) {
+ if (!ValidPoint(triangle.fPts[index])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ValidVector(const SkDVector& v) {
+ if (SkDoubleIsNaN(v.fX)) {
+ return false;
+ }
+ return !SkDoubleIsNaN(v.fY);
+}
diff --git a/src/third_party/skia/tests/PathOpsTestCommon.h b/src/third_party/skia/tests/PathOpsTestCommon.h
new file mode 100644
index 0000000..0c42bfb
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsTestCommon.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef PathOpsTestCommon_DEFINED
+#define PathOpsTestCommon_DEFINED
+
+#include "SkPathOpsQuad.h"
+#include "SkTArray.h"
+
+struct SkPathOpsBounds;
+
+void CubicPathToQuads(const SkPath& cubicPath, SkPath* quadPath);
+void CubicPathToSimple(const SkPath& cubicPath, SkPath* simplePath);
+void CubicToQuads(const SkDCubic& cubic, double precision, SkTArray<SkDQuad, true>& quads);
+bool ValidBounds(const SkPathOpsBounds&);
+bool ValidCubic(const SkDCubic& cubic);
+bool ValidLine(const SkDLine& line);
+bool ValidPoint(const SkDPoint& pt);
+bool ValidPoints(const SkPoint* pts, int count);
+bool ValidQuad(const SkDQuad& quad);
+bool ValidTriangle(const SkDTriangle& triangle);
+bool ValidVector(const SkDVector& v);
+
+#endif
diff --git a/src/third_party/skia/tests/PathOpsThreadedCommon.cpp b/src/third_party/skia/tests/PathOpsThreadedCommon.cpp
new file mode 100644
index 0000000..0adde91
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsThreadedCommon.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "PathOpsExtendedTest.h"
+#include "PathOpsThreadedCommon.h"
+#include "SkTaskGroup.h"
+
+PathOpsThreadedTestRunner::~PathOpsThreadedTestRunner() {
+ for (int index = 0; index < fRunnables.count(); index++) {
+ SkDELETE(fRunnables[index]);
+ }
+}
+
+void PathOpsThreadedTestRunner::render() {
+ SkTaskGroup tg;
+ for (int index = 0; index < fRunnables.count(); ++ index) {
+ tg.add(fRunnables[index]);
+ }
+}
diff --git a/src/third_party/skia/tests/PathOpsThreadedCommon.h b/src/third_party/skia/tests/PathOpsThreadedCommon.h
new file mode 100644
index 0000000..124921e
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsThreadedCommon.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef PathOpsThreadedCommon_DEFINED
+#define PathOpsThreadedCommon_DEFINED
+
+#include "SkGraphics.h"
+#include "SkRunnable.h"
+#include "SkTDArray.h"
+
+#define PATH_STR_SIZE 512
+
+class PathOpsThreadedRunnable;
+
+namespace skiatest {
+class Reporter;
+}
+
+struct PathOpsThreadState {
+ unsigned char fA;
+ unsigned char fB;
+ unsigned char fC;
+ unsigned char fD;
+ char* fPathStr;
+ const char* fKey;
+ char fSerialNo[256];
+ skiatest::Reporter* fReporter;
+ SkBitmap* fBitmap;
+};
+
+class PathOpsThreadedTestRunner {
+public:
+ PathOpsThreadedTestRunner(skiatest::Reporter* reporter) : fReporter(reporter) {}
+
+ ~PathOpsThreadedTestRunner();
+
+ void render();
+
+public:
+ SkTDArray<PathOpsThreadedRunnable*> fRunnables;
+ skiatest::Reporter* fReporter;
+};
+
+class PathOpsThreadedRunnable : public SkRunnable {
+public:
+ PathOpsThreadedRunnable(void (*testFun)(PathOpsThreadState*), int a, int b, int c, int d,
+ PathOpsThreadedTestRunner* runner) {
+ fState.fA = a;
+ fState.fB = b;
+ fState.fC = c;
+ fState.fD = d;
+ fState.fReporter = runner->fReporter;
+ fTestFun = testFun;
+ }
+
+ PathOpsThreadedRunnable(void (*testFun)(PathOpsThreadState*), const char* str,
+ PathOpsThreadedTestRunner* runner) {
+ SkASSERT(strlen(str) < sizeof(fState.fSerialNo) - 1);
+ strcpy(fState.fSerialNo, str);
+ fState.fReporter = runner->fReporter;
+ fTestFun = testFun;
+ }
+
+ PathOpsThreadedRunnable(void (*testFun)(PathOpsThreadState*), int dirNo, const char* str,
+ PathOpsThreadedTestRunner* runner) {
+ SkASSERT(strlen(str) < sizeof(fState.fSerialNo) - 1);
+ fState.fA = dirNo;
+ strcpy(fState.fSerialNo, str);
+ fState.fReporter = runner->fReporter;
+ fTestFun = testFun;
+ }
+
+ virtual void run() SK_OVERRIDE {
+ SkBitmap bitmap;
+ fState.fBitmap = &bitmap;
+ char pathStr[PATH_STR_SIZE];
+ fState.fPathStr = pathStr;
+ SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
+ (*fTestFun)(&fState);
+ }
+
+private:
+ PathOpsThreadState fState;
+ void (*fTestFun)(PathOpsThreadState*);
+};
+
+#endif
diff --git a/src/third_party/skia/tests/PathOpsTightBoundsTest.cpp b/src/third_party/skia/tests/PathOpsTightBoundsTest.cpp
new file mode 100644
index 0000000..cea3752
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsTightBoundsTest.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsExtendedTest.h"
+#include "PathOpsThreadedCommon.h"
+#include "SkCanvas.h"
+#include "SkRandom.h"
+#include "SkTArray.h"
+#include "SkTSort.h"
+#include "Test.h"
+
+static void testTightBoundsLines(PathOpsThreadState* data) {
+ SkRandom ran;
+ for (int index = 0; index < 1000; ++index) {
+ SkPath path;
+ int contourCount = ran.nextRangeU(1, 10);
+ for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
+ int lineCount = ran.nextRangeU(1, 10);
+ path.moveTo(ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000));
+ for (int lIndex = 0; lIndex < lineCount; ++lIndex) {
+ path.lineTo(ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000));
+ }
+ if (ran.nextBool()) {
+ path.close();
+ }
+ }
+ SkRect classicBounds = path.getBounds();
+ SkRect tightBounds;
+ REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds));
+ REPORTER_ASSERT(data->fReporter, classicBounds == tightBounds);
+ }
+}
+
+DEF_TEST(PathOpsTightBoundsLines, reporter) {
+ initializeTests(reporter, "tightBoundsLines");
+ PathOpsThreadedTestRunner testRunner(reporter);
+ int outerCount = reporter->allowExtendedTest() ? 100 : 1;
+ for (int index = 0; index < outerCount; ++index) {
+ for (int idx2 = 0; idx2 < 10; ++idx2) {
+ *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
+ (&testTightBoundsLines, 0, 0, 0, 0, &testRunner));
+ }
+ }
+ testRunner.render();
+}
+
+static void testTightBoundsQuads(PathOpsThreadState* data) {
+ SkRandom ran;
+ const int bitWidth = 32;
+ const int bitHeight = 32;
+ const float pathMin = 1;
+ const float pathMax = (float) (bitHeight - 2);
+ SkBitmap& bits = *data->fBitmap;
+ if (bits.width() == 0) {
+ bits.allocN32Pixels(bitWidth, bitHeight);
+ }
+ SkCanvas canvas(bits);
+ SkPaint paint;
+ for (int index = 0; index < 100; ++index) {
+ SkPath path;
+ int contourCount = ran.nextRangeU(1, 10);
+ for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
+ int lineCount = ran.nextRangeU(1, 10);
+ path.moveTo(ran.nextRangeF(1, pathMax), ran.nextRangeF(pathMin, pathMax));
+ for (int lIndex = 0; lIndex < lineCount; ++lIndex) {
+ if (ran.nextBool()) {
+ path.lineTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax));
+ } else {
+ path.quadTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax),
+ ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax));
+ }
+ }
+ if (ran.nextBool()) {
+ path.close();
+ }
+ }
+ SkRect classicBounds = path.getBounds();
+ SkRect tightBounds;
+ REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds));
+ REPORTER_ASSERT(data->fReporter, classicBounds.contains(tightBounds));
+ canvas.drawColor(SK_ColorWHITE);
+ canvas.drawPath(path, paint);
+ SkIRect bitsWritten = {31, 31, 0, 0};
+ for (int y = 0; y < bitHeight; ++y) {
+ uint32_t* addr1 = data->fBitmap->getAddr32(0, y);
+ bool lineWritten = false;
+ for (int x = 0; x < bitWidth; ++x) {
+ if (addr1[x] == (uint32_t) -1) {
+ continue;
+ }
+ lineWritten = true;
+ bitsWritten.fLeft = SkTMin(bitsWritten.fLeft, x);
+ bitsWritten.fRight = SkTMax(bitsWritten.fRight, x);
+ }
+ if (!lineWritten) {
+ continue;
+ }
+ bitsWritten.fTop = SkTMin(bitsWritten.fTop, y);
+ bitsWritten.fBottom = SkTMax(bitsWritten.fBottom, y);
+ }
+ if (!bitsWritten.isEmpty()) {
+ SkIRect tightOut;
+ tightBounds.roundOut(&tightOut);
+ REPORTER_ASSERT(data->fReporter, tightOut.contains(bitsWritten));
+ }
+ }
+}
+
+DEF_TEST(PathOpsTightBoundsQuads, reporter) {
+ initializeTests(reporter, "tightBoundsQuads");
+ PathOpsThreadedTestRunner testRunner(reporter);
+ int outerCount = reporter->allowExtendedTest() ? 100 : 1;
+ for (int index = 0; index < outerCount; ++index) {
+ for (int idx2 = 0; idx2 < 10; ++idx2) {
+ *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
+ (&testTightBoundsQuads, 0, 0, 0, 0, &testRunner));
+ }
+ }
+ testRunner.render();
+}
diff --git a/src/third_party/skia/tests/PathOpsTypesTest.cpp b/src/third_party/skia/tests/PathOpsTypesTest.cpp
new file mode 100755
index 0000000..a3b051e
--- /dev/null
+++ b/src/third_party/skia/tests/PathOpsTypesTest.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "PathOpsTestCommon.h"
+#include "Test.h"
+
+static const double roughlyTests[][2] = {
+ {5.0402503619650929e-005, 4.3178054475078825e-005}
+};
+
+static const size_t roughlyTestsCount = SK_ARRAY_COUNT(roughlyTests);
+
+DEF_TEST(PathOpsRoughly, reporter) {
+ for (size_t index = 0; index < roughlyTestsCount; ++index) {
+ bool equal = RoughlyEqualUlps(roughlyTests[index][0], roughlyTests[index][1]);
+ REPORTER_ASSERT(reporter, equal);
+ }
+}
diff --git a/src/third_party/skia/tests/PathTest.cpp b/src/third_party/skia/tests/PathTest.cpp
new file mode 100644
index 0000000..1f0422d
--- /dev/null
+++ b/src/third_party/skia/tests/PathTest.cpp
@@ -0,0 +1,3631 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkParse.h"
+#include "SkParsePath.h"
+#include "SkPath.h"
+#include "SkPathEffect.h"
+#include "SkRRect.h"
+#include "SkRandom.h"
+#include "SkReader32.h"
+#include "SkSize.h"
+#include "SkStream.h"
+#include "SkSurface.h"
+#include "SkTypes.h"
+#include "SkWriter32.h"
+#include "Test.h"
+
+static void make_path_crbug364224(SkPath* path) {
+ path->reset();
+ path->moveTo(3.747501373f, 2.724499941f);
+ path->lineTo(3.747501373f, 3.75f);
+ path->cubicTo(3.747501373f, 3.88774991f, 3.635501385f, 4.0f, 3.497501373f, 4.0f);
+ path->lineTo(0.7475013733f, 4.0f);
+ path->cubicTo(0.6095013618f, 4.0f, 0.4975013733f, 3.88774991f, 0.4975013733f, 3.75f);
+ path->lineTo(0.4975013733f, 1.0f);
+ path->cubicTo(0.4975013733f, 0.8622499704f, 0.6095013618f, 0.75f, 0.7475013733f,0.75f);
+ path->lineTo(3.497501373f, 0.75f);
+ path->cubicTo(3.50275135f, 0.75f, 3.5070014f, 0.7527500391f, 3.513001442f, 0.753000021f);
+ path->lineTo(3.715001345f, 0.5512499809f);
+ path->cubicTo(3.648251295f, 0.5194999576f, 3.575501442f, 0.4999999702f, 3.497501373f, 0.4999999702f);
+ path->lineTo(0.7475013733f, 0.4999999702f);
+ path->cubicTo(0.4715013802f, 0.4999999702f, 0.2475013733f, 0.7239999771f, 0.2475013733f, 1.0f);
+ path->lineTo(0.2475013733f, 3.75f);
+ path->cubicTo(0.2475013733f, 4.026000023f, 0.4715013504f, 4.25f, 0.7475013733f, 4.25f);
+ path->lineTo(3.497501373f, 4.25f);
+ path->cubicTo(3.773501396f, 4.25f, 3.997501373f, 4.026000023f, 3.997501373f, 3.75f);
+ path->lineTo(3.997501373f, 2.474750042f);
+ path->lineTo(3.747501373f, 2.724499941f);
+ path->close();
+}
+
+static void make_path_crbug364224_simplified(SkPath* path) {
+ path->moveTo(3.747501373f, 2.724499941f);
+ path->cubicTo(3.648251295f, 0.5194999576f, 3.575501442f, 0.4999999702f, 3.497501373f, 0.4999999702f);
+ path->close();
+}
+
+static void test_path_crbug364224() {
+ SkPath path;
+ SkPaint paint;
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(84, 88));
+ SkCanvas* canvas = surface->getCanvas();
+
+ make_path_crbug364224_simplified(&path);
+ canvas->drawPath(path, paint);
+
+ make_path_crbug364224(&path);
+ canvas->drawPath(path, paint);
+}
+
+/**
+ * In debug mode, this path was causing an assertion to fail in
+ * SkPathStroker::preJoinTo() and, in Release, the use of an unitialized value.
+ */
+static void make_path_crbugskia2820(SkPath* path, skiatest::Reporter* reporter) {
+ SkPoint orig, p1, p2, p3;
+ orig = SkPoint::Make(1.f, 1.f);
+ p1 = SkPoint::Make(1.f - SK_ScalarNearlyZero, 1.f);
+ p2 = SkPoint::Make(1.f, 1.f + SK_ScalarNearlyZero);
+ p3 = SkPoint::Make(2.f, 2.f);
+
+ path->reset();
+ path->moveTo(orig);
+ path->cubicTo(p1, p2, p3);
+ path->close();
+}
+
+static void test_path_crbugskia2820(skiatest::Reporter* reporter) {//GrContext* context) {
+ SkPath path;
+ make_path_crbugskia2820(&path, reporter);
+
+ SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
+ stroke.setStrokeStyle(2 * SK_Scalar1);
+ stroke.applyToPath(&path, path);
+}
+
+static void make_path0(SkPath* path) {
+ // from * https://code.google.com/p/skia/issues/detail?id=1706
+
+ path->moveTo(146.939f, 1012.84f);
+ path->lineTo(181.747f, 1009.18f);
+ path->lineTo(182.165f, 1013.16f);
+ path->lineTo(147.357f, 1016.82f);
+ path->lineTo(146.939f, 1012.84f);
+ path->close();
+}
+
+static void make_path1(SkPath* path) {
+ path->addRect(SkRect::MakeXYWH(10, 10, 10, 1));
+}
+
+typedef void (*PathProc)(SkPath*);
+
+/*
+ * Regression test: we used to crash (overwrite internal storage) during
+ * construction of the region when the path was INVERSE. That is now fixed,
+ * so test these regions (which used to assert/crash).
+ *
+ * https://code.google.com/p/skia/issues/detail?id=1706
+ */
+static void test_path_to_region(skiatest::Reporter* reporter) {
+ PathProc procs[] = {
+ make_path0,
+ make_path1,
+ };
+
+ SkRegion clip;
+ clip.setRect(0, 0, 1255, 1925);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
+ SkPath path;
+ procs[i](&path);
+
+ SkRegion rgn;
+ rgn.setPath(path, clip);
+ path.toggleInverseFillType();
+ rgn.setPath(path, clip);
+ }
+}
+
+#if defined(WIN32)
+ #define SUPPRESS_VISIBILITY_WARNING
+#else
+ #define SUPPRESS_VISIBILITY_WARNING __attribute__((visibility("hidden")))
+#endif
+
+static void test_path_close_issue1474(skiatest::Reporter* reporter) {
+ // This test checks that r{Line,Quad,Conic,Cubic}To following a close()
+ // are relative to the point we close to, not relative to the point we close from.
+ SkPath path;
+ SkPoint last;
+
+ // Test rLineTo().
+ path.rLineTo(0, 100);
+ path.rLineTo(100, 0);
+ path.close(); // Returns us back to 0,0.
+ path.rLineTo(50, 50); // This should go to 50,50.
+
+ path.getLastPt(&last);
+ REPORTER_ASSERT(reporter, 50 == last.fX);
+ REPORTER_ASSERT(reporter, 50 == last.fY);
+
+ // Test rQuadTo().
+ path.rewind();
+ path.rLineTo(0, 100);
+ path.rLineTo(100, 0);
+ path.close();
+ path.rQuadTo(50, 50, 75, 75);
+
+ path.getLastPt(&last);
+ REPORTER_ASSERT(reporter, 75 == last.fX);
+ REPORTER_ASSERT(reporter, 75 == last.fY);
+
+ // Test rConicTo().
+ path.rewind();
+ path.rLineTo(0, 100);
+ path.rLineTo(100, 0);
+ path.close();
+ path.rConicTo(50, 50, 85, 85, 2);
+
+ path.getLastPt(&last);
+ REPORTER_ASSERT(reporter, 85 == last.fX);
+ REPORTER_ASSERT(reporter, 85 == last.fY);
+
+ // Test rCubicTo().
+ path.rewind();
+ path.rLineTo(0, 100);
+ path.rLineTo(100, 0);
+ path.close();
+ path.rCubicTo(50, 50, 85, 85, 95, 95);
+
+ path.getLastPt(&last);
+ REPORTER_ASSERT(reporter, 95 == last.fX);
+ REPORTER_ASSERT(reporter, 95 == last.fY);
+}
+
+static void test_android_specific_behavior(skiatest::Reporter* reporter) {
+#ifdef SK_BUILD_FOR_ANDROID
+ // Make sure we treat fGenerationID and fSourcePath correctly for each of
+ // copy, assign, rewind, reset, and swap.
+ SkPath original, source, anotherSource;
+ original.setSourcePath(&source);
+ original.moveTo(0, 0);
+ original.lineTo(1, 1);
+ REPORTER_ASSERT(reporter, original.getSourcePath() == &source);
+
+ uint32_t copyID, assignID;
+
+ // Test copy constructor. Copy generation ID, copy source path.
+ SkPath copy(original);
+ REPORTER_ASSERT(reporter, copy.getGenerationID() == original.getGenerationID());
+ REPORTER_ASSERT(reporter, copy.getSourcePath() == original.getSourcePath());
+
+ // Test assigment operator. Change generation ID, copy source path.
+ SkPath assign;
+ assignID = assign.getGenerationID();
+ assign = original;
+ REPORTER_ASSERT(reporter, assign.getGenerationID() != assignID);
+ REPORTER_ASSERT(reporter, assign.getSourcePath() == original.getSourcePath());
+
+ // Test rewind. Change generation ID, don't touch source path.
+ copyID = copy.getGenerationID();
+ copy.rewind();
+ REPORTER_ASSERT(reporter, copy.getGenerationID() != copyID);
+ REPORTER_ASSERT(reporter, copy.getSourcePath() == original.getSourcePath());
+
+ // Test reset. Change generation ID, don't touch source path.
+ assignID = assign.getGenerationID();
+ assign.reset();
+ REPORTER_ASSERT(reporter, assign.getGenerationID() != assignID);
+ REPORTER_ASSERT(reporter, assign.getSourcePath() == original.getSourcePath());
+
+ // Test swap. Swap the generation IDs, swap source paths.
+ copy.reset();
+ copy.moveTo(2, 2);
+ copy.setSourcePath(&anotherSource);
+ copyID = copy.getGenerationID();
+ assign.moveTo(3, 3);
+ assignID = assign.getGenerationID();
+ copy.swap(assign);
+ REPORTER_ASSERT(reporter, copy.getGenerationID() != copyID);
+ REPORTER_ASSERT(reporter, assign.getGenerationID() != assignID);
+ REPORTER_ASSERT(reporter, copy.getSourcePath() == original.getSourcePath());
+ REPORTER_ASSERT(reporter, assign.getSourcePath() == &anotherSource);
+#endif
+}
+
+static void test_gen_id(skiatest::Reporter* reporter) {
+ SkPath a, b;
+ REPORTER_ASSERT(reporter, a.getGenerationID() == b.getGenerationID());
+
+ a.moveTo(0, 0);
+ const uint32_t z = a.getGenerationID();
+ REPORTER_ASSERT(reporter, z != b.getGenerationID());
+
+ a.reset();
+ REPORTER_ASSERT(reporter, a.getGenerationID() == b.getGenerationID());
+
+ a.moveTo(1, 1);
+ const uint32_t y = a.getGenerationID();
+ REPORTER_ASSERT(reporter, z != y);
+
+ b.moveTo(2, 2);
+ const uint32_t x = b.getGenerationID();
+ REPORTER_ASSERT(reporter, x != y && x != z);
+
+ a.swap(b);
+ REPORTER_ASSERT(reporter, b.getGenerationID() == y && a.getGenerationID() == x);
+
+ b = a;
+ REPORTER_ASSERT(reporter, b.getGenerationID() == x);
+
+ SkPath c(a);
+ REPORTER_ASSERT(reporter, c.getGenerationID() == x);
+
+ c.lineTo(3, 3);
+ const uint32_t w = c.getGenerationID();
+ REPORTER_ASSERT(reporter, b.getGenerationID() == x);
+ REPORTER_ASSERT(reporter, a.getGenerationID() == x);
+ REPORTER_ASSERT(reporter, w != x);
+
+#ifdef SK_BUILD_FOR_ANDROID
+ static bool kExpectGenIDToIgnoreFill = false;
+#else
+ static bool kExpectGenIDToIgnoreFill = true;
+#endif
+
+ c.toggleInverseFillType();
+ const uint32_t v = c.getGenerationID();
+ REPORTER_ASSERT(reporter, (v == w) == kExpectGenIDToIgnoreFill);
+
+ c.rewind();
+ REPORTER_ASSERT(reporter, v != c.getGenerationID());
+}
+
+// This used to assert in the debug build, as the edges did not all line-up.
+static void test_bad_cubic_crbug234190() {
+ SkPath path;
+ path.moveTo(13.8509f, 3.16858f);
+ path.cubicTo(-2.35893e+08f, -4.21044e+08f,
+ -2.38991e+08f, -4.26573e+08f,
+ -2.41016e+08f, -4.30188e+08f);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(84, 88));
+ surface->getCanvas()->drawPath(path, paint);
+}
+
+static void test_bad_cubic_crbug229478() {
+ const SkPoint pts[] = {
+ { 4595.91064f, -11596.9873f },
+ { 4597.2168f, -11595.9414f },
+ { 4598.52344f, -11594.8955f },
+ { 4599.83008f, -11593.8496f },
+ };
+
+ SkPath path;
+ path.moveTo(pts[0]);
+ path.cubicTo(pts[1], pts[2], pts[3]);
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(20);
+
+ SkPath dst;
+ // Before the fix, this would infinite-recurse, and run out of stack
+ // because we would keep trying to subdivide a degenerate cubic segment.
+ paint.getFillPath(path, &dst, NULL);
+}
+
+static void build_path_170666(SkPath& path) {
+ path.moveTo(17.9459f, 21.6344f);
+ path.lineTo(139.545f, -47.8105f);
+ path.lineTo(139.545f, -47.8105f);
+ path.lineTo(131.07f, -47.3888f);
+ path.lineTo(131.07f, -47.3888f);
+ path.lineTo(122.586f, -46.9532f);
+ path.lineTo(122.586f, -46.9532f);
+ path.lineTo(18076.6f, 31390.9f);
+ path.lineTo(18076.6f, 31390.9f);
+ path.lineTo(18085.1f, 31390.5f);
+ path.lineTo(18085.1f, 31390.5f);
+ path.lineTo(18076.6f, 31390.9f);
+ path.lineTo(18076.6f, 31390.9f);
+ path.lineTo(17955, 31460.3f);
+ path.lineTo(17955, 31460.3f);
+ path.lineTo(17963.5f, 31459.9f);
+ path.lineTo(17963.5f, 31459.9f);
+ path.lineTo(17971.9f, 31459.5f);
+ path.lineTo(17971.9f, 31459.5f);
+ path.lineTo(17.9551f, 21.6205f);
+ path.lineTo(17.9551f, 21.6205f);
+ path.lineTo(9.47091f, 22.0561f);
+ path.lineTo(9.47091f, 22.0561f);
+ path.lineTo(17.9459f, 21.6344f);
+ path.lineTo(17.9459f, 21.6344f);
+ path.close();path.moveTo(0.995934f, 22.4779f);
+ path.lineTo(0.986725f, 22.4918f);
+ path.lineTo(0.986725f, 22.4918f);
+ path.lineTo(17955, 31460.4f);
+ path.lineTo(17955, 31460.4f);
+ path.lineTo(17971.9f, 31459.5f);
+ path.lineTo(17971.9f, 31459.5f);
+ path.lineTo(18093.6f, 31390.1f);
+ path.lineTo(18093.6f, 31390.1f);
+ path.lineTo(18093.6f, 31390);
+ path.lineTo(18093.6f, 31390);
+ path.lineTo(139.555f, -47.8244f);
+ path.lineTo(139.555f, -47.8244f);
+ path.lineTo(122.595f, -46.9671f);
+ path.lineTo(122.595f, -46.9671f);
+ path.lineTo(0.995934f, 22.4779f);
+ path.lineTo(0.995934f, 22.4779f);
+ path.close();
+ path.moveTo(5.43941f, 25.5223f);
+ path.lineTo(798267, -28871.1f);
+ path.lineTo(798267, -28871.1f);
+ path.lineTo(3.12512e+06f, -113102);
+ path.lineTo(3.12512e+06f, -113102);
+ path.cubicTo(5.16324e+06f, -186882, 8.15247e+06f, -295092, 1.1957e+07f, -432813);
+ path.cubicTo(1.95659e+07f, -708257, 3.04359e+07f, -1.10175e+06f, 4.34798e+07f, -1.57394e+06f);
+ path.cubicTo(6.95677e+07f, -2.51831e+06f, 1.04352e+08f, -3.77748e+06f, 1.39135e+08f, -5.03666e+06f);
+ path.cubicTo(1.73919e+08f, -6.29583e+06f, 2.08703e+08f, -7.555e+06f, 2.34791e+08f, -8.49938e+06f);
+ path.cubicTo(2.47835e+08f, -8.97157e+06f, 2.58705e+08f, -9.36506e+06f, 2.66314e+08f, -9.6405e+06f);
+ path.cubicTo(2.70118e+08f, -9.77823e+06f, 2.73108e+08f, -9.88644e+06f, 2.75146e+08f, -9.96022e+06f);
+ path.cubicTo(2.76165e+08f, -9.99711e+06f, 2.76946e+08f, -1.00254e+07f, 2.77473e+08f, -1.00444e+07f);
+ path.lineTo(2.78271e+08f, -1.00733e+07f);
+ path.lineTo(2.78271e+08f, -1.00733e+07f);
+ path.cubicTo(2.78271e+08f, -1.00733e+07f, 2.08703e+08f, -7.555e+06f, 135.238f, 23.3517f);
+ path.cubicTo(131.191f, 23.4981f, 125.995f, 23.7976f, 123.631f, 24.0206f);
+ path.cubicTo(121.267f, 24.2436f, 122.631f, 24.3056f, 126.677f, 24.1591f);
+ path.cubicTo(2.08703e+08f, -7.555e+06f, 2.78271e+08f, -1.00733e+07f, 2.78271e+08f, -1.00733e+07f);
+ path.lineTo(2.77473e+08f, -1.00444e+07f);
+ path.lineTo(2.77473e+08f, -1.00444e+07f);
+ path.cubicTo(2.76946e+08f, -1.00254e+07f, 2.76165e+08f, -9.99711e+06f, 2.75146e+08f, -9.96022e+06f);
+ path.cubicTo(2.73108e+08f, -9.88644e+06f, 2.70118e+08f, -9.77823e+06f, 2.66314e+08f, -9.6405e+06f);
+ path.cubicTo(2.58705e+08f, -9.36506e+06f, 2.47835e+08f, -8.97157e+06f, 2.34791e+08f, -8.49938e+06f);
+ path.cubicTo(2.08703e+08f, -7.555e+06f, 1.73919e+08f, -6.29583e+06f, 1.39135e+08f, -5.03666e+06f);
+ path.cubicTo(1.04352e+08f, -3.77749e+06f, 6.95677e+07f, -2.51831e+06f, 4.34798e+07f, -1.57394e+06f);
+ path.cubicTo(3.04359e+07f, -1.10175e+06f, 1.95659e+07f, -708258, 1.1957e+07f, -432814);
+ path.cubicTo(8.15248e+06f, -295092, 5.16324e+06f, -186883, 3.12513e+06f, -113103);
+ path.lineTo(798284, -28872);
+ path.lineTo(798284, -28872);
+ path.lineTo(22.4044f, 24.6677f);
+ path.lineTo(22.4044f, 24.6677f);
+ path.cubicTo(22.5186f, 24.5432f, 18.8134f, 24.6337f, 14.1287f, 24.8697f);
+ path.cubicTo(9.4439f, 25.1057f, 5.55359f, 25.3978f, 5.43941f, 25.5223f);
+ path.close();
+}
+
+static void build_path_simple_170666(SkPath& path) {
+ path.moveTo(126.677f, 24.1591f);
+ path.cubicTo(2.08703e+08f, -7.555e+06f, 2.78271e+08f, -1.00733e+07f, 2.78271e+08f, -1.00733e+07f);
+}
+
+// This used to assert in the SK_DEBUG build, as the clip step would fail with
+// too-few interations in our cubic-line intersection code. That code now runs
+// 24 interations (instead of 16).
+static void test_crbug_170666() {
+ SkPath path;
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(1000, 1000));
+
+ build_path_simple_170666(path);
+ surface->getCanvas()->drawPath(path, paint);
+
+ build_path_170666(path);
+ surface->getCanvas()->drawPath(path, paint);
+}
+
+static void test_addrect(skiatest::Reporter* reporter) {
+ SkPath path;
+ path.lineTo(0, 0);
+ path.addRect(SkRect::MakeWH(50, 100));
+ REPORTER_ASSERT(reporter, path.isRect(NULL));
+
+ path.reset();
+ path.lineTo(FLT_EPSILON, FLT_EPSILON);
+ path.addRect(SkRect::MakeWH(50, 100));
+ REPORTER_ASSERT(reporter, !path.isRect(NULL));
+
+ path.reset();
+ path.quadTo(0, 0, 0, 0);
+ path.addRect(SkRect::MakeWH(50, 100));
+ REPORTER_ASSERT(reporter, !path.isRect(NULL));
+
+ path.reset();
+ path.conicTo(0, 0, 0, 0, 0.5f);
+ path.addRect(SkRect::MakeWH(50, 100));
+ REPORTER_ASSERT(reporter, !path.isRect(NULL));
+
+ path.reset();
+ path.cubicTo(0, 0, 0, 0, 0, 0);
+ path.addRect(SkRect::MakeWH(50, 100));
+ REPORTER_ASSERT(reporter, !path.isRect(NULL));
+}
+
+// Make sure we stay non-finite once we get there (unless we reset or rewind).
+static void test_addrect_isfinite(skiatest::Reporter* reporter) {
+ SkPath path;
+
+ path.addRect(SkRect::MakeWH(50, 100));
+ REPORTER_ASSERT(reporter, path.isFinite());
+
+ path.moveTo(0, 0);
+ path.lineTo(SK_ScalarInfinity, 42);
+ REPORTER_ASSERT(reporter, !path.isFinite());
+
+ path.addRect(SkRect::MakeWH(50, 100));
+ REPORTER_ASSERT(reporter, !path.isFinite());
+
+ path.reset();
+ REPORTER_ASSERT(reporter, path.isFinite());
+
+ path.addRect(SkRect::MakeWH(50, 100));
+ REPORTER_ASSERT(reporter, path.isFinite());
+}
+
+static void build_big_path(SkPath* path, bool reducedCase) {
+ if (reducedCase) {
+ path->moveTo(577330, 1971.72f);
+ path->cubicTo(10.7082f, -116.596f, 262.057f, 45.6468f, 294.694f, 1.96237f);
+ } else {
+ path->moveTo(60.1631f, 7.70567f);
+ path->quadTo(60.1631f, 7.70567f, 0.99474f, 0.901199f);
+ path->lineTo(577379, 1977.77f);
+ path->quadTo(577364, 1979.57f, 577325, 1980.26f);
+ path->quadTo(577286, 1980.95f, 577245, 1980.13f);
+ path->quadTo(577205, 1979.3f, 577187, 1977.45f);
+ path->quadTo(577168, 1975.6f, 577183, 1973.8f);
+ path->quadTo(577198, 1972, 577238, 1971.31f);
+ path->quadTo(577277, 1970.62f, 577317, 1971.45f);
+ path->quadTo(577330, 1971.72f, 577341, 1972.11f);
+ path->cubicTo(10.7082f, -116.596f, 262.057f, 45.6468f, 294.694f, 1.96237f);
+ path->moveTo(306.718f, -32.912f);
+ path->cubicTo(30.531f, 10.0005f, 1502.47f, 13.2804f, 84.3088f, 9.99601f);
+ }
+}
+
+static void test_clipped_cubic() {
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(640, 480));
+
+ // This path used to assert, because our cubic-chopping code incorrectly
+ // moved control points after the chop. This test should be run in SK_DEBUG
+ // mode to ensure that we no long assert.
+ SkPath path;
+ for (int doReducedCase = 0; doReducedCase <= 1; ++doReducedCase) {
+ build_big_path(&path, SkToBool(doReducedCase));
+
+ SkPaint paint;
+ for (int doAA = 0; doAA <= 1; ++doAA) {
+ paint.setAntiAlias(SkToBool(doAA));
+ surface->getCanvas()->drawPath(path, paint);
+ }
+ }
+}
+
+// Inspired by http://ie.microsoft.com/testdrive/Performance/Chalkboard/
+// which triggered an assert, from a tricky cubic. This test replicates that
+// example, so we can ensure that we handle it (in SkEdge.cpp), and don't
+// assert in the SK_DEBUG build.
+static void test_tricky_cubic() {
+ const SkPoint pts[] = {
+ { SkDoubleToScalar(18.8943768), SkDoubleToScalar(129.121277) },
+ { SkDoubleToScalar(18.8937435), SkDoubleToScalar(129.121689) },
+ { SkDoubleToScalar(18.8950119), SkDoubleToScalar(129.120422) },
+ { SkDoubleToScalar(18.5030727), SkDoubleToScalar(129.13121) },
+ };
+
+ SkPath path;
+ path.moveTo(pts[0]);
+ path.cubicTo(pts[1], pts[2], pts[3]);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkSurface* surface = SkSurface::NewRasterPMColor(19, 130);
+ surface->getCanvas()->drawPath(path, paint);
+ surface->unref();
+}
+
+// Inspired by http://code.google.com/p/chromium/issues/detail?id=141651
+//
+static void test_isfinite_after_transform(skiatest::Reporter* reporter) {
+ SkPath path;
+ path.quadTo(157, 366, 286, 208);
+ path.arcTo(37, 442, 315, 163, 957494590897113.0f);
+
+ SkMatrix matrix;
+ matrix.setScale(1000*1000, 1000*1000);
+
+ // Be sure that path::transform correctly updates isFinite and the bounds
+ // if the transformation overflows. The previous bug was that isFinite was
+ // set to true in this case, but the bounds were not set to empty (which
+ // they should be).
+ while (path.isFinite()) {
+ REPORTER_ASSERT(reporter, path.getBounds().isFinite());
+ REPORTER_ASSERT(reporter, !path.getBounds().isEmpty());
+ path.transform(matrix);
+ }
+ REPORTER_ASSERT(reporter, path.getBounds().isEmpty());
+
+ matrix.setTranslate(SK_Scalar1, SK_Scalar1);
+ path.transform(matrix);
+ // we need to still be non-finite
+ REPORTER_ASSERT(reporter, !path.isFinite());
+ REPORTER_ASSERT(reporter, path.getBounds().isEmpty());
+}
+
+static void add_corner_arc(SkPath* path, const SkRect& rect,
+ SkScalar xIn, SkScalar yIn,
+ int startAngle)
+{
+
+ SkScalar rx = SkMinScalar(rect.width(), xIn);
+ SkScalar ry = SkMinScalar(rect.height(), yIn);
+
+ SkRect arcRect;
+ arcRect.set(-rx, -ry, rx, ry);
+ switch (startAngle) {
+ case 0:
+ arcRect.offset(rect.fRight - arcRect.fRight, rect.fBottom - arcRect.fBottom);
+ break;
+ case 90:
+ arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fBottom - arcRect.fBottom);
+ break;
+ case 180:
+ arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fTop - arcRect.fTop);
+ break;
+ case 270:
+ arcRect.offset(rect.fRight - arcRect.fRight, rect.fTop - arcRect.fTop);
+ break;
+ default:
+ break;
+ }
+
+ path->arcTo(arcRect, SkIntToScalar(startAngle), SkIntToScalar(90), false);
+}
+
+static void make_arb_round_rect(SkPath* path, const SkRect& r,
+ SkScalar xCorner, SkScalar yCorner) {
+ // we are lazy here and use the same x & y for each corner
+ add_corner_arc(path, r, xCorner, yCorner, 270);
+ add_corner_arc(path, r, xCorner, yCorner, 0);
+ add_corner_arc(path, r, xCorner, yCorner, 90);
+ add_corner_arc(path, r, xCorner, yCorner, 180);
+ path->close();
+}
+
+// Chrome creates its own round rects with each corner possibly being different.
+// Performance will suffer if they are not convex.
+// Note: PathBench::ArbRoundRectBench performs almost exactly
+// the same test (but with drawing)
+static void test_arb_round_rect_is_convex(skiatest::Reporter* reporter) {
+ SkRandom rand;
+ SkRect r;
+
+ for (int i = 0; i < 5000; ++i) {
+
+ SkScalar size = rand.nextUScalar1() * 30;
+ if (size < SK_Scalar1) {
+ continue;
+ }
+ r.fLeft = rand.nextUScalar1() * 300;
+ r.fTop = rand.nextUScalar1() * 300;
+ r.fRight = r.fLeft + 2 * size;
+ r.fBottom = r.fTop + 2 * size;
+
+ SkPath temp;
+
+ make_arb_round_rect(&temp, r, r.width() / 10, r.height() / 15);
+
+ REPORTER_ASSERT(reporter, temp.isConvex());
+ }
+}
+
+// Chrome will sometimes create a 0 radius round rect. The degenerate
+// quads prevent the path from being converted to a rect
+// Note: PathBench::ArbRoundRectBench performs almost exactly
+// the same test (but with drawing)
+static void test_arb_zero_rad_round_rect_is_rect(skiatest::Reporter* reporter) {
+ SkRandom rand;
+ SkRect r;
+
+ for (int i = 0; i < 5000; ++i) {
+
+ SkScalar size = rand.nextUScalar1() * 30;
+ if (size < SK_Scalar1) {
+ continue;
+ }
+ r.fLeft = rand.nextUScalar1() * 300;
+ r.fTop = rand.nextUScalar1() * 300;
+ r.fRight = r.fLeft + 2 * size;
+ r.fBottom = r.fTop + 2 * size;
+
+ SkPath temp;
+
+ make_arb_round_rect(&temp, r, 0, 0);
+
+ SkRect result;
+ REPORTER_ASSERT(reporter, temp.isRect(&result));
+ REPORTER_ASSERT(reporter, r == result);
+ }
+}
+
+static void test_rect_isfinite(skiatest::Reporter* reporter) {
+ const SkScalar inf = SK_ScalarInfinity;
+ const SkScalar negInf = SK_ScalarNegativeInfinity;
+ const SkScalar nan = SK_ScalarNaN;
+
+ SkRect r;
+ r.setEmpty();
+ REPORTER_ASSERT(reporter, r.isFinite());
+ r.set(0, 0, inf, negInf);
+ REPORTER_ASSERT(reporter, !r.isFinite());
+ r.set(0, 0, nan, 0);
+ REPORTER_ASSERT(reporter, !r.isFinite());
+
+ SkPoint pts[] = {
+ { 0, 0 },
+ { SK_Scalar1, 0 },
+ { 0, SK_Scalar1 },
+ };
+
+ bool isFine = r.setBoundsCheck(pts, 3);
+ REPORTER_ASSERT(reporter, isFine);
+ REPORTER_ASSERT(reporter, !r.isEmpty());
+
+ pts[1].set(inf, 0);
+ isFine = r.setBoundsCheck(pts, 3);
+ REPORTER_ASSERT(reporter, !isFine);
+ REPORTER_ASSERT(reporter, r.isEmpty());
+
+ pts[1].set(nan, 0);
+ isFine = r.setBoundsCheck(pts, 3);
+ REPORTER_ASSERT(reporter, !isFine);
+ REPORTER_ASSERT(reporter, r.isEmpty());
+}
+
+static void test_path_isfinite(skiatest::Reporter* reporter) {
+ const SkScalar inf = SK_ScalarInfinity;
+ const SkScalar negInf = SK_ScalarNegativeInfinity;
+ const SkScalar nan = SK_ScalarNaN;
+
+ SkPath path;
+ REPORTER_ASSERT(reporter, path.isFinite());
+
+ path.reset();
+ REPORTER_ASSERT(reporter, path.isFinite());
+
+ path.reset();
+ path.moveTo(SK_Scalar1, 0);
+ REPORTER_ASSERT(reporter, path.isFinite());
+
+ path.reset();
+ path.moveTo(inf, negInf);
+ REPORTER_ASSERT(reporter, !path.isFinite());
+
+ path.reset();
+ path.moveTo(nan, 0);
+ REPORTER_ASSERT(reporter, !path.isFinite());
+}
+
+static void test_isfinite(skiatest::Reporter* reporter) {
+ test_rect_isfinite(reporter);
+ test_path_isfinite(reporter);
+}
+
+// assert that we always
+// start with a moveTo
+// only have 1 moveTo
+// only have Lines after that
+// end with a single close
+// only have (at most) 1 close
+//
+static void test_poly(skiatest::Reporter* reporter, const SkPath& path,
+ const SkPoint srcPts[], bool expectClose) {
+ SkPath::RawIter iter(path);
+ SkPoint pts[4];
+
+ bool firstTime = true;
+ bool foundClose = false;
+ for (;;) {
+ switch (iter.next(pts)) {
+ case SkPath::kMove_Verb:
+ REPORTER_ASSERT(reporter, firstTime);
+ REPORTER_ASSERT(reporter, pts[0] == srcPts[0]);
+ srcPts++;
+ firstTime = false;
+ break;
+ case SkPath::kLine_Verb:
+ REPORTER_ASSERT(reporter, !firstTime);
+ REPORTER_ASSERT(reporter, pts[1] == srcPts[0]);
+ srcPts++;
+ break;
+ case SkPath::kQuad_Verb:
+ REPORTER_ASSERT_MESSAGE(reporter, false, "unexpected quad verb");
+ break;
+ case SkPath::kConic_Verb:
+ REPORTER_ASSERT_MESSAGE(reporter, false, "unexpected conic verb");
+ break;
+ case SkPath::kCubic_Verb:
+ REPORTER_ASSERT_MESSAGE(reporter, false, "unexpected cubic verb");
+ break;
+ case SkPath::kClose_Verb:
+ REPORTER_ASSERT(reporter, !firstTime);
+ REPORTER_ASSERT(reporter, !foundClose);
+ REPORTER_ASSERT(reporter, expectClose);
+ foundClose = true;
+ break;
+ case SkPath::kDone_Verb:
+ goto DONE;
+ }
+ }
+DONE:
+ REPORTER_ASSERT(reporter, foundClose == expectClose);
+}
+
+static void test_addPoly(skiatest::Reporter* reporter) {
+ SkPoint pts[32];
+ SkRandom rand;
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) {
+ pts[i].fX = rand.nextSScalar1();
+ pts[i].fY = rand.nextSScalar1();
+ }
+
+ for (int doClose = 0; doClose <= 1; ++doClose) {
+ for (size_t count = 1; count <= SK_ARRAY_COUNT(pts); ++count) {
+ SkPath path;
+ path.addPoly(pts, count, SkToBool(doClose));
+ test_poly(reporter, path, pts, SkToBool(doClose));
+ }
+ }
+}
+
+static void test_strokerec(skiatest::Reporter* reporter) {
+ SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
+ REPORTER_ASSERT(reporter, rec.isFillStyle());
+
+ rec.setHairlineStyle();
+ REPORTER_ASSERT(reporter, rec.isHairlineStyle());
+
+ rec.setStrokeStyle(SK_Scalar1, false);
+ REPORTER_ASSERT(reporter, SkStrokeRec::kStroke_Style == rec.getStyle());
+
+ rec.setStrokeStyle(SK_Scalar1, true);
+ REPORTER_ASSERT(reporter, SkStrokeRec::kStrokeAndFill_Style == rec.getStyle());
+
+ rec.setStrokeStyle(0, false);
+ REPORTER_ASSERT(reporter, SkStrokeRec::kHairline_Style == rec.getStyle());
+
+ rec.setStrokeStyle(0, true);
+ REPORTER_ASSERT(reporter, SkStrokeRec::kFill_Style == rec.getStyle());
+}
+
+// Set this for paths that don't have a consistent direction such as a bowtie.
+// (cheapComputeDirection is not expected to catch these.)
+static const SkPath::Direction kDontCheckDir = static_cast<SkPath::Direction>(-1);
+
+static void check_direction(skiatest::Reporter* reporter, const SkPath& path,
+ SkPath::Direction expected) {
+ if (expected == kDontCheckDir) {
+ return;
+ }
+ SkPath copy(path); // we make a copy so that we don't cache the result on the passed in path.
+
+ SkPath::Direction dir;
+ if (copy.cheapComputeDirection(&dir)) {
+ REPORTER_ASSERT(reporter, dir == expected);
+ } else {
+ REPORTER_ASSERT(reporter, SkPath::kUnknown_Direction == expected);
+ }
+}
+
+static void test_direction(skiatest::Reporter* reporter) {
+ size_t i;
+ SkPath path;
+ REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
+ REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCW_Direction));
+ REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCCW_Direction));
+ REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kUnknown_Direction));
+
+ static const char* gDegen[] = {
+ "M 10 10",
+ "M 10 10 M 20 20",
+ "M 10 10 L 20 20",
+ "M 10 10 L 10 10 L 10 10",
+ "M 10 10 Q 10 10 10 10",
+ "M 10 10 C 10 10 10 10 10 10",
+ };
+ for (i = 0; i < SK_ARRAY_COUNT(gDegen); ++i) {
+ path.reset();
+ bool valid = SkParsePath::FromSVGString(gDegen[i], &path);
+ REPORTER_ASSERT(reporter, valid);
+ REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
+ }
+
+ static const char* gCW[] = {
+ "M 10 10 L 10 10 Q 20 10 20 20",
+ "M 10 10 C 20 10 20 20 20 20",
+ "M 20 10 Q 20 20 30 20 L 10 20", // test double-back at y-max
+ // rect with top two corners replaced by cubics with identical middle
+ // control points
+ "M 10 10 C 10 0 10 0 20 0 L 40 0 C 50 0 50 0 50 10",
+ "M 20 10 L 0 10 Q 10 10 20 0", // left, degenerate serif
+ };
+ for (i = 0; i < SK_ARRAY_COUNT(gCW); ++i) {
+ path.reset();
+ bool valid = SkParsePath::FromSVGString(gCW[i], &path);
+ REPORTER_ASSERT(reporter, valid);
+ check_direction(reporter, path, SkPath::kCW_Direction);
+ }
+
+ static const char* gCCW[] = {
+ "M 10 10 L 10 10 Q 20 10 20 -20",
+ "M 10 10 C 20 10 20 -20 20 -20",
+ "M 20 10 Q 20 20 10 20 L 30 20", // test double-back at y-max
+ // rect with top two corners replaced by cubics with identical middle
+ // control points
+ "M 50 10 C 50 0 50 0 40 0 L 20 0 C 10 0 10 0 10 10",
+ "M 10 10 L 30 10 Q 20 10 10 0", // right, degenerate serif
+ };
+ for (i = 0; i < SK_ARRAY_COUNT(gCCW); ++i) {
+ path.reset();
+ bool valid = SkParsePath::FromSVGString(gCCW[i], &path);
+ REPORTER_ASSERT(reporter, valid);
+ check_direction(reporter, path, SkPath::kCCW_Direction);
+ }
+
+ // Test two donuts, each wound a different direction. Only the outer contour
+ // determines the cheap direction
+ path.reset();
+ path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCW_Direction);
+ path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCCW_Direction);
+ check_direction(reporter, path, SkPath::kCW_Direction);
+
+ path.reset();
+ path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCW_Direction);
+ path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCCW_Direction);
+ check_direction(reporter, path, SkPath::kCCW_Direction);
+
+ // triangle with one point really far from the origin.
+ path.reset();
+ // the first point is roughly 1.05e10, 1.05e10
+ path.moveTo(SkBits2Float(0x501c7652), SkBits2Float(0x501c7652));
+ path.lineTo(110 * SK_Scalar1, -10 * SK_Scalar1);
+ path.lineTo(-10 * SK_Scalar1, 60 * SK_Scalar1);
+ check_direction(reporter, path, SkPath::kCCW_Direction);
+
+ path.reset();
+ path.conicTo(20, 0, 20, 20, 0.5f);
+ path.close();
+ check_direction(reporter, path, SkPath::kCW_Direction);
+
+ path.reset();
+ path.lineTo(1, 1e7f);
+ path.lineTo(1e7f, 2e7f);
+ path.close();
+ REPORTER_ASSERT(reporter, SkPath::kConvex_Convexity == path.getConvexity());
+ check_direction(reporter, path, SkPath::kCCW_Direction);
+}
+
+static void add_rect(SkPath* path, const SkRect& r) {
+ path->moveTo(r.fLeft, r.fTop);
+ path->lineTo(r.fRight, r.fTop);
+ path->lineTo(r.fRight, r.fBottom);
+ path->lineTo(r.fLeft, r.fBottom);
+ path->close();
+}
+
+static void test_bounds(skiatest::Reporter* reporter) {
+ static const SkRect rects[] = {
+ { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
+ { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
+ { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
+ { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
+ };
+
+ SkPath path0, path1;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) {
+ path0.addRect(rects[i]);
+ add_rect(&path1, rects[i]);
+ }
+
+ REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
+}
+
+static void stroke_cubic(const SkPoint pts[4]) {
+ SkPath path;
+ path.moveTo(pts[0]);
+ path.cubicTo(pts[1], pts[2], pts[3]);
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SK_Scalar1 * 2);
+
+ SkPath fill;
+ paint.getFillPath(path, &fill);
+}
+
+// just ensure this can run w/o any SkASSERTS firing in the debug build
+// we used to assert due to differences in how we determine a degenerate vector
+// but that was fixed with the introduction of SkPoint::CanNormalize
+static void stroke_tiny_cubic() {
+ SkPoint p0[] = {
+ { 372.0f, 92.0f },
+ { 372.0f, 92.0f },
+ { 372.0f, 92.0f },
+ { 372.0f, 92.0f },
+ };
+
+ stroke_cubic(p0);
+
+ SkPoint p1[] = {
+ { 372.0f, 92.0f },
+ { 372.0007f, 92.000755f },
+ { 371.99927f, 92.003922f },
+ { 371.99826f, 92.003899f },
+ };
+
+ stroke_cubic(p1);
+}
+
+static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
+ for (int i = 0; i < 2; ++i) {
+ SkPath::Iter iter(path, SkToBool(i));
+ SkPoint mv;
+ SkPoint pts[4];
+ SkPath::Verb v;
+ int nMT = 0;
+ int nCL = 0;
+ mv.set(0, 0);
+ while (SkPath::kDone_Verb != (v = iter.next(pts))) {
+ switch (v) {
+ case SkPath::kMove_Verb:
+ mv = pts[0];
+ ++nMT;
+ break;
+ case SkPath::kClose_Verb:
+ REPORTER_ASSERT(reporter, mv == pts[0]);
+ ++nCL;
+ break;
+ default:
+ break;
+ }
+ }
+ // if we force a close on the interator we should have a close
+ // for every moveTo
+ REPORTER_ASSERT(reporter, !i || nMT == nCL);
+ }
+}
+
+static void test_close(skiatest::Reporter* reporter) {
+ SkPath closePt;
+ closePt.moveTo(0, 0);
+ closePt.close();
+ check_close(reporter, closePt);
+
+ SkPath openPt;
+ openPt.moveTo(0, 0);
+ check_close(reporter, openPt);
+
+ SkPath empty;
+ check_close(reporter, empty);
+ empty.close();
+ check_close(reporter, empty);
+
+ SkPath rect;
+ rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
+ check_close(reporter, rect);
+ rect.close();
+ check_close(reporter, rect);
+
+ SkPath quad;
+ quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
+ check_close(reporter, quad);
+ quad.close();
+ check_close(reporter, quad);
+
+ SkPath cubic;
+ quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
+ 10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
+ check_close(reporter, cubic);
+ cubic.close();
+ check_close(reporter, cubic);
+
+ SkPath line;
+ line.moveTo(SK_Scalar1, SK_Scalar1);
+ line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
+ check_close(reporter, line);
+ line.close();
+ check_close(reporter, line);
+
+ SkPath rect2;
+ rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
+ rect2.close();
+ rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
+ check_close(reporter, rect2);
+ rect2.close();
+ check_close(reporter, rect2);
+
+ SkPath oval3;
+ oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
+ oval3.close();
+ oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
+ check_close(reporter, oval3);
+ oval3.close();
+ check_close(reporter, oval3);
+
+ SkPath moves;
+ moves.moveTo(SK_Scalar1, SK_Scalar1);
+ moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
+ moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
+ moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
+ check_close(reporter, moves);
+
+ stroke_tiny_cubic();
+}
+
+static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
+ SkPath::Convexity expected) {
+ SkPath copy(path); // we make a copy so that we don't cache the result on the passed in path.
+ SkPath::Convexity c = copy.getConvexity();
+ REPORTER_ASSERT(reporter, c == expected);
+}
+
+static void test_convexity2(skiatest::Reporter* reporter) {
+ SkPath pt;
+ pt.moveTo(0, 0);
+ pt.close();
+ check_convexity(reporter, pt, SkPath::kConvex_Convexity);
+ check_direction(reporter, pt, SkPath::kUnknown_Direction);
+
+ SkPath line;
+ line.moveTo(12*SK_Scalar1, 20*SK_Scalar1);
+ line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1);
+ line.close();
+ check_convexity(reporter, line, SkPath::kConvex_Convexity);
+ check_direction(reporter, line, SkPath::kUnknown_Direction);
+
+ SkPath triLeft;
+ triLeft.moveTo(0, 0);
+ triLeft.lineTo(SK_Scalar1, 0);
+ triLeft.lineTo(SK_Scalar1, SK_Scalar1);
+ triLeft.close();
+ check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
+ check_direction(reporter, triLeft, SkPath::kCW_Direction);
+
+ SkPath triRight;
+ triRight.moveTo(0, 0);
+ triRight.lineTo(-SK_Scalar1, 0);
+ triRight.lineTo(SK_Scalar1, SK_Scalar1);
+ triRight.close();
+ check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
+ check_direction(reporter, triRight, SkPath::kCCW_Direction);
+
+ SkPath square;
+ square.moveTo(0, 0);
+ square.lineTo(SK_Scalar1, 0);
+ square.lineTo(SK_Scalar1, SK_Scalar1);
+ square.lineTo(0, SK_Scalar1);
+ square.close();
+ check_convexity(reporter, square, SkPath::kConvex_Convexity);
+ check_direction(reporter, square, SkPath::kCW_Direction);
+
+ SkPath redundantSquare;
+ redundantSquare.moveTo(0, 0);
+ redundantSquare.lineTo(0, 0);
+ redundantSquare.lineTo(0, 0);
+ redundantSquare.lineTo(SK_Scalar1, 0);
+ redundantSquare.lineTo(SK_Scalar1, 0);
+ redundantSquare.lineTo(SK_Scalar1, 0);
+ redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
+ redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
+ redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
+ redundantSquare.lineTo(0, SK_Scalar1);
+ redundantSquare.lineTo(0, SK_Scalar1);
+ redundantSquare.lineTo(0, SK_Scalar1);
+ redundantSquare.close();
+ check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
+ check_direction(reporter, redundantSquare, SkPath::kCW_Direction);
+
+ SkPath bowTie;
+ bowTie.moveTo(0, 0);
+ bowTie.lineTo(0, 0);
+ bowTie.lineTo(0, 0);
+ bowTie.lineTo(SK_Scalar1, SK_Scalar1);
+ bowTie.lineTo(SK_Scalar1, SK_Scalar1);
+ bowTie.lineTo(SK_Scalar1, SK_Scalar1);
+ bowTie.lineTo(SK_Scalar1, 0);
+ bowTie.lineTo(SK_Scalar1, 0);
+ bowTie.lineTo(SK_Scalar1, 0);
+ bowTie.lineTo(0, SK_Scalar1);
+ bowTie.lineTo(0, SK_Scalar1);
+ bowTie.lineTo(0, SK_Scalar1);
+ bowTie.close();
+ check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
+ check_direction(reporter, bowTie, kDontCheckDir);
+
+ SkPath spiral;
+ spiral.moveTo(0, 0);
+ spiral.lineTo(100*SK_Scalar1, 0);
+ spiral.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
+ spiral.lineTo(0, 100*SK_Scalar1);
+ spiral.lineTo(0, 50*SK_Scalar1);
+ spiral.lineTo(50*SK_Scalar1, 50*SK_Scalar1);
+ spiral.lineTo(50*SK_Scalar1, 75*SK_Scalar1);
+ spiral.close();
+ check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
+ check_direction(reporter, spiral, kDontCheckDir);
+
+ SkPath dent;
+ dent.moveTo(0, 0);
+ dent.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
+ dent.lineTo(0, 100*SK_Scalar1);
+ dent.lineTo(-50*SK_Scalar1, 200*SK_Scalar1);
+ dent.lineTo(-200*SK_Scalar1, 100*SK_Scalar1);
+ dent.close();
+ check_convexity(reporter, dent, SkPath::kConcave_Convexity);
+ check_direction(reporter, dent, SkPath::kCW_Direction);
+
+ // http://skbug.com/2235
+ SkPath strokedSin;
+ for (int i = 0; i < 2000; i++) {
+ SkScalar x = SkIntToScalar(i) / 2;
+ SkScalar y = 500 - (x + SkScalarSin(x / 100) * 40) / 3;
+ if (0 == i) {
+ strokedSin.moveTo(x, y);
+ } else {
+ strokedSin.lineTo(x, y);
+ }
+ }
+ SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
+ stroke.setStrokeStyle(2 * SK_Scalar1);
+ stroke.applyToPath(&strokedSin, strokedSin);
+ check_convexity(reporter, strokedSin, SkPath::kConcave_Convexity);
+ check_direction(reporter, strokedSin, kDontCheckDir);
+
+ // http://crbug.com/412640
+ SkPath degenerateConcave;
+ degenerateConcave.moveTo(148.67912f, 191.875f);
+ degenerateConcave.lineTo(470.37695f, 7.5f);
+ degenerateConcave.lineTo(148.67912f, 191.875f);
+ degenerateConcave.lineTo(41.446522f, 376.25f);
+ degenerateConcave.lineTo(-55.971577f, 460.0f);
+ degenerateConcave.lineTo(41.446522f, 376.25f);
+ check_convexity(reporter, degenerateConcave, SkPath::kConcave_Convexity);
+ check_direction(reporter, degenerateConcave, SkPath::kUnknown_Direction);
+}
+
+static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p,
+ const SkRect& bounds) {
+ REPORTER_ASSERT(reporter, p.isConvex());
+ REPORTER_ASSERT(reporter, p.getBounds() == bounds);
+
+ SkPath p2(p);
+ REPORTER_ASSERT(reporter, p2.isConvex());
+ REPORTER_ASSERT(reporter, p2.getBounds() == bounds);
+
+ SkPath other;
+ other.swap(p2);
+ REPORTER_ASSERT(reporter, other.isConvex());
+ REPORTER_ASSERT(reporter, other.getBounds() == bounds);
+}
+
+static void setFromString(SkPath* path, const char str[]) {
+ bool first = true;
+ while (str) {
+ SkScalar x, y;
+ str = SkParse::FindScalar(str, &x);
+ if (NULL == str) {
+ break;
+ }
+ str = SkParse::FindScalar(str, &y);
+ SkASSERT(str);
+ if (first) {
+ path->moveTo(x, y);
+ first = false;
+ } else {
+ path->lineTo(x, y);
+ }
+ }
+}
+
+static void test_convexity(skiatest::Reporter* reporter) {
+ SkPath path;
+
+ check_convexity(reporter, path, SkPath::kConvex_Convexity);
+ path.addCircle(0, 0, SkIntToScalar(10));
+ check_convexity(reporter, path, SkPath::kConvex_Convexity);
+ path.addCircle(0, 0, SkIntToScalar(10)); // 2nd circle
+ check_convexity(reporter, path, SkPath::kConcave_Convexity);
+
+ path.reset();
+ path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCCW_Direction);
+ check_convexity(reporter, path, SkPath::kConvex_Convexity);
+ REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
+
+ path.reset();
+ path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCW_Direction);
+ check_convexity(reporter, path, SkPath::kConvex_Convexity);
+ REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
+
+ static const struct {
+ const char* fPathStr;
+ SkPath::Convexity fExpectedConvexity;
+ SkPath::Direction fExpectedDirection;
+ } gRec[] = {
+ { "", SkPath::kConvex_Convexity, SkPath::kUnknown_Direction },
+ { "0 0", SkPath::kConvex_Convexity, SkPath::kUnknown_Direction },
+ { "0 0 10 10", SkPath::kConvex_Convexity, SkPath::kUnknown_Direction },
+ { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity, SkPath::kUnknown_Direction },
+ { "0 0 10 10 10 20", SkPath::kConvex_Convexity, SkPath::kCW_Direction },
+ { "0 0 10 10 10 0", SkPath::kConvex_Convexity, SkPath::kCCW_Direction },
+ { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity, kDontCheckDir },
+ { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity, SkPath::kCW_Direction },
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
+ SkPath path;
+ setFromString(&path, gRec[i].fPathStr);
+ check_convexity(reporter, path, gRec[i].fExpectedConvexity);
+ check_direction(reporter, path, gRec[i].fExpectedDirection);
+ // check after setting the initial convex and direction
+ if (kDontCheckDir != gRec[i].fExpectedDirection) {
+ SkPath copy(path);
+ SkPath::Direction dir;
+ bool foundDir = copy.cheapComputeDirection(&dir);
+ REPORTER_ASSERT(reporter, (gRec[i].fExpectedDirection == SkPath::kUnknown_Direction)
+ ^ foundDir);
+ REPORTER_ASSERT(reporter, !foundDir || gRec[i].fExpectedDirection == dir);
+ check_convexity(reporter, copy, gRec[i].fExpectedConvexity);
+ }
+ REPORTER_ASSERT(reporter, gRec[i].fExpectedConvexity == path.getConvexity());
+ check_direction(reporter, path, gRec[i].fExpectedDirection);
+ }
+}
+
+static void test_isLine(skiatest::Reporter* reporter) {
+ SkPath path;
+ SkPoint pts[2];
+ const SkScalar value = SkIntToScalar(5);
+
+ REPORTER_ASSERT(reporter, !path.isLine(NULL));
+
+ // set some non-zero values
+ pts[0].set(value, value);
+ pts[1].set(value, value);
+ REPORTER_ASSERT(reporter, !path.isLine(pts));
+ // check that pts was untouched
+ REPORTER_ASSERT(reporter, pts[0].equals(value, value));
+ REPORTER_ASSERT(reporter, pts[1].equals(value, value));
+
+ const SkScalar moveX = SkIntToScalar(1);
+ const SkScalar moveY = SkIntToScalar(2);
+ REPORTER_ASSERT(reporter, value != moveX && value != moveY);
+
+ path.moveTo(moveX, moveY);
+ REPORTER_ASSERT(reporter, !path.isLine(NULL));
+ REPORTER_ASSERT(reporter, !path.isLine(pts));
+ // check that pts was untouched
+ REPORTER_ASSERT(reporter, pts[0].equals(value, value));
+ REPORTER_ASSERT(reporter, pts[1].equals(value, value));
+
+ const SkScalar lineX = SkIntToScalar(2);
+ const SkScalar lineY = SkIntToScalar(2);
+ REPORTER_ASSERT(reporter, value != lineX && value != lineY);
+
+ path.lineTo(lineX, lineY);
+ REPORTER_ASSERT(reporter, path.isLine(NULL));
+
+ REPORTER_ASSERT(reporter, !pts[0].equals(moveX, moveY));
+ REPORTER_ASSERT(reporter, !pts[1].equals(lineX, lineY));
+ REPORTER_ASSERT(reporter, path.isLine(pts));
+ REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
+ REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
+
+ path.lineTo(0, 0); // too many points/verbs
+ REPORTER_ASSERT(reporter, !path.isLine(NULL));
+ REPORTER_ASSERT(reporter, !path.isLine(pts));
+ REPORTER_ASSERT(reporter, pts[0].equals(moveX, moveY));
+ REPORTER_ASSERT(reporter, pts[1].equals(lineX, lineY));
+
+ path.reset();
+ path.quadTo(1, 1, 2, 2);
+ REPORTER_ASSERT(reporter, !path.isLine(NULL));
+}
+
+static void test_conservativelyContains(skiatest::Reporter* reporter) {
+ SkPath path;
+
+ // kBaseRect is used to construct most our test paths: a rect, a circle, and a round-rect.
+ static const SkRect kBaseRect = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
+
+ // A circle that bounds kBaseRect (with a significant amount of slop)
+ SkScalar circleR = SkMaxScalar(kBaseRect.width(), kBaseRect.height());
+ circleR = SkScalarMul(circleR, 1.75f) / 2;
+ static const SkPoint kCircleC = {kBaseRect.centerX(), kBaseRect.centerY()};
+
+ // round-rect radii
+ static const SkScalar kRRRadii[] = {SkIntToScalar(5), SkIntToScalar(3)};
+
+ static const struct SUPPRESS_VISIBILITY_WARNING {
+ SkRect fQueryRect;
+ bool fInRect;
+ bool fInCircle;
+ bool fInRR;
+ bool fInCubicRR;
+ } kQueries[] = {
+ {kBaseRect, true, true, false, false},
+
+ // rect well inside of kBaseRect
+ {SkRect::MakeLTRB(kBaseRect.fLeft + 0.25f*kBaseRect.width(),
+ kBaseRect.fTop + 0.25f*kBaseRect.height(),
+ kBaseRect.fRight - 0.25f*kBaseRect.width(),
+ kBaseRect.fBottom - 0.25f*kBaseRect.height()),
+ true, true, true, true},
+
+ // rects with edges off by one from kBaseRect's edges
+ {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop,
+ kBaseRect.width(), kBaseRect.height() + 1),
+ false, true, false, false},
+ {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop,
+ kBaseRect.width() + 1, kBaseRect.height()),
+ false, true, false, false},
+ {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop,
+ kBaseRect.width() + 1, kBaseRect.height() + 1),
+ false, true, false, false},
+ {SkRect::MakeXYWH(kBaseRect.fLeft - 1, kBaseRect.fTop,
+ kBaseRect.width(), kBaseRect.height()),
+ false, true, false, false},
+ {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop - 1,
+ kBaseRect.width(), kBaseRect.height()),
+ false, true, false, false},
+ {SkRect::MakeXYWH(kBaseRect.fLeft - 1, kBaseRect.fTop,
+ kBaseRect.width() + 2, kBaseRect.height()),
+ false, true, false, false},
+ {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop - 1,
+ kBaseRect.width() + 2, kBaseRect.height()),
+ false, true, false, false},
+
+ // zero-w/h rects at each corner of kBaseRect
+ {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fTop, 0, 0), true, true, false, false},
+ {SkRect::MakeXYWH(kBaseRect.fRight, kBaseRect.fTop, 0, 0), true, true, false, true},
+ {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.fBottom, 0, 0), true, true, false, true},
+ {SkRect::MakeXYWH(kBaseRect.fRight, kBaseRect.fBottom, 0, 0), true, true, false, true},
+
+ // far away rect
+ {SkRect::MakeXYWH(10 * kBaseRect.fRight, 10 * kBaseRect.fBottom,
+ SkIntToScalar(10), SkIntToScalar(10)),
+ false, false, false, false},
+
+ // very large rect containing kBaseRect
+ {SkRect::MakeXYWH(kBaseRect.fLeft - 5 * kBaseRect.width(),
+ kBaseRect.fTop - 5 * kBaseRect.height(),
+ 11 * kBaseRect.width(), 11 * kBaseRect.height()),
+ false, false, false, false},
+
+ // skinny rect that spans same y-range as kBaseRect
+ {SkRect::MakeXYWH(kBaseRect.centerX(), kBaseRect.fTop,
+ SkIntToScalar(1), kBaseRect.height()),
+ true, true, true, true},
+
+ // short rect that spans same x-range as kBaseRect
+ {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.centerY(), kBaseRect.width(), SkScalar(1)),
+ true, true, true, true},
+
+ // skinny rect that spans slightly larger y-range than kBaseRect
+ {SkRect::MakeXYWH(kBaseRect.centerX(), kBaseRect.fTop,
+ SkIntToScalar(1), kBaseRect.height() + 1),
+ false, true, false, false},
+
+ // short rect that spans slightly larger x-range than kBaseRect
+ {SkRect::MakeXYWH(kBaseRect.fLeft, kBaseRect.centerY(),
+ kBaseRect.width() + 1, SkScalar(1)),
+ false, true, false, false},
+ };
+
+ for (int inv = 0; inv < 4; ++inv) {
+ for (size_t q = 0; q < SK_ARRAY_COUNT(kQueries); ++q) {
+ SkRect qRect = kQueries[q].fQueryRect;
+ if (inv & 0x1) {
+ SkTSwap(qRect.fLeft, qRect.fRight);
+ }
+ if (inv & 0x2) {
+ SkTSwap(qRect.fTop, qRect.fBottom);
+ }
+ for (int d = 0; d < 2; ++d) {
+ SkPath::Direction dir = d ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
+ path.reset();
+ path.addRect(kBaseRect, dir);
+ REPORTER_ASSERT(reporter, kQueries[q].fInRect ==
+ path.conservativelyContainsRect(qRect));
+
+ path.reset();
+ path.addCircle(kCircleC.fX, kCircleC.fY, circleR, dir);
+ REPORTER_ASSERT(reporter, kQueries[q].fInCircle ==
+ path.conservativelyContainsRect(qRect));
+
+ path.reset();
+ path.addRoundRect(kBaseRect, kRRRadii[0], kRRRadii[1], dir);
+ REPORTER_ASSERT(reporter, kQueries[q].fInRR ==
+ path.conservativelyContainsRect(qRect));
+
+ path.reset();
+ path.moveTo(kBaseRect.fLeft + kRRRadii[0], kBaseRect.fTop);
+ path.cubicTo(kBaseRect.fLeft + kRRRadii[0] / 2, kBaseRect.fTop,
+ kBaseRect.fLeft, kBaseRect.fTop + kRRRadii[1] / 2,
+ kBaseRect.fLeft, kBaseRect.fTop + kRRRadii[1]);
+ path.lineTo(kBaseRect.fLeft, kBaseRect.fBottom);
+ path.lineTo(kBaseRect.fRight, kBaseRect.fBottom);
+ path.lineTo(kBaseRect.fRight, kBaseRect.fTop);
+ path.close();
+ REPORTER_ASSERT(reporter, kQueries[q].fInCubicRR ==
+ path.conservativelyContainsRect(qRect));
+
+ }
+ // Slightly non-convex shape, shouldn't contain any rects.
+ path.reset();
+ path.moveTo(0, 0);
+ path.lineTo(SkIntToScalar(50), 0.05f);
+ path.lineTo(SkIntToScalar(100), 0);
+ path.lineTo(SkIntToScalar(100), SkIntToScalar(100));
+ path.lineTo(0, SkIntToScalar(100));
+ path.close();
+ REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(qRect));
+ }
+ }
+
+ // make sure a minimal convex shape works, a right tri with edges along pos x and y axes.
+ path.reset();
+ path.moveTo(0, 0);
+ path.lineTo(SkIntToScalar(100), 0);
+ path.lineTo(0, SkIntToScalar(100));
+
+ // inside, on along top edge
+ REPORTER_ASSERT(reporter, path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(50), 0,
+ SkIntToScalar(10),
+ SkIntToScalar(10))));
+ // above
+ REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(
+ SkRect::MakeXYWH(SkIntToScalar(50),
+ SkIntToScalar(-10),
+ SkIntToScalar(10),
+ SkIntToScalar(10))));
+ // to the left
+ REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(-10),
+ SkIntToScalar(5),
+ SkIntToScalar(5),
+ SkIntToScalar(5))));
+
+ // outside the diagonal edge
+ REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(10),
+ SkIntToScalar(200),
+ SkIntToScalar(20),
+ SkIntToScalar(5))));
+
+
+ // Test that multiple move commands do not cause asserts.
+
+ // At the time of writing, this would not modify cached convexity. This caused an assert while
+ // checking conservative containment again. http://skbug.com/1460
+ path.moveTo(SkIntToScalar(100), SkIntToScalar(100));
+#if 0
+ REPORTER_ASSERT(reporter, path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(50), 0,
+ SkIntToScalar(10),
+ SkIntToScalar(10))));
+#endif
+
+ // Same as above path and first test but with an extra moveTo.
+ path.reset();
+ path.moveTo(100, 100);
+ path.moveTo(0, 0);
+ path.lineTo(SkIntToScalar(100), 0);
+ path.lineTo(0, SkIntToScalar(100));
+
+ REPORTER_ASSERT(reporter, path.conservativelyContainsRect(SkRect::MakeXYWH(SkIntToScalar(50), 0,
+ SkIntToScalar(10),
+ SkIntToScalar(10))));
+
+ // Test that multiple move commands do not cause asserts and that the function
+ // is not confused by the multiple moves.
+ path.reset();
+ path.moveTo(0, 0);
+ path.lineTo(SkIntToScalar(100), 0);
+ path.lineTo(0, SkIntToScalar(100));
+ path.moveTo(0, SkIntToScalar(200));
+ path.lineTo(SkIntToScalar(100), SkIntToScalar(200));
+ path.lineTo(0, SkIntToScalar(300));
+
+ REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(
+ SkRect::MakeXYWH(SkIntToScalar(50), 0,
+ SkIntToScalar(10),
+ SkIntToScalar(10))));
+
+ path.reset();
+ path.lineTo(100, 100);
+ REPORTER_ASSERT(reporter, !path.conservativelyContainsRect(SkRect::MakeXYWH(0, 0, 1, 1)));
+}
+
+static void test_isRect_open_close(skiatest::Reporter* reporter) {
+ SkPath path;
+ bool isClosed;
+
+ path.moveTo(0, 0); path.lineTo(1, 0); path.lineTo(1, 1); path.lineTo(0, 1);
+ path.close();
+
+ REPORTER_ASSERT(reporter, path.isRect(NULL, NULL));
+ REPORTER_ASSERT(reporter, path.isRect(&isClosed, NULL));
+ REPORTER_ASSERT(reporter, isClosed);
+ REPORTER_ASSERT(reporter, SkPath::kStroke_PathAsRect == path.asRect(NULL));
+}
+
+// Simple isRect test is inline TestPath, below.
+// test_isRect provides more extensive testing.
+static void test_isRect(skiatest::Reporter* reporter) {
+ test_isRect_open_close(reporter);
+
+ // passing tests (all moveTo / lineTo...
+ SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
+ SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
+ SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
+ SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
+ SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
+ SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
+ SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
+ SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
+ SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
+ SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f}, {1, 0}, {.5f, 0}};
+ SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1}, {0, 1}, {0, .5f}};
+ SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
+ SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
+ SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
+ SkPoint rf[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, 0}};
+
+ // failing tests
+ SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
+ SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
+ SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
+ SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
+ SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
+ SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
+ SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
+ SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
+ SkPoint f9[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, 0}, {2, 0}}; // overlaps
+ SkPoint fa[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, -1}, {1, -1}}; // non colinear gap
+ SkPoint fb[] = {{1, 0}, {8, 0}, {8, 8}, {0, 8}, {0, 1}}; // falls short
+
+ // no close, but we should detect them as fillably the same as a rect
+ SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
+ SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}};
+ SkPoint c3[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}, {0, 0}}; // hit the start
+
+ // like c2, but we double-back on ourselves
+ SkPoint d1[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}, {0, 2}};
+ // like c2, but we overshoot the start point
+ SkPoint d2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, -1}};
+ SkPoint d3[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, -1}, {0, 0}};
+
+ struct IsRectTest {
+ SkPoint *fPoints;
+ size_t fPointCount;
+ bool fClose;
+ bool fIsRect;
+ } tests[] = {
+ { r1, SK_ARRAY_COUNT(r1), true, true },
+ { r2, SK_ARRAY_COUNT(r2), true, true },
+ { r3, SK_ARRAY_COUNT(r3), true, true },
+ { r4, SK_ARRAY_COUNT(r4), true, true },
+ { r5, SK_ARRAY_COUNT(r5), true, true },
+ { r6, SK_ARRAY_COUNT(r6), true, true },
+ { r7, SK_ARRAY_COUNT(r7), true, true },
+ { r8, SK_ARRAY_COUNT(r8), true, true },
+ { r9, SK_ARRAY_COUNT(r9), true, true },
+ { ra, SK_ARRAY_COUNT(ra), true, true },
+ { rb, SK_ARRAY_COUNT(rb), true, true },
+ { rc, SK_ARRAY_COUNT(rc), true, true },
+ { rd, SK_ARRAY_COUNT(rd), true, true },
+ { re, SK_ARRAY_COUNT(re), true, true },
+ { rf, SK_ARRAY_COUNT(rf), true, true },
+
+ { f1, SK_ARRAY_COUNT(f1), true, false },
+ { f2, SK_ARRAY_COUNT(f2), true, false },
+ { f3, SK_ARRAY_COUNT(f3), true, false },
+ { f4, SK_ARRAY_COUNT(f4), true, false },
+ { f5, SK_ARRAY_COUNT(f5), true, false },
+ { f6, SK_ARRAY_COUNT(f6), true, false },
+ { f7, SK_ARRAY_COUNT(f7), true, false },
+ { f8, SK_ARRAY_COUNT(f8), true, false },
+ { f9, SK_ARRAY_COUNT(f9), true, false },
+ { fa, SK_ARRAY_COUNT(fa), true, false },
+ { fb, SK_ARRAY_COUNT(fb), true, false },
+
+ { c1, SK_ARRAY_COUNT(c1), false, true },
+ { c2, SK_ARRAY_COUNT(c2), false, true },
+ { c3, SK_ARRAY_COUNT(c3), false, true },
+
+ { d1, SK_ARRAY_COUNT(d1), false, false },
+ { d2, SK_ARRAY_COUNT(d2), false, false },
+ { d3, SK_ARRAY_COUNT(d3), false, false },
+ };
+
+ const size_t testCount = SK_ARRAY_COUNT(tests);
+ size_t index;
+ for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
+ SkPath path;
+ path.moveTo(tests[testIndex].fPoints[0].fX, tests[testIndex].fPoints[0].fY);
+ for (index = 1; index < tests[testIndex].fPointCount; ++index) {
+ path.lineTo(tests[testIndex].fPoints[index].fX, tests[testIndex].fPoints[index].fY);
+ }
+ if (tests[testIndex].fClose) {
+ path.close();
+ }
+ REPORTER_ASSERT(reporter, tests[testIndex].fIsRect == path.isRect(NULL));
+ REPORTER_ASSERT(reporter, tests[testIndex].fIsRect == path.isRect(NULL, NULL));
+
+ if (tests[testIndex].fIsRect) {
+ SkRect computed, expected;
+ expected.set(tests[testIndex].fPoints, tests[testIndex].fPointCount);
+ REPORTER_ASSERT(reporter, path.isRect(&computed));
+ REPORTER_ASSERT(reporter, expected == computed);
+
+ bool isClosed;
+ SkPath::Direction direction, cheapDirection;
+ REPORTER_ASSERT(reporter, path.cheapComputeDirection(&cheapDirection));
+ REPORTER_ASSERT(reporter, path.isRect(&isClosed, &direction));
+ REPORTER_ASSERT(reporter, isClosed == tests[testIndex].fClose);
+ REPORTER_ASSERT(reporter, direction == cheapDirection);
+ direction = (SkPath::Direction) -1;
+ if (!tests[testIndex].fClose) {
+ REPORTER_ASSERT(reporter, SkPath::kFill_PathAsRect == path.asRect());
+ REPORTER_ASSERT(reporter, SkPath::kFill_PathAsRect == path.asRect(&direction));
+ } else {
+ REPORTER_ASSERT(reporter, SkPath::kStroke_PathAsRect == path.asRect());
+ REPORTER_ASSERT(reporter, SkPath::kStroke_PathAsRect == path.asRect(&direction));
+ }
+ REPORTER_ASSERT(reporter, direction == cheapDirection);
+ } else {
+ SkRect computed;
+ computed.set(123, 456, 789, 1011);
+ REPORTER_ASSERT(reporter, !path.isRect(&computed));
+ REPORTER_ASSERT(reporter, computed.fLeft == 123 && computed.fTop == 456);
+ REPORTER_ASSERT(reporter, computed.fRight == 789 && computed.fBottom == 1011);
+
+ bool isClosed = (bool) -1;
+ SkPath::Direction direction = (SkPath::Direction) -1;
+ REPORTER_ASSERT(reporter, !path.isRect(&isClosed, &direction));
+ REPORTER_ASSERT(reporter, isClosed == (bool) -1);
+ REPORTER_ASSERT(reporter, direction == (SkPath::Direction) -1);
+ REPORTER_ASSERT(reporter, SkPath::kNone_PathAsRect == path.asRect());
+ REPORTER_ASSERT(reporter, SkPath::kNone_PathAsRect == path.asRect(&direction));
+ REPORTER_ASSERT(reporter, direction == (SkPath::Direction) -1);
+ }
+ }
+
+ // fail, close then line
+ SkPath path1;
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ path1.lineTo(1, 0);
+ REPORTER_ASSERT(reporter, !path1.isRect(NULL));
+
+ // fail, move in the middle
+ path1.reset();
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
+ if (index == 2) {
+ path1.moveTo(1, .5f);
+ }
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ REPORTER_ASSERT(reporter, !path1.isRect(NULL));
+
+ // fail, move on the edge
+ path1.reset();
+ for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
+ path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ REPORTER_ASSERT(reporter, !path1.isRect(NULL));
+
+ // fail, quad
+ path1.reset();
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
+ if (index == 2) {
+ path1.quadTo(1, .5f, 1, .5f);
+ }
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ REPORTER_ASSERT(reporter, !path1.isRect(NULL));
+
+ // fail, cubic
+ path1.reset();
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
+ if (index == 2) {
+ path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
+ }
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ REPORTER_ASSERT(reporter, !path1.isRect(NULL));
+}
+
+static void test_isNestedRects(skiatest::Reporter* reporter) {
+ // passing tests (all moveTo / lineTo...
+ SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // CW
+ SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
+ SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
+ SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
+ SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; // CCW
+ SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
+ SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
+ SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
+ SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
+ SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f}, {1, 0}, {.5f, 0}}; // CCW
+ SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1}, {0, 1}, {0, .5f}}; // CW
+ SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}}; // CW
+ SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}}; // CCW
+ SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}}; // CW
+
+ // failing tests
+ SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
+ SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
+ SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
+ SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
+ SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
+ SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
+ SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
+ SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
+
+ // failing, no close
+ SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
+ SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
+
+ struct IsNestedRectTest {
+ SkPoint *fPoints;
+ size_t fPointCount;
+ SkPath::Direction fDirection;
+ bool fClose;
+ bool fIsNestedRect; // nests with path.addRect(-1, -1, 2, 2);
+ } tests[] = {
+ { r1, SK_ARRAY_COUNT(r1), SkPath::kCW_Direction , true, true },
+ { r2, SK_ARRAY_COUNT(r2), SkPath::kCW_Direction , true, true },
+ { r3, SK_ARRAY_COUNT(r3), SkPath::kCW_Direction , true, true },
+ { r4, SK_ARRAY_COUNT(r4), SkPath::kCW_Direction , true, true },
+ { r5, SK_ARRAY_COUNT(r5), SkPath::kCCW_Direction, true, true },
+ { r6, SK_ARRAY_COUNT(r6), SkPath::kCCW_Direction, true, true },
+ { r7, SK_ARRAY_COUNT(r7), SkPath::kCCW_Direction, true, true },
+ { r8, SK_ARRAY_COUNT(r8), SkPath::kCCW_Direction, true, true },
+ { r9, SK_ARRAY_COUNT(r9), SkPath::kCCW_Direction, true, true },
+ { ra, SK_ARRAY_COUNT(ra), SkPath::kCCW_Direction, true, true },
+ { rb, SK_ARRAY_COUNT(rb), SkPath::kCW_Direction, true, true },
+ { rc, SK_ARRAY_COUNT(rc), SkPath::kCW_Direction, true, true },
+ { rd, SK_ARRAY_COUNT(rd), SkPath::kCCW_Direction, true, true },
+ { re, SK_ARRAY_COUNT(re), SkPath::kCW_Direction, true, true },
+
+ { f1, SK_ARRAY_COUNT(f1), SkPath::kUnknown_Direction, true, false },
+ { f2, SK_ARRAY_COUNT(f2), SkPath::kUnknown_Direction, true, false },
+ { f3, SK_ARRAY_COUNT(f3), SkPath::kUnknown_Direction, true, false },
+ { f4, SK_ARRAY_COUNT(f4), SkPath::kUnknown_Direction, true, false },
+ { f5, SK_ARRAY_COUNT(f5), SkPath::kUnknown_Direction, true, false },
+ { f6, SK_ARRAY_COUNT(f6), SkPath::kUnknown_Direction, true, false },
+ { f7, SK_ARRAY_COUNT(f7), SkPath::kUnknown_Direction, true, false },
+ { f8, SK_ARRAY_COUNT(f8), SkPath::kUnknown_Direction, true, false },
+
+ { c1, SK_ARRAY_COUNT(c1), SkPath::kUnknown_Direction, false, false },
+ { c2, SK_ARRAY_COUNT(c2), SkPath::kUnknown_Direction, false, false },
+ };
+
+ const size_t testCount = SK_ARRAY_COUNT(tests);
+ size_t index;
+ for (int rectFirst = 0; rectFirst <= 1; ++rectFirst) {
+ for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
+ SkPath path;
+ if (rectFirst) {
+ path.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
+ }
+ path.moveTo(tests[testIndex].fPoints[0].fX, tests[testIndex].fPoints[0].fY);
+ for (index = 1; index < tests[testIndex].fPointCount; ++index) {
+ path.lineTo(tests[testIndex].fPoints[index].fX, tests[testIndex].fPoints[index].fY);
+ }
+ if (tests[testIndex].fClose) {
+ path.close();
+ }
+ if (!rectFirst) {
+ path.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
+ }
+ REPORTER_ASSERT(reporter, tests[testIndex].fIsNestedRect == path.isNestedRects(NULL));
+ if (tests[testIndex].fIsNestedRect) {
+ SkRect expected[2], computed[2];
+ SkPath::Direction expectedDirs[2], computedDirs[2];
+ SkRect testBounds;
+ testBounds.set(tests[testIndex].fPoints, tests[testIndex].fPointCount);
+ expected[0] = SkRect::MakeLTRB(-1, -1, 2, 2);
+ expected[1] = testBounds;
+ if (rectFirst) {
+ expectedDirs[0] = SkPath::kCW_Direction;
+ } else {
+ expectedDirs[0] = SkPath::kCCW_Direction;
+ }
+ expectedDirs[1] = tests[testIndex].fDirection;
+ REPORTER_ASSERT(reporter, path.isNestedRects(computed, computedDirs));
+ REPORTER_ASSERT(reporter, expected[0] == computed[0]);
+ REPORTER_ASSERT(reporter, expected[1] == computed[1]);
+ REPORTER_ASSERT(reporter, expectedDirs[0] == computedDirs[0]);
+ REPORTER_ASSERT(reporter, expectedDirs[1] == computedDirs[1]);
+ }
+ }
+
+ // fail, close then line
+ SkPath path1;
+ if (rectFirst) {
+ path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
+ }
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ path1.lineTo(1, 0);
+ if (!rectFirst) {
+ path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
+ }
+ REPORTER_ASSERT(reporter, !path1.isNestedRects(NULL));
+
+ // fail, move in the middle
+ path1.reset();
+ if (rectFirst) {
+ path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
+ }
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
+ if (index == 2) {
+ path1.moveTo(1, .5f);
+ }
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ if (!rectFirst) {
+ path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
+ }
+ REPORTER_ASSERT(reporter, !path1.isNestedRects(NULL));
+
+ // fail, move on the edge
+ path1.reset();
+ if (rectFirst) {
+ path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
+ }
+ for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
+ path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ if (!rectFirst) {
+ path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
+ }
+ REPORTER_ASSERT(reporter, !path1.isNestedRects(NULL));
+
+ // fail, quad
+ path1.reset();
+ if (rectFirst) {
+ path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
+ }
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
+ if (index == 2) {
+ path1.quadTo(1, .5f, 1, .5f);
+ }
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ if (!rectFirst) {
+ path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
+ }
+ REPORTER_ASSERT(reporter, !path1.isNestedRects(NULL));
+
+ // fail, cubic
+ path1.reset();
+ if (rectFirst) {
+ path1.addRect(-1, -1, 2, 2, SkPath::kCW_Direction);
+ }
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < SK_ARRAY_COUNT(r1); ++index) {
+ if (index == 2) {
+ path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
+ }
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ if (!rectFirst) {
+ path1.addRect(-1, -1, 2, 2, SkPath::kCCW_Direction);
+ }
+ REPORTER_ASSERT(reporter, !path1.isNestedRects(NULL));
+
+ // fail, not nested
+ path1.reset();
+ path1.addRect(1, 1, 3, 3, SkPath::kCW_Direction);
+ path1.addRect(2, 2, 4, 4, SkPath::kCW_Direction);
+ REPORTER_ASSERT(reporter, !path1.isNestedRects(NULL));
+ }
+
+ // pass, stroke rect
+ SkPath src, dst;
+ src.addRect(1, 1, 7, 7, SkPath::kCW_Direction);
+ SkPaint strokePaint;
+ strokePaint.setStyle(SkPaint::kStroke_Style);
+ strokePaint.setStrokeWidth(2);
+ strokePaint.getFillPath(src, &dst);
+ REPORTER_ASSERT(reporter, dst.isNestedRects(NULL));
+}
+
+static void write_and_read_back(skiatest::Reporter* reporter,
+ const SkPath& p) {
+ SkWriter32 writer;
+ writer.writePath(p);
+ size_t size = writer.bytesWritten();
+ SkAutoMalloc storage(size);
+ writer.flatten(storage.get());
+ SkReader32 reader(storage.get(), size);
+
+ SkPath readBack;
+ REPORTER_ASSERT(reporter, readBack != p);
+ reader.readPath(&readBack);
+ REPORTER_ASSERT(reporter, readBack == p);
+
+ REPORTER_ASSERT(reporter, readBack.getConvexityOrUnknown() ==
+ p.getConvexityOrUnknown());
+
+ REPORTER_ASSERT(reporter, readBack.isOval(NULL) == p.isOval(NULL));
+
+ const SkRect& origBounds = p.getBounds();
+ const SkRect& readBackBounds = readBack.getBounds();
+
+ REPORTER_ASSERT(reporter, origBounds == readBackBounds);
+}
+
+static void test_flattening(skiatest::Reporter* reporter) {
+ SkPath p;
+
+ static const SkPoint pts[] = {
+ { 0, 0 },
+ { SkIntToScalar(10), SkIntToScalar(10) },
+ { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
+ { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
+ };
+ p.moveTo(pts[0]);
+ p.lineTo(pts[1]);
+ p.quadTo(pts[2], pts[3]);
+ p.cubicTo(pts[4], pts[5], pts[6]);
+
+ write_and_read_back(reporter, p);
+
+ // create a buffer that should be much larger than the path so we don't
+ // kill our stack if writer goes too far.
+ char buffer[1024];
+ size_t size1 = p.writeToMemory(NULL);
+ size_t size2 = p.writeToMemory(buffer);
+ REPORTER_ASSERT(reporter, size1 == size2);
+
+ SkPath p2;
+ size_t size3 = p2.readFromMemory(buffer, 1024);
+ REPORTER_ASSERT(reporter, size1 == size3);
+ REPORTER_ASSERT(reporter, p == p2);
+
+ size3 = p2.readFromMemory(buffer, 0);
+ REPORTER_ASSERT(reporter, !size3);
+
+ SkPath tooShort;
+ size3 = tooShort.readFromMemory(buffer, size1 - 1);
+ REPORTER_ASSERT(reporter, tooShort.isEmpty());
+
+ char buffer2[1024];
+ size3 = p2.writeToMemory(buffer2);
+ REPORTER_ASSERT(reporter, size1 == size3);
+ REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
+
+ // test persistence of the oval flag & convexity
+ {
+ SkPath oval;
+ SkRect rect = SkRect::MakeWH(10, 10);
+ oval.addOval(rect);
+
+ write_and_read_back(reporter, oval);
+ }
+}
+
+static void test_transform(skiatest::Reporter* reporter) {
+ SkPath p;
+
+#define CONIC_PERSPECTIVE_BUG_FIXED 0
+ static const SkPoint pts[] = {
+ { 0, 0 }, // move
+ { SkIntToScalar(10), SkIntToScalar(10) }, // line
+ { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 }, // quad
+ { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }, // cubic
+#if CONIC_PERSPECTIVE_BUG_FIXED
+ { 0, 0 }, { SkIntToScalar(20), SkIntToScalar(10) }, // conic
+#endif
+ };
+ const int kPtCount = SK_ARRAY_COUNT(pts);
+
+ p.moveTo(pts[0]);
+ p.lineTo(pts[1]);
+ p.quadTo(pts[2], pts[3]);
+ p.cubicTo(pts[4], pts[5], pts[6]);
+#if CONIC_PERSPECTIVE_BUG_FIXED
+ p.conicTo(pts[4], pts[5], 0.5f);
+#endif
+ p.close();
+
+ {
+ SkMatrix matrix;
+ matrix.reset();
+ SkPath p1;
+ p.transform(matrix, &p1);
+ REPORTER_ASSERT(reporter, p == p1);
+ }
+
+
+ {
+ SkMatrix matrix;
+ matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
+
+ SkPath p1; // Leave p1 non-unique (i.e., the empty path)
+
+ p.transform(matrix, &p1);
+ SkPoint pts1[kPtCount];
+ int count = p1.getPoints(pts1, kPtCount);
+ REPORTER_ASSERT(reporter, kPtCount == count);
+ for (int i = 0; i < count; ++i) {
+ SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
+ REPORTER_ASSERT(reporter, newPt == pts1[i]);
+ }
+ }
+
+ {
+ SkMatrix matrix;
+ matrix.reset();
+ matrix.setPerspX(SkScalarToPersp(4));
+
+ SkPath p1;
+ p1.moveTo(SkPoint::Make(0, 0));
+
+ p.transform(matrix, &p1);
+ REPORTER_ASSERT(reporter, matrix.invert(&matrix));
+ p1.transform(matrix, NULL);
+ SkRect pBounds = p.getBounds();
+ SkRect p1Bounds = p1.getBounds();
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(pBounds.fLeft, p1Bounds.fLeft));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(pBounds.fTop, p1Bounds.fTop));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(pBounds.fRight, p1Bounds.fRight));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(pBounds.fBottom, p1Bounds.fBottom));
+ }
+
+ p.reset();
+ p.addCircle(0, 0, 1, SkPath::kCW_Direction);
+
+ {
+ SkMatrix matrix;
+ matrix.reset();
+ SkPath p1;
+ p1.moveTo(SkPoint::Make(0, 0));
+
+ p.transform(matrix, &p1);
+ REPORTER_ASSERT(reporter, p1.cheapIsDirection(SkPath::kCW_Direction));
+ }
+
+
+ {
+ SkMatrix matrix;
+ matrix.reset();
+ matrix.setScaleX(-1);
+ SkPath p1;
+ p1.moveTo(SkPoint::Make(0, 0)); // Make p1 unique (i.e., not empty path)
+
+ p.transform(matrix, &p1);
+ REPORTER_ASSERT(reporter, p1.cheapIsDirection(SkPath::kCCW_Direction));
+ }
+
+ {
+ SkMatrix matrix;
+ matrix.setAll(1, 1, 0, 1, 1, 0, 0, 0, 1);
+ SkPath p1;
+ p1.moveTo(SkPoint::Make(0, 0)); // Make p1 unique (i.e., not empty path)
+
+ p.transform(matrix, &p1);
+ REPORTER_ASSERT(reporter, p1.cheapIsDirection(SkPath::kUnknown_Direction));
+ }
+}
+
+static void test_zero_length_paths(skiatest::Reporter* reporter) {
+ SkPath p;
+ uint8_t verbs[32];
+
+ struct SUPPRESS_VISIBILITY_WARNING zeroPathTestData {
+ const char* testPath;
+ const size_t numResultPts;
+ const SkRect resultBound;
+ const SkPath::Verb* resultVerbs;
+ const size_t numResultVerbs;
+ };
+
+ static const SkPath::Verb resultVerbs1[] = { SkPath::kMove_Verb };
+ static const SkPath::Verb resultVerbs2[] = { SkPath::kMove_Verb, SkPath::kMove_Verb };
+ static const SkPath::Verb resultVerbs3[] = { SkPath::kMove_Verb, SkPath::kClose_Verb };
+ static const SkPath::Verb resultVerbs4[] = { SkPath::kMove_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kClose_Verb };
+ static const SkPath::Verb resultVerbs5[] = { SkPath::kMove_Verb, SkPath::kLine_Verb };
+ static const SkPath::Verb resultVerbs6[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb, SkPath::kLine_Verb };
+ static const SkPath::Verb resultVerbs7[] = { SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb };
+ static const SkPath::Verb resultVerbs8[] = {
+ SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb
+ };
+ static const SkPath::Verb resultVerbs9[] = { SkPath::kMove_Verb, SkPath::kQuad_Verb };
+ static const SkPath::Verb resultVerbs10[] = { SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kMove_Verb, SkPath::kQuad_Verb };
+ static const SkPath::Verb resultVerbs11[] = { SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kClose_Verb };
+ static const SkPath::Verb resultVerbs12[] = {
+ SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kQuad_Verb, SkPath::kClose_Verb
+ };
+ static const SkPath::Verb resultVerbs13[] = { SkPath::kMove_Verb, SkPath::kCubic_Verb };
+ static const SkPath::Verb resultVerbs14[] = { SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kMove_Verb, SkPath::kCubic_Verb };
+ static const SkPath::Verb resultVerbs15[] = { SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kClose_Verb };
+ static const SkPath::Verb resultVerbs16[] = {
+ SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kCubic_Verb, SkPath::kClose_Verb
+ };
+ static const struct zeroPathTestData gZeroLengthTests[] = {
+ { "M 1 1", 1, {0, 0, 0, 0}, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
+ { "M 1 1 M 2 1", 2, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs2, SK_ARRAY_COUNT(resultVerbs2) },
+ { "M 1 1 z", 1, {0, 0, 0, 0}, resultVerbs3, SK_ARRAY_COUNT(resultVerbs3) },
+ { "M 1 1 z M 2 1 z", 2, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs4, SK_ARRAY_COUNT(resultVerbs4) },
+ { "M 1 1 L 1 1", 2, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs5, SK_ARRAY_COUNT(resultVerbs5) },
+ { "M 1 1 L 1 1 M 2 1 L 2 1", 4, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs6, SK_ARRAY_COUNT(resultVerbs6) },
+ { "M 1 1 L 1 1 z", 2, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs7, SK_ARRAY_COUNT(resultVerbs7) },
+ { "M 1 1 L 1 1 z M 2 1 L 2 1 z", 4, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs8, SK_ARRAY_COUNT(resultVerbs8) },
+ { "M 1 1 Q 1 1 1 1", 3, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs9, SK_ARRAY_COUNT(resultVerbs9) },
+ { "M 1 1 Q 1 1 1 1 M 2 1 Q 2 1 2 1", 6, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs10, SK_ARRAY_COUNT(resultVerbs10) },
+ { "M 1 1 Q 1 1 1 1 z", 3, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs11, SK_ARRAY_COUNT(resultVerbs11) },
+ { "M 1 1 Q 1 1 1 1 z M 2 1 Q 2 1 2 1 z", 6, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs12, SK_ARRAY_COUNT(resultVerbs12) },
+ { "M 1 1 C 1 1 1 1 1 1", 4, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs13, SK_ARRAY_COUNT(resultVerbs13) },
+ { "M 1 1 C 1 1 1 1 1 1 M 2 1 C 2 1 2 1 2 1", 8, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs14,
+ SK_ARRAY_COUNT(resultVerbs14)
+ },
+ { "M 1 1 C 1 1 1 1 1 1 z", 4, {SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1}, resultVerbs15, SK_ARRAY_COUNT(resultVerbs15) },
+ { "M 1 1 C 1 1 1 1 1 1 z M 2 1 C 2 1 2 1 2 1 z", 8, {SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1}, resultVerbs16,
+ SK_ARRAY_COUNT(resultVerbs16)
+ }
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gZeroLengthTests); ++i) {
+ p.reset();
+ bool valid = SkParsePath::FromSVGString(gZeroLengthTests[i].testPath, &p);
+ REPORTER_ASSERT(reporter, valid);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, gZeroLengthTests[i].numResultPts == (size_t)p.countPoints());
+ REPORTER_ASSERT(reporter, gZeroLengthTests[i].resultBound == p.getBounds());
+ REPORTER_ASSERT(reporter, gZeroLengthTests[i].numResultVerbs == (size_t)p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+ for (size_t j = 0; j < gZeroLengthTests[i].numResultVerbs; ++j) {
+ REPORTER_ASSERT(reporter, gZeroLengthTests[i].resultVerbs[j] == verbs[j]);
+ }
+ }
+}
+
+struct SegmentInfo {
+ SkPath fPath;
+ int fPointCount;
+};
+
+#define kCurveSegmentMask (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
+
+static void test_segment_masks(skiatest::Reporter* reporter) {
+ SkPath p, p2;
+
+ p.moveTo(0, 0);
+ p.quadTo(100, 100, 200, 200);
+ REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ p2 = p;
+ REPORTER_ASSERT(reporter, p2.getSegmentMasks() == p.getSegmentMasks());
+ p.cubicTo(100, 100, 200, 200, 300, 300);
+ REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ p2 = p;
+ REPORTER_ASSERT(reporter, p2.getSegmentMasks() == p.getSegmentMasks());
+
+ p.reset();
+ p.moveTo(0, 0);
+ p.cubicTo(100, 100, 200, 200, 300, 300);
+ REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
+ p2 = p;
+ REPORTER_ASSERT(reporter, p2.getSegmentMasks() == p.getSegmentMasks());
+
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+}
+
+static void test_iter(skiatest::Reporter* reporter) {
+ SkPath p;
+ SkPoint pts[4];
+
+ // Test an iterator with no path
+ SkPath::Iter noPathIter;
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+
+ // Test that setting an empty path works
+ noPathIter.setPath(p, false);
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+
+ // Test that close path makes no difference for an empty path
+ noPathIter.setPath(p, true);
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+
+ // Test an iterator with an initial empty path
+ SkPath::Iter iter(p, false);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Test that close path makes no difference
+ iter.setPath(p, true);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+
+ struct iterTestData {
+ const char* testPath;
+ const bool forceClose;
+ const bool consumeDegenerates;
+ const size_t* numResultPtsPerVerb;
+ const SkPoint* resultPts;
+ const SkPath::Verb* resultVerbs;
+ const size_t numResultVerbs;
+ };
+
+ static const SkPath::Verb resultVerbs1[] = { SkPath::kDone_Verb };
+ static const SkPath::Verb resultVerbs2[] = {
+ SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kDone_Verb
+ };
+ static const SkPath::Verb resultVerbs3[] = {
+ SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb, SkPath::kDone_Verb
+ };
+ static const SkPath::Verb resultVerbs4[] = {
+ SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kMove_Verb, SkPath::kClose_Verb, SkPath::kDone_Verb
+ };
+ static const SkPath::Verb resultVerbs5[] = {
+ SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kClose_Verb, SkPath::kMove_Verb, SkPath::kClose_Verb, SkPath::kDone_Verb
+ };
+ static const size_t resultPtsSizes1[] = { 0 };
+ static const size_t resultPtsSizes2[] = { 1, 2, 2, 0 };
+ static const size_t resultPtsSizes3[] = { 1, 2, 2, 2, 1, 0 };
+ static const size_t resultPtsSizes4[] = { 1, 2, 1, 1, 0 };
+ static const size_t resultPtsSizes5[] = { 1, 2, 1, 1, 1, 0 };
+ static const SkPoint* resultPts1 = 0;
+ static const SkPoint resultPts2[] = {
+ { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, SK_Scalar1 }, { SK_Scalar1, SK_Scalar1 }, { 0, SK_Scalar1 }
+ };
+ static const SkPoint resultPts3[] = {
+ { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, SK_Scalar1 }, { SK_Scalar1, SK_Scalar1 }, { 0, SK_Scalar1 },
+ { 0, SK_Scalar1 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }
+ };
+ static const SkPoint resultPts4[] = {
+ { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { 0, 0 }, { 0, 0 }
+ };
+ static const SkPoint resultPts5[] = {
+ { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { SK_Scalar1, 0 }, { 0, 0 }, { 0, 0 }
+ };
+ static const struct iterTestData gIterTests[] = {
+ { "M 1 0", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
+ { "M 1 0 M 2 0 M 3 0 M 4 0 M 5 0", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
+ { "M 1 0 M 1 0 M 3 0 M 4 0 M 5 0", true, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
+ { "z", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
+ { "z", true, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
+ { "z M 1 0 z z M 2 0 z M 3 0 M 4 0 z", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
+ { "z M 1 0 z z M 2 0 z M 3 0 M 4 0 z", true, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
+ { "M 1 0 L 1 1 L 0 1 M 0 0 z", false, true, resultPtsSizes2, resultPts2, resultVerbs2, SK_ARRAY_COUNT(resultVerbs2) },
+ { "M 1 0 L 1 1 L 0 1 M 0 0 z", true, true, resultPtsSizes3, resultPts3, resultVerbs3, SK_ARRAY_COUNT(resultVerbs3) },
+ { "M 1 0 L 1 0 M 0 0 z", false, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
+ { "M 1 0 L 1 0 M 0 0 z", true, true, resultPtsSizes1, resultPts1, resultVerbs1, SK_ARRAY_COUNT(resultVerbs1) },
+ { "M 1 0 L 1 0 M 0 0 z", false, false, resultPtsSizes4, resultPts4, resultVerbs4, SK_ARRAY_COUNT(resultVerbs4) },
+ { "M 1 0 L 1 0 M 0 0 z", true, false, resultPtsSizes5, resultPts5, resultVerbs5, SK_ARRAY_COUNT(resultVerbs5) }
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gIterTests); ++i) {
+ p.reset();
+ bool valid = SkParsePath::FromSVGString(gIterTests[i].testPath, &p);
+ REPORTER_ASSERT(reporter, valid);
+ iter.setPath(p, gIterTests[i].forceClose);
+ int j = 0, l = 0;
+ do {
+ REPORTER_ASSERT(reporter, iter.next(pts, gIterTests[i].consumeDegenerates) == gIterTests[i].resultVerbs[j]);
+ for (int k = 0; k < (int)gIterTests[i].numResultPtsPerVerb[j]; ++k) {
+ REPORTER_ASSERT(reporter, pts[k] == gIterTests[i].resultPts[l++]);
+ }
+ } while (gIterTests[i].resultVerbs[j++] != SkPath::kDone_Verb);
+ REPORTER_ASSERT(reporter, j == (int)gIterTests[i].numResultVerbs);
+ }
+
+ p.reset();
+ iter.setPath(p, false);
+ REPORTER_ASSERT(reporter, !iter.isClosedContour());
+ p.lineTo(1, 1);
+ p.close();
+ iter.setPath(p, false);
+ REPORTER_ASSERT(reporter, iter.isClosedContour());
+ p.reset();
+ iter.setPath(p, true);
+ REPORTER_ASSERT(reporter, !iter.isClosedContour());
+ p.lineTo(1, 1);
+ iter.setPath(p, true);
+ REPORTER_ASSERT(reporter, iter.isClosedContour());
+ p.moveTo(0, 0);
+ p.lineTo(2, 2);
+ iter.setPath(p, false);
+ REPORTER_ASSERT(reporter, !iter.isClosedContour());
+
+ // this checks to see if the NaN logic is executed in SkPath::autoClose(), but does not
+ // check to see if the result is correct.
+ for (int setNaN = 0; setNaN < 4; ++setNaN) {
+ p.reset();
+ p.moveTo(setNaN == 0 ? SK_ScalarNaN : 0, setNaN == 1 ? SK_ScalarNaN : 0);
+ p.lineTo(setNaN == 2 ? SK_ScalarNaN : 1, setNaN == 3 ? SK_ScalarNaN : 1);
+ iter.setPath(p, true);
+ iter.next(pts, false);
+ iter.next(pts, false);
+ REPORTER_ASSERT(reporter, SkPath::kClose_Verb == iter.next(pts, false));
+ }
+
+ p.reset();
+ p.quadTo(0, 0, 0, 0);
+ iter.setPath(p, false);
+ iter.next(pts, false);
+ REPORTER_ASSERT(reporter, SkPath::kQuad_Verb == iter.next(pts, false));
+ iter.setPath(p, false);
+ iter.next(pts, false);
+ REPORTER_ASSERT(reporter, SkPath::kDone_Verb == iter.next(pts, true));
+
+ p.reset();
+ p.conicTo(0, 0, 0, 0, 0.5f);
+ iter.setPath(p, false);
+ iter.next(pts, false);
+ REPORTER_ASSERT(reporter, SkPath::kConic_Verb == iter.next(pts, false));
+ iter.setPath(p, false);
+ iter.next(pts, false);
+ REPORTER_ASSERT(reporter, SkPath::kDone_Verb == iter.next(pts, true));
+
+ p.reset();
+ p.cubicTo(0, 0, 0, 0, 0, 0);
+ iter.setPath(p, false);
+ iter.next(pts, false);
+ REPORTER_ASSERT(reporter, SkPath::kCubic_Verb == iter.next(pts, false));
+ iter.setPath(p, false);
+ iter.next(pts, false);
+ REPORTER_ASSERT(reporter, SkPath::kDone_Verb == iter.next(pts, true));
+
+ p.moveTo(1, 1); // add a trailing moveto
+ iter.setPath(p, false);
+ iter.next(pts, false);
+ REPORTER_ASSERT(reporter, SkPath::kCubic_Verb == iter.next(pts, false));
+ iter.setPath(p, false);
+ iter.next(pts, false);
+ REPORTER_ASSERT(reporter, SkPath::kDone_Verb == iter.next(pts, true));
+
+ // The GM degeneratesegments.cpp test is more extensive
+}
+
+static void test_raw_iter(skiatest::Reporter* reporter) {
+ SkPath p;
+ SkPoint pts[4];
+
+ // Test an iterator with no path
+ SkPath::RawIter noPathIter;
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+ // Test that setting an empty path works
+ noPathIter.setPath(p);
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+
+ // Test an iterator with an initial empty path
+ SkPath::RawIter iter(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Test that a move-only path returns the move.
+ p.moveTo(SK_Scalar1, 0);
+ iter.setPath(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pts[0].fY == 0);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // No matter how many moves we add, we should get them all back
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
+ iter.setPath(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pts[0].fY == 0);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Initial close is never ever stored
+ p.reset();
+ p.close();
+ iter.setPath(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Move/close sequences
+ p.reset();
+ p.close(); // Not stored, no purpose
+ p.moveTo(SK_Scalar1, 0);
+ p.close();
+ p.close(); // Not stored, no purpose
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.close();
+ p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
+ p.moveTo(SK_Scalar1*4, SK_Scalar1*3);
+ p.close();
+ iter.setPath(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pts[0].fY == 0);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pts[0].fY == 0);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Generate random paths and verify
+ SkPoint randomPts[25];
+ for (int i = 0; i < 5; ++i) {
+ for (int j = 0; j < 5; ++j) {
+ randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j);
+ }
+ }
+
+ // Max of 10 segments, max 3 points per segment
+ SkRandom rand(9876543);
+ SkPoint expectedPts[31]; // May have leading moveTo
+ SkPath::Verb expectedVerbs[22]; // May have leading moveTo
+ SkPath::Verb nextVerb;
+
+ for (int i = 0; i < 500; ++i) {
+ p.reset();
+ bool lastWasClose = true;
+ bool haveMoveTo = false;
+ SkPoint lastMoveToPt = { 0, 0 };
+ int numPoints = 0;
+ int numVerbs = (rand.nextU() >> 16) % 10;
+ int numIterVerbs = 0;
+ for (int j = 0; j < numVerbs; ++j) {
+ do {
+ nextVerb = static_cast<SkPath::Verb>((rand.nextU() >> 16) % SkPath::kDone_Verb);
+ } while (lastWasClose && nextVerb == SkPath::kClose_Verb);
+ switch (nextVerb) {
+ case SkPath::kMove_Verb:
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ p.moveTo(expectedPts[numPoints]);
+ lastMoveToPt = expectedPts[numPoints];
+ numPoints += 1;
+ lastWasClose = false;
+ haveMoveTo = true;
+ break;
+ case SkPath::kLine_Verb:
+ if (!haveMoveTo) {
+ expectedPts[numPoints++] = lastMoveToPt;
+ expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
+ haveMoveTo = true;
+ }
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ p.lineTo(expectedPts[numPoints]);
+ numPoints += 1;
+ lastWasClose = false;
+ break;
+ case SkPath::kQuad_Verb:
+ if (!haveMoveTo) {
+ expectedPts[numPoints++] = lastMoveToPt;
+ expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
+ haveMoveTo = true;
+ }
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
+ p.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]);
+ numPoints += 2;
+ lastWasClose = false;
+ break;
+ case SkPath::kConic_Verb:
+ if (!haveMoveTo) {
+ expectedPts[numPoints++] = lastMoveToPt;
+ expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
+ haveMoveTo = true;
+ }
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
+ p.conicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
+ rand.nextUScalar1() * 4);
+ numPoints += 2;
+ lastWasClose = false;
+ break;
+ case SkPath::kCubic_Verb:
+ if (!haveMoveTo) {
+ expectedPts[numPoints++] = lastMoveToPt;
+ expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
+ haveMoveTo = true;
+ }
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
+ expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25];
+ p.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
+ expectedPts[numPoints + 2]);
+ numPoints += 3;
+ lastWasClose = false;
+ break;
+ case SkPath::kClose_Verb:
+ p.close();
+ haveMoveTo = false;
+ lastWasClose = true;
+ break;
+ default:
+ SkDEBUGFAIL("unexpected verb");
+ }
+ expectedVerbs[numIterVerbs++] = nextVerb;
+ }
+
+ iter.setPath(p);
+ numVerbs = numIterVerbs;
+ numIterVerbs = 0;
+ int numIterPts = 0;
+ SkPoint lastMoveTo;
+ SkPoint lastPt;
+ lastMoveTo.set(0, 0);
+ lastPt.set(0, 0);
+ while ((nextVerb = iter.next(pts)) != SkPath::kDone_Verb) {
+ REPORTER_ASSERT(reporter, nextVerb == expectedVerbs[numIterVerbs]);
+ numIterVerbs++;
+ switch (nextVerb) {
+ case SkPath::kMove_Verb:
+ REPORTER_ASSERT(reporter, numIterPts < numPoints);
+ REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]);
+ lastPt = lastMoveTo = pts[0];
+ numIterPts += 1;
+ break;
+ case SkPath::kLine_Verb:
+ REPORTER_ASSERT(reporter, numIterPts < numPoints + 1);
+ REPORTER_ASSERT(reporter, pts[0] == lastPt);
+ REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
+ lastPt = pts[1];
+ numIterPts += 1;
+ break;
+ case SkPath::kQuad_Verb:
+ case SkPath::kConic_Verb:
+ REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
+ REPORTER_ASSERT(reporter, pts[0] == lastPt);
+ REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
+ REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
+ lastPt = pts[2];
+ numIterPts += 2;
+ break;
+ case SkPath::kCubic_Verb:
+ REPORTER_ASSERT(reporter, numIterPts < numPoints + 3);
+ REPORTER_ASSERT(reporter, pts[0] == lastPt);
+ REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
+ REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
+ REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]);
+ lastPt = pts[3];
+ numIterPts += 3;
+ break;
+ case SkPath::kClose_Verb:
+ REPORTER_ASSERT(reporter, pts[0] == lastMoveTo);
+ lastPt = lastMoveTo;
+ break;
+ default:
+ SkDEBUGFAIL("unexpected verb");
+ }
+ }
+ REPORTER_ASSERT(reporter, numIterPts == numPoints);
+ REPORTER_ASSERT(reporter, numIterVerbs == numVerbs);
+ }
+}
+
+static void check_for_circle(skiatest::Reporter* reporter,
+ const SkPath& path,
+ bool expectedCircle,
+ SkPath::Direction expectedDir) {
+ SkRect rect = SkRect::MakeEmpty();
+ REPORTER_ASSERT(reporter, path.isOval(&rect) == expectedCircle);
+ REPORTER_ASSERT(reporter, path.cheapIsDirection(expectedDir));
+
+ if (expectedCircle) {
+ REPORTER_ASSERT(reporter, rect.height() == rect.width());
+ }
+}
+
+static void test_circle_skew(skiatest::Reporter* reporter,
+ const SkPath& path,
+ SkPath::Direction dir) {
+ SkPath tmp;
+
+ SkMatrix m;
+ m.setSkew(SkIntToScalar(3), SkIntToScalar(5));
+ path.transform(m, &tmp);
+ // this matrix reverses the direction.
+ if (SkPath::kCCW_Direction == dir) {
+ dir = SkPath::kCW_Direction;
+ } else {
+ REPORTER_ASSERT(reporter, SkPath::kCW_Direction == dir);
+ dir = SkPath::kCCW_Direction;
+ }
+ check_for_circle(reporter, tmp, false, dir);
+}
+
+static void test_circle_translate(skiatest::Reporter* reporter,
+ const SkPath& path,
+ SkPath::Direction dir) {
+ SkPath tmp;
+
+ // translate at small offset
+ SkMatrix m;
+ m.setTranslate(SkIntToScalar(15), SkIntToScalar(15));
+ path.transform(m, &tmp);
+ check_for_circle(reporter, tmp, true, dir);
+
+ tmp.reset();
+ m.reset();
+
+ // translate at a relatively big offset
+ m.setTranslate(SkIntToScalar(1000), SkIntToScalar(1000));
+ path.transform(m, &tmp);
+ check_for_circle(reporter, tmp, true, dir);
+}
+
+static void test_circle_rotate(skiatest::Reporter* reporter,
+ const SkPath& path,
+ SkPath::Direction dir) {
+ for (int angle = 0; angle < 360; ++angle) {
+ SkPath tmp;
+ SkMatrix m;
+ m.setRotate(SkIntToScalar(angle));
+ path.transform(m, &tmp);
+
+ // TODO: a rotated circle whose rotated angle is not a multiple of 90
+ // degrees is not an oval anymore, this can be improved. we made this
+ // for the simplicity of our implementation.
+ if (angle % 90 == 0) {
+ check_for_circle(reporter, tmp, true, dir);
+ } else {
+ check_for_circle(reporter, tmp, false, dir);
+ }
+ }
+}
+
+static void test_circle_mirror_x(skiatest::Reporter* reporter,
+ const SkPath& path,
+ SkPath::Direction dir) {
+ SkPath tmp;
+ SkMatrix m;
+ m.reset();
+ m.setScaleX(-SK_Scalar1);
+ path.transform(m, &tmp);
+
+ if (SkPath::kCW_Direction == dir) {
+ dir = SkPath::kCCW_Direction;
+ } else {
+ REPORTER_ASSERT(reporter, SkPath::kCCW_Direction == dir);
+ dir = SkPath::kCW_Direction;
+ }
+
+ check_for_circle(reporter, tmp, true, dir);
+}
+
+static void test_circle_mirror_y(skiatest::Reporter* reporter,
+ const SkPath& path,
+ SkPath::Direction dir) {
+ SkPath tmp;
+ SkMatrix m;
+ m.reset();
+ m.setScaleY(-SK_Scalar1);
+ path.transform(m, &tmp);
+
+ if (SkPath::kCW_Direction == dir) {
+ dir = SkPath::kCCW_Direction;
+ } else {
+ REPORTER_ASSERT(reporter, SkPath::kCCW_Direction == dir);
+ dir = SkPath::kCW_Direction;
+ }
+
+ check_for_circle(reporter, tmp, true, dir);
+}
+
+static void test_circle_mirror_xy(skiatest::Reporter* reporter,
+ const SkPath& path,
+ SkPath::Direction dir) {
+ SkPath tmp;
+ SkMatrix m;
+ m.reset();
+ m.setScaleX(-SK_Scalar1);
+ m.setScaleY(-SK_Scalar1);
+ path.transform(m, &tmp);
+
+ check_for_circle(reporter, tmp, true, dir);
+}
+
+static void test_circle_with_direction(skiatest::Reporter* reporter,
+ SkPath::Direction dir) {
+ SkPath path;
+
+ // circle at origin
+ path.addCircle(0, 0, SkIntToScalar(20), dir);
+ check_for_circle(reporter, path, true, dir);
+ test_circle_rotate(reporter, path, dir);
+ test_circle_translate(reporter, path, dir);
+ test_circle_skew(reporter, path, dir);
+
+ // circle at an offset at (10, 10)
+ path.reset();
+ path.addCircle(SkIntToScalar(10), SkIntToScalar(10),
+ SkIntToScalar(20), dir);
+ check_for_circle(reporter, path, true, dir);
+ test_circle_rotate(reporter, path, dir);
+ test_circle_translate(reporter, path, dir);
+ test_circle_skew(reporter, path, dir);
+ test_circle_mirror_x(reporter, path, dir);
+ test_circle_mirror_y(reporter, path, dir);
+ test_circle_mirror_xy(reporter, path, dir);
+}
+
+static void test_circle_with_add_paths(skiatest::Reporter* reporter) {
+ SkPath path;
+ SkPath circle;
+ SkPath rect;
+ SkPath empty;
+
+ static const SkPath::Direction kCircleDir = SkPath::kCW_Direction;
+ static const SkPath::Direction kCircleDirOpposite = SkPath::kCCW_Direction;
+
+ circle.addCircle(0, 0, SkIntToScalar(10), kCircleDir);
+ rect.addRect(SkIntToScalar(5), SkIntToScalar(5),
+ SkIntToScalar(20), SkIntToScalar(20), SkPath::kCW_Direction);
+
+ SkMatrix translate;
+ translate.setTranslate(SkIntToScalar(12), SkIntToScalar(12));
+
+ // Although all the path concatenation related operations leave
+ // the path a circle, most mark it as a non-circle for simplicity
+
+ // empty + circle (translate)
+ path = empty;
+ path.addPath(circle, translate);
+ check_for_circle(reporter, path, false, kCircleDir);
+
+ // circle + empty (translate)
+ path = circle;
+ path.addPath(empty, translate);
+ check_for_circle(reporter, path, true, kCircleDir);
+
+ // test reverseAddPath
+ path = circle;
+ path.reverseAddPath(rect);
+ check_for_circle(reporter, path, false, kCircleDirOpposite);
+}
+
+static void test_circle(skiatest::Reporter* reporter) {
+ test_circle_with_direction(reporter, SkPath::kCW_Direction);
+ test_circle_with_direction(reporter, SkPath::kCCW_Direction);
+
+ // multiple addCircle()
+ SkPath path;
+ path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
+ path.addCircle(0, 0, SkIntToScalar(20), SkPath::kCW_Direction);
+ check_for_circle(reporter, path, false, SkPath::kCW_Direction);
+
+ // some extra lineTo() would make isOval() fail
+ path.reset();
+ path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
+ path.lineTo(0, 0);
+ check_for_circle(reporter, path, false, SkPath::kCW_Direction);
+
+ // not back to the original point
+ path.reset();
+ path.addCircle(0, 0, SkIntToScalar(10), SkPath::kCW_Direction);
+ path.setLastPt(SkIntToScalar(5), SkIntToScalar(5));
+ check_for_circle(reporter, path, false, SkPath::kCW_Direction);
+
+ test_circle_with_add_paths(reporter);
+
+ // test negative radius
+ path.reset();
+ path.addCircle(0, 0, -1, SkPath::kCW_Direction);
+ REPORTER_ASSERT(reporter, path.isEmpty());
+}
+
+static void test_oval(skiatest::Reporter* reporter) {
+ SkRect rect;
+ SkMatrix m;
+ SkPath path;
+
+ rect = SkRect::MakeWH(SkIntToScalar(30), SkIntToScalar(50));
+ path.addOval(rect);
+
+ REPORTER_ASSERT(reporter, path.isOval(NULL));
+
+ m.setRotate(SkIntToScalar(90));
+ SkPath tmp;
+ path.transform(m, &tmp);
+ // an oval rotated 90 degrees is still an oval.
+ REPORTER_ASSERT(reporter, tmp.isOval(NULL));
+
+ m.reset();
+ m.setRotate(SkIntToScalar(30));
+ tmp.reset();
+ path.transform(m, &tmp);
+ // an oval rotated 30 degrees is not an oval anymore.
+ REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
+
+ // since empty path being transformed.
+ path.reset();
+ tmp.reset();
+ m.reset();
+ path.transform(m, &tmp);
+ REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
+
+ // empty path is not an oval
+ tmp.reset();
+ REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
+
+ // only has moveTo()s
+ tmp.reset();
+ tmp.moveTo(0, 0);
+ tmp.moveTo(SkIntToScalar(10), SkIntToScalar(10));
+ REPORTER_ASSERT(reporter, !tmp.isOval(NULL));
+
+ // mimic WebKit's calling convention,
+ // call moveTo() first and then call addOval()
+ path.reset();
+ path.moveTo(0, 0);
+ path.addOval(rect);
+ REPORTER_ASSERT(reporter, path.isOval(NULL));
+
+ // copy path
+ path.reset();
+ tmp.reset();
+ tmp.addOval(rect);
+ path = tmp;
+ REPORTER_ASSERT(reporter, path.isOval(NULL));
+}
+
+static void test_empty(skiatest::Reporter* reporter, const SkPath& p) {
+ SkPath empty;
+
+ REPORTER_ASSERT(reporter, p.isEmpty());
+ REPORTER_ASSERT(reporter, 0 == p.countPoints());
+ REPORTER_ASSERT(reporter, 0 == p.countVerbs());
+ REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, p.isConvex());
+ REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
+ REPORTER_ASSERT(reporter, !p.isInverseFillType());
+ REPORTER_ASSERT(reporter, p == empty);
+ REPORTER_ASSERT(reporter, !(p != empty));
+}
+
+static void test_rrect_is_convex(skiatest::Reporter* reporter, SkPath* path,
+ SkPath::Direction dir) {
+ REPORTER_ASSERT(reporter, path->isConvex());
+ REPORTER_ASSERT(reporter, path->cheapIsDirection(dir));
+ path->setConvexity(SkPath::kUnknown_Convexity);
+ REPORTER_ASSERT(reporter, path->isConvex());
+ path->reset();
+}
+
+static void test_rrect(skiatest::Reporter* reporter) {
+ SkPath p;
+ SkRRect rr;
+ SkVector radii[] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
+ SkRect r = {10, 20, 30, 40};
+ rr.setRectRadii(r, radii);
+ p.addRRect(rr);
+ test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
+ p.addRRect(rr, SkPath::kCCW_Direction);
+ test_rrect_is_convex(reporter, &p, SkPath::kCCW_Direction);
+ p.addRoundRect(r, &radii[0].fX);
+ test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
+ p.addRoundRect(r, &radii[0].fX, SkPath::kCCW_Direction);
+ test_rrect_is_convex(reporter, &p, SkPath::kCCW_Direction);
+ p.addRoundRect(r, radii[1].fX, radii[1].fY);
+ test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
+ p.addRoundRect(r, radii[1].fX, radii[1].fY, SkPath::kCCW_Direction);
+ test_rrect_is_convex(reporter, &p, SkPath::kCCW_Direction);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(radii); ++i) {
+ SkVector save = radii[i];
+ radii[i].set(0, 0);
+ rr.setRectRadii(r, radii);
+ p.addRRect(rr);
+ test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
+ radii[i] = save;
+ }
+ p.addRoundRect(r, 0, 0);
+ SkRect returnedRect;
+ REPORTER_ASSERT(reporter, p.isRect(&returnedRect));
+ REPORTER_ASSERT(reporter, returnedRect == r);
+ test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
+ SkVector zeroRadii[] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
+ rr.setRectRadii(r, zeroRadii);
+ p.addRRect(rr);
+ bool closed;
+ SkPath::Direction dir;
+ REPORTER_ASSERT(reporter, p.isRect(&closed, &dir));
+ REPORTER_ASSERT(reporter, closed);
+ REPORTER_ASSERT(reporter, SkPath::kCW_Direction == dir);
+ test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
+ p.addRRect(rr, SkPath::kCW_Direction);
+ p.addRRect(rr, SkPath::kCW_Direction);
+ REPORTER_ASSERT(reporter, !p.isConvex());
+ p.reset();
+ p.addRRect(rr, SkPath::kCCW_Direction);
+ p.addRRect(rr, SkPath::kCCW_Direction);
+ REPORTER_ASSERT(reporter, !p.isConvex());
+ p.reset();
+ SkRect emptyR = {10, 20, 10, 30};
+ rr.setRectRadii(emptyR, radii);
+ p.addRRect(rr);
+ REPORTER_ASSERT(reporter, p.isEmpty());
+ SkRect largeR = {0, 0, SK_ScalarMax, SK_ScalarMax};
+ rr.setRectRadii(largeR, radii);
+ p.addRRect(rr);
+ test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
+ SkRect infR = {0, 0, SK_ScalarMax, SK_ScalarInfinity};
+ rr.setRectRadii(infR, radii);
+ p.addRRect(rr);
+ test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
+ SkRect tinyR = {0, 0, 1e-9f, 1e-9f};
+ p.addRoundRect(tinyR, 5e-11f, 5e-11f);
+ test_rrect_is_convex(reporter, &p, SkPath::kCW_Direction);
+}
+
+static void test_arc(skiatest::Reporter* reporter) {
+ SkPath p;
+ SkRect emptyOval = {10, 20, 30, 20};
+ REPORTER_ASSERT(reporter, emptyOval.isEmpty());
+ p.addArc(emptyOval, 1, 2);
+ REPORTER_ASSERT(reporter, p.isEmpty());
+ p.reset();
+ SkRect oval = {10, 20, 30, 40};
+ p.addArc(oval, 1, 0);
+ REPORTER_ASSERT(reporter, p.isEmpty());
+ p.reset();
+ SkPath cwOval;
+ cwOval.addOval(oval);
+ p.addArc(oval, 1, 360);
+ REPORTER_ASSERT(reporter, p == cwOval);
+ p.reset();
+ SkPath ccwOval;
+ ccwOval.addOval(oval, SkPath::kCCW_Direction);
+ p.addArc(oval, 1, -360);
+ REPORTER_ASSERT(reporter, p == ccwOval);
+ p.reset();
+ p.addArc(oval, 1, 180);
+ REPORTER_ASSERT(reporter, p.isConvex());
+ REPORTER_ASSERT(reporter, p.cheapIsDirection(SkPath::kCW_Direction));
+ p.setConvexity(SkPath::kUnknown_Convexity);
+ REPORTER_ASSERT(reporter, p.isConvex());
+}
+
+static void check_move(skiatest::Reporter* reporter, SkPath::RawIter* iter,
+ SkScalar x0, SkScalar y0) {
+ SkPoint pts[4];
+ SkPath::Verb v = iter->next(pts);
+ REPORTER_ASSERT(reporter, v == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == x0);
+ REPORTER_ASSERT(reporter, pts[0].fY == y0);
+}
+
+static void check_line(skiatest::Reporter* reporter, SkPath::RawIter* iter,
+ SkScalar x1, SkScalar y1) {
+ SkPoint pts[4];
+ SkPath::Verb v = iter->next(pts);
+ REPORTER_ASSERT(reporter, v == SkPath::kLine_Verb);
+ REPORTER_ASSERT(reporter, pts[1].fX == x1);
+ REPORTER_ASSERT(reporter, pts[1].fY == y1);
+}
+
+static void check_quad(skiatest::Reporter* reporter, SkPath::RawIter* iter,
+ SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
+ SkPoint pts[4];
+ SkPath::Verb v = iter->next(pts);
+ REPORTER_ASSERT(reporter, v == SkPath::kQuad_Verb);
+ REPORTER_ASSERT(reporter, pts[1].fX == x1);
+ REPORTER_ASSERT(reporter, pts[1].fY == y1);
+ REPORTER_ASSERT(reporter, pts[2].fX == x2);
+ REPORTER_ASSERT(reporter, pts[2].fY == y2);
+}
+
+static void check_done(skiatest::Reporter* reporter, SkPath* p, SkPath::RawIter* iter) {
+ SkPoint pts[4];
+ SkPath::Verb v = iter->next(pts);
+ REPORTER_ASSERT(reporter, v == SkPath::kDone_Verb);
+}
+
+static void check_done_and_reset(skiatest::Reporter* reporter, SkPath* p, SkPath::RawIter* iter) {
+ check_done(reporter, p, iter);
+ p->reset();
+}
+
+static void check_path_is_move_and_reset(skiatest::Reporter* reporter, SkPath* p,
+ SkScalar x0, SkScalar y0) {
+ SkPath::RawIter iter(*p);
+ check_move(reporter, &iter, x0, y0);
+ check_done_and_reset(reporter, p, &iter);
+}
+
+static void check_path_is_line_and_reset(skiatest::Reporter* reporter, SkPath* p,
+ SkScalar x1, SkScalar y1) {
+ SkPath::RawIter iter(*p);
+ check_move(reporter, &iter, 0, 0);
+ check_line(reporter, &iter, x1, y1);
+ check_done_and_reset(reporter, p, &iter);
+}
+
+static void check_path_is_line(skiatest::Reporter* reporter, SkPath* p,
+ SkScalar x1, SkScalar y1) {
+ SkPath::RawIter iter(*p);
+ check_move(reporter, &iter, 0, 0);
+ check_line(reporter, &iter, x1, y1);
+ check_done(reporter, p, &iter);
+}
+
+static void check_path_is_line_pair_and_reset(skiatest::Reporter* reporter, SkPath* p,
+ SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
+ SkPath::RawIter iter(*p);
+ check_move(reporter, &iter, 0, 0);
+ check_line(reporter, &iter, x1, y1);
+ check_line(reporter, &iter, x2, y2);
+ check_done_and_reset(reporter, p, &iter);
+}
+
+static void check_path_is_quad_and_reset(skiatest::Reporter* reporter, SkPath* p,
+ SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
+ SkPath::RawIter iter(*p);
+ check_move(reporter, &iter, 0, 0);
+ check_quad(reporter, &iter, x1, y1, x2, y2);
+ check_done_and_reset(reporter, p, &iter);
+}
+
+static void test_arcTo(skiatest::Reporter* reporter) {
+ SkPath p;
+ p.arcTo(0, 0, 1, 2, 1);
+ check_path_is_line_and_reset(reporter, &p, 0, 0);
+ p.arcTo(1, 2, 1, 2, 1);
+ check_path_is_line_and_reset(reporter, &p, 1, 2);
+ p.arcTo(1, 2, 3, 4, 0);
+ check_path_is_line_and_reset(reporter, &p, 1, 2);
+ p.arcTo(1, 2, 0, 0, 1);
+ check_path_is_line_and_reset(reporter, &p, 1, 2);
+ p.arcTo(1, 0, 1, 1, 1);
+ SkPoint pt;
+ REPORTER_ASSERT(reporter, p.getLastPt(&pt) && pt.fX == 1 && pt.fY == 1);
+ p.reset();
+ p.arcTo(1, 0, 1, -1, 1);
+ REPORTER_ASSERT(reporter, p.getLastPt(&pt) && pt.fX == 1 && pt.fY == -1);
+ p.reset();
+ SkRect oval = {1, 2, 3, 4};
+ p.arcTo(oval, 0, 0, true);
+ check_path_is_move_and_reset(reporter, &p, oval.fRight, oval.centerY());
+ p.arcTo(oval, 0, 0, false);
+ check_path_is_move_and_reset(reporter, &p, oval.fRight, oval.centerY());
+ p.arcTo(oval, 360, 0, true);
+ check_path_is_move_and_reset(reporter, &p, oval.fRight, oval.centerY());
+ p.arcTo(oval, 360, 0, false);
+ check_path_is_move_and_reset(reporter, &p, oval.fRight, oval.centerY());
+ for (float sweep = 359, delta = 0.5f; sweep != (float) (sweep + delta); ) {
+ p.arcTo(oval, 0, sweep, false);
+ REPORTER_ASSERT(reporter, p.getBounds() == oval);
+ sweep += delta;
+ delta /= 2;
+ }
+ for (float sweep = 361, delta = 0.5f; sweep != (float) (sweep - delta);) {
+ p.arcTo(oval, 0, sweep, false);
+ REPORTER_ASSERT(reporter, p.getBounds() == oval);
+ sweep -= delta;
+ delta /= 2;
+ }
+ SkRect noOvalWidth = {1, 2, 0, 3};
+ p.reset();
+ p.arcTo(noOvalWidth, 0, 360, false);
+ REPORTER_ASSERT(reporter, p.isEmpty());
+
+ SkRect noOvalHeight = {1, 2, 3, 1};
+ p.reset();
+ p.arcTo(noOvalHeight, 0, 360, false);
+ REPORTER_ASSERT(reporter, p.isEmpty());
+}
+
+static void test_addPath(skiatest::Reporter* reporter) {
+ SkPath p, q;
+ p.lineTo(1, 2);
+ q.moveTo(4, 4);
+ q.lineTo(7, 8);
+ q.conicTo(8, 7, 6, 5, 0.5f);
+ q.quadTo(6, 7, 8, 6);
+ q.cubicTo(5, 6, 7, 8, 7, 5);
+ q.close();
+ p.addPath(q, -4, -4);
+ SkRect expected = {0, 0, 4, 4};
+ REPORTER_ASSERT(reporter, p.getBounds() == expected);
+ p.reset();
+ p.reverseAddPath(q);
+ SkRect reverseExpected = {4, 4, 8, 8};
+ REPORTER_ASSERT(reporter, p.getBounds() == reverseExpected);
+}
+
+static void test_addPathMode(skiatest::Reporter* reporter, bool explicitMoveTo, bool extend) {
+ SkPath p, q;
+ if (explicitMoveTo) {
+ p.moveTo(1, 1);
+ }
+ p.lineTo(1, 2);
+ if (explicitMoveTo) {
+ q.moveTo(2, 1);
+ }
+ q.lineTo(2, 2);
+ p.addPath(q, extend ? SkPath::kExtend_AddPathMode : SkPath::kAppend_AddPathMode);
+ uint8_t verbs[4];
+ int verbcount = p.getVerbs(verbs, 4);
+ REPORTER_ASSERT(reporter, verbcount == 4);
+ REPORTER_ASSERT(reporter, verbs[0] == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, verbs[1] == SkPath::kLine_Verb);
+ REPORTER_ASSERT(reporter, verbs[2] == (extend ? SkPath::kLine_Verb : SkPath::kMove_Verb));
+ REPORTER_ASSERT(reporter, verbs[3] == SkPath::kLine_Verb);
+}
+
+static void test_extendClosedPath(skiatest::Reporter* reporter) {
+ SkPath p, q;
+ p.moveTo(1, 1);
+ p.lineTo(1, 2);
+ p.lineTo(2, 2);
+ p.close();
+ q.moveTo(2, 1);
+ q.lineTo(2, 3);
+ p.addPath(q, SkPath::kExtend_AddPathMode);
+ uint8_t verbs[7];
+ int verbcount = p.getVerbs(verbs, 7);
+ REPORTER_ASSERT(reporter, verbcount == 7);
+ REPORTER_ASSERT(reporter, verbs[0] == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, verbs[1] == SkPath::kLine_Verb);
+ REPORTER_ASSERT(reporter, verbs[2] == SkPath::kLine_Verb);
+ REPORTER_ASSERT(reporter, verbs[3] == SkPath::kClose_Verb);
+ REPORTER_ASSERT(reporter, verbs[4] == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, verbs[5] == SkPath::kLine_Verb);
+ REPORTER_ASSERT(reporter, verbs[6] == SkPath::kLine_Verb);
+
+ SkPoint pt;
+ REPORTER_ASSERT(reporter, p.getLastPt(&pt));
+ REPORTER_ASSERT(reporter, pt == SkPoint::Make(2, 3));
+ REPORTER_ASSERT(reporter, p.getPoint(3) == SkPoint::Make(1, 1));
+}
+
+static void test_addEmptyPath(skiatest::Reporter* reporter, SkPath::AddPathMode mode) {
+ SkPath p, q, r;
+ // case 1: dst is empty
+ p.moveTo(2, 1);
+ p.lineTo(2, 3);
+ q.addPath(p, mode);
+ REPORTER_ASSERT(reporter, q == p);
+ // case 2: src is empty
+ p.addPath(r, mode);
+ REPORTER_ASSERT(reporter, q == p);
+ // case 3: src and dst are empty
+ q.reset();
+ q.addPath(r, mode);
+ REPORTER_ASSERT(reporter, q.isEmpty());
+}
+
+static void test_conicTo_special_case(skiatest::Reporter* reporter) {
+ SkPath p;
+ p.conicTo(1, 2, 3, 4, -1);
+ check_path_is_line_and_reset(reporter, &p, 3, 4);
+ p.conicTo(1, 2, 3, 4, SK_ScalarInfinity);
+ check_path_is_line_pair_and_reset(reporter, &p, 1, 2, 3, 4);
+ p.conicTo(1, 2, 3, 4, 1);
+ check_path_is_quad_and_reset(reporter, &p, 1, 2, 3, 4);
+}
+
+static void test_get_point(skiatest::Reporter* reporter) {
+ SkPath p;
+ SkPoint pt = p.getPoint(0);
+ REPORTER_ASSERT(reporter, pt == SkPoint::Make(0, 0));
+ REPORTER_ASSERT(reporter, !p.getLastPt(NULL));
+ REPORTER_ASSERT(reporter, !p.getLastPt(&pt) && pt == SkPoint::Make(0, 0));
+ p.setLastPt(10, 10);
+ pt = p.getPoint(0);
+ REPORTER_ASSERT(reporter, pt == SkPoint::Make(10, 10));
+ REPORTER_ASSERT(reporter, p.getLastPt(NULL));
+ p.rMoveTo(10, 10);
+ REPORTER_ASSERT(reporter, p.getLastPt(&pt) && pt == SkPoint::Make(20, 20));
+}
+
+static void test_contains(skiatest::Reporter* reporter) {
+ SkPath p;
+ p.setFillType(SkPath::kInverseWinding_FillType);
+ REPORTER_ASSERT(reporter, p.contains(0, 0));
+ p.setFillType(SkPath::kWinding_FillType);
+ REPORTER_ASSERT(reporter, !p.contains(0, 0));
+ p.moveTo(4, 4);
+ p.lineTo(6, 8);
+ p.lineTo(8, 4);
+ // test quick reject
+ REPORTER_ASSERT(reporter, !p.contains(4, 0));
+ REPORTER_ASSERT(reporter, !p.contains(0, 4));
+ REPORTER_ASSERT(reporter, !p.contains(4, 10));
+ REPORTER_ASSERT(reporter, !p.contains(10, 4));
+ // test various crossings in x
+ REPORTER_ASSERT(reporter, !p.contains(5, 7));
+ REPORTER_ASSERT(reporter, p.contains(6, 7));
+ REPORTER_ASSERT(reporter, !p.contains(7, 7));
+ p.reset();
+ p.moveTo(4, 4);
+ p.lineTo(8, 6);
+ p.lineTo(4, 8);
+ // test various crossings in y
+ REPORTER_ASSERT(reporter, !p.contains(7, 5));
+ REPORTER_ASSERT(reporter, p.contains(7, 6));
+ REPORTER_ASSERT(reporter, !p.contains(7, 7));
+ // test quads
+ p.reset();
+ p.moveTo(4, 4);
+ p.quadTo(6, 6, 8, 8);
+ p.quadTo(6, 8, 4, 8);
+ p.quadTo(4, 6, 4, 4);
+ REPORTER_ASSERT(reporter, p.contains(5, 6));
+ REPORTER_ASSERT(reporter, !p.contains(6, 5));
+
+ p.reset();
+ p.moveTo(6, 6);
+ p.quadTo(8, 8, 6, 8);
+ p.quadTo(4, 8, 4, 6);
+ p.quadTo(4, 4, 6, 6);
+ REPORTER_ASSERT(reporter, p.contains(5, 6));
+ REPORTER_ASSERT(reporter, !p.contains(6, 5));
+
+#define CONIC_CONTAINS_BUG_FIXED 0
+#if CONIC_CONTAINS_BUG_FIXED
+ p.reset();
+ p.moveTo(4, 4);
+ p.conicTo(6, 6, 8, 8, 0.5f);
+ p.conicTo(6, 8, 4, 8, 0.5f);
+ p.conicTo(4, 6, 4, 4, 0.5f);
+ REPORTER_ASSERT(reporter, p.contains(5, 6));
+ REPORTER_ASSERT(reporter, !p.contains(6, 5));
+#endif
+
+ // test cubics
+ SkPoint pts[] = {{5, 4}, {6, 5}, {7, 6}, {6, 6}, {4, 6}, {5, 7}, {5, 5}, {5, 4}, {6, 5}, {7, 6}};
+ for (int i = 0; i < 3; ++i) {
+ p.reset();
+ p.setFillType(SkPath::kEvenOdd_FillType);
+ p.moveTo(pts[i].fX, pts[i].fY);
+ p.cubicTo(pts[i + 1].fX, pts[i + 1].fY, pts[i + 2].fX, pts[i + 2].fY, pts[i + 3].fX, pts[i + 3].fY);
+ p.cubicTo(pts[i + 4].fX, pts[i + 4].fY, pts[i + 5].fX, pts[i + 5].fY, pts[i + 6].fX, pts[i + 6].fY);
+ p.close();
+ REPORTER_ASSERT(reporter, p.contains(5.5f, 5.5f));
+ REPORTER_ASSERT(reporter, !p.contains(4.5f, 5.5f));
+ }
+}
+
+class PathRefTest_Private {
+public:
+ static void TestPathRef(skiatest::Reporter* reporter) {
+ static const int kRepeatCnt = 10;
+
+ SkAutoTUnref<SkPathRef> pathRef(SkNEW(SkPathRef));
+
+ SkPathRef::Editor ed(&pathRef);
+
+ {
+ ed.growForRepeatedVerb(SkPath::kMove_Verb, kRepeatCnt);
+ REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
+ REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countPoints());
+ REPORTER_ASSERT(reporter, 0 == pathRef->getSegmentMasks());
+ for (int i = 0; i < kRepeatCnt; ++i) {
+ REPORTER_ASSERT(reporter, SkPath::kMove_Verb == pathRef->atVerb(i));
+ }
+ ed.resetToSize(0, 0, 0);
+ }
+
+ {
+ ed.growForRepeatedVerb(SkPath::kLine_Verb, kRepeatCnt);
+ REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
+ REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countPoints());
+ REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == pathRef->getSegmentMasks());
+ for (int i = 0; i < kRepeatCnt; ++i) {
+ REPORTER_ASSERT(reporter, SkPath::kLine_Verb == pathRef->atVerb(i));
+ }
+ ed.resetToSize(0, 0, 0);
+ }
+
+ {
+ ed.growForRepeatedVerb(SkPath::kQuad_Verb, kRepeatCnt);
+ REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
+ REPORTER_ASSERT(reporter, 2*kRepeatCnt == pathRef->countPoints());
+ REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == pathRef->getSegmentMasks());
+ for (int i = 0; i < kRepeatCnt; ++i) {
+ REPORTER_ASSERT(reporter, SkPath::kQuad_Verb == pathRef->atVerb(i));
+ }
+ ed.resetToSize(0, 0, 0);
+ }
+
+ {
+ SkScalar* weights = NULL;
+ ed.growForRepeatedVerb(SkPath::kConic_Verb, kRepeatCnt, &weights);
+ REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
+ REPORTER_ASSERT(reporter, 2*kRepeatCnt == pathRef->countPoints());
+ REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countWeights());
+ REPORTER_ASSERT(reporter, SkPath::kConic_SegmentMask == pathRef->getSegmentMasks());
+ REPORTER_ASSERT(reporter, weights);
+ for (int i = 0; i < kRepeatCnt; ++i) {
+ REPORTER_ASSERT(reporter, SkPath::kConic_Verb == pathRef->atVerb(i));
+ }
+ ed.resetToSize(0, 0, 0);
+ }
+
+ {
+ ed.growForRepeatedVerb(SkPath::kCubic_Verb, kRepeatCnt);
+ REPORTER_ASSERT(reporter, kRepeatCnt == pathRef->countVerbs());
+ REPORTER_ASSERT(reporter, 3*kRepeatCnt == pathRef->countPoints());
+ REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == pathRef->getSegmentMasks());
+ for (int i = 0; i < kRepeatCnt; ++i) {
+ REPORTER_ASSERT(reporter, SkPath::kCubic_Verb == pathRef->atVerb(i));
+ }
+ ed.resetToSize(0, 0, 0);
+ }
+ }
+};
+
+static void test_operatorEqual(skiatest::Reporter* reporter) {
+ SkPath a;
+ SkPath b;
+ REPORTER_ASSERT(reporter, a == a);
+ REPORTER_ASSERT(reporter, a == b);
+ a.setFillType(SkPath::kInverseWinding_FillType);
+ REPORTER_ASSERT(reporter, a != b);
+ a.reset();
+ REPORTER_ASSERT(reporter, a == b);
+ a.lineTo(1, 1);
+ REPORTER_ASSERT(reporter, a != b);
+ a.reset();
+ REPORTER_ASSERT(reporter, a == b);
+ a.lineTo(1, 1);
+ b.lineTo(1, 2);
+ REPORTER_ASSERT(reporter, a != b);
+ a.reset();
+ a.lineTo(1, 2);
+ REPORTER_ASSERT(reporter, a == b);
+}
+
+static void compare_dump(skiatest::Reporter* reporter, const SkPath& path, bool force,
+ bool dumpAsHex, const char* str) {
+ SkDynamicMemoryWStream wStream;
+ path.dump(&wStream, force, dumpAsHex);
+ SkAutoDataUnref data(wStream.copyToData());
+ REPORTER_ASSERT(reporter, data->size() == strlen(str));
+ REPORTER_ASSERT(reporter, !memcmp(data->data(), str, strlen(str)));
+}
+
+static void test_dump(skiatest::Reporter* reporter) {
+ SkPath p;
+ compare_dump(reporter, p, false, false, "");
+ compare_dump(reporter, p, true, false, "");
+ p.moveTo(1, 2);
+ p.lineTo(3, 4);
+ compare_dump(reporter, p, false, false, "path.moveTo(1, 2);\n"
+ "path.lineTo(3, 4);\n");
+ compare_dump(reporter, p, true, false, "path.moveTo(1, 2);\n"
+ "path.lineTo(3, 4);\n"
+ "path.lineTo(1, 2);\n"
+ "path.close();\n");
+ p.reset();
+ p.moveTo(1, 2);
+ p.quadTo(3, 4, 5, 6);
+ compare_dump(reporter, p, false, false, "path.moveTo(1, 2);\n"
+ "path.quadTo(3, 4, 5, 6);\n");
+ p.reset();
+ p.moveTo(1, 2);
+ p.conicTo(3, 4, 5, 6, 0.5f);
+ compare_dump(reporter, p, false, false, "path.moveTo(1, 2);\n"
+ "path.conicTo(3, 4, 5, 6, 0.5f);\n");
+ p.reset();
+ p.moveTo(1, 2);
+ p.cubicTo(3, 4, 5, 6, 7, 8);
+ compare_dump(reporter, p, false, false, "path.moveTo(1, 2);\n"
+ "path.cubicTo(3, 4, 5, 6, 7, 8);\n");
+ p.reset();
+ p.moveTo(1, 2);
+ p.lineTo(3, 4);
+ compare_dump(reporter, p, false, true, "path.moveTo(SkBits2Float(0x3f800000), SkBits2Float(0x40000000));\n"
+ "path.lineTo(SkBits2Float(0x40400000), SkBits2Float(0x40800000));\n");
+ p.reset();
+ p.moveTo(SkBits2Float(0x3f800000), SkBits2Float(0x40000000));
+ p.lineTo(SkBits2Float(0x40400000), SkBits2Float(0x40800000));
+ compare_dump(reporter, p, false, false, "path.moveTo(1, 2);\n"
+ "path.lineTo(3, 4);\n");
+}
+
+class PathTest_Private {
+public:
+ static void TestPathTo(skiatest::Reporter* reporter) {
+ SkPath p, q;
+ p.lineTo(4, 4);
+ p.reversePathTo(q);
+ check_path_is_line(reporter, &p, 4, 4);
+ q.moveTo(-4, -4);
+ p.reversePathTo(q);
+ check_path_is_line(reporter, &p, 4, 4);
+ q.lineTo(7, 8);
+ q.conicTo(8, 7, 6, 5, 0.5f);
+ q.quadTo(6, 7, 8, 6);
+ q.cubicTo(5, 6, 7, 8, 7, 5);
+ q.close();
+ p.reversePathTo(q);
+ SkRect reverseExpected = {-4, -4, 8, 8};
+ REPORTER_ASSERT(reporter, p.getBounds() == reverseExpected);
+ }
+};
+
+DEF_TEST(Paths, reporter) {
+ test_path_crbug364224();
+
+ SkTSize<SkScalar>::Make(3,4);
+
+ SkPath p, empty;
+ SkRect bounds, bounds2;
+ test_empty(reporter, p);
+
+ REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
+
+ // this triggers a code path in SkPath::operator= which is otherwise unexercised
+ SkPath& self = p;
+ p = self;
+
+ // this triggers a code path in SkPath::swap which is otherwise unexercised
+ p.swap(self);
+
+ bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
+
+ p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
+ check_convex_bounds(reporter, p, bounds);
+ // we have quads or cubics
+ REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+
+ p.reset();
+ test_empty(reporter, p);
+
+ p.addOval(bounds);
+ check_convex_bounds(reporter, p, bounds);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+
+ p.rewind();
+ test_empty(reporter, p);
+
+ p.addRect(bounds);
+ check_convex_bounds(reporter, p, bounds);
+ // we have only lines
+ REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+
+ REPORTER_ASSERT(reporter, p != empty);
+ REPORTER_ASSERT(reporter, !(p == empty));
+
+ // do getPoints and getVerbs return the right result
+ REPORTER_ASSERT(reporter, p.getPoints(NULL, 0) == 4);
+ REPORTER_ASSERT(reporter, p.getVerbs(NULL, 0) == 5);
+ SkPoint pts[4];
+ int count = p.getPoints(pts, 4);
+ REPORTER_ASSERT(reporter, count == 4);
+ uint8_t verbs[6];
+ verbs[5] = 0xff;
+ p.getVerbs(verbs, 5);
+ REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+ REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[1]);
+ REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[2]);
+ REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[3]);
+ REPORTER_ASSERT(reporter, SkPath::kClose_Verb == verbs[4]);
+ REPORTER_ASSERT(reporter, 0xff == verbs[5]);
+ bounds2.set(pts, 4);
+ REPORTER_ASSERT(reporter, bounds == bounds2);
+
+ bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
+ p.offset(SK_Scalar1*3, SK_Scalar1*4);
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ REPORTER_ASSERT(reporter, p.isRect(NULL));
+ bounds2.setEmpty();
+ REPORTER_ASSERT(reporter, p.isRect(&bounds2));
+ REPORTER_ASSERT(reporter, bounds == bounds2);
+
+ // now force p to not be a rect
+ bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
+ p.addRect(bounds);
+ REPORTER_ASSERT(reporter, !p.isRect(NULL));
+
+ test_operatorEqual(reporter);
+ test_isLine(reporter);
+ test_isRect(reporter);
+ test_isNestedRects(reporter);
+ test_zero_length_paths(reporter);
+ test_direction(reporter);
+ test_convexity(reporter);
+ test_convexity2(reporter);
+ test_conservativelyContains(reporter);
+ test_close(reporter);
+ test_segment_masks(reporter);
+ test_flattening(reporter);
+ test_transform(reporter);
+ test_bounds(reporter);
+ test_iter(reporter);
+ test_raw_iter(reporter);
+ test_circle(reporter);
+ test_oval(reporter);
+ test_strokerec(reporter);
+ test_addPoly(reporter);
+ test_isfinite(reporter);
+ test_isfinite_after_transform(reporter);
+ test_arb_round_rect_is_convex(reporter);
+ test_arb_zero_rad_round_rect_is_rect(reporter);
+ test_addrect(reporter);
+ test_addrect_isfinite(reporter);
+ test_tricky_cubic();
+ test_clipped_cubic();
+ test_crbug_170666();
+ test_bad_cubic_crbug229478();
+ test_bad_cubic_crbug234190();
+ test_android_specific_behavior(reporter);
+ test_gen_id(reporter);
+ test_path_close_issue1474(reporter);
+ test_path_to_region(reporter);
+ test_rrect(reporter);
+ test_arc(reporter);
+ test_arcTo(reporter);
+ test_addPath(reporter);
+ test_addPathMode(reporter, false, false);
+ test_addPathMode(reporter, true, false);
+ test_addPathMode(reporter, false, true);
+ test_addPathMode(reporter, true, true);
+ test_extendClosedPath(reporter);
+ test_addEmptyPath(reporter, SkPath::kExtend_AddPathMode);
+ test_addEmptyPath(reporter, SkPath::kAppend_AddPathMode);
+ test_conicTo_special_case(reporter);
+ test_get_point(reporter);
+ test_contains(reporter);
+ PathTest_Private::TestPathTo(reporter);
+ PathRefTest_Private::TestPathRef(reporter);
+ test_dump(reporter);
+ test_path_crbugskia2820(reporter);
+}
diff --git a/src/third_party/skia/tests/PathUtilsTest.cpp b/src/third_party/skia/tests/PathUtilsTest.cpp
new file mode 100644
index 0000000..4dfeda4
--- /dev/null
+++ b/src/third_party/skia/tests/PathUtilsTest.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkPathUtils.h"
+#include "SkRandom.h"
+#include "SkTime.h"
+#include "Test.h"
+
+const int kNumIt = 100;
+
+static void fill_random_bits(int chars, char* bits){
+ SkRandom rand(SkTime::GetMSecs());
+
+ for (int i = 0; i < chars; ++i){
+ bits[i] = rand.nextU();
+ }
+}
+
+static int get_bit(const char* buffer, int x) {
+ int byte = x >> 3;
+ int bit = x & 7;
+
+ return buffer[byte] & (128 >> bit);
+}
+
+/* // useful for debugging errors
+ #include <iostream>
+static void print_bits( const char* bits, int w, int h) {
+
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x){
+ bool bit = get_bit(&bits[y], x)!=0;
+ std::cout << bit;
+ }
+ std::cout << std::endl;
+ }
+}
+
+static void print_bmp( SkBitmap* bmp, int w, int h){
+
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ int d = *bmp->getAddr32(x,y);
+ if (d == -1)
+ std::cout << 0;
+ else
+ std::cout << 1;
+ }
+ std::cout << std::endl;
+ }
+}
+*/
+
+static void binary_to_skbitmap(const char* bin_bmp, SkBitmap* sk_bmp,
+ int w, int h, int rowBytes){
+ //init the SkBitmap
+ sk_bmp->allocN32Pixels(w, h);
+
+ for (int y = 0; y < h; ++y) { // for every row
+
+ const char* curLine = &bin_bmp[y * rowBytes];
+ for (int x = 0; x < w; ++x) {// for every pixel
+ if (get_bit(curLine, x)) {
+ *sk_bmp->getAddr32(x,y) = SK_ColorBLACK;
+ }
+ else {
+ *sk_bmp->getAddr32(x,y) = SK_ColorWHITE;
+ }
+ }
+ }
+}
+
+static bool test_bmp(skiatest::Reporter* reporter,
+ const SkBitmap* bmp1, const SkBitmap* bmp2,
+ int w, int h) {
+ for (int y = 0; y < h; ++y) { // loop through all pixels
+ for (int x = 0; x < w; ++x) {
+ REPORTER_ASSERT( reporter, *bmp1->getAddr32(x,y) == *bmp2->getAddr32(x,y) );
+ }
+ }
+ return true;
+}
+
+static void test_path_eq(skiatest::Reporter* reporter, const SkPath* path,
+ const SkBitmap* truth, int w, int h){
+ // make paint
+ SkPaint bmpPaint;
+ bmpPaint.setAntiAlias(true); // Black paint for bitmap
+ bmpPaint.setStyle(SkPaint::kFill_Style);
+ bmpPaint.setColor(SK_ColorBLACK);
+
+ // make bmp
+ SkBitmap bmp;
+ bmp.allocN32Pixels(w, h);
+ SkCanvas canvas(bmp);
+ canvas.clear(SK_ColorWHITE);
+ canvas.drawPath(*path, bmpPaint);
+
+ // test bmp
+ test_bmp(reporter, truth, &bmp, w, h);
+}
+
+static void test_path(skiatest::Reporter* reporter, const SkBitmap* truth,
+ const char* bin_bmp, int w, int h, int rowBytes){
+ // make path
+ SkPath path;
+ SkPathUtils::BitsToPath_Path(&path, bin_bmp, w, h, rowBytes);
+
+ //test for correctness
+ test_path_eq(reporter, &path, truth, w, h);
+}
+
+static void test_region(skiatest::Reporter* reporter, const SkBitmap* truth,
+ const char* bin_bmp, int w, int h, int rowBytes){
+ //generate bitmap
+ SkPath path;
+ SkPathUtils::BitsToPath_Region(&path, bin_bmp, w, h, rowBytes);
+
+ //test for correctness
+ test_path_eq(reporter, &path, truth, w, h);
+}
+
+DEF_TEST(PathUtils, reporter) {
+ const int w[] = {4, 8, 12, 16};
+ const int h = 8, rowBytes = 4;
+
+ char bits[ h * rowBytes ];
+ static char* binBmp = &bits[0];
+
+ //loop to run randomized test lots of times
+ for (int it = 0; it < kNumIt; ++it)
+ {
+ // generate a random binary bitmap
+ fill_random_bits( h * rowBytes, binBmp); // generate random bitmap
+
+ // for each bitmap width, use subset of binary bitmap
+ for (unsigned int i = 0; i < SK_ARRAY_COUNT(w); ++i) {
+ // generate truth bitmap
+ SkBitmap bmpTruth;
+ binary_to_skbitmap(binBmp, &bmpTruth, w[i], h, rowBytes);
+
+ test_path(reporter, &bmpTruth, binBmp, w[i], h, rowBytes);
+ test_region(reporter, &bmpTruth, binBmp, w[i], h, rowBytes);
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/PictureShaderTest.cpp b/src/third_party/skia/tests/PictureShaderTest.cpp
new file mode 100644
index 0000000..8d933db
--- /dev/null
+++ b/src/third_party/skia/tests/PictureShaderTest.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPicture.h"
+#include "SkPictureRecorder.h"
+#include "SkShader.h"
+#include "Test.h"
+
+// Test that attempting to create a picture shader with a NULL picture or
+// empty picture returns NULL.
+DEF_TEST(PictureShader_empty, reporter) {
+ SkShader* shader = SkShader::CreatePictureShader(NULL,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, NULL, NULL);
+ REPORTER_ASSERT(reporter, NULL == shader);
+
+ SkPictureRecorder factory;
+ factory.beginRecording(0, 0, NULL, 0);
+ SkAutoTUnref<SkPicture> picture(factory.endRecording());
+ shader = SkShader::CreatePictureShader(picture.get(),
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, NULL, NULL);
+ REPORTER_ASSERT(reporter, NULL == shader);
+}
diff --git a/src/third_party/skia/tests/PictureStateTreeTest.cpp b/src/third_party/skia/tests/PictureStateTreeTest.cpp
new file mode 100644
index 0000000..cb154de
--- /dev/null
+++ b/src/third_party/skia/tests/PictureStateTreeTest.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBBHFactory.h"
+#include "SkCanvas.h"
+#include "SkPictureRecorder.h"
+#include "SkPictureStateTree.h"
+#include "Test.h"
+
+static SkPicture* draw_scene(SkBBHFactory* bbhFactory) {
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(200, 200, bbhFactory, 0);
+
+ SkPaint p1, p2;
+ p1.setStyle(SkPaint::kFill_Style);
+ p1.setARGB(0x80, 0, 0xff, 0);
+ p2.setStyle(SkPaint::kFill_Style);
+ p2.setARGB(0x80, 0xff, 0, 0);
+
+ canvas->drawColor(SK_ColorWHITE);
+
+ // This is intended to exercise some tricky SkPictureStateTree code paths when
+ // played back with various clips:
+ //
+ // * cleanup/rewind when the last draw is not at the root of the state tree.
+ // * state nodes with both kSave_Flag & kSaveLayer_Flag set.
+ // * state tree transitions which implicitly reset the matrix via. restore().
+
+ canvas->save();
+ canvas->translate(10, 10);
+
+ canvas->drawRect(SkRect::MakeWH(100, 50), p1);
+ canvas->drawRect(SkRect::MakeWH(50, 100), p2);
+
+ SkRect layerBounds = SkRect::MakeXYWH(0, 0, 90, 90);
+ canvas->saveLayer(&layerBounds, NULL);
+ canvas->save();
+ canvas->clipRect(layerBounds);
+
+ canvas->save();
+ canvas->clipRect(SkRect::MakeWH(25, 25));
+ canvas->rotate(90);
+ canvas->drawRect(SkRect::MakeWH(100, 50), p1);
+ canvas->restore();
+
+ canvas->save();
+ canvas->clipRect(SkRect::MakeWH(25, 25));
+ canvas->save();
+ canvas->rotate(90);
+ canvas->drawRect(SkRect::MakeWH(50, 100), p2);
+ canvas->restore();
+ canvas->drawRect(SkRect::MakeWH(100, 50), p1);
+ canvas->restore();
+ canvas->drawRect(SkRect::MakeXYWH(99, 99, 1, 1), p1);
+ canvas->restore();
+ canvas->restore();
+
+ canvas->restore();
+
+ return recorder.endRecording();
+}
+
+static void check_bms(skiatest::Reporter* reporter, const SkBitmap& bm1, const SkBitmap& bm2) {
+ SkASSERT(bm1.getSize() == bm2.getSize());
+ REPORTER_ASSERT(reporter, 0 == memcmp(bm1.getAddr(0, 0), bm2.getAddr(0, 0), bm1.getSize()));
+}
+
+static void test_reference_picture(skiatest::Reporter* reporter) {
+ SkRTreeFactory bbhFactory;
+
+ SkAutoTUnref<SkPicture> bbhPicture(draw_scene(&bbhFactory));
+ SkAutoTUnref<SkPicture> referencePicture(draw_scene(NULL));
+
+ SkBitmap referenceBitmap;
+ referenceBitmap.allocN32Pixels(100, 100);
+ SkCanvas referenceCanvas(referenceBitmap);
+
+ SkBitmap bbhBitmap;
+ bbhBitmap.allocN32Pixels(100, 100);
+ SkCanvas bbhCanvas(bbhBitmap);
+
+ referenceCanvas.drawColor(SK_ColorTRANSPARENT);
+ referenceCanvas.drawPicture(referencePicture.get());
+ bbhCanvas.drawColor(SK_ColorTRANSPARENT);
+ bbhCanvas.drawPicture(bbhPicture.get());
+ REPORTER_ASSERT(reporter,
+ referenceCanvas.getSaveCount() == bbhCanvas.getSaveCount());
+ REPORTER_ASSERT(reporter,
+ referenceCanvas.getTotalMatrix() == bbhCanvas.getTotalMatrix());
+ check_bms(reporter, referenceBitmap, bbhBitmap);
+
+ referenceCanvas.drawColor(SK_ColorTRANSPARENT);
+ referenceCanvas.clipRect(SkRect::MakeWH(50, 50));
+ referenceCanvas.drawPicture(referencePicture.get());
+ bbhCanvas.drawColor(SK_ColorTRANSPARENT);
+ bbhCanvas.clipRect(SkRect::MakeWH(50, 50));
+ bbhCanvas.drawPicture(bbhPicture.get());
+ REPORTER_ASSERT(reporter,
+ referenceCanvas.getSaveCount() == bbhCanvas.getSaveCount());
+ REPORTER_ASSERT(reporter,
+ referenceCanvas.getTotalMatrix() == bbhCanvas.getTotalMatrix());
+ check_bms(reporter, referenceBitmap, bbhBitmap);
+
+ referenceCanvas.drawColor(SK_ColorTRANSPARENT);
+ referenceCanvas.clipRect(SkRect::MakeWH(10, 10));
+ referenceCanvas.drawPicture(referencePicture.get());
+ bbhCanvas.drawColor(SK_ColorTRANSPARENT);
+ bbhCanvas.clipRect(SkRect::MakeWH(10, 10));
+ bbhCanvas.drawPicture(bbhPicture.get());
+ REPORTER_ASSERT(reporter,
+ referenceCanvas.getSaveCount() == bbhCanvas.getSaveCount());
+ REPORTER_ASSERT(reporter,
+ referenceCanvas.getTotalMatrix() == bbhCanvas.getTotalMatrix());
+ check_bms(reporter, referenceBitmap, bbhBitmap);
+}
+
+DEF_TEST(PictureStateTree, reporter) {
+ test_reference_picture(reporter);
+}
diff --git a/src/third_party/skia/tests/PictureTest.cpp b/src/third_party/skia/tests/PictureTest.cpp
new file mode 100644
index 0000000..9cd63df
--- /dev/null
+++ b/src/third_party/skia/tests/PictureTest.cpp
@@ -0,0 +1,1955 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBBoxHierarchy.h"
+#include "SkBlurImageFilter.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkDashPathEffect.h"
+#include "SkData.h"
+#include "SkDecodingImageGenerator.h"
+#include "SkError.h"
+#include "SkImageEncoder.h"
+#include "SkImageGenerator.h"
+#include "SkPaint.h"
+#include "SkPicture.h"
+#include "SkPictureRecorder.h"
+#include "SkPictureUtils.h"
+#include "SkPixelRef.h"
+#include "SkRRect.h"
+#include "SkRandom.h"
+#include "SkShader.h"
+#include "SkStream.h"
+
+#if SK_SUPPORT_GPU
+#include "SkSurface.h"
+#include "GrContextFactory.h"
+#include "GrPictureUtils.h"
+#endif
+#include "Test.h"
+
+#include "SkLumaColorFilter.h"
+#include "SkColorFilterImageFilter.h"
+
+static const int gColorScale = 30;
+static const int gColorOffset = 60;
+
+static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
+ bm->allocN32Pixels(w, h);
+ bm->eraseColor(color);
+ if (immutable) {
+ bm->setImmutable();
+ }
+}
+
+static void make_checkerboard(SkBitmap* bm, int w, int h, bool immutable) {
+ SkASSERT(w % 2 == 0);
+ SkASSERT(h % 2 == 0);
+ bm->allocPixels(SkImageInfo::Make(w, h, kAlpha_8_SkColorType,
+ kPremul_SkAlphaType));
+ SkAutoLockPixels lock(*bm);
+ for (int y = 0; y < h; y += 2) {
+ uint8_t* s = bm->getAddr8(0, y);
+ for (int x = 0; x < w; x += 2) {
+ *s++ = 0xFF;
+ *s++ = 0x00;
+ }
+ s = bm->getAddr8(0, y + 1);
+ for (int x = 0; x < w; x += 2) {
+ *s++ = 0x00;
+ *s++ = 0xFF;
+ }
+ }
+ if (immutable) {
+ bm->setImmutable();
+ }
+}
+
+static void init_paint(SkPaint* paint, const SkBitmap &bm) {
+ SkShader* shader = SkShader::CreateBitmapShader(bm,
+ SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+ paint->setShader(shader)->unref();
+}
+
+typedef void (*DrawBitmapProc)(SkCanvas*, const SkBitmap&,
+ const SkBitmap&, const SkPoint&,
+ SkTDArray<SkPixelRef*>* usedPixRefs);
+
+static void drawpaint_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ canvas->drawPaint(paint);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+static void drawpoints_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ // draw a rect
+ SkPoint points[5] = {
+ { pos.fX, pos.fY },
+ { pos.fX + bm.width() - 1, pos.fY },
+ { pos.fX + bm.width() - 1, pos.fY + bm.height() - 1 },
+ { pos.fX, pos.fY + bm.height() - 1 },
+ { pos.fX, pos.fY },
+ };
+
+ canvas->drawPoints(SkCanvas::kPolygon_PointMode, 5, points, paint);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+static void drawrect_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
+ r.offset(pos.fX, pos.fY);
+
+ canvas->drawRect(r, paint);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+static void drawoval_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
+ r.offset(pos.fX, pos.fY);
+
+ canvas->drawOval(r, paint);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+static void drawrrect_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
+ r.offset(pos.fX, pos.fY);
+
+ SkRRect rr;
+ rr.setRectXY(r, SkIntToScalar(bm.width())/4, SkIntToScalar(bm.height())/4);
+ canvas->drawRRect(rr, paint);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+static void drawpath_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ SkPath path;
+ path.lineTo(bm.width()/2.0f, SkIntToScalar(bm.height()));
+ path.lineTo(SkIntToScalar(bm.width()), 0);
+ path.close();
+ path.offset(pos.fX, pos.fY);
+
+ canvas->drawPath(path, paint);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+static void drawbitmap_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ canvas->drawBitmap(bm, pos.fX, pos.fY, NULL);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+static void drawbitmap_withshader_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ // The bitmap in the paint is ignored unless we're drawing an A8 bitmap
+ canvas->drawBitmap(altBM, pos.fX, pos.fY, &paint);
+ *usedPixRefs->append() = bm.pixelRef();
+ *usedPixRefs->append() = altBM.pixelRef();
+}
+
+static void drawsprite_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ const SkMatrix& ctm = canvas->getTotalMatrix();
+
+ SkPoint p(pos);
+ ctm.mapPoints(&p, 1);
+
+ canvas->drawSprite(bm, (int)p.fX, (int)p.fY, NULL);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+#if 0
+// Although specifiable, this case doesn't seem to make sense (i.e., the
+// bitmap in the shader is never used).
+static void drawsprite_withshader_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ const SkMatrix& ctm = canvas->getTotalMatrix();
+
+ SkPoint p(pos);
+ ctm.mapPoints(&p, 1);
+
+ canvas->drawSprite(altBM, (int)p.fX, (int)p.fY, &paint);
+ *usedPixRefs->append() = bm.pixelRef();
+ *usedPixRefs->append() = altBM.pixelRef();
+}
+#endif
+
+static void drawbitmaprect_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
+
+ r.offset(pos.fX, pos.fY);
+ canvas->drawBitmapRectToRect(bm, NULL, r, NULL);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+static void drawbitmaprect_withshader_proc(SkCanvas* canvas,
+ const SkBitmap& bm,
+ const SkBitmap& altBM,
+ const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
+ r.offset(pos.fX, pos.fY);
+
+ // The bitmap in the paint is ignored unless we're drawing an A8 bitmap
+ canvas->drawBitmapRectToRect(altBM, NULL, r, &paint);
+ *usedPixRefs->append() = bm.pixelRef();
+ *usedPixRefs->append() = altBM.pixelRef();
+}
+
+static void drawtext_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+ paint.setTextSize(SkIntToScalar(1.5*bm.width()));
+
+ canvas->drawText("0", 1, pos.fX, pos.fY+bm.width(), paint);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+static void drawpostext_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+ paint.setTextSize(SkIntToScalar(1.5*bm.width()));
+
+ SkPoint point = { pos.fX, pos.fY + bm.height() };
+ canvas->drawPosText("O", 1, &point, paint);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+static void drawtextonpath_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+
+ init_paint(&paint, bm);
+ paint.setTextSize(SkIntToScalar(1.5*bm.width()));
+
+ SkPath path;
+ path.lineTo(SkIntToScalar(bm.width()), 0);
+ path.offset(pos.fX, pos.fY+bm.height());
+
+ canvas->drawTextOnPath("O", 1, path, NULL, paint);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+static void drawverts_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ SkPoint verts[4] = {
+ { pos.fX, pos.fY },
+ { pos.fX + bm.width(), pos.fY },
+ { pos.fX + bm.width(), pos.fY + bm.height() },
+ { pos.fX, pos.fY + bm.height() }
+ };
+ SkPoint texs[4] = { { 0, 0 },
+ { SkIntToScalar(bm.width()), 0 },
+ { SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) },
+ { 0, SkIntToScalar(bm.height()) } };
+ uint16_t indices[6] = { 0, 1, 2, 0, 2, 3 };
+
+ canvas->drawVertices(SkCanvas::kTriangles_VertexMode, 4, verts, texs, NULL, NULL,
+ indices, 6, paint);
+ *usedPixRefs->append() = bm.pixelRef();
+}
+
+// Return a picture with the bitmaps drawn at the specified positions.
+static SkPicture* record_bitmaps(const SkBitmap bm[],
+ const SkPoint pos[],
+ SkTDArray<SkPixelRef*> analytic[],
+ int count,
+ DrawBitmapProc proc) {
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(1000, 1000);
+ for (int i = 0; i < count; ++i) {
+ analytic[i].rewind();
+ canvas->save();
+ SkRect clipRect = SkRect::MakeXYWH(pos[i].fX, pos[i].fY,
+ SkIntToScalar(bm[i].width()),
+ SkIntToScalar(bm[i].height()));
+ canvas->clipRect(clipRect, SkRegion::kIntersect_Op);
+ proc(canvas, bm[i], bm[count+i], pos[i], &analytic[i]);
+ canvas->restore();
+ }
+ return recorder.endRecording();
+}
+
+static void rand_rect(SkRect* rect, SkRandom& rand, SkScalar W, SkScalar H) {
+ rect->fLeft = rand.nextRangeScalar(-W, 2*W);
+ rect->fTop = rand.nextRangeScalar(-H, 2*H);
+ rect->fRight = rect->fLeft + rand.nextRangeScalar(0, W);
+ rect->fBottom = rect->fTop + rand.nextRangeScalar(0, H);
+
+ // we integralize rect to make our tests more predictable, since Gather is
+ // a little sloppy.
+ SkIRect ir;
+ rect->round(&ir);
+ rect->set(ir);
+}
+
+static void draw(SkPicture* pic, int width, int height, SkBitmap* result) {
+ make_bm(result, width, height, SK_ColorBLACK, false);
+
+ SkCanvas canvas(*result);
+ canvas.drawPicture(pic);
+}
+
+template <typename T> int find_index(const T* array, T elem, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (array[i] == elem) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+// Return true if 'ref' is found in array[]
+static bool find(SkPixelRef const * const * array, SkPixelRef const * ref, int count) {
+ return find_index<const SkPixelRef*>(array, ref, count) >= 0;
+}
+
+// Look at each pixel that is inside 'subset', and if its color appears in
+// colors[], find the corresponding value in refs[] and append that ref into
+// array, skipping duplicates of the same value.
+// Note that gathering pixelRefs from rendered colors suffers from the problem
+// that multiple simultaneous textures (e.g., A8 for alpha and 8888 for color)
+// isn't easy to reconstruct.
+static void gather_from_image(const SkBitmap& bm, SkPixelRef* const refs[],
+ int count, SkTDArray<SkPixelRef*>* array,
+ const SkRect& subset) {
+ SkIRect ir;
+ subset.roundOut(&ir);
+
+ if (!ir.intersect(0, 0, bm.width()-1, bm.height()-1)) {
+ return;
+ }
+
+ // Since we only want to return unique values in array, when we scan we just
+ // set a bit for each index'd color found. In practice we only have a few
+ // distinct colors, so we just use an int's bits as our array. Hence the
+ // assert that count <= number-of-bits-in-our-int.
+ SkASSERT((unsigned)count <= 32);
+ uint32_t bitarray = 0;
+
+ SkAutoLockPixels alp(bm);
+
+ for (int y = ir.fTop; y < ir.fBottom; ++y) {
+ for (int x = ir.fLeft; x < ir.fRight; ++x) {
+ SkPMColor pmc = *bm.getAddr32(x, y);
+ // the only good case where the color is not found would be if
+ // the color is transparent, meaning no bitmap was drawn in that
+ // pixel.
+ if (pmc) {
+ uint32_t index = SkGetPackedR32(pmc);
+ SkASSERT(SkGetPackedG32(pmc) == index);
+ SkASSERT(SkGetPackedB32(pmc) == index);
+ if (0 == index) {
+ continue; // background color
+ }
+ SkASSERT(0 == (index - gColorOffset) % gColorScale);
+ index = (index - gColorOffset) / gColorScale;
+ SkASSERT(static_cast<int>(index) < count);
+ bitarray |= 1 << index;
+ }
+ }
+ }
+
+ for (int i = 0; i < count; ++i) {
+ if (bitarray & (1 << i)) {
+ *array->append() = refs[i];
+ }
+ }
+}
+
+static void gather_from_analytic(const SkPoint pos[], SkScalar w, SkScalar h,
+ const SkTDArray<SkPixelRef*> analytic[],
+ int count,
+ SkTDArray<SkPixelRef*>* result,
+ const SkRect& subset) {
+ for (int i = 0; i < count; ++i) {
+ SkRect rect = SkRect::MakeXYWH(pos[i].fX, pos[i].fY, w, h);
+
+ if (SkRect::Intersects(subset, rect)) {
+ result->append(analytic[i].count(), analytic[i].begin());
+ }
+ }
+}
+
+
+static const struct {
+ const DrawBitmapProc proc;
+ const char* const desc;
+} gProcs[] = {
+ {drawpaint_proc, "drawpaint"},
+ {drawpoints_proc, "drawpoints"},
+ {drawrect_proc, "drawrect"},
+ {drawoval_proc, "drawoval"},
+ {drawrrect_proc, "drawrrect"},
+ {drawpath_proc, "drawpath"},
+ {drawbitmap_proc, "drawbitmap"},
+ {drawbitmap_withshader_proc, "drawbitmap_withshader"},
+ {drawsprite_proc, "drawsprite"},
+#if 0
+ {drawsprite_withshader_proc, "drawsprite_withshader"},
+#endif
+ {drawbitmaprect_proc, "drawbitmaprect"},
+ {drawbitmaprect_withshader_proc, "drawbitmaprect_withshader"},
+ {drawtext_proc, "drawtext"},
+ {drawpostext_proc, "drawpostext"},
+ {drawtextonpath_proc, "drawtextonpath"},
+ {drawverts_proc, "drawverts"},
+};
+
+static void create_textures(SkBitmap* bm, SkPixelRef** refs, int num, int w, int h) {
+ // Our convention is that the color components contain an encoding of
+ // the index of their corresponding bitmap/pixelref. (0,0,0,0) is
+ // reserved for the background
+ for (int i = 0; i < num; ++i) {
+ make_bm(&bm[i], w, h,
+ SkColorSetARGB(0xFF,
+ gColorScale*i+gColorOffset,
+ gColorScale*i+gColorOffset,
+ gColorScale*i+gColorOffset),
+ true);
+ refs[i] = bm[i].pixelRef();
+ }
+
+ // The A8 alternate bitmaps are all BW checkerboards
+ for (int i = 0; i < num; ++i) {
+ make_checkerboard(&bm[num+i], w, h, true);
+ refs[num+i] = bm[num+i].pixelRef();
+ }
+}
+
+static void test_gatherpixelrefs(skiatest::Reporter* reporter) {
+ const int IW = 32;
+ const int IH = IW;
+ const SkScalar W = SkIntToScalar(IW);
+ const SkScalar H = W;
+
+ static const int N = 4;
+ SkBitmap bm[2*N];
+ SkPixelRef* refs[2*N];
+ SkTDArray<SkPixelRef*> analytic[N];
+
+ const SkPoint pos[N] = {
+ { 0, 0 }, { W, 0 }, { 0, H }, { W, H }
+ };
+
+ create_textures(bm, refs, N, IW, IH);
+
+ SkRandom rand;
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gProcs); ++k) {
+ SkAutoTUnref<SkPicture> pic(
+ record_bitmaps(bm, pos, analytic, N, gProcs[k].proc));
+
+ REPORTER_ASSERT(reporter, pic->willPlayBackBitmaps() || N == 0);
+ // quick check for a small piece of each quadrant, which should just
+ // contain 1 or 2 bitmaps.
+ for (size_t i = 0; i < SK_ARRAY_COUNT(pos); ++i) {
+ SkRect r;
+ r.set(2, 2, W - 2, H - 2);
+ r.offset(pos[i].fX, pos[i].fY);
+ SkAutoDataUnref data(SkPictureUtils::GatherPixelRefs(pic, r));
+ if (!data) {
+ ERRORF(reporter, "SkPictureUtils::GatherPixelRefs returned "
+ "NULL for %s.", gProcs[k].desc);
+ continue;
+ }
+ SkPixelRef** gatheredRefs = (SkPixelRef**)data->data();
+ int count = static_cast<int>(data->size() / sizeof(SkPixelRef*));
+ REPORTER_ASSERT(reporter, 1 == count || 2 == count);
+ if (1 == count) {
+ REPORTER_ASSERT(reporter, gatheredRefs[0] == refs[i]);
+ } else if (2 == count) {
+ REPORTER_ASSERT(reporter,
+ (gatheredRefs[0] == refs[i] && gatheredRefs[1] == refs[i+N]) ||
+ (gatheredRefs[1] == refs[i] && gatheredRefs[0] == refs[i+N]));
+ }
+ }
+
+ SkBitmap image;
+ draw(pic, 2*IW, 2*IH, &image);
+
+ // Test a bunch of random (mostly) rects, and compare the gather results
+ // with a deduced list of refs by looking at the colors drawn.
+ for (int j = 0; j < 100; ++j) {
+ SkRect r;
+ rand_rect(&r, rand, 2*W, 2*H);
+
+ SkTDArray<SkPixelRef*> fromImage;
+ gather_from_image(image, refs, N, &fromImage, r);
+
+ SkTDArray<SkPixelRef*> fromAnalytic;
+ gather_from_analytic(pos, W, H, analytic, N, &fromAnalytic, r);
+
+ SkData* data = SkPictureUtils::GatherPixelRefs(pic, r);
+ size_t dataSize = data ? data->size() : 0;
+ int gatherCount = static_cast<int>(dataSize / sizeof(SkPixelRef*));
+ SkASSERT(gatherCount * sizeof(SkPixelRef*) == dataSize);
+ SkPixelRef** gatherRefs = data ? (SkPixelRef**)(data->data()) : NULL;
+ SkAutoDataUnref adu(data);
+
+ // Everything that we saw drawn should appear in the analytic list
+ // but the analytic list may contain some pixelRefs that were not
+ // seen in the image (e.g., A8 textures used as masks)
+ for (int i = 0; i < fromImage.count(); ++i) {
+ if (-1 == fromAnalytic.find(fromImage[i])) {
+ ERRORF(reporter, "PixelRef missing %d %s",
+ i, gProcs[k].desc);
+ }
+ }
+
+ /*
+ * GatherPixelRefs is conservative, so it can return more bitmaps
+ * than are strictly required. Thus our check here is only that
+ * Gather didn't miss any that we actually needed. Even that isn't
+ * a strict requirement on Gather, which is meant to be quick and
+ * only mostly-correct, but at the moment this test should work.
+ */
+ for (int i = 0; i < fromAnalytic.count(); ++i) {
+ bool found = find(gatherRefs, fromAnalytic[i], gatherCount);
+ if (!found) {
+ ERRORF(reporter, "PixelRef missing %d %s",
+ i, gProcs[k].desc);
+ }
+#if 0
+ // enable this block of code to debug failures, as it will rerun
+ // the case that failed.
+ if (!found) {
+ SkData* data = SkPictureUtils::GatherPixelRefs(pic, r);
+ size_t dataSize = data ? data->size() : 0;
+ }
+#endif
+ }
+ }
+ }
+}
+
+#define GENERATE_CANVAS(recorder, x) \
+ (x) ? recorder.EXPERIMENTAL_beginRecording(100, 100) \
+ : recorder. DEPRECATED_beginRecording(100,100);
+
+/* Hit a few SkPicture::Analysis cases not handled elsewhere. */
+static void test_analysis(skiatest::Reporter* reporter, bool useNewPath) {
+ SkPictureRecorder recorder;
+
+ SkCanvas* canvas = GENERATE_CANVAS(recorder, useNewPath);
+ {
+ canvas->drawRect(SkRect::MakeWH(10, 10), SkPaint ());
+ }
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+ REPORTER_ASSERT(reporter, !picture->willPlayBackBitmaps());
+
+ canvas = GENERATE_CANVAS(recorder, useNewPath);
+ {
+ SkPaint paint;
+ // CreateBitmapShader is too smart for us; an empty (or 1x1) bitmap shader
+ // gets optimized into a non-bitmap form, so we create a 2x2 bitmap here.
+ SkBitmap bitmap;
+ bitmap.allocPixels(SkImageInfo::MakeN32Premul(2, 2));
+ bitmap.eraseColor(SK_ColorBLUE);
+ *(bitmap.getAddr32(0, 0)) = SK_ColorGREEN;
+ SkShader* shader = SkShader::CreateBitmapShader(bitmap, SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+ paint.setShader(shader)->unref();
+ REPORTER_ASSERT(reporter,
+ shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType);
+
+ canvas->drawRect(SkRect::MakeWH(10, 10), paint);
+ }
+ picture.reset(recorder.endRecording());
+ REPORTER_ASSERT(reporter, picture->willPlayBackBitmaps());
+}
+
+
+static void test_gatherpixelrefsandrects(skiatest::Reporter* reporter) {
+ const int IW = 32;
+ const int IH = IW;
+ const SkScalar W = SkIntToScalar(IW);
+ const SkScalar H = W;
+
+ static const int N = 4;
+ SkBitmap bm[2*N];
+ SkPixelRef* refs[2*N];
+ SkTDArray<SkPixelRef*> analytic[N];
+
+ const SkPoint pos[N] = {
+ { 0, 0 }, { W, 0 }, { 0, H }, { W, H }
+ };
+
+ create_textures(bm, refs, N, IW, IH);
+
+ SkRandom rand;
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gProcs); ++k) {
+ SkAutoTUnref<SkPicture> pic(
+ record_bitmaps(bm, pos, analytic, N, gProcs[k].proc));
+
+ REPORTER_ASSERT(reporter, pic->willPlayBackBitmaps() || N == 0);
+
+ SkAutoTUnref<SkPictureUtils::SkPixelRefContainer> prCont(
+ new SkPictureUtils::SkPixelRefsAndRectsList);
+
+ SkPictureUtils::GatherPixelRefsAndRects(pic, prCont);
+
+ // quick check for a small piece of each quadrant, which should just
+ // contain 1 or 2 bitmaps.
+ for (size_t i = 0; i < SK_ARRAY_COUNT(pos); ++i) {
+ SkRect r;
+ r.set(2, 2, W - 2, H - 2);
+ r.offset(pos[i].fX, pos[i].fY);
+
+ SkTDArray<SkPixelRef*> gatheredRefs;
+ prCont->query(r, &gatheredRefs);
+
+ int count = gatheredRefs.count();
+ REPORTER_ASSERT(reporter, 1 == count || 2 == count);
+ if (1 == count) {
+ REPORTER_ASSERT(reporter, gatheredRefs[0] == refs[i]);
+ } else if (2 == count) {
+ REPORTER_ASSERT(reporter,
+ (gatheredRefs[0] == refs[i] && gatheredRefs[1] == refs[i+N]) ||
+ (gatheredRefs[1] == refs[i] && gatheredRefs[0] == refs[i+N]));
+ }
+ }
+
+ SkBitmap image;
+ draw(pic, 2*IW, 2*IH, &image);
+
+ // Test a bunch of random (mostly) rects, and compare the gather results
+ // with the analytic results and the pixel refs seen in a rendering.
+ for (int j = 0; j < 100; ++j) {
+ SkRect r;
+ rand_rect(&r, rand, 2*W, 2*H);
+
+ SkTDArray<SkPixelRef*> fromImage;
+ gather_from_image(image, refs, N, &fromImage, r);
+
+ SkTDArray<SkPixelRef*> fromAnalytic;
+ gather_from_analytic(pos, W, H, analytic, N, &fromAnalytic, r);
+
+ SkTDArray<SkPixelRef*> gatheredRefs;
+ prCont->query(r, &gatheredRefs);
+
+ // Everything that we saw drawn should appear in the analytic list
+ // but the analytic list may contain some pixelRefs that were not
+ // seen in the image (e.g., A8 textures used as masks)
+ for (int i = 0; i < fromImage.count(); ++i) {
+ REPORTER_ASSERT(reporter, -1 != fromAnalytic.find(fromImage[i]));
+ }
+
+ // Everything in the analytic list should appear in the gathered
+ // list.
+ for (int i = 0; i < fromAnalytic.count(); ++i) {
+ REPORTER_ASSERT(reporter, -1 != gatheredRefs.find(fromAnalytic[i]));
+ }
+ }
+ }
+}
+
+#ifdef SK_DEBUG
+// Ensure that deleting an empty SkPicture does not assert. Asserts only fire
+// in debug mode, so only run in debug mode.
+static void test_deleting_empty_picture() {
+ SkPictureRecorder recorder;
+ // Creates an SkPictureRecord
+ recorder.beginRecording(0, 0);
+ // Turns that into an SkPicture
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+ // Ceates a new SkPictureRecord
+ recorder.beginRecording(0, 0);
+}
+
+// Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
+static void test_serializing_empty_picture() {
+ SkPictureRecorder recorder;
+ recorder.beginRecording(0, 0);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+ SkDynamicMemoryWStream stream;
+ picture->serialize(&stream);
+}
+#endif
+
+static void rand_op(SkCanvas* canvas, SkRandom& rand) {
+ SkPaint paint;
+ SkRect rect = SkRect::MakeWH(50, 50);
+
+ SkScalar unit = rand.nextUScalar1();
+ if (unit <= 0.3) {
+// SkDebugf("save\n");
+ canvas->save();
+ } else if (unit <= 0.6) {
+// SkDebugf("restore\n");
+ canvas->restore();
+ } else if (unit <= 0.9) {
+// SkDebugf("clip\n");
+ canvas->clipRect(rect);
+ } else {
+// SkDebugf("draw\n");
+ canvas->drawPaint(paint);
+ }
+}
+
+#if SK_SUPPORT_GPU
+
+static void test_gpu_veto(skiatest::Reporter* reporter,
+ bool useNewPath) {
+
+ SkPictureRecorder recorder;
+
+ SkCanvas* canvas = GENERATE_CANVAS(recorder, useNewPath);
+ {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(50, 50);
+
+ SkScalar intervals[] = { 1.0f, 1.0f };
+ SkAutoTUnref<SkDashPathEffect> dash(SkDashPathEffect::Create(intervals, 2, 0));
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setPathEffect(dash);
+
+ canvas->drawPath(path, paint);
+ }
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+ // path effects currently render an SkPicture undesireable for GPU rendering
+
+ const char *reason = NULL;
+ REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(NULL, &reason));
+ REPORTER_ASSERT(reporter, reason);
+
+ canvas = GENERATE_CANVAS(recorder, useNewPath);
+ {
+ SkPath path;
+
+ path.moveTo(0, 0);
+ path.lineTo(0, 50);
+ path.lineTo(25, 25);
+ path.lineTo(50, 50);
+ path.lineTo(50, 0);
+ path.close();
+ REPORTER_ASSERT(reporter, !path.isConvex());
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ for (int i = 0; i < 50; ++i) {
+ canvas->drawPath(path, paint);
+ }
+ }
+ picture.reset(recorder.endRecording());
+ // A lot of AA concave paths currently render an SkPicture undesireable for GPU rendering
+ REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(NULL));
+
+ canvas = GENERATE_CANVAS(recorder, useNewPath);
+ {
+ SkPath path;
+
+ path.moveTo(0, 0);
+ path.lineTo(0, 50);
+ path.lineTo(25, 25);
+ path.lineTo(50, 50);
+ path.lineTo(50, 0);
+ path.close();
+ REPORTER_ASSERT(reporter, !path.isConvex());
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(0);
+ for (int i = 0; i < 50; ++i) {
+ canvas->drawPath(path, paint);
+ }
+ }
+ picture.reset(recorder.endRecording());
+ // hairline stroked AA concave paths are fine for GPU rendering
+ REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(NULL));
+
+ canvas = GENERATE_CANVAS(recorder, useNewPath);
+ {
+ SkPaint paint;
+ SkScalar intervals [] = { 10, 20 };
+ SkPathEffect* pe = SkDashPathEffect::Create(intervals, 2, 25);
+ paint.setPathEffect(pe)->unref();
+
+ SkPoint points [2] = { { 0, 0 }, { 100, 0 } };
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 2, points, paint);
+ }
+ picture.reset(recorder.endRecording());
+ // fast-path dashed effects are fine for GPU rendering ...
+ REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(NULL));
+
+ canvas = GENERATE_CANVAS(recorder, useNewPath);
+ {
+ SkPaint paint;
+ SkScalar intervals [] = { 10, 20 };
+ SkPathEffect* pe = SkDashPathEffect::Create(intervals, 2, 25);
+ paint.setPathEffect(pe)->unref();
+
+ canvas->drawRect(SkRect::MakeWH(10, 10), paint);
+ }
+ picture.reset(recorder.endRecording());
+ // ... but only when applied to drawPoint() calls
+ REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(NULL));
+
+ // Nest the previous picture inside a new one.
+ // This doesn't work in the old backend.
+ if (useNewPath) {
+ canvas = GENERATE_CANVAS(recorder, useNewPath);
+ {
+ canvas->drawPicture(picture.get());
+ }
+ picture.reset(recorder.endRecording());
+ REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(NULL));
+ }
+}
+
+#undef GENERATE_CANVAS
+
+static void test_gpu_picture_optimization(skiatest::Reporter* reporter,
+ GrContextFactory* factory) {
+ for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
+ GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
+
+ if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
+ continue;
+ }
+
+ GrContext* context = factory->get(glCtxType);
+
+ if (NULL == context) {
+ continue;
+ }
+
+ static const int kWidth = 100;
+ static const int kHeight = 100;
+
+ SkAutoTUnref<SkPicture> pict, child;
+
+ {
+ SkPictureRecorder recorder;
+
+ SkCanvas* c = recorder.beginRecording(SkIntToScalar(kWidth), SkIntToScalar(kHeight));
+
+ c->saveLayer(NULL, NULL);
+ c->restore();
+
+ child.reset(recorder.endRecording());
+ }
+
+ // create a picture with the structure:
+ // 1)
+ // SaveLayer
+ // Restore
+ // 2)
+ // SaveLayer
+ // Translate
+ // SaveLayer w/ bound
+ // Restore
+ // Restore
+ // 3)
+ // SaveLayer w/ copyable paint
+ // Restore
+ // 4)
+ // SaveLayer
+ // DrawPicture (which has a SaveLayer/Restore pair)
+ // Restore
+ // 5)
+ // SaveLayer
+ // DrawPicture with Matrix & Paint (with SaveLayer/Restore pair)
+ // Restore
+ {
+ SkPictureRecorder recorder;
+
+ SkCanvas* c = recorder.beginRecording(SkIntToScalar(kWidth),
+ SkIntToScalar(kHeight));
+ // 1)
+ c->saveLayer(NULL, NULL); // layer #0
+ c->restore();
+
+ // 2)
+ c->saveLayer(NULL, NULL); // layer #1
+ c->translate(kWidth/2.0f, kHeight/2.0f);
+ SkRect r = SkRect::MakeXYWH(0, 0, kWidth/2, kHeight/2);
+ c->saveLayer(&r, NULL); // layer #2
+ c->restore();
+ c->restore();
+
+ // 3)
+ {
+ SkPaint p;
+ p.setColor(SK_ColorRED);
+ c->saveLayer(NULL, &p); // layer #3
+ c->restore();
+ }
+
+ SkPaint layerPaint;
+ layerPaint.setColor(SK_ColorRED); // Non-alpha only to avoid SaveLayerDrawRestoreNooper
+ // 4)
+ {
+ c->saveLayer(NULL, &layerPaint); // layer #4
+ c->drawPicture(child); // layer #5 inside picture
+ c->restore();
+ }
+ // 5
+ {
+ SkPaint picturePaint;
+ SkMatrix trans;
+ trans.setTranslate(10, 10);
+
+ c->saveLayer(NULL, &layerPaint); // layer #6
+ c->drawPicture(child, &trans, &picturePaint); // layer #7 inside picture
+ c->restore();
+ }
+
+ pict.reset(recorder.endRecording());
+ }
+
+ // Now test out the SaveLayer extraction
+ {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
+
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewScratchRenderTarget(context, info));
+
+ SkCanvas* canvas = surface->getCanvas();
+
+ canvas->EXPERIMENTAL_optimize(pict);
+
+ SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
+
+ const SkPicture::AccelData* data = pict->EXPERIMENTAL_getAccelData(key);
+ REPORTER_ASSERT(reporter, data);
+
+ const GrAccelData *gpuData = static_cast<const GrAccelData*>(data);
+ REPORTER_ASSERT(reporter, 8 == gpuData->numSaveLayers());
+
+ const GrAccelData::SaveLayerInfo& info0 = gpuData->saveLayerInfo(0);
+ // The parent/child layers appear in reverse order
+ const GrAccelData::SaveLayerInfo& info1 = gpuData->saveLayerInfo(2);
+ const GrAccelData::SaveLayerInfo& info2 = gpuData->saveLayerInfo(1);
+
+ const GrAccelData::SaveLayerInfo& info3 = gpuData->saveLayerInfo(3);
+
+ // The parent/child layers appear in reverse order
+ const GrAccelData::SaveLayerInfo& info4 = gpuData->saveLayerInfo(5);
+ const GrAccelData::SaveLayerInfo& info5 = gpuData->saveLayerInfo(4);
+
+ // The parent/child layers appear in reverse order
+ const GrAccelData::SaveLayerInfo& info6 = gpuData->saveLayerInfo(7);
+ const GrAccelData::SaveLayerInfo& info7 = gpuData->saveLayerInfo(6);
+
+ REPORTER_ASSERT(reporter, info0.fValid);
+ REPORTER_ASSERT(reporter, NULL == info0.fPicture);
+ REPORTER_ASSERT(reporter, kWidth == info0.fSize.fWidth &&
+ kHeight == info0.fSize.fHeight);
+ REPORTER_ASSERT(reporter, info0.fOriginXform.isIdentity());
+ REPORTER_ASSERT(reporter, 0 == info0.fOffset.fX && 0 == info0.fOffset.fY);
+ REPORTER_ASSERT(reporter, NULL == info0.fPaint);
+ REPORTER_ASSERT(reporter, !info0.fIsNested && !info0.fHasNestedLayers);
+
+ REPORTER_ASSERT(reporter, info1.fValid);
+ REPORTER_ASSERT(reporter, NULL == info1.fPicture);
+ REPORTER_ASSERT(reporter, kWidth == info1.fSize.fWidth &&
+ kHeight == info1.fSize.fHeight);
+ REPORTER_ASSERT(reporter, info1.fOriginXform.isIdentity());
+ REPORTER_ASSERT(reporter, 0 == info1.fOffset.fX && 0 == info1.fOffset.fY);
+ REPORTER_ASSERT(reporter, NULL == info1.fPaint);
+ REPORTER_ASSERT(reporter, !info1.fIsNested &&
+ info1.fHasNestedLayers); // has a nested SL
+
+ REPORTER_ASSERT(reporter, info2.fValid);
+ REPORTER_ASSERT(reporter, NULL == info2.fPicture);
+ REPORTER_ASSERT(reporter, kWidth / 2 == info2.fSize.fWidth &&
+ kHeight/2 == info2.fSize.fHeight); // bound reduces size
+ REPORTER_ASSERT(reporter, !info2.fOriginXform.isIdentity());
+ REPORTER_ASSERT(reporter, kWidth/2 == info2.fOffset.fX && // translated
+ kHeight/2 == info2.fOffset.fY);
+ REPORTER_ASSERT(reporter, NULL == info1.fPaint);
+ REPORTER_ASSERT(reporter, info2.fIsNested && !info2.fHasNestedLayers); // is nested
+
+ REPORTER_ASSERT(reporter, info3.fValid);
+ REPORTER_ASSERT(reporter, NULL == info3.fPicture);
+ REPORTER_ASSERT(reporter, kWidth == info3.fSize.fWidth &&
+ kHeight == info3.fSize.fHeight);
+ REPORTER_ASSERT(reporter, info3.fOriginXform.isIdentity());
+ REPORTER_ASSERT(reporter, 0 == info3.fOffset.fX && 0 == info3.fOffset.fY);
+ REPORTER_ASSERT(reporter, info3.fPaint);
+ REPORTER_ASSERT(reporter, !info3.fIsNested && !info3.fHasNestedLayers);
+
+ REPORTER_ASSERT(reporter, info4.fValid);
+ REPORTER_ASSERT(reporter, NULL == info4.fPicture);
+ REPORTER_ASSERT(reporter, kWidth == info4.fSize.fWidth &&
+ kHeight == info4.fSize.fHeight);
+ REPORTER_ASSERT(reporter, 0 == info4.fOffset.fX && 0 == info4.fOffset.fY);
+ REPORTER_ASSERT(reporter, info4.fOriginXform.isIdentity());
+ REPORTER_ASSERT(reporter, info4.fPaint);
+ REPORTER_ASSERT(reporter, !info4.fIsNested &&
+ info4.fHasNestedLayers); // has a nested SL
+
+ REPORTER_ASSERT(reporter, info5.fValid);
+ REPORTER_ASSERT(reporter, child == info5.fPicture); // in a child picture
+ REPORTER_ASSERT(reporter, kWidth == info5.fSize.fWidth &&
+ kHeight == info5.fSize.fHeight);
+ REPORTER_ASSERT(reporter, 0 == info5.fOffset.fX && 0 == info5.fOffset.fY);
+ REPORTER_ASSERT(reporter, info5.fOriginXform.isIdentity());
+ REPORTER_ASSERT(reporter, NULL == info5.fPaint);
+ REPORTER_ASSERT(reporter, info5.fIsNested && !info5.fHasNestedLayers); // is nested
+
+ REPORTER_ASSERT(reporter, info6.fValid);
+ REPORTER_ASSERT(reporter, NULL == info6.fPicture);
+ REPORTER_ASSERT(reporter, kWidth == info6.fSize.fWidth &&
+ kHeight == info6.fSize.fHeight);
+ REPORTER_ASSERT(reporter, 0 == info6.fOffset.fX && 0 == info6.fOffset.fY);
+ REPORTER_ASSERT(reporter, info6.fOriginXform.isIdentity());
+ REPORTER_ASSERT(reporter, info6.fPaint);
+ REPORTER_ASSERT(reporter, !info6.fIsNested &&
+ info6.fHasNestedLayers); // has a nested SL
+
+ REPORTER_ASSERT(reporter, info7.fValid);
+ REPORTER_ASSERT(reporter, child == info7.fPicture); // in a child picture
+ REPORTER_ASSERT(reporter, kWidth == info7.fSize.fWidth &&
+ kHeight == info7.fSize.fHeight);
+ REPORTER_ASSERT(reporter, 0 == info7.fOffset.fX && 0 == info7.fOffset.fY);
+ REPORTER_ASSERT(reporter, info7.fOriginXform.isIdentity());
+ REPORTER_ASSERT(reporter, NULL == info7.fPaint);
+ REPORTER_ASSERT(reporter, info7.fIsNested && !info7.fHasNestedLayers); // is nested
+ }
+ }
+}
+
+#endif
+
+static void test_has_text(skiatest::Reporter* reporter, bool useNewPath) {
+ SkPictureRecorder recorder;
+#define BEGIN_RECORDING useNewPath ? recorder.EXPERIMENTAL_beginRecording(100, 100) \
+ : recorder. DEPRECATED_beginRecording(100, 100)
+
+ SkCanvas* canvas = BEGIN_RECORDING;
+ {
+ canvas->drawRect(SkRect::MakeWH(20, 20), SkPaint());
+ }
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+ REPORTER_ASSERT(reporter, !picture->hasText());
+
+ SkPoint point = SkPoint::Make(10, 10);
+ canvas = BEGIN_RECORDING;
+ {
+ canvas->drawText("Q", 1, point.fX, point.fY, SkPaint());
+ }
+ picture.reset(recorder.endRecording());
+ REPORTER_ASSERT(reporter, picture->hasText());
+
+ canvas = BEGIN_RECORDING;
+ {
+ canvas->drawPosText("Q", 1, &point, SkPaint());
+ }
+ picture.reset(recorder.endRecording());
+ REPORTER_ASSERT(reporter, picture->hasText());
+
+ canvas = BEGIN_RECORDING;
+ {
+ canvas->drawPosTextH("Q", 1, &point.fX, point.fY, SkPaint());
+ }
+ picture.reset(recorder.endRecording());
+ REPORTER_ASSERT(reporter, picture->hasText());
+
+ canvas = BEGIN_RECORDING;
+ {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(50, 50);
+
+ canvas->drawTextOnPathHV("Q", 1, path, point.fX, point.fY, SkPaint());
+ }
+ picture.reset(recorder.endRecording());
+ REPORTER_ASSERT(reporter, picture->hasText());
+
+ canvas = BEGIN_RECORDING;
+ {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(50, 50);
+
+ canvas->drawTextOnPath("Q", 1, path, NULL, SkPaint());
+ }
+ picture.reset(recorder.endRecording());
+ REPORTER_ASSERT(reporter, picture->hasText());
+
+ // Nest the previous picture inside a new one.
+ // This doesn't work in the old backend.
+ if (useNewPath) {
+ canvas = BEGIN_RECORDING;
+ {
+ canvas->drawPicture(picture.get());
+ }
+ picture.reset(recorder.endRecording());
+ REPORTER_ASSERT(reporter, picture->hasText());
+ }
+#undef BEGIN_RECORDING
+}
+
+static void set_canvas_to_save_count_4(SkCanvas* canvas) {
+ canvas->restoreToCount(1);
+ canvas->save();
+ canvas->save();
+ canvas->save();
+}
+
+/**
+ * A canvas that records the number of saves, saveLayers and restores.
+ */
+class SaveCountingCanvas : public SkCanvas {
+public:
+ SaveCountingCanvas(int width, int height)
+ : INHERITED(width, height)
+ , fSaveCount(0)
+ , fSaveLayerCount(0)
+ , fRestoreCount(0){
+ }
+
+ virtual SaveLayerStrategy willSaveLayer(const SkRect* bounds, const SkPaint* paint,
+ SaveFlags flags) SK_OVERRIDE {
+ ++fSaveLayerCount;
+ return this->INHERITED::willSaveLayer(bounds, paint, flags);
+ }
+
+ virtual void willSave() SK_OVERRIDE {
+ ++fSaveCount;
+ this->INHERITED::willSave();
+ }
+
+ virtual void willRestore() SK_OVERRIDE {
+ ++fRestoreCount;
+ this->INHERITED::willRestore();
+ }
+
+ unsigned int getSaveCount() const { return fSaveCount; }
+ unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
+ unsigned int getRestoreCount() const { return fRestoreCount; }
+
+private:
+ unsigned int fSaveCount;
+ unsigned int fSaveLayerCount;
+ unsigned int fRestoreCount;
+
+ typedef SkCanvas INHERITED;
+};
+
+void check_save_state(skiatest::Reporter* reporter, SkPicture* picture,
+ unsigned int numSaves, unsigned int numSaveLayers,
+ unsigned int numRestores) {
+ SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()),
+ SkScalarCeilToInt(picture->cullRect().height()));
+
+ picture->playback(&canvas);
+
+ // Optimizations may have removed these,
+ // so expect to have seen no more than num{Saves,SaveLayers,Restores}.
+ REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount());
+ REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount());
+ REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount());
+}
+
+// This class exists so SkPicture can friend it and give it access to
+// the 'partialReplay' method.
+class SkPictureRecorderReplayTester {
+public:
+ static SkPicture* Copy(SkPictureRecorder* recorder) {
+ SkPictureRecorder recorder2;
+
+ SkCanvas* canvas = recorder2.beginRecording(10, 10);
+
+ recorder->partialReplay(canvas);
+
+ return recorder2.endRecording();
+ }
+};
+
+static void create_imbalance(SkCanvas* canvas) {
+ SkRect clipRect = SkRect::MakeWH(2, 2);
+ SkRect drawRect = SkRect::MakeWH(10, 10);
+ canvas->save();
+ canvas->clipRect(clipRect, SkRegion::kReplace_Op);
+ canvas->translate(1.0f, 1.0f);
+ SkPaint p;
+ p.setColor(SK_ColorGREEN);
+ canvas->drawRect(drawRect, p);
+ // no restore
+}
+
+// This tests that replaying a potentially unbalanced picture into a canvas
+// doesn't affect the canvas' save count or matrix/clip state.
+static void check_balance(skiatest::Reporter* reporter, SkPicture* picture) {
+ SkBitmap bm;
+ bm.allocN32Pixels(4, 3);
+ SkCanvas canvas(bm);
+
+ int beforeSaveCount = canvas.getSaveCount();
+
+ SkMatrix beforeMatrix = canvas.getTotalMatrix();
+
+ SkRect beforeClip;
+
+ canvas.getClipBounds(&beforeClip);
+
+ canvas.drawPicture(picture);
+
+ REPORTER_ASSERT(reporter, beforeSaveCount == canvas.getSaveCount());
+ REPORTER_ASSERT(reporter, beforeMatrix == canvas.getTotalMatrix());
+
+ SkRect afterClip;
+
+ canvas.getClipBounds(&afterClip);
+
+ REPORTER_ASSERT(reporter, afterClip == beforeClip);
+}
+
+// Test out SkPictureRecorder::partialReplay
+DEF_TEST(PictureRecorder_replay, reporter) {
+ // check save/saveLayer state
+ {
+ SkPictureRecorder recorder;
+
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+
+ canvas->saveLayer(NULL, NULL);
+
+ SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
+
+ // The extra save and restore comes from the Copy process.
+ check_save_state(reporter, copy, 2, 1, 3);
+
+ canvas->saveLayer(NULL, NULL);
+
+ SkAutoTUnref<SkPicture> final(recorder.endRecording());
+
+ check_save_state(reporter, final, 1, 2, 3);
+
+ // The copy shouldn't pick up any operations added after it was made
+ check_save_state(reporter, copy, 2, 1, 3);
+ }
+
+ // (partially) check leakage of draw ops
+ {
+ SkPictureRecorder recorder;
+
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+
+ SkRect r = SkRect::MakeWH(5, 5);
+ SkPaint p;
+
+ canvas->drawRect(r, p);
+
+ SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
+
+ REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
+
+ SkBitmap bm;
+ make_bm(&bm, 10, 10, SK_ColorRED, true);
+
+ r.offset(5.0f, 5.0f);
+ canvas->drawBitmapRectToRect(bm, NULL, r);
+
+ SkAutoTUnref<SkPicture> final(recorder.endRecording());
+ REPORTER_ASSERT(reporter, final->willPlayBackBitmaps());
+
+ REPORTER_ASSERT(reporter, copy->uniqueID() != final->uniqueID());
+
+ // The snapshot shouldn't pick up any operations added after it was made
+ REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
+ }
+
+ // Recreate the Android partialReplay test case
+ {
+ SkPictureRecorder recorder;
+
+ SkCanvas* canvas = recorder.beginRecording(4, 3, NULL, 0);
+ create_imbalance(canvas);
+
+ int expectedSaveCount = canvas->getSaveCount();
+
+ SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
+ check_balance(reporter, copy);
+
+ REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount());
+
+ // End the recording of source to test the picture finalization
+ // process isn't complicated by the partialReplay step
+ SkAutoTUnref<SkPicture> final(recorder.endRecording());
+ }
+}
+
+static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
+ SkCanvas testCanvas(100, 100);
+ set_canvas_to_save_count_4(&testCanvas);
+
+ REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
+
+ SkPaint paint;
+ SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
+
+ SkPictureRecorder recorder;
+
+ {
+ // Create picture with 2 unbalanced saves
+ SkCanvas* canvas = recorder.beginRecording(100, 100);
+ canvas->save();
+ canvas->translate(10, 10);
+ canvas->drawRect(rect, paint);
+ canvas->save();
+ canvas->translate(10, 10);
+ canvas->drawRect(rect, paint);
+ SkAutoTUnref<SkPicture> extraSavePicture(recorder.endRecording());
+
+ testCanvas.drawPicture(extraSavePicture);
+ REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
+ }
+
+ set_canvas_to_save_count_4(&testCanvas);
+
+ {
+ // Create picture with 2 unbalanced restores
+ SkCanvas* canvas = recorder.beginRecording(100, 100);
+ canvas->save();
+ canvas->translate(10, 10);
+ canvas->drawRect(rect, paint);
+ canvas->save();
+ canvas->translate(10, 10);
+ canvas->drawRect(rect, paint);
+ canvas->restore();
+ canvas->restore();
+ canvas->restore();
+ canvas->restore();
+ SkAutoTUnref<SkPicture> extraRestorePicture(recorder.endRecording());
+
+ testCanvas.drawPicture(extraRestorePicture);
+ REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
+ }
+
+ set_canvas_to_save_count_4(&testCanvas);
+
+ {
+ SkCanvas* canvas = recorder.beginRecording(100, 100);
+ canvas->translate(10, 10);
+ canvas->drawRect(rect, paint);
+ SkAutoTUnref<SkPicture> noSavePicture(recorder.endRecording());
+
+ testCanvas.drawPicture(noSavePicture);
+ REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
+ REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
+ }
+}
+
+static void test_peephole() {
+ SkRandom rand;
+
+ SkPictureRecorder recorder;
+
+ for (int j = 0; j < 100; j++) {
+ SkRandom rand2(rand); // remember the seed
+
+ SkCanvas* canvas = recorder.beginRecording(100, 100);
+
+ for (int i = 0; i < 1000; ++i) {
+ rand_op(canvas, rand);
+ }
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ rand = rand2;
+ }
+
+ {
+ SkCanvas* canvas = recorder.beginRecording(100, 100);
+ SkRect rect = SkRect::MakeWH(50, 50);
+
+ for (int i = 0; i < 100; ++i) {
+ canvas->save();
+ }
+ while (canvas->getSaveCount() > 1) {
+ canvas->clipRect(rect);
+ canvas->restore();
+ }
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+ }
+}
+
+#ifndef SK_DEBUG
+// Only test this is in release mode. We deliberately crash in debug mode, since a valid caller
+// should never do this.
+static void test_bad_bitmap() {
+ // This bitmap has a width and height but no pixels. As a result, attempting to record it will
+ // fail.
+ SkBitmap bm;
+ bm.setInfo(SkImageInfo::MakeN32Premul(100, 100));
+ SkPictureRecorder recorder;
+ SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
+ recordingCanvas->drawBitmap(bm, 0, 0);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ SkCanvas canvas;
+ canvas.drawPicture(picture);
+}
+#endif
+
+static SkData* encode_bitmap_to_data(size_t*, const SkBitmap& bm) {
+ return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100);
+}
+
+static SkData* serialized_picture_from_bitmap(const SkBitmap& bitmap) {
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bitmap.width()),
+ SkIntToScalar(bitmap.height()));
+ canvas->drawBitmap(bitmap, 0, 0);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ SkDynamicMemoryWStream wStream;
+ picture->serialize(&wStream, &encode_bitmap_to_data);
+ return wStream.copyToData();
+}
+
+struct ErrorContext {
+ int fErrors;
+ skiatest::Reporter* fReporter;
+};
+
+static void assert_one_parse_error_cb(SkError error, void* context) {
+ ErrorContext* errorContext = static_cast<ErrorContext*>(context);
+ errorContext->fErrors++;
+ // This test only expects one error, and that is a kParseError. If there are others,
+ // there is some unknown problem.
+ REPORTER_ASSERT_MESSAGE(errorContext->fReporter, 1 == errorContext->fErrors,
+ "This threw more errors than expected.");
+ REPORTER_ASSERT_MESSAGE(errorContext->fReporter, kParseError_SkError == error,
+ SkGetLastErrorString());
+}
+
+static void test_bitmap_with_encoded_data(skiatest::Reporter* reporter) {
+ // Create a bitmap that will be encoded.
+ SkBitmap original;
+ make_bm(&original, 100, 100, SK_ColorBLUE, true);
+ SkDynamicMemoryWStream wStream;
+ if (!SkImageEncoder::EncodeStream(&wStream, original, SkImageEncoder::kPNG_Type, 100)) {
+ return;
+ }
+ SkAutoDataUnref data(wStream.copyToData());
+
+ SkBitmap bm;
+ bool installSuccess = SkInstallDiscardablePixelRef(
+ SkDecodingImageGenerator::Create(data, SkDecodingImageGenerator::Options()), &bm);
+ REPORTER_ASSERT(reporter, installSuccess);
+
+ // Write both bitmaps to pictures, and ensure that the resulting data streams are the same.
+ // Flattening original will follow the old path of performing an encode, while flattening bm
+ // will use the already encoded data.
+ SkAutoDataUnref picture1(serialized_picture_from_bitmap(original));
+ SkAutoDataUnref picture2(serialized_picture_from_bitmap(bm));
+ REPORTER_ASSERT(reporter, picture1->equals(picture2));
+ // Now test that a parse error was generated when trying to create a new SkPicture without
+ // providing a function to decode the bitmap.
+ ErrorContext context;
+ context.fErrors = 0;
+ context.fReporter = reporter;
+ SkSetErrorCallback(assert_one_parse_error_cb, &context);
+ SkMemoryStream pictureStream(picture1);
+ SkClearLastError();
+ SkAutoUnref pictureFromStream(SkPicture::CreateFromStream(&pictureStream, NULL));
+ REPORTER_ASSERT(reporter, pictureFromStream.get() != NULL);
+ SkClearLastError();
+ SkSetErrorCallback(NULL, NULL);
+}
+
+static void test_draw_empty(skiatest::Reporter* reporter) {
+ SkBitmap result;
+ make_bm(&result, 2, 2, SK_ColorBLACK, false);
+
+ SkCanvas canvas(result);
+
+ {
+ // stock SkPicture
+ SkPictureRecorder recorder;
+ recorder.beginRecording(1, 1);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ canvas.drawPicture(picture);
+ }
+
+ {
+ // tile grid
+ SkTileGridFactory::TileGridInfo gridInfo;
+ gridInfo.fMargin.setEmpty();
+ gridInfo.fOffset.setZero();
+ gridInfo.fTileInterval.set(1, 1);
+
+ SkTileGridFactory factory(gridInfo);
+ SkPictureRecorder recorder;
+ recorder.beginRecording(1, 1, &factory);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ canvas.drawPicture(picture);
+ }
+
+ {
+ // RTree
+ SkRTreeFactory factory;
+ SkPictureRecorder recorder;
+ recorder.beginRecording(1, 1, &factory);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ canvas.drawPicture(picture);
+ }
+}
+
+static void test_clip_bound_opt(skiatest::Reporter* reporter) {
+ // Test for crbug.com/229011
+ SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
+ SkIntToScalar(2), SkIntToScalar(2));
+ SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
+ SkIntToScalar(1), SkIntToScalar(1));
+ SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
+ SkIntToScalar(1), SkIntToScalar(1));
+
+ SkPath invPath;
+ invPath.addOval(rect1);
+ invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
+ SkPath path;
+ path.addOval(rect2);
+ SkPath path2;
+ path2.addOval(rect3);
+ SkIRect clipBounds;
+ SkPictureRecorder recorder;
+
+ // Testing conservative-raster-clip that is enabled by PictureRecord
+ {
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+ canvas->clipPath(invPath, SkRegion::kIntersect_Op);
+ bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
+ REPORTER_ASSERT(reporter, true == nonEmpty);
+ REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
+ REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
+ REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
+ REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
+ }
+ {
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+ canvas->clipPath(path, SkRegion::kIntersect_Op);
+ canvas->clipPath(invPath, SkRegion::kIntersect_Op);
+ bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
+ REPORTER_ASSERT(reporter, true == nonEmpty);
+ REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
+ REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
+ REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
+ REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
+ }
+ {
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+ canvas->clipPath(path, SkRegion::kIntersect_Op);
+ canvas->clipPath(invPath, SkRegion::kUnion_Op);
+ bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
+ REPORTER_ASSERT(reporter, true == nonEmpty);
+ REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
+ REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
+ REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
+ REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
+ }
+ {
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+ canvas->clipPath(path, SkRegion::kDifference_Op);
+ bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
+ REPORTER_ASSERT(reporter, true == nonEmpty);
+ REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
+ REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
+ REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
+ REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
+ }
+ {
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+ canvas->clipPath(path, SkRegion::kReverseDifference_Op);
+ bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
+ // True clip is actually empty in this case, but the best
+ // determination we can make using only bounds as input is that the
+ // clip is included in the bounds of 'path'.
+ REPORTER_ASSERT(reporter, true == nonEmpty);
+ REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
+ REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
+ REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
+ REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
+ }
+ {
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+ canvas->clipPath(path, SkRegion::kIntersect_Op);
+ canvas->clipPath(path2, SkRegion::kXOR_Op);
+ bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
+ REPORTER_ASSERT(reporter, true == nonEmpty);
+ REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
+ REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
+ REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
+ REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
+ }
+}
+
+/**
+ * A canvas that records the number of clip commands.
+ */
+class ClipCountingCanvas : public SkCanvas {
+public:
+ ClipCountingCanvas(int width, int height)
+ : INHERITED(width, height)
+ , fClipCount(0){
+ }
+
+ virtual void onClipRect(const SkRect& r,
+ SkRegion::Op op,
+ ClipEdgeStyle edgeStyle) SK_OVERRIDE {
+ fClipCount += 1;
+ this->INHERITED::onClipRect(r, op, edgeStyle);
+ }
+
+ virtual void onClipRRect(const SkRRect& rrect,
+ SkRegion::Op op,
+ ClipEdgeStyle edgeStyle)SK_OVERRIDE {
+ fClipCount += 1;
+ this->INHERITED::onClipRRect(rrect, op, edgeStyle);
+ }
+
+ virtual void onClipPath(const SkPath& path,
+ SkRegion::Op op,
+ ClipEdgeStyle edgeStyle) SK_OVERRIDE {
+ fClipCount += 1;
+ this->INHERITED::onClipPath(path, op, edgeStyle);
+ }
+
+ virtual void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) SK_OVERRIDE {
+ fClipCount += 1;
+ this->INHERITED::onClipRegion(deviceRgn, op);
+ }
+
+ unsigned getClipCount() const { return fClipCount; }
+
+private:
+ unsigned fClipCount;
+
+ typedef SkCanvas INHERITED;
+};
+
+static void test_clip_expansion(skiatest::Reporter* reporter) {
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+
+ canvas->clipRect(SkRect::MakeEmpty(), SkRegion::kReplace_Op);
+ // The following expanding clip should not be skipped.
+ canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), SkRegion::kUnion_Op);
+ // Draw something so the optimizer doesn't just fold the world.
+ SkPaint p;
+ p.setColor(SK_ColorBLUE);
+ canvas->drawPaint(p);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ ClipCountingCanvas testCanvas(10, 10);
+ picture->playback(&testCanvas);
+
+ // Both clips should be present on playback.
+ REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
+}
+
+static void test_hierarchical(skiatest::Reporter* reporter) {
+ SkBitmap bm;
+ make_bm(&bm, 10, 10, SK_ColorRED, true);
+
+ SkPictureRecorder recorder;
+
+ recorder.beginRecording(10, 10);
+ SkAutoTUnref<SkPicture> childPlain(recorder.endRecording());
+ REPORTER_ASSERT(reporter, !childPlain->willPlayBackBitmaps()); // 0
+
+ recorder.beginRecording(10, 10)->drawBitmap(bm, 0, 0);
+ SkAutoTUnref<SkPicture> childWithBitmap(recorder.endRecording());
+ REPORTER_ASSERT(reporter, childWithBitmap->willPlayBackBitmaps()); // 1
+
+ {
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+ canvas->drawPicture(childPlain);
+ SkAutoTUnref<SkPicture> parentPP(recorder.endRecording());
+ REPORTER_ASSERT(reporter, !parentPP->willPlayBackBitmaps()); // 0
+ }
+ {
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+ canvas->drawPicture(childWithBitmap);
+ SkAutoTUnref<SkPicture> parentPWB(recorder.endRecording());
+ REPORTER_ASSERT(reporter, parentPWB->willPlayBackBitmaps()); // 1
+ }
+ {
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+ canvas->drawBitmap(bm, 0, 0);
+ canvas->drawPicture(childPlain);
+ SkAutoTUnref<SkPicture> parentWBP(recorder.endRecording());
+ REPORTER_ASSERT(reporter, parentWBP->willPlayBackBitmaps()); // 1
+ }
+ {
+ SkCanvas* canvas = recorder.beginRecording(10, 10);
+ canvas->drawBitmap(bm, 0, 0);
+ canvas->drawPicture(childWithBitmap);
+ SkAutoTUnref<SkPicture> parentWBWB(recorder.endRecording());
+ REPORTER_ASSERT(reporter, parentWBWB->willPlayBackBitmaps()); // 2
+ }
+}
+
+static void test_gen_id(skiatest::Reporter* reporter) {
+
+ SkPictureRecorder recorder;
+ recorder.beginRecording(0, 0);
+ SkAutoTUnref<SkPicture> empty(recorder.endRecording());
+
+ // Empty pictures should still have a valid ID
+ REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID);
+
+ SkCanvas* canvas = recorder.beginRecording(1, 1);
+ canvas->drawARGB(255, 255, 255, 255);
+ SkAutoTUnref<SkPicture> hasData(recorder.endRecording());
+ // picture should have a non-zero id after recording
+ REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
+
+ // both pictures should have different ids
+ REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
+}
+
+DEF_TEST(Picture, reporter) {
+#ifdef SK_DEBUG
+ test_deleting_empty_picture();
+ test_serializing_empty_picture();
+#else
+ test_bad_bitmap();
+#endif
+ test_unbalanced_save_restores(reporter);
+ test_peephole();
+#if SK_SUPPORT_GPU
+ test_gpu_veto(reporter, false);
+ test_gpu_veto(reporter, true);
+#endif
+ test_has_text(reporter, false);
+ test_has_text(reporter, true);
+ test_analysis(reporter, false);
+ test_analysis(reporter, true);
+ test_gatherpixelrefs(reporter);
+ test_gatherpixelrefsandrects(reporter);
+ test_bitmap_with_encoded_data(reporter);
+ test_draw_empty(reporter);
+ test_clip_bound_opt(reporter);
+ test_clip_expansion(reporter);
+ test_hierarchical(reporter);
+ test_gen_id(reporter);
+}
+
+#if SK_SUPPORT_GPU
+DEF_GPUTEST(GPUPicture, reporter, factory) {
+ test_gpu_picture_optimization(reporter, factory);
+}
+#endif
+
+static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
+ const SkPaint paint;
+ const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
+ const SkIRect irect = { 2, 2, 3, 3 };
+
+ // Don't care what these record, as long as they're legal.
+ canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
+ canvas->drawBitmapRectToRect(bitmap, &rect, rect, &paint, SkCanvas::kNone_DrawBitmapRectFlag);
+ canvas->drawBitmapMatrix(bitmap, SkMatrix::I(), &paint);
+ canvas->drawBitmapNine(bitmap, irect, rect, &paint);
+ canvas->drawSprite(bitmap, 1, 1);
+}
+
+static void test_draw_bitmaps(SkCanvas* canvas) {
+ SkBitmap empty;
+ draw_bitmaps(empty, canvas);
+ empty.setInfo(SkImageInfo::MakeN32Premul(10, 10));
+ draw_bitmaps(empty, canvas);
+}
+
+DEF_TEST(Picture_EmptyBitmap, r) {
+ SkPictureRecorder recorder;
+ test_draw_bitmaps(recorder.beginRecording(10, 10));
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+}
+
+DEF_TEST(Canvas_EmptyBitmap, r) {
+ SkBitmap dst;
+ dst.allocN32Pixels(10, 10);
+ SkCanvas canvas(dst);
+
+ test_draw_bitmaps(&canvas);
+}
+
+DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
+ // This test is from crbug.com/344987.
+ // The commands are:
+ // saveLayer with paint that modifies alpha
+ // drawBitmapRectToRect
+ // drawBitmapRectToRect
+ // restore
+ // The bug was that this structure was modified so that:
+ // - The saveLayer and restore were eliminated
+ // - The alpha was only applied to the first drawBitmapRectToRect
+
+ // This test draws blue and red squares inside a 50% transparent
+ // layer. Both colours should show up muted.
+ // When the bug is present, the red square (the second bitmap)
+ // shows upwith full opacity.
+
+ SkBitmap blueBM;
+ make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
+ SkBitmap redBM;
+ make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
+ SkPaint semiTransparent;
+ semiTransparent.setAlpha(0x80);
+
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(100, 100);
+ canvas->drawARGB(0, 0, 0, 0);
+
+ canvas->saveLayer(0, &semiTransparent);
+ canvas->drawBitmap(blueBM, 25, 25);
+ canvas->drawBitmap(redBM, 50, 50);
+ canvas->restore();
+
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ // Now replay the picture back on another canvas
+ // and check a couple of its pixels.
+ SkBitmap replayBM;
+ make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
+ SkCanvas replayCanvas(replayBM);
+ picture->playback(&replayCanvas);
+ replayCanvas.flush();
+
+ // With the bug present, at (55, 55) we would get a fully opaque red
+ // intead of a dark red.
+ REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
+ REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
+}
+
+struct CountingBBH : public SkBBoxHierarchy {
+ mutable int searchCalls;
+
+ CountingBBH() : searchCalls(0) {}
+
+ virtual void search(const SkRect& query, SkTDArray<void*>* results) const {
+ this->searchCalls++;
+ }
+
+ // All other methods unimplemented.
+ virtual void insert(void* data, const SkRect& bounds, bool defer) {}
+ virtual void flushDeferredInserts() {}
+ virtual void clear() {}
+ virtual int getCount() const { return 0; }
+ virtual int getDepth() const { return 0; }
+ virtual void rewindInserts() {}
+};
+
+class SpoonFedBBHFactory : public SkBBHFactory {
+public:
+ explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
+ virtual SkBBoxHierarchy* operator()(int width, int height) const {
+ return SkRef(fBBH);
+ }
+private:
+ SkBBoxHierarchy* fBBH;
+};
+
+// When the canvas clip covers the full picture, we don't need to call the BBH.
+DEF_TEST(Picture_SkipBBH, r) {
+ CountingBBH bbh;
+ SpoonFedBBHFactory factory(&bbh);
+
+ SkPictureRecorder recorder;
+ recorder.beginRecording(320, 240, &factory);
+ SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
+
+ SkCanvas big(640, 480), small(300, 200);
+
+ picture->playback(&big);
+ REPORTER_ASSERT(r, bbh.searchCalls == 0);
+
+ picture->playback(&small);
+ REPORTER_ASSERT(r, bbh.searchCalls == 1);
+}
+
+DEF_TEST(Picture_BitmapLeak, r) {
+ SkBitmap mut, immut;
+ mut.allocN32Pixels(300, 200);
+ immut.allocN32Pixels(300, 200);
+ immut.setImmutable();
+ SkASSERT(!mut.isImmutable());
+ SkASSERT(immut.isImmutable());
+
+ // No one can hold a ref on our pixels yet.
+ REPORTER_ASSERT(r, mut.pixelRef()->unique());
+ REPORTER_ASSERT(r, immut.pixelRef()->unique());
+
+ SkPictureRecorder rec;
+ SkCanvas* canvas = rec.beginRecording(1920, 1200);
+ canvas->drawBitmap(mut, 0, 0);
+ canvas->drawBitmap(immut, 800, 600);
+ SkAutoTDelete<const SkPicture> pic(rec.endRecording());
+
+ // The picture shares the immutable pixels but copies the mutable ones.
+ REPORTER_ASSERT(r, mut.pixelRef()->unique());
+ REPORTER_ASSERT(r, !immut.pixelRef()->unique());
+
+ // When the picture goes away, it's just our bitmaps holding the refs.
+ pic.reset(NULL);
+ REPORTER_ASSERT(r, mut.pixelRef()->unique());
+ REPORTER_ASSERT(r, immut.pixelRef()->unique());
+}
diff --git a/src/third_party/skia/tests/PipeTest.cpp b/src/third_party/skia/tests/PipeTest.cpp
new file mode 100644
index 0000000..00a1a3f
--- /dev/null
+++ b/src/third_party/skia/tests/PipeTest.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SamplePipeControllers.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkGPipe.h"
+#include "SkPaint.h"
+#include "SkShader.h"
+#include "Test.h"
+
+// Ensures that the pipe gracefully handles drawing an invalid bitmap.
+static void testDrawingBadBitmap(SkCanvas* pipeCanvas) {
+ SkBitmap badBitmap;
+ badBitmap.setInfo(SkImageInfo::MakeUnknown(5, 5));
+ pipeCanvas->drawBitmap(badBitmap, 0, 0);
+}
+
+// Ensure that pipe gracefully handles attempting to draw after endRecording is called on the
+// SkGPipeWriter.
+static void testDrawingAfterEndRecording(SkCanvas* canvas) {
+ PipeController pc(canvas);
+ SkGPipeWriter writer;
+ SkCanvas* pipeCanvas = writer.startRecording(&pc, SkGPipeWriter::kCrossProcess_Flag);
+ writer.endRecording();
+
+ SkBitmap bm;
+ bm.allocN32Pixels(2, 2);
+ bm.eraseColor(SK_ColorTRANSPARENT);
+
+ SkShader* shader = SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+ SkPaint paint;
+ paint.setShader(shader)->unref();
+ pipeCanvas->drawPaint(paint);
+
+ pipeCanvas->drawBitmap(bm, 0, 0);
+}
+
+DEF_TEST(Pipe, reporter) {
+ SkBitmap bitmap;
+ bitmap.setInfo(SkImageInfo::MakeN32Premul(64, 64));
+ SkCanvas canvas(bitmap);
+
+ PipeController pipeController(&canvas);
+ SkGPipeWriter writer;
+ SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
+ testDrawingBadBitmap(pipeCanvas);
+ writer.endRecording();
+
+ testDrawingAfterEndRecording(&canvas);
+}
diff --git a/src/third_party/skia/tests/PixelRefTest.cpp b/src/third_party/skia/tests/PixelRefTest.cpp
new file mode 100644
index 0000000..d1d3026
--- /dev/null
+++ b/src/third_party/skia/tests/PixelRefTest.cpp
@@ -0,0 +1,46 @@
+#include "Test.h"
+
+#include "SkMallocPixelRef.h"
+#include "SkPixelRef.h"
+
+class TestListener : public SkPixelRef::GenIDChangeListener {
+public:
+ explicit TestListener(int* ptr) : fPtr(ptr) {}
+ virtual void onChange() SK_OVERRIDE { (*fPtr)++; }
+private:
+ int* fPtr;
+};
+
+DEF_TEST(PixelRef_GenIDChange, r) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
+
+ SkAutoTUnref<SkPixelRef> pixelRef(SkMallocPixelRef::NewAllocate(info, 0, NULL));
+
+ // Register a listener.
+ int count = 0;
+ pixelRef->addGenIDChangeListener(SkNEW_ARGS(TestListener, (&count)));
+ REPORTER_ASSERT(r, 0 == count);
+
+ // No one has looked at our pixelRef's generation ID, so invalidating it doesn't make sense.
+ // (An SkPixelRef tree falls in the forest but there's nobody around to hear it. Do we care?)
+ pixelRef->notifyPixelsChanged();
+ REPORTER_ASSERT(r, 0 == count);
+
+ // Force the generation ID to be calculated.
+ REPORTER_ASSERT(r, 0 != pixelRef->getGenerationID());
+
+ // Our listener was dropped in the first call to notifyPixelsChanged(). This is a no-op.
+ pixelRef->notifyPixelsChanged();
+ REPORTER_ASSERT(r, 0 == count);
+
+ // Force the generation ID to be recalculated, then add a listener.
+ REPORTER_ASSERT(r, 0 != pixelRef->getGenerationID());
+ pixelRef->addGenIDChangeListener(SkNEW_ARGS(TestListener, (&count)));
+ pixelRef->notifyPixelsChanged();
+ REPORTER_ASSERT(r, 1 == count);
+
+ // Quick check that NULL is safe.
+ REPORTER_ASSERT(r, 0 != pixelRef->getGenerationID());
+ pixelRef->addGenIDChangeListener(NULL);
+ pixelRef->notifyPixelsChanged();
+}
diff --git a/src/third_party/skia/tests/PointTest.cpp b/src/third_party/skia/tests/PointTest.cpp
new file mode 100644
index 0000000..fed443a
--- /dev/null
+++ b/src/third_party/skia/tests/PointTest.cpp
@@ -0,0 +1,158 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+// Unit tests for src/core/SkPoint.cpp and its header
+
+#include "SkPoint.h"
+#include "SkRect.h"
+#include "Test.h"
+
+static void test_casts(skiatest::Reporter* reporter) {
+ SkPoint p = { 0, 0 };
+ SkRect r = { 0, 0, 0, 0 };
+
+ const SkScalar* pPtr = SkTCast<const SkScalar*>(&p);
+ const SkScalar* rPtr = SkTCast<const SkScalar*>(&r);
+
+ REPORTER_ASSERT(reporter, p.asScalars() == pPtr);
+ REPORTER_ASSERT(reporter, r.asScalars() == rPtr);
+}
+
+// Tests SkPoint::Normalize() for this (x,y)
+static void test_Normalize(skiatest::Reporter* reporter,
+ SkScalar x, SkScalar y) {
+ SkPoint point;
+ point.set(x, y);
+ SkScalar oldLength = point.length();
+ SkScalar returned = SkPoint::Normalize(&point);
+ SkScalar newLength = point.length();
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(returned, oldLength));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(newLength, SK_Scalar1));
+}
+
+// Tests that SkPoint::length() and SkPoint::Length() both return
+// approximately expectedLength for this (x,y).
+static void test_length(skiatest::Reporter* reporter, SkScalar x, SkScalar y,
+ SkScalar expectedLength) {
+ SkPoint point;
+ point.set(x, y);
+ SkScalar s1 = point.length();
+ SkScalar s2 = SkPoint::Length(x, y);
+ //The following should be exactly the same, but need not be.
+ //See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(s1, s2));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(s1, expectedLength));
+
+ test_Normalize(reporter, x, y);
+}
+
+// Ugh. Windows compiler can dive into other .cpp files, and sometimes
+// notices that I will generate an overflow... which is exactly the point
+// of this test!
+//
+// To avoid this warning, I need to convince the compiler that I might not
+// use that big value, hence this hacky helper function: reporter is
+// ALWAYS non-null. (shhhhhh, don't tell the compiler that).
+template <typename T> T get_value(skiatest::Reporter* reporter, T value) {
+ return reporter ? value : 0;
+}
+
+// On linux gcc, 32bit, we are seeing the compiler propagate up the value
+// of SkPoint::length() as a double (which we use sometimes to avoid overflow
+// during the computation), even though the signature says float (SkScalar).
+//
+// force_as_float is meant to capture our latest technique (horrible as
+// it is) to force the value to be a float, so we can test whether it was
+// finite or not.
+static float force_as_float(skiatest::Reporter* reporter, float value) {
+ uint32_t storage;
+ memcpy(&storage, &value, 4);
+ // even the pair of memcpy calls are not sufficient, since those seem to
+ // be no-op'd, so we add a runtime tests (just like get_value) to force
+ // the compiler to give us an actual float.
+ if (NULL == reporter) {
+ storage = ~storage;
+ }
+ memcpy(&value, &storage, 4);
+ return value;
+}
+
+// test that we handle very large values correctly. i.e. that we can
+// successfully normalize something whose mag overflows a float.
+static void test_overflow(skiatest::Reporter* reporter) {
+ SkScalar bigFloat = get_value(reporter, 3.4e38f);
+ SkPoint pt = { bigFloat, bigFloat };
+
+ SkScalar length = pt.length();
+ length = force_as_float(reporter, length);
+
+ // expect this to be non-finite, but dump the results if not.
+ if (SkScalarIsFinite(length)) {
+ SkDebugf("length(%g, %g) == %g\n", pt.fX, pt.fY, length);
+ REPORTER_ASSERT(reporter, !SkScalarIsFinite(length));
+ }
+
+ // this should succeed, even though we can't represent length
+ REPORTER_ASSERT(reporter, pt.setLength(SK_Scalar1));
+
+ // now that pt is normalized, we check its length
+ length = pt.length();
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(length, SK_Scalar1));
+}
+
+// test that we handle very small values correctly. i.e. that we can
+// report failure if we try to normalize them.
+static void test_underflow(skiatest::Reporter* reporter) {
+ SkPoint pt = { 1.0e-37f, 1.0e-37f };
+ SkPoint copy = pt;
+
+ REPORTER_ASSERT(reporter, 0 == SkPoint::Normalize(&pt));
+ REPORTER_ASSERT(reporter, pt == copy); // pt is unchanged
+
+ REPORTER_ASSERT(reporter, !pt.setLength(SK_Scalar1));
+ REPORTER_ASSERT(reporter, pt == copy); // pt is unchanged
+}
+
+DEF_TEST(Point, reporter) {
+ test_casts(reporter);
+
+ static const struct {
+ SkScalar fX;
+ SkScalar fY;
+ SkScalar fLength;
+ } gRec[] = {
+ { SkIntToScalar(3), SkIntToScalar(4), SkIntToScalar(5) },
+ { 0.6f, 0.8f, SK_Scalar1 },
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
+ test_length(reporter, gRec[i].fX, gRec[i].fY, gRec[i].fLength);
+ }
+
+ test_underflow(reporter);
+ test_overflow(reporter);
+}
+
+DEF_TEST(Point_setLengthFast, reporter) {
+ // Scale a (1,1) point to a bunch of different lengths,
+ // making sure the slow and fast paths are within 0.1%.
+ const float tests[] = { 1.0f, 0.0f, 1.0e-37f, 3.4e38f, 42.0f, 0.00012f };
+
+ const SkPoint kOne = {1.0f, 1.0f};
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); i++) {
+ SkPoint slow = kOne, fast = kOne;
+
+ slow.setLength(tests[i]);
+ fast.setLengthFast(tests[i]);
+
+ if (slow.length() < FLT_MIN && fast.length() < FLT_MIN) continue;
+
+ SkScalar ratio = slow.length() / fast.length();
+ REPORTER_ASSERT(reporter, ratio > 0.999f);
+ REPORTER_ASSERT(reporter, ratio < 1.001f);
+ }
+}
diff --git a/src/third_party/skia/tests/PremulAlphaRoundTripTest.cpp b/src/third_party/skia/tests/PremulAlphaRoundTripTest.cpp
new file mode 100644
index 0000000..ce45f16
--- /dev/null
+++ b/src/third_party/skia/tests/PremulAlphaRoundTripTest.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmapDevice.h"
+#include "SkCanvas.h"
+#include "SkConfig8888.h"
+#include "Test.h"
+#include "sk_tool_utils.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#include "SkGpuDevice.h"
+#endif
+
+static uint32_t pack_unpremul_rgba(SkColor c) {
+ uint32_t packed;
+ uint8_t* byte = reinterpret_cast<uint8_t*>(&packed);
+ byte[0] = SkColorGetR(c);
+ byte[1] = SkColorGetG(c);
+ byte[2] = SkColorGetB(c);
+ byte[3] = SkColorGetA(c);
+ return packed;
+}
+
+static uint32_t pack_unpremul_bgra(SkColor c) {
+ uint32_t packed;
+ uint8_t* byte = reinterpret_cast<uint8_t*>(&packed);
+ byte[0] = SkColorGetB(c);
+ byte[1] = SkColorGetG(c);
+ byte[2] = SkColorGetR(c);
+ byte[3] = SkColorGetA(c);
+ return packed;
+}
+
+typedef uint32_t (*PackUnpremulProc)(SkColor);
+
+const struct {
+ SkColorType fColorType;
+ PackUnpremulProc fPackProc;
+} gUnpremul[] = {
+ { kRGBA_8888_SkColorType, pack_unpremul_rgba },
+ { kBGRA_8888_SkColorType, pack_unpremul_bgra },
+};
+
+static void fillCanvas(SkCanvas* canvas, SkColorType colorType, PackUnpremulProc proc) {
+ // Don't strictly need a bitmap, but its a handy way to allocate the pixels
+ SkBitmap bmp;
+ bmp.allocN32Pixels(256, 256);
+
+ for (int a = 0; a < 256; ++a) {
+ uint32_t* pixels = bmp.getAddr32(0, a);
+ for (int r = 0; r < 256; ++r) {
+ pixels[r] = proc(SkColorSetARGB(a, r, 0, 0));
+ }
+ }
+
+ const SkImageInfo info = SkImageInfo::Make(bmp.width(), bmp.height(),
+ colorType, kUnpremul_SkAlphaType);
+ canvas->writePixels(info, bmp.getPixels(), bmp.rowBytes(), 0, 0);
+}
+
+DEF_GPUTEST(PremulAlphaRoundTrip, reporter, factory) {
+ const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
+
+ for (int dtype = 0; dtype < 2; ++dtype) {
+
+ int glCtxTypeCnt = 1;
+#if SK_SUPPORT_GPU
+ if (0 != dtype) {
+ glCtxTypeCnt = GrContextFactory::kGLContextTypeCnt;
+ }
+#endif
+ for (int glCtxType = 0; glCtxType < glCtxTypeCnt; ++glCtxType) {
+ SkAutoTUnref<SkBaseDevice> device;
+ if (0 == dtype) {
+ device.reset(SkBitmapDevice::Create(info));
+ } else {
+#if SK_SUPPORT_GPU
+ GrContextFactory::GLContextType type =
+ static_cast<GrContextFactory::GLContextType>(glCtxType);
+ if (!GrContextFactory::IsRenderingGLContext(type)) {
+ continue;
+ }
+ GrContext* context = factory->get(type);
+ if (NULL == context) {
+ continue;
+ }
+
+ device.reset(SkGpuDevice::Create(context, info,
+ SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType), 0));
+#else
+ continue;
+#endif
+ }
+ SkCanvas canvas(device);
+
+ for (size_t upmaIdx = 0; upmaIdx < SK_ARRAY_COUNT(gUnpremul); ++upmaIdx) {
+ fillCanvas(&canvas, gUnpremul[upmaIdx].fColorType, gUnpremul[upmaIdx].fPackProc);
+
+ const SkImageInfo info = SkImageInfo::Make(256, 256, gUnpremul[upmaIdx].fColorType,
+ kUnpremul_SkAlphaType);
+ SkBitmap readBmp1;
+ readBmp1.allocPixels(info);
+ SkBitmap readBmp2;
+ readBmp2.allocPixels(info);
+
+ readBmp1.eraseColor(0);
+ readBmp2.eraseColor(0);
+
+ canvas.readPixels(&readBmp1, 0, 0);
+ sk_tool_utils::write_pixels(&canvas, readBmp1, 0, 0, gUnpremul[upmaIdx].fColorType,
+ kUnpremul_SkAlphaType);
+ canvas.readPixels(&readBmp2, 0, 0);
+
+ bool success = true;
+ for (int y = 0; y < 256 && success; ++y) {
+ const uint32_t* pixels1 = readBmp1.getAddr32(0, y);
+ const uint32_t* pixels2 = readBmp2.getAddr32(0, y);
+ for (int x = 0; x < 256 && success; ++x) {
+ // We see sporadic failures here. May help to see where it goes wrong.
+ if (pixels1[x] != pixels2[x]) {
+ SkDebugf("%x != %x, x = %d, y = %d\n", pixels1[x], pixels2[x], x, y);
+ }
+ REPORTER_ASSERT(reporter, success = pixels1[x] == pixels2[x]);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/QuickRejectTest.cpp b/src/third_party/skia/tests/QuickRejectTest.cpp
new file mode 100644
index 0000000..8f4357e
--- /dev/null
+++ b/src/third_party/skia/tests/QuickRejectTest.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkDrawLooper.h"
+#include "SkTypes.h"
+#include "Test.h"
+
+/*
+ * Subclass of looper that just draws once, with an offset in X.
+ */
+class TestLooper : public SkDrawLooper {
+public:
+
+ virtual SkDrawLooper::Context* createContext(SkCanvas*, void* storage) const SK_OVERRIDE {
+ return SkNEW_PLACEMENT(storage, TestDrawLooperContext);
+ }
+
+ virtual size_t contextSize() const SK_OVERRIDE { return sizeof(TestDrawLooperContext); }
+
+#ifndef SK_IGNORE_TO_STRING
+ virtual void toString(SkString* str) const SK_OVERRIDE {
+ str->append("TestLooper:");
+ }
+#endif
+
+private:
+ class TestDrawLooperContext : public SkDrawLooper::Context {
+ public:
+ TestDrawLooperContext() : fOnce(true) {}
+ virtual ~TestDrawLooperContext() {}
+
+ virtual bool next(SkCanvas* canvas, SkPaint*) SK_OVERRIDE {
+ if (fOnce) {
+ fOnce = false;
+ canvas->translate(SkIntToScalar(10), 0);
+ return true;
+ }
+ return false;
+ }
+ private:
+ bool fOnce;
+ };
+
+ SK_DECLARE_UNFLATTENABLE_OBJECT()
+};
+
+static void test_drawBitmap(skiatest::Reporter* reporter) {
+ SkBitmap src;
+ src.allocN32Pixels(10, 10);
+ src.eraseColor(SK_ColorWHITE);
+
+ SkBitmap dst;
+ dst.allocN32Pixels(10, 10);
+ dst.eraseColor(SK_ColorTRANSPARENT);
+
+ SkCanvas canvas(dst);
+ SkPaint paint;
+
+ // we are initially transparent
+ REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
+
+ // we see the bitmap drawn
+ canvas.drawBitmap(src, 0, 0, &paint);
+ REPORTER_ASSERT(reporter, 0xFFFFFFFF == *dst.getAddr32(5, 5));
+
+ // reverify we are clear again
+ dst.eraseColor(SK_ColorTRANSPARENT);
+ REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
+
+ // if the bitmap is clipped out, we don't draw it
+ canvas.drawBitmap(src, SkIntToScalar(-10), 0, &paint);
+ REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
+
+ // now install our looper, which will draw, since it internally translates
+ // to the left. The test is to ensure that canvas' quickReject machinary
+ // allows us through, even though sans-looper we would look like we should
+ // be clipped out.
+ paint.setLooper(new TestLooper)->unref();
+ canvas.drawBitmap(src, SkIntToScalar(-10), 0, &paint);
+ REPORTER_ASSERT(reporter, 0xFFFFFFFF == *dst.getAddr32(5, 5));
+}
+
+DEF_TEST(QuickReject, reporter) {
+ test_drawBitmap(reporter);
+}
diff --git a/src/third_party/skia/tests/RTConfRegistryTest.cpp b/src/third_party/skia/tests/RTConfRegistryTest.cpp
new file mode 100644
index 0000000..59fb3e9
--- /dev/null
+++ b/src/third_party/skia/tests/RTConfRegistryTest.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRTConf.h"
+#include "Test.h"
+
+// Friended proxy for SkRTConfRegistry::parse()
+template <typename T>
+bool test_rt_conf_parse(SkRTConfRegistry* reg, const char* key, T* value) {
+ return reg->parse(key, value);
+}
+
+static void portable_setenv(const char* key, const char* value) {
+#ifdef SK_BUILD_FOR_WIN32
+ _putenv_s(key, value);
+#else
+ setenv(key, value, 1);
+#endif
+}
+
+DEF_TEST(SkRTConfRegistry, reporter) {
+ SkRTConfRegistry reg;
+
+ portable_setenv("skia_nonexistent_item", "132");
+ int result = 0;
+ test_rt_conf_parse(®, "nonexistent.item", &result);
+ REPORTER_ASSERT(reporter, result == 132);
+}
diff --git a/src/third_party/skia/tests/RTreeTest.cpp b/src/third_party/skia/tests/RTreeTest.cpp
new file mode 100644
index 0000000..40af5fe
--- /dev/null
+++ b/src/third_party/skia/tests/RTreeTest.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRTree.h"
+#include "SkRandom.h"
+#include "SkTSort.h"
+#include "Test.h"
+
+static const size_t MIN_CHILDREN = 6;
+static const size_t MAX_CHILDREN = 11;
+
+static const int NUM_RECTS = 200;
+static const size_t NUM_ITERATIONS = 100;
+static const size_t NUM_QUERIES = 50;
+
+struct DataRect {
+ SkRect rect;
+ void* data;
+};
+
+static SkRect random_rect(SkRandom& rand) {
+ SkRect rect = {0,0,0,0};
+ while (rect.isEmpty()) {
+ rect.fLeft = rand.nextRangeF(0, 1000);
+ rect.fRight = rand.nextRangeF(0, 1000);
+ rect.fTop = rand.nextRangeF(0, 1000);
+ rect.fBottom = rand.nextRangeF(0, 1000);
+ rect.sort();
+ }
+ return rect;
+}
+
+static void random_data_rects(SkRandom& rand, DataRect out[], int n) {
+ for (int i = 0; i < n; ++i) {
+ out[i].rect = random_rect(rand);
+ out[i].data = reinterpret_cast<void*>(i);
+ }
+}
+
+static bool verify_query(SkRect query, DataRect rects[],
+ SkTDArray<void*>& found) {
+ // TODO(mtklein): no need to do this after everything's SkRects
+ query.roundOut();
+
+ SkTDArray<void*> expected;
+
+ // manually intersect with every rectangle
+ for (int i = 0; i < NUM_RECTS; ++i) {
+ if (SkRect::Intersects(query, rects[i].rect)) {
+ expected.push(rects[i].data);
+ }
+ }
+
+ if (expected.count() != found.count()) {
+ return false;
+ }
+
+ if (0 == expected.count()) {
+ return true;
+ }
+
+ // Just cast to long since sorting by the value of the void*'s was being problematic...
+ SkTQSort(reinterpret_cast<long*>(expected.begin()),
+ reinterpret_cast<long*>(expected.end() - 1));
+ SkTQSort(reinterpret_cast<long*>(found.begin()),
+ reinterpret_cast<long*>(found.end() - 1));
+ return found == expected;
+}
+
+static void run_queries(skiatest::Reporter* reporter, SkRandom& rand, DataRect rects[],
+ SkRTree& tree) {
+ for (size_t i = 0; i < NUM_QUERIES; ++i) {
+ SkTDArray<void*> hits;
+ SkRect query = random_rect(rand);
+ tree.search(query, &hits);
+ REPORTER_ASSERT(reporter, verify_query(query, rects, hits));
+ }
+}
+
+static void rtree_test_main(SkRTree* rtree, skiatest::Reporter* reporter) {
+ DataRect rects[NUM_RECTS];
+ SkRandom rand;
+ REPORTER_ASSERT(reporter, rtree);
+
+ int expectedDepthMin = -1;
+ int expectedDepthMax = -1;
+
+ int tmp = NUM_RECTS;
+ while (tmp > 0) {
+ tmp -= static_cast<int>(pow(static_cast<double>(MAX_CHILDREN),
+ static_cast<double>(expectedDepthMin + 1)));
+ ++expectedDepthMin;
+ }
+
+ tmp = NUM_RECTS;
+ while (tmp > 0) {
+ tmp -= static_cast<int>(pow(static_cast<double>(MIN_CHILDREN),
+ static_cast<double>(expectedDepthMax + 1)));
+ ++expectedDepthMax;
+ }
+
+ for (size_t i = 0; i < NUM_ITERATIONS; ++i) {
+ random_data_rects(rand, rects, NUM_RECTS);
+
+ // First try bulk-loaded inserts
+ for (int i = 0; i < NUM_RECTS; ++i) {
+ rtree->insert(rects[i].data, rects[i].rect, true);
+ }
+ rtree->flushDeferredInserts();
+ run_queries(reporter, rand, rects, *rtree);
+ REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
+ REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
+ expectedDepthMax >= rtree->getDepth());
+ rtree->clear();
+ REPORTER_ASSERT(reporter, 0 == rtree->getCount());
+
+ // Then try immediate inserts
+ for (int i = 0; i < NUM_RECTS; ++i) {
+ rtree->insert(rects[i].data, rects[i].rect);
+ }
+ run_queries(reporter, rand, rects, *rtree);
+ REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
+ REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
+ expectedDepthMax >= rtree->getDepth());
+ rtree->clear();
+ REPORTER_ASSERT(reporter, 0 == rtree->getCount());
+
+ // And for good measure try immediate inserts, but in reversed order
+ for (int i = NUM_RECTS - 1; i >= 0; --i) {
+ rtree->insert(rects[i].data, rects[i].rect);
+ }
+ run_queries(reporter, rand, rects, *rtree);
+ REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
+ REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
+ expectedDepthMax >= rtree->getDepth());
+ rtree->clear();
+ REPORTER_ASSERT(reporter, 0 == rtree->getCount());
+ }
+}
+
+DEF_TEST(RTree, reporter) {
+ SkRTree* rtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN);
+ SkAutoUnref au(rtree);
+ rtree_test_main(rtree, reporter);
+
+ // Rtree that orders input rectangles on deferred insert.
+ SkRTree* unsortedRtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN, 1, false);
+ SkAutoUnref auo(unsortedRtree);
+ rtree_test_main(unsortedRtree, reporter);
+}
diff --git a/src/third_party/skia/tests/RandomTest.cpp b/src/third_party/skia/tests/RandomTest.cpp
new file mode 100644
index 0000000..8d93d87
--- /dev/null
+++ b/src/third_party/skia/tests/RandomTest.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRandom.h"
+#include "SkTSort.h"
+#include "Test.h"
+
+static bool anderson_darling_test(double p[32]) {
+ // Min and max Anderson-Darling values allowable for k=32
+ const double kADMin32 = 0.202; // p-value of ~0.1
+ const double kADMax32 = 3.89; // p-value of ~0.99
+
+ // sort p values
+ SkTQSort<double>(p, p + 31);
+
+ // and compute Anderson-Darling statistic to ensure these are uniform
+ double s = 0.0;
+ for(int k = 0; k < 32; k++) {
+ double v = p[k]*(1.0 - p[31-k]);
+ if (v < 1.0e-30) {
+ v = 1.0e-30;
+ }
+ s += (2.0*(k+1)-1.0)*log(v);
+ }
+ double a2 = -32.0 - 0.03125*s;
+
+ return (kADMin32 < a2 && a2 < kADMax32);
+}
+
+static bool chi_square_test(int bins[256], int e) {
+ // Min and max chisquare values allowable
+ const double kChiSqMin256 = 206.3179; // probability of chance = 0.99 with k=256
+ const double kChiSqMax256 = 311.5603; // probability of chance = 0.01 with k=256
+
+ // compute chi-square
+ double chi2 = 0.0;
+ for (int j = 0; j < 256; ++j) {
+ double delta = bins[j] - e;
+ chi2 += delta*delta/e;
+ }
+
+ return (kChiSqMin256 < chi2 && chi2 < kChiSqMax256);
+}
+
+// Approximation to the normal distribution CDF
+// From Waissi and Rossin, 1996
+static double normal_cdf(double z) {
+ double t = ((-0.0004406*z*z* + 0.0418198)*z*z + 0.9)*z;
+ t *= -1.77245385091; // -sqrt(PI)
+ double p = 1.0/(1.0 + exp(t));
+
+ return p;
+}
+
+static void test_random_byte(skiatest::Reporter* reporter, int shift) {
+ int bins[256];
+ memset(bins, 0, sizeof(int)*256);
+
+ SkRandom rand;
+ for (int i = 0; i < 256*10000; ++i) {
+ bins[(rand.nextU() >> shift) & 0xff]++;
+ }
+
+ REPORTER_ASSERT(reporter, chi_square_test(bins, 10000));
+}
+
+static void test_random_float(skiatest::Reporter* reporter) {
+ int bins[256];
+ memset(bins, 0, sizeof(int)*256);
+
+ SkRandom rand;
+ for (int i = 0; i < 256*10000; ++i) {
+ float f = rand.nextF();
+ REPORTER_ASSERT(reporter, 0.0f <= f && f < 1.0f);
+ bins[(int)(f*256.f)]++;
+ }
+ REPORTER_ASSERT(reporter, chi_square_test(bins, 10000));
+
+ double p[32];
+ for (int j = 0; j < 32; ++j) {
+ float f = rand.nextF();
+ REPORTER_ASSERT(reporter, 0.0f <= f && f < 1.0f);
+ p[j] = f;
+ }
+ REPORTER_ASSERT(reporter, anderson_darling_test(p));
+}
+
+// This is a test taken from tuftests by Marsaglia and Tsang. The idea here is that
+// we are using the random bit generated from a single shift position to generate
+// "strings" of 16 bits in length, shifting the string and adding a new bit with each
+// iteration. We track the numbers generated. The ones that we don't generate will
+// have a normal distribution with mean ~24108 and standard deviation ~127. By
+// creating a z-score (# of deviations from the mean) for one iteration of this step
+// we can determine its probability.
+//
+// The original test used 26 bit strings, but is somewhat slow. This version uses 16
+// bits which is less rigorous but much faster to generate.
+static double test_single_gorilla(skiatest::Reporter* reporter, int shift) {
+ const int kWordWidth = 16;
+ const double kMean = 24108.0;
+ const double kStandardDeviation = 127.0;
+ const int kN = (1 << kWordWidth);
+ const int kNumEntries = kN >> 5; // dividing by 32
+ unsigned int entries[kNumEntries];
+
+ SkRandom rand;
+ memset(entries, 0, sizeof(unsigned int)*kNumEntries);
+ // pre-seed our string value
+ int value = 0;
+ for (int i = 0; i < kWordWidth-1; ++i) {
+ value <<= 1;
+ unsigned int rnd = rand.nextU();
+ value |= ((rnd >> shift) & 0x1);
+ }
+
+ // now make some strings and track them
+ for (int i = 0; i < kN; ++i) {
+ value <<= 1;
+ unsigned int rnd = rand.nextU();
+ value |= ((rnd >> shift) & 0x1);
+
+ int index = value & (kNumEntries-1);
+ SkASSERT(index < kNumEntries);
+ int entry_shift = (value >> (kWordWidth-5)) & 0x1f;
+ entries[index] |= (0x1 << entry_shift);
+ }
+
+ // count entries
+ int total = 0;
+ for (int i = 0; i < kNumEntries; ++i) {
+ unsigned int entry = entries[i];
+ while (entry) {
+ total += (entry & 0x1);
+ entry >>= 1;
+ }
+ }
+
+ // convert counts to normal distribution z-score
+ double z = ((kN-total)-kMean)/kStandardDeviation;
+
+ // compute probability from normal distibution CDF
+ double p = normal_cdf(z);
+
+ REPORTER_ASSERT(reporter, 0.01 < p && p < 0.99);
+ return p;
+}
+
+static void test_gorilla(skiatest::Reporter* reporter) {
+
+ double p[32];
+ for (int bit_position = 0; bit_position < 32; ++bit_position) {
+ p[bit_position] = test_single_gorilla(reporter, bit_position);
+ }
+
+ REPORTER_ASSERT(reporter, anderson_darling_test(p));
+}
+
+static void test_range(skiatest::Reporter* reporter) {
+ SkRandom rand;
+
+ // just to make sure we don't crash in this case
+ (void) rand.nextRangeU(0, 0xffffffff);
+
+ // check a case to see if it's uniform
+ int bins[256];
+ memset(bins, 0, sizeof(int)*256);
+ for (int i = 0; i < 256*10000; ++i) {
+ unsigned int u = rand.nextRangeU(17, 17+255);
+ REPORTER_ASSERT(reporter, 17 <= u && u <= 17+255);
+ bins[u - 17]++;
+ }
+
+ REPORTER_ASSERT(reporter, chi_square_test(bins, 10000));
+}
+
+DEF_TEST(Random, reporter) {
+ // check uniform distributions of each byte in 32-bit word
+ test_random_byte(reporter, 0);
+ test_random_byte(reporter, 8);
+ test_random_byte(reporter, 16);
+ test_random_byte(reporter, 24);
+
+ test_random_float(reporter);
+
+ test_gorilla(reporter);
+
+ test_range(reporter);
+}
diff --git a/src/third_party/skia/tests/ReadPixelsTest.cpp b/src/third_party/skia/tests/ReadPixelsTest.cpp
new file mode 100644
index 0000000..77aac1f
--- /dev/null
+++ b/src/third_party/skia/tests/ReadPixelsTest.cpp
@@ -0,0 +1,393 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmapDevice.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkMathPriv.h"
+#include "SkRegion.h"
+#include "SkSurface.h"
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#include "SkGpuDevice.h"
+#endif
+
+static const int DEV_W = 100, DEV_H = 100;
+static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
+static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1,
+ DEV_H * SK_Scalar1);
+
+static SkPMColor getCanvasColor(int x, int y) {
+ SkASSERT(x >= 0 && x < DEV_W);
+ SkASSERT(y >= 0 && y < DEV_H);
+
+ U8CPU r = x;
+ U8CPU g = y;
+ U8CPU b = 0xc;
+
+ U8CPU a = 0xff;
+ switch ((x+y) % 5) {
+ case 0:
+ a = 0xff;
+ break;
+ case 1:
+ a = 0x80;
+ break;
+ case 2:
+ a = 0xCC;
+ break;
+ case 4:
+ a = 0x01;
+ break;
+ case 3:
+ a = 0x00;
+ break;
+ }
+ return SkPremultiplyARGBInline(a, r, g, b);
+}
+
+static SkPMColor getBitmapColor(int x, int y, int w) {
+ int n = y * w + x;
+
+ U8CPU b = n & 0xff;
+ U8CPU g = (n >> 8) & 0xff;
+ U8CPU r = (n >> 16) & 0xff;
+ return SkPackARGB32(0xff, r, g , b);
+}
+
+static SkPMColor convertToPMColor(SkColorType ct, SkAlphaType at, const uint32_t* addr,
+ bool* doUnpremul) {
+ *doUnpremul = (kUnpremul_SkAlphaType == at);
+
+ const uint8_t* c = reinterpret_cast<const uint8_t*>(addr);
+ U8CPU a,r,g,b;
+ switch (ct) {
+ case kBGRA_8888_SkColorType:
+ b = static_cast<U8CPU>(c[0]);
+ g = static_cast<U8CPU>(c[1]);
+ r = static_cast<U8CPU>(c[2]);
+ a = static_cast<U8CPU>(c[3]);
+ break;
+ case kRGBA_8888_SkColorType:
+ r = static_cast<U8CPU>(c[0]);
+ g = static_cast<U8CPU>(c[1]);
+ b = static_cast<U8CPU>(c[2]);
+ a = static_cast<U8CPU>(c[3]);
+ break;
+ default:
+ SkDEBUGFAIL("Unexpected colortype");
+ return 0;
+ }
+
+ if (*doUnpremul) {
+ r = SkMulDiv255Ceiling(r, a);
+ g = SkMulDiv255Ceiling(g, a);
+ b = SkMulDiv255Ceiling(b, a);
+ }
+ return SkPackARGB32(a, r, g, b);
+}
+
+static void fillCanvas(SkCanvas* canvas) {
+ static SkBitmap bmp;
+ if (bmp.isNull()) {
+ bmp.allocN32Pixels(DEV_W, DEV_H);
+ intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
+ for (int y = 0; y < DEV_H; ++y) {
+ for (int x = 0; x < DEV_W; ++x) {
+ SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
+ *pixel = getCanvasColor(x, y);
+ }
+ }
+ }
+ canvas->save();
+ canvas->setMatrix(SkMatrix::I());
+ canvas->clipRect(DEV_RECT_S, SkRegion::kReplace_Op);
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas->drawBitmap(bmp, 0, 0, &paint);
+ canvas->restore();
+}
+
+static void fillBitmap(SkBitmap* bitmap) {
+ SkASSERT(bitmap->lockPixelsAreWritable());
+ SkAutoLockPixels alp(*bitmap);
+ int w = bitmap->width();
+ int h = bitmap->height();
+ intptr_t pixels = reinterpret_cast<intptr_t>(bitmap->getPixels());
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel());
+ *pixel = getBitmapColor(x, y, w);
+ }
+ }
+}
+
+static bool checkPixel(SkPMColor a, SkPMColor b, bool didPremulConversion) {
+ if (!didPremulConversion) {
+ return a == b;
+ }
+ int32_t aA = static_cast<int32_t>(SkGetPackedA32(a));
+ int32_t aR = static_cast<int32_t>(SkGetPackedR32(a));
+ int32_t aG = static_cast<int32_t>(SkGetPackedG32(a));
+ int32_t aB = SkGetPackedB32(a);
+
+ int32_t bA = static_cast<int32_t>(SkGetPackedA32(b));
+ int32_t bR = static_cast<int32_t>(SkGetPackedR32(b));
+ int32_t bG = static_cast<int32_t>(SkGetPackedG32(b));
+ int32_t bB = static_cast<int32_t>(SkGetPackedB32(b));
+
+ return aA == bA &&
+ SkAbs32(aR - bR) <= 1 &&
+ SkAbs32(aG - bG) <= 1 &&
+ SkAbs32(aB - bB) <= 1;
+}
+
+// checks the bitmap contains correct pixels after the readPixels
+// if the bitmap was prefilled with pixels it checks that these weren't
+// overwritten in the area outside the readPixels.
+static bool checkRead(skiatest::Reporter* reporter,
+ const SkBitmap& bitmap,
+ int x, int y,
+ bool checkCanvasPixels,
+ bool checkBitmapPixels) {
+ SkASSERT(4 == bitmap.bytesPerPixel());
+ SkASSERT(!bitmap.isNull());
+ SkASSERT(checkCanvasPixels || checkBitmapPixels);
+
+ const SkColorType ct = bitmap.colorType();
+ const SkAlphaType at = bitmap.alphaType();
+
+ int bw = bitmap.width();
+ int bh = bitmap.height();
+
+ SkIRect srcRect = SkIRect::MakeXYWH(x, y, bw, bh);
+ SkIRect clippedSrcRect = DEV_RECT;
+ if (!clippedSrcRect.intersect(srcRect)) {
+ clippedSrcRect.setEmpty();
+ }
+ SkAutoLockPixels alp(bitmap);
+ for (int by = 0; by < bh; ++by) {
+ for (int bx = 0; bx < bw; ++bx) {
+ int devx = bx + srcRect.fLeft;
+ int devy = by + srcRect.fTop;
+
+ const uint32_t* pixel = bitmap.getAddr32(bx, by);
+
+ if (clippedSrcRect.contains(devx, devy)) {
+ if (checkCanvasPixels) {
+ SkPMColor canvasPixel = getCanvasColor(devx, devy);
+ bool didPremul;
+ SkPMColor pmPixel = convertToPMColor(ct, at, pixel, &didPremul);
+ bool check;
+ REPORTER_ASSERT(reporter, check = checkPixel(pmPixel, canvasPixel, didPremul));
+ if (!check) {
+ return false;
+ }
+ }
+ } else if (checkBitmapPixels) {
+ REPORTER_ASSERT(reporter, getBitmapColor(bx, by, bw) == *pixel);
+ if (getBitmapColor(bx, by, bw) != *pixel) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+enum BitmapInit {
+ kFirstBitmapInit = 0,
+
+ kNoPixels_BitmapInit = kFirstBitmapInit,
+ kTight_BitmapInit,
+ kRowBytes_BitmapInit,
+
+ kBitmapInitCnt
+};
+
+static BitmapInit nextBMI(BitmapInit bmi) {
+ int x = bmi;
+ return static_cast<BitmapInit>(++x);
+}
+
+static void init_bitmap(SkBitmap* bitmap, const SkIRect& rect, BitmapInit init, SkColorType ct,
+ SkAlphaType at) {
+ SkImageInfo info = SkImageInfo::Make(rect.width(), rect.height(), ct, at);
+ size_t rowBytes = 0;
+ bool alloc = true;
+ switch (init) {
+ case kNoPixels_BitmapInit:
+ alloc = false;
+ case kTight_BitmapInit:
+ break;
+ case kRowBytes_BitmapInit:
+ rowBytes = (info.width() + 16) * sizeof(SkPMColor);
+ break;
+ default:
+ SkASSERT(0);
+ break;
+ }
+
+ if (alloc) {
+ bitmap->allocPixels(info);
+ } else {
+ bitmap->setInfo(info, rowBytes);
+ }
+}
+
+DEF_GPUTEST(ReadPixels, reporter, factory) {
+ const SkIRect testRects[] = {
+ // entire thing
+ DEV_RECT,
+ // larger on all sides
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
+ // fully contained
+ SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
+ // outside top left
+ SkIRect::MakeLTRB(-10, -10, -1, -1),
+ // touching top left corner
+ SkIRect::MakeLTRB(-10, -10, 0, 0),
+ // overlapping top left corner
+ SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
+ // overlapping top left and top right corners
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H / 4),
+ // touching entire top edge
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, 0),
+ // overlapping top right corner
+ SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H / 4),
+ // contained in x, overlapping top edge
+ SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W / 4, DEV_H / 4),
+ // outside top right corner
+ SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
+ // touching top right corner
+ SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
+ // overlapping top left and bottom left corners
+ SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
+ // touching entire left edge
+ SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
+ // overlapping bottom left corner
+ SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
+ // contained in y, overlapping left edge
+ SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
+ // outside bottom left corner
+ SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
+ // touching bottom left corner
+ SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
+ // overlapping bottom left and bottom right corners
+ SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
+ // touching entire left edge
+ SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
+ // overlapping bottom right corner
+ SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
+ // overlapping top right and bottom right corners
+ SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
+ };
+
+ for (int dtype = 0; dtype < 3; ++dtype) {
+ int glCtxTypeCnt = 1;
+#if SK_SUPPORT_GPU
+ if (0 != dtype) {
+ glCtxTypeCnt = GrContextFactory::kGLContextTypeCnt;
+ }
+#endif
+ const SkImageInfo info = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
+ for (int glCtxType = 0; glCtxType < glCtxTypeCnt; ++glCtxType) {
+ SkAutoTUnref<SkSurface> surface;
+ if (0 == dtype) {
+ surface.reset(SkSurface::NewRaster(info));
+ } else {
+#if SK_SUPPORT_GPU
+ GrContextFactory::GLContextType type =
+ static_cast<GrContextFactory::GLContextType>(glCtxType);
+ if (!GrContextFactory::IsRenderingGLContext(type)) {
+ continue;
+ }
+ GrContext* context = factory->get(type);
+ if (NULL == context) {
+ continue;
+ }
+ GrTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
+ desc.fWidth = DEV_W;
+ desc.fHeight = DEV_H;
+ desc.fConfig = kSkia8888_GrPixelConfig;
+ desc.fOrigin = 1 == dtype ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
+ GrAutoScratchTexture ast(context, desc, GrContext::kExact_ScratchTexMatch);
+ SkAutoTUnref<GrTexture> tex(ast.detach());
+ surface.reset(SkSurface::NewRenderTargetDirect(tex->asRenderTarget()));
+#else
+ continue;
+#endif
+ }
+ SkCanvas& canvas = *surface->getCanvas();
+ fillCanvas(&canvas);
+
+ static const struct {
+ SkColorType fColorType;
+ SkAlphaType fAlphaType;
+ } gReadConfigs[] = {
+ { kRGBA_8888_SkColorType, kPremul_SkAlphaType },
+ { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType },
+ { kBGRA_8888_SkColorType, kPremul_SkAlphaType },
+ { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType },
+ };
+ for (size_t rect = 0; rect < SK_ARRAY_COUNT(testRects); ++rect) {
+ const SkIRect& srcRect = testRects[rect];
+ for (BitmapInit bmi = kFirstBitmapInit; bmi < kBitmapInitCnt; bmi = nextBMI(bmi)) {
+ for (size_t c = 0; c < SK_ARRAY_COUNT(gReadConfigs); ++c) {
+ SkBitmap bmp;
+ init_bitmap(&bmp, srcRect, bmi,
+ gReadConfigs[c].fColorType, gReadConfigs[c].fAlphaType);
+
+ // if the bitmap has pixels allocated before the readPixels,
+ // note that and fill them with pattern
+ bool startsWithPixels = !bmp.isNull();
+ if (startsWithPixels) {
+ fillBitmap(&bmp);
+ }
+ uint32_t idBefore = surface->generationID();
+ bool success = canvas.readPixels(&bmp, srcRect.fLeft, srcRect.fTop);
+ uint32_t idAfter = surface->generationID();
+
+ // we expect to succeed when the read isn't fully clipped
+ // out.
+ bool expectSuccess = SkIRect::Intersects(srcRect, DEV_RECT);
+ // determine whether we expected the read to succeed.
+ REPORTER_ASSERT(reporter, success == expectSuccess);
+ // read pixels should never change the gen id
+ REPORTER_ASSERT(reporter, idBefore == idAfter);
+
+ if (success || startsWithPixels) {
+ checkRead(reporter, bmp, srcRect.fLeft, srcRect.fTop,
+ success, startsWithPixels);
+ } else {
+ // if we had no pixels beforehand and the readPixels
+ // failed then our bitmap should still not have pixels
+ REPORTER_ASSERT(reporter, bmp.isNull());
+ }
+ }
+ // check the old webkit version of readPixels that clips the
+ // bitmap size
+ SkBitmap wkbmp;
+ bool success = canvas.readPixels(srcRect, &wkbmp);
+ SkIRect clippedRect = DEV_RECT;
+ if (clippedRect.intersect(srcRect)) {
+ REPORTER_ASSERT(reporter, success);
+ REPORTER_ASSERT(reporter, kN32_SkColorType == wkbmp.colorType());
+ REPORTER_ASSERT(reporter, kPremul_SkAlphaType == wkbmp.alphaType());
+ checkRead(reporter, wkbmp, clippedRect.fLeft,
+ clippedRect.fTop, true, false);
+ } else {
+ REPORTER_ASSERT(reporter, !success);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/ReadWriteAlphaTest.cpp b/src/third_party/skia/tests/ReadWriteAlphaTest.cpp
new file mode 100644
index 0000000..385a17e
--- /dev/null
+++ b/src/third_party/skia/tests/ReadWriteAlphaTest.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// This test is specific to the GPU backend.
+#if SK_SUPPORT_GPU && !defined(SK_BUILD_FOR_ANDROID)
+
+#include "GrContextFactory.h"
+#include "SkGpuDevice.h"
+#include "Test.h"
+
+static const int X_SIZE = 12;
+static const int Y_SIZE = 12;
+
+DEF_GPUTEST(ReadWriteAlpha, reporter, factory) {
+ for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
+ GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type);
+ if (!GrContextFactory::IsRenderingGLContext(glType)) {
+ continue;
+ }
+ GrContext* context = factory->get(glType);
+ if (NULL == context) {
+ continue;
+ }
+
+ unsigned char textureData[X_SIZE][Y_SIZE];
+
+ memset(textureData, 0, X_SIZE * Y_SIZE);
+
+ GrTextureDesc desc;
+
+ // let Skia know we will be using this texture as a render target
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ // it is a single channel texture
+ desc.fConfig = kAlpha_8_GrPixelConfig;
+ desc.fWidth = X_SIZE;
+ desc.fHeight = Y_SIZE;
+
+ // We are initializing the texture with zeros here
+ GrTexture* texture = context->createUncachedTexture(desc, textureData, 0);
+ if (!texture) {
+ return;
+ }
+
+ SkAutoTUnref<GrTexture> au(texture);
+
+ // create a distinctive texture
+ for (int y = 0; y < Y_SIZE; ++y) {
+ for (int x = 0; x < X_SIZE; ++x) {
+ textureData[x][y] = x*Y_SIZE+y;
+ }
+ }
+
+ // upload the texture
+ texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
+ textureData, 0);
+
+ unsigned char readback[X_SIZE][Y_SIZE];
+
+ // clear readback to something non-zero so we can detect readback failures
+ memset(readback, 0x1, X_SIZE * Y_SIZE);
+
+ // read the texture back
+ texture->readPixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
+ readback, 0);
+
+ // make sure the original & read back versions match
+ bool match = true;
+
+ for (int y = 0; y < Y_SIZE; ++y) {
+ for (int x = 0; x < X_SIZE; ++x) {
+ if (textureData[x][y] != readback[x][y]) {
+ match = false;
+ }
+ }
+ }
+
+ REPORTER_ASSERT(reporter, match);
+
+ // Now try writing on the single channel texture
+ SkAutoTUnref<SkBaseDevice> device(SkGpuDevice::Create(texture->asRenderTarget(),
+ SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)));
+ SkCanvas canvas(device);
+
+ SkPaint paint;
+
+ const SkRect rect = SkRect::MakeLTRB(-10, -10, X_SIZE + 10, Y_SIZE + 10);
+
+ paint.setColor(SK_ColorWHITE);
+
+ canvas.drawRect(rect, paint);
+
+ texture->readPixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
+ readback, 0);
+
+ match = true;
+
+ for (int y = 0; y < Y_SIZE; ++y) {
+ for (int x = 0; x < X_SIZE; ++x) {
+ if (0xFF != readback[x][y]) {
+ match = false;
+ }
+ }
+ }
+
+ REPORTER_ASSERT(reporter, match);
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/Reader32Test.cpp b/src/third_party/skia/tests/Reader32Test.cpp
new file mode 100644
index 0000000..cfa08b3
--- /dev/null
+++ b/src/third_party/skia/tests/Reader32Test.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkReader32.h"
+#include "Test.h"
+
+static void assert_eof(skiatest::Reporter* reporter, const SkReader32& reader) {
+ REPORTER_ASSERT(reporter, reader.eof());
+ REPORTER_ASSERT(reporter, reader.size() == reader.offset());
+ REPORTER_ASSERT(reporter, (const char*)reader.peek() ==
+ (const char*)reader.base() + reader.size());
+}
+
+static void assert_start(skiatest::Reporter* reporter, const SkReader32& reader) {
+ REPORTER_ASSERT(reporter, 0 == reader.offset());
+ REPORTER_ASSERT(reporter, reader.size() == reader.available());
+ REPORTER_ASSERT(reporter, reader.isAvailable(reader.size()));
+ REPORTER_ASSERT(reporter, !reader.isAvailable(reader.size() + 1));
+ REPORTER_ASSERT(reporter, reader.peek() == reader.base());
+}
+
+static void assert_empty(skiatest::Reporter* reporter, const SkReader32& reader) {
+ REPORTER_ASSERT(reporter, 0 == reader.size());
+ REPORTER_ASSERT(reporter, 0 == reader.offset());
+ REPORTER_ASSERT(reporter, 0 == reader.available());
+ REPORTER_ASSERT(reporter, !reader.isAvailable(1));
+ assert_eof(reporter, reader);
+ assert_start(reporter, reader);
+}
+
+DEF_TEST(Reader32, reporter) {
+ SkReader32 reader;
+ assert_empty(reporter, reader);
+ REPORTER_ASSERT(reporter, NULL == reader.base());
+ REPORTER_ASSERT(reporter, NULL == reader.peek());
+
+ size_t i;
+
+ const int32_t data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ const SkScalar data2[] = { 0, SK_Scalar1, -SK_Scalar1, SK_Scalar1/2 };
+ const size_t bufsize = sizeof(data) > sizeof(data2) ?
+ sizeof(data) : sizeof(data2);
+ char buffer[bufsize];
+
+ reader.setMemory(data, sizeof(data));
+ for (i = 0; i < SK_ARRAY_COUNT(data); ++i) {
+ REPORTER_ASSERT(reporter, sizeof(data) == reader.size());
+ REPORTER_ASSERT(reporter, i*4 == reader.offset());
+ REPORTER_ASSERT(reporter, (const void*)data == reader.base());
+ REPORTER_ASSERT(reporter, (const void*)&data[i] == reader.peek());
+ REPORTER_ASSERT(reporter, data[i] == reader.readInt());
+ }
+ assert_eof(reporter, reader);
+ reader.rewind();
+ assert_start(reporter, reader);
+ reader.read(buffer, sizeof(data));
+ REPORTER_ASSERT(reporter, !memcmp(data, buffer, sizeof(data)));
+
+ reader.setMemory(data2, sizeof(data2));
+ for (i = 0; i < SK_ARRAY_COUNT(data2); ++i) {
+ REPORTER_ASSERT(reporter, sizeof(data2) == reader.size());
+ REPORTER_ASSERT(reporter, i*4 == reader.offset());
+ REPORTER_ASSERT(reporter, (const void*)data2 == reader.base());
+ REPORTER_ASSERT(reporter, (const void*)&data2[i] == reader.peek());
+ REPORTER_ASSERT(reporter, data2[i] == reader.readScalar());
+ }
+ assert_eof(reporter, reader);
+ reader.rewind();
+ assert_start(reporter, reader);
+ reader.read(buffer, sizeof(data2));
+ REPORTER_ASSERT(reporter, !memcmp(data2, buffer, sizeof(data2)));
+
+ reader.setMemory(NULL, 0);
+ assert_empty(reporter, reader);
+ REPORTER_ASSERT(reporter, NULL == reader.base());
+ REPORTER_ASSERT(reporter, NULL == reader.peek());
+}
diff --git a/src/third_party/skia/tests/RecordDrawTest.cpp b/src/third_party/skia/tests/RecordDrawTest.cpp
new file mode 100644
index 0000000..33efbd8
--- /dev/null
+++ b/src/third_party/skia/tests/RecordDrawTest.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "RecordTestUtils.h"
+
+#include "SkDebugCanvas.h"
+#include "SkDrawPictureCallback.h"
+#include "SkDropShadowImageFilter.h"
+#include "SkRecord.h"
+#include "SkRecordDraw.h"
+#include "SkRecordOpts.h"
+#include "SkRecorder.h"
+#include "SkRecords.h"
+
+static const int W = 1920, H = 1080;
+
+class JustOneDraw : public SkDrawPictureCallback {
+public:
+ JustOneDraw() : fCalls(0) {}
+
+ virtual bool abortDrawing() SK_OVERRIDE { return fCalls++ > 0; }
+private:
+ int fCalls;
+};
+
+DEF_TEST(RecordDraw_Abort, r) {
+ // Record two commands.
+ SkRecord record;
+ SkRecorder recorder(&record, W, H);
+ recorder.drawRect(SkRect::MakeWH(200, 300), SkPaint());
+ recorder.clipRect(SkRect::MakeWH(100, 200));
+
+ SkRecord rerecord;
+ SkRecorder canvas(&rerecord, W, H);
+
+ JustOneDraw callback;
+ SkRecordDraw(record, &canvas, NULL/*bbh*/, &callback);
+
+ REPORTER_ASSERT(r, 3 == rerecord.count());
+ assert_type<SkRecords::Save> (r, rerecord, 0);
+ assert_type<SkRecords::DrawRect>(r, rerecord, 1);
+ assert_type<SkRecords::Restore> (r, rerecord, 2);
+}
+
+DEF_TEST(RecordDraw_Unbalanced, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, W, H);
+ recorder.save(); // We won't balance this, but SkRecordDraw will for us.
+
+ SkRecord rerecord;
+ SkRecorder canvas(&rerecord, W, H);
+ SkRecordDraw(record, &canvas, NULL/*bbh*/, NULL/*callback*/);
+
+ REPORTER_ASSERT(r, 4 == rerecord.count());
+ assert_type<SkRecords::Save> (r, rerecord, 0);
+ assert_type<SkRecords::Save> (r, rerecord, 1);
+ assert_type<SkRecords::Restore> (r, rerecord, 2);
+ assert_type<SkRecords::Restore> (r, rerecord, 3);
+}
+
+DEF_TEST(RecordDraw_SetMatrixClobber, r) {
+ // Set up an SkRecord that just scales by 2x,3x.
+ SkRecord scaleRecord;
+ SkRecorder scaleCanvas(&scaleRecord, W, H);
+ SkMatrix scale;
+ scale.setScale(2, 3);
+ scaleCanvas.setMatrix(scale);
+
+ // Set up an SkRecord with an initial +20, +20 translate.
+ SkRecord translateRecord;
+ SkRecorder translateCanvas(&translateRecord, W, H);
+ SkMatrix translate;
+ translate.setTranslate(20, 20);
+ translateCanvas.setMatrix(translate);
+
+ SkRecordDraw(scaleRecord, &translateCanvas, NULL/*bbh*/, NULL/*callback*/);
+ REPORTER_ASSERT(r, 4 == translateRecord.count());
+ assert_type<SkRecords::SetMatrix>(r, translateRecord, 0);
+ assert_type<SkRecords::Save> (r, translateRecord, 1);
+ assert_type<SkRecords::SetMatrix>(r, translateRecord, 2);
+ assert_type<SkRecords::Restore> (r, translateRecord, 3);
+
+ // When we look at translateRecord now, it should have its first +20,+20 translate,
+ // then a 2x,3x scale that's been concatted with that +20,+20 translate.
+ const SkRecords::SetMatrix* setMatrix;
+ setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 0);
+ REPORTER_ASSERT(r, setMatrix->matrix == translate);
+
+ setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 2);
+ SkMatrix expected = scale;
+ expected.postConcat(translate);
+ REPORTER_ASSERT(r, setMatrix->matrix == expected);
+}
+
+struct TestBBH : public SkBBoxHierarchy {
+ virtual void insert(void* data, const SkRect& bounds, bool defer) SK_OVERRIDE {
+ Entry e = { (uintptr_t)data, bounds };
+ entries.push(e);
+ }
+ virtual int getCount() const SK_OVERRIDE { return entries.count(); }
+
+ virtual void flushDeferredInserts() SK_OVERRIDE {}
+
+ virtual void search(const SkRect& query, SkTDArray<void*>* results) const SK_OVERRIDE {}
+ virtual void clear() SK_OVERRIDE {}
+ virtual void rewindInserts() SK_OVERRIDE {}
+ virtual int getDepth() const SK_OVERRIDE { return -1; }
+
+ struct Entry {
+ uintptr_t data;
+ SkRect bounds;
+ };
+ SkTDArray<Entry> entries;
+};
+
+// Like a==b, with a little slop recognizing that float equality can be weird.
+static bool sloppy_rect_eq(SkRect a, SkRect b) {
+ SkRect inset(a), outset(a);
+ inset.inset(1, 1);
+ outset.outset(1, 1);
+ return outset.contains(b) && !inset.contains(b);
+}
+
+// This test is not meant to make total sense yet. It's testing the status quo
+// of SkRecordFillBounds(), which itself doesn't make total sense yet.
+DEF_TEST(RecordDraw_BBH, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, W, H);
+ recorder.save();
+ recorder.clipRect(SkRect::MakeWH(400, 500));
+ recorder.scale(2, 2);
+ recorder.drawRect(SkRect::MakeWH(320, 240), SkPaint());
+ recorder.restore();
+
+ TestBBH bbh;
+ SkRecordFillBounds(record, &bbh);
+
+ REPORTER_ASSERT(r, bbh.entries.count() == 5);
+ for (int i = 0; i < bbh.entries.count(); i++) {
+ REPORTER_ASSERT(r, bbh.entries[i].data == (uintptr_t)i);
+
+ REPORTER_ASSERT(r, sloppy_rect_eq(SkRect::MakeWH(400, 480), bbh.entries[i].bounds));
+ }
+}
+
+// A regression test for crbug.com/409110.
+DEF_TEST(RecordDraw_TextBounds, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, W, H);
+
+ // Two Chinese characters in UTF-8.
+ const char text[] = { '\xe6', '\xbc', '\xa2', '\xe5', '\xad', '\x97' };
+ const size_t bytes = SK_ARRAY_COUNT(text);
+
+ const SkScalar xpos[] = { 10, 20 };
+ recorder.drawPosTextH(text, bytes, xpos, 30, SkPaint());
+
+ const SkPoint pos[] = { {40, 50}, {60, 70} };
+ recorder.drawPosText(text, bytes, pos, SkPaint());
+
+ TestBBH bbh;
+ SkRecordFillBounds(record, &bbh);
+ REPORTER_ASSERT(r, bbh.entries.count() == 2);
+
+ // We can make these next assertions confidently because SkRecordFillBounds
+ // builds its bounds by overestimating font metrics in a platform-independent way.
+ // If that changes, these tests will need to be more flexible.
+ REPORTER_ASSERT(r, sloppy_rect_eq(bbh.entries[0].bounds, SkRect::MakeLTRB(-86, 6, 116, 54)));
+ REPORTER_ASSERT(r, sloppy_rect_eq(bbh.entries[1].bounds, SkRect::MakeLTRB(-56, 26, 156, 94)));
+}
+
+// Base test to ensure start/stop range is respected
+DEF_TEST(RecordDraw_PartialStartStop, r) {
+ static const int kWidth = 10, kHeight = 10;
+
+ SkRect r1 = { 0, 0, kWidth, kHeight };
+ SkRect r2 = { 0, 0, kWidth, kHeight/2 };
+ SkRect r3 = { 0, 0, kWidth/2, kHeight };
+ SkPaint p;
+
+ SkRecord record;
+ SkRecorder recorder(&record, kWidth, kHeight);
+ recorder.drawRect(r1, p);
+ recorder.drawRect(r2, p);
+ recorder.drawRect(r3, p);
+
+ SkRecord rerecord;
+ SkRecorder canvas(&rerecord, kWidth, kHeight);
+ SkRecordPartialDraw(record, &canvas, r1, 1, 2, SkMatrix::I()); // replay just drawRect of r2
+
+ REPORTER_ASSERT(r, 3 == rerecord.count());
+ assert_type<SkRecords::Save> (r, rerecord, 0);
+ assert_type<SkRecords::DrawRect> (r, rerecord, 1);
+ assert_type<SkRecords::Restore> (r, rerecord, 2);
+
+ const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, rerecord, 1);
+ REPORTER_ASSERT(r, drawRect->rect == r2);
+}
+
+// Check that clears are converted to drawRects
+DEF_TEST(RecordDraw_PartialClear, r) {
+ static const int kWidth = 10, kHeight = 10;
+
+ SkRect rect = { 0, 0, kWidth, kHeight };
+
+ SkRecord record;
+ SkRecorder recorder(&record, kWidth, kHeight);
+ recorder.clear(SK_ColorRED);
+
+ SkRecord rerecord;
+ SkRecorder canvas(&rerecord, kWidth, kHeight);
+ SkRecordPartialDraw(record, &canvas, rect, 0, 1, SkMatrix::I()); // replay just the clear
+
+ REPORTER_ASSERT(r, 3 == rerecord.count());
+ assert_type<SkRecords::Save> (r, rerecord, 0);
+ assert_type<SkRecords::DrawRect>(r, rerecord, 1);
+ assert_type<SkRecords::Restore> (r, rerecord, 2);
+
+ const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, rerecord, 1);
+ REPORTER_ASSERT(r, drawRect->rect == rect);
+ REPORTER_ASSERT(r, drawRect->paint.getColor() == SK_ColorRED);
+}
+
+// A regression test for crbug.com/415468 and skbug.com/2957.
+//
+// This also now serves as a regression test for crbug.com/418417. We used to adjust the
+// bounds for the saveLayer, clip, and restore to be greater than the bounds of the picture.
+// (We were applying the saveLayer paint to the bounds after restore, which makes no sense.)
+DEF_TEST(RecordDraw_SaveLayerAffectsClipBounds, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, 50, 50);
+
+ // We draw a rectangle with a long drop shadow. We used to not update the clip
+ // bounds based on SaveLayer paints, so the drop shadow could be cut off.
+ SkPaint paint;
+ paint.setImageFilter(SkDropShadowImageFilter::Create(20, 0, 0, 0, SK_ColorBLACK))->unref();
+
+ recorder.saveLayer(NULL, &paint);
+ recorder.clipRect(SkRect::MakeWH(20, 40));
+ recorder.drawRect(SkRect::MakeWH(20, 40), SkPaint());
+ recorder.restore();
+
+ // Under the original bug, the right edge value of the drawRect would be 20 less than asserted
+ // here because we intersected it with a clip that had not been adjusted for the drop shadow.
+ //
+ // The second bug showed up as adjusting the picture bounds (0,0,50,50) by the drop shadow too.
+ // The saveLayer, clipRect, and restore bounds were incorrectly (0,0,70,50).
+ TestBBH bbh;
+ SkRecordFillBounds(record, &bbh);
+ REPORTER_ASSERT(r, bbh.entries.count() == 4);
+ REPORTER_ASSERT(r, sloppy_rect_eq(bbh.entries[0].bounds, SkRect::MakeLTRB(0, 0, 50, 50)));
+ REPORTER_ASSERT(r, sloppy_rect_eq(bbh.entries[1].bounds, SkRect::MakeLTRB(0, 0, 50, 50)));
+ REPORTER_ASSERT(r, sloppy_rect_eq(bbh.entries[2].bounds, SkRect::MakeLTRB(0, 0, 40, 40)));
+ REPORTER_ASSERT(r, sloppy_rect_eq(bbh.entries[3].bounds, SkRect::MakeLTRB(0, 0, 50, 50)));
+}
diff --git a/src/third_party/skia/tests/RecordOptsTest.cpp b/src/third_party/skia/tests/RecordOptsTest.cpp
new file mode 100644
index 0000000..c5c4471
--- /dev/null
+++ b/src/third_party/skia/tests/RecordOptsTest.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "RecordTestUtils.h"
+
+#include "SkRecord.h"
+#include "SkRecordOpts.h"
+#include "SkRecorder.h"
+#include "SkRecords.h"
+#include "SkXfermode.h"
+
+static const int W = 1920, H = 1080;
+
+DEF_TEST(RecordOpts_NoopDrawSaveRestore, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, W, H);
+
+ // The save and restore are pointless if there's only draw commands in the middle.
+ recorder.save();
+ recorder.drawRect(SkRect::MakeWH(200, 200), SkPaint());
+ recorder.drawRect(SkRect::MakeWH(300, 300), SkPaint());
+ recorder.drawRect(SkRect::MakeWH(100, 100), SkPaint());
+ recorder.restore();
+
+ record.replace<SkRecords::NoOp>(2); // NoOps should be allowed.
+
+ SkRecordNoopSaveRestores(&record);
+
+ assert_type<SkRecords::NoOp>(r, record, 0);
+ assert_type<SkRecords::DrawRect>(r, record, 1);
+ assert_type<SkRecords::NoOp>(r, record, 2);
+ assert_type<SkRecords::DrawRect>(r, record, 3);
+ assert_type<SkRecords::NoOp>(r, record, 4);
+}
+
+DEF_TEST(RecordOpts_SingleNoopSaveRestore, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, W, H);
+
+ recorder.save();
+ recorder.clipRect(SkRect::MakeWH(200, 200));
+ recorder.restore();
+
+ SkRecordNoopSaveRestores(&record);
+ for (unsigned i = 0; i < 3; i++) {
+ assert_type<SkRecords::NoOp>(r, record, i);
+ }
+}
+
+DEF_TEST(RecordOpts_NoopSaveRestores, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, W, H);
+
+ // The second pass will clean up this pair after the first pass noops all the innards.
+ recorder.save();
+ // A simple pointless pair of save/restore.
+ recorder.save();
+ recorder.restore();
+
+ // As long as we don't draw in there, everything is a noop.
+ recorder.save();
+ recorder.clipRect(SkRect::MakeWH(200, 200));
+ recorder.clipRect(SkRect::MakeWH(100, 100));
+ recorder.restore();
+ recorder.restore();
+
+ SkRecordNoopSaveRestores(&record);
+ for (unsigned index = 0; index < 8; index++) {
+ assert_type<SkRecords::NoOp>(r, record, index);
+ }
+}
+
+DEF_TEST(RecordOpts_SaveSaveLayerRestoreRestore, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, W, H);
+
+ // A previous bug NoOp'd away the first 3 commands.
+ recorder.save();
+ recorder.saveLayer(NULL, NULL);
+ recorder.restore();
+ recorder.restore();
+
+ SkRecordNoopSaveRestores(&record);
+ assert_type<SkRecords::Save> (r, record, 0);
+ assert_type<SkRecords::SaveLayer>(r, record, 1);
+ assert_type<SkRecords::Restore> (r, record, 2);
+ assert_type<SkRecords::Restore> (r, record, 3);
+}
+
+static void assert_savelayer_restore(skiatest::Reporter* r,
+ SkRecord* record,
+ unsigned i,
+ bool shouldBeNoOped) {
+ SkRecordNoopSaveLayerDrawRestores(record);
+ if (shouldBeNoOped) {
+ assert_type<SkRecords::NoOp>(r, *record, i);
+ assert_type<SkRecords::NoOp>(r, *record, i+2);
+ } else {
+ assert_type<SkRecords::SaveLayer>(r, *record, i);
+ assert_type<SkRecords::Restore>(r, *record, i+2);
+ }
+}
+
+DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, W, H);
+
+ SkRect bounds = SkRect::MakeWH(100, 200);
+ SkRect draw = SkRect::MakeWH(50, 60);
+
+ SkPaint goodLayerPaint, badLayerPaint, worseLayerPaint;
+ goodLayerPaint.setColor(0x03000000); // Only alpha.
+ badLayerPaint.setColor( 0x03040506); // Not only alpha.
+ worseLayerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode); // Any effect will do.
+
+ SkPaint goodDrawPaint, badDrawPaint;
+ goodDrawPaint.setColor(0xFF020202); // Opaque.
+ badDrawPaint.setColor( 0x0F020202); // Not opaque.
+
+ // No change: optimization can't handle bounds.
+ recorder.saveLayer(&bounds, NULL);
+ recorder.drawRect(draw, goodDrawPaint);
+ recorder.restore();
+ assert_savelayer_restore(r, &record, 0, false);
+
+ // SaveLayer/Restore removed: no bounds + no paint = no point.
+ recorder.saveLayer(NULL, NULL);
+ recorder.drawRect(draw, goodDrawPaint);
+ recorder.restore();
+ assert_savelayer_restore(r, &record, 3, true);
+
+ // TODO(mtklein): test case with null draw paint
+
+ // No change: layer paint isn't alpha-only.
+ recorder.saveLayer(NULL, &badLayerPaint);
+ recorder.drawRect(draw, goodDrawPaint);
+ recorder.restore();
+ assert_savelayer_restore(r, &record, 6, false);
+
+ // No change: layer paint has an effect.
+ recorder.saveLayer(NULL, &worseLayerPaint);
+ recorder.drawRect(draw, goodDrawPaint);
+ recorder.restore();
+ assert_savelayer_restore(r, &record, 9, false);
+
+ // No change: draw paint isn't opaque.
+ recorder.saveLayer(NULL, &goodLayerPaint);
+ recorder.drawRect(draw, badDrawPaint);
+ recorder.restore();
+ assert_savelayer_restore(r, &record, 12, false);
+
+ // SaveLayer/Restore removed: we can fold in the alpha!
+ recorder.saveLayer(NULL, &goodLayerPaint);
+ recorder.drawRect(draw, goodDrawPaint);
+ recorder.restore();
+ assert_savelayer_restore(r, &record, 15, true);
+
+ const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, record, 16);
+ REPORTER_ASSERT(r, drawRect != NULL);
+ REPORTER_ASSERT(r, drawRect->paint.getColor() == 0x03020202);
+}
diff --git a/src/third_party/skia/tests/RecordPatternTest.cpp b/src/third_party/skia/tests/RecordPatternTest.cpp
new file mode 100644
index 0000000..5f4d006
--- /dev/null
+++ b/src/third_party/skia/tests/RecordPatternTest.cpp
@@ -0,0 +1,199 @@
+#include "Test.h"
+
+#include "SkRecord.h"
+#include "SkRecordPattern.h"
+#include "SkRecorder.h"
+#include "SkRecords.h"
+
+using namespace SkRecords;
+typedef Pattern3<Is<Save>,
+ Is<ClipRect>,
+ Is<Restore> >
+ SaveClipRectRestore;
+
+DEF_TEST(RecordPattern_Simple, r) {
+ SaveClipRectRestore pattern;
+
+ SkRecord record;
+ REPORTER_ASSERT(r, !pattern.match(&record, 0));
+
+ SkRecorder recorder(&record, 1920, 1200);
+
+ // Build up a save-clip-restore block. The pattern will match only it's complete.
+ recorder.save();
+ REPORTER_ASSERT(r, !pattern.match(&record, 0));
+
+ recorder.clipRect(SkRect::MakeWH(300, 200));
+ REPORTER_ASSERT(r, !pattern.match(&record, 0));
+
+ recorder.restore();
+ REPORTER_ASSERT(r, pattern.match(&record, 0));
+ REPORTER_ASSERT(r, pattern.first<Save>() != NULL);
+ REPORTER_ASSERT(r, pattern.second<ClipRect>() != NULL);
+ REPORTER_ASSERT(r, pattern.third<Restore>() != NULL);
+}
+
+DEF_TEST(RecordPattern_StartingIndex, r) {
+ SaveClipRectRestore pattern;
+
+ SkRecord record;
+ SkRecorder recorder(&record, 1920, 1200);
+
+ // There will be two save-clipRect-restore blocks [0,3) and [3,6).
+ for (int i = 0; i < 2; i++) {
+ recorder.save();
+ recorder.clipRect(SkRect::MakeWH(300, 200));
+ recorder.restore();
+ }
+
+ // We should match only at 0 and 3. Going over the length should fail gracefully.
+ for (unsigned i = 0; i < 8; i++) {
+ if (i == 0 || i == 3) {
+ REPORTER_ASSERT(r, pattern.match(&record, i) == i + 3);
+ } else {
+ REPORTER_ASSERT(r, !pattern.match(&record, i));
+ }
+ }
+}
+
+DEF_TEST(RecordPattern_DontMatchSubsequences, r) {
+ SaveClipRectRestore pattern;
+
+ SkRecord record;
+ SkRecorder recorder(&record, 1920, 1200);
+
+ recorder.save();
+ recorder.clipRect(SkRect::MakeWH(300, 200));
+ recorder.drawRect(SkRect::MakeWH(600, 300), SkPaint());
+ recorder.restore();
+
+ REPORTER_ASSERT(r, !pattern.match(&record, 0));
+}
+
+DEF_TEST(RecordPattern_Star, r) {
+ Pattern3<Is<Save>, Star<Is<ClipRect> >, Is<Restore> > pattern;
+
+ SkRecord record;
+ SkRecorder recorder(&record, 1920, 1200);
+
+ recorder.save();
+ recorder.restore();
+ REPORTER_ASSERT(r, pattern.match(&record, 0));
+
+ recorder.save();
+ recorder.clipRect(SkRect::MakeWH(300, 200));
+ recorder.restore();
+ REPORTER_ASSERT(r, pattern.match(&record, 2));
+
+ recorder.save();
+ recorder.clipRect(SkRect::MakeWH(300, 200));
+ recorder.clipRect(SkRect::MakeWH(100, 100));
+ recorder.restore();
+ REPORTER_ASSERT(r, pattern.match(&record, 5));
+}
+
+DEF_TEST(RecordPattern_IsDraw, r) {
+ Pattern3<Is<Save>, IsDraw, Is<Restore> > pattern;
+
+ SkRecord record;
+ SkRecorder recorder(&record, 1920, 1200);
+
+ recorder.save();
+ recorder.clipRect(SkRect::MakeWH(300, 200));
+ recorder.restore();
+
+ REPORTER_ASSERT(r, !pattern.match(&record, 0));
+
+ SkPaint paint;
+
+ recorder.save();
+ paint.setColor(0xEEAA8822);
+ recorder.drawRect(SkRect::MakeWH(300, 200), paint);
+ recorder.restore();
+
+ recorder.save();
+ paint.setColor(0xFACEFACE);
+ recorder.drawPaint(paint);
+ recorder.restore();
+
+ REPORTER_ASSERT(r, pattern.match(&record, 3));
+ REPORTER_ASSERT(r, pattern.first<Save>() != NULL);
+ REPORTER_ASSERT(r, pattern.second<SkPaint>()->getColor() == 0xEEAA8822);
+ REPORTER_ASSERT(r, pattern.third<Restore>() != NULL);
+
+ REPORTER_ASSERT(r, pattern.match(&record, 6));
+ REPORTER_ASSERT(r, pattern.first<Save>() != NULL);
+ REPORTER_ASSERT(r, pattern.second<SkPaint>()->getColor() == 0xFACEFACE);
+ REPORTER_ASSERT(r, pattern.third<Restore>() != NULL);
+}
+
+DEF_TEST(RecordPattern_Complex, r) {
+ Pattern3<Is<Save>,
+ Star<Not<Or3<Is<Save>,
+ Is<Restore>,
+ IsDraw> > >,
+ Is<Restore> > pattern;
+
+ SkRecord record;
+ SkRecorder recorder(&record, 1920, 1200);
+
+ recorder.save();
+ recorder.restore();
+ REPORTER_ASSERT(r, pattern.match(&record, 0) == 2);
+
+ recorder.save();
+ recorder.save();
+ recorder.restore();
+ recorder.restore();
+ REPORTER_ASSERT(r, !pattern.match(&record, 2));
+ REPORTER_ASSERT(r, pattern.match(&record, 3) == 5);
+
+ recorder.save();
+ recorder.clipRect(SkRect::MakeWH(300, 200));
+ recorder.restore();
+ REPORTER_ASSERT(r, pattern.match(&record, 6) == 9);
+
+ recorder.save();
+ recorder.clipRect(SkRect::MakeWH(300, 200));
+ recorder.drawRect(SkRect::MakeWH(100, 3000), SkPaint());
+ recorder.restore();
+ REPORTER_ASSERT(r, !pattern.match(&record, 9));
+
+ recorder.save();
+ recorder.pushCull(SkRect::MakeWH(300, 200));
+ recorder.clipRect(SkRect::MakeWH(300, 200));
+ recorder.clipRect(SkRect::MakeWH(100, 400));
+ recorder.popCull();
+ recorder.restore();
+ REPORTER_ASSERT(r, pattern.match(&record, 13) == 19);
+
+ // Same as above, but using pattern.search to step through matches.
+ unsigned begin, end = 0;
+ REPORTER_ASSERT(r, pattern.search(&record, &begin, &end));
+ REPORTER_ASSERT(r, begin == 0);
+ REPORTER_ASSERT(r, end == 2);
+
+ REPORTER_ASSERT(r, pattern.search(&record, &begin, &end));
+ REPORTER_ASSERT(r, begin == 3);
+ REPORTER_ASSERT(r, end == 5);
+
+ REPORTER_ASSERT(r, pattern.search(&record, &begin, &end));
+ REPORTER_ASSERT(r, begin == 6);
+ REPORTER_ASSERT(r, end == 9);
+
+ REPORTER_ASSERT(r, pattern.search(&record, &begin, &end));
+ REPORTER_ASSERT(r, begin == 13);
+ REPORTER_ASSERT(r, end == 19);
+
+ REPORTER_ASSERT(r, !pattern.search(&record, &begin, &end));
+}
+
+DEF_TEST(RecordPattern_SaveLayerIsNotADraw, r) {
+ Pattern1<IsDraw> pattern;
+
+ SkRecord record;
+ SkRecorder recorder(&record, 1920, 1200);
+ recorder.saveLayer(NULL, NULL);
+
+ REPORTER_ASSERT(r, !pattern.match(&record, 0));
+}
diff --git a/src/third_party/skia/tests/RecordReplaceDrawTest.cpp b/src/third_party/skia/tests/RecordReplaceDrawTest.cpp
new file mode 100644
index 0000000..618be72
--- /dev/null
+++ b/src/third_party/skia/tests/RecordReplaceDrawTest.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#if SK_SUPPORT_GPU
+
+#include "Test.h"
+#include "RecordTestUtils.h"
+
+#include "SkBBHFactory.h"
+#include "SkRecordDraw.h"
+#include "SkRecorder.h"
+#include "SkUtils.h"
+#include "GrRecordReplaceDraw.h"
+
+static const int kWidth = 100;
+static const int kHeight = 100;
+
+class JustOneDraw : public SkDrawPictureCallback {
+public:
+ JustOneDraw() : fCalls(0) {}
+
+ virtual bool abortDrawing() SK_OVERRIDE { return fCalls++ > 0; }
+private:
+ int fCalls;
+};
+
+// Make sure the abort callback works
+DEF_TEST(RecordReplaceDraw_Abort, r) {
+ // Record two commands.
+ SkRecord record;
+ SkRecorder recorder(&record, kWidth, kHeight);
+ recorder.drawRect(SkRect::MakeWH(SkIntToScalar(kWidth), SkIntToScalar(kHeight)), SkPaint());
+ recorder.clipRect(SkRect::MakeWH(SkIntToScalar(kWidth), SkIntToScalar(kHeight)));
+
+ SkRecord rerecord;
+ SkRecorder canvas(&rerecord, kWidth, kHeight);
+
+ GrReplacements replacements;
+ JustOneDraw callback;
+ GrRecordReplaceDraw(record, &canvas, NULL/*bbh*/, &replacements, &callback);
+
+ REPORTER_ASSERT(r, 3 == rerecord.count());
+ assert_type<SkRecords::Save>(r, rerecord, 0);
+ assert_type<SkRecords::DrawRect>(r, rerecord, 1);
+ assert_type<SkRecords::Restore>(r, rerecord, 2);
+}
+
+// Make sure GrRecordReplaceDraw balances unbalanced saves
+DEF_TEST(RecordReplaceDraw_Unbalanced, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, kWidth, kHeight);
+ recorder.save(); // We won't balance this, but GrRecordReplaceDraw will for us.
+
+ SkRecord rerecord;
+ SkRecorder canvas(&rerecord, kWidth, kHeight);
+
+ GrReplacements replacements;
+ GrRecordReplaceDraw(record, &canvas, NULL/*bbh*/, &replacements, NULL/*callback*/);
+
+ REPORTER_ASSERT(r, 4 == rerecord.count());
+ assert_type<SkRecords::Save>(r, rerecord, 0);
+ assert_type<SkRecords::Save>(r, rerecord, 1);
+ assert_type<SkRecords::Restore>(r, rerecord, 2);
+ assert_type<SkRecords::Restore>(r, rerecord, 3);
+}
+
+static SkImage* make_image(SkColor color) {
+ const SkPMColor pmcolor = SkPreMultiplyColor(color);
+ const SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
+ const size_t rowBytes = info.minRowBytes();
+ const size_t size = rowBytes * info.height();
+
+ SkAutoMalloc addr(size);
+ sk_memset32((SkPMColor*)addr.get(), pmcolor, SkToInt(size >> 2));
+
+ return SkImage::NewRasterCopy(info, addr.get(), rowBytes);
+}
+
+// Test out the layer replacement functionality with and w/o a BBH
+void test_replacements(skiatest::Reporter* r, bool useBBH) {
+ SkRecord record;
+ SkRecorder recorder(&record, kWidth, kHeight);
+ SkAutoTDelete<SkPaint> paint(SkNEW(SkPaint));
+ recorder.saveLayer(NULL, paint);
+ recorder.clear(SK_ColorRED);
+ recorder.restore();
+ recorder.drawRect(SkRect::MakeWH(SkIntToScalar(kWidth/2), SkIntToScalar(kHeight/2)),
+ SkPaint());
+
+ GrReplacements replacements;
+ GrReplacements::ReplacementInfo* ri = replacements.push();
+ ri->fStart = 0;
+ ri->fStop = 2;
+ ri->fPos.set(0, 0);
+ ri->fImage = make_image(SK_ColorRED);
+ ri->fPaint = SkNEW(SkPaint);
+ ri->fSrcRect = SkIRect::MakeWH(kWidth, kHeight);
+
+ SkAutoTUnref<SkBBoxHierarchy> bbh;
+
+ if (useBBH) {
+ SkRTreeFactory factory;
+ bbh.reset((factory)(kWidth, kHeight));
+ SkRecordFillBounds(record, bbh);
+ }
+
+ SkRecord rerecord;
+ SkRecorder canvas(&rerecord, kWidth, kHeight);
+ GrRecordReplaceDraw(record, &canvas, bbh, &replacements, NULL/*callback*/);
+
+ REPORTER_ASSERT(r, 7 == rerecord.count());
+ assert_type<SkRecords::Save>(r, rerecord, 0);
+ assert_type<SkRecords::Save>(r, rerecord, 1);
+ assert_type<SkRecords::SetMatrix>(r, rerecord, 2);
+ assert_type<SkRecords::DrawBitmapRectToRect>(r, rerecord, 3);
+ assert_type<SkRecords::Restore>(r, rerecord, 4);
+ assert_type<SkRecords::DrawRect>(r, rerecord, 5);
+ assert_type<SkRecords::Restore>(r, rerecord, 6);
+}
+
+DEF_TEST(RecordReplaceDraw_Replace, r) { test_replacements(r, false); }
+DEF_TEST(RecordReplaceDraw_ReplaceWithBBH, r) { test_replacements(r, true); }
+
+#endif
diff --git a/src/third_party/skia/tests/RecordTest.cpp b/src/third_party/skia/tests/RecordTest.cpp
new file mode 100644
index 0000000..2a0e615
--- /dev/null
+++ b/src/third_party/skia/tests/RecordTest.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+
+#include "SkBitmap.h"
+#include "SkImageInfo.h"
+#include "SkShader.h"
+#include "SkRecord.h"
+#include "SkRecords.h"
+
+// Sums the area of any DrawRect command it sees.
+class AreaSummer {
+public:
+ AreaSummer() : fArea(0) {}
+
+ template <typename T> void operator()(const T&) { }
+
+ void operator()(const SkRecords::DrawRect& draw) {
+ fArea += (int)(draw.rect.width() * draw.rect.height());
+ }
+
+ int area() const { return fArea; }
+
+ void apply(const SkRecord& record) {
+ for (unsigned i = 0; i < record.count(); i++) {
+ record.visit<void>(i, *this);
+ }
+ }
+
+private:
+ int fArea;
+};
+
+// Scales out the bottom-right corner of any DrawRect command it sees by 2x.
+struct Stretch {
+ template <typename T> void operator()(T*) {}
+ void operator()(SkRecords::DrawRect* draw) {
+ draw->rect.fRight *= 2;
+ draw->rect.fBottom *= 2;
+ }
+
+ void apply(SkRecord* record) {
+ for (unsigned i = 0; i < record->count(); i++) {
+ record->mutate<void>(i, *this);
+ }
+ }
+};
+
+#define APPEND(record, type, ...) SkNEW_PLACEMENT_ARGS(record.append<type>(), type, (__VA_ARGS__))
+
+// Basic tests for the low-level SkRecord code.
+DEF_TEST(Record, r) {
+ SkRecord record;
+
+ // Add a simple DrawRect command.
+ SkRect rect = SkRect::MakeWH(10, 10);
+ SkPaint paint;
+ APPEND(record, SkRecords::DrawRect, paint, rect);
+
+ // Its area should be 100.
+ AreaSummer summer;
+ summer.apply(record);
+ REPORTER_ASSERT(r, summer.area() == 100);
+
+ // Scale 2x.
+ Stretch stretch;
+ stretch.apply(&record);
+
+ // Now its area should be 100 + 400.
+ summer.apply(record);
+ REPORTER_ASSERT(r, summer.area() == 500);
+}
+
+#undef APPEND
+
+template <typename T>
+static bool is_aligned(const T* p) {
+ return (((uintptr_t)p) & (sizeof(T) - 1)) == 0;
+}
+
+DEF_TEST(Record_Alignment, r) {
+ SkRecord record;
+
+ // Of course a byte's always aligned.
+ REPORTER_ASSERT(r, is_aligned(record.alloc<uint8_t>()));
+
+ // (If packed tightly, the rest below here would be off by one.)
+
+ // It happens that the first implementation always aligned to 4 bytes,
+ // so these two were always correct.
+ REPORTER_ASSERT(r, is_aligned(record.alloc<uint16_t>()));
+ REPORTER_ASSERT(r, is_aligned(record.alloc<uint32_t>()));
+
+ // These two are regression tests (void* only on 64-bit machines).
+ REPORTER_ASSERT(r, is_aligned(record.alloc<uint64_t>()));
+ REPORTER_ASSERT(r, is_aligned(record.alloc<void*>()));
+
+ // We're not testing beyond sizeof(void*), which is where the current implementation will break.
+}
+
diff --git a/src/third_party/skia/tests/RecordTestUtils.h b/src/third_party/skia/tests/RecordTestUtils.h
new file mode 100644
index 0000000..0575b83
--- /dev/null
+++ b/src/third_party/skia/tests/RecordTestUtils.h
@@ -0,0 +1,31 @@
+#ifndef RecordTestUtils_DEFINED
+#define RecordTestUtils_DEFINED
+
+#include "SkRecord.h"
+#include "SkRecords.h"
+
+// If the command we're reading is a U, set ptr to it, otherwise set it to NULL.
+template <typename U>
+struct ReadAs {
+ ReadAs() : ptr(NULL), type(SkRecords::Type(~0)) {}
+
+ const U* ptr;
+ SkRecords::Type type;
+
+ void operator()(const U& r) { ptr = &r; type = U::kType; }
+
+ template <typename T>
+ void operator()(const T&) { type = U::kType; }
+};
+
+// Assert that the ith command in record is of type T, and return it.
+template <typename T>
+static const T* assert_type(skiatest::Reporter* r, const SkRecord& record, unsigned index) {
+ ReadAs<T> reader;
+ record.visit<void>(index, reader);
+ REPORTER_ASSERT(r, T::kType == reader.type);
+ REPORTER_ASSERT(r, SkToBool(reader.ptr));
+ return reader.ptr;
+}
+
+#endif//RecordTestUtils_DEFINED
diff --git a/src/third_party/skia/tests/RecorderTest.cpp b/src/third_party/skia/tests/RecorderTest.cpp
new file mode 100644
index 0000000..aced54f
--- /dev/null
+++ b/src/third_party/skia/tests/RecorderTest.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+
+#include "SkPictureRecorder.h"
+#include "SkRecord.h"
+#include "SkRecorder.h"
+#include "SkRecords.h"
+#include "SkShader.h"
+
+#define COUNT(T) + 1
+static const int kRecordTypes = SK_RECORD_TYPES(COUNT);
+#undef COUNT
+
+// Tallies the types of commands it sees into a histogram.
+class Tally {
+public:
+ Tally() { sk_bzero(&fHistogram, sizeof(fHistogram)); }
+
+ template <typename T>
+ void operator()(const T&) { ++fHistogram[T::kType]; }
+
+ template <typename T>
+ int count() const { return fHistogram[T::kType]; }
+
+ void apply(const SkRecord& record) {
+ for (unsigned i = 0; i < record.count(); i++) {
+ record.visit<void>(i, *this);
+ }
+ }
+
+private:
+ int fHistogram[kRecordTypes];
+};
+
+DEF_TEST(Recorder, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, 1920, 1080);
+
+ recorder.drawRect(SkRect::MakeWH(10, 10), SkPaint());
+
+ Tally tally;
+ tally.apply(record);
+ REPORTER_ASSERT(r, 1 == tally.count<SkRecords::DrawRect>());
+}
+
+// All of Skia will work fine without support for comment groups, but
+// Chrome's inspector can break. This serves as a simple regression test.
+DEF_TEST(Recorder_CommentGroups, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, 1920, 1080);
+
+ recorder.beginCommentGroup("test");
+ recorder.addComment("foo", "bar");
+ recorder.addComment("baz", "quux");
+ recorder.endCommentGroup();
+
+ Tally tally;
+ tally.apply(record);
+
+ REPORTER_ASSERT(r, 1 == tally.count<SkRecords::BeginCommentGroup>());
+ REPORTER_ASSERT(r, 2 == tally.count<SkRecords::AddComment>());
+ REPORTER_ASSERT(r, 1 == tally.count<SkRecords::EndCommentGroup>());
+}
+
+// DrawData is similar to comment groups. It doesn't affect drawing, but
+// it's a pass-through we provide to the client. Again, a simple reg. test.
+DEF_TEST(Recorder_DrawData, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, 100, 100);
+
+ const char* data = "This sure is some data, eh?";
+ recorder.drawData(data, strlen(data));
+
+ Tally tally;
+ tally.apply(record);
+ REPORTER_ASSERT(r, 1 == tally.count<SkRecords::DrawData>());
+}
+
+// Regression test for leaking refs held by optional arguments.
+DEF_TEST(Recorder_RefLeaking, r) {
+ // We use SaveLayer to test:
+ // - its SkRect argument is optional and SkRect is POD. Just testing that that works.
+ // - its SkPaint argument is optional and SkPaint is not POD. The bug was here.
+
+ SkRect bounds = SkRect::MakeWH(320, 240);
+ SkPaint paint;
+ paint.setShader(SkShader::CreateEmptyShader())->unref();
+
+ REPORTER_ASSERT(r, paint.getShader()->unique());
+ {
+ SkRecord record;
+ SkRecorder recorder(&record, 1920, 1080);
+ recorder.saveLayer(&bounds, &paint);
+ REPORTER_ASSERT(r, !paint.getShader()->unique());
+ }
+ REPORTER_ASSERT(r, paint.getShader()->unique());
+}
+
+DEF_TEST(Recorder_RefPictures, r) {
+ SkAutoTUnref<SkPicture> pic;
+
+ {
+ SkPictureRecorder pr;
+ SkCanvas* canvas = pr.beginRecording(100, 100);
+ canvas->drawColor(SK_ColorRED);
+ pic.reset(pr.endRecording());
+ }
+ REPORTER_ASSERT(r, pic->unique());
+
+ {
+ SkRecord record;
+ SkRecorder recorder(&record, 100, 100);
+ recorder.drawPicture(pic);
+ // the recorder should now also be an owner
+ REPORTER_ASSERT(r, !pic->unique());
+ }
+ // the recorder destructor should have released us (back to unique)
+ REPORTER_ASSERT(r, pic->unique());
+}
+
+DEF_TEST(Recorder_IsDrawingToLayer, r) {
+ SkRecord record;
+ SkRecorder recorder(&record, 100, 100);
+
+ // We'll save, saveLayer, save, and saveLayer, then restore them all,
+ // checking that isDrawingToLayer() is correct at each step.
+
+ REPORTER_ASSERT(r, !recorder.isDrawingToLayer());
+ recorder.save();
+ REPORTER_ASSERT(r, !recorder.isDrawingToLayer());
+ recorder.saveLayer(NULL, NULL);
+ REPORTER_ASSERT(r, recorder.isDrawingToLayer());
+ recorder.save();
+ REPORTER_ASSERT(r, recorder.isDrawingToLayer());
+ recorder.saveLayer(NULL, NULL);
+ REPORTER_ASSERT(r, recorder.isDrawingToLayer());
+ recorder.restore();
+ REPORTER_ASSERT(r, recorder.isDrawingToLayer());
+ recorder.restore();
+ REPORTER_ASSERT(r, recorder.isDrawingToLayer());
+ recorder.restore();
+ REPORTER_ASSERT(r, !recorder.isDrawingToLayer());
+ recorder.restore();
+ REPORTER_ASSERT(r, !recorder.isDrawingToLayer());
+}
+
diff --git a/src/third_party/skia/tests/RecordingTest.cpp b/src/third_party/skia/tests/RecordingTest.cpp
new file mode 100644
index 0000000..0066556
--- /dev/null
+++ b/src/third_party/skia/tests/RecordingTest.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+
+#include "../include/record/SkRecording.h"
+
+// Minimally exercise the public SkRecording API.
+
+DEF_TEST(SkRecording, r) {
+ EXPERIMENTAL::SkRecording recording(1920, 1080);
+
+ // Some very exciting commands here.
+ recording.canvas()->clipRect(SkRect::MakeWH(320, 240));
+
+ SkAutoTDelete<const EXPERIMENTAL::SkPlayback> playback(recording.releasePlayback());
+
+ SkCanvas target;
+ playback->draw(&target);
+
+ // Here's another recording we never call releasePlayback().
+ // However pointless, this should be safe.
+ EXPERIMENTAL::SkRecording pointless(1920, 1080);
+ pointless.canvas()->clipRect(SkRect::MakeWH(320, 240));
+}
diff --git a/src/third_party/skia/tests/RecordingXfermodeTest.cpp b/src/third_party/skia/tests/RecordingXfermodeTest.cpp
new file mode 100644
index 0000000..8da81b3
--- /dev/null
+++ b/src/third_party/skia/tests/RecordingXfermodeTest.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+
+#include "../include/core/SkCanvas.h"
+#include "../include/core/SkPicture.h"
+#include "../include/core/SkStream.h"
+#include "../include/core/SkString.h"
+#include "../include/record/SkRecording.h"
+#include "../include/core/SkPictureRecorder.h"
+#include <cstring>
+
+// Verify that replay of a recording into a clipped canvas
+// produces the correct bitmap.
+// This arose from http://crbug.com/401593 which has
+// https://code.google.com/p/skia/issues/detail?id=1291 as its root cause.
+
+
+namespace {
+
+class Drawer {
+ public:
+ explicit Drawer()
+ : fImageInfo(SkImageInfo::MakeN32Premul(200,100))
+ {
+ fCircleBM.allocPixels( SkImageInfo::MakeN32Premul(100,100) );
+ SkCanvas canvas(fCircleBM);
+ canvas.clear(0xffffffff);
+ SkPaint circlePaint;
+ circlePaint.setColor(0xff000000);
+ canvas.drawCircle(50,50,50,circlePaint);
+ }
+
+ const SkImageInfo& imageInfo() const { return fImageInfo; }
+
+ void draw(SkCanvas* canvas, const SkRect& clipRect, SkXfermode::Mode mode) const {
+ SkPaint greenPaint;
+ greenPaint.setColor(0xff008000);
+ SkPaint blackPaint;
+ blackPaint.setColor(0xff000000);
+ SkPaint whitePaint;
+ whitePaint.setColor(0xffffffff);
+ SkPaint layerPaint;
+ layerPaint.setColor(0xff000000);
+ layerPaint.setXfermodeMode(mode);
+ SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fImageInfo.width()),SkIntToScalar(fImageInfo.height())));
+
+ canvas->clipRect(clipRect);
+ canvas->clear(0xff000000);
+
+ canvas->saveLayer(NULL,&blackPaint);
+ canvas->drawRect(canvasRect,greenPaint);
+ canvas->saveLayer(NULL,&layerPaint);
+ canvas->drawBitmapRect(fCircleBM,SkRect::MakeXYWH(20,20,60,60),&blackPaint);
+ canvas->restore();
+ canvas->restore();
+ }
+
+ private:
+ const SkImageInfo fImageInfo;
+ SkBitmap fCircleBM;
+};
+
+class RecordingStrategy {
+ public:
+ virtual ~RecordingStrategy() {}
+ virtual void init(const SkImageInfo&) = 0;
+ virtual const SkBitmap& recordAndReplay(const Drawer& drawer,
+ const SkRect& intoClip,
+ SkXfermode::Mode) = 0;
+};
+
+class BitmapBackedCanvasStrategy : public RecordingStrategy {
+ // This version just draws into a bitmap-backed canvas.
+ public:
+ BitmapBackedCanvasStrategy() {}
+
+ virtual void init(const SkImageInfo& imageInfo) {
+ fBitmap.allocPixels(imageInfo);
+ }
+
+ virtual const SkBitmap& recordAndReplay(const Drawer& drawer,
+ const SkRect& intoClip,
+ SkXfermode::Mode mode) {
+ SkCanvas canvas(fBitmap);
+ canvas.clear(0xffffffff);
+ // Note that the scene is drawn just into the clipped region!
+ canvas.clipRect(intoClip);
+ drawer.draw(&canvas, intoClip, mode); // Shouild be canvas-wide...
+ return fBitmap;
+ }
+
+ private:
+ SkBitmap fBitmap;
+};
+
+class DeprecatedRecorderStrategy : public RecordingStrategy {
+ // This version draws the entire scene into an SkPictureRecorder,
+ // using the deprecated recording backend.
+ // Then it then replays the scene through a clip rectangle.
+ // This backend proved to be buggy.
+ public:
+ DeprecatedRecorderStrategy() {}
+
+ virtual void init(const SkImageInfo& imageInfo) {
+ fBitmap.allocPixels(imageInfo);
+ fWidth = imageInfo.width();
+ fHeight= imageInfo.height();
+ }
+
+ virtual const SkBitmap& recordAndReplay(const Drawer& drawer,
+ const SkRect& intoClip,
+ SkXfermode::Mode mode) {
+ SkTileGridFactory::TileGridInfo tileGridInfo = { {100,100}, {0,0}, {0,0} };
+ SkTileGridFactory factory(tileGridInfo);
+ SkPictureRecorder recorder;
+ SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fWidth),SkIntToScalar(fHeight)));
+ SkCanvas* canvas = recorder.DEPRECATED_beginRecording( SkIntToScalar(fWidth), SkIntToScalar(fHeight), &factory);
+ drawer.draw(canvas, canvasRect, mode);
+ SkAutoTDelete<SkPicture> picture(recorder.endRecording());
+
+ SkCanvas replayCanvas(fBitmap);
+ replayCanvas.clear(0xffffffff);
+ replayCanvas.clipRect(intoClip);
+ picture->playback(&replayCanvas);
+
+ return fBitmap;
+ }
+
+ private:
+ SkBitmap fBitmap;
+ int fWidth;
+ int fHeight;
+};
+
+class NewRecordingStrategy : public RecordingStrategy {
+ // This version draws the entire scene into an SkPictureRecorder,
+ // using the new recording backend.
+ // Then it then replays the scene through a clip rectangle.
+ // This backend proved to be buggy.
+ public:
+ NewRecordingStrategy() {}
+
+ virtual void init(const SkImageInfo& imageInfo) {
+ fBitmap.allocPixels(imageInfo);
+ fWidth = imageInfo.width();
+ fHeight= imageInfo.height();
+ }
+
+ virtual const SkBitmap& recordAndReplay(const Drawer& drawer,
+ const SkRect& intoClip,
+ SkXfermode::Mode mode) {
+ SkTileGridFactory::TileGridInfo tileGridInfo = { {100,100}, {0,0}, {0,0} };
+ SkTileGridFactory factory(tileGridInfo);
+ SkPictureRecorder recorder;
+ SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fWidth),SkIntToScalar(fHeight)));
+ SkCanvas* canvas = recorder.EXPERIMENTAL_beginRecording( SkIntToScalar(fWidth), SkIntToScalar(fHeight), &factory);
+
+ drawer.draw(canvas, canvasRect, mode);
+ SkAutoTDelete<SkPicture> picture(recorder.endRecording());
+
+ SkCanvas replayCanvas(fBitmap);
+ replayCanvas.clear(0xffffffff);
+ replayCanvas.clipRect(intoClip);
+ picture->playback(&replayCanvas);
+ return fBitmap;
+ }
+
+ private:
+ SkBitmap fBitmap;
+ int fWidth;
+ int fHeight;
+};
+
+}
+
+
+
+DEF_TEST(SkRecordingAccuracyXfermode, reporter) {
+#define FINEGRAIN 0
+
+ const Drawer drawer;
+
+ BitmapBackedCanvasStrategy golden; // This is the expected result.
+ DeprecatedRecorderStrategy deprecatedRecording;
+ NewRecordingStrategy newRecording;
+
+ golden.init(drawer.imageInfo());
+ deprecatedRecording.init(drawer.imageInfo());
+ newRecording.init(drawer.imageInfo());
+
+#if !FINEGRAIN
+ unsigned numErrors = 0;
+ SkString errors;
+#endif
+
+ for (int iMode = 0; iMode < int(SkXfermode::kLastMode) ; iMode++ ) {
+ const SkRect& clip = SkRect::MakeXYWH(100,0,100,100);
+ SkXfermode::Mode mode = SkXfermode::Mode(iMode);
+
+ const SkBitmap& goldenBM = golden.recordAndReplay(drawer, clip, mode);
+ const SkBitmap& deprecatedBM = deprecatedRecording.recordAndReplay(drawer, clip, mode);
+ const SkBitmap& newRecordingBM = newRecording.recordAndReplay(drawer, clip, mode);
+
+ size_t pixelsSize = goldenBM.getSize();
+ REPORTER_ASSERT( reporter, pixelsSize == deprecatedBM.getSize() );
+ REPORTER_ASSERT( reporter, pixelsSize == newRecordingBM.getSize() );
+
+ // The pixel arrays should match.
+#if FINEGRAIN
+ REPORTER_ASSERT_MESSAGE( reporter,
+ 0==memcmp( goldenBM.getPixels(), deprecatedBM.getPixels(), pixelsSize ),
+ "Tiled bitmap is wrong");
+ REPORTER_ASSERT_MESSAGE( reporter,
+ 0==memcmp( goldenBM.getPixels(), recordingBM.getPixels(), pixelsSize ),
+ "SkRecorder bitmap is wrong");
+#else
+ if ( memcmp( goldenBM.getPixels(), deprecatedBM.getPixels(), pixelsSize ) ) {
+ numErrors++;
+ SkString str;
+ str.printf("For SkXfermode %d %s: Deprecated recorder bitmap is wrong\n", iMode, SkXfermode::ModeName(mode));
+ errors.append(str);
+ }
+ if ( memcmp( goldenBM.getPixels(), newRecordingBM.getPixels(), pixelsSize ) ) {
+ numErrors++;
+ SkString str;
+ str.printf("For SkXfermode %d %s: SkPictureRecorder bitmap is wrong\n", iMode, SkXfermode::ModeName(mode));
+ errors.append(str);
+ }
+#endif
+ }
+#if !FINEGRAIN
+ REPORTER_ASSERT_MESSAGE( reporter, 0==numErrors, errors.c_str() );
+#endif
+}
diff --git a/src/third_party/skia/tests/RefCntTest.cpp b/src/third_party/skia/tests/RefCntTest.cpp
new file mode 100644
index 0000000..bd4f348
--- /dev/null
+++ b/src/third_party/skia/tests/RefCntTest.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRefCnt.h"
+#include "SkTRefArray.h"
+#include "SkThreadUtils.h"
+#include "SkTypes.h"
+#include "SkWeakRefCnt.h"
+#include "Test.h"
+
+class InstCounterClass {
+public:
+ InstCounterClass() { fCount = gInstCounter++; }
+ InstCounterClass(const InstCounterClass& src) {
+ fCount = src.fCount;
+ gInstCounter += 1;
+ }
+ virtual ~InstCounterClass() { gInstCounter -= 1; }
+
+ static int gInstCounter;
+ int fCount;
+};
+
+int InstCounterClass::gInstCounter;
+
+static void test_refarray(skiatest::Reporter* reporter) {
+ REPORTER_ASSERT(reporter, 0 == InstCounterClass::gInstCounter);
+
+ const int N = 10;
+ SkTRefArray<InstCounterClass>* array = SkTRefArray<InstCounterClass>::Create(N);
+
+ REPORTER_ASSERT(reporter, 1 == array->getRefCnt());
+ REPORTER_ASSERT(reporter, N == array->count());
+
+ REPORTER_ASSERT(reporter, N == InstCounterClass::gInstCounter);
+ array->unref();
+ REPORTER_ASSERT(reporter, 0 == InstCounterClass::gInstCounter);
+
+ // Now test the copy factory
+
+ int i;
+ InstCounterClass* src = new InstCounterClass[N];
+ REPORTER_ASSERT(reporter, N == InstCounterClass::gInstCounter);
+ for (i = 0; i < N; ++i) {
+ REPORTER_ASSERT(reporter, i == src[i].fCount);
+ }
+
+ array = SkTRefArray<InstCounterClass>::Create(src, N);
+ REPORTER_ASSERT(reporter, 1 == array->getRefCnt());
+ REPORTER_ASSERT(reporter, N == array->count());
+
+ REPORTER_ASSERT(reporter, 2*N == InstCounterClass::gInstCounter);
+ for (i = 0; i < N; ++i) {
+ REPORTER_ASSERT(reporter, i == (*array)[i].fCount);
+ }
+
+ delete[] src;
+ REPORTER_ASSERT(reporter, N == InstCounterClass::gInstCounter);
+
+ for (i = 0; i < N; ++i) {
+ REPORTER_ASSERT(reporter, i == (*array)[i].fCount);
+ }
+ array->unref();
+ REPORTER_ASSERT(reporter, 0 == InstCounterClass::gInstCounter);
+}
+
+static void bounce_ref(void* data) {
+ SkRefCnt* ref = static_cast<SkRefCnt*>(data);
+ for (int i = 0; i < 100000; ++i) {
+ ref->ref();
+ ref->unref();
+ }
+}
+
+static void test_refCnt(skiatest::Reporter* reporter) {
+ SkRefCnt* ref = new SkRefCnt();
+
+ SkThread thing1(bounce_ref, ref);
+ SkThread thing2(bounce_ref, ref);
+
+ thing1.setProcessorAffinity(0);
+ thing2.setProcessorAffinity(23);
+
+ SkASSERT(thing1.start());
+ SkASSERT(thing2.start());
+
+ thing1.join();
+ thing2.join();
+
+ REPORTER_ASSERT(reporter, ref->getRefCnt() == 1);
+ ref->unref();
+}
+
+static void bounce_weak_ref(void* data) {
+ SkWeakRefCnt* ref = static_cast<SkWeakRefCnt*>(data);
+ for (int i = 0; i < 100000; ++i) {
+ if (ref->try_ref()) {
+ ref->unref();
+ }
+ }
+}
+
+static void bounce_weak_weak_ref(void* data) {
+ SkWeakRefCnt* ref = static_cast<SkWeakRefCnt*>(data);
+ for (int i = 0; i < 100000; ++i) {
+ ref->weak_ref();
+ ref->weak_unref();
+ }
+}
+
+static void test_weakRefCnt(skiatest::Reporter* reporter) {
+ SkWeakRefCnt* ref = new SkWeakRefCnt();
+
+ SkThread thing1(bounce_ref, ref);
+ SkThread thing2(bounce_ref, ref);
+ SkThread thing3(bounce_weak_ref, ref);
+ SkThread thing4(bounce_weak_weak_ref, ref);
+
+ thing1.setProcessorAffinity(0);
+ thing2.setProcessorAffinity(23);
+ thing3.setProcessorAffinity(2);
+ thing4.setProcessorAffinity(17);
+
+ SkASSERT(thing1.start());
+ SkASSERT(thing2.start());
+ SkASSERT(thing3.start());
+ SkASSERT(thing4.start());
+
+ thing1.join();
+ thing2.join();
+ thing3.join();
+ thing4.join();
+
+ REPORTER_ASSERT(reporter, ref->getRefCnt() == 1);
+ REPORTER_ASSERT(reporter, ref->getWeakCnt() == 1);
+ ref->unref();
+}
+
+DEF_TEST(RefCnt, reporter) {
+ test_refCnt(reporter);
+ test_weakRefCnt(reporter);
+ test_refarray(reporter);
+}
diff --git a/src/third_party/skia/tests/RefDictTest.cpp b/src/third_party/skia/tests/RefDictTest.cpp
new file mode 100644
index 0000000..1e18a68
--- /dev/null
+++ b/src/third_party/skia/tests/RefDictTest.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRefDict.h"
+#include "Test.h"
+
+class TestRC : public SkRefCnt {
+public:
+ SK_DECLARE_INST_COUNT(TestRC)
+private:
+ typedef SkRefCnt INHERITED;
+};
+
+DEF_TEST(RefDict, reporter) {
+ TestRC data0, data1;
+ SkRefDict dict;
+
+ REPORTER_ASSERT(reporter, NULL == dict.find(NULL));
+ REPORTER_ASSERT(reporter, NULL == dict.find("foo"));
+ REPORTER_ASSERT(reporter, NULL == dict.find("bar"));
+
+ dict.set("foo", &data0);
+ REPORTER_ASSERT(reporter, &data0 == dict.find("foo"));
+ REPORTER_ASSERT(reporter, 2 == data0.getRefCnt());
+
+ dict.set("foo", &data0);
+ REPORTER_ASSERT(reporter, &data0 == dict.find("foo"));
+ REPORTER_ASSERT(reporter, 2 == data0.getRefCnt());
+
+ dict.set("foo", &data1);
+ REPORTER_ASSERT(reporter, &data1 == dict.find("foo"));
+ REPORTER_ASSERT(reporter, 1 == data0.getRefCnt());
+ REPORTER_ASSERT(reporter, 2 == data1.getRefCnt());
+
+ dict.set("foo", NULL);
+ REPORTER_ASSERT(reporter, NULL == dict.find("foo"));
+ REPORTER_ASSERT(reporter, 1 == data0.getRefCnt());
+ REPORTER_ASSERT(reporter, 1 == data1.getRefCnt());
+
+ dict.set("foo", &data0);
+ dict.set("bar", &data1);
+ REPORTER_ASSERT(reporter, &data0 == dict.find("foo"));
+ REPORTER_ASSERT(reporter, &data1 == dict.find("bar"));
+ REPORTER_ASSERT(reporter, 2 == data0.getRefCnt());
+ REPORTER_ASSERT(reporter, 2 == data1.getRefCnt());
+
+ dict.set("foo", &data1);
+ REPORTER_ASSERT(reporter, &data1 == dict.find("foo"));
+ REPORTER_ASSERT(reporter, &data1 == dict.find("bar"));
+ REPORTER_ASSERT(reporter, 1 == data0.getRefCnt());
+ REPORTER_ASSERT(reporter, 3 == data1.getRefCnt());
+
+ dict.removeAll();
+ REPORTER_ASSERT(reporter, NULL == dict.find("foo"));
+ REPORTER_ASSERT(reporter, NULL == dict.find("bar"));
+ REPORTER_ASSERT(reporter, 1 == data0.getRefCnt());
+ REPORTER_ASSERT(reporter, 1 == data1.getRefCnt());
+
+ {
+ SkRefDict d;
+ REPORTER_ASSERT(reporter, NULL == d.find("foo"));
+ REPORTER_ASSERT(reporter, 1 == data0.getRefCnt());
+ d.set("foo", &data0);
+ REPORTER_ASSERT(reporter, &data0 == d.find("foo"));
+ REPORTER_ASSERT(reporter, 2 == data0.getRefCnt());
+ // let d go out of scope still with a ref on data0
+ }
+ // be sure d's destructor lowered data0's owner count back to 1
+ REPORTER_ASSERT(reporter, 1 == data0.getRefCnt());
+}
diff --git a/src/third_party/skia/tests/RegionTest.cpp b/src/third_party/skia/tests/RegionTest.cpp
new file mode 100644
index 0000000..ae58ae6
--- /dev/null
+++ b/src/third_party/skia/tests/RegionTest.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "Test.h"
+
+static void Union(SkRegion* rgn, const SkIRect& rect) {
+ rgn->op(rect, SkRegion::kUnion_Op);
+}
+
+#define TEST_NO_INTERSECT(rgn, rect) REPORTER_ASSERT(reporter, !rgn.intersects(rect))
+#define TEST_INTERSECT(rgn, rect) REPORTER_ASSERT(reporter, rgn.intersects(rect))
+#define TEST_NO_CONTAINS(rgn, rect) REPORTER_ASSERT(reporter, !rgn.contains(rect))
+
+// inspired by http://code.google.com/p/skia/issues/detail?id=958
+//
+static void test_fromchrome(skiatest::Reporter* reporter) {
+ SkRegion r;
+ Union(&r, SkIRect::MakeXYWH(0, 0, 1, 1));
+ TEST_NO_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 0, 0));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 2, 2));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, 0, 2, 2));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 2, 2));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(0, -1, 2, 2));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 3, 3));
+
+ Union(&r, SkIRect::MakeXYWH(0, 0, 3, 3));
+ Union(&r, SkIRect::MakeXYWH(10, 0, 3, 3));
+ Union(&r, SkIRect::MakeXYWH(0, 10, 13, 3));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, -1, 2, 2));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 2, 2));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 2, 2, 2));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(-1, 2, 2, 2));
+
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(9, -1, 2, 2));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(12, -1, 2, 2));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(12, 2, 2, 2));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(9, 2, 2, 2));
+
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(0, -1, 13, 5));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(1, -1, 11, 5));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 9, 5));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(2, -1, 8, 5));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(3, -1, 8, 5));
+
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 1, 13, 1));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(1, 1, 11, 1));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 1, 9, 1));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(2, 1, 8, 1));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(3, 1, 8, 1));
+
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 0, 13, 13));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 1, 13, 11));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 2, 13, 9));
+ TEST_INTERSECT(r, SkIRect::MakeXYWH(0, 2, 13, 8));
+
+
+ // These test SkRegion::contains(Rect) and SkRegion::contains(Region)
+
+ SkRegion container;
+ Union(&container, SkIRect::MakeXYWH(0, 0, 40, 20));
+ Union(&container, SkIRect::MakeXYWH(30, 20, 10, 20));
+ TEST_NO_CONTAINS(container, SkIRect::MakeXYWH(0, 0, 10, 39));
+ TEST_NO_CONTAINS(container, SkIRect::MakeXYWH(29, 0, 10, 39));
+
+ {
+ SkRegion rgn;
+ Union(&rgn, SkIRect::MakeXYWH(0, 0, 10, 10));
+ Union(&rgn, SkIRect::MakeLTRB(5, 10, 20, 20));
+ TEST_INTERSECT(rgn, SkIRect::MakeXYWH(15, 0, 5, 11));
+ }
+}
+
+static void test_empties(skiatest::Reporter* reporter) {
+ SkRegion valid(SkIRect::MakeWH(10, 10));
+ SkRegion empty, empty2;
+
+ REPORTER_ASSERT(reporter, empty.isEmpty());
+ REPORTER_ASSERT(reporter, !valid.isEmpty());
+
+ // test intersects
+ REPORTER_ASSERT(reporter, !empty.intersects(empty2));
+ REPORTER_ASSERT(reporter, !valid.intersects(empty));
+
+ // test contains
+ REPORTER_ASSERT(reporter, !empty.contains(empty2));
+ REPORTER_ASSERT(reporter, !valid.contains(empty));
+ REPORTER_ASSERT(reporter, !empty.contains(valid));
+}
+
+enum {
+ W = 256,
+ H = 256
+};
+
+static SkIRect randRect(SkRandom& rand) {
+ int x = rand.nextU() % W;
+ int y = rand.nextU() % H;
+ int w = rand.nextU() % W;
+ int h = rand.nextU() % H;
+ return SkIRect::MakeXYWH(x, y, w >> 1, h >> 1);
+}
+
+static void randRgn(SkRandom& rand, SkRegion* rgn, int n) {
+ rgn->setEmpty();
+ for (int i = 0; i < n; ++i) {
+ rgn->op(randRect(rand), SkRegion::kUnion_Op);
+ }
+}
+
+static bool slow_contains(const SkRegion& outer, const SkRegion& inner) {
+ SkRegion tmp;
+ tmp.op(outer, inner, SkRegion::kUnion_Op);
+ return outer == tmp;
+}
+
+static bool slow_contains(const SkRegion& outer, const SkIRect& r) {
+ SkRegion tmp;
+ tmp.op(outer, SkRegion(r), SkRegion::kUnion_Op);
+ return outer == tmp;
+}
+
+static bool slow_intersects(const SkRegion& outer, const SkRegion& inner) {
+ SkRegion tmp;
+ return tmp.op(outer, inner, SkRegion::kIntersect_Op);
+}
+
+static void test_contains_iter(skiatest::Reporter* reporter, const SkRegion& rgn) {
+ SkRegion::Iterator iter(rgn);
+ while (!iter.done()) {
+ SkIRect r = iter.rect();
+ REPORTER_ASSERT(reporter, rgn.contains(r));
+ r.inset(-1, -1);
+ REPORTER_ASSERT(reporter, !rgn.contains(r));
+ iter.next();
+ }
+}
+
+static void contains_proc(skiatest::Reporter* reporter,
+ const SkRegion& a, const SkRegion& b) {
+ // test rgn
+ bool c0 = a.contains(b);
+ bool c1 = slow_contains(a, b);
+ REPORTER_ASSERT(reporter, c0 == c1);
+
+ // test rect
+ SkIRect r = a.getBounds();
+ r.inset(r.width()/4, r.height()/4);
+ c0 = a.contains(r);
+ c1 = slow_contains(a, r);
+ REPORTER_ASSERT(reporter, c0 == c1);
+
+ test_contains_iter(reporter, a);
+ test_contains_iter(reporter, b);
+}
+
+static void test_intersects_iter(skiatest::Reporter* reporter, const SkRegion& rgn) {
+ SkRegion::Iterator iter(rgn);
+ while (!iter.done()) {
+ SkIRect r = iter.rect();
+ REPORTER_ASSERT(reporter, rgn.intersects(r));
+ r.inset(-1, -1);
+ REPORTER_ASSERT(reporter, rgn.intersects(r));
+ iter.next();
+ }
+}
+
+static void intersects_proc(skiatest::Reporter* reporter,
+ const SkRegion& a, const SkRegion& b) {
+ bool c0 = a.intersects(b);
+ bool c1 = slow_intersects(a, b);
+ REPORTER_ASSERT(reporter, c0 == c1);
+
+ test_intersects_iter(reporter, a);
+ test_intersects_iter(reporter, b);
+}
+
+static void test_proc(skiatest::Reporter* reporter,
+ void (*proc)(skiatest::Reporter*,
+ const SkRegion& a, const SkRegion&)) {
+ SkRandom rand;
+ for (int i = 0; i < 10000; ++i) {
+ SkRegion outer;
+ randRgn(rand, &outer, 8);
+ SkRegion inner;
+ randRgn(rand, &inner, 2);
+ proc(reporter, outer, inner);
+ }
+}
+
+static void rand_rect(SkIRect* rect, SkRandom& rand) {
+ int bits = 6;
+ int shift = 32 - bits;
+ rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
+ rand.nextU() >> shift, rand.nextU() >> shift);
+ rect->sort();
+}
+
+static bool test_rects(const SkIRect rect[], int count) {
+ SkRegion rgn0, rgn1;
+
+ for (int i = 0; i < count; i++) {
+ rgn0.op(rect[i], SkRegion::kUnion_Op);
+ }
+ rgn1.setRects(rect, count);
+
+ if (rgn0 != rgn1) {
+ SkDebugf("\n");
+ for (int i = 0; i < count; i++) {
+ SkDebugf(" { %d, %d, %d, %d },\n",
+ rect[i].fLeft, rect[i].fTop,
+ rect[i].fRight, rect[i].fBottom);
+ }
+ SkDebugf("\n");
+ return false;
+ }
+ return true;
+}
+
+DEF_TEST(Region, reporter) {
+ const SkIRect r2[] = {
+ { 0, 0, 1, 1 },
+ { 2, 2, 3, 3 },
+ };
+ REPORTER_ASSERT(reporter, test_rects(r2, SK_ARRAY_COUNT(r2)));
+
+ const SkIRect rects[] = {
+ { 0, 0, 1, 2 },
+ { 2, 1, 3, 3 },
+ { 4, 0, 5, 1 },
+ { 6, 0, 7, 4 },
+ };
+ REPORTER_ASSERT(reporter, test_rects(rects, SK_ARRAY_COUNT(rects)));
+
+ SkRandom rand;
+ for (int i = 0; i < 1000; i++) {
+ SkRegion rgn0, rgn1;
+
+ const int N = 8;
+ SkIRect rect[N];
+ for (int j = 0; j < N; j++) {
+ rand_rect(&rect[j], rand);
+ }
+ REPORTER_ASSERT(reporter, test_rects(rect, N));
+ }
+
+ test_proc(reporter, contains_proc);
+ test_proc(reporter, intersects_proc);
+ test_empties(reporter);
+ test_fromchrome(reporter);
+}
diff --git a/src/third_party/skia/tests/ResourceCacheTest.cpp b/src/third_party/skia/tests/ResourceCacheTest.cpp
new file mode 100644
index 0000000..f9f94d1
--- /dev/null
+++ b/src/third_party/skia/tests/ResourceCacheTest.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#if SK_SUPPORT_GPU
+
+#include "SkCanvas.h"
+#include "GrContextFactory.h"
+#include "GrResourceCache.h"
+#include "SkSurface.h"
+#include "Test.h"
+
+static const int gWidth = 640;
+static const int gHeight = 480;
+
+////////////////////////////////////////////////////////////////////////////////
+static void test_cache(skiatest::Reporter* reporter,
+ GrContext* context,
+ SkCanvas* canvas) {
+ const SkIRect size = SkIRect::MakeWH(gWidth, gHeight);
+
+ SkBitmap src;
+ src.allocN32Pixels(size.width(), size.height());
+ src.eraseColor(SK_ColorBLACK);
+ size_t srcSize = src.getSize();
+
+ size_t initialCacheSize;
+ context->getResourceCacheUsage(NULL, &initialCacheSize);
+
+ int oldMaxNum;
+ size_t oldMaxBytes;
+ context->getResourceCacheLimits(&oldMaxNum, &oldMaxBytes);
+
+ // Set the cache limits so we can fit 10 "src" images and the
+ // max number of textures doesn't matter
+ size_t maxCacheSize = initialCacheSize + 10*srcSize;
+ context->setResourceCacheLimits(1000, maxCacheSize);
+
+ SkBitmap readback;
+ readback.allocN32Pixels(size.width(), size.height());
+
+ for (int i = 0; i < 100; ++i) {
+ canvas->drawBitmap(src, 0, 0);
+ canvas->readPixels(size, &readback);
+
+ // "modify" the src texture
+ src.notifyPixelsChanged();
+
+ size_t curCacheSize;
+ context->getResourceCacheUsage(NULL, &curCacheSize);
+
+ // we should never go over the size limit
+ REPORTER_ASSERT(reporter, curCacheSize <= maxCacheSize);
+ }
+
+ context->setResourceCacheLimits(oldMaxNum, oldMaxBytes);
+}
+
+class TestResource : public GrGpuResource {
+ static const size_t kDefaultSize = 100;
+
+public:
+ SK_DECLARE_INST_COUNT(TestResource);
+ TestResource(GrGpu* gpu, size_t size = kDefaultSize)
+ : INHERITED(gpu, false)
+ , fCache(NULL)
+ , fToDelete(NULL)
+ , fSize(size) {
+ ++fAlive;
+ this->registerWithCache();
+ }
+
+ ~TestResource() {
+ --fAlive;
+ if (fToDelete) {
+ // Breaks our little 2-element cycle below.
+ fToDelete->setDeleteWhenDestroyed(NULL, NULL);
+ fCache->deleteResource(fToDelete->getCacheEntry());
+ }
+ this->release();
+ }
+
+ void setSize(size_t size) {
+ fSize = size;
+ this->didChangeGpuMemorySize();
+ }
+
+ size_t gpuMemorySize() const SK_OVERRIDE { return fSize; }
+
+ static int alive() { return fAlive; }
+
+ void setDeleteWhenDestroyed(GrResourceCache* cache, TestResource* resource) {
+ fCache = cache;
+ fToDelete = resource;
+ }
+
+private:
+ GrResourceCache* fCache;
+ TestResource* fToDelete;
+ size_t fSize;
+ static int fAlive;
+
+ typedef GrGpuResource INHERITED;
+};
+int TestResource::fAlive = 0;
+
+static void test_purge_invalidated(skiatest::Reporter* reporter, GrContext* context) {
+ GrCacheID::Domain domain = GrCacheID::GenerateDomain();
+ GrCacheID::Key keyData;
+ keyData.fData64[0] = 5;
+ keyData.fData64[1] = 18;
+ GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
+ GrResourceKey key(GrCacheID(domain, keyData), t, 0);
+
+ GrResourceCache cache(5, 30000);
+
+ // Add two resources with the same key that delete each other from the cache when destroyed.
+ TestResource* a = new TestResource(context->getGpu());
+ TestResource* b = new TestResource(context->getGpu());
+ cache.addResource(key, a);
+ cache.addResource(key, b);
+ // Circle back.
+ a->setDeleteWhenDestroyed(&cache, b);
+ b->setDeleteWhenDestroyed(&cache, a);
+ a->unref();
+ b->unref();
+
+ // Add a third independent resource also with the same key.
+ GrGpuResource* r = new TestResource(context->getGpu());
+ cache.addResource(key, r);
+ r->unref();
+
+ // Invalidate all three, all three should be purged and destroyed.
+ REPORTER_ASSERT(reporter, 3 == TestResource::alive());
+ const GrResourceInvalidatedMessage msg = { key };
+ SkMessageBus<GrResourceInvalidatedMessage>::Post(msg);
+ cache.purgeAsNeeded();
+ REPORTER_ASSERT(reporter, 0 == TestResource::alive());
+}
+
+static void test_cache_delete_on_destruction(skiatest::Reporter* reporter,
+ GrContext* context) {
+ GrCacheID::Domain domain = GrCacheID::GenerateDomain();
+ GrCacheID::Key keyData;
+ keyData.fData64[0] = 5;
+ keyData.fData64[1] = 0;
+ GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
+
+ GrResourceKey key(GrCacheID(domain, keyData), t, 0);
+
+ {
+ {
+ GrResourceCache cache(3, 30000);
+ TestResource* a = new TestResource(context->getGpu());
+ TestResource* b = new TestResource(context->getGpu());
+ cache.addResource(key, a);
+ cache.addResource(key, b);
+
+ a->setDeleteWhenDestroyed(&cache, b);
+ b->setDeleteWhenDestroyed(&cache, a);
+
+ a->unref();
+ b->unref();
+ REPORTER_ASSERT(reporter, 2 == TestResource::alive());
+ }
+ REPORTER_ASSERT(reporter, 0 == TestResource::alive());
+ }
+ {
+ GrResourceCache cache(3, 30000);
+ TestResource* a = new TestResource(context->getGpu());
+ TestResource* b = new TestResource(context->getGpu());
+ cache.addResource(key, a);
+ cache.addResource(key, b);
+
+ a->setDeleteWhenDestroyed(&cache, b);
+ b->setDeleteWhenDestroyed(&cache, a);
+
+ a->unref();
+ b->unref();
+
+ cache.deleteResource(a->getCacheEntry());
+
+ REPORTER_ASSERT(reporter, 0 == TestResource::alive());
+ }
+}
+
+static void test_resource_size_changed(skiatest::Reporter* reporter,
+ GrContext* context) {
+ GrCacheID::Domain domain = GrCacheID::GenerateDomain();
+ GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
+
+ GrCacheID::Key key1Data;
+ key1Data.fData64[0] = 0;
+ key1Data.fData64[1] = 0;
+ GrResourceKey key1(GrCacheID(domain, key1Data), t, 0);
+
+ GrCacheID::Key key2Data;
+ key2Data.fData64[0] = 1;
+ key2Data.fData64[1] = 0;
+ GrResourceKey key2(GrCacheID(domain, key2Data), t, 0);
+
+ // Test changing resources sizes (both increase & decrease).
+ {
+ GrResourceCache cache(2, 300);
+
+ TestResource* a = new TestResource(context->getGpu());
+ a->setSize(100); // Test didChangeGpuMemorySize() when not in the cache.
+ cache.addResource(key1, a);
+ a->unref();
+
+ TestResource* b = new TestResource(context->getGpu());
+ b->setSize(100);
+ cache.addResource(key2, b);
+ b->unref();
+
+ REPORTER_ASSERT(reporter, 200 == cache.getCachedResourceBytes());
+ REPORTER_ASSERT(reporter, 2 == cache.getCachedResourceCount());
+
+ static_cast<TestResource*>(cache.find(key2))->setSize(200);
+ static_cast<TestResource*>(cache.find(key1))->setSize(50);
+
+ REPORTER_ASSERT(reporter, 250 == cache.getCachedResourceBytes());
+ REPORTER_ASSERT(reporter, 2 == cache.getCachedResourceCount());
+ }
+
+ // Test increasing a resources size beyond the cache budget.
+ {
+ GrResourceCache cache(2, 300);
+
+ TestResource* a = new TestResource(context->getGpu(), 100);
+ cache.addResource(key1, a);
+ a->unref();
+
+ TestResource* b = new TestResource(context->getGpu(), 100);
+ cache.addResource(key2, b);
+ b->unref();
+
+ REPORTER_ASSERT(reporter, 200 == cache.getCachedResourceBytes());
+ REPORTER_ASSERT(reporter, 2 == cache.getCachedResourceCount());
+
+ static_cast<TestResource*>(cache.find(key2))->setSize(201);
+ REPORTER_ASSERT(reporter, NULL == cache.find(key1));
+
+ REPORTER_ASSERT(reporter, 201 == cache.getCachedResourceBytes());
+ REPORTER_ASSERT(reporter, 1 == cache.getCachedResourceCount());
+ }
+
+ // Test changing the size of an exclusively-held resource.
+ {
+ GrResourceCache cache(2, 300);
+
+ TestResource* a = new TestResource(context->getGpu(), 100);
+ cache.addResource(key1, a);
+ cache.makeExclusive(a->getCacheEntry());
+
+ TestResource* b = new TestResource(context->getGpu(), 100);
+ cache.addResource(key2, b);
+ b->unref();
+
+ REPORTER_ASSERT(reporter, 200 == cache.getCachedResourceBytes());
+ REPORTER_ASSERT(reporter, 2 == cache.getCachedResourceCount());
+ REPORTER_ASSERT(reporter, NULL == cache.find(key1));
+
+ a->setSize(200);
+
+ REPORTER_ASSERT(reporter, 300 == cache.getCachedResourceBytes());
+ REPORTER_ASSERT(reporter, 2 == cache.getCachedResourceCount());
+ // Internal resource cache validation will test the detached size (debug mode only).
+
+ cache.makeNonExclusive(a->getCacheEntry());
+ a->unref();
+
+ REPORTER_ASSERT(reporter, 300 == cache.getCachedResourceBytes());
+ REPORTER_ASSERT(reporter, 2 == cache.getCachedResourceCount());
+ REPORTER_ASSERT(reporter, cache.find(key1));
+ // Internal resource cache validation will test the detached size (debug mode only).
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+DEF_GPUTEST(ResourceCache, reporter, factory) {
+ for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
+ GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type);
+ if (!GrContextFactory::IsRenderingGLContext(glType)) {
+ continue;
+ }
+ GrContext* context = factory->get(glType);
+ if (NULL == context) {
+ continue;
+ }
+
+ GrTextureDesc desc;
+ desc.fConfig = kSkia8888_GrPixelConfig;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ desc.fWidth = gWidth;
+ desc.fHeight = gHeight;
+ SkImageInfo info = SkImageInfo::MakeN32Premul(gWidth, gHeight);
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(context, info));
+
+ test_cache(reporter, context, surface->getCanvas());
+ test_purge_invalidated(reporter, context);
+ test_cache_delete_on_destruction(reporter, context);
+ test_resource_size_changed(reporter, context);
+ }
+}
+
+#endif
diff --git a/src/third_party/skia/tests/RoundRectTest.cpp b/src/third_party/skia/tests/RoundRectTest.cpp
new file mode 100644
index 0000000..261ec67
--- /dev/null
+++ b/src/third_party/skia/tests/RoundRectTest.cpp
@@ -0,0 +1,624 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkMatrix.h"
+#include "SkRRect.h"
+#include "Test.h"
+
+static const SkScalar kWidth = 100.0f;
+static const SkScalar kHeight = 100.0f;
+
+static void test_inset(skiatest::Reporter* reporter) {
+ SkRRect rr, rr2;
+ SkRect r = { 0, 0, 100, 100 };
+
+ rr.setRect(r);
+ rr.inset(-20, -20, &rr2);
+ REPORTER_ASSERT(reporter, rr2.isRect());
+
+ rr.inset(20, 20, &rr2);
+ REPORTER_ASSERT(reporter, rr2.isRect());
+
+ rr.inset(r.width()/2, r.height()/2, &rr2);
+ REPORTER_ASSERT(reporter, rr2.isEmpty());
+
+ rr.setRectXY(r, 20, 20);
+ rr.inset(19, 19, &rr2);
+ REPORTER_ASSERT(reporter, rr2.isSimple());
+ rr.inset(20, 20, &rr2);
+ REPORTER_ASSERT(reporter, rr2.isRect());
+}
+
+// Test out the basic API entry points
+static void test_round_rect_basic(skiatest::Reporter* reporter) {
+ // Test out initialization methods
+ SkPoint zeroPt = { 0, 0 };
+ SkRRect empty;
+
+ empty.setEmpty();
+
+ REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
+ REPORTER_ASSERT(reporter, empty.rect().isEmpty());
+
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter, zeroPt == empty.radii((SkRRect::Corner) i));
+ }
+
+ //----
+ SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
+
+ SkRRect rr1;
+ rr1.setRect(rect);
+
+ REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
+ REPORTER_ASSERT(reporter, rr1.rect() == rect);
+
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter, zeroPt == rr1.radii((SkRRect::Corner) i));
+ }
+ SkRRect rr1_2; // construct the same RR using the most general set function
+ SkVector rr1_2_radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
+ rr1_2.setRectRadii(rect, rr1_2_radii);
+ REPORTER_ASSERT(reporter, rr1_2 == rr1 && rr1_2.getType() == rr1.getType());
+ SkRRect rr1_3; // construct the same RR using the nine patch set function
+ rr1_3.setNinePatch(rect, 0, 0, 0, 0);
+ REPORTER_ASSERT(reporter, rr1_3 == rr1 && rr1_3.getType() == rr1.getType());
+
+ //----
+ SkPoint halfPoint = { SkScalarHalf(kWidth), SkScalarHalf(kHeight) };
+ SkRRect rr2;
+ rr2.setOval(rect);
+
+ REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr2.type());
+ REPORTER_ASSERT(reporter, rr2.rect() == rect);
+
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter,
+ rr2.radii((SkRRect::Corner) i).equalsWithinTolerance(halfPoint));
+ }
+ SkRRect rr2_2; // construct the same RR using the most general set function
+ SkVector rr2_2_radii[4] = { { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY },
+ { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY } };
+ rr2_2.setRectRadii(rect, rr2_2_radii);
+ REPORTER_ASSERT(reporter, rr2_2 == rr2 && rr2_2.getType() == rr2.getType());
+ SkRRect rr2_3; // construct the same RR using the nine patch set function
+ rr2_3.setNinePatch(rect, halfPoint.fX, halfPoint.fY, halfPoint.fX, halfPoint.fY);
+ REPORTER_ASSERT(reporter, rr2_3 == rr2 && rr2_3.getType() == rr2.getType());
+
+ //----
+ SkPoint p = { 5, 5 };
+ SkRRect rr3;
+ rr3.setRectXY(rect, p.fX, p.fY);
+
+ REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr3.type());
+ REPORTER_ASSERT(reporter, rr3.rect() == rect);
+
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter, p == rr3.radii((SkRRect::Corner) i));
+ }
+ SkRRect rr3_2; // construct the same RR using the most general set function
+ SkVector rr3_2_radii[4] = { { 5, 5 }, { 5, 5 }, { 5, 5 }, { 5, 5 } };
+ rr3_2.setRectRadii(rect, rr3_2_radii);
+ REPORTER_ASSERT(reporter, rr3_2 == rr3 && rr3_2.getType() == rr3.getType());
+ SkRRect rr3_3; // construct the same RR using the nine patch set function
+ rr3_3.setNinePatch(rect, 5, 5, 5, 5);
+ REPORTER_ASSERT(reporter, rr3_3 == rr3 && rr3_3.getType() == rr3.getType());
+
+ //----
+ SkRect ninePatchRadii = { 10, 9, 8, 7 };
+
+ SkRRect rr4;
+ rr4.setNinePatch(rect, ninePatchRadii.fLeft, ninePatchRadii.fTop, ninePatchRadii.fRight,
+ ninePatchRadii.fBottom);
+
+ REPORTER_ASSERT(reporter, SkRRect::kNinePatch_Type == rr4.type());
+ REPORTER_ASSERT(reporter, rr4.rect() == rect);
+
+ SkPoint rquad[4];
+ ninePatchRadii.toQuad(rquad);
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter, rquad[i] == rr4.radii((SkRRect::Corner) i));
+ }
+ SkRRect rr4_2; // construct the same RR using the most general set function
+ SkVector rr4_2_radii[4] = { { 10, 9 }, { 8, 9 }, {8, 7 }, { 10, 7 } };
+ rr4_2.setRectRadii(rect, rr4_2_radii);
+ REPORTER_ASSERT(reporter, rr4_2 == rr4 && rr4_2.getType() == rr4.getType());
+
+ //----
+ SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } };
+
+ SkRRect rr5;
+ rr5.setRectRadii(rect, radii2);
+
+ REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr5.type());
+ REPORTER_ASSERT(reporter, rr5.rect() == rect);
+
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter, radii2[i] == rr5.radii((SkRRect::Corner) i));
+ }
+
+ // Test out == & !=
+ REPORTER_ASSERT(reporter, empty != rr3);
+ REPORTER_ASSERT(reporter, rr3 != rr4);
+ REPORTER_ASSERT(reporter, rr4 != rr5);
+}
+
+// Test out the cases when the RR degenerates to a rect
+static void test_round_rect_rects(skiatest::Reporter* reporter) {
+ SkRect r;
+
+ //----
+ SkRRect empty;
+
+ empty.setEmpty();
+
+ REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
+ r = empty.rect();
+ REPORTER_ASSERT(reporter, 0 == r.fLeft && 0 == r.fTop && 0 == r.fRight && 0 == r.fBottom);
+
+ //----
+ SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
+ SkRRect rr1;
+ rr1.setRectXY(rect, 0, 0);
+
+ REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
+ r = rr1.rect();
+ REPORTER_ASSERT(reporter, rect == r);
+
+ //----
+ SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
+
+ SkRRect rr2;
+ rr2.setRectRadii(rect, radii);
+
+ REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
+ r = rr2.rect();
+ REPORTER_ASSERT(reporter, rect == r);
+
+ //----
+ SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
+
+ SkRRect rr3;
+ rr3.setRectRadii(rect, radii2);
+ REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr3.type());
+}
+
+// Test out the cases when the RR degenerates to an oval
+static void test_round_rect_ovals(skiatest::Reporter* reporter) {
+ //----
+ SkRect oval;
+ SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
+ SkRRect rr1;
+ rr1.setRectXY(rect, SkScalarHalf(kWidth), SkScalarHalf(kHeight));
+
+ REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr1.type());
+ oval = rr1.rect();
+ REPORTER_ASSERT(reporter, oval == rect);
+}
+
+// Test out the non-degenerate RR cases
+static void test_round_rect_general(skiatest::Reporter* reporter) {
+ //----
+ SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
+ SkRRect rr1;
+ rr1.setRectXY(rect, 20, 20);
+
+ REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr1.type());
+
+ //----
+ SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
+
+ SkRRect rr2;
+ rr2.setRectRadii(rect, radii);
+
+ REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr2.type());
+}
+
+// Test out questionable-parameter handling
+static void test_round_rect_iffy_parameters(skiatest::Reporter* reporter) {
+
+ // When the radii exceed the base rect they are proportionally scaled down
+ // to fit
+ SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
+ SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } };
+
+ SkRRect rr1;
+ rr1.setRectRadii(rect, radii);
+
+ REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr1.type());
+
+ const SkPoint& p = rr1.radii(SkRRect::kUpperLeft_Corner);
+
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fX, 33.33333f));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fY, 66.66666f));
+
+ // Negative radii should be capped at zero
+ SkRRect rr2;
+ rr2.setRectXY(rect, -10, -20);
+
+ REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
+
+ const SkPoint& p2 = rr2.radii(SkRRect::kUpperLeft_Corner);
+
+ REPORTER_ASSERT(reporter, 0.0f == p2.fX);
+ REPORTER_ASSERT(reporter, 0.0f == p2.fY);
+}
+
+// Move a small box from the start position by (stepX, stepY) 'numSteps' times
+// testing for containment in 'rr' at each step.
+static void test_direction(skiatest::Reporter* reporter, const SkRRect &rr,
+ SkScalar initX, int stepX, SkScalar initY, int stepY,
+ int numSteps, const bool* contains) {
+ SkScalar x = initX, y = initY;
+ for (int i = 0; i < numSteps; ++i) {
+ SkRect test = SkRect::MakeXYWH(x, y,
+ stepX ? SkIntToScalar(stepX) : SK_Scalar1,
+ stepY ? SkIntToScalar(stepY) : SK_Scalar1);
+ test.sort();
+
+ REPORTER_ASSERT(reporter, contains[i] == rr.contains(test));
+
+ x += stepX;
+ y += stepY;
+ }
+}
+
+// Exercise the RR's contains rect method
+static void test_round_rect_contains_rect(skiatest::Reporter* reporter) {
+
+ static const int kNumRRects = 4;
+ static const SkVector gRadii[kNumRRects][4] = {
+ { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, // rect
+ { { 20, 20 }, { 20, 20 }, { 20, 20 }, { 20, 20 } }, // circle
+ { { 10, 10 }, { 10, 10 }, { 10, 10 }, { 10, 10 } }, // simple
+ { { 0, 0 }, { 20, 20 }, { 10, 10 }, { 30, 30 } } // complex
+ };
+
+ SkRRect rrects[kNumRRects];
+ for (int i = 0; i < kNumRRects; ++i) {
+ rrects[i].setRectRadii(SkRect::MakeWH(40, 40), gRadii[i]);
+ }
+
+ // First test easy outs - boxes that are obviously out on
+ // each corner and edge
+ static const SkRect easyOuts[] = {
+ { -5, -5, 5, 5 }, // NW
+ { 15, -5, 20, 5 }, // N
+ { 35, -5, 45, 5 }, // NE
+ { 35, 15, 45, 20 }, // E
+ { 35, 45, 35, 45 }, // SE
+ { 15, 35, 20, 45 }, // S
+ { -5, 35, 5, 45 }, // SW
+ { -5, 15, 5, 20 } // W
+ };
+
+ for (int i = 0; i < kNumRRects; ++i) {
+ for (size_t j = 0; j < SK_ARRAY_COUNT(easyOuts); ++j) {
+ REPORTER_ASSERT(reporter, !rrects[i].contains(easyOuts[j]));
+ }
+ }
+
+ // Now test non-trivial containment. For each compass
+ // point walk a 1x1 rect in from the edge of the bounding
+ // rect
+ static const int kNumSteps = 15;
+ bool answers[kNumRRects][8][kNumSteps] = {
+ // all the test rects are inside the degenerate rrect
+ {
+ // rect
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ },
+ // for the circle we expect 6 blocks to be out on the
+ // corners (then the rest in) and only the first block
+ // out on the vertical and horizontal axes (then
+ // the rest in)
+ {
+ // circle
+ { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ },
+ // for the simple round rect we expect 3 out on
+ // the corners (then the rest in) and no blocks out
+ // on the vertical and horizontal axes
+ {
+ // simple RR
+ { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ },
+ // for the complex case the answer is different for each direction
+ {
+ // complex RR
+ // all in for NW (rect) corner (same as rect case)
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ // only first block out for N (same as circle case)
+ { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ // first 6 blocks out for NE (same as circle case)
+ { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ // only first block out for E (same as circle case)
+ { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ // first 3 blocks out for SE (same as simple case)
+ { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ // first two blocks out for S
+ { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ // first 9 blocks out for SW
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
+ // first two blocks out for W (same as S)
+ { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ }
+ };
+
+ for (int i = 0; i < kNumRRects; ++i) {
+ test_direction(reporter, rrects[i], 0, 1, 0, 1, kNumSteps, answers[i][0]); // NW
+ test_direction(reporter, rrects[i], 19.5f, 0, 0, 1, kNumSteps, answers[i][1]); // N
+ test_direction(reporter, rrects[i], 40, -1, 0, 1, kNumSteps, answers[i][2]); // NE
+ test_direction(reporter, rrects[i], 40, -1, 19.5f, 0, kNumSteps, answers[i][3]); // E
+ test_direction(reporter, rrects[i], 40, -1, 40, -1, kNumSteps, answers[i][4]); // SE
+ test_direction(reporter, rrects[i], 19.5f, 0, 40, -1, kNumSteps, answers[i][5]); // S
+ test_direction(reporter, rrects[i], 0, 1, 40, -1, kNumSteps, answers[i][6]); // SW
+ test_direction(reporter, rrects[i], 0, 1, 19.5f, 0, kNumSteps, answers[i][7]); // W
+ }
+}
+
+// Called for a matrix that should cause SkRRect::transform to fail.
+static void assert_transform_failure(skiatest::Reporter* reporter, const SkRRect& orig,
+ const SkMatrix& matrix) {
+ // The test depends on the fact that the original is not empty.
+ SkASSERT(!orig.isEmpty());
+ SkRRect dst;
+ dst.setEmpty();
+
+ const SkRRect copyOfDst = dst;
+ const SkRRect copyOfOrig = orig;
+ bool success = orig.transform(matrix, &dst);
+ // This transform should fail.
+ REPORTER_ASSERT(reporter, !success);
+ // Since the transform failed, dst should be unchanged.
+ REPORTER_ASSERT(reporter, copyOfDst == dst);
+ // original should not be modified.
+ REPORTER_ASSERT(reporter, copyOfOrig == orig);
+ REPORTER_ASSERT(reporter, orig != dst);
+}
+
+#define GET_RADII \
+ const SkVector& origUL = orig.radii(SkRRect::kUpperLeft_Corner); \
+ const SkVector& origUR = orig.radii(SkRRect::kUpperRight_Corner); \
+ const SkVector& origLR = orig.radii(SkRRect::kLowerRight_Corner); \
+ const SkVector& origLL = orig.radii(SkRRect::kLowerLeft_Corner); \
+ const SkVector& dstUL = dst.radii(SkRRect::kUpperLeft_Corner); \
+ const SkVector& dstUR = dst.radii(SkRRect::kUpperRight_Corner); \
+ const SkVector& dstLR = dst.radii(SkRRect::kLowerRight_Corner); \
+ const SkVector& dstLL = dst.radii(SkRRect::kLowerLeft_Corner)
+
+// Called to test various transforms on a single SkRRect.
+static void test_transform_helper(skiatest::Reporter* reporter, const SkRRect& orig) {
+ SkRRect dst;
+ dst.setEmpty();
+
+ // The identity matrix will duplicate the rrect.
+ bool success = orig.transform(SkMatrix::I(), &dst);
+ REPORTER_ASSERT(reporter, success);
+ REPORTER_ASSERT(reporter, orig == dst);
+
+ // Skew and Perspective make transform fail.
+ SkMatrix matrix;
+ matrix.reset();
+ matrix.setSkewX(SkIntToScalar(2));
+ assert_transform_failure(reporter, orig, matrix);
+
+ matrix.reset();
+ matrix.setSkewY(SkIntToScalar(3));
+ assert_transform_failure(reporter, orig, matrix);
+
+ matrix.reset();
+ matrix.setPerspX(SkScalarToPersp(SkIntToScalar(4)));
+ assert_transform_failure(reporter, orig, matrix);
+
+ matrix.reset();
+ matrix.setPerspY(SkScalarToPersp(SkIntToScalar(5)));
+ assert_transform_failure(reporter, orig, matrix);
+
+ // Rotation fails.
+ matrix.reset();
+ matrix.setRotate(SkIntToScalar(90));
+ assert_transform_failure(reporter, orig, matrix);
+ matrix.setRotate(SkIntToScalar(37));
+ assert_transform_failure(reporter, orig, matrix);
+
+ // Translate will keep the rect moved, but otherwise the same.
+ matrix.reset();
+ SkScalar translateX = SkIntToScalar(32);
+ SkScalar translateY = SkIntToScalar(15);
+ matrix.setTranslateX(translateX);
+ matrix.setTranslateY(translateY);
+ dst.setEmpty();
+ success = orig.transform(matrix, &dst);
+ REPORTER_ASSERT(reporter, success);
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter,
+ orig.radii((SkRRect::Corner) i) == dst.radii((SkRRect::Corner) i));
+ }
+ REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
+ REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
+ REPORTER_ASSERT(reporter, dst.rect().left() == orig.rect().left() + translateX);
+ REPORTER_ASSERT(reporter, dst.rect().top() == orig.rect().top() + translateY);
+
+ // Keeping the translation, but adding skew will make transform fail.
+ matrix.setSkewY(SkIntToScalar(7));
+ assert_transform_failure(reporter, orig, matrix);
+
+ // Scaling in -x will flip the round rect horizontally.
+ matrix.reset();
+ matrix.setScaleX(SkIntToScalar(-1));
+ dst.setEmpty();
+ success = orig.transform(matrix, &dst);
+ REPORTER_ASSERT(reporter, success);
+ {
+ GET_RADII;
+ // Radii have swapped in x.
+ REPORTER_ASSERT(reporter, origUL == dstUR);
+ REPORTER_ASSERT(reporter, origUR == dstUL);
+ REPORTER_ASSERT(reporter, origLR == dstLL);
+ REPORTER_ASSERT(reporter, origLL == dstLR);
+ }
+ // Width and height remain the same.
+ REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
+ REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
+ // Right and left have swapped (sort of)
+ REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
+ // Top has stayed the same.
+ REPORTER_ASSERT(reporter, orig.rect().top() == dst.rect().top());
+
+ // Keeping the scale, but adding a persp will make transform fail.
+ matrix.setPerspX(SkScalarToPersp(SkIntToScalar(7)));
+ assert_transform_failure(reporter, orig, matrix);
+
+ // Scaling in -y will flip the round rect vertically.
+ matrix.reset();
+ matrix.setScaleY(SkIntToScalar(-1));
+ dst.setEmpty();
+ success = orig.transform(matrix, &dst);
+ REPORTER_ASSERT(reporter, success);
+ {
+ GET_RADII;
+ // Radii have swapped in y.
+ REPORTER_ASSERT(reporter, origUL == dstLL);
+ REPORTER_ASSERT(reporter, origUR == dstLR);
+ REPORTER_ASSERT(reporter, origLR == dstUR);
+ REPORTER_ASSERT(reporter, origLL == dstUL);
+ }
+ // Width and height remain the same.
+ REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
+ REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
+ // Top and bottom have swapped (sort of)
+ REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
+ // Left has stayed the same.
+ REPORTER_ASSERT(reporter, orig.rect().left() == dst.rect().left());
+
+ // Scaling in -x and -y will swap in both directions.
+ matrix.reset();
+ matrix.setScaleY(SkIntToScalar(-1));
+ matrix.setScaleX(SkIntToScalar(-1));
+ dst.setEmpty();
+ success = orig.transform(matrix, &dst);
+ REPORTER_ASSERT(reporter, success);
+ {
+ GET_RADII;
+ REPORTER_ASSERT(reporter, origUL == dstLR);
+ REPORTER_ASSERT(reporter, origUR == dstLL);
+ REPORTER_ASSERT(reporter, origLR == dstUL);
+ REPORTER_ASSERT(reporter, origLL == dstUR);
+ }
+ // Width and height remain the same.
+ REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
+ REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
+ REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
+ REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
+
+ // Scale in both directions.
+ SkScalar xScale = SkIntToScalar(3);
+ SkScalar yScale = 3.2f;
+ matrix.reset();
+ matrix.setScaleX(xScale);
+ matrix.setScaleY(yScale);
+ dst.setEmpty();
+ success = orig.transform(matrix, &dst);
+ REPORTER_ASSERT(reporter, success);
+ // Radii are scaled.
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fX,
+ SkScalarMul(orig.radii((SkRRect::Corner) i).fX, xScale)));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fY,
+ SkScalarMul(orig.radii((SkRRect::Corner) i).fY, yScale)));
+ }
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().width(),
+ SkScalarMul(orig.rect().width(), xScale)));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().height(),
+ SkScalarMul(orig.rect().height(), yScale)));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().left(),
+ SkScalarMul(orig.rect().left(), xScale)));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().top(),
+ SkScalarMul(orig.rect().top(), yScale)));
+}
+
+static void test_round_rect_transform(skiatest::Reporter* reporter) {
+ SkRRect rrect;
+ {
+ SkRect r = { 0, 0, kWidth, kHeight };
+ rrect.setRectXY(r, SkIntToScalar(4), SkIntToScalar(7));
+ test_transform_helper(reporter, rrect);
+ }
+ {
+ SkRect r = { SkIntToScalar(5), SkIntToScalar(15),
+ SkIntToScalar(27), SkIntToScalar(34) };
+ SkVector radii[4] = { { 0, SkIntToScalar(1) },
+ { SkIntToScalar(2), SkIntToScalar(3) },
+ { SkIntToScalar(4), SkIntToScalar(5) },
+ { SkIntToScalar(6), SkIntToScalar(7) } };
+ rrect.setRectRadii(r, radii);
+ test_transform_helper(reporter, rrect);
+ }
+}
+
+// Test out the case where an oval already off in space is translated/scaled
+// further off into space - yielding numerical issues when the rect & radii
+// are transformed separatly
+// BUG=skia:2696
+static void test_issue_2696(skiatest::Reporter* reporter) {
+ SkRRect rrect;
+ SkRect r = { 28443.8594f, 53.1428604f, 28446.7148f, 56.0000038f };
+ rrect.setOval(r);
+
+ SkMatrix xform;
+ xform.setAll(2.44f, 0.0f, 485411.7f,
+ 0.0f, 2.44f, -438.7f,
+ 0.0f, 0.0f, 1.0f);
+ SkRRect dst;
+
+ bool success = rrect.transform(xform, &dst);
+ REPORTER_ASSERT(reporter, success);
+
+ SkScalar halfWidth = SkScalarHalf(dst.width());
+ SkScalar halfHeight = SkScalarHalf(dst.height());
+
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter,
+ SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fX, halfWidth));
+ REPORTER_ASSERT(reporter,
+ SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fY, halfHeight));
+ }
+}
+
+DEF_TEST(RoundRect, reporter) {
+ test_round_rect_basic(reporter);
+ test_round_rect_rects(reporter);
+ test_round_rect_ovals(reporter);
+ test_round_rect_general(reporter);
+ test_round_rect_iffy_parameters(reporter);
+ test_inset(reporter);
+ test_round_rect_contains_rect(reporter);
+ test_round_rect_transform(reporter);
+ test_issue_2696(reporter);
+}
diff --git a/src/third_party/skia/tests/RuntimeConfigTest.cpp b/src/third_party/skia/tests/RuntimeConfigTest.cpp
new file mode 100644
index 0000000..d40a4f0
--- /dev/null
+++ b/src/third_party/skia/tests/RuntimeConfigTest.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkRTConf.h"
+#include "Test.h"
+
+SK_CONF_DECLARE(int, c_RTConfTestVariable,
+ "test.utils.rtconf.testVariable", 1,
+ "This is only a test. Do not be alarmed.");
+// TODO(skia-team): more comprehensive unit tests of the SkRTConf
+// system.
+DEF_TEST(RuntimeConfig, reporter) {
+ REPORTER_ASSERT(reporter, 1 == c_RTConfTestVariable);
+
+ SK_CONF_SET("test.utils.rtconf.testVariable", 2);
+#ifdef SK_DEVELOPER
+ REPORTER_ASSERT(reporter, 2 == c_RTConfTestVariable);
+#else // not SK_DEVELOPER
+ // Can not change RTConf variables in Release.
+ REPORTER_ASSERT(reporter, 1 == c_RTConfTestVariable);
+#endif // SK_DEVELOPER
+
+ // This should not give a warning.
+ SK_CONF_TRY_SET("test.utils.rtconf.nonexistentVariable", 7);
+}
diff --git a/src/third_party/skia/tests/SHA1Test.cpp b/src/third_party/skia/tests/SHA1Test.cpp
new file mode 100644
index 0000000..fd5fcb7
--- /dev/null
+++ b/src/third_party/skia/tests/SHA1Test.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSHA1.h"
+#include "Test.h"
+
+static bool digests_equal(const SkSHA1::Digest& expectedDigest, const SkSHA1::Digest& computedDigest) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(expectedDigest.data); ++i) {
+ if (expectedDigest.data[i] != computedDigest.data[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static struct SHA1Test {
+ const char* message;
+ const unsigned long int repeatCount;
+ const SkSHA1::Digest digest;
+} sha1_tests[] = {
+ // Reference tests from RFC3174 Section 7.3 ( http://www.ietf.org/rfc/rfc3174.txt )
+ { "abc", 1, {{ 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D }} },
+ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1, {{ 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 }} },
+ { "a", 1000000, {{ 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E, 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }} },
+ { "0123456701234567012345670123456701234567012345670123456701234567", 10, {{ 0xDE, 0xA3, 0x56, 0xA2, 0xCD, 0xDD, 0x90, 0xC7, 0xA7, 0xEC, 0xED, 0xC5, 0xEB, 0xB5, 0x63, 0x93, 0x4F, 0x46, 0x04, 0x52 }} },
+
+ // Reference tests from running GNU sha1sum on test input
+ { "The quick brown fox jumps over the lazy dog", 1, {{ 0x2f, 0xd4, 0xe1, 0xc6, 0x7a, 0x2d, 0x28, 0xfc, 0xed, 0x84, 0x9e, 0xe1, 0xbb, 0x76, 0xe7, 0x39, 0x1b, 0x93, 0xeb, 0x12 }} },
+ { "", 1, {{ 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 }} },
+};
+
+static void sha1_test(const SHA1Test& test, skiatest::Reporter* reporter) {
+ size_t len = strlen(test.message);
+
+ SkSHA1 context;
+ for (unsigned long int i = 0; i < test.repeatCount; ++i) {
+ context.update(reinterpret_cast<const uint8_t*>(test.message), len);
+ }
+ SkSHA1::Digest digest;
+ context.finish(digest);
+
+ REPORTER_ASSERT(reporter, digests_equal(test.digest, digest));
+}
+
+DEF_TEST(SHA1, reporter) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(sha1_tests); ++i) {
+ sha1_test(sha1_tests[i], reporter);
+ }
+}
diff --git a/src/third_party/skia/tests/SListTest.cpp b/src/third_party/skia/tests/SListTest.cpp
new file mode 100644
index 0000000..78fcc65
--- /dev/null
+++ b/src/third_party/skia/tests/SListTest.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTInternalSList.h"
+#include "Test.h"
+
+class SListEntry {
+public:
+ SListEntry* next() { return getSListNext(); }
+private:
+ SK_DECLARE_INTERNAL_SLIST_INTERFACE(SListEntry);
+};
+
+static bool verifyEmptyList(skiatest::Reporter* reporter,
+ const SkTInternalSList<SListEntry>& list,
+ const char* stage) {
+
+ if (!list.isEmpty()) {
+ ERRORF(reporter, "%s - List not empty", stage);
+ return false;
+ }
+ if (0 != list.getCount()) {
+ ERRORF(reporter, "%s - List count is not zero, %d instead", stage, list.getCount());
+ return false;
+ }
+ if (list.head()) {
+ ERRORF(reporter, "%s - List has elements when empty", stage);
+ return false;
+ }
+ return true;
+}
+
+static bool verifyList(skiatest::Reporter* reporter,
+ const SkTInternalSList<SListEntry>& list,
+ const char* stage,
+ SListEntry* start, int count, int step = 1) {
+ SListEntry* next = list.head();
+ if (list.getCount() != count) {
+ ERRORF(reporter, "%s - List was too short, %d instead of %d", stage, list.getCount(), count);
+ return false;
+ }
+ int index = 0;
+ for(SListEntry* value = start; index < count; value += step, ++index) {
+ if (NULL == next) {
+ ERRORF(reporter, "%s - List too short, should be %d", stage, count);
+ return false;
+ }
+ if (next!= value) {
+ ERRORF(reporter, "%s - List entries at index %d of %d don't match", stage, index, count);
+ return false;
+ }
+ next = next->next();
+ }
+ if (next) {
+ ERRORF(reporter, "%s - List too long, should be %d", stage, count);
+ return false;
+ }
+ return true;
+}
+
+static void testTInternalSList(skiatest::Reporter* reporter) {
+ // Build a test array of data
+ static const int testArraySize = 10;
+ SListEntry testArray[testArraySize];
+ // Basic add remove tests
+ SkTInternalSList<SListEntry> list;
+ verifyEmptyList(reporter, list, "start");
+ // Push values in, testing on the way
+ for (int index = 0; index < testArraySize; ++index) {
+ list.push(&testArray[index]);
+ if (!verifyList(reporter, list, "push", &testArray[index], index+1, -1)) {
+ return;
+ }
+ }
+ // Now remove them again
+ for (int index = testArraySize - 1; index >= 0; --index) {
+ REPORTER_ASSERT(reporter, &testArray[index] == list.pop());
+ if ((index != 0) &&
+ !verifyList(reporter, list, "pop", &testArray[index-1], index, -1)) {
+ return;
+ }
+ }
+ verifyEmptyList(reporter, list, "end");
+ // Move between list tests
+ for (int index = 0; index < testArraySize; ++index) {
+ list.push(&testArray[index]);
+ }
+ verifyList(reporter, list, "swap", &testArray[testArraySize-1], testArraySize, -1);
+ SkTInternalSList<SListEntry> other;
+ // Check swap moves the list over unchanged
+ other.swap(&list);
+ verifyEmptyList(reporter, list, "swap");
+ verifyList(reporter, other, "swap", &testArray[testArraySize-1], testArraySize, -1);
+ // Check pushAll optimizes to a swap when one of the is empty
+ list.pushAll(&other);
+ verifyList(reporter, list, "pushAll-empty", &testArray[testArraySize-1], testArraySize, -1);
+ verifyEmptyList(reporter, other, "pushAll-empty");
+ // Check pushAll when non empty works
+ other.push(list.pop());
+ other.pushAll(&list);
+ verifyEmptyList(reporter, list, "pushAll");
+ verifyList(reporter, other, "pushAll", &testArray[0], testArraySize, 1);
+}
+
+DEF_TEST(SList, reporter) {
+ testTInternalSList(reporter);
+}
diff --git a/src/third_party/skia/tests/ScalarTest.cpp b/src/third_party/skia/tests/ScalarTest.cpp
new file mode 100644
index 0000000..b6f71d1
--- /dev/null
+++ b/src/third_party/skia/tests/ScalarTest.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkFloatingPoint.h"
+#include "SkMath.h"
+#include "SkPoint.h"
+#include "SkRandom.h"
+#include "SkRect.h"
+#include "Test.h"
+
+static void test_roundtoint(skiatest::Reporter* reporter) {
+ SkScalar x = 0.49999997f;
+ int ix = SkScalarRoundToInt(x);
+ // We "should" get 0, since x < 0.5, but we don't due to float addition rounding up the low
+ // bit after adding 0.5.
+ REPORTER_ASSERT(reporter, 1 == ix);
+
+ // This version explicitly performs the +0.5 step using double, which should avoid losing the
+ // low bits.
+ ix = SkDScalarRoundToInt(x);
+ REPORTER_ASSERT(reporter, 0 == ix);
+}
+
+struct PointSet {
+ const SkPoint* fPts;
+ size_t fCount;
+ bool fIsFinite;
+};
+
+static void test_isRectFinite(skiatest::Reporter* reporter) {
+ static const SkPoint gF0[] = {
+ { 0, 0 }, { 1, 1 }
+ };
+ static const SkPoint gF1[] = {
+ { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }
+ };
+
+ static const SkPoint gI0[] = {
+ { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { SK_ScalarNaN, 3 }, { 2, 3 },
+ };
+ static const SkPoint gI1[] = {
+ { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { 3, SK_ScalarNaN }, { 2, 3 },
+ };
+ static const SkPoint gI2[] = {
+ { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { SK_ScalarInfinity, 3 }, { 2, 3 },
+ };
+ static const SkPoint gI3[] = {
+ { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { 3, SK_ScalarInfinity }, { 2, 3 },
+ };
+
+ static const struct {
+ const SkPoint* fPts;
+ size_t fCount;
+ bool fIsFinite;
+ } gSets[] = {
+ { gF0, SK_ARRAY_COUNT(gF0), true },
+ { gF1, SK_ARRAY_COUNT(gF1), true },
+
+ { gI0, SK_ARRAY_COUNT(gI0), false },
+ { gI1, SK_ARRAY_COUNT(gI1), false },
+ { gI2, SK_ARRAY_COUNT(gI2), false },
+ { gI3, SK_ARRAY_COUNT(gI3), false },
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gSets); ++i) {
+ SkRect r;
+ r.set(gSets[i].fPts, gSets[i].fCount);
+ bool rectIsFinite = !r.isEmpty();
+ REPORTER_ASSERT(reporter, gSets[i].fIsFinite == rectIsFinite);
+ }
+}
+
+static bool isFinite_int(float x) {
+ uint32_t bits = SkFloat2Bits(x); // need unsigned for our shifts
+ int exponent = bits << 1 >> 24;
+ return exponent != 0xFF;
+}
+
+static bool isFinite_float(float x) {
+ return SkToBool(sk_float_isfinite(x));
+}
+
+static bool isFinite_mulzero(float x) {
+ float y = x * 0;
+ return y == y;
+}
+
+// return true if the float is finite
+typedef bool (*IsFiniteProc1)(float);
+
+static bool isFinite2_and(float x, float y, IsFiniteProc1 proc) {
+ return proc(x) && proc(y);
+}
+
+static bool isFinite2_mulzeroadd(float x, float y, IsFiniteProc1 proc) {
+ return proc(x * 0 + y * 0);
+}
+
+// return true if both floats are finite
+typedef bool (*IsFiniteProc2)(float, float, IsFiniteProc1);
+
+enum FloatClass {
+ kFinite,
+ kInfinite,
+ kNaN
+};
+
+static void test_floatclass(skiatest::Reporter* reporter, float value, FloatClass fc) {
+ // our sk_float_is... function may return int instead of bool,
+ // hence the double ! to turn it into a bool
+ REPORTER_ASSERT(reporter, !!sk_float_isfinite(value) == (fc == kFinite));
+ REPORTER_ASSERT(reporter, !!sk_float_isinf(value) == (fc == kInfinite));
+ REPORTER_ASSERT(reporter, !!sk_float_isnan(value) == (fc == kNaN));
+}
+
+#if defined _WIN32
+#pragma warning ( push )
+// we are intentionally causing an overflow here
+// (warning C4756: overflow in constant arithmetic)
+#pragma warning ( disable : 4756 )
+#endif
+
+static void test_isfinite(skiatest::Reporter* reporter) {
+ struct Rec {
+ float fValue;
+ bool fIsFinite;
+ };
+
+ float max = 3.402823466e+38f;
+ float inf = max * max;
+ float nan = inf * 0;
+
+ test_floatclass(reporter, 0, kFinite);
+ test_floatclass(reporter, max, kFinite);
+ test_floatclass(reporter, -max, kFinite);
+ test_floatclass(reporter, inf, kInfinite);
+ test_floatclass(reporter, -inf, kInfinite);
+ test_floatclass(reporter, nan, kNaN);
+ test_floatclass(reporter, -nan, kNaN);
+
+ const Rec data[] = {
+ { 0, true },
+ { 1, true },
+ { -1, true },
+ { max * 0.75f, true },
+ { max, true },
+ { -max * 0.75f, true },
+ { -max, true },
+ { inf, false },
+ { -inf, false },
+ { nan, false },
+ };
+
+ const IsFiniteProc1 gProc1[] = {
+ isFinite_int,
+ isFinite_float,
+ isFinite_mulzero
+ };
+ const IsFiniteProc2 gProc2[] = {
+ isFinite2_and,
+ isFinite2_mulzeroadd
+ };
+
+ size_t i, n = SK_ARRAY_COUNT(data);
+
+ for (i = 0; i < n; ++i) {
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
+ const Rec& rec = data[i];
+ bool finite = gProc1[k](rec.fValue);
+ REPORTER_ASSERT(reporter, rec.fIsFinite == finite);
+ }
+ }
+
+ for (i = 0; i < n; ++i) {
+ const Rec& rec0 = data[i];
+ for (size_t j = 0; j < n; ++j) {
+ const Rec& rec1 = data[j];
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
+ IsFiniteProc1 proc1 = gProc1[k];
+
+ for (size_t m = 0; m < SK_ARRAY_COUNT(gProc2); ++m) {
+ bool finite = gProc2[m](rec0.fValue, rec1.fValue, proc1);
+ bool finite2 = rec0.fIsFinite && rec1.fIsFinite;
+ REPORTER_ASSERT(reporter, finite2 == finite);
+ }
+ }
+ }
+ }
+
+ test_isRectFinite(reporter);
+}
+
+#if defined _WIN32
+#pragma warning ( pop )
+#endif
+
+DEF_TEST(Scalar, reporter) {
+ test_isfinite(reporter);
+ test_roundtoint(reporter);
+}
diff --git a/src/third_party/skia/tests/SerializationTest.cpp b/src/third_party/skia/tests/SerializationTest.cpp
new file mode 100644
index 0000000..dd9b938
--- /dev/null
+++ b/src/third_party/skia/tests/SerializationTest.cpp
@@ -0,0 +1,531 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Resources.h"
+#include "SkBitmapSource.h"
+#include "SkCanvas.h"
+#include "SkMallocPixelRef.h"
+#include "SkOSFile.h"
+#include "SkPictureRecorder.h"
+#include "SkTableColorFilter.h"
+#include "SkTemplates.h"
+#include "SkTypeface.h"
+#include "SkWriteBuffer.h"
+#include "SkValidatingReadBuffer.h"
+#include "SkXfermodeImageFilter.h"
+#include "Test.h"
+
+static const uint32_t kArraySize = 64;
+static const int kBitmapSize = 256;
+
+template<typename T>
+static void TestAlignment(T* testObj, skiatest::Reporter* reporter) {
+ // Test memory read/write functions directly
+ unsigned char dataWritten[1024];
+ size_t bytesWrittenToMemory = testObj->writeToMemory(dataWritten);
+ REPORTER_ASSERT(reporter, SkAlign4(bytesWrittenToMemory) == bytesWrittenToMemory);
+ size_t bytesReadFromMemory = testObj->readFromMemory(dataWritten, bytesWrittenToMemory);
+ REPORTER_ASSERT(reporter, SkAlign4(bytesReadFromMemory) == bytesReadFromMemory);
+}
+
+template<typename T> struct SerializationUtils {
+ // Generic case for flattenables
+ static void Write(SkWriteBuffer& writer, const T* flattenable) {
+ writer.writeFlattenable(flattenable);
+ }
+ static void Read(SkValidatingReadBuffer& reader, T** flattenable) {
+ *flattenable = (T*)reader.readFlattenable(T::GetFlattenableType());
+ }
+};
+
+template<> struct SerializationUtils<SkMatrix> {
+ static void Write(SkWriteBuffer& writer, const SkMatrix* matrix) {
+ writer.writeMatrix(*matrix);
+ }
+ static void Read(SkValidatingReadBuffer& reader, SkMatrix* matrix) {
+ reader.readMatrix(matrix);
+ }
+};
+
+template<> struct SerializationUtils<SkPath> {
+ static void Write(SkWriteBuffer& writer, const SkPath* path) {
+ writer.writePath(*path);
+ }
+ static void Read(SkValidatingReadBuffer& reader, SkPath* path) {
+ reader.readPath(path);
+ }
+};
+
+template<> struct SerializationUtils<SkRegion> {
+ static void Write(SkWriteBuffer& writer, const SkRegion* region) {
+ writer.writeRegion(*region);
+ }
+ static void Read(SkValidatingReadBuffer& reader, SkRegion* region) {
+ reader.readRegion(region);
+ }
+};
+
+template<> struct SerializationUtils<SkString> {
+ static void Write(SkWriteBuffer& writer, const SkString* string) {
+ writer.writeString(string->c_str());
+ }
+ static void Read(SkValidatingReadBuffer& reader, SkString* string) {
+ reader.readString(string);
+ }
+};
+
+template<> struct SerializationUtils<unsigned char> {
+ static void Write(SkWriteBuffer& writer, unsigned char* data, uint32_t arraySize) {
+ writer.writeByteArray(data, arraySize);
+ }
+ static bool Read(SkValidatingReadBuffer& reader, unsigned char* data, uint32_t arraySize) {
+ return reader.readByteArray(data, arraySize);
+ }
+};
+
+template<> struct SerializationUtils<SkColor> {
+ static void Write(SkWriteBuffer& writer, SkColor* data, uint32_t arraySize) {
+ writer.writeColorArray(data, arraySize);
+ }
+ static bool Read(SkValidatingReadBuffer& reader, SkColor* data, uint32_t arraySize) {
+ return reader.readColorArray(data, arraySize);
+ }
+};
+
+template<> struct SerializationUtils<int32_t> {
+ static void Write(SkWriteBuffer& writer, int32_t* data, uint32_t arraySize) {
+ writer.writeIntArray(data, arraySize);
+ }
+ static bool Read(SkValidatingReadBuffer& reader, int32_t* data, uint32_t arraySize) {
+ return reader.readIntArray(data, arraySize);
+ }
+};
+
+template<> struct SerializationUtils<SkPoint> {
+ static void Write(SkWriteBuffer& writer, SkPoint* data, uint32_t arraySize) {
+ writer.writePointArray(data, arraySize);
+ }
+ static bool Read(SkValidatingReadBuffer& reader, SkPoint* data, uint32_t arraySize) {
+ return reader.readPointArray(data, arraySize);
+ }
+};
+
+template<> struct SerializationUtils<SkScalar> {
+ static void Write(SkWriteBuffer& writer, SkScalar* data, uint32_t arraySize) {
+ writer.writeScalarArray(data, arraySize);
+ }
+ static bool Read(SkValidatingReadBuffer& reader, SkScalar* data, uint32_t arraySize) {
+ return reader.readScalarArray(data, arraySize);
+ }
+};
+
+template<typename T, bool testInvalid> struct SerializationTestUtils {
+ static void InvalidateData(unsigned char* data) {}
+};
+
+template<> struct SerializationTestUtils<SkString, true> {
+ static void InvalidateData(unsigned char* data) {
+ data[3] |= 0x80; // Reverse sign of 1st integer
+ }
+};
+
+template<typename T, bool testInvalid>
+static void TestObjectSerializationNoAlign(T* testObj, skiatest::Reporter* reporter) {
+ SkWriteBuffer writer(SkWriteBuffer::kValidation_Flag);
+ SerializationUtils<T>::Write(writer, testObj);
+ size_t bytesWritten = writer.bytesWritten();
+ REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten);
+
+ unsigned char dataWritten[1024];
+ writer.writeToMemory(dataWritten);
+
+ SerializationTestUtils<T, testInvalid>::InvalidateData(dataWritten);
+
+ // Make sure this fails when it should (test with smaller size, but still multiple of 4)
+ SkValidatingReadBuffer buffer(dataWritten, bytesWritten - 4);
+ T obj;
+ SerializationUtils<T>::Read(buffer, &obj);
+ REPORTER_ASSERT(reporter, !buffer.isValid());
+
+ // Make sure this succeeds when it should
+ SkValidatingReadBuffer buffer2(dataWritten, bytesWritten);
+ const unsigned char* peekBefore = static_cast<const unsigned char*>(buffer2.skip(0));
+ T obj2;
+ SerializationUtils<T>::Read(buffer2, &obj2);
+ const unsigned char* peekAfter = static_cast<const unsigned char*>(buffer2.skip(0));
+ // This should have succeeded, since there are enough bytes to read this
+ REPORTER_ASSERT(reporter, buffer2.isValid() == !testInvalid);
+ // Note: This following test should always succeed, regardless of whether the buffer is valid,
+ // since if it is invalid, it will simply skip to the end, as if it had read the whole buffer.
+ REPORTER_ASSERT(reporter, static_cast<size_t>(peekAfter - peekBefore) == bytesWritten);
+}
+
+template<typename T>
+static void TestObjectSerialization(T* testObj, skiatest::Reporter* reporter) {
+ TestObjectSerializationNoAlign<T, false>(testObj, reporter);
+ TestAlignment(testObj, reporter);
+}
+
+template<typename T>
+static T* TestFlattenableSerialization(T* testObj, bool shouldSucceed,
+ skiatest::Reporter* reporter) {
+ SkWriteBuffer writer(SkWriteBuffer::kValidation_Flag);
+ SerializationUtils<T>::Write(writer, testObj);
+ size_t bytesWritten = writer.bytesWritten();
+ REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten);
+
+ unsigned char dataWritten[4096];
+ SkASSERT(bytesWritten <= sizeof(dataWritten));
+ writer.writeToMemory(dataWritten);
+
+ // Make sure this fails when it should (test with smaller size, but still multiple of 4)
+ SkValidatingReadBuffer buffer(dataWritten, bytesWritten - 4);
+ T* obj = NULL;
+ SerializationUtils<T>::Read(buffer, &obj);
+ REPORTER_ASSERT(reporter, !buffer.isValid());
+ REPORTER_ASSERT(reporter, NULL == obj);
+
+ // Make sure this succeeds when it should
+ SkValidatingReadBuffer buffer2(dataWritten, bytesWritten);
+ const unsigned char* peekBefore = static_cast<const unsigned char*>(buffer2.skip(0));
+ T* obj2 = NULL;
+ SerializationUtils<T>::Read(buffer2, &obj2);
+ const unsigned char* peekAfter = static_cast<const unsigned char*>(buffer2.skip(0));
+ if (shouldSucceed) {
+ // This should have succeeded, since there are enough bytes to read this
+ REPORTER_ASSERT(reporter, buffer2.isValid());
+ REPORTER_ASSERT(reporter, static_cast<size_t>(peekAfter - peekBefore) == bytesWritten);
+ REPORTER_ASSERT(reporter, obj2);
+ } else {
+ // If the deserialization was supposed to fail, make sure it did
+ REPORTER_ASSERT(reporter, !buffer.isValid());
+ REPORTER_ASSERT(reporter, NULL == obj2);
+ }
+
+ return obj2; // Return object to perform further validity tests on it
+}
+
+template<typename T>
+static void TestArraySerialization(T* data, skiatest::Reporter* reporter) {
+ SkWriteBuffer writer(SkWriteBuffer::kValidation_Flag);
+ SerializationUtils<T>::Write(writer, data, kArraySize);
+ size_t bytesWritten = writer.bytesWritten();
+ // This should write the length (in 4 bytes) and the array
+ REPORTER_ASSERT(reporter, (4 + kArraySize * sizeof(T)) == bytesWritten);
+
+ unsigned char dataWritten[1024];
+ writer.writeToMemory(dataWritten);
+
+ // Make sure this fails when it should
+ SkValidatingReadBuffer buffer(dataWritten, bytesWritten);
+ T dataRead[kArraySize];
+ bool success = SerializationUtils<T>::Read(buffer, dataRead, kArraySize / 2);
+ // This should have failed, since the provided size was too small
+ REPORTER_ASSERT(reporter, !success);
+
+ // Make sure this succeeds when it should
+ SkValidatingReadBuffer buffer2(dataWritten, bytesWritten);
+ success = SerializationUtils<T>::Read(buffer2, dataRead, kArraySize);
+ // This should have succeeded, since there are enough bytes to read this
+ REPORTER_ASSERT(reporter, success);
+}
+
+static void TestBitmapSerialization(const SkBitmap& validBitmap,
+ const SkBitmap& invalidBitmap,
+ bool shouldSucceed,
+ skiatest::Reporter* reporter) {
+ SkAutoTUnref<SkBitmapSource> validBitmapSource(SkBitmapSource::Create(validBitmap));
+ SkAutoTUnref<SkBitmapSource> invalidBitmapSource(SkBitmapSource::Create(invalidBitmap));
+ SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
+ SkAutoTUnref<SkXfermodeImageFilter> xfermodeImageFilter(
+ SkXfermodeImageFilter::Create(mode, invalidBitmapSource, validBitmapSource));
+
+ SkAutoTUnref<SkImageFilter> deserializedFilter(
+ TestFlattenableSerialization<SkImageFilter>(
+ xfermodeImageFilter, shouldSucceed, reporter));
+
+ // Try to render a small bitmap using the invalid deserialized filter
+ // to make sure we don't crash while trying to render it
+ if (shouldSucceed) {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(24, 24);
+ SkCanvas canvas(bitmap);
+ canvas.clear(0x00000000);
+ SkPaint paint;
+ paint.setImageFilter(deserializedFilter);
+ canvas.clipRect(SkRect::MakeXYWH(0, 0, SkIntToScalar(24), SkIntToScalar(24)));
+ canvas.drawBitmap(bitmap, 0, 0, &paint);
+ }
+}
+
+static void TestXfermodeSerialization(skiatest::Reporter* reporter) {
+ for (size_t i = 0; i <= SkXfermode::kLastMode; ++i) {
+ if (i == SkXfermode::kSrcOver_Mode) {
+ // skip SrcOver, as it is allowed to return NULL from Create()
+ continue;
+ }
+ SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(static_cast<SkXfermode::Mode>(i)));
+ REPORTER_ASSERT(reporter, mode.get());
+ SkAutoTUnref<SkXfermode> copy(
+ TestFlattenableSerialization<SkXfermode>(mode.get(), true, reporter));
+ }
+}
+
+static void TestColorFilterSerialization(skiatest::Reporter* reporter) {
+ uint8_t table[256];
+ for (int i = 0; i < 256; ++i) {
+ table[i] = (i * 41) % 256;
+ }
+ SkAutoTUnref<SkColorFilter> colorFilter(SkTableColorFilter::Create(table));
+ SkAutoTUnref<SkColorFilter> copy(
+ TestFlattenableSerialization<SkColorFilter>(colorFilter.get(), true, reporter));
+}
+
+static SkBitmap draw_picture(SkPicture& picture) {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(SkScalarCeilToInt(picture.cullRect().width()),
+ SkScalarCeilToInt(picture.cullRect().height()));
+ SkCanvas canvas(bitmap);
+ picture.playback(&canvas);
+ return bitmap;
+}
+
+static void compare_bitmaps(skiatest::Reporter* reporter,
+ const SkBitmap& b1, const SkBitmap& b2) {
+ REPORTER_ASSERT(reporter, b1.width() == b2.width());
+ REPORTER_ASSERT(reporter, b1.height() == b2.height());
+ SkAutoLockPixels autoLockPixels1(b1);
+ SkAutoLockPixels autoLockPixels2(b2);
+
+ if ((b1.width() != b2.width()) ||
+ (b1.height() != b2.height())) {
+ return;
+ }
+
+ int pixelErrors = 0;
+ for (int y = 0; y < b2.height(); ++y) {
+ for (int x = 0; x < b2.width(); ++x) {
+ if (b1.getColor(x, y) != b2.getColor(x, y))
+ ++pixelErrors;
+ }
+ }
+ REPORTER_ASSERT(reporter, 0 == pixelErrors);
+}
+
+static void TestPictureTypefaceSerialization(skiatest::Reporter* reporter) {
+ // Load typeface form file.
+ // This test cannot run if there is no resource path.
+ SkString resourcePath = GetResourcePath();
+ if (resourcePath.isEmpty()) {
+ SkDebugf("Could not run fontstream test because resourcePath not specified.");
+ return;
+ }
+ SkString filename = SkOSPath::Join(resourcePath.c_str(), "test.ttc");
+ SkTypeface* typeface = SkTypeface::CreateFromFile(filename.c_str(), 1);
+ if (!typeface) {
+ SkDebugf("Could not run fontstream test because test.ttc not found.");
+ return;
+ }
+
+ // Create a paint with the typeface we loaded.
+ SkPaint paint;
+ paint.setColor(SK_ColorGRAY);
+ paint.setTextSize(SkIntToScalar(30));
+ SkSafeUnref(paint.setTypeface(typeface));
+
+ // Paint some text.
+ SkPictureRecorder recorder;
+ SkIRect canvasRect = SkIRect::MakeWH(kBitmapSize, kBitmapSize);
+ SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(canvasRect.width()),
+ SkIntToScalar(canvasRect.height()),
+ NULL, 0);
+ canvas->drawColor(SK_ColorWHITE);
+ canvas->drawText("A!", 2, 24, 32, paint);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ // Serlialize picture and create its clone from stream.
+ SkDynamicMemoryWStream stream;
+ picture->serialize(&stream);
+ SkAutoTUnref<SkStream> inputStream(stream.detachAsStream());
+ SkAutoTUnref<SkPicture> loadedPicture(SkPicture::CreateFromStream(inputStream.get()));
+
+ // Draw both original and clone picture and compare bitmaps -- they should be identical.
+ SkBitmap origBitmap = draw_picture(*picture);
+ SkBitmap destBitmap = draw_picture(*loadedPicture);
+ compare_bitmaps(reporter, origBitmap, destBitmap);
+}
+
+static void setup_bitmap_for_canvas(SkBitmap* bitmap) {
+ bitmap->allocN32Pixels(kBitmapSize, kBitmapSize);
+}
+
+static void make_checkerboard_bitmap(SkBitmap& bitmap) {
+ setup_bitmap_for_canvas(&bitmap);
+
+ SkCanvas canvas(bitmap);
+ canvas.clear(0x00000000);
+ SkPaint darkPaint;
+ darkPaint.setColor(0xFF804020);
+ SkPaint lightPaint;
+ lightPaint.setColor(0xFF244484);
+ const int i = kBitmapSize / 8;
+ const SkScalar f = SkIntToScalar(i);
+ for (int y = 0; y < kBitmapSize; y += i) {
+ for (int x = 0; x < kBitmapSize; x += i) {
+ canvas.save();
+ canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
+ canvas.drawRect(SkRect::MakeXYWH(0, 0, f, f), darkPaint);
+ canvas.drawRect(SkRect::MakeXYWH(f, 0, f, f), lightPaint);
+ canvas.drawRect(SkRect::MakeXYWH(0, f, f, f), lightPaint);
+ canvas.drawRect(SkRect::MakeXYWH(f, f, f, f), darkPaint);
+ canvas.restore();
+ }
+ }
+}
+
+static void draw_something(SkCanvas* canvas) {
+ SkPaint paint;
+ SkBitmap bitmap;
+ make_checkerboard_bitmap(bitmap);
+
+ canvas->save();
+ canvas->scale(0.5f, 0.5f);
+ canvas->drawBitmap(bitmap, 0, 0, NULL);
+ canvas->restore();
+
+ const char beforeStr[] = "before circle";
+ const char afterStr[] = "after circle";
+
+ paint.setAntiAlias(true);
+
+ paint.setColor(SK_ColorRED);
+ canvas->drawData(beforeStr, sizeof(beforeStr));
+ canvas->drawCircle(SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/3), paint);
+ canvas->drawData(afterStr, sizeof(afterStr));
+ paint.setColor(SK_ColorBLACK);
+ paint.setTextSize(SkIntToScalar(kBitmapSize/3));
+ canvas->drawText("Picture", 7, SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/4), paint);
+}
+
+DEF_TEST(Serialization, reporter) {
+ // Test matrix serialization
+ {
+ SkMatrix matrix = SkMatrix::I();
+ TestObjectSerialization(&matrix, reporter);
+ }
+
+ // Test path serialization
+ {
+ SkPath path;
+ TestObjectSerialization(&path, reporter);
+ }
+
+ // Test region serialization
+ {
+ SkRegion region;
+ TestObjectSerialization(®ion, reporter);
+ }
+
+ // Test xfermode serialization
+ {
+ TestXfermodeSerialization(reporter);
+ }
+
+ // Test color filter serialization
+ {
+ TestColorFilterSerialization(reporter);
+ }
+
+ // Test string serialization
+ {
+ SkString string("string");
+ TestObjectSerializationNoAlign<SkString, false>(&string, reporter);
+ TestObjectSerializationNoAlign<SkString, true>(&string, reporter);
+ }
+
+ // Test rrect serialization
+ {
+ // SkRRect does not initialize anything.
+ // An uninitialized SkRRect can be serialized,
+ // but will branch on uninitialized data when deserialized.
+ SkRRect rrect;
+ SkRect rect = SkRect::MakeXYWH(1, 2, 20, 30);
+ SkVector corners[4] = { {1, 2}, {2, 3}, {3,4}, {4,5} };
+ rrect.setRectRadii(rect, corners);
+ TestAlignment(&rrect, reporter);
+ }
+
+ // Test readByteArray
+ {
+ unsigned char data[kArraySize] = { 1, 2, 3 };
+ TestArraySerialization(data, reporter);
+ }
+
+ // Test readColorArray
+ {
+ SkColor data[kArraySize] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorRED };
+ TestArraySerialization(data, reporter);
+ }
+
+ // Test readIntArray
+ {
+ int32_t data[kArraySize] = { 1, 2, 4, 8 };
+ TestArraySerialization(data, reporter);
+ }
+
+ // Test readPointArray
+ {
+ SkPoint data[kArraySize] = { {6, 7}, {42, 128} };
+ TestArraySerialization(data, reporter);
+ }
+
+ // Test readScalarArray
+ {
+ SkScalar data[kArraySize] = { SK_Scalar1, SK_ScalarHalf, SK_ScalarMax };
+ TestArraySerialization(data, reporter);
+ }
+
+ // Test invalid deserializations
+ {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(kBitmapSize, kBitmapSize);
+
+ SkBitmap validBitmap;
+ validBitmap.setInfo(info);
+
+ // Create a bitmap with a really large height
+ SkBitmap invalidBitmap;
+ invalidBitmap.setInfo(info.makeWH(info.width(), 1000000000));
+
+ // The deserialization should succeed, and the rendering shouldn't crash,
+ // even when the device fails to initialize, due to its size
+ TestBitmapSerialization(validBitmap, invalidBitmap, true, reporter);
+ }
+
+ // Test simple SkPicture serialization
+ {
+ SkPictureRecorder recorder;
+ draw_something(recorder.beginRecording(SkIntToScalar(kBitmapSize),
+ SkIntToScalar(kBitmapSize),
+ NULL, 0));
+ SkAutoTUnref<SkPicture> pict(recorder.endRecording());
+
+ // Serialize picture
+ SkWriteBuffer writer(SkWriteBuffer::kValidation_Flag);
+ pict->flatten(writer);
+ size_t size = writer.bytesWritten();
+ SkAutoTMalloc<unsigned char> data(size);
+ writer.writeToMemory(static_cast<void*>(data.get()));
+
+ // Deserialize picture
+ SkValidatingReadBuffer reader(static_cast<void*>(data.get()), size);
+ SkAutoTUnref<SkPicture> readPict(
+ SkPicture::CreateFromBuffer(reader));
+ REPORTER_ASSERT(reporter, readPict.get());
+ }
+
+ TestPictureTypefaceSerialization(reporter);
+}
diff --git a/src/third_party/skia/tests/ShaderImageFilterTest.cpp b/src/third_party/skia/tests/ShaderImageFilterTest.cpp
new file mode 100644
index 0000000..45fb5ca
--- /dev/null
+++ b/src/third_party/skia/tests/ShaderImageFilterTest.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkRectShaderImageFilter.h"
+#include "SkShader.h"
+#include "Test.h"
+
+DEF_TEST(ShaderImageFilter, reporter) {
+ int w = 10, h = 10;
+ SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h)); // Make small 10x10 gradient
+
+ SkBitmap filterResult, shaderResult;
+
+ filterResult.allocN32Pixels(w, h);
+ SkCanvas canvasFilter(filterResult);
+ canvasFilter.clear(0x00000000);
+
+ shaderResult.allocN32Pixels(w, h);
+ SkCanvas canvasShader(shaderResult);
+ canvasShader.clear(0x00000000);
+
+ SkPoint center = SkPoint::Make(SkIntToScalar(5), SkIntToScalar(5));
+ SkColor colors[] = {SK_ColorBLUE, SK_ColorRED, SK_ColorGREEN};
+ SkScalar pos[] = {0, SK_ScalarHalf, SK_Scalar1};
+ SkScalar radius = SkIntToScalar(5);
+
+ // Test using the image filter
+ {
+ SkShader* s = SkGradientShader::CreateRadial(
+ center, radius, colors, pos, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode);
+ SkPaint paint;
+ SkImageFilter::CropRect cr(r);
+ paint.setImageFilter(SkRectShaderImageFilter::Create(s, &cr))->unref();
+ canvasFilter.drawRect(r, paint);
+ s->unref();
+ }
+
+ // Test using the shader directly
+ {
+ SkShader* s = SkGradientShader::CreateRadial(
+ center, radius, colors, pos, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode);
+ SkPaint paint;
+ paint.setShader(s)->unref();
+ canvasShader.drawRect(r, paint);
+ }
+
+ // Assert that both paths yielded the same result
+ for (int y = 0; y < r.height(); ++y) {
+ const SkPMColor* filterPtr = filterResult.getAddr32(0, y);
+ const SkPMColor* shaderPtr = shaderResult.getAddr32(0, y);
+ for (int x = 0; x < r.width(); ++x, ++filterPtr, ++shaderPtr) {
+ REPORTER_ASSERT(reporter, *filterPtr == *shaderPtr);
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/ShaderOpacityTest.cpp b/src/third_party/skia/tests/ShaderOpacityTest.cpp
new file mode 100644
index 0000000..90d25d7
--- /dev/null
+++ b/src/third_party/skia/tests/ShaderOpacityTest.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkColorShader.h"
+#include "SkGradientShader.h"
+#include "SkShader.h"
+#include "Test.h"
+
+static void test_bitmap(skiatest::Reporter* reporter) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(2, 2);
+
+ SkBitmap bmp;
+ bmp.setInfo(info);
+
+ // test 1: bitmap without pixel data
+ SkShader* shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ REPORTER_ASSERT(reporter, shader);
+ REPORTER_ASSERT(reporter, !shader->isOpaque());
+ shader->unref();
+
+ // From this point on, we have pixels
+ bmp.allocPixels(info);
+
+ // test 2: not opaque by default
+ shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ REPORTER_ASSERT(reporter, shader);
+ REPORTER_ASSERT(reporter, !shader->isOpaque());
+ shader->unref();
+
+ // test 3: explicitly opaque
+ bmp.setAlphaType(kOpaque_SkAlphaType);
+ shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ REPORTER_ASSERT(reporter, shader);
+ REPORTER_ASSERT(reporter, shader->isOpaque());
+ shader->unref();
+
+ // test 4: explicitly not opaque
+ bmp.setAlphaType(kPremul_SkAlphaType);
+ shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ REPORTER_ASSERT(reporter, shader);
+ REPORTER_ASSERT(reporter, !shader->isOpaque());
+ shader->unref();
+
+}
+
+static void test_gradient(skiatest::Reporter* reporter)
+{
+ SkPoint pts[2];
+ pts[0].iset(0, 0);
+ pts[1].iset(1, 0);
+ SkColor colors[2];
+ SkScalar pos[2] = {SkIntToScalar(0), SkIntToScalar(1)};
+ int count = 2;
+ SkShader::TileMode mode = SkShader::kClamp_TileMode;
+
+ // test 1: all opaque
+ colors[0] = SkColorSetARGB(0xFF, 0, 0, 0);
+ colors[1] = SkColorSetARGB(0xFF, 0, 0, 0);
+ SkShader* grad = SkGradientShader::CreateLinear(pts, colors, pos, count,
+ mode);
+ REPORTER_ASSERT(reporter, grad);
+ REPORTER_ASSERT(reporter, grad->isOpaque());
+ grad->unref();
+
+ // test 2: all 0 alpha
+ colors[0] = SkColorSetARGB(0, 0, 0, 0);
+ colors[1] = SkColorSetARGB(0, 0, 0, 0);
+ grad = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
+ REPORTER_ASSERT(reporter, grad);
+ REPORTER_ASSERT(reporter, !grad->isOpaque());
+ grad->unref();
+
+ // test 3: one opaque, one transparent
+ colors[0] = SkColorSetARGB(0xFF, 0, 0, 0);
+ colors[1] = SkColorSetARGB(0x40, 0, 0, 0);
+ grad = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
+ REPORTER_ASSERT(reporter, grad);
+ REPORTER_ASSERT(reporter, !grad->isOpaque());
+ grad->unref();
+
+ // test 4: test 3, swapped
+ colors[0] = SkColorSetARGB(0x40, 0, 0, 0);
+ colors[1] = SkColorSetARGB(0xFF, 0, 0, 0);
+ grad = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
+ REPORTER_ASSERT(reporter, grad);
+ REPORTER_ASSERT(reporter, !grad->isOpaque());
+ grad->unref();
+}
+
+static void test_color(skiatest::Reporter* reporter)
+{
+ SkColorShader colorShader1(SkColorSetARGB(0,0,0,0));
+ REPORTER_ASSERT(reporter, !colorShader1.isOpaque());
+ SkColorShader colorShader2(SkColorSetARGB(0xFF,0,0,0));
+ REPORTER_ASSERT(reporter, colorShader2.isOpaque());
+ SkColorShader colorShader3(SkColorSetARGB(0x7F,0,0,0));
+ REPORTER_ASSERT(reporter, !colorShader3.isOpaque());
+}
+
+DEF_TEST(ShaderOpacity, reporter) {
+ test_gradient(reporter);
+ test_color(reporter);
+ test_bitmap(reporter);
+}
diff --git a/src/third_party/skia/tests/SizeTest.cpp b/src/third_party/skia/tests/SizeTest.cpp
new file mode 100644
index 0000000..9800aa2
--- /dev/null
+++ b/src/third_party/skia/tests/SizeTest.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSize.h"
+
+#include "Test.h"
+
+DEF_TEST(ISize, reporter) {
+ SkISize a, b;
+
+ a.set(0, 0);
+ REPORTER_ASSERT(reporter, a.isEmpty());
+ a.set(5, -5);
+ REPORTER_ASSERT(reporter, a.isEmpty());
+ a.clampNegToZero();
+ REPORTER_ASSERT(reporter, a.isEmpty());
+ b.set(5, 0);
+ REPORTER_ASSERT(reporter, a == b);
+
+ a.set(3, 5);
+ REPORTER_ASSERT(reporter, !a.isEmpty());
+ b = a;
+ REPORTER_ASSERT(reporter, !b.isEmpty());
+ REPORTER_ASSERT(reporter, a == b);
+ REPORTER_ASSERT(reporter, !(a != b));
+ REPORTER_ASSERT(reporter,
+ a.fWidth == b.fWidth && a.fHeight == b.fHeight);
+}
+
+DEF_TEST(Size, reporter) {
+ SkSize a, b;
+ int ix = 5;
+ int iy = 3;
+ SkScalar x = SkIntToScalar(ix);
+ SkScalar y = SkIntToScalar(iy);
+
+ a.set(0, 0);
+ REPORTER_ASSERT(reporter, a.isEmpty());
+ a.set(x, -x);
+ REPORTER_ASSERT(reporter, a.isEmpty());
+ a.clampNegToZero();
+ REPORTER_ASSERT(reporter, a.isEmpty());
+ b.set(x, 0);
+ REPORTER_ASSERT(reporter, a == b);
+
+ a.set(y, x);
+ REPORTER_ASSERT(reporter, !a.isEmpty());
+ b = a;
+ REPORTER_ASSERT(reporter, !b.isEmpty());
+ REPORTER_ASSERT(reporter, a == b);
+ REPORTER_ASSERT(reporter, !(a != b));
+ REPORTER_ASSERT(reporter,
+ a.fWidth == b.fWidth && a.fHeight == b.fHeight);
+
+ SkISize ia;
+ ia.set(ix, iy);
+ a.set(x, y);
+ REPORTER_ASSERT(reporter, a.toRound() == ia);
+}
diff --git a/src/third_party/skia/tests/SkBase64Test.cpp b/src/third_party/skia/tests/SkBase64Test.cpp
new file mode 100644
index 0000000..14ff1f7
--- /dev/null
+++ b/src/third_party/skia/tests/SkBase64Test.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBase64.h"
+
+#include "Test.h"
+
+DEF_TEST(SkBase64, reporter) {
+ char all[256];
+ for (int index = 0; index < 256; ++index) {
+ all[index] = (signed char) (index + 1);
+ }
+
+ for (int offset = 0; offset < 6; ++offset) {
+ size_t length = 256 - offset;
+ size_t encodeLength = SkBase64::Encode(all + offset, length, NULL);
+ SkAutoTMalloc<char> src(encodeLength + 1);
+ SkBase64::Encode(all + offset, length, src.get());
+ src[encodeLength] = '\0';
+ SkBase64 tryMe;
+ tryMe.decode(src.get(), encodeLength);
+ REPORTER_ASSERT(reporter, (strcmp((const char*) (all + offset), tryMe.getData()) == 0));
+ delete[] tryMe.getData();
+ }
+}
diff --git a/src/third_party/skia/tests/SkResourceCacheTest.cpp b/src/third_party/skia/tests/SkResourceCacheTest.cpp
new file mode 100644
index 0000000..f13476a
--- /dev/null
+++ b/src/third_party/skia/tests/SkResourceCacheTest.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "SkBitmapCache.h"
+#include "SkCanvas.h"
+#include "SkDiscardableMemoryPool.h"
+#include "SkGraphics.h"
+#include "SkResourceCache.h"
+
+static const int kCanvasSize = 1;
+static const int kBitmapSize = 16;
+static const int kScale = 8;
+
+static bool is_in_scaled_image_cache(const SkBitmap& orig,
+ SkScalar xScale,
+ SkScalar yScale) {
+ SkBitmap scaled;
+ float roundedImageWidth = SkScalarRoundToScalar(orig.width() * xScale);
+ float roundedImageHeight = SkScalarRoundToScalar(orig.height() * xScale);
+ return SkBitmapCache::Find(orig, roundedImageWidth, roundedImageHeight, &scaled);
+}
+
+// Draw a scaled bitmap, then return true iff it has been cached.
+static bool test_scaled_image_cache_useage() {
+ SkAutoTUnref<SkCanvas> canvas(
+ SkCanvas::NewRasterN32(kCanvasSize, kCanvasSize));
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(kBitmapSize, kBitmapSize);
+ bitmap.eraseColor(0xFFFFFFFF);
+ SkScalar scale = SkIntToScalar(kScale);
+ SkScalar scaledSize = SkIntToScalar(kBitmapSize) * scale;
+ canvas->clipRect(SkRect::MakeLTRB(0, 0, scaledSize, scaledSize));
+ SkPaint paint;
+ paint.setFilterLevel(SkPaint::kHigh_FilterLevel);
+
+ canvas->drawBitmapRect(bitmap,
+ SkRect::MakeLTRB(0, 0, scaledSize, scaledSize),
+ &paint);
+
+ return is_in_scaled_image_cache(bitmap, scale, scale);
+}
+
+// http://crbug.com/389439
+DEF_TEST(ResourceCache_SingleAllocationByteLimit, reporter) {
+ size_t originalByteLimit = SkGraphics::GetResourceCacheTotalByteLimit();
+ size_t originalAllocationLimit =
+ SkGraphics::GetResourceCacheSingleAllocationByteLimit();
+
+ size_t size = kBitmapSize * kScale * kBitmapSize * kScale
+ * SkColorTypeBytesPerPixel(kN32_SkColorType);
+
+ SkGraphics::SetResourceCacheTotalByteLimit(0); // clear cache
+ SkGraphics::SetResourceCacheTotalByteLimit(2 * size);
+ SkGraphics::SetResourceCacheSingleAllocationByteLimit(0); // No limit
+
+ REPORTER_ASSERT(reporter, test_scaled_image_cache_useage());
+
+ SkGraphics::SetResourceCacheTotalByteLimit(0); // clear cache
+ SkGraphics::SetResourceCacheTotalByteLimit(2 * size);
+ SkGraphics::SetResourceCacheSingleAllocationByteLimit(size * 2); // big enough
+
+ REPORTER_ASSERT(reporter, test_scaled_image_cache_useage());
+
+ SkGraphics::SetResourceCacheTotalByteLimit(0); // clear cache
+ SkGraphics::SetResourceCacheTotalByteLimit(2 * size);
+ SkGraphics::SetResourceCacheSingleAllocationByteLimit(size / 2); // too small
+
+ REPORTER_ASSERT(reporter, !test_scaled_image_cache_useage());
+
+ SkGraphics::SetResourceCacheSingleAllocationByteLimit(originalAllocationLimit);
+ SkGraphics::SetResourceCacheTotalByteLimit(originalByteLimit);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+static void make_bitmap(SkBitmap* bitmap, const SkImageInfo& info, SkBitmap::Allocator* allocator) {
+ if (allocator) {
+ bitmap->setInfo(info);
+ allocator->allocPixelRef(bitmap, 0);
+ } else {
+ bitmap->allocPixels(info);
+ }
+}
+
+// http://skbug.com/2894
+DEF_TEST(BitmapCache_add_rect, reporter) {
+ SkResourceCache::DiscardableFactory factory = SkResourceCache::GetDiscardableFactory();
+ SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator();
+
+ SkAutoTDelete<SkResourceCache> cache;
+ if (factory) {
+ cache.reset(SkNEW_ARGS(SkResourceCache, (factory)));
+ } else {
+ const size_t byteLimit = 100 * 1024;
+ cache.reset(SkNEW_ARGS(SkResourceCache, (byteLimit)));
+ }
+ SkBitmap cachedBitmap;
+ make_bitmap(&cachedBitmap, SkImageInfo::MakeN32Premul(5, 5), allocator);
+ cachedBitmap.setImmutable();
+
+ SkBitmap bm;
+ SkIRect rect = SkIRect::MakeWH(5, 5);
+
+ // Wrong subset size
+ REPORTER_ASSERT(reporter, !SkBitmapCache::Add(cachedBitmap.getGenerationID(), SkIRect::MakeWH(4, 6), cachedBitmap, cache));
+ REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
+ // Wrong offset value
+ REPORTER_ASSERT(reporter, !SkBitmapCache::Add(cachedBitmap.getGenerationID(), SkIRect::MakeXYWH(-1, 0, 5, 5), cachedBitmap, cache));
+ REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
+
+ // Should not be in the cache
+ REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
+
+ REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.getGenerationID(), rect, cachedBitmap, cache));
+ // Should be in the cache, we just added it
+ REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
+}
+
+DEF_TEST(BitmapCache_discarded_bitmap, reporter) {
+ SkResourceCache::DiscardableFactory factory = SkResourceCache::GetDiscardableFactory();
+ SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator();
+
+ SkAutoTDelete<SkResourceCache> cache;
+ if (factory) {
+ cache.reset(SkNEW_ARGS(SkResourceCache, (factory)));
+ } else {
+ const size_t byteLimit = 100 * 1024;
+ cache.reset(SkNEW_ARGS(SkResourceCache, (byteLimit)));
+ }
+ SkBitmap cachedBitmap;
+ make_bitmap(&cachedBitmap, SkImageInfo::MakeN32Premul(5, 5), allocator);
+ cachedBitmap.setImmutable();
+ cachedBitmap.unlockPixels();
+
+ SkBitmap bm;
+ SkIRect rect = SkIRect::MakeWH(5, 5);
+
+ // Add a bitmap to the cache.
+ REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.getGenerationID(), rect, cachedBitmap, cache));
+ REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
+
+ // Finding more than once works fine.
+ REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
+ bm.unlockPixels();
+
+ // Drop the pixels in the bitmap.
+ if (factory) {
+ REPORTER_ASSERT(reporter, SkGetGlobalDiscardableMemoryPool()->getRAMUsed() > 0);
+ SkGetGlobalDiscardableMemoryPool()->dumpPool();
+ REPORTER_ASSERT(reporter, SkGetGlobalDiscardableMemoryPool()->getRAMUsed() == 0);
+
+ // The bitmap is not in the cache since it has been dropped.
+ REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
+ }
+
+ make_bitmap(&cachedBitmap, SkImageInfo::MakeN32Premul(5, 5), allocator);
+ cachedBitmap.setImmutable();
+ cachedBitmap.unlockPixels();
+
+ // We can add the bitmap back to the cache and find it again.
+ REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.getGenerationID(), rect, cachedBitmap, cache));
+ REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache));
+}
diff --git a/src/third_party/skia/tests/SkpSkGrTest.cpp b/src/third_party/skia/tests/SkpSkGrTest.cpp
new file mode 100644
index 0000000..c882654
--- /dev/null
+++ b/src/third_party/skia/tests/SkpSkGrTest.cpp
@@ -0,0 +1,752 @@
+#if !SK_SUPPORT_GPU
+#error "GPU support required"
+#endif
+
+#include "GrContext.h"
+#include "GrContextFactory.h"
+#include "GrRenderTarget.h"
+#include "SkGpuDevice.h"
+#include "gl/GrGLDefines.h"
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColor.h"
+#include "SkDevice.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkImageEncoder.h"
+#include "SkOSFile.h"
+#include "SkPicture.h"
+#include "SkRTConf.h"
+#include "SkRunnable.h"
+#include "SkStream.h"
+#include "SkString.h"
+#include "SkTArray.h"
+#include "SkTDArray.h"
+#include "SkTaskGroup.h"
+#include "SkTime.h"
+#include "Test.h"
+
+#ifdef SK_BUILD_FOR_WIN
+ #define PATH_SLASH "\\"
+ #define IN_DIR "D:\\9-30-13\\"
+ #define OUT_DIR "D:\\skpSkGr\\11\\"
+ #define LINE_FEED "\r\n"
+#else
+ #define PATH_SLASH "/"
+ #define IN_DIR "/usr/local/google/home/caryclark" PATH_SLASH "9-30-13-skp"
+ #define OUT_DIR "/media/01CD75512A7F9EE0/4" PATH_SLASH
+ #define LINE_FEED "\n"
+#endif
+
+#define PATH_STR_SIZE 512
+
+static const struct {
+ int directory;
+ const char* filename;
+} skipOverSkGr[] = {
+ {1, "http___accuweather_com_.skp"}, // Couldn't convert bitmap to texture.http___absoku072_com_
+};
+
+static const size_t skipOverSkGrCount = SK_ARRAY_COUNT(skipOverSkGr);
+
+/////////////////////////////////////////
+
+class SkpSkGrThreadedRunnable;
+
+enum TestStep {
+ kCompareBits,
+ kEncodeFiles,
+};
+
+enum {
+ kMaxLength = 128,
+ kMaxFiles = 128,
+};
+
+struct TestResult {
+ void init(int dirNo) {
+ fDirNo = dirNo;
+ sk_bzero(fFilename, sizeof(fFilename));
+ fTestStep = kCompareBits;
+ fScaleOversized = true;
+ }
+
+ SkString status() {
+ SkString outStr;
+ outStr.printf("%s %d %d%s", fFilename, fPixelError, fTime, LINE_FEED);
+ return outStr;
+ }
+
+ static void Test(int dirNo, const char* filename, TestStep testStep, bool verbose) {
+ TestResult test;
+ test.init(dirNo);
+ test.fTestStep = testStep;
+ strcpy(test.fFilename, filename);
+ test.testOne();
+ if (verbose) {
+ SkDebugf("%s", test.status().c_str());
+ }
+ }
+
+ void test(int dirNo, const SkString& filename) {
+ init(dirNo);
+ strcpy(fFilename, filename.c_str());
+ testOne();
+ }
+
+ void testOne();
+
+ char fFilename[kMaxLength];
+ TestStep fTestStep;
+ int fDirNo;
+ int fPixelError;
+ int fTime;
+ bool fScaleOversized;
+};
+
+struct SkpSkGrThreadState {
+ void init(int dirNo) {
+ fResult.init(dirNo);
+ fFoundCount = 0;
+ fSmallestError = 0;
+ sk_bzero(fFilesFound, sizeof(fFilesFound));
+ sk_bzero(fDirsFound, sizeof(fDirsFound));
+ sk_bzero(fError, sizeof(fError));
+ }
+
+ char fFilesFound[kMaxFiles][kMaxLength];
+ int fDirsFound[kMaxFiles];
+ int fError[kMaxFiles];
+ int fFoundCount;
+ int fSmallestError;
+ skiatest::Reporter* fReporter;
+ TestResult fResult;
+};
+
+struct SkpSkGrThreadedTestRunner {
+ SkpSkGrThreadedTestRunner(skiatest::Reporter* reporter)
+ : fReporter(reporter) {
+ }
+
+ ~SkpSkGrThreadedTestRunner();
+ void render();
+ SkTDArray<SkpSkGrThreadedRunnable*> fRunnables;
+ skiatest::Reporter* fReporter;
+};
+
+class SkpSkGrThreadedRunnable : public SkRunnable {
+public:
+ SkpSkGrThreadedRunnable(void (*testFun)(SkpSkGrThreadState*), int dirNo, const char* str,
+ SkpSkGrThreadedTestRunner* runner) {
+ SkASSERT(strlen(str) < sizeof(fState.fResult.fFilename) - 1);
+ fState.init(dirNo);
+ strcpy(fState.fResult.fFilename, str);
+ fState.fReporter = runner->fReporter;
+ fTestFun = testFun;
+ }
+
+ virtual void run() SK_OVERRIDE {
+ SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
+ (*fTestFun)(&fState);
+ }
+
+ SkpSkGrThreadState fState;
+ void (*fTestFun)(SkpSkGrThreadState*);
+};
+
+SkpSkGrThreadedTestRunner::~SkpSkGrThreadedTestRunner() {
+ for (int index = 0; index < fRunnables.count(); index++) {
+ SkDELETE(fRunnables[index]);
+ }
+}
+
+void SkpSkGrThreadedTestRunner::render() {
+ SkTaskGroup tg;
+ for (int index = 0; index < fRunnables.count(); ++ index) {
+ tg.add(fRunnables[index]);
+ }
+}
+
+////////////////////////////////////////////////
+
+static const char outGrDir[] = OUT_DIR "grTest";
+static const char outSkDir[] = OUT_DIR "skTest";
+static const char outSkpDir[] = OUT_DIR "skpTest";
+static const char outDiffDir[] = OUT_DIR "outTest";
+static const char outStatusDir[] = OUT_DIR "statusTest";
+
+static SkString make_filepath(int dirIndex, const char* dir, const char* name) {
+ SkString path(dir);
+ if (dirIndex) {
+ path.appendf("%d", dirIndex);
+ }
+ path.append(PATH_SLASH);
+ path.append(name);
+ return path;
+}
+
+static SkString make_in_dir_name(int dirIndex) {
+ SkString dirName(IN_DIR);
+ dirName.appendf("%d", dirIndex);
+ if (!sk_exists(dirName.c_str())) {
+ SkDebugf("could not read dir %s\n", dirName.c_str());
+ return SkString();
+ }
+ return dirName;
+}
+
+static bool make_out_dirs() {
+ SkString outDir = make_filepath(0, OUT_DIR, "");
+ if (!sk_exists(outDir.c_str())) {
+ if (!sk_mkdir(outDir.c_str())) {
+ SkDebugf("could not create dir %s\n", outDir.c_str());
+ return false;
+ }
+ }
+ SkString grDir = make_filepath(0, outGrDir, "");
+ if (!sk_exists(grDir.c_str())) {
+ if (!sk_mkdir(grDir.c_str())) {
+ SkDebugf("could not create dir %s\n", grDir.c_str());
+ return false;
+ }
+ }
+ SkString skDir = make_filepath(0, outSkDir, "");
+ if (!sk_exists(skDir.c_str())) {
+ if (!sk_mkdir(skDir.c_str())) {
+ SkDebugf("could not create dir %s\n", skDir.c_str());
+ return false;
+ }
+ }
+ SkString skpDir = make_filepath(0, outSkpDir, "");
+ if (!sk_exists(skpDir.c_str())) {
+ if (!sk_mkdir(skpDir.c_str())) {
+ SkDebugf("could not create dir %s\n", skpDir.c_str());
+ return false;
+ }
+ }
+ SkString diffDir = make_filepath(0, outDiffDir, "");
+ if (!sk_exists(diffDir.c_str())) {
+ if (!sk_mkdir(diffDir.c_str())) {
+ SkDebugf("could not create dir %s\n", diffDir.c_str());
+ return false;
+ }
+ }
+ SkString statusDir = make_filepath(0, outStatusDir, "");
+ if (!sk_exists(statusDir.c_str())) {
+ if (!sk_mkdir(statusDir.c_str())) {
+ SkDebugf("could not create dir %s\n", statusDir.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+static SkString make_png_name(const char* filename) {
+ SkString pngName = SkString(filename);
+ pngName.remove(pngName.size() - 3, 3);
+ pngName.append("png");
+ return pngName;
+}
+
+typedef GrContextFactory::GLContextType GLContextType;
+#ifdef SK_BUILD_FOR_WIN
+static const GLContextType kAngle = GrContextFactory::kANGLE_GLContextType;
+#else
+static const GLContextType kNative = GrContextFactory::kNative_GLContextType;
+#endif
+
+static int similarBits(const SkBitmap& gr, const SkBitmap& sk) {
+ const int kRowCount = 3;
+ const int kThreshold = 3;
+ int width = SkTMin(gr.width(), sk.width());
+ if (width < kRowCount) {
+ return true;
+ }
+ int height = SkTMin(gr.height(), sk.height());
+ if (height < kRowCount) {
+ return true;
+ }
+ int errorTotal = 0;
+ SkTArray<char, true> errorRows;
+ errorRows.push_back_n(width * kRowCount);
+ SkAutoLockPixels autoGr(gr);
+ SkAutoLockPixels autoSk(sk);
+ char* base = &errorRows[0];
+ for (int y = 0; y < height; ++y) {
+ SkPMColor* grRow = gr.getAddr32(0, y);
+ SkPMColor* skRow = sk.getAddr32(0, y);
+ char* cOut = &errorRows[(y % kRowCount) * width];
+ for (int x = 0; x < width; ++x) {
+ SkPMColor grColor = grRow[x];
+ SkPMColor skColor = skRow[x];
+ int dr = SkGetPackedR32(grColor) - SkGetPackedR32(skColor);
+ int dg = SkGetPackedG32(grColor) - SkGetPackedG32(skColor);
+ int db = SkGetPackedB32(grColor) - SkGetPackedB32(skColor);
+ int error = SkTMax(SkAbs32(dr), SkTMax(SkAbs32(dg), SkAbs32(db)));
+ if ((cOut[x] = error >= kThreshold) && x >= 2
+ && base[x - 2] && base[width + x - 2] && base[width * 2 + x - 2]
+ && base[x - 1] && base[width + x - 1] && base[width * 2 + x - 1]
+ && base[x - 0] && base[width + x - 0] && base[width * 2 + x - 0]) {
+ errorTotal += error;
+ }
+ }
+ }
+ return errorTotal;
+}
+
+static bool addError(SkpSkGrThreadState* data) {
+ bool foundSmaller = false;
+ int dCount = data->fFoundCount;
+ int pixelError = data->fResult.fPixelError;
+ if (data->fFoundCount < kMaxFiles) {
+ data->fError[dCount] = pixelError;
+ strcpy(data->fFilesFound[dCount], data->fResult.fFilename);
+ data->fDirsFound[dCount] = data->fResult.fDirNo;
+ ++data->fFoundCount;
+ } else if (pixelError > data->fSmallestError) {
+ int smallest = SK_MaxS32;
+ int smallestIndex = 0;
+ for (int index = 0; index < kMaxFiles; ++index) {
+ if (smallest > data->fError[index]) {
+ smallest = data->fError[index];
+ smallestIndex = index;
+ }
+ }
+ data->fError[smallestIndex] = pixelError;
+ strcpy(data->fFilesFound[smallestIndex], data->fResult.fFilename);
+ data->fDirsFound[smallestIndex] = data->fResult.fDirNo;
+ data->fSmallestError = SK_MaxS32;
+ for (int index = 0; index < kMaxFiles; ++index) {
+ if (data->fSmallestError > data->fError[index]) {
+ data->fSmallestError = data->fError[index];
+ }
+ }
+ SkDebugf("*%d*", data->fSmallestError);
+ foundSmaller = true;
+ }
+ return foundSmaller;
+}
+
+static SkMSec timePict(SkPicture* pic, SkCanvas* canvas) {
+ canvas->save();
+ int pWidth = pic->width();
+ int pHeight = pic->height();
+ const int maxDimension = 1000;
+ const int slices = 3;
+ int xInterval = SkTMax(pWidth - maxDimension, 0) / (slices - 1);
+ int yInterval = SkTMax(pHeight - maxDimension, 0) / (slices - 1);
+ SkRect rect = {0, 0, SkIntToScalar(SkTMin(maxDimension, pWidth)),
+ SkIntToScalar(SkTMin(maxDimension, pHeight))};
+ canvas->clipRect(rect);
+ SkMSec start = SkTime::GetMSecs();
+ for (int x = 0; x < slices; ++x) {
+ for (int y = 0; y < slices; ++y) {
+ pic->draw(canvas);
+ canvas->translate(0, SkIntToScalar(yInterval));
+ }
+ canvas->translate(SkIntToScalar(xInterval), SkIntToScalar(-yInterval * slices));
+ }
+ SkMSec end = SkTime::GetMSecs();
+ canvas->restore();
+ return end - start;
+}
+
+static void drawPict(SkPicture* pic, SkCanvas* canvas, int scale) {
+ canvas->clear(SK_ColorWHITE);
+ if (scale != 1) {
+ canvas->save();
+ canvas->scale(1.0f / scale, 1.0f / scale);
+ }
+ pic->draw(canvas);
+ if (scale != 1) {
+ canvas->restore();
+ }
+}
+
+static void writePict(const SkBitmap& bitmap, const char* outDir, const char* pngName) {
+ SkString outFile = make_filepath(0, outDir, pngName);
+ if (!SkImageEncoder::EncodeFile(outFile.c_str(), bitmap,
+ SkImageEncoder::kPNG_Type, 100)) {
+ SkDebugf("unable to encode gr %s (width=%d height=%d)br \n", pngName,
+ bitmap.width(), bitmap.height());
+ }
+}
+
+void TestResult::testOne() {
+ SkPicture* pic = NULL;
+ {
+ SkString d;
+ d.printf(" {%d, \"%s\"},", fDirNo, fFilename);
+ SkString path = make_filepath(fDirNo, IN_DIR, fFilename);
+ SkFILEStream stream(path.c_str());
+ if (!stream.isValid()) {
+ SkDebugf("invalid stream %s\n", path.c_str());
+ goto finish;
+ }
+ if (fTestStep == kEncodeFiles) {
+ size_t length = stream.getLength();
+ SkTArray<char, true> bytes;
+ bytes.push_back_n(length);
+ stream.read(&bytes[0], length);
+ stream.rewind();
+ SkString wPath = make_filepath(0, outSkpDir, fFilename);
+ SkFILEWStream wStream(wPath.c_str());
+ wStream.write(&bytes[0], length);
+ wStream.flush();
+ }
+ pic = SkPicture::CreateFromStream(&stream, &SkImageDecoder::DecodeMemory);
+ if (!pic) {
+ SkDebugf("unable to decode %s\n", fFilename);
+ goto finish;
+ }
+ int pWidth = pic->width();
+ int pHeight = pic->height();
+ int pLargerWH = SkTMax(pWidth, pHeight);
+ GrContextFactory contextFactory;
+#ifdef SK_BUILD_FOR_WIN
+ GrContext* context = contextFactory.get(kAngle);
+#else
+ GrContext* context = contextFactory.get(kNative);
+#endif
+ if (NULL == context) {
+ SkDebugf("unable to allocate context for %s\n", fFilename);
+ goto finish;
+ }
+ int maxWH = context->getMaxRenderTargetSize();
+ int scale = 1;
+ while (pLargerWH / scale > maxWH) {
+ scale *= 2;
+ }
+ SkBitmap bitmap;
+ SkIPoint dim;
+ do {
+ dim.fX = (pWidth + scale - 1) / scale;
+ dim.fY = (pHeight + scale - 1) / scale;
+ bool success = bitmap.allocN32Pixels(dim.fX, dim.fY);
+ if (success) {
+ break;
+ }
+ SkDebugf("-%d-", scale);
+ } while ((scale *= 2) < 256);
+ if (scale >= 256) {
+ SkDebugf("unable to allocate bitmap for %s (w=%d h=%d) (sw=%d sh=%d)\n",
+ fFilename, pWidth, pHeight, dim.fX, dim.fY);
+ goto finish;
+ }
+ SkCanvas skCanvas(bitmap);
+ drawPict(pic, &skCanvas, fScaleOversized ? scale : 1);
+ GrTextureDesc desc;
+ desc.fConfig = kSkia8888_GrPixelConfig;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ desc.fWidth = dim.fX;
+ desc.fHeight = dim.fY;
+ desc.fSampleCnt = 0;
+ SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, NULL, 0));
+ if (!texture) {
+ SkDebugf("unable to allocate texture for %s (w=%d h=%d)\n", fFilename,
+ dim.fX, dim.fY);
+ goto finish;
+ }
+ SkGpuDevice grDevice(context, texture.get());
+ SkCanvas grCanvas(&grDevice);
+ drawPict(pic, &grCanvas, fScaleOversized ? scale : 1);
+
+ SkBitmap grBitmap;
+ grBitmap.allocPixels(grCanvas.imageInfo());
+ grCanvas.readPixels(&grBitmap, 0, 0);
+
+ if (fTestStep == kCompareBits) {
+ fPixelError = similarBits(grBitmap, bitmap);
+ int skTime = timePict(pic, &skCanvas);
+ int grTime = timePict(pic, &grCanvas);
+ fTime = skTime - grTime;
+ } else if (fTestStep == kEncodeFiles) {
+ SkString pngStr = make_png_name(fFilename);
+ const char* pngName = pngStr.c_str();
+ writePict(grBitmap, outGrDir, pngName);
+ writePict(bitmap, outSkDir, pngName);
+ }
+ }
+finish:
+ SkDELETE(pic);
+}
+
+static SkString makeStatusString(int dirNo) {
+ SkString statName;
+ statName.printf("stats%d.txt", dirNo);
+ SkString statusFile = make_filepath(0, outStatusDir, statName.c_str());
+ return statusFile;
+}
+
+class PreParser {
+public:
+ PreParser(int dirNo)
+ : fDirNo(dirNo)
+ , fIndex(0)
+ , fStatusPath(makeStatusString(dirNo)) {
+ if (!sk_exists(fStatusPath.c_str())) {
+ return;
+ }
+ SkFILEStream reader;
+ reader.setPath(fStatusPath.c_str());
+ while (fetch(reader, &fResults.push_back()))
+ ;
+ fResults.pop_back();
+ }
+
+ bool fetch(SkFILEStream& reader, TestResult* result) {
+ char c;
+ int i = 0;
+ result->init(fDirNo);
+ result->fPixelError = 0;
+ result->fTime = 0;
+ do {
+ bool readOne = reader.read(&c, 1) != 0;
+ if (!readOne) {
+ SkASSERT(i == 0);
+ return false;
+ }
+ if (c == ' ') {
+ result->fFilename[i++] = '\0';
+ break;
+ }
+ result->fFilename[i++] = c;
+ SkASSERT(i < kMaxLength);
+ } while (true);
+ do {
+ SkAssertResult(reader.read(&c, 1) != 0);
+ if (c == ' ') {
+ break;
+ }
+ SkASSERT(c >= '0' && c <= '9');
+ result->fPixelError = result->fPixelError * 10 + (c - '0');
+ } while (true);
+ bool minus = false;
+ do {
+ if (reader.read(&c, 1) == 0) {
+ break;
+ }
+ if (c == '\r' && reader.read(&c, 1) == 0) {
+ break;
+ }
+ if (c == '\n') {
+ break;
+ }
+ if (c == '-') {
+ minus = true;
+ continue;
+ }
+ SkASSERT(c >= '0' && c <= '9');
+ result->fTime = result->fTime * 10 + (c - '0');
+ } while (true);
+ if (minus) {
+ result->fTime = -result->fTime;
+ }
+ return true;
+ }
+
+ bool match(const SkString& filename, SkFILEWStream* stream, TestResult* result) {
+ if (fIndex < fResults.count()) {
+ *result = fResults[fIndex++];
+ SkASSERT(filename.equals(result->fFilename));
+ SkString outStr(result->status());
+ stream->write(outStr.c_str(), outStr.size());
+ stream->flush();
+ return true;
+ }
+ return false;
+ }
+
+private:
+ int fDirNo;
+ int fIndex;
+ SkTArray<TestResult, true> fResults;
+ SkString fStatusPath;
+};
+
+static bool initTest() {
+#if !defined SK_BUILD_FOR_WIN && !defined SK_BUILD_FOR_MAC
+ SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true);
+ SK_CONF_SET("images.png.suppressDecoderWarnings", true);
+#endif
+ return make_out_dirs();
+}
+
+DEF_TEST(SkpSkGr, reporter) {
+ SkTArray<TestResult, true> errors;
+ if (!initTest()) {
+ return;
+ }
+ SkpSkGrThreadState state;
+ state.init(0);
+ int smallCount = 0;
+ for (int dirNo = 1; dirNo <= 100; ++dirNo) {
+ SkString pictDir = make_in_dir_name(dirNo);
+ SkASSERT(pictDir.size());
+ if (reporter->verbose()) {
+ SkDebugf("dirNo=%d\n", dirNo);
+ }
+ SkOSFile::Iter iter(pictDir.c_str(), "skp");
+ SkString filename;
+ int testCount = 0;
+ PreParser preParser(dirNo);
+ SkFILEWStream statusStream(makeStatusString(dirNo).c_str());
+ while (iter.next(&filename)) {
+ for (size_t index = 0; index < skipOverSkGrCount; ++index) {
+ if (skipOverSkGr[index].directory == dirNo
+ && strcmp(filename.c_str(), skipOverSkGr[index].filename) == 0) {
+ goto skipOver;
+ }
+ }
+ if (preParser.match(filename, &statusStream, &state.fResult)) {
+ addError(&state);
+ ++testCount;
+ goto checkEarlyExit;
+ }
+ if (state.fSmallestError > 5000000) {
+ goto breakOut;
+ }
+ {
+ TestResult& result = state.fResult;
+ result.test(dirNo, filename);
+ SkString outStr(result.status());
+ statusStream.write(outStr.c_str(), outStr.size());
+ statusStream.flush();
+ if (1) {
+ SkDebugf("%s", outStr.c_str());
+ }
+ bool noMatch = addError(&state);
+ if (noMatch) {
+ smallCount = 0;
+ } else if (++smallCount > 10000) {
+ goto breakOut;
+ }
+ }
+ ++testCount;
+ if (reporter->verbose()) {
+ if (testCount % 100 == 0) {
+ SkDebugf("#%d\n", testCount);
+ }
+ }
+ skipOver:
+ reporter->bumpTestCount();
+ checkEarlyExit:
+ if (1 && testCount == 20) {
+ break;
+ }
+ }
+ }
+breakOut:
+ if (reporter->verbose()) {
+ for (int index = 0; index < state.fFoundCount; ++index) {
+ SkDebugf("%d %s %d\n", state.fDirsFound[index], state.fFilesFound[index],
+ state.fError[index]);
+ }
+ }
+ for (int index = 0; index < state.fFoundCount; ++index) {
+ TestResult::Test(state.fDirsFound[index], state.fFilesFound[index], kEncodeFiles,
+ reporter->verbose());
+ if (reporter->verbose()) SkDebugf("+");
+ }
+}
+
+static void bumpCount(skiatest::Reporter* reporter, bool skipping) {
+ if (reporter->verbose()) {
+ static int threadTestCount;
+ sk_atomic_inc(&threadTestCount);
+ if (!skipping && threadTestCount % 100 == 0) {
+ SkDebugf("#%d\n", threadTestCount);
+ }
+ if (skipping && threadTestCount % 10000 == 0) {
+ SkDebugf("#%d\n", threadTestCount);
+ }
+ }
+}
+
+static void testSkGrMain(SkpSkGrThreadState* data) {
+ data->fResult.testOne();
+ bumpCount(data->fReporter, false);
+ data->fReporter->bumpTestCount();
+}
+
+DEF_TEST(SkpSkGrThreaded, reporter) {
+ if (!initTest()) {
+ return;
+ }
+ SkpSkGrThreadedTestRunner testRunner(reporter);
+ for (int dirIndex = 1; dirIndex <= 100; ++dirIndex) {
+ SkString pictDir = make_in_dir_name(dirIndex);
+ if (pictDir.size() == 0) {
+ continue;
+ }
+ SkOSFile::Iter iter(pictDir.c_str(), "skp");
+ SkString filename;
+ while (iter.next(&filename)) {
+ SkString pngName = make_png_name(filename.c_str());
+ SkString oldPng = make_filepath(dirIndex, outSkDir, pngName.c_str());
+ SkString newPng = make_filepath(dirIndex, outGrDir, pngName.c_str());
+ if (sk_exists(oldPng.c_str()) && sk_exists(newPng.c_str())) {
+ bumpCount(reporter, true);
+ continue;
+ }
+ for (size_t index = 0; index < skipOverSkGrCount; ++index) {
+ if (skipOverSkGr[index].directory == dirIndex
+ && strcmp(filename.c_str(), skipOverSkGr[index].filename) == 0) {
+ bumpCount(reporter, true);
+ goto skipOver;
+ }
+ }
+ *testRunner.fRunnables.append() = SkNEW_ARGS(SkpSkGrThreadedRunnable,
+ (&testSkGrMain, dirIndex, filename.c_str(), &testRunner));
+ skipOver:
+ ;
+ }
+ }
+ testRunner.render();
+ SkpSkGrThreadState& max = testRunner.fRunnables[0]->fState;
+ for (int dirIndex = 2; dirIndex <= 100; ++dirIndex) {
+ SkpSkGrThreadState& state = testRunner.fRunnables[dirIndex - 1]->fState;
+ for (int index = 0; index < state.fFoundCount; ++index) {
+ int maxIdx = max.fFoundCount;
+ if (maxIdx < kMaxFiles) {
+ max.fError[maxIdx] = state.fError[index];
+ strcpy(max.fFilesFound[maxIdx], state.fFilesFound[index]);
+ max.fDirsFound[maxIdx] = state.fDirsFound[index];
+ ++max.fFoundCount;
+ continue;
+ }
+ for (maxIdx = 0; maxIdx < max.fFoundCount; ++maxIdx) {
+ if (max.fError[maxIdx] < state.fError[index]) {
+ max.fError[maxIdx] = state.fError[index];
+ strcpy(max.fFilesFound[maxIdx], state.fFilesFound[index]);
+ max.fDirsFound[maxIdx] = state.fDirsFound[index];
+ break;
+ }
+ }
+ }
+ }
+ TestResult encoder;
+ encoder.fTestStep = kEncodeFiles;
+ for (int index = 0; index < max.fFoundCount; ++index) {
+ encoder.fDirNo = max.fDirsFound[index];
+ strcpy(encoder.fFilename, max.fFilesFound[index]);
+ encoder.testOne();
+ SkDebugf("+");
+ }
+}
+
+DEF_TEST(SkpSkGrOneOff, reporter) {
+ if (!initTest()) {
+ return;
+ }
+ int testIndex = 166;
+ int dirIndex = skipOverSkGr[testIndex - 166].directory;
+ SkString pictDir = make_in_dir_name(dirIndex);
+ if (pictDir.size() == 0) {
+ return;
+ }
+ SkString filename(skipOverSkGr[testIndex - 166].filename);
+ TestResult::Test(dirIndex, filename.c_str(), kCompareBits, reporter->verbose());
+ TestResult::Test(dirIndex, filename.c_str(), kEncodeFiles, reporter->verbose());
+}
diff --git a/src/third_party/skia/tests/SmallAllocatorTest.cpp b/src/third_party/skia/tests/SmallAllocatorTest.cpp
new file mode 100644
index 0000000..30c8ffa
--- /dev/null
+++ b/src/third_party/skia/tests/SmallAllocatorTest.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014 Google, Inc
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSmallAllocator.h"
+#include "SkTypes.h"
+#include "Test.h"
+
+class CountingClass {
+public:
+ CountingClass() {
+ kCount++;
+ }
+
+ ~CountingClass() {
+ kCount--;
+ }
+
+ static int GetCount() { return kCount; }
+
+private:
+ static int kCount;
+};
+
+int CountingClass::kCount;
+
+template<uint32_t kMaxObjects, size_t kBytes> void test_allocator(skiatest::Reporter* reporter) {
+ {
+ SkSmallAllocator<kMaxObjects, kBytes> alloc;
+ for (uint32_t i = 0; i < kMaxObjects; ++i) {
+ CountingClass* c = alloc.template createT<CountingClass>();
+ REPORTER_ASSERT(reporter, c != NULL);
+ REPORTER_ASSERT(reporter, CountingClass::GetCount() == static_cast<int>(i+1));
+ }
+ }
+ REPORTER_ASSERT(reporter, CountingClass::GetCount() == 0);
+}
+
+// Tests that ensure that the destructor is called, whether the objects
+// were created in fStorage or on the heap.
+DEF_TEST(SmallAllocator_destructor, reporter) {
+ // Four times as many bytes as objects will never require any heap
+ // allocations (since SkAlign4(sizeof(CountingClass)) == 4 and the allocator
+ // will stop once it reaches kMaxObjects).
+ test_allocator<5, 20>(reporter);
+ test_allocator<10, 40>(reporter);
+ test_allocator<20, 80>(reporter);
+
+#ifndef SK_DEBUG
+ // Allowing less bytes than objects means some will be allocated on the
+ // heap. Don't run these in debug where we assert.
+ test_allocator<50, 20>(reporter);
+ test_allocator<100, 20>(reporter);
+#endif
+}
+
+class Dummy {
+};
+
+class DummyContainer {
+public:
+ explicit DummyContainer(Dummy* d)
+ :fDummy(d)
+ {}
+
+ Dummy* getDummy() const { return fDummy; }
+
+private:
+ Dummy* fDummy;
+};
+
+// Test that using a createT with a constructor taking a pointer as a
+// parameter works as expected.
+DEF_TEST(SmallAllocator_pointer, reporter) {
+ SkSmallAllocator<1, 8> alloc;
+ Dummy d;
+ DummyContainer* container = alloc.createT<DummyContainer>(&d);
+ REPORTER_ASSERT(reporter, container != NULL);
+ REPORTER_ASSERT(reporter, container->getDummy() == &d);
+}
diff --git a/src/third_party/skia/tests/SortTest.cpp b/src/third_party/skia/tests/SortTest.cpp
new file mode 100644
index 0000000..e8713dd
--- /dev/null
+++ b/src/third_party/skia/tests/SortTest.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRandom.h"
+#include "SkTSort.h"
+#include "Test.h"
+
+extern "C" {
+ static int compare_int(const void* a, const void* b) {
+ return *(const int*)a - *(const int*)b;
+ }
+}
+
+static void rand_array(SkRandom& rand, int array[], int n) {
+ for (int j = 0; j < n; j++) {
+ array[j] = rand.nextS() & 0xFF;
+ }
+}
+
+static void check_sort(skiatest::Reporter* reporter, const char label[],
+ const int array[], const int reference[], int n) {
+ for (int j = 0; j < n; ++j) {
+ if (array[j] != reference[j]) {
+ ERRORF(reporter, "%sSort [%d] failed %d %d",
+ label, n, array[j], reference[j]);
+ }
+ }
+}
+
+DEF_TEST(Sort, reporter) {
+ /** An array of random numbers to be sorted. */
+ int randomArray[500];
+ /** The reference sort of the random numbers. */
+ int sortedArray[SK_ARRAY_COUNT(randomArray)];
+ /** The random numbers are copied into this array, sorted by an SkSort,
+ then this array is compared against the reference sort. */
+ int workingArray[SK_ARRAY_COUNT(randomArray)];
+ SkRandom rand;
+
+ for (int i = 0; i < 10000; i++) {
+ int count = rand.nextRangeU(1, SK_ARRAY_COUNT(randomArray));
+ rand_array(rand, randomArray, count);
+
+ // Use qsort as the reference sort.
+ memcpy(sortedArray, randomArray, sizeof(randomArray));
+ qsort(sortedArray, count, sizeof(sortedArray[0]), compare_int);
+
+ memcpy(workingArray, randomArray, sizeof(randomArray));
+ SkTHeapSort<int>(workingArray, count);
+ check_sort(reporter, "Heap", workingArray, sortedArray, count);
+
+ memcpy(workingArray, randomArray, sizeof(randomArray));
+ SkTQSort<int>(workingArray, workingArray + count - 1);
+ check_sort(reporter, "Quick", workingArray, sortedArray, count);
+ }
+}
+
+// need tests for SkStrSearch
diff --git a/src/third_party/skia/tests/SrcOverTest.cpp b/src/third_party/skia/tests/SrcOverTest.cpp
new file mode 100644
index 0000000..be64710
--- /dev/null
+++ b/src/third_party/skia/tests/SrcOverTest.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkColorPriv.h"
+#include "SkXfermode.h"
+#include "Test.h"
+
+// our std SkAlpha255To256
+static int test_srcover0(unsigned dst, unsigned alpha) {
+ return alpha + SkAlphaMul(dst, SkAlpha255To256(255 - alpha));
+}
+
+// faster hack +1
+static int test_srcover1(unsigned dst, unsigned alpha) {
+ return alpha + SkAlphaMul(dst, 256 - alpha);
+}
+
+// slower "correct"
+static int test_srcover2(unsigned dst, unsigned alpha) {
+ return alpha + SkMulDiv255Round(dst, 255 - alpha);
+}
+
+DEF_TEST(SrcOver, reporter) {
+ /* Here's the idea. Can we ensure that when we blend on top of an opaque
+ dst, that the result always stay's opaque (i.e. exactly 255)?
+ */
+
+ unsigned i;
+ int opaqueCounter0 = 0;
+ int opaqueCounter1 = 0;
+ int opaqueCounter2 = 0;
+ for (i = 0; i <= 255; i++) {
+ unsigned result0 = test_srcover0(0xFF, i);
+ unsigned result1 = test_srcover1(0xFF, i);
+ unsigned result2 = test_srcover2(0xFF, i);
+ opaqueCounter0 += (result0 == 0xFF);
+ opaqueCounter1 += (result1 == 0xFF);
+ opaqueCounter2 += (result2 == 0xFF);
+ }
+#if 0
+ SkDebugf("---- opaque test: [%d %d %d]\n",
+ opaqueCounter0, opaqueCounter1, opaqueCounter2);
+#endif
+ // we acknowledge that technique0 does not always return opaque
+ REPORTER_ASSERT(reporter, opaqueCounter0 == 256);
+ REPORTER_ASSERT(reporter, opaqueCounter1 == 256);
+ REPORTER_ASSERT(reporter, opaqueCounter2 == 256);
+
+ // Now ensure that we never over/underflow a byte
+ for (i = 0; i <= 255; i++) {
+ for (unsigned dst = 0; dst <= 255; dst++) {
+ unsigned r0 = test_srcover0(dst, i);
+ unsigned r1 = test_srcover1(dst, i);
+ unsigned r2 = test_srcover2(dst, i);
+ unsigned max = SkMax32(dst, i);
+ // ignore the known failure
+ if (dst != 255) {
+ REPORTER_ASSERT(reporter, r0 <= 255 && r0 >= max);
+ }
+ REPORTER_ASSERT(reporter, r1 <= 255 && r1 >= max);
+ REPORTER_ASSERT(reporter, r2 <= 255 && r2 >= max);
+
+#if 0
+ // this shows where r1 (faster) differs from r2 (more exact)
+ if (r1 != r2) {
+ SkDebugf("--- dst=%d i=%d r1=%d r2=%d exact=%g\n",
+ dst, i, r1, r2, i + dst - dst*i/255.0f);
+ }
+#endif
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/StreamTest.cpp b/src/third_party/skia/tests/StreamTest.cpp
new file mode 100644
index 0000000..ce391a3
--- /dev/null
+++ b/src/third_party/skia/tests/StreamTest.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkData.h"
+#include "SkOSFile.h"
+#include "SkRandom.h"
+#include "SkStream.h"
+#include "Test.h"
+
+#ifndef SK_BUILD_FOR_WIN
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+
+#define MAX_SIZE (256 * 1024)
+
+static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream,
+ const void* src, size_t len, int repeat) {
+ SkAutoSMalloc<256> storage(len);
+ void* tmp = storage.get();
+
+ for (int i = 0; i < repeat; ++i) {
+ size_t bytes = stream->read(tmp, len);
+ REPORTER_ASSERT(reporter, bytes == len);
+ REPORTER_ASSERT(reporter, !memcmp(tmp, src, len));
+ }
+
+ // expect EOF
+ size_t bytes = stream->read(tmp, 1);
+ REPORTER_ASSERT(reporter, 0 == bytes);
+ // isAtEnd might not return true until after the first failing read.
+ REPORTER_ASSERT(reporter, stream->isAtEnd());
+}
+
+static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
+ SkString path = SkOSPath::Join(tmpDir, "wstream_test");
+
+ const char s[] = "abcdefghijklmnopqrstuvwxyz";
+
+ {
+ SkFILEWStream writer(path.c_str());
+ if (!writer.isValid()) {
+ ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str());
+ return;
+ }
+
+ for (int i = 0; i < 100; ++i) {
+ writer.write(s, 26);
+ }
+ }
+
+ {
+ SkFILEStream stream(path.c_str());
+ REPORTER_ASSERT(reporter, stream.isValid());
+ test_loop_stream(reporter, &stream, s, 26, 100);
+
+ SkAutoTUnref<SkStreamAsset> stream2(stream.duplicate());
+ test_loop_stream(reporter, stream2.get(), s, 26, 100);
+ }
+
+ {
+ FILE* file = ::fopen(path.c_str(), "rb");
+ SkFILEStream stream(file, SkFILEStream::kCallerPasses_Ownership);
+ REPORTER_ASSERT(reporter, stream.isValid());
+ test_loop_stream(reporter, &stream, s, 26, 100);
+
+ SkAutoTUnref<SkStreamAsset> stream2(stream.duplicate());
+ test_loop_stream(reporter, stream2.get(), s, 26, 100);
+ }
+}
+
+static void TestWStream(skiatest::Reporter* reporter) {
+ SkDynamicMemoryWStream ds;
+ const char s[] = "abcdefghijklmnopqrstuvwxyz";
+ int i;
+ for (i = 0; i < 100; i++) {
+ REPORTER_ASSERT(reporter, ds.write(s, 26));
+ }
+ REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26);
+
+ char* dst = new char[100 * 26 + 1];
+ dst[100*26] = '*';
+ ds.copyTo(dst);
+ REPORTER_ASSERT(reporter, dst[100*26] == '*');
+ for (i = 0; i < 100; i++) {
+ REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
+ }
+
+ {
+ SkAutoTUnref<SkStreamAsset> stream(ds.detachAsStream());
+ REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength());
+ REPORTER_ASSERT(reporter, ds.getOffset() == 0);
+ test_loop_stream(reporter, stream.get(), s, 26, 100);
+
+ SkAutoTUnref<SkStreamAsset> stream2(stream->duplicate());
+ test_loop_stream(reporter, stream2.get(), s, 26, 100);
+
+ SkAutoTUnref<SkStreamAsset> stream3(stream->fork());
+ REPORTER_ASSERT(reporter, stream3->isAtEnd());
+ char tmp;
+ size_t bytes = stream->read(&tmp, 1);
+ REPORTER_ASSERT(reporter, 0 == bytes);
+ stream3->rewind();
+ test_loop_stream(reporter, stream3.get(), s, 26, 100);
+ }
+
+ for (i = 0; i < 100; i++) {
+ REPORTER_ASSERT(reporter, ds.write(s, 26));
+ }
+ REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26);
+
+ {
+ SkAutoTUnref<SkData> data(ds.copyToData());
+ REPORTER_ASSERT(reporter, 100 * 26 == data->size());
+ REPORTER_ASSERT(reporter, memcmp(dst, data->data(), data->size()) == 0);
+ }
+
+ {
+ // Test that this works after a copyToData.
+ SkAutoTUnref<SkStreamAsset> stream(ds.detachAsStream());
+ REPORTER_ASSERT(reporter, ds.getOffset() == 0);
+ test_loop_stream(reporter, stream.get(), s, 26, 100);
+
+ SkAutoTUnref<SkStreamAsset> stream2(stream->duplicate());
+ test_loop_stream(reporter, stream2.get(), s, 26, 100);
+ }
+ delete[] dst;
+
+ SkString tmpDir = skiatest::Test::GetTmpDir();
+ if (!tmpDir.isEmpty()) {
+ test_filestreams(reporter, tmpDir.c_str());
+ }
+}
+
+static void TestPackedUInt(skiatest::Reporter* reporter) {
+ // we know that packeduint tries to write 1, 2 or 4 bytes for the length,
+ // so we test values around each of those transitions (and a few others)
+ const size_t sizes[] = {
+ 0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769,
+ 0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001,
+ 0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001,
+ 0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF
+ };
+
+
+ size_t i;
+ char buffer[sizeof(sizes) * 4];
+
+ SkMemoryWStream wstream(buffer, sizeof(buffer));
+ for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
+ bool success = wstream.writePackedUInt(sizes[i]);
+ REPORTER_ASSERT(reporter, success);
+ }
+ wstream.flush();
+
+ SkMemoryStream rstream(buffer, sizeof(buffer));
+ for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
+ size_t n = rstream.readPackedUInt();
+ if (sizes[i] != n) {
+ SkDebugf("-- %d: sizes:%x n:%x\n", i, sizes[i], n);
+ }
+ REPORTER_ASSERT(reporter, sizes[i] == n);
+ }
+}
+
+// Test that setting an SkMemoryStream to a NULL data does not result in a crash when calling
+// methods that access fData.
+static void TestDereferencingData(SkMemoryStream* memStream) {
+ memStream->read(NULL, 0);
+ memStream->getMemoryBase();
+ SkAutoDataUnref data(memStream->copyToData());
+}
+
+static void TestNullData() {
+ SkData* nullData = NULL;
+ SkMemoryStream memStream(nullData);
+ TestDereferencingData(&memStream);
+
+ memStream.setData(nullData);
+ TestDereferencingData(&memStream);
+
+}
+
+DEF_TEST(Stream, reporter) {
+ TestWStream(reporter);
+ TestPackedUInt(reporter);
+ TestNullData();
+}
diff --git a/src/third_party/skia/tests/StringTest.cpp b/src/third_party/skia/tests/StringTest.cpp
new file mode 100644
index 0000000..13ee5ec
--- /dev/null
+++ b/src/third_party/skia/tests/StringTest.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "SkString.h"
+#include "Test.h"
+
+// Windows vsnprintf doesn't 0-terminate safely), but is so far
+// encapsulated in SkString that we can't test it directly.
+
+#ifdef SK_BUILD_FOR_WIN
+ #define VSNPRINTF(buffer, size, format, args) \
+ vsnprintf_s(buffer, size, _TRUNCATE, format, args)
+#else
+ #define VSNPRINTF vsnprintf
+#endif
+
+#define ARGS_TO_BUFFER(format, buffer, size) \
+ do { \
+ va_list args; \
+ va_start(args, format); \
+ VSNPRINTF(buffer, size, format, args); \
+ va_end(args); \
+ } while (0)
+
+static void printfAnalog(char* buffer, int size, const char format[], ...) {
+ ARGS_TO_BUFFER(format, buffer, size);
+}
+
+DEF_TEST(String, reporter) {
+ SkString a;
+ SkString b((size_t)0);
+ SkString c("");
+ SkString d(NULL, 0);
+
+ REPORTER_ASSERT(reporter, a.isEmpty());
+ REPORTER_ASSERT(reporter, a == b && a == c && a == d);
+
+ a.set("hello");
+ b.set("hellox", 5);
+ c.set(a);
+ d.resize(5);
+ memcpy(d.writable_str(), "helloz", 5);
+
+ REPORTER_ASSERT(reporter, !a.isEmpty());
+ REPORTER_ASSERT(reporter, a.size() == 5);
+ REPORTER_ASSERT(reporter, a == b && a == c && a == d);
+ REPORTER_ASSERT(reporter, a.equals("hello", 5));
+ REPORTER_ASSERT(reporter, a.equals("hello"));
+ REPORTER_ASSERT(reporter, !a.equals("help"));
+
+ REPORTER_ASSERT(reporter, a.startsWith("hell"));
+ REPORTER_ASSERT(reporter, a.startsWith('h'));
+ REPORTER_ASSERT(reporter, !a.startsWith( "ell"));
+ REPORTER_ASSERT(reporter, !a.startsWith( 'e'));
+ REPORTER_ASSERT(reporter, a.startsWith(""));
+ REPORTER_ASSERT(reporter, a.endsWith("llo"));
+ REPORTER_ASSERT(reporter, a.endsWith('o'));
+ REPORTER_ASSERT(reporter, !a.endsWith("ll" ));
+ REPORTER_ASSERT(reporter, !a.endsWith('l'));
+ REPORTER_ASSERT(reporter, a.endsWith(""));
+ REPORTER_ASSERT(reporter, a.contains("he"));
+ REPORTER_ASSERT(reporter, a.contains("ll"));
+ REPORTER_ASSERT(reporter, a.contains("lo"));
+ REPORTER_ASSERT(reporter, a.contains("hello"));
+ REPORTER_ASSERT(reporter, !a.contains("hellohello"));
+ REPORTER_ASSERT(reporter, a.contains(""));
+ REPORTER_ASSERT(reporter, a.contains('e'));
+ REPORTER_ASSERT(reporter, !a.contains('z'));
+
+ SkString e(a);
+ SkString f("hello");
+ SkString g("helloz", 5);
+
+ REPORTER_ASSERT(reporter, a == e && a == f && a == g);
+
+ b.set("world");
+ c = b;
+ REPORTER_ASSERT(reporter, a != b && a != c && b == c);
+
+ a.append(" world");
+ e.append("worldz", 5);
+ e.insert(5, " ");
+ f.set("world");
+ f.prepend("hello ");
+ REPORTER_ASSERT(reporter, a.equals("hello world") && a == e && a == f);
+
+ a.reset();
+ b.resize(0);
+ REPORTER_ASSERT(reporter, a.isEmpty() && b.isEmpty() && a == b);
+
+ a.set("a");
+ a.set("ab");
+ a.set("abc");
+ a.set("abcd");
+
+ a.set("");
+ a.appendS32(0x7FFFFFFFL);
+ REPORTER_ASSERT(reporter, a.equals("2147483647"));
+ a.set("");
+ a.appendS32(0x80000001L);
+ REPORTER_ASSERT(reporter, a.equals("-2147483647"));
+ a.set("");
+ a.appendS32(0x80000000L);
+ REPORTER_ASSERT(reporter, a.equals("-2147483648"));
+
+ a.set("");
+ a.appendU32(0x7FFFFFFFUL);
+ REPORTER_ASSERT(reporter, a.equals("2147483647"));
+ a.set("");
+ a.appendU32(0x80000001UL);
+ REPORTER_ASSERT(reporter, a.equals("2147483649"));
+ a.set("");
+ a.appendU32(0xFFFFFFFFUL);
+ REPORTER_ASSERT(reporter, a.equals("4294967295"));
+
+ a.set("");
+ a.appendS64(0x7FFFFFFFFFFFFFFFLL, 0);
+ REPORTER_ASSERT(reporter, a.equals("9223372036854775807"));
+ a.set("");
+ a.appendS64(0x8000000000000001LL, 0);
+ REPORTER_ASSERT(reporter, a.equals("-9223372036854775807"));
+ a.set("");
+ a.appendS64(0x8000000000000000LL, 0);
+ REPORTER_ASSERT(reporter, a.equals("-9223372036854775808"));
+ a.set("");
+ a.appendS64(0x0000000001000000LL, 15);
+ REPORTER_ASSERT(reporter, a.equals("000000016777216"));
+ a.set("");
+ a.appendS64(0xFFFFFFFFFF000000LL, 15);
+ REPORTER_ASSERT(reporter, a.equals("-000000016777216"));
+
+ a.set("");
+ a.appendU64(0x7FFFFFFFFFFFFFFFULL, 0);
+ REPORTER_ASSERT(reporter, a.equals("9223372036854775807"));
+ a.set("");
+ a.appendU64(0x8000000000000001ULL, 0);
+ REPORTER_ASSERT(reporter, a.equals("9223372036854775809"));
+ a.set("");
+ a.appendU64(0xFFFFFFFFFFFFFFFFULL, 0);
+ REPORTER_ASSERT(reporter, a.equals("18446744073709551615"));
+ a.set("");
+ a.appendU64(0x0000000001000000ULL, 15);
+ REPORTER_ASSERT(reporter, a.equals("000000016777216"));
+
+ static const struct {
+ SkScalar fValue;
+ const char* fString;
+ } gRec[] = {
+ { 0, "0" },
+ { SK_Scalar1, "1" },
+ { -SK_Scalar1, "-1" },
+ { SK_Scalar1/2, "0.5" },
+ #ifdef SK_BUILD_FOR_WIN
+ { 3.4028234e38f, "3.4028235e+038" },
+ { -3.4028234e38f, "-3.4028235e+038" },
+ #else
+ { 3.4028234e38f, "3.4028235e+38" },
+ { -3.4028234e38f, "-3.4028235e+38" },
+ #endif
+ };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
+ a.reset();
+ a.appendScalar(gRec[i].fValue);
+ REPORTER_ASSERT(reporter, a.size() <= SkStrAppendScalar_MaxSize);
+// SkDebugf(" received <%s> expected <%s>\n", a.c_str(), gRec[i].fString);
+ REPORTER_ASSERT(reporter, a.equals(gRec[i].fString));
+ }
+
+ REPORTER_ASSERT(reporter, SkStringPrintf("%i", 0).equals("0"));
+
+ char buffer [40];
+ memset(buffer, 'a', 40);
+ REPORTER_ASSERT(reporter, buffer[18] == 'a');
+ REPORTER_ASSERT(reporter, buffer[19] == 'a');
+ REPORTER_ASSERT(reporter, buffer[20] == 'a');
+ printfAnalog(buffer, 20, "%30d", 0);
+ REPORTER_ASSERT(reporter, buffer[18] == ' ');
+ REPORTER_ASSERT(reporter, buffer[19] == 0);
+ REPORTER_ASSERT(reporter, buffer[20] == 'a');
+
+}
+
+DEF_TEST(String_SkStrSplit, r) {
+ SkTArray<SkString> results;
+
+ SkStrSplit("a-_b_c-dee--f-_-_-g-", "-_", &results);
+ REPORTER_ASSERT(r, results.count() == 6);
+ REPORTER_ASSERT(r, results[0].equals("a"));
+ REPORTER_ASSERT(r, results[1].equals("b"));
+ REPORTER_ASSERT(r, results[2].equals("c"));
+ REPORTER_ASSERT(r, results[3].equals("dee"));
+ REPORTER_ASSERT(r, results[4].equals("f"));
+ REPORTER_ASSERT(r, results[5].equals("g"));
+}
diff --git a/src/third_party/skia/tests/StrokeTest.cpp b/src/third_party/skia/tests/StrokeTest.cpp
new file mode 100644
index 0000000..15220c4
--- /dev/null
+++ b/src/third_party/skia/tests/StrokeTest.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkRect.h"
+#include "SkStroke.h"
+#include "Test.h"
+
+static bool equal(const SkRect& a, const SkRect& b) {
+ return SkScalarNearlyEqual(a.left(), b.left()) &&
+ SkScalarNearlyEqual(a.top(), b.top()) &&
+ SkScalarNearlyEqual(a.right(), b.right()) &&
+ SkScalarNearlyEqual(a.bottom(), b.bottom());
+}
+
+static void test_strokerect(skiatest::Reporter* reporter) {
+ const SkScalar width = SkIntToScalar(10);
+ SkPaint paint;
+
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(width);
+
+ SkRect r = { 0, 0, SkIntToScalar(200), SkIntToScalar(100) };
+
+ SkRect outer(r);
+ outer.outset(width/2, width/2);
+
+ static const SkPaint::Join joins[] = {
+ SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(joins); ++i) {
+ paint.setStrokeJoin(joins[i]);
+
+ SkPath path, fillPath;
+ path.addRect(r);
+ paint.getFillPath(path, &fillPath);
+
+ REPORTER_ASSERT(reporter, equal(outer, fillPath.getBounds()));
+
+ bool isMiter = SkPaint::kMiter_Join == joins[i];
+ SkRect nested[2];
+ REPORTER_ASSERT(reporter, fillPath.isNestedRects(nested) == isMiter);
+ if (isMiter) {
+ SkRect inner(r);
+ inner.inset(width/2, width/2);
+ REPORTER_ASSERT(reporter, equal(nested[0], outer));
+ REPORTER_ASSERT(reporter, equal(nested[1], inner));
+ }
+ }
+}
+
+DEF_TEST(Stroke, reporter) {
+ test_strokerect(reporter);
+}
diff --git a/src/third_party/skia/tests/SurfaceTest.cpp b/src/third_party/skia/tests/SurfaceTest.cpp
new file mode 100644
index 0000000..69c8b84
--- /dev/null
+++ b/src/third_party/skia/tests/SurfaceTest.cpp
@@ -0,0 +1,474 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkData.h"
+#include "SkDecodingImageGenerator.h"
+#include "SkImageEncoder.h"
+#include "SkRRect.h"
+#include "SkSurface.h"
+#include "SkUtils.h"
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#else
+class GrContextFactory;
+class GrContext;
+#endif
+
+enum SurfaceType {
+ kRaster_SurfaceType,
+ kRasterDirect_SurfaceType,
+ kGpu_SurfaceType,
+ kGpuScratch_SurfaceType,
+};
+
+static void release_storage(void* pixels, void* context) {
+ SkASSERT(pixels == context);
+ sk_free(pixels);
+}
+
+static SkSurface* createSurface(SurfaceType surfaceType, GrContext* context,
+ SkImageInfo* requestedInfo = NULL) {
+ static const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
+
+ if (requestedInfo) {
+ *requestedInfo = info;
+ }
+
+ switch (surfaceType) {
+ case kRaster_SurfaceType:
+ return SkSurface::NewRaster(info);
+ case kRasterDirect_SurfaceType: {
+ const size_t rowBytes = info.minRowBytes();
+ void* storage = sk_malloc_throw(info.getSafeSize(rowBytes));
+ return SkSurface::NewRasterDirectReleaseProc(info, storage, rowBytes,
+ release_storage, storage);
+ }
+ case kGpu_SurfaceType:
+#if SK_SUPPORT_GPU
+ return context ? SkSurface::NewRenderTarget(context, info, 0, NULL) : NULL;
+#endif
+ break;
+ case kGpuScratch_SurfaceType:
+#if SK_SUPPORT_GPU
+ return context ? SkSurface::NewScratchRenderTarget(context, info) : NULL;
+#endif
+ break;
+ }
+ return NULL;
+}
+
+enum ImageType {
+ kRasterCopy_ImageType,
+ kRasterData_ImageType,
+ kGpu_ImageType,
+ kCodec_ImageType,
+};
+
+static void test_image(skiatest::Reporter* reporter) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
+ size_t rowBytes = info.minRowBytes();
+ size_t size = info.getSafeSize(rowBytes);
+ SkData* data = SkData::NewUninitialized(size);
+
+ REPORTER_ASSERT(reporter, 1 == data->getRefCnt());
+ SkImage* image = SkImage::NewRasterData(info, data, rowBytes);
+ REPORTER_ASSERT(reporter, 2 == data->getRefCnt());
+ image->unref();
+ REPORTER_ASSERT(reporter, 1 == data->getRefCnt());
+ data->unref();
+}
+
+static SkImage* createImage(ImageType imageType, GrContext* context,
+ SkColor color) {
+ const SkPMColor pmcolor = SkPreMultiplyColor(color);
+ const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
+ const size_t rowBytes = info.minRowBytes();
+ const size_t size = rowBytes * info.height();
+
+ SkAutoTUnref<SkData> data(SkData::NewUninitialized(size));
+ void* addr = data->writable_data();
+ sk_memset32((SkPMColor*)addr, pmcolor, SkToInt(size >> 2));
+
+ switch (imageType) {
+ case kRasterCopy_ImageType:
+ return SkImage::NewRasterCopy(info, addr, rowBytes);
+ case kRasterData_ImageType:
+ return SkImage::NewRasterData(info, data, rowBytes);
+ case kGpu_ImageType:
+ return NULL; // TODO
+ case kCodec_ImageType: {
+ SkBitmap bitmap;
+ bitmap.installPixels(info, addr, rowBytes);
+ SkAutoTUnref<SkData> src(
+ SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type,
+ 100));
+ return SkImage::NewFromGenerator(
+ SkDecodingImageGenerator::Create(data, SkDecodingImageGenerator::Options()));
+ }
+ }
+ SkASSERT(false);
+ return NULL;
+}
+
+static void test_imagepeek(skiatest::Reporter* reporter) {
+ static const struct {
+ ImageType fType;
+ bool fPeekShouldSucceed;
+ } gRec[] = {
+ { kRasterCopy_ImageType, true },
+ { kRasterData_ImageType, true },
+ { kGpu_ImageType, false },
+ { kCodec_ImageType, false },
+ };
+
+ const SkColor color = SK_ColorRED;
+ const SkPMColor pmcolor = SkPreMultiplyColor(color);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
+ SkImageInfo info;
+ size_t rowBytes;
+
+ SkAutoTUnref<SkImage> image(createImage(gRec[i].fType, NULL, color));
+ if (!image.get()) {
+ continue; // gpu may not be enabled
+ }
+ const void* addr = image->peekPixels(&info, &rowBytes);
+ bool success = SkToBool(addr);
+ REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success);
+ if (success) {
+ REPORTER_ASSERT(reporter, 10 == info.width());
+ REPORTER_ASSERT(reporter, 10 == info.height());
+ REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType());
+ REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() ||
+ kOpaque_SkAlphaType == info.alphaType());
+ REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes);
+ REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
+ }
+ }
+}
+
+static void test_canvaspeek(skiatest::Reporter* reporter,
+ GrContextFactory* factory) {
+ static const struct {
+ SurfaceType fType;
+ bool fPeekShouldSucceed;
+ } gRec[] = {
+ { kRaster_SurfaceType, true },
+ { kRasterDirect_SurfaceType, true },
+#if SK_SUPPORT_GPU
+ { kGpu_SurfaceType, false },
+ { kGpuScratch_SurfaceType, false },
+#endif
+ };
+
+ const SkColor color = SK_ColorRED;
+ const SkPMColor pmcolor = SkPreMultiplyColor(color);
+
+ int cnt;
+#if SK_SUPPORT_GPU
+ cnt = GrContextFactory::kGLContextTypeCnt;
+#else
+ cnt = 1;
+#endif
+
+ for (int i= 0; i < cnt; ++i) {
+ GrContext* context = NULL;
+#if SK_SUPPORT_GPU
+ GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
+ if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
+ continue;
+ }
+ context = factory->get(glCtxType);
+
+ if (NULL == context) {
+ continue;
+ }
+#endif
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
+ SkImageInfo info, requestInfo;
+ size_t rowBytes;
+
+ SkAutoTUnref<SkSurface> surface(createSurface(gRec[i].fType, context,
+ &requestInfo));
+ surface->getCanvas()->clear(color);
+
+ const void* addr = surface->getCanvas()->peekPixels(&info, &rowBytes);
+ bool success = SkToBool(addr);
+ REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success);
+
+ SkImageInfo info2;
+ size_t rb2;
+ const void* addr2 = surface->peekPixels(&info2, &rb2);
+
+ if (success) {
+ REPORTER_ASSERT(reporter, requestInfo == info);
+ REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= rowBytes);
+ REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
+
+ REPORTER_ASSERT(reporter, addr2 == addr);
+ REPORTER_ASSERT(reporter, info2 == info);
+ REPORTER_ASSERT(reporter, rb2 == rowBytes);
+ } else {
+ REPORTER_ASSERT(reporter, NULL == addr2);
+ }
+ }
+ }
+}
+
+static void TestSurfaceCopyOnWrite(skiatest::Reporter* reporter, SurfaceType surfaceType,
+ GrContext* context) {
+ // Verify that the right canvas commands trigger a copy on write
+ SkSurface* surface = createSurface(surfaceType, context);
+ SkAutoTUnref<SkSurface> aur_surface(surface);
+ SkCanvas* canvas = surface->getCanvas();
+
+ const SkRect testRect =
+ SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
+ SkIntToScalar(4), SkIntToScalar(5));
+ SkMatrix testMatrix;
+ testMatrix.reset();
+ testMatrix.setScale(SkIntToScalar(2), SkIntToScalar(3));
+
+ SkPath testPath;
+ testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
+ SkIntToScalar(2), SkIntToScalar(1)));
+
+ const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1);
+
+ SkRegion testRegion;
+ testRegion.setRect(testIRect);
+
+
+ const SkColor testColor = 0x01020304;
+ const SkPaint testPaint;
+ const SkPoint testPoints[3] = {
+ {SkIntToScalar(0), SkIntToScalar(0)},
+ {SkIntToScalar(2), SkIntToScalar(1)},
+ {SkIntToScalar(0), SkIntToScalar(2)}
+ };
+ const size_t testPointCount = 3;
+
+ SkBitmap testBitmap;
+ testBitmap.allocN32Pixels(10, 10);
+ testBitmap.eraseColor(0);
+
+ SkRRect testRRect;
+ testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1);
+
+ SkString testText("Hello World");
+ const SkPoint testPoints2[] = {
+ { SkIntToScalar(0), SkIntToScalar(1) },
+ { SkIntToScalar(1), SkIntToScalar(1) },
+ { SkIntToScalar(2), SkIntToScalar(1) },
+ { SkIntToScalar(3), SkIntToScalar(1) },
+ { SkIntToScalar(4), SkIntToScalar(1) },
+ { SkIntToScalar(5), SkIntToScalar(1) },
+ { SkIntToScalar(6), SkIntToScalar(1) },
+ { SkIntToScalar(7), SkIntToScalar(1) },
+ { SkIntToScalar(8), SkIntToScalar(1) },
+ { SkIntToScalar(9), SkIntToScalar(1) },
+ { SkIntToScalar(10), SkIntToScalar(1) },
+ };
+
+#define EXPECT_COPY_ON_WRITE(command) \
+ { \
+ SkImage* imageBefore = surface->newImageSnapshot(); \
+ SkAutoTUnref<SkImage> aur_before(imageBefore); \
+ canvas-> command ; \
+ SkImage* imageAfter = surface->newImageSnapshot(); \
+ SkAutoTUnref<SkImage> aur_after(imageAfter); \
+ REPORTER_ASSERT(reporter, imageBefore != imageAfter); \
+ }
+
+ EXPECT_COPY_ON_WRITE(clear(testColor))
+ EXPECT_COPY_ON_WRITE(drawPaint(testPaint))
+ EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \
+ testPaint))
+ EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint))
+ EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint))
+ EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint))
+ EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint))
+ EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0))
+ EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, NULL, testRect))
+ EXPECT_COPY_ON_WRITE(drawBitmapMatrix(testBitmap, testMatrix, NULL))
+ EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, NULL))
+ EXPECT_COPY_ON_WRITE(drawSprite(testBitmap, 0, 0, NULL))
+ EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint))
+ EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \
+ testPaint))
+ EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, NULL, \
+ testPaint))
+}
+
+static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter,
+ SurfaceType surfaceType,
+ GrContext* context) {
+ // This test succeeds by not triggering an assertion.
+ // The test verifies that the surface remains writable (usable) after
+ // acquiring and releasing a snapshot without triggering a copy on write.
+ SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context));
+ SkCanvas* canvas = surface->getCanvas();
+ canvas->clear(1);
+ surface->newImageSnapshot()->unref(); // Create and destroy SkImage
+ canvas->clear(2); // Must not assert internally
+}
+
+#if SK_SUPPORT_GPU
+static void TestSurfaceInCache(skiatest::Reporter* reporter,
+ SurfaceType surfaceType,
+ GrContext* context) {
+ context->freeGpuResources();
+ int resourceCount;
+
+ context->getResourceCacheUsage(&resourceCount, NULL);
+ REPORTER_ASSERT(reporter, 0 == resourceCount);
+ SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context));
+ // Note: the stencil buffer is always cached, so kGpu_SurfaceType uses
+ // one cached resource, and kGpuScratch_SurfaceType uses two.
+ int expectedCachedResources = surfaceType == kGpuScratch_SurfaceType ? 2 : 1;
+ context->getResourceCacheUsage(&resourceCount, NULL);
+ REPORTER_ASSERT(reporter, expectedCachedResources == resourceCount);
+
+ // Verify that all the cached resources are locked in cache.
+ context->freeGpuResources();
+ context->getResourceCacheUsage(&resourceCount, NULL);
+ REPORTER_ASSERT(reporter, expectedCachedResources == resourceCount);
+
+ // Verify that all the cached resources are unlocked upon surface release
+ surface.reset(0);
+ context->freeGpuResources();
+ context->getResourceCacheUsage(&resourceCount, NULL);
+ REPORTER_ASSERT(reporter, 0 == resourceCount);
+}
+
+static void Test_crbug263329(skiatest::Reporter* reporter,
+ SurfaceType surfaceType,
+ GrContext* context) {
+ // This is a regression test for crbug.com/263329
+ // Bug was caused by onCopyOnWrite releasing the old surface texture
+ // back to the scratch texture pool even though the texture is used
+ // by and active SkImage_Gpu.
+ SkAutoTUnref<SkSurface> surface1(createSurface(surfaceType, context));
+ SkAutoTUnref<SkSurface> surface2(createSurface(surfaceType, context));
+ SkCanvas* canvas1 = surface1->getCanvas();
+ SkCanvas* canvas2 = surface2->getCanvas();
+ canvas1->clear(1);
+ SkAutoTUnref<SkImage> image1(surface1->newImageSnapshot());
+ // Trigger copy on write, new backing is a scratch texture
+ canvas1->clear(2);
+ SkAutoTUnref<SkImage> image2(surface1->newImageSnapshot());
+ // Trigger copy on write, old backing should not be returned to scratch
+ // pool because it is held by image2
+ canvas1->clear(3);
+
+ canvas2->clear(4);
+ SkAutoTUnref<SkImage> image3(surface2->newImageSnapshot());
+ // Trigger copy on write on surface2. The new backing store should not
+ // be recycling a texture that is held by an existing image.
+ canvas2->clear(5);
+ SkAutoTUnref<SkImage> image4(surface2->newImageSnapshot());
+ REPORTER_ASSERT(reporter, image4->getTexture() != image3->getTexture());
+ // The following assertion checks crbug.com/263329
+ REPORTER_ASSERT(reporter, image4->getTexture() != image2->getTexture());
+ REPORTER_ASSERT(reporter, image4->getTexture() != image1->getTexture());
+ REPORTER_ASSERT(reporter, image3->getTexture() != image2->getTexture());
+ REPORTER_ASSERT(reporter, image3->getTexture() != image1->getTexture());
+ REPORTER_ASSERT(reporter, image2->getTexture() != image1->getTexture());
+}
+
+static void TestGetTexture(skiatest::Reporter* reporter,
+ SurfaceType surfaceType,
+ GrContext* context) {
+ SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context));
+ SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
+ GrTexture* texture = image->getTexture();
+ if (surfaceType == kGpu_SurfaceType || surfaceType == kGpuScratch_SurfaceType) {
+ REPORTER_ASSERT(reporter, texture);
+ REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle());
+ } else {
+ REPORTER_ASSERT(reporter, NULL == texture);
+ }
+ surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
+ REPORTER_ASSERT(reporter, image->getTexture() == texture);
+}
+#endif
+
+static void TestSurfaceNoCanvas(skiatest::Reporter* reporter,
+ SurfaceType surfaceType,
+ GrContext* context,
+ SkSurface::ContentChangeMode mode) {
+ // Verifies the robustness of SkSurface for handling use cases where calls
+ // are made before a canvas is created.
+ {
+ // Test passes by not asserting
+ SkSurface* surface = createSurface(surfaceType, context);
+ SkAutoTUnref<SkSurface> aur_surface(surface);
+ surface->notifyContentWillChange(mode);
+ SkDEBUGCODE(surface->validate();)
+ }
+ {
+ SkSurface* surface = createSurface(surfaceType, context);
+ SkAutoTUnref<SkSurface> aur_surface(surface);
+ SkImage* image1 = surface->newImageSnapshot();
+ SkAutoTUnref<SkImage> aur_image1(image1);
+ SkDEBUGCODE(image1->validate();)
+ SkDEBUGCODE(surface->validate();)
+ surface->notifyContentWillChange(mode);
+ SkDEBUGCODE(image1->validate();)
+ SkDEBUGCODE(surface->validate();)
+ SkImage* image2 = surface->newImageSnapshot();
+ SkAutoTUnref<SkImage> aur_image2(image2);
+ SkDEBUGCODE(image2->validate();)
+ SkDEBUGCODE(surface->validate();)
+ REPORTER_ASSERT(reporter, image1 != image2);
+ }
+
+}
+
+DEF_GPUTEST(Surface, reporter, factory) {
+ test_image(reporter);
+
+ TestSurfaceCopyOnWrite(reporter, kRaster_SurfaceType, NULL);
+ TestSurfaceWritableAfterSnapshotRelease(reporter, kRaster_SurfaceType, NULL);
+ TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kDiscard_ContentChangeMode);
+ TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kRetain_ContentChangeMode);
+
+ test_imagepeek(reporter);
+ test_canvaspeek(reporter, factory);
+
+#if SK_SUPPORT_GPU
+ TestGetTexture(reporter, kRaster_SurfaceType, NULL);
+ if (factory) {
+ for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
+ GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
+ if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
+ continue;
+ }
+ GrContext* context = factory->get(glCtxType);
+ if (context) {
+ TestSurfaceInCache(reporter, kGpu_SurfaceType, context);
+ TestSurfaceInCache(reporter, kGpuScratch_SurfaceType, context);
+ Test_crbug263329(reporter, kGpu_SurfaceType, context);
+ Test_crbug263329(reporter, kGpuScratch_SurfaceType, context);
+ TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context);
+ TestSurfaceCopyOnWrite(reporter, kGpuScratch_SurfaceType, context);
+ TestSurfaceWritableAfterSnapshotRelease(reporter, kGpu_SurfaceType, context);
+ TestSurfaceWritableAfterSnapshotRelease(reporter, kGpuScratch_SurfaceType, context);
+ TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
+ TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
+ TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
+ TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
+ TestGetTexture(reporter, kGpu_SurfaceType, context);
+ TestGetTexture(reporter, kGpuScratch_SurfaceType, context);
+ }
+ }
+ }
+#endif
+}
diff --git a/src/third_party/skia/tests/TArrayTest.cpp b/src/third_party/skia/tests/TArrayTest.cpp
new file mode 100644
index 0000000..b85efca
--- /dev/null
+++ b/src/third_party/skia/tests/TArrayTest.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTArray.h"
+#include "Test.h"
+
+// Tests the SkTArray<T> class template.
+
+template <bool MEM_COPY>
+static void TestTSet_basic(skiatest::Reporter* reporter) {
+ SkTArray<int, MEM_COPY> a;
+
+ // Starts empty.
+ REPORTER_ASSERT(reporter, a.empty());
+ REPORTER_ASSERT(reporter, a.count() == 0);
+
+ // { }, add a default constructed element
+ a.push_back() = 0;
+ REPORTER_ASSERT(reporter, !a.empty());
+ REPORTER_ASSERT(reporter, a.count() == 1);
+
+ // { 0 }, removeShuffle the only element.
+ a.removeShuffle(0);
+ REPORTER_ASSERT(reporter, a.empty());
+ REPORTER_ASSERT(reporter, a.count() == 0);
+
+ // { }, add a default, add a 1, remove first
+ a.push_back() = 0;
+ REPORTER_ASSERT(reporter, a.push_back() = 1);
+ a.removeShuffle(0);
+ REPORTER_ASSERT(reporter, !a.empty());
+ REPORTER_ASSERT(reporter, a.count() == 1);
+ REPORTER_ASSERT(reporter, a[0] == 1);
+
+ // { 1 }, replace with new array
+ int b[5] = { 0, 1, 2, 3, 4 };
+ a.reset(b, SK_ARRAY_COUNT(b));
+ REPORTER_ASSERT(reporter, a.count() == SK_ARRAY_COUNT(b));
+ REPORTER_ASSERT(reporter, a[2] == 2);
+ REPORTER_ASSERT(reporter, a[4] == 4);
+
+ // { 0, 1, 2, 3, 4 }, removeShuffle the last
+ a.removeShuffle(4);
+ REPORTER_ASSERT(reporter, a.count() == SK_ARRAY_COUNT(b) - 1);
+ REPORTER_ASSERT(reporter, a[3] == 3);
+
+ // { 0, 1, 2, 3 }, remove a middle, note shuffle
+ a.removeShuffle(1);
+ REPORTER_ASSERT(reporter, a.count() == SK_ARRAY_COUNT(b) - 2);
+ REPORTER_ASSERT(reporter, a[0] == 0);
+ REPORTER_ASSERT(reporter, a[1] == 3);
+ REPORTER_ASSERT(reporter, a[2] == 2);
+
+ // {0, 3, 2 }
+}
+
+DEF_TEST(TArray, reporter) {
+ TestTSet_basic<true>(reporter);
+ TestTSet_basic<false>(reporter);
+}
diff --git a/src/third_party/skia/tests/TDStackNesterTest.cpp b/src/third_party/skia/tests/TDStackNesterTest.cpp
new file mode 100644
index 0000000..968654b
--- /dev/null
+++ b/src/third_party/skia/tests/TDStackNesterTest.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTDStackNester.h"
+
+#include "Test.h"
+
+/**
+ * Test SkTDStackNester<int>::push(). Pushes the current count onto the stack,
+ * and checks that the count has increased by one.
+ */
+static void test_push(skiatest::Reporter* reporter, SkTDStackNester<int>* nester) {
+ SkASSERT(nester);
+ const int count = nester->count();
+ // test_pop depends on this value.
+ nester->push(count);
+ REPORTER_ASSERT(reporter, nester->count() == count + 1);
+}
+
+/**
+ * Test SkTDStackNester<int>::pop(). Pops the top element off the stack, and
+ * checks that the new count is one smaller, and that the popped element
+ * matches the new count (as was pushed by test_push).
+ */
+static void test_pop(skiatest::Reporter* reporter, SkTDStackNester<int>* nester) {
+ SkASSERT(nester);
+ const int count = nester->count();
+ // This test should not be called with a count <= 0.
+ SkASSERT(count > 0);
+ const int top = nester->top();
+ int value = -1;
+ nester->pop(&value);
+ REPORTER_ASSERT(reporter, top == value);
+ const int newCount = nester->count();
+ REPORTER_ASSERT(reporter, newCount == count - 1);
+ // Since test_push always pushes the count prior to the push, value should
+ // always be one less than count.
+ REPORTER_ASSERT(reporter, newCount == value);
+}
+
+/**
+ * Test nest() and unnest(). nest() is called, and it is confirmed that the
+ * count is now zero. Then test_push() is called inc times, followed by a call to
+ * unnest(). After this call, check that the count has returned to the initial count, and
+ * that nestingLevel() has returned to its initial value.
+ */
+static void test_nest(skiatest::Reporter* reporter, SkTDStackNester<int>* nester, int inc) {
+ SkASSERT(nester);
+ SkASSERT(inc > 0);
+ const int initialCount = nester->count();
+ const int initialNesting = nester->nestingLevel();
+
+ nester->nest();
+ REPORTER_ASSERT(reporter, nester->count() == 0);
+ REPORTER_ASSERT(reporter, nester->nestingLevel() == initialNesting + 1);
+
+ for (int i = 0; i < inc; ++i) {
+ test_push(reporter, nester);
+ }
+
+ nester->unnest();
+ REPORTER_ASSERT(reporter, nester->count() == initialCount);
+ REPORTER_ASSERT(reporter, nester->nestingLevel() == initialNesting);
+}
+
+class SkTDStackNesterTester {
+public:
+ static int GetSlotCount() {
+ return SkTDStackNester<int>::kSlotCount;
+ }
+};
+
+static void test_stack_nester(skiatest::Reporter* reporter) {
+ SkTDStackNester<int> nester;
+ int count = nester.count();
+ REPORTER_ASSERT(reporter, 0 == count);
+ REPORTER_ASSERT(reporter, nester.nestingLevel() == 0);
+ REPORTER_ASSERT(reporter, nester.empty());
+
+ // Test nesting (with arbitrary number of pushes) from the beginning.
+ test_nest(reporter, &nester, 3);
+
+ const int slotCount = SkTDStackNesterTester::GetSlotCount();
+
+ // Test pushing beyond the boundary of the first Rec.
+ for (; count < 2 * slotCount; ++count) {
+ if (3 == count) {
+ // Test nesting (an arbitrary number of pushes) early on.
+ test_nest(reporter, &nester, 7);
+ } else if (slotCount - 4 == count) {
+ // Test nesting across the boundary of a Rec.
+ test_nest(reporter, &nester, 6);
+ }
+ test_push(reporter, &nester);
+ }
+
+ // Pop everything off the stack except for the last one, to confirm
+ // that the destructor handles a remaining object.
+ while (nester.count() > 1) {
+ test_pop(reporter, &nester);
+ }
+}
+
+DEF_TEST(TDStackNester, reporter) {
+ test_stack_nester(reporter);
+}
diff --git a/src/third_party/skia/tests/TLSTest.cpp b/src/third_party/skia/tests/TLSTest.cpp
new file mode 100644
index 0000000..53bb5fe
--- /dev/null
+++ b/src/third_party/skia/tests/TLSTest.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkGraphics.h"
+#include "SkPaint.h"
+#include "SkTLS.h"
+#include "SkThreadUtils.h"
+#include "Test.h"
+
+static void thread_main(void*) {
+ SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
+
+ const char text[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ size_t len = strlen(text);
+
+ SkPaint paint;
+
+ for (int j = 0; j < 10; ++j) {
+ for (int i = 9; i <= 48; ++i) {
+ paint.setTextSize(SkIntToScalar(i));
+ paint.setAntiAlias(false);
+ paint.measureText(text, len);
+ paint.setAntiAlias(true);
+ paint.measureText(text, len);
+ }
+ }
+}
+
+static void test_threads(SkThread::entryPointProc proc) {
+ SkThread* threads[8];
+ int N = SK_ARRAY_COUNT(threads);
+ int i;
+
+ for (i = 0; i < N; ++i) {
+ threads[i] = new SkThread(proc);
+ }
+
+ for (i = 0; i < N; ++i) {
+ threads[i]->start();
+ }
+
+ for (i = 0; i < N; ++i) {
+ threads[i]->join();
+ }
+
+ for (i = 0; i < N; ++i) {
+ delete threads[i];
+ }
+}
+
+static int32_t gCounter;
+
+static void* FakeCreateTLS() {
+ sk_atomic_inc(&gCounter);
+ return NULL;
+}
+
+static void FakeDeleteTLS(void*) {
+ sk_atomic_dec(&gCounter);
+}
+
+static void testTLSDestructor(void*) {
+ SkTLS::Get(FakeCreateTLS, FakeDeleteTLS);
+}
+
+DEF_TEST(TLS, reporter) {
+ // TODO: Disabled for now to work around
+ // http://code.google.com/p/skia/issues/detail?id=619
+ // ('flaky segfault in TLS test on Shuttle_Ubuntu12 buildbots')
+ if( false ) test_threads(&thread_main);
+
+ // Test to ensure that at thread destruction, TLS destructors
+ // have been called.
+ test_threads(&testTLSDestructor);
+ REPORTER_ASSERT(reporter, 0 == gCounter);
+}
diff --git a/src/third_party/skia/tests/TSetTest.cpp b/src/third_party/skia/tests/TSetTest.cpp
new file mode 100644
index 0000000..3f82648
--- /dev/null
+++ b/src/third_party/skia/tests/TSetTest.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTSet.h"
+#include "Test.h"
+
+// Tests the SkTSet<T> class template.
+// Functions that just call SkTDArray are not tested.
+
+static void TestTSet_basic(skiatest::Reporter* reporter) {
+ SkTSet<int> set0;
+ REPORTER_ASSERT(reporter, set0.isEmpty());
+ REPORTER_ASSERT(reporter, !set0.contains(-1));
+ REPORTER_ASSERT(reporter, !set0.contains(0));
+ REPORTER_ASSERT(reporter, !set0.contains(1));
+ REPORTER_ASSERT(reporter, set0.count() == 0);
+
+ REPORTER_ASSERT(reporter, set0.add(0));
+ REPORTER_ASSERT(reporter, !set0.isEmpty());
+ REPORTER_ASSERT(reporter, !set0.contains(-1));
+ REPORTER_ASSERT(reporter, set0.contains(0));
+ REPORTER_ASSERT(reporter, !set0.contains(1));
+ REPORTER_ASSERT(reporter, set0.count() == 1);
+ REPORTER_ASSERT(reporter, !set0.add(0));
+ REPORTER_ASSERT(reporter, set0.count() == 1);
+
+#ifdef SK_DEBUG
+ set0.validate();
+#endif
+}
+
+#define COUNT 1732
+#define PRIME1 10007
+#define PRIME2 1733
+
+// Generates a series of positive unique pseudo-random numbers.
+static int f(int i) {
+ return (long(i) * PRIME1) % PRIME2;
+}
+
+// Will expose contains() too.
+static void TestTSet_advanced(skiatest::Reporter* reporter) {
+ SkTSet<int> set0;
+
+ for (int i = 0; i < COUNT; i++) {
+ REPORTER_ASSERT(reporter, !set0.contains(f(i)));
+ if (i > 0) {
+ REPORTER_ASSERT(reporter, set0.contains(f(0)));
+ REPORTER_ASSERT(reporter, set0.contains(f(i / 2)));
+ REPORTER_ASSERT(reporter, set0.contains(f(i - 1)));
+ }
+ REPORTER_ASSERT(reporter, !set0.contains(f(i)));
+ REPORTER_ASSERT(reporter, set0.count() == i);
+ REPORTER_ASSERT(reporter, set0.add(f(i)));
+ REPORTER_ASSERT(reporter, set0.contains(f(i)));
+ REPORTER_ASSERT(reporter, set0.count() == i + 1);
+ REPORTER_ASSERT(reporter, !set0.add(f(i)));
+ }
+
+ // Test deterministic output
+ for (int i = 0; i < COUNT; i++) {
+ REPORTER_ASSERT(reporter, set0[i] == f(i));
+ }
+
+ // Test copy constructor too.
+ SkTSet<int> set1 = set0;
+
+ REPORTER_ASSERT(reporter, set0.count() == set1.count());
+ REPORTER_ASSERT(reporter, !set1.contains(-1000));
+
+ for (int i = 0; i < COUNT; i++) {
+ REPORTER_ASSERT(reporter, set1.contains(f(i)));
+ REPORTER_ASSERT(reporter, set1[i] == f(i));
+ }
+
+ // Test operator= too.
+ SkTSet<int> set2;
+ set2 = set0;
+
+ REPORTER_ASSERT(reporter, set0.count() == set2.count());
+ REPORTER_ASSERT(reporter, !set2.contains(-1000));
+
+ for (int i = 0; i < COUNT; i++) {
+ REPORTER_ASSERT(reporter, set2.contains(f(i)));
+ REPORTER_ASSERT(reporter, set2[i] == f(i));
+ }
+
+#ifdef SK_DEBUG
+ set0.validate();
+ set1.validate();
+ set2.validate();
+#endif
+}
+
+static void TestTSet_merge(skiatest::Reporter* reporter) {
+ SkTSet<int> set;
+ SkTSet<int> setOdd;
+
+ for (int i = 0; i < COUNT; i++) {
+ REPORTER_ASSERT(reporter, set.add(2 * i));
+ REPORTER_ASSERT(reporter, setOdd.add(2 * i + 1));
+ }
+ // mergeInto returns the number of duplicates. Expected 0.
+ REPORTER_ASSERT(reporter, set.mergeInto(setOdd) == 0);
+ REPORTER_ASSERT(reporter, set.count() == 2 * COUNT);
+
+ // mergeInto should now find all new numbers duplicate.
+ REPORTER_ASSERT(reporter, set.mergeInto(setOdd) == setOdd.count());
+ REPORTER_ASSERT(reporter, set.count() == 2 * COUNT);
+
+ for (int i = 0; i < 2 * COUNT; i++) {
+ REPORTER_ASSERT(reporter, set.contains(i));
+ }
+
+ // check deterministic output
+ for (int i = 0; i < COUNT; i++) {
+ REPORTER_ASSERT(reporter, set[i] == 2 * i);
+ REPORTER_ASSERT(reporter, set[COUNT + i] == 2 * i + 1);
+ }
+
+#ifdef SK_DEBUG
+ set.validate();
+ setOdd.validate();
+#endif
+}
+
+DEF_TEST(TSet, reporter) {
+ TestTSet_basic(reporter);
+ TestTSet_advanced(reporter);
+ TestTSet_merge(reporter);
+}
diff --git a/src/third_party/skia/tests/Test.cpp b/src/third_party/skia/tests/Test.cpp
new file mode 100644
index 0000000..d0147e1
--- /dev/null
+++ b/src/third_party/skia/tests/Test.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+
+#include "SkCommandLineFlags.h"
+#include "SkError.h"
+#include "SkString.h"
+#include "SkTArray.h"
+#include "SkTime.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContext.h"
+#include "gl/SkNativeGLContext.h"
+#else
+class GrContext;
+#endif
+
+DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
+
+using namespace skiatest;
+
+Reporter::Reporter() : fTestCount(0) {
+}
+
+void Reporter::startTest(Test* test) {
+ this->onStart(test);
+}
+
+void Reporter::reportFailed(const SkString& desc) {
+ this->onReportFailed(desc);
+}
+
+void Reporter::endTest(Test* test) {
+ this->onEnd(test);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+Test::Test() : fReporter(NULL), fPassed(true) {}
+
+Test::~Test() {
+ SkSafeUnref(fReporter);
+}
+
+void Test::setReporter(Reporter* r) {
+ SkRefCnt_SafeAssign(fReporter, r);
+}
+
+const char* Test::getName() {
+ if (fName.size() == 0) {
+ this->onGetName(&fName);
+ }
+ return fName.c_str();
+}
+
+class LocalReporter : public Reporter {
+public:
+ explicit LocalReporter(Reporter* reporterToMimic) : fReporter(reporterToMimic) {}
+
+ int numFailures() const { return fFailures.count(); }
+ const SkString& failure(int i) const { return fFailures[i]; }
+
+protected:
+ virtual void onReportFailed(const SkString& desc) SK_OVERRIDE {
+ fFailures.push_back(desc);
+ }
+
+ // Proxy down to fReporter. We assume these calls are threadsafe.
+ virtual bool allowExtendedTest() const SK_OVERRIDE {
+ return fReporter->allowExtendedTest();
+ }
+
+ virtual void bumpTestCount() SK_OVERRIDE {
+ fReporter->bumpTestCount();
+ }
+
+ virtual bool verbose() const SK_OVERRIDE {
+ return fReporter->verbose();
+ }
+
+private:
+ Reporter* fReporter; // Unowned.
+ SkTArray<SkString> fFailures;
+};
+
+void Test::run() {
+ // Clear the Skia error callback before running any test, to ensure that tests
+ // don't have unintended side effects when running more than one.
+ SkSetErrorCallback( NULL, NULL );
+
+ // Tell (likely shared) fReporter that this test has started.
+ fReporter->startTest(this);
+
+ const SkMSec start = SkTime::GetMSecs();
+ // Run the test into a LocalReporter so we know if it's passed or failed without interference
+ // from other tests that might share fReporter.
+ LocalReporter local(fReporter);
+ this->onRun(&local);
+ fPassed = local.numFailures() == 0;
+ fElapsed = SkTime::GetMSecs() - start;
+
+ // Now tell fReporter about any failures and wrap up.
+ for (int i = 0; i < local.numFailures(); i++) {
+ fReporter->reportFailed(local.failure(i));
+ }
+ fReporter->endTest(this);
+
+}
+
+SkString Test::GetTmpDir() {
+ const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0];
+ return SkString(tmpDir);
+}
diff --git a/src/third_party/skia/tests/Test.h b/src/third_party/skia/tests/Test.h
new file mode 100644
index 0000000..6c85b32
--- /dev/null
+++ b/src/third_party/skia/tests/Test.h
@@ -0,0 +1,174 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef skiatest_Test_DEFINED
+#define skiatest_Test_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkString.h"
+#include "SkTRegistry.h"
+#include "SkThread.h"
+#include "SkTypes.h"
+
+class GrContextFactory;
+
+namespace skiatest {
+
+ class Test;
+
+ class Reporter : public SkRefCnt {
+ public:
+ SK_DECLARE_INST_COUNT(Reporter)
+ Reporter();
+
+ int countTests() const { return fTestCount; }
+
+ void startTest(Test*);
+ void reportFailed(const SkString& desc);
+ void endTest(Test*);
+
+ virtual bool allowExtendedTest() const { return false; }
+ virtual bool verbose() const { return false; }
+ virtual void bumpTestCount() { sk_atomic_inc(&fTestCount); }
+
+ protected:
+ virtual void onStart(Test*) {}
+ virtual void onReportFailed(const SkString& desc) {}
+ virtual void onEnd(Test*) {}
+
+ private:
+ int32_t fTestCount;
+
+ typedef SkRefCnt INHERITED;
+ };
+
+ class Test {
+ public:
+ Test();
+ virtual ~Test();
+
+ Reporter* getReporter() const { return fReporter; }
+ void setReporter(Reporter*);
+
+ const char* getName();
+ void run();
+ bool passed() const { return fPassed; }
+ SkMSec elapsedMs() const { return fElapsed; }
+
+ static SkString GetTmpDir();
+
+ virtual bool isGPUTest() const { return false; }
+ virtual void setGrContextFactory(GrContextFactory* factory) {}
+
+ protected:
+ virtual void onGetName(SkString*) = 0;
+ virtual void onRun(Reporter*) = 0;
+
+ private:
+ Reporter* fReporter;
+ SkString fName;
+ bool fPassed;
+ SkMSec fElapsed;
+ };
+
+ class GpuTest : public Test{
+ public:
+ GpuTest() : Test(), fGrContextFactory(NULL) {}
+
+ virtual bool isGPUTest() const { return true; }
+ virtual void setGrContextFactory(GrContextFactory* factory) {
+ fGrContextFactory = factory;
+ }
+
+ protected:
+ GrContextFactory* fGrContextFactory; // Unowned.
+ };
+
+ typedef SkTRegistry<Test*(*)(void*)> TestRegistry;
+} // namespace skiatest
+
+/*
+ Use the following macros to make use of the skiatest classes, e.g.
+
+ #include "Test.h"
+
+ DEF_TEST(TestName, reporter) {
+ ...
+ REPORTER_ASSERT(reporter, x == 15);
+ ...
+ REPORTER_ASSERT_MESSAGE(reporter, x == 15, "x should be 15");
+ ...
+ if (x != 15) {
+ ERRORF(reporter, "x should be 15, but is %d", x);
+ return;
+ }
+ ...
+ }
+*/
+
+#define REPORTER_ASSERT(r, cond) \
+ do { \
+ if (!(cond)) { \
+ SkString desc; \
+ desc.printf("%s:%d\t%s", __FILE__, __LINE__, #cond); \
+ r->reportFailed(desc); \
+ } \
+ } while(0)
+
+#define REPORTER_ASSERT_MESSAGE(r, cond, message) \
+ do { \
+ if (!(cond)) { \
+ SkString desc; \
+ desc.printf("%s:%d\t%s: %s", __FILE__, __LINE__, \
+ message, #cond); \
+ r->reportFailed(desc); \
+ } \
+ } while(0)
+
+#define ERRORF(reporter, ...) \
+ do { \
+ SkString desc; \
+ desc.printf("%s:%d\t", __FILE__, __LINE__); \
+ desc.appendf(__VA_ARGS__) ; \
+ (reporter)->reportFailed(desc); \
+ } while(0)
+
+#define DEF_TEST(name, reporter) \
+ static void test_##name(skiatest::Reporter*); \
+ namespace skiatest { \
+ class name##Class : public Test { \
+ public: \
+ static Test* Factory(void*) { return SkNEW(name##Class); } \
+ protected: \
+ virtual void onGetName(SkString* name) SK_OVERRIDE { \
+ name->set(#name); \
+ } \
+ virtual void onRun(Reporter* r) SK_OVERRIDE { test_##name(r); } \
+ }; \
+ static TestRegistry gReg_##name##Class(name##Class::Factory); \
+ } \
+ static void test_##name(skiatest::Reporter* reporter)
+
+#define DEF_GPUTEST(name, reporter, factory) \
+ static void test_##name(skiatest::Reporter*, GrContextFactory*); \
+ namespace skiatest { \
+ class name##Class : public GpuTest { \
+ public: \
+ static Test* Factory(void*) { return SkNEW(name##Class); } \
+ protected: \
+ virtual void onGetName(SkString* name) SK_OVERRIDE { \
+ name->set(#name); \
+ } \
+ virtual void onRun(Reporter* r) SK_OVERRIDE { \
+ test_##name(r, fGrContextFactory); \
+ } \
+ }; \
+ static TestRegistry gReg_##name##Class(name##Class::Factory); \
+ } \
+ static void test_##name(skiatest::Reporter* reporter, GrContextFactory* factory)
+
+#endif
diff --git a/src/third_party/skia/tests/TextBlobTest.cpp b/src/third_party/skia/tests/TextBlobTest.cpp
new file mode 100644
index 0000000..5d08b01
--- /dev/null
+++ b/src/third_party/skia/tests/TextBlobTest.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPaint.h"
+#include "SkPoint.h"
+#include "SkTextBlob.h"
+
+#include "Test.h"
+
+
+class TextBlobTester {
+public:
+ // This unit test feeds an SkTextBlobBuilder various runs then checks to see if
+ // the result contains the provided data and merges runs when appropriate.
+ static void TestBuilder(skiatest::Reporter* reporter) {
+ SkTextBlobBuilder builder;
+
+ // empty run set
+ RunBuilderTest(reporter, builder, NULL, 0, NULL, 0);
+
+ RunDef set1[] = {
+ { 128, SkTextBlob::kDefault_Positioning, 100, 100 },
+ };
+ RunBuilderTest(reporter, builder, set1, SK_ARRAY_COUNT(set1), set1, SK_ARRAY_COUNT(set1));
+
+ RunDef set2[] = {
+ { 128, SkTextBlob::kHorizontal_Positioning, 100, 100 },
+ };
+ RunBuilderTest(reporter, builder, set2, SK_ARRAY_COUNT(set2), set2, SK_ARRAY_COUNT(set2));
+
+ RunDef set3[] = {
+ { 128, SkTextBlob::kFull_Positioning, 100, 100 },
+ };
+ RunBuilderTest(reporter, builder, set3, SK_ARRAY_COUNT(set3), set3, SK_ARRAY_COUNT(set3));
+
+ RunDef set4[] = {
+ { 128, SkTextBlob::kDefault_Positioning, 100, 150 },
+ { 128, SkTextBlob::kDefault_Positioning, 100, 150 },
+ { 128, SkTextBlob::kDefault_Positioning, 100, 150 },
+ };
+ RunBuilderTest(reporter, builder, set4, SK_ARRAY_COUNT(set4), set4, SK_ARRAY_COUNT(set4));
+
+ RunDef set5[] = {
+ { 128, SkTextBlob::kHorizontal_Positioning, 100, 150 },
+ { 128, SkTextBlob::kHorizontal_Positioning, 200, 150 },
+ { 128, SkTextBlob::kHorizontal_Positioning, 300, 250 },
+ };
+ RunDef mergedSet5[] = {
+ { 256, SkTextBlob::kHorizontal_Positioning, 0, 150 },
+ { 128, SkTextBlob::kHorizontal_Positioning, 0, 250 },
+ };
+ RunBuilderTest(reporter, builder, set5, SK_ARRAY_COUNT(set5), mergedSet5,
+ SK_ARRAY_COUNT(mergedSet5));
+
+ RunDef set6[] = {
+ { 128, SkTextBlob::kFull_Positioning, 100, 100 },
+ { 128, SkTextBlob::kFull_Positioning, 200, 200 },
+ { 128, SkTextBlob::kFull_Positioning, 300, 300 },
+ };
+ RunDef mergedSet6[] = {
+ { 384, SkTextBlob::kFull_Positioning, 0, 0 },
+ };
+ RunBuilderTest(reporter, builder, set6, SK_ARRAY_COUNT(set6), mergedSet6,
+ SK_ARRAY_COUNT(mergedSet6));
+
+ RunDef set7[] = {
+ { 128, SkTextBlob::kDefault_Positioning, 100, 150 },
+ { 128, SkTextBlob::kDefault_Positioning, 100, 150 },
+ { 128, SkTextBlob::kHorizontal_Positioning, 100, 150 },
+ { 128, SkTextBlob::kHorizontal_Positioning, 200, 150 },
+ { 128, SkTextBlob::kFull_Positioning, 400, 350 },
+ { 128, SkTextBlob::kFull_Positioning, 400, 350 },
+ { 128, SkTextBlob::kDefault_Positioning, 100, 450 },
+ { 128, SkTextBlob::kDefault_Positioning, 100, 450 },
+ { 128, SkTextBlob::kHorizontal_Positioning, 100, 550 },
+ { 128, SkTextBlob::kHorizontal_Positioning, 200, 650 },
+ { 128, SkTextBlob::kFull_Positioning, 400, 750 },
+ { 128, SkTextBlob::kFull_Positioning, 400, 850 },
+ };
+ RunDef mergedSet7[] = {
+ { 128, SkTextBlob::kDefault_Positioning, 100, 150 },
+ { 128, SkTextBlob::kDefault_Positioning, 100, 150 },
+ { 256, SkTextBlob::kHorizontal_Positioning, 0, 150 },
+ { 256, SkTextBlob::kFull_Positioning, 0, 0 },
+ { 128, SkTextBlob::kDefault_Positioning, 100, 450 },
+ { 128, SkTextBlob::kDefault_Positioning, 100, 450 },
+ { 128, SkTextBlob::kHorizontal_Positioning, 0, 550 },
+ { 128, SkTextBlob::kHorizontal_Positioning, 0, 650 },
+ { 256, SkTextBlob::kFull_Positioning, 0, 0 },
+ };
+ RunBuilderTest(reporter, builder, set7, SK_ARRAY_COUNT(set7), mergedSet7,
+ SK_ARRAY_COUNT(mergedSet7));
+ }
+
+ // This unit test verifies blob bounds computation.
+ static void TestBounds(skiatest::Reporter* reporter) {
+ SkTextBlobBuilder builder;
+ SkPaint font;
+ font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ // Explicit bounds.
+ {
+ SkAutoTUnref<const SkTextBlob> blob(builder.build());
+ REPORTER_ASSERT(reporter, blob->bounds().isEmpty());
+ }
+
+ {
+ SkRect r1 = SkRect::MakeXYWH(10, 10, 20, 20);
+ builder.allocRun(font, 16, 0, 0, &r1);
+ SkAutoTUnref<const SkTextBlob> blob(builder.build());
+ REPORTER_ASSERT(reporter, blob->bounds() == r1);
+ }
+
+ {
+ SkRect r1 = SkRect::MakeXYWH(10, 10, 20, 20);
+ builder.allocRunPosH(font, 16, 0, &r1);
+ SkAutoTUnref<const SkTextBlob> blob(builder.build());
+ REPORTER_ASSERT(reporter, blob->bounds() == r1);
+ }
+
+ {
+ SkRect r1 = SkRect::MakeXYWH(10, 10, 20, 20);
+ builder.allocRunPos(font, 16, &r1);
+ SkAutoTUnref<const SkTextBlob> blob(builder.build());
+ REPORTER_ASSERT(reporter, blob->bounds() == r1);
+ }
+
+ {
+ SkRect r1 = SkRect::MakeXYWH(10, 10, 20, 20);
+ SkRect r2 = SkRect::MakeXYWH(15, 20, 50, 50);
+ SkRect r3 = SkRect::MakeXYWH(0, 5, 10, 5);
+
+ builder.allocRun(font, 16, 0, 0, &r1);
+ builder.allocRunPosH(font, 16, 0, &r2);
+ builder.allocRunPos(font, 16, &r3);
+
+ SkAutoTUnref<const SkTextBlob> blob(builder.build());
+ REPORTER_ASSERT(reporter, blob->bounds() == SkRect::MakeXYWH(0, 5, 65, 65));
+ }
+
+ {
+ // Verify empty blob bounds after building some non-empty blobs.
+ SkAutoTUnref<const SkTextBlob> blob(builder.build());
+ REPORTER_ASSERT(reporter, blob->bounds().isEmpty());
+ }
+
+ // Implicit bounds
+ // FIXME: not supported yet.
+ }
+
+private:
+ struct RunDef {
+ unsigned count;
+ SkTextBlob::GlyphPositioning pos;
+ SkScalar x, y;
+ };
+
+ static void RunBuilderTest(skiatest::Reporter* reporter, SkTextBlobBuilder& builder,
+ const RunDef in[], unsigned inCount,
+ const RunDef out[], unsigned outCount) {
+ SkPaint font;
+ font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ unsigned glyphCount = 0;
+ unsigned posCount = 0;
+
+ for (unsigned i = 0; i < inCount; ++i) {
+ AddRun(font, in[i].count, in[i].pos, SkPoint::Make(in[i].x, in[i].y), builder);
+ glyphCount += in[i].count;
+ posCount += in[i].count * in[i].pos;
+ }
+
+ SkAutoTUnref<const SkTextBlob> blob(builder.build());
+
+ SkTextBlob::RunIterator it(blob);
+ for (unsigned i = 0; i < outCount; ++i) {
+ REPORTER_ASSERT(reporter, !it.done());
+ REPORTER_ASSERT(reporter, out[i].pos == it.positioning());
+ REPORTER_ASSERT(reporter, out[i].count == it.glyphCount());
+ if (SkTextBlob::kDefault_Positioning == out[i].pos) {
+ REPORTER_ASSERT(reporter, out[i].x == it.offset().x());
+ REPORTER_ASSERT(reporter, out[i].y == it.offset().y());
+ } else if (SkTextBlob::kHorizontal_Positioning == out[i].pos) {
+ REPORTER_ASSERT(reporter, out[i].y == it.offset().y());
+ }
+
+ for (unsigned k = 0; k < it.glyphCount(); ++k) {
+ REPORTER_ASSERT(reporter, k % 128 == it.glyphs()[k]);
+ if (SkTextBlob::kHorizontal_Positioning == it.positioning()) {
+ REPORTER_ASSERT(reporter, SkIntToScalar(k % 128) == it.pos()[k]);
+ } else if (SkTextBlob::kFull_Positioning == it.positioning()) {
+ REPORTER_ASSERT(reporter, SkIntToScalar(k % 128) == it.pos()[k * 2]);
+ REPORTER_ASSERT(reporter, -SkIntToScalar(k % 128) == it.pos()[k * 2 + 1]);
+ }
+ }
+
+ it.next();
+ }
+
+ REPORTER_ASSERT(reporter, it.done());
+ }
+
+ static void AddRun(const SkPaint& font, int count, SkTextBlob::GlyphPositioning pos,
+ const SkPoint& offset, SkTextBlobBuilder& builder,
+ const SkRect* bounds = NULL) {
+ switch (pos) {
+ case SkTextBlob::kDefault_Positioning: {
+ const SkTextBlobBuilder::RunBuffer& rb = builder.allocRun(font, count, offset.x(),
+ offset.y(), bounds);
+ for (int i = 0; i < count; ++i) {
+ rb.glyphs[i] = i;
+ }
+ } break;
+ case SkTextBlob::kHorizontal_Positioning: {
+ const SkTextBlobBuilder::RunBuffer& rb = builder.allocRunPosH(font, count, offset.y(),
+ bounds);
+ for (int i = 0; i < count; ++i) {
+ rb.glyphs[i] = i;
+ rb.pos[i] = SkIntToScalar(i);
+ }
+ } break;
+ case SkTextBlob::kFull_Positioning: {
+ const SkTextBlobBuilder::RunBuffer& rb = builder.allocRunPos(font, count, bounds);
+ for (int i = 0; i < count; ++i) {
+ rb.glyphs[i] = i;
+ rb.pos[i * 2] = SkIntToScalar(i);
+ rb.pos[i * 2 + 1] = -SkIntToScalar(i);
+ }
+ } break;
+ default:
+ SkFAIL("unhandled positioning value");
+ }
+ }
+};
+
+DEF_TEST(TextBlob_builder, reporter) {
+ TextBlobTester::TestBuilder(reporter);
+ TextBlobTester::TestBounds(reporter);
+}
diff --git a/src/third_party/skia/tests/TextureCompressionTest.cpp b/src/third_party/skia/tests/TextureCompressionTest.cpp
new file mode 100644
index 0000000..7dd285d
--- /dev/null
+++ b/src/third_party/skia/tests/TextureCompressionTest.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkData.h"
+#include "SkEndian.h"
+#include "SkImageInfo.h"
+#include "SkTextureCompressor.h"
+#include "Test.h"
+
+// TODO: Create separate tests for RGB and RGBA data once
+// ASTC and ETC1 decompression is implemented.
+
+static bool decompresses_a8(SkTextureCompressor::Format fmt) {
+ switch (fmt) {
+ case SkTextureCompressor::kLATC_Format:
+ case SkTextureCompressor::kR11_EAC_Format:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool compresses_a8(SkTextureCompressor::Format fmt) {
+ switch (fmt) {
+ case SkTextureCompressor::kLATC_Format:
+ case SkTextureCompressor::kR11_EAC_Format:
+ case SkTextureCompressor::kASTC_12x12_Format:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/**
+ * Make sure that we properly fail when we don't have multiple of four image dimensions.
+ */
+DEF_TEST(CompressAlphaFailDimensions, reporter) {
+ SkBitmap bitmap;
+ static const int kWidth = 17;
+ static const int kHeight = 17;
+ SkImageInfo info = SkImageInfo::MakeA8(kWidth, kHeight);
+
+ // R11_EAC and LATC are both dimensions of 4, so we need to make sure that we
+ // are violating those assumptions. And if we are, then we're also violating the
+ // assumptions of ASTC, which is 12x12 since any number not divisible by 4 is
+ // also not divisible by 12. Our dimensions are prime, so any block dimension
+ // larger than 1 should fail.
+ REPORTER_ASSERT(reporter, kWidth % 4 != 0);
+ REPORTER_ASSERT(reporter, kHeight % 4 != 0);
+
+ bool setInfoSuccess = bitmap.setInfo(info);
+ REPORTER_ASSERT(reporter, setInfoSuccess);
+
+ bitmap.allocPixels(info);
+ bitmap.unlockPixels();
+
+ for (int i = 0; i < SkTextureCompressor::kFormatCnt; ++i) {
+ const SkTextureCompressor::Format fmt = static_cast<SkTextureCompressor::Format>(i);
+ if (!compresses_a8(fmt)) {
+ continue;
+ }
+ SkAutoDataUnref data(SkTextureCompressor::CompressBitmapToFormat(bitmap, fmt));
+ REPORTER_ASSERT(reporter, NULL == data);
+ }
+}
+
+/**
+ * Make sure that we properly fail when we don't have the correct bitmap type.
+ * compressed textures can (currently) only be created from A8 bitmaps.
+ */
+DEF_TEST(CompressAlphaFailColorType, reporter) {
+ SkBitmap bitmap;
+ static const int kWidth = 12;
+ static const int kHeight = 12;
+ SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
+
+ // ASTC is at most 12x12, and any dimension divisible by 12 is also divisible
+ // by 4, which is the dimensions of R11_EAC and LATC. In the future, we might
+ // support additional variants of ASTC, such as 5x6 and 8x8, in which case this would
+ // need to be updated.
+ REPORTER_ASSERT(reporter, kWidth % 12 == 0);
+ REPORTER_ASSERT(reporter, kHeight % 12 == 0);
+
+ bool setInfoSuccess = bitmap.setInfo(info);
+ REPORTER_ASSERT(reporter, setInfoSuccess);
+
+ bitmap.allocPixels(info);
+ bitmap.unlockPixels();
+
+ for (int i = 0; i < SkTextureCompressor::kFormatCnt; ++i) {
+ const SkTextureCompressor::Format fmt = static_cast<SkTextureCompressor::Format>(i);
+ if (!compresses_a8(fmt)) {
+ continue;
+ }
+ SkAutoDataUnref data(SkTextureCompressor::CompressBitmapToFormat(bitmap, fmt));
+ REPORTER_ASSERT(reporter, NULL == data);
+ }
+}
+
+/**
+ * Make sure that if you compress a texture with alternating black/white pixels, and
+ * then decompress it, you get what you started with.
+ */
+DEF_TEST(CompressCheckerboard, reporter) {
+ SkBitmap bitmap;
+ static const int kWidth = 48; // We need the number to be divisible by both
+ static const int kHeight = 48; // 12 (ASTC) and 16 (ARM NEON R11 EAC).
+ SkImageInfo info = SkImageInfo::MakeA8(kWidth, kHeight);
+
+ // ASTC is at most 12x12, and any dimension divisible by 12 is also divisible
+ // by 4, which is the dimensions of R11_EAC and LATC. In the future, we might
+ // support additional variants of ASTC, such as 5x6 and 8x8, in which case this would
+ // need to be updated. Additionally, ARM NEON and SSE code paths support up to
+ // four blocks of R11 EAC at once, so they operate on 16-wide blocks. Hence, the
+ // valid width and height is going to be the LCM of 12 and 16 which is 4*4*3 = 48
+ REPORTER_ASSERT(reporter, kWidth % 48 == 0);
+ REPORTER_ASSERT(reporter, kHeight % 48 == 0);
+
+ bool setInfoSuccess = bitmap.setInfo(info);
+ REPORTER_ASSERT(reporter, setInfoSuccess);
+
+ bitmap.allocPixels(info);
+ bitmap.unlockPixels();
+
+ // Populate bitmap
+ {
+ SkAutoLockPixels alp(bitmap);
+
+ uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap.getPixels());
+ REPORTER_ASSERT(reporter, pixels);
+ if (NULL == pixels) {
+ return;
+ }
+
+ for (int y = 0; y < kHeight; ++y) {
+ for (int x = 0; x < kWidth; ++x) {
+ if ((x ^ y) & 1) {
+ pixels[x] = 0xFF;
+ } else {
+ pixels[x] = 0;
+ }
+ }
+ pixels += bitmap.rowBytes();
+ }
+ }
+
+ SkAutoMalloc decompMemory(kWidth*kHeight);
+ uint8_t* decompBuffer = reinterpret_cast<uint8_t*>(decompMemory.get());
+ REPORTER_ASSERT(reporter, decompBuffer);
+ if (NULL == decompBuffer) {
+ return;
+ }
+
+ for (int i = 0; i < SkTextureCompressor::kFormatCnt; ++i) {
+ const SkTextureCompressor::Format fmt = static_cast<SkTextureCompressor::Format>(i);
+
+ // Ignore formats for RGBA data, since the decompressed buffer
+ // won't match the size and contents of the original.
+ if (!decompresses_a8(fmt) || !compresses_a8(fmt)) {
+ continue;
+ }
+
+ SkAutoDataUnref data(SkTextureCompressor::CompressBitmapToFormat(bitmap, fmt));
+ REPORTER_ASSERT(reporter, data);
+ if (NULL == data) {
+ continue;
+ }
+
+ bool decompResult =
+ SkTextureCompressor::DecompressBufferFromFormat(
+ decompBuffer, kWidth,
+ data->bytes(),
+ kWidth, kHeight, fmt);
+ REPORTER_ASSERT(reporter, decompResult);
+
+ SkAutoLockPixels alp(bitmap);
+ uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap.getPixels());
+ REPORTER_ASSERT(reporter, pixels);
+ if (NULL == pixels) {
+ continue;
+ }
+
+ for (int y = 0; y < kHeight; ++y) {
+ for (int x = 0; x < kWidth; ++x) {
+ bool ok = pixels[y*bitmap.rowBytes() + x] == decompBuffer[y*kWidth + x];
+ REPORTER_ASSERT(reporter, ok);
+ }
+ }
+ }
+}
+
+/**
+ * Make sure that if we pass in a solid color bitmap that we get the appropriate results
+ */
+DEF_TEST(CompressLATC, reporter) {
+
+ const SkTextureCompressor::Format kLATCFormat = SkTextureCompressor::kLATC_Format;
+ static const int kLATCEncodedBlockSize = 8;
+
+ SkBitmap bitmap;
+ static const int kWidth = 8;
+ static const int kHeight = 8;
+ SkImageInfo info = SkImageInfo::MakeA8(kWidth, kHeight);
+
+ bool setInfoSuccess = bitmap.setInfo(info);
+ REPORTER_ASSERT(reporter, setInfoSuccess);
+
+ bitmap.allocPixels(info);
+ bitmap.unlockPixels();
+
+ int latcDimX, latcDimY;
+ SkTextureCompressor::GetBlockDimensions(kLATCFormat, &latcDimX, &latcDimY);
+
+ REPORTER_ASSERT(reporter, kWidth % latcDimX == 0);
+ REPORTER_ASSERT(reporter, kHeight % latcDimY == 0);
+ const size_t kSizeToBe =
+ SkTextureCompressor::GetCompressedDataSize(kLATCFormat, kWidth, kHeight);
+ REPORTER_ASSERT(reporter, kSizeToBe == ((kWidth*kHeight*kLATCEncodedBlockSize)/16));
+ REPORTER_ASSERT(reporter, (kSizeToBe % kLATCEncodedBlockSize) == 0);
+
+ for (int lum = 0; lum < 256; ++lum) {
+ bitmap.lockPixels();
+ uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap.getPixels());
+ REPORTER_ASSERT(reporter, pixels);
+ if (NULL == pixels) {
+ bitmap.unlockPixels();
+ continue;
+ }
+
+ for (int i = 0; i < kWidth*kHeight; ++i) {
+ pixels[i] = lum;
+ }
+ bitmap.unlockPixels();
+
+ SkAutoDataUnref latcData(
+ SkTextureCompressor::CompressBitmapToFormat(bitmap, kLATCFormat));
+ REPORTER_ASSERT(reporter, latcData);
+ if (NULL == latcData) {
+ continue;
+ }
+
+ REPORTER_ASSERT(reporter, kSizeToBe == latcData->size());
+
+ // Make sure that it all matches a given block encoding. Since we have
+ // COMPRESS_LATC_FAST defined in SkTextureCompressor_LATC.cpp, we are using
+ // an approximation scheme that optimizes for speed against coverage maps.
+ // That means that each palette in the encoded block is exactly the same,
+ // and that the three bits saved per pixel are computed from the top three
+ // bits of the luminance value.
+ const uint64_t kIndexEncodingMap[8] = { 1, 7, 6, 5, 4, 3, 2, 0 };
+ const uint64_t kIndex = kIndexEncodingMap[lum >> 5];
+ const uint64_t kConstColorEncoding =
+ SkEndian_SwapLE64(
+ 255 |
+ (kIndex << 16) | (kIndex << 19) | (kIndex << 22) | (kIndex << 25) |
+ (kIndex << 28) | (kIndex << 31) | (kIndex << 34) | (kIndex << 37) |
+ (kIndex << 40) | (kIndex << 43) | (kIndex << 46) | (kIndex << 49) |
+ (kIndex << 52) | (kIndex << 55) | (kIndex << 58) | (kIndex << 61));
+
+ const uint64_t* blockPtr = reinterpret_cast<const uint64_t*>(latcData->data());
+ for (size_t i = 0; i < (kSizeToBe/8); ++i) {
+ REPORTER_ASSERT(reporter, blockPtr[i] == kConstColorEncoding);
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/TileGridTest.cpp b/src/third_party/skia/tests/TileGridTest.cpp
new file mode 100644
index 0000000..16434ab
--- /dev/null
+++ b/src/third_party/skia/tests/TileGridTest.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkPictureRecorder.h"
+#include "SkTileGrid.h"
+#include "Test.h"
+
+enum Tile {
+ kTopLeft_Tile = 0x1,
+ kTopRight_Tile = 0x2,
+ kBottomLeft_Tile = 0x4,
+ kBottomRight_Tile = 0x8,
+
+ kAll_Tile = kTopLeft_Tile | kTopRight_Tile | kBottomLeft_Tile | kBottomRight_Tile,
+};
+
+class MockCanvas : public SkCanvas {
+public:
+ MockCanvas(const SkBitmap& bm) : SkCanvas(bm) {}
+
+ virtual void drawRect(const SkRect& rect, const SkPaint&) {
+ // This capture occurs before quick reject.
+ fRects.push(rect);
+ }
+
+ SkTDArray<SkRect> fRects;
+};
+
+static void verifyTileHits(skiatest::Reporter* reporter, SkRect rect,
+ uint32_t tileMask, int borderPixels = 0) {
+ SkTileGridFactory::TileGridInfo info;
+ info.fMargin.set(borderPixels, borderPixels);
+ info.fOffset.setZero();
+ info.fTileInterval.set(10 - 2 * borderPixels, 10 - 2 * borderPixels);
+ SkTileGrid grid(2, 2, info);
+ grid.insert(NULL, rect, false);
+ REPORTER_ASSERT(reporter, grid.tileCount(0, 0) ==
+ ((tileMask & kTopLeft_Tile)? 1 : 0));
+ REPORTER_ASSERT(reporter, grid.tileCount(1, 0) ==
+ ((tileMask & kTopRight_Tile)? 1 : 0));
+ REPORTER_ASSERT(reporter, grid.tileCount(0, 1) ==
+ ((tileMask & kBottomLeft_Tile)? 1 : 0));
+ REPORTER_ASSERT(reporter, grid.tileCount(1, 1) ==
+ ((tileMask & kBottomRight_Tile)? 1 : 0));
+}
+
+DEF_TEST(TileGrid_UnalignedQuery, reporter) {
+ // Use SkTileGridPicture to generate a SkTileGrid with a helper
+ SkTileGridFactory::TileGridInfo info;
+ info.fMargin.setEmpty();
+ info.fOffset.setZero();
+ info.fTileInterval.set(10, 10);
+ SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
+ SkIntToScalar(8), SkIntToScalar(8));
+ SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(11), SkIntToScalar(11),
+ SkIntToScalar(1), SkIntToScalar(1));
+ SkTileGridFactory factory(info);
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(20, 20, &factory, 0);
+ SkPaint paint;
+ canvas->drawRect(rect1, paint);
+ canvas->drawRect(rect2, paint);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ SkBitmap store;
+ store.allocN32Pixels(1, 1);
+
+ // Test parts of top-left tile
+ {
+ MockCanvas mockCanvas(store);
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
+ }
+ {
+ MockCanvas mockCanvas(store);
+ mockCanvas.translate(-7.99f, -7.99f);
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
+ }
+ // Corner overlap
+ {
+ MockCanvas mockCanvas(store);
+ mockCanvas.translate(-9.5f, -9.5f);
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
+ REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
+ }
+ // Intersect bottom right tile, but does not overlap rect 2
+ {
+ MockCanvas mockCanvas(store);
+ mockCanvas.translate(-16.0f, -16.0f);
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
+ }
+ // Out of bounds queries, snap to border tiles
+ {
+ MockCanvas mockCanvas(store);
+ mockCanvas.translate(2.0f, 0.0f);
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
+ }
+ {
+ MockCanvas mockCanvas(store);
+ mockCanvas.translate(0.0f, 2.0f);
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
+ }
+ {
+ MockCanvas mockCanvas(store);
+ mockCanvas.translate(-22.0f, -16.0f);
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
+ }
+ {
+ MockCanvas mockCanvas(store);
+ mockCanvas.translate(-16.0f, -22.0f);
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
+ }
+}
+
+DEF_TEST(TileGrid_OverlapOffsetQueryAlignment, reporter) {
+ // Use SkTileGridPicture to generate a SkTileGrid with a helper
+ SkTileGridFactory::TileGridInfo info;
+ info.fMargin.set(1, 1);
+ info.fOffset.set(-1, -1);
+ info.fTileInterval.set(8, 8);
+
+ // rect landing entirely in top left tile
+ SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
+ SkIntToScalar(1), SkIntToScalar(1));
+ // rect landing entirely in center tile
+ SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(12), SkIntToScalar(12),
+ SkIntToScalar(1), SkIntToScalar(1));
+ // rect landing entirely in bottomright tile
+ SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(19), SkIntToScalar(19),
+ SkIntToScalar(1), SkIntToScalar(1));
+ SkTileGridFactory factory(info);
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(20, 20, &factory, 0);
+ SkPaint paint;
+ canvas->drawRect(rect1, paint);
+ canvas->drawRect(rect2, paint);
+ canvas->drawRect(rect3, paint);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ SkBitmap tileBitmap;
+ tileBitmap.allocN32Pixels(10, 10);
+ SkBitmap moreThanATileBitmap;
+ moreThanATileBitmap.allocN32Pixels(11, 11);
+ SkBitmap tinyBitmap;
+ tinyBitmap.allocN32Pixels(2, 2);
+ // Test parts of top-left tile
+ {
+ // The offset should cancel the top and left borders of the top left tile
+ // So a look-up at interval 0-10 should be grid aligned,
+ MockCanvas mockCanvas(tileBitmap);
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
+ }
+ {
+ // Encroaching border by one pixel
+ MockCanvas mockCanvas(moreThanATileBitmap);
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
+ REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
+ }
+ {
+ // Tile stride is 8 (tileWidth - 2 * border pixels
+ // so translating by 8, should make query grid-aligned
+ // with middle tile.
+ MockCanvas mockCanvas(tileBitmap);
+ mockCanvas.translate(SkIntToScalar(-8), SkIntToScalar(-8));
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
+ }
+ {
+ MockCanvas mockCanvas(tileBitmap);
+ mockCanvas.translate(-7.9f, -7.9f);
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
+ REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
+ }
+ {
+ MockCanvas mockCanvas(tileBitmap);
+ mockCanvas.translate(-8.1f, -8.1f);
+ picture->playback(&mockCanvas);
+ REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
+ REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
+ REPORTER_ASSERT(reporter, rect3 == mockCanvas.fRects[1]);
+ }
+ {
+ // Regression test for crbug.com/234688
+ // Once the 2x2 device region is inset by margin, it yields an empty
+ // adjusted region, sitting right on top of the tile boundary.
+ MockCanvas mockCanvas(tinyBitmap);
+ mockCanvas.translate(-8.0f, -8.0f);
+ picture->playback(&mockCanvas);
+ // This test passes by not asserting. We do not validate the rects recorded
+ // because the result is numerically unstable (floating point equality).
+ // The content of any one of the four tiles of the tilegrid would be a valid
+ // result since any bbox that covers the center point of the canvas will be
+ // recorded in all four tiles.
+ }
+}
+
+DEF_TEST(TileGrid, reporter) {
+ // Out of bounds
+ verifyTileHits(reporter, SkRect::MakeXYWH(30, 0, 1, 1), 0);
+ verifyTileHits(reporter, SkRect::MakeXYWH(0, 30, 1, 1), 0);
+ verifyTileHits(reporter, SkRect::MakeXYWH(-10, 0, 1, 1), 0);
+ verifyTileHits(reporter, SkRect::MakeXYWH(0, -10, 1, 1), 0);
+
+ // Dilation for AA consideration
+ verifyTileHits(reporter, SkRect::MakeXYWH(0, 0, 9, 9), kTopLeft_Tile);
+ verifyTileHits(reporter, SkRect::MakeXYWH(0, 0, 10, 10), kAll_Tile);
+ verifyTileHits(reporter, SkRect::MakeXYWH(9, 9, 1, 1), kAll_Tile);
+ verifyTileHits(reporter, SkRect::MakeXYWH(10, 10, 1, 1), kAll_Tile);
+ verifyTileHits(reporter, SkRect::MakeXYWH(11, 11, 1, 1), kBottomRight_Tile);
+
+ // BorderPixels
+ verifyTileHits(reporter, SkRect::MakeXYWH(0, 0, 6, 6), kTopLeft_Tile, 1);
+ verifyTileHits(reporter, SkRect::MakeXYWH(0, 0, 7, 7), kAll_Tile, 1);
+ verifyTileHits(reporter, SkRect::MakeXYWH(9, 9, 1, 1), kAll_Tile, 1);
+ verifyTileHits(reporter, SkRect::MakeXYWH(10, 10, 1, 1), kBottomRight_Tile, 1);
+ verifyTileHits(reporter, SkRect::MakeXYWH(17, 17, 1, 1), kBottomRight_Tile, 1);
+
+ // BBoxes that overlap tiles
+ verifyTileHits(reporter, SkRect::MakeXYWH(5, 5, 10, 1), kTopLeft_Tile | kTopRight_Tile);
+ verifyTileHits(reporter, SkRect::MakeXYWH(5, 5, 1, 10), kTopLeft_Tile |
+ kBottomLeft_Tile);
+ verifyTileHits(reporter, SkRect::MakeXYWH(5, 5, 10, 10), kAll_Tile);
+ verifyTileHits(reporter, SkRect::MakeXYWH(-10, -10, 40, 40), kAll_Tile);
+}
diff --git a/src/third_party/skia/tests/ToUnicodeTest.cpp b/src/third_party/skia/tests/ToUnicodeTest.cpp
new file mode 100644
index 0000000..919ba11
--- /dev/null
+++ b/src/third_party/skia/tests/ToUnicodeTest.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2010 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkData.h"
+#include "SkPDFFont.h"
+#include "SkPDFTypes.h"
+#include "SkStream.h"
+#include "Test.h"
+
+static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
+ const char* buffer, size_t len) {
+ SkAutoDataUnref data(stream.copyToData());
+ if (offset + len > data->size()) {
+ return false;
+ }
+ if (len != strlen(buffer)) {
+ return false;
+ }
+ return memcmp(data->bytes() + offset, buffer, len) == 0;
+}
+
+void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode,
+ const SkPDFGlyphSet* subset,
+ SkDynamicMemoryWStream* cmap,
+ bool multiByteGlyphs,
+ uint16_t firstGlypthID,
+ uint16_t lastGlypthID);
+
+DEF_TEST(ToUnicode, reporter) {
+ SkTDArray<SkUnichar> glyphToUnicode;
+ SkTDArray<uint16_t> glyphsInSubset;
+ SkPDFGlyphSet subset;
+
+ glyphToUnicode.push(0); // 0
+ glyphToUnicode.push(0); // 1
+ glyphToUnicode.push(0); // 2
+ glyphsInSubset.push(3);
+ glyphToUnicode.push(0x20); // 3
+ glyphsInSubset.push(4);
+ glyphToUnicode.push(0x25); // 4
+ glyphsInSubset.push(5);
+ glyphToUnicode.push(0x27); // 5
+ glyphsInSubset.push(6);
+ glyphToUnicode.push(0x28); // 6
+ glyphsInSubset.push(7);
+ glyphToUnicode.push(0x29); // 7
+ glyphsInSubset.push(8);
+ glyphToUnicode.push(0x2F); // 8
+ glyphsInSubset.push(9);
+ glyphToUnicode.push(0x33); // 9
+ glyphToUnicode.push(0); // 10
+ glyphsInSubset.push(11);
+ glyphToUnicode.push(0x35); // 11
+ glyphsInSubset.push(12);
+ glyphToUnicode.push(0x36); // 12
+ glyphsInSubset.push(13);
+ glyphToUnicode.push(0x37); // 13
+ for (uint16_t i = 14; i < 0xFE; ++i) {
+ glyphToUnicode.push(0); // Zero from index 0x9 to 0xFD
+ }
+ glyphsInSubset.push(0xFE);
+ glyphToUnicode.push(0x1010);
+ glyphsInSubset.push(0xFF);
+ glyphToUnicode.push(0x1011);
+ glyphsInSubset.push(0x100);
+ glyphToUnicode.push(0x1012);
+ glyphsInSubset.push(0x101);
+ glyphToUnicode.push(0x1013);
+
+ SkDynamicMemoryWStream buffer;
+ subset.set(glyphsInSubset.begin(), glyphsInSubset.count());
+ append_cmap_sections(glyphToUnicode, &subset, &buffer, true, 0, 0xFFFF);
+
+ char expectedResult[] =
+"4 beginbfchar\n\
+<0003> <0020>\n\
+<0004> <0025>\n\
+<0008> <002F>\n\
+<0009> <0033>\n\
+endbfchar\n\
+4 beginbfrange\n\
+<0005> <0007> <0027>\n\
+<000B> <000D> <0035>\n\
+<00FE> <00FF> <1010>\n\
+<0100> <0101> <1012>\n\
+endbfrange\n";
+
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
+ buffer.getOffset()));
+
+ // Remove characters and ranges.
+ buffer.reset();
+
+ append_cmap_sections(glyphToUnicode, &subset, &buffer, true, 8, 0x00FF);
+
+ char expectedResultChop1[] =
+"2 beginbfchar\n\
+<0008> <002F>\n\
+<0009> <0033>\n\
+endbfchar\n\
+2 beginbfrange\n\
+<000B> <000D> <0035>\n\
+<00FE> <00FF> <1010>\n\
+endbfrange\n";
+
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResultChop1,
+ buffer.getOffset()));
+
+ // Remove characters from range to downdrade it to one char.
+ buffer.reset();
+
+ append_cmap_sections(glyphToUnicode, &subset, &buffer, true, 0x00D, 0x00FE);
+
+ char expectedResultChop2[] =
+"2 beginbfchar\n\
+<000D> <0037>\n\
+<00FE> <1010>\n\
+endbfchar\n";
+
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResultChop2,
+ buffer.getOffset()));
+
+ buffer.reset();
+
+ append_cmap_sections(glyphToUnicode, NULL, &buffer, false, 0xFC, 0x110);
+
+ char expectedResultSingleBytes[] =
+"2 beginbfchar\n\
+<0001> <0000>\n\
+<0002> <0000>\n\
+endbfchar\n\
+1 beginbfrange\n\
+<0003> <0006> <1010>\n\
+endbfrange\n";
+
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0,
+ expectedResultSingleBytes,
+ buffer.getOffset()));
+
+ glyphToUnicode.reset();
+ glyphsInSubset.reset();
+ SkPDFGlyphSet subset2;
+
+ // Test mapping:
+ // I n s t a l
+ // Glyph id 2c 51 56 57 44 4f
+ // Unicode 49 6e 73 74 61 6c
+ for (size_t i = 0; i < 100; ++i) {
+ glyphToUnicode.push(i + 29);
+ }
+
+ glyphsInSubset.push(0x2C);
+ glyphsInSubset.push(0x44);
+ glyphsInSubset.push(0x4F);
+ glyphsInSubset.push(0x51);
+ glyphsInSubset.push(0x56);
+ glyphsInSubset.push(0x57);
+
+ SkDynamicMemoryWStream buffer2;
+ subset2.set(glyphsInSubset.begin(), glyphsInSubset.count());
+ append_cmap_sections(glyphToUnicode, &subset2, &buffer2, true, 0, 0xffff);
+
+ char expectedResult2[] =
+"4 beginbfchar\n\
+<002C> <0049>\n\
+<0044> <0061>\n\
+<004F> <006C>\n\
+<0051> <006E>\n\
+endbfchar\n\
+1 beginbfrange\n\
+<0056> <0057> <0073>\n\
+endbfrange\n";
+
+ REPORTER_ASSERT(reporter, stream_equals(buffer2, 0, expectedResult2,
+ buffer2.getOffset()));
+}
diff --git a/src/third_party/skia/tests/TracingTest.cpp b/src/third_party/skia/tests/TracingTest.cpp
new file mode 100644
index 0000000..730a46c
--- /dev/null
+++ b/src/third_party/skia/tests/TracingTest.cpp
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTraceEvent.h"
+#include "Test.h"
+
+DEF_TEST(Tracing, reporter) {
+ TRACE_EVENT0("skia.testing", "just a test");
+}
diff --git a/src/third_party/skia/tests/TypefaceTest.cpp b/src/third_party/skia/tests/TypefaceTest.cpp
new file mode 100644
index 0000000..bb5d361
--- /dev/null
+++ b/src/third_party/skia/tests/TypefaceTest.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypeface.h"
+#include "Test.h"
+
+DEF_TEST(Typeface, reporter) {
+
+ SkAutoTUnref<SkTypeface> t1(SkTypeface::CreateFromName(NULL, SkTypeface::kNormal));
+ SkAutoTUnref<SkTypeface> t2(SkTypeface::RefDefault(SkTypeface::kNormal));
+
+ REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), t2.get()));
+ REPORTER_ASSERT(reporter, SkTypeface::Equal(0, t1.get()));
+ REPORTER_ASSERT(reporter, SkTypeface::Equal(0, t2.get()));
+ REPORTER_ASSERT(reporter, SkTypeface::Equal(t1.get(), 0));
+ REPORTER_ASSERT(reporter, SkTypeface::Equal(t2.get(), 0));
+
+#ifdef SK_BUILD_FOR_ANDROID
+ SkAutoTUnref<SkTypeface> t3(SkTypeface::CreateFromName("non-existent-font", SkTypeface::kNormal));
+ REPORTER_ASSERT(reporter, NULL == t3.get());
+#endif
+}
diff --git a/src/third_party/skia/tests/UnicodeTest.cpp b/src/third_party/skia/tests/UnicodeTest.cpp
new file mode 100644
index 0000000..5ed92d4
--- /dev/null
+++ b/src/third_party/skia/tests/UnicodeTest.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPaint.h"
+#include "SkUtils.h"
+#include "Test.h"
+
+// Unicode Variation Selector ranges: inclusive
+#define UVS_MIN0 0x180B
+#define UVS_MAX0 0x180D
+#define UVS_MIN1 0xFE00
+#define UVS_MAX1 0xFE0F
+#define UVS_MIN2 0xE0100
+#define UVS_MAX2 0xE01EF
+
+static bool isUVS(SkUnichar uni) {
+ return (uni >= UVS_MIN0 && uni <= UVS_MAX0) ||
+ (uni >= UVS_MIN1 && uni <= UVS_MAX1) ||
+ (uni >= UVS_MIN2 && uni <= UVS_MAX2);
+}
+
+static void test_uvs(skiatest::Reporter* reporter) {
+ // [min, max], [min, max] ... inclusive
+ static const SkUnichar gRanges[] = {
+ UVS_MIN0, UVS_MAX0, UVS_MIN1, UVS_MAX1, UVS_MIN2, UVS_MAX2
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRanges); i += 2) {
+ for (SkUnichar uni = gRanges[i] - 8; uni <= gRanges[i+1] + 8; ++uni) {
+ bool uvs0 = isUVS(uni);
+ bool uvs1 = SkUnichar_IsVariationSelector(uni);
+ REPORTER_ASSERT(reporter, uvs0 == uvs1);
+ }
+ }
+}
+
+// Simple test to ensure that when we call textToGlyphs, we get the same
+// result (for the same text) when using UTF8, UTF16, UTF32.
+// TODO: make the text more complex (i.e. incorporate chars>7bits)
+static void test_textencodings(skiatest::Reporter* reporter) {
+ const char text8[] = "ABCDEFGabcdefg0123456789";
+ uint16_t text16[sizeof(text8)];
+ int32_t text32[sizeof(text8)];
+ size_t len8 = strlen(text8);
+ size_t len16 = len8 * 2;
+ size_t len32 = len8 * 4;
+
+ // expand our 8bit chars to 16 and 32
+ for (size_t i = 0; i < len8; ++i) {
+ text32[i] = text16[i] = text8[i];
+ }
+
+ uint16_t glyphs8[sizeof(text8)];
+ uint16_t glyphs16[sizeof(text8)];
+ uint16_t glyphs32[sizeof(text8)];
+
+ SkPaint paint;
+
+ paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
+ int count8 = paint.textToGlyphs(text8, len8, glyphs8);
+
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ int count16 = paint.textToGlyphs(text16, len16, glyphs16);
+
+ paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
+ int count32 = paint.textToGlyphs(text32, len32, glyphs32);
+
+ REPORTER_ASSERT(reporter, (int)len8 == count8);
+ REPORTER_ASSERT(reporter, (int)len8 == count16);
+ REPORTER_ASSERT(reporter, (int)len8 == count32);
+
+ REPORTER_ASSERT(reporter, !memcmp(glyphs8, glyphs16, count8 * sizeof(uint16_t)));
+ REPORTER_ASSERT(reporter, !memcmp(glyphs8, glyphs32, count8 * sizeof(uint16_t)));
+}
+
+DEF_TEST(Unicode, reporter) {
+ test_uvs(reporter);
+ test_textencodings(reporter);
+}
diff --git a/src/third_party/skia/tests/UtilsTest.cpp b/src/third_party/skia/tests/UtilsTest.cpp
new file mode 100644
index 0000000..2c84c95
--- /dev/null
+++ b/src/third_party/skia/tests/UtilsTest.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRandom.h"
+#include "SkRefCnt.h"
+#include "SkTSearch.h"
+#include "SkTSort.h"
+#include "SkUtils.h"
+#include "Test.h"
+
+class RefClass : public SkRefCnt {
+public:
+ SK_DECLARE_INST_COUNT(RefClass)
+
+ RefClass(int n) : fN(n) {}
+ int get() const { return fN; }
+
+private:
+ int fN;
+
+ typedef SkRefCnt INHERITED;
+};
+
+static void test_autounref(skiatest::Reporter* reporter) {
+ RefClass obj(0);
+ REPORTER_ASSERT(reporter, 1 == obj.getRefCnt());
+
+ SkAutoTUnref<RefClass> tmp(&obj);
+ REPORTER_ASSERT(reporter, &obj == tmp.get());
+ REPORTER_ASSERT(reporter, 1 == obj.getRefCnt());
+
+ REPORTER_ASSERT(reporter, &obj == tmp.detach());
+ REPORTER_ASSERT(reporter, 1 == obj.getRefCnt());
+ REPORTER_ASSERT(reporter, NULL == tmp.detach());
+ REPORTER_ASSERT(reporter, NULL == tmp.get());
+
+ obj.ref();
+ REPORTER_ASSERT(reporter, 2 == obj.getRefCnt());
+ {
+ SkAutoTUnref<RefClass> tmp2(&obj);
+ }
+ REPORTER_ASSERT(reporter, 1 == obj.getRefCnt());
+}
+
+static void test_autostarray(skiatest::Reporter* reporter) {
+ RefClass obj0(0);
+ RefClass obj1(1);
+ REPORTER_ASSERT(reporter, 1 == obj0.getRefCnt());
+ REPORTER_ASSERT(reporter, 1 == obj1.getRefCnt());
+
+ {
+ SkAutoSTArray<2, SkAutoTUnref<RefClass> > tmp;
+ REPORTER_ASSERT(reporter, 0 == tmp.count());
+
+ tmp.reset(0); // test out reset(0) when already at 0
+ tmp.reset(4); // this should force a new allocation
+ REPORTER_ASSERT(reporter, 4 == tmp.count());
+ tmp[0].reset(SkRef(&obj0));
+ tmp[1].reset(SkRef(&obj1));
+ REPORTER_ASSERT(reporter, 2 == obj0.getRefCnt());
+ REPORTER_ASSERT(reporter, 2 == obj1.getRefCnt());
+
+ // test out reset with data in the array (and a new allocation)
+ tmp.reset(0);
+ REPORTER_ASSERT(reporter, 0 == tmp.count());
+ REPORTER_ASSERT(reporter, 1 == obj0.getRefCnt());
+ REPORTER_ASSERT(reporter, 1 == obj1.getRefCnt());
+
+ tmp.reset(2); // this should use the preexisting allocation
+ REPORTER_ASSERT(reporter, 2 == tmp.count());
+ tmp[0].reset(SkRef(&obj0));
+ tmp[1].reset(SkRef(&obj1));
+ }
+
+ // test out destructor with data in the array (and using existing allocation)
+ REPORTER_ASSERT(reporter, 1 == obj0.getRefCnt());
+ REPORTER_ASSERT(reporter, 1 == obj1.getRefCnt());
+
+ {
+ // test out allocating ctor (this should allocate new memory)
+ SkAutoSTArray<2, SkAutoTUnref<RefClass> > tmp(4);
+ REPORTER_ASSERT(reporter, 4 == tmp.count());
+
+ tmp[0].reset(SkRef(&obj0));
+ tmp[1].reset(SkRef(&obj1));
+ REPORTER_ASSERT(reporter, 2 == obj0.getRefCnt());
+ REPORTER_ASSERT(reporter, 2 == obj1.getRefCnt());
+
+ // Test out resut with data in the array and malloced storage
+ tmp.reset(0);
+ REPORTER_ASSERT(reporter, 1 == obj0.getRefCnt());
+ REPORTER_ASSERT(reporter, 1 == obj1.getRefCnt());
+
+ tmp.reset(2); // this should use the preexisting storage
+ tmp[0].reset(SkRef(&obj0));
+ tmp[1].reset(SkRef(&obj1));
+ REPORTER_ASSERT(reporter, 2 == obj0.getRefCnt());
+ REPORTER_ASSERT(reporter, 2 == obj1.getRefCnt());
+
+ tmp.reset(4); // this should force a new malloc
+ REPORTER_ASSERT(reporter, 1 == obj0.getRefCnt());
+ REPORTER_ASSERT(reporter, 1 == obj1.getRefCnt());
+
+ tmp[0].reset(SkRef(&obj0));
+ tmp[1].reset(SkRef(&obj1));
+ REPORTER_ASSERT(reporter, 2 == obj0.getRefCnt());
+ REPORTER_ASSERT(reporter, 2 == obj1.getRefCnt());
+ }
+
+ REPORTER_ASSERT(reporter, 1 == obj0.getRefCnt());
+ REPORTER_ASSERT(reporter, 1 == obj1.getRefCnt());
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define kSEARCH_COUNT 91
+
+static void test_search(skiatest::Reporter* reporter) {
+ int i, array[kSEARCH_COUNT];
+ SkRandom rand;
+
+ for (i = 0; i < kSEARCH_COUNT; i++) {
+ array[i] = rand.nextS();
+ }
+
+ SkTHeapSort<int>(array, kSEARCH_COUNT);
+ // make sure we got sorted properly
+ for (i = 1; i < kSEARCH_COUNT; i++) {
+ REPORTER_ASSERT(reporter, array[i-1] <= array[i]);
+ }
+
+ // make sure we can find all of our values
+ for (i = 0; i < kSEARCH_COUNT; i++) {
+ int index = SkTSearch<int>(array, kSEARCH_COUNT, array[i], sizeof(int));
+ REPORTER_ASSERT(reporter, index == i);
+ }
+
+ // make sure that random values are either found, or the correct
+ // insertion index is returned
+ for (i = 0; i < 10000; i++) {
+ int value = rand.nextS();
+ int index = SkTSearch<int>(array, kSEARCH_COUNT, value, sizeof(int));
+
+ if (index >= 0) {
+ REPORTER_ASSERT(reporter,
+ index < kSEARCH_COUNT && array[index] == value);
+ } else {
+ index = ~index;
+ REPORTER_ASSERT(reporter, index <= kSEARCH_COUNT);
+ if (index < kSEARCH_COUNT) {
+ REPORTER_ASSERT(reporter, value < array[index]);
+ if (index > 0) {
+ REPORTER_ASSERT(reporter, value > array[index - 1]);
+ }
+ } else {
+ // we should append the new value
+ REPORTER_ASSERT(reporter, value > array[kSEARCH_COUNT - 1]);
+ }
+ }
+ }
+}
+
+static void test_utf16(skiatest::Reporter* reporter) {
+ static const SkUnichar gUni[] = {
+ 0x10000, 0x18080, 0x20202, 0xFFFFF, 0x101234
+ };
+
+ uint16_t buf[2];
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gUni); i++) {
+ size_t count = SkUTF16_FromUnichar(gUni[i], buf);
+ REPORTER_ASSERT(reporter, count == 2);
+ size_t count2 = SkUTF16_CountUnichars(buf, 2);
+ REPORTER_ASSERT(reporter, count2 == 1);
+ const uint16_t* ptr = buf;
+ SkUnichar c = SkUTF16_NextUnichar(&ptr);
+ REPORTER_ASSERT(reporter, c == gUni[i]);
+ REPORTER_ASSERT(reporter, ptr - buf == 2);
+ }
+}
+
+DEF_TEST(Utils, reporter) {
+ static const struct {
+ const char* fUtf8;
+ SkUnichar fUni;
+ } gTest[] = {
+ { "a", 'a' },
+ { "\x7f", 0x7f },
+ { "\xC2\x80", 0x80 },
+ { "\xC3\x83", (3 << 6) | 3 },
+ { "\xDF\xBF", 0x7ff },
+ { "\xE0\xA0\x80", 0x800 },
+ { "\xE0\xB0\xB8", 0xC38 },
+ { "\xE3\x83\x83", (3 << 12) | (3 << 6) | 3 },
+ { "\xEF\xBF\xBF", 0xFFFF },
+ { "\xF0\x90\x80\x80", 0x10000 },
+ { "\xF3\x83\x83\x83", (3 << 18) | (3 << 12) | (3 << 6) | 3 }
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gTest); i++) {
+ const char* p = gTest[i].fUtf8;
+ int n = SkUTF8_CountUnichars(p);
+ SkUnichar u0 = SkUTF8_ToUnichar(gTest[i].fUtf8);
+ SkUnichar u1 = SkUTF8_NextUnichar(&p);
+
+ REPORTER_ASSERT(reporter, n == 1);
+ REPORTER_ASSERT(reporter, u0 == u1);
+ REPORTER_ASSERT(reporter, u0 == gTest[i].fUni);
+ REPORTER_ASSERT(reporter,
+ p - gTest[i].fUtf8 == (int)strlen(gTest[i].fUtf8));
+ }
+
+ test_utf16(reporter);
+ test_search(reporter);
+ test_autounref(reporter);
+ test_autostarray(reporter);
+}
diff --git a/src/third_party/skia/tests/WArrayTest.cpp b/src/third_party/skia/tests/WArrayTest.cpp
new file mode 100644
index 0000000..7f03e5b
--- /dev/null
+++ b/src/third_party/skia/tests/WArrayTest.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+
+// Include the implementation so we can make an appropriate template instance.
+#include "SkAdvancedTypefaceMetrics.h"
+
+using namespace skia_advanced_typeface_metrics_utils;
+
+// Negative values and zeros in a range plus trailing zeros.
+// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
+static const int16_t data1[] = {-1, 0, -3, 4, 5, 6, 7, 0, 0, 0, 8, 0, 0, 0, 0};
+static const char* expected1 = "0[-1 0 -3 4 5 6 7 0 0 0 8]";
+
+// Run with leading and trailing zeros.
+// Test rules: d 0 1 2 3 4 5 6 7 8 9 10 11
+static const int16_t data2[] = {0, 0, 0, 100, 100, 100, 100, 100, 100, 100, 0, 0};
+static const char* expected2 = "3 9 100";
+
+// Removing 0's from a range.
+// Test rules: a 0 1 2 3 4 5 6 7 8 9 10 11
+static const int16_t data3[] = {1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 0, 5};
+static const char* expected3 = "0[1 2 0 0 0 3 4] 11[5]";
+
+// Removing 0's from a run/range and between runs.
+// Test rules: a, b 0 1 2 3 4 5 6 7 8 9 10 11 12 14 15
+static const int16_t data4[] = {1, 0, 0, 0, 1, 2, 2, 2, 3, 0, 0, 0, 0, 3, 4};
+static const char* expected4 = "0[1 0 0 0 1] 5 7 2 8[3] 13[3 4]";
+
+// Runs that starts outside a range.
+// Test rules: a, e 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+static const int16_t data5[] = {1, 1, 2, 3, 0, 0, 0, 0, 5, 5, 6, 7, 0, 0, 0, 0, 8, 0};
+static const char* expected5 = "0 1 1 2[2 3] 8 9 5 10[6 7] 16[8]";
+
+// Zeros and runs that should be broken out.
+// Test rules: a, b, e 0 1 2 3 4 5 6 7 8 9 10 11 12 13
+static const int16_t data6[] = {1, 0, 0, 0, 0, 1, 2, 3, 3, 4, 5, 5, 5, 6};
+static const char* expected6 = "0[1] 5[1 2 3 3 4] 10 12 5 13[6]";
+
+// Don't cares that aren't enough to break out a run.
+// Test rules: c 0 1 2 3 4 5
+static const int16_t data7[] = {1, 2, 10, 11, 2, 3};
+static const char* expected7 = "0[1 2 10 11 2 3]";
+static const uint32_t subset7[] = {0, 1, 4, 5};
+static const char* expectedSubset7 = "0[1 2 0 0 2 3]";
+
+// Don't cares that are enough to break out a run.
+// Test rules: c 0 1 2 3 4 5 6
+static const int16_t data8[] = {1, 2, 10, 11, 12, 2, 3};
+static const char* expected8 = "0[1 2 10 11 12 2 3]";
+static const uint32_t subset8[] = {0, 1, 5, 6};
+static const char* expectedSubset8 = "0[1] 1 5 2 6[3]";
+
+// Leading don't cares.
+// Test rules: d 0 1 2 3 4
+static const int16_t data9[] = {1, 1, 10, 2, 3};
+static const char* expected9 = "0 1 1 2[10 2 3]";
+static const uint32_t subset9[] = {0, 1, 3, 4};
+static const char* expectedSubset9 = "0 1 1 3[2 3]";
+
+// Almost run of don't cares inside a range.
+// Test rules: c 0 1 2 3 4 5
+static const int16_t data10[] = {1, 2, 10, 11, 12, 3};
+static const char* expected10 = "0[1 2 10 11 12 3]";
+static const uint32_t subset10[] = {0, 1, 5};
+static const char* expectedSubset10 = "0[1 2 0 0 0 3]";
+
+// Run of don't cares inside a range.
+// Test rules: c 0 1 2 3 4 5 6
+static const int16_t data11[] = {1, 2, 10, 11, 12, 13, 3};
+static const char* expected11 = "0[1 2 10 11 12 13 3]";
+static const uint32_t subset11[] = {0, 1, 6};
+static const char* expectedSubset11 = "0[1 2] 6[3]";
+
+// Almost run within a range with leading don't cares.
+// Test rules: c 0 1 2 3 4 5 6
+static const int16_t data12[] = {1, 10, 11, 2, 12, 13, 3};
+static const char* expected12 = "0[1 10 11 2 12 13 3]";
+static const uint32_t subset12[] = {0, 3, 6};
+static const char* expectedSubset12 = "0[1 0 0 2 0 0 3]";
+
+// Run within a range with leading don't cares.
+// Test rules: c 0 1 2 3 4 5 6 7
+static const int16_t data13[] = {1, 10, 11, 2, 2, 12, 13, 3};
+static const char* expected13 = "0[1 10 11 2 2 12 13 3]";
+static const uint32_t subset13[] = {0, 3, 4, 7};
+static const char* expectedSubset13 = "0[1] 1 6 2 7[3]";
+
+// Enough don't cares to breakup something.
+// Test rules: a 0 1 2 3 4 5
+static const int16_t data14[] = {1, 0, 0, 0, 0, 2};
+static const char* expected14 = "0[1] 5[2]";
+static const uint32_t subset14[] = {0, 5};
+static const char* expectedSubset14 = "0[1] 5[2]";
+
+static SkString stringify_advance_data(SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>* data) {
+ SkString result;
+ bool leadingSpace = false;
+ while (data != NULL) {
+ if (leadingSpace) {
+ result.append(" ");
+ } else {
+ leadingSpace = true;
+ }
+ switch(data->fType) {
+ case SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>::kRun:
+ result.appendf("%d %d %d", data->fStartId, data->fEndId, data->fAdvance[0]);
+ break;
+ case SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>::kRange:
+ result.appendf("%d[", data->fStartId);
+ for (int i = 0; i < data->fAdvance.count(); ++i) {
+ if (i > 0) {
+ result.append(" ");
+ }
+ result.appendf("%d", data->fAdvance[i]);
+ }
+ result.append("]");
+ break;
+ case SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>::kDefault:
+ result.appendf("<Default=%d>", data->fAdvance[0]);
+ break;
+ }
+ data = data->fNext.get();
+ }
+ return result;
+}
+
+class TestWData {
+ public:
+ TestWData(skiatest::Reporter* reporter,
+ const int16_t advances[], int advanceLen,
+ const uint32_t subset[], int subsetLen,
+ const char* expected)
+ : fAdvances(advances)
+ , fAdvancesLen(advanceLen)
+ , fSubset(subset)
+ , fSubsetLen(subsetLen)
+ , fExpected(expected) {
+ REPORTER_ASSERT(reporter, RunTest());
+ }
+
+ private:
+ const int16_t* fAdvances;
+ const int fAdvancesLen;
+ const uint32_t* fSubset;
+ const int fSubsetLen;
+ const char* fExpected;
+
+ static bool getAdvance(void* tc, int gId, int16_t* advance) {
+ TestWData* testCase = (TestWData*)tc;
+ if (gId >= 0 && gId < testCase->fAdvancesLen) {
+ *advance = testCase->fAdvances[gId];
+ return true;
+ }
+ return false;
+ }
+
+ bool RunTest() {
+ SkAutoTDelete<SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t> > result;
+ result.reset(getAdvanceData((void*)this, fAdvancesLen, fSubset, fSubsetLen, getAdvance));
+
+ SkString stringResult = stringify_advance_data(result);
+ if (!stringResult.equals(fExpected)) {
+ SkDebugf("Expected: %s\n Result: %s\n", fExpected, stringResult.c_str());
+ return false;
+ }
+ return true;
+ }
+};
+
+DEF_TEST(WArray, reporter) {
+ TestWData(reporter, data1, SK_ARRAY_COUNT(data1), NULL, 0, expected1);
+ TestWData(reporter, data2, SK_ARRAY_COUNT(data2), NULL, 0, expected2);
+ TestWData(reporter, data3, SK_ARRAY_COUNT(data3), NULL, 0, expected3);
+ TestWData(reporter, data4, SK_ARRAY_COUNT(data4), NULL, 0, expected4);
+ TestWData(reporter, data5, SK_ARRAY_COUNT(data5), NULL, 0, expected5);
+ TestWData(reporter, data6, SK_ARRAY_COUNT(data6), NULL, 0, expected6);
+ TestWData(reporter, data7, SK_ARRAY_COUNT(data7), NULL, 0, expected7);
+ TestWData(reporter, data7, SK_ARRAY_COUNT(data7), subset7,
+ SK_ARRAY_COUNT(subset7), expectedSubset7);
+ TestWData(reporter, data8, SK_ARRAY_COUNT(data8), NULL, 0, expected8);
+ TestWData(reporter, data8, SK_ARRAY_COUNT(data8), subset8,
+ SK_ARRAY_COUNT(subset8), expectedSubset8);
+ TestWData(reporter, data9, SK_ARRAY_COUNT(data9), NULL, 0, expected9);
+ TestWData(reporter, data9, SK_ARRAY_COUNT(data9), subset9,
+ SK_ARRAY_COUNT(subset9), expectedSubset9);
+ TestWData(reporter, data10, SK_ARRAY_COUNT(data10), NULL, 0, expected10);
+ TestWData(reporter, data10, SK_ARRAY_COUNT(data10), subset10,
+ SK_ARRAY_COUNT(subset10), expectedSubset10);
+ TestWData(reporter, data11, SK_ARRAY_COUNT(data11), NULL, 0, expected11);
+ TestWData(reporter, data11, SK_ARRAY_COUNT(data11), subset11,
+ SK_ARRAY_COUNT(subset11), expectedSubset11);
+ TestWData(reporter, data12, SK_ARRAY_COUNT(data12), NULL, 0, expected12);
+ TestWData(reporter, data12, SK_ARRAY_COUNT(data12), subset12,
+ SK_ARRAY_COUNT(subset12), expectedSubset12);
+ TestWData(reporter, data13, SK_ARRAY_COUNT(data13), NULL, 0, expected13);
+ TestWData(reporter, data13, SK_ARRAY_COUNT(data13), subset13,
+ SK_ARRAY_COUNT(subset13), expectedSubset13);
+ TestWData(reporter, data14, SK_ARRAY_COUNT(data14), NULL, 0, expected14);
+ TestWData(reporter, data14, SK_ARRAY_COUNT(data14), subset14,
+ SK_ARRAY_COUNT(subset14), expectedSubset14);
+}
diff --git a/src/third_party/skia/tests/WritePixelsTest.cpp b/src/third_party/skia/tests/WritePixelsTest.cpp
new file mode 100644
index 0000000..f47c67b
--- /dev/null
+++ b/src/third_party/skia/tests/WritePixelsTest.cpp
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmapDevice.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkMathPriv.h"
+#include "SkRegion.h"
+#include "SkSurface.h"
+#include "Test.h"
+#include "sk_tool_utils.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#include "SkGpuDevice.h"
+#else
+class GrContext;
+class GrContextFactory;
+#endif
+
+static const int DEV_W = 100, DEV_H = 100;
+static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
+static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1,
+ DEV_H * SK_Scalar1);
+static const U8CPU DEV_PAD = 0xee;
+
+static SkPMColor getCanvasColor(int x, int y) {
+ SkASSERT(x >= 0 && x < DEV_W);
+ SkASSERT(y >= 0 && y < DEV_H);
+
+ U8CPU r = x;
+ U8CPU g = y;
+ U8CPU b = 0xc;
+
+ U8CPU a = 0x0;
+ switch ((x+y) % 5) {
+ case 0:
+ a = 0xff;
+ break;
+ case 1:
+ a = 0x80;
+ break;
+ case 2:
+ a = 0xCC;
+ break;
+ case 3:
+ a = 0x00;
+ break;
+ case 4:
+ a = 0x01;
+ break;
+ }
+ return SkPremultiplyARGBInline(a, r, g, b);
+}
+
+// assumes any premu/.unpremul has been applied
+static uint32_t packColorType(SkColorType ct, U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
+ uint32_t r32;
+ uint8_t* result = reinterpret_cast<uint8_t*>(&r32);
+ switch (ct) {
+ case kBGRA_8888_SkColorType:
+ result[0] = b;
+ result[1] = g;
+ result[2] = r;
+ result[3] = a;
+ break;
+ case kRGBA_8888_SkColorType:
+ result[0] = r;
+ result[1] = g;
+ result[2] = b;
+ result[3] = a;
+ break;
+ default:
+ SkASSERT(0);
+ return 0;
+ }
+ return r32;
+}
+
+static uint32_t getBitmapColor(int x, int y, int w, SkColorType ct, SkAlphaType at) {
+ int n = y * w + x;
+ U8CPU b = n & 0xff;
+ U8CPU g = (n >> 8) & 0xff;
+ U8CPU r = (n >> 16) & 0xff;
+ U8CPU a = 0;
+ switch ((x+y) % 5) {
+ case 4:
+ a = 0xff;
+ break;
+ case 3:
+ a = 0x80;
+ break;
+ case 2:
+ a = 0xCC;
+ break;
+ case 1:
+ a = 0x01;
+ break;
+ case 0:
+ a = 0x00;
+ break;
+ }
+ if (kPremul_SkAlphaType == at) {
+ r = SkMulDiv255Ceiling(r, a);
+ g = SkMulDiv255Ceiling(g, a);
+ b = SkMulDiv255Ceiling(b, a);
+ }
+ return packColorType(ct, a, r, g , b);
+}
+
+static void fillCanvas(SkCanvas* canvas) {
+ SkBitmap bmp;
+ if (bmp.isNull()) {
+ bmp.allocN32Pixels(DEV_W, DEV_H);
+ for (int y = 0; y < DEV_H; ++y) {
+ for (int x = 0; x < DEV_W; ++x) {
+ *bmp.getAddr32(x, y) = getCanvasColor(x, y);
+ }
+ }
+ }
+ canvas->save();
+ canvas->setMatrix(SkMatrix::I());
+ canvas->clipRect(DEV_RECT_S, SkRegion::kReplace_Op);
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas->drawBitmap(bmp, 0, 0, &paint);
+ canvas->restore();
+}
+
+/**
+ * Lucky for us, alpha is always in the same spot (SK_A32_SHIFT), for both RGBA and BGRA.
+ * Thus this routine doesn't need to know the exact colortype
+ */
+static uint32_t premul(uint32_t color) {
+ unsigned a = SkGetPackedA32(color);
+ // these next three are not necessarily r,g,b in that order, but they are r,g,b in some order.
+ unsigned c0 = SkGetPackedR32(color);
+ unsigned c1 = SkGetPackedG32(color);
+ unsigned c2 = SkGetPackedB32(color);
+ c0 = SkMulDiv255Ceiling(c0, a);
+ c1 = SkMulDiv255Ceiling(c1, a);
+ c2 = SkMulDiv255Ceiling(c2, a);
+ return SkPackARGB32NoCheck(a, c0, c1, c2);
+}
+
+static SkPMColor convert_to_PMColor(SkColorType ct, SkAlphaType at, uint32_t color) {
+ if (kUnpremul_SkAlphaType == at) {
+ color = premul(color);
+ }
+ switch (ct) {
+ case kRGBA_8888_SkColorType:
+ color = SkSwizzle_RGBA_to_PMColor(color);
+ break;
+ case kBGRA_8888_SkColorType:
+ color = SkSwizzle_BGRA_to_PMColor(color);
+ break;
+ default:
+ SkASSERT(0);
+ break;
+ }
+ return color;
+}
+
+static bool checkPixel(SkPMColor a, SkPMColor b, bool didPremulConversion) {
+ if (!didPremulConversion) {
+ return a == b;
+ }
+ int32_t aA = static_cast<int32_t>(SkGetPackedA32(a));
+ int32_t aR = static_cast<int32_t>(SkGetPackedR32(a));
+ int32_t aG = static_cast<int32_t>(SkGetPackedG32(a));
+ int32_t aB = SkGetPackedB32(a);
+
+ int32_t bA = static_cast<int32_t>(SkGetPackedA32(b));
+ int32_t bR = static_cast<int32_t>(SkGetPackedR32(b));
+ int32_t bG = static_cast<int32_t>(SkGetPackedG32(b));
+ int32_t bB = static_cast<int32_t>(SkGetPackedB32(b));
+
+ return aA == bA &&
+ SkAbs32(aR - bR) <= 1 &&
+ SkAbs32(aG - bG) <= 1 &&
+ SkAbs32(aB - bB) <= 1;
+}
+
+static bool check_write(skiatest::Reporter* reporter, SkCanvas* canvas, const SkBitmap& bitmap,
+ int writeX, int writeY) {
+ const SkImageInfo canvasInfo = canvas->imageInfo();
+ size_t canvasRowBytes;
+ const uint32_t* canvasPixels;
+
+ // Can't use canvas->peekPixels(), as we are trying to look at GPU pixels sometimes as well.
+ // At some point this will be unsupported, as we won't allow accessBitmap() to magically call
+ // readPixels for the client.
+ SkBitmap secretDevBitmap;
+ canvas->readPixels(SkIRect::MakeWH(canvasInfo.width(), canvasInfo.height()), &secretDevBitmap);
+
+ SkAutoLockPixels alp(secretDevBitmap);
+ canvasRowBytes = secretDevBitmap.rowBytes();
+ canvasPixels = static_cast<const uint32_t*>(secretDevBitmap.getPixels());
+
+ if (NULL == canvasPixels) {
+ return false;
+ }
+
+ if (canvasInfo.width() != DEV_W ||
+ canvasInfo.height() != DEV_H ||
+ canvasInfo.colorType() != kN32_SkColorType) {
+ return false;
+ }
+
+ const SkImageInfo bmInfo = bitmap.info();
+
+ SkIRect writeRect = SkIRect::MakeXYWH(writeX, writeY, bitmap.width(), bitmap.height());
+ for (int cy = 0; cy < DEV_H; ++cy) {
+ for (int cx = 0; cx < DEV_W; ++cx) {
+ SkPMColor canvasPixel = canvasPixels[cx];
+ if (writeRect.contains(cx, cy)) {
+ int bx = cx - writeX;
+ int by = cy - writeY;
+ uint32_t bmpColor8888 = getBitmapColor(bx, by, bitmap.width(),
+ bmInfo.colorType(), bmInfo.alphaType());
+ bool mul = (kUnpremul_SkAlphaType == bmInfo.alphaType());
+ SkPMColor bmpPMColor = convert_to_PMColor(bmInfo.colorType(), bmInfo.alphaType(),
+ bmpColor8888);
+ bool check = checkPixel(bmpPMColor, canvasPixel, mul);
+ REPORTER_ASSERT(reporter, check);
+ if (!check) {
+ return false;
+ }
+ } else {
+ bool check;
+ SkPMColor testColor = getCanvasColor(cx, cy);
+ REPORTER_ASSERT(reporter, check = (canvasPixel == testColor));
+ if (!check) {
+ return false;
+ }
+ }
+ }
+ if (cy != DEV_H -1) {
+ const char* pad = reinterpret_cast<const char*>(canvasPixels + DEV_W);
+ for (size_t px = 0; px < canvasRowBytes - 4 * DEV_W; ++px) {
+ bool check;
+ REPORTER_ASSERT(reporter, check = (pad[px] == static_cast<char>(DEV_PAD)));
+ if (!check) {
+ return false;
+ }
+ }
+ }
+ canvasPixels += canvasRowBytes/4;
+ }
+
+ return true;
+}
+
+enum DevType {
+ kRaster_DevType,
+#if SK_SUPPORT_GPU
+ kGpu_BottomLeft_DevType,
+ kGpu_TopLeft_DevType,
+#endif
+};
+
+struct CanvasConfig {
+ DevType fDevType;
+ bool fTightRowBytes;
+};
+
+static const CanvasConfig gCanvasConfigs[] = {
+ {kRaster_DevType, true},
+ {kRaster_DevType, false},
+#if SK_SUPPORT_GPU
+ {kGpu_BottomLeft_DevType, true}, // row bytes has no meaning on gpu devices
+ {kGpu_TopLeft_DevType, true}, // row bytes has no meaning on gpu devices
+#endif
+};
+
+#include "SkMallocPixelRef.h"
+
+// This is a tricky pattern, because we have to setConfig+rowBytes AND specify
+// a custom pixelRef (which also has to specify its rowBytes), so we have to be
+// sure that the two rowBytes match (and the infos match).
+//
+static bool allocRowBytes(SkBitmap* bm, const SkImageInfo& info, size_t rowBytes) {
+ if (!bm->setInfo(info, rowBytes)) {
+ return false;
+ }
+ SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, rowBytes, NULL);
+ bm->setPixelRef(pr)->unref();
+ return true;
+}
+
+static void free_pixels(void* pixels, void* ctx) {
+ sk_free(pixels);
+}
+
+static SkSurface* create_surface(const CanvasConfig& c, GrContext* grCtx) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
+ switch (c.fDevType) {
+ case kRaster_DevType: {
+ const size_t rowBytes = c.fTightRowBytes ? info.minRowBytes() : 4 * DEV_W + 100;
+ const size_t size = info.getSafeSize(rowBytes);
+ void* pixels = sk_malloc_throw(size);
+ // if rowBytes isn't tight then set the padding to a known value
+ if (!c.fTightRowBytes) {
+ memset(pixels, DEV_PAD, size);
+ }
+ return SkSurface::NewRasterDirectReleaseProc(info, pixels, rowBytes, free_pixels, NULL);
+ }
+#if SK_SUPPORT_GPU
+ case kGpu_BottomLeft_DevType:
+ case kGpu_TopLeft_DevType:
+ GrTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ desc.fWidth = DEV_W;
+ desc.fHeight = DEV_H;
+ desc.fConfig = kSkia8888_GrPixelConfig;
+ desc.fOrigin = kGpu_TopLeft_DevType == c.fDevType ?
+ kTopLeft_GrSurfaceOrigin : kBottomLeft_GrSurfaceOrigin;
+ GrAutoScratchTexture ast(grCtx, desc, GrContext::kExact_ScratchTexMatch);
+ SkAutoTUnref<GrTexture> tex(ast.detach());
+ return SkSurface::NewRenderTargetDirect(tex->asRenderTarget());
+#endif
+ }
+ return NULL;
+}
+
+static bool setup_bitmap(SkBitmap* bm, SkColorType ct, SkAlphaType at, int w, int h, int tightRB) {
+ size_t rowBytes = tightRB ? 0 : 4 * w + 60;
+ SkImageInfo info = SkImageInfo::Make(w, h, ct, at);
+ if (!allocRowBytes(bm, info, rowBytes)) {
+ return false;
+ }
+ SkAutoLockPixels alp(*bm);
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ *bm->getAddr32(x, y) = getBitmapColor(x, y, w, ct, at);
+ }
+ }
+ return true;
+}
+
+static void call_writepixels(SkCanvas* canvas) {
+ const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
+ SkPMColor pixel = 0;
+ canvas->writePixels(info, &pixel, sizeof(SkPMColor), 0, 0);
+}
+
+static void test_surface_genid(skiatest::Reporter* reporter) {
+ const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
+ uint32_t genID1 = surface->generationID();
+ call_writepixels(surface->getCanvas());
+ uint32_t genID2 = surface->generationID();
+ REPORTER_ASSERT(reporter, genID1 != genID2);
+}
+
+DEF_GPUTEST(WritePixels, reporter, factory) {
+ test_surface_genid(reporter);
+
+ SkCanvas canvas;
+
+ const SkIRect testRects[] = {
+ // entire thing
+ DEV_RECT,
+ // larger on all sides
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
+ // fully contained
+ SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
+ // outside top left
+ SkIRect::MakeLTRB(-10, -10, -1, -1),
+ // touching top left corner
+ SkIRect::MakeLTRB(-10, -10, 0, 0),
+ // overlapping top left corner
+ SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
+ // overlapping top left and top right corners
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H / 4),
+ // touching entire top edge
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, 0),
+ // overlapping top right corner
+ SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H / 4),
+ // contained in x, overlapping top edge
+ SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W / 4, DEV_H / 4),
+ // outside top right corner
+ SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
+ // touching top right corner
+ SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
+ // overlapping top left and bottom left corners
+ SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
+ // touching entire left edge
+ SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
+ // overlapping bottom left corner
+ SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
+ // contained in y, overlapping left edge
+ SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
+ // outside bottom left corner
+ SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
+ // touching bottom left corner
+ SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
+ // overlapping bottom left and bottom right corners
+ SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
+ // touching entire left edge
+ SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
+ // overlapping bottom right corner
+ SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
+ // overlapping top right and bottom right corners
+ SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gCanvasConfigs); ++i) {
+ int glCtxTypeCnt = 1;
+#if SK_SUPPORT_GPU
+ bool isGPUDevice = kGpu_TopLeft_DevType == gCanvasConfigs[i].fDevType ||
+ kGpu_BottomLeft_DevType == gCanvasConfigs[i].fDevType;
+ if (isGPUDevice) {
+ glCtxTypeCnt = GrContextFactory::kGLContextTypeCnt;
+ }
+#endif
+ for (int glCtxType = 0; glCtxType < glCtxTypeCnt; ++glCtxType) {
+ GrContext* context = NULL;
+#if SK_SUPPORT_GPU
+ if (isGPUDevice) {
+ GrContextFactory::GLContextType type =
+ static_cast<GrContextFactory::GLContextType>(glCtxType);
+ if (!GrContextFactory::IsRenderingGLContext(type)) {
+ continue;
+ }
+ context = factory->get(type);
+ if (NULL == context) {
+ continue;
+ }
+ }
+#endif
+
+ SkAutoTUnref<SkSurface> surface(create_surface(gCanvasConfigs[i], context));
+ SkCanvas& canvas = *surface->getCanvas();
+
+ static const struct {
+ SkColorType fColorType;
+ SkAlphaType fAlphaType;
+ } gSrcConfigs[] = {
+ { kRGBA_8888_SkColorType, kPremul_SkAlphaType },
+ { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType },
+ { kBGRA_8888_SkColorType, kPremul_SkAlphaType },
+ { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType },
+ };
+ for (size_t r = 0; r < SK_ARRAY_COUNT(testRects); ++r) {
+ const SkIRect& rect = testRects[r];
+ for (int tightBmp = 0; tightBmp < 2; ++tightBmp) {
+ for (size_t c = 0; c < SK_ARRAY_COUNT(gSrcConfigs); ++c) {
+ const SkColorType ct = gSrcConfigs[c].fColorType;
+ const SkAlphaType at = gSrcConfigs[c].fAlphaType;
+
+ fillCanvas(&canvas);
+ SkBitmap bmp;
+ REPORTER_ASSERT(reporter, setup_bitmap(&bmp, ct, at, rect.width(),
+ rect.height(), SkToBool(tightBmp)));
+ uint32_t idBefore = surface->generationID();
+
+ // sk_tool_utils::write_pixels(&canvas, bmp, rect.fLeft, rect.fTop, ct, at);
+ canvas.writePixels(bmp, rect.fLeft, rect.fTop);
+
+ uint32_t idAfter = surface->generationID();
+ REPORTER_ASSERT(reporter, check_write(reporter, &canvas, bmp,
+ rect.fLeft, rect.fTop));
+
+ // we should change the genID iff pixels were actually written.
+ SkIRect canvasRect = SkIRect::MakeSize(canvas.getDeviceSize());
+ SkIRect writeRect = SkIRect::MakeXYWH(rect.fLeft, rect.fTop,
+ bmp.width(), bmp.height());
+ bool intersects = SkIRect::Intersects(canvasRect, writeRect) ;
+ REPORTER_ASSERT(reporter, intersects == (idBefore != idAfter));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/third_party/skia/tests/Writer32Test.cpp b/src/third_party/skia/tests/Writer32Test.cpp
new file mode 100644
index 0000000..56cea2a
--- /dev/null
+++ b/src/third_party/skia/tests/Writer32Test.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRandom.h"
+#include "SkReader32.h"
+#include "SkWriter32.h"
+#include "Test.h"
+
+static void check_contents(skiatest::Reporter* reporter, const SkWriter32& writer,
+ const void* expected, size_t size) {
+ SkAutoSMalloc<256> storage(size);
+ REPORTER_ASSERT(reporter, writer.bytesWritten() == size);
+ writer.flatten(storage.get());
+ REPORTER_ASSERT(reporter, !memcmp(storage.get(), expected, size));
+}
+
+
+static void test_reserve(skiatest::Reporter* reporter) {
+ // There used to be a bug where we'd assert your first reservation had to
+ // fit in external storage if you used it. This would crash in debug mode.
+ uint8_t storage[4];
+ SkWriter32 writer(storage, sizeof(storage));
+ writer.reserve(40);
+}
+
+static void test_string_null(skiatest::Reporter* reporter) {
+ uint8_t storage[8];
+ SkWriter32 writer(storage, sizeof(storage));
+
+ // Can we write NULL?
+ writer.writeString(NULL);
+ const int32_t expected[] = { 0x0, 0x0 };
+ check_contents(reporter, writer, expected, sizeof(expected));
+}
+
+static void test_rewind(skiatest::Reporter* reporter) {
+ SkSWriter32<32> writer;
+ int32_t array[3] = { 1, 2, 4 };
+
+ REPORTER_ASSERT(reporter, 0 == writer.bytesWritten());
+ for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
+ writer.writeInt(array[i]);
+ }
+ check_contents(reporter, writer, array, sizeof(array));
+
+ writer.rewindToOffset(2*sizeof(int32_t));
+ REPORTER_ASSERT(reporter, sizeof(array) - 4 == writer.bytesWritten());
+ writer.writeInt(3);
+ REPORTER_ASSERT(reporter, sizeof(array) == writer.bytesWritten());
+ array[2] = 3;
+ check_contents(reporter, writer, array, sizeof(array));
+
+ // test rewinding past allocated chunks. This used to crash because we
+ // didn't truncate our link-list after freeing trailing blocks
+ {
+ SkWriter32 writer;
+ for (int i = 0; i < 100; ++i) {
+ writer.writeInt(i);
+ }
+ REPORTER_ASSERT(reporter, 100*4 == writer.bytesWritten());
+ for (int j = 100*4; j >= 0; j -= 16) {
+ writer.rewindToOffset(j);
+ }
+ REPORTER_ASSERT(reporter, writer.bytesWritten() < 16);
+ }
+}
+
+static void test_ptr(skiatest::Reporter* reporter) {
+ SkSWriter32<32> writer;
+
+ void* p0 = reporter;
+ void* p1 = &writer;
+
+ // try writing ptrs where at least one of them may be at a non-multiple of
+ // 8 boundary, to confirm this works on 64bit machines.
+
+ writer.writePtr(p0);
+ writer.write8(0x33);
+ writer.writePtr(p1);
+ writer.write8(0x66);
+
+ size_t size = writer.bytesWritten();
+ REPORTER_ASSERT(reporter, 2 * sizeof(void*) + 2 * sizeof(int32_t));
+
+ char buffer[32];
+ SkASSERT(sizeof(buffer) >= size);
+ writer.flatten(buffer);
+
+ SkReader32 reader(buffer, size);
+ REPORTER_ASSERT(reporter, reader.readPtr() == p0);
+ REPORTER_ASSERT(reporter, reader.readInt() == 0x33);
+ REPORTER_ASSERT(reporter, reader.readPtr() == p1);
+ REPORTER_ASSERT(reporter, reader.readInt() == 0x66);
+}
+
+static void test1(skiatest::Reporter* reporter, SkWriter32* writer) {
+ const uint32_t data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(data); ++i) {
+ REPORTER_ASSERT(reporter, i*4 == writer->bytesWritten());
+ writer->write32(data[i]);
+ REPORTER_ASSERT(reporter, data[i] == writer->readTAt<uint32_t>(i * 4));
+ }
+
+ char buffer[sizeof(data)];
+ REPORTER_ASSERT(reporter, sizeof(buffer) == writer->bytesWritten());
+ writer->flatten(buffer);
+ REPORTER_ASSERT(reporter, !memcmp(data, buffer, sizeof(buffer)));
+}
+
+static void test2(skiatest::Reporter* reporter, SkWriter32* writer) {
+ static const char gStr[] = "abcdefghimjklmnopqrstuvwxyz";
+ size_t i;
+
+ size_t len = 0;
+ for (i = 0; i <= 26; ++i) {
+ len += SkWriter32::WriteStringSize(gStr, i);
+ writer->writeString(gStr, i);
+ }
+ REPORTER_ASSERT(reporter, writer->bytesWritten() == len);
+
+ SkAutoMalloc storage(len);
+ writer->flatten(storage.get());
+
+ SkReader32 reader;
+ reader.setMemory(storage.get(), len);
+ for (i = 0; i <= 26; ++i) {
+ REPORTER_ASSERT(reporter, !reader.eof());
+ const char* str = reader.readString(&len);
+ REPORTER_ASSERT(reporter, i == len);
+ REPORTER_ASSERT(reporter, strlen(str) == len);
+ REPORTER_ASSERT(reporter, !memcmp(str, gStr, len));
+ // Ensure that the align4 of the string is padded with zeroes.
+ size_t alignedSize = SkAlign4(len + 1);
+ for (size_t j = len; j < alignedSize; j++) {
+ REPORTER_ASSERT(reporter, 0 == str[j]);
+ }
+ }
+ REPORTER_ASSERT(reporter, reader.eof());
+}
+
+static void testWritePad(skiatest::Reporter* reporter, SkWriter32* writer) {
+ // Create some random data to write.
+ const size_t dataSize = 10<<2;
+ SkASSERT(SkIsAlign4(dataSize));
+
+ SkAutoMalloc originalData(dataSize);
+ {
+ SkRandom rand(0);
+ uint32_t* ptr = static_cast<uint32_t*>(originalData.get());
+ uint32_t* stop = ptr + (dataSize>>2);
+ while (ptr < stop) {
+ *ptr++ = rand.nextU();
+ }
+
+ // Write the random data to the writer at different lengths for
+ // different alignments.
+ for (size_t len = 0; len < dataSize; len++) {
+ writer->writePad(originalData.get(), len);
+ }
+ }
+
+ uint32_t totalBytes = writer->bytesWritten();
+
+ SkAutoMalloc readStorage(totalBytes);
+ writer->flatten(readStorage.get());
+
+ SkReader32 reader;
+ reader.setMemory(readStorage.get(), totalBytes);
+
+ for (size_t len = 0; len < dataSize; len++) {
+ const char* readPtr = static_cast<const char*>(reader.skip(len));
+ // Ensure that the data read is the same as what was written.
+ REPORTER_ASSERT(reporter, memcmp(readPtr, originalData.get(), len) == 0);
+ // Ensure that the rest is padded with zeroes.
+ const char* stop = readPtr + SkAlign4(len);
+ readPtr += len;
+ while (readPtr < stop) {
+ REPORTER_ASSERT(reporter, *readPtr++ == 0);
+ }
+ }
+}
+
+static void testOverwriteT(skiatest::Reporter* reporter, SkWriter32* writer) {
+ const size_t padding = 64;
+
+ const uint32_t uint1 = 0x12345678;
+ const uint32_t uint2 = 0x98765432;
+ const SkScalar scalar1 = 1234.5678f;
+ const SkScalar scalar2 = 9876.5432f;
+ const SkRect rect1 = SkRect::MakeXYWH(1, 2, 3, 4);
+ const SkRect rect2 = SkRect::MakeXYWH(5, 6, 7, 8);
+
+ for (size_t i = 0; i < (padding / 4); ++i) {
+ writer->write32(0);
+ }
+
+ writer->write32(uint1);
+ writer->writeRect(rect1);
+ writer->writeScalar(scalar1);
+
+ for (size_t i = 0; i < (padding / 4); ++i) {
+ writer->write32(0);
+ }
+
+ REPORTER_ASSERT(reporter, writer->readTAt<uint32_t>(padding) == uint1);
+ REPORTER_ASSERT(reporter, writer->readTAt<SkRect>(padding + sizeof(uint32_t)) == rect1);
+ REPORTER_ASSERT(reporter, writer->readTAt<SkScalar>(
+ padding + sizeof(uint32_t) + sizeof(SkRect)) == scalar1);
+
+ writer->overwriteTAt(padding, uint2);
+ writer->overwriteTAt(padding + sizeof(uint32_t), rect2);
+ writer->overwriteTAt(padding + sizeof(uint32_t) + sizeof(SkRect), scalar2);
+
+ REPORTER_ASSERT(reporter, writer->readTAt<uint32_t>(padding) == uint2);
+ REPORTER_ASSERT(reporter, writer->readTAt<SkRect>(padding + sizeof(uint32_t)) == rect2);
+ REPORTER_ASSERT(reporter, writer->readTAt<SkScalar>(
+ padding + sizeof(uint32_t) + sizeof(SkRect)) == scalar2);
+}
+
+DEF_TEST(Writer32_dynamic, reporter) {
+ SkWriter32 writer;
+ test1(reporter, &writer);
+
+ writer.reset();
+ test2(reporter, &writer);
+
+ writer.reset();
+ testWritePad(reporter, &writer);
+
+ writer.reset();
+ testOverwriteT(reporter, &writer);
+}
+
+DEF_TEST(Writer32_contiguous, reporter) {
+ uint32_t storage[256];
+ SkWriter32 writer;
+ writer.reset(storage, sizeof(storage));
+ // This write is small enough to fit in storage, so it's contiguous.
+ test1(reporter, &writer);
+ REPORTER_ASSERT(reporter, writer.contiguousArray() != NULL);
+
+ // Everything other aspect of contiguous/non-contiguous is an
+ // implementation detail, not part of the public contract for
+ // SkWriter32, and so not tested here.
+}
+
+DEF_TEST(Writer32_small, reporter) {
+ SkSWriter32<8 * sizeof(intptr_t)> writer;
+ test1(reporter, &writer);
+ writer.reset(); // should just rewind our storage
+ test2(reporter, &writer);
+
+ writer.reset();
+ testWritePad(reporter, &writer);
+
+ writer.reset();
+ testOverwriteT(reporter, &writer);
+}
+
+DEF_TEST(Writer32_large, reporter) {
+ SkSWriter32<1024 * sizeof(intptr_t)> writer;
+ test1(reporter, &writer);
+ writer.reset(); // should just rewind our storage
+ test2(reporter, &writer);
+
+ writer.reset();
+ testWritePad(reporter, &writer);
+
+ writer.reset();
+ testOverwriteT(reporter, &writer);
+}
+
+DEF_TEST(Writer32_misc, reporter) {
+ test_reserve(reporter);
+ test_string_null(reporter);
+ test_ptr(reporter);
+ test_rewind(reporter);
+}
+
+DEF_TEST(Writer32_snapshot, reporter) {
+ int32_t array[] = { 1, 2, 4, 11 };
+ SkSWriter32<sizeof(array) + 4> writer;
+ writer.write(array, sizeof(array));
+ check_contents(reporter, writer, array, sizeof(array));
+ const void* beforeData = writer.contiguousArray();
+ SkAutoDataUnref snapshot(writer.snapshotAsData());
+ // check the snapshot forced a copy of the static data
+ REPORTER_ASSERT(reporter, snapshot->data() != beforeData);
+ REPORTER_ASSERT(reporter, snapshot->size() == writer.bytesWritten());
+}
+
+DEF_TEST(Writer32_snapshot_dynamic, reporter) {
+ int32_t array[] = { 1, 2, 4, 11 };
+ SkWriter32 writer;
+ writer.write(array, sizeof(array));
+ check_contents(reporter, writer, array, sizeof(array));
+ // force a capacity increase so we can test COW behaviour
+ writer.write(array, sizeof(array));
+ writer.rewindToOffset(sizeof(array));
+ const void* beforeData = writer.contiguousArray();
+ SkAutoDataUnref snapshot(writer.snapshotAsData());
+ // check the snapshot still points to the same data as the writer
+ REPORTER_ASSERT(reporter, writer.contiguousArray() == beforeData);
+ REPORTER_ASSERT(reporter, snapshot->data() == beforeData);
+ REPORTER_ASSERT(reporter, snapshot->size() == writer.bytesWritten());
+ // write more data that would fit in the buffer
+ writer.write(array, sizeof(array));
+ // test it triggered COW anyway
+ REPORTER_ASSERT(reporter, writer.contiguousArray() != beforeData);
+}
diff --git a/src/third_party/skia/tests/XfermodeTest.cpp b/src/third_party/skia/tests/XfermodeTest.cpp
new file mode 100644
index 0000000..34f5233
--- /dev/null
+++ b/src/third_party/skia/tests/XfermodeTest.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkColor.h"
+#include "SkXfermode.h"
+#include "Test.h"
+
+#define ILLEGAL_MODE ((SkXfermode::Mode)-1)
+
+static void test_asMode(skiatest::Reporter* reporter) {
+ for (int mode = 0; mode <= SkXfermode::kLastMode; mode++) {
+ SkXfermode* xfer = SkXfermode::Create((SkXfermode::Mode) mode);
+
+ SkXfermode::Mode reportedMode = ILLEGAL_MODE;
+ REPORTER_ASSERT(reporter, reportedMode != mode);
+
+ // test IsMode
+ REPORTER_ASSERT(reporter, SkXfermode::AsMode(xfer, &reportedMode));
+ REPORTER_ASSERT(reporter, reportedMode == mode);
+
+ // repeat that test, but with asMode instead
+ if (xfer) {
+ reportedMode = (SkXfermode::Mode) -1;
+ REPORTER_ASSERT(reporter, xfer->asMode(&reportedMode));
+ REPORTER_ASSERT(reporter, reportedMode == mode);
+ xfer->unref();
+ } else {
+ REPORTER_ASSERT(reporter, SkXfermode::kSrcOver_Mode == mode);
+ }
+ }
+}
+
+static void test_IsMode(skiatest::Reporter* reporter) {
+ REPORTER_ASSERT(reporter, SkXfermode::IsMode(NULL,
+ SkXfermode::kSrcOver_Mode));
+
+ for (int i = 0; i <= SkXfermode::kLastMode; ++i) {
+ SkXfermode::Mode mode = (SkXfermode::Mode)i;
+
+ SkXfermode* xfer = SkXfermode::Create(mode);
+ REPORTER_ASSERT(reporter, SkXfermode::IsMode(xfer, mode));
+ SkSafeUnref(xfer);
+
+ if (SkXfermode::kSrcOver_Mode != mode) {
+ REPORTER_ASSERT(reporter, !SkXfermode::IsMode(NULL, mode));
+ }
+ }
+}
+
+DEF_TEST(Xfermode, reporter) {
+ test_asMode(reporter);
+ test_IsMode(reporter);
+}
diff --git a/src/third_party/skia/tests/skia_test.cpp b/src/third_party/skia/tests/skia_test.cpp
new file mode 100644
index 0000000..0058215
--- /dev/null
+++ b/src/third_party/skia/tests/skia_test.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "CrashHandler.h"
+#include "OverwriteLine.h"
+#include "Resources.h"
+#include "SkCommonFlags.h"
+#include "SkGraphics.h"
+#include "SkOSFile.h"
+#include "SkTArray.h"
+#include "SkTaskGroup.h"
+#include "SkTemplates.h"
+#include "SkTime.h"
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContext.h"
+#include "GrContextFactory.h"
+#endif
+
+using namespace skiatest;
+
+DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
+
+// need to explicitly declare this, or we get some weird infinite loop llist
+template TestRegistry* TestRegistry::gHead;
+
+class Iter {
+public:
+ Iter() { this->reset(); }
+ void reset() { fReg = TestRegistry::Head(); }
+
+ Test* next(Reporter* r) {
+ if (fReg) {
+ TestRegistry::Factory fact = fReg->factory();
+ fReg = fReg->next();
+ Test* test = fact(NULL);
+ test->setReporter(r);
+ return test;
+ }
+ return NULL;
+ }
+
+private:
+ const TestRegistry* fReg;
+};
+
+class DebugfReporter : public Reporter {
+public:
+ explicit DebugfReporter(int total) : fDone(0), fTotal(total) {}
+
+ virtual bool allowExtendedTest() const SK_OVERRIDE { return FLAGS_extendedTest; }
+ virtual bool verbose() const SK_OVERRIDE { return FLAGS_veryVerbose; }
+
+protected:
+ virtual void onReportFailed(const SkString& desc) SK_OVERRIDE {
+ SkDebugf("\nFAILED: %s", desc.c_str());
+ }
+
+ virtual void onEnd(Test* test) SK_OVERRIDE {
+ const int done = 1 + sk_atomic_inc(&fDone);
+
+ if (!test->passed()) {
+ SkDebugf("\n---- %s FAILED", test->getName());
+ }
+
+ SkString prefix(kSkOverwriteLine);
+ SkString time;
+ if (FLAGS_verbose) {
+ prefix.printf("\n");
+ time.printf("%5dms ", test->elapsedMs());
+ }
+ SkDebugf("%s[%3d/%3d] %s%s", prefix.c_str(), done, fTotal, time.c_str(), test->getName());
+ }
+
+private:
+ int32_t fDone; // atomic
+ const int fTotal;
+};
+
+// Deletes self when run.
+class SkTestRunnable : public SkRunnable {
+public:
+ // Takes ownership of test.
+ SkTestRunnable(Test* test, int32_t* failCount) : fTest(test), fFailCount(failCount) {}
+
+ virtual void run() {
+ fTest->run();
+ if(!fTest->passed()) {
+ sk_atomic_inc(fFailCount);
+ }
+ SkDELETE(this);
+ }
+
+private:
+ SkAutoTDelete<Test> fTest;
+ int32_t* fFailCount;
+};
+
+static bool should_run(const char* testName, bool isGPUTest) {
+ if (SkCommandLineFlags::ShouldSkip(FLAGS_match, testName)) {
+ return false;
+ }
+ if (!FLAGS_cpu && !isGPUTest) {
+ return false;
+ }
+ if (!FLAGS_gpu && isGPUTest) {
+ return false;
+ }
+ return true;
+}
+
+int test_main();
+int test_main() {
+ SetupCrashHandler();
+
+#if SK_ENABLE_INST_COUNT
+ if (FLAGS_leaks) {
+ gPrintInstCount = true;
+ }
+#endif
+
+ SkGraphics::Init();
+
+ {
+ SkString header("Skia UnitTests:");
+ if (!FLAGS_match.isEmpty()) {
+ header.appendf(" --match");
+ for (int index = 0; index < FLAGS_match.count(); ++index) {
+ header.appendf(" %s", FLAGS_match[index]);
+ }
+ }
+ SkString tmpDir = Test::GetTmpDir();
+ if (!tmpDir.isEmpty()) {
+ header.appendf(" --tmpDir %s", tmpDir.c_str());
+ }
+ SkString resourcePath = GetResourcePath();
+ if (!resourcePath.isEmpty()) {
+ header.appendf(" --resourcePath %s", resourcePath.c_str());
+ }
+#ifdef SK_DEBUG
+ header.append(" SK_DEBUG");
+#else
+ header.append(" SK_RELEASE");
+#endif
+ header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8);
+ if (FLAGS_veryVerbose) {
+ header.appendf("\n");
+ }
+ SkDebugf(header.c_str());
+ }
+
+
+ // Count tests first.
+ int total = 0;
+ int toRun = 0;
+ Test* test;
+
+ Iter iter;
+ while ((test = iter.next(NULL/*reporter not needed*/)) != NULL) {
+ SkAutoTDelete<Test> owned(test);
+ if (should_run(test->getName(), test->isGPUTest())) {
+ toRun++;
+ }
+ total++;
+ }
+
+ // Now run them.
+ iter.reset();
+ int32_t failCount = 0;
+ int skipCount = 0;
+
+ SkTaskGroup::Enabler enabled(FLAGS_threads);
+ SkTaskGroup cpuTests;
+ SkTArray<Test*> gpuTests; // Always passes ownership to an SkTestRunnable
+
+ DebugfReporter reporter(toRun);
+ for (int i = 0; i < total; i++) {
+ SkAutoTDelete<Test> test(iter.next(&reporter));
+ if (!should_run(test->getName(), test->isGPUTest())) {
+ ++skipCount;
+ } else if (test->isGPUTest()) {
+ gpuTests.push_back() = test.detach();
+ } else {
+ cpuTests.add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
+ }
+ }
+
+#if SK_SUPPORT_GPU
+ // Give GPU tests a context factory if that makes sense on this machine.
+ GrContextFactory grContextFactory;
+ for (int i = 0; i < gpuTests.count(); i++) {
+ gpuTests[i]->setGrContextFactory(&grContextFactory);
+ }
+#endif
+
+ // Run GPU tests on this thread.
+ for (int i = 0; i < gpuTests.count(); i++) {
+ SkNEW_ARGS(SkTestRunnable, (gpuTests[i], &failCount))->run();
+ }
+
+ // Block until threaded tests finish.
+ cpuTests.wait();
+
+ if (FLAGS_verbose) {
+ SkDebugf("\nFinished %d tests, %d failures, %d skipped. (%d internal tests)",
+ toRun, failCount, skipCount, reporter.countTests());
+ }
+ SkGraphics::Term();
+
+ SkDebugf("\n");
+ return (failCount == 0) ? 0 : 1;
+}
+
+#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
+int main(int argc, char** argv) {
+ SkCommandLineFlags::Parse(argc, argv);
+ return test_main();
+}
+#endif