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.
5 #include "ui/gfx/platform_font_mac.h"
7 #include <Cocoa/Cocoa.h>
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"
21 // Returns an autoreleased NSFont created with the passed-in specifications.
22 NSFont* NSFontWithSpec(const std::string& font_name,
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) };
34 NSDictionary* attrs = @{
35 NSFontFamilyAttribute : base::SysUTF8ToNSString(font_name),
36 NSFontTraitsAttribute : traits
38 NSFontDescriptor* descriptor =
39 [NSFontDescriptor fontDescriptorWithFontAttributes:attrs];
40 NSFont* font = [NSFont fontWithDescriptor:descriptor size:font_size];
44 // Make one fallback attempt by looking up via font name rather than font
47 NSFontNameAttribute : base::SysUTF8ToNSString(font_name),
48 NSFontTraitsAttribute : traits
50 descriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:attrs];
51 return [NSFont fontWithDescriptor:descriptor size:font_size];
56 ////////////////////////////////////////////////////////////////////////////////
57 // PlatformFontMac, public:
59 PlatformFontMac::PlatformFontMac()
60 : PlatformFontMac([NSFont systemFontOfSize:[NSFont systemFontSize]]) {
63 PlatformFontMac::PlatformFontMac(NativeFont native_font)
64 : native_font_([native_font retain]),
65 font_name_(base::SysNSStringToUTF8([native_font_ familyName])),
66 font_size_([native_font_ pointSize]),
67 font_style_(Font::NORMAL) {
68 NSFontSymbolicTraits traits = [[native_font fontDescriptor] symbolicTraits];
69 if (traits & NSFontItalicTrait)
70 font_style_ |= Font::ITALIC;
71 if (traits & NSFontBoldTrait)
72 font_style_ |= Font::BOLD;
74 CalculateMetricsAndInitRenderParams();
77 PlatformFontMac::PlatformFontMac(const std::string& font_name,
79 : native_font_([NSFontWithSpec(font_name, font_size, Font::NORMAL) retain]),
80 font_name_(font_name),
81 font_size_(font_size),
82 font_style_(Font::NORMAL) {
83 CalculateMetricsAndInitRenderParams();
86 ////////////////////////////////////////////////////////////////////////////////
87 // PlatformFontMac, PlatformFont implementation:
89 Font PlatformFontMac::DeriveFont(int size_delta, int style) const {
90 if (native_font_ && style == font_style_) {
91 // System fonts have special attributes starting with 10.11. They should be
92 // requested using the same descriptor to preserve these attributes.
93 return Font(new PlatformFontMac(
94 [NSFont fontWithDescriptor:[native_font_ fontDescriptor]
95 size:font_size_ + size_delta]));
98 return Font(new PlatformFontMac(font_name_, font_size_ + size_delta, style));
101 int PlatformFontMac::GetHeight() const {
105 int PlatformFontMac::GetBaseline() const {
109 int PlatformFontMac::GetCapHeight() const {
113 int PlatformFontMac::GetExpectedTextWidth(int length) const {
114 return length * average_width_;
117 int PlatformFontMac::GetStyle() const {
121 std::string PlatformFontMac::GetFontName() const {
125 std::string PlatformFontMac::GetActualFontNameForTesting() const {
126 return base::SysNSStringToUTF8([native_font_ familyName]);
129 int PlatformFontMac::GetFontSize() const {
133 const FontRenderParams& PlatformFontMac::GetFontRenderParams() {
134 return render_params_;
137 NativeFont PlatformFontMac::GetNativeFont() const {
138 return [[native_font_.get() retain] autorelease];
141 ////////////////////////////////////////////////////////////////////////////////
142 // PlatformFontMac, private:
144 PlatformFontMac::PlatformFontMac(const std::string& font_name,
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 CalculateMetricsAndInitRenderParams();
154 PlatformFontMac::~PlatformFontMac() {
157 void PlatformFontMac::CalculateMetricsAndInitRenderParams() {
158 NSFont* font = native_font_.get();
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.
169 ascent_ = ceil([font ascender]);
170 cap_height_ = ceil([font capHeight]);
172 // PlatformFontMac once used -[NSLayoutManager defaultLineHeightForFont:] to
173 // initialize |height_|. However, it has a silly rounding bug. Essentially, it
174 // gives round(ascent) + round(descent). E.g. Helvetica Neue at size 16 gives
175 // ascent=15.4634, descent=3.38208 -> 15 + 3 = 18. When the height should be
176 // at least 19. According to the OpenType specification, these values should
177 // simply be added, so do that. Note this uses the already-rounded |ascent_|
178 // to ensure GetBaseline() + descender fits within GetHeight() during layout.
179 height_ = ceil(ascent_ + std::abs([font descender]) + [font leading]);
182 NSWidth([font boundingRectForGlyph:[font glyphWithName:@"x"]]);
184 FontRenderParamsQuery query;
185 query.families.push_back(font_name_);
186 query.pixel_size = font_size_;
187 query.style = font_style_;
188 render_params_ = gfx::GetFontRenderParams(query, NULL);
191 ////////////////////////////////////////////////////////////////////////////////
192 // PlatformFont, public:
195 PlatformFont* PlatformFont::CreateDefault() {
196 return new PlatformFontMac;
200 PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) {
201 return new PlatformFontMac(native_font);
205 PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
207 return new PlatformFontMac(font_name, font_size);