Commit 0bd5f0cb authored by estade's avatar estade Committed by Commit bot

Implement Harmony spec for dialog/bubble border aesthetics.

Uses drawing commands rather than raster assets.

This CL tries to retain/reuse the same positioning logic that already exists, but I didn't attempt to correct any bugs in positioning that might be introduced. That's up next.

BUG=635170

Review-Url: https://codereview.chromium.org/2343913003
Cr-Commit-Position: refs/heads/master@{#419203}
parent 50afd4c0
...@@ -7,12 +7,15 @@ ...@@ -7,12 +7,15 @@
#include <algorithm> #include <algorithm>
#include "base/logging.h" #include "base/logging.h"
#include "third_party/skia/include/core/SkDrawLooper.h"
#include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkPath.h"
#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/gfx/path.h" #include "ui/gfx/path.h"
#include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/skia_util.h" #include "ui/gfx/skia_util.h"
#include "ui/resources/grit/ui_resources.h" #include "ui/resources/grit/ui_resources.h"
#include "ui/views/painter.h" #include "ui/views/painter.h"
...@@ -57,6 +60,20 @@ BorderImages::~BorderImages() {} ...@@ -57,6 +60,20 @@ BorderImages::~BorderImages() {}
namespace { namespace {
// Blur and offset values for the two shadows drawn around each dialog. The
// values are all in dip.
const int kSmallShadowVerticalOffset = 2;
const int kSmallShadowBlur = 4;
const SkColor kSmallShadowColor = SkColorSetA(SK_ColorBLACK, 0x33);
const int kLargeShadowVerticalOffset = 2;
const int kLargeShadowBlur = 6;
const SkColor kLargeShadowColor = SkColorSetA(SK_ColorBLACK, 0x1A);
bool UseMd() {
return ui::MaterialDesignController::IsSecondaryUiMaterial();
}
// Bubble border and arrow image resource ids. They don't use the IMAGE_GRID // Bubble border and arrow image resource ids. They don't use the IMAGE_GRID
// macro because there is no center image. // macro because there is no center image.
const int kNoShadowImages[] = { const int kNoShadowImages[] = {
...@@ -143,6 +160,7 @@ BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color) ...@@ -143,6 +160,7 @@ BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color)
arrow_paint_type_(PAINT_NORMAL), arrow_paint_type_(PAINT_NORMAL),
alignment_(ALIGN_ARROW_TO_MID_ANCHOR), alignment_(ALIGN_ARROW_TO_MID_ANCHOR),
shadow_(shadow), shadow_(shadow),
images_(nullptr),
background_color_(color), background_color_(color),
use_theme_background_color_(false) { use_theme_background_color_(false) {
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
...@@ -151,11 +169,23 @@ BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color) ...@@ -151,11 +169,23 @@ BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color)
shadow_ = NO_ASSETS; shadow_ = NO_ASSETS;
#endif // OS_MACOSX #endif // OS_MACOSX
DCHECK(shadow_ < SHADOW_COUNT); DCHECK(shadow_ < SHADOW_COUNT);
images_ = GetBorderImages(shadow_); if (UseMd()) {
// Harmony bubbles don't use arrows.
alignment_ = ALIGN_EDGE_TO_ANCHOR_EDGE;
arrow_paint_type_ = PAINT_NONE;
} else {
images_ = GetBorderImages(shadow_);
}
} }
BubbleBorder::~BubbleBorder() {} BubbleBorder::~BubbleBorder() {}
void BubbleBorder::set_paint_arrow(ArrowPaintType value) {
if (UseMd())
return;
arrow_paint_type_ = value;
}
gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect, gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
const gfx::Size& contents_size) const { const gfx::Size& contents_size) const {
int x = anchor_rect.x(); int x = anchor_rect.x();
...@@ -166,7 +196,7 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect, ...@@ -166,7 +196,7 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
const int arrow_offset = GetArrowOffset(size); const int arrow_offset = GetArrowOffset(size);
// |arrow_shift| is necessary to visually align the tip of the bubble arrow // |arrow_shift| is necessary to visually align the tip of the bubble arrow
// with the anchor point. This shift is an inverse of the shadow thickness. // with the anchor point. This shift is an inverse of the shadow thickness.
int arrow_shift = int arrow_shift = UseMd() ? 0 :
images_->arrow_interior_thickness + kStroke - images_->arrow_thickness; images_->arrow_interior_thickness + kStroke - images_->arrow_thickness;
// When arrow is painted transparently the visible border of the bubble needs // When arrow is painted transparently the visible border of the bubble needs
// to be positioned at the same bounds as when the arrow is shown. // to be positioned at the same bounds as when the arrow is shown.
...@@ -206,14 +236,20 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect, ...@@ -206,14 +236,20 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
} }
int BubbleBorder::GetBorderThickness() const { int BubbleBorder::GetBorderThickness() const {
return images_->border_thickness - images_->border_interior_thickness; // TODO(estade): this shouldn't be called in MD.
return UseMd()
? 0
: images_->border_thickness - images_->border_interior_thickness;
} }
int BubbleBorder::GetBorderCornerRadius() const { int BubbleBorder::GetBorderCornerRadius() const {
return images_->corner_radius; return UseMd() ? 3 : images_->corner_radius;
} }
int BubbleBorder::GetArrowOffset(const gfx::Size& border_size) const { int BubbleBorder::GetArrowOffset(const gfx::Size& border_size) const {
if (UseMd())
return 0;
const int edge_length = is_arrow_on_horizontal(arrow_) ? const int edge_length = is_arrow_on_horizontal(arrow_) ?
border_size.width() : border_size.height(); border_size.width() : border_size.height();
if (is_arrow_at_center(arrow_) && arrow_offset_ == 0) if (is_arrow_at_center(arrow_) && arrow_offset_ == 0)
...@@ -241,6 +277,9 @@ void BubbleBorder::SetBorderInteriorThickness(int border_interior_thickness) { ...@@ -241,6 +277,9 @@ void BubbleBorder::SetBorderInteriorThickness(int border_interior_thickness) {
} }
void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) { void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
if (UseMd())
return PaintMd(view, canvas);
gfx::Rect bounds(view.GetContentsBounds()); gfx::Rect bounds(view.GetContentsBounds());
bounds.Inset(-GetBorderThickness(), -GetBorderThickness()); bounds.Inset(-GetBorderThickness(), -GetBorderThickness());
const gfx::Rect arrow_bounds = GetArrowRect(view.GetLocalBounds()); const gfx::Rect arrow_bounds = GetArrowRect(view.GetLocalBounds());
...@@ -264,6 +303,13 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) { ...@@ -264,6 +303,13 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
} }
gfx::Insets BubbleBorder::GetInsets() const { gfx::Insets BubbleBorder::GetInsets() const {
if (UseMd()) {
gfx::Insets blur(kLargeShadowBlur);
gfx::Insets offset(-kLargeShadowVerticalOffset, 0,
kLargeShadowVerticalOffset, 0);
return blur + offset;
}
// The insets contain the stroke and shadow pixels outside the bubble fill. // The insets contain the stroke and shadow pixels outside the bubble fill.
const int inset = GetBorderThickness(); const int inset = GetBorderThickness();
if (arrow_paint_type_ != PAINT_NORMAL || !has_arrow(arrow_)) if (arrow_paint_type_ != PAINT_NORMAL || !has_arrow(arrow_))
...@@ -289,6 +335,8 @@ gfx::Size BubbleBorder::GetSizeForContentsSize( ...@@ -289,6 +335,8 @@ gfx::Size BubbleBorder::GetSizeForContentsSize(
gfx::Size size(contents_size); gfx::Size size(contents_size);
const gfx::Insets insets = GetInsets(); const gfx::Insets insets = GetInsets();
size.Enlarge(insets.width(), insets.height()); size.Enlarge(insets.width(), insets.height());
if (UseMd())
return size;
// Ensure the bubble is large enough to not overlap border and arrow images. // Ensure the bubble is large enough to not overlap border and arrow images.
const int min = 2 * images_->border_thickness; const int min = 2 * images_->border_thickness;
...@@ -360,6 +408,7 @@ gfx::Rect BubbleBorder::GetArrowRect(const gfx::Rect& bounds) const { ...@@ -360,6 +408,7 @@ gfx::Rect BubbleBorder::GetArrowRect(const gfx::Rect& bounds) const {
void BubbleBorder::GetArrowPathFromArrowBounds(const gfx::Rect& arrow_bounds, void BubbleBorder::GetArrowPathFromArrowBounds(const gfx::Rect& arrow_bounds,
SkPath* path) const { SkPath* path) const {
DCHECK(!UseMd());
const bool horizontal = is_arrow_on_horizontal(arrow_); const bool horizontal = is_arrow_on_horizontal(arrow_);
const int thickness = images_->arrow_interior_thickness; const int thickness = images_->arrow_interior_thickness;
float tip_x = horizontal ? arrow_bounds.CenterPoint().x() : float tip_x = horizontal ? arrow_bounds.CenterPoint().x() :
...@@ -385,6 +434,7 @@ void BubbleBorder::GetArrowPathFromArrowBounds(const gfx::Rect& arrow_bounds, ...@@ -385,6 +434,7 @@ void BubbleBorder::GetArrowPathFromArrowBounds(const gfx::Rect& arrow_bounds,
void BubbleBorder::DrawArrow(gfx::Canvas* canvas, void BubbleBorder::DrawArrow(gfx::Canvas* canvas,
const gfx::Rect& arrow_bounds) const { const gfx::Rect& arrow_bounds) const {
DCHECK(!UseMd());
canvas->DrawImageInt(*GetArrowImage(), arrow_bounds.x(), arrow_bounds.y()); canvas->DrawImageInt(*GetArrowImage(), arrow_bounds.x(), arrow_bounds.y());
SkPath path; SkPath path;
GetArrowPathFromArrowBounds(arrow_bounds, &path); GetArrowPathFromArrowBounds(arrow_bounds, &path);
...@@ -395,6 +445,38 @@ void BubbleBorder::DrawArrow(gfx::Canvas* canvas, ...@@ -395,6 +445,38 @@ void BubbleBorder::DrawArrow(gfx::Canvas* canvas,
canvas->DrawPath(path, paint); canvas->DrawPath(path, paint);
} }
void BubbleBorder::PaintMd(const View& view, gfx::Canvas* canvas) {
gfx::ScopedCanvas scoped(canvas);
SkPaint paint;
std::vector<gfx::ShadowValue> shadows;
// gfx::ShadowValue counts blur pixels both inside and outside the shape,
// whereas these blur values only describe the outside portion, hence they
// must be doubled.
shadows.emplace_back(gfx::Vector2d(0, kSmallShadowVerticalOffset),
2 * kSmallShadowBlur, kSmallShadowColor);
shadows.emplace_back(gfx::Vector2d(0, kLargeShadowVerticalOffset),
2 * kLargeShadowBlur, kLargeShadowColor);
paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows));
paint.setColor(SkColorSetA(SK_ColorBLACK, 0x0D));
paint.setAntiAlias(true);
gfx::Rect bounds(view.GetLocalBounds());
bounds.Inset(GetInsets());
SkRRect r_rect =
SkRRect::MakeRectXY(gfx::RectToSkRect(bounds), GetBorderCornerRadius(),
GetBorderCornerRadius());
// Clip out a round rect so the fill and shadow don't draw over the contents
// of the bubble.
SkRRect clip_r_rect = r_rect;
// Stroke width is a single pixel at any scale factor.
const SkScalar one_pixel = SkFloatToScalar(1 / canvas->image_scale());
clip_r_rect.inset(one_pixel, one_pixel);
canvas->sk_canvas()->clipRRect(clip_r_rect, SkRegion::kDifference_Op,
true /*doAntiAlias*/);
canvas->sk_canvas()->drawRRect(r_rect, paint);
}
internal::BorderImages* BubbleBorder::GetImagesForTest() const { internal::BorderImages* BubbleBorder::GetImagesForTest() const {
return images_; return images_;
} }
......
...@@ -182,7 +182,7 @@ class VIEWS_EXPORT BubbleBorder : public Border { ...@@ -182,7 +182,7 @@ class VIEWS_EXPORT BubbleBorder : public Border {
void set_arrow_offset(int offset) { arrow_offset_ = offset; } void set_arrow_offset(int offset) { arrow_offset_ = offset; }
// Sets the way the arrow is actually painted. Default is PAINT_NORMAL. // Sets the way the arrow is actually painted. Default is PAINT_NORMAL.
void set_paint_arrow(ArrowPaintType value) { arrow_paint_type_ = value; } void set_paint_arrow(ArrowPaintType value);
// Get the desired widget bounds (in screen coordinates) given the anchor rect // Get the desired widget bounds (in screen coordinates) given the anchor rect
// and bubble content size; calculated from shadow and arrow image dimensions. // and bubble content size; calculated from shadow and arrow image dimensions.
...@@ -229,6 +229,8 @@ class VIEWS_EXPORT BubbleBorder : public Border { ...@@ -229,6 +229,8 @@ class VIEWS_EXPORT BubbleBorder : public Border {
SkPath* path) const; SkPath* path) const;
void DrawArrow(gfx::Canvas* canvas, const gfx::Rect& arrow_bounds) const; void DrawArrow(gfx::Canvas* canvas, const gfx::Rect& arrow_bounds) const;
void PaintMd(const View& view, gfx::Canvas* canvas);
internal::BorderImages* GetImagesForTest() const; internal::BorderImages* GetImagesForTest() const;
Arrow arrow_; Arrow arrow_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment