blob: 3f909b5b2fb1a9c4172cd60ddf7c8ac7c7e78a88 [file] [log] [blame]
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:171// Copyright 2022 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/native_theme/native_theme_fluent.h"
6
Kevin Lubick24166022023-11-01 17:14:047#include "skia/ext/font_utils.h"
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:178#include "testing/gtest/include/gtest/gtest.h"
Yaroslav Shalivskyyaad76592022-10-31 19:01:299#include "third_party/skia/include/core/SkTypeface.h"
10#include "ui/gfx/geometry/rect_conversions.h"
11#include "ui/gfx/geometry/rect_f.h"
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1712#include "ui/native_theme/native_theme_constants_fluent.h"
13
14namespace ui {
15
16class NativeThemeFluentTest : public ::testing::Test,
17 public ::testing::WithParamInterface<float> {
18 protected:
Yaroslav Shalivskyyaad76592022-10-31 19:01:2919 void VerifyArrowRectCommonDimensions(const gfx::RectF& arrow_rect) const {
20 EXPECT_FALSE(arrow_rect.IsEmpty());
21 EXPECT_EQ(arrow_rect.width(), arrow_rect.height());
22 EXPECT_EQ(arrow_rect.width(), std::floor(arrow_rect.width()));
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1723 }
24
Yaroslav Shalivskyyaad76592022-10-31 19:01:2925 void VerifyArrowRectIsCentered(const gfx::RectF& button_rect,
26 const gfx::RectF& arrow_rect,
27 NativeTheme::Part part) const {
28 if (part == NativeTheme::kScrollbarUpArrow ||
29 part == NativeTheme::kScrollbarDownArrow) {
30 EXPECT_EQ(button_rect.CenterPoint().x(), arrow_rect.CenterPoint().x());
31 // Due to the offset the arrow rect is shifted from the center.
32 // See NativeThemeFluent::OffsetArrowRect() for more details. Same below.
33 EXPECT_NEAR(button_rect.CenterPoint().y(), arrow_rect.CenterPoint().y(),
34 ScaleFromDIP() * 2);
35 } else {
36 EXPECT_EQ(button_rect.CenterPoint().y(), arrow_rect.CenterPoint().y());
37 EXPECT_NEAR(button_rect.CenterPoint().x(), arrow_rect.CenterPoint().x(),
38 ScaleFromDIP() * 2);
39 }
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1740 }
41
Yaroslav Shalivskyyaad76592022-10-31 19:01:2942 void VerifyArrowRectIsIntRect(const gfx::RectF& arrow_rect) const {
43 if (theme_.ArrowIconsAvailable())
44 return;
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1745
Yaroslav Shalivskyyaad76592022-10-31 19:01:2946 // Verify that an arrow rect with triangular arrows is an integer rect.
47 EXPECT_TRUE(IsNearestRectWithinDistance(arrow_rect, 0.01f));
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1748 }
49
Yaroslav Shalivskyyaad76592022-10-31 19:01:2950 void VerifyArrowRectLengthRatio(const gfx::RectF& button_rect,
51 const gfx::RectF& arrow_rect,
52 NativeTheme::State state) const {
53 const int smaller_button_side =
54 std::min(button_rect.width(), button_rect.height());
55 if (state == NativeTheme::kNormal) {
56 // Default state arrows are slightly bigger than the half of the button's
57 // smaller side (track thickness).
58 EXPECT_GT(arrow_rect.width(), smaller_button_side / 2.0f);
59 EXPECT_LT(arrow_rect.width(), smaller_button_side);
60 } else {
61 EXPECT_GT(arrow_rect.width(), smaller_button_side / 3.0f);
62 EXPECT_LT(arrow_rect.width(), smaller_button_side / 1.5f);
63 }
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1764 }
65
Yaroslav Shalivskyyaad76592022-10-31 19:01:2966 void VerifyArrowRect() const {
67 for (auto const& part :
68 {NativeTheme::kScrollbarUpArrow, NativeTheme::kScrollbarLeftArrow}) {
69 const gfx::RectF button_rect(ButtonRect(part));
70 for (auto const& state : {NativeTheme::kNormal, NativeTheme::kPressed}) {
71 const gfx::RectF arrow_rect =
72 theme_.GetArrowRect(ToNearestRect(button_rect), part, state);
73 VerifyArrowRectCommonDimensions(arrow_rect);
74 VerifyArrowRectIsIntRect(arrow_rect);
75 VerifyArrowRectIsCentered(button_rect, arrow_rect, part);
76 VerifyArrowRectLengthRatio(button_rect, arrow_rect, state);
77 }
78 }
79 }
80
81 gfx::RectF ButtonRect(NativeTheme::Part part) const {
82 const int button_length =
83 base::ClampFloor(kFluentScrollbarButtonSideLength * ScaleFromDIP());
84 const int track_thickness =
85 base::ClampFloor(kFluentScrollbarThickness * ScaleFromDIP());
86
87 if (part == NativeTheme::kScrollbarUpArrow ||
88 part == NativeTheme::kScrollbarDownArrow)
89 return gfx::RectF(0, 0, track_thickness, button_length);
90
91 return gfx::RectF(0, 0, button_length, track_thickness);
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1792 }
93
94 float ScaleFromDIP() const { return GetParam(); }
Yaroslav Shalivskyyaad76592022-10-31 19:01:2995
96 // Mocks the availability of the font for drawing arrow icons.
97 void SetArrowIconsAvailable(bool enabled) {
98 if (enabled) {
Kevin Lubick24166022023-11-01 17:14:0499 theme_.typeface_ = skia::DefaultTypeface();
Yaroslav Shalivskyyaad76592022-10-31 19:01:29100 EXPECT_TRUE(theme_.ArrowIconsAvailable());
101 } else {
102 theme_.typeface_ = nullptr;
103 EXPECT_FALSE(theme_.ArrowIconsAvailable());
104 }
105 }
106
107 NativeThemeFluent theme_{false};
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:17108};
109
Yaroslav Shalivskyyaad76592022-10-31 19:01:29110// Verify the dimensions of an arrow rect with triangular arrows for a given
111// button rect depending on the arrow direction and state.
112TEST_P(NativeThemeFluentTest, VerifyArrowRectWithTriangularArrows) {
113 SetArrowIconsAvailable(false);
114 VerifyArrowRect();
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:17115}
116
Yaroslav Shalivskyyaad76592022-10-31 19:01:29117// Verify the dimensions of an arrow rect with arrow icons for a given
118// button rect depending on the arrow direction and state.
119TEST_P(NativeThemeFluentTest, VerifyArrowRectWithArrowIcons) {
120 SetArrowIconsAvailable(true);
121 VerifyArrowRect();
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:17122}
123
124INSTANTIATE_TEST_SUITE_P(All,
125 NativeThemeFluentTest,
126 ::testing::Values(1.f, 1.25f, 1.5f, 1.75f, 2.f));
127
128} // namespace ui