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(nullptr)
     21     , fDiscardableMemoryIsLocked(false)
     22 {
     23     SkASSERT(fGenerator != nullptr);
     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     delete fDiscardableMemory;
     37     SkSafeUnref(fDMFactory);
     38     delete fGenerator;
     39 }
     40 
     41 bool SkDiscardablePixelRef::onNewLockPixels(LockRec* rec) {
     42     if (fDiscardableMemory != nullptr) {
     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         delete fDiscardableMemory;
     51         fDiscardableMemory = nullptr;
     52         fDiscardableMemoryIsLocked = false;
     53     }
     54 
     55     const size_t size = this->info().getSafeSize(fRowBytes);
     56 
     57     if (fDMFactory != nullptr) {
     58         fDiscardableMemory = fDMFactory->create(size);
     59         fDiscardableMemoryIsLocked = true;
     60     } else {
     61         fDiscardableMemory = SkDiscardableMemory::Create(size);
     62         fDiscardableMemoryIsLocked = true;
     63     }
     64     if (nullptr == 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     if (!fGenerator->getPixels(info, pixels, fRowBytes, colors, &colorCount)) {
     75         fDiscardableMemory->unlock();
     76         fDiscardableMemoryIsLocked = false;
     77         delete fDiscardableMemory;
     78         fDiscardableMemory = nullptr;
     79         return false;
     80     }
     81 
     82     // Note: our ctable is not purgeable, as it is not stored in the discardablememory block.
     83     // This is because SkColorTable is refcntable, and therefore our caller could hold onto it
     84     // beyond the scope of a lock/unlock. If we change the API/lifecycle for SkColorTable, we
     85     // could move it into the block, but then again perhaps it is small enough that this doesn't
     86     // really matter.
     87     if (colorCount > 0) {
     88         fCTable.reset(new SkColorTable(colors, colorCount));
     89     } else {
     90         fCTable.reset(nullptr);
     91     }
     92 
     93     rec->fPixels = pixels;
     94     rec->fColorTable = fCTable.get();
     95     rec->fRowBytes = fRowBytes;
     96     return true;
     97 }
     98 
     99 void SkDiscardablePixelRef::onUnlockPixels() {
    100     fDiscardableMemory->unlock();
    101     fDiscardableMemoryIsLocked = false;
    102 }
    103 
    104 bool SkDEPRECATED_InstallDiscardablePixelRef(SkImageGenerator* generator, const SkIRect* subset,
    105                                              SkBitmap* dst, SkDiscardableMemory::Factory* factory) {
    106     SkAutoTDelete<SkImageGenerator> autoGenerator(generator);
    107     if (nullptr == autoGenerator.get()) {
    108         return false;
    109     }
    110 
    111     SkImageInfo prInfo = autoGenerator->getInfo();
    112     if (prInfo.isEmpty()) {
    113         return false;
    114     }
    115 
    116     SkIPoint origin = SkIPoint::Make(0, 0);
    117     SkImageInfo bmInfo = prInfo;
    118     if (subset) {
    119         const SkIRect prBounds = SkIRect::MakeWH(prInfo.width(), prInfo.height());
    120         if (subset->isEmpty() || !prBounds.contains(*subset)) {
    121             return false;
    122         }
    123         bmInfo = prInfo.makeWH(subset->width(), subset->height());
    124         origin.set(subset->x(), subset->y());
    125     }
    126 
    127     // must compute our desired rowBytes w.r.t. the pixelRef's dimensions, not ours, which may be
    128     // smaller.
    129     if (!dst->setInfo(bmInfo, prInfo.minRowBytes())) {
    130         return false;
    131     }
    132 
    133     // Since dst->setInfo() may have changed/fixed-up info, we check from the bitmap
    134     SkASSERT(dst->info().colorType() != kUnknown_SkColorType);
    135 
    136     if (dst->empty()) {  // Use a normal pixelref.
    137         return dst->tryAllocPixels();
    138     }
    139     SkAutoTUnref<SkDiscardablePixelRef> ref(
    140             new SkDiscardablePixelRef(prInfo, autoGenerator.detach(), dst->rowBytes(), factory));
    141     dst->setPixelRef(ref, origin.x(), origin.y());
    142     return true;
    143 }
    144 
    145 // These are the public API
    146 
    147 bool SkDEPRECATED_InstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst) {
    148     return SkDEPRECATED_InstallDiscardablePixelRef(generator, nullptr, dst, nullptr);
    149 }
    150 
    151 bool SkDEPRECATED_InstallDiscardablePixelRef(SkData* encoded, SkBitmap* dst) {
    152     SkImageGenerator* generator = SkImageGenerator::NewFromEncoded(encoded);
    153     return generator ?
    154             SkDEPRECATED_InstallDiscardablePixelRef(generator, nullptr, dst, nullptr) : false;
    155 }
    156