1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/codec/SkCodec.h" 9cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 10cb93a386Sopenharmony_ci#include "include/core/SkColorSpace.h" 11cb93a386Sopenharmony_ci#include "include/core/SkData.h" 12cb93a386Sopenharmony_ci#include "include/core/SkImage.h" 13cb93a386Sopenharmony_ci#include "include/core/SkStream.h" 14cb93a386Sopenharmony_ci#include "include/private/SkHalf.h" 15cb93a386Sopenharmony_ci#include "src/codec/SkCodecPriv.h" 16cb93a386Sopenharmony_ci#include "src/codec/SkFrameHolder.h" 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ci// We always include and compile in these BMP codecs 19cb93a386Sopenharmony_ci#include "src/codec/SkBmpCodec.h" 20cb93a386Sopenharmony_ci#include "src/codec/SkWbmpCodec.h" 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ci#ifdef SK_HAS_ANDROID_CODEC 23cb93a386Sopenharmony_ci#include "include/codec/SkAndroidCodec.h" 24cb93a386Sopenharmony_ci#endif 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci#ifdef SK_HAS_HEIF_LIBRARY 27cb93a386Sopenharmony_ci#include "src/codec/SkHeifCodec.h" 28cb93a386Sopenharmony_ci#endif 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci#ifdef SK_CODEC_DECODES_JPEG 31cb93a386Sopenharmony_ci#include "src/codec/SkJpegCodec.h" 32cb93a386Sopenharmony_ci#endif 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci#ifdef SK_CODEC_DECODES_PNG 35cb93a386Sopenharmony_ci#include "src/codec/SkIcoCodec.h" 36cb93a386Sopenharmony_ci#include "src/codec/SkPngCodec.h" 37cb93a386Sopenharmony_ci#endif 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci#ifdef SK_CODEC_DECODES_RAW 40cb93a386Sopenharmony_ci#include "src/codec/SkRawCodec.h" 41cb93a386Sopenharmony_ci#endif 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci#ifdef SK_CODEC_DECODES_WEBP 44cb93a386Sopenharmony_ci#include "src/codec/SkWebpCodec.h" 45cb93a386Sopenharmony_ci#endif 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci#ifdef SK_HAS_WUFFS_LIBRARY 48cb93a386Sopenharmony_ci#include "src/codec/SkWuffsCodec.h" 49cb93a386Sopenharmony_ci#elif defined(SK_USE_LIBGIFCODEC) 50cb93a386Sopenharmony_ci#include "SkGifCodec.h" 51cb93a386Sopenharmony_ci#endif 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_cistruct DecoderProc { 54cb93a386Sopenharmony_ci bool (*IsFormat)(const void*, size_t); 55cb93a386Sopenharmony_ci std::unique_ptr<SkCodec> (*MakeFromStream)(std::unique_ptr<SkStream>, SkCodec::Result*); 56cb93a386Sopenharmony_ci}; 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_cistatic std::vector<DecoderProc>* decoders() { 59cb93a386Sopenharmony_ci static auto* decoders = new std::vector<DecoderProc> { 60cb93a386Sopenharmony_ci #ifdef SK_CODEC_DECODES_JPEG 61cb93a386Sopenharmony_ci { SkJpegCodec::IsJpeg, SkJpegCodec::MakeFromStream }, 62cb93a386Sopenharmony_ci #endif 63cb93a386Sopenharmony_ci #ifdef SK_CODEC_DECODES_WEBP 64cb93a386Sopenharmony_ci { SkWebpCodec::IsWebp, SkWebpCodec::MakeFromStream }, 65cb93a386Sopenharmony_ci #endif 66cb93a386Sopenharmony_ci #ifdef SK_HAS_WUFFS_LIBRARY 67cb93a386Sopenharmony_ci { SkWuffsCodec_IsFormat, SkWuffsCodec_MakeFromStream }, 68cb93a386Sopenharmony_ci #elif defined(SK_USE_LIBGIFCODEC) 69cb93a386Sopenharmony_ci { SkGifCodec::IsGif, SkGifCodec::MakeFromStream }, 70cb93a386Sopenharmony_ci #endif 71cb93a386Sopenharmony_ci #ifdef SK_CODEC_DECODES_PNG 72cb93a386Sopenharmony_ci { SkIcoCodec::IsIco, SkIcoCodec::MakeFromStream }, 73cb93a386Sopenharmony_ci #endif 74cb93a386Sopenharmony_ci { SkBmpCodec::IsBmp, SkBmpCodec::MakeFromStream }, 75cb93a386Sopenharmony_ci { SkWbmpCodec::IsWbmp, SkWbmpCodec::MakeFromStream }, 76cb93a386Sopenharmony_ci }; 77cb93a386Sopenharmony_ci return decoders; 78cb93a386Sopenharmony_ci} 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_civoid SkCodec::Register( 81cb93a386Sopenharmony_ci bool (*peek)(const void*, size_t), 82cb93a386Sopenharmony_ci std::unique_ptr<SkCodec> (*make)(std::unique_ptr<SkStream>, SkCodec::Result*)) { 83cb93a386Sopenharmony_ci decoders()->push_back(DecoderProc{peek, make}); 84cb93a386Sopenharmony_ci} 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_cistd::unique_ptr<SkCodec> SkCodec::MakeFromStream( 87cb93a386Sopenharmony_ci std::unique_ptr<SkStream> stream, Result* outResult, 88cb93a386Sopenharmony_ci SkPngChunkReader* chunkReader, SelectionPolicy selectionPolicy) { 89cb93a386Sopenharmony_ci Result resultStorage; 90cb93a386Sopenharmony_ci if (!outResult) { 91cb93a386Sopenharmony_ci outResult = &resultStorage; 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci if (!stream) { 95cb93a386Sopenharmony_ci *outResult = kInvalidInput; 96cb93a386Sopenharmony_ci return nullptr; 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci if (selectionPolicy != SelectionPolicy::kPreferStillImage 100cb93a386Sopenharmony_ci && selectionPolicy != SelectionPolicy::kPreferAnimation) { 101cb93a386Sopenharmony_ci *outResult = kInvalidParameters; 102cb93a386Sopenharmony_ci return nullptr; 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci constexpr size_t bytesToRead = MinBufferedBytesNeeded(); 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci char buffer[bytesToRead]; 108cb93a386Sopenharmony_ci size_t bytesRead = stream->peek(buffer, bytesToRead); 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci // It is also possible to have a complete image less than bytesToRead bytes 111cb93a386Sopenharmony_ci // (e.g. a 1 x 1 wbmp), meaning peek() would return less than bytesToRead. 112cb93a386Sopenharmony_ci // Assume that if bytesRead < bytesToRead, but > 0, the stream is shorter 113cb93a386Sopenharmony_ci // than bytesToRead, so pass that directly to the decoder. 114cb93a386Sopenharmony_ci // It also is possible the stream uses too small a buffer for peeking, but 115cb93a386Sopenharmony_ci // we trust the caller to use a large enough buffer. 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci if (0 == bytesRead) { 118cb93a386Sopenharmony_ci // TODO: After implementing peek in CreateJavaOutputStreamAdaptor.cpp, this 119cb93a386Sopenharmony_ci // printf could be useful to notice failures. 120cb93a386Sopenharmony_ci // SkCodecPrintf("Encoded image data failed to peek!\n"); 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci // It is possible the stream does not support peeking, but does support 123cb93a386Sopenharmony_ci // rewinding. 124cb93a386Sopenharmony_ci // Attempt to read() and pass the actual amount read to the decoder. 125cb93a386Sopenharmony_ci bytesRead = stream->read(buffer, bytesToRead); 126cb93a386Sopenharmony_ci if (!stream->rewind()) { 127cb93a386Sopenharmony_ci SkCodecPrintf("Encoded image data could not peek or rewind to determine format!\n"); 128cb93a386Sopenharmony_ci *outResult = kCouldNotRewind; 129cb93a386Sopenharmony_ci return nullptr; 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci // PNG is special, since we want to be able to supply an SkPngChunkReader. 134cb93a386Sopenharmony_ci // But this code follows the same pattern as the loop. 135cb93a386Sopenharmony_ci#ifdef SK_CODEC_DECODES_PNG 136cb93a386Sopenharmony_ci if (SkPngCodec::IsPng(buffer, bytesRead)) { 137cb93a386Sopenharmony_ci return SkPngCodec::MakeFromStream(std::move(stream), outResult, chunkReader); 138cb93a386Sopenharmony_ci } else 139cb93a386Sopenharmony_ci#endif 140cb93a386Sopenharmony_ci { 141cb93a386Sopenharmony_ci for (DecoderProc proc : *decoders()) { 142cb93a386Sopenharmony_ci if (proc.IsFormat(buffer, bytesRead)) { 143cb93a386Sopenharmony_ci return proc.MakeFromStream(std::move(stream), outResult); 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci } 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci#ifdef SK_HAS_HEIF_LIBRARY 148cb93a386Sopenharmony_ci SkEncodedImageFormat format; 149cb93a386Sopenharmony_ci if (SkHeifCodec::IsSupported(buffer, bytesRead, &format)) { 150cb93a386Sopenharmony_ci return SkHeifCodec::MakeFromStream(std::move(stream), selectionPolicy, 151cb93a386Sopenharmony_ci format, outResult); 152cb93a386Sopenharmony_ci } 153cb93a386Sopenharmony_ci#endif 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci#ifdef SK_CODEC_DECODES_RAW 156cb93a386Sopenharmony_ci // Try to treat the input as RAW if all the other checks failed. 157cb93a386Sopenharmony_ci return SkRawCodec::MakeFromStream(std::move(stream), outResult); 158cb93a386Sopenharmony_ci#endif 159cb93a386Sopenharmony_ci } 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_ci if (bytesRead < bytesToRead) { 162cb93a386Sopenharmony_ci *outResult = kIncompleteInput; 163cb93a386Sopenharmony_ci } else { 164cb93a386Sopenharmony_ci *outResult = kUnimplemented; 165cb93a386Sopenharmony_ci } 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci return nullptr; 168cb93a386Sopenharmony_ci} 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_cistd::unique_ptr<SkCodec> SkCodec::MakeFromData(sk_sp<SkData> data, SkPngChunkReader* reader) { 171cb93a386Sopenharmony_ci if (!data) { 172cb93a386Sopenharmony_ci return nullptr; 173cb93a386Sopenharmony_ci } 174cb93a386Sopenharmony_ci return MakeFromStream(SkMemoryStream::Make(std::move(data)), nullptr, reader); 175cb93a386Sopenharmony_ci} 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_ciSkCodec::SkCodec(SkEncodedInfo&& info, XformFormat srcFormat, std::unique_ptr<SkStream> stream, 178cb93a386Sopenharmony_ci SkEncodedOrigin origin) 179cb93a386Sopenharmony_ci : fEncodedInfo(std::move(info)) 180cb93a386Sopenharmony_ci , fSrcXformFormat(srcFormat) 181cb93a386Sopenharmony_ci , fStream(std::move(stream)) 182cb93a386Sopenharmony_ci , fNeedsRewind(false) 183cb93a386Sopenharmony_ci , fOrigin(origin) 184cb93a386Sopenharmony_ci , fDstInfo() 185cb93a386Sopenharmony_ci , fOptions() 186cb93a386Sopenharmony_ci , fCurrScanline(-1) 187cb93a386Sopenharmony_ci , fStartedIncrementalDecode(false) 188cb93a386Sopenharmony_ci , fAndroidCodecHandlesFrameIndex(false) 189cb93a386Sopenharmony_ci{} 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ciSkCodec::~SkCodec() {} 192cb93a386Sopenharmony_ci 193cb93a386Sopenharmony_cibool SkCodec::queryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes, 194cb93a386Sopenharmony_ci SkYUVAPixmapInfo* yuvaPixmapInfo) const { 195cb93a386Sopenharmony_ci if (!yuvaPixmapInfo) { 196cb93a386Sopenharmony_ci return false; 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci return this->onQueryYUVAInfo(supportedDataTypes, yuvaPixmapInfo) && 199cb93a386Sopenharmony_ci yuvaPixmapInfo->isSupported(supportedDataTypes); 200cb93a386Sopenharmony_ci} 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_ciSkCodec::Result SkCodec::getYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) { 203cb93a386Sopenharmony_ci if (!yuvaPixmaps.isValid()) { 204cb93a386Sopenharmony_ci return kInvalidInput; 205cb93a386Sopenharmony_ci } 206cb93a386Sopenharmony_ci if (!this->rewindIfNeeded()) { 207cb93a386Sopenharmony_ci return kCouldNotRewind; 208cb93a386Sopenharmony_ci } 209cb93a386Sopenharmony_ci return this->onGetYUVAPlanes(yuvaPixmaps); 210cb93a386Sopenharmony_ci} 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_cibool SkCodec::conversionSupported(const SkImageInfo& dst, bool srcIsOpaque, bool needsColorXform) { 213cb93a386Sopenharmony_ci if (!valid_alpha(dst.alphaType(), srcIsOpaque)) { 214cb93a386Sopenharmony_ci return false; 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci switch (dst.colorType()) { 218cb93a386Sopenharmony_ci case kRGBA_8888_SkColorType: 219cb93a386Sopenharmony_ci case kBGRA_8888_SkColorType: 220cb93a386Sopenharmony_ci case kRGBA_F16_SkColorType: 221cb93a386Sopenharmony_ci return true; 222cb93a386Sopenharmony_ci case kRGB_565_SkColorType: 223cb93a386Sopenharmony_ci return srcIsOpaque; 224cb93a386Sopenharmony_ci case kGray_8_SkColorType: 225cb93a386Sopenharmony_ci return SkEncodedInfo::kGray_Color == fEncodedInfo.color() && srcIsOpaque; 226cb93a386Sopenharmony_ci case kAlpha_8_SkColorType: 227cb93a386Sopenharmony_ci // conceptually we can convert anything into alpha_8, but we haven't actually coded 228cb93a386Sopenharmony_ci // all of those other conversions yet. 229cb93a386Sopenharmony_ci return SkEncodedInfo::kXAlpha_Color == fEncodedInfo.color(); 230cb93a386Sopenharmony_ci default: 231cb93a386Sopenharmony_ci return false; 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci} 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_cibool SkCodec::rewindIfNeeded() { 236cb93a386Sopenharmony_ci // Store the value of fNeedsRewind so we can update it. Next read will 237cb93a386Sopenharmony_ci // require a rewind. 238cb93a386Sopenharmony_ci const bool needsRewind = fNeedsRewind; 239cb93a386Sopenharmony_ci fNeedsRewind = true; 240cb93a386Sopenharmony_ci if (!needsRewind) { 241cb93a386Sopenharmony_ci return true; 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci // startScanlineDecode will need to be called before decoding scanlines. 245cb93a386Sopenharmony_ci fCurrScanline = -1; 246cb93a386Sopenharmony_ci // startIncrementalDecode will need to be called before incrementalDecode. 247cb93a386Sopenharmony_ci fStartedIncrementalDecode = false; 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci // Some codecs do not have a stream. They may hold onto their own data or another codec. 250cb93a386Sopenharmony_ci // They must handle rewinding themselves. 251cb93a386Sopenharmony_ci if (fStream && !fStream->rewind()) { 252cb93a386Sopenharmony_ci return false; 253cb93a386Sopenharmony_ci } 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_ci return this->onRewind(); 256cb93a386Sopenharmony_ci} 257cb93a386Sopenharmony_ci 258cb93a386Sopenharmony_cistatic SkIRect frame_rect_on_screen(SkIRect frameRect, 259cb93a386Sopenharmony_ci const SkIRect& screenRect) { 260cb93a386Sopenharmony_ci if (!frameRect.intersect(screenRect)) { 261cb93a386Sopenharmony_ci return SkIRect::MakeEmpty(); 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_ci return frameRect; 265cb93a386Sopenharmony_ci} 266cb93a386Sopenharmony_ci 267cb93a386Sopenharmony_cibool zero_rect(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes, 268cb93a386Sopenharmony_ci SkISize srcDimensions, SkIRect prevRect) { 269cb93a386Sopenharmony_ci const auto dimensions = dstInfo.dimensions(); 270cb93a386Sopenharmony_ci if (dimensions != srcDimensions) { 271cb93a386Sopenharmony_ci SkRect src = SkRect::Make(srcDimensions); 272cb93a386Sopenharmony_ci SkRect dst = SkRect::Make(dimensions); 273cb93a386Sopenharmony_ci SkMatrix map = SkMatrix::RectToRect(src, dst); 274cb93a386Sopenharmony_ci SkRect asRect = SkRect::Make(prevRect); 275cb93a386Sopenharmony_ci if (!map.mapRect(&asRect)) { 276cb93a386Sopenharmony_ci return false; 277cb93a386Sopenharmony_ci } 278cb93a386Sopenharmony_ci asRect.roundOut(&prevRect); 279cb93a386Sopenharmony_ci } 280cb93a386Sopenharmony_ci 281cb93a386Sopenharmony_ci if (!prevRect.intersect(SkIRect::MakeSize(dimensions))) { 282cb93a386Sopenharmony_ci // Nothing to zero, due to scaling or bad frame rect. 283cb93a386Sopenharmony_ci return true; 284cb93a386Sopenharmony_ci } 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_ci const SkImageInfo info = dstInfo.makeDimensions(prevRect.size()); 287cb93a386Sopenharmony_ci const size_t bpp = dstInfo.bytesPerPixel(); 288cb93a386Sopenharmony_ci const size_t offset = prevRect.x() * bpp + prevRect.y() * rowBytes; 289cb93a386Sopenharmony_ci void* eraseDst = SkTAddOffset<void>(pixels, offset); 290cb93a386Sopenharmony_ci SkSampler::Fill(info, eraseDst, rowBytes, SkCodec::kNo_ZeroInitialized); 291cb93a386Sopenharmony_ci return true; 292cb93a386Sopenharmony_ci} 293cb93a386Sopenharmony_ci 294cb93a386Sopenharmony_ciSkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels, size_t rowBytes, 295cb93a386Sopenharmony_ci const Options& options, SkAndroidCodec* androidCodec) { 296cb93a386Sopenharmony_ci if (androidCodec) { 297cb93a386Sopenharmony_ci // This is never set back to false. If SkAndroidCodec is calling this method, its fCodec 298cb93a386Sopenharmony_ci // should never call it directly. 299cb93a386Sopenharmony_ci fAndroidCodecHandlesFrameIndex = true; 300cb93a386Sopenharmony_ci } else if (fAndroidCodecHandlesFrameIndex) { 301cb93a386Sopenharmony_ci return kSuccess; 302cb93a386Sopenharmony_ci } 303cb93a386Sopenharmony_ci 304cb93a386Sopenharmony_ci if (!this->rewindIfNeeded()) { 305cb93a386Sopenharmony_ci return kCouldNotRewind; 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci 308cb93a386Sopenharmony_ci const int index = options.fFrameIndex; 309cb93a386Sopenharmony_ci if (0 == index) { 310cb93a386Sopenharmony_ci return this->initializeColorXform(info, fEncodedInfo.alpha(), fEncodedInfo.opaque()) 311cb93a386Sopenharmony_ci ? kSuccess : kInvalidConversion; 312cb93a386Sopenharmony_ci } 313cb93a386Sopenharmony_ci 314cb93a386Sopenharmony_ci if (index < 0) { 315cb93a386Sopenharmony_ci return kInvalidParameters; 316cb93a386Sopenharmony_ci } 317cb93a386Sopenharmony_ci 318cb93a386Sopenharmony_ci if (options.fSubset) { 319cb93a386Sopenharmony_ci // If we add support for this, we need to update the code that zeroes 320cb93a386Sopenharmony_ci // a kRestoreBGColor frame. 321cb93a386Sopenharmony_ci return kInvalidParameters; 322cb93a386Sopenharmony_ci } 323cb93a386Sopenharmony_ci 324cb93a386Sopenharmony_ci if (index >= this->onGetFrameCount()) { 325cb93a386Sopenharmony_ci return kIncompleteInput; 326cb93a386Sopenharmony_ci } 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_ci const auto* frameHolder = this->getFrameHolder(); 329cb93a386Sopenharmony_ci SkASSERT(frameHolder); 330cb93a386Sopenharmony_ci 331cb93a386Sopenharmony_ci const auto* frame = frameHolder->getFrame(index); 332cb93a386Sopenharmony_ci SkASSERT(frame); 333cb93a386Sopenharmony_ci 334cb93a386Sopenharmony_ci const int requiredFrame = frame->getRequiredFrame(); 335cb93a386Sopenharmony_ci if (requiredFrame != kNoFrame) { 336cb93a386Sopenharmony_ci const SkFrame* preppedFrame = nullptr; 337cb93a386Sopenharmony_ci if (options.fPriorFrame == kNoFrame) { 338cb93a386Sopenharmony_ci Result result = kInternalError; 339cb93a386Sopenharmony_ci if (androidCodec) { 340cb93a386Sopenharmony_ci#ifdef SK_HAS_ANDROID_CODEC 341cb93a386Sopenharmony_ci SkAndroidCodec::AndroidOptions prevFrameOptions( 342cb93a386Sopenharmony_ci reinterpret_cast<const SkAndroidCodec::AndroidOptions&>(options)); 343cb93a386Sopenharmony_ci prevFrameOptions.fFrameIndex = requiredFrame; 344cb93a386Sopenharmony_ci result = androidCodec->getAndroidPixels(info, pixels, rowBytes, &prevFrameOptions); 345cb93a386Sopenharmony_ci#endif 346cb93a386Sopenharmony_ci } else { 347cb93a386Sopenharmony_ci Options prevFrameOptions(options); 348cb93a386Sopenharmony_ci prevFrameOptions.fFrameIndex = requiredFrame; 349cb93a386Sopenharmony_ci result = this->getPixels(info, pixels, rowBytes, &prevFrameOptions); 350cb93a386Sopenharmony_ci } 351cb93a386Sopenharmony_ci if (result != kSuccess) { 352cb93a386Sopenharmony_ci return result; 353cb93a386Sopenharmony_ci } 354cb93a386Sopenharmony_ci preppedFrame = frameHolder->getFrame(requiredFrame); 355cb93a386Sopenharmony_ci } else { 356cb93a386Sopenharmony_ci // Check for a valid frame as a starting point. Alternatively, we could 357cb93a386Sopenharmony_ci // treat an invalid frame as not providing one, but rejecting it will 358cb93a386Sopenharmony_ci // make it easier to catch the mistake. 359cb93a386Sopenharmony_ci if (options.fPriorFrame < requiredFrame || options.fPriorFrame >= index) { 360cb93a386Sopenharmony_ci return kInvalidParameters; 361cb93a386Sopenharmony_ci } 362cb93a386Sopenharmony_ci preppedFrame = frameHolder->getFrame(options.fPriorFrame); 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci 365cb93a386Sopenharmony_ci SkASSERT(preppedFrame); 366cb93a386Sopenharmony_ci switch (preppedFrame->getDisposalMethod()) { 367cb93a386Sopenharmony_ci case SkCodecAnimation::DisposalMethod::kRestorePrevious: 368cb93a386Sopenharmony_ci SkASSERT(options.fPriorFrame != kNoFrame); 369cb93a386Sopenharmony_ci return kInvalidParameters; 370cb93a386Sopenharmony_ci case SkCodecAnimation::DisposalMethod::kRestoreBGColor: 371cb93a386Sopenharmony_ci // If a frame after the required frame is provided, there is no 372cb93a386Sopenharmony_ci // need to clear, since it must be covered by the desired frame. 373cb93a386Sopenharmony_ci // FIXME: If the required frame is kRestoreBGColor, we don't actually need to decode 374cb93a386Sopenharmony_ci // it, since we'll just clear it to transparent. Instead, we could decode *its* 375cb93a386Sopenharmony_ci // required frame and then clear. 376cb93a386Sopenharmony_ci if (preppedFrame->frameId() == requiredFrame) { 377cb93a386Sopenharmony_ci SkIRect preppedRect = preppedFrame->frameRect(); 378cb93a386Sopenharmony_ci if (!zero_rect(info, pixels, rowBytes, this->dimensions(), preppedRect)) { 379cb93a386Sopenharmony_ci return kInternalError; 380cb93a386Sopenharmony_ci } 381cb93a386Sopenharmony_ci } 382cb93a386Sopenharmony_ci break; 383cb93a386Sopenharmony_ci default: 384cb93a386Sopenharmony_ci break; 385cb93a386Sopenharmony_ci } 386cb93a386Sopenharmony_ci } 387cb93a386Sopenharmony_ci 388cb93a386Sopenharmony_ci return this->initializeColorXform(info, frame->reportedAlpha(), !frame->hasAlpha()) 389cb93a386Sopenharmony_ci ? kSuccess : kInvalidConversion; 390cb93a386Sopenharmony_ci} 391cb93a386Sopenharmony_ci 392cb93a386Sopenharmony_ciSkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, 393cb93a386Sopenharmony_ci const Options* options) { 394cb93a386Sopenharmony_ci if (kUnknown_SkColorType == info.colorType()) { 395cb93a386Sopenharmony_ci return kInvalidConversion; 396cb93a386Sopenharmony_ci } 397cb93a386Sopenharmony_ci if (nullptr == pixels) { 398cb93a386Sopenharmony_ci return kInvalidParameters; 399cb93a386Sopenharmony_ci } 400cb93a386Sopenharmony_ci if (rowBytes < info.minRowBytes()) { 401cb93a386Sopenharmony_ci return kInvalidParameters; 402cb93a386Sopenharmony_ci } 403cb93a386Sopenharmony_ci 404cb93a386Sopenharmony_ci // Default options. 405cb93a386Sopenharmony_ci Options optsStorage; 406cb93a386Sopenharmony_ci if (nullptr == options) { 407cb93a386Sopenharmony_ci options = &optsStorage; 408cb93a386Sopenharmony_ci } else { 409cb93a386Sopenharmony_ci if (options->fSubset) { 410cb93a386Sopenharmony_ci SkIRect subset(*options->fSubset); 411cb93a386Sopenharmony_ci if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) { 412cb93a386Sopenharmony_ci // FIXME: How to differentiate between not supporting subset at all 413cb93a386Sopenharmony_ci // and not supporting this particular subset? 414cb93a386Sopenharmony_ci return kUnimplemented; 415cb93a386Sopenharmony_ci } 416cb93a386Sopenharmony_ci } 417cb93a386Sopenharmony_ci } 418cb93a386Sopenharmony_ci 419cb93a386Sopenharmony_ci const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes, 420cb93a386Sopenharmony_ci *options); 421cb93a386Sopenharmony_ci if (frameIndexResult != kSuccess) { 422cb93a386Sopenharmony_ci return frameIndexResult; 423cb93a386Sopenharmony_ci } 424cb93a386Sopenharmony_ci 425cb93a386Sopenharmony_ci // FIXME: Support subsets somehow? Note that this works for SkWebpCodec 426cb93a386Sopenharmony_ci // because it supports arbitrary scaling/subset combinations. 427cb93a386Sopenharmony_ci if (!this->dimensionsSupported(info.dimensions())) { 428cb93a386Sopenharmony_ci return kInvalidScale; 429cb93a386Sopenharmony_ci } 430cb93a386Sopenharmony_ci 431cb93a386Sopenharmony_ci fDstInfo = info; 432cb93a386Sopenharmony_ci fOptions = *options; 433cb93a386Sopenharmony_ci 434cb93a386Sopenharmony_ci // On an incomplete decode, the subclass will specify the number of scanlines that it decoded 435cb93a386Sopenharmony_ci // successfully. 436cb93a386Sopenharmony_ci int rowsDecoded = 0; 437cb93a386Sopenharmony_ci const Result result = this->onGetPixels(info, pixels, rowBytes, *options, &rowsDecoded); 438cb93a386Sopenharmony_ci 439cb93a386Sopenharmony_ci // A return value of kIncompleteInput indicates a truncated image stream. 440cb93a386Sopenharmony_ci // In this case, we will fill any uninitialized memory with a default value. 441cb93a386Sopenharmony_ci // Some subclasses will take care of filling any uninitialized memory on 442cb93a386Sopenharmony_ci // their own. They indicate that all of the memory has been filled by 443cb93a386Sopenharmony_ci // setting rowsDecoded equal to the height. 444cb93a386Sopenharmony_ci if ((kIncompleteInput == result || kErrorInInput == result) && rowsDecoded != info.height()) { 445cb93a386Sopenharmony_ci // FIXME: (skbug.com/5772) fillIncompleteImage will fill using the swizzler's width, unless 446cb93a386Sopenharmony_ci // there is a subset. In that case, it will use the width of the subset. From here, the 447cb93a386Sopenharmony_ci // subset will only be non-null in the case of SkWebpCodec, but it treats the subset 448cb93a386Sopenharmony_ci // differenty from the other codecs, and it needs to use the width specified by the info. 449cb93a386Sopenharmony_ci // Set the subset to null so SkWebpCodec uses the correct width. 450cb93a386Sopenharmony_ci fOptions.fSubset = nullptr; 451cb93a386Sopenharmony_ci this->fillIncompleteImage(info, pixels, rowBytes, options->fZeroInitialized, info.height(), 452cb93a386Sopenharmony_ci rowsDecoded); 453cb93a386Sopenharmony_ci } 454cb93a386Sopenharmony_ci 455cb93a386Sopenharmony_ci return result; 456cb93a386Sopenharmony_ci} 457cb93a386Sopenharmony_ci 458cb93a386Sopenharmony_cistd::tuple<sk_sp<SkImage>, SkCodec::Result> SkCodec::getImage(const SkImageInfo& info, 459cb93a386Sopenharmony_ci const Options* options) { 460cb93a386Sopenharmony_ci SkBitmap bm; 461cb93a386Sopenharmony_ci if (!bm.tryAllocPixels(info)) { 462cb93a386Sopenharmony_ci return {nullptr, kInternalError}; 463cb93a386Sopenharmony_ci } 464cb93a386Sopenharmony_ci 465cb93a386Sopenharmony_ci Result result = this->getPixels(info, bm.getPixels(), bm.rowBytes(), options); 466cb93a386Sopenharmony_ci switch (result) { 467cb93a386Sopenharmony_ci case kSuccess: 468cb93a386Sopenharmony_ci case kIncompleteInput: 469cb93a386Sopenharmony_ci case kErrorInInput: 470cb93a386Sopenharmony_ci bm.setImmutable(); 471cb93a386Sopenharmony_ci return {bm.asImage(), result}; 472cb93a386Sopenharmony_ci 473cb93a386Sopenharmony_ci default: break; 474cb93a386Sopenharmony_ci } 475cb93a386Sopenharmony_ci return {nullptr, result}; 476cb93a386Sopenharmony_ci} 477cb93a386Sopenharmony_ci 478cb93a386Sopenharmony_cistd::tuple<sk_sp<SkImage>, SkCodec::Result> SkCodec::getImage() { 479cb93a386Sopenharmony_ci return this->getImage(this->getInfo(), nullptr); 480cb93a386Sopenharmony_ci} 481cb93a386Sopenharmony_ci 482cb93a386Sopenharmony_ciSkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* pixels, 483cb93a386Sopenharmony_ci size_t rowBytes, const SkCodec::Options* options) { 484cb93a386Sopenharmony_ci fStartedIncrementalDecode = false; 485cb93a386Sopenharmony_ci 486cb93a386Sopenharmony_ci if (kUnknown_SkColorType == info.colorType()) { 487cb93a386Sopenharmony_ci return kInvalidConversion; 488cb93a386Sopenharmony_ci } 489cb93a386Sopenharmony_ci if (nullptr == pixels) { 490cb93a386Sopenharmony_ci return kInvalidParameters; 491cb93a386Sopenharmony_ci } 492cb93a386Sopenharmony_ci 493cb93a386Sopenharmony_ci // Set options. 494cb93a386Sopenharmony_ci Options optsStorage; 495cb93a386Sopenharmony_ci if (nullptr == options) { 496cb93a386Sopenharmony_ci options = &optsStorage; 497cb93a386Sopenharmony_ci } else { 498cb93a386Sopenharmony_ci if (options->fSubset) { 499cb93a386Sopenharmony_ci SkIRect size = SkIRect::MakeSize(info.dimensions()); 500cb93a386Sopenharmony_ci if (!size.contains(*options->fSubset)) { 501cb93a386Sopenharmony_ci return kInvalidParameters; 502cb93a386Sopenharmony_ci } 503cb93a386Sopenharmony_ci 504cb93a386Sopenharmony_ci const int top = options->fSubset->top(); 505cb93a386Sopenharmony_ci const int bottom = options->fSubset->bottom(); 506cb93a386Sopenharmony_ci if (top < 0 || top >= info.height() || top >= bottom || bottom > info.height()) { 507cb93a386Sopenharmony_ci return kInvalidParameters; 508cb93a386Sopenharmony_ci } 509cb93a386Sopenharmony_ci } 510cb93a386Sopenharmony_ci } 511cb93a386Sopenharmony_ci 512cb93a386Sopenharmony_ci const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes, 513cb93a386Sopenharmony_ci *options); 514cb93a386Sopenharmony_ci if (frameIndexResult != kSuccess) { 515cb93a386Sopenharmony_ci return frameIndexResult; 516cb93a386Sopenharmony_ci } 517cb93a386Sopenharmony_ci 518cb93a386Sopenharmony_ci if (!this->dimensionsSupported(info.dimensions())) { 519cb93a386Sopenharmony_ci return kInvalidScale; 520cb93a386Sopenharmony_ci } 521cb93a386Sopenharmony_ci 522cb93a386Sopenharmony_ci fDstInfo = info; 523cb93a386Sopenharmony_ci fOptions = *options; 524cb93a386Sopenharmony_ci 525cb93a386Sopenharmony_ci const Result result = this->onStartIncrementalDecode(info, pixels, rowBytes, fOptions); 526cb93a386Sopenharmony_ci if (kSuccess == result) { 527cb93a386Sopenharmony_ci fStartedIncrementalDecode = true; 528cb93a386Sopenharmony_ci } else if (kUnimplemented == result) { 529cb93a386Sopenharmony_ci // FIXME: This is temporarily necessary, until we transition SkCodec 530cb93a386Sopenharmony_ci // implementations from scanline decoding to incremental decoding. 531cb93a386Sopenharmony_ci // SkAndroidCodec will first attempt to use incremental decoding, but 532cb93a386Sopenharmony_ci // will fall back to scanline decoding if incremental returns 533cb93a386Sopenharmony_ci // kUnimplemented. rewindIfNeeded(), above, set fNeedsRewind to true 534cb93a386Sopenharmony_ci // (after potentially rewinding), but we do not want the next call to 535cb93a386Sopenharmony_ci // startScanlineDecode() to do a rewind. 536cb93a386Sopenharmony_ci fNeedsRewind = false; 537cb93a386Sopenharmony_ci } 538cb93a386Sopenharmony_ci return result; 539cb93a386Sopenharmony_ci} 540cb93a386Sopenharmony_ci 541cb93a386Sopenharmony_ci 542cb93a386Sopenharmony_ciSkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info, 543cb93a386Sopenharmony_ci const SkCodec::Options* options) { 544cb93a386Sopenharmony_ci // Reset fCurrScanline in case of failure. 545cb93a386Sopenharmony_ci fCurrScanline = -1; 546cb93a386Sopenharmony_ci 547cb93a386Sopenharmony_ci // Set options. 548cb93a386Sopenharmony_ci Options optsStorage; 549cb93a386Sopenharmony_ci if (nullptr == options) { 550cb93a386Sopenharmony_ci options = &optsStorage; 551cb93a386Sopenharmony_ci } else if (options->fSubset) { 552cb93a386Sopenharmony_ci SkIRect size = SkIRect::MakeSize(info.dimensions()); 553cb93a386Sopenharmony_ci if (!size.contains(*options->fSubset)) { 554cb93a386Sopenharmony_ci return kInvalidInput; 555cb93a386Sopenharmony_ci } 556cb93a386Sopenharmony_ci 557cb93a386Sopenharmony_ci // We only support subsetting in the x-dimension for scanline decoder. 558cb93a386Sopenharmony_ci // Subsetting in the y-dimension can be accomplished using skipScanlines(). 559cb93a386Sopenharmony_ci if (options->fSubset->top() != 0 || options->fSubset->height() != info.height()) { 560cb93a386Sopenharmony_ci return kInvalidInput; 561cb93a386Sopenharmony_ci } 562cb93a386Sopenharmony_ci } 563cb93a386Sopenharmony_ci 564cb93a386Sopenharmony_ci // Scanline decoding only supports decoding the first frame. 565cb93a386Sopenharmony_ci if (options->fFrameIndex != 0) { 566cb93a386Sopenharmony_ci return kUnimplemented; 567cb93a386Sopenharmony_ci } 568cb93a386Sopenharmony_ci 569cb93a386Sopenharmony_ci // The void* dst and rowbytes in handleFrameIndex or only used for decoding prior 570cb93a386Sopenharmony_ci // frames, which is not supported here anyway, so it is safe to pass nullptr/0. 571cb93a386Sopenharmony_ci const Result frameIndexResult = this->handleFrameIndex(info, nullptr, 0, *options); 572cb93a386Sopenharmony_ci if (frameIndexResult != kSuccess) { 573cb93a386Sopenharmony_ci return frameIndexResult; 574cb93a386Sopenharmony_ci } 575cb93a386Sopenharmony_ci 576cb93a386Sopenharmony_ci // FIXME: Support subsets somehow? 577cb93a386Sopenharmony_ci if (!this->dimensionsSupported(info.dimensions())) { 578cb93a386Sopenharmony_ci return kInvalidScale; 579cb93a386Sopenharmony_ci } 580cb93a386Sopenharmony_ci 581cb93a386Sopenharmony_ci const Result result = this->onStartScanlineDecode(info, *options); 582cb93a386Sopenharmony_ci if (result != SkCodec::kSuccess) { 583cb93a386Sopenharmony_ci return result; 584cb93a386Sopenharmony_ci } 585cb93a386Sopenharmony_ci 586cb93a386Sopenharmony_ci // FIXME: See startIncrementalDecode. That method set fNeedsRewind to false 587cb93a386Sopenharmony_ci // so that when onStartScanlineDecode calls rewindIfNeeded it would not 588cb93a386Sopenharmony_ci // rewind. But it also relies on that call to rewindIfNeeded to set 589cb93a386Sopenharmony_ci // fNeedsRewind to true for future decodes. When 590cb93a386Sopenharmony_ci // fAndroidCodecHandlesFrameIndex is true, that call to rewindIfNeeded is 591cb93a386Sopenharmony_ci // skipped, so this method sets it back to true. 592cb93a386Sopenharmony_ci SkASSERT(fAndroidCodecHandlesFrameIndex || fNeedsRewind); 593cb93a386Sopenharmony_ci fNeedsRewind = true; 594cb93a386Sopenharmony_ci 595cb93a386Sopenharmony_ci fCurrScanline = 0; 596cb93a386Sopenharmony_ci fDstInfo = info; 597cb93a386Sopenharmony_ci fOptions = *options; 598cb93a386Sopenharmony_ci return kSuccess; 599cb93a386Sopenharmony_ci} 600cb93a386Sopenharmony_ci 601cb93a386Sopenharmony_ciint SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { 602cb93a386Sopenharmony_ci if (fCurrScanline < 0) { 603cb93a386Sopenharmony_ci return 0; 604cb93a386Sopenharmony_ci } 605cb93a386Sopenharmony_ci 606cb93a386Sopenharmony_ci SkASSERT(!fDstInfo.isEmpty()); 607cb93a386Sopenharmony_ci if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) { 608cb93a386Sopenharmony_ci return 0; 609cb93a386Sopenharmony_ci } 610cb93a386Sopenharmony_ci 611cb93a386Sopenharmony_ci const int linesDecoded = this->onGetScanlines(dst, countLines, rowBytes); 612cb93a386Sopenharmony_ci if (linesDecoded < countLines) { 613cb93a386Sopenharmony_ci this->fillIncompleteImage(this->dstInfo(), dst, rowBytes, this->options().fZeroInitialized, 614cb93a386Sopenharmony_ci countLines, linesDecoded); 615cb93a386Sopenharmony_ci } 616cb93a386Sopenharmony_ci fCurrScanline += countLines; 617cb93a386Sopenharmony_ci return linesDecoded; 618cb93a386Sopenharmony_ci} 619cb93a386Sopenharmony_ci 620cb93a386Sopenharmony_cibool SkCodec::skipScanlines(int countLines) { 621cb93a386Sopenharmony_ci if (fCurrScanline < 0) { 622cb93a386Sopenharmony_ci return false; 623cb93a386Sopenharmony_ci } 624cb93a386Sopenharmony_ci 625cb93a386Sopenharmony_ci SkASSERT(!fDstInfo.isEmpty()); 626cb93a386Sopenharmony_ci if (countLines < 0 || fCurrScanline + countLines > fDstInfo.height()) { 627cb93a386Sopenharmony_ci // Arguably, we could just skip the scanlines which are remaining, 628cb93a386Sopenharmony_ci // and return true. We choose to return false so the client 629cb93a386Sopenharmony_ci // can catch their bug. 630cb93a386Sopenharmony_ci return false; 631cb93a386Sopenharmony_ci } 632cb93a386Sopenharmony_ci 633cb93a386Sopenharmony_ci bool result = this->onSkipScanlines(countLines); 634cb93a386Sopenharmony_ci fCurrScanline += countLines; 635cb93a386Sopenharmony_ci return result; 636cb93a386Sopenharmony_ci} 637cb93a386Sopenharmony_ci 638cb93a386Sopenharmony_ciint SkCodec::outputScanline(int inputScanline) const { 639cb93a386Sopenharmony_ci SkASSERT(0 <= inputScanline && inputScanline < fEncodedInfo.height()); 640cb93a386Sopenharmony_ci return this->onOutputScanline(inputScanline); 641cb93a386Sopenharmony_ci} 642cb93a386Sopenharmony_ci 643cb93a386Sopenharmony_ciint SkCodec::onOutputScanline(int inputScanline) const { 644cb93a386Sopenharmony_ci switch (this->getScanlineOrder()) { 645cb93a386Sopenharmony_ci case kTopDown_SkScanlineOrder: 646cb93a386Sopenharmony_ci return inputScanline; 647cb93a386Sopenharmony_ci case kBottomUp_SkScanlineOrder: 648cb93a386Sopenharmony_ci return fEncodedInfo.height() - inputScanline - 1; 649cb93a386Sopenharmony_ci default: 650cb93a386Sopenharmony_ci // This case indicates an interlaced gif and is implemented by SkGifCodec. 651cb93a386Sopenharmony_ci SkASSERT(false); 652cb93a386Sopenharmony_ci return 0; 653cb93a386Sopenharmony_ci } 654cb93a386Sopenharmony_ci} 655cb93a386Sopenharmony_ci 656cb93a386Sopenharmony_civoid SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t rowBytes, 657cb93a386Sopenharmony_ci ZeroInitialized zeroInit, int linesRequested, int linesDecoded) { 658cb93a386Sopenharmony_ci if (kYes_ZeroInitialized == zeroInit) { 659cb93a386Sopenharmony_ci return; 660cb93a386Sopenharmony_ci } 661cb93a386Sopenharmony_ci 662cb93a386Sopenharmony_ci const int linesRemaining = linesRequested - linesDecoded; 663cb93a386Sopenharmony_ci SkSampler* sampler = this->getSampler(false); 664cb93a386Sopenharmony_ci 665cb93a386Sopenharmony_ci const int fillWidth = sampler ? sampler->fillWidth() : 666cb93a386Sopenharmony_ci fOptions.fSubset ? fOptions.fSubset->width() : 667cb93a386Sopenharmony_ci info.width() ; 668cb93a386Sopenharmony_ci void* fillDst = this->getScanlineOrder() == kBottomUp_SkScanlineOrder ? dst : 669cb93a386Sopenharmony_ci SkTAddOffset<void>(dst, linesDecoded * rowBytes); 670cb93a386Sopenharmony_ci const auto fillInfo = info.makeWH(fillWidth, linesRemaining); 671cb93a386Sopenharmony_ci SkSampler::Fill(fillInfo, fillDst, rowBytes, kNo_ZeroInitialized); 672cb93a386Sopenharmony_ci} 673cb93a386Sopenharmony_ci 674cb93a386Sopenharmony_cibool sk_select_xform_format(SkColorType colorType, bool forColorTable, 675cb93a386Sopenharmony_ci skcms_PixelFormat* outFormat) { 676cb93a386Sopenharmony_ci SkASSERT(outFormat); 677cb93a386Sopenharmony_ci 678cb93a386Sopenharmony_ci switch (colorType) { 679cb93a386Sopenharmony_ci case kRGBA_8888_SkColorType: 680cb93a386Sopenharmony_ci *outFormat = skcms_PixelFormat_RGBA_8888; 681cb93a386Sopenharmony_ci break; 682cb93a386Sopenharmony_ci case kBGRA_8888_SkColorType: 683cb93a386Sopenharmony_ci *outFormat = skcms_PixelFormat_BGRA_8888; 684cb93a386Sopenharmony_ci break; 685cb93a386Sopenharmony_ci case kRGB_565_SkColorType: 686cb93a386Sopenharmony_ci if (forColorTable) { 687cb93a386Sopenharmony_ci#ifdef SK_PMCOLOR_IS_RGBA 688cb93a386Sopenharmony_ci *outFormat = skcms_PixelFormat_RGBA_8888; 689cb93a386Sopenharmony_ci#else 690cb93a386Sopenharmony_ci *outFormat = skcms_PixelFormat_BGRA_8888; 691cb93a386Sopenharmony_ci#endif 692cb93a386Sopenharmony_ci break; 693cb93a386Sopenharmony_ci } 694cb93a386Sopenharmony_ci *outFormat = skcms_PixelFormat_BGR_565; 695cb93a386Sopenharmony_ci break; 696cb93a386Sopenharmony_ci case kRGBA_F16_SkColorType: 697cb93a386Sopenharmony_ci *outFormat = skcms_PixelFormat_RGBA_hhhh; 698cb93a386Sopenharmony_ci break; 699cb93a386Sopenharmony_ci case kGray_8_SkColorType: 700cb93a386Sopenharmony_ci *outFormat = skcms_PixelFormat_G_8; 701cb93a386Sopenharmony_ci break; 702cb93a386Sopenharmony_ci default: 703cb93a386Sopenharmony_ci return false; 704cb93a386Sopenharmony_ci } 705cb93a386Sopenharmony_ci return true; 706cb93a386Sopenharmony_ci} 707cb93a386Sopenharmony_ci 708cb93a386Sopenharmony_cibool SkCodec::initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha encodedAlpha, 709cb93a386Sopenharmony_ci bool srcIsOpaque) { 710cb93a386Sopenharmony_ci fXformTime = kNo_XformTime; 711cb93a386Sopenharmony_ci bool needsColorXform = false; 712cb93a386Sopenharmony_ci if (this->usesColorXform()) { 713cb93a386Sopenharmony_ci if (kRGBA_F16_SkColorType == dstInfo.colorType()) { 714cb93a386Sopenharmony_ci needsColorXform = true; 715cb93a386Sopenharmony_ci if (dstInfo.colorSpace()) { 716cb93a386Sopenharmony_ci dstInfo.colorSpace()->toProfile(&fDstProfile); 717cb93a386Sopenharmony_ci } else { 718cb93a386Sopenharmony_ci // Use the srcProfile to avoid conversion. 719cb93a386Sopenharmony_ci const auto* srcProfile = fEncodedInfo.profile(); 720cb93a386Sopenharmony_ci fDstProfile = srcProfile ? *srcProfile : *skcms_sRGB_profile(); 721cb93a386Sopenharmony_ci } 722cb93a386Sopenharmony_ci } else if (dstInfo.colorSpace()) { 723cb93a386Sopenharmony_ci dstInfo.colorSpace()->toProfile(&fDstProfile); 724cb93a386Sopenharmony_ci const auto* srcProfile = fEncodedInfo.profile(); 725cb93a386Sopenharmony_ci if (!srcProfile) { 726cb93a386Sopenharmony_ci srcProfile = skcms_sRGB_profile(); 727cb93a386Sopenharmony_ci } 728cb93a386Sopenharmony_ci if (!skcms_ApproximatelyEqualProfiles(srcProfile, &fDstProfile) ) { 729cb93a386Sopenharmony_ci needsColorXform = true; 730cb93a386Sopenharmony_ci } 731cb93a386Sopenharmony_ci } 732cb93a386Sopenharmony_ci } 733cb93a386Sopenharmony_ci 734cb93a386Sopenharmony_ci if (!this->conversionSupported(dstInfo, srcIsOpaque, needsColorXform)) { 735cb93a386Sopenharmony_ci return false; 736cb93a386Sopenharmony_ci } 737cb93a386Sopenharmony_ci 738cb93a386Sopenharmony_ci if (needsColorXform) { 739cb93a386Sopenharmony_ci fXformTime = SkEncodedInfo::kPalette_Color != fEncodedInfo.color() 740cb93a386Sopenharmony_ci || kRGBA_F16_SkColorType == dstInfo.colorType() 741cb93a386Sopenharmony_ci ? kDecodeRow_XformTime : kPalette_XformTime; 742cb93a386Sopenharmony_ci if (!sk_select_xform_format(dstInfo.colorType(), fXformTime == kPalette_XformTime, 743cb93a386Sopenharmony_ci &fDstXformFormat)) { 744cb93a386Sopenharmony_ci return false; 745cb93a386Sopenharmony_ci } 746cb93a386Sopenharmony_ci if (encodedAlpha == SkEncodedInfo::kUnpremul_Alpha 747cb93a386Sopenharmony_ci && dstInfo.alphaType() == kPremul_SkAlphaType) { 748cb93a386Sopenharmony_ci fDstXformAlphaFormat = skcms_AlphaFormat_PremulAsEncoded; 749cb93a386Sopenharmony_ci } else { 750cb93a386Sopenharmony_ci fDstXformAlphaFormat = skcms_AlphaFormat_Unpremul; 751cb93a386Sopenharmony_ci } 752cb93a386Sopenharmony_ci } 753cb93a386Sopenharmony_ci return true; 754cb93a386Sopenharmony_ci} 755cb93a386Sopenharmony_ci 756cb93a386Sopenharmony_civoid SkCodec::applyColorXform(void* dst, const void* src, int count) const { 757cb93a386Sopenharmony_ci // It is okay for srcProfile to be null. This will use sRGB. 758cb93a386Sopenharmony_ci const auto* srcProfile = fEncodedInfo.profile(); 759cb93a386Sopenharmony_ci SkAssertResult(skcms_Transform(src, fSrcXformFormat, skcms_AlphaFormat_Unpremul, srcProfile, 760cb93a386Sopenharmony_ci dst, fDstXformFormat, fDstXformAlphaFormat, &fDstProfile, 761cb93a386Sopenharmony_ci count)); 762cb93a386Sopenharmony_ci} 763cb93a386Sopenharmony_ci 764cb93a386Sopenharmony_cistd::vector<SkCodec::FrameInfo> SkCodec::getFrameInfo() { 765cb93a386Sopenharmony_ci const int frameCount = this->getFrameCount(); 766cb93a386Sopenharmony_ci SkASSERT(frameCount >= 0); 767cb93a386Sopenharmony_ci if (frameCount <= 0) { 768cb93a386Sopenharmony_ci return std::vector<FrameInfo>{}; 769cb93a386Sopenharmony_ci } 770cb93a386Sopenharmony_ci 771cb93a386Sopenharmony_ci if (frameCount == 1 && !this->onGetFrameInfo(0, nullptr)) { 772cb93a386Sopenharmony_ci // Not animated. 773cb93a386Sopenharmony_ci return std::vector<FrameInfo>{}; 774cb93a386Sopenharmony_ci } 775cb93a386Sopenharmony_ci 776cb93a386Sopenharmony_ci std::vector<FrameInfo> result(frameCount); 777cb93a386Sopenharmony_ci for (int i = 0; i < frameCount; ++i) { 778cb93a386Sopenharmony_ci SkAssertResult(this->onGetFrameInfo(i, &result[i])); 779cb93a386Sopenharmony_ci } 780cb93a386Sopenharmony_ci return result; 781cb93a386Sopenharmony_ci} 782cb93a386Sopenharmony_ci 783cb93a386Sopenharmony_ciconst char* SkCodec::ResultToString(Result result) { 784cb93a386Sopenharmony_ci switch (result) { 785cb93a386Sopenharmony_ci case kSuccess: 786cb93a386Sopenharmony_ci return "success"; 787cb93a386Sopenharmony_ci case kIncompleteInput: 788cb93a386Sopenharmony_ci return "incomplete input"; 789cb93a386Sopenharmony_ci case kErrorInInput: 790cb93a386Sopenharmony_ci return "error in input"; 791cb93a386Sopenharmony_ci case kInvalidConversion: 792cb93a386Sopenharmony_ci return "invalid conversion"; 793cb93a386Sopenharmony_ci case kInvalidScale: 794cb93a386Sopenharmony_ci return "invalid scale"; 795cb93a386Sopenharmony_ci case kInvalidParameters: 796cb93a386Sopenharmony_ci return "invalid parameters"; 797cb93a386Sopenharmony_ci case kInvalidInput: 798cb93a386Sopenharmony_ci return "invalid input"; 799cb93a386Sopenharmony_ci case kCouldNotRewind: 800cb93a386Sopenharmony_ci return "could not rewind"; 801cb93a386Sopenharmony_ci case kInternalError: 802cb93a386Sopenharmony_ci return "internal error"; 803cb93a386Sopenharmony_ci case kUnimplemented: 804cb93a386Sopenharmony_ci return "unimplemented"; 805cb93a386Sopenharmony_ci default: 806cb93a386Sopenharmony_ci SkASSERT(false); 807cb93a386Sopenharmony_ci return "bogus result value"; 808cb93a386Sopenharmony_ci } 809cb93a386Sopenharmony_ci} 810cb93a386Sopenharmony_ci 811cb93a386Sopenharmony_civoid SkFrame::fillIn(SkCodec::FrameInfo* frameInfo, bool fullyReceived) const { 812cb93a386Sopenharmony_ci SkASSERT(frameInfo); 813cb93a386Sopenharmony_ci 814cb93a386Sopenharmony_ci frameInfo->fRequiredFrame = fRequiredFrame; 815cb93a386Sopenharmony_ci frameInfo->fDuration = fDuration; 816cb93a386Sopenharmony_ci frameInfo->fFullyReceived = fullyReceived; 817cb93a386Sopenharmony_ci frameInfo->fAlphaType = fHasAlpha ? kUnpremul_SkAlphaType 818cb93a386Sopenharmony_ci : kOpaque_SkAlphaType; 819cb93a386Sopenharmony_ci frameInfo->fHasAlphaWithinBounds = this->reportedAlpha() != SkEncodedInfo::kOpaque_Alpha; 820cb93a386Sopenharmony_ci frameInfo->fDisposalMethod = fDisposalMethod; 821cb93a386Sopenharmony_ci frameInfo->fBlend = fBlend; 822cb93a386Sopenharmony_ci frameInfo->fFrameRect = fRect; 823cb93a386Sopenharmony_ci} 824cb93a386Sopenharmony_ci 825cb93a386Sopenharmony_cistatic bool independent(const SkFrame& frame) { 826cb93a386Sopenharmony_ci return frame.getRequiredFrame() == SkCodec::kNoFrame; 827cb93a386Sopenharmony_ci} 828cb93a386Sopenharmony_ci 829cb93a386Sopenharmony_cistatic bool restore_bg(const SkFrame& frame) { 830cb93a386Sopenharmony_ci return frame.getDisposalMethod() == SkCodecAnimation::DisposalMethod::kRestoreBGColor; 831cb93a386Sopenharmony_ci} 832cb93a386Sopenharmony_ci 833cb93a386Sopenharmony_ci// As its name suggests, this method computes a frame's alpha (e.g. completely 834cb93a386Sopenharmony_ci// opaque, unpremul, binary) and its required frame (a preceding frame that 835cb93a386Sopenharmony_ci// this frame depends on, to draw the complete image at this frame's point in 836cb93a386Sopenharmony_ci// the animation stream), and calls this frame's setter methods with that 837cb93a386Sopenharmony_ci// computed information. 838cb93a386Sopenharmony_ci// 839cb93a386Sopenharmony_ci// A required frame of kNoFrame means that this frame is independent: drawing 840cb93a386Sopenharmony_ci// the complete image at this frame's point in the animation stream does not 841cb93a386Sopenharmony_ci// require first preparing the pixel buffer based on another frame. Instead, 842cb93a386Sopenharmony_ci// drawing can start from an uninitialized pixel buffer. 843cb93a386Sopenharmony_ci// 844cb93a386Sopenharmony_ci// "Uninitialized" is from the SkCodec's caller's point of view. In the SkCodec 845cb93a386Sopenharmony_ci// implementation, for independent frames, first party Skia code (in src/codec) 846cb93a386Sopenharmony_ci// will typically fill the buffer with a uniform background color (e.g. 847cb93a386Sopenharmony_ci// transparent black) before calling into third party codec-specific code (e.g. 848cb93a386Sopenharmony_ci// libjpeg or libpng). Pixels outside of the frame's rect will remain this 849cb93a386Sopenharmony_ci// background color after drawing this frame. For incomplete decodes, pixels 850cb93a386Sopenharmony_ci// inside that rect may be (at least temporarily) set to that background color. 851cb93a386Sopenharmony_ci// In an incremental decode, later passes may then overwrite that background 852cb93a386Sopenharmony_ci// color. 853cb93a386Sopenharmony_ci// 854cb93a386Sopenharmony_ci// Determining kNoFrame or otherwise involves testing a number of conditions 855cb93a386Sopenharmony_ci// sequentially. The first satisfied condition results in setting the required 856cb93a386Sopenharmony_ci// frame to kNoFrame (an "INDx" condition) or to a non-negative frame number (a 857cb93a386Sopenharmony_ci// "DEPx" condition), and the function returning early. Those "INDx" and "DEPx" 858cb93a386Sopenharmony_ci// labels also map to comments in the function body. 859cb93a386Sopenharmony_ci// 860cb93a386Sopenharmony_ci// - IND1: this frame is the first frame. 861cb93a386Sopenharmony_ci// - IND2: this frame fills out the whole image, and it is completely opaque 862cb93a386Sopenharmony_ci// or it overwrites (not blends with) the previous frame. 863cb93a386Sopenharmony_ci// - IND3: all preceding frames' disposals are kRestorePrevious. 864cb93a386Sopenharmony_ci// - IND4: the prevFrame's disposal is kRestoreBGColor, and it fills out the 865cb93a386Sopenharmony_ci// whole image or it is itself otherwise independent. 866cb93a386Sopenharmony_ci// - DEP5: this frame reports alpha (it is not completely opaque) and it 867cb93a386Sopenharmony_ci// blends with (not overwrites) the previous frame. 868cb93a386Sopenharmony_ci// - IND6: this frame's rect covers the rects of all preceding frames back to 869cb93a386Sopenharmony_ci// and including the most recent independent frame before this frame. 870cb93a386Sopenharmony_ci// - DEP7: unconditional. 871cb93a386Sopenharmony_ci// 872cb93a386Sopenharmony_ci// The "prevFrame" variable initially points to the previous frame (also known 873cb93a386Sopenharmony_ci// as the prior frame), but that variable may iterate further backwards over 874cb93a386Sopenharmony_ci// the course of this computation. 875cb93a386Sopenharmony_civoid SkFrameHolder::setAlphaAndRequiredFrame(SkFrame* frame) { 876cb93a386Sopenharmony_ci const bool reportsAlpha = frame->reportedAlpha() != SkEncodedInfo::kOpaque_Alpha; 877cb93a386Sopenharmony_ci const auto screenRect = SkIRect::MakeWH(fScreenWidth, fScreenHeight); 878cb93a386Sopenharmony_ci const auto frameRect = frame_rect_on_screen(frame->frameRect(), screenRect); 879cb93a386Sopenharmony_ci 880cb93a386Sopenharmony_ci const int i = frame->frameId(); 881cb93a386Sopenharmony_ci if (0 == i) { 882cb93a386Sopenharmony_ci frame->setHasAlpha(reportsAlpha || frameRect != screenRect); 883cb93a386Sopenharmony_ci frame->setRequiredFrame(SkCodec::kNoFrame); // IND1 884cb93a386Sopenharmony_ci return; 885cb93a386Sopenharmony_ci } 886cb93a386Sopenharmony_ci 887cb93a386Sopenharmony_ci 888cb93a386Sopenharmony_ci const bool blendWithPrevFrame = frame->getBlend() == SkCodecAnimation::Blend::kSrcOver; 889cb93a386Sopenharmony_ci if ((!reportsAlpha || !blendWithPrevFrame) && frameRect == screenRect) { 890cb93a386Sopenharmony_ci frame->setHasAlpha(reportsAlpha); 891cb93a386Sopenharmony_ci frame->setRequiredFrame(SkCodec::kNoFrame); // IND2 892cb93a386Sopenharmony_ci return; 893cb93a386Sopenharmony_ci } 894cb93a386Sopenharmony_ci 895cb93a386Sopenharmony_ci const SkFrame* prevFrame = this->getFrame(i-1); 896cb93a386Sopenharmony_ci while (prevFrame->getDisposalMethod() == SkCodecAnimation::DisposalMethod::kRestorePrevious) { 897cb93a386Sopenharmony_ci const int prevId = prevFrame->frameId(); 898cb93a386Sopenharmony_ci if (0 == prevId) { 899cb93a386Sopenharmony_ci frame->setHasAlpha(true); 900cb93a386Sopenharmony_ci frame->setRequiredFrame(SkCodec::kNoFrame); // IND3 901cb93a386Sopenharmony_ci return; 902cb93a386Sopenharmony_ci } 903cb93a386Sopenharmony_ci 904cb93a386Sopenharmony_ci prevFrame = this->getFrame(prevId - 1); 905cb93a386Sopenharmony_ci } 906cb93a386Sopenharmony_ci 907cb93a386Sopenharmony_ci const bool clearPrevFrame = restore_bg(*prevFrame); 908cb93a386Sopenharmony_ci auto prevFrameRect = frame_rect_on_screen(prevFrame->frameRect(), screenRect); 909cb93a386Sopenharmony_ci 910cb93a386Sopenharmony_ci if (clearPrevFrame) { 911cb93a386Sopenharmony_ci if (prevFrameRect == screenRect || independent(*prevFrame)) { 912cb93a386Sopenharmony_ci frame->setHasAlpha(true); 913cb93a386Sopenharmony_ci frame->setRequiredFrame(SkCodec::kNoFrame); // IND4 914cb93a386Sopenharmony_ci return; 915cb93a386Sopenharmony_ci } 916cb93a386Sopenharmony_ci } 917cb93a386Sopenharmony_ci 918cb93a386Sopenharmony_ci if (reportsAlpha && blendWithPrevFrame) { 919cb93a386Sopenharmony_ci // Note: We could be more aggressive here. If prevFrame clears 920cb93a386Sopenharmony_ci // to background color and covers its required frame (and that 921cb93a386Sopenharmony_ci // frame is independent), prevFrame could be marked independent. 922cb93a386Sopenharmony_ci // Would this extra complexity be worth it? 923cb93a386Sopenharmony_ci frame->setRequiredFrame(prevFrame->frameId()); // DEP5 924cb93a386Sopenharmony_ci frame->setHasAlpha(prevFrame->hasAlpha() || clearPrevFrame); 925cb93a386Sopenharmony_ci return; 926cb93a386Sopenharmony_ci } 927cb93a386Sopenharmony_ci 928cb93a386Sopenharmony_ci while (frameRect.contains(prevFrameRect)) { 929cb93a386Sopenharmony_ci const int prevRequiredFrame = prevFrame->getRequiredFrame(); 930cb93a386Sopenharmony_ci if (prevRequiredFrame == SkCodec::kNoFrame) { 931cb93a386Sopenharmony_ci frame->setRequiredFrame(SkCodec::kNoFrame); // IND6 932cb93a386Sopenharmony_ci frame->setHasAlpha(true); 933cb93a386Sopenharmony_ci return; 934cb93a386Sopenharmony_ci } 935cb93a386Sopenharmony_ci 936cb93a386Sopenharmony_ci prevFrame = this->getFrame(prevRequiredFrame); 937cb93a386Sopenharmony_ci prevFrameRect = frame_rect_on_screen(prevFrame->frameRect(), screenRect); 938cb93a386Sopenharmony_ci } 939cb93a386Sopenharmony_ci 940cb93a386Sopenharmony_ci frame->setRequiredFrame(prevFrame->frameId()); // DEP7 941cb93a386Sopenharmony_ci if (restore_bg(*prevFrame)) { 942cb93a386Sopenharmony_ci frame->setHasAlpha(true); 943cb93a386Sopenharmony_ci return; 944cb93a386Sopenharmony_ci } 945cb93a386Sopenharmony_ci SkASSERT(prevFrame->getDisposalMethod() == SkCodecAnimation::DisposalMethod::kKeep); 946cb93a386Sopenharmony_ci frame->setHasAlpha(prevFrame->hasAlpha() || (reportsAlpha && !blendWithPrevFrame)); 947cb93a386Sopenharmony_ci} 948cb93a386Sopenharmony_ci 949