OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/platform_font_mac.h" | |
6 | |
7 #include <Cocoa/Cocoa.h> | 5 #include <Cocoa/Cocoa.h> |
8 #include <stddef.h> | 6 #include <stddef.h> |
9 | 7 |
10 #include "base/mac/mac_util.h" | |
11 #include "base/macros.h" | 8 #include "base/macros.h" |
12 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
13 #include "ui/gfx/font.h" | 10 #include "ui/gfx/font.h" |
14 | 11 |
15 // TODO(tapted): Remove gfx:: prefixes. | |
16 namespace gfx { | |
17 | |
18 TEST(PlatformFontMacTest, DeriveFont) { | 12 TEST(PlatformFontMacTest, DeriveFont) { |
19 // Use a base font that support all traits. | 13 // Use a base font that support all traits. |
20 gfx::Font base_font("Helvetica", 13); | 14 gfx::Font base_font("Helvetica", 13); |
21 | 15 |
22 // Bold | 16 // Bold |
23 gfx::Font bold_font( | 17 gfx::Font bold_font( |
24 base_font.Derive(0, gfx::Font::NORMAL, gfx::Font::Weight::BOLD)); | 18 base_font.Derive(0, gfx::Font::NORMAL, gfx::Font::Weight::BOLD)); |
25 NSFontTraitMask traits = [[NSFontManager sharedFontManager] | 19 NSFontTraitMask traits = [[NSFontManager sharedFontManager] |
26 traitsOfFont:bold_font.GetNativeFont()]; | 20 traitsOfFont:bold_font.GetNativeFont()]; |
27 EXPECT_EQ(NSBoldFontMask, traits); | 21 EXPECT_EQ(NSBoldFontMask, traits); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 | 53 |
60 int actual_style = gfx::Font::UNDERLINE; | 54 int actual_style = gfx::Font::UNDERLINE; |
61 if (traits & NSFontItalicTrait) | 55 if (traits & NSFontItalicTrait) |
62 actual_style |= gfx::Font::ITALIC; | 56 actual_style |= gfx::Font::ITALIC; |
63 | 57 |
64 EXPECT_TRUE(derived_font.GetStyle() & gfx::Font::UNDERLINE); | 58 EXPECT_TRUE(derived_font.GetStyle() & gfx::Font::UNDERLINE); |
65 EXPECT_EQ(derived_font.GetStyle(), actual_style); | 59 EXPECT_EQ(derived_font.GetStyle(), actual_style); |
66 EXPECT_EQ(derived_font.GetWeight(), actual_weight); | 60 EXPECT_EQ(derived_font.GetWeight(), actual_weight); |
67 } | 61 } |
68 | 62 |
69 // Tests internal methods for extracting gfx::Font properties from the | |
70 // underlying CTFont representation. | |
71 TEST(PlatformFontMacTest, ConstructFromNativeFont) { | 63 TEST(PlatformFontMacTest, ConstructFromNativeFont) { |
72 Font normal_font([NSFont fontWithName:@"Helvetica" size:12]); | 64 gfx::Font normal_font([NSFont fontWithName:@"Helvetica" size:12]); |
73 EXPECT_EQ(12, normal_font.GetFontSize()); | 65 EXPECT_EQ(12, normal_font.GetFontSize()); |
74 EXPECT_EQ("Helvetica", normal_font.GetFontName()); | 66 EXPECT_EQ("Helvetica", normal_font.GetFontName()); |
75 EXPECT_EQ(Font::NORMAL, normal_font.GetStyle()); | 67 EXPECT_EQ(gfx::Font::NORMAL, normal_font.GetStyle()); |
76 EXPECT_EQ(Font::Weight::NORMAL, normal_font.GetWeight()); | |
77 | 68 |
78 Font bold_font([NSFont fontWithName:@"Helvetica-Bold" size:14]); | 69 gfx::Font bold_font([NSFont fontWithName:@"Helvetica-Bold" size:14]); |
79 EXPECT_EQ(14, bold_font.GetFontSize()); | 70 EXPECT_EQ(14, bold_font.GetFontSize()); |
80 EXPECT_EQ("Helvetica", bold_font.GetFontName()); | 71 EXPECT_EQ("Helvetica", bold_font.GetFontName()); |
81 EXPECT_EQ(Font::NORMAL, bold_font.GetStyle()); | 72 EXPECT_EQ(gfx::Font::Weight::BOLD, bold_font.GetWeight()); |
82 EXPECT_EQ(Font::Weight::BOLD, bold_font.GetWeight()); | |
83 | 73 |
84 Font italic_font([NSFont fontWithName:@"Helvetica-Oblique" size:14]); | 74 gfx::Font italic_font([NSFont fontWithName:@"Helvetica-Oblique" size:14]); |
85 EXPECT_EQ(14, italic_font.GetFontSize()); | 75 EXPECT_EQ(14, italic_font.GetFontSize()); |
86 EXPECT_EQ("Helvetica", italic_font.GetFontName()); | 76 EXPECT_EQ("Helvetica", italic_font.GetFontName()); |
87 EXPECT_EQ(Font::ITALIC, italic_font.GetStyle()); | 77 EXPECT_EQ(gfx::Font::ITALIC, italic_font.GetStyle()); |
88 EXPECT_EQ(Font::Weight::NORMAL, italic_font.GetWeight()); | |
89 | 78 |
90 Font bold_italic_font([NSFont fontWithName:@"Helvetica-BoldOblique" size:14]); | 79 gfx::Font bold_italic_font( |
| 80 [NSFont fontWithName:@"Helvetica-BoldOblique" size:14]); |
91 EXPECT_EQ(14, bold_italic_font.GetFontSize()); | 81 EXPECT_EQ(14, bold_italic_font.GetFontSize()); |
92 EXPECT_EQ("Helvetica", bold_italic_font.GetFontName()); | 82 EXPECT_EQ("Helvetica", bold_italic_font.GetFontName()); |
93 EXPECT_EQ(Font::ITALIC, bold_italic_font.GetStyle()); | 83 EXPECT_EQ(gfx::Font::ITALIC, bold_italic_font.GetStyle()); |
94 EXPECT_EQ(Font::Weight::BOLD, bold_italic_font.GetWeight()); | 84 EXPECT_EQ(gfx::Font::Weight::BOLD, bold_italic_font.GetWeight()); |
95 } | |
96 | |
97 // Specific test for the mapping from the NSFont weight API to gfx::Font::Weight | |
98 // values. | |
99 TEST(PlatformFontMacTest, FontWeightAPIConsistency) { | |
100 // Vanilla Helvetica only has bold and normal, so use a system font. | |
101 NSFont* ns_font = [NSFont systemFontOfSize:13]; | |
102 NSFontManager* manager = [NSFontManager sharedFontManager]; | |
103 | |
104 // -[NSFontManager convertWeight:ofFont] supposedly steps the font up and down | |
105 // in weight values according to a table at | |
106 // https://developer.apple.com/reference/appkit/nsfontmanager/1462321-convertw
eight | |
107 // Apple Terminology | ISO Equivalent | |
108 // 1. ultralight | none | |
109 // 2. thin | W1. ultralight | |
110 // 3. light, extralight | W2. extralight | |
111 // 4. book | W3. light | |
112 // 5. regular, plain, display, roman | W4. semilight | |
113 // 6. medium | W5. medium | |
114 // 7. demi, demibold | none | |
115 // 8. semi, semibold | W6. semibold | |
116 // 9. bold | W7. bold | |
117 // 10. extra, extrabold | W8. extrabold | |
118 // 11. heavy, heavyface | none | |
119 // 12. black, super | W9. ultrabold | |
120 // 13. ultra, ultrablack, fat | none | |
121 // 14. extrablack, obese, nord | none | |
122 EXPECT_EQ(Font::Weight::NORMAL, Font(ns_font).GetWeight()); // Row 5. | |
123 | |
124 // Ensure the Bold "symbolic" trait from the NSFont traits API maps correctly | |
125 // to the weight (non-symbolic) trait from the CTFont API. | |
126 NSFont* bold_ns_font = | |
127 [manager convertFont:ns_font toHaveTrait:NSFontBoldTrait]; | |
128 Font bold_font(bold_ns_font); | |
129 EXPECT_EQ(Font::Weight::BOLD, bold_font.GetWeight()); | |
130 | |
131 // No thin fonts on the lower rows of the table for San Francisco or earlier | |
132 // system fonts. | |
133 BOOL down = NO; | |
134 ns_font = [NSFont systemFontOfSize:13]; | |
135 for (int row = 4; row > 0; --row) { | |
136 SCOPED_TRACE(testing::Message() << "Row: " << row); | |
137 ns_font = [manager convertWeight:down ofFont:ns_font]; | |
138 EXPECT_EQ(Font::Weight::NORMAL, Font(ns_font).GetWeight()); | |
139 } | |
140 | |
141 BOOL up = YES; | |
142 // That is... unless we first go up by one and then down. A LIGHT and a THIN | |
143 // font reveal themselves somehow. Only tested on 10.11+. | |
144 if (base::mac::IsAtLeastOS10_11()) { | |
145 ns_font = [NSFont systemFontOfSize:13]; | |
146 ns_font = [manager convertWeight:up ofFont:ns_font]; | |
147 ns_font = [manager convertWeight:down ofFont:ns_font]; | |
148 EXPECT_EQ(Font::Weight::LIGHT, Font(ns_font).GetWeight()); | |
149 ns_font = [manager convertWeight:down ofFont:ns_font]; | |
150 EXPECT_EQ(Font::Weight::THIN, Font(ns_font).GetWeight()); | |
151 } | |
152 | |
153 ns_font = [NSFont systemFontOfSize:13]; | |
154 if (base::mac::IsOS10_9()) { | |
155 // On 10.9 the system font doesn't provide finer-grained weights. It's | |
156 // either bold or it isn't. | |
157 for (int row = 6; row <= 14; ++row) { | |
158 SCOPED_TRACE(testing::Message() << "Row: " << row); | |
159 ns_font = [manager convertWeight:up ofFont:ns_font]; | |
160 EXPECT_EQ(Font::Weight::BOLD, Font(ns_font).GetWeight()); | |
161 } | |
162 return; | |
163 } | |
164 | |
165 // Each typeface maps weight notches differently, and the weight is actually a | |
166 // floating point value that may not map directly to a gfx::Font::Weight. For | |
167 // example San Francisco on macOS 10.12 goes up from 0 in the sequence: | |
168 // [0.23, 0.23, 0.3, 0.4, 0.56, 0.62, 0.62, ...] and has no "thin" weights. | |
169 // But also iterating over weights does weird stuff sometimes - occasionally | |
170 // the font goes italic, but going up another step goes back to non-italic, | |
171 // at a heavier weight. | |
172 | |
173 // NSCTFontUIUsageAttribute = CTFontMediumUsage. | |
174 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.23. | |
175 EXPECT_EQ(Font::Weight::MEDIUM, Font(ns_font).GetWeight()); // Row 6. | |
176 | |
177 // Goes italic: NSCTFontUIUsageAttribute = CTFontMediumItalicUsage. | |
178 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.23. | |
179 EXPECT_EQ(Font::Weight::MEDIUM, Font(ns_font).GetWeight()); // Row 7. | |
180 | |
181 // NSCTFontUIUsageAttribute = CTFontDemiUsage. | |
182 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.3. | |
183 if (base::mac::IsOS10_10()) { | |
184 // 10.10 is Helvetica Neue. It only has NORMAL, MEDIUM, BOLD and BLACK. | |
185 EXPECT_EQ(Font::Weight::BOLD, Font(ns_font).GetWeight()); // Row 8. | |
186 } else { | |
187 EXPECT_EQ(Font::Weight::SEMIBOLD, Font(ns_font).GetWeight()); // Row 8. | |
188 } | |
189 | |
190 // NSCTFontUIUsageAttribute = CTFontEmphasizedUsage. | |
191 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.4 on 10.11+. | |
192 | |
193 if (base::mac::IsOS10_10()) { | |
194 // Remaining rows are all BLACK on 10.10. | |
195 for (int row = 9; row <= 14; ++row) { | |
196 SCOPED_TRACE(testing::Message() << "Row: " << row); | |
197 ns_font = [manager convertWeight:up ofFont:ns_font]; | |
198 EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); | |
199 } | |
200 return; | |
201 } | |
202 EXPECT_EQ(Font::Weight::BOLD, Font(ns_font).GetWeight()); // Row 9. | |
203 | |
204 // NSCTFontUIUsageAttribute = CTFontHeavyUsage. | |
205 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.56. | |
206 EXPECT_EQ(Font::Weight::EXTRA_BOLD, Font(ns_font).GetWeight()); // Row 10. | |
207 | |
208 // NSCTFontUIUsageAttribute = CTFontBlackUsage. | |
209 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.62. | |
210 EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); // Row 11. | |
211 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.62. | |
212 EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); // Row 12. | |
213 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.62. | |
214 EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); // Row 13. | |
215 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.62. | |
216 EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); // Row 14. | |
217 } | |
218 | |
219 // Test font derivation for fine-grained font weights. | |
220 TEST(PlatformFontMacTest, DerivedFineGrainedFonts) { | |
221 // Only test where San Francisco is available. | |
222 if (base::mac::IsAtMostOS10_10()) | |
223 return; | |
224 | |
225 using Weight = Font::Weight; | |
226 Font base([NSFont systemFontOfSize:13]); | |
227 | |
228 // The resulting, actual font weight after deriving |weight| from |base|. | |
229 auto DerivedWeight = [&](Weight weight) { | |
230 Font derived(base.Derive(0, 0, weight)); | |
231 // PlatformFont should always pass the requested weight, not what the OS | |
232 // could provide. This just checks a constructor argument, so not very | |
233 // interesting. | |
234 EXPECT_EQ(weight, derived.GetWeight()); | |
235 | |
236 // Return the weight enum value that PlatformFontMac internally derives from | |
237 // the floating point weight given by the kCTFontWeightTrait of |font|. Do | |
238 // this by creating a new font based only off the NSFont in |derived|. | |
239 return Font(derived.GetNativeFont()).GetWeight(); | |
240 }; | |
241 | |
242 // Only use NORMAL or BOLD as a base font. Mac font APIs go whacky otherwise. | |
243 // See comments in PlatformFontMac::DeriveFont(). | |
244 for (Weight base_weight : {Weight::NORMAL, Weight::BOLD}) { | |
245 SCOPED_TRACE(testing::Message() | |
246 << "BaseWeight: " << static_cast<int>(base_weight)); | |
247 if (base_weight != Weight::NORMAL) { | |
248 base = base.Derive(0, 0, base_weight); | |
249 EXPECT_EQ(base_weight, base.GetWeight()); | |
250 } | |
251 | |
252 // San Francisco doesn't offer anything between THIN and LIGHT. | |
253 EXPECT_EQ(Weight::THIN, DerivedWeight(Weight::EXTRA_LIGHT)); | |
254 | |
255 // All the rest should map correctly. | |
256 EXPECT_EQ(Weight::THIN, DerivedWeight(Weight::THIN)); | |
257 EXPECT_EQ(Weight::LIGHT, DerivedWeight(Weight::LIGHT)); | |
258 EXPECT_EQ(Weight::NORMAL, DerivedWeight(Weight::NORMAL)); | |
259 EXPECT_EQ(Weight::MEDIUM, DerivedWeight(Weight::MEDIUM)); | |
260 EXPECT_EQ(Weight::SEMIBOLD, DerivedWeight(Weight::SEMIBOLD)); | |
261 EXPECT_EQ(Weight::BOLD, DerivedWeight(Weight::BOLD)); | |
262 EXPECT_EQ(Weight::EXTRA_BOLD, DerivedWeight(Weight::EXTRA_BOLD)); | |
263 EXPECT_EQ(Weight::BLACK, DerivedWeight(Weight::BLACK)); | |
264 } | |
265 } | 85 } |
266 | 86 |
267 // Ensures that the Font's reported height is consistent with the native font's | 87 // Ensures that the Font's reported height is consistent with the native font's |
268 // ascender and descender metrics. | 88 // ascender and descender metrics. |
269 TEST(PlatformFontMacTest, ValidateFontHeight) { | 89 TEST(PlatformFontMacTest, ValidateFontHeight) { |
270 // Use the default ResourceBundle system font. E.g. Helvetica Neue in 10.10, | 90 // Use the default ResourceBundle system font. E.g. Helvetica Neue in 10.10, |
271 // Lucida Grande before that, and San Francisco after. | 91 // Lucida Grande before that, and San Francisco after. |
272 gfx::Font default_font; | 92 gfx::Font default_font; |
273 gfx::Font::FontStyle styles[] = {gfx::Font::NORMAL, gfx::Font::ITALIC, | 93 gfx::Font::FontStyle styles[] = {gfx::Font::NORMAL, gfx::Font::ITALIC, |
274 gfx::Font::UNDERLINE}; | 94 gfx::Font::UNDERLINE}; |
(...skipping 24 matching lines...) Expand all Loading... |
299 // (plus baseline). So the height depends on the rounding of the ascender, | 119 // (plus baseline). So the height depends on the rounding of the ascender, |
300 // and can be as much as 1 greater than the simple sum of floats. | 120 // and can be as much as 1 greater than the simple sum of floats. |
301 EXPECT_LE(sum, font.GetHeight()); | 121 EXPECT_LE(sum, font.GetHeight()); |
302 EXPECT_GE(sum + 1, font.GetHeight()); | 122 EXPECT_GE(sum + 1, font.GetHeight()); |
303 | 123 |
304 // Recreate the rounding performed for GetBaseLine(). | 124 // Recreate the rounding performed for GetBaseLine(). |
305 EXPECT_EQ(ceil(ceil(ascender) - descender + leading), font.GetHeight()); | 125 EXPECT_EQ(ceil(ceil(ascender) - descender + leading), font.GetHeight()); |
306 } | 126 } |
307 } | 127 } |
308 } | 128 } |
309 | |
310 } // namespace gfx | |
OLD | NEW |