| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  * Copyright 2015 Google Inc. | 2  * Copyright 2015 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 "SkBmpCodec.h" | 8 #include "SkBmpCodec.h" | 
| 9 #include "SkCodec_libico.h" | 9 #include "SkCodec_libico.h" | 
| 10 #include "SkCodec_libpng.h" | 10 #include "SkCodec_libpng.h" | 
| 11 #include "SkCodecPriv.h" | 11 #include "SkCodecPriv.h" | 
| 12 #include "SkColorPriv.h" | 12 #include "SkColorPriv.h" | 
| 13 #include "SkData.h" | 13 #include "SkData.h" | 
| 14 #include "SkStream.h" | 14 #include "SkStream.h" | 
| 15 #include "SkTDArray.h" | 15 #include "SkTDArray.h" | 
| 16 #include "SkTSort.h" | 16 #include "SkTSort.h" | 
| 17 | 17 | 
|  | 18 static bool ico_conversion_possible(const SkImageInfo& dstInfo) { | 
|  | 19     // We only support kN32_SkColorType. | 
|  | 20     // This makes sense for BMP-in-ICO.  The presence of an AND | 
|  | 21     // mask (which changes colors and adds transparency) means that | 
|  | 22     // we cannot use k565 or kIndex8. | 
|  | 23     // FIXME: For PNG-in-ICO, we could technically support whichever | 
|  | 24     //        color types that the png supports. | 
|  | 25     if (kN32_SkColorType != dstInfo.colorType()) { | 
|  | 26         return false; | 
|  | 27     } | 
|  | 28 | 
|  | 29     // We only support transparent alpha types.  This is necessary for | 
|  | 30     // BMP-in-ICOs since there will be an AND mask. | 
|  | 31     // FIXME: For opaque PNG-in-ICOs, we should be able to support kOpaque. | 
|  | 32     return kPremul_SkAlphaType == dstInfo.alphaType() || | 
|  | 33             kUnpremul_SkAlphaType == dstInfo.alphaType(); | 
|  | 34 } | 
|  | 35 | 
|  | 36 static SkImageInfo fix_embedded_alpha(const SkImageInfo& dstInfo, SkAlphaType em
     beddedAlpha) { | 
|  | 37     // FIXME (msarett): ICO is considered non-opaque, even if the embedded BMP | 
|  | 38     // incorrectly claims it has no alpha. | 
|  | 39     switch (embeddedAlpha) { | 
|  | 40         case kPremul_SkAlphaType: | 
|  | 41         case kUnpremul_SkAlphaType: | 
|  | 42             // Use the requested alpha type if the embedded codec supports alpha
     . | 
|  | 43             embeddedAlpha = dstInfo.alphaType(); | 
|  | 44             break; | 
|  | 45         case kOpaque_SkAlphaType: | 
|  | 46             // If the embedded codec claims it is opaque, decode as if it is opa
     que. | 
|  | 47             break; | 
|  | 48         default: | 
|  | 49             SkASSERT(false); | 
|  | 50             break; | 
|  | 51     } | 
|  | 52     return dstInfo.makeAlphaType(embeddedAlpha); | 
|  | 53 } | 
|  | 54 | 
| 18 /* | 55 /* | 
| 19  * Checks the start of the stream to see if the image is an Ico or Cur | 56  * Checks the start of the stream to see if the image is an Ico or Cur | 
| 20  */ | 57  */ | 
| 21 bool SkIcoCodec::IsIco(SkStream* stream) { | 58 bool SkIcoCodec::IsIco(SkStream* stream) { | 
| 22     const char icoSig[] = { '\x00', '\x00', '\x01', '\x00' }; | 59     const char icoSig[] = { '\x00', '\x00', '\x01', '\x00' }; | 
| 23     const char curSig[] = { '\x00', '\x00', '\x02', '\x00' }; | 60     const char curSig[] = { '\x00', '\x00', '\x02', '\x00' }; | 
| 24     char buffer[sizeof(icoSig)]; | 61     char buffer[sizeof(icoSig)]; | 
| 25     return stream->read(buffer, sizeof(icoSig)) == sizeof(icoSig) && | 62     return stream->read(buffer, sizeof(icoSig)) == sizeof(icoSig) && | 
| 26             (!memcmp(buffer, icoSig, sizeof(icoSig)) || | 63             (!memcmp(buffer, icoSig, sizeof(icoSig)) || | 
| 27             !memcmp(buffer, curSig, sizeof(curSig))); | 64             !memcmp(buffer, curSig, sizeof(curSig))); | 
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 190 } | 227 } | 
| 191 | 228 | 
| 192 /* | 229 /* | 
| 193  * Creates an instance of the decoder | 230  * Creates an instance of the decoder | 
| 194  * Called only by NewFromStream | 231  * Called only by NewFromStream | 
| 195  */ | 232  */ | 
| 196 SkIcoCodec::SkIcoCodec(const SkImageInfo& info, | 233 SkIcoCodec::SkIcoCodec(const SkImageInfo& info, | 
| 197                        SkTArray<SkAutoTDelete<SkCodec>, true>* codecs) | 234                        SkTArray<SkAutoTDelete<SkCodec>, true>* codecs) | 
| 198     : INHERITED(info, nullptr) | 235     : INHERITED(info, nullptr) | 
| 199     , fEmbeddedCodecs(codecs) | 236     , fEmbeddedCodecs(codecs) | 
|  | 237     , fCurrScanlineCodec(nullptr) | 
| 200 {} | 238 {} | 
| 201 | 239 | 
| 202 /* | 240 /* | 
| 203  * Chooses the best dimensions given the desired scale | 241  * Chooses the best dimensions given the desired scale | 
| 204  */ | 242  */ | 
| 205 SkISize SkIcoCodec::onGetScaledDimensions(float desiredScale) const { | 243 SkISize SkIcoCodec::onGetScaledDimensions(float desiredScale) const { | 
| 206     // We set the dimensions to the largest candidate image by default. | 244     // We set the dimensions to the largest candidate image by default. | 
| 207     // Regardless of the scale request, this is the largest image that we | 245     // Regardless of the scale request, this is the largest image that we | 
| 208     // will decode. | 246     // will decode. | 
| 209     int origWidth = this->getInfo().width(); | 247     int origWidth = this->getInfo().width(); | 
| 210     int origHeight = this->getInfo().height(); | 248     int origHeight = this->getInfo().height(); | 
| 211     float desiredSize = desiredScale * origWidth * origHeight; | 249     float desiredSize = desiredScale * origWidth * origHeight; | 
| 212     // At least one image will have smaller error than this initial value | 250     // At least one image will have smaller error than this initial value | 
| 213     float minError = ((float) (origWidth * origHeight)) - desiredSize + 1.0f; | 251     float minError = ((float) (origWidth * origHeight)) - desiredSize + 1.0f; | 
| 214     int32_t minIndex = -1; | 252     int32_t minIndex = -1; | 
| 215     for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) { | 253     for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) { | 
| 216         int width = fEmbeddedCodecs->operator[](i)->getInfo().width(); | 254         int width = fEmbeddedCodecs->operator[](i)->getInfo().width(); | 
| 217         int height = fEmbeddedCodecs->operator[](i)->getInfo().height(); | 255         int height = fEmbeddedCodecs->operator[](i)->getInfo().height(); | 
| 218         float error = SkTAbs(((float) (width * height)) - desiredSize); | 256         float error = SkTAbs(((float) (width * height)) - desiredSize); | 
| 219         if (error < minError) { | 257         if (error < minError) { | 
| 220             minError = error; | 258             minError = error; | 
| 221             minIndex = i; | 259             minIndex = i; | 
| 222         } | 260         } | 
| 223     } | 261     } | 
| 224     SkASSERT(minIndex >= 0); | 262     SkASSERT(minIndex >= 0); | 
| 225 | 263 | 
| 226     return fEmbeddedCodecs->operator[](minIndex)->getInfo().dimensions(); | 264     return fEmbeddedCodecs->operator[](minIndex)->getInfo().dimensions(); | 
| 227 } | 265 } | 
| 228 | 266 | 
| 229 bool SkIcoCodec::onDimensionsSupported(const SkISize& dim) { | 267 int SkIcoCodec::chooseCodec(const SkISize& requestedSize, int startIndex) { | 
|  | 268     SkASSERT(startIndex >= 0); | 
|  | 269 | 
| 230     // FIXME: Cache the index from onGetScaledDimensions? | 270     // FIXME: Cache the index from onGetScaledDimensions? | 
| 231     for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) { | 271     for (int i = startIndex; i < fEmbeddedCodecs->count(); i++) { | 
| 232         if (fEmbeddedCodecs->operator[](i)->getInfo().dimensions() == dim) { | 272         if (fEmbeddedCodecs->operator[](i)->getInfo().dimensions() == requestedS
     ize) { | 
| 233             return true; | 273             return i; | 
| 234         } | 274         } | 
| 235     } | 275     } | 
| 236 | 276 | 
| 237     return false; | 277     return -1; | 
|  | 278 } | 
|  | 279 | 
|  | 280 bool SkIcoCodec::onDimensionsSupported(const SkISize& dim) { | 
|  | 281     return this->chooseCodec(dim, 0) >= 0; | 
| 238 } | 282 } | 
| 239 | 283 | 
| 240 /* | 284 /* | 
| 241  * Initiates the Ico decode | 285  * Initiates the Ico decode | 
| 242  */ | 286  */ | 
| 243 SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo, | 287 SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo, | 
| 244                                         void* dst, size_t dstRowBytes, | 288                                         void* dst, size_t dstRowBytes, | 
| 245                                         const Options& opts, SkPMColor* colorTab
     le, | 289                                         const Options& opts, SkPMColor* colorTab
     le, | 
| 246                                         int* colorCount, int* rowsDecoded) { | 290                                         int* colorCount, int* rowsDecoded) { | 
| 247     if (opts.fSubset) { | 291     if (opts.fSubset) { | 
| 248         // Subsets are not supported. | 292         // Subsets are not supported. | 
| 249         return kUnimplemented; | 293         return kUnimplemented; | 
| 250     } | 294     } | 
| 251 | 295 | 
| 252     if (!valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType())) { | 296     if (!ico_conversion_possible(dstInfo)) { | 
| 253         return kInvalidConversion; | 297         return kInvalidConversion; | 
| 254     } | 298     } | 
| 255 | 299 | 
| 256     // We return invalid scale if there is no candidate image with matching | 300     int index = 0; | 
| 257     // dimensions. | 301     SkCodec::Result result = kInvalidScale; | 
| 258     Result result = kInvalidScale; | 302     while (true) { | 
| 259     for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) { | 303         index = this->chooseCodec(dstInfo.dimensions(), index); | 
| 260         SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](i); | 304         if (index < 0) { | 
| 261         // If the dimensions match, try to decode | 305             break; | 
| 262         if (dstInfo.dimensions() == embeddedCodec->getInfo().dimensions()) { | 306         } | 
| 263 | 307 | 
| 264             // Perform the decode | 308         SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); | 
| 265             // FIXME (msarett): ICO is considered non-opaque, even if the embedd
     ed BMP | 309         SkImageInfo decodeInfo = fix_embedded_alpha(dstInfo, embeddedCodec->getI
     nfo().alphaType()); | 
| 266             // incorrectly claims it has no alpha. | 310         SkASSERT(decodeInfo.colorType() == kN32_SkColorType); | 
| 267             SkAlphaType embeddedAlpha = embeddedCodec->getInfo().alphaType(); | 311         result = embeddedCodec->getPixels(decodeInfo, dst, dstRowBytes, &opts, c
     olorTable, | 
| 268             switch (embeddedAlpha) { | 312                 colorCount); | 
| 269                 case kPremul_SkAlphaType: |  | 
| 270                 case kUnpremul_SkAlphaType: |  | 
| 271                     // Use the requested alpha type if the embedded codec suppor
     ts alpha. |  | 
| 272                     embeddedAlpha = dstInfo.alphaType(); |  | 
| 273                     break; |  | 
| 274                 case kOpaque_SkAlphaType: |  | 
| 275                     // If the embedded codec claims it is opaque, decode as if i
     t is opaque. |  | 
| 276                     break; |  | 
| 277                 default: |  | 
| 278                     SkASSERT(false); |  | 
| 279                     break; |  | 
| 280             } |  | 
| 281             SkImageInfo info = dstInfo.makeAlphaType(embeddedAlpha); |  | 
| 282             result = embeddedCodec->getPixels(info, dst, dstRowBytes, &opts, col
     orTable, |  | 
| 283                     colorCount); |  | 
| 284             // The embedded codec will handle filling incomplete images, so we w
     ill indicate |  | 
| 285             // that all of the rows are initialized. |  | 
| 286             *rowsDecoded = info.height(); |  | 
| 287 | 313 | 
| 288             // On a fatal error, keep trying to find an image to decode | 314         switch (result) { | 
| 289             if (kInvalidConversion == result || kInvalidInput == result || | 315             case kSuccess: | 
| 290                     kInvalidScale == result) { | 316             case kIncompleteInput: | 
| 291                 SkCodecPrintf("Warning: Attempt to decode candidate ico failed.\
     n"); | 317                 // The embedded codec will handle filling incomplete images, so 
     we will indicate | 
| 292                 continue; | 318                 // that all of the rows are initialized. | 
| 293             } | 319                 *rowsDecoded = decodeInfo.height(); | 
|  | 320                 return result; | 
|  | 321             default: | 
|  | 322                 // Continue trying to find a valid embedded codec on a failed de
     code. | 
|  | 323                 break; | 
|  | 324         } | 
| 294 | 325 | 
| 295             // On success or partial success, return the result | 326         index++; | 
| 296             return result; |  | 
| 297         } |  | 
| 298     } | 327     } | 
| 299 | 328 | 
| 300     SkCodecPrintf("Error: No matching candidate image in ico.\n"); | 329     SkCodecPrintf("Error: No matching candidate image in ico.\n"); | 
| 301     return result; | 330     return result; | 
| 302 } | 331 } | 
|  | 332 | 
|  | 333 SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, | 
|  | 334         const SkCodec::Options& options, SkPMColor colorTable[], int* colorCount
     ) { | 
|  | 335     if (!ico_conversion_possible(dstInfo)) { | 
|  | 336         return kInvalidConversion; | 
|  | 337     } | 
|  | 338 | 
|  | 339     int index = 0; | 
|  | 340     SkCodec::Result result = kInvalidScale; | 
|  | 341     while (true) { | 
|  | 342         index = this->chooseCodec(dstInfo.dimensions(), index); | 
|  | 343         if (index < 0) { | 
|  | 344             break; | 
|  | 345         } | 
|  | 346 | 
|  | 347         SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); | 
|  | 348         SkImageInfo decodeInfo = fix_embedded_alpha(dstInfo, embeddedCodec->getI
     nfo().alphaType()); | 
|  | 349         result = embeddedCodec->startScanlineDecode(decodeInfo, &options, colorT
     able, colorCount); | 
|  | 350         if (kSuccess == result) { | 
|  | 351             fCurrScanlineCodec = embeddedCodec; | 
|  | 352             return result; | 
|  | 353         } | 
|  | 354 | 
|  | 355         index++; | 
|  | 356     } | 
|  | 357 | 
|  | 358     SkCodecPrintf("Error: No matching candidate image in ico.\n"); | 
|  | 359     return result; | 
|  | 360 } | 
|  | 361 | 
|  | 362 int SkIcoCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { | 
|  | 363     SkASSERT(fCurrScanlineCodec); | 
|  | 364     return fCurrScanlineCodec->getScanlines(dst, count, rowBytes); | 
|  | 365 } | 
|  | 366 | 
|  | 367 bool SkIcoCodec::onSkipScanlines(int count) { | 
|  | 368     SkASSERT(fCurrScanlineCodec); | 
|  | 369     return fCurrScanlineCodec->skipScanlines(count); | 
|  | 370 } | 
|  | 371 | 
|  | 372 SkCodec::SkScanlineOrder SkIcoCodec::onGetScanlineOrder() const { | 
|  | 373     // FIXME: This function will possibly return the wrong value if it is called | 
|  | 374     //        before startScanlineDecode(). | 
|  | 375     return fCurrScanlineCodec ? fCurrScanlineCodec->getScanlineOrder() : | 
|  | 376             INHERITED::onGetScanlineOrder(); | 
|  | 377 } | 
|  | 378 | 
|  | 379 SkSampler* SkIcoCodec::getSampler(bool createIfNecessary) { | 
|  | 380     return fCurrScanlineCodec ? fCurrScanlineCodec->getSampler(createIfNecessary
     ) : nullptr; | 
|  | 381 } | 
| OLD | NEW | 
|---|