blob: 0e22e3019ca0c33ea9a6d04f6f8fdaa46a1131f6 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
herbb906daf2015-09-29 09:37:59 -07008#include "SkAtomics.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkBitmap.h"
10#include "SkColorPriv.h"
Matt Sarett485c4992017-02-14 14:18:27 -050011#include "SkConvertPixels.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkData.h"
13#include "SkFilterQuality.h"
Hal Canary4cba3fe2016-12-07 14:59:27 -050014#include "SkHalf.h"
Matt Sarett03dd6d52017-01-23 12:15:09 -050015#include "SkImageInfoPriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkMallocPixelRef.h"
17#include "SkMask.h"
bungemand3ebb482015-08-05 13:57:49 -070018#include "SkMath.h"
jvanverth02802f62015-07-02 06:42:49 -070019#include "SkPixelRef.h"
mtklein1b249332015-07-07 12:21:21 -070020#include "SkReadBuffer.h"
bungemand3ebb482015-08-05 13:57:49 -070021#include "SkRect.h"
22#include "SkScalar.h"
scroggo565901d2015-12-10 10:44:13 -080023#include "SkTemplates.h"
vandebo@chromium.org112706d2011-02-24 22:50:55 +000024#include "SkUnPreMultiply.h"
mtklein1b249332015-07-07 12:21:21 -070025#include "SkWriteBuffer.h"
Matt Sarett03dd6d52017-01-23 12:15:09 -050026#include "SkWritePixelsRec.h"
bungemand3ebb482015-08-05 13:57:49 -070027
28#include <string.h>
reed@android.com8a1c16f2008-12-17 15:59:43 +000029
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +000030static bool reset_return_false(SkBitmap* bm) {
31 bm->reset();
32 return false;
33}
34
Hal Canary1b3387b2016-12-12 13:48:12 -050035SkBitmap::SkBitmap()
36 : fPixelLockCount(0)
37 , fPixels (nullptr)
38 , fColorTable (nullptr)
39 , fPixelRefOrigin{0, 0}
40 , fRowBytes (0)
41 , fFlags (0) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000042
Hal Canary1b3387b2016-12-12 13:48:12 -050043// copy pixelref, but don't copy lock.
44SkBitmap::SkBitmap(const SkBitmap& src)
45 : fPixelRef (src.fPixelRef)
46 , fPixelLockCount(0)
47 , fPixels (nullptr)
48 , fColorTable (nullptr)
49 , fPixelRefOrigin(src.fPixelRefOrigin)
50 , fInfo (src.fInfo)
51 , fRowBytes (src.fRowBytes)
52 , fFlags (src.fFlags)
53{
reed@android.com8a1c16f2008-12-17 15:59:43 +000054 SkDEBUGCODE(src.validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +000055 SkDEBUGCODE(this->validate();)
56}
57
Hal Canary1b3387b2016-12-12 13:48:12 -050058// take lock and lockcount from other.
59SkBitmap::SkBitmap(SkBitmap&& other)
60 : fPixelRef (std::move(other.fPixelRef))
61 , fPixelLockCount (other.fPixelLockCount)
62 , fPixels (other.fPixels)
63 , fColorTable (other.fColorTable)
64 , fPixelRefOrigin (other.fPixelRefOrigin)
65 , fInfo (std::move(other.fInfo))
66 , fRowBytes (other.fRowBytes)
67 , fFlags (other.fFlags) {
68 SkASSERT(!other.fPixelRef);
69 other.fInfo.reset();
70 other.fPixelLockCount = 0;
71 other.fPixels = nullptr;
72 other.fColorTable = nullptr;
73 other.fPixelRefOrigin = SkIPoint{0, 0};
74 other.fRowBytes = 0;
75 other.fFlags = 0;
76}
halcanary023bda02015-12-14 10:19:17 -080077
reed@android.com8a1c16f2008-12-17 15:59:43 +000078SkBitmap::~SkBitmap() {
79 SkDEBUGCODE(this->validate();)
80 this->freePixels();
81}
82
83SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
84 if (this != &src) {
85 this->freePixels();
Hal Canary1b3387b2016-12-12 13:48:12 -050086 SkASSERT(!fPixels);
87 SkASSERT(!fColorTable);
88 SkASSERT(!fPixelLockCount);
89 fPixelRef = src.fPixelRef;
90 fPixelRefOrigin = src.fPixelRefOrigin;
91 fInfo = src.fInfo;
92 fRowBytes = src.fRowBytes;
93 fFlags = src.fFlags;
reed@android.com8a1c16f2008-12-17 15:59:43 +000094 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 SkDEBUGCODE(this->validate();)
96 return *this;
97}
98
halcanary023bda02015-12-14 10:19:17 -080099SkBitmap& SkBitmap::operator=(SkBitmap&& other) {
100 if (this != &other) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500101 this->freePixels();
102 SkASSERT(!fPixels);
103 SkASSERT(!fColorTable);
104 SkASSERT(!fPixelLockCount);
105 fPixelRef = std::move(other.fPixelRef);
106 fInfo = std::move(other.fInfo);
107 fPixelLockCount = other.fPixelLockCount;
108 fPixels = other.fPixels;
109 fColorTable = other.fColorTable;
110 fPixelRefOrigin = other.fPixelRefOrigin;
111 fRowBytes = other.fRowBytes;
112 fFlags = other.fFlags;
113 SkASSERT(!other.fPixelRef);
114 other.fInfo.reset();
115 other.fPixelLockCount = 0;
116 other.fPixels = nullptr;
117 other.fColorTable = nullptr;
118 other.fPixelRefOrigin = SkIPoint{0, 0};
119 other.fRowBytes = 0;
120 other.fFlags = 0;
halcanary023bda02015-12-14 10:19:17 -0800121 }
122 return *this;
123}
124
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125void SkBitmap::swap(SkBitmap& other) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500126 SkTSwap(*this, other);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 SkDEBUGCODE(this->validate();)
128}
129
130void SkBitmap::reset() {
131 this->freePixels();
msarett23c51102016-05-27 07:39:02 -0700132 this->fInfo.reset();
reed@android.com4516f472009-06-29 16:25:36 +0000133 sk_bzero(this, sizeof(*this));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134}
135
reed@google.com86b2e432012-03-15 21:17:03 +0000136void SkBitmap::getBounds(SkRect* bounds) const {
137 SkASSERT(bounds);
138 bounds->set(0, 0,
reede5ea5002014-09-03 11:54:58 -0700139 SkIntToScalar(fInfo.width()), SkIntToScalar(fInfo.height()));
reed@google.com86b2e432012-03-15 21:17:03 +0000140}
141
reed@google.com80e14592012-03-16 14:58:07 +0000142void SkBitmap::getBounds(SkIRect* bounds) const {
143 SkASSERT(bounds);
reede5ea5002014-09-03 11:54:58 -0700144 bounds->set(0, 0, fInfo.width(), fInfo.height());
reed@google.com80e14592012-03-16 14:58:07 +0000145}
146
reed@google.com86b2e432012-03-15 21:17:03 +0000147///////////////////////////////////////////////////////////////////////////////
148
reede5ea5002014-09-03 11:54:58 -0700149bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) {
150 SkAlphaType newAT = info.alphaType();
151 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) {
commit-bot@chromium.orgd5414e52014-02-13 22:30:38 +0000152 return reset_return_false(this);
153 }
reede5ea5002014-09-03 11:54:58 -0700154 // don't look at info.alphaType(), since newAT is the real value...
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000155
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000156 // require that rowBytes fit in 31bits
157 int64_t mrb = info.minRowBytes64();
158 if ((int32_t)mrb != mrb) {
159 return reset_return_false(this);
reed@google.com383a6972013-10-21 14:00:07 +0000160 }
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000161 if ((int64_t)rowBytes != (int32_t)rowBytes) {
162 return reset_return_false(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163 }
reed@android.com89bb83a2009-05-29 21:30:42 +0000164
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000165 if (info.width() < 0 || info.height() < 0) {
166 return reset_return_false(this);
167 }
168
169 if (kUnknown_SkColorType == info.colorType()) {
170 rowBytes = 0;
171 } else if (0 == rowBytes) {
172 rowBytes = (size_t)mrb;
reedf0aed972014-07-01 12:48:11 -0700173 } else if (!info.validRowBytes(rowBytes)) {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000174 return reset_return_false(this);
reed@google.com383a6972013-10-21 14:00:07 +0000175 }
176
177 this->freePixels();
178
reede5ea5002014-09-03 11:54:58 -0700179 fInfo = info.makeAlphaType(newAT);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000180 fRowBytes = SkToU32(rowBytes);
reed@google.com383a6972013-10-21 14:00:07 +0000181 return true;
reed@google.com383a6972013-10-21 14:00:07 +0000182}
183
reede5ea5002014-09-03 11:54:58 -0700184bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) {
185 if (!SkColorTypeValidateAlphaType(fInfo.colorType(), newAlphaType, &newAlphaType)) {
reed@google.com383a6972013-10-21 14:00:07 +0000186 return false;
187 }
reede5ea5002014-09-03 11:54:58 -0700188 if (fInfo.alphaType() != newAlphaType) {
189 fInfo = fInfo.makeAlphaType(newAlphaType);
commit-bot@chromium.org0e8d0d62014-01-27 15:41:07 +0000190 if (fPixelRef) {
reede5ea5002014-09-03 11:54:58 -0700191 fPixelRef->changeAlphaType(newAlphaType);
commit-bot@chromium.org0e8d0d62014-01-27 15:41:07 +0000192 }
193 }
reed@google.com383a6972013-10-21 14:00:07 +0000194 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195}
196
197void SkBitmap::updatePixelsFromRef() const {
bsalomon49f085d2014-09-05 13:34:00 -0700198 if (fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 if (fPixelLockCount > 0) {
reed@google.comff0da4f2012-05-17 13:14:52 +0000200 SkASSERT(fPixelRef->isLocked());
weita@google.comf9ab99a2009-05-03 18:23:30 +0000201
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 void* p = fPixelRef->pixels();
bsalomon49f085d2014-09-05 13:34:00 -0700203 if (p) {
reed@google.com672588b2014-01-08 15:42:01 +0000204 p = (char*)p
reed@google.com303c4752014-01-09 20:00:14 +0000205 + fPixelRefOrigin.fY * fRowBytes
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000206 + fPixelRefOrigin.fX * fInfo.bytesPerPixel();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 }
208 fPixels = p;
reed@google.com5f62ed72014-01-15 19:59:45 +0000209 fColorTable = fPixelRef->colorTable();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210 } else {
211 SkASSERT(0 == fPixelLockCount);
halcanary96fcdcc2015-08-27 07:41:13 -0700212 fPixels = nullptr;
213 fColorTable = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214 }
215 }
216}
217
Hal Canary1b3387b2016-12-12 13:48:12 -0500218#ifdef SK_SUPPORT_LEGACY_BITMAP_SETPIXELREF
reed@google.com672588b2014-01-08 15:42:01 +0000219SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500220 this->setPixelRef(sk_ref_sp(pr), dx, dy);
221 return pr;
222}
223#endif
224
225void SkBitmap::setPixelRef(sk_sp<SkPixelRef> pr, int dx, int dy) {
reed@google.comdcea5302014-01-03 13:43:01 +0000226#ifdef SK_DEBUG
reed@google.com672588b2014-01-08 15:42:01 +0000227 if (pr) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000228 if (kUnknown_SkColorType != fInfo.colorType()) {
reed@google.comdcea5302014-01-03 13:43:01 +0000229 const SkImageInfo& prInfo = pr->info();
reede5ea5002014-09-03 11:54:58 -0700230 SkASSERT(fInfo.width() <= prInfo.width());
231 SkASSERT(fInfo.height() <= prInfo.height());
232 SkASSERT(fInfo.colorType() == prInfo.colorType());
233 switch (prInfo.alphaType()) {
reed44977482015-02-27 10:23:00 -0800234 case kUnknown_SkAlphaType:
235 SkASSERT(fInfo.alphaType() == kUnknown_SkAlphaType);
reed@google.comdcea5302014-01-03 13:43:01 +0000236 break;
237 case kOpaque_SkAlphaType:
238 case kPremul_SkAlphaType:
reede5ea5002014-09-03 11:54:58 -0700239 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
240 fInfo.alphaType() == kPremul_SkAlphaType);
reed@google.comdcea5302014-01-03 13:43:01 +0000241 break;
242 case kUnpremul_SkAlphaType:
reede5ea5002014-09-03 11:54:58 -0700243 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
244 fInfo.alphaType() == kUnpremul_SkAlphaType);
reed@google.comdcea5302014-01-03 13:43:01 +0000245 break;
246 }
247 }
248 }
249#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250
reed@google.com672588b2014-01-08 15:42:01 +0000251 if (pr) {
252 const SkImageInfo& info = pr->info();
bungeman62ce0302015-08-28 09:09:32 -0700253 fPixelRefOrigin.set(SkTPin(dx, 0, info.width()), SkTPin(dy, 0, info.height()));
reed@google.com672588b2014-01-08 15:42:01 +0000254 } else {
255 // ignore dx,dy if there is no pixelref
256 fPixelRefOrigin.setZero();
257 }
258
259 if (fPixelRef != pr) {
piotaixr0eb02a62014-06-16 11:50:49 -0700260 this->freePixels();
Hal Canary1b3387b2016-12-12 13:48:12 -0500261 SkASSERT(!fPixelRef);
weita@google.comf9ab99a2009-05-03 18:23:30 +0000262
Hal Canary1b3387b2016-12-12 13:48:12 -0500263 fPixelRef = std::move(pr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264 this->updatePixelsFromRef();
265 }
266
267 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268}
269
270void SkBitmap::lockPixels() const {
bsalomon49f085d2014-09-05 13:34:00 -0700271 if (fPixelRef && 0 == sk_atomic_inc(&fPixelLockCount)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 fPixelRef->lockPixels();
273 this->updatePixelsFromRef();
274 }
275 SkDEBUGCODE(this->validate();)
276}
277
278void SkBitmap::unlockPixels() const {
Hal Canary1b3387b2016-12-12 13:48:12 -0500279 SkASSERT(!fPixelRef || fPixelLockCount > 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280
bsalomon49f085d2014-09-05 13:34:00 -0700281 if (fPixelRef && 1 == sk_atomic_dec(&fPixelLockCount)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282 fPixelRef->unlockPixels();
283 this->updatePixelsFromRef();
284 }
285 SkDEBUGCODE(this->validate();)
286}
287
reed@google.com9c49bc32011-07-07 13:42:37 +0000288bool SkBitmap::lockPixelsAreWritable() const {
Hal Canary1b3387b2016-12-12 13:48:12 -0500289 return fPixelRef ? fPixelRef->lockPixelsAreWritable() : false;
reed@google.com9c49bc32011-07-07 13:42:37 +0000290}
291
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700293 if (nullptr == p) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500294 this->setPixelRef(nullptr, 0, 0);
reed@google.com8e1034e2012-07-30 13:16:35 +0000295 return;
296 }
297
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000298 if (kUnknown_SkColorType == fInfo.colorType()) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500299 this->setPixelRef(nullptr, 0, 0);
reed@google.combf790232013-12-13 19:45:58 +0000300 return;
301 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302
Mike Reed6b3155c2017-04-03 14:41:44 -0400303 this->setPixelRef(SkMallocPixelRef::MakeDirect(fInfo, p, fRowBytes, sk_ref_sp(ctable)), 0, 0);
Hal Canary1b3387b2016-12-12 13:48:12 -0500304 if (!fPixelRef) {
reed@google.combf790232013-12-13 19:45:58 +0000305 return;
306 }
djsollen@google.comc84b8332012-07-27 13:41:44 +0000307 // since we're already allocated, we lockPixels right away
308 this->lockPixels();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000309 SkDEBUGCODE(this->validate();)
310}
311
reed84825042014-09-02 12:50:45 -0700312bool SkBitmap::tryAllocPixels(Allocator* allocator, SkColorTable* ctable) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 HeapAllocator stdalloc;
skia.committer@gmail.comd2ac07b2014-01-25 07:01:49 +0000314
halcanary96fcdcc2015-08-27 07:41:13 -0700315 if (nullptr == allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316 allocator = &stdalloc;
317 }
318 return allocator->allocPixelRef(this, ctable);
319}
320
reed@google.com9ebcac52014-01-24 18:53:42 +0000321///////////////////////////////////////////////////////////////////////////////
322
reed84825042014-09-02 12:50:45 -0700323bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
reedbae704b2014-06-28 14:26:35 -0700324 if (kIndex_8_SkColorType == requestedInfo.colorType()) {
325 return reset_return_false(this);
326 }
reedf0aed972014-07-01 12:48:11 -0700327 if (!this->setInfo(requestedInfo, rowBytes)) {
reedbae704b2014-06-28 14:26:35 -0700328 return reset_return_false(this);
329 }
mtklein775b8192014-12-02 09:11:25 -0800330
reedbae704b2014-06-28 14:26:35 -0700331 // setInfo may have corrected info (e.g. 565 is always opaque).
332 const SkImageInfo& correctedInfo = this->info();
reedf0aed972014-07-01 12:48:11 -0700333 // setInfo may have computed a valid rowbytes if 0 were passed in
334 rowBytes = this->rowBytes();
335
Mike Reed6b3155c2017-04-03 14:41:44 -0400336 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo, rowBytes, nullptr);
Hal Canary1b3387b2016-12-12 13:48:12 -0500337 if (!pr) {
reedbae704b2014-06-28 14:26:35 -0700338 return reset_return_false(this);
339 }
Hal Canary1b3387b2016-12-12 13:48:12 -0500340 this->setPixelRef(std::move(pr), 0, 0);
mtklein775b8192014-12-02 09:11:25 -0800341
halcanary96fcdcc2015-08-27 07:41:13 -0700342 // TODO: lockPixels could/should return bool or void*/nullptr
reedbae704b2014-06-28 14:26:35 -0700343 this->lockPixels();
halcanary96fcdcc2015-08-27 07:41:13 -0700344 if (nullptr == this->getPixels()) {
reedbae704b2014-06-28 14:26:35 -0700345 return reset_return_false(this);
346 }
347 return true;
348}
349
Mike Reed6b3155c2017-04-03 14:41:44 -0400350bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, sk_sp<SkColorTable> ctable,
351 uint32_t allocFlags) {
halcanary96fcdcc2015-08-27 07:41:13 -0700352 if (kIndex_8_SkColorType == requestedInfo.colorType() && nullptr == ctable) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000353 return reset_return_false(this);
354 }
scroggo0187dc22014-06-05 11:18:04 -0700355 if (!this->setInfo(requestedInfo)) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000356 return reset_return_false(this);
357 }
358
scroggo0187dc22014-06-05 11:18:04 -0700359 // setInfo may have corrected info (e.g. 565 is always opaque).
360 const SkImageInfo& correctedInfo = this->info();
361
Mike Reed6b3155c2017-04-03 14:41:44 -0400362 sk_sp<SkPixelRef> pr = (allocFlags & kZeroPixels_AllocFlag) ?
363 SkMallocPixelRef::MakeZeroed(correctedInfo, correctedInfo.minRowBytes(), ctable) :
364 SkMallocPixelRef::MakeAllocate(correctedInfo, correctedInfo.minRowBytes(), ctable);
Hal Canary1b3387b2016-12-12 13:48:12 -0500365 if (!pr) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000366 return reset_return_false(this);
367 }
Hal Canary1b3387b2016-12-12 13:48:12 -0500368 this->setPixelRef(std::move(pr), 0, 0);
reed@google.com9ebcac52014-01-24 18:53:42 +0000369
reed@google.com9ebcac52014-01-24 18:53:42 +0000370 this->lockPixels();
halcanary96fcdcc2015-08-27 07:41:13 -0700371 if (nullptr == this->getPixels()) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000372 return reset_return_false(this);
373 }
374 return true;
375}
376
reeddb74f622015-05-30 13:41:15 -0700377static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
378 if (proc) {
379 proc(pixels, ctx);
380 }
381}
382
scroggo0187dc22014-06-05 11:18:04 -0700383bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
384 SkColorTable* ct, void (*releaseProc)(void* addr, void* context),
385 void* context) {
386 if (!this->setInfo(requestedInfo, rb)) {
reeddb74f622015-05-30 13:41:15 -0700387 invoke_release_proc(releaseProc, pixels, context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000388 this->reset();
389 return false;
390 }
halcanary96fcdcc2015-08-27 07:41:13 -0700391 if (nullptr == pixels) {
reeddb74f622015-05-30 13:41:15 -0700392 invoke_release_proc(releaseProc, pixels, context);
393 return true; // we behaved as if they called setInfo()
394 }
reed@google.com9ebcac52014-01-24 18:53:42 +0000395
scroggo0187dc22014-06-05 11:18:04 -0700396 // setInfo may have corrected info (e.g. 565 is always opaque).
397 const SkImageInfo& correctedInfo = this->info();
398
Mike Reed6b3155c2017-04-03 14:41:44 -0400399 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithProc(correctedInfo, rb, sk_ref_sp(ct),
400 pixels, releaseProc, context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000401 if (!pr) {
402 this->reset();
403 return false;
404 }
405
Hal Canary1b3387b2016-12-12 13:48:12 -0500406 this->setPixelRef(std::move(pr), 0, 0);
mike@reedtribe.org6e58cf32014-02-16 20:54:21 +0000407
408 // since we're already allocated, we lockPixels right away
409 this->lockPixels();
mike@reedtribe.org6e58cf32014-02-16 20:54:21 +0000410 SkDEBUGCODE(this->validate();)
reed@google.com9ebcac52014-01-24 18:53:42 +0000411 return true;
412}
413
halcanarye36ec872015-12-09 11:36:59 -0800414bool SkBitmap::installPixels(const SkPixmap& pixmap) {
415 return this->installPixels(pixmap.info(), pixmap.writable_addr(),
416 pixmap.rowBytes(), pixmap.ctable(),
417 nullptr, nullptr);
418}
419
commit-bot@chromium.orgdac52252014-02-17 21:21:46 +0000420bool SkBitmap::installMaskPixels(const SkMask& mask) {
421 if (SkMask::kA8_Format != mask.fFormat) {
422 this->reset();
423 return false;
424 }
425 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
426 mask.fBounds.height()),
427 mask.fImage, mask.fRowBytes);
428}
429
reed@google.comeb9a46c2014-01-25 16:46:20 +0000430///////////////////////////////////////////////////////////////////////////////
431
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432void SkBitmap::freePixels() {
bsalomon49f085d2014-09-05 13:34:00 -0700433 if (fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434 if (fPixelLockCount > 0) {
435 fPixelRef->unlockPixels();
436 }
halcanary96fcdcc2015-08-27 07:41:13 -0700437 fPixelRef = nullptr;
reed@google.com672588b2014-01-08 15:42:01 +0000438 fPixelRefOrigin.setZero();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000439 }
440 fPixelLockCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700441 fPixels = nullptr;
442 fColorTable = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443}
444
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445uint32_t SkBitmap::getGenerationID() const {
Hal Canary1b3387b2016-12-12 13:48:12 -0500446 return fPixelRef ? fPixelRef->getGenerationID() : 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000447}
448
449void SkBitmap::notifyPixelsChanged() const {
junov@chromium.orgb0521292011-12-15 20:14:06 +0000450 SkASSERT(!this->isImmutable());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000451 if (fPixelRef) {
452 fPixelRef->notifyPixelsChanged();
453 }
454}
455
456///////////////////////////////////////////////////////////////////////////////
457
reed@android.com8a1c16f2008-12-17 15:59:43 +0000458/** We explicitly use the same allocator for our pixels that SkMask does,
459 so that we can freely assign memory allocated by one class to the other.
460 */
461bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
462 SkColorTable* ctable) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000463 const SkImageInfo info = dst->info();
464 if (kUnknown_SkColorType == info.colorType()) {
reed@google.combf790232013-12-13 19:45:58 +0000465// SkDebugf("unsupported config for info %d\n", dst->config());
466 return false;
467 }
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000468
Mike Reed6b3155c2017-04-03 14:41:44 -0400469 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes(), sk_ref_sp(ctable));
Hal Canary1b3387b2016-12-12 13:48:12 -0500470 if (!pr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000471 return false;
472 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000473
Hal Canary1b3387b2016-12-12 13:48:12 -0500474 dst->setPixelRef(std::move(pr), 0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000475 // since we're already allocated, we lockPixels right away
476 dst->lockPixels();
477 return true;
478}
479
480///////////////////////////////////////////////////////////////////////////////
481
reed92fc2ae2015-05-22 08:06:21 -0700482static bool copy_pixels_to(const SkPixmap& src, void* const dst, size_t dstSize,
483 size_t dstRowBytes, bool preserveDstPad) {
484 const SkImageInfo& info = src.info();
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000485
scroggo@google.com0ba4bf42013-02-25 16:02:36 +0000486 if (0 == dstRowBytes) {
reed92fc2ae2015-05-22 08:06:21 -0700487 dstRowBytes = src.rowBytes();
scroggo@google.com0ba4bf42013-02-25 16:02:36 +0000488 }
reed92fc2ae2015-05-22 08:06:21 -0700489 if (dstRowBytes < info.minRowBytes()) {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000490 return false;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000491 }
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000492
reed92fc2ae2015-05-22 08:06:21 -0700493 if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == src.rowBytes()) {
494 size_t safeSize = src.getSafeSize();
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000495 if (safeSize > dstSize || safeSize == 0)
496 return false;
497 else {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000498 // This implementation will write bytes beyond the end of each row,
499 // excluding the last row, if the bitmap's stride is greater than
500 // strictly required by the current config.
reed92fc2ae2015-05-22 08:06:21 -0700501 memcpy(dst, src.addr(), safeSize);
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000502 return true;
503 }
504 } else {
505 // If destination has different stride than us, then copy line by line.
reed92fc2ae2015-05-22 08:06:21 -0700506 if (info.getSafeSize(dstRowBytes) > dstSize) {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000507 return false;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000508 } else {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000509 // Just copy what we need on each line.
reed92fc2ae2015-05-22 08:06:21 -0700510 size_t rowBytes = info.minRowBytes();
511 const uint8_t* srcP = reinterpret_cast<const uint8_t*>(src.addr());
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000512 uint8_t* dstP = reinterpret_cast<uint8_t*>(dst);
reed92fc2ae2015-05-22 08:06:21 -0700513 for (int row = 0; row < info.height(); ++row) {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000514 memcpy(dstP, srcP, rowBytes);
reed92fc2ae2015-05-22 08:06:21 -0700515 srcP += src.rowBytes();
516 dstP += dstRowBytes;
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000517 }
518
519 return true;
520 }
521 }
522}
523
reed92fc2ae2015-05-22 08:06:21 -0700524bool SkBitmap::copyPixelsTo(void* dst, size_t dstSize, size_t dstRB, bool preserveDstPad) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700525 if (nullptr == dst) {
reed92fc2ae2015-05-22 08:06:21 -0700526 return false;
527 }
528 SkAutoPixmapUnlock result;
529 if (!this->requestLock(&result)) {
530 return false;
531 }
532 return copy_pixels_to(result.pixmap(), dst, dstSize, dstRB, preserveDstPad);
533}
534
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000535///////////////////////////////////////////////////////////////////////////////
536
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000537bool SkBitmap::isImmutable() const {
scroggo08470592014-07-15 19:56:48 -0700538 return fPixelRef ? fPixelRef->isImmutable() : false;
junov@chromium.orgb0521292011-12-15 20:14:06 +0000539}
540
541void SkBitmap::setImmutable() {
542 if (fPixelRef) {
543 fPixelRef->setImmutable();
junov@chromium.orgb0521292011-12-15 20:14:06 +0000544 }
545}
546
junov@google.com4ee7ae52011-06-30 17:30:49 +0000547bool SkBitmap::isVolatile() const {
548 return (fFlags & kImageIsVolatile_Flag) != 0;
549}
550
551void SkBitmap::setIsVolatile(bool isVolatile) {
552 if (isVolatile) {
553 fFlags |= kImageIsVolatile_Flag;
554 } else {
555 fFlags &= ~kImageIsVolatile_Flag;
556 }
557}
558
reed@android.com8a1c16f2008-12-17 15:59:43 +0000559void* SkBitmap::getAddr(int x, int y) const {
560 SkASSERT((unsigned)x < (unsigned)this->width());
561 SkASSERT((unsigned)y < (unsigned)this->height());
562
563 char* base = (char*)this->getPixels();
564 if (base) {
565 base += y * this->rowBytes();
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000566 switch (this->colorType()) {
mtklein7fd93e32016-07-26 13:05:30 -0700567 case kRGBA_F16_SkColorType:
568 base += x << 3;
569 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000570 case kRGBA_8888_SkColorType:
571 case kBGRA_8888_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000572 base += x << 2;
573 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000574 case kARGB_4444_SkColorType:
575 case kRGB_565_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576 base += x << 1;
577 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000578 case kAlpha_8_SkColorType:
579 case kIndex_8_SkColorType:
reed0c9b1a82015-03-17 17:44:06 -0700580 case kGray_8_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000581 base += x;
582 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000583 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000584 SkDEBUGFAIL("Can't return addr for config");
halcanary96fcdcc2015-08-27 07:41:13 -0700585 base = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000586 break;
587 }
588 }
589 return base;
590}
591
592///////////////////////////////////////////////////////////////////////////////
593///////////////////////////////////////////////////////////////////////////////
594
reed7aefe032015-06-08 10:22:22 -0700595void SkBitmap::erase(SkColor c, const SkIRect& area) const {
reed92fc2ae2015-05-22 08:06:21 -0700596 SkDEBUGCODE(this->validate();)
reed92fc2ae2015-05-22 08:06:21 -0700597
598 switch (fInfo.colorType()) {
599 case kUnknown_SkColorType:
600 case kIndex_8_SkColorType:
601 // TODO: can we ASSERT that we never get here?
602 return; // can't erase. Should we bzero so the memory is not uninitialized?
603 default:
604 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000605 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000606
reed92fc2ae2015-05-22 08:06:21 -0700607 SkAutoPixmapUnlock result;
608 if (!this->requestLock(&result)) {
609 return;
610 }
611
reed7aefe032015-06-08 10:22:22 -0700612 if (result.pixmap().erase(c, area)) {
reed92fc2ae2015-05-22 08:06:21 -0700613 this->notifyPixelsChanged();
614 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615}
616
reed7aefe032015-06-08 10:22:22 -0700617void SkBitmap::eraseColor(SkColor c) const {
618 this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
reed@google.com60d32352013-06-28 19:40:50 +0000619}
620
reed@android.com8a1c16f2008-12-17 15:59:43 +0000621//////////////////////////////////////////////////////////////////////////////////////
622//////////////////////////////////////////////////////////////////////////////////////
623
reed@android.com8a1c16f2008-12-17 15:59:43 +0000624bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
625 SkDEBUGCODE(this->validate();)
626
Hal Canary1b3387b2016-12-12 13:48:12 -0500627 if (nullptr == result || !fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628 return false; // no src pixels
629 }
630
631 SkIRect srcRect, r;
632 srcRect.set(0, 0, this->width(), this->height());
633 if (!r.intersect(srcRect, subset)) {
634 return false; // r is empty (i.e. no intersection)
635 }
636
scroggo@google.coma2a31922012-12-07 19:14:45 +0000637 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
638 // exited above.
639 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
640 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
641
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642 SkBitmap dst;
herbb5d74682016-04-21 08:45:39 -0700643 dst.setInfo(this->info().makeWH(r.width(), r.height()), this->rowBytes());
skyostil@google.com0eb75762012-01-16 10:45:53 +0000644 dst.setIsVolatile(this->isVolatile());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000645
646 if (fPixelRef) {
reed@google.com672588b2014-01-08 15:42:01 +0000647 SkIPoint origin = fPixelRefOrigin;
648 origin.fX += r.fLeft;
649 origin.fY += r.fTop;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000650 // share the pixelref with a custom offset
Hal Canary1b3387b2016-12-12 13:48:12 -0500651 dst.setPixelRef(fPixelRef, origin.x(), origin.y());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000652 }
653 SkDEBUGCODE(dst.validate();)
654
655 // we know we're good, so commit to result
656 result->swap(dst);
657 return true;
658}
659
660///////////////////////////////////////////////////////////////////////////////
661
Mike Reed22f34822016-11-28 17:17:38 -0500662bool SkBitmap::canCopyTo(SkColorType dstCT) const {
reedb184f7f2014-07-13 04:32:32 -0700663 const SkColorType srcCT = this->colorType();
664
665 if (srcCT == kUnknown_SkColorType) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666 return false;
667 }
Mike Reed22f34822016-11-28 17:17:38 -0500668 if (srcCT == kAlpha_8_SkColorType && dstCT != kAlpha_8_SkColorType) {
669 return false; // can't convert from alpha to non-alpha
670 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000671
Mike Reed22f34822016-11-28 17:17:38 -0500672 bool sameConfigs = (srcCT == dstCT);
673 switch (dstCT) {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000674 case kAlpha_8_SkColorType:
675 case kRGB_565_SkColorType:
commit-bot@chromium.org60b5dce2014-04-22 20:24:33 +0000676 case kRGBA_8888_SkColorType:
677 case kBGRA_8888_SkColorType:
Matt Sarettd9836f42017-04-05 15:41:53 -0400678 case kRGBA_F16_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679 break;
Matt Sarettcb6266b2017-01-17 10:48:53 -0500680 case kGray_8_SkColorType:
weita@google.comf9ab99a2009-05-03 18:23:30 +0000681 if (!sameConfigs) {
682 return false;
683 }
684 break;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000685 case kARGB_4444_SkColorType:
reedb184f7f2014-07-13 04:32:32 -0700686 return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687 default:
688 return false;
689 }
reed@android.comfbaa88d2009-05-06 17:44:34 +0000690 return true;
691}
692
reedb184f7f2014-07-13 04:32:32 -0700693bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
694 int x, int y) const {
reed95d343f2015-05-23 13:21:06 -0700695 SkAutoPixmapUnlock src;
696 if (!this->requestLock(&src)) {
reedb184f7f2014-07-13 04:32:32 -0700697 return false;
698 }
reed95d343f2015-05-23 13:21:06 -0700699 return src.pixmap().readPixels(requestedDstInfo, dstPixels, dstRB, x, y);
reedb184f7f2014-07-13 04:32:32 -0700700}
701
Mike Reed68dd8d02017-01-04 16:34:31 -0500702bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
703 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
704}
705
Matt Sarettd2adc662017-03-27 15:07:35 -0400706bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY,
707 SkTransferFunctionBehavior behavior) {
Mike Reed68dd8d02017-01-04 16:34:31 -0500708 SkAutoPixmapUnlock dst;
709 if (!this->requestLock(&dst)) {
710 return false;
711 }
712
Matt Sarett03dd6d52017-01-23 12:15:09 -0500713 if (!SkImageInfoValidConversion(fInfo, src.info())) {
Mike Reed68dd8d02017-01-04 16:34:31 -0500714 return false;
715 }
716
Matt Sarett03dd6d52017-01-23 12:15:09 -0500717 SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY);
718 if (!rec.trim(fInfo.width(), fInfo.height())) {
719 return false;
720 }
721
722 void* dstPixels = this->getAddr(rec.fX, rec.fY);
723 const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
Matt Sarett485c4992017-02-14 14:18:27 -0500724 SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes,
Matt Sarettd2adc662017-03-27 15:07:35 -0400725 src.ctable(), behavior);
Matt Sarett8572d852017-02-14 11:21:02 -0500726 return true;
Mike Reed68dd8d02017-01-04 16:34:31 -0500727}
728
reedb184f7f2014-07-13 04:32:32 -0700729bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000730 if (!this->canCopyTo(dstColorType)) {
reed@android.comfbaa88d2009-05-06 17:44:34 +0000731 return false;
732 }
733
reed95d343f2015-05-23 13:21:06 -0700734 SkAutoPixmapUnlock srcUnlocker;
Matt Sarett19873662017-04-05 13:36:08 -0400735 if (!this->requestLock(&srcUnlocker)) {
reed@google.com50dfa012011-04-01 19:05:36 +0000736 return false;
737 }
Matt Sarettcb6266b2017-01-17 10:48:53 -0500738 SkPixmap srcPM = srcUnlocker.pixmap();
Matt Sarettd9836f42017-04-05 15:41:53 -0400739
740 // Various Android specific compatibility modes.
741 // TODO:
742 // Move the logic of this entire function into the framework, then call readPixels() directly.
743 SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType);
744 switch (dstColorType) {
745 case kRGB_565_SkColorType:
746 // copyTo() is not strict on alpha type. Here we set the src to opaque to allow
747 // the call to readPixels() to succeed and preserve this lenient behavior.
748 if (kOpaque_SkAlphaType != srcPM.alphaType()) {
749 srcPM = SkPixmap(srcPM.info().makeAlphaType(kOpaque_SkAlphaType), srcPM.addr(),
750 srcPM.rowBytes(), srcPM.ctable());
751 dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
752 }
753 break;
754 case kRGBA_F16_SkColorType:
755 // The caller does not have an opportunity to pass a dst color space. Assume that
756 // they want linear sRGB.
757 dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
758
759 if (!srcPM.colorSpace()) {
760 // We can't do a sane conversion to F16 without a dst color space. Guess sRGB
761 // in this case.
762 srcPM.setColorSpace(SkColorSpace::MakeSRGB());
763 }
764 break;
765 default:
766 break;
Matt Sarettcb6266b2017-01-17 10:48:53 -0500767 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000768
reed@google.com50dfa012011-04-01 19:05:36 +0000769 SkBitmap tmpDst;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000770 if (!tmpDst.setInfo(dstInfo)) {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000771 return false;
772 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000773
weita@google.comf9ab99a2009-05-03 18:23:30 +0000774 // allocate colortable if srcConfig == kIndex8_Config
Hal Canary704cd322016-11-07 14:13:52 -0500775 sk_sp<SkColorTable> ctable;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000776 if (dstColorType == kIndex_8_SkColorType) {
reed95d343f2015-05-23 13:21:06 -0700777 ctable.reset(SkRef(srcPM.ctable()));
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000778 }
Hal Canary704cd322016-11-07 14:13:52 -0500779 if (!tmpDst.tryAllocPixels(alloc, ctable.get())) {
weita@google.comf9ab99a2009-05-03 18:23:30 +0000780 return false;
781 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000782
reed95d343f2015-05-23 13:21:06 -0700783 SkAutoPixmapUnlock dstUnlocker;
784 if (!tmpDst.requestLock(&dstUnlocker)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000785 return false;
786 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000787
Matt Sarettd9836f42017-04-05 15:41:53 -0400788 SkPixmap dstPM = dstUnlocker.pixmap();
789
790 // We can't do a sane conversion from F16 without a src color space. Guess sRGB in this case.
791 if (kRGBA_F16_SkColorType == srcPM.colorType() && !dstPM.colorSpace()) {
792 dstPM.setColorSpace(SkColorSpace::MakeSRGB());
793 }
794
795 // readPixels does not yet support color spaces with parametric transfer functions. This
796 // works around that restriction when the color spaces are equal.
797 if (kRGBA_F16_SkColorType != dstColorType && kRGBA_F16_SkColorType != srcPM.colorType() &&
798 dstPM.colorSpace() == srcPM.colorSpace()) {
799 dstPM.setColorSpace(nullptr);
800 srcPM.setColorSpace(nullptr);
801 }
802
803 if (!srcPM.readPixels(dstPM)) {
reedb184f7f2014-07-13 04:32:32 -0700804 return false;
805 }
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000806
reedb184f7f2014-07-13 04:32:32 -0700807 // (for BitmapHeap) Clone the pixelref genID even though we have a new pixelref.
808 // The old copyTo impl did this, so we continue it for now.
809 //
810 // TODO: should we ignore rowbytes (i.e. getSize)? Then it could just be
811 // if (src_pixelref->info == dst_pixelref->info)
812 //
reed95d343f2015-05-23 13:21:06 -0700813 if (srcPM.colorType() == dstColorType && tmpDst.getSize() == srcPM.getSize64()) {
reedb184f7f2014-07-13 04:32:32 -0700814 SkPixelRef* dstPixelRef = tmpDst.pixelRef();
815 if (dstPixelRef->info() == fPixelRef->info()) {
816 dstPixelRef->cloneGenID(*fPixelRef);
reed@android.com311c82d2009-05-05 23:13:23 +0000817 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000818 }
819
reed@google.com50dfa012011-04-01 19:05:36 +0000820 dst->swap(tmpDst);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821 return true;
822}
823
reedc7ec7c92016-07-25 08:29:10 -0700824// TODO: can we merge this with copyTo?
commit-bot@chromium.orgfab349c2014-03-05 02:34:58 +0000825bool SkBitmap::deepCopyTo(SkBitmap* dst) const {
reede4538f52014-06-11 06:09:50 -0700826 const SkColorType dstCT = this->colorType();
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000827
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000828 if (!this->canCopyTo(dstCT)) {
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000829 return false;
830 }
reedc7ec7c92016-07-25 08:29:10 -0700831 return this->copyTo(dst, dstCT, nullptr);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000832}
833
reed@android.com8a1c16f2008-12-17 15:59:43 +0000834///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000835
reed92fc2ae2015-05-22 08:06:21 -0700836static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
halcanary96fcdcc2015-08-27 07:41:13 -0700837 SkASSERT(alpha != nullptr);
reed92fc2ae2015-05-22 08:06:21 -0700838 SkASSERT(alphaRowBytes >= src.width());
839
840 SkAutoPixmapUnlock apl;
841 if (!src.requestLock(&apl)) {
lsalzmana2415ac2016-10-11 14:29:12 -0700842 for (int y = 0; y < src.height(); ++y) {
843 memset(alpha, 0, src.width());
844 alpha += alphaRowBytes;
845 }
reed92fc2ae2015-05-22 08:06:21 -0700846 return false;
847 }
lsalzmana2415ac2016-10-11 14:29:12 -0700848 const SkPixmap& pmap = apl.pixmap();
Matt Sarett485c4992017-02-14 14:18:27 -0500849 SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
Matt Sarettd2adc662017-03-27 15:07:35 -0400850 pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable(),
851 SkTransferFunctionBehavior::kRespect);
reed@android.com1cdcb512009-08-24 19:11:00 +0000852 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000853}
854
855#include "SkPaint.h"
856#include "SkMaskFilter.h"
857#include "SkMatrix.h"
858
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000859bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
djsollen@google.com57f49692011-02-23 20:46:31 +0000860 Allocator *allocator, SkIPoint* offset) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000861 SkDEBUGCODE(this->validate();)
862
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000863 SkBitmap tmpBitmap;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000864 SkMatrix identity;
865 SkMask srcM, dstM;
866
867 srcM.fBounds.set(0, 0, this->width(), this->height());
868 srcM.fRowBytes = SkAlign4(this->width());
869 srcM.fFormat = SkMask::kA8_Format;
870
halcanary96fcdcc2015-08-27 07:41:13 -0700871 SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000872
873 // compute our (larger?) dst bounds if we have a filter
bsalomon49f085d2014-09-05 13:34:00 -0700874 if (filter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000875 identity.reset();
halcanary96fcdcc2015-08-27 07:41:13 -0700876 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000877 goto NO_FILTER_CASE;
878 }
879 dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
880 } else {
881 NO_FILTER_CASE:
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000882 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -0700883 if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000884 // Allocation of pixels for alpha bitmap failed.
885 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
886 tmpBitmap.width(), tmpBitmap.height());
887 return false;
888 }
889 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000890 if (offset) {
891 offset->set(0, 0);
892 }
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000893 tmpBitmap.swap(*dst);
894 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000895 }
bungeman@google.com02f55842011-10-04 21:25:00 +0000896 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
897 SkAutoMaskFreeImage srcCleanup(srcM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000898
899 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -0700900 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000901 goto NO_FILTER_CASE;
902 }
bungeman@google.com02f55842011-10-04 21:25:00 +0000903 SkAutoMaskFreeImage dstCleanup(dstM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000904
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000905 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
906 dstM.fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -0700907 if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000908 // Allocation of pixels for alpha bitmap failed.
909 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
910 tmpBitmap.width(), tmpBitmap.height());
911 return false;
912 }
913 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000914 if (offset) {
915 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
916 }
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000917 SkDEBUGCODE(tmpBitmap.validate();)
918
919 tmpBitmap.swap(*dst);
920 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000921}
922
923///////////////////////////////////////////////////////////////////////////////
924
reed92fc2ae2015-05-22 08:06:21 -0700925static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) {
926 const SkImageInfo& info = pmap.info();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000927 const size_t snugRB = info.width() * info.bytesPerPixel();
reed92fc2ae2015-05-22 08:06:21 -0700928 const char* src = (const char*)pmap.addr();
929 const size_t ramRB = pmap.rowBytes();
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +0000930
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000931 buffer->write32(SkToU32(snugRB));
932 info.flatten(*buffer);
933
934 const size_t size = snugRB * info.height();
scroggo565901d2015-12-10 10:44:13 -0800935 SkAutoTMalloc<char> storage(size);
936 char* dst = storage.get();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000937 for (int y = 0; y < info.height(); ++y) {
938 memcpy(dst, src, snugRB);
939 dst += snugRB;
940 src += ramRB;
941 }
942 buffer->writeByteArray(storage.get(), size);
943
reed92fc2ae2015-05-22 08:06:21 -0700944 const SkColorTable* ct = pmap.ctable();
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000945 if (kIndex_8_SkColorType == info.colorType() && ct) {
946 buffer->writeBool(true);
947 ct->writeToBuffer(*buffer);
948 } else {
949 buffer->writeBool(false);
950 }
951}
952
reed92fc2ae2015-05-22 08:06:21 -0700953void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) {
954 const SkImageInfo info = bitmap.info();
Hal Canary1b3387b2016-12-12 13:48:12 -0500955 if (0 == info.width() || 0 == info.height() || bitmap.isNull()) {
reed92fc2ae2015-05-22 08:06:21 -0700956 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
957 return;
958 }
959
960 SkAutoPixmapUnlock result;
961 if (!bitmap.requestLock(&result)) {
962 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
963 return;
964 }
965
966 write_raw_pixels(buffer, result.pixmap());
967}
968
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000969bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) {
970 const size_t snugRB = buffer->readUInt();
971 if (0 == snugRB) { // no pixels
972 return false;
973 }
974
975 SkImageInfo info;
976 info.unflatten(*buffer);
977
Robert Phillipsb2cb5352016-12-20 12:44:41 -0500978 if (info.width() < 0 || info.height() < 0) {
979 return false;
980 }
981
mtklein58e389b2016-07-15 07:00:11 -0700982 // If there was an error reading "info" or if it is bogus,
robertphillips74139f12016-06-28 09:04:34 -0700983 // don't use it to compute minRowBytes()
984 if (!buffer->validate(SkColorTypeValidateAlphaType(info.colorType(),
985 info.alphaType()))) {
sugoica95c192014-07-08 09:18:48 -0700986 return false;
987 }
988
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000989 const size_t ramRB = info.minRowBytes();
sugoibd0d9da2015-01-07 08:47:44 -0800990 const int height = SkMax32(info.height(), 0);
991 const uint64_t snugSize = sk_64_mul(snugRB, height);
992 const uint64_t ramSize = sk_64_mul(ramRB, height);
993 static const uint64_t max_size_t = (size_t)(-1);
994 if (!buffer->validate((snugSize <= ramSize) && (ramSize <= max_size_t))) {
commit-bot@chromium.org05858432014-05-30 01:06:44 +0000995 return false;
996 }
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000997
reedfde05112016-03-11 13:02:28 -0800998 sk_sp<SkData> data(SkData::MakeUninitialized(SkToSizeT(ramSize)));
robertphillips28937842015-06-08 07:10:49 -0700999 unsigned char* dst = (unsigned char*)data->writable_data();
sugoibd0d9da2015-01-07 08:47:44 -08001000 buffer->readByteArray(dst, SkToSizeT(snugSize));
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001001
1002 if (snugSize != ramSize) {
robertphillips28937842015-06-08 07:10:49 -07001003 const unsigned char* srcRow = dst + snugRB * (height - 1);
1004 unsigned char* dstRow = dst + ramRB * (height - 1);
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001005 for (int y = height - 1; y >= 1; --y) {
1006 memmove(dstRow, srcRow, snugRB);
1007 srcRow -= snugRB;
1008 dstRow -= ramRB;
1009 }
1010 SkASSERT(srcRow == dstRow); // first row does not need to be moved
1011 }
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +00001012
Hal Canary704cd322016-11-07 14:13:52 -05001013 sk_sp<SkColorTable> ctable;
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001014 if (buffer->readBool()) {
Mike Reed6b3155c2017-04-03 14:41:44 -04001015 ctable = SkColorTable::Create(*buffer);
reedb236d1a2015-08-28 10:14:18 -07001016 if (!ctable) {
1017 return false;
1018 }
robertphillips28937842015-06-08 07:10:49 -07001019
reedb236d1a2015-08-28 10:14:18 -07001020 if (info.isEmpty()) {
1021 // require an empty ctable
1022 if (ctable->count() != 0) {
1023 buffer->validate(false);
1024 return false;
1025 }
1026 } else {
1027 // require a non-empty ctable
1028 if (ctable->count() == 0) {
1029 buffer->validate(false);
1030 return false;
1031 }
1032 unsigned char maxIndex = ctable->count() - 1;
1033 for (uint64_t i = 0; i < ramSize; ++i) {
1034 dst[i] = SkTMin(dst[i], maxIndex);
1035 }
robertphillips28937842015-06-08 07:10:49 -07001036 }
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001037 }
skia.committer@gmail.com3c134a92014-05-24 03:05:26 +00001038
Mike Reed6b3155c2017-04-03 14:41:44 -04001039 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithData(info, info.minRowBytes(),
1040 std::move(ctable), std::move(data));
1041 if (!pr) {
sugoi6af31472015-01-28 13:15:32 -08001042 return false;
1043 }
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +00001044 bitmap->setInfo(pr->info());
Hal Canary1b3387b2016-12-12 13:48:12 -05001045 bitmap->setPixelRef(std::move(pr), 0, 0);
commit-bot@chromium.org968edca2014-05-23 13:21:55 +00001046 return true;
1047}
1048
reed@android.com8a1c16f2008-12-17 15:59:43 +00001049enum {
1050 SERIALIZE_PIXELTYPE_NONE,
djsollen@google.com21830d92012-08-07 19:49:41 +00001051 SERIALIZE_PIXELTYPE_REF_DATA
reed@android.com8a1c16f2008-12-17 15:59:43 +00001052};
1053
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054///////////////////////////////////////////////////////////////////////////////
1055
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056#ifdef SK_DEBUG
1057void SkBitmap::validate() const {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001058 fInfo.validate();
commit-bot@chromium.orgd5414e52014-02-13 22:30:38 +00001059
1060 // ImageInfo may not require this, but Bitmap ensures that opaque-only
1061 // colorTypes report opaque for their alphatype
1062 if (kRGB_565_SkColorType == fInfo.colorType()) {
1063 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
1064 }
1065
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001066 SkASSERT(fInfo.validRowBytes(fRowBytes));
scroggo08470592014-07-15 19:56:48 -07001067 uint8_t allFlags = kImageIsVolatile_Flag;
scroggo@google.com8e990eb2013-06-14 15:55:56 +00001068#ifdef SK_BUILD_FOR_ANDROID
1069 allFlags |= kHasHardwareMipMap_Flag;
1070#endif
scroggo08470592014-07-15 19:56:48 -07001071 SkASSERT((~allFlags & fFlags) == 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072 SkASSERT(fPixelLockCount >= 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001073
reed@google.com615316c2014-01-15 19:15:23 +00001074 if (fPixels) {
1075 SkASSERT(fPixelRef);
robertphillipse77dadd2014-11-21 05:50:21 -08001076 SkASSERT(fPixelLockCount > 0);
reed@google.com615316c2014-01-15 19:15:23 +00001077 SkASSERT(fPixelRef->isLocked());
1078 SkASSERT(fPixelRef->rowBytes() == fRowBytes);
1079 SkASSERT(fPixelRefOrigin.fX >= 0);
1080 SkASSERT(fPixelRefOrigin.fY >= 0);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001081 SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX);
reede5ea5002014-09-03 11:54:58 -07001082 SkASSERT(fPixelRef->info().height() >= (int)this->height() + fPixelRefOrigin.fY);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001083 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
reed@google.com615316c2014-01-15 19:15:23 +00001084 } else {
halcanary96fcdcc2015-08-27 07:41:13 -07001085 SkASSERT(nullptr == fColorTable);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087}
1088#endif
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001089
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001090#ifndef SK_IGNORE_TO_STRING
bungemand3ebb482015-08-05 13:57:49 -07001091#include "SkString.h"
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001092void SkBitmap::toString(SkString* str) const {
1093
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +00001094 static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = {
1095 "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8",
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001096 };
1097
1098 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +00001099 gColorTypeNames[this->colorType()]);
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001100
1101 str->append(" (");
1102 if (this->isOpaque()) {
1103 str->append("opaque");
1104 } else {
1105 str->append("transparent");
1106 }
1107 if (this->isImmutable()) {
1108 str->append(", immutable");
1109 } else {
1110 str->append(", not-immutable");
1111 }
1112 str->append(")");
1113
1114 SkPixelRef* pr = this->pixelRef();
halcanary96fcdcc2015-08-27 07:41:13 -07001115 if (nullptr == pr) {
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001116 // show null or the explicit pixel address (rare)
1117 str->appendf(" pixels:%p", this->getPixels());
1118 } else {
1119 const char* uri = pr->getURI();
bsalomon49f085d2014-09-05 13:34:00 -07001120 if (uri) {
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001121 str->appendf(" uri:\"%s\"", uri);
1122 } else {
1123 str->appendf(" pixelref:%p", pr);
1124 }
1125 }
1126
1127 str->append(")");
1128}
1129#endif
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001130
1131///////////////////////////////////////////////////////////////////////////////
1132
reed92fc2ae2015-05-22 08:06:21 -07001133bool SkBitmap::requestLock(SkAutoPixmapUnlock* result) const {
1134 SkASSERT(result);
1135
Hal Canary1b3387b2016-12-12 13:48:12 -05001136 SkPixelRef* pr = fPixelRef.get();
halcanary96fcdcc2015-08-27 07:41:13 -07001137 if (nullptr == pr) {
reed92fc2ae2015-05-22 08:06:21 -07001138 return false;
1139 }
1140
reed871872f2015-06-22 12:48:26 -07001141 // We have to lock the whole thing (using the pixelref's dimensions) until the api supports
1142 // a partial lock (with offset/origin). Hence we can't use our fInfo.
1143 SkPixelRef::LockRequest req = { pr->info().dimensions(), kNone_SkFilterQuality };
reed92fc2ae2015-05-22 08:06:21 -07001144 SkPixelRef::LockResult res;
1145 if (pr->requestLock(req, &res)) {
reede8006572015-05-28 14:06:06 -07001146 SkASSERT(res.fPixels);
reed92fc2ae2015-05-22 08:06:21 -07001147 // The bitmap may be a subset of the pixelref's dimensions
1148 SkASSERT(fPixelRefOrigin.x() + fInfo.width() <= res.fSize.width());
1149 SkASSERT(fPixelRefOrigin.y() + fInfo.height() <= res.fSize.height());
1150 const void* addr = (const char*)res.fPixels + SkColorTypeComputeOffset(fInfo.colorType(),
1151 fPixelRefOrigin.x(),
1152 fPixelRefOrigin.y(),
1153 res.fRowBytes);
1154
1155 result->reset(SkPixmap(this->info(), addr, res.fRowBytes, res.fCTable),
1156 res.fUnlockProc, res.fUnlockContext);
1157 return true;
1158 }
1159 return false;
1160}
1161
reedcb674142015-06-05 06:58:22 -07001162bool SkBitmap::peekPixels(SkPixmap* pmap) const {
1163 if (fPixels) {
1164 if (pmap) {
1165 pmap->reset(fInfo, fPixels, fRowBytes, fColorTable);
1166 }
1167 return true;
1168 }
1169 return false;
1170}
1171
reed92fc2ae2015-05-22 08:06:21 -07001172///////////////////////////////////////////////////////////////////////////////
1173
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001174#ifdef SK_DEBUG
1175void SkImageInfo::validate() const {
1176 SkASSERT(fWidth >= 0);
1177 SkASSERT(fHeight >= 0);
1178 SkASSERT(SkColorTypeIsValid(fColorType));
1179 SkASSERT(SkAlphaTypeIsValid(fAlphaType));
1180}
1181#endif