| Index: ios/web/public/image_fetcher/webp_decoder.mm | 
| diff --git a/ios/web/public/image_fetcher/webp_decoder.mm b/ios/web/public/image_fetcher/webp_decoder.mm | 
| deleted file mode 100644 | 
| index d5e7d923add86c93ae77a8ed9a6417e2673f0639..0000000000000000000000000000000000000000 | 
| --- a/ios/web/public/image_fetcher/webp_decoder.mm | 
| +++ /dev/null | 
| @@ -1,309 +0,0 @@ | 
| -// Copyright 2013 The Chromium Authors. All rights reserved. | 
| -// Use of this source code is governed by a BSD-style license that can be | 
| -// found in the LICENSE file. | 
| - | 
| -#import "ios/web/public/image_fetcher/webp_decoder.h" | 
| - | 
| -#import <Foundation/Foundation.h> | 
| -#include <stdint.h> | 
| -#import <UIKit/UIKit.h> | 
| - | 
| -#include "base/logging.h" | 
| -#include "base/metrics/histogram_macros.h" | 
| - | 
| -#if !defined(__has_feature) || !__has_feature(objc_arc) | 
| -#error "This file requires ARC support." | 
| -#endif | 
| - | 
| -namespace { | 
| - | 
| -class WebpDecoderDelegate : public webp_transcode::WebpDecoder::Delegate { | 
| - public: | 
| -  WebpDecoderDelegate() = default; | 
| - | 
| -  NSData* data() const { return decoded_image_; } | 
| - | 
| -  // WebpDecoder::Delegate methods | 
| -  void OnFinishedDecoding(bool success) override { | 
| -    if (!success) | 
| -      decoded_image_ = nil; | 
| -  } | 
| - | 
| -  void SetImageFeatures( | 
| -      size_t total_size, | 
| -      webp_transcode::WebpDecoder::DecodedImageFormat format) override { | 
| -    decoded_image_ = [[NSMutableData alloc] initWithCapacity:total_size]; | 
| -  } | 
| - | 
| -  void OnDataDecoded(NSData* data) override { | 
| -    DCHECK(decoded_image_); | 
| -    [decoded_image_ appendData:data]; | 
| -  } | 
| - | 
| - private: | 
| -  ~WebpDecoderDelegate() override {} | 
| -  NSMutableData* decoded_image_; | 
| - | 
| -  DISALLOW_COPY_AND_ASSIGN(WebpDecoderDelegate); | 
| -}; | 
| - | 
| -// Content-type header for WebP images. | 
| -const char kWEBPFirstMagicPattern[] = "RIFF"; | 
| -const char kWEBPSecondMagicPattern[] = "WEBP"; | 
| - | 
| -const uint8_t kNumIfdEntries = 15; | 
| -const unsigned int kExtraDataSize = 16; | 
| -// 10b for signature/header + n * 12b entries + 4b for IFD terminator: | 
| -const unsigned int kExtraDataOffset = 10 + 12 * kNumIfdEntries + 4; | 
| -const unsigned int kHeaderSize = kExtraDataOffset + kExtraDataSize; | 
| -const int kRecompressionThreshold = 64 * 64;  // Threshold in pixels. | 
| -const CGFloat kJpegQuality = 0.85; | 
| - | 
| -// Adapted from libwebp example dwebp.c. | 
| -void PutLE16(uint8_t* const dst, uint32_t value) { | 
| -  dst[0] = (value >> 0) & 0xff; | 
| -  dst[1] = (value >> 8) & 0xff; | 
| -} | 
| - | 
| -void PutLE32(uint8_t* const dst, uint32_t value) { | 
| -  PutLE16(dst + 0, (value >> 0) & 0xffff); | 
| -  PutLE16(dst + 2, (value >> 16) & 0xffff); | 
| -} | 
| - | 
| -void WriteTiffHeader(uint8_t* dst, | 
| -                     int width, | 
| -                     int height, | 
| -                     int bytes_per_px, | 
| -                     bool has_alpha) { | 
| -  // For non-alpha case, we omit tag 0x152 (ExtraSamples). | 
| -  const uint8_t num_ifd_entries = | 
| -      has_alpha ? kNumIfdEntries : kNumIfdEntries - 1; | 
| -  uint8_t tiff_header[kHeaderSize] = { | 
| -      0x49, 0x49, 0x2a, 0x00,  // little endian signature | 
| -      8, 0, 0, 0,              // offset to the unique IFD that follows | 
| -      // IFD (offset = 8). Entries must be written in increasing tag order. | 
| -      num_ifd_entries, 0,  // Number of entries in the IFD (12 bytes each). | 
| -      0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0,  //  10: Width  (TBD) | 
| -      0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0,  //  22: Height (TBD) | 
| -      0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0,   //  34: BitsPerSample: 8888 | 
| -      kExtraDataOffset + 0, 0, 0, 0, 0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, | 
| -      0,                                         //  46: Compression: none | 
| -      0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0,  //  58: Photometric: RGB | 
| -      0x11, 0x01, 4, 0, 1, 0, 0, 0,              //  70: Strips offset: | 
| -      kHeaderSize, 0, 0, 0,                      //      data follows header | 
| -      0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0,  //  82: Orientation: topleft | 
| -      0x15, 0x01, 3, 0, 1, 0, 0, 0,              //  94: SamplesPerPixels | 
| -      bytes_per_px, 0, 0, 0, 0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, | 
| -      0,                                         // 106: Rows per strip (TBD) | 
| -      0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0,  // 118: StripByteCount (TBD) | 
| -      0x1a, 0x01, 5, 0, 1, 0, 0, 0,              // 130: X-resolution | 
| -      kExtraDataOffset + 8, 0, 0, 0, 0x1b, 0x01, 5, 0, 1, 0, 0, | 
| -      0,  // 142: Y-resolution | 
| -      kExtraDataOffset + 8, 0, 0, 0, 0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, | 
| -      0,                                         // 154: PlanarConfiguration | 
| -      0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0,  // 166: ResolutionUnit (inch) | 
| -      0x52, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0,  // 178: ExtraSamples: rgbA | 
| -      0, 0, 0, 0,                                // 190: IFD terminator | 
| -      // kExtraDataOffset: | 
| -      8, 0, 8, 0, 8, 0, 8, 0,  // BitsPerSample | 
| -      72, 0, 0, 0, 1, 0, 0, 0  // 72 pixels/inch, for X/Y-resolution | 
| -  }; | 
| - | 
| -  // Fill placeholders in IFD: | 
| -  PutLE32(tiff_header + 10 + 8, width); | 
| -  PutLE32(tiff_header + 22 + 8, height); | 
| -  PutLE32(tiff_header + 106 + 8, height); | 
| -  PutLE32(tiff_header + 118 + 8, width * bytes_per_px * height); | 
| -  if (!has_alpha) | 
| -    PutLE32(tiff_header + 178, 0); | 
| - | 
| -  memcpy(dst, tiff_header, kHeaderSize); | 
| -} | 
| - | 
| -}  // namespace | 
| - | 
| -namespace webp_transcode { | 
| - | 
| -// static | 
| -NSData* WebpDecoder::DecodeWebpImage(NSData* webp_image) { | 
| -  scoped_refptr<WebpDecoderDelegate> delegate(new WebpDecoderDelegate); | 
| - | 
| -  scoped_refptr<webp_transcode::WebpDecoder> decoder( | 
| -      new webp_transcode::WebpDecoder(delegate.get())); | 
| - | 
| -  decoder->OnDataReceived(webp_image); | 
| -  DLOG_IF(ERROR, !delegate->data()) << "WebP image decoding failed."; | 
| -  return delegate->data(); | 
| -} | 
| - | 
| -// static | 
| -bool WebpDecoder::IsWebpImage(const std::string& image_data) { | 
| -  if (image_data.length() < 12) | 
| -    return false; | 
| -  return image_data.compare(0, 4, kWEBPFirstMagicPattern) == 0 && | 
| -         image_data.compare(8, 4, kWEBPSecondMagicPattern) == 0; | 
| -} | 
| - | 
| -// static | 
| -size_t WebpDecoder::GetHeaderSize() { | 
| -  return kHeaderSize; | 
| -} | 
| - | 
| -WebpDecoder::WebpDecoder(WebpDecoder::Delegate* delegate) | 
| -    : delegate_(delegate), state_(READING_FEATURES), has_alpha_(0) { | 
| -  DCHECK(delegate_.get()); | 
| -  const bool rv = WebPInitDecoderConfig(&config_); | 
| -  DCHECK(rv); | 
| -} | 
| - | 
| -WebpDecoder::~WebpDecoder() { | 
| -  WebPFreeDecBuffer(&config_.output); | 
| -} | 
| - | 
| -void WebpDecoder::OnDataReceived(NSData* data) { | 
| -  DCHECK(data); | 
| -  switch (state_) { | 
| -    case READING_FEATURES: | 
| -      DoReadFeatures(data); | 
| -      break; | 
| -    case READING_DATA: | 
| -      DoReadData(data); | 
| -      break; | 
| -    case DONE: | 
| -      DLOG(WARNING) << "Received WebP data but decoding is finished. Ignoring."; | 
| -      break; | 
| -  } | 
| -} | 
| - | 
| -void WebpDecoder::Stop() { | 
| -  if (state_ != DONE) { | 
| -    state_ = DONE; | 
| -    DLOG(WARNING) << "Unexpected end of WebP data."; | 
| -    delegate_->OnFinishedDecoding(false); | 
| -  } | 
| -} | 
| - | 
| -void WebpDecoder::DoReadFeatures(NSData* data) { | 
| -  DCHECK_EQ(READING_FEATURES, state_); | 
| -  DCHECK(data); | 
| -  if (features_) | 
| -    [features_ appendData:data]; | 
| -  else | 
| -    features_.reset([[NSMutableData alloc] initWithData:data]); | 
| -  VP8StatusCode status = | 
| -      WebPGetFeatures(static_cast<const uint8_t*>([features_ bytes]), | 
| -                      [features_ length], &config_.input); | 
| -  switch (status) { | 
| -    case VP8_STATUS_OK: { | 
| -      has_alpha_ = config_.input.has_alpha; | 
| -      const uint32_t width = config_.input.width; | 
| -      const uint32_t height = config_.input.height; | 
| -      const size_t bytes_per_px = has_alpha_ ? 4 : 3; | 
| -      const int stride = bytes_per_px * width; | 
| -      const size_t image_data_size = stride * height; | 
| -      const size_t total_size = image_data_size + kHeaderSize; | 
| -      // Force pre-multiplied alpha. | 
| -      config_.output.colorspace = has_alpha_ ? MODE_rgbA : MODE_RGB; | 
| -      config_.output.u.RGBA.stride = stride; | 
| -      // Create the output buffer. | 
| -      config_.output.u.RGBA.size = image_data_size; | 
| -      uint8_t* dst = static_cast<uint8_t*>(malloc(total_size)); | 
| -      if (!dst) { | 
| -        DLOG(ERROR) << "Could not allocate WebP decoding buffer (size = " | 
| -                    << total_size << ")."; | 
| -        delegate_->OnFinishedDecoding(false); | 
| -        state_ = DONE; | 
| -        break; | 
| -      } | 
| -      WriteTiffHeader(dst, width, height, bytes_per_px, has_alpha_); | 
| -      output_buffer_.reset([[NSData alloc] initWithBytesNoCopy:dst | 
| -                                                        length:total_size | 
| -                                                  freeWhenDone:YES]); | 
| -      config_.output.is_external_memory = 1; | 
| -      config_.output.u.RGBA.rgba = dst + kHeaderSize; | 
| -      // Start decoding. | 
| -      state_ = READING_DATA; | 
| -      incremental_decoder_.reset(WebPINewDecoder(&config_.output)); | 
| -      DoReadData(features_); | 
| -      features_.reset(); | 
| -      break; | 
| -    } | 
| -    case VP8_STATUS_NOT_ENOUGH_DATA: | 
| -      // Do nothing. | 
| -      break; | 
| -    default: | 
| -      DLOG(ERROR) << "Error in WebP image features."; | 
| -      delegate_->OnFinishedDecoding(false); | 
| -      state_ = DONE; | 
| -      break; | 
| -  } | 
| -} | 
| - | 
| -void WebpDecoder::DoReadData(NSData* data) { | 
| -  DCHECK_EQ(READING_DATA, state_); | 
| -  DCHECK(incremental_decoder_); | 
| -  DCHECK(data); | 
| -  VP8StatusCode status = | 
| -      WebPIAppend(incremental_decoder_.get(), | 
| -                  static_cast<const uint8_t*>([data bytes]), [data length]); | 
| -  switch (status) { | 
| -    case VP8_STATUS_SUSPENDED: | 
| -      // Do nothing: re-compression to JPEG or PNG cannot be done incrementally. | 
| -      // Wait for the whole image to be decoded. | 
| -      break; | 
| -    case VP8_STATUS_OK: { | 
| -      bool rv = DoSendData(); | 
| -      DLOG_IF(ERROR, !rv) << "Error in WebP image conversion."; | 
| -      state_ = DONE; | 
| -      delegate_->OnFinishedDecoding(rv); | 
| -      break; | 
| -    } | 
| -    default: | 
| -      DLOG(ERROR) << "Error in WebP image decoding."; | 
| -      delegate_->OnFinishedDecoding(false); | 
| -      state_ = DONE; | 
| -      break; | 
| -  } | 
| -} | 
| - | 
| -bool WebpDecoder::DoSendData() { | 
| -  DCHECK_EQ(READING_DATA, state_); | 
| -  int width, height; | 
| -  uint8_t* data_ptr = WebPIDecGetRGB(incremental_decoder_.get(), nullptr, | 
| -                                     &width, &height, nullptr); | 
| -  if (!data_ptr) | 
| -    return false; | 
| -  DCHECK_EQ(static_cast<const uint8_t*>([output_buffer_ bytes]) + kHeaderSize, | 
| -            data_ptr); | 
| -  base::scoped_nsobject<NSData> result_data; | 
| -  // When the WebP image is larger than |kRecompressionThreshold| it is | 
| -  // compressed to JPEG or PNG. Otherwise, the uncompressed TIFF is used. | 
| -  DecodedImageFormat format = TIFF; | 
| -  if (width * height > kRecompressionThreshold) { | 
| -    base::scoped_nsobject<UIImage> tiff_image( | 
| -        [[UIImage alloc] initWithData:output_buffer_]); | 
| -    if (!tiff_image) | 
| -      return false; | 
| -    // Compress to PNG if the image is transparent, JPEG otherwise. | 
| -    // TODO(droger): Use PNG instead of JPEG if the WebP image is lossless. | 
| -    if (has_alpha_) { | 
| -      result_data.reset(UIImagePNGRepresentation(tiff_image)); | 
| -      format = PNG; | 
| -    } else { | 
| -      result_data.reset(UIImageJPEGRepresentation(tiff_image, kJpegQuality)); | 
| -      format = JPEG; | 
| -    } | 
| -    if (!result_data) | 
| -      return false; | 
| -  } else { | 
| -    result_data.reset(output_buffer_); | 
| -  } | 
| -  UMA_HISTOGRAM_ENUMERATION("WebP.DecodedImageFormat", format, | 
| -                            DECODED_FORMAT_COUNT); | 
| -  delegate_->SetImageFeatures([result_data length], format); | 
| -  delegate_->OnDataDecoded(result_data); | 
| -  output_buffer_.reset(); | 
| -  return true; | 
| -} | 
| - | 
| -}  // namespace webp_transcode | 
|  |