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