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