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