- add sources.
[platform/framework/web/crosswalk.git] / src / ui / gfx / font_list.cc
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/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
14 namespace {
15
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,
19                                 int* font_style,
20                                 int* font_size) {
21   base::SplitString(font_description_string, ',', font_names);
22   DCHECK_GT(font_names->size(), 1U);
23
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();
31
32   // Font supports BOLD and ITALIC; underline is supported via RenderText.
33   *font_style = 0;
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())
38       continue;
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;
43     else
44       NOTREACHED();
45   }
46 }
47
48 // Returns the font style and size as a string.
49 std::string FontStyleAndSizeToString(int font_style, int font_size) {
50   std::string result;
51   if (font_style & gfx::Font::BOLD)
52     result += "Bold ";
53   if (font_style & gfx::Font::ITALIC)
54     result += "Italic ";
55   result += base::IntToString(font_size);
56   result += "px";
57   return result;
58 }
59
60 // Returns font description from |font_names|, |font_style|, and |font_size|.
61 std::string BuildFontDescription(const std::vector<std::string>& font_names,
62                                  int font_style,
63                                  int font_size) {
64   std::string description = JoinString(font_names, ',');
65   description += "," + FontStyleAndSizeToString(font_style, font_size);
66   return description;
67 }
68
69 }  // namespace
70
71 namespace gfx {
72
73 FontList::FontList()
74     : common_height_(-1),
75       common_baseline_(-1),
76       font_style_(-1),
77       font_size_(-1) {
78   fonts_.push_back(Font());
79 }
80
81 FontList::FontList(const std::string& font_description_string)
82     : font_description_string_(font_description_string),
83       common_height_(-1),
84       common_baseline_(-1),
85       font_style_(-1),
86       font_size_(-1) {
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));
90 }
91
92 FontList::FontList(const std::vector<std::string>& font_names,
93                    int font_style,
94                    int font_size)
95     : font_description_string_(BuildFontDescription(font_names, font_style,
96                                                     font_size)),
97       common_height_(-1),
98       common_baseline_(-1),
99       font_style_(font_style),
100       font_size_(font_size) {
101   DCHECK(!font_names.empty());
102   DCHECK(!font_names[0].empty());
103 }
104
105 FontList::FontList(const std::vector<Font>& fonts)
106     : fonts_(fonts),
107       common_height_(-1),
108       common_baseline_(-1),
109       font_style_(-1),
110       font_size_(-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_);
118     }
119   }
120 }
121
122 FontList::FontList(const Font& font)
123     : common_height_(-1),
124       common_baseline_(-1),
125       font_style_(-1),
126       font_size_(-1) {
127   fonts_.push_back(font);
128 }
129
130 FontList::~FontList() {
131 }
132
133 FontList FontList::DeriveFontList(int font_style) const {
134   return DeriveFontListWithSizeDeltaAndStyle(0, font_style);
135 }
136
137 FontList FontList::DeriveFontListWithSize(int size) const {
138   DCHECK_GT(size, 0);
139   return DeriveFontListWithSizeDeltaAndStyle(size - GetFontSize(),
140                                              GetFontStyle());
141 }
142
143 FontList FontList::DeriveFontListWithSizeDelta(int size_delta) const {
144   return DeriveFontListWithSizeDeltaAndStyle(size_delta, GetFontStyle());
145 }
146
147 FontList FontList::DeriveFontListWithSizeDeltaAndStyle(int size_delta,
148                                                        int style) const {
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);
155   }
156
157   // Otherwise, parse the font description string to derive from it.
158   std::vector<std::string> font_names;
159   int old_size;
160   int old_style;
161   ParseFontDescriptionString(font_description_string_, &font_names,
162                              &old_style, &old_size);
163   int size = old_size + size_delta;
164   DCHECK_GT(size, 0);
165   return FontList(font_names, style, size);
166 }
167
168 int FontList::GetHeight() const {
169   if (common_height_ == -1)
170     CacheCommonFontHeightAndBaseline();
171   return common_height_;
172 }
173
174 int FontList::GetBaseline() const {
175   if (common_baseline_ == -1)
176     CacheCommonFontHeightAndBaseline();
177   return common_baseline_;
178 }
179
180 int FontList::GetCapHeight() const {
181   // Assume the primary font is used to render Latin characters.
182   return GetPrimaryFont().GetCapHeight();
183 }
184
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);
196 }
197
198 int FontList::GetExpectedTextWidth(int length) const {
199   // Rely on the primary font metrics for the time being.
200   return GetPrimaryFont().GetExpectedTextWidth(length);
201 }
202
203 int FontList::GetFontStyle() const {
204   if (font_style_ == -1)
205     CacheFontStyleAndSize();
206   return font_style_;
207 }
208
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_ += ',';
216     }
217     // All fonts have the same style and size.
218     font_description_string_ +=
219         FontStyleAndSizeToString(fonts_[0].GetStyle(), fonts_[0].GetFontSize());
220   }
221   return font_description_string_;
222 }
223
224 int FontList::GetFontSize() const {
225   if (font_size_ == -1)
226     CacheFontStyleAndSize();
227   return font_size_;
228 }
229
230 const std::vector<Font>& FontList::GetFonts() const {
231   if (fonts_.empty()) {
232     DCHECK(!font_description_string_.empty());
233
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());
239
240       Font font(font_names[i], font_size_);
241       if (font_style_ == Font::NORMAL)
242         fonts_.push_back(font);
243       else
244         fonts_.push_back(font.DeriveFont(0, font_style_));
245     }
246   }
247   return fonts_;
248 }
249
250 const Font& FontList::GetPrimaryFont() const {
251   return GetFonts()[0];
252 }
253
254 void FontList::CacheCommonFontHeightAndBaseline() const {
255   int ascent = 0;
256   int descent = 0;
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());
262   }
263   common_height_ = ascent + descent;
264   common_baseline_ = ascent;
265 }
266
267 void FontList::CacheFontStyleAndSize() const {
268   if (!fonts_.empty()) {
269     font_style_ = fonts_[0].GetStyle();
270     font_size_ = fonts_[0].GetFontSize();
271   } else {
272     std::vector<std::string> font_names;
273     ParseFontDescriptionString(font_description_string_, &font_names,
274                                &font_style_, &font_size_);
275   }
276 }
277
278 }  // namespace gfx