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