xref: /aosp_15_r20/external/skia/gm/drawbitmaprect.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2011 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/SkFont.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkMaskFilter.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 "include/gpu/ganesh/GrDirectContext.h"
32 #include "src/base/SkMathPriv.h"
33 #include "src/core/SkBlurMask.h"
34 #include "tools/GpuToolUtils.h"
35 #include "tools/ToolUtils.h"
36 #include "tools/fonts/FontToolUtils.h"
37 
make_chessbm(int w,int h)38 static SkBitmap make_chessbm(int w, int h) {
39     SkBitmap bm;
40     bm.allocN32Pixels(w, h);
41 
42     for (int y = 0; y < bm.height(); y++) {
43         uint32_t* p = bm.getAddr32(0, y);
44         for (int x = 0; x < bm.width(); x++) {
45             p[x] = ((x + y) & 1) ? SK_ColorWHITE : SK_ColorBLACK;
46         }
47     }
48     bm.setImmutable();
49     return bm;
50 }
51 
52 // Creates a bitmap and a matching image.
makebm(SkCanvas * origCanvas,SkBitmap * resultBM,int w,int h)53 static sk_sp<SkImage> makebm(SkCanvas* origCanvas, SkBitmap* resultBM, int w, int h) {
54     SkImageInfo info = SkImageInfo::MakeN32Premul(w, h);
55 
56     auto      surface(ToolUtils::makeSurface(origCanvas, info));
57     SkCanvas* canvas = surface->getCanvas();
58 
59     canvas->clear(SK_ColorTRANSPARENT);
60 
61     SkScalar wScalar = SkIntToScalar(w);
62     SkScalar hScalar = SkIntToScalar(h);
63 
64     SkPoint     pt = { wScalar / 2, hScalar / 2 };
65 
66     SkScalar    radius = 4 * std::max(wScalar, hScalar);
67 
68     SkColor     colors[] = { SK_ColorRED, SK_ColorYELLOW,
69                              SK_ColorGREEN, SK_ColorMAGENTA,
70                              SK_ColorBLUE, SK_ColorCYAN,
71                              SK_ColorRED};
72 
73     SkScalar    pos[] = {0,
74                          SK_Scalar1 / 6,
75                          2 * SK_Scalar1 / 6,
76                          3 * SK_Scalar1 / 6,
77                          4 * SK_Scalar1 / 6,
78                          5 * SK_Scalar1 / 6,
79                          SK_Scalar1};
80 
81     SkPaint     paint;
82     SkRect rect = SkRect::MakeWH(wScalar, hScalar);
83     SkMatrix mat = SkMatrix::I();
84     for (int i = 0; i < 4; ++i) {
85         paint.setShader(SkGradientShader::MakeRadial(
86                         pt, radius,
87                         colors, pos,
88                         std::size(colors),
89                         SkTileMode::kRepeat,
90                         0, &mat));
91         canvas->drawRect(rect, paint);
92         rect.inset(wScalar / 8, hScalar / 8);
93         mat.postScale(SK_Scalar1 / 4, SK_Scalar1 / 4);
94     }
95 
96     auto image = surface->makeImageSnapshot();
97 
98     SkBitmap tempBM;
99 
100     image->asLegacyBitmap(&tempBM);
101 
102     // Let backends know we won't change this, so they don't have to deep copy it defensively.
103     tempBM.setImmutable();
104     *resultBM = tempBM;
105 
106     return image;
107 }
108 
bitmapproc(SkCanvas * canvas,sk_sp<SkImage> image,const SkBitmap &,const SkIRect & srcR,const SkRect & dstR,const SkSamplingOptions & sampling,const SkPaint * paint)109 static void bitmapproc(SkCanvas* canvas, sk_sp<SkImage> image,
110                        const SkBitmap&, const SkIRect& srcR,
111                        const SkRect& dstR, const SkSamplingOptions& sampling,
112                        const SkPaint* paint) {
113     canvas->drawImageRect(image, SkRect::Make(srcR), dstR, sampling, paint,
114                           SkCanvas::kStrict_SrcRectConstraint);
115 }
116 
bitmapsubsetproc(SkCanvas * canvas,sk_sp<SkImage> image,const SkBitmap & bm,const SkIRect & srcR,const SkRect & dstR,const SkSamplingOptions & sampling,const SkPaint * paint)117 static void bitmapsubsetproc(SkCanvas* canvas, sk_sp<SkImage> image,
118                              const SkBitmap& bm, const SkIRect& srcR,
119                              const SkRect& dstR, const SkSamplingOptions& sampling,
120                              const SkPaint* paint) {
121     if (!bm.bounds().contains(srcR)) {
122         bitmapproc(canvas, std::move(image), bm, srcR, dstR, sampling, paint);
123         return;
124     }
125 
126     SkBitmap subset;
127     if (bm.extractSubset(&subset, srcR)) {
128         sk_sp<SkImage> subsetImg = ToolUtils::MakeTextureImage(canvas, subset.asImage());
129         canvas->drawImageRect(subsetImg, dstR, sampling, paint);
130     }
131 }
132 
imageproc(SkCanvas * canvas,sk_sp<SkImage> image,const SkBitmap &,const SkIRect & srcR,const SkRect & dstR,const SkSamplingOptions & sampling,const SkPaint * paint)133 static void imageproc(SkCanvas* canvas, sk_sp<SkImage> image, const SkBitmap&, const SkIRect& srcR,
134                       const SkRect& dstR, const SkSamplingOptions& sampling, const SkPaint* paint) {
135     sk_sp<SkImage> tmp = ToolUtils::MakeTextureImage(canvas, std::move(image));
136     canvas->drawImageRect(tmp, SkRect::Make(srcR), dstR, sampling, paint,
137                           SkCanvas::kStrict_SrcRectConstraint);
138 }
139 
imagesubsetproc(SkCanvas * canvas,sk_sp<SkImage> image,const SkBitmap & bm,const SkIRect & srcR,const SkRect & dstR,const SkSamplingOptions & sampling,const SkPaint * paint)140 static void imagesubsetproc(SkCanvas* canvas, sk_sp<SkImage> image, const SkBitmap& bm,
141                             const SkIRect& srcR, const SkRect& dstR,
142                             const SkSamplingOptions& sampling, const SkPaint* paint) {
143     SkASSERT_RELEASE(image);
144     if (!image->bounds().contains(srcR)) {
145         imageproc(canvas, std::move(image), bm, srcR, dstR, sampling, paint);
146         return;
147     }
148 
149     auto direct = GrAsDirectContext(canvas->recordingContext());
150     if (sk_sp<SkImage> subset = image->makeSubset(direct, srcR)) {
151         canvas->drawImageRect(subset, dstR, sampling, paint);
152         return;
153     }
154 #if defined(SK_GRAPHITE)
155     if (sk_sp<SkImage> subset = image->makeSubset(canvas->recorder(), srcR, {})) {
156         canvas->drawImageRect(subset, dstR, sampling, paint);
157     }
158 #endif
159 }
160 
161 typedef void DrawRectRectProc(SkCanvas*, sk_sp<SkImage>, const SkBitmap&,
162                               const SkIRect& srcR, const SkRect& dstR,
163                               const SkSamplingOptions&, const SkPaint*);
164 
165 constexpr int gSize = 1024;
166 constexpr int gBmpSize = 2048;
167 
168 class DrawBitmapRectGM : public skiagm::GM {
169 public:
DrawBitmapRectGM(DrawRectRectProc proc,const char suffix[])170     DrawBitmapRectGM(DrawRectRectProc proc, const char suffix[]) : fProc(proc) {
171         fName.set("drawbitmaprect");
172         if (suffix) {
173             fName.append(suffix);
174         }
175     }
176 
177     DrawRectRectProc*   fProc;
178     SkBitmap            fLargeBitmap;
179     sk_sp<SkImage>      fImage;
180     SkString            fName;
181 
182 protected:
getName() const183     SkString getName() const override { return fName; }
184 
getISize()185     SkISize getISize() override { return SkISize::Make(gSize, gSize); }
186 
onDraw(SkCanvas * canvas,SkString * errorMsg)187     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
188         if (!fImage || !fImage->isValid(canvas->recordingContext())) {
189             fImage = ToolUtils::MakeTextureImage(canvas,
190                                                  makebm(canvas, &fLargeBitmap, gBmpSize, gBmpSize));
191             if (!fImage) {
192                 *errorMsg = "Image creation failed";
193                 return DrawResult::kSkip;
194             }
195         }
196 
197         SkRect dstRect = { 0, 0, SkIntToScalar(64), SkIntToScalar(64)};
198         const int kMaxSrcRectSize = 1 << (SkNextLog2(gBmpSize) + 2);
199 
200         const int kPadX = 30;
201         const int kPadY = 40;
202         SkPaint alphaPaint;
203         alphaPaint.setAlphaf(0.125f);
204         canvas->drawImageRect(fImage, SkRect::MakeIWH(gSize, gSize), SkSamplingOptions(),
205                               &alphaPaint);
206         canvas->translate(SK_Scalar1 * kPadX / 2,
207                           SK_Scalar1 * kPadY / 2);
208         SkPaint blackPaint;
209         SkScalar titleHeight = SK_Scalar1 * 24;
210         blackPaint.setColor(SK_ColorBLACK);
211         blackPaint.setAntiAlias(true);
212 
213         SkFont font(ToolUtils::DefaultPortableTypeface(), titleHeight);
214 
215         SkString title;
216         title.printf("Bitmap size: %d x %d", gBmpSize, gBmpSize);
217         canvas->drawString(title, 0, titleHeight, font, blackPaint);
218 
219         canvas->translate(0, SK_Scalar1 * kPadY / 2  + titleHeight);
220         int rowCount = 0;
221         canvas->save();
222         for (int w = 1; w <= kMaxSrcRectSize; w *= 4) {
223             for (int h = 1; h <= kMaxSrcRectSize; h *= 4) {
224 
225                 SkIRect srcRect = SkIRect::MakeXYWH((gBmpSize - w) / 2, (gBmpSize - h) / 2, w, h);
226                 fProc(canvas, fImage, fLargeBitmap, srcRect, dstRect, SkSamplingOptions(),
227                       nullptr);
228 
229                 SkString label;
230                 label.appendf("%d x %d", w, h);
231                 blackPaint.setAntiAlias(true);
232                 blackPaint.setStyle(SkPaint::kFill_Style);
233                 font.setSize(SK_Scalar1 * 10);
234                 SkScalar baseline = dstRect.height() + font.getSize() + SK_Scalar1 * 3;
235                 canvas->drawString(label, 0, baseline, font, blackPaint);
236                 blackPaint.setStyle(SkPaint::kStroke_Style);
237                 blackPaint.setStrokeWidth(SK_Scalar1);
238                 blackPaint.setAntiAlias(false);
239                 canvas->drawRect(dstRect, blackPaint);
240 
241                 canvas->translate(dstRect.width() + SK_Scalar1 * kPadX, 0);
242                 ++rowCount;
243                 if ((dstRect.width() + kPadX) * rowCount > gSize) {
244                     canvas->restore();
245                     canvas->translate(0, dstRect.height() + SK_Scalar1 * kPadY);
246                     canvas->save();
247                     rowCount = 0;
248                 }
249             }
250         }
251 
252         {
253             // test the following code path:
254             // SkGpuDevice::drawPath() -> SkGpuDevice::drawWithMaskFilter()
255             SkIRect srcRect;
256             SkPaint maskPaint;
257             SkBitmap bm = make_chessbm(5, 5);
258             sk_sp<SkImage> img = ToolUtils::MakeTextureImage(canvas, bm.asImage());
259 
260             srcRect.setXYWH(1, 1, 3, 3);
261             maskPaint.setMaskFilter(SkMaskFilter::MakeBlur(
262                 kNormal_SkBlurStyle,
263                 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5))));
264 
265             fProc(canvas, img, bm, srcRect, dstRect,
266                   SkSamplingOptions(SkFilterMode::kLinear), &maskPaint);
267         }
268 
269         return DrawResult::kOk;
270     }
271 
272 private:
273     using INHERITED = skiagm::GM;
274 };
275 
276 DEF_GM( return new DrawBitmapRectGM(bitmapproc      , nullptr); )
277 DEF_GM( return new DrawBitmapRectGM(bitmapsubsetproc, "-subset"); )
278 DEF_GM( return new DrawBitmapRectGM(imageproc       , "-imagerect"); )
279 DEF_GM( return new DrawBitmapRectGM(imagesubsetproc , "-imagerect-subset"); )
280