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/menu/menu_image_util.h"
6
7#include "base/i18n/rtl.h"
8#include "base/logging.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/canvas_image_source.h"
13#include "ui/gfx/image/image.h"
14#include "ui/gfx/image/image_skia.h"
15#include "ui/gfx/image/image_skia_source.h"
16#include "ui/gfx/point.h"
17#include "ui/gfx/size.h"
18#include "ui/resources/grit/ui_resources.h"
19
20namespace {
21
22// Size of the radio button inciator.
23const int kSelectedIndicatorSize = 5;
24const int kIndicatorSize = 10;
25
26// Used for the radio indicator. See theme_draw for details.
27const double kGradientStop = .5;
28const SkColor kGradient0 = SkColorSetRGB(255, 255, 255);
29const SkColor kGradient1 = SkColorSetRGB(255, 255, 255);
30const SkColor kGradient2 = SkColorSetRGB(0xD8, 0xD8, 0xD8);
31const SkColor kBaseStroke = SkColorSetRGB(0x8F, 0x8F, 0x8F);
32const SkColor kRadioButtonIndicatorGradient0 = SkColorSetRGB(0, 0, 0);
33const SkColor kRadioButtonIndicatorGradient1 = SkColorSetRGB(0x83, 0x83, 0x83);
34const SkColor kIndicatorStroke = SkColorSetRGB(0, 0, 0);
35
36class RadioButtonImageSource : public gfx::CanvasImageSource {
37 public:
38  explicit RadioButtonImageSource(bool selected)
39      : CanvasImageSource(gfx::Size(kIndicatorSize + 2, kIndicatorSize + 2),
40                          false),
41        selected_(selected) {
42  }
43  virtual ~RadioButtonImageSource() {}
44
45  virtual void Draw(gfx::Canvas* canvas) OVERRIDE {
46    canvas->Translate(gfx::Vector2d(1, 1));
47
48    SkPoint gradient_points[3];
49    gradient_points[0].iset(0, 0);
50    gradient_points[1].iset(0,
51                            static_cast<int>(kIndicatorSize * kGradientStop));
52    gradient_points[2].iset(0, kIndicatorSize);
53    SkColor gradient_colors[3] = { kGradient0, kGradient1, kGradient2 };
54    skia::RefPtr<SkShader> shader = skia::AdoptRef(
55        SkGradientShader::CreateLinear(
56            gradient_points, gradient_colors, NULL, arraysize(gradient_points),
57            SkShader::kClamp_TileMode));
58    SkPaint paint;
59    paint.setStyle(SkPaint::kFill_Style);
60    paint.setAntiAlias(true);
61    paint.setShader(shader.get());
62    int radius = kIndicatorSize / 2;
63    canvas->sk_canvas()->drawCircle(radius, radius, radius, paint);
64    paint.setStrokeWidth(SkIntToScalar(0));
65    paint.setShader(NULL);
66    paint.setStyle(SkPaint::kStroke_Style);
67    paint.setColor(kBaseStroke);
68    canvas->sk_canvas()->drawCircle(radius, radius, radius, paint);
69
70    if (selected_) {
71      SkPoint selected_gradient_points[2];
72      selected_gradient_points[0].iset(0, 0);
73      selected_gradient_points[1].iset(0, kSelectedIndicatorSize);
74      SkColor selected_gradient_colors[2] = { kRadioButtonIndicatorGradient0,
75                                              kRadioButtonIndicatorGradient1 };
76      shader = skia::AdoptRef(
77          SkGradientShader::CreateLinear(
78              selected_gradient_points, selected_gradient_colors, NULL,
79              arraysize(selected_gradient_points), SkShader::kClamp_TileMode));
80      paint.setShader(shader.get());
81      paint.setStyle(SkPaint::kFill_Style);
82      canvas->sk_canvas()->drawCircle(radius, radius,
83                                      kSelectedIndicatorSize / 2, paint);
84
85      paint.setStrokeWidth(SkIntToScalar(0));
86      paint.setShader(NULL);
87      paint.setStyle(SkPaint::kStroke_Style);
88      paint.setColor(kIndicatorStroke);
89      canvas->sk_canvas()->drawCircle(radius, radius,
90                                      kSelectedIndicatorSize / 2, paint);
91    }
92  }
93
94 private:
95  bool selected_;
96
97  DISALLOW_COPY_AND_ASSIGN(RadioButtonImageSource);
98};
99
100class SubmenuArrowImageSource : public gfx::CanvasImageSource {
101 public:
102  SubmenuArrowImageSource(int image_id)
103      : gfx::CanvasImageSource(ui::ResourceBundle::GetSharedInstance().
104            GetImageNamed(image_id).ToImageSkia()->size(), false),
105        image_id_(image_id) {}
106  virtual ~SubmenuArrowImageSource() {}
107
108  virtual void Draw(gfx::Canvas* canvas) OVERRIDE {
109    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
110    const gfx::ImageSkia* r = rb.GetImageNamed(image_id_).ToImageSkia();
111    canvas->Scale(-1, 1);
112    canvas->DrawImageInt(*r, - r->width(), 0);
113  }
114
115 private:
116  static gfx::Size GetSubmenuArrowSize() {
117    return ui::ResourceBundle::GetSharedInstance()
118        .GetImageNamed(IDR_MENU_HIERARCHY_ARROW).ToImageSkia()->size();
119  }
120
121  int image_id_;
122
123  DISALLOW_COPY_AND_ASSIGN(SubmenuArrowImageSource);
124};
125
126gfx::ImageSkia GetRtlSubmenuArrowImage(bool rtl,
127                                       bool dark_background) {
128  int image_id = dark_background ? IDR_MENU_HIERARCHY_ARROW_DARK_BACKGROUND :
129                                   IDR_MENU_HIERARCHY_ARROW;
130
131  if (!rtl) {
132    return ui::ResourceBundle::GetSharedInstance().GetImageNamed(image_id).
133        AsImageSkia();
134  }
135
136  static gfx::ImageSkia* kRtlArrow = NULL;
137  static gfx::ImageSkia* kRtlArrowDarkBg = NULL;
138  gfx::ImageSkia** image = dark_background ? &kRtlArrowDarkBg : &kRtlArrow;
139
140  if (!*image) {
141    SubmenuArrowImageSource* source = new SubmenuArrowImageSource(image_id);
142    *image = new gfx::ImageSkia(source, source->size());
143  }
144
145  return **image;
146}
147
148}  // namespace
149
150namespace views {
151
152gfx::ImageSkia GetMenuCheckImage(bool dark_background) {
153  int image_id = dark_background ? IDR_MENU_CHECK_CHECKED_DARK_BACKGROUND :
154                                   IDR_MENU_CHECK_CHECKED;
155  return ui::ResourceBundle::GetSharedInstance().GetImageNamed(image_id).
156      AsImageSkia();
157}
158
159gfx::ImageSkia GetRadioButtonImage(bool selected) {
160  int image_id = selected ? IDR_MENU_RADIO_SELECTED : IDR_MENU_RADIO_EMPTY;
161  return ui::ResourceBundle::GetSharedInstance().GetImageNamed(image_id).
162      AsImageSkia();
163}
164
165gfx::ImageSkia GetSubmenuArrowImage(bool dark_background) {
166  return GetRtlSubmenuArrowImage(base::i18n::IsRTL(), dark_background);
167}
168
169}  // namespace views
170