1 // Copyright 2018 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
5 #include "ui/views/controls/image_view.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10
11 #include "base/i18n/rtl.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/skia/include/core/SkBitmap.h"
14 #include "third_party/skia/include/core/SkColor.h"
15 #include "ui/accessibility/ax_enums.mojom.h"
16 #include "ui/accessibility/ax_node_data.h"
17 #include "ui/gfx/geometry/insets.h"
18 #include "ui/gfx/geometry/point.h"
19 #include "ui/gfx/geometry/size.h"
20 #include "ui/gfx/image/image_skia.h"
21 #include "ui/views/border.h"
22 #include "ui/views/layout/box_layout.h"
23 #include "ui/views/test/ax_event_counter.h"
24 #include "ui/views/test/views_test_base.h"
25 #include "ui/views/widget/widget.h"
26
27 namespace {
28
29 enum class Axis {
30 kHorizontal,
31 kVertical,
32 };
33
34 // A test utility function to set the application default text direction.
SetRTL(bool rtl)35 void SetRTL(bool rtl) {
36 // Override the current locale/direction.
37 base::i18n::SetICUDefaultLocale(rtl ? "he" : "en");
38 EXPECT_EQ(rtl, base::i18n::IsRTL());
39 }
40
41 } // namespace
42
43 namespace views {
44
45 class ImageViewTest : public ViewsTestBase,
46 public ::testing::WithParamInterface<Axis> {
47 public:
48 ImageViewTest() = default;
49
50 // ViewsTestBase:
SetUp()51 void SetUp() override {
52 ViewsTestBase::SetUp();
53
54 Widget::InitParams params =
55 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
56 params.bounds = gfx::Rect(200, 200);
57 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
58 widget_.Init(std::move(params));
59 auto container = std::make_unique<View>();
60 // Make sure children can take up exactly as much space as they require.
61 BoxLayout::Orientation orientation =
62 GetParam() == Axis::kHorizontal ? BoxLayout::Orientation::kHorizontal
63 : BoxLayout::Orientation::kVertical;
64 container->SetLayoutManager(std::make_unique<BoxLayout>(orientation));
65 image_view_ = container->AddChildView(std::make_unique<ImageView>());
66 widget_.SetContentsView(std::move(container));
67
68 widget_.Show();
69 }
70
TearDown()71 void TearDown() override {
72 widget_.Close();
73 ViewsTestBase::TearDown();
74 }
75
CurrentImageOriginForParam()76 int CurrentImageOriginForParam() {
77 image_view()->UpdateImageOrigin();
78 gfx::Point origin = image_view()->GetImageBounds().origin();
79 return GetParam() == Axis::kHorizontal ? origin.x() : origin.y();
80 }
81
82 protected:
image_view()83 ImageView* image_view() { return image_view_; }
widget()84 Widget* widget() { return &widget_; }
85
86 private:
87 ImageView* image_view_ = nullptr;
88 Widget widget_;
89
90 DISALLOW_COPY_AND_ASSIGN(ImageViewTest);
91 };
92
93 // Test the image origin of the internal ImageSkia is correct when it is
94 // center-aligned (both horizontally and vertically).
TEST_P(ImageViewTest,CenterAlignment)95 TEST_P(ImageViewTest, CenterAlignment) {
96 image_view()->SetHorizontalAlignment(ImageView::Alignment::kCenter);
97
98 constexpr int kImageSkiaSize = 4;
99 SkBitmap bitmap;
100 bitmap.allocN32Pixels(kImageSkiaSize, kImageSkiaSize);
101 gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
102 image_view()->SetImage(image_skia);
103 widget()->GetContentsView()->Layout();
104 EXPECT_NE(gfx::Size(), image_skia.size());
105
106 // With no changes to the size / padding of |image_view|, the origin of
107 // |image_skia| is the same as the origin of |image_view|.
108 EXPECT_EQ(0, CurrentImageOriginForParam());
109
110 // Test insets are always respected in LTR and RTL.
111 constexpr int kInset = 5;
112 image_view()->SetBorder(CreateEmptyBorder(gfx::Insets(kInset)));
113 widget()->GetContentsView()->Layout();
114 EXPECT_EQ(kInset, CurrentImageOriginForParam());
115
116 SetRTL(true);
117 widget()->GetContentsView()->Layout();
118 EXPECT_EQ(kInset, CurrentImageOriginForParam());
119
120 // Check this still holds true when the insets are asymmetrical.
121 constexpr int kLeadingInset = 4;
122 constexpr int kTrailingInset = 6;
123 image_view()->SetBorder(CreateEmptyBorder(
124 gfx::Insets(/*top=*/kLeadingInset, /*left=*/kLeadingInset,
125 /*bottom=*/kTrailingInset, /*right=*/kTrailingInset)));
126 widget()->GetContentsView()->Layout();
127 EXPECT_EQ(kLeadingInset, CurrentImageOriginForParam());
128
129 SetRTL(false);
130 widget()->GetContentsView()->Layout();
131 EXPECT_EQ(kLeadingInset, CurrentImageOriginForParam());
132 }
133
TEST_P(ImageViewTest,ImageOriginForCustomViewBounds)134 TEST_P(ImageViewTest, ImageOriginForCustomViewBounds) {
135 gfx::Rect image_view_bounds(10, 10, 80, 80);
136 image_view()->SetHorizontalAlignment(ImageView::Alignment::kCenter);
137 image_view()->SetBoundsRect(image_view_bounds);
138
139 SkBitmap bitmap;
140 constexpr int kImageSkiaSize = 20;
141 bitmap.allocN32Pixels(kImageSkiaSize, kImageSkiaSize);
142 gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
143 image_view()->SetImage(image_skia);
144
145 EXPECT_EQ(gfx::Point(30, 30), image_view()->GetImageBounds().origin());
146 EXPECT_EQ(image_view_bounds, image_view()->bounds());
147 }
148
149 // Verifies setting the accessible name will be call NotifyAccessibilityEvent.
TEST_P(ImageViewTest,SetAccessibleNameNotifiesAccessibilityEvent)150 TEST_P(ImageViewTest, SetAccessibleNameNotifiesAccessibilityEvent) {
151 base::string16 test_tooltip_text = base::ASCIIToUTF16("Test Tooltip Text");
152 test::AXEventCounter counter(views::AXEventManager::Get());
153 EXPECT_EQ(0, counter.GetCount(ax::mojom::Event::kTextChanged));
154 image_view()->SetAccessibleName(test_tooltip_text);
155 EXPECT_EQ(1, counter.GetCount(ax::mojom::Event::kTextChanged));
156 EXPECT_EQ(test_tooltip_text, image_view()->GetAccessibleName());
157 ui::AXNodeData data;
158 image_view()->GetAccessibleNodeData(&data);
159 const std::string& name =
160 data.GetStringAttribute(ax::mojom::StringAttribute::kName);
161 EXPECT_EQ(test_tooltip_text, base::ASCIIToUTF16(name));
162 }
163
164 INSTANTIATE_TEST_SUITE_P(All,
165 ImageViewTest,
166 ::testing::Values(Axis::kHorizontal, Axis::kVertical));
167
168 } // namespace views
169