Home | History | Annotate | Download | only in login
      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