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.
4 
5 #include "ui/gfx/font_list_impl.h"
6 
7 #include <stddef.h>
8 
9 #include <algorithm>
10 
11 #include "base/check_op.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "ui/gfx/font_list.h"
15 
16 namespace gfx {
17 namespace {
18 
19 // Returns a font description from |families|, |style|, and |size_pixels|.
BuildDescription(const std::vector<std::string> & families,int style,int size_pixels,Font::Weight weight)20 std::string BuildDescription(const std::vector<std::string>& families,
21                              int style,
22                              int size_pixels,
23                              Font::Weight weight) {
24   std::string description = base::JoinString(families, ",");
25   description += ",";
26 
27   if (style & Font::ITALIC)
28     description += "Italic ";
29   switch (weight) {
30     case Font::Weight::THIN:
31       description += "Thin ";
32       break;
33     case Font::Weight::EXTRA_LIGHT:
34       description += "Ultra-Light ";
35       break;
36     case Font::Weight::LIGHT:
37       description += "Light ";
38       break;
39     case Font::Weight::MEDIUM:
40       description += "Medium ";
41       break;
42     case Font::Weight::SEMIBOLD:
43       description += "Semi-Bold ";
44       break;
45     case Font::Weight::BOLD:
46       description += "Bold ";
47       break;
48     case Font::Weight::EXTRA_BOLD:
49       description += "Ultra-Bold ";
50       break;
51     case Font::Weight::BLACK:
52       description += "Heavy ";
53       break;
54     case Font::Weight::NORMAL:
55     case Font::Weight::INVALID:
56       break;
57   }
58 
59   description += base::NumberToString(size_pixels);
60   description += "px";
61 
62   return description;
63 }
64 
65 }  // namespace
66 
FontListImpl(const std::string & font_description_string)67 FontListImpl::FontListImpl(const std::string& font_description_string)
68     : font_description_string_(font_description_string),
69       common_height_(-1),
70       common_baseline_(-1),
71       font_style_(-1),
72       font_size_(-1),
73       font_weight_(Font::Weight::INVALID) {
74   DCHECK(!font_description_string.empty());
75   // DCHECK description string ends with "px" for size in pixel.
76   DCHECK(base::EndsWith(font_description_string, "px",
77                         base::CompareCase::SENSITIVE));
78 }
79 
FontListImpl(const std::vector<std::string> & font_names,int font_style,int font_size,Font::Weight font_weight)80 FontListImpl::FontListImpl(const std::vector<std::string>& font_names,
81                            int font_style,
82                            int font_size,
83                            Font::Weight font_weight)
84     : font_description_string_(
85           BuildDescription(font_names, font_style, font_size, font_weight)),
86       common_height_(-1),
87       common_baseline_(-1),
88       font_style_(font_style),
89       font_size_(font_size),
90       font_weight_(font_weight) {
91   DCHECK(!font_names.empty());
92   DCHECK(!font_names[0].empty());
93 }
94 
FontListImpl(const std::vector<Font> & fonts)95 FontListImpl::FontListImpl(const std::vector<Font>& fonts)
96     : fonts_(fonts),
97       common_height_(-1),
98       common_baseline_(-1),
99       font_style_(-1),
100       font_size_(-1),
101       font_weight_(Font::Weight::INVALID) {
102   DCHECK(!fonts.empty());
103   font_style_ = fonts[0].GetStyle();
104   font_size_ = fonts[0].GetFontSize();
105   font_weight_ = fonts[0].GetWeight();
106 #if DCHECK_IS_ON()
107   for (size_t i = 1; i < fonts.size(); ++i) {
108     DCHECK_EQ(fonts[i].GetStyle(), font_style_);
109     DCHECK_EQ(fonts[i].GetFontSize(), font_size_);
110   }
111 #endif
112 }
113 
FontListImpl(const Font & font)114 FontListImpl::FontListImpl(const Font& font)
115     : common_height_(-1),
116       common_baseline_(-1),
117       font_style_(-1),
118       font_size_(-1),
119       font_weight_(Font::Weight::INVALID) {
120   fonts_.push_back(font);
121 }
122 
Derive(int size_delta,int font_style,Font::Weight weight) const123 FontListImpl* FontListImpl::Derive(int size_delta,
124                                    int font_style,
125                                    Font::Weight weight) const {
126   // If there is a font vector, derive from that.
127   if (!fonts_.empty()) {
128     std::vector<Font> fonts = fonts_;
129     for (size_t i = 0; i < fonts.size(); ++i)
130       fonts[i] = fonts[i].Derive(size_delta, font_style, weight);
131     return new FontListImpl(fonts);
132   }
133 
134   // Otherwise, parse the font description string to derive from it.
135   std::vector<std::string> font_names;
136   int old_size;
137   int old_style;
138   Font::Weight old_weight;
139   CHECK(FontList::ParseDescription(font_description_string_, &font_names,
140                                    &old_style, &old_size, &old_weight));
141   const int size = std::max(1, old_size + size_delta);
142   return new FontListImpl(font_names, font_style, size, weight);
143 }
144 
GetHeight() const145 int FontListImpl::GetHeight() const {
146   if (common_height_ == -1)
147     CacheCommonFontHeightAndBaseline();
148   return common_height_;
149 }
150 
GetBaseline() const151 int FontListImpl::GetBaseline() const {
152   if (common_baseline_ == -1)
153     CacheCommonFontHeightAndBaseline();
154   return common_baseline_;
155 }
156 
GetCapHeight() const157 int FontListImpl::GetCapHeight() const {
158   // Assume the primary font is used to render Latin characters.
159   return GetPrimaryFont().GetCapHeight();
160 }
161 
GetExpectedTextWidth(int length) const162 int FontListImpl::GetExpectedTextWidth(int length) const {
163   // Rely on the primary font metrics for the time being.
164   return GetPrimaryFont().GetExpectedTextWidth(length);
165 }
166 
GetFontStyle() const167 int FontListImpl::GetFontStyle() const {
168   if (font_style_ == -1)
169     CacheFontStyleAndSize();
170   return font_style_;
171 }
172 
GetFontSize() const173 int FontListImpl::GetFontSize() const {
174   if (font_size_ == -1)
175     CacheFontStyleAndSize();
176   return font_size_;
177 }
178 
GetFontWeight() const179 Font::Weight FontListImpl::GetFontWeight() const {
180   if (font_weight_ == Font::Weight::INVALID)
181     CacheFontStyleAndSize();
182   return font_weight_;
183 }
184 
GetFonts() const185 const std::vector<Font>& FontListImpl::GetFonts() const {
186   if (fonts_.empty()) {
187     DCHECK(!font_description_string_.empty());
188 
189     std::vector<std::string> font_names;
190     // It's possible that Font::UNDERLINE is specified and it's already
191     // stored in |font_style_| but |font_description_string_| doesn't have the
192     // underline info.  So we should respect |font_style_| as long as it's
193     // valid.
194     int style = 0;
195     CHECK(FontList::ParseDescription(font_description_string_, &font_names,
196                                      &style, &font_size_, &font_weight_));
197     if (font_style_ == -1)
198       font_style_ = style;
199     for (size_t i = 0; i < font_names.size(); ++i) {
200       DCHECK(!font_names[i].empty());
201 
202       Font font(font_names[i], font_size_);
203       if (font_style_ == Font::NORMAL && font_weight_ == Font::Weight::NORMAL)
204         fonts_.push_back(font);
205       else
206         fonts_.push_back(font.Derive(0, font_style_, font_weight_));
207     }
208   }
209   return fonts_;
210 }
211 
GetPrimaryFont() const212 const Font& FontListImpl::GetPrimaryFont() const {
213   return GetFonts()[0];
214 }
215 
~FontListImpl()216 FontListImpl::~FontListImpl() {}
217 
CacheCommonFontHeightAndBaseline() const218 void FontListImpl::CacheCommonFontHeightAndBaseline() const {
219   int ascent = 0;
220   int descent = 0;
221   const std::vector<Font>& fonts = GetFonts();
222   for (auto i = fonts.begin(); i != fonts.end(); ++i) {
223     ascent = std::max(ascent, i->GetBaseline());
224     descent = std::max(descent, i->GetHeight() - i->GetBaseline());
225   }
226   common_height_ = ascent + descent;
227   common_baseline_ = ascent;
228 }
229 
CacheFontStyleAndSize() const230 void FontListImpl::CacheFontStyleAndSize() const {
231   if (!fonts_.empty()) {
232     font_style_ = fonts_[0].GetStyle();
233     font_size_ = fonts_[0].GetFontSize();
234     font_weight_ = fonts_[0].GetWeight();
235   } else {
236     std::vector<std::string> font_names;
237     CHECK(FontList::ParseDescription(font_description_string_, &font_names,
238                                      &font_style_, &font_size_, &font_weight_));
239   }
240 }
241 
242 }  // namespace gfx
243