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 #include "SampleCode.h" 8 #include "SkBlurMask.h" 9 #include "SkCanvas.h" 10 #include "SkView.h" 11 #include "Sk1DPathEffect.h" 12 #include "Sk2DPathEffect.h" 13 #include "SkBlurMaskFilter.h" 14 #include "SkColorMatrixFilter.h" 15 #include "SkColorPriv.h" 16 #include "SkCornerPathEffect.h" 17 #include "SkDashPathEffect.h" 18 #include "SkDiscretePathEffect.h" 19 #include "SkEmbossMaskFilter.h" 20 #include "SkReadBuffer.h" 21 #include "SkWriteBuffer.h" 22 #include "SkGradientShader.h" 23 #include "SkLayerRasterizer.h" 24 #include "SkMath.h" 25 #include "SkPath.h" 26 #include "SkPictureRecorder.h" 27 #include "SkRegion.h" 28 #include "SkShader.h" 29 #include "SkCornerPathEffect.h" 30 #include "SkPathMeasure.h" 31 #include "SkPicture.h" 32 #include "SkRandom.h" 33 #include "SkTypeface.h" 34 #include "SkUtils.h" 35 36 #include <math.h> 37 #include "DecodeFile.h" 38 39 static void r0(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) { 40 p.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 41 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3)), 42 SkBlurMaskFilter::kNone_BlurFlag)); 43 rastBuilder->addLayer(p, SkIntToScalar(3), SkIntToScalar(3)); 44 45 p.setMaskFilter(nullptr); 46 p.setStyle(SkPaint::kStroke_Style); 47 p.setStrokeWidth(SK_Scalar1); 48 rastBuilder->addLayer(p); 49 50 p.setAlpha(0x11); 51 p.setStyle(SkPaint::kFill_Style); 52 p.setBlendMode(SkBlendMode::kSrc); 53 rastBuilder->addLayer(p); 54 } 55 56 static void r1(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) { 57 rastBuilder->addLayer(p); 58 59 p.setAlpha(0x40); 60 p.setBlendMode(SkBlendMode::kSrc); 61 p.setStyle(SkPaint::kStroke_Style); 62 p.setStrokeWidth(SK_Scalar1*2); 63 rastBuilder->addLayer(p); 64 } 65 66 static void r2(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) { 67 p.setStyle(SkPaint::kStrokeAndFill_Style); 68 p.setStrokeWidth(SK_Scalar1*4); 69 rastBuilder->addLayer(p); 70 71 p.setStyle(SkPaint::kStroke_Style); 72 p.setStrokeWidth(SK_Scalar1*3/2); 73 p.setBlendMode(SkBlendMode::kClear); 74 rastBuilder->addLayer(p); 75 } 76 77 static void r3(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) { 78 p.setStyle(SkPaint::kStroke_Style); 79 p.setStrokeWidth(SK_Scalar1*3); 80 rastBuilder->addLayer(p); 81 82 p.setAlpha(0x20); 83 p.setStyle(SkPaint::kFill_Style); 84 p.setBlendMode(SkBlendMode::kSrc); 85 rastBuilder->addLayer(p); 86 } 87 88 static void r4(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) { 89 p.setAlpha(0x60); 90 rastBuilder->addLayer(p, SkIntToScalar(3), SkIntToScalar(3)); 91 92 p.setAlpha(0xFF); 93 p.setBlendMode(SkBlendMode::kClear); 94 rastBuilder->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2); 95 96 p.setBlendMode(SkBlendMode::kSrcOver); 97 rastBuilder->addLayer(p); 98 } 99 100 static void r5(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) { 101 rastBuilder->addLayer(p); 102 103 p.setPathEffect(SkDiscretePathEffect::Make(SK_Scalar1*4, SK_Scalar1*3)); 104 p.setBlendMode(SkBlendMode::kSrcOut); 105 rastBuilder->addLayer(p); 106 } 107 108 static void r6(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) { 109 rastBuilder->addLayer(p); 110 111 p.setAntiAlias(false); 112 SkLayerRasterizer::Builder rastBuilder2; 113 r5(&rastBuilder2, p); 114 p.setRasterizer(rastBuilder2.detach()); 115 p.setBlendMode(SkBlendMode::kClear); 116 rastBuilder->addLayer(p); 117 } 118 119 class Dot2DPathEffect : public Sk2DPathEffect { 120 public: 121 Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix) 122 : Sk2DPathEffect(matrix), fRadius(radius) {} 123 124 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Dot2DPathEffect) 125 126 protected: 127 void next(const SkPoint& loc, int u, int v, SkPath* dst) const override { 128 dst->addCircle(loc.fX, loc.fY, fRadius); 129 } 130 131 void flatten(SkWriteBuffer& buffer) const override { 132 this->INHERITED::flatten(buffer); 133 buffer.writeScalar(fRadius); 134 } 135 136 private: 137 SkScalar fRadius; 138 139 typedef Sk2DPathEffect INHERITED; 140 }; 141 142 static void r7(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) { 143 SkMatrix lattice; 144 lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0); 145 lattice.postSkew(SK_Scalar1/3, 0, 0, 0); 146 p.setPathEffect(sk_make_sp<Dot2DPathEffect>(SK_Scalar1*4, lattice)); 147 rastBuilder->addLayer(p); 148 } 149 150 static void r8(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) { 151 rastBuilder->addLayer(p); 152 153 SkMatrix lattice; 154 lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0); 155 lattice.postSkew(SK_Scalar1/3, 0, 0, 0); 156 p.setPathEffect(sk_make_sp<Dot2DPathEffect>(SK_Scalar1*2, lattice)); 157 p.setBlendMode(SkBlendMode::kClear); 158 rastBuilder->addLayer(p); 159 160 p.setPathEffect(nullptr); 161 p.setBlendMode(SkBlendMode::kSrcOver); 162 p.setStyle(SkPaint::kStroke_Style); 163 p.setStrokeWidth(SK_Scalar1); 164 rastBuilder->addLayer(p); 165 } 166 167 static void r9(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) { 168 rastBuilder->addLayer(p); 169 170 SkMatrix lattice; 171 lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0); 172 lattice.postRotate(SkIntToScalar(30), 0, 0); 173 p.setPathEffect(SkLine2DPathEffect::Make(SK_Scalar1*2, lattice)); 174 p.setBlendMode(SkBlendMode::kClear); 175 rastBuilder->addLayer(p); 176 177 p.setPathEffect(nullptr); 178 p.setBlendMode(SkBlendMode::kSrcOver); 179 p.setStyle(SkPaint::kStroke_Style); 180 p.setStrokeWidth(SK_Scalar1); 181 rastBuilder->addLayer(p); 182 } 183 184 typedef void (*raster_proc)(SkLayerRasterizer::Builder*, SkPaint&); 185 186 static const raster_proc gRastProcs[] = { 187 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9 188 }; 189 190 static const struct { 191 SkColor fMul, fAdd; 192 } gLightingColors[] = { 193 { 0x808080, 0x800000 }, // general case 194 { 0x707070, 0x707070 }, // no-pin case 195 { 0xFFFFFF, 0x800000 }, // just-add case 196 { 0x808080, 0x000000 }, // just-mul case 197 { 0xFFFFFF, 0x000000 } // identity case 198 }; 199 200 static void apply_shader(SkPaint* paint, int index) { 201 raster_proc proc = gRastProcs[index]; 202 if (proc) { 203 SkPaint p; 204 SkLayerRasterizer::Builder rastBuilder; 205 206 p.setAntiAlias(true); 207 proc(&rastBuilder, p); 208 paint->setRasterizer(rastBuilder.detach()); 209 } 210 211 #ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER 212 SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 }; 213 paint->setMaskFilter(SkBlurMaskFilter::MakeEmboss( 214 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3)), dir, 215 SK_Scalar1/4, SkIntToScalar(4))); 216 paint->setColor(SK_ColorBLUE); 217 #endif 218 } 219 220 class DemoView : public SampleView { 221 public: 222 DemoView() {} 223 224 protected: 225 // overrides from SkEventSink 226 virtual bool onQuery(SkEvent* evt) { 227 if (SampleCode::TitleQ(*evt)) { 228 SampleCode::TitleR(evt, "Demo"); 229 return true; 230 } 231 return this->INHERITED::onQuery(evt); 232 } 233 234 virtual bool onClick(Click* click) { 235 return this->INHERITED::onClick(click); 236 } 237 238 void makePath(SkPath& path) { 239 path.addCircle(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(20), 240 SkPath::kCCW_Direction); 241 for (int index = 0; index < 10; index++) { 242 SkScalar x = (float) cos(index / 10.0f * 2 * 3.1415925358f); 243 SkScalar y = (float) sin(index / 10.0f * 2 * 3.1415925358f); 244 x *= index & 1 ? 7 : 14; 245 y *= index & 1 ? 7 : 14; 246 x += SkIntToScalar(20); 247 y += SkIntToScalar(20); 248 if (index == 0) 249 path.moveTo(x, y); 250 else 251 path.lineTo(x, y); 252 } 253 path.close(); 254 } 255 256 virtual void onDrawContent(SkCanvas* canvas) { 257 canvas->save(); 258 this->drawPicture(canvas, 0); 259 canvas->restore(); 260 261 { 262 SkPictureRecorder recorder; 263 { 264 SkCanvas* record = recorder.beginRecording(320, 480, nullptr, 0); 265 this->drawPicture(record, 120); 266 } 267 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 268 269 canvas->translate(0, SkIntToScalar(120)); 270 271 SkRect clip; 272 clip.set(0, 0, SkIntToScalar(160), SkIntToScalar(160)); 273 do { 274 canvas->save(); 275 canvas->clipRect(clip); 276 picture->playback(canvas); 277 canvas->restore(); 278 if (clip.fRight < SkIntToScalar(320)) 279 clip.offset(SkIntToScalar(160), 0); 280 else if (clip.fBottom < SkIntToScalar(480)) 281 clip.offset(-SkIntToScalar(320), SkIntToScalar(160)); 282 else 283 break; 284 } while (true); 285 } 286 } 287 288 void drawPicture(SkCanvas* canvas, int spriteOffset) { 289 SkMatrix matrix; matrix.reset(); 290 SkPaint paint; 291 SkPath path; 292 SkPoint start = {0, 0}; 293 SkPoint stop = { SkIntToScalar(40), SkIntToScalar(40) }; 294 SkRect rect = {0, 0, SkIntToScalar(40), SkIntToScalar(40) }; 295 SkRect rect2 = {0, 0, SkIntToScalar(65), SkIntToScalar(20) }; 296 SkScalar left = 0, top = 0, x = 0, y = 0; 297 int index; 298 299 char ascii[] = "ascii..."; 300 int asciiLength = sizeof(ascii) - 1; 301 char utf8[] = "utf8" "\xe2\x80\xa6"; 302 short utf16[] = {'u', 't', 'f', '1', '6', 0x2026 }; 303 short utf16simple[] = {'u', 't', 'f', '1', '6', '!' }; 304 305 makePath(path); 306 SkTDArray<SkPoint>(pos); 307 pos.setCount(asciiLength); 308 for (index = 0; index < asciiLength; index++) 309 pos[index].set(SkIntToScalar((unsigned int)index * 10), 310 SkIntToScalar((unsigned int)index * 2)); 311 SkTDArray<SkPoint>(pos2); 312 pos2.setCount(asciiLength); 313 for (index = 0; index < asciiLength; index++) 314 pos2[index].set(SkIntToScalar((unsigned int)index * 10), 315 SkIntToScalar(20)); 316 317 // shaders 318 SkPoint linearPoints[] = { { 0, 0, }, { SkIntToScalar(40), SkIntToScalar(40) } }; 319 SkColor linearColors[] = { SK_ColorRED, SK_ColorBLUE }; 320 SkScalar* linearPos = nullptr; 321 int linearCount = 2; 322 SkShader::TileMode linearMode = SkShader::kMirror_TileMode; 323 auto linear = SkGradientShader::MakeLinear(linearPoints, 324 linearColors, linearPos, linearCount, linearMode); 325 326 SkPoint radialCenter = { SkIntToScalar(25), SkIntToScalar(25) }; 327 SkScalar radialRadius = SkIntToScalar(25); 328 SkColor radialColors[] = { SK_ColorGREEN, SK_ColorGRAY, SK_ColorRED }; 329 SkScalar radialPos[] = { 0, SkIntToScalar(3) / 5, SkIntToScalar(1)}; 330 int radialCount = 3; 331 SkShader::TileMode radialMode = SkShader::kRepeat_TileMode; 332 auto radial = SkGradientShader::MakeRadial(radialCenter, 333 radialRadius, radialColors, radialPos, radialCount, 334 radialMode); 335 336 SkEmbossMaskFilter::Light light; 337 light.fDirection[0] = SK_Scalar1/2; 338 light.fDirection[1] = SK_Scalar1/2; 339 light.fDirection[2] = SK_Scalar1/3; 340 light.fAmbient = 0x48; 341 light.fSpecular = 0x80; 342 343 auto lightingFilter = SkColorMatrixFilter::MakeLightingFilter( 344 0xff89bc45, 0xff112233); 345 346 canvas->save(); 347 canvas->translate(SkIntToScalar(0), SkIntToScalar(5)); 348 paint.setAntiAlias(true); 349 paint.setFilterQuality(kLow_SkFilterQuality); 350 // !!! draw through a clip 351 paint.setColor(SK_ColorLTGRAY); 352 paint.setStyle(SkPaint::kFill_Style); 353 SkRect clip = {0, 0, SkIntToScalar(320), SkIntToScalar(120)}; 354 canvas->clipRect(clip); 355 paint.setShader(SkShader::MakeBitmapShader(fTx, 356 SkShader::kMirror_TileMode, SkShader::kRepeat_TileMode)); 357 canvas->drawPaint(paint); 358 canvas->save(); 359 360 // line (exercises xfermode, colorShader, colorFilter, filterShader) 361 paint.setColor(SK_ColorGREEN); 362 paint.setStrokeWidth(SkIntToScalar(10)); 363 paint.setStyle(SkPaint::kStroke_Style); 364 paint.setBlendMode(SkBlendMode::kXor); 365 paint.setColorFilter(lightingFilter); 366 canvas->drawLine(start, stop, paint); // should not be green 367 paint.setBlendMode(SkBlendMode::kSrcOver); 368 paint.setColorFilter(nullptr); 369 370 // rectangle 371 paint.setStyle(SkPaint::kFill_Style); 372 canvas->translate(SkIntToScalar(50), 0); 373 paint.setColor(SK_ColorYELLOW); 374 paint.setShader(linear); 375 paint.setPathEffect(pathEffectTest()); 376 canvas->drawRect(rect, paint); 377 paint.setPathEffect(nullptr); 378 379 // circle w/ emboss & transparent (exercises 3dshader) 380 canvas->translate(SkIntToScalar(50), 0); 381 paint.setMaskFilter(SkEmbossMaskFilter::Make( 382 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(12)/5), light)); 383 canvas->drawOval(rect, paint); 384 canvas->translate(SkIntToScalar(10), SkIntToScalar(10)); 385 // paint.setShader(transparentShader)->unref(); 386 canvas->drawOval(rect, paint); 387 canvas->translate(0, SkIntToScalar(-10)); 388 389 // path 390 canvas->translate(SkIntToScalar(50), 0); 391 paint.setColor(SK_ColorRED); 392 paint.setStyle(SkPaint::kStroke_Style); 393 paint.setStrokeWidth(SkIntToScalar(5)); 394 paint.setShader(radial); 395 paint.setMaskFilter(nullptr); 396 canvas->drawPath(path, paint); 397 398 paint.setShader(nullptr); 399 // bitmap 400 canvas->translate(SkIntToScalar(50), 0); 401 paint.setStyle(SkPaint::kFill_Style); 402 canvas->drawBitmap(fBug, left, top, &paint); 403 404 canvas->translate(-SkIntToScalar(30), SkIntToScalar(30)); 405 paint.setShader(shaderTest()); // test compose shader 406 canvas->drawRect(rect2, paint); 407 paint.setShader(nullptr); 408 409 canvas->restore(); 410 // text 411 canvas->translate(0, SkIntToScalar(60)); 412 canvas->save(); 413 paint.setColor(SK_ColorGRAY); 414 canvas->drawPosText(ascii, asciiLength, pos.begin(), paint); 415 canvas->drawPosText(ascii, asciiLength, pos2.begin(), paint); 416 417 canvas->translate(SkIntToScalar(50), 0); 418 paint.setColor(SK_ColorCYAN); 419 canvas->drawText(utf8, sizeof(utf8) - 1, x, y, paint); 420 421 canvas->translate(SkIntToScalar(30), 0); 422 paint.setColor(SK_ColorMAGENTA); 423 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); 424 matrix.setTranslate(SkIntToScalar(10), SkIntToScalar(10)); 425 canvas->drawTextOnPath((void*) utf16, sizeof(utf16), path, &matrix, paint); 426 canvas->translate(0, SkIntToScalar(20)); 427 canvas->drawTextOnPath((void*) utf16simple, sizeof(utf16simple), path, &matrix, paint); 428 canvas->restore(); 429 430 canvas->translate(0, SkIntToScalar(60)); 431 paint.setTextEncoding(SkPaint::kUTF8_TextEncoding); 432 canvas->restore(); 433 } 434 435 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) { 436 fClickPt.set(x, y); 437 this->inval(nullptr); 438 return this->INHERITED::onFindClickHandler(x, y, modi); 439 } 440 441 sk_sp<SkPathEffect> pathEffectTest() { 442 static const int gXY[] = { 1, 0, 0, -1, 2, -1, 3, 0, 2, 1, 0, 1 }; 443 SkScalar gPhase = 0; 444 SkPath path; 445 path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1])); 446 for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2) 447 path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1])); 448 path.close(); 449 path.offset(SkIntToScalar(-6), 0); 450 auto outer = SkPath1DPathEffect::Make(path, SkIntToScalar(12), 451 gPhase, SkPath1DPathEffect::kRotate_Style); 452 auto inner = SkDiscretePathEffect::Make(SkIntToScalar(2), 453 SkIntToScalar(1)/10); // SkCornerPathEffect(SkIntToScalar(2)); 454 return SkPathEffect::MakeCompose(outer, inner); 455 } 456 457 sk_sp<SkShader> shaderTest() { 458 SkPoint pts[] = { { 0, 0, }, { SkIntToScalar(100), 0 } }; 459 SkColor colors[] = { SK_ColorRED, SK_ColorBLUE }; 460 auto shaderA = SkGradientShader::MakeLinear(pts, colors, nullptr, 461 2, SkShader::kClamp_TileMode); 462 pts[1].set(0, SkIntToScalar(100)); 463 SkColor colors2[] = {SK_ColorBLACK, SkColorSetARGB(0x80, 0, 0, 0)}; 464 auto shaderB = SkGradientShader::MakeLinear(pts, colors2, nullptr, 465 2, SkShader::kClamp_TileMode); 466 return SkShader::MakeComposeShader(std::move(shaderA), std::move(shaderB), 467 SkBlendMode::kDstIn); 468 } 469 470 virtual void startTest() { 471 decode_file("/Users/caryclark/Desktop/bugcirc.gif", &fBug); 472 decode_file("/Users/caryclark/Desktop/tbcirc.gif", &fTb); 473 decode_file("/Users/caryclark/Desktop/05psp04.gif", &fTx); 474 } 475 476 void drawRaster(SkCanvas* canvas) { 477 for (size_t index = 0; index < SK_ARRAY_COUNT(gRastProcs); index++) 478 drawOneRaster(canvas); 479 } 480 481 void drawOneRaster(SkCanvas* canvas) { 482 canvas->save(); 483 484 SkScalar x = SkIntToScalar(20); 485 SkScalar y = SkIntToScalar(40); 486 SkPaint paint; 487 488 paint.setAntiAlias(true); 489 paint.setTextSize(SkIntToScalar(48)); 490 paint.setTypeface(SkTypeface::MakeFromName("sans-serif", 491 SkFontStyle::FromOldStyle(SkTypeface::kBold))); 492 493 SkString str("GOOGLE"); 494 495 for (size_t i = 0; i < SK_ARRAY_COUNT(gRastProcs); i++) { 496 apply_shader(&paint, (int)i); 497 498 // paint.setMaskFilter(nullptr); 499 // paint.setColor(SK_ColorBLACK); 500 501 #if 01 502 int index = i % SK_ARRAY_COUNT(gLightingColors); 503 paint.setColorFilter(SkColorMatrixFilter::MakeLightingFilter( 504 gLightingColors[index].fMul, 505 gLightingColors[index].fAdd)); 506 #endif 507 508 canvas->drawString(str, x, y, paint); 509 SkRect oval = { x, y - SkIntToScalar(40), x + SkIntToScalar(40), y }; 510 paint.setStyle(SkPaint::kStroke_Style); 511 canvas->drawOval(oval, paint); 512 paint.setStyle(SkPaint::kFill_Style); 513 514 y += paint.getFontSpacing(); 515 } 516 517 canvas->restore(); 518 } 519 520 private: 521 SkPoint fClickPt; 522 SkBitmap fBug, fTb, fTx; 523 typedef SampleView INHERITED; 524 }; 525 526 ////////////////////////////////////////////////////////////////////////////// 527 528 static SkView* MyFactory() { return new DemoView; } 529 static SkViewRegister reg(MyFactory); 530