Home | History | Annotate | Download | only in profiles
      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 "chrome/browser/profiles/profile_info_util.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "third_party/skia/include/core/SkPaint.h"
      9 #include "third_party/skia/include/core/SkPath.h"
     10 #include "third_party/skia/include/core/SkScalar.h"
     11 #include "third_party/skia/include/core/SkXfermode.h"
     12 #include "ui/gfx/canvas.h"
     13 #include "ui/gfx/image/canvas_image_source.h"
     14 #include "ui/gfx/image/image_skia_operations.h"
     15 
     16 namespace profiles {
     17 
     18 const int kAvatarIconWidth = 38;
     19 const int kAvatarIconHeight = 31;
     20 const int kAvatarIconPadding = 2;
     21 
     22 namespace internal {
     23 
     24 // A CanvasImageSource that draws a sized and positioned avatar with an
     25 // optional border independently of the scale factor.
     26 class AvatarImageSource : public gfx::CanvasImageSource {
     27  public:
     28   enum AvatarPosition {
     29     POSITION_CENTER,
     30     POSITION_BOTTOM_CENTER,
     31   };
     32 
     33   enum AvatarBorder {
     34     BORDER_NONE,
     35     BORDER_NORMAL,
     36     BORDER_ETCHED,
     37   };
     38 
     39   AvatarImageSource(gfx::ImageSkia avatar,
     40                     const gfx::Size& canvas_size,
     41                     int size,
     42                     AvatarPosition position,
     43                     AvatarBorder border);
     44   virtual ~AvatarImageSource();
     45 
     46   // CanvasImageSource override:
     47   virtual void Draw(gfx::Canvas* canvas) OVERRIDE;
     48 
     49  private:
     50   gfx::ImageSkia avatar_;
     51   const gfx::Size canvas_size_;
     52   const int size_;
     53   const AvatarPosition position_;
     54   const AvatarBorder border_;
     55 
     56   DISALLOW_COPY_AND_ASSIGN(AvatarImageSource);
     57 };
     58 
     59 AvatarImageSource::AvatarImageSource(gfx::ImageSkia avatar,
     60                                      const gfx::Size& canvas_size,
     61                                      int size,
     62                                      AvatarPosition position,
     63                                      AvatarBorder border)
     64     : gfx::CanvasImageSource(canvas_size, false),
     65       canvas_size_(canvas_size),
     66       size_(size - kAvatarIconPadding),
     67       position_(position),
     68       border_(border) {
     69   // Resize the avatar to the desired square size.
     70   avatar_ = gfx::ImageSkiaOperations::CreateResizedImage(
     71       avatar, skia::ImageOperations::RESIZE_BEST, gfx::Size(size_, size_));
     72 }
     73 
     74 AvatarImageSource::~AvatarImageSource() {
     75 }
     76 
     77 void AvatarImageSource::Draw(gfx::Canvas* canvas) {
     78   // Center the avatar horizontally.
     79   int x = (canvas_size_.width() - size_) / 2;
     80   int y;
     81 
     82   if (position_ == POSITION_CENTER) {
     83     // Draw the avatar centered on the canvas.
     84     y = (canvas_size_.height() - size_) / 2;
     85   } else {
     86     // Draw the avatar on the bottom center of the canvas, leaving 1px below.
     87     y = canvas_size_.height() - size_ - 1;
     88   }
     89 
     90   canvas->DrawImageInt(avatar_, x, y);
     91 
     92   if (border_ == BORDER_NORMAL) {
     93     // Draw a gray border on the inside of the avatar.
     94     SkColor border_color = SkColorSetARGB(83, 0, 0, 0);
     95 
     96     // Offset the rectangle by a half pixel so the border is drawn within the
     97     // appropriate pixels no matter the scale factor. Subtract 1 from the right
     98     // and bottom sizes to specify the endpoints, yielding -0.5.
     99     SkPath path;
    100     path.addRect(SkFloatToScalar(x + 0.5f),  // left
    101                  SkFloatToScalar(y + 0.5f),  // top
    102                  SkFloatToScalar(x + size_ - 0.5f),   // right
    103                  SkFloatToScalar(y + size_ - 0.5f));  // bottom
    104 
    105     SkPaint paint;
    106     paint.setColor(border_color);
    107     paint.setStyle(SkPaint::kStroke_Style);
    108     paint.setStrokeWidth(SkIntToScalar(1));
    109 
    110     canvas->DrawPath(path, paint);
    111   } else if (border_ == BORDER_ETCHED) {
    112     // Give the avatar an etched look by drawing a highlight on the bottom and
    113     // right edges.
    114     SkColor shadow_color = SkColorSetARGB(83, 0, 0, 0);
    115     SkColor highlight_color = SkColorSetARGB(96, 255, 255, 255);
    116 
    117     SkPaint paint;
    118     paint.setStyle(SkPaint::kStroke_Style);
    119     paint.setStrokeWidth(SkIntToScalar(1));
    120 
    121     SkPath path;
    122 
    123     // Left and top shadows. To support higher scale factors than 1, position
    124     // the orthogonal dimension of each line on the half-pixel to separate the
    125     // pixel. For a vertical line, this means adding 0.5 to the x-value.
    126     path.moveTo(SkFloatToScalar(x + 0.5f), SkIntToScalar(y + size_));
    127 
    128     // Draw up to the top-left. Stop with the y-value at a half-pixel.
    129     path.rLineTo(SkIntToScalar(0), SkFloatToScalar(-size_ + 0.5f));
    130 
    131     // Draw right to the top-right, stopping within the last pixel.
    132     path.rLineTo(SkFloatToScalar(size_ - 0.5f), SkIntToScalar(0));
    133 
    134     paint.setColor(shadow_color);
    135     canvas->DrawPath(path, paint);
    136 
    137     path.reset();
    138 
    139     // Bottom and right highlights. Note that the shadows own the shared corner
    140     // pixels, so reduce the sizes accordingly.
    141     path.moveTo(SkIntToScalar(x + 1), SkFloatToScalar(y + size_ - 0.5f));
    142 
    143     // Draw right to the bottom-right.
    144     path.rLineTo(SkFloatToScalar(size_ - 1.5f), SkIntToScalar(0));
    145 
    146     // Draw up to the top-right.
    147     path.rLineTo(SkIntToScalar(0), SkFloatToScalar(-size_ + 1.5f));
    148 
    149     paint.setColor(highlight_color);
    150     canvas->DrawPath(path, paint);
    151   }
    152 }
    153 
    154 }  // namespace internal
    155 
    156 gfx::Image GetSizedAvatarIconWithBorder(const gfx::Image& image,
    157                                         bool is_rectangle,
    158                                         int width, int height) {
    159   if (!is_rectangle)
    160     return image;
    161 
    162   gfx::Size size(width, height);
    163 
    164   // Source for a centered, sized icon with a border.
    165   scoped_ptr<gfx::ImageSkiaSource> source(
    166       new internal::AvatarImageSource(
    167           *image.ToImageSkia(),
    168           size,
    169           std::min(width, height),
    170           internal::AvatarImageSource::POSITION_CENTER,
    171           internal::AvatarImageSource::BORDER_NORMAL));
    172 
    173   return gfx::Image(gfx::ImageSkia(source.release(), size));
    174 }
    175 
    176 gfx::Image GetAvatarIconForMenu(const gfx::Image& image,
    177                                 bool is_rectangle) {
    178   return GetSizedAvatarIconWithBorder(
    179       image, is_rectangle, kAvatarIconWidth, kAvatarIconHeight);
    180 }
    181 
    182 gfx::Image GetAvatarIconForWebUI(const gfx::Image& image,
    183                                  bool is_rectangle) {
    184   if (!is_rectangle)
    185     return image;
    186 
    187   gfx::Size size(kAvatarIconWidth, kAvatarIconHeight);
    188 
    189   // Source for a centered, sized icon.
    190   scoped_ptr<gfx::ImageSkiaSource> source(
    191       new internal::AvatarImageSource(
    192           *image.ToImageSkia(),
    193           size,
    194           std::min(kAvatarIconWidth, kAvatarIconHeight),
    195           internal::AvatarImageSource::POSITION_CENTER,
    196           internal::AvatarImageSource::BORDER_NONE));
    197 
    198   return gfx::Image(gfx::ImageSkia(source.release(), size));
    199 }
    200 
    201 gfx::Image GetAvatarIconForTitleBar(const gfx::Image& image,
    202                                     bool is_rectangle,
    203                                     int dst_width,
    204                                     int dst_height) {
    205   if (!is_rectangle)
    206     return image;
    207 
    208   int size = std::min(std::min(kAvatarIconWidth, kAvatarIconHeight),
    209                       std::min(dst_width, dst_height));
    210   gfx::Size dst_size(dst_width, dst_height);
    211 
    212   // Source for a sized icon drawn at the bottom center of the canvas,
    213   // with an etched border.
    214   scoped_ptr<gfx::ImageSkiaSource> source(
    215       new internal::AvatarImageSource(
    216           *image.ToImageSkia(),
    217           dst_size,
    218           size,
    219           internal::AvatarImageSource::POSITION_BOTTOM_CENTER,
    220           internal::AvatarImageSource::BORDER_ETCHED));
    221 
    222   return gfx::Image(gfx::ImageSkia(source.release(), dst_size));
    223 }
    224 
    225 }  // namespace profiles
    226