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 "SampleCode.h" 9#include "SkAnimTimer.h" 10#include "SkView.h" 11#include "SkCanvas.h" 12#include "SkGradientShader.h" 13#include "SkGraphics.h" 14#include "SkPath.h" 15#include "SkRegion.h" 16#include "SkShader.h" 17#include "SkUtils.h" 18#include "SkColorPriv.h" 19#include "SkColorFilter.h" 20#include "SkParsePath.h" 21#include "SkTime.h" 22#include "SkTypeface.h" 23 24#include "SkGeometry.h" 25 26#include <stdlib.h> 27 28// http://code.google.com/p/skia/issues/detail?id=32 29static void test_cubic() { 30 SkPoint src[4] = { 31 { 556.25000f, 523.03003f }, 32 { 556.23999f, 522.96002f }, 33 { 556.21997f, 522.89001f }, 34 { 556.21997f, 522.82001f } 35 }; 36 SkPoint dst[11]; 37 dst[10].set(42, -42); // one past the end, that we don't clobber these 38 SkScalar tval[] = { 0.33333334f, 0.99999994f }; 39 40 SkChopCubicAt(src, dst, tval, 2); 41 42#if 0 43 for (int i = 0; i < 11; i++) { 44 SkDebugf("--- %d [%g %g]\n", i, dst[i].fX, dst[i].fY); 45 } 46#endif 47} 48 49static void test_cubic2() { 50 const char* str = "M2242 -590088L-377758 9.94099e+07L-377758 9.94099e+07L2242 -590088Z"; 51 SkPath path; 52 SkParsePath::FromSVGString(str, &path); 53 54 { 55 SkRect r = path.getBounds(); 56 SkIRect ir; 57 r.round(&ir); 58 SkDebugf("[%g %g %g %g] [%x %x %x %x]\n", 59 SkScalarToDouble(r.fLeft), SkScalarToDouble(r.fTop), 60 SkScalarToDouble(r.fRight), SkScalarToDouble(r.fBottom), 61 ir.fLeft, ir.fTop, ir.fRight, ir.fBottom); 62 } 63 64 SkBitmap bitmap; 65 bitmap.allocN32Pixels(300, 200); 66 67 SkCanvas canvas(bitmap); 68 SkPaint paint; 69 paint.setAntiAlias(true); 70 canvas.drawPath(path, paint); 71} 72 73class PathView : public SampleView { 74 SkScalar fPrevSecs; 75public: 76 SkScalar fDStroke, fStroke, fMinStroke, fMaxStroke; 77 SkPath fPath[6]; 78 bool fShowHairline; 79 bool fOnce; 80 81 PathView() { 82 fPrevSecs = 0; 83 fOnce = false; 84 } 85 86 void init() { 87 if (fOnce) { 88 return; 89 } 90 fOnce = true; 91 92 test_cubic(); 93 test_cubic2(); 94 95 fShowHairline = false; 96 97 fDStroke = 1; 98 fStroke = 10; 99 fMinStroke = 10; 100 fMaxStroke = 180; 101 102 const SkScalar V = 85; 103 104 fPath[0].moveTo(40, 70); 105 fPath[0].lineTo(70, 70 + SK_ScalarHalf); 106 fPath[0].lineTo(110, 70); 107 108 fPath[1].moveTo(40, 70); 109 fPath[1].lineTo(70, 70 - SK_ScalarHalf); 110 fPath[1].lineTo(110, 70); 111 112 fPath[2].moveTo(V, V); 113 fPath[2].lineTo(50, V); 114 fPath[2].lineTo(50, 50); 115 116 fPath[3].moveTo(50, 50); 117 fPath[3].lineTo(50, V); 118 fPath[3].lineTo(V, V); 119 120 fPath[4].moveTo(50, 50); 121 fPath[4].lineTo(50, V); 122 fPath[4].lineTo(52, 50); 123 124 fPath[5].moveTo(52, 50); 125 fPath[5].lineTo(50, V); 126 fPath[5].lineTo(50, 50); 127 128 this->setBGColor(0xFFDDDDDD); 129 } 130 131protected: 132 // overrides from SkEventSink 133 bool onQuery(SkEvent* evt) override { 134 if (SampleCode::TitleQ(*evt)) { 135 SampleCode::TitleR(evt, "Paths"); 136 return true; 137 } 138 return this->INHERITED::onQuery(evt); 139 } 140 141 void drawPath(SkCanvas* canvas, const SkPath& path, SkPaint::Join j) { 142 SkPaint paint; 143 144 paint.setAntiAlias(true); 145 paint.setStyle(SkPaint::kStroke_Style); 146 paint.setStrokeJoin(j); 147 paint.setStrokeWidth(fStroke); 148 149 if (fShowHairline) { 150 SkPath fill; 151 152 paint.getFillPath(path, &fill); 153 paint.setStrokeWidth(0); 154 canvas->drawPath(fill, paint); 155 } else { 156 canvas->drawPath(path, paint); 157 } 158 159 paint.setColor(SK_ColorRED); 160 paint.setStrokeWidth(0); 161 canvas->drawPath(path, paint); 162 } 163 164 void onDrawContent(SkCanvas* canvas) override { 165 this->init(); 166 canvas->translate(50, 50); 167 168 static const SkPaint::Join gJoins[] = { 169 SkPaint::kBevel_Join, 170 SkPaint::kMiter_Join, 171 SkPaint::kRound_Join 172 }; 173 174 for (size_t i = 0; i < SK_ARRAY_COUNT(gJoins); i++) { 175 canvas->save(); 176 for (size_t j = 0; j < SK_ARRAY_COUNT(fPath); j++) { 177 this->drawPath(canvas, fPath[j], gJoins[i]); 178 canvas->translate(200, 0); 179 } 180 canvas->restore(); 181 182 canvas->translate(0, 200); 183 } 184 } 185 186 bool onAnimate(const SkAnimTimer& timer) override { 187 SkScalar currSecs = timer.scaled(100); 188 SkScalar delta = currSecs - fPrevSecs; 189 fPrevSecs = currSecs; 190 191 fStroke += fDStroke * delta; 192 if (fStroke > fMaxStroke || fStroke < fMinStroke) { 193 fDStroke = -fDStroke; 194 } 195 return true; 196 } 197 198 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override { 199 fShowHairline = !fShowHairline; 200 this->inval(nullptr); 201 return this->INHERITED::onFindClickHandler(x, y, modi); 202 } 203 204private: 205 typedef SampleView INHERITED; 206}; 207DEF_SAMPLE( return new PathView; ) 208 209////////////////////////////////////////////////////////////////////////////// 210 211#include "SkArcToPathEffect.h" 212#include "SkCornerPathEffect.h" 213#include "SkRandom.h" 214 215class ArcToView : public SampleView { 216 bool fDoFrame, fDoArcTo, fDoCorner, fDoConic; 217 SkPaint fPtsPaint, fArcToPaint, fSkeletonPaint, fCornerPaint; 218public: 219 enum { 220 N = 4 221 }; 222 SkPoint fPts[N]; 223 224 ArcToView() 225 : fDoFrame(false), fDoArcTo(false), fDoCorner(false), fDoConic(false) 226 { 227 SkRandom rand; 228 for (int i = 0; i < N; ++i) { 229 fPts[i].fX = 20 + rand.nextUScalar1() * 640; 230 fPts[i].fY = 20 + rand.nextUScalar1() * 480; 231 } 232 233 const SkScalar rad = 50; 234 235 fPtsPaint.setAntiAlias(true); 236 fPtsPaint.setStrokeWidth(15); 237 fPtsPaint.setStrokeCap(SkPaint::kRound_Cap); 238 239 fArcToPaint.setAntiAlias(true); 240 fArcToPaint.setStyle(SkPaint::kStroke_Style); 241 fArcToPaint.setStrokeWidth(9); 242 fArcToPaint.setColor(0x800000FF); 243 fArcToPaint.setPathEffect(SkArcToPathEffect::Make(rad)); 244 245 fCornerPaint.setAntiAlias(true); 246 fCornerPaint.setStyle(SkPaint::kStroke_Style); 247 fCornerPaint.setStrokeWidth(13); 248 fCornerPaint.setColor(SK_ColorGREEN); 249 fCornerPaint.setPathEffect(SkCornerPathEffect::Make(rad*2)); 250 251 fSkeletonPaint.setAntiAlias(true); 252 fSkeletonPaint.setStyle(SkPaint::kStroke_Style); 253 fSkeletonPaint.setColor(SK_ColorRED); 254 } 255 256 void toggle(bool& value) { 257 value = !value; 258 this->inval(nullptr); 259 } 260 261protected: 262 // overrides from SkEventSink 263 bool onQuery(SkEvent* evt) override { 264 if (SampleCode::TitleQ(*evt)) { 265 SampleCode::TitleR(evt, "ArcTo"); 266 return true; 267 } 268 SkUnichar uni; 269 if (SampleCode::CharQ(*evt, &uni)) { 270 switch (uni) { 271 case '1': this->toggle(fDoFrame); return true; 272 case '2': this->toggle(fDoArcTo); return true; 273 case '3': this->toggle(fDoCorner); return true; 274 case '4': this->toggle(fDoConic); return true; 275 default: break; 276 } 277 } 278 return this->INHERITED::onQuery(evt); 279 } 280 281 void makePath(SkPath* path) { 282 path->moveTo(fPts[0]); 283 for (int i = 1; i < N; ++i) { 284 path->lineTo(fPts[i]); 285 } 286 if (!fDoFrame) { 287 path->close(); 288 } 289 } 290 291 void onDrawContent(SkCanvas* canvas) override { 292 canvas->drawPoints(SkCanvas::kPoints_PointMode, N, fPts, fPtsPaint); 293 294 SkPath path; 295 this->makePath(&path); 296 297 if (fDoCorner) { 298 canvas->drawPath(path, fCornerPaint); 299 } 300 if (fDoArcTo) { 301 canvas->drawPath(path, fArcToPaint); 302 } 303 304 canvas->drawPath(path, fSkeletonPaint); 305 } 306 307 bool onClick(Click* click) override { 308 int32_t index; 309 if (click->fMeta.findS32("index", &index)) { 310 SkASSERT((unsigned)index < N); 311 fPts[index] = click->fCurr; 312 this->inval(nullptr); 313 return true; 314 } 315 return false; 316 } 317 318 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override { 319 const SkScalar tol = 4; 320 const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2); 321 for (int i = 0; i < N; ++i) { 322 if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) { 323 Click* click = new Click(this); 324 click->fMeta.setS32("index", i); 325 return click; 326 } 327 } 328 return this->INHERITED::onFindClickHandler(x, y, modi); 329 } 330 331private: 332 typedef SampleView INHERITED; 333}; 334DEF_SAMPLE( return new ArcToView; ) 335 336///////////// 337 338class FatStroke : public SampleView { 339 bool fClosed, fShowStroke, fShowHidden, fShowSkeleton; 340 int fJoinType, fCapType; 341 float fWidth = 30; 342 SkPaint fPtsPaint, fHiddenPaint, fSkeletonPaint, fStrokePaint; 343public: 344 enum { 345 N = 4 346 }; 347 SkPoint fPts[N]; 348 349 FatStroke() : fClosed(false), fShowStroke(true), fShowHidden(false), fShowSkeleton(true), 350 fJoinType(0), fCapType(0) 351 { 352 SkRandom rand; 353 for (int i = 0; i < N; ++i) { 354 fPts[i].fX = 20 + rand.nextUScalar1() * 640; 355 fPts[i].fY = 20 + rand.nextUScalar1() * 480; 356 } 357 358 fPtsPaint.setAntiAlias(true); 359 fPtsPaint.setStrokeWidth(10); 360 fPtsPaint.setStrokeCap(SkPaint::kRound_Cap); 361 362 fHiddenPaint.setAntiAlias(true); 363 fHiddenPaint.setStyle(SkPaint::kStroke_Style); 364 fHiddenPaint.setColor(0xFF0000FF); 365 366 fStrokePaint.setAntiAlias(true); 367 fStrokePaint.setStyle(SkPaint::kStroke_Style); 368 fStrokePaint.setStrokeWidth(50); 369 fStrokePaint.setColor(0x8000FF00); 370 371 fSkeletonPaint.setAntiAlias(true); 372 fSkeletonPaint.setStyle(SkPaint::kStroke_Style); 373 fSkeletonPaint.setColor(SK_ColorRED); 374 } 375 376 void toggle(bool& value) { 377 value = !value; 378 this->inval(nullptr); 379 } 380 381 void toggle3(int& value) { 382 value = (value + 1) % 3; 383 this->inval(nullptr); 384 } 385 386protected: 387 // overrides from SkEventSink 388 bool onQuery(SkEvent* evt) override { 389 if (SampleCode::TitleQ(*evt)) { 390 SampleCode::TitleR(evt, "FatStroke"); 391 return true; 392 } 393 SkUnichar uni; 394 if (SampleCode::CharQ(*evt, &uni)) { 395 switch (uni) { 396 case '1': this->toggle(fShowSkeleton); return true; 397 case '2': this->toggle(fShowStroke); return true; 398 case '3': this->toggle(fShowHidden); return true; 399 case '4': this->toggle3(fJoinType); return true; 400 case '5': this->toggle3(fCapType); return true; 401 case '6': this->toggle(fClosed); return true; 402 case '-': fWidth -= 5; this->inval(nullptr); return true; 403 case '=': fWidth += 5; this->inval(nullptr); return true; 404 default: break; 405 } 406 } 407 return this->INHERITED::onQuery(evt); 408 } 409 410 void makePath(SkPath* path) { 411 path->moveTo(fPts[0]); 412 for (int i = 1; i < N; ++i) { 413 path->lineTo(fPts[i]); 414 } 415 if (fClosed) { 416 path->close(); 417 } 418 } 419 420 void onDrawContent(SkCanvas* canvas) override { 421 canvas->drawColor(0xFFEEEEEE); 422 423 SkPath path; 424 this->makePath(&path); 425 426 fStrokePaint.setStrokeWidth(fWidth); 427 fStrokePaint.setStrokeJoin((SkPaint::Join)fJoinType); 428 fStrokePaint.setStrokeCap((SkPaint::Cap)fCapType); 429 430 if (fShowStroke) { 431 canvas->drawPath(path, fStrokePaint); 432 } 433 if (fShowHidden) { 434 SkPath hidden; 435 fStrokePaint.getFillPath(path, &hidden); 436 canvas->drawPath(hidden, fHiddenPaint); 437 } 438 if (fShowSkeleton) { 439 canvas->drawPath(path, fSkeletonPaint); 440 } 441 canvas->drawPoints(SkCanvas::kPoints_PointMode, N, fPts, fPtsPaint); 442 } 443 444 bool onClick(Click* click) override { 445 int32_t index; 446 if (click->fMeta.findS32("index", &index)) { 447 SkASSERT((unsigned)index < N); 448 fPts[index] = click->fCurr; 449 this->inval(nullptr); 450 return true; 451 } 452 return false; 453 } 454 455 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override { 456 const SkScalar tol = 4; 457 const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2); 458 for (int i = 0; i < N; ++i) { 459 if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) { 460 Click* click = new Click(this); 461 click->fMeta.setS32("index", i); 462 return click; 463 } 464 } 465 return this->INHERITED::onFindClickHandler(x, y, modi); 466 } 467 468private: 469 typedef SampleView INHERITED; 470}; 471DEF_SAMPLE( return new FatStroke; ) 472