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 "SkPath.h"
11 #include "SkRandom.h"
12 #include "SkShader.h"
13 #include "SkXfermode.h"
14 
15 namespace skiagm {
16 
17 /**
18  * Renders overlapping shapes with colorburn against a checkerboard.
19  */
20 class DstReadShuffle : public GM {
21 public:
DstReadShuffle()22     DstReadShuffle() {
23        this->setBGColor(SkColorSetARGB(0xff, 0xff, 0, 0xff));
24     }
25 
26 protected:
27     enum ShapeType {
28         kCircle_ShapeType,
29         kRoundRect_ShapeType,
30         kRect_ShapeType,
31         kConvexPath_ShapeType,
32         kConcavePath_ShapeType,
33         kText_ShapeType,
34         kNumShapeTypes
35     };
36 
onShortName()37     SkString onShortName() override {
38         return SkString("dstreadshuffle");
39     }
40 
onISize()41     SkISize onISize() override {
42         return SkISize::Make(kWidth, kHeight);
43     }
44 
drawShape(SkCanvas * canvas,SkPaint * paint,ShapeType type)45     void drawShape(SkCanvas* canvas,
46                    SkPaint* paint,
47                    ShapeType type) {
48         static const SkRect kRect = SkRect::MakeXYWH(SkIntToScalar(-50), SkIntToScalar(-50),
49                                                      SkIntToScalar(75), SkIntToScalar(105));
50         switch (type) {
51             case kCircle_ShapeType:
52                 canvas->drawCircle(0, 0, 50, *paint);
53                 break;
54             case kRoundRect_ShapeType:
55                 canvas->drawRoundRect(kRect, SkIntToScalar(10), SkIntToScalar(20), *paint);
56                 break;
57             case kRect_ShapeType:
58                 canvas->drawRect(kRect, *paint);
59                 break;
60             case kConvexPath_ShapeType:
61                 if (fConvexPath.isEmpty()) {
62                     SkPoint points[4];
63                     kRect.toQuad(points);
64                     fConvexPath.moveTo(points[0]);
65                     fConvexPath.quadTo(points[1], points[2]);
66                     fConvexPath.quadTo(points[3], points[0]);
67                     SkASSERT(fConvexPath.isConvex());
68                 }
69                 canvas->drawPath(fConvexPath, *paint);
70                 break;
71             case kConcavePath_ShapeType:
72                 if (fConcavePath.isEmpty()) {
73                     SkPoint points[5] = {{0, SkIntToScalar(-50)} };
74                     SkMatrix rot;
75                     rot.setRotate(SkIntToScalar(360) / 5);
76                     for (int i = 1; i < 5; ++i) {
77                         rot.mapPoints(points + i, points + i - 1, 1);
78                     }
79                     fConcavePath.moveTo(points[0]);
80                     for (int i = 0; i < 5; ++i) {
81                         fConcavePath.lineTo(points[(2 * i) % 5]);
82                     }
83                     fConcavePath.setFillType(SkPath::kEvenOdd_FillType);
84                     SkASSERT(!fConcavePath.isConvex());
85                 }
86                 canvas->drawPath(fConcavePath, *paint);
87                 break;
88             case kText_ShapeType: {
89                 const char* text = "Hello!";
90                 paint->setTextSize(30);
91                 sk_tool_utils::set_portable_typeface(paint);
92                 canvas->drawText(text, strlen(text), 0, 0, *paint);
93             }
94             default:
95                 break;
96         }
97     }
98 
GetColor(SkRandom * random,int i,int nextColor)99     static SkColor GetColor(SkRandom* random, int i, int nextColor) {
100         static SkColor colors[] = { SK_ColorRED,
101                                     sk_tool_utils::color_to_565(0xFFFF7F00), // Orange
102                                     SK_ColorYELLOW,
103                                     SK_ColorGREEN,
104                                     SK_ColorBLUE,
105                                     sk_tool_utils::color_to_565(0xFF4B0082), // indigo
106                                     sk_tool_utils::color_to_565(0xFF7F00FF) }; // violet
107         SkColor color;
108         int index = nextColor % SK_ARRAY_COUNT(colors);
109         switch (i) {
110             case 0:
111                 color = SK_ColorTRANSPARENT;
112                 break;
113             case 1:
114                 color = SkColorSetARGB(0xff,
115                                        SkColorGetR(colors[index]),
116                                        SkColorGetG(colors[index]),
117                                        SkColorGetB(colors[index]));
118                 break;
119             default:
120                 uint8_t alpha = 0x80;
121                 color = SkColorSetARGB(alpha,
122                                        SkColorGetR(colors[index]),
123                                        SkColorGetG(colors[index]),
124                                        SkColorGetB(colors[index]));
125                 break;
126         }
127         return color;
128     }
129 
SetStyle(SkPaint * p,int style,int width)130     static void SetStyle(SkPaint* p, int style, int width) {
131         switch (style) {
132             case 0:
133                 p->setStyle(SkPaint::kStroke_Style);
134                 p->setStrokeWidth((SkScalar)width);
135                 break;
136             case 1:
137                 p->setStyle(SkPaint::kStrokeAndFill_Style);
138                 p->setStrokeWidth((SkScalar)width);
139                 break;
140             default:
141                 p->setStyle(SkPaint::kFill_Style);
142                 break;
143         }
144     }
145 
onDraw(SkCanvas * canvas)146     void onDraw(SkCanvas* canvas) override {
147         SkRandom random;
148         SkScalar y = 100;
149         for (int i = 0; i < kNumShapeTypes; i++) {
150             ShapeType shapeType = static_cast<ShapeType>(i);
151             SkScalar x = 25;
152             for (int style = 0; style < 3; style++) {
153                 for (int width = 0; width <= 1; width++) {
154                     for (int alpha = 0; alpha <= 2; alpha++) {
155                         for (int r = 0; r <= 5; r++) {
156                             SkColor color = GetColor(&random, alpha, style + width + alpha + r);
157 
158                             SkPaint p;
159                             p.setAntiAlias(true);
160                             p.setColor(color);
161                             // In order to get some batching on the GPU backend we do 2 src over for
162                             // each xfer mode which requires a dst read
163                             p.setXfermodeMode(r % 3 == 0 ? SkXfermode::kLighten_Mode :
164                                                            SkXfermode::kSrcOver_Mode);
165                             SetStyle(&p, style, width);
166                             canvas->save();
167                             canvas->translate(x, y);
168                             canvas->rotate((SkScalar)(r < 3 ? 10 : 0));
169                             this->drawShape(canvas, &p, shapeType);
170                             canvas->restore();
171                             x += 8;
172                         }
173                     }
174                 }
175             }
176             y += 50;
177         }
178     }
179 
180 private:
181     enum {
182         kNumShapes = 100,
183     };
184     SkAutoTUnref<SkShader> fBG;
185     SkPath                 fConcavePath;
186     SkPath                 fConvexPath;
187     static const int kWidth = 900;
188     static const int kHeight = 400;
189     typedef GM INHERITED;
190 };
191 
192 //////////////////////////////////////////////////////////////////////////////
193 
MyFactory(void *)194 static GM* MyFactory(void*) { return new DstReadShuffle; }
195 static GMRegistry reg(MyFactory);
196 
197 }
198