blob: 4c4f76ae95b5b70db31c4f313905c84c67db55c7 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
herbb906daf2015-09-29 09:37:59 -07008#include "SkAtomics.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkBitmap.h"
Cary Clarka4083c92017-09-15 11:59:23 -040010#include "SkColorData.h"
Mike Reed086a4272017-07-18 10:53:11 -040011#include "SkColorTable.h"
Matt Sarett485c4992017-02-14 14:18:27 -050012#include "SkConvertPixels.h"
bungemand3ebb482015-08-05 13:57:49 -070013#include "SkData.h"
14#include "SkFilterQuality.h"
Hal Canary4cba3fe2016-12-07 14:59:27 -050015#include "SkHalf.h"
Matt Sarett03dd6d52017-01-23 12:15:09 -050016#include "SkImageInfoPriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#include "SkMallocPixelRef.h"
18#include "SkMask.h"
bungemand3ebb482015-08-05 13:57:49 -070019#include "SkMath.h"
jvanverth02802f62015-07-02 06:42:49 -070020#include "SkPixelRef.h"
mtklein1b249332015-07-07 12:21:21 -070021#include "SkReadBuffer.h"
bungemand3ebb482015-08-05 13:57:49 -070022#include "SkRect.h"
23#include "SkScalar.h"
scroggo565901d2015-12-10 10:44:13 -080024#include "SkTemplates.h"
vandebo@chromium.org112706d2011-02-24 22:50:55 +000025#include "SkUnPreMultiply.h"
mtklein1b249332015-07-07 12:21:21 -070026#include "SkWriteBuffer.h"
Matt Sarett03dd6d52017-01-23 12:15:09 -050027#include "SkWritePixelsRec.h"
bungemand3ebb482015-08-05 13:57:49 -070028
29#include <string.h>
reed@android.com8a1c16f2008-12-17 15:59:43 +000030
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +000031static bool reset_return_false(SkBitmap* bm) {
32 bm->reset();
33 return false;
34}
35
Hal Canary1b3387b2016-12-12 13:48:12 -050036SkBitmap::SkBitmap()
Mike Reedb7120892017-04-14 17:16:36 -040037 : fPixels (nullptr)
Hal Canary1b3387b2016-12-12 13:48:12 -050038 , fPixelRefOrigin{0, 0}
39 , fRowBytes (0)
40 , fFlags (0) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000041
Hal Canary1b3387b2016-12-12 13:48:12 -050042SkBitmap::SkBitmap(const SkBitmap& src)
43 : fPixelRef (src.fPixelRef)
Mike Reedb7120892017-04-14 17:16:36 -040044 , fPixels (src.fPixels)
Hal Canary1b3387b2016-12-12 13:48:12 -050045 , fPixelRefOrigin(src.fPixelRefOrigin)
46 , fInfo (src.fInfo)
47 , fRowBytes (src.fRowBytes)
48 , fFlags (src.fFlags)
49{
reed@android.com8a1c16f2008-12-17 15:59:43 +000050 SkDEBUGCODE(src.validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +000051 SkDEBUGCODE(this->validate();)
52}
53
Hal Canary1b3387b2016-12-12 13:48:12 -050054SkBitmap::SkBitmap(SkBitmap&& other)
55 : fPixelRef (std::move(other.fPixelRef))
Hal Canary1b3387b2016-12-12 13:48:12 -050056 , fPixels (other.fPixels)
Hal Canary1b3387b2016-12-12 13:48:12 -050057 , fPixelRefOrigin (other.fPixelRefOrigin)
58 , fInfo (std::move(other.fInfo))
59 , fRowBytes (other.fRowBytes)
Mike Reedb7120892017-04-14 17:16:36 -040060 , fFlags (other.fFlags)
61{
Hal Canary1b3387b2016-12-12 13:48:12 -050062 SkASSERT(!other.fPixelRef);
63 other.fInfo.reset();
Hal Canary1b3387b2016-12-12 13:48:12 -050064 other.fPixels = nullptr;
Hal Canary1b3387b2016-12-12 13:48:12 -050065 other.fPixelRefOrigin = SkIPoint{0, 0};
66 other.fRowBytes = 0;
67 other.fFlags = 0;
68}
halcanary023bda02015-12-14 10:19:17 -080069
Mike Reedb7120892017-04-14 17:16:36 -040070SkBitmap::~SkBitmap() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000071
72SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
73 if (this != &src) {
Hal Canary1b3387b2016-12-12 13:48:12 -050074 fPixelRef = src.fPixelRef;
Mike Reedb7120892017-04-14 17:16:36 -040075 fPixels = src.fPixels;
Hal Canary1b3387b2016-12-12 13:48:12 -050076 fPixelRefOrigin = src.fPixelRefOrigin;
77 fInfo = src.fInfo;
78 fRowBytes = src.fRowBytes;
79 fFlags = src.fFlags;
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 SkDEBUGCODE(this->validate();)
82 return *this;
83}
84
halcanary023bda02015-12-14 10:19:17 -080085SkBitmap& SkBitmap::operator=(SkBitmap&& other) {
86 if (this != &other) {
Hal Canary1b3387b2016-12-12 13:48:12 -050087 fPixelRef = std::move(other.fPixelRef);
88 fInfo = std::move(other.fInfo);
Hal Canary1b3387b2016-12-12 13:48:12 -050089 fPixels = other.fPixels;
Hal Canary1b3387b2016-12-12 13:48:12 -050090 fPixelRefOrigin = other.fPixelRefOrigin;
91 fRowBytes = other.fRowBytes;
92 fFlags = other.fFlags;
93 SkASSERT(!other.fPixelRef);
94 other.fInfo.reset();
Hal Canary1b3387b2016-12-12 13:48:12 -050095 other.fPixels = nullptr;
Hal Canary1b3387b2016-12-12 13:48:12 -050096 other.fPixelRefOrigin = SkIPoint{0, 0};
97 other.fRowBytes = 0;
98 other.fFlags = 0;
halcanary023bda02015-12-14 10:19:17 -080099 }
100 return *this;
101}
102
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103void SkBitmap::swap(SkBitmap& other) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500104 SkTSwap(*this, other);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105 SkDEBUGCODE(this->validate();)
106}
107
108void SkBitmap::reset() {
109 this->freePixels();
msarett23c51102016-05-27 07:39:02 -0700110 this->fInfo.reset();
reed@android.com4516f472009-06-29 16:25:36 +0000111 sk_bzero(this, sizeof(*this));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112}
113
reed@google.com86b2e432012-03-15 21:17:03 +0000114void SkBitmap::getBounds(SkRect* bounds) const {
115 SkASSERT(bounds);
116 bounds->set(0, 0,
reede5ea5002014-09-03 11:54:58 -0700117 SkIntToScalar(fInfo.width()), SkIntToScalar(fInfo.height()));
reed@google.com86b2e432012-03-15 21:17:03 +0000118}
119
reed@google.com80e14592012-03-16 14:58:07 +0000120void SkBitmap::getBounds(SkIRect* bounds) const {
121 SkASSERT(bounds);
reede5ea5002014-09-03 11:54:58 -0700122 bounds->set(0, 0, fInfo.width(), fInfo.height());
reed@google.com80e14592012-03-16 14:58:07 +0000123}
124
reed@google.com86b2e432012-03-15 21:17:03 +0000125///////////////////////////////////////////////////////////////////////////////
126
reede5ea5002014-09-03 11:54:58 -0700127bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) {
128 SkAlphaType newAT = info.alphaType();
129 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) {
commit-bot@chromium.orgd5414e52014-02-13 22:30:38 +0000130 return reset_return_false(this);
131 }
reede5ea5002014-09-03 11:54:58 -0700132 // don't look at info.alphaType(), since newAT is the real value...
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000133
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000134 // require that rowBytes fit in 31bits
135 int64_t mrb = info.minRowBytes64();
136 if ((int32_t)mrb != mrb) {
137 return reset_return_false(this);
reed@google.com383a6972013-10-21 14:00:07 +0000138 }
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000139 if ((int64_t)rowBytes != (int32_t)rowBytes) {
140 return reset_return_false(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141 }
reed@android.com89bb83a2009-05-29 21:30:42 +0000142
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000143 if (info.width() < 0 || info.height() < 0) {
144 return reset_return_false(this);
145 }
146
147 if (kUnknown_SkColorType == info.colorType()) {
148 rowBytes = 0;
149 } else if (0 == rowBytes) {
150 rowBytes = (size_t)mrb;
reedf0aed972014-07-01 12:48:11 -0700151 } else if (!info.validRowBytes(rowBytes)) {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000152 return reset_return_false(this);
reed@google.com383a6972013-10-21 14:00:07 +0000153 }
154
155 this->freePixels();
156
reede5ea5002014-09-03 11:54:58 -0700157 fInfo = info.makeAlphaType(newAT);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000158 fRowBytes = SkToU32(rowBytes);
Mike Reedb7120892017-04-14 17:16:36 -0400159 SkDEBUGCODE(this->validate();)
reed@google.com383a6972013-10-21 14:00:07 +0000160 return true;
reed@google.com383a6972013-10-21 14:00:07 +0000161}
162
reede5ea5002014-09-03 11:54:58 -0700163bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) {
164 if (!SkColorTypeValidateAlphaType(fInfo.colorType(), newAlphaType, &newAlphaType)) {
reed@google.com383a6972013-10-21 14:00:07 +0000165 return false;
166 }
reede5ea5002014-09-03 11:54:58 -0700167 if (fInfo.alphaType() != newAlphaType) {
168 fInfo = fInfo.makeAlphaType(newAlphaType);
commit-bot@chromium.org0e8d0d62014-01-27 15:41:07 +0000169 }
Mike Reedb7120892017-04-14 17:16:36 -0400170 SkDEBUGCODE(this->validate();)
reed@google.com383a6972013-10-21 14:00:07 +0000171 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172}
173
Mike Reedb7120892017-04-14 17:16:36 -0400174void SkBitmap::updatePixelsFromRef() {
175 void* p = nullptr;
bsalomon49f085d2014-09-05 13:34:00 -0700176 if (fPixelRef) {
Mike Reedb7120892017-04-14 17:16:36 -0400177 // wish we could assert that a pixelref *always* has pixels
178 p = fPixelRef->pixels();
179 if (p) {
180 SkASSERT(fRowBytes == fPixelRef->rowBytes());
181 p = (char*)p
182 + fPixelRefOrigin.fY * fRowBytes
183 + fPixelRefOrigin.fX * fInfo.bytesPerPixel();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 }
185 }
Mike Reedb7120892017-04-14 17:16:36 -0400186 fPixels = p;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187}
188
Hal Canary1b3387b2016-12-12 13:48:12 -0500189void SkBitmap::setPixelRef(sk_sp<SkPixelRef> pr, int dx, int dy) {
reed@google.comdcea5302014-01-03 13:43:01 +0000190#ifdef SK_DEBUG
reed@google.com672588b2014-01-08 15:42:01 +0000191 if (pr) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000192 if (kUnknown_SkColorType != fInfo.colorType()) {
Cary Clark4b85b6d2017-09-29 14:25:30 -0400193 SkASSERT(dx >= 0 && fInfo.width() + dx <= pr->width());
194 SkASSERT(dy >= 0 && fInfo.height() + dy <= pr->height());
reed@google.comdcea5302014-01-03 13:43:01 +0000195 }
196 }
197#endif
Cary Clark4b85b6d2017-09-29 14:25:30 -0400198 fPixelRef = kUnknown_SkColorType != fInfo.colorType() ? std::move(pr) : nullptr;
Mike Reedb7120892017-04-14 17:16:36 -0400199 if (fPixelRef) {
Cary Clark4b85b6d2017-09-29 14:25:30 -0400200 fPixelRefOrigin.set(dx, dy);
201 fRowBytes = fPixelRef->rowBytes();
Mike Reedb7120892017-04-14 17:16:36 -0400202 this->updatePixelsFromRef();
reed@google.com672588b2014-01-08 15:42:01 +0000203 } else {
204 // ignore dx,dy if there is no pixelref
205 fPixelRefOrigin.setZero();
Mike Reedb7120892017-04-14 17:16:36 -0400206 fPixels = nullptr;
reed@google.com672588b2014-01-08 15:42:01 +0000207 }
208
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 SkDEBUGCODE(this->validate();)
210}
211
Mike Reed086a4272017-07-18 10:53:11 -0400212void SkBitmap::setPixels(void* p) {
halcanary96fcdcc2015-08-27 07:41:13 -0700213 if (nullptr == p) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500214 this->setPixelRef(nullptr, 0, 0);
reed@google.com8e1034e2012-07-30 13:16:35 +0000215 return;
216 }
217
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000218 if (kUnknown_SkColorType == fInfo.colorType()) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500219 this->setPixelRef(nullptr, 0, 0);
reed@google.combf790232013-12-13 19:45:58 +0000220 return;
221 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222
Mike Reed086a4272017-07-18 10:53:11 -0400223 this->setPixelRef(SkMallocPixelRef::MakeDirect(fInfo, p, fRowBytes), 0, 0);
Hal Canary1b3387b2016-12-12 13:48:12 -0500224 if (!fPixelRef) {
reed@google.combf790232013-12-13 19:45:58 +0000225 return;
226 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 SkDEBUGCODE(this->validate();)
228}
229
Mike Reed086a4272017-07-18 10:53:11 -0400230bool SkBitmap::tryAllocPixels(Allocator* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 HeapAllocator stdalloc;
skia.committer@gmail.comd2ac07b2014-01-25 07:01:49 +0000232
halcanary96fcdcc2015-08-27 07:41:13 -0700233 if (nullptr == allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 allocator = &stdalloc;
235 }
Mike Reed086a4272017-07-18 10:53:11 -0400236 return allocator->allocPixelRef(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237}
238
reed@google.com9ebcac52014-01-24 18:53:42 +0000239///////////////////////////////////////////////////////////////////////////////
240
reed84825042014-09-02 12:50:45 -0700241bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
reedf0aed972014-07-01 12:48:11 -0700242 if (!this->setInfo(requestedInfo, rowBytes)) {
reedbae704b2014-06-28 14:26:35 -0700243 return reset_return_false(this);
244 }
mtklein775b8192014-12-02 09:11:25 -0800245
reedbae704b2014-06-28 14:26:35 -0700246 // setInfo may have corrected info (e.g. 565 is always opaque).
247 const SkImageInfo& correctedInfo = this->info();
Cary Clark4b85b6d2017-09-29 14:25:30 -0400248 if (kUnknown_SkColorType == correctedInfo.colorType()) {
249 return true;
250 }
reedf0aed972014-07-01 12:48:11 -0700251 // setInfo may have computed a valid rowbytes if 0 were passed in
252 rowBytes = this->rowBytes();
253
Mike Reed086a4272017-07-18 10:53:11 -0400254 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo, rowBytes);
Hal Canary1b3387b2016-12-12 13:48:12 -0500255 if (!pr) {
reedbae704b2014-06-28 14:26:35 -0700256 return reset_return_false(this);
257 }
Hal Canary1b3387b2016-12-12 13:48:12 -0500258 this->setPixelRef(std::move(pr), 0, 0);
halcanary96fcdcc2015-08-27 07:41:13 -0700259 if (nullptr == this->getPixels()) {
reedbae704b2014-06-28 14:26:35 -0700260 return reset_return_false(this);
261 }
Mike Reedb7120892017-04-14 17:16:36 -0400262 SkDEBUGCODE(this->validate();)
reedbae704b2014-06-28 14:26:35 -0700263 return true;
264}
265
Mike Reed086a4272017-07-18 10:53:11 -0400266bool SkBitmap::tryAllocPixelsFlags(const SkImageInfo& requestedInfo, uint32_t allocFlags) {
scroggo0187dc22014-06-05 11:18:04 -0700267 if (!this->setInfo(requestedInfo)) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000268 return reset_return_false(this);
269 }
270
scroggo0187dc22014-06-05 11:18:04 -0700271 // setInfo may have corrected info (e.g. 565 is always opaque).
272 const SkImageInfo& correctedInfo = this->info();
273
Mike Reed6b3155c2017-04-03 14:41:44 -0400274 sk_sp<SkPixelRef> pr = (allocFlags & kZeroPixels_AllocFlag) ?
Mike Reed086a4272017-07-18 10:53:11 -0400275 SkMallocPixelRef::MakeZeroed(correctedInfo, correctedInfo.minRowBytes()) :
276 SkMallocPixelRef::MakeAllocate(correctedInfo, correctedInfo.minRowBytes());
Hal Canary1b3387b2016-12-12 13:48:12 -0500277 if (!pr) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000278 return reset_return_false(this);
279 }
Hal Canary1b3387b2016-12-12 13:48:12 -0500280 this->setPixelRef(std::move(pr), 0, 0);
halcanary96fcdcc2015-08-27 07:41:13 -0700281 if (nullptr == this->getPixels()) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000282 return reset_return_false(this);
283 }
Mike Reedb7120892017-04-14 17:16:36 -0400284 SkDEBUGCODE(this->validate();)
reed@google.com9ebcac52014-01-24 18:53:42 +0000285 return true;
286}
287
reeddb74f622015-05-30 13:41:15 -0700288static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
289 if (proc) {
290 proc(pixels, ctx);
291 }
292}
293
scroggo0187dc22014-06-05 11:18:04 -0700294bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
Mike Reed086a4272017-07-18 10:53:11 -0400295 void (*releaseProc)(void* addr, void* context), void* context) {
scroggo0187dc22014-06-05 11:18:04 -0700296 if (!this->setInfo(requestedInfo, rb)) {
reeddb74f622015-05-30 13:41:15 -0700297 invoke_release_proc(releaseProc, pixels, context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000298 this->reset();
299 return false;
300 }
halcanary96fcdcc2015-08-27 07:41:13 -0700301 if (nullptr == pixels) {
reeddb74f622015-05-30 13:41:15 -0700302 invoke_release_proc(releaseProc, pixels, context);
303 return true; // we behaved as if they called setInfo()
304 }
reed@google.com9ebcac52014-01-24 18:53:42 +0000305
scroggo0187dc22014-06-05 11:18:04 -0700306 // setInfo may have corrected info (e.g. 565 is always opaque).
307 const SkImageInfo& correctedInfo = this->info();
308
Mike Reed086a4272017-07-18 10:53:11 -0400309 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithProc(correctedInfo, rb, pixels,
310 releaseProc, context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000311 if (!pr) {
312 this->reset();
313 return false;
314 }
315
Hal Canary1b3387b2016-12-12 13:48:12 -0500316 this->setPixelRef(std::move(pr), 0, 0);
mike@reedtribe.org6e58cf32014-02-16 20:54:21 +0000317 SkDEBUGCODE(this->validate();)
reed@google.com9ebcac52014-01-24 18:53:42 +0000318 return true;
319}
320
halcanarye36ec872015-12-09 11:36:59 -0800321bool SkBitmap::installPixels(const SkPixmap& pixmap) {
Mike Reed086a4272017-07-18 10:53:11 -0400322 return this->installPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(),
halcanarye36ec872015-12-09 11:36:59 -0800323 nullptr, nullptr);
324}
325
commit-bot@chromium.orgdac52252014-02-17 21:21:46 +0000326bool SkBitmap::installMaskPixels(const SkMask& mask) {
327 if (SkMask::kA8_Format != mask.fFormat) {
328 this->reset();
329 return false;
330 }
331 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
332 mask.fBounds.height()),
333 mask.fImage, mask.fRowBytes);
334}
335
reed@google.comeb9a46c2014-01-25 16:46:20 +0000336///////////////////////////////////////////////////////////////////////////////
337
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338void SkBitmap::freePixels() {
Mike Reedb7120892017-04-14 17:16:36 -0400339 fPixelRef = nullptr;
340 fPixelRefOrigin.setZero();
halcanary96fcdcc2015-08-27 07:41:13 -0700341 fPixels = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342}
343
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344uint32_t SkBitmap::getGenerationID() const {
Hal Canary1b3387b2016-12-12 13:48:12 -0500345 return fPixelRef ? fPixelRef->getGenerationID() : 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346}
347
348void SkBitmap::notifyPixelsChanged() const {
junov@chromium.orgb0521292011-12-15 20:14:06 +0000349 SkASSERT(!this->isImmutable());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 if (fPixelRef) {
351 fPixelRef->notifyPixelsChanged();
352 }
353}
354
355///////////////////////////////////////////////////////////////////////////////
356
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357/** We explicitly use the same allocator for our pixels that SkMask does,
358 so that we can freely assign memory allocated by one class to the other.
359 */
Mike Reedb7648a22017-07-19 15:45:45 -0400360bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000361 const SkImageInfo info = dst->info();
362 if (kUnknown_SkColorType == info.colorType()) {
reed@google.combf790232013-12-13 19:45:58 +0000363// SkDebugf("unsupported config for info %d\n", dst->config());
364 return false;
365 }
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000366
Mike Reed086a4272017-07-18 10:53:11 -0400367 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes());
Hal Canary1b3387b2016-12-12 13:48:12 -0500368 if (!pr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 return false;
370 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000371
Hal Canary1b3387b2016-12-12 13:48:12 -0500372 dst->setPixelRef(std::move(pr), 0, 0);
Mike Reedb7120892017-04-14 17:16:36 -0400373 SkDEBUGCODE(dst->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374 return true;
375}
376
377///////////////////////////////////////////////////////////////////////////////
378
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000379bool SkBitmap::isImmutable() const {
scroggo08470592014-07-15 19:56:48 -0700380 return fPixelRef ? fPixelRef->isImmutable() : false;
junov@chromium.orgb0521292011-12-15 20:14:06 +0000381}
382
383void SkBitmap::setImmutable() {
384 if (fPixelRef) {
385 fPixelRef->setImmutable();
junov@chromium.orgb0521292011-12-15 20:14:06 +0000386 }
387}
388
junov@google.com4ee7ae52011-06-30 17:30:49 +0000389bool SkBitmap::isVolatile() const {
390 return (fFlags & kImageIsVolatile_Flag) != 0;
391}
392
393void SkBitmap::setIsVolatile(bool isVolatile) {
394 if (isVolatile) {
395 fFlags |= kImageIsVolatile_Flag;
396 } else {
397 fFlags &= ~kImageIsVolatile_Flag;
398 }
399}
400
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401void* SkBitmap::getAddr(int x, int y) const {
402 SkASSERT((unsigned)x < (unsigned)this->width());
403 SkASSERT((unsigned)y < (unsigned)this->height());
404
405 char* base = (char*)this->getPixels();
406 if (base) {
407 base += y * this->rowBytes();
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000408 switch (this->colorType()) {
mtklein7fd93e32016-07-26 13:05:30 -0700409 case kRGBA_F16_SkColorType:
410 base += x << 3;
411 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000412 case kRGBA_8888_SkColorType:
413 case kBGRA_8888_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000414 base += x << 2;
415 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000416 case kARGB_4444_SkColorType:
417 case kRGB_565_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000418 base += x << 1;
419 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000420 case kAlpha_8_SkColorType:
reed0c9b1a82015-03-17 17:44:06 -0700421 case kGray_8_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 base += x;
423 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000424 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000425 SkDEBUGFAIL("Can't return addr for config");
halcanary96fcdcc2015-08-27 07:41:13 -0700426 base = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 break;
428 }
429 }
430 return base;
431}
432
433///////////////////////////////////////////////////////////////////////////////
434///////////////////////////////////////////////////////////////////////////////
435
reed7aefe032015-06-08 10:22:22 -0700436void SkBitmap::erase(SkColor c, const SkIRect& area) const {
reed92fc2ae2015-05-22 08:06:21 -0700437 SkDEBUGCODE(this->validate();)
reed92fc2ae2015-05-22 08:06:21 -0700438
439 switch (fInfo.colorType()) {
440 case kUnknown_SkColorType:
reed92fc2ae2015-05-22 08:06:21 -0700441 // TODO: can we ASSERT that we never get here?
442 return; // can't erase. Should we bzero so the memory is not uninitialized?
443 default:
444 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000446
Mike Reed4edb5d22017-04-17 11:02:51 -0400447 SkPixmap result;
448 if (!this->peekPixels(&result)) {
reed92fc2ae2015-05-22 08:06:21 -0700449 return;
450 }
451
Mike Reed4edb5d22017-04-17 11:02:51 -0400452 if (result.erase(c, area)) {
reed92fc2ae2015-05-22 08:06:21 -0700453 this->notifyPixelsChanged();
454 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000455}
456
reed7aefe032015-06-08 10:22:22 -0700457void SkBitmap::eraseColor(SkColor c) const {
458 this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
reed@google.com60d32352013-06-28 19:40:50 +0000459}
460
reed@android.com8a1c16f2008-12-17 15:59:43 +0000461//////////////////////////////////////////////////////////////////////////////////////
462//////////////////////////////////////////////////////////////////////////////////////
463
reed@android.com8a1c16f2008-12-17 15:59:43 +0000464bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
465 SkDEBUGCODE(this->validate();)
466
Hal Canary1b3387b2016-12-12 13:48:12 -0500467 if (nullptr == result || !fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000468 return false; // no src pixels
469 }
470
471 SkIRect srcRect, r;
472 srcRect.set(0, 0, this->width(), this->height());
473 if (!r.intersect(srcRect, subset)) {
474 return false; // r is empty (i.e. no intersection)
475 }
476
scroggo@google.coma2a31922012-12-07 19:14:45 +0000477 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
478 // exited above.
479 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
480 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
481
reed@android.com8a1c16f2008-12-17 15:59:43 +0000482 SkBitmap dst;
herbb5d74682016-04-21 08:45:39 -0700483 dst.setInfo(this->info().makeWH(r.width(), r.height()), this->rowBytes());
skyostil@google.com0eb75762012-01-16 10:45:53 +0000484 dst.setIsVolatile(this->isVolatile());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000485
486 if (fPixelRef) {
reed@google.com672588b2014-01-08 15:42:01 +0000487 SkIPoint origin = fPixelRefOrigin;
488 origin.fX += r.fLeft;
489 origin.fY += r.fTop;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000490 // share the pixelref with a custom offset
Hal Canary1b3387b2016-12-12 13:48:12 -0500491 dst.setPixelRef(fPixelRef, origin.x(), origin.y());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000492 }
493 SkDEBUGCODE(dst.validate();)
494
495 // we know we're good, so commit to result
496 result->swap(dst);
497 return true;
498}
499
500///////////////////////////////////////////////////////////////////////////////
501
reedb184f7f2014-07-13 04:32:32 -0700502bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
Matt Sarett3928ff82017-06-06 10:11:34 -0400503 int x, int y, SkTransferFunctionBehavior behavior) const {
Mike Reed4edb5d22017-04-17 11:02:51 -0400504 SkPixmap src;
505 if (!this->peekPixels(&src)) {
reedb184f7f2014-07-13 04:32:32 -0700506 return false;
507 }
Matt Sarett3928ff82017-06-06 10:11:34 -0400508 return src.readPixels(requestedDstInfo, dstPixels, dstRB, x, y, behavior);
reedb184f7f2014-07-13 04:32:32 -0700509}
510
Mike Reed68dd8d02017-01-04 16:34:31 -0500511bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
512 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
513}
514
Matt Sarettd2adc662017-03-27 15:07:35 -0400515bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY,
516 SkTransferFunctionBehavior behavior) {
Matt Sarett03dd6d52017-01-23 12:15:09 -0500517 if (!SkImageInfoValidConversion(fInfo, src.info())) {
Mike Reed68dd8d02017-01-04 16:34:31 -0500518 return false;
519 }
520
Matt Sarett03dd6d52017-01-23 12:15:09 -0500521 SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY);
522 if (!rec.trim(fInfo.width(), fInfo.height())) {
523 return false;
524 }
525
526 void* dstPixels = this->getAddr(rec.fX, rec.fY);
527 const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
Matt Sarett485c4992017-02-14 14:18:27 -0500528 SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes,
Mike Reed086a4272017-07-18 10:53:11 -0400529 nullptr, behavior);
Matt Sarett8572d852017-02-14 11:21:02 -0500530 return true;
Mike Reed68dd8d02017-01-04 16:34:31 -0500531}
532
reed@android.com8a1c16f2008-12-17 15:59:43 +0000533///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534
reed92fc2ae2015-05-22 08:06:21 -0700535static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
halcanary96fcdcc2015-08-27 07:41:13 -0700536 SkASSERT(alpha != nullptr);
reed92fc2ae2015-05-22 08:06:21 -0700537 SkASSERT(alphaRowBytes >= src.width());
538
Mike Reed4edb5d22017-04-17 11:02:51 -0400539 SkPixmap pmap;
540 if (!src.peekPixels(&pmap)) {
lsalzmana2415ac2016-10-11 14:29:12 -0700541 for (int y = 0; y < src.height(); ++y) {
542 memset(alpha, 0, src.width());
543 alpha += alphaRowBytes;
544 }
reed92fc2ae2015-05-22 08:06:21 -0700545 return false;
546 }
Matt Sarett485c4992017-02-14 14:18:27 -0500547 SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
Mike Reed086a4272017-07-18 10:53:11 -0400548 pmap.info(), pmap.addr(), pmap.rowBytes(), nullptr,
Matt Sarettd2adc662017-03-27 15:07:35 -0400549 SkTransferFunctionBehavior::kRespect);
reed@android.com1cdcb512009-08-24 19:11:00 +0000550 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000551}
552
553#include "SkPaint.h"
554#include "SkMaskFilter.h"
555#include "SkMatrix.h"
556
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000557bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
djsollen@google.com57f49692011-02-23 20:46:31 +0000558 Allocator *allocator, SkIPoint* offset) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000559 SkDEBUGCODE(this->validate();)
560
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000561 SkBitmap tmpBitmap;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000562 SkMatrix identity;
563 SkMask srcM, dstM;
564
565 srcM.fBounds.set(0, 0, this->width(), this->height());
566 srcM.fRowBytes = SkAlign4(this->width());
567 srcM.fFormat = SkMask::kA8_Format;
568
halcanary96fcdcc2015-08-27 07:41:13 -0700569 SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000570
571 // compute our (larger?) dst bounds if we have a filter
bsalomon49f085d2014-09-05 13:34:00 -0700572 if (filter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000573 identity.reset();
halcanary96fcdcc2015-08-27 07:41:13 -0700574 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575 goto NO_FILTER_CASE;
576 }
577 dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
578 } else {
579 NO_FILTER_CASE:
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000580 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
Mike Reed086a4272017-07-18 10:53:11 -0400581 if (!tmpBitmap.tryAllocPixels(allocator)) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000582 // Allocation of pixels for alpha bitmap failed.
583 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
584 tmpBitmap.width(), tmpBitmap.height());
585 return false;
586 }
587 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588 if (offset) {
589 offset->set(0, 0);
590 }
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000591 tmpBitmap.swap(*dst);
592 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593 }
bungeman@google.com02f55842011-10-04 21:25:00 +0000594 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
595 SkAutoMaskFreeImage srcCleanup(srcM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000596
597 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -0700598 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000599 goto NO_FILTER_CASE;
600 }
bungeman@google.com02f55842011-10-04 21:25:00 +0000601 SkAutoMaskFreeImage dstCleanup(dstM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000602
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000603 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
604 dstM.fRowBytes);
Mike Reed086a4272017-07-18 10:53:11 -0400605 if (!tmpBitmap.tryAllocPixels(allocator)) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000606 // Allocation of pixels for alpha bitmap failed.
607 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
608 tmpBitmap.width(), tmpBitmap.height());
609 return false;
610 }
611 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 if (offset) {
613 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
614 }
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000615 SkDEBUGCODE(tmpBitmap.validate();)
616
617 tmpBitmap.swap(*dst);
618 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619}
620
621///////////////////////////////////////////////////////////////////////////////
622
reed92fc2ae2015-05-22 08:06:21 -0700623static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) {
624 const SkImageInfo& info = pmap.info();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000625 const size_t snugRB = info.width() * info.bytesPerPixel();
reed92fc2ae2015-05-22 08:06:21 -0700626 const char* src = (const char*)pmap.addr();
627 const size_t ramRB = pmap.rowBytes();
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +0000628
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000629 buffer->write32(SkToU32(snugRB));
630 info.flatten(*buffer);
631
632 const size_t size = snugRB * info.height();
scroggo565901d2015-12-10 10:44:13 -0800633 SkAutoTMalloc<char> storage(size);
634 char* dst = storage.get();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000635 for (int y = 0; y < info.height(); ++y) {
636 memcpy(dst, src, snugRB);
637 dst += snugRB;
638 src += ramRB;
639 }
640 buffer->writeByteArray(storage.get(), size);
Mike Reed262b3192017-07-17 10:13:58 -0400641 // no colortable
642 buffer->writeBool(false);
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000643}
644
reed92fc2ae2015-05-22 08:06:21 -0700645void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) {
646 const SkImageInfo info = bitmap.info();
Hal Canary1b3387b2016-12-12 13:48:12 -0500647 if (0 == info.width() || 0 == info.height() || bitmap.isNull()) {
reed92fc2ae2015-05-22 08:06:21 -0700648 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
649 return;
650 }
651
Mike Reed4edb5d22017-04-17 11:02:51 -0400652 SkPixmap result;
653 if (!bitmap.peekPixels(&result)) {
reed92fc2ae2015-05-22 08:06:21 -0700654 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
655 return;
656 }
657
Mike Reed4edb5d22017-04-17 11:02:51 -0400658 write_raw_pixels(buffer, result);
reed92fc2ae2015-05-22 08:06:21 -0700659}
660
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000661bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) {
Mike Kleind6c04d92017-09-25 13:49:49 -0400662 if (0 == buffer->readUInt()) {
663 return false; // no pixels
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000664 }
665
666 SkImageInfo info;
667 info.unflatten(*buffer);
668
Robert Phillipsb2cb5352016-12-20 12:44:41 -0500669 if (info.width() < 0 || info.height() < 0) {
670 return false;
671 }
672
mtklein58e389b2016-07-15 07:00:11 -0700673 // If there was an error reading "info" or if it is bogus,
Mike Kleind6c04d92017-09-25 13:49:49 -0400674 // don't use it to compute minRowBytes().
robertphillips74139f12016-06-28 09:04:34 -0700675 if (!buffer->validate(SkColorTypeValidateAlphaType(info.colorType(),
676 info.alphaType()))) {
sugoica95c192014-07-08 09:18:48 -0700677 return false;
678 }
679
Mike Kleind6c04d92017-09-25 13:49:49 -0400680 // write_raw_pixels() always writes snug buffers with rowBytes == minRowBytes().
Mike Reedcd284c52017-09-29 15:22:56 -0400681 size_t bytes = info.computeMinByteSize();
Mike Kleind6c04d92017-09-25 13:49:49 -0400682 if (!buffer->validate(bytes != 0)) {
commit-bot@chromium.org05858432014-05-30 01:06:44 +0000683 return false;
684 }
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000685
Mike Kleind6c04d92017-09-25 13:49:49 -0400686 sk_sp<SkData> data(SkData::MakeUninitialized(bytes));
robertphillips28937842015-06-08 07:10:49 -0700687 unsigned char* dst = (unsigned char*)data->writable_data();
Mike Kleind6c04d92017-09-25 13:49:49 -0400688 if (!buffer->readByteArray(dst, bytes)) {
689 return false;
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000690 }
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +0000691
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000692 if (buffer->readBool()) {
Mike Reed323ae0e2017-07-24 22:05:25 -0400693 SkColorTable::Skip(*buffer);
694 if (!buffer->isValid()) {
reedb236d1a2015-08-28 10:14:18 -0700695 return false;
696 }
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000697 }
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +0000698
Mike Reed6b3155c2017-04-03 14:41:44 -0400699 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithData(info, info.minRowBytes(),
Mike Reed086a4272017-07-18 10:53:11 -0400700 std::move(data));
Mike Reed6b3155c2017-04-03 14:41:44 -0400701 if (!pr) {
sugoi6af31472015-01-28 13:15:32 -0800702 return false;
703 }
Matt Sarettf7583112017-05-01 10:22:31 -0400704 bitmap->setInfo(info);
Hal Canary1b3387b2016-12-12 13:48:12 -0500705 bitmap->setPixelRef(std::move(pr), 0, 0);
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000706 return true;
707}
708
reed@android.com8a1c16f2008-12-17 15:59:43 +0000709enum {
710 SERIALIZE_PIXELTYPE_NONE,
djsollen@google.com21830d92012-08-07 19:49:41 +0000711 SERIALIZE_PIXELTYPE_REF_DATA
reed@android.com8a1c16f2008-12-17 15:59:43 +0000712};
713
reed@android.com8a1c16f2008-12-17 15:59:43 +0000714///////////////////////////////////////////////////////////////////////////////
715
reed@android.com8a1c16f2008-12-17 15:59:43 +0000716#ifdef SK_DEBUG
717void SkBitmap::validate() const {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000718 fInfo.validate();
commit-bot@chromium.orgd5414e52014-02-13 22:30:38 +0000719
720 // ImageInfo may not require this, but Bitmap ensures that opaque-only
721 // colorTypes report opaque for their alphatype
722 if (kRGB_565_SkColorType == fInfo.colorType()) {
723 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
724 }
725
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000726 SkASSERT(fInfo.validRowBytes(fRowBytes));
scroggo08470592014-07-15 19:56:48 -0700727 uint8_t allFlags = kImageIsVolatile_Flag;
scroggo@google.com8e990eb2013-06-14 15:55:56 +0000728#ifdef SK_BUILD_FOR_ANDROID
729 allFlags |= kHasHardwareMipMap_Flag;
730#endif
scroggo08470592014-07-15 19:56:48 -0700731 SkASSERT((~allFlags & fFlags) == 0);
Mike Reedb7120892017-04-14 17:16:36 -0400732
733 if (fPixelRef && fPixelRef->pixels()) {
734 SkASSERT(fPixels);
735 } else {
736 SkASSERT(!fPixels);
737 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738
reed@google.com615316c2014-01-15 19:15:23 +0000739 if (fPixels) {
740 SkASSERT(fPixelRef);
reed@google.com615316c2014-01-15 19:15:23 +0000741 SkASSERT(fPixelRef->rowBytes() == fRowBytes);
742 SkASSERT(fPixelRefOrigin.fX >= 0);
743 SkASSERT(fPixelRefOrigin.fY >= 0);
Matt Sarettf7583112017-05-01 10:22:31 -0400744 SkASSERT(fPixelRef->width() >= (int)this->width() + fPixelRefOrigin.fX);
745 SkASSERT(fPixelRef->height() >= (int)this->height() + fPixelRefOrigin.fY);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000746 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000747 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000748}
749#endif
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000750
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000751#ifndef SK_IGNORE_TO_STRING
bungemand3ebb482015-08-05 13:57:49 -0700752#include "SkString.h"
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000753void SkBitmap::toString(SkString* str) const {
754
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000755 static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = {
756 "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8",
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000757 };
758
759 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000760 gColorTypeNames[this->colorType()]);
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000761
762 str->append(" (");
763 if (this->isOpaque()) {
764 str->append("opaque");
765 } else {
766 str->append("transparent");
767 }
768 if (this->isImmutable()) {
769 str->append(", immutable");
770 } else {
771 str->append(", not-immutable");
772 }
773 str->append(")");
774
Mike Reed96d5b9a2017-04-12 22:29:00 -0400775 str->appendf(" pixelref:%p", this->pixelRef());
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000776 str->append(")");
777}
778#endif
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000779
780///////////////////////////////////////////////////////////////////////////////
781
reedcb674142015-06-05 06:58:22 -0700782bool SkBitmap::peekPixels(SkPixmap* pmap) const {
783 if (fPixels) {
784 if (pmap) {
Mike Reed086a4272017-07-18 10:53:11 -0400785 pmap->reset(fInfo, fPixels, fRowBytes);
reedcb674142015-06-05 06:58:22 -0700786 }
787 return true;
788 }
789 return false;
790}
791
reed92fc2ae2015-05-22 08:06:21 -0700792///////////////////////////////////////////////////////////////////////////////
793
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000794#ifdef SK_DEBUG
795void SkImageInfo::validate() const {
796 SkASSERT(fWidth >= 0);
797 SkASSERT(fHeight >= 0);
798 SkASSERT(SkColorTypeIsValid(fColorType));
799 SkASSERT(SkAlphaTypeIsValid(fAlphaType));
800}
801#endif