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