1 // Copyright (c) 2010 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 "chrome/browser/chromeos/login/rounded_rect_painter.h"
6
7 #include "base/logging.h"
8 #include "chrome/browser/chromeos/login/helper.h"
9 #include "third_party/skia/include/effects/SkBlurMaskFilter.h"
10 #include "third_party/skia/include/effects/SkGradientShader.h"
11 #include "ui/gfx/canvas_skia.h"
12 #include "views/border.h"
13 #include "views/painter.h"
14
15 namespace chromeos {
16
17 namespace {
18
19 const SkColor kScreenTopColor = SkColorSetRGB(250, 251, 251);
20 const SkColor kScreenBottomColor = SkColorSetRGB(204, 209, 212);
21 const SkColor kScreenShadowColor = SkColorSetARGB(64, 34, 54, 115);
22 const SkColor kShadowStrokeColor = 0;
23 const int kScreenShadow = 10;
24
DrawRoundedRect(gfx::Canvas * canvas,int x,int y,int w,int h,int corner_radius,SkColor top_color,SkColor bottom_color,SkColor stroke_color)25 static void DrawRoundedRect(
26 gfx::Canvas* canvas,
27 int x, int y,
28 int w, int h,
29 int corner_radius,
30 SkColor top_color, SkColor bottom_color,
31 SkColor stroke_color) {
32 SkRect rect;
33 rect.set(
34 SkIntToScalar(x), SkIntToScalar(y),
35 SkIntToScalar(x + w), SkIntToScalar(y + h));
36 SkPath path;
37 path.addRoundRect(
38 rect, SkIntToScalar(corner_radius), SkIntToScalar(corner_radius));
39 SkPaint paint;
40 paint.setStyle(SkPaint::kFill_Style);
41 paint.setFlags(SkPaint::kAntiAlias_Flag);
42 if (top_color != bottom_color) {
43 SkPoint p[2];
44 p[0].set(SkIntToScalar(x), SkIntToScalar(y));
45 p[1].set(SkIntToScalar(x), SkIntToScalar(y + h));
46 SkColor colors[2] = { top_color, bottom_color };
47 SkShader* s =
48 SkGradientShader::CreateLinear(p, colors, NULL, 2,
49 SkShader::kClamp_TileMode, NULL);
50 paint.setShader(s);
51 // Need to unref shader, otherwise never deleted.
52 s->unref();
53 } else {
54 paint.setColor(top_color);
55 }
56 canvas->AsCanvasSkia()->drawPath(path, paint);
57
58 if (stroke_color != 0) {
59 // Expand rect by 0.5px so resulting stroke will take the whole pixel.
60 rect.set(
61 SkIntToScalar(x) - SK_ScalarHalf,
62 SkIntToScalar(y) - SK_ScalarHalf,
63 SkIntToScalar(x + w) + SK_ScalarHalf,
64 SkIntToScalar(y + h) + SK_ScalarHalf);
65 paint.setShader(NULL);
66 paint.setStyle(SkPaint::kStroke_Style);
67 paint.setStrokeWidth(SkIntToScalar(SK_Scalar1));
68 paint.setColor(stroke_color);
69 canvas->AsCanvasSkia()->drawRoundRect(
70 rect,
71 SkIntToScalar(corner_radius), SkIntToScalar(corner_radius),
72 paint);
73 }
74 }
75
DrawRoundedRectShadow(gfx::Canvas * canvas,int x,int y,int w,int h,int corner_radius,int shadow,SkColor color)76 static void DrawRoundedRectShadow(
77 gfx::Canvas* canvas,
78 int x, int y,
79 int w, int h,
80 int corner_radius,
81 int shadow,
82 SkColor color) {
83 SkPaint paint;
84 paint.setFlags(SkPaint::kAntiAlias_Flag);
85 paint.setStyle(SkPaint::kFill_Style);
86 paint.setColor(color);
87 SkMaskFilter* filter = SkBlurMaskFilter::Create(
88 shadow / 2, SkBlurMaskFilter::kNormal_BlurStyle);
89 paint.setMaskFilter(filter)->unref();
90 SkRect rect;
91 rect.set(
92 SkIntToScalar(x + shadow / 2), SkIntToScalar(y + shadow / 2),
93 SkIntToScalar(x + w - shadow / 2), SkIntToScalar(y + h - shadow / 2));
94 canvas->AsCanvasSkia()->drawRoundRect(
95 rect,
96 SkIntToScalar(corner_radius), SkIntToScalar(corner_radius),
97 paint);
98 paint.setMaskFilter(NULL);
99 }
100
DrawRectWithBorder(int w,int h,const BorderDefinition * const border,gfx::Canvas * canvas)101 static void DrawRectWithBorder(int w,
102 int h,
103 const BorderDefinition* const border,
104 gfx::Canvas* canvas) {
105 int padding = border->padding;
106 SkColor padding_color = border->padding_color;
107 int shadow = border->shadow;
108 SkColor shadow_color = border->shadow_color;
109 int corner_radius = border->corner_radius;
110 SkColor top_color = border->top_color;
111 SkColor bottom_color = border->bottom_color;
112 if (padding > 0) {
113 SkPaint paint;
114 paint.setColor(padding_color);
115 canvas->AsCanvasSkia()->drawRectCoords(
116 SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(w), SkIntToScalar(h),
117 paint);
118 }
119 if (border->shadow > 0) {
120 DrawRoundedRectShadow(
121 canvas,
122 padding, padding,
123 w - 2 * padding, h - 2 * padding,
124 corner_radius,
125 shadow, shadow_color);
126 }
127 DrawRoundedRect(
128 canvas,
129 padding + shadow,
130 padding + shadow - shadow / 3,
131 w - 2 * padding - 2 * shadow,
132 h - 2 * padding - 2 * shadow,
133 corner_radius,
134 top_color, bottom_color,
135 shadow ? kShadowStrokeColor : 0);
136 }
137
138 // This Painter can be used to draw a background consistent cross all login
139 // screens. It draws a rect with padding, shadow and rounded corners.
140 class RoundedRectPainter : public views::Painter {
141 public:
RoundedRectPainter(const BorderDefinition * const border)142 explicit RoundedRectPainter(const BorderDefinition* const border)
143 : border_(border) {
144 }
145
Paint(int w,int h,gfx::Canvas * canvas)146 virtual void Paint(int w, int h, gfx::Canvas* canvas) {
147 DrawRectWithBorder(w, h, border_, canvas);
148 }
149
150 private:
151 const BorderDefinition* const border_;
152
153 DISALLOW_COPY_AND_ASSIGN(RoundedRectPainter);
154 };
155
156 // This border can be used to draw shadow and rounded corners across all
157 // login screens.
158 class RoundedRectBorder : public views::Border {
159 public:
RoundedRectBorder(const BorderDefinition * const border)160 explicit RoundedRectBorder(const BorderDefinition* const border)
161 : border_(border) {
162 }
163
164 virtual void Paint(const views::View& view, gfx::Canvas* canvas) const;
165 virtual void GetInsets(gfx::Insets* insets) const;
166
167 private:
168 const BorderDefinition* const border_;
169
170 DISALLOW_COPY_AND_ASSIGN(RoundedRectBorder);
171 };
172
Paint(const views::View & view,gfx::Canvas * canvas) const173 void RoundedRectBorder::Paint(const views::View& view,
174 gfx::Canvas* canvas) const {
175 // Don't paint anything. RoundedRectBorder is used to provide insets only.
176 }
177
GetInsets(gfx::Insets * insets) const178 void RoundedRectBorder::GetInsets(gfx::Insets* insets) const {
179 DCHECK(insets);
180 int shadow = border_->shadow;
181 int inset = border_->corner_radius / 2 + border_->padding + shadow;
182 insets->Set(inset - shadow / 3, inset, inset + shadow / 3, inset);
183 }
184
185 // Simple solid round background.
186 class RoundedBackground : public views::Background {
187 public:
RoundedBackground(int corner_radius,int stroke_width,const SkColor & background_color,const SkColor & stroke_color)188 explicit RoundedBackground(int corner_radius,
189 int stroke_width,
190 const SkColor& background_color,
191 const SkColor& stroke_color)
192 : corner_radius_(corner_radius),
193 stroke_width_(stroke_width),
194 stroke_color_(stroke_color) {
195 SetNativeControlColor(background_color);
196 }
197
Paint(gfx::Canvas * canvas,views::View * view) const198 virtual void Paint(gfx::Canvas* canvas, views::View* view) const {
199 SkRect rect;
200 rect.iset(0, 0, view->width(), view->height());
201 SkPath path;
202 path.addRoundRect(rect,
203 SkIntToScalar(corner_radius_),
204 SkIntToScalar(corner_radius_));
205 // Draw interior.
206 SkPaint paint;
207 paint.setStyle(SkPaint::kFill_Style);
208 paint.setFlags(SkPaint::kAntiAlias_Flag);
209 paint.setColor(get_color());
210 canvas->AsCanvasSkia()->drawPath(path, paint);
211 // Redraw boundary region with correspoinding color.
212 paint.setStyle(SkPaint::kStroke_Style);
213 paint.setStrokeWidth(SkIntToScalar(stroke_width_));
214 paint.setColor(stroke_color_);
215 canvas->AsCanvasSkia()->drawPath(path, paint);
216 }
217
218 private:
219 int corner_radius_;
220 int stroke_width_;
221 SkColor stroke_color_;
222
223 DISALLOW_COPY_AND_ASSIGN(RoundedBackground);
224 };
225
226 } // namespace
227
228 // static
229 const BorderDefinition BorderDefinition::kScreenBorder = {
230 0,
231 SK_ColorBLACK,
232 kScreenShadow,
233 kScreenShadowColor,
234 login::kScreenCornerRadius,
235 kScreenTopColor,
236 kScreenBottomColor
237 };
238
239 const BorderDefinition BorderDefinition::kUserBorder = {
240 0,
241 SK_ColorBLACK,
242 0,
243 kScreenShadowColor,
244 login::kUserCornerRadius,
245 kScreenTopColor,
246 kScreenBottomColor
247 };
248
CreateWizardPainter(const BorderDefinition * const border)249 views::Painter* CreateWizardPainter(const BorderDefinition* const border) {
250 return new RoundedRectPainter(border);
251 }
252
CreateWizardBorder(const BorderDefinition * const border)253 views::Border* CreateWizardBorder(const BorderDefinition* const border) {
254 return new RoundedRectBorder(border);
255 }
256
CreateRoundedBackground(int corner_radius,int stroke_width,SkColor background_color,SkColor stroke_color)257 views::Background* CreateRoundedBackground(int corner_radius,
258 int stroke_width,
259 SkColor background_color,
260 SkColor stroke_color) {
261 return new RoundedBackground(
262 corner_radius, stroke_width, background_color, stroke_color);
263 }
264
265 } // namespace chromeos
266