xref: /aosp_15_r20/external/skia/gm/alpha_image.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2017 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 
8 #include "gm/gm.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkBlurTypes.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkColorFilter.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkMaskFilter.h"
17 #include "include/core/SkPaint.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkShader.h"
20 #include "tools/DecodeUtils.h"
21 #include "tools/Resources.h"
22 
make_alpha_image(int w,int h)23 static SkBitmap make_alpha_image(int w, int h) {
24     SkBitmap bm;
25     bm.allocPixels(SkImageInfo::MakeA8(w, h));
26     bm.eraseARGB(10, 0, 0 , 0);
27     for (int y = 0; y < bm.height(); ++y) {
28         for (int x = y; x < bm.width(); ++x) {
29             *bm.getAddr8(x, y) = 0xFF;
30         }
31     }
32     bm.setImmutable();
33     return bm;
34 }
35 
make_color_filter()36 static sk_sp<SkColorFilter> make_color_filter() {
37     float colorMatrix[20] = {
38         1, 0, 0,   0,   0,
39         0, 1, 0,   0,   0,
40         0, 0, 0.5, 0.5, 0,
41         0, 0, 0.5, 0.5, 0}; // mix G and A.
42     return SkColorFilters::Matrix(colorMatrix);
43 }
44 
45 DEF_SIMPLE_GM(alpha_image, canvas, 256, 256) {
46     auto image = make_alpha_image(96, 96).asImage();
47     SkPaint paint;
48 
49     paint.setColorFilter(make_color_filter());
50     paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 10.0f));
51     canvas->drawImage(image.get(), 16, 16, SkSamplingOptions(), &paint);
52 
53     paint.setColorFilter(nullptr);
54     paint.setShader(SkShaders::Color(SK_ColorCYAN));
55     canvas->drawImage(image.get(), 144, 16, SkSamplingOptions(), &paint);
56 
57     paint.setColorFilter(make_color_filter());
58     canvas->drawImage(image.get(), 16, 144, SkSamplingOptions(), &paint);
59 
60     paint.setMaskFilter(nullptr);
61     canvas->drawImage(image.get(), 144, 144, SkSamplingOptions(), &paint);
62 }
63 
64 // Created to demonstrate skbug.com/10556 - GPU backend was failing to apply paint alpha to
65 // alpha-only image shaders. The two boxes should look the same.
66 DEF_SIMPLE_GM(alpha_image_alpha_tint, canvas, 152, 80) {
67     canvas->clear(SK_ColorGRAY);
68 
69     SkBitmap bm;
70     bm.allocPixels(SkImageInfo::MakeA8(64, 64));
71     for (int y = 0; y < bm.height(); ++y) {
72         for (int x = 0; x < bm.width(); ++x) {
73             *bm.getAddr8(x, y) = y * 4;
74         }
75     }
76     bm.setImmutable();
77     auto image = bm.asImage();
78 
79     SkPaint paint;
80     paint.setColor4f({ 0, 1, 0, 0.5f });
81 
82     canvas->translate(8, 8);
83     canvas->drawImage(image.get(), 0, 0, SkSamplingOptions(), &paint);
84 
85     canvas->translate(72, 0);
86     paint.setShader(image->makeShader(SkSamplingOptions()));
87     canvas->drawRect({ 0, 0, 64, 64 }, paint);
88 }
89 
90 #if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
91 // For a long time, the CPU backend treated A8 bitmaps as coverage, rather than alpha. This was
92 // inconsistent with the GPU backend (skbug.com/9692). When this was fixed, it altered behavior
93 // for some Android apps (b/231400686). This GM verifies that our Android framework workaround
94 // produces the old result (mandrill with a round-rect border).
95 DEF_SIMPLE_GM(alpha_bitmap_is_coverage_ANDROID, canvas, 128, 128) {
96     SkBitmap maskBitmap;
97     maskBitmap.allocPixels(SkImageInfo::MakeA8(128, 128));
98     {
99         SkCanvas maskCanvas(maskBitmap);
100         maskCanvas.clear(SK_ColorWHITE);
101 
102         SkPaint maskPaint;
103         maskPaint.setAntiAlias(true);
104         maskPaint.setColor(SK_ColorWHITE);
105         maskPaint.setBlendMode(SkBlendMode::kClear);
106         maskCanvas.drawRoundRect({0, 0, 128, 128}, 16, 16, maskPaint);
107     }
108 
109     SkBitmap offscreenBitmap;
110     offscreenBitmap.allocN32Pixels(128, 128);
111     {
112         SkCanvas offscreenCanvas(offscreenBitmap);
113         offscreenCanvas.drawImage(ToolUtils::GetResourceAsImage("images/mandrill_128.png"), 0, 0);
114 
115         SkPaint clearPaint;
116         clearPaint.setAntiAlias(true);
117         clearPaint.setBlendMode(SkBlendMode::kClear);
118         // At tip-of-tree (or at any time on the GPU backend), this draw produces full coverage,
119         // completely erasing the mandrill. With the workaround enabled, the alpha border is treated
120         // as coverage, so we only apply kClear to those pixels, just erasing the outer border.
121         offscreenCanvas.drawImage(maskBitmap.asImage(), 0, 0, SkSamplingOptions{}, &clearPaint);
122     }
123 
124     canvas->drawImage(offscreenBitmap.asImage(), 0, 0);
125 }
126 #endif
127