1 /*
2 * Copyright 2008 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkBitmap.h"
9
10 #include "include/core/SkData.h"
11 #include "include/core/SkFilterQuality.h"
12 #include "include/core/SkMallocPixelRef.h"
13 #include "include/core/SkMath.h"
14 #include "include/core/SkPixelRef.h"
15 #include "include/core/SkRect.h"
16 #include "include/core/SkScalar.h"
17 #include "include/core/SkUnPreMultiply.h"
18 #include "include/private/SkColorData.h"
19 #include "include/private/SkHalf.h"
20 #include "include/private/SkImageInfoPriv.h"
21 #include "include/private/SkTemplates.h"
22 #include "include/private/SkTo.h"
23 #include "src/core/SkConvertPixels.h"
24 #include "src/core/SkMask.h"
25 #include "src/core/SkMaskFilterBase.h"
26 #include "src/core/SkPixelRefPriv.h"
27 #include "src/core/SkPixmapPriv.h"
28 #include "src/core/SkReadBuffer.h"
29 #include "src/core/SkWriteBuffer.h"
30 #include "src/core/SkWritePixelsRec.h"
31
32 #include <cstring>
33 #include <utility>
34
reset_return_false(SkBitmap * bm)35 static bool reset_return_false(SkBitmap* bm) {
36 bm->reset();
37 return false;
38 }
39
SkBitmap()40 SkBitmap::SkBitmap() : fFlags(0) {}
41
SkBitmap(const SkBitmap & src)42 SkBitmap::SkBitmap(const SkBitmap& src)
43 : fPixelRef (src.fPixelRef)
44 , fPixmap (src.fPixmap)
45 , fFlags (src.fFlags)
46 {
47 SkDEBUGCODE(src.validate();)
48 SkDEBUGCODE(this->validate();)
49 }
50
SkBitmap(SkBitmap && other)51 SkBitmap::SkBitmap(SkBitmap&& other)
52 : fPixelRef (std::move(other.fPixelRef))
53 , fPixmap (std::move(other.fPixmap))
54 , fFlags (other.fFlags)
55 {
56 SkASSERT(!other.fPixelRef);
57 other.fPixmap.reset();
58 other.fFlags = 0;
59 }
60
~SkBitmap()61 SkBitmap::~SkBitmap() {}
62
operator =(const SkBitmap & src)63 SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
64 if (this != &src) {
65 fPixelRef = src.fPixelRef;
66 fPixmap = src.fPixmap;
67 fFlags = src.fFlags;
68 }
69 SkDEBUGCODE(this->validate();)
70 return *this;
71 }
72
operator =(SkBitmap && other)73 SkBitmap& SkBitmap::operator=(SkBitmap&& other) {
74 if (this != &other) {
75 fPixelRef = std::move(other.fPixelRef);
76 fPixmap = std::move(other.fPixmap);
77 fFlags = other.fFlags;
78 SkASSERT(!other.fPixelRef);
79 other.fPixmap.reset();
80 other.fFlags = 0;
81 }
82 return *this;
83 }
84
swap(SkBitmap & other)85 void SkBitmap::swap(SkBitmap& other) {
86 using std::swap;
87 swap(*this, other);
88 SkDEBUGCODE(this->validate();)
89 }
90
reset()91 void SkBitmap::reset() {
92 fPixelRef = nullptr; // Free pixels.
93 fPixmap.reset();
94 fFlags = 0;
95 }
96
getBounds(SkRect * bounds) const97 void SkBitmap::getBounds(SkRect* bounds) const {
98 SkASSERT(bounds);
99 *bounds = SkRect::Make(this->dimensions());
100 }
101
getBounds(SkIRect * bounds) const102 void SkBitmap::getBounds(SkIRect* bounds) const {
103 SkASSERT(bounds);
104 *bounds = fPixmap.bounds();
105 }
106
107 ///////////////////////////////////////////////////////////////////////////////
108
setInfo(const SkImageInfo & info,size_t rowBytes)109 bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) {
110 SkAlphaType newAT = info.alphaType();
111 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) {
112 return reset_return_false(this);
113 }
114 // don't look at info.alphaType(), since newAT is the real value...
115
116 // require that rowBytes fit in 31bits
117 int64_t mrb = info.minRowBytes64();
118 if (!SkTFitsIn<int32_t>(mrb)) {
119 return reset_return_false(this);
120 }
121 if (!SkTFitsIn<int32_t>(rowBytes)) {
122 return reset_return_false(this);
123 }
124
125 if (info.width() < 0 || info.height() < 0) {
126 return reset_return_false(this);
127 }
128
129 if (kUnknown_SkColorType == info.colorType()) {
130 rowBytes = 0;
131 } else if (0 == rowBytes) {
132 rowBytes = (size_t)mrb;
133 } else if (!info.validRowBytes(rowBytes)) {
134 return reset_return_false(this);
135 }
136
137 fPixelRef = nullptr; // Free pixels.
138 fPixmap.reset(info.makeAlphaType(newAT), nullptr, SkToU32(rowBytes));
139 SkDEBUGCODE(this->validate();)
140 return true;
141 }
142
143
144
setAlphaType(SkAlphaType newAlphaType)145 bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) {
146 if (!SkColorTypeValidateAlphaType(this->colorType(), newAlphaType, &newAlphaType)) {
147 return false;
148 }
149 if (this->alphaType() != newAlphaType) {
150 auto newInfo = fPixmap.info().makeAlphaType(newAlphaType);
151 fPixmap.reset(std::move(newInfo), fPixmap.addr(), fPixmap.rowBytes());
152 }
153 SkDEBUGCODE(this->validate();)
154 return true;
155 }
156
pixelRefOrigin() const157 SkIPoint SkBitmap::pixelRefOrigin() const {
158 const char* addr = (const char*)fPixmap.addr();
159 const char* pix = (const char*)(fPixelRef ? fPixelRef->pixels() : nullptr);
160 size_t rb = this->rowBytes();
161 if (!pix || 0 == rb) {
162 return {0, 0};
163 }
164 SkASSERT(this->bytesPerPixel() > 0);
165 SkASSERT(this->bytesPerPixel() == (1 << this->shiftPerPixel()));
166 SkASSERT(addr >= pix);
167 size_t off = addr - pix;
168 return {SkToS32((off % rb) >> this->shiftPerPixel()), SkToS32(off / rb)};
169 }
170
setPixelRef(sk_sp<SkPixelRef> pr,int dx,int dy)171 void SkBitmap::setPixelRef(sk_sp<SkPixelRef> pr, int dx, int dy) {
172 #ifdef SK_DEBUG
173 if (pr) {
174 if (kUnknown_SkColorType != this->colorType()) {
175 SkASSERT(dx >= 0 && this->width() + dx <= pr->width());
176 SkASSERT(dy >= 0 && this->height() + dy <= pr->height());
177 }
178 }
179 #endif
180 fPixelRef = kUnknown_SkColorType != this->colorType() ? std::move(pr) : nullptr;
181 void* p = nullptr;
182 size_t rowBytes = this->rowBytes();
183 // ignore dx,dy if there is no pixelref
184 if (fPixelRef) {
185 rowBytes = fPixelRef->rowBytes();
186 // TODO(reed): Enforce that PixelRefs must have non-null pixels.
187 p = fPixelRef->pixels();
188 if (p) {
189 p = (char*)p + dy * rowBytes + dx * this->bytesPerPixel();
190 }
191 }
192 SkPixmapPriv::ResetPixmapKeepInfo(&fPixmap, p, rowBytes);
193 SkDEBUGCODE(this->validate();)
194 }
195
setPixels(void * p)196 void SkBitmap::setPixels(void* p) {
197 if (nullptr == p) {
198 this->setPixelRef(nullptr, 0, 0);
199 return;
200 }
201
202 if (kUnknown_SkColorType == this->colorType()) {
203 this->setPixelRef(nullptr, 0, 0);
204 return;
205 }
206 this->setPixelRef(
207 sk_make_sp<SkPixelRef>(this->width(), this->height(), p, this->rowBytes()), 0, 0);
208 SkDEBUGCODE(this->validate();)
209 }
210
tryAllocPixels(Allocator * allocator)211 bool SkBitmap::tryAllocPixels(Allocator* allocator) {
212 HeapAllocator stdalloc;
213
214 if (nullptr == allocator) {
215 allocator = &stdalloc;
216 }
217 return allocator->allocPixelRef(this);
218 }
219
tryAllocN32Pixels(int width,int height,bool isOpaque)220 bool SkBitmap::tryAllocN32Pixels(int width, int height, bool isOpaque) {
221 SkImageInfo info = SkImageInfo::MakeN32(width, height,
222 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
223 return this->tryAllocPixels(info);
224 }
225
allocN32Pixels(int width,int height,bool isOpaque)226 void SkBitmap::allocN32Pixels(int width, int height, bool isOpaque) {
227 SkImageInfo info = SkImageInfo::MakeN32(width, height,
228 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
229 this->allocPixels(info);
230 }
231
allocPixels()232 void SkBitmap::allocPixels() {
233 this->allocPixels((Allocator*)nullptr);
234 }
235
allocPixels(Allocator * allocator)236 void SkBitmap::allocPixels(Allocator* allocator) {
237 SkASSERT_RELEASE(this->tryAllocPixels(allocator));
238 }
239
allocPixelsFlags(const SkImageInfo & info,uint32_t flags)240 void SkBitmap::allocPixelsFlags(const SkImageInfo& info, uint32_t flags) {
241 SkASSERT_RELEASE(this->tryAllocPixelsFlags(info, flags));
242 }
243
allocPixels(const SkImageInfo & info,size_t rowBytes)244 void SkBitmap::allocPixels(const SkImageInfo& info, size_t rowBytes) {
245 SkASSERT_RELEASE(this->tryAllocPixels(info, rowBytes));
246 }
247
allocPixels(const SkImageInfo & info)248 void SkBitmap::allocPixels(const SkImageInfo& info) {
249 this->allocPixels(info, info.minRowBytes());
250 }
251
252 ///////////////////////////////////////////////////////////////////////////////
253
tryAllocPixels(const SkImageInfo & requestedInfo,size_t rowBytes)254 bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
255 if (!this->setInfo(requestedInfo, rowBytes)) {
256 return reset_return_false(this);
257 }
258
259 // setInfo may have corrected info (e.g. 565 is always opaque).
260 const SkImageInfo& correctedInfo = this->info();
261 if (kUnknown_SkColorType == correctedInfo.colorType()) {
262 return true;
263 }
264 // setInfo may have computed a valid rowbytes if 0 were passed in
265 rowBytes = this->rowBytes();
266
267 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo, rowBytes);
268 if (!pr) {
269 return reset_return_false(this);
270 }
271 this->setPixelRef(std::move(pr), 0, 0);
272 if (nullptr == this->getPixels()) {
273 return reset_return_false(this);
274 }
275 SkDEBUGCODE(this->validate();)
276 return true;
277 }
278
tryAllocPixelsFlags(const SkImageInfo & requestedInfo,uint32_t allocFlags)279 bool SkBitmap::tryAllocPixelsFlags(const SkImageInfo& requestedInfo, uint32_t allocFlags) {
280 if (!this->setInfo(requestedInfo)) {
281 return reset_return_false(this);
282 }
283
284 // setInfo may have corrected info (e.g. 565 is always opaque).
285 const SkImageInfo& correctedInfo = this->info();
286
287 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo,
288 correctedInfo.minRowBytes());
289 if (!pr) {
290 return reset_return_false(this);
291 }
292 this->setPixelRef(std::move(pr), 0, 0);
293 if (nullptr == this->getPixels()) {
294 return reset_return_false(this);
295 }
296 SkDEBUGCODE(this->validate();)
297 return true;
298 }
299
invoke_release_proc(void (* proc)(void * pixels,void * ctx),void * pixels,void * ctx)300 static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
301 if (proc) {
302 proc(pixels, ctx);
303 }
304 }
305
installPixels(const SkImageInfo & requestedInfo,void * pixels,size_t rb,void (* releaseProc)(void * addr,void * context),void * context)306 bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
307 void (*releaseProc)(void* addr, void* context), void* context) {
308 if (!this->setInfo(requestedInfo, rb)) {
309 invoke_release_proc(releaseProc, pixels, context);
310 this->reset();
311 return false;
312 }
313 if (nullptr == pixels) {
314 invoke_release_proc(releaseProc, pixels, context);
315 return true; // we behaved as if they called setInfo()
316 }
317
318 // setInfo may have corrected info (e.g. 565 is always opaque).
319 const SkImageInfo& correctedInfo = this->info();
320 this->setPixelRef(
321 SkMakePixelRefWithProc(correctedInfo.width(), correctedInfo.height(),
322 rb, pixels, releaseProc, context), 0, 0);
323 SkDEBUGCODE(this->validate();)
324 return true;
325 }
326
installPixels(const SkPixmap & pixmap)327 bool SkBitmap::installPixels(const SkPixmap& pixmap) {
328 return this->installPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(),
329 nullptr, nullptr);
330 }
331
installMaskPixels(const SkMask & mask)332 bool SkBitmap::installMaskPixels(const SkMask& mask) {
333 if (SkMask::kA8_Format != mask.fFormat) {
334 this->reset();
335 return false;
336 }
337 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
338 mask.fBounds.height()),
339 mask.fImage, mask.fRowBytes);
340 }
341
342 ///////////////////////////////////////////////////////////////////////////////
343
getGenerationID() const344 uint32_t SkBitmap::getGenerationID() const {
345 return fPixelRef ? fPixelRef->getGenerationID() : 0;
346 }
347
notifyPixelsChanged() const348 void SkBitmap::notifyPixelsChanged() const {
349 SkASSERT(!this->isImmutable());
350 if (fPixelRef) {
351 fPixelRef->notifyPixelsChanged();
352 }
353 }
354
355 ///////////////////////////////////////////////////////////////////////////////
356
357 /** We explicitly use the same allocator for our pixels that SkMask does,
358 so that we can freely assign memory allocated by one class to the other.
359 */
allocPixelRef(SkBitmap * dst)360 bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst) {
361 const SkImageInfo info = dst->info();
362 if (kUnknown_SkColorType == info.colorType()) {
363 // SkDebugf("unsupported config for info %d\n", dst->config());
364 return false;
365 }
366
367 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes());
368 if (!pr) {
369 return false;
370 }
371
372 dst->setPixelRef(std::move(pr), 0, 0);
373 SkDEBUGCODE(dst->validate();)
374 return true;
375 }
376
377 ///////////////////////////////////////////////////////////////////////////////
378
isImmutable() const379 bool SkBitmap::isImmutable() const {
380 return fPixelRef ? fPixelRef->isImmutable() : false;
381 }
382
setImmutable()383 void SkBitmap::setImmutable() {
384 if (fPixelRef) {
385 fPixelRef->setImmutable();
386 }
387 }
388
isVolatile() const389 bool SkBitmap::isVolatile() const {
390 return (fFlags & kImageIsVolatile_Flag) != 0;
391 }
392
setIsVolatile(bool isVolatile)393 void SkBitmap::setIsVolatile(bool isVolatile) {
394 if (isVolatile) {
395 fFlags |= kImageIsVolatile_Flag;
396 } else {
397 fFlags &= ~kImageIsVolatile_Flag;
398 }
399 }
400
getAddr(int x,int y) const401 void* SkBitmap::getAddr(int x, int y) const {
402 SkASSERT((unsigned)x < (unsigned)this->width());
403 SkASSERT((unsigned)y < (unsigned)this->height());
404
405 char* base = (char*)this->getPixels();
406 if (base) {
407 base += (y * this->rowBytes()) + (x << this->shiftPerPixel());
408 }
409 return base;
410 }
411
412 ///////////////////////////////////////////////////////////////////////////////
413 ///////////////////////////////////////////////////////////////////////////////
414
erase(SkColor c,const SkIRect & area) const415 void SkBitmap::erase(SkColor c, const SkIRect& area) const {
416 SkDEBUGCODE(this->validate();)
417
418 if (kUnknown_SkColorType == this->colorType()) {
419 // TODO: can we ASSERT that we never get here?
420 return; // can't erase. Should we bzero so the memory is not uninitialized?
421 }
422
423 SkPixmap result;
424 if (!this->peekPixels(&result)) {
425 return;
426 }
427
428 if (result.erase(c, area)) {
429 this->notifyPixelsChanged();
430 }
431 }
432
eraseColor(SkColor c) const433 void SkBitmap::eraseColor(SkColor c) const {
434 this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
435 }
436
437 //////////////////////////////////////////////////////////////////////////////////////
438 //////////////////////////////////////////////////////////////////////////////////////
439
extractSubset(SkBitmap * result,const SkIRect & subset) const440 bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
441 SkDEBUGCODE(this->validate();)
442
443 if (nullptr == result || !fPixelRef) {
444 return false; // no src pixels
445 }
446
447 SkIRect srcRect, r;
448 srcRect.set(0, 0, this->width(), this->height());
449 if (!r.intersect(srcRect, subset)) {
450 return false; // r is empty (i.e. no intersection)
451 }
452
453 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
454 // exited above.
455 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
456 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
457
458 SkBitmap dst;
459 dst.setInfo(this->info().makeWH(r.width(), r.height()), this->rowBytes());
460 dst.setIsVolatile(this->isVolatile());
461
462 if (fPixelRef) {
463 SkIPoint origin = this->pixelRefOrigin();
464 // share the pixelref with a custom offset
465 dst.setPixelRef(fPixelRef, origin.x() + r.fLeft, origin.y() + r.fTop);
466 }
467 SkDEBUGCODE(dst.validate();)
468
469 // we know we're good, so commit to result
470 result->swap(dst);
471 return true;
472 }
473
474 ///////////////////////////////////////////////////////////////////////////////
475
readPixels(const SkImageInfo & requestedDstInfo,void * dstPixels,size_t dstRB,int x,int y) const476 bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
477 int x, int y) const {
478 SkPixmap src;
479 if (!this->peekPixels(&src)) {
480 return false;
481 }
482 return src.readPixels(requestedDstInfo, dstPixels, dstRB, x, y);
483 }
484
readPixels(const SkPixmap & dst,int srcX,int srcY) const485 bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
486 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
487 }
488
writePixels(const SkPixmap & src,int dstX,int dstY)489 bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY) {
490 if (!SkImageInfoValidConversion(this->info(), src.info())) {
491 return false;
492 }
493
494 SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY);
495 if (!rec.trim(this->width(), this->height())) {
496 return false;
497 }
498
499 void* dstPixels = this->getAddr(rec.fX, rec.fY);
500 const SkImageInfo dstInfo = this->info().makeWH(rec.fInfo.width(), rec.fInfo.height());
501 SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes);
502 this->notifyPixelsChanged();
503 return true;
504 }
505
506 ///////////////////////////////////////////////////////////////////////////////
507
GetBitmapAlpha(const SkBitmap & src,uint8_t * SK_RESTRICT alpha,int alphaRowBytes)508 static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
509 SkASSERT(alpha != nullptr);
510 SkASSERT(alphaRowBytes >= src.width());
511
512 SkPixmap pmap;
513 if (!src.peekPixels(&pmap)) {
514 for (int y = 0; y < src.height(); ++y) {
515 memset(alpha, 0, src.width());
516 alpha += alphaRowBytes;
517 }
518 return false;
519 }
520 SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
521 pmap.info(), pmap.addr(), pmap.rowBytes());
522 return true;
523 }
524
525 #include "include/core/SkMaskFilter.h"
526 #include "include/core/SkMatrix.h"
527 #include "include/core/SkPaint.h"
528
extractAlpha(SkBitmap * dst,const SkPaint * paint,Allocator * allocator,SkIPoint * offset) const529 bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
530 Allocator *allocator, SkIPoint* offset) const {
531 SkDEBUGCODE(this->validate();)
532
533 SkBitmap tmpBitmap;
534 SkMatrix identity;
535 SkMask srcM, dstM;
536
537 if (this->width() == 0 || this->height() == 0) {
538 return false;
539 }
540 srcM.fBounds.set(0, 0, this->width(), this->height());
541 srcM.fRowBytes = SkAlign4(this->width());
542 srcM.fFormat = SkMask::kA8_Format;
543
544 SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
545
546 // compute our (larger?) dst bounds if we have a filter
547 if (filter) {
548 identity.reset();
549 if (!as_MFB(filter)->filterMask(&dstM, srcM, identity, nullptr)) {
550 goto NO_FILTER_CASE;
551 }
552 dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
553 } else {
554 NO_FILTER_CASE:
555 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
556 if (!tmpBitmap.tryAllocPixels(allocator)) {
557 // Allocation of pixels for alpha bitmap failed.
558 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
559 tmpBitmap.width(), tmpBitmap.height());
560 return false;
561 }
562 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
563 if (offset) {
564 offset->set(0, 0);
565 }
566 tmpBitmap.swap(*dst);
567 return true;
568 }
569 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
570 SkAutoMaskFreeImage srcCleanup(srcM.fImage);
571
572 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
573 if (!as_MFB(filter)->filterMask(&dstM, srcM, identity, nullptr)) {
574 goto NO_FILTER_CASE;
575 }
576 SkAutoMaskFreeImage dstCleanup(dstM.fImage);
577
578 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
579 dstM.fRowBytes);
580 if (!tmpBitmap.tryAllocPixels(allocator)) {
581 // Allocation of pixels for alpha bitmap failed.
582 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
583 tmpBitmap.width(), tmpBitmap.height());
584 return false;
585 }
586 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
587 if (offset) {
588 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
589 }
590 SkDEBUGCODE(tmpBitmap.validate();)
591
592 tmpBitmap.swap(*dst);
593 return true;
594 }
595
596 ///////////////////////////////////////////////////////////////////////////////
597
598 #ifdef SK_DEBUG
validate() const599 void SkBitmap::validate() const {
600 this->info().validate();
601
602 SkASSERT(this->info().validRowBytes(this->rowBytes()));
603 uint8_t allFlags = kImageIsVolatile_Flag;
604 SkASSERT((~allFlags & fFlags) == 0);
605
606 if (fPixelRef && fPixelRef->pixels()) {
607 SkASSERT(this->getPixels());
608 } else {
609 SkASSERT(!this->getPixels());
610 }
611
612 if (this->getPixels()) {
613 SkASSERT(fPixelRef);
614 SkASSERT(fPixelRef->rowBytes() == this->rowBytes());
615 SkIPoint origin = this->pixelRefOrigin();
616 SkASSERT(origin.fX >= 0);
617 SkASSERT(origin.fY >= 0);
618 SkASSERT(fPixelRef->width() >= (int)this->width() + origin.fX);
619 SkASSERT(fPixelRef->height() >= (int)this->height() + origin.fY);
620 SkASSERT(fPixelRef->rowBytes() >= this->info().minRowBytes());
621 }
622 }
623 #endif
624
625 ///////////////////////////////////////////////////////////////////////////////
626
peekPixels(SkPixmap * pmap) const627 bool SkBitmap::peekPixels(SkPixmap* pmap) const {
628 if (this->getPixels()) {
629 if (pmap) {
630 *pmap = fPixmap;
631 }
632 return true;
633 }
634 return false;
635 }
636
637 ///////////////////////////////////////////////////////////////////////////////
638
639 #ifdef SK_DEBUG
validate() const640 void SkImageInfo::validate() const {
641 SkASSERT(fDimensions.width() >= 0);
642 SkASSERT(fDimensions.height() >= 0);
643 SkASSERT(SkColorTypeIsValid(fColorType));
644 SkASSERT(SkAlphaTypeIsValid(fAlphaType));
645 }
646 #endif
647