• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 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 "gm.h"
8 #include "sk_tool_utils.h"
9 #include "SkBitmap.h"
10 #include "SkPath.h"
11 #include "SkRandom.h"
12 #include "SkShader.h"
13 #include "SkSurface.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() { this->setBGColor(kBackground); }
23 
24 protected:
25     enum ShapeType {
26         kCircle_ShapeType,
27         kRoundRect_ShapeType,
28         kRect_ShapeType,
29         kConvexPath_ShapeType,
30         kConcavePath_ShapeType,
31         kText_ShapeType,
32         kNumShapeTypes
33     };
34 
onShortName()35     SkString onShortName() override {
36         return SkString("dstreadshuffle");
37     }
38 
onISize()39     SkISize onISize() override {
40         return SkISize::Make(530, 680);
41     }
42 
drawShape(SkCanvas * canvas,SkPaint * paint,ShapeType type)43     void drawShape(SkCanvas* canvas, SkPaint* paint, ShapeType type) {
44         const SkRect kRect = SkRect::MakeXYWH(0, 0, 75.f, 85.f);
45         switch (type) {
46             case kCircle_ShapeType:
47                 canvas->drawCircle(kRect.centerX(), kRect.centerY(), kRect.width() / 2.f, *paint);
48                 break;
49             case kRoundRect_ShapeType:
50                 canvas->drawRoundRect(kRect, 15.f, 15.f, *paint);
51                 break;
52             case kRect_ShapeType:
53                 canvas->drawRect(kRect, *paint);
54                 break;
55             case kConvexPath_ShapeType:
56                 if (fConvexPath.isEmpty()) {
57                     SkPoint points[4];
58                     kRect.toQuad(points);
59                     fConvexPath.moveTo(points[0]);
60                     fConvexPath.quadTo(points[1], points[2]);
61                     fConvexPath.quadTo(points[3], points[0]);
62                     SkASSERT(fConvexPath.isConvex());
63                 }
64                 canvas->drawPath(fConvexPath, *paint);
65                 break;
66             case kConcavePath_ShapeType:
67                 if (fConcavePath.isEmpty()) {
68                     SkPoint points[5] = {{50.f, 0.f}};
69                     SkMatrix rot;
70                     rot.setRotate(360.f / 5, 50.f, 70.f);
71                     for (int i = 1; i < 5; ++i) {
72                         rot.mapPoints(points + i, points + i - 1, 1);
73                     }
74                     fConcavePath.moveTo(points[0]);
75                     for (int i = 0; i < 5; ++i) {
76                         fConcavePath.lineTo(points[(2 * i) % 5]);
77                     }
78                     fConcavePath.setFillType(SkPath::kEvenOdd_FillType);
79                     SkASSERT(!fConcavePath.isConvex());
80                 }
81                 canvas->drawPath(fConcavePath, *paint);
82                 break;
83             case kText_ShapeType: {
84                 const char* text = "N";
85                 paint->setTextSize(100.f);
86                 paint->setFakeBoldText(true);
87                 sk_tool_utils::set_portable_typeface(paint);
88                 canvas->drawString(text, 0.f, 100.f, *paint);
89             }
90             default:
91                 break;
92         }
93     }
94 
GetColor(SkRandom * random)95     static SkColor GetColor(SkRandom* random) {
96         SkColor color = sk_tool_utils::color_to_565(random->nextU() | 0xFF000000);
97         return SkColorSetA(color, 0x80);
98     }
99 
DrawHairlines(SkCanvas * canvas)100     static void DrawHairlines(SkCanvas* canvas) {
101         if (canvas->imageInfo().alphaType() == kOpaque_SkAlphaType) {
102             canvas->clear(kBackground);
103         } else {
104             canvas->clear(SK_ColorTRANSPARENT);
105         }
106         SkPaint hairPaint;
107         hairPaint.setStyle(SkPaint::kStroke_Style);
108         hairPaint.setStrokeWidth(0);
109         hairPaint.setAntiAlias(true);
110         static constexpr int kNumHairlines = 12;
111         SkPoint pts[] = {{3.f, 7.f}, {29.f, 7.f}};
112         SkRandom colorRandom;
113         SkMatrix rot;
114         rot.setRotate(360.f / kNumHairlines, 15.5f, 12.f);
115         rot.postTranslate(3.f, 0);
116         for (int i = 0; i < 12; ++i) {
117             hairPaint.setColor(GetColor(&colorRandom));
118             canvas->drawLine(pts[0], pts[1], hairPaint);
119             rot.mapPoints(pts, 2);
120         }
121     }
122 
onDraw(SkCanvas * canvas)123     void onDraw(SkCanvas* canvas) override {
124         SkScalar y = 5;
125         for (int i = 0; i < kNumShapeTypes; i++) {
126             SkRandom colorRandom;
127             ShapeType shapeType = static_cast<ShapeType>(i);
128             SkScalar x = 5;
129             for (int r = 0; r <= 15; r++) {
130                 SkPaint p;
131                 p.setAntiAlias(true);
132                 p.setColor(GetColor(&colorRandom));
133                 // In order to get some op combining on the GPU backend we do 2 src over
134                 // for each xfer mode which requires a dst read
135                 p.setBlendMode(r % 3 == 0 ? SkBlendMode::kColorBurn : SkBlendMode::kSrcOver);
136                 canvas->save();
137                 canvas->translate(x, y);
138                 this->drawShape(canvas, &p, shapeType);
139                 canvas->restore();
140                 x += 15;
141             }
142             y += 110;
143         }
144         // Draw hairlines to a surface and then draw that to the main canvas with a zoom so that
145         // it is easier to see how they blend.
146         SkImageInfo info;
147         // Recording canvases don't have a color type.
148         if (SkColorType::kUnknown_SkColorType == canvas->imageInfo().colorType()) {
149             info = SkImageInfo::MakeN32Premul(35, 35);
150         } else {
151             info = SkImageInfo::Make(35, 35,
152                                      canvas->imageInfo().colorType(),
153                                      canvas->imageInfo().alphaType(),
154                                      canvas->imageInfo().refColorSpace());
155         }
156         auto surf = canvas->makeSurface(info);
157         if (!surf) {
158             // Fall back to raster. Raster supports only one of the 8 bit per-channel RGBA or BGRA
159             // formats. This fall back happens when running with --preAbandonGpuContext.
160             if ((info.colorType() == kRGBA_8888_SkColorType ||
161                  info.colorType() == kBGRA_8888_SkColorType) &&
162                 info.colorType() != kN32_SkColorType) {
163                 info = SkImageInfo::Make(35, 35,
164                                          kN32_SkColorType,
165                                          canvas->imageInfo().alphaType(),
166                                          canvas->imageInfo().refColorSpace());
167             }
168             surf = SkSurface::MakeRaster(info);
169         }
170         canvas->scale(5.f, 5.f);
171         canvas->translate(67.f, 10.f);
172         DrawHairlines(surf->getCanvas());
173         canvas->drawImage(surf->makeImageSnapshot(), 0.f, 0.f);
174     }
175 
176 private:
177     static constexpr SkColor kBackground = SK_ColorLTGRAY;
178     SkPath fConcavePath;
179     SkPath fConvexPath;
180     typedef GM INHERITED;
181 };
182 
183 //////////////////////////////////////////////////////////////////////////////
184 
MyFactory(void *)185 static GM* MyFactory(void*) { return new DstReadShuffle; }
186 static GMRegistry reg(MyFactory);
187 
188 }
189