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