Home | History | Annotate | Download | only in gfx
      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::GetStringWidth(const base::string16& text) const {
    181   // Rely on the primary font metrics for the time being.
    182   // TODO(yukishiino): Not only the first font, all the fonts in the list should
    183   // be taken into account to compute the pixels needed to display |text|.
    184   // Also this method, including one in Font class, should be deprecated and
    185   // client code should call Canvas::GetStringWidth(text, font_list) directly.
    186   // Our plan is as follows:
    187   //   1. Introduce the FontList version of Canvas::GetStringWidth().
    188   //   2. Make client code call Canvas::GetStringWidth().
    189   //   3. Retire {Font,FontList}::GetStringWidth().
    190   return GetPrimaryFont().GetStringWidth(text);
    191 }
    192 
    193 int FontList::GetExpectedTextWidth(int length) const {
    194   // Rely on the primary font metrics for the time being.
    195   return GetPrimaryFont().GetExpectedTextWidth(length);
    196 }
    197 
    198 int FontList::GetFontStyle() const {
    199   if (font_style_ == -1)
    200     CacheFontStyleAndSize();
    201   return font_style_;
    202 }
    203 
    204 const std::string& FontList::GetFontDescriptionString() const {
    205   if (font_description_string_.empty()) {
    206     DCHECK(!fonts_.empty());
    207     for (size_t i = 0; i < fonts_.size(); ++i) {
    208       std::string name = fonts_[i].GetFontName();
    209       font_description_string_ += name;
    210       font_description_string_ += ',';
    211     }
    212     // All fonts have the same style and size.
    213     font_description_string_ +=
    214         FontStyleAndSizeToString(fonts_[0].GetStyle(), fonts_[0].GetFontSize());
    215   }
    216   return font_description_string_;
    217 }
    218 
    219 int FontList::GetFontSize() const {
    220   if (font_size_ == -1)
    221     CacheFontStyleAndSize();
    222   return font_size_;
    223 }
    224 
    225 const std::vector<Font>& FontList::GetFonts() const {
    226   if (fonts_.empty()) {
    227     DCHECK(!font_description_string_.empty());
    228 
    229     std::vector<std::string> font_names;
    230     ParseFontDescriptionString(font_description_string_, &font_names,
    231                                &font_style_, &font_size_);
    232     for (size_t i = 0; i < font_names.size(); ++i) {
    233       DCHECK(!font_names[i].empty());
    234 
    235       Font font(font_names[i], font_size_);
    236       if (font_style_ == Font::NORMAL)
    237         fonts_.push_back(font);
    238       else
    239         fonts_.push_back(font.DeriveFont(0, font_style_));
    240     }
    241   }
    242   return fonts_;
    243 }
    244 
    245 const Font& FontList::GetPrimaryFont() const {
    246   return GetFonts()[0];
    247 }
    248 
    249 void FontList::CacheCommonFontHeightAndBaseline() const {
    250   int ascent = 0;
    251   int descent = 0;
    252   const std::vector<Font>& fonts = GetFonts();
    253   for (std::vector<Font>::const_iterator i = fonts.begin();
    254        i != fonts.end(); ++i) {
    255     ascent = std::max(ascent, i->GetBaseline());
    256     descent = std::max(descent, i->GetHeight() - i->GetBaseline());
    257   }
    258   common_height_ = ascent + descent;
    259   common_baseline_ = ascent;
    260 }
    261 
    262 void FontList::CacheFontStyleAndSize() const {
    263   if (!fonts_.empty()) {
    264     font_style_ = fonts_[0].GetStyle();
    265     font_size_ = fonts_[0].GetFontSize();
    266   } else {
    267     std::vector<std::string> font_names;
    268     ParseFontDescriptionString(font_description_string_, &font_names,
    269                                &font_style_, &font_size_);
    270   }
    271 }
    272 
    273 }  // namespace gfx
    274