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|.
ParseFontDescriptionString(const std::string & font_description_string,std::vector<std::string> * font_names,int * font_style,int * 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.
FontStyleAndSizeToString(int font_style,int font_size)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|.
BuildFontDescription(const std::vector<std::string> & font_names,int font_style,int 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
FontList()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
FontList(const std::string & font_description_string)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
FontList(const std::vector<std::string> & font_names,int font_style,int font_size)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
FontList(const std::vector<Font> & fonts)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
FontList(const Font & font)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
~FontList()142 FontList::~FontList() {
143 }
144
145 // static
SetDefaultFontDescription(const std::string & font_description)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
DeriveFontList(int font_style) const155 FontList FontList::DeriveFontList(int font_style) const {
156 return DeriveFontListWithSizeDeltaAndStyle(0, font_style);
157 }
158
DeriveFontListWithSize(int size) const159 FontList FontList::DeriveFontListWithSize(int size) const {
160 DCHECK_GT(size, 0);
161 return DeriveFontListWithSizeDeltaAndStyle(size - GetFontSize(),
162 GetFontStyle());
163 }
164
DeriveFontListWithSizeDelta(int size_delta) const165 FontList FontList::DeriveFontListWithSizeDelta(int size_delta) const {
166 return DeriveFontListWithSizeDeltaAndStyle(size_delta, GetFontStyle());
167 }
168
DeriveFontListWithSizeDeltaAndStyle(int size_delta,int style) const169 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
GetHeight() const190 int FontList::GetHeight() const {
191 if (common_height_ == -1)
192 CacheCommonFontHeightAndBaseline();
193 return common_height_;
194 }
195
GetBaseline() const196 int FontList::GetBaseline() const {
197 if (common_baseline_ == -1)
198 CacheCommonFontHeightAndBaseline();
199 return common_baseline_;
200 }
201
GetCapHeight() const202 int FontList::GetCapHeight() const {
203 // Assume the primary font is used to render Latin characters.
204 return GetPrimaryFont().GetCapHeight();
205 }
206
GetStringWidth(const base::string16 & text) const207 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
GetExpectedTextWidth(int length) const220 int FontList::GetExpectedTextWidth(int length) const {
221 // Rely on the primary font metrics for the time being.
222 return GetPrimaryFont().GetExpectedTextWidth(length);
223 }
224
GetFontStyle() const225 int FontList::GetFontStyle() const {
226 if (font_style_ == -1)
227 CacheFontStyleAndSize();
228 return font_style_;
229 }
230
GetFontDescriptionString() const231 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
GetFontSize() const246 int FontList::GetFontSize() const {
247 if (font_size_ == -1)
248 CacheFontStyleAndSize();
249 return font_size_;
250 }
251
GetFonts() const252 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
GetPrimaryFont() const272 const Font& FontList::GetPrimaryFont() const {
273 return GetFonts()[0];
274 }
275
CacheCommonFontHeightAndBaseline() const276 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
CacheFontStyleAndSize() const289 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