| Index: ui/views/bubble/bubble_border.cc
|
| diff --git a/ui/views/bubble/bubble_border.cc b/ui/views/bubble/bubble_border.cc
|
| index f14daeb3ead54fcb566c86876f2a0eba97343a8d..2f961092033540d14fddbfb0824dca393789a1d9 100644
|
| --- a/ui/views/bubble/bubble_border.cc
|
| +++ b/ui/views/bubble/bubble_border.cc
|
| @@ -7,12 +7,15 @@
|
| #include <algorithm>
|
|
|
| #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/SkPath.h"
|
| +#include "ui/base/material_design/material_design_controller.h"
|
| #include "ui/base/resource/resource_bundle.h"
|
| #include "ui/gfx/canvas.h"
|
| #include "ui/gfx/geometry/rect.h"
|
| #include "ui/gfx/path.h"
|
| +#include "ui/gfx/scoped_canvas.h"
|
| #include "ui/gfx/skia_util.h"
|
| #include "ui/resources/grit/ui_resources.h"
|
| #include "ui/views/painter.h"
|
| @@ -57,6 +60,20 @@ BorderImages::~BorderImages() {}
|
|
|
| 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
|
| // macro because there is no center image.
|
| const int kNoShadowImages[] = {
|
| @@ -143,6 +160,7 @@ BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color)
|
| arrow_paint_type_(PAINT_NORMAL),
|
| alignment_(ALIGN_ARROW_TO_MID_ANCHOR),
|
| shadow_(shadow),
|
| + images_(nullptr),
|
| background_color_(color),
|
| use_theme_background_color_(false) {
|
| #if defined(OS_MACOSX)
|
| @@ -151,11 +169,23 @@ BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color)
|
| shadow_ = NO_ASSETS;
|
| #endif // OS_MACOSX
|
| 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() {}
|
|
|
| +void BubbleBorder::set_paint_arrow(ArrowPaintType value) {
|
| + if (UseMd())
|
| + return;
|
| + arrow_paint_type_ = value;
|
| +}
|
| +
|
| gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
|
| const gfx::Size& contents_size) const {
|
| int x = anchor_rect.x();
|
| @@ -166,7 +196,7 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
|
| const int arrow_offset = GetArrowOffset(size);
|
| // |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.
|
| - int arrow_shift =
|
| + int arrow_shift = UseMd() ? 0 :
|
| images_->arrow_interior_thickness + kStroke - images_->arrow_thickness;
|
| // 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.
|
| @@ -206,14 +236,20 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
|
| }
|
|
|
| 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 {
|
| - return images_->corner_radius;
|
| + return UseMd() ? 3 : images_->corner_radius;
|
| }
|
|
|
| int BubbleBorder::GetArrowOffset(const gfx::Size& border_size) const {
|
| + if (UseMd())
|
| + return 0;
|
| +
|
| const int edge_length = is_arrow_on_horizontal(arrow_) ?
|
| border_size.width() : border_size.height();
|
| if (is_arrow_at_center(arrow_) && arrow_offset_ == 0)
|
| @@ -241,6 +277,9 @@ void BubbleBorder::SetBorderInteriorThickness(int border_interior_thickness) {
|
| }
|
|
|
| void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
|
| + if (UseMd())
|
| + return PaintMd(view, canvas);
|
| +
|
| gfx::Rect bounds(view.GetContentsBounds());
|
| bounds.Inset(-GetBorderThickness(), -GetBorderThickness());
|
| const gfx::Rect arrow_bounds = GetArrowRect(view.GetLocalBounds());
|
| @@ -264,6 +303,13 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
|
| }
|
|
|
| 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.
|
| const int inset = GetBorderThickness();
|
| if (arrow_paint_type_ != PAINT_NORMAL || !has_arrow(arrow_))
|
| @@ -289,6 +335,8 @@ gfx::Size BubbleBorder::GetSizeForContentsSize(
|
| gfx::Size size(contents_size);
|
| const gfx::Insets insets = GetInsets();
|
| size.Enlarge(insets.width(), insets.height());
|
| + if (UseMd())
|
| + return size;
|
|
|
| // Ensure the bubble is large enough to not overlap border and arrow images.
|
| const int min = 2 * images_->border_thickness;
|
| @@ -360,6 +408,7 @@ gfx::Rect BubbleBorder::GetArrowRect(const gfx::Rect& bounds) const {
|
|
|
| void BubbleBorder::GetArrowPathFromArrowBounds(const gfx::Rect& arrow_bounds,
|
| SkPath* path) const {
|
| + DCHECK(!UseMd());
|
| const bool horizontal = is_arrow_on_horizontal(arrow_);
|
| const int thickness = images_->arrow_interior_thickness;
|
| float tip_x = horizontal ? arrow_bounds.CenterPoint().x() :
|
| @@ -385,6 +434,7 @@ void BubbleBorder::GetArrowPathFromArrowBounds(const gfx::Rect& arrow_bounds,
|
|
|
| void BubbleBorder::DrawArrow(gfx::Canvas* canvas,
|
| const gfx::Rect& arrow_bounds) const {
|
| + DCHECK(!UseMd());
|
| canvas->DrawImageInt(*GetArrowImage(), arrow_bounds.x(), arrow_bounds.y());
|
| SkPath path;
|
| GetArrowPathFromArrowBounds(arrow_bounds, &path);
|
| @@ -395,6 +445,38 @@ void BubbleBorder::DrawArrow(gfx::Canvas* canvas,
|
| 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 {
|
| return images_;
|
| }
|
|
|