Coverage Report

Created: 2021-08-22 09:07

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