// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/profiles/profile_info_util.h" #include "base/memory/scoped_ptr.h" #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkScalar.h" #include "third_party/skia/include/core/SkXfermode.h" #include "ui/gfx/canvas.h" #include "ui/gfx/image/canvas_image_source.h" #include "ui/gfx/image/image_skia_operations.h" namespace profiles { const int kAvatarIconWidth = 38; const int kAvatarIconHeight = 31; const int kAvatarIconPadding = 2; namespace internal { // A CanvasImageSource that draws a sized and positioned avatar with an // optional border independently of the scale factor. class AvatarImageSource : public gfx::CanvasImageSource { public: enum AvatarPosition { POSITION_CENTER, POSITION_BOTTOM_CENTER, }; enum AvatarBorder { BORDER_NONE, BORDER_NORMAL, BORDER_ETCHED, }; AvatarImageSource(gfx::ImageSkia avatar, const gfx::Size& canvas_size, int size, AvatarPosition position, AvatarBorder border); virtual ~AvatarImageSource(); // CanvasImageSource override: virtual void Draw(gfx::Canvas* canvas) OVERRIDE; private: gfx::ImageSkia avatar_; const gfx::Size canvas_size_; const int size_; const AvatarPosition position_; const AvatarBorder border_; DISALLOW_COPY_AND_ASSIGN(AvatarImageSource); }; AvatarImageSource::AvatarImageSource(gfx::ImageSkia avatar, const gfx::Size& canvas_size, int size, AvatarPosition position, AvatarBorder border) : gfx::CanvasImageSource(canvas_size, false), canvas_size_(canvas_size), size_(size - kAvatarIconPadding), position_(position), border_(border) { // Resize the avatar to the desired square size. avatar_ = gfx::ImageSkiaOperations::CreateResizedImage( avatar, skia::ImageOperations::RESIZE_BEST, gfx::Size(size_, size_)); } AvatarImageSource::~AvatarImageSource() { } void AvatarImageSource::Draw(gfx::Canvas* canvas) { // Center the avatar horizontally. int x = (canvas_size_.width() - size_) / 2; int y; if (position_ == POSITION_CENTER) { // Draw the avatar centered on the canvas. y = (canvas_size_.height() - size_) / 2; } else { // Draw the avatar on the bottom center of the canvas, leaving 1px below. y = canvas_size_.height() - size_ - 1; } canvas->DrawImageInt(avatar_, x, y); if (border_ == BORDER_NORMAL) { // Draw a gray border on the inside of the avatar. SkColor border_color = SkColorSetARGB(83, 0, 0, 0); // Offset the rectangle by a half pixel so the border is drawn within the // appropriate pixels no matter the scale factor. Subtract 1 from the right // and bottom sizes to specify the endpoints, yielding -0.5. SkPath path; path.addRect(SkFloatToScalar(x + 0.5f), // left SkFloatToScalar(y + 0.5f), // top SkFloatToScalar(x + size_ - 0.5f), // right SkFloatToScalar(y + size_ - 0.5f)); // bottom SkPaint paint; paint.setColor(border_color); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkIntToScalar(1)); canvas->DrawPath(path, paint); } else if (border_ == BORDER_ETCHED) { // Give the avatar an etched look by drawing a highlight on the bottom and // right edges. SkColor shadow_color = SkColorSetARGB(83, 0, 0, 0); SkColor highlight_color = SkColorSetARGB(96, 255, 255, 255); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkIntToScalar(1)); SkPath path; // Left and top shadows. To support higher scale factors than 1, position // the orthogonal dimension of each line on the half-pixel to separate the // pixel. For a vertical line, this means adding 0.5 to the x-value. path.moveTo(SkFloatToScalar(x + 0.5f), SkIntToScalar(y + size_)); // Draw up to the top-left. Stop with the y-value at a half-pixel. path.rLineTo(SkIntToScalar(0), SkFloatToScalar(-size_ + 0.5f)); // Draw right to the top-right, stopping within the last pixel. path.rLineTo(SkFloatToScalar(size_ - 0.5f), SkIntToScalar(0)); paint.setColor(shadow_color); canvas->DrawPath(path, paint); path.reset(); // Bottom and right highlights. Note that the shadows own the shared corner // pixels, so reduce the sizes accordingly. path.moveTo(SkIntToScalar(x + 1), SkFloatToScalar(y + size_ - 0.5f)); // Draw right to the bottom-right. path.rLineTo(SkFloatToScalar(size_ - 1.5f), SkIntToScalar(0)); // Draw up to the top-right. path.rLineTo(SkIntToScalar(0), SkFloatToScalar(-size_ + 1.5f)); paint.setColor(highlight_color); canvas->DrawPath(path, paint); } } } // namespace internal gfx::Image GetSizedAvatarIconWithBorder(const gfx::Image& image, bool is_rectangle, int width, int height) { if (!is_rectangle) return image; gfx::Size size(width, height); // Source for a centered, sized icon with a border. scoped_ptr<gfx::ImageSkiaSource> source( new internal::AvatarImageSource( *image.ToImageSkia(), size, std::min(width, height), internal::AvatarImageSource::POSITION_CENTER, internal::AvatarImageSource::BORDER_NORMAL)); return gfx::Image(gfx::ImageSkia(source.release(), size)); } gfx::Image GetAvatarIconForMenu(const gfx::Image& image, bool is_rectangle) { return GetSizedAvatarIconWithBorder( image, is_rectangle, kAvatarIconWidth, kAvatarIconHeight); } gfx::Image GetAvatarIconForWebUI(const gfx::Image& image, bool is_rectangle) { if (!is_rectangle) return image; gfx::Size size(kAvatarIconWidth, kAvatarIconHeight); // Source for a centered, sized icon. scoped_ptr<gfx::ImageSkiaSource> source( new internal::AvatarImageSource( *image.ToImageSkia(), size, std::min(kAvatarIconWidth, kAvatarIconHeight), internal::AvatarImageSource::POSITION_CENTER, internal::AvatarImageSource::BORDER_NONE)); return gfx::Image(gfx::ImageSkia(source.release(), size)); } gfx::Image GetAvatarIconForTitleBar(const gfx::Image& image, bool is_rectangle, int dst_width, int dst_height) { if (!is_rectangle) return image; int size = std::min(std::min(kAvatarIconWidth, kAvatarIconHeight), std::min(dst_width, dst_height)); gfx::Size dst_size(dst_width, dst_height); // Source for a sized icon drawn at the bottom center of the canvas, // with an etched border. scoped_ptr<gfx::ImageSkiaSource> source( new internal::AvatarImageSource( *image.ToImageSkia(), dst_size, size, internal::AvatarImageSource::POSITION_BOTTOM_CENTER, internal::AvatarImageSource::BORDER_ETCHED)); return gfx::Image(gfx::ImageSkia(source.release(), dst_size)); } } // namespace profiles