| Index: third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp
 | 
| diff --git a/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp
 | 
| index a2ebf6cb967b33593313ca267d227800dbbf3fbe..6deba9ce22adfd250319cac12dada224f706df3d 100644
 | 
| --- a/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp
 | 
| +++ b/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp
 | 
| @@ -54,58 +54,58 @@ PNGImageDecoder::PNGImageDecoder(AlphaOption alphaOption,
 | 
|  
 | 
|  PNGImageDecoder::~PNGImageDecoder() {}
 | 
|  
 | 
| -inline float pngFixedToFloat(png_fixed_point x) {
 | 
| -  return ((float)x) * 0.00001f;
 | 
| -}
 | 
| -
 | 
|  inline sk_sp<SkColorSpace> readColorSpace(png_structp png, png_infop info) {
 | 
| -  if (png_get_valid(png, info, PNG_INFO_sRGB)) {
 | 
| +  if (png_get_valid(png, info, PNG_INFO_sRGB))
 | 
|      return SkColorSpace::MakeSRGB();
 | 
| -  }
 | 
|  
 | 
| -  png_charp name = nullptr;
 | 
| -  int compression = 0;
 | 
| -  png_bytep profile = nullptr;
 | 
| -  png_uint_32 length = 0;
 | 
| -  if (png_get_iCCP(png, info, &name, &compression, &profile, &length)) {
 | 
| +  png_charp name;
 | 
| +  int compression;
 | 
| +  png_bytep profile;
 | 
| +  png_uint_32 length;
 | 
| +  if (png_get_iCCP(png, info, &name, &compression, &profile, &length))
 | 
|      return SkColorSpace::MakeICC(profile, length);
 | 
| -  }
 | 
|  
 | 
|    png_fixed_point chrm[8];
 | 
| -  if (png_get_cHRM_fixed(png, info, &chrm[0], &chrm[1], &chrm[2], &chrm[3],
 | 
| -                         &chrm[4], &chrm[5], &chrm[6], &chrm[7])) {
 | 
| -    SkColorSpacePrimaries primaries;
 | 
| -    primaries.fRX = pngFixedToFloat(chrm[2]);
 | 
| -    primaries.fRY = pngFixedToFloat(chrm[3]);
 | 
| -    primaries.fGX = pngFixedToFloat(chrm[4]);
 | 
| -    primaries.fGY = pngFixedToFloat(chrm[5]);
 | 
| -    primaries.fBX = pngFixedToFloat(chrm[6]);
 | 
| -    primaries.fBY = pngFixedToFloat(chrm[7]);
 | 
| -    primaries.fWX = pngFixedToFloat(chrm[0]);
 | 
| -    primaries.fWY = pngFixedToFloat(chrm[1]);
 | 
| -
 | 
| -    SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
 | 
| -    if (primaries.toXYZD50(&toXYZD50)) {
 | 
| -      png_fixed_point gammaFixed;
 | 
| -      if (PNG_INFO_gAMA == png_get_gAMA_fixed(png, info, &gammaFixed)) {
 | 
| -        SkColorSpaceTransferFn fn;
 | 
| -        fn.fA = 1.0f;
 | 
| -        fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f;
 | 
| -        // This is necessary because the gAMA chunk actually stores 1/gamma.
 | 
| -        fn.fG = 1.0f / pngFixedToFloat(gammaFixed);
 | 
| -        return SkColorSpace::MakeRGB(fn, toXYZD50);
 | 
| -      }
 | 
| -
 | 
| -      // Note that we only use the cHRM tag when gAMA is present.  The
 | 
| -      // specification states that the cHRM is valid even without a gAMA
 | 
| -      // tag, but we cannot apply the cHRM without guessing a transfer
 | 
| -      // function.  It's possible that we should guess sRGB transfer
 | 
| -      // function, given that unmarked PNGs should be treated as sRGB.
 | 
| -      // However, the current behavior matches Safari and Firefox.
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  return nullptr;
 | 
| +  if (!png_get_cHRM_fixed(png, info, &chrm[0], &chrm[1], &chrm[2], &chrm[3],
 | 
| +                          &chrm[4], &chrm[5], &chrm[6], &chrm[7]))
 | 
| +    return nullptr;
 | 
| +
 | 
| +  png_fixed_point inverseGamma;
 | 
| +  if (!png_get_gAMA_fixed(png, info, &inverseGamma))
 | 
| +    return nullptr;
 | 
| +
 | 
| +  // cHRM and gAMA tags are both present. The PNG spec states that cHRM is
 | 
| +  // valid even without gAMA but we cannot apply the cHRM without guessing
 | 
| +  // a gAMA. Color correction is not a guessing game: match the behavior
 | 
| +  // of Safari and Firefox instead (compat).
 | 
| +
 | 
| +  struct pngFixedToFloat {
 | 
| +    explicit pngFixedToFloat(png_fixed_point value)
 | 
| +        : floatValue(.00001f * value) {}
 | 
| +    operator float() { return floatValue; }
 | 
| +    float floatValue;
 | 
| +  };
 | 
| +
 | 
| +  SkColorSpacePrimaries primaries;
 | 
| +  primaries.fRX = pngFixedToFloat(chrm[2]);
 | 
| +  primaries.fRY = pngFixedToFloat(chrm[3]);
 | 
| +  primaries.fGX = pngFixedToFloat(chrm[4]);
 | 
| +  primaries.fGY = pngFixedToFloat(chrm[5]);
 | 
| +  primaries.fBX = pngFixedToFloat(chrm[6]);
 | 
| +  primaries.fBY = pngFixedToFloat(chrm[7]);
 | 
| +  primaries.fWX = pngFixedToFloat(chrm[0]);
 | 
| +  primaries.fWY = pngFixedToFloat(chrm[1]);
 | 
| +
 | 
| +  SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
 | 
| +  if (!primaries.toXYZD50(&toXYZD50))
 | 
| +    return nullptr;
 | 
| +
 | 
| +  SkColorSpaceTransferFn fn;
 | 
| +  fn.fG = 1.0f / pngFixedToFloat(inverseGamma);
 | 
| +  fn.fA = 1.0f;
 | 
| +  fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f;
 | 
| +
 | 
| +  return SkColorSpace::MakeRGB(fn, toXYZD50);
 | 
|  }
 | 
|  
 | 
|  void PNGImageDecoder::headerAvailable() {
 | 
| @@ -127,9 +127,9 @@ void PNGImageDecoder::headerAvailable() {
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| -  int bitDepth, colorType, interlaceType, compressionType, filterType, channels;
 | 
| +  int bitDepth, colorType, interlaceType, compressionType;
 | 
|    png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType,
 | 
| -               &interlaceType, &compressionType, &filterType);
 | 
| +               &interlaceType, &compressionType, nullptr);
 | 
|  
 | 
|    // The options we set here match what Mozilla does.
 | 
|  
 | 
| @@ -138,12 +138,8 @@ void PNGImageDecoder::headerAvailable() {
 | 
|        (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8))
 | 
|      png_set_expand(png);
 | 
|  
 | 
| -  png_bytep trns = 0;
 | 
| -  int trnsCount = 0;
 | 
| -  if (png_get_valid(png, info, PNG_INFO_tRNS)) {
 | 
| -    png_get_tRNS(png, info, &trns, &trnsCount, 0);
 | 
| +  if (png_get_valid(png, info, PNG_INFO_tRNS))
 | 
|      png_set_expand(png);
 | 
| -  }
 | 
|  
 | 
|    if (bitDepth == 16)
 | 
|      png_set_strip_16(png);
 | 
| @@ -154,27 +150,12 @@ void PNGImageDecoder::headerAvailable() {
 | 
|  
 | 
|    if ((colorType & PNG_COLOR_MASK_COLOR) && !ignoresColorSpace()) {
 | 
|      // We only support color profiles for color PALETTE and RGB[A] PNG.
 | 
| -    // Supporting color profiles for gray-scale images is slightly tricky, at
 | 
| -    // least using the CoreGraphics ICC library, because we expand gray-scale
 | 
| -    // images to RGB but we do not similarly transform the color profile. We'd
 | 
| -    // either need to transform the color profile or we'd need to decode into a
 | 
| -    // gray-scale image buffer and hand that to CoreGraphics.
 | 
| -    sk_sp<SkColorSpace> colorSpace = readColorSpace(png, info);
 | 
| -    if (colorSpace) {
 | 
| -      setEmbeddedColorSpace(colorSpace);
 | 
| -    }
 | 
| +    // TODO(msarret): Add GRAY profile support, block CYMK?
 | 
| +    if (sk_sp<SkColorSpace> colorSpace = readColorSpace(png, info))
 | 
| +      setEmbeddedColorSpace(std::move(colorSpace));
 | 
|    }
 | 
|  
 | 
|    if (!hasEmbeddedColorSpace()) {
 | 
| -    // TODO (msarett):
 | 
| -    // Applying the transfer function (gamma) should be handled by
 | 
| -    // SkColorSpaceXform.  Here we always convert to a transfer function that
 | 
| -    // is a 2.2 exponential.  This is a little strange given that the dst
 | 
| -    // transfer function is not necessarily a 2.2 exponential.
 | 
| -    // TODO (msarett):
 | 
| -    // Often, PNGs that specify their transfer function with the gAMA tag will
 | 
| -    // also specify their gamut with the cHRM tag.  We should read this tag
 | 
| -    // and do a full color space transformation if it is present.
 | 
|      const double inverseGamma = 0.45455;
 | 
|      const double defaultGamma = 2.2;
 | 
|      double gamma;
 | 
| @@ -194,11 +175,11 @@ void PNGImageDecoder::headerAvailable() {
 | 
|    if (interlaceType == PNG_INTERLACE_ADAM7)
 | 
|      png_set_interlace_handling(png);
 | 
|  
 | 
| -  // Update our info now.
 | 
| +  // Update our info now (so we can get color channel info).
 | 
|    png_read_update_info(png, info);
 | 
| -  channels = png_get_channels(png, info);
 | 
| -  ASSERT(channels == 3 || channels == 4);
 | 
|  
 | 
| +  int channels = png_get_channels(png, info);
 | 
| +  DCHECK(channels == 3 || channels == 4);
 | 
|    m_reader->setHasAlpha(channels == 4);
 | 
|  
 | 
|    if (m_reader->decodingSizeOnly()) {
 | 
| @@ -250,16 +231,16 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer,
 | 
|    }
 | 
|  
 | 
|    /* libpng comments (here to explain what follows).
 | 
| -     *
 | 
| -     * this function is called for every row in the image. If the
 | 
| -     * image is interlacing, and you turned on the interlace handler,
 | 
| -     * this function will be called for every row in every pass.
 | 
| -     * Some of these rows will not be changed from the previous pass.
 | 
| -     * When the row is not changed, the new_row variable will be NULL.
 | 
| -     * The rows and passes are called in order, so you don't really
 | 
| -     * need the row_num and pass, but I'm supplying them because it
 | 
| -     * may make your life easier.
 | 
| -     */
 | 
| +   *
 | 
| +   * this function is called for every row in the image. If the
 | 
| +   * image is interlacing, and you turned on the interlace handler,
 | 
| +   * this function will be called for every row in every pass.
 | 
| +   * Some of these rows will not be changed from the previous pass.
 | 
| +   * When the row is not changed, the new_row variable will be NULL.
 | 
| +   * The rows and passes are called in order, so you don't really
 | 
| +   * need the row_num and pass, but I'm supplying them because it
 | 
| +   * may make your life easier.
 | 
| +   */
 | 
|  
 | 
|    // Nothing to do if the row is unchanged, or the row is outside
 | 
|    // the image bounds: libpng may send extra rows, ignore them to
 | 
| @@ -271,23 +252,23 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer,
 | 
|      return;
 | 
|  
 | 
|    /* libpng comments (continued).
 | 
| -     *
 | 
| -     * For the non-NULL rows of interlaced images, you must call
 | 
| -     * png_progressive_combine_row() passing in the row and the
 | 
| -     * old row.  You can call this function for NULL rows (it will
 | 
| -     * just return) and for non-interlaced images (it just does the
 | 
| -     * memcpy for you) if it will make the code easier. Thus, you
 | 
| -     * can just do this for all cases:
 | 
| -     *
 | 
| -     *    png_progressive_combine_row(png_ptr, old_row, new_row);
 | 
| -     *
 | 
| -     * where old_row is what was displayed for previous rows. Note
 | 
| -     * that the first pass (pass == 0 really) will completely cover
 | 
| -     * the old row, so the rows do not have to be initialized. After
 | 
| -     * the first pass (and only for interlaced images), you will have
 | 
| -     * to pass the current row, and the function will combine the
 | 
| -     * old row and the new row.
 | 
| -     */
 | 
| +   *
 | 
| +   * For the non-NULL rows of interlaced images, you must call
 | 
| +   * png_progressive_combine_row() passing in the row and the
 | 
| +   * old row.  You can call this function for NULL rows (it will
 | 
| +   * just return) and for non-interlaced images (it just does the
 | 
| +   * memcpy for you) if it will make the code easier. Thus, you
 | 
| +   * can just do this for all cases:
 | 
| +   *
 | 
| +   *    png_progressive_combine_row(png_ptr, old_row, new_row);
 | 
| +   *
 | 
| +   * where old_row is what was displayed for previous rows. Note
 | 
| +   * that the first pass (pass == 0 really) will completely cover
 | 
| +   * the old row, so the rows do not have to be initialized. After
 | 
| +   * the first pass (and only for interlaced images), you will have
 | 
| +   * to pass the current row, and the function will combine the
 | 
| +   * old row and the new row.
 | 
| +   */
 | 
|  
 | 
|    bool hasAlpha = m_reader->hasAlpha();
 | 
|    png_bytep row = rowBuffer;
 | 
| @@ -301,7 +282,6 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer,
 | 
|    // Write the decoded row pixels to the frame buffer. The repetitive
 | 
|    // form of the row write loops is for speed.
 | 
|    ImageFrame::PixelData* const dstRow = buffer.getAddr(0, y);
 | 
| -  unsigned alphaMask = 255;
 | 
|    int width = size().width();
 | 
|  
 | 
|    png_bytep srcPtr = row;
 | 
| @@ -321,26 +301,31 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer,
 | 
|            SkColorSpaceXform::kRGBA_8888_ColorFormat;
 | 
|        xform->apply(colorFormat, dstRow, colorFormat, srcPtr, size().width(),
 | 
|                     kUnpremul_SkAlphaType);
 | 
| -      srcPtr = (png_bytep)dstRow;
 | 
| +      srcPtr = png_bytep(dstRow);
 | 
|      }
 | 
|  
 | 
| +    unsigned alphaMask = 255;
 | 
|      if (buffer.premultiplyAlpha()) {
 | 
|        for (auto *dstPixel = dstRow; dstPixel < dstRow + width;
 | 
| -           dstPixel++, srcPtr += 4) {
 | 
| +           srcPtr += 4, ++dstPixel) {
 | 
|          buffer.setRGBAPremultiply(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2],
 | 
|                                    srcPtr[3]);
 | 
|          alphaMask &= srcPtr[3];
 | 
|        }
 | 
|      } else {
 | 
|        for (auto *dstPixel = dstRow; dstPixel < dstRow + width;
 | 
| -           dstPixel++, srcPtr += 4) {
 | 
| +           srcPtr += 4, ++dstPixel) {
 | 
|          buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], srcPtr[3]);
 | 
|          alphaMask &= srcPtr[3];
 | 
|        }
 | 
|      }
 | 
| +
 | 
| +    if (alphaMask != 255 && !buffer.hasAlpha())
 | 
| +      buffer.setHasAlpha(true);
 | 
| +
 | 
|    } else {
 | 
|      for (auto *dstPixel = dstRow; dstPixel < dstRow + width;
 | 
| -         dstPixel++, srcPtr += 3) {
 | 
| +         srcPtr += 3, ++dstPixel) {
 | 
|        buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], 255);
 | 
|      }
 | 
|  
 | 
| @@ -353,9 +338,6 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer,
 | 
|      }
 | 
|    }
 | 
|  
 | 
| -  if (alphaMask != 255 && !buffer.hasAlpha())
 | 
| -    buffer.setHasAlpha(true);
 | 
| -
 | 
|    buffer.setPixelsChanged(true);
 | 
|  }
 | 
|  
 | 
| 
 |