| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/views/controls/styled_label.h" |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <string> |
| |
| #include "base/macros.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "build/build_config.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "ui/base/ui_base_features.h" |
| #include "ui/gfx/font_list.h" |
| #include "ui/views/border.h" |
| #include "ui/views/controls/link.h" |
| #include "ui/views/controls/styled_label_listener.h" |
| #include "ui/views/style/typography.h" |
| #include "ui/views/test/test_layout_provider.h" |
| #include "ui/views/test/views_test_base.h" |
| #include "ui/views/widget/widget.h" |
| |
| using base::ASCIIToUTF16; |
| |
| namespace views { |
| namespace { |
| |
| enum class SecondaryUiMode { NON_MD, MD }; |
| |
| std::string SecondaryUiModeToString( |
| const ::testing::TestParamInfo<SecondaryUiMode>& info) { |
| return info.param == SecondaryUiMode::MD ? "MD" : "NonMD"; |
| } |
| } // namespace |
| |
| class StyledLabelTest : public ViewsTestBase, public StyledLabelListener { |
| public: |
| StyledLabelTest() {} |
| ~StyledLabelTest() override {} |
| |
| // StyledLabelListener implementation. |
| void StyledLabelLinkClicked(StyledLabel* label, |
| const gfx::Range& range, |
| int event_flags) override {} |
| |
| protected: |
| StyledLabel* styled() { return styled_.get(); } |
| |
| void InitStyledLabel(const std::string& ascii_text) { |
| styled_.reset(new StyledLabel(ASCIIToUTF16(ascii_text), this)); |
| styled_->set_owned_by_client(); |
| } |
| |
| int StyledLabelContentHeightForWidth(int w) { |
| return styled_->GetHeightForWidth(w) - styled_->GetInsets().height(); |
| } |
| |
| private: |
| std::unique_ptr<StyledLabel> styled_; |
| |
| DISALLOW_COPY_AND_ASSIGN(StyledLabelTest); |
| }; |
| |
| // StyledLabelTest harness that runs both with and without secondary UI set to |
| // MD. |
| class MDStyledLabelTest |
| : public StyledLabelTest, |
| public ::testing::WithParamInterface<SecondaryUiMode> { |
| public: |
| MDStyledLabelTest() {} |
| |
| // StyledLabelTest: |
| void SetUp() override { |
| // This works while StyledLabelTest has no SetUp() of its own. Otherwise the |
| // mode should be set after ViewsTestBase::SetUp(), but before the rest of |
| // StyledLabelTest::SetUp(), so that StyledLabelTest::SetUp() obeys the MD |
| // setting. |
| StyledLabelTest::SetUp(); |
| if (GetParam() == SecondaryUiMode::MD) |
| scoped_feature_list_.InitAndEnableFeature(features::kSecondaryUiMd); |
| else |
| scoped_feature_list_.InitAndDisableFeature(features::kSecondaryUiMd); |
| } |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| |
| DISALLOW_COPY_AND_ASSIGN(MDStyledLabelTest); |
| }; |
| |
| TEST_F(StyledLabelTest, NoWrapping) { |
| const std::string text("This is a test block of text"); |
| InitStyledLabel(text); |
| Label label(ASCIIToUTF16(text)); |
| const gfx::Size label_preferred_size = label.GetPreferredSize(); |
| EXPECT_EQ(label_preferred_size.height(), |
| StyledLabelContentHeightForWidth(label_preferred_size.width() * 2)); |
| } |
| |
| TEST_F(StyledLabelTest, TrailingWhitespaceiIgnored) { |
| const std::string text("This is a test block of text "); |
| InitStyledLabel(text); |
| |
| styled()->SetBounds(0, 0, 1000, 1000); |
| styled()->Layout(); |
| |
| ASSERT_EQ(1, styled()->child_count()); |
| ASSERT_EQ(std::string(Label::kViewClassName), |
| styled()->child_at(0)->GetClassName()); |
| EXPECT_EQ(ASCIIToUTF16("This is a test block of text"), |
| static_cast<Label*>(styled()->child_at(0))->text()); |
| } |
| |
| TEST_F(StyledLabelTest, RespectLeadingWhitespace) { |
| const std::string text(" This is a test block of text"); |
| InitStyledLabel(text); |
| |
| styled()->SetBounds(0, 0, 1000, 1000); |
| styled()->Layout(); |
| |
| ASSERT_EQ(1, styled()->child_count()); |
| ASSERT_EQ(std::string(Label::kViewClassName), |
| styled()->child_at(0)->GetClassName()); |
| EXPECT_EQ(ASCIIToUTF16(" This is a test block of text"), |
| static_cast<Label*>(styled()->child_at(0))->text()); |
| } |
| |
| TEST_F(StyledLabelTest, RespectLeadingSpacesInNonFirstLine) { |
| const std::string indented_line = " indented line"; |
| const std::string text(std::string("First line\n") + indented_line); |
| InitStyledLabel(text); |
| styled()->SetBounds(0, 0, 1000, 1000); |
| styled()->Layout(); |
| ASSERT_EQ(2, styled()->child_count()); |
| ASSERT_EQ(std::string(Label::kViewClassName), |
| styled()->child_at(0)->GetClassName()); |
| EXPECT_EQ(ASCIIToUTF16(indented_line), |
| static_cast<Label*>(styled()->child_at(1))->text()); |
| } |
| |
| TEST_F(StyledLabelTest, CorrectWrapAtNewline) { |
| const std::string first_line = "Line one"; |
| const std::string second_line = " two"; |
| const std::string multiline_text(first_line + "\n" + second_line); |
| InitStyledLabel(multiline_text); |
| Label label(ASCIIToUTF16(first_line)); |
| gfx::Size label_preferred_size = label.GetPreferredSize(); |
| // Correct handling of \n and label width limit encountered at the same place |
| styled()->SetBounds(0, 0, label_preferred_size.width(), 1000); |
| styled()->Layout(); |
| ASSERT_EQ(2, styled()->child_count()); |
| ASSERT_EQ(std::string(Label::kViewClassName), |
| styled()->child_at(1)->GetClassName()); |
| EXPECT_EQ(ASCIIToUTF16(first_line), |
| static_cast<Label*>(styled()->child_at(0))->text()); |
| EXPECT_EQ(ASCIIToUTF16(second_line), |
| static_cast<Label*>(styled()->child_at(1))->text()); |
| EXPECT_EQ(styled()->GetHeightForWidth(1000), |
| styled()->child_at(1)->bounds().bottom()); |
| } |
| |
| TEST_F(StyledLabelTest, FirstLineNotEmptyWhenLeadingWhitespaceTooLong) { |
| const std::string text(" a"); |
| InitStyledLabel(text); |
| |
| Label label(ASCIIToUTF16(text)); |
| gfx::Size label_preferred_size = label.GetPreferredSize(); |
| |
| styled()->SetBounds(0, 0, label_preferred_size.width() / 2, 1000); |
| styled()->Layout(); |
| |
| ASSERT_EQ(1, styled()->child_count()); |
| ASSERT_EQ(std::string(Label::kViewClassName), |
| styled()->child_at(0)->GetClassName()); |
| EXPECT_EQ(ASCIIToUTF16("a"), |
| static_cast<Label*>(styled()->child_at(0))->text()); |
| EXPECT_EQ(label_preferred_size.height(), |
| styled()->GetHeightForWidth(label_preferred_size.width() / 2)); |
| } |
| |
| TEST_F(StyledLabelTest, BasicWrapping) { |
| const std::string text("This is a test block of text"); |
| InitStyledLabel(text); |
| Label label(ASCIIToUTF16(text.substr(0, text.size() * 2 / 3))); |
| gfx::Size label_preferred_size = label.GetPreferredSize(); |
| EXPECT_EQ(label_preferred_size.height() * 2, |
| StyledLabelContentHeightForWidth(label_preferred_size.width())); |
| |
| // Also respect the border. |
| styled()->SetBorder(CreateEmptyBorder(3, 3, 3, 3)); |
| styled()->SetBounds( |
| 0, |
| 0, |
| styled()->GetInsets().width() + label_preferred_size.width(), |
| styled()->GetInsets().height() + 2 * label_preferred_size.height()); |
| styled()->Layout(); |
| ASSERT_EQ(2, styled()->child_count()); |
| EXPECT_EQ(3, styled()->child_at(0)->x()); |
| EXPECT_EQ(3, styled()->child_at(0)->y()); |
| EXPECT_EQ(styled()->height() - 3, styled()->child_at(1)->bounds().bottom()); |
| } |
| |
| TEST_F(StyledLabelTest, AllowEmptyLines) { |
| const std::string text("one"); |
| InitStyledLabel(text); |
| int default_height = styled()->GetHeightForWidth(1000); |
| const std::string multiline_text("one\n\nthree"); |
| InitStyledLabel(multiline_text); |
| styled()->SetBounds(0, 0, 1000, 1000); |
| styled()->Layout(); |
| EXPECT_EQ(3 * default_height, styled()->GetHeightForWidth(1000)); |
| ASSERT_EQ(2, styled()->child_count()); |
| EXPECT_EQ(styled()->GetHeightForWidth(1000), |
| styled()->child_at(1)->bounds().bottom()); |
| } |
| |
| TEST_F(StyledLabelTest, WrapLongWords) { |
| const std::string text("ThisIsTextAsASingleWord"); |
| InitStyledLabel(text); |
| Label label(ASCIIToUTF16(text.substr(0, text.size() * 2 / 3))); |
| gfx::Size label_preferred_size = label.GetPreferredSize(); |
| EXPECT_EQ(label_preferred_size.height() * 2, |
| StyledLabelContentHeightForWidth(label_preferred_size.width())); |
| |
| styled()->SetBounds( |
| 0, 0, styled()->GetInsets().width() + label_preferred_size.width(), |
| styled()->GetInsets().height() + 2 * label_preferred_size.height()); |
| styled()->Layout(); |
| |
| ASSERT_EQ(2, styled()->child_count()); |
| ASSERT_EQ(gfx::Point(), styled()->origin()); |
| EXPECT_EQ(gfx::Point(), styled()->child_at(0)->origin()); |
| EXPECT_EQ(gfx::Point(0, styled()->height() / 2), |
| styled()->child_at(1)->origin()); |
| |
| EXPECT_FALSE(static_cast<Label*>(styled()->child_at(0))->text().empty()); |
| EXPECT_FALSE(static_cast<Label*>(styled()->child_at(1))->text().empty()); |
| EXPECT_EQ(ASCIIToUTF16(text), |
| static_cast<Label*>(styled()->child_at(0))->text() + |
| static_cast<Label*>(styled()->child_at(1))->text()); |
| } |
| |
| TEST_P(MDStyledLabelTest, CreateLinks) { |
| const std::string text("This is a test block of text."); |
| InitStyledLabel(text); |
| |
| // Without links, there should be no focus border. |
| EXPECT_TRUE(styled()->GetInsets().IsEmpty()); |
| |
| // Now let's add some links. |
| styled()->AddStyleRange(gfx::Range(0, 1), |
| StyledLabel::RangeStyleInfo::CreateForLink()); |
| styled()->AddStyleRange(gfx::Range(1, 2), |
| StyledLabel::RangeStyleInfo::CreateForLink()); |
| styled()->AddStyleRange(gfx::Range(10, 11), |
| StyledLabel::RangeStyleInfo::CreateForLink()); |
| styled()->AddStyleRange(gfx::Range(12, 13), |
| StyledLabel::RangeStyleInfo::CreateForLink()); |
| |
| if (GetParam() == SecondaryUiMode::MD) { |
| // Insets shouldn't change under MD when links are added, since the links |
| // indicate focus by adding an underline instead. |
| EXPECT_TRUE(styled()->GetInsets().IsEmpty()); |
| } else { |
| // Now there should be a focus border because there are non-empty Links. |
| EXPECT_FALSE(styled()->GetInsets().IsEmpty()); |
| } |
| |
| // Verify layout creates the right number of children. |
| styled()->SetBounds(0, 0, 1000, 1000); |
| styled()->Layout(); |
| EXPECT_EQ(7, styled()->child_count()); |
| } |
| |
| TEST_P(MDStyledLabelTest, DontBreakLinks) { |
| const std::string text("This is a test block of text, "); |
| const std::string link_text("and this should be a link"); |
| InitStyledLabel(text + link_text); |
| styled()->AddStyleRange( |
| gfx::Range(static_cast<uint32_t>(text.size()), |
| static_cast<uint32_t>(text.size() + link_text.size())), |
| StyledLabel::RangeStyleInfo::CreateForLink()); |
| |
| Label label(ASCIIToUTF16(text + link_text.substr(0, link_text.size() / 2))); |
| gfx::Size label_preferred_size = label.GetPreferredSize(); |
| int pref_height = styled()->GetHeightForWidth(label_preferred_size.width()); |
| EXPECT_EQ(label_preferred_size.height() * 2, |
| pref_height - styled()->GetInsets().height()); |
| |
| styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height); |
| styled()->Layout(); |
| ASSERT_EQ(2, styled()->child_count()); |
| |
| if (GetParam() == SecondaryUiMode::MD) { |
| // No additional insets should be added under MD. |
| EXPECT_EQ(0, styled()->child_at(0)->x()); |
| } else { |
| // The label has no focus border while, when non-MD, the link (and thus |
| // overall styled label) does, so the label should be inset by the width of |
| // the focus border. |
| EXPECT_EQ(Link::kFocusBorderPadding, styled()->child_at(0)->x()); |
| } |
| // The Link shouldn't be offset (it grows in size under non-MD instead). |
| EXPECT_EQ(0, styled()->child_at(1)->x()); |
| } |
| |
| TEST_F(StyledLabelTest, StyledRangeWithDisabledLineWrapping) { |
| const std::string text("This is a test block of text, "); |
| const std::string unbreakable_text("and this should not be broken"); |
| InitStyledLabel(text + unbreakable_text); |
| StyledLabel::RangeStyleInfo style_info; |
| style_info.disable_line_wrapping = true; |
| styled()->AddStyleRange( |
| gfx::Range(static_cast<uint32_t>(text.size()), |
| static_cast<uint32_t>(text.size() + unbreakable_text.size())), |
| style_info); |
| |
| Label label(ASCIIToUTF16( |
| text + unbreakable_text.substr(0, unbreakable_text.size() / 2))); |
| gfx::Size label_preferred_size = label.GetPreferredSize(); |
| int pref_height = styled()->GetHeightForWidth(label_preferred_size.width()); |
| EXPECT_EQ(label_preferred_size.height() * 2, |
| pref_height - styled()->GetInsets().height()); |
| |
| styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height); |
| styled()->Layout(); |
| ASSERT_EQ(2, styled()->child_count()); |
| EXPECT_EQ(0, styled()->child_at(0)->x()); |
| EXPECT_EQ(0, styled()->child_at(1)->x()); |
| } |
| |
| TEST_F(StyledLabelTest, StyledRangeCustomFontUnderlined) { |
| const std::string text("This is a test block of text, "); |
| const std::string underlined_text("and this should be undelined"); |
| InitStyledLabel(text + underlined_text); |
| StyledLabel::RangeStyleInfo style_info; |
| style_info.tooltip = ASCIIToUTF16("tooltip"); |
| style_info.custom_font = |
| styled()->GetDefaultFontList().DeriveWithStyle(gfx::Font::UNDERLINE); |
| styled()->AddStyleRange( |
| gfx::Range(static_cast<uint32_t>(text.size()), |
| static_cast<uint32_t>(text.size() + underlined_text.size())), |
| style_info); |
| |
| styled()->SetBounds(0, 0, 1000, 1000); |
| styled()->Layout(); |
| |
| ASSERT_EQ(2, styled()->child_count()); |
| ASSERT_EQ(std::string(Label::kViewClassName), |
| styled()->child_at(1)->GetClassName()); |
| EXPECT_EQ( |
| gfx::Font::UNDERLINE, |
| static_cast<Label*>(styled()->child_at(1))->font_list().GetFontStyle()); |
| } |
| |
| TEST_F(StyledLabelTest, StyledRangeTextStyleBold) { |
| test::TestLayoutProvider bold_provider; |
| const std::string bold_text( |
| "This is a block of text whose style will be set to BOLD in the test"); |
| const std::string text(" normal text"); |
| InitStyledLabel(bold_text + text); |
| |
| // Pretend disabled text becomes bold for testing. |
| bold_provider.SetFont( |
| style::CONTEXT_LABEL, style::STYLE_DISABLED, |
| styled()->GetDefaultFontList().DeriveWithWeight(gfx::Font::Weight::BOLD)); |
| |
| StyledLabel::RangeStyleInfo style_info; |
| style_info.text_style = style::STYLE_DISABLED; |
| styled()->AddStyleRange( |
| gfx::Range(0u, static_cast<uint32_t>(bold_text.size())), style_info); |
| |
| // Calculate the bold text width if it were a pure label view, both with bold |
| // and normal style. |
| Label label(ASCIIToUTF16(bold_text)); |
| const gfx::Size normal_label_size = label.GetPreferredSize(); |
| label.SetFontList( |
| label.font_list().DeriveWithWeight(gfx::Font::Weight::BOLD)); |
| const gfx::Size bold_label_size = label.GetPreferredSize(); |
| |
| ASSERT_GE(bold_label_size.width(), normal_label_size.width()); |
| |
| // Set the width so |bold_text| doesn't fit on a single line with bold style, |
| // but does with normal font style. |
| int styled_width = (normal_label_size.width() + bold_label_size.width()) / 2; |
| int pref_height = styled()->GetHeightForWidth(styled_width); |
| |
| // Sanity check that |bold_text| with normal font style would fit on a single |
| // line in a styled label with width |styled_width|. |
| StyledLabel unstyled(ASCIIToUTF16(bold_text), this); |
| unstyled.SetBounds(0, 0, styled_width, pref_height); |
| unstyled.Layout(); |
| EXPECT_EQ(1, unstyled.child_count()); |
| |
| styled()->SetBounds(0, 0, styled_width, pref_height); |
| styled()->Layout(); |
| |
| ASSERT_EQ(3, styled()->child_count()); |
| |
| // The bold text should be broken up into two parts. |
| ASSERT_EQ(std::string(Label::kViewClassName), |
| styled()->child_at(0)->GetClassName()); |
| EXPECT_EQ( |
| gfx::Font::Weight::BOLD, |
| static_cast<Label*>(styled()->child_at(0))->font_list().GetFontWeight()); |
| ASSERT_EQ(std::string(Label::kViewClassName), |
| styled()->child_at(1)->GetClassName()); |
| EXPECT_EQ( |
| gfx::Font::Weight::BOLD, |
| static_cast<Label*>(styled()->child_at(1))->font_list().GetFontWeight()); |
| ASSERT_EQ(std::string(Label::kViewClassName), |
| styled()->child_at(2)->GetClassName()); |
| EXPECT_EQ( |
| gfx::Font::NORMAL, |
| static_cast<Label*>(styled()->child_at(2))->font_list().GetFontStyle()); |
| |
| // The second bold part should start on a new line. |
| EXPECT_EQ(0, styled()->child_at(0)->x()); |
| EXPECT_EQ(0, styled()->child_at(1)->x()); |
| EXPECT_EQ(styled()->child_at(1)->bounds().right(), |
| styled()->child_at(2)->x()); |
| } |
| |
| TEST_F(StyledLabelTest, Color) { |
| const std::string text_red("RED"); |
| const std::string text_link("link"); |
| const std::string text("word"); |
| InitStyledLabel(text_red + text_link + text); |
| |
| StyledLabel::RangeStyleInfo style_info_red; |
| style_info_red.override_color = SK_ColorRED; |
| styled()->AddStyleRange( |
| gfx::Range(0u, static_cast<uint32_t>(text_red.size())), style_info_red); |
| |
| StyledLabel::RangeStyleInfo style_info_link = |
| StyledLabel::RangeStyleInfo::CreateForLink(); |
| styled()->AddStyleRange( |
| gfx::Range(static_cast<uint32_t>(text_red.size()), |
| static_cast<uint32_t>(text_red.size() + text_link.size())), |
| style_info_link); |
| |
| styled()->SetBounds(0, 0, 1000, 1000); |
| styled()->Layout(); |
| |
| Widget* widget = new Widget(); |
| Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
| widget->Init(params); |
| View* container = new View(); |
| widget->SetContentsView(container); |
| container->AddChildView(styled()); |
| |
| // Obtain the default text color for a label. |
| Label* label = new Label(ASCIIToUTF16(text)); |
| container->AddChildView(label); |
| const SkColor kDefaultTextColor = label->enabled_color(); |
| |
| // Obtain the default text color for a link. |
| Link* link = new Link(ASCIIToUTF16(text_link)); |
| container->AddChildView(link); |
| const SkColor kDefaultLinkColor = link->enabled_color(); |
| |
| EXPECT_EQ(SK_ColorRED, |
| static_cast<Label*>(styled()->child_at(0))->enabled_color()); |
| EXPECT_EQ(kDefaultLinkColor, |
| static_cast<Label*>(styled()->child_at(1))->enabled_color()); |
| EXPECT_EQ(kDefaultTextColor, |
| static_cast<Label*>(styled()->child_at(2))->enabled_color()); |
| |
| // Test adjusted color readability. |
| styled()->SetDisplayedOnBackgroundColor(SK_ColorBLACK); |
| styled()->Layout(); |
| label->SetBackgroundColor(SK_ColorBLACK); |
| |
| const SkColor kAdjustedTextColor = label->enabled_color(); |
| EXPECT_NE(kAdjustedTextColor, kDefaultTextColor); |
| EXPECT_EQ(kAdjustedTextColor, |
| static_cast<Label*>(styled()->child_at(2))->enabled_color()); |
| |
| widget->CloseNow(); |
| } |
| |
| TEST_P(MDStyledLabelTest, StyledRangeWithTooltip) { |
| const std::string text("This is a test block of text, "); |
| const std::string tooltip_text("this should have a tooltip,"); |
| const std::string normal_text(" this should not have a tooltip, "); |
| const std::string link_text("and this should be a link"); |
| |
| const size_t tooltip_start = text.size(); |
| const size_t link_start = |
| text.size() + tooltip_text.size() + normal_text.size(); |
| |
| InitStyledLabel(text + tooltip_text + normal_text + link_text); |
| StyledLabel::RangeStyleInfo tooltip_style; |
| tooltip_style.tooltip = ASCIIToUTF16("tooltip"); |
| styled()->AddStyleRange( |
| gfx::Range(static_cast<uint32_t>(tooltip_start), |
| static_cast<uint32_t>(tooltip_start + tooltip_text.size())), |
| tooltip_style); |
| styled()->AddStyleRange( |
| gfx::Range(static_cast<uint32_t>(link_start), |
| static_cast<uint32_t>(link_start + link_text.size())), |
| StyledLabel::RangeStyleInfo::CreateForLink()); |
| |
| // Break line inside the range with the tooltip. |
| Label label(ASCIIToUTF16( |
| text + tooltip_text.substr(0, tooltip_text.size() - 3))); |
| gfx::Size label_preferred_size = label.GetPreferredSize(); |
| int pref_height = styled()->GetHeightForWidth(label_preferred_size.width()); |
| EXPECT_EQ(label_preferred_size.height() * 3, |
| pref_height - styled()->GetInsets().height()); |
| |
| styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height); |
| styled()->Layout(); |
| |
| EXPECT_EQ(label_preferred_size.width(), styled()->width()); |
| |
| ASSERT_EQ(5, styled()->child_count()); |
| |
| if (GetParam() == SecondaryUiMode::MD) { |
| // In MD, the labels shouldn't be offset to cater for focus rings. |
| EXPECT_EQ(0, styled()->child_at(0)->x()); |
| EXPECT_EQ(0, styled()->child_at(2)->x()); |
| } else { |
| // The labels have no focus border while the link (and thus overall styled |
| // label) does, so the labels should be inset by the width of the focus |
| // border. |
| EXPECT_EQ(Link::kFocusBorderPadding, styled()->child_at(0)->x()); |
| EXPECT_EQ(Link::kFocusBorderPadding, styled()->child_at(2)->x()); |
| } |
| |
| EXPECT_EQ(styled()->child_at(0)->bounds().right(), |
| styled()->child_at(1)->x()); |
| EXPECT_EQ(styled()->child_at(2)->bounds().right(), |
| styled()->child_at(3)->x()); |
| EXPECT_EQ(0, styled()->child_at(4)->x()); |
| |
| base::string16 tooltip; |
| EXPECT_TRUE( |
| styled()->child_at(1)->GetTooltipText(gfx::Point(1, 1), &tooltip)); |
| EXPECT_EQ(ASCIIToUTF16("tooltip"), tooltip); |
| EXPECT_TRUE( |
| styled()->child_at(2)->GetTooltipText(gfx::Point(1, 1), &tooltip)); |
| EXPECT_EQ(ASCIIToUTF16("tooltip"), tooltip); |
| } |
| |
| TEST_F(StyledLabelTest, SetTextContextAndDefaultStyle) { |
| const std::string text("This is a test block of text."); |
| InitStyledLabel(text); |
| styled()->SetTextContext(style::CONTEXT_DIALOG_TITLE); |
| styled()->SetDefaultTextStyle(style::STYLE_DISABLED); |
| Label label(ASCIIToUTF16(text), style::CONTEXT_DIALOG_TITLE, |
| style::STYLE_DISABLED); |
| |
| styled()->SetBounds(0, |
| 0, |
| label.GetPreferredSize().width(), |
| label.GetPreferredSize().height()); |
| |
| // Make sure we have the same sizing as a label with the same style. |
| EXPECT_EQ(label.GetPreferredSize().height(), styled()->height()); |
| EXPECT_EQ(label.GetPreferredSize().width(), styled()->width()); |
| |
| styled()->Layout(); |
| ASSERT_EQ(1, styled()->child_count()); |
| Label* sublabel = static_cast<Label*>(styled()->child_at(0)); |
| EXPECT_EQ(style::CONTEXT_DIALOG_TITLE, sublabel->text_context()); |
| |
| EXPECT_NE(SK_ColorBLACK, label.enabled_color()); // Sanity check, |
| EXPECT_EQ(label.enabled_color(), sublabel->enabled_color()); |
| } |
| |
| TEST_F(StyledLabelTest, LineHeight) { |
| const std::string text("one"); |
| InitStyledLabel(text); |
| int default_height = styled()->GetHeightForWidth(100); |
| const std::string newline_text("one\ntwo\nthree"); |
| InitStyledLabel(newline_text); |
| styled()->SetLineHeight(18); |
| EXPECT_EQ(18 * 2 + default_height, styled()->GetHeightForWidth(100)); |
| } |
| |
| TEST_F(StyledLabelTest, HandleEmptyLayout) { |
| const std::string text("This is a test block of text."); |
| InitStyledLabel(text); |
| styled()->Layout(); |
| EXPECT_EQ(0, styled()->child_count()); |
| } |
| |
| TEST_F(StyledLabelTest, CacheSize) { |
| const int preferred_height = 50; |
| const int preferred_width = 100; |
| const std::string text("This is a test block of text."); |
| const base::string16 another_text(base::ASCIIToUTF16( |
| "This is a test block of text. This text is much longer than previous")); |
| |
| InitStyledLabel(text); |
| |
| // we should be able to calculate height without any problem |
| // no controls should be created |
| int precalculated_height = styled()->GetHeightForWidth(preferred_width); |
| EXPECT_LT(0, precalculated_height); |
| EXPECT_EQ(0, styled()->child_count()); |
| |
| styled()->SetBounds(0, 0, preferred_width, preferred_height); |
| styled()->Layout(); |
| |
| // controls should be created after layout |
| // height should be the same as precalculated |
| int real_height = styled()->GetHeightForWidth(styled()->width()); |
| View* first_child_after_layout = styled()->has_children() ? |
| styled()->child_at(0) : nullptr; |
| EXPECT_LT(0, styled()->child_count()); |
| EXPECT_LT(0, real_height); |
| EXPECT_EQ(real_height, precalculated_height); |
| |
| // another call to Layout should not kill and recreate all controls |
| styled()->Layout(); |
| View* first_child_after_second_layout = styled()->has_children() ? |
| styled()->child_at(0) : nullptr; |
| EXPECT_EQ(first_child_after_layout, first_child_after_second_layout); |
| |
| // if text is changed: |
| // layout should be recalculated |
| // all controls should be recreated |
| styled()->SetText(another_text); |
| int updated_height = styled()->GetHeightForWidth(styled()->width()); |
| EXPECT_NE(updated_height, real_height); |
| View* first_child_after_text_update = styled()->has_children() ? |
| styled()->child_at(0) : nullptr; |
| EXPECT_NE(first_child_after_text_update, first_child_after_layout); |
| } |
| |
| TEST_F(StyledLabelTest, Border) { |
| const std::string text("One line"); |
| InitStyledLabel(text); |
| Label label(ASCIIToUTF16(text)); |
| gfx::Size label_preferred_size = label.GetPreferredSize(); |
| styled()->SetBorder( |
| CreateEmptyBorder(5 /*top*/, 10 /*left*/, 6 /*bottom*/, 20 /*right*/)); |
| styled()->SetBounds(0, 0, 1000, 0); |
| styled()->Layout(); |
| EXPECT_EQ( |
| label_preferred_size.height() + 5 /*top border*/ + 6 /*bottom border*/, |
| styled()->GetPreferredSize().height()); |
| EXPECT_EQ( |
| label_preferred_size.width() + 10 /*left border*/ + 20 /*right border*/, |
| styled()->GetPreferredSize().width()); |
| } |
| |
| INSTANTIATE_TEST_CASE_P(, |
| MDStyledLabelTest, |
| ::testing::Values(SecondaryUiMode::MD, |
| SecondaryUiMode::NON_MD), |
| &SecondaryUiModeToString); |
| |
| } // namespace views |