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