| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/controls/label.h" | 5 #include "ui/views/controls/label.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/i18n/rtl.h" | 10 #include "base/i18n/rtl.h" |
| 11 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
| 15 #include "ui/accessibility/ax_node_data.h" | 15 #include "ui/accessibility/ax_node_data.h" |
| 16 #include "ui/base/clipboard/clipboard.h" | 16 #include "ui/base/clipboard/clipboard.h" |
| 17 #include "ui/base/l10n/l10n_util.h" | 17 #include "ui/base/l10n/l10n_util.h" |
| 18 #include "ui/base/test/material_design_controller_test_api.h" |
| 18 #include "ui/compositor/canvas_painter.h" | 19 #include "ui/compositor/canvas_painter.h" |
| 19 #include "ui/events/base_event_utils.h" | 20 #include "ui/events/base_event_utils.h" |
| 20 #include "ui/events/test/event_generator.h" | 21 #include "ui/events/test/event_generator.h" |
| 21 #include "ui/gfx/canvas.h" | 22 #include "ui/gfx/canvas.h" |
| 22 #include "ui/gfx/render_text.h" | 23 #include "ui/gfx/render_text.h" |
| 23 #include "ui/gfx/switches.h" | 24 #include "ui/gfx/switches.h" |
| 24 #include "ui/strings/grit/ui_strings.h" | 25 #include "ui/strings/grit/ui_strings.h" |
| 25 #include "ui/views/border.h" | 26 #include "ui/views/border.h" |
| 27 #include "ui/views/controls/link.h" |
| 26 #include "ui/views/test/focus_manager_test.h" | 28 #include "ui/views/test/focus_manager_test.h" |
| 27 #include "ui/views/test/views_test_base.h" | 29 #include "ui/views/test/views_test_base.h" |
| 28 #include "ui/views/widget/widget.h" | 30 #include "ui/views/widget/widget.h" |
| 29 | 31 |
| 30 using base::ASCIIToUTF16; | 32 using base::ASCIIToUTF16; |
| 31 using base::WideToUTF16; | 33 using base::WideToUTF16; |
| 32 | 34 |
| 33 #define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16) | 35 #define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16) |
| 34 | 36 |
| 35 namespace views { | 37 namespace views { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 return increased; | 85 return increased; |
| 84 } | 86 } |
| 85 | 87 |
| 86 base::string16 GetClipboardText(ui::ClipboardType clipboard_type) { | 88 base::string16 GetClipboardText(ui::ClipboardType clipboard_type) { |
| 87 base::string16 clipboard_text; | 89 base::string16 clipboard_text; |
| 88 ui::Clipboard::GetForCurrentThread()->ReadText(clipboard_type, | 90 ui::Clipboard::GetForCurrentThread()->ReadText(clipboard_type, |
| 89 &clipboard_text); | 91 &clipboard_text); |
| 90 return clipboard_text; | 92 return clipboard_text; |
| 91 } | 93 } |
| 92 | 94 |
| 95 enum class SecondaryUiMode { NON_MD, MD }; |
| 96 |
| 97 std::string SecondaryUiModeToString( |
| 98 const ::testing::TestParamInfo<SecondaryUiMode>& info) { |
| 99 return info.param == SecondaryUiMode::MD ? "MD" : "NonMD"; |
| 100 } |
| 101 |
| 93 } // namespace | 102 } // namespace |
| 94 | 103 |
| 95 class LabelTest : public ViewsTestBase { | 104 class LabelTest : public ViewsTestBase { |
| 96 public: | 105 public: |
| 97 LabelTest() {} | 106 LabelTest() {} |
| 98 | 107 |
| 99 // ViewsTestBase overrides: | 108 // Called after ViewsTestBase is set up. ViewsTestBase initializes the |
| 109 // MaterialDesignController, so this allows a subclass to influence settings |
| 110 // used for the remainder of SetUp(). |
| 111 virtual void OnBaseSetUp() {} |
| 112 |
| 113 // ViewsTestBase: |
| 100 void SetUp() override { | 114 void SetUp() override { |
| 101 ViewsTestBase::SetUp(); | 115 ViewsTestBase::SetUp(); |
| 116 OnBaseSetUp(); |
| 102 | 117 |
| 103 Widget::InitParams params = | 118 Widget::InitParams params = |
| 104 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); | 119 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
| 105 params.bounds = gfx::Rect(200, 200); | 120 params.bounds = gfx::Rect(200, 200); |
| 106 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 121 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| 107 widget_.Init(params); | 122 widget_.Init(params); |
| 108 View* container = new View(); | 123 View* container = new View(); |
| 109 widget_.SetContentsView(container); | 124 widget_.SetContentsView(container); |
| 110 | 125 |
| 111 label_ = new Label(); | 126 label_ = new Label(); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 bool IsMenuCommandEnabled(int command_id) { | 229 bool IsMenuCommandEnabled(int command_id) { |
| 215 return label()->IsCommandIdEnabled(command_id); | 230 return label()->IsCommandIdEnabled(command_id); |
| 216 } | 231 } |
| 217 | 232 |
| 218 private: | 233 private: |
| 219 std::unique_ptr<ui::test::EventGenerator> event_generator_; | 234 std::unique_ptr<ui::test::EventGenerator> event_generator_; |
| 220 | 235 |
| 221 DISALLOW_COPY_AND_ASSIGN(LabelSelectionTest); | 236 DISALLOW_COPY_AND_ASSIGN(LabelSelectionTest); |
| 222 }; | 237 }; |
| 223 | 238 |
| 239 // LabelTest harness that runs both with and without secondary UI set to MD. |
| 240 class MDLabelTest : public LabelTest, |
| 241 public ::testing::WithParamInterface<SecondaryUiMode> { |
| 242 public: |
| 243 MDLabelTest() |
| 244 : md_test_api_(ui::MaterialDesignController::Mode::MATERIAL_NORMAL) {} |
| 245 |
| 246 // LabelTest: |
| 247 void OnBaseSetUp() override { |
| 248 md_test_api_.SetSecondaryUiMaterial(GetParam() == SecondaryUiMode::MD); |
| 249 } |
| 250 |
| 251 private: |
| 252 ui::test::MaterialDesignControllerTestAPI md_test_api_; |
| 253 |
| 254 DISALLOW_COPY_AND_ASSIGN(MDLabelTest); |
| 255 }; |
| 256 |
| 224 // Crashes on Linux only. http://crbug.com/612406 | 257 // Crashes on Linux only. http://crbug.com/612406 |
| 225 #if defined(OS_LINUX) | 258 #if defined(OS_LINUX) |
| 226 #define MAYBE_FontPropertySymbol DISABLED_FontPropertySymbol | 259 #define MAYBE_FontPropertySymbol DISABLED_FontPropertySymbol |
| 227 #else | 260 #else |
| 228 #define MAYBE_FontPropertySymbol FontPropertySymbol | 261 #define MAYBE_FontPropertySymbol FontPropertySymbol |
| 229 #endif | 262 #endif |
| 230 TEST_F(LabelTest, MAYBE_FontPropertySymbol) { | 263 TEST_F(LabelTest, MAYBE_FontPropertySymbol) { |
| 231 std::string font_name("symbol"); | 264 std::string font_name("symbol"); |
| 232 gfx::Font font(font_name, 26); | 265 gfx::Font font(font_name, 26); |
| 233 label()->SetFontList(gfx::FontList(font)); | 266 label()->SetFontList(gfx::FontList(font)); |
| (...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 776 label.SizeToPreferredSize(); | 809 label.SizeToPreferredSize(); |
| 777 EXPECT_TRUE(Increased(label.schedule_paint_count(), &count)); | 810 EXPECT_TRUE(Increased(label.schedule_paint_count(), &count)); |
| 778 | 811 |
| 779 label.SetEnabledColor(SK_ColorBLUE); | 812 label.SetEnabledColor(SK_ColorBLUE); |
| 780 EXPECT_TRUE(Increased(label.schedule_paint_count(), &count)); | 813 EXPECT_TRUE(Increased(label.schedule_paint_count(), &count)); |
| 781 | 814 |
| 782 label.SimulatePaint(); | 815 label.SimulatePaint(); |
| 783 EXPECT_EQ(count, label.schedule_paint_count()); // Unchanged. | 816 EXPECT_EQ(count, label.schedule_paint_count()); // Unchanged. |
| 784 } | 817 } |
| 785 | 818 |
| 786 TEST_F(LabelTest, FocusBounds) { | 819 TEST_P(MDLabelTest, FocusBounds) { |
| 787 label()->SetText(ASCIIToUTF16("Example")); | 820 label()->SetText(ASCIIToUTF16("Example")); |
| 788 gfx::Size normal_size = label()->GetPreferredSize(); | 821 Link concrete_link(ASCIIToUTF16("Example")); |
| 789 | 822 Label* link = &concrete_link; // Allow LabelTest to call methods as friend. |
| 790 label()->SetFocusBehavior(View::FocusBehavior::ALWAYS); | 823 link->SetFocusBehavior(View::FocusBehavior::NEVER); |
| 791 label()->RequestFocus(); | |
| 792 gfx::Size focusable_size = label()->GetPreferredSize(); | |
| 793 // Focusable label requires larger size to paint the focus rectangle. | |
| 794 EXPECT_GT(focusable_size.width(), normal_size.width()); | |
| 795 EXPECT_GT(focusable_size.height(), normal_size.height()); | |
| 796 | 824 |
| 797 label()->SizeToPreferredSize(); | 825 label()->SizeToPreferredSize(); |
| 798 gfx::Rect focus_bounds = label()->GetFocusBounds(); | 826 link->SizeToPreferredSize(); |
| 827 |
| 828 // A regular label never draws a focus ring, so it should exactly match the |
| 829 // font height (assuming no glyphs came from fallback fonts). |
| 830 EXPECT_EQ(label()->font_list().GetHeight(), |
| 831 label()->GetFocusRingBounds().height()); |
| 832 |
| 833 // The test starts by setting the link unfocusable, so it should also match. |
| 834 EXPECT_EQ(link->font_list().GetHeight(), link->GetFocusRingBounds().height()); |
| 835 |
| 836 // Labels are not focusable unless they are links, so don't change size when |
| 837 // the focus behavior changes. |
| 838 gfx::Size normal_label_size = label()->GetPreferredSize(); |
| 839 label()->SetFocusBehavior(View::FocusBehavior::ALWAYS); |
| 840 EXPECT_EQ(normal_label_size, label()->GetPreferredSize()); |
| 841 |
| 842 gfx::Size normal_link_size = link->GetPreferredSize(); |
| 843 link->SetFocusBehavior(View::FocusBehavior::ALWAYS); |
| 844 gfx::Size focusable_link_size = link->GetPreferredSize(); |
| 845 if (GetParam() == SecondaryUiMode::MD) { |
| 846 // Everything should match under MD since underlines indicates focus. |
| 847 EXPECT_EQ(normal_label_size, normal_link_size); |
| 848 EXPECT_EQ(normal_link_size, focusable_link_size); |
| 849 } else { |
| 850 // Otherwise, links get bigger in order to paint the focus rectangle. |
| 851 EXPECT_NE(normal_link_size, focusable_link_size); |
| 852 EXPECT_GT(focusable_link_size.width(), normal_link_size.width()); |
| 853 EXPECT_GT(focusable_link_size.height(), normal_link_size.height()); |
| 854 } |
| 855 |
| 856 // Requesting focus doesn't change the preferred size since that would mess up |
| 857 // layout. |
| 858 label()->RequestFocus(); |
| 859 EXPECT_EQ(focusable_link_size, link->GetPreferredSize()); |
| 860 |
| 861 label()->SizeToPreferredSize(); |
| 862 gfx::Rect focus_bounds = label()->GetFocusRingBounds(); |
| 799 EXPECT_EQ(label()->GetLocalBounds().ToString(), focus_bounds.ToString()); | 863 EXPECT_EQ(label()->GetLocalBounds().ToString(), focus_bounds.ToString()); |
| 800 | 864 |
| 865 gfx::Size focusable_size = normal_label_size; |
| 801 label()->SetBounds( | 866 label()->SetBounds( |
| 802 0, 0, focusable_size.width() * 2, focusable_size.height() * 2); | 867 0, 0, focusable_size.width() * 2, focusable_size.height() * 2); |
| 803 label()->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 868 label()->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| 804 focus_bounds = label()->GetFocusBounds(); | 869 focus_bounds = label()->GetFocusRingBounds(); |
| 805 EXPECT_EQ(0, focus_bounds.x()); | 870 EXPECT_EQ(0, focus_bounds.x()); |
| 806 EXPECT_LT(0, focus_bounds.y()); | 871 EXPECT_LT(0, focus_bounds.y()); |
| 807 EXPECT_GT(label()->bounds().bottom(), focus_bounds.bottom()); | 872 EXPECT_GT(label()->bounds().bottom(), focus_bounds.bottom()); |
| 808 EXPECT_EQ(focusable_size.ToString(), focus_bounds.size().ToString()); | 873 EXPECT_EQ(focusable_size.ToString(), focus_bounds.size().ToString()); |
| 809 | 874 |
| 810 label()->SetHorizontalAlignment(gfx::ALIGN_RIGHT); | 875 label()->SetHorizontalAlignment(gfx::ALIGN_RIGHT); |
| 811 focus_bounds = label()->GetFocusBounds(); | 876 focus_bounds = label()->GetFocusRingBounds(); |
| 812 EXPECT_LT(0, focus_bounds.x()); | 877 EXPECT_LT(0, focus_bounds.x()); |
| 813 EXPECT_EQ(label()->bounds().right(), focus_bounds.right()); | 878 EXPECT_EQ(label()->bounds().right(), focus_bounds.right()); |
| 814 EXPECT_LT(0, focus_bounds.y()); | 879 EXPECT_LT(0, focus_bounds.y()); |
| 815 EXPECT_GT(label()->bounds().bottom(), focus_bounds.bottom()); | 880 EXPECT_GT(label()->bounds().bottom(), focus_bounds.bottom()); |
| 816 EXPECT_EQ(focusable_size.ToString(), focus_bounds.size().ToString()); | 881 EXPECT_EQ(focusable_size.ToString(), focus_bounds.size().ToString()); |
| 817 | 882 |
| 818 label()->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 883 label()->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| 819 label()->SetElideBehavior(gfx::FADE_TAIL); | 884 label()->SetElideBehavior(gfx::FADE_TAIL); |
| 820 label()->SetBounds(0, 0, focusable_size.width() / 2, focusable_size.height()); | 885 label()->SetBounds(0, 0, focusable_size.width() / 2, focusable_size.height()); |
| 821 focus_bounds = label()->GetFocusBounds(); | 886 focus_bounds = label()->GetFocusRingBounds(); |
| 822 EXPECT_EQ(0, focus_bounds.x()); | 887 EXPECT_EQ(0, focus_bounds.x()); |
| 823 EXPECT_EQ(focusable_size.width() / 2, focus_bounds.width()); | 888 EXPECT_EQ(focusable_size.width() / 2, focus_bounds.width()); |
| 824 } | 889 } |
| 825 | 890 |
| 826 TEST_F(LabelTest, EmptyLabel) { | 891 TEST_F(LabelTest, EmptyLabel) { |
| 827 label()->SetFocusBehavior(View::FocusBehavior::ALWAYS); | 892 label()->SetFocusBehavior(View::FocusBehavior::ALWAYS); |
| 828 label()->RequestFocus(); | 893 label()->RequestFocus(); |
| 829 label()->SizeToPreferredSize(); | 894 label()->SizeToPreferredSize(); |
| 830 | 895 |
| 831 gfx::Rect focus_bounds = label()->GetFocusBounds(); | 896 Link concrete_link((base::string16())); |
| 832 EXPECT_FALSE(focus_bounds.IsEmpty()); | 897 Label* link = &concrete_link; // Allow LabelTest to call methods as friend. |
| 833 EXPECT_LT(label()->font_list().GetHeight(), focus_bounds.height()); | 898 |
| 899 // With no text, neither links nor labels are focusable, and have no size in |
| 900 // any dimension. |
| 901 EXPECT_EQ(gfx::Rect(), label()->GetFocusRingBounds()); |
| 902 EXPECT_EQ(gfx::Rect(), link->GetFocusRingBounds()); |
| 834 } | 903 } |
| 835 | 904 |
| 836 TEST_F(LabelSelectionTest, Selectable) { | 905 TEST_F(LabelSelectionTest, Selectable) { |
| 837 // By default, labels don't support text selection. | 906 // By default, labels don't support text selection. |
| 838 EXPECT_FALSE(label()->selectable()); | 907 EXPECT_FALSE(label()->selectable()); |
| 839 | 908 |
| 840 ASSERT_TRUE(label()->SetSelectable(true)); | 909 ASSERT_TRUE(label()->SetSelectable(true)); |
| 841 EXPECT_TRUE(label()->selectable()); | 910 EXPECT_TRUE(label()->selectable()); |
| 842 | 911 |
| 843 // Verify that making a label multiline still causes the label to support text | 912 // Verify that making a label multiline still causes the label to support text |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1112 EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_SELECT_ALL)); | 1181 EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_SELECT_ALL)); |
| 1113 label()->SetObscured(false); | 1182 label()->SetObscured(false); |
| 1114 | 1183 |
| 1115 // For an empty label, both COPY and SELECT_ALL should be disabled. | 1184 // For an empty label, both COPY and SELECT_ALL should be disabled. |
| 1116 label()->SetText(base::string16()); | 1185 label()->SetText(base::string16()); |
| 1117 ASSERT_TRUE(label()->SetSelectable(true)); | 1186 ASSERT_TRUE(label()->SetSelectable(true)); |
| 1118 EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_COPY)); | 1187 EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_COPY)); |
| 1119 EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_SELECT_ALL)); | 1188 EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_SELECT_ALL)); |
| 1120 } | 1189 } |
| 1121 | 1190 |
| 1191 INSTANTIATE_TEST_CASE_P(, |
| 1192 MDLabelTest, |
| 1193 ::testing::Values(SecondaryUiMode::MD, |
| 1194 SecondaryUiMode::NON_MD), |
| 1195 &SecondaryUiModeToString); |
| 1196 |
| 1122 } // namespace views | 1197 } // namespace views |
| OLD | NEW |