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