blob: 7cc7344d2f94432e03465cce78582aceed129e45 [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
mtklein1b249332015-07-07 12:21:21 -07008#include "SkAtomics.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkBitmap.h"
10#include "SkColorPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkData.h"
12#include "SkFilterQuality.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkMallocPixelRef.h"
14#include "SkMask.h"
bungemand3ebb482015-08-05 13:57:49 -070015#include "SkMath.h"
jvanverth02802f62015-07-02 06:42:49 -070016#include "SkPixelRef.h"
mtklein1b249332015-07-07 12:21:21 -070017#include "SkReadBuffer.h"
bungemand3ebb482015-08-05 13:57:49 -070018#include "SkRect.h"
19#include "SkScalar.h"
vandebo@chromium.org112706d2011-02-24 22:50:55 +000020#include "SkUnPreMultiply.h"
mtklein1b249332015-07-07 12:21:21 -070021#include "SkWriteBuffer.h"
bungemand3ebb482015-08-05 13:57:49 -070022
23#include <string.h>
reed@android.com8a1c16f2008-12-17 15:59:43 +000024
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +000025static bool reset_return_false(SkBitmap* bm) {
26 bm->reset();
27 return false;
28}
29
reed@android.com8a1c16f2008-12-17 15:59:43 +000030SkBitmap::SkBitmap() {
reed@android.com4516f472009-06-29 16:25:36 +000031 sk_bzero(this, sizeof(*this));
reed@android.com8a1c16f2008-12-17 15:59:43 +000032}
33
34SkBitmap::SkBitmap(const SkBitmap& src) {
35 SkDEBUGCODE(src.validate();)
reed@android.com4516f472009-06-29 16:25:36 +000036 sk_bzero(this, sizeof(*this));
reed@android.com8a1c16f2008-12-17 15:59:43 +000037 *this = src;
38 SkDEBUGCODE(this->validate();)
39}
40
41SkBitmap::~SkBitmap() {
42 SkDEBUGCODE(this->validate();)
43 this->freePixels();
44}
45
46SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
47 if (this != &src) {
48 this->freePixels();
49 memcpy(this, &src, sizeof(src));
50
51 // inc src reference counts
reed@android.com83f7bc32009-07-17 02:42:41 +000052 SkSafeRef(src.fPixelRef);
reed@android.com8a1c16f2008-12-17 15:59:43 +000053
54 // we reset our locks if we get blown away
55 fPixelLockCount = 0;
weita@google.comf9ab99a2009-05-03 18:23:30 +000056
reed@google.com5f62ed72014-01-15 19:59:45 +000057 if (fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000058 // ignore the values from the memcpy
halcanary96fcdcc2015-08-27 07:41:13 -070059 fPixels = nullptr;
60 fColorTable = nullptr;
bsalomon@google.com586f48c2011-04-14 15:07:22 +000061 // Note that what to for genID is somewhat arbitrary. We have no
62 // way to track changes to raw pixels across multiple SkBitmaps.
63 // Would benefit from an SkRawPixelRef type created by
64 // setPixels.
65 // Just leave the memcpy'ed one but they'll get out of sync
66 // as soon either is modified.
reed@android.com8a1c16f2008-12-17 15:59:43 +000067 }
68 }
69
70 SkDEBUGCODE(this->validate();)
71 return *this;
72}
73
74void SkBitmap::swap(SkBitmap& other) {
bsalomon@google.com586f48c2011-04-14 15:07:22 +000075 SkTSwap(fColorTable, other.fColorTable);
76 SkTSwap(fPixelRef, other.fPixelRef);
reed@google.com672588b2014-01-08 15:42:01 +000077 SkTSwap(fPixelRefOrigin, other.fPixelRefOrigin);
bsalomon@google.com586f48c2011-04-14 15:07:22 +000078 SkTSwap(fPixelLockCount, other.fPixelLockCount);
bsalomon@google.com586f48c2011-04-14 15:07:22 +000079 SkTSwap(fPixels, other.fPixels);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +000080 SkTSwap(fInfo, other.fInfo);
bsalomon@google.com586f48c2011-04-14 15:07:22 +000081 SkTSwap(fRowBytes, other.fRowBytes);
bsalomon@google.com586f48c2011-04-14 15:07:22 +000082 SkTSwap(fFlags, other.fFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +000083
84 SkDEBUGCODE(this->validate();)
85}
86
87void SkBitmap::reset() {
88 this->freePixels();
reed@android.com4516f472009-06-29 16:25:36 +000089 sk_bzero(this, sizeof(*this));
reed@android.com8a1c16f2008-12-17 15:59:43 +000090}
91
reed@google.com86b2e432012-03-15 21:17:03 +000092void SkBitmap::getBounds(SkRect* bounds) const {
93 SkASSERT(bounds);
94 bounds->set(0, 0,
reede5ea5002014-09-03 11:54:58 -070095 SkIntToScalar(fInfo.width()), SkIntToScalar(fInfo.height()));
reed@google.com86b2e432012-03-15 21:17:03 +000096}
97
reed@google.com80e14592012-03-16 14:58:07 +000098void SkBitmap::getBounds(SkIRect* bounds) const {
99 SkASSERT(bounds);
reede5ea5002014-09-03 11:54:58 -0700100 bounds->set(0, 0, fInfo.width(), fInfo.height());
reed@google.com80e14592012-03-16 14:58:07 +0000101}
102
reed@google.com86b2e432012-03-15 21:17:03 +0000103///////////////////////////////////////////////////////////////////////////////
104
reede5ea5002014-09-03 11:54:58 -0700105bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) {
106 SkAlphaType newAT = info.alphaType();
107 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) {
commit-bot@chromium.orgd5414e52014-02-13 22:30:38 +0000108 return reset_return_false(this);
109 }
reede5ea5002014-09-03 11:54:58 -0700110 // don't look at info.alphaType(), since newAT is the real value...
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000111
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000112 // require that rowBytes fit in 31bits
113 int64_t mrb = info.minRowBytes64();
114 if ((int32_t)mrb != mrb) {
115 return reset_return_false(this);
reed@google.com383a6972013-10-21 14:00:07 +0000116 }
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000117 if ((int64_t)rowBytes != (int32_t)rowBytes) {
118 return reset_return_false(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119 }
reed@android.com89bb83a2009-05-29 21:30:42 +0000120
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000121 if (info.width() < 0 || info.height() < 0) {
122 return reset_return_false(this);
123 }
124
125 if (kUnknown_SkColorType == info.colorType()) {
126 rowBytes = 0;
127 } else if (0 == rowBytes) {
128 rowBytes = (size_t)mrb;
reedf0aed972014-07-01 12:48:11 -0700129 } else if (!info.validRowBytes(rowBytes)) {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000130 return reset_return_false(this);
reed@google.com383a6972013-10-21 14:00:07 +0000131 }
132
133 this->freePixels();
134
reede5ea5002014-09-03 11:54:58 -0700135 fInfo = info.makeAlphaType(newAT);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000136 fRowBytes = SkToU32(rowBytes);
reed@google.com383a6972013-10-21 14:00:07 +0000137 return true;
reed@google.com383a6972013-10-21 14:00:07 +0000138}
139
reede5ea5002014-09-03 11:54:58 -0700140bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) {
141 if (!SkColorTypeValidateAlphaType(fInfo.colorType(), newAlphaType, &newAlphaType)) {
reed@google.com383a6972013-10-21 14:00:07 +0000142 return false;
143 }
reede5ea5002014-09-03 11:54:58 -0700144 if (fInfo.alphaType() != newAlphaType) {
145 fInfo = fInfo.makeAlphaType(newAlphaType);
commit-bot@chromium.org0e8d0d62014-01-27 15:41:07 +0000146 if (fPixelRef) {
reede5ea5002014-09-03 11:54:58 -0700147 fPixelRef->changeAlphaType(newAlphaType);
commit-bot@chromium.org0e8d0d62014-01-27 15:41:07 +0000148 }
149 }
reed@google.com383a6972013-10-21 14:00:07 +0000150 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151}
152
153void SkBitmap::updatePixelsFromRef() const {
bsalomon49f085d2014-09-05 13:34:00 -0700154 if (fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155 if (fPixelLockCount > 0) {
reed@google.comff0da4f2012-05-17 13:14:52 +0000156 SkASSERT(fPixelRef->isLocked());
weita@google.comf9ab99a2009-05-03 18:23:30 +0000157
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158 void* p = fPixelRef->pixels();
bsalomon49f085d2014-09-05 13:34:00 -0700159 if (p) {
reed@google.com672588b2014-01-08 15:42:01 +0000160 p = (char*)p
reed@google.com303c4752014-01-09 20:00:14 +0000161 + fPixelRefOrigin.fY * fRowBytes
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000162 + fPixelRefOrigin.fX * fInfo.bytesPerPixel();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163 }
164 fPixels = p;
reed@google.com5f62ed72014-01-15 19:59:45 +0000165 fColorTable = fPixelRef->colorTable();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 } else {
167 SkASSERT(0 == fPixelLockCount);
halcanary96fcdcc2015-08-27 07:41:13 -0700168 fPixels = nullptr;
169 fColorTable = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170 }
171 }
172}
173
reed@google.com672588b2014-01-08 15:42:01 +0000174SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) {
reed@google.comdcea5302014-01-03 13:43:01 +0000175#ifdef SK_DEBUG
reed@google.com672588b2014-01-08 15:42:01 +0000176 if (pr) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000177 if (kUnknown_SkColorType != fInfo.colorType()) {
reed@google.comdcea5302014-01-03 13:43:01 +0000178 const SkImageInfo& prInfo = pr->info();
reede5ea5002014-09-03 11:54:58 -0700179 SkASSERT(fInfo.width() <= prInfo.width());
180 SkASSERT(fInfo.height() <= prInfo.height());
181 SkASSERT(fInfo.colorType() == prInfo.colorType());
182 switch (prInfo.alphaType()) {
reed44977482015-02-27 10:23:00 -0800183 case kUnknown_SkAlphaType:
184 SkASSERT(fInfo.alphaType() == kUnknown_SkAlphaType);
reed@google.comdcea5302014-01-03 13:43:01 +0000185 break;
186 case kOpaque_SkAlphaType:
187 case kPremul_SkAlphaType:
reede5ea5002014-09-03 11:54:58 -0700188 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
189 fInfo.alphaType() == kPremul_SkAlphaType);
reed@google.comdcea5302014-01-03 13:43:01 +0000190 break;
191 case kUnpremul_SkAlphaType:
reede5ea5002014-09-03 11:54:58 -0700192 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
193 fInfo.alphaType() == kUnpremul_SkAlphaType);
reed@google.comdcea5302014-01-03 13:43:01 +0000194 break;
195 }
196 }
197 }
198#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199
reed@google.com672588b2014-01-08 15:42:01 +0000200 if (pr) {
201 const SkImageInfo& info = pr->info();
reede5ea5002014-09-03 11:54:58 -0700202 fPixelRefOrigin.set(SkPin32(dx, 0, info.width()), SkPin32(dy, 0, info.height()));
reed@google.com672588b2014-01-08 15:42:01 +0000203 } else {
204 // ignore dx,dy if there is no pixelref
205 fPixelRefOrigin.setZero();
206 }
207
208 if (fPixelRef != pr) {
piotaixr0eb02a62014-06-16 11:50:49 -0700209 this->freePixels();
halcanary96fcdcc2015-08-27 07:41:13 -0700210 SkASSERT(nullptr == fPixelRef);
weita@google.comf9ab99a2009-05-03 18:23:30 +0000211
piotaixr0eb02a62014-06-16 11:50:49 -0700212 SkSafeRef(pr);
213 fPixelRef = pr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214 this->updatePixelsFromRef();
215 }
216
217 SkDEBUGCODE(this->validate();)
218 return pr;
219}
220
221void SkBitmap::lockPixels() const {
bsalomon49f085d2014-09-05 13:34:00 -0700222 if (fPixelRef && 0 == sk_atomic_inc(&fPixelLockCount)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 fPixelRef->lockPixels();
224 this->updatePixelsFromRef();
225 }
226 SkDEBUGCODE(this->validate();)
227}
228
229void SkBitmap::unlockPixels() const {
halcanary96fcdcc2015-08-27 07:41:13 -0700230 SkASSERT(nullptr == fPixelRef || fPixelLockCount > 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231
bsalomon49f085d2014-09-05 13:34:00 -0700232 if (fPixelRef && 1 == sk_atomic_dec(&fPixelLockCount)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 fPixelRef->unlockPixels();
234 this->updatePixelsFromRef();
235 }
236 SkDEBUGCODE(this->validate();)
237}
238
reed@google.com9c49bc32011-07-07 13:42:37 +0000239bool SkBitmap::lockPixelsAreWritable() const {
djsollen@google.comc84b8332012-07-27 13:41:44 +0000240 return (fPixelRef) ? fPixelRef->lockPixelsAreWritable() : false;
reed@google.com9c49bc32011-07-07 13:42:37 +0000241}
242
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700244 if (nullptr == p) {
245 this->setPixelRef(nullptr);
reed@google.com8e1034e2012-07-30 13:16:35 +0000246 return;
247 }
248
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000249 if (kUnknown_SkColorType == fInfo.colorType()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700250 this->setPixelRef(nullptr);
reed@google.combf790232013-12-13 19:45:58 +0000251 return;
252 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000254 SkPixelRef* pr = SkMallocPixelRef::NewDirect(fInfo, p, fRowBytes, ctable);
halcanary96fcdcc2015-08-27 07:41:13 -0700255 if (nullptr == pr) {
256 this->setPixelRef(nullptr);
reed@google.combf790232013-12-13 19:45:58 +0000257 return;
258 }
259
260 this->setPixelRef(pr)->unref();
261
djsollen@google.comc84b8332012-07-27 13:41:44 +0000262 // since we're already allocated, we lockPixels right away
263 this->lockPixels();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264 SkDEBUGCODE(this->validate();)
265}
266
reed84825042014-09-02 12:50:45 -0700267bool SkBitmap::tryAllocPixels(Allocator* allocator, SkColorTable* ctable) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 HeapAllocator stdalloc;
skia.committer@gmail.comd2ac07b2014-01-25 07:01:49 +0000269
halcanary96fcdcc2015-08-27 07:41:13 -0700270 if (nullptr == allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 allocator = &stdalloc;
272 }
273 return allocator->allocPixelRef(this, ctable);
274}
275
reed@google.com9ebcac52014-01-24 18:53:42 +0000276///////////////////////////////////////////////////////////////////////////////
277
reed84825042014-09-02 12:50:45 -0700278bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
reedbae704b2014-06-28 14:26:35 -0700279 if (kIndex_8_SkColorType == requestedInfo.colorType()) {
280 return reset_return_false(this);
281 }
reedf0aed972014-07-01 12:48:11 -0700282 if (!this->setInfo(requestedInfo, rowBytes)) {
reedbae704b2014-06-28 14:26:35 -0700283 return reset_return_false(this);
284 }
mtklein775b8192014-12-02 09:11:25 -0800285
reedbae704b2014-06-28 14:26:35 -0700286 // setInfo may have corrected info (e.g. 565 is always opaque).
287 const SkImageInfo& correctedInfo = this->info();
reedf0aed972014-07-01 12:48:11 -0700288 // setInfo may have computed a valid rowbytes if 0 were passed in
289 rowBytes = this->rowBytes();
290
reedbae704b2014-06-28 14:26:35 -0700291 SkMallocPixelRef::PRFactory defaultFactory;
mtklein775b8192014-12-02 09:11:25 -0800292
halcanary96fcdcc2015-08-27 07:41:13 -0700293 SkPixelRef* pr = defaultFactory.create(correctedInfo, rowBytes, nullptr);
294 if (nullptr == pr) {
reedbae704b2014-06-28 14:26:35 -0700295 return reset_return_false(this);
296 }
297 this->setPixelRef(pr)->unref();
mtklein775b8192014-12-02 09:11:25 -0800298
halcanary96fcdcc2015-08-27 07:41:13 -0700299 // TODO: lockPixels could/should return bool or void*/nullptr
reedbae704b2014-06-28 14:26:35 -0700300 this->lockPixels();
halcanary96fcdcc2015-08-27 07:41:13 -0700301 if (nullptr == this->getPixels()) {
reedbae704b2014-06-28 14:26:35 -0700302 return reset_return_false(this);
303 }
304 return true;
305}
306
reed84825042014-09-02 12:50:45 -0700307bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, SkPixelRefFactory* factory,
308 SkColorTable* ctable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700309 if (kIndex_8_SkColorType == requestedInfo.colorType() && nullptr == ctable) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000310 return reset_return_false(this);
311 }
scroggo0187dc22014-06-05 11:18:04 -0700312 if (!this->setInfo(requestedInfo)) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000313 return reset_return_false(this);
314 }
315
scroggo0187dc22014-06-05 11:18:04 -0700316 // setInfo may have corrected info (e.g. 565 is always opaque).
317 const SkImageInfo& correctedInfo = this->info();
318
reed@google.com9ebcac52014-01-24 18:53:42 +0000319 SkMallocPixelRef::PRFactory defaultFactory;
halcanary96fcdcc2015-08-27 07:41:13 -0700320 if (nullptr == factory) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000321 factory = &defaultFactory;
322 }
skia.committer@gmail.comd2ac07b2014-01-25 07:01:49 +0000323
reedf0aed972014-07-01 12:48:11 -0700324 SkPixelRef* pr = factory->create(correctedInfo, correctedInfo.minRowBytes(), ctable);
halcanary96fcdcc2015-08-27 07:41:13 -0700325 if (nullptr == pr) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000326 return reset_return_false(this);
327 }
328 this->setPixelRef(pr)->unref();
329
halcanary96fcdcc2015-08-27 07:41:13 -0700330 // TODO: lockPixels could/should return bool or void*/nullptr
reed@google.com9ebcac52014-01-24 18:53:42 +0000331 this->lockPixels();
halcanary96fcdcc2015-08-27 07:41:13 -0700332 if (nullptr == this->getPixels()) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000333 return reset_return_false(this);
334 }
335 return true;
336}
337
reeddb74f622015-05-30 13:41:15 -0700338static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
339 if (proc) {
340 proc(pixels, ctx);
341 }
342}
343
scroggo0187dc22014-06-05 11:18:04 -0700344bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
345 SkColorTable* ct, void (*releaseProc)(void* addr, void* context),
346 void* context) {
347 if (!this->setInfo(requestedInfo, rb)) {
reeddb74f622015-05-30 13:41:15 -0700348 invoke_release_proc(releaseProc, pixels, context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000349 this->reset();
350 return false;
351 }
halcanary96fcdcc2015-08-27 07:41:13 -0700352 if (nullptr == pixels) {
reeddb74f622015-05-30 13:41:15 -0700353 invoke_release_proc(releaseProc, pixels, context);
354 return true; // we behaved as if they called setInfo()
355 }
reed@google.com9ebcac52014-01-24 18:53:42 +0000356
scroggo0187dc22014-06-05 11:18:04 -0700357 // setInfo may have corrected info (e.g. 565 is always opaque).
358 const SkImageInfo& correctedInfo = this->info();
359
360 SkPixelRef* pr = SkMallocPixelRef::NewWithProc(correctedInfo, rb, ct, pixels, releaseProc,
361 context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000362 if (!pr) {
363 this->reset();
364 return false;
365 }
366
367 this->setPixelRef(pr)->unref();
mike@reedtribe.org6e58cf32014-02-16 20:54:21 +0000368
369 // since we're already allocated, we lockPixels right away
370 this->lockPixels();
mike@reedtribe.org6e58cf32014-02-16 20:54:21 +0000371 SkDEBUGCODE(this->validate();)
reed@google.com9ebcac52014-01-24 18:53:42 +0000372 return true;
373}
374
commit-bot@chromium.orgdac52252014-02-17 21:21:46 +0000375bool SkBitmap::installMaskPixels(const SkMask& mask) {
376 if (SkMask::kA8_Format != mask.fFormat) {
377 this->reset();
378 return false;
379 }
380 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
381 mask.fBounds.height()),
382 mask.fImage, mask.fRowBytes);
383}
384
reed@google.comeb9a46c2014-01-25 16:46:20 +0000385///////////////////////////////////////////////////////////////////////////////
386
reed@android.com8a1c16f2008-12-17 15:59:43 +0000387void SkBitmap::freePixels() {
bsalomon49f085d2014-09-05 13:34:00 -0700388 if (fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000389 if (fPixelLockCount > 0) {
390 fPixelRef->unlockPixels();
391 }
392 fPixelRef->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700393 fPixelRef = nullptr;
reed@google.com672588b2014-01-08 15:42:01 +0000394 fPixelRefOrigin.setZero();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000395 }
396 fPixelLockCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700397 fPixels = nullptr;
398 fColorTable = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000399}
400
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401uint32_t SkBitmap::getGenerationID() const {
djsollen@google.comc84b8332012-07-27 13:41:44 +0000402 return (fPixelRef) ? fPixelRef->getGenerationID() : 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403}
404
405void SkBitmap::notifyPixelsChanged() const {
junov@chromium.orgb0521292011-12-15 20:14:06 +0000406 SkASSERT(!this->isImmutable());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000407 if (fPixelRef) {
408 fPixelRef->notifyPixelsChanged();
409 }
410}
411
commit-bot@chromium.orgb8d00db2013-06-26 19:18:23 +0000412GrTexture* SkBitmap::getTexture() const {
halcanary96fcdcc2015-08-27 07:41:13 -0700413 return fPixelRef ? fPixelRef->getTexture() : nullptr;
reed@android.comce4e53a2010-09-09 16:01:26 +0000414}
415
reed@android.com8a1c16f2008-12-17 15:59:43 +0000416///////////////////////////////////////////////////////////////////////////////
417
reed@android.com8a1c16f2008-12-17 15:59:43 +0000418/** We explicitly use the same allocator for our pixels that SkMask does,
419 so that we can freely assign memory allocated by one class to the other.
420 */
421bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
422 SkColorTable* ctable) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000423 const SkImageInfo info = dst->info();
424 if (kUnknown_SkColorType == info.colorType()) {
reed@google.combf790232013-12-13 19:45:58 +0000425// SkDebugf("unsupported config for info %d\n", dst->config());
426 return false;
427 }
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000428
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000429 SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, dst->rowBytes(), ctable);
halcanary96fcdcc2015-08-27 07:41:13 -0700430 if (nullptr == pr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000431 return false;
432 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000433
reed@google.com672588b2014-01-08 15:42:01 +0000434 dst->setPixelRef(pr)->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435 // since we're already allocated, we lockPixels right away
436 dst->lockPixels();
437 return true;
438}
439
440///////////////////////////////////////////////////////////////////////////////
441
reed92fc2ae2015-05-22 08:06:21 -0700442static bool copy_pixels_to(const SkPixmap& src, void* const dst, size_t dstSize,
443 size_t dstRowBytes, bool preserveDstPad) {
444 const SkImageInfo& info = src.info();
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000445
scroggo@google.com0ba4bf42013-02-25 16:02:36 +0000446 if (0 == dstRowBytes) {
reed92fc2ae2015-05-22 08:06:21 -0700447 dstRowBytes = src.rowBytes();
scroggo@google.com0ba4bf42013-02-25 16:02:36 +0000448 }
reed92fc2ae2015-05-22 08:06:21 -0700449 if (dstRowBytes < info.minRowBytes()) {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000450 return false;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000451 }
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000452
reed92fc2ae2015-05-22 08:06:21 -0700453 if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == src.rowBytes()) {
454 size_t safeSize = src.getSafeSize();
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000455 if (safeSize > dstSize || safeSize == 0)
456 return false;
457 else {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000458 // This implementation will write bytes beyond the end of each row,
459 // excluding the last row, if the bitmap's stride is greater than
460 // strictly required by the current config.
reed92fc2ae2015-05-22 08:06:21 -0700461 memcpy(dst, src.addr(), safeSize);
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000462 return true;
463 }
464 } else {
465 // If destination has different stride than us, then copy line by line.
reed92fc2ae2015-05-22 08:06:21 -0700466 if (info.getSafeSize(dstRowBytes) > dstSize) {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000467 return false;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000468 } else {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000469 // Just copy what we need on each line.
reed92fc2ae2015-05-22 08:06:21 -0700470 size_t rowBytes = info.minRowBytes();
471 const uint8_t* srcP = reinterpret_cast<const uint8_t*>(src.addr());
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000472 uint8_t* dstP = reinterpret_cast<uint8_t*>(dst);
reed92fc2ae2015-05-22 08:06:21 -0700473 for (int row = 0; row < info.height(); ++row) {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000474 memcpy(dstP, srcP, rowBytes);
reed92fc2ae2015-05-22 08:06:21 -0700475 srcP += src.rowBytes();
476 dstP += dstRowBytes;
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000477 }
478
479 return true;
480 }
481 }
482}
483
reed92fc2ae2015-05-22 08:06:21 -0700484bool SkBitmap::copyPixelsTo(void* dst, size_t dstSize, size_t dstRB, bool preserveDstPad) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700485 if (nullptr == dst) {
reed92fc2ae2015-05-22 08:06:21 -0700486 return false;
487 }
488 SkAutoPixmapUnlock result;
489 if (!this->requestLock(&result)) {
490 return false;
491 }
492 return copy_pixels_to(result.pixmap(), dst, dstSize, dstRB, preserveDstPad);
493}
494
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000495///////////////////////////////////////////////////////////////////////////////
496
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000497bool SkBitmap::isImmutable() const {
scroggo08470592014-07-15 19:56:48 -0700498 return fPixelRef ? fPixelRef->isImmutable() : false;
junov@chromium.orgb0521292011-12-15 20:14:06 +0000499}
500
501void SkBitmap::setImmutable() {
502 if (fPixelRef) {
503 fPixelRef->setImmutable();
junov@chromium.orgb0521292011-12-15 20:14:06 +0000504 }
505}
506
junov@google.com4ee7ae52011-06-30 17:30:49 +0000507bool SkBitmap::isVolatile() const {
508 return (fFlags & kImageIsVolatile_Flag) != 0;
509}
510
511void SkBitmap::setIsVolatile(bool isVolatile) {
512 if (isVolatile) {
513 fFlags |= kImageIsVolatile_Flag;
514 } else {
515 fFlags &= ~kImageIsVolatile_Flag;
516 }
517}
518
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519void* SkBitmap::getAddr(int x, int y) const {
520 SkASSERT((unsigned)x < (unsigned)this->width());
521 SkASSERT((unsigned)y < (unsigned)this->height());
522
523 char* base = (char*)this->getPixels();
524 if (base) {
525 base += y * this->rowBytes();
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000526 switch (this->colorType()) {
527 case kRGBA_8888_SkColorType:
528 case kBGRA_8888_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000529 base += x << 2;
530 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000531 case kARGB_4444_SkColorType:
532 case kRGB_565_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000533 base += x << 1;
534 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000535 case kAlpha_8_SkColorType:
536 case kIndex_8_SkColorType:
reed0c9b1a82015-03-17 17:44:06 -0700537 case kGray_8_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000538 base += x;
539 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000541 SkDEBUGFAIL("Can't return addr for config");
halcanary96fcdcc2015-08-27 07:41:13 -0700542 base = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000543 break;
544 }
545 }
546 return base;
547}
548
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000549SkColor SkBitmap::getColor(int x, int y) const {
550 SkASSERT((unsigned)x < (unsigned)this->width());
551 SkASSERT((unsigned)y < (unsigned)this->height());
552
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000553 switch (this->colorType()) {
reed0c9b1a82015-03-17 17:44:06 -0700554 case kGray_8_SkColorType: {
555 uint8_t* addr = this->getAddr8(x, y);
556 return SkColorSetRGB(*addr, *addr, *addr);
557 }
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000558 case kAlpha_8_SkColorType: {
reed@google.com3b521d02011-04-29 11:53:41 +0000559 uint8_t* addr = this->getAddr8(x, y);
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000560 return SkColorSetA(0, addr[0]);
561 }
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000562 case kIndex_8_SkColorType: {
reed@google.com3b521d02011-04-29 11:53:41 +0000563 SkPMColor c = this->getIndex8Color(x, y);
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000564 return SkUnPreMultiply::PMColorToColor(c);
565 }
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000566 case kRGB_565_SkColorType: {
reed@google.com3b521d02011-04-29 11:53:41 +0000567 uint16_t* addr = this->getAddr16(x, y);
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000568 return SkPixel16ToColor(addr[0]);
569 }
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000570 case kARGB_4444_SkColorType: {
reed@google.com3b521d02011-04-29 11:53:41 +0000571 uint16_t* addr = this->getAddr16(x, y);
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000572 SkPMColor c = SkPixel4444ToPixel32(addr[0]);
573 return SkUnPreMultiply::PMColorToColor(c);
574 }
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000575 case kBGRA_8888_SkColorType:
576 case kRGBA_8888_SkColorType: {
reed@google.com3b521d02011-04-29 11:53:41 +0000577 uint32_t* addr = this->getAddr32(x, y);
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000578 return SkUnPreMultiply::PMColorToColor(addr[0]);
579 }
rmistry@google.comd6bab022013-12-02 13:50:38 +0000580 default:
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000581 SkASSERT(false);
582 return 0;
583 }
584 SkASSERT(false); // Not reached.
585 return 0;
586}
587
reed92fc2ae2015-05-22 08:06:21 -0700588static bool compute_is_opaque(const SkPixmap& pmap) {
589 const int height = pmap.height();
590 const int width = pmap.width();
reed@google.com2a7579d2012-11-07 18:30:18 +0000591
reed92fc2ae2015-05-22 08:06:21 -0700592 switch (pmap.colorType()) {
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000593 case kAlpha_8_SkColorType: {
reed@google.com2a7579d2012-11-07 18:30:18 +0000594 unsigned a = 0xFF;
595 for (int y = 0; y < height; ++y) {
reed92fc2ae2015-05-22 08:06:21 -0700596 const uint8_t* row = pmap.addr8(0, y);
reed@google.com2a7579d2012-11-07 18:30:18 +0000597 for (int x = 0; x < width; ++x) {
598 a &= row[x];
599 }
600 if (0xFF != a) {
601 return false;
602 }
603 }
604 return true;
605 } break;
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000606 case kIndex_8_SkColorType: {
reed92fc2ae2015-05-22 08:06:21 -0700607 const SkColorTable* ctable = pmap.ctable();
halcanary96fcdcc2015-08-27 07:41:13 -0700608 if (nullptr == ctable) {
reed@google.com2a7579d2012-11-07 18:30:18 +0000609 return false;
610 }
reed92fc2ae2015-05-22 08:06:21 -0700611 const SkPMColor* table = ctable->readColors();
reed@google.com140d7282013-01-07 20:25:04 +0000612 SkPMColor c = (SkPMColor)~0;
reed92fc2ae2015-05-22 08:06:21 -0700613 for (int i = ctable->count() - 1; i >= 0; --i) {
reed@google.com2a7579d2012-11-07 18:30:18 +0000614 c &= table[i];
615 }
616 return 0xFF == SkGetPackedA32(c);
617 } break;
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000618 case kRGB_565_SkColorType:
reed0c9b1a82015-03-17 17:44:06 -0700619 case kGray_8_SkColorType:
reed@google.com2a7579d2012-11-07 18:30:18 +0000620 return true;
621 break;
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000622 case kARGB_4444_SkColorType: {
reed@google.com2a7579d2012-11-07 18:30:18 +0000623 unsigned c = 0xFFFF;
624 for (int y = 0; y < height; ++y) {
reed92fc2ae2015-05-22 08:06:21 -0700625 const SkPMColor16* row = pmap.addr16(0, y);
reed@google.com2a7579d2012-11-07 18:30:18 +0000626 for (int x = 0; x < width; ++x) {
627 c &= row[x];
628 }
629 if (0xF != SkGetPackedA4444(c)) {
630 return false;
631 }
632 }
633 return true;
634 } break;
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000635 case kBGRA_8888_SkColorType:
636 case kRGBA_8888_SkColorType: {
reed@google.com140d7282013-01-07 20:25:04 +0000637 SkPMColor c = (SkPMColor)~0;
reed@google.com2a7579d2012-11-07 18:30:18 +0000638 for (int y = 0; y < height; ++y) {
reed92fc2ae2015-05-22 08:06:21 -0700639 const SkPMColor* row = pmap.addr32(0, y);
reed@google.com2a7579d2012-11-07 18:30:18 +0000640 for (int x = 0; x < width; ++x) {
641 c &= row[x];
642 }
643 if (0xFF != SkGetPackedA32(c)) {
644 return false;
645 }
646 }
647 return true;
648 }
649 default:
650 break;
651 }
652 return false;
653}
654
reed92fc2ae2015-05-22 08:06:21 -0700655bool SkBitmap::ComputeIsOpaque(const SkBitmap& bm) {
656 SkAutoPixmapUnlock result;
657 if (!bm.requestLock(&result)) {
658 return false;
659 }
660 return compute_is_opaque(result.pixmap());
661}
662
reed@google.com2a7579d2012-11-07 18:30:18 +0000663
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664///////////////////////////////////////////////////////////////////////////////
665///////////////////////////////////////////////////////////////////////////////
666
reed7aefe032015-06-08 10:22:22 -0700667void SkBitmap::erase(SkColor c, const SkIRect& area) const {
reed92fc2ae2015-05-22 08:06:21 -0700668 SkDEBUGCODE(this->validate();)
reed92fc2ae2015-05-22 08:06:21 -0700669
670 switch (fInfo.colorType()) {
671 case kUnknown_SkColorType:
672 case kIndex_8_SkColorType:
673 // TODO: can we ASSERT that we never get here?
674 return; // can't erase. Should we bzero so the memory is not uninitialized?
675 default:
676 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000678
reed92fc2ae2015-05-22 08:06:21 -0700679 SkAutoPixmapUnlock result;
680 if (!this->requestLock(&result)) {
681 return;
682 }
683
reed7aefe032015-06-08 10:22:22 -0700684 if (result.pixmap().erase(c, area)) {
reed92fc2ae2015-05-22 08:06:21 -0700685 this->notifyPixelsChanged();
686 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687}
688
reed7aefe032015-06-08 10:22:22 -0700689void SkBitmap::eraseColor(SkColor c) const {
690 this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
reed@google.com60d32352013-06-28 19:40:50 +0000691}
692
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693//////////////////////////////////////////////////////////////////////////////////////
694//////////////////////////////////////////////////////////////////////////////////////
695
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
697 SkDEBUGCODE(this->validate();)
698
halcanary96fcdcc2015-08-27 07:41:13 -0700699 if (nullptr == result || nullptr == fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000700 return false; // no src pixels
701 }
702
703 SkIRect srcRect, r;
704 srcRect.set(0, 0, this->width(), this->height());
705 if (!r.intersect(srcRect, subset)) {
706 return false; // r is empty (i.e. no intersection)
707 }
708
halcanary96fcdcc2015-08-27 07:41:13 -0700709 if (fPixelRef->getTexture() != nullptr) {
scroggo@google.coma2a31922012-12-07 19:14:45 +0000710 // Do a deep copy
jvanverthfa1e8a72014-12-22 08:31:49 -0800711 SkPixelRef* pixelRef = fPixelRef->deepCopy(this->colorType(), this->profileType(), &subset);
halcanary96fcdcc2015-08-27 07:41:13 -0700712 if (pixelRef != nullptr) {
scroggo@google.coma2a31922012-12-07 19:14:45 +0000713 SkBitmap dst;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000714 dst.setInfo(SkImageInfo::Make(subset.width(), subset.height(),
715 this->colorType(), this->alphaType()));
scroggo@google.coma2a31922012-12-07 19:14:45 +0000716 dst.setIsVolatile(this->isVolatile());
scroggo@google.coma2a31922012-12-07 19:14:45 +0000717 dst.setPixelRef(pixelRef)->unref();
718 SkDEBUGCODE(dst.validate());
719 result->swap(dst);
720 return true;
721 }
722 }
723
scroggo@google.coma2a31922012-12-07 19:14:45 +0000724 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
725 // exited above.
726 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
727 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
728
reed@android.com8a1c16f2008-12-17 15:59:43 +0000729 SkBitmap dst;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000730 dst.setInfo(SkImageInfo::Make(r.width(), r.height(), this->colorType(), this->alphaType()),
731 this->rowBytes());
skyostil@google.com0eb75762012-01-16 10:45:53 +0000732 dst.setIsVolatile(this->isVolatile());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000733
734 if (fPixelRef) {
reed@google.com672588b2014-01-08 15:42:01 +0000735 SkIPoint origin = fPixelRefOrigin;
736 origin.fX += r.fLeft;
737 origin.fY += r.fTop;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738 // share the pixelref with a custom offset
reed@google.com672588b2014-01-08 15:42:01 +0000739 dst.setPixelRef(fPixelRef, origin);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740 }
741 SkDEBUGCODE(dst.validate();)
742
743 // we know we're good, so commit to result
744 result->swap(dst);
745 return true;
746}
747
748///////////////////////////////////////////////////////////////////////////////
749
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000750bool SkBitmap::canCopyTo(SkColorType dstColorType) const {
reedb184f7f2014-07-13 04:32:32 -0700751 const SkColorType srcCT = this->colorType();
752
753 if (srcCT == kUnknown_SkColorType) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754 return false;
755 }
756
reedb184f7f2014-07-13 04:32:32 -0700757 bool sameConfigs = (srcCT == dstColorType);
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000758 switch (dstColorType) {
759 case kAlpha_8_SkColorType:
760 case kRGB_565_SkColorType:
commit-bot@chromium.org60b5dce2014-04-22 20:24:33 +0000761 case kRGBA_8888_SkColorType:
762 case kBGRA_8888_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000763 break;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000764 case kIndex_8_SkColorType:
weita@google.comf9ab99a2009-05-03 18:23:30 +0000765 if (!sameConfigs) {
766 return false;
767 }
768 break;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000769 case kARGB_4444_SkColorType:
reedb184f7f2014-07-13 04:32:32 -0700770 return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT;
reed0c9b1a82015-03-17 17:44:06 -0700771 case kGray_8_SkColorType:
772 switch (srcCT) {
773 case kGray_8_SkColorType:
774 case kRGBA_8888_SkColorType:
775 case kBGRA_8888_SkColorType:
776 return true;
777 default:
778 break;
779 }
780 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000781 default:
782 return false;
783 }
reed@android.comfbaa88d2009-05-06 17:44:34 +0000784 return true;
785}
786
reedb184f7f2014-07-13 04:32:32 -0700787bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
788 int x, int y) const {
reed95d343f2015-05-23 13:21:06 -0700789 SkAutoPixmapUnlock src;
790 if (!this->requestLock(&src)) {
reedb184f7f2014-07-13 04:32:32 -0700791 return false;
792 }
reed95d343f2015-05-23 13:21:06 -0700793 return src.pixmap().readPixels(requestedDstInfo, dstPixels, dstRB, x, y);
reedb184f7f2014-07-13 04:32:32 -0700794}
795
796bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000797 if (!this->canCopyTo(dstColorType)) {
reed@android.comfbaa88d2009-05-06 17:44:34 +0000798 return false;
799 }
800
reed@google.com50dfa012011-04-01 19:05:36 +0000801 // if we have a texture, first get those pixels
802 SkBitmap tmpSrc;
803 const SkBitmap* src = this;
804
scroggo@google.coma2a31922012-12-07 19:14:45 +0000805 if (fPixelRef) {
806 SkIRect subset;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000807 subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY,
808 fInfo.width(), fInfo.height());
reed@google.com672588b2014-01-08 15:42:01 +0000809 if (fPixelRef->readPixels(&tmpSrc, &subset)) {
scroggo0187dc22014-06-05 11:18:04 -0700810 if (fPixelRef->info().alphaType() == kUnpremul_SkAlphaType) {
811 // FIXME: The only meaningful implementation of readPixels
812 // (GrPixelRef) assumes premultiplied pixels.
813 return false;
814 }
reed@google.com672588b2014-01-08 15:42:01 +0000815 SkASSERT(tmpSrc.width() == this->width());
816 SkASSERT(tmpSrc.height() == this->height());
reed@google.com50dfa012011-04-01 19:05:36 +0000817
reed@google.com672588b2014-01-08 15:42:01 +0000818 // did we get lucky and we can just return tmpSrc?
halcanary96fcdcc2015-08-27 07:41:13 -0700819 if (tmpSrc.colorType() == dstColorType && nullptr == alloc) {
reed@google.com672588b2014-01-08 15:42:01 +0000820 dst->swap(tmpSrc);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000821 // If the result is an exact copy, clone the gen ID.
822 if (dst->pixelRef() && dst->pixelRef()->info() == fPixelRef->info()) {
reed@google.com672588b2014-01-08 15:42:01 +0000823 dst->pixelRef()->cloneGenID(*fPixelRef);
scroggo@google.coma2a31922012-12-07 19:14:45 +0000824 }
reed@google.com672588b2014-01-08 15:42:01 +0000825 return true;
scroggo@google.comd5764e82012-08-22 15:00:05 +0000826 }
reed@google.com672588b2014-01-08 15:42:01 +0000827
828 // fall through to the raster case
829 src = &tmpSrc;
reed@google.com50dfa012011-04-01 19:05:36 +0000830 }
reed@android.comfbaa88d2009-05-06 17:44:34 +0000831 }
reed@android.com311c82d2009-05-05 23:13:23 +0000832
reed95d343f2015-05-23 13:21:06 -0700833 SkAutoPixmapUnlock srcUnlocker;
834 if (!src->requestLock(&srcUnlocker)) {
reed@google.com50dfa012011-04-01 19:05:36 +0000835 return false;
836 }
reed95d343f2015-05-23 13:21:06 -0700837 const SkPixmap& srcPM = srcUnlocker.pixmap();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000838
reed95d343f2015-05-23 13:21:06 -0700839 const SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType);
reed@google.com50dfa012011-04-01 19:05:36 +0000840 SkBitmap tmpDst;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000841 if (!tmpDst.setInfo(dstInfo)) {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000842 return false;
843 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000844
weita@google.comf9ab99a2009-05-03 18:23:30 +0000845 // allocate colortable if srcConfig == kIndex8_Config
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000846 SkAutoTUnref<SkColorTable> ctable;
847 if (dstColorType == kIndex_8_SkColorType) {
reed95d343f2015-05-23 13:21:06 -0700848 ctable.reset(SkRef(srcPM.ctable()));
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000849 }
reed84825042014-09-02 12:50:45 -0700850 if (!tmpDst.tryAllocPixels(alloc, ctable)) {
weita@google.comf9ab99a2009-05-03 18:23:30 +0000851 return false;
852 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000853
reed95d343f2015-05-23 13:21:06 -0700854 SkAutoPixmapUnlock dstUnlocker;
855 if (!tmpDst.requestLock(&dstUnlocker)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000856 return false;
857 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000858
reed95d343f2015-05-23 13:21:06 -0700859 if (!srcPM.readPixels(dstUnlocker.pixmap())) {
reedb184f7f2014-07-13 04:32:32 -0700860 return false;
861 }
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000862
reedb184f7f2014-07-13 04:32:32 -0700863 // (for BitmapHeap) Clone the pixelref genID even though we have a new pixelref.
864 // The old copyTo impl did this, so we continue it for now.
865 //
866 // TODO: should we ignore rowbytes (i.e. getSize)? Then it could just be
867 // if (src_pixelref->info == dst_pixelref->info)
868 //
reed95d343f2015-05-23 13:21:06 -0700869 if (srcPM.colorType() == dstColorType && tmpDst.getSize() == srcPM.getSize64()) {
reedb184f7f2014-07-13 04:32:32 -0700870 SkPixelRef* dstPixelRef = tmpDst.pixelRef();
871 if (dstPixelRef->info() == fPixelRef->info()) {
872 dstPixelRef->cloneGenID(*fPixelRef);
reed@android.com311c82d2009-05-05 23:13:23 +0000873 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874 }
875
reed@google.com50dfa012011-04-01 19:05:36 +0000876 dst->swap(tmpDst);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000877 return true;
878}
879
commit-bot@chromium.orgfab349c2014-03-05 02:34:58 +0000880bool SkBitmap::deepCopyTo(SkBitmap* dst) const {
reede4538f52014-06-11 06:09:50 -0700881 const SkColorType dstCT = this->colorType();
jvanverthfa1e8a72014-12-22 08:31:49 -0800882 const SkColorProfileType dstPT = this->profileType();
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000883
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000884 if (!this->canCopyTo(dstCT)) {
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000885 return false;
886 }
887
888 // If we have a PixelRef, and it supports deep copy, use it.
889 // Currently supported only by texture-backed bitmaps.
890 if (fPixelRef) {
halcanary96fcdcc2015-08-27 07:41:13 -0700891 SkPixelRef* pixelRef = fPixelRef->deepCopy(dstCT, dstPT, nullptr);
commit-bot@chromium.orgeeef0cc2014-05-21 15:58:00 +0000892 if (pixelRef) {
893 uint32_t rowBytes;
jvanverthfa1e8a72014-12-22 08:31:49 -0800894 if (this->colorType() == dstCT && this->profileType() == dstPT) {
commit-bot@chromium.orgeeef0cc2014-05-21 15:58:00 +0000895 // Since there is no subset to pass to deepCopy, and deepCopy
896 // succeeded, the new pixel ref must be identical.
897 SkASSERT(fPixelRef->info() == pixelRef->info());
898 pixelRef->cloneGenID(*fPixelRef);
899 // Use the same rowBytes as the original.
900 rowBytes = fRowBytes;
901 } else {
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000902 // With the new config, an appropriate fRowBytes will be computed by setInfo.
commit-bot@chromium.orgeeef0cc2014-05-21 15:58:00 +0000903 rowBytes = 0;
904 }
905
reede5ea5002014-09-03 11:54:58 -0700906 const SkImageInfo info = fInfo.makeColorType(dstCT);
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000907 if (!dst->setInfo(info, rowBytes)) {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000908 return false;
909 }
commit-bot@chromium.orgeeef0cc2014-05-21 15:58:00 +0000910 dst->setPixelRef(pixelRef, fPixelRefOrigin)->unref();
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000911 return true;
912 }
913 }
914
915 if (this->getTexture()) {
916 return false;
917 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700918 return this->copyTo(dst, dstCT, nullptr);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000919 }
920}
921
reed@android.com8a1c16f2008-12-17 15:59:43 +0000922///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000923
reed92fc2ae2015-05-22 08:06:21 -0700924static void rect_memset(uint8_t* array, U8CPU value, SkISize size, size_t rowBytes) {
925 for (int y = 0; y < size.height(); ++y) {
926 memset(array, value, size.width());
927 array += rowBytes;
reed@android.com1cdcb512009-08-24 19:11:00 +0000928 }
reed92fc2ae2015-05-22 08:06:21 -0700929}
reed@google.com82065d62011-02-07 15:30:46 +0000930
reed92fc2ae2015-05-22 08:06:21 -0700931static void get_bitmap_alpha(const SkPixmap& pmap, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
932 SkColorType colorType = pmap.colorType();
933 int w = pmap.width();
934 int h = pmap.height();
935 size_t rb = pmap.rowBytes();
936
937 if (kAlpha_8_SkColorType == colorType && !pmap.isOpaque()) {
938 const uint8_t* s = pmap.addr8(0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000939 while (--h >= 0) {
940 memcpy(alpha, s, w);
941 s += rb;
942 alpha += alphaRowBytes;
943 }
reed92fc2ae2015-05-22 08:06:21 -0700944 } else if (kN32_SkColorType == colorType && !pmap.isOpaque()) {
945 const SkPMColor* SK_RESTRICT s = pmap.addr32(0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000946 while (--h >= 0) {
947 for (int x = 0; x < w; x++) {
948 alpha[x] = SkGetPackedA32(s[x]);
949 }
950 s = (const SkPMColor*)((const char*)s + rb);
951 alpha += alphaRowBytes;
952 }
reed92fc2ae2015-05-22 08:06:21 -0700953 } else if (kARGB_4444_SkColorType == colorType && !pmap.isOpaque()) {
954 const SkPMColor16* SK_RESTRICT s = pmap.addr16(0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955 while (--h >= 0) {
956 for (int x = 0; x < w; x++) {
957 alpha[x] = SkPacked4444ToA32(s[x]);
958 }
959 s = (const SkPMColor16*)((const char*)s + rb);
960 alpha += alphaRowBytes;
961 }
reed92fc2ae2015-05-22 08:06:21 -0700962 } else if (kIndex_8_SkColorType == colorType && !pmap.isOpaque()) {
963 const SkColorTable* ct = pmap.ctable();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 if (ct) {
mtklein775b8192014-12-02 09:11:25 -0800965 const SkPMColor* SK_RESTRICT table = ct->readColors();
reed92fc2ae2015-05-22 08:06:21 -0700966 const uint8_t* SK_RESTRICT s = pmap.addr8(0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967 while (--h >= 0) {
968 for (int x = 0; x < w; x++) {
969 alpha[x] = SkGetPackedA32(table[s[x]]);
970 }
971 s += rb;
972 alpha += alphaRowBytes;
973 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 }
975 } else { // src is opaque, so just fill alpha[] with 0xFF
reed92fc2ae2015-05-22 08:06:21 -0700976 rect_memset(alpha, 0xFF, pmap.info().dimensions(), alphaRowBytes);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977 }
reed92fc2ae2015-05-22 08:06:21 -0700978}
979
980static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
halcanary96fcdcc2015-08-27 07:41:13 -0700981 SkASSERT(alpha != nullptr);
reed92fc2ae2015-05-22 08:06:21 -0700982 SkASSERT(alphaRowBytes >= src.width());
983
984 SkAutoPixmapUnlock apl;
985 if (!src.requestLock(&apl)) {
986 rect_memset(alpha, 0, src.info().dimensions(), alphaRowBytes);
987 return false;
988 }
989 get_bitmap_alpha(apl.pixmap(), alpha, alphaRowBytes);
reed@android.com1cdcb512009-08-24 19:11:00 +0000990 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000991}
992
993#include "SkPaint.h"
994#include "SkMaskFilter.h"
995#include "SkMatrix.h"
996
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000997bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
djsollen@google.com57f49692011-02-23 20:46:31 +0000998 Allocator *allocator, SkIPoint* offset) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000999 SkDEBUGCODE(this->validate();)
1000
djsollen@google.comcd9d69b2011-03-14 20:30:14 +00001001 SkBitmap tmpBitmap;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001002 SkMatrix identity;
1003 SkMask srcM, dstM;
1004
1005 srcM.fBounds.set(0, 0, this->width(), this->height());
1006 srcM.fRowBytes = SkAlign4(this->width());
1007 srcM.fFormat = SkMask::kA8_Format;
1008
halcanary96fcdcc2015-08-27 07:41:13 -07001009 SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001010
1011 // compute our (larger?) dst bounds if we have a filter
bsalomon49f085d2014-09-05 13:34:00 -07001012 if (filter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001013 identity.reset();
halcanary96fcdcc2015-08-27 07:41:13 -07001014 srcM.fImage = nullptr;
1015 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001016 goto NO_FILTER_CASE;
1017 }
1018 dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
1019 } else {
1020 NO_FILTER_CASE:
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +00001021 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -07001022 if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +00001023 // Allocation of pixels for alpha bitmap failed.
1024 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
1025 tmpBitmap.width(), tmpBitmap.height());
1026 return false;
1027 }
1028 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029 if (offset) {
1030 offset->set(0, 0);
1031 }
djsollen@google.comcd9d69b2011-03-14 20:30:14 +00001032 tmpBitmap.swap(*dst);
1033 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001034 }
bungeman@google.com02f55842011-10-04 21:25:00 +00001035 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
1036 SkAutoMaskFreeImage srcCleanup(srcM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037
1038 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -07001039 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001040 goto NO_FILTER_CASE;
1041 }
bungeman@google.com02f55842011-10-04 21:25:00 +00001042 SkAutoMaskFreeImage dstCleanup(dstM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001043
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +00001044 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
1045 dstM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -07001046 if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +00001047 // Allocation of pixels for alpha bitmap failed.
1048 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
1049 tmpBitmap.width(), tmpBitmap.height());
1050 return false;
1051 }
1052 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001053 if (offset) {
1054 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
1055 }
djsollen@google.comcd9d69b2011-03-14 20:30:14 +00001056 SkDEBUGCODE(tmpBitmap.validate();)
1057
1058 tmpBitmap.swap(*dst);
1059 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001060}
1061
1062///////////////////////////////////////////////////////////////////////////////
1063
reed92fc2ae2015-05-22 08:06:21 -07001064static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) {
1065 const SkImageInfo& info = pmap.info();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001066 const size_t snugRB = info.width() * info.bytesPerPixel();
reed92fc2ae2015-05-22 08:06:21 -07001067 const char* src = (const char*)pmap.addr();
1068 const size_t ramRB = pmap.rowBytes();
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +00001069
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001070 buffer->write32(SkToU32(snugRB));
1071 info.flatten(*buffer);
1072
1073 const size_t size = snugRB * info.height();
1074 SkAutoMalloc storage(size);
1075 char* dst = (char*)storage.get();
1076 for (int y = 0; y < info.height(); ++y) {
1077 memcpy(dst, src, snugRB);
1078 dst += snugRB;
1079 src += ramRB;
1080 }
1081 buffer->writeByteArray(storage.get(), size);
1082
reed92fc2ae2015-05-22 08:06:21 -07001083 const SkColorTable* ct = pmap.ctable();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001084 if (kIndex_8_SkColorType == info.colorType() && ct) {
1085 buffer->writeBool(true);
1086 ct->writeToBuffer(*buffer);
1087 } else {
1088 buffer->writeBool(false);
1089 }
1090}
1091
reed92fc2ae2015-05-22 08:06:21 -07001092void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) {
1093 const SkImageInfo info = bitmap.info();
halcanary96fcdcc2015-08-27 07:41:13 -07001094 if (0 == info.width() || 0 == info.height() || nullptr == bitmap.pixelRef()) {
reed92fc2ae2015-05-22 08:06:21 -07001095 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
1096 return;
1097 }
1098
1099 SkAutoPixmapUnlock result;
1100 if (!bitmap.requestLock(&result)) {
1101 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
1102 return;
1103 }
1104
1105 write_raw_pixels(buffer, result.pixmap());
1106}
1107
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001108bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) {
1109 const size_t snugRB = buffer->readUInt();
1110 if (0 == snugRB) { // no pixels
1111 return false;
1112 }
1113
1114 SkImageInfo info;
1115 info.unflatten(*buffer);
1116
sugoica95c192014-07-08 09:18:48 -07001117 // If there was an error reading "info", don't use it to compute minRowBytes()
1118 if (!buffer->validate(true)) {
1119 return false;
1120 }
1121
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001122 const size_t ramRB = info.minRowBytes();
sugoibd0d9da2015-01-07 08:47:44 -08001123 const int height = SkMax32(info.height(), 0);
1124 const uint64_t snugSize = sk_64_mul(snugRB, height);
1125 const uint64_t ramSize = sk_64_mul(ramRB, height);
1126 static const uint64_t max_size_t = (size_t)(-1);
1127 if (!buffer->validate((snugSize <= ramSize) && (ramSize <= max_size_t))) {
commit-bot@chromium.org05858432014-05-30 01:06:44 +00001128 return false;
1129 }
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001130
sugoibd0d9da2015-01-07 08:47:44 -08001131 SkAutoDataUnref data(SkData::NewUninitialized(SkToSizeT(ramSize)));
robertphillips28937842015-06-08 07:10:49 -07001132 unsigned char* dst = (unsigned char*)data->writable_data();
sugoibd0d9da2015-01-07 08:47:44 -08001133 buffer->readByteArray(dst, SkToSizeT(snugSize));
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001134
1135 if (snugSize != ramSize) {
robertphillips28937842015-06-08 07:10:49 -07001136 const unsigned char* srcRow = dst + snugRB * (height - 1);
1137 unsigned char* dstRow = dst + ramRB * (height - 1);
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001138 for (int y = height - 1; y >= 1; --y) {
1139 memmove(dstRow, srcRow, snugRB);
1140 srcRow -= snugRB;
1141 dstRow -= ramRB;
1142 }
1143 SkASSERT(srcRow == dstRow); // first row does not need to be moved
1144 }
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +00001145
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001146 SkAutoTUnref<SkColorTable> ctable;
1147 if (buffer->readBool()) {
halcanary385fe4d2015-08-26 13:07:48 -07001148 ctable.reset(new SkColorTable(*buffer));
robertphillips28937842015-06-08 07:10:49 -07001149
1150 unsigned char maxIndex = ctable->count() ? ctable->count()-1 : 0;
1151 for (uint64_t i = 0; i < ramSize; ++i) {
1152 dst[i] = SkTMin(dst[i], maxIndex);
1153 }
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001154 }
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +00001155
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001156 SkAutoTUnref<SkPixelRef> pr(SkMallocPixelRef::NewWithData(info, info.minRowBytes(),
1157 ctable.get(), data.get()));
sugoi6af31472015-01-28 13:15:32 -08001158 if (!pr.get()) {
1159 return false;
1160 }
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +00001161 bitmap->setInfo(pr->info());
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001162 bitmap->setPixelRef(pr, 0, 0);
1163 return true;
1164}
1165
reed@android.com8a1c16f2008-12-17 15:59:43 +00001166enum {
1167 SERIALIZE_PIXELTYPE_NONE,
djsollen@google.com21830d92012-08-07 19:49:41 +00001168 SERIALIZE_PIXELTYPE_REF_DATA
reed@android.com8a1c16f2008-12-17 15:59:43 +00001169};
1170
reed@android.com8a1c16f2008-12-17 15:59:43 +00001171///////////////////////////////////////////////////////////////////////////////
1172
1173SkBitmap::RLEPixels::RLEPixels(int width, int height) {
1174 fHeight = height;
commit-bot@chromium.org235002f2013-10-09 18:39:59 +00001175 fYPtrs = (uint8_t**)sk_calloc_throw(height * sizeof(uint8_t*));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001176}
1177
1178SkBitmap::RLEPixels::~RLEPixels() {
1179 sk_free(fYPtrs);
1180}
1181
1182///////////////////////////////////////////////////////////////////////////////
1183
1184#ifdef SK_DEBUG
1185void SkBitmap::validate() const {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001186 fInfo.validate();
commit-bot@chromium.orgd5414e52014-02-13 22:30:38 +00001187
1188 // ImageInfo may not require this, but Bitmap ensures that opaque-only
1189 // colorTypes report opaque for their alphatype
1190 if (kRGB_565_SkColorType == fInfo.colorType()) {
1191 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
1192 }
1193
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001194 SkASSERT(fInfo.validRowBytes(fRowBytes));
scroggo08470592014-07-15 19:56:48 -07001195 uint8_t allFlags = kImageIsVolatile_Flag;
scroggo@google.com8e990eb2013-06-14 15:55:56 +00001196#ifdef SK_BUILD_FOR_ANDROID
1197 allFlags |= kHasHardwareMipMap_Flag;
1198#endif
scroggo08470592014-07-15 19:56:48 -07001199 SkASSERT((~allFlags & fFlags) == 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200 SkASSERT(fPixelLockCount >= 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201
reed@google.com615316c2014-01-15 19:15:23 +00001202 if (fPixels) {
1203 SkASSERT(fPixelRef);
robertphillipse77dadd2014-11-21 05:50:21 -08001204 SkASSERT(fPixelLockCount > 0);
reed@google.com615316c2014-01-15 19:15:23 +00001205 SkASSERT(fPixelRef->isLocked());
1206 SkASSERT(fPixelRef->rowBytes() == fRowBytes);
1207 SkASSERT(fPixelRefOrigin.fX >= 0);
1208 SkASSERT(fPixelRefOrigin.fY >= 0);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001209 SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX);
reede5ea5002014-09-03 11:54:58 -07001210 SkASSERT(fPixelRef->info().height() >= (int)this->height() + fPixelRefOrigin.fY);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001211 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
reed@google.com615316c2014-01-15 19:15:23 +00001212 } else {
halcanary96fcdcc2015-08-27 07:41:13 -07001213 SkASSERT(nullptr == fColorTable);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001214 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001215}
1216#endif
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001217
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001218#ifndef SK_IGNORE_TO_STRING
bungemand3ebb482015-08-05 13:57:49 -07001219#include "SkString.h"
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001220void SkBitmap::toString(SkString* str) const {
1221
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +00001222 static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = {
1223 "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8",
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001224 };
1225
1226 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +00001227 gColorTypeNames[this->colorType()]);
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001228
1229 str->append(" (");
1230 if (this->isOpaque()) {
1231 str->append("opaque");
1232 } else {
1233 str->append("transparent");
1234 }
1235 if (this->isImmutable()) {
1236 str->append(", immutable");
1237 } else {
1238 str->append(", not-immutable");
1239 }
1240 str->append(")");
1241
1242 SkPixelRef* pr = this->pixelRef();
halcanary96fcdcc2015-08-27 07:41:13 -07001243 if (nullptr == pr) {
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001244 // show null or the explicit pixel address (rare)
1245 str->appendf(" pixels:%p", this->getPixels());
1246 } else {
1247 const char* uri = pr->getURI();
bsalomon49f085d2014-09-05 13:34:00 -07001248 if (uri) {
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001249 str->appendf(" uri:\"%s\"", uri);
1250 } else {
1251 str->appendf(" pixelref:%p", pr);
1252 }
1253 }
1254
1255 str->append(")");
1256}
1257#endif
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001258
1259///////////////////////////////////////////////////////////////////////////////
1260
reed92fc2ae2015-05-22 08:06:21 -07001261bool SkBitmap::requestLock(SkAutoPixmapUnlock* result) const {
1262 SkASSERT(result);
1263
1264 SkPixelRef* pr = fPixelRef;
halcanary96fcdcc2015-08-27 07:41:13 -07001265 if (nullptr == pr) {
reed92fc2ae2015-05-22 08:06:21 -07001266 return false;
1267 }
1268
reed871872f2015-06-22 12:48:26 -07001269 // We have to lock the whole thing (using the pixelref's dimensions) until the api supports
1270 // a partial lock (with offset/origin). Hence we can't use our fInfo.
1271 SkPixelRef::LockRequest req = { pr->info().dimensions(), kNone_SkFilterQuality };
reed92fc2ae2015-05-22 08:06:21 -07001272 SkPixelRef::LockResult res;
1273 if (pr->requestLock(req, &res)) {
reede8006572015-05-28 14:06:06 -07001274 SkASSERT(res.fPixels);
reed92fc2ae2015-05-22 08:06:21 -07001275 // The bitmap may be a subset of the pixelref's dimensions
1276 SkASSERT(fPixelRefOrigin.x() + fInfo.width() <= res.fSize.width());
1277 SkASSERT(fPixelRefOrigin.y() + fInfo.height() <= res.fSize.height());
1278 const void* addr = (const char*)res.fPixels + SkColorTypeComputeOffset(fInfo.colorType(),
1279 fPixelRefOrigin.x(),
1280 fPixelRefOrigin.y(),
1281 res.fRowBytes);
1282
1283 result->reset(SkPixmap(this->info(), addr, res.fRowBytes, res.fCTable),
1284 res.fUnlockProc, res.fUnlockContext);
1285 return true;
1286 }
1287 return false;
1288}
1289
reedcb674142015-06-05 06:58:22 -07001290bool SkBitmap::peekPixels(SkPixmap* pmap) const {
1291 if (fPixels) {
1292 if (pmap) {
1293 pmap->reset(fInfo, fPixels, fRowBytes, fColorTable);
1294 }
1295 return true;
1296 }
1297 return false;
1298}
1299
reed92fc2ae2015-05-22 08:06:21 -07001300///////////////////////////////////////////////////////////////////////////////
1301
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001302#ifdef SK_DEBUG
1303void SkImageInfo::validate() const {
1304 SkASSERT(fWidth >= 0);
1305 SkASSERT(fHeight >= 0);
1306 SkASSERT(SkColorTypeIsValid(fColorType));
1307 SkASSERT(SkAlphaTypeIsValid(fAlphaType));
1308}
1309#endif