普通文本  |  266行  |  8.08 KB

// Copyright (c) 2010 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/chromeos/login/rounded_rect_painter.h"

#include "base/logging.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/gfx/canvas_skia.h"
#include "views/border.h"
#include "views/painter.h"

namespace chromeos {

namespace {

const SkColor kScreenTopColor = SkColorSetRGB(250, 251, 251);
const SkColor kScreenBottomColor = SkColorSetRGB(204, 209, 212);
const SkColor kScreenShadowColor = SkColorSetARGB(64, 34, 54, 115);
const SkColor kShadowStrokeColor = 0;
const int kScreenShadow = 10;

static void DrawRoundedRect(
      gfx::Canvas* canvas,
      int x, int y,
      int w, int h,
      int corner_radius,
      SkColor top_color, SkColor bottom_color,
      SkColor stroke_color) {
  SkRect rect;
  rect.set(
      SkIntToScalar(x), SkIntToScalar(y),
      SkIntToScalar(x + w), SkIntToScalar(y + h));
  SkPath path;
  path.addRoundRect(
      rect, SkIntToScalar(corner_radius), SkIntToScalar(corner_radius));
  SkPaint paint;
  paint.setStyle(SkPaint::kFill_Style);
  paint.setFlags(SkPaint::kAntiAlias_Flag);
  if (top_color != bottom_color) {
    SkPoint p[2];
    p[0].set(SkIntToScalar(x), SkIntToScalar(y));
    p[1].set(SkIntToScalar(x), SkIntToScalar(y + h));
    SkColor colors[2] = { top_color, bottom_color };
    SkShader* s =
        SkGradientShader::CreateLinear(p, colors, NULL, 2,
                                       SkShader::kClamp_TileMode, NULL);
    paint.setShader(s);
    // Need to unref shader, otherwise never deleted.
    s->unref();
  } else {
    paint.setColor(top_color);
  }
  canvas->AsCanvasSkia()->drawPath(path, paint);

  if (stroke_color != 0) {
    // Expand rect by 0.5px so resulting stroke will take the whole pixel.
    rect.set(
        SkIntToScalar(x) - SK_ScalarHalf,
        SkIntToScalar(y) - SK_ScalarHalf,
        SkIntToScalar(x + w) + SK_ScalarHalf,
        SkIntToScalar(y + h) + SK_ScalarHalf);
    paint.setShader(NULL);
    paint.setStyle(SkPaint::kStroke_Style);
    paint.setStrokeWidth(SkIntToScalar(SK_Scalar1));
    paint.setColor(stroke_color);
    canvas->AsCanvasSkia()->drawRoundRect(
      rect,
      SkIntToScalar(corner_radius), SkIntToScalar(corner_radius),
      paint);
  }
}

static void DrawRoundedRectShadow(
    gfx::Canvas* canvas,
    int x, int y,
    int w, int h,
    int corner_radius,
    int shadow,
    SkColor color) {
  SkPaint paint;
  paint.setFlags(SkPaint::kAntiAlias_Flag);
  paint.setStyle(SkPaint::kFill_Style);
  paint.setColor(color);
  SkMaskFilter* filter = SkBlurMaskFilter::Create(
      shadow / 2, SkBlurMaskFilter::kNormal_BlurStyle);
  paint.setMaskFilter(filter)->unref();
  SkRect rect;
  rect.set(
      SkIntToScalar(x + shadow / 2), SkIntToScalar(y + shadow / 2),
      SkIntToScalar(x + w - shadow / 2), SkIntToScalar(y + h - shadow / 2));
  canvas->AsCanvasSkia()->drawRoundRect(
      rect,
      SkIntToScalar(corner_radius), SkIntToScalar(corner_radius),
      paint);
  paint.setMaskFilter(NULL);
}

static void DrawRectWithBorder(int w,
                               int h,
                               const BorderDefinition* const border,
                               gfx::Canvas* canvas) {
  int padding = border->padding;
  SkColor padding_color = border->padding_color;
  int shadow = border->shadow;
  SkColor shadow_color = border->shadow_color;
  int corner_radius = border->corner_radius;
  SkColor top_color = border->top_color;
  SkColor bottom_color = border->bottom_color;
  if (padding > 0) {
    SkPaint paint;
    paint.setColor(padding_color);
    canvas->AsCanvasSkia()->drawRectCoords(
        SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(w), SkIntToScalar(h),
        paint);
  }
  if (border->shadow > 0) {
    DrawRoundedRectShadow(
        canvas,
        padding, padding,
        w - 2 * padding, h - 2 * padding,
        corner_radius,
        shadow, shadow_color);
  }
  DrawRoundedRect(
        canvas,
        padding + shadow,
        padding + shadow - shadow / 3,
        w - 2 * padding - 2 * shadow,
        h - 2 * padding - 2 * shadow,
        corner_radius,
        top_color, bottom_color,
        shadow ? kShadowStrokeColor : 0);
}

// This Painter can be used to draw a background consistent cross all login
// screens. It draws a rect with padding, shadow and rounded corners.
class RoundedRectPainter : public views::Painter {
 public:
  explicit RoundedRectPainter(const BorderDefinition* const border)
      : border_(border) {
  }

  virtual void Paint(int w, int h, gfx::Canvas* canvas) {
    DrawRectWithBorder(w, h, border_, canvas);
  }

 private:
  const BorderDefinition* const border_;

  DISALLOW_COPY_AND_ASSIGN(RoundedRectPainter);
};

// This border can be used to draw shadow and rounded corners across all
// login screens.
class RoundedRectBorder : public views::Border {
 public:
  explicit RoundedRectBorder(const BorderDefinition* const border)
      : border_(border) {
  }

  virtual void Paint(const views::View& view, gfx::Canvas* canvas) const;
  virtual void GetInsets(gfx::Insets* insets) const;

 private:
  const BorderDefinition* const border_;

  DISALLOW_COPY_AND_ASSIGN(RoundedRectBorder);
};

void RoundedRectBorder::Paint(const views::View& view,
                              gfx::Canvas* canvas) const {
  // Don't paint anything. RoundedRectBorder is used to provide insets only.
}

void RoundedRectBorder::GetInsets(gfx::Insets* insets) const {
  DCHECK(insets);
  int shadow = border_->shadow;
  int inset = border_->corner_radius / 2 + border_->padding + shadow;
  insets->Set(inset - shadow / 3, inset, inset + shadow / 3, inset);
}

// Simple solid round background.
class RoundedBackground : public views::Background {
 public:
  explicit RoundedBackground(int corner_radius,
                             int stroke_width,
                             const SkColor& background_color,
                             const SkColor& stroke_color)
      : corner_radius_(corner_radius),
        stroke_width_(stroke_width),
        stroke_color_(stroke_color) {
    SetNativeControlColor(background_color);
  }

  virtual void Paint(gfx::Canvas* canvas, views::View* view) const {
    SkRect rect;
    rect.iset(0, 0, view->width(), view->height());
    SkPath path;
    path.addRoundRect(rect,
                      SkIntToScalar(corner_radius_),
                      SkIntToScalar(corner_radius_));
    // Draw interior.
    SkPaint paint;
    paint.setStyle(SkPaint::kFill_Style);
    paint.setFlags(SkPaint::kAntiAlias_Flag);
    paint.setColor(get_color());
    canvas->AsCanvasSkia()->drawPath(path, paint);
    // Redraw boundary region with correspoinding color.
    paint.setStyle(SkPaint::kStroke_Style);
    paint.setStrokeWidth(SkIntToScalar(stroke_width_));
    paint.setColor(stroke_color_);
    canvas->AsCanvasSkia()->drawPath(path, paint);
  }

 private:
  int corner_radius_;
  int stroke_width_;
  SkColor stroke_color_;

  DISALLOW_COPY_AND_ASSIGN(RoundedBackground);
};

}  // namespace

// static
const BorderDefinition BorderDefinition::kScreenBorder = {
  0,
  SK_ColorBLACK,
  kScreenShadow,
  kScreenShadowColor,
  login::kScreenCornerRadius,
  kScreenTopColor,
  kScreenBottomColor
};

const BorderDefinition BorderDefinition::kUserBorder = {
  0,
  SK_ColorBLACK,
  0,
  kScreenShadowColor,
  login::kUserCornerRadius,
  kScreenTopColor,
  kScreenBottomColor
};

views::Painter* CreateWizardPainter(const BorderDefinition* const border) {
  return new RoundedRectPainter(border);
}

views::Border* CreateWizardBorder(const BorderDefinition* const border) {
  return new RoundedRectBorder(border);
}

views::Background* CreateRoundedBackground(int corner_radius,
                                           int stroke_width,
                                           SkColor background_color,
                                           SkColor stroke_color) {
  return new RoundedBackground(
      corner_radius, stroke_width, background_color, stroke_color);
}

}  // namespace chromeos