diff options
author | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-10 09:57:19 +0000 |
---|---|---|
committer | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-10 09:57:19 +0000 |
commit | 8ad3c5a758ba0d46bee600f559a7af88d3038ea6 (patch) | |
tree | fd317d0b10b4740b3c0965c14dedd0f945eaf675 | |
parent | 51cc0bd3ab9e3e8d905d4fce624cd352e2d97915 (diff) | |
download | chromium_src-8ad3c5a758ba0d46bee600f559a7af88d3038ea6.zip chromium_src-8ad3c5a758ba0d46bee600f559a7af88d3038ea6.tar.gz chromium_src-8ad3c5a758ba0d46bee600f559a7af88d3038ea6.tar.bz2 |
Uses and returns the fractional width in text eliding
On Mac, the width is repsented as CGFloat due to possible sub-pixel
rendering and extra kerning. We need to return the fractional widt,
instead of the integral width.
Some tests have been updated with the hack removed.
BUG=288987
TEST=new tests plus updating existing tests
Review URL: https://codereview.chromium.org/24883002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@227905 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ui/gfx/canvas.cc | 24 | ||||
-rw-r--r-- | ui/gfx/canvas.h | 17 | ||||
-rw-r--r-- | ui/gfx/canvas_android.cc | 12 | ||||
-rw-r--r-- | ui/gfx/canvas_skia.cc | 18 | ||||
-rw-r--r-- | ui/gfx/canvas_unittest_mac.mm | 50 | ||||
-rw-r--r-- | ui/gfx/render_text.cc | 5 | ||||
-rw-r--r-- | ui/gfx/render_text.h | 8 | ||||
-rw-r--r-- | ui/gfx/render_text_mac.cc | 7 | ||||
-rw-r--r-- | ui/gfx/render_text_mac.h | 3 | ||||
-rw-r--r-- | ui/gfx/text_elider.cc | 139 | ||||
-rw-r--r-- | ui/gfx/text_elider.h | 20 | ||||
-rw-r--r-- | ui/gfx/text_elider_unittest.cc | 193 | ||||
-rw-r--r-- | ui/gfx/text_utils.h | 4 | ||||
-rw-r--r-- | ui/gfx/text_utils_android.cc | 5 | ||||
-rw-r--r-- | ui/gfx/text_utils_ios.mm | 6 | ||||
-rw-r--r-- | ui/gfx/text_utils_skia.cc | 4 |
16 files changed, 286 insertions, 229 deletions
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc index eb0834b..69f10cf 100644 --- a/ui/gfx/canvas.cc +++ b/ui/gfx/canvas.cc @@ -4,6 +4,7 @@ #include "ui/gfx/canvas.h" +#include <cmath> #include <limits> #include "base/i18n/rtl.h" @@ -84,6 +85,21 @@ void Canvas::RecreateBackingCanvas(const Size& size, // static void Canvas::SizeStringInt(const base::string16& text, + const FontList& font_list, + int* width, + int* height, + int line_height, + int flags) { + float fractional_width = *width; + float factional_height = *height; + SizeStringFloat(text, font_list, &fractional_width, + &factional_height, line_height, flags); + *width = std::ceil(fractional_width); + *height = std::ceil(factional_height); +} + +// static +void Canvas::SizeStringInt(const base::string16& text, const Font& font, int* width, int* height, @@ -101,6 +117,14 @@ int Canvas::GetStringWidth(const base::string16& text, } // static +float Canvas::GetStringWidthF(const base::string16& text, + const FontList& font_list) { + float width = 0, height = 0; + SizeStringFloat(text, font_list, &width, &height, 0, NO_ELLIPSIS); + return width; +} + +// static int Canvas::GetStringWidth(const base::string16& text, const Font& font) { int width = 0, height = 0; SizeStringInt(text, FontList(font), &width, &height, 0, NO_ELLIPSIS); diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h index 9aa7a0a..4470023 100644 --- a/ui/gfx/canvas.h +++ b/ui/gfx/canvas.h @@ -139,6 +139,15 @@ class GFX_EXPORT Canvas { int line_height, int flags); + // This is same as SizeStringInt except that fractional size is returned. + // See comment in GetStringWidthF for its usage. + static void SizeStringFloat(const base::string16& text, + const FontList& font_list, + float* width, + float* height, + int line_height, + int flags); + // Returns the number of horizontal pixels needed to display the specified // |text| with |font_list|. static int GetStringWidth(const base::string16& text, @@ -146,6 +155,14 @@ class GFX_EXPORT Canvas { // Obsolete version. Use the above version which takes FontList. static int GetStringWidth(const base::string16& text, const Font& font); + // This is same as GetStringWidth except that fractional width is returned. + // Use this method for the scenario that multiple string widths need to be + // summed up. This is because GetStringWidth returns the ceiled width and + // adding multiple ceiled widths could cause more precision loss for certain + // platform like Mac where the fractioal width is used. + static float GetStringWidthF(const base::string16& text, + const FontList& font_list); + // Returns the default text alignment to be used when drawing text on a // Canvas based on the directionality of the system locale language. // This function is used by Canvas::DrawStringInt when the text alignment diff --git a/ui/gfx/canvas_android.cc b/ui/gfx/canvas_android.cc index 54e45f7..61e3a3a 100644 --- a/ui/gfx/canvas_android.cc +++ b/ui/gfx/canvas_android.cc @@ -9,12 +9,12 @@ namespace gfx { // static -void Canvas::SizeStringInt(const base::string16& text, - const FontList& font_list, - int* width, - int* height, - int line_height, - int flags) { +void Canvas::SizeStringFloat(const base::string16& text, + const FontList& font_list, + float* width, + float* height, + int line_height, + int flags) { NOTIMPLEMENTED(); } diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc index ad15edd..c259232 100644 --- a/ui/gfx/canvas_skia.cc +++ b/ui/gfx/canvas_skia.cc @@ -155,11 +155,11 @@ void UpdateRenderText(const Rect& rect, } // namespace // static -void Canvas::SizeStringInt(const base::string16& text, - const FontList& font_list, - int* width, int* height, - int line_height, - int flags) { +void Canvas::SizeStringFloat(const base::string16& text, + const FontList& font_list, + float* width, float* height, + int line_height, + int flags) { DCHECK_GE(*width, 0); DCHECK_GE(*height, 0); @@ -184,12 +184,12 @@ void Canvas::SizeStringInt(const base::string16& text, UpdateRenderText(rect, base::string16(), font_list, flags, 0, render_text.get()); - int h = 0; - int w = 0; + float h = 0; + float w = 0; for (size_t i = 0; i < strings.size(); ++i) { StripAcceleratorChars(flags, &strings[i]); render_text->SetText(strings[i]); - const Size& string_size = render_text->GetStringSize(); + const SizeF& string_size = render_text->GetStringSizeF(); w = std::max(w, string_size.width()); h += (i > 0 && line_height > 0) ? line_height : string_size.height(); } @@ -208,7 +208,7 @@ void Canvas::SizeStringInt(const base::string16& text, StripAcceleratorChars(flags, &adjusted_text); UpdateRenderText(rect, adjusted_text, font_list, flags, 0, render_text.get()); - const Size& string_size = render_text->GetStringSize(); + const SizeF& string_size = render_text->GetStringSizeF(); *width = string_size.width(); *height = string_size.height(); } diff --git a/ui/gfx/canvas_unittest_mac.mm b/ui/gfx/canvas_unittest_mac.mm index d607218..7aff64b 100644 --- a/ui/gfx/canvas_unittest_mac.mm +++ b/ui/gfx/canvas_unittest_mac.mm @@ -18,25 +18,16 @@ namespace gfx { namespace { -// Mac-specific code for string size computations. This is a verbatim copy -// of the old implementation that used to be in canvas_mac.mm. -void CanvasMac_SizeStringInt(const base::string16& text, - const FontList& font_list, - int* width, - int* height, - int line_height, - int flags) { - DLOG_IF(WARNING, line_height != 0) << "Line heights not implemented."; - DLOG_IF(WARNING, flags & Canvas::MULTI_LINE) << "Multi-line not implemented."; - +// Returns the pixel width of the string via calling the native method +// -sizeWithAttributes. +float GetStringNativeWidth(const base::string16& text, + const FontList& font_list) { NSFont* native_font = font_list.GetPrimaryFont().GetNativeFont(); NSString* ns_string = base::SysUTF16ToNSString(text); NSDictionary* attributes = [NSDictionary dictionaryWithObject:native_font forKey:NSFontAttributeName]; - NSSize string_size = [ns_string sizeWithAttributes:attributes]; - *width = std::ceil(string_size.width); - *height = font_list.GetHeight(); + return [ns_string sizeWithAttributes:attributes].width; } } // namespace @@ -49,30 +40,31 @@ class CanvasTestMac : public testing::Test { // without specified line height, since that is all the platform // implementation supports. void CompareSizes(const char* text) { - const int kReallyLargeNumber = 12345678; + const float kReallyLargeNumber = 12345678; FontList font_list(font_); base::string16 text16 = base::UTF8ToUTF16(text); - int mac_width = kReallyLargeNumber; - int mac_height = kReallyLargeNumber; - CanvasMac_SizeStringInt(text16, font_list, &mac_width, &mac_height, 0, 0); + float mac_width = GetStringNativeWidth(text16, font_list); + int mac_height = font_list.GetHeight(); - int canvas_width = kReallyLargeNumber; - int canvas_height = kReallyLargeNumber; - Canvas::SizeStringInt( + float canvas_width = kReallyLargeNumber; + float canvas_height = kReallyLargeNumber; + Canvas::SizeStringFloat( text16, font_list, &canvas_width, &canvas_height, 0, 0); EXPECT_NE(kReallyLargeNumber, mac_width) << "no width for " << text; EXPECT_NE(kReallyLargeNumber, mac_height) << "no height for " << text; EXPECT_EQ(mac_width, canvas_width) << " width for " << text; - EXPECT_EQ(mac_height, canvas_height) << " height for " << text; + // FontList::GetHeight returns a truncated height. + EXPECT_EQ(mac_height, + static_cast<int>(canvas_height)) << " height for " << text; } private: Font font_; }; - // Tests that Canvas' SizeStringInt yields result consistent with a native + // Tests that Canvas' SizeStringFloat yields result consistent with a native // implementation. TEST_F(CanvasTestMac, StringSizeIdenticalForSkia) { CompareSizes(""); @@ -81,4 +73,16 @@ class CanvasTestMac : public testing::Test { CompareSizes("This is a complete sentence."); } +TEST_F(CanvasTestMac, FractionalWidth) { + const float kReallyLargeNumber = 12345678; + float width = kReallyLargeNumber; + float height = kReallyLargeNumber; + + FontList font_list; + Canvas::SizeStringFloat( + base::UTF8ToUTF16("Test"), font_list, &width, &height, 0, 0); + + EXPECT_GT(width, static_cast<int>(width)); +} + } // namespace gfx diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index 6e7fbda..fc8bad1 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc @@ -644,6 +644,11 @@ VisualCursorDirection RenderText::GetVisualDirectionOfLogicalEnd() { CURSOR_RIGHT : CURSOR_LEFT; } +SizeF RenderText::GetStringSizeF() { + const Size size = GetStringSize(); + return SizeF(size.width(), size.height()); +} + int RenderText::GetContentWidth() { return GetStringSize().width() + (cursor_enabled_ ? 1 : 0); } diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h index df23ff3..ce0a027 100644 --- a/ui/gfx/render_text.h +++ b/ui/gfx/render_text.h @@ -25,6 +25,7 @@ #include "ui/gfx/rect.h" #include "ui/gfx/selection_model.h" #include "ui/gfx/shadow_value.h" +#include "ui/gfx/size_f.h" #include "ui/gfx/text_constants.h" #include "ui/gfx/vector2d.h" @@ -326,6 +327,13 @@ class GFX_EXPORT RenderText { // shadows. virtual Size GetStringSize() = 0; + // This is same as GetStringSize except that fractional size is returned. + // The default implementation is same as GetStringSize. Certain platforms that + // compute the text size as floating-point values, like Mac, will override + // this method. + // See comment in Canvas::GetStringWidthF for its usage. + virtual SizeF GetStringSizeF(); + // Returns the width of the content (which is the wrapped width in multiline // mode). Reserves room for the cursor if |cursor_enabled_| is true. int GetContentWidth(); diff --git a/ui/gfx/render_text_mac.cc b/ui/gfx/render_text_mac.cc index 2fcea01..d86975d 100644 --- a/ui/gfx/render_text_mac.cc +++ b/ui/gfx/render_text_mac.cc @@ -25,6 +25,11 @@ RenderTextMac::~RenderTextMac() { Size RenderTextMac::GetStringSize() { EnsureLayout(); + return Size(std::ceil(string_size_.width()), string_size_.height()); +} + +SizeF RenderTextMac::GetStringSizeF() { + EnsureLayout(); return string_size_; } @@ -149,7 +154,7 @@ void RenderTextMac::EnsureLayout() { CGFloat font_list_baseline = font_list().GetBaseline(); ascent = std::max(ascent, font_list_baseline); descent = std::max(descent, font_list_height - font_list_baseline); - string_size_ = Size(std::ceil(width), ascent + descent + leading); + string_size_ = SizeF(width, ascent + descent + leading); common_baseline_ = ascent; } diff --git a/ui/gfx/render_text_mac.h b/ui/gfx/render_text_mac.h index be5f128..3d25430 100644 --- a/ui/gfx/render_text_mac.h +++ b/ui/gfx/render_text_mac.h @@ -27,6 +27,7 @@ class RenderTextMac : public RenderText { // Overridden from RenderText: virtual Size GetStringSize() OVERRIDE; + virtual SizeF GetStringSizeF() OVERRIDE; virtual int GetBaseline() OVERRIDE; virtual SelectionModel FindCursorPosition(const Point& point) OVERRIDE; virtual std::vector<FontSpan> GetFontSpansForTesting() OVERRIDE; @@ -81,7 +82,7 @@ class RenderTextMac : public RenderText { base::ScopedCFTypeRef<CFMutableArrayRef> attributes_; // Visual dimensions of the text. Computed by |EnsureLayout()|. - Size string_size_; + SizeF string_size_; // Common baseline for this line of text. Computed by |EnsureLayout()|. SkScalar common_baseline_; diff --git a/ui/gfx/text_elider.cc b/ui/gfx/text_elider.cc index bc4eb3b..9fec05f 100644 --- a/ui/gfx/text_elider.cc +++ b/ui/gfx/text_elider.cc @@ -129,15 +129,15 @@ string16 ElideComponentizedPath(const string16& url_path_prefix, const std::vector<string16>& url_path_elements, const string16& url_filename, const string16& url_query, - const gfx::FontList& font_list, - int available_pixel_width) { + const FontList& font_list, + float available_pixel_width) { const size_t url_path_number_of_elements = url_path_elements.size(); CHECK(url_path_number_of_elements); for (size_t i = url_path_number_of_elements - 1; i > 0; --i) { string16 elided_path = BuildPathFromComponents(url_path_prefix, url_path_elements, url_filename, i); - if (available_pixel_width >= gfx::GetStringWidth(elided_path, font_list)) + if (available_pixel_width >= GetStringWidthF(elided_path, font_list)) return ElideText(elided_path + url_query, font_list, available_pixel_width, ELIDE_AT_END); } @@ -148,9 +148,9 @@ string16 ElideComponentizedPath(const string16& url_path_prefix, } // namespace string16 ElideEmail(const string16& email, - const gfx::FontList& font_list, - int available_pixel_width) { - if (gfx::GetStringWidth(email, font_list) <= available_pixel_width) + const FontList& font_list, + float available_pixel_width) { + if (GetStringWidthF(email, font_list) <= available_pixel_width) return email; // Split the email into its local-part (username) and domain-part. The email @@ -167,24 +167,24 @@ string16 ElideEmail(const string16& email, // Subtract the @ symbol from the available width as it is mandatory. const string16 kAtSignUTF16 = ASCIIToUTF16("@"); - available_pixel_width -= gfx::GetStringWidth(kAtSignUTF16, font_list); + available_pixel_width -= GetStringWidthF(kAtSignUTF16, font_list); // Check whether eliding the domain is necessary: if eliding the username // is sufficient, the domain will not be elided. - const int full_username_width = gfx::GetStringWidth(username, font_list); - const int available_domain_width = + const float full_username_width = GetStringWidthF(username, font_list); + const float available_domain_width = available_pixel_width - std::min(full_username_width, - gfx::GetStringWidth(username.substr(0, 1) + kEllipsisUTF16, - font_list)); - if (gfx::GetStringWidth(domain, font_list) > available_domain_width) { + GetStringWidthF(username.substr(0, 1) + kEllipsisUTF16, + font_list)); + if (GetStringWidthF(domain, font_list) > available_domain_width) { // Elide the domain so that it only takes half of the available width. // Should the username not need all the width available in its half, the // domain will occupy the leftover width. // If |desired_domain_width| is greater than |available_domain_width|: the // minimal username elision allowed by the specifications will not fit; thus // |desired_domain_width| must be <= |available_domain_width| at all cost. - const int desired_domain_width = + const float desired_domain_width = std::min(available_domain_width, std::max(available_pixel_width - full_username_width, available_pixel_width / 2)); @@ -199,7 +199,7 @@ string16 ElideEmail(const string16& email, // Fit the username in the remaining width (at this point the elided username // is guaranteed to fit with at least one character remaining given all the // precautions taken earlier). - available_pixel_width -= gfx::GetStringWidth(domain, font_list); + available_pixel_width -= GetStringWidthF(domain, font_list); username = ElideText(username, font_list, available_pixel_width, ELIDE_AT_END); @@ -207,9 +207,9 @@ string16 ElideEmail(const string16& email, } string16 ElideEmail(const string16& email, - const gfx::Font& font, - int available_pixel_width) { - return ElideEmail(email, gfx::FontList(font), available_pixel_width); + const Font& font, + float available_pixel_width) { + return ElideEmail(email, FontList(font), available_pixel_width); } // TODO(pkasting): http://crbug.com/77883 This whole function gets @@ -217,8 +217,8 @@ string16 ElideEmail(const string16& email, // a rendered string is always the sum of the widths of its substrings. Also I // suspect it could be made simpler. string16 ElideUrl(const GURL& url, - const gfx::FontList& font_list, - int available_pixel_width, + const FontList& font_list, + float available_pixel_width, const std::string& languages) { // Get a formatted string and corresponding parsing of the url. url_parse::Parsed parsed; @@ -235,7 +235,7 @@ string16 ElideUrl(const GURL& url, // Now start eliding url_string to fit within available pixel width. // Fist pass - check to see whether entire url_string fits. - const int pixel_width_url_string = gfx::GetStringWidth(url_string, font_list); + const float pixel_width_url_string = GetStringWidthF(url_string, font_list); if (available_pixel_width >= pixel_width_url_string) return url_string; @@ -248,7 +248,7 @@ string16 ElideUrl(const GURL& url, // Return general elided text if url minus the query fits. const string16 url_minus_query = url_string.substr(0, path_start_index + path_len); - if (available_pixel_width >= gfx::GetStringWidth(url_minus_query, font_list)) + if (available_pixel_width >= GetStringWidthF(url_minus_query, font_list)) return ElideText(url_string, font_list, available_pixel_width, ELIDE_AT_END); @@ -298,17 +298,17 @@ string16 ElideUrl(const GURL& url, } // Second Pass - remove scheme - the rest fits. - const int pixel_width_url_host = gfx::GetStringWidth(url_host, font_list); - const int pixel_width_url_path = gfx::GetStringWidth(url_path_query_etc, - font_list); + const float pixel_width_url_host = GetStringWidthF(url_host, font_list); + const float pixel_width_url_path = GetStringWidthF(url_path_query_etc, + font_list); if (available_pixel_width >= pixel_width_url_host + pixel_width_url_path) return url_host + url_path_query_etc; // Third Pass: Subdomain, domain and entire path fits. - const int pixel_width_url_domain = gfx::GetStringWidth(url_domain, font_list); - const int pixel_width_url_subdomain = gfx::GetStringWidth(url_subdomain, - font_list); + const float pixel_width_url_domain = GetStringWidthF(url_domain, font_list); + const float pixel_width_url_subdomain = + GetStringWidthF(url_subdomain, font_list); if (available_pixel_width >= pixel_width_url_subdomain + pixel_width_url_domain + pixel_width_url_path) @@ -316,13 +316,13 @@ string16 ElideUrl(const GURL& url, // Query element. string16 url_query; - const int kPixelWidthDotsTrailer = gfx::GetStringWidth( + const float kPixelWidthDotsTrailer = GetStringWidthF( string16(kEllipsisUTF16), font_list); if (parsed.query.is_nonempty()) { url_query = UTF8ToUTF16("?") + url_string.substr(parsed.query.begin); if (available_pixel_width >= (pixel_width_url_subdomain + pixel_width_url_domain + - pixel_width_url_path - gfx::GetStringWidth(url_query, font_list))) { + pixel_width_url_path - GetStringWidthF(url_query, font_list))) { return ElideText(url_subdomain + url_domain + url_path_query_etc, font_list, available_pixel_width, ELIDE_AT_END); } @@ -357,8 +357,8 @@ string16 ElideUrl(const GURL& url, // Start eliding the path and replacing elements by ".../". const string16 kEllipsisAndSlash = string16(kEllipsisUTF16) + kForwardSlash; - const int pixel_width_ellipsis_slash = gfx::GetStringWidth(kEllipsisAndSlash, - font_list); + const float pixel_width_ellipsis_slash = + GetStringWidthF(kEllipsisAndSlash, font_list); // Check with both subdomain and domain. string16 elided_path = @@ -390,13 +390,13 @@ string16 ElideUrl(const GURL& url, // Return elided domain/.../filename anyway. string16 final_elided_url_string(url_elided_domain); - const int url_elided_domain_width = gfx::GetStringWidth(url_elided_domain, - font_list); + const float url_elided_domain_width = GetStringWidthF(url_elided_domain, + font_list); // A hack to prevent trailing ".../...". if ((available_pixel_width - url_elided_domain_width) > pixel_width_ellipsis_slash + kPixelWidthDotsTrailer + - gfx::GetStringWidth(ASCIIToUTF16("UV"), font_list)) { + GetStringWidthF(ASCIIToUTF16("UV"), font_list)) { final_elided_url_string += BuildPathFromComponents(string16(), url_path_elements, url_filename, 1); } else { @@ -408,15 +408,15 @@ string16 ElideUrl(const GURL& url, } string16 ElideUrl(const GURL& url, - const gfx::Font& font, - int available_pixel_width, + const Font& font, + float available_pixel_width, const std::string& languages) { - return ElideUrl(url, gfx::FontList(font), available_pixel_width, languages); + return ElideUrl(url, FontList(font), available_pixel_width, languages); } string16 ElideFilename(const base::FilePath& filename, - const gfx::FontList& font_list, - int available_pixel_width) { + const FontList& font_list, + float available_pixel_width) { #if defined(OS_WIN) string16 filename_utf16 = filename.value(); string16 extension = filename.Extension(); @@ -430,7 +430,7 @@ string16 ElideFilename(const base::FilePath& filename, filename.BaseName().RemoveExtension().value())); #endif - const int full_width = gfx::GetStringWidth(filename_utf16, font_list); + const float full_width = GetStringWidthF(filename_utf16, font_list); if (full_width <= available_pixel_width) return base::i18n::GetDisplayStringInLTRDirectionality(filename_utf16); @@ -440,8 +440,8 @@ string16 ElideFilename(const base::FilePath& filename, return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); } - const int ext_width = gfx::GetStringWidth(extension, font_list); - const int root_width = gfx::GetStringWidth(rootname, font_list); + const float ext_width = GetStringWidthF(extension, font_list); + const float root_width = GetStringWidthF(rootname, font_list); // We may have trimmed the path. if (root_width + ext_width <= available_pixel_width) { @@ -456,7 +456,7 @@ string16 ElideFilename(const base::FilePath& filename, return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); } - int available_root_width = available_pixel_width - ext_width; + float available_root_width = available_pixel_width - ext_width; string16 elided_name = ElideText(rootname, font_list, available_root_width, ELIDE_AT_END); elided_name += extension; @@ -464,19 +464,19 @@ string16 ElideFilename(const base::FilePath& filename, } string16 ElideFilename(const base::FilePath& filename, - const gfx::Font& font, - int available_pixel_width) { - return ElideFilename(filename, gfx::FontList(font), available_pixel_width); + const Font& font, + float available_pixel_width) { + return ElideFilename(filename, FontList(font), available_pixel_width); } string16 ElideText(const string16& text, - const gfx::FontList& font_list, - int available_pixel_width, + const FontList& font_list, + float available_pixel_width, ElideBehavior elide_behavior) { if (text.empty()) return text; - const int current_text_pixel_width = gfx::GetStringWidth(text, font_list); + const float current_text_pixel_width = GetStringWidthF(text, font_list); const bool elide_in_middle = (elide_behavior == ELIDE_IN_MIDDLE); const bool insert_ellipsis = (elide_behavior != TRUNCATE_AT_END); @@ -500,7 +500,7 @@ string16 ElideText(const string16& text, return text; if (insert_ellipsis && - gfx::GetStringWidth(ellipsis, font_list) > available_pixel_width) + GetStringWidthF(ellipsis, font_list) > available_pixel_width) return string16(); // Use binary search to compute the elided text. @@ -511,7 +511,7 @@ string16 ElideText(const string16& text, // We check the length of the whole desired string at once to ensure we // handle kerning/ligatures/etc. correctly. const string16 cut = slicer.CutString(guess, insert_ellipsis); - const int guess_length = gfx::GetStringWidth(cut, font_list); + const float guess_length = GetStringWidthF(cut, font_list); // 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) { @@ -528,11 +528,10 @@ string16 ElideText(const string16& text, } string16 ElideText(const string16& text, - const gfx::Font& font, - int available_pixel_width, + const Font& font, + float available_pixel_width, ElideBehavior elide_behavior) { - return ElideText(text, gfx::FontList(font), available_pixel_width, - elide_behavior); + return ElideText(text, FontList(font), available_pixel_width, elide_behavior); } SortedDisplayURL::SortedDisplayURL(const GURL& url, @@ -809,8 +808,8 @@ void RectangleString::NewLine(bool output) { // can be broken into smaller methods sharing this state. class RectangleText { public: - RectangleText(const gfx::FontList& font_list, - int available_pixel_width, + RectangleText(const FontList& font_list, + float available_pixel_width, int available_pixel_height, WordWrapBehavior wrap_behavior, std::vector<string16>* lines) @@ -859,7 +858,7 @@ class RectangleText { // Append the specified |text| to the current output line, incrementing the // running width by the specified amount. This is an optimization over // |AddToCurrentLine()| when |text_width| is already known. - void AddToCurrentLineWithWidth(const string16& text, int text_width); + void AddToCurrentLineWithWidth(const string16& text, float text_width); // Append the specified |text| to the current output line. void AddToCurrentLine(const string16& text); @@ -868,13 +867,13 @@ class RectangleText { bool NewLine(); // The font list used for measuring text width. - const gfx::FontList& font_list_; + const FontList& font_list_; // The height of each line of text. const int line_height_; // The number of pixels of available width in the rectangle. - const int available_pixel_width_; + const float available_pixel_width_; // The number of pixels of available height in the rectangle. const int available_pixel_height_; @@ -883,7 +882,7 @@ class RectangleText { const WordWrapBehavior wrap_behavior_; // The current running width. - int current_width_; + float current_width_; // The current running height. int current_height_; @@ -941,7 +940,7 @@ int RectangleText::Finalize() { } void RectangleText::AddLine(const string16& line) { - const int line_width = gfx::GetStringWidth(line, font_list_); + const float line_width = GetStringWidthF(line, font_list_); if (line_width <= available_pixel_width_) { AddToCurrentLineWithWidth(line, line_width); } else { @@ -1028,7 +1027,7 @@ int RectangleText::AddWord(const string16& word) { int lines_added = 0; string16 trimmed; TrimWhitespace(word, TRIM_TRAILING, &trimmed); - const int trimmed_width = gfx::GetStringWidth(trimmed, font_list_); + const float trimmed_width = GetStringWidthF(trimmed, font_list_); if (trimmed_width <= available_pixel_width_) { // Word can be made to fit, no need to fragment it. if ((current_width_ + trimmed_width > available_pixel_width_) && NewLine()) @@ -1043,11 +1042,11 @@ int RectangleText::AddWord(const string16& word) { } void RectangleText::AddToCurrentLine(const string16& text) { - AddToCurrentLineWithWidth(text, gfx::GetStringWidth(text, font_list_)); + AddToCurrentLineWithWidth(text, GetStringWidthF(text, font_list_)); } void RectangleText::AddToCurrentLineWithWidth(const string16& text, - int text_width) { + float text_width) { if (current_height_ >= available_pixel_height_) { insufficient_height_ = true; return; @@ -1081,8 +1080,8 @@ bool ElideRectangleString(const string16& input, size_t max_rows, } int ElideRectangleText(const string16& input, - const gfx::FontList& font_list, - int available_pixel_width, + const FontList& font_list, + float available_pixel_width, int available_pixel_height, WordWrapBehavior wrap_behavior, std::vector<string16>* lines) { @@ -1097,12 +1096,12 @@ int ElideRectangleText(const string16& input, } int ElideRectangleText(const string16& input, - const gfx::Font& font, - int available_pixel_width, + const Font& font, + float available_pixel_width, int available_pixel_height, WordWrapBehavior wrap_behavior, std::vector<string16>* lines) { - return ElideRectangleText(input, gfx::FontList(font), + return ElideRectangleText(input, FontList(font), available_pixel_width, available_pixel_height, wrap_behavior, lines); } diff --git a/ui/gfx/text_elider.h b/ui/gfx/text_elider.h index ff0cef0..8ea1921 100644 --- a/ui/gfx/text_elider.h +++ b/ui/gfx/text_elider.h @@ -41,11 +41,11 @@ GFX_EXPORT extern const char16 kEllipsisUTF16[]; // extra width). GFX_EXPORT string16 ElideEmail(const string16& email, const gfx::FontList& font_list, - int available_pixel_width); + float available_pixel_width); // Obsolete version. Use the above version which takes gfx::FontList. GFX_EXPORT string16 ElideEmail(const string16& email, const gfx::Font& font, - int available_pixel_width); + float available_pixel_width); // This function takes a GURL object and elides it. It returns a string // which composed of parts from subdomain, domain, path, filename and query. @@ -63,12 +63,12 @@ GFX_EXPORT string16 ElideEmail(const string16& email, // http://crbug.com/6487 for more information. GFX_EXPORT string16 ElideUrl(const GURL& url, const gfx::FontList& font_list, - int available_pixel_width, + float available_pixel_width, const std::string& languages); // Obsolete version. Use the above version which takes gfx::FontList. GFX_EXPORT string16 ElideUrl(const GURL& url, const gfx::Font& font, - int available_pixel_width, + float available_pixel_width, const std::string& languages); enum ElideBehavior { @@ -84,12 +84,12 @@ enum ElideBehavior { // |elide_behavior|. GFX_EXPORT string16 ElideText(const string16& text, const gfx::FontList& font_list, - int available_pixel_width, + float available_pixel_width, ElideBehavior elide_behavior); // Obsolete version. Use the above version which takes gfx::FontList. GFX_EXPORT string16 ElideText(const string16& text, const gfx::Font& font, - int available_pixel_width, + float available_pixel_width, ElideBehavior elide_behavior); // Elide a filename to fit a given pixel width, with an emphasis on not hiding @@ -100,11 +100,11 @@ GFX_EXPORT string16 ElideText(const string16& text, // PDF (Pop Directional Formatting) mark. GFX_EXPORT string16 ElideFilename(const base::FilePath& filename, const gfx::FontList& font_list, - int available_pixel_width); + float available_pixel_width); // Obsolete version. Use the above version which takes gfx::FontList. GFX_EXPORT string16 ElideFilename(const base::FilePath& filename, const gfx::Font& font, - int available_pixel_width); + float available_pixel_width); // SortedDisplayURL maintains a string from a URL suitable for display to the // use. SortedDisplayURL also provides a function used for comparing two @@ -208,14 +208,14 @@ enum ReformattingResultFlags { // leading to elision or truncation (and not just reformatting). GFX_EXPORT int ElideRectangleText(const string16& text, const gfx::FontList& font_list, - int available_pixel_width, + float available_pixel_width, int available_pixel_height, WordWrapBehavior wrap_behavior, std::vector<string16>* lines); // Obsolete version. Use the above version which takes gfx::FontList. GFX_EXPORT int ElideRectangleText(const string16& text, const gfx::Font& font, - int available_pixel_width, + float available_pixel_width, int available_pixel_height, WordWrapBehavior wrap_behavior, std::vector<string16>* lines); diff --git a/ui/gfx/text_elider_unittest.cc b/ui/gfx/text_elider_unittest.cc index 2a90e5d..6b1a4e3 100644 --- a/ui/gfx/text_elider_unittest.cc +++ b/ui/gfx/text_elider_unittest.cc @@ -13,6 +13,8 @@ #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/font.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/text_utils.h" #include "url/gurl.h" namespace gfx { @@ -41,36 +43,22 @@ struct TestData { }; void RunUrlTest(Testcase* testcases, size_t num_testcases) { - static const gfx::Font font; + static const FontList font_list; for (size_t i = 0; i < num_testcases; ++i) { const GURL url(testcases[i].input); // Should we test with non-empty language list? // That's kinda redundant with net_util_unittests. + const float available_width = + GetStringWidthF(UTF8ToUTF16(testcases[i].output), font_list); EXPECT_EQ(UTF8ToUTF16(testcases[i].output), - ElideUrl(url, font, - font.GetStringWidth(UTF8ToUTF16(testcases[i].output)), - std::string())); + ElideUrl(url, font_list, available_width, std::string())); } } -gfx::Font GetTestingFont() { - gfx::Font font; -#if defined(OS_MACOSX) - // Use a specific font for certain tests on Mac. - // 1) Different Mac machines might be configured with different default font. - // The number of extra pixels needed to make ElideEmail/TestFilenameEliding - // tests work might vary per the default font. - // 2) This specific font helps expose the line width exceeding problem as in - // ElideRectangleTextCheckLineWidth. - font = gfx::Font("LucidaGrande", 12); -#endif - return font; -} - } // namespace -// TODO(ios): Complex eliding is off by one for some of those tests on iOS. -// See crbug.com/154019 +// TODO(ios): This test fails on iOS because iOS version of GetStringWidthF +// that calls [NSString sizeWithFont] returns the rounded string width. #if defined(OS_IOS) #define MAYBE_ElideEmail DISABLED_ElideEmail #else @@ -121,22 +109,14 @@ TEST(TextEliderTest, MAYBE_ElideEmail) { {"mmmmm@llllllllll", "m" + kEllipsisStr + "@l" + kEllipsisStr}, }; - const gfx::Font font = GetTestingFont(); + const FontList font_list; for (size_t i = 0; i < arraysize(testcases); ++i) { const string16 expected_output = UTF8ToUTF16(testcases[i].output); - int available_width = font.GetStringWidth(expected_output); -#if defined(OS_MACOSX) - // Give two extra pixels to offset the ceiling width returned by - // GetStringWidth on Mac. This workaround will no longer be needed once - // the floating point width is adopted (http://crbug.com/288987). - // Note that we need one more pixel than TestFilenameEliding because - // multiple strings are elided and we need to offset more. - available_width += 2; -#endif EXPECT_EQ(expected_output, - ElideEmail(UTF8ToUTF16(testcases[i].input), - font, - available_width)); + ElideEmail( + UTF8ToUTF16(testcases[i].input), + font_list, + GetStringWidthF(expected_output, font_list))); } } @@ -153,7 +133,7 @@ TEST(TextEliderTest, ElideEmailMoreSpace) { "supermegalongusername@withasuperlonnnggggdomain.gouv.qc.ca", }; - const gfx::Font font; + const Font font; for (size_t i = 0; i < arraysize(test_width_factors); ++i) { const int test_width = test_width_factors[i] * font.GetAverageCharacterWidth(); @@ -199,23 +179,26 @@ TEST(TextEliderTest, TestTrailingEllipsisSlashEllipsisHack) { const std::string kEllipsisStr(kEllipsis); // Very little space, would cause double ellipsis. - gfx::Font font; + FontList font_list; GURL url("http://battersbox.com/directory/foo/peter_paul_and_mary.html"); - int available_width = font.GetStringWidth( - UTF8ToUTF16("battersbox.com/" + kEllipsisStr + "/" + kEllipsisStr)); + float available_width = GetStringWidthF( + UTF8ToUTF16("battersbox.com/" + kEllipsisStr + "/" + kEllipsisStr), + font_list); // Create the expected string, after elision. Depending on font size, the // directory might become /dir... or /di... or/d... - it never should be // shorter than that. (If it is, the font considers d... to be longer // than .../... - that should never happen). - ASSERT_GT(font.GetStringWidth(UTF8ToUTF16(kEllipsisStr + "/" + kEllipsisStr)), - font.GetStringWidth(UTF8ToUTF16("d" + kEllipsisStr))); + ASSERT_GT(GetStringWidthF(UTF8ToUTF16(kEllipsisStr + "/" + kEllipsisStr), + font_list), + GetStringWidthF(UTF8ToUTF16("d" + kEllipsisStr), font_list)); GURL long_url("http://battersbox.com/directorynameisreallylongtoforcetrunc"); - string16 expected = ElideUrl(long_url, font, available_width, std::string()); + string16 expected = + ElideUrl(long_url, font_list, available_width, std::string()); // Ensure that the expected result still contains part of the directory name. ASSERT_GT(expected.length(), std::string("battersbox.com/d").length()); EXPECT_EQ(expected, - ElideUrl(url, font, available_width, std::string())); + ElideUrl(url, font_list, available_width, std::string())); // More space available - elide directories, partially elide filename. Testcase testcases[] = { @@ -288,8 +271,8 @@ TEST(TextEliderTest, TestFileURLEliding) { RunUrlTest(testcases, arraysize(testcases)); } -// TODO(ios): Complex eliding is off by one for some of those tests on iOS. -// See crbug.com/154019 +// TODO(ios): This test fails on iOS because iOS version of GetStringWidthF +// that calls [NSString sizeWithFont] returns the rounded string width. #if defined(OS_IOS) #define MAYBE_TestFilenameEliding DISABLED_TestFilenameEliding #else @@ -334,28 +317,22 @@ TEST(TextEliderTest, MAYBE_TestFilenameEliding) { "file.name.re" + kEllipsisStr + "emelylongext"} }; - static const gfx::Font font = GetTestingFont(); + static const FontList font_list; for (size_t i = 0; i < arraysize(testcases); ++i) { base::FilePath filepath(testcases[i].input); string16 expected = UTF8ToUTF16(testcases[i].output); expected = base::i18n::GetDisplayStringInLTRDirectionality(expected); - int available_width = font.GetStringWidth(UTF8ToUTF16(testcases[i].output)); -#if defined(OS_MACOSX) - // Give one extra pixel to offset the ceiling width returned by - // GetStringWidth on Mac. This workaround will no longer be needed once - // the floating point width is adopted (http://crbug.com/288987). - available_width += 1; -#endif - EXPECT_EQ(expected, ElideFilename(filepath, font, available_width)); + EXPECT_EQ(expected, ElideFilename(filepath, font_list, + GetStringWidthF(UTF8ToUTF16(testcases[i].output), font_list))); } } TEST(TextEliderTest, ElideTextTruncate) { - const gfx::Font font; - const int kTestWidth = font.GetStringWidth(ASCIIToUTF16("Test")); + const FontList font_list; + const float kTestWidth = GetStringWidthF(ASCIIToUTF16("Test"), font_list); struct TestData { const char* input; - int width; + float width; const char* output; } cases[] = { { "", 0, "" }, @@ -367,20 +344,21 @@ TEST(TextEliderTest, ElideTextTruncate) { }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - string16 result = ElideText(UTF8ToUTF16(cases[i].input), font, + string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list, cases[i].width, TRUNCATE_AT_END); EXPECT_EQ(cases[i].output, UTF16ToUTF8(result)); } } TEST(TextEliderTest, ElideTextEllipsis) { - const gfx::Font font; - const int kTestWidth = font.GetStringWidth(ASCIIToUTF16("Test")); + const FontList font_list; + const float kTestWidth = GetStringWidthF(ASCIIToUTF16("Test"), font_list); const char* kEllipsis = "\xE2\x80\xA6"; - const int kEllipsisWidth = font.GetStringWidth(UTF8ToUTF16(kEllipsis)); + const float kEllipsisWidth = + GetStringWidthF(UTF8ToUTF16(kEllipsis), font_list); struct TestData { const char* input; - int width; + float width; const char* output; } cases[] = { { "", 0, "" }, @@ -392,7 +370,7 @@ TEST(TextEliderTest, ElideTextEllipsis) { }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - string16 result = ElideText(UTF8ToUTF16(cases[i].input), font, + string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list, cases[i].width, ELIDE_AT_END); EXPECT_EQ(cases[i].output, UTF16ToUTF8(result)); } @@ -418,27 +396,27 @@ static void CheckSurrogatePairs(const string16& text, } TEST(TextEliderTest, ElideTextSurrogatePairs) { - const gfx::Font font; + const FontList font_list; // The below is 'MUSICAL SYMBOL G CLEF', which is represented in UTF-16 as // two characters forming a surrogate pair 0x0001D11E. const std::string kSurrogate = "\xF0\x9D\x84\x9E"; const string16 kTestString = UTF8ToUTF16(kSurrogate + "ab" + kSurrogate + kSurrogate + "cd"); - const int kTestStringWidth = font.GetStringWidth(kTestString); + const float kTestStringWidth = GetStringWidthF(kTestString, font_list); const char16 kSurrogateFirstChar = kTestString[0]; const char16 kSurrogateSecondChar = kTestString[1]; string16 result; // Elide |kTextString| to all possible widths and check that no instance of // |kSurrogate| was split in two. - for (int width = 0; width <= kTestStringWidth; width++) { - result = ElideText(kTestString, font, width, TRUNCATE_AT_END); + for (float width = 0; width <= kTestStringWidth; width++) { + result = ElideText(kTestString, font_list, width, TRUNCATE_AT_END); CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar); - result = ElideText(kTestString, font, width, ELIDE_AT_END); + result = ElideText(kTestString, font_list, width, ELIDE_AT_END); CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar); - result = ElideText(kTestString, font, width, ELIDE_IN_MIDDLE); + result = ElideText(kTestString, font_list, width, ELIDE_IN_MIDDLE); CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar); } } @@ -467,17 +445,19 @@ TEST(TextEliderTest, ElideTextLongStrings) { {data_scheme + million_a, long_string_end}, }; - const gfx::Font font; - int ellipsis_width = font.GetStringWidth(kEllipsisStr); + const FontList font_list; + float ellipsis_width = GetStringWidthF(kEllipsisStr, font_list); for (size_t i = 0; i < arraysize(testcases_end); ++i) { // Compare sizes rather than actual contents because if the test fails, // output is rather long. EXPECT_EQ(testcases_end[i].output.size(), - ElideText(testcases_end[i].input, font, - font.GetStringWidth(testcases_end[i].output), - ELIDE_AT_END).size()); + ElideText( + testcases_end[i].input, + font_list, + GetStringWidthF(testcases_end[i].output, font_list), + ELIDE_AT_END).size()); EXPECT_EQ(kEllipsisStr, - ElideText(testcases_end[i].input, font, ellipsis_width, + ElideText(testcases_end[i].input, font_list, ellipsis_width, ELIDE_AT_END)); } @@ -498,11 +478,13 @@ TEST(TextEliderTest, ElideTextLongStrings) { // Compare sizes rather than actual contents because if the test fails, // output is rather long. EXPECT_EQ(testcases_middle[i].output.size(), - ElideText(testcases_middle[i].input, font, - font.GetStringWidth(testcases_middle[i].output), - ELIDE_AT_END).size()); + ElideText( + testcases_middle[i].input, + font_list, + GetStringWidthF(testcases_middle[i].output, font_list), + ELIDE_AT_END).size()); EXPECT_EQ(kEllipsisStr, - ElideText(testcases_middle[i].input, font, ellipsis_width, + ElideText(testcases_middle[i].input, font_list, ellipsis_width, ELIDE_AT_END)); } } @@ -580,13 +562,13 @@ TEST(TextEliderTest, ElideString) { } TEST(TextEliderTest, ElideRectangleText) { - const gfx::Font font; - const int line_height = font.GetHeight(); - const int test_width = font.GetStringWidth(ASCIIToUTF16("Test")); + const FontList font_list; + const int line_height = font_list.GetHeight(); + const float test_width = GetStringWidthF(ASCIIToUTF16("Test"), font_list); struct TestData { const char* input; - int available_pixel_width; + float available_pixel_width; int available_pixel_height; bool truncated_y; const char* output; @@ -622,7 +604,7 @@ TEST(TextEliderTest, ElideRectangleText) { std::vector<string16> lines; EXPECT_EQ(cases[i].truncated_y ? INSUFFICIENT_SPACE_VERTICAL : 0, ElideRectangleText(UTF8ToUTF16(cases[i].input), - font, + font_list, cases[i].available_pixel_width, cases[i].available_pixel_height, TRUNCATE_LONG_WORDS, @@ -637,14 +619,14 @@ TEST(TextEliderTest, ElideRectangleText) { } TEST(TextEliderTest, ElideRectangleTextPunctuation) { - const gfx::Font font; - const int line_height = font.GetHeight(); - const int test_width = font.GetStringWidth(ASCIIToUTF16("Test")); - const int test_t_width = font.GetStringWidth(ASCIIToUTF16("Test T")); + const FontList font_list; + const int line_height = font_list.GetHeight(); + const float test_width = GetStringWidthF(ASCIIToUTF16("Test"), font_list); + const float test_t_width = GetStringWidthF(ASCIIToUTF16("Test T"), font_list); struct TestData { const char* input; - int available_pixel_width; + float available_pixel_width; int available_pixel_height; bool wrap_words; bool truncated_x; @@ -662,7 +644,7 @@ TEST(TextEliderTest, ElideRectangleTextPunctuation) { (cases[i].wrap_words ? WRAP_LONG_WORDS : TRUNCATE_LONG_WORDS); EXPECT_EQ(cases[i].truncated_x ? INSUFFICIENT_SPACE_HORIZONTAL : 0, ElideRectangleText(UTF8ToUTF16(cases[i].input), - font, + font_list, cases[i].available_pixel_width, cases[i].available_pixel_height, wrap_behavior, @@ -677,15 +659,15 @@ TEST(TextEliderTest, ElideRectangleTextPunctuation) { } TEST(TextEliderTest, ElideRectangleTextLongWords) { - const gfx::Font font; + const FontList font_list; const int kAvailableHeight = 1000; const string16 kElidedTesting = UTF8ToUTF16(std::string("Tes") + kEllipsis); - const int elided_width = font.GetStringWidth(kElidedTesting); - const int test_width = font.GetStringWidth(ASCIIToUTF16("Test")); + const float elided_width = GetStringWidthF(kElidedTesting, font_list); + const float test_width = GetStringWidthF(ASCIIToUTF16("Test"), font_list); struct TestData { const char* input; - int available_pixel_width; + float available_pixel_width; WordWrapBehavior wrap_behavior; bool truncated_x; const char* output; @@ -723,7 +705,7 @@ TEST(TextEliderTest, ElideRectangleTextLongWords) { std::vector<string16> lines; EXPECT_EQ(cases[i].truncated_x ? INSUFFICIENT_SPACE_HORIZONTAL : 0, ElideRectangleText(UTF8ToUTF16(cases[i].input), - font, + font_list, cases[i].available_pixel_width, kAvailableHeight, cases[i].wrap_behavior, @@ -735,35 +717,30 @@ TEST(TextEliderTest, ElideRectangleTextLongWords) { } } -// TODO(ios): Complex eliding is off by one for some of those tests on iOS. -// See crbug.com/154019 -#if defined(OS_IOS) -#define MAYBE_ElideRectangleTextCheckLineWidth \ - DISABLED_ElideRectangleTextCheckLineWidth -#else -#define MAYBE_ElideRectangleTextCheckLineWidth ElideRectangleTextCheckLineWidth -#endif - // This test is to make sure that the width of each wrapped line does not // exceed the available width. On some platform like Mac, this test used to // fail because the truncated integer width is returned for the string // and the accumulation of the truncated values causes the elide function // to wrap incorrectly. -TEST(TextEliderTest, MAYBE_ElideRectangleTextCheckLineWidth) { - gfx::Font font = GetTestingFont(); - const int kAvailableWidth = 235; +TEST(TextEliderTest, ElideRectangleTextCheckLineWidth) { + FontList font_list; +#if defined(OS_MACOSX) && !defined(OS_IOS) + // Use a specific font to expose the line width exceeding problem. + font_list = FontList(Font("LucidaGrande", 12)); +#endif + const float kAvailableWidth = 235; const int kAvailableHeight = 1000; const char text[] = "that Russian place we used to go to after fencing"; std::vector<string16> lines; EXPECT_EQ(0, ElideRectangleText(UTF8ToUTF16(text), - font, + font_list, kAvailableWidth, kAvailableHeight, WRAP_LONG_WORDS, &lines)); ASSERT_EQ(2u, lines.size()); - EXPECT_LE(font.GetStringWidth(lines[0]), kAvailableWidth); - EXPECT_LE(font.GetStringWidth(lines[1]), kAvailableWidth); + EXPECT_LE(GetStringWidthF(lines[0], font_list), kAvailableWidth); + EXPECT_LE(GetStringWidthF(lines[1], font_list), kAvailableWidth); } TEST(TextEliderTest, ElideRectangleString) { diff --git a/ui/gfx/text_utils.h b/ui/gfx/text_utils.h index fa5caef..088f97c 100644 --- a/ui/gfx/text_utils.h +++ b/ui/gfx/text_utils.h @@ -27,6 +27,10 @@ GFX_EXPORT base::string16 RemoveAcceleratorChar(const base::string16& s, GFX_EXPORT int GetStringWidth(const base::string16& text, const FontList& font_list); +// This is same as GetStringWidth except that fractional width is returned. +GFX_EXPORT float GetStringWidthF(const base::string16& text, + const FontList& font_list); + } // namespace gfx #endif // UI_GFX_TEXT_UTILS_H_ diff --git a/ui/gfx/text_utils_android.cc b/ui/gfx/text_utils_android.cc index c564b9b..93938d5 100644 --- a/ui/gfx/text_utils_android.cc +++ b/ui/gfx/text_utils_android.cc @@ -13,4 +13,9 @@ int GetStringWidth(const base::string16& text, const FontList& font_list) { return 0; } +float GetStringWidthF(const base::string16& text, const FontList& font_list) { + NOTIMPLEMENTED(); + return 0; +} + } // namespace gfx diff --git a/ui/gfx/text_utils_ios.mm b/ui/gfx/text_utils_ios.mm index 1841864..56c01df7 100644 --- a/ui/gfx/text_utils_ios.mm +++ b/ui/gfx/text_utils_ios.mm @@ -14,9 +14,13 @@ namespace gfx { int GetStringWidth(const base::string16& text, const FontList& font_list) { + return std::ceil(GetStringWidthF(text, font_list)); +} + +float GetStringWidthF(const base::string16& text, const FontList& font_list) { NSString* ns_text = base::SysUTF16ToNSString(text); NativeFont native_font = font_list.GetPrimaryFont().GetNativeFont(); - return std::ceil([ns_text sizeWithFont:native_font].width); + return [ns_text sizeWithFont:native_font].width; } } // namespace gfx diff --git a/ui/gfx/text_utils_skia.cc b/ui/gfx/text_utils_skia.cc index 0de1156..4ef0c23 100644 --- a/ui/gfx/text_utils_skia.cc +++ b/ui/gfx/text_utils_skia.cc @@ -12,4 +12,8 @@ int GetStringWidth(const base::string16& text, const FontList& font_list) { return Canvas::GetStringWidth(text, font_list); } +float GetStringWidthF(const base::string16& text, const FontList& font_list) { + return Canvas::GetStringWidthF(text, font_list); +} + } // namespace gfx |