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/core/SkBitmap.h" 9cb93a386Sopenharmony_ci#include "include/core/SkColorSpace.h" 10cb93a386Sopenharmony_ci#include "include/core/SkMath.h" 11cb93a386Sopenharmony_ci#include "include/core/SkPoint3.h" 12cb93a386Sopenharmony_ci#include "include/core/SkSize.h" 13cb93a386Sopenharmony_ci#include "include/core/SkStream.h" 14cb93a386Sopenharmony_ci#include "include/private/SkColorData.h" 15cb93a386Sopenharmony_ci#include "include/private/SkMacros.h" 16cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 17cb93a386Sopenharmony_ci#include "src/codec/SkCodecPriv.h" 18cb93a386Sopenharmony_ci#include "src/codec/SkColorTable.h" 19cb93a386Sopenharmony_ci#include "src/codec/SkPngCodec.h" 20cb93a386Sopenharmony_ci#include "src/codec/SkPngPriv.h" 21cb93a386Sopenharmony_ci#include "src/codec/SkSwizzler.h" 22cb93a386Sopenharmony_ci#include "src/core/SkOpts.h" 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ci#include "png.h" 25cb93a386Sopenharmony_ci#include <algorithm> 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 28cb93a386Sopenharmony_ci #include "include/android/SkAndroidFrameworkUtils.h" 29cb93a386Sopenharmony_ci#endif 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci// This warning triggers false postives way too often in here. 32cb93a386Sopenharmony_ci#if defined(__GNUC__) && !defined(__clang__) 33cb93a386Sopenharmony_ci #pragma GCC diagnostic ignored "-Wclobbered" 34cb93a386Sopenharmony_ci#endif 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci// FIXME (scroggo): We can use png_jumpbuf directly once Google3 is on 1.6 37cb93a386Sopenharmony_ci#define PNG_JMPBUF(x) png_jmpbuf((png_structp) x) 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 40cb93a386Sopenharmony_ci// Callback functions 41cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci// When setjmp is first called, it returns 0, meaning longjmp was not called. 44cb93a386Sopenharmony_ciconstexpr int kSetJmpOkay = 0; 45cb93a386Sopenharmony_ci// An error internal to libpng. 46cb93a386Sopenharmony_ciconstexpr int kPngError = 1; 47cb93a386Sopenharmony_ci// Passed to longjmp when we have decoded as many lines as we need. 48cb93a386Sopenharmony_ciconstexpr int kStopDecoding = 2; 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_cistatic void sk_error_fn(png_structp png_ptr, png_const_charp msg) { 51cb93a386Sopenharmony_ci SkCodecPrintf("------ png error %s\n", msg); 52cb93a386Sopenharmony_ci longjmp(PNG_JMPBUF(png_ptr), kPngError); 53cb93a386Sopenharmony_ci} 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_civoid sk_warning_fn(png_structp, png_const_charp msg) { 56cb93a386Sopenharmony_ci SkCodecPrintf("----- png warning %s\n", msg); 57cb93a386Sopenharmony_ci} 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED 60cb93a386Sopenharmony_cistatic int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { 61cb93a386Sopenharmony_ci SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr); 62cb93a386Sopenharmony_ci // readChunk() returning true means continue decoding 63cb93a386Sopenharmony_ci return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? 1 : -1; 64cb93a386Sopenharmony_ci} 65cb93a386Sopenharmony_ci#endif 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 68cb93a386Sopenharmony_ci// Helpers 69cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ciclass AutoCleanPng : public SkNoncopyable { 72cb93a386Sopenharmony_cipublic: 73cb93a386Sopenharmony_ci /* 74cb93a386Sopenharmony_ci * This class does not take ownership of stream or reader, but if codecPtr 75cb93a386Sopenharmony_ci * is non-NULL, and decodeBounds succeeds, it will have created a new 76cb93a386Sopenharmony_ci * SkCodec (pointed to by *codecPtr) which will own/ref them, as well as 77cb93a386Sopenharmony_ci * the png_ptr and info_ptr. 78cb93a386Sopenharmony_ci */ 79cb93a386Sopenharmony_ci AutoCleanPng(png_structp png_ptr, SkStream* stream, SkPngChunkReader* reader, 80cb93a386Sopenharmony_ci SkCodec** codecPtr) 81cb93a386Sopenharmony_ci : fPng_ptr(png_ptr) 82cb93a386Sopenharmony_ci , fInfo_ptr(nullptr) 83cb93a386Sopenharmony_ci , fStream(stream) 84cb93a386Sopenharmony_ci , fChunkReader(reader) 85cb93a386Sopenharmony_ci , fOutCodec(codecPtr) 86cb93a386Sopenharmony_ci {} 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci ~AutoCleanPng() { 89cb93a386Sopenharmony_ci // fInfo_ptr will never be non-nullptr unless fPng_ptr is. 90cb93a386Sopenharmony_ci if (fPng_ptr) { 91cb93a386Sopenharmony_ci png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr; 92cb93a386Sopenharmony_ci png_destroy_read_struct(&fPng_ptr, info_pp, nullptr); 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci void setInfoPtr(png_infop info_ptr) { 97cb93a386Sopenharmony_ci SkASSERT(nullptr == fInfo_ptr); 98cb93a386Sopenharmony_ci fInfo_ptr = info_ptr; 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci /** 102cb93a386Sopenharmony_ci * Reads enough of the input stream to decode the bounds. 103cb93a386Sopenharmony_ci * @return false if the stream is not a valid PNG (or too short). 104cb93a386Sopenharmony_ci * true if it read enough of the stream to determine the bounds. 105cb93a386Sopenharmony_ci * In the latter case, the stream may have been read beyond the 106cb93a386Sopenharmony_ci * point to determine the bounds, and the png_ptr will have saved 107cb93a386Sopenharmony_ci * any extra data. Further, if the codecPtr supplied to the 108cb93a386Sopenharmony_ci * constructor was not NULL, it will now point to a new SkCodec, 109cb93a386Sopenharmony_ci * which owns (or refs, in the case of the SkPngChunkReader) the 110cb93a386Sopenharmony_ci * inputs. If codecPtr was NULL, the png_ptr and info_ptr are 111cb93a386Sopenharmony_ci * unowned, and it is up to the caller to destroy them. 112cb93a386Sopenharmony_ci */ 113cb93a386Sopenharmony_ci bool decodeBounds(); 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ciprivate: 116cb93a386Sopenharmony_ci png_structp fPng_ptr; 117cb93a386Sopenharmony_ci png_infop fInfo_ptr; 118cb93a386Sopenharmony_ci SkStream* fStream; 119cb93a386Sopenharmony_ci SkPngChunkReader* fChunkReader; 120cb93a386Sopenharmony_ci SkCodec** fOutCodec; 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci void infoCallback(size_t idatLength); 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci void releasePngPtrs() { 125cb93a386Sopenharmony_ci fPng_ptr = nullptr; 126cb93a386Sopenharmony_ci fInfo_ptr = nullptr; 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci}; 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_cistatic inline bool is_chunk(const png_byte* chunk, const char* tag) { 131cb93a386Sopenharmony_ci return memcmp(chunk + 4, tag, 4) == 0; 132cb93a386Sopenharmony_ci} 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_cistatic inline bool process_data(png_structp png_ptr, png_infop info_ptr, 135cb93a386Sopenharmony_ci SkStream* stream, void* buffer, size_t bufferSize, size_t length) { 136cb93a386Sopenharmony_ci while (length > 0) { 137cb93a386Sopenharmony_ci const size_t bytesToProcess = std::min(bufferSize, length); 138cb93a386Sopenharmony_ci const size_t bytesRead = stream->read(buffer, bytesToProcess); 139cb93a386Sopenharmony_ci png_process_data(png_ptr, info_ptr, (png_bytep) buffer, bytesRead); 140cb93a386Sopenharmony_ci if (bytesRead < bytesToProcess) { 141cb93a386Sopenharmony_ci return false; 142cb93a386Sopenharmony_ci } 143cb93a386Sopenharmony_ci length -= bytesToProcess; 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci return true; 146cb93a386Sopenharmony_ci} 147cb93a386Sopenharmony_ci 148cb93a386Sopenharmony_cibool AutoCleanPng::decodeBounds() { 149cb93a386Sopenharmony_ci if (setjmp(PNG_JMPBUF(fPng_ptr))) { 150cb93a386Sopenharmony_ci return false; 151cb93a386Sopenharmony_ci } 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci png_set_progressive_read_fn(fPng_ptr, nullptr, nullptr, nullptr, nullptr); 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci // Arbitrary buffer size, though note that it matches (below) 156cb93a386Sopenharmony_ci // SkPngCodec::processData(). FIXME: Can we better suit this to the size of 157cb93a386Sopenharmony_ci // the PNG header? 158cb93a386Sopenharmony_ci constexpr size_t kBufferSize = 4096; 159cb93a386Sopenharmony_ci char buffer[kBufferSize]; 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_ci { 162cb93a386Sopenharmony_ci // Parse the signature. 163cb93a386Sopenharmony_ci if (fStream->read(buffer, 8) < 8) { 164cb93a386Sopenharmony_ci return false; 165cb93a386Sopenharmony_ci } 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci png_process_data(fPng_ptr, fInfo_ptr, (png_bytep) buffer, 8); 168cb93a386Sopenharmony_ci } 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci while (true) { 171cb93a386Sopenharmony_ci // Parse chunk length and type. 172cb93a386Sopenharmony_ci if (fStream->read(buffer, 8) < 8) { 173cb93a386Sopenharmony_ci // We have read to the end of the input without decoding bounds. 174cb93a386Sopenharmony_ci break; 175cb93a386Sopenharmony_ci } 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_ci png_byte* chunk = reinterpret_cast<png_byte*>(buffer); 178cb93a386Sopenharmony_ci const size_t length = png_get_uint_32(chunk); 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ci if (is_chunk(chunk, "IDAT")) { 181cb93a386Sopenharmony_ci this->infoCallback(length); 182cb93a386Sopenharmony_ci return true; 183cb93a386Sopenharmony_ci } 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci png_process_data(fPng_ptr, fInfo_ptr, chunk, 8); 186cb93a386Sopenharmony_ci // Process the full chunk + CRC. 187cb93a386Sopenharmony_ci if (!process_data(fPng_ptr, fInfo_ptr, fStream, buffer, kBufferSize, length + 4)) { 188cb93a386Sopenharmony_ci return false; 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci return false; 193cb93a386Sopenharmony_ci} 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_cibool SkPngCodec::processData() { 196cb93a386Sopenharmony_ci switch (setjmp(PNG_JMPBUF(fPng_ptr))) { 197cb93a386Sopenharmony_ci case kPngError: 198cb93a386Sopenharmony_ci // There was an error. Stop processing data. 199cb93a386Sopenharmony_ci // FIXME: Do we need to discard png_ptr? 200cb93a386Sopenharmony_ci return false; 201cb93a386Sopenharmony_ci case kStopDecoding: 202cb93a386Sopenharmony_ci // We decoded all the lines we want. 203cb93a386Sopenharmony_ci return true; 204cb93a386Sopenharmony_ci case kSetJmpOkay: 205cb93a386Sopenharmony_ci // Everything is okay. 206cb93a386Sopenharmony_ci break; 207cb93a386Sopenharmony_ci default: 208cb93a386Sopenharmony_ci // No other values should be passed to longjmp. 209cb93a386Sopenharmony_ci SkASSERT(false); 210cb93a386Sopenharmony_ci } 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_ci // Arbitrary buffer size 213cb93a386Sopenharmony_ci#ifdef TURBO_PNG_MULTY_LINE_OPT 214cb93a386Sopenharmony_ci // OH ISSUE: png optimize 215cb93a386Sopenharmony_ci constexpr size_t kBufferSize = 65536; // 65536, expand buffer to improve performance 216cb93a386Sopenharmony_ci#else 217cb93a386Sopenharmony_ci constexpr size_t kBufferSize = 4096; 218cb93a386Sopenharmony_ci#endif 219cb93a386Sopenharmony_ci char buffer[kBufferSize]; 220cb93a386Sopenharmony_ci 221cb93a386Sopenharmony_ci bool iend = false; 222cb93a386Sopenharmony_ci while (true) { 223cb93a386Sopenharmony_ci size_t length; 224cb93a386Sopenharmony_ci if (fDecodedIdat) { 225cb93a386Sopenharmony_ci // Parse chunk length and type. 226cb93a386Sopenharmony_ci if (this->stream()->read(buffer, 8) < 8) { 227cb93a386Sopenharmony_ci break; 228cb93a386Sopenharmony_ci } 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci png_byte* chunk = reinterpret_cast<png_byte*>(buffer); 231cb93a386Sopenharmony_ci png_process_data(fPng_ptr, fInfo_ptr, chunk, 8); 232cb93a386Sopenharmony_ci if (is_chunk(chunk, "IEND")) { 233cb93a386Sopenharmony_ci iend = true; 234cb93a386Sopenharmony_ci } 235cb93a386Sopenharmony_ci 236cb93a386Sopenharmony_ci length = png_get_uint_32(chunk); 237cb93a386Sopenharmony_ci } else { 238cb93a386Sopenharmony_ci length = fIdatLength; 239cb93a386Sopenharmony_ci png_byte idat[] = {0, 0, 0, 0, 'I', 'D', 'A', 'T'}; 240cb93a386Sopenharmony_ci png_save_uint_32(idat, length); 241cb93a386Sopenharmony_ci png_process_data(fPng_ptr, fInfo_ptr, idat, 8); 242cb93a386Sopenharmony_ci fDecodedIdat = true; 243cb93a386Sopenharmony_ci } 244cb93a386Sopenharmony_ci 245cb93a386Sopenharmony_ci // Process the full chunk + CRC. 246cb93a386Sopenharmony_ci if (!process_data(fPng_ptr, fInfo_ptr, this->stream(), buffer, kBufferSize, length + 4) 247cb93a386Sopenharmony_ci || iend) { 248cb93a386Sopenharmony_ci break; 249cb93a386Sopenharmony_ci } 250cb93a386Sopenharmony_ci } 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci return true; 253cb93a386Sopenharmony_ci} 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_cistatic constexpr SkColorType kXformSrcColorType = kRGBA_8888_SkColorType; 256cb93a386Sopenharmony_ci 257cb93a386Sopenharmony_cistatic inline bool needs_premul(SkAlphaType dstAT, SkEncodedInfo::Alpha encodedAlpha) { 258cb93a386Sopenharmony_ci return kPremul_SkAlphaType == dstAT && SkEncodedInfo::kUnpremul_Alpha == encodedAlpha; 259cb93a386Sopenharmony_ci} 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_ci// Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here. 262cb93a386Sopenharmony_cibool SkPngCodec::createColorTable(const SkImageInfo& dstInfo) { 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_ci int numColors; 265cb93a386Sopenharmony_ci png_color* palette; 266cb93a386Sopenharmony_ci if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) { 267cb93a386Sopenharmony_ci return false; 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci 270cb93a386Sopenharmony_ci // Contents depend on tableColorType and our choice of if/when to premultiply: 271cb93a386Sopenharmony_ci // { kPremul, kUnpremul, kOpaque } x { RGBA, BGRA } 272cb93a386Sopenharmony_ci SkPMColor colorTable[256]; 273cb93a386Sopenharmony_ci SkColorType tableColorType = this->colorXform() ? kXformSrcColorType : dstInfo.colorType(); 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_ci png_bytep alphas; 276cb93a386Sopenharmony_ci int numColorsWithAlpha = 0; 277cb93a386Sopenharmony_ci if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) { 278cb93a386Sopenharmony_ci bool premultiply = needs_premul(dstInfo.alphaType(), this->getEncodedInfo().alpha()); 279cb93a386Sopenharmony_ci 280cb93a386Sopenharmony_ci // Choose which function to use to create the color table. If the final destination's 281cb93a386Sopenharmony_ci // colortype is unpremultiplied, the color table will store unpremultiplied colors. 282cb93a386Sopenharmony_ci PackColorProc proc = choose_pack_color_proc(premultiply, tableColorType); 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci for (int i = 0; i < numColorsWithAlpha; i++) { 285cb93a386Sopenharmony_ci // We don't have a function in SkOpts that combines a set of alphas with a set 286cb93a386Sopenharmony_ci // of RGBs. We could write one, but it's hardly worth it, given that this 287cb93a386Sopenharmony_ci // is such a small fraction of the total decode time. 288cb93a386Sopenharmony_ci colorTable[i] = proc(alphas[i], palette->red, palette->green, palette->blue); 289cb93a386Sopenharmony_ci palette++; 290cb93a386Sopenharmony_ci } 291cb93a386Sopenharmony_ci } 292cb93a386Sopenharmony_ci 293cb93a386Sopenharmony_ci if (numColorsWithAlpha < numColors) { 294cb93a386Sopenharmony_ci // The optimized code depends on a 3-byte png_color struct with the colors 295cb93a386Sopenharmony_ci // in RGB order. These checks make sure it is safe to use. 296cb93a386Sopenharmony_ci static_assert(3 == sizeof(png_color), "png_color struct has changed. Opts are broken."); 297cb93a386Sopenharmony_ci#ifdef SK_DEBUG 298cb93a386Sopenharmony_ci SkASSERT(&palette->red < &palette->green); 299cb93a386Sopenharmony_ci SkASSERT(&palette->green < &palette->blue); 300cb93a386Sopenharmony_ci#endif 301cb93a386Sopenharmony_ci 302cb93a386Sopenharmony_ci if (is_rgba(tableColorType)) { 303cb93a386Sopenharmony_ci SkOpts::RGB_to_RGB1(colorTable + numColorsWithAlpha, (const uint8_t*)palette, 304cb93a386Sopenharmony_ci numColors - numColorsWithAlpha); 305cb93a386Sopenharmony_ci } else { 306cb93a386Sopenharmony_ci SkOpts::RGB_to_BGR1(colorTable + numColorsWithAlpha, (const uint8_t*)palette, 307cb93a386Sopenharmony_ci numColors - numColorsWithAlpha); 308cb93a386Sopenharmony_ci } 309cb93a386Sopenharmony_ci } 310cb93a386Sopenharmony_ci 311cb93a386Sopenharmony_ci if (this->colorXform() && !this->xformOnDecode()) { 312cb93a386Sopenharmony_ci this->applyColorXform(colorTable, colorTable, numColors); 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci // Pad the color table with the last color in the table (or black) in the case that 316cb93a386Sopenharmony_ci // invalid pixel indices exceed the number of colors in the table. 317cb93a386Sopenharmony_ci const int maxColors = 1 << fBitDepth; 318cb93a386Sopenharmony_ci if (numColors < maxColors) { 319cb93a386Sopenharmony_ci SkPMColor lastColor = numColors > 0 ? colorTable[numColors - 1] : SK_ColorBLACK; 320cb93a386Sopenharmony_ci sk_memset32(colorTable + numColors, lastColor, maxColors - numColors); 321cb93a386Sopenharmony_ci } 322cb93a386Sopenharmony_ci 323cb93a386Sopenharmony_ci fColorTable.reset(new SkColorTable(colorTable, maxColors)); 324cb93a386Sopenharmony_ci return true; 325cb93a386Sopenharmony_ci} 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 328cb93a386Sopenharmony_ci// Creation 329cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 330cb93a386Sopenharmony_ci 331cb93a386Sopenharmony_cibool SkPngCodec::IsPng(const void* buf, size_t bytesRead) { 332cb93a386Sopenharmony_ci return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead); 333cb93a386Sopenharmony_ci} 334cb93a386Sopenharmony_ci 335cb93a386Sopenharmony_ci#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6) 336cb93a386Sopenharmony_ci 337cb93a386Sopenharmony_cistatic float png_fixed_point_to_float(png_fixed_point x) { 338cb93a386Sopenharmony_ci // We multiply by the same factor that libpng used to convert 339cb93a386Sopenharmony_ci // fixed point -> double. Since we want floats, we choose to 340cb93a386Sopenharmony_ci // do the conversion ourselves rather than convert 341cb93a386Sopenharmony_ci // fixed point -> double -> float. 342cb93a386Sopenharmony_ci return ((float) x) * 0.00001f; 343cb93a386Sopenharmony_ci} 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_cistatic float png_inverted_fixed_point_to_float(png_fixed_point x) { 346cb93a386Sopenharmony_ci // This is necessary because the gAMA chunk actually stores 1/gamma. 347cb93a386Sopenharmony_ci return 1.0f / png_fixed_point_to_float(x); 348cb93a386Sopenharmony_ci} 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_ci#endif // LIBPNG >= 1.6 351cb93a386Sopenharmony_ci 352cb93a386Sopenharmony_ci// If there is no color profile information, it will use sRGB. 353cb93a386Sopenharmony_cistd::unique_ptr<SkEncodedInfo::ICCProfile> read_color_profile(png_structp png_ptr, 354cb93a386Sopenharmony_ci png_infop info_ptr) { 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6) 357cb93a386Sopenharmony_ci // First check for an ICC profile 358cb93a386Sopenharmony_ci png_bytep profile; 359cb93a386Sopenharmony_ci png_uint_32 length; 360cb93a386Sopenharmony_ci // The below variables are unused, however, we need to pass them in anyway or 361cb93a386Sopenharmony_ci // png_get_iCCP() will return nothing. 362cb93a386Sopenharmony_ci // Could knowing the |name| of the profile ever be interesting? Maybe for debugging? 363cb93a386Sopenharmony_ci png_charp name; 364cb93a386Sopenharmony_ci // The |compression| is uninteresting since: 365cb93a386Sopenharmony_ci // (1) libpng has already decompressed the profile for us. 366cb93a386Sopenharmony_ci // (2) "deflate" is the only mode of decompression that libpng supports. 367cb93a386Sopenharmony_ci int compression; 368cb93a386Sopenharmony_ci if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile, 369cb93a386Sopenharmony_ci &length)) { 370cb93a386Sopenharmony_ci auto data = SkData::MakeWithCopy(profile, length); 371cb93a386Sopenharmony_ci return SkEncodedInfo::ICCProfile::Make(std::move(data)); 372cb93a386Sopenharmony_ci } 373cb93a386Sopenharmony_ci 374cb93a386Sopenharmony_ci // Second, check for sRGB. 375cb93a386Sopenharmony_ci // Note that Blink does this first. This code checks ICC first, with the thinking that 376cb93a386Sopenharmony_ci // an image has both truly wants the potentially more specific ICC chunk, with sRGB as a 377cb93a386Sopenharmony_ci // backup in case the decoder does not support full color management. 378cb93a386Sopenharmony_ci if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) { 379cb93a386Sopenharmony_ci // sRGB chunks also store a rendering intent: Absolute, Relative, 380cb93a386Sopenharmony_ci // Perceptual, and Saturation. 381cb93a386Sopenharmony_ci // FIXME (scroggo): Extract this information from the sRGB chunk once 382cb93a386Sopenharmony_ci // we are able to handle this information in 383cb93a386Sopenharmony_ci // skcms_ICCProfile 384cb93a386Sopenharmony_ci return nullptr; 385cb93a386Sopenharmony_ci } 386cb93a386Sopenharmony_ci 387cb93a386Sopenharmony_ci // Default to SRGB gamut. 388cb93a386Sopenharmony_ci skcms_Matrix3x3 toXYZD50 = skcms_sRGB_profile()->toXYZD50; 389cb93a386Sopenharmony_ci // Next, check for chromaticities. 390cb93a386Sopenharmony_ci png_fixed_point chrm[8]; 391cb93a386Sopenharmony_ci png_fixed_point gamma; 392cb93a386Sopenharmony_ci if (png_get_cHRM_fixed(png_ptr, info_ptr, &chrm[0], &chrm[1], &chrm[2], &chrm[3], &chrm[4], 393cb93a386Sopenharmony_ci &chrm[5], &chrm[6], &chrm[7])) 394cb93a386Sopenharmony_ci { 395cb93a386Sopenharmony_ci float rx = png_fixed_point_to_float(chrm[2]); 396cb93a386Sopenharmony_ci float ry = png_fixed_point_to_float(chrm[3]); 397cb93a386Sopenharmony_ci float gx = png_fixed_point_to_float(chrm[4]); 398cb93a386Sopenharmony_ci float gy = png_fixed_point_to_float(chrm[5]); 399cb93a386Sopenharmony_ci float bx = png_fixed_point_to_float(chrm[6]); 400cb93a386Sopenharmony_ci float by = png_fixed_point_to_float(chrm[7]); 401cb93a386Sopenharmony_ci float wx = png_fixed_point_to_float(chrm[0]); 402cb93a386Sopenharmony_ci float wy = png_fixed_point_to_float(chrm[1]); 403cb93a386Sopenharmony_ci 404cb93a386Sopenharmony_ci skcms_Matrix3x3 tmp; 405cb93a386Sopenharmony_ci if (skcms_PrimariesToXYZD50(rx, ry, gx, gy, bx, by, wx, wy, &tmp)) { 406cb93a386Sopenharmony_ci toXYZD50 = tmp; 407cb93a386Sopenharmony_ci } else { 408cb93a386Sopenharmony_ci // Note that Blink simply returns nullptr in this case. We'll fall 409cb93a386Sopenharmony_ci // back to srgb. 410cb93a386Sopenharmony_ci } 411cb93a386Sopenharmony_ci } 412cb93a386Sopenharmony_ci 413cb93a386Sopenharmony_ci skcms_TransferFunction fn; 414cb93a386Sopenharmony_ci if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { 415cb93a386Sopenharmony_ci fn.a = 1.0f; 416cb93a386Sopenharmony_ci fn.b = fn.c = fn.d = fn.e = fn.f = 0.0f; 417cb93a386Sopenharmony_ci fn.g = png_inverted_fixed_point_to_float(gamma); 418cb93a386Sopenharmony_ci } else { 419cb93a386Sopenharmony_ci // Default to sRGB gamma if the image has color space information, 420cb93a386Sopenharmony_ci // but does not specify gamma. 421cb93a386Sopenharmony_ci // Note that Blink would again return nullptr in this case. 422cb93a386Sopenharmony_ci fn = *skcms_sRGB_TransferFunction(); 423cb93a386Sopenharmony_ci } 424cb93a386Sopenharmony_ci 425cb93a386Sopenharmony_ci skcms_ICCProfile skcmsProfile; 426cb93a386Sopenharmony_ci skcms_Init(&skcmsProfile); 427cb93a386Sopenharmony_ci skcms_SetTransferFunction(&skcmsProfile, &fn); 428cb93a386Sopenharmony_ci skcms_SetXYZD50(&skcmsProfile, &toXYZD50); 429cb93a386Sopenharmony_ci 430cb93a386Sopenharmony_ci return SkEncodedInfo::ICCProfile::Make(skcmsProfile); 431cb93a386Sopenharmony_ci#else // LIBPNG >= 1.6 432cb93a386Sopenharmony_ci return nullptr; 433cb93a386Sopenharmony_ci#endif // LIBPNG >= 1.6 434cb93a386Sopenharmony_ci} 435cb93a386Sopenharmony_ci 436cb93a386Sopenharmony_civoid SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) { 437cb93a386Sopenharmony_ci switch (fXformMode) { 438cb93a386Sopenharmony_ci case kSwizzleOnly_XformMode: 439cb93a386Sopenharmony_ci break; 440cb93a386Sopenharmony_ci case kColorOnly_XformMode: 441cb93a386Sopenharmony_ci // Intentional fall through. A swizzler hasn't been created yet, but one will 442cb93a386Sopenharmony_ci // be created later if we are sampling. We'll go ahead and allocate 443cb93a386Sopenharmony_ci // enough memory to swizzle if necessary. 444cb93a386Sopenharmony_ci case kSwizzleColor_XformMode: { 445cb93a386Sopenharmony_ci const int bitsPerPixel = this->getEncodedInfo().bitsPerPixel(); 446cb93a386Sopenharmony_ci 447cb93a386Sopenharmony_ci // If we have more than 8-bits (per component) of precision, we will keep that 448cb93a386Sopenharmony_ci // extra precision. Otherwise, we will swizzle to RGBA_8888 before transforming. 449cb93a386Sopenharmony_ci const size_t bytesPerPixel = (bitsPerPixel > 32) ? bitsPerPixel / 8 : 4; 450cb93a386Sopenharmony_ci const size_t colorXformBytes = dstInfo.width() * bytesPerPixel; 451cb93a386Sopenharmony_ci fStorage.reset(colorXformBytes); 452cb93a386Sopenharmony_ci fColorXformSrcRow = fStorage.get(); 453cb93a386Sopenharmony_ci break; 454cb93a386Sopenharmony_ci } 455cb93a386Sopenharmony_ci } 456cb93a386Sopenharmony_ci} 457cb93a386Sopenharmony_ci 458cb93a386Sopenharmony_cistatic skcms_PixelFormat png_select_xform_format(const SkEncodedInfo& info) { 459cb93a386Sopenharmony_ci // We use kRGB and kRGBA formats because color PNGs are always RGB or RGBA. 460cb93a386Sopenharmony_ci if (16 == info.bitsPerComponent()) { 461cb93a386Sopenharmony_ci if (SkEncodedInfo::kRGBA_Color == info.color()) { 462cb93a386Sopenharmony_ci return skcms_PixelFormat_RGBA_16161616BE; 463cb93a386Sopenharmony_ci } else if (SkEncodedInfo::kRGB_Color == info.color()) { 464cb93a386Sopenharmony_ci return skcms_PixelFormat_RGB_161616BE; 465cb93a386Sopenharmony_ci } 466cb93a386Sopenharmony_ci } else if (SkEncodedInfo::kGray_Color == info.color()) { 467cb93a386Sopenharmony_ci return skcms_PixelFormat_G_8; 468cb93a386Sopenharmony_ci } 469cb93a386Sopenharmony_ci 470cb93a386Sopenharmony_ci return skcms_PixelFormat_RGBA_8888; 471cb93a386Sopenharmony_ci} 472cb93a386Sopenharmony_ci 473cb93a386Sopenharmony_civoid SkPngCodec::applyXformRow(void* dst, const void* src) { 474cb93a386Sopenharmony_ci switch (fXformMode) { 475cb93a386Sopenharmony_ci case kSwizzleOnly_XformMode: 476cb93a386Sopenharmony_ci fSwizzler->swizzle(dst, (const uint8_t*) src); 477cb93a386Sopenharmony_ci break; 478cb93a386Sopenharmony_ci case kColorOnly_XformMode: 479cb93a386Sopenharmony_ci this->applyColorXform(dst, src, fXformWidth); 480cb93a386Sopenharmony_ci break; 481cb93a386Sopenharmony_ci case kSwizzleColor_XformMode: 482cb93a386Sopenharmony_ci fSwizzler->swizzle(fColorXformSrcRow, (const uint8_t*) src); 483cb93a386Sopenharmony_ci this->applyColorXform(dst, fColorXformSrcRow, fXformWidth); 484cb93a386Sopenharmony_ci break; 485cb93a386Sopenharmony_ci } 486cb93a386Sopenharmony_ci} 487cb93a386Sopenharmony_ci 488cb93a386Sopenharmony_cistatic SkCodec::Result log_and_return_error(bool success) { 489cb93a386Sopenharmony_ci if (success) return SkCodec::kIncompleteInput; 490cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 491cb93a386Sopenharmony_ci SkAndroidFrameworkUtils::SafetyNetLog("117838472"); 492cb93a386Sopenharmony_ci#endif 493cb93a386Sopenharmony_ci return SkCodec::kErrorInInput; 494cb93a386Sopenharmony_ci} 495cb93a386Sopenharmony_ci 496cb93a386Sopenharmony_ciclass SkPngNormalDecoder : public SkPngCodec { 497cb93a386Sopenharmony_cipublic: 498cb93a386Sopenharmony_ci SkPngNormalDecoder(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream, 499cb93a386Sopenharmony_ci SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, int bitDepth) 500cb93a386Sopenharmony_ci : INHERITED(std::move(info), std::move(stream), reader, png_ptr, info_ptr, bitDepth) 501cb93a386Sopenharmony_ci , fRowsWrittenToOutput(0) 502cb93a386Sopenharmony_ci , fDst(nullptr) 503cb93a386Sopenharmony_ci , fRowBytes(0) 504cb93a386Sopenharmony_ci , fFirstRow(0) 505cb93a386Sopenharmony_ci , fLastRow(0) 506cb93a386Sopenharmony_ci {} 507cb93a386Sopenharmony_ci 508cb93a386Sopenharmony_ci static void AllRowsCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) { 509cb93a386Sopenharmony_ci GetDecoder(png_ptr)->allRowsCallback(row, rowNum); 510cb93a386Sopenharmony_ci } 511cb93a386Sopenharmony_ci 512cb93a386Sopenharmony_ci static void RowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) { 513cb93a386Sopenharmony_ci GetDecoder(png_ptr)->rowCallback(row, rowNum); 514cb93a386Sopenharmony_ci } 515cb93a386Sopenharmony_ci 516cb93a386Sopenharmony_ciprivate: 517cb93a386Sopenharmony_ci int fRowsWrittenToOutput; 518cb93a386Sopenharmony_ci void* fDst; 519cb93a386Sopenharmony_ci size_t fRowBytes; 520cb93a386Sopenharmony_ci 521cb93a386Sopenharmony_ci // Variables for partial decode 522cb93a386Sopenharmony_ci int fFirstRow; // FIXME: Move to baseclass? 523cb93a386Sopenharmony_ci int fLastRow; 524cb93a386Sopenharmony_ci int fRowsNeeded; 525cb93a386Sopenharmony_ci 526cb93a386Sopenharmony_ci using INHERITED = SkPngCodec; 527cb93a386Sopenharmony_ci 528cb93a386Sopenharmony_ci static SkPngNormalDecoder* GetDecoder(png_structp png_ptr) { 529cb93a386Sopenharmony_ci return static_cast<SkPngNormalDecoder*>(png_get_progressive_ptr(png_ptr)); 530cb93a386Sopenharmony_ci } 531cb93a386Sopenharmony_ci 532cb93a386Sopenharmony_ci Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override { 533cb93a386Sopenharmony_ci const int height = this->dimensions().height(); 534cb93a386Sopenharmony_ci png_set_progressive_read_fn(this->png_ptr(), this, nullptr, AllRowsCallback, nullptr); 535cb93a386Sopenharmony_ci fDst = dst; 536cb93a386Sopenharmony_ci fRowBytes = rowBytes; 537cb93a386Sopenharmony_ci 538cb93a386Sopenharmony_ci fRowsWrittenToOutput = 0; 539cb93a386Sopenharmony_ci fFirstRow = 0; 540cb93a386Sopenharmony_ci fLastRow = height - 1; 541cb93a386Sopenharmony_ci 542cb93a386Sopenharmony_ci const bool success = this->processData(); 543cb93a386Sopenharmony_ci if (success && fRowsWrittenToOutput == height) { 544cb93a386Sopenharmony_ci return kSuccess; 545cb93a386Sopenharmony_ci } 546cb93a386Sopenharmony_ci 547cb93a386Sopenharmony_ci if (rowsDecoded) { 548cb93a386Sopenharmony_ci *rowsDecoded = fRowsWrittenToOutput; 549cb93a386Sopenharmony_ci } 550cb93a386Sopenharmony_ci 551cb93a386Sopenharmony_ci return log_and_return_error(success); 552cb93a386Sopenharmony_ci } 553cb93a386Sopenharmony_ci 554cb93a386Sopenharmony_ci void allRowsCallback(png_bytep row, int rowNum) { 555cb93a386Sopenharmony_ci SkASSERT(rowNum == fRowsWrittenToOutput); 556cb93a386Sopenharmony_ci fRowsWrittenToOutput++; 557cb93a386Sopenharmony_ci this->applyXformRow(fDst, row); 558cb93a386Sopenharmony_ci fDst = SkTAddOffset<void>(fDst, fRowBytes); 559cb93a386Sopenharmony_ci } 560cb93a386Sopenharmony_ci 561cb93a386Sopenharmony_ci void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override { 562cb93a386Sopenharmony_ci png_set_progressive_read_fn(this->png_ptr(), this, nullptr, RowCallback, nullptr); 563cb93a386Sopenharmony_ci fFirstRow = firstRow; 564cb93a386Sopenharmony_ci fLastRow = lastRow; 565cb93a386Sopenharmony_ci fDst = dst; 566cb93a386Sopenharmony_ci fRowBytes = rowBytes; 567cb93a386Sopenharmony_ci fRowsWrittenToOutput = 0; 568cb93a386Sopenharmony_ci fRowsNeeded = fLastRow - fFirstRow + 1; 569cb93a386Sopenharmony_ci } 570cb93a386Sopenharmony_ci 571cb93a386Sopenharmony_ci Result decode(int* rowsDecoded) override { 572cb93a386Sopenharmony_ci if (this->swizzler()) { 573cb93a386Sopenharmony_ci const int sampleY = this->swizzler()->sampleY(); 574cb93a386Sopenharmony_ci fRowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY); 575cb93a386Sopenharmony_ci } 576cb93a386Sopenharmony_ci 577cb93a386Sopenharmony_ci const bool success = this->processData(); 578cb93a386Sopenharmony_ci if (success && fRowsWrittenToOutput == fRowsNeeded) { 579cb93a386Sopenharmony_ci return kSuccess; 580cb93a386Sopenharmony_ci } 581cb93a386Sopenharmony_ci 582cb93a386Sopenharmony_ci if (rowsDecoded) { 583cb93a386Sopenharmony_ci *rowsDecoded = fRowsWrittenToOutput; 584cb93a386Sopenharmony_ci } 585cb93a386Sopenharmony_ci 586cb93a386Sopenharmony_ci return log_and_return_error(success); 587cb93a386Sopenharmony_ci } 588cb93a386Sopenharmony_ci 589cb93a386Sopenharmony_ci void rowCallback(png_bytep row, int rowNum) { 590cb93a386Sopenharmony_ci if (rowNum < fFirstRow) { 591cb93a386Sopenharmony_ci // Ignore this row. 592cb93a386Sopenharmony_ci return; 593cb93a386Sopenharmony_ci } 594cb93a386Sopenharmony_ci 595cb93a386Sopenharmony_ci SkASSERT(rowNum <= fLastRow); 596cb93a386Sopenharmony_ci SkASSERT(fRowsWrittenToOutput < fRowsNeeded); 597cb93a386Sopenharmony_ci 598cb93a386Sopenharmony_ci // If there is no swizzler, all rows are needed. 599cb93a386Sopenharmony_ci if (!this->swizzler() || this->swizzler()->rowNeeded(rowNum - fFirstRow)) { 600cb93a386Sopenharmony_ci this->applyXformRow(fDst, row); 601cb93a386Sopenharmony_ci fDst = SkTAddOffset<void>(fDst, fRowBytes); 602cb93a386Sopenharmony_ci fRowsWrittenToOutput++; 603cb93a386Sopenharmony_ci } 604cb93a386Sopenharmony_ci 605cb93a386Sopenharmony_ci if (fRowsWrittenToOutput == fRowsNeeded) { 606cb93a386Sopenharmony_ci // Fake error to stop decoding scanlines. 607cb93a386Sopenharmony_ci longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding); 608cb93a386Sopenharmony_ci } 609cb93a386Sopenharmony_ci } 610cb93a386Sopenharmony_ci}; 611cb93a386Sopenharmony_ci 612cb93a386Sopenharmony_ciclass SkPngInterlacedDecoder : public SkPngCodec { 613cb93a386Sopenharmony_cipublic: 614cb93a386Sopenharmony_ci SkPngInterlacedDecoder(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream, 615cb93a386Sopenharmony_ci SkPngChunkReader* reader, png_structp png_ptr, 616cb93a386Sopenharmony_ci png_infop info_ptr, int bitDepth, int numberPasses) 617cb93a386Sopenharmony_ci : INHERITED(std::move(info), std::move(stream), reader, png_ptr, info_ptr, bitDepth) 618cb93a386Sopenharmony_ci , fNumberPasses(numberPasses) 619cb93a386Sopenharmony_ci , fFirstRow(0) 620cb93a386Sopenharmony_ci , fLastRow(0) 621cb93a386Sopenharmony_ci , fLinesDecoded(0) 622cb93a386Sopenharmony_ci , fInterlacedComplete(false) 623cb93a386Sopenharmony_ci , fPng_rowbytes(0) 624cb93a386Sopenharmony_ci {} 625cb93a386Sopenharmony_ci 626cb93a386Sopenharmony_ci static void InterlacedRowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int pass) { 627cb93a386Sopenharmony_ci auto decoder = static_cast<SkPngInterlacedDecoder*>(png_get_progressive_ptr(png_ptr)); 628cb93a386Sopenharmony_ci decoder->interlacedRowCallback(row, rowNum, pass); 629cb93a386Sopenharmony_ci } 630cb93a386Sopenharmony_ci 631cb93a386Sopenharmony_ciprivate: 632cb93a386Sopenharmony_ci const int fNumberPasses; 633cb93a386Sopenharmony_ci int fFirstRow; 634cb93a386Sopenharmony_ci int fLastRow; 635cb93a386Sopenharmony_ci void* fDst; 636cb93a386Sopenharmony_ci size_t fRowBytes; 637cb93a386Sopenharmony_ci int fLinesDecoded; 638cb93a386Sopenharmony_ci bool fInterlacedComplete; 639cb93a386Sopenharmony_ci size_t fPng_rowbytes; 640cb93a386Sopenharmony_ci SkAutoTMalloc<png_byte> fInterlaceBuffer; 641cb93a386Sopenharmony_ci 642cb93a386Sopenharmony_ci using INHERITED = SkPngCodec; 643cb93a386Sopenharmony_ci 644cb93a386Sopenharmony_ci // FIXME: Currently sharing interlaced callback for all rows and subset. It's not 645cb93a386Sopenharmony_ci // as expensive as the subset version of non-interlaced, but it still does extra 646cb93a386Sopenharmony_ci // work. 647cb93a386Sopenharmony_ci void interlacedRowCallback(png_bytep row, int rowNum, int pass) { 648cb93a386Sopenharmony_ci if (rowNum < fFirstRow || rowNum > fLastRow || fInterlacedComplete) { 649cb93a386Sopenharmony_ci // Ignore this row 650cb93a386Sopenharmony_ci return; 651cb93a386Sopenharmony_ci } 652cb93a386Sopenharmony_ci 653cb93a386Sopenharmony_ci png_bytep oldRow = fInterlaceBuffer.get() + (rowNum - fFirstRow) * fPng_rowbytes; 654cb93a386Sopenharmony_ci png_progressive_combine_row(this->png_ptr(), oldRow, row); 655cb93a386Sopenharmony_ci 656cb93a386Sopenharmony_ci if (0 == pass) { 657cb93a386Sopenharmony_ci // The first pass initializes all rows. 658cb93a386Sopenharmony_ci SkASSERT(row); 659cb93a386Sopenharmony_ci SkASSERT(fLinesDecoded == rowNum - fFirstRow); 660cb93a386Sopenharmony_ci fLinesDecoded++; 661cb93a386Sopenharmony_ci } else { 662cb93a386Sopenharmony_ci SkASSERT(fLinesDecoded == fLastRow - fFirstRow + 1); 663cb93a386Sopenharmony_ci if (fNumberPasses - 1 == pass && rowNum == fLastRow) { 664cb93a386Sopenharmony_ci // Last pass, and we have read all of the rows we care about. 665cb93a386Sopenharmony_ci fInterlacedComplete = true; 666cb93a386Sopenharmony_ci if (fLastRow != this->dimensions().height() - 1 || 667cb93a386Sopenharmony_ci (this->swizzler() && this->swizzler()->sampleY() != 1)) { 668cb93a386Sopenharmony_ci // Fake error to stop decoding scanlines. Only stop if we're not decoding the 669cb93a386Sopenharmony_ci // whole image, in which case processing the rest of the image might be 670cb93a386Sopenharmony_ci // expensive. When decoding the whole image, read through the IEND chunk to 671cb93a386Sopenharmony_ci // preserve Android behavior of leaving the input stream in the right place. 672cb93a386Sopenharmony_ci longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding); 673cb93a386Sopenharmony_ci } 674cb93a386Sopenharmony_ci } 675cb93a386Sopenharmony_ci } 676cb93a386Sopenharmony_ci } 677cb93a386Sopenharmony_ci 678cb93a386Sopenharmony_ci Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override { 679cb93a386Sopenharmony_ci const int height = this->dimensions().height(); 680cb93a386Sopenharmony_ci this->setUpInterlaceBuffer(height); 681cb93a386Sopenharmony_ci png_set_progressive_read_fn(this->png_ptr(), this, nullptr, InterlacedRowCallback, 682cb93a386Sopenharmony_ci nullptr); 683cb93a386Sopenharmony_ci 684cb93a386Sopenharmony_ci fFirstRow = 0; 685cb93a386Sopenharmony_ci fLastRow = height - 1; 686cb93a386Sopenharmony_ci fLinesDecoded = 0; 687cb93a386Sopenharmony_ci 688cb93a386Sopenharmony_ci const bool success = this->processData(); 689cb93a386Sopenharmony_ci png_bytep srcRow = fInterlaceBuffer.get(); 690cb93a386Sopenharmony_ci // FIXME: When resuming, this may rewrite rows that did not change. 691cb93a386Sopenharmony_ci for (int rowNum = 0; rowNum < fLinesDecoded; rowNum++) { 692cb93a386Sopenharmony_ci this->applyXformRow(dst, srcRow); 693cb93a386Sopenharmony_ci dst = SkTAddOffset<void>(dst, rowBytes); 694cb93a386Sopenharmony_ci srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes); 695cb93a386Sopenharmony_ci } 696cb93a386Sopenharmony_ci if (success && fInterlacedComplete) { 697cb93a386Sopenharmony_ci return kSuccess; 698cb93a386Sopenharmony_ci } 699cb93a386Sopenharmony_ci 700cb93a386Sopenharmony_ci if (rowsDecoded) { 701cb93a386Sopenharmony_ci *rowsDecoded = fLinesDecoded; 702cb93a386Sopenharmony_ci } 703cb93a386Sopenharmony_ci 704cb93a386Sopenharmony_ci return log_and_return_error(success); 705cb93a386Sopenharmony_ci } 706cb93a386Sopenharmony_ci 707cb93a386Sopenharmony_ci void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override { 708cb93a386Sopenharmony_ci // FIXME: We could skip rows in the interlace buffer that we won't put in the output. 709cb93a386Sopenharmony_ci this->setUpInterlaceBuffer(lastRow - firstRow + 1); 710cb93a386Sopenharmony_ci png_set_progressive_read_fn(this->png_ptr(), this, nullptr, InterlacedRowCallback, nullptr); 711cb93a386Sopenharmony_ci fFirstRow = firstRow; 712cb93a386Sopenharmony_ci fLastRow = lastRow; 713cb93a386Sopenharmony_ci fDst = dst; 714cb93a386Sopenharmony_ci fRowBytes = rowBytes; 715cb93a386Sopenharmony_ci fLinesDecoded = 0; 716cb93a386Sopenharmony_ci } 717cb93a386Sopenharmony_ci 718cb93a386Sopenharmony_ci Result decode(int* rowsDecoded) override { 719cb93a386Sopenharmony_ci const bool success = this->processData(); 720cb93a386Sopenharmony_ci 721cb93a386Sopenharmony_ci // Now apply Xforms on all the rows that were decoded. 722cb93a386Sopenharmony_ci if (!fLinesDecoded) { 723cb93a386Sopenharmony_ci if (rowsDecoded) { 724cb93a386Sopenharmony_ci *rowsDecoded = 0; 725cb93a386Sopenharmony_ci } 726cb93a386Sopenharmony_ci return log_and_return_error(success); 727cb93a386Sopenharmony_ci } 728cb93a386Sopenharmony_ci 729cb93a386Sopenharmony_ci const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1; 730cb93a386Sopenharmony_ci const int rowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY); 731cb93a386Sopenharmony_ci 732cb93a386Sopenharmony_ci // FIXME: For resuming interlace, we may swizzle a row that hasn't changed. But it 733cb93a386Sopenharmony_ci // may be too tricky/expensive to handle that correctly. 734cb93a386Sopenharmony_ci 735cb93a386Sopenharmony_ci // Offset srcRow by get_start_coord rows. We do not need to account for fFirstRow, 736cb93a386Sopenharmony_ci // since the first row in fInterlaceBuffer corresponds to fFirstRow. 737cb93a386Sopenharmony_ci int srcRow = get_start_coord(sampleY); 738cb93a386Sopenharmony_ci void* dst = fDst; 739cb93a386Sopenharmony_ci int rowsWrittenToOutput = 0; 740cb93a386Sopenharmony_ci while (rowsWrittenToOutput < rowsNeeded && srcRow < fLinesDecoded) { 741cb93a386Sopenharmony_ci png_bytep src = SkTAddOffset<png_byte>(fInterlaceBuffer.get(), fPng_rowbytes * srcRow); 742cb93a386Sopenharmony_ci this->applyXformRow(dst, src); 743cb93a386Sopenharmony_ci dst = SkTAddOffset<void>(dst, fRowBytes); 744cb93a386Sopenharmony_ci 745cb93a386Sopenharmony_ci rowsWrittenToOutput++; 746cb93a386Sopenharmony_ci srcRow += sampleY; 747cb93a386Sopenharmony_ci } 748cb93a386Sopenharmony_ci 749cb93a386Sopenharmony_ci if (success && fInterlacedComplete) { 750cb93a386Sopenharmony_ci return kSuccess; 751cb93a386Sopenharmony_ci } 752cb93a386Sopenharmony_ci 753cb93a386Sopenharmony_ci if (rowsDecoded) { 754cb93a386Sopenharmony_ci *rowsDecoded = rowsWrittenToOutput; 755cb93a386Sopenharmony_ci } 756cb93a386Sopenharmony_ci return log_and_return_error(success); 757cb93a386Sopenharmony_ci } 758cb93a386Sopenharmony_ci 759cb93a386Sopenharmony_ci void setUpInterlaceBuffer(int height) { 760cb93a386Sopenharmony_ci fPng_rowbytes = png_get_rowbytes(this->png_ptr(), this->info_ptr()); 761cb93a386Sopenharmony_ci fInterlaceBuffer.reset(fPng_rowbytes * height); 762cb93a386Sopenharmony_ci fInterlacedComplete = false; 763cb93a386Sopenharmony_ci } 764cb93a386Sopenharmony_ci}; 765cb93a386Sopenharmony_ci 766cb93a386Sopenharmony_ci// Reads the header and initializes the output fields, if not NULL. 767cb93a386Sopenharmony_ci// 768cb93a386Sopenharmony_ci// @param stream Input data. Will be read to get enough information to properly 769cb93a386Sopenharmony_ci// setup the codec. 770cb93a386Sopenharmony_ci// @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL. 771cb93a386Sopenharmony_ci// If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is 772cb93a386Sopenharmony_ci// expected to continue to own it for the lifetime of the png_ptr. 773cb93a386Sopenharmony_ci// @param outCodec Optional output variable. If non-NULL, will be set to a new 774cb93a386Sopenharmony_ci// SkPngCodec on success. 775cb93a386Sopenharmony_ci// @param png_ptrp Optional output variable. If non-NULL, will be set to a new 776cb93a386Sopenharmony_ci// png_structp on success. 777cb93a386Sopenharmony_ci// @param info_ptrp Optional output variable. If non-NULL, will be set to a new 778cb93a386Sopenharmony_ci// png_infop on success; 779cb93a386Sopenharmony_ci// @return if kSuccess, the caller is responsible for calling 780cb93a386Sopenharmony_ci// png_destroy_read_struct(png_ptrp, info_ptrp). 781cb93a386Sopenharmony_ci// Otherwise, the passed in fields (except stream) are unchanged. 782cb93a386Sopenharmony_cistatic SkCodec::Result read_header(SkStream* stream, SkPngChunkReader* chunkReader, 783cb93a386Sopenharmony_ci SkCodec** outCodec, 784cb93a386Sopenharmony_ci png_structp* png_ptrp, png_infop* info_ptrp) { 785cb93a386Sopenharmony_ci // The image is known to be a PNG. Decode enough to know the SkImageInfo. 786cb93a386Sopenharmony_ci png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, 787cb93a386Sopenharmony_ci sk_error_fn, sk_warning_fn); 788cb93a386Sopenharmony_ci if (!png_ptr) { 789cb93a386Sopenharmony_ci return SkCodec::kInternalError; 790cb93a386Sopenharmony_ci } 791cb93a386Sopenharmony_ci 792cb93a386Sopenharmony_ci#ifdef PNG_SET_OPTION_SUPPORTED 793cb93a386Sopenharmony_ci // This setting ensures that we display images with incorrect CMF bytes. 794cb93a386Sopenharmony_ci // See crbug.com/807324. 795cb93a386Sopenharmony_ci png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON); 796cb93a386Sopenharmony_ci#endif 797cb93a386Sopenharmony_ci 798cb93a386Sopenharmony_ci AutoCleanPng autoClean(png_ptr, stream, chunkReader, outCodec); 799cb93a386Sopenharmony_ci 800cb93a386Sopenharmony_ci png_infop info_ptr = png_create_info_struct(png_ptr); 801cb93a386Sopenharmony_ci if (info_ptr == nullptr) { 802cb93a386Sopenharmony_ci return SkCodec::kInternalError; 803cb93a386Sopenharmony_ci } 804cb93a386Sopenharmony_ci 805cb93a386Sopenharmony_ci autoClean.setInfoPtr(info_ptr); 806cb93a386Sopenharmony_ci 807cb93a386Sopenharmony_ci if (setjmp(PNG_JMPBUF(png_ptr))) { 808cb93a386Sopenharmony_ci return SkCodec::kInvalidInput; 809cb93a386Sopenharmony_ci } 810cb93a386Sopenharmony_ci 811cb93a386Sopenharmony_ci#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED 812cb93a386Sopenharmony_ci // Hookup our chunkReader so we can see any user-chunks the caller may be interested in. 813cb93a386Sopenharmony_ci // This needs to be installed before we read the png header. Android may store ninepatch 814cb93a386Sopenharmony_ci // chunks in the header. 815cb93a386Sopenharmony_ci if (chunkReader) { 816cb93a386Sopenharmony_ci png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); 817cb93a386Sopenharmony_ci png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk); 818cb93a386Sopenharmony_ci } 819cb93a386Sopenharmony_ci#endif 820cb93a386Sopenharmony_ci 821cb93a386Sopenharmony_ci const bool decodedBounds = autoClean.decodeBounds(); 822cb93a386Sopenharmony_ci 823cb93a386Sopenharmony_ci if (!decodedBounds) { 824cb93a386Sopenharmony_ci return SkCodec::kIncompleteInput; 825cb93a386Sopenharmony_ci } 826cb93a386Sopenharmony_ci 827cb93a386Sopenharmony_ci // On success, decodeBounds releases ownership of png_ptr and info_ptr. 828cb93a386Sopenharmony_ci if (png_ptrp) { 829cb93a386Sopenharmony_ci *png_ptrp = png_ptr; 830cb93a386Sopenharmony_ci } 831cb93a386Sopenharmony_ci if (info_ptrp) { 832cb93a386Sopenharmony_ci *info_ptrp = info_ptr; 833cb93a386Sopenharmony_ci } 834cb93a386Sopenharmony_ci 835cb93a386Sopenharmony_ci // decodeBounds takes care of setting outCodec 836cb93a386Sopenharmony_ci if (outCodec) { 837cb93a386Sopenharmony_ci SkASSERT(*outCodec); 838cb93a386Sopenharmony_ci } 839cb93a386Sopenharmony_ci return SkCodec::kSuccess; 840cb93a386Sopenharmony_ci} 841cb93a386Sopenharmony_ci 842cb93a386Sopenharmony_civoid AutoCleanPng::infoCallback(size_t idatLength) { 843cb93a386Sopenharmony_ci png_uint_32 origWidth, origHeight; 844cb93a386Sopenharmony_ci int bitDepth, encodedColorType; 845cb93a386Sopenharmony_ci png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth, 846cb93a386Sopenharmony_ci &encodedColorType, nullptr, nullptr, nullptr); 847cb93a386Sopenharmony_ci 848cb93a386Sopenharmony_ci // TODO: Should we support 16-bits of precision for gray images? 849cb93a386Sopenharmony_ci if (bitDepth == 16 && (PNG_COLOR_TYPE_GRAY == encodedColorType || 850cb93a386Sopenharmony_ci PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType)) { 851cb93a386Sopenharmony_ci bitDepth = 8; 852cb93a386Sopenharmony_ci png_set_strip_16(fPng_ptr); 853cb93a386Sopenharmony_ci } 854cb93a386Sopenharmony_ci 855cb93a386Sopenharmony_ci // Now determine the default colorType and alphaType and set the required transforms. 856cb93a386Sopenharmony_ci // Often, we depend on SkSwizzler to perform any transforms that we need. However, we 857cb93a386Sopenharmony_ci // still depend on libpng for many of the rare and PNG-specific cases. 858cb93a386Sopenharmony_ci SkEncodedInfo::Color color; 859cb93a386Sopenharmony_ci SkEncodedInfo::Alpha alpha; 860cb93a386Sopenharmony_ci switch (encodedColorType) { 861cb93a386Sopenharmony_ci case PNG_COLOR_TYPE_PALETTE: 862cb93a386Sopenharmony_ci // Extract multiple pixels with bit depths of 1, 2, and 4 from a single 863cb93a386Sopenharmony_ci // byte into separate bytes (useful for paletted and grayscale images). 864cb93a386Sopenharmony_ci if (bitDepth < 8) { 865cb93a386Sopenharmony_ci // TODO: Should we use SkSwizzler here? 866cb93a386Sopenharmony_ci bitDepth = 8; 867cb93a386Sopenharmony_ci png_set_packing(fPng_ptr); 868cb93a386Sopenharmony_ci } 869cb93a386Sopenharmony_ci 870cb93a386Sopenharmony_ci color = SkEncodedInfo::kPalette_Color; 871cb93a386Sopenharmony_ci // Set the alpha depending on if a transparency chunk exists. 872cb93a386Sopenharmony_ci alpha = png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS) ? 873cb93a386Sopenharmony_ci SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha; 874cb93a386Sopenharmony_ci break; 875cb93a386Sopenharmony_ci case PNG_COLOR_TYPE_RGB: 876cb93a386Sopenharmony_ci if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { 877cb93a386Sopenharmony_ci // Convert to RGBA if transparency chunk exists. 878cb93a386Sopenharmony_ci png_set_tRNS_to_alpha(fPng_ptr); 879cb93a386Sopenharmony_ci color = SkEncodedInfo::kRGBA_Color; 880cb93a386Sopenharmony_ci alpha = SkEncodedInfo::kBinary_Alpha; 881cb93a386Sopenharmony_ci } else { 882cb93a386Sopenharmony_ci color = SkEncodedInfo::kRGB_Color; 883cb93a386Sopenharmony_ci alpha = SkEncodedInfo::kOpaque_Alpha; 884cb93a386Sopenharmony_ci } 885cb93a386Sopenharmony_ci break; 886cb93a386Sopenharmony_ci case PNG_COLOR_TYPE_GRAY: 887cb93a386Sopenharmony_ci // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. 888cb93a386Sopenharmony_ci if (bitDepth < 8) { 889cb93a386Sopenharmony_ci // TODO: Should we use SkSwizzler here? 890cb93a386Sopenharmony_ci bitDepth = 8; 891cb93a386Sopenharmony_ci png_set_expand_gray_1_2_4_to_8(fPng_ptr); 892cb93a386Sopenharmony_ci } 893cb93a386Sopenharmony_ci 894cb93a386Sopenharmony_ci if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { 895cb93a386Sopenharmony_ci png_set_tRNS_to_alpha(fPng_ptr); 896cb93a386Sopenharmony_ci color = SkEncodedInfo::kGrayAlpha_Color; 897cb93a386Sopenharmony_ci alpha = SkEncodedInfo::kBinary_Alpha; 898cb93a386Sopenharmony_ci } else { 899cb93a386Sopenharmony_ci color = SkEncodedInfo::kGray_Color; 900cb93a386Sopenharmony_ci alpha = SkEncodedInfo::kOpaque_Alpha; 901cb93a386Sopenharmony_ci } 902cb93a386Sopenharmony_ci break; 903cb93a386Sopenharmony_ci case PNG_COLOR_TYPE_GRAY_ALPHA: 904cb93a386Sopenharmony_ci color = SkEncodedInfo::kGrayAlpha_Color; 905cb93a386Sopenharmony_ci alpha = SkEncodedInfo::kUnpremul_Alpha; 906cb93a386Sopenharmony_ci break; 907cb93a386Sopenharmony_ci case PNG_COLOR_TYPE_RGBA: 908cb93a386Sopenharmony_ci color = SkEncodedInfo::kRGBA_Color; 909cb93a386Sopenharmony_ci alpha = SkEncodedInfo::kUnpremul_Alpha; 910cb93a386Sopenharmony_ci break; 911cb93a386Sopenharmony_ci default: 912cb93a386Sopenharmony_ci // All the color types have been covered above. 913cb93a386Sopenharmony_ci SkASSERT(false); 914cb93a386Sopenharmony_ci color = SkEncodedInfo::kRGBA_Color; 915cb93a386Sopenharmony_ci alpha = SkEncodedInfo::kUnpremul_Alpha; 916cb93a386Sopenharmony_ci } 917cb93a386Sopenharmony_ci 918cb93a386Sopenharmony_ci const int numberPasses = png_set_interlace_handling(fPng_ptr); 919cb93a386Sopenharmony_ci 920cb93a386Sopenharmony_ci if (fOutCodec) { 921cb93a386Sopenharmony_ci SkASSERT(nullptr == *fOutCodec); 922cb93a386Sopenharmony_ci auto profile = read_color_profile(fPng_ptr, fInfo_ptr); 923cb93a386Sopenharmony_ci if (profile) { 924cb93a386Sopenharmony_ci switch (profile->profile()->data_color_space) { 925cb93a386Sopenharmony_ci case skcms_Signature_CMYK: 926cb93a386Sopenharmony_ci profile = nullptr; 927cb93a386Sopenharmony_ci break; 928cb93a386Sopenharmony_ci case skcms_Signature_Gray: 929cb93a386Sopenharmony_ci if (SkEncodedInfo::kGray_Color != color && 930cb93a386Sopenharmony_ci SkEncodedInfo::kGrayAlpha_Color != color) 931cb93a386Sopenharmony_ci { 932cb93a386Sopenharmony_ci profile = nullptr; 933cb93a386Sopenharmony_ci } 934cb93a386Sopenharmony_ci break; 935cb93a386Sopenharmony_ci default: 936cb93a386Sopenharmony_ci break; 937cb93a386Sopenharmony_ci } 938cb93a386Sopenharmony_ci } 939cb93a386Sopenharmony_ci 940cb93a386Sopenharmony_ci switch (encodedColorType) { 941cb93a386Sopenharmony_ci case PNG_COLOR_TYPE_GRAY_ALPHA:{ 942cb93a386Sopenharmony_ci png_color_8p sigBits; 943cb93a386Sopenharmony_ci if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) { 944cb93a386Sopenharmony_ci if (8 == sigBits->alpha && kGraySigBit_GrayAlphaIsJustAlpha == sigBits->gray) { 945cb93a386Sopenharmony_ci color = SkEncodedInfo::kXAlpha_Color; 946cb93a386Sopenharmony_ci } 947cb93a386Sopenharmony_ci } 948cb93a386Sopenharmony_ci break; 949cb93a386Sopenharmony_ci } 950cb93a386Sopenharmony_ci case PNG_COLOR_TYPE_RGB:{ 951cb93a386Sopenharmony_ci png_color_8p sigBits; 952cb93a386Sopenharmony_ci if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) { 953cb93a386Sopenharmony_ci if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) { 954cb93a386Sopenharmony_ci // Recommend a decode to 565 if the sBIT indicates 565. 955cb93a386Sopenharmony_ci color = SkEncodedInfo::k565_Color; 956cb93a386Sopenharmony_ci } 957cb93a386Sopenharmony_ci } 958cb93a386Sopenharmony_ci break; 959cb93a386Sopenharmony_ci } 960cb93a386Sopenharmony_ci } 961cb93a386Sopenharmony_ci 962cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 963cb93a386Sopenharmony_ci if (encodedColorType != PNG_COLOR_TYPE_GRAY_ALPHA 964cb93a386Sopenharmony_ci && SkEncodedInfo::kOpaque_Alpha == alpha) { 965cb93a386Sopenharmony_ci png_color_8p sigBits; 966cb93a386Sopenharmony_ci if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) { 967cb93a386Sopenharmony_ci if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) { 968cb93a386Sopenharmony_ci SkAndroidFrameworkUtils::SafetyNetLog("190188264"); 969cb93a386Sopenharmony_ci } 970cb93a386Sopenharmony_ci } 971cb93a386Sopenharmony_ci } 972cb93a386Sopenharmony_ci#endif // SK_BUILD_FOR_ANDROID_FRAMEWORK 973cb93a386Sopenharmony_ci 974cb93a386Sopenharmony_ci SkEncodedInfo encodedInfo = SkEncodedInfo::Make(origWidth, origHeight, color, alpha, 975cb93a386Sopenharmony_ci bitDepth, std::move(profile)); 976cb93a386Sopenharmony_ci if (1 == numberPasses) { 977cb93a386Sopenharmony_ci *fOutCodec = new SkPngNormalDecoder(std::move(encodedInfo), 978cb93a386Sopenharmony_ci std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth); 979cb93a386Sopenharmony_ci } else { 980cb93a386Sopenharmony_ci *fOutCodec = new SkPngInterlacedDecoder(std::move(encodedInfo), 981cb93a386Sopenharmony_ci std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth, 982cb93a386Sopenharmony_ci numberPasses); 983cb93a386Sopenharmony_ci } 984cb93a386Sopenharmony_ci static_cast<SkPngCodec*>(*fOutCodec)->setIdatLength(idatLength); 985cb93a386Sopenharmony_ci } 986cb93a386Sopenharmony_ci 987cb93a386Sopenharmony_ci // Release the pointers, which are now owned by the codec or the caller is expected to 988cb93a386Sopenharmony_ci // take ownership. 989cb93a386Sopenharmony_ci this->releasePngPtrs(); 990cb93a386Sopenharmony_ci} 991cb93a386Sopenharmony_ci 992cb93a386Sopenharmony_ciSkPngCodec::SkPngCodec(SkEncodedInfo&& encodedInfo, std::unique_ptr<SkStream> stream, 993cb93a386Sopenharmony_ci SkPngChunkReader* chunkReader, void* png_ptr, void* info_ptr, int bitDepth) 994cb93a386Sopenharmony_ci : INHERITED(std::move(encodedInfo), png_select_xform_format(encodedInfo), std::move(stream)) 995cb93a386Sopenharmony_ci , fPngChunkReader(SkSafeRef(chunkReader)) 996cb93a386Sopenharmony_ci , fPng_ptr(png_ptr) 997cb93a386Sopenharmony_ci , fInfo_ptr(info_ptr) 998cb93a386Sopenharmony_ci , fColorXformSrcRow(nullptr) 999cb93a386Sopenharmony_ci , fBitDepth(bitDepth) 1000cb93a386Sopenharmony_ci , fIdatLength(0) 1001cb93a386Sopenharmony_ci , fDecodedIdat(false) 1002cb93a386Sopenharmony_ci{} 1003cb93a386Sopenharmony_ci 1004cb93a386Sopenharmony_ciSkPngCodec::~SkPngCodec() { 1005cb93a386Sopenharmony_ci this->destroyReadStruct(); 1006cb93a386Sopenharmony_ci} 1007cb93a386Sopenharmony_ci 1008cb93a386Sopenharmony_civoid SkPngCodec::destroyReadStruct() { 1009cb93a386Sopenharmony_ci if (fPng_ptr) { 1010cb93a386Sopenharmony_ci // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr 1011cb93a386Sopenharmony_ci SkASSERT(fInfo_ptr); 1012cb93a386Sopenharmony_ci png_destroy_read_struct((png_struct**)&fPng_ptr, (png_info**)&fInfo_ptr, nullptr); 1013cb93a386Sopenharmony_ci fPng_ptr = nullptr; 1014cb93a386Sopenharmony_ci fInfo_ptr = nullptr; 1015cb93a386Sopenharmony_ci } 1016cb93a386Sopenharmony_ci} 1017cb93a386Sopenharmony_ci 1018cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 1019cb93a386Sopenharmony_ci// Getting the pixels 1020cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 1021cb93a386Sopenharmony_ci 1022cb93a386Sopenharmony_ciSkCodec::Result SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& options) { 1023cb93a386Sopenharmony_ci if (setjmp(PNG_JMPBUF((png_struct*)fPng_ptr))) { 1024cb93a386Sopenharmony_ci SkCodecPrintf("Failed on png_read_update_info.\n"); 1025cb93a386Sopenharmony_ci return kInvalidInput; 1026cb93a386Sopenharmony_ci } 1027cb93a386Sopenharmony_ci png_read_update_info(fPng_ptr, fInfo_ptr); 1028cb93a386Sopenharmony_ci 1029cb93a386Sopenharmony_ci // Reset fSwizzler and this->colorXform(). We can't do this in onRewind() because the 1030cb93a386Sopenharmony_ci // interlaced scanline decoder may need to rewind. 1031cb93a386Sopenharmony_ci fSwizzler.reset(nullptr); 1032cb93a386Sopenharmony_ci 1033cb93a386Sopenharmony_ci // If skcms directly supports the encoded PNG format, we should skip format 1034cb93a386Sopenharmony_ci // conversion in the swizzler (or skip swizzling altogether). 1035cb93a386Sopenharmony_ci bool skipFormatConversion = false; 1036cb93a386Sopenharmony_ci switch (this->getEncodedInfo().color()) { 1037cb93a386Sopenharmony_ci case SkEncodedInfo::kRGB_Color: 1038cb93a386Sopenharmony_ci if (this->getEncodedInfo().bitsPerComponent() != 16) { 1039cb93a386Sopenharmony_ci break; 1040cb93a386Sopenharmony_ci } 1041cb93a386Sopenharmony_ci [[fallthrough]]; 1042cb93a386Sopenharmony_ci case SkEncodedInfo::kRGBA_Color: 1043cb93a386Sopenharmony_ci case SkEncodedInfo::kGray_Color: 1044cb93a386Sopenharmony_ci skipFormatConversion = this->colorXform(); 1045cb93a386Sopenharmony_ci break; 1046cb93a386Sopenharmony_ci default: 1047cb93a386Sopenharmony_ci break; 1048cb93a386Sopenharmony_ci } 1049cb93a386Sopenharmony_ci if (skipFormatConversion && !options.fSubset) { 1050cb93a386Sopenharmony_ci fXformMode = kColorOnly_XformMode; 1051cb93a386Sopenharmony_ci return kSuccess; 1052cb93a386Sopenharmony_ci } 1053cb93a386Sopenharmony_ci 1054cb93a386Sopenharmony_ci if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) { 1055cb93a386Sopenharmony_ci if (!this->createColorTable(dstInfo)) { 1056cb93a386Sopenharmony_ci return kInvalidInput; 1057cb93a386Sopenharmony_ci } 1058cb93a386Sopenharmony_ci } 1059cb93a386Sopenharmony_ci 1060cb93a386Sopenharmony_ci this->initializeSwizzler(dstInfo, options, skipFormatConversion); 1061cb93a386Sopenharmony_ci return kSuccess; 1062cb93a386Sopenharmony_ci} 1063cb93a386Sopenharmony_ci 1064cb93a386Sopenharmony_civoid SkPngCodec::initializeXformParams() { 1065cb93a386Sopenharmony_ci switch (fXformMode) { 1066cb93a386Sopenharmony_ci case kColorOnly_XformMode: 1067cb93a386Sopenharmony_ci fXformWidth = this->dstInfo().width(); 1068cb93a386Sopenharmony_ci break; 1069cb93a386Sopenharmony_ci case kSwizzleColor_XformMode: 1070cb93a386Sopenharmony_ci fXformWidth = this->swizzler()->swizzleWidth(); 1071cb93a386Sopenharmony_ci break; 1072cb93a386Sopenharmony_ci default: 1073cb93a386Sopenharmony_ci break; 1074cb93a386Sopenharmony_ci } 1075cb93a386Sopenharmony_ci} 1076cb93a386Sopenharmony_ci 1077cb93a386Sopenharmony_civoid SkPngCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options, 1078cb93a386Sopenharmony_ci bool skipFormatConversion) { 1079cb93a386Sopenharmony_ci SkImageInfo swizzlerInfo = dstInfo; 1080cb93a386Sopenharmony_ci Options swizzlerOptions = options; 1081cb93a386Sopenharmony_ci fXformMode = kSwizzleOnly_XformMode; 1082cb93a386Sopenharmony_ci if (this->colorXform() && this->xformOnDecode()) { 1083cb93a386Sopenharmony_ci if (SkEncodedInfo::kGray_Color == this->getEncodedInfo().color()) { 1084cb93a386Sopenharmony_ci swizzlerInfo = swizzlerInfo.makeColorType(kGray_8_SkColorType); 1085cb93a386Sopenharmony_ci } else { 1086cb93a386Sopenharmony_ci swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType); 1087cb93a386Sopenharmony_ci } 1088cb93a386Sopenharmony_ci if (kPremul_SkAlphaType == dstInfo.alphaType()) { 1089cb93a386Sopenharmony_ci swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType); 1090cb93a386Sopenharmony_ci } 1091cb93a386Sopenharmony_ci 1092cb93a386Sopenharmony_ci fXformMode = kSwizzleColor_XformMode; 1093cb93a386Sopenharmony_ci 1094cb93a386Sopenharmony_ci // Here, we swizzle into temporary memory, which is not zero initialized. 1095cb93a386Sopenharmony_ci // FIXME (msarett): 1096cb93a386Sopenharmony_ci // Is this a problem? 1097cb93a386Sopenharmony_ci swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized; 1098cb93a386Sopenharmony_ci } 1099cb93a386Sopenharmony_ci 1100cb93a386Sopenharmony_ci if (skipFormatConversion) { 1101cb93a386Sopenharmony_ci // We cannot skip format conversion when there is a color table. 1102cb93a386Sopenharmony_ci SkASSERT(!fColorTable); 1103cb93a386Sopenharmony_ci int srcBPP = 0; 1104cb93a386Sopenharmony_ci switch (this->getEncodedInfo().color()) { 1105cb93a386Sopenharmony_ci case SkEncodedInfo::kRGB_Color: 1106cb93a386Sopenharmony_ci SkASSERT(this->getEncodedInfo().bitsPerComponent() == 16); 1107cb93a386Sopenharmony_ci srcBPP = 6; 1108cb93a386Sopenharmony_ci break; 1109cb93a386Sopenharmony_ci case SkEncodedInfo::kRGBA_Color: 1110cb93a386Sopenharmony_ci srcBPP = this->getEncodedInfo().bitsPerComponent() / 2; 1111cb93a386Sopenharmony_ci break; 1112cb93a386Sopenharmony_ci case SkEncodedInfo::kGray_Color: 1113cb93a386Sopenharmony_ci srcBPP = 1; 1114cb93a386Sopenharmony_ci break; 1115cb93a386Sopenharmony_ci default: 1116cb93a386Sopenharmony_ci SkASSERT(false); 1117cb93a386Sopenharmony_ci break; 1118cb93a386Sopenharmony_ci } 1119cb93a386Sopenharmony_ci fSwizzler = SkSwizzler::MakeSimple(srcBPP, swizzlerInfo, swizzlerOptions); 1120cb93a386Sopenharmony_ci } else { 1121cb93a386Sopenharmony_ci const SkPMColor* colors = get_color_ptr(fColorTable.get()); 1122cb93a386Sopenharmony_ci fSwizzler = SkSwizzler::Make(this->getEncodedInfo(), colors, swizzlerInfo, 1123cb93a386Sopenharmony_ci swizzlerOptions); 1124cb93a386Sopenharmony_ci } 1125cb93a386Sopenharmony_ci SkASSERT(fSwizzler); 1126cb93a386Sopenharmony_ci} 1127cb93a386Sopenharmony_ci 1128cb93a386Sopenharmony_ciSkSampler* SkPngCodec::getSampler(bool createIfNecessary) { 1129cb93a386Sopenharmony_ci if (fSwizzler || !createIfNecessary) { 1130cb93a386Sopenharmony_ci return fSwizzler.get(); 1131cb93a386Sopenharmony_ci } 1132cb93a386Sopenharmony_ci 1133cb93a386Sopenharmony_ci this->initializeSwizzler(this->dstInfo(), this->options(), true); 1134cb93a386Sopenharmony_ci return fSwizzler.get(); 1135cb93a386Sopenharmony_ci} 1136cb93a386Sopenharmony_ci 1137cb93a386Sopenharmony_cibool SkPngCodec::onRewind() { 1138cb93a386Sopenharmony_ci // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header 1139cb93a386Sopenharmony_ci // succeeds, they will be repopulated, and if it fails, they will 1140cb93a386Sopenharmony_ci // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will 1141cb93a386Sopenharmony_ci // come through this function which will rewind and again attempt 1142cb93a386Sopenharmony_ci // to reinitialize them. 1143cb93a386Sopenharmony_ci this->destroyReadStruct(); 1144cb93a386Sopenharmony_ci 1145cb93a386Sopenharmony_ci png_structp png_ptr; 1146cb93a386Sopenharmony_ci png_infop info_ptr; 1147cb93a386Sopenharmony_ci if (kSuccess != read_header(this->stream(), fPngChunkReader.get(), nullptr, 1148cb93a386Sopenharmony_ci &png_ptr, &info_ptr)) { 1149cb93a386Sopenharmony_ci return false; 1150cb93a386Sopenharmony_ci } 1151cb93a386Sopenharmony_ci 1152cb93a386Sopenharmony_ci fPng_ptr = png_ptr; 1153cb93a386Sopenharmony_ci fInfo_ptr = info_ptr; 1154cb93a386Sopenharmony_ci fDecodedIdat = false; 1155cb93a386Sopenharmony_ci return true; 1156cb93a386Sopenharmony_ci} 1157cb93a386Sopenharmony_ci 1158cb93a386Sopenharmony_ciSkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, 1159cb93a386Sopenharmony_ci size_t rowBytes, const Options& options, 1160cb93a386Sopenharmony_ci int* rowsDecoded) { 1161cb93a386Sopenharmony_ci Result result = this->initializeXforms(dstInfo, options); 1162cb93a386Sopenharmony_ci if (kSuccess != result) { 1163cb93a386Sopenharmony_ci return result; 1164cb93a386Sopenharmony_ci } 1165cb93a386Sopenharmony_ci 1166cb93a386Sopenharmony_ci if (options.fSubset) { 1167cb93a386Sopenharmony_ci return kUnimplemented; 1168cb93a386Sopenharmony_ci } 1169cb93a386Sopenharmony_ci 1170cb93a386Sopenharmony_ci this->allocateStorage(dstInfo); 1171cb93a386Sopenharmony_ci this->initializeXformParams(); 1172cb93a386Sopenharmony_ci return this->decodeAllRows(dst, rowBytes, rowsDecoded); 1173cb93a386Sopenharmony_ci} 1174cb93a386Sopenharmony_ci 1175cb93a386Sopenharmony_ciSkCodec::Result SkPngCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, 1176cb93a386Sopenharmony_ci void* dst, size_t rowBytes, const SkCodec::Options& options) { 1177cb93a386Sopenharmony_ci Result result = this->initializeXforms(dstInfo, options); 1178cb93a386Sopenharmony_ci if (kSuccess != result) { 1179cb93a386Sopenharmony_ci return result; 1180cb93a386Sopenharmony_ci } 1181cb93a386Sopenharmony_ci 1182cb93a386Sopenharmony_ci this->allocateStorage(dstInfo); 1183cb93a386Sopenharmony_ci 1184cb93a386Sopenharmony_ci int firstRow, lastRow; 1185cb93a386Sopenharmony_ci if (options.fSubset) { 1186cb93a386Sopenharmony_ci firstRow = options.fSubset->top(); 1187cb93a386Sopenharmony_ci lastRow = options.fSubset->bottom() - 1; 1188cb93a386Sopenharmony_ci } else { 1189cb93a386Sopenharmony_ci firstRow = 0; 1190cb93a386Sopenharmony_ci lastRow = dstInfo.height() - 1; 1191cb93a386Sopenharmony_ci } 1192cb93a386Sopenharmony_ci this->setRange(firstRow, lastRow, dst, rowBytes); 1193cb93a386Sopenharmony_ci return kSuccess; 1194cb93a386Sopenharmony_ci} 1195cb93a386Sopenharmony_ci 1196cb93a386Sopenharmony_ciSkCodec::Result SkPngCodec::onIncrementalDecode(int* rowsDecoded) { 1197cb93a386Sopenharmony_ci // FIXME: Only necessary on the first call. 1198cb93a386Sopenharmony_ci this->initializeXformParams(); 1199cb93a386Sopenharmony_ci 1200cb93a386Sopenharmony_ci return this->decode(rowsDecoded); 1201cb93a386Sopenharmony_ci} 1202cb93a386Sopenharmony_ci 1203cb93a386Sopenharmony_cistd::unique_ptr<SkCodec> SkPngCodec::MakeFromStream(std::unique_ptr<SkStream> stream, 1204cb93a386Sopenharmony_ci Result* result, SkPngChunkReader* chunkReader) { 1205cb93a386Sopenharmony_ci SkCodec* outCodec = nullptr; 1206cb93a386Sopenharmony_ci *result = read_header(stream.get(), chunkReader, &outCodec, nullptr, nullptr); 1207cb93a386Sopenharmony_ci if (kSuccess == *result) { 1208cb93a386Sopenharmony_ci // Codec has taken ownership of the stream. 1209cb93a386Sopenharmony_ci SkASSERT(outCodec); 1210cb93a386Sopenharmony_ci stream.release(); 1211cb93a386Sopenharmony_ci } 1212cb93a386Sopenharmony_ci return std::unique_ptr<SkCodec>(outCodec); 1213cb93a386Sopenharmony_ci} 1214