| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  * Copyright 2013 Google Inc. | 2  * Copyright 2013 Google Inc. | 
| 3  * | 3  * | 
| 4  * Use of this source code is governed by a BSD-style license that can be | 4  * Use of this source code is governed by a BSD-style license that can be | 
| 5  * found in the LICENSE file. | 5  * found in the LICENSE file. | 
| 6  */ | 6  */ | 
| 7 | 7 | 
|  | 8 #include "SkData.h" | 
| 8 #include "SkDecodingImageGenerator.h" | 9 #include "SkDecodingImageGenerator.h" | 
| 9 #include "SkData.h" |  | 
| 10 #include "SkImageDecoder.h" | 10 #include "SkImageDecoder.h" | 
|  | 11 #include "SkImageInfo.h" | 
| 11 #include "SkImageGenerator.h" | 12 #include "SkImageGenerator.h" | 
| 12 #include "SkImagePriv.h" | 13 #include "SkImagePriv.h" | 
| 13 #include "SkStream.h" | 14 #include "SkStream.h" | 
| 14 | 15 #include "SkUtils.h" | 
| 15 | 16 | 
| 16 namespace { | 17 namespace { | 
| 17 /** | 18 /** | 
| 18  *  Special allocator used by getPixels(). Uses preallocated memory | 19  *  Special allocator used by getPixels(). Uses preallocated memory | 
| 19  *  provided. | 20  *  provided. | 
| 20  */ | 21  */ | 
| 21 class TargetAllocator : public SkBitmap::Allocator { | 22 class TargetAllocator : public SkBitmap::Allocator { | 
| 22 public: | 23 public: | 
| 23     TargetAllocator(void* target, size_t rowBytes, const SkImageInfo& info) | 24     TargetAllocator(void* target, | 
|  | 25                     size_t rowBytes, | 
|  | 26                     int width, | 
|  | 27                     int height, | 
|  | 28                     SkBitmap::Config config) | 
| 24         : fTarget(target) | 29         : fTarget(target) | 
| 25         , fRowBytes(rowBytes) | 30         , fRowBytes(rowBytes) | 
| 26         , fInfo(info) { } | 31         , fWidth(width) | 
|  | 32         , fHeight(height) | 
|  | 33         , fConfig(config) { } | 
| 27 | 34 | 
| 28     virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE { | 35     bool isReady() { return (fTarget != NULL); } | 
| 29         if ((SkImageInfoToBitmapConfig(fInfo) != bm->config()) | 36 | 
| 30             || (bm->width() != fInfo.fWidth) | 37     virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) { | 
| 31             || (bm->height() != fInfo.fHeight)) { | 38         if ((NULL == fTarget) | 
| 32             return false; | 39             || (fConfig != bm->config()) | 
|  | 40             || (fWidth != bm->width()) | 
|  | 41             || (fHeight != bm->height()) | 
|  | 42             || (ct != NULL)) { | 
|  | 43             // Call default allocator. | 
|  | 44             return bm->allocPixels(NULL, ct); | 
| 33         } | 45         } | 
| 34         bm->setConfig(bm->config(), bm->width(), bm->height(), | 46         // make sure fRowBytes is correct. | 
| 35                       fRowBytes, bm->alphaType()); | 47         bm->setConfig(fConfig, fWidth, fHeight, fRowBytes, bm->alphaType()); | 
| 36         bm->setPixels(fTarget, ct); | 48         // TODO(halcanary): verify that all callers of this function | 
|  | 49         // will respect new RowBytes.  Will be moot once rowbytes belongs | 
|  | 50         // to PixelRef. | 
|  | 51         bm->setPixels(fTarget, NULL); | 
|  | 52         fTarget = NULL;  // never alloc same pixels twice! | 
| 37         return true; | 53         return true; | 
| 38     } | 54     } | 
| 39 | 55 | 
| 40 private: | 56 private: | 
| 41     void* fTarget; | 57     void* fTarget;  // Block of memory to be supplied as pixel memory | 
| 42     size_t fRowBytes; | 58                     // in allocPixelRef.  Must be large enough to hold | 
| 43     SkImageInfo fInfo; | 59                     // a bitmap described by fWidth, fHeight, and | 
|  | 60                     // fRowBytes. | 
|  | 61     size_t fRowBytes;  // rowbytes for the destination bitmap | 
|  | 62     int fWidth;   // Along with fHeight and fConfig, the information | 
|  | 63     int fHeight;  // about the bitmap whose pixels this allocator is | 
|  | 64                   // expected to allocate. If they do not match the | 
|  | 65                   // bitmap passed to allocPixelRef, it is assumed | 
|  | 66                   // that the bitmap will be copied to a bitmap with | 
|  | 67                   // the correct info using this allocator, so the | 
|  | 68                   // default allocator will be used instead of | 
|  | 69                   // fTarget. | 
|  | 70     SkBitmap::Config fConfig; | 
| 44     typedef SkBitmap::Allocator INHERITED; | 71     typedef SkBitmap::Allocator INHERITED; | 
| 45 }; | 72 }; | 
|  | 73 | 
|  | 74 // TODO(halcanary): Give this macro a better name and move it into SkTypes.h | 
|  | 75 #ifdef SK_DEBUG | 
|  | 76     #define SkCheckResult(expr, value)  SkASSERT((value) == (expr)) | 
|  | 77 #else | 
|  | 78     #define SkCheckResult(expr, value)  (void)(expr) | 
|  | 79 #endif | 
|  | 80 | 
|  | 81 #ifdef SK_DEBUG | 
|  | 82 inline bool check_alpha(SkAlphaType reported, SkAlphaType actual) { | 
|  | 83     return ((reported == actual) | 
|  | 84             || ((reported == kPremul_SkAlphaType) | 
|  | 85                 && (actual == kOpaque_SkAlphaType))); | 
|  | 86 } | 
|  | 87 #endif  // SK_DEBUG | 
|  | 88 | 
| 46 }  // namespace | 89 }  // namespace | 
| 47 //////////////////////////////////////////////////////////////////////////////// | 90 //////////////////////////////////////////////////////////////////////////////// | 
| 48 | 91 | 
| 49 SkDecodingImageGenerator::SkDecodingImageGenerator(SkData* data) | 92 SkDecodingImageGenerator::SkDecodingImageGenerator( | 
|  | 93         SkData* data, | 
|  | 94         SkStreamRewindable* stream, | 
|  | 95         const SkImageInfo& info, | 
|  | 96         int sampleSize, | 
|  | 97         bool ditherImage, | 
|  | 98         SkBitmap::Config requestedConfig) | 
| 50     : fData(data) | 99     : fData(data) | 
| 51     , fHasInfo(false) |  | 
| 52     , fDoCopyTo(false) { |  | 
| 53     SkASSERT(fData != NULL); |  | 
| 54     fStream = SkNEW_ARGS(SkMemoryStream, (fData)); |  | 
| 55     SkASSERT(fStream != NULL); |  | 
| 56     SkASSERT(fStream->unique()); |  | 
| 57     fData->ref(); |  | 
| 58 } |  | 
| 59 |  | 
| 60 SkDecodingImageGenerator::SkDecodingImageGenerator(SkStreamRewindable* stream) |  | 
| 61     : fData(NULL) |  | 
| 62     , fStream(stream) | 100     , fStream(stream) | 
| 63     , fHasInfo(false) | 101     , fInfo(info) | 
| 64     , fDoCopyTo(false) { | 102     , fSampleSize(sampleSize) | 
| 65     SkASSERT(fStream != NULL); | 103     , fDitherImage(ditherImage) | 
| 66     SkASSERT(fStream->unique()); | 104     , fRequestedConfig(requestedConfig) { | 
|  | 105     SkASSERT(stream != NULL); | 
|  | 106     SkSafeRef(fData);  // may be NULL. | 
| 67 } | 107 } | 
| 68 | 108 | 
| 69 SkDecodingImageGenerator::~SkDecodingImageGenerator() { | 109 SkDecodingImageGenerator::~SkDecodingImageGenerator() { | 
| 70     SkSafeUnref(fData); | 110     SkSafeUnref(fData); | 
| 71     fStream->unref(); | 111     fStream->unref(); | 
| 72 } | 112 } | 
| 73 | 113 | 
| 74 // TODO(halcanary): Give this macro a better name and move it into SkTypes.h | 114 bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) { | 
| 75 #ifdef SK_DEBUG | 115     if (info != NULL) { | 
| 76     #define SkCheckResult(expr, value)  SkASSERT((value) == (expr)) | 116         *info = fInfo; | 
| 77 #else | 117     } | 
| 78     #define SkCheckResult(expr, value)  (void)(expr) | 118     return true; | 
| 79 #endif | 119 } | 
| 80 | 120 | 
| 81 SkData* SkDecodingImageGenerator::refEncodedData() { | 121 SkData* SkDecodingImageGenerator::refEncodedData() { | 
| 82     // This functionality is used in `gm --serialize` | 122     // This functionality is used in `gm --serialize` | 
|  | 123     // Does not encode options. | 
| 83     if (fData != NULL) { | 124     if (fData != NULL) { | 
| 84         return SkSafeRef(fData); | 125         return SkSafeRef(fData); | 
| 85     } | 126     } | 
| 86     // TODO(halcanary): SkStreamRewindable needs a refData() function | 127     // TODO(halcanary): SkStreamRewindable needs a refData() function | 
| 87     // which returns a cheap copy of the underlying data. | 128     // which returns a cheap copy of the underlying data. | 
| 88     if (!fStream->rewind()) { | 129     if (!fStream->rewind()) { | 
| 89         return NULL; | 130         return NULL; | 
| 90     } | 131     } | 
| 91     size_t length = fStream->getLength(); | 132     size_t length = fStream->getLength(); | 
| 92     if (0 == length) { | 133     if (0 == length) { | 
| 93         return NULL; | 134         return NULL; | 
| 94     } | 135     } | 
| 95     void* buffer = sk_malloc_flags(length, 0); | 136     void* buffer = sk_malloc_flags(length, 0); | 
| 96     SkCheckResult(fStream->read(buffer, length), length); | 137     SkCheckResult(fStream->read(buffer, length), length); | 
| 97     fData = SkData::NewFromMalloc(buffer, length); | 138     fData = SkData::NewFromMalloc(buffer, length); | 
| 98     return SkSafeRef(fData); | 139     return SkSafeRef(fData); | 
| 99 } | 140 } | 
| 100 | 141 | 
| 101 bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) { |  | 
| 102     // info can be NULL.  If so, will update fInfo, fDoCopyTo, and fHasInfo. |  | 
| 103     if (fHasInfo) { |  | 
| 104         if (info != NULL) { |  | 
| 105             *info = fInfo; |  | 
| 106         } |  | 
| 107         return true; |  | 
| 108     } |  | 
| 109     SkAssertResult(fStream->rewind()); |  | 
| 110     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream)); |  | 
| 111     if (NULL == decoder.get()) { |  | 
| 112         return false; |  | 
| 113     } |  | 
| 114     SkBitmap bitmap; |  | 
| 115     if (!decoder->decode(fStream, &bitmap, |  | 
| 116                          SkImageDecoder::kDecodeBounds_Mode)) { |  | 
| 117         return false; |  | 
| 118     } |  | 
| 119     if (bitmap.config() == SkBitmap::kNo_Config) { |  | 
| 120         return false; |  | 
| 121     } |  | 
| 122     if (!bitmap.asImageInfo(&fInfo)) { |  | 
| 123         // We can't use bitmap.config() as is. |  | 
| 124         if (!bitmap.canCopyTo(SkBitmap::kARGB_8888_Config)) { |  | 
| 125             SkDEBUGFAIL("!bitmap->canCopyTo(SkBitmap::kARGB_8888_Config)"); |  | 
| 126             return false; |  | 
| 127         } |  | 
| 128         fDoCopyTo = true; |  | 
| 129         fInfo.fWidth = bitmap.width(); |  | 
| 130         fInfo.fHeight = bitmap.height(); |  | 
| 131         fInfo.fColorType = kPMColor_SkColorType; |  | 
| 132         fInfo.fAlphaType = bitmap.alphaType(); |  | 
| 133     } |  | 
| 134     if (info != NULL) { |  | 
| 135         *info = fInfo; |  | 
| 136     } |  | 
| 137     fHasInfo = true; |  | 
| 138     return true; |  | 
| 139 } |  | 
| 140 |  | 
| 141 bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info, | 142 bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info, | 
| 142                                          void* pixels, | 143                                          void* pixels, | 
| 143                                          size_t rowBytes) { | 144                                          size_t rowBytes) { | 
| 144     if (NULL == pixels) { | 145     if (NULL == pixels) { | 
| 145         return false; | 146         return false; | 
| 146     } | 147     } | 
| 147     if (!this->getInfo(NULL)) { | 148     if (fInfo != info) { | 
|  | 149         // The caller has specified a different info.  This is an | 
|  | 150         // error for this kind of SkImageGenerator.  Use the Options | 
|  | 151         // to change the settings. | 
| 148         return false; | 152         return false; | 
| 149     } | 153     } | 
| 150     if (SkImageInfoToBitmapConfig(info) == SkBitmap::kNo_Config) { | 154     int bpp = SkBitmap::ComputeBytesPerPixel(fRequestedConfig); | 
| 151         return false;  // Unsupported SkColorType. | 155     if (static_cast<size_t>(bpp * info.fWidth) > rowBytes) { | 
|  | 156         // The caller has specified a bad rowBytes. | 
|  | 157         return false; | 
| 152     } | 158     } | 
|  | 159 | 
| 153     SkAssertResult(fStream->rewind()); | 160     SkAssertResult(fStream->rewind()); | 
| 154     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream)); | 161     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream)); | 
| 155     if (NULL == decoder.get()) { | 162     if (NULL == decoder.get()) { | 
| 156         return false; | 163         return false; | 
| 157     } | 164     } | 
| 158     if (fInfo != info) { | 165     decoder->setDitherImage(fDitherImage); | 
| 159         // The caller has specified a different info.  For now, this | 166     decoder->setSampleSize(fSampleSize); | 
| 160         // is an error.  In the future, we will check to see if we can | 167 | 
| 161         // convert. |  | 
| 162         return false; |  | 
| 163     } |  | 
| 164     int bpp = SkBitmap::ComputeBytesPerPixel(SkImageInfoToBitmapConfig(info)); |  | 
| 165     if (static_cast<size_t>(bpp * info.fWidth) > rowBytes) { |  | 
| 166         return false; |  | 
| 167     } |  | 
| 168     SkBitmap bitmap; | 168     SkBitmap bitmap; | 
| 169     if (!bitmap.setConfig(info, rowBytes)) { | 169     TargetAllocator allocator(pixels, rowBytes, info.fWidth, | 
| 170         return false; | 170                               info.fHeight, fRequestedConfig); | 
| 171     } | 171     decoder->setAllocator(&allocator); | 
| 172 | 172     bool success = decoder->decode(fStream, &bitmap, fRequestedConfig, | 
| 173     TargetAllocator allocator(pixels, rowBytes, info); |  | 
| 174     if (!fDoCopyTo) { |  | 
| 175         decoder->setAllocator(&allocator); |  | 
| 176     } |  | 
| 177     bool success = decoder->decode(fStream, &bitmap, |  | 
| 178                                    SkImageDecoder::kDecodePixels_Mode); | 173                                    SkImageDecoder::kDecodePixels_Mode); | 
| 179     decoder->setAllocator(NULL); | 174     decoder->setAllocator(NULL); | 
| 180     if (!success) { | 175     if (!success) { | 
| 181         return false; | 176         return false; | 
| 182     } | 177     } | 
| 183     if (fDoCopyTo) { | 178     if (allocator.isReady()) {  // Did not use pixels! | 
| 184         SkBitmap bm8888; | 179         SkBitmap bm; | 
| 185         bitmap.copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator); | 180         SkASSERT(bitmap.canCopyTo(fRequestedConfig)); | 
|  | 181         if (!bitmap.copyTo(&bm, fRequestedConfig, &allocator) | 
|  | 182             || allocator.isReady()) { | 
|  | 183             SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed."); | 
|  | 184             // Earlier we checked canCopyto(); we expect consistency. | 
|  | 185             return false; | 
|  | 186         } | 
|  | 187         SkASSERT(check_alpha(fInfo.fAlphaType, bm.alphaType())); | 
|  | 188     } else { | 
|  | 189         SkASSERT(check_alpha(fInfo.fAlphaType, bitmap.alphaType())); | 
| 186     } | 190     } | 
| 187     return true; | 191     return true; | 
| 188 } | 192 } | 
| 189 bool SkDecodingImageGenerator::Install(SkData* data, SkBitmap* dst, | 193 | 
| 190                                        SkDiscardableMemory::Factory* factory) { | 194 SkImageGenerator* SkDecodingImageGenerator::Create( | 
|  | 195         SkData* data, | 
|  | 196         const SkDecodingImageGenerator::Options& opts) { | 
| 191     SkASSERT(data != NULL); | 197     SkASSERT(data != NULL); | 
| 192     SkASSERT(dst != NULL); | 198     if (NULL == data) { | 
| 193     SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (data))); | 199         return NULL; | 
| 194     return SkInstallDiscardablePixelRef(gen, dst, factory); | 200     } | 
|  | 201     SkStreamRewindable* stream = SkNEW_ARGS(SkMemoryStream, (data)); | 
|  | 202     SkASSERT(stream != NULL); | 
|  | 203     SkASSERT(stream->unique()); | 
|  | 204     return SkDecodingImageGenerator::Create(data, stream, opts); | 
| 195 } | 205 } | 
| 196 | 206 | 
| 197 bool SkDecodingImageGenerator::Install(SkStreamRewindable* stream, | 207 SkImageGenerator* SkDecodingImageGenerator::Create( | 
| 198                                        SkBitmap* dst, | 208         SkStreamRewindable* stream, | 
| 199                                        SkDiscardableMemory::Factory* factory) { | 209         const SkDecodingImageGenerator::Options& opts) { | 
| 200     SkASSERT(stream != NULL); | 210     SkASSERT(stream != NULL); | 
| 201     SkASSERT(dst != NULL); | 211     SkASSERT(stream->unique()); | 
| 202     if ((stream == NULL) || !stream->unique()) { | 212     if ((stream == NULL) || !stream->unique()) { | 
| 203         SkSafeUnref(stream); | 213         SkSafeUnref(stream); | 
| 204         return false; | 214         return NULL; | 
| 205     } | 215     } | 
| 206     SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (stream))); | 216     return SkDecodingImageGenerator::Create(NULL, stream, opts); | 
| 207     return SkInstallDiscardablePixelRef(gen, dst, factory); |  | 
| 208 } | 217 } | 
|  | 218 | 
|  | 219 // A contructor-type function that returns NULL on failure.  This | 
|  | 220 // prevents the returned SkImageGenerator from ever being in a bad | 
|  | 221 // state.  Called by both Create() functions | 
|  | 222 SkImageGenerator* SkDecodingImageGenerator::Create( | 
|  | 223         SkData* data, | 
|  | 224         SkStreamRewindable* stream, | 
|  | 225         const SkDecodingImageGenerator::Options& opts) { | 
|  | 226     SkASSERT(stream); | 
|  | 227     SkAutoTUnref<SkStreamRewindable> autoStream(stream);  // always unref this. | 
|  | 228     if (opts.fUseRequestedColorType && | 
|  | 229         (kIndex_8_SkColorType == opts.fRequestedColorType)) { | 
|  | 230         // We do not support indexed color with SkImageGenerators, | 
|  | 231         return NULL; | 
|  | 232     } | 
|  | 233     SkAssertResult(autoStream->rewind()); | 
|  | 234     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(autoStream)); | 
|  | 235     if (NULL == decoder.get()) { | 
|  | 236         return NULL; | 
|  | 237     } | 
|  | 238     SkBitmap bitmap; | 
|  | 239     decoder->setSampleSize(opts.fSampleSize); | 
|  | 240     if (!decoder->decode(stream, &bitmap, | 
|  | 241                          SkImageDecoder::kDecodeBounds_Mode)) { | 
|  | 242         return NULL; | 
|  | 243     } | 
|  | 244     if (bitmap.config() == SkBitmap::kNo_Config) { | 
|  | 245         return NULL; | 
|  | 246     } | 
|  | 247 | 
|  | 248     SkImageInfo info; | 
|  | 249     SkBitmap::Config config; | 
|  | 250 | 
|  | 251     if (!opts.fUseRequestedColorType) { | 
|  | 252         // Use default config. | 
|  | 253         if (SkBitmap::kIndex8_Config == bitmap.config()) { | 
|  | 254             // We don't support kIndex8 because we don't support | 
|  | 255             // colortables in this workflow. | 
|  | 256             config = SkBitmap::kARGB_8888_Config; | 
|  | 257             info.fWidth = bitmap.width(); | 
|  | 258             info.fHeight = bitmap.height(); | 
|  | 259             info.fColorType = kPMColor_SkColorType; | 
|  | 260             info.fAlphaType = bitmap.alphaType(); | 
|  | 261         } else { | 
|  | 262             config = bitmap.config();  // Save for later! | 
|  | 263             if (!bitmap.asImageInfo(&info)) { | 
|  | 264                 SkDEBUGFAIL("Getting SkImageInfo from bitmap failed."); | 
|  | 265                 return NULL; | 
|  | 266             } | 
|  | 267         } | 
|  | 268     } else { | 
|  | 269         config = SkColorTypeToBitmapConfig(opts.fRequestedColorType); | 
|  | 270         if (!bitmap.canCopyTo(config)) { | 
|  | 271             SkASSERT(bitmap.config() != config); | 
|  | 272             return NULL;  // Can not translate to needed config. | 
|  | 273         } | 
|  | 274         info.fWidth = bitmap.width(); | 
|  | 275         info.fHeight = bitmap.height(); | 
|  | 276         info.fColorType = opts.fRequestedColorType; | 
|  | 277         info.fAlphaType = bitmap.alphaType(); | 
|  | 278 | 
|  | 279         // Sanity check. | 
|  | 280         SkDEBUGCODE(SkColorType tmp;) | 
|  | 281         SkASSERT(SkBitmapConfigToColorType(config, &tmp)); | 
|  | 282         SkASSERT(tmp == opts.fRequestedColorType); | 
|  | 283     } | 
|  | 284     return SkNEW_ARGS(SkDecodingImageGenerator, | 
|  | 285                       (data, autoStream.detach(), info, | 
|  | 286                        opts.fSampleSize, opts.fDitherImage, config)); | 
|  | 287 } | 
| OLD | NEW | 
|---|