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