Add SkCodec, including PNG implementation.
DM:
Add a flag to use SkCodec instead of SkImageDecoder.
SkCodec:
Base class for codecs, allowing creation from an SkStream or an SkData.
An SkCodec, on creation, knows properties of the data like its width and height. Further calls can be used to generate the image.
TODO: Add scanline iterator
SkPngCodec:
New decoder for png. Wraps libpng. The code has been repurposed from SkImageDecoder_libpng.
TODO: Handle other destination colortypes
TODO: Substitute the transpose color
TODO: Allow silencing warnings
TODO: Use RGB instead of filler?
TODO: sRGB
SkSwizzler:
Simplified version of SkScaledSampler. Unlike the sampler, this object does no sampling.
TODO: Implement other swizzles.
Requires a gclient sync to pull down libpng.
BUG=skia:3257
Committed: https://skia.googlesource.com/skia/+/ca358852b4fed656d11107b2aaf28318a4518b49
(and then reverted)
Review URL: https://codereview.chromium.org/930283002
diff --git a/DEPS b/DEPS
index 3c16bd9..15917a9 100644
--- a/DEPS
+++ b/DEPS
@@ -9,15 +9,17 @@
# - both Android and ChromeOS pull the same giflib;
# - can use use our existing t_p/e/libjpeg instead of pulling it for Android?
- "third_party/externals/angle2" : "https://chromium.googlesource.com/angle/angle.git@c415283b2bcd786e1a8c55c19ef3511eb2b3928c",
- "third_party/externals/freetype" : "https://skia.googlesource.com/third_party/freetype2.git@VER-2-5-0-1",
- "third_party/externals/gyp" : "https://chromium.googlesource.com/external/gyp.git@dd831fd86e7a254c696f53944333562466e453ad",
+ "third_party/externals/angle2" : "https://chromium.googlesource.com/angle/angle.git@c415283b2bcd786e1a8c55c19ef3511eb2b3928c",
+ "third_party/externals/freetype": "https://skia.googlesource.com/third_party/freetype2.git@VER-2-5-0-1",
+ "third_party/externals/gyp" : "https://chromium.googlesource.com/external/gyp.git@dd831fd86e7a254c696f53944333562466e453ad",
"third_party/externals/harfbuzz": "https://skia.googlesource.com/third_party/harfbuzz.git@0.9.35",
"third_party/externals/jsoncpp" : "https://chromium.googlesource.com/external/jsoncpp/jsoncpp.git@1afff032c83e26ddf7f2776e8b43de5ad666c1fa",
"third_party/externals/libjpeg" : "https://chromium.googlesource.com/chromium/deps/libjpeg_turbo.git@82ce8a6d4ebe12a177c0c3597192f2b4f09e81c3",
"third_party/externals/libwebp" : "https://chromium.googlesource.com/webm/libwebp.git@3fe91635df8734b23f3c1b9d1f0c4fa8cfaf4e39",
"third_party/externals/nanomsg" : "https://skia.googlesource.com/third_party/nanomsg.git@0.4-beta",
"third_party/externals/zlib" : "https://chromium.googlesource.com/chromium/src/third_party/zlib@4ba7cdd0e7bf49d671645264f839838fc56e1492",
+ # NOTE: If we update libpng, we may need to update the generated file at third_party/libpng/pnglibconf.h
+ "third_party/externals/libpng" : "git://git.code.sf.net/p/libpng/code@070a616b8275277e18ef8ee91e2ca23f7bdc67d5",
"platform_tools/android/third_party/externals/expat" : "https://android.googlesource.com/platform/external/expat.git@android-4.2.2_r1.2",
"platform_tools/android/third_party/externals/gif" : "https://android.googlesource.com/platform/external/giflib.git@android-4.2.2_r1.2",
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index e67d435..67f8ac6 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -1,6 +1,7 @@
#include "DMSrcSink.h"
#include "SamplePipeControllers.h"
#include "SkCommonFlags.h"
+#include "SkCodec.h"
#include "SkDocument.h"
#include "SkError.h"
#include "SkMultiPictureDraw.h"
@@ -12,6 +13,8 @@
#include "SkStream.h"
#include "SkXMLWriter.h"
+DEFINE_bool(codec, false, "Use SkCodec instead of SkImageDecoder");
+
namespace DM {
GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {}
@@ -46,9 +49,35 @@
if (fDivisor == 0) {
// Decode the full image.
SkBitmap bitmap;
- if (!SkImageDecoder::DecodeMemory(encoded->data(), encoded->size(), &bitmap,
- dstColorType, SkImageDecoder::kDecodePixels_Mode)) {
- return SkStringPrintf("Couldn't decode %s.", fPath.c_str());
+ if (FLAGS_codec) {
+ SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
+ if (!codec) {
+ return SkStringPrintf("Couldn't decode %s.", fPath.c_str());
+ }
+ SkImageInfo info;
+ if (!codec->getInfo(&info)) {
+ return SkStringPrintf("Couldn't getInfo %s.", fPath.c_str());
+ }
+ info = info.makeColorType(dstColorType);
+ if (info.alphaType() == kUnpremul_SkAlphaType) {
+ // FIXME: Currently we cannot draw unpremultiplied sources.
+ info = info.makeAlphaType(kPremul_SkAlphaType);
+ }
+ if (!bitmap.tryAllocPixels(info)) {
+ return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(),
+ info.width(), info.height());
+ }
+ SkAutoLockPixels alp(bitmap);
+ const SkImageGenerator::Result result = codec->getPixels(info, bitmap.getPixels(),
+ bitmap.rowBytes());
+ if (result != SkImageGenerator::kSuccess) {
+ return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
+ }
+ } else {
+ if (!SkImageDecoder::DecodeMemory(encoded->data(), encoded->size(), &bitmap,
+ dstColorType, SkImageDecoder::kDecodePixels_Mode)) {
+ return SkStringPrintf("Couldn't decode %s.", fPath.c_str());
+ }
}
encoded.reset((SkData*)NULL); // Might as well drop this when we're done with it.
canvas->drawBitmap(bitmap, 0,0);
diff --git a/gyp/codec.gyp b/gyp/codec.gyp
new file mode 100644
index 0000000..b962799
--- /dev/null
+++ b/gyp/codec.gyp
@@ -0,0 +1,29 @@
+# GYP file for codec project.
+{
+ 'targets': [
+ {
+ 'target_name': 'codec',
+ 'product_name': 'skia_codec',
+ 'type': 'static_library',
+ 'standalone_static_library': 1,
+ 'dependencies': [
+ 'core.gyp:*',
+ 'libpng.gyp:libpng',
+ ],
+ 'include_dirs': [
+ '../include/codec',
+ '../src/codec',
+ ],
+ 'sources': [
+ '../src/codec/SkCodec.cpp',
+ '../src/codec/SkCodec_libpng.cpp',
+ '../src/codec/SkSwizzler.cpp',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../include/codec',
+ ],
+ },
+ },
+ ],
+}
diff --git a/gyp/common_variables.gypi b/gyp/common_variables.gypi
index 9750187..d089512 100644
--- a/gyp/common_variables.gypi
+++ b/gyp/common_variables.gypi
@@ -76,10 +76,16 @@
'skia_os%': 'android',
'skia_chrome_utils%': 0,
'skia_use_system_json%': 1,
+ # skia_libpng_static - instead of linking libpng with '-lpng' and
+ # including the headers from '/usr/include/png.h', compile and
+ # statically link the version of libpng in
+ # third_party/externals/libpng.
+ 'skia_libpng_static%': '0',
}, {
'skia_os%': '<(skia_os)',
'skia_chrome_utils%': 1,
'skia_use_system_json%': 0,
+ 'skia_libpng_static%': '1',
}],
[ 'skia_os == "win"', {
'os_posix%': 0,
@@ -129,11 +135,6 @@
# giflib in third_party/externals/giflib.
'skia_giflib_static%': '0',
- # skia_libpng_static - on OS variants that normally would link libpng
- # with '-lpng' and include the headers from '/usr/include/png.h',
- # don't do that; instead compile and staticlly link the version of
- # libpng in third_party/externals/libpng.
- 'skia_libpng_static%': '0',
# skia_no_fontconfig - On POSIX systems that would normally use the
# SkFontHost_fontconfig interface; use the SkFontHost_linux
diff --git a/gyp/libpng.gyp b/gyp/libpng.gyp
index 92ff8d5..1ca6eef 100644
--- a/gyp/libpng.gyp
+++ b/gyp/libpng.gyp
@@ -16,6 +16,8 @@
'type': 'static_library',
'include_dirs': [
'../third_party/externals/libpng',
+ # Needed for generated pnglibconf.h
+ '../third_party/libpng',
],
'dependencies': [
'zlib.gyp:zlib',
@@ -26,16 +28,27 @@
'direct_dependent_settings': {
'include_dirs': [
'../third_party/externals/libpng',
+ # Needed for generated pnglibconf.h
+ '../third_party/libpng',
],
},
'cflags': [
'-w',
'-fvisibility=hidden',
],
+ 'conditions': [
+ ['not arm_neon', {
+ 'defines': [
+ # FIXME: Why is this needed? Without it, pngpriv.h sets it
+ # to 2 if __ARM_NEON is defined, but shouldn't __ARM_NEON
+ # not be defined since arm_neon is 0?
+ 'PNG_ARM_NEON_OPT=0',
+ ],
+ }],
+ ],
'sources': [
'../third_party/externals/libpng/png.c',
'../third_party/externals/libpng/pngerror.c',
- '../third_party/externals/libpng/pnggccrd.c',
'../third_party/externals/libpng/pngget.c',
'../third_party/externals/libpng/pngmem.c',
'../third_party/externals/libpng/pngpread.c',
@@ -45,7 +58,6 @@
'../third_party/externals/libpng/pngrutil.c',
'../third_party/externals/libpng/pngset.c',
'../third_party/externals/libpng/pngtrans.c',
- '../third_party/externals/libpng/pngvcrd.c',
'../third_party/externals/libpng/pngwio.c',
'../third_party/externals/libpng/pngwrite.c',
'../third_party/externals/libpng/pngwtran.c',
diff --git a/gyp/skia_lib.gyp b/gyp/skia_lib.gyp
index cc4984a..80d4f8f 100644
--- a/gyp/skia_lib.gyp
+++ b/gyp/skia_lib.gyp
@@ -4,6 +4,7 @@
'variables': {
'component_libs': [
'core.gyp:core',
+ 'codec.gyp:codec',
'effects.gyp:effects',
'images.gyp:images',
'opts.gyp:opts',
diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h
new file mode 100644
index 0000000..beb9cb9
--- /dev/null
+++ b/include/codec/SkCodec.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkCodec_DEFINED
+#define SkCodec_DEFINED
+
+#include "SkImageGenerator.h"
+#include "SkImageInfo.h"
+#include "SkSize.h"
+#include "SkTemplates.h"
+#include "SkTypes.h"
+
+class SkData;
+class SkStream;
+
+/**
+ * Abstraction layer directly on top of an image codec.
+ */
+class SkCodec : public SkImageGenerator {
+public:
+ /**
+ * If this stream represents an encoded image that we know how to decode,
+ * return an SkCodec that can decode it. Otherwise return NULL.
+ *
+ * If NULL is returned, the stream is deleted immediately. Otherwise, the
+ * SkCodec takes ownership of it, and will delete it when done with it.
+ */
+ static SkCodec* NewFromStream(SkStream*);
+
+ /**
+ * If this data represents an encoded image that we know how to decode,
+ * return an SkCodec that can decode it. Otherwise return NULL.
+ *
+ * Will take a ref if it returns a codec, else will not affect the data.
+ */
+ static SkCodec* NewFromData(SkData*);
+
+ /**
+ * Return a size that approximately supports the desired scale factor.
+ * The codec may not be able to scale efficiently to the exact scale
+ * factor requested, so return a size that approximates that scale.
+ *
+ * FIXME: Move to SkImageGenerator?
+ */
+ SkISize getScaledDimensions(float desiredScale) const;
+
+protected:
+ SkCodec(const SkImageInfo&, SkStream*);
+
+ /**
+ * The SkAlphaType is a conservative answer. i.e. it is possible that it
+ * initially returns a non-opaque answer, but completing the decode
+ * reveals that the image is actually opaque.
+ */
+ bool onGetInfo(SkImageInfo* info) SK_OVERRIDE {
+ *info = fInfo;
+ return true;
+ }
+
+ // Helper for subclasses.
+ const SkImageInfo& getOriginalInfo() { return fInfo; }
+
+ virtual SkISize onGetScaledDimensions(float /* desiredScale */) const {
+ // By default, scaling is not supported.
+ return fInfo.dimensions();
+ }
+
+ /**
+ * If the stream was previously read, attempt to rewind.
+ * @returns:
+ * true
+ * - if the stream needed to be rewound, and the rewind
+ * succeeded.
+ * - if the stream did not need to be rewound.
+ * false
+ * - if the stream needed to be rewound, and rewind failed.
+ * Subclasses MUST call this function before reading the stream (e.g. in
+ * onGetPixels). If it returns false, onGetPixels should return
+ * kCouldNotRewind.
+ */
+ bool SK_WARN_UNUSED_RESULT rewindIfNeeded();
+
+private:
+ const SkImageInfo fInfo;
+ SkAutoTDelete<SkStream> fStream;
+ bool fNeedsRewind;
+};
+#endif // SkCodec_DEFINED
diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp
new file mode 100644
index 0000000..ec36bc7
--- /dev/null
+++ b/src/codec/SkCodec.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCodec.h"
+#include "SkData.h"
+#include "SkCodec_libpng.h"
+#include "SkStream.h"
+
+SkCodec* SkCodec::NewFromStream(SkStream* stream) {
+ if (!stream) {
+ return NULL;
+ }
+ SkAutoTDelete<SkStream> streamDeleter(stream);
+ const bool isPng = SkPngCodec::IsPng(stream);
+ // TODO: Avoid rewinding.
+ if (!stream->rewind()) {
+ return NULL;
+ }
+ if (isPng) {
+ streamDeleter.detach();
+ return SkPngCodec::NewFromStream(stream);
+ }
+ // TODO: Check other image types.
+ return NULL;
+}
+
+SkCodec* SkCodec::NewFromData(SkData* data) {
+ if (!data) {
+ return NULL;
+ }
+ return NewFromStream(SkNEW_ARGS(SkMemoryStream, (data)));
+}
+
+SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream)
+ : fInfo(info)
+ , fStream(stream)
+ , fNeedsRewind(false)
+{}
+
+bool SkCodec::rewindIfNeeded() {
+ // Store the value of fNeedsRewind so we can update it. Next read will
+ // require a rewind.
+ const bool neededRewind = fNeedsRewind;
+ fNeedsRewind = true;
+ return !neededRewind || fStream->rewind();
+}
diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp
new file mode 100644
index 0000000..8e7ee33
--- /dev/null
+++ b/src/codec/SkCodec_libpng.cpp
@@ -0,0 +1,492 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCodec_libpng.h"
+#include "SkColorPriv.h"
+#include "SkColorTable.h"
+#include "SkBitmap.h"
+#include "SkMath.h"
+#include "SkSize.h"
+#include "SkStream.h"
+#include "SkSwizzler.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Helper macros
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef png_jmpbuf
+# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
+#endif
+
+/* These were dropped in libpng >= 1.4 */
+#ifndef png_infopp_NULL
+ #define png_infopp_NULL NULL
+#endif
+
+#ifndef png_bytepp_NULL
+ #define png_bytepp_NULL NULL
+#endif
+
+#ifndef int_p_NULL
+ #define int_p_NULL NULL
+#endif
+
+#ifndef png_flush_ptr_NULL
+ #define png_flush_ptr_NULL NULL
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Callback functions
+///////////////////////////////////////////////////////////////////////////////
+
+static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
+ SkDebugf("------ png error %s\n", msg);
+ longjmp(png_jmpbuf(png_ptr), 1);
+}
+
+static void sk_read_fn(png_structp png_ptr, png_bytep data,
+ png_size_t length) {
+ SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr));
+ const size_t bytes = stream->read(data, length);
+ if (bytes != length) {
+ // FIXME: We want to report the fact that the stream was truncated.
+ // One way to do that might be to pass a enum to longjmp so setjmp can
+ // specify the failure.
+ png_error(png_ptr, "Read Error!");
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+///////////////////////////////////////////////////////////////////////////////
+
+class AutoCleanPng : public SkNoncopyable {
+public:
+ AutoCleanPng(png_structp png_ptr)
+ : fPng_ptr(png_ptr)
+ , fInfo_ptr(NULL) {}
+
+ ~AutoCleanPng() {
+ // fInfo_ptr will never be non-NULL unless fPng_ptr is.
+ if (fPng_ptr) {
+ png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : NULL;
+ png_destroy_read_struct(&fPng_ptr, info_pp, png_infopp_NULL);
+ }
+ }
+
+ void setInfoPtr(png_infop info_ptr) {
+ SkASSERT(NULL == fInfo_ptr);
+ fInfo_ptr = info_ptr;
+ }
+
+ void detach() {
+ fPng_ptr = NULL;
+ fInfo_ptr = NULL;
+ }
+
+private:
+ png_structp fPng_ptr;
+ png_infop fInfo_ptr;
+};
+#define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
+
+// call only if color_type is PALETTE. Returns true if the ctable has alpha
+static bool has_transparency_in_palette(png_structp png_ptr,
+ png_infop info_ptr) {
+ if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+ return false;
+ }
+
+ png_bytep trans;
+ int num_trans;
+ png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
+ return num_trans > 0;
+}
+
+// Method for coverting to either an SkPMColor or a similarly packed
+// unpremultiplied color.
+typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
+
+// Note: SkColorTable claims to store SkPMColors, which is not necessarily
+// the case here.
+SkColorTable* decode_palette(png_structp png_ptr, png_infop info_ptr,
+ bool premultiply, SkAlphaType* outAlphaType) {
+ SkASSERT(outAlphaType != NULL);
+ int numPalette;
+ png_colorp palette;
+ png_bytep trans;
+
+ if (!png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette)) {
+ return NULL;
+ }
+
+ /* BUGGY IMAGE WORKAROUND
+
+ We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count
+ which is a problem since we use the byte as an index. To work around this we grow
+ the colortable by 1 (if its < 256) and duplicate the last color into that slot.
+ */
+ const int colorCount = numPalette + (numPalette < 256);
+ // Note: These are not necessarily SkPMColors.
+ SkPMColor colorStorage[256]; // worst-case storage
+ SkPMColor* colorPtr = colorStorage;
+
+ int numTrans;
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+ png_get_tRNS(png_ptr, info_ptr, &trans, &numTrans, NULL);
+ } else {
+ numTrans = 0;
+ }
+
+ // check for bad images that might make us crash
+ if (numTrans > numPalette) {
+ numTrans = numPalette;
+ }
+
+ int index = 0;
+ int transLessThanFF = 0;
+
+ // Choose which function to use to create the color table. If the final destination's
+ // colortype is unpremultiplied, the color table will store unpremultiplied colors.
+ PackColorProc proc;
+ if (premultiply) {
+ proc = &SkPreMultiplyARGB;
+ } else {
+ proc = &SkPackARGB32NoCheck;
+ }
+ for (; index < numTrans; index++) {
+ transLessThanFF |= (int)*trans - 0xFF;
+ *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue);
+ palette++;
+ }
+
+ if (transLessThanFF < 0) {
+ *outAlphaType = premultiply ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
+ } else {
+ *outAlphaType = kOpaque_SkAlphaType;
+ }
+
+ for (; index < numPalette; index++) {
+ *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
+ palette++;
+ }
+
+ // see BUGGY IMAGE WORKAROUND comment above
+ if (numPalette < 256) {
+ *colorPtr = colorPtr[-1];
+ }
+
+ return SkNEW_ARGS(SkColorTable, (colorStorage, colorCount));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Creation
+///////////////////////////////////////////////////////////////////////////////
+
+#define PNG_BYTES_TO_CHECK 4
+
+bool SkPngCodec::IsPng(SkStream* stream) {
+ char buf[PNG_BYTES_TO_CHECK];
+ if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) {
+ return false;
+ }
+ if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
+ return false;
+ }
+ return true;
+}
+
+SkCodec* SkPngCodec::NewFromStream(SkStream* stream) {
+ // The image is known to be a PNG. Decode enough to know the SkImageInfo.
+ // FIXME: Allow silencing warnings.
+ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
+ sk_error_fn, NULL);
+ if (!png_ptr) {
+ return NULL;
+ }
+
+ AutoCleanPng autoClean(png_ptr);
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL) {
+ return NULL;
+ }
+
+ autoClean.setInfoPtr(info_ptr);
+
+ // FIXME: Could we use the return value of setjmp to specify the type of
+ // error?
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ return NULL;
+ }
+
+ png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn);
+
+ // FIXME: This is where the old code hooks up the Peeker. Does it need to
+ // be set this early? (i.e. where are the user chunks? early in the stream,
+ // potentially?)
+ // If it does, we need to figure out a way to set it here.
+
+ // The call to png_read_info() gives us all of the information from the
+ // PNG file before the first IDAT (image data chunk).
+ png_read_info(png_ptr, info_ptr);
+ png_uint_32 origWidth, origHeight;
+ int bitDepth, colorType;
+ png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
+ &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
+
+ // sanity check for size
+ {
+ int64_t size = sk_64_mul(origWidth, origHeight);
+ // now check that if we are 4-bytes per pixel, we also don't overflow
+ if (size < 0 || size > (0x7FFFFFFF >> 2)) {
+ return NULL;
+ }
+ }
+
+ // Tell libpng to strip 16 bit/color files down to 8 bits/color
+ if (bitDepth == 16) {
+ png_set_strip_16(png_ptr);
+ }
+#ifdef PNG_READ_PACK_SUPPORTED
+ // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
+ // byte into separate bytes (useful for paletted and grayscale images).
+ if (bitDepth < 8) {
+ png_set_packing(png_ptr);
+ }
+#endif
+ // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
+ if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
+ png_set_expand_gray_1_2_4_to_8(png_ptr);
+ }
+
+
+ // Now determine the default SkColorType and SkAlphaType.
+ SkColorType skColorType;
+ SkAlphaType skAlphaType;
+ switch (colorType) {
+ case PNG_COLOR_TYPE_PALETTE:
+ // Technically, this is true of the data, but I don't think we want
+ // to support it.
+ // skColorType = kIndex8_SkColorType;
+ skColorType = kN32_SkColorType;
+ skAlphaType = has_transparency_in_palette(png_ptr, info_ptr) ?
+ kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
+ break;
+ case PNG_COLOR_TYPE_GRAY:
+ if (false) {
+ // FIXME: Is this the wrong default behavior? This means if the
+ // caller supplies the info we gave them, they'll get Alpha 8.
+ skColorType = kAlpha_8_SkColorType;
+ // FIXME: Strangely, the canonical type for Alpha 8 is Premul.
+ skAlphaType = kPremul_SkAlphaType;
+ } else {
+ skColorType = kN32_SkColorType;
+ skAlphaType = kOpaque_SkAlphaType;
+ }
+ break;
+ default:
+ // Note: This *almost* mimics the code in SkImageDecoder_libpng.
+ // has_transparency_in_palette makes an additional check - whether
+ // numTrans is greater than 0. Why does the other code not make that
+ // check?
+ if (has_transparency_in_palette(png_ptr, info_ptr)
+ || PNG_COLOR_TYPE_RGB_ALPHA == colorType
+ || PNG_COLOR_TYPE_GRAY_ALPHA == colorType)
+ {
+ skAlphaType = kUnpremul_SkAlphaType;
+ } else {
+ skAlphaType = kOpaque_SkAlphaType;
+ }
+ skColorType = kN32_SkColorType;
+ break;
+ }
+
+ {
+ // FIXME: Again, this block needs to go into onGetPixels.
+ bool convertGrayToRGB = PNG_COLOR_TYPE_GRAY == colorType && skColorType != kAlpha_8_SkColorType;
+
+ // Unless the user is requesting A8, convert a grayscale image into RGB.
+ // GRAY_ALPHA will always be converted to RGB
+ if (convertGrayToRGB || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
+ png_set_gray_to_rgb(png_ptr);
+ }
+
+ // Add filler (or alpha) byte (after each RGB triplet) if necessary.
+ // FIXME: It seems like we could just use RGB as the SrcConfig here.
+ if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) {
+ png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+ }
+ }
+
+ // FIXME: Also need to check for sRGB (skbug.com/3471).
+
+ SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType,
+ skAlphaType);
+ SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, png_ptr, info_ptr));
+ autoClean.detach();
+ return codec;
+}
+
+SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream,
+ png_structp png_ptr, png_infop info_ptr)
+ : INHERITED(info, stream)
+ , fPng_ptr(png_ptr)
+ , fInfo_ptr(info_ptr) {}
+
+SkPngCodec::~SkPngCodec() {
+ png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Getting the pixels
+///////////////////////////////////////////////////////////////////////////////
+
+static bool premul_and_unpremul(SkAlphaType A, SkAlphaType B) {
+ return kPremul_SkAlphaType == A && kUnpremul_SkAlphaType == B;
+}
+
+static bool conversion_possible(const SkImageInfo& A, const SkImageInfo& B) {
+ // TODO: Support other conversions
+ if (A.colorType() != B.colorType()) {
+ return false;
+ }
+ if (A.profileType() != B.profileType()) {
+ return false;
+ }
+ if (A.alphaType() == B.alphaType()) {
+ return true;
+ }
+ return premul_and_unpremul(A.alphaType(), B.alphaType())
+ || premul_and_unpremul(B.alphaType(), A.alphaType());
+}
+
+SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
+ size_t rowBytes, SkPMColor ctable[],
+ int* ctableCount) {
+ if (!this->rewindIfNeeded()) {
+ return kCouldNotRewind;
+ }
+ if (requestedInfo.dimensions() != this->getOriginalInfo().dimensions()) {
+ return kInvalidScale;
+ }
+ if (!conversion_possible(requestedInfo, this->getOriginalInfo())) {
+ return kInvalidConversion;
+ }
+
+ SkBitmap decodedBitmap;
+ // If installPixels would have failed, getPixels should have failed before
+ // calling onGetPixels.
+ SkAssertResult(decodedBitmap.installPixels(requestedInfo, dst, rowBytes));
+
+ // Initialize all non-trivial objects before setjmp.
+ SkAutoTUnref<SkColorTable> colorTable;
+ SkAutoTDelete<SkSwizzler> swizzler;
+ SkAutoMalloc storage; // Scratch memory for pre-swizzled rows.
+
+ // FIXME: Could we use the return value of setjmp to specify the type of
+ // error?
+ if (setjmp(png_jmpbuf(fPng_ptr))) {
+ SkDebugf("setjmp long jump!\n");
+ return kInvalidInput;
+ }
+
+ // FIXME: We already retrieved this information. Store it in SkPngCodec?
+ png_uint_32 origWidth, origHeight;
+ int bitDepth, pngColorType, interlaceType;
+ png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth,
+ &pngColorType, &interlaceType, int_p_NULL, int_p_NULL);
+
+ const int numberPasses = (interlaceType != PNG_INTERLACE_NONE) ?
+ png_set_interlace_handling(fPng_ptr) : 1;
+
+ SkSwizzler::SrcConfig sc;
+ bool reallyHasAlpha = false;
+ if (PNG_COLOR_TYPE_PALETTE == pngColorType) {
+ sc = SkSwizzler::kIndex;
+ SkAlphaType at = requestedInfo.alphaType();
+ colorTable.reset(decode_palette(fPng_ptr, fInfo_ptr,
+ kPremul_SkAlphaType == at,
+ &at));
+ if (!colorTable) {
+ return kInvalidInput;
+ }
+
+ reallyHasAlpha = (at != kOpaque_SkAlphaType);
+
+ if (at != requestedInfo.alphaType()) {
+ // It turns out the image is opaque.
+ SkASSERT(kOpaque_SkAlphaType == at);
+ }
+ } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) {
+ // Note: we check the destination, since otherwise we would have
+ // told png to upscale.
+ SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType);
+ sc = SkSwizzler::kGray;
+ } else if (this->getOriginalInfo().alphaType() == kOpaque_SkAlphaType) {
+ sc = SkSwizzler::kRGBX;
+ } else {
+ sc = SkSwizzler::kRGBA;
+ }
+ const SkPMColor* colors = colorTable ? colorTable->readColors() : NULL;
+ // TODO: Support skipZeroes.
+ swizzler.reset(SkSwizzler::CreateSwizzler(sc, colors, requestedInfo,
+ dst, rowBytes, false));
+ if (!swizzler) {
+ // FIXME: CreateSwizzler could fail for another reason.
+ return kUnimplemented;
+ }
+
+ // FIXME: Here is where we should likely insert some of the modifications
+ // made in the factory.
+ png_read_update_info(fPng_ptr, fInfo_ptr);
+
+ if (numberPasses > 1) {
+ const int width = requestedInfo.width();
+ const int height = requestedInfo.height();
+ const int bpp = SkSwizzler::BytesPerPixel(sc);
+ const size_t rowBytes = width * bpp;
+
+ storage.reset(width * height * bpp);
+ uint8_t* const base = static_cast<uint8_t*>(storage.get());
+
+ for (int i = 0; i < numberPasses; i++) {
+ uint8_t* row = base;
+ for (int y = 0; y < height; y++) {
+ uint8_t* bmRow = row;
+ png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1);
+ row += rowBytes;
+ }
+ }
+
+ // Now swizzle it.
+ uint8_t* row = base;
+ for (int y = 0; y < height; y++) {
+ reallyHasAlpha |= swizzler->next(row);
+ row += rowBytes;
+ }
+ } else {
+ storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(sc));
+ uint8_t* srcRow = static_cast<uint8_t*>(storage.get());
+ for (int y = 0; y < requestedInfo.height(); y++) {
+ png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1);
+ reallyHasAlpha |= swizzler->next(srcRow);
+ }
+ }
+
+ /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
+ png_read_end(fPng_ptr, fInfo_ptr);
+
+ // FIXME: do we need substituteTranspColor?
+
+ if (reallyHasAlpha && requestedInfo.alphaType() != kOpaque_SkAlphaType) {
+ // FIXME: We want to alert the caller. Is this the right way?
+ SkImageInfo* modInfo = const_cast<SkImageInfo*>(&requestedInfo);
+ *modInfo = requestedInfo.makeAlphaType(kOpaque_SkAlphaType);
+ }
+ return kSuccess;
+}
diff --git a/src/codec/SkCodec_libpng.h b/src/codec/SkCodec_libpng.h
new file mode 100644
index 0000000..a5327dd
--- /dev/null
+++ b/src/codec/SkCodec_libpng.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCodec.h"
+#include "SkImageInfo.h"
+
+extern "C" {
+ // FIXME: I'd like to force all platforms to use the same decoder, but this
+ // means an extra dependency on Mac/Win.
+ #include "png.h"
+}
+
+class SkStream;
+
+class SkPngCodec : public SkCodec {
+public:
+ // Assumes IsPng was called and returned true.
+ static SkCodec* NewFromStream(SkStream*);
+ static bool IsPng(SkStream*);
+protected:
+ Result onGetPixels(const SkImageInfo&, void*, size_t, SkPMColor*, int*) SK_OVERRIDE;
+private:
+ png_structp fPng_ptr;
+ png_infop fInfo_ptr;
+
+ SkPngCodec(const SkImageInfo&, SkStream*, png_structp, png_infop);
+ ~SkPngCodec();
+
+ typedef SkCodec INHERITED;
+};
diff --git a/src/codec/SkSwizzler.cpp b/src/codec/SkSwizzler.cpp
new file mode 100644
index 0000000..563933f
--- /dev/null
+++ b/src/codec/SkSwizzler.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkColorPriv.h"
+#include "SkSwizzler.h"
+#include "SkTemplates.h"
+
+// index
+
+#define A32_MASK_IN_PLACE (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT)
+
+static bool swizzle_index_to_n32(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int, const SkPMColor ctable[]) {
+
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
+ SkPMColor cc = A32_MASK_IN_PLACE;
+ for (int x = 0; x < width; x++) {
+ SkPMColor c = ctable[*src];
+ cc &= c;
+ dst[x] = c;
+ src += deltaSrc;
+ }
+ return cc != A32_MASK_IN_PLACE;
+}
+
+static bool swizzle_index_to_n32_skipZ(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int,
+ const SkPMColor ctable[]) {
+
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
+ SkPMColor cc = A32_MASK_IN_PLACE;
+ for (int x = 0; x < width; x++) {
+ SkPMColor c = ctable[*src];
+ cc &= c;
+ if (c != 0) {
+ dst[x] = c;
+ }
+ src += deltaSrc;
+ }
+ return cc != A32_MASK_IN_PLACE;
+}
+
+#undef A32_MASK_IN_PLACE
+
+// n32
+static bool swizzle_rgbx_to_n32(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int, const SkPMColor[]) {
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
+ for (int x = 0; x < width; x++) {
+ dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]);
+ src += deltaSrc;
+ }
+ return false;
+}
+
+static bool swizzle_rgba_to_n32_premul(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int, const SkPMColor[]) {
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
+ unsigned alphaMask = 0xFF;
+ for (int x = 0; x < width; x++) {
+ unsigned alpha = src[3];
+ dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
+ src += deltaSrc;
+ alphaMask &= alpha;
+ }
+ return alphaMask != 0xFF;
+}
+
+static bool swizzle_rgba_to_n32_unpremul(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int,
+ const SkPMColor[]) {
+ uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow);
+ unsigned alphaMask = 0xFF;
+ for (int x = 0; x < width; x++) {
+ unsigned alpha = src[3];
+ dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
+ src += deltaSrc;
+ alphaMask &= alpha;
+ }
+ return alphaMask != 0xFF;
+}
+
+static bool swizzle_rgba_to_n32_premul_skipZ(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int,
+ const SkPMColor[]) {
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
+ unsigned alphaMask = 0xFF;
+ for (int x = 0; x < width; x++) {
+ unsigned alpha = src[3];
+ if (0 != alpha) {
+ dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
+ }
+ src += deltaSrc;
+ alphaMask &= alpha;
+ }
+ return alphaMask != 0xFF;
+}
+
+/**
+ FIXME: This was my idea to cheat in order to continue taking advantage of skipping zeroes.
+ This would be fine for drawing normally, but not for drawing with transfer modes. Being
+ honest means we can draw correctly with transfer modes, with the cost of not being able
+ to take advantage of Android's free unwritten pages. Something to keep in mind when we
+ decide whether to switch to unpremul default.
+static bool swizzle_rgba_to_n32_unpremul_skipZ(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int,
+ const SkPMColor[]) {
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
+ unsigned alphaMask = 0xFF;
+ for (int x = 0; x < width; x++) {
+ unsigned alpha = src[3];
+ // NOTE: We cheat here. The caller requested unpremul and skip zeroes. It's possible
+ // the color components are not zero, but we skip them anyway, meaning they'll remain
+ // zero (implied by the request to skip zeroes).
+ if (0 != alpha) {
+ dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
+ }
+ src += deltaSrc;
+ alphaMask &= alpha;
+ }
+ return alphaMask != 0xFF;
+}
+*/
+
+SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, const SkPMColor* ctable,
+ const SkImageInfo& info, void* dst,
+ size_t dstRowBytes, bool skipZeroes) {
+ if (info.colorType() == kUnknown_SkColorType) {
+ return NULL;
+ }
+ if (info.minRowBytes() > dstRowBytes) {
+ return NULL;
+ }
+ if (kIndex == sc && NULL == ctable) {
+ return NULL;
+ }
+ RowProc proc = NULL;
+ switch (sc) {
+ case kIndex:
+ switch (info.colorType()) {
+ case kN32_SkColorType:
+ // We assume the color premultiplied ctable (or not) as desired.
+ if (skipZeroes) {
+ proc = &swizzle_index_to_n32_skipZ;
+ } else {
+ proc = &swizzle_index_to_n32;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+ case kRGBX:
+ // TODO: Support other swizzles.
+ switch (info.colorType()) {
+ case kN32_SkColorType:
+ proc = &swizzle_rgbx_to_n32;
+ break;
+ default:
+ break;
+ }
+ break;
+ case kRGBA:
+ switch (info.colorType()) {
+ case kN32_SkColorType:
+ if (info.alphaType() == kUnpremul_SkAlphaType) {
+ // Respect skipZeroes?
+ proc = &swizzle_rgba_to_n32_unpremul;
+ } else {
+ if (skipZeroes) {
+ proc = &swizzle_rgba_to_n32_premul_skipZ;
+ } else {
+ proc = &swizzle_rgba_to_n32_premul;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ if (NULL == proc) {
+ return NULL;
+ }
+ return SkNEW_ARGS(SkSwizzler, (proc, ctable, BytesPerPixel(sc), info, dst, dstRowBytes));
+}
+
+SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcBpp,
+ const SkImageInfo& info, void* dst, size_t rowBytes)
+ : fRowProc(proc)
+ , fColorTable(ctable)
+ , fSrcPixelSize(srcBpp)
+ , fDstInfo(info)
+ , fDstRow(dst)
+ , fDstRowBytes(rowBytes)
+ , fCurrY(0)
+{
+}
+
+bool SkSwizzler::next(const uint8_t* SK_RESTRICT src) {
+ SkASSERT(fCurrY < fDstInfo.height());
+ const bool hadAlpha = fRowProc(fDstRow, src, fDstInfo.width(), fSrcPixelSize,
+ fCurrY, fColorTable);
+ fCurrY++;
+ fDstRow = SkTAddOffset<void>(fDstRow, fDstRowBytes);
+ return hadAlpha;
+}
diff --git a/src/codec/SkSwizzler.h b/src/codec/SkSwizzler.h
new file mode 100644
index 0000000..0bf2ee3
--- /dev/null
+++ b/src/codec/SkSwizzler.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSwizzler_DEFINED
+#define SkSwizzler_DEFINED
+
+#include "SkTypes.h"
+#include "SkColor.h"
+#include "SkImageInfo.h"
+
+class SkSwizzler : public SkNoncopyable {
+public:
+ /**
+ * Enum describing the config of the source data.
+ */
+ enum SrcConfig {
+ kGray, // 1 byte per pixel
+ kIndex, // 1 byte per pixel
+ kRGB, // 3 bytes per pixel
+ kRGBX, // 4 byes per pixel (ignore 4th)
+ kRGBA, // 4 bytes per pixel
+ kRGB_565 // 2 bytes per pixel
+ };
+
+ static int BytesPerPixel(SrcConfig sc) {
+ switch (sc) {
+ case kGray:
+ case kIndex:
+ return 1;
+ case kRGB:
+ return 3;
+ case kRGBX:
+ case kRGBA:
+ return 4;
+ case kRGB_565:
+ return 2;
+ default:
+ SkDebugf("invalid source config passed to BytesPerPixel\n");
+ return -1;
+ }
+ }
+
+ /**
+ * Create a new SkSwizzler.
+ * @param sc SrcConfig
+ * @param info dimensions() describe both the src and the dst.
+ * Other fields describe the dst.
+ * @param dst Destination to write pixels. Must match info and dstRowBytes
+ * @param dstRowBytes rowBytes for dst.
+ * @param skipZeroes Whether to skip writing zeroes. Useful if dst is
+ * zero-initialized. The implementation may or may not respect this.
+ * @return A new SkSwizzler or NULL on failure.
+ */
+ static SkSwizzler* CreateSwizzler(SrcConfig sc, const SkPMColor* ctable,
+ const SkImageInfo& info, void* dst,
+ size_t dstRowBytes, bool skipZeroes);
+ /**
+ * Swizzle the next line. Call height times, once for each row of source.
+ * @param src The next row of the source data.
+ * @return Whether the row had non-opaque alpha.
+ */
+ bool next(const uint8_t* SK_RESTRICT src);
+private:
+ /**
+ * Method for converting raw data to Skia pixels.
+ * @param dstRow Row in which to write the resulting pixels.
+ * @param src Row of src data, in format specified by SrcConfig
+ * @param width Width in pixels
+ * @param bpp bytes per pixel of the source.
+ * @param y Line of source.
+ * @param ctable Colors (used for kIndex source).
+ */
+ typedef bool (*RowProc)(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int bpp, int y,
+ const SkPMColor ctable[]);
+
+ const RowProc fRowProc;
+ const SkPMColor* fColorTable; // Unowned pointer
+ const int fSrcPixelSize;
+ const SkImageInfo fDstInfo;
+ void* fDstRow;
+ const size_t fDstRowBytes;
+ int fCurrY;
+
+ SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcBpp,
+ const SkImageInfo& info, void* dst, size_t rowBytes);
+
+};
+#endif // SkSwizzler_DEFINED
diff --git a/third_party/libpng/LICENSE b/third_party/libpng/LICENSE
new file mode 100644
index 0000000..ce2f3c8
--- /dev/null
+++ b/third_party/libpng/LICENSE
@@ -0,0 +1,172 @@
+/*
+ * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
+ *
+ * If you modify libpng you may insert additional notices immediately following
+ * this sentence.
+ *
+ * This code is released under the libpng license.
+ *
+ * libpng versions 1.2.6, August 15, 2004, through 1.6.16, December 22, 2014, are
+ * Copyright (c) 2004, 2006-2014 Glenn Randers-Pehrson, and are
+ * distributed according to the same disclaimer and license as libpng-1.2.5
+ * with the following individual added to the list of Contributing Authors:
+ *
+ * Cosmin Truta
+ *
+ * libpng versions 1.0.7, July 1, 2000, through 1.2.5, October 3, 2002, are
+ * Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
+ * distributed according to the same disclaimer and license as libpng-1.0.6
+ * with the following individuals added to the list of Contributing Authors:
+ *
+ * Simon-Pierre Cadieux
+ * Eric S. Raymond
+ * Gilles Vollant
+ *
+ * and with the following additions to the disclaimer:
+ *
+ * There is no warranty against interference with your enjoyment of the
+ * library or against infringement. There is no warranty that our
+ * efforts or the library will fulfill any of your particular purposes
+ * or needs. This library is provided with all faults, and the entire
+ * risk of satisfactory quality, performance, accuracy, and effort is with
+ * the user.
+ *
+ * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
+ * Copyright (c) 1998, 1999, 2000 Glenn Randers-Pehrson, and are
+ * distributed according to the same disclaimer and license as libpng-0.96,
+ * with the following individuals added to the list of Contributing Authors:
+ *
+ * Tom Lane
+ * Glenn Randers-Pehrson
+ * Willem van Schaik
+ *
+ * libpng versions 0.89, June 1996, through 0.96, May 1997, are
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Distributed according to the same disclaimer and license as libpng-0.88,
+ * with the following individuals added to the list of Contributing Authors:
+ *
+ * John Bowler
+ * Kevin Bracey
+ * Sam Bushell
+ * Magnus Holmgren
+ * Greg Roelofs
+ * Tom Tanner
+ *
+ * libpng versions 0.5, May 1995, through 0.88, January 1996, are
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ *
+ * For the purposes of this copyright and license, "Contributing Authors"
+ * is defined as the following set of individuals:
+ *
+ * Andreas Dilger
+ * Dave Martindale
+ * Guy Eric Schalnat
+ * Paul Schmidt
+ * Tim Wegner
+ *
+ * The PNG Reference Library is supplied "AS IS". The Contributing Authors
+ * and Group 42, Inc. disclaim all warranties, expressed or implied,
+ * including, without limitation, the warranties of merchantability and of
+ * fitness for any purpose. The Contributing Authors and Group 42, Inc.
+ * assume no liability for direct, indirect, incidental, special, exemplary,
+ * or consequential damages, which may result from the use of the PNG
+ * Reference Library, even if advised of the possibility of such damage.
+ *
+ * Permission is hereby granted to use, copy, modify, and distribute this
+ * source code, or portions hereof, for any purpose, without fee, subject
+ * to the following restrictions:
+ *
+ * 1. The origin of this source code must not be misrepresented.
+ *
+ * 2. Altered versions must be plainly marked as such and must not
+ * be misrepresented as being the original source.
+ *
+ * 3. This Copyright notice may not be removed or altered from
+ * any source or altered source distribution.
+ *
+ * The Contributing Authors and Group 42, Inc. specifically permit, without
+ * fee, and encourage the use of this source code as a component to
+ * supporting the PNG file format in commercial products. If you use this
+ * source code in a product, acknowledgment is not required but would be
+ * appreciated.
+ */
+
+/*
+ * A "png_get_copyright" function is available, for convenient use in "about"
+ * boxes and the like:
+ *
+ * printf("%s", png_get_copyright(NULL));
+ *
+ * Also, the PNG logo (in PNG format, of course) is supplied in the
+ * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
+ */
+
+/*
+ * Libpng is OSI Certified Open Source Software. OSI Certified is a
+ * certification mark of the Open Source Initiative.
+ */
+
+/*
+ * The contributing authors would like to thank all those who helped
+ * with testing, bug fixes, and patience. This wouldn't have been
+ * possible without all of you.
+ *
+ * Thanks to Frank J. T. Wojcik for helping with the documentation.
+ */
+
+/*
+ * Y2K compliance in libpng:
+ * =========================
+ *
+ * December 22, 2014
+ *
+ * Since the PNG Development group is an ad-hoc body, we can't make
+ * an official declaration.
+ *
+ * This is your unofficial assurance that libpng from version 0.71 and
+ * upward through 1.6.16 are Y2K compliant. It is my belief that
+ * earlier versions were also Y2K compliant.
+ *
+ * Libpng only has two year fields. One is a 2-byte unsigned integer
+ * that will hold years up to 65535. The other, which is deprecated,
+ * holds the date in text format, and will hold years up to 9999.
+ *
+ * The integer is
+ * "png_uint_16 year" in png_time_struct.
+ *
+ * The string is
+ * "char time_buffer[29]" in png_struct. This is no longer used
+ * in libpng-1.6.x and will be removed from libpng-1.7.0.
+ *
+ * There are seven time-related functions:
+ * png.c: png_convert_to_rfc_1123_buffer() in png.c
+ * (formerly png_convert_to_rfc_1123() prior to libpng-1.5.x and
+ * png_convert_to_rfc_1152() in error prior to libpng-0.98)
+ * png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c
+ * png_convert_from_time_t() in pngwrite.c
+ * png_get_tIME() in pngget.c
+ * png_handle_tIME() in pngrutil.c, called in pngread.c
+ * png_set_tIME() in pngset.c
+ * png_write_tIME() in pngwutil.c, called in pngwrite.c
+ *
+ * All handle dates properly in a Y2K environment. The
+ * png_convert_from_time_t() function calls gmtime() to convert from system
+ * clock time, which returns (year - 1900), which we properly convert to
+ * the full 4-digit year. There is a possibility that libpng applications
+ * are not passing 4-digit years into the png_convert_to_rfc_1123_buffer()
+ * function, or that they are incorrectly passing only a 2-digit year
+ * instead of "year - 1900" into the png_convert_from_struct_tm() function,
+ * but this is not under our control. The libpng documentation has always
+ * stated that it works with 4-digit years, and the APIs have been
+ * documented as such.
+ *
+ * The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned
+ * integer to hold the year, and can hold years as large as 65535.
+ *
+ * zlib, upon which libpng depends, is also Y2K compliant. It contains
+ * no date-related code.
+ *
+ * Glenn Randers-Pehrson
+ * libpng maintainer
+ * PNG Development Group
+ */
diff --git a/third_party/libpng/README.google b/third_party/libpng/README.google
new file mode 100644
index 0000000..4578d35
--- /dev/null
+++ b/third_party/libpng/README.google
@@ -0,0 +1,16 @@
+URL: http://www.libpng.org/pub/png/libpng.html
+Version: 1.6.16
+License: libpng license
+License File: LICENSE, pulled out of png.h
+Description: png compression/decompression library
+Local Modifications: Created pnglibconf.h from pnglibconf.h.prebuilt (just a
+ rename). Pulled LICENSE into its own file.
+
+FAQ:
+Q: Why does this directory exist?
+A: libpng is pulled in through DEPS, but in order to build it using ninja, we
+ need to create pnglibconf.h. In https://codereview.chromium.org/930283002/,
+ we originally tried creating the file as an action, but this apparently led
+ to a race condition on Windows, where some builds failed to create the file
+ in time for other files to include it. By checking pnglibconf.h directly
+ into Skia, we eliminate the race condition.
diff --git a/third_party/libpng/pnglibconf.h b/third_party/libpng/pnglibconf.h
new file mode 100644
index 0000000..da3b229
--- /dev/null
+++ b/third_party/libpng/pnglibconf.h
@@ -0,0 +1,210 @@
+/* libpng 1.6.16 STANDARD API DEFINITION */
+
+/* pnglibconf.h - library build configuration */
+
+/* Libpng version 1.6.16 - December 22, 2014 */
+
+/* Copyright (c) 1998-2014 Glenn Randers-Pehrson */
+
+/* This code is released under the libpng license. */
+/* For conditions of distribution and use, see the disclaimer */
+/* and license in png.h */
+
+/* pnglibconf.h */
+/* Machine generated file: DO NOT EDIT */
+/* Derived from: scripts/pnglibconf.dfa */
+#ifndef PNGLCONF_H
+#define PNGLCONF_H
+/* options */
+#define PNG_16BIT_SUPPORTED
+#define PNG_ALIGNED_MEMORY_SUPPORTED
+/*#undef PNG_ARM_NEON_API_SUPPORTED*/
+/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/
+#define PNG_BENIGN_ERRORS_SUPPORTED
+#define PNG_BENIGN_READ_ERRORS_SUPPORTED
+/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/
+#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
+#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+#define PNG_COLORSPACE_SUPPORTED
+#define PNG_CONSOLE_IO_SUPPORTED
+#define PNG_CONVERT_tIME_SUPPORTED
+#define PNG_EASY_ACCESS_SUPPORTED
+/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/
+#define PNG_ERROR_TEXT_SUPPORTED
+#define PNG_FIXED_POINT_SUPPORTED
+#define PNG_FLOATING_ARITHMETIC_SUPPORTED
+#define PNG_FLOATING_POINT_SUPPORTED
+#define PNG_FORMAT_AFIRST_SUPPORTED
+#define PNG_FORMAT_BGR_SUPPORTED
+#define PNG_GAMMA_SUPPORTED
+#define PNG_GET_PALETTE_MAX_SUPPORTED
+#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+#define PNG_INCH_CONVERSIONS_SUPPORTED
+#define PNG_INFO_IMAGE_SUPPORTED
+#define PNG_IO_STATE_SUPPORTED
+#define PNG_MNG_FEATURES_SUPPORTED
+#define PNG_POINTER_INDEXING_SUPPORTED
+#define PNG_PROGRESSIVE_READ_SUPPORTED
+#define PNG_READ_16BIT_SUPPORTED
+#define PNG_READ_ALPHA_MODE_SUPPORTED
+#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
+#define PNG_READ_BACKGROUND_SUPPORTED
+#define PNG_READ_BGR_SUPPORTED
+#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
+#define PNG_READ_COMPOSITE_NODIV_SUPPORTED
+#define PNG_READ_COMPRESSED_TEXT_SUPPORTED
+#define PNG_READ_EXPAND_16_SUPPORTED
+#define PNG_READ_EXPAND_SUPPORTED
+#define PNG_READ_FILLER_SUPPORTED
+#define PNG_READ_GAMMA_SUPPORTED
+#define PNG_READ_GET_PALETTE_MAX_SUPPORTED
+#define PNG_READ_GRAY_TO_RGB_SUPPORTED
+#define PNG_READ_INTERLACING_SUPPORTED
+#define PNG_READ_INT_FUNCTIONS_SUPPORTED
+#define PNG_READ_INVERT_ALPHA_SUPPORTED
+#define PNG_READ_INVERT_SUPPORTED
+#define PNG_READ_OPT_PLTE_SUPPORTED
+#define PNG_READ_PACKSWAP_SUPPORTED
+#define PNG_READ_PACK_SUPPORTED
+#define PNG_READ_QUANTIZE_SUPPORTED
+#define PNG_READ_RGB_TO_GRAY_SUPPORTED
+#define PNG_READ_SCALE_16_TO_8_SUPPORTED
+#define PNG_READ_SHIFT_SUPPORTED
+#define PNG_READ_STRIP_16_TO_8_SUPPORTED
+#define PNG_READ_STRIP_ALPHA_SUPPORTED
+#define PNG_READ_SUPPORTED
+#define PNG_READ_SWAP_ALPHA_SUPPORTED
+#define PNG_READ_SWAP_SUPPORTED
+#define PNG_READ_TEXT_SUPPORTED
+#define PNG_READ_TRANSFORMS_SUPPORTED
+#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
+#define PNG_READ_USER_CHUNKS_SUPPORTED
+#define PNG_READ_USER_TRANSFORM_SUPPORTED
+#define PNG_READ_bKGD_SUPPORTED
+#define PNG_READ_cHRM_SUPPORTED
+#define PNG_READ_gAMA_SUPPORTED
+#define PNG_READ_hIST_SUPPORTED
+#define PNG_READ_iCCP_SUPPORTED
+#define PNG_READ_iTXt_SUPPORTED
+#define PNG_READ_oFFs_SUPPORTED
+#define PNG_READ_pCAL_SUPPORTED
+#define PNG_READ_pHYs_SUPPORTED
+#define PNG_READ_sBIT_SUPPORTED
+#define PNG_READ_sCAL_SUPPORTED
+#define PNG_READ_sPLT_SUPPORTED
+#define PNG_READ_sRGB_SUPPORTED
+#define PNG_READ_tEXt_SUPPORTED
+#define PNG_READ_tIME_SUPPORTED
+#define PNG_READ_tRNS_SUPPORTED
+#define PNG_READ_zTXt_SUPPORTED
+/*#undef PNG_SAFE_LIMITS_SUPPORTED*/
+#define PNG_SAVE_INT_32_SUPPORTED
+#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
+#define PNG_SEQUENTIAL_READ_SUPPORTED
+#define PNG_SETJMP_SUPPORTED
+#define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED
+#define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
+#define PNG_SET_OPTION_SUPPORTED
+#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+#define PNG_SET_USER_LIMITS_SUPPORTED
+#define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED
+#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED
+#define PNG_SIMPLIFIED_READ_SUPPORTED
+#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
+#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
+#define PNG_SIMPLIFIED_WRITE_SUPPORTED
+#define PNG_STDIO_SUPPORTED
+#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+#define PNG_TEXT_SUPPORTED
+#define PNG_TIME_RFC1123_SUPPORTED
+#define PNG_UNKNOWN_CHUNKS_SUPPORTED
+#define PNG_USER_CHUNKS_SUPPORTED
+#define PNG_USER_LIMITS_SUPPORTED
+#define PNG_USER_MEM_SUPPORTED
+#define PNG_USER_TRANSFORM_INFO_SUPPORTED
+#define PNG_USER_TRANSFORM_PTR_SUPPORTED
+#define PNG_WARNINGS_SUPPORTED
+#define PNG_WRITE_16BIT_SUPPORTED
+#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
+#define PNG_WRITE_BGR_SUPPORTED
+#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
+#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
+#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+#define PNG_WRITE_FILLER_SUPPORTED
+#define PNG_WRITE_FILTER_SUPPORTED
+#define PNG_WRITE_FLUSH_SUPPORTED
+#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED
+#define PNG_WRITE_INTERLACING_SUPPORTED
+#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED
+#define PNG_WRITE_INVERT_ALPHA_SUPPORTED
+#define PNG_WRITE_INVERT_SUPPORTED
+#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
+#define PNG_WRITE_PACKSWAP_SUPPORTED
+#define PNG_WRITE_PACK_SUPPORTED
+#define PNG_WRITE_SHIFT_SUPPORTED
+#define PNG_WRITE_SUPPORTED
+#define PNG_WRITE_SWAP_ALPHA_SUPPORTED
+#define PNG_WRITE_SWAP_SUPPORTED
+#define PNG_WRITE_TEXT_SUPPORTED
+#define PNG_WRITE_TRANSFORMS_SUPPORTED
+#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+#define PNG_WRITE_USER_TRANSFORM_SUPPORTED
+#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
+#define PNG_WRITE_bKGD_SUPPORTED
+#define PNG_WRITE_cHRM_SUPPORTED
+#define PNG_WRITE_gAMA_SUPPORTED
+#define PNG_WRITE_hIST_SUPPORTED
+#define PNG_WRITE_iCCP_SUPPORTED
+#define PNG_WRITE_iTXt_SUPPORTED
+#define PNG_WRITE_oFFs_SUPPORTED
+#define PNG_WRITE_pCAL_SUPPORTED
+#define PNG_WRITE_pHYs_SUPPORTED
+#define PNG_WRITE_sBIT_SUPPORTED
+#define PNG_WRITE_sCAL_SUPPORTED
+#define PNG_WRITE_sPLT_SUPPORTED
+#define PNG_WRITE_sRGB_SUPPORTED
+#define PNG_WRITE_tEXt_SUPPORTED
+#define PNG_WRITE_tIME_SUPPORTED
+#define PNG_WRITE_tRNS_SUPPORTED
+#define PNG_WRITE_zTXt_SUPPORTED
+#define PNG_bKGD_SUPPORTED
+#define PNG_cHRM_SUPPORTED
+#define PNG_gAMA_SUPPORTED
+#define PNG_hIST_SUPPORTED
+#define PNG_iCCP_SUPPORTED
+#define PNG_iTXt_SUPPORTED
+#define PNG_oFFs_SUPPORTED
+#define PNG_pCAL_SUPPORTED
+#define PNG_pHYs_SUPPORTED
+#define PNG_sBIT_SUPPORTED
+#define PNG_sCAL_SUPPORTED
+#define PNG_sPLT_SUPPORTED
+#define PNG_sRGB_SUPPORTED
+#define PNG_tEXt_SUPPORTED
+#define PNG_tIME_SUPPORTED
+#define PNG_tRNS_SUPPORTED
+#define PNG_zTXt_SUPPORTED
+/* end of options */
+/* settings */
+#define PNG_API_RULE 0
+#define PNG_COST_SHIFT 3
+#define PNG_DEFAULT_READ_MACROS 1
+#define PNG_GAMMA_THRESHOLD_FIXED 5000
+#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE
+#define PNG_INFLATE_BUF_SIZE 1024
+#define PNG_MAX_GAMMA_8 11
+#define PNG_QUANTIZE_BLUE_BITS 5
+#define PNG_QUANTIZE_GREEN_BITS 5
+#define PNG_QUANTIZE_RED_BITS 5
+#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1)
+#define PNG_TEXT_Z_DEFAULT_STRATEGY 0
+#define PNG_WEIGHT_SHIFT 8
+#define PNG_ZBUF_SIZE 8192
+#define PNG_ZLIB_VERNUM 0 /* unknown */
+#define PNG_Z_DEFAULT_COMPRESSION (-1)
+#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0
+#define PNG_Z_DEFAULT_STRATEGY 1
+#define PNG_sCAL_PRECISION 5
+#define PNG_sRGB_PROFILE_CHECKS 2
+/* end of settings */
+#endif /* PNGLCONF_H */