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 "SkArenaAlloc.h"
9 #include "SkOpts.h"
10 #include "SkSpriteBlitter.h"
11
SkSpriteBlitter(const SkPixmap & source)12 SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source)
13 : fSource(source) {}
14
setup(const SkPixmap & dst,int left,int top,const SkPaint & paint)15 void SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) {
16 fDst = dst;
17 fLeft = left;
18 fTop = top;
19 fPaint = &paint;
20 }
21
blitH(int x,int y,int width)22 void SkSpriteBlitter::blitH(int x, int y, int width) {
23 SkDEBUGFAIL("how did we get here?");
24
25 // Fallback to blitRect.
26 this->blitRect(x, y, width, 1);
27 }
28
blitAntiH(int x,int y,const SkAlpha antialias[],const int16_t runs[])29 void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) {
30 SkDEBUGFAIL("how did we get here?");
31
32 // No fallback strategy.
33 }
34
blitV(int x,int y,int height,SkAlpha alpha)35 void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
36 SkDEBUGFAIL("how did we get here?");
37
38 // Fall back to superclass if the code gets here in release mode.
39 INHERITED::blitV(x, y, height, alpha);
40 }
41
blitMask(const SkMask & mask,const SkIRect & clip)42 void SkSpriteBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
43 SkDEBUGFAIL("how did we get here?");
44
45 // Fall back to superclass if the code gets here in release mode.
46 INHERITED::blitMask(mask, clip);
47 }
48
49 ///////////////////////////////////////////////////////////////////////////////
50
51 // Only valid if...
52 // 1. src == dst format
53 // 2. paint has no modifiers (i.e. alpha, colorfilter, etc.)
54 // 3. xfermode needs no blending: e.g. kSrc_Mode or kSrcOver_Mode + opaque src
55 //
56 class SkSpriteBlitter_Src_SrcOver final : public SkSpriteBlitter {
57 public:
Supports(const SkPixmap & dst,const SkPixmap & src,const SkPaint & paint)58 static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) {
59 if (dst.colorType() != src.colorType()) {
60 return false;
61 }
62 if (dst.info().gammaCloseToSRGB() != src.info().gammaCloseToSRGB()) {
63 return false;
64 }
65 if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) {
66 return false;
67 }
68 if (0xFF != paint.getAlpha()) {
69 return false;
70 }
71 SkBlendMode mode = paint.getBlendMode();
72 if (SkBlendMode::kSrc == mode) {
73 return true;
74 }
75 if (SkBlendMode::kSrcOver == mode && src.isOpaque()) {
76 return true;
77 }
78
79 // At this point memcpy can't be used. The following check for using SrcOver.
80
81 if (dst.colorType() != kN32_SkColorType || !dst.info().gammaCloseToSRGB()) {
82 return false;
83 }
84
85 return SkBlendMode::kSrcOver == mode;
86 }
87
SkSpriteBlitter_Src_SrcOver(const SkPixmap & src)88 SkSpriteBlitter_Src_SrcOver(const SkPixmap& src)
89 : INHERITED(src) {}
90
setup(const SkPixmap & dst,int left,int top,const SkPaint & paint)91 void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
92 SkASSERT(Supports(dst, fSource, paint));
93 this->INHERITED::setup(dst, left, top, paint);
94 SkBlendMode mode = paint.getBlendMode();
95
96 SkASSERT(mode == SkBlendMode::kSrcOver || mode == SkBlendMode::kSrc);
97
98 if (mode == SkBlendMode::kSrcOver && !fSource.isOpaque()) {
99 fUseMemcpy = false;
100 }
101 }
102
blitRect(int x,int y,int width,int height)103 void blitRect(int x, int y, int width, int height) override {
104 SkASSERT(fDst.colorType() == fSource.colorType());
105 SkASSERT(fDst.info().gammaCloseToSRGB() == fSource.info().gammaCloseToSRGB());
106 SkASSERT(width > 0 && height > 0);
107
108 if (fUseMemcpy) {
109 char* dst = (char*)fDst.writable_addr(x, y);
110 const char* src = (const char*)fSource.addr(x - fLeft, y - fTop);
111 const size_t dstRB = fDst.rowBytes();
112 const size_t srcRB = fSource.rowBytes();
113 const size_t bytesToCopy = width << fSource.shiftPerPixel();
114
115 while (height --> 0) {
116 memcpy(dst, src, bytesToCopy);
117 dst += dstRB;
118 src += srcRB;
119 }
120 } else {
121 uint32_t* dst = fDst.writable_addr32(x, y);
122 const uint32_t* src = fSource.addr32(x - fLeft, y - fTop);
123 const int dstStride = fDst.rowBytesAsPixels();
124 const int srcStride = fSource.rowBytesAsPixels();
125
126 while (height --> 0) {
127 SkOpts::srcover_srgb_srgb(dst, src, width, width);
128 dst += dstStride;
129 src += srcStride;
130 }
131 }
132 }
133
134 private:
135 typedef SkSpriteBlitter INHERITED;
136
137 bool fUseMemcpy {true};
138 };
139
140 // returning null means the caller will call SkBlitter::Choose() and
141 // have wrapped the source bitmap inside a shader
ChooseSprite(const SkPixmap & dst,const SkPaint & paint,const SkPixmap & source,int left,int top,SkArenaAlloc * allocator)142 SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
143 const SkPixmap& source, int left, int top, SkArenaAlloc* allocator) {
144 /* We currently ignore antialiasing and filtertype, meaning we will take our
145 special blitters regardless of these settings. Ignoring filtertype seems fine
146 since by definition there is no scale in the matrix. Ignoring antialiasing is
147 a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
148 and respect that by blending the edges of the bitmap against the device. To support
149 this we could either add more special blitters here, or detect antialiasing in the
150 paint and return null if it is set, forcing the client to take the slow shader case
151 (which does respect soft edges).
152 */
153 SkASSERT(allocator != nullptr);
154
155 // Defer to the general code if the pixels are unpremultipled. This case is not common,
156 // and this simplifies the code.
157 if (source.alphaType() == kUnpremul_SkAlphaType) {
158 return nullptr;
159 }
160
161 SkSpriteBlitter* blitter = nullptr;
162
163 if (SkSpriteBlitter_Src_SrcOver::Supports(dst, source, paint)) {
164 blitter = allocator->make<SkSpriteBlitter_Src_SrcOver>(source);
165 } else {
166 switch (dst.colorType()) {
167 case kRGB_565_SkColorType:
168 blitter = SkSpriteBlitter::ChooseD16(source, paint, allocator);
169 break;
170 case kN32_SkColorType:
171 if (dst.info().gammaCloseToSRGB()) {
172 blitter = SkSpriteBlitter::ChooseS32(source, paint, allocator);
173 } else {
174 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
175 }
176 break;
177 case kRGBA_F16_SkColorType:
178 blitter = SkSpriteBlitter::ChooseF16(source, paint, allocator);
179 break;
180 default:
181 break;
182 }
183 }
184
185 if (blitter) {
186 blitter->setup(dst, left, top, paint);
187 }
188 return blitter;
189 }
190