gfx/skia/trunk/src/core/SkBitmap.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2008 The Android Open Source Project
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8
michael@0 9
michael@0 10 #include "SkBitmap.h"
michael@0 11 #include "SkColorPriv.h"
michael@0 12 #include "SkDither.h"
michael@0 13 #include "SkFlattenable.h"
michael@0 14 #include "SkImagePriv.h"
michael@0 15 #include "SkMallocPixelRef.h"
michael@0 16 #include "SkMask.h"
michael@0 17 #include "SkReadBuffer.h"
michael@0 18 #include "SkWriteBuffer.h"
michael@0 19 #include "SkPixelRef.h"
michael@0 20 #include "SkThread.h"
michael@0 21 #include "SkUnPreMultiply.h"
michael@0 22 #include "SkUtils.h"
michael@0 23 #include "SkValidationUtils.h"
michael@0 24 #include "SkPackBits.h"
michael@0 25 #include <new>
michael@0 26
michael@0 27 static bool reset_return_false(SkBitmap* bm) {
michael@0 28 bm->reset();
michael@0 29 return false;
michael@0 30 }
michael@0 31
michael@0 32 struct MipLevel {
michael@0 33 void* fPixels;
michael@0 34 uint32_t fRowBytes;
michael@0 35 uint32_t fWidth, fHeight;
michael@0 36 };
michael@0 37
michael@0 38 struct SkBitmap::MipMap : SkNoncopyable {
michael@0 39 int32_t fRefCnt;
michael@0 40 int fLevelCount;
michael@0 41 // MipLevel fLevel[fLevelCount];
michael@0 42 // Pixels[]
michael@0 43
michael@0 44 static MipMap* Alloc(int levelCount, size_t pixelSize) {
michael@0 45 if (levelCount < 0) {
michael@0 46 return NULL;
michael@0 47 }
michael@0 48 int64_t size = (levelCount + 1) * sizeof(MipLevel);
michael@0 49 size += sizeof(MipMap) + pixelSize;
michael@0 50 if (!sk_64_isS32(size)) {
michael@0 51 return NULL;
michael@0 52 }
michael@0 53 MipMap* mm = (MipMap*)sk_malloc_throw(sk_64_asS32(size));
michael@0 54 mm->fRefCnt = 1;
michael@0 55 mm->fLevelCount = levelCount;
michael@0 56 return mm;
michael@0 57 }
michael@0 58
michael@0 59 const MipLevel* levels() const { return (const MipLevel*)(this + 1); }
michael@0 60 MipLevel* levels() { return (MipLevel*)(this + 1); }
michael@0 61
michael@0 62 const void* pixels() const { return levels() + fLevelCount; }
michael@0 63 void* pixels() { return levels() + fLevelCount; }
michael@0 64
michael@0 65 void ref() {
michael@0 66 if (SK_MaxS32 == sk_atomic_inc(&fRefCnt)) {
michael@0 67 sk_throw();
michael@0 68 }
michael@0 69 }
michael@0 70 void unref() {
michael@0 71 SkASSERT(fRefCnt > 0);
michael@0 72 if (sk_atomic_dec(&fRefCnt) == 1) {
michael@0 73 sk_free(this);
michael@0 74 }
michael@0 75 }
michael@0 76 };
michael@0 77
michael@0 78 ///////////////////////////////////////////////////////////////////////////////
michael@0 79 ///////////////////////////////////////////////////////////////////////////////
michael@0 80
michael@0 81 SkBitmap::SkBitmap() {
michael@0 82 sk_bzero(this, sizeof(*this));
michael@0 83 }
michael@0 84
michael@0 85 SkBitmap::SkBitmap(const SkBitmap& src) {
michael@0 86 SkDEBUGCODE(src.validate();)
michael@0 87 sk_bzero(this, sizeof(*this));
michael@0 88 *this = src;
michael@0 89 SkDEBUGCODE(this->validate();)
michael@0 90 }
michael@0 91
michael@0 92 SkBitmap::~SkBitmap() {
michael@0 93 SkDEBUGCODE(this->validate();)
michael@0 94 this->freePixels();
michael@0 95 }
michael@0 96
michael@0 97 SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
michael@0 98 if (this != &src) {
michael@0 99 this->freePixels();
michael@0 100 memcpy(this, &src, sizeof(src));
michael@0 101
michael@0 102 // inc src reference counts
michael@0 103 SkSafeRef(src.fPixelRef);
michael@0 104 SkSafeRef(src.fMipMap);
michael@0 105
michael@0 106 // we reset our locks if we get blown away
michael@0 107 fPixelLockCount = 0;
michael@0 108
michael@0 109 if (fPixelRef) {
michael@0 110 // ignore the values from the memcpy
michael@0 111 fPixels = NULL;
michael@0 112 fColorTable = NULL;
michael@0 113 // Note that what to for genID is somewhat arbitrary. We have no
michael@0 114 // way to track changes to raw pixels across multiple SkBitmaps.
michael@0 115 // Would benefit from an SkRawPixelRef type created by
michael@0 116 // setPixels.
michael@0 117 // Just leave the memcpy'ed one but they'll get out of sync
michael@0 118 // as soon either is modified.
michael@0 119 }
michael@0 120 }
michael@0 121
michael@0 122 SkDEBUGCODE(this->validate();)
michael@0 123 return *this;
michael@0 124 }
michael@0 125
michael@0 126 void SkBitmap::swap(SkBitmap& other) {
michael@0 127 SkTSwap(fColorTable, other.fColorTable);
michael@0 128 SkTSwap(fPixelRef, other.fPixelRef);
michael@0 129 SkTSwap(fPixelRefOrigin, other.fPixelRefOrigin);
michael@0 130 SkTSwap(fPixelLockCount, other.fPixelLockCount);
michael@0 131 SkTSwap(fMipMap, other.fMipMap);
michael@0 132 SkTSwap(fPixels, other.fPixels);
michael@0 133 SkTSwap(fInfo, other.fInfo);
michael@0 134 SkTSwap(fRowBytes, other.fRowBytes);
michael@0 135 SkTSwap(fFlags, other.fFlags);
michael@0 136
michael@0 137 SkDEBUGCODE(this->validate();)
michael@0 138 }
michael@0 139
michael@0 140 void SkBitmap::reset() {
michael@0 141 this->freePixels();
michael@0 142 sk_bzero(this, sizeof(*this));
michael@0 143 }
michael@0 144
michael@0 145 SkBitmap::Config SkBitmap::config() const {
michael@0 146 return SkColorTypeToBitmapConfig(fInfo.colorType());
michael@0 147 }
michael@0 148
michael@0 149 int SkBitmap::ComputeBytesPerPixel(SkBitmap::Config config) {
michael@0 150 int bpp;
michael@0 151 switch (config) {
michael@0 152 case kNo_Config:
michael@0 153 bpp = 0; // not applicable
michael@0 154 break;
michael@0 155 case kA8_Config:
michael@0 156 case kIndex8_Config:
michael@0 157 bpp = 1;
michael@0 158 break;
michael@0 159 case kRGB_565_Config:
michael@0 160 case kARGB_4444_Config:
michael@0 161 bpp = 2;
michael@0 162 break;
michael@0 163 case kARGB_8888_Config:
michael@0 164 bpp = 4;
michael@0 165 break;
michael@0 166 default:
michael@0 167 SkDEBUGFAIL("unknown config");
michael@0 168 bpp = 0; // error
michael@0 169 break;
michael@0 170 }
michael@0 171 return bpp;
michael@0 172 }
michael@0 173
michael@0 174 size_t SkBitmap::ComputeRowBytes(Config c, int width) {
michael@0 175 return SkColorTypeMinRowBytes(SkBitmapConfigToColorType(c), width);
michael@0 176 }
michael@0 177
michael@0 178 int64_t SkBitmap::ComputeSize64(Config config, int width, int height) {
michael@0 179 SkColorType ct = SkBitmapConfigToColorType(config);
michael@0 180 int64_t rowBytes = sk_64_mul(SkColorTypeBytesPerPixel(ct), width);
michael@0 181 return rowBytes * height;
michael@0 182 }
michael@0 183
michael@0 184 size_t SkBitmap::ComputeSize(Config c, int width, int height) {
michael@0 185 int64_t size = SkBitmap::ComputeSize64(c, width, height);
michael@0 186 return sk_64_isS32(size) ? sk_64_asS32(size) : 0;
michael@0 187 }
michael@0 188
michael@0 189 int64_t SkBitmap::ComputeSafeSize64(Config config,
michael@0 190 uint32_t width,
michael@0 191 uint32_t height,
michael@0 192 size_t rowBytes) {
michael@0 193 SkImageInfo info = SkImageInfo::Make(width, height,
michael@0 194 SkBitmapConfigToColorType(config),
michael@0 195 kPremul_SkAlphaType);
michael@0 196 return info.getSafeSize64(rowBytes);
michael@0 197 }
michael@0 198
michael@0 199 size_t SkBitmap::ComputeSafeSize(Config config,
michael@0 200 uint32_t width,
michael@0 201 uint32_t height,
michael@0 202 size_t rowBytes) {
michael@0 203 int64_t safeSize = ComputeSafeSize64(config, width, height, rowBytes);
michael@0 204 int32_t safeSize32 = (int32_t)safeSize;
michael@0 205
michael@0 206 if (safeSize32 != safeSize) {
michael@0 207 safeSize32 = 0;
michael@0 208 }
michael@0 209 return safeSize32;
michael@0 210 }
michael@0 211
michael@0 212 void SkBitmap::getBounds(SkRect* bounds) const {
michael@0 213 SkASSERT(bounds);
michael@0 214 bounds->set(0, 0,
michael@0 215 SkIntToScalar(fInfo.fWidth), SkIntToScalar(fInfo.fHeight));
michael@0 216 }
michael@0 217
michael@0 218 void SkBitmap::getBounds(SkIRect* bounds) const {
michael@0 219 SkASSERT(bounds);
michael@0 220 bounds->set(0, 0, fInfo.fWidth, fInfo.fHeight);
michael@0 221 }
michael@0 222
michael@0 223 ///////////////////////////////////////////////////////////////////////////////
michael@0 224
michael@0 225 static bool validate_alphaType(SkColorType colorType, SkAlphaType alphaType,
michael@0 226 SkAlphaType* canonical = NULL) {
michael@0 227 switch (colorType) {
michael@0 228 case kUnknown_SkColorType:
michael@0 229 alphaType = kIgnore_SkAlphaType;
michael@0 230 break;
michael@0 231 case kAlpha_8_SkColorType:
michael@0 232 if (kUnpremul_SkAlphaType == alphaType) {
michael@0 233 alphaType = kPremul_SkAlphaType;
michael@0 234 }
michael@0 235 // fall-through
michael@0 236 case kIndex_8_SkColorType:
michael@0 237 case kARGB_4444_SkColorType:
michael@0 238 case kRGBA_8888_SkColorType:
michael@0 239 case kBGRA_8888_SkColorType:
michael@0 240 if (kIgnore_SkAlphaType == alphaType) {
michael@0 241 return false;
michael@0 242 }
michael@0 243 break;
michael@0 244 case kRGB_565_SkColorType:
michael@0 245 alphaType = kOpaque_SkAlphaType;
michael@0 246 break;
michael@0 247 default:
michael@0 248 return false;
michael@0 249 }
michael@0 250 if (canonical) {
michael@0 251 *canonical = alphaType;
michael@0 252 }
michael@0 253 return true;
michael@0 254 }
michael@0 255
michael@0 256 bool SkBitmap::setConfig(const SkImageInfo& origInfo, size_t rowBytes) {
michael@0 257 SkImageInfo info = origInfo;
michael@0 258
michael@0 259 if (!validate_alphaType(info.fColorType, info.fAlphaType,
michael@0 260 &info.fAlphaType)) {
michael@0 261 return reset_return_false(this);
michael@0 262 }
michael@0 263
michael@0 264 // require that rowBytes fit in 31bits
michael@0 265 int64_t mrb = info.minRowBytes64();
michael@0 266 if ((int32_t)mrb != mrb) {
michael@0 267 return reset_return_false(this);
michael@0 268 }
michael@0 269 if ((int64_t)rowBytes != (int32_t)rowBytes) {
michael@0 270 return reset_return_false(this);
michael@0 271 }
michael@0 272
michael@0 273 if (info.width() < 0 || info.height() < 0) {
michael@0 274 return reset_return_false(this);
michael@0 275 }
michael@0 276
michael@0 277 if (kUnknown_SkColorType == info.colorType()) {
michael@0 278 rowBytes = 0;
michael@0 279 } else if (0 == rowBytes) {
michael@0 280 rowBytes = (size_t)mrb;
michael@0 281 } else if (rowBytes < info.minRowBytes()) {
michael@0 282 return reset_return_false(this);
michael@0 283 }
michael@0 284
michael@0 285 this->freePixels();
michael@0 286
michael@0 287 fInfo = info;
michael@0 288 fRowBytes = SkToU32(rowBytes);
michael@0 289 return true;
michael@0 290 }
michael@0 291
michael@0 292 bool SkBitmap::setConfig(Config config, int width, int height, size_t rowBytes,
michael@0 293 SkAlphaType alphaType) {
michael@0 294 SkColorType ct = SkBitmapConfigToColorType(config);
michael@0 295 return this->setConfig(SkImageInfo::Make(width, height, ct, alphaType),
michael@0 296 rowBytes);
michael@0 297 }
michael@0 298
michael@0 299 bool SkBitmap::setAlphaType(SkAlphaType alphaType) {
michael@0 300 if (!validate_alphaType(fInfo.fColorType, alphaType, &alphaType)) {
michael@0 301 return false;
michael@0 302 }
michael@0 303 if (fInfo.fAlphaType != alphaType) {
michael@0 304 fInfo.fAlphaType = alphaType;
michael@0 305 if (fPixelRef) {
michael@0 306 fPixelRef->changeAlphaType(alphaType);
michael@0 307 }
michael@0 308 }
michael@0 309 return true;
michael@0 310 }
michael@0 311
michael@0 312 void SkBitmap::updatePixelsFromRef() const {
michael@0 313 if (NULL != fPixelRef) {
michael@0 314 if (fPixelLockCount > 0) {
michael@0 315 SkASSERT(fPixelRef->isLocked());
michael@0 316
michael@0 317 void* p = fPixelRef->pixels();
michael@0 318 if (NULL != p) {
michael@0 319 p = (char*)p
michael@0 320 + fPixelRefOrigin.fY * fRowBytes
michael@0 321 + fPixelRefOrigin.fX * fInfo.bytesPerPixel();
michael@0 322 }
michael@0 323 fPixels = p;
michael@0 324 fColorTable = fPixelRef->colorTable();
michael@0 325 } else {
michael@0 326 SkASSERT(0 == fPixelLockCount);
michael@0 327 fPixels = NULL;
michael@0 328 fColorTable = NULL;
michael@0 329 }
michael@0 330 }
michael@0 331 }
michael@0 332
michael@0 333 static bool config_to_colorType(SkBitmap::Config config, SkColorType* ctOut) {
michael@0 334 SkColorType ct;
michael@0 335 switch (config) {
michael@0 336 case SkBitmap::kA8_Config:
michael@0 337 ct = kAlpha_8_SkColorType;
michael@0 338 break;
michael@0 339 case SkBitmap::kIndex8_Config:
michael@0 340 ct = kIndex_8_SkColorType;
michael@0 341 break;
michael@0 342 case SkBitmap::kRGB_565_Config:
michael@0 343 ct = kRGB_565_SkColorType;
michael@0 344 break;
michael@0 345 case SkBitmap::kARGB_4444_Config:
michael@0 346 ct = kARGB_4444_SkColorType;
michael@0 347 break;
michael@0 348 case SkBitmap::kARGB_8888_Config:
michael@0 349 ct = kPMColor_SkColorType;
michael@0 350 break;
michael@0 351 case SkBitmap::kNo_Config:
michael@0 352 default:
michael@0 353 return false;
michael@0 354 }
michael@0 355 if (ctOut) {
michael@0 356 *ctOut = ct;
michael@0 357 }
michael@0 358 return true;
michael@0 359 }
michael@0 360
michael@0 361 SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) {
michael@0 362 #ifdef SK_DEBUG
michael@0 363 if (pr) {
michael@0 364 SkImageInfo info;
michael@0 365 if (this->asImageInfo(&info)) {
michael@0 366 const SkImageInfo& prInfo = pr->info();
michael@0 367 SkASSERT(info.fWidth <= prInfo.fWidth);
michael@0 368 SkASSERT(info.fHeight <= prInfo.fHeight);
michael@0 369 SkASSERT(info.fColorType == prInfo.fColorType);
michael@0 370 switch (prInfo.fAlphaType) {
michael@0 371 case kIgnore_SkAlphaType:
michael@0 372 SkASSERT(fInfo.fAlphaType == kIgnore_SkAlphaType);
michael@0 373 break;
michael@0 374 case kOpaque_SkAlphaType:
michael@0 375 case kPremul_SkAlphaType:
michael@0 376 SkASSERT(info.fAlphaType == kOpaque_SkAlphaType ||
michael@0 377 info.fAlphaType == kPremul_SkAlphaType);
michael@0 378 break;
michael@0 379 case kUnpremul_SkAlphaType:
michael@0 380 SkASSERT(info.fAlphaType == kOpaque_SkAlphaType ||
michael@0 381 info.fAlphaType == kUnpremul_SkAlphaType);
michael@0 382 break;
michael@0 383 }
michael@0 384 }
michael@0 385 }
michael@0 386 #endif
michael@0 387
michael@0 388 if (pr) {
michael@0 389 const SkImageInfo& info = pr->info();
michael@0 390 fPixelRefOrigin.set(SkPin32(dx, 0, info.fWidth),
michael@0 391 SkPin32(dy, 0, info.fHeight));
michael@0 392 } else {
michael@0 393 // ignore dx,dy if there is no pixelref
michael@0 394 fPixelRefOrigin.setZero();
michael@0 395 }
michael@0 396
michael@0 397 if (fPixelRef != pr) {
michael@0 398 if (fPixelRef != pr) {
michael@0 399 this->freePixels();
michael@0 400 SkASSERT(NULL == fPixelRef);
michael@0 401
michael@0 402 SkSafeRef(pr);
michael@0 403 fPixelRef = pr;
michael@0 404 }
michael@0 405 this->updatePixelsFromRef();
michael@0 406 }
michael@0 407
michael@0 408 SkDEBUGCODE(this->validate();)
michael@0 409 return pr;
michael@0 410 }
michael@0 411
michael@0 412 void SkBitmap::lockPixels() const {
michael@0 413 if (NULL != fPixelRef && 0 == sk_atomic_inc(&fPixelLockCount)) {
michael@0 414 fPixelRef->lockPixels();
michael@0 415 this->updatePixelsFromRef();
michael@0 416 }
michael@0 417 SkDEBUGCODE(this->validate();)
michael@0 418 }
michael@0 419
michael@0 420 void SkBitmap::unlockPixels() const {
michael@0 421 SkASSERT(NULL == fPixelRef || fPixelLockCount > 0);
michael@0 422
michael@0 423 if (NULL != fPixelRef && 1 == sk_atomic_dec(&fPixelLockCount)) {
michael@0 424 fPixelRef->unlockPixels();
michael@0 425 this->updatePixelsFromRef();
michael@0 426 }
michael@0 427 SkDEBUGCODE(this->validate();)
michael@0 428 }
michael@0 429
michael@0 430 bool SkBitmap::lockPixelsAreWritable() const {
michael@0 431 return (fPixelRef) ? fPixelRef->lockPixelsAreWritable() : false;
michael@0 432 }
michael@0 433
michael@0 434 void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
michael@0 435 if (NULL == p) {
michael@0 436 this->setPixelRef(NULL);
michael@0 437 return;
michael@0 438 }
michael@0 439
michael@0 440 SkImageInfo info;
michael@0 441 if (!this->asImageInfo(&info)) {
michael@0 442 this->setPixelRef(NULL);
michael@0 443 return;
michael@0 444 }
michael@0 445
michael@0 446 SkPixelRef* pr = SkMallocPixelRef::NewDirect(info, p, fRowBytes, ctable);
michael@0 447 if (NULL == pr) {
michael@0 448 this->setPixelRef(NULL);
michael@0 449 return;
michael@0 450 }
michael@0 451
michael@0 452 this->setPixelRef(pr)->unref();
michael@0 453
michael@0 454 // since we're already allocated, we lockPixels right away
michael@0 455 this->lockPixels();
michael@0 456 SkDEBUGCODE(this->validate();)
michael@0 457 }
michael@0 458
michael@0 459 bool SkBitmap::allocPixels(Allocator* allocator, SkColorTable* ctable) {
michael@0 460 HeapAllocator stdalloc;
michael@0 461
michael@0 462 if (NULL == allocator) {
michael@0 463 allocator = &stdalloc;
michael@0 464 }
michael@0 465 return allocator->allocPixelRef(this, ctable);
michael@0 466 }
michael@0 467
michael@0 468 ///////////////////////////////////////////////////////////////////////////////
michael@0 469
michael@0 470 bool SkBitmap::allocPixels(const SkImageInfo& info, SkPixelRefFactory* factory,
michael@0 471 SkColorTable* ctable) {
michael@0 472 if (kIndex_8_SkColorType == info.fColorType && NULL == ctable) {
michael@0 473 return reset_return_false(this);
michael@0 474 }
michael@0 475 if (!this->setConfig(info)) {
michael@0 476 return reset_return_false(this);
michael@0 477 }
michael@0 478
michael@0 479 SkMallocPixelRef::PRFactory defaultFactory;
michael@0 480 if (NULL == factory) {
michael@0 481 factory = &defaultFactory;
michael@0 482 }
michael@0 483
michael@0 484 SkPixelRef* pr = factory->create(info, ctable);
michael@0 485 if (NULL == pr) {
michael@0 486 return reset_return_false(this);
michael@0 487 }
michael@0 488 this->setPixelRef(pr)->unref();
michael@0 489
michael@0 490 // TODO: lockPixels could/should return bool or void*/NULL
michael@0 491 this->lockPixels();
michael@0 492 if (NULL == this->getPixels()) {
michael@0 493 return reset_return_false(this);
michael@0 494 }
michael@0 495 return true;
michael@0 496 }
michael@0 497
michael@0 498 bool SkBitmap::installPixels(const SkImageInfo& info, void* pixels, size_t rb,
michael@0 499 void (*releaseProc)(void* addr, void* context),
michael@0 500 void* context) {
michael@0 501 if (!this->setConfig(info, rb)) {
michael@0 502 this->reset();
michael@0 503 return false;
michael@0 504 }
michael@0 505
michael@0 506 SkPixelRef* pr = SkMallocPixelRef::NewWithProc(info, rb, NULL, pixels,
michael@0 507 releaseProc, context);
michael@0 508 if (!pr) {
michael@0 509 this->reset();
michael@0 510 return false;
michael@0 511 }
michael@0 512
michael@0 513 this->setPixelRef(pr)->unref();
michael@0 514
michael@0 515 // since we're already allocated, we lockPixels right away
michael@0 516 this->lockPixels();
michael@0 517 SkDEBUGCODE(this->validate();)
michael@0 518 return true;
michael@0 519 }
michael@0 520
michael@0 521 bool SkBitmap::installMaskPixels(const SkMask& mask) {
michael@0 522 if (SkMask::kA8_Format != mask.fFormat) {
michael@0 523 this->reset();
michael@0 524 return false;
michael@0 525 }
michael@0 526 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
michael@0 527 mask.fBounds.height()),
michael@0 528 mask.fImage, mask.fRowBytes);
michael@0 529 }
michael@0 530
michael@0 531 bool SkBitmap::allocConfigPixels(Config config, int width, int height,
michael@0 532 bool isOpaque) {
michael@0 533 SkColorType ct;
michael@0 534 if (!config_to_colorType(config, &ct)) {
michael@0 535 return false;
michael@0 536 }
michael@0 537
michael@0 538 SkAlphaType at = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
michael@0 539 return this->allocPixels(SkImageInfo::Make(width, height, ct, at));
michael@0 540 }
michael@0 541
michael@0 542 ///////////////////////////////////////////////////////////////////////////////
michael@0 543
michael@0 544 void SkBitmap::freePixels() {
michael@0 545 // if we're gonna free the pixels, we certainly need to free the mipmap
michael@0 546 this->freeMipMap();
michael@0 547
michael@0 548 if (NULL != fPixelRef) {
michael@0 549 if (fPixelLockCount > 0) {
michael@0 550 fPixelRef->unlockPixels();
michael@0 551 }
michael@0 552 fPixelRef->unref();
michael@0 553 fPixelRef = NULL;
michael@0 554 fPixelRefOrigin.setZero();
michael@0 555 }
michael@0 556 fPixelLockCount = 0;
michael@0 557 fPixels = NULL;
michael@0 558 fColorTable = NULL;
michael@0 559 }
michael@0 560
michael@0 561 void SkBitmap::freeMipMap() {
michael@0 562 if (fMipMap) {
michael@0 563 fMipMap->unref();
michael@0 564 fMipMap = NULL;
michael@0 565 }
michael@0 566 }
michael@0 567
michael@0 568 uint32_t SkBitmap::getGenerationID() const {
michael@0 569 return (fPixelRef) ? fPixelRef->getGenerationID() : 0;
michael@0 570 }
michael@0 571
michael@0 572 void SkBitmap::notifyPixelsChanged() const {
michael@0 573 SkASSERT(!this->isImmutable());
michael@0 574 if (fPixelRef) {
michael@0 575 fPixelRef->notifyPixelsChanged();
michael@0 576 }
michael@0 577 }
michael@0 578
michael@0 579 GrTexture* SkBitmap::getTexture() const {
michael@0 580 return fPixelRef ? fPixelRef->getTexture() : NULL;
michael@0 581 }
michael@0 582
michael@0 583 ///////////////////////////////////////////////////////////////////////////////
michael@0 584
michael@0 585 /** We explicitly use the same allocator for our pixels that SkMask does,
michael@0 586 so that we can freely assign memory allocated by one class to the other.
michael@0 587 */
michael@0 588 bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
michael@0 589 SkColorTable* ctable) {
michael@0 590 SkImageInfo info;
michael@0 591 if (!dst->asImageInfo(&info)) {
michael@0 592 // SkDebugf("unsupported config for info %d\n", dst->config());
michael@0 593 return false;
michael@0 594 }
michael@0 595
michael@0 596 SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, dst->rowBytes(),
michael@0 597 ctable);
michael@0 598 if (NULL == pr) {
michael@0 599 return false;
michael@0 600 }
michael@0 601
michael@0 602 dst->setPixelRef(pr)->unref();
michael@0 603 // since we're already allocated, we lockPixels right away
michael@0 604 dst->lockPixels();
michael@0 605 return true;
michael@0 606 }
michael@0 607
michael@0 608 ///////////////////////////////////////////////////////////////////////////////
michael@0 609
michael@0 610 bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize,
michael@0 611 size_t dstRowBytes, bool preserveDstPad) const {
michael@0 612
michael@0 613 if (0 == dstRowBytes) {
michael@0 614 dstRowBytes = fRowBytes;
michael@0 615 }
michael@0 616
michael@0 617 if (dstRowBytes < fInfo.minRowBytes() ||
michael@0 618 dst == NULL || (getPixels() == NULL && pixelRef() == NULL)) {
michael@0 619 return false;
michael@0 620 }
michael@0 621
michael@0 622 if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == fRowBytes) {
michael@0 623 size_t safeSize = this->getSafeSize();
michael@0 624 if (safeSize > dstSize || safeSize == 0)
michael@0 625 return false;
michael@0 626 else {
michael@0 627 SkAutoLockPixels lock(*this);
michael@0 628 // This implementation will write bytes beyond the end of each row,
michael@0 629 // excluding the last row, if the bitmap's stride is greater than
michael@0 630 // strictly required by the current config.
michael@0 631 memcpy(dst, getPixels(), safeSize);
michael@0 632
michael@0 633 return true;
michael@0 634 }
michael@0 635 } else {
michael@0 636 // If destination has different stride than us, then copy line by line.
michael@0 637 if (fInfo.getSafeSize(dstRowBytes) > dstSize) {
michael@0 638 return false;
michael@0 639 } else {
michael@0 640 // Just copy what we need on each line.
michael@0 641 size_t rowBytes = fInfo.minRowBytes();
michael@0 642 SkAutoLockPixels lock(*this);
michael@0 643 const uint8_t* srcP = reinterpret_cast<const uint8_t*>(getPixels());
michael@0 644 uint8_t* dstP = reinterpret_cast<uint8_t*>(dst);
michael@0 645 for (int row = 0; row < fInfo.fHeight;
michael@0 646 row++, srcP += fRowBytes, dstP += dstRowBytes) {
michael@0 647 memcpy(dstP, srcP, rowBytes);
michael@0 648 }
michael@0 649
michael@0 650 return true;
michael@0 651 }
michael@0 652 }
michael@0 653 }
michael@0 654
michael@0 655 ///////////////////////////////////////////////////////////////////////////////
michael@0 656
michael@0 657 bool SkBitmap::isImmutable() const {
michael@0 658 return fPixelRef ? fPixelRef->isImmutable() :
michael@0 659 fFlags & kImageIsImmutable_Flag;
michael@0 660 }
michael@0 661
michael@0 662 void SkBitmap::setImmutable() {
michael@0 663 if (fPixelRef) {
michael@0 664 fPixelRef->setImmutable();
michael@0 665 } else {
michael@0 666 fFlags |= kImageIsImmutable_Flag;
michael@0 667 }
michael@0 668 }
michael@0 669
michael@0 670 bool SkBitmap::isVolatile() const {
michael@0 671 return (fFlags & kImageIsVolatile_Flag) != 0;
michael@0 672 }
michael@0 673
michael@0 674 void SkBitmap::setIsVolatile(bool isVolatile) {
michael@0 675 if (isVolatile) {
michael@0 676 fFlags |= kImageIsVolatile_Flag;
michael@0 677 } else {
michael@0 678 fFlags &= ~kImageIsVolatile_Flag;
michael@0 679 }
michael@0 680 }
michael@0 681
michael@0 682 void* SkBitmap::getAddr(int x, int y) const {
michael@0 683 SkASSERT((unsigned)x < (unsigned)this->width());
michael@0 684 SkASSERT((unsigned)y < (unsigned)this->height());
michael@0 685
michael@0 686 char* base = (char*)this->getPixels();
michael@0 687 if (base) {
michael@0 688 base += y * this->rowBytes();
michael@0 689 switch (this->colorType()) {
michael@0 690 case kRGBA_8888_SkColorType:
michael@0 691 case kBGRA_8888_SkColorType:
michael@0 692 base += x << 2;
michael@0 693 break;
michael@0 694 case kARGB_4444_SkColorType:
michael@0 695 case kRGB_565_SkColorType:
michael@0 696 base += x << 1;
michael@0 697 break;
michael@0 698 case kAlpha_8_SkColorType:
michael@0 699 case kIndex_8_SkColorType:
michael@0 700 base += x;
michael@0 701 break;
michael@0 702 default:
michael@0 703 SkDEBUGFAIL("Can't return addr for config");
michael@0 704 base = NULL;
michael@0 705 break;
michael@0 706 }
michael@0 707 }
michael@0 708 return base;
michael@0 709 }
michael@0 710
michael@0 711 SkColor SkBitmap::getColor(int x, int y) const {
michael@0 712 SkASSERT((unsigned)x < (unsigned)this->width());
michael@0 713 SkASSERT((unsigned)y < (unsigned)this->height());
michael@0 714
michael@0 715 switch (this->config()) {
michael@0 716 case SkBitmap::kA8_Config: {
michael@0 717 uint8_t* addr = this->getAddr8(x, y);
michael@0 718 return SkColorSetA(0, addr[0]);
michael@0 719 }
michael@0 720 case SkBitmap::kIndex8_Config: {
michael@0 721 SkPMColor c = this->getIndex8Color(x, y);
michael@0 722 return SkUnPreMultiply::PMColorToColor(c);
michael@0 723 }
michael@0 724 case SkBitmap::kRGB_565_Config: {
michael@0 725 uint16_t* addr = this->getAddr16(x, y);
michael@0 726 return SkPixel16ToColor(addr[0]);
michael@0 727 }
michael@0 728 case SkBitmap::kARGB_4444_Config: {
michael@0 729 uint16_t* addr = this->getAddr16(x, y);
michael@0 730 SkPMColor c = SkPixel4444ToPixel32(addr[0]);
michael@0 731 return SkUnPreMultiply::PMColorToColor(c);
michael@0 732 }
michael@0 733 case SkBitmap::kARGB_8888_Config: {
michael@0 734 uint32_t* addr = this->getAddr32(x, y);
michael@0 735 return SkUnPreMultiply::PMColorToColor(addr[0]);
michael@0 736 }
michael@0 737 case kNo_Config:
michael@0 738 default:
michael@0 739 SkASSERT(false);
michael@0 740 return 0;
michael@0 741 }
michael@0 742 SkASSERT(false); // Not reached.
michael@0 743 return 0;
michael@0 744 }
michael@0 745
michael@0 746 bool SkBitmap::ComputeIsOpaque(const SkBitmap& bm) {
michael@0 747 SkAutoLockPixels alp(bm);
michael@0 748 if (!bm.getPixels()) {
michael@0 749 return false;
michael@0 750 }
michael@0 751
michael@0 752 const int height = bm.height();
michael@0 753 const int width = bm.width();
michael@0 754
michael@0 755 switch (bm.config()) {
michael@0 756 case SkBitmap::kA8_Config: {
michael@0 757 unsigned a = 0xFF;
michael@0 758 for (int y = 0; y < height; ++y) {
michael@0 759 const uint8_t* row = bm.getAddr8(0, y);
michael@0 760 for (int x = 0; x < width; ++x) {
michael@0 761 a &= row[x];
michael@0 762 }
michael@0 763 if (0xFF != a) {
michael@0 764 return false;
michael@0 765 }
michael@0 766 }
michael@0 767 return true;
michael@0 768 } break;
michael@0 769 case SkBitmap::kIndex8_Config: {
michael@0 770 SkAutoLockColors alc(bm);
michael@0 771 const SkPMColor* table = alc.colors();
michael@0 772 if (!table) {
michael@0 773 return false;
michael@0 774 }
michael@0 775 SkPMColor c = (SkPMColor)~0;
michael@0 776 for (int i = bm.getColorTable()->count() - 1; i >= 0; --i) {
michael@0 777 c &= table[i];
michael@0 778 }
michael@0 779 return 0xFF == SkGetPackedA32(c);
michael@0 780 } break;
michael@0 781 case SkBitmap::kRGB_565_Config:
michael@0 782 return true;
michael@0 783 break;
michael@0 784 case SkBitmap::kARGB_4444_Config: {
michael@0 785 unsigned c = 0xFFFF;
michael@0 786 for (int y = 0; y < height; ++y) {
michael@0 787 const SkPMColor16* row = bm.getAddr16(0, y);
michael@0 788 for (int x = 0; x < width; ++x) {
michael@0 789 c &= row[x];
michael@0 790 }
michael@0 791 if (0xF != SkGetPackedA4444(c)) {
michael@0 792 return false;
michael@0 793 }
michael@0 794 }
michael@0 795 return true;
michael@0 796 } break;
michael@0 797 case SkBitmap::kARGB_8888_Config: {
michael@0 798 SkPMColor c = (SkPMColor)~0;
michael@0 799 for (int y = 0; y < height; ++y) {
michael@0 800 const SkPMColor* row = bm.getAddr32(0, y);
michael@0 801 for (int x = 0; x < width; ++x) {
michael@0 802 c &= row[x];
michael@0 803 }
michael@0 804 if (0xFF != SkGetPackedA32(c)) {
michael@0 805 return false;
michael@0 806 }
michael@0 807 }
michael@0 808 return true;
michael@0 809 }
michael@0 810 default:
michael@0 811 break;
michael@0 812 }
michael@0 813 return false;
michael@0 814 }
michael@0 815
michael@0 816
michael@0 817 ///////////////////////////////////////////////////////////////////////////////
michael@0 818 ///////////////////////////////////////////////////////////////////////////////
michael@0 819
michael@0 820 static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) {
michael@0 821 unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) |
michael@0 822 (SkR32To4444(r) << SK_R4444_SHIFT) |
michael@0 823 (SkG32To4444(g) << SK_G4444_SHIFT) |
michael@0 824 (SkB32To4444(b) << SK_B4444_SHIFT);
michael@0 825 return SkToU16(pixel);
michael@0 826 }
michael@0 827
michael@0 828 void SkBitmap::internalErase(const SkIRect& area,
michael@0 829 U8CPU a, U8CPU r, U8CPU g, U8CPU b) const {
michael@0 830 #ifdef SK_DEBUG
michael@0 831 SkDEBUGCODE(this->validate();)
michael@0 832 SkASSERT(!area.isEmpty());
michael@0 833 {
michael@0 834 SkIRect total = { 0, 0, this->width(), this->height() };
michael@0 835 SkASSERT(total.contains(area));
michael@0 836 }
michael@0 837 #endif
michael@0 838
michael@0 839 switch (fInfo.colorType()) {
michael@0 840 case kUnknown_SkColorType:
michael@0 841 case kIndex_8_SkColorType:
michael@0 842 return; // can't erase
michael@0 843 default:
michael@0 844 break;
michael@0 845 }
michael@0 846
michael@0 847 SkAutoLockPixels alp(*this);
michael@0 848 // perform this check after the lock call
michael@0 849 if (!this->readyToDraw()) {
michael@0 850 return;
michael@0 851 }
michael@0 852
michael@0 853 int height = area.height();
michael@0 854 const int width = area.width();
michael@0 855 const int rowBytes = fRowBytes;
michael@0 856
michael@0 857 // make rgb premultiplied
michael@0 858 if (255 != a) {
michael@0 859 r = SkAlphaMul(r, a);
michael@0 860 g = SkAlphaMul(g, a);
michael@0 861 b = SkAlphaMul(b, a);
michael@0 862 }
michael@0 863
michael@0 864 switch (this->colorType()) {
michael@0 865 case kAlpha_8_SkColorType: {
michael@0 866 uint8_t* p = this->getAddr8(area.fLeft, area.fTop);
michael@0 867 while (--height >= 0) {
michael@0 868 memset(p, a, width);
michael@0 869 p += rowBytes;
michael@0 870 }
michael@0 871 break;
michael@0 872 }
michael@0 873 case kARGB_4444_SkColorType:
michael@0 874 case kRGB_565_SkColorType: {
michael@0 875 uint16_t* p = this->getAddr16(area.fLeft, area.fTop);;
michael@0 876 uint16_t v;
michael@0 877
michael@0 878 if (kARGB_4444_SkColorType == this->colorType()) {
michael@0 879 v = pack_8888_to_4444(a, r, g, b);
michael@0 880 } else {
michael@0 881 v = SkPackRGB16(r >> (8 - SK_R16_BITS),
michael@0 882 g >> (8 - SK_G16_BITS),
michael@0 883 b >> (8 - SK_B16_BITS));
michael@0 884 }
michael@0 885 while (--height >= 0) {
michael@0 886 sk_memset16(p, v, width);
michael@0 887 p = (uint16_t*)((char*)p + rowBytes);
michael@0 888 }
michael@0 889 break;
michael@0 890 }
michael@0 891 case kPMColor_SkColorType: {
michael@0 892 // what to do about BGRA or RGBA (which ever is != PMColor ?
michael@0 893 // for now we don't support them.
michael@0 894 uint32_t* p = this->getAddr32(area.fLeft, area.fTop);
michael@0 895 uint32_t v = SkPackARGB32(a, r, g, b);
michael@0 896
michael@0 897 while (--height >= 0) {
michael@0 898 sk_memset32(p, v, width);
michael@0 899 p = (uint32_t*)((char*)p + rowBytes);
michael@0 900 }
michael@0 901 break;
michael@0 902 }
michael@0 903 default:
michael@0 904 return; // no change, so don't call notifyPixelsChanged()
michael@0 905 }
michael@0 906
michael@0 907 this->notifyPixelsChanged();
michael@0 908 }
michael@0 909
michael@0 910 void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const {
michael@0 911 SkIRect area = { 0, 0, this->width(), this->height() };
michael@0 912 if (!area.isEmpty()) {
michael@0 913 this->internalErase(area, a, r, g, b);
michael@0 914 }
michael@0 915 }
michael@0 916
michael@0 917 void SkBitmap::eraseArea(const SkIRect& rect, SkColor c) const {
michael@0 918 SkIRect area = { 0, 0, this->width(), this->height() };
michael@0 919 if (area.intersect(rect)) {
michael@0 920 this->internalErase(area, SkColorGetA(c), SkColorGetR(c),
michael@0 921 SkColorGetG(c), SkColorGetB(c));
michael@0 922 }
michael@0 923 }
michael@0 924
michael@0 925 //////////////////////////////////////////////////////////////////////////////////////
michael@0 926 //////////////////////////////////////////////////////////////////////////////////////
michael@0 927
michael@0 928 bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
michael@0 929 SkDEBUGCODE(this->validate();)
michael@0 930
michael@0 931 if (NULL == result || NULL == fPixelRef) {
michael@0 932 return false; // no src pixels
michael@0 933 }
michael@0 934
michael@0 935 SkIRect srcRect, r;
michael@0 936 srcRect.set(0, 0, this->width(), this->height());
michael@0 937 if (!r.intersect(srcRect, subset)) {
michael@0 938 return false; // r is empty (i.e. no intersection)
michael@0 939 }
michael@0 940
michael@0 941 if (fPixelRef->getTexture() != NULL) {
michael@0 942 // Do a deep copy
michael@0 943 SkPixelRef* pixelRef = fPixelRef->deepCopy(this->config(), &subset);
michael@0 944 if (pixelRef != NULL) {
michael@0 945 SkBitmap dst;
michael@0 946 dst.setConfig(this->config(), subset.width(), subset.height(), 0,
michael@0 947 this->alphaType());
michael@0 948 dst.setIsVolatile(this->isVolatile());
michael@0 949 dst.setPixelRef(pixelRef)->unref();
michael@0 950 SkDEBUGCODE(dst.validate());
michael@0 951 result->swap(dst);
michael@0 952 return true;
michael@0 953 }
michael@0 954 }
michael@0 955
michael@0 956 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
michael@0 957 // exited above.
michael@0 958 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
michael@0 959 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
michael@0 960
michael@0 961 SkBitmap dst;
michael@0 962 dst.setConfig(this->config(), r.width(), r.height(), this->rowBytes(),
michael@0 963 this->alphaType());
michael@0 964 dst.setIsVolatile(this->isVolatile());
michael@0 965
michael@0 966 if (fPixelRef) {
michael@0 967 SkIPoint origin = fPixelRefOrigin;
michael@0 968 origin.fX += r.fLeft;
michael@0 969 origin.fY += r.fTop;
michael@0 970 // share the pixelref with a custom offset
michael@0 971 dst.setPixelRef(fPixelRef, origin);
michael@0 972 }
michael@0 973 SkDEBUGCODE(dst.validate();)
michael@0 974
michael@0 975 // we know we're good, so commit to result
michael@0 976 result->swap(dst);
michael@0 977 return true;
michael@0 978 }
michael@0 979
michael@0 980 ///////////////////////////////////////////////////////////////////////////////
michael@0 981
michael@0 982 #include "SkCanvas.h"
michael@0 983 #include "SkPaint.h"
michael@0 984
michael@0 985 bool SkBitmap::canCopyTo(SkColorType dstColorType) const {
michael@0 986 if (this->colorType() == kUnknown_SkColorType) {
michael@0 987 return false;
michael@0 988 }
michael@0 989
michael@0 990 bool sameConfigs = (this->colorType() == dstColorType);
michael@0 991 switch (dstColorType) {
michael@0 992 case kAlpha_8_SkColorType:
michael@0 993 case kRGB_565_SkColorType:
michael@0 994 case kPMColor_SkColorType:
michael@0 995 break;
michael@0 996 case kIndex_8_SkColorType:
michael@0 997 if (!sameConfigs) {
michael@0 998 return false;
michael@0 999 }
michael@0 1000 break;
michael@0 1001 case kARGB_4444_SkColorType:
michael@0 1002 return sameConfigs || kPMColor_SkColorType == this->colorType();
michael@0 1003 default:
michael@0 1004 return false;
michael@0 1005 }
michael@0 1006 return true;
michael@0 1007 }
michael@0 1008
michael@0 1009 bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType,
michael@0 1010 Allocator* alloc) const {
michael@0 1011 if (!this->canCopyTo(dstColorType)) {
michael@0 1012 return false;
michael@0 1013 }
michael@0 1014
michael@0 1015 // if we have a texture, first get those pixels
michael@0 1016 SkBitmap tmpSrc;
michael@0 1017 const SkBitmap* src = this;
michael@0 1018
michael@0 1019 if (fPixelRef) {
michael@0 1020 SkIRect subset;
michael@0 1021 subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY,
michael@0 1022 fInfo.width(), fInfo.height());
michael@0 1023 if (fPixelRef->readPixels(&tmpSrc, &subset)) {
michael@0 1024 SkASSERT(tmpSrc.width() == this->width());
michael@0 1025 SkASSERT(tmpSrc.height() == this->height());
michael@0 1026
michael@0 1027 // did we get lucky and we can just return tmpSrc?
michael@0 1028 if (tmpSrc.colorType() == dstColorType && NULL == alloc) {
michael@0 1029 dst->swap(tmpSrc);
michael@0 1030 // If the result is an exact copy, clone the gen ID.
michael@0 1031 if (dst->pixelRef() && dst->pixelRef()->info() == fPixelRef->info()) {
michael@0 1032 dst->pixelRef()->cloneGenID(*fPixelRef);
michael@0 1033 }
michael@0 1034 return true;
michael@0 1035 }
michael@0 1036
michael@0 1037 // fall through to the raster case
michael@0 1038 src = &tmpSrc;
michael@0 1039 }
michael@0 1040 }
michael@0 1041
michael@0 1042 // we lock this now, since we may need its colortable
michael@0 1043 SkAutoLockPixels srclock(*src);
michael@0 1044 if (!src->readyToDraw()) {
michael@0 1045 return false;
michael@0 1046 }
michael@0 1047
michael@0 1048 // The only way to be readyToDraw is if fPixelRef is non NULL.
michael@0 1049 SkASSERT(fPixelRef != NULL);
michael@0 1050
michael@0 1051 SkImageInfo dstInfo = src->info();
michael@0 1052 dstInfo.fColorType = dstColorType;
michael@0 1053
michael@0 1054 SkBitmap tmpDst;
michael@0 1055 if (!tmpDst.setConfig(dstInfo)) {
michael@0 1056 return false;
michael@0 1057 }
michael@0 1058
michael@0 1059 // allocate colortable if srcConfig == kIndex8_Config
michael@0 1060 SkAutoTUnref<SkColorTable> ctable;
michael@0 1061 if (dstColorType == kIndex_8_SkColorType) {
michael@0 1062 // TODO: can we just ref() the src colortable? Is it reentrant-safe?
michael@0 1063 ctable.reset(SkNEW_ARGS(SkColorTable, (*src->getColorTable())));
michael@0 1064 }
michael@0 1065 if (!tmpDst.allocPixels(alloc, ctable)) {
michael@0 1066 return false;
michael@0 1067 }
michael@0 1068
michael@0 1069 if (!tmpDst.readyToDraw()) {
michael@0 1070 // allocator/lock failed
michael@0 1071 return false;
michael@0 1072 }
michael@0 1073
michael@0 1074 // pixelRef must be non NULL or tmpDst.readyToDraw() would have
michael@0 1075 // returned false.
michael@0 1076 SkASSERT(tmpDst.pixelRef() != NULL);
michael@0 1077
michael@0 1078 /* do memcpy for the same configs cases, else use drawing
michael@0 1079 */
michael@0 1080 if (src->colorType() == dstColorType) {
michael@0 1081 if (tmpDst.getSize() == src->getSize()) {
michael@0 1082 memcpy(tmpDst.getPixels(), src->getPixels(), src->getSafeSize());
michael@0 1083 SkPixelRef* pixelRef = tmpDst.pixelRef();
michael@0 1084
michael@0 1085 // In order to reach this point, we know that the width, config and
michael@0 1086 // rowbytes of the SkPixelRefs are the same, but it is possible for
michael@0 1087 // the heights to differ, if this SkBitmap's height is a subset of
michael@0 1088 // fPixelRef. Only if the SkPixelRefs' heights match are we
michael@0 1089 // guaranteed that this is an exact copy, meaning we should clone
michael@0 1090 // the genID.
michael@0 1091 if (pixelRef->info().fHeight == fPixelRef->info().fHeight) {
michael@0 1092 // TODO: what to do if the two infos match, BUT
michael@0 1093 // fPixelRef is premul and pixelRef is opaque?
michael@0 1094 // skipping assert for now
michael@0 1095 // https://code.google.com/p/skia/issues/detail?id=2012
michael@0 1096 // SkASSERT(pixelRef->info() == fPixelRef->info());
michael@0 1097 SkASSERT(pixelRef->info().fWidth == fPixelRef->info().fWidth);
michael@0 1098 SkASSERT(pixelRef->info().fColorType == fPixelRef->info().fColorType);
michael@0 1099 pixelRef->cloneGenID(*fPixelRef);
michael@0 1100 }
michael@0 1101 } else {
michael@0 1102 const char* srcP = reinterpret_cast<const char*>(src->getPixels());
michael@0 1103 char* dstP = reinterpret_cast<char*>(tmpDst.getPixels());
michael@0 1104 // to be sure we don't read too much, only copy our logical pixels
michael@0 1105 size_t bytesToCopy = tmpDst.width() * tmpDst.bytesPerPixel();
michael@0 1106 for (int y = 0; y < tmpDst.height(); y++) {
michael@0 1107 memcpy(dstP, srcP, bytesToCopy);
michael@0 1108 srcP += src->rowBytes();
michael@0 1109 dstP += tmpDst.rowBytes();
michael@0 1110 }
michael@0 1111 }
michael@0 1112 } else if (kARGB_4444_SkColorType == dstColorType
michael@0 1113 && kPMColor_SkColorType == src->colorType()) {
michael@0 1114 SkASSERT(src->height() == tmpDst.height());
michael@0 1115 SkASSERT(src->width() == tmpDst.width());
michael@0 1116 for (int y = 0; y < src->height(); ++y) {
michael@0 1117 SkPMColor16* SK_RESTRICT dstRow = (SkPMColor16*) tmpDst.getAddr16(0, y);
michael@0 1118 SkPMColor* SK_RESTRICT srcRow = (SkPMColor*) src->getAddr32(0, y);
michael@0 1119 DITHER_4444_SCAN(y);
michael@0 1120 for (int x = 0; x < src->width(); ++x) {
michael@0 1121 dstRow[x] = SkDitherARGB32To4444(srcRow[x],
michael@0 1122 DITHER_VALUE(x));
michael@0 1123 }
michael@0 1124 }
michael@0 1125 } else {
michael@0 1126 // Always clear the dest in case one of the blitters accesses it
michael@0 1127 // TODO: switch the allocation of tmpDst to call sk_calloc_throw
michael@0 1128 tmpDst.eraseColor(SK_ColorTRANSPARENT);
michael@0 1129
michael@0 1130 SkCanvas canvas(tmpDst);
michael@0 1131 SkPaint paint;
michael@0 1132
michael@0 1133 paint.setDither(true);
michael@0 1134 canvas.drawBitmap(*src, 0, 0, &paint);
michael@0 1135 }
michael@0 1136
michael@0 1137 dst->swap(tmpDst);
michael@0 1138 return true;
michael@0 1139 }
michael@0 1140
michael@0 1141 bool SkBitmap::deepCopyTo(SkBitmap* dst) const {
michael@0 1142 const SkBitmap::Config dstConfig = this->config();
michael@0 1143 const SkColorType dstCT = SkBitmapConfigToColorType(dstConfig);
michael@0 1144
michael@0 1145 if (!this->canCopyTo(dstCT)) {
michael@0 1146 return false;
michael@0 1147 }
michael@0 1148
michael@0 1149 // If we have a PixelRef, and it supports deep copy, use it.
michael@0 1150 // Currently supported only by texture-backed bitmaps.
michael@0 1151 if (fPixelRef) {
michael@0 1152 SkPixelRef* pixelRef = fPixelRef->deepCopy(dstConfig);
michael@0 1153 if (pixelRef) {
michael@0 1154 uint32_t rowBytes;
michael@0 1155 if (this->colorType() == dstCT) {
michael@0 1156 // Since there is no subset to pass to deepCopy, and deepCopy
michael@0 1157 // succeeded, the new pixel ref must be identical.
michael@0 1158 SkASSERT(fPixelRef->info() == pixelRef->info());
michael@0 1159 pixelRef->cloneGenID(*fPixelRef);
michael@0 1160 // Use the same rowBytes as the original.
michael@0 1161 rowBytes = fRowBytes;
michael@0 1162 } else {
michael@0 1163 // With the new config, an appropriate fRowBytes will be computed by setConfig.
michael@0 1164 rowBytes = 0;
michael@0 1165 }
michael@0 1166
michael@0 1167 SkImageInfo info = fInfo;
michael@0 1168 info.fColorType = dstCT;
michael@0 1169 if (!dst->setConfig(info, rowBytes)) {
michael@0 1170 return false;
michael@0 1171 }
michael@0 1172 dst->setPixelRef(pixelRef, fPixelRefOrigin)->unref();
michael@0 1173 return true;
michael@0 1174 }
michael@0 1175 }
michael@0 1176
michael@0 1177 if (this->getTexture()) {
michael@0 1178 return false;
michael@0 1179 } else {
michael@0 1180 return this->copyTo(dst, dstCT, NULL);
michael@0 1181 }
michael@0 1182 }
michael@0 1183
michael@0 1184 ///////////////////////////////////////////////////////////////////////////////
michael@0 1185 ///////////////////////////////////////////////////////////////////////////////
michael@0 1186
michael@0 1187 static void downsampleby2_proc32(SkBitmap* dst, int x, int y,
michael@0 1188 const SkBitmap& src) {
michael@0 1189 x <<= 1;
michael@0 1190 y <<= 1;
michael@0 1191 const SkPMColor* p = src.getAddr32(x, y);
michael@0 1192 const SkPMColor* baseP = p;
michael@0 1193 SkPMColor c, ag, rb;
michael@0 1194
michael@0 1195 c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF;
michael@0 1196 if (x < src.width() - 1) {
michael@0 1197 p += 1;
michael@0 1198 }
michael@0 1199 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF;
michael@0 1200
michael@0 1201 p = baseP;
michael@0 1202 if (y < src.height() - 1) {
michael@0 1203 p += src.rowBytes() >> 2;
michael@0 1204 }
michael@0 1205 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF;
michael@0 1206 if (x < src.width() - 1) {
michael@0 1207 p += 1;
michael@0 1208 }
michael@0 1209 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF;
michael@0 1210
michael@0 1211 *dst->getAddr32(x >> 1, y >> 1) =
michael@0 1212 ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00);
michael@0 1213 }
michael@0 1214
michael@0 1215 static inline uint32_t expand16(U16CPU c) {
michael@0 1216 return (c & ~SK_G16_MASK_IN_PLACE) | ((c & SK_G16_MASK_IN_PLACE) << 16);
michael@0 1217 }
michael@0 1218
michael@0 1219 // returns dirt in the top 16bits, but we don't care, since we only
michael@0 1220 // store the low 16bits.
michael@0 1221 static inline U16CPU pack16(uint32_t c) {
michael@0 1222 return (c & ~SK_G16_MASK_IN_PLACE) | ((c >> 16) & SK_G16_MASK_IN_PLACE);
michael@0 1223 }
michael@0 1224
michael@0 1225 static void downsampleby2_proc16(SkBitmap* dst, int x, int y,
michael@0 1226 const SkBitmap& src) {
michael@0 1227 x <<= 1;
michael@0 1228 y <<= 1;
michael@0 1229 const uint16_t* p = src.getAddr16(x, y);
michael@0 1230 const uint16_t* baseP = p;
michael@0 1231 SkPMColor c;
michael@0 1232
michael@0 1233 c = expand16(*p);
michael@0 1234 if (x < src.width() - 1) {
michael@0 1235 p += 1;
michael@0 1236 }
michael@0 1237 c += expand16(*p);
michael@0 1238
michael@0 1239 p = baseP;
michael@0 1240 if (y < src.height() - 1) {
michael@0 1241 p += src.rowBytes() >> 1;
michael@0 1242 }
michael@0 1243 c += expand16(*p);
michael@0 1244 if (x < src.width() - 1) {
michael@0 1245 p += 1;
michael@0 1246 }
michael@0 1247 c += expand16(*p);
michael@0 1248
michael@0 1249 *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)pack16(c >> 2);
michael@0 1250 }
michael@0 1251
michael@0 1252 static uint32_t expand4444(U16CPU c) {
michael@0 1253 return (c & 0xF0F) | ((c & ~0xF0F) << 12);
michael@0 1254 }
michael@0 1255
michael@0 1256 static U16CPU collaps4444(uint32_t c) {
michael@0 1257 return (c & 0xF0F) | ((c >> 12) & ~0xF0F);
michael@0 1258 }
michael@0 1259
michael@0 1260 static void downsampleby2_proc4444(SkBitmap* dst, int x, int y,
michael@0 1261 const SkBitmap& src) {
michael@0 1262 x <<= 1;
michael@0 1263 y <<= 1;
michael@0 1264 const uint16_t* p = src.getAddr16(x, y);
michael@0 1265 const uint16_t* baseP = p;
michael@0 1266 uint32_t c;
michael@0 1267
michael@0 1268 c = expand4444(*p);
michael@0 1269 if (x < src.width() - 1) {
michael@0 1270 p += 1;
michael@0 1271 }
michael@0 1272 c += expand4444(*p);
michael@0 1273
michael@0 1274 p = baseP;
michael@0 1275 if (y < src.height() - 1) {
michael@0 1276 p += src.rowBytes() >> 1;
michael@0 1277 }
michael@0 1278 c += expand4444(*p);
michael@0 1279 if (x < src.width() - 1) {
michael@0 1280 p += 1;
michael@0 1281 }
michael@0 1282 c += expand4444(*p);
michael@0 1283
michael@0 1284 *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)collaps4444(c >> 2);
michael@0 1285 }
michael@0 1286
michael@0 1287 void SkBitmap::buildMipMap(bool forceRebuild) {
michael@0 1288 if (forceRebuild)
michael@0 1289 this->freeMipMap();
michael@0 1290 else if (fMipMap)
michael@0 1291 return; // we're already built
michael@0 1292
michael@0 1293 SkASSERT(NULL == fMipMap);
michael@0 1294
michael@0 1295 void (*proc)(SkBitmap* dst, int x, int y, const SkBitmap& src);
michael@0 1296
michael@0 1297 const SkBitmap::Config config = this->config();
michael@0 1298
michael@0 1299 switch (config) {
michael@0 1300 case kARGB_8888_Config:
michael@0 1301 proc = downsampleby2_proc32;
michael@0 1302 break;
michael@0 1303 case kRGB_565_Config:
michael@0 1304 proc = downsampleby2_proc16;
michael@0 1305 break;
michael@0 1306 case kARGB_4444_Config:
michael@0 1307 proc = downsampleby2_proc4444;
michael@0 1308 break;
michael@0 1309 case kIndex8_Config:
michael@0 1310 case kA8_Config:
michael@0 1311 default:
michael@0 1312 return; // don't build mipmaps for these configs
michael@0 1313 }
michael@0 1314
michael@0 1315 SkAutoLockPixels alp(*this);
michael@0 1316 if (!this->readyToDraw()) {
michael@0 1317 return;
michael@0 1318 }
michael@0 1319
michael@0 1320 // whip through our loop to compute the exact size needed
michael@0 1321 size_t size = 0;
michael@0 1322 int maxLevels = 0;
michael@0 1323 {
michael@0 1324 int width = this->width();
michael@0 1325 int height = this->height();
michael@0 1326 for (;;) {
michael@0 1327 width >>= 1;
michael@0 1328 height >>= 1;
michael@0 1329 if (0 == width || 0 == height) {
michael@0 1330 break;
michael@0 1331 }
michael@0 1332 size += ComputeRowBytes(config, width) * height;
michael@0 1333 maxLevels += 1;
michael@0 1334 }
michael@0 1335 }
michael@0 1336
michael@0 1337 // nothing to build
michael@0 1338 if (0 == maxLevels) {
michael@0 1339 return;
michael@0 1340 }
michael@0 1341
michael@0 1342 SkBitmap srcBM(*this);
michael@0 1343 srcBM.lockPixels();
michael@0 1344 if (!srcBM.readyToDraw()) {
michael@0 1345 return;
michael@0 1346 }
michael@0 1347
michael@0 1348 MipMap* mm = MipMap::Alloc(maxLevels, size);
michael@0 1349 if (NULL == mm) {
michael@0 1350 return;
michael@0 1351 }
michael@0 1352
michael@0 1353 MipLevel* level = mm->levels();
michael@0 1354 uint8_t* addr = (uint8_t*)mm->pixels();
michael@0 1355 int width = this->width();
michael@0 1356 int height = this->height();
michael@0 1357 uint32_t rowBytes;
michael@0 1358 SkBitmap dstBM;
michael@0 1359
michael@0 1360 for (int i = 0; i < maxLevels; i++) {
michael@0 1361 width >>= 1;
michael@0 1362 height >>= 1;
michael@0 1363 rowBytes = SkToU32(ComputeRowBytes(config, width));
michael@0 1364
michael@0 1365 level[i].fPixels = addr;
michael@0 1366 level[i].fWidth = width;
michael@0 1367 level[i].fHeight = height;
michael@0 1368 level[i].fRowBytes = rowBytes;
michael@0 1369
michael@0 1370 dstBM.setConfig(config, width, height, rowBytes);
michael@0 1371 dstBM.setPixels(addr);
michael@0 1372
michael@0 1373 srcBM.lockPixels();
michael@0 1374 for (int y = 0; y < height; y++) {
michael@0 1375 for (int x = 0; x < width; x++) {
michael@0 1376 proc(&dstBM, x, y, srcBM);
michael@0 1377 }
michael@0 1378 }
michael@0 1379 srcBM.unlockPixels();
michael@0 1380
michael@0 1381 srcBM = dstBM;
michael@0 1382 addr += height * rowBytes;
michael@0 1383 }
michael@0 1384 SkASSERT(addr == (uint8_t*)mm->pixels() + size);
michael@0 1385 fMipMap = mm;
michael@0 1386 }
michael@0 1387
michael@0 1388 bool SkBitmap::hasMipMap() const {
michael@0 1389 return fMipMap != NULL;
michael@0 1390 }
michael@0 1391
michael@0 1392 int SkBitmap::extractMipLevel(SkBitmap* dst, SkFixed sx, SkFixed sy) {
michael@0 1393 if (NULL == fMipMap) {
michael@0 1394 return 0;
michael@0 1395 }
michael@0 1396
michael@0 1397 int level = ComputeMipLevel(sx, sy) >> 16;
michael@0 1398 SkASSERT(level >= 0);
michael@0 1399 if (level <= 0) {
michael@0 1400 return 0;
michael@0 1401 }
michael@0 1402
michael@0 1403 if (level >= fMipMap->fLevelCount) {
michael@0 1404 level = fMipMap->fLevelCount - 1;
michael@0 1405 }
michael@0 1406 if (dst) {
michael@0 1407 const MipLevel& mip = fMipMap->levels()[level - 1];
michael@0 1408 dst->setConfig((SkBitmap::Config)this->config(),
michael@0 1409 mip.fWidth, mip.fHeight, mip.fRowBytes);
michael@0 1410 dst->setPixels(mip.fPixels);
michael@0 1411 }
michael@0 1412 return level;
michael@0 1413 }
michael@0 1414
michael@0 1415 SkFixed SkBitmap::ComputeMipLevel(SkFixed sx, SkFixed sy) {
michael@0 1416 sx = SkAbs32(sx);
michael@0 1417 sy = SkAbs32(sy);
michael@0 1418 if (sx < sy) {
michael@0 1419 sx = sy;
michael@0 1420 }
michael@0 1421 if (sx < SK_Fixed1) {
michael@0 1422 return 0;
michael@0 1423 }
michael@0 1424 int clz = SkCLZ(sx);
michael@0 1425 SkASSERT(clz >= 1 && clz <= 15);
michael@0 1426 return SkIntToFixed(15 - clz) + ((unsigned)(sx << (clz + 1)) >> 16);
michael@0 1427 }
michael@0 1428
michael@0 1429 ///////////////////////////////////////////////////////////////////////////////
michael@0 1430
michael@0 1431 static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha,
michael@0 1432 int alphaRowBytes) {
michael@0 1433 SkASSERT(alpha != NULL);
michael@0 1434 SkASSERT(alphaRowBytes >= src.width());
michael@0 1435
michael@0 1436 SkBitmap::Config config = src.config();
michael@0 1437 int w = src.width();
michael@0 1438 int h = src.height();
michael@0 1439 size_t rb = src.rowBytes();
michael@0 1440
michael@0 1441 SkAutoLockPixels alp(src);
michael@0 1442 if (!src.readyToDraw()) {
michael@0 1443 // zero out the alpha buffer and return
michael@0 1444 while (--h >= 0) {
michael@0 1445 memset(alpha, 0, w);
michael@0 1446 alpha += alphaRowBytes;
michael@0 1447 }
michael@0 1448 return false;
michael@0 1449 }
michael@0 1450
michael@0 1451 if (SkBitmap::kA8_Config == config && !src.isOpaque()) {
michael@0 1452 const uint8_t* s = src.getAddr8(0, 0);
michael@0 1453 while (--h >= 0) {
michael@0 1454 memcpy(alpha, s, w);
michael@0 1455 s += rb;
michael@0 1456 alpha += alphaRowBytes;
michael@0 1457 }
michael@0 1458 } else if (SkBitmap::kARGB_8888_Config == config && !src.isOpaque()) {
michael@0 1459 const SkPMColor* SK_RESTRICT s = src.getAddr32(0, 0);
michael@0 1460 while (--h >= 0) {
michael@0 1461 for (int x = 0; x < w; x++) {
michael@0 1462 alpha[x] = SkGetPackedA32(s[x]);
michael@0 1463 }
michael@0 1464 s = (const SkPMColor*)((const char*)s + rb);
michael@0 1465 alpha += alphaRowBytes;
michael@0 1466 }
michael@0 1467 } else if (SkBitmap::kARGB_4444_Config == config && !src.isOpaque()) {
michael@0 1468 const SkPMColor16* SK_RESTRICT s = src.getAddr16(0, 0);
michael@0 1469 while (--h >= 0) {
michael@0 1470 for (int x = 0; x < w; x++) {
michael@0 1471 alpha[x] = SkPacked4444ToA32(s[x]);
michael@0 1472 }
michael@0 1473 s = (const SkPMColor16*)((const char*)s + rb);
michael@0 1474 alpha += alphaRowBytes;
michael@0 1475 }
michael@0 1476 } else if (SkBitmap::kIndex8_Config == config && !src.isOpaque()) {
michael@0 1477 SkColorTable* ct = src.getColorTable();
michael@0 1478 if (ct) {
michael@0 1479 const SkPMColor* SK_RESTRICT table = ct->lockColors();
michael@0 1480 const uint8_t* SK_RESTRICT s = src.getAddr8(0, 0);
michael@0 1481 while (--h >= 0) {
michael@0 1482 for (int x = 0; x < w; x++) {
michael@0 1483 alpha[x] = SkGetPackedA32(table[s[x]]);
michael@0 1484 }
michael@0 1485 s += rb;
michael@0 1486 alpha += alphaRowBytes;
michael@0 1487 }
michael@0 1488 ct->unlockColors();
michael@0 1489 }
michael@0 1490 } else { // src is opaque, so just fill alpha[] with 0xFF
michael@0 1491 memset(alpha, 0xFF, h * alphaRowBytes);
michael@0 1492 }
michael@0 1493 return true;
michael@0 1494 }
michael@0 1495
michael@0 1496 #include "SkPaint.h"
michael@0 1497 #include "SkMaskFilter.h"
michael@0 1498 #include "SkMatrix.h"
michael@0 1499
michael@0 1500 bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
michael@0 1501 Allocator *allocator, SkIPoint* offset) const {
michael@0 1502 SkDEBUGCODE(this->validate();)
michael@0 1503
michael@0 1504 SkBitmap tmpBitmap;
michael@0 1505 SkMatrix identity;
michael@0 1506 SkMask srcM, dstM;
michael@0 1507
michael@0 1508 srcM.fBounds.set(0, 0, this->width(), this->height());
michael@0 1509 srcM.fRowBytes = SkAlign4(this->width());
michael@0 1510 srcM.fFormat = SkMask::kA8_Format;
michael@0 1511
michael@0 1512 SkMaskFilter* filter = paint ? paint->getMaskFilter() : NULL;
michael@0 1513
michael@0 1514 // compute our (larger?) dst bounds if we have a filter
michael@0 1515 if (NULL != filter) {
michael@0 1516 identity.reset();
michael@0 1517 srcM.fImage = NULL;
michael@0 1518 if (!filter->filterMask(&dstM, srcM, identity, NULL)) {
michael@0 1519 goto NO_FILTER_CASE;
michael@0 1520 }
michael@0 1521 dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
michael@0 1522 } else {
michael@0 1523 NO_FILTER_CASE:
michael@0 1524 tmpBitmap.setConfig(SkBitmap::kA8_Config, this->width(), this->height(),
michael@0 1525 srcM.fRowBytes);
michael@0 1526 if (!tmpBitmap.allocPixels(allocator, NULL)) {
michael@0 1527 // Allocation of pixels for alpha bitmap failed.
michael@0 1528 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
michael@0 1529 tmpBitmap.width(), tmpBitmap.height());
michael@0 1530 return false;
michael@0 1531 }
michael@0 1532 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
michael@0 1533 if (offset) {
michael@0 1534 offset->set(0, 0);
michael@0 1535 }
michael@0 1536 tmpBitmap.swap(*dst);
michael@0 1537 return true;
michael@0 1538 }
michael@0 1539 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
michael@0 1540 SkAutoMaskFreeImage srcCleanup(srcM.fImage);
michael@0 1541
michael@0 1542 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
michael@0 1543 if (!filter->filterMask(&dstM, srcM, identity, NULL)) {
michael@0 1544 goto NO_FILTER_CASE;
michael@0 1545 }
michael@0 1546 SkAutoMaskFreeImage dstCleanup(dstM.fImage);
michael@0 1547
michael@0 1548 tmpBitmap.setConfig(SkBitmap::kA8_Config, dstM.fBounds.width(),
michael@0 1549 dstM.fBounds.height(), dstM.fRowBytes);
michael@0 1550 if (!tmpBitmap.allocPixels(allocator, NULL)) {
michael@0 1551 // Allocation of pixels for alpha bitmap failed.
michael@0 1552 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
michael@0 1553 tmpBitmap.width(), tmpBitmap.height());
michael@0 1554 return false;
michael@0 1555 }
michael@0 1556 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
michael@0 1557 if (offset) {
michael@0 1558 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
michael@0 1559 }
michael@0 1560 SkDEBUGCODE(tmpBitmap.validate();)
michael@0 1561
michael@0 1562 tmpBitmap.swap(*dst);
michael@0 1563 return true;
michael@0 1564 }
michael@0 1565
michael@0 1566 ///////////////////////////////////////////////////////////////////////////////
michael@0 1567
michael@0 1568 enum {
michael@0 1569 SERIALIZE_PIXELTYPE_NONE,
michael@0 1570 SERIALIZE_PIXELTYPE_REF_DATA
michael@0 1571 };
michael@0 1572
michael@0 1573 void SkBitmap::flatten(SkWriteBuffer& buffer) const {
michael@0 1574 fInfo.flatten(buffer);
michael@0 1575 buffer.writeInt(fRowBytes);
michael@0 1576
michael@0 1577 if (fPixelRef) {
michael@0 1578 if (fPixelRef->getFactory()) {
michael@0 1579 buffer.writeInt(SERIALIZE_PIXELTYPE_REF_DATA);
michael@0 1580 buffer.writeInt(fPixelRefOrigin.fX);
michael@0 1581 buffer.writeInt(fPixelRefOrigin.fY);
michael@0 1582 buffer.writeFlattenable(fPixelRef);
michael@0 1583 return;
michael@0 1584 }
michael@0 1585 // if we get here, we can't record the pixels
michael@0 1586 buffer.writeInt(SERIALIZE_PIXELTYPE_NONE);
michael@0 1587 } else {
michael@0 1588 buffer.writeInt(SERIALIZE_PIXELTYPE_NONE);
michael@0 1589 }
michael@0 1590 }
michael@0 1591
michael@0 1592 void SkBitmap::unflatten(SkReadBuffer& buffer) {
michael@0 1593 this->reset();
michael@0 1594
michael@0 1595 SkImageInfo info;
michael@0 1596 info.unflatten(buffer);
michael@0 1597 size_t rowBytes = buffer.readInt();
michael@0 1598 if (!buffer.validate((info.width() >= 0) && (info.height() >= 0) &&
michael@0 1599 SkColorTypeIsValid(info.fColorType) &&
michael@0 1600 SkAlphaTypeIsValid(info.fAlphaType) &&
michael@0 1601 validate_alphaType(info.fColorType, info.fAlphaType) &&
michael@0 1602 info.validRowBytes(rowBytes))) {
michael@0 1603 return;
michael@0 1604 }
michael@0 1605
michael@0 1606 bool configIsValid = this->setConfig(info, rowBytes);
michael@0 1607 buffer.validate(configIsValid);
michael@0 1608
michael@0 1609 int reftype = buffer.readInt();
michael@0 1610 if (buffer.validate((SERIALIZE_PIXELTYPE_REF_DATA == reftype) ||
michael@0 1611 (SERIALIZE_PIXELTYPE_NONE == reftype))) {
michael@0 1612 switch (reftype) {
michael@0 1613 case SERIALIZE_PIXELTYPE_REF_DATA: {
michael@0 1614 SkIPoint origin;
michael@0 1615 origin.fX = buffer.readInt();
michael@0 1616 origin.fY = buffer.readInt();
michael@0 1617 size_t offset = origin.fY * rowBytes + origin.fX * info.bytesPerPixel();
michael@0 1618 SkPixelRef* pr = buffer.readPixelRef();
michael@0 1619 if (!buffer.validate((NULL == pr) ||
michael@0 1620 (pr->getAllocatedSizeInBytes() >= (offset + this->getSafeSize())))) {
michael@0 1621 origin.setZero();
michael@0 1622 }
michael@0 1623 SkSafeUnref(this->setPixelRef(pr, origin));
michael@0 1624 break;
michael@0 1625 }
michael@0 1626 case SERIALIZE_PIXELTYPE_NONE:
michael@0 1627 break;
michael@0 1628 default:
michael@0 1629 SkDEBUGFAIL("unrecognized pixeltype in serialized data");
michael@0 1630 sk_throw();
michael@0 1631 }
michael@0 1632 }
michael@0 1633 }
michael@0 1634
michael@0 1635 ///////////////////////////////////////////////////////////////////////////////
michael@0 1636
michael@0 1637 SkBitmap::RLEPixels::RLEPixels(int width, int height) {
michael@0 1638 fHeight = height;
michael@0 1639 fYPtrs = (uint8_t**)sk_calloc_throw(height * sizeof(uint8_t*));
michael@0 1640 }
michael@0 1641
michael@0 1642 SkBitmap::RLEPixels::~RLEPixels() {
michael@0 1643 sk_free(fYPtrs);
michael@0 1644 }
michael@0 1645
michael@0 1646 ///////////////////////////////////////////////////////////////////////////////
michael@0 1647
michael@0 1648 #ifdef SK_DEBUG
michael@0 1649 void SkBitmap::validate() const {
michael@0 1650 fInfo.validate();
michael@0 1651
michael@0 1652 // ImageInfo may not require this, but Bitmap ensures that opaque-only
michael@0 1653 // colorTypes report opaque for their alphatype
michael@0 1654 if (kRGB_565_SkColorType == fInfo.colorType()) {
michael@0 1655 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
michael@0 1656 }
michael@0 1657
michael@0 1658 SkASSERT(fInfo.validRowBytes(fRowBytes));
michael@0 1659 uint8_t allFlags = kImageIsOpaque_Flag | kImageIsVolatile_Flag | kImageIsImmutable_Flag;
michael@0 1660 #ifdef SK_BUILD_FOR_ANDROID
michael@0 1661 allFlags |= kHasHardwareMipMap_Flag;
michael@0 1662 #endif
michael@0 1663 SkASSERT(fFlags <= allFlags);
michael@0 1664 SkASSERT(fPixelLockCount >= 0);
michael@0 1665
michael@0 1666 if (fPixels) {
michael@0 1667 SkASSERT(fPixelRef);
michael@0 1668 SkASSERT(fPixelLockCount > 0);
michael@0 1669 SkASSERT(fPixelRef->isLocked());
michael@0 1670 SkASSERT(fPixelRef->rowBytes() == fRowBytes);
michael@0 1671 SkASSERT(fPixelRefOrigin.fX >= 0);
michael@0 1672 SkASSERT(fPixelRefOrigin.fY >= 0);
michael@0 1673 SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX);
michael@0 1674 SkASSERT(fPixelRef->info().fHeight >= (int)this->height() + fPixelRefOrigin.fY);
michael@0 1675 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
michael@0 1676 } else {
michael@0 1677 SkASSERT(NULL == fColorTable);
michael@0 1678 }
michael@0 1679 }
michael@0 1680 #endif
michael@0 1681
michael@0 1682 #ifndef SK_IGNORE_TO_STRING
michael@0 1683 void SkBitmap::toString(SkString* str) const {
michael@0 1684
michael@0 1685 static const char* gConfigNames[kConfigCount] = {
michael@0 1686 "NONE", "A8", "INDEX8", "565", "4444", "8888"
michael@0 1687 };
michael@0 1688
michael@0 1689 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
michael@0 1690 gConfigNames[this->config()]);
michael@0 1691
michael@0 1692 str->append(" (");
michael@0 1693 if (this->isOpaque()) {
michael@0 1694 str->append("opaque");
michael@0 1695 } else {
michael@0 1696 str->append("transparent");
michael@0 1697 }
michael@0 1698 if (this->isImmutable()) {
michael@0 1699 str->append(", immutable");
michael@0 1700 } else {
michael@0 1701 str->append(", not-immutable");
michael@0 1702 }
michael@0 1703 str->append(")");
michael@0 1704
michael@0 1705 SkPixelRef* pr = this->pixelRef();
michael@0 1706 if (NULL == pr) {
michael@0 1707 // show null or the explicit pixel address (rare)
michael@0 1708 str->appendf(" pixels:%p", this->getPixels());
michael@0 1709 } else {
michael@0 1710 const char* uri = pr->getURI();
michael@0 1711 if (NULL != uri) {
michael@0 1712 str->appendf(" uri:\"%s\"", uri);
michael@0 1713 } else {
michael@0 1714 str->appendf(" pixelref:%p", pr);
michael@0 1715 }
michael@0 1716 }
michael@0 1717
michael@0 1718 str->append(")");
michael@0 1719 }
michael@0 1720 #endif
michael@0 1721
michael@0 1722 ///////////////////////////////////////////////////////////////////////////////
michael@0 1723
michael@0 1724 #ifdef SK_DEBUG
michael@0 1725 void SkImageInfo::validate() const {
michael@0 1726 SkASSERT(fWidth >= 0);
michael@0 1727 SkASSERT(fHeight >= 0);
michael@0 1728 SkASSERT(SkColorTypeIsValid(fColorType));
michael@0 1729 SkASSERT(SkAlphaTypeIsValid(fAlphaType));
michael@0 1730 }
michael@0 1731 #endif

mercurial