Home | History | Annotate | Download | only in lazy
      1 /*
      2  * Copyright 2013 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkDiscardablePixelRef.h"
      9 #include "SkDiscardableMemory.h"
     10 #include "SkImageGenerator.h"
     11 
     12 SkDiscardablePixelRef::SkDiscardablePixelRef(const SkImageInfo& info,
     13                                              SkImageGenerator* generator,
     14                                              size_t rowBytes,
     15                                              SkDiscardableMemory::Factory* fact)
     16     : INHERITED(info)
     17     , fGenerator(generator)
     18     , fDMFactory(fact)
     19     , fRowBytes(rowBytes)
     20     , fDiscardableMemory(NULL)
     21     , fDiscardableMemoryIsLocked(false)
     22 {
     23     SkASSERT(fGenerator != NULL);
     24     SkASSERT(fRowBytes > 0);
     25     // The SkImageGenerator contract requires fGenerator to always
     26     // decode the same image on each call to getPixels().
     27     this->setImmutable();
     28     SkSafeRef(fDMFactory);
     29 }
     30 
     31 SkDiscardablePixelRef::~SkDiscardablePixelRef() {
     32     if (fDiscardableMemoryIsLocked) {
     33         fDiscardableMemory->unlock();
     34         fDiscardableMemoryIsLocked = false;
     35     }
     36     SkDELETE(fDiscardableMemory);
     37     SkSafeUnref(fDMFactory);
     38     SkDELETE(fGenerator);
     39 }
     40 
     41 bool SkDiscardablePixelRef::onNewLockPixels(LockRec* rec) {
     42     if (fDiscardableMemory != NULL) {
     43         if (fDiscardableMemory->lock()) {
     44             fDiscardableMemoryIsLocked = true;
     45             rec->fPixels = fDiscardableMemory->data();
     46             rec->fColorTable = fCTable.get();
     47             rec->fRowBytes = fRowBytes;
     48             return true;
     49         }
     50         SkDELETE(fDiscardableMemory);
     51         fDiscardableMemory = NULL;
     52         fDiscardableMemoryIsLocked = false;
     53     }
     54 
     55     const size_t size = this->info().getSafeSize(fRowBytes);
     56 
     57     if (fDMFactory != NULL) {
     58         fDiscardableMemory = fDMFactory->create(size);
     59         fDiscardableMemoryIsLocked = true;
     60     } else {
     61         fDiscardableMemory = SkDiscardableMemory::Create(size);
     62         fDiscardableMemoryIsLocked = true;
     63     }
     64     if (NULL == fDiscardableMemory) {
     65         fDiscardableMemoryIsLocked = false;
     66         return false;  // Memory allocation failed.
     67     }
     68 
     69     void* pixels = fDiscardableMemory->data();
     70     const SkImageInfo& info = this->info();
     71     SkPMColor colors[256];
     72     int colorCount = 0;
     73 
     74     const SkImageGenerator::Result result = fGenerator->getPixels(info, pixels, fRowBytes, NULL,
     75                                                                   colors, &colorCount);
     76     switch (result) {
     77         case SkImageGenerator::kSuccess:
     78         case SkImageGenerator::kIncompleteInput:
     79             break;
     80         default:
     81             fDiscardableMemory->unlock();
     82             fDiscardableMemoryIsLocked = false;
     83             SkDELETE(fDiscardableMemory);
     84             fDiscardableMemory = NULL;
     85             return false;
     86     }
     87 
     88     // Note: our ctable is not purgeable, as it is not stored in the discardablememory block.
     89     // This is because SkColorTable is refcntable, and therefore our caller could hold onto it
     90     // beyond the scope of a lock/unlock. If we change the API/lifecycle for SkColorTable, we
     91     // could move it into the block, but then again perhaps it is small enough that this doesn't
     92     // really matter.
     93     if (colorCount > 0) {
     94         fCTable.reset(SkNEW_ARGS(SkColorTable, (colors, colorCount)));
     95     } else {
     96         fCTable.reset(NULL);
     97     }
     98 
     99     rec->fPixels = pixels;
    100     rec->fColorTable = fCTable.get();
    101     rec->fRowBytes = fRowBytes;
    102     return true;
    103 }
    104 
    105 void SkDiscardablePixelRef::onUnlockPixels() {
    106     fDiscardableMemory->unlock();
    107     fDiscardableMemoryIsLocked = false;
    108 }
    109 
    110 bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst,
    111                                   SkDiscardableMemory::Factory* factory) {
    112     SkAutoTDelete<SkImageGenerator> autoGenerator(generator);
    113     if (NULL == autoGenerator.get()) {
    114         return false;
    115     }
    116     SkImageInfo info = autoGenerator->getInfo();
    117     if (info.isEmpty() || !dst->setInfo(info)) {
    118         return false;
    119     }
    120     // Since dst->setInfo() may have changed/fixed-up info, we copy it back from that bitmap
    121     info = dst->info();
    122 
    123     SkASSERT(info.colorType() != kUnknown_SkColorType);
    124     if (dst->empty()) {  // Use a normal pixelref.
    125         return dst->tryAllocPixels();
    126     }
    127     SkAutoTUnref<SkDiscardablePixelRef> ref(
    128         SkNEW_ARGS(SkDiscardablePixelRef,
    129                    (info, autoGenerator.detach(), dst->rowBytes(), factory)));
    130     dst->setPixelRef(ref);
    131     return true;
    132 }
    133 
    134 // These are the public API
    135 
    136 bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst) {
    137     return SkInstallDiscardablePixelRef(generator, dst, NULL);
    138 }
    139 
    140 bool SkInstallDiscardablePixelRef(SkData* encoded, SkBitmap* dst) {
    141     SkImageGenerator* generator = SkImageGenerator::NewFromData(encoded);
    142     return generator ? SkInstallDiscardablePixelRef(generator, dst, NULL) : false;
    143 }
    144