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
3 // found in the LICENSE file.
5 #include "ui/views/controls/label.h"
7 #include "base/i18n/rtl.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/accessibility/ax_view_state.h"
11 #include "ui/base/l10n/l10n_util.h"
12 #include "ui/compositor/canvas_painter.h"
13 #include "ui/gfx/canvas.h"
14 #include "ui/views/border.h"
15 #include "ui/views/test/focus_manager_test.h"
16 #include "ui/views/test/views_test_base.h"
17 #include "ui/views/widget/widget.h"
19 using base::ASCIIToUTF16
;
23 typedef ViewsTestBase LabelTest
;
25 class LabelFocusTest
: public FocusManagerTest
{
28 ~LabelFocusTest() override
{}
31 views::Label
* label() { return label_
; }
35 void InitContentView() override
{
36 label_
= new views::Label();
37 GetContentsView()->AddChildView(label_
);
43 // All text sizing measurements (width and height) should be greater than this.
44 const int kMinTextDimension
= 4;
46 // A test utility function to set the application default text direction.
47 void SetRTL(bool rtl
) {
48 // Override the current locale/direction.
49 base::i18n::SetICUDefaultLocale(rtl
? "he" : "en");
50 EXPECT_EQ(rtl
, base::i18n::IsRTL());
53 TEST_F(LabelTest
, FontPropertySymbol
) {
55 std::string
font_name("symbol");
56 gfx::Font
font(font_name
, 26);
57 label
.SetFontList(gfx::FontList(font
));
58 gfx::Font font_used
= label
.font_list().GetPrimaryFont();
59 EXPECT_EQ(font_name
, font_used
.GetFontName());
60 EXPECT_EQ(26, font_used
.GetFontSize());
63 TEST_F(LabelTest
, FontPropertyArial
) {
65 std::string
font_name("arial");
66 gfx::Font
font(font_name
, 30);
67 label
.SetFontList(gfx::FontList(font
));
68 gfx::Font font_used
= label
.font_list().GetPrimaryFont();
69 EXPECT_EQ(font_name
, font_used
.GetFontName());
70 EXPECT_EQ(30, font_used
.GetFontSize());
73 TEST_F(LabelTest
, TextProperty
) {
75 base::string16
test_text(ASCIIToUTF16("A random string."));
76 label
.SetText(test_text
);
77 EXPECT_EQ(test_text
, label
.text());
80 TEST_F(LabelTest
, ColorProperty
) {
82 SkColor color
= SkColorSetARGB(20, 40, 10, 5);
83 label
.SetAutoColorReadabilityEnabled(false);
84 label
.SetEnabledColor(color
);
85 EXPECT_EQ(color
, label
.enabled_color());
88 TEST_F(LabelTest
, AlignmentProperty
) {
89 const bool was_rtl
= base::i18n::IsRTL();
92 for (size_t i
= 0; i
< 2; ++i
) {
93 // Toggle the application default text direction (to try each direction).
94 SetRTL(!base::i18n::IsRTL());
95 bool reverse_alignment
= base::i18n::IsRTL();
97 // The alignment should be flipped in RTL UI.
98 label
.SetHorizontalAlignment(gfx::ALIGN_RIGHT
);
99 EXPECT_EQ(reverse_alignment
? gfx::ALIGN_LEFT
: gfx::ALIGN_RIGHT
,
100 label
.horizontal_alignment());
101 label
.SetHorizontalAlignment(gfx::ALIGN_LEFT
);
102 EXPECT_EQ(reverse_alignment
? gfx::ALIGN_RIGHT
: gfx::ALIGN_LEFT
,
103 label
.horizontal_alignment());
104 label
.SetHorizontalAlignment(gfx::ALIGN_CENTER
);
105 EXPECT_EQ(gfx::ALIGN_CENTER
, label
.horizontal_alignment());
107 for (size_t j
= 0; j
< 2; ++j
) {
108 label
.SetHorizontalAlignment(gfx::ALIGN_TO_HEAD
);
109 const bool rtl
= j
== 0;
110 label
.SetText(rtl
? base::WideToUTF16(L
"\x5d0") : ASCIIToUTF16("A"));
111 EXPECT_EQ(gfx::ALIGN_TO_HEAD
, label
.horizontal_alignment());
115 EXPECT_EQ(was_rtl
, base::i18n::IsRTL());
118 TEST_F(LabelTest
, ElideBehavior
) {
120 base::string16
text(ASCIIToUTF16("This is example text."));
122 EXPECT_EQ(gfx::ELIDE_TAIL
, label
.elide_behavior());
123 gfx::Size size
= label
.GetPreferredSize();
124 label
.SetBoundsRect(gfx::Rect(size
));
125 EXPECT_EQ(text
, label
.GetDisplayTextForTesting());
127 size
.set_width(size
.width() / 2);
128 label
.SetBoundsRect(gfx::Rect(size
));
129 EXPECT_GT(text
.size(), label
.GetDisplayTextForTesting().size());
131 label
.SetElideBehavior(gfx::NO_ELIDE
);
132 EXPECT_EQ(text
, label
.GetDisplayTextForTesting());
135 TEST_F(LabelTest
, MultiLineProperty
) {
137 EXPECT_FALSE(label
.multi_line());
138 label
.SetMultiLine(true);
139 EXPECT_TRUE(label
.multi_line());
140 label
.SetMultiLine(false);
141 EXPECT_FALSE(label
.multi_line());
144 TEST_F(LabelTest
, ObscuredProperty
) {
146 base::string16
test_text(ASCIIToUTF16("Password!"));
147 label
.SetText(test_text
);
148 label
.SizeToPreferredSize();
150 // The text should be unobscured by default.
151 EXPECT_FALSE(label
.obscured());
152 EXPECT_EQ(test_text
, label
.GetDisplayTextForTesting());
153 EXPECT_EQ(test_text
, label
.text());
155 label
.SetObscured(true);
156 label
.SizeToPreferredSize();
157 EXPECT_TRUE(label
.obscured());
158 EXPECT_EQ(ASCIIToUTF16("*********"), label
.GetDisplayTextForTesting());
159 EXPECT_EQ(test_text
, label
.text());
161 label
.SetText(test_text
+ test_text
);
162 label
.SizeToPreferredSize();
163 EXPECT_EQ(ASCIIToUTF16("******************"),
164 label
.GetDisplayTextForTesting());
165 EXPECT_EQ(test_text
+ test_text
, label
.text());
167 label
.SetObscured(false);
168 label
.SizeToPreferredSize();
169 EXPECT_FALSE(label
.obscured());
170 EXPECT_EQ(test_text
+ test_text
, label
.GetDisplayTextForTesting());
171 EXPECT_EQ(test_text
+ test_text
, label
.text());
174 TEST_F(LabelTest
, ObscuredSurrogatePair
) {
175 // 'MUSICAL SYMBOL G CLEF': represented in UTF-16 as two characters
176 // forming the surrogate pair 0x0001D11E.
178 base::string16 test_text
= base::UTF8ToUTF16("\xF0\x9D\x84\x9E");
179 label
.SetText(test_text
);
180 label
.SetObscured(true);
181 label
.SizeToPreferredSize();
182 EXPECT_EQ(ASCIIToUTF16("*"), label
.GetDisplayTextForTesting());
183 EXPECT_EQ(test_text
, label
.text());
186 // This test case verifies the label preferred size will change based on the
187 // current layout, which may seem wrong. However many of our code base assumes
188 // this behavior, therefore this behavior will have to be kept until the code
189 // with this assumption is fixed. See http://crbug.com/468494 and
190 // http://crbug.com/467526.
191 // TODO(mukai): fix the code assuming this behavior and then fix Label
192 // implementation, and remove this test case.
193 TEST_F(LabelTest
, MultilinePreferredSizeTest
) {
195 label
.SetText(ASCIIToUTF16("This is an example."));
197 gfx::Size single_line_size
= label
.GetPreferredSize();
199 label
.SetMultiLine(true);
200 gfx::Size multi_line_size
= label
.GetPreferredSize();
201 EXPECT_EQ(single_line_size
, multi_line_size
);
203 int new_width
= multi_line_size
.width() / 2;
204 label
.SetBounds(0, 0, new_width
, label
.GetHeightForWidth(new_width
));
205 gfx::Size new_size
= label
.GetPreferredSize();
206 EXPECT_GT(multi_line_size
.width(), new_size
.width());
207 EXPECT_LT(multi_line_size
.height(), new_size
.height());
210 TEST_F(LabelTest
, TooltipProperty
) {
212 label
.SetText(ASCIIToUTF16("My cool string."));
214 // Initially, label has no bounds, its text does not fit, and therefore its
215 // text should be returned as the tooltip text.
216 base::string16 tooltip
;
217 EXPECT_TRUE(label
.GetTooltipText(gfx::Point(), &tooltip
));
218 EXPECT_EQ(label
.text(), tooltip
);
220 // While tooltip handling is disabled, GetTooltipText() should fail.
221 label
.SetHandlesTooltips(false);
222 EXPECT_FALSE(label
.GetTooltipText(gfx::Point(), &tooltip
));
223 label
.SetHandlesTooltips(true);
225 // When set, custom tooltip text should be returned instead of the label's
227 base::string16
tooltip_text(ASCIIToUTF16("The tooltip!"));
228 label
.SetTooltipText(tooltip_text
);
229 EXPECT_TRUE(label
.GetTooltipText(gfx::Point(), &tooltip
));
230 EXPECT_EQ(tooltip_text
, tooltip
);
232 // While tooltip handling is disabled, GetTooltipText() should fail.
233 label
.SetHandlesTooltips(false);
234 EXPECT_FALSE(label
.GetTooltipText(gfx::Point(), &tooltip
));
235 label
.SetHandlesTooltips(true);
237 // When the tooltip text is set to an empty string, the original behavior is
239 label
.SetTooltipText(base::string16());
240 EXPECT_TRUE(label
.GetTooltipText(gfx::Point(), &tooltip
));
241 EXPECT_EQ(label
.text(), tooltip
);
243 // While tooltip handling is disabled, GetTooltipText() should fail.
244 label
.SetHandlesTooltips(false);
245 EXPECT_FALSE(label
.GetTooltipText(gfx::Point(), &tooltip
));
246 label
.SetHandlesTooltips(true);
248 // Make the label big enough to hold the text
249 // and expect there to be no tooltip.
250 label
.SetBounds(0, 0, 1000, 40);
251 EXPECT_FALSE(label
.GetTooltipText(gfx::Point(), &tooltip
));
253 // Shrinking the single-line label's height shouldn't trigger a tooltip.
254 label
.SetBounds(0, 0, 1000, label
.GetPreferredSize().height() / 2);
255 EXPECT_FALSE(label
.GetTooltipText(gfx::Point(), &tooltip
));
257 // Verify that explicitly set tooltip text is shown, regardless of size.
258 label
.SetTooltipText(tooltip_text
);
259 EXPECT_TRUE(label
.GetTooltipText(gfx::Point(), &tooltip
));
260 EXPECT_EQ(tooltip_text
, tooltip
);
261 // Clear out the explicitly set tooltip text.
262 label
.SetTooltipText(base::string16());
264 // Shrink the bounds and the tooltip should come back.
265 label
.SetBounds(0, 0, 10, 10);
266 EXPECT_TRUE(label
.GetTooltipText(gfx::Point(), &tooltip
));
268 // Make the label obscured and there is no tooltip.
269 label
.SetObscured(true);
270 EXPECT_FALSE(label
.GetTooltipText(gfx::Point(), &tooltip
));
272 // Obscuring the text shouldn't permanently clobber the tooltip.
273 label
.SetObscured(false);
274 EXPECT_TRUE(label
.GetTooltipText(gfx::Point(), &tooltip
));
276 // Making the label multiline shouldn't eliminate the tooltip.
277 label
.SetMultiLine(true);
278 EXPECT_TRUE(label
.GetTooltipText(gfx::Point(), &tooltip
));
279 // Expanding the multiline label bounds should eliminate the tooltip.
280 label
.SetBounds(0, 0, 1000, 1000);
281 EXPECT_FALSE(label
.GetTooltipText(gfx::Point(), &tooltip
));
283 // Verify that setting the tooltip still shows it.
284 label
.SetTooltipText(tooltip_text
);
285 EXPECT_TRUE(label
.GetTooltipText(gfx::Point(), &tooltip
));
286 EXPECT_EQ(tooltip_text
, tooltip
);
287 // Clear out the tooltip.
288 label
.SetTooltipText(base::string16());
291 TEST_F(LabelTest
, Accessibility
) {
293 label
.SetText(ASCIIToUTF16("My special text."));
295 ui::AXViewState state
;
296 label
.GetAccessibleState(&state
);
297 EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT
, state
.role
);
298 EXPECT_EQ(label
.text(), state
.name
);
299 EXPECT_TRUE(state
.HasStateFlag(ui::AX_STATE_READ_ONLY
));
302 TEST_F(LabelTest
, TextChangeWithoutLayout
) {
304 label
.SetText(ASCIIToUTF16("Example"));
305 label
.SetBounds(0, 0, 200, 200);
307 gfx::Canvas
canvas(gfx::Size(200, 200), 1.0f
, true);
308 label
.Paint(ui::CanvasPainter(&canvas
, 1.f
).context());
309 EXPECT_EQ(1u, label
.lines_
.size());
310 EXPECT_EQ(ASCIIToUTF16("Example"), label
.lines_
[0]->GetDisplayText());
312 label
.SetText(ASCIIToUTF16("Altered"));
313 // The altered text should be painted even though Layout() or SetBounds() are
315 label
.Paint(ui::CanvasPainter(&canvas
, 1.f
).context());
316 EXPECT_EQ(1u, label
.lines_
.size());
317 EXPECT_EQ(ASCIIToUTF16("Altered"), label
.lines_
[0]->GetDisplayText());
320 TEST_F(LabelTest
, EmptyLabelSizing
) {
322 const gfx::Size
expected_size(0, gfx::FontList().GetHeight());
323 EXPECT_EQ(expected_size
, label
.GetPreferredSize());
324 label
.SetMultiLine(!label
.multi_line());
325 EXPECT_EQ(expected_size
, label
.GetPreferredSize());
328 TEST_F(LabelTest
, SingleLineSizing
) {
330 label
.SetText(ASCIIToUTF16("A not so random string in one line."));
331 const gfx::Size size
= label
.GetPreferredSize();
332 EXPECT_GT(size
.height(), kMinTextDimension
);
333 EXPECT_GT(size
.width(), kMinTextDimension
);
335 // Setting a size smaller than preferred should not change the preferred size.
336 label
.SetSize(gfx::Size(size
.width() / 2, size
.height() / 2));
337 EXPECT_EQ(size
, label
.GetPreferredSize());
339 const gfx::Insets
border(10, 20, 30, 40);
340 label
.SetBorder(Border::CreateEmptyBorder(
341 border
.top(), border
.left(), border
.bottom(), border
.right()));
342 const gfx::Size size_with_border
= label
.GetPreferredSize();
343 EXPECT_EQ(size_with_border
.height(), size
.height() + border
.height());
344 EXPECT_EQ(size_with_border
.width(), size
.width() + border
.width());
345 EXPECT_EQ(size
.height() + border
.height(),
346 label
.GetHeightForWidth(size_with_border
.width()));
349 TEST_F(LabelTest
, MultilineSmallAvailableWidthSizing
) {
351 label
.SetMultiLine(true);
352 label
.SetAllowCharacterBreak(true);
353 label
.SetText(ASCIIToUTF16("Too Wide."));
355 // Check that Label can be laid out at a variety of small sizes,
356 // splitting the words into up to one character per line if necessary.
357 // Incorrect word splitting may cause infinite loops in text layout.
358 gfx::Size required_size
= label
.GetPreferredSize();
359 for (int i
= 1; i
< required_size
.width(); ++i
)
360 EXPECT_GT(label
.GetHeightForWidth(i
), 0);
363 // Verifies if SetAllowCharacterBreak(true) doesn't change the preferred size.
364 // See crbug.com/469559
365 TEST_F(LabelTest
, PreferredSizeForAllowCharacterBreak
) {
366 Label
label(base::ASCIIToUTF16("Example"));
367 gfx::Size preferred_size
= label
.GetPreferredSize();
369 label
.SetMultiLine(true);
370 label
.SetAllowCharacterBreak(true);
371 EXPECT_EQ(preferred_size
, label
.GetPreferredSize());
374 TEST_F(LabelTest
, MultiLineSizing
) {
376 label
.SetFocusable(false);
378 ASCIIToUTF16("A random string\nwith multiple lines\nand returns!"));
379 label
.SetMultiLine(true);
382 gfx::Size required_size
= label
.GetPreferredSize();
383 EXPECT_GT(required_size
.height(), kMinTextDimension
);
384 EXPECT_GT(required_size
.width(), kMinTextDimension
);
386 // SizeToFit with unlimited width.
388 int required_width
= label
.GetLocalBounds().width();
389 EXPECT_GT(required_width
, kMinTextDimension
);
391 // SizeToFit with limited width.
392 label
.SizeToFit(required_width
- 1);
393 int constrained_width
= label
.GetLocalBounds().width();
395 // Canvas::SizeStringInt (in ui/gfx/canvas_linux.cc)
396 // has to be fixed to return the size that fits to given width/height.
397 EXPECT_LT(constrained_width
, required_width
);
399 EXPECT_GT(constrained_width
, kMinTextDimension
);
401 // Change the width back to the desire width.
402 label
.SizeToFit(required_width
);
403 EXPECT_EQ(required_width
, label
.GetLocalBounds().width());
405 // General tests for GetHeightForWidth.
406 int required_height
= label
.GetHeightForWidth(required_width
);
407 EXPECT_GT(required_height
, kMinTextDimension
);
408 int height_for_constrained_width
= label
.GetHeightForWidth(constrained_width
);
410 // Canvas::SizeStringInt (in ui/gfx/canvas_linux.cc)
411 // has to be fixed to return the size that fits to given width/height.
412 EXPECT_GT(height_for_constrained_width
, required_height
);
414 // Using the constrained width or the required_width - 1 should give the
415 // same result for the height because the constrainted width is the tight
416 // width when given "required_width - 1" as the max width.
417 EXPECT_EQ(height_for_constrained_width
,
418 label
.GetHeightForWidth(required_width
- 1));
420 // Test everything with borders.
421 gfx::Insets
border(10, 20, 30, 40);
422 label
.SetBorder(Border::CreateEmptyBorder(
423 border
.top(), border
.left(), border
.bottom(), border
.right()));
425 // SizeToFit and borders.
427 int required_width_with_border
= label
.GetLocalBounds().width();
428 EXPECT_EQ(required_width_with_border
, required_width
+ border
.width());
430 // GetHeightForWidth and borders.
431 int required_height_with_border
=
432 label
.GetHeightForWidth(required_width_with_border
);
433 EXPECT_EQ(required_height_with_border
, required_height
+ border
.height());
435 // Test that the border width is subtracted before doing the height
436 // calculation. If it is, then the height will grow when width
438 int height1
= label
.GetHeightForWidth(required_width_with_border
- 1);
440 // Canvas::SizeStringInt (in ui/gfx/canvas_linux.cc)
441 // has to be fixed to return the size that fits to given width/height.
442 EXPECT_GT(height1
, required_height_with_border
);
444 EXPECT_EQ(height1
, height_for_constrained_width
+ border
.height());
446 // GetPreferredSize and borders.
447 label
.SetBounds(0, 0, 0, 0);
448 gfx::Size required_size_with_border
= label
.GetPreferredSize();
449 EXPECT_EQ(required_size_with_border
.height(),
450 required_size
.height() + border
.height());
451 EXPECT_EQ(required_size_with_border
.width(),
452 required_size
.width() + border
.width());
455 // Verifies if the combination of text eliding and multiline doesn't cause
456 // any side effects of size / layout calculation.
457 TEST_F(LabelTest
, MultiLineSizingWithElide
) {
458 const base::string16 text
=
459 ASCIIToUTF16("A random string\nwith multiple lines\nand returns!");
461 label
.SetFocusable(false);
463 label
.SetMultiLine(true);
465 gfx::Size required_size
= label
.GetPreferredSize();
466 EXPECT_GT(required_size
.height(), kMinTextDimension
);
467 EXPECT_GT(required_size
.width(), kMinTextDimension
);
468 label
.SetBoundsRect(gfx::Rect(required_size
));
470 label
.SetElideBehavior(gfx::ELIDE_TAIL
);
471 EXPECT_EQ(required_size
.ToString(), label
.GetPreferredSize().ToString());
472 EXPECT_EQ(text
, label
.GetDisplayTextForTesting());
474 label
.SizeToFit(required_size
.width() - 1);
475 gfx::Size narrow_size
= label
.GetPreferredSize();
476 EXPECT_GT(required_size
.width(), narrow_size
.width());
477 EXPECT_LT(required_size
.height(), narrow_size
.height());
479 // SetBounds() doesn't change the preferred size.
480 label
.SetBounds(0, 0, narrow_size
.width() - 1, narrow_size
.height());
481 EXPECT_EQ(narrow_size
.ToString(), label
.GetPreferredSize().ToString());
483 // Paint() doesn't change the preferred size.
485 label
.Paint(ui::CanvasPainter(&canvas
, 1.f
).context());
486 EXPECT_EQ(narrow_size
.ToString(), label
.GetPreferredSize().ToString());
489 // Check that labels support GetTooltipHandlerForPoint.
490 TEST_F(LabelTest
, GetTooltipHandlerForPoint
) {
491 // A root view must be defined for this test because the hit-testing
492 // behaviour used by GetTooltipHandlerForPoint() is defined by
493 // the ViewTargeter installed on the root view.
495 Widget::InitParams init_params
=
496 CreateParams(Widget::InitParams::TYPE_POPUP
);
497 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
498 init_params
.bounds
= gfx::Rect(0, 0, 200, 200);
499 widget
.Init(init_params
);
503 ASCIIToUTF16("A string that's long enough to exceed the bounds"));
504 label
.SetBounds(0, 0, 10, 10);
505 widget
.SetContentsView(&label
);
507 // By default, labels start out as tooltip handlers.
508 ASSERT_TRUE(label
.handles_tooltips());
510 // There's a default tooltip if the text is too big to fit.
511 EXPECT_EQ(&label
, label
.GetTooltipHandlerForPoint(gfx::Point(2, 2)));
513 // If tooltip handling is disabled, the label should not provide a tooltip
515 label
.SetHandlesTooltips(false);
516 EXPECT_FALSE(label
.GetTooltipHandlerForPoint(gfx::Point(2, 2)));
517 label
.SetHandlesTooltips(true);
519 // If there's no default tooltip, this should return NULL.
520 label
.SetBounds(0, 0, 500, 50);
521 EXPECT_FALSE(label
.GetTooltipHandlerForPoint(gfx::Point(2, 2)));
523 label
.SetTooltipText(ASCIIToUTF16("a tooltip"));
524 // If the point hits the label, and tooltip is set, the label should be
525 // returned as its tooltip handler.
526 EXPECT_EQ(&label
, label
.GetTooltipHandlerForPoint(gfx::Point(2, 2)));
528 // Additionally, GetTooltipHandlerForPoint should verify that the label
529 // actually contains the point.
530 EXPECT_FALSE(label
.GetTooltipHandlerForPoint(gfx::Point(2, 51)));
531 EXPECT_FALSE(label
.GetTooltipHandlerForPoint(gfx::Point(-1, 20)));
533 // Again, if tooltip handling is disabled, the label should not provide a
535 label
.SetHandlesTooltips(false);
536 EXPECT_FALSE(label
.GetTooltipHandlerForPoint(gfx::Point(2, 2)));
537 EXPECT_FALSE(label
.GetTooltipHandlerForPoint(gfx::Point(2, 51)));
538 EXPECT_FALSE(label
.GetTooltipHandlerForPoint(gfx::Point(-1, 20)));
539 label
.SetHandlesTooltips(true);
541 // GetTooltipHandlerForPoint works should work in child bounds.
542 label
.SetBounds(2, 2, 10, 10);
543 EXPECT_EQ(&label
, label
.GetTooltipHandlerForPoint(gfx::Point(1, 5)));
544 EXPECT_FALSE(label
.GetTooltipHandlerForPoint(gfx::Point(3, 11)));
547 // Check that label releases its internal layout data when it's unnecessary.
548 TEST_F(LabelTest
, ResetRenderTextData
) {
550 label
.SetText(ASCIIToUTF16("Example"));
551 label
.SizeToPreferredSize();
552 gfx::Size preferred_size
= label
.GetPreferredSize();
554 EXPECT_NE(gfx::Size().ToString(), preferred_size
.ToString());
555 EXPECT_EQ(0u, label
.lines_
.size());
557 gfx::Canvas
canvas(preferred_size
, 1.0f
, true);
558 label
.Paint(ui::CanvasPainter(&canvas
, 1.f
).context());
559 EXPECT_EQ(1u, label
.lines_
.size());
561 // Label should recreate its RenderText object when it's invisible, to release
562 // the layout structures and data.
563 label
.SetVisible(false);
564 EXPECT_EQ(0u, label
.lines_
.size());
566 // Querying fields or size information should not recompute the layout
568 EXPECT_EQ(ASCIIToUTF16("Example"), label
.text());
569 EXPECT_EQ(0u, label
.lines_
.size());
571 EXPECT_EQ(preferred_size
.ToString(), label
.GetPreferredSize().ToString());
572 EXPECT_EQ(0u, label
.lines_
.size());
574 // RenderText data should be back when it's necessary.
575 label
.SetVisible(true);
576 EXPECT_EQ(0u, label
.lines_
.size());
578 label
.Paint(ui::CanvasPainter(&canvas
, 1.f
).context());
579 EXPECT_EQ(1u, label
.lines_
.size());
581 // Changing layout just resets |lines_|. It'll recover next time it's drawn.
582 label
.SetBounds(0, 0, 10, 10);
583 EXPECT_EQ(0u, label
.lines_
.size());
585 label
.Paint(ui::CanvasPainter(&canvas
, 1.f
).context());
586 EXPECT_EQ(1u, label
.lines_
.size());
589 #if !defined(OS_MACOSX)
590 TEST_F(LabelTest
, MultilineSupportedRenderText
) {
591 scoped_ptr
<gfx::RenderText
> render_text(gfx::RenderText::CreateInstance());
592 ASSERT_TRUE(render_text
->MultilineSupported());
595 label
.SetText(ASCIIToUTF16("Example of\nmultilined label"));
596 label
.SetMultiLine(true);
597 label
.SizeToPreferredSize();
599 gfx::Canvas
canvas(label
.GetPreferredSize(), 1.0f
, true);
600 label
.Paint(ui::CanvasPainter(&canvas
, 1.f
).context());
602 // There's only one 'line', RenderText itself supports multiple lines.
603 EXPECT_EQ(1u, label
.lines_
.size());
607 TEST_F(LabelFocusTest
, FocusBounds
) {
608 label()->SetText(ASCIIToUTF16("Example"));
609 gfx::Size normal_size
= label()->GetPreferredSize();
611 label()->SetFocusable(true);
612 label()->RequestFocus();
613 gfx::Size focusable_size
= label()->GetPreferredSize();
614 // Focusable label requires larger size to paint the focus rectangle.
615 EXPECT_GT(focusable_size
.width(), normal_size
.width());
616 EXPECT_GT(focusable_size
.height(), normal_size
.height());
618 label()->SizeToPreferredSize();
619 gfx::Rect focus_bounds
= label()->GetFocusBounds();
620 EXPECT_EQ(label()->GetLocalBounds().ToString(), focus_bounds
.ToString());
623 0, 0, focusable_size
.width() * 2, focusable_size
.height() * 2);
624 label()->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
625 focus_bounds
= label()->GetFocusBounds();
626 EXPECT_EQ(0, focus_bounds
.x());
627 EXPECT_LT(0, focus_bounds
.y());
628 EXPECT_GT(label()->bounds().bottom(), focus_bounds
.bottom());
629 EXPECT_EQ(focusable_size
.ToString(), focus_bounds
.size().ToString());
631 label()->SetHorizontalAlignment(gfx::ALIGN_RIGHT
);
632 focus_bounds
= label()->GetFocusBounds();
633 EXPECT_LT(0, focus_bounds
.x());
634 EXPECT_EQ(label()->bounds().right(), focus_bounds
.right());
635 EXPECT_LT(0, focus_bounds
.y());
636 EXPECT_GT(label()->bounds().bottom(), focus_bounds
.bottom());
637 EXPECT_EQ(focusable_size
.ToString(), focus_bounds
.size().ToString());
639 label()->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
640 label()->SetElideBehavior(gfx::FADE_TAIL
);
641 label()->SetBounds(0, 0, focusable_size
.width() / 2, focusable_size
.height());
642 focus_bounds
= label()->GetFocusBounds();
643 EXPECT_EQ(0, focus_bounds
.x());
644 EXPECT_EQ(focusable_size
.width() / 2, focus_bounds
.width());
647 TEST_F(LabelFocusTest
, EmptyLabel
) {
648 label()->SetFocusable(true);
649 label()->RequestFocus();
650 label()->SizeToPreferredSize();
652 gfx::Rect focus_bounds
= label()->GetFocusBounds();
653 EXPECT_FALSE(focus_bounds
.IsEmpty());
654 EXPECT_LT(label()->font_list().GetHeight(), focus_bounds
.height());