| Index: ui/gfx/image/image_skia.cc
|
| diff --git a/ui/gfx/image/image_skia.cc b/ui/gfx/image/image_skia.cc
|
| index 3c2e94f867221b4240065aef0652376daca0b435..21fb659881aa18849fdf1b96d18572f44c72171f 100644
|
| --- a/ui/gfx/image/image_skia.cc
|
| +++ b/ui/gfx/image/image_skia.cc
|
| @@ -8,139 +8,185 @@
|
| #include <cmath>
|
|
|
| #include "base/logging.h"
|
| -#include "base/stl_util.h"
|
| +#include "ui/gfx/size.h"
|
|
|
| namespace gfx {
|
|
|
| -ImageSkia::ImageSkia(const SkBitmap* bitmap)
|
| - : size_(bitmap->width(), bitmap->height()),
|
| - mip_map_build_pending_(false) {
|
| - CHECK(bitmap);
|
| - // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull()
|
| - bitmaps_.push_back(bitmap);
|
| -}
|
| -
|
| -ImageSkia::ImageSkia(const std::vector<const SkBitmap*>& bitmaps)
|
| - : bitmaps_(bitmaps),
|
| - mip_map_build_pending_(false) {
|
| - CHECK(!bitmaps_.empty());
|
| - // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull() for each
|
| - // vector element.
|
| - // Assume that the smallest bitmap represents 1x scale factor.
|
| - for (size_t i = 0; i < bitmaps_.size(); ++i) {
|
| - gfx::Size bitmap_size(bitmaps_[i]->width(), bitmaps_[i]->height());
|
| - if (size_.IsEmpty() || bitmap_size.GetArea() < size_.GetArea())
|
| - size_ = bitmap_size;
|
| +namespace internal {
|
| +
|
| +// A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a
|
| +// refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's
|
| +// information.
|
| +class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> {
|
| + public:
|
| + ImageSkiaStorage() {
|
| }
|
| -}
|
|
|
| -ImageSkia::~ImageSkia() {
|
| - STLDeleteElements(&bitmaps_);
|
| -}
|
| + void AddBitmap(const SkBitmap& bitmap) {
|
| + bitmaps_.push_back(bitmap);
|
| + }
|
|
|
| -void ImageSkia::BuildMipMap() {
|
| - mip_map_build_pending_ = true;
|
| -}
|
| + const std::vector<SkBitmap>& bitmaps() const { return bitmaps_; }
|
|
|
| -void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, int x, int y) {
|
| - SkPaint p;
|
| - DrawToCanvasInt(canvas, x, y, p);
|
| -}
|
| + void set_size(const gfx::Size& size) { size_ = size; }
|
| + const gfx::Size& size() const { return size_; }
|
|
|
| -void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas,
|
| - int x, int y,
|
| - const SkPaint& paint) {
|
| + private:
|
| + ~ImageSkiaStorage() {
|
| + }
|
|
|
| - if (IsZeroSized())
|
| - return;
|
| + // Bitmaps at different densities.
|
| + std::vector<SkBitmap> bitmaps_;
|
|
|
| - SkMatrix m = canvas->sk_canvas()->getTotalMatrix();
|
| - float scale_x = std::abs(SkScalarToFloat(m.getScaleX()));
|
| - float scale_y = std::abs(SkScalarToFloat(m.getScaleY()));
|
| + // Size of the image in DIP.
|
| + gfx::Size size_;
|
|
|
| - const SkBitmap* bitmap = GetBitmapForScale(scale_x, scale_y);
|
| + friend class base::RefCounted<ImageSkiaStorage>;
|
| +};
|
|
|
| - if (mip_map_build_pending_) {
|
| - const_cast<SkBitmap*>(bitmap)->buildMipMap();
|
| - mip_map_build_pending_ = false;
|
| - }
|
| +} // internal
|
|
|
| - float bitmap_scale_x = static_cast<float>(bitmap->width()) / width();
|
| - float bitmap_scale_y = static_cast<float>(bitmap->height()) / height();
|
| +// static
|
| +SkBitmap* ImageSkia::null_bitmap_ = new SkBitmap();
|
|
|
| - canvas->Save();
|
| - canvas->sk_canvas()->scale(1.0f / bitmap_scale_x,
|
| - 1.0f / bitmap_scale_y);
|
| - canvas->sk_canvas()->drawBitmap(*bitmap, SkFloatToScalar(x * bitmap_scale_x),
|
| - SkFloatToScalar(y * bitmap_scale_y));
|
| - canvas->Restore();
|
| +ImageSkia::ImageSkia() : storage_(NULL) {
|
| }
|
|
|
| -void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas,
|
| - int src_x, int src_y, int src_w, int src_h,
|
| - int dest_x, int dest_y, int dest_w, int dest_h,
|
| - bool filter) {
|
| - SkPaint p;
|
| - DrawToCanvasInt(canvas, src_x, src_y, src_w, src_h, dest_x, dest_y,
|
| - dest_w, dest_h, filter, p);
|
| +ImageSkia::ImageSkia(const SkBitmap& bitmap) {
|
| + Init(bitmap);
|
| }
|
|
|
| -void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas,
|
| - int src_x, int src_y, int src_w, int src_h,
|
| - int dest_x, int dest_y, int dest_w, int dest_h,
|
| - bool filter,
|
| - const SkPaint& paint) {
|
| - if (IsZeroSized())
|
| - return;
|
| +ImageSkia::ImageSkia(const SkBitmap& bitmap, float dip_scale_factor) {
|
| + Init(bitmap, dip_scale_factor);
|
| +}
|
|
|
| - SkMatrix m = canvas->sk_canvas()->getTotalMatrix();
|
| - float scale_x = std::abs(SkScalarToFloat(m.getScaleX()));
|
| - float scale_y = std::abs(SkScalarToFloat(m.getScaleY()));
|
| +ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) {
|
| +}
|
| +
|
| +ImageSkia& ImageSkia::operator=(const ImageSkia& other) {
|
| + storage_ = other.storage_;
|
| + return *this;
|
| +}
|
|
|
| - const SkBitmap* bitmap = GetBitmapForScale(scale_x, scale_y);
|
| +ImageSkia& ImageSkia::operator=(const SkBitmap& other) {
|
| + Init(other);
|
| + return *this;
|
| +}
|
|
|
| - if (mip_map_build_pending_) {
|
| - const_cast<SkBitmap*>(bitmap)->buildMipMap();
|
| - mip_map_build_pending_ = false;
|
| +ImageSkia::operator SkBitmap&() const {
|
| + if (isNull()) {
|
| + return *null_bitmap_;
|
| }
|
|
|
| - float bitmap_scale_x = static_cast<float>(bitmap->width()) / width();
|
| - float bitmap_scale_y = static_cast<float>(bitmap->height()) / height();
|
| + return const_cast<SkBitmap&>(storage_->bitmaps()[0]);
|
| +}
|
|
|
| - canvas->Save();
|
| - canvas->sk_canvas()->scale(1.0f / bitmap_scale_x,
|
| - 1.0f / bitmap_scale_y);
|
| - canvas->DrawBitmapFloat(*bitmap,
|
| - src_x * bitmap_scale_x, src_y * bitmap_scale_x,
|
| - src_w * bitmap_scale_x, src_h * bitmap_scale_y,
|
| - dest_x * bitmap_scale_x, dest_y * bitmap_scale_y,
|
| - dest_w * bitmap_scale_x, dest_h * bitmap_scale_y,
|
| - filter, paint);
|
| +ImageSkia::~ImageSkia() {
|
| +}
|
|
|
| - canvas->Restore();
|
| +void ImageSkia::AddBitmapForScale(const SkBitmap& bitmap,
|
| + float dip_scale_factor) {
|
| + DCHECK(!bitmap.isNull());
|
| +
|
| + if (isNull()) {
|
| + Init(bitmap, dip_scale_factor);
|
| + } else {
|
| + // We currently assume that the bitmap size = 1x size * |dip_scale_factor|.
|
| + // TODO(pkotwicz): Do something better because of rounding errors when
|
| + // |dip_scale_factor| is not an int.
|
| + // TODO(pkotwicz): Remove DCHECK for dip_scale_factor == 1.0f once
|
| + // image_loading_tracker correctly handles multiple sized images.
|
| + DCHECK(dip_scale_factor == 1.0f ||
|
| + static_cast<int>(width() * dip_scale_factor) == bitmap.width());
|
| + DCHECK(dip_scale_factor == 1.0f ||
|
| + static_cast<int>(height() * dip_scale_factor) == bitmap.height());
|
| + storage_->AddBitmap(bitmap);
|
| + }
|
| }
|
|
|
| -const SkBitmap* ImageSkia::GetBitmapForScale(float x_scale_factor,
|
| - float y_scale_factor) const {
|
| +const SkBitmap& ImageSkia::GetBitmapForScale(float x_scale_factor,
|
| + float y_scale_factor,
|
| + float* bitmap_scale_factor) const {
|
| +
|
| + if (empty())
|
| + return *null_bitmap_;
|
| +
|
| // Get the desired bitmap width and height given |x_scale_factor|,
|
| - // |y_scale_factor| and |size_| at 1x density.
|
| - float desired_width = size_.width() * x_scale_factor;
|
| - float desired_height = size_.height() * y_scale_factor;
|
| + // |y_scale_factor| and size at 1x density.
|
| + float desired_width = width() * x_scale_factor;
|
| + float desired_height = height() * y_scale_factor;
|
|
|
| + const std::vector<SkBitmap>& bitmaps = storage_->bitmaps();
|
| size_t closest_index = 0;
|
| float smallest_diff = std::numeric_limits<float>::max();
|
| - for (size_t i = 0; i < bitmaps_.size(); ++i) {
|
| - if (bitmaps_[i]->isNull())
|
| - continue;
|
| -
|
| - float diff = std::abs(bitmaps_[i]->width() - desired_width) +
|
| - std::abs(bitmaps_[i]->height() - desired_height);
|
| + for (size_t i = 0; i < bitmaps.size(); ++i) {
|
| + float diff = std::abs(bitmaps[i].width() - desired_width) +
|
| + std::abs(bitmaps[i].height() - desired_height);
|
| if (diff < smallest_diff) {
|
| closest_index = i;
|
| smallest_diff = diff;
|
| }
|
| }
|
| - return bitmaps_[closest_index];
|
| + if (smallest_diff < std::numeric_limits<float>::max()) {
|
| + *bitmap_scale_factor = static_cast<float>(bitmaps[closest_index].width()) /
|
| + width();
|
| + return bitmaps[closest_index];
|
| + }
|
| +
|
| + return *null_bitmap_;
|
| +}
|
| +
|
| +bool ImageSkia::empty() const {
|
| + return isNull() || storage_->size().IsEmpty();
|
| +}
|
| +
|
| +int ImageSkia::width() const {
|
| + return isNull() ? 0 : storage_->size().width();
|
| +}
|
| +
|
| +int ImageSkia::height() const {
|
| + return isNull() ? 0 : storage_->size().height();
|
| +}
|
| +
|
| +bool ImageSkia::extractSubset(ImageSkia* dst, SkIRect& subset) const {
|
| + if (isNull())
|
| + return false;
|
| + SkBitmap dst_bitmap;
|
| + bool return_value = storage_->bitmaps()[0].extractSubset(&dst_bitmap,
|
| + subset);
|
| + *dst = ImageSkia(dst_bitmap);
|
| + return return_value;
|
| +}
|
| +
|
| +const std::vector<SkBitmap> ImageSkia::bitmaps() const {
|
| + return storage_->bitmaps();
|
| +}
|
| +
|
| +const SkBitmap* ImageSkia::bitmap() const {
|
| + if (isNull()) {
|
| + // Callers expect an SkBitmap even if it is |isNull()|.
|
| + // TODO(pkotwicz): Fix this.
|
| + return null_bitmap_;
|
| + }
|
| +
|
| + return &storage_->bitmaps()[0];
|
| +}
|
| +
|
| +void ImageSkia::Init(const SkBitmap& bitmap) {
|
| + Init(bitmap, 1.0f);
|
| +}
|
| +
|
| +void ImageSkia::Init(const SkBitmap& bitmap, float scale_factor) {
|
| + DCHECK_GT(scale_factor, 0.0f);
|
| + // TODO(pkotwicz): The image should be null whenever bitmap is null.
|
| + if (bitmap.empty() && bitmap.isNull()) {
|
| + storage_ = NULL;
|
| + return;
|
| + }
|
| + storage_ = new internal::ImageSkiaStorage();
|
| + storage_->set_size(gfx::Size(static_cast<int>(bitmap.width() / scale_factor),
|
| + static_cast<int>(bitmap.height() / scale_factor)));
|
| + storage_->AddBitmap(bitmap);
|
| }
|
|
|
| } // namespace gfx
|
|
|