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.
4
5#include "ui/views/controls/label.h"
6
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/gfx/canvas.h"
13#include "ui/views/border.h"
14#include "ui/views/test/views_test_base.h"
15#include "ui/views/widget/widget.h"
16
17using base::ASCIIToUTF16;
18
19namespace views {
20
21typedef ViewsTestBase LabelTest;
22
23// All text sizing measurements (width and height) should be greater than this.
24const int kMinTextDimension = 4;
25
26// A test utility function to set the application default text direction.
27void SetRTL(bool rtl) {
28  // Override the current locale/direction.
29  base::i18n::SetICUDefaultLocale(rtl ? "he" : "en");
30  EXPECT_EQ(rtl, base::i18n::IsRTL());
31}
32
33TEST_F(LabelTest, FontPropertySymbol) {
34  Label label;
35  std::string font_name("symbol");
36  gfx::Font font(font_name, 26);
37  label.SetFontList(gfx::FontList(font));
38  gfx::Font font_used = label.font_list().GetPrimaryFont();
39  EXPECT_EQ(font_name, font_used.GetFontName());
40  EXPECT_EQ(26, font_used.GetFontSize());
41}
42
43TEST_F(LabelTest, FontPropertyArial) {
44  Label label;
45  std::string font_name("arial");
46  gfx::Font font(font_name, 30);
47  label.SetFontList(gfx::FontList(font));
48  gfx::Font font_used = label.font_list().GetPrimaryFont();
49  EXPECT_EQ(font_name, font_used.GetFontName());
50  EXPECT_EQ(30, font_used.GetFontSize());
51}
52
53TEST_F(LabelTest, TextProperty) {
54  Label label;
55  base::string16 test_text(ASCIIToUTF16("A random string."));
56  label.SetText(test_text);
57  EXPECT_EQ(test_text, label.text());
58}
59
60TEST_F(LabelTest, ColorProperty) {
61  Label label;
62  SkColor color = SkColorSetARGB(20, 40, 10, 5);
63  label.SetAutoColorReadabilityEnabled(false);
64  label.SetEnabledColor(color);
65  EXPECT_EQ(color, label.enabled_color());
66}
67
68TEST_F(LabelTest, AlignmentProperty) {
69  const bool was_rtl = base::i18n::IsRTL();
70
71  Label label;
72  for (size_t i = 0; i < 2; ++i) {
73    // Toggle the application default text direction (to try each direction).
74    SetRTL(!base::i18n::IsRTL());
75    bool reverse_alignment = base::i18n::IsRTL();
76
77    // The alignment should be flipped in RTL UI.
78    label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
79    EXPECT_EQ(reverse_alignment ? gfx::ALIGN_LEFT : gfx::ALIGN_RIGHT,
80              label.GetHorizontalAlignment());
81    label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
82    EXPECT_EQ(reverse_alignment ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT,
83              label.GetHorizontalAlignment());
84    label.SetHorizontalAlignment(gfx::ALIGN_CENTER);
85    EXPECT_EQ(gfx::ALIGN_CENTER, label.GetHorizontalAlignment());
86
87    for (size_t j = 0; j < 2; ++j) {
88      label.SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
89      const bool rtl = j == 0;
90      label.SetText(rtl ? base::WideToUTF16(L"\x5d0") : ASCIIToUTF16("A"));
91      EXPECT_EQ(rtl ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT,
92                label.GetHorizontalAlignment());
93    }
94  }
95
96  EXPECT_EQ(was_rtl, base::i18n::IsRTL());
97}
98
99TEST_F(LabelTest, MultiLineProperty) {
100  Label label;
101  EXPECT_FALSE(label.multi_line());
102  label.SetMultiLine(true);
103  EXPECT_TRUE(label.multi_line());
104  label.SetMultiLine(false);
105  EXPECT_FALSE(label.multi_line());
106}
107
108TEST_F(LabelTest, ObscuredProperty) {
109  Label label;
110  base::string16 test_text(ASCIIToUTF16("Password!"));
111  label.SetText(test_text);
112
113  // The text should be unobscured by default.
114  EXPECT_FALSE(label.obscured());
115  EXPECT_EQ(test_text, label.GetLayoutTextForTesting());
116  EXPECT_EQ(test_text, label.text());
117
118  label.SetObscured(true);
119  EXPECT_TRUE(label.obscured());
120  EXPECT_EQ(ASCIIToUTF16("*********"), label.GetLayoutTextForTesting());
121  EXPECT_EQ(test_text, label.text());
122
123  label.SetText(test_text + test_text);
124  EXPECT_EQ(ASCIIToUTF16("******************"),
125            label.GetLayoutTextForTesting());
126  EXPECT_EQ(test_text + test_text, label.text());
127
128  label.SetObscured(false);
129  EXPECT_FALSE(label.obscured());
130  EXPECT_EQ(test_text + test_text, label.GetLayoutTextForTesting());
131  EXPECT_EQ(test_text + test_text, label.text());
132}
133
134TEST_F(LabelTest, ObscuredSurrogatePair) {
135  // 'MUSICAL SYMBOL G CLEF': represented in UTF-16 as two characters
136  // forming the surrogate pair 0x0001D11E.
137  Label label;
138  base::string16 test_text = base::UTF8ToUTF16("\xF0\x9D\x84\x9E");
139  label.SetText(test_text);
140
141  label.SetObscured(true);
142  EXPECT_EQ(ASCIIToUTF16("*"), label.GetLayoutTextForTesting());
143  EXPECT_EQ(test_text, label.text());
144}
145
146TEST_F(LabelTest, TooltipProperty) {
147  Label label;
148  label.SetText(ASCIIToUTF16("My cool string."));
149
150  base::string16 tooltip;
151  EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
152  EXPECT_EQ(label.text(), tooltip);
153
154  base::string16 tooltip_text(ASCIIToUTF16("The tooltip!"));
155  label.SetTooltipText(tooltip_text);
156  EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
157  EXPECT_EQ(tooltip_text, tooltip);
158
159  label.SetTooltipText(base::string16());
160  EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
161  EXPECT_EQ(label.text(), tooltip);
162
163  // Make the label big enough to hold the text
164  // and expect there to be no tooltip.
165  label.SetBounds(0, 0, 1000, 40);
166  EXPECT_FALSE(label.GetTooltipText(gfx::Point(), &tooltip));
167
168  // Shrinking the single-line label's height shouldn't trigger a tooltip.
169  label.SetBounds(0, 0, 1000, label.GetPreferredSize().height() / 2);
170  EXPECT_FALSE(label.GetTooltipText(gfx::Point(), &tooltip));
171
172  // Verify that explicitly set tooltip text is shown, regardless of size.
173  label.SetTooltipText(tooltip_text);
174  EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
175  EXPECT_EQ(tooltip_text, tooltip);
176  // Clear out the explicitly set tooltip text.
177  label.SetTooltipText(base::string16());
178
179  // Shrink the bounds and the tooltip should come back.
180  label.SetBounds(0, 0, 10, 10);
181  EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
182
183  // Make the label obscured and there is no tooltip.
184  label.SetObscured(true);
185  EXPECT_FALSE(label.GetTooltipText(gfx::Point(), &tooltip));
186
187  // Obscuring the text shouldn't permanently clobber the tooltip.
188  label.SetObscured(false);
189  EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
190
191  // Making the label multiline shouldn't eliminate the tooltip.
192  label.SetMultiLine(true);
193  EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
194  // Expanding the multiline label bounds should eliminate the tooltip.
195  label.SetBounds(0, 0, 1000, 1000);
196  EXPECT_FALSE(label.GetTooltipText(gfx::Point(), &tooltip));
197
198  // Verify that setting the tooltip still shows it.
199  label.SetTooltipText(tooltip_text);
200  EXPECT_TRUE(label.GetTooltipText(gfx::Point(), &tooltip));
201  EXPECT_EQ(tooltip_text, tooltip);
202  // Clear out the tooltip.
203  label.SetTooltipText(base::string16());
204}
205
206TEST_F(LabelTest, Accessibility) {
207  Label label;
208  label.SetText(ASCIIToUTF16("My special text."));
209
210  ui::AXViewState state;
211  label.GetAccessibleState(&state);
212  EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, state.role);
213  EXPECT_EQ(label.text(), state.name);
214  EXPECT_TRUE(state.HasStateFlag(ui::AX_STATE_READ_ONLY));
215}
216
217TEST_F(LabelTest, EmptyLabelSizing) {
218  Label label;
219  const gfx::Size expected_size(0, gfx::FontList().GetHeight());
220  EXPECT_EQ(expected_size, label.GetPreferredSize());
221  label.SetMultiLine(!label.multi_line());
222  EXPECT_EQ(expected_size, label.GetPreferredSize());
223}
224
225TEST_F(LabelTest, SingleLineSizing) {
226  Label label;
227  label.SetText(ASCIIToUTF16("A not so random string in one line."));
228  const gfx::Size size = label.GetPreferredSize();
229  EXPECT_GT(size.height(), kMinTextDimension);
230  EXPECT_GT(size.width(), kMinTextDimension);
231
232  // Setting a size smaller than preferred should not change the preferred size.
233  label.SetSize(gfx::Size(size.width() / 2, size.height() / 2));
234  EXPECT_EQ(size, label.GetPreferredSize());
235
236  const gfx::Insets border(10, 20, 30, 40);
237  label.SetBorder(Border::CreateEmptyBorder(
238      border.top(), border.left(), border.bottom(), border.right()));
239  const gfx::Size size_with_border = label.GetPreferredSize();
240  EXPECT_EQ(size_with_border.height(), size.height() + border.height());
241  EXPECT_EQ(size_with_border.width(), size.width() + border.width());
242}
243
244TEST_F(LabelTest, MultilineSmallAvailableWidthSizing) {
245  Label label;
246  label.SetMultiLine(true);
247  label.SetAllowCharacterBreak(true);
248  label.SetText(ASCIIToUTF16("Too Wide."));
249
250  // Check that Label can be laid out at a variety of small sizes,
251  // splitting the words into up to one character per line if necessary.
252  // Incorrect word splitting may cause infinite loops in text layout.
253  gfx::Size required_size = label.GetPreferredSize();
254  for (int i = 1; i < required_size.width(); ++i)
255    EXPECT_GT(label.GetHeightForWidth(i), 0);
256}
257
258TEST_F(LabelTest, MultiLineSizing) {
259  Label label;
260  label.SetFocusable(false);
261  label.SetText(
262      ASCIIToUTF16("A random string\nwith multiple lines\nand returns!"));
263  label.SetMultiLine(true);
264
265  // GetPreferredSize
266  gfx::Size required_size = label.GetPreferredSize();
267  EXPECT_GT(required_size.height(), kMinTextDimension);
268  EXPECT_GT(required_size.width(), kMinTextDimension);
269
270  // SizeToFit with unlimited width.
271  label.SizeToFit(0);
272  int required_width = label.GetLocalBounds().width();
273  EXPECT_GT(required_width, kMinTextDimension);
274
275  // SizeToFit with limited width.
276  label.SizeToFit(required_width - 1);
277  int constrained_width = label.GetLocalBounds().width();
278#if defined(OS_WIN)
279  // Canvas::SizeStringInt (in ui/gfx/canvas_linux.cc)
280  // has to be fixed to return the size that fits to given width/height.
281  EXPECT_LT(constrained_width, required_width);
282#endif
283  EXPECT_GT(constrained_width, kMinTextDimension);
284
285  // Change the width back to the desire width.
286  label.SizeToFit(required_width);
287  EXPECT_EQ(required_width, label.GetLocalBounds().width());
288
289  // General tests for GetHeightForWidth.
290  int required_height = label.GetHeightForWidth(required_width);
291  EXPECT_GT(required_height, kMinTextDimension);
292  int height_for_constrained_width = label.GetHeightForWidth(constrained_width);
293#if defined(OS_WIN)
294  // Canvas::SizeStringInt (in ui/gfx/canvas_linux.cc)
295  // has to be fixed to return the size that fits to given width/height.
296  EXPECT_GT(height_for_constrained_width, required_height);
297#endif
298  // Using the constrained width or the required_width - 1 should give the
299  // same result for the height because the constrainted width is the tight
300  // width when given "required_width - 1" as the max width.
301  EXPECT_EQ(height_for_constrained_width,
302            label.GetHeightForWidth(required_width - 1));
303
304  // Test everything with borders.
305  gfx::Insets border(10, 20, 30, 40);
306  label.SetBorder(Border::CreateEmptyBorder(
307      border.top(), border.left(), border.bottom(), border.right()));
308
309  // SizeToFit and borders.
310  label.SizeToFit(0);
311  int required_width_with_border = label.GetLocalBounds().width();
312  EXPECT_EQ(required_width_with_border, required_width + border.width());
313
314  // GetHeightForWidth and borders.
315  int required_height_with_border =
316      label.GetHeightForWidth(required_width_with_border);
317  EXPECT_EQ(required_height_with_border, required_height + border.height());
318
319  // Test that the border width is subtracted before doing the height
320  // calculation.  If it is, then the height will grow when width
321  // is shrunk.
322  int height1 = label.GetHeightForWidth(required_width_with_border - 1);
323#if defined(OS_WIN)
324  // Canvas::SizeStringInt (in ui/gfx/canvas_linux.cc)
325  // has to be fixed to return the size that fits to given width/height.
326  EXPECT_GT(height1, required_height_with_border);
327#endif
328  EXPECT_EQ(height1, height_for_constrained_width + border.height());
329
330  // GetPreferredSize and borders.
331  label.SetBounds(0, 0, 0, 0);
332  gfx::Size required_size_with_border = label.GetPreferredSize();
333  EXPECT_EQ(required_size_with_border.height(),
334            required_size.height() + border.height());
335  EXPECT_EQ(required_size_with_border.width(),
336            required_size.width() + border.width());
337}
338
339TEST_F(LabelTest, DirectionalityFromText) {
340  Label label;
341  label.SetBounds(0, 0, 1000, 1000);
342  base::string16 paint_text;
343  gfx::Rect text_bounds;
344  int flags = -1;
345
346  // Test text starts with RTL character.
347  label.SetText(base::WideToUTF16(L"  \x5d0\x5d1\x5d2 abc"));
348  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
349  EXPECT_EQ(gfx::Canvas::FORCE_RTL_DIRECTIONALITY,
350            flags & (gfx::Canvas::FORCE_RTL_DIRECTIONALITY |
351                     gfx::Canvas::FORCE_LTR_DIRECTIONALITY));
352
353  // Test text starts with LTR character.
354  label.SetText(base::WideToUTF16(L"ltr \x5d0\x5d1\x5d2 abc"));
355  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
356  EXPECT_EQ(gfx::Canvas::FORCE_LTR_DIRECTIONALITY,
357            flags & (gfx::Canvas::FORCE_RTL_DIRECTIONALITY |
358                     gfx::Canvas::FORCE_LTR_DIRECTIONALITY));
359}
360
361TEST_F(LabelTest, DrawSingleLineString) {
362  Label label;
363  label.SetFocusable(false);
364
365  label.SetText(ASCIIToUTF16("Here's a string with no returns."));
366  gfx::Size required_size(label.GetPreferredSize());
367  gfx::Size extra(22, 8);
368  label.SetBounds(0, 0, required_size.width() + extra.width(),
369                  required_size.height() + extra.height());
370
371  // Do some basic verifications for all three alignments.
372  base::string16 paint_text;
373  gfx::Rect text_bounds;
374  int flags = -1;
375
376  // Centered text.
377  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
378  EXPECT_EQ(label.text(), paint_text);
379  // The text should be centered horizontally and vertically.
380  EXPECT_EQ(extra.width() / 2, text_bounds.x());
381  EXPECT_EQ(0, text_bounds.y());
382  EXPECT_EQ(required_size.width(), text_bounds.width());
383  EXPECT_EQ(label.height(), text_bounds.height());
384  EXPECT_EQ(gfx::Canvas::TEXT_ALIGN_CENTER,
385            flags & (gfx::Canvas::TEXT_ALIGN_LEFT |
386                     gfx::Canvas::TEXT_ALIGN_CENTER |
387                     gfx::Canvas::TEXT_ALIGN_RIGHT));
388
389  // Left aligned text.
390  label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
391  paint_text.clear();
392  text_bounds.SetRect(0, 0, 0, 0);
393  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
394  EXPECT_EQ(label.text(), paint_text);
395  // The text should be left aligned horizontally and centered vertically.
396  EXPECT_EQ(0, text_bounds.x());
397  EXPECT_EQ(0, text_bounds.y());
398  EXPECT_EQ(required_size.width(), text_bounds.width());
399  EXPECT_EQ(label.height(), text_bounds.height());
400  EXPECT_EQ(gfx::Canvas::TEXT_ALIGN_LEFT,
401            flags & (gfx::Canvas::TEXT_ALIGN_LEFT |
402                     gfx::Canvas::TEXT_ALIGN_CENTER |
403                     gfx::Canvas::TEXT_ALIGN_RIGHT));
404
405  // Right aligned text.
406  label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
407  paint_text.clear();
408  text_bounds.SetRect(0, 0, 0, 0);
409  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
410  EXPECT_EQ(label.text(), paint_text);
411  // The text should be right aligned horizontally and centered vertically.
412  EXPECT_EQ(extra.width(), text_bounds.x());
413  EXPECT_EQ(0, text_bounds.y());
414  EXPECT_EQ(required_size.width(), text_bounds.width());
415  EXPECT_EQ(label.height(), text_bounds.height());
416  EXPECT_EQ(gfx::Canvas::TEXT_ALIGN_RIGHT,
417            flags & (gfx::Canvas::TEXT_ALIGN_LEFT |
418                     gfx::Canvas::TEXT_ALIGN_CENTER |
419                     gfx::Canvas::TEXT_ALIGN_RIGHT));
420
421  // Test single line drawing with a border.
422  gfx::Insets border(39, 34, 8, 96);
423  label.SetBorder(Border::CreateEmptyBorder(
424      border.top(), border.left(), border.bottom(), border.right()));
425
426  gfx::Size required_size_with_border(label.GetPreferredSize());
427  EXPECT_EQ(required_size.width() + border.width(),
428            required_size_with_border.width());
429  EXPECT_EQ(required_size.height() + border.height(),
430            required_size_with_border.height());
431  label.SetBounds(0, 0, required_size_with_border.width() + extra.width(),
432                  required_size_with_border.height() + extra.height());
433
434  // Centered text with border.
435  label.SetHorizontalAlignment(gfx::ALIGN_CENTER);
436  paint_text.clear();
437  text_bounds.SetRect(0, 0, 0, 0);
438  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
439  EXPECT_EQ(label.text(), paint_text);
440  // The text should be centered horizontally and vertically within the border.
441  EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
442  EXPECT_EQ(border.top(), text_bounds.y());
443  EXPECT_EQ(required_size.width(), text_bounds.width());
444  EXPECT_EQ(label.GetContentsBounds().height(), text_bounds.height());
445  EXPECT_EQ(gfx::Canvas::TEXT_ALIGN_CENTER,
446            flags & (gfx::Canvas::TEXT_ALIGN_LEFT |
447                     gfx::Canvas::TEXT_ALIGN_CENTER |
448                     gfx::Canvas::TEXT_ALIGN_RIGHT));
449
450  // Left aligned text with border.
451  label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
452  paint_text.clear();
453  text_bounds.SetRect(0, 0, 0, 0);
454  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
455  EXPECT_EQ(label.text(), paint_text);
456  // The text should be left aligned horizontally and centered vertically.
457  EXPECT_EQ(border.left(), text_bounds.x());
458  EXPECT_EQ(border.top(), text_bounds.y());
459  EXPECT_EQ(required_size.width(), text_bounds.width());
460  EXPECT_EQ(label.GetContentsBounds().height(), text_bounds.height());
461  EXPECT_EQ(gfx::Canvas::TEXT_ALIGN_LEFT,
462            flags & (gfx::Canvas::TEXT_ALIGN_LEFT |
463                     gfx::Canvas::TEXT_ALIGN_CENTER |
464                     gfx::Canvas::TEXT_ALIGN_RIGHT));
465
466  // Right aligned text.
467  label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
468  paint_text.clear();
469  text_bounds.SetRect(0, 0, 0, 0);
470  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
471  EXPECT_EQ(label.text(), paint_text);
472  // The text should be right aligned horizontally and centered vertically.
473  EXPECT_EQ(border.left() + extra.width(), text_bounds.x());
474  EXPECT_EQ(border.top(), text_bounds.y());
475  EXPECT_EQ(required_size.width(), text_bounds.width());
476  EXPECT_EQ(label.GetContentsBounds().height(), text_bounds.height());
477  EXPECT_EQ(gfx::Canvas::TEXT_ALIGN_RIGHT,
478            flags & (gfx::Canvas::TEXT_ALIGN_LEFT |
479                     gfx::Canvas::TEXT_ALIGN_CENTER |
480                     gfx::Canvas::TEXT_ALIGN_RIGHT));
481}
482
483// Pango needs a max height to elide multiline text; that is not supported here.
484TEST_F(LabelTest, DrawMultiLineString) {
485  Label label;
486  label.SetFocusable(false);
487  // Set a background color to prevent gfx::Canvas::NO_SUBPIXEL_RENDERING flags.
488  label.SetBackgroundColor(SK_ColorWHITE);
489
490  label.SetText(ASCIIToUTF16("Another string\nwith returns\n\n!"));
491  label.SetMultiLine(true);
492  label.SizeToFit(0);
493  gfx::Size extra(50, 10);
494  label.SetBounds(label.x(), label.y(),
495                  label.width() + extra.width(),
496                  label.height() + extra.height());
497
498  // Do some basic verifications for all three alignments.
499  base::string16 paint_text;
500  gfx::Rect text_bounds;
501  int flags = -1;
502  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
503  EXPECT_EQ(label.text(), paint_text);
504  EXPECT_EQ(extra.width() / 2, text_bounds.x());
505  EXPECT_EQ(extra.height() / 2, text_bounds.y());
506  EXPECT_GT(text_bounds.width(), kMinTextDimension);
507  EXPECT_GT(text_bounds.height(), kMinTextDimension);
508  int expected_flags = gfx::Canvas::MULTI_LINE |
509                       gfx::Canvas::TEXT_ALIGN_CENTER |
510                       gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
511#if !defined(OS_WIN)
512  expected_flags |= gfx::Canvas::NO_ELLIPSIS;
513#endif
514  EXPECT_EQ(expected_flags, expected_flags);
515  gfx::Rect center_bounds(text_bounds);
516
517  label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
518  paint_text.clear();
519  text_bounds.SetRect(0, 0, 0, 0);
520  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
521  EXPECT_EQ(label.text(), paint_text);
522  EXPECT_EQ(0, text_bounds.x());
523  EXPECT_EQ(extra.height() / 2, text_bounds.y());
524  EXPECT_GT(text_bounds.width(), kMinTextDimension);
525  EXPECT_GT(text_bounds.height(), kMinTextDimension);
526  expected_flags = gfx::Canvas::MULTI_LINE |
527                   gfx::Canvas::TEXT_ALIGN_LEFT |
528                   gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
529#if !defined(OS_WIN)
530  expected_flags |= gfx::Canvas::NO_ELLIPSIS;
531#endif
532  EXPECT_EQ(expected_flags, expected_flags);
533
534  label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
535  paint_text.clear();
536  text_bounds.SetRect(0, 0, 0, 0);
537  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
538  EXPECT_EQ(label.text(), paint_text);
539  EXPECT_EQ(extra.width(), text_bounds.x());
540  EXPECT_EQ(extra.height() / 2, text_bounds.y());
541  EXPECT_GT(text_bounds.width(), kMinTextDimension);
542  EXPECT_GT(text_bounds.height(), kMinTextDimension);
543  expected_flags = gfx::Canvas::MULTI_LINE |
544                   gfx::Canvas::TEXT_ALIGN_RIGHT |
545                   gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
546#if !defined(OS_WIN)
547  expected_flags |= gfx::Canvas::NO_ELLIPSIS;
548#endif
549  EXPECT_EQ(expected_flags, expected_flags);
550
551  // Test multiline drawing with a border.
552  gfx::Insets border(19, 92, 23, 2);
553  label.SetBorder(Border::CreateEmptyBorder(
554      border.top(), border.left(), border.bottom(), border.right()));
555  label.SizeToFit(0);
556  label.SetBounds(label.x(), label.y(),
557                  label.width() + extra.width(),
558                  label.height() + extra.height());
559
560  label.SetHorizontalAlignment(gfx::ALIGN_CENTER);
561  paint_text.clear();
562  text_bounds.SetRect(0, 0, 0, 0);
563  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
564  EXPECT_EQ(label.text(), paint_text);
565  EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
566  EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
567  EXPECT_EQ(center_bounds.width(), text_bounds.width());
568  EXPECT_EQ(center_bounds.height(), text_bounds.height());
569  expected_flags = gfx::Canvas::MULTI_LINE |
570                   gfx::Canvas::TEXT_ALIGN_CENTER |
571                   gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
572#if !defined(OS_WIN)
573  expected_flags |= gfx::Canvas::NO_ELLIPSIS;
574#endif
575  EXPECT_EQ(expected_flags, expected_flags);
576
577  label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
578  paint_text.clear();
579  text_bounds.SetRect(0, 0, 0, 0);
580  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
581  EXPECT_EQ(label.text(), paint_text);
582  EXPECT_EQ(border.left(), text_bounds.x());
583  EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
584  EXPECT_EQ(center_bounds.width(), text_bounds.width());
585  EXPECT_EQ(center_bounds.height(), text_bounds.height());
586  expected_flags = gfx::Canvas::MULTI_LINE |
587                   gfx::Canvas::TEXT_ALIGN_LEFT |
588                   gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
589#if !defined(OS_WIN)
590  expected_flags |= gfx::Canvas::NO_ELLIPSIS;
591#endif
592  EXPECT_EQ(expected_flags, expected_flags);
593
594  label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
595  paint_text.clear();
596  text_bounds.SetRect(0, 0, 0, 0);
597  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
598  EXPECT_EQ(label.text(), paint_text);
599  EXPECT_EQ(extra.width() + border.left(), text_bounds.x());
600  EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
601  EXPECT_EQ(center_bounds.width(), text_bounds.width());
602  EXPECT_EQ(center_bounds.height(), text_bounds.height());
603  expected_flags = gfx::Canvas::MULTI_LINE |
604                   gfx::Canvas::TEXT_ALIGN_RIGHT |
605                   gfx::Canvas::FORCE_LTR_DIRECTIONALITY;
606#if !defined(OS_WIN)
607  expected_flags |= gfx::Canvas::NO_ELLIPSIS;
608#endif
609  EXPECT_EQ(expected_flags, expected_flags);
610}
611
612TEST_F(LabelTest, DrawSingleLineStringInRTL) {
613  Label label;
614  label.SetFocusable(false);
615
616  std::string locale = l10n_util::GetApplicationLocale("");
617  base::i18n::SetICUDefaultLocale("he");
618
619  label.SetText(ASCIIToUTF16("Here's a string with no returns."));
620  gfx::Size required_size(label.GetPreferredSize());
621  gfx::Size extra(22, 8);
622  label.SetBounds(0, 0, required_size.width() + extra.width(),
623                  required_size.height() + extra.height());
624
625  // Do some basic verifications for all three alignments.
626  base::string16 paint_text;
627  gfx::Rect text_bounds;
628  int flags = -1;
629
630  // Centered text.
631  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
632  EXPECT_EQ(label.text(), paint_text);
633  // The text should be centered horizontally and vertically.
634  EXPECT_EQ(extra.width() / 2, text_bounds.x());
635  EXPECT_EQ(0, text_bounds.y());
636  EXPECT_EQ(required_size.width(), text_bounds.width());
637  EXPECT_EQ(label.height(), text_bounds.height());
638  EXPECT_EQ(gfx::Canvas::TEXT_ALIGN_CENTER,
639            flags & (gfx::Canvas::TEXT_ALIGN_LEFT |
640                     gfx::Canvas::TEXT_ALIGN_CENTER |
641                     gfx::Canvas::TEXT_ALIGN_RIGHT));
642
643  // ALIGN_LEFT label.
644  label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
645  paint_text.clear();
646  text_bounds.SetRect(0, 0, 0, 0);
647  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
648  EXPECT_EQ(label.text(), paint_text);
649  // The text should be right aligned horizontally and centered vertically.
650  EXPECT_EQ(extra.width(), text_bounds.x());
651  EXPECT_EQ(0, text_bounds.y());
652  EXPECT_EQ(required_size.width(), text_bounds.width());
653  EXPECT_EQ(label.height(), text_bounds.height());
654  EXPECT_EQ(gfx::Canvas::TEXT_ALIGN_RIGHT,
655            flags & (gfx::Canvas::TEXT_ALIGN_LEFT |
656                     gfx::Canvas::TEXT_ALIGN_CENTER |
657                     gfx::Canvas::TEXT_ALIGN_RIGHT));
658
659  // ALIGN_RIGHT label.
660  label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
661  paint_text.clear();
662  text_bounds.SetRect(0, 0, 0, 0);
663  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
664  EXPECT_EQ(label.text(), paint_text);
665  // The text should be left aligned horizontally and centered vertically.
666  EXPECT_EQ(0, text_bounds.x());
667  EXPECT_EQ(0, text_bounds.y());
668  EXPECT_EQ(required_size.width(), text_bounds.width());
669  EXPECT_EQ(label.height(), text_bounds.height());
670  EXPECT_EQ(gfx::Canvas::TEXT_ALIGN_LEFT,
671            flags & (gfx::Canvas::TEXT_ALIGN_LEFT |
672                     gfx::Canvas::TEXT_ALIGN_CENTER |
673                     gfx::Canvas::TEXT_ALIGN_RIGHT));
674
675
676  // Test single line drawing with a border.
677  gfx::Insets border(39, 34, 8, 96);
678  label.SetBorder(Border::CreateEmptyBorder(
679      border.top(), border.left(), border.bottom(), border.right()));
680
681  gfx::Size required_size_with_border(label.GetPreferredSize());
682  EXPECT_EQ(required_size.width() + border.width(),
683            required_size_with_border.width());
684  EXPECT_EQ(required_size.height() + border.height(),
685            required_size_with_border.height());
686  label.SetBounds(0, 0, required_size_with_border.width() + extra.width(),
687                  required_size_with_border.height() + extra.height());
688
689  // Centered text with border.
690  label.SetHorizontalAlignment(gfx::ALIGN_CENTER);
691  paint_text.clear();
692  text_bounds.SetRect(0, 0, 0, 0);
693  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
694  EXPECT_EQ(label.text(), paint_text);
695  // The text should be centered horizontally and vertically within the border.
696  EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
697  EXPECT_EQ(border.top(), text_bounds.y());
698  EXPECT_EQ(required_size.width(), text_bounds.width());
699  EXPECT_EQ(label.GetContentsBounds().height(), text_bounds.height());
700  EXPECT_EQ(gfx::Canvas::TEXT_ALIGN_CENTER,
701            flags & (gfx::Canvas::TEXT_ALIGN_LEFT |
702                     gfx::Canvas::TEXT_ALIGN_CENTER |
703                     gfx::Canvas::TEXT_ALIGN_RIGHT));
704
705  // ALIGN_LEFT text with border.
706  label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
707  paint_text.clear();
708  text_bounds.SetRect(0, 0, 0, 0);
709  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
710  EXPECT_EQ(label.text(), paint_text);
711  // The text should be right aligned horizontally and centered vertically.
712  EXPECT_EQ(border.left() + extra.width(), text_bounds.x());
713  EXPECT_EQ(border.top(), text_bounds.y());
714  EXPECT_EQ(required_size.width(), text_bounds.width());
715  EXPECT_EQ(label.GetContentsBounds().height(), text_bounds.height());
716  EXPECT_EQ(gfx::Canvas::TEXT_ALIGN_RIGHT,
717            flags & (gfx::Canvas::TEXT_ALIGN_LEFT |
718                     gfx::Canvas::TEXT_ALIGN_CENTER |
719                     gfx::Canvas::TEXT_ALIGN_RIGHT));
720
721  // ALIGN_RIGHT text.
722  label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
723  paint_text.clear();
724  text_bounds.SetRect(0, 0, 0, 0);
725  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
726  EXPECT_EQ(label.text(), paint_text);
727  // The text should be left aligned horizontally and centered vertically.
728  EXPECT_EQ(border.left(), text_bounds.x());
729  EXPECT_EQ(border.top(), text_bounds.y());
730  EXPECT_EQ(required_size.width(), text_bounds.width());
731  EXPECT_EQ(label.GetContentsBounds().height(), text_bounds.height());
732  EXPECT_EQ(gfx::Canvas::TEXT_ALIGN_LEFT,
733            flags & (gfx::Canvas::TEXT_ALIGN_LEFT |
734                     gfx::Canvas::TEXT_ALIGN_CENTER |
735                     gfx::Canvas::TEXT_ALIGN_RIGHT));
736
737  // Reset locale.
738  base::i18n::SetICUDefaultLocale(locale);
739}
740
741// On Linux the underlying pango routines require a max height in order to
742// ellide multiline text. So until that can be resolved, we set all
743// multiline lables to not ellide in Linux only.
744TEST_F(LabelTest, DrawMultiLineStringInRTL) {
745  Label label;
746  label.SetFocusable(false);
747
748  // Test for RTL.
749  std::string locale = l10n_util::GetApplicationLocale("");
750  base::i18n::SetICUDefaultLocale("he");
751
752  label.SetText(ASCIIToUTF16("Another string\nwith returns\n\n!"));
753  label.SetMultiLine(true);
754  label.SizeToFit(0);
755  gfx::Size extra(50, 10);
756  label.SetBounds(label.x(), label.y(),
757                  label.width() + extra.width(),
758                  label.height() + extra.height());
759
760  // Do some basic verifications for all three alignments.
761  base::string16 paint_text;
762  gfx::Rect text_bounds;
763  int flags = -1;
764  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
765  EXPECT_EQ(label.text(), paint_text);
766  EXPECT_EQ(extra.width() / 2, text_bounds.x());
767  EXPECT_EQ(extra.height() / 2, text_bounds.y());
768  EXPECT_GT(text_bounds.width(), kMinTextDimension);
769  EXPECT_GT(text_bounds.height(), kMinTextDimension);
770  EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
771  EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_CENTER & flags);
772#if !defined(OS_WIN)
773  EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
774#endif
775  gfx::Rect center_bounds(text_bounds);
776
777  label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
778  paint_text.clear();
779  text_bounds.SetRect(0, 0, 0, 0);
780  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
781  EXPECT_EQ(label.text(), paint_text);
782  EXPECT_EQ(extra.width(), text_bounds.x());
783  EXPECT_EQ(extra.height() / 2, text_bounds.y());
784  EXPECT_GT(text_bounds.width(), kMinTextDimension);
785  EXPECT_GT(text_bounds.height(), kMinTextDimension);
786  EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
787  EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_RIGHT & flags);
788#if !defined(OS_WIN)
789  EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
790#endif
791
792  label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
793  paint_text.clear();
794  text_bounds.SetRect(0, 0, 0, 0);
795  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
796  EXPECT_EQ(label.text(), paint_text);
797  EXPECT_EQ(0, text_bounds.x());
798  EXPECT_EQ(extra.height() / 2, text_bounds.y());
799  EXPECT_GT(text_bounds.width(), kMinTextDimension);
800  EXPECT_GT(text_bounds.height(), kMinTextDimension);
801  EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
802  EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_LEFT & flags);
803#if !defined(OS_WIN)
804  EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
805#endif
806
807  // Test multiline drawing with a border.
808  gfx::Insets border(19, 92, 23, 2);
809  label.SetBorder(Border::CreateEmptyBorder(
810      border.top(), border.left(), border.bottom(), border.right()));
811  label.SizeToFit(0);
812  label.SetBounds(label.x(), label.y(),
813                  label.width() + extra.width(),
814                  label.height() + extra.height());
815
816  label.SetHorizontalAlignment(gfx::ALIGN_CENTER);
817  paint_text.clear();
818  text_bounds.SetRect(0, 0, 0, 0);
819  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
820  EXPECT_EQ(label.text(), paint_text);
821  EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
822  EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
823  EXPECT_EQ(center_bounds.width(), text_bounds.width());
824  EXPECT_EQ(center_bounds.height(), text_bounds.height());
825  EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
826  EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_CENTER & flags);
827#if !defined(OS_WIN)
828  EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
829#endif
830
831  label.SetHorizontalAlignment(gfx::ALIGN_LEFT);
832  paint_text.clear();
833  text_bounds.SetRect(0, 0, 0, 0);
834  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
835  EXPECT_EQ(label.text(), paint_text);
836  EXPECT_EQ(border.left() + extra.width(), text_bounds.x());
837  EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
838  EXPECT_EQ(center_bounds.width(), text_bounds.width());
839  EXPECT_EQ(center_bounds.height(), text_bounds.height());
840  EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
841  EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_RIGHT & flags);
842#if !defined(OS_WIN)
843  EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
844#endif
845
846  label.SetHorizontalAlignment(gfx::ALIGN_RIGHT);
847  paint_text.clear();
848  text_bounds.SetRect(0, 0, 0, 0);
849  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
850  EXPECT_EQ(label.text(), paint_text);
851  EXPECT_EQ(border.left(), text_bounds.x());
852  EXPECT_EQ(border.top() + extra.height() / 2, text_bounds.y());
853  EXPECT_EQ(center_bounds.width(), text_bounds.width());
854  EXPECT_EQ(center_bounds.height(), text_bounds.height());
855  EXPECT_TRUE(gfx::Canvas::MULTI_LINE & flags);
856  EXPECT_TRUE(gfx::Canvas::TEXT_ALIGN_LEFT & flags);
857#if !defined(OS_WIN)
858  EXPECT_TRUE(gfx::Canvas::NO_ELLIPSIS & flags);
859#endif
860
861  // Reset Locale
862  base::i18n::SetICUDefaultLocale(locale);
863}
864
865// Ensure the subpixel rendering flag and background color alpha are respected.
866TEST_F(LabelTest, DisableSubpixelRendering) {
867  Label label;
868  label.SetBackgroundColor(SK_ColorWHITE);
869  const int flag = gfx::Canvas::NO_SUBPIXEL_RENDERING;
870  EXPECT_EQ(0, label.ComputeDrawStringFlags() & flag);
871  label.SetSubpixelRenderingEnabled(false);
872  EXPECT_EQ(flag, label.ComputeDrawStringFlags() & flag);
873  label.SetSubpixelRenderingEnabled(true);
874  EXPECT_EQ(0, label.ComputeDrawStringFlags() & flag);
875  // Text cannot be drawn with subpixel rendering on transparent backgrounds.
876  label.SetBackgroundColor(SkColorSetARGB(64, 255, 255, 255));
877  EXPECT_EQ(flag, label.ComputeDrawStringFlags() & flag);
878}
879
880// Check that labels support GetTooltipHandlerForPoint.
881TEST_F(LabelTest, GetTooltipHandlerForPoint) {
882  // A root view must be defined for this test because the hit-testing
883  // behaviour used by GetTooltipHandlerForPoint() is defined by
884  // the ViewTargeter installed on the root view.
885  Widget widget;
886  Widget::InitParams init_params =
887      CreateParams(Widget::InitParams::TYPE_POPUP);
888  init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
889  init_params.bounds = gfx::Rect(0, 0, 200, 200);
890  widget.Init(init_params);
891
892  Label label;
893  label.SetText(
894      ASCIIToUTF16("A string that's long enough to exceed the bounds"));
895  label.SetBounds(0, 0, 10, 10);
896  widget.SetContentsView(&label);
897
898  // There's a default tooltip if the text is too big to fit.
899  EXPECT_EQ(&label, label.GetTooltipHandlerForPoint(gfx::Point(2, 2)));
900
901  // If there's no default tooltip, this should return NULL.
902  label.SetBounds(0, 0, 500, 50);
903  EXPECT_FALSE(label.GetTooltipHandlerForPoint(gfx::Point(2, 2)));
904
905  label.SetTooltipText(ASCIIToUTF16("a tooltip"));
906  // If the point hits the label, and tooltip is set, the label should be
907  // returned as its tooltip handler.
908  EXPECT_EQ(&label, label.GetTooltipHandlerForPoint(gfx::Point(2, 2)));
909
910  // Additionally, GetTooltipHandlerForPoint should verify that the label
911  // actually contains the point.
912  EXPECT_FALSE(label.GetTooltipHandlerForPoint(gfx::Point(2, 51)));
913  EXPECT_FALSE(label.GetTooltipHandlerForPoint(gfx::Point(-1, 20)));
914
915  // GetTooltipHandlerForPoint works should work in child bounds.
916  label.SetBounds(2, 2, 10, 10);
917  EXPECT_EQ(&label, label.GetTooltipHandlerForPoint(gfx::Point(1, 5)));
918  EXPECT_FALSE(label.GetTooltipHandlerForPoint(gfx::Point(3, 11)));
919}
920
921}  // namespace views
922