blob: 4fba80f365752d1a1f2fd83a7edc66f6003ffaf2 [file] [log] [blame]
joshualitt5ce33c12015-01-28 11:08:00 -08001/*
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 */
Mike Kleinc0bd9f92019-04-23 12:05:21 -05007#include "gm/gm.h"
8#include "include/core/SkBitmap.h"
9#include "include/core/SkPath.h"
10#include "include/core/SkShader.h"
11#include "include/core/SkSurface.h"
12#include "include/utils/SkRandom.h"
13#include "tools/ToolUtils.h"
joshualitt5ce33c12015-01-28 11:08:00 -080014
15namespace skiagm {
16
17/**
18 * Renders overlapping shapes with colorburn against a checkerboard.
19 */
20class DstReadShuffle : public GM {
21public:
Brian Salomond02b6f32017-03-17 10:41:39 -040022 DstReadShuffle() { this->setBGColor(kBackground); }
joshualitt5ce33c12015-01-28 11:08:00 -080023
24protected:
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
mtklein36352bf2015-03-25 18:17:31 -070035 SkString onShortName() override {
joshualitt5ce33c12015-01-28 11:08:00 -080036 return SkString("dstreadshuffle");
37 }
38
mtklein36352bf2015-03-25 18:17:31 -070039 SkISize onISize() override {
Brian Salomon8336e942017-03-15 15:37:43 -040040 return SkISize::Make(530, 680);
joshualitt5ce33c12015-01-28 11:08:00 -080041 }
42
Brian Salomon8336e942017-03-15 15:37:43 -040043 void drawShape(SkCanvas* canvas, SkPaint* paint, ShapeType type) {
44 const SkRect kRect = SkRect::MakeXYWH(0, 0, 75.f, 85.f);
joshualitt5ce33c12015-01-28 11:08:00 -080045 switch (type) {
46 case kCircle_ShapeType:
Brian Salomon8336e942017-03-15 15:37:43 -040047 canvas->drawCircle(kRect.centerX(), kRect.centerY(), kRect.width() / 2.f, *paint);
joshualitt5ce33c12015-01-28 11:08:00 -080048 break;
49 case kRoundRect_ShapeType:
Brian Salomon8336e942017-03-15 15:37:43 -040050 canvas->drawRoundRect(kRect, 15.f, 15.f, *paint);
joshualitt5ce33c12015-01-28 11:08:00 -080051 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()) {
Brian Salomon8336e942017-03-15 15:37:43 -040068 SkPoint points[5] = {{50.f, 0.f}};
joshualitt5ce33c12015-01-28 11:08:00 -080069 SkMatrix rot;
Brian Salomon8336e942017-03-15 15:37:43 -040070 rot.setRotate(360.f / 5, 50.f, 70.f);
joshualitt5ce33c12015-01-28 11:08:00 -080071 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: {
Brian Salomon8336e942017-03-15 15:37:43 -040084 const char* text = "N";
Mike Kleinea3f0142019-03-20 11:12:10 -050085 SkFont font(ToolUtils::create_portable_typeface(), 100);
Hal Canary6ac0df82019-01-07 16:01:22 -050086 font.setEmbolden(true);
87 canvas->drawString(text, 0.f, 100.f, font, *paint);
joshualitt5ce33c12015-01-28 11:08:00 -080088 }
89 default:
90 break;
91 }
92 }
93
Brian Salomon8336e942017-03-15 15:37:43 -040094 static SkColor GetColor(SkRandom* random) {
Mike Kleinea3f0142019-03-20 11:12:10 -050095 SkColor color = ToolUtils::color_to_565(random->nextU() | 0xFF000000);
Brian Salomon8336e942017-03-15 15:37:43 -040096 return SkColorSetA(color, 0x80);
joshualitt5ce33c12015-01-28 11:08:00 -080097 }
98
Brian Salomon8336e942017-03-15 15:37:43 -040099 static void DrawHairlines(SkCanvas* canvas) {
Brian Salomond02b6f32017-03-17 10:41:39 -0400100 if (canvas->imageInfo().alphaType() == kOpaque_SkAlphaType) {
101 canvas->clear(kBackground);
102 } else {
103 canvas->clear(SK_ColorTRANSPARENT);
104 }
Brian Salomon8336e942017-03-15 15:37:43 -0400105 SkPaint hairPaint;
106 hairPaint.setStyle(SkPaint::kStroke_Style);
107 hairPaint.setStrokeWidth(0);
108 hairPaint.setAntiAlias(true);
109 static constexpr int kNumHairlines = 12;
110 SkPoint pts[] = {{3.f, 7.f}, {29.f, 7.f}};
111 SkRandom colorRandom;
112 SkMatrix rot;
113 rot.setRotate(360.f / kNumHairlines, 15.5f, 12.f);
114 rot.postTranslate(3.f, 0);
115 for (int i = 0; i < 12; ++i) {
116 hairPaint.setColor(GetColor(&colorRandom));
Hal Canary23e474c2017-05-15 13:35:35 -0400117 canvas->drawLine(pts[0], pts[1], hairPaint);
Brian Salomon8336e942017-03-15 15:37:43 -0400118 rot.mapPoints(pts, 2);
joshualitt5ce33c12015-01-28 11:08:00 -0800119 }
120 }
121
mtklein36352bf2015-03-25 18:17:31 -0700122 void onDraw(SkCanvas* canvas) override {
Brian Salomon8336e942017-03-15 15:37:43 -0400123 SkScalar y = 5;
joshualitt5ce33c12015-01-28 11:08:00 -0800124 for (int i = 0; i < kNumShapeTypes; i++) {
Brian Salomon8336e942017-03-15 15:37:43 -0400125 SkRandom colorRandom;
joshualitt5ce33c12015-01-28 11:08:00 -0800126 ShapeType shapeType = static_cast<ShapeType>(i);
Brian Salomon8336e942017-03-15 15:37:43 -0400127 SkScalar x = 5;
128 for (int r = 0; r <= 15; r++) {
129 SkPaint p;
130 p.setAntiAlias(true);
131 p.setColor(GetColor(&colorRandom));
132 // In order to get some op combining on the GPU backend we do 2 src over
133 // for each xfer mode which requires a dst read
134 p.setBlendMode(r % 3 == 0 ? SkBlendMode::kColorBurn : SkBlendMode::kSrcOver);
135 canvas->save();
136 canvas->translate(x, y);
137 this->drawShape(canvas, &p, shapeType);
138 canvas->restore();
139 x += 15;
joshualitt5ce33c12015-01-28 11:08:00 -0800140 }
Brian Salomon8336e942017-03-15 15:37:43 -0400141 y += 110;
joshualitt5ce33c12015-01-28 11:08:00 -0800142 }
Brian Salomon8336e942017-03-15 15:37:43 -0400143 // Draw hairlines to a surface and then draw that to the main canvas with a zoom so that
144 // it is easier to see how they blend.
145 SkImageInfo info;
Brian Salomond02b6f32017-03-17 10:41:39 -0400146 // Recording canvases don't have a color type.
147 if (SkColorType::kUnknown_SkColorType == canvas->imageInfo().colorType()) {
148 info = SkImageInfo::MakeN32Premul(35, 35);
149 } else {
Brian Salomon8336e942017-03-15 15:37:43 -0400150 info = SkImageInfo::Make(35, 35,
151 canvas->imageInfo().colorType(),
152 canvas->imageInfo().alphaType(),
153 canvas->imageInfo().refColorSpace());
Brian Salomon8336e942017-03-15 15:37:43 -0400154 }
155 auto surf = canvas->makeSurface(info);
Cary Clarka24712e2018-09-05 18:41:40 +0000156 if (!surf) {
157 // Fall back to raster. Raster supports only one of the 8 bit per-channel RGBA or BGRA
158 // formats. This fall back happens when running with --preAbandonGpuContext.
159 if ((info.colorType() == kRGBA_8888_SkColorType ||
160 info.colorType() == kBGRA_8888_SkColorType) &&
161 info.colorType() != kN32_SkColorType) {
162 info = SkImageInfo::Make(35, 35,
163 kN32_SkColorType,
164 canvas->imageInfo().alphaType(),
165 canvas->imageInfo().refColorSpace());
166 }
167 surf = SkSurface::MakeRaster(info);
168 SkASSERT(surf);
169 }
Brian Salomon8336e942017-03-15 15:37:43 -0400170 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);
joshualitt5ce33c12015-01-28 11:08:00 -0800174 }
175
176private:
Brian Salomond02b6f32017-03-17 10:41:39 -0400177 static constexpr SkColor kBackground = SK_ColorLTGRAY;
Brian Salomon8336e942017-03-15 15:37:43 -0400178 SkPath fConcavePath;
179 SkPath fConvexPath;
joshualitt5ce33c12015-01-28 11:08:00 -0800180 typedef GM INHERITED;
181};
182
183//////////////////////////////////////////////////////////////////////////////
184
Hal Canarye964c182019-01-23 10:22:01 -0500185DEF_GM( return new DstReadShuffle; )
joshualitt5ce33c12015-01-28 11:08:00 -0800186
187}