1/* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7#include "PathOpsExtendedTest.h" 8#include "PathOpsThreadedCommon.h" 9#include "SkCanvas.h" 10#include "SkRandom.h" 11#include "SkTSort.h" 12#include "Test.h" 13 14static void testTightBoundsLines(PathOpsThreadState* data) { 15 SkRandom ran; 16 for (int index = 0; index < 1000; ++index) { 17 SkPath path; 18 int contourCount = ran.nextRangeU(1, 10); 19 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 20 int lineCount = ran.nextRangeU(1, 10); 21 path.moveTo(ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)); 22 for (int lIndex = 0; lIndex < lineCount; ++lIndex) { 23 path.lineTo(ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000)); 24 } 25 if (ran.nextBool()) { 26 path.close(); 27 } 28 } 29 SkRect classicBounds = path.getBounds(); 30 SkRect tightBounds; 31 REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds)); 32 REPORTER_ASSERT(data->fReporter, classicBounds == tightBounds); 33 } 34} 35 36DEF_TEST(PathOpsTightBoundsLines, reporter) { 37 initializeTests(reporter, "tightBoundsLines"); 38 PathOpsThreadedTestRunner testRunner(reporter); 39 int outerCount = reporter->allowExtendedTest() ? 100 : 1; 40 for (int index = 0; index < outerCount; ++index) { 41 for (int idx2 = 0; idx2 < 10; ++idx2) { 42 *testRunner.fRunnables.append() = 43 new PathOpsThreadedRunnable(&testTightBoundsLines, 0, 0, 0, 0, &testRunner); 44 } 45 } 46 testRunner.render(); 47} 48 49static void testTightBoundsQuads(PathOpsThreadState* data) { 50 SkRandom ran; 51 const int bitWidth = 32; 52 const int bitHeight = 32; 53 const float pathMin = 1; 54 const float pathMax = (float) (bitHeight - 2); 55 SkBitmap& bits = *data->fBitmap; 56 if (bits.width() == 0) { 57 bits.allocN32Pixels(bitWidth, bitHeight); 58 } 59 SkCanvas canvas(bits); 60 SkPaint paint; 61 for (int index = 0; index < 100; ++index) { 62 SkPath path; 63 int contourCount = ran.nextRangeU(1, 10); 64 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 65 int lineCount = ran.nextRangeU(1, 10); 66 path.moveTo(ran.nextRangeF(1, pathMax), ran.nextRangeF(pathMin, pathMax)); 67 for (int lIndex = 0; lIndex < lineCount; ++lIndex) { 68 if (ran.nextBool()) { 69 path.lineTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax)); 70 } else { 71 path.quadTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax), 72 ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax)); 73 } 74 } 75 if (ran.nextBool()) { 76 path.close(); 77 } 78 } 79 SkRect classicBounds = path.getBounds(); 80 SkRect tightBounds; 81 REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds)); 82 REPORTER_ASSERT(data->fReporter, classicBounds.contains(tightBounds)); 83 canvas.drawColor(SK_ColorWHITE); 84 canvas.drawPath(path, paint); 85 SkIRect bitsWritten = {31, 31, 0, 0}; 86 for (int y = 0; y < bitHeight; ++y) { 87 uint32_t* addr1 = data->fBitmap->getAddr32(0, y); 88 bool lineWritten = false; 89 for (int x = 0; x < bitWidth; ++x) { 90 if (addr1[x] == (uint32_t) -1) { 91 continue; 92 } 93 lineWritten = true; 94 bitsWritten.fLeft = SkTMin(bitsWritten.fLeft, x); 95 bitsWritten.fRight = SkTMax(bitsWritten.fRight, x); 96 } 97 if (!lineWritten) { 98 continue; 99 } 100 bitsWritten.fTop = SkTMin(bitsWritten.fTop, y); 101 bitsWritten.fBottom = SkTMax(bitsWritten.fBottom, y); 102 } 103 if (!bitsWritten.isEmpty()) { 104 SkIRect tightOut; 105 tightBounds.roundOut(&tightOut); 106 REPORTER_ASSERT(data->fReporter, tightOut.contains(bitsWritten)); 107 } 108 } 109} 110 111DEF_TEST(PathOpsTightBoundsQuads, reporter) { 112 initializeTests(reporter, "tightBoundsQuads"); 113 PathOpsThreadedTestRunner testRunner(reporter); 114 int outerCount = reporter->allowExtendedTest() ? 100 : 1; 115 for (int index = 0; index < outerCount; ++index) { 116 for (int idx2 = 0; idx2 < 10; ++idx2) { 117 *testRunner.fRunnables.append() = 118 new PathOpsThreadedRunnable(&testTightBoundsQuads, 0, 0, 0, 0, &testRunner); 119 } 120 } 121 testRunner.render(); 122} 123 124DEF_TEST(PathOpsTightBoundsMove, reporter) { 125 SkPath path; 126 path.moveTo(10, 10); 127 path.close(); 128 path.moveTo(20, 20); 129 path.lineTo(20, 20); 130 path.close(); 131 path.moveTo(15, 15); 132 path.lineTo(15, 15); 133 path.close(); 134 const SkRect& bounds = path.getBounds(); 135 SkRect tight; 136 REPORTER_ASSERT(reporter, TightBounds(path, &tight)); 137 REPORTER_ASSERT(reporter, bounds == tight); 138} 139 140DEF_TEST(PathOpsTightBoundsMoveOne, reporter) { 141 SkPath path; 142 path.moveTo(20, 20); 143 const SkRect& bounds = path.getBounds(); 144 SkRect tight; 145 REPORTER_ASSERT(reporter, TightBounds(path, &tight)); 146 REPORTER_ASSERT(reporter, bounds == tight); 147} 148 149DEF_TEST(PathOpsTightBoundsMoveTwo, reporter) { 150 SkPath path; 151 path.moveTo(20, 20); 152 path.moveTo(40, 40); 153 const SkRect& bounds = path.getBounds(); 154 SkRect tight; 155 REPORTER_ASSERT(reporter, TightBounds(path, &tight)); 156 REPORTER_ASSERT(reporter, bounds == tight); 157} 158 159DEF_TEST(PathOpsTightBoundsTiny, reporter) { 160 SkPath path; 161 path.moveTo(1, 1); 162 path.quadTo(1.000001f, 1, 1, 1); 163 const SkRect& bounds = path.getBounds(); 164 SkRect tight; 165 REPORTER_ASSERT(reporter, TightBounds(path, &tight)); 166 SkRect moveBounds = {1, 1, 1, 1}; 167 REPORTER_ASSERT(reporter, bounds != tight); 168 REPORTER_ASSERT(reporter, moveBounds == tight); 169} 170 171DEF_TEST(PathOpsTightBoundsWellBehaved, reporter) { 172 SkPath path; 173 path.moveTo(1, 1); 174 path.quadTo(2, 3, 4, 5); 175 const SkRect& bounds = path.getBounds(); 176 SkRect tight; 177 REPORTER_ASSERT(reporter, TightBounds(path, &tight)); 178 REPORTER_ASSERT(reporter, bounds == tight); 179} 180 181DEF_TEST(PathOpsTightBoundsIllBehaved, reporter) { 182 SkPath path; 183 path.moveTo(1, 1); 184 path.quadTo(4, 3, 2, 2); 185 const SkRect& bounds = path.getBounds(); 186 SkRect tight; 187 REPORTER_ASSERT(reporter, TightBounds(path, &tight)); 188 REPORTER_ASSERT(reporter, bounds != tight); 189} 190 191DEF_TEST(PathOpsTightBoundsIllBehavedScaled, reporter) { 192 SkPath path; 193 path.moveTo(0, 0); 194 path.quadTo(1048578, 1048577, 1048576, 1048576); 195 const SkRect& bounds = path.getBounds(); 196 SkRect tight; 197 REPORTER_ASSERT(reporter, TightBounds(path, &tight)); 198 REPORTER_ASSERT(reporter, bounds != tight); 199 REPORTER_ASSERT(reporter, tight.right() == 1048576); 200 REPORTER_ASSERT(reporter, tight.bottom() == 1048576); 201} 202