Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gfx/image/image_skia.h" | 5 #include "ui/gfx/image/image_skia.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "ui/gfx/size.h" | |
| 12 #include "ui/gfx/screen.h" | |
| 11 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 12 | 14 |
| 13 namespace gfx { | 15 namespace gfx { |
| 14 | 16 |
| 15 ImageSkia::ImageSkia(const SkBitmap* bitmap) | 17 namespace internal { |
| 16 : size_(bitmap->width(), bitmap->height()), | 18 |
| 17 mip_map_build_pending_(false) { | 19 // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a |
| 18 CHECK(bitmap); | 20 // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's |
| 19 // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull() | 21 // information. |
| 20 bitmaps_.push_back(bitmap); | 22 class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> { |
| 23 public: | |
| 24 ImageSkiaStorage() { | |
| 25 } | |
| 26 | |
| 27 void add_bitmap(const SkBitmap* bitmap) { | |
| 28 bitmaps_.push_back(bitmap); | |
| 29 } | |
| 30 | |
| 31 void set_bitmaps(const std::vector<const SkBitmap*>& bitmaps) { | |
| 32 bitmaps_ = bitmaps; | |
| 33 } | |
| 34 const std::vector<const SkBitmap*>& bitmaps() const { return bitmaps_; } | |
| 35 | |
| 36 void set_size(gfx::Size size) { size_ = size; } | |
| 37 gfx::Size size() const { return size_; } | |
| 38 | |
| 39 private: | |
| 40 ~ImageSkiaStorage() { | |
| 41 STLDeleteElements(&bitmaps_); | |
| 42 } | |
| 43 | |
| 44 // Bitmaps at different densities. | |
| 45 std::vector<const SkBitmap*> bitmaps_; | |
| 46 | |
| 47 // Size of the image in DIP. | |
| 48 gfx::Size size_; | |
| 49 | |
| 50 friend class base::RefCounted<ImageSkiaStorage>; | |
| 51 }; | |
| 52 | |
| 53 } // internal | |
| 54 | |
| 55 ImageSkia::ImageSkia() : storage_(NULL) { | |
| 56 } | |
| 57 | |
| 58 ImageSkia::ImageSkia(const SkBitmap& bitmap) { | |
| 59 Init(new SkBitmap(bitmap)); | |
| 60 } | |
| 61 | |
| 62 ImageSkia::ImageSkia(const SkBitmap& bitmap, float scale_factor) { | |
| 63 Init(new SkBitmap(bitmap), scale_factor); | |
| 64 } | |
| 65 | |
| 66 ImageSkia::ImageSkia(const SkBitmap* bitmap) { | |
| 67 Init(bitmap); | |
| 21 } | 68 } |
| 22 | 69 |
| 23 ImageSkia::ImageSkia(const std::vector<const SkBitmap*>& bitmaps) | 70 ImageSkia::ImageSkia(const std::vector<const SkBitmap*>& bitmaps) |
| 24 : bitmaps_(bitmaps), | 71 : storage_(new internal::ImageSkiaStorage()) { |
| 25 mip_map_build_pending_(false) { | 72 storage_->set_bitmaps(bitmaps); |
| 26 CHECK(!bitmaps_.empty()); | |
| 27 // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull() for each | |
| 28 // vector element. | |
| 29 // Assume that the smallest bitmap represents 1x scale factor. | 73 // Assume that the smallest bitmap represents 1x scale factor. |
| 30 for (size_t i = 0; i < bitmaps_.size(); ++i) { | 74 gfx::Size smallest_bitmap_size; |
| 31 gfx::Size bitmap_size(bitmaps_[i]->width(), bitmaps_[i]->height()); | 75 for (size_t i = 0; i < bitmaps.size(); ++i) { |
| 32 if (size_.IsEmpty() || bitmap_size.GetArea() < size_.GetArea()) | 76 gfx::Size bitmap_size(bitmaps[i]->width(), bitmaps[i]->height()); |
| 33 size_ = bitmap_size; | 77 DCHECK(!bitmaps[i]->isNull()); |
| 78 if (smallest_bitmap_size.IsEmpty() || | |
| 79 bitmap_size.GetArea() < smallest_bitmap_size.GetArea()) | |
| 80 smallest_bitmap_size = bitmap_size; | |
| 34 } | 81 } |
| 82 storage_->set_size(smallest_bitmap_size); | |
| 83 } | |
| 84 | |
| 85 ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) { | |
| 86 } | |
| 87 | |
| 88 ImageSkia& ImageSkia::operator=(const ImageSkia& other) { | |
| 89 storage_ = other.storage_; | |
| 90 return *this; | |
| 91 } | |
| 92 | |
| 93 ImageSkia& ImageSkia::operator=(const SkBitmap& other) { | |
| 94 Init(new SkBitmap(other)); | |
| 95 return *this; | |
| 96 } | |
| 97 | |
| 98 ImageSkia::operator SkBitmap() const { | |
| 99 return isNull() ? SkBitmap() : *bitmaps()[0]; | |
| 35 } | 100 } |
| 36 | 101 |
| 37 ImageSkia::~ImageSkia() { | 102 ImageSkia::~ImageSkia() { |
| 38 STLDeleteElements(&bitmaps_); | |
| 39 } | |
| 40 | |
| 41 void ImageSkia::BuildMipMap() { | |
| 42 mip_map_build_pending_ = true; | |
| 43 } | |
| 44 | |
| 45 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, int x, int y) { | |
| 46 SkPaint p; | |
| 47 DrawToCanvasInt(canvas, x, y, p); | |
| 48 } | |
| 49 | |
| 50 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, | |
| 51 int x, int y, | |
| 52 const SkPaint& paint) { | |
| 53 | |
| 54 if (IsZeroSized()) | |
| 55 return; | |
| 56 | |
| 57 SkMatrix m = canvas->sk_canvas()->getTotalMatrix(); | |
| 58 float scale_x = std::abs(SkScalarToFloat(m.getScaleX())); | |
| 59 float scale_y = std::abs(SkScalarToFloat(m.getScaleY())); | |
| 60 | |
| 61 const SkBitmap* bitmap = GetBitmapForScale(scale_x, scale_y); | |
| 62 | |
| 63 if (mip_map_build_pending_) { | |
| 64 const_cast<SkBitmap*>(bitmap)->buildMipMap(); | |
| 65 mip_map_build_pending_ = false; | |
| 66 } | |
| 67 | |
| 68 float bitmap_scale_x = static_cast<float>(bitmap->width()) / width(); | |
| 69 float bitmap_scale_y = static_cast<float>(bitmap->height()) / height(); | |
| 70 | |
| 71 canvas->Save(); | |
| 72 canvas->sk_canvas()->scale(1.0f / bitmap_scale_x, | |
| 73 1.0f / bitmap_scale_y); | |
| 74 canvas->sk_canvas()->drawBitmap(*bitmap, SkFloatToScalar(x * bitmap_scale_x), | |
| 75 SkFloatToScalar(y * bitmap_scale_y)); | |
| 76 canvas->Restore(); | |
| 77 } | |
| 78 | |
| 79 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, | |
| 80 int src_x, int src_y, int src_w, int src_h, | |
| 81 int dest_x, int dest_y, int dest_w, int dest_h, | |
| 82 bool filter) { | |
| 83 SkPaint p; | |
| 84 DrawToCanvasInt(canvas, src_x, src_y, src_w, src_h, dest_x, dest_y, | |
| 85 dest_w, dest_h, filter, p); | |
| 86 } | |
| 87 | |
| 88 void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, | |
| 89 int src_x, int src_y, int src_w, int src_h, | |
| 90 int dest_x, int dest_y, int dest_w, int dest_h, | |
| 91 bool filter, | |
| 92 const SkPaint& paint) { | |
| 93 if (IsZeroSized()) | |
| 94 return; | |
| 95 | |
| 96 SkMatrix m = canvas->sk_canvas()->getTotalMatrix(); | |
| 97 float scale_x = std::abs(SkScalarToFloat(m.getScaleX())); | |
| 98 float scale_y = std::abs(SkScalarToFloat(m.getScaleY())); | |
| 99 | |
| 100 const SkBitmap* bitmap = GetBitmapForScale(scale_x, scale_y); | |
| 101 | |
| 102 if (mip_map_build_pending_) { | |
| 103 const_cast<SkBitmap*>(bitmap)->buildMipMap(); | |
| 104 mip_map_build_pending_ = false; | |
| 105 } | |
| 106 | |
| 107 float bitmap_scale_x = static_cast<float>(bitmap->width()) / width(); | |
| 108 float bitmap_scale_y = static_cast<float>(bitmap->height()) / height(); | |
| 109 | |
| 110 canvas->Save(); | |
| 111 canvas->sk_canvas()->scale(1.0f / bitmap_scale_x, | |
| 112 1.0f / bitmap_scale_y); | |
| 113 canvas->DrawBitmapFloat(*bitmap, | |
| 114 src_x * bitmap_scale_x, src_y * bitmap_scale_x, | |
| 115 src_w * bitmap_scale_x, src_h * bitmap_scale_y, | |
| 116 dest_x * bitmap_scale_x, dest_y * bitmap_scale_y, | |
| 117 dest_w * bitmap_scale_x, dest_h * bitmap_scale_y, | |
| 118 filter, paint); | |
| 119 | |
| 120 canvas->Restore(); | |
| 121 } | 103 } |
| 122 | 104 |
| 123 const SkBitmap* ImageSkia::GetBitmapForScale(float x_scale_factor, | 105 const SkBitmap* ImageSkia::GetBitmapForScale(float x_scale_factor, |
| 124 float y_scale_factor) const { | 106 float y_scale_factor) const { |
| 107 if (isNull()) | |
| 108 return NULL; | |
| 109 | |
| 125 // Get the desired bitmap width and height given |x_scale_factor|, | 110 // Get the desired bitmap width and height given |x_scale_factor|, |
| 126 // |y_scale_factor| and |size_| at 1x density. | 111 // |y_scale_factor| and size at 1x density. |
| 127 float desired_width = size_.width() * x_scale_factor; | 112 float desired_width = width() * x_scale_factor; |
| 128 float desired_height = size_.height() * y_scale_factor; | 113 float desired_height = height() * y_scale_factor; |
| 129 | 114 |
| 130 size_t closest_index = 0; | 115 const std::vector<const SkBitmap*>& bitmaps = storage_->bitmaps(); |
| 116 size_t closest_index = -1; | |
| 131 float smallest_diff = std::numeric_limits<float>::max(); | 117 float smallest_diff = std::numeric_limits<float>::max(); |
| 132 for (size_t i = 0; i < bitmaps_.size(); ++i) { | 118 for (size_t i = 0; i < bitmaps.size(); ++i) { |
| 133 if (bitmaps_[i]->isNull()) | 119 float diff = std::abs(bitmaps[i]->width() - desired_width) + |
| 134 continue; | 120 std::abs(bitmaps[i]->height() - desired_height); |
| 135 | |
| 136 float diff = std::abs(bitmaps_[i]->width() - desired_width) + | |
| 137 std::abs(bitmaps_[i]->height() - desired_height); | |
| 138 if (diff < smallest_diff) { | 121 if (diff < smallest_diff) { |
| 139 closest_index = i; | 122 closest_index = i; |
| 140 smallest_diff = diff; | 123 smallest_diff = diff; |
| 141 } | 124 } |
| 142 } | 125 } |
| 143 return bitmaps_[closest_index]; | 126 return closest_index < 0 ? NULL : bitmaps[closest_index]; |
| 127 } | |
| 128 | |
| 129 bool ImageSkia::empty() const { | |
| 130 return isNull() || storage_->size().IsEmpty(); | |
| 131 } | |
| 132 | |
| 133 int ImageSkia::width() const { | |
| 134 return isNull() ? 0 : storage_->size().width(); | |
|
oshima
2012/04/30 21:10:08
We don't want to exclude the possibility to have i
| |
| 135 } | |
| 136 | |
| 137 int ImageSkia::height() const { | |
| 138 return isNull() ? 0 : storage_->size().height(); | |
| 139 } | |
| 140 | |
| 141 bool ImageSkia::extractSubset(ImageSkia* dst, SkIRect& subset) const { | |
| 142 if (isNull()) | |
| 143 return false; | |
| 144 SkBitmap dst_bitmap; | |
| 145 bool return_value = bitmaps()[0]->extractSubset(&dst_bitmap, subset); | |
| 146 *dst = ImageSkia(dst_bitmap); | |
| 147 return return_value; | |
| 148 } | |
| 149 | |
| 150 const std::vector<const SkBitmap*>& ImageSkia::bitmaps() const { | |
| 151 return storage_->bitmaps(); | |
| 152 } | |
| 153 | |
| 154 void ImageSkia::Init(const SkBitmap* bitmap) { | |
| 155 #if defined(ENABLE_DIP) | |
| 156 Init(bitmap, Screen::GetPrimaryMonitor().device_scale_factor()); | |
| 157 #else | |
| 158 Init(bitmap, 1.0f); | |
| 159 #endif | |
| 160 } | |
| 161 | |
| 162 void ImageSkia::Init(const SkBitmap* bitmap, float scale_factor) { | |
| 163 DCHECK(scale_factor >= 1.0f); | |
| 164 if (bitmap->isNull()) { | |
| 165 storage_ = NULL; | |
| 166 return; | |
| 167 } | |
| 168 | |
| 169 storage_ = new internal::ImageSkiaStorage(); | |
| 170 storage_->set_size(gfx::Size(bitmap->width(), bitmap->height())); | |
| 171 storage_->add_bitmap(bitmap); | |
| 144 } | 172 } |
| 145 | 173 |
| 146 } // namespace gfx | 174 } // namespace gfx |
| OLD | NEW |