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/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|.
     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.
     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|.
     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 
     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 
     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 
    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 
    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 
    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 
    142 FontList::~FontList() {
    143 }
    144 
    145 // static
    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 
    155 FontList FontList::DeriveFontList(int font_style) const {
    156   return DeriveFontListWithSizeDeltaAndStyle(0, font_style);
    157 }
    158 
    159 FontList FontList::DeriveFontListWithSize(int size) const {
    160   DCHECK_GT(size, 0);
    161   return DeriveFontListWithSizeDeltaAndStyle(size - GetFontSize(),
    162                                              GetFontStyle());
    163 }
    164 
    165 FontList FontList::DeriveFontListWithSizeDelta(int size_delta) const {
    166   return DeriveFontListWithSizeDeltaAndStyle(size_delta, GetFontStyle());
    167 }
    168 
    169 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 
    190 int FontList::GetHeight() const {
    191   if (common_height_ == -1)
    192     CacheCommonFontHeightAndBaseline();
    193   return common_height_;
    194 }
    195 
    196 int FontList::GetBaseline() const {
    197   if (common_baseline_ == -1)
    198     CacheCommonFontHeightAndBaseline();
    199   return common_baseline_;
    200 }
    201 
    202 int FontList::GetCapHeight() const {
    203   // Assume the primary font is used to render Latin characters.
    204   return GetPrimaryFont().GetCapHeight();
    205 }
    206 
    207 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 
    220 int FontList::GetExpectedTextWidth(int length) const {
    221   // Rely on the primary font metrics for the time being.
    222   return GetPrimaryFont().GetExpectedTextWidth(length);
    223 }
    224 
    225 int FontList::GetFontStyle() const {
    226   if (font_style_ == -1)
    227     CacheFontStyleAndSize();
    228   return font_style_;
    229 }
    230 
    231 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 
    246 int FontList::GetFontSize() const {
    247   if (font_size_ == -1)
    248     CacheFontStyleAndSize();
    249   return font_size_;
    250 }
    251 
    252 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 
    272 const Font& FontList::GetPrimaryFont() const {
    273   return GetFonts()[0];
    274 }
    275 
    276 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 
    289 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