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.
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"
18 class StyledLabelTest : public testing::Test, public StyledLabelListener {
21 virtual ~StyledLabelTest() {}
23 // StyledLabelListener implementation.
24 virtual void StyledLabelLinkClicked(const gfx::Range& range,
25 int event_flags) OVERRIDE {}
28 StyledLabel* styled() { return styled_.get(); }
30 void InitStyledLabel(const std::string& ascii_text) {
31 styled_.reset(new StyledLabel(ASCIIToUTF16(ascii_text), this));
34 int StyledLabelContentHeightForWidth(int w) {
35 return styled_->GetHeightForWidth(w) - styled_->GetInsets().height();
39 scoped_ptr<StyledLabel> styled_;
41 DISALLOW_COPY_AND_ASSIGN(StyledLabelTest);
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));
53 TEST_F(StyledLabelTest, TrailingWhitespaceiIgnored) {
54 const std::string text("This is a test block of text ");
55 InitStyledLabel(text);
57 styled()->SetBounds(0, 0, 1000, 1000);
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());
67 TEST_F(StyledLabelTest, RespectLeadingWhitespace) {
68 const std::string text(" This is a test block of text");
69 InitStyledLabel(text);
71 styled()->SetBounds(0, 0, 1000, 1000);
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());
81 TEST_F(StyledLabelTest, FirstLineNotEmptyWhenLeadingWhitespaceTooLong) {
82 const std::string text(" a");
83 InitStyledLabel(text);
85 Label label(ASCIIToUTF16(text));
86 gfx::Size label_preferred_size = label.GetPreferredSize();
88 styled()->SetBounds(0, 0, label_preferred_size.width() / 2, 1000);
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());
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()));
106 // Also respect the border.
107 styled()->set_border(Border::CreateEmptyBorder(3, 3, 3, 3));
111 styled()->GetInsets().width() + label_preferred_size.width(),
112 styled()->GetInsets().height() + 2 * label_preferred_size.height());
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());
121 TEST_F(StyledLabelTest, CreateLinks) {
122 const std::string text("This is a test block of text.");
123 InitStyledLabel(text);
124 styled()->AddStyleRange(gfx::Range(0, 1),
125 StyledLabel::RangeStyleInfo::CreateForLink());
126 styled()->AddStyleRange(gfx::Range(1, 2),
127 StyledLabel::RangeStyleInfo::CreateForLink());
128 styled()->AddStyleRange(gfx::Range(10, 11),
129 StyledLabel::RangeStyleInfo::CreateForLink());
130 styled()->AddStyleRange(gfx::Range(12, 13),
131 StyledLabel::RangeStyleInfo::CreateForLink());
133 styled()->SetBounds(0, 0, 1000, 1000);
135 ASSERT_EQ(7, styled()->child_count());
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 gfx::Range(text.size(), text.size() + link_text.size()),
144 StyledLabel::RangeStyleInfo::CreateForLink());
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());
152 styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height);
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());
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 gfx::Range(text.size(), text.size() + unbreakable_text.size()),
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());
176 styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height);
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());
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 gfx::Range(text.size(), text.size() + underlined_text.size()),
193 styled()->SetBounds(0, 0, 1000, 1000);
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());
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);
209 StyledLabel::RangeStyleInfo style_info;
210 style_info.font_style = gfx::Font::BOLD;
211 styled()->AddStyleRange(gfx::Range(0, bold_text.size()), style_info);
213 // Calculate the bold text width if it were a pure label view, both with bold
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();
220 ASSERT_GE(bold_label_size.width(), normal_label_size.width());
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);
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);
232 ASSERT_EQ(1, unstyled.child_count());
234 styled()->SetBounds(0, 0, styled_width, pref_height);
237 ASSERT_EQ(3, styled()->child_count());
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());
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());
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);
266 StyledLabel::RangeStyleInfo style_info_red;
267 style_info_red.color = SK_ColorRED;
268 styled()->AddStyleRange(gfx::Range(0, text_red.size()), style_info_red);
270 StyledLabel::RangeStyleInfo style_info_link =
271 StyledLabel::RangeStyleInfo::CreateForLink();
272 styled()->AddStyleRange(gfx::Range(text_red.size(),
273 text_red.size() + text_link.size()),
276 // Obtain the default text color for a label.
277 Label label(ASCIIToUTF16(text));
278 const SkColor kDefaultTextColor = label.enabled_color();
280 // Obtain the default text color for a link;
281 Link link(ASCIIToUTF16(text_link));
282 const SkColor kDefaultLinkColor = link.enabled_color();
284 styled()->SetBounds(0, 0, 1000, 1000);
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());
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);
301 // Obtain the text color if it were a pure label.
302 Label label(ASCIIToUTF16(text));
303 label.SetBackgroundColor(SK_ColorBLACK);
305 styled()->SetBounds(0, 0, 1000, 1000);
308 EXPECT_EQ(label.enabled_color(),
309 static_cast<Label*>(styled()->child_at(0))->enabled_color());
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");
318 const size_t tooltip_start = text.size();
319 const size_t link_start =
320 text.size() + tooltip_text.size() + normal_text.size();
322 InitStyledLabel(text + tooltip_text + normal_text + link_text);
323 StyledLabel::RangeStyleInfo tooltip_style;
324 tooltip_style.tooltip = ASCIIToUTF16("tooltip");
325 styled()->AddStyleRange(
326 gfx::Range(tooltip_start, tooltip_start + tooltip_text.size()),
328 styled()->AddStyleRange(gfx::Range(link_start, link_start + link_text.size()),
329 StyledLabel::RangeStyleInfo::CreateForLink());
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());
339 styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height);
342 EXPECT_EQ(label_preferred_size.width(), styled()->width());
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());
355 styled()->child_at(1)->GetTooltipText(gfx::Point(1, 1), &tooltip));
356 EXPECT_EQ(ASCIIToUTF16("tooltip"), tooltip);
358 styled()->child_at(2)->GetTooltipText(gfx::Point(1, 1), &tooltip));
359 EXPECT_EQ(ASCIIToUTF16("tooltip"), tooltip);
362 TEST_F(StyledLabelTest, HandleEmptyLayout) {
363 const std::string text("This is a test block of text, ");
364 InitStyledLabel(text);
366 ASSERT_EQ(0, styled()->child_count());