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 15namespace { 16 17// Parses font description into |font_names|, |font_style| and |font_size|. 18void 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. 50std::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|. 62std::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 72namespace gfx { 73 74FontListImpl::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 85FontListImpl::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 98FontListImpl::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#endif 113} 114 115FontListImpl::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 123FontListImpl* 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 142int FontListImpl::GetHeight() const { 143 if (common_height_ == -1) 144 CacheCommonFontHeightAndBaseline(); 145 return common_height_; 146} 147 148int FontListImpl::GetBaseline() const { 149 if (common_baseline_ == -1) 150 CacheCommonFontHeightAndBaseline(); 151 return common_baseline_; 152} 153 154int FontListImpl::GetCapHeight() const { 155 // Assume the primary font is used to render Latin characters. 156 return GetPrimaryFont().GetCapHeight(); 157} 158 159int FontListImpl::GetExpectedTextWidth(int length) const { 160 // Rely on the primary font metrics for the time being. 161 return GetPrimaryFont().GetExpectedTextWidth(length); 162} 163 164int FontListImpl::GetFontStyle() const { 165 if (font_style_ == -1) 166 CacheFontStyleAndSize(); 167 return font_style_; 168} 169 170const 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 185int FontListImpl::GetFontSize() const { 186 if (font_size_ == -1) 187 CacheFontStyleAndSize(); 188 return font_size_; 189} 190 191const 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 218const Font& FontListImpl::GetPrimaryFont() const { 219 return GetFonts()[0]; 220} 221 222FontListImpl::~FontListImpl() {} 223 224void 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 237void 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 249