• 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 "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