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 "SkColorData.h"
11 #include "SkConvertPixels.h"
12 #include "SkData.h"
13 #include "SkImageInfoPriv.h"
14 #include "SkImageShader.h"
15 #include "SkHalf.h"
16 #include "SkMask.h"
17 #include "SkNx.h"
18 #include "SkPM4f.h"
19 #include "SkPixmapPriv.h"
20 #include "SkReadPixelsRec.h"
21 #include "SkSurface.h"
22 #include "SkTemplates.h"
23 #include "SkUnPreMultiply.h"
24 #include "SkUtils.h"
25 
26 /////////////////////////////////////////////////////////////////////////////////////////////////
27 
reset()28 void SkPixmap::reset() {
29     fPixels = nullptr;
30     fRowBytes = 0;
31     fInfo = SkImageInfo::MakeUnknown();
32 }
33 
reset(const SkImageInfo & info,const void * addr,size_t rowBytes)34 void SkPixmap::reset(const SkImageInfo& info, const void* addr, size_t rowBytes) {
35     if (addr) {
36         SkASSERT(info.validRowBytes(rowBytes));
37     }
38     fPixels = addr;
39     fRowBytes = rowBytes;
40     fInfo = info;
41 }
42 
reset(const SkMask & src)43 bool SkPixmap::reset(const SkMask& src) {
44     if (SkMask::kA8_Format == src.fFormat) {
45         this->reset(SkImageInfo::MakeA8(src.fBounds.width(), src.fBounds.height()),
46                     src.fImage, src.fRowBytes);
47         return true;
48     }
49     this->reset();
50     return false;
51 }
52 
setColorSpace(sk_sp<SkColorSpace> cs)53 void SkPixmap::setColorSpace(sk_sp<SkColorSpace> cs) {
54     fInfo = fInfo.makeColorSpace(std::move(cs));
55 }
56 
extractSubset(SkPixmap * result,const SkIRect & subset) const57 bool SkPixmap::extractSubset(SkPixmap* result, const SkIRect& subset) const {
58     SkIRect srcRect, r;
59     srcRect.set(0, 0, this->width(), this->height());
60     if (!r.intersect(srcRect, subset)) {
61         return false;   // r is empty (i.e. no intersection)
62     }
63 
64     // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
65     // exited above.
66     SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
67     SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
68 
69     const void* pixels = nullptr;
70     if (fPixels) {
71         const size_t bpp = fInfo.bytesPerPixel();
72         pixels = (const uint8_t*)fPixels + r.fTop * fRowBytes + r.fLeft * bpp;
73     }
74     result->reset(fInfo.makeWH(r.width(), r.height()), pixels, fRowBytes);
75     return true;
76 }
77 
readPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRB,int x,int y,SkTransferFunctionBehavior behavior) const78 bool SkPixmap::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, int x, int y,
79                           SkTransferFunctionBehavior behavior) const {
80     if (!SkImageInfoValidConversion(dstInfo, fInfo)) {
81         return false;
82     }
83 
84     SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, x, y);
85     if (!rec.trim(fInfo.width(), fInfo.height())) {
86         return false;
87     }
88 
89     const void* srcPixels = this->addr(rec.fX, rec.fY);
90     const SkImageInfo srcInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
91     SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes(),
92                     nullptr, behavior);
93     return true;
94 }
95 
pack_8888_to_4444(unsigned a,unsigned r,unsigned g,unsigned b)96 static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) {
97     unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) |
98     (SkR32To4444(r) << SK_R4444_SHIFT) |
99     (SkG32To4444(g) << SK_G4444_SHIFT) |
100     (SkB32To4444(b) << SK_B4444_SHIFT);
101     return SkToU16(pixel);
102 }
103 
erase(SkColor color,const SkIRect & inArea) const104 bool SkPixmap::erase(SkColor color, const SkIRect& inArea) const {
105     if (nullptr == fPixels) {
106         return false;
107     }
108     SkIRect area;
109     if (!area.intersect(this->bounds(), inArea)) {
110         return false;
111     }
112 
113     U8CPU a = SkColorGetA(color);
114     U8CPU r = SkColorGetR(color);
115     U8CPU g = SkColorGetG(color);
116     U8CPU b = SkColorGetB(color);
117 
118     int height = area.height();
119     const int width = area.width();
120     const int rowBytes = this->rowBytes();
121 
122     if (color == 0
123           && width == this->rowBytesAsPixels()
124           && inArea == this->bounds()) {
125         // All formats represent SkColor(0) as byte 0.
126         memset(this->writable_addr(), 0, (int64_t)height * rowBytes);
127         return true;
128     }
129 
130     switch (this->colorType()) {
131         case kGray_8_SkColorType: {
132             if (255 != a) {
133                 r = SkMulDiv255Round(r, a);
134                 g = SkMulDiv255Round(g, a);
135                 b = SkMulDiv255Round(b, a);
136             }
137             int gray = SkComputeLuminance(r, g, b);
138             uint8_t* p = this->writable_addr8(area.fLeft, area.fTop);
139             while (--height >= 0) {
140                 memset(p, gray, width);
141                 p += rowBytes;
142             }
143             break;
144         }
145         case kAlpha_8_SkColorType: {
146             uint8_t* p = this->writable_addr8(area.fLeft, area.fTop);
147             while (--height >= 0) {
148                 memset(p, a, width);
149                 p += rowBytes;
150             }
151             break;
152         }
153         case kARGB_4444_SkColorType:
154         case kRGB_565_SkColorType: {
155             uint16_t* p = this->writable_addr16(area.fLeft, area.fTop);
156             uint16_t v;
157 
158             // make rgb premultiplied
159             if (255 != a) {
160                 r = SkMulDiv255Round(r, a);
161                 g = SkMulDiv255Round(g, a);
162                 b = SkMulDiv255Round(b, a);
163             }
164 
165             if (kARGB_4444_SkColorType == this->colorType()) {
166                 v = pack_8888_to_4444(a, r, g, b);
167             } else {
168                 v = SkPackRGB16(r >> (8 - SK_R16_BITS),
169                                 g >> (8 - SK_G16_BITS),
170                                 b >> (8 - SK_B16_BITS));
171             }
172             while (--height >= 0) {
173                 sk_memset16(p, v, width);
174                 p = (uint16_t*)((char*)p + rowBytes);
175             }
176             break;
177         }
178         case kBGRA_8888_SkColorType:
179         case kRGBA_8888_SkColorType: {
180             uint32_t* p = this->writable_addr32(area.fLeft, area.fTop);
181 
182             if (255 != a && kPremul_SkAlphaType == this->alphaType()) {
183                 r = SkMulDiv255Round(r, a);
184                 g = SkMulDiv255Round(g, a);
185                 b = SkMulDiv255Round(b, a);
186             }
187             uint32_t v = kRGBA_8888_SkColorType == this->colorType()
188                              ? SkPackARGB_as_RGBA(a, r, g, b)
189                              : SkPackARGB_as_BGRA(a, r, g, b);
190 
191             while (--height >= 0) {
192                 sk_memset32(p, v, width);
193                 p = (uint32_t*)((char*)p + rowBytes);
194             }
195             break;
196         }
197         case kRGBA_F16_SkColorType:
198             // The colorspace is unspecified, so assume linear just like getColor().
199             this->erase(SkColor4f{(1 / 255.0f) * r,
200                                   (1 / 255.0f) * g,
201                                   (1 / 255.0f) * b,
202                                   (1 / 255.0f) * a}, &area);
203             break;
204         default:
205             return false; // no change, so don't call notifyPixelsChanged()
206     }
207     return true;
208 }
209 
erase(const SkColor4f & origColor,const SkIRect * subset) const210 bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const {
211     SkPixmap pm;
212     if (subset) {
213         if (!this->extractSubset(&pm, *subset)) {
214             return false;
215         }
216     } else {
217         pm = *this;
218     }
219 
220     const SkColor4f color = origColor.pin();
221 
222     if (kRGBA_F16_SkColorType != pm.colorType()) {
223         return pm.erase(color.toSkColor());
224     }
225 
226     const uint64_t half4 = color.premul().toF16();
227     for (int y = 0; y < pm.height(); ++y) {
228         sk_memset64(pm.writable_addr64(0, y), half4, pm.width());
229     }
230     return true;
231 }
232 
scalePixels(const SkPixmap & actualDst,SkFilterQuality quality) const233 bool SkPixmap::scalePixels(const SkPixmap& actualDst, SkFilterQuality quality) const {
234     // We may need to tweak how we interpret these just a little below, so we make copies.
235     SkPixmap src = *this,
236              dst = actualDst;
237 
238     // Can't do anthing with empty src or dst
239     if (src.width() <= 0 || src.height() <= 0 ||
240         dst.width() <= 0 || dst.height() <= 0) {
241         return false;
242     }
243 
244     // no scaling involved?
245     if (src.width() == dst.width() && src.height() == dst.height()) {
246         return src.readPixels(dst);
247     }
248 
249     // If src and dst are both unpremul, we'll fake them out to appear as if premul.
250     bool clampAsIfUnpremul = false;
251     if (src.alphaType() == kUnpremul_SkAlphaType &&
252         dst.alphaType() == kUnpremul_SkAlphaType) {
253         src.reset(src.info().makeAlphaType(kPremul_SkAlphaType), src.addr(), src.rowBytes());
254         dst.reset(dst.info().makeAlphaType(kPremul_SkAlphaType), dst.addr(), dst.rowBytes());
255 
256         // In turn, we'll need to tell the image shader to clamp to [0,1] instead
257         // of the usual [0,a] when using a bicubic scaling (kHigh_SkFilterQuality)
258         // or a gamut transformation.
259         clampAsIfUnpremul = true;
260     }
261 
262     SkBitmap bitmap;
263     if (!bitmap.installPixels(src)) {
264         return false;
265     }
266     bitmap.setImmutable();        // Don't copy when we create an image.
267     bitmap.setIsVolatile(true);   // Disable any caching.
268 
269     SkMatrix scale = SkMatrix::MakeRectToRect(SkRect::Make(src.bounds()),
270                                               SkRect::Make(dst.bounds()),
271                                               SkMatrix::kFill_ScaleToFit);
272 
273     // We'll create a shader to do this draw so we have control over the bicubic clamp.
274     sk_sp<SkShader> shader = SkImageShader::Make(SkImage::MakeFromBitmap(bitmap),
275                                                  SkShader::kClamp_TileMode,
276                                                  SkShader::kClamp_TileMode,
277                                                  &scale,
278                                                  clampAsIfUnpremul);
279 
280     sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(dst.info(),
281                                                            dst.writable_addr(),
282                                                            dst.rowBytes());
283     if (!shader || !surface) {
284         return false;
285     }
286 
287     SkPaint paint;
288     paint.setBlendMode(SkBlendMode::kSrc);
289     paint.setFilterQuality(quality);
290     paint.setShader(std::move(shader));
291     surface->getCanvas()->drawPaint(paint);
292     return true;
293 }
294 
295 //////////////////////////////////////////////////////////////////////////////////////////////////
296 
getColor(int x,int y) const297 SkColor SkPixmap::getColor(int x, int y) const {
298     SkASSERT(this->addr());
299     SkASSERT((unsigned)x < (unsigned)this->width());
300     SkASSERT((unsigned)y < (unsigned)this->height());
301 
302     const bool needsUnpremul = (kPremul_SkAlphaType == fInfo.alphaType());
303     auto toColor = [needsUnpremul](uint32_t maybePremulColor) {
304         return needsUnpremul ? SkUnPreMultiply::PMColorToColor(maybePremulColor)
305                              : SkSwizzle_BGRA_to_PMColor(maybePremulColor);
306     };
307 
308     switch (this->colorType()) {
309         case kGray_8_SkColorType: {
310             uint8_t value = *this->addr8(x, y);
311             return SkColorSetRGB(value, value, value);
312         }
313         case kAlpha_8_SkColorType: {
314             return SkColorSetA(0, *this->addr8(x, y));
315         }
316         case kRGB_565_SkColorType: {
317             return SkPixel16ToColor(*this->addr16(x, y));
318         }
319         case kARGB_4444_SkColorType: {
320             uint16_t value = *this->addr16(x, y);
321             SkPMColor c = SkPixel4444ToPixel32(value);
322             return toColor(c);
323         }
324         case kBGRA_8888_SkColorType: {
325             uint32_t value = *this->addr32(x, y);
326             SkPMColor c = SkSwizzle_BGRA_to_PMColor(value);
327             return toColor(c);
328         }
329         case kRGBA_8888_SkColorType: {
330             uint32_t value = *this->addr32(x, y);
331             SkPMColor c = SkSwizzle_RGBA_to_PMColor(value);
332             return toColor(c);
333         }
334         case kRGBA_F16_SkColorType: {
335              const uint64_t* addr =
336                  (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x;
337              Sk4f p4 = SkHalfToFloat_finite_ftz(*addr);
338              if (p4[3] && needsUnpremul) {
339                  float inva = 1 / p4[3];
340                  p4 = p4 * Sk4f(inva, inva, inva, 1);
341              }
342              SkColor c;
343              SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c);
344              // p4 is RGBA, but we want BGRA, so we need to swap next
345              return SkSwizzle_RB(c);
346         }
347         default:
348             SkDEBUGFAIL("");
349             return SkColorSetARGB(0, 0, 0, 0);
350     }
351 }
352 
computeIsOpaque() const353 bool SkPixmap::computeIsOpaque() const {
354     const int height = this->height();
355     const int width = this->width();
356 
357     switch (this->colorType()) {
358         case kAlpha_8_SkColorType: {
359             unsigned a = 0xFF;
360             for (int y = 0; y < height; ++y) {
361                 const uint8_t* row = this->addr8(0, y);
362                 for (int x = 0; x < width; ++x) {
363                     a &= row[x];
364                 }
365                 if (0xFF != a) {
366                     return false;
367                 }
368             }
369             return true;
370         } break;
371         case kRGB_565_SkColorType:
372         case kGray_8_SkColorType:
373             return true;
374             break;
375         case kARGB_4444_SkColorType: {
376             unsigned c = 0xFFFF;
377             for (int y = 0; y < height; ++y) {
378                 const SkPMColor16* row = this->addr16(0, y);
379                 for (int x = 0; x < width; ++x) {
380                     c &= row[x];
381                 }
382                 if (0xF != SkGetPackedA4444(c)) {
383                     return false;
384                 }
385             }
386             return true;
387         } break;
388         case kBGRA_8888_SkColorType:
389         case kRGBA_8888_SkColorType: {
390             SkPMColor c = (SkPMColor)~0;
391             for (int y = 0; y < height; ++y) {
392                 const SkPMColor* row = this->addr32(0, y);
393                 for (int x = 0; x < width; ++x) {
394                     c &= row[x];
395                 }
396                 if (0xFF != SkGetPackedA32(c)) {
397                     return false;
398                 }
399             }
400             return true;
401         }
402         case kRGBA_F16_SkColorType: {
403             const SkHalf* row = (const SkHalf*)this->addr();
404             for (int y = 0; y < height; ++y) {
405                 for (int x = 0; x < width; ++x) {
406                     if (row[4 * x + 3] < SK_Half1) {
407                         return false;
408                     }
409                 }
410                 row += this->rowBytes() >> 1;
411             }
412             return true;
413         }
414         default:
415             break;
416     }
417     return false;
418 }
419 
420 //////////////////////////////////////////////////////////////////////////////////////////////////
421 
draw_orientation(const SkPixmap & dst,const SkPixmap & src,unsigned flags)422 static bool draw_orientation(const SkPixmap& dst, const SkPixmap& src, unsigned flags) {
423     auto surf = SkSurface::MakeRasterDirect(dst.info(), dst.writable_addr(), dst.rowBytes());
424     if (!surf) {
425         return false;
426     }
427 
428     SkBitmap bm;
429     bm.installPixels(src);
430 
431     SkMatrix m;
432     m.setIdentity();
433 
434     SkScalar W = SkIntToScalar(src.width());
435     SkScalar H = SkIntToScalar(src.height());
436     if (flags & SkPixmapPriv::kSwapXY) {
437         SkMatrix s;
438         s.setAll(0, 1, 0, 1, 0, 0, 0, 0, 1);
439         m.postConcat(s);
440         SkTSwap(W, H);
441     }
442     if (flags & SkPixmapPriv::kMirrorX) {
443         m.postScale(-1, 1);
444         m.postTranslate(W, 0);
445     }
446     if (flags & SkPixmapPriv::kMirrorY) {
447         m.postScale(1, -1);
448         m.postTranslate(0, H);
449     }
450     SkPaint p;
451     p.setBlendMode(SkBlendMode::kSrc);
452     surf->getCanvas()->concat(m);
453     surf->getCanvas()->drawBitmap(bm, 0, 0, &p);
454     return true;
455 }
456 
Orient(const SkPixmap & dst,const SkPixmap & src,OrientFlags flags)457 bool SkPixmapPriv::Orient(const SkPixmap& dst, const SkPixmap& src, OrientFlags flags) {
458     SkASSERT((flags & ~(kMirrorX | kMirrorY | kSwapXY)) == 0);
459     if (src.colorType() != dst.colorType()) {
460         return false;
461     }
462     // note: we just ignore alphaType and colorSpace for this transformation
463 
464     int w = src.width();
465     int h = src.height();
466     if (flags & kSwapXY) {
467         SkTSwap(w, h);
468     }
469     if (dst.width() != w || dst.height() != h) {
470         return false;
471     }
472     if (w == 0 || h == 0) {
473         return true;
474     }
475 
476     // check for aliasing to self
477     if (src.addr() == dst.addr()) {
478         return flags == 0;
479     }
480     return draw_orientation(dst, src, flags);
481 }
482 
483 #define kMirrorX    SkPixmapPriv::kMirrorX
484 #define kMirrorY    SkPixmapPriv::kMirrorY
485 #define kSwapXY     SkPixmapPriv::kSwapXY
486 
487 static constexpr uint8_t gOrientationFlags[] = {
488     0,                              // kTopLeft_SkEncodedOrigin
489     kMirrorX,                       // kTopRight_SkEncodedOrigin
490     kMirrorX | kMirrorY,            // kBottomRight_SkEncodedOrigin
491                kMirrorY,            // kBottomLeft_SkEncodedOrigin
492                           kSwapXY,  // kLeftTop_SkEncodedOrigin
493     kMirrorX            | kSwapXY,  // kRightTop_SkEncodedOrigin
494     kMirrorX | kMirrorY | kSwapXY,  // kRightBottom_SkEncodedOrigin
495                kMirrorY | kSwapXY,  // kLeftBottom_SkEncodedOrigin
496 };
497 
OriginToOrient(SkEncodedOrigin o)498 SkPixmapPriv::OrientFlags SkPixmapPriv::OriginToOrient(SkEncodedOrigin o) {
499     unsigned io = static_cast<int>(o) - 1;
500     SkASSERT(io < SK_ARRAY_COUNT(gOrientationFlags));
501     return static_cast<SkPixmapPriv::OrientFlags>(gOrientationFlags[io]);
502 }
503 
ShouldSwapWidthHeight(SkEncodedOrigin o)504 bool SkPixmapPriv::ShouldSwapWidthHeight(SkEncodedOrigin o) {
505     return SkToBool(OriginToOrient(o) & kSwapXY);
506 }
507 
SwapWidthHeight(const SkImageInfo & info)508 SkImageInfo SkPixmapPriv::SwapWidthHeight(const SkImageInfo& info) {
509     return info.makeWH(info.height(), info.width());
510 }
511 
512