| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/corewm/tooltip_aura.h" | 5 #include "ui/views/corewm/tooltip_aura.h" |
| 6 | 6 |
| 7 #include "base/strings/string_split.h" |
| 7 #include "base/strings/utf_string_conversions.h" | 8 #include "base/strings/utf_string_conversions.h" |
| 8 #include "ui/aura/test/aura_test_base.h" | 9 #include "ui/aura/test/aura_test_base.h" |
| 9 #include "ui/base/resource/resource_bundle.h" | |
| 10 #include "ui/gfx/font_list.h" | 10 #include "ui/gfx/font_list.h" |
| 11 #include "ui/gfx/text_elider.h" | 11 #include "ui/gfx/text_elider.h" |
| 12 #include "ui/gfx/text_utils.h" | 12 #include "ui/gfx/text_utils.h" |
| 13 | 13 |
| 14 using base::ASCIIToUTF16; | |
| 15 using base::UTF8ToUTF16; | |
| 16 | |
| 17 namespace views { | 14 namespace views { |
| 18 namespace corewm { | 15 namespace corewm { |
| 19 | 16 |
| 17 namespace { |
| 18 |
| 19 // Generates a string consisting of repeated copies of |word| separated by |
| 20 // |separator|. The string will be long enough to fill |num_lines| lines wrapped |
| 21 // at |max_width| pixels. |
| 22 base::string16 FillLines(const base::string16& word, |
| 23 const base::string16& separator, |
| 24 int max_width, |
| 25 int num_lines, |
| 26 const gfx::FontList& font_list) { |
| 27 base::string16 text; |
| 28 for (int lines = 0; lines < num_lines; ++lines) { |
| 29 base::string16 line = word; |
| 30 while (gfx::GetStringWidth(line + separator + word, font_list) <= max_width) |
| 31 line += separator + word; |
| 32 |
| 33 if (lines != 0) |
| 34 text += separator; |
| 35 text += line; |
| 36 } |
| 37 return text; |
| 38 } |
| 39 |
| 40 } // namespace |
| 41 |
| 20 typedef aura::test::AuraTestBase TooltipAuraTest; | 42 typedef aura::test::AuraTestBase TooltipAuraTest; |
| 21 | 43 |
| 22 TEST_F(TooltipAuraTest, TrimTooltipToFitTests) { | 44 TEST_F(TooltipAuraTest, TrimTooltipToFit) { |
| 23 const gfx::FontList font_list; | 45 const gfx::FontList kFontList; |
| 24 const int max_width = 4000; | 46 const gfx::Size kMaxSize(2000, 1500); |
| 25 base::string16 tooltip; | 47 const base::string16 kWord = base::ASCIIToUTF16("word"); |
| 26 int width, line_count, expect_lines; | 48 const base::string16 kSpace = base::ASCIIToUTF16(" "); |
| 27 int max_pixel_width = 400; // copied from constants in tooltip_controller.cc | 49 const base::string16 kNewline = base::ASCIIToUTF16("\n"); |
| 28 int max_lines = 10; // copied from constants in tooltip_controller.cc | |
| 29 size_t tooltip_len; | |
| 30 | 50 |
| 31 // Error in computed size vs. expected size should not be greater than the | 51 // Long tooltips should wrap to the next line. |
| 32 // size of the longest word. | 52 base::string16 text = FillLines(kWord, kSpace, |
| 33 int error_in_pixel_width = gfx::GetStringWidth(ASCIIToUTF16("tooltip"), | 53 TooltipAura::kPreferredWidthPixels, 1, kFontList); |
| 34 font_list); | 54 text += kSpace + kWord; |
| 55 // The last space should be replaced by a newline. |
| 56 base::string16 expected_text = text; |
| 57 expected_text[expected_text.find_last_of(L' ')] = L'\n'; |
| 58 int width = 0, line_count = 0; |
| 59 TooltipAura::TrimTooltipToFit(kFontList, kMaxSize, &text, &width, |
| 60 &line_count); |
| 61 EXPECT_LE(width, TooltipAura::kPreferredWidthPixels); |
| 62 EXPECT_EQ(2, line_count); |
| 63 EXPECT_EQ(expected_text, text); |
| 35 | 64 |
| 36 // Long tooltips should wrap to next line | 65 // The tooltip should be truncated to the number of lines that fit in the |
| 37 tooltip.clear(); | 66 // passed-in maximum size. |
| 38 width = line_count = -1; | 67 int max_lines = kMaxSize.height() / kFontList.GetHeight(); |
| 39 expect_lines = 3; | 68 text = FillLines( |
| 40 for (; gfx::GetStringWidth(tooltip, font_list) <= | 69 kWord, kSpace, TooltipAura::kPreferredWidthPixels, max_lines, kFontList); |
| 41 (expect_lines - 1) * max_pixel_width;) | 70 text += kSpace + kWord; |
| 42 tooltip.append(ASCIIToUTF16("This is part of the tooltip")); | 71 size_t orig_length = text.size(); |
| 43 tooltip_len = tooltip.length(); | 72 TooltipAura::TrimTooltipToFit(kFontList, kMaxSize, &text, &width, |
| 44 TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width, | |
| 45 &line_count); | 73 &line_count); |
| 46 EXPECT_NEAR(max_pixel_width, width, error_in_pixel_width); | 74 EXPECT_LE(width, TooltipAura::kPreferredWidthPixels); |
| 47 EXPECT_EQ(expect_lines, line_count); | 75 EXPECT_EQ(max_lines, line_count); |
| 48 EXPECT_EQ(tooltip_len + expect_lines - 1, tooltip.length()); | 76 EXPECT_LT(text.size(), orig_length); |
| 49 | 77 |
| 50 // More than |max_lines| lines should get truncated at 10 lines. | 78 // When the original string contains two long lines, each line should be |
| 51 tooltip.clear(); | 79 // wrapped individually. |
| 52 width = line_count = -1; | 80 base::string16 line = FillLines( |
| 53 expect_lines = 13; | 81 kWord, kSpace, TooltipAura::kPreferredWidthPixels, 1, kFontList); |
| 54 for (; gfx::GetStringWidth(tooltip, font_list) <= | 82 text = line + kSpace + kWord + kNewline + line + kSpace + kWord; |
| 55 (expect_lines - 1) * max_pixel_width;) | 83 orig_length = text.size(); |
| 56 tooltip.append(ASCIIToUTF16("This is part of the tooltip")); | 84 TooltipAura::TrimTooltipToFit(kFontList, kMaxSize, &text, &width, |
| 57 TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width, | |
| 58 &line_count); | 85 &line_count); |
| 59 EXPECT_NEAR(max_pixel_width, width, error_in_pixel_width); | 86 EXPECT_LE(width, TooltipAura::kPreferredWidthPixels); |
| 60 EXPECT_EQ(max_lines, line_count); | 87 EXPECT_EQ(4, line_count); |
| 88 std::vector<base::string16> lines; |
| 89 base::SplitString(text, L'\n', &lines); |
| 90 ASSERT_EQ(4U, lines.size()); |
| 91 EXPECT_EQ(line, lines[0]); |
| 92 EXPECT_EQ(kWord, lines[1]); |
| 93 EXPECT_EQ(line, lines[2]); |
| 94 EXPECT_EQ(kWord, lines[3]); |
| 61 | 95 |
| 62 // Long multi line tooltips should wrap individual lines. | 96 // The preferred width should be exceeded if there's a long word. |
| 63 tooltip.clear(); | 97 text = FillLines(kWord, base::string16(), |
| 64 width = line_count = -1; | 98 TooltipAura::kPreferredWidthPixels, 1, kFontList); |
| 65 expect_lines = 4; | 99 text += kWord; |
| 66 for (; gfx::GetStringWidth(tooltip, font_list) <= | 100 expected_text = text; |
| 67 (expect_lines - 2) * max_pixel_width;) | 101 TooltipAura::TrimTooltipToFit(kFontList, kMaxSize, &text, &width, |
| 68 tooltip.append(ASCIIToUTF16("This is part of the tooltip")); | |
| 69 tooltip.insert(tooltip.length() / 2, ASCIIToUTF16("\n")); | |
| 70 tooltip_len = tooltip.length(); | |
| 71 TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width, | |
| 72 &line_count); | 102 &line_count); |
| 73 EXPECT_NEAR(max_pixel_width, width, error_in_pixel_width); | 103 EXPECT_GT(width, TooltipAura::kPreferredWidthPixels); |
| 74 EXPECT_EQ(expect_lines, line_count); | 104 EXPECT_LT(width, kMaxSize.width()); |
| 75 // We may have inserted the line break above near a space which will get | 105 EXPECT_EQ(1, line_count); |
| 76 // trimmed. Hence we may be off by 1 in the final tooltip length calculation. | 106 EXPECT_EQ(expected_text, text); |
| 77 EXPECT_NEAR(tooltip_len + expect_lines - 2, tooltip.length(), 1); | |
| 78 | 107 |
| 79 #if !defined(OS_WIN) | 108 // If a word exceeds the maximum width, it should be elided. |
| 80 // Tooltip with really long word gets elided. | 109 const base::string16 kLongWord = |
| 81 tooltip.clear(); | 110 FillLines(kWord, base::string16(), kMaxSize.width(), 1, kFontList) + |
| 82 width = line_count = -1; | 111 kWord; |
| 83 tooltip = UTF8ToUTF16(std::string('a', max_pixel_width)); | 112 text = kLongWord; |
| 84 TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width, | 113 expected_text = gfx::ElideText( |
| 114 text, kFontList, kMaxSize.width(), gfx::ELIDE_TAIL); |
| 115 TooltipAura::TrimTooltipToFit(kFontList, kMaxSize, &text, &width, |
| 85 &line_count); | 116 &line_count); |
| 86 EXPECT_NEAR(max_pixel_width, width, 5); | 117 EXPECT_GT(width, TooltipAura::kPreferredWidthPixels); |
| 118 EXPECT_LE(width, kMaxSize.width()); |
| 87 EXPECT_EQ(1, line_count); | 119 EXPECT_EQ(1, line_count); |
| 88 EXPECT_EQ(gfx::ElideText(UTF8ToUTF16(std::string('a', max_pixel_width)), | 120 EXPECT_EQ(expected_text, text); |
| 89 font_list, max_pixel_width, gfx::ELIDE_TAIL), | |
| 90 tooltip); | |
| 91 #endif | |
| 92 | 121 |
| 93 // Normal small tooltip should stay as is. | 122 // When a long word makes the tooltip wider than the preferred width, |
| 94 tooltip.clear(); | 123 // other lines should be wrapped at the new, longer size. |
| 95 width = line_count = -1; | 124 text = FillLines(kWord, kSpace, kMaxSize.width(), 1, kFontList); |
| 96 tooltip = ASCIIToUTF16("Small Tooltip"); | 125 text += kNewline + kLongWord; |
| 97 TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width, | 126 text += kNewline + FillLines(kWord, kSpace, kMaxSize.width(), 1, kFontList); |
| 127 TooltipAura::TrimTooltipToFit(kFontList, kMaxSize, &text, &width, |
| 98 &line_count); | 128 &line_count); |
| 99 EXPECT_EQ(gfx::GetStringWidth(ASCIIToUTF16("Small Tooltip"), font_list), | 129 EXPECT_GT(width, TooltipAura::kPreferredWidthPixels); |
| 100 width); | 130 EXPECT_LE(width, kMaxSize.width()); |
| 131 EXPECT_EQ(3, line_count); |
| 132 |
| 133 // A normal small tooltip should stay as is. |
| 134 text = base::ASCIIToUTF16("Small Tooltip"); |
| 135 expected_text = text; |
| 136 TooltipAura::TrimTooltipToFit(kFontList, kMaxSize, &text, &width, |
| 137 &line_count); |
| 138 EXPECT_LE(width, TooltipAura::kPreferredWidthPixels); |
| 101 EXPECT_EQ(1, line_count); | 139 EXPECT_EQ(1, line_count); |
| 102 EXPECT_EQ(ASCIIToUTF16("Small Tooltip"), tooltip); | 140 EXPECT_EQ(expected_text, text); |
| 103 | 141 |
| 104 // Normal small multi-line tooltip should stay as is. | 142 // A normal small multi-line tooltip should stay as is. |
| 105 tooltip.clear(); | 143 text = base::ASCIIToUTF16("Multi line\nTooltip"); |
| 106 width = line_count = -1; | 144 expected_text = text; |
| 107 tooltip = ASCIIToUTF16("Multi line\nTooltip"); | 145 TooltipAura::TrimTooltipToFit(kFontList, kMaxSize, &text, &width, |
| 108 TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width, | |
| 109 &line_count); | 146 &line_count); |
| 110 int expected_width = gfx::GetStringWidth(ASCIIToUTF16("Multi line"), | 147 EXPECT_LE(width, TooltipAura::kPreferredWidthPixels); |
| 111 font_list); | |
| 112 expected_width = std::max(expected_width, | |
| 113 gfx::GetStringWidth(ASCIIToUTF16("Tooltip"), | |
| 114 font_list)); | |
| 115 EXPECT_EQ(expected_width, width); | |
| 116 EXPECT_EQ(2, line_count); | 148 EXPECT_EQ(2, line_count); |
| 117 EXPECT_EQ(ASCIIToUTF16("Multi line\nTooltip"), tooltip); | 149 EXPECT_EQ(expected_text, text); |
| 118 | 150 |
| 119 // Whitespaces in tooltips are preserved. | 151 // Whitespace in the middle of tooltips should be preserved. |
| 120 tooltip.clear(); | 152 text = base::ASCIIToUTF16("Small Tool t\tip"); |
| 121 width = line_count = -1; | 153 expected_text = text; |
| 122 tooltip = ASCIIToUTF16("Small Tool t\tip"); | 154 TooltipAura::TrimTooltipToFit(kFontList, kMaxSize, &text, &width, |
| 123 TooltipAura::TrimTooltipToFit(font_list, max_width, &tooltip, &width, | |
| 124 &line_count); | 155 &line_count); |
| 125 EXPECT_EQ(gfx::GetStringWidth(ASCIIToUTF16("Small Tool t\tip"), font_list), | 156 EXPECT_LE(width, TooltipAura::kPreferredWidthPixels); |
| 126 width); | |
| 127 EXPECT_EQ(1, line_count); | 157 EXPECT_EQ(1, line_count); |
| 128 EXPECT_EQ(ASCIIToUTF16("Small Tool t\tip"), tooltip); | 158 EXPECT_EQ(expected_text, text); |
| 129 } | 159 } |
| 130 | 160 |
| 131 } // namespace corewm | 161 } // namespace corewm |
| 132 } // namespace views | 162 } // namespace views |
| OLD | NEW |