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