1 /* 2 * Copyright 2015 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 8 #include "GrStrokeInfo.h" 9 #include "GrTestUtils.h" 10 #include "SkMatrix.h" 11 #include "SkPathEffect.h" 12 #include "SkPath.h" 13 #include "SkRRect.h" 14 15 #ifdef GR_TEST_UTILS 16 17 static const SkMatrix& test_matrix(SkRandom* random, bool includePerspective) { 18 static SkMatrix gMatrices[5]; 19 static const int kPerspectiveCount = 1; 20 static bool gOnce; 21 if (!gOnce) { 22 gOnce = true; 23 gMatrices[0].reset(); 24 gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100)); 25 gMatrices[2].setRotate(SkIntToScalar(17)); 26 gMatrices[3].setRotate(SkIntToScalar(185)); 27 gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33)); 28 gMatrices[3].postScale(SkIntToScalar(2), SK_ScalarHalf); 29 30 // Perspective matrices 31 gMatrices[4].setRotate(SkIntToScalar(215)); 32 gMatrices[4].set(SkMatrix::kMPersp0, 0.00013f); 33 gMatrices[4].set(SkMatrix::kMPersp1, -0.000039f); 34 } 35 36 uint32_t count = static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices)); 37 if (includePerspective) { 38 return gMatrices[random->nextULessThan(count)]; 39 } else { 40 return gMatrices[random->nextULessThan(count - kPerspectiveCount)]; 41 } 42 } 43 44 namespace GrTest { 45 const SkMatrix& TestMatrix(SkRandom* random) { return test_matrix(random, true); } 46 47 const SkMatrix& TestMatrixPreservesRightAngles(SkRandom* random) { 48 static SkMatrix gMatrices[5]; 49 static bool gOnce; 50 if (!gOnce) { 51 gOnce = true; 52 // identity 53 gMatrices[0].reset(); 54 // translation 55 gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100)); 56 // scale 57 gMatrices[2].setScale(SkIntToScalar(17), SkIntToScalar(17)); 58 // scale + translation 59 gMatrices[3].setScale(SkIntToScalar(-17), SkIntToScalar(-17)); 60 gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33)); 61 // orthogonal basis vectors 62 gMatrices[4].reset(); 63 gMatrices[4].setScale(SkIntToScalar(-1), SkIntToScalar(-1)); 64 gMatrices[4].setRotate(47); 65 66 for (size_t i = 0; i < SK_ARRAY_COUNT(gMatrices); i++) { 67 SkASSERT(gMatrices[i].preservesRightAngles()); 68 } 69 } 70 return gMatrices[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices)))]; 71 } 72 73 const SkMatrix& TestMatrixRectStaysRect(SkRandom* random) { 74 static SkMatrix gMatrices[6]; 75 static bool gOnce; 76 if (!gOnce) { 77 gOnce = true; 78 // identity 79 gMatrices[0].reset(); 80 // translation 81 gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100)); 82 // scale 83 gMatrices[2].setScale(SkIntToScalar(17), SkIntToScalar(17)); 84 // scale + translation 85 gMatrices[3].setScale(SkIntToScalar(-17), SkIntToScalar(-17)); 86 gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33)); 87 // reflection 88 gMatrices[4].setScale(SkIntToScalar(-1), SkIntToScalar(-1)); 89 // 90 degress rotation 90 gMatrices[5].setRotate(90); 91 92 for (size_t i = 0; i < SK_ARRAY_COUNT(gMatrices); i++) { 93 SkASSERT(gMatrices[i].rectStaysRect()); 94 } 95 } 96 return gMatrices[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices)))]; 97 } 98 99 const SkMatrix& TestMatrixInvertible(SkRandom* random) { return test_matrix(random, false); } 100 101 const SkRect& TestRect(SkRandom* random) { 102 static SkRect gRects[7]; 103 static bool gOnce; 104 if (!gOnce) { 105 gOnce = true; 106 gRects[0] = SkRect::MakeWH(1.f, 1.f); 107 gRects[1] = SkRect::MakeWH(1.0f, 256.0f); 108 gRects[2] = SkRect::MakeWH(256.0f, 1.0f); 109 gRects[3] = SkRect::MakeLargest(); 110 gRects[4] = SkRect::MakeLTRB(-65535.0f, -65535.0f, 65535.0f, 65535.0f); 111 gRects[5] = SkRect::MakeLTRB(-10.0f, -10.0f, 10.0f, 10.0f); 112 } 113 return gRects[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gRects)))]; 114 } 115 116 // Just some simple rects for code which expects its input very sanitized 117 const SkRect& TestSquare(SkRandom* random) { 118 static SkRect gRects[2]; 119 static bool gOnce; 120 if (!gOnce) { 121 gOnce = true; 122 gRects[0] = SkRect::MakeWH(128.f, 128.f); 123 gRects[1] = SkRect::MakeWH(256.0f, 256.0f); 124 } 125 return gRects[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gRects)))]; 126 } 127 128 const SkRRect& TestRRectSimple(SkRandom* random) { 129 static SkRRect gRRect[2]; 130 static bool gOnce; 131 if (!gOnce) { 132 gOnce = true; 133 SkRect rectangle = SkRect::MakeWH(10.f, 20.f); 134 // true round rect with circular corners 135 gRRect[0].setRectXY(rectangle, 1.f, 1.f); 136 // true round rect with elliptical corners 137 gRRect[1].setRectXY(rectangle, 2.0f, 1.0f); 138 139 for (size_t i = 0; i < SK_ARRAY_COUNT(gRRect); i++) { 140 SkASSERT(gRRect[i].isSimple()); 141 } 142 } 143 return gRRect[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gRRect)))]; 144 } 145 146 const SkPath& TestPath(SkRandom* random) { 147 static SkPath gPath[7]; 148 static bool gOnce; 149 if (!gOnce) { 150 gOnce = true; 151 // line 152 gPath[0].moveTo(0.f, 0.f); 153 gPath[0].lineTo(10.f, 10.f); 154 // quad 155 gPath[1].moveTo(0.f, 0.f); 156 gPath[1].quadTo(10.f, 10.f, 20.f, 20.f); 157 // conic 158 gPath[2].moveTo(0.f, 0.f); 159 gPath[2].conicTo(10.f, 10.f, 20.f, 20.f, 1.f); 160 // cubic 161 gPath[3].moveTo(0.f, 0.f); 162 gPath[3].cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f); 163 // all three 164 gPath[4].moveTo(0.f, 0.f); 165 gPath[4].lineTo(10.f, 10.f); 166 gPath[4].quadTo(10.f, 10.f, 20.f, 20.f); 167 gPath[4].conicTo(10.f, 10.f, 20.f, 20.f, 1.f); 168 gPath[4].cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f); 169 // convex 170 gPath[5].moveTo(0.0f, 0.0f); 171 gPath[5].lineTo(10.0f, 0.0f); 172 gPath[5].lineTo(10.0f, 10.0f); 173 gPath[5].lineTo(0.0f, 10.0f); 174 gPath[5].close(); 175 // concave 176 gPath[6].moveTo(0.0f, 0.0f); 177 gPath[6].lineTo(5.0f, 5.0f); 178 gPath[6].lineTo(10.0f, 0.0f); 179 gPath[6].lineTo(10.0f, 10.0f); 180 gPath[6].lineTo(0.0f, 10.0f); 181 gPath[6].close(); 182 } 183 184 return gPath[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gPath)))]; 185 } 186 187 const SkPath& TestPathConvex(SkRandom* random) { 188 static SkPath gPath[3]; 189 static bool gOnce; 190 if (!gOnce) { 191 gOnce = true; 192 // narrow rect 193 gPath[0].moveTo(-1.5f, -50.0f); 194 gPath[0].lineTo(-1.5f, -50.0f); 195 gPath[0].lineTo( 1.5f, -50.0f); 196 gPath[0].lineTo( 1.5f, 50.0f); 197 gPath[0].lineTo(-1.5f, 50.0f); 198 // degenerate 199 gPath[1].moveTo(-0.025f, -0.025f); 200 gPath[1].lineTo(-0.025f, -0.025f); 201 gPath[1].lineTo( 0.025f, -0.025f); 202 gPath[1].lineTo( 0.025f, 0.025f); 203 gPath[1].lineTo(-0.025f, 0.025f); 204 // clipped triangle 205 gPath[2].moveTo(-10.0f, -50.0f); 206 gPath[2].lineTo(-10.0f, -50.0f); 207 gPath[2].lineTo( 10.0f, -50.0f); 208 gPath[2].lineTo( 50.0f, 31.0f); 209 gPath[2].lineTo( 40.0f, 50.0f); 210 gPath[2].lineTo(-40.0f, 50.0f); 211 gPath[2].lineTo(-50.0f, 31.0f); 212 213 for (size_t i = 0; i < SK_ARRAY_COUNT(gPath); i++) { 214 SkASSERT(SkPath::kConvex_Convexity == gPath[i].getConvexity()); 215 } 216 } 217 218 return gPath[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gPath)))]; 219 } 220 221 static void randomize_stroke_rec(SkStrokeRec* rec, SkRandom* random) { 222 bool strokeAndFill = random->nextBool(); 223 SkScalar strokeWidth = random->nextBool() ? 0.f : 1.f; 224 rec->setStrokeStyle(strokeWidth, strokeAndFill); 225 226 SkPaint::Cap cap = SkPaint::Cap(random->nextULessThan(SkPaint::kCapCount)); 227 SkPaint::Join join = SkPaint::Join(random->nextULessThan(SkPaint::kJoinCount)); 228 SkScalar miterLimit = random->nextRangeScalar(1.f, 5.f); 229 rec->setStrokeParams(cap, join, miterLimit); 230 } 231 232 SkStrokeRec TestStrokeRec(SkRandom* random) { 233 SkStrokeRec::InitStyle style = 234 SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1)); 235 SkStrokeRec rec(style); 236 randomize_stroke_rec(&rec, random); 237 return rec; 238 } 239 240 GrStrokeInfo TestStrokeInfo(SkRandom* random) { 241 SkStrokeRec::InitStyle style = 242 SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1)); 243 GrStrokeInfo strokeInfo(style); 244 randomize_stroke_rec(&strokeInfo, random); 245 SkPathEffect::DashInfo dashInfo; 246 dashInfo.fCount = random->nextRangeU(1, 50) * 2; 247 dashInfo.fIntervals = new SkScalar[dashInfo.fCount]; 248 SkScalar sum = 0; 249 for (int i = 0; i < dashInfo.fCount; i++) { 250 dashInfo.fIntervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01), 251 SkDoubleToScalar(10.0)); 252 sum += dashInfo.fIntervals[i]; 253 } 254 dashInfo.fPhase = random->nextRangeScalar(0, sum); 255 strokeInfo.setDashInfo(dashInfo); 256 delete[] dashInfo.fIntervals; 257 return strokeInfo; 258 } 259 260 }; 261 262 #endif 263