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.
5 #include "ui/gfx/font_list.h"
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"
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,
21 base::SplitString(font_description_string, ',', font_names);
22 DCHECK_GT(font_names->size(), 1U);
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();
32 // Font supports BOLD and ITALIC; underline is supported via RenderText.
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())
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;
48 // Returns the font style and size as a string.
49 std::string FontStyleAndSizeToString(int font_style, int font_size) {
51 if (font_style & gfx::Font::BOLD)
53 if (font_style & gfx::Font::ITALIC)
55 result += base::IntToString(font_size);
60 // Returns font description from |font_names|, |font_style|, and |font_size|.
61 std::string BuildFontDescription(const std::vector<std::string>& font_names,
64 std::string description = JoinString(font_names, ',');
65 description += "," + FontStyleAndSizeToString(font_style, font_size);
78 fonts_.push_back(Font());
81 FontList::FontList(const std::string& font_description_string)
82 : font_description_string_(font_description_string),
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));
92 FontList::FontList(const std::vector<std::string>& font_names,
95 : font_description_string_(BuildFontDescription(font_names, font_style,
99 font_style_(font_style),
100 font_size_(font_size) {
101 DCHECK(!font_names.empty());
102 DCHECK(!font_names[0].empty());
105 FontList::FontList(const std::vector<Font>& fonts)
108 common_baseline_(-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_);
122 FontList::FontList(const Font& font)
123 : common_height_(-1),
124 common_baseline_(-1),
127 fonts_.push_back(font);
130 FontList::~FontList() {
133 FontList FontList::DeriveFontList(int font_style) const {
134 return DeriveFontListWithSizeDeltaAndStyle(0, font_style);
137 FontList FontList::DeriveFontListWithSize(int size) const {
139 return DeriveFontListWithSizeDeltaAndStyle(size - GetFontSize(),
143 FontList FontList::DeriveFontListWithSizeDelta(int size_delta) const {
144 return DeriveFontListWithSizeDeltaAndStyle(size_delta, GetFontStyle());
147 FontList FontList::DeriveFontListWithSizeDeltaAndStyle(int size_delta,
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);
157 // Otherwise, parse the font description string to derive from it.
158 std::vector<std::string> font_names;
161 ParseFontDescriptionString(font_description_string_, &font_names,
162 &old_style, &old_size);
163 int size = old_size + size_delta;
165 return FontList(font_names, style, size);
168 int FontList::GetHeight() const {
169 if (common_height_ == -1)
170 CacheCommonFontHeightAndBaseline();
171 return common_height_;
174 int FontList::GetBaseline() const {
175 if (common_baseline_ == -1)
176 CacheCommonFontHeightAndBaseline();
177 return common_baseline_;
180 int FontList::GetCapHeight() const {
181 // Assume the primary font is used to render Latin characters.
182 return GetPrimaryFont().GetCapHeight();
185 int FontList::GetStringWidth(const base::string16& text) const {
186 // Rely on the primary font metrics for the time being.
187 // TODO(yukishiino): Not only the first font, all the fonts in the list should
188 // be taken into account to compute the pixels needed to display |text|.
189 // Also this method, including one in Font class, should be deprecated and
190 // client code should call Canvas::GetStringWidth(text, font_list) directly.
191 // Our plan is as follows:
192 // 1. Introduce the FontList version of Canvas::GetStringWidth().
193 // 2. Make client code call Canvas::GetStringWidth().
194 // 3. Retire {Font,FontList}::GetStringWidth().
195 return GetPrimaryFont().GetStringWidth(text);
198 int FontList::GetExpectedTextWidth(int length) const {
199 // Rely on the primary font metrics for the time being.
200 return GetPrimaryFont().GetExpectedTextWidth(length);
203 int FontList::GetFontStyle() const {
204 if (font_style_ == -1)
205 CacheFontStyleAndSize();
209 const std::string& FontList::GetFontDescriptionString() const {
210 if (font_description_string_.empty()) {
211 DCHECK(!fonts_.empty());
212 for (size_t i = 0; i < fonts_.size(); ++i) {
213 std::string name = fonts_[i].GetFontName();
214 font_description_string_ += name;
215 font_description_string_ += ',';
217 // All fonts have the same style and size.
218 font_description_string_ +=
219 FontStyleAndSizeToString(fonts_[0].GetStyle(), fonts_[0].GetFontSize());
221 return font_description_string_;
224 int FontList::GetFontSize() const {
225 if (font_size_ == -1)
226 CacheFontStyleAndSize();
230 const std::vector<Font>& FontList::GetFonts() const {
231 if (fonts_.empty()) {
232 DCHECK(!font_description_string_.empty());
234 std::vector<std::string> font_names;
235 ParseFontDescriptionString(font_description_string_, &font_names,
236 &font_style_, &font_size_);
237 for (size_t i = 0; i < font_names.size(); ++i) {
238 DCHECK(!font_names[i].empty());
240 Font font(font_names[i], font_size_);
241 if (font_style_ == Font::NORMAL)
242 fonts_.push_back(font);
244 fonts_.push_back(font.DeriveFont(0, font_style_));
250 const Font& FontList::GetPrimaryFont() const {
251 return GetFonts()[0];
254 void FontList::CacheCommonFontHeightAndBaseline() const {
257 const std::vector<Font>& fonts = GetFonts();
258 for (std::vector<Font>::const_iterator i = fonts.begin();
259 i != fonts.end(); ++i) {
260 ascent = std::max(ascent, i->GetBaseline());
261 descent = std::max(descent, i->GetHeight() - i->GetBaseline());
263 common_height_ = ascent + descent;
264 common_baseline_ = ascent;
267 void FontList::CacheFontStyleAndSize() const {
268 if (!fonts_.empty()) {
269 font_style_ = fonts_[0].GetStyle();
270 font_size_ = fonts_[0].GetFontSize();
272 std::vector<std::string> font_names;
273 ParseFontDescriptionString(font_description_string_, &font_names,
274 &font_style_, &font_size_);