| Index: app/gfx/codec/png_codec.cc
 | 
| ===================================================================
 | 
| --- app/gfx/codec/png_codec.cc	(revision 0)
 | 
| +++ app/gfx/codec/png_codec.cc	(working copy)
 | 
| @@ -1,11 +1,13 @@
 | 
| -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
 | 
| +// Copyright (c) 2009 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.
 | 
|  
 | 
| -#include "base/gfx/png_decoder.h"
 | 
| +#include "app/gfx/codec/png_codec.h"
 | 
|  
 | 
|  #include "base/logging.h"
 | 
| +#include "base/scoped_ptr.h"
 | 
|  #include "third_party/skia/include/core/SkBitmap.h"
 | 
| +#include "third_party/skia/include/core/SkUnPreMultiply.h"
 | 
|  
 | 
|  extern "C" {
 | 
|  #if defined(USE_SYSTEM_LIBPNG)
 | 
| @@ -15,6 +17,8 @@
 | 
|  #endif
 | 
|  }
 | 
|  
 | 
| +namespace gfx {
 | 
| +
 | 
|  namespace {
 | 
|  
 | 
|  // Converts BGRA->RGBA and RGBA->BGRA.
 | 
| @@ -57,7 +61,7 @@
 | 
|  
 | 
|  class PngDecoderState {
 | 
|   public:
 | 
| -  PngDecoderState(PNGDecoder::ColorFormat ofmt, std::vector<unsigned char>* o)
 | 
| +  PngDecoderState(PNGCodec::ColorFormat ofmt, std::vector<unsigned char>* o)
 | 
|        : output_format(ofmt),
 | 
|          output_channels(0),
 | 
|          output(o),
 | 
| @@ -67,7 +71,7 @@
 | 
|          done(false) {
 | 
|    }
 | 
|  
 | 
| -  PNGDecoder::ColorFormat output_format;
 | 
| +  PNGCodec::ColorFormat output_format;
 | 
|    int output_channels;
 | 
|  
 | 
|    std::vector<unsigned char>* output;
 | 
| @@ -84,7 +88,7 @@
 | 
|    bool done;
 | 
|  
 | 
|   private:
 | 
| -  DISALLOW_EVIL_CONSTRUCTORS(PngDecoderState);
 | 
| +  DISALLOW_COPY_AND_ASSIGN(PngDecoderState);
 | 
|  };
 | 
|  
 | 
|  void ConvertRGBtoRGBA(const unsigned char* rgb, int pixel_width,
 | 
| @@ -176,15 +180,15 @@
 | 
|    // Pick our row format converter necessary for this data.
 | 
|    if (channels == 3) {
 | 
|      switch (state->output_format) {
 | 
| -      case PNGDecoder::FORMAT_RGB:
 | 
| +      case PNGCodec::FORMAT_RGB:
 | 
|          state->row_converter = NULL;  // no conversion necessary
 | 
|          state->output_channels = 3;
 | 
|          break;
 | 
| -      case PNGDecoder::FORMAT_RGBA:
 | 
| +      case PNGCodec::FORMAT_RGBA:
 | 
|          state->row_converter = &ConvertRGBtoRGBA;
 | 
|          state->output_channels = 4;
 | 
|          break;
 | 
| -      case PNGDecoder::FORMAT_BGRA:
 | 
| +      case PNGCodec::FORMAT_BGRA:
 | 
|          state->row_converter = &ConvertRGBtoBGRA;
 | 
|          state->output_channels = 4;
 | 
|          break;
 | 
| @@ -194,15 +198,15 @@
 | 
|      }
 | 
|    } else if (channels == 4) {
 | 
|      switch (state->output_format) {
 | 
| -      case PNGDecoder::FORMAT_RGB:
 | 
| +      case PNGCodec::FORMAT_RGB:
 | 
|          state->row_converter = &ConvertRGBAtoRGB;
 | 
|          state->output_channels = 3;
 | 
|          break;
 | 
| -      case PNGDecoder::FORMAT_RGBA:
 | 
| +      case PNGCodec::FORMAT_RGBA:
 | 
|          state->row_converter = NULL;  // no conversion necessary
 | 
|          state->output_channels = 4;
 | 
|          break;
 | 
| -      case PNGDecoder::FORMAT_BGRA:
 | 
| +      case PNGCodec::FORMAT_BGRA:
 | 
|          state->row_converter = &ConvertBetweenBGRAandRGBA;
 | 
|          state->output_channels = 4;
 | 
|          break;
 | 
| @@ -264,9 +268,9 @@
 | 
|  }  // namespace
 | 
|  
 | 
|  // static
 | 
| -bool PNGDecoder::Decode(const unsigned char* input, size_t input_size,
 | 
| -                        ColorFormat format, std::vector<unsigned char>* output,
 | 
| -                        int* w, int* h) {
 | 
| +bool PNGCodec::Decode(const unsigned char* input, size_t input_size,
 | 
| +                      ColorFormat format, std::vector<unsigned char>* output,
 | 
| +                      int* w, int* h) {
 | 
|    if (input_size < 8)
 | 
|      return false;  // Input data too small to be a png
 | 
|  
 | 
| @@ -317,15 +321,15 @@
 | 
|  }
 | 
|  
 | 
|  // static
 | 
| -bool PNGDecoder::Decode(const std::vector<unsigned char>* data,
 | 
| -                        SkBitmap* bitmap) {
 | 
| +bool PNGCodec::Decode(const std::vector<unsigned char>* data,
 | 
| +                      SkBitmap* bitmap) {
 | 
|    DCHECK(bitmap);
 | 
|    if (!data || data->empty())
 | 
|      return false;
 | 
|    int width, height;
 | 
|    std::vector<unsigned char> decoded_data;
 | 
| -  if (PNGDecoder::Decode(&data->front(), data->size(), PNGDecoder::FORMAT_BGRA,
 | 
| -                         &decoded_data, &width, &height)) {
 | 
| +  if (PNGCodec::Decode(&data->front(), data->size(), PNGCodec::FORMAT_BGRA,
 | 
| +                       &decoded_data, &width, &height)) {
 | 
|      bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
 | 
|      bitmap->allocPixels();
 | 
|      unsigned char* bitmap_data =
 | 
| @@ -351,8 +355,8 @@
 | 
|    return false;
 | 
|  }
 | 
|  
 | 
| -//static
 | 
| -SkBitmap* PNGDecoder::CreateSkBitmapFromBGRAFormat(
 | 
| +// static
 | 
| +SkBitmap* PNGCodec::CreateSkBitmapFromBGRAFormat(
 | 
|      std::vector<unsigned char>& bgra, int width, int height) {
 | 
|    SkBitmap* bitmap = new SkBitmap();
 | 
|    bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
 | 
| @@ -375,3 +379,199 @@
 | 
|    bitmap->setIsOpaque(opaque);
 | 
|    return bitmap;
 | 
|  }
 | 
| +
 | 
| +// Encoder --------------------------------------------------------------------
 | 
| +//
 | 
| +// This section of the code is based on nsPNGEncoder.cpp in Mozilla
 | 
| +// (Copyright 2005 Google Inc.)
 | 
| +
 | 
| +namespace {
 | 
| +
 | 
| +// Passed around as the io_ptr in the png structs so our callbacks know where
 | 
| +// to write data.
 | 
| +struct PngEncoderState {
 | 
| +  PngEncoderState(std::vector<unsigned char>* o) : out(o) {}
 | 
| +  std::vector<unsigned char>* out;
 | 
| +};
 | 
| +
 | 
| +// Called by libpng to flush its internal buffer to ours.
 | 
| +void EncoderWriteCallback(png_structp png, png_bytep data, png_size_t size) {
 | 
| +  PngEncoderState* state = static_cast<PngEncoderState*>(png_get_io_ptr(png));
 | 
| +  DCHECK(state->out);
 | 
| +
 | 
| +  size_t old_size = state->out->size();
 | 
| +  state->out->resize(old_size + size);
 | 
| +  memcpy(&(*state->out)[old_size], data, size);
 | 
| +}
 | 
| +
 | 
| +void ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width,
 | 
| +                      unsigned char* rgb) {
 | 
| +  for (int x = 0; x < pixel_width; x++) {
 | 
| +    const unsigned char* pixel_in = &bgra[x * 4];
 | 
| +    unsigned char* pixel_out = &rgb[x * 3];
 | 
| +    pixel_out[0] = pixel_in[2];
 | 
| +    pixel_out[1] = pixel_in[1];
 | 
| +    pixel_out[2] = pixel_in[0];
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +// Automatically destroys the given write structs on destruction to make
 | 
| +// cleanup and error handling code cleaner.
 | 
| +class PngWriteStructDestroyer {
 | 
| + public:
 | 
| +  PngWriteStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) {
 | 
| +  }
 | 
| +  ~PngWriteStructDestroyer() {
 | 
| +    png_destroy_write_struct(ps_, pi_);
 | 
| +  }
 | 
| + private:
 | 
| +  png_struct** ps_;
 | 
| +  png_info** pi_;
 | 
| +
 | 
| +  DISALLOW_EVIL_CONSTRUCTORS(PngWriteStructDestroyer);
 | 
| +};
 | 
| +
 | 
| +}  // namespace
 | 
| +
 | 
| +// static
 | 
| +bool PNGCodec::Encode(const unsigned char* input, ColorFormat format,
 | 
| +                      int w, int h, int row_byte_width,
 | 
| +                      bool discard_transparency,
 | 
| +                      std::vector<unsigned char>* output) {
 | 
| +  // Run to convert an input row into the output row format, NULL means no
 | 
| +  // conversion is necessary.
 | 
| +  void (*converter)(const unsigned char* in, int w, unsigned char* out) = NULL;
 | 
| +
 | 
| +  int input_color_components, output_color_components;
 | 
| +  int png_output_color_type;
 | 
| +  switch (format) {
 | 
| +    case FORMAT_RGB:
 | 
| +      input_color_components = 3;
 | 
| +      output_color_components = 3;
 | 
| +      png_output_color_type = PNG_COLOR_TYPE_RGB;
 | 
| +      discard_transparency = false;
 | 
| +      break;
 | 
| +
 | 
| +    case FORMAT_RGBA:
 | 
| +      input_color_components = 4;
 | 
| +      if (discard_transparency) {
 | 
| +        output_color_components = 3;
 | 
| +        png_output_color_type = PNG_COLOR_TYPE_RGB;
 | 
| +        converter = ConvertRGBAtoRGB;
 | 
| +      } else {
 | 
| +        output_color_components = 4;
 | 
| +        png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
 | 
| +        converter = NULL;
 | 
| +      }
 | 
| +      break;
 | 
| +
 | 
| +    case FORMAT_BGRA:
 | 
| +      input_color_components = 4;
 | 
| +      if (discard_transparency) {
 | 
| +        output_color_components = 3;
 | 
| +        png_output_color_type = PNG_COLOR_TYPE_RGB;
 | 
| +        converter = ConvertBGRAtoRGB;
 | 
| +      } else {
 | 
| +        output_color_components = 4;
 | 
| +        png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
 | 
| +        converter = ConvertBetweenBGRAandRGBA;
 | 
| +      }
 | 
| +      break;
 | 
| +
 | 
| +    default:
 | 
| +      NOTREACHED() << "Unknown pixel format";
 | 
| +      return false;
 | 
| +  }
 | 
| +
 | 
| +  // Row stride should be at least as long as the length of the data.
 | 
| +  DCHECK(input_color_components * w <= row_byte_width);
 | 
| +
 | 
| +  png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
 | 
| +                                                png_voidp_NULL,
 | 
| +                                                png_error_ptr_NULL,
 | 
| +                                                png_error_ptr_NULL);
 | 
| +  if (!png_ptr)
 | 
| +    return false;
 | 
| +  png_info* info_ptr = png_create_info_struct(png_ptr);
 | 
| +  if (!info_ptr) {
 | 
| +    png_destroy_write_struct(&png_ptr, NULL);
 | 
| +    return false;
 | 
| +  }
 | 
| +  PngWriteStructDestroyer destroyer(&png_ptr, &info_ptr);
 | 
| +
 | 
| +  if (setjmp(png_jmpbuf(png_ptr))) {
 | 
| +    // The destroyer will ensure that the structures are cleaned up in this
 | 
| +    // case, even though we may get here as a jump from random parts of the
 | 
| +    // PNG library called below.
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  // Set our callback for libpng to give us the data.
 | 
| +  PngEncoderState state(output);
 | 
| +  png_set_write_fn(png_ptr, &state, EncoderWriteCallback, NULL);
 | 
| +
 | 
| +  png_set_IHDR(png_ptr, info_ptr, w, h, 8, png_output_color_type,
 | 
| +               PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
 | 
| +               PNG_FILTER_TYPE_DEFAULT);
 | 
| +  png_write_info(png_ptr, info_ptr);
 | 
| +
 | 
| +  if (!converter) {
 | 
| +    // No conversion needed, give the data directly to libpng.
 | 
| +    for (int y = 0; y < h; y ++)
 | 
| +      png_write_row(png_ptr,
 | 
| +                    const_cast<unsigned char*>(&input[y * row_byte_width]));
 | 
| +  } else {
 | 
| +    // Needs conversion using a separate buffer.
 | 
| +    unsigned char* row = new unsigned char[w * output_color_components];
 | 
| +    for (int y = 0; y < h; y ++) {
 | 
| +      converter(&input[y * row_byte_width], w, row);
 | 
| +      png_write_row(png_ptr, row);
 | 
| +    }
 | 
| +    delete[] row;
 | 
| +  }
 | 
| +
 | 
| +  png_write_end(png_ptr, info_ptr);
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +// static
 | 
| +bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input,
 | 
| +                                  bool discard_transparency,
 | 
| +                                  std::vector<unsigned char>* output) {
 | 
| +  static const int bbp = 4;
 | 
| +
 | 
| +  SkAutoLockPixels lock_input(input);
 | 
| +  DCHECK(input.empty() || input.bytesPerPixel() == bbp);
 | 
| +
 | 
| +  // SkBitmaps are premultiplied, we need to unpremultiply them.
 | 
| +  scoped_array<unsigned char> divided(
 | 
| +      new unsigned char[input.width() * input.height() * bbp]);
 | 
| +
 | 
| +  int i = 0;
 | 
| +  for (int y = 0; y < input.height(); y++) {
 | 
| +    for (int x = 0; x < input.width(); x++) {
 | 
| +      uint32 pixel = input.getAddr32(0, y)[x];
 | 
| +
 | 
| +      int alpha = SkColorGetA(pixel);
 | 
| +      if (alpha != 0 && alpha != 255) {
 | 
| +        SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel);
 | 
| +        divided[i + 0] = SkColorGetR(unmultiplied);
 | 
| +        divided[i + 1] = SkColorGetG(unmultiplied);
 | 
| +        divided[i + 2] = SkColorGetB(unmultiplied);
 | 
| +        divided[i + 3] = alpha;
 | 
| +      } else {
 | 
| +        divided[i + 0] = SkColorGetR(pixel);
 | 
| +        divided[i + 1] = SkColorGetG(pixel);
 | 
| +        divided[i + 2] = SkColorGetB(pixel);
 | 
| +        divided[i + 3] = alpha;
 | 
| +      }
 | 
| +      i += bbp;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  return Encode(divided.get(),
 | 
| +                PNGCodec::FORMAT_RGBA, input.width(), input.height(),
 | 
| +                input.width() * bbp, discard_transparency, output);
 | 
| +}
 | 
| +
 | 
| +}  // namespace gfx
 | 
| 
 | 
| Property changes on: app/gfx/codec/png_codec.cc
 | 
| ___________________________________________________________________
 | 
| Added: svn:mergeinfo
 | 
|    Merged /branches/chrome_webkit_merge_branch/base/gfx/png_decoder.cc:r69-2775
 | 
| 
 | 
| 
 |