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

changeset 0
6474c204b198
     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

mercurial