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/SkPixelRefPriv.h"
27#include "src/core/SkPixmapPriv.h"
28#include "src/core/SkReadBuffer.h"
29#include "src/core/SkWriteBuffer.h"
30#include "src/core/SkWritePixelsRec.h"
31
32#include <cstring>
33#include <utility>
34
35static bool reset_return_false(SkBitmap* bm) {
36 bm->reset();
37 return false;
38}
39
40SkBitmap::SkBitmap() : fFlags(0) {}
41
42SkBitmap::SkBitmap(const SkBitmap& src)
43 : fPixelRef (src.fPixelRef)
44 , fPixmap (src.fPixmap)
45 , fFlags (src.fFlags)
46{
47 SkDEBUGCODE(src.validate();)
48 SkDEBUGCODE(this->validate();)
49}
50
51SkBitmap::SkBitmap(SkBitmap&& other)
52 : fPixelRef (std::move(other.fPixelRef))
53 , fPixmap (std::move(other.fPixmap))
54 , fFlags (other.fFlags)
55{
56 SkASSERT(!other.fPixelRef);
57 other.fPixmap.reset();
58 other.fFlags = 0;
59}
60
61SkBitmap::~SkBitmap() {}
62
63SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
64 if (this != &src) {
65 fPixelRef = src.fPixelRef;
66 fPixmap = src.fPixmap;
67 fFlags = src.fFlags;
68 }
69 SkDEBUGCODE(this->validate();)
70 return *this;
71}
72
73SkBitmap& SkBitmap::operator=(SkBitmap&& other) {
74 if (this != &other) {
75 fPixelRef = std::move(other.fPixelRef);
76 fPixmap = std::move(other.fPixmap);
77 fFlags = other.fFlags;
78 SkASSERT(!other.fPixelRef);
79 other.fPixmap.reset();
80 other.fFlags = 0;
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 fFlags = 0;
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 SkASSERT_RELEASE(this->tryAllocPixels(allocator));
233}
234
235void SkBitmap::allocPixelsFlags(const SkImageInfo& info, uint32_t flags) {
236 SkASSERT_RELEASE(this->tryAllocPixelsFlags(info, flags));
237}
238
239void SkBitmap::allocPixels(const SkImageInfo& info, size_t rowBytes) {
240 SkASSERT_RELEASE(this->tryAllocPixels(info, rowBytes));
241}
242
243void SkBitmap::allocPixels(const SkImageInfo& info) {
244 this->allocPixels(info, info.minRowBytes());
245}
246
247///////////////////////////////////////////////////////////////////////////////
248
249bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
250 if (!this->setInfo(requestedInfo, rowBytes)) {
251 return reset_return_false(this);
252 }
253
254 // setInfo may have corrected info (e.g. 565 is always opaque).
255 const SkImageInfo& correctedInfo = this->info();
256 if (kUnknown_SkColorType == correctedInfo.colorType()) {
257 return true;
258 }
259 // setInfo may have computed a valid rowbytes if 0 were passed in
260 rowBytes = this->rowBytes();
261
262 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo, rowBytes);
263 if (!pr) {
264 return reset_return_false(this);
265 }
266 this->setPixelRef(std::move(pr), 0, 0);
267 if (nullptr == this->getPixels()) {
268 return reset_return_false(this);
269 }
270 SkDEBUGCODE(this->validate();)
271 return true;
272}
273
274bool SkBitmap::tryAllocPixelsFlags(const SkImageInfo& requestedInfo, uint32_t allocFlags) {
275 if (!this->setInfo(requestedInfo)) {
276 return reset_return_false(this);
277 }
278
279 // setInfo may have corrected info (e.g. 565 is always opaque).
280 const SkImageInfo& correctedInfo = this->info();
281
282 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo,
283 correctedInfo.minRowBytes());
284 if (!pr) {
285 return reset_return_false(this);
286 }
287 this->setPixelRef(std::move(pr), 0, 0);
288 if (nullptr == this->getPixels()) {
289 return reset_return_false(this);
290 }
291 SkDEBUGCODE(this->validate();)
292 return true;
293}
294
295static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
296 if (proc) {
297 proc(pixels, ctx);
298 }
299}
300
301bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
302 void (*releaseProc)(void* addr, void* context), void* context) {
303 if (!this->setInfo(requestedInfo, rb)) {
304 invoke_release_proc(releaseProc, pixels, context);
305 this->reset();
306 return false;
307 }
308 if (nullptr == pixels) {
309 invoke_release_proc(releaseProc, pixels, context);
310 return true; // we behaved as if they called setInfo()
311 }
312
313 // setInfo may have corrected info (e.g. 565 is always opaque).
314 const SkImageInfo& correctedInfo = this->info();
315 this->setPixelRef(
316 SkMakePixelRefWithProc(correctedInfo.width(), correctedInfo.height(),
317 rb, pixels, releaseProc, context), 0, 0);
318 SkDEBUGCODE(this->validate();)
319 return true;
320}
321
322bool SkBitmap::installPixels(const SkPixmap& pixmap) {
323 return this->installPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(),
324 nullptr, nullptr);
325}
326
327bool SkBitmap::installMaskPixels(const SkMask& mask) {
328 if (SkMask::kA8_Format != mask.fFormat) {
329 this->reset();
330 return false;
331 }
332 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
333 mask.fBounds.height()),
334 mask.fImage, mask.fRowBytes);
335}
336
337///////////////////////////////////////////////////////////////////////////////
338
339uint32_t SkBitmap::getGenerationID() const {
340 return fPixelRef ? fPixelRef->getGenerationID() : 0;
341}
342
343void SkBitmap::notifyPixelsChanged() const {
344 SkASSERT(!this->isImmutable());
345 if (fPixelRef) {
346 fPixelRef->notifyPixelsChanged();
347 }
348}
349
350///////////////////////////////////////////////////////////////////////////////
351
352/** We explicitly use the same allocator for our pixels that SkMask does,
353 so that we can freely assign memory allocated by one class to the other.
354 */
355bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst) {
356 const SkImageInfo info = dst->info();
357 if (kUnknown_SkColorType == info.colorType()) {
358// SkDebugf("unsupported config for info %d\n", dst->config());
359 return false;
360 }
361
362 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes());
363 if (!pr) {
364 return false;
365 }
366
367 dst->setPixelRef(std::move(pr), 0, 0);
368 SkDEBUGCODE(dst->validate();)
369 return true;
370}
371
372///////////////////////////////////////////////////////////////////////////////
373
374bool SkBitmap::isImmutable() const {
375 return fPixelRef ? fPixelRef->isImmutable() : false;
376}
377
378void SkBitmap::setImmutable() {
379 if (fPixelRef) {
380 fPixelRef->setImmutable();
381 }
382}
383
384bool SkBitmap::isVolatile() const {
385 return (fFlags & kImageIsVolatile_Flag) != 0;
386}
387
388void SkBitmap::setIsVolatile(bool isVolatile) {
389 if (isVolatile) {
390 fFlags |= kImageIsVolatile_Flag;
391 } else {
392 fFlags &= ~kImageIsVolatile_Flag;
393 }
394}
395
396void* SkBitmap::getAddr(int x, int y) const {
397 SkASSERT((unsigned)x < (unsigned)this->width());
398 SkASSERT((unsigned)y < (unsigned)this->height());
399
400 char* base = (char*)this->getPixels();
401 if (base) {
402 base += (y * this->rowBytes()) + (x << this->shiftPerPixel());
403 }
404 return base;
405}
406
407///////////////////////////////////////////////////////////////////////////////
408///////////////////////////////////////////////////////////////////////////////
409
410void SkBitmap::erase(SkColor c, const SkIRect& area) const {
411 SkDEBUGCODE(this->validate();)
412
413 if (kUnknown_SkColorType == this->colorType()) {
414 // TODO: can we ASSERT that we never get here?
415 return; // can't erase. Should we bzero so the memory is not uninitialized?
416 }
417
418 SkPixmap result;
419 if (!this->peekPixels(&result)) {
420 return;
421 }
422
423 if (result.erase(c, area)) {
424 this->notifyPixelsChanged();
425 }
426}
427
428void SkBitmap::eraseColor(SkColor c) const {
429 this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
430}
431
432//////////////////////////////////////////////////////////////////////////////////////
433//////////////////////////////////////////////////////////////////////////////////////
434
435bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
436 SkDEBUGCODE(this->validate();)
437
438 if (nullptr == result || !fPixelRef) {
439 return false; // no src pixels
440 }
441
442 SkIRect srcRect, r;
443 srcRect.setWH(this->width(), this->height());
444 if (!r.intersect(srcRect, subset)) {
445 return false; // r is empty (i.e. no intersection)
446 }
447
448 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
449 // exited above.
450 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
451 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
452
453 SkBitmap dst;
454 dst.setInfo(this->info().makeDimensions(r.size()), this->rowBytes());
455 dst.setIsVolatile(this->isVolatile());
456
457 if (fPixelRef) {
458 SkIPoint origin = this->pixelRefOrigin();
459 // share the pixelref with a custom offset
460 dst.setPixelRef(fPixelRef, origin.x() + r.fLeft, origin.y() + r.fTop);
461 }
462 SkDEBUGCODE(dst.validate();)
463
464 // we know we're good, so commit to result
465 result->swap(dst);
466 return true;
467}
468
469///////////////////////////////////////////////////////////////////////////////
470
471bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
472 int x, int y) const {
473 SkPixmap src;
474 if (!this->peekPixels(&src)) {
475 return false;
476 }
477 return src.readPixels(requestedDstInfo, dstPixels, dstRB, x, y);
478}
479
480bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
481 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
482}
483
484bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY) {
485 if (!SkImageInfoValidConversion(this->info(), src.info())) {
486 return false;
487 }
488
489 SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY);
490 if (!rec.trim(this->width(), this->height())) {
491 return false;
492 }
493
494 void* dstPixels = this->getAddr(rec.fX, rec.fY);
495 const SkImageInfo dstInfo = this->info().makeDimensions(rec.fInfo.dimensions());
496 SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes);
497 this->notifyPixelsChanged();
498 return true;
499}
500
501///////////////////////////////////////////////////////////////////////////////
502
503static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
504 SkASSERT(alpha != nullptr);
505 SkASSERT(alphaRowBytes >= src.width());
506
507 SkPixmap pmap;
508 if (!src.peekPixels(&pmap)) {
509 for (int y = 0; y < src.height(); ++y) {
510 memset(alpha, 0, src.width());
511 alpha += alphaRowBytes;
512 }
513 return false;
514 }
515 SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
516 pmap.info(), pmap.addr(), pmap.rowBytes());
517 return true;
518}
519
520#include "include/core/SkMaskFilter.h"
521#include "include/core/SkMatrix.h"
522#include "include/core/SkPaint.h"
523
524bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
525 Allocator *allocator, SkIPoint* offset) const {
526 SkDEBUGCODE(this->validate();)
527
528 SkBitmap tmpBitmap;
529 SkMatrix identity;
530 SkMask srcM, dstM;
531
532 if (this->width() == 0 || this->height() == 0) {
533 return false;
534 }
535 srcM.fBounds.setWH(this->width(), this->height());
536 srcM.fRowBytes = SkAlign4(this->width());
537 srcM.fFormat = SkMask::kA8_Format;
538
539 SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
540
541 // compute our (larger?) dst bounds if we have a filter
542 if (filter) {
543 identity.reset();
544 if (!as_MFB(filter)->filterMask(&dstM, srcM, identity, nullptr)) {
545 goto NO_FILTER_CASE;
546 }
547 dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
548 } else {
549 NO_FILTER_CASE:
550 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
551 if (!tmpBitmap.tryAllocPixels(allocator)) {
552 // Allocation of pixels for alpha bitmap failed.
553 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
554 tmpBitmap.width(), tmpBitmap.height());
555 return false;
556 }
557 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
558 if (offset) {
559 offset->set(0, 0);
560 }
561 tmpBitmap.swap(*dst);
562 return true;
563 }
564 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
565 SkAutoMaskFreeImage srcCleanup(srcM.fImage);
566
567 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
568 if (!as_MFB(filter)->filterMask(&dstM, srcM, identity, nullptr)) {
569 goto NO_FILTER_CASE;
570 }
571 SkAutoMaskFreeImage dstCleanup(dstM.fImage);
572
573 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
574 dstM.fRowBytes);
575 if (!tmpBitmap.tryAllocPixels(allocator)) {
576 // Allocation of pixels for alpha bitmap failed.
577 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
578 tmpBitmap.width(), tmpBitmap.height());
579 return false;
580 }
581 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
582 if (offset) {
583 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
584 }
585 SkDEBUGCODE(tmpBitmap.validate();)
586
587 tmpBitmap.swap(*dst);
588 return true;
589}
590
591///////////////////////////////////////////////////////////////////////////////
592
593#ifdef SK_DEBUG
594void SkBitmap::validate() const {
595 this->info().validate();
596
597 SkASSERT(this->info().validRowBytes(this->rowBytes()));
598 uint8_t allFlags = kImageIsVolatile_Flag;
599 SkASSERT((~allFlags & fFlags) == 0);
600
601 if (fPixelRef && fPixelRef->pixels()) {
602 SkASSERT(this->getPixels());
603 } else {
604 SkASSERT(!this->getPixels());
605 }
606
607 if (this->getPixels()) {
608 SkASSERT(fPixelRef);
609 SkASSERT(fPixelRef->rowBytes() == this->rowBytes());
610 SkIPoint origin = this->pixelRefOrigin();
611 SkASSERT(origin.fX >= 0);
612 SkASSERT(origin.fY >= 0);
613 SkASSERT(fPixelRef->width() >= (int)this->width() + origin.fX);
614 SkASSERT(fPixelRef->height() >= (int)this->height() + origin.fY);
615 SkASSERT(fPixelRef->rowBytes() >= this->info().minRowBytes());
616 }
617}
618#endif
619
620///////////////////////////////////////////////////////////////////////////////
621
622bool SkBitmap::peekPixels(SkPixmap* pmap) const {
623 if (this->getPixels()) {
624 if (pmap) {
625 *pmap = fPixmap;
626 }
627 return true;
628 }
629 return false;
630}
631