rounded_image_view.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/public/cpp/rounded_image_view.h"
  5. #include "skia/ext/image_operations.h"
  6. #include "third_party/skia/include/core/SkPath.h"
  7. #include "ui/gfx/canvas.h"
  8. #include "ui/gfx/geometry/skia_conversions.h"
  9. #include "ui/gfx/image/image_skia_operations.h"
  10. namespace ash {
  11. RoundedImageView::RoundedImageView()
  12. : RoundedImageView(/*corner_radius=*/0, Alignment::kLeading) {}
  13. RoundedImageView::RoundedImageView(int corner_radius, Alignment alignment)
  14. : alignment_(alignment) {
  15. for (int i = 0; i < 4; ++i)
  16. corner_radius_[i] = corner_radius;
  17. }
  18. RoundedImageView::~RoundedImageView() = default;
  19. void RoundedImageView::SetImage(const gfx::ImageSkia& image) {
  20. SetImage(image, image.size());
  21. }
  22. void RoundedImageView::SetImage(const gfx::ImageSkia& image,
  23. const gfx::Size& size) {
  24. const bool is_size_same = GetImageSize() == size;
  25. const bool is_image_same = original_image_.BackedBySameObjectAs(image);
  26. if (is_size_same && is_image_same)
  27. return;
  28. if (!is_image_same)
  29. original_image_ = image;
  30. // Try to get the best image quality for the avatar.
  31. resized_image_ = gfx::ImageSkiaOperations::CreateResizedImage(
  32. original_image_, skia::ImageOperations::RESIZE_BEST, size);
  33. if (GetWidget() && GetVisible()) {
  34. PreferredSizeChanged();
  35. SchedulePaint();
  36. }
  37. }
  38. void RoundedImageView::SetCornerRadii(int top_left,
  39. int top_right,
  40. int bottom_right,
  41. int bottom_left) {
  42. corner_radius_[0] = top_left;
  43. corner_radius_[1] = top_right;
  44. corner_radius_[2] = bottom_right;
  45. corner_radius_[3] = bottom_left;
  46. }
  47. void RoundedImageView::SetCornerRadius(int corner_radius) {
  48. SetCornerRadii(corner_radius, corner_radius, corner_radius, corner_radius);
  49. }
  50. gfx::Size RoundedImageView::CalculatePreferredSize() const {
  51. return gfx::Size(GetImageSize().width() + GetInsets().width(),
  52. GetImageSize().height() + GetInsets().height());
  53. }
  54. void RoundedImageView::OnPaint(gfx::Canvas* canvas) {
  55. View::OnPaint(canvas);
  56. gfx::Rect drawn_image_bounds(size());
  57. drawn_image_bounds.Inset(GetInsets());
  58. // It handles the situation that the size of the drawing space is greater
  59. // than that of the image to draw.
  60. drawn_image_bounds.ClampToCenteredSize(GetImageSize());
  61. const SkScalar kRadius[8] = {
  62. SkIntToScalar(corner_radius_[0]), SkIntToScalar(corner_radius_[0]),
  63. SkIntToScalar(corner_radius_[1]), SkIntToScalar(corner_radius_[1]),
  64. SkIntToScalar(corner_radius_[2]), SkIntToScalar(corner_radius_[2]),
  65. SkIntToScalar(corner_radius_[3]), SkIntToScalar(corner_radius_[3])};
  66. SkPath path;
  67. path.addRoundRect(gfx::RectToSkRect(drawn_image_bounds), kRadius);
  68. cc::PaintFlags flags;
  69. flags.setAntiAlias(true);
  70. gfx::ImageSkia image_to_draw;
  71. switch (alignment_) {
  72. case Alignment::kLeading:
  73. image_to_draw = resized_image_;
  74. break;
  75. case Alignment::kCenter:
  76. gfx::Rect image_size(GetImageSize());
  77. // It handles the situation that the size of the image to draw is greater
  78. // than that of the drawing space.
  79. image_size.ClampToCenteredSize(drawn_image_bounds.size());
  80. image_to_draw =
  81. gfx::ImageSkiaOperations::ExtractSubset(resized_image_, image_size);
  82. break;
  83. }
  84. // The size of the area to paint `image_to_draw` should be no greater than
  85. // that of `image_to_draw`. Otherwise, `image_to_draw` will be tiled.
  86. DCHECK_LE(drawn_image_bounds.width(), image_to_draw.width());
  87. DCHECK_LE(drawn_image_bounds.height(), image_to_draw.height());
  88. canvas->DrawImageInPath(image_to_draw, drawn_image_bounds.x(),
  89. drawn_image_bounds.y(), path, flags);
  90. }
  91. const char* RoundedImageView::GetClassName() const {
  92. return "RoundedImageView";
  93. }
  94. gfx::Size RoundedImageView::GetImageSize() const {
  95. return resized_image_.size();
  96. }
  97. } // namespace ash