• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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