1 2 /* 3 * Copyright 2013 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "gm.h" 9 #include "SkBitmap.h" 10 #include "SkRandom.h" 11 #include "SkShader.h" 12 #include "SkXfermode.h" 13 14 namespace skiagm { 15 16 /** 17 * Renders overlapping shapes with random SkXfermode::Modes against a checkerboard. 18 */ 19 class MixedXfermodesGM : public GM { 20 public: 21 MixedXfermodesGM() { 22 } 23 24 protected: 25 virtual SkString onShortName() SK_OVERRIDE { 26 return SkString("mixed_xfermodes"); 27 } 28 29 virtual SkISize onISize() SK_OVERRIDE { 30 return make_isize(790, 640); 31 } 32 33 void drawShape(SkCanvas* canvas, 34 const SkPaint& paint, 35 SkMWCRandom* random) { 36 static const SkRect kRect = SkRect::MakeXYWH(SkIntToScalar(-50), SkIntToScalar(-50), 37 SkIntToScalar(75), SkIntToScalar(105)); 38 int shape = random->nextULessThan(5); 39 switch (shape) { 40 case 0: 41 canvas->drawCircle(0, 0, 50, paint); 42 break; 43 case 1: 44 canvas->drawRoundRect(kRect, SkIntToScalar(10), SkIntToScalar(20), paint); 45 break; 46 case 2: 47 canvas->drawRect(kRect, paint); 48 break; 49 case 3: 50 if (fConvexPath.isEmpty()) { 51 SkPoint points[4]; 52 kRect.toQuad(points); 53 fConvexPath.moveTo(points[0]); 54 fConvexPath.quadTo(points[1], points[2]); 55 fConvexPath.quadTo(points[3], points[0]); 56 SkASSERT(fConvexPath.isConvex()); 57 } 58 canvas->drawPath(fConvexPath, paint); 59 break; 60 case 4: 61 if (fConcavePath.isEmpty()) { 62 SkPoint points[5] = {{0, SkIntToScalar(-50)} }; 63 SkMatrix rot; 64 rot.setRotate(SkIntToScalar(360) / 5); 65 for (int i = 1; i < 5; ++i) { 66 rot.mapPoints(points + i, points + i - 1, 1); 67 } 68 fConcavePath.moveTo(points[0]); 69 for (int i = 0; i < 5; ++i) { 70 fConcavePath.lineTo(points[(2 * i) % 5]); 71 } 72 fConcavePath.setFillType(SkPath::kEvenOdd_FillType); 73 SkASSERT(!fConcavePath.isConvex()); 74 } 75 canvas->drawPath(fConcavePath, paint); 76 break; 77 } 78 } 79 80 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { 81 if (NULL == fBG.get()) { 82 static uint32_t kCheckerPixelData[] = { 0xFFFFFFFF, 83 0xFFCCCCCC, 84 0xFFCCCCCC, 85 0xFFFFFFFF }; 86 SkBitmap bitmap; 87 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2, 2 * sizeof(uint32_t)); 88 bitmap.allocPixels(); 89 bitmap.lockPixels(); 90 memcpy(bitmap.getPixels(), kCheckerPixelData, sizeof(kCheckerPixelData)); 91 bitmap.unlockPixels(); 92 fBG.reset(SkShader::CreateBitmapShader(bitmap, 93 SkShader::kRepeat_TileMode, 94 SkShader::kRepeat_TileMode)); 95 } 96 SkMatrix lm; 97 lm.setScale(SkIntToScalar(20), SkIntToScalar(20)); 98 fBG->setLocalMatrix(lm); 99 100 SkPaint bgPaint; 101 bgPaint.setShader(fBG.get()); 102 canvas->drawPaint(bgPaint); 103 SkISize size = canvas->getDeviceSize(); 104 SkScalar maxScale = SkScalarSqrt((SkIntToScalar(size.fWidth * size.fHeight))) / 300; 105 SkMWCRandom random; 106 for (int i = 0; i < kNumShapes; ++i) { 107 SkScalar s = random.nextRangeScalar(SK_Scalar1 / 8, SK_Scalar1) * maxScale; 108 SkScalar r = random.nextRangeScalar(0, SkIntToScalar(360)); 109 SkScalar dx = random.nextRangeScalar(0, SkIntToScalar(size.fWidth)); 110 SkScalar dy = random.nextRangeScalar(0, SkIntToScalar(size.fHeight)); 111 SkColor color = random.nextU(); 112 SkXfermode::Mode mode = 113 static_cast<SkXfermode::Mode>(random.nextULessThan(SkXfermode::kLastMode + 1)); 114 115 SkPaint p; 116 p.setAntiAlias(true); 117 p.setColor(color); 118 p.setXfermodeMode(mode); 119 canvas->save(); 120 canvas->translate(dx, dy); 121 canvas->scale(s, s); 122 canvas->rotate(r); 123 this->drawShape(canvas, p, &random); 124 canvas->restore(); 125 } 126 } 127 128 private: 129 enum { 130 kNumShapes = 100, 131 }; 132 SkAutoTUnref<SkShader> fBG; 133 SkPath fConcavePath; 134 SkPath fConvexPath; 135 typedef GM INHERITED; 136 }; 137 138 ////////////////////////////////////////////////////////////////////////////// 139 140 static GM* MyFactory(void*) { return new MixedXfermodesGM; } 141 static GMRegistry reg(MyFactory); 142 143 } 144