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/platform_font_mac.h"
      6 
      7 #include <Cocoa/Cocoa.h>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/mac/scoped_nsobject.h"
     11 #include "base/strings/sys_string_conversions.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "ui/gfx/canvas.h"
     14 #include "ui/gfx/font.h"
     15 
     16 namespace gfx {
     17 
     18 namespace {
     19 
     20 // Returns an autoreleased NSFont created with the passed-in specifications.
     21 NSFont* NSFontWithSpec(const std::string& font_name,
     22                        int font_size,
     23                        int font_style) {
     24   NSFontSymbolicTraits trait_bits = 0;
     25   if (font_style & Font::BOLD)
     26     trait_bits |= NSFontBoldTrait;
     27   if (font_style & Font::ITALIC)
     28     trait_bits |= NSFontItalicTrait;
     29   // The Mac doesn't support underline as a font trait, so just drop it.
     30   // (Underlines must be added as an attribute on an NSAttributedString.)
     31   NSDictionary* traits = @{ NSFontSymbolicTrait : @(trait_bits) };
     32 
     33   NSDictionary* attrs = @{
     34     NSFontFamilyAttribute : base::SysUTF8ToNSString(font_name),
     35     NSFontTraitsAttribute : traits
     36   };
     37   NSFontDescriptor* descriptor =
     38       [NSFontDescriptor fontDescriptorWithFontAttributes:attrs];
     39   NSFont* font = [NSFont fontWithDescriptor:descriptor size:font_size];
     40   if (font)
     41     return font;
     42 
     43   // Make one fallback attempt by looking up via font name rather than font
     44   // family name.
     45   attrs = @{
     46     NSFontNameAttribute : base::SysUTF8ToNSString(font_name),
     47     NSFontTraitsAttribute : traits
     48   };
     49   descriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:attrs];
     50   return [NSFont fontWithDescriptor:descriptor size:font_size];
     51 }
     52 
     53 }  // namespace
     54 
     55 ////////////////////////////////////////////////////////////////////////////////
     56 // PlatformFontMac, public:
     57 
     58 PlatformFontMac::PlatformFontMac()
     59     : native_font_([[NSFont systemFontOfSize:[NSFont systemFontSize]] retain]),
     60       font_name_(base::SysNSStringToUTF8([native_font_ familyName])),
     61       font_size_([NSFont systemFontSize]),
     62       font_style_(Font::NORMAL) {
     63   CalculateMetrics();
     64 }
     65 
     66 PlatformFontMac::PlatformFontMac(NativeFont native_font)
     67     : native_font_([native_font retain]),
     68       font_name_(base::SysNSStringToUTF8([native_font_ familyName])),
     69       font_size_([native_font_ pointSize]),
     70       font_style_(Font::NORMAL) {
     71   NSFontSymbolicTraits traits = [[native_font fontDescriptor] symbolicTraits];
     72   if (traits & NSFontItalicTrait)
     73     font_style_ |= Font::ITALIC;
     74   if (traits & NSFontBoldTrait)
     75     font_style_ |= Font::BOLD;
     76 
     77   CalculateMetrics();
     78 }
     79 
     80 PlatformFontMac::PlatformFontMac(const std::string& font_name,
     81                                  int font_size)
     82     : native_font_([NSFontWithSpec(font_name, font_size, Font::NORMAL) retain]),
     83       font_name_(font_name),
     84       font_size_(font_size),
     85       font_style_(Font::NORMAL) {
     86   CalculateMetrics();
     87 }
     88 
     89 ////////////////////////////////////////////////////////////////////////////////
     90 // PlatformFontMac, PlatformFont implementation:
     91 
     92 Font PlatformFontMac::DeriveFont(int size_delta, int style) const {
     93   return Font(new PlatformFontMac(font_name_, font_size_ + size_delta, style));
     94 }
     95 
     96 int PlatformFontMac::GetHeight() const {
     97   return height_;
     98 }
     99 
    100 int PlatformFontMac::GetBaseline() const {
    101   return ascent_;
    102 }
    103 
    104 int PlatformFontMac::GetCapHeight() const {
    105   return cap_height_;
    106 }
    107 
    108 int PlatformFontMac::GetAverageCharacterWidth() const {
    109   return average_width_;
    110 }
    111 
    112 int PlatformFontMac::GetStringWidth(const base::string16& text) const {
    113   return Canvas::GetStringWidth(text,
    114                                 Font(const_cast<PlatformFontMac*>(this)));
    115 }
    116 
    117 int PlatformFontMac::GetExpectedTextWidth(int length) const {
    118   return length * average_width_;
    119 }
    120 
    121 int PlatformFontMac::GetStyle() const {
    122   return font_style_;
    123 }
    124 
    125 std::string PlatformFontMac::GetFontName() const {
    126   return font_name_;
    127 }
    128 
    129 std::string PlatformFontMac::GetActualFontNameForTesting() const {
    130   return base::SysNSStringToUTF8([native_font_ familyName]);
    131 }
    132 
    133 int PlatformFontMac::GetFontSize() const {
    134   return font_size_;
    135 }
    136 
    137 NativeFont PlatformFontMac::GetNativeFont() const {
    138   return [[native_font_.get() retain] autorelease];
    139 }
    140 
    141 ////////////////////////////////////////////////////////////////////////////////
    142 // PlatformFontMac, private:
    143 
    144 PlatformFontMac::PlatformFontMac(const std::string& font_name,
    145                                  int font_size,
    146                                  int font_style)
    147     : native_font_([NSFontWithSpec(font_name, font_size, font_style) retain]),
    148       font_name_(font_name),
    149       font_size_(font_size),
    150       font_style_(font_style) {
    151   CalculateMetrics();
    152 }
    153 
    154 PlatformFontMac::~PlatformFontMac() {
    155 }
    156 
    157 void PlatformFontMac::CalculateMetrics() {
    158   NSFont* font = native_font_.get();
    159   if (!font) {
    160     // This object was constructed from a font name that doesn't correspond to
    161     // an actual font. Don't waste time working out metrics.
    162     height_ = 0;
    163     ascent_ = 0;
    164     cap_height_ = 0;
    165     average_width_ = 0;
    166     return;
    167   }
    168 
    169   base::scoped_nsobject<NSLayoutManager> layout_manager(
    170       [[NSLayoutManager alloc] init]);
    171   height_ = [layout_manager defaultLineHeightForFont:font];
    172   ascent_ = [font ascender];
    173   cap_height_ = [font capHeight];
    174   average_width_ =
    175       NSWidth([font boundingRectForGlyph:[font glyphWithName:@"x"]]);
    176 }
    177 
    178 ////////////////////////////////////////////////////////////////////////////////
    179 // PlatformFont, public:
    180 
    181 // static
    182 PlatformFont* PlatformFont::CreateDefault() {
    183   return new PlatformFontMac;
    184 }
    185 
    186 // static
    187 PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) {
    188   return new PlatformFontMac(native_font);
    189 }
    190 
    191 // static
    192 PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
    193                                                   int font_size) {
    194   return new PlatformFontMac(font_name, font_size);
    195 }
    196 
    197 }  // namespace gfx
    198