1 // Copyright 2014 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_impl.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"
13 #include "ui/gfx/font.h"
17 // Parses font description into |font_names|, |font_style| and |font_size|.
18 void ParseFontDescriptionString(const std::string
& font_description_string
,
19 std::vector
<std::string
>* font_names
,
22 base::SplitString(font_description_string
, ',', font_names
);
23 DCHECK_GT(font_names
->size(), 1U);
25 // The last item is [STYLE_OPTIONS] SIZE.
26 std::vector
<std::string
> styles_size
;
27 base::SplitString(font_names
->back(), ' ', &styles_size
);
28 DCHECK(!styles_size
.empty());
29 base::StringToInt(styles_size
.back(), font_size
);
30 DCHECK_GT(*font_size
, 0);
31 font_names
->pop_back();
33 // Font supports BOLD and ITALIC; underline is supported via RenderText.
35 for (size_t i
= 0; i
< styles_size
.size() - 1; ++i
) {
36 // Styles are separated by white spaces. base::SplitString splits styles
37 // by space, and it inserts empty string for continuous spaces.
38 if (styles_size
[i
].empty())
40 if (!styles_size
[i
].compare("Bold"))
41 *font_style
|= gfx::Font::BOLD
;
42 else if (!styles_size
[i
].compare("Italic"))
43 *font_style
|= gfx::Font::ITALIC
;
49 // Returns the font style and size as a string.
50 std::string
FontStyleAndSizeToString(int font_style
, int font_size
) {
52 if (font_style
& gfx::Font::BOLD
)
54 if (font_style
& gfx::Font::ITALIC
)
56 result
+= base::IntToString(font_size
);
61 // Returns font description from |font_names|, |font_style|, and |font_size|.
62 std::string
BuildFontDescription(const std::vector
<std::string
>& font_names
,
65 std::string description
= JoinString(font_names
, ',');
66 description
+= "," + FontStyleAndSizeToString(font_style
, font_size
);
74 FontListImpl::FontListImpl(const std::string
& font_description_string
)
75 : font_description_string_(font_description_string
),
80 DCHECK(!font_description_string
.empty());
81 // DCHECK description string ends with "px" for size in pixel.
82 DCHECK(EndsWith(font_description_string
, "px", true));
85 FontListImpl::FontListImpl(const std::vector
<std::string
>& font_names
,
88 : font_description_string_(BuildFontDescription(font_names
, font_style
,
92 font_style_(font_style
),
93 font_size_(font_size
) {
94 DCHECK(!font_names
.empty());
95 DCHECK(!font_names
[0].empty());
98 FontListImpl::FontListImpl(const std::vector
<Font
>& fonts
)
101 common_baseline_(-1),
104 DCHECK(!fonts
.empty());
105 font_style_
= fonts
[0].GetStyle();
106 font_size_
= fonts
[0].GetFontSize();
108 for (size_t i
= 1; i
< fonts
.size(); ++i
) {
109 DCHECK_EQ(fonts
[i
].GetStyle(), font_style_
);
110 DCHECK_EQ(fonts
[i
].GetFontSize(), font_size_
);
115 FontListImpl::FontListImpl(const Font
& font
)
116 : common_height_(-1),
117 common_baseline_(-1),
120 fonts_
.push_back(font
);
123 FontListImpl
* FontListImpl::Derive(int size_delta
, int font_style
) const {
124 // If there is a font vector, derive from that.
125 if (!fonts_
.empty()) {
126 std::vector
<Font
> fonts
= fonts_
;
127 for (size_t i
= 0; i
< fonts
.size(); ++i
)
128 fonts
[i
] = fonts
[i
].Derive(size_delta
, font_style
);
129 return new FontListImpl(fonts
);
132 // Otherwise, parse the font description string to derive from it.
133 std::vector
<std::string
> font_names
;
136 ParseFontDescriptionString(font_description_string_
, &font_names
,
137 &old_style
, &old_size
);
138 const int size
= std::max(1, old_size
+ size_delta
);
139 return new FontListImpl(font_names
, font_style
, size
);
142 int FontListImpl::GetHeight() const {
143 if (common_height_
== -1)
144 CacheCommonFontHeightAndBaseline();
145 return common_height_
;
148 int FontListImpl::GetBaseline() const {
149 if (common_baseline_
== -1)
150 CacheCommonFontHeightAndBaseline();
151 return common_baseline_
;
154 int FontListImpl::GetCapHeight() const {
155 // Assume the primary font is used to render Latin characters.
156 return GetPrimaryFont().GetCapHeight();
159 int FontListImpl::GetExpectedTextWidth(int length
) const {
160 // Rely on the primary font metrics for the time being.
161 return GetPrimaryFont().GetExpectedTextWidth(length
);
164 int FontListImpl::GetFontStyle() const {
165 if (font_style_
== -1)
166 CacheFontStyleAndSize();
170 const std::string
& FontListImpl::GetFontDescriptionString() const {
171 if (font_description_string_
.empty()) {
172 DCHECK(!fonts_
.empty());
173 for (size_t i
= 0; i
< fonts_
.size(); ++i
) {
174 std::string name
= fonts_
[i
].GetFontName();
175 font_description_string_
+= name
;
176 font_description_string_
+= ',';
178 // All fonts have the same style and size.
179 font_description_string_
+=
180 FontStyleAndSizeToString(fonts_
[0].GetStyle(), fonts_
[0].GetFontSize());
182 return font_description_string_
;
185 int FontListImpl::GetFontSize() const {
186 if (font_size_
== -1)
187 CacheFontStyleAndSize();
191 const std::vector
<Font
>& FontListImpl::GetFonts() const {
192 if (fonts_
.empty()) {
193 DCHECK(!font_description_string_
.empty());
195 std::vector
<std::string
> font_names
;
196 // It's possible that gfx::Font::UNDERLINE is specified and it's already
197 // stored in |font_style_| but |font_description_string_| doesn't have the
198 // underline info. So we should respect |font_style_| as long as it's
201 ParseFontDescriptionString(font_description_string_
, &font_names
,
202 &style
, &font_size_
);
203 if (font_style_
== -1)
205 for (size_t i
= 0; i
< font_names
.size(); ++i
) {
206 DCHECK(!font_names
[i
].empty());
208 Font
font(font_names
[i
], font_size_
);
209 if (font_style_
== Font::NORMAL
)
210 fonts_
.push_back(font
);
212 fonts_
.push_back(font
.Derive(0, font_style_
));
218 const Font
& FontListImpl::GetPrimaryFont() const {
219 return GetFonts()[0];
222 FontListImpl::~FontListImpl() {}
224 void FontListImpl::CacheCommonFontHeightAndBaseline() const {
227 const std::vector
<Font
>& fonts
= GetFonts();
228 for (std::vector
<Font
>::const_iterator i
= fonts
.begin();
229 i
!= fonts
.end(); ++i
) {
230 ascent
= std::max(ascent
, i
->GetBaseline());
231 descent
= std::max(descent
, i
->GetHeight() - i
->GetBaseline());
233 common_height_
= ascent
+ descent
;
234 common_baseline_
= ascent
;
237 void FontListImpl::CacheFontStyleAndSize() const {
238 if (!fonts_
.empty()) {
239 font_style_
= fonts_
[0].GetStyle();
240 font_size_
= fonts_
[0].GetFontSize();
242 std::vector
<std::string
> font_names
;
243 ParseFontDescriptionString(font_description_string_
, &font_names
,
244 &font_style_
, &font_size_
);