blob: 28f687ca178f3e7464b3b3e3b81a7e45ec0e86d5 [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
7#include "testing/gtest/include/gtest/gtest.h"
Yaroslav Shalivskyyaad76592022-10-31 19:01:298#include "third_party/skia/include/core/SkTypeface.h"
9#include "ui/gfx/geometry/rect_conversions.h"
10#include "ui/gfx/geometry/rect_f.h"
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1711#include "ui/native_theme/native_theme_constants_fluent.h"
12
13namespace ui {
14
15class NativeThemeFluentTest : public ::testing::Test,
16 public ::testing::WithParamInterface<float> {
17 protected:
Yaroslav Shalivskyyaad76592022-10-31 19:01:2918 void VerifyArrowRectCommonDimensions(const gfx::RectF& arrow_rect) const {
19 EXPECT_FALSE(arrow_rect.IsEmpty());
20 EXPECT_EQ(arrow_rect.width(), arrow_rect.height());
21 EXPECT_EQ(arrow_rect.width(), std::floor(arrow_rect.width()));
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1722 }
23
Yaroslav Shalivskyyaad76592022-10-31 19:01:2924 void VerifyArrowRectIsCentered(const gfx::RectF& button_rect,
25 const gfx::RectF& arrow_rect,
26 NativeTheme::Part part) const {
27 if (part == NativeTheme::kScrollbarUpArrow ||
28 part == NativeTheme::kScrollbarDownArrow) {
29 EXPECT_EQ(button_rect.CenterPoint().x(), arrow_rect.CenterPoint().x());
30 // Due to the offset the arrow rect is shifted from the center.
31 // See NativeThemeFluent::OffsetArrowRect() for more details. Same below.
32 EXPECT_NEAR(button_rect.CenterPoint().y(), arrow_rect.CenterPoint().y(),
33 ScaleFromDIP() * 2);
34 } else {
35 EXPECT_EQ(button_rect.CenterPoint().y(), arrow_rect.CenterPoint().y());
36 EXPECT_NEAR(button_rect.CenterPoint().x(), arrow_rect.CenterPoint().x(),
37 ScaleFromDIP() * 2);
38 }
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1739 }
40
Yaroslav Shalivskyyaad76592022-10-31 19:01:2941 void VerifyArrowRectIsIntRect(const gfx::RectF& arrow_rect) const {
42 if (theme_.ArrowIconsAvailable())
43 return;
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1744
Yaroslav Shalivskyyaad76592022-10-31 19:01:2945 // Verify that an arrow rect with triangular arrows is an integer rect.
46 EXPECT_TRUE(IsNearestRectWithinDistance(arrow_rect, 0.01f));
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1747 }
48
Yaroslav Shalivskyyaad76592022-10-31 19:01:2949 void VerifyArrowRectLengthRatio(const gfx::RectF& button_rect,
50 const gfx::RectF& arrow_rect,
51 NativeTheme::State state) const {
52 const int smaller_button_side =
53 std::min(button_rect.width(), button_rect.height());
54 if (state == NativeTheme::kNormal) {
55 // Default state arrows are slightly bigger than the half of the button's
56 // smaller side (track thickness).
57 EXPECT_GT(arrow_rect.width(), smaller_button_side / 2.0f);
58 EXPECT_LT(arrow_rect.width(), smaller_button_side);
59 } else {
60 EXPECT_GT(arrow_rect.width(), smaller_button_side / 3.0f);
61 EXPECT_LT(arrow_rect.width(), smaller_button_side / 1.5f);
62 }
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1763 }
64
Yaroslav Shalivskyyaad76592022-10-31 19:01:2965 void VerifyArrowRect() const {
66 for (auto const& part :
67 {NativeTheme::kScrollbarUpArrow, NativeTheme::kScrollbarLeftArrow}) {
68 const gfx::RectF button_rect(ButtonRect(part));
69 for (auto const& state : {NativeTheme::kNormal, NativeTheme::kPressed}) {
70 const gfx::RectF arrow_rect =
71 theme_.GetArrowRect(ToNearestRect(button_rect), part, state);
72 VerifyArrowRectCommonDimensions(arrow_rect);
73 VerifyArrowRectIsIntRect(arrow_rect);
74 VerifyArrowRectIsCentered(button_rect, arrow_rect, part);
75 VerifyArrowRectLengthRatio(button_rect, arrow_rect, state);
76 }
77 }
78 }
79
80 gfx::RectF ButtonRect(NativeTheme::Part part) const {
81 const int button_length =
82 base::ClampFloor(kFluentScrollbarButtonSideLength * ScaleFromDIP());
83 const int track_thickness =
84 base::ClampFloor(kFluentScrollbarThickness * ScaleFromDIP());
85
86 if (part == NativeTheme::kScrollbarUpArrow ||
87 part == NativeTheme::kScrollbarDownArrow)
88 return gfx::RectF(0, 0, track_thickness, button_length);
89
90 return gfx::RectF(0, 0, button_length, track_thickness);
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:1791 }
92
93 float ScaleFromDIP() const { return GetParam(); }
Yaroslav Shalivskyyaad76592022-10-31 19:01:2994
95 // Mocks the availability of the font for drawing arrow icons.
96 void SetArrowIconsAvailable(bool enabled) {
97 if (enabled) {
98 theme_.typeface_ = SkTypeface::MakeDefault();
99 EXPECT_TRUE(theme_.ArrowIconsAvailable());
100 } else {
101 theme_.typeface_ = nullptr;
102 EXPECT_FALSE(theme_.ArrowIconsAvailable());
103 }
104 }
105
106 NativeThemeFluent theme_{false};
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:17107};
108
Yaroslav Shalivskyyaad76592022-10-31 19:01:29109// Verify the dimensions of an arrow rect with triangular arrows for a given
110// button rect depending on the arrow direction and state.
111TEST_P(NativeThemeFluentTest, VerifyArrowRectWithTriangularArrows) {
112 SetArrowIconsAvailable(false);
113 VerifyArrowRect();
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:17114}
115
Yaroslav Shalivskyyaad76592022-10-31 19:01:29116// Verify the dimensions of an arrow rect with arrow icons for a given
117// button rect depending on the arrow direction and state.
118TEST_P(NativeThemeFluentTest, VerifyArrowRectWithArrowIcons) {
119 SetArrowIconsAvailable(true);
120 VerifyArrowRect();
Yaroslav Shalivskyy80ae54e2022-09-12 20:54:17121}
122
123INSTANTIATE_TEST_SUITE_P(All,
124 NativeThemeFluentTest,
125 ::testing::Values(1.f, 1.25f, 1.5f, 1.75f, 2.f));
126
127} // namespace ui