1 /* libs/graphics/sgl/SkBlitter_A8.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include "SkCoreBlitters.h"
19 #include "SkColorPriv.h"
20 #include "SkShader.h"
21 #include "SkXfermode.h"
22
SkA8_Blitter(const SkBitmap & device,const SkPaint & paint)23 SkA8_Blitter::SkA8_Blitter(const SkBitmap& device, const SkPaint& paint)
24 : INHERITED(device)
25 {
26 fSrcA = SkColorGetA(paint.getColor());
27 }
28
justAnOpaqueColor(uint32_t * value)29 const SkBitmap* SkA8_Blitter::justAnOpaqueColor(uint32_t* value)
30 {
31 if (255 == fSrcA)
32 {
33 *value = 255;
34 return &fDevice;
35 }
36 return NULL;
37 }
38
blitH(int x,int y,int width)39 void SkA8_Blitter::blitH(int x, int y, int width)
40 {
41 SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= (unsigned)fDevice.width());
42
43 if (fSrcA == 0)
44 return;
45
46 uint8_t* device = fDevice.getAddr8(x, y);
47
48 if (fSrcA == 255)
49 {
50 memset(device, 0xFF, width);
51 }
52 else
53 {
54 unsigned scale = 256 - SkAlpha255To256(fSrcA);
55 unsigned srcA = fSrcA;
56
57 for (int i = 0; i < width; i++)
58 {
59 device[i] = SkToU8(srcA + SkAlphaMul(device[i], scale));
60 }
61 }
62 }
63
blitAntiH(int x,int y,const SkAlpha antialias[],const int16_t runs[])64 void SkA8_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])
65 {
66 if (fSrcA == 0)
67 return;
68
69 uint8_t* device = fDevice.getAddr8(x, y);
70 unsigned srcA = fSrcA;
71
72 for (;;)
73 {
74 int count = runs[0];
75 SkASSERT(count >= 0);
76 if (count == 0)
77 return;
78 unsigned aa = antialias[0];
79
80 if (aa == 255 && srcA == 255)
81 memset(device, 0xFF, count);
82 else
83 {
84 unsigned sa = SkAlphaMul(srcA, SkAlpha255To256(aa));
85 unsigned scale = 256 - sa;
86
87 for (int i = 0; i < count; i++)
88 {
89 device[i] = SkToU8(sa + SkAlphaMul(device[i], scale));
90 }
91 }
92 runs += count;
93 antialias += count;
94 device += count;
95 }
96 }
97
98 /////////////////////////////////////////////////////////////////////////////////////
99
100 #define solid_8_pixels(mask, dst) \
101 do { \
102 if (mask & 0x80) dst[0] = 0xFF; \
103 if (mask & 0x40) dst[1] = 0xFF; \
104 if (mask & 0x20) dst[2] = 0xFF; \
105 if (mask & 0x10) dst[3] = 0xFF; \
106 if (mask & 0x08) dst[4] = 0xFF; \
107 if (mask & 0x04) dst[5] = 0xFF; \
108 if (mask & 0x02) dst[6] = 0xFF; \
109 if (mask & 0x01) dst[7] = 0xFF; \
110 } while (0)
111
112 #define SK_BLITBWMASK_NAME SkA8_BlitBW
113 #define SK_BLITBWMASK_ARGS
114 #define SK_BLITBWMASK_BLIT8(mask, dst) solid_8_pixels(mask, dst)
115 #define SK_BLITBWMASK_GETADDR getAddr8
116 #define SK_BLITBWMASK_DEVTYPE uint8_t
117 #include "SkBlitBWMaskTemplate.h"
118
blend_8_pixels(U8CPU bw,uint8_t dst[],U8CPU sa,unsigned dst_scale)119 static inline void blend_8_pixels(U8CPU bw, uint8_t dst[], U8CPU sa, unsigned dst_scale)
120 {
121 if (bw & 0x80) dst[0] = SkToU8(sa + SkAlphaMul(dst[0], dst_scale));
122 if (bw & 0x40) dst[1] = SkToU8(sa + SkAlphaMul(dst[1], dst_scale));
123 if (bw & 0x20) dst[2] = SkToU8(sa + SkAlphaMul(dst[2], dst_scale));
124 if (bw & 0x10) dst[3] = SkToU8(sa + SkAlphaMul(dst[3], dst_scale));
125 if (bw & 0x08) dst[4] = SkToU8(sa + SkAlphaMul(dst[4], dst_scale));
126 if (bw & 0x04) dst[5] = SkToU8(sa + SkAlphaMul(dst[5], dst_scale));
127 if (bw & 0x02) dst[6] = SkToU8(sa + SkAlphaMul(dst[6], dst_scale));
128 if (bw & 0x01) dst[7] = SkToU8(sa + SkAlphaMul(dst[7], dst_scale));
129 }
130
131 #define SK_BLITBWMASK_NAME SkA8_BlendBW
132 #define SK_BLITBWMASK_ARGS , U8CPU sa, unsigned dst_scale
133 #define SK_BLITBWMASK_BLIT8(mask, dst) blend_8_pixels(mask, dst, sa, dst_scale)
134 #define SK_BLITBWMASK_GETADDR getAddr8
135 #define SK_BLITBWMASK_DEVTYPE uint8_t
136 #include "SkBlitBWMaskTemplate.h"
137
blitMask(const SkMask & mask,const SkIRect & clip)138 void SkA8_Blitter::blitMask(const SkMask& mask, const SkIRect& clip)
139 {
140 if (fSrcA == 0)
141 return;
142
143 if (mask.fFormat == SkMask::kBW_Format)
144 {
145 if (fSrcA == 0xFF)
146 SkA8_BlitBW(fDevice, mask, clip);
147 else
148 SkA8_BlendBW(fDevice, mask, clip, fSrcA, SkAlpha255To256(255 - fSrcA));
149 return;
150 }
151
152 int x = clip.fLeft;
153 int y = clip.fTop;
154 int width = clip.width();
155 int height = clip.height();
156 uint8_t* device = fDevice.getAddr8(x, y);
157 const uint8_t* alpha = mask.getAddr(x, y);
158 unsigned srcA = fSrcA;
159
160 while (--height >= 0)
161 {
162 for (int i = width - 1; i >= 0; --i)
163 {
164 unsigned sa;
165 // scale our src by the alpha value
166 {
167 int aa = alpha[i];
168 if (aa == 0)
169 continue;
170
171 if (aa == 255)
172 {
173 if (srcA == 255)
174 {
175 device[i] = 0xFF;
176 continue;
177 }
178 sa = srcA;
179 }
180 else
181 sa = SkAlphaMul(srcA, SkAlpha255To256(aa));
182 }
183
184 int scale = 256 - SkAlpha255To256(sa);
185 device[i] = SkToU8(sa + SkAlphaMul(device[i], scale));
186 }
187 device += fDevice.rowBytes();
188 alpha += mask.fRowBytes;
189 }
190 }
191
192 ///////////////////////////////////////////////////////////////////////////////////////
193
blitV(int x,int y,int height,SkAlpha alpha)194 void SkA8_Blitter::blitV(int x, int y, int height, SkAlpha alpha)
195 {
196 if (fSrcA == 0)
197 return;
198
199 unsigned sa = SkAlphaMul(fSrcA, SkAlpha255To256(alpha));
200 uint8_t* device = fDevice.getAddr8(x, y);
201 int rowBytes = fDevice.rowBytes();
202
203 if (sa == 0xFF)
204 {
205 for (int i = 0; i < height; i++)
206 {
207 *device = SkToU8(sa);
208 device += rowBytes;
209 }
210 }
211 else
212 {
213 unsigned scale = 256 - SkAlpha255To256(sa);
214
215 for (int i = 0; i < height; i++)
216 {
217 *device = SkToU8(sa + SkAlphaMul(*device, scale));
218 device += rowBytes;
219 }
220 }
221 }
222
blitRect(int x,int y,int width,int height)223 void SkA8_Blitter::blitRect(int x, int y, int width, int height)
224 {
225 SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= (unsigned)fDevice.width() && (unsigned)(y + height) <= (unsigned)fDevice.height());
226
227 if (fSrcA == 0)
228 return;
229
230 uint8_t* device = fDevice.getAddr8(x, y);
231 unsigned srcA = fSrcA;
232
233 if (srcA == 255)
234 {
235 while (--height >= 0)
236 {
237 memset(device, 0xFF, width);
238 device += fDevice.rowBytes();
239 }
240 }
241 else
242 {
243 unsigned scale = 256 - SkAlpha255To256(srcA);
244
245 while (--height >= 0)
246 {
247 for (int i = 0; i < width; i++)
248 {
249 device[i] = SkToU8(srcA + SkAlphaMul(device[i], scale));
250 }
251 device += fDevice.rowBytes();
252 }
253 }
254 }
255
256 ///////////////////////////////////////////////////////////////////////
257
SkA8_Shader_Blitter(const SkBitmap & device,const SkPaint & paint)258 SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint)
259 : INHERITED(device, paint)
260 {
261 if ((fXfermode = paint.getXfermode()) != NULL)
262 {
263 fXfermode->ref();
264 SkASSERT(fShader);
265 }
266
267 int width = device.width();
268 fBuffer = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * (width + (SkAlign4(width) >> 2)));
269 fAAExpand = (uint8_t*)(fBuffer + width);
270 }
271
~SkA8_Shader_Blitter()272 SkA8_Shader_Blitter::~SkA8_Shader_Blitter()
273 {
274 fXfermode->safeUnref();
275 sk_free(fBuffer);
276 }
277
blitH(int x,int y,int width)278 void SkA8_Shader_Blitter::blitH(int x, int y, int width)
279 {
280 SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= (unsigned)fDevice.width());
281
282 uint8_t* device = fDevice.getAddr8(x, y);
283
284 if ((fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) && fXfermode == NULL)
285 {
286 memset(device, 0xFF, width);
287 }
288 else
289 {
290 SkPMColor* span = fBuffer;
291
292 fShader->shadeSpan(x, y, span, width);
293 if (fXfermode)
294 fXfermode->xferA8(device, span, width, NULL);
295 else
296 {
297 for (int i = width - 1; i >= 0; --i)
298 {
299 unsigned srcA = SkGetPackedA32(span[i]);
300 unsigned scale = 256 - SkAlpha255To256(srcA);
301
302 device[i] = SkToU8(srcA + SkAlphaMul(device[i], scale));
303 }
304 }
305 }
306 }
307
aa_blend8(SkPMColor src,U8CPU da,int aa)308 static inline uint8_t aa_blend8(SkPMColor src, U8CPU da, int aa)
309 {
310 SkASSERT((unsigned)aa <= 255);
311
312 int src_scale = SkAlpha255To256(aa);
313 int sa = SkGetPackedA32(src);
314 int dst_scale = 256 - SkAlphaMul(sa, src_scale);
315
316 return SkToU8((sa * src_scale + da * dst_scale) >> 8);
317 }
318
blitAntiH(int x,int y,const SkAlpha antialias[],const int16_t runs[])319 void SkA8_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])
320 {
321 SkShader* shader = fShader;
322 SkXfermode* mode = fXfermode;
323 uint8_t* aaExpand = fAAExpand;
324 SkPMColor* span = fBuffer;
325 uint8_t* device = fDevice.getAddr8(x, y);
326 int opaque = fShader->getFlags() & SkShader::kOpaqueAlpha_Flag;
327
328 for (;;)
329 {
330 int count = *runs;
331 if (count == 0)
332 break;
333 int aa = *antialias;
334 if (aa)
335 {
336 if (opaque && aa == 255 && mode == NULL)
337 memset(device, 0xFF, count);
338 else
339 {
340 shader->shadeSpan(x, y, span, count);
341 if (mode)
342 {
343 memset(aaExpand, aa, count);
344 mode->xferA8(device, span, count, aaExpand);
345 }
346 else
347 {
348 for (int i = count - 1; i >= 0; --i)
349 device[i] = aa_blend8(span[i], device[i], aa);
350 }
351 }
352 }
353 device += count;
354 runs += count;
355 antialias += count;
356 x += count;
357 }
358 }
359
blitMask(const SkMask & mask,const SkIRect & clip)360 void SkA8_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip)
361 {
362 if (mask.fFormat == SkMask::kBW_Format)
363 {
364 this->INHERITED::blitMask(mask, clip);
365 return;
366 }
367
368 int x = clip.fLeft;
369 int y = clip.fTop;
370 int width = clip.width();
371 int height = clip.height();
372 uint8_t* device = fDevice.getAddr8(x, y);
373 const uint8_t* alpha = mask.getAddr(x, y);
374
375 SkPMColor* span = fBuffer;
376
377 while (--height >= 0)
378 {
379 fShader->shadeSpan(x, y, span, width);
380 fXfermode->xferA8(device, span, width, alpha);
381
382 y += 1;
383 device += fDevice.rowBytes();
384 alpha += mask.fRowBytes;
385 }
386 }
387
388