blob: 1ba2968466ea2e07bcb083c4048c2b898a66492a [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"
10#include "SkColorPriv.h"
Matt Sarett485c4992017-02-14 14:18:27 -050011#include "SkConvertPixels.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkData.h"
13#include "SkFilterQuality.h"
Hal Canary4cba3fe2016-12-07 14:59:27 -050014#include "SkHalf.h"
Matt Sarett03dd6d52017-01-23 12:15:09 -050015#include "SkImageInfoPriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkMallocPixelRef.h"
17#include "SkMask.h"
bungemand3ebb482015-08-05 13:57:49 -070018#include "SkMath.h"
jvanverth02802f62015-07-02 06:42:49 -070019#include "SkPixelRef.h"
mtklein1b249332015-07-07 12:21:21 -070020#include "SkReadBuffer.h"
bungemand3ebb482015-08-05 13:57:49 -070021#include "SkRect.h"
22#include "SkScalar.h"
scroggo565901d2015-12-10 10:44:13 -080023#include "SkTemplates.h"
vandebo@chromium.org112706d2011-02-24 22:50:55 +000024#include "SkUnPreMultiply.h"
mtklein1b249332015-07-07 12:21:21 -070025#include "SkWriteBuffer.h"
Matt Sarett03dd6d52017-01-23 12:15:09 -050026#include "SkWritePixelsRec.h"
bungemand3ebb482015-08-05 13:57:49 -070027
28#include <string.h>
reed@android.com8a1c16f2008-12-17 15:59:43 +000029
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +000030static bool reset_return_false(SkBitmap* bm) {
31 bm->reset();
32 return false;
33}
34
Hal Canary1b3387b2016-12-12 13:48:12 -050035SkBitmap::SkBitmap()
Mike Reedb7120892017-04-14 17:16:36 -040036 : fPixels (nullptr)
Hal Canary1b3387b2016-12-12 13:48:12 -050037 , fPixelRefOrigin{0, 0}
38 , fRowBytes (0)
39 , fFlags (0) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000040
Hal Canary1b3387b2016-12-12 13:48:12 -050041// copy pixelref, but don't copy lock.
42SkBitmap::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 -050054// take lock and lockcount from other.
55SkBitmap::SkBitmap(SkBitmap&& other)
56 : fPixelRef (std::move(other.fPixelRef))
Hal Canary1b3387b2016-12-12 13:48:12 -050057 , fPixels (other.fPixels)
Hal Canary1b3387b2016-12-12 13:48:12 -050058 , fPixelRefOrigin (other.fPixelRefOrigin)
59 , fInfo (std::move(other.fInfo))
60 , fRowBytes (other.fRowBytes)
Mike Reedb7120892017-04-14 17:16:36 -040061 , fFlags (other.fFlags)
62{
Hal Canary1b3387b2016-12-12 13:48:12 -050063 SkASSERT(!other.fPixelRef);
64 other.fInfo.reset();
Hal Canary1b3387b2016-12-12 13:48:12 -050065 other.fPixels = nullptr;
Hal Canary1b3387b2016-12-12 13:48:12 -050066 other.fPixelRefOrigin = SkIPoint{0, 0};
67 other.fRowBytes = 0;
68 other.fFlags = 0;
69}
halcanary023bda02015-12-14 10:19:17 -080070
Mike Reedb7120892017-04-14 17:16:36 -040071SkBitmap::~SkBitmap() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000072
73SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
74 if (this != &src) {
Hal Canary1b3387b2016-12-12 13:48:12 -050075 fPixelRef = src.fPixelRef;
Mike Reedb7120892017-04-14 17:16:36 -040076 fPixels = src.fPixels;
Hal Canary1b3387b2016-12-12 13:48:12 -050077 fPixelRefOrigin = src.fPixelRefOrigin;
78 fInfo = src.fInfo;
79 fRowBytes = src.fRowBytes;
80 fFlags = src.fFlags;
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000082 SkDEBUGCODE(this->validate();)
83 return *this;
84}
85
halcanary023bda02015-12-14 10:19:17 -080086SkBitmap& SkBitmap::operator=(SkBitmap&& other) {
87 if (this != &other) {
Hal Canary1b3387b2016-12-12 13:48:12 -050088 fPixelRef = std::move(other.fPixelRef);
89 fInfo = std::move(other.fInfo);
Hal Canary1b3387b2016-12-12 13:48:12 -050090 fPixels = other.fPixels;
Hal Canary1b3387b2016-12-12 13:48:12 -050091 fPixelRefOrigin = other.fPixelRefOrigin;
92 fRowBytes = other.fRowBytes;
93 fFlags = other.fFlags;
94 SkASSERT(!other.fPixelRef);
95 other.fInfo.reset();
Hal Canary1b3387b2016-12-12 13:48:12 -050096 other.fPixels = nullptr;
Hal Canary1b3387b2016-12-12 13:48:12 -050097 other.fPixelRefOrigin = SkIPoint{0, 0};
98 other.fRowBytes = 0;
99 other.fFlags = 0;
halcanary023bda02015-12-14 10:19:17 -0800100 }
101 return *this;
102}
103
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104void SkBitmap::swap(SkBitmap& other) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500105 SkTSwap(*this, other);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106 SkDEBUGCODE(this->validate();)
107}
108
109void SkBitmap::reset() {
110 this->freePixels();
msarett23c51102016-05-27 07:39:02 -0700111 this->fInfo.reset();
reed@android.com4516f472009-06-29 16:25:36 +0000112 sk_bzero(this, sizeof(*this));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113}
114
reed@google.com86b2e432012-03-15 21:17:03 +0000115void SkBitmap::getBounds(SkRect* bounds) const {
116 SkASSERT(bounds);
117 bounds->set(0, 0,
reede5ea5002014-09-03 11:54:58 -0700118 SkIntToScalar(fInfo.width()), SkIntToScalar(fInfo.height()));
reed@google.com86b2e432012-03-15 21:17:03 +0000119}
120
reed@google.com80e14592012-03-16 14:58:07 +0000121void SkBitmap::getBounds(SkIRect* bounds) const {
122 SkASSERT(bounds);
reede5ea5002014-09-03 11:54:58 -0700123 bounds->set(0, 0, fInfo.width(), fInfo.height());
reed@google.com80e14592012-03-16 14:58:07 +0000124}
125
Mike Reedb7120892017-04-14 17:16:36 -0400126SkColorTable* SkBitmap::getColorTable() const {
127 return fPixelRef ? fPixelRef->colorTable() : nullptr;
128}
129
reed@google.com86b2e432012-03-15 21:17:03 +0000130///////////////////////////////////////////////////////////////////////////////
131
reede5ea5002014-09-03 11:54:58 -0700132bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) {
133 SkAlphaType newAT = info.alphaType();
134 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) {
commit-bot@chromium.orgd5414e52014-02-13 22:30:38 +0000135 return reset_return_false(this);
136 }
reede5ea5002014-09-03 11:54:58 -0700137 // don't look at info.alphaType(), since newAT is the real value...
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000138
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000139 // require that rowBytes fit in 31bits
140 int64_t mrb = info.minRowBytes64();
141 if ((int32_t)mrb != mrb) {
142 return reset_return_false(this);
reed@google.com383a6972013-10-21 14:00:07 +0000143 }
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000144 if ((int64_t)rowBytes != (int32_t)rowBytes) {
145 return reset_return_false(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 }
reed@android.com89bb83a2009-05-29 21:30:42 +0000147
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000148 if (info.width() < 0 || info.height() < 0) {
149 return reset_return_false(this);
150 }
151
152 if (kUnknown_SkColorType == info.colorType()) {
153 rowBytes = 0;
154 } else if (0 == rowBytes) {
155 rowBytes = (size_t)mrb;
reedf0aed972014-07-01 12:48:11 -0700156 } else if (!info.validRowBytes(rowBytes)) {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000157 return reset_return_false(this);
reed@google.com383a6972013-10-21 14:00:07 +0000158 }
159
160 this->freePixels();
161
reede5ea5002014-09-03 11:54:58 -0700162 fInfo = info.makeAlphaType(newAT);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000163 fRowBytes = SkToU32(rowBytes);
Mike Reedb7120892017-04-14 17:16:36 -0400164 SkDEBUGCODE(this->validate();)
reed@google.com383a6972013-10-21 14:00:07 +0000165 return true;
reed@google.com383a6972013-10-21 14:00:07 +0000166}
167
reede5ea5002014-09-03 11:54:58 -0700168bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) {
169 if (!SkColorTypeValidateAlphaType(fInfo.colorType(), newAlphaType, &newAlphaType)) {
reed@google.com383a6972013-10-21 14:00:07 +0000170 return false;
171 }
reede5ea5002014-09-03 11:54:58 -0700172 if (fInfo.alphaType() != newAlphaType) {
173 fInfo = fInfo.makeAlphaType(newAlphaType);
Ben Wagner2fcd4a42017-04-28 13:06:02 -0400174 if (fPixelRef) {
175 fPixelRef->changeAlphaType(newAlphaType);
176 }
commit-bot@chromium.org0e8d0d62014-01-27 15:41:07 +0000177 }
Mike Reedb7120892017-04-14 17:16:36 -0400178 SkDEBUGCODE(this->validate();)
reed@google.com383a6972013-10-21 14:00:07 +0000179 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180}
181
Mike Reedb7120892017-04-14 17:16:36 -0400182void SkBitmap::updatePixelsFromRef() {
183 void* p = nullptr;
bsalomon49f085d2014-09-05 13:34:00 -0700184 if (fPixelRef) {
Mike Reedb7120892017-04-14 17:16:36 -0400185 // wish we could assert that a pixelref *always* has pixels
186 p = fPixelRef->pixels();
187 if (p) {
188 SkASSERT(fRowBytes == fPixelRef->rowBytes());
189 p = (char*)p
190 + fPixelRefOrigin.fY * fRowBytes
191 + fPixelRefOrigin.fX * fInfo.bytesPerPixel();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 }
193 }
Mike Reedb7120892017-04-14 17:16:36 -0400194 fPixels = p;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195}
196
Hal Canary1b3387b2016-12-12 13:48:12 -0500197void SkBitmap::setPixelRef(sk_sp<SkPixelRef> pr, int dx, int dy) {
reed@google.comdcea5302014-01-03 13:43:01 +0000198#ifdef SK_DEBUG
reed@google.com672588b2014-01-08 15:42:01 +0000199 if (pr) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000200 if (kUnknown_SkColorType != fInfo.colorType()) {
Ben Wagner2fcd4a42017-04-28 13:06:02 -0400201 const SkImageInfo& prInfo = pr->info();
202 SkASSERT(fInfo.width() <= prInfo.width());
203 SkASSERT(fInfo.height() <= prInfo.height());
204 SkASSERT(fInfo.colorType() == prInfo.colorType());
205 switch (prInfo.alphaType()) {
206 case kUnknown_SkAlphaType:
207 SkASSERT(fInfo.alphaType() == kUnknown_SkAlphaType);
208 break;
209 case kOpaque_SkAlphaType:
210 case kPremul_SkAlphaType:
211 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
212 fInfo.alphaType() == kPremul_SkAlphaType);
213 break;
214 case kUnpremul_SkAlphaType:
215 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
216 fInfo.alphaType() == kUnpremul_SkAlphaType);
217 break;
218 }
reed@google.comdcea5302014-01-03 13:43:01 +0000219 }
220 }
221#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222
Mike Reedb7120892017-04-14 17:16:36 -0400223 fPixelRef = std::move(pr);
224 if (fPixelRef) {
Ben Wagner2fcd4a42017-04-28 13:06:02 -0400225 const SkImageInfo& info = fPixelRef->info();
226 fPixelRefOrigin.set(SkTPin(dx, 0, info.width()), SkTPin(dy, 0, info.height()));
Mike Reedb7120892017-04-14 17:16:36 -0400227 this->updatePixelsFromRef();
reed@google.com672588b2014-01-08 15:42:01 +0000228 } else {
229 // ignore dx,dy if there is no pixelref
230 fPixelRefOrigin.setZero();
Mike Reedb7120892017-04-14 17:16:36 -0400231 fPixels = nullptr;
reed@google.com672588b2014-01-08 15:42:01 +0000232 }
233
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 SkDEBUGCODE(this->validate();)
235}
236
237void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700238 if (nullptr == p) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500239 this->setPixelRef(nullptr, 0, 0);
reed@google.com8e1034e2012-07-30 13:16:35 +0000240 return;
241 }
242
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000243 if (kUnknown_SkColorType == fInfo.colorType()) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500244 this->setPixelRef(nullptr, 0, 0);
reed@google.combf790232013-12-13 19:45:58 +0000245 return;
246 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247
Mike Reed6b3155c2017-04-03 14:41:44 -0400248 this->setPixelRef(SkMallocPixelRef::MakeDirect(fInfo, p, fRowBytes, sk_ref_sp(ctable)), 0, 0);
Hal Canary1b3387b2016-12-12 13:48:12 -0500249 if (!fPixelRef) {
reed@google.combf790232013-12-13 19:45:58 +0000250 return;
251 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 SkDEBUGCODE(this->validate();)
253}
254
reed84825042014-09-02 12:50:45 -0700255bool SkBitmap::tryAllocPixels(Allocator* allocator, SkColorTable* ctable) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256 HeapAllocator stdalloc;
skia.committer@gmail.comd2ac07b2014-01-25 07:01:49 +0000257
halcanary96fcdcc2015-08-27 07:41:13 -0700258 if (nullptr == allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259 allocator = &stdalloc;
260 }
261 return allocator->allocPixelRef(this, ctable);
262}
263
reed@google.com9ebcac52014-01-24 18:53:42 +0000264///////////////////////////////////////////////////////////////////////////////
265
reed84825042014-09-02 12:50:45 -0700266bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
reedbae704b2014-06-28 14:26:35 -0700267 if (kIndex_8_SkColorType == requestedInfo.colorType()) {
268 return reset_return_false(this);
269 }
reedf0aed972014-07-01 12:48:11 -0700270 if (!this->setInfo(requestedInfo, rowBytes)) {
reedbae704b2014-06-28 14:26:35 -0700271 return reset_return_false(this);
272 }
mtklein775b8192014-12-02 09:11:25 -0800273
reedbae704b2014-06-28 14:26:35 -0700274 // setInfo may have corrected info (e.g. 565 is always opaque).
275 const SkImageInfo& correctedInfo = this->info();
reedf0aed972014-07-01 12:48:11 -0700276 // setInfo may have computed a valid rowbytes if 0 were passed in
277 rowBytes = this->rowBytes();
278
Mike Reed6b3155c2017-04-03 14:41:44 -0400279 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo, rowBytes, nullptr);
Hal Canary1b3387b2016-12-12 13:48:12 -0500280 if (!pr) {
reedbae704b2014-06-28 14:26:35 -0700281 return reset_return_false(this);
282 }
Hal Canary1b3387b2016-12-12 13:48:12 -0500283 this->setPixelRef(std::move(pr), 0, 0);
halcanary96fcdcc2015-08-27 07:41:13 -0700284 if (nullptr == this->getPixels()) {
reedbae704b2014-06-28 14:26:35 -0700285 return reset_return_false(this);
286 }
Mike Reedb7120892017-04-14 17:16:36 -0400287 SkDEBUGCODE(this->validate();)
reedbae704b2014-06-28 14:26:35 -0700288 return true;
289}
290
Mike Reed6b3155c2017-04-03 14:41:44 -0400291bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, sk_sp<SkColorTable> ctable,
292 uint32_t allocFlags) {
halcanary96fcdcc2015-08-27 07:41:13 -0700293 if (kIndex_8_SkColorType == requestedInfo.colorType() && nullptr == ctable) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000294 return reset_return_false(this);
295 }
scroggo0187dc22014-06-05 11:18:04 -0700296 if (!this->setInfo(requestedInfo)) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000297 return reset_return_false(this);
298 }
299
scroggo0187dc22014-06-05 11:18:04 -0700300 // setInfo may have corrected info (e.g. 565 is always opaque).
301 const SkImageInfo& correctedInfo = this->info();
302
Mike Reed6b3155c2017-04-03 14:41:44 -0400303 sk_sp<SkPixelRef> pr = (allocFlags & kZeroPixels_AllocFlag) ?
304 SkMallocPixelRef::MakeZeroed(correctedInfo, correctedInfo.minRowBytes(), ctable) :
305 SkMallocPixelRef::MakeAllocate(correctedInfo, correctedInfo.minRowBytes(), ctable);
Hal Canary1b3387b2016-12-12 13:48:12 -0500306 if (!pr) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000307 return reset_return_false(this);
308 }
Hal Canary1b3387b2016-12-12 13:48:12 -0500309 this->setPixelRef(std::move(pr), 0, 0);
halcanary96fcdcc2015-08-27 07:41:13 -0700310 if (nullptr == this->getPixels()) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000311 return reset_return_false(this);
312 }
Mike Reedb7120892017-04-14 17:16:36 -0400313 SkDEBUGCODE(this->validate();)
reed@google.com9ebcac52014-01-24 18:53:42 +0000314 return true;
315}
316
reeddb74f622015-05-30 13:41:15 -0700317static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
318 if (proc) {
319 proc(pixels, ctx);
320 }
321}
322
scroggo0187dc22014-06-05 11:18:04 -0700323bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
324 SkColorTable* ct, void (*releaseProc)(void* addr, void* context),
325 void* context) {
326 if (!this->setInfo(requestedInfo, rb)) {
reeddb74f622015-05-30 13:41:15 -0700327 invoke_release_proc(releaseProc, pixels, context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000328 this->reset();
329 return false;
330 }
halcanary96fcdcc2015-08-27 07:41:13 -0700331 if (nullptr == pixels) {
reeddb74f622015-05-30 13:41:15 -0700332 invoke_release_proc(releaseProc, pixels, context);
333 return true; // we behaved as if they called setInfo()
334 }
reed@google.com9ebcac52014-01-24 18:53:42 +0000335
scroggo0187dc22014-06-05 11:18:04 -0700336 // setInfo may have corrected info (e.g. 565 is always opaque).
337 const SkImageInfo& correctedInfo = this->info();
338
Mike Reed6b3155c2017-04-03 14:41:44 -0400339 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithProc(correctedInfo, rb, sk_ref_sp(ct),
340 pixels, releaseProc, context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000341 if (!pr) {
342 this->reset();
343 return false;
344 }
345
Hal Canary1b3387b2016-12-12 13:48:12 -0500346 this->setPixelRef(std::move(pr), 0, 0);
mike@reedtribe.org6e58cf32014-02-16 20:54:21 +0000347 SkDEBUGCODE(this->validate();)
reed@google.com9ebcac52014-01-24 18:53:42 +0000348 return true;
349}
350
halcanarye36ec872015-12-09 11:36:59 -0800351bool SkBitmap::installPixels(const SkPixmap& pixmap) {
352 return this->installPixels(pixmap.info(), pixmap.writable_addr(),
353 pixmap.rowBytes(), pixmap.ctable(),
354 nullptr, nullptr);
355}
356
commit-bot@chromium.orgdac52252014-02-17 21:21:46 +0000357bool SkBitmap::installMaskPixels(const SkMask& mask) {
358 if (SkMask::kA8_Format != mask.fFormat) {
359 this->reset();
360 return false;
361 }
362 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
363 mask.fBounds.height()),
364 mask.fImage, mask.fRowBytes);
365}
366
reed@google.comeb9a46c2014-01-25 16:46:20 +0000367///////////////////////////////////////////////////////////////////////////////
368
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369void SkBitmap::freePixels() {
Mike Reedb7120892017-04-14 17:16:36 -0400370 fPixelRef = nullptr;
371 fPixelRefOrigin.setZero();
halcanary96fcdcc2015-08-27 07:41:13 -0700372 fPixels = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373}
374
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375uint32_t SkBitmap::getGenerationID() const {
Hal Canary1b3387b2016-12-12 13:48:12 -0500376 return fPixelRef ? fPixelRef->getGenerationID() : 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377}
378
379void SkBitmap::notifyPixelsChanged() const {
junov@chromium.orgb0521292011-12-15 20:14:06 +0000380 SkASSERT(!this->isImmutable());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381 if (fPixelRef) {
382 fPixelRef->notifyPixelsChanged();
383 }
384}
385
386///////////////////////////////////////////////////////////////////////////////
387
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388/** We explicitly use the same allocator for our pixels that SkMask does,
389 so that we can freely assign memory allocated by one class to the other.
390 */
391bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
392 SkColorTable* ctable) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000393 const SkImageInfo info = dst->info();
394 if (kUnknown_SkColorType == info.colorType()) {
reed@google.combf790232013-12-13 19:45:58 +0000395// SkDebugf("unsupported config for info %d\n", dst->config());
396 return false;
397 }
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000398
Mike Reed6b3155c2017-04-03 14:41:44 -0400399 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes(), sk_ref_sp(ctable));
Hal Canary1b3387b2016-12-12 13:48:12 -0500400 if (!pr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401 return false;
402 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000403
Hal Canary1b3387b2016-12-12 13:48:12 -0500404 dst->setPixelRef(std::move(pr), 0, 0);
Mike Reedb7120892017-04-14 17:16:36 -0400405 SkDEBUGCODE(dst->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000406 return true;
407}
408
409///////////////////////////////////////////////////////////////////////////////
410
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000411bool SkBitmap::isImmutable() const {
scroggo08470592014-07-15 19:56:48 -0700412 return fPixelRef ? fPixelRef->isImmutable() : false;
junov@chromium.orgb0521292011-12-15 20:14:06 +0000413}
414
415void SkBitmap::setImmutable() {
416 if (fPixelRef) {
417 fPixelRef->setImmutable();
junov@chromium.orgb0521292011-12-15 20:14:06 +0000418 }
419}
420
junov@google.com4ee7ae52011-06-30 17:30:49 +0000421bool SkBitmap::isVolatile() const {
422 return (fFlags & kImageIsVolatile_Flag) != 0;
423}
424
425void SkBitmap::setIsVolatile(bool isVolatile) {
426 if (isVolatile) {
427 fFlags |= kImageIsVolatile_Flag;
428 } else {
429 fFlags &= ~kImageIsVolatile_Flag;
430 }
431}
432
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433void* SkBitmap::getAddr(int x, int y) const {
434 SkASSERT((unsigned)x < (unsigned)this->width());
435 SkASSERT((unsigned)y < (unsigned)this->height());
436
437 char* base = (char*)this->getPixels();
438 if (base) {
439 base += y * this->rowBytes();
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000440 switch (this->colorType()) {
mtklein7fd93e32016-07-26 13:05:30 -0700441 case kRGBA_F16_SkColorType:
442 base += x << 3;
443 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000444 case kRGBA_8888_SkColorType:
445 case kBGRA_8888_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446 base += x << 2;
447 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000448 case kARGB_4444_SkColorType:
449 case kRGB_565_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000450 base += x << 1;
451 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000452 case kAlpha_8_SkColorType:
453 case kIndex_8_SkColorType:
reed0c9b1a82015-03-17 17:44:06 -0700454 case kGray_8_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000455 base += x;
456 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000457 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000458 SkDEBUGFAIL("Can't return addr for config");
halcanary96fcdcc2015-08-27 07:41:13 -0700459 base = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460 break;
461 }
462 }
463 return base;
464}
465
466///////////////////////////////////////////////////////////////////////////////
467///////////////////////////////////////////////////////////////////////////////
468
reed7aefe032015-06-08 10:22:22 -0700469void SkBitmap::erase(SkColor c, const SkIRect& area) const {
reed92fc2ae2015-05-22 08:06:21 -0700470 SkDEBUGCODE(this->validate();)
reed92fc2ae2015-05-22 08:06:21 -0700471
472 switch (fInfo.colorType()) {
473 case kUnknown_SkColorType:
474 case kIndex_8_SkColorType:
475 // TODO: can we ASSERT that we never get here?
476 return; // can't erase. Should we bzero so the memory is not uninitialized?
477 default:
478 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000479 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000480
Mike Reed4edb5d22017-04-17 11:02:51 -0400481 SkPixmap result;
482 if (!this->peekPixels(&result)) {
reed92fc2ae2015-05-22 08:06:21 -0700483 return;
484 }
485
Mike Reed4edb5d22017-04-17 11:02:51 -0400486 if (result.erase(c, area)) {
reed92fc2ae2015-05-22 08:06:21 -0700487 this->notifyPixelsChanged();
488 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000489}
490
reed7aefe032015-06-08 10:22:22 -0700491void SkBitmap::eraseColor(SkColor c) const {
492 this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
reed@google.com60d32352013-06-28 19:40:50 +0000493}
494
reed@android.com8a1c16f2008-12-17 15:59:43 +0000495//////////////////////////////////////////////////////////////////////////////////////
496//////////////////////////////////////////////////////////////////////////////////////
497
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
499 SkDEBUGCODE(this->validate();)
500
Hal Canary1b3387b2016-12-12 13:48:12 -0500501 if (nullptr == result || !fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000502 return false; // no src pixels
503 }
504
505 SkIRect srcRect, r;
506 srcRect.set(0, 0, this->width(), this->height());
507 if (!r.intersect(srcRect, subset)) {
508 return false; // r is empty (i.e. no intersection)
509 }
510
scroggo@google.coma2a31922012-12-07 19:14:45 +0000511 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
512 // exited above.
513 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
514 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
515
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 SkBitmap dst;
herbb5d74682016-04-21 08:45:39 -0700517 dst.setInfo(this->info().makeWH(r.width(), r.height()), this->rowBytes());
skyostil@google.com0eb75762012-01-16 10:45:53 +0000518 dst.setIsVolatile(this->isVolatile());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519
520 if (fPixelRef) {
reed@google.com672588b2014-01-08 15:42:01 +0000521 SkIPoint origin = fPixelRefOrigin;
522 origin.fX += r.fLeft;
523 origin.fY += r.fTop;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000524 // share the pixelref with a custom offset
Hal Canary1b3387b2016-12-12 13:48:12 -0500525 dst.setPixelRef(fPixelRef, origin.x(), origin.y());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526 }
527 SkDEBUGCODE(dst.validate();)
528
529 // we know we're good, so commit to result
530 result->swap(dst);
531 return true;
532}
533
534///////////////////////////////////////////////////////////////////////////////
535
Mike Reed22f34822016-11-28 17:17:38 -0500536bool SkBitmap::canCopyTo(SkColorType dstCT) const {
reedb184f7f2014-07-13 04:32:32 -0700537 const SkColorType srcCT = this->colorType();
538
539 if (srcCT == kUnknown_SkColorType) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540 return false;
541 }
Mike Reed22f34822016-11-28 17:17:38 -0500542 if (srcCT == kAlpha_8_SkColorType && dstCT != kAlpha_8_SkColorType) {
543 return false; // can't convert from alpha to non-alpha
544 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000545
Mike Reed22f34822016-11-28 17:17:38 -0500546 bool sameConfigs = (srcCT == dstCT);
547 switch (dstCT) {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000548 case kAlpha_8_SkColorType:
549 case kRGB_565_SkColorType:
commit-bot@chromium.org60b5dce2014-04-22 20:24:33 +0000550 case kRGBA_8888_SkColorType:
551 case kBGRA_8888_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552 break;
Matt Sarettcb6266b2017-01-17 10:48:53 -0500553 case kGray_8_SkColorType:
weita@google.comf9ab99a2009-05-03 18:23:30 +0000554 if (!sameConfigs) {
555 return false;
556 }
557 break;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000558 case kARGB_4444_SkColorType:
reedb184f7f2014-07-13 04:32:32 -0700559 return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000560 default:
561 return false;
562 }
reed@android.comfbaa88d2009-05-06 17:44:34 +0000563 return true;
564}
565
reedb184f7f2014-07-13 04:32:32 -0700566bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
567 int x, int y) const {
Mike Reed4edb5d22017-04-17 11:02:51 -0400568 SkPixmap src;
569 if (!this->peekPixels(&src)) {
reedb184f7f2014-07-13 04:32:32 -0700570 return false;
571 }
Mike Reed4edb5d22017-04-17 11:02:51 -0400572 return src.readPixels(requestedDstInfo, dstPixels, dstRB, x, y);
reedb184f7f2014-07-13 04:32:32 -0700573}
574
Mike Reed68dd8d02017-01-04 16:34:31 -0500575bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
576 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
577}
578
Matt Sarettd2adc662017-03-27 15:07:35 -0400579bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY,
580 SkTransferFunctionBehavior behavior) {
Matt Sarett03dd6d52017-01-23 12:15:09 -0500581 if (!SkImageInfoValidConversion(fInfo, src.info())) {
Mike Reed68dd8d02017-01-04 16:34:31 -0500582 return false;
583 }
584
Matt Sarett03dd6d52017-01-23 12:15:09 -0500585 SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY);
586 if (!rec.trim(fInfo.width(), fInfo.height())) {
587 return false;
588 }
589
590 void* dstPixels = this->getAddr(rec.fX, rec.fY);
591 const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
Matt Sarett485c4992017-02-14 14:18:27 -0500592 SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes,
Matt Sarettd2adc662017-03-27 15:07:35 -0400593 src.ctable(), behavior);
Matt Sarett8572d852017-02-14 11:21:02 -0500594 return true;
Mike Reed68dd8d02017-01-04 16:34:31 -0500595}
596
Matt Sarett68b8e3d2017-04-28 11:15:22 -0400597#ifdef SK_SUPPORT_LEGACY_BITMAP_COPYTO
598bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType) const {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000599 if (!this->canCopyTo(dstColorType)) {
reed@android.comfbaa88d2009-05-06 17:44:34 +0000600 return false;
601 }
602
Mike Reed4edb5d22017-04-17 11:02:51 -0400603 SkPixmap srcPM;
604 if (!this->peekPixels(&srcPM)) {
reed@google.com50dfa012011-04-01 19:05:36 +0000605 return false;
606 }
Matt Sarettd9836f42017-04-05 15:41:53 -0400607
Matt Sarett0122af02017-04-27 20:08:39 +0000608 SkBitmap tmpDst;
Matt Sarett68b8e3d2017-04-28 11:15:22 -0400609 SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType);
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000610 if (!tmpDst.setInfo(dstInfo)) {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000611 return false;
612 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000613
weita@google.comf9ab99a2009-05-03 18:23:30 +0000614 // allocate colortable if srcConfig == kIndex8_Config
Hal Canary704cd322016-11-07 14:13:52 -0500615 sk_sp<SkColorTable> ctable;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000616 if (dstColorType == kIndex_8_SkColorType) {
reed95d343f2015-05-23 13:21:06 -0700617 ctable.reset(SkRef(srcPM.ctable()));
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000618 }
Matt Sarett68b8e3d2017-04-28 11:15:22 -0400619 if (!tmpDst.tryAllocPixels(ctable.get())) {
weita@google.comf9ab99a2009-05-03 18:23:30 +0000620 return false;
621 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000622
Mike Reed4edb5d22017-04-17 11:02:51 -0400623 SkPixmap dstPM;
624 if (!tmpDst.peekPixels(&dstPM)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625 return false;
626 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000627
Matt Sarettd9836f42017-04-05 15:41:53 -0400628 if (!srcPM.readPixels(dstPM)) {
reedb184f7f2014-07-13 04:32:32 -0700629 return false;
630 }
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000631
reed@google.com50dfa012011-04-01 19:05:36 +0000632 dst->swap(tmpDst);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000633 return true;
634}
Mike Reed42ce38f2017-04-06 14:03:25 -0400635#endif
636
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638
reed92fc2ae2015-05-22 08:06:21 -0700639static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
halcanary96fcdcc2015-08-27 07:41:13 -0700640 SkASSERT(alpha != nullptr);
reed92fc2ae2015-05-22 08:06:21 -0700641 SkASSERT(alphaRowBytes >= src.width());
642
Mike Reed4edb5d22017-04-17 11:02:51 -0400643 SkPixmap pmap;
644 if (!src.peekPixels(&pmap)) {
lsalzmana2415ac2016-10-11 14:29:12 -0700645 for (int y = 0; y < src.height(); ++y) {
646 memset(alpha, 0, src.width());
647 alpha += alphaRowBytes;
648 }
reed92fc2ae2015-05-22 08:06:21 -0700649 return false;
650 }
Matt Sarett485c4992017-02-14 14:18:27 -0500651 SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
Matt Sarettd2adc662017-03-27 15:07:35 -0400652 pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable(),
653 SkTransferFunctionBehavior::kRespect);
reed@android.com1cdcb512009-08-24 19:11:00 +0000654 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000655}
656
657#include "SkPaint.h"
658#include "SkMaskFilter.h"
659#include "SkMatrix.h"
660
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000661bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
djsollen@google.com57f49692011-02-23 20:46:31 +0000662 Allocator *allocator, SkIPoint* offset) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663 SkDEBUGCODE(this->validate();)
664
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000665 SkBitmap tmpBitmap;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666 SkMatrix identity;
667 SkMask srcM, dstM;
668
669 srcM.fBounds.set(0, 0, this->width(), this->height());
670 srcM.fRowBytes = SkAlign4(this->width());
671 srcM.fFormat = SkMask::kA8_Format;
672
halcanary96fcdcc2015-08-27 07:41:13 -0700673 SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674
675 // compute our (larger?) dst bounds if we have a filter
bsalomon49f085d2014-09-05 13:34:00 -0700676 if (filter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677 identity.reset();
halcanary96fcdcc2015-08-27 07:41:13 -0700678 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679 goto NO_FILTER_CASE;
680 }
681 dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
682 } else {
683 NO_FILTER_CASE:
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000684 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -0700685 if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000686 // Allocation of pixels for alpha bitmap failed.
687 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
688 tmpBitmap.width(), tmpBitmap.height());
689 return false;
690 }
691 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692 if (offset) {
693 offset->set(0, 0);
694 }
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000695 tmpBitmap.swap(*dst);
696 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697 }
bungeman@google.com02f55842011-10-04 21:25:00 +0000698 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
699 SkAutoMaskFreeImage srcCleanup(srcM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000700
701 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -0700702 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000703 goto NO_FILTER_CASE;
704 }
bungeman@google.com02f55842011-10-04 21:25:00 +0000705 SkAutoMaskFreeImage dstCleanup(dstM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000706
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000707 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
708 dstM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -0700709 if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000710 // Allocation of pixels for alpha bitmap failed.
711 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
712 tmpBitmap.width(), tmpBitmap.height());
713 return false;
714 }
715 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000716 if (offset) {
717 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
718 }
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000719 SkDEBUGCODE(tmpBitmap.validate();)
720
721 tmpBitmap.swap(*dst);
722 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000723}
724
725///////////////////////////////////////////////////////////////////////////////
726
reed92fc2ae2015-05-22 08:06:21 -0700727static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) {
728 const SkImageInfo& info = pmap.info();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000729 const size_t snugRB = info.width() * info.bytesPerPixel();
reed92fc2ae2015-05-22 08:06:21 -0700730 const char* src = (const char*)pmap.addr();
731 const size_t ramRB = pmap.rowBytes();
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +0000732
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000733 buffer->write32(SkToU32(snugRB));
734 info.flatten(*buffer);
735
736 const size_t size = snugRB * info.height();
scroggo565901d2015-12-10 10:44:13 -0800737 SkAutoTMalloc<char> storage(size);
738 char* dst = storage.get();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000739 for (int y = 0; y < info.height(); ++y) {
740 memcpy(dst, src, snugRB);
741 dst += snugRB;
742 src += ramRB;
743 }
744 buffer->writeByteArray(storage.get(), size);
745
reed92fc2ae2015-05-22 08:06:21 -0700746 const SkColorTable* ct = pmap.ctable();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000747 if (kIndex_8_SkColorType == info.colorType() && ct) {
748 buffer->writeBool(true);
749 ct->writeToBuffer(*buffer);
750 } else {
751 buffer->writeBool(false);
752 }
753}
754
reed92fc2ae2015-05-22 08:06:21 -0700755void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) {
756 const SkImageInfo info = bitmap.info();
Hal Canary1b3387b2016-12-12 13:48:12 -0500757 if (0 == info.width() || 0 == info.height() || bitmap.isNull()) {
reed92fc2ae2015-05-22 08:06:21 -0700758 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
759 return;
760 }
761
Mike Reed4edb5d22017-04-17 11:02:51 -0400762 SkPixmap result;
763 if (!bitmap.peekPixels(&result)) {
reed92fc2ae2015-05-22 08:06:21 -0700764 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
765 return;
766 }
767
Mike Reed4edb5d22017-04-17 11:02:51 -0400768 write_raw_pixels(buffer, result);
reed92fc2ae2015-05-22 08:06:21 -0700769}
770
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000771bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) {
772 const size_t snugRB = buffer->readUInt();
773 if (0 == snugRB) { // no pixels
774 return false;
775 }
776
777 SkImageInfo info;
778 info.unflatten(*buffer);
779
Robert Phillipsb2cb5352016-12-20 12:44:41 -0500780 if (info.width() < 0 || info.height() < 0) {
781 return false;
782 }
783
mtklein58e389b2016-07-15 07:00:11 -0700784 // If there was an error reading "info" or if it is bogus,
robertphillips74139f12016-06-28 09:04:34 -0700785 // don't use it to compute minRowBytes()
786 if (!buffer->validate(SkColorTypeValidateAlphaType(info.colorType(),
787 info.alphaType()))) {
sugoica95c192014-07-08 09:18:48 -0700788 return false;
789 }
790
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000791 const size_t ramRB = info.minRowBytes();
sugoibd0d9da2015-01-07 08:47:44 -0800792 const int height = SkMax32(info.height(), 0);
793 const uint64_t snugSize = sk_64_mul(snugRB, height);
794 const uint64_t ramSize = sk_64_mul(ramRB, height);
795 static const uint64_t max_size_t = (size_t)(-1);
796 if (!buffer->validate((snugSize <= ramSize) && (ramSize <= max_size_t))) {
commit-bot@chromium.org05858432014-05-30 01:06:44 +0000797 return false;
798 }
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000799
reedfde05112016-03-11 13:02:28 -0800800 sk_sp<SkData> data(SkData::MakeUninitialized(SkToSizeT(ramSize)));
robertphillips28937842015-06-08 07:10:49 -0700801 unsigned char* dst = (unsigned char*)data->writable_data();
sugoibd0d9da2015-01-07 08:47:44 -0800802 buffer->readByteArray(dst, SkToSizeT(snugSize));
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000803
804 if (snugSize != ramSize) {
robertphillips28937842015-06-08 07:10:49 -0700805 const unsigned char* srcRow = dst + snugRB * (height - 1);
806 unsigned char* dstRow = dst + ramRB * (height - 1);
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000807 for (int y = height - 1; y >= 1; --y) {
808 memmove(dstRow, srcRow, snugRB);
809 srcRow -= snugRB;
810 dstRow -= ramRB;
811 }
812 SkASSERT(srcRow == dstRow); // first row does not need to be moved
813 }
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +0000814
Hal Canary704cd322016-11-07 14:13:52 -0500815 sk_sp<SkColorTable> ctable;
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000816 if (buffer->readBool()) {
Mike Reed6b3155c2017-04-03 14:41:44 -0400817 ctable = SkColorTable::Create(*buffer);
reedb236d1a2015-08-28 10:14:18 -0700818 if (!ctable) {
819 return false;
820 }
robertphillips28937842015-06-08 07:10:49 -0700821
reedb236d1a2015-08-28 10:14:18 -0700822 if (info.isEmpty()) {
823 // require an empty ctable
824 if (ctable->count() != 0) {
825 buffer->validate(false);
826 return false;
827 }
828 } else {
829 // require a non-empty ctable
830 if (ctable->count() == 0) {
831 buffer->validate(false);
832 return false;
833 }
834 unsigned char maxIndex = ctable->count() - 1;
835 for (uint64_t i = 0; i < ramSize; ++i) {
836 dst[i] = SkTMin(dst[i], maxIndex);
837 }
robertphillips28937842015-06-08 07:10:49 -0700838 }
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000839 }
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +0000840
Mike Reed6b3155c2017-04-03 14:41:44 -0400841 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithData(info, info.minRowBytes(),
842 std::move(ctable), std::move(data));
843 if (!pr) {
sugoi6af31472015-01-28 13:15:32 -0800844 return false;
845 }
Ben Wagner2fcd4a42017-04-28 13:06:02 -0400846 bitmap->setInfo(pr->info());
Hal Canary1b3387b2016-12-12 13:48:12 -0500847 bitmap->setPixelRef(std::move(pr), 0, 0);
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000848 return true;
849}
850
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851enum {
852 SERIALIZE_PIXELTYPE_NONE,
djsollen@google.com21830d92012-08-07 19:49:41 +0000853 SERIALIZE_PIXELTYPE_REF_DATA
reed@android.com8a1c16f2008-12-17 15:59:43 +0000854};
855
reed@android.com8a1c16f2008-12-17 15:59:43 +0000856///////////////////////////////////////////////////////////////////////////////
857
reed@android.com8a1c16f2008-12-17 15:59:43 +0000858#ifdef SK_DEBUG
859void SkBitmap::validate() const {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000860 fInfo.validate();
commit-bot@chromium.orgd5414e52014-02-13 22:30:38 +0000861
862 // ImageInfo may not require this, but Bitmap ensures that opaque-only
863 // colorTypes report opaque for their alphatype
864 if (kRGB_565_SkColorType == fInfo.colorType()) {
865 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
866 }
867
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000868 SkASSERT(fInfo.validRowBytes(fRowBytes));
scroggo08470592014-07-15 19:56:48 -0700869 uint8_t allFlags = kImageIsVolatile_Flag;
scroggo@google.com8e990eb2013-06-14 15:55:56 +0000870#ifdef SK_BUILD_FOR_ANDROID
871 allFlags |= kHasHardwareMipMap_Flag;
872#endif
scroggo08470592014-07-15 19:56:48 -0700873 SkASSERT((~allFlags & fFlags) == 0);
Mike Reedb7120892017-04-14 17:16:36 -0400874
875 if (fPixelRef && fPixelRef->pixels()) {
876 SkASSERT(fPixels);
877 } else {
878 SkASSERT(!fPixels);
879 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000880
reed@google.com615316c2014-01-15 19:15:23 +0000881 if (fPixels) {
882 SkASSERT(fPixelRef);
reed@google.com615316c2014-01-15 19:15:23 +0000883 SkASSERT(fPixelRef->rowBytes() == fRowBytes);
884 SkASSERT(fPixelRefOrigin.fX >= 0);
885 SkASSERT(fPixelRefOrigin.fY >= 0);
Ben Wagner2fcd4a42017-04-28 13:06:02 -0400886 SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX);
887 SkASSERT(fPixelRef->info().height() >= (int)this->height() + fPixelRefOrigin.fY);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000888 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000889 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000890}
891#endif
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000892
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000893#ifndef SK_IGNORE_TO_STRING
bungemand3ebb482015-08-05 13:57:49 -0700894#include "SkString.h"
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000895void SkBitmap::toString(SkString* str) const {
896
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000897 static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = {
898 "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8",
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000899 };
900
901 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000902 gColorTypeNames[this->colorType()]);
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000903
904 str->append(" (");
905 if (this->isOpaque()) {
906 str->append("opaque");
907 } else {
908 str->append("transparent");
909 }
910 if (this->isImmutable()) {
911 str->append(", immutable");
912 } else {
913 str->append(", not-immutable");
914 }
915 str->append(")");
916
Mike Reed96d5b9a2017-04-12 22:29:00 -0400917 str->appendf(" pixelref:%p", this->pixelRef());
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000918 str->append(")");
919}
920#endif
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000921
922///////////////////////////////////////////////////////////////////////////////
923
reedcb674142015-06-05 06:58:22 -0700924bool SkBitmap::peekPixels(SkPixmap* pmap) const {
925 if (fPixels) {
926 if (pmap) {
Mike Reedb7120892017-04-14 17:16:36 -0400927 pmap->reset(fInfo, fPixels, fRowBytes, this->getColorTable());
reedcb674142015-06-05 06:58:22 -0700928 }
929 return true;
930 }
931 return false;
932}
933
reed92fc2ae2015-05-22 08:06:21 -0700934///////////////////////////////////////////////////////////////////////////////
935
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000936#ifdef SK_DEBUG
937void SkImageInfo::validate() const {
938 SkASSERT(fWidth >= 0);
939 SkASSERT(fHeight >= 0);
940 SkASSERT(SkColorTypeIsValid(fColorType));
941 SkASSERT(SkAlphaTypeIsValid(fAlphaType));
942}
943#endif