2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkColorPriv.h"
14 #include "include/core/SkColorSpace.h"
15 #include "include/core/SkFont.h"
16 #include "include/core/SkImageInfo.h"
17 #include "include/core/SkMatrix.h"
18 #include "include/core/SkPaint.h"
19 #include "include/core/SkPoint.h"
20 #include "include/core/SkRect.h"
21 #include "include/core/SkRefCnt.h"
22 #include "include/core/SkScalar.h"
23 #include "include/core/SkShader.h"
24 #include "include/core/SkSize.h"
25 #include "include/core/SkString.h"
26 #include "include/core/SkSurface.h"
27 #include "include/core/SkTileMode.h"
28 #include "include/core/SkTypeface.h"
29 #include "include/core/SkTypes.h"
30 #include "include/effects/SkGradientShader.h"
31 #include "tools/ToolUtils.h"
38 * This tests drawing device-covering rects with solid colors and bitmap shaders over a
39 * checkerboard background using different xfermodes.
41 class Xfermodes3GM : public GM {
43 Xfermodes3GM() { this->setBGColor(ToolUtils::color_to_565(0xFF70D0E0)); }
46 SkString onShortName() override {
47 return SkString("xfermodes3");
50 SkISize onISize() override {
51 return SkISize::Make(630, 1215);
54 void onDraw(SkCanvas* canvas) override {
55 canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
57 SkFont font(ToolUtils::create_portable_typeface());
60 constexpr SkColor kSolidColors[] = {
66 constexpr SkColor kBmpAlphas[] = {
71 auto tempSurface(this->makeTempSurface(canvas, kSize, kSize));
75 constexpr struct { SkPaint::Style fStyle; SkScalar fWidth; } kStrokes[] = {
76 {SkPaint::kFill_Style, 0},
77 {SkPaint::kStroke_Style, SkIntToScalar(kSize) / 2},
79 for (size_t s = 0; s < SK_ARRAY_COUNT(kStrokes); ++s) {
80 for (size_t m = 0; m < kSkBlendModeCount; ++m) {
81 SkBlendMode mode = static_cast<SkBlendMode>(m);
82 canvas->drawString(SkBlendMode_Name(mode),
84 SkIntToScalar(y + kSize + 3) + font.getSize(),
86 for (size_t c = 0; c < SK_ARRAY_COUNT(kSolidColors); ++c) {
88 modePaint.setBlendMode(mode);
89 modePaint.setColor(kSolidColors[c]);
90 modePaint.setStyle(kStrokes[s].fStyle);
91 modePaint.setStrokeWidth(kStrokes[s].fWidth);
93 this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempSurface.get());
97 if (!(test % kTestsPerRow)) {
102 for (size_t a = 0; a < SK_ARRAY_COUNT(kBmpAlphas); ++a) {
104 modePaint.setBlendMode(mode);
105 modePaint.setAlpha(kBmpAlphas[a]);
106 modePaint.setShader(fBmpShader);
107 modePaint.setStyle(kStrokes[s].fStyle);
108 modePaint.setStrokeWidth(kStrokes[s].fWidth);
110 this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempSurface.get());
114 if (!(test % kTestsPerRow)) {
125 * GrContext has optimizations around full rendertarget draws that can be replaced with clears.
126 * We are trying to test those. We could use saveLayer() to create small SkGpuDevices but
127 * saveLayer() uses the texture cache. This means that the actual render target may be larger
128 * than the layer. Because the clip will contain the layer's bounds, no draws will be full-RT.
129 * So explicitly create a temporary canvas with dimensions exactly the layer size.
131 sk_sp<SkSurface> makeTempSurface(SkCanvas* baseCanvas, int w, int h) {
132 SkImageInfo baseInfo = baseCanvas->imageInfo();
133 SkImageInfo info = SkImageInfo::Make(w, h, baseInfo.colorType(), baseInfo.alphaType(),
134 baseInfo.refColorSpace());
135 return baseCanvas->makeSurface(info);
138 void drawMode(SkCanvas* canvas,
139 int x, int y, int w, int h,
140 const SkPaint& modePaint, SkSurface* surface) {
142 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
144 SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h));
146 SkCanvas* modeCanvas;
147 if (nullptr == surface) {
148 canvas->saveLayer(&r, nullptr);
152 modeCanvas = surface->getCanvas();
156 bgPaint.setAntiAlias(false);
157 bgPaint.setShader(fBGShader);
158 modeCanvas->drawRect(r, bgPaint);
159 modeCanvas->drawRect(r, modePaint);
160 modeCanvas = nullptr;
162 if (nullptr == surface) {
165 surface->draw(canvas, 0, 0);
168 r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
170 borderPaint.setStyle(SkPaint::kStroke_Style);
171 canvas->drawRect(r, borderPaint);
176 void onOnceBeforeDraw() override {
177 const uint32_t kCheckData[] = {
178 SkPackARGB32(0xFF, 0x42, 0x41, 0x42),
179 SkPackARGB32(0xFF, 0xD6, 0xD3, 0xD6),
180 SkPackARGB32(0xFF, 0xD6, 0xD3, 0xD6),
181 SkPackARGB32(0xFF, 0x42, 0x41, 0x42)
184 bg.allocN32Pixels(2, 2, true);
185 memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData));
188 lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize));
189 fBGShader = bg.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
190 SkSamplingOptions(), lm);
193 const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 };
194 const SkColor kColors[] = {
195 SK_ColorTRANSPARENT, 0x80800000, 0xF020F060, SK_ColorWHITE
197 bmpPaint.setShader(SkGradientShader::MakeRadial(kCenter, 3 * SkIntToScalar(kSize) / 4,
198 kColors, nullptr, SK_ARRAY_COUNT(kColors),
199 SkTileMode::kRepeat));
202 bmp.allocN32Pixels(kSize, kSize);
203 SkCanvas bmpCanvas(bmp);
205 bmpCanvas.clear(SK_ColorTRANSPARENT);
206 SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8,
207 7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8};
208 bmpCanvas.drawRect(rect, bmpPaint);
210 fBmpShader = bmp.makeShader(SkSamplingOptions());
219 sk_sp<SkShader> fBGShader;
220 sk_sp<SkShader> fBmpShader;
222 using INHERITED = GM;
225 //////////////////////////////////////////////////////////////////////////////
227 DEF_GM(return new Xfermodes3GM;)
229 } // namespace skiagm