blob: 5ca3601a42f5e189385168c8d2297b6a61a3948b [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "SkBitmap.h"
18#include "SkColorPriv.h"
19#include "SkDither.h"
20#include "SkFlattenable.h"
21#include "SkMallocPixelRef.h"
22#include "SkMask.h"
23#include "SkPixelRef.h"
24#include "SkThread.h"
25#include "SkUtils.h"
26#include "SkPackBits.h"
27#include <new>
28
29#ifdef SK_SUPPORT_MIPMAP
30struct MipLevel {
31 void* fPixels;
32 uint32_t fRowBytes;
33 uint16_t fWidth, fHeight;
34};
35
36struct SkBitmap::MipMap : SkNoncopyable {
37 int32_t fRefCnt;
38 int fLevelCount;
39// MipLevel fLevel[fLevelCount];
40// Pixels[]
41
42 static MipMap* Alloc(int levelCount, size_t pixelSize) {
43 MipMap* mm = (MipMap*)sk_malloc_throw(sizeof(MipMap) +
44 levelCount * sizeof(MipLevel) +
45 pixelSize);
46 mm->fRefCnt = 1;
47 mm->fLevelCount = levelCount;
48 return mm;
49 }
50
51 const MipLevel* levels() const { return (const MipLevel*)(this + 1); }
52 MipLevel* levels() { return (MipLevel*)(this + 1); }
53
54 const void* pixels() const { return levels() + fLevelCount; }
55 void* pixels() { return levels() + fLevelCount; }
56
57 void safeRef() {
58 if (this) {
59 SkASSERT(fRefCnt > 0);
60 sk_atomic_inc(&fRefCnt);
61 }
62 }
63 void safeUnref() {
64 if (this) {
65 SkASSERT(fRefCnt > 0);
66 if (sk_atomic_dec(&fRefCnt) == 1) {
67 sk_free(this);
68 }
69 }
70 }
71};
72#endif
73
74///////////////////////////////////////////////////////////////////////////////
75///////////////////////////////////////////////////////////////////////////////
76
77SkBitmap::SkBitmap() {
78 bzero(this, sizeof(*this));
79}
80
81SkBitmap::SkBitmap(const SkBitmap& src) {
82 SkDEBUGCODE(src.validate();)
83 bzero(this, sizeof(*this));
84 *this = src;
85 SkDEBUGCODE(this->validate();)
86}
87
88SkBitmap::~SkBitmap() {
89 SkDEBUGCODE(this->validate();)
90 this->freePixels();
91}
92
93SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
94 if (this != &src) {
95 this->freePixels();
96 memcpy(this, &src, sizeof(src));
97
98 // inc src reference counts
99 src.fPixelRef->safeRef();
100#ifdef SK_SUPPORT_MIPMAP
101 src.fMipMap->safeRef();
102#endif
103
104 // we reset our locks if we get blown away
105 fPixelLockCount = 0;
106
107 /* The src could be in 3 states
108 1. no pixelref, in which case we just copy/ref the pixels/ctable
109 2. unlocked pixelref, pixels/ctable should be null
110 3. locked pixelref, we should lock the ref again ourselves
111 */
112 if (NULL == fPixelRef) {
113 // leave fPixels as it is
114 fColorTable->safeRef(); // ref the user's ctable if present
115 } else { // we have a pixelref, so pixels/ctable reflect it
116 // ignore the values from the memcpy
117 fPixels = NULL;
118 fColorTable = NULL;
119 }
120 }
121
122 SkDEBUGCODE(this->validate();)
123 return *this;
124}
125
126void SkBitmap::swap(SkBitmap& other) {
127 SkTSwap<SkColorTable*>(fColorTable, other.fColorTable);
128 SkTSwap<SkPixelRef*>(fPixelRef, other.fPixelRef);
129 SkTSwap<size_t>(fPixelRefOffset, other.fPixelRefOffset);
130 SkTSwap<int>(fPixelLockCount, other.fPixelLockCount);
131#ifdef SK_SUPPORT_MIPMAP
132 SkTSwap<MipMap*>(fMipMap, other.fMipMap);
133#endif
134 SkTSwap<void*>(fPixels, other.fPixels);
135 SkTSwap<uint16_t>(fWidth, other.fWidth);
136 SkTSwap<uint16_t>(fHeight, other.fHeight);
137 SkTSwap<uint32_t>(fRowBytes, other.fRowBytes);
138 SkTSwap<uint8_t>(fConfig, other.fConfig);
139 SkTSwap<uint8_t>(fFlags, other.fFlags);
140 SkTSwap<uint8_t>(fBytesPerPixel, other.fBytesPerPixel);
141
142 SkDEBUGCODE(this->validate();)
143}
144
145void SkBitmap::reset() {
146 this->freePixels();
147 bzero(this, sizeof(*this));
148}
149
150int SkBitmap::ComputeBytesPerPixel(SkBitmap::Config config) {
151 int bpp;
152 switch (config) {
153 case kNo_Config:
154 case kA1_Config:
155 bpp = 0; // not applicable
156 break;
157 case kRLE_Index8_Config:
158 case kA8_Config:
159 case kIndex8_Config:
160 bpp = 1;
161 break;
162 case kRGB_565_Config:
163 case kARGB_4444_Config:
164 bpp = 2;
165 break;
166 case kARGB_8888_Config:
167 bpp = 4;
168 break;
169 default:
170 SkASSERT(!"unknown config");
171 bpp = 0; // error
172 break;
173 }
174 return bpp;
175}
176
177int SkBitmap::ComputeRowBytes(Config c, int width) {
178 int rowBytes = 0;
179
180 switch (c) {
181 case kNo_Config:
182 case kRLE_Index8_Config:
183 // assume that the bitmap has no pixels to draw to
184 rowBytes = 0;
185 break;
186 case kA1_Config:
187 rowBytes = (width + 7) >> 3;
188 break;
189 case kA8_Config:
190 case kIndex8_Config:
191 rowBytes = width;
192 break;
193 case kRGB_565_Config:
194 case kARGB_4444_Config:
195 rowBytes = width << 1;
196 break;
197 case kARGB_8888_Config:
198 rowBytes = width << 2;
199 break;
200 default:
201 SkASSERT(!"unknown config");
202 break;
203 }
204 return rowBytes;
205}
206
207Sk64 SkBitmap::ComputeSize64(Config c, int width, int height) {
208 Sk64 size;
209 size.setMul(SkBitmap::ComputeRowBytes(c, width), height);
210 return size;
211}
212
213size_t SkBitmap::ComputeSize(Config c, int width, int height) {
214 Sk64 size = SkBitmap::ComputeSize64(c, width, height);
215 if (size.isNeg() || !size.is32()) {
216 return 0;
217 }
218 return size.get32();
219}
220
221void SkBitmap::setConfig(Config c, int width, int height, int rowBytes) {
222 this->freePixels();
223
224 if (rowBytes == 0) {
225 rowBytes = SkBitmap::ComputeRowBytes(c, width);
226 }
227 fConfig = SkToU8(c);
228 fWidth = SkToU16(width);
229 fHeight = SkToU16(height);
230 fRowBytes = rowBytes;
231
232 fBytesPerPixel = (uint8_t)ComputeBytesPerPixel(c);
233
234 SkDEBUGCODE(this->validate();)
235}
236
237void SkBitmap::updatePixelsFromRef() const {
238 if (NULL != fPixelRef) {
239 if (fPixelLockCount > 0) {
240 SkASSERT(fPixelRef->getLockCount() > 0);
241
242 void* p = fPixelRef->pixels();
243 if (NULL != p) {
244 p = (char*)p + fPixelRefOffset;
245 }
246 fPixels = p;
247 SkRefCnt_SafeAssign(fColorTable, fPixelRef->colorTable());
248 } else {
249 SkASSERT(0 == fPixelLockCount);
250 fPixels = NULL;
251 fColorTable->safeUnref();
252 fColorTable = NULL;
253 }
254 }
255}
256
257SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, size_t offset) {
258 // do this first, we that we never have a non-zero offset with a null ref
259 if (NULL == pr) {
260 offset = 0;
261 }
262
263 if (fPixelRef != pr || fPixelRefOffset != offset) {
264 if (fPixelRef != pr) {
265 this->freePixels();
266 SkASSERT(NULL == fPixelRef);
267
268 pr->safeRef();
269 fPixelRef = pr;
270 }
271 fPixelRefOffset = offset;
272 this->updatePixelsFromRef();
273 }
274
275 SkDEBUGCODE(this->validate();)
276 return pr;
277}
278
279void SkBitmap::lockPixels() const {
280 if (NULL != fPixelRef && 1 == ++fPixelLockCount) {
281 fPixelRef->lockPixels();
282 this->updatePixelsFromRef();
283 }
284 SkDEBUGCODE(this->validate();)
285}
286
287void SkBitmap::unlockPixels() const {
288 SkASSERT(NULL == fPixelRef || fPixelLockCount > 0);
289
290 if (NULL != fPixelRef && 0 == --fPixelLockCount) {
291 fPixelRef->unlockPixels();
292 this->updatePixelsFromRef();
293 }
294 SkDEBUGCODE(this->validate();)
295}
296
297void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
298 this->freePixels();
299 fPixels = p;
300 SkRefCnt_SafeAssign(fColorTable, ctable);
301
302 SkDEBUGCODE(this->validate();)
303}
304
305bool SkBitmap::allocPixels(Allocator* allocator, SkColorTable* ctable) {
306 HeapAllocator stdalloc;
307
308 if (NULL == allocator) {
309 allocator = &stdalloc;
310 }
311 return allocator->allocPixelRef(this, ctable);
312}
313
314void SkBitmap::freePixels() {
315 // if we're gonna free the pixels, we certainly need to free the mipmap
316 this->freeMipMap();
317
318 fColorTable->safeUnref();
319 fColorTable = NULL;
320
321 if (NULL != fPixelRef) {
322 if (fPixelLockCount > 0) {
323 fPixelRef->unlockPixels();
324 }
325 fPixelRef->unref();
326 fPixelRef = NULL;
327 fPixelRefOffset = 0;
328 }
329 fPixelLockCount = 0;
330 fPixels = NULL;
331}
332
333void SkBitmap::freeMipMap() {
334#ifdef SK_SUPPORT_MIPMAP
335 fMipMap->safeUnref();
336 fMipMap = NULL;
337#endif
338}
339
340uint32_t SkBitmap::getGenerationID() const {
341 return fPixelRef ? fPixelRef->getGenerationID() : 0;
342}
343
344void SkBitmap::notifyPixelsChanged() const {
345 if (fPixelRef) {
346 fPixelRef->notifyPixelsChanged();
347 }
348}
349
350///////////////////////////////////////////////////////////////////////////////
351
352SkMallocPixelRef::SkMallocPixelRef(void* storage, size_t size,
353 SkColorTable* ctable) {
354 SkASSERT(storage);
355 fStorage = storage;
356 fSize = size;
357 fCTable = ctable;
358 ctable->safeRef();
359}
360
361SkMallocPixelRef::~SkMallocPixelRef() {
362 fCTable->safeUnref();
363 sk_free(fStorage);
364}
365
366void* SkMallocPixelRef::onLockPixels(SkColorTable** ct) {
367 *ct = fCTable;
368 return fStorage;
369}
370
371void SkMallocPixelRef::onUnlockPixels() {
372 // nothing to do
373}
374
375void SkMallocPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
376 this->INHERITED::flatten(buffer);
377
378 buffer.write32(fSize);
379 buffer.writePad(fStorage, fSize);
380 if (fCTable) {
381 buffer.writeBool(true);
382 fCTable->flatten(buffer);
383 } else {
384 buffer.writeBool(false);
385 }
386}
387
388SkMallocPixelRef::SkMallocPixelRef(SkFlattenableReadBuffer& buffer) : INHERITED(buffer, NULL) {
389 fSize = buffer.readU32();
390 fStorage = sk_malloc_throw(fSize);
391 buffer.read(fStorage, fSize);
392 if (buffer.readBool()) {
393 fCTable = SkNEW_ARGS(SkColorTable, (buffer));
394 } else {
395 fCTable = NULL;
396 }
397}
398
399static SkPixelRef::Registrar reg("SkMallocPixelRef",
400 SkMallocPixelRef::Create);
401
402/** We explicitly use the same allocator for our pixels that SkMask does,
403 so that we can freely assign memory allocated by one class to the other.
404 */
405bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
406 SkColorTable* ctable) {
407 Sk64 size = dst->getSize64();
408 if (size.isNeg() || !size.is32()) {
409 return false;
410 }
411
412 void* addr = sk_malloc_flags(size.get32(), 0); // returns NULL on failure
413 if (NULL == addr) {
414 return false;
415 }
416
417 dst->setPixelRef(new SkMallocPixelRef(addr, size.get32(), ctable))->unref();
418 // since we're already allocated, we lockPixels right away
419 dst->lockPixels();
420 return true;
421}
422
423///////////////////////////////////////////////////////////////////////////////
424
425bool SkBitmap::isOpaque() const {
426 switch (fConfig) {
427 case kNo_Config:
428 return true;
429
430 case kA1_Config:
431 case kA8_Config:
432 case kARGB_4444_Config:
433 case kARGB_8888_Config:
434 return (fFlags & kImageIsOpaque_Flag) != 0;
435
436 case kIndex8_Config:
437 case kRLE_Index8_Config: {
438 uint32_t flags = 0;
439
440 this->lockPixels();
441 // if lockPixels failed, we may not have a ctable ptr
442 if (fColorTable) {
443 flags = fColorTable->getFlags();
444 }
445 this->unlockPixels();
446
447 return (flags & SkColorTable::kColorsAreOpaque_Flag) != 0;
448 }
449
450 case kRGB_565_Config:
451 return true;
452
453 default:
454 SkASSERT(!"unknown bitmap config pased to isOpaque");
455 return false;
456 }
457}
458
459void SkBitmap::setIsOpaque(bool isOpaque) {
460 /* we record this regardless of fConfig, though it is ignored in
461 isOpaque() for configs that can't support per-pixel alpha.
462 */
463 if (isOpaque) {
464 fFlags |= kImageIsOpaque_Flag;
465 } else {
466 fFlags &= ~kImageIsOpaque_Flag;
467 }
468}
469
470void* SkBitmap::getAddr(int x, int y) const {
471 SkASSERT((unsigned)x < (unsigned)this->width());
472 SkASSERT((unsigned)y < (unsigned)this->height());
473
474 char* base = (char*)this->getPixels();
475 if (base) {
476 base += y * this->rowBytes();
477 switch (this->config()) {
478 case SkBitmap::kARGB_8888_Config:
479 base += x << 2;
480 break;
481 case SkBitmap::kARGB_4444_Config:
482 case SkBitmap::kRGB_565_Config:
483 base += x << 1;
484 break;
485 case SkBitmap::kA8_Config:
486 case SkBitmap::kIndex8_Config:
487 base += x;
488 break;
489 case SkBitmap::kA1_Config:
490 base += x >> 3;
491 break;
492 case kRLE_Index8_Config:
493 SkASSERT(!"Can't return addr for kRLE_Index8_Config");
494 base = NULL;
495 break;
496 default:
497 SkASSERT(!"Can't return addr for config");
498 base = NULL;
499 break;
500 }
501 }
502 return base;
503}
504
505///////////////////////////////////////////////////////////////////////////////
506///////////////////////////////////////////////////////////////////////////////
507
508void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const {
509 SkDEBUGCODE(this->validate();)
510
511 if (0 == fWidth || 0 == fHeight ||
512 kNo_Config == fConfig || kIndex8_Config == fConfig) {
513 return;
514 }
515
516 SkAutoLockPixels alp(*this);
517 // perform this check after the lock call
518 if (!this->readyToDraw()) {
519 return;
520 }
521
522 int height = fHeight;
523 const int width = fWidth;
524 const int rowBytes = fRowBytes;
525
526 // make rgb premultiplied
527 if (255 != a) {
528 r = SkAlphaMul(r, a);
529 g = SkAlphaMul(g, a);
530 b = SkAlphaMul(b, a);
531 }
532
533 switch (fConfig) {
534 case kA1_Config: {
535 uint8_t* p = (uint8_t*)fPixels;
536 const int count = (width + 7) >> 3;
537 a = (a >> 7) ? 0xFF : 0;
538 SkASSERT(count <= rowBytes);
539 while (--height >= 0) {
540 memset(p, a, count);
541 p += rowBytes;
542 }
543 break;
544 }
545 case kA8_Config: {
546 uint8_t* p = (uint8_t*)fPixels;
547 while (--height >= 0) {
548 memset(p, a, width);
549 p += rowBytes;
550 }
551 break;
552 }
553 case kARGB_4444_Config:
554 case kRGB_565_Config: {
555 uint16_t* p = (uint16_t*)fPixels;
556 uint16_t v;
557
558 if (kARGB_4444_Config == fConfig) {
559 v = SkPackARGB4444(a >> 4, r >> 4, g >> 4, b >> 4);
560 } else { // kRGB_565_Config
561 v = SkPackRGB16(r >> (8 - SK_R16_BITS), g >> (8 - SK_G16_BITS),
562 b >> (8 - SK_B16_BITS));
563 }
564 while (--height >= 0) {
565 sk_memset16(p, v, width);
566 p = (uint16_t*)((char*)p + rowBytes);
567 }
568 break;
569 }
570 case kARGB_8888_Config: {
571 uint32_t* p = (uint32_t*)fPixels;
572 uint32_t v = SkPackARGB32(a, r, g, b);
573
574 while (--height >= 0) {
575 sk_memset32(p, v, width);
576 p = (uint32_t*)((char*)p + rowBytes);
577 }
578 break;
579 }
580 }
581
582 this->notifyPixelsChanged();
583}
584
585//////////////////////////////////////////////////////////////////////////////////////
586//////////////////////////////////////////////////////////////////////////////////////
587
588#define SUB_OFFSET_FAILURE ((size_t)-1)
589
590static size_t getSubOffset(const SkBitmap& bm, int x, int y) {
591 SkASSERT((unsigned)x < (unsigned)bm.width());
592 SkASSERT((unsigned)y < (unsigned)bm.height());
593
594 switch (bm.getConfig()) {
595 case SkBitmap::kA8_Config:
596 case SkBitmap:: kIndex8_Config:
597 // x is fine as is for the calculation
598 break;
599
600 case SkBitmap::kRGB_565_Config:
601 case SkBitmap::kARGB_4444_Config:
602 x <<= 1;
603 break;
604
605 case SkBitmap::kARGB_8888_Config:
606 x <<= 2;
607 break;
608
609 case SkBitmap::kNo_Config:
610 case SkBitmap::kA1_Config:
611 default:
612 return SUB_OFFSET_FAILURE;
613 }
614 return y * bm.rowBytes() + x;
615}
616
617bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
618 SkDEBUGCODE(this->validate();)
619
620 if (NULL == result || (NULL == fPixelRef && NULL == fPixels)) {
621 return false; // no src pixels
622 }
623
624 SkIRect srcRect, r;
625 srcRect.set(0, 0, this->width(), this->height());
626 if (!r.intersect(srcRect, subset)) {
627 return false; // r is empty (i.e. no intersection)
628 }
629
630 if (kRLE_Index8_Config == fConfig) {
631 SkAutoLockPixels alp(*this);
632 // don't call readyToDraw(), since we can operate w/o a colortable
633 // at this stage
634 if (this->getPixels() == NULL) {
635 return false;
636 }
637 SkBitmap bm;
638
639 bm.setConfig(kIndex8_Config, r.width(), r.height());
640 bm.allocPixels(this->getColorTable());
641 if (NULL == bm.getPixels()) {
642 return false;
643 }
644
645 const RLEPixels* rle = (const RLEPixels*)this->getPixels();
646 uint8_t* dst = bm.getAddr8(0, 0);
647 const int width = bm.width();
648 const int rowBytes = bm.rowBytes();
649
650 for (int y = r.fTop; y < r.fBottom; y++) {
651 SkPackBits::Unpack8(dst, r.fLeft, width, rle->packedAtY(y));
652 dst += rowBytes;
653 }
654 result->swap(bm);
655 return true;
656 }
657
658 size_t offset = getSubOffset(*this, r.fLeft, r.fTop);
659 if (SUB_OFFSET_FAILURE == offset) {
660 return false; // config not supported
661 }
662
663 SkBitmap dst;
664 dst.setConfig(this->config(), r.width(), r.height(), this->rowBytes());
665
666 if (fPixelRef) {
667 // share the pixelref with a custom offset
668 dst.setPixelRef(fPixelRef, fPixelRefOffset + offset);
669 } else {
670 // share the pixels (owned by the caller)
671 dst.setPixels((char*)fPixels + offset, this->getColorTable());
672 }
673 SkDEBUGCODE(dst.validate();)
674
675 // we know we're good, so commit to result
676 result->swap(dst);
677 return true;
678}
679
680///////////////////////////////////////////////////////////////////////////////
681
682#include "SkCanvas.h"
683#include "SkPaint.h"
684
685bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const {
686 if (NULL == dst || this->width() == 0 || this->height() == 0) {
687 return false;
688 }
689
690 switch (dstConfig) {
691 case kA8_Config:
692 case kARGB_4444_Config:
693 case kRGB_565_Config:
694 case kARGB_8888_Config:
695 break;
696 default:
697 return false;
698 }
699
700 SkBitmap tmp;
701
702 tmp.setConfig(dstConfig, this->width(), this->height());
703 // pass null for colortable, since we don't support Index8 config for dst
704 if (!tmp.allocPixels(alloc, NULL)) {
705 return false;
706 }
707
708 SkAutoLockPixels srclock(*this);
709 SkAutoLockPixels dstlock(tmp);
710
711 if (!this->readyToDraw() || !tmp.readyToDraw()) {
712 // allocator/lock failed
713 return false;
714 }
715
716 // if the src has alpha, we have to clear the dst first
717 if (!this->isOpaque()) {
718 tmp.eraseColor(0);
719 }
720
721 SkCanvas canvas(tmp);
722 SkPaint paint;
723
724 paint.setDither(true);
725 canvas.drawBitmap(*this, 0, 0, &paint);
726
727 dst->swap(tmp);
728 return true;
729}
730
731///////////////////////////////////////////////////////////////////////////////
732///////////////////////////////////////////////////////////////////////////////
733
734static void downsampleby2_proc32(SkBitmap* dst, int x, int y,
735 const SkBitmap& src) {
736 x <<= 1;
737 y <<= 1;
738 const SkPMColor* p = src.getAddr32(x, y);
739 SkPMColor c, ag, rb;
740
741 c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF;
742 if (x < src.width() - 1) {
743 p += 1;
744 }
745 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF;
746
747 if (y < src.height() - 1) {
748 p = src.getAddr32(x, y + 1);
749 }
750 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF;
751 if (x < src.width() - 1) {
752 p += 1;
753 }
754 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF;
755
756 *dst->getAddr32(x >> 1, y >> 1) =
757 ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00);
758}
759
760static inline uint32_t expand16(U16CPU c) {
761 return (c & ~SK_G16_MASK_IN_PLACE) | ((c & SK_G16_MASK_IN_PLACE) << 16);
762}
763
764// returns dirt in the top 16bits, but we don't care, since we only
765// store the low 16bits.
766static inline U16CPU pack16(uint32_t c) {
767 return (c & ~SK_G16_MASK_IN_PLACE) | ((c >> 16) & SK_G16_MASK_IN_PLACE);
768}
769
770static void downsampleby2_proc16(SkBitmap* dst, int x, int y,
771 const SkBitmap& src) {
772 x <<= 1;
773 y <<= 1;
774 const uint16_t* p = src.getAddr16(x, y);
775 SkPMColor c;
776
777 c = expand16(*p);
778 if (x < (int)src.width() - 1) {
779 p += 1;
780 }
781 c += expand16(*p);
782
783 if (y < (int)src.height() - 1) {
784 p = src.getAddr16(x, y + 1);
785 }
786 c += expand16(*p);
787 if (x < (int)src.width() - 1) {
788 p += 1;
789 }
790 c += expand16(*p);
791
792 *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)pack16(c >> 2);
793}
794
795static uint32_t expand4444(U16CPU c) {
796 return (c & 0xF0F) | ((c & ~0xF0F) << 12);
797}
798
799static U16CPU collaps4444(uint32_t c) {
800 return (c & 0xF0F) | ((c >> 12) & ~0xF0F);
801}
802
803static void downsampleby2_proc4444(SkBitmap* dst, int x, int y,
804 const SkBitmap& src) {
805 x <<= 1;
806 y <<= 1;
807 const uint16_t* p = src.getAddr16(x, y);
808 uint32_t c;
809
810 c = expand4444(*p);
811 if (x < src.width() - 1) {
812 p += 1;
813 }
814 c += expand4444(*p);
815
816 if (y < src.height() - 1) {
817 p = src.getAddr16(x, y + 1);
818 }
819 c += expand4444(*p);
820 if (x < src.width() - 1) {
821 p += 1;
822 }
823 c += expand4444(*p);
824
825 *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)collaps4444(c >> 2);
826}
827
828void SkBitmap::buildMipMap(bool forceRebuild) {
829#ifdef SK_SUPPORT_MIPMAP
830 if (forceRebuild)
831 this->freeMipMap();
832 else if (fMipMap)
833 return; // we're already built
834
835 SkASSERT(NULL == fMipMap);
836
837 void (*proc)(SkBitmap* dst, int x, int y, const SkBitmap& src);
838
839 const SkBitmap::Config config = this->getConfig();
840
841 switch (config) {
842 case kARGB_8888_Config:
843 proc = downsampleby2_proc32;
844 break;
845 case kRGB_565_Config:
846 proc = downsampleby2_proc16;
847 break;
848 case kARGB_4444_Config:
849 proc = downsampleby2_proc4444;
850 break;
851 case kIndex8_Config:
852 case kA8_Config:
853 default:
854 return; // don't build mipmaps for these configs
855 }
856
857 // whip through our loop to compute the exact size needed
858 size_t size = 0;
859 int maxLevels = 0;
860 {
861 unsigned width = this->width();
862 unsigned height = this->height();
863 for (;;) {
864 width >>= 1;
865 height >>= 1;
866 if (0 == width || 0 == height) {
867 break;
868 }
869 size += ComputeRowBytes(config, width) * height;
870 maxLevels += 1;
871 }
872 }
873 if (0 == maxLevels) {
874 return;
875 }
876
877 MipMap* mm = MipMap::Alloc(maxLevels, size);
878 MipLevel* level = mm->levels();
879 uint8_t* addr = (uint8_t*)mm->pixels();
880
881 unsigned width = this->width();
882 unsigned height = this->height();
883 unsigned rowBytes = this->rowBytes();
884 SkBitmap srcBM(*this), dstBM;
885
886 srcBM.lockPixels();
887
888 for (int i = 0; i < maxLevels; i++) {
889 width >>= 1;
890 height >>= 1;
891 rowBytes = ComputeRowBytes(config, width);
892
893 level[i].fPixels = addr;
894 level[i].fWidth = SkToU16(width);
895 level[i].fHeight = SkToU16(height);
896 level[i].fRowBytes = SkToU16(rowBytes);
897
898 dstBM.setConfig(config, width, height, rowBytes);
899 dstBM.setPixels(addr);
900
901 for (unsigned y = 0; y < height; y++) {
902 for (unsigned x = 0; x < width; x++) {
903 proc(&dstBM, x, y, srcBM);
904 }
905 }
906
907 srcBM = dstBM;
908 addr += height * rowBytes;
909 }
910 SkASSERT(addr == (uint8_t*)mm->pixels() + size);
911 fMipMap = mm;
912#endif
913}
914
915bool SkBitmap::hasMipMap() const {
916#ifdef SK_SUPPORT_MIPMAP
917 return fMipMap != NULL;
918#else
919 return false;
920#endif
921}
922
923int SkBitmap::extractMipLevel(SkBitmap* dst, SkFixed sx, SkFixed sy) {
924#ifdef SK_SUPPORT_MIPMAP
925 if (NULL == fMipMap)
926 return 0;
927
928 int level = ComputeMipLevel(sx, sy) >> 16;
929 SkASSERT(level >= 0);
930 if (level <= 0) {
931 return 0;
932 }
933
934 if (level >= fMipMap->fLevelCount) {
935 level = fMipMap->fLevelCount - 1;
936 }
937 if (dst) {
938 const MipLevel& mip = fMipMap->levels()[level - 1];
939 dst->setConfig((SkBitmap::Config)this->config(),
940 mip.fWidth, mip.fHeight, mip.fRowBytes);
941 dst->setPixels(mip.fPixels);
942 }
943 return level;
944#else
945 return 0;
946#endif
947}
948
949SkFixed SkBitmap::ComputeMipLevel(SkFixed sx, SkFixed sy) {
950#ifdef SK_SUPPORT_MIPMAP
951 sx = SkAbs32(sx);
952 sy = SkAbs32(sy);
953 if (sx < sy) {
954 sx = sy;
955 }
956 if (sx < SK_Fixed1) {
957 return 0;
958 }
959 int clz = SkCLZ(sx);
960 SkASSERT(clz >= 1 && clz <= 15);
961 return SkIntToFixed(15 - clz) + ((unsigned)(sx << (clz + 1)) >> 16);
962#else
963 return 0;
964#endif
965}
966
967///////////////////////////////////////////////////////////////////////////////
968
969static void GetBitmapAlpha(const SkBitmap& src, uint8_t SK_RESTRICT alpha[],
970 int alphaRowBytes) {
971 SkASSERT(alpha != NULL);
972 SkASSERT(alphaRowBytes >= src.width());
973
974 SkBitmap::Config config = src.getConfig();
975 int w = src.width();
976 int h = src.height();
977 int rb = src.rowBytes();
978
979 if (SkBitmap::kA8_Config == config && !src.isOpaque()) {
980 const uint8_t* s = src.getAddr8(0, 0);
981 while (--h >= 0) {
982 memcpy(alpha, s, w);
983 s += rb;
984 alpha += alphaRowBytes;
985 }
986 } else if (SkBitmap::kARGB_8888_Config == config && !src.isOpaque()) {
987 const SkPMColor* SK_RESTRICT s = src.getAddr32(0, 0);
988 while (--h >= 0) {
989 for (int x = 0; x < w; x++) {
990 alpha[x] = SkGetPackedA32(s[x]);
991 }
992 s = (const SkPMColor*)((const char*)s + rb);
993 alpha += alphaRowBytes;
994 }
995 } else if (SkBitmap::kARGB_4444_Config == config && !src.isOpaque()) {
996 const SkPMColor16* SK_RESTRICT s = src.getAddr16(0, 0);
997 while (--h >= 0) {
998 for (int x = 0; x < w; x++) {
999 alpha[x] = SkPacked4444ToA32(s[x]);
1000 }
1001 s = (const SkPMColor16*)((const char*)s + rb);
1002 alpha += alphaRowBytes;
1003 }
1004 } else if (SkBitmap::kIndex8_Config == config && !src.isOpaque()) {
1005 SkColorTable* ct = src.getColorTable();
1006 if (ct) {
1007 const SkPMColor* SK_RESTRICT table = ct->lockColors();
1008 const uint8_t* SK_RESTRICT s = src.getAddr8(0, 0);
1009 while (--h >= 0) {
1010 for (int x = 0; x < w; x++) {
1011 alpha[x] = SkGetPackedA32(table[s[x]]);
1012 }
1013 s += rb;
1014 alpha += alphaRowBytes;
1015 }
1016 ct->unlockColors(false);
1017 }
1018 } else { // src is opaque, so just fill alpha[] with 0xFF
1019 memset(alpha, 0xFF, h * alphaRowBytes);
1020 }
1021}
1022
1023#include "SkPaint.h"
1024#include "SkMaskFilter.h"
1025#include "SkMatrix.h"
1026
1027void SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
1028 SkIPoint* offset) const {
1029 SkDEBUGCODE(this->validate();)
1030
1031 SkMatrix identity;
1032 SkMask srcM, dstM;
1033
1034 srcM.fBounds.set(0, 0, this->width(), this->height());
1035 srcM.fRowBytes = SkAlign4(this->width());
1036 srcM.fFormat = SkMask::kA8_Format;
1037
1038 SkMaskFilter* filter = paint ? paint->getMaskFilter() : NULL;
1039
1040 // compute our (larger?) dst bounds if we have a filter
1041 if (NULL != filter) {
1042 identity.reset();
1043 srcM.fImage = NULL;
1044 if (!filter->filterMask(&dstM, srcM, identity, NULL)) {
1045 goto NO_FILTER_CASE;
1046 }
1047 dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
1048 } else {
1049 NO_FILTER_CASE:
1050 dst->setConfig(SkBitmap::kA8_Config, this->width(), this->height(),
1051 srcM.fRowBytes);
1052 dst->allocPixels();
1053 GetBitmapAlpha(*this, dst->getAddr8(0, 0), srcM.fRowBytes);
1054 if (offset) {
1055 offset->set(0, 0);
1056 }
1057 return;
1058 }
1059
1060 SkAutoMaskImage srcCleanup(&srcM, true);
1061
1062 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
1063 if (!filter->filterMask(&dstM, srcM, identity, NULL)) {
1064 goto NO_FILTER_CASE;
1065 }
1066
1067 SkAutoMaskImage dstCleanup(&dstM, false);
1068
1069 dst->setConfig(SkBitmap::kA8_Config, dstM.fBounds.width(),
1070 dstM.fBounds.height(), dstM.fRowBytes);
1071 dst->allocPixels();
1072 memcpy(dst->getPixels(), dstM.fImage, dstM.computeImageSize());
1073 if (offset) {
1074 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
1075 }
1076 SkDEBUGCODE(dst->validate();)
1077}
1078
1079///////////////////////////////////////////////////////////////////////////////
1080
1081enum {
1082 SERIALIZE_PIXELTYPE_NONE,
1083 SERIALIZE_PIXELTYPE_RAW_WITH_CTABLE,
1084 SERIALIZE_PIXELTYPE_RAW_NO_CTABLE,
1085 SERIALIZE_PIXELTYPE_REF_DATA,
1086 SERIALIZE_PIXELTYPE_REF_PTR,
1087};
1088
1089static void writeString(SkFlattenableWriteBuffer& buffer, const char str[]) {
1090 size_t len = strlen(str);
1091 buffer.write32(len);
1092 buffer.writePad(str, len);
1093}
1094
1095static SkPixelRef::Factory deserialize_factory(SkFlattenableReadBuffer& buffer) {
1096 size_t len = buffer.readInt();
1097 SkAutoSMalloc<256> storage(len + 1);
1098 char* str = (char*)storage.get();
1099 buffer.read(str, len);
1100 str[len] = 0;
1101 return SkPixelRef::NameToFactory(str);
1102}
1103
1104/*
1105 It is tricky to know how much to flatten. If we don't have a pixelref (i.e.
1106 we just have pixels, then we can only flatten the pixels, or write out an
1107 empty bitmap.
1108
1109 With a pixelref, we still have the question of recognizing when two sitings
1110 of the same pixelref are the same, and when they are different. Perhaps we
1111 should look at the generationID and keep a record of that in some dictionary
1112 associated with the buffer. SkGLTextureCache does this sort of thing to know
1113 when to create a new texture.
1114*/
1115void SkBitmap::flatten(SkFlattenableWriteBuffer& buffer) const {
1116 buffer.write32(fWidth);
1117 buffer.write32(fHeight);
1118 buffer.write32(fRowBytes);
1119 buffer.write8(fConfig);
1120 buffer.writeBool(this->isOpaque());
1121
1122 /* If we are called in this mode, then it is up to the caller to manage
1123 the owner-counts on the pixelref, as we just record the ptr itself.
1124 */
1125 if (!buffer.persistBitmapPixels()) {
1126 if (fPixelRef) {
1127 buffer.write8(SERIALIZE_PIXELTYPE_REF_PTR);
1128 buffer.write32(fPixelRefOffset);
1129 buffer.writeRefCnt(fPixelRef);
1130 return;
1131 } else {
1132 // we ignore the non-persist request, since we don't have a ref
1133 // ... or we could just write an empty bitmap...
1134 // (true) will write an empty bitmap, (false) will flatten the pix
1135 if (true) {
1136 buffer.write8(SERIALIZE_PIXELTYPE_NONE);
1137 return;
1138 }
1139 }
1140 }
1141
1142 if (fPixelRef) {
1143 SkPixelRef::Factory fact = fPixelRef->getFactory();
1144 if (fact) {
1145 const char* name = SkPixelRef::FactoryToName(fact);
1146 if (name && *name) {
1147 buffer.write8(SERIALIZE_PIXELTYPE_REF_DATA);
1148 buffer.write32(fPixelRefOffset);
1149 writeString(buffer, name);
1150 fPixelRef->flatten(buffer);
1151 return;
1152 }
1153 }
1154 // if we get here, we can't record the pixels
1155 buffer.write8(SERIALIZE_PIXELTYPE_NONE);
1156 } else if (fPixels) {
1157 if (fColorTable) {
1158 buffer.write8(SERIALIZE_PIXELTYPE_RAW_WITH_CTABLE);
1159 fColorTable->flatten(buffer);
1160 } else {
1161 buffer.write8(SERIALIZE_PIXELTYPE_RAW_NO_CTABLE);
1162 }
1163 buffer.writePad(fPixels, this->getSize());
1164 } else {
1165 buffer.write8(SERIALIZE_PIXELTYPE_NONE);
1166 }
1167}
1168
1169void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) {
1170 this->reset();
1171
1172 int width = buffer.readInt();
1173 int height = buffer.readInt();
1174 int rowBytes = buffer.readInt();
1175 int config = buffer.readU8();
1176
1177 this->setConfig((Config)config, width, height, rowBytes);
1178 this->setIsOpaque(buffer.readBool());
1179
1180 size_t size = this->getSize();
1181 int reftype = buffer.readU8();
1182 switch (reftype) {
1183 case SERIALIZE_PIXELTYPE_REF_PTR: {
1184 size_t offset = buffer.readU32();
1185 SkPixelRef* pr = (SkPixelRef*)buffer.readRefCnt();
1186 this->setPixelRef(pr, offset);
1187 break;
1188 }
1189 case SERIALIZE_PIXELTYPE_REF_DATA: {
1190 size_t offset = buffer.readU32();
1191 SkPixelRef::Factory fact = deserialize_factory(buffer);
1192 SkPixelRef* pr = fact(buffer);
1193 this->setPixelRef(pr, offset)->safeUnref();
1194 break;
1195 }
1196 case SERIALIZE_PIXELTYPE_RAW_WITH_CTABLE:
1197 case SERIALIZE_PIXELTYPE_RAW_NO_CTABLE: {
1198 SkColorTable* ctable = NULL;
1199 if (SERIALIZE_PIXELTYPE_RAW_WITH_CTABLE == reftype) {
1200 ctable = SkNEW_ARGS(SkColorTable, (buffer));
1201 }
1202 if (this->allocPixels(ctable)) {
1203 this->lockPixels();
1204 buffer.read(this->getPixels(), size);
1205 this->unlockPixels();
1206 } else {
1207 buffer.skip(size);
1208 }
1209 ctable->safeUnref();
1210 break;
1211 }
1212 case SERIALIZE_PIXELTYPE_NONE:
1213 break;
1214 default:
1215 SkASSERT(!"unrecognized pixeltype in serialized data");
1216 sk_throw();
1217 }
1218}
1219
1220///////////////////////////////////////////////////////////////////////////////
1221
1222SkBitmap::RLEPixels::RLEPixels(int width, int height) {
1223 fHeight = height;
1224 fYPtrs = (uint8_t**)sk_malloc_throw(height * sizeof(uint8_t*));
1225 bzero(fYPtrs, height * sizeof(uint8_t*));
1226}
1227
1228SkBitmap::RLEPixels::~RLEPixels() {
1229 sk_free(fYPtrs);
1230}
1231
1232///////////////////////////////////////////////////////////////////////////////
1233
1234#ifdef SK_DEBUG
1235void SkBitmap::validate() const {
1236 SkASSERT(fConfig < kConfigCount);
1237 SkASSERT(fRowBytes >= (unsigned)ComputeRowBytes((Config)fConfig, fWidth));
1238 SkASSERT(fFlags <= kImageIsOpaque_Flag);
1239 SkASSERT(fPixelLockCount >= 0);
1240 SkASSERT(NULL == fColorTable || (unsigned)fColorTable->getRefCnt() < 10000);
1241 SkASSERT((uint8_t)ComputeBytesPerPixel((Config)fConfig) == fBytesPerPixel);
1242
1243#if 0 // these asserts are not thread-correct, so disable for now
1244 if (fPixelRef) {
1245 if (fPixelLockCount > 0) {
1246 SkASSERT(fPixelRef->getLockCount() > 0);
1247 } else {
1248 SkASSERT(NULL == fPixels);
1249 SkASSERT(NULL == fColorTable);
1250 }
1251 }
1252#endif
1253}
1254#endif
1255