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