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