| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ui/views/controls/image_view.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "base/strings/utf_string_conversions.h" | |
| 9 #include "third_party/skia/include/core/SkPaint.h" | |
| 10 #include "ui/accessibility/ax_view_state.h" | |
| 11 #include "ui/gfx/canvas.h" | |
| 12 #include "ui/gfx/insets.h" | |
| 13 #include "ui/views/painter.h" | |
| 14 | |
| 15 namespace views { | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 // Returns the pixels for the bitmap in |image| at scale |image_scale|. | |
| 20 void* GetBitmapPixels(const gfx::ImageSkia& img, float image_scale) { | |
| 21 DCHECK_NE(0.0f, image_scale); | |
| 22 const SkBitmap& bitmap = img.GetRepresentation(image_scale).sk_bitmap(); | |
| 23 SkAutoLockPixels pixel_lock(bitmap); | |
| 24 return bitmap.getPixels(); | |
| 25 } | |
| 26 | |
| 27 } // namespace | |
| 28 | |
| 29 ImageView::ImageView() | |
| 30 : image_size_set_(false), | |
| 31 horiz_alignment_(CENTER), | |
| 32 vert_alignment_(CENTER), | |
| 33 interactive_(true), | |
| 34 last_paint_scale_(0.f), | |
| 35 last_painted_bitmap_pixels_(NULL), | |
| 36 focus_painter_(Painter::CreateDashedFocusPainter()) { | |
| 37 } | |
| 38 | |
| 39 ImageView::~ImageView() { | |
| 40 } | |
| 41 | |
| 42 void ImageView::SetImage(const gfx::ImageSkia& img) { | |
| 43 if (IsImageEqual(img)) | |
| 44 return; | |
| 45 | |
| 46 last_painted_bitmap_pixels_ = NULL; | |
| 47 gfx::Size pref_size(GetPreferredSize()); | |
| 48 image_ = img; | |
| 49 if (pref_size != GetPreferredSize()) | |
| 50 PreferredSizeChanged(); | |
| 51 SchedulePaint(); | |
| 52 } | |
| 53 | |
| 54 void ImageView::SetImage(const gfx::ImageSkia* image_skia) { | |
| 55 if (image_skia) { | |
| 56 SetImage(*image_skia); | |
| 57 } else { | |
| 58 gfx::ImageSkia t; | |
| 59 SetImage(t); | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 const gfx::ImageSkia& ImageView::GetImage() { | |
| 64 return image_; | |
| 65 } | |
| 66 | |
| 67 void ImageView::SetImageSize(const gfx::Size& image_size) { | |
| 68 image_size_set_ = true; | |
| 69 image_size_ = image_size; | |
| 70 PreferredSizeChanged(); | |
| 71 } | |
| 72 | |
| 73 bool ImageView::GetImageSize(gfx::Size* image_size) const { | |
| 74 DCHECK(image_size); | |
| 75 if (image_size_set_) | |
| 76 *image_size = image_size_; | |
| 77 return image_size_set_; | |
| 78 } | |
| 79 | |
| 80 gfx::Rect ImageView::GetImageBounds() const { | |
| 81 gfx::Size image_size(image_size_set_ ? | |
| 82 image_size_ : gfx::Size(image_.width(), image_.height())); | |
| 83 return gfx::Rect(ComputeImageOrigin(image_size), image_size); | |
| 84 } | |
| 85 | |
| 86 void ImageView::ResetImageSize() { | |
| 87 image_size_set_ = false; | |
| 88 } | |
| 89 | |
| 90 void ImageView::SetFocusPainter(scoped_ptr<Painter> focus_painter) { | |
| 91 focus_painter_ = focus_painter.Pass(); | |
| 92 } | |
| 93 | |
| 94 gfx::Size ImageView::GetPreferredSize() const { | |
| 95 gfx::Insets insets = GetInsets(); | |
| 96 if (image_size_set_) { | |
| 97 gfx::Size image_size; | |
| 98 GetImageSize(&image_size); | |
| 99 image_size.Enlarge(insets.width(), insets.height()); | |
| 100 return image_size; | |
| 101 } | |
| 102 return gfx::Size(image_.width() + insets.width(), | |
| 103 image_.height() + insets.height()); | |
| 104 } | |
| 105 | |
| 106 bool ImageView::IsImageEqual(const gfx::ImageSkia& img) const { | |
| 107 // Even though we copy ImageSkia in SetImage() the backing store | |
| 108 // (ImageSkiaStorage) is not copied and may have changed since the last call | |
| 109 // to SetImage(). The expectation is that SetImage() with different pixels is | |
| 110 // treated as though the image changed. For this reason we compare not only | |
| 111 // the backing store but also the pixels of the last image we painted. | |
| 112 return image_.BackedBySameObjectAs(img) && | |
| 113 last_paint_scale_ != 0.0f && | |
| 114 last_painted_bitmap_pixels_ == GetBitmapPixels(img, last_paint_scale_); | |
| 115 } | |
| 116 | |
| 117 gfx::Point ImageView::ComputeImageOrigin(const gfx::Size& image_size) const { | |
| 118 gfx::Insets insets = GetInsets(); | |
| 119 | |
| 120 int x; | |
| 121 // In order to properly handle alignment of images in RTL locales, we need | |
| 122 // to flip the meaning of trailing and leading. For example, if the | |
| 123 // horizontal alignment is set to trailing, then we'll use left alignment for | |
| 124 // the image instead of right alignment if the UI layout is RTL. | |
| 125 Alignment actual_horiz_alignment = horiz_alignment_; | |
| 126 if (base::i18n::IsRTL() && (horiz_alignment_ != CENTER)) | |
| 127 actual_horiz_alignment = (horiz_alignment_ == LEADING) ? TRAILING : LEADING; | |
| 128 switch (actual_horiz_alignment) { | |
| 129 case LEADING: x = insets.left(); break; | |
| 130 case TRAILING: x = width() - insets.right() - image_size.width(); break; | |
| 131 case CENTER: x = (width() - image_size.width()) / 2; break; | |
| 132 default: NOTREACHED(); x = 0; break; | |
| 133 } | |
| 134 | |
| 135 int y; | |
| 136 switch (vert_alignment_) { | |
| 137 case LEADING: y = insets.top(); break; | |
| 138 case TRAILING: y = height() - insets.bottom() - image_size.height(); break; | |
| 139 case CENTER: y = (height() - image_size.height()) / 2; break; | |
| 140 default: NOTREACHED(); y = 0; break; | |
| 141 } | |
| 142 | |
| 143 return gfx::Point(x, y); | |
| 144 } | |
| 145 | |
| 146 void ImageView::OnFocus() { | |
| 147 View::OnFocus(); | |
| 148 if (focus_painter_.get()) | |
| 149 SchedulePaint(); | |
| 150 } | |
| 151 | |
| 152 void ImageView::OnBlur() { | |
| 153 View::OnBlur(); | |
| 154 if (focus_painter_.get()) | |
| 155 SchedulePaint(); | |
| 156 } | |
| 157 | |
| 158 void ImageView::OnPaint(gfx::Canvas* canvas) { | |
| 159 View::OnPaint(canvas); | |
| 160 OnPaintImage(canvas); | |
| 161 Painter::PaintFocusPainter(this, canvas, focus_painter_.get()); | |
| 162 } | |
| 163 | |
| 164 void ImageView::GetAccessibleState(ui::AXViewState* state) { | |
| 165 state->role = ui::AX_ROLE_IMAGE; | |
| 166 state->name = tooltip_text_; | |
| 167 } | |
| 168 | |
| 169 void ImageView::SetHorizontalAlignment(Alignment ha) { | |
| 170 if (ha != horiz_alignment_) { | |
| 171 horiz_alignment_ = ha; | |
| 172 SchedulePaint(); | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 ImageView::Alignment ImageView::GetHorizontalAlignment() const { | |
| 177 return horiz_alignment_; | |
| 178 } | |
| 179 | |
| 180 void ImageView::SetVerticalAlignment(Alignment va) { | |
| 181 if (va != vert_alignment_) { | |
| 182 vert_alignment_ = va; | |
| 183 SchedulePaint(); | |
| 184 } | |
| 185 } | |
| 186 | |
| 187 ImageView::Alignment ImageView::GetVerticalAlignment() const { | |
| 188 return vert_alignment_; | |
| 189 } | |
| 190 | |
| 191 void ImageView::SetTooltipText(const base::string16& tooltip) { | |
| 192 tooltip_text_ = tooltip; | |
| 193 } | |
| 194 | |
| 195 base::string16 ImageView::GetTooltipText() const { | |
| 196 return tooltip_text_; | |
| 197 } | |
| 198 | |
| 199 bool ImageView::GetTooltipText(const gfx::Point& p, | |
| 200 base::string16* tooltip) const { | |
| 201 if (tooltip_text_.empty()) | |
| 202 return false; | |
| 203 | |
| 204 *tooltip = GetTooltipText(); | |
| 205 return true; | |
| 206 } | |
| 207 | |
| 208 bool ImageView::CanProcessEventsWithinSubtree() const { | |
| 209 return interactive_; | |
| 210 } | |
| 211 | |
| 212 void ImageView::OnPaintImage(gfx::Canvas* canvas) { | |
| 213 last_paint_scale_ = canvas->image_scale(); | |
| 214 last_painted_bitmap_pixels_ = NULL; | |
| 215 | |
| 216 if (image_.isNull()) | |
| 217 return; | |
| 218 | |
| 219 gfx::Rect image_bounds(GetImageBounds()); | |
| 220 if (image_bounds.IsEmpty()) | |
| 221 return; | |
| 222 | |
| 223 if (image_bounds.size() != gfx::Size(image_.width(), image_.height())) { | |
| 224 // Resize case | |
| 225 SkPaint paint; | |
| 226 paint.setFilterLevel(SkPaint::kLow_FilterLevel); | |
| 227 canvas->DrawImageInt(image_, 0, 0, image_.width(), image_.height(), | |
| 228 image_bounds.x(), image_bounds.y(), image_bounds.width(), | |
| 229 image_bounds.height(), true, paint); | |
| 230 } else { | |
| 231 canvas->DrawImageInt(image_, image_bounds.x(), image_bounds.y()); | |
| 232 } | |
| 233 last_painted_bitmap_pixels_ = GetBitmapPixels(image_, last_paint_scale_); | |
| 234 } | |
| 235 | |
| 236 } // namespace views | |
| OLD | NEW |