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