1
2 /*
3 * Copyright 2008 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10 #include "SkBitmap.h"
11 #include "SkColorPriv.h"
12 #include "SkDither.h"
13 #include "SkFlattenable.h"
14 #include "SkImagePriv.h"
15 #include "SkMallocPixelRef.h"
16 #include "SkMask.h"
17 #include "SkReadBuffer.h"
18 #include "SkWriteBuffer.h"
19 #include "SkPixelRef.h"
20 #include "SkThread.h"
21 #include "SkUnPreMultiply.h"
22 #include "SkUtils.h"
23 #include "SkValidationUtils.h"
24 #include "SkPackBits.h"
25 #include <new>
26
reset_return_false(SkBitmap * bm)27 static bool reset_return_false(SkBitmap* bm) {
28 bm->reset();
29 return false;
30 }
31
SkBitmap()32 SkBitmap::SkBitmap() {
33 sk_bzero(this, sizeof(*this));
34 }
35
SkBitmap(const SkBitmap & src)36 SkBitmap::SkBitmap(const SkBitmap& src) {
37 SkDEBUGCODE(src.validate();)
38 sk_bzero(this, sizeof(*this));
39 *this = src;
40 SkDEBUGCODE(this->validate();)
41 }
42
~SkBitmap()43 SkBitmap::~SkBitmap() {
44 SkDEBUGCODE(this->validate();)
45 this->freePixels();
46 }
47
operator =(const SkBitmap & src)48 SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
49 if (this != &src) {
50 this->freePixels();
51 memcpy(this, &src, sizeof(src));
52
53 // inc src reference counts
54 SkSafeRef(src.fPixelRef);
55
56 // we reset our locks if we get blown away
57 fPixelLockCount = 0;
58
59 if (fPixelRef) {
60 // ignore the values from the memcpy
61 fPixels = NULL;
62 fColorTable = NULL;
63 // Note that what to for genID is somewhat arbitrary. We have no
64 // way to track changes to raw pixels across multiple SkBitmaps.
65 // Would benefit from an SkRawPixelRef type created by
66 // setPixels.
67 // Just leave the memcpy'ed one but they'll get out of sync
68 // as soon either is modified.
69 }
70 }
71
72 SkDEBUGCODE(this->validate();)
73 return *this;
74 }
75
swap(SkBitmap & other)76 void SkBitmap::swap(SkBitmap& other) {
77 SkTSwap(fColorTable, other.fColorTable);
78 SkTSwap(fPixelRef, other.fPixelRef);
79 SkTSwap(fPixelRefOrigin, other.fPixelRefOrigin);
80 SkTSwap(fPixelLockCount, other.fPixelLockCount);
81 SkTSwap(fPixels, other.fPixels);
82 SkTSwap(fInfo, other.fInfo);
83 SkTSwap(fRowBytes, other.fRowBytes);
84 SkTSwap(fFlags, other.fFlags);
85
86 SkDEBUGCODE(this->validate();)
87 }
88
reset()89 void SkBitmap::reset() {
90 this->freePixels();
91 sk_bzero(this, sizeof(*this));
92 }
93
getBounds(SkRect * bounds) const94 void SkBitmap::getBounds(SkRect* bounds) const {
95 SkASSERT(bounds);
96 bounds->set(0, 0,
97 SkIntToScalar(fInfo.width()), SkIntToScalar(fInfo.height()));
98 }
99
getBounds(SkIRect * bounds) const100 void SkBitmap::getBounds(SkIRect* bounds) const {
101 SkASSERT(bounds);
102 bounds->set(0, 0, fInfo.width(), fInfo.height());
103 }
104
105 ///////////////////////////////////////////////////////////////////////////////
106
setInfo(const SkImageInfo & info,size_t rowBytes)107 bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) {
108 SkAlphaType newAT = info.alphaType();
109 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) {
110 return reset_return_false(this);
111 }
112 // don't look at info.alphaType(), since newAT is the real value...
113
114 // require that rowBytes fit in 31bits
115 int64_t mrb = info.minRowBytes64();
116 if ((int32_t)mrb != mrb) {
117 return reset_return_false(this);
118 }
119 if ((int64_t)rowBytes != (int32_t)rowBytes) {
120 return reset_return_false(this);
121 }
122
123 if (info.width() < 0 || info.height() < 0) {
124 return reset_return_false(this);
125 }
126
127 if (kUnknown_SkColorType == info.colorType()) {
128 rowBytes = 0;
129 } else if (0 == rowBytes) {
130 rowBytes = (size_t)mrb;
131 } else if (!info.validRowBytes(rowBytes)) {
132 return reset_return_false(this);
133 }
134
135 this->freePixels();
136
137 fInfo = info.makeAlphaType(newAT);
138 fRowBytes = SkToU32(rowBytes);
139 return true;
140 }
141
setAlphaType(SkAlphaType newAlphaType)142 bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) {
143 if (!SkColorTypeValidateAlphaType(fInfo.colorType(), newAlphaType, &newAlphaType)) {
144 return false;
145 }
146 if (fInfo.alphaType() != newAlphaType) {
147 fInfo = fInfo.makeAlphaType(newAlphaType);
148 if (fPixelRef) {
149 fPixelRef->changeAlphaType(newAlphaType);
150 }
151 }
152 return true;
153 }
154
updatePixelsFromRef() const155 void SkBitmap::updatePixelsFromRef() const {
156 if (fPixelRef) {
157 if (fPixelLockCount > 0) {
158 SkASSERT(fPixelRef->isLocked());
159
160 void* p = fPixelRef->pixels();
161 if (p) {
162 p = (char*)p
163 + fPixelRefOrigin.fY * fRowBytes
164 + fPixelRefOrigin.fX * fInfo.bytesPerPixel();
165 }
166 fPixels = p;
167 fColorTable = fPixelRef->colorTable();
168 } else {
169 SkASSERT(0 == fPixelLockCount);
170 fPixels = NULL;
171 fColorTable = NULL;
172 }
173 }
174 }
175
setPixelRef(SkPixelRef * pr,int dx,int dy)176 SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) {
177 #ifdef SK_DEBUG
178 if (pr) {
179 if (kUnknown_SkColorType != fInfo.colorType()) {
180 const SkImageInfo& prInfo = pr->info();
181 SkASSERT(fInfo.width() <= prInfo.width());
182 SkASSERT(fInfo.height() <= prInfo.height());
183 SkASSERT(fInfo.colorType() == prInfo.colorType());
184 switch (prInfo.alphaType()) {
185 case kUnknown_SkAlphaType:
186 SkASSERT(fInfo.alphaType() == kUnknown_SkAlphaType);
187 break;
188 case kOpaque_SkAlphaType:
189 case kPremul_SkAlphaType:
190 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
191 fInfo.alphaType() == kPremul_SkAlphaType);
192 break;
193 case kUnpremul_SkAlphaType:
194 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
195 fInfo.alphaType() == kUnpremul_SkAlphaType);
196 break;
197 }
198 }
199 }
200 #endif
201
202 if (pr) {
203 const SkImageInfo& info = pr->info();
204 fPixelRefOrigin.set(SkPin32(dx, 0, info.width()), SkPin32(dy, 0, info.height()));
205 } else {
206 // ignore dx,dy if there is no pixelref
207 fPixelRefOrigin.setZero();
208 }
209
210 if (fPixelRef != pr) {
211 this->freePixels();
212 SkASSERT(NULL == fPixelRef);
213
214 SkSafeRef(pr);
215 fPixelRef = pr;
216 this->updatePixelsFromRef();
217 }
218
219 SkDEBUGCODE(this->validate();)
220 return pr;
221 }
222
lockPixels() const223 void SkBitmap::lockPixels() const {
224 if (fPixelRef && 0 == sk_atomic_inc(&fPixelLockCount)) {
225 fPixelRef->lockPixels();
226 this->updatePixelsFromRef();
227 }
228 SkDEBUGCODE(this->validate();)
229 }
230
unlockPixels() const231 void SkBitmap::unlockPixels() const {
232 SkASSERT(NULL == fPixelRef || fPixelLockCount > 0);
233
234 if (fPixelRef && 1 == sk_atomic_dec(&fPixelLockCount)) {
235 fPixelRef->unlockPixels();
236 this->updatePixelsFromRef();
237 }
238 SkDEBUGCODE(this->validate();)
239 }
240
lockPixelsAreWritable() const241 bool SkBitmap::lockPixelsAreWritable() const {
242 return (fPixelRef) ? fPixelRef->lockPixelsAreWritable() : false;
243 }
244
setPixels(void * p,SkColorTable * ctable)245 void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
246 if (NULL == p) {
247 this->setPixelRef(NULL);
248 return;
249 }
250
251 if (kUnknown_SkColorType == fInfo.colorType()) {
252 this->setPixelRef(NULL);
253 return;
254 }
255
256 SkPixelRef* pr = SkMallocPixelRef::NewDirect(fInfo, p, fRowBytes, ctable);
257 if (NULL == pr) {
258 this->setPixelRef(NULL);
259 return;
260 }
261
262 this->setPixelRef(pr)->unref();
263
264 // since we're already allocated, we lockPixels right away
265 this->lockPixels();
266 SkDEBUGCODE(this->validate();)
267 }
268
tryAllocPixels(Allocator * allocator,SkColorTable * ctable)269 bool SkBitmap::tryAllocPixels(Allocator* allocator, SkColorTable* ctable) {
270 HeapAllocator stdalloc;
271
272 if (NULL == allocator) {
273 allocator = &stdalloc;
274 }
275 return allocator->allocPixelRef(this, ctable);
276 }
277
278 ///////////////////////////////////////////////////////////////////////////////
279
tryAllocPixels(const SkImageInfo & requestedInfo,size_t rowBytes)280 bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
281 if (kIndex_8_SkColorType == requestedInfo.colorType()) {
282 return reset_return_false(this);
283 }
284 if (!this->setInfo(requestedInfo, rowBytes)) {
285 return reset_return_false(this);
286 }
287
288 // setInfo may have corrected info (e.g. 565 is always opaque).
289 const SkImageInfo& correctedInfo = this->info();
290 // setInfo may have computed a valid rowbytes if 0 were passed in
291 rowBytes = this->rowBytes();
292
293 SkMallocPixelRef::PRFactory defaultFactory;
294
295 SkPixelRef* pr = defaultFactory.create(correctedInfo, rowBytes, NULL);
296 if (NULL == pr) {
297 return reset_return_false(this);
298 }
299 this->setPixelRef(pr)->unref();
300
301 // TODO: lockPixels could/should return bool or void*/NULL
302 this->lockPixels();
303 if (NULL == this->getPixels()) {
304 return reset_return_false(this);
305 }
306 return true;
307 }
308
tryAllocPixels(const SkImageInfo & requestedInfo,SkPixelRefFactory * factory,SkColorTable * ctable)309 bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, SkPixelRefFactory* factory,
310 SkColorTable* ctable) {
311 if (kIndex_8_SkColorType == requestedInfo.colorType() && NULL == ctable) {
312 return reset_return_false(this);
313 }
314 if (!this->setInfo(requestedInfo)) {
315 return reset_return_false(this);
316 }
317
318 // setInfo may have corrected info (e.g. 565 is always opaque).
319 const SkImageInfo& correctedInfo = this->info();
320
321 SkMallocPixelRef::PRFactory defaultFactory;
322 if (NULL == factory) {
323 factory = &defaultFactory;
324 }
325
326 SkPixelRef* pr = factory->create(correctedInfo, correctedInfo.minRowBytes(), ctable);
327 if (NULL == pr) {
328 return reset_return_false(this);
329 }
330 this->setPixelRef(pr)->unref();
331
332 // TODO: lockPixels could/should return bool or void*/NULL
333 this->lockPixels();
334 if (NULL == this->getPixels()) {
335 return reset_return_false(this);
336 }
337 return true;
338 }
339
installPixels(const SkImageInfo & requestedInfo,void * pixels,size_t rb,SkColorTable * ct,void (* releaseProc)(void * addr,void * context),void * context)340 bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
341 SkColorTable* ct, void (*releaseProc)(void* addr, void* context),
342 void* context) {
343 if (!this->setInfo(requestedInfo, rb)) {
344 this->reset();
345 return false;
346 }
347
348 // setInfo may have corrected info (e.g. 565 is always opaque).
349 const SkImageInfo& correctedInfo = this->info();
350
351 SkPixelRef* pr = SkMallocPixelRef::NewWithProc(correctedInfo, rb, ct, pixels, releaseProc,
352 context);
353 if (!pr) {
354 this->reset();
355 return false;
356 }
357
358 this->setPixelRef(pr)->unref();
359
360 // since we're already allocated, we lockPixels right away
361 this->lockPixels();
362 SkDEBUGCODE(this->validate();)
363 return true;
364 }
365
installMaskPixels(const SkMask & mask)366 bool SkBitmap::installMaskPixels(const SkMask& mask) {
367 if (SkMask::kA8_Format != mask.fFormat) {
368 this->reset();
369 return false;
370 }
371 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
372 mask.fBounds.height()),
373 mask.fImage, mask.fRowBytes);
374 }
375
376 ///////////////////////////////////////////////////////////////////////////////
377
freePixels()378 void SkBitmap::freePixels() {
379 if (fPixelRef) {
380 if (fPixelLockCount > 0) {
381 fPixelRef->unlockPixels();
382 }
383 fPixelRef->unref();
384 fPixelRef = NULL;
385 fPixelRefOrigin.setZero();
386 }
387 fPixelLockCount = 0;
388 fPixels = NULL;
389 fColorTable = NULL;
390 }
391
getGenerationID() const392 uint32_t SkBitmap::getGenerationID() const {
393 return (fPixelRef) ? fPixelRef->getGenerationID() : 0;
394 }
395
notifyPixelsChanged() const396 void SkBitmap::notifyPixelsChanged() const {
397 SkASSERT(!this->isImmutable());
398 if (fPixelRef) {
399 fPixelRef->notifyPixelsChanged();
400 }
401 }
402
getTexture() const403 GrTexture* SkBitmap::getTexture() const {
404 return fPixelRef ? fPixelRef->getTexture() : NULL;
405 }
406
407 ///////////////////////////////////////////////////////////////////////////////
408
409 /** We explicitly use the same allocator for our pixels that SkMask does,
410 so that we can freely assign memory allocated by one class to the other.
411 */
allocPixelRef(SkBitmap * dst,SkColorTable * ctable)412 bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
413 SkColorTable* ctable) {
414 const SkImageInfo info = dst->info();
415 if (kUnknown_SkColorType == info.colorType()) {
416 // SkDebugf("unsupported config for info %d\n", dst->config());
417 return false;
418 }
419
420 SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, dst->rowBytes(), ctable);
421 if (NULL == pr) {
422 return false;
423 }
424
425 dst->setPixelRef(pr)->unref();
426 // since we're already allocated, we lockPixels right away
427 dst->lockPixels();
428 return true;
429 }
430
431 ///////////////////////////////////////////////////////////////////////////////
432
copyPixelsTo(void * const dst,size_t dstSize,size_t dstRowBytes,bool preserveDstPad) const433 bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize,
434 size_t dstRowBytes, bool preserveDstPad) const {
435
436 if (0 == dstRowBytes) {
437 dstRowBytes = fRowBytes;
438 }
439
440 if (dstRowBytes < fInfo.minRowBytes() ||
441 dst == NULL || (getPixels() == NULL && pixelRef() == NULL)) {
442 return false;
443 }
444
445 if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == fRowBytes) {
446 size_t safeSize = this->getSafeSize();
447 if (safeSize > dstSize || safeSize == 0)
448 return false;
449 else {
450 SkAutoLockPixels lock(*this);
451 // This implementation will write bytes beyond the end of each row,
452 // excluding the last row, if the bitmap's stride is greater than
453 // strictly required by the current config.
454 memcpy(dst, getPixels(), safeSize);
455
456 return true;
457 }
458 } else {
459 // If destination has different stride than us, then copy line by line.
460 if (fInfo.getSafeSize(dstRowBytes) > dstSize) {
461 return false;
462 } else {
463 // Just copy what we need on each line.
464 size_t rowBytes = fInfo.minRowBytes();
465 SkAutoLockPixels lock(*this);
466 const uint8_t* srcP = reinterpret_cast<const uint8_t*>(getPixels());
467 uint8_t* dstP = reinterpret_cast<uint8_t*>(dst);
468 for (int row = 0; row < fInfo.height(); row++, srcP += fRowBytes, dstP += dstRowBytes) {
469 memcpy(dstP, srcP, rowBytes);
470 }
471
472 return true;
473 }
474 }
475 }
476
477 ///////////////////////////////////////////////////////////////////////////////
478
isImmutable() const479 bool SkBitmap::isImmutable() const {
480 return fPixelRef ? fPixelRef->isImmutable() : false;
481 }
482
setImmutable()483 void SkBitmap::setImmutable() {
484 if (fPixelRef) {
485 fPixelRef->setImmutable();
486 }
487 }
488
isVolatile() const489 bool SkBitmap::isVolatile() const {
490 return (fFlags & kImageIsVolatile_Flag) != 0;
491 }
492
setIsVolatile(bool isVolatile)493 void SkBitmap::setIsVolatile(bool isVolatile) {
494 if (isVolatile) {
495 fFlags |= kImageIsVolatile_Flag;
496 } else {
497 fFlags &= ~kImageIsVolatile_Flag;
498 }
499 }
500
getAddr(int x,int y) const501 void* SkBitmap::getAddr(int x, int y) const {
502 SkASSERT((unsigned)x < (unsigned)this->width());
503 SkASSERT((unsigned)y < (unsigned)this->height());
504
505 char* base = (char*)this->getPixels();
506 if (base) {
507 base += y * this->rowBytes();
508 switch (this->colorType()) {
509 case kRGBA_8888_SkColorType:
510 case kBGRA_8888_SkColorType:
511 base += x << 2;
512 break;
513 case kARGB_4444_SkColorType:
514 case kRGB_565_SkColorType:
515 base += x << 1;
516 break;
517 case kAlpha_8_SkColorType:
518 case kIndex_8_SkColorType:
519 case kGray_8_SkColorType:
520 base += x;
521 break;
522 default:
523 SkDEBUGFAIL("Can't return addr for config");
524 base = NULL;
525 break;
526 }
527 }
528 return base;
529 }
530
getColor(int x,int y) const531 SkColor SkBitmap::getColor(int x, int y) const {
532 SkASSERT((unsigned)x < (unsigned)this->width());
533 SkASSERT((unsigned)y < (unsigned)this->height());
534
535 switch (this->colorType()) {
536 case kGray_8_SkColorType: {
537 uint8_t* addr = this->getAddr8(x, y);
538 return SkColorSetRGB(*addr, *addr, *addr);
539 }
540 case kAlpha_8_SkColorType: {
541 uint8_t* addr = this->getAddr8(x, y);
542 return SkColorSetA(0, addr[0]);
543 }
544 case kIndex_8_SkColorType: {
545 SkPMColor c = this->getIndex8Color(x, y);
546 return SkUnPreMultiply::PMColorToColor(c);
547 }
548 case kRGB_565_SkColorType: {
549 uint16_t* addr = this->getAddr16(x, y);
550 return SkPixel16ToColor(addr[0]);
551 }
552 case kARGB_4444_SkColorType: {
553 uint16_t* addr = this->getAddr16(x, y);
554 SkPMColor c = SkPixel4444ToPixel32(addr[0]);
555 return SkUnPreMultiply::PMColorToColor(c);
556 }
557 case kBGRA_8888_SkColorType:
558 case kRGBA_8888_SkColorType: {
559 uint32_t* addr = this->getAddr32(x, y);
560 return SkUnPreMultiply::PMColorToColor(addr[0]);
561 }
562 default:
563 SkASSERT(false);
564 return 0;
565 }
566 SkASSERT(false); // Not reached.
567 return 0;
568 }
569
ComputeIsOpaque(const SkBitmap & bm)570 bool SkBitmap::ComputeIsOpaque(const SkBitmap& bm) {
571 SkAutoLockPixels alp(bm);
572 if (!bm.getPixels()) {
573 return false;
574 }
575
576 const int height = bm.height();
577 const int width = bm.width();
578
579 switch (bm.colorType()) {
580 case kAlpha_8_SkColorType: {
581 unsigned a = 0xFF;
582 for (int y = 0; y < height; ++y) {
583 const uint8_t* row = bm.getAddr8(0, y);
584 for (int x = 0; x < width; ++x) {
585 a &= row[x];
586 }
587 if (0xFF != a) {
588 return false;
589 }
590 }
591 return true;
592 } break;
593 case kIndex_8_SkColorType: {
594 if (!bm.getColorTable()) {
595 return false;
596 }
597 const SkPMColor* table = bm.getColorTable()->readColors();
598 SkPMColor c = (SkPMColor)~0;
599 for (int i = bm.getColorTable()->count() - 1; i >= 0; --i) {
600 c &= table[i];
601 }
602 return 0xFF == SkGetPackedA32(c);
603 } break;
604 case kRGB_565_SkColorType:
605 case kGray_8_SkColorType:
606 return true;
607 break;
608 case kARGB_4444_SkColorType: {
609 unsigned c = 0xFFFF;
610 for (int y = 0; y < height; ++y) {
611 const SkPMColor16* row = bm.getAddr16(0, y);
612 for (int x = 0; x < width; ++x) {
613 c &= row[x];
614 }
615 if (0xF != SkGetPackedA4444(c)) {
616 return false;
617 }
618 }
619 return true;
620 } break;
621 case kBGRA_8888_SkColorType:
622 case kRGBA_8888_SkColorType: {
623 SkPMColor c = (SkPMColor)~0;
624 for (int y = 0; y < height; ++y) {
625 const SkPMColor* row = bm.getAddr32(0, y);
626 for (int x = 0; x < width; ++x) {
627 c &= row[x];
628 }
629 if (0xFF != SkGetPackedA32(c)) {
630 return false;
631 }
632 }
633 return true;
634 }
635 default:
636 break;
637 }
638 return false;
639 }
640
641
642 ///////////////////////////////////////////////////////////////////////////////
643 ///////////////////////////////////////////////////////////////////////////////
644
pack_8888_to_4444(unsigned a,unsigned r,unsigned g,unsigned b)645 static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) {
646 unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) |
647 (SkR32To4444(r) << SK_R4444_SHIFT) |
648 (SkG32To4444(g) << SK_G4444_SHIFT) |
649 (SkB32To4444(b) << SK_B4444_SHIFT);
650 return SkToU16(pixel);
651 }
652
internalErase(const SkIRect & area,U8CPU a,U8CPU r,U8CPU g,U8CPU b) const653 void SkBitmap::internalErase(const SkIRect& area,
654 U8CPU a, U8CPU r, U8CPU g, U8CPU b) const {
655 #ifdef SK_DEBUG
656 SkDEBUGCODE(this->validate();)
657 SkASSERT(!area.isEmpty());
658 {
659 SkIRect total = { 0, 0, this->width(), this->height() };
660 SkASSERT(total.contains(area));
661 }
662 #endif
663
664 switch (fInfo.colorType()) {
665 case kUnknown_SkColorType:
666 case kIndex_8_SkColorType:
667 return; // can't erase. Should we bzero so the memory is not uninitialized?
668 default:
669 break;
670 }
671
672 SkAutoLockPixels alp(*this);
673 // perform this check after the lock call
674 if (!this->readyToDraw()) {
675 return;
676 }
677
678 int height = area.height();
679 const int width = area.width();
680 const int rowBytes = fRowBytes;
681
682 switch (this->colorType()) {
683 case kGray_8_SkColorType: {
684 if (255 != a) {
685 r = SkMulDiv255Round(r, a);
686 g = SkMulDiv255Round(g, a);
687 b = SkMulDiv255Round(b, a);
688 }
689 int gray = SkComputeLuminance(r, g, b);
690 uint8_t* p = this->getAddr8(area.fLeft, area.fTop);
691 while (--height >= 0) {
692 memset(p, gray, width);
693 p += rowBytes;
694 }
695 break;
696 }
697 case kAlpha_8_SkColorType: {
698 uint8_t* p = this->getAddr8(area.fLeft, area.fTop);
699 while (--height >= 0) {
700 memset(p, a, width);
701 p += rowBytes;
702 }
703 break;
704 }
705 case kARGB_4444_SkColorType:
706 case kRGB_565_SkColorType: {
707 uint16_t* p = this->getAddr16(area.fLeft, area.fTop);
708 uint16_t v;
709
710 // make rgb premultiplied
711 if (255 != a) {
712 r = SkAlphaMul(r, a);
713 g = SkAlphaMul(g, a);
714 b = SkAlphaMul(b, a);
715 }
716
717 if (kARGB_4444_SkColorType == this->colorType()) {
718 v = pack_8888_to_4444(a, r, g, b);
719 } else {
720 v = SkPackRGB16(r >> (8 - SK_R16_BITS),
721 g >> (8 - SK_G16_BITS),
722 b >> (8 - SK_B16_BITS));
723 }
724 while (--height >= 0) {
725 sk_memset16(p, v, width);
726 p = (uint16_t*)((char*)p + rowBytes);
727 }
728 break;
729 }
730 case kBGRA_8888_SkColorType:
731 case kRGBA_8888_SkColorType: {
732 uint32_t* p = this->getAddr32(area.fLeft, area.fTop);
733
734 if (255 != a && kPremul_SkAlphaType == this->alphaType()) {
735 r = SkAlphaMul(r, a);
736 g = SkAlphaMul(g, a);
737 b = SkAlphaMul(b, a);
738 }
739 uint32_t v = kRGBA_8888_SkColorType == this->colorType() ?
740 SkPackARGB_as_RGBA(a, r, g, b) : SkPackARGB_as_BGRA(a, r, g, b);
741
742 while (--height >= 0) {
743 sk_memset32(p, v, width);
744 p = (uint32_t*)((char*)p + rowBytes);
745 }
746 break;
747 }
748 default:
749 return; // no change, so don't call notifyPixelsChanged()
750 }
751
752 this->notifyPixelsChanged();
753 }
754
eraseARGB(U8CPU a,U8CPU r,U8CPU g,U8CPU b) const755 void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const {
756 SkIRect area = { 0, 0, this->width(), this->height() };
757 if (!area.isEmpty()) {
758 this->internalErase(area, a, r, g, b);
759 }
760 }
761
eraseArea(const SkIRect & rect,SkColor c) const762 void SkBitmap::eraseArea(const SkIRect& rect, SkColor c) const {
763 SkIRect area = { 0, 0, this->width(), this->height() };
764 if (area.intersect(rect)) {
765 this->internalErase(area, SkColorGetA(c), SkColorGetR(c),
766 SkColorGetG(c), SkColorGetB(c));
767 }
768 }
769
770 //////////////////////////////////////////////////////////////////////////////////////
771 //////////////////////////////////////////////////////////////////////////////////////
772
extractSubset(SkBitmap * result,const SkIRect & subset) const773 bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
774 SkDEBUGCODE(this->validate();)
775
776 if (NULL == result || NULL == fPixelRef) {
777 return false; // no src pixels
778 }
779
780 SkIRect srcRect, r;
781 srcRect.set(0, 0, this->width(), this->height());
782 if (!r.intersect(srcRect, subset)) {
783 return false; // r is empty (i.e. no intersection)
784 }
785
786 if (fPixelRef->getTexture() != NULL) {
787 // Do a deep copy
788 SkPixelRef* pixelRef = fPixelRef->deepCopy(this->colorType(), this->profileType(), &subset);
789 if (pixelRef != NULL) {
790 SkBitmap dst;
791 dst.setInfo(SkImageInfo::Make(subset.width(), subset.height(),
792 this->colorType(), this->alphaType()));
793 dst.setIsVolatile(this->isVolatile());
794 dst.setPixelRef(pixelRef)->unref();
795 SkDEBUGCODE(dst.validate());
796 result->swap(dst);
797 return true;
798 }
799 }
800
801 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
802 // exited above.
803 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
804 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
805
806 SkBitmap dst;
807 dst.setInfo(SkImageInfo::Make(r.width(), r.height(), this->colorType(), this->alphaType()),
808 this->rowBytes());
809 dst.setIsVolatile(this->isVolatile());
810
811 if (fPixelRef) {
812 SkIPoint origin = fPixelRefOrigin;
813 origin.fX += r.fLeft;
814 origin.fY += r.fTop;
815 // share the pixelref with a custom offset
816 dst.setPixelRef(fPixelRef, origin);
817 }
818 SkDEBUGCODE(dst.validate();)
819
820 // we know we're good, so commit to result
821 result->swap(dst);
822 return true;
823 }
824
825 ///////////////////////////////////////////////////////////////////////////////
826
827 #include "SkCanvas.h"
828 #include "SkPaint.h"
829
canCopyTo(SkColorType dstColorType) const830 bool SkBitmap::canCopyTo(SkColorType dstColorType) const {
831 const SkColorType srcCT = this->colorType();
832
833 if (srcCT == kUnknown_SkColorType) {
834 return false;
835 }
836
837 bool sameConfigs = (srcCT == dstColorType);
838 switch (dstColorType) {
839 case kAlpha_8_SkColorType:
840 case kRGB_565_SkColorType:
841 case kRGBA_8888_SkColorType:
842 case kBGRA_8888_SkColorType:
843 break;
844 case kIndex_8_SkColorType:
845 if (!sameConfigs) {
846 return false;
847 }
848 break;
849 case kARGB_4444_SkColorType:
850 return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT;
851 case kGray_8_SkColorType:
852 switch (srcCT) {
853 case kGray_8_SkColorType:
854 case kRGBA_8888_SkColorType:
855 case kBGRA_8888_SkColorType:
856 return true;
857 default:
858 break;
859 }
860 return false;
861 default:
862 return false;
863 }
864 return true;
865 }
866
867 #include "SkConfig8888.h"
868
readPixels(const SkImageInfo & requestedDstInfo,void * dstPixels,size_t dstRB,int x,int y) const869 bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
870 int x, int y) const {
871 if (kUnknown_SkColorType == requestedDstInfo.colorType()) {
872 return false;
873 }
874 if (NULL == dstPixels || dstRB < requestedDstInfo.minRowBytes()) {
875 return false;
876 }
877 if (0 == requestedDstInfo.width() || 0 == requestedDstInfo.height()) {
878 return false;
879 }
880
881 SkIRect srcR = SkIRect::MakeXYWH(x, y, requestedDstInfo.width(), requestedDstInfo.height());
882 if (!srcR.intersect(0, 0, this->width(), this->height())) {
883 return false;
884 }
885
886 // the intersect may have shrunk info's logical size
887 const SkImageInfo dstInfo = requestedDstInfo.makeWH(srcR.width(), srcR.height());
888
889 // if x or y are negative, then we have to adjust pixels
890 if (x > 0) {
891 x = 0;
892 }
893 if (y > 0) {
894 y = 0;
895 }
896 // here x,y are either 0 or negative
897 dstPixels = ((char*)dstPixels - y * dstRB - x * dstInfo.bytesPerPixel());
898
899 //////////////
900
901 SkAutoLockPixels alp(*this);
902
903 // since we don't stop creating un-pixeled devices yet, check for no pixels here
904 if (NULL == this->getPixels()) {
905 return false;
906 }
907
908 const SkImageInfo srcInfo = this->info().makeWH(dstInfo.width(), dstInfo.height());
909
910 const void* srcPixels = this->getAddr(srcR.x(), srcR.y());
911 return SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, this->rowBytes(),
912 this->getColorTable());
913 }
914
copyTo(SkBitmap * dst,SkColorType dstColorType,Allocator * alloc) const915 bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const {
916 if (!this->canCopyTo(dstColorType)) {
917 return false;
918 }
919
920 // if we have a texture, first get those pixels
921 SkBitmap tmpSrc;
922 const SkBitmap* src = this;
923
924 if (fPixelRef) {
925 SkIRect subset;
926 subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY,
927 fInfo.width(), fInfo.height());
928 if (fPixelRef->readPixels(&tmpSrc, &subset)) {
929 if (fPixelRef->info().alphaType() == kUnpremul_SkAlphaType) {
930 // FIXME: The only meaningful implementation of readPixels
931 // (GrPixelRef) assumes premultiplied pixels.
932 return false;
933 }
934 SkASSERT(tmpSrc.width() == this->width());
935 SkASSERT(tmpSrc.height() == this->height());
936
937 // did we get lucky and we can just return tmpSrc?
938 if (tmpSrc.colorType() == dstColorType && NULL == alloc) {
939 dst->swap(tmpSrc);
940 // If the result is an exact copy, clone the gen ID.
941 if (dst->pixelRef() && dst->pixelRef()->info() == fPixelRef->info()) {
942 dst->pixelRef()->cloneGenID(*fPixelRef);
943 }
944 return true;
945 }
946
947 // fall through to the raster case
948 src = &tmpSrc;
949 }
950 }
951
952 // we lock this now, since we may need its colortable
953 SkAutoLockPixels srclock(*src);
954 if (!src->readyToDraw()) {
955 return false;
956 }
957
958 // The only way to be readyToDraw is if fPixelRef is non NULL.
959 SkASSERT(fPixelRef != NULL);
960
961 const SkImageInfo dstInfo = src->info().makeColorType(dstColorType);
962
963 SkBitmap tmpDst;
964 if (!tmpDst.setInfo(dstInfo)) {
965 return false;
966 }
967
968 // allocate colortable if srcConfig == kIndex8_Config
969 SkAutoTUnref<SkColorTable> ctable;
970 if (dstColorType == kIndex_8_SkColorType) {
971 ctable.reset(SkRef(src->getColorTable()));
972 }
973 if (!tmpDst.tryAllocPixels(alloc, ctable)) {
974 return false;
975 }
976
977 if (!tmpDst.readyToDraw()) {
978 // allocator/lock failed
979 return false;
980 }
981
982 // pixelRef must be non NULL or tmpDst.readyToDraw() would have
983 // returned false.
984 SkASSERT(tmpDst.pixelRef() != NULL);
985
986 if (!src->readPixels(tmpDst.info(), tmpDst.getPixels(), tmpDst.rowBytes(), 0, 0)) {
987 return false;
988 }
989
990 // (for BitmapHeap) Clone the pixelref genID even though we have a new pixelref.
991 // The old copyTo impl did this, so we continue it for now.
992 //
993 // TODO: should we ignore rowbytes (i.e. getSize)? Then it could just be
994 // if (src_pixelref->info == dst_pixelref->info)
995 //
996 if (src->colorType() == dstColorType && tmpDst.getSize() == src->getSize()) {
997 SkPixelRef* dstPixelRef = tmpDst.pixelRef();
998 if (dstPixelRef->info() == fPixelRef->info()) {
999 dstPixelRef->cloneGenID(*fPixelRef);
1000 }
1001 }
1002
1003 dst->swap(tmpDst);
1004 return true;
1005 }
1006
deepCopyTo(SkBitmap * dst) const1007 bool SkBitmap::deepCopyTo(SkBitmap* dst) const {
1008 const SkColorType dstCT = this->colorType();
1009 const SkColorProfileType dstPT = this->profileType();
1010
1011 if (!this->canCopyTo(dstCT)) {
1012 return false;
1013 }
1014
1015 // If we have a PixelRef, and it supports deep copy, use it.
1016 // Currently supported only by texture-backed bitmaps.
1017 if (fPixelRef) {
1018 SkPixelRef* pixelRef = fPixelRef->deepCopy(dstCT, dstPT, NULL);
1019 if (pixelRef) {
1020 uint32_t rowBytes;
1021 if (this->colorType() == dstCT && this->profileType() == dstPT) {
1022 // Since there is no subset to pass to deepCopy, and deepCopy
1023 // succeeded, the new pixel ref must be identical.
1024 SkASSERT(fPixelRef->info() == pixelRef->info());
1025 pixelRef->cloneGenID(*fPixelRef);
1026 // Use the same rowBytes as the original.
1027 rowBytes = fRowBytes;
1028 } else {
1029 // With the new config, an appropriate fRowBytes will be computed by setInfo.
1030 rowBytes = 0;
1031 }
1032
1033 const SkImageInfo info = fInfo.makeColorType(dstCT);
1034 if (!dst->setInfo(info, rowBytes)) {
1035 return false;
1036 }
1037 dst->setPixelRef(pixelRef, fPixelRefOrigin)->unref();
1038 return true;
1039 }
1040 }
1041
1042 if (this->getTexture()) {
1043 return false;
1044 } else {
1045 return this->copyTo(dst, dstCT, NULL);
1046 }
1047 }
1048
1049 ///////////////////////////////////////////////////////////////////////////////
1050
GetBitmapAlpha(const SkBitmap & src,uint8_t * SK_RESTRICT alpha,int alphaRowBytes)1051 static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha,
1052 int alphaRowBytes) {
1053 SkASSERT(alpha != NULL);
1054 SkASSERT(alphaRowBytes >= src.width());
1055
1056 SkColorType colorType = src.colorType();
1057 int w = src.width();
1058 int h = src.height();
1059 size_t rb = src.rowBytes();
1060
1061 SkAutoLockPixels alp(src);
1062 if (!src.readyToDraw()) {
1063 // zero out the alpha buffer and return
1064 while (--h >= 0) {
1065 memset(alpha, 0, w);
1066 alpha += alphaRowBytes;
1067 }
1068 return false;
1069 }
1070
1071 if (kAlpha_8_SkColorType == colorType && !src.isOpaque()) {
1072 const uint8_t* s = src.getAddr8(0, 0);
1073 while (--h >= 0) {
1074 memcpy(alpha, s, w);
1075 s += rb;
1076 alpha += alphaRowBytes;
1077 }
1078 } else if (kN32_SkColorType == colorType && !src.isOpaque()) {
1079 const SkPMColor* SK_RESTRICT s = src.getAddr32(0, 0);
1080 while (--h >= 0) {
1081 for (int x = 0; x < w; x++) {
1082 alpha[x] = SkGetPackedA32(s[x]);
1083 }
1084 s = (const SkPMColor*)((const char*)s + rb);
1085 alpha += alphaRowBytes;
1086 }
1087 } else if (kARGB_4444_SkColorType == colorType && !src.isOpaque()) {
1088 const SkPMColor16* SK_RESTRICT s = src.getAddr16(0, 0);
1089 while (--h >= 0) {
1090 for (int x = 0; x < w; x++) {
1091 alpha[x] = SkPacked4444ToA32(s[x]);
1092 }
1093 s = (const SkPMColor16*)((const char*)s + rb);
1094 alpha += alphaRowBytes;
1095 }
1096 } else if (kIndex_8_SkColorType == colorType && !src.isOpaque()) {
1097 SkColorTable* ct = src.getColorTable();
1098 if (ct) {
1099 const SkPMColor* SK_RESTRICT table = ct->readColors();
1100 const uint8_t* SK_RESTRICT s = src.getAddr8(0, 0);
1101 while (--h >= 0) {
1102 for (int x = 0; x < w; x++) {
1103 alpha[x] = SkGetPackedA32(table[s[x]]);
1104 }
1105 s += rb;
1106 alpha += alphaRowBytes;
1107 }
1108 }
1109 } else { // src is opaque, so just fill alpha[] with 0xFF
1110 memset(alpha, 0xFF, h * alphaRowBytes);
1111 }
1112 return true;
1113 }
1114
1115 #include "SkPaint.h"
1116 #include "SkMaskFilter.h"
1117 #include "SkMatrix.h"
1118
extractAlpha(SkBitmap * dst,const SkPaint * paint,Allocator * allocator,SkIPoint * offset) const1119 bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
1120 Allocator *allocator, SkIPoint* offset) const {
1121 SkDEBUGCODE(this->validate();)
1122
1123 SkBitmap tmpBitmap;
1124 SkMatrix identity;
1125 SkMask srcM, dstM;
1126
1127 srcM.fBounds.set(0, 0, this->width(), this->height());
1128 srcM.fRowBytes = SkAlign4(this->width());
1129 srcM.fFormat = SkMask::kA8_Format;
1130
1131 SkMaskFilter* filter = paint ? paint->getMaskFilter() : NULL;
1132
1133 // compute our (larger?) dst bounds if we have a filter
1134 if (filter) {
1135 identity.reset();
1136 srcM.fImage = NULL;
1137 if (!filter->filterMask(&dstM, srcM, identity, NULL)) {
1138 goto NO_FILTER_CASE;
1139 }
1140 dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
1141 } else {
1142 NO_FILTER_CASE:
1143 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
1144 if (!tmpBitmap.tryAllocPixels(allocator, NULL)) {
1145 // Allocation of pixels for alpha bitmap failed.
1146 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
1147 tmpBitmap.width(), tmpBitmap.height());
1148 return false;
1149 }
1150 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
1151 if (offset) {
1152 offset->set(0, 0);
1153 }
1154 tmpBitmap.swap(*dst);
1155 return true;
1156 }
1157 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
1158 SkAutoMaskFreeImage srcCleanup(srcM.fImage);
1159
1160 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
1161 if (!filter->filterMask(&dstM, srcM, identity, NULL)) {
1162 goto NO_FILTER_CASE;
1163 }
1164 SkAutoMaskFreeImage dstCleanup(dstM.fImage);
1165
1166 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
1167 dstM.fRowBytes);
1168 if (!tmpBitmap.tryAllocPixels(allocator, NULL)) {
1169 // Allocation of pixels for alpha bitmap failed.
1170 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
1171 tmpBitmap.width(), tmpBitmap.height());
1172 return false;
1173 }
1174 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
1175 if (offset) {
1176 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
1177 }
1178 SkDEBUGCODE(tmpBitmap.validate();)
1179
1180 tmpBitmap.swap(*dst);
1181 return true;
1182 }
1183
1184 ///////////////////////////////////////////////////////////////////////////////
1185
WriteRawPixels(SkWriteBuffer * buffer,const SkBitmap & bitmap)1186 void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) {
1187 const SkImageInfo info = bitmap.info();
1188 SkAutoLockPixels alp(bitmap);
1189 if (0 == info.width() || 0 == info.height() || NULL == bitmap.getPixels()) {
1190 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
1191 return;
1192 }
1193
1194 const size_t snugRB = info.width() * info.bytesPerPixel();
1195 const char* src = (const char*)bitmap.getPixels();
1196 const size_t ramRB = bitmap.rowBytes();
1197
1198 buffer->write32(SkToU32(snugRB));
1199 info.flatten(*buffer);
1200
1201 const size_t size = snugRB * info.height();
1202 SkAutoMalloc storage(size);
1203 char* dst = (char*)storage.get();
1204 for (int y = 0; y < info.height(); ++y) {
1205 memcpy(dst, src, snugRB);
1206 dst += snugRB;
1207 src += ramRB;
1208 }
1209 buffer->writeByteArray(storage.get(), size);
1210
1211 SkColorTable* ct = bitmap.getColorTable();
1212 if (kIndex_8_SkColorType == info.colorType() && ct) {
1213 buffer->writeBool(true);
1214 ct->writeToBuffer(*buffer);
1215 } else {
1216 buffer->writeBool(false);
1217 }
1218 }
1219
ReadRawPixels(SkReadBuffer * buffer,SkBitmap * bitmap)1220 bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) {
1221 const size_t snugRB = buffer->readUInt();
1222 if (0 == snugRB) { // no pixels
1223 return false;
1224 }
1225
1226 SkImageInfo info;
1227 info.unflatten(*buffer);
1228
1229 // If there was an error reading "info", don't use it to compute minRowBytes()
1230 if (!buffer->validate(true)) {
1231 return false;
1232 }
1233
1234 const size_t ramRB = info.minRowBytes();
1235 const int height = SkMax32(info.height(), 0);
1236 const uint64_t snugSize = sk_64_mul(snugRB, height);
1237 const uint64_t ramSize = sk_64_mul(ramRB, height);
1238 static const uint64_t max_size_t = (size_t)(-1);
1239 if (!buffer->validate((snugSize <= ramSize) && (ramSize <= max_size_t))) {
1240 return false;
1241 }
1242
1243 SkAutoDataUnref data(SkData::NewUninitialized(SkToSizeT(ramSize)));
1244 char* dst = (char*)data->writable_data();
1245 buffer->readByteArray(dst, SkToSizeT(snugSize));
1246
1247 if (snugSize != ramSize) {
1248 const char* srcRow = dst + snugRB * (height - 1);
1249 char* dstRow = dst + ramRB * (height - 1);
1250 for (int y = height - 1; y >= 1; --y) {
1251 memmove(dstRow, srcRow, snugRB);
1252 srcRow -= snugRB;
1253 dstRow -= ramRB;
1254 }
1255 SkASSERT(srcRow == dstRow); // first row does not need to be moved
1256 }
1257
1258 SkAutoTUnref<SkColorTable> ctable;
1259 if (buffer->readBool()) {
1260 ctable.reset(SkNEW_ARGS(SkColorTable, (*buffer)));
1261 }
1262
1263 SkAutoTUnref<SkPixelRef> pr(SkMallocPixelRef::NewWithData(info, info.minRowBytes(),
1264 ctable.get(), data.get()));
1265 if (!pr.get()) {
1266 return false;
1267 }
1268 bitmap->setInfo(pr->info());
1269 bitmap->setPixelRef(pr, 0, 0);
1270 return true;
1271 }
1272
1273 enum {
1274 SERIALIZE_PIXELTYPE_NONE,
1275 SERIALIZE_PIXELTYPE_REF_DATA
1276 };
1277
1278 ///////////////////////////////////////////////////////////////////////////////
1279
RLEPixels(int width,int height)1280 SkBitmap::RLEPixels::RLEPixels(int width, int height) {
1281 fHeight = height;
1282 fYPtrs = (uint8_t**)sk_calloc_throw(height * sizeof(uint8_t*));
1283 }
1284
~RLEPixels()1285 SkBitmap::RLEPixels::~RLEPixels() {
1286 sk_free(fYPtrs);
1287 }
1288
1289 ///////////////////////////////////////////////////////////////////////////////
1290
1291 #ifdef SK_DEBUG
validate() const1292 void SkBitmap::validate() const {
1293 fInfo.validate();
1294
1295 // ImageInfo may not require this, but Bitmap ensures that opaque-only
1296 // colorTypes report opaque for their alphatype
1297 if (kRGB_565_SkColorType == fInfo.colorType()) {
1298 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
1299 }
1300
1301 SkASSERT(fInfo.validRowBytes(fRowBytes));
1302 uint8_t allFlags = kImageIsVolatile_Flag;
1303 #ifdef SK_BUILD_FOR_ANDROID
1304 allFlags |= kHasHardwareMipMap_Flag;
1305 #endif
1306 SkASSERT((~allFlags & fFlags) == 0);
1307 SkASSERT(fPixelLockCount >= 0);
1308
1309 if (fPixels) {
1310 SkASSERT(fPixelRef);
1311 SkASSERT(fPixelLockCount > 0);
1312 SkASSERT(fPixelRef->isLocked());
1313 SkASSERT(fPixelRef->rowBytes() == fRowBytes);
1314 SkASSERT(fPixelRefOrigin.fX >= 0);
1315 SkASSERT(fPixelRefOrigin.fY >= 0);
1316 SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX);
1317 SkASSERT(fPixelRef->info().height() >= (int)this->height() + fPixelRefOrigin.fY);
1318 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
1319 } else {
1320 SkASSERT(NULL == fColorTable);
1321 }
1322 }
1323 #endif
1324
1325 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const1326 void SkBitmap::toString(SkString* str) const {
1327
1328 static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = {
1329 "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8",
1330 };
1331
1332 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
1333 gColorTypeNames[this->colorType()]);
1334
1335 str->append(" (");
1336 if (this->isOpaque()) {
1337 str->append("opaque");
1338 } else {
1339 str->append("transparent");
1340 }
1341 if (this->isImmutable()) {
1342 str->append(", immutable");
1343 } else {
1344 str->append(", not-immutable");
1345 }
1346 str->append(")");
1347
1348 SkPixelRef* pr = this->pixelRef();
1349 if (NULL == pr) {
1350 // show null or the explicit pixel address (rare)
1351 str->appendf(" pixels:%p", this->getPixels());
1352 } else {
1353 const char* uri = pr->getURI();
1354 if (uri) {
1355 str->appendf(" uri:\"%s\"", uri);
1356 } else {
1357 str->appendf(" pixelref:%p", pr);
1358 }
1359 }
1360
1361 str->append(")");
1362 }
1363 #endif
1364
1365 ///////////////////////////////////////////////////////////////////////////////
1366
1367 #ifdef SK_DEBUG
validate() const1368 void SkImageInfo::validate() const {
1369 SkASSERT(fWidth >= 0);
1370 SkASSERT(fHeight >= 0);
1371 SkASSERT(SkColorTypeIsValid(fColorType));
1372 SkASSERT(SkAlphaTypeIsValid(fAlphaType));
1373 }
1374 #endif
1375