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