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