• 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 "include/core/SkColorSpace.h"
9 #include "include/private/SkImageInfoPriv.h"
10 #include "src/core/SkArenaAlloc.h"
11 #include "src/core/SkColorSpacePriv.h"
12 #include "src/core/SkColorSpaceXformSteps.h"
13 #include "src/core/SkCoreBlitters.h"
14 #include "src/core/SkOpts.h"
15 #include "src/core/SkRasterPipeline.h"
16 #include "src/core/SkSpriteBlitter.h"
17 #include "src/core/SkVMBlitter.h"
18 
19 extern bool gUseSkVMBlitter;
20 extern bool gSkForceRasterPipelineBlitter;
21 
SkSpriteBlitter(const SkPixmap & source)22 SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source)
23     : fSource(source) {}
24 
setup(const SkPixmap & dst,int left,int top,const SkPaint & paint)25 bool SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) {
26     fDst = dst;
27     fLeft = left;
28     fTop = top;
29     fPaint = &paint;
30     return true;
31 }
32 
blitH(int x,int y,int width)33 void SkSpriteBlitter::blitH(int x, int y, int width) {
34     SkDEBUGFAIL("how did we get here?");
35 
36     // Fallback to blitRect.
37     this->blitRect(x, y, width, 1);
38 }
39 
blitAntiH(int x,int y,const SkAlpha antialias[],const int16_t runs[])40 void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) {
41     SkDEBUGFAIL("how did we get here?");
42 
43     // No fallback strategy.
44 }
45 
blitV(int x,int y,int height,SkAlpha alpha)46 void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
47     SkDEBUGFAIL("how did we get here?");
48 
49     // Fall back to superclass if the code gets here in release mode.
50     INHERITED::blitV(x, y, height, alpha);
51 }
52 
blitMask(const SkMask & mask,const SkIRect & clip)53 void SkSpriteBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
54     SkDEBUGFAIL("how did we get here?");
55 
56     // Fall back to superclass if the code gets here in release mode.
57     INHERITED::blitMask(mask, clip);
58 }
59 
60 ///////////////////////////////////////////////////////////////////////////////
61 
62 class SkSpriteBlitter_Memcpy final : public SkSpriteBlitter {
63 public:
Supports(const SkPixmap & dst,const SkPixmap & src,const SkPaint & paint)64     static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) {
65         // the caller has already inspected the colorspace on src and dst
66         SkASSERT(0 == SkColorSpaceXformSteps(src,dst).flags.mask());
67 
68         if (dst.colorType() != src.colorType()) {
69             return false;
70         }
71         if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) {
72             return false;
73         }
74         if (0xFF != paint.getAlpha()) {
75             return false;
76         }
77         const auto mode = paint.asBlendMode();
78         return mode == SkBlendMode::kSrc || (mode == SkBlendMode::kSrcOver && src.isOpaque());
79     }
80 
SkSpriteBlitter_Memcpy(const SkPixmap & src)81     SkSpriteBlitter_Memcpy(const SkPixmap& src)
82         : INHERITED(src) {}
83 
blitRect(int x,int y,int width,int height)84     void blitRect(int x, int y, int width, int height) override {
85         SkASSERT(fDst.colorType() == fSource.colorType());
86         SkASSERT(width > 0 && height > 0);
87 
88         char* dst = (char*)fDst.writable_addr(x, y);
89         const char* src = (const char*)fSource.addr(x - fLeft, y - fTop);
90         const size_t dstRB = fDst.rowBytes();
91         const size_t srcRB = fSource.rowBytes();
92         const size_t bytesToCopy = width << fSource.shiftPerPixel();
93 
94         while (height --> 0) {
95             memcpy(dst, src, bytesToCopy);
96             dst += dstRB;
97             src += srcRB;
98         }
99     }
100 
101 private:
102     using INHERITED = SkSpriteBlitter;
103 };
104 
105 class SkRasterPipelineSpriteBlitter : public SkSpriteBlitter {
106 public:
SkRasterPipelineSpriteBlitter(const SkPixmap & src,SkArenaAlloc * alloc,sk_sp<SkShader> clipShader)107     SkRasterPipelineSpriteBlitter(const SkPixmap& src, SkArenaAlloc* alloc,
108                                   sk_sp<SkShader> clipShader)
109         : INHERITED(src)
110         , fAlloc(alloc)
111         , fBlitter(nullptr)
112         , fSrcPtr{nullptr, 0}
113         , fClipShader(std::move(clipShader))
114     {}
115 
setup(const SkPixmap & dst,int left,int top,const SkPaint & paint)116     bool setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
117         fDst  = dst;
118         fLeft = left;
119         fTop  = top;
120         fPaintColor = paint.getColor4f();
121 
122         SkRasterPipeline p(fAlloc);
123         p.append_load(fSource.colorType(), &fSrcPtr);
124 
125         if (SkColorTypeIsAlphaOnly(fSource.colorType())) {
126             // The color for A8 images comes from the (sRGB) paint color.
127             p.append_set_rgb(fAlloc, fPaintColor);
128             p.append(SkRasterPipeline::premul);
129         }
130         if (auto dstCS = fDst.colorSpace()) {
131             auto srcCS = fSource.colorSpace();
132             if (!srcCS || SkColorTypeIsAlphaOnly(fSource.colorType())) {
133                 // We treat untagged images as sRGB.
134                 // Alpha-only images get their r,g,b from the paint color, so they're also sRGB.
135                 srcCS = sk_srgb_singleton();
136             }
137             auto srcAT = fSource.isOpaque() ? kOpaque_SkAlphaType
138                                             : kPremul_SkAlphaType;
139             fAlloc->make<SkColorSpaceXformSteps>(srcCS, srcAT,
140                                                  dstCS, kPremul_SkAlphaType)
141                 ->apply(&p);
142         }
143         if (fPaintColor.fA != 1.0f) {
144             p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA);
145         }
146 
147         bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f;
148         fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc, fClipShader);
149         return fBlitter != nullptr;
150     }
151 
blitRect(int x,int y,int width,int height)152     void blitRect(int x, int y, int width, int height) override {
153         fSrcPtr.stride = fSource.rowBytesAsPixels();
154 
155         // We really want fSrcPtr.pixels = fSource.addr(-fLeft, -fTop) here, but that asserts.
156         // Instead we ask for addr(-fLeft+x, -fTop+y), then back up (x,y) manually.
157         // Representing bpp as a size_t keeps all this math in size_t instead of int,
158         // which could wrap around with large enough fSrcPtr.stride and y.
159         size_t bpp = fSource.info().bytesPerPixel();
160         fSrcPtr.pixels = (char*)fSource.addr(-fLeft+x, -fTop+y) - bpp * x
161                                                                 - bpp * y * fSrcPtr.stride;
162 
163         fBlitter->blitRect(x,y,width,height);
164     }
165 
166 private:
167     SkArenaAlloc*              fAlloc;
168     SkBlitter*                 fBlitter;
169     SkRasterPipeline_MemoryCtx fSrcPtr;
170     SkColor4f                  fPaintColor;
171     sk_sp<SkShader>            fClipShader;
172 
173     using INHERITED = SkSpriteBlitter;
174 };
175 
176 // returning null means the caller will call SkBlitter::Choose() and
177 // have wrapped the source bitmap inside a shader
ChooseSprite(const SkPixmap & dst,const SkPaint & paint,const SkPixmap & source,int left,int top,SkArenaAlloc * alloc,sk_sp<SkShader> clipShader)178 SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
179                                    const SkPixmap& source, int left, int top,
180                                    SkArenaAlloc* alloc, sk_sp<SkShader> clipShader) {
181     /*  We currently ignore antialiasing and filtertype, meaning we will take our
182         special blitters regardless of these settings. Ignoring filtertype seems fine
183         since by definition there is no scale in the matrix. Ignoring antialiasing is
184         a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
185         and respect that by blending the edges of the bitmap against the device. To support
186         this we could either add more special blitters here, or detect antialiasing in the
187         paint and return null if it is set, forcing the client to take the slow shader case
188         (which does respect soft edges).
189     */
190     SkASSERT(alloc != nullptr);
191 
192     if (gUseSkVMBlitter) {
193         return SkVMBlitter::Make(dst, paint, source,left,top, alloc, std::move(clipShader));
194     }
195 
196     // TODO: in principle SkRasterPipelineSpriteBlitter could be made to handle this.
197     if (source.alphaType() == kUnpremul_SkAlphaType) {
198         return nullptr;
199     }
200 
201     SkSpriteBlitter* blitter = nullptr;
202 
203     if (gSkForceRasterPipelineBlitter) {
204         // Do not use any of these optimized memory blitters
205     } else if (0 == SkColorSpaceXformSteps(source,dst).flags.mask() && !clipShader) {
206         if (!blitter && SkSpriteBlitter_Memcpy::Supports(dst, source, paint)) {
207             blitter = alloc->make<SkSpriteBlitter_Memcpy>(source);
208         }
209         if (!blitter) {
210             switch (dst.colorType()) {
211                 case kN32_SkColorType:
212                     blitter = SkSpriteBlitter::ChooseL32(source, paint, alloc);
213                     break;
214                 case kRGB_565_SkColorType:
215                     blitter = SkSpriteBlitter::ChooseL565(source, paint, alloc);
216                     break;
217                 case kAlpha_8_SkColorType:
218                     blitter = SkSpriteBlitter::ChooseLA8(source, paint, alloc);
219                     break;
220                 default:
221                     break;
222             }
223         }
224     }
225     if (!blitter && !paint.getMaskFilter()) {
226         blitter = alloc->make<SkRasterPipelineSpriteBlitter>(source, alloc, clipShader);
227     }
228 
229     if (blitter && blitter->setup(dst, left,top, paint)) {
230         return blitter;
231     }
232 
233     return SkVMBlitter::Make(dst, paint, source,left,top, alloc, std::move(clipShader));
234 }
235