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