1 /* 2 * Copyright 2011 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 "gm.h" 9 #include "SkPath.h" 10 11 typedef SkScalar (*MakePathProc)(SkPath*); 12 13 static SkScalar make_frame(SkPath* path) { 14 SkRect r = { SkIntToScalar(10), SkIntToScalar(10), 15 SkIntToScalar(630), SkIntToScalar(470) }; 16 path->addRoundRect(r, SkIntToScalar(15), SkIntToScalar(15)); 17 18 SkPaint paint; 19 paint.setStyle(SkPaint::kStroke_Style); 20 paint.setStrokeWidth(SkIntToScalar(5)); 21 paint.getFillPath(*path, path); 22 return SkIntToScalar(15); 23 } 24 25 static SkScalar make_triangle(SkPath* path) { 26 constexpr int gCoord[] = { 27 10, 20, 15, 5, 30, 30 28 }; 29 path->moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1])); 30 path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3])); 31 path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5])); 32 path->close(); 33 path->offset(SkIntToScalar(10), SkIntToScalar(0)); 34 return SkIntToScalar(30); 35 } 36 37 static SkScalar make_rect(SkPath* path) { 38 SkRect r = { SkIntToScalar(10), SkIntToScalar(10), 39 SkIntToScalar(30), SkIntToScalar(30) }; 40 path->addRect(r); 41 path->offset(SkIntToScalar(10), SkIntToScalar(0)); 42 return SkIntToScalar(30); 43 } 44 45 static SkScalar make_oval(SkPath* path) { 46 SkRect r = { SkIntToScalar(10), SkIntToScalar(10), 47 SkIntToScalar(30), SkIntToScalar(30) }; 48 path->addOval(r); 49 path->offset(SkIntToScalar(10), SkIntToScalar(0)); 50 return SkIntToScalar(30); 51 } 52 53 static SkScalar make_sawtooth(SkPath* path, int teeth) { 54 SkScalar x = SkIntToScalar(20); 55 SkScalar y = SkIntToScalar(20); 56 const SkScalar x0 = x; 57 const SkScalar dx = SkIntToScalar(5); 58 const SkScalar dy = SkIntToScalar(10); 59 60 path->moveTo(x, y); 61 for (int i = 0; i < teeth; i++) { 62 x += dx; 63 path->lineTo(x, y - dy); 64 x += dx; 65 path->lineTo(x, y + dy); 66 } 67 path->lineTo(x, y + (2 * dy)); 68 path->lineTo(x0, y + (2 * dy)); 69 path->close(); 70 return SkIntToScalar(30); 71 } 72 73 static SkScalar make_sawtooth_3(SkPath* path) { return make_sawtooth(path, 3); } 74 static SkScalar make_sawtooth_32(SkPath* path) { return make_sawtooth(path, 32); } 75 76 static SkScalar make_house(SkPath* path) { 77 path->moveTo(21, 23); 78 path->lineTo(21, 11.534f); 79 path->lineTo(22.327f, 12.741f); 80 path->lineTo(23.673f, 11.261f); 81 path->lineTo(12, 0.648f); 82 path->lineTo(8, 4.285f); 83 path->lineTo(8, 2); 84 path->lineTo(4, 2); 85 path->lineTo(4, 7.921f); 86 path->lineTo(0.327f, 11.26f); 87 path->lineTo(1.673f, 12.74f); 88 path->lineTo(3, 11.534f); 89 path->lineTo(3, 23); 90 path->lineTo(11, 23); 91 path->lineTo(11, 18); 92 path->lineTo(13, 18); 93 path->lineTo(13, 23); 94 path->lineTo(21, 23); 95 path->close(); 96 path->lineTo(9, 16); 97 path->lineTo(9, 21); 98 path->lineTo(5, 21); 99 path->lineTo(5, 9.715f); 100 path->lineTo(12, 3.351f); 101 path->lineTo(19, 9.715f); 102 path->lineTo(19, 21); 103 path->lineTo(15, 21); 104 path->lineTo(15, 16); 105 path->lineTo(9, 16); 106 path->close(); 107 path->offset(20, 0); 108 return SkIntToScalar(30); 109 } 110 111 static SkScalar make_star(SkPath* path, int n) { 112 const SkScalar c = SkIntToScalar(45); 113 const SkScalar r = SkIntToScalar(20); 114 115 SkScalar rad = -SK_ScalarPI / 2; 116 const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n; 117 118 path->moveTo(c, c - r); 119 for (int i = 1; i < n; i++) { 120 rad += drad; 121 SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV); 122 path->lineTo(c + cosV * r, c + sinV * r); 123 } 124 path->close(); 125 return r * 2 * 6 / 5; 126 } 127 128 static SkScalar make_star_5(SkPath* path) { return make_star(path, 5); } 129 static SkScalar make_star_13(SkPath* path) { return make_star(path, 13); } 130 131 // We don't expect any output from this path. 132 static SkScalar make_line(SkPath* path) { 133 path->moveTo(SkIntToScalar(30), SkIntToScalar(30)); 134 path->lineTo(SkIntToScalar(120), SkIntToScalar(40)); 135 path->close(); 136 path->moveTo(SkIntToScalar(150), SkIntToScalar(30)); 137 path->lineTo(SkIntToScalar(150), SkIntToScalar(30)); 138 path->lineTo(SkIntToScalar(300), SkIntToScalar(40)); 139 path->close(); 140 return SkIntToScalar(40); 141 } 142 143 static void make_info(SkPath* path) { 144 path->moveTo(24, 4); 145 path->cubicTo(12.94999980926514f, 146 4, 147 4, 148 12.94999980926514f, 149 4, 150 24); 151 path->cubicTo(4, 152 35.04999923706055f, 153 12.94999980926514f, 154 44, 155 24, 156 44); 157 path->cubicTo(35.04999923706055f, 158 44, 159 44, 160 35.04999923706055f, 161 44, 162 24); 163 path->cubicTo(44, 164 12.95000076293945f, 165 35.04999923706055f, 166 4, 167 24, 168 4); 169 path->close(); 170 path->moveTo(26, 34); 171 path->lineTo(22, 34); 172 path->lineTo(22, 22); 173 path->lineTo(26, 22); 174 path->lineTo(26, 34); 175 path->close(); 176 path->moveTo(26, 18); 177 path->lineTo(22, 18); 178 path->lineTo(22, 14); 179 path->lineTo(26, 14); 180 path->lineTo(26, 18); 181 path->close(); 182 } 183 184 static void make_accessibility(SkPath* path) { 185 path->moveTo(12, 2); 186 path->cubicTo(13.10000038146973f, 187 2, 188 14, 189 2.900000095367432f, 190 14, 191 4); 192 path->cubicTo(14, 193 5.099999904632568f, 194 13.10000038146973f, 195 6, 196 12, 197 6); 198 path->cubicTo(10.89999961853027f, 199 6, 200 10, 201 5.099999904632568f, 202 10, 203 4); 204 path->cubicTo(10, 205 2.900000095367432f, 206 10.89999961853027f, 207 2, 208 12, 209 2); 210 path->close(); 211 path->moveTo(21, 9); 212 path->lineTo(15, 9); 213 path->lineTo(15, 22); 214 path->lineTo(13, 22); 215 path->lineTo(13, 16); 216 path->lineTo(11, 16); 217 path->lineTo(11, 22); 218 path->lineTo(9, 22); 219 path->lineTo(9, 9); 220 path->lineTo(3, 9); 221 path->lineTo(3, 7); 222 path->lineTo(21, 7); 223 path->lineTo(21, 9); 224 path->close(); 225 } 226 227 // test case for http://crbug.com/695196 228 static void make_visualizer(SkPath* path) { 229 path->moveTo(1.9520f, 2.0000f); 230 path->conicTo(1.5573f, 1.9992f, 1.2782f, 2.2782f, 0.9235f); 231 path->conicTo(0.9992f, 2.5573f, 1.0000f, 2.9520f, 0.9235f); 232 path->lineTo(1.0000f, 5.4300f); 233 path->lineTo(17.0000f, 5.4300f); 234 path->lineTo(17.0000f, 2.9520f); 235 path->conicTo(17.0008f, 2.5573f, 16.7218f, 2.2782f, 0.9235f); 236 path->conicTo(16.4427f, 1.9992f, 16.0480f, 2.0000f, 0.9235f); 237 path->lineTo(1.9520f, 2.0000f); 238 path->close(); 239 path->moveTo(2.7140f, 3.1430f); 240 path->conicTo(3.0547f, 3.1287f, 3.2292f, 3.4216f, 0.8590f); 241 path->conicTo(3.4038f, 3.7145f, 3.2292f, 4.0074f, 0.8590f); 242 path->conicTo(3.0547f, 4.3003f, 2.7140f, 4.2860f, 0.8590f); 243 path->conicTo(2.1659f, 4.2631f, 2.1659f, 3.7145f, 0.7217f); 244 path->conicTo(2.1659f, 3.1659f, 2.7140f, 3.1430f, 0.7217f); 245 path->lineTo(2.7140f, 3.1430f); 246 path->close(); 247 path->moveTo(5.0000f, 3.1430f); 248 path->conicTo(5.3407f, 3.1287f, 5.5152f, 3.4216f, 0.8590f); 249 path->conicTo(5.6898f, 3.7145f, 5.5152f, 4.0074f, 0.8590f); 250 path->conicTo(5.3407f, 4.3003f, 5.0000f, 4.2860f, 0.8590f); 251 path->conicTo(4.4519f, 4.2631f, 4.4519f, 3.7145f, 0.7217f); 252 path->conicTo(4.4519f, 3.1659f, 5.0000f, 3.1430f, 0.7217f); 253 path->lineTo(5.0000f, 3.1430f); 254 path->close(); 255 path->moveTo(7.2860f, 3.1430f); 256 path->conicTo(7.6267f, 3.1287f, 7.8012f, 3.4216f, 0.8590f); 257 path->conicTo(7.9758f, 3.7145f, 7.8012f, 4.0074f, 0.8590f); 258 path->conicTo(7.6267f, 4.3003f, 7.2860f, 4.2860f, 0.8590f); 259 path->conicTo(6.7379f, 4.2631f, 6.7379f, 3.7145f, 0.7217f); 260 path->conicTo(6.7379f, 3.1659f, 7.2860f, 3.1430f, 0.7217f); 261 path->close(); 262 path->moveTo(1.0000f, 6.1900f); 263 path->lineTo(1.0000f, 14.3810f); 264 path->conicTo(0.9992f, 14.7757f, 1.2782f, 15.0548f, 0.9235f); 265 path->conicTo(1.5573f, 15.3338f, 1.9520f, 15.3330f, 0.9235f); 266 path->lineTo(16.0480f, 15.3330f); 267 path->conicTo(16.4427f, 15.3338f, 16.7218f, 15.0548f, 0.9235f); 268 path->conicTo(17.0008f, 14.7757f, 17.0000f, 14.3810f, 0.9235f); 269 path->lineTo(17.0000f, 6.1910f); 270 path->lineTo(1.0000f, 6.1910f); 271 path->lineTo(1.0000f, 6.1900f); 272 path->close(); 273 } 274 275 constexpr MakePathProc gProcs[] = { 276 make_frame, 277 make_triangle, 278 make_rect, 279 make_oval, 280 make_sawtooth_32, 281 make_star_5, 282 make_star_13, 283 make_line, 284 make_house, 285 make_sawtooth_3, 286 }; 287 288 #define N SK_ARRAY_COUNT(gProcs) 289 290 class PathFillGM : public skiagm::GM { 291 SkPath fPath[N]; 292 SkScalar fDY[N]; 293 SkPath fInfoPath; 294 SkPath fAccessibilityPath; 295 SkPath fVisualizerPath; 296 protected: 297 void onOnceBeforeDraw() override { 298 for (size_t i = 0; i < N; i++) { 299 fDY[i] = gProcs[i](&fPath[i]); 300 } 301 302 make_info(&fInfoPath); 303 make_accessibility(&fAccessibilityPath); 304 make_visualizer(&fVisualizerPath); 305 } 306 307 308 SkString onShortName() override { 309 return SkString("pathfill"); 310 } 311 312 SkISize onISize() override { 313 return SkISize::Make(640, 480); 314 } 315 316 void onDraw(SkCanvas* canvas) override { 317 SkPaint paint; 318 paint.setAntiAlias(true); 319 320 for (size_t i = 0; i < N; i++) { 321 canvas->drawPath(fPath[i], paint); 322 canvas->translate(SkIntToScalar(0), fDY[i]); 323 } 324 325 canvas->save(); 326 canvas->scale(0.300000011920929f, 0.300000011920929f); 327 canvas->translate(50, 50); 328 canvas->drawPath(fInfoPath, paint); 329 canvas->restore(); 330 331 canvas->scale(2, 2); 332 canvas->translate(5, 15); 333 canvas->drawPath(fAccessibilityPath, paint); 334 335 canvas->scale(0.5f, 0.5f); 336 canvas->translate(5, 50); 337 canvas->drawPath(fVisualizerPath, paint); 338 } 339 340 private: 341 typedef skiagm::GM INHERITED; 342 }; 343 344 // test inverse-fill w/ a clip that completely excludes the geometry 345 class PathInverseFillGM : public skiagm::GM { 346 SkPath fPath[N]; 347 SkScalar fDY[N]; 348 protected: 349 void onOnceBeforeDraw() override { 350 for (size_t i = 0; i < N; i++) { 351 fDY[i] = gProcs[i](&fPath[i]); 352 } 353 } 354 355 SkString onShortName() override { 356 return SkString("pathinvfill"); 357 } 358 359 SkISize onISize() override { 360 return SkISize::Make(450, 220); 361 } 362 363 static void show(SkCanvas* canvas, const SkPath& path, const SkPaint& paint, 364 const SkRect* clip, SkScalar top, const SkScalar bottom) { 365 canvas->save(); 366 if (clip) { 367 SkRect r = *clip; 368 r.fTop = top; 369 r.fBottom = bottom; 370 canvas->clipRect(r); 371 } 372 canvas->drawPath(path, paint); 373 canvas->restore(); 374 } 375 376 void onDraw(SkCanvas* canvas) override { 377 SkPath path; 378 379 path.addCircle(SkIntToScalar(50), SkIntToScalar(50), SkIntToScalar(40)); 380 path.toggleInverseFillType(); 381 382 SkRect clipR = { 0, 0, SkIntToScalar(100), SkIntToScalar(200) }; 383 384 canvas->translate(SkIntToScalar(10), SkIntToScalar(10)); 385 386 for (int doclip = 0; doclip <= 1; ++doclip) { 387 for (int aa = 0; aa <= 1; ++aa) { 388 SkPaint paint; 389 paint.setAntiAlias(SkToBool(aa)); 390 391 canvas->save(); 392 canvas->clipRect(clipR); 393 394 const SkRect* clipPtr = doclip ? &clipR : nullptr; 395 396 show(canvas, path, paint, clipPtr, clipR.fTop, clipR.centerY()); 397 show(canvas, path, paint, clipPtr, clipR.centerY(), clipR.fBottom); 398 399 canvas->restore(); 400 canvas->translate(SkIntToScalar(110), 0); 401 } 402 } 403 } 404 405 private: 406 typedef skiagm::GM INHERITED; 407 }; 408 409 DEF_SIMPLE_GM(rotatedcubicpath, canvas, 200, 200) { 410 SkPaint p; 411 p.setAntiAlias(true); 412 p.setStyle(SkPaint::kFill_Style); 413 414 canvas->translate(50, 50); 415 SkPath path; 416 path.moveTo(48,-23); 417 path.cubicTo(48,-29.5, 6,-30, 6,-30); 418 path.cubicTo(6,-30, 2,0, 2,0); 419 path.cubicTo(2,0, 44,-21.5, 48,-23); 420 path.close(); 421 422 p.setColor(SK_ColorBLUE); 423 canvas->drawPath(path, p); 424 425 // Rotated path, which is not antialiased on GPU 426 p.setColor(SK_ColorRED); 427 canvas->rotate(90); 428 canvas->drawPath(path, p); 429 } 430 431 /////////////////////////////////////////////////////////////////////////////// 432 433 DEF_GM( return new PathFillGM; ) 434 DEF_GM( return new PathInverseFillGM; ) 435