diff options
author | asvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-12 19:58:18 +0000 |
---|---|---|
committer | asvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-12 19:58:18 +0000 |
commit | 9b6e452c3cefd6ae2c3cb199add3c43b20bae214 (patch) | |
tree | 7f382adc8d156068e45b9b9898bf3ae55c9cae2e | |
parent | 8d1558d71bf32daa6d2f4639eea9eda0778a9705 (diff) | |
download | chromium_src-9b6e452c3cefd6ae2c3cb199add3c43b20bae214.zip chromium_src-9b6e452c3cefd6ae2c3cb199add3c43b20bae214.tar.gz chromium_src-9b6e452c3cefd6ae2c3cb199add3c43b20bae214.tar.bz2 |
Change signature of |ui::ElideText()|. Add a truncate mode.
The new truncate mode is needed by my upcoming changes to
rewrite CanvasSkia::DrawText().
Part of the change is changing the binary search code to a
more traditional form that also makes the truncate mode
work correctly. This is covered by the new unit tests.
BUG=105550
TEST=New and existing tests in text_elider_unittest.cc.
Review URL: http://codereview.chromium.org/8917011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114063 0039d316-1c4b-4281-b951-d872f2087c98
17 files changed, 89 insertions, 45 deletions
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm index a854689..4dd32d3 100644 --- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm +++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm @@ -33,7 +33,7 @@ const NSUInteger kMaximumMenuPixelsWide = 300; string16 title = ui::ElideText(node->GetTitle(), font, kMaximumMenuPixelsWide, - false); + ui::ELIDE_AT_END); return base::SysUTF16ToNSString(title); } diff --git a/chrome/browser/ui/cocoa/download/download_item_cell.mm b/chrome/browser/ui/cocoa/download/download_item_cell.mm index 3b29656..f0f06d7 100644 --- a/chrome/browser/ui/cocoa/download/download_item_cell.mm +++ b/chrome/browser/ui/cocoa/download/download_item_cell.mm @@ -352,7 +352,7 @@ const int kInterruptedAnimationDuration = 2.5; base::SysNSStringToUTF16([self secondaryTitle]), font_chr, availableWidth, - false)); + ui::ELIDE_AT_END)); } - (ui::ThemeProvider*)backgroundThemeWrappingProvider: diff --git a/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.mm b/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.mm index 23e733f..ee36d6d 100644 --- a/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.mm +++ b/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.mm @@ -95,7 +95,7 @@ CGFloat EVBubbleDecoration::GetWidthForSpace(CGFloat width) { [font_ pointSize]); NSString* elided_label = base::SysUTF16ToNSString( ui::ElideText(base::SysNSStringToUTF16(full_label_), font, width_left, - true)); + ui::ELIDE_IN_MIDDLE)); // Use the elided label. SetLabel(elided_label); diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm index c77efd7..abb528d 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm @@ -164,7 +164,8 @@ NSMutableAttributedString* OmniboxPopupViewMac::ElideString( } // If ElideText() decides to do nothing, nothing to be done. - const string16 elided = ui::ElideText(originalString, font, width, false); + const string16 elided = + ui::ElideText(originalString, font, width, ui::ELIDE_AT_END); if (0 == elided.compare(originalString)) { return aString; } diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm index 40c0cc6..83fab91 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm @@ -461,14 +461,14 @@ TEST_F(OmniboxPopupViewMacTest, ElideString) { // When elided, result is the same as ElideText(). ret = OmniboxPopupViewMac::ElideString(as, contents16, font_, kNarrow); - string16 elided = ui::ElideText(contents16, font_, kNarrow, false); + string16 elided = ui::ElideText(contents16, font_, kNarrow, ui::ELIDE_AT_END); EXPECT_TRUE(ret == as); EXPECT_FALSE([[as string] isEqualToString:contents]); EXPECT_TRUE([[as string] isEqualToString:base::SysUTF16ToNSString(elided)]); // When elided, result is the same as ElideText(). ret = OmniboxPopupViewMac::ElideString(as, contents16, font_, 0.0); - elided = ui::ElideText(contents16, font_, 0.0, false); + elided = ui::ElideText(contents16, font_, 0.0, ui::ELIDE_AT_END); EXPECT_TRUE(ret == as); EXPECT_FALSE([[as string] isEqualToString:contents]); EXPECT_TRUE([[as string] isEqualToString:base::SysUTF16ToNSString(elided)]); diff --git a/chrome/browser/ui/gtk/avatar_menu_item_gtk.cc b/chrome/browser/ui/gtk/avatar_menu_item_gtk.cc index 195397e..a63539f 100644 --- a/chrome/browser/ui/gtk/avatar_menu_item_gtk.cc +++ b/chrome/browser/ui/gtk/avatar_menu_item_gtk.cc @@ -253,7 +253,7 @@ void AvatarMenuItemGtk::Init(GtkThemeService* theme_service) { string16 elided_name = ui::ElideText(item_.name, gfx::Font(), kUserNameMaxWidth, - /* elide_in_middle */ false); + ui::ELIDE_AT_END); if (item_.active) { name_label = gtk_util::CreateBoldLabel(UTF16ToUTF8(elided_name)); } else { diff --git a/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc b/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc index 3205daf..90c5cc1 100644 --- a/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc @@ -42,7 +42,7 @@ std::string BuildElidedText(const std::string& input) { UTF8ToUTF16(input), gfx::Font(), kMaxLinkPixelSize, - false)); + ui::ELIDE_AT_END)); } } // namespace diff --git a/chrome/browser/ui/toolbar/back_forward_menu_model.cc b/chrome/browser/ui/toolbar/back_forward_menu_model.cc index c9a9f7e..515c57b 100644 --- a/chrome/browser/ui/toolbar/back_forward_menu_model.cc +++ b/chrome/browser/ui/toolbar/back_forward_menu_model.cc @@ -92,7 +92,8 @@ string16 BackForwardMenuModel::GetLabelAt(int index) const { Profile::FromBrowserContext(GetTabContents()->browser_context()); string16 menu_text(entry->GetTitleForDisplay( profile->GetPrefs()->GetString(prefs::kAcceptLanguages))); - menu_text = ui::ElideText(menu_text, gfx::Font(), kMaxWidth, false); + menu_text = + ui::ElideText(menu_text, gfx::Font(), kMaxWidth, ui::ELIDE_AT_END); #if !defined(OS_MACOSX) for (size_t i = menu_text.find('&'); i != string16::npos; diff --git a/chrome/browser/ui/views/autocomplete/autocomplete_result_view.cc b/chrome/browser/ui/views/autocomplete/autocomplete_result_view.cc index 37dd4ca..a1acc9b 100644 --- a/chrome/browser/ui/views/autocomplete/autocomplete_result_view.cc +++ b/chrome/browser/ui/views/autocomplete/autocomplete_result_view.cc @@ -440,7 +440,7 @@ void AutocompleteResultView::Elide(Runs* runs, int remaining_width) const { // Can we fit at least an ellipsis? string16 elided_text = - ui::ElideText(j->text, *j->font, remaining_width, false); + ui::ElideText(j->text, *j->font, remaining_width, ui::ELIDE_AT_END); Classifications::reverse_iterator prior_classification(j); ++prior_classification; const bool on_first_classification = diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc index 3e5fc17..45fe6c3 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc @@ -532,7 +532,8 @@ string16 BookmarkBarView::CreateToolTipForURLAndTitle( if (!title.empty()) { string16 localized_title = title; base::i18n::AdjustStringForLocaleDirection(&localized_title); - result.append(ui::ElideText(localized_title, tt_font, max_width, false)); + result.append(ui::ElideText(localized_title, tt_font, max_width, + ui::ELIDE_AT_END)); } // Only show the URL if the url and title differ. diff --git a/printing/print_settings_initializer.cc b/printing/print_settings_initializer.cc index 8d9065d..e82bbfc 100644 --- a/printing/print_settings_initializer.cc +++ b/printing/print_settings_initializer.cc @@ -47,7 +47,7 @@ void PrintSettingsInitializer::InitHeaderFooterStrings( double segment_width = GetHeaderFooterSegmentWidth(ConvertUnitDouble( print_settings->page_setup_device_units().physical_size().width(), print_settings->device_units_per_inch(), kPixelsPerInch)); - date = ui::ElideText(date, font, segment_width, false); + date = ui::ElideText(date, font, segment_width, ui::ELIDE_AT_END); print_settings->date = date; // Calculate the available title width. If the date string is not long @@ -57,7 +57,8 @@ void PrintSettingsInitializer::InitHeaderFooterStrings( double max_title_width = std::min(2 * segment_width, 2 * (segment_width - date_width) + segment_width); - print_settings->title = ui::ElideText(title, font, max_title_width, false); + print_settings->title = + ui::ElideText(title, font, max_title_width, ui::ELIDE_AT_END); double max_url_width = 2 * segment_width; GURL gurl(url); diff --git a/ui/aura_shell/shell_tooltip_manager.cc b/ui/aura_shell/shell_tooltip_manager.cc index 3f38eda..1062b27 100644 --- a/ui/aura_shell/shell_tooltip_manager.cc +++ b/ui/aura_shell/shell_tooltip_manager.cc @@ -95,7 +95,8 @@ void TrimTooltipToFit(string16* text, string16 result; for (std::vector<string16>::iterator i = lines.begin(); i != lines.end(); ++i) { - string16 elided_text = ui::ElideText(*i, font, available_width, false); + string16 elided_text = + ui::ElideText(*i, font, available_width, ui::ELIDE_AT_END); *max_width = std::max(*max_width, font.GetStringWidth(elided_text)); if (!result.empty()) result.push_back('\n'); diff --git a/ui/base/text/text_elider.cc b/ui/base/text/text_elider.cc index 17f41c4..13ee279 100644 --- a/ui/base/text/text_elider.cc +++ b/ui/base/text/text_elider.cc @@ -94,7 +94,7 @@ string16 ElideComponentizedPath(const string16& url_path_prefix, url_path_elements, url_filename, i); if (available_pixel_width >= font.GetStringWidth(elided_path)) return ElideText(elided_path + url_query, - font, available_pixel_width, false); + font, available_pixel_width, ui::ELIDE_AT_END); } return string16(); @@ -125,7 +125,7 @@ string16 ElideUrl(const GURL& url, // If non-standard or not file type, return plain eliding. if (!(url.SchemeIsFile() || url.IsStandard())) - return ElideText(url_string, font, available_pixel_width, false); + return ElideText(url_string, font, available_pixel_width, ui::ELIDE_AT_END); // Now start eliding url_string to fit within available pixel width. // Fist pass - check to see whether entire url_string fits. @@ -142,7 +142,7 @@ string16 ElideUrl(const GURL& url, // Return general elided text if url minus the query fits. string16 url_minus_query = url_string.substr(0, path_start_index + path_len); if (available_pixel_width >= font.GetStringWidth(url_minus_query)) - return ElideText(url_string, font, available_pixel_width, false); + return ElideText(url_string, font, available_pixel_width, ui::ELIDE_AT_END); // Get Host. string16 url_host = UTF8ToUTF16(url.host()); @@ -213,7 +213,7 @@ string16 ElideUrl(const GURL& url, pixel_width_url_domain + pixel_width_url_path - font.GetStringWidth(url_query))) { return ElideText(url_subdomain + url_domain + url_path_query_etc, - font, available_pixel_width, false); + font, available_pixel_width, ui::ELIDE_AT_END); } } @@ -241,7 +241,7 @@ string16 ElideUrl(const GURL& url, // No path to elide, or too long of a path (could overflow in loop below) // Just elide this as a text string. return ElideText(url_subdomain + url_domain + url_path_query_etc, font, - available_pixel_width, false); + available_pixel_width, ui::ELIDE_AT_END); } // Start eliding the path and replacing elements by ".../". @@ -288,7 +288,8 @@ string16 ElideUrl(const GURL& url, final_elided_url_string += url_path; } - return ElideText(final_elided_url_string, font, available_pixel_width, false); + return ElideText(final_elided_url_string, font, available_pixel_width, + ui::ELIDE_AT_END); } string16 ElideFilename(const FilePath& filename, @@ -313,7 +314,7 @@ string16 ElideFilename(const FilePath& filename, if (rootname.empty() || extension.empty()) { string16 elided_name = ElideText(filename_utf16, font, - available_pixel_width, false); + available_pixel_width, ui::ELIDE_AT_END); return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); } @@ -328,13 +329,14 @@ string16 ElideFilename(const FilePath& filename, if (ext_width >= available_pixel_width) { string16 elided_name = ElideText(rootname + extension, font, - available_pixel_width, true); + available_pixel_width, + ui::ELIDE_IN_MIDDLE); return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); } int available_root_width = available_pixel_width - ext_width; string16 elided_name = - ElideText(rootname, font, available_root_width, false); + ElideText(rootname, font, available_root_width, ui::ELIDE_AT_END); elided_name += extension; return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); } @@ -344,11 +346,13 @@ string16 ElideFilename(const FilePath& filename, string16 ElideText(const string16& text, const gfx::Font& font, int available_pixel_width, - bool elide_in_middle) { + ElideBehavior elide_behavior) { if (text.empty()) return text; int current_text_pixel_width = font.GetStringWidth(text); + bool elide_in_middle = (elide_behavior == ui::ELIDE_IN_MIDDLE); + bool insert_ellipsis = (elide_behavior != ui::TRUNCATE_AT_END); // Pango will return 0 width for absurdly long strings. Cut the string in // half and try again. @@ -360,7 +364,7 @@ string16 ElideText(const string16& text, // ridiculous), but we should check other widths for bogus values as well. if (current_text_pixel_width <= 0 && !text.empty()) { return ElideText(CutString(text, text.length() / 2, elide_in_middle, false), - font, available_pixel_width, false); + font, available_pixel_width, elide_behavior); } if (current_text_pixel_width <= available_pixel_width) @@ -372,24 +376,25 @@ string16 ElideText(const string16& text, // Use binary search to compute the elided text. size_t lo = 0; size_t hi = text.length() - 1; - for (size_t guess = (lo + hi) / 2; guess != lo; guess = (lo + hi) / 2) { + size_t guess; + for (guess = (lo + hi) / 2; lo <= hi; guess = (lo + hi) / 2) { // We check the length of the whole desired string at once to ensure we // handle kerning/ligatures/etc. correctly. - int guess_length = font.GetStringWidth( - CutString(text, guess, elide_in_middle, true)); + string16 cut = CutString(text, guess, elide_in_middle, insert_ellipsis); + int guess_length = font.GetStringWidth(cut); // Check again that we didn't hit a Pango width overflow. If so, cut the // current string in half and start over. if (guess_length <= 0) { return ElideText(CutString(text, guess / 2, elide_in_middle, false), - font, available_pixel_width, elide_in_middle); + font, available_pixel_width, elide_behavior); } if (guess_length > available_pixel_width) - hi = guess; + hi = guess - 1; else - lo = guess; + lo = guess + 1; } - return CutString(text, lo, elide_in_middle, true); + return CutString(text, guess, elide_in_middle, insert_ellipsis); } SortedDisplayURL::SortedDisplayURL(const GURL& url, @@ -576,6 +581,8 @@ class RectangleString { // String onto which the output is accumulated. string16* output_; + + DISALLOW_COPY_AND_ASSIGN(RectangleString); }; void RectangleString::AddString(const string16& input) { diff --git a/ui/base/text/text_elider.h b/ui/base/text/text_elider.h index 7b298ee..a1dd86a 100644 --- a/ui/base/text/text_elider.h +++ b/ui/base/text/text_elider.h @@ -40,13 +40,21 @@ UI_EXPORT string16 ElideUrl(const GURL& url, int available_pixel_width, const std::string& languages); -// Elides |text| to fit in |available_pixel_width|. If |elide_in_middle| is -// set the ellipsis is placed in the middle of the string; otherwise it is -// placed at the end. +enum ElideBehavior { + // Add ellipsis at the end of the string. + ELIDE_AT_END, + // Add ellipsis in the middle of the string. + ELIDE_IN_MIDDLE, + // Truncate the end of the string. + TRUNCATE_AT_END +}; + +// Elides |text| to fit in |available_pixel_width| according to the specified +// |elide_behavior|. UI_EXPORT string16 ElideText(const string16& text, const gfx::Font& font, int available_pixel_width, - bool elide_in_middle); + ElideBehavior elide_behavior); // Elide a filename to fit a given pixel width, with an emphasis on not hiding // the extension unless we have to. If filename contains a path, the path will diff --git a/ui/base/text/text_elider_unittest.cc b/ui/base/text/text_elider_unittest.cc index 60ab1f7..b716a00 100644 --- a/ui/base/text/text_elider_unittest.cc +++ b/ui/base/text/text_elider_unittest.cc @@ -82,8 +82,7 @@ TEST(TextEliderTest, TestGeneralEliding) { // both path AND file name to an ellipsis - ".../...". To avoid this result, // there is a hack in place that simply treats them as one string in this // case. -TEST(TextEliderTest, TestTrailingEllipsisSlashEllipsisHack) -{ +TEST(TextEliderTest, TestTrailingEllipsisSlashEllipsisHack) { const std::string kEllipsisStr(kEllipsis); // Very little space, would cause double ellipsis. @@ -215,6 +214,29 @@ TEST(TextEliderTest, TestFilenameEliding) { } } +TEST(TextEliderTest, ElideTextTruncate) { + const gfx::Font font; + const int kTestWidth = font.GetStringWidth(ASCIIToUTF16("Test")); + struct TestData { + const char* input; + int width; + const char* output; + } cases[] = { + { "", 0, "" }, + { "Test", 0, "" }, + { "", kTestWidth, "" }, + { "Tes", kTestWidth, "Tes" }, + { "Test", kTestWidth, "Test" }, + { "Tests", kTestWidth, "Test" }, + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { + string16 result = ui::ElideText(UTF8ToUTF16(cases[i].input), font, + cases[i].width, ui::TRUNCATE_AT_END); + EXPECT_EQ(cases[i].output, UTF16ToUTF8(result)); + } +} + TEST(TextEliderTest, ElideTextLongStrings) { const string16 kEllipsisStr = UTF8ToUTF16(kEllipsis); string16 data_scheme(UTF8ToUTF16("data:text/plain,")); @@ -247,9 +269,10 @@ TEST(TextEliderTest, ElideTextLongStrings) { EXPECT_EQ(testcases_end[i].output.size(), ElideText(testcases_end[i].input, font, font.GetStringWidth(testcases_end[i].output), - false).size()); + ui::ELIDE_AT_END).size()); EXPECT_EQ(kEllipsisStr, - ElideText(testcases_end[i].input, font, ellipsis_width, false)); + ElideText(testcases_end[i].input, font, ellipsis_width, + ui::ELIDE_AT_END)); } size_t number_of_trailing_as = (data_scheme_length + number_of_as) / 2; @@ -271,10 +294,10 @@ TEST(TextEliderTest, ElideTextLongStrings) { EXPECT_EQ(testcases_middle[i].output.size(), ElideText(testcases_middle[i].input, font, font.GetStringWidth(testcases_middle[i].output), - false).size()); + ui::ELIDE_AT_END).size()); EXPECT_EQ(kEllipsisStr, ElideText(testcases_middle[i].input, font, ellipsis_width, - false)); + ui::ELIDE_AT_END)); } } diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc index 1bf0326..ab46dbd 100644 --- a/ui/views/controls/label.cc +++ b/ui/views/controls/label.cc @@ -485,8 +485,8 @@ void Label::CalculateDrawStringParams(string16* paint_text, *paint_text = base::i18n::GetDisplayStringInLTRDirectionality( *paint_text); } else if (elide_in_middle_) { - *paint_text = ui::ElideText(text_, - font_, GetAvailableRect().width(), true); + *paint_text = ui::ElideText(text_, font_, GetAvailableRect().width(), + ui::ELIDE_IN_MIDDLE); } else { *paint_text = text_; } diff --git a/ui/views/widget/tooltip_manager.cc b/ui/views/widget/tooltip_manager.cc index 7f4d193..5647575 100644 --- a/ui/views/widget/tooltip_manager.cc +++ b/ui/views/widget/tooltip_manager.cc @@ -51,7 +51,8 @@ void TooltipManager::TrimTooltipToFit(string16* text, string16 result; for (std::vector<string16>::iterator i = lines.begin(); i != lines.end(); ++i) { - string16 elided_text = ui::ElideText(*i, font, available_width, false); + string16 elided_text = + ui::ElideText(*i, font, available_width, ui::ELIDE_AT_END); *max_width = std::max(*max_width, font.GetStringWidth(elided_text)); if (!result.empty()) result.push_back('\n'); |