1/*
2 * Copyright 2015 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 "SkBitmap.h"
9#include "SkCanvas.h"
10#include "SkColorPriv.h"
11#include "SkConvertPixels.h"
12#include "SkData.h"
13#include "SkImageInfoPriv.h"
14#include "SkHalf.h"
15#include "SkMask.h"
16#include "SkNx.h"
17#include "SkPM4f.h"
18#include "SkPixmap.h"
19#include "SkReadPixelsRec.h"
20#include "SkSurface.h"
21#include "SkUtils.h"
22
23/////////////////////////////////////////////////////////////////////////////////////////////////
24
25void SkPixmap::reset() {
26    fPixels = nullptr;
27    fRowBytes = 0;
28    fInfo = SkImageInfo::MakeUnknown();
29}
30
31void SkPixmap::reset(const SkImageInfo& info, const void* addr, size_t rowBytes) {
32    if (addr) {
33        SkASSERT(info.validRowBytes(rowBytes));
34    }
35    fPixels = addr;
36    fRowBytes = rowBytes;
37    fInfo = info;
38}
39
40bool SkPixmap::reset(const SkMask& src) {
41    if (SkMask::kA8_Format == src.fFormat) {
42        this->reset(SkImageInfo::MakeA8(src.fBounds.width(), src.fBounds.height()),
43                    src.fImage, src.fRowBytes);
44        return true;
45    }
46    this->reset();
47    return false;
48}
49
50void SkPixmap::setColorSpace(sk_sp<SkColorSpace> cs) {
51    fInfo = fInfo.makeColorSpace(std::move(cs));
52}
53
54bool SkPixmap::extractSubset(SkPixmap* result, const SkIRect& subset) const {
55    SkIRect srcRect, r;
56    srcRect.set(0, 0, this->width(), this->height());
57    if (!r.intersect(srcRect, subset)) {
58        return false;   // r is empty (i.e. no intersection)
59    }
60
61    // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
62    // exited above.
63    SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
64    SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
65
66    const void* pixels = nullptr;
67    if (fPixels) {
68        const size_t bpp = fInfo.bytesPerPixel();
69        pixels = (const uint8_t*)fPixels + r.fTop * fRowBytes + r.fLeft * bpp;
70    }
71    result->reset(fInfo.makeWH(r.width(), r.height()), pixels, fRowBytes);
72    return true;
73}
74
75bool SkPixmap::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, int x, int y,
76                          SkTransferFunctionBehavior behavior) const {
77    if (!SkImageInfoValidConversion(dstInfo, fInfo)) {
78        return false;
79    }
80
81    SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, x, y);
82    if (!rec.trim(fInfo.width(), fInfo.height())) {
83        return false;
84    }
85
86    const void* srcPixels = this->addr(rec.fX, rec.fY);
87    const SkImageInfo srcInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
88    SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes(),
89                    nullptr, behavior);
90    return true;
91}
92
93static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) {
94    unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) |
95    (SkR32To4444(r) << SK_R4444_SHIFT) |
96    (SkG32To4444(g) << SK_G4444_SHIFT) |
97    (SkB32To4444(b) << SK_B4444_SHIFT);
98    return SkToU16(pixel);
99}
100
101bool SkPixmap::erase(SkColor color, const SkIRect& inArea) const {
102    if (nullptr == fPixels) {
103        return false;
104    }
105    SkIRect area;
106    if (!area.intersect(this->bounds(), inArea)) {
107        return false;
108    }
109
110    U8CPU a = SkColorGetA(color);
111    U8CPU r = SkColorGetR(color);
112    U8CPU g = SkColorGetG(color);
113    U8CPU b = SkColorGetB(color);
114
115    int height = area.height();
116    const int width = area.width();
117    const int rowBytes = this->rowBytes();
118
119    switch (this->colorType()) {
120        case kGray_8_SkColorType: {
121            if (255 != a) {
122                r = SkMulDiv255Round(r, a);
123                g = SkMulDiv255Round(g, a);
124                b = SkMulDiv255Round(b, a);
125            }
126            int gray = SkComputeLuminance(r, g, b);
127            uint8_t* p = this->writable_addr8(area.fLeft, area.fTop);
128            while (--height >= 0) {
129                memset(p, gray, width);
130                p += rowBytes;
131            }
132            break;
133        }
134        case kAlpha_8_SkColorType: {
135            uint8_t* p = this->writable_addr8(area.fLeft, area.fTop);
136            while (--height >= 0) {
137                memset(p, a, width);
138                p += rowBytes;
139            }
140            break;
141        }
142        case kARGB_4444_SkColorType:
143        case kRGB_565_SkColorType: {
144            uint16_t* p = this->writable_addr16(area.fLeft, area.fTop);
145            uint16_t v;
146
147            // make rgb premultiplied
148            if (255 != a) {
149                r = SkMulDiv255Round(r, a);
150                g = SkMulDiv255Round(g, a);
151                b = SkMulDiv255Round(b, a);
152            }
153
154            if (kARGB_4444_SkColorType == this->colorType()) {
155                v = pack_8888_to_4444(a, r, g, b);
156            } else {
157                v = SkPackRGB16(r >> (8 - SK_R16_BITS),
158                                g >> (8 - SK_G16_BITS),
159                                b >> (8 - SK_B16_BITS));
160            }
161            while (--height >= 0) {
162                sk_memset16(p, v, width);
163                p = (uint16_t*)((char*)p + rowBytes);
164            }
165            break;
166        }
167        case kBGRA_8888_SkColorType:
168        case kRGBA_8888_SkColorType: {
169            uint32_t* p = this->writable_addr32(area.fLeft, area.fTop);
170
171            if (255 != a && kPremul_SkAlphaType == this->alphaType()) {
172                r = SkMulDiv255Round(r, a);
173                g = SkMulDiv255Round(g, a);
174                b = SkMulDiv255Round(b, a);
175            }
176            uint32_t v = kRGBA_8888_SkColorType == this->colorType()
177                             ? SkPackARGB_as_RGBA(a, r, g, b)
178                             : SkPackARGB_as_BGRA(a, r, g, b);
179
180            while (--height >= 0) {
181                sk_memset32(p, v, width);
182                p = (uint32_t*)((char*)p + rowBytes);
183            }
184            break;
185        }
186        case kRGBA_F16_SkColorType:
187            // The colorspace is unspecified, so assume linear just like getColor().
188            this->erase(SkColor4f{(1 / 255.0f) * r,
189                                  (1 / 255.0f) * g,
190                                  (1 / 255.0f) * b,
191                                  (1 / 255.0f) * a}, &area);
192            break;
193        default:
194            return false; // no change, so don't call notifyPixelsChanged()
195    }
196    return true;
197}
198
199bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const {
200    SkPixmap pm;
201    if (subset) {
202        if (!this->extractSubset(&pm, *subset)) {
203            return false;
204        }
205    } else {
206        pm = *this;
207    }
208
209    const SkColor4f color = origColor.pin();
210
211    if (kRGBA_F16_SkColorType != pm.colorType()) {
212        return pm.erase(color.toSkColor());
213    }
214
215    const uint64_t half4 = color.premul().toF16();
216    for (int y = 0; y < pm.height(); ++y) {
217        sk_memset64(pm.writable_addr64(0, y), half4, pm.width());
218    }
219    return true;
220}
221
222bool SkPixmap::scalePixels(const SkPixmap& dst, SkFilterQuality quality) const {
223    // Can't do anthing with empty src or dst
224    if (this->width() <= 0 || this->height() <= 0 || dst.width() <= 0 || dst.height() <= 0) {
225        return false;
226    }
227
228    // no scaling involved?
229    if (dst.width() == this->width() && dst.height() == this->height()) {
230        return this->readPixels(dst);
231    }
232
233    SkBitmap bitmap;
234    if (!bitmap.installPixels(*this)) {
235        return false;
236    }
237    bitmap.setIsVolatile(true); // so we don't try to cache it
238
239    auto surface(SkSurface::MakeRasterDirect(dst.info(), dst.writable_addr(), dst.rowBytes()));
240    if (!surface) {
241        return false;
242    }
243
244    SkPaint paint;
245    paint.setFilterQuality(quality);
246    paint.setBlendMode(SkBlendMode::kSrc);
247    surface->getCanvas()->drawBitmapRect(bitmap, SkRect::MakeIWH(dst.width(), dst.height()),
248                                         &paint);
249    return true;
250}
251
252//////////////////////////////////////////////////////////////////////////////////////////////////
253
254SkColor SkPixmap::getColor(int x, int y) const {
255    SkASSERT(this->addr());
256    SkASSERT((unsigned)x < (unsigned)this->width());
257    SkASSERT((unsigned)y < (unsigned)this->height());
258
259    const bool needsUnpremul = (kPremul_SkAlphaType == fInfo.alphaType());
260    auto toColor = [needsUnpremul](uint32_t maybePremulColor) {
261        return needsUnpremul ? SkUnPreMultiply::PMColorToColor(maybePremulColor)
262                             : SkSwizzle_BGRA_to_PMColor(maybePremulColor);
263    };
264
265    switch (this->colorType()) {
266        case kGray_8_SkColorType: {
267            uint8_t value = *this->addr8(x, y);
268            return SkColorSetRGB(value, value, value);
269        }
270        case kAlpha_8_SkColorType: {
271            return SkColorSetA(0, *this->addr8(x, y));
272        }
273        case kRGB_565_SkColorType: {
274            return SkPixel16ToColor(*this->addr16(x, y));
275        }
276        case kARGB_4444_SkColorType: {
277            uint16_t value = *this->addr16(x, y);
278            SkPMColor c = SkPixel4444ToPixel32(value);
279            return toColor(c);
280        }
281        case kBGRA_8888_SkColorType: {
282            uint32_t value = *this->addr32(x, y);
283            SkPMColor c = SkSwizzle_BGRA_to_PMColor(value);
284            return toColor(c);
285        }
286        case kRGBA_8888_SkColorType: {
287            uint32_t value = *this->addr32(x, y);
288            SkPMColor c = SkSwizzle_RGBA_to_PMColor(value);
289            return toColor(c);
290        }
291        case kRGBA_F16_SkColorType: {
292             const uint64_t* addr =
293                 (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x;
294             Sk4f p4 = SkHalfToFloat_finite_ftz(*addr);
295             if (p4[3] && needsUnpremul) {
296                 float inva = 1 / p4[3];
297                 p4 = p4 * Sk4f(inva, inva, inva, 1);
298             }
299             SkColor c;
300             SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c);
301             // p4 is RGBA, but we want BGRA, so we need to swap next
302             return SkSwizzle_RB(c);
303        }
304        default:
305            SkDEBUGFAIL("");
306            return SkColorSetARGB(0, 0, 0, 0);
307    }
308}
309
310bool SkPixmap::computeIsOpaque() const {
311    const int height = this->height();
312    const int width = this->width();
313
314    switch (this->colorType()) {
315        case kAlpha_8_SkColorType: {
316            unsigned a = 0xFF;
317            for (int y = 0; y < height; ++y) {
318                const uint8_t* row = this->addr8(0, y);
319                for (int x = 0; x < width; ++x) {
320                    a &= row[x];
321                }
322                if (0xFF != a) {
323                    return false;
324                }
325            }
326            return true;
327        } break;
328        case kRGB_565_SkColorType:
329        case kGray_8_SkColorType:
330            return true;
331            break;
332        case kARGB_4444_SkColorType: {
333            unsigned c = 0xFFFF;
334            for (int y = 0; y < height; ++y) {
335                const SkPMColor16* row = this->addr16(0, y);
336                for (int x = 0; x < width; ++x) {
337                    c &= row[x];
338                }
339                if (0xF != SkGetPackedA4444(c)) {
340                    return false;
341                }
342            }
343            return true;
344        } break;
345        case kBGRA_8888_SkColorType:
346        case kRGBA_8888_SkColorType: {
347            SkPMColor c = (SkPMColor)~0;
348            for (int y = 0; y < height; ++y) {
349                const SkPMColor* row = this->addr32(0, y);
350                for (int x = 0; x < width; ++x) {
351                    c &= row[x];
352                }
353                if (0xFF != SkGetPackedA32(c)) {
354                    return false;
355                }
356            }
357            return true;
358        }
359        case kRGBA_F16_SkColorType: {
360            const SkHalf* row = (const SkHalf*)this->addr();
361            for (int y = 0; y < height; ++y) {
362                for (int x = 0; x < width; ++x) {
363                    if (row[4 * x + 3] < SK_Half1) {
364                        return false;
365                    }
366                }
367                row += this->rowBytes() >> 1;
368            }
369            return true;
370        }
371        default:
372            break;
373    }
374    return false;
375}
376