diff options
author | xji@chromium.org <xji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-19 04:09:01 +0000 |
---|---|---|
committer | xji@chromium.org <xji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-19 04:09:01 +0000 |
commit | 732ef6737ef6e1346255be7230032dcaf4e9ad03 (patch) | |
tree | c9663673eba42c9f33c413a909c16a37d7bd2ebb /ui | |
parent | 963c1b96abd9baa3ccddb7bc59da8a93e0c2ae93 (diff) | |
download | chromium_src-732ef6737ef6e1346255be7230032dcaf4e9ad03.zip chromium_src-732ef6737ef6e1346255be7230032dcaf4e9ad03.tar.gz chromium_src-732ef6737ef6e1346255be7230032dcaf4e9ad03.tar.bz2 |
specify locale-dependent font list for UI on ChromeOS, so that those fonts have higher priority over the fallback fonts Pango picks up.
BUG=103860
TEST=build aura, start chromium in 'ar' locale. type in Arabic and check the Arabic text's shapes. remove IDS_UI_FONT_FAMILY_CROS from 'ar' resource file, build aura again, start chromium in 'ar', type in Arabic and the Arabic text's shapes should be different.
Review URL: http://codereview.chromium.org/8770034
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114953 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/base/strings/app_locale_settings.grd | 2 | ||||
-rw-r--r-- | ui/base/strings/app_locale_settings_ar.xtb | 1 | ||||
-rw-r--r-- | ui/base/strings/app_locale_settings_hi.xtb | 1 | ||||
-rw-r--r-- | ui/base/strings/app_locale_settings_ja.xtb | 2 | ||||
-rw-r--r-- | ui/base/strings/app_locale_settings_ko.xtb | 1 | ||||
-rw-r--r-- | ui/base/strings/app_locale_settings_th.xtb | 1 | ||||
-rw-r--r-- | ui/base/strings/app_locale_settings_zh-CN.xtb | 1 | ||||
-rw-r--r-- | ui/base/strings/app_locale_settings_zh-TW.xtb | 1 | ||||
-rw-r--r-- | ui/gfx/font_list.cc | 115 | ||||
-rw-r--r-- | ui/gfx/font_list.h | 79 | ||||
-rw-r--r-- | ui/gfx/font_list_unittest.cc | 208 | ||||
-rw-r--r-- | ui/gfx/pango_util.cc | 44 | ||||
-rw-r--r-- | ui/gfx/pango_util.h | 12 | ||||
-rw-r--r-- | ui/gfx/render_text.cc | 51 | ||||
-rw-r--r-- | ui/gfx/render_text.h | 22 | ||||
-rw-r--r-- | ui/gfx/render_text_linux.cc | 47 | ||||
-rw-r--r-- | ui/gfx/render_text_linux.h | 9 | ||||
-rw-r--r-- | ui/gfx/render_text_unittest.cc | 2 | ||||
-rw-r--r-- | ui/gfx/render_text_win.cc | 5 | ||||
-rw-r--r-- | ui/ui.gyp | 2 | ||||
-rw-r--r-- | ui/ui_unittests.gypi | 1 | ||||
-rw-r--r-- | ui/views/controls/textfield/native_textfield_views.cc | 20 |
22 files changed, 508 insertions, 119 deletions
diff --git a/ui/base/strings/app_locale_settings.grd b/ui/base/strings/app_locale_settings.grd index 91156c4..ca451d4 100644 --- a/ui/base/strings/app_locale_settings.grd +++ b/ui/base/strings/app_locale_settings.grd @@ -192,7 +192,7 @@ <if expr="pp_ifdef('chromeos')"> <!-- The font name like: 'Font Name, 10' --> <message name="IDS_UI_FONT_FAMILY_CROS" use_name_for_id="true"> - default + Chrome Droid Sans,Droid Sans Fallback,sans-serif, 9 </message> </if> </messages> diff --git a/ui/base/strings/app_locale_settings_ar.xtb b/ui/base/strings/app_locale_settings_ar.xtb index e1d3faf..3e447d7 100644 --- a/ui/base/strings/app_locale_settings_ar.xtb +++ b/ui/base/strings/app_locale_settings_ar.xtb @@ -2,4 +2,5 @@ <!DOCTYPE translationbundle> <translationbundle lang="ar"> <translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation> +<translation id="IDS_UI_FONT_FAMILY_CROS">Chrome Droid Sans,Droid Arabic Kufi,Droid Sans Fallback,sans-serif, 10</translation> </translationbundle> diff --git a/ui/base/strings/app_locale_settings_hi.xtb b/ui/base/strings/app_locale_settings_hi.xtb index 56983d7..e024983 100644 --- a/ui/base/strings/app_locale_settings_hi.xtb +++ b/ui/base/strings/app_locale_settings_hi.xtb @@ -4,4 +4,5 @@ <translation id="IDS_UI_FONT_SIZE_SCALER_XP">140</translation> <translation id="IDS_UI_FONT_SIZE_SCALER">125</translation> <translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation> +<translation id="IDS_UI_FONT_FAMILY_CROS">Chrome Droid Sans,Mangal,Lohit Hindi,Droid Sans Fallback,sans-serif, 10</translation> </translationbundle> diff --git a/ui/base/strings/app_locale_settings_ja.xtb b/ui/base/strings/app_locale_settings_ja.xtb index 933d47d..9010c05 100644 --- a/ui/base/strings/app_locale_settings_ja.xtb +++ b/ui/base/strings/app_locale_settings_ja.xtb @@ -2,5 +2,5 @@ <!DOCTYPE translationbundle> <translationbundle lang="ja"> <translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation> -<translation id="IDS_UI_FONT_FAMILY_CROS">IPAPGothic, 10</translation> +<translation id="IDS_UI_FONT_FAMILY_CROS">Chrome Droid Sans,IPAPGothic,Droid Sans Fallback,sans-serif, 10</translation> </translationbundle> diff --git a/ui/base/strings/app_locale_settings_ko.xtb b/ui/base/strings/app_locale_settings_ko.xtb index 7c4134c..2110024 100644 --- a/ui/base/strings/app_locale_settings_ko.xtb +++ b/ui/base/strings/app_locale_settings_ko.xtb @@ -2,4 +2,5 @@ <!DOCTYPE translationbundle> <translationbundle lang="ko"> <translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation> +<translation id="IDS_UI_FONT_FAMILY_CROS">Chrome Droid Sans,NanumGothic,Droid Sans Fallback,sans-serif, 10</translation> </translationbundle> diff --git a/ui/base/strings/app_locale_settings_th.xtb b/ui/base/strings/app_locale_settings_th.xtb index 070c16e..550b08e 100644 --- a/ui/base/strings/app_locale_settings_th.xtb +++ b/ui/base/strings/app_locale_settings_th.xtb @@ -2,4 +2,5 @@ <!DOCTYPE translationbundle> <translationbundle lang="th"> <translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation> +<translation id="IDS_UI_FONT_FAMILY_CROS">Chrome Droid Sans,Droid Sans Thai,Droid Sans Fallback,sans-serif, 10</translation> </translationbundle> diff --git a/ui/base/strings/app_locale_settings_zh-CN.xtb b/ui/base/strings/app_locale_settings_zh-CN.xtb index 1034e66..f1d2a57 100644 --- a/ui/base/strings/app_locale_settings_zh-CN.xtb +++ b/ui/base/strings/app_locale_settings_zh-CN.xtb @@ -2,4 +2,5 @@ <!DOCTYPE translationbundle> <translationbundle lang="zh-CN"> <translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation> +<translation id="IDS_UI_FONT_FAMILY_CROS">Chrome Droid Sans,Song ASC,Droid Sans Fallback,sans-serif, 10</translation> </translationbundle> diff --git a/ui/base/strings/app_locale_settings_zh-TW.xtb b/ui/base/strings/app_locale_settings_zh-TW.xtb index 8829d71..c7a01c1 100644 --- a/ui/base/strings/app_locale_settings_zh-TW.xtb +++ b/ui/base/strings/app_locale_settings_zh-TW.xtb @@ -2,4 +2,5 @@ <!DOCTYPE translationbundle> <translationbundle lang="zh-TW"> <translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation> +<translation id="IDS_UI_FONT_FAMILY_CROS">Chrome Droid Sans,Song ASC,Droid Sans Fallback,sans-serif, 10</translation> </translationbundle> diff --git a/ui/gfx/font_list.cc b/ui/gfx/font_list.cc new file mode 100644 index 0000000..a6c0867 --- /dev/null +++ b/ui/gfx/font_list.cc @@ -0,0 +1,115 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stdlib.h> + +#include "base/logging.h" +#include "base/string_number_conversions.h" +#include "base/string_split.h" +#include "ui/gfx/font_list.h" + +namespace gfx { + +FontList::FontList() { + fonts_.push_back(Font()); +} + +FontList::FontList(const std::string& font_description_string) + : font_description_string_(font_description_string) { + DCHECK(!font_description_string.empty()); +} + +FontList::FontList(const std::vector<Font>& fonts) + : fonts_(fonts) { + DCHECK(!fonts.empty()); + if (DCHECK_IS_ON()) { + int style = fonts[0].GetStyle(); + int size = fonts[0].GetFontSize(); + for (size_t i = 1; i < fonts.size(); ++i) { + DCHECK_EQ(fonts[i].GetStyle(), style); + DCHECK_EQ(fonts[i].GetFontSize(), size); + } + } +} + +FontList::FontList(const Font& font) { + fonts_.push_back(font); +} + +FontList::~FontList() { +} + +const std::string& FontList::GetFontDescriptionString() const { + if (font_description_string_.empty()) { + DCHECK(!fonts_.empty()); + for (size_t i = 0; i < fonts_.size(); ++i) { + std::string name = fonts_[i].GetFontName(); + font_description_string_ += name; + font_description_string_ += ','; + } + // All fonts have the same style and size. + // TODO(xji): add style for Windows. +#if defined(OS_LINUX) + int style = fonts_[0].GetStyle(); + if (style & Font::BOLD) + font_description_string_ += "PANGO_WEIGHT_BOLD "; + if (style & Font::ITALIC) + font_description_string_ += "PANGO_STYLE_ITALIC "; +#endif + int size = fonts_[0].GetFontSize(); + font_description_string_ += base::IntToString(size); + } + return font_description_string_; +} + +const std::vector<Font>& FontList::GetFonts() const { + if (fonts_.empty()) { + DCHECK(!font_description_string_.empty()); + + std::vector<std::string> name_style_size; + base::SplitString(font_description_string_, ',', &name_style_size); + int item_count = static_cast<int>(name_style_size.size()); + DCHECK_GT(item_count, 1); + + // The last item is [STYLE_OPTIONS] SIZE. + std::vector<std::string> styles_size; + base::SplitString(name_style_size[item_count - 1], ' ', &styles_size); + int size; + DCHECK(!styles_size.empty()); + base::StringToInt(styles_size[styles_size.size() - 1], &size); + DCHECK_GT(size, 0); + + int style = 0; + // TODO(xji): parse style for Windows. +#if defined(OS_LINUX) + // Besides underline (which is supported through StyleRange), Font only + // supports BOLD and ITALIC styles, not other Pango styles. + for (size_t i = 0; i < styles_size.size() - 1; ++i) { + // Styles are separated by white spaces. base::SplitString splits styles + // by space, and it inserts empty string for continuous spaces. + if (styles_size[i].empty()) + continue; + if (!styles_size[i].compare("PANGO_WEIGHT_BOLD")) + style |= Font::BOLD; + else if (!styles_size[i].compare("PANGO_STYLE_ITALIC")) + style |= Font::ITALIC; + else + NOTREACHED(); + } +#endif + + for (int i = 0; i < item_count - 1; ++i) { + DCHECK(!name_style_size[i].empty()); + + Font font(name_style_size[i], size); + if (style == Font::NORMAL) + fonts_.push_back(font); + else + fonts_.push_back(font.DeriveFont(0, style)); + } + } + return fonts_; +} + +} // namespace gfx diff --git a/ui/gfx/font_list.h b/ui/gfx/font_list.h new file mode 100644 index 0000000..ef6b357 --- /dev/null +++ b/ui/gfx/font_list.h @@ -0,0 +1,79 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_GFX_FONT_LIST_H_ +#define UI_GFX_FONT_LIST_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/gtest_prod_util.h" +#include "ui/base/ui_export.h" +#include "ui/gfx/font.h" + +namespace gfx { + +// FontList represents a list of fonts either in the form of Font vector or in +// the form of a string representing font names, styles, and size. +// +// The string representation is in the form "FAMILY_LIST [STYLE_OPTIONS] SIZE", +// where FAMILY_LIST is a comma separated list of families terminated by a +// comma, STYLE_OPTIONS is a whitespace separated list of words where each word +// describes one of style, variant, weight, stretch, or gravity, and SIZE is +// a decimal number (size in points). STYLE_OPTIONS may be absent. +// +// The string format complies with that of Pango detailed at +// http://developer.gnome.org/pango/stable/pango-Fonts.html#pango-font-description-from-string +// +// FontList could be initialized either way without conversion to the other +// form. The conversion to the other form is done only when asked to get the +// other form. +// +// FontList allows operator= since FontList is a data member type in RenderText, +// and operator= is used in RenderText::SetFontList(). +class UI_EXPORT FontList { + public: + // Creates a font list with a Font with default name and style. + FontList(); + + // Creates a font list from a string representing font names, styles, and + // size. + explicit FontList(const std::string& font_description_string); + + // Creates a font list from a Font vector. + // All fonts in this vector should have the same style and size. + explicit FontList(const std::vector<Font>& fonts); + + // Creates a font list from a Font. + explicit FontList(const Font& font); + + ~FontList(); + + // Returns a string representing font names, styles, and size. If the FontList + // is initialized by a vector of Font, use the first font's style and size + // for the description. + const std::string& GetFontDescriptionString() const; + + // Returns the Font vector. + const std::vector<Font>& GetFonts() const; + + private: + // A vector of Font. If FontList is constructed with font description string, + // |fonts_| is not initialized during construction. Instead, it is computed + // lazily when user asked to get the font vector. + mutable std::vector<Font> fonts_; + + // A string representing font names, styles, and sizes. + // Please refer to the comments before class declaration for details on string + // format. + // If FontList is constructed with a vector of font, + // |font_description_string_| is not initialized during construction. Instead, + // it is computed lazily when user asked to get the font description string. + mutable std::string font_description_string_; +}; + +} // namespace gfx + +#endif // UI_GFX_FONT_LIST_H_ diff --git a/ui/gfx/font_list_unittest.cc b/ui/gfx/font_list_unittest.cc new file mode 100644 index 0000000..a9b02fb --- /dev/null +++ b/ui/gfx/font_list_unittest.cc @@ -0,0 +1,208 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/font_list.h" + +#include <string> +#include <vector> + +#include "testing/gtest/include/gtest/gtest.h" + +namespace gfx { + +typedef testing::Test FontListTest; + +TEST_F(FontListTest, FontDescString_FromDescString) { + // Test init from font name style size string. + FontList font_list = FontList("Droid Sans serif, Sans serif, 10"); + const std::string& font_str = font_list.GetFontDescriptionString(); + EXPECT_EQ("Droid Sans serif, Sans serif, 10", font_str); +} + +TEST_F(FontListTest, FontDescString_FromFont) { + // Test init from Font. + Font font("Arial", 8); + FontList font_list = FontList(font); + const std::string& font_str = font_list.GetFontDescriptionString(); + EXPECT_EQ("Arial,8", font_str); +} + +TEST_F(FontListTest, FontDescString_FromFontWithNonNormalStyle) { + // Test init from Font with non-normal style. + Font font("Arial", 8); + FontList font_list = FontList(font.DeriveFont(2, Font::BOLD)); + const std::string& font_str = font_list.GetFontDescriptionString(); +#if defined(OS_LINUX) + EXPECT_EQ("Arial,PANGO_WEIGHT_BOLD 10", font_str); +#else + EXPECT_EQ("Arial,10", font_str); +#endif + + font_list = FontList(font.DeriveFont(-2, Font::ITALIC)); + const std::string& font_str_1 = font_list.GetFontDescriptionString(); +#if defined(OS_LINUX) + EXPECT_EQ("Arial,PANGO_STYLE_ITALIC 6", font_str_1); +#else + EXPECT_EQ("Arial,6", font_str_1); +#endif +} + +TEST_F(FontListTest, FontDescString_FromFontVector) { + // Test init from Font vector. + Font font("Arial", 8); + Font font_1("Sans serif", 10); + std::vector<Font> fonts; + fonts.push_back(font.DeriveFont(0, Font::BOLD)); + fonts.push_back(font_1.DeriveFont(-2, Font::BOLD)); + FontList font_list = FontList(fonts); + const std::string& font_str = font_list.GetFontDescriptionString(); +#if defined(OS_LINUX) + EXPECT_EQ("Arial,Sans serif,PANGO_WEIGHT_BOLD 8", font_str); +#else + EXPECT_EQ("Arial,Sans serif,8", font_str); +#endif +} + +TEST_F(FontListTest, Fonts_FromDescString) { + // Test init from font name size string. + FontList font_list = FontList("serif,Sans serif, 10"); + const std::vector<Font>& fonts = font_list.GetFonts(); + EXPECT_EQ(2U, fonts.size()); + EXPECT_EQ("serif", fonts[0].GetFontName()); + EXPECT_EQ(10, fonts[0].GetFontSize()); + EXPECT_EQ(Font::NORMAL, fonts[0].GetStyle()); + EXPECT_EQ("Sans serif", fonts[1].GetFontName()); + EXPECT_EQ(10, fonts[1].GetFontSize()); + EXPECT_EQ(Font::NORMAL, fonts[1].GetStyle()); +} + +TEST_F(FontListTest, Fonts_FromDescStringInFlexibleFormat) { + // Test init from font name size string with flexible format. + FontList font_list = FontList(" serif , Sans serif , 10 "); + const std::vector<Font>& fonts = font_list.GetFonts(); + EXPECT_EQ(2U, fonts.size()); + EXPECT_EQ("serif", fonts[0].GetFontName()); + EXPECT_EQ(10, fonts[0].GetFontSize()); + EXPECT_EQ(Font::NORMAL, fonts[0].GetStyle()); + EXPECT_EQ("Sans serif", fonts[1].GetFontName()); + EXPECT_EQ(10, fonts[1].GetFontSize()); + EXPECT_EQ(Font::NORMAL, fonts[1].GetStyle()); +} + +TEST_F(FontListTest, Fonts_FromDescStringWithStyleInFlexibleFormat) { + // Test init from font name style size string with flexible format. + FontList font_list = FontList(" serif , Sans serif , PANGO_WEIGHT_BOLD " + " PANGO_STYLE_ITALIC 10 "); + const std::vector<Font>& fonts = font_list.GetFonts(); + EXPECT_EQ(2U, fonts.size()); + EXPECT_EQ("serif", fonts[0].GetFontName()); + EXPECT_EQ(10, fonts[0].GetFontSize()); +#if defined(OS_LINUX) + EXPECT_EQ(Font::BOLD | Font::ITALIC, fonts[0].GetStyle()); +#else + EXPECT_EQ(Font::NORMAL, fonts[0].GetStyle()); +#endif + EXPECT_EQ("Sans serif", fonts[1].GetFontName()); + EXPECT_EQ(10, fonts[1].GetFontSize()); +#if defined(OS_LINUX) + EXPECT_EQ(Font::BOLD | Font::ITALIC, fonts[1].GetStyle()); +#else + EXPECT_EQ(Font::NORMAL, fonts[1].GetStyle()); +#endif +} + +TEST_F(FontListTest, Fonts_FromFont) { + // Test init from Font. + Font font("Arial", 8); + FontList font_list = FontList(font); + const std::vector<Font>& fonts = font_list.GetFonts(); + EXPECT_EQ(1U, fonts.size()); + EXPECT_EQ("Arial", fonts[0].GetFontName()); + EXPECT_EQ(8, fonts[0].GetFontSize()); + EXPECT_EQ(Font::NORMAL, fonts[0].GetStyle()); +} + +TEST_F(FontListTest, Fonts_FromFontWithNonNormalStyle) { + // Test init from Font with non-normal style. + Font font("Arial", 8); + FontList font_list = FontList(font.DeriveFont(2, Font::BOLD)); + const std::vector<Font>& fonts = font_list.GetFonts(); + EXPECT_EQ(1U, fonts.size()); + EXPECT_EQ("Arial", fonts[0].GetFontName()); + EXPECT_EQ(10, fonts[0].GetFontSize()); + EXPECT_EQ(Font::BOLD, fonts[0].GetStyle()); + + font_list = FontList(font.DeriveFont(-2, Font::ITALIC)); + const std::vector<Font>& fonts_1 = font_list.GetFonts(); + EXPECT_EQ(1U, fonts_1.size()); + EXPECT_EQ("Arial", fonts_1[0].GetFontName()); + EXPECT_EQ(6, fonts_1[0].GetFontSize()); + EXPECT_EQ(Font::ITALIC, fonts_1[0].GetStyle()); +} + +TEST_F(FontListTest, Fonts_FromFontVector) { + // Test init from Font vector. + Font font("Arial", 8); + Font font_1("Sans serif", 10); + std::vector<Font> input_fonts; + input_fonts.push_back(font.DeriveFont(0, Font::BOLD)); + input_fonts.push_back(font_1.DeriveFont(-2, Font::BOLD)); + FontList font_list = FontList(input_fonts); + const std::vector<Font>& fonts = font_list.GetFonts(); + EXPECT_EQ(2U, fonts.size()); + EXPECT_EQ("Arial", fonts[0].GetFontName()); + EXPECT_EQ(8, fonts[0].GetFontSize()); + EXPECT_EQ(Font::BOLD, fonts[0].GetStyle()); + EXPECT_EQ("Sans serif", fonts[1].GetFontName()); + EXPECT_EQ(8, fonts[1].GetFontSize()); + EXPECT_EQ(Font::BOLD, fonts[1].GetStyle()); +} + +TEST_F(FontListTest, Fonts_DescStringWithStyleInFlexibleFormat_RoundTrip) { + // Test round trip from font description string to font vector to + // font description string. + FontList font_list = FontList(" serif , Sans serif , PANGO_WEIGHT_BOLD " + " PANGO_STYLE_ITALIC 10 "); + + const std::vector<Font>& fonts = font_list.GetFonts(); + FontList font_list_1 = FontList(fonts); + const std::string& desc_str = font_list_1.GetFontDescriptionString(); + +#if defined(OS_LINUX) + EXPECT_EQ("serif,Sans serif,PANGO_WEIGHT_BOLD PANGO_STYLE_ITALIC 10", + desc_str); +#else + EXPECT_EQ("serif,Sans serif,10", desc_str); +#endif +} + +TEST_F(FontListTest, Fonts_FontVector_RoundTrip) { + // Test round trip from font vector to font description string to font vector. + Font font("Arial", 8); + Font font_1("Sans serif", 10); + std::vector<Font> input_fonts; + input_fonts.push_back(font.DeriveFont(0, Font::BOLD)); + input_fonts.push_back(font_1.DeriveFont(-2, Font::BOLD)); + FontList font_list = FontList(input_fonts); + + const std::string& desc_string = font_list.GetFontDescriptionString(); + FontList font_list_1 = FontList(desc_string); + const std::vector<Font>& round_trip_fonts = font_list_1.GetFonts(); + + EXPECT_EQ(2U, round_trip_fonts.size()); + EXPECT_EQ("Arial", round_trip_fonts[0].GetFontName()); + EXPECT_EQ(8, round_trip_fonts[0].GetFontSize()); + EXPECT_EQ("Sans serif", round_trip_fonts[1].GetFontName()); + EXPECT_EQ(8, round_trip_fonts[1].GetFontSize()); +#if defined(OS_LINUX) + EXPECT_EQ(Font::BOLD, round_trip_fonts[0].GetStyle()); + EXPECT_EQ(Font::BOLD, round_trip_fonts[1].GetStyle()); +#else + // Style is ignored. + EXPECT_EQ(Font::NORMAL, round_trip_fonts[0].GetStyle()); + EXPECT_EQ(Font::NORMAL, round_trip_fonts[1].GetStyle()); +#endif +} + +} // namespace gfx diff --git a/ui/gfx/pango_util.cc b/ui/gfx/pango_util.cc index 55e4374..1c7e9e4 100644 --- a/ui/gfx/pango_util.cc +++ b/ui/gfx/pango_util.cc @@ -169,12 +169,12 @@ void DrawTextOntoCairoSurface(cairo_t* cr, } // Pass a width greater than 0 to force wrapping and eliding. -void SetupPangoLayout(PangoLayout* layout, - const string16& text, - const Font& font, - int width, - base::i18n::TextDirection text_direction, - int flags) { +static void SetupPangoLayoutWithoutFont( + PangoLayout* layout, + const string16& text, + int width, + base::i18n::TextDirection text_direction, + int flags) { cairo_font_options_t* cairo_font_options = GetCairoFontOptions(); // This needs to be done early on; it has no effect when called just before // pango_cairo_show_layout(). @@ -221,10 +221,6 @@ void SetupPangoLayout(PangoLayout* layout, resolution); } - PangoFontDescription* desc = font.GetNativeFont(); - pango_layout_set_font_description(layout, desc); - pango_font_description_free(desc); - // Set text and accelerator character if needed. if (flags & Canvas::SHOW_PREFIX) { // Escape the text string to be used as markup. @@ -254,6 +250,34 @@ void SetupPangoLayout(PangoLayout* layout, } } +void SetupPangoLayout(PangoLayout* layout, + const string16& text, + const Font& font, + int width, + base::i18n::TextDirection text_direction, + int flags) { + SetupPangoLayoutWithoutFont(layout, text, width, text_direction, flags); + + PangoFontDescription* desc = font.GetNativeFont(); + pango_layout_set_font_description(layout, desc); + pango_font_description_free(desc); +} + +void SetupPangoLayoutWithFontDescription( + PangoLayout* layout, + const string16& text, + const std::string& font_description, + int width, + base::i18n::TextDirection text_direction, + int flags) { + SetupPangoLayoutWithoutFont(layout, text, width, text_direction, flags); + + PangoFontDescription* desc = pango_font_description_from_string( + font_description.c_str()); + pango_layout_set_font_description(layout, desc); + pango_font_description_free(desc); +} + void AdjustTextRectBasedOnLayout(PangoLayout* layout, const gfx::Rect& bounds, int flags, diff --git a/ui/gfx/pango_util.h b/ui/gfx/pango_util.h index 903e6df..93b9bf2 100644 --- a/ui/gfx/pango_util.h +++ b/ui/gfx/pango_util.h @@ -8,6 +8,7 @@ #include <cairo/cairo.h> #include <pango/pango.h> +#include <string> #include "base/i18n/rtl.h" #include "base/string16.h" @@ -47,6 +48,17 @@ void SetupPangoLayout(PangoLayout* layout, base::i18n::TextDirection text_direction, int flags); + +// Setup pango layout |layout| the same way as SetupPangoLayout(), except this +// sets the font description based on |font_description|. +void SetupPangoLayoutWithFontDescription( + PangoLayout* layout, + const string16& text, + const std::string& font_description, + int width, + base::i18n::TextDirection text_direction, + int flags); + // Get Pango's calculated size of |layout| and modify |text_rect| within // |bounds|. void AdjustTextRectBasedOnLayout(PangoLayout* layout, diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index 657dd1a..017ae73 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc @@ -163,11 +163,9 @@ void SkiaTextRenderer::DrawDecorations(int x, int y, int width, StyleRange::StyleRange() - : font(), - foreground(SK_ColorBLACK), + : foreground(SK_ColorBLACK), strike(false), - underline(false), - range() { + underline(false) { } RenderText::~RenderText() { @@ -211,6 +209,16 @@ void RenderText::SetText(const string16& text) { UpdateLayout(); } +void RenderText::SetFontList(const FontList& font_list) { + font_list_ = font_list; + cached_bounds_and_offset_valid_ = false; + UpdateLayout(); +} + +const Font& RenderText::GetFont() const { + return font_list_.GetFonts()[0]; +} + void RenderText::ToggleInsertMode() { insert_mode_ = !insert_mode_; cached_bounds_and_offset_valid_ = false; @@ -425,10 +433,6 @@ base::i18n::TextDirection RenderText::GetTextDirection() { return base::i18n::LEFT_TO_RIGHT; } -int RenderText::GetStringWidth() { - return default_style_.font.GetStringWidth(text()); -} - void RenderText::Draw(Canvas* canvas) { TRACE_EVENT0("gfx", "RenderText::Draw"); { @@ -444,35 +448,6 @@ void RenderText::Draw(Canvas* canvas) { DrawCursor(canvas); } -SelectionModel RenderText::FindCursorPosition(const Point& point) { - const Font& font = default_style_.font; - int left = 0; - int left_pos = 0; - int right = font.GetStringWidth(text()); - int right_pos = text().length(); - - int x = point.x() - (display_rect_.x() + GetUpdatedDisplayOffset().x()); - if (x <= left) return SelectionModel(left_pos); - if (x >= right) return SelectionModel(right_pos); - // binary searching the cursor position. - // TODO(oshima): use the center of character instead of edge. - // Binary search may not work for language like Arabic. - while (std::abs(right_pos - left_pos) > 1) { - int pivot_pos = left_pos + (right_pos - left_pos) / 2; - int pivot = font.GetStringWidth(text().substr(0, pivot_pos)); - if (pivot < x) { - left = pivot; - left_pos = pivot_pos; - } else if (pivot == x) { - return SelectionModel(pivot_pos); - } else { - right = pivot; - right_pos = pivot_pos; - } - } - return SelectionModel(left_pos); -} - const Rect& RenderText::GetUpdatedCursorBounds() { UpdateCachedBoundsAndOffset(); return cursor_bounds_; @@ -645,7 +620,7 @@ Point RenderText::ToViewPoint(const Point& point) { Point RenderText::GetOriginForSkiaDrawing() { Point origin(ToViewPoint(Point())); // TODO(msw): Establish a vertical baseline for strings of mixed font heights. - const Font& font = default_style().font; + const Font& font = GetFont(); size_t height = font.GetHeight(); // Center the text vertically in the display area. origin.Offset(0, (display_rect().height() - height) / 2); diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h index 4329a2c..9f13be4 100644 --- a/ui/gfx/render_text.h +++ b/ui/gfx/render_text.h @@ -15,7 +15,7 @@ #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkPaint.h" #include "ui/base/range/range.h" -#include "ui/gfx/font.h" +#include "ui/gfx/font_list.h" #include "ui/gfx/point.h" #include "ui/gfx/rect.h" #include "ui/gfx/selection_model.h" @@ -70,7 +70,11 @@ const SkColor kCursorColor = SK_ColorBLACK; struct UI_EXPORT StyleRange { StyleRange(); - Font font; + // TODO(asvitkine): Add RenderText support for font weight. Add a |bold| style + // flag here, to be handled in RenderText's layout phase. For example, in + // RenderTextLinux, generate the new font description with font weight style + // option, create a Pango attribute from it, and append the attribute to + // layout. SkColor foreground; bool strike; bool underline; @@ -105,6 +109,11 @@ class UI_EXPORT RenderText { const string16& text() const { return text_; } void SetText(const string16& text); + const FontList& font_list() const { return font_list_; } + void SetFontList(const FontList& font_list); + // Get the first font in |font_list_|. + const Font& GetFont() const; + const SelectionModel& selection_model() const { return selection_model_; } bool cursor_visible() const { return cursor_visible_; } @@ -188,12 +197,12 @@ class UI_EXPORT RenderText { virtual base::i18n::TextDirection GetTextDirection(); // Get the width of the entire string. - virtual int GetStringWidth(); + virtual int GetStringWidth() = 0; - virtual void Draw(Canvas* canvas); + void Draw(Canvas* canvas); // Gets the SelectionModel from a visual point in local coordinates. - virtual SelectionModel FindCursorPosition(const Point& point); + virtual SelectionModel FindCursorPosition(const Point& point) = 0; // Get the visual bounds of a cursor at |selection|. These bounds typically // represent a vertical line, but if |insert_mode| is true they contain the @@ -318,6 +327,9 @@ class UI_EXPORT RenderText { // Logical UTF-16 string data to be drawn. string16 text_; + // A list of fonts used to render |text_|. + FontList font_list_; + // Logical selection range and visual cursor position. SelectionModel selection_model_; diff --git a/ui/gfx/render_text_linux.cc b/ui/gfx/render_text_linux.cc index 3aab7f8..9a17ab4 100644 --- a/ui/gfx/render_text_linux.cc +++ b/ui/gfx/render_text_linux.cc @@ -6,6 +6,7 @@ #include <pango/pangocairo.h> #include <algorithm> +#include <string> #include <vector> #include "base/debug/trace_event.h" @@ -242,10 +243,10 @@ void RenderTextLinux::EnsureLayout() { cairo_t* cr = scoped_platform_paint.GetPlatformSurface(); layout_ = pango_cairo_create_layout(cr); - SetupPangoLayout( + SetupPangoLayoutWithFontDescription( layout_, text(), - default_style().font, + font_list().GetFontDescriptionString(), display_rect().width(), base::i18n::GetFirstStrongCharacterDirection(text()), CanvasSkia::DefaultCanvasTextAlignment()); @@ -257,7 +258,6 @@ void RenderTextLinux::EnsureLayout() { // TODO(xji): If RenderText will be used for displaying purpose, such as // label, we will need to remove the single-line-mode setting. pango_layout_set_single_paragraph_mode(layout_, true); - SetupPangoAttributes(layout_); current_line_ = pango_layout_get_line_readonly(layout_, 0); pango_layout_line_ref(current_line_); @@ -648,47 +648,6 @@ void RenderTextLinux::ResetLayout() { layout_text_len_ = 0; } -void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) { - PangoAttrList* attrs = pango_attr_list_new(); - - PlatformFont* default_platform_font = default_style().font.platform_font(); - - PangoAttribute* pango_attr; - for (StyleRanges::const_iterator i = style_ranges().begin(); - i < style_ranges().end(); ++i) { - size_t start = std::min(i->range.start(), text().length()); - size_t end = std::min(i->range.end(), text().length()); - if (start >= end) - continue; - - const Font& font = i->font; - // In Pango, different fonts means different runs, and it breaks Arabic - // shaping acorss run boundaries. So, set font only when it is different - // from the default font. - // TODO(xji): we'll eventually need to split up StyleRange into components - // (ColorRange, FontRange, etc.) so that we can combine adjacent ranges - // with the same Fonts (to avoid unnecessarily splitting up runs) - if (font.platform_font() != default_platform_font) { - PangoFontDescription* desc = font.GetNativeFont(); - pango_attr = pango_attr_font_desc_new(desc); - AppendPangoAttribute(start, end, pango_attr, attrs); - pango_font_description_free(desc); - } - } - - pango_layout_set_attributes(layout, attrs); - pango_attr_list_unref(attrs); -} - -void RenderTextLinux::AppendPangoAttribute(size_t start, - size_t end, - PangoAttribute* pango_attr, - PangoAttrList* attrs) { - pango_attr->start_index = Utf16IndexToUtf8Index(start); - pango_attr->end_index = Utf16IndexToUtf8Index(end); - pango_attr_list_insert(attrs, pango_attr); -} - // TODO(xji): Keep a vector of runs to avoid using a singly-linked list. PangoLayoutRun* RenderTextLinux::GetPreviousRun(PangoLayoutRun* run) const { GSList* current = current_line_->runs; diff --git a/ui/gfx/render_text_linux.h b/ui/gfx/render_text_linux.h index 462494d..bbb6052 100644 --- a/ui/gfx/render_text_linux.h +++ b/ui/gfx/render_text_linux.h @@ -78,15 +78,6 @@ class RenderTextLinux : public RenderText { // Unref |layout_| and |pango_line_|. Set them to NULL. void ResetLayout(); - // Setup pango attribute: foreground, background, font, strike. - void SetupPangoAttributes(PangoLayout* layout); - - // Append one pango attribute |pango_attr| into pango attribute list |attrs|. - void AppendPangoAttribute(size_t start, - size_t end, - PangoAttribute* pango_attr, - PangoAttrList* attrs); - // Returns |run|'s visually previous run. // The complexity is O(n) since it is a single-linked list. PangoLayoutRun* GetPreviousRun(PangoLayoutRun* run) const; diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc index 0aa6625..2c60d90 100644 --- a/ui/gfx/render_text_unittest.cc +++ b/ui/gfx/render_text_unittest.cc @@ -27,8 +27,6 @@ TEST_F(RenderTextTest, DefaultStyle) { render_text->SetText(ASCIIToUTF16("abc")); EXPECT_EQ(1U, render_text->style_ranges().size()); StyleRange style; - EXPECT_EQ(style.font.GetFontName(), - render_text->style_ranges()[0].font.GetFontName()); EXPECT_EQ(style.foreground, render_text->style_ranges()[0].foreground); EXPECT_EQ(ui::Range(0, 3), render_text->style_ranges()[0].range); EXPECT_EQ(style.strike, render_text->style_ranges()[0].strike); diff --git a/ui/gfx/render_text_win.cc b/ui/gfx/render_text_win.cc index 1086c65..5a76179 100644 --- a/ui/gfx/render_text_win.cc +++ b/ui/gfx/render_text_win.cc @@ -202,7 +202,7 @@ Rect RenderTextWin::GetCursorBounds(const SelectionModel& selection, DCHECK(SUCCEEDED(hr)); } // TODO(msw): Use the last visual run's font instead of the default font? - int height = run ? run->font.GetHeight() : default_style().font.GetHeight(); + int height = run ? run->font.GetHeight() : GetFont().GetHeight(); Rect rect(std::min(start_x, end_x), 0, std::abs(end_x - start_x), height); // Offset to the run start or the right/left end for an out of bounds index. // Also center the rect vertically in the display area. @@ -508,7 +508,7 @@ void RenderTextWin::ItemizeLogicalText() { for (int run_break = 0; run_break < text_length;) { internal::TextRun* run = new internal::TextRun(); run->range.set_start(run_break); - run->font = style->font; + run->font = GetFont(); run->foreground = style->foreground; run->strike = style->strike; run->underline = style->underline; @@ -577,6 +577,7 @@ void RenderTextWin::LayoutVisualText() { } // The run's font doesn't contain the required glyphs, use an alternate. + // TODO(msw): support RenderText's font_list(). if (ChooseFallbackFont(hdc, run->font, run_text, run_length, &run->font)) { ScriptFreeCache(&run->script_cache); @@ -266,6 +266,8 @@ 'gfx/favicon_size.h', 'gfx/font.h', 'gfx/font.cc', + 'gfx/font_list.h', + 'gfx/font_list.cc', 'gfx/gfx_paths.cc', 'gfx/gfx_paths.h', 'gfx/image/image.cc', diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi index 7b1ec9f..359dc89 100644 --- a/ui/ui_unittests.gypi +++ b/ui/ui_unittests.gypi @@ -73,6 +73,7 @@ 'gfx/color_analysis_unittest.cc', 'gfx/color_utils_unittest.cc', 'gfx/font_unittest.cc', + 'gfx/font_list_unittest.cc', 'gfx/image/image_mac_unittest.mm', 'gfx/image/image_unittest.cc', 'gfx/image/image_unittest_util.h', diff --git a/ui/views/controls/textfield/native_textfield_views.cc b/ui/views/controls/textfield/native_textfield_views.cc index 677c458..f5089d7 100644 --- a/ui/views/controls/textfield/native_textfield_views.cc +++ b/ui/views/controls/textfield/native_textfield_views.cc @@ -12,9 +12,11 @@ #include "base/logging.h" #include "base/message_loop.h" #include "base/utf_string_conversions.h" +#include "grit/app_locale_settings.h" #include "grit/ui_strings.h" #include "ui/base/clipboard/clipboard.h" #include "ui/base/dragdrop/drag_drop_types.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/range/range.h" #include "ui/gfx/canvas.h" #include "ui/gfx/insets.h" @@ -77,9 +79,14 @@ NativeTextfieldViews::NativeTextfieldViews(Textfield* parent) // Lowercase is not supported. DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE); +#if defined(OS_CHROMEOS) + GetRenderText()->SetFontList(gfx::FontList(l10n_util::GetStringUTF8( + IDS_UI_FONT_FAMILY_CROS))); +#else + GetRenderText()->SetFontList(gfx::FontList(textfield_->font())); +#endif // Set the default text style. gfx::StyleRange default_style; - default_style.font = textfield_->font(); default_style.foreground = textfield_->text_color(); GetRenderText()->set_default_style(default_style); GetRenderText()->ApplyDefaultStyle(); @@ -390,13 +397,12 @@ void NativeTextfieldViews::UpdateReadOnly() { } void NativeTextfieldViews::UpdateFont() { - // Update the default text style. - gfx::StyleRange default_style(GetRenderText()->default_style()); - default_style.font = textfield_->font(); - GetRenderText()->set_default_style(default_style); - GetRenderText()->ApplyDefaultStyle(); - +#if !defined(OS_CHROMEOS) + // For ChromeOS, we support a font list per locale, UpdateFont() should not + // take any effect. + GetRenderText()->SetFontList(gfx::FontList(textfield_->font())); OnCaretBoundsChanged(); +#endif } void NativeTextfieldViews::UpdateIsPassword() { |