1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkBitmap.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1731 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2008 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#include "SkBitmap.h" 1.14 +#include "SkColorPriv.h" 1.15 +#include "SkDither.h" 1.16 +#include "SkFlattenable.h" 1.17 +#include "SkImagePriv.h" 1.18 +#include "SkMallocPixelRef.h" 1.19 +#include "SkMask.h" 1.20 +#include "SkReadBuffer.h" 1.21 +#include "SkWriteBuffer.h" 1.22 +#include "SkPixelRef.h" 1.23 +#include "SkThread.h" 1.24 +#include "SkUnPreMultiply.h" 1.25 +#include "SkUtils.h" 1.26 +#include "SkValidationUtils.h" 1.27 +#include "SkPackBits.h" 1.28 +#include <new> 1.29 + 1.30 +static bool reset_return_false(SkBitmap* bm) { 1.31 + bm->reset(); 1.32 + return false; 1.33 +} 1.34 + 1.35 +struct MipLevel { 1.36 + void* fPixels; 1.37 + uint32_t fRowBytes; 1.38 + uint32_t fWidth, fHeight; 1.39 +}; 1.40 + 1.41 +struct SkBitmap::MipMap : SkNoncopyable { 1.42 + int32_t fRefCnt; 1.43 + int fLevelCount; 1.44 +// MipLevel fLevel[fLevelCount]; 1.45 +// Pixels[] 1.46 + 1.47 + static MipMap* Alloc(int levelCount, size_t pixelSize) { 1.48 + if (levelCount < 0) { 1.49 + return NULL; 1.50 + } 1.51 + int64_t size = (levelCount + 1) * sizeof(MipLevel); 1.52 + size += sizeof(MipMap) + pixelSize; 1.53 + if (!sk_64_isS32(size)) { 1.54 + return NULL; 1.55 + } 1.56 + MipMap* mm = (MipMap*)sk_malloc_throw(sk_64_asS32(size)); 1.57 + mm->fRefCnt = 1; 1.58 + mm->fLevelCount = levelCount; 1.59 + return mm; 1.60 + } 1.61 + 1.62 + const MipLevel* levels() const { return (const MipLevel*)(this + 1); } 1.63 + MipLevel* levels() { return (MipLevel*)(this + 1); } 1.64 + 1.65 + const void* pixels() const { return levels() + fLevelCount; } 1.66 + void* pixels() { return levels() + fLevelCount; } 1.67 + 1.68 + void ref() { 1.69 + if (SK_MaxS32 == sk_atomic_inc(&fRefCnt)) { 1.70 + sk_throw(); 1.71 + } 1.72 + } 1.73 + void unref() { 1.74 + SkASSERT(fRefCnt > 0); 1.75 + if (sk_atomic_dec(&fRefCnt) == 1) { 1.76 + sk_free(this); 1.77 + } 1.78 + } 1.79 +}; 1.80 + 1.81 +/////////////////////////////////////////////////////////////////////////////// 1.82 +/////////////////////////////////////////////////////////////////////////////// 1.83 + 1.84 +SkBitmap::SkBitmap() { 1.85 + sk_bzero(this, sizeof(*this)); 1.86 +} 1.87 + 1.88 +SkBitmap::SkBitmap(const SkBitmap& src) { 1.89 + SkDEBUGCODE(src.validate();) 1.90 + sk_bzero(this, sizeof(*this)); 1.91 + *this = src; 1.92 + SkDEBUGCODE(this->validate();) 1.93 +} 1.94 + 1.95 +SkBitmap::~SkBitmap() { 1.96 + SkDEBUGCODE(this->validate();) 1.97 + this->freePixels(); 1.98 +} 1.99 + 1.100 +SkBitmap& SkBitmap::operator=(const SkBitmap& src) { 1.101 + if (this != &src) { 1.102 + this->freePixels(); 1.103 + memcpy(this, &src, sizeof(src)); 1.104 + 1.105 + // inc src reference counts 1.106 + SkSafeRef(src.fPixelRef); 1.107 + SkSafeRef(src.fMipMap); 1.108 + 1.109 + // we reset our locks if we get blown away 1.110 + fPixelLockCount = 0; 1.111 + 1.112 + if (fPixelRef) { 1.113 + // ignore the values from the memcpy 1.114 + fPixels = NULL; 1.115 + fColorTable = NULL; 1.116 + // Note that what to for genID is somewhat arbitrary. We have no 1.117 + // way to track changes to raw pixels across multiple SkBitmaps. 1.118 + // Would benefit from an SkRawPixelRef type created by 1.119 + // setPixels. 1.120 + // Just leave the memcpy'ed one but they'll get out of sync 1.121 + // as soon either is modified. 1.122 + } 1.123 + } 1.124 + 1.125 + SkDEBUGCODE(this->validate();) 1.126 + return *this; 1.127 +} 1.128 + 1.129 +void SkBitmap::swap(SkBitmap& other) { 1.130 + SkTSwap(fColorTable, other.fColorTable); 1.131 + SkTSwap(fPixelRef, other.fPixelRef); 1.132 + SkTSwap(fPixelRefOrigin, other.fPixelRefOrigin); 1.133 + SkTSwap(fPixelLockCount, other.fPixelLockCount); 1.134 + SkTSwap(fMipMap, other.fMipMap); 1.135 + SkTSwap(fPixels, other.fPixels); 1.136 + SkTSwap(fInfo, other.fInfo); 1.137 + SkTSwap(fRowBytes, other.fRowBytes); 1.138 + SkTSwap(fFlags, other.fFlags); 1.139 + 1.140 + SkDEBUGCODE(this->validate();) 1.141 +} 1.142 + 1.143 +void SkBitmap::reset() { 1.144 + this->freePixels(); 1.145 + sk_bzero(this, sizeof(*this)); 1.146 +} 1.147 + 1.148 +SkBitmap::Config SkBitmap::config() const { 1.149 + return SkColorTypeToBitmapConfig(fInfo.colorType()); 1.150 +} 1.151 + 1.152 +int SkBitmap::ComputeBytesPerPixel(SkBitmap::Config config) { 1.153 + int bpp; 1.154 + switch (config) { 1.155 + case kNo_Config: 1.156 + bpp = 0; // not applicable 1.157 + break; 1.158 + case kA8_Config: 1.159 + case kIndex8_Config: 1.160 + bpp = 1; 1.161 + break; 1.162 + case kRGB_565_Config: 1.163 + case kARGB_4444_Config: 1.164 + bpp = 2; 1.165 + break; 1.166 + case kARGB_8888_Config: 1.167 + bpp = 4; 1.168 + break; 1.169 + default: 1.170 + SkDEBUGFAIL("unknown config"); 1.171 + bpp = 0; // error 1.172 + break; 1.173 + } 1.174 + return bpp; 1.175 +} 1.176 + 1.177 +size_t SkBitmap::ComputeRowBytes(Config c, int width) { 1.178 + return SkColorTypeMinRowBytes(SkBitmapConfigToColorType(c), width); 1.179 +} 1.180 + 1.181 +int64_t SkBitmap::ComputeSize64(Config config, int width, int height) { 1.182 + SkColorType ct = SkBitmapConfigToColorType(config); 1.183 + int64_t rowBytes = sk_64_mul(SkColorTypeBytesPerPixel(ct), width); 1.184 + return rowBytes * height; 1.185 +} 1.186 + 1.187 +size_t SkBitmap::ComputeSize(Config c, int width, int height) { 1.188 + int64_t size = SkBitmap::ComputeSize64(c, width, height); 1.189 + return sk_64_isS32(size) ? sk_64_asS32(size) : 0; 1.190 +} 1.191 + 1.192 +int64_t SkBitmap::ComputeSafeSize64(Config config, 1.193 + uint32_t width, 1.194 + uint32_t height, 1.195 + size_t rowBytes) { 1.196 + SkImageInfo info = SkImageInfo::Make(width, height, 1.197 + SkBitmapConfigToColorType(config), 1.198 + kPremul_SkAlphaType); 1.199 + return info.getSafeSize64(rowBytes); 1.200 +} 1.201 + 1.202 +size_t SkBitmap::ComputeSafeSize(Config config, 1.203 + uint32_t width, 1.204 + uint32_t height, 1.205 + size_t rowBytes) { 1.206 + int64_t safeSize = ComputeSafeSize64(config, width, height, rowBytes); 1.207 + int32_t safeSize32 = (int32_t)safeSize; 1.208 + 1.209 + if (safeSize32 != safeSize) { 1.210 + safeSize32 = 0; 1.211 + } 1.212 + return safeSize32; 1.213 +} 1.214 + 1.215 +void SkBitmap::getBounds(SkRect* bounds) const { 1.216 + SkASSERT(bounds); 1.217 + bounds->set(0, 0, 1.218 + SkIntToScalar(fInfo.fWidth), SkIntToScalar(fInfo.fHeight)); 1.219 +} 1.220 + 1.221 +void SkBitmap::getBounds(SkIRect* bounds) const { 1.222 + SkASSERT(bounds); 1.223 + bounds->set(0, 0, fInfo.fWidth, fInfo.fHeight); 1.224 +} 1.225 + 1.226 +/////////////////////////////////////////////////////////////////////////////// 1.227 + 1.228 +static bool validate_alphaType(SkColorType colorType, SkAlphaType alphaType, 1.229 + SkAlphaType* canonical = NULL) { 1.230 + switch (colorType) { 1.231 + case kUnknown_SkColorType: 1.232 + alphaType = kIgnore_SkAlphaType; 1.233 + break; 1.234 + case kAlpha_8_SkColorType: 1.235 + if (kUnpremul_SkAlphaType == alphaType) { 1.236 + alphaType = kPremul_SkAlphaType; 1.237 + } 1.238 + // fall-through 1.239 + case kIndex_8_SkColorType: 1.240 + case kARGB_4444_SkColorType: 1.241 + case kRGBA_8888_SkColorType: 1.242 + case kBGRA_8888_SkColorType: 1.243 + if (kIgnore_SkAlphaType == alphaType) { 1.244 + return false; 1.245 + } 1.246 + break; 1.247 + case kRGB_565_SkColorType: 1.248 + alphaType = kOpaque_SkAlphaType; 1.249 + break; 1.250 + default: 1.251 + return false; 1.252 + } 1.253 + if (canonical) { 1.254 + *canonical = alphaType; 1.255 + } 1.256 + return true; 1.257 +} 1.258 + 1.259 +bool SkBitmap::setConfig(const SkImageInfo& origInfo, size_t rowBytes) { 1.260 + SkImageInfo info = origInfo; 1.261 + 1.262 + if (!validate_alphaType(info.fColorType, info.fAlphaType, 1.263 + &info.fAlphaType)) { 1.264 + return reset_return_false(this); 1.265 + } 1.266 + 1.267 + // require that rowBytes fit in 31bits 1.268 + int64_t mrb = info.minRowBytes64(); 1.269 + if ((int32_t)mrb != mrb) { 1.270 + return reset_return_false(this); 1.271 + } 1.272 + if ((int64_t)rowBytes != (int32_t)rowBytes) { 1.273 + return reset_return_false(this); 1.274 + } 1.275 + 1.276 + if (info.width() < 0 || info.height() < 0) { 1.277 + return reset_return_false(this); 1.278 + } 1.279 + 1.280 + if (kUnknown_SkColorType == info.colorType()) { 1.281 + rowBytes = 0; 1.282 + } else if (0 == rowBytes) { 1.283 + rowBytes = (size_t)mrb; 1.284 + } else if (rowBytes < info.minRowBytes()) { 1.285 + return reset_return_false(this); 1.286 + } 1.287 + 1.288 + this->freePixels(); 1.289 + 1.290 + fInfo = info; 1.291 + fRowBytes = SkToU32(rowBytes); 1.292 + return true; 1.293 +} 1.294 + 1.295 +bool SkBitmap::setConfig(Config config, int width, int height, size_t rowBytes, 1.296 + SkAlphaType alphaType) { 1.297 + SkColorType ct = SkBitmapConfigToColorType(config); 1.298 + return this->setConfig(SkImageInfo::Make(width, height, ct, alphaType), 1.299 + rowBytes); 1.300 +} 1.301 + 1.302 +bool SkBitmap::setAlphaType(SkAlphaType alphaType) { 1.303 + if (!validate_alphaType(fInfo.fColorType, alphaType, &alphaType)) { 1.304 + return false; 1.305 + } 1.306 + if (fInfo.fAlphaType != alphaType) { 1.307 + fInfo.fAlphaType = alphaType; 1.308 + if (fPixelRef) { 1.309 + fPixelRef->changeAlphaType(alphaType); 1.310 + } 1.311 + } 1.312 + return true; 1.313 +} 1.314 + 1.315 +void SkBitmap::updatePixelsFromRef() const { 1.316 + if (NULL != fPixelRef) { 1.317 + if (fPixelLockCount > 0) { 1.318 + SkASSERT(fPixelRef->isLocked()); 1.319 + 1.320 + void* p = fPixelRef->pixels(); 1.321 + if (NULL != p) { 1.322 + p = (char*)p 1.323 + + fPixelRefOrigin.fY * fRowBytes 1.324 + + fPixelRefOrigin.fX * fInfo.bytesPerPixel(); 1.325 + } 1.326 + fPixels = p; 1.327 + fColorTable = fPixelRef->colorTable(); 1.328 + } else { 1.329 + SkASSERT(0 == fPixelLockCount); 1.330 + fPixels = NULL; 1.331 + fColorTable = NULL; 1.332 + } 1.333 + } 1.334 +} 1.335 + 1.336 +static bool config_to_colorType(SkBitmap::Config config, SkColorType* ctOut) { 1.337 + SkColorType ct; 1.338 + switch (config) { 1.339 + case SkBitmap::kA8_Config: 1.340 + ct = kAlpha_8_SkColorType; 1.341 + break; 1.342 + case SkBitmap::kIndex8_Config: 1.343 + ct = kIndex_8_SkColorType; 1.344 + break; 1.345 + case SkBitmap::kRGB_565_Config: 1.346 + ct = kRGB_565_SkColorType; 1.347 + break; 1.348 + case SkBitmap::kARGB_4444_Config: 1.349 + ct = kARGB_4444_SkColorType; 1.350 + break; 1.351 + case SkBitmap::kARGB_8888_Config: 1.352 + ct = kPMColor_SkColorType; 1.353 + break; 1.354 + case SkBitmap::kNo_Config: 1.355 + default: 1.356 + return false; 1.357 + } 1.358 + if (ctOut) { 1.359 + *ctOut = ct; 1.360 + } 1.361 + return true; 1.362 +} 1.363 + 1.364 +SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) { 1.365 +#ifdef SK_DEBUG 1.366 + if (pr) { 1.367 + SkImageInfo info; 1.368 + if (this->asImageInfo(&info)) { 1.369 + const SkImageInfo& prInfo = pr->info(); 1.370 + SkASSERT(info.fWidth <= prInfo.fWidth); 1.371 + SkASSERT(info.fHeight <= prInfo.fHeight); 1.372 + SkASSERT(info.fColorType == prInfo.fColorType); 1.373 + switch (prInfo.fAlphaType) { 1.374 + case kIgnore_SkAlphaType: 1.375 + SkASSERT(fInfo.fAlphaType == kIgnore_SkAlphaType); 1.376 + break; 1.377 + case kOpaque_SkAlphaType: 1.378 + case kPremul_SkAlphaType: 1.379 + SkASSERT(info.fAlphaType == kOpaque_SkAlphaType || 1.380 + info.fAlphaType == kPremul_SkAlphaType); 1.381 + break; 1.382 + case kUnpremul_SkAlphaType: 1.383 + SkASSERT(info.fAlphaType == kOpaque_SkAlphaType || 1.384 + info.fAlphaType == kUnpremul_SkAlphaType); 1.385 + break; 1.386 + } 1.387 + } 1.388 + } 1.389 +#endif 1.390 + 1.391 + if (pr) { 1.392 + const SkImageInfo& info = pr->info(); 1.393 + fPixelRefOrigin.set(SkPin32(dx, 0, info.fWidth), 1.394 + SkPin32(dy, 0, info.fHeight)); 1.395 + } else { 1.396 + // ignore dx,dy if there is no pixelref 1.397 + fPixelRefOrigin.setZero(); 1.398 + } 1.399 + 1.400 + if (fPixelRef != pr) { 1.401 + if (fPixelRef != pr) { 1.402 + this->freePixels(); 1.403 + SkASSERT(NULL == fPixelRef); 1.404 + 1.405 + SkSafeRef(pr); 1.406 + fPixelRef = pr; 1.407 + } 1.408 + this->updatePixelsFromRef(); 1.409 + } 1.410 + 1.411 + SkDEBUGCODE(this->validate();) 1.412 + return pr; 1.413 +} 1.414 + 1.415 +void SkBitmap::lockPixels() const { 1.416 + if (NULL != fPixelRef && 0 == sk_atomic_inc(&fPixelLockCount)) { 1.417 + fPixelRef->lockPixels(); 1.418 + this->updatePixelsFromRef(); 1.419 + } 1.420 + SkDEBUGCODE(this->validate();) 1.421 +} 1.422 + 1.423 +void SkBitmap::unlockPixels() const { 1.424 + SkASSERT(NULL == fPixelRef || fPixelLockCount > 0); 1.425 + 1.426 + if (NULL != fPixelRef && 1 == sk_atomic_dec(&fPixelLockCount)) { 1.427 + fPixelRef->unlockPixels(); 1.428 + this->updatePixelsFromRef(); 1.429 + } 1.430 + SkDEBUGCODE(this->validate();) 1.431 +} 1.432 + 1.433 +bool SkBitmap::lockPixelsAreWritable() const { 1.434 + return (fPixelRef) ? fPixelRef->lockPixelsAreWritable() : false; 1.435 +} 1.436 + 1.437 +void SkBitmap::setPixels(void* p, SkColorTable* ctable) { 1.438 + if (NULL == p) { 1.439 + this->setPixelRef(NULL); 1.440 + return; 1.441 + } 1.442 + 1.443 + SkImageInfo info; 1.444 + if (!this->asImageInfo(&info)) { 1.445 + this->setPixelRef(NULL); 1.446 + return; 1.447 + } 1.448 + 1.449 + SkPixelRef* pr = SkMallocPixelRef::NewDirect(info, p, fRowBytes, ctable); 1.450 + if (NULL == pr) { 1.451 + this->setPixelRef(NULL); 1.452 + return; 1.453 + } 1.454 + 1.455 + this->setPixelRef(pr)->unref(); 1.456 + 1.457 + // since we're already allocated, we lockPixels right away 1.458 + this->lockPixels(); 1.459 + SkDEBUGCODE(this->validate();) 1.460 +} 1.461 + 1.462 +bool SkBitmap::allocPixels(Allocator* allocator, SkColorTable* ctable) { 1.463 + HeapAllocator stdalloc; 1.464 + 1.465 + if (NULL == allocator) { 1.466 + allocator = &stdalloc; 1.467 + } 1.468 + return allocator->allocPixelRef(this, ctable); 1.469 +} 1.470 + 1.471 +/////////////////////////////////////////////////////////////////////////////// 1.472 + 1.473 +bool SkBitmap::allocPixels(const SkImageInfo& info, SkPixelRefFactory* factory, 1.474 + SkColorTable* ctable) { 1.475 + if (kIndex_8_SkColorType == info.fColorType && NULL == ctable) { 1.476 + return reset_return_false(this); 1.477 + } 1.478 + if (!this->setConfig(info)) { 1.479 + return reset_return_false(this); 1.480 + } 1.481 + 1.482 + SkMallocPixelRef::PRFactory defaultFactory; 1.483 + if (NULL == factory) { 1.484 + factory = &defaultFactory; 1.485 + } 1.486 + 1.487 + SkPixelRef* pr = factory->create(info, ctable); 1.488 + if (NULL == pr) { 1.489 + return reset_return_false(this); 1.490 + } 1.491 + this->setPixelRef(pr)->unref(); 1.492 + 1.493 + // TODO: lockPixels could/should return bool or void*/NULL 1.494 + this->lockPixels(); 1.495 + if (NULL == this->getPixels()) { 1.496 + return reset_return_false(this); 1.497 + } 1.498 + return true; 1.499 +} 1.500 + 1.501 +bool SkBitmap::installPixels(const SkImageInfo& info, void* pixels, size_t rb, 1.502 + void (*releaseProc)(void* addr, void* context), 1.503 + void* context) { 1.504 + if (!this->setConfig(info, rb)) { 1.505 + this->reset(); 1.506 + return false; 1.507 + } 1.508 + 1.509 + SkPixelRef* pr = SkMallocPixelRef::NewWithProc(info, rb, NULL, pixels, 1.510 + releaseProc, context); 1.511 + if (!pr) { 1.512 + this->reset(); 1.513 + return false; 1.514 + } 1.515 + 1.516 + this->setPixelRef(pr)->unref(); 1.517 + 1.518 + // since we're already allocated, we lockPixels right away 1.519 + this->lockPixels(); 1.520 + SkDEBUGCODE(this->validate();) 1.521 + return true; 1.522 +} 1.523 + 1.524 +bool SkBitmap::installMaskPixels(const SkMask& mask) { 1.525 + if (SkMask::kA8_Format != mask.fFormat) { 1.526 + this->reset(); 1.527 + return false; 1.528 + } 1.529 + return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), 1.530 + mask.fBounds.height()), 1.531 + mask.fImage, mask.fRowBytes); 1.532 +} 1.533 + 1.534 +bool SkBitmap::allocConfigPixels(Config config, int width, int height, 1.535 + bool isOpaque) { 1.536 + SkColorType ct; 1.537 + if (!config_to_colorType(config, &ct)) { 1.538 + return false; 1.539 + } 1.540 + 1.541 + SkAlphaType at = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; 1.542 + return this->allocPixels(SkImageInfo::Make(width, height, ct, at)); 1.543 +} 1.544 + 1.545 +/////////////////////////////////////////////////////////////////////////////// 1.546 + 1.547 +void SkBitmap::freePixels() { 1.548 + // if we're gonna free the pixels, we certainly need to free the mipmap 1.549 + this->freeMipMap(); 1.550 + 1.551 + if (NULL != fPixelRef) { 1.552 + if (fPixelLockCount > 0) { 1.553 + fPixelRef->unlockPixels(); 1.554 + } 1.555 + fPixelRef->unref(); 1.556 + fPixelRef = NULL; 1.557 + fPixelRefOrigin.setZero(); 1.558 + } 1.559 + fPixelLockCount = 0; 1.560 + fPixels = NULL; 1.561 + fColorTable = NULL; 1.562 +} 1.563 + 1.564 +void SkBitmap::freeMipMap() { 1.565 + if (fMipMap) { 1.566 + fMipMap->unref(); 1.567 + fMipMap = NULL; 1.568 + } 1.569 +} 1.570 + 1.571 +uint32_t SkBitmap::getGenerationID() const { 1.572 + return (fPixelRef) ? fPixelRef->getGenerationID() : 0; 1.573 +} 1.574 + 1.575 +void SkBitmap::notifyPixelsChanged() const { 1.576 + SkASSERT(!this->isImmutable()); 1.577 + if (fPixelRef) { 1.578 + fPixelRef->notifyPixelsChanged(); 1.579 + } 1.580 +} 1.581 + 1.582 +GrTexture* SkBitmap::getTexture() const { 1.583 + return fPixelRef ? fPixelRef->getTexture() : NULL; 1.584 +} 1.585 + 1.586 +/////////////////////////////////////////////////////////////////////////////// 1.587 + 1.588 +/** We explicitly use the same allocator for our pixels that SkMask does, 1.589 + so that we can freely assign memory allocated by one class to the other. 1.590 + */ 1.591 +bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst, 1.592 + SkColorTable* ctable) { 1.593 + SkImageInfo info; 1.594 + if (!dst->asImageInfo(&info)) { 1.595 +// SkDebugf("unsupported config for info %d\n", dst->config()); 1.596 + return false; 1.597 + } 1.598 + 1.599 + SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, dst->rowBytes(), 1.600 + ctable); 1.601 + if (NULL == pr) { 1.602 + return false; 1.603 + } 1.604 + 1.605 + dst->setPixelRef(pr)->unref(); 1.606 + // since we're already allocated, we lockPixels right away 1.607 + dst->lockPixels(); 1.608 + return true; 1.609 +} 1.610 + 1.611 +/////////////////////////////////////////////////////////////////////////////// 1.612 + 1.613 +bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize, 1.614 + size_t dstRowBytes, bool preserveDstPad) const { 1.615 + 1.616 + if (0 == dstRowBytes) { 1.617 + dstRowBytes = fRowBytes; 1.618 + } 1.619 + 1.620 + if (dstRowBytes < fInfo.minRowBytes() || 1.621 + dst == NULL || (getPixels() == NULL && pixelRef() == NULL)) { 1.622 + return false; 1.623 + } 1.624 + 1.625 + if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == fRowBytes) { 1.626 + size_t safeSize = this->getSafeSize(); 1.627 + if (safeSize > dstSize || safeSize == 0) 1.628 + return false; 1.629 + else { 1.630 + SkAutoLockPixels lock(*this); 1.631 + // This implementation will write bytes beyond the end of each row, 1.632 + // excluding the last row, if the bitmap's stride is greater than 1.633 + // strictly required by the current config. 1.634 + memcpy(dst, getPixels(), safeSize); 1.635 + 1.636 + return true; 1.637 + } 1.638 + } else { 1.639 + // If destination has different stride than us, then copy line by line. 1.640 + if (fInfo.getSafeSize(dstRowBytes) > dstSize) { 1.641 + return false; 1.642 + } else { 1.643 + // Just copy what we need on each line. 1.644 + size_t rowBytes = fInfo.minRowBytes(); 1.645 + SkAutoLockPixels lock(*this); 1.646 + const uint8_t* srcP = reinterpret_cast<const uint8_t*>(getPixels()); 1.647 + uint8_t* dstP = reinterpret_cast<uint8_t*>(dst); 1.648 + for (int row = 0; row < fInfo.fHeight; 1.649 + row++, srcP += fRowBytes, dstP += dstRowBytes) { 1.650 + memcpy(dstP, srcP, rowBytes); 1.651 + } 1.652 + 1.653 + return true; 1.654 + } 1.655 + } 1.656 +} 1.657 + 1.658 +/////////////////////////////////////////////////////////////////////////////// 1.659 + 1.660 +bool SkBitmap::isImmutable() const { 1.661 + return fPixelRef ? fPixelRef->isImmutable() : 1.662 + fFlags & kImageIsImmutable_Flag; 1.663 +} 1.664 + 1.665 +void SkBitmap::setImmutable() { 1.666 + if (fPixelRef) { 1.667 + fPixelRef->setImmutable(); 1.668 + } else { 1.669 + fFlags |= kImageIsImmutable_Flag; 1.670 + } 1.671 +} 1.672 + 1.673 +bool SkBitmap::isVolatile() const { 1.674 + return (fFlags & kImageIsVolatile_Flag) != 0; 1.675 +} 1.676 + 1.677 +void SkBitmap::setIsVolatile(bool isVolatile) { 1.678 + if (isVolatile) { 1.679 + fFlags |= kImageIsVolatile_Flag; 1.680 + } else { 1.681 + fFlags &= ~kImageIsVolatile_Flag; 1.682 + } 1.683 +} 1.684 + 1.685 +void* SkBitmap::getAddr(int x, int y) const { 1.686 + SkASSERT((unsigned)x < (unsigned)this->width()); 1.687 + SkASSERT((unsigned)y < (unsigned)this->height()); 1.688 + 1.689 + char* base = (char*)this->getPixels(); 1.690 + if (base) { 1.691 + base += y * this->rowBytes(); 1.692 + switch (this->colorType()) { 1.693 + case kRGBA_8888_SkColorType: 1.694 + case kBGRA_8888_SkColorType: 1.695 + base += x << 2; 1.696 + break; 1.697 + case kARGB_4444_SkColorType: 1.698 + case kRGB_565_SkColorType: 1.699 + base += x << 1; 1.700 + break; 1.701 + case kAlpha_8_SkColorType: 1.702 + case kIndex_8_SkColorType: 1.703 + base += x; 1.704 + break; 1.705 + default: 1.706 + SkDEBUGFAIL("Can't return addr for config"); 1.707 + base = NULL; 1.708 + break; 1.709 + } 1.710 + } 1.711 + return base; 1.712 +} 1.713 + 1.714 +SkColor SkBitmap::getColor(int x, int y) const { 1.715 + SkASSERT((unsigned)x < (unsigned)this->width()); 1.716 + SkASSERT((unsigned)y < (unsigned)this->height()); 1.717 + 1.718 + switch (this->config()) { 1.719 + case SkBitmap::kA8_Config: { 1.720 + uint8_t* addr = this->getAddr8(x, y); 1.721 + return SkColorSetA(0, addr[0]); 1.722 + } 1.723 + case SkBitmap::kIndex8_Config: { 1.724 + SkPMColor c = this->getIndex8Color(x, y); 1.725 + return SkUnPreMultiply::PMColorToColor(c); 1.726 + } 1.727 + case SkBitmap::kRGB_565_Config: { 1.728 + uint16_t* addr = this->getAddr16(x, y); 1.729 + return SkPixel16ToColor(addr[0]); 1.730 + } 1.731 + case SkBitmap::kARGB_4444_Config: { 1.732 + uint16_t* addr = this->getAddr16(x, y); 1.733 + SkPMColor c = SkPixel4444ToPixel32(addr[0]); 1.734 + return SkUnPreMultiply::PMColorToColor(c); 1.735 + } 1.736 + case SkBitmap::kARGB_8888_Config: { 1.737 + uint32_t* addr = this->getAddr32(x, y); 1.738 + return SkUnPreMultiply::PMColorToColor(addr[0]); 1.739 + } 1.740 + case kNo_Config: 1.741 + default: 1.742 + SkASSERT(false); 1.743 + return 0; 1.744 + } 1.745 + SkASSERT(false); // Not reached. 1.746 + return 0; 1.747 +} 1.748 + 1.749 +bool SkBitmap::ComputeIsOpaque(const SkBitmap& bm) { 1.750 + SkAutoLockPixels alp(bm); 1.751 + if (!bm.getPixels()) { 1.752 + return false; 1.753 + } 1.754 + 1.755 + const int height = bm.height(); 1.756 + const int width = bm.width(); 1.757 + 1.758 + switch (bm.config()) { 1.759 + case SkBitmap::kA8_Config: { 1.760 + unsigned a = 0xFF; 1.761 + for (int y = 0; y < height; ++y) { 1.762 + const uint8_t* row = bm.getAddr8(0, y); 1.763 + for (int x = 0; x < width; ++x) { 1.764 + a &= row[x]; 1.765 + } 1.766 + if (0xFF != a) { 1.767 + return false; 1.768 + } 1.769 + } 1.770 + return true; 1.771 + } break; 1.772 + case SkBitmap::kIndex8_Config: { 1.773 + SkAutoLockColors alc(bm); 1.774 + const SkPMColor* table = alc.colors(); 1.775 + if (!table) { 1.776 + return false; 1.777 + } 1.778 + SkPMColor c = (SkPMColor)~0; 1.779 + for (int i = bm.getColorTable()->count() - 1; i >= 0; --i) { 1.780 + c &= table[i]; 1.781 + } 1.782 + return 0xFF == SkGetPackedA32(c); 1.783 + } break; 1.784 + case SkBitmap::kRGB_565_Config: 1.785 + return true; 1.786 + break; 1.787 + case SkBitmap::kARGB_4444_Config: { 1.788 + unsigned c = 0xFFFF; 1.789 + for (int y = 0; y < height; ++y) { 1.790 + const SkPMColor16* row = bm.getAddr16(0, y); 1.791 + for (int x = 0; x < width; ++x) { 1.792 + c &= row[x]; 1.793 + } 1.794 + if (0xF != SkGetPackedA4444(c)) { 1.795 + return false; 1.796 + } 1.797 + } 1.798 + return true; 1.799 + } break; 1.800 + case SkBitmap::kARGB_8888_Config: { 1.801 + SkPMColor c = (SkPMColor)~0; 1.802 + for (int y = 0; y < height; ++y) { 1.803 + const SkPMColor* row = bm.getAddr32(0, y); 1.804 + for (int x = 0; x < width; ++x) { 1.805 + c &= row[x]; 1.806 + } 1.807 + if (0xFF != SkGetPackedA32(c)) { 1.808 + return false; 1.809 + } 1.810 + } 1.811 + return true; 1.812 + } 1.813 + default: 1.814 + break; 1.815 + } 1.816 + return false; 1.817 +} 1.818 + 1.819 + 1.820 +/////////////////////////////////////////////////////////////////////////////// 1.821 +/////////////////////////////////////////////////////////////////////////////// 1.822 + 1.823 +static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) { 1.824 + unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) | 1.825 + (SkR32To4444(r) << SK_R4444_SHIFT) | 1.826 + (SkG32To4444(g) << SK_G4444_SHIFT) | 1.827 + (SkB32To4444(b) << SK_B4444_SHIFT); 1.828 + return SkToU16(pixel); 1.829 +} 1.830 + 1.831 +void SkBitmap::internalErase(const SkIRect& area, 1.832 + U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { 1.833 +#ifdef SK_DEBUG 1.834 + SkDEBUGCODE(this->validate();) 1.835 + SkASSERT(!area.isEmpty()); 1.836 + { 1.837 + SkIRect total = { 0, 0, this->width(), this->height() }; 1.838 + SkASSERT(total.contains(area)); 1.839 + } 1.840 +#endif 1.841 + 1.842 + switch (fInfo.colorType()) { 1.843 + case kUnknown_SkColorType: 1.844 + case kIndex_8_SkColorType: 1.845 + return; // can't erase 1.846 + default: 1.847 + break; 1.848 + } 1.849 + 1.850 + SkAutoLockPixels alp(*this); 1.851 + // perform this check after the lock call 1.852 + if (!this->readyToDraw()) { 1.853 + return; 1.854 + } 1.855 + 1.856 + int height = area.height(); 1.857 + const int width = area.width(); 1.858 + const int rowBytes = fRowBytes; 1.859 + 1.860 + // make rgb premultiplied 1.861 + if (255 != a) { 1.862 + r = SkAlphaMul(r, a); 1.863 + g = SkAlphaMul(g, a); 1.864 + b = SkAlphaMul(b, a); 1.865 + } 1.866 + 1.867 + switch (this->colorType()) { 1.868 + case kAlpha_8_SkColorType: { 1.869 + uint8_t* p = this->getAddr8(area.fLeft, area.fTop); 1.870 + while (--height >= 0) { 1.871 + memset(p, a, width); 1.872 + p += rowBytes; 1.873 + } 1.874 + break; 1.875 + } 1.876 + case kARGB_4444_SkColorType: 1.877 + case kRGB_565_SkColorType: { 1.878 + uint16_t* p = this->getAddr16(area.fLeft, area.fTop);; 1.879 + uint16_t v; 1.880 + 1.881 + if (kARGB_4444_SkColorType == this->colorType()) { 1.882 + v = pack_8888_to_4444(a, r, g, b); 1.883 + } else { 1.884 + v = SkPackRGB16(r >> (8 - SK_R16_BITS), 1.885 + g >> (8 - SK_G16_BITS), 1.886 + b >> (8 - SK_B16_BITS)); 1.887 + } 1.888 + while (--height >= 0) { 1.889 + sk_memset16(p, v, width); 1.890 + p = (uint16_t*)((char*)p + rowBytes); 1.891 + } 1.892 + break; 1.893 + } 1.894 + case kPMColor_SkColorType: { 1.895 + // what to do about BGRA or RGBA (which ever is != PMColor ? 1.896 + // for now we don't support them. 1.897 + uint32_t* p = this->getAddr32(area.fLeft, area.fTop); 1.898 + uint32_t v = SkPackARGB32(a, r, g, b); 1.899 + 1.900 + while (--height >= 0) { 1.901 + sk_memset32(p, v, width); 1.902 + p = (uint32_t*)((char*)p + rowBytes); 1.903 + } 1.904 + break; 1.905 + } 1.906 + default: 1.907 + return; // no change, so don't call notifyPixelsChanged() 1.908 + } 1.909 + 1.910 + this->notifyPixelsChanged(); 1.911 +} 1.912 + 1.913 +void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { 1.914 + SkIRect area = { 0, 0, this->width(), this->height() }; 1.915 + if (!area.isEmpty()) { 1.916 + this->internalErase(area, a, r, g, b); 1.917 + } 1.918 +} 1.919 + 1.920 +void SkBitmap::eraseArea(const SkIRect& rect, SkColor c) const { 1.921 + SkIRect area = { 0, 0, this->width(), this->height() }; 1.922 + if (area.intersect(rect)) { 1.923 + this->internalErase(area, SkColorGetA(c), SkColorGetR(c), 1.924 + SkColorGetG(c), SkColorGetB(c)); 1.925 + } 1.926 +} 1.927 + 1.928 +////////////////////////////////////////////////////////////////////////////////////// 1.929 +////////////////////////////////////////////////////////////////////////////////////// 1.930 + 1.931 +bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { 1.932 + SkDEBUGCODE(this->validate();) 1.933 + 1.934 + if (NULL == result || NULL == fPixelRef) { 1.935 + return false; // no src pixels 1.936 + } 1.937 + 1.938 + SkIRect srcRect, r; 1.939 + srcRect.set(0, 0, this->width(), this->height()); 1.940 + if (!r.intersect(srcRect, subset)) { 1.941 + return false; // r is empty (i.e. no intersection) 1.942 + } 1.943 + 1.944 + if (fPixelRef->getTexture() != NULL) { 1.945 + // Do a deep copy 1.946 + SkPixelRef* pixelRef = fPixelRef->deepCopy(this->config(), &subset); 1.947 + if (pixelRef != NULL) { 1.948 + SkBitmap dst; 1.949 + dst.setConfig(this->config(), subset.width(), subset.height(), 0, 1.950 + this->alphaType()); 1.951 + dst.setIsVolatile(this->isVolatile()); 1.952 + dst.setPixelRef(pixelRef)->unref(); 1.953 + SkDEBUGCODE(dst.validate()); 1.954 + result->swap(dst); 1.955 + return true; 1.956 + } 1.957 + } 1.958 + 1.959 + // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have 1.960 + // exited above. 1.961 + SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width())); 1.962 + SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height())); 1.963 + 1.964 + SkBitmap dst; 1.965 + dst.setConfig(this->config(), r.width(), r.height(), this->rowBytes(), 1.966 + this->alphaType()); 1.967 + dst.setIsVolatile(this->isVolatile()); 1.968 + 1.969 + if (fPixelRef) { 1.970 + SkIPoint origin = fPixelRefOrigin; 1.971 + origin.fX += r.fLeft; 1.972 + origin.fY += r.fTop; 1.973 + // share the pixelref with a custom offset 1.974 + dst.setPixelRef(fPixelRef, origin); 1.975 + } 1.976 + SkDEBUGCODE(dst.validate();) 1.977 + 1.978 + // we know we're good, so commit to result 1.979 + result->swap(dst); 1.980 + return true; 1.981 +} 1.982 + 1.983 +/////////////////////////////////////////////////////////////////////////////// 1.984 + 1.985 +#include "SkCanvas.h" 1.986 +#include "SkPaint.h" 1.987 + 1.988 +bool SkBitmap::canCopyTo(SkColorType dstColorType) const { 1.989 + if (this->colorType() == kUnknown_SkColorType) { 1.990 + return false; 1.991 + } 1.992 + 1.993 + bool sameConfigs = (this->colorType() == dstColorType); 1.994 + switch (dstColorType) { 1.995 + case kAlpha_8_SkColorType: 1.996 + case kRGB_565_SkColorType: 1.997 + case kPMColor_SkColorType: 1.998 + break; 1.999 + case kIndex_8_SkColorType: 1.1000 + if (!sameConfigs) { 1.1001 + return false; 1.1002 + } 1.1003 + break; 1.1004 + case kARGB_4444_SkColorType: 1.1005 + return sameConfigs || kPMColor_SkColorType == this->colorType(); 1.1006 + default: 1.1007 + return false; 1.1008 + } 1.1009 + return true; 1.1010 +} 1.1011 + 1.1012 +bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, 1.1013 + Allocator* alloc) const { 1.1014 + if (!this->canCopyTo(dstColorType)) { 1.1015 + return false; 1.1016 + } 1.1017 + 1.1018 + // if we have a texture, first get those pixels 1.1019 + SkBitmap tmpSrc; 1.1020 + const SkBitmap* src = this; 1.1021 + 1.1022 + if (fPixelRef) { 1.1023 + SkIRect subset; 1.1024 + subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY, 1.1025 + fInfo.width(), fInfo.height()); 1.1026 + if (fPixelRef->readPixels(&tmpSrc, &subset)) { 1.1027 + SkASSERT(tmpSrc.width() == this->width()); 1.1028 + SkASSERT(tmpSrc.height() == this->height()); 1.1029 + 1.1030 + // did we get lucky and we can just return tmpSrc? 1.1031 + if (tmpSrc.colorType() == dstColorType && NULL == alloc) { 1.1032 + dst->swap(tmpSrc); 1.1033 + // If the result is an exact copy, clone the gen ID. 1.1034 + if (dst->pixelRef() && dst->pixelRef()->info() == fPixelRef->info()) { 1.1035 + dst->pixelRef()->cloneGenID(*fPixelRef); 1.1036 + } 1.1037 + return true; 1.1038 + } 1.1039 + 1.1040 + // fall through to the raster case 1.1041 + src = &tmpSrc; 1.1042 + } 1.1043 + } 1.1044 + 1.1045 + // we lock this now, since we may need its colortable 1.1046 + SkAutoLockPixels srclock(*src); 1.1047 + if (!src->readyToDraw()) { 1.1048 + return false; 1.1049 + } 1.1050 + 1.1051 + // The only way to be readyToDraw is if fPixelRef is non NULL. 1.1052 + SkASSERT(fPixelRef != NULL); 1.1053 + 1.1054 + SkImageInfo dstInfo = src->info(); 1.1055 + dstInfo.fColorType = dstColorType; 1.1056 + 1.1057 + SkBitmap tmpDst; 1.1058 + if (!tmpDst.setConfig(dstInfo)) { 1.1059 + return false; 1.1060 + } 1.1061 + 1.1062 + // allocate colortable if srcConfig == kIndex8_Config 1.1063 + SkAutoTUnref<SkColorTable> ctable; 1.1064 + if (dstColorType == kIndex_8_SkColorType) { 1.1065 + // TODO: can we just ref() the src colortable? Is it reentrant-safe? 1.1066 + ctable.reset(SkNEW_ARGS(SkColorTable, (*src->getColorTable()))); 1.1067 + } 1.1068 + if (!tmpDst.allocPixels(alloc, ctable)) { 1.1069 + return false; 1.1070 + } 1.1071 + 1.1072 + if (!tmpDst.readyToDraw()) { 1.1073 + // allocator/lock failed 1.1074 + return false; 1.1075 + } 1.1076 + 1.1077 + // pixelRef must be non NULL or tmpDst.readyToDraw() would have 1.1078 + // returned false. 1.1079 + SkASSERT(tmpDst.pixelRef() != NULL); 1.1080 + 1.1081 + /* do memcpy for the same configs cases, else use drawing 1.1082 + */ 1.1083 + if (src->colorType() == dstColorType) { 1.1084 + if (tmpDst.getSize() == src->getSize()) { 1.1085 + memcpy(tmpDst.getPixels(), src->getPixels(), src->getSafeSize()); 1.1086 + SkPixelRef* pixelRef = tmpDst.pixelRef(); 1.1087 + 1.1088 + // In order to reach this point, we know that the width, config and 1.1089 + // rowbytes of the SkPixelRefs are the same, but it is possible for 1.1090 + // the heights to differ, if this SkBitmap's height is a subset of 1.1091 + // fPixelRef. Only if the SkPixelRefs' heights match are we 1.1092 + // guaranteed that this is an exact copy, meaning we should clone 1.1093 + // the genID. 1.1094 + if (pixelRef->info().fHeight == fPixelRef->info().fHeight) { 1.1095 + // TODO: what to do if the two infos match, BUT 1.1096 + // fPixelRef is premul and pixelRef is opaque? 1.1097 + // skipping assert for now 1.1098 + // https://code.google.com/p/skia/issues/detail?id=2012 1.1099 +// SkASSERT(pixelRef->info() == fPixelRef->info()); 1.1100 + SkASSERT(pixelRef->info().fWidth == fPixelRef->info().fWidth); 1.1101 + SkASSERT(pixelRef->info().fColorType == fPixelRef->info().fColorType); 1.1102 + pixelRef->cloneGenID(*fPixelRef); 1.1103 + } 1.1104 + } else { 1.1105 + const char* srcP = reinterpret_cast<const char*>(src->getPixels()); 1.1106 + char* dstP = reinterpret_cast<char*>(tmpDst.getPixels()); 1.1107 + // to be sure we don't read too much, only copy our logical pixels 1.1108 + size_t bytesToCopy = tmpDst.width() * tmpDst.bytesPerPixel(); 1.1109 + for (int y = 0; y < tmpDst.height(); y++) { 1.1110 + memcpy(dstP, srcP, bytesToCopy); 1.1111 + srcP += src->rowBytes(); 1.1112 + dstP += tmpDst.rowBytes(); 1.1113 + } 1.1114 + } 1.1115 + } else if (kARGB_4444_SkColorType == dstColorType 1.1116 + && kPMColor_SkColorType == src->colorType()) { 1.1117 + SkASSERT(src->height() == tmpDst.height()); 1.1118 + SkASSERT(src->width() == tmpDst.width()); 1.1119 + for (int y = 0; y < src->height(); ++y) { 1.1120 + SkPMColor16* SK_RESTRICT dstRow = (SkPMColor16*) tmpDst.getAddr16(0, y); 1.1121 + SkPMColor* SK_RESTRICT srcRow = (SkPMColor*) src->getAddr32(0, y); 1.1122 + DITHER_4444_SCAN(y); 1.1123 + for (int x = 0; x < src->width(); ++x) { 1.1124 + dstRow[x] = SkDitherARGB32To4444(srcRow[x], 1.1125 + DITHER_VALUE(x)); 1.1126 + } 1.1127 + } 1.1128 + } else { 1.1129 + // Always clear the dest in case one of the blitters accesses it 1.1130 + // TODO: switch the allocation of tmpDst to call sk_calloc_throw 1.1131 + tmpDst.eraseColor(SK_ColorTRANSPARENT); 1.1132 + 1.1133 + SkCanvas canvas(tmpDst); 1.1134 + SkPaint paint; 1.1135 + 1.1136 + paint.setDither(true); 1.1137 + canvas.drawBitmap(*src, 0, 0, &paint); 1.1138 + } 1.1139 + 1.1140 + dst->swap(tmpDst); 1.1141 + return true; 1.1142 +} 1.1143 + 1.1144 +bool SkBitmap::deepCopyTo(SkBitmap* dst) const { 1.1145 + const SkBitmap::Config dstConfig = this->config(); 1.1146 + const SkColorType dstCT = SkBitmapConfigToColorType(dstConfig); 1.1147 + 1.1148 + if (!this->canCopyTo(dstCT)) { 1.1149 + return false; 1.1150 + } 1.1151 + 1.1152 + // If we have a PixelRef, and it supports deep copy, use it. 1.1153 + // Currently supported only by texture-backed bitmaps. 1.1154 + if (fPixelRef) { 1.1155 + SkPixelRef* pixelRef = fPixelRef->deepCopy(dstConfig); 1.1156 + if (pixelRef) { 1.1157 + uint32_t rowBytes; 1.1158 + if (this->colorType() == dstCT) { 1.1159 + // Since there is no subset to pass to deepCopy, and deepCopy 1.1160 + // succeeded, the new pixel ref must be identical. 1.1161 + SkASSERT(fPixelRef->info() == pixelRef->info()); 1.1162 + pixelRef->cloneGenID(*fPixelRef); 1.1163 + // Use the same rowBytes as the original. 1.1164 + rowBytes = fRowBytes; 1.1165 + } else { 1.1166 + // With the new config, an appropriate fRowBytes will be computed by setConfig. 1.1167 + rowBytes = 0; 1.1168 + } 1.1169 + 1.1170 + SkImageInfo info = fInfo; 1.1171 + info.fColorType = dstCT; 1.1172 + if (!dst->setConfig(info, rowBytes)) { 1.1173 + return false; 1.1174 + } 1.1175 + dst->setPixelRef(pixelRef, fPixelRefOrigin)->unref(); 1.1176 + return true; 1.1177 + } 1.1178 + } 1.1179 + 1.1180 + if (this->getTexture()) { 1.1181 + return false; 1.1182 + } else { 1.1183 + return this->copyTo(dst, dstCT, NULL); 1.1184 + } 1.1185 +} 1.1186 + 1.1187 +/////////////////////////////////////////////////////////////////////////////// 1.1188 +/////////////////////////////////////////////////////////////////////////////// 1.1189 + 1.1190 +static void downsampleby2_proc32(SkBitmap* dst, int x, int y, 1.1191 + const SkBitmap& src) { 1.1192 + x <<= 1; 1.1193 + y <<= 1; 1.1194 + const SkPMColor* p = src.getAddr32(x, y); 1.1195 + const SkPMColor* baseP = p; 1.1196 + SkPMColor c, ag, rb; 1.1197 + 1.1198 + c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF; 1.1199 + if (x < src.width() - 1) { 1.1200 + p += 1; 1.1201 + } 1.1202 + c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; 1.1203 + 1.1204 + p = baseP; 1.1205 + if (y < src.height() - 1) { 1.1206 + p += src.rowBytes() >> 2; 1.1207 + } 1.1208 + c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; 1.1209 + if (x < src.width() - 1) { 1.1210 + p += 1; 1.1211 + } 1.1212 + c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; 1.1213 + 1.1214 + *dst->getAddr32(x >> 1, y >> 1) = 1.1215 + ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00); 1.1216 +} 1.1217 + 1.1218 +static inline uint32_t expand16(U16CPU c) { 1.1219 + return (c & ~SK_G16_MASK_IN_PLACE) | ((c & SK_G16_MASK_IN_PLACE) << 16); 1.1220 +} 1.1221 + 1.1222 +// returns dirt in the top 16bits, but we don't care, since we only 1.1223 +// store the low 16bits. 1.1224 +static inline U16CPU pack16(uint32_t c) { 1.1225 + return (c & ~SK_G16_MASK_IN_PLACE) | ((c >> 16) & SK_G16_MASK_IN_PLACE); 1.1226 +} 1.1227 + 1.1228 +static void downsampleby2_proc16(SkBitmap* dst, int x, int y, 1.1229 + const SkBitmap& src) { 1.1230 + x <<= 1; 1.1231 + y <<= 1; 1.1232 + const uint16_t* p = src.getAddr16(x, y); 1.1233 + const uint16_t* baseP = p; 1.1234 + SkPMColor c; 1.1235 + 1.1236 + c = expand16(*p); 1.1237 + if (x < src.width() - 1) { 1.1238 + p += 1; 1.1239 + } 1.1240 + c += expand16(*p); 1.1241 + 1.1242 + p = baseP; 1.1243 + if (y < src.height() - 1) { 1.1244 + p += src.rowBytes() >> 1; 1.1245 + } 1.1246 + c += expand16(*p); 1.1247 + if (x < src.width() - 1) { 1.1248 + p += 1; 1.1249 + } 1.1250 + c += expand16(*p); 1.1251 + 1.1252 + *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)pack16(c >> 2); 1.1253 +} 1.1254 + 1.1255 +static uint32_t expand4444(U16CPU c) { 1.1256 + return (c & 0xF0F) | ((c & ~0xF0F) << 12); 1.1257 +} 1.1258 + 1.1259 +static U16CPU collaps4444(uint32_t c) { 1.1260 + return (c & 0xF0F) | ((c >> 12) & ~0xF0F); 1.1261 +} 1.1262 + 1.1263 +static void downsampleby2_proc4444(SkBitmap* dst, int x, int y, 1.1264 + const SkBitmap& src) { 1.1265 + x <<= 1; 1.1266 + y <<= 1; 1.1267 + const uint16_t* p = src.getAddr16(x, y); 1.1268 + const uint16_t* baseP = p; 1.1269 + uint32_t c; 1.1270 + 1.1271 + c = expand4444(*p); 1.1272 + if (x < src.width() - 1) { 1.1273 + p += 1; 1.1274 + } 1.1275 + c += expand4444(*p); 1.1276 + 1.1277 + p = baseP; 1.1278 + if (y < src.height() - 1) { 1.1279 + p += src.rowBytes() >> 1; 1.1280 + } 1.1281 + c += expand4444(*p); 1.1282 + if (x < src.width() - 1) { 1.1283 + p += 1; 1.1284 + } 1.1285 + c += expand4444(*p); 1.1286 + 1.1287 + *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)collaps4444(c >> 2); 1.1288 +} 1.1289 + 1.1290 +void SkBitmap::buildMipMap(bool forceRebuild) { 1.1291 + if (forceRebuild) 1.1292 + this->freeMipMap(); 1.1293 + else if (fMipMap) 1.1294 + return; // we're already built 1.1295 + 1.1296 + SkASSERT(NULL == fMipMap); 1.1297 + 1.1298 + void (*proc)(SkBitmap* dst, int x, int y, const SkBitmap& src); 1.1299 + 1.1300 + const SkBitmap::Config config = this->config(); 1.1301 + 1.1302 + switch (config) { 1.1303 + case kARGB_8888_Config: 1.1304 + proc = downsampleby2_proc32; 1.1305 + break; 1.1306 + case kRGB_565_Config: 1.1307 + proc = downsampleby2_proc16; 1.1308 + break; 1.1309 + case kARGB_4444_Config: 1.1310 + proc = downsampleby2_proc4444; 1.1311 + break; 1.1312 + case kIndex8_Config: 1.1313 + case kA8_Config: 1.1314 + default: 1.1315 + return; // don't build mipmaps for these configs 1.1316 + } 1.1317 + 1.1318 + SkAutoLockPixels alp(*this); 1.1319 + if (!this->readyToDraw()) { 1.1320 + return; 1.1321 + } 1.1322 + 1.1323 + // whip through our loop to compute the exact size needed 1.1324 + size_t size = 0; 1.1325 + int maxLevels = 0; 1.1326 + { 1.1327 + int width = this->width(); 1.1328 + int height = this->height(); 1.1329 + for (;;) { 1.1330 + width >>= 1; 1.1331 + height >>= 1; 1.1332 + if (0 == width || 0 == height) { 1.1333 + break; 1.1334 + } 1.1335 + size += ComputeRowBytes(config, width) * height; 1.1336 + maxLevels += 1; 1.1337 + } 1.1338 + } 1.1339 + 1.1340 + // nothing to build 1.1341 + if (0 == maxLevels) { 1.1342 + return; 1.1343 + } 1.1344 + 1.1345 + SkBitmap srcBM(*this); 1.1346 + srcBM.lockPixels(); 1.1347 + if (!srcBM.readyToDraw()) { 1.1348 + return; 1.1349 + } 1.1350 + 1.1351 + MipMap* mm = MipMap::Alloc(maxLevels, size); 1.1352 + if (NULL == mm) { 1.1353 + return; 1.1354 + } 1.1355 + 1.1356 + MipLevel* level = mm->levels(); 1.1357 + uint8_t* addr = (uint8_t*)mm->pixels(); 1.1358 + int width = this->width(); 1.1359 + int height = this->height(); 1.1360 + uint32_t rowBytes; 1.1361 + SkBitmap dstBM; 1.1362 + 1.1363 + for (int i = 0; i < maxLevels; i++) { 1.1364 + width >>= 1; 1.1365 + height >>= 1; 1.1366 + rowBytes = SkToU32(ComputeRowBytes(config, width)); 1.1367 + 1.1368 + level[i].fPixels = addr; 1.1369 + level[i].fWidth = width; 1.1370 + level[i].fHeight = height; 1.1371 + level[i].fRowBytes = rowBytes; 1.1372 + 1.1373 + dstBM.setConfig(config, width, height, rowBytes); 1.1374 + dstBM.setPixels(addr); 1.1375 + 1.1376 + srcBM.lockPixels(); 1.1377 + for (int y = 0; y < height; y++) { 1.1378 + for (int x = 0; x < width; x++) { 1.1379 + proc(&dstBM, x, y, srcBM); 1.1380 + } 1.1381 + } 1.1382 + srcBM.unlockPixels(); 1.1383 + 1.1384 + srcBM = dstBM; 1.1385 + addr += height * rowBytes; 1.1386 + } 1.1387 + SkASSERT(addr == (uint8_t*)mm->pixels() + size); 1.1388 + fMipMap = mm; 1.1389 +} 1.1390 + 1.1391 +bool SkBitmap::hasMipMap() const { 1.1392 + return fMipMap != NULL; 1.1393 +} 1.1394 + 1.1395 +int SkBitmap::extractMipLevel(SkBitmap* dst, SkFixed sx, SkFixed sy) { 1.1396 + if (NULL == fMipMap) { 1.1397 + return 0; 1.1398 + } 1.1399 + 1.1400 + int level = ComputeMipLevel(sx, sy) >> 16; 1.1401 + SkASSERT(level >= 0); 1.1402 + if (level <= 0) { 1.1403 + return 0; 1.1404 + } 1.1405 + 1.1406 + if (level >= fMipMap->fLevelCount) { 1.1407 + level = fMipMap->fLevelCount - 1; 1.1408 + } 1.1409 + if (dst) { 1.1410 + const MipLevel& mip = fMipMap->levels()[level - 1]; 1.1411 + dst->setConfig((SkBitmap::Config)this->config(), 1.1412 + mip.fWidth, mip.fHeight, mip.fRowBytes); 1.1413 + dst->setPixels(mip.fPixels); 1.1414 + } 1.1415 + return level; 1.1416 +} 1.1417 + 1.1418 +SkFixed SkBitmap::ComputeMipLevel(SkFixed sx, SkFixed sy) { 1.1419 + sx = SkAbs32(sx); 1.1420 + sy = SkAbs32(sy); 1.1421 + if (sx < sy) { 1.1422 + sx = sy; 1.1423 + } 1.1424 + if (sx < SK_Fixed1) { 1.1425 + return 0; 1.1426 + } 1.1427 + int clz = SkCLZ(sx); 1.1428 + SkASSERT(clz >= 1 && clz <= 15); 1.1429 + return SkIntToFixed(15 - clz) + ((unsigned)(sx << (clz + 1)) >> 16); 1.1430 +} 1.1431 + 1.1432 +/////////////////////////////////////////////////////////////////////////////// 1.1433 + 1.1434 +static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, 1.1435 + int alphaRowBytes) { 1.1436 + SkASSERT(alpha != NULL); 1.1437 + SkASSERT(alphaRowBytes >= src.width()); 1.1438 + 1.1439 + SkBitmap::Config config = src.config(); 1.1440 + int w = src.width(); 1.1441 + int h = src.height(); 1.1442 + size_t rb = src.rowBytes(); 1.1443 + 1.1444 + SkAutoLockPixels alp(src); 1.1445 + if (!src.readyToDraw()) { 1.1446 + // zero out the alpha buffer and return 1.1447 + while (--h >= 0) { 1.1448 + memset(alpha, 0, w); 1.1449 + alpha += alphaRowBytes; 1.1450 + } 1.1451 + return false; 1.1452 + } 1.1453 + 1.1454 + if (SkBitmap::kA8_Config == config && !src.isOpaque()) { 1.1455 + const uint8_t* s = src.getAddr8(0, 0); 1.1456 + while (--h >= 0) { 1.1457 + memcpy(alpha, s, w); 1.1458 + s += rb; 1.1459 + alpha += alphaRowBytes; 1.1460 + } 1.1461 + } else if (SkBitmap::kARGB_8888_Config == config && !src.isOpaque()) { 1.1462 + const SkPMColor* SK_RESTRICT s = src.getAddr32(0, 0); 1.1463 + while (--h >= 0) { 1.1464 + for (int x = 0; x < w; x++) { 1.1465 + alpha[x] = SkGetPackedA32(s[x]); 1.1466 + } 1.1467 + s = (const SkPMColor*)((const char*)s + rb); 1.1468 + alpha += alphaRowBytes; 1.1469 + } 1.1470 + } else if (SkBitmap::kARGB_4444_Config == config && !src.isOpaque()) { 1.1471 + const SkPMColor16* SK_RESTRICT s = src.getAddr16(0, 0); 1.1472 + while (--h >= 0) { 1.1473 + for (int x = 0; x < w; x++) { 1.1474 + alpha[x] = SkPacked4444ToA32(s[x]); 1.1475 + } 1.1476 + s = (const SkPMColor16*)((const char*)s + rb); 1.1477 + alpha += alphaRowBytes; 1.1478 + } 1.1479 + } else if (SkBitmap::kIndex8_Config == config && !src.isOpaque()) { 1.1480 + SkColorTable* ct = src.getColorTable(); 1.1481 + if (ct) { 1.1482 + const SkPMColor* SK_RESTRICT table = ct->lockColors(); 1.1483 + const uint8_t* SK_RESTRICT s = src.getAddr8(0, 0); 1.1484 + while (--h >= 0) { 1.1485 + for (int x = 0; x < w; x++) { 1.1486 + alpha[x] = SkGetPackedA32(table[s[x]]); 1.1487 + } 1.1488 + s += rb; 1.1489 + alpha += alphaRowBytes; 1.1490 + } 1.1491 + ct->unlockColors(); 1.1492 + } 1.1493 + } else { // src is opaque, so just fill alpha[] with 0xFF 1.1494 + memset(alpha, 0xFF, h * alphaRowBytes); 1.1495 + } 1.1496 + return true; 1.1497 +} 1.1498 + 1.1499 +#include "SkPaint.h" 1.1500 +#include "SkMaskFilter.h" 1.1501 +#include "SkMatrix.h" 1.1502 + 1.1503 +bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint, 1.1504 + Allocator *allocator, SkIPoint* offset) const { 1.1505 + SkDEBUGCODE(this->validate();) 1.1506 + 1.1507 + SkBitmap tmpBitmap; 1.1508 + SkMatrix identity; 1.1509 + SkMask srcM, dstM; 1.1510 + 1.1511 + srcM.fBounds.set(0, 0, this->width(), this->height()); 1.1512 + srcM.fRowBytes = SkAlign4(this->width()); 1.1513 + srcM.fFormat = SkMask::kA8_Format; 1.1514 + 1.1515 + SkMaskFilter* filter = paint ? paint->getMaskFilter() : NULL; 1.1516 + 1.1517 + // compute our (larger?) dst bounds if we have a filter 1.1518 + if (NULL != filter) { 1.1519 + identity.reset(); 1.1520 + srcM.fImage = NULL; 1.1521 + if (!filter->filterMask(&dstM, srcM, identity, NULL)) { 1.1522 + goto NO_FILTER_CASE; 1.1523 + } 1.1524 + dstM.fRowBytes = SkAlign4(dstM.fBounds.width()); 1.1525 + } else { 1.1526 + NO_FILTER_CASE: 1.1527 + tmpBitmap.setConfig(SkBitmap::kA8_Config, this->width(), this->height(), 1.1528 + srcM.fRowBytes); 1.1529 + if (!tmpBitmap.allocPixels(allocator, NULL)) { 1.1530 + // Allocation of pixels for alpha bitmap failed. 1.1531 + SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n", 1.1532 + tmpBitmap.width(), tmpBitmap.height()); 1.1533 + return false; 1.1534 + } 1.1535 + GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes); 1.1536 + if (offset) { 1.1537 + offset->set(0, 0); 1.1538 + } 1.1539 + tmpBitmap.swap(*dst); 1.1540 + return true; 1.1541 + } 1.1542 + srcM.fImage = SkMask::AllocImage(srcM.computeImageSize()); 1.1543 + SkAutoMaskFreeImage srcCleanup(srcM.fImage); 1.1544 + 1.1545 + GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes); 1.1546 + if (!filter->filterMask(&dstM, srcM, identity, NULL)) { 1.1547 + goto NO_FILTER_CASE; 1.1548 + } 1.1549 + SkAutoMaskFreeImage dstCleanup(dstM.fImage); 1.1550 + 1.1551 + tmpBitmap.setConfig(SkBitmap::kA8_Config, dstM.fBounds.width(), 1.1552 + dstM.fBounds.height(), dstM.fRowBytes); 1.1553 + if (!tmpBitmap.allocPixels(allocator, NULL)) { 1.1554 + // Allocation of pixels for alpha bitmap failed. 1.1555 + SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n", 1.1556 + tmpBitmap.width(), tmpBitmap.height()); 1.1557 + return false; 1.1558 + } 1.1559 + memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize()); 1.1560 + if (offset) { 1.1561 + offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop); 1.1562 + } 1.1563 + SkDEBUGCODE(tmpBitmap.validate();) 1.1564 + 1.1565 + tmpBitmap.swap(*dst); 1.1566 + return true; 1.1567 +} 1.1568 + 1.1569 +/////////////////////////////////////////////////////////////////////////////// 1.1570 + 1.1571 +enum { 1.1572 + SERIALIZE_PIXELTYPE_NONE, 1.1573 + SERIALIZE_PIXELTYPE_REF_DATA 1.1574 +}; 1.1575 + 1.1576 +void SkBitmap::flatten(SkWriteBuffer& buffer) const { 1.1577 + fInfo.flatten(buffer); 1.1578 + buffer.writeInt(fRowBytes); 1.1579 + 1.1580 + if (fPixelRef) { 1.1581 + if (fPixelRef->getFactory()) { 1.1582 + buffer.writeInt(SERIALIZE_PIXELTYPE_REF_DATA); 1.1583 + buffer.writeInt(fPixelRefOrigin.fX); 1.1584 + buffer.writeInt(fPixelRefOrigin.fY); 1.1585 + buffer.writeFlattenable(fPixelRef); 1.1586 + return; 1.1587 + } 1.1588 + // if we get here, we can't record the pixels 1.1589 + buffer.writeInt(SERIALIZE_PIXELTYPE_NONE); 1.1590 + } else { 1.1591 + buffer.writeInt(SERIALIZE_PIXELTYPE_NONE); 1.1592 + } 1.1593 +} 1.1594 + 1.1595 +void SkBitmap::unflatten(SkReadBuffer& buffer) { 1.1596 + this->reset(); 1.1597 + 1.1598 + SkImageInfo info; 1.1599 + info.unflatten(buffer); 1.1600 + size_t rowBytes = buffer.readInt(); 1.1601 + if (!buffer.validate((info.width() >= 0) && (info.height() >= 0) && 1.1602 + SkColorTypeIsValid(info.fColorType) && 1.1603 + SkAlphaTypeIsValid(info.fAlphaType) && 1.1604 + validate_alphaType(info.fColorType, info.fAlphaType) && 1.1605 + info.validRowBytes(rowBytes))) { 1.1606 + return; 1.1607 + } 1.1608 + 1.1609 + bool configIsValid = this->setConfig(info, rowBytes); 1.1610 + buffer.validate(configIsValid); 1.1611 + 1.1612 + int reftype = buffer.readInt(); 1.1613 + if (buffer.validate((SERIALIZE_PIXELTYPE_REF_DATA == reftype) || 1.1614 + (SERIALIZE_PIXELTYPE_NONE == reftype))) { 1.1615 + switch (reftype) { 1.1616 + case SERIALIZE_PIXELTYPE_REF_DATA: { 1.1617 + SkIPoint origin; 1.1618 + origin.fX = buffer.readInt(); 1.1619 + origin.fY = buffer.readInt(); 1.1620 + size_t offset = origin.fY * rowBytes + origin.fX * info.bytesPerPixel(); 1.1621 + SkPixelRef* pr = buffer.readPixelRef(); 1.1622 + if (!buffer.validate((NULL == pr) || 1.1623 + (pr->getAllocatedSizeInBytes() >= (offset + this->getSafeSize())))) { 1.1624 + origin.setZero(); 1.1625 + } 1.1626 + SkSafeUnref(this->setPixelRef(pr, origin)); 1.1627 + break; 1.1628 + } 1.1629 + case SERIALIZE_PIXELTYPE_NONE: 1.1630 + break; 1.1631 + default: 1.1632 + SkDEBUGFAIL("unrecognized pixeltype in serialized data"); 1.1633 + sk_throw(); 1.1634 + } 1.1635 + } 1.1636 +} 1.1637 + 1.1638 +/////////////////////////////////////////////////////////////////////////////// 1.1639 + 1.1640 +SkBitmap::RLEPixels::RLEPixels(int width, int height) { 1.1641 + fHeight = height; 1.1642 + fYPtrs = (uint8_t**)sk_calloc_throw(height * sizeof(uint8_t*)); 1.1643 +} 1.1644 + 1.1645 +SkBitmap::RLEPixels::~RLEPixels() { 1.1646 + sk_free(fYPtrs); 1.1647 +} 1.1648 + 1.1649 +/////////////////////////////////////////////////////////////////////////////// 1.1650 + 1.1651 +#ifdef SK_DEBUG 1.1652 +void SkBitmap::validate() const { 1.1653 + fInfo.validate(); 1.1654 + 1.1655 + // ImageInfo may not require this, but Bitmap ensures that opaque-only 1.1656 + // colorTypes report opaque for their alphatype 1.1657 + if (kRGB_565_SkColorType == fInfo.colorType()) { 1.1658 + SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType()); 1.1659 + } 1.1660 + 1.1661 + SkASSERT(fInfo.validRowBytes(fRowBytes)); 1.1662 + uint8_t allFlags = kImageIsOpaque_Flag | kImageIsVolatile_Flag | kImageIsImmutable_Flag; 1.1663 +#ifdef SK_BUILD_FOR_ANDROID 1.1664 + allFlags |= kHasHardwareMipMap_Flag; 1.1665 +#endif 1.1666 + SkASSERT(fFlags <= allFlags); 1.1667 + SkASSERT(fPixelLockCount >= 0); 1.1668 + 1.1669 + if (fPixels) { 1.1670 + SkASSERT(fPixelRef); 1.1671 + SkASSERT(fPixelLockCount > 0); 1.1672 + SkASSERT(fPixelRef->isLocked()); 1.1673 + SkASSERT(fPixelRef->rowBytes() == fRowBytes); 1.1674 + SkASSERT(fPixelRefOrigin.fX >= 0); 1.1675 + SkASSERT(fPixelRefOrigin.fY >= 0); 1.1676 + SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX); 1.1677 + SkASSERT(fPixelRef->info().fHeight >= (int)this->height() + fPixelRefOrigin.fY); 1.1678 + SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes()); 1.1679 + } else { 1.1680 + SkASSERT(NULL == fColorTable); 1.1681 + } 1.1682 +} 1.1683 +#endif 1.1684 + 1.1685 +#ifndef SK_IGNORE_TO_STRING 1.1686 +void SkBitmap::toString(SkString* str) const { 1.1687 + 1.1688 + static const char* gConfigNames[kConfigCount] = { 1.1689 + "NONE", "A8", "INDEX8", "565", "4444", "8888" 1.1690 + }; 1.1691 + 1.1692 + str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(), 1.1693 + gConfigNames[this->config()]); 1.1694 + 1.1695 + str->append(" ("); 1.1696 + if (this->isOpaque()) { 1.1697 + str->append("opaque"); 1.1698 + } else { 1.1699 + str->append("transparent"); 1.1700 + } 1.1701 + if (this->isImmutable()) { 1.1702 + str->append(", immutable"); 1.1703 + } else { 1.1704 + str->append(", not-immutable"); 1.1705 + } 1.1706 + str->append(")"); 1.1707 + 1.1708 + SkPixelRef* pr = this->pixelRef(); 1.1709 + if (NULL == pr) { 1.1710 + // show null or the explicit pixel address (rare) 1.1711 + str->appendf(" pixels:%p", this->getPixels()); 1.1712 + } else { 1.1713 + const char* uri = pr->getURI(); 1.1714 + if (NULL != uri) { 1.1715 + str->appendf(" uri:\"%s\"", uri); 1.1716 + } else { 1.1717 + str->appendf(" pixelref:%p", pr); 1.1718 + } 1.1719 + } 1.1720 + 1.1721 + str->append(")"); 1.1722 +} 1.1723 +#endif 1.1724 + 1.1725 +/////////////////////////////////////////////////////////////////////////////// 1.1726 + 1.1727 +#ifdef SK_DEBUG 1.1728 +void SkImageInfo::validate() const { 1.1729 + SkASSERT(fWidth >= 0); 1.1730 + SkASSERT(fHeight >= 0); 1.1731 + SkASSERT(SkColorTypeIsValid(fColorType)); 1.1732 + SkASSERT(SkAlphaTypeIsValid(fAlphaType)); 1.1733 +} 1.1734 +#endif