1 /* 2 * Copyright 2015 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 "SkBmpCodec.h" 9 #include "SkCodec.h" 10 #include "SkCodecPriv.h" 11 #include "SkColorSpace.h" 12 #include "SkData.h" 13 #include "SkFrameHolder.h" 14 #include "SkHalf.h" 15 #ifdef SK_HAS_HEIF_LIBRARY 16 #include "SkHeifCodec.h" 17 #endif 18 #include "SkIcoCodec.h" 19 #include "SkJpegCodec.h" 20 #ifdef SK_HAS_PNG_LIBRARY 21 #include "SkPngCodec.h" 22 #endif 23 #include "SkRawCodec.h" 24 #include "SkStream.h" 25 #include "SkWbmpCodec.h" 26 #include "SkWebpCodec.h" 27 #ifdef SK_HAS_WUFFS_LIBRARY 28 #include "SkWuffsCodec.h" 29 #else 30 #include "SkGifCodec.h" 31 #endif 32 33 struct DecoderProc { 34 bool (*IsFormat)(const void*, size_t); 35 std::unique_ptr<SkCodec> (*MakeFromStream)(std::unique_ptr<SkStream>, SkCodec::Result*); 36 }; 37 38 static constexpr DecoderProc gDecoderProcs[] = { 39 #ifdef SK_HAS_JPEG_LIBRARY 40 { SkJpegCodec::IsJpeg, SkJpegCodec::MakeFromStream }, 41 #endif 42 #ifdef SK_HAS_WEBP_LIBRARY 43 { SkWebpCodec::IsWebp, SkWebpCodec::MakeFromStream }, 44 #endif 45 #ifdef SK_HAS_WUFFS_LIBRARY 46 { SkWuffsCodec_IsFormat, SkWuffsCodec_MakeFromStream }, 47 #else 48 { SkGifCodec::IsGif, SkGifCodec::MakeFromStream }, 49 #endif 50 #ifdef SK_HAS_PNG_LIBRARY 51 { SkIcoCodec::IsIco, SkIcoCodec::MakeFromStream }, 52 #endif 53 { SkBmpCodec::IsBmp, SkBmpCodec::MakeFromStream }, 54 { SkWbmpCodec::IsWbmp, SkWbmpCodec::MakeFromStream }, 55 #ifdef SK_HAS_HEIF_LIBRARY 56 { SkHeifCodec::IsHeif, SkHeifCodec::MakeFromStream }, 57 #endif 58 }; 59 60 std::unique_ptr<SkCodec> SkCodec::MakeFromStream(std::unique_ptr<SkStream> stream, 61 Result* outResult, SkPngChunkReader* chunkReader) { 62 Result resultStorage; 63 if (!outResult) { 64 outResult = &resultStorage; 65 } 66 67 if (!stream) { 68 *outResult = kInvalidInput; 69 return nullptr; 70 } 71 72 constexpr size_t bytesToRead = MinBufferedBytesNeeded(); 73 74 char buffer[bytesToRead]; 75 size_t bytesRead = stream->peek(buffer, bytesToRead); 76 77 // It is also possible to have a complete image less than bytesToRead bytes 78 // (e.g. a 1 x 1 wbmp), meaning peek() would return less than bytesToRead. 79 // Assume that if bytesRead < bytesToRead, but > 0, the stream is shorter 80 // than bytesToRead, so pass that directly to the decoder. 81 // It also is possible the stream uses too small a buffer for peeking, but 82 // we trust the caller to use a large enough buffer. 83 84 if (0 == bytesRead) { 85 // TODO: After implementing peek in CreateJavaOutputStreamAdaptor.cpp, this 86 // printf could be useful to notice failures. 87 // SkCodecPrintf("Encoded image data failed to peek!\n"); 88 89 // It is possible the stream does not support peeking, but does support 90 // rewinding. 91 // Attempt to read() and pass the actual amount read to the decoder. 92 bytesRead = stream->read(buffer, bytesToRead); 93 if (!stream->rewind()) { 94 SkCodecPrintf("Encoded image data could not peek or rewind to determine format!\n"); 95 *outResult = kCouldNotRewind; 96 return nullptr; 97 } 98 } 99 100 // PNG is special, since we want to be able to supply an SkPngChunkReader. 101 // But this code follows the same pattern as the loop. 102 #ifdef SK_HAS_PNG_LIBRARY 103 if (SkPngCodec::IsPng(buffer, bytesRead)) { 104 return SkPngCodec::MakeFromStream(std::move(stream), outResult, chunkReader); 105 } else 106 #endif 107 { 108 for (DecoderProc proc : gDecoderProcs) { 109 if (proc.IsFormat(buffer, bytesRead)) { 110 return proc.MakeFromStream(std::move(stream), outResult); 111 } 112 } 113 114 #ifdef SK_CODEC_DECODES_RAW 115 // Try to treat the input as RAW if all the other checks failed. 116 return SkRawCodec::MakeFromStream(std::move(stream), outResult); 117 #endif 118 } 119 120 if (bytesRead < bytesToRead) { 121 *outResult = kIncompleteInput; 122 } else { 123 *outResult = kUnimplemented; 124 } 125 126 return nullptr; 127 } 128 129 std::unique_ptr<SkCodec> SkCodec::MakeFromData(sk_sp<SkData> data, SkPngChunkReader* reader) { 130 if (!data) { 131 return nullptr; 132 } 133 return MakeFromStream(SkMemoryStream::Make(std::move(data)), nullptr, reader); 134 } 135 136 SkCodec::SkCodec(SkEncodedInfo&& info, XformFormat srcFormat, std::unique_ptr<SkStream> stream, 137 SkEncodedOrigin origin) 138 : fEncodedInfo(std::move(info)) 139 , fSrcXformFormat(srcFormat) 140 , fStream(std::move(stream)) 141 , fNeedsRewind(false) 142 , fOrigin(origin) 143 , fDstInfo() 144 , fOptions() 145 , fCurrScanline(-1) 146 , fStartedIncrementalDecode(false) 147 {} 148 149 SkCodec::~SkCodec() {} 150 151 bool SkCodec::conversionSupported(const SkImageInfo& dst, bool srcIsOpaque, bool needsColorXform) { 152 if (!valid_alpha(dst.alphaType(), srcIsOpaque)) { 153 return false; 154 } 155 156 switch (dst.colorType()) { 157 case kRGBA_8888_SkColorType: 158 case kBGRA_8888_SkColorType: 159 return true; 160 case kRGBA_F16_SkColorType: 161 return dst.colorSpace(); 162 case kRGB_565_SkColorType: 163 return srcIsOpaque; 164 case kGray_8_SkColorType: 165 return SkEncodedInfo::kGray_Color == fEncodedInfo.color() && srcIsOpaque; 166 case kAlpha_8_SkColorType: 167 // conceptually we can convert anything into alpha_8, but we haven't actually coded 168 // all of those other conversions yet. 169 return SkEncodedInfo::kXAlpha_Color == fEncodedInfo.color(); 170 default: 171 return false; 172 } 173 } 174 175 bool SkCodec::rewindIfNeeded() { 176 // Store the value of fNeedsRewind so we can update it. Next read will 177 // require a rewind. 178 const bool needsRewind = fNeedsRewind; 179 fNeedsRewind = true; 180 if (!needsRewind) { 181 return true; 182 } 183 184 // startScanlineDecode will need to be called before decoding scanlines. 185 fCurrScanline = -1; 186 // startIncrementalDecode will need to be called before incrementalDecode. 187 fStartedIncrementalDecode = false; 188 189 // Some codecs do not have a stream. They may hold onto their own data or another codec. 190 // They must handle rewinding themselves. 191 if (fStream && !fStream->rewind()) { 192 return false; 193 } 194 195 return this->onRewind(); 196 } 197 198 bool zero_rect(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes, 199 SkISize srcDimensions, SkIRect prevRect) { 200 const auto dimensions = dstInfo.dimensions(); 201 if (dimensions != srcDimensions) { 202 SkRect src = SkRect::Make(srcDimensions); 203 SkRect dst = SkRect::Make(dimensions); 204 SkMatrix map = SkMatrix::MakeRectToRect(src, dst, SkMatrix::kCenter_ScaleToFit); 205 SkRect asRect = SkRect::Make(prevRect); 206 if (!map.mapRect(&asRect)) { 207 return false; 208 } 209 asRect.roundIn(&prevRect); 210 if (prevRect.isEmpty()) { 211 // Down-scaling shrank the empty portion to nothing, 212 // so nothing to zero. 213 return true; 214 } 215 } 216 217 if (!prevRect.intersect(dstInfo.bounds())) { 218 SkCodecPrintf("rectangles do not intersect!"); 219 SkASSERT(false); 220 return true; 221 } 222 223 const SkImageInfo info = dstInfo.makeWH(prevRect.width(), prevRect.height()); 224 const size_t bpp = dstInfo.bytesPerPixel(); 225 const size_t offset = prevRect.x() * bpp + prevRect.y() * rowBytes; 226 void* eraseDst = SkTAddOffset<void>(pixels, offset); 227 SkSampler::Fill(info, eraseDst, rowBytes, SkCodec::kNo_ZeroInitialized); 228 return true; 229 } 230 231 SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels, size_t rowBytes, 232 const Options& options) { 233 const int index = options.fFrameIndex; 234 if (0 == index) { 235 return this->initializeColorXform(info, fEncodedInfo.alpha(), fEncodedInfo.opaque()) 236 ? kSuccess : kInvalidConversion; 237 } 238 239 if (index < 0) { 240 return kInvalidParameters; 241 } 242 243 if (options.fSubset) { 244 // If we add support for this, we need to update the code that zeroes 245 // a kRestoreBGColor frame. 246 return kInvalidParameters; 247 } 248 249 if (index >= this->onGetFrameCount()) { 250 return kIncompleteInput; 251 } 252 253 const auto* frameHolder = this->getFrameHolder(); 254 SkASSERT(frameHolder); 255 256 const auto* frame = frameHolder->getFrame(index); 257 SkASSERT(frame); 258 259 const int requiredFrame = frame->getRequiredFrame(); 260 if (requiredFrame != kNoFrame) { 261 if (options.fPriorFrame != kNoFrame) { 262 // Check for a valid frame as a starting point. Alternatively, we could 263 // treat an invalid frame as not providing one, but rejecting it will 264 // make it easier to catch the mistake. 265 if (options.fPriorFrame < requiredFrame || options.fPriorFrame >= index) { 266 return kInvalidParameters; 267 } 268 const auto* prevFrame = frameHolder->getFrame(options.fPriorFrame); 269 switch (prevFrame->getDisposalMethod()) { 270 case SkCodecAnimation::DisposalMethod::kRestorePrevious: 271 return kInvalidParameters; 272 case SkCodecAnimation::DisposalMethod::kRestoreBGColor: 273 // If a frame after the required frame is provided, there is no 274 // need to clear, since it must be covered by the desired frame. 275 if (options.fPriorFrame == requiredFrame) { 276 SkIRect prevRect = prevFrame->frameRect(); 277 if (!zero_rect(info, pixels, rowBytes, this->dimensions(), prevRect)) { 278 return kInternalError; 279 } 280 } 281 break; 282 default: 283 break; 284 } 285 } else { 286 Options prevFrameOptions(options); 287 prevFrameOptions.fFrameIndex = requiredFrame; 288 prevFrameOptions.fZeroInitialized = kNo_ZeroInitialized; 289 const Result result = this->getPixels(info, pixels, rowBytes, &prevFrameOptions); 290 if (result != kSuccess) { 291 return result; 292 } 293 const auto* prevFrame = frameHolder->getFrame(requiredFrame); 294 const auto disposalMethod = prevFrame->getDisposalMethod(); 295 if (disposalMethod == SkCodecAnimation::DisposalMethod::kRestoreBGColor) { 296 auto prevRect = prevFrame->frameRect(); 297 if (!zero_rect(info, pixels, rowBytes, this->dimensions(), prevRect)) { 298 return kInternalError; 299 } 300 } 301 } 302 } 303 304 return this->initializeColorXform(info, frame->reportedAlpha(), !frame->hasAlpha()) 305 ? kSuccess : kInvalidConversion; 306 } 307 308 SkCodec::Result SkCodec::getPixels(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes, 309 const Options* options) { 310 SkImageInfo info = dstInfo; 311 if (!info.colorSpace()) { 312 info = info.makeColorSpace(SkColorSpace::MakeSRGB()); 313 } 314 315 if (kUnknown_SkColorType == info.colorType()) { 316 return kInvalidConversion; 317 } 318 if (nullptr == pixels) { 319 return kInvalidParameters; 320 } 321 if (rowBytes < info.minRowBytes()) { 322 return kInvalidParameters; 323 } 324 325 if (!this->rewindIfNeeded()) { 326 return kCouldNotRewind; 327 } 328 329 // Default options. 330 Options optsStorage; 331 if (nullptr == options) { 332 options = &optsStorage; 333 } else { 334 if (options->fSubset) { 335 SkIRect subset(*options->fSubset); 336 if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) { 337 // FIXME: How to differentiate between not supporting subset at all 338 // and not supporting this particular subset? 339 return kUnimplemented; 340 } 341 } 342 } 343 344 const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes, 345 *options); 346 if (frameIndexResult != kSuccess) { 347 return frameIndexResult; 348 } 349 350 // FIXME: Support subsets somehow? Note that this works for SkWebpCodec 351 // because it supports arbitrary scaling/subset combinations. 352 if (!this->dimensionsSupported(info.dimensions())) { 353 return kInvalidScale; 354 } 355 356 fDstInfo = info; 357 fOptions = *options; 358 359 // On an incomplete decode, the subclass will specify the number of scanlines that it decoded 360 // successfully. 361 int rowsDecoded = 0; 362 const Result result = this->onGetPixels(info, pixels, rowBytes, *options, &rowsDecoded); 363 364 // A return value of kIncompleteInput indicates a truncated image stream. 365 // In this case, we will fill any uninitialized memory with a default value. 366 // Some subclasses will take care of filling any uninitialized memory on 367 // their own. They indicate that all of the memory has been filled by 368 // setting rowsDecoded equal to the height. 369 if ((kIncompleteInput == result || kErrorInInput == result) && rowsDecoded != info.height()) { 370 // FIXME: (skbug.com/5772) fillIncompleteImage will fill using the swizzler's width, unless 371 // there is a subset. In that case, it will use the width of the subset. From here, the 372 // subset will only be non-null in the case of SkWebpCodec, but it treats the subset 373 // differenty from the other codecs, and it needs to use the width specified by the info. 374 // Set the subset to null so SkWebpCodec uses the correct width. 375 fOptions.fSubset = nullptr; 376 this->fillIncompleteImage(info, pixels, rowBytes, options->fZeroInitialized, info.height(), 377 rowsDecoded); 378 } 379 380 return result; 381 } 382 383 SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& dstInfo, void* pixels, 384 size_t rowBytes, const SkCodec::Options* options) { 385 fStartedIncrementalDecode = false; 386 387 SkImageInfo info = dstInfo; 388 if (!info.colorSpace()) { 389 info = info.makeColorSpace(SkColorSpace::MakeSRGB()); 390 } 391 if (kUnknown_SkColorType == info.colorType()) { 392 return kInvalidConversion; 393 } 394 if (nullptr == pixels) { 395 return kInvalidParameters; 396 } 397 398 // FIXME: If the rows come after the rows of a previous incremental decode, 399 // we might be able to skip the rewind, but only the implementation knows 400 // that. (e.g. PNG will always need to rewind, since we called longjmp, but 401 // a bottom-up BMP could skip rewinding if the new rows are above the old 402 // rows.) 403 if (!this->rewindIfNeeded()) { 404 return kCouldNotRewind; 405 } 406 407 // Set options. 408 Options optsStorage; 409 if (nullptr == options) { 410 options = &optsStorage; 411 } else { 412 if (options->fSubset) { 413 SkIRect size = SkIRect::MakeSize(info.dimensions()); 414 if (!size.contains(*options->fSubset)) { 415 return kInvalidParameters; 416 } 417 418 const int top = options->fSubset->top(); 419 const int bottom = options->fSubset->bottom(); 420 if (top < 0 || top >= info.height() || top >= bottom || bottom > info.height()) { 421 return kInvalidParameters; 422 } 423 } 424 } 425 426 const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes, 427 *options); 428 if (frameIndexResult != kSuccess) { 429 return frameIndexResult; 430 } 431 432 if (!this->dimensionsSupported(info.dimensions())) { 433 return kInvalidScale; 434 } 435 436 fDstInfo = info; 437 fOptions = *options; 438 439 const Result result = this->onStartIncrementalDecode(info, pixels, rowBytes, fOptions); 440 if (kSuccess == result) { 441 fStartedIncrementalDecode = true; 442 } else if (kUnimplemented == result) { 443 // FIXME: This is temporarily necessary, until we transition SkCodec 444 // implementations from scanline decoding to incremental decoding. 445 // SkAndroidCodec will first attempt to use incremental decoding, but 446 // will fall back to scanline decoding if incremental returns 447 // kUnimplemented. rewindIfNeeded(), above, set fNeedsRewind to true 448 // (after potentially rewinding), but we do not want the next call to 449 // startScanlineDecode() to do a rewind. 450 fNeedsRewind = false; 451 } 452 return result; 453 } 454 455 456 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, 457 const SkCodec::Options* options) { 458 // Reset fCurrScanline in case of failure. 459 fCurrScanline = -1; 460 461 SkImageInfo info = dstInfo; 462 if (!info.colorSpace()) { 463 info = info.makeColorSpace(SkColorSpace::MakeSRGB()); 464 } 465 466 if (!this->rewindIfNeeded()) { 467 return kCouldNotRewind; 468 } 469 470 // Set options. 471 Options optsStorage; 472 if (nullptr == options) { 473 options = &optsStorage; 474 } else if (options->fSubset) { 475 SkIRect size = SkIRect::MakeSize(info.dimensions()); 476 if (!size.contains(*options->fSubset)) { 477 return kInvalidInput; 478 } 479 480 // We only support subsetting in the x-dimension for scanline decoder. 481 // Subsetting in the y-dimension can be accomplished using skipScanlines(). 482 if (options->fSubset->top() != 0 || options->fSubset->height() != info.height()) { 483 return kInvalidInput; 484 } 485 } 486 487 // Scanline decoding only supports decoding the first frame. 488 if (options->fFrameIndex != 0) { 489 return kUnimplemented; 490 } 491 492 // The void* dst and rowbytes in handleFrameIndex or only used for decoding prior 493 // frames, which is not supported here anyway, so it is safe to pass nullptr/0. 494 const Result frameIndexResult = this->handleFrameIndex(info, nullptr, 0, *options); 495 if (frameIndexResult != kSuccess) { 496 return frameIndexResult; 497 } 498 499 // FIXME: Support subsets somehow? 500 if (!this->dimensionsSupported(info.dimensions())) { 501 return kInvalidScale; 502 } 503 504 const Result result = this->onStartScanlineDecode(info, *options); 505 if (result != SkCodec::kSuccess) { 506 return result; 507 } 508 509 fCurrScanline = 0; 510 fDstInfo = info; 511 fOptions = *options; 512 return kSuccess; 513 } 514 515 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { 516 if (fCurrScanline < 0) { 517 return 0; 518 } 519 520 SkASSERT(!fDstInfo.isEmpty()); 521 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) { 522 return 0; 523 } 524 525 const int linesDecoded = this->onGetScanlines(dst, countLines, rowBytes); 526 if (linesDecoded < countLines) { 527 this->fillIncompleteImage(this->dstInfo(), dst, rowBytes, this->options().fZeroInitialized, 528 countLines, linesDecoded); 529 } 530 fCurrScanline += countLines; 531 return linesDecoded; 532 } 533 534 bool SkCodec::skipScanlines(int countLines) { 535 if (fCurrScanline < 0) { 536 return false; 537 } 538 539 SkASSERT(!fDstInfo.isEmpty()); 540 if (countLines < 0 || fCurrScanline + countLines > fDstInfo.height()) { 541 // Arguably, we could just skip the scanlines which are remaining, 542 // and return true. We choose to return false so the client 543 // can catch their bug. 544 return false; 545 } 546 547 bool result = this->onSkipScanlines(countLines); 548 fCurrScanline += countLines; 549 return result; 550 } 551 552 int SkCodec::outputScanline(int inputScanline) const { 553 SkASSERT(0 <= inputScanline && inputScanline < fEncodedInfo.height()); 554 return this->onOutputScanline(inputScanline); 555 } 556 557 int SkCodec::onOutputScanline(int inputScanline) const { 558 switch (this->getScanlineOrder()) { 559 case kTopDown_SkScanlineOrder: 560 return inputScanline; 561 case kBottomUp_SkScanlineOrder: 562 return fEncodedInfo.height() - inputScanline - 1; 563 default: 564 // This case indicates an interlaced gif and is implemented by SkGifCodec. 565 SkASSERT(false); 566 return 0; 567 } 568 } 569 570 void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t rowBytes, 571 ZeroInitialized zeroInit, int linesRequested, int linesDecoded) { 572 if (kYes_ZeroInitialized == zeroInit) { 573 return; 574 } 575 576 const int linesRemaining = linesRequested - linesDecoded; 577 SkSampler* sampler = this->getSampler(false); 578 579 const int fillWidth = sampler ? sampler->fillWidth() : 580 fOptions.fSubset ? fOptions.fSubset->width() : 581 info.width() ; 582 void* fillDst = this->getScanlineOrder() == kBottomUp_SkScanlineOrder ? dst : 583 SkTAddOffset<void>(dst, linesDecoded * rowBytes); 584 const auto fillInfo = info.makeWH(fillWidth, linesRemaining); 585 SkSampler::Fill(fillInfo, fillDst, rowBytes, kNo_ZeroInitialized); 586 } 587 588 bool sk_select_xform_format(SkColorType colorType, bool forColorTable, 589 skcms_PixelFormat* outFormat) { 590 SkASSERT(outFormat); 591 592 switch (colorType) { 593 case kRGBA_8888_SkColorType: 594 *outFormat = skcms_PixelFormat_RGBA_8888; 595 break; 596 case kBGRA_8888_SkColorType: 597 *outFormat = skcms_PixelFormat_BGRA_8888; 598 break; 599 case kRGB_565_SkColorType: 600 if (forColorTable) { 601 #ifdef SK_PMCOLOR_IS_RGBA 602 *outFormat = skcms_PixelFormat_RGBA_8888; 603 #else 604 *outFormat = skcms_PixelFormat_BGRA_8888; 605 #endif 606 break; 607 } 608 *outFormat = skcms_PixelFormat_BGR_565; 609 break; 610 case kRGBA_F16_SkColorType: 611 *outFormat = skcms_PixelFormat_RGBA_hhhh; 612 break; 613 case kGray_8_SkColorType: 614 *outFormat = skcms_PixelFormat_G_8; 615 break; 616 default: 617 return false; 618 } 619 return true; 620 } 621 622 bool SkCodec::initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha encodedAlpha, 623 bool srcIsOpaque) { 624 fXformTime = kNo_XformTime; 625 bool needsColorXform = false; 626 if (this->usesColorXform() && dstInfo.colorSpace()) { 627 dstInfo.colorSpace()->toProfile(&fDstProfile); 628 if (kRGBA_F16_SkColorType == dstInfo.colorType()) { 629 needsColorXform = true; 630 } else { 631 const auto* srcProfile = fEncodedInfo.profile(); 632 if (!srcProfile) { 633 srcProfile = skcms_sRGB_profile(); 634 } 635 if (!skcms_ApproximatelyEqualProfiles(srcProfile, &fDstProfile) ) { 636 needsColorXform = true; 637 } 638 } 639 } 640 641 if (!this->conversionSupported(dstInfo, srcIsOpaque, needsColorXform)) { 642 return false; 643 } 644 645 if (needsColorXform) { 646 fXformTime = SkEncodedInfo::kPalette_Color != fEncodedInfo.color() 647 || kRGBA_F16_SkColorType == dstInfo.colorType() 648 ? kDecodeRow_XformTime : kPalette_XformTime; 649 if (!sk_select_xform_format(dstInfo.colorType(), fXformTime == kPalette_XformTime, 650 &fDstXformFormat)) { 651 return false; 652 } 653 if (encodedAlpha == SkEncodedInfo::kUnpremul_Alpha 654 && dstInfo.alphaType() == kPremul_SkAlphaType) { 655 fDstXformAlphaFormat = skcms_AlphaFormat_PremulAsEncoded; 656 } else { 657 fDstXformAlphaFormat = skcms_AlphaFormat_Unpremul; 658 } 659 } 660 return true; 661 } 662 663 void SkCodec::applyColorXform(void* dst, const void* src, int count) const { 664 // It is okay for srcProfile to be null. This will use sRGB. 665 const auto* srcProfile = fEncodedInfo.profile(); 666 SkAssertResult(skcms_Transform(src, fSrcXformFormat, skcms_AlphaFormat_Unpremul, srcProfile, 667 dst, fDstXformFormat, fDstXformAlphaFormat, &fDstProfile, 668 count)); 669 } 670 671 std::vector<SkCodec::FrameInfo> SkCodec::getFrameInfo() { 672 const int frameCount = this->getFrameCount(); 673 SkASSERT(frameCount >= 0); 674 if (frameCount <= 0) { 675 return std::vector<FrameInfo>{}; 676 } 677 678 if (frameCount == 1 && !this->onGetFrameInfo(0, nullptr)) { 679 // Not animated. 680 return std::vector<FrameInfo>{}; 681 } 682 683 std::vector<FrameInfo> result(frameCount); 684 for (int i = 0; i < frameCount; ++i) { 685 SkAssertResult(this->onGetFrameInfo(i, &result[i])); 686 } 687 return result; 688 } 689 690 const char* SkCodec::ResultToString(Result result) { 691 switch (result) { 692 case kSuccess: 693 return "success"; 694 case kIncompleteInput: 695 return "incomplete input"; 696 case kErrorInInput: 697 return "error in input"; 698 case kInvalidConversion: 699 return "invalid conversion"; 700 case kInvalidScale: 701 return "invalid scale"; 702 case kInvalidParameters: 703 return "invalid parameters"; 704 case kInvalidInput: 705 return "invalid input"; 706 case kCouldNotRewind: 707 return "could not rewind"; 708 case kInternalError: 709 return "internal error"; 710 case kUnimplemented: 711 return "unimplemented"; 712 default: 713 SkASSERT(false); 714 return "bogus result value"; 715 } 716 } 717 718 static SkIRect frame_rect_on_screen(SkIRect frameRect, 719 const SkIRect& screenRect) { 720 if (!frameRect.intersect(screenRect)) { 721 return SkIRect::MakeEmpty(); 722 } 723 724 return frameRect; 725 } 726 727 static bool independent(const SkFrame& frame) { 728 return frame.getRequiredFrame() == SkCodec::kNoFrame; 729 } 730 731 static bool restore_bg(const SkFrame& frame) { 732 return frame.getDisposalMethod() == SkCodecAnimation::DisposalMethod::kRestoreBGColor; 733 } 734 735 void SkFrameHolder::setAlphaAndRequiredFrame(SkFrame* frame) { 736 const bool reportsAlpha = frame->reportedAlpha() != SkEncodedInfo::kOpaque_Alpha; 737 const auto screenRect = SkIRect::MakeWH(fScreenWidth, fScreenHeight); 738 const auto frameRect = frame_rect_on_screen(frame->frameRect(), screenRect); 739 740 const int i = frame->frameId(); 741 if (0 == i) { 742 frame->setHasAlpha(reportsAlpha || frameRect != screenRect); 743 frame->setRequiredFrame(SkCodec::kNoFrame); 744 return; 745 } 746 747 748 const bool blendWithPrevFrame = frame->getBlend() == SkCodecAnimation::Blend::kPriorFrame; 749 if ((!reportsAlpha || !blendWithPrevFrame) && frameRect == screenRect) { 750 frame->setHasAlpha(reportsAlpha); 751 frame->setRequiredFrame(SkCodec::kNoFrame); 752 return; 753 } 754 755 const SkFrame* prevFrame = this->getFrame(i-1); 756 while (prevFrame->getDisposalMethod() == SkCodecAnimation::DisposalMethod::kRestorePrevious) { 757 const int prevId = prevFrame->frameId(); 758 if (0 == prevId) { 759 frame->setHasAlpha(true); 760 frame->setRequiredFrame(SkCodec::kNoFrame); 761 return; 762 } 763 764 prevFrame = this->getFrame(prevId - 1); 765 } 766 767 const bool clearPrevFrame = restore_bg(*prevFrame); 768 auto prevFrameRect = frame_rect_on_screen(prevFrame->frameRect(), screenRect); 769 770 if (clearPrevFrame) { 771 if (prevFrameRect == screenRect || independent(*prevFrame)) { 772 frame->setHasAlpha(true); 773 frame->setRequiredFrame(SkCodec::kNoFrame); 774 return; 775 } 776 } 777 778 if (reportsAlpha && blendWithPrevFrame) { 779 // Note: We could be more aggressive here. If prevFrame clears 780 // to background color and covers its required frame (and that 781 // frame is independent), prevFrame could be marked independent. 782 // Would this extra complexity be worth it? 783 frame->setRequiredFrame(prevFrame->frameId()); 784 frame->setHasAlpha(prevFrame->hasAlpha() || clearPrevFrame); 785 return; 786 } 787 788 while (frameRect.contains(prevFrameRect)) { 789 const int prevRequiredFrame = prevFrame->getRequiredFrame(); 790 if (prevRequiredFrame == SkCodec::kNoFrame) { 791 frame->setRequiredFrame(SkCodec::kNoFrame); 792 frame->setHasAlpha(true); 793 return; 794 } 795 796 prevFrame = this->getFrame(prevRequiredFrame); 797 prevFrameRect = frame_rect_on_screen(prevFrame->frameRect(), screenRect); 798 } 799 800 if (restore_bg(*prevFrame)) { 801 frame->setHasAlpha(true); 802 if (prevFrameRect == screenRect || independent(*prevFrame)) { 803 frame->setRequiredFrame(SkCodec::kNoFrame); 804 } else { 805 // Note: As above, frame could still be independent, e.g. if 806 // prevFrame covers its required frame and that frame is 807 // independent. 808 frame->setRequiredFrame(prevFrame->frameId()); 809 } 810 return; 811 } 812 813 SkASSERT(prevFrame->getDisposalMethod() == SkCodecAnimation::DisposalMethod::kKeep); 814 frame->setRequiredFrame(prevFrame->frameId()); 815 frame->setHasAlpha(prevFrame->hasAlpha() || (reportsAlpha && !blendWithPrevFrame)); 816 } 817 818