Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / ui / gfx / font_list_impl.cc
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 <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 #include "ui/gfx/font.h"
14
15 namespace {
16
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,
20                                 int* font_style,
21                                 int* font_size) {
22   base::SplitString(font_description_string, ',', font_names);
23   DCHECK_GT(font_names->size(), 1U);
24
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();
32
33   // Font supports BOLD and ITALIC; underline is supported via RenderText.
34   *font_style = 0;
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())
39       continue;
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;
44     else
45       NOTREACHED();
46   }
47 }
48
49 // Returns the font style and size as a string.
50 std::string FontStyleAndSizeToString(int font_style, int font_size) {
51   std::string result;
52   if (font_style & gfx::Font::BOLD)
53     result += "Bold ";
54   if (font_style & gfx::Font::ITALIC)
55     result += "Italic ";
56   result += base::IntToString(font_size);
57   result += "px";
58   return result;
59 }
60
61 // Returns font description from |font_names|, |font_style|, and |font_size|.
62 std::string BuildFontDescription(const std::vector<std::string>& font_names,
63                                  int font_style,
64                                  int font_size) {
65   std::string description = JoinString(font_names, ',');
66   description += "," + FontStyleAndSizeToString(font_style, font_size);
67   return description;
68 }
69
70 }  // namespace
71
72 namespace gfx {
73
74 FontListImpl::FontListImpl(const std::string& font_description_string)
75     : font_description_string_(font_description_string),
76       common_height_(-1),
77       common_baseline_(-1),
78       font_style_(-1),
79       font_size_(-1) {
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));
83 }
84
85 FontListImpl::FontListImpl(const std::vector<std::string>& font_names,
86                            int font_style,
87                            int font_size)
88     : font_description_string_(BuildFontDescription(font_names, font_style,
89                                                     font_size)),
90       common_height_(-1),
91       common_baseline_(-1),
92       font_style_(font_style),
93       font_size_(font_size) {
94   DCHECK(!font_names.empty());
95   DCHECK(!font_names[0].empty());
96 }
97
98 FontListImpl::FontListImpl(const std::vector<Font>& fonts)
99     : fonts_(fonts),
100       common_height_(-1),
101       common_baseline_(-1),
102       font_style_(-1),
103       font_size_(-1) {
104   DCHECK(!fonts.empty());
105   font_style_ = fonts[0].GetStyle();
106   font_size_ = fonts[0].GetFontSize();
107   if (DCHECK_IS_ON()) {
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_);
111     }
112   }
113 }
114
115 FontListImpl::FontListImpl(const Font& font)
116     : common_height_(-1),
117       common_baseline_(-1),
118       font_style_(-1),
119       font_size_(-1) {
120   fonts_.push_back(font);
121 }
122
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);
130   }
131
132   // Otherwise, parse the font description string to derive from it.
133   std::vector<std::string> font_names;
134   int old_size;
135   int old_style;
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);
140 }
141
142 int FontListImpl::GetHeight() const {
143   if (common_height_ == -1)
144     CacheCommonFontHeightAndBaseline();
145   return common_height_;
146 }
147
148 int FontListImpl::GetBaseline() const {
149   if (common_baseline_ == -1)
150     CacheCommonFontHeightAndBaseline();
151   return common_baseline_;
152 }
153
154 int FontListImpl::GetCapHeight() const {
155   // Assume the primary font is used to render Latin characters.
156   return GetPrimaryFont().GetCapHeight();
157 }
158
159 int FontListImpl::GetExpectedTextWidth(int length) const {
160   // Rely on the primary font metrics for the time being.
161   return GetPrimaryFont().GetExpectedTextWidth(length);
162 }
163
164 int FontListImpl::GetFontStyle() const {
165   if (font_style_ == -1)
166     CacheFontStyleAndSize();
167   return font_style_;
168 }
169
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_ += ',';
177     }
178     // All fonts have the same style and size.
179     font_description_string_ +=
180         FontStyleAndSizeToString(fonts_[0].GetStyle(), fonts_[0].GetFontSize());
181   }
182   return font_description_string_;
183 }
184
185 int FontListImpl::GetFontSize() const {
186   if (font_size_ == -1)
187     CacheFontStyleAndSize();
188   return font_size_;
189 }
190
191 const std::vector<Font>& FontListImpl::GetFonts() const {
192   if (fonts_.empty()) {
193     DCHECK(!font_description_string_.empty());
194
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
199     // valid.
200     int style = 0;
201     ParseFontDescriptionString(font_description_string_, &font_names,
202                                &style, &font_size_);
203     if (font_style_ == -1)
204       font_style_ = style;
205     for (size_t i = 0; i < font_names.size(); ++i) {
206       DCHECK(!font_names[i].empty());
207
208       Font font(font_names[i], font_size_);
209       if (font_style_ == Font::NORMAL)
210         fonts_.push_back(font);
211       else
212         fonts_.push_back(font.Derive(0, font_style_));
213     }
214   }
215   return fonts_;
216 }
217
218 const Font& FontListImpl::GetPrimaryFont() const {
219   return GetFonts()[0];
220 }
221
222 FontListImpl::~FontListImpl() {}
223
224 void FontListImpl::CacheCommonFontHeightAndBaseline() const {
225   int ascent = 0;
226   int descent = 0;
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());
232   }
233   common_height_ = ascent + descent;
234   common_baseline_ = ascent;
235 }
236
237 void FontListImpl::CacheFontStyleAndSize() const {
238   if (!fonts_.empty()) {
239     font_style_ = fonts_[0].GetStyle();
240     font_size_ = fonts_[0].GetFontSize();
241   } else {
242     std::vector<std::string> font_names;
243     ParseFontDescriptionString(font_description_string_, &font_names,
244                                &font_style_, &font_size_);
245   }
246 }
247
248 }  // namespace gfx