blob: c66a5b2fd5c2495e05386fe3c6d81568c4d87adc [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"
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"
scroggo565901d2015-12-10 10:44:13 -080020#include "SkTemplates.h"
vandebo@chromium.org112706d2011-02-24 22:50:55 +000021#include "SkUnPreMultiply.h"
mtklein1b249332015-07-07 12:21:21 -070022#include "SkWriteBuffer.h"
bungemand3ebb482015-08-05 13:57:49 -070023
24#include <string.h>
reed@android.com8a1c16f2008-12-17 15:59:43 +000025
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +000026static bool reset_return_false(SkBitmap* bm) {
27 bm->reset();
28 return false;
29}
30
reed@android.com8a1c16f2008-12-17 15:59:43 +000031SkBitmap::SkBitmap() {
reed@android.com4516f472009-06-29 16:25:36 +000032 sk_bzero(this, sizeof(*this));
reed@android.com8a1c16f2008-12-17 15:59:43 +000033}
34
35SkBitmap::SkBitmap(const SkBitmap& src) {
36 SkDEBUGCODE(src.validate();)
reed@android.com4516f472009-06-29 16:25:36 +000037 sk_bzero(this, sizeof(*this));
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 *this = src;
39 SkDEBUGCODE(this->validate();)
40}
41
halcanary023bda02015-12-14 10:19:17 -080042SkBitmap::SkBitmap(SkBitmap&& other) : SkBitmap() { this->swap(other); }
43
reed@android.com8a1c16f2008-12-17 15:59:43 +000044SkBitmap::~SkBitmap() {
45 SkDEBUGCODE(this->validate();)
46 this->freePixels();
47}
48
49SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
50 if (this != &src) {
51 this->freePixels();
52 memcpy(this, &src, sizeof(src));
53
54 // inc src reference counts
reed@android.com83f7bc32009-07-17 02:42:41 +000055 SkSafeRef(src.fPixelRef);
reed@android.com8a1c16f2008-12-17 15:59:43 +000056
57 // we reset our locks if we get blown away
58 fPixelLockCount = 0;
weita@google.comf9ab99a2009-05-03 18:23:30 +000059
reed@google.com5f62ed72014-01-15 19:59:45 +000060 if (fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 // ignore the values from the memcpy
halcanary96fcdcc2015-08-27 07:41:13 -070062 fPixels = nullptr;
63 fColorTable = nullptr;
bsalomon@google.com586f48c2011-04-14 15:07:22 +000064 // Note that what to for genID is somewhat arbitrary. We have no
65 // way to track changes to raw pixels across multiple SkBitmaps.
66 // Would benefit from an SkRawPixelRef type created by
67 // setPixels.
68 // Just leave the memcpy'ed one but they'll get out of sync
69 // as soon either is modified.
reed@android.com8a1c16f2008-12-17 15:59:43 +000070 }
71 }
72
73 SkDEBUGCODE(this->validate();)
74 return *this;
75}
76
halcanary023bda02015-12-14 10:19:17 -080077SkBitmap& SkBitmap::operator=(SkBitmap&& other) {
78 if (this != &other) {
79 this->swap(other);
80 other.reset();
81 }
82 return *this;
83}
84
reed@android.com8a1c16f2008-12-17 15:59:43 +000085void SkBitmap::swap(SkBitmap& other) {
bsalomon@google.com586f48c2011-04-14 15:07:22 +000086 SkTSwap(fColorTable, other.fColorTable);
87 SkTSwap(fPixelRef, other.fPixelRef);
reed@google.com672588b2014-01-08 15:42:01 +000088 SkTSwap(fPixelRefOrigin, other.fPixelRefOrigin);
bsalomon@google.com586f48c2011-04-14 15:07:22 +000089 SkTSwap(fPixelLockCount, other.fPixelLockCount);
bsalomon@google.com586f48c2011-04-14 15:07:22 +000090 SkTSwap(fPixels, other.fPixels);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +000091 SkTSwap(fInfo, other.fInfo);
bsalomon@google.com586f48c2011-04-14 15:07:22 +000092 SkTSwap(fRowBytes, other.fRowBytes);
bsalomon@google.com586f48c2011-04-14 15:07:22 +000093 SkTSwap(fFlags, other.fFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +000094
95 SkDEBUGCODE(this->validate();)
96}
97
98void SkBitmap::reset() {
99 this->freePixels();
reed@android.com4516f472009-06-29 16:25:36 +0000100 sk_bzero(this, sizeof(*this));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101}
102
reed@google.com86b2e432012-03-15 21:17:03 +0000103void SkBitmap::getBounds(SkRect* bounds) const {
104 SkASSERT(bounds);
105 bounds->set(0, 0,
reede5ea5002014-09-03 11:54:58 -0700106 SkIntToScalar(fInfo.width()), SkIntToScalar(fInfo.height()));
reed@google.com86b2e432012-03-15 21:17:03 +0000107}
108
reed@google.com80e14592012-03-16 14:58:07 +0000109void SkBitmap::getBounds(SkIRect* bounds) const {
110 SkASSERT(bounds);
reede5ea5002014-09-03 11:54:58 -0700111 bounds->set(0, 0, fInfo.width(), fInfo.height());
reed@google.com80e14592012-03-16 14:58:07 +0000112}
113
reed@google.com86b2e432012-03-15 21:17:03 +0000114///////////////////////////////////////////////////////////////////////////////
115
reede5ea5002014-09-03 11:54:58 -0700116bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) {
117 SkAlphaType newAT = info.alphaType();
118 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) {
commit-bot@chromium.orgd5414e52014-02-13 22:30:38 +0000119 return reset_return_false(this);
120 }
reede5ea5002014-09-03 11:54:58 -0700121 // don't look at info.alphaType(), since newAT is the real value...
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000122
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000123 // require that rowBytes fit in 31bits
124 int64_t mrb = info.minRowBytes64();
125 if ((int32_t)mrb != mrb) {
126 return reset_return_false(this);
reed@google.com383a6972013-10-21 14:00:07 +0000127 }
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000128 if ((int64_t)rowBytes != (int32_t)rowBytes) {
129 return reset_return_false(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 }
reed@android.com89bb83a2009-05-29 21:30:42 +0000131
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000132 if (info.width() < 0 || info.height() < 0) {
133 return reset_return_false(this);
134 }
135
136 if (kUnknown_SkColorType == info.colorType()) {
137 rowBytes = 0;
138 } else if (0 == rowBytes) {
139 rowBytes = (size_t)mrb;
reedf0aed972014-07-01 12:48:11 -0700140 } else if (!info.validRowBytes(rowBytes)) {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000141 return reset_return_false(this);
reed@google.com383a6972013-10-21 14:00:07 +0000142 }
143
144 this->freePixels();
145
reede5ea5002014-09-03 11:54:58 -0700146 fInfo = info.makeAlphaType(newAT);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000147 fRowBytes = SkToU32(rowBytes);
reed@google.com383a6972013-10-21 14:00:07 +0000148 return true;
reed@google.com383a6972013-10-21 14:00:07 +0000149}
150
reede5ea5002014-09-03 11:54:58 -0700151bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) {
152 if (!SkColorTypeValidateAlphaType(fInfo.colorType(), newAlphaType, &newAlphaType)) {
reed@google.com383a6972013-10-21 14:00:07 +0000153 return false;
154 }
reede5ea5002014-09-03 11:54:58 -0700155 if (fInfo.alphaType() != newAlphaType) {
156 fInfo = fInfo.makeAlphaType(newAlphaType);
commit-bot@chromium.org0e8d0d62014-01-27 15:41:07 +0000157 if (fPixelRef) {
reede5ea5002014-09-03 11:54:58 -0700158 fPixelRef->changeAlphaType(newAlphaType);
commit-bot@chromium.org0e8d0d62014-01-27 15:41:07 +0000159 }
160 }
reed@google.com383a6972013-10-21 14:00:07 +0000161 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162}
163
164void SkBitmap::updatePixelsFromRef() const {
bsalomon49f085d2014-09-05 13:34:00 -0700165 if (fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 if (fPixelLockCount > 0) {
reed@google.comff0da4f2012-05-17 13:14:52 +0000167 SkASSERT(fPixelRef->isLocked());
weita@google.comf9ab99a2009-05-03 18:23:30 +0000168
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 void* p = fPixelRef->pixels();
bsalomon49f085d2014-09-05 13:34:00 -0700170 if (p) {
reed@google.com672588b2014-01-08 15:42:01 +0000171 p = (char*)p
reed@google.com303c4752014-01-09 20:00:14 +0000172 + fPixelRefOrigin.fY * fRowBytes
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000173 + fPixelRefOrigin.fX * fInfo.bytesPerPixel();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174 }
175 fPixels = p;
reed@google.com5f62ed72014-01-15 19:59:45 +0000176 fColorTable = fPixelRef->colorTable();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 } else {
178 SkASSERT(0 == fPixelLockCount);
halcanary96fcdcc2015-08-27 07:41:13 -0700179 fPixels = nullptr;
180 fColorTable = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181 }
182 }
183}
184
reed@google.com672588b2014-01-08 15:42:01 +0000185SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) {
reed@google.comdcea5302014-01-03 13:43:01 +0000186#ifdef SK_DEBUG
reed@google.com672588b2014-01-08 15:42:01 +0000187 if (pr) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000188 if (kUnknown_SkColorType != fInfo.colorType()) {
reed@google.comdcea5302014-01-03 13:43:01 +0000189 const SkImageInfo& prInfo = pr->info();
reede5ea5002014-09-03 11:54:58 -0700190 SkASSERT(fInfo.width() <= prInfo.width());
191 SkASSERT(fInfo.height() <= prInfo.height());
192 SkASSERT(fInfo.colorType() == prInfo.colorType());
193 switch (prInfo.alphaType()) {
reed44977482015-02-27 10:23:00 -0800194 case kUnknown_SkAlphaType:
195 SkASSERT(fInfo.alphaType() == kUnknown_SkAlphaType);
reed@google.comdcea5302014-01-03 13:43:01 +0000196 break;
197 case kOpaque_SkAlphaType:
198 case kPremul_SkAlphaType:
reede5ea5002014-09-03 11:54:58 -0700199 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
200 fInfo.alphaType() == kPremul_SkAlphaType);
reed@google.comdcea5302014-01-03 13:43:01 +0000201 break;
202 case kUnpremul_SkAlphaType:
reede5ea5002014-09-03 11:54:58 -0700203 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
204 fInfo.alphaType() == kUnpremul_SkAlphaType);
reed@google.comdcea5302014-01-03 13:43:01 +0000205 break;
206 }
207 }
208 }
209#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210
reed@google.com672588b2014-01-08 15:42:01 +0000211 if (pr) {
212 const SkImageInfo& info = pr->info();
bungeman62ce0302015-08-28 09:09:32 -0700213 fPixelRefOrigin.set(SkTPin(dx, 0, info.width()), SkTPin(dy, 0, info.height()));
reed@google.com672588b2014-01-08 15:42:01 +0000214 } else {
215 // ignore dx,dy if there is no pixelref
216 fPixelRefOrigin.setZero();
217 }
218
219 if (fPixelRef != pr) {
piotaixr0eb02a62014-06-16 11:50:49 -0700220 this->freePixels();
halcanary96fcdcc2015-08-27 07:41:13 -0700221 SkASSERT(nullptr == fPixelRef);
weita@google.comf9ab99a2009-05-03 18:23:30 +0000222
piotaixr0eb02a62014-06-16 11:50:49 -0700223 SkSafeRef(pr);
224 fPixelRef = pr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 this->updatePixelsFromRef();
226 }
227
228 SkDEBUGCODE(this->validate();)
229 return pr;
230}
231
232void SkBitmap::lockPixels() const {
bsalomon49f085d2014-09-05 13:34:00 -0700233 if (fPixelRef && 0 == sk_atomic_inc(&fPixelLockCount)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 fPixelRef->lockPixels();
235 this->updatePixelsFromRef();
236 }
237 SkDEBUGCODE(this->validate();)
238}
239
240void SkBitmap::unlockPixels() const {
halcanary96fcdcc2015-08-27 07:41:13 -0700241 SkASSERT(nullptr == fPixelRef || fPixelLockCount > 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242
bsalomon49f085d2014-09-05 13:34:00 -0700243 if (fPixelRef && 1 == sk_atomic_dec(&fPixelLockCount)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 fPixelRef->unlockPixels();
245 this->updatePixelsFromRef();
246 }
247 SkDEBUGCODE(this->validate();)
248}
249
reed@google.com9c49bc32011-07-07 13:42:37 +0000250bool SkBitmap::lockPixelsAreWritable() const {
djsollen@google.comc84b8332012-07-27 13:41:44 +0000251 return (fPixelRef) ? fPixelRef->lockPixelsAreWritable() : false;
reed@google.com9c49bc32011-07-07 13:42:37 +0000252}
253
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700255 if (nullptr == p) {
256 this->setPixelRef(nullptr);
reed@google.com8e1034e2012-07-30 13:16:35 +0000257 return;
258 }
259
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000260 if (kUnknown_SkColorType == fInfo.colorType()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700261 this->setPixelRef(nullptr);
reed@google.combf790232013-12-13 19:45:58 +0000262 return;
263 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000265 SkPixelRef* pr = SkMallocPixelRef::NewDirect(fInfo, p, fRowBytes, ctable);
halcanary96fcdcc2015-08-27 07:41:13 -0700266 if (nullptr == pr) {
267 this->setPixelRef(nullptr);
reed@google.combf790232013-12-13 19:45:58 +0000268 return;
269 }
270
271 this->setPixelRef(pr)->unref();
272
djsollen@google.comc84b8332012-07-27 13:41:44 +0000273 // since we're already allocated, we lockPixels right away
274 this->lockPixels();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 SkDEBUGCODE(this->validate();)
276}
277
reed84825042014-09-02 12:50:45 -0700278bool SkBitmap::tryAllocPixels(Allocator* allocator, SkColorTable* ctable) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 HeapAllocator stdalloc;
skia.committer@gmail.comd2ac07b2014-01-25 07:01:49 +0000280
halcanary96fcdcc2015-08-27 07:41:13 -0700281 if (nullptr == allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282 allocator = &stdalloc;
283 }
284 return allocator->allocPixelRef(this, ctable);
285}
286
reed@google.com9ebcac52014-01-24 18:53:42 +0000287///////////////////////////////////////////////////////////////////////////////
288
reed84825042014-09-02 12:50:45 -0700289bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
reedbae704b2014-06-28 14:26:35 -0700290 if (kIndex_8_SkColorType == requestedInfo.colorType()) {
291 return reset_return_false(this);
292 }
reedf0aed972014-07-01 12:48:11 -0700293 if (!this->setInfo(requestedInfo, rowBytes)) {
reedbae704b2014-06-28 14:26:35 -0700294 return reset_return_false(this);
295 }
mtklein775b8192014-12-02 09:11:25 -0800296
reedbae704b2014-06-28 14:26:35 -0700297 // setInfo may have corrected info (e.g. 565 is always opaque).
298 const SkImageInfo& correctedInfo = this->info();
reedf0aed972014-07-01 12:48:11 -0700299 // setInfo may have computed a valid rowbytes if 0 were passed in
300 rowBytes = this->rowBytes();
301
reedbae704b2014-06-28 14:26:35 -0700302 SkMallocPixelRef::PRFactory defaultFactory;
mtklein775b8192014-12-02 09:11:25 -0800303
halcanary96fcdcc2015-08-27 07:41:13 -0700304 SkPixelRef* pr = defaultFactory.create(correctedInfo, rowBytes, nullptr);
305 if (nullptr == pr) {
reedbae704b2014-06-28 14:26:35 -0700306 return reset_return_false(this);
307 }
308 this->setPixelRef(pr)->unref();
mtklein775b8192014-12-02 09:11:25 -0800309
halcanary96fcdcc2015-08-27 07:41:13 -0700310 // TODO: lockPixels could/should return bool or void*/nullptr
reedbae704b2014-06-28 14:26:35 -0700311 this->lockPixels();
halcanary96fcdcc2015-08-27 07:41:13 -0700312 if (nullptr == this->getPixels()) {
reedbae704b2014-06-28 14:26:35 -0700313 return reset_return_false(this);
314 }
315 return true;
316}
317
reed84825042014-09-02 12:50:45 -0700318bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, SkPixelRefFactory* factory,
319 SkColorTable* ctable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700320 if (kIndex_8_SkColorType == requestedInfo.colorType() && nullptr == ctable) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000321 return reset_return_false(this);
322 }
scroggo0187dc22014-06-05 11:18:04 -0700323 if (!this->setInfo(requestedInfo)) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000324 return reset_return_false(this);
325 }
326
scroggo0187dc22014-06-05 11:18:04 -0700327 // setInfo may have corrected info (e.g. 565 is always opaque).
328 const SkImageInfo& correctedInfo = this->info();
329
reed@google.com9ebcac52014-01-24 18:53:42 +0000330 SkMallocPixelRef::PRFactory defaultFactory;
halcanary96fcdcc2015-08-27 07:41:13 -0700331 if (nullptr == factory) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000332 factory = &defaultFactory;
333 }
skia.committer@gmail.comd2ac07b2014-01-25 07:01:49 +0000334
reedf0aed972014-07-01 12:48:11 -0700335 SkPixelRef* pr = factory->create(correctedInfo, correctedInfo.minRowBytes(), ctable);
halcanary96fcdcc2015-08-27 07:41:13 -0700336 if (nullptr == pr) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000337 return reset_return_false(this);
338 }
339 this->setPixelRef(pr)->unref();
340
halcanary96fcdcc2015-08-27 07:41:13 -0700341 // TODO: lockPixels could/should return bool or void*/nullptr
reed@google.com9ebcac52014-01-24 18:53:42 +0000342 this->lockPixels();
halcanary96fcdcc2015-08-27 07:41:13 -0700343 if (nullptr == this->getPixels()) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000344 return reset_return_false(this);
345 }
346 return true;
347}
348
reeddb74f622015-05-30 13:41:15 -0700349static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
350 if (proc) {
351 proc(pixels, ctx);
352 }
353}
354
scroggo0187dc22014-06-05 11:18:04 -0700355bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
356 SkColorTable* ct, void (*releaseProc)(void* addr, void* context),
357 void* context) {
358 if (!this->setInfo(requestedInfo, rb)) {
reeddb74f622015-05-30 13:41:15 -0700359 invoke_release_proc(releaseProc, pixels, context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000360 this->reset();
361 return false;
362 }
halcanary96fcdcc2015-08-27 07:41:13 -0700363 if (nullptr == pixels) {
reeddb74f622015-05-30 13:41:15 -0700364 invoke_release_proc(releaseProc, pixels, context);
365 return true; // we behaved as if they called setInfo()
366 }
reed@google.com9ebcac52014-01-24 18:53:42 +0000367
scroggo0187dc22014-06-05 11:18:04 -0700368 // setInfo may have corrected info (e.g. 565 is always opaque).
369 const SkImageInfo& correctedInfo = this->info();
370
371 SkPixelRef* pr = SkMallocPixelRef::NewWithProc(correctedInfo, rb, ct, pixels, releaseProc,
372 context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000373 if (!pr) {
374 this->reset();
375 return false;
376 }
377
378 this->setPixelRef(pr)->unref();
mike@reedtribe.org6e58cf32014-02-16 20:54:21 +0000379
380 // since we're already allocated, we lockPixels right away
381 this->lockPixels();
mike@reedtribe.org6e58cf32014-02-16 20:54:21 +0000382 SkDEBUGCODE(this->validate();)
reed@google.com9ebcac52014-01-24 18:53:42 +0000383 return true;
384}
385
halcanarye36ec872015-12-09 11:36:59 -0800386bool SkBitmap::installPixels(const SkPixmap& pixmap) {
387 return this->installPixels(pixmap.info(), pixmap.writable_addr(),
388 pixmap.rowBytes(), pixmap.ctable(),
389 nullptr, nullptr);
390}
391
commit-bot@chromium.orgdac52252014-02-17 21:21:46 +0000392bool SkBitmap::installMaskPixels(const SkMask& mask) {
393 if (SkMask::kA8_Format != mask.fFormat) {
394 this->reset();
395 return false;
396 }
397 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
398 mask.fBounds.height()),
399 mask.fImage, mask.fRowBytes);
400}
401
reed@google.comeb9a46c2014-01-25 16:46:20 +0000402///////////////////////////////////////////////////////////////////////////////
403
reed@android.com8a1c16f2008-12-17 15:59:43 +0000404void SkBitmap::freePixels() {
bsalomon49f085d2014-09-05 13:34:00 -0700405 if (fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000406 if (fPixelLockCount > 0) {
407 fPixelRef->unlockPixels();
408 }
409 fPixelRef->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700410 fPixelRef = nullptr;
reed@google.com672588b2014-01-08 15:42:01 +0000411 fPixelRefOrigin.setZero();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000412 }
413 fPixelLockCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700414 fPixels = nullptr;
415 fColorTable = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000416}
417
reed@android.com8a1c16f2008-12-17 15:59:43 +0000418uint32_t SkBitmap::getGenerationID() const {
djsollen@google.comc84b8332012-07-27 13:41:44 +0000419 return (fPixelRef) ? fPixelRef->getGenerationID() : 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000420}
421
422void SkBitmap::notifyPixelsChanged() const {
junov@chromium.orgb0521292011-12-15 20:14:06 +0000423 SkASSERT(!this->isImmutable());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000424 if (fPixelRef) {
425 fPixelRef->notifyPixelsChanged();
426 }
427}
428
commit-bot@chromium.orgb8d00db2013-06-26 19:18:23 +0000429GrTexture* SkBitmap::getTexture() const {
halcanary96fcdcc2015-08-27 07:41:13 -0700430 return fPixelRef ? fPixelRef->getTexture() : nullptr;
reed@android.comce4e53a2010-09-09 16:01:26 +0000431}
432
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433///////////////////////////////////////////////////////////////////////////////
434
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435/** We explicitly use the same allocator for our pixels that SkMask does,
436 so that we can freely assign memory allocated by one class to the other.
437 */
438bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
439 SkColorTable* ctable) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000440 const SkImageInfo info = dst->info();
441 if (kUnknown_SkColorType == info.colorType()) {
reed@google.combf790232013-12-13 19:45:58 +0000442// SkDebugf("unsupported config for info %d\n", dst->config());
443 return false;
444 }
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000445
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000446 SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, dst->rowBytes(), ctable);
halcanary96fcdcc2015-08-27 07:41:13 -0700447 if (nullptr == pr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000448 return false;
449 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000450
reed@google.com672588b2014-01-08 15:42:01 +0000451 dst->setPixelRef(pr)->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452 // since we're already allocated, we lockPixels right away
453 dst->lockPixels();
454 return true;
455}
456
457///////////////////////////////////////////////////////////////////////////////
458
reed92fc2ae2015-05-22 08:06:21 -0700459static bool copy_pixels_to(const SkPixmap& src, void* const dst, size_t dstSize,
460 size_t dstRowBytes, bool preserveDstPad) {
461 const SkImageInfo& info = src.info();
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000462
scroggo@google.com0ba4bf42013-02-25 16:02:36 +0000463 if (0 == dstRowBytes) {
reed92fc2ae2015-05-22 08:06:21 -0700464 dstRowBytes = src.rowBytes();
scroggo@google.com0ba4bf42013-02-25 16:02:36 +0000465 }
reed92fc2ae2015-05-22 08:06:21 -0700466 if (dstRowBytes < info.minRowBytes()) {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000467 return false;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000468 }
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000469
reed92fc2ae2015-05-22 08:06:21 -0700470 if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == src.rowBytes()) {
471 size_t safeSize = src.getSafeSize();
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000472 if (safeSize > dstSize || safeSize == 0)
473 return false;
474 else {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000475 // This implementation will write bytes beyond the end of each row,
476 // excluding the last row, if the bitmap's stride is greater than
477 // strictly required by the current config.
reed92fc2ae2015-05-22 08:06:21 -0700478 memcpy(dst, src.addr(), safeSize);
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000479 return true;
480 }
481 } else {
482 // If destination has different stride than us, then copy line by line.
reed92fc2ae2015-05-22 08:06:21 -0700483 if (info.getSafeSize(dstRowBytes) > dstSize) {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000484 return false;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000485 } else {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000486 // Just copy what we need on each line.
reed92fc2ae2015-05-22 08:06:21 -0700487 size_t rowBytes = info.minRowBytes();
488 const uint8_t* srcP = reinterpret_cast<const uint8_t*>(src.addr());
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000489 uint8_t* dstP = reinterpret_cast<uint8_t*>(dst);
reed92fc2ae2015-05-22 08:06:21 -0700490 for (int row = 0; row < info.height(); ++row) {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000491 memcpy(dstP, srcP, rowBytes);
reed92fc2ae2015-05-22 08:06:21 -0700492 srcP += src.rowBytes();
493 dstP += dstRowBytes;
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000494 }
495
496 return true;
497 }
498 }
499}
500
reed92fc2ae2015-05-22 08:06:21 -0700501bool SkBitmap::copyPixelsTo(void* dst, size_t dstSize, size_t dstRB, bool preserveDstPad) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700502 if (nullptr == dst) {
reed92fc2ae2015-05-22 08:06:21 -0700503 return false;
504 }
505 SkAutoPixmapUnlock result;
506 if (!this->requestLock(&result)) {
507 return false;
508 }
509 return copy_pixels_to(result.pixmap(), dst, dstSize, dstRB, preserveDstPad);
510}
511
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000512///////////////////////////////////////////////////////////////////////////////
513
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000514bool SkBitmap::isImmutable() const {
scroggo08470592014-07-15 19:56:48 -0700515 return fPixelRef ? fPixelRef->isImmutable() : false;
junov@chromium.orgb0521292011-12-15 20:14:06 +0000516}
517
518void SkBitmap::setImmutable() {
519 if (fPixelRef) {
520 fPixelRef->setImmutable();
junov@chromium.orgb0521292011-12-15 20:14:06 +0000521 }
522}
523
junov@google.com4ee7ae52011-06-30 17:30:49 +0000524bool SkBitmap::isVolatile() const {
525 return (fFlags & kImageIsVolatile_Flag) != 0;
526}
527
528void SkBitmap::setIsVolatile(bool isVolatile) {
529 if (isVolatile) {
530 fFlags |= kImageIsVolatile_Flag;
531 } else {
532 fFlags &= ~kImageIsVolatile_Flag;
533 }
534}
535
reed@android.com8a1c16f2008-12-17 15:59:43 +0000536void* SkBitmap::getAddr(int x, int y) const {
537 SkASSERT((unsigned)x < (unsigned)this->width());
538 SkASSERT((unsigned)y < (unsigned)this->height());
539
540 char* base = (char*)this->getPixels();
541 if (base) {
542 base += y * this->rowBytes();
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000543 switch (this->colorType()) {
544 case kRGBA_8888_SkColorType:
545 case kBGRA_8888_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000546 base += x << 2;
547 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000548 case kARGB_4444_SkColorType:
549 case kRGB_565_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000550 base += x << 1;
551 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000552 case kAlpha_8_SkColorType:
553 case kIndex_8_SkColorType:
reed0c9b1a82015-03-17 17:44:06 -0700554 case kGray_8_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555 base += x;
556 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000557 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000558 SkDEBUGFAIL("Can't return addr for config");
halcanary96fcdcc2015-08-27 07:41:13 -0700559 base = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000560 break;
561 }
562 }
563 return base;
564}
565
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000566SkColor SkBitmap::getColor(int x, int y) const {
567 SkASSERT((unsigned)x < (unsigned)this->width());
568 SkASSERT((unsigned)y < (unsigned)this->height());
569
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000570 switch (this->colorType()) {
reed0c9b1a82015-03-17 17:44:06 -0700571 case kGray_8_SkColorType: {
572 uint8_t* addr = this->getAddr8(x, y);
573 return SkColorSetRGB(*addr, *addr, *addr);
574 }
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000575 case kAlpha_8_SkColorType: {
reed@google.com3b521d02011-04-29 11:53:41 +0000576 uint8_t* addr = this->getAddr8(x, y);
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000577 return SkColorSetA(0, addr[0]);
578 }
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000579 case kIndex_8_SkColorType: {
reed@google.com3b521d02011-04-29 11:53:41 +0000580 SkPMColor c = this->getIndex8Color(x, y);
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000581 return SkUnPreMultiply::PMColorToColor(c);
582 }
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000583 case kRGB_565_SkColorType: {
reed@google.com3b521d02011-04-29 11:53:41 +0000584 uint16_t* addr = this->getAddr16(x, y);
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000585 return SkPixel16ToColor(addr[0]);
586 }
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000587 case kARGB_4444_SkColorType: {
reed@google.com3b521d02011-04-29 11:53:41 +0000588 uint16_t* addr = this->getAddr16(x, y);
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000589 SkPMColor c = SkPixel4444ToPixel32(addr[0]);
590 return SkUnPreMultiply::PMColorToColor(c);
591 }
halcanaryb260d132015-12-09 10:21:59 -0800592 case kBGRA_8888_SkColorType: {
593 uint32_t* addr = this->getAddr32(x, y);
594 SkPMColor c = SkSwizzle_BGRA_to_PMColor(addr[0]);
595 return SkUnPreMultiply::PMColorToColor(c);
596 }
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000597 case kRGBA_8888_SkColorType: {
reed@google.com3b521d02011-04-29 11:53:41 +0000598 uint32_t* addr = this->getAddr32(x, y);
halcanaryb260d132015-12-09 10:21:59 -0800599 SkPMColor c = SkSwizzle_RGBA_to_PMColor(addr[0]);
600 return SkUnPreMultiply::PMColorToColor(c);
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000601 }
rmistry@google.comd6bab022013-12-02 13:50:38 +0000602 default:
vandebo@chromium.org112706d2011-02-24 22:50:55 +0000603 SkASSERT(false);
604 return 0;
605 }
606 SkASSERT(false); // Not reached.
607 return 0;
608}
609
reed92fc2ae2015-05-22 08:06:21 -0700610static bool compute_is_opaque(const SkPixmap& pmap) {
611 const int height = pmap.height();
612 const int width = pmap.width();
reed@google.com2a7579d2012-11-07 18:30:18 +0000613
reed92fc2ae2015-05-22 08:06:21 -0700614 switch (pmap.colorType()) {
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000615 case kAlpha_8_SkColorType: {
reed@google.com2a7579d2012-11-07 18:30:18 +0000616 unsigned a = 0xFF;
617 for (int y = 0; y < height; ++y) {
reed92fc2ae2015-05-22 08:06:21 -0700618 const uint8_t* row = pmap.addr8(0, y);
reed@google.com2a7579d2012-11-07 18:30:18 +0000619 for (int x = 0; x < width; ++x) {
620 a &= row[x];
621 }
622 if (0xFF != a) {
623 return false;
624 }
625 }
626 return true;
627 } break;
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000628 case kIndex_8_SkColorType: {
reed92fc2ae2015-05-22 08:06:21 -0700629 const SkColorTable* ctable = pmap.ctable();
halcanary96fcdcc2015-08-27 07:41:13 -0700630 if (nullptr == ctable) {
reed@google.com2a7579d2012-11-07 18:30:18 +0000631 return false;
632 }
reed92fc2ae2015-05-22 08:06:21 -0700633 const SkPMColor* table = ctable->readColors();
reed@google.com140d7282013-01-07 20:25:04 +0000634 SkPMColor c = (SkPMColor)~0;
reed92fc2ae2015-05-22 08:06:21 -0700635 for (int i = ctable->count() - 1; i >= 0; --i) {
reed@google.com2a7579d2012-11-07 18:30:18 +0000636 c &= table[i];
637 }
638 return 0xFF == SkGetPackedA32(c);
639 } break;
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000640 case kRGB_565_SkColorType:
reed0c9b1a82015-03-17 17:44:06 -0700641 case kGray_8_SkColorType:
reed@google.com2a7579d2012-11-07 18:30:18 +0000642 return true;
643 break;
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000644 case kARGB_4444_SkColorType: {
reed@google.com2a7579d2012-11-07 18:30:18 +0000645 unsigned c = 0xFFFF;
646 for (int y = 0; y < height; ++y) {
reed92fc2ae2015-05-22 08:06:21 -0700647 const SkPMColor16* row = pmap.addr16(0, y);
reed@google.com2a7579d2012-11-07 18:30:18 +0000648 for (int x = 0; x < width; ++x) {
649 c &= row[x];
650 }
651 if (0xF != SkGetPackedA4444(c)) {
652 return false;
653 }
654 }
655 return true;
656 } break;
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000657 case kBGRA_8888_SkColorType:
658 case kRGBA_8888_SkColorType: {
reed@google.com140d7282013-01-07 20:25:04 +0000659 SkPMColor c = (SkPMColor)~0;
reed@google.com2a7579d2012-11-07 18:30:18 +0000660 for (int y = 0; y < height; ++y) {
reed92fc2ae2015-05-22 08:06:21 -0700661 const SkPMColor* row = pmap.addr32(0, y);
reed@google.com2a7579d2012-11-07 18:30:18 +0000662 for (int x = 0; x < width; ++x) {
663 c &= row[x];
664 }
665 if (0xFF != SkGetPackedA32(c)) {
666 return false;
667 }
668 }
669 return true;
670 }
671 default:
672 break;
673 }
674 return false;
675}
676
reed92fc2ae2015-05-22 08:06:21 -0700677bool SkBitmap::ComputeIsOpaque(const SkBitmap& bm) {
678 SkAutoPixmapUnlock result;
679 if (!bm.requestLock(&result)) {
680 return false;
681 }
682 return compute_is_opaque(result.pixmap());
683}
684
reed@google.com2a7579d2012-11-07 18:30:18 +0000685
reed@android.com8a1c16f2008-12-17 15:59:43 +0000686///////////////////////////////////////////////////////////////////////////////
687///////////////////////////////////////////////////////////////////////////////
688
reed7aefe032015-06-08 10:22:22 -0700689void SkBitmap::erase(SkColor c, const SkIRect& area) const {
reed92fc2ae2015-05-22 08:06:21 -0700690 SkDEBUGCODE(this->validate();)
reed92fc2ae2015-05-22 08:06:21 -0700691
692 switch (fInfo.colorType()) {
693 case kUnknown_SkColorType:
694 case kIndex_8_SkColorType:
695 // TODO: can we ASSERT that we never get here?
696 return; // can't erase. Should we bzero so the memory is not uninitialized?
697 default:
698 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000700
reed92fc2ae2015-05-22 08:06:21 -0700701 SkAutoPixmapUnlock result;
702 if (!this->requestLock(&result)) {
703 return;
704 }
705
reed7aefe032015-06-08 10:22:22 -0700706 if (result.pixmap().erase(c, area)) {
reed92fc2ae2015-05-22 08:06:21 -0700707 this->notifyPixelsChanged();
708 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000709}
710
reed7aefe032015-06-08 10:22:22 -0700711void SkBitmap::eraseColor(SkColor c) const {
712 this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
reed@google.com60d32352013-06-28 19:40:50 +0000713}
714
reed@android.com8a1c16f2008-12-17 15:59:43 +0000715//////////////////////////////////////////////////////////////////////////////////////
716//////////////////////////////////////////////////////////////////////////////////////
717
reed@android.com8a1c16f2008-12-17 15:59:43 +0000718bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
719 SkDEBUGCODE(this->validate();)
720
halcanary96fcdcc2015-08-27 07:41:13 -0700721 if (nullptr == result || nullptr == fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000722 return false; // no src pixels
723 }
724
725 SkIRect srcRect, r;
726 srcRect.set(0, 0, this->width(), this->height());
727 if (!r.intersect(srcRect, subset)) {
728 return false; // r is empty (i.e. no intersection)
729 }
730
halcanary96fcdcc2015-08-27 07:41:13 -0700731 if (fPixelRef->getTexture() != nullptr) {
scroggo@google.coma2a31922012-12-07 19:14:45 +0000732 // Do a deep copy
jvanverthfa1e8a72014-12-22 08:31:49 -0800733 SkPixelRef* pixelRef = fPixelRef->deepCopy(this->colorType(), this->profileType(), &subset);
halcanary96fcdcc2015-08-27 07:41:13 -0700734 if (pixelRef != nullptr) {
scroggo@google.coma2a31922012-12-07 19:14:45 +0000735 SkBitmap dst;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000736 dst.setInfo(SkImageInfo::Make(subset.width(), subset.height(),
737 this->colorType(), this->alphaType()));
scroggo@google.coma2a31922012-12-07 19:14:45 +0000738 dst.setIsVolatile(this->isVolatile());
scroggo@google.coma2a31922012-12-07 19:14:45 +0000739 dst.setPixelRef(pixelRef)->unref();
740 SkDEBUGCODE(dst.validate());
741 result->swap(dst);
742 return true;
743 }
744 }
745
scroggo@google.coma2a31922012-12-07 19:14:45 +0000746 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
747 // exited above.
748 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
749 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
750
reed@android.com8a1c16f2008-12-17 15:59:43 +0000751 SkBitmap dst;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000752 dst.setInfo(SkImageInfo::Make(r.width(), r.height(), this->colorType(), this->alphaType()),
753 this->rowBytes());
skyostil@google.com0eb75762012-01-16 10:45:53 +0000754 dst.setIsVolatile(this->isVolatile());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000755
756 if (fPixelRef) {
reed@google.com672588b2014-01-08 15:42:01 +0000757 SkIPoint origin = fPixelRefOrigin;
758 origin.fX += r.fLeft;
759 origin.fY += r.fTop;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000760 // share the pixelref with a custom offset
reed@google.com672588b2014-01-08 15:42:01 +0000761 dst.setPixelRef(fPixelRef, origin);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000762 }
763 SkDEBUGCODE(dst.validate();)
764
765 // we know we're good, so commit to result
766 result->swap(dst);
767 return true;
768}
769
770///////////////////////////////////////////////////////////////////////////////
771
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000772bool SkBitmap::canCopyTo(SkColorType dstColorType) const {
reedb184f7f2014-07-13 04:32:32 -0700773 const SkColorType srcCT = this->colorType();
774
775 if (srcCT == kUnknown_SkColorType) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000776 return false;
777 }
778
reedb184f7f2014-07-13 04:32:32 -0700779 bool sameConfigs = (srcCT == dstColorType);
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000780 switch (dstColorType) {
781 case kAlpha_8_SkColorType:
782 case kRGB_565_SkColorType:
commit-bot@chromium.org60b5dce2014-04-22 20:24:33 +0000783 case kRGBA_8888_SkColorType:
784 case kBGRA_8888_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000785 break;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000786 case kIndex_8_SkColorType:
weita@google.comf9ab99a2009-05-03 18:23:30 +0000787 if (!sameConfigs) {
788 return false;
789 }
790 break;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000791 case kARGB_4444_SkColorType:
reedb184f7f2014-07-13 04:32:32 -0700792 return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT;
reed0c9b1a82015-03-17 17:44:06 -0700793 case kGray_8_SkColorType:
794 switch (srcCT) {
795 case kGray_8_SkColorType:
796 case kRGBA_8888_SkColorType:
797 case kBGRA_8888_SkColorType:
798 return true;
799 default:
800 break;
801 }
802 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000803 default:
804 return false;
805 }
reed@android.comfbaa88d2009-05-06 17:44:34 +0000806 return true;
807}
808
reedb184f7f2014-07-13 04:32:32 -0700809bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
810 int x, int y) const {
reed95d343f2015-05-23 13:21:06 -0700811 SkAutoPixmapUnlock src;
812 if (!this->requestLock(&src)) {
reedb184f7f2014-07-13 04:32:32 -0700813 return false;
814 }
reed95d343f2015-05-23 13:21:06 -0700815 return src.pixmap().readPixels(requestedDstInfo, dstPixels, dstRB, x, y);
reedb184f7f2014-07-13 04:32:32 -0700816}
817
818bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000819 if (!this->canCopyTo(dstColorType)) {
reed@android.comfbaa88d2009-05-06 17:44:34 +0000820 return false;
821 }
822
reed@google.com50dfa012011-04-01 19:05:36 +0000823 // if we have a texture, first get those pixels
824 SkBitmap tmpSrc;
825 const SkBitmap* src = this;
826
scroggo@google.coma2a31922012-12-07 19:14:45 +0000827 if (fPixelRef) {
828 SkIRect subset;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000829 subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY,
830 fInfo.width(), fInfo.height());
reed@google.com672588b2014-01-08 15:42:01 +0000831 if (fPixelRef->readPixels(&tmpSrc, &subset)) {
scroggo0187dc22014-06-05 11:18:04 -0700832 if (fPixelRef->info().alphaType() == kUnpremul_SkAlphaType) {
833 // FIXME: The only meaningful implementation of readPixels
834 // (GrPixelRef) assumes premultiplied pixels.
835 return false;
836 }
reed@google.com672588b2014-01-08 15:42:01 +0000837 SkASSERT(tmpSrc.width() == this->width());
838 SkASSERT(tmpSrc.height() == this->height());
reed@google.com50dfa012011-04-01 19:05:36 +0000839
reed@google.com672588b2014-01-08 15:42:01 +0000840 // did we get lucky and we can just return tmpSrc?
halcanary96fcdcc2015-08-27 07:41:13 -0700841 if (tmpSrc.colorType() == dstColorType && nullptr == alloc) {
reed@google.com672588b2014-01-08 15:42:01 +0000842 dst->swap(tmpSrc);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000843 // If the result is an exact copy, clone the gen ID.
844 if (dst->pixelRef() && dst->pixelRef()->info() == fPixelRef->info()) {
reed@google.com672588b2014-01-08 15:42:01 +0000845 dst->pixelRef()->cloneGenID(*fPixelRef);
scroggo@google.coma2a31922012-12-07 19:14:45 +0000846 }
reed@google.com672588b2014-01-08 15:42:01 +0000847 return true;
scroggo@google.comd5764e82012-08-22 15:00:05 +0000848 }
reed@google.com672588b2014-01-08 15:42:01 +0000849
850 // fall through to the raster case
851 src = &tmpSrc;
reed@google.com50dfa012011-04-01 19:05:36 +0000852 }
reed@android.comfbaa88d2009-05-06 17:44:34 +0000853 }
reed@android.com311c82d2009-05-05 23:13:23 +0000854
reed95d343f2015-05-23 13:21:06 -0700855 SkAutoPixmapUnlock srcUnlocker;
856 if (!src->requestLock(&srcUnlocker)) {
reed@google.com50dfa012011-04-01 19:05:36 +0000857 return false;
858 }
reed95d343f2015-05-23 13:21:06 -0700859 const SkPixmap& srcPM = srcUnlocker.pixmap();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000860
reed95d343f2015-05-23 13:21:06 -0700861 const SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType);
reed@google.com50dfa012011-04-01 19:05:36 +0000862 SkBitmap tmpDst;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000863 if (!tmpDst.setInfo(dstInfo)) {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000864 return false;
865 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000866
weita@google.comf9ab99a2009-05-03 18:23:30 +0000867 // allocate colortable if srcConfig == kIndex8_Config
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000868 SkAutoTUnref<SkColorTable> ctable;
869 if (dstColorType == kIndex_8_SkColorType) {
reed95d343f2015-05-23 13:21:06 -0700870 ctable.reset(SkRef(srcPM.ctable()));
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000871 }
reed84825042014-09-02 12:50:45 -0700872 if (!tmpDst.tryAllocPixels(alloc, ctable)) {
weita@google.comf9ab99a2009-05-03 18:23:30 +0000873 return false;
874 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000875
reed95d343f2015-05-23 13:21:06 -0700876 SkAutoPixmapUnlock dstUnlocker;
877 if (!tmpDst.requestLock(&dstUnlocker)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000878 return false;
879 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000880
reed95d343f2015-05-23 13:21:06 -0700881 if (!srcPM.readPixels(dstUnlocker.pixmap())) {
reedb184f7f2014-07-13 04:32:32 -0700882 return false;
883 }
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000884
reedb184f7f2014-07-13 04:32:32 -0700885 // (for BitmapHeap) Clone the pixelref genID even though we have a new pixelref.
886 // The old copyTo impl did this, so we continue it for now.
887 //
888 // TODO: should we ignore rowbytes (i.e. getSize)? Then it could just be
889 // if (src_pixelref->info == dst_pixelref->info)
890 //
reed95d343f2015-05-23 13:21:06 -0700891 if (srcPM.colorType() == dstColorType && tmpDst.getSize() == srcPM.getSize64()) {
reedb184f7f2014-07-13 04:32:32 -0700892 SkPixelRef* dstPixelRef = tmpDst.pixelRef();
893 if (dstPixelRef->info() == fPixelRef->info()) {
894 dstPixelRef->cloneGenID(*fPixelRef);
reed@android.com311c82d2009-05-05 23:13:23 +0000895 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000896 }
897
reed@google.com50dfa012011-04-01 19:05:36 +0000898 dst->swap(tmpDst);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000899 return true;
900}
901
commit-bot@chromium.orgfab349c2014-03-05 02:34:58 +0000902bool SkBitmap::deepCopyTo(SkBitmap* dst) const {
reede4538f52014-06-11 06:09:50 -0700903 const SkColorType dstCT = this->colorType();
jvanverthfa1e8a72014-12-22 08:31:49 -0800904 const SkColorProfileType dstPT = this->profileType();
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000905
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000906 if (!this->canCopyTo(dstCT)) {
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000907 return false;
908 }
909
910 // If we have a PixelRef, and it supports deep copy, use it.
911 // Currently supported only by texture-backed bitmaps.
912 if (fPixelRef) {
halcanary96fcdcc2015-08-27 07:41:13 -0700913 SkPixelRef* pixelRef = fPixelRef->deepCopy(dstCT, dstPT, nullptr);
commit-bot@chromium.orgeeef0cc2014-05-21 15:58:00 +0000914 if (pixelRef) {
915 uint32_t rowBytes;
jvanverthfa1e8a72014-12-22 08:31:49 -0800916 if (this->colorType() == dstCT && this->profileType() == dstPT) {
commit-bot@chromium.orgeeef0cc2014-05-21 15:58:00 +0000917 // Since there is no subset to pass to deepCopy, and deepCopy
918 // succeeded, the new pixel ref must be identical.
919 SkASSERT(fPixelRef->info() == pixelRef->info());
920 pixelRef->cloneGenID(*fPixelRef);
921 // Use the same rowBytes as the original.
922 rowBytes = fRowBytes;
923 } else {
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000924 // With the new config, an appropriate fRowBytes will be computed by setInfo.
commit-bot@chromium.orgeeef0cc2014-05-21 15:58:00 +0000925 rowBytes = 0;
926 }
927
reede5ea5002014-09-03 11:54:58 -0700928 const SkImageInfo info = fInfo.makeColorType(dstCT);
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000929 if (!dst->setInfo(info, rowBytes)) {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000930 return false;
931 }
commit-bot@chromium.orgeeef0cc2014-05-21 15:58:00 +0000932 dst->setPixelRef(pixelRef, fPixelRefOrigin)->unref();
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000933 return true;
934 }
935 }
936
937 if (this->getTexture()) {
938 return false;
939 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700940 return this->copyTo(dst, dstCT, nullptr);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000941 }
942}
943
reed@android.com8a1c16f2008-12-17 15:59:43 +0000944///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000945
reed92fc2ae2015-05-22 08:06:21 -0700946static void rect_memset(uint8_t* array, U8CPU value, SkISize size, size_t rowBytes) {
947 for (int y = 0; y < size.height(); ++y) {
948 memset(array, value, size.width());
949 array += rowBytes;
reed@android.com1cdcb512009-08-24 19:11:00 +0000950 }
reed92fc2ae2015-05-22 08:06:21 -0700951}
reed@google.com82065d62011-02-07 15:30:46 +0000952
reed92fc2ae2015-05-22 08:06:21 -0700953static void get_bitmap_alpha(const SkPixmap& pmap, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
954 SkColorType colorType = pmap.colorType();
955 int w = pmap.width();
956 int h = pmap.height();
957 size_t rb = pmap.rowBytes();
958
959 if (kAlpha_8_SkColorType == colorType && !pmap.isOpaque()) {
960 const uint8_t* s = pmap.addr8(0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000961 while (--h >= 0) {
962 memcpy(alpha, s, w);
963 s += rb;
964 alpha += alphaRowBytes;
965 }
reed92fc2ae2015-05-22 08:06:21 -0700966 } else if (kN32_SkColorType == colorType && !pmap.isOpaque()) {
967 const SkPMColor* SK_RESTRICT s = pmap.addr32(0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968 while (--h >= 0) {
969 for (int x = 0; x < w; x++) {
970 alpha[x] = SkGetPackedA32(s[x]);
971 }
972 s = (const SkPMColor*)((const char*)s + rb);
973 alpha += alphaRowBytes;
974 }
reed92fc2ae2015-05-22 08:06:21 -0700975 } else if (kARGB_4444_SkColorType == colorType && !pmap.isOpaque()) {
976 const SkPMColor16* SK_RESTRICT s = pmap.addr16(0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977 while (--h >= 0) {
978 for (int x = 0; x < w; x++) {
979 alpha[x] = SkPacked4444ToA32(s[x]);
980 }
981 s = (const SkPMColor16*)((const char*)s + rb);
982 alpha += alphaRowBytes;
983 }
reed92fc2ae2015-05-22 08:06:21 -0700984 } else if (kIndex_8_SkColorType == colorType && !pmap.isOpaque()) {
985 const SkColorTable* ct = pmap.ctable();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986 if (ct) {
mtklein775b8192014-12-02 09:11:25 -0800987 const SkPMColor* SK_RESTRICT table = ct->readColors();
reed92fc2ae2015-05-22 08:06:21 -0700988 const uint8_t* SK_RESTRICT s = pmap.addr8(0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989 while (--h >= 0) {
990 for (int x = 0; x < w; x++) {
991 alpha[x] = SkGetPackedA32(table[s[x]]);
992 }
993 s += rb;
994 alpha += alphaRowBytes;
995 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000996 }
997 } else { // src is opaque, so just fill alpha[] with 0xFF
reed92fc2ae2015-05-22 08:06:21 -0700998 rect_memset(alpha, 0xFF, pmap.info().dimensions(), alphaRowBytes);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000999 }
reed92fc2ae2015-05-22 08:06:21 -07001000}
1001
1002static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
halcanary96fcdcc2015-08-27 07:41:13 -07001003 SkASSERT(alpha != nullptr);
reed92fc2ae2015-05-22 08:06:21 -07001004 SkASSERT(alphaRowBytes >= src.width());
1005
1006 SkAutoPixmapUnlock apl;
1007 if (!src.requestLock(&apl)) {
1008 rect_memset(alpha, 0, src.info().dimensions(), alphaRowBytes);
1009 return false;
1010 }
1011 get_bitmap_alpha(apl.pixmap(), alpha, alphaRowBytes);
reed@android.com1cdcb512009-08-24 19:11:00 +00001012 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001013}
1014
1015#include "SkPaint.h"
1016#include "SkMaskFilter.h"
1017#include "SkMatrix.h"
1018
djsollen@google.comcd9d69b2011-03-14 20:30:14 +00001019bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
djsollen@google.com57f49692011-02-23 20:46:31 +00001020 Allocator *allocator, SkIPoint* offset) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001021 SkDEBUGCODE(this->validate();)
1022
djsollen@google.comcd9d69b2011-03-14 20:30:14 +00001023 SkBitmap tmpBitmap;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001024 SkMatrix identity;
1025 SkMask srcM, dstM;
1026
1027 srcM.fBounds.set(0, 0, this->width(), this->height());
1028 srcM.fRowBytes = SkAlign4(this->width());
1029 srcM.fFormat = SkMask::kA8_Format;
1030
halcanary96fcdcc2015-08-27 07:41:13 -07001031 SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001032
1033 // compute our (larger?) dst bounds if we have a filter
bsalomon49f085d2014-09-05 13:34:00 -07001034 if (filter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001035 identity.reset();
halcanary96fcdcc2015-08-27 07:41:13 -07001036 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037 goto NO_FILTER_CASE;
1038 }
1039 dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
1040 } else {
1041 NO_FILTER_CASE:
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +00001042 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -07001043 if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +00001044 // Allocation of pixels for alpha bitmap failed.
1045 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
1046 tmpBitmap.width(), tmpBitmap.height());
1047 return false;
1048 }
1049 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001050 if (offset) {
1051 offset->set(0, 0);
1052 }
djsollen@google.comcd9d69b2011-03-14 20:30:14 +00001053 tmpBitmap.swap(*dst);
1054 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001055 }
bungeman@google.com02f55842011-10-04 21:25:00 +00001056 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
1057 SkAutoMaskFreeImage srcCleanup(srcM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058
1059 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -07001060 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001061 goto NO_FILTER_CASE;
1062 }
bungeman@google.com02f55842011-10-04 21:25:00 +00001063 SkAutoMaskFreeImage dstCleanup(dstM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +00001065 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
1066 dstM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -07001067 if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +00001068 // Allocation of pixels for alpha bitmap failed.
1069 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
1070 tmpBitmap.width(), tmpBitmap.height());
1071 return false;
1072 }
1073 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001074 if (offset) {
1075 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
1076 }
djsollen@google.comcd9d69b2011-03-14 20:30:14 +00001077 SkDEBUGCODE(tmpBitmap.validate();)
1078
1079 tmpBitmap.swap(*dst);
1080 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001081}
1082
1083///////////////////////////////////////////////////////////////////////////////
1084
reed92fc2ae2015-05-22 08:06:21 -07001085static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) {
1086 const SkImageInfo& info = pmap.info();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001087 const size_t snugRB = info.width() * info.bytesPerPixel();
reed92fc2ae2015-05-22 08:06:21 -07001088 const char* src = (const char*)pmap.addr();
1089 const size_t ramRB = pmap.rowBytes();
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +00001090
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001091 buffer->write32(SkToU32(snugRB));
1092 info.flatten(*buffer);
1093
1094 const size_t size = snugRB * info.height();
scroggo565901d2015-12-10 10:44:13 -08001095 SkAutoTMalloc<char> storage(size);
1096 char* dst = storage.get();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001097 for (int y = 0; y < info.height(); ++y) {
1098 memcpy(dst, src, snugRB);
1099 dst += snugRB;
1100 src += ramRB;
1101 }
1102 buffer->writeByteArray(storage.get(), size);
1103
reed92fc2ae2015-05-22 08:06:21 -07001104 const SkColorTable* ct = pmap.ctable();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001105 if (kIndex_8_SkColorType == info.colorType() && ct) {
1106 buffer->writeBool(true);
1107 ct->writeToBuffer(*buffer);
1108 } else {
1109 buffer->writeBool(false);
1110 }
1111}
1112
reed92fc2ae2015-05-22 08:06:21 -07001113void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) {
1114 const SkImageInfo info = bitmap.info();
halcanary96fcdcc2015-08-27 07:41:13 -07001115 if (0 == info.width() || 0 == info.height() || nullptr == bitmap.pixelRef()) {
reed92fc2ae2015-05-22 08:06:21 -07001116 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
1117 return;
1118 }
1119
1120 SkAutoPixmapUnlock result;
1121 if (!bitmap.requestLock(&result)) {
1122 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
1123 return;
1124 }
1125
1126 write_raw_pixels(buffer, result.pixmap());
1127}
1128
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001129bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) {
1130 const size_t snugRB = buffer->readUInt();
1131 if (0 == snugRB) { // no pixels
1132 return false;
1133 }
1134
1135 SkImageInfo info;
1136 info.unflatten(*buffer);
1137
sugoica95c192014-07-08 09:18:48 -07001138 // If there was an error reading "info", don't use it to compute minRowBytes()
1139 if (!buffer->validate(true)) {
1140 return false;
1141 }
1142
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001143 const size_t ramRB = info.minRowBytes();
sugoibd0d9da2015-01-07 08:47:44 -08001144 const int height = SkMax32(info.height(), 0);
1145 const uint64_t snugSize = sk_64_mul(snugRB, height);
1146 const uint64_t ramSize = sk_64_mul(ramRB, height);
1147 static const uint64_t max_size_t = (size_t)(-1);
1148 if (!buffer->validate((snugSize <= ramSize) && (ramSize <= max_size_t))) {
commit-bot@chromium.org05858432014-05-30 01:06:44 +00001149 return false;
1150 }
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001151
sugoibd0d9da2015-01-07 08:47:44 -08001152 SkAutoDataUnref data(SkData::NewUninitialized(SkToSizeT(ramSize)));
robertphillips28937842015-06-08 07:10:49 -07001153 unsigned char* dst = (unsigned char*)data->writable_data();
sugoibd0d9da2015-01-07 08:47:44 -08001154 buffer->readByteArray(dst, SkToSizeT(snugSize));
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001155
1156 if (snugSize != ramSize) {
robertphillips28937842015-06-08 07:10:49 -07001157 const unsigned char* srcRow = dst + snugRB * (height - 1);
1158 unsigned char* dstRow = dst + ramRB * (height - 1);
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001159 for (int y = height - 1; y >= 1; --y) {
1160 memmove(dstRow, srcRow, snugRB);
1161 srcRow -= snugRB;
1162 dstRow -= ramRB;
1163 }
1164 SkASSERT(srcRow == dstRow); // first row does not need to be moved
1165 }
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +00001166
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001167 SkAutoTUnref<SkColorTable> ctable;
1168 if (buffer->readBool()) {
reedb236d1a2015-08-28 10:14:18 -07001169 ctable.reset(SkColorTable::Create(*buffer));
1170 if (!ctable) {
1171 return false;
1172 }
robertphillips28937842015-06-08 07:10:49 -07001173
reedb236d1a2015-08-28 10:14:18 -07001174 if (info.isEmpty()) {
1175 // require an empty ctable
1176 if (ctable->count() != 0) {
1177 buffer->validate(false);
1178 return false;
1179 }
1180 } else {
1181 // require a non-empty ctable
1182 if (ctable->count() == 0) {
1183 buffer->validate(false);
1184 return false;
1185 }
1186 unsigned char maxIndex = ctable->count() - 1;
1187 for (uint64_t i = 0; i < ramSize; ++i) {
1188 dst[i] = SkTMin(dst[i], maxIndex);
1189 }
robertphillips28937842015-06-08 07:10:49 -07001190 }
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001191 }
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +00001192
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001193 SkAutoTUnref<SkPixelRef> pr(SkMallocPixelRef::NewWithData(info, info.minRowBytes(),
1194 ctable.get(), data.get()));
sugoi6af31472015-01-28 13:15:32 -08001195 if (!pr.get()) {
1196 return false;
1197 }
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +00001198 bitmap->setInfo(pr->info());
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001199 bitmap->setPixelRef(pr, 0, 0);
1200 return true;
1201}
1202
reed@android.com8a1c16f2008-12-17 15:59:43 +00001203enum {
1204 SERIALIZE_PIXELTYPE_NONE,
djsollen@google.com21830d92012-08-07 19:49:41 +00001205 SERIALIZE_PIXELTYPE_REF_DATA
reed@android.com8a1c16f2008-12-17 15:59:43 +00001206};
1207
reed@android.com8a1c16f2008-12-17 15:59:43 +00001208///////////////////////////////////////////////////////////////////////////////
1209
1210SkBitmap::RLEPixels::RLEPixels(int width, int height) {
1211 fHeight = height;
commit-bot@chromium.org235002f2013-10-09 18:39:59 +00001212 fYPtrs = (uint8_t**)sk_calloc_throw(height * sizeof(uint8_t*));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001213}
1214
1215SkBitmap::RLEPixels::~RLEPixels() {
1216 sk_free(fYPtrs);
1217}
1218
1219///////////////////////////////////////////////////////////////////////////////
1220
1221#ifdef SK_DEBUG
1222void SkBitmap::validate() const {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001223 fInfo.validate();
commit-bot@chromium.orgd5414e52014-02-13 22:30:38 +00001224
1225 // ImageInfo may not require this, but Bitmap ensures that opaque-only
1226 // colorTypes report opaque for their alphatype
1227 if (kRGB_565_SkColorType == fInfo.colorType()) {
1228 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
1229 }
1230
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001231 SkASSERT(fInfo.validRowBytes(fRowBytes));
scroggo08470592014-07-15 19:56:48 -07001232 uint8_t allFlags = kImageIsVolatile_Flag;
scroggo@google.com8e990eb2013-06-14 15:55:56 +00001233#ifdef SK_BUILD_FOR_ANDROID
1234 allFlags |= kHasHardwareMipMap_Flag;
1235#endif
scroggo08470592014-07-15 19:56:48 -07001236 SkASSERT((~allFlags & fFlags) == 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001237 SkASSERT(fPixelLockCount >= 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001238
reed@google.com615316c2014-01-15 19:15:23 +00001239 if (fPixels) {
1240 SkASSERT(fPixelRef);
robertphillipse77dadd2014-11-21 05:50:21 -08001241 SkASSERT(fPixelLockCount > 0);
reed@google.com615316c2014-01-15 19:15:23 +00001242 SkASSERT(fPixelRef->isLocked());
1243 SkASSERT(fPixelRef->rowBytes() == fRowBytes);
1244 SkASSERT(fPixelRefOrigin.fX >= 0);
1245 SkASSERT(fPixelRefOrigin.fY >= 0);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001246 SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX);
reede5ea5002014-09-03 11:54:58 -07001247 SkASSERT(fPixelRef->info().height() >= (int)this->height() + fPixelRefOrigin.fY);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001248 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
reed@google.com615316c2014-01-15 19:15:23 +00001249 } else {
halcanary96fcdcc2015-08-27 07:41:13 -07001250 SkASSERT(nullptr == fColorTable);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001252}
1253#endif
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001254
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001255#ifndef SK_IGNORE_TO_STRING
bungemand3ebb482015-08-05 13:57:49 -07001256#include "SkString.h"
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001257void SkBitmap::toString(SkString* str) const {
1258
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +00001259 static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = {
1260 "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8",
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001261 };
1262
1263 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +00001264 gColorTypeNames[this->colorType()]);
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001265
1266 str->append(" (");
1267 if (this->isOpaque()) {
1268 str->append("opaque");
1269 } else {
1270 str->append("transparent");
1271 }
1272 if (this->isImmutable()) {
1273 str->append(", immutable");
1274 } else {
1275 str->append(", not-immutable");
1276 }
1277 str->append(")");
1278
1279 SkPixelRef* pr = this->pixelRef();
halcanary96fcdcc2015-08-27 07:41:13 -07001280 if (nullptr == pr) {
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001281 // show null or the explicit pixel address (rare)
1282 str->appendf(" pixels:%p", this->getPixels());
1283 } else {
1284 const char* uri = pr->getURI();
bsalomon49f085d2014-09-05 13:34:00 -07001285 if (uri) {
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001286 str->appendf(" uri:\"%s\"", uri);
1287 } else {
1288 str->appendf(" pixelref:%p", pr);
1289 }
1290 }
1291
1292 str->append(")");
1293}
1294#endif
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001295
1296///////////////////////////////////////////////////////////////////////////////
1297
reed92fc2ae2015-05-22 08:06:21 -07001298bool SkBitmap::requestLock(SkAutoPixmapUnlock* result) const {
1299 SkASSERT(result);
1300
1301 SkPixelRef* pr = fPixelRef;
halcanary96fcdcc2015-08-27 07:41:13 -07001302 if (nullptr == pr) {
reed92fc2ae2015-05-22 08:06:21 -07001303 return false;
1304 }
1305
reed871872f2015-06-22 12:48:26 -07001306 // We have to lock the whole thing (using the pixelref's dimensions) until the api supports
1307 // a partial lock (with offset/origin). Hence we can't use our fInfo.
1308 SkPixelRef::LockRequest req = { pr->info().dimensions(), kNone_SkFilterQuality };
reed92fc2ae2015-05-22 08:06:21 -07001309 SkPixelRef::LockResult res;
1310 if (pr->requestLock(req, &res)) {
reede8006572015-05-28 14:06:06 -07001311 SkASSERT(res.fPixels);
reed92fc2ae2015-05-22 08:06:21 -07001312 // The bitmap may be a subset of the pixelref's dimensions
1313 SkASSERT(fPixelRefOrigin.x() + fInfo.width() <= res.fSize.width());
1314 SkASSERT(fPixelRefOrigin.y() + fInfo.height() <= res.fSize.height());
1315 const void* addr = (const char*)res.fPixels + SkColorTypeComputeOffset(fInfo.colorType(),
1316 fPixelRefOrigin.x(),
1317 fPixelRefOrigin.y(),
1318 res.fRowBytes);
1319
1320 result->reset(SkPixmap(this->info(), addr, res.fRowBytes, res.fCTable),
1321 res.fUnlockProc, res.fUnlockContext);
1322 return true;
1323 }
1324 return false;
1325}
1326
reedcb674142015-06-05 06:58:22 -07001327bool SkBitmap::peekPixels(SkPixmap* pmap) const {
1328 if (fPixels) {
1329 if (pmap) {
1330 pmap->reset(fInfo, fPixels, fRowBytes, fColorTable);
1331 }
1332 return true;
1333 }
1334 return false;
1335}
1336
reed92fc2ae2015-05-22 08:06:21 -07001337///////////////////////////////////////////////////////////////////////////////
1338
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001339#ifdef SK_DEBUG
1340void SkImageInfo::validate() const {
1341 SkASSERT(fWidth >= 0);
1342 SkASSERT(fHeight >= 0);
1343 SkASSERT(SkColorTypeIsValid(fColorType));
1344 SkASSERT(SkAlphaTypeIsValid(fAlphaType));
1345}
1346#endif