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 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 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 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: 142 explicit RoundedRectPainter(const BorderDefinition* const border) 143 : border_(border) { 144 } 145 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: 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 173 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 178 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: 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 198 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 249 views::Painter* CreateWizardPainter(const BorderDefinition* const border) { 250 return new RoundedRectPainter(border); 251 } 252 253 views::Border* CreateWizardBorder(const BorderDefinition* const border) { 254 return new RoundedRectBorder(border); 255 } 256 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