Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2014 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 "SkImage.h"
      9 #include "SkImageGenerator.h"
     10 #include "SkNextID.h"
     11 
     12 SkImageGenerator::SkImageGenerator(const SkImageInfo& info, uint32_t uniqueID)
     13     : fInfo(info)
     14     , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID)
     15 {}
     16 
     17 bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
     18                                  SkPMColor ctable[], int* ctableCount) {
     19     if (kUnknown_SkColorType == info.colorType()) {
     20         return false;
     21     }
     22     if (nullptr == pixels) {
     23         return false;
     24     }
     25     if (rowBytes < info.minRowBytes()) {
     26         return false;
     27     }
     28 
     29     if (kIndex_8_SkColorType == info.colorType()) {
     30         if (nullptr == ctable || nullptr == ctableCount) {
     31             return false;
     32         }
     33     } else {
     34         if (ctableCount) {
     35             *ctableCount = 0;
     36         }
     37         ctableCount = nullptr;
     38         ctable = nullptr;
     39     }
     40 
     41     const bool success = this->onGetPixels(info, pixels, rowBytes, ctable, ctableCount);
     42     if (success && ctableCount) {
     43         SkASSERT(*ctableCount >= 0 && *ctableCount <= 256);
     44     }
     45     return success;
     46 }
     47 
     48 bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
     49     SkASSERT(kIndex_8_SkColorType != info.colorType());
     50     if (kIndex_8_SkColorType == info.colorType()) {
     51         return false;
     52     }
     53     return this->getPixels(info, pixels, rowBytes, nullptr, nullptr);
     54 }
     55 
     56 bool SkImageGenerator::queryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const {
     57     SkASSERT(sizeInfo);
     58 
     59     return this->onQueryYUV8(sizeInfo, colorSpace);
     60 }
     61 
     62 bool SkImageGenerator::getYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
     63     SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth >= 0);
     64     SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight >= 0);
     65     SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU].fWidth >= 0);
     66     SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight >= 0);
     67     SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kV].fWidth >= 0);
     68     SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kV].fHeight >= 0);
     69     SkASSERT(sizeInfo.fWidthBytes[SkYUVSizeInfo::kY] >=
     70             (size_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth);
     71     SkASSERT(sizeInfo.fWidthBytes[SkYUVSizeInfo::kU] >=
     72             (size_t) sizeInfo.fSizes[SkYUVSizeInfo::kU].fWidth);
     73     SkASSERT(sizeInfo.fWidthBytes[SkYUVSizeInfo::kV] >=
     74             (size_t) sizeInfo.fSizes[SkYUVSizeInfo::kV].fWidth);
     75     SkASSERT(planes && planes[0] && planes[1] && planes[2]);
     76 
     77     return this->onGetYUV8Planes(sizeInfo, planes);
     78 }
     79 
     80 #if SK_SUPPORT_GPU
     81 #include "GrTextureProxy.h"
     82 
     83 sk_sp<GrTextureProxy> SkImageGenerator::generateTexture(GrContext* ctx, const SkImageInfo& info,
     84                                                         const SkIPoint& origin) {
     85     SkIRect srcRect = SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height());
     86     if (!SkIRect::MakeWH(fInfo.width(), fInfo.height()).contains(srcRect)) {
     87         return nullptr;
     88     }
     89     return this->onGenerateTexture(ctx, info, origin);
     90 }
     91 
     92 sk_sp<GrTextureProxy> SkImageGenerator::onGenerateTexture(GrContext*, const SkImageInfo&,
     93                                                           const SkIPoint&) {
     94     return nullptr;
     95 }
     96 #endif
     97 
     98 /////////////////////////////////////////////////////////////////////////////////////////////
     99 
    100 SkData* SkImageGenerator::onRefEncodedData(GrContext* ctx) {
    101     return nullptr;
    102 }
    103 
    104 bool SkImageGenerator::onGetPixels(const SkImageInfo& info, void* dst, size_t rb,
    105                                    SkPMColor* colors, int* colorCount) {
    106     return false;
    107 }
    108 
    109 ///////////////////////////////////////////////////////////////////////////////////////////////////
    110 
    111 #include "SkBitmap.h"
    112 #include "SkColorTable.h"
    113 
    114 static bool reset_and_return_false(SkBitmap* bitmap) {
    115     bitmap->reset();
    116     return false;
    117 }
    118 
    119 bool SkImageGenerator::tryGenerateBitmap(SkBitmap* bitmap, const SkImageInfo& info,
    120                                          SkBitmap::Allocator* allocator) {
    121     if (0 == info.getSafeSize(info.minRowBytes())) {
    122         return false;
    123     }
    124     if (!bitmap->setInfo(info)) {
    125         return reset_and_return_false(bitmap);
    126     }
    127 
    128     SkPMColor ctStorage[256];
    129     memset(ctStorage, 0xFF, sizeof(ctStorage)); // init with opaque-white for the moment
    130     sk_sp<SkColorTable> ctable(new SkColorTable(ctStorage, 256));
    131     if (!bitmap->tryAllocPixels(allocator, ctable.get())) {
    132         // SkResourceCache's custom allcator can'thandle ctables, so it may fail on
    133         // kIndex_8_SkColorTable.
    134         // https://bug.skia.org/4355
    135 #if 1
    136         // ignore the allocator, and see if we can succeed without it
    137         if (!bitmap->tryAllocPixels(nullptr, ctable.get())) {
    138             return reset_and_return_false(bitmap);
    139         }
    140 #else
    141         // this is the up-scale technique, not fully debugged, but we keep it here at the moment
    142         // to remind ourselves that this might be better than ignoring the allocator.
    143 
    144         info = SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType());
    145         if (!bitmap->setInfo(info)) {
    146             return reset_and_return_false(bitmap);
    147         }
    148         // we pass nullptr for the ctable arg, since we are now explicitly N32
    149         if (!bitmap->tryAllocPixels(allocator, nullptr)) {
    150             return reset_and_return_false(bitmap);
    151         }
    152 #endif
    153     }
    154 
    155     bitmap->lockPixels();
    156     if (!bitmap->getPixels()) {
    157         return reset_and_return_false(bitmap);
    158     }
    159 
    160     int ctCount = 0;
    161     if (!this->getPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(),
    162                          ctStorage, &ctCount)) {
    163         return reset_and_return_false(bitmap);
    164     }
    165 
    166     if (ctCount > 0) {
    167         SkASSERT(kIndex_8_SkColorType == bitmap->colorType());
    168         // we and bitmap should be owners
    169         SkASSERT(!ctable->unique());
    170 
    171         // Now we need to overwrite the ctable we built earlier, with the correct colors.
    172         // This does mean that we may have made the table too big, but that cannot be avoided
    173         // until we can change SkImageGenerator's API to return us the ctable *before* we have to
    174         // allocate space for all the pixels.
    175         ctable->dangerous_overwriteColors(ctStorage, ctCount);
    176     } else {
    177         SkASSERT(kIndex_8_SkColorType != bitmap->colorType());
    178         // we should be the only owner
    179         SkASSERT(ctable->unique());
    180     }
    181     return true;
    182 }
    183 
    184 #include "SkGraphics.h"
    185 
    186 static SkGraphics::ImageGeneratorFromEncodedDataFactory gFactory;
    187 
    188 SkGraphics::ImageGeneratorFromEncodedDataFactory
    189 SkGraphics::SetImageGeneratorFromEncodedDataFactory(ImageGeneratorFromEncodedDataFactory factory)
    190 {
    191     ImageGeneratorFromEncodedDataFactory prev = gFactory;
    192     gFactory = factory;
    193     return prev;
    194 }
    195 
    196 std::unique_ptr<SkImageGenerator> SkImageGenerator::MakeFromEncoded(sk_sp<SkData> data) {
    197     if (!data) {
    198         return nullptr;
    199     }
    200     if (gFactory) {
    201         if (std::unique_ptr<SkImageGenerator> generator = gFactory(data)) {
    202             return generator;
    203         }
    204     }
    205     return SkImageGenerator::MakeFromEncodedImpl(std::move(data));
    206 }
    207