blob: 5969a73a050b13613ff6c588c3a67edffc3c6541 [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()) {
Matt Sarettf7583112017-05-01 10:22:31 -0400201 SkASSERT(fInfo.width() + dx <= pr->width());
202 SkASSERT(fInfo.height() + dy <= pr->height());
reed@google.comdcea5302014-01-03 13:43:01 +0000203 }
204 }
205#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206
Mike Reedb7120892017-04-14 17:16:36 -0400207 fPixelRef = std::move(pr);
208 if (fPixelRef) {
Matt Sarettf7583112017-05-01 10:22:31 -0400209 fPixelRefOrigin.set(SkTPin(dx, 0, fPixelRef->width()), SkTPin(dy, 0, fPixelRef->height()));
Mike Reedb7120892017-04-14 17:16:36 -0400210 this->updatePixelsFromRef();
reed@google.com672588b2014-01-08 15:42:01 +0000211 } else {
212 // ignore dx,dy if there is no pixelref
213 fPixelRefOrigin.setZero();
Mike Reedb7120892017-04-14 17:16:36 -0400214 fPixels = nullptr;
reed@google.com672588b2014-01-08 15:42:01 +0000215 }
216
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217 SkDEBUGCODE(this->validate();)
218}
219
220void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700221 if (nullptr == p) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500222 this->setPixelRef(nullptr, 0, 0);
reed@google.com8e1034e2012-07-30 13:16:35 +0000223 return;
224 }
225
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000226 if (kUnknown_SkColorType == fInfo.colorType()) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500227 this->setPixelRef(nullptr, 0, 0);
reed@google.combf790232013-12-13 19:45:58 +0000228 return;
229 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230
Mike Reed6b3155c2017-04-03 14:41:44 -0400231 this->setPixelRef(SkMallocPixelRef::MakeDirect(fInfo, p, fRowBytes, sk_ref_sp(ctable)), 0, 0);
Hal Canary1b3387b2016-12-12 13:48:12 -0500232 if (!fPixelRef) {
reed@google.combf790232013-12-13 19:45:58 +0000233 return;
234 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235 SkDEBUGCODE(this->validate();)
236}
237
reed84825042014-09-02 12:50:45 -0700238bool SkBitmap::tryAllocPixels(Allocator* allocator, SkColorTable* ctable) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 HeapAllocator stdalloc;
skia.committer@gmail.comd2ac07b2014-01-25 07:01:49 +0000240
halcanary96fcdcc2015-08-27 07:41:13 -0700241 if (nullptr == allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 allocator = &stdalloc;
243 }
244 return allocator->allocPixelRef(this, ctable);
245}
246
reed@google.com9ebcac52014-01-24 18:53:42 +0000247///////////////////////////////////////////////////////////////////////////////
248
reed84825042014-09-02 12:50:45 -0700249bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
reedbae704b2014-06-28 14:26:35 -0700250 if (kIndex_8_SkColorType == requestedInfo.colorType()) {
251 return reset_return_false(this);
252 }
reedf0aed972014-07-01 12:48:11 -0700253 if (!this->setInfo(requestedInfo, rowBytes)) {
reedbae704b2014-06-28 14:26:35 -0700254 return reset_return_false(this);
255 }
mtklein775b8192014-12-02 09:11:25 -0800256
reedbae704b2014-06-28 14:26:35 -0700257 // setInfo may have corrected info (e.g. 565 is always opaque).
258 const SkImageInfo& correctedInfo = this->info();
reedf0aed972014-07-01 12:48:11 -0700259 // setInfo may have computed a valid rowbytes if 0 were passed in
260 rowBytes = this->rowBytes();
261
Mike Reed6b3155c2017-04-03 14:41:44 -0400262 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo, rowBytes, nullptr);
Hal Canary1b3387b2016-12-12 13:48:12 -0500263 if (!pr) {
reedbae704b2014-06-28 14:26:35 -0700264 return reset_return_false(this);
265 }
Hal Canary1b3387b2016-12-12 13:48:12 -0500266 this->setPixelRef(std::move(pr), 0, 0);
halcanary96fcdcc2015-08-27 07:41:13 -0700267 if (nullptr == this->getPixels()) {
reedbae704b2014-06-28 14:26:35 -0700268 return reset_return_false(this);
269 }
Mike Reedb7120892017-04-14 17:16:36 -0400270 SkDEBUGCODE(this->validate();)
reedbae704b2014-06-28 14:26:35 -0700271 return true;
272}
273
Mike Reed6b3155c2017-04-03 14:41:44 -0400274bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, sk_sp<SkColorTable> ctable,
275 uint32_t allocFlags) {
halcanary96fcdcc2015-08-27 07:41:13 -0700276 if (kIndex_8_SkColorType == requestedInfo.colorType() && nullptr == ctable) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000277 return reset_return_false(this);
278 }
scroggo0187dc22014-06-05 11:18:04 -0700279 if (!this->setInfo(requestedInfo)) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000280 return reset_return_false(this);
281 }
282
scroggo0187dc22014-06-05 11:18:04 -0700283 // setInfo may have corrected info (e.g. 565 is always opaque).
284 const SkImageInfo& correctedInfo = this->info();
285
Mike Reed6b3155c2017-04-03 14:41:44 -0400286 sk_sp<SkPixelRef> pr = (allocFlags & kZeroPixels_AllocFlag) ?
287 SkMallocPixelRef::MakeZeroed(correctedInfo, correctedInfo.minRowBytes(), ctable) :
288 SkMallocPixelRef::MakeAllocate(correctedInfo, correctedInfo.minRowBytes(), ctable);
Hal Canary1b3387b2016-12-12 13:48:12 -0500289 if (!pr) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000290 return reset_return_false(this);
291 }
Hal Canary1b3387b2016-12-12 13:48:12 -0500292 this->setPixelRef(std::move(pr), 0, 0);
halcanary96fcdcc2015-08-27 07:41:13 -0700293 if (nullptr == this->getPixels()) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000294 return reset_return_false(this);
295 }
Mike Reedb7120892017-04-14 17:16:36 -0400296 SkDEBUGCODE(this->validate();)
reed@google.com9ebcac52014-01-24 18:53:42 +0000297 return true;
298}
299
reeddb74f622015-05-30 13:41:15 -0700300static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
301 if (proc) {
302 proc(pixels, ctx);
303 }
304}
305
scroggo0187dc22014-06-05 11:18:04 -0700306bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
307 SkColorTable* ct, void (*releaseProc)(void* addr, void* context),
308 void* context) {
309 if (!this->setInfo(requestedInfo, rb)) {
reeddb74f622015-05-30 13:41:15 -0700310 invoke_release_proc(releaseProc, pixels, context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000311 this->reset();
312 return false;
313 }
halcanary96fcdcc2015-08-27 07:41:13 -0700314 if (nullptr == pixels) {
reeddb74f622015-05-30 13:41:15 -0700315 invoke_release_proc(releaseProc, pixels, context);
316 return true; // we behaved as if they called setInfo()
317 }
reed@google.com9ebcac52014-01-24 18:53:42 +0000318
scroggo0187dc22014-06-05 11:18:04 -0700319 // setInfo may have corrected info (e.g. 565 is always opaque).
320 const SkImageInfo& correctedInfo = this->info();
321
Mike Reed6b3155c2017-04-03 14:41:44 -0400322 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithProc(correctedInfo, rb, sk_ref_sp(ct),
323 pixels, releaseProc, context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000324 if (!pr) {
325 this->reset();
326 return false;
327 }
328
Hal Canary1b3387b2016-12-12 13:48:12 -0500329 this->setPixelRef(std::move(pr), 0, 0);
mike@reedtribe.org6e58cf32014-02-16 20:54:21 +0000330 SkDEBUGCODE(this->validate();)
reed@google.com9ebcac52014-01-24 18:53:42 +0000331 return true;
332}
333
halcanarye36ec872015-12-09 11:36:59 -0800334bool SkBitmap::installPixels(const SkPixmap& pixmap) {
335 return this->installPixels(pixmap.info(), pixmap.writable_addr(),
336 pixmap.rowBytes(), pixmap.ctable(),
337 nullptr, nullptr);
338}
339
commit-bot@chromium.orgdac52252014-02-17 21:21:46 +0000340bool SkBitmap::installMaskPixels(const SkMask& mask) {
341 if (SkMask::kA8_Format != mask.fFormat) {
342 this->reset();
343 return false;
344 }
345 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
346 mask.fBounds.height()),
347 mask.fImage, mask.fRowBytes);
348}
349
reed@google.comeb9a46c2014-01-25 16:46:20 +0000350///////////////////////////////////////////////////////////////////////////////
351
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352void SkBitmap::freePixels() {
Mike Reedb7120892017-04-14 17:16:36 -0400353 fPixelRef = nullptr;
354 fPixelRefOrigin.setZero();
halcanary96fcdcc2015-08-27 07:41:13 -0700355 fPixels = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356}
357
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358uint32_t SkBitmap::getGenerationID() const {
Hal Canary1b3387b2016-12-12 13:48:12 -0500359 return fPixelRef ? fPixelRef->getGenerationID() : 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360}
361
362void SkBitmap::notifyPixelsChanged() const {
junov@chromium.orgb0521292011-12-15 20:14:06 +0000363 SkASSERT(!this->isImmutable());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 if (fPixelRef) {
365 fPixelRef->notifyPixelsChanged();
366 }
367}
368
369///////////////////////////////////////////////////////////////////////////////
370
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371/** We explicitly use the same allocator for our pixels that SkMask does,
372 so that we can freely assign memory allocated by one class to the other.
373 */
374bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
375 SkColorTable* ctable) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000376 const SkImageInfo info = dst->info();
377 if (kUnknown_SkColorType == info.colorType()) {
reed@google.combf790232013-12-13 19:45:58 +0000378// SkDebugf("unsupported config for info %d\n", dst->config());
379 return false;
380 }
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000381
Mike Reed6b3155c2017-04-03 14:41:44 -0400382 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes(), sk_ref_sp(ctable));
Hal Canary1b3387b2016-12-12 13:48:12 -0500383 if (!pr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384 return false;
385 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000386
Hal Canary1b3387b2016-12-12 13:48:12 -0500387 dst->setPixelRef(std::move(pr), 0, 0);
Mike Reedb7120892017-04-14 17:16:36 -0400388 SkDEBUGCODE(dst->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000389 return true;
390}
391
392///////////////////////////////////////////////////////////////////////////////
393
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000394bool SkBitmap::isImmutable() const {
scroggo08470592014-07-15 19:56:48 -0700395 return fPixelRef ? fPixelRef->isImmutable() : false;
junov@chromium.orgb0521292011-12-15 20:14:06 +0000396}
397
398void SkBitmap::setImmutable() {
399 if (fPixelRef) {
400 fPixelRef->setImmutable();
junov@chromium.orgb0521292011-12-15 20:14:06 +0000401 }
402}
403
junov@google.com4ee7ae52011-06-30 17:30:49 +0000404bool SkBitmap::isVolatile() const {
405 return (fFlags & kImageIsVolatile_Flag) != 0;
406}
407
408void SkBitmap::setIsVolatile(bool isVolatile) {
409 if (isVolatile) {
410 fFlags |= kImageIsVolatile_Flag;
411 } else {
412 fFlags &= ~kImageIsVolatile_Flag;
413 }
414}
415
reed@android.com8a1c16f2008-12-17 15:59:43 +0000416void* SkBitmap::getAddr(int x, int y) const {
417 SkASSERT((unsigned)x < (unsigned)this->width());
418 SkASSERT((unsigned)y < (unsigned)this->height());
419
420 char* base = (char*)this->getPixels();
421 if (base) {
422 base += y * this->rowBytes();
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000423 switch (this->colorType()) {
mtklein7fd93e32016-07-26 13:05:30 -0700424 case kRGBA_F16_SkColorType:
425 base += x << 3;
426 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000427 case kRGBA_8888_SkColorType:
428 case kBGRA_8888_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429 base += x << 2;
430 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000431 case kARGB_4444_SkColorType:
432 case kRGB_565_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433 base += x << 1;
434 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000435 case kAlpha_8_SkColorType:
436 case kIndex_8_SkColorType:
reed0c9b1a82015-03-17 17:44:06 -0700437 case kGray_8_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438 base += x;
439 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000441 SkDEBUGFAIL("Can't return addr for config");
halcanary96fcdcc2015-08-27 07:41:13 -0700442 base = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443 break;
444 }
445 }
446 return base;
447}
448
449///////////////////////////////////////////////////////////////////////////////
450///////////////////////////////////////////////////////////////////////////////
451
reed7aefe032015-06-08 10:22:22 -0700452void SkBitmap::erase(SkColor c, const SkIRect& area) const {
reed92fc2ae2015-05-22 08:06:21 -0700453 SkDEBUGCODE(this->validate();)
reed92fc2ae2015-05-22 08:06:21 -0700454
455 switch (fInfo.colorType()) {
456 case kUnknown_SkColorType:
457 case kIndex_8_SkColorType:
458 // TODO: can we ASSERT that we never get here?
459 return; // can't erase. Should we bzero so the memory is not uninitialized?
460 default:
461 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000462 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000463
Mike Reed4edb5d22017-04-17 11:02:51 -0400464 SkPixmap result;
465 if (!this->peekPixels(&result)) {
reed92fc2ae2015-05-22 08:06:21 -0700466 return;
467 }
468
Mike Reed4edb5d22017-04-17 11:02:51 -0400469 if (result.erase(c, area)) {
reed92fc2ae2015-05-22 08:06:21 -0700470 this->notifyPixelsChanged();
471 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000472}
473
reed7aefe032015-06-08 10:22:22 -0700474void SkBitmap::eraseColor(SkColor c) const {
475 this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
reed@google.com60d32352013-06-28 19:40:50 +0000476}
477
reed@android.com8a1c16f2008-12-17 15:59:43 +0000478//////////////////////////////////////////////////////////////////////////////////////
479//////////////////////////////////////////////////////////////////////////////////////
480
reed@android.com8a1c16f2008-12-17 15:59:43 +0000481bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
482 SkDEBUGCODE(this->validate();)
483
Hal Canary1b3387b2016-12-12 13:48:12 -0500484 if (nullptr == result || !fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000485 return false; // no src pixels
486 }
487
488 SkIRect srcRect, r;
489 srcRect.set(0, 0, this->width(), this->height());
490 if (!r.intersect(srcRect, subset)) {
491 return false; // r is empty (i.e. no intersection)
492 }
493
scroggo@google.coma2a31922012-12-07 19:14:45 +0000494 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
495 // exited above.
496 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
497 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
498
reed@android.com8a1c16f2008-12-17 15:59:43 +0000499 SkBitmap dst;
herbb5d74682016-04-21 08:45:39 -0700500 dst.setInfo(this->info().makeWH(r.width(), r.height()), this->rowBytes());
skyostil@google.com0eb75762012-01-16 10:45:53 +0000501 dst.setIsVolatile(this->isVolatile());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000502
503 if (fPixelRef) {
reed@google.com672588b2014-01-08 15:42:01 +0000504 SkIPoint origin = fPixelRefOrigin;
505 origin.fX += r.fLeft;
506 origin.fY += r.fTop;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000507 // share the pixelref with a custom offset
Hal Canary1b3387b2016-12-12 13:48:12 -0500508 dst.setPixelRef(fPixelRef, origin.x(), origin.y());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 }
510 SkDEBUGCODE(dst.validate();)
511
512 // we know we're good, so commit to result
513 result->swap(dst);
514 return true;
515}
516
517///////////////////////////////////////////////////////////////////////////////
518
Mike Reed22f34822016-11-28 17:17:38 -0500519bool SkBitmap::canCopyTo(SkColorType dstCT) const {
reedb184f7f2014-07-13 04:32:32 -0700520 const SkColorType srcCT = this->colorType();
521
522 if (srcCT == kUnknown_SkColorType) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523 return false;
524 }
Mike Reed22f34822016-11-28 17:17:38 -0500525 if (srcCT == kAlpha_8_SkColorType && dstCT != kAlpha_8_SkColorType) {
526 return false; // can't convert from alpha to non-alpha
527 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528
Mike Reed22f34822016-11-28 17:17:38 -0500529 bool sameConfigs = (srcCT == dstCT);
530 switch (dstCT) {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000531 case kAlpha_8_SkColorType:
532 case kRGB_565_SkColorType:
commit-bot@chromium.org60b5dce2014-04-22 20:24:33 +0000533 case kRGBA_8888_SkColorType:
534 case kBGRA_8888_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000535 break;
Matt Sarettcb6266b2017-01-17 10:48:53 -0500536 case kGray_8_SkColorType:
weita@google.comf9ab99a2009-05-03 18:23:30 +0000537 if (!sameConfigs) {
538 return false;
539 }
540 break;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000541 case kARGB_4444_SkColorType:
reedb184f7f2014-07-13 04:32:32 -0700542 return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000543 default:
544 return false;
545 }
reed@android.comfbaa88d2009-05-06 17:44:34 +0000546 return true;
547}
548
reedb184f7f2014-07-13 04:32:32 -0700549bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
550 int x, int y) const {
Mike Reed4edb5d22017-04-17 11:02:51 -0400551 SkPixmap src;
552 if (!this->peekPixels(&src)) {
reedb184f7f2014-07-13 04:32:32 -0700553 return false;
554 }
Mike Reed4edb5d22017-04-17 11:02:51 -0400555 return src.readPixels(requestedDstInfo, dstPixels, dstRB, x, y);
reedb184f7f2014-07-13 04:32:32 -0700556}
557
Mike Reed68dd8d02017-01-04 16:34:31 -0500558bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
559 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
560}
561
Matt Sarettd2adc662017-03-27 15:07:35 -0400562bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY,
563 SkTransferFunctionBehavior behavior) {
Matt Sarett03dd6d52017-01-23 12:15:09 -0500564 if (!SkImageInfoValidConversion(fInfo, src.info())) {
Mike Reed68dd8d02017-01-04 16:34:31 -0500565 return false;
566 }
567
Matt Sarett03dd6d52017-01-23 12:15:09 -0500568 SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY);
569 if (!rec.trim(fInfo.width(), fInfo.height())) {
570 return false;
571 }
572
573 void* dstPixels = this->getAddr(rec.fX, rec.fY);
574 const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
Matt Sarett485c4992017-02-14 14:18:27 -0500575 SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes,
Matt Sarettd2adc662017-03-27 15:07:35 -0400576 src.ctable(), behavior);
Matt Sarett8572d852017-02-14 11:21:02 -0500577 return true;
Mike Reed68dd8d02017-01-04 16:34:31 -0500578}
579
Matt Sarett68b8e3d2017-04-28 11:15:22 -0400580#ifdef SK_SUPPORT_LEGACY_BITMAP_COPYTO
581bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType) const {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000582 if (!this->canCopyTo(dstColorType)) {
reed@android.comfbaa88d2009-05-06 17:44:34 +0000583 return false;
584 }
585
Mike Reed4edb5d22017-04-17 11:02:51 -0400586 SkPixmap srcPM;
587 if (!this->peekPixels(&srcPM)) {
reed@google.com50dfa012011-04-01 19:05:36 +0000588 return false;
589 }
Matt Sarettd9836f42017-04-05 15:41:53 -0400590
Matt Sarett0122af02017-04-27 20:08:39 +0000591 SkBitmap tmpDst;
Matt Sarett68b8e3d2017-04-28 11:15:22 -0400592 SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType);
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000593 if (!tmpDst.setInfo(dstInfo)) {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000594 return false;
595 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000596
weita@google.comf9ab99a2009-05-03 18:23:30 +0000597 // allocate colortable if srcConfig == kIndex8_Config
Hal Canary704cd322016-11-07 14:13:52 -0500598 sk_sp<SkColorTable> ctable;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000599 if (dstColorType == kIndex_8_SkColorType) {
reed95d343f2015-05-23 13:21:06 -0700600 ctable.reset(SkRef(srcPM.ctable()));
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000601 }
Matt Sarett68b8e3d2017-04-28 11:15:22 -0400602 if (!tmpDst.tryAllocPixels(ctable.get())) {
weita@google.comf9ab99a2009-05-03 18:23:30 +0000603 return false;
604 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000605
Mike Reed4edb5d22017-04-17 11:02:51 -0400606 SkPixmap dstPM;
607 if (!tmpDst.peekPixels(&dstPM)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000608 return false;
609 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000610
Matt Sarettd9836f42017-04-05 15:41:53 -0400611 if (!srcPM.readPixels(dstPM)) {
reedb184f7f2014-07-13 04:32:32 -0700612 return false;
613 }
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000614
reed@google.com50dfa012011-04-01 19:05:36 +0000615 dst->swap(tmpDst);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000616 return true;
617}
Mike Reed42ce38f2017-04-06 14:03:25 -0400618#endif
619
reed@android.com8a1c16f2008-12-17 15:59:43 +0000620///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000621
reed92fc2ae2015-05-22 08:06:21 -0700622static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
halcanary96fcdcc2015-08-27 07:41:13 -0700623 SkASSERT(alpha != nullptr);
reed92fc2ae2015-05-22 08:06:21 -0700624 SkASSERT(alphaRowBytes >= src.width());
625
Mike Reed4edb5d22017-04-17 11:02:51 -0400626 SkPixmap pmap;
627 if (!src.peekPixels(&pmap)) {
lsalzmana2415ac2016-10-11 14:29:12 -0700628 for (int y = 0; y < src.height(); ++y) {
629 memset(alpha, 0, src.width());
630 alpha += alphaRowBytes;
631 }
reed92fc2ae2015-05-22 08:06:21 -0700632 return false;
633 }
Matt Sarett485c4992017-02-14 14:18:27 -0500634 SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
Matt Sarettd2adc662017-03-27 15:07:35 -0400635 pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable(),
636 SkTransferFunctionBehavior::kRespect);
reed@android.com1cdcb512009-08-24 19:11:00 +0000637 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638}
639
640#include "SkPaint.h"
641#include "SkMaskFilter.h"
642#include "SkMatrix.h"
643
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000644bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
djsollen@google.com57f49692011-02-23 20:46:31 +0000645 Allocator *allocator, SkIPoint* offset) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000646 SkDEBUGCODE(this->validate();)
647
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000648 SkBitmap tmpBitmap;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649 SkMatrix identity;
650 SkMask srcM, dstM;
651
652 srcM.fBounds.set(0, 0, this->width(), this->height());
653 srcM.fRowBytes = SkAlign4(this->width());
654 srcM.fFormat = SkMask::kA8_Format;
655
halcanary96fcdcc2015-08-27 07:41:13 -0700656 SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657
658 // compute our (larger?) dst bounds if we have a filter
bsalomon49f085d2014-09-05 13:34:00 -0700659 if (filter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000660 identity.reset();
halcanary96fcdcc2015-08-27 07:41:13 -0700661 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662 goto NO_FILTER_CASE;
663 }
664 dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
665 } else {
666 NO_FILTER_CASE:
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000667 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -0700668 if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000669 // Allocation of pixels for alpha bitmap failed.
670 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
671 tmpBitmap.width(), tmpBitmap.height());
672 return false;
673 }
674 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000675 if (offset) {
676 offset->set(0, 0);
677 }
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000678 tmpBitmap.swap(*dst);
679 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680 }
bungeman@google.com02f55842011-10-04 21:25:00 +0000681 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
682 SkAutoMaskFreeImage srcCleanup(srcM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000683
684 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -0700685 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000686 goto NO_FILTER_CASE;
687 }
bungeman@google.com02f55842011-10-04 21:25:00 +0000688 SkAutoMaskFreeImage dstCleanup(dstM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000689
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000690 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
691 dstM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -0700692 if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000693 // Allocation of pixels for alpha bitmap failed.
694 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
695 tmpBitmap.width(), tmpBitmap.height());
696 return false;
697 }
698 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699 if (offset) {
700 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
701 }
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000702 SkDEBUGCODE(tmpBitmap.validate();)
703
704 tmpBitmap.swap(*dst);
705 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000706}
707
708///////////////////////////////////////////////////////////////////////////////
709
reed92fc2ae2015-05-22 08:06:21 -0700710static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) {
711 const SkImageInfo& info = pmap.info();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000712 const size_t snugRB = info.width() * info.bytesPerPixel();
reed92fc2ae2015-05-22 08:06:21 -0700713 const char* src = (const char*)pmap.addr();
714 const size_t ramRB = pmap.rowBytes();
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +0000715
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000716 buffer->write32(SkToU32(snugRB));
717 info.flatten(*buffer);
718
719 const size_t size = snugRB * info.height();
scroggo565901d2015-12-10 10:44:13 -0800720 SkAutoTMalloc<char> storage(size);
721 char* dst = storage.get();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000722 for (int y = 0; y < info.height(); ++y) {
723 memcpy(dst, src, snugRB);
724 dst += snugRB;
725 src += ramRB;
726 }
727 buffer->writeByteArray(storage.get(), size);
728
reed92fc2ae2015-05-22 08:06:21 -0700729 const SkColorTable* ct = pmap.ctable();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000730 if (kIndex_8_SkColorType == info.colorType() && ct) {
731 buffer->writeBool(true);
732 ct->writeToBuffer(*buffer);
733 } else {
734 buffer->writeBool(false);
735 }
736}
737
reed92fc2ae2015-05-22 08:06:21 -0700738void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) {
739 const SkImageInfo info = bitmap.info();
Hal Canary1b3387b2016-12-12 13:48:12 -0500740 if (0 == info.width() || 0 == info.height() || bitmap.isNull()) {
reed92fc2ae2015-05-22 08:06:21 -0700741 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
742 return;
743 }
744
Mike Reed4edb5d22017-04-17 11:02:51 -0400745 SkPixmap result;
746 if (!bitmap.peekPixels(&result)) {
reed92fc2ae2015-05-22 08:06:21 -0700747 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
748 return;
749 }
750
Mike Reed4edb5d22017-04-17 11:02:51 -0400751 write_raw_pixels(buffer, result);
reed92fc2ae2015-05-22 08:06:21 -0700752}
753
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000754bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) {
755 const size_t snugRB = buffer->readUInt();
756 if (0 == snugRB) { // no pixels
757 return false;
758 }
759
760 SkImageInfo info;
761 info.unflatten(*buffer);
762
Robert Phillipsb2cb5352016-12-20 12:44:41 -0500763 if (info.width() < 0 || info.height() < 0) {
764 return false;
765 }
766
mtklein58e389b2016-07-15 07:00:11 -0700767 // If there was an error reading "info" or if it is bogus,
robertphillips74139f12016-06-28 09:04:34 -0700768 // don't use it to compute minRowBytes()
769 if (!buffer->validate(SkColorTypeValidateAlphaType(info.colorType(),
770 info.alphaType()))) {
sugoica95c192014-07-08 09:18:48 -0700771 return false;
772 }
773
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000774 const size_t ramRB = info.minRowBytes();
sugoibd0d9da2015-01-07 08:47:44 -0800775 const int height = SkMax32(info.height(), 0);
776 const uint64_t snugSize = sk_64_mul(snugRB, height);
777 const uint64_t ramSize = sk_64_mul(ramRB, height);
778 static const uint64_t max_size_t = (size_t)(-1);
779 if (!buffer->validate((snugSize <= ramSize) && (ramSize <= max_size_t))) {
commit-bot@chromium.org05858432014-05-30 01:06:44 +0000780 return false;
781 }
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000782
reedfde05112016-03-11 13:02:28 -0800783 sk_sp<SkData> data(SkData::MakeUninitialized(SkToSizeT(ramSize)));
robertphillips28937842015-06-08 07:10:49 -0700784 unsigned char* dst = (unsigned char*)data->writable_data();
sugoibd0d9da2015-01-07 08:47:44 -0800785 buffer->readByteArray(dst, SkToSizeT(snugSize));
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000786
787 if (snugSize != ramSize) {
robertphillips28937842015-06-08 07:10:49 -0700788 const unsigned char* srcRow = dst + snugRB * (height - 1);
789 unsigned char* dstRow = dst + ramRB * (height - 1);
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000790 for (int y = height - 1; y >= 1; --y) {
791 memmove(dstRow, srcRow, snugRB);
792 srcRow -= snugRB;
793 dstRow -= ramRB;
794 }
795 SkASSERT(srcRow == dstRow); // first row does not need to be moved
796 }
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +0000797
Hal Canary704cd322016-11-07 14:13:52 -0500798 sk_sp<SkColorTable> ctable;
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000799 if (buffer->readBool()) {
Mike Reed6b3155c2017-04-03 14:41:44 -0400800 ctable = SkColorTable::Create(*buffer);
reedb236d1a2015-08-28 10:14:18 -0700801 if (!ctable) {
802 return false;
803 }
robertphillips28937842015-06-08 07:10:49 -0700804
reedb236d1a2015-08-28 10:14:18 -0700805 if (info.isEmpty()) {
806 // require an empty ctable
807 if (ctable->count() != 0) {
808 buffer->validate(false);
809 return false;
810 }
811 } else {
812 // require a non-empty ctable
813 if (ctable->count() == 0) {
814 buffer->validate(false);
815 return false;
816 }
817 unsigned char maxIndex = ctable->count() - 1;
818 for (uint64_t i = 0; i < ramSize; ++i) {
819 dst[i] = SkTMin(dst[i], maxIndex);
820 }
robertphillips28937842015-06-08 07:10:49 -0700821 }
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000822 }
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +0000823
Mike Reed6b3155c2017-04-03 14:41:44 -0400824 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithData(info, info.minRowBytes(),
825 std::move(ctable), std::move(data));
826 if (!pr) {
sugoi6af31472015-01-28 13:15:32 -0800827 return false;
828 }
Matt Sarettf7583112017-05-01 10:22:31 -0400829 bitmap->setInfo(info);
Hal Canary1b3387b2016-12-12 13:48:12 -0500830 bitmap->setPixelRef(std::move(pr), 0, 0);
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000831 return true;
832}
833
reed@android.com8a1c16f2008-12-17 15:59:43 +0000834enum {
835 SERIALIZE_PIXELTYPE_NONE,
djsollen@google.com21830d92012-08-07 19:49:41 +0000836 SERIALIZE_PIXELTYPE_REF_DATA
reed@android.com8a1c16f2008-12-17 15:59:43 +0000837};
838
reed@android.com8a1c16f2008-12-17 15:59:43 +0000839///////////////////////////////////////////////////////////////////////////////
840
reed@android.com8a1c16f2008-12-17 15:59:43 +0000841#ifdef SK_DEBUG
842void SkBitmap::validate() const {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000843 fInfo.validate();
commit-bot@chromium.orgd5414e52014-02-13 22:30:38 +0000844
845 // ImageInfo may not require this, but Bitmap ensures that opaque-only
846 // colorTypes report opaque for their alphatype
847 if (kRGB_565_SkColorType == fInfo.colorType()) {
848 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
849 }
850
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000851 SkASSERT(fInfo.validRowBytes(fRowBytes));
scroggo08470592014-07-15 19:56:48 -0700852 uint8_t allFlags = kImageIsVolatile_Flag;
scroggo@google.com8e990eb2013-06-14 15:55:56 +0000853#ifdef SK_BUILD_FOR_ANDROID
854 allFlags |= kHasHardwareMipMap_Flag;
855#endif
scroggo08470592014-07-15 19:56:48 -0700856 SkASSERT((~allFlags & fFlags) == 0);
Mike Reedb7120892017-04-14 17:16:36 -0400857
858 if (fPixelRef && fPixelRef->pixels()) {
859 SkASSERT(fPixels);
860 } else {
861 SkASSERT(!fPixels);
862 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000863
reed@google.com615316c2014-01-15 19:15:23 +0000864 if (fPixels) {
865 SkASSERT(fPixelRef);
reed@google.com615316c2014-01-15 19:15:23 +0000866 SkASSERT(fPixelRef->rowBytes() == fRowBytes);
867 SkASSERT(fPixelRefOrigin.fX >= 0);
868 SkASSERT(fPixelRefOrigin.fY >= 0);
Matt Sarettf7583112017-05-01 10:22:31 -0400869 SkASSERT(fPixelRef->width() >= (int)this->width() + fPixelRefOrigin.fX);
870 SkASSERT(fPixelRef->height() >= (int)this->height() + fPixelRefOrigin.fY);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000871 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000872 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000873}
874#endif
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000875
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000876#ifndef SK_IGNORE_TO_STRING
bungemand3ebb482015-08-05 13:57:49 -0700877#include "SkString.h"
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000878void SkBitmap::toString(SkString* str) const {
879
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000880 static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = {
881 "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8",
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000882 };
883
884 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000885 gColorTypeNames[this->colorType()]);
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000886
887 str->append(" (");
888 if (this->isOpaque()) {
889 str->append("opaque");
890 } else {
891 str->append("transparent");
892 }
893 if (this->isImmutable()) {
894 str->append(", immutable");
895 } else {
896 str->append(", not-immutable");
897 }
898 str->append(")");
899
Mike Reed96d5b9a2017-04-12 22:29:00 -0400900 str->appendf(" pixelref:%p", this->pixelRef());
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000901 str->append(")");
902}
903#endif
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000904
905///////////////////////////////////////////////////////////////////////////////
906
reedcb674142015-06-05 06:58:22 -0700907bool SkBitmap::peekPixels(SkPixmap* pmap) const {
908 if (fPixels) {
909 if (pmap) {
Mike Reedb7120892017-04-14 17:16:36 -0400910 pmap->reset(fInfo, fPixels, fRowBytes, this->getColorTable());
reedcb674142015-06-05 06:58:22 -0700911 }
912 return true;
913 }
914 return false;
915}
916
reed92fc2ae2015-05-22 08:06:21 -0700917///////////////////////////////////////////////////////////////////////////////
918
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000919#ifdef SK_DEBUG
920void SkImageInfo::validate() const {
921 SkASSERT(fWidth >= 0);
922 SkASSERT(fHeight >= 0);
923 SkASSERT(SkColorTypeIsValid(fColorType));
924 SkASSERT(SkAlphaTypeIsValid(fAlphaType));
925}
926#endif