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