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 |
5 #include <Cocoa/Cocoa.h> | 7 #include <Cocoa/Cocoa.h> |
6 #include <stddef.h> | 8 #include <stddef.h> |
7 | 9 |
| 10 #include "base/mac/mac_util.h" |
8 #include "base/macros.h" | 11 #include "base/macros.h" |
9 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
10 #include "ui/gfx/font.h" | 13 #include "ui/gfx/font.h" |
11 | 14 |
| 15 // TODO(tapted): Remove gfx:: prefixes. |
| 16 namespace gfx { |
| 17 |
12 TEST(PlatformFontMacTest, DeriveFont) { | 18 TEST(PlatformFontMacTest, DeriveFont) { |
13 // Use a base font that support all traits. | 19 // Use a base font that support all traits. |
14 gfx::Font base_font("Helvetica", 13); | 20 gfx::Font base_font("Helvetica", 13); |
15 | 21 |
16 // Bold | 22 // Bold |
17 gfx::Font bold_font( | 23 gfx::Font bold_font( |
18 base_font.Derive(0, gfx::Font::NORMAL, gfx::Font::Weight::BOLD)); | 24 base_font.Derive(0, gfx::Font::NORMAL, gfx::Font::Weight::BOLD)); |
19 NSFontTraitMask traits = [[NSFontManager sharedFontManager] | 25 NSFontTraitMask traits = [[NSFontManager sharedFontManager] |
20 traitsOfFont:bold_font.GetNativeFont()]; | 26 traitsOfFont:bold_font.GetNativeFont()]; |
21 EXPECT_EQ(NSBoldFontMask, traits); | 27 EXPECT_EQ(NSBoldFontMask, traits); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 | 59 |
54 int actual_style = gfx::Font::UNDERLINE; | 60 int actual_style = gfx::Font::UNDERLINE; |
55 if (traits & NSFontItalicTrait) | 61 if (traits & NSFontItalicTrait) |
56 actual_style |= gfx::Font::ITALIC; | 62 actual_style |= gfx::Font::ITALIC; |
57 | 63 |
58 EXPECT_TRUE(derived_font.GetStyle() & gfx::Font::UNDERLINE); | 64 EXPECT_TRUE(derived_font.GetStyle() & gfx::Font::UNDERLINE); |
59 EXPECT_EQ(derived_font.GetStyle(), actual_style); | 65 EXPECT_EQ(derived_font.GetStyle(), actual_style); |
60 EXPECT_EQ(derived_font.GetWeight(), actual_weight); | 66 EXPECT_EQ(derived_font.GetWeight(), actual_weight); |
61 } | 67 } |
62 | 68 |
| 69 // Tests internal methods for extracting gfx::Font properties from the |
| 70 // underlying CTFont representation. |
63 TEST(PlatformFontMacTest, ConstructFromNativeFont) { | 71 TEST(PlatformFontMacTest, ConstructFromNativeFont) { |
64 gfx::Font normal_font([NSFont fontWithName:@"Helvetica" size:12]); | 72 Font normal_font([NSFont fontWithName:@"Helvetica" size:12]); |
65 EXPECT_EQ(12, normal_font.GetFontSize()); | 73 EXPECT_EQ(12, normal_font.GetFontSize()); |
66 EXPECT_EQ("Helvetica", normal_font.GetFontName()); | 74 EXPECT_EQ("Helvetica", normal_font.GetFontName()); |
67 EXPECT_EQ(gfx::Font::NORMAL, normal_font.GetStyle()); | 75 EXPECT_EQ(Font::NORMAL, normal_font.GetStyle()); |
68 | 76 EXPECT_EQ(Font::Weight::NORMAL, normal_font.GetWeight()); |
69 gfx::Font bold_font([NSFont fontWithName:@"Helvetica-Bold" size:14]); | 77 |
| 78 Font bold_font([NSFont fontWithName:@"Helvetica-Bold" size:14]); |
70 EXPECT_EQ(14, bold_font.GetFontSize()); | 79 EXPECT_EQ(14, bold_font.GetFontSize()); |
71 EXPECT_EQ("Helvetica", bold_font.GetFontName()); | 80 EXPECT_EQ("Helvetica", bold_font.GetFontName()); |
72 EXPECT_EQ(gfx::Font::Weight::BOLD, bold_font.GetWeight()); | 81 EXPECT_EQ(Font::NORMAL, bold_font.GetStyle()); |
73 | 82 EXPECT_EQ(Font::Weight::BOLD, bold_font.GetWeight()); |
74 gfx::Font italic_font([NSFont fontWithName:@"Helvetica-Oblique" size:14]); | 83 |
| 84 Font italic_font([NSFont fontWithName:@"Helvetica-Oblique" size:14]); |
75 EXPECT_EQ(14, italic_font.GetFontSize()); | 85 EXPECT_EQ(14, italic_font.GetFontSize()); |
76 EXPECT_EQ("Helvetica", italic_font.GetFontName()); | 86 EXPECT_EQ("Helvetica", italic_font.GetFontName()); |
77 EXPECT_EQ(gfx::Font::ITALIC, italic_font.GetStyle()); | 87 EXPECT_EQ(Font::ITALIC, italic_font.GetStyle()); |
78 | 88 EXPECT_EQ(Font::Weight::NORMAL, italic_font.GetWeight()); |
79 gfx::Font bold_italic_font( | 89 |
80 [NSFont fontWithName:@"Helvetica-BoldOblique" size:14]); | 90 Font bold_italic_font([NSFont fontWithName:@"Helvetica-BoldOblique" size:14]); |
81 EXPECT_EQ(14, bold_italic_font.GetFontSize()); | 91 EXPECT_EQ(14, bold_italic_font.GetFontSize()); |
82 EXPECT_EQ("Helvetica", bold_italic_font.GetFontName()); | 92 EXPECT_EQ("Helvetica", bold_italic_font.GetFontName()); |
83 EXPECT_EQ(gfx::Font::ITALIC, bold_italic_font.GetStyle()); | 93 EXPECT_EQ(Font::ITALIC, bold_italic_font.GetStyle()); |
84 EXPECT_EQ(gfx::Font::Weight::BOLD, bold_italic_font.GetWeight()); | 94 EXPECT_EQ(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.12. |
| 144 if (base::mac::IsAtLeastOS10_12()) { |
| 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 if (base::mac::IsOS10_11()) { |
| 166 // On 10.11 the API jumps to BOLD, but has heavier weights as well. |
| 167 ns_font = [manager convertWeight:up ofFont:ns_font]; |
| 168 EXPECT_EQ(Font::Weight::BOLD, Font(ns_font).GetWeight()); |
| 169 ns_font = [manager convertWeight:up ofFont:ns_font]; |
| 170 EXPECT_EQ(Font::Weight::EXTRA_BOLD, Font(ns_font).GetWeight()); |
| 171 ns_font = [manager convertWeight:up ofFont:ns_font]; |
| 172 EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); |
| 173 return; |
| 174 } |
| 175 |
| 176 // Each typeface maps weight notches differently, and the weight is actually a |
| 177 // floating point value that may not map directly to a gfx::Font::Weight. For |
| 178 // example San Francisco on macOS 10.12 goes up from 0 in the sequence: |
| 179 // [0.23, 0.23, 0.3, 0.4, 0.56, 0.62, 0.62, ...] and has no "thin" weights. |
| 180 // But also iterating over weights does weird stuff sometimes - occasionally |
| 181 // the font goes italic, but going up another step goes back to non-italic, |
| 182 // at a heavier weight. |
| 183 |
| 184 // NSCTFontUIUsageAttribute = CTFontMediumUsage. |
| 185 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.23. |
| 186 EXPECT_EQ(Font::Weight::MEDIUM, Font(ns_font).GetWeight()); // Row 6. |
| 187 |
| 188 // Goes italic: NSCTFontUIUsageAttribute = CTFontMediumItalicUsage. |
| 189 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.23. |
| 190 EXPECT_EQ(Font::Weight::MEDIUM, Font(ns_font).GetWeight()); // Row 7. |
| 191 |
| 192 // NSCTFontUIUsageAttribute = CTFontDemiUsage. |
| 193 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.3. |
| 194 if (base::mac::IsOS10_10()) { |
| 195 // 10.10 is Helvetica Neue. It only has NORMAL, MEDIUM, BOLD and BLACK. |
| 196 EXPECT_EQ(Font::Weight::BOLD, Font(ns_font).GetWeight()); // Row 8. |
| 197 } else { |
| 198 EXPECT_EQ(Font::Weight::SEMIBOLD, Font(ns_font).GetWeight()); // Row 8. |
| 199 } |
| 200 |
| 201 // NSCTFontUIUsageAttribute = CTFontEmphasizedUsage. |
| 202 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.4 on 10.11+. |
| 203 |
| 204 if (base::mac::IsOS10_10()) { |
| 205 // Remaining rows are all BLACK on 10.10. |
| 206 for (int row = 9; row <= 14; ++row) { |
| 207 SCOPED_TRACE(testing::Message() << "Row: " << row); |
| 208 ns_font = [manager convertWeight:up ofFont:ns_font]; |
| 209 EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); |
| 210 } |
| 211 return; |
| 212 } |
| 213 EXPECT_EQ(Font::Weight::BOLD, Font(ns_font).GetWeight()); // Row 9. |
| 214 |
| 215 // NSCTFontUIUsageAttribute = CTFontHeavyUsage. |
| 216 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.56. |
| 217 EXPECT_EQ(Font::Weight::EXTRA_BOLD, Font(ns_font).GetWeight()); // Row 10. |
| 218 |
| 219 // NSCTFontUIUsageAttribute = CTFontBlackUsage. |
| 220 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.62. |
| 221 EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); // Row 11. |
| 222 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.62. |
| 223 EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); // Row 12. |
| 224 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.62. |
| 225 EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); // Row 13. |
| 226 ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.62. |
| 227 EXPECT_EQ(Font::Weight::BLACK, Font(ns_font).GetWeight()); // Row 14. |
| 228 } |
| 229 |
| 230 // Test font derivation for fine-grained font weights. |
| 231 TEST(PlatformFontMacTest, DerivedFineGrainedFonts) { |
| 232 // Only test where San Francisco is available. |
| 233 if (base::mac::IsAtMostOS10_10()) |
| 234 return; |
| 235 |
| 236 using Weight = Font::Weight; |
| 237 Font base([NSFont systemFontOfSize:13]); |
| 238 |
| 239 // The resulting, actual font weight after deriving |weight| from |base|. |
| 240 auto DerivedWeight = [&](Weight weight) { |
| 241 Font derived(base.Derive(0, 0, weight)); |
| 242 // PlatformFont should always pass the requested weight, not what the OS |
| 243 // could provide. This just checks a constructor argument, so not very |
| 244 // interesting. |
| 245 EXPECT_EQ(weight, derived.GetWeight()); |
| 246 |
| 247 // Return the weight enum value that PlatformFontMac internally derives from |
| 248 // the floating point weight given by the kCTFontWeightTrait of |font|. Do |
| 249 // this by creating a new font based only off the NSFont in |derived|. |
| 250 return Font(derived.GetNativeFont()).GetWeight(); |
| 251 }; |
| 252 |
| 253 // Only use NORMAL or BOLD as a base font. Mac font APIs go whacky otherwise. |
| 254 // See comments in PlatformFontMac::DeriveFont(). |
| 255 for (Weight base_weight : {Weight::NORMAL, Weight::BOLD}) { |
| 256 SCOPED_TRACE(testing::Message() |
| 257 << "BaseWeight: " << static_cast<int>(base_weight)); |
| 258 if (base_weight != Weight::NORMAL) { |
| 259 base = base.Derive(0, 0, base_weight); |
| 260 EXPECT_EQ(base_weight, base.GetWeight()); |
| 261 } |
| 262 |
| 263 // Normal and heavy weights map correctly on 10.11 and 10.12. |
| 264 EXPECT_EQ(Weight::NORMAL, DerivedWeight(Weight::NORMAL)); |
| 265 EXPECT_EQ(Weight::BOLD, DerivedWeight(Weight::BOLD)); |
| 266 EXPECT_EQ(Weight::EXTRA_BOLD, DerivedWeight(Weight::EXTRA_BOLD)); |
| 267 EXPECT_EQ(Weight::BLACK, DerivedWeight(Weight::BLACK)); |
| 268 |
| 269 if (base::mac::IsAtMostOS10_11()) { |
| 270 // The fine-grained font weights on 10.11 are incomplete. |
| 271 EXPECT_EQ(Weight::NORMAL, DerivedWeight(Weight::EXTRA_LIGHT)); |
| 272 EXPECT_EQ(Weight::NORMAL, DerivedWeight(Weight::THIN)); |
| 273 EXPECT_EQ(Weight::NORMAL, DerivedWeight(Weight::LIGHT)); |
| 274 EXPECT_EQ(Weight::BOLD, DerivedWeight(Weight::MEDIUM)); |
| 275 EXPECT_EQ(Weight::BOLD, DerivedWeight(Weight::SEMIBOLD)); |
| 276 continue; |
| 277 } |
| 278 |
| 279 // San Francisco doesn't offer anything between THIN and LIGHT. |
| 280 EXPECT_EQ(Weight::THIN, DerivedWeight(Weight::EXTRA_LIGHT)); |
| 281 |
| 282 // All the rest should map correctly. |
| 283 EXPECT_EQ(Weight::THIN, DerivedWeight(Weight::THIN)); |
| 284 EXPECT_EQ(Weight::LIGHT, DerivedWeight(Weight::LIGHT)); |
| 285 EXPECT_EQ(Weight::MEDIUM, DerivedWeight(Weight::MEDIUM)); |
| 286 EXPECT_EQ(Weight::SEMIBOLD, DerivedWeight(Weight::SEMIBOLD)); |
| 287 } |
85 } | 288 } |
86 | 289 |
87 // Ensures that the Font's reported height is consistent with the native font's | 290 // Ensures that the Font's reported height is consistent with the native font's |
88 // ascender and descender metrics. | 291 // ascender and descender metrics. |
89 TEST(PlatformFontMacTest, ValidateFontHeight) { | 292 TEST(PlatformFontMacTest, ValidateFontHeight) { |
90 // Use the default ResourceBundle system font. E.g. Helvetica Neue in 10.10, | 293 // Use the default ResourceBundle system font. E.g. Helvetica Neue in 10.10, |
91 // Lucida Grande before that, and San Francisco after. | 294 // Lucida Grande before that, and San Francisco after. |
92 gfx::Font default_font; | 295 gfx::Font default_font; |
93 gfx::Font::FontStyle styles[] = {gfx::Font::NORMAL, gfx::Font::ITALIC, | 296 gfx::Font::FontStyle styles[] = {gfx::Font::NORMAL, gfx::Font::ITALIC, |
94 gfx::Font::UNDERLINE}; | 297 gfx::Font::UNDERLINE}; |
(...skipping 24 matching lines...) Expand all Loading... |
119 // (plus baseline). So the height depends on the rounding of the ascender, | 322 // (plus baseline). So the height depends on the rounding of the ascender, |
120 // and can be as much as 1 greater than the simple sum of floats. | 323 // and can be as much as 1 greater than the simple sum of floats. |
121 EXPECT_LE(sum, font.GetHeight()); | 324 EXPECT_LE(sum, font.GetHeight()); |
122 EXPECT_GE(sum + 1, font.GetHeight()); | 325 EXPECT_GE(sum + 1, font.GetHeight()); |
123 | 326 |
124 // Recreate the rounding performed for GetBaseLine(). | 327 // Recreate the rounding performed for GetBaseLine(). |
125 EXPECT_EQ(ceil(ceil(ascender) - descender + leading), font.GetHeight()); | 328 EXPECT_EQ(ceil(ceil(ascender) - descender + leading), font.GetHeight()); |
126 } | 329 } |
127 } | 330 } |
128 } | 331 } |
| 332 |
| 333 } // namespace gfx |
OLD | NEW |