blob: 33575499e6aabf57f6de7784942f003f9a8651fa [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"
lsalzmana2415ac2016-10-11 14:29:12 -070011#include "SkConfig8888.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
Hal Canary1b3387b2016-12-12 13:48:12 -0500303 sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewDirect(fInfo, p, fRowBytes, ctable));
304 this->setPixelRef(std::move(pr), 0, 0);
305 if (!fPixelRef) {
reed@google.combf790232013-12-13 19:45:58 +0000306 return;
307 }
djsollen@google.comc84b8332012-07-27 13:41:44 +0000308 // since we're already allocated, we lockPixels right away
309 this->lockPixels();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310 SkDEBUGCODE(this->validate();)
311}
312
reed84825042014-09-02 12:50:45 -0700313bool SkBitmap::tryAllocPixels(Allocator* allocator, SkColorTable* ctable) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314 HeapAllocator stdalloc;
skia.committer@gmail.comd2ac07b2014-01-25 07:01:49 +0000315
halcanary96fcdcc2015-08-27 07:41:13 -0700316 if (nullptr == allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000317 allocator = &stdalloc;
318 }
319 return allocator->allocPixelRef(this, ctable);
320}
321
reed@google.com9ebcac52014-01-24 18:53:42 +0000322///////////////////////////////////////////////////////////////////////////////
323
reed84825042014-09-02 12:50:45 -0700324bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
reedbae704b2014-06-28 14:26:35 -0700325 if (kIndex_8_SkColorType == requestedInfo.colorType()) {
326 return reset_return_false(this);
327 }
reedf0aed972014-07-01 12:48:11 -0700328 if (!this->setInfo(requestedInfo, rowBytes)) {
reedbae704b2014-06-28 14:26:35 -0700329 return reset_return_false(this);
330 }
mtklein775b8192014-12-02 09:11:25 -0800331
reedbae704b2014-06-28 14:26:35 -0700332 // setInfo may have corrected info (e.g. 565 is always opaque).
333 const SkImageInfo& correctedInfo = this->info();
reedf0aed972014-07-01 12:48:11 -0700334 // setInfo may have computed a valid rowbytes if 0 were passed in
335 rowBytes = this->rowBytes();
336
reedbae704b2014-06-28 14:26:35 -0700337 SkMallocPixelRef::PRFactory defaultFactory;
mtklein775b8192014-12-02 09:11:25 -0800338
Hal Canary1b3387b2016-12-12 13:48:12 -0500339 sk_sp<SkPixelRef> pr(defaultFactory.create(correctedInfo, rowBytes, nullptr));
340 if (!pr) {
reedbae704b2014-06-28 14:26:35 -0700341 return reset_return_false(this);
342 }
Hal Canary1b3387b2016-12-12 13:48:12 -0500343 this->setPixelRef(std::move(pr), 0, 0);
mtklein775b8192014-12-02 09:11:25 -0800344
halcanary96fcdcc2015-08-27 07:41:13 -0700345 // TODO: lockPixels could/should return bool or void*/nullptr
reedbae704b2014-06-28 14:26:35 -0700346 this->lockPixels();
halcanary96fcdcc2015-08-27 07:41:13 -0700347 if (nullptr == this->getPixels()) {
reedbae704b2014-06-28 14:26:35 -0700348 return reset_return_false(this);
349 }
350 return true;
351}
352
reed84825042014-09-02 12:50:45 -0700353bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, SkPixelRefFactory* factory,
354 SkColorTable* ctable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700355 if (kIndex_8_SkColorType == requestedInfo.colorType() && nullptr == ctable) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000356 return reset_return_false(this);
357 }
scroggo0187dc22014-06-05 11:18:04 -0700358 if (!this->setInfo(requestedInfo)) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000359 return reset_return_false(this);
360 }
361
scroggo0187dc22014-06-05 11:18:04 -0700362 // setInfo may have corrected info (e.g. 565 is always opaque).
363 const SkImageInfo& correctedInfo = this->info();
364
reed@google.com9ebcac52014-01-24 18:53:42 +0000365 SkMallocPixelRef::PRFactory defaultFactory;
halcanary96fcdcc2015-08-27 07:41:13 -0700366 if (nullptr == factory) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000367 factory = &defaultFactory;
368 }
skia.committer@gmail.comd2ac07b2014-01-25 07:01:49 +0000369
Hal Canary1b3387b2016-12-12 13:48:12 -0500370 sk_sp<SkPixelRef> pr(factory->create(correctedInfo, correctedInfo.minRowBytes(), ctable));
371 if (!pr) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000372 return reset_return_false(this);
373 }
Hal Canary1b3387b2016-12-12 13:48:12 -0500374 this->setPixelRef(std::move(pr), 0, 0);
reed@google.com9ebcac52014-01-24 18:53:42 +0000375
halcanary96fcdcc2015-08-27 07:41:13 -0700376 // TODO: lockPixels could/should return bool or void*/nullptr
reed@google.com9ebcac52014-01-24 18:53:42 +0000377 this->lockPixels();
halcanary96fcdcc2015-08-27 07:41:13 -0700378 if (nullptr == this->getPixels()) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000379 return reset_return_false(this);
380 }
381 return true;
382}
383
reeddb74f622015-05-30 13:41:15 -0700384static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
385 if (proc) {
386 proc(pixels, ctx);
387 }
388}
389
scroggo0187dc22014-06-05 11:18:04 -0700390bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
391 SkColorTable* ct, void (*releaseProc)(void* addr, void* context),
392 void* context) {
393 if (!this->setInfo(requestedInfo, rb)) {
reeddb74f622015-05-30 13:41:15 -0700394 invoke_release_proc(releaseProc, pixels, context);
reed@google.com9ebcac52014-01-24 18:53:42 +0000395 this->reset();
396 return false;
397 }
halcanary96fcdcc2015-08-27 07:41:13 -0700398 if (nullptr == pixels) {
reeddb74f622015-05-30 13:41:15 -0700399 invoke_release_proc(releaseProc, pixels, context);
400 return true; // we behaved as if they called setInfo()
401 }
reed@google.com9ebcac52014-01-24 18:53:42 +0000402
scroggo0187dc22014-06-05 11:18:04 -0700403 // setInfo may have corrected info (e.g. 565 is always opaque).
404 const SkImageInfo& correctedInfo = this->info();
405
Hal Canary1b3387b2016-12-12 13:48:12 -0500406 sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewWithProc(correctedInfo, rb, ct, pixels, releaseProc,
407 context));
reed@google.com9ebcac52014-01-24 18:53:42 +0000408 if (!pr) {
409 this->reset();
410 return false;
411 }
412
Hal Canary1b3387b2016-12-12 13:48:12 -0500413 this->setPixelRef(std::move(pr), 0, 0);
mike@reedtribe.org6e58cf32014-02-16 20:54:21 +0000414
415 // since we're already allocated, we lockPixels right away
416 this->lockPixels();
mike@reedtribe.org6e58cf32014-02-16 20:54:21 +0000417 SkDEBUGCODE(this->validate();)
reed@google.com9ebcac52014-01-24 18:53:42 +0000418 return true;
419}
420
halcanarye36ec872015-12-09 11:36:59 -0800421bool SkBitmap::installPixels(const SkPixmap& pixmap) {
422 return this->installPixels(pixmap.info(), pixmap.writable_addr(),
423 pixmap.rowBytes(), pixmap.ctable(),
424 nullptr, nullptr);
425}
426
commit-bot@chromium.orgdac52252014-02-17 21:21:46 +0000427bool SkBitmap::installMaskPixels(const SkMask& mask) {
428 if (SkMask::kA8_Format != mask.fFormat) {
429 this->reset();
430 return false;
431 }
432 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
433 mask.fBounds.height()),
434 mask.fImage, mask.fRowBytes);
435}
436
reed@google.comeb9a46c2014-01-25 16:46:20 +0000437///////////////////////////////////////////////////////////////////////////////
438
reed@android.com8a1c16f2008-12-17 15:59:43 +0000439void SkBitmap::freePixels() {
bsalomon49f085d2014-09-05 13:34:00 -0700440 if (fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441 if (fPixelLockCount > 0) {
442 fPixelRef->unlockPixels();
443 }
halcanary96fcdcc2015-08-27 07:41:13 -0700444 fPixelRef = nullptr;
reed@google.com672588b2014-01-08 15:42:01 +0000445 fPixelRefOrigin.setZero();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446 }
447 fPixelLockCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700448 fPixels = nullptr;
449 fColorTable = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000450}
451
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452uint32_t SkBitmap::getGenerationID() const {
Hal Canary1b3387b2016-12-12 13:48:12 -0500453 return fPixelRef ? fPixelRef->getGenerationID() : 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454}
455
456void SkBitmap::notifyPixelsChanged() const {
junov@chromium.orgb0521292011-12-15 20:14:06 +0000457 SkASSERT(!this->isImmutable());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000458 if (fPixelRef) {
459 fPixelRef->notifyPixelsChanged();
460 }
461}
462
463///////////////////////////////////////////////////////////////////////////////
464
reed@android.com8a1c16f2008-12-17 15:59:43 +0000465/** We explicitly use the same allocator for our pixels that SkMask does,
466 so that we can freely assign memory allocated by one class to the other.
467 */
468bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
469 SkColorTable* ctable) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000470 const SkImageInfo info = dst->info();
471 if (kUnknown_SkColorType == info.colorType()) {
reed@google.combf790232013-12-13 19:45:58 +0000472// SkDebugf("unsupported config for info %d\n", dst->config());
473 return false;
474 }
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000475
Hal Canary1b3387b2016-12-12 13:48:12 -0500476 sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewAllocate(info, dst->rowBytes(), ctable));
477 if (!pr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000478 return false;
479 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000480
Hal Canary1b3387b2016-12-12 13:48:12 -0500481 dst->setPixelRef(std::move(pr), 0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000482 // since we're already allocated, we lockPixels right away
483 dst->lockPixels();
484 return true;
485}
486
487///////////////////////////////////////////////////////////////////////////////
488
reed92fc2ae2015-05-22 08:06:21 -0700489static bool copy_pixels_to(const SkPixmap& src, void* const dst, size_t dstSize,
490 size_t dstRowBytes, bool preserveDstPad) {
491 const SkImageInfo& info = src.info();
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000492
scroggo@google.com0ba4bf42013-02-25 16:02:36 +0000493 if (0 == dstRowBytes) {
reed92fc2ae2015-05-22 08:06:21 -0700494 dstRowBytes = src.rowBytes();
scroggo@google.com0ba4bf42013-02-25 16:02:36 +0000495 }
reed92fc2ae2015-05-22 08:06:21 -0700496 if (dstRowBytes < info.minRowBytes()) {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000497 return false;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000498 }
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000499
reed92fc2ae2015-05-22 08:06:21 -0700500 if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == src.rowBytes()) {
501 size_t safeSize = src.getSafeSize();
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000502 if (safeSize > dstSize || safeSize == 0)
503 return false;
504 else {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000505 // This implementation will write bytes beyond the end of each row,
506 // excluding the last row, if the bitmap's stride is greater than
507 // strictly required by the current config.
reed92fc2ae2015-05-22 08:06:21 -0700508 memcpy(dst, src.addr(), safeSize);
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000509 return true;
510 }
511 } else {
512 // If destination has different stride than us, then copy line by line.
reed92fc2ae2015-05-22 08:06:21 -0700513 if (info.getSafeSize(dstRowBytes) > dstSize) {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000514 return false;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000515 } else {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000516 // Just copy what we need on each line.
reed92fc2ae2015-05-22 08:06:21 -0700517 size_t rowBytes = info.minRowBytes();
518 const uint8_t* srcP = reinterpret_cast<const uint8_t*>(src.addr());
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000519 uint8_t* dstP = reinterpret_cast<uint8_t*>(dst);
reed92fc2ae2015-05-22 08:06:21 -0700520 for (int row = 0; row < info.height(); ++row) {
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000521 memcpy(dstP, srcP, rowBytes);
reed92fc2ae2015-05-22 08:06:21 -0700522 srcP += src.rowBytes();
523 dstP += dstRowBytes;
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000524 }
525
526 return true;
527 }
528 }
529}
530
reed92fc2ae2015-05-22 08:06:21 -0700531bool SkBitmap::copyPixelsTo(void* dst, size_t dstSize, size_t dstRB, bool preserveDstPad) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700532 if (nullptr == dst) {
reed92fc2ae2015-05-22 08:06:21 -0700533 return false;
534 }
535 SkAutoPixmapUnlock result;
536 if (!this->requestLock(&result)) {
537 return false;
538 }
539 return copy_pixels_to(result.pixmap(), dst, dstSize, dstRB, preserveDstPad);
540}
541
wjmaclean@chromium.org86bff1f2010-11-16 20:22:41 +0000542///////////////////////////////////////////////////////////////////////////////
543
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000544bool SkBitmap::isImmutable() const {
scroggo08470592014-07-15 19:56:48 -0700545 return fPixelRef ? fPixelRef->isImmutable() : false;
junov@chromium.orgb0521292011-12-15 20:14:06 +0000546}
547
548void SkBitmap::setImmutable() {
549 if (fPixelRef) {
550 fPixelRef->setImmutable();
junov@chromium.orgb0521292011-12-15 20:14:06 +0000551 }
552}
553
junov@google.com4ee7ae52011-06-30 17:30:49 +0000554bool SkBitmap::isVolatile() const {
555 return (fFlags & kImageIsVolatile_Flag) != 0;
556}
557
558void SkBitmap::setIsVolatile(bool isVolatile) {
559 if (isVolatile) {
560 fFlags |= kImageIsVolatile_Flag;
561 } else {
562 fFlags &= ~kImageIsVolatile_Flag;
563 }
564}
565
reed@android.com8a1c16f2008-12-17 15:59:43 +0000566void* SkBitmap::getAddr(int x, int y) const {
567 SkASSERT((unsigned)x < (unsigned)this->width());
568 SkASSERT((unsigned)y < (unsigned)this->height());
569
570 char* base = (char*)this->getPixels();
571 if (base) {
572 base += y * this->rowBytes();
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000573 switch (this->colorType()) {
mtklein7fd93e32016-07-26 13:05:30 -0700574 case kRGBA_F16_SkColorType:
575 base += x << 3;
576 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000577 case kRGBA_8888_SkColorType:
578 case kBGRA_8888_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000579 base += x << 2;
580 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000581 case kARGB_4444_SkColorType:
582 case kRGB_565_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000583 base += x << 1;
584 break;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000585 case kAlpha_8_SkColorType:
586 case kIndex_8_SkColorType:
reed0c9b1a82015-03-17 17:44:06 -0700587 case kGray_8_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588 base += x;
589 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000590 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000591 SkDEBUGFAIL("Can't return addr for config");
halcanary96fcdcc2015-08-27 07:41:13 -0700592 base = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593 break;
594 }
595 }
596 return base;
597}
598
599///////////////////////////////////////////////////////////////////////////////
600///////////////////////////////////////////////////////////////////////////////
601
reed7aefe032015-06-08 10:22:22 -0700602void SkBitmap::erase(SkColor c, const SkIRect& area) const {
reed92fc2ae2015-05-22 08:06:21 -0700603 SkDEBUGCODE(this->validate();)
reed92fc2ae2015-05-22 08:06:21 -0700604
605 switch (fInfo.colorType()) {
606 case kUnknown_SkColorType:
607 case kIndex_8_SkColorType:
608 // TODO: can we ASSERT that we never get here?
609 return; // can't erase. Should we bzero so the memory is not uninitialized?
610 default:
611 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 }
weita@google.comf9ab99a2009-05-03 18:23:30 +0000613
reed92fc2ae2015-05-22 08:06:21 -0700614 SkAutoPixmapUnlock result;
615 if (!this->requestLock(&result)) {
616 return;
617 }
618
reed7aefe032015-06-08 10:22:22 -0700619 if (result.pixmap().erase(c, area)) {
reed92fc2ae2015-05-22 08:06:21 -0700620 this->notifyPixelsChanged();
621 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000622}
623
reed7aefe032015-06-08 10:22:22 -0700624void SkBitmap::eraseColor(SkColor c) const {
625 this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
reed@google.com60d32352013-06-28 19:40:50 +0000626}
627
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628//////////////////////////////////////////////////////////////////////////////////////
629//////////////////////////////////////////////////////////////////////////////////////
630
reed@android.com8a1c16f2008-12-17 15:59:43 +0000631bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
632 SkDEBUGCODE(this->validate();)
633
Hal Canary1b3387b2016-12-12 13:48:12 -0500634 if (nullptr == result || !fPixelRef) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000635 return false; // no src pixels
636 }
637
638 SkIRect srcRect, r;
639 srcRect.set(0, 0, this->width(), this->height());
640 if (!r.intersect(srcRect, subset)) {
641 return false; // r is empty (i.e. no intersection)
642 }
643
scroggo@google.coma2a31922012-12-07 19:14:45 +0000644 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
645 // exited above.
646 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
647 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
648
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649 SkBitmap dst;
herbb5d74682016-04-21 08:45:39 -0700650 dst.setInfo(this->info().makeWH(r.width(), r.height()), this->rowBytes());
skyostil@google.com0eb75762012-01-16 10:45:53 +0000651 dst.setIsVolatile(this->isVolatile());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000652
653 if (fPixelRef) {
reed@google.com672588b2014-01-08 15:42:01 +0000654 SkIPoint origin = fPixelRefOrigin;
655 origin.fX += r.fLeft;
656 origin.fY += r.fTop;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657 // share the pixelref with a custom offset
Hal Canary1b3387b2016-12-12 13:48:12 -0500658 dst.setPixelRef(fPixelRef, origin.x(), origin.y());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000659 }
660 SkDEBUGCODE(dst.validate();)
661
662 // we know we're good, so commit to result
663 result->swap(dst);
664 return true;
665}
666
667///////////////////////////////////////////////////////////////////////////////
668
Mike Reed22f34822016-11-28 17:17:38 -0500669bool SkBitmap::canCopyTo(SkColorType dstCT) const {
reedb184f7f2014-07-13 04:32:32 -0700670 const SkColorType srcCT = this->colorType();
671
672 if (srcCT == kUnknown_SkColorType) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000673 return false;
674 }
Mike Reed22f34822016-11-28 17:17:38 -0500675 if (srcCT == kAlpha_8_SkColorType && dstCT != kAlpha_8_SkColorType) {
676 return false; // can't convert from alpha to non-alpha
677 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000678
Mike Reed22f34822016-11-28 17:17:38 -0500679 bool sameConfigs = (srcCT == dstCT);
680 switch (dstCT) {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000681 case kAlpha_8_SkColorType:
682 case kRGB_565_SkColorType:
commit-bot@chromium.org60b5dce2014-04-22 20:24:33 +0000683 case kRGBA_8888_SkColorType:
684 case kBGRA_8888_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000685 break;
Matt Sarettcb6266b2017-01-17 10:48:53 -0500686 case kGray_8_SkColorType:
weita@google.comf9ab99a2009-05-03 18:23:30 +0000687 if (!sameConfigs) {
688 return false;
689 }
690 break;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000691 case kARGB_4444_SkColorType:
reedb184f7f2014-07-13 04:32:32 -0700692 return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693 default:
694 return false;
695 }
reed@android.comfbaa88d2009-05-06 17:44:34 +0000696 return true;
697}
698
reedb184f7f2014-07-13 04:32:32 -0700699bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
700 int x, int y) const {
reed95d343f2015-05-23 13:21:06 -0700701 SkAutoPixmapUnlock src;
702 if (!this->requestLock(&src)) {
reedb184f7f2014-07-13 04:32:32 -0700703 return false;
704 }
reed95d343f2015-05-23 13:21:06 -0700705 return src.pixmap().readPixels(requestedDstInfo, dstPixels, dstRB, x, y);
reedb184f7f2014-07-13 04:32:32 -0700706}
707
Mike Reed68dd8d02017-01-04 16:34:31 -0500708bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
709 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
710}
711
712bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY) {
713 SkAutoPixmapUnlock dst;
714 if (!this->requestLock(&dst)) {
715 return false;
716 }
717
Matt Sarett03dd6d52017-01-23 12:15:09 -0500718 if (!SkImageInfoValidConversion(fInfo, src.info())) {
Mike Reed68dd8d02017-01-04 16:34:31 -0500719 return false;
720 }
721
Matt Sarett03dd6d52017-01-23 12:15:09 -0500722 SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY);
723 if (!rec.trim(fInfo.width(), fInfo.height())) {
724 return false;
725 }
726
727 void* dstPixels = this->getAddr(rec.fX, rec.fY);
728 const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
Matt Sarett8572d852017-02-14 11:21:02 -0500729 SkPixelInfo::CopyPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels,
730 rec.fRowBytes, src.ctable());
731 return true;
Mike Reed68dd8d02017-01-04 16:34:31 -0500732}
733
reedb184f7f2014-07-13 04:32:32 -0700734bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000735 if (!this->canCopyTo(dstColorType)) {
reed@android.comfbaa88d2009-05-06 17:44:34 +0000736 return false;
737 }
738
reed@google.com50dfa012011-04-01 19:05:36 +0000739 // if we have a texture, first get those pixels
740 SkBitmap tmpSrc;
741 const SkBitmap* src = this;
742
scroggo@google.coma2a31922012-12-07 19:14:45 +0000743 if (fPixelRef) {
744 SkIRect subset;
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000745 subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY,
746 fInfo.width(), fInfo.height());
bsalomon9d22fd62016-01-11 11:14:17 -0800747 if (fPixelRef->readPixels(&tmpSrc, dstColorType, &subset)) {
scroggo0187dc22014-06-05 11:18:04 -0700748 if (fPixelRef->info().alphaType() == kUnpremul_SkAlphaType) {
749 // FIXME: The only meaningful implementation of readPixels
750 // (GrPixelRef) assumes premultiplied pixels.
751 return false;
752 }
reed@google.com672588b2014-01-08 15:42:01 +0000753 SkASSERT(tmpSrc.width() == this->width());
754 SkASSERT(tmpSrc.height() == this->height());
reed@google.com50dfa012011-04-01 19:05:36 +0000755
reed@google.com672588b2014-01-08 15:42:01 +0000756 // did we get lucky and we can just return tmpSrc?
halcanary96fcdcc2015-08-27 07:41:13 -0700757 if (tmpSrc.colorType() == dstColorType && nullptr == alloc) {
reed@google.com672588b2014-01-08 15:42:01 +0000758 dst->swap(tmpSrc);
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000759 // If the result is an exact copy, clone the gen ID.
Hal Canary1b3387b2016-12-12 13:48:12 -0500760 SkPixelRef* dstPixelRef = dst->pixelRef();
761 if (!dstPixelRef && dstPixelRef->info() == fPixelRef->info()) {
762 dstPixelRef->cloneGenID(*fPixelRef);
scroggo@google.coma2a31922012-12-07 19:14:45 +0000763 }
reed@google.com672588b2014-01-08 15:42:01 +0000764 return true;
scroggo@google.comd5764e82012-08-22 15:00:05 +0000765 }
reed@google.com672588b2014-01-08 15:42:01 +0000766
767 // fall through to the raster case
768 src = &tmpSrc;
reed@google.com50dfa012011-04-01 19:05:36 +0000769 }
reed@android.comfbaa88d2009-05-06 17:44:34 +0000770 }
reed@android.com311c82d2009-05-05 23:13:23 +0000771
reed95d343f2015-05-23 13:21:06 -0700772 SkAutoPixmapUnlock srcUnlocker;
773 if (!src->requestLock(&srcUnlocker)) {
reed@google.com50dfa012011-04-01 19:05:36 +0000774 return false;
775 }
Matt Sarettcb6266b2017-01-17 10:48:53 -0500776 SkPixmap srcPM = srcUnlocker.pixmap();
777 if (kRGB_565_SkColorType == dstColorType && kOpaque_SkAlphaType != srcPM.alphaType()) {
778 // copyTo() is not strict on alpha type. Here we set the src to opaque to allow
779 // the call to readPixels() to succeed and preserve this lenient behavior.
780 srcPM = SkPixmap(srcPM.info().makeAlphaType(kOpaque_SkAlphaType), srcPM.addr(),
781 srcPM.rowBytes(), srcPM.ctable());
782 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000783
reed95d343f2015-05-23 13:21:06 -0700784 const SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType);
reed@google.com50dfa012011-04-01 19:05:36 +0000785 SkBitmap tmpDst;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000786 if (!tmpDst.setInfo(dstInfo)) {
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000787 return false;
788 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000789
weita@google.comf9ab99a2009-05-03 18:23:30 +0000790 // allocate colortable if srcConfig == kIndex8_Config
Hal Canary704cd322016-11-07 14:13:52 -0500791 sk_sp<SkColorTable> ctable;
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000792 if (dstColorType == kIndex_8_SkColorType) {
reed95d343f2015-05-23 13:21:06 -0700793 ctable.reset(SkRef(srcPM.ctable()));
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000794 }
Hal Canary704cd322016-11-07 14:13:52 -0500795 if (!tmpDst.tryAllocPixels(alloc, ctable.get())) {
weita@google.comf9ab99a2009-05-03 18:23:30 +0000796 return false;
797 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000798
reed95d343f2015-05-23 13:21:06 -0700799 SkAutoPixmapUnlock dstUnlocker;
800 if (!tmpDst.requestLock(&dstUnlocker)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801 return false;
802 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000803
reed95d343f2015-05-23 13:21:06 -0700804 if (!srcPM.readPixels(dstUnlocker.pixmap())) {
reedb184f7f2014-07-13 04:32:32 -0700805 return false;
806 }
scroggo@google.com5ccae2c2014-01-15 16:56:52 +0000807
reedb184f7f2014-07-13 04:32:32 -0700808 // (for BitmapHeap) Clone the pixelref genID even though we have a new pixelref.
809 // The old copyTo impl did this, so we continue it for now.
810 //
811 // TODO: should we ignore rowbytes (i.e. getSize)? Then it could just be
812 // if (src_pixelref->info == dst_pixelref->info)
813 //
reed95d343f2015-05-23 13:21:06 -0700814 if (srcPM.colorType() == dstColorType && tmpDst.getSize() == srcPM.getSize64()) {
reedb184f7f2014-07-13 04:32:32 -0700815 SkPixelRef* dstPixelRef = tmpDst.pixelRef();
816 if (dstPixelRef->info() == fPixelRef->info()) {
817 dstPixelRef->cloneGenID(*fPixelRef);
reed@android.com311c82d2009-05-05 23:13:23 +0000818 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000819 }
820
reed@google.com50dfa012011-04-01 19:05:36 +0000821 dst->swap(tmpDst);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000822 return true;
823}
824
reedc7ec7c92016-07-25 08:29:10 -0700825// TODO: can we merge this with copyTo?
commit-bot@chromium.orgfab349c2014-03-05 02:34:58 +0000826bool SkBitmap::deepCopyTo(SkBitmap* dst) const {
reede4538f52014-06-11 06:09:50 -0700827 const SkColorType dstCT = this->colorType();
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +0000828
commit-bot@chromium.org8a2ad3c2014-02-23 03:59:35 +0000829 if (!this->canCopyTo(dstCT)) {
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000830 return false;
831 }
reedc7ec7c92016-07-25 08:29:10 -0700832 return this->copyTo(dst, dstCT, nullptr);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000833}
834
reed@android.com8a1c16f2008-12-17 15:59:43 +0000835///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836
reed92fc2ae2015-05-22 08:06:21 -0700837static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
halcanary96fcdcc2015-08-27 07:41:13 -0700838 SkASSERT(alpha != nullptr);
reed92fc2ae2015-05-22 08:06:21 -0700839 SkASSERT(alphaRowBytes >= src.width());
840
841 SkAutoPixmapUnlock apl;
842 if (!src.requestLock(&apl)) {
lsalzmana2415ac2016-10-11 14:29:12 -0700843 for (int y = 0; y < src.height(); ++y) {
844 memset(alpha, 0, src.width());
845 alpha += alphaRowBytes;
846 }
reed92fc2ae2015-05-22 08:06:21 -0700847 return false;
848 }
lsalzmana2415ac2016-10-11 14:29:12 -0700849 const SkPixmap& pmap = apl.pixmap();
850 SkPixelInfo::CopyPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
851 pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable());
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()) {
reedb236d1a2015-08-28 10:14:18 -07001015 ctable.reset(SkColorTable::Create(*buffer));
1016 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
Hal Canary704cd322016-11-07 14:13:52 -05001039 sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewWithData(info, info.minRowBytes(),
1040 ctable.get(), data.get()));
sugoi6af31472015-01-28 13:15:32 -08001041 if (!pr.get()) {
1042 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
1056SkBitmap::RLEPixels::RLEPixels(int width, int height) {
1057 fHeight = height;
commit-bot@chromium.org235002f2013-10-09 18:39:59 +00001058 fYPtrs = (uint8_t**)sk_calloc_throw(height * sizeof(uint8_t*));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059}
1060
1061SkBitmap::RLEPixels::~RLEPixels() {
1062 sk_free(fYPtrs);
1063}
1064
1065///////////////////////////////////////////////////////////////////////////////
1066
1067#ifdef SK_DEBUG
1068void SkBitmap::validate() const {
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001069 fInfo.validate();
commit-bot@chromium.orgd5414e52014-02-13 22:30:38 +00001070
1071 // ImageInfo may not require this, but Bitmap ensures that opaque-only
1072 // colorTypes report opaque for their alphatype
1073 if (kRGB_565_SkColorType == fInfo.colorType()) {
1074 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
1075 }
1076
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001077 SkASSERT(fInfo.validRowBytes(fRowBytes));
scroggo08470592014-07-15 19:56:48 -07001078 uint8_t allFlags = kImageIsVolatile_Flag;
scroggo@google.com8e990eb2013-06-14 15:55:56 +00001079#ifdef SK_BUILD_FOR_ANDROID
1080 allFlags |= kHasHardwareMipMap_Flag;
1081#endif
scroggo08470592014-07-15 19:56:48 -07001082 SkASSERT((~allFlags & fFlags) == 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001083 SkASSERT(fPixelLockCount >= 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001084
reed@google.com615316c2014-01-15 19:15:23 +00001085 if (fPixels) {
1086 SkASSERT(fPixelRef);
robertphillipse77dadd2014-11-21 05:50:21 -08001087 SkASSERT(fPixelLockCount > 0);
reed@google.com615316c2014-01-15 19:15:23 +00001088 SkASSERT(fPixelRef->isLocked());
1089 SkASSERT(fPixelRef->rowBytes() == fRowBytes);
1090 SkASSERT(fPixelRefOrigin.fX >= 0);
1091 SkASSERT(fPixelRefOrigin.fY >= 0);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001092 SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX);
reede5ea5002014-09-03 11:54:58 -07001093 SkASSERT(fPixelRef->info().height() >= (int)this->height() + fPixelRefOrigin.fY);
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001094 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
reed@google.com615316c2014-01-15 19:15:23 +00001095 } else {
halcanary96fcdcc2015-08-27 07:41:13 -07001096 SkASSERT(nullptr == fColorTable);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001097 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098}
1099#endif
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001100
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001101#ifndef SK_IGNORE_TO_STRING
bungemand3ebb482015-08-05 13:57:49 -07001102#include "SkString.h"
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001103void SkBitmap::toString(SkString* str) const {
1104
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +00001105 static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = {
1106 "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8",
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001107 };
1108
1109 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +00001110 gColorTypeNames[this->colorType()]);
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001111
1112 str->append(" (");
1113 if (this->isOpaque()) {
1114 str->append("opaque");
1115 } else {
1116 str->append("transparent");
1117 }
1118 if (this->isImmutable()) {
1119 str->append(", immutable");
1120 } else {
1121 str->append(", not-immutable");
1122 }
1123 str->append(")");
1124
1125 SkPixelRef* pr = this->pixelRef();
halcanary96fcdcc2015-08-27 07:41:13 -07001126 if (nullptr == pr) {
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001127 // show null or the explicit pixel address (rare)
1128 str->appendf(" pixels:%p", this->getPixels());
1129 } else {
1130 const char* uri = pr->getURI();
bsalomon49f085d2014-09-05 13:34:00 -07001131 if (uri) {
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001132 str->appendf(" uri:\"%s\"", uri);
1133 } else {
1134 str->appendf(" pixelref:%p", pr);
1135 }
1136 }
1137
1138 str->append(")");
1139}
1140#endif
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001141
1142///////////////////////////////////////////////////////////////////////////////
1143
reed92fc2ae2015-05-22 08:06:21 -07001144bool SkBitmap::requestLock(SkAutoPixmapUnlock* result) const {
1145 SkASSERT(result);
1146
Hal Canary1b3387b2016-12-12 13:48:12 -05001147 SkPixelRef* pr = fPixelRef.get();
halcanary96fcdcc2015-08-27 07:41:13 -07001148 if (nullptr == pr) {
reed92fc2ae2015-05-22 08:06:21 -07001149 return false;
1150 }
1151
reed871872f2015-06-22 12:48:26 -07001152 // We have to lock the whole thing (using the pixelref's dimensions) until the api supports
1153 // a partial lock (with offset/origin). Hence we can't use our fInfo.
1154 SkPixelRef::LockRequest req = { pr->info().dimensions(), kNone_SkFilterQuality };
reed92fc2ae2015-05-22 08:06:21 -07001155 SkPixelRef::LockResult res;
1156 if (pr->requestLock(req, &res)) {
reede8006572015-05-28 14:06:06 -07001157 SkASSERT(res.fPixels);
reed92fc2ae2015-05-22 08:06:21 -07001158 // The bitmap may be a subset of the pixelref's dimensions
1159 SkASSERT(fPixelRefOrigin.x() + fInfo.width() <= res.fSize.width());
1160 SkASSERT(fPixelRefOrigin.y() + fInfo.height() <= res.fSize.height());
1161 const void* addr = (const char*)res.fPixels + SkColorTypeComputeOffset(fInfo.colorType(),
1162 fPixelRefOrigin.x(),
1163 fPixelRefOrigin.y(),
1164 res.fRowBytes);
1165
1166 result->reset(SkPixmap(this->info(), addr, res.fRowBytes, res.fCTable),
1167 res.fUnlockProc, res.fUnlockContext);
1168 return true;
1169 }
1170 return false;
1171}
1172
reedcb674142015-06-05 06:58:22 -07001173bool SkBitmap::peekPixels(SkPixmap* pmap) const {
1174 if (fPixels) {
1175 if (pmap) {
1176 pmap->reset(fInfo, fPixels, fRowBytes, fColorTable);
1177 }
1178 return true;
1179 }
1180 return false;
1181}
1182
reed92fc2ae2015-05-22 08:06:21 -07001183///////////////////////////////////////////////////////////////////////////////
1184
commit-bot@chromium.org61e96cd2014-02-11 18:21:45 +00001185#ifdef SK_DEBUG
1186void SkImageInfo::validate() const {
1187 SkASSERT(fWidth >= 0);
1188 SkASSERT(fHeight >= 0);
1189 SkASSERT(SkColorTypeIsValid(fColorType));
1190 SkASSERT(SkAlphaTypeIsValid(fAlphaType));
1191}
1192#endif