diff options
-rw-r--r-- | ui/gfx/render_text_linux.cc | 4 | ||||
-rw-r--r-- | ui/gfx/render_text_mac.cc | 10 | ||||
-rw-r--r-- | ui/gfx/render_text_unittest.cc | 70 | ||||
-rw-r--r-- | ui/gfx/render_text_win.cc | 7 |
4 files changed, 87 insertions, 4 deletions
diff --git a/ui/gfx/render_text_linux.cc b/ui/gfx/render_text_linux.cc index 8700d5d..0bf2686 100644 --- a/ui/gfx/render_text_linux.cc +++ b/ui/gfx/render_text_linux.cc @@ -85,6 +85,9 @@ Size RenderTextLinux::GetStringSize() { pango_layout_get_pixel_size(layout_, &width, &height); // Keep a consistent height between this particular string's PangoLayout and // potentially larger text supported by the FontList. + // For example, if a text field contains a Japanese character, which is + // smaller than Latin ones, and then later a Latin one is inserted, this + // ensures that the text baseline does not shift. return Size(width, std::max(height, font_list().GetHeight())); } @@ -92,6 +95,7 @@ int RenderTextLinux::GetBaseline() { EnsureLayout(); // Keep a consistent baseline between this particular string's PangoLayout and // potentially larger text supported by the FontList. + // See the example in GetStringSize(). return std::max(PANGO_PIXELS(pango_layout_get_baseline(layout_)), font_list().GetBaseline()); } diff --git a/ui/gfx/render_text_mac.cc b/ui/gfx/render_text_mac.cc index f6a1b78..cfc7a51 100644 --- a/ui/gfx/render_text_mac.cc +++ b/ui/gfx/render_text_mac.cc @@ -6,6 +6,7 @@ #include <ApplicationServices/ApplicationServices.h> +#include <algorithm> #include <cmath> #include <utility> @@ -140,6 +141,15 @@ void RenderTextMac::EnsureLayout() { CGFloat leading = 0; // TODO(asvitkine): Consider using CTLineGetBoundsWithOptions() on 10.8+. double width = CTLineGetTypographicBounds(line_, &ascent, &descent, &leading); + // Ensure ascent and descent are not smaller than ones of the font list. + // Keep them tall enough to draw often-used characters. + // For example, if a text field contains a Japanese character, which is + // smaller than Latin ones, and then later a Latin one is inserted, this + // ensures that the text baseline does not shift. + CGFloat font_list_height = font_list().GetHeight(); + 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(width, ascent + descent + leading); common_baseline_ = ascent; } diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc index 391f189..7b9f9b6 100644 --- a/ui/gfx/render_text_unittest.cc +++ b/ui/gfx/render_text_unittest.cc @@ -4,6 +4,8 @@ #include "ui/gfx/render_text.h" +#include <algorithm> + #include "base/memory/scoped_ptr.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -1130,19 +1132,69 @@ TEST_F(RenderTextTest, StringSizeSanity) { // sizes instead of pixel sizes like other implementations. #if !defined(OS_MACOSX) TEST_F(RenderTextTest, StringSizeEmptyString) { - const Font font; + // Ascent and descent of Arial and Symbol are different on most platforms. + const FontList font_list("Arial,Symbol, 16px"); scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); - render_text->SetFont(font); + render_text->SetFontList(font_list); + // The empty string respects FontList metrics for non-zero height + // and baseline. render_text->SetText(base::string16()); - EXPECT_EQ(font.GetHeight(), render_text->GetStringSize().height()); + EXPECT_EQ(font_list.GetHeight(), render_text->GetStringSize().height()); EXPECT_EQ(0, render_text->GetStringSize().width()); + EXPECT_EQ(font_list.GetBaseline(), render_text->GetBaseline()); render_text->SetText(UTF8ToUTF16(" ")); - EXPECT_EQ(font.GetHeight(), render_text->GetStringSize().height()); + EXPECT_EQ(font_list.GetHeight(), render_text->GetStringSize().height()); + EXPECT_EQ(font_list.GetBaseline(), render_text->GetBaseline()); } #endif // !defined(OS_MACOSX) +TEST_F(RenderTextTest, StringSizeRespectsFontListMetrics) { + // Check that Arial and Symbol have different font metrics. + Font arial_font("Arial", 16); + Font symbol_font("Symbol", 16); + EXPECT_NE(arial_font.GetHeight(), symbol_font.GetHeight()); + EXPECT_NE(arial_font.GetBaseline(), symbol_font.GetBaseline()); + // "a" should be rendered with Arial, not with Symbol. + const char* arial_font_text = "a"; + // "®" (registered trademark symbol) should be rendered with Symbol, + // not with Arial. + const char* symbol_font_text = "\xC2\xAE"; + + Font smaller_font = arial_font; + Font larger_font = symbol_font; + const char* smaller_font_text = arial_font_text; + const char* larger_font_text = symbol_font_text; + if (symbol_font.GetHeight() < arial_font.GetHeight() && + symbol_font.GetBaseline() < arial_font.GetBaseline()) { + std::swap(smaller_font, larger_font); + std::swap(smaller_font_text, larger_font_text); + } + ASSERT_LT(smaller_font.GetHeight(), larger_font.GetHeight()); + ASSERT_LT(smaller_font.GetBaseline(), larger_font.GetBaseline()); + + // Check |smaller_font_text| is rendered with the smaller font. + scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); + render_text->SetText(UTF8ToUTF16(smaller_font_text)); + render_text->SetFont(smaller_font); + EXPECT_EQ(smaller_font.GetHeight(), render_text->GetStringSize().height()); + EXPECT_EQ(smaller_font.GetBaseline(), render_text->GetBaseline()); + + // Layout the same text with mixed fonts. The text should be rendered with + // the smaller font, but the height and baseline are determined with the + // metrics of the font list, which is equal to the larger font. + std::vector<Font> fonts; + fonts.push_back(smaller_font); // The primary font is the smaller font. + fonts.push_back(larger_font); + const FontList font_list(fonts); + render_text->SetFontList(font_list); + EXPECT_LT(smaller_font.GetHeight(), render_text->GetStringSize().height()); + EXPECT_LT(smaller_font.GetBaseline(), render_text->GetBaseline()); + EXPECT_EQ(font_list.GetHeight(), render_text->GetStringSize().height()); + EXPECT_EQ(font_list.GetBaseline(), render_text->GetBaseline()); +} + TEST_F(RenderTextTest, SetFont) { scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); render_text->SetFont(Font("Arial", 12)); @@ -1150,6 +1202,16 @@ TEST_F(RenderTextTest, SetFont) { EXPECT_EQ(12, render_text->GetFont().GetFontSize()); } +TEST_F(RenderTextTest, SetFontList) { + scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); + render_text->SetFontList(FontList("Arial,Symbol, 13px")); + const std::vector<Font>& fonts = render_text->font_list().GetFonts(); + ASSERT_EQ(2U, fonts.size()); + EXPECT_EQ("Arial", fonts[0].GetFontName()); + EXPECT_EQ("Symbol", fonts[1].GetFontName()); + EXPECT_EQ(13, render_text->GetFont().GetFontSize()); +} + TEST_F(RenderTextTest, StringSizeBoldWidth) { scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); render_text->SetText(UTF8ToUTF16("Hello World")); diff --git a/ui/gfx/render_text_win.cc b/ui/gfx/render_text_win.cc index 2433dc6..e38d263 100644 --- a/ui/gfx/render_text_win.cc +++ b/ui/gfx/render_text_win.cc @@ -534,6 +534,8 @@ void RenderTextWin::DrawVisualText(Canvas* canvas) { void RenderTextWin::ItemizeLogicalText() { runs_.clear(); + // Make |string_size_|'s height and |common_baseline_| tall enough to draw + // often-used characters which are rendered with fonts in the font list. string_size_ = Size(0, font_list().GetHeight()); common_baseline_ = font_list().GetBaseline(); @@ -611,6 +613,11 @@ void RenderTextWin::LayoutVisualText() { cached_hdc_ = CreateCompatibleDC(NULL); HRESULT hr = E_FAIL; + // Ensure ascent and descent are not smaller than ones of the font list. + // Keep them tall enough to draw often-used characters. + // For example, if a text field contains a Japanese character, which is + // smaller than Latin ones, and then later a Latin one is inserted, this + // ensures that the text baseline does not shift. int ascent = font_list().GetBaseline(); int descent = font_list().GetHeight() - font_list().GetBaseline(); for (size_t i = 0; i < runs_.size(); ++i) { |