aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ports
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2016-03-24 04:45:39 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-03-24 04:45:39 -0700
commit910f7ec7e79cd051f69b47c3e19d4fda2adbcef4 (patch)
treeff5cd50c65edb6e3b77f77327165ad0162557137 /src/ports
parentf037fdebda2a2626e6512d7532063f2cd41a264d (diff)
Revert of Delete SkImageDecoder (patchset #9 id:150001 of https://codereview.chromium.org/1820503002/ )
Reason for revert: Roll still failing Original issue's description: > Delete SkImageDecoder > > This image decoding implementation has been replaced > by SkCodec in Android. > > Additionally, we have replaced uses of SkImageDecoder > in Skia and Google3 with uses of SkCodec. > > Now we can delete SkImageDecoder :). > > BUG=skia: > GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1820503002 > CQ_EXTRA_TRYBOTS=client.skia.compile:Build-Ubuntu-GCC-x86_64-Release-CMake-Trybot,Build-Mac-Clang-x86_64-Release-CMake-Trybot > > Committed: https://skia.googlesource.com/skia/+/f799706656f2581c5bf5510d94df3fa17cce1607 > > Committed: https://skia.googlesource.com/skia/+/5b6e73e0c8282c4d85accbfbcecc6dee84f8a1eb > > Committed: https://skia.googlesource.com/skia/+/f037fdebda2a2626e6512d7532063f2cd41a264d TBR=scroggo@google.com,djsollen@google.com # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=skia: Review URL: https://codereview.chromium.org/1830943002
Diffstat (limited to 'src/ports')
-rw-r--r--src/ports/SkImageDecoder_CG.cpp255
-rw-r--r--src/ports/SkImageDecoder_WIC.cpp232
-rw-r--r--src/ports/SkImageDecoder_empty.cpp63
3 files changed, 542 insertions, 8 deletions
diff --git a/src/ports/SkImageDecoder_CG.cpp b/src/ports/SkImageDecoder_CG.cpp
index ead0ed6506..c4446ae16d 100644
--- a/src/ports/SkImageDecoder_CG.cpp
+++ b/src/ports/SkImageDecoder_CG.cpp
@@ -11,6 +11,7 @@
#include "SkCGUtils.h"
#include "SkColorPriv.h"
#include "SkData.h"
+#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
#include "SkMovie.h"
#include "SkStream.h"
@@ -28,6 +29,210 @@
#include <MobileCoreServices/MobileCoreServices.h>
#endif
+static void data_unref_proc(void* skdata, const void*, size_t) {
+ SkASSERT(skdata);
+ static_cast<SkData*>(skdata)->unref();
+}
+
+static CGDataProviderRef SkStreamToDataProvider(SkStream* stream) {
+ // TODO: use callbacks, so we don't have to load all the data into RAM
+ SkData* skdata = SkCopyStreamToData(stream).release();
+ if (!skdata) {
+ return nullptr;
+ }
+
+ return CGDataProviderCreateWithData(skdata, skdata->data(), skdata->size(), data_unref_proc);
+}
+
+static CGImageSourceRef SkStreamToCGImageSource(SkStream* stream) {
+ CGDataProviderRef data = SkStreamToDataProvider(stream);
+ if (!data) {
+ return nullptr;
+ }
+ CGImageSourceRef imageSrc = CGImageSourceCreateWithDataProvider(data, 0);
+ CGDataProviderRelease(data);
+ return imageSrc;
+}
+
+class SkImageDecoder_CG : public SkImageDecoder {
+protected:
+ virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode);
+};
+
+static void argb_4444_force_opaque(void* row, int count) {
+ uint16_t* row16 = (uint16_t*)row;
+ for (int i = 0; i < count; ++i) {
+ row16[i] |= 0xF000;
+ }
+}
+
+static void argb_8888_force_opaque(void* row, int count) {
+ // can use RGBA or BGRA, they have the same shift for alpha
+ const uint32_t alphaMask = 0xFF << SK_RGBA_A32_SHIFT;
+ uint32_t* row32 = (uint32_t*)row;
+ for (int i = 0; i < count; ++i) {
+ row32[i] |= alphaMask;
+ }
+}
+
+static void alpha_8_force_opaque(void* row, int count) {
+ memset(row, 0xFF, count);
+}
+
+static void force_opaque(SkBitmap* bm) {
+ SkAutoLockPixels alp(*bm);
+ if (!bm->getPixels()) {
+ return;
+ }
+
+ void (*proc)(void*, int);
+ switch (bm->colorType()) {
+ case kARGB_4444_SkColorType:
+ proc = argb_4444_force_opaque;
+ break;
+ case kRGBA_8888_SkColorType:
+ case kBGRA_8888_SkColorType:
+ proc = argb_8888_force_opaque;
+ break;
+ case kAlpha_8_SkColorType:
+ proc = alpha_8_force_opaque;
+ break;
+ default:
+ return;
+ }
+
+ char* row = (char*)bm->getPixels();
+ for (int y = 0; y < bm->height(); ++y) {
+ proc(row, bm->width());
+ row += bm->rowBytes();
+ }
+ bm->setAlphaType(kOpaque_SkAlphaType);
+}
+
+#define BITMAP_INFO (kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast)
+
+class AutoCFDataRelease {
+ CFDataRef fDR;
+public:
+ AutoCFDataRelease(CFDataRef dr) : fDR(dr) {}
+ ~AutoCFDataRelease() { if (fDR) { CFRelease(fDR); } }
+
+ operator CFDataRef () { return fDR; }
+};
+
+static bool colorspace_is_sRGB(CGColorSpaceRef cs) {
+#ifdef SK_BUILD_FOR_IOS
+ return true; // iOS seems to define itself to always return sRGB <reed>
+#else
+ AutoCFDataRelease data(CGColorSpaceCopyICCProfile(cs));
+ if (data) {
+ // found by inspection -- need a cleaner way to sniff a profile
+ const CFIndex ICC_PROFILE_OFFSET_TO_SRGB_TAG = 52;
+
+ if (CFDataGetLength(data) >= ICC_PROFILE_OFFSET_TO_SRGB_TAG + 4) {
+ return !memcmp(CFDataGetBytePtr(data) + ICC_PROFILE_OFFSET_TO_SRGB_TAG, "sRGB", 4);
+ }
+ }
+ return false;
+#endif
+}
+
+SkImageDecoder::Result SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
+ CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream);
+
+ if (nullptr == imageSrc) {
+ return kFailure;
+ }
+ SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc);
+
+ CGImageRef image = CGImageSourceCreateImageAtIndex(imageSrc, 0, nullptr);
+ if (nullptr == image) {
+ return kFailure;
+ }
+ SkAutoTCallVProc<CGImage, CGImageRelease> arimage(image);
+
+ const int width = SkToInt(CGImageGetWidth(image));
+ const int height = SkToInt(CGImageGetHeight(image));
+ SkColorProfileType cpType = kLinear_SkColorProfileType;
+
+ CGColorSpaceRef cs = CGImageGetColorSpace(image);
+ if (cs) {
+ CGColorSpaceModel m = CGColorSpaceGetModel(cs);
+ if (kCGColorSpaceModelRGB == m && colorspace_is_sRGB(cs)) {
+ cpType = kSRGB_SkColorProfileType;
+ }
+ }
+
+ SkAlphaType at = kPremul_SkAlphaType;
+ switch (CGImageGetAlphaInfo(image)) {
+ case kCGImageAlphaNone:
+ case kCGImageAlphaNoneSkipLast:
+ case kCGImageAlphaNoneSkipFirst:
+ at = kOpaque_SkAlphaType;
+ break;
+ default:
+ break;
+ }
+
+ bm->setInfo(SkImageInfo::Make(width, height, kN32_SkColorType, at, cpType));
+ if (SkImageDecoder::kDecodeBounds_Mode == mode) {
+ return kSuccess;
+ }
+
+ if (!this->allocPixelRef(bm, nullptr)) {
+ return kFailure;
+ }
+
+ SkAutoLockPixels alp(*bm);
+
+ if (!SkCopyPixelsFromCGImage(bm->info(), bm->rowBytes(), bm->getPixels(), image)) {
+ return kFailure;
+ }
+
+ CGImageAlphaInfo info = CGImageGetAlphaInfo(image);
+ switch (info) {
+ case kCGImageAlphaNone:
+ case kCGImageAlphaNoneSkipLast:
+ case kCGImageAlphaNoneSkipFirst:
+ // We're opaque, but we can't rely on the data always having 0xFF
+ // in the alpha slot (which Skia wants), so we have to ram it in
+ // ourselves.
+ force_opaque(bm);
+ break;
+ default:
+ // we don't know if we're opaque or not, so compute it.
+ if (SkBitmap::ComputeIsOpaque(*bm)) {
+ bm->setAlphaType(kOpaque_SkAlphaType);
+ }
+ }
+ if (!bm->isOpaque() && this->getRequireUnpremultipliedColors()) {
+ // CGBitmapContext does not support unpremultiplied, so the image has been premultiplied.
+ // Convert to unpremultiplied.
+ for (int i = 0; i < width; ++i) {
+ for (int j = 0; j < height; ++j) {
+ uint32_t* addr = bm->getAddr32(i, j);
+ *addr = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(*addr);
+ }
+ }
+ bm->setAlphaType(kUnpremul_SkAlphaType);
+ }
+ return kSuccess;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*);
+
+SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) {
+ SkImageDecoder* decoder = image_decoder_from_stream(stream);
+ if (nullptr == decoder) {
+ // If no image decoder specific to the stream exists, use SkImageDecoder_CG.
+ return new SkImageDecoder_CG;
+ } else {
+ return decoder;
+ }
+}
+
/////////////////////////////////////////////////////////////////////////
SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
@@ -150,13 +355,57 @@ static SkImageEncoder* sk_imageencoder_cg_factory(SkImageEncoder::Type t) {
static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_cg_factory);
-class SkPNGImageEncoder_CG : public SkImageEncoder_CG {
+#ifdef SK_BUILD_FOR_IOS
+class SkPNGImageEncoder_IOS : public SkImageEncoder_CG {
public:
- SkPNGImageEncoder_CG()
+ SkPNGImageEncoder_IOS()
: SkImageEncoder_CG(kPNG_Type) {
}
};
-DEFINE_ENCODER_CREATOR(PNGImageEncoder_CG);
+DEFINE_ENCODER_CREATOR(PNGImageEncoder_IOS);
+#endif
+
+struct FormatConversion {
+ CFStringRef fUTType;
+ SkImageDecoder::Format fFormat;
+};
+
+// Array of the types supported by the decoder.
+static const FormatConversion gFormatConversions[] = {
+ { kUTTypeBMP, SkImageDecoder::kBMP_Format },
+ { kUTTypeGIF, SkImageDecoder::kGIF_Format },
+ { kUTTypeICO, SkImageDecoder::kICO_Format },
+ { kUTTypeJPEG, SkImageDecoder::kJPEG_Format },
+ // Also include JPEG2000
+ { kUTTypeJPEG2000, SkImageDecoder::kJPEG_Format },
+ { kUTTypePNG, SkImageDecoder::kPNG_Format },
+};
+
+static SkImageDecoder::Format UTType_to_Format(const CFStringRef uttype) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) {
+ if (CFStringCompare(uttype, gFormatConversions[i].fUTType, 0) == kCFCompareEqualTo) {
+ return gFormatConversions[i].fFormat;
+ }
+ }
+ return SkImageDecoder::kUnknown_Format;
+}
+
+static SkImageDecoder::Format get_format_cg(SkStreamRewindable* stream) {
+ CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream);
+
+ if (nullptr == imageSrc) {
+ return SkImageDecoder::kUnknown_Format;
+ }
+
+ SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc);
+ const CFStringRef name = CGImageSourceGetType(imageSrc);
+ if (nullptr == name) {
+ return SkImageDecoder::kUnknown_Format;
+ }
+ return UTType_to_Format(name);
+}
+
+static SkImageDecoder_FormatReg gFormatReg(get_format_cg);
#endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
diff --git a/src/ports/SkImageDecoder_WIC.cpp b/src/ports/SkImageDecoder_WIC.cpp
index 43068fc8f6..5febd856d6 100644
--- a/src/ports/SkImageDecoder_WIC.cpp
+++ b/src/ports/SkImageDecoder_WIC.cpp
@@ -31,6 +31,7 @@
#include <wincodec.h>
#include "SkAutoCoInitialize.h"
+#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
#include "SkIStream.h"
#include "SkMovie.h"
@@ -47,6 +48,222 @@
#undef CLSID_WICImagingFactory
#endif
+class SkImageDecoder_WIC : public SkImageDecoder {
+public:
+ // Decoding modes corresponding to SkImageDecoder::Mode, plus an extra mode for decoding
+ // only the format.
+ enum WICModes {
+ kDecodeFormat_WICMode,
+ kDecodeBounds_WICMode,
+ kDecodePixels_WICMode,
+ };
+
+ /**
+ * Helper function to decode an SkStream.
+ * @param stream SkStream to decode. Must be at the beginning.
+ * @param bm SkBitmap to decode into. Only used if wicMode is kDecodeBounds_WICMode or
+ * kDecodePixels_WICMode, in which case it must not be nullptr.
+ * @param format Out parameter for the SkImageDecoder::Format of the SkStream. Only used if
+ * wicMode is kDecodeFormat_WICMode.
+ */
+ bool decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, Format* format) const;
+
+protected:
+ Result onDecode(SkStream* stream, SkBitmap* bm, Mode mode) override;
+};
+
+struct FormatConversion {
+ GUID fGuidFormat;
+ SkImageDecoder::Format fFormat;
+};
+
+static const FormatConversion gFormatConversions[] = {
+ { GUID_ContainerFormatBmp, SkImageDecoder::kBMP_Format },
+ { GUID_ContainerFormatGif, SkImageDecoder::kGIF_Format },
+ { GUID_ContainerFormatIco, SkImageDecoder::kICO_Format },
+ { GUID_ContainerFormatJpeg, SkImageDecoder::kJPEG_Format },
+ { GUID_ContainerFormatPng, SkImageDecoder::kPNG_Format },
+};
+
+static SkImageDecoder::Format GuidContainerFormat_to_Format(REFGUID guid) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) {
+ if (IsEqualGUID(guid, gFormatConversions[i].fGuidFormat)) {
+ return gFormatConversions[i].fFormat;
+ }
+ }
+ return SkImageDecoder::kUnknown_Format;
+}
+
+SkImageDecoder::Result SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
+ WICModes wicMode;
+ switch (mode) {
+ case SkImageDecoder::kDecodeBounds_Mode:
+ wicMode = kDecodeBounds_WICMode;
+ break;
+ case SkImageDecoder::kDecodePixels_Mode:
+ wicMode = kDecodePixels_WICMode;
+ break;
+ }
+ return this->decodeStream(stream, bm, wicMode, nullptr) ? kSuccess : kFailure;
+}
+
+bool SkImageDecoder_WIC::decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode,
+ Format* format) const {
+ //Initialize COM.
+ SkAutoCoInitialize scopedCo;
+ if (!scopedCo.succeeded()) {
+ return false;
+ }
+
+ HRESULT hr = S_OK;
+
+ //Create Windows Imaging Component ImagingFactory.
+ SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
+ if (SUCCEEDED(hr)) {
+ hr = CoCreateInstance(
+ CLSID_WICImagingFactory
+ , nullptr
+ , CLSCTX_INPROC_SERVER
+ , IID_PPV_ARGS(&piImagingFactory)
+ );
+ }
+
+ //Convert SkStream to IStream.
+ SkTScopedComPtr<IStream> piStream;
+ if (SUCCEEDED(hr)) {
+ hr = SkIStream::CreateFromSkStream(stream, false, &piStream);
+ }
+
+ //Make sure we're at the beginning of the stream.
+ if (SUCCEEDED(hr)) {
+ LARGE_INTEGER liBeginning = { 0 };
+ hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, nullptr);
+ }
+
+ //Create the decoder from the stream content.
+ SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder;
+ if (SUCCEEDED(hr)) {
+ hr = piImagingFactory->CreateDecoderFromStream(
+ piStream.get() //Image to be decoded
+ , nullptr //No particular vendor
+ , WICDecodeMetadataCacheOnDemand //Cache metadata when needed
+ , &piBitmapDecoder //Pointer to the decoder
+ );
+ }
+
+ if (kDecodeFormat_WICMode == wicMode) {
+ SkASSERT(format != nullptr);
+ //Get the format
+ if (SUCCEEDED(hr)) {
+ GUID guidFormat;
+ hr = piBitmapDecoder->GetContainerFormat(&guidFormat);
+ if (SUCCEEDED(hr)) {
+ *format = GuidContainerFormat_to_Format(guidFormat);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ //Get the first frame from the decoder.
+ SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode;
+ if (SUCCEEDED(hr)) {
+ hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode);
+ }
+
+ //Get the BitmapSource interface of the frame.
+ SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal;
+ if (SUCCEEDED(hr)) {
+ hr = piBitmapFrameDecode->QueryInterface(
+ IID_PPV_ARGS(&piBitmapSourceOriginal)
+ );
+ }
+
+ //Get the size of the bitmap.
+ UINT width;
+ UINT height;
+ if (SUCCEEDED(hr)) {
+ hr = piBitmapSourceOriginal->GetSize(&width, &height);
+ }
+
+ //Exit early if we're only looking for the bitmap bounds.
+ if (SUCCEEDED(hr)) {
+ bm->setInfo(SkImageInfo::MakeN32Premul(width, height));
+ if (kDecodeBounds_WICMode == wicMode) {
+ return true;
+ }
+ if (!this->allocPixelRef(bm, nullptr)) {
+ return false;
+ }
+ }
+
+ //Create a format converter.
+ SkTScopedComPtr<IWICFormatConverter> piFormatConverter;
+ if (SUCCEEDED(hr)) {
+ hr = piImagingFactory->CreateFormatConverter(&piFormatConverter);
+ }
+
+ GUID destinationPixelFormat;
+ if (this->getRequireUnpremultipliedColors()) {
+ destinationPixelFormat = GUID_WICPixelFormat32bppBGRA;
+ } else {
+ destinationPixelFormat = GUID_WICPixelFormat32bppPBGRA;
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = piFormatConverter->Initialize(
+ piBitmapSourceOriginal.get() //Input bitmap to convert
+ , destinationPixelFormat //Destination pixel format
+ , WICBitmapDitherTypeNone //Specified dither patterm
+ , nullptr //Specify a particular palette
+ , 0.f //Alpha threshold
+ , WICBitmapPaletteTypeCustom //Palette translation type
+ );
+ }
+
+ //Get the BitmapSource interface of the format converter.
+ SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted;
+ if (SUCCEEDED(hr)) {
+ hr = piFormatConverter->QueryInterface(
+ IID_PPV_ARGS(&piBitmapSourceConverted)
+ );
+ }
+
+ //Copy the pixels into the bitmap.
+ if (SUCCEEDED(hr)) {
+ SkAutoLockPixels alp(*bm);
+ bm->eraseColor(SK_ColorTRANSPARENT);
+ const UINT stride = (UINT) bm->rowBytes();
+ hr = piBitmapSourceConverted->CopyPixels(
+ nullptr, //Get all the pixels
+ stride,
+ stride * height,
+ reinterpret_cast<BYTE *>(bm->getPixels())
+ );
+
+ // Note: we don't need to premultiply here since we specified PBGRA
+ if (SkBitmap::ComputeIsOpaque(*bm)) {
+ bm->setAlphaType(kOpaque_SkAlphaType);
+ }
+ }
+
+ return SUCCEEDED(hr);
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*);
+
+SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) {
+ SkImageDecoder* decoder = image_decoder_from_stream(stream);
+ if (nullptr == decoder) {
+ // If no image decoder specific to the stream exists, use SkImageDecoder_WIC.
+ return new SkImageDecoder_WIC;
+ } else {
+ return decoder;
+ }
+}
+
/////////////////////////////////////////////////////////////////////////
SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
@@ -58,10 +275,6 @@ SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
class SkImageEncoder_WIC : public SkImageEncoder {
public:
SkImageEncoder_WIC(Type t) : fType(t) {}
-
- // DO NOT USE this constructor. This exists only so SkForceLinking can
- // link the WIC image encoder.
- SkImageEncoder_WIC() {}
protected:
virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
@@ -241,6 +454,15 @@ static SkImageEncoder* sk_imageencoder_wic_factory(SkImageEncoder::Type t) {
static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_wic_factory);
-DEFINE_ENCODER_CREATOR(ImageEncoder_WIC);
+static SkImageDecoder::Format get_format_wic(SkStreamRewindable* stream) {
+ SkImageDecoder::Format format;
+ SkImageDecoder_WIC codec;
+ if (!codec.decodeStream(stream, nullptr, SkImageDecoder_WIC::kDecodeFormat_WICMode, &format)) {
+ format = SkImageDecoder::kUnknown_Format;
+ }
+ return format;
+}
+
+static SkImageDecoder_FormatReg gFormatReg(get_format_wic);
#endif // defined(SK_BUILD_FOR_WIN32)
diff --git a/src/ports/SkImageDecoder_empty.cpp b/src/ports/SkImageDecoder_empty.cpp
index 33e07acea6..f52dada73b 100644
--- a/src/ports/SkImageDecoder_empty.cpp
+++ b/src/ports/SkImageDecoder_empty.cpp
@@ -8,11 +8,74 @@
#include "SkBitmap.h"
#include "SkImage.h"
+#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
#include "SkMovie.h"
#include "SkPixelSerializer.h"
#include "SkStream.h"
+class SkColorTable;
+class SkPngChunkReader;
+
+// Empty implementations for SkImageDecoder.
+
+SkImageDecoder::SkImageDecoder() {}
+
+SkImageDecoder::~SkImageDecoder() {}
+
+SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable*) {
+ return nullptr;
+}
+
+void SkImageDecoder::copyFieldsToOther(SkImageDecoder* ) {}
+
+bool SkImageDecoder::DecodeFile(const char[], SkBitmap*, SkColorType, Mode, Format*) {
+ return false;
+}
+
+SkImageDecoder::Result SkImageDecoder::decode(SkStream*, SkBitmap*, SkColorType, Mode) {
+ return kFailure;
+}
+
+bool SkImageDecoder::DecodeStream(SkStreamRewindable*, SkBitmap*, SkColorType, Mode, Format*) {
+ return false;
+}
+
+bool SkImageDecoder::DecodeMemory(const void*, size_t, SkBitmap*, SkColorType, Mode, Format*) {
+ return false;
+}
+
+bool SkImageDecoder::decodeYUV8Planes(SkStream*, SkISize[3], void*[3],
+ size_t[3], SkYUVColorSpace*) {
+ return false;
+}
+
+SkImageDecoder::Format SkImageDecoder::getFormat() const {
+ return kUnknown_Format;
+}
+
+SkImageDecoder::Format SkImageDecoder::GetStreamFormat(SkStreamRewindable*) {
+ return kUnknown_Format;
+}
+
+const char* SkImageDecoder::GetFormatName(Format) {
+ return nullptr;
+}
+
+SkPngChunkReader* SkImageDecoder::setPeeker(SkPngChunkReader*) {
+ return nullptr;
+}
+
+SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator*) {
+ return nullptr;
+}
+
+void SkImageDecoder::setSampleSize(int) {}
+
+bool SkImageDecoder::allocPixelRef(SkBitmap*, SkColorTable*) const {
+ return false;
+}
+
/////////////////////////////////////////////////////////////////////////
// Empty implementation for SkMovie.