OLD | NEW |
| (Empty) |
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 | |
29 #ifdef SK_SUPPORT_MIPMAP | |
30 struct MipLevel { | |
31 void* fPixels; | |
32 uint32_t fRowBytes; | |
33 uint16_t fWidth, fHeight; | |
34 }; | |
35 | |
36 struct 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 | |
77 SkBitmap::SkBitmap() { | |
78 bzero(this, sizeof(*this)); | |
79 } | |
80 | |
81 SkBitmap::SkBitmap(const SkBitmap& src) { | |
82 SkDEBUGCODE(src.validate();) | |
83 bzero(this, sizeof(*this)); | |
84 *this = src; | |
85 SkDEBUGCODE(this->validate();) | |
86 } | |
87 | |
88 SkBitmap::~SkBitmap() { | |
89 SkDEBUGCODE(this->validate();) | |
90 this->freePixels(); | |
91 } | |
92 | |
93 SkBitmap& 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 | |
126 void 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 | |
145 void SkBitmap::reset() { | |
146 this->freePixels(); | |
147 bzero(this, sizeof(*this)); | |
148 } | |
149 | |
150 int 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 | |
177 int 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 | |
207 Sk64 SkBitmap::ComputeSize64(Config c, int width, int height) { | |
208 Sk64 size; | |
209 size.setMul(SkBitmap::ComputeRowBytes(c, width), height); | |
210 return size; | |
211 } | |
212 | |
213 size_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 | |
221 void 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 | |
237 void 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 | |
257 SkPixelRef* 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 | |
279 void SkBitmap::lockPixels() const { | |
280 if (NULL != fPixelRef && 1 == ++fPixelLockCount) { | |
281 fPixelRef->lockPixels(); | |
282 this->updatePixelsFromRef(); | |
283 } | |
284 SkDEBUGCODE(this->validate();) | |
285 } | |
286 | |
287 void 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 | |
297 void SkBitmap::setPixels(void* p, SkColorTable* ctable) { | |
298 this->freePixels(); | |
299 fPixels = p; | |
300 SkRefCnt_SafeAssign(fColorTable, ctable); | |
301 | |
302 SkDEBUGCODE(this->validate();) | |
303 } | |
304 | |
305 bool 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 | |
314 void 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 | |
333 void SkBitmap::freeMipMap() { | |
334 #ifdef SK_SUPPORT_MIPMAP | |
335 fMipMap->safeUnref(); | |
336 fMipMap = NULL; | |
337 #endif | |
338 } | |
339 | |
340 uint32_t SkBitmap::getGenerationID() const { | |
341 return fPixelRef ? fPixelRef->getGenerationID() : 0; | |
342 } | |
343 | |
344 void SkBitmap::notifyPixelsChanged() const { | |
345 if (fPixelRef) { | |
346 fPixelRef->notifyPixelsChanged(); | |
347 } | |
348 } | |
349 | |
350 /////////////////////////////////////////////////////////////////////////////// | |
351 | |
352 SkMallocPixelRef::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 | |
361 SkMallocPixelRef::~SkMallocPixelRef() { | |
362 fCTable->safeUnref(); | |
363 sk_free(fStorage); | |
364 } | |
365 | |
366 void* SkMallocPixelRef::onLockPixels(SkColorTable** ct) { | |
367 *ct = fCTable; | |
368 return fStorage; | |
369 } | |
370 | |
371 void SkMallocPixelRef::onUnlockPixels() { | |
372 // nothing to do | |
373 } | |
374 | |
375 void 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 | |
388 SkMallocPixelRef::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 | |
399 static 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 */ | |
405 bool 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 | |
425 bool 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 | |
459 void 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 | |
470 void* 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 | |
508 void 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 | |
590 static 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 | |
617 bool 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 | |
685 bool 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 | |
734 static 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 | |
760 static 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. | |
766 static inline U16CPU pack16(uint32_t c) { | |
767 return (c & ~SK_G16_MASK_IN_PLACE) | ((c >> 16) & SK_G16_MASK_IN_PLACE); | |
768 } | |
769 | |
770 static 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 | |
795 static uint32_t expand4444(U16CPU c) { | |
796 return (c & 0xF0F) | ((c & ~0xF0F) << 12); | |
797 } | |
798 | |
799 static U16CPU collaps4444(uint32_t c) { | |
800 return (c & 0xF0F) | ((c >> 12) & ~0xF0F); | |
801 } | |
802 | |
803 static 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 | |
828 void 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 | |
915 bool SkBitmap::hasMipMap() const { | |
916 #ifdef SK_SUPPORT_MIPMAP | |
917 return fMipMap != NULL; | |
918 #else | |
919 return false; | |
920 #endif | |
921 } | |
922 | |
923 int 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 | |
949 SkFixed 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 | |
969 static 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 | |
1027 void 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 | |
1081 enum { | |
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 | |
1089 static void writeString(SkFlattenableWriteBuffer& buffer, const char str[]) { | |
1090 size_t len = strlen(str); | |
1091 buffer.write32(len); | |
1092 buffer.writePad(str, len); | |
1093 } | |
1094 | |
1095 static 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 */ | |
1115 void 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 | |
1169 void 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 | |
1222 SkBitmap::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 | |
1228 SkBitmap::RLEPixels::~RLEPixels() { | |
1229 sk_free(fYPtrs); | |
1230 } | |
1231 | |
1232 /////////////////////////////////////////////////////////////////////////////// | |
1233 | |
1234 #ifdef SK_DEBUG | |
1235 void 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 | |
OLD | NEW |