blob: 6b6d8b10d75e1a11fbdd07ee55049057c5190b6c [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 "SkSpriteBlitter.h"
Herb Derby57bfa022017-02-09 17:25:43 -05009#include "SkArenaAlloc.h"
reed@android.comc4cae852009-09-23 15:06:10 +000010#include "SkBlitRow.h"
11#include "SkColorFilter.h"
12#include "SkColorPriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkTemplates.h"
14#include "SkUtils.h"
Mike Reedd4706732016-11-15 16:44:34 -050015#include "SkXfermodePriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
17///////////////////////////////////////////////////////////////////////////////
18
reed@android.comc4cae852009-09-23 15:06:10 +000019class Sprite_D32_S32 : public SkSpriteBlitter {
reed@android.com8a1c16f2008-12-17 15:59:43 +000020public:
reedc240e712015-05-23 12:26:41 -070021 Sprite_D32_S32(const SkPixmap& src, U8CPU alpha) : INHERITED(src) {
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +000022 SkASSERT(src.colorType() == kN32_SkColorType);
reed@android.com8a1c16f2008-12-17 15:59:43 +000023
reed@android.comc4cae852009-09-23 15:06:10 +000024 unsigned flags32 = 0;
25 if (255 != alpha) {
26 flags32 |= SkBlitRow::kGlobalAlpha_Flag32;
27 }
28 if (!src.isOpaque()) {
29 flags32 |= SkBlitRow::kSrcPixelAlpha_Flag32;
30 }
31
32 fProc32 = SkBlitRow::Factory32(flags32);
33 fAlpha = alpha;
34 }
reed@google.com82065d62011-02-07 15:30:46 +000035
mtklein36352bf2015-03-25 18:17:31 -070036 void blitRect(int x, int y, int width, int height) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +000037 SkASSERT(width > 0 && height > 0);
reedcb674142015-06-05 06:58:22 -070038 uint32_t* SK_RESTRICT dst = fDst.writable_addr32(x, y);
reedc240e712015-05-23 12:26:41 -070039 const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop);
reedcb674142015-06-05 06:58:22 -070040 size_t dstRB = fDst.rowBytes();
reedc240e712015-05-23 12:26:41 -070041 size_t srcRB = fSource.rowBytes();
reed@android.comc4cae852009-09-23 15:06:10 +000042 SkBlitRow::Proc32 proc = fProc32;
43 U8CPU alpha = fAlpha;
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
45 do {
reed@android.comc4cae852009-09-23 15:06:10 +000046 proc(dst, src, width, alpha);
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +000047 dst = (uint32_t* SK_RESTRICT)((char*)dst + dstRB);
48 src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB);
reed@android.com8a1c16f2008-12-17 15:59:43 +000049 } while (--height != 0);
50 }
reed@android.comc4cae852009-09-23 15:06:10 +000051
52private:
53 SkBlitRow::Proc32 fProc32;
54 U8CPU fAlpha;
reed@google.com82065d62011-02-07 15:30:46 +000055
reed@android.comc4cae852009-09-23 15:06:10 +000056 typedef SkSpriteBlitter INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +000057};
58
59///////////////////////////////////////////////////////////////////////////////
60
reed@android.com8a1c16f2008-12-17 15:59:43 +000061class Sprite_D32_XferFilter : public SkSpriteBlitter {
62public:
reedc240e712015-05-23 12:26:41 -070063 Sprite_D32_XferFilter(const SkPixmap& source, const SkPaint& paint) : SkSpriteBlitter(source) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000064 fColorFilter = paint.getColorFilter();
reed@google.com82065d62011-02-07 15:30:46 +000065 SkSafeRef(fColorFilter);
66
reed374772b2016-10-05 17:33:02 -070067 fXfermode = SkXfermode::Peek(paint.getBlendMode());
reed@google.com82065d62011-02-07 15:30:46 +000068
reed@android.com8a1c16f2008-12-17 15:59:43 +000069 fBufferSize = 0;
halcanary96fcdcc2015-08-27 07:41:13 -070070 fBuffer = nullptr;
reed@android.comc4cae852009-09-23 15:06:10 +000071
72 unsigned flags32 = 0;
73 if (255 != paint.getAlpha()) {
74 flags32 |= SkBlitRow::kGlobalAlpha_Flag32;
75 }
76 if (!source.isOpaque()) {
77 flags32 |= SkBlitRow::kSrcPixelAlpha_Flag32;
78 }
reed@google.com82065d62011-02-07 15:30:46 +000079
reed@android.comc4cae852009-09-23 15:06:10 +000080 fProc32 = SkBlitRow::Factory32(flags32);
81 fAlpha = paint.getAlpha();
reed@android.com8a1c16f2008-12-17 15:59:43 +000082 }
reed@google.com82065d62011-02-07 15:30:46 +000083
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 virtual ~Sprite_D32_XferFilter() {
85 delete[] fBuffer;
reed@google.com82065d62011-02-07 15:30:46 +000086 SkSafeUnref(fColorFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +000087 }
reed@google.com82065d62011-02-07 15:30:46 +000088
reedcb674142015-06-05 06:58:22 -070089 void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
90 this->INHERITED::setup(dst, left, top, paint);
reed@google.com82065d62011-02-07 15:30:46 +000091
reedcb674142015-06-05 06:58:22 -070092 int width = dst.width();
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 if (width > fBufferSize) {
94 fBufferSize = width;
95 delete[] fBuffer;
96 fBuffer = new SkPMColor[width];
97 }
98 }
99
100protected:
reed@android.comc4cae852009-09-23 15:06:10 +0000101 SkColorFilter* fColorFilter;
102 SkXfermode* fXfermode;
103 int fBufferSize;
104 SkPMColor* fBuffer;
105 SkBlitRow::Proc32 fProc32;
106 U8CPU fAlpha;
107
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108private:
109 typedef SkSpriteBlitter INHERITED;
110};
111
112///////////////////////////////////////////////////////////////////////////////
113
114class Sprite_D32_S32A_XferFilter : public Sprite_D32_XferFilter {
115public:
reedc240e712015-05-23 12:26:41 -0700116 Sprite_D32_S32A_XferFilter(const SkPixmap& source, const SkPaint& paint)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000117 : Sprite_D32_XferFilter(source, paint) {}
118
mtklein36352bf2015-03-25 18:17:31 -0700119 void blitRect(int x, int y, int width, int height) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000120 SkASSERT(width > 0 && height > 0);
reedcb674142015-06-05 06:58:22 -0700121 uint32_t* SK_RESTRICT dst = fDst.writable_addr32(x, y);
reedc240e712015-05-23 12:26:41 -0700122 const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop);
reedcb674142015-06-05 06:58:22 -0700123 size_t dstRB = fDst.rowBytes();
reedc240e712015-05-23 12:26:41 -0700124 size_t srcRB = fSource.rowBytes();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125 SkColorFilter* colorFilter = fColorFilter;
126 SkXfermode* xfermode = fXfermode;
127
128 do {
129 const SkPMColor* tmp = src;
reed@google.com82065d62011-02-07 15:30:46 +0000130
bsalomon49f085d2014-09-05 13:34:00 -0700131 if (colorFilter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 colorFilter->filterSpan(src, width, fBuffer);
133 tmp = fBuffer;
134 }
reed@google.com82065d62011-02-07 15:30:46 +0000135
bsalomon49f085d2014-09-05 13:34:00 -0700136 if (xfermode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700137 xfermode->xfer32(dst, tmp, width, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138 } else {
reed@android.comc4cae852009-09-23 15:06:10 +0000139 fProc32(dst, tmp, width, fAlpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140 }
141
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000142 dst = (uint32_t* SK_RESTRICT)((char*)dst + dstRB);
143 src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144 } while (--height != 0);
145 }
reed@google.com82065d62011-02-07 15:30:46 +0000146
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147private:
148 typedef Sprite_D32_XferFilter INHERITED;
149};
150
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000151static void fillbuffer(SkPMColor* SK_RESTRICT dst,
152 const SkPMColor16* SK_RESTRICT src, int count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 SkASSERT(count > 0);
reed@google.com82065d62011-02-07 15:30:46 +0000154
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155 do {
156 *dst++ = SkPixel4444ToPixel32(*src++);
157 } while (--count != 0);
158}
159
160class Sprite_D32_S4444_XferFilter : public Sprite_D32_XferFilter {
161public:
reedc240e712015-05-23 12:26:41 -0700162 Sprite_D32_S4444_XferFilter(const SkPixmap& source, const SkPaint& paint)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163 : Sprite_D32_XferFilter(source, paint) {}
reed@google.com82065d62011-02-07 15:30:46 +0000164
mtklein36352bf2015-03-25 18:17:31 -0700165 void blitRect(int x, int y, int width, int height) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 SkASSERT(width > 0 && height > 0);
reedcb674142015-06-05 06:58:22 -0700167 SkPMColor* SK_RESTRICT dst = fDst.writable_addr32(x, y);
reedc240e712015-05-23 12:26:41 -0700168 const SkPMColor16* SK_RESTRICT src = fSource.addr16(x - fLeft, y - fTop);
reedcb674142015-06-05 06:58:22 -0700169 size_t dstRB = fDst.rowBytes();
reedc240e712015-05-23 12:26:41 -0700170 size_t srcRB = fSource.rowBytes();
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000171 SkPMColor* SK_RESTRICT buffer = fBuffer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 SkColorFilter* colorFilter = fColorFilter;
173 SkXfermode* xfermode = fXfermode;
174
175 do {
176 fillbuffer(buffer, src, width);
reed@google.com82065d62011-02-07 15:30:46 +0000177
bsalomon49f085d2014-09-05 13:34:00 -0700178 if (colorFilter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 colorFilter->filterSpan(buffer, width, buffer);
180 }
bsalomon49f085d2014-09-05 13:34:00 -0700181 if (xfermode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700182 xfermode->xfer32(dst, buffer, width, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183 } else {
reed@android.comc4cae852009-09-23 15:06:10 +0000184 fProc32(dst, buffer, width, fAlpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 }
reed@google.com82065d62011-02-07 15:30:46 +0000186
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000187 dst = (SkPMColor* SK_RESTRICT)((char*)dst + dstRB);
188 src = (const SkPMColor16* SK_RESTRICT)((const char*)src + srcRB);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 } while (--height != 0);
190 }
reed@google.com82065d62011-02-07 15:30:46 +0000191
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192private:
193 typedef Sprite_D32_XferFilter INHERITED;
194};
195
196///////////////////////////////////////////////////////////////////////////////
197
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000198static void src_row(SkPMColor* SK_RESTRICT dst,
199 const SkPMColor16* SK_RESTRICT src, int count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 do {
201 *dst = SkPixel4444ToPixel32(*src);
202 src += 1;
203 dst += 1;
204 } while (--count != 0);
205}
206
207class Sprite_D32_S4444_Opaque : public SkSpriteBlitter {
208public:
reedc240e712015-05-23 12:26:41 -0700209 Sprite_D32_S4444_Opaque(const SkPixmap& source) : SkSpriteBlitter(source) {}
reed@google.com82065d62011-02-07 15:30:46 +0000210
mtklein36352bf2015-03-25 18:17:31 -0700211 void blitRect(int x, int y, int width, int height) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 SkASSERT(width > 0 && height > 0);
reedcb674142015-06-05 06:58:22 -0700213 SkPMColor* SK_RESTRICT dst = fDst.writable_addr32(x, y);
reedc240e712015-05-23 12:26:41 -0700214 const SkPMColor16* SK_RESTRICT src = fSource.addr16(x - fLeft, y - fTop);
reedcb674142015-06-05 06:58:22 -0700215 size_t dstRB = fDst.rowBytes();
reedc240e712015-05-23 12:26:41 -0700216 size_t srcRB = fSource.rowBytes();
reed@google.com82065d62011-02-07 15:30:46 +0000217
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 do {
219 src_row(dst, src, width);
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000220 dst = (SkPMColor* SK_RESTRICT)((char*)dst + dstRB);
221 src = (const SkPMColor16* SK_RESTRICT)((const char*)src + srcRB);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 } while (--height != 0);
223 }
224};
225
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000226static void srcover_row(SkPMColor* SK_RESTRICT dst,
227 const SkPMColor16* SK_RESTRICT src, int count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228 do {
229 *dst = SkPMSrcOver(SkPixel4444ToPixel32(*src), *dst);
230 src += 1;
231 dst += 1;
232 } while (--count != 0);
233}
234
235class Sprite_D32_S4444 : public SkSpriteBlitter {
236public:
reedc240e712015-05-23 12:26:41 -0700237 Sprite_D32_S4444(const SkPixmap& source) : SkSpriteBlitter(source) {}
reed@google.com82065d62011-02-07 15:30:46 +0000238
mtklein36352bf2015-03-25 18:17:31 -0700239 void blitRect(int x, int y, int width, int height) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 SkASSERT(width > 0 && height > 0);
reedcb674142015-06-05 06:58:22 -0700241 SkPMColor* SK_RESTRICT dst = fDst.writable_addr32(x, y);
reedc240e712015-05-23 12:26:41 -0700242 const SkPMColor16* SK_RESTRICT src = fSource.addr16(x - fLeft, y - fTop);
reedcb674142015-06-05 06:58:22 -0700243 size_t dstRB = fDst.rowBytes();
reedc240e712015-05-23 12:26:41 -0700244 size_t srcRB = fSource.rowBytes();
reed@google.com82065d62011-02-07 15:30:46 +0000245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 do {
247 srcover_row(dst, src, width);
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000248 dst = (SkPMColor* SK_RESTRICT)((char*)dst + dstRB);
249 src = (const SkPMColor16* SK_RESTRICT)((const char*)src + srcRB);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250 } while (--height != 0);
251 }
252};
253
254///////////////////////////////////////////////////////////////////////////////
255
brianosmanfe4b4f02016-02-26 09:19:02 -0800256SkSpriteBlitter* SkSpriteBlitter::ChooseL32(const SkPixmap& source, const SkPaint& paint,
Herb Derby57bfa022017-02-09 17:25:43 -0500257 SkArenaAlloc* allocator) {
halcanary96fcdcc2015-08-27 07:41:13 -0700258 SkASSERT(allocator != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259
halcanary96fcdcc2015-08-27 07:41:13 -0700260 if (paint.getMaskFilter() != nullptr) {
261 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262 }
263
reed@android.comc4cae852009-09-23 15:06:10 +0000264 U8CPU alpha = paint.getAlpha();
reed374772b2016-10-05 17:33:02 -0700265 bool isSrcOver = paint.isSrcOver();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266 SkColorFilter* filter = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700267 SkSpriteBlitter* blitter = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268
reed@google.com900ecf22014-02-20 20:55:37 +0000269 switch (source.colorType()) {
270 case kARGB_4444_SkColorType:
reed@android.comc4cae852009-09-23 15:06:10 +0000271 if (alpha != 0xFF) {
halcanary96fcdcc2015-08-27 07:41:13 -0700272 return nullptr; // we only have opaque sprites
reed@android.comc4cae852009-09-23 15:06:10 +0000273 }
reed374772b2016-10-05 17:33:02 -0700274 if (!isSrcOver || filter) {
Herb Derby57bfa022017-02-09 17:25:43 -0500275 blitter = allocator->make<Sprite_D32_S4444_XferFilter>(source, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 } else if (source.isOpaque()) {
Herb Derby57bfa022017-02-09 17:25:43 -0500277 blitter = allocator->make<Sprite_D32_S4444_Opaque>(source);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 } else {
Herb Derby57bfa022017-02-09 17:25:43 -0500279 blitter = allocator->make<Sprite_D32_S4444>(source);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 }
281 break;
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000282 case kN32_SkColorType:
reed374772b2016-10-05 17:33:02 -0700283 if (!isSrcOver || filter) {
reed@android.comc4cae852009-09-23 15:06:10 +0000284 if (255 == alpha) {
285 // this can handle xfermode or filter, but not alpha
Herb Derby57bfa022017-02-09 17:25:43 -0500286 blitter = allocator->make<Sprite_D32_S32A_XferFilter>(source, paint);
reed@android.comc4cae852009-09-23 15:06:10 +0000287 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288 } else {
reed@android.comc4cae852009-09-23 15:06:10 +0000289 // this can handle alpha, but not xfermode or filter
Herb Derby57bfa022017-02-09 17:25:43 -0500290 blitter = allocator->make<Sprite_D32_S32>(source, alpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291 }
292 break;
293 default:
294 break;
295 }
296 return blitter;
297}