1 /*
2  * Copyright 2008 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 "SkAtomics.h"
9 #include "SkBitmap.h"
10 #include "SkColorPriv.h"
11 #include "SkConvertPixels.h"
12 #include "SkData.h"
13 #include "SkFilterQuality.h"
14 #include "SkHalf.h"
15 #include "SkImageInfoPriv.h"
16 #include "SkMallocPixelRef.h"
17 #include "SkMask.h"
18 #include "SkMath.h"
19 #include "SkPixelRef.h"
20 #include "SkReadBuffer.h"
21 #include "SkRect.h"
22 #include "SkScalar.h"
23 #include "SkTemplates.h"
24 #include "SkUnPreMultiply.h"
25 #include "SkWriteBuffer.h"
26 #include "SkWritePixelsRec.h"
27 
28 #include <string.h>
29 
reset_return_false(SkBitmap * bm)30 static bool reset_return_false(SkBitmap* bm) {
31     bm->reset();
32     return false;
33 }
34 
SkBitmap()35 SkBitmap::SkBitmap()
36     : fPixelLockCount(0)
37     , fPixels        (nullptr)
38     , fColorTable    (nullptr)
39     , fPixelRefOrigin{0, 0}
40     , fRowBytes      (0)
41     , fFlags         (0) {}
42 
43 // copy pixelref, but don't copy lock.
SkBitmap(const SkBitmap & src)44 SkBitmap::SkBitmap(const SkBitmap& src)
45     : fPixelRef      (src.fPixelRef)
46     , fPixelLockCount(0)
47     , fPixels        (nullptr)
48     , fColorTable    (nullptr)
49     , fPixelRefOrigin(src.fPixelRefOrigin)
50     , fInfo          (src.fInfo)
51     , fRowBytes      (src.fRowBytes)
52     , fFlags         (src.fFlags)
53 {
54     SkDEBUGCODE(src.validate();)
55     SkDEBUGCODE(this->validate();)
56 }
57 
58 // take lock and lockcount from other.
SkBitmap(SkBitmap && other)59 SkBitmap::SkBitmap(SkBitmap&& other)
60     : fPixelRef      (std::move(other.fPixelRef))
61     , fPixelLockCount          (other.fPixelLockCount)
62     , fPixels                  (other.fPixels)
63     , fColorTable              (other.fColorTable)
64     , fPixelRefOrigin          (other.fPixelRefOrigin)
65     , fInfo          (std::move(other.fInfo))
66     , fRowBytes                (other.fRowBytes)
67     , fFlags                   (other.fFlags) {
68     SkASSERT(!other.fPixelRef);
69     other.fInfo.reset();
70     other.fPixelLockCount = 0;
71     other.fPixels         = nullptr;
72     other.fColorTable     = nullptr;
73     other.fPixelRefOrigin = SkIPoint{0, 0};
74     other.fRowBytes       = 0;
75     other.fFlags          = 0;
76 }
77 
~SkBitmap()78 SkBitmap::~SkBitmap() {
79     SkDEBUGCODE(this->validate();)
80     this->freePixels();
81 }
82 
operator =(const SkBitmap & src)83 SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
84     if (this != &src) {
85         this->freePixels();
86         SkASSERT(!fPixels);
87         SkASSERT(!fColorTable);
88         SkASSERT(!fPixelLockCount);
89         fPixelRef       = src.fPixelRef;
90         fPixelRefOrigin = src.fPixelRefOrigin;
91         fInfo           = src.fInfo;
92         fRowBytes       = src.fRowBytes;
93         fFlags          = src.fFlags;
94     }
95     SkDEBUGCODE(this->validate();)
96     return *this;
97 }
98 
operator =(SkBitmap && other)99 SkBitmap& SkBitmap::operator=(SkBitmap&& other) {
100     if (this != &other) {
101         this->freePixels();
102         SkASSERT(!fPixels);
103         SkASSERT(!fColorTable);
104         SkASSERT(!fPixelLockCount);
105         fPixelRef       = std::move(other.fPixelRef);
106         fInfo           = std::move(other.fInfo);
107         fPixelLockCount = other.fPixelLockCount;
108         fPixels         = other.fPixels;
109         fColorTable     = other.fColorTable;
110         fPixelRefOrigin = other.fPixelRefOrigin;
111         fRowBytes       = other.fRowBytes;
112         fFlags          = other.fFlags;
113         SkASSERT(!other.fPixelRef);
114         other.fInfo.reset();
115         other.fPixelLockCount = 0;
116         other.fPixels         = nullptr;
117         other.fColorTable     = nullptr;
118         other.fPixelRefOrigin = SkIPoint{0, 0};
119         other.fRowBytes       = 0;
120         other.fFlags          = 0;
121     }
122     return *this;
123 }
124 
swap(SkBitmap & other)125 void SkBitmap::swap(SkBitmap& other) {
126     SkTSwap(*this, other);
127     SkDEBUGCODE(this->validate();)
128 }
129 
reset()130 void SkBitmap::reset() {
131     this->freePixels();
132     this->fInfo.reset();
133     sk_bzero(this, sizeof(*this));
134 }
135 
getBounds(SkRect * bounds) const136 void SkBitmap::getBounds(SkRect* bounds) const {
137     SkASSERT(bounds);
138     bounds->set(0, 0,
139                 SkIntToScalar(fInfo.width()), SkIntToScalar(fInfo.height()));
140 }
141 
getBounds(SkIRect * bounds) const142 void SkBitmap::getBounds(SkIRect* bounds) const {
143     SkASSERT(bounds);
144     bounds->set(0, 0, fInfo.width(), fInfo.height());
145 }
146 
147 ///////////////////////////////////////////////////////////////////////////////
148 
setInfo(const SkImageInfo & info,size_t rowBytes)149 bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) {
150     SkAlphaType newAT = info.alphaType();
151     if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) {
152         return reset_return_false(this);
153     }
154     // don't look at info.alphaType(), since newAT is the real value...
155 
156     // require that rowBytes fit in 31bits
157     int64_t mrb = info.minRowBytes64();
158     if ((int32_t)mrb != mrb) {
159         return reset_return_false(this);
160     }
161     if ((int64_t)rowBytes != (int32_t)rowBytes) {
162         return reset_return_false(this);
163     }
164 
165     if (info.width() < 0 || info.height() < 0) {
166         return reset_return_false(this);
167     }
168 
169     if (kUnknown_SkColorType == info.colorType()) {
170         rowBytes = 0;
171     } else if (0 == rowBytes) {
172         rowBytes = (size_t)mrb;
173     } else if (!info.validRowBytes(rowBytes)) {
174         return reset_return_false(this);
175     }
176 
177     this->freePixels();
178 
179     fInfo = info.makeAlphaType(newAT);
180     fRowBytes = SkToU32(rowBytes);
181     return true;
182 }
183 
setAlphaType(SkAlphaType newAlphaType)184 bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) {
185     if (!SkColorTypeValidateAlphaType(fInfo.colorType(), newAlphaType, &newAlphaType)) {
186         return false;
187     }
188     if (fInfo.alphaType() != newAlphaType) {
189         fInfo = fInfo.makeAlphaType(newAlphaType);
190         if (fPixelRef) {
191             fPixelRef->changeAlphaType(newAlphaType);
192         }
193     }
194     return true;
195 }
196 
updatePixelsFromRef() const197 void SkBitmap::updatePixelsFromRef() const {
198     if (fPixelRef) {
199         if (fPixelLockCount > 0) {
200             SkASSERT(fPixelRef->isLocked());
201 
202             void* p = fPixelRef->pixels();
203             if (p) {
204                 p = (char*)p
205                     + fPixelRefOrigin.fY * fRowBytes
206                     + fPixelRefOrigin.fX * fInfo.bytesPerPixel();
207             }
208             fPixels = p;
209             fColorTable = fPixelRef->colorTable();
210         } else {
211             SkASSERT(0 == fPixelLockCount);
212             fPixels = nullptr;
213             fColorTable = nullptr;
214         }
215     }
216 }
217 
218 #ifdef SK_SUPPORT_LEGACY_BITMAP_SETPIXELREF
setPixelRef(SkPixelRef * pr,int dx,int dy)219 SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) {
220     this->setPixelRef(sk_ref_sp(pr), dx, dy);
221     return pr;
222 }
223 #endif
224 
setPixelRef(sk_sp<SkPixelRef> pr,int dx,int dy)225 void SkBitmap::setPixelRef(sk_sp<SkPixelRef> pr, int dx, int dy) {
226 #ifdef SK_DEBUG
227     if (pr) {
228         if (kUnknown_SkColorType != fInfo.colorType()) {
229             const SkImageInfo& prInfo = pr->info();
230             SkASSERT(fInfo.width() <= prInfo.width());
231             SkASSERT(fInfo.height() <= prInfo.height());
232             SkASSERT(fInfo.colorType() == prInfo.colorType());
233             switch (prInfo.alphaType()) {
234                 case kUnknown_SkAlphaType:
235                     SkASSERT(fInfo.alphaType() == kUnknown_SkAlphaType);
236                     break;
237                 case kOpaque_SkAlphaType:
238                 case kPremul_SkAlphaType:
239                     SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
240                              fInfo.alphaType() == kPremul_SkAlphaType);
241                     break;
242                 case kUnpremul_SkAlphaType:
243                     SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
244                              fInfo.alphaType() == kUnpremul_SkAlphaType);
245                     break;
246             }
247         }
248     }
249 #endif
250 
251     if (pr) {
252         const SkImageInfo& info = pr->info();
253         fPixelRefOrigin.set(SkTPin(dx, 0, info.width()), SkTPin(dy, 0, info.height()));
254     } else {
255         // ignore dx,dy if there is no pixelref
256         fPixelRefOrigin.setZero();
257     }
258 
259     if (fPixelRef != pr) {
260         this->freePixels();
261         SkASSERT(!fPixelRef);
262 
263         fPixelRef = std::move(pr);
264         this->updatePixelsFromRef();
265     }
266 
267     SkDEBUGCODE(this->validate();)
268 }
269 
lockPixels() const270 void SkBitmap::lockPixels() const {
271     if (fPixelRef && 0 == sk_atomic_inc(&fPixelLockCount)) {
272         fPixelRef->lockPixels();
273         this->updatePixelsFromRef();
274     }
275     SkDEBUGCODE(this->validate();)
276 }
277 
unlockPixels() const278 void SkBitmap::unlockPixels() const {
279     SkASSERT(!fPixelRef || fPixelLockCount > 0);
280 
281     if (fPixelRef && 1 == sk_atomic_dec(&fPixelLockCount)) {
282         fPixelRef->unlockPixels();
283         this->updatePixelsFromRef();
284     }
285     SkDEBUGCODE(this->validate();)
286 }
287 
lockPixelsAreWritable() const288 bool SkBitmap::lockPixelsAreWritable() const {
289     return fPixelRef ? fPixelRef->lockPixelsAreWritable() : false;
290 }
291 
setPixels(void * p,SkColorTable * ctable)292 void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
293     if (nullptr == p) {
294         this->setPixelRef(nullptr, 0, 0);
295         return;
296     }
297 
298     if (kUnknown_SkColorType == fInfo.colorType()) {
299         this->setPixelRef(nullptr, 0, 0);
300         return;
301     }
302 
303     sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewDirect(fInfo, p, fRowBytes, ctable));
304     this->setPixelRef(std::move(pr), 0, 0);
305     if (!fPixelRef) {
306         return;
307     }
308     // since we're already allocated, we lockPixels right away
309     this->lockPixels();
310     SkDEBUGCODE(this->validate();)
311 }
312 
tryAllocPixels(Allocator * allocator,SkColorTable * ctable)313 bool SkBitmap::tryAllocPixels(Allocator* allocator, SkColorTable* ctable) {
314     HeapAllocator stdalloc;
315 
316     if (nullptr == allocator) {
317         allocator = &stdalloc;
318     }
319     return allocator->allocPixelRef(this, ctable);
320 }
321 
322 ///////////////////////////////////////////////////////////////////////////////
323 
tryAllocPixels(const SkImageInfo & requestedInfo,size_t rowBytes)324 bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
325     if (kIndex_8_SkColorType == requestedInfo.colorType()) {
326         return reset_return_false(this);
327     }
328     if (!this->setInfo(requestedInfo, rowBytes)) {
329         return reset_return_false(this);
330     }
331 
332     // setInfo may have corrected info (e.g. 565 is always opaque).
333     const SkImageInfo& correctedInfo = this->info();
334     // setInfo may have computed a valid rowbytes if 0 were passed in
335     rowBytes = this->rowBytes();
336 
337     SkMallocPixelRef::PRFactory defaultFactory;
338 
339     sk_sp<SkPixelRef> pr(defaultFactory.create(correctedInfo, rowBytes, nullptr));
340     if (!pr) {
341         return reset_return_false(this);
342     }
343     this->setPixelRef(std::move(pr), 0, 0);
344 
345     // TODO: lockPixels could/should return bool or void*/nullptr
346     this->lockPixels();
347     if (nullptr == this->getPixels()) {
348         return reset_return_false(this);
349     }
350     return true;
351 }
352 
tryAllocPixels(const SkImageInfo & requestedInfo,SkPixelRefFactory * factory,SkColorTable * ctable)353 bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, SkPixelRefFactory* factory,
354                                 SkColorTable* ctable) {
355     if (kIndex_8_SkColorType == requestedInfo.colorType() && nullptr == ctable) {
356         return reset_return_false(this);
357     }
358     if (!this->setInfo(requestedInfo)) {
359         return reset_return_false(this);
360     }
361 
362     // setInfo may have corrected info (e.g. 565 is always opaque).
363     const SkImageInfo& correctedInfo = this->info();
364 
365     SkMallocPixelRef::PRFactory defaultFactory;
366     if (nullptr == factory) {
367         factory = &defaultFactory;
368     }
369 
370     sk_sp<SkPixelRef> pr(factory->create(correctedInfo, correctedInfo.minRowBytes(), ctable));
371     if (!pr) {
372         return reset_return_false(this);
373     }
374     this->setPixelRef(std::move(pr), 0, 0);
375 
376     // TODO: lockPixels could/should return bool or void*/nullptr
377     this->lockPixels();
378     if (nullptr == this->getPixels()) {
379         return reset_return_false(this);
380     }
381     return true;
382 }
383 
invoke_release_proc(void (* proc)(void * pixels,void * ctx),void * pixels,void * ctx)384 static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
385     if (proc) {
386         proc(pixels, ctx);
387     }
388 }
389 
installPixels(const SkImageInfo & requestedInfo,void * pixels,size_t rb,SkColorTable * ct,void (* releaseProc)(void * addr,void * context),void * context)390 bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
391                              SkColorTable* ct, void (*releaseProc)(void* addr, void* context),
392                              void* context) {
393     if (!this->setInfo(requestedInfo, rb)) {
394         invoke_release_proc(releaseProc, pixels, context);
395         this->reset();
396         return false;
397     }
398     if (nullptr == pixels) {
399         invoke_release_proc(releaseProc, pixels, context);
400         return true;    // we behaved as if they called setInfo()
401     }
402 
403     // setInfo may have corrected info (e.g. 565 is always opaque).
404     const SkImageInfo& correctedInfo = this->info();
405 
406     sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewWithProc(correctedInfo, rb, ct, pixels, releaseProc,
407                                                        context));
408     if (!pr) {
409         this->reset();
410         return false;
411     }
412 
413     this->setPixelRef(std::move(pr), 0, 0);
414 
415     // since we're already allocated, we lockPixels right away
416     this->lockPixels();
417     SkDEBUGCODE(this->validate();)
418     return true;
419 }
420 
installPixels(const SkPixmap & pixmap)421 bool SkBitmap::installPixels(const SkPixmap& pixmap) {
422     return this->installPixels(pixmap.info(), pixmap.writable_addr(),
423                                pixmap.rowBytes(), pixmap.ctable(),
424                                nullptr, nullptr);
425 }
426 
installMaskPixels(const SkMask & mask)427 bool SkBitmap::installMaskPixels(const SkMask& mask) {
428     if (SkMask::kA8_Format != mask.fFormat) {
429         this->reset();
430         return false;
431     }
432     return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
433                                                    mask.fBounds.height()),
434                                mask.fImage, mask.fRowBytes);
435 }
436 
437 ///////////////////////////////////////////////////////////////////////////////
438 
freePixels()439 void SkBitmap::freePixels() {
440     if (fPixelRef) {
441         if (fPixelLockCount > 0) {
442             fPixelRef->unlockPixels();
443         }
444         fPixelRef = nullptr;
445         fPixelRefOrigin.setZero();
446     }
447     fPixelLockCount = 0;
448     fPixels = nullptr;
449     fColorTable = nullptr;
450 }
451 
getGenerationID() const452 uint32_t SkBitmap::getGenerationID() const {
453     return fPixelRef ? fPixelRef->getGenerationID() : 0;
454 }
455 
notifyPixelsChanged() const456 void SkBitmap::notifyPixelsChanged() const {
457     SkASSERT(!this->isImmutable());
458     if (fPixelRef) {
459         fPixelRef->notifyPixelsChanged();
460     }
461 }
462 
463 ///////////////////////////////////////////////////////////////////////////////
464 
465 /** We explicitly use the same allocator for our pixels that SkMask does,
466  so that we can freely assign memory allocated by one class to the other.
467  */
allocPixelRef(SkBitmap * dst,SkColorTable * ctable)468 bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
469                                             SkColorTable* ctable) {
470     const SkImageInfo info = dst->info();
471     if (kUnknown_SkColorType == info.colorType()) {
472 //        SkDebugf("unsupported config for info %d\n", dst->config());
473         return false;
474     }
475 
476     sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewAllocate(info, dst->rowBytes(), ctable));
477     if (!pr) {
478         return false;
479     }
480 
481     dst->setPixelRef(std::move(pr), 0, 0);
482     // since we're already allocated, we lockPixels right away
483     dst->lockPixels();
484     return true;
485 }
486 
487 ///////////////////////////////////////////////////////////////////////////////
488 
copy_pixels_to(const SkPixmap & src,void * const dst,size_t dstSize,size_t dstRowBytes,bool preserveDstPad)489 static bool copy_pixels_to(const SkPixmap& src, void* const dst, size_t dstSize,
490                            size_t dstRowBytes, bool preserveDstPad) {
491     const SkImageInfo& info = src.info();
492 
493     if (0 == dstRowBytes) {
494         dstRowBytes = src.rowBytes();
495     }
496     if (dstRowBytes < info.minRowBytes()) {
497         return false;
498     }
499 
500     if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == src.rowBytes()) {
501         size_t safeSize = src.getSafeSize();
502         if (safeSize > dstSize || safeSize == 0)
503             return false;
504         else {
505             // This implementation will write bytes beyond the end of each row,
506             // excluding the last row, if the bitmap's stride is greater than
507             // strictly required by the current config.
508             memcpy(dst, src.addr(), safeSize);
509             return true;
510         }
511     } else {
512         // If destination has different stride than us, then copy line by line.
513         if (info.getSafeSize(dstRowBytes) > dstSize) {
514             return false;
515         } else {
516             // Just copy what we need on each line.
517             size_t rowBytes = info.minRowBytes();
518             const uint8_t* srcP = reinterpret_cast<const uint8_t*>(src.addr());
519             uint8_t* dstP = reinterpret_cast<uint8_t*>(dst);
520             for (int row = 0; row < info.height(); ++row) {
521                 memcpy(dstP, srcP, rowBytes);
522                 srcP += src.rowBytes();
523                 dstP += dstRowBytes;
524             }
525 
526             return true;
527         }
528     }
529 }
530 
copyPixelsTo(void * dst,size_t dstSize,size_t dstRB,bool preserveDstPad) const531 bool SkBitmap::copyPixelsTo(void* dst, size_t dstSize, size_t dstRB, bool preserveDstPad) const {
532     if (nullptr == dst) {
533         return false;
534     }
535     SkAutoPixmapUnlock result;
536     if (!this->requestLock(&result)) {
537         return false;
538     }
539     return copy_pixels_to(result.pixmap(), dst, dstSize, dstRB, preserveDstPad);
540 }
541 
542 ///////////////////////////////////////////////////////////////////////////////
543 
isImmutable() const544 bool SkBitmap::isImmutable() const {
545     return fPixelRef ? fPixelRef->isImmutable() : false;
546 }
547 
setImmutable()548 void SkBitmap::setImmutable() {
549     if (fPixelRef) {
550         fPixelRef->setImmutable();
551     }
552 }
553 
isVolatile() const554 bool SkBitmap::isVolatile() const {
555     return (fFlags & kImageIsVolatile_Flag) != 0;
556 }
557 
setIsVolatile(bool isVolatile)558 void SkBitmap::setIsVolatile(bool isVolatile) {
559     if (isVolatile) {
560         fFlags |= kImageIsVolatile_Flag;
561     } else {
562         fFlags &= ~kImageIsVolatile_Flag;
563     }
564 }
565 
getAddr(int x,int y) const566 void* SkBitmap::getAddr(int x, int y) const {
567     SkASSERT((unsigned)x < (unsigned)this->width());
568     SkASSERT((unsigned)y < (unsigned)this->height());
569 
570     char* base = (char*)this->getPixels();
571     if (base) {
572         base += y * this->rowBytes();
573         switch (this->colorType()) {
574             case kRGBA_F16_SkColorType:
575                 base += x << 3;
576                 break;
577             case kRGBA_8888_SkColorType:
578             case kBGRA_8888_SkColorType:
579                 base += x << 2;
580                 break;
581             case kARGB_4444_SkColorType:
582             case kRGB_565_SkColorType:
583                 base += x << 1;
584                 break;
585             case kAlpha_8_SkColorType:
586             case kIndex_8_SkColorType:
587             case kGray_8_SkColorType:
588                 base += x;
589                 break;
590             default:
591                 SkDEBUGFAIL("Can't return addr for config");
592                 base = nullptr;
593                 break;
594         }
595     }
596     return base;
597 }
598 
599 ///////////////////////////////////////////////////////////////////////////////
600 ///////////////////////////////////////////////////////////////////////////////
601 
erase(SkColor c,const SkIRect & area) const602 void SkBitmap::erase(SkColor c, const SkIRect& area) const {
603     SkDEBUGCODE(this->validate();)
604 
605     switch (fInfo.colorType()) {
606         case kUnknown_SkColorType:
607         case kIndex_8_SkColorType:
608             // TODO: can we ASSERT that we never get here?
609             return; // can't erase. Should we bzero so the memory is not uninitialized?
610         default:
611             break;
612     }
613 
614     SkAutoPixmapUnlock result;
615     if (!this->requestLock(&result)) {
616         return;
617     }
618 
619     if (result.pixmap().erase(c, area)) {
620         this->notifyPixelsChanged();
621     }
622 }
623 
eraseColor(SkColor c) const624 void SkBitmap::eraseColor(SkColor c) const {
625     this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
626 }
627 
628 //////////////////////////////////////////////////////////////////////////////////////
629 //////////////////////////////////////////////////////////////////////////////////////
630 
extractSubset(SkBitmap * result,const SkIRect & subset) const631 bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
632     SkDEBUGCODE(this->validate();)
633 
634     if (nullptr == result || !fPixelRef) {
635         return false;   // no src pixels
636     }
637 
638     SkIRect srcRect, r;
639     srcRect.set(0, 0, this->width(), this->height());
640     if (!r.intersect(srcRect, subset)) {
641         return false;   // r is empty (i.e. no intersection)
642     }
643 
644     // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
645     // exited above.
646     SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
647     SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
648 
649     SkBitmap dst;
650     dst.setInfo(this->info().makeWH(r.width(), r.height()), this->rowBytes());
651     dst.setIsVolatile(this->isVolatile());
652 
653     if (fPixelRef) {
654         SkIPoint origin = fPixelRefOrigin;
655         origin.fX += r.fLeft;
656         origin.fY += r.fTop;
657         // share the pixelref with a custom offset
658         dst.setPixelRef(fPixelRef, origin.x(), origin.y());
659     }
660     SkDEBUGCODE(dst.validate();)
661 
662     // we know we're good, so commit to result
663     result->swap(dst);
664     return true;
665 }
666 
667 ///////////////////////////////////////////////////////////////////////////////
668 
canCopyTo(SkColorType dstCT) const669 bool SkBitmap::canCopyTo(SkColorType dstCT) const {
670     const SkColorType srcCT = this->colorType();
671 
672     if (srcCT == kUnknown_SkColorType) {
673         return false;
674     }
675     if (srcCT == kAlpha_8_SkColorType && dstCT != kAlpha_8_SkColorType) {
676         return false;   // can't convert from alpha to non-alpha
677     }
678 
679     bool sameConfigs = (srcCT == dstCT);
680     switch (dstCT) {
681         case kAlpha_8_SkColorType:
682         case kRGB_565_SkColorType:
683         case kRGBA_8888_SkColorType:
684         case kBGRA_8888_SkColorType:
685         case kRGBA_F16_SkColorType:
686             break;
687         case kGray_8_SkColorType:
688             if (!sameConfigs) {
689                 return false;
690             }
691             break;
692         case kARGB_4444_SkColorType:
693             return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT;
694         default:
695             return false;
696     }
697     return true;
698 }
699 
readPixels(const SkImageInfo & requestedDstInfo,void * dstPixels,size_t dstRB,int x,int y) const700 bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
701                           int x, int y) const {
702     SkAutoPixmapUnlock src;
703     if (!this->requestLock(&src)) {
704         return false;
705     }
706     return src.pixmap().readPixels(requestedDstInfo, dstPixels, dstRB, x, y);
707 }
708 
readPixels(const SkPixmap & dst,int srcX,int srcY) const709 bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
710     return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
711 }
712 
writePixels(const SkPixmap & src,int dstX,int dstY,SkTransferFunctionBehavior behavior)713 bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY,
714                            SkTransferFunctionBehavior behavior) {
715     SkAutoPixmapUnlock dst;
716     if (!this->requestLock(&dst)) {
717         return false;
718     }
719 
720     if (!SkImageInfoValidConversion(fInfo, src.info())) {
721         return false;
722     }
723 
724     SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY);
725     if (!rec.trim(fInfo.width(), fInfo.height())) {
726         return false;
727     }
728 
729     void* dstPixels = this->getAddr(rec.fX, rec.fY);
730     const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
731     SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes,
732                     src.ctable(), behavior);
733     return true;
734 }
735 
copyTo(SkBitmap * dst,SkColorType dstColorType,Allocator * alloc) const736 bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const {
737     if (!this->canCopyTo(dstColorType)) {
738         return false;
739     }
740 
741     SkAutoPixmapUnlock srcUnlocker;
742     if (!this->requestLock(&srcUnlocker)) {
743         return false;
744     }
745     SkPixmap srcPM = srcUnlocker.pixmap();
746 
747     // Various Android specific compatibility modes.
748     // TODO:
749     // Move the logic of this entire function into the framework, then call readPixels() directly.
750     SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType);
751     switch (dstColorType) {
752         case kRGB_565_SkColorType:
753             // copyTo() is not strict on alpha type.  Here we set the src to opaque to allow
754             // the call to readPixels() to succeed and preserve this lenient behavior.
755             if (kOpaque_SkAlphaType != srcPM.alphaType()) {
756                 srcPM = SkPixmap(srcPM.info().makeAlphaType(kOpaque_SkAlphaType), srcPM.addr(),
757                                  srcPM.rowBytes(), srcPM.ctable());
758                 dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
759             }
760             break;
761         case kRGBA_F16_SkColorType:
762             // The caller does not have an opportunity to pass a dst color space.  Assume that
763             // they want linear sRGB.
764             dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
765 
766             if (!srcPM.colorSpace()) {
767                 // We can't do a sane conversion to F16 without a dst color space.  Guess sRGB
768                 // in this case.
769                 srcPM.setColorSpace(SkColorSpace::MakeSRGB());
770             }
771             break;
772         default:
773             break;
774     }
775 
776     SkBitmap tmpDst;
777     if (!tmpDst.setInfo(dstInfo)) {
778         return false;
779     }
780 
781     // allocate colortable if srcConfig == kIndex8_Config
782     sk_sp<SkColorTable> ctable;
783     if (dstColorType == kIndex_8_SkColorType) {
784         ctable.reset(SkRef(srcPM.ctable()));
785     }
786     if (!tmpDst.tryAllocPixels(alloc, ctable.get())) {
787         return false;
788     }
789 
790     SkAutoPixmapUnlock dstUnlocker;
791     if (!tmpDst.requestLock(&dstUnlocker)) {
792         return false;
793     }
794 
795     SkPixmap dstPM = dstUnlocker.pixmap();
796 
797     // We can't do a sane conversion from F16 without a src color space.  Guess sRGB in this case.
798     if (kRGBA_F16_SkColorType == srcPM.colorType() && !dstPM.colorSpace()) {
799         dstPM.setColorSpace(SkColorSpace::MakeSRGB());
800     }
801 
802     // readPixels does not yet support color spaces with parametric transfer functions.  This
803     // works around that restriction when the color spaces are equal.
804     if (kRGBA_F16_SkColorType != dstColorType && kRGBA_F16_SkColorType != srcPM.colorType() &&
805             dstPM.colorSpace() == srcPM.colorSpace()) {
806         dstPM.setColorSpace(nullptr);
807         srcPM.setColorSpace(nullptr);
808     }
809 
810     if (!srcPM.readPixels(dstPM)) {
811         return false;
812     }
813 
814     //  (for BitmapHeap) Clone the pixelref genID even though we have a new pixelref.
815     //  The old copyTo impl did this, so we continue it for now.
816     //
817     //  TODO: should we ignore rowbytes (i.e. getSize)? Then it could just be
818     //      if (src_pixelref->info == dst_pixelref->info)
819     //
820     if (srcPM.colorType() == dstColorType && tmpDst.getSize() == srcPM.getSize64()) {
821         SkPixelRef* dstPixelRef = tmpDst.pixelRef();
822         if (dstPixelRef->info() == fPixelRef->info()) {
823             dstPixelRef->cloneGenID(*fPixelRef);
824         }
825     }
826 
827     dst->swap(tmpDst);
828     return true;
829 }
830 
831 // TODO: can we merge this with copyTo?
deepCopyTo(SkBitmap * dst) const832 bool SkBitmap::deepCopyTo(SkBitmap* dst) const {
833     const SkColorType dstCT = this->colorType();
834 
835     if (!this->canCopyTo(dstCT)) {
836         return false;
837     }
838     return this->copyTo(dst, dstCT, nullptr);
839 }
840 
841 ///////////////////////////////////////////////////////////////////////////////
842 
GetBitmapAlpha(const SkBitmap & src,uint8_t * SK_RESTRICT alpha,int alphaRowBytes)843 static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
844     SkASSERT(alpha != nullptr);
845     SkASSERT(alphaRowBytes >= src.width());
846 
847     SkAutoPixmapUnlock apl;
848     if (!src.requestLock(&apl)) {
849         for (int y = 0; y < src.height(); ++y) {
850             memset(alpha, 0, src.width());
851             alpha += alphaRowBytes;
852         }
853         return false;
854     }
855     const SkPixmap& pmap = apl.pixmap();
856     SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
857                     pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable(),
858                     SkTransferFunctionBehavior::kRespect);
859     return true;
860 }
861 
862 #include "SkPaint.h"
863 #include "SkMaskFilter.h"
864 #include "SkMatrix.h"
865 
extractAlpha(SkBitmap * dst,const SkPaint * paint,Allocator * allocator,SkIPoint * offset) const866 bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
867                             Allocator *allocator, SkIPoint* offset) const {
868     SkDEBUGCODE(this->validate();)
869 
870     SkBitmap    tmpBitmap;
871     SkMatrix    identity;
872     SkMask      srcM, dstM;
873 
874     srcM.fBounds.set(0, 0, this->width(), this->height());
875     srcM.fRowBytes = SkAlign4(this->width());
876     srcM.fFormat = SkMask::kA8_Format;
877 
878     SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
879 
880     // compute our (larger?) dst bounds if we have a filter
881     if (filter) {
882         identity.reset();
883         if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
884             goto NO_FILTER_CASE;
885         }
886         dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
887     } else {
888     NO_FILTER_CASE:
889         tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
890         if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
891             // Allocation of pixels for alpha bitmap failed.
892             SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
893                     tmpBitmap.width(), tmpBitmap.height());
894             return false;
895         }
896         GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
897         if (offset) {
898             offset->set(0, 0);
899         }
900         tmpBitmap.swap(*dst);
901         return true;
902     }
903     srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
904     SkAutoMaskFreeImage srcCleanup(srcM.fImage);
905 
906     GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
907     if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
908         goto NO_FILTER_CASE;
909     }
910     SkAutoMaskFreeImage dstCleanup(dstM.fImage);
911 
912     tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
913                       dstM.fRowBytes);
914     if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
915         // Allocation of pixels for alpha bitmap failed.
916         SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
917                 tmpBitmap.width(), tmpBitmap.height());
918         return false;
919     }
920     memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
921     if (offset) {
922         offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
923     }
924     SkDEBUGCODE(tmpBitmap.validate();)
925 
926     tmpBitmap.swap(*dst);
927     return true;
928 }
929 
930 ///////////////////////////////////////////////////////////////////////////////
931 
write_raw_pixels(SkWriteBuffer * buffer,const SkPixmap & pmap)932 static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) {
933     const SkImageInfo& info = pmap.info();
934     const size_t snugRB = info.width() * info.bytesPerPixel();
935     const char* src = (const char*)pmap.addr();
936     const size_t ramRB = pmap.rowBytes();
937 
938     buffer->write32(SkToU32(snugRB));
939     info.flatten(*buffer);
940 
941     const size_t size = snugRB * info.height();
942     SkAutoTMalloc<char> storage(size);
943     char* dst = storage.get();
944     for (int y = 0; y < info.height(); ++y) {
945         memcpy(dst, src, snugRB);
946         dst += snugRB;
947         src += ramRB;
948     }
949     buffer->writeByteArray(storage.get(), size);
950 
951     const SkColorTable* ct = pmap.ctable();
952     if (kIndex_8_SkColorType == info.colorType() && ct) {
953         buffer->writeBool(true);
954         ct->writeToBuffer(*buffer);
955     } else {
956         buffer->writeBool(false);
957     }
958 }
959 
WriteRawPixels(SkWriteBuffer * buffer,const SkBitmap & bitmap)960 void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) {
961     const SkImageInfo info = bitmap.info();
962     if (0 == info.width() || 0 == info.height() || bitmap.isNull()) {
963         buffer->writeUInt(0); // instead of snugRB, signaling no pixels
964         return;
965     }
966 
967     SkAutoPixmapUnlock result;
968     if (!bitmap.requestLock(&result)) {
969         buffer->writeUInt(0); // instead of snugRB, signaling no pixels
970         return;
971     }
972 
973     write_raw_pixels(buffer, result.pixmap());
974 }
975 
ReadRawPixels(SkReadBuffer * buffer,SkBitmap * bitmap)976 bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) {
977     const size_t snugRB = buffer->readUInt();
978     if (0 == snugRB) {  // no pixels
979         return false;
980     }
981 
982     SkImageInfo info;
983     info.unflatten(*buffer);
984 
985     if (info.width() < 0 || info.height() < 0) {
986         return false;
987     }
988 
989     // If there was an error reading "info" or if it is bogus,
990     // don't use it to compute minRowBytes()
991     if (!buffer->validate(SkColorTypeValidateAlphaType(info.colorType(),
992                                                        info.alphaType()))) {
993         return false;
994     }
995 
996     const size_t ramRB = info.minRowBytes();
997     const int height = SkMax32(info.height(), 0);
998     const uint64_t snugSize = sk_64_mul(snugRB, height);
999     const uint64_t ramSize = sk_64_mul(ramRB, height);
1000     static const uint64_t max_size_t = (size_t)(-1);
1001     if (!buffer->validate((snugSize <= ramSize) && (ramSize <= max_size_t))) {
1002         return false;
1003     }
1004 
1005     sk_sp<SkData> data(SkData::MakeUninitialized(SkToSizeT(ramSize)));
1006     unsigned char* dst = (unsigned char*)data->writable_data();
1007     buffer->readByteArray(dst, SkToSizeT(snugSize));
1008 
1009     if (snugSize != ramSize) {
1010         const unsigned char* srcRow = dst + snugRB * (height - 1);
1011         unsigned char* dstRow = dst + ramRB * (height - 1);
1012         for (int y = height - 1; y >= 1; --y) {
1013             memmove(dstRow, srcRow, snugRB);
1014             srcRow -= snugRB;
1015             dstRow -= ramRB;
1016         }
1017         SkASSERT(srcRow == dstRow); // first row does not need to be moved
1018     }
1019 
1020     sk_sp<SkColorTable> ctable;
1021     if (buffer->readBool()) {
1022         ctable.reset(SkColorTable::Create(*buffer));
1023         if (!ctable) {
1024             return false;
1025         }
1026 
1027         if (info.isEmpty()) {
1028             // require an empty ctable
1029             if (ctable->count() != 0) {
1030                 buffer->validate(false);
1031                 return false;
1032             }
1033         } else {
1034             // require a non-empty ctable
1035             if (ctable->count() == 0) {
1036                 buffer->validate(false);
1037                 return false;
1038             }
1039             unsigned char maxIndex = ctable->count() - 1;
1040             for (uint64_t i = 0; i < ramSize; ++i) {
1041                 dst[i] = SkTMin(dst[i], maxIndex);
1042             }
1043         }
1044     }
1045 
1046     sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewWithData(info, info.minRowBytes(),
1047                                                        ctable.get(), data.get()));
1048     if (!pr.get()) {
1049         return false;
1050     }
1051     bitmap->setInfo(pr->info());
1052     bitmap->setPixelRef(std::move(pr), 0, 0);
1053     return true;
1054 }
1055 
1056 enum {
1057     SERIALIZE_PIXELTYPE_NONE,
1058     SERIALIZE_PIXELTYPE_REF_DATA
1059 };
1060 
1061 ///////////////////////////////////////////////////////////////////////////////
1062 
1063 #ifdef SK_DEBUG
validate() const1064 void SkBitmap::validate() const {
1065     fInfo.validate();
1066 
1067     // ImageInfo may not require this, but Bitmap ensures that opaque-only
1068     // colorTypes report opaque for their alphatype
1069     if (kRGB_565_SkColorType == fInfo.colorType()) {
1070         SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
1071     }
1072 
1073     SkASSERT(fInfo.validRowBytes(fRowBytes));
1074     uint8_t allFlags = kImageIsVolatile_Flag;
1075 #ifdef SK_BUILD_FOR_ANDROID
1076     allFlags |= kHasHardwareMipMap_Flag;
1077 #endif
1078     SkASSERT((~allFlags & fFlags) == 0);
1079     SkASSERT(fPixelLockCount >= 0);
1080 
1081     if (fPixels) {
1082         SkASSERT(fPixelRef);
1083         SkASSERT(fPixelLockCount > 0);
1084         SkASSERT(fPixelRef->isLocked());
1085         SkASSERT(fPixelRef->rowBytes() == fRowBytes);
1086         SkASSERT(fPixelRefOrigin.fX >= 0);
1087         SkASSERT(fPixelRefOrigin.fY >= 0);
1088         SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX);
1089         SkASSERT(fPixelRef->info().height() >= (int)this->height() + fPixelRefOrigin.fY);
1090         SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
1091     } else {
1092         SkASSERT(nullptr == fColorTable);
1093     }
1094 }
1095 #endif
1096 
1097 #ifndef SK_IGNORE_TO_STRING
1098 #include "SkString.h"
toString(SkString * str) const1099 void SkBitmap::toString(SkString* str) const {
1100 
1101     static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = {
1102         "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8",
1103     };
1104 
1105     str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
1106                  gColorTypeNames[this->colorType()]);
1107 
1108     str->append(" (");
1109     if (this->isOpaque()) {
1110         str->append("opaque");
1111     } else {
1112         str->append("transparent");
1113     }
1114     if (this->isImmutable()) {
1115         str->append(", immutable");
1116     } else {
1117         str->append(", not-immutable");
1118     }
1119     str->append(")");
1120 
1121     SkPixelRef* pr = this->pixelRef();
1122     if (nullptr == pr) {
1123         // show null or the explicit pixel address (rare)
1124         str->appendf(" pixels:%p", this->getPixels());
1125     } else {
1126         const char* uri = pr->getURI();
1127         if (uri) {
1128             str->appendf(" uri:\"%s\"", uri);
1129         } else {
1130             str->appendf(" pixelref:%p", pr);
1131         }
1132     }
1133 
1134     str->append(")");
1135 }
1136 #endif
1137 
1138 ///////////////////////////////////////////////////////////////////////////////
1139 
requestLock(SkAutoPixmapUnlock * result) const1140 bool SkBitmap::requestLock(SkAutoPixmapUnlock* result) const {
1141     SkASSERT(result);
1142 
1143     SkPixelRef* pr = fPixelRef.get();
1144     if (nullptr == pr) {
1145         return false;
1146     }
1147 
1148     // We have to lock the whole thing (using the pixelref's dimensions) until the api supports
1149     // a partial lock (with offset/origin). Hence we can't use our fInfo.
1150     SkPixelRef::LockRequest req = { pr->info().dimensions(), kNone_SkFilterQuality };
1151     SkPixelRef::LockResult res;
1152     if (pr->requestLock(req, &res)) {
1153         SkASSERT(res.fPixels);
1154         // The bitmap may be a subset of the pixelref's dimensions
1155         SkASSERT(fPixelRefOrigin.x() + fInfo.width()  <= res.fSize.width());
1156         SkASSERT(fPixelRefOrigin.y() + fInfo.height() <= res.fSize.height());
1157         const void* addr = (const char*)res.fPixels + SkColorTypeComputeOffset(fInfo.colorType(),
1158                                                                                fPixelRefOrigin.x(),
1159                                                                                fPixelRefOrigin.y(),
1160                                                                                res.fRowBytes);
1161 
1162         result->reset(SkPixmap(this->info(), addr, res.fRowBytes, res.fCTable),
1163                       res.fUnlockProc, res.fUnlockContext);
1164         return true;
1165     }
1166     return false;
1167 }
1168 
peekPixels(SkPixmap * pmap) const1169 bool SkBitmap::peekPixels(SkPixmap* pmap) const {
1170     if (fPixels) {
1171         if (pmap) {
1172             pmap->reset(fInfo, fPixels, fRowBytes, fColorTable);
1173         }
1174         return true;
1175     }
1176     return false;
1177 }
1178 
1179 ///////////////////////////////////////////////////////////////////////////////
1180 
1181 #ifdef SK_DEBUG
validate() const1182 void SkImageInfo::validate() const {
1183     SkASSERT(fWidth >= 0);
1184     SkASSERT(fHeight >= 0);
1185     SkASSERT(SkColorTypeIsValid(fColorType));
1186     SkASSERT(SkAlphaTypeIsValid(fAlphaType));
1187 }
1188 #endif
1189