1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/gfx/font_list.h" 6 7 #include <algorithm> 8 9 #include "base/lazy_instance.h" 10 #include "base/logging.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_split.h" 13 #include "base/strings/string_util.h" 14 15 namespace { 16 17 // Font description of the default font set. 18 base::LazyInstance<std::string>::Leaky g_default_font_description = 19 LAZY_INSTANCE_INITIALIZER; 20 21 // Parses font description into |font_names|, |font_style| and |font_size|. 22 void ParseFontDescriptionString(const std::string& font_description_string, 23 std::vector<std::string>* font_names, 24 int* font_style, 25 int* font_size) { 26 base::SplitString(font_description_string, ',', font_names); 27 DCHECK_GT(font_names->size(), 1U); 28 29 // The last item is [STYLE_OPTIONS] SIZE. 30 std::vector<std::string> styles_size; 31 base::SplitString(font_names->back(), ' ', &styles_size); 32 DCHECK(!styles_size.empty()); 33 base::StringToInt(styles_size.back(), font_size); 34 DCHECK_GT(*font_size, 0); 35 font_names->pop_back(); 36 37 // Font supports BOLD and ITALIC; underline is supported via RenderText. 38 *font_style = 0; 39 for (size_t i = 0; i < styles_size.size() - 1; ++i) { 40 // Styles are separated by white spaces. base::SplitString splits styles 41 // by space, and it inserts empty string for continuous spaces. 42 if (styles_size[i].empty()) 43 continue; 44 if (!styles_size[i].compare("Bold")) 45 *font_style |= gfx::Font::BOLD; 46 else if (!styles_size[i].compare("Italic")) 47 *font_style |= gfx::Font::ITALIC; 48 else 49 NOTREACHED(); 50 } 51 } 52 53 // Returns the font style and size as a string. 54 std::string FontStyleAndSizeToString(int font_style, int font_size) { 55 std::string result; 56 if (font_style & gfx::Font::BOLD) 57 result += "Bold "; 58 if (font_style & gfx::Font::ITALIC) 59 result += "Italic "; 60 result += base::IntToString(font_size); 61 result += "px"; 62 return result; 63 } 64 65 // Returns font description from |font_names|, |font_style|, and |font_size|. 66 std::string BuildFontDescription(const std::vector<std::string>& font_names, 67 int font_style, 68 int font_size) { 69 std::string description = JoinString(font_names, ','); 70 description += "," + FontStyleAndSizeToString(font_style, font_size); 71 return description; 72 } 73 74 } // namespace 75 76 namespace gfx { 77 78 FontList::FontList() 79 : common_height_(-1), 80 common_baseline_(-1), 81 font_style_(-1), 82 font_size_(-1) { 83 // SetDefaultFontDescription() must be called and the default font description 84 // must be set earlier than any call of the default constructor. 85 DCHECK(!(g_default_font_description == NULL)) // != is not overloaded. 86 << "SetDefaultFontDescription has not been called."; 87 88 font_description_string_ = g_default_font_description.Get(); 89 if (font_description_string_.empty()) 90 fonts_.push_back(Font()); 91 } 92 93 FontList::FontList(const std::string& font_description_string) 94 : font_description_string_(font_description_string), 95 common_height_(-1), 96 common_baseline_(-1), 97 font_style_(-1), 98 font_size_(-1) { 99 DCHECK(!font_description_string.empty()); 100 // DCHECK description string ends with "px" for size in pixel. 101 DCHECK(EndsWith(font_description_string, "px", true)); 102 } 103 104 FontList::FontList(const std::vector<std::string>& font_names, 105 int font_style, 106 int font_size) 107 : font_description_string_(BuildFontDescription(font_names, font_style, 108 font_size)), 109 common_height_(-1), 110 common_baseline_(-1), 111 font_style_(font_style), 112 font_size_(font_size) { 113 DCHECK(!font_names.empty()); 114 DCHECK(!font_names[0].empty()); 115 } 116 117 FontList::FontList(const std::vector<Font>& fonts) 118 : fonts_(fonts), 119 common_height_(-1), 120 common_baseline_(-1), 121 font_style_(-1), 122 font_size_(-1) { 123 DCHECK(!fonts.empty()); 124 font_style_ = fonts[0].GetStyle(); 125 font_size_ = fonts[0].GetFontSize(); 126 if (DCHECK_IS_ON()) { 127 for (size_t i = 1; i < fonts.size(); ++i) { 128 DCHECK_EQ(fonts[i].GetStyle(), font_style_); 129 DCHECK_EQ(fonts[i].GetFontSize(), font_size_); 130 } 131 } 132 } 133 134 FontList::FontList(const Font& font) 135 : common_height_(-1), 136 common_baseline_(-1), 137 font_style_(-1), 138 font_size_(-1) { 139 fonts_.push_back(font); 140 } 141 142 FontList::~FontList() { 143 } 144 145 // static 146 void FontList::SetDefaultFontDescription(const std::string& font_description) { 147 // The description string must end with "px" for size in pixel, or must be 148 // the empty string, which specifies to use a single default font. 149 DCHECK(font_description.empty() || 150 EndsWith(font_description, "px", true)); 151 152 g_default_font_description.Get() = font_description; 153 } 154 155 FontList FontList::DeriveFontList(int font_style) const { 156 return DeriveFontListWithSizeDeltaAndStyle(0, font_style); 157 } 158 159 FontList FontList::DeriveFontListWithSize(int size) const { 160 DCHECK_GT(size, 0); 161 return DeriveFontListWithSizeDeltaAndStyle(size - GetFontSize(), 162 GetFontStyle()); 163 } 164 165 FontList FontList::DeriveFontListWithSizeDelta(int size_delta) const { 166 return DeriveFontListWithSizeDeltaAndStyle(size_delta, GetFontStyle()); 167 } 168 169 FontList FontList::DeriveFontListWithSizeDeltaAndStyle(int size_delta, 170 int style) const { 171 // If there is a font vector, derive from that. 172 if (!fonts_.empty()) { 173 std::vector<Font> fonts = fonts_; 174 for (size_t i = 0; i < fonts.size(); ++i) 175 fonts[i] = fonts[i].DeriveFont(size_delta, style); 176 return FontList(fonts); 177 } 178 179 // Otherwise, parse the font description string to derive from it. 180 std::vector<std::string> font_names; 181 int old_size; 182 int old_style; 183 ParseFontDescriptionString(font_description_string_, &font_names, 184 &old_style, &old_size); 185 int size = old_size + size_delta; 186 DCHECK_GT(size, 0); 187 return FontList(font_names, style, size); 188 } 189 190 int FontList::GetHeight() const { 191 if (common_height_ == -1) 192 CacheCommonFontHeightAndBaseline(); 193 return common_height_; 194 } 195 196 int FontList::GetBaseline() const { 197 if (common_baseline_ == -1) 198 CacheCommonFontHeightAndBaseline(); 199 return common_baseline_; 200 } 201 202 int FontList::GetCapHeight() const { 203 // Assume the primary font is used to render Latin characters. 204 return GetPrimaryFont().GetCapHeight(); 205 } 206 207 int FontList::GetStringWidth(const base::string16& text) const { 208 // Rely on the primary font metrics for the time being. 209 // TODO(yukishiino): Not only the first font, all the fonts in the list should 210 // be taken into account to compute the pixels needed to display |text|. 211 // Also this method, including one in Font class, should be deprecated and 212 // client code should call Canvas::GetStringWidth(text, font_list) directly. 213 // Our plan is as follows: 214 // 1. Introduce the FontList version of Canvas::GetStringWidth(). 215 // 2. Make client code call Canvas::GetStringWidth(). 216 // 3. Retire {Font,FontList}::GetStringWidth(). 217 return GetPrimaryFont().GetStringWidth(text); 218 } 219 220 int FontList::GetExpectedTextWidth(int length) const { 221 // Rely on the primary font metrics for the time being. 222 return GetPrimaryFont().GetExpectedTextWidth(length); 223 } 224 225 int FontList::GetFontStyle() const { 226 if (font_style_ == -1) 227 CacheFontStyleAndSize(); 228 return font_style_; 229 } 230 231 const std::string& FontList::GetFontDescriptionString() const { 232 if (font_description_string_.empty()) { 233 DCHECK(!fonts_.empty()); 234 for (size_t i = 0; i < fonts_.size(); ++i) { 235 std::string name = fonts_[i].GetFontName(); 236 font_description_string_ += name; 237 font_description_string_ += ','; 238 } 239 // All fonts have the same style and size. 240 font_description_string_ += 241 FontStyleAndSizeToString(fonts_[0].GetStyle(), fonts_[0].GetFontSize()); 242 } 243 return font_description_string_; 244 } 245 246 int FontList::GetFontSize() const { 247 if (font_size_ == -1) 248 CacheFontStyleAndSize(); 249 return font_size_; 250 } 251 252 const std::vector<Font>& FontList::GetFonts() const { 253 if (fonts_.empty()) { 254 DCHECK(!font_description_string_.empty()); 255 256 std::vector<std::string> font_names; 257 ParseFontDescriptionString(font_description_string_, &font_names, 258 &font_style_, &font_size_); 259 for (size_t i = 0; i < font_names.size(); ++i) { 260 DCHECK(!font_names[i].empty()); 261 262 Font font(font_names[i], font_size_); 263 if (font_style_ == Font::NORMAL) 264 fonts_.push_back(font); 265 else 266 fonts_.push_back(font.DeriveFont(0, font_style_)); 267 } 268 } 269 return fonts_; 270 } 271 272 const Font& FontList::GetPrimaryFont() const { 273 return GetFonts()[0]; 274 } 275 276 void FontList::CacheCommonFontHeightAndBaseline() const { 277 int ascent = 0; 278 int descent = 0; 279 const std::vector<Font>& fonts = GetFonts(); 280 for (std::vector<Font>::const_iterator i = fonts.begin(); 281 i != fonts.end(); ++i) { 282 ascent = std::max(ascent, i->GetBaseline()); 283 descent = std::max(descent, i->GetHeight() - i->GetBaseline()); 284 } 285 common_height_ = ascent + descent; 286 common_baseline_ = ascent; 287 } 288 289 void FontList::CacheFontStyleAndSize() const { 290 if (!fonts_.empty()) { 291 font_style_ = fonts_[0].GetStyle(); 292 font_size_ = fonts_[0].GetFontSize(); 293 } else { 294 std::vector<std::string> font_names; 295 ParseFontDescriptionString(font_description_string_, &font_names, 296 &font_style_, &font_size_); 297 } 298 } 299 300 } // namespace gfx 301