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 SkISize::Make(790, 640); 31 } 32 33 void drawShape(SkCanvas* canvas, 34 const SkPaint& paint, 35 SkRandom* 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.allocN32Pixels(2, 2); 88 memcpy(bitmap.getPixels(), kCheckerPixelData, sizeof(kCheckerPixelData)); 89 SkMatrix lm; 90 lm.setScale(SkIntToScalar(20), SkIntToScalar(20)); 91 fBG.reset(SkShader::CreateBitmapShader(bitmap, 92 SkShader::kRepeat_TileMode, 93 SkShader::kRepeat_TileMode, 94 &lm)); 95 } 96 97 SkPaint bgPaint; 98 bgPaint.setShader(fBG.get()); 99 canvas->drawPaint(bgPaint); 100 SkISize size = canvas->getDeviceSize(); 101 SkScalar maxScale = SkScalarSqrt((SkIntToScalar(size.fWidth * size.fHeight))) / 300; 102 SkRandom random; 103 for (int i = 0; i < kNumShapes; ++i) { 104 SkScalar s = random.nextRangeScalar(SK_Scalar1 / 8, SK_Scalar1) * maxScale; 105 SkScalar r = random.nextRangeScalar(0, SkIntToScalar(360)); 106 SkScalar dx = random.nextRangeScalar(0, SkIntToScalar(size.fWidth)); 107 SkScalar dy = random.nextRangeScalar(0, SkIntToScalar(size.fHeight)); 108 SkColor color = random.nextU(); 109 SkXfermode::Mode mode = 110 static_cast<SkXfermode::Mode>(random.nextULessThan(SkXfermode::kLastMode + 1)); 111 112 SkPaint p; 113 p.setAntiAlias(true); 114 p.setColor(color); 115 p.setXfermodeMode(mode); 116 canvas->save(); 117 canvas->translate(dx, dy); 118 canvas->scale(s, s); 119 canvas->rotate(r); 120 this->drawShape(canvas, p, &random); 121 canvas->restore(); 122 } 123 } 124 125 virtual uint32_t onGetFlags() const { 126 // Skip PDF rasterization since rendering this PDF takes forever. 127 return kSkipPDFRasterization_Flag | kSkipTiled_Flag; 128 } 129 130 private: 131 enum { 132 kNumShapes = 100, 133 }; 134 SkAutoTUnref<SkShader> fBG; 135 SkPath fConcavePath; 136 SkPath fConvexPath; 137 typedef GM INHERITED; 138 }; 139 140 ////////////////////////////////////////////////////////////////////////////// 141 142 static GM* MyFactory(void*) { return new MixedXfermodesGM; } 143 static GMRegistry reg(MyFactory); 144 145 } 146