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 "SkConvertPixels.h"
12 #include "SkData.h"
13 #include "SkFilterQuality.h"
14 #include "SkHalf.h"
15 #include "SkImageInfoPriv.h"
16 #include "SkMallocPixelRef.h"
17 #include "SkMask.h"
18 #include "SkMath.h"
19 #include "SkPixelRef.h"
20 #include "SkReadBuffer.h"
21 #include "SkRect.h"
22 #include "SkScalar.h"
23 #include "SkTemplates.h"
24 #include "SkUnPreMultiply.h"
25 #include "SkWriteBuffer.h"
26 #include "SkWritePixelsRec.h"
27
28 #include <string.h>
29
reset_return_false(SkBitmap * bm)30 static bool reset_return_false(SkBitmap* bm) {
31 bm->reset();
32 return false;
33 }
34
SkBitmap()35 SkBitmap::SkBitmap()
36 : fPixelLockCount(0)
37 , fPixels (nullptr)
38 , fColorTable (nullptr)
39 , fPixelRefOrigin{0, 0}
40 , fRowBytes (0)
41 , fFlags (0) {}
42
43 // copy pixelref, but don't copy lock.
SkBitmap(const SkBitmap & src)44 SkBitmap::SkBitmap(const SkBitmap& src)
45 : fPixelRef (src.fPixelRef)
46 , fPixelLockCount(0)
47 , fPixels (nullptr)
48 , fColorTable (nullptr)
49 , fPixelRefOrigin(src.fPixelRefOrigin)
50 , fInfo (src.fInfo)
51 , fRowBytes (src.fRowBytes)
52 , fFlags (src.fFlags)
53 {
54 SkDEBUGCODE(src.validate();)
55 SkDEBUGCODE(this->validate();)
56 }
57
58 // take lock and lockcount from other.
SkBitmap(SkBitmap && other)59 SkBitmap::SkBitmap(SkBitmap&& other)
60 : fPixelRef (std::move(other.fPixelRef))
61 , fPixelLockCount (other.fPixelLockCount)
62 , fPixels (other.fPixels)
63 , fColorTable (other.fColorTable)
64 , fPixelRefOrigin (other.fPixelRefOrigin)
65 , fInfo (std::move(other.fInfo))
66 , fRowBytes (other.fRowBytes)
67 , fFlags (other.fFlags) {
68 SkASSERT(!other.fPixelRef);
69 other.fInfo.reset();
70 other.fPixelLockCount = 0;
71 other.fPixels = nullptr;
72 other.fColorTable = nullptr;
73 other.fPixelRefOrigin = SkIPoint{0, 0};
74 other.fRowBytes = 0;
75 other.fFlags = 0;
76 }
77
~SkBitmap()78 SkBitmap::~SkBitmap() {
79 SkDEBUGCODE(this->validate();)
80 this->freePixels();
81 }
82
operator =(const SkBitmap & src)83 SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
84 if (this != &src) {
85 this->freePixels();
86 SkASSERT(!fPixels);
87 SkASSERT(!fColorTable);
88 SkASSERT(!fPixelLockCount);
89 fPixelRef = src.fPixelRef;
90 fPixelRefOrigin = src.fPixelRefOrigin;
91 fInfo = src.fInfo;
92 fRowBytes = src.fRowBytes;
93 fFlags = src.fFlags;
94 }
95 SkDEBUGCODE(this->validate();)
96 return *this;
97 }
98
operator =(SkBitmap && other)99 SkBitmap& SkBitmap::operator=(SkBitmap&& other) {
100 if (this != &other) {
101 this->freePixels();
102 SkASSERT(!fPixels);
103 SkASSERT(!fColorTable);
104 SkASSERT(!fPixelLockCount);
105 fPixelRef = std::move(other.fPixelRef);
106 fInfo = std::move(other.fInfo);
107 fPixelLockCount = other.fPixelLockCount;
108 fPixels = other.fPixels;
109 fColorTable = other.fColorTable;
110 fPixelRefOrigin = other.fPixelRefOrigin;
111 fRowBytes = other.fRowBytes;
112 fFlags = other.fFlags;
113 SkASSERT(!other.fPixelRef);
114 other.fInfo.reset();
115 other.fPixelLockCount = 0;
116 other.fPixels = nullptr;
117 other.fColorTable = nullptr;
118 other.fPixelRefOrigin = SkIPoint{0, 0};
119 other.fRowBytes = 0;
120 other.fFlags = 0;
121 }
122 return *this;
123 }
124
swap(SkBitmap & other)125 void SkBitmap::swap(SkBitmap& other) {
126 SkTSwap(*this, other);
127 SkDEBUGCODE(this->validate();)
128 }
129
reset()130 void SkBitmap::reset() {
131 this->freePixels();
132 this->fInfo.reset();
133 sk_bzero(this, sizeof(*this));
134 }
135
getBounds(SkRect * bounds) const136 void SkBitmap::getBounds(SkRect* bounds) const {
137 SkASSERT(bounds);
138 bounds->set(0, 0,
139 SkIntToScalar(fInfo.width()), SkIntToScalar(fInfo.height()));
140 }
141
getBounds(SkIRect * bounds) const142 void SkBitmap::getBounds(SkIRect* bounds) const {
143 SkASSERT(bounds);
144 bounds->set(0, 0, fInfo.width(), fInfo.height());
145 }
146
147 ///////////////////////////////////////////////////////////////////////////////
148
setInfo(const SkImageInfo & info,size_t rowBytes)149 bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) {
150 SkAlphaType newAT = info.alphaType();
151 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) {
152 return reset_return_false(this);
153 }
154 // don't look at info.alphaType(), since newAT is the real value...
155
156 // require that rowBytes fit in 31bits
157 int64_t mrb = info.minRowBytes64();
158 if ((int32_t)mrb != mrb) {
159 return reset_return_false(this);
160 }
161 if ((int64_t)rowBytes != (int32_t)rowBytes) {
162 return reset_return_false(this);
163 }
164
165 if (info.width() < 0 || info.height() < 0) {
166 return reset_return_false(this);
167 }
168
169 if (kUnknown_SkColorType == info.colorType()) {
170 rowBytes = 0;
171 } else if (0 == rowBytes) {
172 rowBytes = (size_t)mrb;
173 } else if (!info.validRowBytes(rowBytes)) {
174 return reset_return_false(this);
175 }
176
177 this->freePixels();
178
179 fInfo = info.makeAlphaType(newAT);
180 fRowBytes = SkToU32(rowBytes);
181 return true;
182 }
183
setAlphaType(SkAlphaType newAlphaType)184 bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) {
185 if (!SkColorTypeValidateAlphaType(fInfo.colorType(), newAlphaType, &newAlphaType)) {
186 return false;
187 }
188 if (fInfo.alphaType() != newAlphaType) {
189 fInfo = fInfo.makeAlphaType(newAlphaType);
190 if (fPixelRef) {
191 fPixelRef->changeAlphaType(newAlphaType);
192 }
193 }
194 return true;
195 }
196
updatePixelsFromRef() const197 void SkBitmap::updatePixelsFromRef() const {
198 if (fPixelRef) {
199 if (fPixelLockCount > 0) {
200 SkASSERT(fPixelRef->isLocked());
201
202 void* p = fPixelRef->pixels();
203 if (p) {
204 p = (char*)p
205 + fPixelRefOrigin.fY * fRowBytes
206 + fPixelRefOrigin.fX * fInfo.bytesPerPixel();
207 }
208 fPixels = p;
209 fColorTable = fPixelRef->colorTable();
210 } else {
211 SkASSERT(0 == fPixelLockCount);
212 fPixels = nullptr;
213 fColorTable = nullptr;
214 }
215 }
216 }
217
218 #ifdef SK_SUPPORT_LEGACY_BITMAP_SETPIXELREF
setPixelRef(SkPixelRef * pr,int dx,int dy)219 SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) {
220 this->setPixelRef(sk_ref_sp(pr), dx, dy);
221 return pr;
222 }
223 #endif
224
setPixelRef(sk_sp<SkPixelRef> pr,int dx,int dy)225 void SkBitmap::setPixelRef(sk_sp<SkPixelRef> pr, int dx, int dy) {
226 #ifdef SK_DEBUG
227 if (pr) {
228 if (kUnknown_SkColorType != fInfo.colorType()) {
229 const SkImageInfo& prInfo = pr->info();
230 SkASSERT(fInfo.width() <= prInfo.width());
231 SkASSERT(fInfo.height() <= prInfo.height());
232 SkASSERT(fInfo.colorType() == prInfo.colorType());
233 switch (prInfo.alphaType()) {
234 case kUnknown_SkAlphaType:
235 SkASSERT(fInfo.alphaType() == kUnknown_SkAlphaType);
236 break;
237 case kOpaque_SkAlphaType:
238 case kPremul_SkAlphaType:
239 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
240 fInfo.alphaType() == kPremul_SkAlphaType);
241 break;
242 case kUnpremul_SkAlphaType:
243 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
244 fInfo.alphaType() == kUnpremul_SkAlphaType);
245 break;
246 }
247 }
248 }
249 #endif
250
251 if (pr) {
252 const SkImageInfo& info = pr->info();
253 fPixelRefOrigin.set(SkTPin(dx, 0, info.width()), SkTPin(dy, 0, info.height()));
254 } else {
255 // ignore dx,dy if there is no pixelref
256 fPixelRefOrigin.setZero();
257 }
258
259 if (fPixelRef != pr) {
260 this->freePixels();
261 SkASSERT(!fPixelRef);
262
263 fPixelRef = std::move(pr);
264 this->updatePixelsFromRef();
265 }
266
267 SkDEBUGCODE(this->validate();)
268 }
269
lockPixels() const270 void SkBitmap::lockPixels() const {
271 if (fPixelRef && 0 == sk_atomic_inc(&fPixelLockCount)) {
272 fPixelRef->lockPixels();
273 this->updatePixelsFromRef();
274 }
275 SkDEBUGCODE(this->validate();)
276 }
277
unlockPixels() const278 void SkBitmap::unlockPixels() const {
279 SkASSERT(!fPixelRef || fPixelLockCount > 0);
280
281 if (fPixelRef && 1 == sk_atomic_dec(&fPixelLockCount)) {
282 fPixelRef->unlockPixels();
283 this->updatePixelsFromRef();
284 }
285 SkDEBUGCODE(this->validate();)
286 }
287
lockPixelsAreWritable() const288 bool SkBitmap::lockPixelsAreWritable() const {
289 return fPixelRef ? fPixelRef->lockPixelsAreWritable() : false;
290 }
291
setPixels(void * p,SkColorTable * ctable)292 void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
293 if (nullptr == p) {
294 this->setPixelRef(nullptr, 0, 0);
295 return;
296 }
297
298 if (kUnknown_SkColorType == fInfo.colorType()) {
299 this->setPixelRef(nullptr, 0, 0);
300 return;
301 }
302
303 sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewDirect(fInfo, p, fRowBytes, ctable));
304 this->setPixelRef(std::move(pr), 0, 0);
305 if (!fPixelRef) {
306 return;
307 }
308 // since we're already allocated, we lockPixels right away
309 this->lockPixels();
310 SkDEBUGCODE(this->validate();)
311 }
312
tryAllocPixels(Allocator * allocator,SkColorTable * ctable)313 bool SkBitmap::tryAllocPixels(Allocator* allocator, SkColorTable* ctable) {
314 HeapAllocator stdalloc;
315
316 if (nullptr == allocator) {
317 allocator = &stdalloc;
318 }
319 return allocator->allocPixelRef(this, ctable);
320 }
321
322 ///////////////////////////////////////////////////////////////////////////////
323
tryAllocPixels(const SkImageInfo & requestedInfo,size_t rowBytes)324 bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
325 if (kIndex_8_SkColorType == requestedInfo.colorType()) {
326 return reset_return_false(this);
327 }
328 if (!this->setInfo(requestedInfo, rowBytes)) {
329 return reset_return_false(this);
330 }
331
332 // setInfo may have corrected info (e.g. 565 is always opaque).
333 const SkImageInfo& correctedInfo = this->info();
334 // setInfo may have computed a valid rowbytes if 0 were passed in
335 rowBytes = this->rowBytes();
336
337 SkMallocPixelRef::PRFactory defaultFactory;
338
339 sk_sp<SkPixelRef> pr(defaultFactory.create(correctedInfo, rowBytes, nullptr));
340 if (!pr) {
341 return reset_return_false(this);
342 }
343 this->setPixelRef(std::move(pr), 0, 0);
344
345 // TODO: lockPixels could/should return bool or void*/nullptr
346 this->lockPixels();
347 if (nullptr == this->getPixels()) {
348 return reset_return_false(this);
349 }
350 return true;
351 }
352
tryAllocPixels(const SkImageInfo & requestedInfo,SkPixelRefFactory * factory,SkColorTable * ctable)353 bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, SkPixelRefFactory* factory,
354 SkColorTable* ctable) {
355 if (kIndex_8_SkColorType == requestedInfo.colorType() && nullptr == ctable) {
356 return reset_return_false(this);
357 }
358 if (!this->setInfo(requestedInfo)) {
359 return reset_return_false(this);
360 }
361
362 // setInfo may have corrected info (e.g. 565 is always opaque).
363 const SkImageInfo& correctedInfo = this->info();
364
365 SkMallocPixelRef::PRFactory defaultFactory;
366 if (nullptr == factory) {
367 factory = &defaultFactory;
368 }
369
370 sk_sp<SkPixelRef> pr(factory->create(correctedInfo, correctedInfo.minRowBytes(), ctable));
371 if (!pr) {
372 return reset_return_false(this);
373 }
374 this->setPixelRef(std::move(pr), 0, 0);
375
376 // TODO: lockPixels could/should return bool or void*/nullptr
377 this->lockPixels();
378 if (nullptr == this->getPixels()) {
379 return reset_return_false(this);
380 }
381 return true;
382 }
383
invoke_release_proc(void (* proc)(void * pixels,void * ctx),void * pixels,void * ctx)384 static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
385 if (proc) {
386 proc(pixels, ctx);
387 }
388 }
389
installPixels(const SkImageInfo & requestedInfo,void * pixels,size_t rb,SkColorTable * ct,void (* releaseProc)(void * addr,void * context),void * context)390 bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
391 SkColorTable* ct, void (*releaseProc)(void* addr, void* context),
392 void* context) {
393 if (!this->setInfo(requestedInfo, rb)) {
394 invoke_release_proc(releaseProc, pixels, context);
395 this->reset();
396 return false;
397 }
398 if (nullptr == pixels) {
399 invoke_release_proc(releaseProc, pixels, context);
400 return true; // we behaved as if they called setInfo()
401 }
402
403 // setInfo may have corrected info (e.g. 565 is always opaque).
404 const SkImageInfo& correctedInfo = this->info();
405
406 sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewWithProc(correctedInfo, rb, ct, pixels, releaseProc,
407 context));
408 if (!pr) {
409 this->reset();
410 return false;
411 }
412
413 this->setPixelRef(std::move(pr), 0, 0);
414
415 // since we're already allocated, we lockPixels right away
416 this->lockPixels();
417 SkDEBUGCODE(this->validate();)
418 return true;
419 }
420
installPixels(const SkPixmap & pixmap)421 bool SkBitmap::installPixels(const SkPixmap& pixmap) {
422 return this->installPixels(pixmap.info(), pixmap.writable_addr(),
423 pixmap.rowBytes(), pixmap.ctable(),
424 nullptr, nullptr);
425 }
426
installMaskPixels(const SkMask & mask)427 bool SkBitmap::installMaskPixels(const SkMask& mask) {
428 if (SkMask::kA8_Format != mask.fFormat) {
429 this->reset();
430 return false;
431 }
432 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
433 mask.fBounds.height()),
434 mask.fImage, mask.fRowBytes);
435 }
436
437 ///////////////////////////////////////////////////////////////////////////////
438
freePixels()439 void SkBitmap::freePixels() {
440 if (fPixelRef) {
441 if (fPixelLockCount > 0) {
442 fPixelRef->unlockPixels();
443 }
444 fPixelRef = nullptr;
445 fPixelRefOrigin.setZero();
446 }
447 fPixelLockCount = 0;
448 fPixels = nullptr;
449 fColorTable = nullptr;
450 }
451
getGenerationID() const452 uint32_t SkBitmap::getGenerationID() const {
453 return fPixelRef ? fPixelRef->getGenerationID() : 0;
454 }
455
notifyPixelsChanged() const456 void SkBitmap::notifyPixelsChanged() const {
457 SkASSERT(!this->isImmutable());
458 if (fPixelRef) {
459 fPixelRef->notifyPixelsChanged();
460 }
461 }
462
463 ///////////////////////////////////////////////////////////////////////////////
464
465 /** We explicitly use the same allocator for our pixels that SkMask does,
466 so that we can freely assign memory allocated by one class to the other.
467 */
allocPixelRef(SkBitmap * dst,SkColorTable * ctable)468 bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
469 SkColorTable* ctable) {
470 const SkImageInfo info = dst->info();
471 if (kUnknown_SkColorType == info.colorType()) {
472 // SkDebugf("unsupported config for info %d\n", dst->config());
473 return false;
474 }
475
476 sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewAllocate(info, dst->rowBytes(), ctable));
477 if (!pr) {
478 return false;
479 }
480
481 dst->setPixelRef(std::move(pr), 0, 0);
482 // since we're already allocated, we lockPixels right away
483 dst->lockPixels();
484 return true;
485 }
486
487 ///////////////////////////////////////////////////////////////////////////////
488
copy_pixels_to(const SkPixmap & src,void * const dst,size_t dstSize,size_t dstRowBytes,bool preserveDstPad)489 static bool copy_pixels_to(const SkPixmap& src, void* const dst, size_t dstSize,
490 size_t dstRowBytes, bool preserveDstPad) {
491 const SkImageInfo& info = src.info();
492
493 if (0 == dstRowBytes) {
494 dstRowBytes = src.rowBytes();
495 }
496 if (dstRowBytes < info.minRowBytes()) {
497 return false;
498 }
499
500 if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == src.rowBytes()) {
501 size_t safeSize = src.getSafeSize();
502 if (safeSize > dstSize || safeSize == 0)
503 return false;
504 else {
505 // This implementation will write bytes beyond the end of each row,
506 // excluding the last row, if the bitmap's stride is greater than
507 // strictly required by the current config.
508 memcpy(dst, src.addr(), safeSize);
509 return true;
510 }
511 } else {
512 // If destination has different stride than us, then copy line by line.
513 if (info.getSafeSize(dstRowBytes) > dstSize) {
514 return false;
515 } else {
516 // Just copy what we need on each line.
517 size_t rowBytes = info.minRowBytes();
518 const uint8_t* srcP = reinterpret_cast<const uint8_t*>(src.addr());
519 uint8_t* dstP = reinterpret_cast<uint8_t*>(dst);
520 for (int row = 0; row < info.height(); ++row) {
521 memcpy(dstP, srcP, rowBytes);
522 srcP += src.rowBytes();
523 dstP += dstRowBytes;
524 }
525
526 return true;
527 }
528 }
529 }
530
copyPixelsTo(void * dst,size_t dstSize,size_t dstRB,bool preserveDstPad) const531 bool SkBitmap::copyPixelsTo(void* dst, size_t dstSize, size_t dstRB, bool preserveDstPad) const {
532 if (nullptr == dst) {
533 return false;
534 }
535 SkAutoPixmapUnlock result;
536 if (!this->requestLock(&result)) {
537 return false;
538 }
539 return copy_pixels_to(result.pixmap(), dst, dstSize, dstRB, preserveDstPad);
540 }
541
542 ///////////////////////////////////////////////////////////////////////////////
543
isImmutable() const544 bool SkBitmap::isImmutable() const {
545 return fPixelRef ? fPixelRef->isImmutable() : false;
546 }
547
setImmutable()548 void SkBitmap::setImmutable() {
549 if (fPixelRef) {
550 fPixelRef->setImmutable();
551 }
552 }
553
isVolatile() const554 bool SkBitmap::isVolatile() const {
555 return (fFlags & kImageIsVolatile_Flag) != 0;
556 }
557
setIsVolatile(bool isVolatile)558 void SkBitmap::setIsVolatile(bool isVolatile) {
559 if (isVolatile) {
560 fFlags |= kImageIsVolatile_Flag;
561 } else {
562 fFlags &= ~kImageIsVolatile_Flag;
563 }
564 }
565
getAddr(int x,int y) const566 void* SkBitmap::getAddr(int x, int y) const {
567 SkASSERT((unsigned)x < (unsigned)this->width());
568 SkASSERT((unsigned)y < (unsigned)this->height());
569
570 char* base = (char*)this->getPixels();
571 if (base) {
572 base += y * this->rowBytes();
573 switch (this->colorType()) {
574 case kRGBA_F16_SkColorType:
575 base += x << 3;
576 break;
577 case kRGBA_8888_SkColorType:
578 case kBGRA_8888_SkColorType:
579 base += x << 2;
580 break;
581 case kARGB_4444_SkColorType:
582 case kRGB_565_SkColorType:
583 base += x << 1;
584 break;
585 case kAlpha_8_SkColorType:
586 case kIndex_8_SkColorType:
587 case kGray_8_SkColorType:
588 base += x;
589 break;
590 default:
591 SkDEBUGFAIL("Can't return addr for config");
592 base = nullptr;
593 break;
594 }
595 }
596 return base;
597 }
598
599 ///////////////////////////////////////////////////////////////////////////////
600 ///////////////////////////////////////////////////////////////////////////////
601
erase(SkColor c,const SkIRect & area) const602 void SkBitmap::erase(SkColor c, const SkIRect& area) const {
603 SkDEBUGCODE(this->validate();)
604
605 switch (fInfo.colorType()) {
606 case kUnknown_SkColorType:
607 case kIndex_8_SkColorType:
608 // TODO: can we ASSERT that we never get here?
609 return; // can't erase. Should we bzero so the memory is not uninitialized?
610 default:
611 break;
612 }
613
614 SkAutoPixmapUnlock result;
615 if (!this->requestLock(&result)) {
616 return;
617 }
618
619 if (result.pixmap().erase(c, area)) {
620 this->notifyPixelsChanged();
621 }
622 }
623
eraseColor(SkColor c) const624 void SkBitmap::eraseColor(SkColor c) const {
625 this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
626 }
627
628 //////////////////////////////////////////////////////////////////////////////////////
629 //////////////////////////////////////////////////////////////////////////////////////
630
extractSubset(SkBitmap * result,const SkIRect & subset) const631 bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
632 SkDEBUGCODE(this->validate();)
633
634 if (nullptr == result || !fPixelRef) {
635 return false; // no src pixels
636 }
637
638 SkIRect srcRect, r;
639 srcRect.set(0, 0, this->width(), this->height());
640 if (!r.intersect(srcRect, subset)) {
641 return false; // r is empty (i.e. no intersection)
642 }
643
644 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
645 // exited above.
646 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
647 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
648
649 SkBitmap dst;
650 dst.setInfo(this->info().makeWH(r.width(), r.height()), this->rowBytes());
651 dst.setIsVolatile(this->isVolatile());
652
653 if (fPixelRef) {
654 SkIPoint origin = fPixelRefOrigin;
655 origin.fX += r.fLeft;
656 origin.fY += r.fTop;
657 // share the pixelref with a custom offset
658 dst.setPixelRef(fPixelRef, origin.x(), origin.y());
659 }
660 SkDEBUGCODE(dst.validate();)
661
662 // we know we're good, so commit to result
663 result->swap(dst);
664 return true;
665 }
666
667 ///////////////////////////////////////////////////////////////////////////////
668
canCopyTo(SkColorType dstCT) const669 bool SkBitmap::canCopyTo(SkColorType dstCT) const {
670 const SkColorType srcCT = this->colorType();
671
672 if (srcCT == kUnknown_SkColorType) {
673 return false;
674 }
675 if (srcCT == kAlpha_8_SkColorType && dstCT != kAlpha_8_SkColorType) {
676 return false; // can't convert from alpha to non-alpha
677 }
678
679 bool sameConfigs = (srcCT == dstCT);
680 switch (dstCT) {
681 case kAlpha_8_SkColorType:
682 case kRGB_565_SkColorType:
683 case kRGBA_8888_SkColorType:
684 case kBGRA_8888_SkColorType:
685 case kRGBA_F16_SkColorType:
686 break;
687 case kGray_8_SkColorType:
688 if (!sameConfigs) {
689 return false;
690 }
691 break;
692 case kARGB_4444_SkColorType:
693 return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT;
694 default:
695 return false;
696 }
697 return true;
698 }
699
readPixels(const SkImageInfo & requestedDstInfo,void * dstPixels,size_t dstRB,int x,int y) const700 bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
701 int x, int y) const {
702 SkAutoPixmapUnlock src;
703 if (!this->requestLock(&src)) {
704 return false;
705 }
706 return src.pixmap().readPixels(requestedDstInfo, dstPixels, dstRB, x, y);
707 }
708
readPixels(const SkPixmap & dst,int srcX,int srcY) const709 bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
710 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
711 }
712
writePixels(const SkPixmap & src,int dstX,int dstY,SkTransferFunctionBehavior behavior)713 bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY,
714 SkTransferFunctionBehavior behavior) {
715 SkAutoPixmapUnlock dst;
716 if (!this->requestLock(&dst)) {
717 return false;
718 }
719
720 if (!SkImageInfoValidConversion(fInfo, src.info())) {
721 return false;
722 }
723
724 SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY);
725 if (!rec.trim(fInfo.width(), fInfo.height())) {
726 return false;
727 }
728
729 void* dstPixels = this->getAddr(rec.fX, rec.fY);
730 const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
731 SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes,
732 src.ctable(), behavior);
733 return true;
734 }
735
copyTo(SkBitmap * dst,SkColorType dstColorType,Allocator * alloc) const736 bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const {
737 if (!this->canCopyTo(dstColorType)) {
738 return false;
739 }
740
741 SkAutoPixmapUnlock srcUnlocker;
742 if (!this->requestLock(&srcUnlocker)) {
743 return false;
744 }
745 SkPixmap srcPM = srcUnlocker.pixmap();
746
747 // Various Android specific compatibility modes.
748 // TODO:
749 // Move the logic of this entire function into the framework, then call readPixels() directly.
750 SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType);
751 switch (dstColorType) {
752 case kRGB_565_SkColorType:
753 // copyTo() is not strict on alpha type. Here we set the src to opaque to allow
754 // the call to readPixels() to succeed and preserve this lenient behavior.
755 if (kOpaque_SkAlphaType != srcPM.alphaType()) {
756 srcPM = SkPixmap(srcPM.info().makeAlphaType(kOpaque_SkAlphaType), srcPM.addr(),
757 srcPM.rowBytes(), srcPM.ctable());
758 dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
759 }
760 break;
761 case kRGBA_F16_SkColorType:
762 // The caller does not have an opportunity to pass a dst color space. Assume that
763 // they want linear sRGB.
764 dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
765
766 if (!srcPM.colorSpace()) {
767 // We can't do a sane conversion to F16 without a dst color space. Guess sRGB
768 // in this case.
769 srcPM.setColorSpace(SkColorSpace::MakeSRGB());
770 }
771 break;
772 default:
773 break;
774 }
775
776 SkBitmap tmpDst;
777 if (!tmpDst.setInfo(dstInfo)) {
778 return false;
779 }
780
781 // allocate colortable if srcConfig == kIndex8_Config
782 sk_sp<SkColorTable> ctable;
783 if (dstColorType == kIndex_8_SkColorType) {
784 ctable.reset(SkRef(srcPM.ctable()));
785 }
786 if (!tmpDst.tryAllocPixels(alloc, ctable.get())) {
787 return false;
788 }
789
790 SkAutoPixmapUnlock dstUnlocker;
791 if (!tmpDst.requestLock(&dstUnlocker)) {
792 return false;
793 }
794
795 SkPixmap dstPM = dstUnlocker.pixmap();
796
797 // We can't do a sane conversion from F16 without a src color space. Guess sRGB in this case.
798 if (kRGBA_F16_SkColorType == srcPM.colorType() && !dstPM.colorSpace()) {
799 dstPM.setColorSpace(SkColorSpace::MakeSRGB());
800 }
801
802 // readPixels does not yet support color spaces with parametric transfer functions. This
803 // works around that restriction when the color spaces are equal.
804 if (kRGBA_F16_SkColorType != dstColorType && kRGBA_F16_SkColorType != srcPM.colorType() &&
805 dstPM.colorSpace() == srcPM.colorSpace()) {
806 dstPM.setColorSpace(nullptr);
807 srcPM.setColorSpace(nullptr);
808 }
809
810 if (!srcPM.readPixels(dstPM)) {
811 return false;
812 }
813
814 // (for BitmapHeap) Clone the pixelref genID even though we have a new pixelref.
815 // The old copyTo impl did this, so we continue it for now.
816 //
817 // TODO: should we ignore rowbytes (i.e. getSize)? Then it could just be
818 // if (src_pixelref->info == dst_pixelref->info)
819 //
820 if (srcPM.colorType() == dstColorType && tmpDst.getSize() == srcPM.getSize64()) {
821 SkPixelRef* dstPixelRef = tmpDst.pixelRef();
822 if (dstPixelRef->info() == fPixelRef->info()) {
823 dstPixelRef->cloneGenID(*fPixelRef);
824 }
825 }
826
827 dst->swap(tmpDst);
828 return true;
829 }
830
831 // TODO: can we merge this with copyTo?
deepCopyTo(SkBitmap * dst) const832 bool SkBitmap::deepCopyTo(SkBitmap* dst) const {
833 const SkColorType dstCT = this->colorType();
834
835 if (!this->canCopyTo(dstCT)) {
836 return false;
837 }
838 return this->copyTo(dst, dstCT, nullptr);
839 }
840
841 ///////////////////////////////////////////////////////////////////////////////
842
GetBitmapAlpha(const SkBitmap & src,uint8_t * SK_RESTRICT alpha,int alphaRowBytes)843 static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
844 SkASSERT(alpha != nullptr);
845 SkASSERT(alphaRowBytes >= src.width());
846
847 SkAutoPixmapUnlock apl;
848 if (!src.requestLock(&apl)) {
849 for (int y = 0; y < src.height(); ++y) {
850 memset(alpha, 0, src.width());
851 alpha += alphaRowBytes;
852 }
853 return false;
854 }
855 const SkPixmap& pmap = apl.pixmap();
856 SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
857 pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable(),
858 SkTransferFunctionBehavior::kRespect);
859 return true;
860 }
861
862 #include "SkPaint.h"
863 #include "SkMaskFilter.h"
864 #include "SkMatrix.h"
865
extractAlpha(SkBitmap * dst,const SkPaint * paint,Allocator * allocator,SkIPoint * offset) const866 bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
867 Allocator *allocator, SkIPoint* offset) const {
868 SkDEBUGCODE(this->validate();)
869
870 SkBitmap tmpBitmap;
871 SkMatrix identity;
872 SkMask srcM, dstM;
873
874 srcM.fBounds.set(0, 0, this->width(), this->height());
875 srcM.fRowBytes = SkAlign4(this->width());
876 srcM.fFormat = SkMask::kA8_Format;
877
878 SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
879
880 // compute our (larger?) dst bounds if we have a filter
881 if (filter) {
882 identity.reset();
883 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
884 goto NO_FILTER_CASE;
885 }
886 dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
887 } else {
888 NO_FILTER_CASE:
889 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
890 if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
891 // Allocation of pixels for alpha bitmap failed.
892 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
893 tmpBitmap.width(), tmpBitmap.height());
894 return false;
895 }
896 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
897 if (offset) {
898 offset->set(0, 0);
899 }
900 tmpBitmap.swap(*dst);
901 return true;
902 }
903 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
904 SkAutoMaskFreeImage srcCleanup(srcM.fImage);
905
906 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
907 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
908 goto NO_FILTER_CASE;
909 }
910 SkAutoMaskFreeImage dstCleanup(dstM.fImage);
911
912 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
913 dstM.fRowBytes);
914 if (!tmpBitmap.tryAllocPixels(allocator, nullptr)) {
915 // Allocation of pixels for alpha bitmap failed.
916 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
917 tmpBitmap.width(), tmpBitmap.height());
918 return false;
919 }
920 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
921 if (offset) {
922 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
923 }
924 SkDEBUGCODE(tmpBitmap.validate();)
925
926 tmpBitmap.swap(*dst);
927 return true;
928 }
929
930 ///////////////////////////////////////////////////////////////////////////////
931
write_raw_pixels(SkWriteBuffer * buffer,const SkPixmap & pmap)932 static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) {
933 const SkImageInfo& info = pmap.info();
934 const size_t snugRB = info.width() * info.bytesPerPixel();
935 const char* src = (const char*)pmap.addr();
936 const size_t ramRB = pmap.rowBytes();
937
938 buffer->write32(SkToU32(snugRB));
939 info.flatten(*buffer);
940
941 const size_t size = snugRB * info.height();
942 SkAutoTMalloc<char> storage(size);
943 char* dst = storage.get();
944 for (int y = 0; y < info.height(); ++y) {
945 memcpy(dst, src, snugRB);
946 dst += snugRB;
947 src += ramRB;
948 }
949 buffer->writeByteArray(storage.get(), size);
950
951 const SkColorTable* ct = pmap.ctable();
952 if (kIndex_8_SkColorType == info.colorType() && ct) {
953 buffer->writeBool(true);
954 ct->writeToBuffer(*buffer);
955 } else {
956 buffer->writeBool(false);
957 }
958 }
959
WriteRawPixels(SkWriteBuffer * buffer,const SkBitmap & bitmap)960 void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) {
961 const SkImageInfo info = bitmap.info();
962 if (0 == info.width() || 0 == info.height() || bitmap.isNull()) {
963 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
964 return;
965 }
966
967 SkAutoPixmapUnlock result;
968 if (!bitmap.requestLock(&result)) {
969 buffer->writeUInt(0); // instead of snugRB, signaling no pixels
970 return;
971 }
972
973 write_raw_pixels(buffer, result.pixmap());
974 }
975
ReadRawPixels(SkReadBuffer * buffer,SkBitmap * bitmap)976 bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) {
977 const size_t snugRB = buffer->readUInt();
978 if (0 == snugRB) { // no pixels
979 return false;
980 }
981
982 SkImageInfo info;
983 info.unflatten(*buffer);
984
985 if (info.width() < 0 || info.height() < 0) {
986 return false;
987 }
988
989 // If there was an error reading "info" or if it is bogus,
990 // don't use it to compute minRowBytes()
991 if (!buffer->validate(SkColorTypeValidateAlphaType(info.colorType(),
992 info.alphaType()))) {
993 return false;
994 }
995
996 const size_t ramRB = info.minRowBytes();
997 const int height = SkMax32(info.height(), 0);
998 const uint64_t snugSize = sk_64_mul(snugRB, height);
999 const uint64_t ramSize = sk_64_mul(ramRB, height);
1000 static const uint64_t max_size_t = (size_t)(-1);
1001 if (!buffer->validate((snugSize <= ramSize) && (ramSize <= max_size_t))) {
1002 return false;
1003 }
1004
1005 sk_sp<SkData> data(SkData::MakeUninitialized(SkToSizeT(ramSize)));
1006 unsigned char* dst = (unsigned char*)data->writable_data();
1007 buffer->readByteArray(dst, SkToSizeT(snugSize));
1008
1009 if (snugSize != ramSize) {
1010 const unsigned char* srcRow = dst + snugRB * (height - 1);
1011 unsigned char* dstRow = dst + ramRB * (height - 1);
1012 for (int y = height - 1; y >= 1; --y) {
1013 memmove(dstRow, srcRow, snugRB);
1014 srcRow -= snugRB;
1015 dstRow -= ramRB;
1016 }
1017 SkASSERT(srcRow == dstRow); // first row does not need to be moved
1018 }
1019
1020 sk_sp<SkColorTable> ctable;
1021 if (buffer->readBool()) {
1022 ctable.reset(SkColorTable::Create(*buffer));
1023 if (!ctable) {
1024 return false;
1025 }
1026
1027 if (info.isEmpty()) {
1028 // require an empty ctable
1029 if (ctable->count() != 0) {
1030 buffer->validate(false);
1031 return false;
1032 }
1033 } else {
1034 // require a non-empty ctable
1035 if (ctable->count() == 0) {
1036 buffer->validate(false);
1037 return false;
1038 }
1039 unsigned char maxIndex = ctable->count() - 1;
1040 for (uint64_t i = 0; i < ramSize; ++i) {
1041 dst[i] = SkTMin(dst[i], maxIndex);
1042 }
1043 }
1044 }
1045
1046 sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewWithData(info, info.minRowBytes(),
1047 ctable.get(), data.get()));
1048 if (!pr.get()) {
1049 return false;
1050 }
1051 bitmap->setInfo(pr->info());
1052 bitmap->setPixelRef(std::move(pr), 0, 0);
1053 return true;
1054 }
1055
1056 enum {
1057 SERIALIZE_PIXELTYPE_NONE,
1058 SERIALIZE_PIXELTYPE_REF_DATA
1059 };
1060
1061 ///////////////////////////////////////////////////////////////////////////////
1062
1063 #ifdef SK_DEBUG
validate() const1064 void SkBitmap::validate() const {
1065 fInfo.validate();
1066
1067 // ImageInfo may not require this, but Bitmap ensures that opaque-only
1068 // colorTypes report opaque for their alphatype
1069 if (kRGB_565_SkColorType == fInfo.colorType()) {
1070 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
1071 }
1072
1073 SkASSERT(fInfo.validRowBytes(fRowBytes));
1074 uint8_t allFlags = kImageIsVolatile_Flag;
1075 #ifdef SK_BUILD_FOR_ANDROID
1076 allFlags |= kHasHardwareMipMap_Flag;
1077 #endif
1078 SkASSERT((~allFlags & fFlags) == 0);
1079 SkASSERT(fPixelLockCount >= 0);
1080
1081 if (fPixels) {
1082 SkASSERT(fPixelRef);
1083 SkASSERT(fPixelLockCount > 0);
1084 SkASSERT(fPixelRef->isLocked());
1085 SkASSERT(fPixelRef->rowBytes() == fRowBytes);
1086 SkASSERT(fPixelRefOrigin.fX >= 0);
1087 SkASSERT(fPixelRefOrigin.fY >= 0);
1088 SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX);
1089 SkASSERT(fPixelRef->info().height() >= (int)this->height() + fPixelRefOrigin.fY);
1090 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
1091 } else {
1092 SkASSERT(nullptr == fColorTable);
1093 }
1094 }
1095 #endif
1096
1097 #ifndef SK_IGNORE_TO_STRING
1098 #include "SkString.h"
toString(SkString * str) const1099 void SkBitmap::toString(SkString* str) const {
1100
1101 static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = {
1102 "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8",
1103 };
1104
1105 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
1106 gColorTypeNames[this->colorType()]);
1107
1108 str->append(" (");
1109 if (this->isOpaque()) {
1110 str->append("opaque");
1111 } else {
1112 str->append("transparent");
1113 }
1114 if (this->isImmutable()) {
1115 str->append(", immutable");
1116 } else {
1117 str->append(", not-immutable");
1118 }
1119 str->append(")");
1120
1121 SkPixelRef* pr = this->pixelRef();
1122 if (nullptr == pr) {
1123 // show null or the explicit pixel address (rare)
1124 str->appendf(" pixels:%p", this->getPixels());
1125 } else {
1126 const char* uri = pr->getURI();
1127 if (uri) {
1128 str->appendf(" uri:\"%s\"", uri);
1129 } else {
1130 str->appendf(" pixelref:%p", pr);
1131 }
1132 }
1133
1134 str->append(")");
1135 }
1136 #endif
1137
1138 ///////////////////////////////////////////////////////////////////////////////
1139
requestLock(SkAutoPixmapUnlock * result) const1140 bool SkBitmap::requestLock(SkAutoPixmapUnlock* result) const {
1141 SkASSERT(result);
1142
1143 SkPixelRef* pr = fPixelRef.get();
1144 if (nullptr == pr) {
1145 return false;
1146 }
1147
1148 // We have to lock the whole thing (using the pixelref's dimensions) until the api supports
1149 // a partial lock (with offset/origin). Hence we can't use our fInfo.
1150 SkPixelRef::LockRequest req = { pr->info().dimensions(), kNone_SkFilterQuality };
1151 SkPixelRef::LockResult res;
1152 if (pr->requestLock(req, &res)) {
1153 SkASSERT(res.fPixels);
1154 // The bitmap may be a subset of the pixelref's dimensions
1155 SkASSERT(fPixelRefOrigin.x() + fInfo.width() <= res.fSize.width());
1156 SkASSERT(fPixelRefOrigin.y() + fInfo.height() <= res.fSize.height());
1157 const void* addr = (const char*)res.fPixels + SkColorTypeComputeOffset(fInfo.colorType(),
1158 fPixelRefOrigin.x(),
1159 fPixelRefOrigin.y(),
1160 res.fRowBytes);
1161
1162 result->reset(SkPixmap(this->info(), addr, res.fRowBytes, res.fCTable),
1163 res.fUnlockProc, res.fUnlockContext);
1164 return true;
1165 }
1166 return false;
1167 }
1168
peekPixels(SkPixmap * pmap) const1169 bool SkBitmap::peekPixels(SkPixmap* pmap) const {
1170 if (fPixels) {
1171 if (pmap) {
1172 pmap->reset(fInfo, fPixels, fRowBytes, fColorTable);
1173 }
1174 return true;
1175 }
1176 return false;
1177 }
1178
1179 ///////////////////////////////////////////////////////////////////////////////
1180
1181 #ifdef SK_DEBUG
validate() const1182 void SkImageInfo::validate() const {
1183 SkASSERT(fWidth >= 0);
1184 SkASSERT(fHeight >= 0);
1185 SkASSERT(SkColorTypeIsValid(fColorType));
1186 SkASSERT(SkAlphaTypeIsValid(fAlphaType));
1187 }
1188 #endif
1189