| 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 "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| 11 #include "SkData.h" | 11 #include "SkData.h" |
| 12 #include "SkIcoCodec.h" | 12 #include "SkIcoCodec.h" |
| 13 #include "SkPngCodec.h" | 13 #include "SkPngCodec.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 | |
| 55 /* | 18 /* |
| 56 * Checks the start of the stream to see if the image is an Ico or Cur | 19 * Checks the start of the stream to see if the image is an Ico or Cur |
| 57 */ | 20 */ |
| 58 bool SkIcoCodec::IsIco(const void* buffer, size_t bytesRead) { | 21 bool SkIcoCodec::IsIco(const void* buffer, size_t bytesRead) { |
| 59 const char icoSig[] = { '\x00', '\x00', '\x01', '\x00' }; | 22 const char icoSig[] = { '\x00', '\x00', '\x01', '\x00' }; |
| 60 const char curSig[] = { '\x00', '\x00', '\x02', '\x00' }; | 23 const char curSig[] = { '\x00', '\x00', '\x02', '\x00' }; |
| 61 return bytesRead >= sizeof(icoSig) && | 24 return bytesRead >= sizeof(icoSig) && |
| 62 (!memcmp(buffer, icoSig, sizeof(icoSig)) || | 25 (!memcmp(buffer, icoSig, sizeof(icoSig)) || |
| 63 !memcmp(buffer, curSig, sizeof(curSig))); | 26 !memcmp(buffer, curSig, sizeof(curSig))); |
| 64 } | 27 } |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 for (int32_t i = 0; i < codecs->count(); i++) { | 163 for (int32_t i = 0; i < codecs->count(); i++) { |
| 201 SkImageInfo info = codecs->operator[](i)->getInfo(); | 164 SkImageInfo info = codecs->operator[](i)->getInfo(); |
| 202 uint32_t size = info.width() * info.height(); | 165 uint32_t size = info.width() * info.height(); |
| 203 if (size > maxSize) { | 166 if (size > maxSize) { |
| 204 maxSize = size; | 167 maxSize = size; |
| 205 maxIndex = i; | 168 maxIndex = i; |
| 206 } | 169 } |
| 207 } | 170 } |
| 208 SkImageInfo info = codecs->operator[](maxIndex)->getInfo(); | 171 SkImageInfo info = codecs->operator[](maxIndex)->getInfo(); |
| 209 | 172 |
| 210 // ICOs contain an alpha mask after the image which means we cannot | |
| 211 // guarantee that an image is opaque, even if the sub-codec thinks it | |
| 212 // is. | |
| 213 // FIXME (msarett): The BMP decoder depends on the alpha type in order | |
| 214 // to decode correctly, otherwise it could report kUnpremul and we would | |
| 215 // not have to correct it here. Is there a better way? | |
| 216 // FIXME (msarett): This is only true for BMP in ICO - could a PNG in ICO | |
| 217 // be opaque? Is it okay that we missed out on the opportunity to mark | |
| 218 // such an image as opaque? | |
| 219 info = info.makeAlphaType(kUnpremul_SkAlphaType); | |
| 220 | |
| 221 // Note that stream is owned by the embedded codec, the ico does not need | 173 // Note that stream is owned by the embedded codec, the ico does not need |
| 222 // direct access to the stream. | 174 // direct access to the stream. |
| 223 return new SkIcoCodec(info, codecs.detach()); | 175 return new SkIcoCodec(info, codecs.detach()); |
| 224 } | 176 } |
| 225 | 177 |
| 226 /* | 178 /* |
| 227 * Creates an instance of the decoder | 179 * Creates an instance of the decoder |
| 228 * Called only by NewFromStream | 180 * Called only by NewFromStream |
| 229 */ | 181 */ |
| 230 SkIcoCodec::SkIcoCodec(const SkImageInfo& info, | 182 SkIcoCodec::SkIcoCodec(const SkImageInfo& info, |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 */ | 235 */ |
| 284 SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo, | 236 SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo, |
| 285 void* dst, size_t dstRowBytes, | 237 void* dst, size_t dstRowBytes, |
| 286 const Options& opts, SkPMColor* colorTab
le, | 238 const Options& opts, SkPMColor* colorTab
le, |
| 287 int* colorCount, int* rowsDecoded) { | 239 int* colorCount, int* rowsDecoded) { |
| 288 if (opts.fSubset) { | 240 if (opts.fSubset) { |
| 289 // Subsets are not supported. | 241 // Subsets are not supported. |
| 290 return kUnimplemented; | 242 return kUnimplemented; |
| 291 } | 243 } |
| 292 | 244 |
| 293 if (!ico_conversion_possible(dstInfo)) { | |
| 294 return kInvalidConversion; | |
| 295 } | |
| 296 | |
| 297 int index = 0; | 245 int index = 0; |
| 298 SkCodec::Result result = kInvalidScale; | 246 SkCodec::Result result = kInvalidScale; |
| 299 while (true) { | 247 while (true) { |
| 300 index = this->chooseCodec(dstInfo.dimensions(), index); | 248 index = this->chooseCodec(dstInfo.dimensions(), index); |
| 301 if (index < 0) { | 249 if (index < 0) { |
| 302 break; | 250 break; |
| 303 } | 251 } |
| 304 | 252 |
| 305 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); | 253 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); |
| 306 SkImageInfo decodeInfo = fix_embedded_alpha(dstInfo, embeddedCodec->getI
nfo().alphaType()); | 254 result = embeddedCodec->getPixels(dstInfo, dst, dstRowBytes, &opts, colo
rTable, |
| 307 SkASSERT(decodeInfo.colorType() == kN32_SkColorType); | |
| 308 result = embeddedCodec->getPixels(decodeInfo, dst, dstRowBytes, &opts, c
olorTable, | |
| 309 colorCount); | 255 colorCount); |
| 310 | 256 |
| 311 switch (result) { | 257 switch (result) { |
| 312 case kSuccess: | 258 case kSuccess: |
| 313 case kIncompleteInput: | 259 case kIncompleteInput: |
| 314 // The embedded codec will handle filling incomplete images, so
we will indicate | 260 // The embedded codec will handle filling incomplete images, so
we will indicate |
| 315 // that all of the rows are initialized. | 261 // that all of the rows are initialized. |
| 316 *rowsDecoded = decodeInfo.height(); | 262 *rowsDecoded = dstInfo.height(); |
| 317 return result; | 263 return result; |
| 318 default: | 264 default: |
| 319 // Continue trying to find a valid embedded codec on a failed de
code. | 265 // Continue trying to find a valid embedded codec on a failed de
code. |
| 320 break; | 266 break; |
| 321 } | 267 } |
| 322 | 268 |
| 323 index++; | 269 index++; |
| 324 } | 270 } |
| 325 | 271 |
| 326 SkCodecPrintf("Error: No matching candidate image in ico.\n"); | 272 SkCodecPrintf("Error: No matching candidate image in ico.\n"); |
| 327 return result; | 273 return result; |
| 328 } | 274 } |
| 329 | 275 |
| 330 SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, | 276 SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, |
| 331 const SkCodec::Options& options, SkPMColor colorTable[], int* colorCount
) { | 277 const SkCodec::Options& options, SkPMColor colorTable[], int* colorCount
) { |
| 332 if (!ico_conversion_possible(dstInfo)) { | |
| 333 return kInvalidConversion; | |
| 334 } | |
| 335 | |
| 336 int index = 0; | 278 int index = 0; |
| 337 SkCodec::Result result = kInvalidScale; | 279 SkCodec::Result result = kInvalidScale; |
| 338 while (true) { | 280 while (true) { |
| 339 index = this->chooseCodec(dstInfo.dimensions(), index); | 281 index = this->chooseCodec(dstInfo.dimensions(), index); |
| 340 if (index < 0) { | 282 if (index < 0) { |
| 341 break; | 283 break; |
| 342 } | 284 } |
| 343 | 285 |
| 344 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); | 286 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); |
| 345 SkImageInfo decodeInfo = fix_embedded_alpha(dstInfo, embeddedCodec->getI
nfo().alphaType()); | 287 result = embeddedCodec->startScanlineDecode(dstInfo, &options, colorTabl
e, colorCount); |
| 346 result = embeddedCodec->startScanlineDecode(decodeInfo, &options, colorT
able, colorCount); | |
| 347 if (kSuccess == result) { | 288 if (kSuccess == result) { |
| 348 fCurrScanlineCodec = embeddedCodec; | 289 fCurrScanlineCodec = embeddedCodec; |
| 349 return result; | 290 return result; |
| 350 } | 291 } |
| 351 | 292 |
| 352 index++; | 293 index++; |
| 353 } | 294 } |
| 354 | 295 |
| 355 SkCodecPrintf("Error: No matching candidate image in ico.\n"); | 296 SkCodecPrintf("Error: No matching candidate image in ico.\n"); |
| 356 return result; | 297 return result; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 369 SkCodec::SkScanlineOrder SkIcoCodec::onGetScanlineOrder() const { | 310 SkCodec::SkScanlineOrder SkIcoCodec::onGetScanlineOrder() const { |
| 370 // FIXME: This function will possibly return the wrong value if it is called | 311 // FIXME: This function will possibly return the wrong value if it is called |
| 371 // before startScanlineDecode(). | 312 // before startScanlineDecode(). |
| 372 return fCurrScanlineCodec ? fCurrScanlineCodec->getScanlineOrder() : | 313 return fCurrScanlineCodec ? fCurrScanlineCodec->getScanlineOrder() : |
| 373 INHERITED::onGetScanlineOrder(); | 314 INHERITED::onGetScanlineOrder(); |
| 374 } | 315 } |
| 375 | 316 |
| 376 SkSampler* SkIcoCodec::getSampler(bool createIfNecessary) { | 317 SkSampler* SkIcoCodec::getSampler(bool createIfNecessary) { |
| 377 return fCurrScanlineCodec ? fCurrScanlineCodec->getSampler(createIfNecessary
) : nullptr; | 318 return fCurrScanlineCodec ? fCurrScanlineCodec->getSampler(createIfNecessary
) : nullptr; |
| 378 } | 319 } |
| OLD | NEW |