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/SkColorFilter.h"
9#include "include/core/SkPaint.h"
10#include "include/private/SkColorData.h"
11#include "include/private/SkTemplates.h"
12#include "src/core/SkArenaAlloc.h"
13#include "src/core/SkBlitRow.h"
14#include "src/core/SkSpriteBlitter.h"
15#include "src/core/SkXfermodePriv.h"
16
17///////////////////////////////////////////////////////////////////////////////
18
19class Sprite_D32_S32 : public SkSpriteBlitter {
20public:
21    Sprite_D32_S32(const SkPixmap& src, U8CPU alpha)  : INHERITED(src) {
22        SkASSERT(src.colorType() == kN32_SkColorType);
23
24        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    }
35
36    void blitRect(int x, int y, int width, int height) override {
37        SkASSERT(width > 0 && height > 0);
38        uint32_t* SK_RESTRICT dst = fDst.writable_addr32(x, y);
39        const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop);
40        size_t dstRB = fDst.rowBytes();
41        size_t srcRB = fSource.rowBytes();
42        SkBlitRow::Proc32 proc = fProc32;
43        U8CPU             alpha = fAlpha;
44
45        do {
46            proc(dst, src, width, alpha);
47            dst = (uint32_t* SK_RESTRICT)((char*)dst + dstRB);
48            src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB);
49        } while (--height != 0);
50    }
51
52private:
53    SkBlitRow::Proc32   fProc32;
54    U8CPU               fAlpha;
55
56    using INHERITED = SkSpriteBlitter;
57};
58
59///////////////////////////////////////////////////////////////////////////////
60
61class Sprite_D32_S32A_Xfer: public SkSpriteBlitter {
62public:
63    Sprite_D32_S32A_Xfer(const SkPixmap& source, const SkPaint& paint) : SkSpriteBlitter(source) {
64        fXfermode = SkXfermode::Peek(paint.getBlendMode_or(SkBlendMode::kSrcOver));
65        SkASSERT(fXfermode);
66    }
67
68    void blitRect(int x, int y, int width, int height) override {
69        SkASSERT(width > 0 && height > 0);
70        uint32_t* SK_RESTRICT dst = fDst.writable_addr32(x, y);
71        const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop);
72        size_t dstRB = fDst.rowBytes();
73        size_t srcRB = fSource.rowBytes();
74        SkXfermode* xfermode = fXfermode;
75
76        do {
77            xfermode->xfer32(dst, src, width, nullptr);
78
79            dst = (uint32_t* SK_RESTRICT)((char*)dst + dstRB);
80            src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB);
81        } while (--height != 0);
82    }
83
84protected:
85    SkXfermode* fXfermode;
86
87private:
88    using INHERITED = SkSpriteBlitter;
89};
90
91///////////////////////////////////////////////////////////////////////////////
92
93SkSpriteBlitter* SkSpriteBlitter::ChooseL32(const SkPixmap& source, const SkPaint& paint,
94                                            SkArenaAlloc* allocator) {
95    SkASSERT(allocator != nullptr);
96
97    if (paint.getColorFilter() != nullptr) {
98        return nullptr;
99    }
100    if (paint.getMaskFilter() != nullptr) {
101        return nullptr;
102    }
103    if (!paint.asBlendMode()) {
104        return nullptr;
105    }
106
107    U8CPU alpha = paint.getAlpha();
108
109    if (source.colorType() == kN32_SkColorType) {
110        if (paint.isSrcOver()) {
111            // this can handle alpha, but not xfermode
112            return allocator->make<Sprite_D32_S32>(source, alpha);
113        }
114        if (255 == alpha) {
115            // this can handle an xfermode, but not alpha
116            return allocator->make<Sprite_D32_S32A_Xfer>(source, paint);
117        }
118    }
119    return nullptr;
120}
121