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/painter.h" 6 7 #include "base/logging.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "third_party/skia/include/effects/SkGradientShader.h" 10 #include "ui/base/resource/resource_bundle.h" 11 #include "ui/gfx/canvas.h" 12 #include "ui/gfx/image/image.h" 13 #include "ui/gfx/image/image_skia.h" 14 #include "ui/gfx/image/image_skia_operations.h" 15 #include "ui/gfx/insets.h" 16 #include "ui/gfx/nine_image_painter.h" 17 #include "ui/gfx/point.h" 18 #include "ui/gfx/rect.h" 19 #include "ui/views/view.h" 20 21 namespace views { 22 23 namespace { 24 25 // DashedFocusPainter ---------------------------------------------------------- 26 27 class DashedFocusPainter : public Painter { 28 public: 29 explicit DashedFocusPainter(const gfx::Insets& insets); 30 virtual ~DashedFocusPainter(); 31 32 // Painter: 33 virtual gfx::Size GetMinimumSize() const OVERRIDE; 34 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE; 35 36 private: 37 const gfx::Insets insets_; 38 39 DISALLOW_COPY_AND_ASSIGN(DashedFocusPainter); 40 }; 41 42 DashedFocusPainter::DashedFocusPainter(const gfx::Insets& insets) 43 : insets_(insets) { 44 } 45 46 DashedFocusPainter::~DashedFocusPainter() { 47 } 48 49 gfx::Size DashedFocusPainter::GetMinimumSize() const { 50 return gfx::Size(); 51 } 52 53 void DashedFocusPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) { 54 gfx::Rect rect(size); 55 rect.Inset(insets_); 56 canvas->DrawFocusRect(rect); 57 } 58 59 // SolidFocusPainter ----------------------------------------------------------- 60 61 class SolidFocusPainter : public Painter { 62 public: 63 SolidFocusPainter(SkColor color, const gfx::Insets& insets); 64 virtual ~SolidFocusPainter(); 65 66 // Painter: 67 virtual gfx::Size GetMinimumSize() const OVERRIDE; 68 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE; 69 70 private: 71 const SkColor color_; 72 const gfx::Insets insets_; 73 74 DISALLOW_COPY_AND_ASSIGN(SolidFocusPainter); 75 }; 76 77 SolidFocusPainter::SolidFocusPainter(SkColor color, 78 const gfx::Insets& insets) 79 : color_(color), 80 insets_(insets) { 81 } 82 83 SolidFocusPainter::~SolidFocusPainter() { 84 } 85 86 gfx::Size SolidFocusPainter::GetMinimumSize() const { 87 return gfx::Size(); 88 } 89 90 void SolidFocusPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) { 91 gfx::Rect rect(size); 92 rect.Inset(insets_); 93 canvas->DrawSolidFocusRect(rect, color_); 94 } 95 96 // GradientPainter ------------------------------------------------------------ 97 98 class GradientPainter : public Painter { 99 public: 100 GradientPainter(bool horizontal, 101 SkColor* colors, 102 SkScalar* pos, 103 size_t count); 104 virtual ~GradientPainter(); 105 106 // Painter: 107 virtual gfx::Size GetMinimumSize() const OVERRIDE; 108 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE; 109 110 private: 111 // If |horizontal_| is true then the gradient is painted horizontally. 112 bool horizontal_; 113 // The gradient colors. 114 scoped_ptr<SkColor[]> colors_; 115 // The relative positions of the corresponding gradient colors. 116 scoped_ptr<SkScalar[]> pos_; 117 // The number of elements in |colors_| and |pos_|. 118 size_t count_; 119 120 DISALLOW_COPY_AND_ASSIGN(GradientPainter); 121 }; 122 123 GradientPainter::GradientPainter(bool horizontal, 124 SkColor* colors, 125 SkScalar* pos, 126 size_t count) 127 : horizontal_(horizontal), 128 colors_(new SkColor[count]), 129 pos_(new SkScalar[count]), 130 count_(count) { 131 for (size_t i = 0; i < count_; ++i) { 132 pos_[i] = pos[i]; 133 colors_[i] = colors[i]; 134 } 135 } 136 137 GradientPainter::~GradientPainter() { 138 } 139 140 gfx::Size GradientPainter::GetMinimumSize() const { 141 return gfx::Size(); 142 } 143 144 void GradientPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) { 145 SkPaint paint; 146 SkPoint p[2]; 147 p[0].iset(0, 0); 148 if (horizontal_) 149 p[1].iset(size.width(), 0); 150 else 151 p[1].iset(0, size.height()); 152 153 skia::RefPtr<SkShader> s = skia::AdoptRef(SkGradientShader::CreateLinear( 154 p, colors_.get(), pos_.get(), count_, SkShader::kClamp_TileMode)); 155 paint.setStyle(SkPaint::kFill_Style); 156 paint.setShader(s.get()); 157 158 canvas->sk_canvas()->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0), 159 SkIntToScalar(size.width()), 160 SkIntToScalar(size.height()), paint); 161 } 162 163 // ImagePainter --------------------------------------------------------------- 164 165 // ImagePainter stores and paints nine images as a scalable grid. 166 class VIEWS_EXPORT ImagePainter : public Painter { 167 public: 168 // Constructs an ImagePainter with the specified image resource ids. 169 // See CreateImageGridPainter()'s comment regarding image ID count and order. 170 explicit ImagePainter(const int image_ids[]); 171 172 // Constructs an ImagePainter with the specified image and insets. 173 ImagePainter(const gfx::ImageSkia& image, const gfx::Insets& insets); 174 175 virtual ~ImagePainter(); 176 177 // Painter: 178 virtual gfx::Size GetMinimumSize() const OVERRIDE; 179 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE; 180 181 private: 182 scoped_ptr<gfx::NineImagePainter> nine_painter_; 183 184 DISALLOW_COPY_AND_ASSIGN(ImagePainter); 185 }; 186 187 ImagePainter::ImagePainter(const int image_ids[]) 188 : nine_painter_(ui::CreateNineImagePainter(image_ids)) { 189 } 190 191 ImagePainter::ImagePainter(const gfx::ImageSkia& image, 192 const gfx::Insets& insets) 193 : nine_painter_(new gfx::NineImagePainter(image, insets)) { 194 } 195 196 ImagePainter::~ImagePainter() { 197 } 198 199 gfx::Size ImagePainter::GetMinimumSize() const { 200 return nine_painter_->GetMinimumSize(); 201 } 202 203 void ImagePainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) { 204 nine_painter_->Paint(canvas, gfx::Rect(size)); 205 } 206 207 } // namespace 208 209 210 // Painter -------------------------------------------------------------------- 211 212 Painter::Painter() { 213 } 214 215 Painter::~Painter() { 216 } 217 218 // static 219 void Painter::PaintPainterAt(gfx::Canvas* canvas, 220 Painter* painter, 221 const gfx::Rect& rect) { 222 DCHECK(canvas && painter); 223 canvas->Save(); 224 canvas->Translate(rect.OffsetFromOrigin()); 225 painter->Paint(canvas, rect.size()); 226 canvas->Restore(); 227 } 228 229 // static 230 void Painter::PaintFocusPainter(View* view, 231 gfx::Canvas* canvas, 232 Painter* focus_painter) { 233 if (focus_painter && view->HasFocus()) 234 PaintPainterAt(canvas, focus_painter, view->GetLocalBounds()); 235 } 236 237 // static 238 Painter* Painter::CreateHorizontalGradient(SkColor c1, SkColor c2) { 239 SkColor colors[2]; 240 colors[0] = c1; 241 colors[1] = c2; 242 SkScalar pos[] = {0, 1}; 243 return new GradientPainter(true, colors, pos, 2); 244 } 245 246 // static 247 Painter* Painter::CreateVerticalGradient(SkColor c1, SkColor c2) { 248 SkColor colors[2]; 249 colors[0] = c1; 250 colors[1] = c2; 251 SkScalar pos[] = {0, 1}; 252 return new GradientPainter(false, colors, pos, 2); 253 } 254 255 // static 256 Painter* Painter::CreateVerticalMultiColorGradient(SkColor* colors, 257 SkScalar* pos, 258 size_t count) { 259 return new GradientPainter(false, colors, pos, count); 260 } 261 262 // static 263 Painter* Painter::CreateImagePainter(const gfx::ImageSkia& image, 264 const gfx::Insets& insets) { 265 return new ImagePainter(image, insets); 266 } 267 268 // static 269 Painter* Painter::CreateImageGridPainter(const int image_ids[]) { 270 return new ImagePainter(image_ids); 271 } 272 273 // static 274 scoped_ptr<Painter> Painter::CreateDashedFocusPainter() { 275 return scoped_ptr<Painter>(new DashedFocusPainter(gfx::Insets())).Pass(); 276 } 277 278 // static 279 scoped_ptr<Painter> Painter::CreateDashedFocusPainterWithInsets( 280 const gfx::Insets& insets) { 281 return scoped_ptr<Painter>(new DashedFocusPainter(insets)).Pass(); 282 } 283 284 // static 285 scoped_ptr<Painter> Painter::CreateSolidFocusPainter( 286 SkColor color, 287 const gfx::Insets& insets) { 288 return scoped_ptr<Painter>(new SolidFocusPainter(color, insets)).Pass(); 289 } 290 291 // HorizontalPainter ---------------------------------------------------------- 292 293 HorizontalPainter::HorizontalPainter(const int image_resource_names[]) { 294 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 295 for (int i = 0; i < 3; ++i) 296 images_[i] = rb.GetImageNamed(image_resource_names[i]).ToImageSkia(); 297 DCHECK_EQ(images_[LEFT]->height(), images_[CENTER]->height()); 298 DCHECK_EQ(images_[LEFT]->height(), images_[RIGHT]->height()); 299 } 300 301 HorizontalPainter::~HorizontalPainter() { 302 } 303 304 gfx::Size HorizontalPainter::GetMinimumSize() const { 305 return gfx::Size( 306 images_[LEFT]->width() + images_[CENTER]->width() + 307 images_[RIGHT]->width(), images_[LEFT]->height()); 308 } 309 310 void HorizontalPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) { 311 if (size.width() < GetMinimumSize().width()) 312 return; // No room to paint. 313 314 canvas->DrawImageInt(*images_[LEFT], 0, 0); 315 canvas->DrawImageInt(*images_[RIGHT], size.width() - images_[RIGHT]->width(), 316 0); 317 canvas->TileImageInt( 318 *images_[CENTER], images_[LEFT]->width(), 0, 319 size.width() - images_[LEFT]->width() - images_[RIGHT]->width(), 320 images_[LEFT]->height()); 321 } 322 323 } // namespace views 324