blob: 24ab330769adfe129572ea3792f87216c87d4de5 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkCoreBlitters.h"
9#include "SkColorPriv.h"
10#include "SkShader.h"
11#include "SkUtils.h"
12#include "SkXfermode.h"
reed@google.com58af9a62011-10-12 13:43:52 +000013#include "SkBlitMask.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
reed@google.comf88d6762011-03-10 15:06:27 +000015///////////////////////////////////////////////////////////////////////////////
16
reed@android.comf2b98d62010-12-20 18:26:13 +000017static void SkARGB32_Blit32(const SkBitmap& device, const SkMask& mask,
18 const SkIRect& clip, SkPMColor srcColor) {
19 U8CPU alpha = SkGetPackedA32(srcColor);
20 unsigned flags = SkBlitRow::kSrcPixelAlpha_Flag32;
21 if (alpha != 255) {
22 flags |= SkBlitRow::kGlobalAlpha_Flag32;
23 }
24 SkBlitRow::Proc32 proc = SkBlitRow::Factory32(flags);
25
26 int x = clip.fLeft;
27 int y = clip.fTop;
28 int width = clip.width();
29 int height = clip.height();
reed@google.com82065d62011-02-07 15:30:46 +000030
reed@android.comf2b98d62010-12-20 18:26:13 +000031 SkPMColor* dstRow = device.getAddr32(x, y);
reed@google.com79891862011-10-18 15:44:57 +000032 const SkPMColor* srcRow = reinterpret_cast<const SkPMColor*>(mask.getAddr8(x, y));
reed@android.comf2b98d62010-12-20 18:26:13 +000033
34 do {
35 proc(dstRow, srcRow, width, alpha);
36 dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes());
37 srcRow = (const SkPMColor*)((const char*)srcRow + mask.fRowBytes);
38 } while (--height != 0);
39}
40
41//////////////////////////////////////////////////////////////////////////////////////
42
reed@android.com8a1c16f2008-12-17 15:59:43 +000043SkARGB32_Blitter::SkARGB32_Blitter(const SkBitmap& device, const SkPaint& paint)
44 : INHERITED(device) {
reed@google.comee467ee2011-03-09 13:23:57 +000045 SkColor color = paint.getColor();
46 fColor = color;
reed@android.com8a1c16f2008-12-17 15:59:43 +000047
48 fSrcA = SkColorGetA(color);
49 unsigned scale = SkAlpha255To256(fSrcA);
50 fSrcR = SkAlphaMul(SkColorGetR(color), scale);
51 fSrcG = SkAlphaMul(SkColorGetG(color), scale);
52 fSrcB = SkAlphaMul(SkColorGetB(color), scale);
53
54 fPMColor = SkPackARGB32(fSrcA, fSrcR, fSrcG, fSrcB);
senorblanco@chromium.org29e50542010-12-16 19:07:45 +000055 fColor32Proc = SkBlitRow::ColorProcFactory();
reed@android.com8a1c16f2008-12-17 15:59:43 +000056}
57
58const SkBitmap* SkARGB32_Blitter::justAnOpaqueColor(uint32_t* value) {
59 if (255 == fSrcA) {
60 *value = fPMColor;
61 return &fDevice;
62 }
63 return NULL;
64}
65
66#if defined _WIN32 && _MSC_VER >= 1300 // disable warning : local variable used without having been initialized
67#pragma warning ( push )
68#pragma warning ( disable : 4701 )
69#endif
70
71void SkARGB32_Blitter::blitH(int x, int y, int width) {
72 SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
73
senorblanco@chromium.org29e50542010-12-16 19:07:45 +000074 uint32_t* device = fDevice.getAddr32(x, y);
75 fColor32Proc(device, device, width, fPMColor);
reed@android.com8a1c16f2008-12-17 15:59:43 +000076}
77
78void SkARGB32_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
79 const int16_t runs[]) {
80 if (fSrcA == 0) {
81 return;
82 }
83
84 uint32_t color = fPMColor;
85 uint32_t* device = fDevice.getAddr32(x, y);
86 unsigned opaqueMask = fSrcA; // if fSrcA is 0xFF, then we will catch the fast opaque case
87
88 for (;;) {
89 int count = runs[0];
90 SkASSERT(count >= 0);
91 if (count <= 0) {
92 return;
93 }
94 unsigned aa = antialias[0];
95 if (aa) {
96 if ((opaqueMask & aa) == 255) {
97 sk_memset32(device, color, count);
98 } else {
reed@android.comc4cae852009-09-23 15:06:10 +000099 uint32_t sc = SkAlphaMulQ(color, SkAlpha255To256(aa));
senorblanco@chromium.org29e50542010-12-16 19:07:45 +0000100 fColor32Proc(device, device, count, sc);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101 }
102 }
103 runs += count;
104 antialias += count;
105 device += count;
106 }
107}
108
109//////////////////////////////////////////////////////////////////////////////////////
110
111#define solid_8_pixels(mask, dst, color) \
112 do { \
113 if (mask & 0x80) dst[0] = color; \
114 if (mask & 0x40) dst[1] = color; \
115 if (mask & 0x20) dst[2] = color; \
116 if (mask & 0x10) dst[3] = color; \
117 if (mask & 0x08) dst[4] = color; \
118 if (mask & 0x04) dst[5] = color; \
119 if (mask & 0x02) dst[6] = color; \
120 if (mask & 0x01) dst[7] = color; \
121 } while (0)
122
123#define SK_BLITBWMASK_NAME SkARGB32_BlitBW
124#define SK_BLITBWMASK_ARGS , SkPMColor color
125#define SK_BLITBWMASK_BLIT8(mask, dst) solid_8_pixels(mask, dst, color)
126#define SK_BLITBWMASK_GETADDR getAddr32
127#define SK_BLITBWMASK_DEVTYPE uint32_t
128#include "SkBlitBWMaskTemplate.h"
129
130#define blend_8_pixels(mask, dst, sc, dst_scale) \
131 do { \
132 if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ(dst[0], dst_scale); } \
133 if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ(dst[1], dst_scale); } \
134 if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ(dst[2], dst_scale); } \
135 if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ(dst[3], dst_scale); } \
136 if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ(dst[4], dst_scale); } \
137 if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ(dst[5], dst_scale); } \
138 if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ(dst[6], dst_scale); } \
139 if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ(dst[7], dst_scale); } \
140 } while (0)
141
142#define SK_BLITBWMASK_NAME SkARGB32_BlendBW
143#define SK_BLITBWMASK_ARGS , uint32_t sc, unsigned dst_scale
144#define SK_BLITBWMASK_BLIT8(mask, dst) blend_8_pixels(mask, dst, sc, dst_scale)
145#define SK_BLITBWMASK_GETADDR getAddr32
146#define SK_BLITBWMASK_DEVTYPE uint32_t
147#include "SkBlitBWMaskTemplate.h"
148
149void SkARGB32_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
150 SkASSERT(mask.fBounds.contains(clip));
151 SkASSERT(fSrcA != 0xFF);
152
153 if (fSrcA == 0) {
154 return;
155 }
156
reed@google.comedb606c2011-10-18 13:56:50 +0000157 if (SkBlitMask::BlitColor(fDevice, mask, clip, fColor)) {
caryclark@google.com1eeaf0b2011-06-22 13:19:43 +0000158 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 }
160
reed@google.comedb606c2011-10-18 13:56:50 +0000161 if (mask.fFormat == SkMask::kBW_Format) {
162 SkARGB32_BlendBW(fDevice, mask, clip, fPMColor, SkAlpha255To256(255 - fSrcA));
163 } else if (SkMask::kARGB32_Format == mask.fFormat) {
164 SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
165 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166}
167
168void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask,
169 const SkIRect& clip) {
170 SkASSERT(mask.fBounds.contains(clip));
171
reed@google.comedb606c2011-10-18 13:56:50 +0000172 if (SkBlitMask::BlitColor(fDevice, mask, clip, fColor)) {
173 return;
174 }
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 if (mask.fFormat == SkMask::kBW_Format) {
177 SkARGB32_BlitBW(fDevice, mask, clip, fPMColor);
reed@android.comf2b98d62010-12-20 18:26:13 +0000178 } else if (SkMask::kARGB32_Format == mask.fFormat) {
179 SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
reed@android.comf2b98d62010-12-20 18:26:13 +0000180 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181}
182
reed@google.com67cdbf52011-10-25 20:47:10 +0000183///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184
185void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
186 if (alpha == 0 || fSrcA == 0) {
187 return;
188 }
189
190 uint32_t* device = fDevice.getAddr32(x, y);
191 uint32_t color = fPMColor;
192
193 if (alpha != 255) {
194 color = SkAlphaMulQ(color, SkAlpha255To256(alpha));
195 }
196
197 unsigned dst_scale = 255 - SkGetPackedA32(color);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198 uint32_t rowBytes = fDevice.rowBytes();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 while (--height >= 0) {
reed@google.com67cdbf52011-10-25 20:47:10 +0000200 device[0] = color + SkAlphaMulQ(device[0], dst_scale);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 device = (uint32_t*)((char*)device + rowBytes);
202 }
203}
204
205void SkARGB32_Blitter::blitRect(int x, int y, int width, int height) {
206 SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() && y + height <= fDevice.height());
207
208 if (fSrcA == 0) {
209 return;
210 }
211
212 uint32_t* device = fDevice.getAddr32(x, y);
213 uint32_t color = fPMColor;
reed@android.comc4cae852009-09-23 15:06:10 +0000214 size_t rowBytes = fDevice.rowBytes();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215
reed@android.comc4cae852009-09-23 15:06:10 +0000216 while (--height >= 0) {
senorblanco@chromium.org29e50542010-12-16 19:07:45 +0000217 fColor32Proc(device, device, width, color);
reed@android.comc4cae852009-09-23 15:06:10 +0000218 device = (uint32_t*)((char*)device + rowBytes);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 }
220}
221
222#if defined _WIN32 && _MSC_VER >= 1300
223#pragma warning ( pop )
224#endif
225
226///////////////////////////////////////////////////////////////////////
227
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228void SkARGB32_Black_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
229 const int16_t runs[]) {
230 uint32_t* device = fDevice.getAddr32(x, y);
231 SkPMColor black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT);
232
233 for (;;) {
234 int count = runs[0];
235 SkASSERT(count >= 0);
236 if (count <= 0) {
237 return;
238 }
239 unsigned aa = antialias[0];
240 if (aa) {
241 if (aa == 255) {
242 sk_memset32(device, black, count);
243 } else {
244 SkPMColor src = aa << SK_A32_SHIFT;
245 unsigned dst_scale = 256 - aa;
246 int n = count;
247 do {
248 --n;
249 device[n] = src + SkAlphaMulQ(device[n], dst_scale);
250 } while (n > 0);
251 }
252 }
253 runs += count;
254 antialias += count;
255 device += count;
256 }
257}
258
reed@google.com1750bf12011-11-15 19:51:02 +0000259///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260
261SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device,
reed@android.comc4cae852009-09-23 15:06:10 +0000262 const SkPaint& paint) : INHERITED(device, paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
264
reed@android.comc4cae852009-09-23 15:06:10 +0000265 fXfermode = paint.getXfermode();
266 SkSafeRef(fXfermode);
267
268 int flags = 0;
269 if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
270 flags |= SkBlitRow::kSrcPixelAlpha_Flag32;
271 }
272 // we call this on the output from the shader
273 fProc32 = SkBlitRow::Factory32(flags);
274 // we call this on the output from the shader + alpha from the aa buffer
275 fProc32Blend = SkBlitRow::Factory32(flags | SkBlitRow::kGlobalAlpha_Flag32);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276}
277
278SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() {
reed@google.com82065d62011-02-07 15:30:46 +0000279 SkSafeUnref(fXfermode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 sk_free(fBuffer);
281}
282
283void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) {
284 SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
285
286 uint32_t* device = fDevice.getAddr32(x, y);
287
288 if (fXfermode == NULL && (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
289 fShader->shadeSpan(x, y, device, width);
290 } else {
291 SkPMColor* span = fBuffer;
292 fShader->shadeSpan(x, y, span, width);
293 if (fXfermode) {
294 fXfermode->xfer32(device, span, width, NULL);
295 } else {
reed@android.comc4cae852009-09-23 15:06:10 +0000296 fProc32(device, span, width, 255);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 }
298 }
299}
300
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
302 const int16_t runs[]) {
303 SkPMColor* span = fBuffer;
304 uint32_t* device = fDevice.getAddr32(x, y);
305 SkShader* shader = fShader;
306
307 if (fXfermode) {
308 for (;;) {
309 SkXfermode* xfer = fXfermode;
310
311 int count = *runs;
312 if (count <= 0)
313 break;
314 int aa = *antialias;
315 if (aa) {
316 shader->shadeSpan(x, y, span, count);
317 if (aa == 255) {
318 xfer->xfer32(device, span, count, NULL);
319 } else {
320 // count is almost always 1
321 for (int i = count - 1; i >= 0; --i) {
322 xfer->xfer32(&device[i], &span[i], 1, antialias);
323 }
324 }
325 }
326 device += count;
327 runs += count;
328 antialias += count;
329 x += count;
reed@google.com82065d62011-02-07 15:30:46 +0000330 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 } else if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) {
332 for (;;) {
333 int count = *runs;
334 if (count <= 0) {
335 break;
336 }
337 int aa = *antialias;
338 if (aa) {
reed@android.comc4cae852009-09-23 15:06:10 +0000339 if (aa == 255) {
340 // cool, have the shader draw right into the device
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 shader->shadeSpan(x, y, device, count);
342 } else {
343 shader->shadeSpan(x, y, span, count);
reed@android.comc4cae852009-09-23 15:06:10 +0000344 fProc32Blend(device, span, count, aa);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 }
346 }
347 device += count;
348 runs += count;
349 antialias += count;
350 x += count;
reed@google.com82065d62011-02-07 15:30:46 +0000351 }
reed@android.comc4cae852009-09-23 15:06:10 +0000352 } else { // no xfermode but the shader not opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 for (;;) {
354 int count = *runs;
355 if (count <= 0) {
356 break;
357 }
358 int aa = *antialias;
359 if (aa) {
360 fShader->shadeSpan(x, y, span, count);
361 if (aa == 255) {
reed@android.comc4cae852009-09-23 15:06:10 +0000362 fProc32(device, span, count, 255);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363 } else {
reed@android.comc4cae852009-09-23 15:06:10 +0000364 fProc32Blend(device, span, count, aa);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365 }
366 }
367 device += count;
368 runs += count;
369 antialias += count;
370 x += count;
reed@google.com82065d62011-02-07 15:30:46 +0000371 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372 }
373}
reed@google.com1750bf12011-11-15 19:51:02 +0000374
375void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
376 // we only handle kA8 with an xfermode
377 if (fXfermode && (SkMask::kA8_Format != mask.fFormat)) {
378 this->INHERITED::blitMask(mask, clip);
379 return;
380 }
381
382 SkASSERT(mask.fBounds.contains(clip));
383
384 SkBlitMask::RowProc proc = NULL;
385 if (!fXfermode) {
386 unsigned flags = 0;
387 if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) {
388 flags |= SkBlitMask::kSrcIsOpaque_RowFlag;
389 }
390 proc = SkBlitMask::RowFactory(SkBitmap::kARGB_8888_Config, mask.fFormat,
391 (SkBlitMask::RowFlags)flags);
392 if (NULL == proc) {
393 this->INHERITED::blitMask(mask, clip);
394 return;
395 }
396 }
397
398 const int x = clip.fLeft;
399 const int width = clip.width();
400 int y = clip.fTop;
401 int height = clip.height();
402
403 char* dstRow = (char*)fDevice.getAddr32(x, y);
404 const size_t dstRB = fDevice.rowBytes();
405 const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y);
406 const size_t maskRB = mask.fRowBytes;
407
408 SkShader* shader = fShader;
409 SkPMColor* span = fBuffer;
410
411 if (fXfermode) {
412 SkASSERT(SkMask::kA8_Format == mask.fFormat);
413 SkXfermode* xfer = fXfermode;
414 do {
415 shader->shadeSpan(x, y, span, width);
416 xfer->xfer32((SkPMColor*)dstRow, span, width, maskRow);
417 dstRow += dstRB;
418 maskRow += maskRB;
419 y += 1;
420 } while (--height > 0);
421 } else {
422 do {
423 shader->shadeSpan(x, y, span, width);
424 proc(dstRow, maskRow, span, width);
425 dstRow += dstRB;
426 maskRow += maskRB;
427 y += 1;
428 } while (--height > 0);
429 }
430}
431