1/*
2 * Copyright 2017 Google Inc.
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
19static void S32_src(uint16_t dst[], const SkPMColor src[], int count) {
20    for (int i = 0; i < count; ++i) {
21        dst[i] = SkPixel32ToPixel16(src[i]);
22    }
23}
24
25static void S32_srcover(uint16_t dst[], const SkPMColor src[], int count) {
26    for (int i = 0; i < count; ++i) {
27        dst[i] = SkSrcOver32To16(src[i], dst[i]);
28    }
29}
30
31class Sprite_D16_S32 : public SkSpriteBlitter {
32public:
33    Sprite_D16_S32(const SkPixmap& src, SkBlendMode mode)  : INHERITED(src) {
34        SkASSERT(src.colorType() == kN32_SkColorType);
35        SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver);
36
37        fUseSrcOver = (mode == SkBlendMode::kSrcOver) && !src.isOpaque();
38    }
39
40    void blitRect(int x, int y, int width, int height) override {
41        SkASSERT(width > 0 && height > 0);
42        uint16_t* SK_RESTRICT dst = fDst.writable_addr16(x, y);
43        const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop);
44        size_t dstRB = fDst.rowBytes();
45        size_t srcRB = fSource.rowBytes();
46
47        do {
48            if (fUseSrcOver) {
49                S32_srcover(dst, src, width);
50            } else {
51                S32_src(dst, src, width);
52            }
53
54            dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB);
55            src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB);
56        } while (--height != 0);
57    }
58
59private:
60    bool fUseSrcOver;
61
62    using INHERITED = SkSpriteBlitter;
63};
64
65SkSpriteBlitter* SkSpriteBlitter::ChooseL565(const SkPixmap& source, const SkPaint& paint,
66                                             SkArenaAlloc* allocator) {
67    SkASSERT(allocator != nullptr);
68
69    if (paint.getColorFilter() != nullptr) {
70        return nullptr;
71    }
72    if (paint.getMaskFilter() != nullptr) {
73        return nullptr;
74    }
75
76    U8CPU alpha = paint.getAlpha();
77    if (alpha != 0xFF) {
78        return nullptr;
79    }
80
81    const auto bm = paint.asBlendMode();
82    if ((source.colorType() == kN32_SkColorType) && bm) {
83        switch (bm.value()) {
84            case SkBlendMode::kSrc:
85            case SkBlendMode::kSrcOver:
86                return allocator->make<Sprite_D16_S32>(source, bm.value());
87            default:
88                break;
89        }
90    }
91    return nullptr;
92}
93
94//////////////////////////////////////////////////////////////////////////////////////////////////
95
96static unsigned div255(unsigned a, unsigned b) {
97    return (a * b * 257 + 127) >> 16;
98}
99
100static void S32_src_da8(uint8_t dst[], const SkPMColor src[], int count) {
101    for (int i = 0; i < count; ++i) {
102        dst[i] = SkGetPackedA32(src[i]);
103    }
104}
105
106static void S32_srcover_da8(uint8_t dst[], const SkPMColor src[], int count) {
107    for (int i = 0; i < count; ++i) {
108        SkPMColor c = src[i];
109        if (c) {
110            unsigned a = SkGetPackedA32(c);
111            if (a == 0xFF) {
112                dst[i] = 0xFF;
113            } else {
114                dst[i] = a + div255(255 - a, dst[i]);
115            }
116        }
117    }
118}
119
120class Sprite_D8_S32 : public SkSpriteBlitter {
121public:
122    Sprite_D8_S32(const SkPixmap& src, SkBlendMode mode)  : INHERITED(src) {
123        SkASSERT(src.colorType() == kN32_SkColorType);
124        SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver);
125
126        fUseSrcOver = (mode == SkBlendMode::kSrcOver) && !src.isOpaque();
127    }
128
129    void blitRect(int x, int y, int width, int height) override {
130        SkASSERT(width > 0 && height > 0);
131        uint8_t* SK_RESTRICT dst = fDst.writable_addr8(x, y);
132        const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop);
133        size_t dstRB = fDst.rowBytes();
134        size_t srcRB = fSource.rowBytes();
135
136        do {
137            if (fUseSrcOver) {
138                S32_srcover_da8(dst, src, width);
139            } else {
140                S32_src_da8(dst, src, width);
141            }
142
143            dst = (uint8_t* SK_RESTRICT)((char*)dst + dstRB);
144            src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB);
145        } while (--height != 0);
146    }
147
148private:
149    bool fUseSrcOver;
150
151    using INHERITED = SkSpriteBlitter;
152};
153
154SkSpriteBlitter* SkSpriteBlitter::ChooseLA8(const SkPixmap& source, const SkPaint& paint,
155                                            SkArenaAlloc* allocator) {
156    SkASSERT(allocator != nullptr);
157
158    if (paint.getColorFilter() != nullptr) {
159        return nullptr;
160    }
161    if (paint.getMaskFilter() != nullptr) {
162        return nullptr;
163    }
164
165    U8CPU alpha = paint.getAlpha();
166    if (alpha != 0xFF) {
167        return nullptr;
168    }
169
170    const auto bm = paint.asBlendMode();
171    if ((source.colorType() == kN32_SkColorType) && bm) {
172        switch (bm.value()) {
173            case SkBlendMode::kSrc:
174            case SkBlendMode::kSrcOver:
175                return allocator->make<Sprite_D8_S32>(source, bm.value());
176            default:
177                break;
178        }
179    }
180    return nullptr;
181}
182