xref: /aosp_15_r20/external/skia/src/core/SkBlitter_A8.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2006 The Android Open Source Project
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 "src/core/SkBlitter_A8.h"
9 
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkColorType.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkRect.h"
14 #include "include/core/SkShader.h" // IWYU pragma: keep
15 #include "include/core/SkTypes.h"
16 #include "include/private/base/SkDebug.h"
17 #include "src/base/SkArenaAlloc.h"
18 #include "src/core/SkMask.h"
19 
20 #include <cstring>
21 #include <optional>
22 
SkA8_Coverage_Blitter(const SkPixmap & device,const SkPaint & paint)23 SkA8_Coverage_Blitter::SkA8_Coverage_Blitter(const SkPixmap& device, const SkPaint& paint)
24     : fDevice(device)
25 {
26     SkASSERT(nullptr == paint.getShader());
27     SkASSERT(nullptr == paint.getColorFilter());
28 }
29 
blitAntiH(int x,int y,const SkAlpha antialias[],const int16_t runs[])30 void SkA8_Coverage_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
31                                       const int16_t runs[]) {
32     uint8_t* device = fDevice.writable_addr8(x, y);
33     SkDEBUGCODE(int totalCount = 0;)
34 
35     for (;;) {
36         int count = runs[0];
37         SkASSERT(count >= 0);
38         if (count == 0) {
39             return;
40         }
41         if (antialias[0]) {
42             memset(device, antialias[0], count);
43         }
44         runs += count;
45         antialias += count;
46         device += count;
47 
48         SkDEBUGCODE(totalCount += count;)
49     }
50     SkASSERT(fDevice.width() == totalCount);
51 }
52 
blitH(int x,int y,int width)53 void SkA8_Coverage_Blitter::blitH(int x, int y, int width) {
54     memset(fDevice.writable_addr8(x, y), 0xFF, width);
55 }
56 
blitV(int x,int y,int height,SkAlpha alpha)57 void SkA8_Coverage_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
58     if (0 == alpha) {
59         return;
60     }
61 
62     uint8_t* dst = fDevice.writable_addr8(x, y);
63     const size_t dstRB = fDevice.rowBytes();
64     while (--height >= 0) {
65         *dst = alpha;
66         dst += dstRB;
67     }
68 }
69 
blitRect(int x,int y,int width,int height)70 void SkA8_Coverage_Blitter::blitRect(int x, int y, int width, int height) {
71     uint8_t* dst = fDevice.writable_addr8(x, y);
72     const size_t dstRB = fDevice.rowBytes();
73     while (--height >= 0) {
74         memset(dst, 0xFF, width);
75         dst += dstRB;
76     }
77 }
78 
blitMask(const SkMask & mask,const SkIRect & clip)79 void SkA8_Coverage_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
80     if (SkMask::kA8_Format != mask.fFormat) {
81         this->SkBlitter::blitMask(mask, clip);
82         return;
83     }
84 
85     int x = clip.fLeft;
86     int y = clip.fTop;
87     int width = clip.width();
88     int height = clip.height();
89 
90     uint8_t* dst = fDevice.writable_addr8(x, y);
91     const uint8_t* src = mask.getAddr8(x, y);
92     const size_t srcRB = mask.fRowBytes;
93     const size_t dstRB = fDevice.rowBytes();
94 
95     while (--height >= 0) {
96         memcpy(dst, src, width);
97         dst += dstRB;
98         src += srcRB;
99     }
100 }
101 
102 //////////////
103 
div255(unsigned prod)104 static inline uint8_t div255(unsigned prod) {
105     SkASSERT(prod <= 255*255);
106     return (prod + 128) * 257 >> 16;
107 }
108 
u8_lerp(uint8_t a,uint8_t b,uint8_t t)109 static inline unsigned u8_lerp(uint8_t a, uint8_t b, uint8_t t) {
110     return div255((255 - t) * a + t * b);
111 }
112 
113 using AlphaProc = uint8_t(*)(uint8_t src, uint8_t dst);
114 
srcover_p(uint8_t src,uint8_t dst)115 static uint8_t srcover_p (uint8_t src, uint8_t dst) { return src + div255((255 - src) * dst); }
src_p(uint8_t src,uint8_t dst)116 static uint8_t src_p     (uint8_t src, uint8_t dst) { return src; }
117 
A8_row_bw(uint8_t dst[],uint8_t src,int N,Mode proc)118 template <typename Mode> void A8_row_bw(uint8_t dst[], uint8_t src, int N, Mode proc) {
119     for (int i = 0; i < N; ++i) {
120         dst[i] = proc(src, dst[i]);
121     }
122 }
123 using A8_RowBlitBW = void(*)(uint8_t[], uint8_t, int);
124 
125 template <typename Mode>
A8_row_aa(uint8_t dst[],uint8_t src,int N,uint8_t aa,Mode proc,const bool canFoldAA)126 void A8_row_aa(uint8_t dst[], uint8_t src, int N, uint8_t aa, Mode proc, const bool canFoldAA) {
127     if (canFoldAA) {
128         src = div255(src * aa);
129         for (int i = 0; i < N; ++i) {
130             dst[i] = proc(src, dst[i]);
131         }
132     } else {
133         for (int i = 0; i < N; ++i) {
134             dst[i] = u8_lerp(dst[i], proc(src, dst[i]), aa);
135         }
136     }
137 }
138 using A8_RowBlitAA = void(*)(uint8_t[], uint8_t, int, uint8_t aa);
139 
140 #define WRAP_BLIT(proc, canFoldAA)                      \
141     proc,                                               \
142     [](uint8_t dst[], uint8_t src, int N)               \
143       { A8_row_bw(dst, src, N, proc); },                \
144     [](uint8_t dst[], uint8_t src, int N, uint8_t aa)   \
145       { A8_row_aa(dst, src, N, aa, proc, canFoldAA); }
146 
147 struct A8_RowBlitBWPair {
148     SkBlendMode     mode;
149     AlphaProc       oneProc;
150     A8_RowBlitBW    bwProc;
151     A8_RowBlitAA    aaProc;
152 };
153 constexpr A8_RowBlitBWPair gA8_RowBlitPairs[] = {
154     {SkBlendMode::kSrcOver,  WRAP_BLIT(srcover_p,  true)},
155     {SkBlendMode::kSrc,      WRAP_BLIT(src_p,      false)},
156 };
157 #undef WRAP_BLIT
158 
find_a8_rowproc_pair(SkBlendMode bm)159 static const A8_RowBlitBWPair* find_a8_rowproc_pair(SkBlendMode bm) {
160     for (auto& pair : gA8_RowBlitPairs) {
161         if (pair.mode == bm) {
162             return &pair;
163         }
164     }
165     return nullptr;
166 }
167 
168 class SkA8_Blitter : public SkBlitter {
169 public:
170     SkA8_Blitter(const SkPixmap& device, const SkPaint& paint);
171     void blitH(int x, int y, int width) override;
172     void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override;
173     void blitV(int x, int y, int height, SkAlpha alpha) override;
174     void blitRect(int x, int y, int width, int height) override;
175     void blitMask(const SkMask&, const SkIRect&) override;
176 
177 private:
178     const SkPixmap  fDevice;
179     AlphaProc       fOneProc;
180     A8_RowBlitBW    fBWProc;
181     A8_RowBlitAA    fAAProc;
182     SkAlpha         fSrc;
183 
184     using INHERITED = SkBlitter;
185 };
186 
SkA8_Blitter(const SkPixmap & device,const SkPaint & paint)187 SkA8_Blitter::SkA8_Blitter(const SkPixmap& device,
188                            const SkPaint& paint) : fDevice(device) {
189     SkASSERT(nullptr == paint.getShader());
190     SkASSERT(nullptr == paint.getColorFilter());
191     auto mode = paint.asBlendMode();
192     SkASSERT(mode);
193     auto pair = find_a8_rowproc_pair(*mode);
194     SkASSERT(pair);
195 
196     fOneProc = pair->oneProc;
197     fBWProc  = pair->bwProc;
198     fAAProc  = pair->aaProc;
199     fSrc = paint.getAlpha();
200 }
201 
blitAntiH(int x,int y,const SkAlpha antialias[],const int16_t runs[])202 void SkA8_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) {
203     uint8_t* device = fDevice.writable_addr8(x, y);
204     SkDEBUGCODE(int totalCount = 0;)
205 
206     for (;;) {
207         int count = runs[0];
208         SkASSERT(count >= 0);
209         if (count == 0) {
210             return;
211         }
212 
213         if (antialias[0] == 0xFF) {
214             fBWProc(device, fSrc, count);
215         } else if (antialias[0] != 0) {
216             fAAProc(device, fSrc, count, antialias[0]);
217         }
218 
219         runs += count;
220         antialias += count;
221         device += count;
222 
223         SkDEBUGCODE(totalCount += count;)
224     }
225     SkASSERT(fDevice.width() == totalCount);
226 }
227 
blitH(int x,int y,int width)228 void SkA8_Blitter::blitH(int x, int y, int width) {
229     fBWProc(fDevice.writable_addr8(x, y), fSrc, width);
230 }
231 
blitV(int x,int y,int height,SkAlpha aa)232 void SkA8_Blitter::blitV(int x, int y, int height, SkAlpha aa) {
233     uint8_t* device = fDevice.writable_addr8(x, y);
234     const size_t dstRB = fDevice.rowBytes();
235 
236     if (aa == 0xFF) {
237         while (--height >= 0) {
238             *device = fOneProc(fSrc, *device);
239             device += dstRB;
240         }
241     } else if (aa != 0) {
242         while (--height >= 0) {
243             fAAProc(device, fSrc, 1, aa);
244             device += dstRB;
245         }
246     }
247 }
248 
blitRect(int x,int y,int width,int height)249 void SkA8_Blitter::blitRect(int x, int y, int width, int height) {
250     uint8_t* device = fDevice.writable_addr8(x, y);
251     const size_t dstRB = fDevice.rowBytes();
252 
253     while (--height >= 0) {
254         fBWProc(device, fSrc, width);
255         device += dstRB;
256     }
257 }
258 
blitMask(const SkMask & mask,const SkIRect & clip)259 void SkA8_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
260     if (SkMask::kA8_Format != mask.fFormat) {
261         this->INHERITED::blitMask(mask, clip);
262         return;
263     }
264 
265     int x = clip.fLeft;
266     int y = clip.fTop;
267     int width = clip.width();
268     int height = clip.height();
269 
270     uint8_t* dst = fDevice.writable_addr8(x, y);
271     const uint8_t* src = mask.getAddr8(x, y);
272     const size_t srcRB = mask.fRowBytes;
273     const size_t dstRB = fDevice.rowBytes();
274 
275     while (--height >= 0) {
276         for (int i = 0; i < width; ++i) {
277             dst[i] = u8_lerp(dst[i], fOneProc(fSrc, dst[i]), src[i]);
278         }
279         dst += dstRB;
280         src += srcRB;
281     }
282 }
283 
284 //////////////////
285 
SkA8Blitter_Choose(const SkPixmap & dst,const SkMatrix & ctm,const SkPaint & paint,SkArenaAlloc * alloc,bool drawCoverage,sk_sp<SkShader> clipShader,const SkSurfaceProps &)286 SkBlitter* SkA8Blitter_Choose(const SkPixmap& dst,
287                               const SkMatrix& ctm,
288                               const SkPaint& paint,
289                               SkArenaAlloc* alloc,
290                               bool drawCoverage,
291                               sk_sp<SkShader> clipShader,
292                               const SkSurfaceProps&) {
293     if (dst.colorType() != SkColorType::kAlpha_8_SkColorType) {
294         return nullptr;
295     }
296     if (paint.getShader() || paint.getColorFilter()) {
297         return nullptr;
298     }
299     if (clipShader) {
300         return nullptr; // would not be hard to support ...?
301     }
302 
303     if (drawCoverage) {
304         return alloc->make<SkA8_Coverage_Blitter>(dst, paint);
305     } else {
306         // we only support certain blendmodes...
307         auto mode = paint.asBlendMode();
308         if (mode && find_a8_rowproc_pair(*mode)) {
309             return alloc->make<SkA8_Blitter>(dst, paint);
310         }
311     }
312     return nullptr;
313 }
314 
315