Home | History | Annotate | Download | only in controls
      1 // Copyright 2013 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 <string>
      6 
      7 #include "base/basictypes.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "testing/gtest/include/gtest/gtest.h"
     11 #include "third_party/skia/include/core/SkColor.h"
     12 #include "ui/views/controls/link.h"
     13 #include "ui/views/controls/styled_label.h"
     14 #include "ui/views/controls/styled_label_listener.h"
     15 
     16 namespace views {
     17 
     18 class StyledLabelTest : public testing::Test, public StyledLabelListener {
     19  public:
     20   StyledLabelTest() {}
     21   virtual ~StyledLabelTest() {}
     22 
     23   // StyledLabelListener implementation.
     24   virtual void StyledLabelLinkClicked(const ui::Range& range,
     25                                       int event_flags) OVERRIDE {}
     26 
     27  protected:
     28   StyledLabel* styled() { return styled_.get(); }
     29 
     30   void InitStyledLabel(const std::string& ascii_text) {
     31     styled_.reset(new StyledLabel(ASCIIToUTF16(ascii_text), this));
     32   }
     33 
     34   int StyledLabelContentHeightForWidth(int w) {
     35     return styled_->GetHeightForWidth(w) - styled_->GetInsets().height();
     36   }
     37 
     38  private:
     39   scoped_ptr<StyledLabel> styled_;
     40 
     41   DISALLOW_COPY_AND_ASSIGN(StyledLabelTest);
     42 };
     43 
     44 TEST_F(StyledLabelTest, NoWrapping) {
     45   const std::string text("This is a test block of text");
     46   InitStyledLabel(text);
     47   Label label(ASCIIToUTF16(text));
     48   const gfx::Size label_preferred_size = label.GetPreferredSize();
     49   EXPECT_EQ(label_preferred_size.height(),
     50             StyledLabelContentHeightForWidth(label_preferred_size.width() * 2));
     51 }
     52 
     53 TEST_F(StyledLabelTest, TrailingWhitespaceiIgnored) {
     54   const std::string text("This is a test block of text   ");
     55   InitStyledLabel(text);
     56 
     57   styled()->SetBounds(0, 0, 1000, 1000);
     58   styled()->Layout();
     59 
     60   ASSERT_EQ(1, styled()->child_count());
     61   ASSERT_EQ(std::string(Label::kViewClassName),
     62             styled()->child_at(0)->GetClassName());
     63   EXPECT_EQ(ASCIIToUTF16("This is a test block of text"),
     64             static_cast<Label*>(styled()->child_at(0))->text());
     65 }
     66 
     67 TEST_F(StyledLabelTest, RespectLeadingWhitespace) {
     68   const std::string text("   This is a test block of text");
     69   InitStyledLabel(text);
     70 
     71   styled()->SetBounds(0, 0, 1000, 1000);
     72   styled()->Layout();
     73 
     74   ASSERT_EQ(1, styled()->child_count());
     75   ASSERT_EQ(std::string(Label::kViewClassName),
     76             styled()->child_at(0)->GetClassName());
     77   EXPECT_EQ(ASCIIToUTF16("   This is a test block of text"),
     78             static_cast<Label*>(styled()->child_at(0))->text());
     79 }
     80 
     81 TEST_F(StyledLabelTest, FirstLineNotEmptyWhenLeadingWhitespaceTooLong) {
     82   const std::string text("                                     a");
     83   InitStyledLabel(text);
     84 
     85   Label label(ASCIIToUTF16(text));
     86   gfx::Size label_preferred_size = label.GetPreferredSize();
     87 
     88   styled()->SetBounds(0, 0, label_preferred_size.width() / 2, 1000);
     89   styled()->Layout();
     90 
     91   ASSERT_EQ(1, styled()->child_count());
     92   ASSERT_EQ(std::string(Label::kViewClassName),
     93             styled()->child_at(0)->GetClassName());
     94   EXPECT_EQ(ASCIIToUTF16("a"),
     95             static_cast<Label*>(styled()->child_at(0))->text());
     96 }
     97 
     98 TEST_F(StyledLabelTest, BasicWrapping) {
     99   const std::string text("This is a test block of text");
    100   InitStyledLabel(text);
    101   Label label(ASCIIToUTF16(text.substr(0, text.size() * 2 / 3)));
    102   gfx::Size label_preferred_size = label.GetPreferredSize();
    103   EXPECT_EQ(label_preferred_size.height() * 2,
    104             StyledLabelContentHeightForWidth(label_preferred_size.width()));
    105 
    106   // Also respect the border.
    107   styled()->set_border(Border::CreateEmptyBorder(3, 3, 3, 3));
    108   styled()->SetBounds(
    109       0,
    110       0,
    111       styled()->GetInsets().width() + label_preferred_size.width(),
    112       styled()->GetInsets().height() + 2 * label_preferred_size.height());
    113   styled()->Layout();
    114   ASSERT_EQ(2, styled()->child_count());
    115   EXPECT_EQ(3, styled()->child_at(0)->bounds().x());
    116   EXPECT_EQ(3, styled()->child_at(0)->bounds().y());
    117   EXPECT_EQ(styled()->bounds().height() - 3,
    118             styled()->child_at(1)->bounds().bottom());
    119 }
    120 
    121 TEST_F(StyledLabelTest, CreateLinks) {
    122   const std::string text("This is a test block of text.");
    123   InitStyledLabel(text);
    124   styled()->AddStyleRange(ui::Range(0, 1),
    125                           StyledLabel::RangeStyleInfo::CreateForLink());
    126   styled()->AddStyleRange(ui::Range(1, 2),
    127                           StyledLabel::RangeStyleInfo::CreateForLink());
    128   styled()->AddStyleRange(ui::Range(10, 11),
    129                           StyledLabel::RangeStyleInfo::CreateForLink());
    130   styled()->AddStyleRange(ui::Range(12, 13),
    131                           StyledLabel::RangeStyleInfo::CreateForLink());
    132 
    133   styled()->SetBounds(0, 0, 1000, 1000);
    134   styled()->Layout();
    135   ASSERT_EQ(7, styled()->child_count());
    136 }
    137 
    138 TEST_F(StyledLabelTest, DontBreakLinks) {
    139   const std::string text("This is a test block of text, ");
    140   const std::string link_text("and this should be a link");
    141   InitStyledLabel(text + link_text);
    142   styled()->AddStyleRange(
    143       ui::Range(text.size(), text.size() + link_text.size()),
    144       StyledLabel::RangeStyleInfo::CreateForLink());
    145 
    146   Label label(ASCIIToUTF16(text + link_text.substr(0, link_text.size() / 2)));
    147   gfx::Size label_preferred_size = label.GetPreferredSize();
    148   int pref_height = styled()->GetHeightForWidth(label_preferred_size.width());
    149   EXPECT_EQ(label_preferred_size.height() * 2,
    150             pref_height - styled()->GetInsets().height());
    151 
    152   styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height);
    153   styled()->Layout();
    154   ASSERT_EQ(2, styled()->child_count());
    155   EXPECT_EQ(0, styled()->child_at(0)->bounds().x());
    156   EXPECT_EQ(0, styled()->child_at(1)->bounds().x());
    157 }
    158 
    159 TEST_F(StyledLabelTest, StyledRangeWithDisabledLineWrapping) {
    160   const std::string text("This is a test block of text, ");
    161   const std::string unbreakable_text("and this should not be breaked");
    162   InitStyledLabel(text + unbreakable_text);
    163   StyledLabel::RangeStyleInfo style_info;
    164   style_info.disable_line_wrapping = true;
    165   styled()->AddStyleRange(
    166       ui::Range(text.size(), text.size() + unbreakable_text.size()),
    167       style_info);
    168 
    169   Label label(ASCIIToUTF16(
    170       text + unbreakable_text.substr(0, unbreakable_text.size() / 2)));
    171   gfx::Size label_preferred_size = label.GetPreferredSize();
    172   int pref_height = styled()->GetHeightForWidth(label_preferred_size.width());
    173   EXPECT_EQ(label_preferred_size.height() * 2,
    174             pref_height - styled()->GetInsets().height());
    175 
    176   styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height);
    177   styled()->Layout();
    178   ASSERT_EQ(2, styled()->child_count());
    179   EXPECT_EQ(0, styled()->child_at(0)->bounds().x());
    180   EXPECT_EQ(0, styled()->child_at(1)->bounds().x());
    181 }
    182 
    183 TEST_F(StyledLabelTest, StyledRangeUnderlined) {
    184   const std::string text("This is a test block of text, ");
    185   const std::string underlined_text("and this should be undelined");
    186   InitStyledLabel(text + underlined_text);
    187   StyledLabel::RangeStyleInfo style_info;
    188   style_info.font_style = gfx::Font::UNDERLINE;
    189   styled()->AddStyleRange(
    190       ui::Range(text.size(), text.size() + underlined_text.size()),
    191       style_info);
    192 
    193   styled()->SetBounds(0, 0, 1000, 1000);
    194   styled()->Layout();
    195 
    196   ASSERT_EQ(2, styled()->child_count());
    197   ASSERT_EQ(std::string(Label::kViewClassName),
    198             styled()->child_at(1)->GetClassName());
    199   EXPECT_EQ(gfx::Font::UNDERLINE,
    200             static_cast<Label*>(styled()->child_at(1))->font().GetStyle());
    201 }
    202 
    203 TEST_F(StyledLabelTest, StyledRangeBold) {
    204   const std::string bold_text(
    205       "This is a block of text whose style will be set to BOLD in the test");
    206   const std::string text(" normal text");
    207   InitStyledLabel(bold_text + text);
    208 
    209   StyledLabel::RangeStyleInfo style_info;
    210   style_info.font_style = gfx::Font::BOLD;
    211   styled()->AddStyleRange(ui::Range(0, bold_text.size()), style_info);
    212 
    213   // Calculate the bold text width if it were a pure label view, both with bold
    214   // and normal style.
    215   Label label(ASCIIToUTF16(bold_text));
    216   const gfx::Size normal_label_size = label.GetPreferredSize();
    217   label.SetFont(label.font().DeriveFont(0, gfx::Font::BOLD));
    218   const gfx::Size bold_label_size = label.GetPreferredSize();
    219 
    220   ASSERT_GE(bold_label_size.width(), normal_label_size.width());
    221 
    222   // Set the width so |bold_text| doesn't fit on a single line with bold style,
    223   // but does with normal font style.
    224   int styled_width = (normal_label_size.width() + bold_label_size.width()) / 2;
    225   int pref_height = styled()->GetHeightForWidth(styled_width);
    226 
    227   // Sanity check that |bold_text| with normal font style would fit on a single
    228   // line in a styled label with width |styled_width|.
    229   StyledLabel unstyled(ASCIIToUTF16(bold_text), this);
    230   unstyled.SetBounds(0, 0, styled_width, pref_height);
    231   unstyled.Layout();
    232   ASSERT_EQ(1, unstyled.child_count());
    233 
    234   styled()->SetBounds(0, 0, styled_width, pref_height);
    235   styled()->Layout();
    236 
    237   ASSERT_EQ(3, styled()->child_count());
    238 
    239   // The bold text should be broken up into two parts.
    240   ASSERT_EQ(std::string(Label::kViewClassName),
    241             styled()->child_at(0)->GetClassName());
    242   EXPECT_EQ(gfx::Font::BOLD,
    243             static_cast<Label*>(styled()->child_at(0))->font().GetStyle());
    244   ASSERT_EQ(std::string(Label::kViewClassName),
    245             styled()->child_at(1)->GetClassName());
    246   EXPECT_EQ(gfx::Font::BOLD,
    247             static_cast<Label*>(styled()->child_at(1))->font().GetStyle());
    248   ASSERT_EQ(std::string(Label::kViewClassName),
    249             styled()->child_at(2)->GetClassName());
    250   EXPECT_EQ(gfx::Font::NORMAL,
    251             static_cast<Label*>(styled()->child_at(2))->font().GetStyle());
    252 
    253   // The second bold part should start on a new line.
    254   EXPECT_EQ(0, styled()->child_at(0)->bounds().x());
    255   EXPECT_EQ(0, styled()->child_at(1)->bounds().x());
    256   EXPECT_EQ(styled()->child_at(1)->bounds().right() - 2,
    257             styled()->child_at(2)->bounds().x());
    258 }
    259 
    260 TEST_F(StyledLabelTest, Color) {
    261   const std::string text_red("RED");
    262   const std::string text_link("link");
    263   const std::string text("word");
    264   InitStyledLabel(text_red + text_link + text);
    265 
    266   StyledLabel::RangeStyleInfo style_info_red;
    267   style_info_red.color = SK_ColorRED;
    268   styled()->AddStyleRange(ui::Range(0, text_red.size()), style_info_red);
    269 
    270   StyledLabel::RangeStyleInfo style_info_link =
    271       StyledLabel::RangeStyleInfo::CreateForLink();
    272   styled()->AddStyleRange(ui::Range(text_red.size(),
    273                                     text_red.size() + text_link.size()),
    274                           style_info_link);
    275 
    276   // Obtain the default text color for a label.
    277   Label label(ASCIIToUTF16(text));
    278   const SkColor kDefaultTextColor = label.enabled_color();
    279 
    280   // Obtain the default text color for a link;
    281   Link link(ASCIIToUTF16(text_link));
    282   const SkColor kDefaultLinkColor = link.enabled_color();
    283 
    284   styled()->SetBounds(0, 0, 1000, 1000);
    285   styled()->Layout();
    286 
    287   EXPECT_EQ(SK_ColorRED,
    288             static_cast<Label*>(styled()->child_at(0))->enabled_color());
    289   EXPECT_EQ(kDefaultLinkColor,
    290             static_cast<Label*>(styled()->child_at(1))->enabled_color());
    291   EXPECT_EQ(kDefaultTextColor,
    292             static_cast<Label*>(styled()->child_at(2))->enabled_color());
    293 }
    294 
    295 TEST_F(StyledLabelTest, ColorReadability) {
    296   const std::string text(
    297       "This is a block of text that needs color adjustment.");
    298   InitStyledLabel(text);
    299   styled()->SetDisplayedOnBackgroundColor(SK_ColorBLACK);
    300 
    301   // Obtain the text color if it were a pure label.
    302   Label label(ASCIIToUTF16(text));
    303   label.SetBackgroundColor(SK_ColorBLACK);
    304 
    305   styled()->SetBounds(0, 0, 1000, 1000);
    306   styled()->Layout();
    307 
    308   EXPECT_EQ(label.enabled_color(),
    309             static_cast<Label*>(styled()->child_at(0))->enabled_color());
    310 }
    311 
    312 TEST_F(StyledLabelTest, StyledRangeWithTooltip) {
    313   const std::string text("This is a test block of text, ");
    314   const std::string tooltip_text("this should have a tooltip,");
    315   const std::string normal_text(" this should not have a tooltip, ");
    316   const std::string link_text("and this should be a link");
    317 
    318   const size_t tooltip_start = text.size();
    319   const size_t link_start =
    320       text.size() + tooltip_text.size() + normal_text.size();
    321 
    322   InitStyledLabel(text + tooltip_text + normal_text + link_text);
    323   StyledLabel::RangeStyleInfo tooltip_style;
    324   tooltip_style.tooltip = ASCIIToUTF16("tooltip");
    325   styled()->AddStyleRange(
    326       ui::Range(tooltip_start, tooltip_start + tooltip_text.size()),
    327       tooltip_style);
    328   styled()->AddStyleRange(ui::Range(link_start, link_start + link_text.size()),
    329                           StyledLabel::RangeStyleInfo::CreateForLink());
    330 
    331   // Break line inside the range with the tooltip.
    332   Label label(ASCIIToUTF16(
    333        text + tooltip_text.substr(0, tooltip_text.size() - 3)));
    334   gfx::Size label_preferred_size = label.GetPreferredSize();
    335   int pref_height = styled()->GetHeightForWidth(label_preferred_size.width());
    336   EXPECT_EQ(label_preferred_size.height() * 3,
    337             pref_height - styled()->GetInsets().height());
    338 
    339   styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height);
    340   styled()->Layout();
    341 
    342   EXPECT_EQ(label_preferred_size.width(), styled()->width());
    343 
    344   ASSERT_EQ(5, styled()->child_count());
    345   EXPECT_EQ(0, styled()->child_at(0)->bounds().x());
    346   EXPECT_EQ(styled()->child_at(0)->bounds().right() - 2,
    347             styled()->child_at(1)->bounds().x());
    348   EXPECT_EQ(0, styled()->child_at(2)->bounds().x());
    349   EXPECT_EQ(styled()->child_at(2)->bounds().right() - 2,
    350             styled()->child_at(3)->bounds().x());
    351   EXPECT_EQ(0, styled()->child_at(4)->bounds().x());
    352 
    353   string16 tooltip;
    354   EXPECT_TRUE(
    355       styled()->child_at(1)->GetTooltipText(gfx::Point(1, 1), &tooltip));
    356   EXPECT_EQ(ASCIIToUTF16("tooltip"), tooltip);
    357   EXPECT_TRUE(
    358       styled()->child_at(2)->GetTooltipText(gfx::Point(1, 1), &tooltip));
    359   EXPECT_EQ(ASCIIToUTF16("tooltip"), tooltip);
    360 }
    361 
    362 TEST_F(StyledLabelTest, HandleEmptyLayout) {
    363   const std::string text("This is a test block of text, ");
    364   InitStyledLabel(text);
    365   styled()->Layout();
    366   ASSERT_EQ(0, styled()->child_count());
    367 }
    368 
    369 }  // namespace
    370