| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/views/highlight_border.h" |
| |
| #include "chromeos/constants/chromeos_features.h" |
| #include "ui/chromeos/styles/cros_tokens_color_mappings.h" |
| #include "ui/color/color_id.h" |
| #include "ui/color/color_provider.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/geometry/dip_util.h" |
| #include "ui/gfx/geometry/rounded_corners_f.h" |
| #include "ui/gfx/geometry/skia_conversions.h" |
| #include "ui/gfx/scoped_canvas.h" |
| #include "ui/views/view.h" |
| |
| namespace views { |
| |
| // static |
| void HighlightBorder::PaintBorderToCanvas( |
| gfx::Canvas* canvas, |
| SkColor highlight_color, |
| SkColor border_color, |
| const gfx::Rect& bounds, |
| const gfx::RoundedCornersF& corner_radii, |
| Type type, |
| bool use_light_colors) { |
| cc::PaintFlags flags; |
| flags.setStrokeWidth(kHighlightBorderThickness); |
| flags.setColor(border_color); |
| flags.setStyle(cc::PaintFlags::kStroke_Style); |
| flags.setAntiAlias(true); |
| |
| const float half_thickness = kHighlightBorderThickness / 2.0f; |
| |
| // Scale bounds and corner radius with device scale factor to make sure |
| // border bounds match content bounds but keep border stroke width the same. |
| gfx::ScopedCanvas scoped_canvas(canvas); |
| const float dsf = canvas->UndoDeviceScaleFactor(); |
| const gfx::RectF pixel_bounds = gfx::ConvertRectToPixels(bounds, dsf); |
| |
| const SkScalar radii[8] = { |
| corner_radii.upper_left() * dsf, corner_radii.upper_left() * dsf, |
| corner_radii.upper_right() * dsf, corner_radii.upper_right() * dsf, |
| corner_radii.lower_right() * dsf, corner_radii.lower_right() * dsf, |
| corner_radii.lower_left() * dsf, corner_radii.lower_left() * dsf}; |
| |
| gfx::RectF outer_border_bounds(pixel_bounds); |
| outer_border_bounds.Inset(half_thickness); |
| SkPath outer_path; |
| outer_path.addRoundRect(gfx::RectFToSkRect(outer_border_bounds), radii); |
| canvas->DrawPath(outer_path, flags); |
| |
| gfx::RectF inner_border_bounds(pixel_bounds); |
| inner_border_bounds.Inset(kHighlightBorderThickness); |
| inner_border_bounds.Inset(half_thickness); |
| flags.setColor(highlight_color); |
| SkPath inner_path; |
| inner_path.addRoundRect(gfx::RectFToSkRect(inner_border_bounds), radii); |
| canvas->DrawPath(inner_path, flags); |
| } |
| |
| // static |
| void HighlightBorder::PaintBorderToCanvas( |
| gfx::Canvas* canvas, |
| const views::View& view, |
| const gfx::Rect& bounds, |
| const gfx::RoundedCornersF& corner_radii, |
| Type type, |
| bool use_light_colors) { |
| PaintBorderToCanvas(canvas, GetHighlightColor(view, type, use_light_colors), |
| GetBorderColor(view, type, use_light_colors), bounds, |
| corner_radii, type, use_light_colors); |
| } |
| |
| // static |
| SkColor HighlightBorder::GetHighlightColor(const views::View& view, |
| HighlightBorder::Type type, |
| bool use_light_colors) { |
| ui::ColorId highlight_color_id; |
| if (use_light_colors) { |
| // TODO(crbug/1319917): These light color values are used here since we want |
| // to use light colors when dark/light mode feature is not enabled. This |
| // should be removed after dark light mode is launched. |
| DCHECK(!chromeos::features::IsDarkLightModeEnabled()); |
| DCHECK(!chromeos::features::IsJellyrollEnabled()); |
| // `kHighlightBorder3` can only be used when the dark light mode is enabled. |
| DCHECK(type != HighlightBorder::Type::kHighlightBorder3); |
| highlight_color_id = type == HighlightBorder::Type::kHighlightBorder1 |
| ? ui::kColorAshSystemUILightHighlightColor1 |
| : ui::kColorAshSystemUILightHighlightColor2; |
| } else { |
| switch (type) { |
| case HighlightBorder::Type::kHighlightBorderNoShadow: |
| highlight_color_id = cros_tokens::kCrosSysSystemHighlight; |
| break; |
| case HighlightBorder::Type::kHighlightBorderOnShadow: |
| highlight_color_id = cros_tokens::kCrosSysSystemHighlight1; |
| break; |
| case HighlightBorder::Type::kHighlightBorder1: |
| highlight_color_id = ui::kColorHighlightBorderHighlight1; |
| break; |
| case HighlightBorder::Type::kHighlightBorder2: |
| highlight_color_id = ui::kColorHighlightBorderHighlight2; |
| break; |
| case HighlightBorder::Type::kHighlightBorder3: |
| highlight_color_id = ui::kColorHighlightBorderHighlight3; |
| break; |
| } |
| } |
| |
| // `view` should be embedded in a Widget to use color provider. |
| DCHECK(view.GetWidget()); |
| return view.GetColorProvider()->GetColor(highlight_color_id); |
| } |
| |
| // static |
| SkColor HighlightBorder::GetBorderColor(const views::View& view, |
| HighlightBorder::Type type, |
| bool use_light_colors) { |
| ui::ColorId border_color_id; |
| if (use_light_colors) { |
| // TODO(crbug/1319917): These light color values are used here since we want |
| // to use light colors when dark/light mode feature is not enabled. This |
| // should be removed after dark light mode is launched. |
| DCHECK(!chromeos::features::IsDarkLightModeEnabled()); |
| DCHECK(!chromeos::features::IsJellyrollEnabled()); |
| // `kHighlightBorder3` can only be used when the dark light mode is enabled. |
| DCHECK(type != HighlightBorder::Type::kHighlightBorder3); |
| border_color_id = type == HighlightBorder::Type::kHighlightBorder1 |
| ? ui::kColorAshSystemUILightBorderColor1 |
| : ui::kColorAshSystemUILightBorderColor2; |
| } else { |
| switch (type) { |
| case HighlightBorder::Type::kHighlightBorderNoShadow: |
| border_color_id = cros_tokens::kCrosSysSystemBorder; |
| break; |
| case HighlightBorder::Type::kHighlightBorderOnShadow: |
| border_color_id = cros_tokens::kCrosSysSystemBorder1; |
| break; |
| case HighlightBorder::Type::kHighlightBorder1: |
| border_color_id = ui::kColorHighlightBorderBorder1; |
| break; |
| case HighlightBorder::Type::kHighlightBorder2: |
| border_color_id = ui::kColorHighlightBorderBorder2; |
| break; |
| case HighlightBorder::Type::kHighlightBorder3: |
| border_color_id = ui::kColorHighlightBorderBorder3; |
| break; |
| } |
| } |
| |
| // `view` should be embedded in a Widget to use color provider. |
| DCHECK(view.GetWidget()); |
| return view.GetColorProvider()->GetColor(border_color_id); |
| } |
| |
| HighlightBorder::HighlightBorder(int corner_radius, |
| Type type, |
| bool use_light_colors, |
| InsetsType insets_type) |
| : HighlightBorder(gfx::RoundedCornersF(corner_radius), |
| type, |
| use_light_colors, |
| insets_type) {} |
| |
| HighlightBorder::HighlightBorder(const gfx::RoundedCornersF& rounded_corners, |
| Type type, |
| bool use_light_colors, |
| InsetsType insets_type) |
| : rounded_corners_(rounded_corners), |
| type_(type), |
| use_light_colors_(use_light_colors), |
| insets_type_(insets_type) {} |
| |
| void HighlightBorder::Paint(const views::View& view, gfx::Canvas* canvas) { |
| PaintBorderToCanvas(canvas, view, view.GetLocalBounds(), rounded_corners_, |
| type_, use_light_colors_); |
| } |
| |
| void HighlightBorder::OnViewThemeChanged(views::View* view) { |
| view->SchedulePaint(); |
| } |
| |
| gfx::Insets HighlightBorder::GetInsets() const { |
| switch (insets_type_) { |
| case InsetsType::kNoInsets: |
| return gfx::Insets(); |
| case InsetsType::kHalfInsets: |
| return gfx::Insets(kHighlightBorderThickness); |
| case InsetsType::kFullInsets: |
| return gfx::Insets(2 * kHighlightBorderThickness); |
| } |
| } |
| |
| gfx::Size HighlightBorder::GetMinimumSize() const { |
| return gfx::Size(kHighlightBorderThickness * 4, |
| kHighlightBorderThickness * 4); |
| } |
| |
| } // namespace views |